diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 91c84cbe..28ac5c82 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -858,6 +858,20 @@ config ARCH_OMAP help Support for TI's OMAP platform (OMAP1/2/3/4). +config ARCH_FULLHAN + bool "FullHan" + select GENERIC_CLOCKEVENTS +# select GENERIC_TIME + select HAVE_SCHED_CLOCK + select ARCH_REQUIRE_GPIOLIB +# select ZONE_DMA + select CLKDEV_LOOKUP + select GENERIC_ALLOCATOR +# select GENERIC_IRQ_CHIP + select HAVE_SYSCALL_TRACEPOINTS + help + Support for FullHan's FH platform. + config PLAT_SPEAR bool "ST SPEAr" select ARM_AMBA @@ -900,6 +914,8 @@ source "arch/arm/mach-dove/Kconfig" source "arch/arm/mach-ep93xx/Kconfig" +source "arch/arm/mach-fh/Kconfig" + source "arch/arm/mach-footbridge/Kconfig" source "arch/arm/mach-gemini/Kconfig" @@ -1577,7 +1593,8 @@ config LEDS ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \ ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \ ARCH_AT91 || ARCH_DAVINCI || \ - ARCH_KS8695 || MACH_RD88F5182 || ARCH_REALVIEW + ARCH_KS8695 || MACH_RD88F5182 || ARCH_REALVIEW || \ + ARCH_FULLHAN help If you say Y here, the LEDs on your machine will be used to provide useful information about your current system status. diff --git a/arch/arm/Makefile b/arch/arm/Makefile index f5b2b390..20ef496c 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -139,6 +139,7 @@ machine-$(CONFIG_ARCH_DAVINCI) := davinci machine-$(CONFIG_ARCH_DOVE) := dove machine-$(CONFIG_ARCH_EBSA110) := ebsa110 machine-$(CONFIG_ARCH_EP93XX) := ep93xx +machine-$(CONFIG_ARCH_FULLHAN) := fh machine-$(CONFIG_ARCH_GEMINI) := gemini machine-$(CONFIG_ARCH_H720X) := h720x machine-$(CONFIG_ARCH_INTEGRATOR) := integrator diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c index 832d3723..0bcea2c1 100644 --- a/arch/arm/boot/compressed/misc.c +++ b/arch/arm/boot/compressed/misc.c @@ -169,6 +169,23 @@ asmlinkage void __div0(void) extern int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x)); +#ifdef CONFIG_TEST_BOOT_TIME +#define SET_TIMING_GPIO(port, level) \ + do { \ + unsigned char *p_gpio = (unsigned char *) 0xf0300000; \ + int data = *(p_gpio + 0x0004); \ + data |= 1 << (port); \ + *(p_gpio + 0x0004) = data; \ + data = *(p_gpio); \ + if ((level) == 0) \ + data &= ~(1 << (port)); \ + else \ + data |= 1 << (port); \ + *(p_gpio) = data; \ + } while (0) +#else +#define SET_TIMING_GPIO(port, level) +#endif void decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, @@ -182,6 +199,8 @@ decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, free_mem_end_ptr = free_mem_ptr_end_p; __machine_arch_type = arch_id; + SET_TIMING_GPIO(4, 1); + arch_decomp_setup(); putstr("Uncompressing Linux..."); diff --git a/arch/arm/configs/fh8632_defconfig b/arch/arm/configs/fh8632_defconfig new file mode 100644 index 00000000..4e5f7a34 --- /dev/null +++ b/arch/arm/configs/fh8632_defconfig @@ -0,0 +1,1797 @@ +# +# Automatically generated make config: don't edit +# Linux/arm 3.0.8 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_HAVE_SCHED_CLOCK=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_KTIME_SCALAR=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_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y +CONFIG_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +# CONFIG_KERNEL_GZIP is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_LZO is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_HAVE_SPARSE_IRQ=y +CONFIG_GENERIC_IRQ_SHOW=y +# CONFIG_SPARSE_IRQ is not set + +# +# RCU Subsystem +# +CONFIG_TINY_RCU=y +# CONFIG_PREEMPT_RCU is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_TREE_RCU_TRACE is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=16 +# CONFIG_CGROUPS is not set +# CONFIG_NAMESPACES is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="usr/rootfs" +CONFIG_INITRAMFS_ROOT_UID=0 +CONFIG_INITRAMFS_ROOT_GID=0 +# CONFIG_RD_GZIP is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +CONFIG_RD_XZ=y +# CONFIG_RD_LZO is not set +# CONFIG_INITRAMFS_COMPRESSION_NONE is not set +CONFIG_INITRAMFS_COMPRESSION_XZ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_PERF_COUNTERS is not set +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=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=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +# CONFIG_LBDAF is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK_BH is not set +CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX 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_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_LPC32XX 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_NUC93X is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS4 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_TCC_926 is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +CONFIG_ARCH_FULLHAN=y +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +CONFIG_CPU_FH8833=y + +# +# FullHan Implementations +# + +# +# FullHan Core Type +# +CONFIG_ARCH_FH8833=y + +# +# FullHan Board Type +# +CONFIG_USE_PTS_AS_CLOCKSOURCE=y +# CONFIG_FH_SIMPLE_TIMER is not set +CONFIG_MACH_FH8833=y + +# +# Hikvision board settings +# +CONFIG_HIKVISION_BOARD=y +# CONFIG_MACH_FH_NAND is not set +# CONFIG_JLINK_DEBUG is not set + +# +# System MMU +# + +# +# Processor Type +# +CONFIG_CPU_V6=y +CONFIG_CPU_32v6=y +CONFIG_CPU_ABRT_EV6=y +CONFIG_CPU_PABRT_V6=y +CONFIG_CPU_CACHE_V6=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V6=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_USE_DOMAINS=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_ARM_L1_CACHE_SHIFT=5 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_CPU_HAS_PMU=y +CONFIG_ARM_ERRATA_411920=y + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_HZ=100 +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 is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_COMPACTION is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_NEED_PER_CPU_KM=y +# CONFIG_CLEANCACHE is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# +# CONFIG_CPU_IDLE is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_VFP=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_PM_SLEEP=y +# CONFIG_PM_RUNTIME is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +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=y +# CONFIG_IP_FIB_TRIE_STATS is not set +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +# CONFIG_IP_PIMSM_V1 is not set +# CONFIG_IP_PIMSM_V2 is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=m +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +CONFIG_DEFAULT_CUBIC=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NETFILTER_XTABLES is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_ARPTABLES is not set + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_DEFRAG_IPV6 is not set +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set + +# +# Classification +# +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +# CONFIG_NET_CLS_U32 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV 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_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_PRIV=y +CONFIG_CFG80211=y +CONFIG_NL80211_TESTMODE=y +# 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=y +CONFIG_WIRELESS_EXT_SYSFS=y +CONFIG_LIB80211=y +# CONFIG_LIB80211_DEBUG is not set +CONFIG_MAC80211=y +CONFIG_MAC80211_HAS_RC=y +# CONFIG_MAC80211_RC_PID is not set +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_DEBUG_MENU 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 + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/mdev" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# 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_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +CONFIG_MTD_M25P80=y +CONFIG_M25PXX_USE_FAST_READ=y +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=1 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# 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 +# CONFIG_SENSORS_LIS3LV02D is not set +CONFIG_MISC_DEVICES=y +# CONFIG_AD525X_DPOT is not set +# CONFIG_INTEL_MID_PTI 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_FH_I2S_SLAVE is not set +# CONFIG_FH_I2S_MASTER is not set +CONFIG_FH_PINCTRL=y +CONFIG_FH_SADC=y +CONFIG_FH_FIRMWARE_LOADER=m +CONFIG_FH_EFUSE=y +CONFIG_FH_CLK_MISC=y +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_BMP085 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +CONFIG_EEPROM_AT24=m +# 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_IWMC3200TOP 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 +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_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +# CONFIG_BLK_DEV_SD is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m +# CONFIG_VETH is not set +CONFIG_MII=y +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# 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_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_NET_ETHERNET=y +# CONFIG_AX88796 is not set +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set +CONFIG_FH_GMAC=y +CONFIG_FH_GMAC_DA=y +# CONFIG_ENC28J60 is not set +# CONFIG_ETHOC is not set +# CONFIG_SMC911X is not set +# CONFIG_SMSC911X is not set +# CONFIG_DNET is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_B44 is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_FTMAC100 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +CONFIG_WLAN=y +CONFIG_LIBERTAS_THINFIRM=y +# CONFIG_LIBERTAS_THINFIRM_DEBUG is not set +# CONFIG_MAC80211_HWSIM is not set +# CONFIG_ATH_COMMON is not set +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_HOSTAP is not set +# CONFIG_IWM is not set +# CONFIG_LIBERTAS is not set +# CONFIG_P54_COMMON is not set +# CONFIG_RT2X00 is not set +# CONFIG_RTL8192SE is not set +# CONFIG_WL1251 is not set +# CONFIG_WL12XX_MENU is not set +# CONFIG_MWIFIEX is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set + +# +# CAIF transport drivers +# +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPP_MPPE is not set +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set +CONFIG_SLHC=m +CONFIG_NETCONSOLE=y +CONFIG_NETPOLL=y +CONFIG_NETPOLL_TRAP=y +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_ISDN is not set +# CONFIG_PHONE 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 + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_MATRIX 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_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD 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=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +# CONFIG_VT_CONSOLE is not set +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +CONFIG_SERIAL_FH=y +CONFIG_SERIAL_FH_CONSOLE=y +# CONFIG_TTY_PRINTK 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_RAMOOPS is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +# CONFIG_I2C_HELPER_AUTO 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_FH_INTERRUPT=y +# CONFIG_I2C_DESIGNWARE is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set +CONFIG_SPI_FH=y +CONFIG_SPI_FH_SLAVE=y + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_TLE62X0 is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_BASIC_MMIO is not set +# CONFIG_GPIO_IT8761E is not set +CONFIG_GPIO_FH=y + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_MAX63XX_WATCHDOG is not set +CONFIG_FH_WATCHDOG=y +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set +CONFIG_MFD_SUPPORT=y +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_REGULATOR is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_CLKGATE is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_DW is not set +CONFIG_MMC_FH=y +CONFIG_MMC_FH_IDMAC=y +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +# CONFIG_LEDS_CLASS is not set + +# +# LED drivers +# + +# +# LED Triggers +# +# CONFIG_NFC_DEVICES is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_FH=y +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +# CONFIG_DW_DMAC is not set +CONFIG_FH_DMAC=y +CONFIG_FH_DMAC_MISC=y +# CONFIG_TIMB_DMA is not set +CONFIG_DMA_ENGINE=y + +# +# DMA Clients +# +# CONFIG_NET_DMA is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +# CONFIG_STAGING is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_PWM=y +CONFIG_PWM_FULLHAN=y +CONFIG_FH_PWM_NUM=8 + +# +# 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_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_GENERIC_ACL=y + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_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=y +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +# CONFIG_JFFS2_RTIME is not set +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_XATTR is not set +# CONFIG_SQUASHFS_LZO is not set +CONFIG_SQUASHFS_XZ=y +# 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_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m + +# +# Kernel hacking +# +# CONFIG_TEST_BOOT_TIME is not set +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_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_KERNEL is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_SPARSE_RCU_POINTER is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_MEMORY_INIT is not set +CONFIG_FRAME_POINTER=y +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +# CONFIG_FTRACE_SYSCALLS is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +# CONFIG_ARM_UNWIND is not set +CONFIG_DEBUG_USER=y +# CONFIG_OC_ETM is not set + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_DEBUG_PROC_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_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_AUTHENC=y +# 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=y + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_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_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=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_USER_API=y +# CONFIG_CRYPTO_USER_API_HASH is not set +CONFIG_CRYPTO_USER_API_SKCIPHER=y +CONFIG_CRYPTO_HW=y +CONFIG_FH_AES=y +# CONFIG_FH_AES_SELF_TEST is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=m +# CONFIG_CRC16 is not set +CONFIG_CRC_T10DIF=m +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=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_XZ=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y +CONFIG_GENERIC_ATOMIC64=y +CONFIG_AVERAGE=y diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h index ee2ad8ae..3aefe527 100644 --- a/arch/arm/include/asm/setup.h +++ b/arch/arm/include/asm/setup.h @@ -143,6 +143,12 @@ struct tag_memclk { __u32 fmemclk; }; +#define ATAG_PHYMODE 0x41000601 + +struct tag_phymode { + u32 phymode; +}; + struct tag { struct tag_header hdr; union { @@ -165,6 +171,11 @@ struct tag { * DC21285 specific */ struct tag_memclk memclk; + + /* + * Fullhan specific + */ + struct tag_phymode phymode; } u; }; diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 278c1b0e..9a375efa 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -226,6 +226,7 @@ __create_page_tables: * This allows debug messages to be output * via a serial console before paging_init. */ +#ifndef CONFIG_JLINK_DEBUG addruart r7, r3 mov r3, r3, lsr #20 @@ -243,6 +244,7 @@ __create_page_tables: add r3, r3, #1 << 20 teq r0, r6 bne 1b +#endif #else /* CONFIG_DEBUG_ICEDCC */ /* we don't need any serial debugging mappings for ICEDCC */ @@ -362,6 +364,13 @@ __enable_mmu: #ifdef CONFIG_CPU_ICACHE_DISABLE bic r0, r0, #CR_I #endif + /* + * add by fullhan + */ +#ifdef CONFIG_JLINK_DEBUG + mov r4, #0x10000000 +#endif + mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \ domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \ diff --git a/arch/arm/mach-fh/Kconfig b/arch/arm/mach-fh/Kconfig new file mode 100644 index 00000000..624516ae --- /dev/null +++ b/arch/arm/mach-fh/Kconfig @@ -0,0 +1,52 @@ +if ARCH_FULLHAN + +config CPU_FH8833 + select CPU_V6 + bool +menu "FullHan Implementations" + +comment "FullHan Core Type" + +choice + prompt "Select Fullhan Chip:" + default ARCH_FH8833 + +config ARCH_FH8833 + bool "FullHan FH8833 based system" + select CPU_FH8833 + +endchoice + +comment "FullHan Board Type" + +config USE_PTS_AS_CLOCKSOURCE + bool "use pts as clock source" + default n + +config FH_SIMPLE_TIMER + bool "use fh self-defined simple timer" + default n + +config MACH_FH8833 + bool "FullHan FH8833 board" + default y + depends on ARCH_FH8833 + select MISC_DEVICES + select I2C + help + Configure this option to specify the whether the board used + for development is FH8833 + + +config MACH_FH_NAND + bool "USE NAND FLASH" + default n + help + use NAND FLASH + +config JLINK_DEBUG + bool "Use jlink to debug kernel." + +endmenu + +endif diff --git a/arch/arm/mach-fh/Makefile b/arch/arm/mach-fh/Makefile new file mode 100644 index 00000000..28de292a --- /dev/null +++ b/arch/arm/mach-fh/Makefile @@ -0,0 +1,19 @@ +# +# Makefile for the linux kernel. +# +# + +# Common objects +obj-y := time.o clock.o \ + sram.o irq.o pmu.o pm.o sram.o +# gpio.o +# Chip specific +obj-$(CONFIG_ARCH_FH8833) += fh8833.o +# Board specific +obj-$(CONFIG_MACH_FH8833) += board-fh8833.o pinctrl.o +obj-$(CONFIG_FH_SIMPLE_TIMER) += fh_simple_timer.o + +# Power Management +obj-$(CONFIG_CPU_FREQ) += cpufreq.o +obj-$(CONFIG_CPU_IDLE) += cpuidle.o +obj-$(CONFIG_SUSPEND) += pm.o sleep.o diff --git a/arch/arm/mach-fh/Makefile.boot b/arch/arm/mach-fh/Makefile.boot new file mode 100644 index 00000000..f05489f0 --- /dev/null +++ b/arch/arm/mach-fh/Makefile.boot @@ -0,0 +1,4 @@ + zreladdr-y := 0xA0008000 +params_phys-y := 0xA0000100 +initrd_phys-y := 0xA0800000 + diff --git a/arch/arm/mach-fh/board-fh8833.c b/arch/arm/mach-fh/board-fh8833.c new file mode 100644 index 00000000..2c81f6f3 --- /dev/null +++ b/arch/arm/mach-fh/board-fh8833.c @@ -0,0 +1,1200 @@ +/* + * Fullhan FH8810 board support + * + * Copyright (C) 2014 Fullhan Microelectronics 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static struct map_desc fh8833_io_desc[] = { + { + .virtual = VA_RAM_REG_BASE, + .pfn = __phys_to_pfn(RAM_BASE), + .length = SZ_16K, + .type = MT_MEMORY, + }, + { + .virtual = VA_DDRC_REG_BASE, + .pfn = __phys_to_pfn(DDRC_REG_BASE), + .length = SZ_16K, + .type = MT_DEVICE, + }, + { + .virtual = VA_INTC_REG_BASE, + .pfn = __phys_to_pfn(INTC_REG_BASE), + .length = SZ_16K, + .type = MT_DEVICE, + }, + { + .virtual = VA_TIMER_REG_BASE, + .pfn = __phys_to_pfn(TIMER_REG_BASE), + .length = SZ_16K, + .type = MT_DEVICE, + }, + { + .virtual = VA_PMU_REG_BASE, + .pfn = __phys_to_pfn(PMU_REG_BASE), + .length = SZ_16K, + .type = MT_DEVICE, + }, + { + .virtual = VA_UART0_REG_BASE, + .pfn = __phys_to_pfn(UART0_REG_BASE), + .length = SZ_16K, + .type = MT_DEVICE, + }, + { + .virtual = VA_UART1_REG_BASE, + .pfn = __phys_to_pfn(UART1_REG_BASE), + .length = SZ_16K, + .type = MT_DEVICE, + }, + { + .virtual = VA_PAE_REG_BASE, + .pfn = __phys_to_pfn(PAE_REG_BASE), + .length = SZ_16K, + .type = MT_DEVICE, + }, +}; + + +static struct resource fh_gpio0_resources[] = { + { + .start = GPIO0_REG_BASE, + .end = GPIO0_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + + { + .start = GPIO0_IRQ, + .end = GPIO0_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource fh_gpio1_resources[] = { + { + .start = GPIO1_REG_BASE, + .end = GPIO1_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + + { + .start = GPIO1_IRQ, + .end = GPIO1_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + + +static struct resource fh_uart0_resources[] = { + { + .start = (UART0_REG_BASE), + .end = (UART0_REG_BASE) + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + + { + .start = UART0_IRQ, + .end = UART0_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource fh_uart1_resources[] = { + { + .start = (UART1_REG_BASE), + .end = (UART1_REG_BASE) + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + + { + .start = UART1_IRQ, + .end = UART1_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource fh_dma_resources[] = { + { + .start = (DMAC_REG_BASE), + .end = (DMAC_REG_BASE) + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + + { + .start = DMAC0_IRQ, + .end = DMAC0_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; +static struct resource fh_i2c_resources_0[] = { + { + .start = I2C0_REG_BASE, + .end = I2C0_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + + { + .start = I2C0_IRQ, + .end = I2C0_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; +static struct resource fh_i2c_resources_1[] = { + { + .start = I2C1_REG_BASE, + .end = I2C1_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + + { + .start = I2C1_IRQ, + .end = I2C1_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource fh_sdc0_resources[] = { + { + .start = SDC0_REG_BASE, + .end = SDC0_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = SDC0_IRQ, + .end = SDC0_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; +static struct resource fh_sdc1_resources[] = { + { + .start = SDC1_REG_BASE, + .end = SDC1_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = SDC1_IRQ, + .end = SDC1_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; +static struct resource fh_wdt_resources[] = { + { + .start = WDT_REG_BASE, + .end = WDT_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = WDT_IRQ, + .end = WDT_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; +static struct resource fh_i2s_resources[] = { + { + .start = I2S_REG_BASE, + .end = I2S_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = I2S0_IRQ, + .end = I2S0_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource fh_spi0_resources[] = { + { + .start = SPI0_REG_BASE, + .end = SPI0_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + .name = "fh spi0 mem", + }, + { + .start = SPI0_IRQ, + .end = SPI0_IRQ, + .flags = IORESOURCE_IRQ, + .name = "fh spi0 irq", + }, +}; + +static struct resource fh_spi1_resources[] = { + { + .start = SPI1_REG_BASE, + .end = SPI1_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + .name = "fh spi1 mem", + }, + { + .start = SPI1_IRQ, + .end = SPI1_IRQ, + .flags = IORESOURCE_IRQ, + .name = "fh spi1 irq", + }, +}; + +static struct resource fh_spi2_resources[] = { + { + .start = SPI2_REG_BASE, + .end = SPI2_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + .name = "fh spi2 mem", + }, + { + .start = SPI2_IRQ, + .end = SPI2_IRQ, + .flags = IORESOURCE_IRQ, + .name = "fh spi2 irq", + }, +}; + + + +static struct resource fh_gmac_resources[] = { + { + .start = GMAC_REG_BASE, + .end = GMAC_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + + { + .start = GMAC_IRQ, + .end = GMAC_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource fh_pwm_resources[] = { + { + .start = PWM_REG_BASE, + .end = PWM_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = PWM_IRQ, + .end = PWM_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource fh_sadc_resources[] = { + { + .start = SADC_REG_BASE, + .end = SADC_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + .name = "fh sadc mem", + }, + { + .start = SADC_IRQ, + .end = SADC_IRQ, + .flags = IORESOURCE_IRQ, + .name = "fh sadc irq", + }, +}; + +static struct resource fh_aes_resources[] = { + { + .start = AES_REG_BASE, + .end = AES_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + .name = "fh aes mem", + }, + { + .start = AES_IRQ, + .end = AES_IRQ, + .flags = IORESOURCE_IRQ, + .name = "fh aes irq", + }, +}; + +static struct resource fh_acw_resources[] = { + { + .start = ACW_REG_BASE, + .end = ACW_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = ACW_IRQ, + .end = ACW_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + + +static struct resource fh_rtc_resources[] = { + { + .start = RTC_REG_BASE, + .end = RTC_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = RTC_IRQ, + .end = RTC_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + + +static struct resource fh_efuse_resources[] = { + { + .start = EFUSE_REG_BASE, + .end = EFUSE_REG_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + +}; + +static void fh_gmac_early_init(struct fh_gmac_platform_data *plat_data) +{ + if (plat_data->interface == PHY_INTERFACE_MODE_RMII) + fh_pmu_set_reg(REG_PMU_PAD_MAC_REF_CLK_CFG, 0x10001000); + else if (plat_data->interface == PHY_INTERFACE_MODE_MII) + fh_pmu_set_reg(REG_PMU_PAD_MAC_REF_CLK_CFG, 0x1000); +} + +static void fh_gmac_plat_init(struct fh_gmac_platform_data *plat_data) +{ + u32 reg; + + if (plat_data->interface == PHY_INTERFACE_MODE_RMII) { + reg = fh_pmu_get_reg(REG_PMU_SYS_CTRL); + reg |= 0x7000000; + fh_pmu_set_reg(REG_PMU_SYS_CTRL, reg); + + fh_pmu_set_reg(REG_PMU_SWRST_AHB_CTRL, 0xfffdffff); + while (fh_pmu_get_reg(REG_PMU_SWRST_AHB_CTRL) != 0xffffffff) + ; + + } else if (plat_data->interface == PHY_INTERFACE_MODE_MII) { + reg = fh_pmu_get_reg(REG_PMU_SYS_CTRL); + reg &= ~(0x7000000); + reg |= 0x1000000; + fh_pmu_set_reg(REG_PMU_SYS_CTRL, reg); + + fh_pmu_set_reg(REG_PMU_SWRST_AHB_CTRL, 0xfffdffff); + while (fh_pmu_get_reg(REG_PMU_SWRST_AHB_CTRL) != 0xffffffff) + ; + } +} + +static void fh_set_rmii_speed(int speed) +{ + u32 reg; + + if (speed == gmac_speed_10m) { + reg = fh_pmu_get_reg(REG_PMU_SYS_CTRL); + reg &= ~(0x1000000); + fh_pmu_set_reg(REG_PMU_SYS_CTRL, reg); + } else { + reg = fh_pmu_get_reg(REG_PMU_SYS_CTRL); + reg |= 0x1000000; + fh_pmu_set_reg(REG_PMU_SYS_CTRL, reg); + } +} + +static void fh_phy_reset(void) +{ + /* + * RXDV must be low during phy reset + * also, use AC_MCLK as our RMII REF CLK + * just for temp use + */ + fh_pmu_set_reg(0x16c, 0x3001000); + fh_pmu_set_reg(0x1c, 0x0); + fh_pmu_set_reg(0x3c, 0x0b77030b); + fh_pmu_set_reg(0xe8, 0x1101000); + + gpio_request(CONFIG_GPIO_EMACPHY_RESET, "phy_reset"); + gpio_request(CONFIG_GPIO_EMACPHY_RXDV, "phy_rxdv"); + + gpio_direction_output(CONFIG_GPIO_EMACPHY_RXDV, 0); + gpio_direction_output(CONFIG_GPIO_EMACPHY_RESET, 0); + mdelay(10); + gpio_direction_output(CONFIG_GPIO_EMACPHY_RESET, 1); + mdelay(10); + gpio_free(CONFIG_GPIO_EMACPHY_RESET); + gpio_free(CONFIG_GPIO_EMACPHY_RXDV); + + fh_pmu_set_reg(0xe8, 0x101000); + +} + +static struct fh_gmac_platform_data fh_gmac_data = { + .early_init = fh_gmac_early_init, + .plat_init = fh_gmac_plat_init, + .set_rmii_speed = fh_set_rmii_speed, + .phy_reset = fh_phy_reset, + .phyid = -1, +}; + +static const char *const fh_gpio0_names[] = { + "GPIO0", "GPIO1", "GPIO2", "GPIO3", + "GPIO4", "GPIO5", "GPIO6", "GPIO7", + "GPIO8", "GPIO9", "GPIO10", "GPIO11", + "GPIO12", "GPIO13", "GPIO14", "GPIO15", + "GPIO16", "GPIO17", "GPIO18", "GPIO19", + "GPIO20", "GPIO21", "GPIO22", "GPIO23", + "GPIO24", "GPIO25", "GPIO26", "GPIO27", + "GPIO28", "GPIO29", "GPIO30", "GPIO31", +}; + +static const char *const fh_gpio1_names[] = { + "GPIO32", "GPIO33", "GPIO34", "GPIO35", + "GPIO36", "GPIO37", "GPIO38", "GPIO39", + "GPIO40", "GPIO41", "GPIO42", "GPIO43", + "GPIO44", "GPIO45", "GPIO46", "GPIO47", + "GPIO48", "GPIO49", "GPIO50", "GPIO51", + "GPIO52", "GPIO53", "GPIO54", "GPIO55", + "GPIO56", "GPIO57", "GPIO58", "GPIO59", + "GPIO60", "GPIO61", "GPIO62", "GPIO63", + "GPIO64", "GPIO65", "GPIO66", "GPIO67", + "GPIO68", "GPIO69", "GPIO70", "GPIO71", +}; + +static struct fh_gpio_chip fh_gpio0_chip = { + .chip = { + .owner = THIS_MODULE, + .label = "FH_GPIO0", + .base = 0, + .ngpio = 32, + .names = fh_gpio0_names, + }, +}; + +static struct fh_gpio_chip fh_gpio1_chip = { + .chip = { + .owner = THIS_MODULE, + .label = "FH_GPIO1", + .base = 32, + .ngpio = 32, + .names = fh_gpio1_names, + }, +}; + + +static void fh_wdt_pause(void) +{ + unsigned int reg; + + reg = fh_pmu_get_reg(REG_PMU_WDT_CTRL); + reg |= 0x100; + fh_pmu_set_reg(REG_PMU_WDT_CTRL, reg); + + printk(KERN_INFO "wdt pause\n"); +} + +static void fh_wdt_resume(void) +{ + unsigned int reg; + + reg = fh_pmu_get_reg(REG_PMU_WDT_CTRL); + reg &= ~(0x100); + fh_pmu_set_reg(REG_PMU_WDT_CTRL, reg); +} + +static struct fh_wdt_platform_data fh_wdt_data = { + .pause = fh_wdt_pause, + .resume = fh_wdt_resume, +}; + +static int fh_buswd(u32 slot_id) +{ + return 4; +} + +static int sd_init(unsigned int slot_id, void *data, void *v) +{ + u32 reg; + + reg = slot_id ? 0xfffffffd : 0xfffffffb; + fh_pmu_set_reg(REG_PMU_SWRST_AHB_CTRL, reg); + while (fh_pmu_get_reg(REG_PMU_SWRST_AHB_CTRL) != 0xffffffff) + ; + return 0; +} + +static unsigned int __maybe_unused +fh_mci_sys_card_detect_fixed(struct fhmci_host *host) +{ + return 0; +} + +static unsigned int __maybe_unused +fh_mci_sys_read_only_fixed(struct fhmci_host *host) +{ + return 0; +} + +struct fh_mci_board fh_mci = { + .init = sd_init, +#ifdef CONFIG_SD_CD_FIXED + .get_cd = fh_mci_sys_card_detect_fixed, +#endif +#ifdef CONFIG_SD_WP_FIXED + .get_ro = fh_mci_sys_read_only_fixed, +#endif + .num_slots = 1, + .bus_hz = 50000000, + .detect_delay_ms = 200, + .get_bus_wd = fh_buswd, + .caps = MMC_CAP_4_BIT_DATA + | MMC_CAP_SD_HIGHSPEED + | MMC_CAP_MMC_HIGHSPEED + | MMC_CAP_NEEDS_POLL + /* | MMC_CAP_SDIO_IRQ */, +}; + +struct fh_mci_board fh_mci_sd = { +#ifdef CONFIG_SD_WP_FIXED + .get_ro = fh_mci_sys_read_only_fixed, +#endif + .init = sd_init, + .num_slots = 1, + .bus_hz = 50000000, + .detect_delay_ms = 200, + .get_bus_wd = fh_buswd, + .caps = MMC_CAP_SD_HIGHSPEED + | MMC_CAP_MMC_HIGHSPEED + | MMC_CAP_NEEDS_POLL + /* | MMC_CAP_SDIO_IRQ */, +}; + +static struct fh_dma_platform_data fh_dma_data = { + .chan_priority = CHAN_PRIORITY_DESCENDING, + .nr_channels = 8, +}; + +static struct at24_platform_data at24c02 = { + .byte_len = SZ_2K / 8, + .page_size = 8, + .flags = AT24_FLAG_TAKE8ADDR, +}; + +static struct platform_device fh_gmac_device = { + .name = "fh_gmac", + .id = 0, + .num_resources = ARRAY_SIZE(fh_gmac_resources), + .resource = fh_gmac_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &fh_gmac_data, + }, +}; + +static struct platform_device fh_i2s_misc_device = { + .name = "fh_i2s", + .id = 0, + .num_resources = ARRAY_SIZE(fh_i2s_resources), + .resource = fh_i2s_resources, +}; + +static struct platform_device fh_acw_misc_device = { + .name = "fh_acw", + .id = 0, + .num_resources = ARRAY_SIZE(fh_acw_resources), + .resource = fh_acw_resources, +}; + +static struct platform_device fh_gpio0_device = { + .name = GPIO_NAME, + .id = 0, + .num_resources = ARRAY_SIZE(fh_gpio0_resources), + .resource = fh_gpio0_resources, + .dev = { + .platform_data = &fh_gpio0_chip, + }, +}; + +static struct platform_device fh_gpio1_device = { + .name = GPIO_NAME, + .id = 1, + .num_resources = ARRAY_SIZE(fh_gpio1_resources), + .resource = fh_gpio1_resources, + .dev = { + .platform_data = &fh_gpio1_chip, + }, +}; + +struct platform_device fh_sd0_device = { + .name = "fh_mci", + .id = 0, + .num_resources = ARRAY_SIZE(fh_sdc0_resources), + .resource = fh_sdc0_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &fh_mci_sd, + } +}; + +struct platform_device fh_sd1_device = { + .name = "fh_mci", + .id = 1, + .num_resources = ARRAY_SIZE(fh_sdc1_resources), + .resource = fh_sdc1_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &fh_mci, + } +}; + +struct platform_device fh_wdt_device = { + .name = "fh_wdt", + .id = 0, + .num_resources = ARRAY_SIZE(fh_wdt_resources), + .resource = fh_wdt_resources, + .dev = { + .platform_data = &fh_wdt_data, + } +}; + +static struct platform_device fh_uart0_device = { + .name = "ttyS", + .id = 0, + .num_resources = ARRAY_SIZE(fh_uart0_resources), + .resource = fh_uart0_resources, +}; + +static struct platform_device fh_uart1_device = { + .name = "ttyS", + .id = 1, + .num_resources = ARRAY_SIZE(fh_uart1_resources), + .resource = fh_uart1_resources, +}; + +static struct platform_device fh_dma_device = { + .name = "fh_dmac", + .id = 0, + .num_resources = ARRAY_SIZE(fh_dma_resources), + .resource = fh_dma_resources, + .dev.platform_data = &fh_dma_data, +}; + +static struct platform_device fh_i2c0_device = { + .name = "fh_i2c", + .id = 0, + .num_resources = ARRAY_SIZE(fh_i2c_resources_0), + .resource = fh_i2c_resources_0, +}; + +static struct platform_device fh_i2c1_device = { + .name = "fh_i2c", + .id = 1, + .num_resources = ARRAY_SIZE(fh_i2c_resources_1), + .resource = fh_i2c_resources_1, +}; + +static struct i2c_board_info __initdata fh_i2c_devices[] = { + { + I2C_BOARD_INFO("24c02", 0x50), + .platform_data = &at24c02, + }, + { + I2C_BOARD_INFO("pcf8563", 0x51) + } +}; + +#define FH_SPI0_CS0 (54) +#define FH_SPI0_CS1 (55) + +#define FH_SPI1_CS0 (56) +#define FH_SPI1_CS1 (57) + +#define FH_SPI3_CS0 (58) +#define FH_SPI3_CS1 (59) + +#define SPI0_FIFO_DEPTH (64) +#define SPI0_CLK_IN (100000000) +#define SPI0_MAX_SLAVE_NO (2) +#define SPI0_DMA_RX_CHANNEL (0) +#define SPI0_DMA_TX_CHANNEL (1) + +#define SPI1_FIFO_DEPTH (32) +#define SPI1_CLK_IN (100000000) +#define SPI1_MAX_SLAVE_NO (2) +#define SPI1_DMA_RX_CHANNEL (2) +#define SPI1_DMA_TX_CHANNEL (3) + +#define SPI2_FIFO_DEPTH (64) +#define SPI2_CLK_IN (100000000) + +#define SPI3_FIFO_DEPTH (32) +#define SPI3_CLK_IN (100000000) +#define SPI3_MAX_SLAVE_NO (2) +#define SPI3_DMA_RX_CHANNEL (4) +#define SPI3_DMA_TX_CHANNEL (5) +/* SPI_TRANSFER_USE_DMA */ + +static struct fh_spi_platform_data fh_spi0_data = { + .apb_clock_in = SPI0_CLK_IN, + .fifo_len = SPI0_FIFO_DEPTH, + .slave_max_num = SPI0_MAX_SLAVE_NO, + .cs_data[0].GPIO_Pin = FH_SPI0_CS0, + .cs_data[0].name = "spi0_cs0", + .cs_data[1].GPIO_Pin = FH_SPI0_CS1, + .cs_data[1].name = "spi0_cs1", + .dma_transfer_enable = 0, + .rx_handshake_num = 2, + .tx_handshake_num = 3, + .rx_dma_channel = SPI0_DMA_RX_CHANNEL, + .tx_dma_channel = SPI0_DMA_TX_CHANNEL, + .clk_name = "spi0_clk", +}; + +static struct fh_spi_platform_data fh_spi1_data = { + .apb_clock_in = SPI1_CLK_IN, + .fifo_len = SPI1_FIFO_DEPTH, + .slave_max_num = SPI1_MAX_SLAVE_NO, + .cs_data[0].GPIO_Pin = FH_SPI1_CS0, + .cs_data[0].name = "spi1_cs0", + .cs_data[1].GPIO_Pin = FH_SPI1_CS1, + .cs_data[1].name = "spi1_cs1", + .dma_transfer_enable = 0, + .rx_handshake_num = 4, + .tx_handshake_num = 5, + .rx_dma_channel = SPI1_DMA_RX_CHANNEL, + .tx_dma_channel = SPI1_DMA_TX_CHANNEL, + .clk_name = "spi1_clk", +}; + +static struct fh_spi_platform_data fh_spi2_data = { + .apb_clock_in = SPI2_CLK_IN, + .fifo_len = SPI2_FIFO_DEPTH, + .dma_transfer_enable = 0, + .rx_handshake_num = 12, + .tx_handshake_num = 13, + .clk_name = "spi2_clk", +}; + +static struct fh_rtc_platform_data fh_rtc_data = { + .clock_in = 32768, + .dev_name = "rtc", + .clk_name = "rtc_clk", + .base_year = 2000, + .base_month = 1, + .base_day = 1, + .sadc_channel = -1, +}; + + + +static struct platform_device fh_spi0_device = { + .name = "fh_spi", + .id = 0, + .num_resources = ARRAY_SIZE(fh_spi0_resources), + .resource = fh_spi0_resources, + .dev = { + .platform_data = &fh_spi0_data, + }, +}; + +static struct platform_device fh_spi1_device = { + .name = "fh_spi", + .id = 1, + .num_resources = ARRAY_SIZE(fh_spi1_resources), + .resource = fh_spi1_resources, + .dev = { + .platform_data = &fh_spi1_data, + }, +}; + + +static struct platform_device fh_spi2_device = { + .name = "fh_spi_slave", + .id = 0, + .num_resources = ARRAY_SIZE(fh_spi2_resources), + .resource = fh_spi2_resources, + .dev = { + .platform_data = &fh_spi2_data, + }, +}; + +static struct platform_device fh_pwm_device = { + .name = "fh_pwm", + .id = 0, + .num_resources = ARRAY_SIZE(fh_pwm_resources), + .resource = fh_pwm_resources, + +}; + +static struct platform_device fh_pinctrl_device = { + .name = "fh_pinctrl", + .id = 0, +}; + +static struct platform_device fh_sadc_device = { + .name = "fh_sadc", + .id = 0, + .num_resources = ARRAY_SIZE(fh_sadc_resources), + .resource = fh_sadc_resources, + .dev = { + .platform_data = NULL, + }, +}; + +static struct platform_device fh_aes_device = { + .name = "fh_aes", + .id = 0, + .num_resources = ARRAY_SIZE(fh_aes_resources), + .resource = fh_aes_resources, + .dev = { + .platform_data = NULL, + }, +}; + +static struct platform_device fh_ac97_device = { + .name = "fh-acodec", + .id = -1, +}; + +static struct platform_device fh_pcm_device = { + .name = "fh-pcm-audio", + .id = -1, +}; + +static struct platform_device fh_rtc_device = { + .name = "fh_rtc", + .id = 0, + .num_resources = ARRAY_SIZE(fh_rtc_resources), + .resource = fh_rtc_resources, + .dev = { + .platform_data = &fh_rtc_data, + }, +}; + +static struct platform_device fh_efuse_device = { + .name = "fh_efuse", + .id = 0, + .num_resources = ARRAY_SIZE(fh_efuse_resources), + .resource = fh_efuse_resources, +}; + +/* + * fh8833 usb board config + * add 2016/12/20 + * + */ +#define USB_REG_BASE 0xe0700000 +#define S3C64XX_PA_USBHOST USB_REG_BASE +#define IRQ_UHOST USBC_IRQ +#define S3C_PA_OTG S3C64XX_PA_USBHOST +#define IRQ_OTG IRQ_UHOST +#define S3C64XX_SZ_USBHOST SZ_1M +#define S3C_SZ_OTG SZ_1M +/* USB Host Controller */ + +static struct resource s3c_usb_resource[] = { + [0] = { + .start = S3C64XX_PA_USBHOST, + .end = S3C64XX_PA_USBHOST + S3C64XX_SZ_USBHOST - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_UHOST, + .end = IRQ_UHOST, + .flags = IORESOURCE_IRQ, + } +}; + +static u64 s3c_device_usb_dmamask = 0xffffffffUL; + +struct platform_device s3c_device_usb = { + .name = "s3c2410-ohci", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usb_resource), + .resource = s3c_usb_resource, + .dev = { + .dma_mask = &s3c_device_usb_dmamask, + .coherent_dma_mask = 0xffffffffUL + } +}; + +EXPORT_SYMBOL(s3c_device_usb); + +/* USB Device (Gadget)*/ + +static struct resource s3c_usbgadget_resource[] = { + [0] = { + .start = S3C_PA_OTG, + .end = S3C_PA_OTG + S3C_SZ_OTG - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_OTG, + .end = IRQ_OTG, + .flags = IORESOURCE_IRQ, + } +}; + +struct platform_device s3c_device_usbgadget = { + .name = "s3c-usbgadget", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usbgadget_resource), + .resource = s3c_usbgadget_resource, +}; + +EXPORT_SYMBOL(s3c_device_usbgadget); + +/* USB Device (OTG hcd)*/ + +static struct resource s3c_usb_otghcd_resource[] = { + { + .start = S3C_PA_OTG, + .end = S3C_PA_OTG + S3C_SZ_OTG - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = IRQ_OTG, + .end = IRQ_OTG, + .flags = IORESOURCE_IRQ, + } +}; + +static u64 s3c_device_usb_otghcd_dmamask = 0xffffffffUL; + +struct platform_device s3c_device_usb_otghcd = { + .name = "s3c_otghcd", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usb_otghcd_resource), + .resource = s3c_usb_otghcd_resource, + .dev = { + .dma_mask = &s3c_device_usb_otghcd_dmamask, + .coherent_dma_mask = 0xffffffffUL + } +}; + +static u64 fh_usb_otghcd_dmamask = 0xffffffffUL; +struct platform_device fh_device_usb_otghcd = { + .name = "fh_otg", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usb_otghcd_resource), + .resource = s3c_usb_otghcd_resource, + .dev = { + .dma_mask = &fh_usb_otghcd_dmamask, + .coherent_dma_mask = 0xffffffffUL, + } +}; + +static struct platform_device *fh8833_devices[] __initdata = { + &fh_gmac_device, + &fh_uart0_device, + &fh_uart1_device, + &fh_dma_device, + &fh_i2c0_device, + &fh_i2c1_device, + &fh_sd0_device, + &fh_sd1_device, + &fh_spi0_device, + &fh_spi1_device, + &fh_spi2_device, + &fh_gpio0_device, + &fh_gpio1_device, + &fh_wdt_device, + &fh_pwm_device, + &fh_pinctrl_device, + &fh_sadc_device, + &fh_aes_device, + &fh_pcm_device, + &fh_ac97_device, + &fh_acw_misc_device, + &fh_i2s_misc_device, + &fh_rtc_device, + &fh_device_usb_otghcd, + &fh_efuse_device, + +}; + +static struct mtd_partition fh_sf_parts[] = { + { + /* head & Ramboot */ + .name = "bootstrap", + .offset = 0, + .size = SZ_256K, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + /* Ramboot & U-Boot environment */ + .name = "uboot-env", + .offset = MTDPART_OFS_APPEND, + .size = SZ_64K, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + /* U-Boot */ + .name = "uboot", + .offset = MTDPART_OFS_APPEND, + .size = 3 * SZ_64K, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_4M, + .mask_flags = 0, + }, { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = SZ_8M, + .mask_flags = 0, + }, { + .name = "app", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0, + } + /* mtdparts= + * spi_flash:256k(bootstrap), + * 64k(u-boot-env), + * 192k(u-boot),4M(kernel), + * 8M(rootfs), + * -(app) */ + /* two blocks with bad block table (and mirror) at the end */ +}; +#ifdef CONFIG_MACH_FH_NAND +static struct mtd_partition fh_sf_nand_parts[] = { + { + /* head & Ramboot */ + .name = "bootstrap", + .offset = 0, + .size = SZ_256K, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "uboot-env", + .offset = MTDPART_OFS_APPEND, + .size = SZ_256K, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "uboot", + .offset = MTDPART_OFS_APPEND, + .size = SZ_256K, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_4M, + .mask_flags = 0, + }, { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = SZ_8M, + .mask_flags = 0, + }, { + .name = "app", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0, + } + /* mtdparts= + * spi0.0:64k(bootstrap), + * 64k(u-boot-env), + * 192k(u-boot), + * 4M(kernel), + * 8M(rootfs), + * -(app) */ + /* two blocks with bad block table (and mirror) at the end */ +}; +static struct flash_platform_data fh_nandflash_platform_data = { + .name = "spi_nandflash", + .parts = fh_sf_nand_parts, + .nr_parts = ARRAY_SIZE(fh_sf_nand_parts), +}; +#endif +static struct flash_platform_data fh_flash_platform_data = { + .name = "spi_flash", + .parts = fh_sf_parts, + .nr_parts = ARRAY_SIZE(fh_sf_parts), +}; +static struct spi_board_info fh_spi_devices[] = { +#ifdef CONFIG_MACH_FH_NAND + { + .modalias = "spi-nand", + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 50000000, + .mode = SPI_MODE_3, + .platform_data = &fh_nandflash_platform_data, + }, +#endif + { + .modalias = "m25p80", + .bus_num = 0, + .chip_select = 0, + .mode = SPI_MODE_3, + .max_speed_hz = 25000000, + .platform_data = &fh_flash_platform_data, + }, + +}; +static void __init fh8833_map_io(void) +{ + iotable_init(fh8833_io_desc, ARRAY_SIZE(fh8833_io_desc)); +} + + +static __init void fh8833_board_init(void) +{ + printk(KERN_INFO "fh8833 board init\n"); + platform_add_devices(fh8833_devices, ARRAY_SIZE(fh8833_devices)); + i2c_register_board_info(1, fh_i2c_devices, ARRAY_SIZE(fh_i2c_devices)); + spi_register_board_info(fh_spi_devices, ARRAY_SIZE(fh_spi_devices)); + fh_clk_procfs_init(); + fh_pmu_init(); +} + +static void __init fh8833_init_early(void) +{ + fh_clk_init(); + fh_pinctrl_init(VA_PMU_REG_BASE + 0x80); +} + +MACHINE_START(FH8833, "FH8833") + .boot_params = DDR_BASE + 0x100, + .map_io = fh8833_map_io, + .init_irq = fh_intc_init, + .timer = &fh_timer, + .init_machine = fh8833_board_init, + .init_early = fh8833_init_early, +MACHINE_END diff --git a/arch/arm/mach-fh/clock.c b/arch/arm/mach-fh/clock.c new file mode 100644 index 00000000..c883b639 --- /dev/null +++ b/arch/arm/mach-fh/clock.c @@ -0,0 +1,638 @@ +/* + * Clock and PLL control for FH devices + * + * Copyright (C) 2014 Fullhan Microelectronics 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PROC_FILE "driver/clock" + +static LIST_HEAD(clocks); +static DEFINE_MUTEX(clocks_mutex); +static DEFINE_SPINLOCK(clocks_lock); + +struct proc_dir_entry *proc_file; + + +//#define FH_CLK_DEBUG + +#if defined(FH_CLK_DEBUG) +#define PRINT_CLK_DBG(fmt, args...) \ + do \ + { \ + printk("FH_CLK_DEBUG: "); \ + printk(fmt, ##args); \ + } while (0) +#else +#define PRINT_CLK_DBG(fmt, args...) \ + do \ + { \ + } while (0) +#endif + + +void clk_set_clk_sel(unsigned int reg) +{ + fh_pmu_set_reg(REG_PMU_CLK_SEL, reg); +} +EXPORT_SYMBOL(clk_set_clk_sel); + +unsigned int clk_get_clk_sel(void) +{ + return fh_pmu_get_reg(REG_PMU_CLK_SEL); +} +EXPORT_SYMBOL(clk_get_clk_sel); + +#ifdef FH_CLOCK_DEBUG +static void __clk_sel_ddr_clk(int source) +{ + unsigned int clk_sel; + int shift = 24; + clk_sel = clk_get_clk_sel(); + clk_sel &= ~(0x1 << shift); + clk_sel |= (source & 0x1) << shift; + clk_set_clk_sel(clk_sel); +} + +static void __clk_sel_pix_clk(int source) +{ + unsigned int clk_sel; + int shift = 4; + clk_sel = clk_get_clk_sel(); + clk_sel &= ~(0x3 << shift); + clk_sel |= (source & 0x3) << shift; + clk_set_clk_sel(clk_sel); +} + +static void __clk_sel_ac_clk(int source) +{ + unsigned int clk_sel; + int shift = 0; + clk_sel = clk_get_clk_sel(); + clk_sel &= ~(0x1 << shift); + clk_sel |= (source & 0x1) << shift; + clk_set_clk_sel(clk_sel); +} +#endif + + +static void fh_clk_enable(struct clk *clk) +{ + unsigned int reg; + + if (clk->flag & CLOCK_NOGATE) { + PRINT_CLK_DBG("%s, %s has no gate register\n", __func__, clk->name); + return; + } + + reg = fh_pmu_get_reg(clk->en_reg_offset); + PRINT_CLK_DBG("%s, clk: %s, reg: 0x%x\n", __func__, clk->name, reg); + reg &= ~(clk->en_reg_mask); + fh_pmu_set_reg(clk->en_reg_offset, reg); + PRINT_CLK_DBG("%s, clk: %s, after mask: 0x%x\n", __func__, clk->name, reg); +} + +static void fh_clk_disable(struct clk *clk) +{ + unsigned int reg; + + if (clk->flag & CLOCK_NOGATE) { + PRINT_CLK_DBG("%s, %s has no gate register\n", __func__, clk->name); + return; + } + + reg = fh_pmu_get_reg(clk->en_reg_offset); + reg |= clk->en_reg_mask; + fh_pmu_set_reg(clk->en_reg_offset, reg); + + PRINT_CLK_DBG("%s, clk: %s, reg: 0x%x\n", __func__, clk->name, reg); +} + +static int fh_clk_get_sel(struct clk *clk) +{ + unsigned int reg, shift; + int ret; + + if (!(clk->flag & CLOCK_MULTI_PARENT)) + return 0; + + shift = ffs(clk->sel_reg_mask) - 1; + reg = fh_pmu_get_reg(clk->sel_reg_offset); + reg &= clk->sel_reg_mask; + ret = reg >> shift; + PRINT_CLK_DBG("%s, clk: %s, sel: %d\n", __func__, clk->name, ret); + + return ret; +} + +static void fh_clk_set_sel(struct clk *clk, int sel) +{ + unsigned int reg, shift; + + if (!(clk->flag & CLOCK_MULTI_PARENT)) { + PRINT_CLK_DBG("%s, clk: %s has only one parent\n", __func__, clk->name); + return; + } + + clk->select = sel; + shift = ffs(clk->sel_reg_mask) - 1; + reg = fh_pmu_get_reg(clk->sel_reg_offset); + reg &= ~(clk->sel_reg_mask); + reg |= (sel << shift); + fh_pmu_set_reg(clk->rst_reg_offset, reg); + PRINT_CLK_DBG("%s, clk: %s, select: %d, reg: 0x%x\n", __func__, clk->name, sel, + reg); +} + +static unsigned long fh_clk_get_pll_rate(struct clk *clk) +{ + unsigned int reg, m, n, od, no = 1, i; + + reg = fh_pmu_get_reg(clk->div_reg_offset); + m = reg & 0xff; + n = (reg >> 8) & 0xf; + od = (reg >> 16) & 0x3; + + for(i=0; ifrequency = OSC_FREQUENCY * m / n / no; + + return clk->frequency; +} + +static int fh_clk_get_div(struct clk *clk) +{ + unsigned int reg, shift; + int ret; + + if (clk->flag & (CLOCK_NODIV | CLOCK_FIXED)) + return 0; + + shift = ffs(clk->div_reg_mask) - 1; + reg = fh_pmu_get_reg(clk->div_reg_offset); + PRINT_CLK_DBG("%s, clk: %s, reg: 0x%x\n", __func__, clk->name, reg); + reg &= clk->div_reg_mask; + PRINT_CLK_DBG("%s, clk: %s, shift: %d, after mask: 0x%x\n", __func__, clk->name, + shift, reg); + ret = reg >> shift; + PRINT_CLK_DBG("%s, clk: %s, div: %d\n", __func__, clk->name, ret); + PRINT_CLK_DBG("%s, clk: %s, div_mask: 0x%x, div_offset: 0x%x\n", + __func__, clk->name, clk->div_reg_mask, clk->div_reg_offset); + + return ret; +} + +static void fh_clk_set_div(struct clk *clk, int div) +{ + unsigned int reg, shift; + + if (clk->flag & CLOCK_NODIV) { + PRINT_CLK_DBG("%s, clk: %s has no divide\n", __func__, clk->name); + return; + } + + shift = ffs(clk->div_reg_mask) - 1; + + if(div > clk->div_reg_mask >> shift) + { + pr_err("%s, clk: %s, curr div %d is too big, max is %d\n", + __func__, clk->name, div, clk->div_reg_mask >> shift); + return; + } + + clk->divide = div; + + reg = fh_pmu_get_reg(clk->div_reg_offset); + PRINT_CLK_DBG("%s, clk: %s, reg: 0x%x\n", __func__, clk->name, reg); + reg &= ~(clk->div_reg_mask); + reg |= (div << shift); + PRINT_CLK_DBG("%s, clk: %s, shift: %d, after mask: 0x%x\n", __func__, clk->name, + shift, reg); + fh_pmu_set_reg(clk->div_reg_offset, reg); + PRINT_CLK_DBG("%s, clk: %s, div: %d, reg: 0x%x\n", __func__, clk->name, div, + reg); + PRINT_CLK_DBG("%s, clk: %s, div_mask: 0x%x, div_offset: 0x%x\n", + __func__, clk->name, clk->div_reg_mask, clk->div_reg_offset); + +} + +unsigned long fh_clk_get_rate(struct clk *clk) +{ + if (clk->flag & CLOCK_FIXED) { + PRINT_CLK_DBG("%s, clk: %s is fixed clock, rate: %lu\n", __func__, clk->name, + clk->frequency); + return clk->frequency; + } + + if (clk->flag & CLOCK_PLL) { + PRINT_CLK_DBG("%s, clk: %s is a PLL clock\n", __func__, clk->name); + return fh_clk_get_pll_rate(clk); + } + + + clk->select = fh_clk_get_sel(clk); + clk->divide = fh_clk_get_div(clk) + 1; + + if (clk->select > CLOCK_MAX_PARENT) { + pr_err("ERROR, %s, clk: %s, select is not correct, clk->select: %d\n", __func__, + clk->name, clk->select); + return 0; + } + + if (!clk->parent[clk->select]) { + pr_err("ERROR, %s, clk: %s has no parent and is not a fixed clock\n", __func__, + clk->name); + return 0; + } + + clk->frequency = clk->parent[clk->select]->frequency / clk->prediv; + clk->frequency /= clk->divide; + + PRINT_CLK_DBG("%s, clk: %s, rate: %lu\n", __func__, clk->name, clk->frequency); + + return clk->frequency; +} + +void fh_clk_set_rate(struct clk *clk, unsigned long rate) +{ + if (clk->flag & CLOCK_FIXED) { + pr_err("%s, clk: %s is fixed clock, rate: %lu\n", __func__, clk->name, + clk->frequency); + return; + } + + if (clk->flag & CLOCK_PLL) { + pr_err("%s, clk: %s is a PLL clock, changing frequency is not recommended\n", + __func__, clk->name); + return; + } + + if (clk->select > CLOCK_MAX_PARENT) { + pr_err("ERROR, %s, clk: %s, select is not correct, clk->select: %d\n", __func__, + clk->name, clk->select); + return; + } + + if (!clk->parent[clk->select]) { + pr_err("ERROR, %s, clk: %s has no parent and is not a fixed clock\n", __func__, + clk->name); + return; + } + + clk->frequency = clk->parent[clk->select]->frequency / clk->prediv; + clk->divide = clk->frequency / rate; + PRINT_CLK_DBG("%s, clk: %s, set rate: %lu, divide: %d\n", __func__, clk->name, + rate, clk->divide); + fh_clk_set_div(clk, clk->divide - 1); + + clk->frequency = rate; + + PRINT_CLK_DBG("%s, clk: %s, rate: %lu\n", __func__, clk->name, clk->frequency); +} + +void fh_clk_reset(struct clk *clk) +{ + unsigned int reg; + + if (clk->flag & CLOCK_NORESET) { + pr_err("%s, clk: %s has no reset\n", __func__, clk->name); + return; + } + + reg = 0xffffffff & ~(clk->rst_reg_mask); + + fh_pmu_set_reg(clk->rst_reg_offset, reg); + while (fh_pmu_get_reg(clk->rst_reg_offset) != 0xffffffff) { + + } + PRINT_CLK_DBG("%s, clk: %s has been reset\n", __func__, clk->name); +} + +int clk_enable(struct clk *clk) +{ + unsigned long flags; + + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + spin_lock_irqsave(&clocks_lock, flags); + fh_clk_enable(clk); + spin_unlock_irqrestore(&clocks_lock, flags); + + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ + unsigned long flags; + + if (clk == NULL || IS_ERR(clk)) + return; + + spin_lock_irqsave(&clocks_lock, flags); + fh_clk_disable(clk); + spin_unlock_irqrestore(&clocks_lock, flags); +} +EXPORT_SYMBOL(clk_disable); + + +unsigned long clk_get_rate(struct clk *clk) +{ + unsigned long flags, rate; + + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + spin_lock_irqsave(&clocks_lock, flags); + + rate = fh_clk_get_rate(clk); + + spin_unlock_irqrestore(&clocks_lock, flags); + + return rate; +} +EXPORT_SYMBOL(clk_get_rate); + + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long flags, real_rate; + int ret = -EINVAL; + + if (clk == NULL || IS_ERR(clk)) + return ret; + + spin_lock_irqsave(&clocks_lock, flags); + fh_clk_set_rate(clk, rate); + real_rate = clk_get_rate(clk); + if(rate != real_rate) + { + printk("WARN: set clk %s to %ld, but get %ld\n", clk->name, rate, real_rate); + } + spin_unlock_irqrestore(&clocks_lock, flags); + + return 0; +} +EXPORT_SYMBOL(clk_set_rate); + +void clk_reset(struct clk *clk) +{ + unsigned long flags; + + if (clk == NULL || IS_ERR(clk)) + return; + + spin_lock_irqsave(&clocks_lock, flags); + fh_clk_reset(clk); + spin_unlock_irqrestore(&clocks_lock, flags); +} +EXPORT_SYMBOL(clk_reset); + +void clk_change_parent(struct clk *clk, int select) +{ + unsigned long flags; + + if (clk == NULL || IS_ERR(clk)) + return; + + spin_lock_irqsave(&clocks_lock, flags); + fh_clk_set_sel(clk, select); + spin_unlock_irqrestore(&clocks_lock, flags); +} +EXPORT_SYMBOL(clk_change_parent); + +int clk_register(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + if (WARN(clk->parent[clk->select] && !clk->parent[clk->select]->frequency, + "CLK: %s parent %s has no rate!\n", + clk->name, clk->parent[clk->select]->name)) + return -EINVAL; + + clk_get_rate(clk); + + PRINT_CLK_DBG("clk: %s has been registered, div: %d, sel: %d\n", + clk->name, clk->divide, clk->select); + + mutex_lock(&clocks_mutex); + list_add_tail(&clk->list, &clocks); + mutex_unlock(&clocks_mutex); + + return 0; +} +EXPORT_SYMBOL(clk_register); + +void clk_unregister(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk)) + return; + + mutex_lock(&clocks_mutex); + list_del(&clk->list); + mutex_unlock(&clocks_mutex); +} +EXPORT_SYMBOL(clk_unregister); + + +static void del_char(char* str,char ch) +{ + char *p = str; + char *q = str; + while(*q) + { + if (*q !=ch) + { + *p++ = *q; + } + q++; + } + *p='\0'; +} + +static ssize_t fh_clk_proc_write(struct file *filp, const char *buf, size_t len, loff_t *off) +{ + int i, ret; + char message[64] = {0}; + char * const delim = ","; + char *cur = message; + char* param_str[4]; + unsigned int param[4]; + struct clk *clk; + + len = (len > 64) ? 64 : len; + + if (copy_from_user(message, buf, len)) + return -EFAULT; + + for(i=0; i<3; i++) + { + param_str[i] = strsep(&cur, delim); + if(!param_str[i]) + { + pr_err("%s: ERROR: parameter[%d] is empty\n", __func__, i); + pr_err("[clk name], [enable/disable], [clk rate]\n"); + return -EINVAL; + } + else + { + del_char(param_str[i], ' '); + del_char(param_str[i], '\n'); + } + } + + clk = clk_get(NULL, param_str[0]); + if(!clk) + { + pr_err("%s: ERROR: clk %s is not found\n", __func__, param_str[0]); + pr_err("[clk name], [enable/disable], [clk rate]\n"); + return -EINVAL; + } + + param[2] = (u32)simple_strtoul(param_str[2], NULL, 10); + if(param[2] < 0) + { + pr_err("ERROR: parameter[2] is incorrect\n"); + return -EINVAL; + } + + ret = clk_set_rate(clk, param[2]); + if(ret) + { + pr_err("set clk rate failed\n, ret=%d\n", ret); + } + + if(!strcmp(param_str[1], "enable")) + { + clk_enable(clk); + printk("clk %s enabled\n", param_str[0]); + } + else if(!strcmp(param_str[1], "disable")) + { + clk_disable(clk); + printk("clk %s disabled\n", param_str[0]); + } + else + { + pr_err("%s: ERROR: parameter[1]:%s is incorrect\n", __func__, param_str[1]); + pr_err("[clk name], [enable/disable], [clk rate]\n"); + return -EINVAL; + } + + return len; +} + + +static void *v_seq_start(struct seq_file *s, loff_t *pos) +{ + static unsigned long counter = 0; + if (*pos == 0) + return &counter; + else { + *pos = 0; + return NULL; + } +} + +static void *v_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + (*pos)++; + return NULL; +} + +static void v_seq_stop(struct seq_file *s, void *v) +{ + +} + +static int v_seq_show(struct seq_file *sfile, void *v) +{ + + struct clk_lookup *clock_lookup; + struct clk *clk; + unsigned long rate; + + seq_printf(sfile, "\nPLL Information: \n"); + + for (clock_lookup = fh_clks; clock_lookup->clk; clock_lookup++) { + clk = clock_lookup->clk; + rate = clk_get_rate(clk); + seq_printf(sfile, "\t%-20s \t%9lu HZ\n", clk->name, rate); + } + return 0; +} + +static const struct seq_operations fh_clk_seq_ops = { + .start = v_seq_start, + .next = v_seq_next, + .stop = v_seq_stop, + .show = v_seq_show +}; + +static int fh_clk_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &fh_clk_seq_ops); +} + + +static struct file_operations fh_clk_proc_ops = { + .owner = THIS_MODULE, + .open = fh_clk_proc_open, + .read = seq_read, + .write = fh_clk_proc_write, + .release = seq_release, +}; + +int __init fh_clk_procfs_init(void) +{ + proc_file = create_proc_entry(PROC_FILE, 0644, NULL); + if (proc_file) + proc_file->proc_fops = &fh_clk_proc_ops; + else + pr_err("clock, create proc fs failed\n"); + + return 0; +} + +int __init fh_clk_init(void) +{ + struct clk_lookup *clock_lookup; + struct clk *clk; + size_t num_clocks = 0; + + for (clock_lookup = fh_clks; clock_lookup->clk; clock_lookup++) { + clk = clock_lookup->clk; + num_clocks++; + clk_register(clk); + if (clk->def_rate) + clk_set_rate(clk, clk->def_rate); + } + clkdev_add_table(fh_clks, num_clocks); + return 0; +} diff --git a/arch/arm/mach-fh/fh8833.c b/arch/arm/mach-fh/fh8833.c new file mode 100644 index 00000000..daac50e7 --- /dev/null +++ b/arch/arm/mach-fh/fh8833.c @@ -0,0 +1,466 @@ +/* + * Fullhan FH8833 board support + * + * Copyright (C) 2014 Fullhan Microelectronics 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +/* + * external oscillator + * fixed to 24M + */ +static struct clk osc_clk = { + .name = "osc_clk", + .frequency = OSC_FREQUENCY, + .flag = CLOCK_FIXED, +}; + +/* + * phase-locked-loop device, + * generates a higher frequency clock + * from the external oscillator reference + */ +static struct clk pll0_clk = { + .name = "pll0_clk", + .flag = CLOCK_PLL, + .parent = {&osc_clk}, + .div_reg_offset = REG_PMU_PLL0, +}; + +static struct clk pll1_clk = { + .name = "pll1_clk", + .flag = CLOCK_PLL, + .parent = {&osc_clk}, + .div_reg_offset = REG_PMU_PLL1, +}; + +/* + * CPU + */ +static struct clk arm_clk = { + .name = "arm_clk", + .flag = CLOCK_NOGATE, + .parent = {&pll0_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV0, + .div_reg_mask = 0xf, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x1, +}; + +static struct clk arc_clk = { + .name = "arc_clk", + .flag = CLOCK_NOGATE | CLOCK_NODIV, + .parent = {&pll0_clk}, + .prediv = 1, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x400000, +}; + +/* + * BUS + */ +static struct clk axi_clk = { + .name = "axi_clk", + .flag = CLOCK_NOGATE | CLOCK_NODIV | CLOCK_NORESET, + .parent = {&arm_clk}, + .prediv = 2, +}; + +static struct clk ahb_clk = { + .name = "ahb_clk", + .flag = CLOCK_NOGATE | CLOCK_NORESET, + .parent = {&pll0_clk}, + .prediv = 2, + .div_reg_offset = REG_PMU_CLK_DIV0, + .div_reg_mask = 0xf0000, +}; + +static struct clk apb_clk = { + .name = "apb_clk", + .flag = CLOCK_NOGATE | CLOCK_NORESET | CLOCK_NODIV, + .parent = {&ahb_clk}, + .prediv = 1, +}; + + +/* + * ip + */ +static struct clk ddr_clk = { + .name = "ddr_clk", + .parent = {&pll0_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV1, + .div_reg_mask = 0xf, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x40, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x8, +}; + +static struct clk isp_aclk = { + .name = "isp_aclk", + .flag = CLOCK_NORESET, + .parent = {&pll0_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV0, + .div_reg_mask = 0xf00, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x1, +}; + +static struct clk pae_clk = { + .name = "pae_clk", + .flag = CLOCK_NORESET, + .parent = {&pll0_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV0, + .div_reg_mask = 0x7000000, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x10, +}; + +static struct clk bgm_clk = { + .name = "bgm_clk", + .flag = CLOCK_NORESET, + .parent = {&isp_aclk}, + .prediv = 1, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x40000, +}; + +static struct clk cis_clk_out = { + .name = "cis_clk_out", + .flag = CLOCK_NORESET, + .parent = {&pll0_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV1, + .div_reg_mask = 0xff0000, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x800000, +}; + +static struct clk cis_clk_out_revert = { + .name = "cis_clk_out_revert", + .flag = CLOCK_NOGATE | CLOCK_NORESET | CLOCK_NODIV, + .parent = {&cis_clk_out}, + .prediv = 1, +}; + +static struct clk mipi_dphy_clk = { + .name = "mipi_dphy_clk", + .flag = CLOCK_NORESET, + .parent = {&pll0_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV2, + .div_reg_mask = 0x1f0000, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x100000, +}; + +static struct clk mipi_pix_clk = { + .name = "mipi_pix_clk", + .flag = CLOCK_NORESET | CLOCK_NOGATE, + .parent = {&pll0_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV2, + .div_reg_mask = 0xf000000, +}; + +static struct clk pix_clk = { + .name = "pix_clk", + .flag = CLOCK_NORESET | CLOCK_NODIV | CLOCK_MULTI_PARENT, + .parent = {&cis_clk_out, &cis_clk_out_revert, &mipi_pix_clk}, + .prediv = 1, + .sel_reg_offset = REG_PMU_CLK_SEL, + .sel_reg_mask = 0x30, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x400000, +}; + +static struct clk pts_clk = { + .name = "pts_clk", + .parent = {&pll1_clk}, + .prediv = 10, + .div_reg_offset = REG_PMU_CLK_DIV2, + .div_reg_mask = 0x1ff, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x80000, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x20000, +}; + +static struct clk spi0_clk = { + .name = "spi0_clk", + .parent = {&pll1_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV3, + .div_reg_mask = 0xff, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x80, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x100, +}; + +static struct clk spi1_clk = { + .name = "spi1_clk", + .parent = {&pll1_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV3, + .div_reg_mask = 0xff0000, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x100, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x200, +}; + +static struct clk spi2_clk = { + .name = "spi2_clk", + .parent = {&pll1_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV3, + .div_reg_mask = 0xf000, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x2, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x100000, +}; + +static struct clk sdc0_clk = { + .name = "sdc0_clk", + .parent = {&pll1_clk}, + .prediv = 2, + .div_reg_offset = REG_PMU_CLK_DIV3, + .div_reg_mask = 0xf00, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x200, + .rst_reg_offset = REG_PMU_SWRST_AHB_CTRL, + .rst_reg_mask = 0x4, +}; + +static struct clk sdc1_clk = { + .name = "sdc1_clk", + .parent = {&pll1_clk}, + .prediv = 2, + .div_reg_offset = REG_PMU_CLK_DIV3, + .div_reg_mask = 0xf000000, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x400, + .rst_reg_offset = REG_PMU_SWRST_AHB_CTRL, + .rst_reg_mask = 0x2, +}; + +static struct clk uart0_clk = { + .name = "uart0_clk", + .parent = {&pll1_clk}, + .prediv = 10, + .div_reg_offset = REG_PMU_CLK_DIV4, + .div_reg_mask = 0x1f, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x2000, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x4000, +}; + +static struct clk uart1_clk = { + .name = "uart1_clk", + .parent = {&pll1_clk}, + .prediv = 10, + .div_reg_offset = REG_PMU_CLK_DIV4, + .div_reg_mask = 0x1f00, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x4000, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x8000, +}; + +static struct clk i2c0_clk = { + .name = "i2c0_clk", + .parent = {&pll1_clk}, + .prediv = 20, + .div_reg_offset = REG_PMU_CLK_DIV4, + .div_reg_mask = 0x3f0000, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x1000, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x400, +}; + +static struct clk i2c1_clk = { + .name = "i2c1_clk", + .parent = {&pll1_clk}, + .prediv = 20, + .div_reg_offset = REG_PMU_CLK_DIV4, + .div_reg_mask = 0x3f000000, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x8000000, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x800, +}; + +static struct clk pwm_clk = { + .name = "pwm_clk", + .parent = {&pll1_clk}, + .prediv = 2, + .div_reg_offset = REG_PMU_CLK_DIV5, + .div_reg_mask = 0xff, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x10000, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x80, + .def_rate = 25000000, +}; + +static struct clk wdt_clk = { + .name = "wdt_clk", + .flag = CLOCK_NOGATE, + .parent = {&ahb_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV5, + .div_reg_mask = 0xff00, + .rst_reg_offset = REG_PMU_SWRST_APB_CTRL, + .rst_reg_mask = 0x100000, +}; + + +static struct clk tmr0_clk = { + .name = "tmr0_clk", + .parent = {&pll1_clk}, + .prediv = 10, + .div_reg_offset = REG_PMU_CLK_DIV5, + .div_reg_mask = 0xff0000, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x20000, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x40000, +}; + +static struct clk ac_clk = { + .name = "ac_clk", + .parent = {&pll1_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV6, + .div_reg_mask = 0x3f, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x800, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x1000, +}; + +static struct clk i2s_clk = { + .name = "i2s_clk", + .parent = {&ac_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV6, + .div_reg_mask = 0x3f00, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x1000000, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x2000, +}; + +static struct clk sadc_clk = { + .name = "sadc_clk", + .parent = {&pll1_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV6, + .div_reg_mask = 0x7f0000, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x4000000, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x10000, +}; + +static struct clk eth_clk = { + .name = "eth_clk", + .parent = {&pll1_clk}, + .prediv = 2, + .div_reg_offset = REG_PMU_CLK_DIV6, + .div_reg_mask = 0xf000000, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x72000000, + .rst_reg_offset = REG_PMU_SWRST_AHB_CTRL, + .rst_reg_mask = 0x20000, +}; + +static struct clk efuse_clk = { + .name = "efuse_clk", + .parent = {&pll1_clk}, + .prediv = 1, + .div_reg_offset = REG_PMU_CLK_DIV1, + .div_reg_mask = 0x3f000000, + .en_reg_offset = REG_PMU_CLK_GATE, + .en_reg_mask = 0x200000, + .rst_reg_offset = REG_PMU_SWRST_MAIN_CTRL, + .rst_reg_mask = 0x800000, +}; + +struct clk_lookup fh_clks[] = { + CLK(NULL, "osc_clk", &osc_clk), + CLK(NULL, "pll0_clk", &pll0_clk), + CLK(NULL, "pll1_clk", &pll1_clk), + + CLK(NULL, "arm_clk", &arm_clk), + CLK(NULL, "arc_clk", &arc_clk), + CLK(NULL, "axi_clk", &axi_clk), + CLK(NULL, "ahb_clk", &ahb_clk), + CLK(NULL, "apb_clk", &apb_clk), + + CLK(NULL, "ddr_clk", &ddr_clk), + CLK(NULL, "isp_aclk", &isp_aclk), + CLK(NULL, "pae_clk", &pae_clk), + CLK(NULL, "bgm_clk", &bgm_clk), + + CLK(NULL, "cis_clk_out", &cis_clk_out), + CLK(NULL, "cis_clk_out_revert", &cis_clk_out_revert), + CLK(NULL, "mipi_dphy_clk", &mipi_dphy_clk), + CLK(NULL, "mipi_pix_clk", &mipi_pix_clk), + CLK(NULL, "pix_clk", &pix_clk), + CLK(NULL, "pts_clk", &pts_clk), + + CLK(NULL, "spi0_clk", &spi0_clk), + CLK(NULL, "spi1_clk", &spi1_clk), + CLK(NULL, "spi2_clk", &spi2_clk), + CLK(NULL, "sdc0_clk", &sdc0_clk), + CLK(NULL, "sdc1_clk", &sdc1_clk), + CLK(NULL, "uart0_clk", &uart0_clk), + CLK(NULL, "uart1_clk", &uart1_clk), + CLK(NULL, "i2c0_clk", &i2c0_clk), + CLK(NULL, "i2c1_clk", &i2c1_clk), + CLK(NULL, "pwm_clk", &pwm_clk), + CLK(NULL, "wdt_clk", &wdt_clk), + CLK(NULL, "tmr0_clk", &tmr0_clk), + CLK(NULL, "ac_clk", &ac_clk), + CLK(NULL, "i2s_clk", &i2s_clk), + CLK(NULL, "sadc_clk", &sadc_clk), + CLK(NULL, "eth_clk", ð_clk), + CLK(NULL, "efuse_clk", &efuse_clk), + + CLK(NULL, NULL, NULL), +}; + +EXPORT_SYMBOL(fh_clks); diff --git a/arch/arm/mach-fh/fh_simple_timer.c b/arch/arm/mach-fh/fh_simple_timer.c new file mode 100644 index 00000000..b3c8e929 --- /dev/null +++ b/arch/arm/mach-fh/fh_simple_timer.c @@ -0,0 +1,165 @@ +#include +#include + +//#define FH_TIMER_DEBUG +#ifdef FH_TIMER_DEBUG +#define PRINT_DBG(fmt,args...) printk(fmt,##args) +#else +#define PRINT_DBG(fmt,args...) do{} while(0) +#endif + +struct simple_time_base +{ + struct timerqueue_head simple_timer_queue; + int state; +}; + +struct simple_time_base base; + +static void fh_timer_enable(void) +{ + SET_REG(VTIMER(REG_TIMER_CTRL_REG(SIMPLE_TIMER_BASE)), 0x3); +} + +static void fh_timer_disable(void) +{ + SET_REG(VTIMER(REG_TIMER_CTRL_REG(SIMPLE_TIMER_BASE)), 0x0); +} + +static void fh_timer_clearirq(void) +{ + GET_REG(VTIMER(REG_TIMER_EOI_REG(SIMPLE_TIMER_BASE))); +} + +void fh_simple_timer_set_next(long cycles) +{ + long curr_val; + + PRINT_DBG("cycles: %lu\n", cycles); + + if(cycles < 0) + { + pr_err("ERROR: cycles is invaild: %lu\n", cycles); + fh_timer_clearirq(); + fh_timer_disable(); + base.state = SIMPLE_TIMER_ERROR; + return; + } + + SET_REG_M(VTIMER(REG_TIMER_CTRL_REG(SIMPLE_TIMER_BASE)), 0x00, 0x0); + SET_REG(VTIMER(REG_TIMER_LOADCNT(SIMPLE_TIMER_BASE)), cycles); + SET_REG_M(VTIMER(REG_TIMER_CTRL_REG(SIMPLE_TIMER_BASE)), 0x01, 0x1); +#ifdef CONFIG_USE_PTS_AS_CLOCKSOURCE + curr_val = GET_REG(VTIMER(REG_TIMER_CUR_VAL(SIMPLE_TIMER_BASE))) ; + if (curr_val > 0x80000000) { ///0xffff0000) + panic("timer curr %lu, want cycles %lu\n", curr_val, cycles); + + SET_REG_M(VTIMER(REG_TIMER_CTRL_REG(SIMPLE_TIMER_BASE)), 0x01, 0x1); + SET_REG(VTIMER(REG_TIMER_LOADCNT(SIMPLE_TIMER_BASE)), cycles); + + //pmu reset + fh_pmu_set_reg(REG_PMU_SWRST_MAIN_CTRL, 0xfffbffff); + while (fh_pmu_get_reg(REG_PMU_SWRST_MAIN_CTRL) != 0xffffffff) { + + } + } + + fh_pmu_set_reg(REG_PMU_SWRST_MAIN_CTRL, 0xfffbffff); + while (fh_pmu_get_reg(REG_PMU_SWRST_MAIN_CTRL) != 0xffffffff) { + + } +#endif + +} + +int fh_simple_timer_create(struct fh_simple_timer* new) +{ + if(base.state == SIMPLE_TIMER_START) + { + pr_err("ERROR: simple timer is working\n"); + return 0; + } + timerqueue_init(&new->node); + new->node.expires = new->it_value; + timerqueue_add(&base.simple_timer_queue, &new->node); + return 0; +} +EXPORT_SYMBOL_GPL(fh_simple_timer_create); + +int fh_timer_start(void) +{ + struct fh_simple_timer *timer = NULL; + struct timerqueue_node *node; + + node = timerqueue_getnext(&base.simple_timer_queue); + + if(node == NULL) + { + pr_err("ERROR: timequeue is empty\n"); + return -1; + } + + timer = container_of(node, struct fh_simple_timer, node); + + base.state = SIMPLE_TIMER_START; + fh_timer_enable(); + fh_simple_timer_set_next(ktime_to_us(ktime_sub(timer->it_value, timer->it_delay))); + return 0; +} +EXPORT_SYMBOL_GPL(fh_timer_start); + +int fh_simple_timer_interrupt(void) +{ + ktime_t diff; + struct fh_simple_timer *curr = NULL, *next = NULL; + struct timerqueue_node *node; + + node = timerqueue_getnext(&base.simple_timer_queue); + + if(node == NULL) + { + pr_err("ERROR: timequeue is empty\n"); + fh_timer_clearirq(); + fh_timer_disable(); + base.state = SIMPLE_TIMER_ERROR; + return -1; + } + + curr = container_of(node, struct fh_simple_timer, node); + + timerqueue_del(&base.simple_timer_queue, &curr->node); + + curr->function(curr->param); + + node = timerqueue_getnext(&base.simple_timer_queue); + + if(node == NULL) + { + PRINT_DBG("finished all timers, close device\n"); + fh_timer_clearirq(); + fh_timer_disable(); + base.state = SIMPLE_TIMER_STOP; + return 0; + } + + next = container_of(node, struct fh_simple_timer, node); + + PRINT_DBG("sec: %lu, nsec: %lu\n", ktime_to_timespec(next->it_value).tv_sec, + ktime_to_timespec(next->it_value).tv_nsec); + + diff = ktime_sub(next->it_value, curr->it_value); + + fh_simple_timer_set_next(ktime_to_us(ktime_sub(diff, next->it_delay))); + fh_timer_clearirq(); + return 0; +} + + +int fh_simple_timer_init(void) +{ + base.state = SIMPLE_TIMER_STOP; + timerqueue_init_head(&base.simple_timer_queue); + fh_timer_disable(); + return 0; +} +EXPORT_SYMBOL_GPL(fh_simple_timer_init); diff --git a/arch/arm/mach-fh/include/mach/board_config.h b/arch/arm/mach-fh/include/mach/board_config.h new file mode 100644 index 00000000..128fbcd2 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/board_config.h @@ -0,0 +1,40 @@ +/* + * board_config.h + * + * Created on: Jan 9, 2017 + * Author: duobao + */ + +#ifndef BOARD_CONFIG_H_ +#define BOARD_CONFIG_H_ + +/* + * GPIO0 -> IRCUT_ON + * GPIO1 -> IRCUT_OFF + * GPIO2 -> PHY Reset + * GPIO3 -> IR + * GPIO13 -> Sensor Reset + * GPIO14 -> Sensor Power Down + * GPIO55 -> CSN1 + */ + +#define CONFIG_GPIO_EMACPHY_RESET 2 +#define CONFIG_GPIO_EMACPHY_RXDV 41 +#define CONFIG_SD_WP_FIXED + +#define CONFIG_PINCTRL_SELECT \ + "MIPI", "RMII", "UART0", "USB", "DWI2S", \ + "I2C0", "SSI0", "SD0_CARD_1BIT", \ + "GPIO0", "GPIO1", "GPIO2", "GPIO3", \ + "GPIO13", \ + \ + "GPIO4", "GPIO11", "GPIO5", "GPIO6", "GPIO7", \ + "GPIO8", "GPIO9", "GPIO10", "GPIO14", "GPIO19", \ + "GPIO20", "GPIO21", "GPIO23", "GPIO28", "GPIO29", \ + "GPIO30", "GPIO31", "GPIO32", "GPIO33", "GPIO35", \ + "GPIO36", "GPIO37", "GPIO39", "GPIO40", "GPIO44", \ + "GPIO45", "GPIO47", "GPIO50", "GPIO51", "GPIO55", \ + "GPIO61", \ + + +#endif /* BOARD_CONFIG_H_ */ diff --git a/arch/arm/mach-fh/include/mach/chip.h b/arch/arm/mach-fh/include/mach/chip.h new file mode 100644 index 00000000..ca6bcf56 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/chip.h @@ -0,0 +1,19 @@ +/***************************************************************************** +* +* chip.h +* +* Copyright (c) 2010 Shanghai Fullhan Microelectronics Co., Ltd. +* All Rights Reserved. Confidential. +* +* File Description: +* Chip definition. Include the base address of each module, memory +* address, memory size +* +* Modification History: +* +******************************************************************************/ +#ifndef _CHIP_H_ +#define _CHIP_H_ + +#include +#endif diff --git a/arch/arm/mach-fh/include/mach/clkdev.h b/arch/arm/mach-fh/include/mach/clkdev.h new file mode 100644 index 00000000..14a50488 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/clkdev.h @@ -0,0 +1,15 @@ +#ifndef __MACH_CLKDEV_H +#define __MACH_CLKDEV_H + +struct clk; + +static inline int __clk_get(struct clk *clk) +{ + return 1; +} + +static inline void __clk_put(struct clk *clk) +{ +} + +#endif diff --git a/arch/arm/mach-fh/include/mach/clock.h b/arch/arm/mach-fh/include/mach/clock.h new file mode 100644 index 00000000..a14b3763 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/clock.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2010 Shanghai Fullhan Microelectronics Co., Ltd. + * All Rights Reserved. Confidential. + * + *This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __ASM_ARCH_FH_CLOCK_H +#define __ASM_ARCH_FH_CLOCK_H + +#include +#include + +#define CLOCK_MAX_PARENT 4 + +#define OSC_FREQUENCY (24000000) + +#define CLOCK_FIXED (1<<0) +#define CLOCK_NOGATE (1<<1) +#define CLOCK_NODIV (1<<2) +#define CLOCK_NORESET (1<<3) +#define CLOCK_MULTI_PARENT (1<<4) +#define CLOCK_PLL (1<<5) + + +#define CLK_IOCTL_MAGIC 'c' +#define ENABLE_CLK _IOWR(CLK_IOCTL_MAGIC, 0, unsigned int) +#define DISABLE_CLK _IOWR(CLK_IOCTL_MAGIC, 1, unsigned int) +#define SET_CLK_RATE _IOWR(CLK_IOCTL_MAGIC, 2, unsigned int) +#define GET_CLK_RATE _IOWR(CLK_IOCTL_MAGIC, 3, unsigned int) +#define SET_PMU _IOWR(CLK_IOCTL_MAGIC, 4, unsigned int) +#define GET_PMU _IOWR(CLK_IOCTL_MAGIC, 5, unsigned int) + +#define CLK_IOCTL_MAXNR 8 + + +#define CLK(dev, con, ck) \ + { \ + .dev_id = dev, \ + .con_id = con, \ + .clk = ck, \ + } + +struct clk_usr { + char *name; + unsigned long frequency; +}; + + +struct clk { + struct list_head list; + const char *name; + unsigned long frequency; + unsigned int flag; + int select; + struct clk *parent[CLOCK_MAX_PARENT]; + int prediv; + int divide; + unsigned int div_reg_offset; + unsigned int div_reg_mask; + unsigned int en_reg_offset; + unsigned int en_reg_mask; + unsigned int rst_reg_offset; + unsigned int rst_reg_mask; + unsigned int sel_reg_offset; + unsigned int sel_reg_mask; + unsigned int def_rate; +}; + +extern int clk_register(struct clk *clk); +extern void clk_unregister(struct clk *clk); + +void clk_set_clk_sel(unsigned int reg); +unsigned int clk_get_clk_sel(void); + +int fh_clk_init(void); +int fh_clk_procfs_init(void); +int fh_clk_misc_init(void); + +extern struct clk_lookup fh_clks[]; + +#endif diff --git a/arch/arm/mach-fh/include/mach/ddrc.h b/arch/arm/mach-fh/include/mach/ddrc.h new file mode 100644 index 00000000..b6cdb5b7 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/ddrc.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010 Shanghai Fullhan Microelectronics Co., Ltd. + * All Rights Reserved. Confidential. + * + *This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef DDRC_H_ +#define DDRC_H_ + +#define OFFSET_DENAL_CTL_31 (0x007c) +#define OFFSET_DENAL_CTL_57 (0x00e4) +#define OFFSET_DENAL_CTL_97 (0x0184) + +#define DDRC_CONTROLLER_BUSY (1 << 24) +#define DDRC_CKE_STATUS (1 << 8) + +#define DDRC_LP_CMD_SELFREFRESH (10 << 8) +#define DDRC_LP_CMD_EXITLOWPOWER (1 << 8) + +#define DDRC_LPI_SR_WAKEUP_TIME (3 << 24) +#define DDRC_CKSRX_DELAY (1 << 0) + +#endif /* DDRC_H_ */ diff --git a/arch/arm/mach-fh/include/mach/debug-macro.S b/arch/arm/mach-fh/include/mach/debug-macro.S new file mode 100644 index 00000000..3f542607 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/debug-macro.S @@ -0,0 +1,50 @@ +/* linux/arch/arm/mach-fh/include/mach/debug-macro.S + * + * + * + * 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. +*/ + +/* pull in the relevant register and map files. */ + + /* note, for the boot process to work we have to keep the UART + * virtual address aligned to an 1MiB boundary for the L1 + * mapping the head code makes. We keep the UART virtual address + * aligned and add in the offset when we load the value here. + */ + + +#include +#include +#include +#include + +#include + + .macro addruart, rp, rv + ldr \rp, =CONSOLE_REG_BASE + ldr \rv, =VA_CONSOLE_REG_BASE + .endm + + .macro senduart,data,addr + strb \data, [\addr, #(0x00)] @ Write to Transmitter Holding Register + .endm + + .macro waituart,data,addr +1001: ldr \data, [\addr, #(0x14)] @ Read Status Register + tst \data, #(0x40) @when TX FIFO Full, then wait + beq 1001b + .endm + + .macro busyuart,data,addr +@ stmfd r13!, {r4} +1002: + ldr \data, [\addr, #(0x14)] + tst \data, #(0x40) + beq 1002b + .endm + + + diff --git a/arch/arm/mach-fh/include/mach/entry-macro.S b/arch/arm/mach-fh/include/mach/entry-macro.S new file mode 100644 index 00000000..6eea8639 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/entry-macro.S @@ -0,0 +1,31 @@ +#include +#include + + .macro disable_fiq + .endm + + .macro get_irqnr_preamble, base, tmp + ldr \base, =VA_INTC_REG_BASE + .endm + + .macro arch_ret_to_user, tmp1, tmp2 + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + @ check low interrupts + ldr \irqstat, [\base, #0x30] + mov \irqnr, #31 + ands \irqstat, \irqstat, #0xffffffff + + @ if no low interrupts set, check high interrupts + ldreq \irqstat, [\base, #0x34] + moveq \irqnr, #63 + andeqs \irqstat, \irqstat, #0xffffffff + + @ find first active interrupt source + clzne \irqstat, \irqstat + subne \irqnr, \irqnr, \irqstat + .endm + + .macro irq_prio_table + .endm diff --git a/arch/arm/mach-fh/include/mach/fh8833.h b/arch/arm/mach-fh/include/mach/fh8833.h new file mode 100644 index 00000000..ceed7b96 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/fh8833.h @@ -0,0 +1,258 @@ +/* + * + * Copyright (C) 2015 Fullhan.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __ASM_ARCH_FH8833_H +#define __ASM_ARCH_FH8833_H + +#include + +#define SRAM_GRANULARITY 32 +#define SRAM_SIZE SZ_32K + +#define SIMPLE_TIMER_BASE 2 + +#define RAM_BASE (0x10000000) +#define DDR_BASE (0xA0000000) + +#define PMU_REG_BASE (0xF0000000) +#define TIMER_REG_BASE (0xF0C00000) +#define GPIO0_REG_BASE (0xF0300000) +#define GPIO1_REG_BASE (0xF4000000) +#define UART0_REG_BASE (0xF0700000) +#define UART1_REG_BASE (0xF0800000) +#define SPI0_REG_BASE (0xF0500000) +#define SPI1_REG_BASE (0xF0600000) +#define SPI2_REG_BASE (0xF0640000) +#define INTC_REG_BASE (0xE0200000) +#define GMAC_REG_BASE (0xE0600000) +#define USBC_REG_BASE (0xE0700000) +#define DMAC_REG_BASE (0xE0300000) +#define I2C1_REG_BASE (0xF0B00000) +#define I2C0_REG_BASE (0xF0200000) +#define SDC0_REG_BASE (0xE2000000) +#define SDC1_REG_BASE (0xE2200000) +#define WDT_REG_BASE (0xF0D00000) +#define PWM_REG_BASE (0xF0400000) +#define PAE_REG_BASE (0xE7000000) +#define I2S_REG_BASE (0xF0900000) +#define ACW_REG_BASE (0xF0A00000) +#define SADC_REG_BASE (0xF1200000) +#define EFUSE_REG_BASE (0xF1600000) +#define AES_REG_BASE (0xE8200000) +#define RTC_REG_BASE (0xF1500000) +#define DDRC_REG_BASE (0xED000000) +#define CONSOLE_REG_BASE UART0_REG_BASE +#define FH_UART_NUMBER 2 + +#define PMU_REG_SIZE 0x2018 +#define PMU_DEBUG + +#define REG_PMU_CHIP_ID (0x0000) +#define REG_PMU_IP_VER (0x0004) +#define REG_PMU_FW_VER (0x0008) +#define REG_PMU_SYS_CTRL (0x000c) +#define REG_PMU_PLL0 (0x0010) +#define REG_PMU_PLL1 (0x0014) +#define REG_PMU_PLL2 (0x0018) +#define REG_PMU_CLK_GATE (0x001c) +#define REG_PMU_CLK_SEL (0x0020) +#define REG_PMU_CLK_DIV0 (0x0024) +#define REG_PMU_CLK_DIV1 (0x0028) +#define REG_PMU_CLK_DIV2 (0x002c) +#define REG_PMU_CLK_DIV3 (0x0030) +#define REG_PMU_CLK_DIV4 (0x0034) +#define REG_PMU_CLK_DIV5 (0x0038) +#define REG_PMU_CLK_DIV6 (0x003c) +#define REG_PMU_SWRST_MAIN_CTRL (0x0040) +#define REG_PMU_SWRST_AXI_CTRL (0x0044) +#define REG_PMU_SWRST_AHB_CTRL (0x0048) +#define REG_PMU_SWRST_APB_CTRL (0x004c) +#define REG_PMU_SPC_IO_STATUS (0x0054) +#define REG_PMU_SPC_FUN (0x0058) +#define REG_PMU_DBG_SPOT0 (0x005c) +#define REG_PMU_DBG_SPOT1 (0x0060) +#define REG_PMU_DBG_SPOT2 (0x0064) +#define REG_PMU_DBG_SPOT3 (0x0068) + +#define REG_PMU_PAD_CIS_HSYNC_CFG (0x0080) +#define REG_PMU_PAD_CIS_VSYNC_CFG (0x0084) +#define REG_PMU_PAD_CIS_PCLK_CFG (0x0088) +#define REG_PMU_PAD_CIS_D_0_CFG (0x008c) +#define REG_PMU_PAD_CIS_D_1_CFG (0x0090) +#define REG_PMU_PAD_CIS_D_2_CFG (0x0094) +#define REG_PMU_PAD_CIS_D_3_CFG (0x0098) +#define REG_PMU_PAD_CIS_D_4_CFG (0x009c) +#define REG_PMU_PAD_CIS_D_5_CFG (0x00a0) +#define REG_PMU_PAD_CIS_D_6_CFG (0x00a4) +#define REG_PMU_PAD_CIS_D_7_CFG (0x00a8) +#define REG_PMU_PAD_CIS_D_8_CFG (0x00ac) +#define REG_PMU_PAD_CIS_D_9_CFG (0x00b0) +#define REG_PMU_PAD_CIS_D_10_CFG (0x00b4) +#define REG_PMU_PAD_CIS_D_11_CFG (0x00b8) +#define REG_PMU_PAD_MAC_RMII_CLK_CFG (0x00bc) +#define REG_PMU_PAD_MAC_REF_CLK_CFG (0x00c0) +#define REG_PMU_PAD_MAC_MDC_CFG (0x00c4) +#define REG_PMU_PAD_MAC_MDIO_CFG (0x00c8) +#define REG_PMU_PAD_MAC_COL_MII_CFG (0x00cc) +#define REG_PMU_PAD_MAC_CRS_MII_CFG (0x00d0) +#define REG_PMU_PAD_MAC_RXCK_CFG (0x00d4) +#define REG_PMU_PAD_MAC_RXD0_CFG (0x00d8) +#define REG_PMU_PAD_MAC_RXD1_CFG (0x00dc) +#define REG_PMU_PAD_MAC_RXD2_MII_CFG (0x00e0) +#define REG_PMU_PAD_MAC_RXD3_MII_CFG (0x00e4) +#define REG_PMU_PAD_MAC_RXDV_CFG (0x00e8) +#define REG_PMU_PAD_MAC_TXCK_CFG (0x00ec) +#define REG_PMU_PAD_MAC_TXD0_CFG (0x00f0) +#define REG_PMU_PAD_MAC_TXD1_CFG (0x00f4) +#define REG_PMU_PAD_MAC_TXD2_MII_CFG (0x00f8) +#define REG_PMU_PAD_MAC_TXD3_MII_CFG (0x00fc) +#define REG_PMU_PAD_MAC_TXEN_CFG (0x0100) +#define REG_PMU_PAD_MAC_RXER_MII_CFG (0x0104) +#define REG_PMU_PAD_MAC_TXER_MII_CFG (0x0108) +#define REG_PMU_PAD_GPIO_0_CFG (0x010c) +#define REG_PMU_PAD_GPIO_1_CFG (0x0110) +#define REG_PMU_PAD_GPIO_2_CFG (0x0114) +#define REG_PMU_PAD_GPIO_3_CFG (0x0118) +#define REG_PMU_PAD_GPIO_4_CFG (0x011c) +#define REG_PMU_PAD_GPIO_5_CFG (0x0120) +#define REG_PMU_PAD_GPIO_6_CFG (0x0124) +#define REG_PMU_PAD_GPIO_7_CFG (0x0128) +#define REG_PMU_PAD_GPIO_8_CFG (0x012c) +#define REG_PMU_PAD_GPIO_9_CFG (0x0130) +#define REG_PMU_PAD_GPIO_10_CFG (0x0134) +#define REG_PMU_PAD_GPIO_11_CFG (0x0138) +#define REG_PMU_PAD_GPIO_12_CFG (0x013c) +#define REG_PMU_PAD_GPIO_13_CFG (0x0140) +#define REG_PMU_PAD_GPIO_14_CFG (0x0144) +#define REG_PMU_PAD_UART_RX_CFG (0x0148) +#define REG_PMU_PAD_UART_TX_CFG (0x014c) +#define REG_PMU_PAD_CIS_SCL_CFG (0x0150) +#define REG_PMU_PAD_CIS_SDA_CFG (0x0154) +#define REG_PMU_PAD_I2C_SCL_CFG (0x0158) +#define REG_PMU_PAD_I2C_SDA_CFG (0x015c) +#define REG_PMU_PAD_SSI0_CLK_CFG (0x0160) +#define REG_PMU_PAD_SSI0_TXD_CFG (0x0164) +#define REG_PMU_PAD_SSI0_CSN_0_CFG (0x0168) +#define REG_PMU_PAD_SSI0_CSN_1_CFG (0x016c) +#define REG_PMU_PAD_SSI0_RXD_CFG (0x0170) +#define REG_PMU_PAD_SD0_CD_CFG (0x0174) +#define REG_PMU_PAD_SD0_WP_CFG (0x0178) +#define REG_PMU_PAD_SD0_CLK_CFG (0x017c) +#define REG_PMU_PAD_SD0_CMD_RSP_CFG (0x0180) +#define REG_PMU_PAD_SD0_DATA_0_CFG (0x0184) +#define REG_PMU_PAD_SD0_DATA_1_CFG (0x0188) +#define REG_PMU_PAD_SD0_DATA_2_CFG (0x018c) +#define REG_PMU_PAD_SD0_DATA_3_CFG (0x0190) +#define REG_PMU_PAD_SD1_CD_CFG (0x0194) +#define REG_PMU_PAD_SD1_WP_CFG (0x0198) +#define REG_PMU_PAD_SD1_CLK_CFG (0x019c) +#define REG_PMU_PAD_SD1_CMD_RSP_CFG (0x01a0) +#define REG_PMU_PAD_SD1_DATA_0_CFG (0x01a4) +#define REG_PMU_PAD_SD1_DATA_1_CFG (0x01a8) +#define REG_PMU_PAD_SD1_DATA_2_CFG (0x01ac) +#define REG_PMU_PAD_SD1_DATA_3_CFG (0x01b0) +#define REG_PMU_AXI0_PRIO_CFG0 (0x01b4) +#define REG_PMU_AXI0_PRIO_CFG1 (0x01b8) +#define REG_PMU_AXI1_PRIO_CFG0 (0x01bc) +#define REG_PMU_AXI1_PRIO_CFG1 (0x01c0) +#define REG_PMU_SWRSTN_NSR (0x01c4) +#define REG_PMU_ARM_INT_0 (0x01e0) +#define REG_PMU_ARM_INT_1 (0x01e4) +#define REG_PMU_ARM_INT_2 (0x01e8) +#define REG_PMU_A625_INT_0 (0x01ec) +#define REG_PMU_A625_INT_1 (0x01f0) +#define REG_PMU_A625_INT_2 (0x01f4) +#define REG_PMU_DMA (0x01f8) +#define REG_PMU_WDT_CTRL (0x01fc) +#define REG_PMU_DBG_STAT0 (0x0200) +#define REG_PMU_DBG_STAT1 (0x0204) +#define REG_PMU_DBG_STAT2 (0x0208) +#define REG_PMU_DBG_STAT3 (0x020c) +#define REG_PMU_USB_SYS (0x0210) +#define REG_PMU_USB_CFG (0x0214) +#define REG_PMU_USB_TUNE (0x0218) +#define REG_PMU_PAD_CIS_CLK_CFG (0x021c) +#define REG_PMU_PAEARCBOOT0 (0x1000) +#define REG_PMU_PAEARCBOOT1 (0x1004) +#define REG_PMU_PAEARCBOOT2 (0x1008) +#define REG_PMU_PAEARCBOOT3 (0x100c) +#define REG_PMU_PAE_ARC_START_CTRL (0x1010) +#define REG_PMU_A625BOOT0 (0x2000) +#define REG_PMU_A625BOOT1 (0x2004) +#define REG_PMU_A625BOOT2 (0x2008) +#define REG_PMU_A625BOOT3 (0x200c) +#define REG_PMU_A625_START_CTRL (0x2010) +#define REG_PMU_ARC_INTC_MASK (0x2014) +#define REG_PMU_PAE_ARC_INTC_MASK (0x2018) + +/*ATTENTION: written by ARC */ +#define PMU_ARM_INT_MASK (0x01e0) +#define PMU_ARM_INT_RAWSTAT (0x01e4) +#define PMU_ARM_INT_STAT (0x01e8) + +#define PMU_A625_INT_MASK (0x01ec) +#define PMU_A625_INT_RAWSTAT (0x01f0) +#define PMU_A625_INT_STAT (0x01f4) + +#define ARM_PMU_IRQ 0 +#define DDRC_IRQ 1 +#define WDT_IRQ 2 +#define TMR0_IRQ 3 +#define PAE_ARC_IRQ0 4 +#define PAE_ARC_IRQ1 5 +#define PAE_ARC_IRQ2 6 +#define ISPP_IRQ 7 +#define ISPF_IRQ 8 +#define VPU_IRQ 9 +#define PAE_IRQ 10 +#define I2C0_IRQ 11 +#define I2C1_IRQ 12 +#define JPEG_IRQ 13 +#define BGM_IRQ 14 +#define GMAC_IRQ 15 +#define AES_IRQ 16 +#define SDC0_IRQ 17 +#define SDC1_IRQ 18 +#define ACW_IRQ 19 +#define SADC_IRQ 20 +#define SPI1_IRQ 21 +#define SPI2_IRQ 22 +#define DMAC0_IRQ 23 +#define DMAC1_IRQ 24 +#define I2S0_IRQ 25 +#define GPIO0_IRQ 26 +#define USBC_IRQ 27 +#define SPI0_IRQ 28 +#define ARC_SW_IRQ 29 +#define UART0_IRQ 30 +#define UART1_IRQ 31 +#define ARM_SW_IRQ 32 +#define RTC_IRQ 33 +#define AHBC0_IRQ 34 +#define AHBC1_IRQ 35 +#define PWM_IRQ 36 +#define MIPIC_IRQ 37 +#define MIPI_WRAP_IRQ 38 + +#define GPIO1_IRQ 40 +#define USBC_IDHV_IRQ 41 +#define USBC_OTG_IRQ 42 +#define USBC_DP_IRQ 43 +#define USBC_DM_IRQ 44 + +#define NR_INTERNAL_IRQS (64) +#define NR_EXTERNAL_IRQS (64) +#define NR_IRQS (NR_INTERNAL_IRQS + NR_EXTERNAL_IRQS) + +#endif /* __ASM_ARCH_FH8833_H */ diff --git a/arch/arm/mach-fh/include/mach/fh8833_iopad_mipi.h b/arch/arm/mach-fh/include/mach/fh8833_iopad_mipi.h new file mode 100644 index 00000000..bd9c3146 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/fh8833_iopad_mipi.h @@ -0,0 +1,647 @@ + +#include "pinctrl.h" +#include "pinctrl_osdep.h" +#include "board_config.h" + +PINCTRL_FUNC(CIS_HSYNC, 0, FUNC0, PUPD_DOWN); +PINCTRL_FUNC(GPIO20, 0, FUNC1, PUPD_DOWN); +PINCTRL_FUNC(CIS_VSYNC, 1, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO21, 1, FUNC1, PUPD_UP); +PINCTRL_FUNC(PWM0, 1, FUNC2, PUPD_UP); +PINCTRL_FUNC(UART1_TX, 1, FUNC3, PUPD_UP); +PINCTRL_FUNC(CIS_PCLK, 2, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO19, 2, FUNC1, PUPD_UP); +PINCTRL_FUNC(PWM1, 2, FUNC2, PUPD_UP); +PINCTRL_FUNC(UART1_RX, 2, FUNC3, PUPD_UP); +PINCTRL_FUNC(CIS_D_0, 3, FUNC0, PUPD_DOWN); +PINCTRL_FUNC(GPIO22, 3, FUNC1, PUPD_DOWN); +PINCTRL_FUNC(PWM2, 3, FUNC2, PUPD_DOWN); +PINCTRL_FUNC(USB_PWREN, 3, FUNC3, PUPD_DOWN); +PINCTRL_FUNC(AD_I2S_DI, 3, FUNC4, PUPD_DOWN); +PINCTRL_FUNC(RTC_CLK, 3, FUNC5, PUPD_DOWN); +PINCTRL_FUNC(CIS_D_1, 4, FUNC0, PUPD_DOWN); +PINCTRL_FUNC(GPIO23, 4, FUNC1, PUPD_DOWN); +PINCTRL_FUNC(PWM3, 4, FUNC2, PUPD_DOWN); +PINCTRL_FUNC(AC_MCLK, 4, FUNC3, PUPD_DOWN); +PINCTRL_FUNC(AD_I2S_CLK, 4, FUNC4, PUPD_DOWN); +PINCTRL_FUNC(CIS_D_2, 5, FUNC0, PUPD_DOWN); +PINCTRL_FUNC(GPIO24, 5, FUNC1, PUPD_DOWN); +PINCTRL_FUNC(PWM4, 5, FUNC2, PUPD_DOWN); +PINCTRL_FUNC(I2S_DI, 5, FUNC3, PUPD_DOWN); +PINCTRL_FUNC(AD_I2S_WS, 5, FUNC4, PUPD_DOWN); +PINCTRL_FUNC(CIS_D_3, 6, FUNC0, PUPD_DOWN); +PINCTRL_FUNC(GPIO25, 6, FUNC1, PUPD_DOWN); +PINCTRL_FUNC(PWM5, 6, FUNC2, PUPD_DOWN); +PINCTRL_FUNC(I2S_CLK, 6, FUNC3, PUPD_DOWN); +PINCTRL_FUNC(DA_I2S_DO, 6, FUNC4, PUPD_DOWN); +PINCTRL_FUNC(CIS_D_4, 7, FUNC0, PUPD_DOWN); +PINCTRL_FUNC(GPIO26, 7, FUNC1, PUPD_DOWN); +PINCTRL_FUNC(PWM6, 7, FUNC2, PUPD_DOWN); +PINCTRL_FUNC(I2S_WS, 7, FUNC3, PUPD_DOWN); +PINCTRL_FUNC(DA_I2S_WS, 7, FUNC4, PUPD_DOWN); +PINCTRL_FUNC(CIS_D_5, 8, FUNC0, PUPD_DOWN); +PINCTRL_FUNC(GPIO27, 8, FUNC1, PUPD_DOWN); +PINCTRL_FUNC(PWM7, 8, FUNC2, PUPD_DOWN); +PINCTRL_FUNC(I2S_DO, 8, FUNC3, PUPD_DOWN); +PINCTRL_FUNC(DA_I2S_CLK, 8, FUNC4, PUPD_DOWN); +PINCTRL_FUNC(CIS_D_6, 9, FUNC0, PUPD_DOWN); +PINCTRL_FUNC(GPIO28, 9, FUNC1, PUPD_DOWN); +PINCTRL_FUNC(CIS_D_7, 10, FUNC0, PUPD_DOWN); +PINCTRL_FUNC(GPIO29, 10, FUNC1, PUPD_DOWN); +PINCTRL_FUNC(CIS_D_8, 11, FUNC0, PUPD_DOWN); +PINCTRL_FUNC(GPIO30, 11, FUNC1, PUPD_DOWN); +PINCTRL_FUNC(CIS_D_9, 12, FUNC0, PUPD_DOWN); +PINCTRL_FUNC(GPIO31, 12, FUNC1, PUPD_DOWN); +PINCTRL_FUNC(CIS_D_10, 13, FUNC0, PUPD_DOWN); +PINCTRL_FUNC(GPIO32, 13, FUNC1, PUPD_DOWN); +PINCTRL_FUNC(CIS_D_11, 14, FUNC0, PUPD_DOWN); +PINCTRL_FUNC(GPIO33, 14, FUNC1, PUPD_DOWN); +PINCTRL_FUNC(MAC_RMII_CLK, 15, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO15, 15, FUNC1, PUPD_UP); +PINCTRL_FUNC(SD1_CLK, 15, FUNC2, PUPD_UP); +PINCTRL_FUNC(PWM0, 15, FUNC3, PUPD_UP); +PINCTRL_FUNC(USB_PWREN, 15, FUNC4, PUPD_UP); +PINCTRL_FUNC(I2S_DI, 15, FUNC5, PUPD_UP); +PINCTRL_FUNC(MAC_REF_CLK, 16, FUNC0, PUPD_NONE); +PINCTRL_FUNC(MAC_MDC, 17, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO34, 17, FUNC1, PUPD_UP); +PINCTRL_FUNC(SD1_WP, 17, FUNC2, PUPD_UP); +PINCTRL_FUNC(I2C1_SDA, 17, FUNC3, PUPD_UP); +PINCTRL_FUNC(UART1_TX, 17, FUNC4, PUPD_UP); +PINCTRL_FUNC(SSI1_CLK, 17, FUNC5, PUPD_UP); +PINCTRL_FUNC(MAC_MDIO, 18, FUNC0, PUPD_NONE); +PINCTRL_FUNC(GPIO17, 18, FUNC1, PUPD_NONE); +PINCTRL_FUNC(ARM_JTAG_TDO, 18, FUNC2, PUPD_NONE); +PINCTRL_FUNC(I2C1_SCL, 18, FUNC3, PUPD_NONE); +PINCTRL_FUNC(UART1_RX, 18, FUNC4, PUPD_NONE); +PINCTRL_FUNC(PWM7, 18, FUNC5, PUPD_NONE); +PINCTRL_FUNC(PWM0, 19, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO35, 19, FUNC1, PUPD_UP); +PINCTRL_FUNC(PWM1, 20, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO36, 20, FUNC1, PUPD_UP); +PINCTRL_FUNC(MAC_RXCK, 21, FUNC0, PUPD_NONE); +PINCTRL_FUNC(MAC_RXD_0, 22, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO16, 22, FUNC1, PUPD_UP); +PINCTRL_FUNC(SD1_DATA_0, 22, FUNC2, PUPD_UP); +PINCTRL_FUNC(PWM1, 22, FUNC3, PUPD_UP); +PINCTRL_FUNC(AD_I2S_DI, 22, FUNC4, PUPD_UP); +PINCTRL_FUNC(I2S_CLK, 22, FUNC5, PUPD_UP); +PINCTRL_FUNC(MAC_RXD_1, 23, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO38, 23, FUNC1, PUPD_UP); +PINCTRL_FUNC(SD1_DATA_1, 23, FUNC2, PUPD_UP); +PINCTRL_FUNC(PWM2, 23, FUNC3, PUPD_UP); +PINCTRL_FUNC(AD_I2S_CLK, 23, FUNC4, PUPD_UP); +PINCTRL_FUNC(I2S_WS, 23, FUNC5, PUPD_UP); +PINCTRL_FUNC(PWM2, 24, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO39, 24, FUNC1, PUPD_UP); +PINCTRL_FUNC(PWM3, 25, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO40, 25, FUNC1, PUPD_UP); +PINCTRL_FUNC(MAC_RXDV, 26, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO41, 26, FUNC1, PUPD_UP); +PINCTRL_FUNC(SD1_CD, 26, FUNC2, PUPD_UP); +PINCTRL_FUNC(PWM3, 26, FUNC3, PUPD_UP); +PINCTRL_FUNC(AD_I2S_WS, 26, FUNC4, PUPD_UP); +PINCTRL_FUNC(I2S_DO, 26, FUNC5, PUPD_UP); +PINCTRL_FUNC(MAC_TXCK, 27, FUNC0, PUPD_NONE); +PINCTRL_FUNC(MAC_TXD_0, 28, FUNC0, PUPD_NONE); +PINCTRL_FUNC(GPIO42, 28, FUNC1, PUPD_NONE); +PINCTRL_FUNC(SD1_DATA_2, 28, FUNC2, PUPD_NONE); +PINCTRL_FUNC(PWM4, 28, FUNC3, PUPD_NONE); +PINCTRL_FUNC(DA_I2S_DO, 28, FUNC4, PUPD_NONE); +PINCTRL_FUNC(SSI1_TXD, 28, FUNC5, PUPD_NONE); +PINCTRL_FUNC(MAC_TXD_1, 29, FUNC0, PUPD_NONE); +PINCTRL_FUNC(GPIO43, 29, FUNC1, PUPD_NONE); +PINCTRL_FUNC(SD1_DATA_3, 29, FUNC2, PUPD_NONE); +PINCTRL_FUNC(PWM5, 29, FUNC3, PUPD_NONE); +PINCTRL_FUNC(DA_I2S_WS, 29, FUNC4, PUPD_NONE); +PINCTRL_FUNC(SSI1_RXD, 29, FUNC5, PUPD_NONE); +PINCTRL_FUNC(PWM4, 30, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO44, 30, FUNC1, PUPD_UP); +PINCTRL_FUNC(PWM5, 31, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO45, 31, FUNC1, PUPD_UP); +PINCTRL_FUNC(MAC_TXEN, 32, FUNC0, PUPD_NONE); +PINCTRL_FUNC(GPIO46, 32, FUNC1, PUPD_NONE); +PINCTRL_FUNC(SD1_CMD_RSP, 32, FUNC2, PUPD_NONE); +PINCTRL_FUNC(PWM6, 32, FUNC3, PUPD_NONE); +PINCTRL_FUNC(DA_I2S_CLK, 32, FUNC4, PUPD_NONE); +PINCTRL_FUNC(AC_MCLK, 32, FUNC5, PUPD_NONE); +PINCTRL_FUNC(PWM6, 33, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO47, 33, FUNC1, PUPD_UP); +PINCTRL_FUNC(PWM7, 34, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO37, 34, FUNC1, PUPD_UP); +PINCTRL_FUNC(ARM_JTAG_TRSTN, 35, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO0, 35, FUNC1, PUPD_UP); +PINCTRL_FUNC(SSI1_TXD, 35, FUNC2, PUPD_UP); +PINCTRL_FUNC(SSI2_TXD, 35, FUNC3, PUPD_UP); +PINCTRL_FUNC(PWM0, 35, FUNC4, PUPD_UP); +PINCTRL_FUNC(I2S_DI, 35, FUNC5, PUPD_UP); +PINCTRL_FUNC(ARM_JTAG_TMS, 36, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO1, 36, FUNC1, PUPD_UP); +PINCTRL_FUNC(SSI1_RXD, 36, FUNC2, PUPD_UP); +PINCTRL_FUNC(SSI2_RXD, 36, FUNC3, PUPD_UP); +PINCTRL_FUNC(PWM1, 36, FUNC4, PUPD_UP); +PINCTRL_FUNC(I2S_WS, 36, FUNC5, PUPD_UP); +PINCTRL_FUNC(ARM_JTAG_TCK, 37, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO2, 37, FUNC1, PUPD_UP); +PINCTRL_FUNC(SSI1_CLK, 37, FUNC2, PUPD_UP); +PINCTRL_FUNC(SSI2_CLK, 37, FUNC3, PUPD_UP); +PINCTRL_FUNC(PWM2, 37, FUNC4, PUPD_UP); +PINCTRL_FUNC(I2S_DO, 37, FUNC5, PUPD_UP); +PINCTRL_FUNC(ARM_JTAG_TDI, 38, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO3, 38, FUNC1, PUPD_UP); +PINCTRL_FUNC(SSI1_CSN_0, 38, FUNC2, PUPD_UP); +PINCTRL_FUNC(SSI2_CSN, 38, FUNC3, PUPD_UP); +PINCTRL_FUNC(PWM3, 38, FUNC4, PUPD_UP); +PINCTRL_FUNC(I2S_CLK, 38, FUNC5, PUPD_UP); +PINCTRL_FUNC(GPIO4, 39, FUNC0, PUPD_UP); +PINCTRL_FUNC(ARM_JTAG_TCK, 40, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO5, 40, FUNC1, PUPD_UP); +PINCTRL_FUNC(ARM_JTAG_TRSTN, 41, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO6, 41, FUNC1, PUPD_UP); +PINCTRL_FUNC(ARM_JTAG_TMS, 42, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO7, 42, FUNC1, PUPD_UP); +PINCTRL_FUNC(ARM_JTAG_TDI, 43, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO8, 43, FUNC1, PUPD_UP); +PINCTRL_FUNC(ARM_JTAG_TDO, 44, FUNC0, PUPD_NONE); +PINCTRL_FUNC(GPIO9, 44, FUNC1, PUPD_NONE); +PINCTRL_FUNC(UART1_TX, 45, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO10, 45, FUNC1, PUPD_UP); +PINCTRL_FUNC(UART1_RX, 46, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO11, 46, FUNC1, PUPD_UP); +PINCTRL_FUNC(PWM0, 47, FUNC0, PUPD_NONE); +PINCTRL_FUNC(GPIO12, 47, FUNC1, PUPD_NONE); +PINCTRL_FUNC(CIS_CLK, 47, FUNC2, PUPD_NONE); +PINCTRL_FUNC(PWM1, 48, FUNC0, PUPD_NONE); +PINCTRL_FUNC(GPIO13, 48, FUNC1, PUPD_NONE); +PINCTRL_FUNC(PWM2, 49, FUNC0, PUPD_NONE); +PINCTRL_FUNC(GPIO14, 49, FUNC1, PUPD_NONE); +PINCTRL_FUNC(UART0_RX, 50, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO48, 50, FUNC1, PUPD_UP); +PINCTRL_FUNC(I2S_WS, 50, FUNC2, PUPD_UP); +PINCTRL_FUNC(UART0_TX, 51, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO49, 51, FUNC1, PUPD_UP); +PINCTRL_FUNC(I2S_CLK, 51, FUNC2, PUPD_UP); +PINCTRL_FUNC(I2C0_SCL, 52, FUNC0, PUPD_NONE); +PINCTRL_FUNC(GPIO57, 52, FUNC1, PUPD_NONE); +PINCTRL_FUNC(I2C0_SDA, 53, FUNC0, PUPD_NONE); +PINCTRL_FUNC(GPIO56, 53, FUNC1, PUPD_NONE); +PINCTRL_FUNC(I2C1_SCL, 54, FUNC0, PUPD_NONE); +PINCTRL_FUNC(GPIO51, 54, FUNC1, PUPD_NONE); +PINCTRL_FUNC(I2S_DI, 54, FUNC2, PUPD_NONE); +PINCTRL_FUNC(I2C1_SDA, 55, FUNC0, PUPD_NONE); +PINCTRL_FUNC(GPIO50, 55, FUNC1, PUPD_NONE); +PINCTRL_FUNC(I2S_DO, 55, FUNC2, PUPD_NONE); +PINCTRL_FUNC(SSI0_CLK, 56, FUNC0, PUPD_NONE); +PINCTRL_FUNC(SSI0_TXD, 57, FUNC0, PUPD_NONE); +PINCTRL_FUNC(SSI0_CSN_0, 58, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO54, 58, FUNC1, PUPD_UP); +PINCTRL_FUNC(SSI0_CSN_1, 59, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO55, 59, FUNC1, PUPD_UP); +PINCTRL_FUNC(USB_PWREN, 59, FUNC2, PUPD_UP); +PINCTRL_FUNC(AC_MCLK, 59, FUNC3, PUPD_UP); +PINCTRL_FUNC(PWM3, 59, FUNC4, PUPD_UP); +PINCTRL_FUNC(UART1_TX, 59, FUNC5, PUPD_UP); +PINCTRL_FUNC(SSI0_RXD, 60, FUNC0, PUPD_UP); +PINCTRL_FUNC(SD0_CD, 61, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO52, 61, FUNC1, PUPD_UP); +PINCTRL_FUNC(ARC_JTAG_TRSTN, 61, FUNC2, PUPD_UP); +PINCTRL_FUNC(PAE_JTAG_TRSTN, 61, FUNC3, PUPD_UP); +PINCTRL_FUNC(PWM5, 61, FUNC4, PUPD_UP); +PINCTRL_FUNC(SSI2_TXD, 61, FUNC5, PUPD_UP); +PINCTRL_FUNC(SD0_WP, 62, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO53, 62, FUNC1, PUPD_UP); +PINCTRL_FUNC(USB_PWREN, 62, FUNC2, PUPD_UP); +PINCTRL_FUNC(SD0_CLK, 63, FUNC0, PUPD_NONE); +PINCTRL_FUNC(GPIO63, 63, FUNC1, PUPD_NONE); +PINCTRL_FUNC(ARC_JTAG_TMS, 63, FUNC2, PUPD_NONE); +PINCTRL_FUNC(PAE_JTAG_TMS, 63, FUNC3, PUPD_NONE); +PINCTRL_FUNC(PWM6, 63, FUNC4, PUPD_NONE); +PINCTRL_FUNC(SSI2_RXD, 63, FUNC5, PUPD_NONE); +PINCTRL_FUNC(SD0_CMD_RSP, 64, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO11, 64, FUNC1, PUPD_UP); +PINCTRL_FUNC(ARC_JTAG_TCK, 64, FUNC2, PUPD_UP); +PINCTRL_FUNC(PAE_JTAG_TCK, 64, FUNC3, PUPD_UP); +PINCTRL_FUNC(PWM7, 64, FUNC4, PUPD_UP); +PINCTRL_FUNC(SSI2_CLK, 64, FUNC5, PUPD_UP); +PINCTRL_FUNC(SD0_DATA_0, 65, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO62, 65, FUNC1, PUPD_UP); +PINCTRL_FUNC(ARC_JTAG_TDI, 65, FUNC2, PUPD_UP); +PINCTRL_FUNC(PAE_JTAG_TDI, 65, FUNC3, PUPD_UP); +PINCTRL_FUNC(PWM4, 65, FUNC4, PUPD_UP); +PINCTRL_FUNC(SSI2_CSN, 65, FUNC5, PUPD_UP); +PINCTRL_FUNC(SD0_DATA_1, 66, FUNC0, PUPD_UP); +PINCTRL_FUNC(GPIO61, 66, FUNC1, PUPD_UP); +PINCTRL_FUNC(ARC_JTAG_TDO, 66, FUNC2, PUPD_UP); +PINCTRL_FUNC(PAE_JTAG_TDO, 66, FUNC3, PUPD_UP); +PINCTRL_FUNC(SD0_WP, 66, FUNC4, PUPD_UP); +PINCTRL_FUNC(UART1_TX, 66, FUNC5, PUPD_UP); + +PINCTRL_MUX(USB_PWREN, 0, &PAD3_USB_PWREN, &PAD15_USB_PWREN, + &PAD59_USB_PWREN, &PAD62_USB_PWREN); +PINCTRL_MUX(AC_MCLK, 2, &PAD4_AC_MCLK, &PAD32_AC_MCLK, &PAD59_AC_MCLK); + +PINCTRL_MUX(ACI2S_AD_CLK, 1, &PAD4_AD_I2S_CLK, &PAD23_AD_I2S_CLK); +PINCTRL_MUX(ACI2S_AD_DI, 1, &PAD3_AD_I2S_DI, &PAD22_AD_I2S_DI); +PINCTRL_MUX(ACI2S_AD_WS, 0, &PAD5_AD_I2S_WS, &PAD26_AD_I2S_WS); +PINCTRL_MUX(ACI2S_DA_CLK, 0, &PAD8_DA_I2S_CLK, &PAD32_DA_I2S_CLK); +PINCTRL_MUX(ACI2S_DA_DO, 0, &PAD6_DA_I2S_DO, &PAD28_DA_I2S_DO); +PINCTRL_MUX(ACI2S_DA_WS, 0, &PAD7_DA_I2S_WS, &PAD29_DA_I2S_WS); + +PINCTRL_MUX(DWI2S_CLK, 0, &PAD6_I2S_CLK, &PAD22_I2S_CLK, + &PAD38_I2S_CLK, &PAD51_I2S_CLK); +PINCTRL_MUX(DWI2S_DI, 0, &PAD5_I2S_DI, &PAD15_I2S_DI, + &PAD35_I2S_DI, &PAD54_I2S_DI); +PINCTRL_MUX(DWI2S_DO, 0, &PAD8_I2S_DO, &PAD26_I2S_DO, + &PAD37_I2S_DO, &PAD55_I2S_DO); +PINCTRL_MUX(DWI2S_WS, 0, &PAD7_I2S_WS, &PAD23_I2S_WS, + &PAD36_I2S_WS, &PAD50_I2S_WS); + +PINCTRL_MUX(ARCJTAG_TCK, 0, &PAD64_ARC_JTAG_TCK); +PINCTRL_MUX(ARCJTAG_TDI, 0, &PAD65_ARC_JTAG_TDI); +PINCTRL_MUX(ARCJTAG_TDO, 0, &PAD66_ARC_JTAG_TDO); +PINCTRL_MUX(ARCJTAG_TMS, 0, &PAD63_ARC_JTAG_TMS); +PINCTRL_MUX(ARCJTAG_TRSTN, 0, &PAD61_ARC_JTAG_TRSTN); + +PINCTRL_MUX(ARMJTAG_TCK, 1, &PAD37_ARM_JTAG_TCK, &PAD40_ARM_JTAG_TCK); +PINCTRL_MUX(ARMJTAG_TDI, 1, &PAD38_ARM_JTAG_TDI, &PAD43_ARM_JTAG_TDI); +PINCTRL_MUX(ARMJTAG_TDO, 1, &PAD18_ARM_JTAG_TDO, &PAD44_ARM_JTAG_TDO); +PINCTRL_MUX(ARMJTAG_TMS, 1, &PAD36_ARM_JTAG_TMS, &PAD42_ARM_JTAG_TMS); +PINCTRL_MUX(ARMJTAG_TRSTN, 1, &PAD35_ARM_JTAG_TRSTN, &PAD41_ARM_JTAG_TRSTN); + +PINCTRL_MUX(PAEJTAG_TCK, 0, &PAD64_PAE_JTAG_TCK); +PINCTRL_MUX(PAEJTAG_TDI, 0, &PAD65_PAE_JTAG_TDI); +PINCTRL_MUX(PAEJTAG_TDO, 0, &PAD66_PAE_JTAG_TDO); +PINCTRL_MUX(PAEJTAG_TMS, 0, &PAD63_PAE_JTAG_TMS); +PINCTRL_MUX(PAEJTAG_TRSTN, 0, &PAD61_PAE_JTAG_TRSTN); + +PINCTRL_MUX(CIS_CLK, 0, &PAD47_CIS_CLK); +PINCTRL_MUX(CIS_PCLK, 0, &PAD2_CIS_PCLK); +PINCTRL_MUX(CIS_HSYNC, 0, &PAD0_CIS_HSYNC); +PINCTRL_MUX(CIS_VSYNC, 0, &PAD1_CIS_VSYNC); +PINCTRL_MUX(CIS_D_0, 0, &PAD3_CIS_D_0); +PINCTRL_MUX(CIS_D_1, 0, &PAD4_CIS_D_1); +PINCTRL_MUX(CIS_D_2, 0, &PAD5_CIS_D_2); +PINCTRL_MUX(CIS_D_3, 0, &PAD6_CIS_D_3); +PINCTRL_MUX(CIS_D_4, 0, &PAD7_CIS_D_4); +PINCTRL_MUX(CIS_D_5, 0, &PAD8_CIS_D_5); +PINCTRL_MUX(CIS_D_6, 0, &PAD9_CIS_D_6); +PINCTRL_MUX(CIS_D_7, 0, &PAD10_CIS_D_7); +PINCTRL_MUX(CIS_D_8, 0, &PAD11_CIS_D_8); +PINCTRL_MUX(CIS_D_9, 0, &PAD12_CIS_D_9); +PINCTRL_MUX(CIS_D_10, 0, &PAD13_CIS_D_10); +PINCTRL_MUX(CIS_D_11, 0, &PAD14_CIS_D_11); + +PINCTRL_MUX(I2C0_SCL, 0, &PAD52_I2C0_SCL); +PINCTRL_MUX(I2C0_SDA, 0, &PAD53_I2C0_SDA); + +PINCTRL_MUX(I2C1_SCL, 1, &PAD18_I2C1_SCL, &PAD54_I2C1_SCL); +PINCTRL_MUX(I2C1_SDA, 1, &PAD17_I2C1_SDA, &PAD55_I2C1_SDA); + +PINCTRL_MUX(MAC_REF_CLK, 0, &PAD16_MAC_REF_CLK); +PINCTRL_MUX(MAC_RMII_CLK, 0, &PAD15_MAC_RMII_CLK); +PINCTRL_MUX(MAC_MDC, 0, &PAD17_MAC_MDC); +PINCTRL_MUX(MAC_MDIO, 0, &PAD18_MAC_MDIO); +PINCTRL_MUX(MAC_RXCK, 0, &PAD21_MAC_RXCK); +PINCTRL_MUX(MAC_RXD_0, 0, &PAD22_MAC_RXD_0); +PINCTRL_MUX(MAC_RXD_1, 0, &PAD23_MAC_RXD_1); +PINCTRL_MUX(MAC_RXDV, 0, &PAD26_MAC_RXDV); +PINCTRL_MUX(MAC_TXCK, 0, &PAD27_MAC_TXCK); +PINCTRL_MUX(MAC_TXD_0, 0, &PAD28_MAC_TXD_0); +PINCTRL_MUX(MAC_TXD_1, 0, &PAD29_MAC_TXD_1); +PINCTRL_MUX(MAC_TXEN, 0, &PAD32_MAC_TXEN); + +PINCTRL_MUX(PWM0, 3, &PAD1_PWM0, &PAD15_PWM0, + &PAD19_PWM0, &PAD35_PWM0, &PAD47_PWM0); +PINCTRL_MUX(PWM1, 3, &PAD2_PWM1, &PAD20_PWM1, + &PAD22_PWM1, &PAD36_PWM1, &PAD48_PWM1); +PINCTRL_MUX(PWM2, 3, &PAD3_PWM2, &PAD23_PWM2, + &PAD24_PWM2, &PAD37_PWM2, &PAD49_PWM2); +PINCTRL_MUX(PWM3, 3, &PAD4_PWM3, &PAD25_PWM3, + &PAD26_PWM3, &PAD38_PWM3, &PAD59_PWM3); +PINCTRL_MUX(PWM4, 2, &PAD5_PWM4, &PAD28_PWM4, &PAD30_PWM4, + &PAD65_PWM4); +PINCTRL_MUX(PWM5, 2, &PAD6_PWM5, &PAD29_PWM5, &PAD31_PWM5, + &PAD61_PWM5); +PINCTRL_MUX(PWM6, 2, &PAD7_PWM6, &PAD32_PWM6, &PAD33_PWM6, + &PAD63_PWM6); +PINCTRL_MUX(PWM7, 2, &PAD8_PWM7, &PAD18_PWM7, &PAD34_PWM7, + &PAD64_PWM7); + +PINCTRL_MUX(SD0_CLK, 0, &PAD63_SD0_CLK); +PINCTRL_MUX(SD0_CD, 0, &PAD61_SD0_CD); +PINCTRL_MUX(SD0_CMD_RSP, 0, &PAD64_SD0_CMD_RSP); +PINCTRL_MUX(SD0_WP, 0, &PAD62_SD0_WP, &PAD66_SD0_WP); +PINCTRL_MUX(SD0_DATA_0, 0, &PAD65_SD0_DATA_0); +PINCTRL_MUX(SD0_DATA_1, 0, &PAD66_SD0_DATA_1); + +PINCTRL_MUX(SD1_CLK, 0, &PAD15_SD1_CLK); +PINCTRL_MUX(SD1_CD, 0, &PAD26_SD1_CD); +PINCTRL_MUX(SD1_CMD_RSP, 0, &PAD32_SD1_CMD_RSP); +PINCTRL_MUX(SD1_WP, 0, &PAD17_SD1_WP); +PINCTRL_MUX(SD1_DATA_0, 0, &PAD22_SD1_DATA_0); +PINCTRL_MUX(SD1_DATA_1, 0, &PAD23_SD1_DATA_1); +PINCTRL_MUX(SD1_DATA_2, 0, &PAD28_SD1_DATA_2); +PINCTRL_MUX(SD1_DATA_3, 0, &PAD29_SD1_DATA_3); + +PINCTRL_MUX(SSI0_CLK, 0, &PAD56_SSI0_CLK); +PINCTRL_MUX(SSI0_RXD, 0, &PAD60_SSI0_RXD); +PINCTRL_MUX(SSI0_TXD, 0, &PAD57_SSI0_TXD); +PINCTRL_MUX(SSI0_CSN_0, 0, &PAD58_SSI0_CSN_0); +PINCTRL_MUX(SSI0_CSN_1, 0, &PAD59_SSI0_CSN_1); + +PINCTRL_MUX(SSI1_CLK, 0, &PAD37_SSI1_CLK); +PINCTRL_MUX(SSI1_RXD, 1, &PAD29_SSI1_RXD, &PAD36_SSI1_RXD); +PINCTRL_MUX(SSI1_TXD, 1, &PAD28_SSI1_TXD, &PAD35_SSI1_TXD); +PINCTRL_MUX(SSI1_CSN_0, 0, &PAD38_SSI1_CSN_0); + +PINCTRL_MUX(SSI2_CLK, 0, &PAD37_SSI2_CLK, &PAD64_SSI2_CLK); +PINCTRL_MUX(SSI2_RXD, 0, &PAD36_SSI2_RXD, &PAD63_SSI2_RXD); +PINCTRL_MUX(SSI2_TXD, 0, &PAD35_SSI2_TXD, &PAD61_SSI2_TXD); +PINCTRL_MUX(SSI2_CSN, 0, &PAD38_SSI2_CSN, &PAD65_SSI2_CSN); + +PINCTRL_MUX(UART0_RX, 0, &PAD50_UART0_RX); +PINCTRL_MUX(UART0_TX, 0, &PAD51_UART0_TX); +PINCTRL_MUX(UART1_RX, 0, &PAD2_UART1_RX, &PAD18_UART1_RX, + &PAD46_UART1_RX); +PINCTRL_MUX(UART1_TX, 0, &PAD1_UART1_TX, &PAD17_UART1_TX, + &PAD45_UART1_TX, &PAD59_UART1_TX, &PAD66_UART1_TX); + +PINCTRL_MUX(GPIO0, 0, &PAD35_GPIO0); +PINCTRL_MUX(GPIO1, 0, &PAD36_GPIO1); +PINCTRL_MUX(GPIO2, 0, &PAD37_GPIO2); +PINCTRL_MUX(GPIO3, 0, &PAD38_GPIO3); +PINCTRL_MUX(GPIO4, 0, &PAD39_GPIO4); +PINCTRL_MUX(GPIO5, 0, &PAD40_GPIO5); +PINCTRL_MUX(GPIO6, 0, &PAD41_GPIO6); +PINCTRL_MUX(GPIO7, 0, &PAD42_GPIO7); +PINCTRL_MUX(GPIO8, 0, &PAD43_GPIO8); +PINCTRL_MUX(GPIO9, 0, &PAD44_GPIO9); +PINCTRL_MUX(GPIO10, 0, &PAD45_GPIO10); +PINCTRL_MUX(GPIO11, 0, &PAD46_GPIO11, &PAD64_GPIO11); +PINCTRL_MUX(GPIO12, 0, &PAD47_GPIO12); +PINCTRL_MUX(GPIO13, 0, &PAD48_GPIO13); +PINCTRL_MUX(GPIO14, 0, &PAD49_GPIO14); +PINCTRL_MUX(GPIO15, 0, &PAD15_GPIO15); +PINCTRL_MUX(GPIO16, 0, &PAD22_GPIO16); +PINCTRL_MUX(GPIO17, 0, &PAD18_GPIO17); +PINCTRL_MUX(GPIO19, 0, &PAD2_GPIO19); +PINCTRL_MUX(GPIO20, 0, &PAD0_GPIO20); +PINCTRL_MUX(GPIO21, 0, &PAD1_GPIO21); +PINCTRL_MUX(GPIO22, 0, &PAD3_GPIO22); +PINCTRL_MUX(GPIO23, 0, &PAD4_GPIO23); +PINCTRL_MUX(GPIO24, 0, &PAD5_GPIO24); +PINCTRL_MUX(GPIO25, 0, &PAD6_GPIO25); +PINCTRL_MUX(GPIO26, 0, &PAD7_GPIO26); +PINCTRL_MUX(GPIO27, 0, &PAD8_GPIO27); +PINCTRL_MUX(GPIO28, 0, &PAD9_GPIO28); +PINCTRL_MUX(GPIO29, 0, &PAD10_GPIO29); +PINCTRL_MUX(GPIO30, 0, &PAD11_GPIO30); +PINCTRL_MUX(GPIO31, 0, &PAD12_GPIO31); +PINCTRL_MUX(GPIO32, 0, &PAD13_GPIO32); +PINCTRL_MUX(GPIO33, 0, &PAD14_GPIO33); +PINCTRL_MUX(GPIO34, 0, &PAD17_GPIO34); +PINCTRL_MUX(GPIO35, 0, &PAD19_GPIO35); +PINCTRL_MUX(GPIO36, 0, &PAD20_GPIO36); +PINCTRL_MUX(GPIO37, 0, &PAD34_GPIO37); +PINCTRL_MUX(GPIO38, 0, &PAD23_GPIO38); +PINCTRL_MUX(GPIO39, 0, &PAD24_GPIO39); +PINCTRL_MUX(GPIO40, 0, &PAD25_GPIO40); +PINCTRL_MUX(GPIO41, 0, &PAD26_GPIO41); +PINCTRL_MUX(GPIO42, 0, &PAD28_GPIO42); +PINCTRL_MUX(GPIO43, 0, &PAD29_GPIO43); +PINCTRL_MUX(GPIO44, 0, &PAD30_GPIO44); +PINCTRL_MUX(GPIO45, 0, &PAD31_GPIO45); +PINCTRL_MUX(GPIO46, 0, &PAD32_GPIO46); +PINCTRL_MUX(GPIO47, 0, &PAD33_GPIO47); +PINCTRL_MUX(GPIO48, 0, &PAD50_GPIO48); +PINCTRL_MUX(GPIO49, 0, &PAD51_GPIO49); +PINCTRL_MUX(GPIO50, 0, &PAD55_GPIO50); +PINCTRL_MUX(GPIO51, 0, &PAD54_GPIO51); +PINCTRL_MUX(GPIO52, 0, &PAD61_GPIO52); +PINCTRL_MUX(GPIO53, 0, &PAD62_GPIO53); +PINCTRL_MUX(GPIO54, 0, &PAD58_GPIO54); +PINCTRL_MUX(GPIO55, 0, &PAD59_GPIO55); +PINCTRL_MUX(GPIO56, 0, &PAD53_GPIO56); +PINCTRL_MUX(GPIO57, 0, &PAD52_GPIO57); +PINCTRL_MUX(GPIO61, 0, &PAD66_GPIO61); +PINCTRL_MUX(GPIO62, 0, &PAD65_GPIO62); +PINCTRL_MUX(GPIO63, 0, &PAD63_GPIO63); + +PINCTRL_DEVICE(USB, 1, &MUX_USB_PWREN); +PINCTRL_DEVICE(AC, 1, &MUX_AC_MCLK); +PINCTRL_DEVICE(ACI2S, 6, &MUX_ACI2S_AD_CLK, &MUX_ACI2S_AD_DI, &MUX_ACI2S_AD_WS, + &MUX_ACI2S_DA_CLK, &MUX_ACI2S_DA_DO, &MUX_ACI2S_DA_WS); +PINCTRL_DEVICE(DWI2S, 4, &MUX_DWI2S_CLK, &MUX_DWI2S_DI, + &MUX_DWI2S_DO, &MUX_DWI2S_WS); +PINCTRL_DEVICE(ARCJTAG, 5, &MUX_ARCJTAG_TCK, &MUX_ARCJTAG_TDI, &MUX_ARCJTAG_TDO, + &MUX_ARCJTAG_TMS, &MUX_ARCJTAG_TRSTN); +PINCTRL_DEVICE(ARMJTAG, 5, &MUX_ARMJTAG_TCK, &MUX_ARMJTAG_TDI, &MUX_ARMJTAG_TDO, + &MUX_ARMJTAG_TMS, &MUX_ARMJTAG_TRSTN); +PINCTRL_DEVICE(PAEJTAG, 5, &MUX_PAEJTAG_TCK, &MUX_PAEJTAG_TDI, &MUX_PAEJTAG_TDO, + &MUX_PAEJTAG_TMS, &MUX_PAEJTAG_TRSTN); +PINCTRL_DEVICE(CIS, 16, &MUX_CIS_CLK, &MUX_CIS_PCLK, &MUX_CIS_HSYNC, + &MUX_CIS_VSYNC, &MUX_CIS_D_0, &MUX_CIS_D_1, &MUX_CIS_D_2, + &MUX_CIS_D_3, &MUX_CIS_D_4, &MUX_CIS_D_5, &MUX_CIS_D_6, + &MUX_CIS_D_7, &MUX_CIS_D_8, &MUX_CIS_D_9, &MUX_CIS_D_10, + &MUX_CIS_D_11); +PINCTRL_DEVICE(CIS_10BIT, 14, &MUX_CIS_CLK, &MUX_CIS_PCLK, &MUX_CIS_HSYNC, + &MUX_CIS_VSYNC, &MUX_CIS_D_2, &MUX_CIS_D_3, + &MUX_CIS_D_4, &MUX_CIS_D_5, &MUX_CIS_D_6, &MUX_CIS_D_7, + &MUX_CIS_D_8, &MUX_CIS_D_9, &MUX_CIS_D_10, &MUX_CIS_D_11); +PINCTRL_DEVICE(MIPI, 1, &MUX_CIS_CLK); +PINCTRL_DEVICE(I2C0, 2, &MUX_I2C0_SCL, &MUX_I2C0_SDA); +PINCTRL_DEVICE(I2C1, 2, &MUX_I2C1_SCL, &MUX_I2C1_SDA); +PINCTRL_DEVICE(RMII, 12, &MUX_MAC_REF_CLK, &MUX_MAC_RMII_CLK, + &MUX_MAC_MDC, &MUX_MAC_MDIO, &MUX_MAC_RXD_0, + &MUX_MAC_RXD_1, &MUX_MAC_RXDV, &MUX_MAC_TXD_0, + &MUX_MAC_TXD_1, &MUX_MAC_TXEN, &MUX_MAC_TXCK, &MUX_MAC_RXCK); +PINCTRL_DEVICE(PWM0, 1, &MUX_PWM0); +PINCTRL_DEVICE(PWM1, 1, &MUX_PWM1); +PINCTRL_DEVICE(PWM2, 1, &MUX_PWM2); +PINCTRL_DEVICE(PWM3, 1, &MUX_PWM3); +PINCTRL_DEVICE(PWM4, 1, &MUX_PWM4); +PINCTRL_DEVICE(PWM5, 1, &MUX_PWM5); +PINCTRL_DEVICE(PWM6, 1, &MUX_PWM6); +PINCTRL_DEVICE(PWM7, 1, &MUX_PWM7); +PINCTRL_DEVICE(SD0, 6, &MUX_SD0_CLK, &MUX_SD0_CD, &MUX_SD0_CMD_RSP, + &MUX_SD0_WP, &MUX_SD0_DATA_0, &MUX_SD0_DATA_1); +PINCTRL_DEVICE(SD0_CARD_1BIT, 5, &MUX_SD0_CLK, &MUX_SD0_CD, &MUX_SD0_CMD_RSP, + &MUX_SD0_WP, &MUX_SD0_DATA_0); +PINCTRL_DEVICE(SD0_WIFI_2BIT, 4, &MUX_SD0_CLK, &MUX_SD0_CMD_RSP, + &MUX_SD0_DATA_0, &MUX_SD0_DATA_1); +PINCTRL_DEVICE(SD1, 8, &MUX_SD1_CLK, &MUX_SD1_CD, &MUX_SD1_CMD_RSP, + &MUX_SD1_WP, &MUX_SD1_DATA_0, &MUX_SD1_DATA_1, &MUX_SD1_DATA_2, + &MUX_SD1_DATA_3); +PINCTRL_DEVICE(SSI0, 4, &MUX_SSI0_CLK, &MUX_SSI0_RXD, &MUX_SSI0_TXD, + &MUX_GPIO54); +PINCTRL_DEVICE(SSI1, 4, &MUX_SSI1_CLK, &MUX_SSI1_RXD, &MUX_SSI1_TXD, + &MUX_SSI1_CSN_0); +PINCTRL_DEVICE(SSI2, 4, &MUX_SSI2_CLK, &MUX_SSI2_RXD, &MUX_SSI2_TXD, + &MUX_SSI2_CSN); +PINCTRL_DEVICE(UART0, 2, &MUX_UART0_RX, &MUX_UART0_TX); +PINCTRL_DEVICE(UART1, 2, &MUX_UART1_RX, &MUX_UART1_TX); +PINCTRL_DEVICE(GPIO0, 1, &MUX_GPIO0); +PINCTRL_DEVICE(GPIO1, 1, &MUX_GPIO1); +PINCTRL_DEVICE(GPIO2, 1, &MUX_GPIO2); +PINCTRL_DEVICE(GPIO3, 1, &MUX_GPIO3); +PINCTRL_DEVICE(GPIO4, 1, &MUX_GPIO4); +PINCTRL_DEVICE(GPIO5, 1, &MUX_GPIO5); +PINCTRL_DEVICE(GPIO6, 1, &MUX_GPIO6); +PINCTRL_DEVICE(GPIO7, 1, &MUX_GPIO7); +PINCTRL_DEVICE(GPIO8, 1, &MUX_GPIO8); +PINCTRL_DEVICE(GPIO9, 1, &MUX_GPIO9); +PINCTRL_DEVICE(GPIO10, 1, &MUX_GPIO10); +PINCTRL_DEVICE(GPIO11, 1, &MUX_GPIO11); +PINCTRL_DEVICE(GPIO12, 1, &MUX_GPIO12); +PINCTRL_DEVICE(GPIO13, 1, &MUX_GPIO13); +PINCTRL_DEVICE(GPIO14, 1, &MUX_GPIO14); +PINCTRL_DEVICE(GPIO15, 1, &MUX_GPIO15); +PINCTRL_DEVICE(GPIO16, 1, &MUX_GPIO16); +PINCTRL_DEVICE(GPIO17, 1, &MUX_GPIO17); +PINCTRL_DEVICE(GPIO19, 1, &MUX_GPIO19); +PINCTRL_DEVICE(GPIO20, 1, &MUX_GPIO20); +PINCTRL_DEVICE(GPIO21, 1, &MUX_GPIO21); +PINCTRL_DEVICE(GPIO22, 1, &MUX_GPIO22); +PINCTRL_DEVICE(GPIO23, 1, &MUX_GPIO23); +PINCTRL_DEVICE(GPIO24, 1, &MUX_GPIO24); +PINCTRL_DEVICE(GPIO25, 1, &MUX_GPIO25); +PINCTRL_DEVICE(GPIO26, 1, &MUX_GPIO26); +PINCTRL_DEVICE(GPIO27, 1, &MUX_GPIO27); +PINCTRL_DEVICE(GPIO28, 1, &MUX_GPIO28); +PINCTRL_DEVICE(GPIO29, 1, &MUX_GPIO29); +PINCTRL_DEVICE(GPIO30, 1, &MUX_GPIO30); +PINCTRL_DEVICE(GPIO31, 1, &MUX_GPIO31); +PINCTRL_DEVICE(GPIO32, 1, &MUX_GPIO32); +PINCTRL_DEVICE(GPIO33, 1, &MUX_GPIO33); +PINCTRL_DEVICE(GPIO34, 1, &MUX_GPIO34); +PINCTRL_DEVICE(GPIO35, 1, &MUX_GPIO35); +PINCTRL_DEVICE(GPIO36, 1, &MUX_GPIO36); +PINCTRL_DEVICE(GPIO37, 1, &MUX_GPIO37); +PINCTRL_DEVICE(GPIO38, 1, &MUX_GPIO38); +PINCTRL_DEVICE(GPIO39, 1, &MUX_GPIO39); +PINCTRL_DEVICE(GPIO40, 1, &MUX_GPIO40); +PINCTRL_DEVICE(GPIO41, 1, &MUX_GPIO41); +PINCTRL_DEVICE(GPIO42, 1, &MUX_GPIO42); +PINCTRL_DEVICE(GPIO43, 1, &MUX_GPIO43); +PINCTRL_DEVICE(GPIO44, 1, &MUX_GPIO44); +PINCTRL_DEVICE(GPIO45, 1, &MUX_GPIO45); +PINCTRL_DEVICE(GPIO46, 1, &MUX_GPIO46); +PINCTRL_DEVICE(GPIO47, 1, &MUX_GPIO47); +PINCTRL_DEVICE(GPIO48, 1, &MUX_GPIO48); +PINCTRL_DEVICE(GPIO49, 1, &MUX_GPIO49); +PINCTRL_DEVICE(GPIO50, 1, &MUX_GPIO50); +PINCTRL_DEVICE(GPIO51, 1, &MUX_GPIO51); +PINCTRL_DEVICE(GPIO52, 1, &MUX_GPIO52); +PINCTRL_DEVICE(GPIO53, 1, &MUX_GPIO53); +PINCTRL_DEVICE(GPIO54, 1, &MUX_GPIO54); +PINCTRL_DEVICE(GPIO55, 1, &MUX_GPIO55); +PINCTRL_DEVICE(GPIO56, 1, &MUX_GPIO56); +PINCTRL_DEVICE(GPIO57, 1, &MUX_GPIO57); +PINCTRL_DEVICE(GPIO61, 1, &MUX_GPIO61); +PINCTRL_DEVICE(GPIO62, 1, &MUX_GPIO62); +PINCTRL_DEVICE(GPIO63, 1, &MUX_GPIO63); + + +void fh_pinctrl_init_devicelist(OS_LIST *list) +{ + OS_LIST_EMPTY(list); + + PINCTRL_ADD_DEVICE(USB); + PINCTRL_ADD_DEVICE(AC); + PINCTRL_ADD_DEVICE(ACI2S); + PINCTRL_ADD_DEVICE(DWI2S); + PINCTRL_ADD_DEVICE(ARCJTAG); + PINCTRL_ADD_DEVICE(ARMJTAG); + PINCTRL_ADD_DEVICE(PAEJTAG); + PINCTRL_ADD_DEVICE(CIS); + PINCTRL_ADD_DEVICE(MIPI); + PINCTRL_ADD_DEVICE(CIS_10BIT); + + PINCTRL_ADD_DEVICE(I2C0); + PINCTRL_ADD_DEVICE(I2C1); + PINCTRL_ADD_DEVICE(RMII); + PINCTRL_ADD_DEVICE(PWM0); + PINCTRL_ADD_DEVICE(PWM1); + PINCTRL_ADD_DEVICE(PWM2); + PINCTRL_ADD_DEVICE(PWM3); + PINCTRL_ADD_DEVICE(PWM4); + PINCTRL_ADD_DEVICE(PWM5); + PINCTRL_ADD_DEVICE(PWM6); + PINCTRL_ADD_DEVICE(PWM7); + PINCTRL_ADD_DEVICE(SD0); + PINCTRL_ADD_DEVICE(SD0_CARD_1BIT); + PINCTRL_ADD_DEVICE(SD0_WIFI_2BIT); + PINCTRL_ADD_DEVICE(SD1); + PINCTRL_ADD_DEVICE(SSI0); + PINCTRL_ADD_DEVICE(SSI1); + PINCTRL_ADD_DEVICE(SSI2); + PINCTRL_ADD_DEVICE(UART0); + PINCTRL_ADD_DEVICE(UART1); + PINCTRL_ADD_DEVICE(GPIO0); + PINCTRL_ADD_DEVICE(GPIO1); + PINCTRL_ADD_DEVICE(GPIO2); + PINCTRL_ADD_DEVICE(GPIO3); + PINCTRL_ADD_DEVICE(GPIO4); + PINCTRL_ADD_DEVICE(GPIO5); + PINCTRL_ADD_DEVICE(GPIO6); + PINCTRL_ADD_DEVICE(GPIO7); + PINCTRL_ADD_DEVICE(GPIO8); + PINCTRL_ADD_DEVICE(GPIO9); + PINCTRL_ADD_DEVICE(GPIO10); + PINCTRL_ADD_DEVICE(GPIO11); + PINCTRL_ADD_DEVICE(GPIO12); + PINCTRL_ADD_DEVICE(GPIO13); + PINCTRL_ADD_DEVICE(GPIO14); + PINCTRL_ADD_DEVICE(GPIO15); + PINCTRL_ADD_DEVICE(GPIO16); + PINCTRL_ADD_DEVICE(GPIO17); + PINCTRL_ADD_DEVICE(GPIO19); + PINCTRL_ADD_DEVICE(GPIO20); + PINCTRL_ADD_DEVICE(GPIO21); + PINCTRL_ADD_DEVICE(GPIO22); + PINCTRL_ADD_DEVICE(GPIO23); + PINCTRL_ADD_DEVICE(GPIO24); + PINCTRL_ADD_DEVICE(GPIO25); + PINCTRL_ADD_DEVICE(GPIO26); + PINCTRL_ADD_DEVICE(GPIO27); + PINCTRL_ADD_DEVICE(GPIO28); + PINCTRL_ADD_DEVICE(GPIO29); + PINCTRL_ADD_DEVICE(GPIO30); + PINCTRL_ADD_DEVICE(GPIO31); + PINCTRL_ADD_DEVICE(GPIO32); + PINCTRL_ADD_DEVICE(GPIO33); + PINCTRL_ADD_DEVICE(GPIO34); + PINCTRL_ADD_DEVICE(GPIO35); + PINCTRL_ADD_DEVICE(GPIO36); + PINCTRL_ADD_DEVICE(GPIO37); + PINCTRL_ADD_DEVICE(GPIO38); + PINCTRL_ADD_DEVICE(GPIO39); + PINCTRL_ADD_DEVICE(GPIO40); + PINCTRL_ADD_DEVICE(GPIO41); + PINCTRL_ADD_DEVICE(GPIO42); + PINCTRL_ADD_DEVICE(GPIO43); + PINCTRL_ADD_DEVICE(GPIO44); + PINCTRL_ADD_DEVICE(GPIO45); + PINCTRL_ADD_DEVICE(GPIO46); + PINCTRL_ADD_DEVICE(GPIO47); + PINCTRL_ADD_DEVICE(GPIO48); + PINCTRL_ADD_DEVICE(GPIO49); + PINCTRL_ADD_DEVICE(GPIO50); + PINCTRL_ADD_DEVICE(GPIO51); + PINCTRL_ADD_DEVICE(GPIO52); + PINCTRL_ADD_DEVICE(GPIO53); + PINCTRL_ADD_DEVICE(GPIO54); + PINCTRL_ADD_DEVICE(GPIO55); + PINCTRL_ADD_DEVICE(GPIO56); + PINCTRL_ADD_DEVICE(GPIO57); + PINCTRL_ADD_DEVICE(GPIO61); + PINCTRL_ADD_DEVICE(GPIO62); + PINCTRL_ADD_DEVICE(GPIO63); +} + + + +char* fh_pinctrl_selected_devices[] = +{ + CONFIG_PINCTRL_SELECT +}; diff --git a/arch/arm/mach-fh/include/mach/fh_dmac.h b/arch/arm/mach-fh/include/mach/fh_dmac.h new file mode 100644 index 00000000..c6d100b6 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/fh_dmac.h @@ -0,0 +1,151 @@ +/* + * Driver for the Synopsys DesignWare DMA Controller (aka DMACA on + * AVR32 systems.) + * + * Copyright (C) 2007 Atmel Corporation + * Copyright (C) 2010-2011 ST Microelectronics + * + * 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 FH_DMAC_H +#define FH_DMAC_H + +#include + +/** + * enum fh_dma_slave_width - DMA slave register access width. + * @DMA_SLAVE_WIDTH_8BIT: Do 8-bit slave register accesses + * @DMA_SLAVE_WIDTH_16BIT: Do 16-bit slave register accesses + * @DMA_SLAVE_WIDTH_32BIT: Do 32-bit slave register accesses + */ +enum fh_dma_slave_width { + FH_DMA_SLAVE_WIDTH_8BIT, + FH_DMA_SLAVE_WIDTH_16BIT, + FH_DMA_SLAVE_WIDTH_32BIT, +}; + +/* bursts size */ +enum fh_dma_msize { + FH_DMA_MSIZE_1, + FH_DMA_MSIZE_4, + FH_DMA_MSIZE_8, + FH_DMA_MSIZE_16, + FH_DMA_MSIZE_32, + FH_DMA_MSIZE_64, + FH_DMA_MSIZE_128, + FH_DMA_MSIZE_256, +}; + +/* flow controller */ +enum fh_dma_fc { + FH_DMA_FC_D_M2M, + FH_DMA_FC_D_M2P, + FH_DMA_FC_D_P2M, + FH_DMA_FC_D_P2P, + FH_DMA_FC_P_P2M, + FH_DMA_FC_SP_P2P, + FH_DMA_FC_P_M2P, + FH_DMA_FC_DP_P2P, +}; + +/** + * struct fh_dma_slave - Controller-specific information about a slave + * + * @dma_dev: required DMA master device + * @tx_reg: physical address of data register used for + * memory-to-peripheral transfers + * @rx_reg: physical address of data register used for + * peripheral-to-memory transfers + * @reg_width: peripheral register width + * @cfg_hi: Platform-specific initializer for the CFG_HI register + * @cfg_lo: Platform-specific initializer for the CFG_LO register + * @src_master: src master for transfers on allocated channel. + * @dst_master: dest master for transfers on allocated channel. + * @src_msize: src burst size. + * @dst_msize: dest burst size. + * @fc: flow controller for DMA transfer + */ +struct fh_dma_slave { + struct device *dma_dev; + dma_addr_t tx_reg; + dma_addr_t rx_reg; + enum fh_dma_slave_width reg_width; + u32 cfg_hi; + u32 cfg_lo; + u8 src_master; + u8 dst_master; + u8 src_msize; + u8 dst_msize; + u8 fc; +}; + + +/** + * struct fh_dma_platform_data - Controller configuration parameters + * @nr_channels: Number of channels supported by hardware (max 8) + * @is_private: The device channels should be marked as private and not for + * by the general purpose DMA channel allocator. + * @chan_allocation_order: Allocate channels starting from 0 or 7 + * @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0. + * @block_size: Maximum block size supported by the controller + * @nr_masters: Number of AHB masters supported by the controller + * @data_width: Maximum data width supported by hardware per AHB master + * (0 - 8bits, 1 - 16bits, ..., 5 - 256bits) + * @sd: slave specific data. Used for configuring channels + * @sd_count: count of slave data structures passed. + */ +struct fh_dma_platform_data { + unsigned int nr_channels; + bool is_private; +#define CHAN_ALLOCATION_ASCENDING 0 /* zero to seven */ +#define CHAN_ALLOCATION_DESCENDING 1 /* seven to zero */ + unsigned char chan_allocation_order; +#define CHAN_PRIORITY_ASCENDING 0 /* chan0 highest */ +#define CHAN_PRIORITY_DESCENDING 1 /* chan7 highest */ + unsigned char chan_priority; + unsigned short block_size; + unsigned char nr_masters; + unsigned char data_width[4]; +}; + +/* Platform-configurable bits in CFG_HI */ +#define FHC_CFGH_FCMODE (1 << 0) +#define FHC_CFGH_FIFO_MODE (1 << 1) +#define FHC_CFGH_PROTCTL(x) ((x) << 2) +#define FHC_CFGH_SRC_PER(x) ((x) << 7) +#define FHC_CFGH_DST_PER(x) ((x) << 11) + +/* Platform-configurable bits in CFG_LO */ +#define FHC_CFGL_LOCK_CH_XFER (0 << 12) /* scope of LOCK_CH */ +#define FHC_CFGL_LOCK_CH_BLOCK (1 << 12) +#define FHC_CFGL_LOCK_CH_XACT (2 << 12) +#define FHC_CFGL_LOCK_BUS_XFER (0 << 14) /* scope of LOCK_BUS */ +#define FHC_CFGL_LOCK_BUS_BLOCK (1 << 14) +#define FHC_CFGL_LOCK_BUS_XACT (2 << 14) +#define FHC_CFGL_LOCK_CH (1 << 15) /* channel lockout */ +#define FHC_CFGL_LOCK_BUS (1 << 16) /* busmaster lockout */ +#define FHC_CFGL_HS_DST_POL (1 << 18) /* dst handshake active low */ +#define FHC_CFGL_HS_SRC_POL (1 << 19) /* src handshake active low */ + +/* DMA API extensions */ +struct fh_cyclic_desc { + struct fh_desc **desc; + unsigned long periods; + void (*period_callback)(void *param); + void *period_callback_param; +}; + +struct fh_cyclic_desc *fh_dma_cyclic_prep(struct dma_chan *chan, + dma_addr_t buf_addr, size_t buf_len, size_t period_len, + enum dma_transfer_direction direction); +void fh_dma_cyclic_free(struct dma_chan *chan); +int fh_dma_cyclic_start(struct dma_chan *chan); +void fh_dma_cyclic_stop(struct dma_chan *chan); + +dma_addr_t fh_dma_get_src_addr(struct dma_chan *chan); + +dma_addr_t fh_dma_get_dst_addr(struct dma_chan *chan); + +#endif /* FH_DMAC_H */ diff --git a/arch/arm/mach-fh/include/mach/fh_dmac_regs.h b/arch/arm/mach-fh/include/mach/fh_dmac_regs.h new file mode 100644 index 00000000..504dfead --- /dev/null +++ b/arch/arm/mach-fh/include/mach/fh_dmac_regs.h @@ -0,0 +1,312 @@ +/* + * Driver for the Synopsys DesignWare AHB DMA Controller + * + * Copyright (C) 2005-2007 Atmel Corporation + * Copyright (C) 2010-2011 ST Microelectronics + * + * 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 +#include + +#define FH_DMA_MAX_NR_CHANNELS 8 +#define FH_DMA_MAX_NR_REQUESTS 16 + +/* + * Redefine this macro to handle differences between 32- and 64-bit + * addressing, big vs. little endian, etc. + */ +#define FH_REG(name) u32 name; u32 __pad_##name + +/* Hardware register definitions. */ +struct fh_dma_chan_regs { + FH_REG(SAR); /* Source Address Register */ + FH_REG(DAR); /* Destination Address Register */ + FH_REG(LLP); /* Linked List Pointer */ + u32 CTL_LO; /* Control Register Low */ + u32 CTL_HI; /* Control Register High */ + FH_REG(SSTAT); + FH_REG(DSTAT); + FH_REG(SSTATAR); + FH_REG(DSTATAR); + u32 CFG_LO; /* Configuration Register Low */ + u32 CFG_HI; /* Configuration Register High */ + FH_REG(SGR); + FH_REG(DSR); +}; + +struct fh_dma_irq_regs { + FH_REG(XFER); + FH_REG(BLOCK); + FH_REG(SRC_TRAN); + FH_REG(DST_TRAN); + FH_REG(ERROR); +}; + +struct fh_dma_regs { + /* per-channel registers */ + struct fh_dma_chan_regs CHAN[FH_DMA_MAX_NR_CHANNELS]; + + /* irq handling */ + struct fh_dma_irq_regs RAW; /* r */ + struct fh_dma_irq_regs STATUS; /* r (raw & mask) */ + struct fh_dma_irq_regs MASK; /* rw (set = irq enabled) */ + struct fh_dma_irq_regs CLEAR; /* w (ack, affects "raw") */ + + FH_REG(STATUS_INT); /* r */ + + /* software handshaking */ + FH_REG(REQ_SRC); + FH_REG(REQ_DST); + FH_REG(SGL_REQ_SRC); + FH_REG(SGL_REQ_DST); + FH_REG(LAST_SRC); + FH_REG(LAST_DST); + + /* miscellaneous */ + FH_REG(CFG); + FH_REG(CH_EN); + FH_REG(ID); + FH_REG(TEST); + + /* reserved */ + FH_REG(__reserved0); + FH_REG(__reserved1); + + /* optional encoded params, 0x3c8..0x3f7 */ + u32 __reserved; + + /* per-channel configuration registers */ + u32 FHC_PARAMS[FH_DMA_MAX_NR_CHANNELS]; + u32 MULTI_BLK_TYPE; + u32 MAX_BLK_SIZE; + + /* top-level parameters */ + u32 FH_PARAMS; +}; + +#ifdef CONFIG_FH_DMAC_BIG_ENDIAN_IO +#define dma_readl_native ioread32be +#define dma_writel_native iowrite32be +#else +#define dma_readl_native readl +#define dma_writel_native writel +#endif + +/* To access the registers in early stage of probe */ +#define dma_read_byaddr(addr, name) \ + dma_readl_native((addr) + offsetof(struct fh_dma_regs, name)) + +/* Bitfields in FH_PARAMS */ +#define FH_PARAMS_NR_CHAN 8 /* number of channels */ +#define FH_PARAMS_NR_MASTER 11 /* number of AHB masters */ +#define FH_PARAMS_DATA_WIDTH(n) (15 + 2 * (n)) +#define FH_PARAMS_DATA_WIDTH1 15 /* master 1 data width */ +#define FH_PARAMS_DATA_WIDTH2 17 /* master 2 data width */ +#define FH_PARAMS_DATA_WIDTH3 19 /* master 3 data width */ +#define FH_PARAMS_DATA_WIDTH4 21 /* master 4 data width */ +#define FH_PARAMS_EN 28 /* encoded parameters */ + +/* Bitfields in FHC_PARAMS */ +#define FHC_PARAMS_MBLK_EN 11 /* multi block transfer */ + +/* Bitfields in CTL_LO */ +#define FHC_CTLL_INT_EN (1 << 0) /* irqs enabled? */ +#define FHC_CTLL_DST_WIDTH(n) ((n)<<1) /* bytes per element */ +#define FHC_CTLL_SRC_WIDTH(n) ((n)<<4) +#define FHC_CTLL_DST_INC (0<<7) /* DAR update/not */ +#define FHC_CTLL_DST_DEC (1<<7) +#define FHC_CTLL_DST_FIX (2<<7) +#define FHC_CTLL_SRC_INC (0<<9) /* SAR update/not */ +#define FHC_CTLL_SRC_DEC (1<<9) +#define FHC_CTLL_SRC_FIX (2<<9) +#define FHC_CTLL_DST_MSIZE(n) ((n)<<11) /* burst, #elements */ +#define FHC_CTLL_SRC_MSIZE(n) ((n)<<14) +#define FHC_CTLL_S_GATH_EN (1 << 17) /* src gather, !FIX */ +#define FHC_CTLL_D_SCAT_EN (1 << 18) /* dst scatter, !FIX */ +#define FHC_CTLL_FC(n) ((n) << 20) +#define FHC_CTLL_FC_M2M (0 << 20) /* mem-to-mem */ +#define FHC_CTLL_FC_M2P (1 << 20) /* mem-to-periph */ +#define FHC_CTLL_FC_P2M (2 << 20) /* periph-to-mem */ +#define FHC_CTLL_FC_P2P (3 << 20) /* periph-to-periph */ +/* plus 4 transfer types for peripheral-as-flow-controller */ +#define FHC_CTLL_DMS(n) ((n)<<23) /* dst master select */ +#define FHC_CTLL_SMS(n) ((n)<<25) /* src master select */ +#define FHC_CTLL_LLP_D_EN (1 << 27) /* dest block chain */ +#define FHC_CTLL_LLP_S_EN (1 << 28) /* src block chain */ + +/* Bitfields in CTL_HI */ +#define FHC_CTLH_DONE 0x00001000 +#define FHC_CTLH_BLOCK_TS_MASK 0x00000fff + +/* Bitfields in CFG_LO. Platform-configurable bits are in */ +#define FHC_CFGL_CH_PRIOR_MASK (0x7 << 5) /* priority mask */ +#define FHC_CFGL_CH_PRIOR(x) ((x) << 5) /* priority */ +#define FHC_CFGL_CH_SUSP (1 << 8) /* pause xfer */ +#define FHC_CFGL_FIFO_EMPTY (1 << 9) /* pause xfer */ +#define FHC_CFGL_HS_DST (1 << 10) /* handshake w/dst */ +#define FHC_CFGL_HS_SRC (1 << 11) /* handshake w/src */ +#define FHC_CFGL_MAX_BURST(x) ((x) << 20) +#define FHC_CFGL_RELOAD_SAR (1 << 30) +#define FHC_CFGL_RELOAD_DAR (1 << 31) + +/* Bitfields in CFG_HI. Platform-configurable bits are in */ +#define FHC_CFGH_DS_UPD_EN (1 << 5) +#define FHC_CFGH_SS_UPD_EN (1 << 6) + +/* Bitfields in SGR */ +#define FHC_SGR_SGI(x) ((x) << 0) +#define FHC_SGR_SGC(x) ((x) << 20) + +/* Bitfields in DSR */ +#define FHC_DSR_DSI(x) ((x) << 0) +#define FHC_DSR_DSC(x) ((x) << 20) + +/* Bitfields in CFG */ +#define FH_CFG_DMA_EN (1 << 0) + +#define FH_REGLEN 0x400 + +enum fh_dmac_flags { + FH_DMA_IS_CYCLIC = 0, + FH_DMA_IS_SOFT_LLP = 1, +}; + +struct fh_dma_chan { + struct dma_chan chan; + void __iomem *ch_regs; + u8 mask; + u8 priority; + enum dma_transfer_direction direction; + bool paused; + bool initialized; + + /* software emulation of the LLP transfers */ + struct list_head *tx_node_active; + + spinlock_t lock; + + /* these other elements are all protected by lock */ + unsigned long flags; + struct list_head active_list; + struct list_head queue; + struct list_head free_list; + u32 residue; + struct fh_cyclic_desc *cdesc; + + unsigned int descs_allocated; + + /* hardware configuration */ + unsigned int block_size; + bool nollp; + + /* custom slave configuration */ + unsigned int request_line; + unsigned char src_master; + unsigned char dst_master; + + /* configuration passed via DMA_SLAVE_CONFIG */ + struct dma_slave_config dma_sconfig; +}; + +enum fh_dma_slave_increment { + FH_DMA_SLAVE_INC, + FH_DMA_SLAVE_DEC, + FH_DMA_SLAVE_FIX, +}; + +struct fh_dma_pri { + u32 sinc; + u32 dinc; +}; + +static inline struct fh_dma_chan_regs __iomem * +__fhc_regs(struct fh_dma_chan *fhc) +{ + return fhc->ch_regs; +} + +#define channel_readl(fhc, name) \ + dma_readl_native(&(__fhc_regs(fhc)->name)) +#define channel_writel(fhc, name, val) \ + dma_writel_native((val), &(__fhc_regs(fhc)->name)) + +static inline struct fh_dma_chan *to_fh_dma_chan(struct dma_chan *chan) +{ + return container_of(chan, struct fh_dma_chan, chan); +} + +struct fh_dma { + struct dma_device dma; + void __iomem *regs; + struct dma_pool *desc_pool; + struct tasklet_struct tasklet; + struct clk *clk; + + u8 all_chan_mask; + + /* hardware configuration */ + unsigned char nr_masters; + unsigned char data_width[4]; + + struct fh_dma_chan chan[0]; +}; + +static inline struct fh_dma_regs __iomem *__fh_regs(struct fh_dma *dw) +{ + return dw->regs; +} + +#define dma_readl(dw, name) \ + dma_readl_native(&(__fh_regs(dw)->name)) +#define dma_writel(dw, name, val) \ + dma_writel_native((val), &(__fh_regs(dw)->name)) + +#define channel_set_bit(dw, reg, mask) \ + dma_writel(dw, reg, ((mask) << 8) | (mask)) +#define channel_clear_bit(dw, reg, mask) \ + dma_writel(dw, reg, ((mask) << 8) | 0) + +static inline struct fh_dma *to_fh_dma(struct dma_device *ddev) +{ + return container_of(ddev, struct fh_dma, dma); +} + +/* LLI == Linked List Item; a.k.a. DMA block descriptor */ +struct fh_lli { + /* values that are not changed by hardware */ + u32 sar; + u32 dar; + u32 llp; /* chain to next lli */ + u32 ctllo; + /* values that may get written back: */ + u32 ctlhi; + /* sstat and dstat can snapshot peripheral register state. + * silicon config may discard either or both... + */ + u32 sstat; + u32 dstat; +}; + +struct fh_desc { + /* FIRST values the hardware uses */ + struct fh_lli lli; + + /* THEN values for driver housekeeping */ + struct list_head desc_node; + struct list_head tx_list; + struct dma_async_tx_descriptor txd; + size_t len; + size_t total_len; +}; + +#define to_fh_desc(h) list_entry(h, struct fh_desc, desc_node) + +static inline struct fh_desc * +txd_to_fh_desc(struct dma_async_tx_descriptor *txd) +{ + return container_of(txd, struct fh_desc, txd); +} diff --git a/arch/arm/mach-fh/include/mach/fh_gmac.h b/arch/arm/mach-fh/include/mach/fh_gmac.h new file mode 100644 index 00000000..1ab649d0 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/fh_gmac.h @@ -0,0 +1,33 @@ +#ifndef __FH_GMAC_PLATFORM_DATA +#define __FH_GMAC_PLATFORM_DATA + +#include + +enum { + gmac_phyt_reg_basic_ctrl = 0, + gmac_phyt_reg_basic_status = 1, + gmac_phyt_reg_phy_id1 = 2, + gmac_phyt_reg_phy_id2 = 3, + gmac_phyt_rtl8201_rmii_mode = 16, + gmac_phyt_ti83848_rmii_mode = 17, + gmac_phyt_rtl8201_power_saving = 24, + gmac_phyt_rtl8201_page_select = 31, + gmac_phyt_ip101g_page_select = 20 +}; + +enum { + gmac_speed_10m, + gmac_speed_100m +}; + +struct fh_gmac_platform_data { + int interface; + int phyid; + void (*early_init)(struct fh_gmac_platform_data *plat_data); + void (*plat_init)(struct fh_gmac_platform_data *plat_data); + void (*set_rmii_speed)(int speed); + void (*phy_reset)(void); +}; + +#endif + diff --git a/arch/arm/mach-fh/include/mach/fh_predefined.h b/arch/arm/mach-fh/include/mach/fh_predefined.h new file mode 100644 index 00000000..a5572f2f --- /dev/null +++ b/arch/arm/mach-fh/include/mach/fh_predefined.h @@ -0,0 +1,40 @@ +/* + * fh_predefined.h + * + * Created on: May 22, 2014 + * Author: duobao + */ + +#ifndef FH_PREDEFINED_H_ +#define FH_PREDEFINED_H_ + +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned int UINT32; +typedef unsigned long long UINT64; + +typedef char SINT8; +typedef short SINT16; +typedef int SINT32; +typedef long long SINT64; +#define FALSE (0) +#define TRUE (!FALSE) +#define reg_read(addr) (*((volatile UINT32 *)(addr))) +#define reg_write(addr,value) (*(volatile UINT32 *)(addr)=(value)) + +#define GET_REG(addr) reg_read(addr) +#define SET_REG(addr,value) reg_write(addr,value) +#define SET_REG_M(addr,value,mask) reg_write(addr,(reg_read(addr)&(~(mask)))|((value)&(mask))) +#define SET_REG_B(addr,element,highbit,lowbit) SET_REG_M((addr),((element)<<(lowbit)),(((1<<((highbit)-(lowbit)+1))-1)<<(lowbit))) + +#define GET_REG8(addr) (*((volatile UINT8 *)(addr))) +#define SET_REG8(addr,value) (*(volatile UINT8 *)(addr)=(value)) + +#define LD8(addr) (*((volatile u8 *)(addr))) +#define ST8(addr,value) (*(volatile u8 *)(addr)=(value)) +#define LD16(addr) (*((volatile u16 *)(addr))) +#define ST16(addr,value) (*(volatile u16 *)(addr)=(value)) +#define LD32(addr) (*((volatile u32 *)(addr))) +#define ST32(addr,value) (*(volatile u32 *)(addr)=(value)) + +#endif /* FH_PREDEFINED_H_ */ diff --git a/arch/arm/mach-fh/include/mach/fh_sadc.h b/arch/arm/mach-fh/include/mach/fh_sadc.h new file mode 100644 index 00000000..6f73bc90 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/fh_sadc.h @@ -0,0 +1,83 @@ +/* + * fh_sadc.h + * + * Created on: Mar 13, 2015 + * Author: duobao + */ + +#ifndef FH_SADC_H_ +#define FH_SADC_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * #define section + * add constant #define here if any + ***************************************************************************/ +#define FH_SADC_PROC_FILE "driver/sadc" +#define MAX_CHANNEL_NO (8) +#define SADC_REF (3300) +#define SADC_MAX_AD_VALUE (0x3ff) +#define LOOP_MODE (0x55) +#define ISR_MODE (0xAA) + + +#define SADC_TIMEOUT 0x55 +/**************************************************************************** + * ADT section + * add Abstract Data Type definition here + ***************************************************************************/ + +struct wrap_sadc_reg { + u32 sadc_cmd; + u32 sadc_control; + u32 sadc_ier; + u32 sadc_int_status; + u32 sadc_dout0; + u32 sadc_dout1; + u32 sadc_dout2; + u32 sadc_dout3; + u32 sadc_debuge0; + u32 sadc_status; + u32 sadc_cnt; + u32 sadc_timeout; +}; + +struct wrap_sadc_obj { + void *regs; + u32 irq_no; + u32 active_channel_no; + u32 active_channel_status; + uint16_t channel_data[MAX_CHANNEL_NO]; + u32 error_rec; + u32 en_isr; + u32 sample_mode; + spinlock_t lock; + struct completion done; + struct proc_dir_entry *proc_file; +}; + +#ifdef CONFIG_FH_SADC +long fh_sadc_get_value(int channel); +#else +long fh_sadc_get_value(int channel) +{ + return 0; +} +#endif + +#endif /* fh_SADC_H_ */ diff --git a/arch/arm/mach-fh/include/mach/fh_simple_timer.h b/arch/arm/mach-fh/include/mach/fh_simple_timer.h new file mode 100644 index 00000000..a5f08a54 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/fh_simple_timer.h @@ -0,0 +1,45 @@ +/* + * fh_simple_timer.h + * + * Created on: Jan 22, 2017 + * Author: duobao + */ + +#ifndef FH_SIMPLE_TIMER_H_ +#define FH_SIMPLE_TIMER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum simple_timer_state { + SIMPLE_TIMER_STOP, + SIMPLE_TIMER_START, + SIMPLE_TIMER_ERROR, +}; + +struct fh_simple_timer +{ + struct timerqueue_node node; + ktime_t it_interval; /* timer period */ + ktime_t it_value; /* timer expiration */ + ktime_t it_delay; + void (*function) (void *); + void *param; +}; + + +int fh_simple_timer_interrupt(void); +int fh_simple_timer_create(struct fh_simple_timer* tim); +int fh_timer_start(void); +int fh_simple_timer_init(void); + +#endif /* FH_SIMPLE_TIMER_H_ */ diff --git a/arch/arm/mach-fh/include/mach/fh_wdt.h b/arch/arm/mach-fh/include/mach/fh_wdt.h new file mode 100644 index 00000000..22e4a45f --- /dev/null +++ b/arch/arm/mach-fh/include/mach/fh_wdt.h @@ -0,0 +1,12 @@ +#ifndef __FH_WDT_PLATFORM_DATA +#define __FH_WDT_PLATFORM_DATA + +#include + +struct fh_wdt_platform_data { + void (*resume)(void); + void (*pause)(void); +}; + +#endif + diff --git a/arch/arm/mach-fh/include/mach/fhmci.h b/arch/arm/mach-fh/include/mach/fhmci.h new file mode 100644 index 00000000..b60ad26e --- /dev/null +++ b/arch/arm/mach-fh/include/mach/fhmci.h @@ -0,0 +1,178 @@ +#ifndef _FH_MCI_H_ +#define _FH_MCI_H_ + +extern int trace_level; +#define FHMCI_TRACE_LEVEL 5 +/* + 0 - all message + 1 - dump all register read/write + 2 - flow trace + 3 - timeout err and protocol err + */ + +#define FHMCI_TRACE_FMT KERN_INFO +#define ID_SD0 0 +#define ID_SD1 1 + +#define POWER_ON 1 +#define POWER_OFF 0 + +#define CARD_UNPLUGED 1 +#define CARD_PLUGED 0 + +#define ENABLE 1 +#define DISABLE 0 + +#define FH_MCI_DETECT_TIMEOUT (HZ/4) + +#define FH_MCI_REQUEST_TIMEOUT (5 * HZ) + +#define MAX_RETRY_COUNT 100 +#define MAX_MCI_HOST (2) /* max num of host on soc */ + +#define fhmci_trace(level, msg...) do { \ + if ((level) >= trace_level) { \ + printk(FHMCI_TRACE_FMT "%s:%d: ", __func__, __LINE__); \ + printk(msg); \ + printk("\n"); \ + } \ +} while (0) + +#define fhmci_assert(cond) do { \ + if (!(cond)) {\ + printk(KERN_ERR "Assert:fhmci:%s:%d\n", \ + __func__, \ + __LINE__); \ + BUG(); \ + } \ +} while (0) + +#define fhmci_error(s...) do { \ + printk(KERN_ERR "fhmci:%s:%d: ", __func__, __LINE__); \ + printk(s); \ + printk("\n"); \ +} while (0) + +#define fhmci_readl(addr) ({unsigned int reg = readl((unsigned int)addr); \ + fhmci_trace(1, "readl(0x%04X) = 0x%08X", (unsigned int)addr, reg); \ + reg; }) + +#define fhmci_writel(v, addr) do { \ + writel(v, (unsigned int)addr); \ + fhmci_trace(1, "writel(0x%04X) = 0x%08X",\ + (unsigned int)addr, (unsigned int)(v)); \ +} while (0) + + +struct fhmci_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 fhmci_host { + struct mmc_host *mmc; + spinlock_t lock; + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; + void __iomem *base; + unsigned int card_status; + struct scatterlist *dma_sg; + unsigned int dma_sg_num; + unsigned int dma_alloc_size; + unsigned int dma_dir; + dma_addr_t dma_paddr; + unsigned int *dma_vaddr; + struct timer_list timer; + unsigned int irq; + unsigned int irq_status; + unsigned int is_tuning; + wait_queue_head_t intr_wait; + unsigned long pending_events; + unsigned int id; + struct fh_mci_board *pdata; + unsigned int (*get_cd)(struct fhmci_host *host); + unsigned int (*get_ro)(struct fhmci_host *host); +#define FHMCI_PEND_DTO_b (0) +#define FHMCI_PEND_DTO_m (1 << FHMCI_PEND_DTO_b) +}; + +/* Board platform data */ +struct fh_mci_board { + unsigned int num_slots; + + unsigned int quirks; /* Workaround / Quirk flags */ + unsigned int bus_hz; /* Bus speed */ + + unsigned int caps; /* Capabilities */ + + /* delay in mS before detecting cards after interrupt */ + unsigned int detect_delay_ms; + + int (*init)(unsigned int slot_id,void* irq_handler_t , void *); + unsigned int (*get_ro)(struct fhmci_host *host); + unsigned int (*get_cd)(struct fhmci_host *host); + int (*get_ocr)(unsigned int slot_id); + int (*get_bus_wd)(unsigned int slot_id); + /* + * Enable power to selected slot and set voltage to desired level. + * Voltage levels are specified using MMC_VDD_xxx defines defined + * in linux/mmc/host.h file. + */ + void (*setpower)(unsigned int slot_id, unsigned int volt); + void (*exit)(unsigned int slot_id); + void (*select_slot)(unsigned int slot_id); + + struct dw_mci_dma_ops *dma_ops; + struct dma_pdata *data; + struct block_settings *blk_settings; + int fifo_depth; +}; + +union cmd_arg_s { + 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_ctrl { + unsigned int slot_idx; /*0: mmc0; 1: mmc1*/ + unsigned int mmc_ctrl_state; /*0: enable mmc_rescan; 1: disable mmc_rescan*/ +}; + +enum mmc_ctrl_state { + RESCAN_ENABLE = 0, + RESCAN_DISABLE +}; + +struct platform_device *get_mci_device(unsigned int index); +int storage_dev_set_mmc_rescan(struct mmc_ctrl *m_ctrl); +int read_mci_ctrl_states(int id_mmc_sd); + +#endif + diff --git a/arch/arm/mach-fh/include/mach/gpio.h b/arch/arm/mach-fh/include/mach/gpio.h new file mode 100644 index 00000000..781093dd --- /dev/null +++ b/arch/arm/mach-fh/include/mach/gpio.h @@ -0,0 +1,259 @@ +/* + * TI DaVinci GPIO Support + * + * Copyright (c) 2006 David Brownell + * Copyright (c) 2007, MontaVista Software, 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. + */ + +#ifndef __FH_GPIO_H +#define __FH_GPIO_H + +#include +#include + +#include + +#include +#include + +/* + * GPIO Direction + */ +#define GPIO_DIR_INPUT 0 +#define GPIO_DIR_OUTPUT 1 + +/* + * GPIO interrupt type + */ +#define GPIO_INT_TYPE_LEVEL 0 +#define GPIO_INT_TYPE_EDGE 1 + +/* + * GPIO interrupt polarity + */ +#define GPIO_INT_POL_LOW 0 +#define GPIO_INT_POL_HIGH 1 + +#define OFFSET_GPIO_SWPORTA_DR (0x0000) +#define OFFSET_GPIO_SWPORTA_DDR (0x0004) +#define OFFSET_GPIO_PORTA_CTL (0x0008) +#define OFFSET_GPIO_SWPORTB_DR (0x000C) +#define OFFSET_GPIO_SWPORTB_DDR (0x0010) +#define OFFSET_GPIO_PORTB_CTL (0x0014) +#define OFFSET_GPIO_INTEN (0x0030) +#define OFFSET_GPIO_INTMASK (0x0034) +#define OFFSET_GPIO_INTTYPE_LEVEL (0x0038) +#define OFFSET_GPIO_INT_POLARITY (0x003C) +#define OFFSET_GPIO_INTSTATUS (0x0040) +#define OFFSET_GPIO_RAWINTSTATUS (0x0044) +#define OFFSET_GPIO_DEBOUNCE (0x0048) +#define OFFSET_GPIO_PORTA_EOI (0x004C) +#define OFFSET_GPIO_EXT_PORTA (0x0050) +#define OFFSET_GPIO_EXT_PORTB (0x0054) + +static inline void FH_GPIO_SetValue(unsigned int base, int bit, int val) +{ + unsigned int reg; + + reg = GET_REG(base + OFFSET_GPIO_SWPORTA_DR); + reg = val ? (reg | (1 << bit)) : (reg & ~(1 << bit)); + SET_REG(base + OFFSET_GPIO_SWPORTA_DR, reg); +} + +static inline int FH_GPIO_GetValue(unsigned int base, int bit) +{ + return (GET_REG(base + OFFSET_GPIO_EXT_PORTA) >> bit) & 0x1; +} + +static inline void FH_GPIO_SetDirection(unsigned int base, int bit, int dir) +{ + unsigned int reg; + + reg = GET_REG(base + OFFSET_GPIO_SWPORTA_DDR); + reg = dir ? reg | (1 << bit) : reg & ~(1 << bit); + SET_REG(base + OFFSET_GPIO_SWPORTA_DDR, reg); +} + +static inline int FH_GPIO_GetDirection(unsigned int base, int bit) +{ + return (GET_REG(base + OFFSET_GPIO_SWPORTA_DDR) >> bit) & 0x1; +} + +static inline void FH_GPIOB_SetValue(unsigned int base, int bit, int val) +{ + unsigned int reg; + + reg = GET_REG(base + OFFSET_GPIO_SWPORTB_DR); + reg = val ? (reg | (1 << bit)) : (reg & ~(1 << bit)); + SET_REG(base + OFFSET_GPIO_SWPORTB_DR, reg); +} + +static inline int FH_GPIOB_GetValue(unsigned int base, int bit) +{ + return (GET_REG(base + OFFSET_GPIO_EXT_PORTB) >> bit) & 0x1; +} + +static inline void FH_GPIOB_SetDirection(unsigned int base, int bit, int dir) +{ + unsigned int reg; + + reg = GET_REG(base + OFFSET_GPIO_SWPORTB_DDR); + reg = dir ? reg | (1 << bit) : reg & ~(1 << bit); + SET_REG(base + OFFSET_GPIO_SWPORTB_DDR, reg); +} + +static inline int FH_GPIOB_GetDirection(unsigned int base, int bit) +{ + return (GET_REG(base + OFFSET_GPIO_SWPORTB_DDR) >> bit) & 0x1; +} + +static inline void FH_GPIO_EnableDebounce(unsigned int base, int bit, int bool) +{ + unsigned int reg; + + reg = GET_REG(base + OFFSET_GPIO_DEBOUNCE); + reg = bool ? reg | (1 << bit) : reg & ~(1 << bit); + SET_REG(base + OFFSET_GPIO_DEBOUNCE, reg); +} + +static inline void FH_GPIO_SetInterruptType(unsigned int base, int bit, + int type) +{ + unsigned int reg; + + reg = GET_REG(base + OFFSET_GPIO_INTTYPE_LEVEL); + reg = type ? reg | (1 << bit) : reg & ~(1 << bit); + SET_REG(base + OFFSET_GPIO_INTTYPE_LEVEL, reg); +} + +static inline void FH_GPIO_SetInterruptPolarity(unsigned int base, int bit, + int pol) +{ + unsigned int reg; + + reg = GET_REG(base + OFFSET_GPIO_INT_POLARITY); + reg = pol ? reg | (1 << bit) : reg & ~(1 << bit); + SET_REG(base + OFFSET_GPIO_INT_POLARITY, reg); +} + +static inline void FH_GPIO_EnableInterruptMask(unsigned int base, int bit, + int bool) +{ + unsigned int reg; + + reg = GET_REG(base + OFFSET_GPIO_INTMASK); + reg = bool ? reg | (1 << bit) : reg & ~(1 << bit); + SET_REG(base + OFFSET_GPIO_INTMASK, reg); +} + +static inline void FH_GPIO_EnableInterrupt(unsigned int base, int bit, int bool) +{ + unsigned int reg; + + reg = GET_REG(base + OFFSET_GPIO_INTEN); + reg = bool ? reg | (1 << bit) : reg & ~(1 << bit); + SET_REG(base + OFFSET_GPIO_INTEN, reg); +} + +static inline void FH_GPIO_SetEnableInterrupts(unsigned int base, + unsigned int val) +{ + SET_REG(base + OFFSET_GPIO_INTEN, val); +} + +static inline unsigned int FH_GPIO_GetEnableInterrupts(unsigned int base) +{ + return GET_REG(base + OFFSET_GPIO_INTEN); +} + +static inline unsigned int FH_GPIO_GetInterruptStatus(unsigned int base) +{ + return GET_REG(base + OFFSET_GPIO_INTSTATUS); +} + +static inline void FH_GPIO_ClearInterrupt(unsigned int base, int bit) +{ + unsigned int reg; + + reg = GET_REG(base + OFFSET_GPIO_PORTA_EOI); + reg |= (1 << bit); + SET_REG(base + OFFSET_GPIO_PORTA_EOI, reg); +} + +#define GPIO_NAME "FH_GPIO" + + +struct gpio_irq_info { + int irq_gpio; + int irq_line; + int irq_type; + int irq_gpio_val; + int irq_gpio_mode; +}; + +struct fh_gpio_chip { + struct gpio_chip chip; + void __iomem *base; + + struct platform_device *pdev; + int irq; + spinlock_t lock; + + u32 gpio_wakeups; + u32 gpio_backups; +}; + +/* + * The get/set/clear functions will inline when called with constant + * parameters referencing built-in GPIOs, for low-overhead bitbanging. + * + * gpio_set_value() will inline only on traditional Davinci style controllers + * with distinct set/clear registers. + * + * Otherwise, calls with variable parameters or referencing external + * GPIOs (e.g. on GPIO expander chips) use outlined functions. + */ +static inline void gpio_set_value(unsigned gpio, int value) +{ + __gpio_set_value(gpio, value); +} + +/* Returns zero or nonzero; works for gpios configured as inputs OR + * as outputs, at least for built-in GPIOs. + * + * NOTE: for built-in GPIOs, changes in reported values are synchronized + * to the GPIO clock. This is easily seen after calling gpio_set_value() + * and then immediately gpio_get_value(), where the gpio_get_value() will + * return the old value until the GPIO clock ticks and the new value gets + * latched. + */ +static inline int gpio_get_value(unsigned gpio) +{ + return __gpio_get_value(gpio); +} + +static inline int gpio_cansleep(unsigned gpio) +{ + return 0; +} + +static inline int gpio_to_irq(unsigned gpio) +{ + return __gpio_to_irq(gpio); +} + +static inline int irq_to_gpio(unsigned irq) +{ + return 0; +} + +void fh_gpio_irq_suspend(void); +void fh_gpio_irq_resume(void); + +#endif + diff --git a/arch/arm/mach-fh/include/mach/hardware.h b/arch/arm/mach-fh/include/mach/hardware.h new file mode 100644 index 00000000..af93e037 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/hardware.h @@ -0,0 +1,18 @@ +/* +* Copyright (c) 2010 Shanghai Fullhan Microelectronics Co., Ltd. +* All Rights Reserved. Confidential. +* +*This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#endif /* __ASM_ARCH_HARDWARE_H */ diff --git a/arch/arm/mach-fh/include/mach/i2c.h b/arch/arm/mach-fh/include/mach/i2c.h new file mode 100644 index 00000000..991000c5 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/i2c.h @@ -0,0 +1,327 @@ +/* +* Copyright (c) 2010 Shanghai Fullhan Microelectronics Co., Ltd. +* All Rights Reserved. Confidential. +* +*This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#ifndef __ASM_ARCH_I2C_H +#define __ASM_ARCH_I2C_H +#include "fh_predefined.h" + +//I2C +#define REG_I2C_CON (0x0000) +#define REG_I2C_TAR (0x0004) +#define REG_I2C_SAR (0x0008) +#define REG_I2C_HS_MADDR (0x000C) +#define REG_I2C_DATA_CMD (0x0010) +#define REG_I2C_SS_SCL_HCNT (0x0014) +#define REG_I2C_SS_SCL_LCNT (0x0018) +#define REG_I2C_FS_SCL_HCNT (0x001C) +#define REG_I2C_FS_SCL_LCNT (0x0020) +#define REG_I2C_HS_SCL_HCNT (0x0024) +#define REG_I2C_HS_SCL_LCNT (0x0028) +#define REG_I2C_INTR_STAT (0x002c) +#define REG_I2C_INTR_MASK (0x0030) +#define REG_I2C_RAW_INTR_STAT (0x0034) +#define REG_I2C_RX_TL (0x0038) +#define REG_I2C_TX_TL (0x003c) +#define REG_I2C_CLR_INTR (0x0040) +#define REG_I2C_ENABLE (0x006c) +#define REG_I2C_STATUS (0x0070) +#define REG_I2C_TXFLR (0x0074) +#define REG_I2C_RXFLR (0x0078) +#define REG_I2C_DMA_CR (0x0088) +#define REG_I2C_DMA_TDLR (0x008c) +#define REG_I2C_DMA_RDLR (0x0090) + +#define DW_IC_INTR_NONE 0x0 + + +enum BUS_STATUS { + I2C_BUSY, + I2C_IDLE +}; +enum RESULT { + SUCCESS, + FAILURE +}; +enum ENABLE_SET { + DISABLE, + ENABLE +}; +enum SPEED_MODE { + SSPEED = 1, + FSPEED = 2, + HSPEED = 3, +}; + +UINT32 I2c_Disable(UINT32 base_addr); + +void I2c_SetSpeed(UINT32 base_addr, UINT8 model); +void I2c_SetDeviceId(UINT32 base_addr, UINT32 deviceID); +void I2c_Enable(UINT32 enable); +UINT32 I2c_GetStatus(UINT32 base_addr); +void I2c_SetIr(UINT32 base_addr, UINT16 mask); +UINT32 I2c_Disable(UINT32 base_addr); + +void I2c_Init(UINT32 base_addr, UINT16 slave_addr, enum SPEED_MODE speed, + int txtl, int rxtl); + +/* function Macro */ +/******************************************************************************* +* Function Name : I2c_GetTxFifoDepth +* Description : get tx fifo depth +* Input : base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define I2c_GetTxFifoDepth( base_addr) (((GET_REG(base_addr + \ + DW_IC_COMP_PARAM_1)>> 16) & 0xff) + 1) + +/******************************************************************************* +* Function Name : I2c_GetRxFifoDepth +* Description : get rx fifo depth +* Input : base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define I2c_GetRxFifoDepth( base_addr) (((GET_REG(base_addr + \ + DW_IC_COMP_PARAM_1)>> 8) & 0xff) + 1) +/******************************************************************************* +* Function Name : I2c_SetDeviceId +* Description : set the slave addr +* Input : deviceID:slave addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define I2c_SetDeviceId( base_addr,deviceID) SET_REG(base_addr + REG_I2C_TAR,deviceID) //set IIC slave address + +/******************************************************************************* +* Function Name : I2c_Read +* Description : read data from I2C bus +* Input : None +* Output : None +* Return : data:I2C data +* + *******************************************************************************/ + +#define I2c_Read(base_addr ) (GET_REG(base_addr + REG_I2C_DATA_CMD)&0xff) //DW_I2C_DATA_CMD +/******************************************************************************* +* Function Name : I2c_SetSsSclHcnt +* Description : set i2c ss scl hcnt +* Input : hcnt +* Output : None +* Return : data:I2C data +* + *******************************************************************************/ + +#define I2c_SetSsHcnt(base_addr, hcnt) SET_REG(base_addr + DW_IC_SS_SCL_HCNT,hcnt) + +/******************************************************************************* +* Function Name : I2c_SetSsSclLcnt +* Description : set i2c ss scl lcnt +* Input : lcnt +* Output : None +* Return : data:I2C data +* + *******************************************************************************/ + +#define I2c_SetSsLcnt(base_addr, lcnt) SET_REG(base_addr + DW_IC_SS_SCL_LCNT,lcnt) +/******************************************************************************* +* Function Name : I2c_SetFsSclHcnt +* Description : set i2c fs scl hcnt +* Input : hcnt +* Output : None +* Return : data:I2C data +* + *******************************************************************************/ + +#define I2c_SetFsHcnt(base_addr, hcnt) SET_REG(base_addr + DW_IC_FS_SCL_HCNT,hcnt) + +/******************************************************************************* +* Function Name : I2c_SetFsSclLcnt +* Description : set i2c fs scl lcnt +* Input : lcnt +* Output : None +* Return : data:I2C data +* + *******************************************************************************/ + +#define I2c_SetFsLcnt(base_addr, lcnt) SET_REG(base_addr + DW_IC_FS_SCL_LCNT,lcnt) +/******************************************************************************* +* Function Name : I2c_Disable +* Description : disable I2C bus +* Input : None +* Output : None +* Return : None +* + *******************************************************************************/ +#define I2c_DisEnable(base_addr) SET_REG(base_addr + REG_I2C_ENABLE,DISABLE); +/******************************************************************************* +* Function Name : I2c_Enable +* Description : set the I2C bus enable +* Input : enable +* Output : None +* Return : None +* + *******************************************************************************/ +#define I2c_Enable(base_addr) SET_REG(base_addr + REG_I2C_ENABLE,ENABLE); +/******************************************************************************* +* Function Name : I2c_Write +* Description : Write data to I2C bus +* Input : data:wirte out data +* Output : None +* Return : None +* + *******************************************************************************/ +#define I2c_Write(base_addr, data) SET_REG(base_addr + REG_I2C_DATA_CMD,data) + +/******************************************************************************* +* Function Name : I2c_GetTxTl +* Description : Get TX_TL +* Input : TX_TL +* Return : None + *******************************************************************************/ +#define I2c_GetTxTl(base_addr ) (GET_REG(base_addr + REG_I2C_TX_TL)&0xff); +/******************************************************************************* +* Function Name : I2c_GetRxTl +* Description : Get RX_TL +* Input : RX_TL +* Return : None + *******************************************************************************/ +#define I2c_GetRxTl(base_addr ) (GET_REG(base_addr + REG_I2C_RX_TL)&0xff); +/******************************************************************************* +* Function Name : I2c_GetRxFLR +* Description : Get RX_FLR +* Input : base_addr +* Return : None + *******************************************************************************/ +#define I2c_GetRxFLR(base_addr) (GET_REG(base_addr + DW_IC_RXFLR)&0xff); +/******************************************************************************* +* Function Name : I2c_GetTxFLR +* Description : Get TX_FLR +* Input : base_addr +* Return : None + *******************************************************************************/ +#define I2c_GetTxFLR(base_addr) (GET_REG(base_addr + DW_IC_TXFLR)&0xff); +/******************************************************************************* +* Function Name : I2c_SetTxRxTl +* Description : set TX_TL RX_TL +* Input : TX_TL, RX_TL +* Return : None + *******************************************************************************/ +#define I2c_SetTxRxTl(base_addr ,txtl,rxtl) \ + SET_REG(base_addr + REG_I2C_TX_TL, txtl); \ + SET_REG(base_addr + REG_I2C_RX_TL, rxtl) + +/******************************************************************************* +* Function Name : I2c_IsActiveMst +* Description : if master mode is active, return 1 +* Input : none +* Return : MST_ACTIVITY (IC_STATUS[5]) + *******************************************************************************/ +#define I2c_IsActiveMst(base_addr) (GET_REG(base_addr + REG_I2C_STATUS)>>5 & 1) + +/******************************************************************************* +* Function Name : I2c_SetCon +* Description : set config +* Input : config +* Return : None + *******************************************************************************/ +#define I2c_SetCon(base_addr,config) SET_REG(base_addr + REG_I2C_CON,config) +/******************************************************************************* +* Function Name : I2c_GetCon +* Description : get config +* Input : config +* Return : None + *******************************************************************************/ +#define I2c_GetCon(base_addr) GET_REG(base_addr + REG_I2C_CON) + +/******************************************************************************* +* Function Name : I2c_Status +* Description : get i2c status +* Input : None +* Return : None + *******************************************************************************/ +#define I2c_Status(base_addr) GET_REG(base_addr + REG_I2C_STATUS) + +/******************************************************************************* +* Function Name : I2c_SetTar +* Description : set target address +* Input : id +* Return : None + *******************************************************************************/ +#define I2c_SetTar(base_addr, id) SET_REG(base_addr + REG_I2C_TAR,id) + +/******************************************************************************* +* Function Name : I2c_SetIntrMask +* Description : set interrupt mask +* Input : mask +* Return : None + *******************************************************************************/ +#define I2c_SetIntrMask(base_addr,mask) SET_REG(base_addr + REG_I2C_INTR_MASK,mask) + +/******************************************************************************* +* Function Name : I2c_ClrIntr +* Description : clear interrupt +* Input : mask +* Return : None + *******************************************************************************/ +#define I2c_ClrIntr(base_addr,mask) GET_REG(base_addr + mask) +/******************************************************************************* +* Function Name : I2c_REG_STATUS +* Description : clear interrupt +* Input : mask +* Return : None + *******************************************************************************/ +#define I2c_GetTxAbrtSource(base_addr) GET_REG(base_addr + DW_IC_TX_ABRT_SOURCE) + +/******************************************************************************* +* Function Name : I2c_TxEmpty +* Description : TX_EMPTY interrupt assert +* Input : none +* Return : TX_EMPTY + *******************************************************************************/ +#define I2c_TxEmpty(base_addr) (GET_REG(base_addr + REG_I2C_RAW_INTR_STAT) & M_TX_EMPTY) + +/******************************************************************************* +* Function Name : I2c_RxFull +* Description : RX_FULL interrupt assert +* Input : none +* Return : RX_FULL + *******************************************************************************/ +#define I2c_RxFull(base_addr) (GET_REG(base_addr + REG_I2C_RAW_INTR_STAT) & M_RX_FULL) +/******************************************************************************* +* Function Name : I2c_RxEmpty +* Description : RX_EMPTY interrupt assert +* Input : none +* Return : RX_EMPTY + *******************************************************************************/ +#define I2c_RxEmpty(base_addr) (GET_REG(base_addr + REG_I2C_RAW_INTR_STAT) & M_RX_OVER) + +/* register define */ +typedef union { + struct { + UINT32 MASTER_MODE : 1; + UINT32 SPEED : 2; + UINT32 IC_10BITADDR_SLAVE : 1; + UINT32 IC_10BITADDR_MASTER : 1; + UINT32 IC_RESTART_EN : 1; + UINT32 IC_SLAVE_DISABLE : 1; + UINT32 reserved_31_7 : 25; + } x; + UINT32 dw; +} Reg_I2c_Con; + +#endif /* __ASM_ARCH_I2C_H */ diff --git a/arch/arm/mach-fh/include/mach/io.h b/arch/arm/mach-fh/include/mach/io.h new file mode 100644 index 00000000..7a987d6e --- /dev/null +++ b/arch/arm/mach-fh/include/mach/io.h @@ -0,0 +1,126 @@ +/* + * fh io definitions + * + * Copyright (C) 2014 Fullhan Microelectronics 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. + */ +#ifndef __ASM_ARCH_IO_H +#define __ASM_ARCH_IO_H + +#include + +#define IO_SPACE_LIMIT 0xffffffff + +/* + * We don't actually have real ISA nor PCI buses, but there is so many + * drivers out there that might just work if we fake them... + */ +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) +#define __mem_isa(a) (a) + +#ifndef CONFIG_JLINK_DEBUG +#define FH_VIRT 0xFE000000 + +#define VA_INTC_REG_BASE (FH_VIRT + 0x00000) +#define VA_TIMER_REG_BASE (FH_VIRT + 0x10000) +#define VA_UART0_REG_BASE (FH_VIRT + 0x20000) +//#define VA_GMAC_REG_BASE (FH_VIRT + 0x30000) +//#define VA_SPI0_REG_BASE (FH_VIRT + 0x40000) +//#define VA_GPIO_REG_BASE (FH_VIRT + 0x50000) +//#define VA_DMAC_REG_BASE (FH_VIRT + 0x60000) +//#define VA_SDC0_REG_BASE (FH_VIRT + 0x70000) +//#define VA_I2C_REG_BASE (FH_VIRT + 0x80000) +#define VA_PMU_REG_BASE (FH_VIRT + 0x90000) +//#define VA_SDC1_REG_BASE (FH_VIRT + 0xa0000) +// +#define VA_UART1_REG_BASE (FH_VIRT + 0xb0000) +#define VA_PAE_REG_BASE (FH_VIRT + 0xc0000) + +#define VA_RAM_REG_BASE (FH_VIRT + 0xd0000) +#define VA_DDRC_REG_BASE (FH_VIRT + 0xe0000) +#define VA_UART2_REG_BASE (FH_VIRT + 0xf0000) +#ifdef CONFIG_ARCH_FH +#define VA_CONSOLE_REG_BASE VA_UART1_REG_BASE +#else +#define VA_CONSOLE_REG_BASE VA_UART0_REG_BASE +#endif + +#define I2C_OFFSET (VA_I2C_REG_BASE - I2C_REG_BASE) +#define VI2C(x) (x + I2C_OFFSET) + +#define INTC_OFFSET (VA_INTC_REG_BASE - INTC_REG_BASE) +#define VINTC(x) (x + INTC_OFFSET) + +#define TIME_OFFSET (VA_TIMER_REG_BASE - TIMER_REG_BASE) +#define VTIMER(x) (x + TIME_OFFSET) + +#define UART0_OFFSET (VA_UART0_REG_BASE - UART0_REG_BASE) +#define VUART0(x) (x + UART0_OFFSET) + +#define UART1_OFFSET (VA_UART1_REG_BASE - UART1_REG_BASE) +#define VUART1(x) (x + UART1_OFFSET) + +#define UART2_OFFSET (VA_UART2_REG_BASE - UART2_REG_BASE) +#define VUART2(x) (x + UART2_OFFSET) + +#define SPI0_OFFSET (VA_SPI0_REG_BASE - SPI0_REG_BASE) +#define VSPI0(x) (x + SPI0_OFFSET) + +#define GMAC_OFFSET (VA_GMAC_REG_BASE - GMAC_REG_BASE) +#define VGMAC(x) (x + GMAC_OFFSET) + +#define DMAC_OFFSET (VA_DMAC_REG_BASE - DMAC_REG_BASE) +#define VDMAC(x) (x + DMAC_OFFSET) + +#define SDC0_OFFSET (VA_SDC0_REG_BASE - SDC0_REG_BASE) +#define VSDC0(x) (x + SDC0_OFFSET) + +#define SDC1_OFFSET (VA_SDC1_REG_BASE - SDC1_REG_BASE) +#define VSDC1(x) (x + SDC1_OFFSET) + +#define GPIO_OFFSET (VA_GPIO_REG_BASE - GPIO_REG_BASE) +#define VGPIO(x) (x + GPIO_OFFSET) + +#define PMU_OFFSET (VA_PMU_REG_BASE - PMU_REG_BASE) +#define VPMU(x) (x + PMU_OFFSET) + +#define PAE_OFFSET (VA_PAE_REG_BASE - PAE_REG_BASE) +#define VPAE(x) (x + PAE_OFFSET) + +#else +#define VA_INTC_REG_BASE INTC_REG_BASE +#define VA_TIMER_REG_BASE TIMER_REG_BASE +#define VA_UART0_REG_BASE UART0_REG_BASE +#define VA_UART1_REG_BASE UART1_REG_BASE +#define VA_GMAC_REG_BASE GMAC_REG_BASE +#define VA_DMAC_REG_BASE DMAC_REG_BASE +#define VA_I2C_REG_BASE I2C_REG_BASE +#define VA_SDC0_REG_BASE SDC0_REG_BASE + +#define VA_SPI0_REG_BASE SPI0_REG_BASE + +#define VA_GPIO_REG_BASE GPIO0_REG_BASE +#define VA_PMU_REG_BASE PMU_REG_BASE + +//#define VA_GPIO_REG_BASE (FH_VIRT + 0x500000) + +#define VINTC(x) x +#define VTIMER(x) x +#define VUART0(x) x +#define VUART1(x) x +#define VGMAC(x) x + +#define VDMAC(x) x +#define VI2C(x) x +#define VSDC0(x) x + +#define VSPI0(x) x +#define VPMU(x) x + +#endif +#endif /* __ASM_ARCH_IO_H */ diff --git a/arch/arm/mach-fh/include/mach/iomux.h b/arch/arm/mach-fh/include/mach/iomux.h new file mode 100644 index 00000000..398b0a6e --- /dev/null +++ b/arch/arm/mach-fh/include/mach/iomux.h @@ -0,0 +1,165 @@ +#ifndef IOMUX_H_ +#define IOMUX_H_ +#include +#include +#include + +#define IOMUX_PADTYPE(n) (Iomux_PadType##n *) +#define IOMUX_PUPD_NONE 0 +#define IOMUX_PUPD_DOWN 1 +#define IOMUX_PUPD_UP 2 +#define IOMUX_PUPD_KEEPER 3 +//#define IOMUX_DEBUG + + +typedef union { + struct { + __u32 sr : 1; + __u32 reserved_3_1 : 3; + + __u32 e8_e4 : 2; + __u32 reserved_31_6 : 24; + + } bit; + __u32 dw; +} Iomux_PadType5; + +typedef union { + struct { + __u32 sr : 1; + __u32 reserved_3_1 : 3; + + __u32 e8_e4 : 2; + __u32 reserved_7_6 : 2; + + __u32 mfs : 1; + __u32 reserved_31_9 : 23; + + } bit; + __u32 dw; +} Iomux_PadType8; + + +typedef union { + struct { + __u32 smt : 1; + __u32 reserved_3_1 : 3; + + __u32 ie : 1; + __u32 reserved_7_5 : 3; + + __u32 pu_pd : 2; + __u32 reserved_31_10 : 22; + + } bit; + __u32 dw; +} Iomux_PadType9; + + +typedef union { + struct { + __u32 e4_e2 : 2; + __u32 reserved_3_2 : 2; + + __u32 smt : 1; + __u32 reserved_7_5 : 3; + + __u32 ie : 1; + __u32 reserved_11_9 : 3; + + __u32 mfs : 2; + __u32 reserved_31_14 : 18; + + } bit; + __u32 dw; +} Iomux_PadType13; + +typedef union { + struct { + __u32 sr : 1; + __u32 reserved_3_1 : 3; + + __u32 e8_e4 : 2; + __u32 reserved_7_6 : 2; + + __u32 smt : 1; + __u32 reserved_11_9 : 3; + + __u32 ie : 1; + __u32 e : 1; //only for PAD_MAC_REF_CLK_CFG (0x00a4) + __u32 reserved_15_12 : 2; + + __u32 pu_pd : 2; + __u32 reserved_31_18 : 14; + + } bit; + __u32 dw; +} Iomux_PadType17; + +typedef union { + struct { + __u32 sr : 1; + __u32 reserved_3_1 : 3; + + __u32 e4_e2 : 2; + __u32 reserved_7_6 : 2; + + __u32 smt : 1; + __u32 reserved_11_9 : 3; + + __u32 ie : 1; + __u32 reserved_15_13 : 3; + + __u32 pu_pd : 2; + __u32 reserved_19_18 : 2; + + __u32 mfs : 1; + __u32 reserved_31_21 : 11; + + } bit; + __u32 dw; +} Iomux_PadType20; + + +typedef union { + struct { + __u32 sr : 1; + __u32 reserved_3_1 : 3; + + __u32 e4_e2 : 2; + __u32 reserved_7_6 : 2; + + __u32 smt : 1; + __u32 reserved_11_9 : 3; + + __u32 ie : 1; + __u32 reserved_15_13 : 3; + + __u32 pu_pd : 2; + __u32 reserved_19_18 : 2; + + __u32 mfs : 2; + __u32 reserved_31_21 : 10; + + } bit; + __u32 dw; +} Iomux_PadType21; + +typedef struct { + u32 *reg; + u32 reg_offset; + char *func_name[4]; + int reg_type; + int func_sel; + int drv_cur; + int pupd; +} Iomux_Pad; + +typedef struct { + void __iomem *base; + Iomux_Pad *pads; +} Iomux_Object; + +void fh_iomux_init(Iomux_Object *iomux_obj); + +#endif /* IOMUX_H_ */ diff --git a/arch/arm/mach-fh/include/mach/irqs.h b/arch/arm/mach-fh/include/mach/irqs.h new file mode 100644 index 00000000..0138006f --- /dev/null +++ b/arch/arm/mach-fh/include/mach/irqs.h @@ -0,0 +1,43 @@ +/* + * fh interrupt controller definitions + * + * Copyright (C) 2014 Fullhan Microelectronics 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. + */ +#ifndef __ASM_ARCH_IRQS_H +#define __ASM_ARCH_IRQS_H + +#include + +#define REG_IRQ_EN_LOW (INTC_REG_BASE + 0x0000) +#define REG_IRQ_EN_HIGH (INTC_REG_BASE + 0x0004) +#define REG_IRQ_IRQMASK_LOW (INTC_REG_BASE + 0x0008) +#define REG_IRQ_IRQMASK_HIGH (INTC_REG_BASE + 0x000C) +#define REG_IRQ_IRQFORCE_LOW (INTC_REG_BASE + 0x0010) +#define REG_IRQ_IRQFORCE_HIGH (INTC_REG_BASE + 0x0014) +#define REG_IRQ_RAWSTATUS_LOW (INTC_REG_BASE + 0x0018) +#define REG_IRQ_RAWSTATUS_HIGH (INTC_REG_BASE + 0x001C) +#define REG_IRQ_STATUS_LOW (INTC_REG_BASE + 0x0020) +#define REG_IRQ_STATUS_HIGH (INTC_REG_BASE + 0x0024) +#define REG_IRQ_MASKSTATUS_LOW (INTC_REG_BASE + 0x0028) +#define REG_IRQ_MASKSTATUS_HIGH (INTC_REG_BASE + 0x002C) +#define REG_IRQ_FINSTATUS_LOW (INTC_REG_BASE + 0x0030) +#define REG_IRQ_FINSTATUS_HIGH (INTC_REG_BASE + 0x0034) +#define REG_FIQ_EN_LOW (INTC_REG_BASE + 0x02C0) +#define REG_FIQ_EN_HIGH (INTC_REG_BASE + 0x02C4) +#define REG_FIQ_FIQMASK_LOW (INTC_REG_BASE + 0x02C8) +#define REG_FIQ_FIQMASK_HIGH (INTC_REG_BASE + 0x02CC) +#define REG_FIQ_FIQFORCE_LOW (INTC_REG_BASE + 0x02D0) +#define REG_FIQ_FIQFORCE_HIGH (INTC_REG_BASE + 0x02D4) +#define REG_FIQ_RAWSTATUS_LOW (INTC_REG_BASE + 0x02D8) +#define REG_FIQ_RAWSTATUS_HIGH (INTC_REG_BASE + 0x02DC) +#define REG_FIQ_STATUS_LOW (INTC_REG_BASE + 0x02E0) +#define REG_FIQ_STATUS_HIGH (INTC_REG_BASE + 0x02E4) +#define REG_FIQ_FINSTATUS_LOW (INTC_REG_BASE + 0x02E8) +#define REG_FIQ_FINSTATUS_HIGH (INTC_REG_BASE + 0x02EC) + +#endif /* __ASM_ARCH_IRQS_H */ diff --git a/arch/arm/mach-fh/include/mach/memory.h b/arch/arm/mach-fh/include/mach/memory.h new file mode 100644 index 00000000..c8c984a9 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/memory.h @@ -0,0 +1,27 @@ +/* + * fh memory space definitions + * + * Copyright (C) 2014 Fullhan Microelectronics 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. + */ +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +/************************************************************************** + * Included Files + **************************************************************************/ +#include +#include + +/************************************************************************** + * Definitions + **************************************************************************/ +#define FH_DDR_BASE 0xA0000000 + +#define PLAT_PHYS_OFFSET FH_DDR_BASE + +#endif /* __ASM_ARCH_MEMORY_H */ diff --git a/arch/arm/mach-fh/include/mach/pinctrl.h b/arch/arm/mach-fh/include/mach/pinctrl.h new file mode 100644 index 00000000..90c02c11 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/pinctrl.h @@ -0,0 +1,118 @@ +#ifndef PINCTRL_H_ +#define PINCTRL_H_ +#include "pinctrl_osdep.h" +#include + +#define PINCTRL_UNUSED (-1) + +#define PUPD_NONE (0) +#define PUPD_UP (1) +#define PUPD_DOWN (2) + +#define INPUT_DISABLE (0) +#define INPUT_ENABLE (1) +#define OUTPUT_DISABLE (0) +#define OUTPUT_ENABLE (1) + +#define FUNC0 (0) +#define FUNC1 (1) +#define FUNC2 (2) +#define FUNC3 (3) +#define FUNC4 (4) +#define FUNC5 (5) +#define FUNC6 (6) +#define FUNC7 (7) + +#define NEED_CHECK_PINLIST (1) + +#define MAX_FUNC_NUM 8 + +#define PINCTRL_FUNC(name, id, sel, pupd) \ +PinCtrl_Pin PAD##id##_##name = \ +{ \ + .pad_id = id, \ + .func_name = #name, \ + .reg_offset = (id * 4), \ + .func_sel = sel, \ + .pullup_pulldown= pupd, \ +} + +#define PINCTRL_MUX(pname, sel, ...) \ +PinCtrl_Mux MUX_##pname = \ +{ \ + .mux_pin = { __VA_ARGS__ }, \ + .cur_pin = sel, \ +} + +#define PINCTRL_DEVICE(name, count, ...) \ +typedef struct \ +{ \ + char *dev_name; \ + int mux_count; \ + OS_LIST list; \ + PinCtrl_Mux *mux[count]; \ +} PinCtrl_Device_##name; \ +PinCtrl_Device_##name pinctrl_dev_##name = \ +{ \ + .dev_name = #name, \ + .mux_count = count, \ + .mux = { __VA_ARGS__ }, \ +} + +typedef union { + struct + { + unsigned int : 12; //0~11 + unsigned int ie : 1; //12 + unsigned int : 3; //13~15 + unsigned int pdn : 1; //16 + unsigned int : 3; //17~19 + unsigned int pun : 1; //20 + unsigned int : 3; //21~23 + unsigned int mfs : 4; //24~27 + unsigned int oe : 1; //28 + unsigned int : 3; //29~31 + } bit; + unsigned int dw; +} PinCtrl_Register; + +typedef struct +{ + char *func_name; + PinCtrl_Register *reg; + int pad_id : 12; + unsigned int reg_offset : 12; + int func_sel : 4; + int input_enable : 1; + int output_enable : 1; + int pullup_pulldown : 2; +}PinCtrl_Pin; + +typedef struct +{ + //todo: int lock; + int cur_pin; + PinCtrl_Pin *mux_pin[MUX_NUM]; +} PinCtrl_Mux; + +typedef struct +{ + void *vbase; + void *pbase; + PinCtrl_Pin *pinlist[PAD_NUM]; +} PinCtrl_Object; + +typedef struct +{ + char *dev_name; + int mux_count; + OS_LIST list; + void *mux; +}PinCtrl_Device; + +void fh_pinctrl_init(unsigned int base); +void fh_pinctrl_prt(struct seq_file *sfile); +int fh_pinctrl_smux(char *devname, char* muxname, int muxsel, unsigned int flag); +int fh_pinctrl_sdev(char *devname, unsigned int flag); +void fh_pinctrl_init_devicelist(OS_LIST *list); +#endif /* PINCTRL_H_ */ diff --git a/arch/arm/mach-fh/include/mach/pinctrl_osdep.h b/arch/arm/mach-fh/include/mach/pinctrl_osdep.h new file mode 100644 index 00000000..8e3d24de --- /dev/null +++ b/arch/arm/mach-fh/include/mach/pinctrl_osdep.h @@ -0,0 +1,23 @@ +#ifndef PINCTRL_OSDEP_H_ +#define PINCTRL_OSDEP_H_ + +#include +#include +#include +#include + +#define OS_LIST_INIT LIST_HEAD_INIT +#define OS_LIST struct list_head +#define OS_PRINT printk +#define OS_LIST_EMPTY INIT_LIST_HEAD +#define OS_NULL NULL + +#define PINCTRL_ADD_DEVICE(name) \ + list_add(&pinctrl_dev_##name.list, \ + list) + +#define PAD_NUM (77) + +#define MUX_NUM (6) + +#endif /* PINCTRL_OSDEP_H_ */ diff --git a/arch/arm/mach-fh/include/mach/pmu.h b/arch/arm/mach-fh/include/mach/pmu.h new file mode 100644 index 00000000..e9de6447 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/pmu.h @@ -0,0 +1,15 @@ + +#ifndef _FH_PMU_H_ +#define _FH_PMU_H_ + +#include + +void fh_pmu_set_reg(u32 offset, u32 data); +u32 fh_pmu_get_reg(u32 offset); +int fh_pmu_init(void); + +void fh_pmu_stop(void); + +void fh_pae_set_reg(u32 offset, u32 data); + +#endif /* _FH_PMU_H_ */ diff --git a/arch/arm/mach-fh/include/mach/rtc.h b/arch/arm/mach-fh/include/mach/rtc.h new file mode 100644 index 00000000..594259eb --- /dev/null +++ b/arch/arm/mach-fh/include/mach/rtc.h @@ -0,0 +1,238 @@ +/* + * rtc.h + * + * Created on: Aug 18, 2016 + * Author: fullhan + */ + +#ifndef ARCH_ARM_MACH_FH_INCLUDE_MACH_RTC_H_ +#define ARCH_ARM_MACH_FH_INCLUDE_MACH_RTC_H_ +#include "fh_predefined.h" + +/* + * Registers offset + */ +#define FH_RTC_COUNTER 0x0 +#define FH_RTC_OFFSET 0x4 +#define FH_RTC_POWER_FAIL 0x8 +#define FH_RTC_ALARM_COUNTER 0xC +#define FH_RTC_INT_STAT 0x10 +#define FH_RTC_INT_EN 0x14 +#define FH_RTC_SYNC 0x18 +#define FH_RTC_DEBUG 0x1C +#define FH_RTC_USER_REG 0x20 + +#define SEC_BIT_START 0 +#define SEC_VAL_MASK 0x3f + +#define MIN_BIT_START 6 +#define MIN_VAL_MASK 0xfc0 + +#define HOUR_BIT_START 12 +#define HOUR_VAL_MASK 0x1f000 + +#define DAY_BIT_START 17 +#define DAY_VAL_MASK 0xfffe0000 + +#define FH_RTC_ISR_SEC_POS 1<<0 +#define FH_RTC_ISR_MIN_POS 1<<1 +#define FH_RTC_ISR_HOUR_POS 1<<2 +#define FH_RTC_ISR_DAY_POS 1<<3 +#define FH_RTC_ISR_ALARM_POS 1<<4 +#define FH_RTC_ISR_SEC_MASK 1<<27 +#define FH_RTC_ISR_MIN_MASK 1<<28 +#define FH_RTC_ISR_HOUR_MASK 1<<29 +#define FH_RTC_ISR_DAY_MASK 1<<30 +#define FH_RTC_ISR_ALARM_MASK 1<<31 + +// input: val=fh_rtc_get_time(base_addr) +#define FH_GET_RTC_SEC(val) ((val & SEC_VAL_MASK) >> SEC_BIT_START) +#define FH_GET_RTC_MIN(val) ((val & MIN_VAL_MASK) >> MIN_BIT_START) +#define FH_GET_RTC_HOUR(val) ((val & HOUR_VAL_MASK) >> HOUR_BIT_START) +#define FH_GET_RTC_DAY(val) ((val & DAY_VAL_MASK) >> DAY_BIT_START) + +#define ELAPSED_LEAP_YEARS(y) (((y -1)/4)-((y-1)/100)+((y+299)/400)-17) + +#define FH_RTC_PROC_FILE "driver/fh_rtc" + +struct fh_rtc_platform_data +{ + u32 clock_in; + char *clk_name; + char *dev_name; + u32 base_year; + u32 base_month; + u32 base_day; + int sadc_channel; +}; +enum +{ + init_done=1, + initing=0 + +}; + +/******************************************************************************* +* Function Name : fh_rtc_interrupt_disabel +* Description : disabale rtc interrupt +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_interrupt_disabel(base_addr) SET_REG(base_addr+REG_RTC_INT_EN,DISABLE) + +/******************************************************************************* +* Function Name : fh_rtc_get_time +* Description : get rtc current time +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_get_time(base_addr) GET_REG(base_addr+FH_RTC_COUNTER) + +/******************************************************************************* +* Function Name : fh_rtc_set_time +* Description : set rtc current time +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_set_time(base_addr,value) SET_REG(base_addr+FH_RTC_COUNTER,value) + +/******************************************************************************* +* Function Name : fh_rtc_set_alarm_time +* Description : set rtc alarm +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_set_alarm_time(base_addr,value) SET_REG(base_addr+FH_RTC_ALARM_COUNTER,value) + +/******************************************************************************* +* Function Name : fh_rtc_get_alarm_time +* Description : get alarm register +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_get_alarm_time(base_addr) GET_REG(base_addr+FH_RTC_ALARM_COUNTER) + +/******************************************************************************* +* Function Name : fh_rtc_get_int_status +* Description : get rtc current interrupt status +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_get_int_status(base_addr) GET_REG(base_addr+FH_RTC_INT_STAT) +/******************************************************************************* +* Function Name : fh_rtc_enable_interrupt +* Description : enable rtc interrupt +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_enable_interrupt(base_addr,value) SET_REG(base_addr+FH_RTC_INT_EN,value|GET_REG(base_addr+FH_RTC_INT_EN)) +/******************************************************************************* +* Function Name : fh_rtc_disenable_interrupt +* Description : disable interrupt +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_disenable_interrupt(base_addr,value) SET_REG(base_addr+FH_RTC_INT_EN,(~value)&GET_REG(base_addr+FH_RTC_INT_EN)) + +/******************************************************************************* +* Function Name : fh_rtc_get_enabled_interrupt +* Description : get rtc current interrupt enabled +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_get_enabled_interrupt(base_addr) GET_REG(base_addr+FH_RTC_INT_EN) +/******************************************************************************* +* Function Name : fh_rtc_set_mask_interrupt +* Description : set rtc interrupt mask +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_set_mask_interrupt(base_addr,value) SET_REG(base_addr+FH_RTC_INT_EN,value|GET_REG(base_addr+FH_RTC_INT_EN)) +/******************************************************************************* +* Function Name : fh_rtc_clear_interrupt_status +* Description : clear rtc interrupt status +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_clear_interrupt_status(base_addr,value) SET_REG(base_addr+FH_RTC_INT_STAT,(~value)&GET_REG(base_addr+FH_RTC_INT_STAT)) +/******************************************************************************* +* Function Name : fh_rtc_get_offset +* Description : get rtc offset +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_get_offset(base_addr) GET_REG(base_addr+FH_RTC_OFFSET) +/******************************************************************************* +* Function Name : fh_rtc_get_power_fail +* Description : get rtc power fail register +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_get_power_fail(base_addr) GET_REG(base_addr+FH_RTC_POWER_FAIL) + +/******************************************************************************* +* Function Name : fh_rtc_get_sync +* Description : get rtc sync register value +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_get_sync(base_addr) GET_REG(base_addr+FH_RTC_SYNC) + +/******************************************************************************* +* Function Name : fh_rtc_set_sync +* Description : set rtc sync register value +* Input : rtc base addr,init_done/initing +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_set_sync(base_addr,value) SET_REG(base_addr+FH_RTC_SYNC,value) + +/******************************************************************************* +* Function Name : fh_rtc_get_debug +* Description : get rtc debug register value +* Input : rtc base addr +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_get_debug(base_addr) GET_REG(base_addr+FH_RTC_DEBUG) + +/******************************************************************************* +* Function Name : fh_rtc_set_debug +* Description : set rtc debug register value +* Input : rtc base addr,x pclk +* Output : None +* Return : None +* + *******************************************************************************/ +#define fh_rtc_set_debug(base_addr,value) SET_REG(base_addr+FH_RTC_DEBUG,value) +#endif /* ARCH_ARM_MACH_FH_INCLUDE_MACH_RTC_H_ */ diff --git a/arch/arm/mach-fh/include/mach/spi.h b/arch/arm/mach-fh/include/mach/spi.h new file mode 100644 index 00000000..cc350f0e --- /dev/null +++ b/arch/arm/mach-fh/include/mach/spi.h @@ -0,0 +1,57 @@ +/* + * Copyright 2009 Texas Instruments. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __ARCH_ARM_FH_SPI_H +#define __ARCH_ARM_FH_SPI_H + +#include +#include + +#define SPI_MASTER_CONTROLLER_MAX_SLAVE (2) +#define SPI_TRANSFER_USE_DMA (0x77888877) + +struct fh_spi_cs { + u32 GPIO_Pin; + char *name; +}; + +struct fh_spi_chip { + u8 poll_mode; /* 0 for contoller polling mode */ + u8 type; /* SPI/SSP/Micrwire */ + u8 enable_dma; + void *cs_control; +// void (*cs_control)(u32 command); +}; + +struct fh_spi_platform_data { + u32 apb_clock_in; + u32 fifo_len; + u32 slave_max_num; + struct fh_spi_cs cs_data[SPI_MASTER_CONTROLLER_MAX_SLAVE]; + //below is dma transfer needed + u32 dma_transfer_enable; + u32 rx_handshake_num; + u32 tx_handshake_num; + u32 bus_no; + char *clk_name; + u32 rx_dma_channel; + u32 tx_dma_channel; + +}; + +#endif /* __ARCH_ARM_FH_SPI_H */ diff --git a/arch/arm/mach-fh/include/mach/sram.h b/arch/arm/mach-fh/include/mach/sram.h new file mode 100644 index 00000000..46d2dcd1 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/sram.h @@ -0,0 +1,25 @@ +/* + * mach/sram.h - FH simple SRAM allocator + * + * Copyright (C) 2014 Fullhan Microelectronics 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. + */ +#ifndef __MACH_SRAM_H +#define __MACH_SRAM_H + +/* + * SRAM allocations return a CPU virtual address, or NULL on error. + * If a DMA address is requested and the SRAM supports DMA, its + * mapped address is also returned. + * + * Errors include SRAM memory not being available, and requesting + * DMA mapped SRAM on systems which don't allow that. + */ +extern void *sram_alloc(size_t len, dma_addr_t *dma); +extern void sram_free(void *addr, size_t len); + +#endif /* __MACH_SRAM_H */ diff --git a/arch/arm/mach-fh/include/mach/system.h b/arch/arm/mach-fh/include/mach/system.h new file mode 100644 index 00000000..fbcda2b2 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/system.h @@ -0,0 +1,40 @@ +/* + * mach/system.h + * + * Copyright (C) 2014 Fullhan Microelectronics 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. + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include +#include +#include +#include +#include +#include +#include + +extern void fh_intc_init(void); + +void fh_irq_suspend(void); +void fh_irq_resume(void); + +extern unsigned int fh_cpu_suspend_sz; +extern void fh_cpu_suspend(void); + +static inline void arch_idle(void) +{ + /* cpu_do_idle(); */ +} + +static inline void arch_reset(char mode, const char *cmd) +{ + fh_pmu_set_reg(REG_PMU_SWRST_MAIN_CTRL, 0x7fffffff); +} + +#endif /* __ASM_ARCH_SYSTEM_H */ diff --git a/arch/arm/mach-fh/include/mach/timex.h b/arch/arm/mach-fh/include/mach/timex.h new file mode 100644 index 00000000..308fd1ee --- /dev/null +++ b/arch/arm/mach-fh/include/mach/timex.h @@ -0,0 +1,22 @@ +/* + * FH timer subsystem + * + * Copyright (C) 2014 Fullhan Microelectronics 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. + */ +#ifndef __ASM_ARCH_TIMEX_H +#define __ASM_ARCH_TIMEX_H + +#define TIMER0_CLK (1000000) +#define TIMER1_CLK (1000000) +#define PAE_PTS_CLK (1000000) + +#define CLOCK_TICK_RATE TIMER0_CLK + +extern struct sys_timer fh_timer; + +#endif /* __ASM_ARCH_TIMEX_H__ */ diff --git a/arch/arm/mach-fh/include/mach/uncompress.h b/arch/arm/mach-fh/include/mach/uncompress.h new file mode 100644 index 00000000..819c6257 --- /dev/null +++ b/arch/arm/mach-fh/include/mach/uncompress.h @@ -0,0 +1,57 @@ +/* + * Serial port stubs for kernel decompress status messages + * + * Initially based on: + * arch/arm/plat-omap/include/mach/uncompress.h + * + * Original copyrights follow. + * + * Copyright (C) 2000 RidgeRun, Inc. + * Author: Greg Lonnon + * + * Rewritten by: + * Author: + * 2004 (c) MontaVista Software, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include + +#include +#include + +#define REG_UART_THR (0x0000) +#define REG_UART_USR (0x007c) + +#define REG_UART0_THR (*(unsigned char *)(CONSOLE_REG_BASE + REG_UART_THR)) +#define REG_UART0_USR (*(unsigned char *)(CONSOLE_REG_BASE + REG_UART_USR)) + +static void putc(char c) +{ + while (!(REG_UART0_USR & (1 << 1))) + barrier(); + + REG_UART0_THR = c; +} + +static inline void flush(void) +{ + while (!(REG_UART0_USR & (1 << 2))) + barrier(); +} + +static inline void set_uart_info(u32 phys, void *__iomem virt) +{ + +} + +static inline void __arch_decomp_setup(unsigned long arch_id) +{ + +} + +#define arch_decomp_setup() __arch_decomp_setup(arch_id) +#define arch_decomp_wdog() diff --git a/arch/arm/mach-fh/include/mach/vmalloc.h b/arch/arm/mach-fh/include/mach/vmalloc.h new file mode 100644 index 00000000..7796486e --- /dev/null +++ b/arch/arm/mach-fh/include/mach/vmalloc.h @@ -0,0 +1,16 @@ +/* + * DaVinci vmalloc definitions + * + * Author: Kevin Hilman, MontaVista Software, Inc. + * + * 2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#include + +/* Allow vmalloc range until the IO virtual range minus a 2M "hole" */ +///#define VMALLOC_END (IO_VIRT - (2<<20)) + +#define VMALLOC_END (PAGE_OFFSET + 0x3e000000) diff --git a/arch/arm/mach-fh/iomux.c b/arch/arm/mach-fh/iomux.c new file mode 100644 index 00000000..f042a4bd --- /dev/null +++ b/arch/arm/mach-fh/iomux.c @@ -0,0 +1,854 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +Iomux_Pad fh_iomux_cfg[] = { + { + .func_name = { "RESETN", "", "", "", }, + .reg_type = 9, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = -1, + }, + { + .func_name = { "TEST", "", "", "", }, + .reg_type = 9, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = -1, + }, + { + .func_name = { "CIS_CLK", "", "", "", }, + .reg_type = 5, + .func_sel = 0, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "CIS_HSYNC", "GPIO20", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "CIS_VSYNC", "GPIO21", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "CIS_PCLK", "", "", "", }, + .reg_type = 9, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 0, + }, + { + .func_name = { "CIS_D0", "GPIO22", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "CIS_D1", "GPIO23", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "CIS_D2", "GPIO24", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "CIS_D3", "GPIO25", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "CIS_D4", "GPIO26", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "CIS_D5", "GPIO27", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "CIS_D6", "GPIO28", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "CIS_D7", "GPIO29", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "CIS_D8", "GPIO30", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "CIS_D9", "GPIO31", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "CIS_D10", "GPIO32", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "CIS_D11", "GPIO33", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "MAC_REF_CLK", "", "", "", }, + .reg_type = 17, + .func_sel = 0, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 3, + }, + { + .func_name = { "MAC_MDC", "GPIO34", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 0, + }, + { + .func_name = { "MAC_MDIO", "", "", "", }, + .reg_type = 17, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "MAC_COL", "GPIO35", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "MAC_CRS", "GPIO36", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "MAC_RXCK", "", "", "", }, + .reg_type = 9, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = -1, + }, + { + .func_name = { "MAC_RXD0", "", "", "", }, + .reg_type = 17, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = -1, + }, + + { + .func_name = { "MAC_RXD1", "GPIO38", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "MAC_RXD2", "GPIO39", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "MAC_RXD3", "GPIO40", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "MAC_RXDV", "GPIO41", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "MAC_TXCK", "", "", "", }, + .reg_type = 9, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = -1, + }, + { + .func_name = { "MAC_TXD0", "GPIO42", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "MAC_TXD1", "GPIO43", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "MAC_TXD2", "GPIO44", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "MAC_TXD3", "GPIO45", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "MAC_TXEN", "GPIO46", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "MAC_RXER", "GPIO47", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "GPIO0", "ARC_JTAG_TCK", "GPIO0", "CIS_SSI0_CSN1", }, + .reg_type = 21, + .func_sel = 0, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "GPIO1", "ARC_JTAG_TRSTN", "GPIO1", "CIS_SSI0_RXD", }, + .reg_type = 21, + .func_sel = 0, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "GPIO2", "ARC_JTAG_TMS", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "GPIO3", "ARC_JTAG_TDI", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "GPIO4", "ARC_JTAG_TDO", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "JTAG_TCK", "GPIO5", "", "", }, + .reg_type = 20, + .func_sel = 1, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "JTAG_TRSTN", "GPIO6", "PWM_OUT3", "", }, + .reg_type = 20, + .func_sel = 1, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "JTAG_TMS", "GPIO7", "", "", }, + .reg_type = 20, + .func_sel = 1, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "JTAG_TDI", "GPIO8", "", "", }, + .reg_type = 20, + .func_sel = 1, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "JTAG_TDO", "GPIO9", "", "", }, + .reg_type = 20, + .func_sel = 1, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "GPIO10", "UART1_OUT", "", "", }, + .reg_type = 20, + .func_sel = 1, + .pupd = IOMUX_PUPD_UP, + .drv_cur = 1, + }, + { + .func_name = { "GPIO11", "UART1_IN", "", "", }, + .reg_type = 20, + .func_sel = 1, + .pupd = IOMUX_PUPD_UP, + .drv_cur = 1, + }, + { + .func_name = { "GPIO12", "PWM_OUT0", "", "", }, + .reg_type = 20, + .func_sel = 1, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "GPIO13", "PWM_OUT1", "", "", }, + .reg_type = 20, + .func_sel = 1, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "GPIO14", "PWM_OUT2", "", "", }, + .reg_type = 20, + .func_sel = 1, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "RESERVED", "", "", "", }, + .reg_type = 20, + .func_sel = -1, + }, + { + .func_name = { "RESERVED", "", "", "", }, + .reg_type = 20, + .func_sel = -1, + }, + { + .func_name = { "RESERVED", "", "", "", }, + .reg_type = 20, + .func_sel = -1, + }, + { + .func_name = { "RESERVED", "", "", "", }, + .reg_type = 20, + .func_sel = -1, + }, + { + .func_name = { "RESERVED", "", "", "", }, + .reg_type = 20, + .func_sel = -1, + }, + { + .func_name = { "UART0_IN", "GPIO48", "UART0_IN", " I2S_WS", }, + .reg_type = 21, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = 1, + }, + { + .func_name = { "UART0_OUT", "GPIO49", "UART0_OUT", "I2S_CLK", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = 1, + }, + { + .func_name = { "CIS_SCL", "GPIO56", "CIS_SCL", "CIS_SSI0_CLK", }, + .reg_type = 13, + .func_sel = 0, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "CIS_SDA", "GPIO57", "CIS_SDA", "CIS_SSI0_TXD", }, + .reg_type = 13, + .func_sel = 0, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "SCL1", "GPIO50", "SCL1", "I2S_DI", }, + .reg_type = 21, + .func_sel = 0, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "SDA1", "GPIO51", "I2S_DO", "", }, + .reg_type = 21, + .func_sel = 0, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "SSI0_CLK", "", "", "", }, + .reg_type = 5, + .func_sel = 0, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "SSI0_TXD", "", "", "", }, + .reg_type = 5, + .func_sel = 0, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "SSI0_CSN0", "GPIO54", "", "", }, + .reg_type = 20, + .func_sel = 1, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "SSI0_CSN1", "GPIO55", "", "", }, + .reg_type = 20, + .func_sel = 1, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "SSI0_RXD", "", "", "", }, + .reg_type = 17, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = -1, + }, + { + .func_name = { "SD0_CD", "GPIO52", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "SD0_WP", "GPIO53", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "SD0_CLK", "", "", "", }, + .reg_type = 5, + .func_sel = 0, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 3, + }, + { + .func_name = { "SD0_CMD_RSP", "", "", "", }, + .reg_type = 17, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = 3, + }, + { + .func_name = { "SD0_DATA0", "", "", "", }, + .reg_type = 17, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = 3, + }, + { + .func_name = { "SD0_DATA1", "", "", "", }, + .reg_type = 17, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = 2, + }, + { + .func_name = { "SD0_DATA2", "", "", "", }, + .reg_type = 17, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = 3, + }, + { + .func_name = { "SD0_DATA3", "", "", "", }, + .reg_type = 17, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = 3, + }, + { + .func_name = { "SD1_CLK", "SSI1_CLK", "", "", }, + .reg_type = 8, + .func_sel = 0, + .pupd = IOMUX_PUPD_NONE, + .drv_cur = 1, + }, + { + .func_name = { "SD1_CD", "GPIO_58", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "SD1_WP", "GPIO_59", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, + { + .func_name = { "SD1_DATA0", "SSI1_TXD", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = 3, + }, + { + .func_name = { "SD1_DATA1", "SSI1_CSN0", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = 3, + }, + { + .func_name = { "SD1_DATA2", "SSI1_CSN1", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = 3, + }, + { + .func_name = { "SD1_DATA3", "", "", "", }, + .reg_type = 17, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = 3, + }, + { + .func_name = { "SD1_CMD_RSP", "SSI1_RXD", "", "", }, + .reg_type = 20, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = 3, + }, + { + .func_name = { "RESERVED", "", "", "", }, + .reg_type = 20, + .func_sel = -1, + }, + { + .func_name = { "RESERVED", "", "", "", }, + .reg_type = 20, + .func_sel = -1, + }, + { + .func_name = { "RESERVED", "", "", "", }, + .reg_type = 20, + .func_sel = -1, + }, + { + .func_name = { "RESERVED", "", "", "", }, + .reg_type = 20, + .func_sel = -1, + }, + { + .func_name = { "CLK_SW0", "", "", "", }, + .reg_type = 9, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = -1, + }, + { + .func_name = { "CLK_SW1", "", "", "", }, + .reg_type = 9, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = -1, + }, + { + .func_name = { "CLK_SW2", "", "", "", }, + .reg_type = 9, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = -1, + }, + { + .func_name = { "CLK_SW3", "", "", "", }, + .reg_type = 9, + .func_sel = 0, + .pupd = IOMUX_PUPD_UP, + .drv_cur = -1, + }, + { + .func_name = { "RESERVED", "", "", "", }, + .reg_type = 20, + .func_sel = -1, + }, + { + .func_name = { "MAC_TXER", "GPIO37", "", "", }, + .reg_type = 20, + .func_sel = 1, + .pupd = IOMUX_PUPD_DOWN, + .drv_cur = 1, + }, +}; + + +static void fh_iomux_setmfs(Iomux_Object *iomux_obj, Iomux_Pad *pad) +{ + switch (pad->reg_type) { + case 8: + (IOMUX_PADTYPE(8)pad->reg)->bit.mfs = pad->func_sel; + break; + case 13: + (IOMUX_PADTYPE(13)pad->reg)->bit.mfs = pad->func_sel; + break; + case 20: + (IOMUX_PADTYPE(20)pad->reg)->bit.mfs = pad->func_sel; + break; + case 21: + (IOMUX_PADTYPE(21)pad->reg)->bit.mfs = pad->func_sel; + break; + default: + break; + } + +} + +#ifdef IOMUX_DEBUG + +static int fh_iomux_getmfs(Iomux_Object *iomux_obj, Iomux_Pad *pad) +{ + int mfs; + + switch (pad->reg_type) { + case 8: + mfs = (IOMUX_PADTYPE(8)pad->reg)->bit.mfs; + break; + case 13: + mfs = (IOMUX_PADTYPE(13)pad->reg)->bit.mfs; + break; + case 20: + mfs = (IOMUX_PADTYPE(20)pad->reg)->bit.mfs; + break; + case 21: + mfs = (IOMUX_PADTYPE(21)pad->reg)->bit.mfs; + break; + default: + mfs = -1; + break; + + } + return mfs; +} + + +static void fh_iomux_print(Iomux_Object *iomux_obj) +{ + int i; + u32 reg; + + printk("\tPad No.\t\tFunction Select\t\tRegister\n"); + + for (i = 0; i < ARRAY_SIZE(fh_iomux_cfg); i++) { + int curr_func; + + curr_func = fh_iomux_getmfs(iomux_obj, &iomux_obj->pads[i]); + reg = readl((u32)iomux_obj->pads[i].reg); + + if (curr_func < 0) + printk("\t%d\t\t%-8s(no mfs)\t0x%08x\n", i, iomux_obj->pads[i].func_name[0], + reg); + else + printk("\t%d\t\t%-16s\t0x%08x\n", i, iomux_obj->pads[i].func_name[curr_func], + reg); + + } + +} + +#endif + +static void fh_iomux_setcur(Iomux_Object *iomux_obj, Iomux_Pad *pad) +{ + switch (pad->reg_type) { + case 5: + (IOMUX_PADTYPE(5)pad->reg)->bit.e8_e4 = pad->drv_cur; + break; + case 8: + (IOMUX_PADTYPE(8)pad->reg)->bit.e8_e4 = pad->drv_cur; + break; + case 13: + (IOMUX_PADTYPE(13)pad->reg)->bit.e4_e2 = pad->drv_cur; + break; + case 17: + (IOMUX_PADTYPE(17)pad->reg)->bit.e8_e4 = pad->drv_cur; + break; + case 20: + (IOMUX_PADTYPE(20)pad->reg)->bit.e4_e2 = pad->drv_cur; + break; + case 21: + (IOMUX_PADTYPE(21)pad->reg)->bit.e4_e2 = pad->drv_cur; + break; + default: + break; + } + +} + +static void fh_iomux_setpupd(Iomux_Object *iomux_obj, Iomux_Pad *pad) +{ + switch (pad->reg_type) { + case 9: + (IOMUX_PADTYPE(9)pad->reg)->bit.pu_pd = pad->pupd; + break; + case 17: + (IOMUX_PADTYPE(17)pad->reg)->bit.pu_pd = pad->pupd; + break; + case 20: + (IOMUX_PADTYPE(20)pad->reg)->bit.pu_pd = pad->pupd; + break; + case 21: + (IOMUX_PADTYPE(21)pad->reg)->bit.pu_pd = pad->pupd; + break; + default: + break; + } +} + +static void fh_iomux_setrest(Iomux_Object *iomux_obj, Iomux_Pad *pad) +{ + switch (pad->reg_type) { + case 5: + (IOMUX_PADTYPE(5)pad->reg)->bit.sr = 0; + break; + case 8: + (IOMUX_PADTYPE(8)pad->reg)->bit.sr = 0; + break; + case 9: + (IOMUX_PADTYPE(9)pad->reg)->bit.ie = 1; + (IOMUX_PADTYPE(9)pad->reg)->bit.smt = 1; + break; + case 13: + (IOMUX_PADTYPE(13)pad->reg)->bit.ie = 1; + (IOMUX_PADTYPE(13)pad->reg)->bit.smt = 1; + break; + case 17: + (IOMUX_PADTYPE(17)pad->reg)->bit.sr = 0; + (IOMUX_PADTYPE(17)pad->reg)->bit.ie = 1; + (IOMUX_PADTYPE(17)pad->reg)->bit.e = 1; + (IOMUX_PADTYPE(17)pad->reg)->bit.smt = 1; + break; + case 20: + (IOMUX_PADTYPE(20)pad->reg)->bit.sr = 0; + (IOMUX_PADTYPE(20)pad->reg)->bit.ie = 1; + (IOMUX_PADTYPE(20)pad->reg)->bit.smt = 1; + break; + case 21: + (IOMUX_PADTYPE(21)pad->reg)->bit.sr = 0; + (IOMUX_PADTYPE(21)pad->reg)->bit.ie = 1; + (IOMUX_PADTYPE(21)pad->reg)->bit.smt = 1; + break; + default: + break; + } + +} + +void fh_iomux_init(Iomux_Object *iomux_obj) +{ + int i; + u32 reg = 0; + + iomux_obj->pads = fh_iomux_cfg; + + for (i = 0; i < ARRAY_SIZE(fh_iomux_cfg); i++) { + iomux_obj->pads[i].reg_offset = i * 4; + iomux_obj->pads[i].reg = ® + +#if defined(CONFIG_FH_PWM_NUM) && CONFIG_FH_PWM_NUM == 4 + //for pwm3 only + if(fh_iomux_cfg[i].func_sel == 2 + && iomux_obj->pads[i].reg_offset == 0xa8) + { + fh_pmu_set_reg(0x128, 0x00101110); + fh_iomux_cfg[i].func_sel = 1; + } +#endif + + if(iomux_obj->pads[i].func_sel < 0) + continue; + + fh_iomux_setmfs(iomux_obj, &fh_iomux_cfg[i]); + fh_iomux_setcur(iomux_obj, &fh_iomux_cfg[i]); + fh_iomux_setpupd(iomux_obj, &fh_iomux_cfg[i]); + fh_iomux_setrest(iomux_obj, &fh_iomux_cfg[i]); + fh_pmu_set_reg(0x5c + iomux_obj->pads[i].reg_offset, reg); + } +#ifdef CONFIG_FH_GMAC_RMII + //(IOMUX_PADTYPE(17)(iomux_obj->pads[18]).reg)->bit.e = 1; + reg = fh_pmu_get_reg(REG_PMU_PAD_MAC_REF_CLK_CFG); + reg |= (1 << 13); + fh_pmu_set_reg(REG_PMU_PAD_MAC_REF_CLK_CFG, reg); +#else + //(IOMUX_PADTYPE(17)(iomux_obj->pads[18]).reg)->bit.e = 0; + reg = fh_pmu_get_reg(REG_PMU_PAD_MAC_REF_CLK_CFG); + reg &= ~(1 << 13); + fh_pmu_set_reg(REG_PMU_PAD_MAC_REF_CLK_CFG, reg); +#endif +#ifdef IOMUX_DEBUG + fh_iomux_print(iomux_obj); +#endif +} diff --git a/arch/arm/mach-fh/irq.c b/arch/arm/mach-fh/irq.c new file mode 100644 index 00000000..a17666fa --- /dev/null +++ b/arch/arm/mach-fh/irq.c @@ -0,0 +1,151 @@ +/* + * Fullhan FH board support + * + * Copyright (C) 2014 Fullhan Microelectronics 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +static void fh_intc_ack(struct irq_data *d) +{ + +} +static void fh_intc_enable(struct irq_data *d) +{ + if (d->irq >= NR_INTERNAL_IRQS) + return; + + if (d->irq > 31) { + SET_REG_M(VINTC(REG_IRQ_EN_HIGH), 1 << (d->irq - 32), + 1 << (d->irq - 32)); + } else + SET_REG_M(VINTC(REG_IRQ_EN_LOW), 1 << d->irq, 1 << d->irq); + +} +static void fh_intc_disable(struct irq_data *d) +{ + if (d->irq >= NR_INTERNAL_IRQS) + return; + if (d->irq > 31) + SET_REG_M(VINTC(REG_IRQ_EN_HIGH), 0, 1 << (d->irq - 32)); + else + SET_REG_M(VINTC(REG_IRQ_EN_LOW), 0, 1 << d->irq); +} + +static void fh_intc_mask(struct irq_data *d) +{ + if (d->irq >= NR_INTERNAL_IRQS) + return; + if (d->irq > 31) { + SET_REG_M(VINTC(REG_IRQ_IRQMASK_HIGH), 1 << (d->irq - 32), + 1 << (d->irq - 32)); + } else + SET_REG_M(VINTC(REG_IRQ_IRQMASK_LOW), 1 << d->irq, 1 << d->irq); +} + +static void fh_intc_unmask(struct irq_data *d) +{ + if (d->irq >= NR_INTERNAL_IRQS) + return; + if (d->irq > 31) + SET_REG_M(VINTC(REG_IRQ_IRQMASK_HIGH), 0, 1 << (d->irq - 32)); + else + SET_REG_M(VINTC(REG_IRQ_IRQMASK_LOW), 0, 1 << d->irq); +} + +#ifdef CONFIG_PM + +static u32 wakeups_high; +static u32 wakeups_low; +static u32 backups_high; +static u32 backups_low; + +static int fh_intc_set_wake(struct irq_data *d, unsigned value) +{ + if (unlikely(d->irq >= NR_IRQS)) + return -EINVAL; + + if (value) { + if (d->irq > 31) + wakeups_high |= (1 << (d->irq - 32)); + else + wakeups_low |= (1 << d->irq); + } else { + if (d->irq > 31) + wakeups_high &= ~(1 << (d->irq - 32)); + else + wakeups_low &= ~(1 << d->irq); + } + return 0; +} + +void fh_irq_suspend(void) +{ + backups_high = GET_REG(VINTC(REG_IRQ_EN_HIGH)); + backups_low = GET_REG(VINTC(REG_IRQ_EN_LOW)); + + SET_REG(VINTC(REG_IRQ_EN_HIGH), wakeups_high); + SET_REG(VINTC(REG_IRQ_EN_LOW), wakeups_low); +} + +void fh_irq_resume(void) +{ + SET_REG(VINTC(REG_IRQ_EN_HIGH), backups_high); + SET_REG(VINTC(REG_IRQ_EN_LOW), backups_low); +} + +#else +#define fh_intc_set_wake NULL +#endif + +static struct irq_chip fh_irq_chip = { + .name = "FH_INTC", + .irq_ack = fh_intc_ack, + .irq_mask = fh_intc_mask, + .irq_unmask = fh_intc_unmask, + + .irq_enable = fh_intc_enable, + .irq_disable = fh_intc_disable, + .irq_set_wake = fh_intc_set_wake, +}; + +void __init fh_intc_init(void) +{ + int i; + + //disable all interrupts + SET_REG(VINTC(REG_IRQ_EN_LOW), 0x0); + SET_REG(VINTC(REG_IRQ_EN_HIGH), 0x0); + + for (i = 0; i < NR_IRQS; i++) { + irq_set_chip_and_handler(i, &fh_irq_chip, handle_level_irq); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + } + +} diff --git a/arch/arm/mach-fh/pinctrl.c b/arch/arm/mach-fh/pinctrl.c new file mode 100644 index 00000000..58fad592 --- /dev/null +++ b/arch/arm/mach-fh/pinctrl.c @@ -0,0 +1,299 @@ +#ifdef CONFIG_MACH_FH8830 +#ifdef CONFIG_MACH_FH8830_QFN +#include +#else +#include +#endif +#endif + +#ifdef CONFIG_MACH_FH8833 +#include +#endif + +#include +#include + +/* #define FH_PINCTRL_DEBUG */ +#ifdef FH_PINCTRL_DEBUG +#define PRINT_DBG(fmt,args...) OS_PRINT(fmt,##args) +#else +#define PRINT_DBG(fmt,args...) do{} while(0) +#endif + +static PinCtrl_Object pinctrl_obj; +OS_LIST fh_pinctrl_devices = OS_LIST_INIT(fh_pinctrl_devices); + +static int fh_pinctrl_func_select(PinCtrl_Pin *pin, unsigned int flag) +{ + unsigned int reg; + + if(!pin) + { + OS_PRINT("ERROR: pin is null\n\n"); + return -1; + } + + if(flag & NEED_CHECK_PINLIST) + { + if(pinctrl_obj.pinlist[pin->pad_id]) + { + OS_PRINT("ERROR: pad %d has already been set\n\n", pin->pad_id); + return -2; + } + } + + reg = GET_REG(pinctrl_obj.vbase + pin->reg_offset); + + pin->reg = (PinCtrl_Register *)® + + pin->reg->bit.mfs = pin->func_sel; + + if(pin->pullup_pulldown == PUPD_DOWN) + { + pin->reg->bit.pdn = 0; + } + else if(pin->pullup_pulldown == PUPD_UP) + { + pin->reg->bit.pun = 0; + } + else + { + pin->reg->bit.pdn = 1; + pin->reg->bit.pun = 1; + } + + pin->reg->bit.ie = 1; + + SET_REG(pinctrl_obj.vbase + pin->reg_offset, pin->reg->dw); + + pinctrl_obj.pinlist[pin->pad_id] = pin; + + return 0; +} + +static int fh_pinctrl_mux_switch(PinCtrl_Mux *mux, unsigned int flag) +{ + if(mux->cur_pin > MUX_NUM) + { + OS_PRINT("ERROR: selected function is not exist, sel_func=%d\n\n", mux->cur_pin); + return -3; + } + + if(!mux->mux_pin[mux->cur_pin]) + { + OS_PRINT("ERROR: mux->mux_pin[%d] has no pin\n\n", mux->cur_pin); + return -4; + } + + PRINT_DBG("\t%s[%d]\n", mux->mux_pin[mux->cur_pin]->func_name, mux->cur_pin); + return fh_pinctrl_func_select(mux->mux_pin[mux->cur_pin], flag); +} + + +static int fh_pinctrl_device_switch(PinCtrl_Device *dev, unsigned int flag) +{ + int i, ret; + for(i=0; imux_count; i++) + { + unsigned int *mux_addr = (unsigned int *)((unsigned int)dev + + sizeof(*dev) - 4 + i*4); + PinCtrl_Mux *mux = (PinCtrl_Mux *)(*mux_addr); + + ret = fh_pinctrl_mux_switch(mux, flag); + if(ret) + { + return ret; + } + } + + return 0; +} + +static PinCtrl_Device * fh_pinctrl_get_device_by_name(char *name) +{ + PinCtrl_Device *dev = OS_NULL; + + list_for_each_entry(dev, &fh_pinctrl_devices, list) + { + if(!strcmp(name, dev->dev_name)) + { + return dev; + } + } + + return 0; +} + +int fh_pinctrl_check_pinlist(void) +{ + int i; + for(i=0; idev_name); + ret = fh_pinctrl_device_switch(dev, flag); + PRINT_DBG("\n"); + if(ret) + { + return ret; + } + + } + + fh_pinctrl_check_pinlist(); + + return 0; + +} + +static void fh_pinctrl_init_pin(void) +{ + int i; + + for(i=0; ireg->dw = GET_REG(pinctrl_obj.vbase + + pin->reg_offset); + + pin->input_enable = pin->reg->bit.ie; + pin->output_enable = pin->reg->bit.oe; + } +} + + +void fh_pinctrl_init(unsigned int base) +{ + pinctrl_obj.vbase = pinctrl_obj.pbase = (void *)base; + + fh_pinctrl_init_devicelist(&fh_pinctrl_devices); + fh_pinctrl_init_devices(fh_pinctrl_selected_devices, + ARRAY_SIZE(fh_pinctrl_selected_devices), + NEED_CHECK_PINLIST); + fh_pinctrl_init_pin(); +} + +void fh_pinctrl_prt(struct seq_file *sfile) +{ + int i; + seq_printf(sfile, "%2s\t%8s\t%4s\t%8s\t%4s\t%4s\t%4s\t%4s\n", + "id", "name", "addr", "reg", "sel", "ie", "oe", "pupd"); + for(i=0; ipad_id, + pinctrl_obj.pinlist[i]->func_name, + pinctrl_obj.pinlist[i]->reg_offset + 0xf0000080, + GET_REG(pinctrl_obj.vbase + pinctrl_obj.pinlist[i]->reg_offset), + pinctrl_obj.pinlist[i]->func_sel, + pinctrl_obj.pinlist[i]->input_enable, + pinctrl_obj.pinlist[i]->output_enable, + pinctrl_obj.pinlist[i]->pullup_pulldown); + } + +} + + +int fh_pinctrl_smux(char *devname, char* muxname, int muxsel, unsigned int flag) +{ + PinCtrl_Device *dev; + int i, ret; + + dev = fh_pinctrl_get_device_by_name(devname); + + if(!dev) + { + OS_PRINT("ERROR: cannot find device %s\n", devname); + return -4; + } + + for(i=0; imux_count; i++) + { + unsigned int *mux_addr = (unsigned int *)((unsigned int)dev + + sizeof(*dev) - 4 + i*4); + PinCtrl_Mux *mux = (PinCtrl_Mux *)(*mux_addr); + + if(!strcmp(muxname, mux->mux_pin[0]->func_name)) + { + mux->cur_pin = muxsel; + ret = fh_pinctrl_mux_switch(mux, flag); + return ret; + } + } + + if(i == dev->mux_count) + { + OS_PRINT("ERROR: cannot find mux %s of device %s\n", muxname, devname); + return -6; + } + + fh_pinctrl_check_pinlist(); + + return 0; +} +EXPORT_SYMBOL(fh_pinctrl_smux); + +int fh_pinctrl_sdev(char *devname, unsigned int flag) +{ + PinCtrl_Device *dev; + int ret; + + dev = fh_pinctrl_get_device_by_name(devname); + if(!dev) + { + OS_PRINT("ERROR: cannot find device %s\n", devname); + return -7; + } + + OS_PRINT("%s:\n", dev->dev_name); + ret = fh_pinctrl_device_switch(dev, flag); + OS_PRINT("\n"); + if(ret) + { + return ret; + } + + fh_pinctrl_check_pinlist(); + + return 0; +} +EXPORT_SYMBOL(fh_pinctrl_sdev); diff --git a/arch/arm/mach-fh/pm.c b/arch/arm/mach-fh/pm.c new file mode 100644 index 00000000..a7ec90b5 --- /dev/null +++ b/arch/arm/mach-fh/pm.c @@ -0,0 +1,223 @@ +/* + * FH Power Management Routines + * + * Copyright (C) 2014 Fullhan Microelectronics 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PM +static u32 old_clk_gate = 0; + +static void (*fh_sram_suspend)(void); + +static inline void fh_pm_pll0_to_xtal(void) +{ + u32 reg; + + reg = fh_pmu_get_reg(REG_PMU_SYS_CTRL); + reg &= ~(0x1); + fh_pmu_set_reg(REG_PMU_SYS_CTRL, reg); +} + +static inline void fh_pm_xtal_to_pll0(void) +{ + u32 reg; + + reg = fh_pmu_get_reg(REG_PMU_SYS_CTRL); + reg |= 0x1; + fh_pmu_set_reg(REG_PMU_SYS_CTRL, reg); +} + +static inline void fh_pm_gate_clocks(void) +{ + u32 reg; + old_clk_gate = fh_pmu_get_reg(REG_PMU_CLK_GATE); + reg = fh_pmu_get_reg(REG_PMU_CLK_GATE); + reg |= 0x7fff3fb1; + fh_pmu_set_reg(REG_PMU_CLK_GATE, reg); +} + +static inline void fh_pm_ungate_clocks(void) +{ + u32 reg; + + reg = old_clk_gate; + fh_pmu_set_reg(REG_PMU_CLK_GATE, reg); +} + + +static void fh_sram_push(void *dest, void *src, unsigned int size) +{ + memcpy(dest, src, size); + flush_icache_range((unsigned long)dest, (unsigned long)(dest + size)); +} + +static int fh_pm_valid_state(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_ON: + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + return 1; + + default: + return 0; + } +} + +static void fh_pm_suspend_to_ram(void) +{ + fh_pm_pll0_to_xtal(); + fh_pm_gate_clocks(); + + fh_sram_suspend(); + + fh_pm_ungate_clocks(); + fh_pm_xtal_to_pll0(); +} + +static inline void fh_ddrc_selfrefresh_enable(void) +{ + u32 reg; + + /* + * Ensure that the Cadence DDR Controller is idle, + * that is when the controller_busy signal is low. + */ + do { + reg = readl(VA_DDRC_REG_BASE + OFFSET_DENAL_CTL_57); + } while (reg & DDRC_CONTROLLER_BUSY); + + /* + * Put the memories into self-refresh mode + * by issuing one of the self-refresh entry commands + * through the Low Power Control Module + */ + writel(DDRC_LPI_SR_WAKEUP_TIME | DDRC_LP_CMD_SELFREFRESH | DDRC_CKSRX_DELAY, + VA_DDRC_REG_BASE + OFFSET_DENAL_CTL_31); + + //wait no more + /* + do + { + reg = readl(VA_DDRC_REG_BASE + OFFSET_DENAL_CTL_97); + } + while(reg & DDRC_CKE_STATUS); + */ +} + +static inline void fh_ddrc_selfrefresh_disable(void) +{ + //Exit any low power state + writel(DDRC_LPI_SR_WAKEUP_TIME | DDRC_LP_CMD_EXITLOWPOWER | DDRC_CKSRX_DELAY, + VA_DDRC_REG_BASE + OFFSET_DENAL_CTL_31); +} + +static void fh_pm_suspend_to_cache(void) +{ + asm volatile("mov r1, #0\n\t" + "mcr p15, 0, r1, c7, c10, 4\n\t" + "mcr p15, 0, r1, c7, c0, 4\n\t" + : /* no output */ + : /* no input */ + : "r1"); + + fh_ddrc_selfrefresh_enable(); + + asm volatile("mov r1, #0\n\t" + "mcr p15, 0, r1, c7, c10, 4\n\t" + "mcr p15, 0, r1, c7, c0, 4\n\t" + : /* no output */ + : /* no input */ + : "r1"); + fh_ddrc_selfrefresh_disable(); +} + +static int fh_pm_enter(suspend_state_t state) +{ + int ret = 0; + + fh_irq_suspend(); + fh_gpio_irq_suspend(); + + switch (state) { + case PM_SUSPEND_ON: + cpu_do_idle(); + break; + case PM_SUSPEND_STANDBY: + fh_pm_suspend_to_cache(); + break; + case PM_SUSPEND_MEM: + fh_pm_suspend_to_ram(); + break; + default: + ret = -EINVAL; + } + + fh_gpio_irq_resume(); + fh_irq_resume(); + + return ret; +} + +static const struct platform_suspend_ops fh_pm_ops = { + .enter = fh_pm_enter, + .valid = fh_pm_valid_state, +}; + +static int __init fh_pm_probe(struct platform_device *pdev) +{ + fh_sram_suspend = sram_alloc(fh_cpu_suspend_sz, NULL); + if (!fh_sram_suspend) { + dev_err(&pdev->dev, "cannot allocate SRAM memory\n"); + return -ENOMEM; + } + fh_sram_push(fh_sram_suspend, fh_cpu_suspend, + fh_cpu_suspend_sz); + suspend_set_ops(&fh_pm_ops); + + return 0; +} + +static int __exit fh_pm_remove(struct platform_device *pdev) +{ + sram_free(fh_sram_suspend, fh_cpu_suspend_sz); + return 0; +} + +static struct platform_driver fh_pm_driver = { + .driver = + { + .name = "pm-fh", + .owner = THIS_MODULE, + }, + .remove = __exit_p(fh_pm_remove), +}; + +static int __init fh_pm_init(void) +{ + return platform_driver_probe(&fh_pm_driver, fh_pm_probe); +} +late_initcall(fh_pm_init); +#endif diff --git a/arch/arm/mach-fh/pmu.c b/arch/arm/mach-fh/pmu.c new file mode 100644 index 00000000..2e1dc40b --- /dev/null +++ b/arch/arm/mach-fh/pmu.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include + +#include +#include + +static int fh_pmu_flag_stop = 0; + +void fh_pmu_stop(void) +{ + fh_pmu_flag_stop = 1; +} +EXPORT_SYMBOL(fh_pmu_stop); + +void fh_pmu_set_reg(u32 offset, u32 data) +{ + if (fh_pmu_flag_stop) + return; + + if (offset > PMU_REG_SIZE) { + pr_err("fh_pmu_set_reg: offset is out of range"); + return; + } + writel(data, VPMU(PMU_REG_BASE + offset)); +} +EXPORT_SYMBOL(fh_pmu_set_reg); + +u32 fh_pmu_get_reg(u32 offset) +{ + if (fh_pmu_flag_stop) + return 0; + + if (offset > PMU_REG_SIZE) { + pr_err("fh_pmu_get_reg: offset is out of range"); + return 0; + } + return readl(VPMU(PMU_REG_BASE + offset)); +} +EXPORT_SYMBOL(fh_pmu_get_reg); + +void fh_pae_set_reg(u32 offset, u32 data) +{ + if (offset > 0x60) { + pr_err("fh_pae_set_reg: offset is out of range"); + return; + } + writel(data, VPAE(PAE_REG_BASE + offset)); +} +EXPORT_SYMBOL(fh_pae_set_reg); + +int fh_pmu_init(void) +{ + return 0; +} diff --git a/arch/arm/mach-fh/sleep.S b/arch/arm/mach-fh/sleep.S new file mode 100644 index 00000000..5eb4ac23 --- /dev/null +++ b/arch/arm/mach-fh/sleep.S @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include + +#ifdef CONFIG_PM +#define PMU_MASK_SWITCH_PLL0 0x1 +#define PMU_MASK_DDR_SEL 0x1000000 +#define PMU_MASK_DDR_DIV 0xff +#define PMU_MASK_PLL1_PDN 0x80000000 + + + .macro wait_ddrc_idle +1: ldr r3, [r1, #OFFSET_DENAL_CTL_57] + tst r3, #DDRC_CONTROLLER_BUSY + bne 1b + .endm + + + .macro enable_ddrc_selfrefresh + ldr r3, .fh_ddrc_cmd_en_self_refresh + str r3, [r1, #OFFSET_DENAL_CTL_31] + .endm + + + .macro wait_ddrc_cke +1: ldr r3, [r1, #OFFSET_DENAL_CTL_97] + tst r3, #DDRC_CKE_STATUS + bne 1b + .endm + + + .macro disable_ddrc_selfrefresh + ldr r3, .fh_ddrc_cmd_dis_self_refresh + str r3, [r1, #OFFSET_DENAL_CTL_31] + .endm + + + .macro ddr_to_pll0 + ldr r3, [r2, #REG_PMU_CLK_SEL] + bic r3, r3, #PMU_MASK_DDR_SEL + str r3, [r2, #REG_PMU_CLK_SEL] + .endm + + + .macro ddr_to_pll1 + ldr r3, [r2, #REG_PMU_CLK_SEL] + orr r3, r3, #PMU_MASK_DDR_SEL + str r3, [r2, #REG_PMU_CLK_SEL] + .endm + +#if 1 + .macro ddr_dec_feq + ldr r3, [r2, #REG_PMU_CLK_DIV1] + orr r3, r3, #PMU_MASK_DDR_DIV + str r3, [r2, #REG_PMU_CLK_SEL] + .endm + + + .macro ddr_inc_feq + ldr r3, [r2, #REG_PMU_CLK_DIV1] + bic r3, r3, #PMU_MASK_DDR_DIV + orr r3, r3, #0x1 + str r3, [r2, #REG_PMU_CLK_SEL] + .endm + + + .macro pll1_power_down + ldr r3, [r2, #REG_PMU_PLL1_CTRL] + bic r3, r3, #PMU_MASK_PLL1_PDN + str r3, [r2, #REG_PMU_PLL1_CTRL] + .endm + + + .macro pll1_power_on + ldr r3, [r2, #REG_PMU_PLL1_CTRL] + orr r3, r3, #PMU_MASK_PLL1_PDN + str r3, [r2, #REG_PMU_PLL1_CTRL] + .endm +#endif + + .text +ENTRY(fh_cpu_suspend) + + stmfd sp!, {r0-r12, lr} @ save registers on stack + + /* + + * Register usage: + * R1 = Base address of DDRC + * R2 = Base register for PMU + * R3 = temporary register + * R4 = temporary register + * + * R9 = Test address + */ + + ldr r1, .fh_va_base_ddrc + ldr r2, .fh_va_base_pmu + ldr r9, .fh_va_test_addr + + wait_ddrc_idle + enable_ddrc_selfrefresh + wait_ddrc_cke + + @ddr_dec_feq + ddr_to_pll0 + + @pll1_power_down + + mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier operation + mcr p15, 0, r0, c7, c0, 4 @ Wait-for-Interrupt + + @pll1_power_on + + @ddr_inc_feq + ddr_to_pll1 + + disable_ddrc_selfrefresh + + ldmfd sp!, {r0-r12, pc} + +ENDPROC(fh_cpu_suspend) + +.fh_va_base_ddrc: + .word VA_DDRC_REG_BASE + +.fh_va_base_pmu: + .word VA_PMU_REG_BASE + +.fh_va_test_addr: + .word 0xc03efef0 + +.fh_ddrc_cmd_en_self_refresh: + .word 0x3000a01 + +.fh_ddrc_cmd_dis_self_refresh: + .word 0x3000101 + +ENTRY(fh_cpu_suspend_sz) + .word . - fh_cpu_suspend +ENDPROC(fh_cpu_suspend_sz) +#endif diff --git a/arch/arm/mach-fh/sram.c b/arch/arm/mach-fh/sram.c new file mode 100644 index 00000000..4df4838b --- /dev/null +++ b/arch/arm/mach-fh/sram.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +static struct gen_pool *sram_pool; + +void *sram_alloc(size_t len, dma_addr_t *dma) +{ + unsigned long vaddr; + + if (!sram_pool) + return NULL; + + vaddr = gen_pool_alloc(sram_pool, len); + if (!vaddr) + return NULL; + + return (void *)vaddr; +} +EXPORT_SYMBOL(sram_alloc); + +void sram_free(void *addr, size_t len) +{ + gen_pool_free(sram_pool, (unsigned long) addr, len); +} +EXPORT_SYMBOL(sram_free); + + +/* + * REVISIT This supports CPU and DMA access to/from SRAM, but it + * doesn't (yet?) support some other notable uses of SRAM: as TCM + * for data and/or instructions; and holding code needed to enter + * and exit suspend states (while DRAM can't be used). + */ +static int __init sram_init(void) +{ + int status = 0; + + sram_pool = gen_pool_create(ilog2(SRAM_GRANULARITY), -1); + if (!sram_pool) + status = -ENOMEM; + + if (sram_pool) + status = gen_pool_add(sram_pool, VA_RAM_REG_BASE, SRAM_SIZE, -1); + WARN_ON(status < 0); + return status; +} +core_initcall(sram_init); + diff --git a/arch/arm/mach-fh/time.c b/arch/arm/mach-fh/time.c new file mode 100644 index 00000000..f8978a4b --- /dev/null +++ b/arch/arm/mach-fh/time.c @@ -0,0 +1,278 @@ +/* + * FH timer subsystem + * + * Copyright (C) 2014 Fullhan Microelectronics 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define TIMERN_REG_BASE(n) (TIMER_REG_BASE + 0x14 * n) + +#define REG_TIMER_LOADCNT(n) (TIMERN_REG_BASE(n) + 0x00) +#define REG_TIMER_CUR_VAL(n) (TIMERN_REG_BASE(n) + 0x04) +#define REG_TIMER_CTRL_REG(n) (TIMERN_REG_BASE(n) + 0x08) +#define REG_TIMER_EOI_REG(n) (TIMERN_REG_BASE(n) + 0x0C) +#define REG_TIMER_INTSTATUS(n) (TIMERN_REG_BASE(n) + 0x10) + +#define REG_TIMERS_INTSTATUS (TIMER_REG_BASE + 0xa0) + +#define REG_PAE_PTS_REG 0xe7000040 + +static struct clock_event_device clockevent_fh; +static struct clocksource clocksource_fh; +#ifndef CONFIG_USE_PTS_AS_CLOCKSOURCE +static unsigned int prev_cycle = 0; +#endif + +struct clk *timer0_clk, *timer1_clk, *pts_clk; + +/* + * clockevent + */ + +static int fh_set_next_event(unsigned long cycles, + struct clock_event_device *evt) +{ + + /* SET_REG_M(VTIMER(REG_TIMER_CTRL_REG(1)), 0x00, 0x1); */ + SET_REG(VTIMER(REG_TIMER_LOADCNT(1)), cycles); + SET_REG_M(VTIMER(REG_TIMER_CTRL_REG(1)), 0x01, 0x1); + +#if defined(CONFIG_ARCH_FH8833) + fh_pmu_set_reg(REG_PMU_SWRST_MAIN_CTRL, 0xfffbffff); + while (fh_pmu_get_reg(REG_PMU_SWRST_MAIN_CTRL) != 0xffffffff) + ; +#endif + +#if defined(CONFIG_ARCH_FH8810) + unsigned int curr_val; + + curr_val = GET_REG(VTIMER(REG_TIMER_CUR_VAL(1))) ; + if (curr_val > 0x80000000) { + panic("timer curr %u, want cycles %lu\n", curr_val, cycles); + + SET_REG_M(VTIMER(REG_TIMER_CTRL_REG(1)), 0x01, 0x1); + SET_REG(VTIMER(REG_TIMER_LOADCNT(1)), cycles); + + fh_pmu_set_reg(REG_PMU_SWRST_MAIN_CTRL, 0xfff7ffff); + while (fh_pmu_get_reg(REG_PMU_SWRST_MAIN_CTRL) != 0xffffffff) + ; + } +#endif + return 0; +} + +static void fh_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + + SET_REG(VTIMER(REG_TIMER_CTRL_REG(1)), 0x3); + SET_REG(VTIMER(REG_TIMER_LOADCNT(1)), TIMER1_CLK / HZ); + +#if defined(CONFIG_ARCH_FH8833) + fh_pmu_set_reg(REG_PMU_SWRST_MAIN_CTRL, 0xfffbffff); + while (fh_pmu_get_reg(REG_PMU_SWRST_MAIN_CTRL) != 0xffffffff) + ; +#endif + +#if defined(CONFIG_ARCH_FH8810) + fh_pmu_set_reg(REG_PMU_SWRST_MAIN_CTRL, 0xfff7ffff); + while (fh_pmu_get_reg(REG_PMU_SWRST_MAIN_CTRL) != 0xffffffff) + ; +#endif + break; + case CLOCK_EVT_MODE_ONESHOT: + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + SET_REG(VTIMER(REG_TIMER_CTRL_REG(1)), 0x0); + break; + case CLOCK_EVT_MODE_RESUME: + SET_REG(VTIMER(REG_TIMER_CTRL_REG(1)), 0x3); + break; + } +} + + +static irqreturn_t fh_clock_timer_interrupt_handle(int irq, void *dev_id) +{ + unsigned int status; + status = GET_REG(VTIMER(REG_TIMERS_INTSTATUS)); + + +#ifdef CONFIG_FH_SIMPLE_TIMER + if (status & (1 << SIMPLE_TIMER_BASE)) + fh_simple_timer_interrupt(); +#endif + if (status & 0x2) { + GET_REG(VTIMER(REG_TIMER_EOI_REG(1))); + clockevent_fh.event_handler(&clockevent_fh); + } + + return IRQ_HANDLED; +} + +static struct irqaction fh_eventtimer_irq = { + .name = "System Timer Tick", + .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER, + .handler = fh_clock_timer_interrupt_handle, + .dev_id = &clockevent_fh, +}; + + +static void fh_timer_resources(void) +{ + +} +static DEFINE_CLOCK_DATA(cd); + +static void notrace fh_update_sched_clock(void) +{ + const cycle_t cyc = clocksource_fh.read(&clocksource_fh); + update_sched_clock(&cd, cyc, (u32)~0); +} + +unsigned long long notrace sched_clock(void) +{ + const cycle_t cyc = clocksource_fh.read(&clocksource_fh); + + return cyc_to_sched_clock(&cd, cyc, (u32)~0); +} + +static void fh_clocksource_init(void) +{ +#ifdef CONFIG_USE_PTS_AS_CLOCKSOURCE + unsigned long clock_tick_rate = pts_clk->frequency; +#else + unsigned long clock_tick_rate = timer0_clk->frequency; + prev_cycle = 0; +#endif + + if (clocksource_register_hz(&clocksource_fh, clock_tick_rate)) + panic("register clocksouce :%s error\n", clocksource_fh.name); + + printk(KERN_INFO "timer mult: 0x%x, timer shift: 0x%x\n", + clocksource_fh.mult, clocksource_fh.shift); + + /* force check the mult/shift of clocksource */ + init_fixed_sched_clock(&cd, fh_update_sched_clock, 32, clock_tick_rate, + clocksource_fh.mult, clocksource_fh.shift); +} + +static cycle_t fh_clocksource_read(struct clocksource *cs) +{ +#ifdef CONFIG_USE_PTS_AS_CLOCKSOURCE + return GET_REG(VPAE(REG_PAE_PTS_REG)); +#else + unsigned int cycle; + cycle = ~GET_REG(VTIMER(REG_TIMER_CUR_VAL(0))); +#ifdef CONFIG_ARCH_FH8810 + if (unlikely(prev_cycle > cycle)) + cycle = ~GET_REG(VTIMER(REG_TIMER_CUR_VAL(0))); + prev_cycle = cycle; +#endif + return cycle; +#endif +} + +static void fh_clockevent_init(void) +{ + setup_irq(TMR0_IRQ, &fh_eventtimer_irq); + clockevent_fh.mult = div_sc(timer1_clk->frequency, + NSEC_PER_SEC, clockevent_fh.shift); + clockevent_fh.max_delta_ns = clockevent_delta2ns(0xffffffff, + &clockevent_fh); + + clockevent_fh.min_delta_ns = clockevent_delta2ns(0xf, &clockevent_fh); + + clockevent_fh.cpumask = cpumask_of(0); + clockevents_register_device(&clockevent_fh); +} + + +static void __init fh_timer_init(void) +{ + + timer0_clk = clk_get(NULL, "tmr0_clk"); + timer1_clk = clk_get(NULL, "tmr0_clk"); + pts_clk = clk_get(NULL, "pts_clk"); + +#ifdef CONFIG_USE_PTS_AS_CLOCKSOURCE + clk_set_rate(pts_clk, PAE_PTS_CLK); + clk_enable(pts_clk); +#endif + + clk_set_rate(timer0_clk, TIMER0_CLK); + clk_enable(timer0_clk); + + clk_set_rate(timer1_clk, TIMER1_CLK); + clk_enable(timer1_clk); + timer0_clk->frequency = 1000000; + timer1_clk->frequency = 1000000; + if (IS_ERR(timer0_clk) || IS_ERR(timer1_clk) || IS_ERR(pts_clk)) + pr_err("fh_timer: clock is not defined\n"); + + + fh_timer_resources(); + fh_clocksource_init(); + fh_clockevent_init(); +#ifdef CONFIG_FH_SIMPLE_TIMER + fh_simple_timer_init(); +#endif +} + + + +static struct clocksource clocksource_fh = { + .name = "fh_clocksource", + .rating = 300, + .read = fh_clocksource_read, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + + +static struct clock_event_device clockevent_fh = { + .name = "fh_clockevent", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .shift = 32, + .set_next_event = fh_set_next_event, + .set_mode = fh_set_mode, +}; + +struct sys_timer fh_timer = { + .init = fh_timer_init, +}; diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 3b3776d0..96681cd9 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -1113,3 +1113,6 @@ blissc MACH_BLISSC BLISSC 3491 thales_adc MACH_THALES_ADC THALES_ADC 3492 ubisys_p9d_evp MACH_UBISYS_P9D_EVP UBISYS_P9D_EVP 3493 atdgp318 MACH_ATDGP318 ATDGP318 3494 +fh8810 MACH_FH8810 FH8810 9999 +fh8830 MACH_FH8830 FH8830 9999 +fh8833 MACH_FH8833 FH8833 9999 \ No newline at end of file diff --git a/arch/microblaze/boot/dts/system.dts b/arch/microblaze/boot/dts/system.dts deleted file mode 120000 index 7cb65789..00000000 --- a/arch/microblaze/boot/dts/system.dts +++ /dev/null @@ -1 +0,0 @@ -../../platform/generic/system.dts \ No newline at end of file diff --git a/arch/microblaze/boot/dts/system.dts b/arch/microblaze/boot/dts/system.dts new file mode 100644 index 00000000..3f85df2b --- /dev/null +++ b/arch/microblaze/boot/dts/system.dts @@ -0,0 +1,367 @@ +/* + * Device Tree Generator version: 1.1 + * + * (C) Copyright 2007-2008 Xilinx, Inc. + * (C) Copyright 2007-2009 Michal Simek + * + * Michal SIMEK + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * CAUTION: This file is automatically generated by libgen. + * Version: Xilinx EDK 10.1.03 EDK_K_SP3.6 + * + * XPS project directory: Xilinx-ML505-ll_temac-sgdma-MMU-FDT-edk101 + */ + +/dts-v1/; +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,microblaze"; + hard-reset-gpios = <&LEDs_8Bit 2 1>; + model = "testing"; + DDR2_SDRAM: memory@90000000 { + device_type = "memory"; + reg = < 0x90000000 0x10000000 >; + } ; + aliases { + ethernet0 = &Hard_Ethernet_MAC; + serial0 = &RS232_Uart_1; + } ; + chosen { + bootargs = "console=ttyUL0,115200 highres=on"; + linux,stdout-path = "/plb@0/serial@84000000"; + } ; + cpus { + #address-cells = <1>; + #cpus = <0x1>; + #size-cells = <0>; + microblaze_0: cpu@0 { + clock-frequency = <125000000>; + compatible = "xlnx,microblaze-7.10.d"; + d-cache-baseaddr = <0x90000000>; + d-cache-highaddr = <0x9fffffff>; + d-cache-line-size = <0x10>; + d-cache-size = <0x2000>; + device_type = "cpu"; + i-cache-baseaddr = <0x90000000>; + i-cache-highaddr = <0x9fffffff>; + i-cache-line-size = <0x10>; + i-cache-size = <0x2000>; + model = "microblaze,7.10.d"; + reg = <0>; + timebase-frequency = <125000000>; + xlnx,addr-tag-bits = <0xf>; + xlnx,allow-dcache-wr = <0x1>; + xlnx,allow-icache-wr = <0x1>; + xlnx,area-optimized = <0x0>; + xlnx,cache-byte-size = <0x2000>; + xlnx,d-lmb = <0x1>; + xlnx,d-opb = <0x0>; + xlnx,d-plb = <0x1>; + xlnx,data-size = <0x20>; + xlnx,dcache-addr-tag = <0xf>; + xlnx,dcache-always-used = <0x1>; + xlnx,dcache-byte-size = <0x2000>; + xlnx,dcache-line-len = <0x4>; + xlnx,dcache-use-fsl = <0x1>; + xlnx,debug-enabled = <0x1>; + xlnx,div-zero-exception = <0x1>; + xlnx,dopb-bus-exception = <0x0>; + xlnx,dynamic-bus-sizing = <0x1>; + xlnx,edge-is-positive = <0x1>; + xlnx,family = "virtex5"; + xlnx,endianness = <0x1>; + xlnx,fpu-exception = <0x1>; + xlnx,fsl-data-size = <0x20>; + xlnx,fsl-exception = <0x0>; + xlnx,fsl-links = <0x0>; + xlnx,i-lmb = <0x1>; + xlnx,i-opb = <0x0>; + xlnx,i-plb = <0x1>; + xlnx,icache-always-used = <0x1>; + xlnx,icache-line-len = <0x4>; + xlnx,icache-use-fsl = <0x1>; + xlnx,ill-opcode-exception = <0x1>; + xlnx,instance = "microblaze_0"; + xlnx,interconnect = <0x1>; + xlnx,interrupt-is-edge = <0x0>; + xlnx,iopb-bus-exception = <0x0>; + xlnx,mmu-dtlb-size = <0x4>; + xlnx,mmu-itlb-size = <0x2>; + xlnx,mmu-tlb-access = <0x3>; + xlnx,mmu-zones = <0x10>; + xlnx,number-of-pc-brk = <0x1>; + xlnx,number-of-rd-addr-brk = <0x0>; + xlnx,number-of-wr-addr-brk = <0x0>; + xlnx,opcode-0x0-illegal = <0x1>; + xlnx,pvr = <0x2>; + xlnx,pvr-user1 = <0x0>; + xlnx,pvr-user2 = <0x0>; + xlnx,reset-msr = <0x0>; + xlnx,sco = <0x0>; + xlnx,unaligned-exceptions = <0x1>; + xlnx,use-barrel = <0x1>; + xlnx,use-dcache = <0x1>; + xlnx,use-div = <0x1>; + xlnx,use-ext-brk = <0x1>; + xlnx,use-ext-nm-brk = <0x1>; + xlnx,use-extended-fsl-instr = <0x0>; + xlnx,use-fpu = <0x2>; + xlnx,use-hw-mul = <0x2>; + xlnx,use-icache = <0x1>; + xlnx,use-interrupt = <0x1>; + xlnx,use-mmu = <0x3>; + xlnx,use-msr-instr = <0x1>; + xlnx,use-pcmp-instr = <0x1>; + } ; + } ; + mb_plb: plb@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,plb-v46-1.03.a", "xlnx,plb-v46-1.00.a", "simple-bus"; + ranges ; + FLASH: flash@a0000000 { + bank-width = <2>; + compatible = "xlnx,xps-mch-emc-2.00.a", "cfi-flash"; + reg = < 0xa0000000 0x2000000 >; + xlnx,family = "virtex5"; + xlnx,include-datawidth-matching-0 = <0x1>; + xlnx,include-datawidth-matching-1 = <0x0>; + xlnx,include-datawidth-matching-2 = <0x0>; + xlnx,include-datawidth-matching-3 = <0x0>; + xlnx,include-negedge-ioregs = <0x0>; + xlnx,include-plb-ipif = <0x1>; + xlnx,include-wrbuf = <0x1>; + xlnx,max-mem-width = <0x10>; + xlnx,mch-native-dwidth = <0x20>; + xlnx,mch-plb-clk-period-ps = <0x1f40>; + xlnx,mch-splb-awidth = <0x20>; + xlnx,mch0-accessbuf-depth = <0x10>; + xlnx,mch0-protocol = <0x0>; + xlnx,mch0-rddatabuf-depth = <0x10>; + xlnx,mch1-accessbuf-depth = <0x10>; + xlnx,mch1-protocol = <0x0>; + xlnx,mch1-rddatabuf-depth = <0x10>; + xlnx,mch2-accessbuf-depth = <0x10>; + xlnx,mch2-protocol = <0x0>; + xlnx,mch2-rddatabuf-depth = <0x10>; + xlnx,mch3-accessbuf-depth = <0x10>; + xlnx,mch3-protocol = <0x0>; + xlnx,mch3-rddatabuf-depth = <0x10>; + xlnx,mem0-width = <0x10>; + xlnx,mem1-width = <0x20>; + xlnx,mem2-width = <0x20>; + xlnx,mem3-width = <0x20>; + xlnx,num-banks-mem = <0x1>; + xlnx,num-channels = <0x0>; + xlnx,priority-mode = <0x0>; + xlnx,synch-mem-0 = <0x0>; + xlnx,synch-mem-1 = <0x0>; + xlnx,synch-mem-2 = <0x0>; + xlnx,synch-mem-3 = <0x0>; + xlnx,synch-pipedelay-0 = <0x2>; + xlnx,synch-pipedelay-1 = <0x2>; + xlnx,synch-pipedelay-2 = <0x2>; + xlnx,synch-pipedelay-3 = <0x2>; + xlnx,tavdv-ps-mem-0 = <0x1adb0>; + xlnx,tavdv-ps-mem-1 = <0x3a98>; + xlnx,tavdv-ps-mem-2 = <0x3a98>; + xlnx,tavdv-ps-mem-3 = <0x3a98>; + xlnx,tcedv-ps-mem-0 = <0x1adb0>; + xlnx,tcedv-ps-mem-1 = <0x3a98>; + xlnx,tcedv-ps-mem-2 = <0x3a98>; + xlnx,tcedv-ps-mem-3 = <0x3a98>; + xlnx,thzce-ps-mem-0 = <0x88b8>; + xlnx,thzce-ps-mem-1 = <0x1b58>; + xlnx,thzce-ps-mem-2 = <0x1b58>; + xlnx,thzce-ps-mem-3 = <0x1b58>; + xlnx,thzoe-ps-mem-0 = <0x1b58>; + xlnx,thzoe-ps-mem-1 = <0x1b58>; + xlnx,thzoe-ps-mem-2 = <0x1b58>; + xlnx,thzoe-ps-mem-3 = <0x1b58>; + xlnx,tlzwe-ps-mem-0 = <0x88b8>; + xlnx,tlzwe-ps-mem-1 = <0x0>; + xlnx,tlzwe-ps-mem-2 = <0x0>; + xlnx,tlzwe-ps-mem-3 = <0x0>; + xlnx,twc-ps-mem-0 = <0x2af8>; + xlnx,twc-ps-mem-1 = <0x3a98>; + xlnx,twc-ps-mem-2 = <0x3a98>; + xlnx,twc-ps-mem-3 = <0x3a98>; + xlnx,twp-ps-mem-0 = <0x11170>; + xlnx,twp-ps-mem-1 = <0x2ee0>; + xlnx,twp-ps-mem-2 = <0x2ee0>; + xlnx,twp-ps-mem-3 = <0x2ee0>; + xlnx,xcl0-linesize = <0x4>; + xlnx,xcl0-writexfer = <0x1>; + xlnx,xcl1-linesize = <0x4>; + xlnx,xcl1-writexfer = <0x1>; + xlnx,xcl2-linesize = <0x4>; + xlnx,xcl2-writexfer = <0x1>; + xlnx,xcl3-linesize = <0x4>; + xlnx,xcl3-writexfer = <0x1>; + } ; + Hard_Ethernet_MAC: xps-ll-temac@81c00000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,compound"; + ranges ; + ethernet@81c00000 { + compatible = "xlnx,xps-ll-temac-1.01.b", "xlnx,xps-ll-temac-1.00.a"; + device_type = "network"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 5 2 >; + llink-connected = <&PIM3>; + local-mac-address = [ 00 0a 35 00 00 00 ]; + reg = < 0x81c00000 0x40 >; + xlnx,bus2core-clk-ratio = <0x1>; + xlnx,phy-type = <0x1>; + xlnx,phyaddr = <0x1>; + xlnx,rxcsum = <0x0>; + xlnx,rxfifo = <0x1000>; + xlnx,temac-type = <0x0>; + xlnx,txcsum = <0x0>; + xlnx,txfifo = <0x1000>; + } ; + } ; + IIC_EEPROM: i2c@81600000 { + compatible = "xlnx,xps-iic-2.00.a"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 6 2 >; + reg = < 0x81600000 0x10000 >; + xlnx,clk-freq = <0x7735940>; + xlnx,family = "virtex5"; + xlnx,gpo-width = <0x1>; + xlnx,iic-freq = <0x186a0>; + xlnx,scl-inertial-delay = <0x0>; + xlnx,sda-inertial-delay = <0x0>; + xlnx,ten-bit-adr = <0x0>; + } ; + LEDs_8Bit: gpio@81400000 { + compatible = "xlnx,xps-gpio-1.00.a"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 7 2 >; + reg = < 0x81400000 0x10000 >; + xlnx,all-inputs = <0x0>; + xlnx,all-inputs-2 = <0x0>; + xlnx,dout-default = <0x0>; + xlnx,dout-default-2 = <0x0>; + xlnx,family = "virtex5"; + xlnx,gpio-width = <0x8>; + xlnx,interrupt-present = <0x1>; + xlnx,is-bidir = <0x1>; + xlnx,is-bidir-2 = <0x1>; + xlnx,is-dual = <0x0>; + xlnx,tri-default = <0xffffffff>; + xlnx,tri-default-2 = <0xffffffff>; + #gpio-cells = <2>; + gpio-controller; + } ; + + gpio-leds { + compatible = "gpio-leds"; + + heartbeat { + label = "Heartbeat"; + gpios = <&LEDs_8Bit 4 1>; + linux,default-trigger = "heartbeat"; + }; + + yellow { + label = "Yellow"; + gpios = <&LEDs_8Bit 5 1>; + }; + + red { + label = "Red"; + gpios = <&LEDs_8Bit 6 1>; + }; + + green { + label = "Green"; + gpios = <&LEDs_8Bit 7 1>; + }; + } ; + RS232_Uart_1: serial@84000000 { + clock-frequency = <125000000>; + compatible = "xlnx,xps-uartlite-1.00.a"; + current-speed = <115200>; + device_type = "serial"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 8 0 >; + port-number = <0>; + reg = < 0x84000000 0x10000 >; + xlnx,baudrate = <0x1c200>; + xlnx,data-bits = <0x8>; + xlnx,family = "virtex5"; + xlnx,odd-parity = <0x0>; + xlnx,use-parity = <0x0>; + } ; + SysACE_CompactFlash: sysace@83600000 { + compatible = "xlnx,xps-sysace-1.00.a"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 4 2 >; + reg = < 0x83600000 0x10000 >; + xlnx,family = "virtex5"; + xlnx,mem-width = <0x10>; + } ; + debug_module: debug@84400000 { + compatible = "xlnx,mdm-1.00.d"; + reg = < 0x84400000 0x10000 >; + xlnx,family = "virtex5"; + xlnx,interconnect = <0x1>; + xlnx,jtag-chain = <0x2>; + xlnx,mb-dbg-ports = <0x1>; + xlnx,uart-width = <0x8>; + xlnx,use-uart = <0x1>; + xlnx,write-fsl-ports = <0x0>; + } ; + mpmc@90000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,mpmc-4.02.a"; + ranges ; + PIM3: sdma@84600180 { + compatible = "xlnx,ll-dma-1.00.a"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 2 2 1 2 >; + reg = < 0x84600180 0x80 >; + } ; + } ; + xps_intc_0: interrupt-controller@81800000 { + #interrupt-cells = <0x2>; + compatible = "xlnx,xps-intc-1.00.a"; + interrupt-controller ; + reg = < 0x81800000 0x10000 >; + xlnx,kind-of-intr = <0x100>; + xlnx,num-intr-inputs = <0x9>; + } ; + xps_timer_1: timer@83c00000 { + compatible = "xlnx,xps-timer-1.00.a"; + interrupt-parent = <&xps_intc_0>; + interrupts = < 3 2 >; + reg = < 0x83c00000 0x10000 >; + xlnx,count-width = <0x20>; + xlnx,family = "virtex5"; + xlnx,gen0-assert = <0x1>; + xlnx,gen1-assert = <0x1>; + xlnx,one-timer-only = <0x0>; + xlnx,trig0-assert = <0x1>; + xlnx,trig1-assert = <0x1>; + } ; + } ; +} ; diff --git a/drivers/Kconfig b/drivers/Kconfig index 3bb154d8..67f5c27f 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -126,4 +126,6 @@ source "drivers/hwspinlock/Kconfig" source "drivers/clocksource/Kconfig" +source "drivers/pwm/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 09f3232b..c3217634 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -6,6 +6,7 @@ # obj-y += gpio/ +obj-y += pwm/ obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_PARISC) += parisc/ obj-$(CONFIG_RAPIDIO) += rapidio/ diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index e0b25de1..8624d851 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -292,4 +292,24 @@ config CRYPTO_DEV_S5P Select this to offload Samsung S5PV210 or S5PC110 from AES algorithms execution. +config FH_AES + tristate "FH AES support" + select CRYPTO_BLKCIPHER + select CRYPTO_AES + select CRYPTO_DES +# select CRYPTO_AUTHENC +# select CRYPTO_ALGAPI + select CRYPTO_CBC + select CRYPTO_ECB + select CRYPTO_SEQIV + + help + To compile this driver as a module, choose M here: the module will + be called fh_aes. + + +config FH_AES_SELF_TEST + bool "fh aes self test" + depends on FH_AES + endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 53ea5015..46f30b50 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -13,3 +13,6 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o + +obj-$(CONFIG_FH_AES) += fh_aes.o +obj-$(CONFIG_FH_AES_SELF_TEST) += fh_aes_test.o diff --git a/drivers/crypto/fh_aes.c b/drivers/crypto/fh_aes.c new file mode 100644 index 00000000..bf9dbc2f --- /dev/null +++ b/drivers/crypto/fh_aes.c @@ -0,0 +1,1548 @@ +/***************************************************************************** + * Include Section + * add all #include here + *****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fh_aes.h" + +/***************************************************************************** + * Define section + * add all #define here + *****************************************************************************/ + +#define CRYPTO_QUEUE_LEN (1) +#define CRYPTION_POS (0) +#define METHOD_POS (1) +#define EMODE_POS (4) + +#define aes_readl(aes, name) \ + __raw_readl(&(((struct fh_aes_reg *)aes->regs)->name)) + +#define aes_writel(aes, name, val) \ + __raw_writel((val), &(((struct fh_aes_reg *)aes->regs)->name)) + +#define aes_readw(aes, name) \ + __raw_readw(&(((struct fh_aes_reg *)aes->regs)->name)) + +#define aes_writew(aes, name, val) \ + __raw_writew((val), &(((struct fh_aes_reg *)aes->regs)->name)) + +#define aes_readb(aes, name) \ + __raw_readb(&(((struct fh_aes_reg *)aes->regs)->name)) + +#define aes_writeb(aes, name, val) \ + __raw_writeb((val), &(((struct fh_aes_reg *)aes->regs)->name)) + + +#ifdef CONFIG_FH_EFUSE +#define FH_AESV2 +#else +#undef FH_AESV2 +#endif + +#define FH_AES_ALLIGN_SIZE 64 +#define FH_AES_MALLOC_SIZE 4096 +#define FH_AES_CTL_MAX_PROCESS_SIZE (FH_AES_MALLOC_SIZE - 1) + +#ifdef FH_AESV2 +#include <../drivers/misc/fh_efuse.h> +extern struct wrap_efuse_obj s_efuse_obj; +#endif +/**************************************************************************** + * ADT section + * add definition of user defined Data Type that only be used in this file here + ***************************************************************************/ + +enum { + ENCRYPT = 0 << CRYPTION_POS, + DECRYPT = 1 << CRYPTION_POS, +}; + +enum { + ECB_MODE = 0 << EMODE_POS, + CBC_MODE = 1 << EMODE_POS, + CTR_MODE = 2 << EMODE_POS, + CFB_MODE = 4 << EMODE_POS, + OFB_MODE = 5 << EMODE_POS, +}; + +enum { + DES_METHOD = 0 << METHOD_POS, + TRIPLE_DES_METHOD = 1 << METHOD_POS, + AES_128_METHOD = 4 << METHOD_POS, + AES_192_METHOD = 5 << METHOD_POS, + AES_256_METHOD = 6 << METHOD_POS, +}; + +/***************************************************************************** + + * static fun; + *****************************************************************************/ + +static int fh_aes_handle_req(struct fh_aes_dev *dev, + struct ablkcipher_request *req); +/*aes*/ +static int fh_aes_crypt(struct ablkcipher_request *req, unsigned long mode); +static int fh_aes_ecb_encrypt(struct ablkcipher_request *req); +static int fh_aes_ecb_decrypt(struct ablkcipher_request *req); +static int fh_aes_cbc_encrypt(struct ablkcipher_request *req); +static int fh_aes_cbc_decrypt(struct ablkcipher_request *req); +static int fh_aes_ctr_encrypt(struct ablkcipher_request *req); +static int fh_aes_ctr_decrypt(struct ablkcipher_request *req); +static int fh_aes_ofb_encrypt(struct ablkcipher_request *req); +static int fh_aes_ofb_decrypt(struct ablkcipher_request *req); +static int fh_aes_cfb_encrypt(struct ablkcipher_request *req); +static int fh_aes_cfb_decrypt(struct ablkcipher_request *req); + +/*des*/ +static int fh_des_ecb_encrypt(struct ablkcipher_request *req); +static int fh_des_ecb_decrypt(struct ablkcipher_request *req); +static int fh_des_cbc_encrypt(struct ablkcipher_request *req); +static int fh_des_cbc_decrypt(struct ablkcipher_request *req); +static int fh_des_ofb_encrypt(struct ablkcipher_request *req); +static int fh_des_ofb_decrypt(struct ablkcipher_request *req); +static int fh_des_cfb_encrypt(struct ablkcipher_request *req); +static int fh_des_cfb_decrypt(struct ablkcipher_request *req); + +/*tri des*/ +static int fh_des_tri_ecb_encrypt(struct ablkcipher_request *req); +static int fh_des_tri_ecb_decrypt(struct ablkcipher_request *req); +static int fh_des_tri_cbc_encrypt(struct ablkcipher_request *req); +static int fh_des_tri_cbc_decrypt(struct ablkcipher_request *req); +static int fh_des_tri_ofb_encrypt(struct ablkcipher_request *req); +static int fh_des_tri_ofb_decrypt(struct ablkcipher_request *req); +static int fh_des_tri_cfb_encrypt(struct ablkcipher_request *req); +static int fh_des_tri_cfb_decrypt(struct ablkcipher_request *req); +static int fh_aes_setkey(struct crypto_ablkcipher *cipher, const uint8_t *key, + unsigned int keylen); +static int fh_aes_cra_init(struct crypto_tfm *tfm); +static void fh_aes_tx(struct fh_aes_dev *dev); +static void fh_aes_rx(struct fh_aes_dev *dev); +static irqreturn_t fh_aes_interrupt(int irq, void *dev_id); +static void aes_biglittle_swap(u8 *buf); +static int fh_set_indata(struct fh_aes_dev *dev, struct scatterlist *sg); +static int fh_set_outdata(struct fh_aes_dev *dev, struct scatterlist *sg); +static void fh_set_aes_key_reg(struct fh_aes_dev *dev, uint8_t *key, + uint8_t *iv, unsigned int keylen); +static void fh_set_dma_indata(struct fh_aes_dev *dev, + struct scatterlist *sg); +static void fh_set_dma_outdata(struct fh_aes_dev *dev, + struct scatterlist *sg); +static void fh_unset_indata(struct fh_aes_dev *dev); +static void fh_unset_outdata(struct fh_aes_dev *dev); +static void fh_aes_complete(struct fh_aes_dev *dev, int err); +static void fh_aes_crypt_start(struct fh_aes_dev *dev, unsigned long mode); +static void fh_aes_tasklet_cb(unsigned long data); + +#define fh_des_setkey fh_aes_setkey +/***************************************************************************** + * Global variables section - Local + * define global variables(will be refered only in this file) here, + * static keyword should be used to limit scope of local variable to this file + * e.g. + * static uint8_t ufoo; + *****************************************************************************/ +struct fh_aes_dev *pobj_aes_dev = NULL; +static struct crypto_alg algs[] = { + { + .cra_name = "ecb(aes)", + .cra_driver_name = "ecb-aes-fh", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct fh_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = fh_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = fh_aes_setkey, + .encrypt = fh_aes_ecb_encrypt, + .decrypt = fh_aes_ecb_decrypt, + } + }, + { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-aes-fh", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct fh_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = fh_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = fh_aes_setkey, + .encrypt = fh_aes_cbc_encrypt, + .decrypt = fh_aes_cbc_decrypt, + } + }, + { + .cra_name = "ctr(aes)", + .cra_driver_name = "ctr-aes-fh", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct fh_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = fh_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = fh_aes_setkey, + .encrypt = fh_aes_ctr_encrypt, + .decrypt = fh_aes_ctr_decrypt, + } + }, + { + .cra_name = "ofb(aes)", + .cra_driver_name = "ofb-aes-fh", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct fh_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = fh_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = fh_aes_setkey, + .encrypt = fh_aes_ofb_encrypt, + .decrypt = fh_aes_ofb_decrypt, + } + }, + { + .cra_name = "cfb(aes)", + .cra_driver_name = "cfb-aes-fh", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct fh_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = fh_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = fh_aes_setkey, + .encrypt = fh_aes_cfb_encrypt, + .decrypt = fh_aes_cfb_decrypt, + } + }, + { + .cra_name = "ecb(des)", + .cra_driver_name = "ecb-des-fh", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct fh_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = fh_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .setkey = fh_des_setkey, + .encrypt = fh_des_ecb_encrypt, + .decrypt = fh_des_ecb_decrypt, + } + }, + { + .cra_name = "cbc(des)", + .cra_driver_name = "cbc-des-fh", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct fh_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = fh_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, + .setkey = fh_des_setkey, + .encrypt = fh_des_cbc_encrypt, + .decrypt = fh_des_cbc_decrypt, + } + }, + { + .cra_name = "ofb(des)", + .cra_driver_name = "ofb-des-fh", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct fh_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = fh_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, + .setkey = fh_des_setkey, + .encrypt = fh_des_ofb_encrypt, + .decrypt = fh_des_ofb_decrypt, + } + }, + { + .cra_name = "cfb(des)", + .cra_driver_name = "cfb-des-fh", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct fh_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = fh_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, + .setkey = fh_des_setkey, + .encrypt = fh_des_cfb_encrypt, + .decrypt = fh_des_cfb_decrypt, + } + }, + { + .cra_name = "ecb(des3)", + .cra_driver_name = "ecb-des3-fh", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct fh_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = fh_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = DES3_EDE_KEY_SIZE, + .max_keysize = DES3_EDE_KEY_SIZE, + .setkey = fh_des_setkey, + .encrypt = fh_des_tri_ecb_encrypt, + .decrypt = fh_des_tri_ecb_decrypt, + } + }, + { + .cra_name = "cbc(des3)", + .cra_driver_name = "cbc-des3-fh", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct fh_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = fh_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = DES3_EDE_KEY_SIZE, + .max_keysize = DES3_EDE_KEY_SIZE, + .ivsize = DES3_EDE_BLOCK_SIZE, + .setkey = fh_des_setkey, + .encrypt = fh_des_tri_cbc_encrypt, + .decrypt = fh_des_tri_cbc_decrypt, + } + }, + { + .cra_name = "ofb(des3)", + .cra_driver_name = "ofb-des3-fh", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct fh_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = fh_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = DES3_EDE_KEY_SIZE, + .max_keysize = DES3_EDE_KEY_SIZE, + .ivsize = DES3_EDE_BLOCK_SIZE, + .setkey = fh_des_setkey, + .encrypt = fh_des_tri_ofb_encrypt, + .decrypt = fh_des_tri_ofb_decrypt, + } + }, + { + .cra_name = "cfb(des3)", + .cra_driver_name = "cfb-des3-fh", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct fh_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = fh_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = DES3_EDE_KEY_SIZE, + .max_keysize = DES3_EDE_KEY_SIZE, + .ivsize = DES3_EDE_BLOCK_SIZE, + .setkey = fh_des_setkey, + .encrypt = fh_des_tri_cfb_encrypt, + .decrypt = fh_des_tri_cfb_decrypt, + } + }, +}; + +#ifdef CONFIG_FH_AES_SELF_TEST +extern void fh_aes_self_test_all(void); +#endif + +/* function body */ +static int fh_aes_handle_req(struct fh_aes_dev *dev, + struct ablkcipher_request *req) +{ + unsigned long flags; + int err; + spin_lock_irqsave(&dev->lock, flags); + if (dev->busy) { + err = -EAGAIN; + spin_unlock_irqrestore(&dev->lock, flags); + goto exit; + } + dev->busy = true; /*true :1 ;false :0.*/ + err = ablkcipher_enqueue_request(&dev->queue, req); + spin_unlock_irqrestore(&dev->lock, flags); + tasklet_schedule(&dev->tasklet); +exit: + return err; +} + +static int fh_aes_crypt(struct ablkcipher_request *req, unsigned long mode) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); + struct fh_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); + struct fh_aes_reqctx *reqctx = ablkcipher_request_ctx(req); + struct fh_aes_dev *dev = ctx->dev; + AES_DBG("%s\n", __func__); + dev->reqctx = reqctx; + /*if (!(mode & CFB_MODE)) {*/ + if ((!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) + && (!IS_ALIGNED(req->nbytes, DES_BLOCK_SIZE))) { + pr_err("request size is not exact amount of AES blocks\n"); + return -EINVAL; + } + /*}*/ + AES_DBG("reqctx->mode value: %x\n", (unsigned int_t)mode); + reqctx->mode = mode; + return fh_aes_handle_req(dev, req); +} + +static int fh_aes_ecb_encrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); + struct fh_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); + u32 method = 0; + switch (ctx->keylen) { + case AES_KEYSIZE_128: + method = AES_128_METHOD; + break; + case AES_KEYSIZE_192: + method = AES_192_METHOD; + break; + case AES_KEYSIZE_256: + method = AES_256_METHOD; + break; + default: + break; + } + return fh_aes_crypt(req, method | ECB_MODE | ENCRYPT); +} + + +static int fh_aes_ecb_decrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); + struct fh_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); + u32 method = 0; + + switch (ctx->keylen) { + case AES_KEYSIZE_128: + method = AES_128_METHOD; + break; + case AES_KEYSIZE_192: + method = AES_192_METHOD; + break; + case AES_KEYSIZE_256: + method = AES_256_METHOD; + break; + default: + break; + } + return fh_aes_crypt(req, method | ECB_MODE | DECRYPT); +} + +static int fh_aes_cbc_encrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); + struct fh_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); + u32 method = 0; + + switch (ctx->keylen) { + case AES_KEYSIZE_128: + method = AES_128_METHOD; + break; + case AES_KEYSIZE_192: + method = AES_192_METHOD; + break; + case AES_KEYSIZE_256: + method = AES_256_METHOD; + break; + default: + break; + } + return fh_aes_crypt(req, method | CBC_MODE | ENCRYPT); +} + +static int fh_aes_cbc_decrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *tfm; + struct fh_aes_ctx *ctx; + u32 method; + + tfm = crypto_ablkcipher_reqtfm(req); + ctx = crypto_ablkcipher_ctx(tfm); + method = 0; + AES_DBG("%s\n", __func__); + switch (ctx->keylen) { + case AES_KEYSIZE_128: + method = AES_128_METHOD; + break; + case AES_KEYSIZE_192: + method = AES_192_METHOD; + break; + case AES_KEYSIZE_256: + method = AES_256_METHOD; + break; + default: + break; + } + + return fh_aes_crypt(req, method | CBC_MODE | DECRYPT); +} + +static int fh_aes_ctr_encrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *tfm; + struct fh_aes_ctx *ctx; + u32 method; + tfm = crypto_ablkcipher_reqtfm(req); + ctx = crypto_ablkcipher_ctx(tfm); + method = 0; + + switch (ctx->keylen) { + case AES_KEYSIZE_128: + method = AES_128_METHOD; + break; + case AES_KEYSIZE_192: + method = AES_192_METHOD; + break; + case AES_KEYSIZE_256: + method = AES_256_METHOD; + break; + default: + break; + } + + return fh_aes_crypt(req, method | CTR_MODE | ENCRYPT); +} + +static int fh_aes_ctr_decrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *tfm; + struct fh_aes_ctx *ctx; + u32 method; + + tfm = crypto_ablkcipher_reqtfm(req); + ctx = crypto_ablkcipher_ctx(tfm); + method = 0; + AES_DBG("%s\n", __func__); + switch (ctx->keylen) { + case AES_KEYSIZE_128: + method = AES_128_METHOD; + break; + case AES_KEYSIZE_192: + method = AES_192_METHOD; + break; + case AES_KEYSIZE_256: + method = AES_256_METHOD; + break; + default: + break; + } + return fh_aes_crypt(req, method | CTR_MODE | DECRYPT); +} + +static int fh_aes_ofb_encrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *tfm; + struct fh_aes_ctx *ctx; + u32 method; + + tfm = crypto_ablkcipher_reqtfm(req); + ctx = crypto_ablkcipher_ctx(tfm); + method = 0; + + switch (ctx->keylen) { + case AES_KEYSIZE_128: + method = AES_128_METHOD; + break; + case AES_KEYSIZE_192: + method = AES_192_METHOD; + break; + case AES_KEYSIZE_256: + method = AES_256_METHOD; + break; + default: + break; + } + return fh_aes_crypt(req, method | OFB_MODE | ENCRYPT); +} + +static int fh_aes_ofb_decrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *tfm; + struct fh_aes_ctx *ctx; + u32 method; + + tfm = crypto_ablkcipher_reqtfm(req); + ctx = crypto_ablkcipher_ctx(tfm); + method = 0; + + AES_DBG("%s\n", __func__); + switch (ctx->keylen) { + case AES_KEYSIZE_128: + method = AES_128_METHOD; + break; + case AES_KEYSIZE_192: + method = AES_192_METHOD; + break; + case AES_KEYSIZE_256: + method = AES_256_METHOD; + break; + default: + break; + } + + return fh_aes_crypt(req, method | OFB_MODE | DECRYPT); +} + +static int fh_aes_cfb_encrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *tfm; + struct fh_aes_ctx *ctx; + u32 method; + + tfm = crypto_ablkcipher_reqtfm(req); + ctx = crypto_ablkcipher_ctx(tfm); + method = 0; + + switch (ctx->keylen) { + case AES_KEYSIZE_128: + method = AES_128_METHOD; + break; + case AES_KEYSIZE_192: + method = AES_192_METHOD; + break; + case AES_KEYSIZE_256: + method = AES_256_METHOD; + break; + default: + break; + } + return fh_aes_crypt(req, method | CFB_MODE | ENCRYPT); +} + +static int fh_aes_cfb_decrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *tfm; + struct fh_aes_ctx *ctx; + u32 method; + + tfm = crypto_ablkcipher_reqtfm(req); + ctx = crypto_ablkcipher_ctx(tfm); + method = 0; + + AES_DBG("%s\n", __func__); + switch (ctx->keylen) { + case AES_KEYSIZE_128: + method = AES_128_METHOD; + break; + case AES_KEYSIZE_192: + method = AES_192_METHOD; + break; + case AES_KEYSIZE_256: + method = AES_256_METHOD; + break; + default: + break; + } + + return fh_aes_crypt(req, method | CFB_MODE | DECRYPT); +} +static int fh_des_ecb_encrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = DES_METHOD; + + return fh_aes_crypt(req, method | ECB_MODE | ENCRYPT); +} + +static int fh_des_ecb_decrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = DES_METHOD; + + return fh_aes_crypt(req, method | ECB_MODE | DECRYPT); +} + +static int fh_des_cbc_encrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = DES_METHOD; + + return fh_aes_crypt(req, method | CBC_MODE | ENCRYPT); +} + +static int fh_des_cbc_decrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = DES_METHOD; + + return fh_aes_crypt(req, method | CBC_MODE | DECRYPT); +} + +static int fh_des_ofb_encrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = DES_METHOD; + + return fh_aes_crypt(req, method | OFB_MODE | ENCRYPT); +} + +static int fh_des_ofb_decrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = DES_METHOD; + + return fh_aes_crypt(req, method | OFB_MODE | DECRYPT); +} + +static int fh_des_cfb_encrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = DES_METHOD; + + return fh_aes_crypt(req, method | CFB_MODE | ENCRYPT); +} + +static int fh_des_cfb_decrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = DES_METHOD; + + return fh_aes_crypt(req, method | CFB_MODE | DECRYPT); +} +static int fh_des_tri_ecb_encrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = TRIPLE_DES_METHOD; + return fh_aes_crypt(req, method | ECB_MODE | ENCRYPT); +} + +static int fh_des_tri_ecb_decrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = TRIPLE_DES_METHOD; + return fh_aes_crypt(req, method | ECB_MODE | DECRYPT); +} + +static int fh_des_tri_cbc_encrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = TRIPLE_DES_METHOD; + return fh_aes_crypt(req, method | CBC_MODE | ENCRYPT); +} + +static int fh_des_tri_cbc_decrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = TRIPLE_DES_METHOD; + return fh_aes_crypt(req, method | CBC_MODE | DECRYPT); +} + +static int fh_des_tri_ofb_encrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = TRIPLE_DES_METHOD; + return fh_aes_crypt(req, method | OFB_MODE | ENCRYPT); +} + +static int fh_des_tri_ofb_decrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = TRIPLE_DES_METHOD; + return fh_aes_crypt(req, method | OFB_MODE | DECRYPT); +} + +static int fh_des_tri_cfb_encrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = TRIPLE_DES_METHOD; + return fh_aes_crypt(req, method | CFB_MODE | ENCRYPT); +} + +static int fh_des_tri_cfb_decrypt(struct ablkcipher_request *req) +{ + u32 method; + method = 0; + method = TRIPLE_DES_METHOD; + return fh_aes_crypt(req, method | CFB_MODE | DECRYPT); +} +static int fh_aes_setkey(struct crypto_ablkcipher *cipher, const uint8_t *key, + unsigned int keylen) +{ + struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); + struct fh_aes_ctx *ctx = crypto_tfm_ctx(tfm); + int i = 0; + AES_DBG("%s\n", __func__); + if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 + && keylen != AES_KEYSIZE_256 && keylen != DES_KEY_SIZE + && keylen != DES3_EDE_KEY_SIZE) + return -EINVAL; + + for (; i < keylen; i++) + AES_DBG("%x", key[i]); + AES_DBG("\n"); + + memcpy(ctx->aes_key, key, keylen); + ctx->keylen = keylen; + + return 0; +} + +static int fh_aes_cra_init(struct crypto_tfm *tfm) +{ + struct fh_aes_ctx *ctx = crypto_tfm_ctx(tfm); + ctx->dev = pobj_aes_dev; + tfm->crt_ablkcipher.reqsize = sizeof(struct fh_aes_reqctx); + AES_DBG("%s\n", __func__); + + return 0; +} + +static void fh_aes_tx(struct fh_aes_dev *dev) +{ + int err = 0; + unsigned int i = 0; + struct ablkcipher_request *req = dev->req; + struct scatterlist *temp_sg = req->dst; + fh_unset_outdata(dev); + do { + sg_copy_from_buffer(temp_sg, 1, &dev->ctl_dst_xbuf[i], + sg_dma_len(temp_sg)); + i += sg_dma_len(temp_sg); + temp_sg = sg_next(temp_sg); + } while (temp_sg != NULL); + + fh_aes_complete(dev, err); +} + +static void fh_aes_rx(struct fh_aes_dev *dev) +{ + fh_unset_indata(dev); +} + +static irqreturn_t fh_aes_interrupt(int irq, void *dev_id) +{ + + u32 isr_status; + unsigned long flags; + struct platform_device *pdev = (struct platform_device *) dev_id; + struct fh_aes_dev *dev = platform_get_drvdata(pdev); + + u32 isr = dev->en_isr; + AES_DBG("%s\n", __func__); + spin_lock_irqsave(&dev->lock, flags); + aes_writel(dev, dma_control, 0); + isr_status = aes_readl(dev, intr_src); + aes_writel(dev, intr_clear_status, 0x07); + aes_writel(dev, intr_enable, 0); + if (isr_status & 0x02) + AES_DBG("dma rev hreap error...\n"); + if (isr_status & 0x04) + AES_DBG("dma stop src ..\n"); + if (isr_status & 0x01) { + AES_DBG("dma done..\n"); + fh_aes_rx(dev); + fh_aes_tx(dev); + if (dev->busy == true) { + /*begin the next transfer...*/ + aes_writel(dev, intr_enable, isr); + /*enable dma go..*/ + aes_writel(dev, dma_control, 1); + } + + } + spin_unlock_irqrestore(&dev->lock, flags); + return IRQ_HANDLED; +} + +static void aes_biglittle_swap(u8 *buf) +{ + u8 tmp, tmp1; + tmp = buf[0]; + tmp1 = buf[1]; + buf[0] = buf[3]; + buf[1] = buf[2]; + buf[2] = tmp1; + buf[3] = tmp; +} + +static int fh_set_indata(struct fh_aes_dev *dev, struct scatterlist *sg) +{ + int err; + unsigned int i = 0; + unsigned int len = 0; + struct scatterlist *temp_sg = sg; + unsigned char *src_xbuf; + src_xbuf = &dev->ctl_src_xbuf[0]; + do { + if (len + sg_dma_len(temp_sg) > FH_AES_CTL_MAX_PROCESS_SIZE) { + printk("%s: total size > driver size 0x%x\n", __func__, FH_AES_CTL_MAX_PROCESS_SIZE); + err = -ENOMEM; + goto exit; + } + sg_copy_to_buffer(temp_sg, 1, &src_xbuf[i], sg_dma_len(temp_sg)); + len += sg_dma_len(temp_sg); + i += sg_dma_len(temp_sg); + temp_sg = sg_next(temp_sg); + } while (temp_sg != NULL); + + sg_init_one(&dev->src_sg[0], &src_xbuf[0], len); + err = dma_map_sg(dev->dev, &dev->src_sg[0], 1, DMA_TO_DEVICE); + if (!err) { + err = -ENOMEM; + goto exit; + } + dev->sg_src = &dev->src_sg[0]; + err = 0; +exit: + return err; +} + +static int fh_set_outdata(struct fh_aes_dev *dev, struct scatterlist *sg) +{ + int err; + sg_init_one(&dev->dst_sg[0], &dev->ctl_dst_xbuf[0], FH_AES_CTL_MAX_PROCESS_SIZE); + err = dma_map_sg(dev->dev, &dev->dst_sg[0], 1, DMA_FROM_DEVICE); + if (!err) { + err = -ENOMEM; + goto exit; + } + dev->sg_dst = &dev->dst_sg[0]; + err = 0; +exit: + return err; +} + +static void fh_set_aes_key_reg(struct fh_aes_dev *dev, uint8_t *key, + uint8_t *iv, unsigned int keylen) +{ + + int i; + u32 method; + u32 temp_key_buf[32]; + u32 temp_iv_buf[32]; + u32 *p_dst = NULL; + u32 key_size = 0; + if (dev->iv_flag == true) { + /*set iv*/ + /*if aes mode ....set 128 bit iv, des set 64bit iv..*/ + AES_DBG("set iv reg\n"); + if ((dev->control_reg & AES_128_METHOD) + || ((dev->control_reg & AES_192_METHOD)) + || (dev->control_reg & AES_256_METHOD)) { + AES_DBG("aes iv mode...\n"); + + memcpy((u8 *)&temp_iv_buf[0], iv, 16); + p_dst = &temp_iv_buf[0]; + for (i = 0; i < 16 / sizeof(u32); i++) + aes_biglittle_swap((u8 *)(p_dst + i)); + memcpy((u8 *)&((struct fh_aes_reg *) dev->regs)->initial_vector0, + temp_iv_buf, 16); + } else { + AES_DBG("des iv mode...\n"); + + memcpy((u8 *)&temp_iv_buf[0], iv, 8); + p_dst = &temp_iv_buf[0]; + for (i = 0; i < 8 / sizeof(u32); i++) + aes_biglittle_swap((u8 *)(p_dst + i)); + + memcpy((u8 *)&((struct fh_aes_reg *) dev->regs)->initial_vector0, + temp_iv_buf, 8); + + } + } + /*set key...*/ + method = dev->control_reg & 0x0e; + AES_DBG("set key reg\n"); + + switch (method) { + case AES_128_METHOD: + AES_DBG("set key aes 128 mode..\n"); + key_size = 16; + + break; + case AES_192_METHOD: + AES_DBG("set key aes 192 mode..\n"); + key_size = 24; + break; + + case AES_256_METHOD: + AES_DBG("set key aes 256 mode..\n"); + key_size = 32; + break; + + case DES_METHOD: + AES_DBG("set key des normal mode..\n"); + key_size = 8; + break; + + case TRIPLE_DES_METHOD: + AES_DBG("set key des triple mode..\n"); + key_size = 24; + break; + + default: + AES_DBG("error method!!\n"); + break; + + } +#ifdef FH_AESV2 + + if (s_efuse_obj.open_flag == USE_CPU_SET_KEY) { + memcpy((u8 *)&temp_key_buf[0], key, key_size); + p_dst = &temp_key_buf[0]; + for (i = 0; i < key_size / sizeof(u32); i++) + aes_biglittle_swap((u8 *)(p_dst + i)); + memcpy((u8 *)&((struct fh_aes_reg *) dev->regs)->security_key0, + (u8 *)&temp_key_buf[0], + key_size); + } else { + s_efuse_obj.trans_key_start_no = 0; + s_efuse_obj.trans_key_size = key_size / 4; + efuse_trans_key(&s_efuse_obj, + s_efuse_obj.trans_key_start_no, + s_efuse_obj.trans_key_size); + } + +#else + memcpy((u8 *)&temp_key_buf[0], key, key_size); + p_dst = &temp_key_buf[0]; + for (i = 0; i < key_size / sizeof(u32); i++) + aes_biglittle_swap((u8 *)(p_dst + i)); + + memcpy((u8 *)&((struct fh_aes_reg *) dev->regs)->security_key0, + (u8 *)&temp_key_buf[0], + key_size); + +#endif + + +} + +static void fh_set_dma_indata(struct fh_aes_dev *dev, + struct scatterlist *sg) +{ + aes_writel(dev, dma_src_add, sg_dma_address(sg)); + AES_DBG("%s :dma trans size is :%x\n", __func__, sg_dma_len(sg)); + aes_writel(dev, dma_trans_size, sg_dma_len(sg)); +} + +static void fh_set_dma_outdata(struct fh_aes_dev *dev, + struct scatterlist *sg) +{ + aes_writel(dev, dma_dst_add, sg_dma_address(sg)); +} + +static void fh_unset_indata(struct fh_aes_dev *dev) +{ + dma_unmap_sg(dev->dev, dev->sg_src, 1, DMA_TO_DEVICE); +} + +static void fh_unset_outdata(struct fh_aes_dev *dev) +{ + dma_unmap_sg(dev->dev, dev->sg_dst, 1, DMA_FROM_DEVICE); +} + +static void fh_aes_complete(struct fh_aes_dev *dev, int err) +{ + if (dev->req->base.complete) + dev->req->base.complete(&dev->req->base, err); + dev->busy = false; +} + +static void fh_aes_crypt_start(struct fh_aes_dev *dev, unsigned long mode) +{ + + struct ablkcipher_request *req = dev->req; + u32 control_reg; + u32 outfifo_thold = 0; + u32 infifo_thold = 0; + u32 isr; + int err; + unsigned long flags; + control_reg = 0; + + if ((mode & CBC_MODE) || (mode & CTR_MODE) || (mode & CFB_MODE) + || (mode & OFB_MODE)) { + control_reg |= 1 << 7; + dev->iv_flag = true; + } else + dev->iv_flag = false; + + /*emode & method*/ + control_reg |= (unsigned int) mode; + dev->control_reg = control_reg; + outfifo_thold = 0; + infifo_thold = 8; + isr = dev->en_isr; + spin_lock_irqsave(&dev->lock, flags); + AES_DBG("control_reg:0x%x\n", control_reg); + aes_writel(dev, encrypt_control, control_reg); + /*set key...*/ + fh_set_aes_key_reg(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen); + err = fh_set_indata(dev, req->src); + if (err) + goto indata_error; + + err = fh_set_outdata(dev, req->dst); + if (err) + goto outdata_error; + + fh_set_dma_indata(dev, dev->sg_src); + fh_set_dma_outdata(dev, dev->sg_dst); + + /*set fifo..*/ + AES_DBG("outfifo thold:%x\n", outfifo_thold); + AES_DBG("infifo thold:%x\n", infifo_thold); + aes_writel(dev, fifo_threshold, outfifo_thold << 8 | infifo_thold); + /*set isr..*/ + AES_DBG("intr enable:%x\n", isr); + aes_writel(dev, intr_enable, isr); + /*enable dma go..*/ + aes_writel(dev, dma_control, 1); + spin_unlock_irqrestore(&dev->lock, flags); + + return; + +outdata_error: + AES_DBG("outdata_error ..\n"); + fh_unset_indata(dev); + +indata_error: + AES_DBG("indata_error ..\n"); + fh_aes_complete(dev, err); + spin_unlock_irqrestore(&dev->lock, flags); + +} + +static void fh_aes_tasklet_cb(unsigned long data) +{ + + struct fh_aes_dev *dev = (struct fh_aes_dev *) data; + struct crypto_async_request *async_req, *backlog; + struct fh_aes_reqctx *reqctx; + unsigned long flags; + + AES_DBG("%s\n", __func__); + spin_lock_irqsave(&dev->lock, flags); + backlog = crypto_get_backlog(&dev->queue); + AES_DBG("backlog add is :%x\n", (u32)backlog); + /*get the req need to handle*/ + async_req = crypto_dequeue_request(&dev->queue); + spin_unlock_irqrestore(&dev->lock, flags); + if (!async_req) + return; + if (backlog) { + if (backlog->complete) + backlog->complete(backlog, -EINPROGRESS); + } + + dev->req = ablkcipher_request_cast(async_req); + dev->ctx = crypto_tfm_ctx(dev->req->base.tfm); + reqctx = ablkcipher_request_ctx(dev->req); + fh_aes_crypt_start(dev, reqctx->mode); +} + +/*add chenjn dsp use...*/ +typedef struct { + unsigned int base; + void *vbase; + unsigned int size; +} MEM_INFO; +typedef struct { + MEM_INFO mem; + unsigned char *remap_base; /**<已用大小*/ +} RW_MEM_INFO; + +struct tcrypt_result { + struct completion completion; + int err; +}; + +int aes_128_ecb_encrypt(char *key_128, RW_MEM_INFO in, + RW_MEM_INFO out, unsigned int data_len_align16); + + +int fh_aes_ctl_mem_init(struct fh_aes_dev *pdata) +{ + unsigned int t1; + unsigned int t2; + unsigned int t3; + unsigned int t4; + + t1 = (unsigned int)kmalloc(FH_AES_MALLOC_SIZE + FH_AES_ALLIGN_SIZE, GFP_KERNEL); + if (!t1) + goto err1; + + t2 = (unsigned int)kmalloc(FH_AES_MALLOC_SIZE + FH_AES_ALLIGN_SIZE, GFP_KERNEL); + if (!t2) + goto err2; + + + t3 = ((t1 + FH_AES_ALLIGN_SIZE - 1) & (~(FH_AES_ALLIGN_SIZE - 1))); + t4 = ((t2 + FH_AES_ALLIGN_SIZE - 1) & (~(FH_AES_ALLIGN_SIZE - 1))); + + pdata->ctl_raw_src_xbuf = (unsigned char *)t1; + pdata->ctl_raw_dst_xbuf = (unsigned char *)t2; + pdata->ctl_src_xbuf = (unsigned char *)t3; + pdata->ctl_dst_xbuf = (unsigned char *)t4; + return 0; +err2: + kfree((void *)t1); +err1: + return -1; + +} + +static int __devinit fh_aes_probe(struct platform_device *pdev) +{ + + int i, j, err = -ENODEV; + struct fh_aes_dev *pdata; + struct device *dev = &pdev->dev; + struct resource *res; + struct resource *ioarea; + + AES_DBG("aes probe get in..\n"); + if (pobj_aes_dev) { + dev_err(&pdev->dev, "second crypto dev..\n"); + return -EEXIST; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "get platform source error..\n"); + return -ENODEV; + } + + ioarea = request_mem_region(res->start, resource_size(res), pdev->name); + if (!ioarea) { + dev_err(&pdev->dev, "aes region already claimed\n"); + /*BUG_ON(ioarea);*/ + return -EBUSY; + } + + pdata = kzalloc(sizeof(struct fh_aes_dev), GFP_KERNEL); + if (!pdata) { + err = -ENOMEM; + goto err_malloc; + } + + spin_lock_init(&pdata->lock); + pdata->regs = ioremap(res->start, resource_size(res)); + + if (!pdata->regs) { + dev_err(&pdev->dev, "aes region already mapped\n"); + err = -EINVAL; + goto err_iomap; + } + pdata->irq_no = platform_get_irq(pdev, 0); + if (pdata->irq_no < 0) { + err = pdata->irq_no; + dev_warn(dev, "aes interrupt is not available.\n"); + goto err_irq; + } + /*only enable dma done isr..*/ + pdata->en_isr = 1 << 0; + err = request_irq(pdata->irq_no, fh_aes_interrupt, 0, + dev_name(&pdev->dev), pdev); + + if (err) { + dev_dbg(&pdev->dev, "request_irq failed, %d\n", err); + goto err_irq; + } + /*bind to plat dev..*/ + pdata->dev = dev; + /*bing to static para..only one aes controller in fh..*/ + pobj_aes_dev = pdata; + platform_set_drvdata(pdev, pdata); + + tasklet_init(&pdata->tasklet, fh_aes_tasklet_cb, (unsigned long) pdata); + crypto_init_queue(&pdata->queue, CRYPTO_QUEUE_LEN); + for (i = 0; i < ARRAY_SIZE(algs); i++) { + INIT_LIST_HEAD(&algs[i].cra_list); + err = crypto_register_alg(&algs[i]); + + if (err) { + dev_warn(dev, "register alg error...\n"); + goto err_algs; + } + } + + err = fh_aes_ctl_mem_init(pdata); + if (err) { + dev_err(&pdev->dev, "aes malloc mem error..\n"); + goto err_algs; + } + pr_info("aes driver registered\n"); + +#ifdef CONFIG_FH_AES_SELF_TEST + + fh_aes_self_test_all(); +#endif + + return 0; +err_algs: + for (j = 0; j < i; j++) + crypto_unregister_alg(&algs[j]); + tasklet_kill(&pdata->tasklet); + platform_set_drvdata(pdev, NULL); + pobj_aes_dev = NULL; + free_irq(pdata->irq_no, pdata); + +err_irq: + iounmap(pdata->regs); + +err_iomap: + kfree(pdata); + +err_malloc: + release_mem_region(res->start, resource_size(res)); + return err; +} + +static int __devexit fh_aes_remove(struct platform_device *pdev) +{ + + int i; + struct fh_aes_dev *pdata = platform_get_drvdata(pdev); + struct resource *res; + + for (i = 0; i < ARRAY_SIZE(algs); i++) + crypto_unregister_alg(&algs[i]); + + tasklet_kill(&pdata->tasklet); + platform_set_drvdata(pdev, NULL); + pobj_aes_dev = NULL; + free_irq(pdata->irq_no, pdata); + iounmap(pdata->regs); + kfree(pdata->ctl_raw_src_xbuf); + kfree(pdata->ctl_raw_dst_xbuf); + pdata->ctl_raw_src_xbuf = NULL; + pdata->ctl_raw_dst_xbuf = NULL; + pdata->ctl_src_xbuf = NULL; + pdata->ctl_dst_xbuf = NULL; + kfree(pdata); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + return 0; +} + +static struct platform_driver fh_aes_driver = { + .driver = { + .name = "fh_aes", + .owner = THIS_MODULE, + }, + .probe = fh_aes_probe, + .remove = __devexit_p(fh_aes_remove), +}; + +static int __init fh_aes_init(void) +{ + return platform_driver_register(&fh_aes_driver); +} +late_initcall(fh_aes_init); + +static void __exit fh_aes_exit(void) +{ + platform_driver_unregister(&fh_aes_driver); +} +module_exit(fh_aes_exit); + +static void tcrypt_complete(struct crypto_async_request *req, int err) +{ + struct tcrypt_result *res = req->data; + if (err == -EINPROGRESS) + return; + complete(&res->completion); +} + +int aes_128_ecb_encrypt(char *key_128, RW_MEM_INFO in, RW_MEM_INFO out, unsigned int data_len_align16) +{ + static char *xbuf; + static char *dst_xbuf; + static struct crypto_ablkcipher *tfm; + static struct ablkcipher_request *req; + static int malloc_flag; + /*const char *algo = NULL;*/ + struct scatterlist sg[8]; + struct scatterlist dst_sg[8]; + void *data; + void *dst_data; + struct tcrypt_result wait_result; + + /*malloc buf...*/ + if (malloc_flag != 0) + goto work_go; + malloc_flag = 1; + xbuf = (void *)__get_free_page(GFP_KERNEL); + if (!xbuf) { + printk("no pages.\n"); + return -1; + } + + dst_xbuf = (void *)__get_free_page(GFP_KERNEL); + if (!dst_xbuf) { + free_page((unsigned long)xbuf); + printk("no pages.\n"); + return -1; + } + + tfm = crypto_alloc_ablkcipher("ecb-aes-fh", + CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, 0); + if (IS_ERR(tfm)) { + printk("aes_test: failed to alloc cipher!\n"); + free_page((unsigned long)xbuf); + free_page((unsigned long)dst_xbuf); + return -1; + } + req = ablkcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) { + printk(KERN_ERR "alg: skcipher: Failed to allocate request " + "for\n"); + return -1; + } + +work_go: + init_completion(&wait_result.completion); + crypto_ablkcipher_setkey(tfm, (u8 *)key_128, 16); + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + tcrypt_complete, &wait_result); + data = xbuf; + dst_data = dst_xbuf; + /*encrypt*/ + memcpy(data, in.remap_base, data_len_align16); + sg_init_one(&sg[0], data, data_len_align16); + sg_init_one(&dst_sg[0], dst_data, data_len_align16); + ablkcipher_request_set_crypt(req, sg, dst_sg, data_len_align16, NULL); + crypto_ablkcipher_encrypt(req); + wait_for_completion(&wait_result.completion); + memcpy(out.remap_base, dst_data, data_len_align16); + + return 0; + +} +EXPORT_SYMBOL(aes_128_ecb_encrypt); + + +MODULE_AUTHOR("yu.zhang "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Fullhan AES driver support"); diff --git a/drivers/crypto/fh_aes.h b/drivers/crypto/fh_aes.h new file mode 100644 index 00000000..90eaa8a5 --- /dev/null +++ b/drivers/crypto/fh_aes.h @@ -0,0 +1,119 @@ +/* + * fh_aes.h + * + * Created on: 3.12.2015 + * Author: duobao + */ + +#ifndef FH_AES_H_ +#define FH_AES_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct fh_aes_reg { + u32 encrypt_control; /*0*/ + u32 reserved_4_8; /*4*/ + u32 fifo_status; /*8*/ + u32 parity_error; /*c*/ + u32 security_key0; /*10*/ + u32 security_key1; /*14*/ + u32 security_key2; /*18*/ + u32 security_key3; /*1c*/ + u32 security_key4; /*20*/ + u32 security_key5; /*24*/ + u32 security_key6; /*28*/ + u32 security_key7; /*2c*/ + u32 initial_vector0; /*30*/ + u32 initial_vector1; /*34*/ + u32 initial_vector2; /*38*/ + u32 initial_vector3; /*3c*/ + u32 reserved_40_44; /*40*/ + u32 reserved_44_48; /*44*/ + u32 dma_src_add; /*48*/ + u32 dma_dst_add; /*4c*/ + u32 dma_trans_size; /*50*/ + u32 dma_control; /*54*/ + u32 fifo_threshold; /*58*/ + u32 intr_enable; /*5c*/ + u32 intr_src; /*60*/ + u32 mask_intr_status; /*64*/ + u32 intr_clear_status; /*68*/ + u32 reserved_6c_70; /*6c*/ + u32 revision; /*70*/ + u32 feature; /*74*/ + u32 reserved_78_7c; /*78*/ + u32 reserved_7c_80; /*7c*/ + u32 last_initial_vector0; /*80*/ + u32 last_initial_vector1; /*84*/ + u32 last_initial_vector2; /*88*/ + u32 last_initial_vector3; /*8c*/ +}; + +/*requst ctx.....*/ +struct fh_aes_reqctx { + unsigned long mode; +}; +/*aes ctx....*/ +struct fh_aes_ctx { + struct fh_aes_dev *dev; /*bind to aes dev..*/ + uint8_t aes_key[AES_MAX_KEY_SIZE]; /*rec key value..*/ + int keylen; /*rec key len.*/ +}; + +struct fh_aes_dev { + /*common driver paras..*/ + void *regs; + struct device *dev; /*bind to the platform dev...*/ + struct clk *clk; + bool busy; /*software sync the hardware....*/ + spinlock_t lock; /*just lock...*/ + u32 irq_no; /*board info...*/ + u32 en_isr; /*software rec the isr src*/ + bool iv_flag; + u32 control_reg; + /*crypto need below...*/ + struct fh_aes_ctx *ctx; /*bind to the aes ctx...*/ + struct fh_aes_reqctx *reqctx; /*bind to the req ctx..*/ + struct scatterlist *sg_src; /*rec the src data need to be handled*/ + struct scatterlist *sg_dst; /*rec the dst data need to be handled*/ + struct tasklet_struct tasklet; /*async process the crypto*/ + struct ablkcipher_request *req; /*active req...*/ + struct crypto_queue queue; + unsigned char *ctl_src_xbuf; + unsigned char *ctl_dst_xbuf; + unsigned char *ctl_raw_src_xbuf; + unsigned char *ctl_raw_dst_xbuf; + struct scatterlist src_sg[1]; + struct scatterlist dst_sg[1]; +}; + + +/*#define FH_AES_SELF_TEST*/ +/*#define FH_AES_DEBUG*/ +#ifdef FH_AES_DEBUG +#define AES_DBG(fmt, args...) printk(fmt, ## args) +#else +#define AES_DBG(fmt, args...) do { } while (0) +#endif + +#define AES_PRINT_RESULT(fmt, args...) printk(fmt, ## args) + +#endif /* fh_AES_H_ */ + + diff --git a/drivers/crypto/fh_aes_test.c b/drivers/crypto/fh_aes_test.c new file mode 100644 index 00000000..25dca9a6 --- /dev/null +++ b/drivers/crypto/fh_aes_test.c @@ -0,0 +1,1369 @@ +/* + * fh_aes_test.c + * + * Created on: May 7, 2015 + * Author: yu.zhang + */ +#ifdef CONFIG_FH_AES_SELF_TEST +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fh_aes.h" +//cbc aes 128 +#define AES_IV0 0x00010203 +#define AES_IV1 0x04050607 +#define AES_IV2 0x08090a0b +#define AES_IV3 0x0c0d0e0f + +#define AES_KEY0 0x2b7e1516 +#define AES_KEY1 0x28aed2a6 +#define AES_KEY2 0xabf71588 +#define AES_KEY3 0x09cf4f3c + + +static const unsigned char aes_cbc_iv_buf[] = { + 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07, 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f, +}; + +static const unsigned char aes_cbc_key_buf[] = { + 0x2b,0x7e,0x15,0x16, 0x28,0xae,0xd2,0xa6, 0xab,0xf7,0x15,0x88, 0x09,0xcf,0x4f,0x3c, +}; + + +//ecb aes 256 +#define AES_ECB_KEY0 0x603deb10 +#define AES_ECB_KEY1 0x15ca71be +#define AES_ECB_KEY2 0x2b73aef0 +#define AES_ECB_KEY3 0x857d7781 +#define AES_ECB_KEY4 0x1f352c07 +#define AES_ECB_KEY5 0x3b6108d7 +#define AES_ECB_KEY6 0x2d9810a3 +#define AES_ECB_KEY7 0x0914dff4 + + +static const unsigned char aes_ecb_key_buf[] = { + 0x60,0x3d,0xeb,0x10, 0x15,0xca,0x71,0xbe, 0x2b,0x73,0xae,0xf0, 0x85,0x7d,0x77,0x81, + 0x1f,0x35,0x2c,0x07, 0x3b,0x61,0x08,0xd7, 0x2d,0x98,0x10,0xa3, 0x09,0x14,0xdf,0xf4, +}; + +//ctr aes 192 +#define AES_CTR_KEY0 0x8e73b0f7 +#define AES_CTR_KEY1 0xda0e6452 +#define AES_CTR_KEY2 0xc810f32b +#define AES_CTR_KEY3 0x809079e5 +#define AES_CTR_KEY4 0x62f8ead2 +#define AES_CTR_KEY5 0x522c6b7b + +#define AES_CTR_IV0 0xf0f1f2f3 +#define AES_CTR_IV1 0xf4f5f6f7 +#define AES_CTR_IV2 0xf8f9fafb +#define AES_CTR_IV3 0xfcfdfeff + + +static const unsigned char aes_ctr_iv_buf[] = { + 0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff, +}; + +static const unsigned char aes_ctr_key_buf[] = { + 0x8e,0x73,0xb0,0xf7, 0xda,0x0e,0x64,0x52, 0xc8,0x10,0xf3,0x2b, 0x80,0x90,0x79,0xe5, + 0x62,0xf8,0xea,0xd2, 0x52,0x2c,0x6b,0x7b, +}; + + +//cfb aes 192 +//#define AES_CFB_KEY0 0x8e73b0f7 +//#define AES_CFB_KEY1 0xda0e6452 +//#define AES_CFB_KEY2 0xc810f32b +//#define AES_CFB_KEY3 0x809079e5 +//#define AES_CFB_KEY4 0x62f8ead2 +//#define AES_CFB_KEY5 0x522c6b7b +// +//#define AES_CFB_IV0 0x00010203 +//#define AES_CFB_IV1 0x04050607 +//#define AES_CFB_IV2 0x08090a0b +//#define AES_CFB_IV3 0x0c0d0e0f + +//ofb aes 256 +#define AES_OFB_256_KEY0 0x603deb10 +#define AES_OFB_256_KEY1 0x15ca71be +#define AES_OFB_256_KEY2 0x2b73aef0 +#define AES_OFB_256_KEY3 0x857d7781 +#define AES_OFB_256_KEY4 0x1f352c07 +#define AES_OFB_256_KEY5 0x3b6108d7 +#define AES_OFB_256_KEY6 0x2d9810a3 +#define AES_OFB_256_KEY7 0x0914dff4 + +#define AES_OFB_IV0 0x00010203 +#define AES_OFB_IV1 0x04050607 +#define AES_OFB_IV2 0x08090a0b +#define AES_OFB_IV3 0x0c0d0e0f + +static const unsigned char aes_ofb_iv_buf[] = { + 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07, 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f, +}; + +static const unsigned char aes_ofb_key_buf[] = { + 0x60,0x3d,0xeb,0x10, 0x15,0xca,0x71,0xbe, 0x2b,0x73,0xae,0xf0, 0x85,0x7d,0x77,0x81, + 0x1f,0x35,0x2c,0x07, 0x3b,0x61,0x08,0xd7, 0x2d,0x98,0x10,0xa3, 0x09,0x14,0xdf,0xf4, +}; + +//des ecb +#define DES_ECB_KEY0 0x01010101 +#define DES_ECB_KEY1 0x01010101 + +static const unsigned char des_ecb_key_buf[] = { + 0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01, +}; +//des cbc +#define DES_CBC_KEY0 0x01234567 +#define DES_CBC_KEY1 0x89abcdef + +#define DES_CBC_IV0 0x12345678 +#define DES_CBC_IV1 0x90abcdef + + +static const unsigned char des_cbc_key_buf[] = { + 0x01,0x23,0x45,0x67, 0x89,0xab,0xcd,0xef, +}; + +static const unsigned char des_cbc_iv_buf[] = { + 0x12,0x34,0x56,0x78, 0x90,0xab,0xcd,0xef, +}; + + +//ofb cbc +#define DES_OFB_KEY0 0x01234567 +#define DES_OFB_KEY1 0x89abcdef + +#define DES_OFB_IV0 0x12345678 +#define DES_OFB_IV1 0x90abcdef + +static const unsigned char des_ofb_key_buf[] = { + 0x01,0x23,0x45,0x67, 0x89,0xab,0xcd,0xef, +}; + +static const unsigned char des_ofb_iv_buf[] = { + 0x12,0x34,0x56,0x78, 0x90,0xab,0xcd,0xef, +}; + +//ecb tri-des +#define DES_TRI_ECB_KEY0 0x01234567 +#define DES_TRI_ECB_KEY1 0x89abcdef + +#define DES_TRI_ECB_KEY2 0x23456789 +#define DES_TRI_ECB_KEY3 0xabcdef01 + +#define DES_TRI_ECB_KEY4 0x456789ab +#define DES_TRI_ECB_KEY5 0xcdef0123 + +static const unsigned char des3_ecb_key_buf[] = { + 0x01,0x23,0x45,0x67, 0x89,0xab,0xcd,0xef, 0x23,0x45,0x67,0x89, 0xab,0xcd,0xef,0x01, + 0x45,0x67,0x89,0xab, 0xcd,0xef,0x01,0x23, +}; + +//cbc tri-des +#define DES_TRI_CBC_KEY0 0x01234567 +#define DES_TRI_CBC_KEY1 0x89abcdef + +#define DES_TRI_CBC_KEY2 0x23456789 +#define DES_TRI_CBC_KEY3 0xabcdef01 + +#define DES_TRI_CBC_KEY4 0x456789ab +#define DES_TRI_CBC_KEY5 0xcdef0123 + +#define DES_TRI_CBC_IV0 0x12345678 +#define DES_TRI_CBC_IV1 0x90abcdef + +static const unsigned char des3_cbc_key_buf[] = { + 0x01,0x23,0x45,0x67, 0x89,0xab,0xcd,0xef, 0x23,0x45,0x67,0x89, 0xab,0xcd,0xef,0x01, + 0x45,0x67,0x89,0xab, 0xcd,0xef,0x01,0x23, +}; +static const unsigned char des3_cbc_iv_buf[] = { + 0x12,0x34,0x56,0x78, 0x90,0xab,0xcd,0xef, +}; +#define XBUFSIZE 128 + +struct tcrypt_result { + struct completion completion; + int err; +}; + +static inline void hexdump(unsigned char *buf, unsigned int len); +static void tcrypt_complete(struct crypto_async_request *req, int err); +static int testmgr_alloc_buf(char *buf[XBUFSIZE]); +static int fh_aes_cbc128_self_test(void); +static int fh_aes_ecb256_self_test(void); + +static struct tcrypt_result result; +static const unsigned char plain_text[] = { + 0x6b,0xc1,0xbe,0xe2, 0x2e,0x40,0x9f,0x96, 0xe9,0x3d,0x7e,0x11, 0x73,0x93,0x17,0x2a, + 0xae,0x2d,0x8a,0x57, 0x1e,0x03,0xac,0x9c, 0x9e,0xb7,0x6f,0xac, 0x45,0xaf,0x8e,0x51, + 0x30,0xc8,0x1c,0x46, 0xa3,0x5c,0xe4,0x11, 0xe5,0xfb,0xc1,0x19, 0x1a,0x0a,0x52,0xef, + 0xf6,0x9f,0x24,0x45, 0xdf,0x4f,0x9b,0x17, 0xad,0x2b,0x41,0x7b, 0xe6,0x6c,0x37,0x10, +}; + +static const unsigned char cipher_text[] = { + 0x76,0x49,0xab,0xac, 0x81,0x19,0xb2,0x46, 0xce,0xe9,0x8e,0x9b, 0x12,0xe9,0x19,0x7d, + 0x50,0x86,0xcb,0x9b, 0x50,0x72,0x19,0xee, 0x95,0xdb,0x11,0x3a, 0x91,0x76,0x78,0xb2, + 0x73,0xbe,0xd6,0xb8, 0xe3,0xc1,0x74,0x3b, 0x71,0x16,0xe6,0x9e, 0x22,0x22,0x95,0x16, + 0x3f,0xf1,0xca,0xa1, 0x68,0x1f,0xac,0x09, 0x12,0x0e,0xca,0x30, 0x75,0x86,0xe1,0xa7, +}; + +static const unsigned char plain_ecb_256_text[] = { + 0x6b,0xc1,0xbe,0xe2, 0x2e,0x40,0x9f,0x96, 0xe9,0x3d,0x7e,0x11, 0x73,0x93,0x17,0x2a, + 0xae,0x2d,0x8a,0x57, 0x1e,0x03,0xac,0x9c, 0x9e,0xb7,0x6f,0xac, 0x45,0xaf,0x8e,0x51, + 0x30,0xc8,0x1c,0x46, 0xa3,0x5c,0xe4,0x11, 0xe5,0xfb,0xc1,0x19, 0x1a,0x0a,0x52,0xef, + 0xf6,0x9f,0x24,0x45, 0xdf,0x4f,0x9b,0x17, 0xad,0x2b,0x41,0x7b, 0xe6,0x6c,0x37,0x10, +}; + +static const unsigned char cipher_ecb_256_text[] = { + 0xf3,0xee,0xd1,0xbd, 0xb5,0xd2,0xa0,0x3c, 0x06,0x4b,0x5a,0x7e, 0x3d,0xb1,0x81,0xf8, + 0x59,0x1c,0xcb,0x10, 0xd4,0x10,0xed,0x26, 0xdc,0x5b,0xa7,0x4a, 0x31,0x36,0x28,0x70, + 0xb6,0xed,0x21,0xb9, 0x9c,0xa6,0xf4,0xf9, 0xf1,0x53,0xe7,0xb1, 0xbe,0xaf,0xed,0x1d, + 0x23,0x30,0x4b,0x7a, 0x39,0xf9,0xf3,0xff, 0x06,0x7d,0x8d,0x8f, 0x9e,0x24,0xec,0xc7, +}; + +static const unsigned char plain_ctr_192_text[] = { + 0x6b,0xc1,0xbe,0xe2, 0x2e,0x40,0x9f,0x96, 0xe9,0x3d,0x7e,0x11, 0x73,0x93,0x17,0x2a, + 0xae,0x2d,0x8a,0x57, 0x1e,0x03,0xac,0x9c, 0x9e,0xb7,0x6f,0xac, 0x45,0xaf,0x8e,0x51, + 0x30,0xc8,0x1c,0x46, 0xa3,0x5c,0xe4,0x11, 0xe5,0xfb,0xc1,0x19, 0x1a,0x0a,0x52,0xef, + 0xf6,0x9f,0x24,0x45, 0xdf,0x4f,0x9b,0x17, 0xad,0x2b,0x41,0x7b, 0xe6,0x6c,0x37,0x10, +}; + +static const unsigned char cipher_ctr_192_text[] = { + 0x1a,0xbc,0x93,0x24, 0x17,0x52,0x1c,0xa2, 0x4f,0x2b,0x04,0x59, 0xfe,0x7e,0x6e,0x0b, + 0x09,0x03,0x39,0xec, 0x0a,0xa6,0xfa,0xef, 0xd5,0xcc,0xc2,0xc6, 0xf4,0xce,0x8e,0x94, + 0x1e,0x36,0xb2,0x6b, 0xd1,0xeb,0xc6,0x70, 0xd1,0xbd,0x1d,0x66, 0x56,0x20,0xab,0xf7, + 0x4f,0x78,0xa7,0xf6, 0xd2,0x98,0x09,0x58, 0x5a,0x97,0xda,0xec, 0x58,0xc6,0xb0,0x50, +}; + +static const unsigned char plain_ofb_256_text[] = { + 0x6b,0xc1,0xbe,0xe2, 0x2e,0x40,0x9f,0x96, 0xe9,0x3d,0x7e,0x11, 0x73,0x93,0x17,0x2a, + 0xae,0x2d,0x8a,0x57, 0x1e,0x03,0xac,0x9c, 0x9e,0xb7,0x6f,0xac, 0x45,0xaf,0x8e,0x51, + 0x30,0xc8,0x1c,0x46, 0xa3,0x5c,0xe4,0x11, 0xe5,0xfb,0xc1,0x19, 0x1a,0x0a,0x52,0xef, + 0xf6,0x9f,0x24,0x45, 0xdf,0x4f,0x9b,0x17, 0xad,0x2b,0x41,0x7b, 0xe6,0x6c,0x37,0x10, +}; + +static const unsigned char cipher_ofb_256_text[] = { + 0xdc,0x7e,0x84,0xbf,0xda,0x79,0x16,0x4b,0x7e,0xcd,0x84,0x86,0x98,0x5d,0x38,0x60, + 0x4f,0xeb,0xdc,0x67,0x40,0xd2,0x0b,0x3a,0xc8,0x8f,0x6a,0xd8,0x2a,0x4f,0xb0,0x8d, + 0x71,0xab,0x47,0xa0,0x86,0xe8,0x6e,0xed,0xf3,0x9d,0x1c,0x5b,0xba,0x97,0xc4,0x08, + 0x01,0x26,0x14,0x1d,0x67,0xf3,0x7b,0xe8,0x53,0x8f,0x5a,0x8b,0xe7,0x40,0xe4,0x84, +}; + +static const unsigned char plain_des_ecb_text[] = { + 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const unsigned char cipher_des_ecb_text[] = { + 0x95,0xF8,0xA5,0xE5,0xDD,0x31,0xD9,0x00,0xDD,0x7F,0x12,0x1C,0xA5,0x01,0x56,0x19, + 0x2E,0x86,0x53,0x10,0x4F,0x38,0x34,0xEA,0x4B,0xD3,0x88,0xFF,0x6C,0xD8,0x1D,0x4F, + 0x20,0xB9,0xE7,0x67,0xB2,0xFB,0x14,0x56,0x55,0x57,0x93,0x80,0xD7,0x71,0x38,0xEF, + 0x6C,0xC5,0xDE,0xFA,0xAF,0x04,0x51,0x2F,0x0D,0x9F,0x27,0x9B,0xA5,0xD8,0x72,0x60, +}; + +static const unsigned char plain_des_cbc_text[] = { + 0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74,0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20, + 0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20, +}; + +static const unsigned char cipher_des_cbc_text[] = { + 0xe5,0xc7,0xcd,0xde,0x87,0x2b,0xf2,0x7c,0x43,0xe9,0x34,0x00,0x8c,0x38,0x9c,0x0f, + 0x68,0x37,0x88,0x49,0x9a,0x7c,0x05,0xf6, +}; + +static const unsigned char plain_des_ofb_text[] = { + 0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74,0x43,0xe9,0x34,0x00,0x8c,0x38,0x9c,0x0f, + 0x68,0x37,0x88,0x49,0x9a,0x7c,0x05,0xf6, +}; + +static const unsigned char cipher_des_ofb_text[] = { + 0xf3,0x09,0x62,0x49,0xc7,0xf4,0x6e,0x51,0x1e,0x7e,0x5e,0x50,0xcb,0xbe,0xc4,0x10, + 0x33,0x35,0xa1,0x8a,0xde,0x4a,0x91,0x15, +}; + +static const unsigned char plain_des_tri_ecb_text[] = { + 0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74,0x43,0xe9,0x34,0x00,0x8c,0x38,0x9c,0x0f, + 0x68,0x37,0x88,0x49,0x9a,0x7c,0x05,0xf6, +}; + +static const unsigned char cipher_des_tri_ecb_text[] = { + 0x31,0x4f,0x83,0x27,0xfa,0x7a,0x09,0xa8,0xd5,0x89,0x5f,0xad,0xe9,0x8f,0xae,0xdf, + 0x98,0xf4,0x70,0xeb,0x35,0x53,0xa5,0xda, +}; + +static const unsigned char plain_des_tri_cbc_text[] = { + 0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74,0x43,0xe9,0x34,0x00,0x8c,0x38,0x9c,0x0f, + 0x68,0x37,0x88,0x49,0x9a,0x7c,0x05,0xf6, +}; + +static const unsigned char cipher_des_tri_cbc_text[] = { + 0xf3,0xc0,0xff,0x02,0x6c,0x02,0x30,0x89,0xc4,0x3a,0xdd,0x8f,0xd8,0xcd,0x5e,0x43, + 0x2b,0xfd,0x41,0xd3,0x13,0x0b,0xcf,0x40, +}; + +static inline void hexdump(unsigned char *buf, unsigned int len) +{ + while (len--) + AES_DBG("%02x", *buf++); + AES_DBG("\n"); +} + +static void tcrypt_complete(struct crypto_async_request *req, int err) +{ + struct tcrypt_result *res = req->data; + if (err == -EINPROGRESS) + return; +// res->err = err; + AES_DBG("crypt all over....\n"); + complete(&res->completion); + +} + +static int testmgr_alloc_buf(char *buf[XBUFSIZE]) +{ + int i; + for (i = 0; i < XBUFSIZE; i++) { + buf[i] = (void *)__get_free_page(GFP_KERNEL); + if (!buf[i]) + goto err_free_buf; + } + + return 0; +err_free_buf: + while (i-- > 0) + free_page((unsigned long)buf[i]); + + return -ENOMEM; +} + +static int fh_aes_cbc128_self_test(void) +{ + struct crypto_ablkcipher *tfm; + struct ablkcipher_request *req; + const char *algo; + + struct scatterlist sg[8]; + struct scatterlist dst_sg[8]; + + u32 key[4] = { AES_KEY0, AES_KEY1, AES_KEY2, AES_KEY3 }; + u32 iv[4] = { AES_IV0, AES_IV1, AES_IV2, AES_IV3 }; + //void * memcpy(void * dest, const void *src, size_t n) + + char *xbuf[XBUFSIZE]; + char *dst_xbuf[XBUFSIZE]; + //int ret = -ENOMEM; + void *data; + void *dst_data; + memcpy(&key[0],&aes_cbc_key_buf[0],sizeof(aes_cbc_key_buf)); + memcpy(&iv[0],&aes_cbc_iv_buf[0],sizeof(aes_cbc_iv_buf)); + if (testmgr_alloc_buf(xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + if (testmgr_alloc_buf(dst_xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + AES_DBG("aes self test get in...\n"); + AES_DBG(" *_* step 1\n"); + tfm = + crypto_alloc_ablkcipher("cbc-aes-fh", + CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, 0); + if (IS_ERR(tfm)) { + AES_DBG("aes_test: failed to alloc cipher!\n"); + return -1; + } + + AES_DBG(" *_* step 2\n"); + algo = crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm)); + init_completion(&result.completion); + + AES_DBG(" *_* step 3\n"); + crypto_ablkcipher_setkey(tfm, (u8 *) key, 16); + + AES_DBG(" *_* step 4\n"); + req = ablkcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) { + AES_DBG(KERN_ERR "alg: skcipher: Failed to allocate request " + "for %s\n", algo); + return -1; + } + + AES_DBG(" *_* step 5\n"); + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + tcrypt_complete, &result); + + AES_DBG(" *_* step 6\n"); + data = xbuf[0]; + dst_data = dst_xbuf[0]; + + //encrypt + memcpy(data, plain_text, 64); + memset(dst_data, 0, 64); + sg_init_one(&sg[0], data, 64); + sg_init_one(&dst_sg[0], dst_data, 64); + + AES_DBG(" *_* step 7\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 64, (void *)iv); + + AES_DBG(" *_* step 8\n"); + crypto_ablkcipher_encrypt(req); + + wait_for_completion(&result.completion); + + if (memcmp(dst_data, cipher_text, 64)) + AES_PRINT_RESULT(" encrypt error....\n"); + else + AES_PRINT_RESULT(" encrypt ok....\n"); + + //decrypt + memcpy(data, cipher_text, 64); + memset(dst_data, 0, 64); + sg_init_one(&sg[0], data, 64); + sg_init_one(&dst_sg[0], dst_data, 64); + AES_DBG(" *_* step 8\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 64, (void *)iv); + AES_DBG(" *_* step 9\n"); + crypto_ablkcipher_decrypt(req); + wait_for_completion(&result.completion); + + if (memcmp(dst_data, plain_text, 64)) + AES_PRINT_RESULT(" decrypt error....\n"); + else + AES_PRINT_RESULT(" decrypt ok....\n"); + + return 0; + +} + +static int fh_aes_ecb256_self_test(void) +{ + struct crypto_ablkcipher *tfm; + struct ablkcipher_request *req; + const char *algo; + struct scatterlist sg[8]; + struct scatterlist dst_sg[8]; + u32 key[8] = { + AES_ECB_KEY0, AES_ECB_KEY1, AES_ECB_KEY2, AES_ECB_KEY3, + AES_ECB_KEY4, AES_ECB_KEY5, AES_ECB_KEY6, AES_ECB_KEY7 + }; + //const u32 iv[4] = {AES_IV0,AES_IV1,AES_IV2,AES_IV3}; + + + //memcpy(&iv[0],&aes_cbc_iv_buf[0],sizeof(aes_cbc_iv_buf)); + + char *xbuf[XBUFSIZE]; + char *dst_xbuf[XBUFSIZE]; + + //int ret = -ENOMEM; + void *data; + void *dst_data; + memcpy(&key[0],&aes_ecb_key_buf[0],sizeof(aes_ecb_key_buf)); + if (testmgr_alloc_buf(xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + if (testmgr_alloc_buf(dst_xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + AES_DBG("aes self test get in...\n"); + AES_DBG(" *_* step 1\n"); + tfm = + crypto_alloc_ablkcipher("ecb-aes-fh", + CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, 0); + if (IS_ERR(tfm)) { + AES_DBG("aes_test: failed to alloc cipher!\n"); + return -1; + } + + AES_DBG(" *_* step 2\n"); + algo = crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm)); + init_completion(&result.completion); + + AES_DBG(" *_* step 3\n"); + crypto_ablkcipher_setkey(tfm, (u8 *) key, 32); + + AES_DBG(" *_* step 4\n"); + req = ablkcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) { + AES_DBG(KERN_ERR "alg: skcipher: Failed to allocate request " + "for %s\n", algo); + return -1; + } + + AES_DBG(" *_* step 5\n"); + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + tcrypt_complete, &result); + + AES_DBG(" *_* step 6\n"); + data = xbuf[0]; + dst_data = dst_xbuf[0]; + + //encrypt + memcpy(data, plain_ecb_256_text, 64); + memset(dst_data, 0, 64); + sg_init_one(&sg[0], data, 64); + sg_init_one(&dst_sg[0], dst_data, 64); + + AES_DBG(" *_* step 7\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 64, NULL); + + AES_DBG(" *_* step 8\n"); + crypto_ablkcipher_encrypt(req); + + wait_for_completion(&result.completion); + + if (memcmp(dst_data, cipher_ecb_256_text, 64)) + AES_PRINT_RESULT(" encrypt error....\n"); + else + AES_PRINT_RESULT(" encrypt ok....\n"); + + //decrypt + memcpy(data, cipher_ecb_256_text, 64); + memset(dst_data, 0, 64); + sg_init_one(&sg[0], data, 64); + sg_init_one(&dst_sg[0], dst_data, 64); + + AES_DBG(" *_* step 8\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 64, NULL); + + AES_DBG(" *_* step 9\n"); + crypto_ablkcipher_decrypt(req); + + wait_for_completion(&result.completion); + + if (memcmp(dst_data, plain_ecb_256_text, 64)) + AES_PRINT_RESULT(" decrypt error....\n"); + else + AES_PRINT_RESULT(" decrypt ok....\n"); + + return 0; + +} + +static int fh_aes_ofb256_self_test(void) +{ + struct crypto_ablkcipher *tfm; + struct ablkcipher_request *req; + const char *algo; + struct scatterlist sg[8]; + struct scatterlist dst_sg[8]; + u32 key[8] = { + AES_OFB_256_KEY0, AES_OFB_256_KEY1, AES_OFB_256_KEY2, + AES_OFB_256_KEY3, + AES_OFB_256_KEY4, AES_OFB_256_KEY5, AES_OFB_256_KEY6, + AES_OFB_256_KEY7 + }; + u32 iv[4] = + { AES_OFB_IV0, AES_OFB_IV1, AES_OFB_IV2, AES_OFB_IV3 }; + char *xbuf[XBUFSIZE]; + char *dst_xbuf[XBUFSIZE]; + void *data; + void *dst_data; + memcpy(&key[0],&aes_ofb_key_buf[0],sizeof(aes_ofb_key_buf)); + memcpy(&iv[0],&aes_ofb_iv_buf[0],sizeof(aes_ofb_iv_buf)); + if (testmgr_alloc_buf(xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + if (testmgr_alloc_buf(dst_xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + AES_DBG("aes self test get in...\n"); + AES_DBG(" *_* step 1\n"); + tfm = + crypto_alloc_ablkcipher("ofb-aes-fh", + CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, 0); + if (IS_ERR(tfm)) { + AES_DBG("aes_test: failed to alloc cipher!\n"); + return -1; + } + + AES_DBG(" *_* step 2\n"); + algo = crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm)); + init_completion(&result.completion); + + AES_DBG(" *_* step 3\n"); + crypto_ablkcipher_setkey(tfm, (u8 *) key, 32); + + AES_DBG(" *_* step 4\n"); + req = ablkcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) { + AES_DBG(KERN_ERR "alg: skcipher: Failed to allocate request " + "for %s\n", algo); + return -1; + } + + AES_DBG(" *_* step 5\n"); + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + tcrypt_complete, &result); + + AES_DBG(" *_* step 6\n"); + data = xbuf[0]; + dst_data = dst_xbuf[0]; + //encrypt + memcpy(data, plain_ofb_256_text, 64); + memset(dst_data, 0, 64); + sg_init_one(&sg[0], data, 64); + sg_init_one(&dst_sg[0], dst_data, 64); + + AES_DBG(" *_* step 7\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 64, (void *)iv); + + AES_DBG(" *_* step 8\n"); + crypto_ablkcipher_encrypt(req); + wait_for_completion(&result.completion); + if (memcmp(dst_data, cipher_ofb_256_text, 64)) + AES_PRINT_RESULT(" encrypt error....\n"); + else + AES_PRINT_RESULT(" encrypt ok....\n"); + //decrypt + memcpy(data, cipher_ofb_256_text, 64); + memset(dst_data, 0, 64); + sg_init_one(&sg[0], data, 64); + sg_init_one(&dst_sg[0], dst_data, 64); + AES_DBG(" *_* step 8\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 64, (void *)iv); + AES_DBG(" *_* step 9\n"); + crypto_ablkcipher_decrypt(req); + + wait_for_completion(&result.completion); + + if (memcmp(dst_data, plain_ofb_256_text, 64)) + AES_PRINT_RESULT(" decrypt error....\n"); + else + AES_PRINT_RESULT(" decrypt ok....\n"); + + return 0; +} + +static int fh_des_ecb_self_test(void) +{ + struct crypto_ablkcipher *tfm; + struct ablkcipher_request *req; + const char *algo; + struct scatterlist sg[8]; + struct scatterlist dst_sg[8]; + u32 key[2] = { DES_ECB_KEY0, DES_ECB_KEY1 }; + char *xbuf[XBUFSIZE]; + char *dst_xbuf[XBUFSIZE]; + void *data; + void *dst_data; + + + memcpy(&key[0],&des_ecb_key_buf[0],sizeof(des_ecb_key_buf)); + //memcpy(&iv[0],&aes_ofb_iv_buf[0],sizeof(aes_ofb_iv_buf)); + + if (testmgr_alloc_buf(xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + if (testmgr_alloc_buf(dst_xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + AES_DBG("aes self test get in...\n"); + + AES_DBG(" *_* step 1\n"); + tfm = + crypto_alloc_ablkcipher("ecb-des-fh", + CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, 0); + if (IS_ERR(tfm)) { + AES_DBG("aes_test: failed to alloc cipher!\n"); + return -1; + } + + AES_DBG(" *_* step 2\n"); + algo = crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm)); + init_completion(&result.completion); + + AES_DBG(" *_* step 3\n"); + crypto_ablkcipher_setkey(tfm, (u8 *) key, 8); + + AES_DBG(" *_* step 4\n"); + req = ablkcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) { + AES_DBG(KERN_ERR "alg: skcipher: Failed to allocate request " + "for %s\n", algo); + return -1; + } + + AES_DBG(" *_* step 5\n"); + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + tcrypt_complete, &result); + + AES_DBG(" *_* step 6\n"); + data = xbuf[0]; + dst_data = dst_xbuf[0]; + + //encrypt + memcpy(data, plain_des_ecb_text, 64); + memset(dst_data, 0, 64); + sg_init_one(&sg[0], data, 64); + sg_init_one(&dst_sg[0], dst_data, 64); + + AES_DBG(" *_* step 7\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 64, NULL); + + AES_DBG(" *_* step 8\n"); + crypto_ablkcipher_encrypt(req); + + wait_for_completion(&result.completion); + + if (memcmp(dst_data, cipher_des_ecb_text, 64)) + AES_PRINT_RESULT(" encrypt error....\n"); + else + AES_PRINT_RESULT(" encrypt ok....\n"); + + //decrypt + memcpy(data, cipher_des_ecb_text, 64); + memset(dst_data, 0, 64); + sg_init_one(&sg[0], data, 64); + sg_init_one(&dst_sg[0], dst_data, 64); + + AES_DBG(" *_* step 8\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 64, NULL); + + AES_DBG(" *_* step 9\n"); + crypto_ablkcipher_decrypt(req); + + wait_for_completion(&result.completion); + + if (memcmp(dst_data, plain_des_ecb_text, 64)) + AES_PRINT_RESULT(" decrypt error....\n"); + else + AES_PRINT_RESULT(" decrypt ok....\n"); + + return 0; + +} + +static int fh_des_cbc_self_test(void) +{ + struct crypto_ablkcipher *tfm; + struct ablkcipher_request *req; + const char *algo; + struct scatterlist sg[8]; + struct scatterlist dst_sg[8]; + u32 key[2] = { DES_CBC_KEY0, DES_CBC_KEY1 }; + u32 iv[2] = { DES_CBC_IV0, DES_CBC_IV1 }; + char *xbuf[XBUFSIZE]; + char *dst_xbuf[XBUFSIZE]; + void *data; + void *dst_data; + + + memcpy(&key[0],&des_cbc_key_buf[0],sizeof(des_cbc_key_buf)); + memcpy(&iv[0],&des_cbc_iv_buf[0],sizeof(des_cbc_iv_buf)); + + if (testmgr_alloc_buf(xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + if (testmgr_alloc_buf(dst_xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + AES_DBG("aes self test get in...\n"); + + AES_DBG(" *_* step 1\n"); + tfm = + crypto_alloc_ablkcipher("cbc-des-fh", + CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, 0); + if (IS_ERR(tfm)) { + AES_DBG("aes_test: failed to alloc cipher!\n"); + return -1; + } + + AES_DBG(" *_* step 2\n"); + algo = crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm)); + init_completion(&result.completion); + + AES_DBG(" *_* step 3\n"); + crypto_ablkcipher_setkey(tfm, (u8 *) key, 8); + + AES_DBG(" *_* step 4\n"); + req = ablkcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) { + AES_DBG(KERN_ERR "alg: skcipher: Failed to allocate request " + "for %s\n", algo); + return -1; + } + + AES_DBG(" *_* step 5\n"); + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + tcrypt_complete, &result); + + AES_DBG(" *_* step 6\n"); + data = xbuf[0]; + dst_data = dst_xbuf[0]; + + //encrypt + memcpy(data, plain_des_cbc_text, 24); + memset(dst_data, 0, 24); + sg_init_one(&sg[0], data, 24); + sg_init_one(&dst_sg[0], dst_data, 24); + + AES_DBG(" *_* step 7\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 24, (void *)iv); + + AES_DBG(" *_* step 8\n"); + crypto_ablkcipher_encrypt(req); + + wait_for_completion(&result.completion); + + if (memcmp(dst_data, cipher_des_cbc_text, 24)) + AES_PRINT_RESULT(" encrypt error....\n"); + else + AES_PRINT_RESULT(" encrypt ok....\n"); + + //decrypt + memcpy(data, cipher_des_cbc_text, 24); + memset(dst_data, 0, 24); + sg_init_one(&sg[0], data, 24); + sg_init_one(&dst_sg[0], dst_data, 24); + + AES_DBG(" *_* step 8\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 24, (void *)iv); + + AES_DBG(" *_* step 9\n"); + crypto_ablkcipher_decrypt(req); + + wait_for_completion(&result.completion); + + if (memcmp(dst_data, plain_des_cbc_text, 24)) + AES_PRINT_RESULT(" decrypt error....\n"); + else + AES_PRINT_RESULT(" decrypt ok....\n"); + + return 0; +} + +static int fh_des_ofb_self_test(void) +{ + struct crypto_ablkcipher *tfm; + struct ablkcipher_request *req; + const char *algo; + struct scatterlist sg[8]; + struct scatterlist dst_sg[8]; + u32 key[2] = { DES_OFB_KEY0, DES_OFB_KEY1 }; + u32 iv[2] = { DES_OFB_IV0, DES_OFB_IV1 }; + char *xbuf[XBUFSIZE]; + char *dst_xbuf[XBUFSIZE]; + void *data; + void *dst_data; + + memcpy(&key[0],&des_ofb_key_buf[0],sizeof(des_ofb_key_buf)); + memcpy(&iv[0],&des_ofb_iv_buf[0],sizeof(des_ofb_iv_buf)); + + if (testmgr_alloc_buf(xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + if (testmgr_alloc_buf(dst_xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + AES_DBG("aes self test get in...\n"); + AES_DBG(" *_* step 1\n"); + tfm = + crypto_alloc_ablkcipher("ofb-des-fh", + CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, 0); + if (IS_ERR(tfm)) { + AES_DBG("aes_test: failed to alloc cipher!\n"); + return -1; + } + + AES_DBG(" *_* step 2\n"); + algo = crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm)); + init_completion(&result.completion); + + AES_DBG(" *_* step 3\n"); + crypto_ablkcipher_setkey(tfm, (u8 *) key, 8); + + AES_DBG(" *_* step 4\n"); + req = ablkcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) { + AES_DBG(KERN_ERR "alg: skcipher: Failed to allocate request " + "for %s\n", algo); + return -1; + } + + AES_DBG(" *_* step 5\n"); + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + tcrypt_complete, &result); + + AES_DBG(" *_* step 6\n"); + data = xbuf[0]; + dst_data = dst_xbuf[0]; + + //encrypt + memcpy(data, plain_des_ofb_text, 24); + memset(dst_data, 0, 24); + sg_init_one(&sg[0], data, 24); + sg_init_one(&dst_sg[0], dst_data, 24); + + AES_DBG(" *_* step 7\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 24, (void *)iv); + AES_DBG(" *_* step 8\n"); + crypto_ablkcipher_encrypt(req); + wait_for_completion(&result.completion); + if (memcmp(dst_data, cipher_des_ofb_text, 24)) + AES_PRINT_RESULT(" encrypt error....\n"); + else + AES_PRINT_RESULT(" encrypt ok....\n"); + + //decrypt + memcpy(data, cipher_des_ofb_text, 24); + memset(dst_data, 0, 24); + sg_init_one(&sg[0], data, 24); + sg_init_one(&dst_sg[0], dst_data, 24); + AES_DBG(" *_* step 8\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 24, (void *)iv); + + AES_DBG(" *_* step 9\n"); + crypto_ablkcipher_decrypt(req); + wait_for_completion(&result.completion); + if (memcmp(dst_data, plain_des_ofb_text, 24)) + AES_PRINT_RESULT(" decrypt error....\n"); + else + AES_PRINT_RESULT(" decrypt ok....\n"); + + return 0; + +} + +static int fh_des_tri_ecb_self_test(void) +{ + struct crypto_ablkcipher *tfm; + struct ablkcipher_request *req; + const char *algo; + struct scatterlist sg[8]; + struct scatterlist dst_sg[8]; + u32 key[6] = { + DES_TRI_ECB_KEY0, DES_TRI_ECB_KEY1, DES_TRI_ECB_KEY2, + DES_TRI_ECB_KEY3, DES_TRI_ECB_KEY4, DES_TRI_ECB_KEY5 + }; + char *xbuf[XBUFSIZE]; + char *dst_xbuf[XBUFSIZE]; + void *data; + void *dst_data; + + memcpy(&key[0],&des3_ecb_key_buf[0],sizeof(des3_ecb_key_buf)); + //memcpy(&iv[0],&des_ofb_iv_buf[0],sizeof(des_ofb_iv_buf)); + if (testmgr_alloc_buf(xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + if (testmgr_alloc_buf(dst_xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + AES_DBG("aes self test get in...\n"); + + AES_DBG(" *_* step 1\n"); + tfm = + crypto_alloc_ablkcipher("ecb-des3-fh", + CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, 0); + if (IS_ERR(tfm)) { + AES_DBG("aes_test: failed to alloc cipher!\n"); + return -1; + } + + AES_DBG(" *_* step 2\n"); + algo = crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm)); + init_completion(&result.completion); + + AES_DBG(" *_* step 3\n"); + crypto_ablkcipher_setkey(tfm, (u8 *) key, 24); + + AES_DBG(" *_* step 4\n"); + req = ablkcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) { + AES_DBG(KERN_ERR "alg: skcipher: Failed to allocate request " + "for %s\n", algo); + return -1; + } + + AES_DBG(" *_* step 5\n"); + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + tcrypt_complete, &result); + + AES_DBG(" *_* step 6\n"); + data = xbuf[0]; + dst_data = dst_xbuf[0]; + + //encrypt + memcpy(data, plain_des_tri_ecb_text, 24); + memset(dst_data, 0, 24); + sg_init_one(&sg[0], data, 24); + sg_init_one(&dst_sg[0], dst_data, 24); + + AES_DBG(" *_* step 7\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 24, (void *)NULL); + + AES_DBG(" *_* step 8\n"); + crypto_ablkcipher_encrypt(req); + + wait_for_completion(&result.completion); + + if (memcmp(dst_data, cipher_des_tri_ecb_text, 24)) + AES_PRINT_RESULT(" encrypt error....\n"); + else + AES_PRINT_RESULT(" encrypt ok....\n"); + + //decrypt + memcpy(data, cipher_des_tri_ecb_text, 24); + memset(dst_data, 0, 24); + sg_init_one(&sg[0], data, 24); + sg_init_one(&dst_sg[0], dst_data, 24); + + AES_DBG(" *_* step 8\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 24, (void *)NULL); + + AES_DBG(" *_* step 9\n"); + crypto_ablkcipher_decrypt(req); + + wait_for_completion(&result.completion); + + if (memcmp(dst_data, plain_des_tri_ecb_text, 24)) + AES_PRINT_RESULT(" decrypt error....\n"); + else + AES_PRINT_RESULT(" decrypt ok....\n"); + + return 0; + +} + +static int fh_des_tri_cbc_self_test(void) +{ + struct crypto_ablkcipher *tfm; + struct ablkcipher_request *req; + const char *algo; + struct scatterlist sg[8]; + struct scatterlist dst_sg[8]; + u32 key[6] = { + DES_TRI_CBC_KEY0, DES_TRI_CBC_KEY1, DES_TRI_CBC_KEY2, + DES_TRI_CBC_KEY3, DES_TRI_CBC_KEY4, DES_TRI_CBC_KEY5 + }; + u32 iv[2] = { DES_TRI_CBC_IV0, DES_TRI_CBC_IV1 }; + char *xbuf[XBUFSIZE]; + char *dst_xbuf[XBUFSIZE]; + void *data; + void *dst_data; + + + memcpy(&key[0],&des3_cbc_key_buf[0],sizeof(des3_cbc_key_buf)); + memcpy(&iv[0],&des3_cbc_iv_buf[0],sizeof(des3_cbc_iv_buf)); + + + if (testmgr_alloc_buf(xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + if (testmgr_alloc_buf(dst_xbuf)) { + AES_DBG("no pages.\n"); + return -1; + } + + AES_DBG("aes self test get in...\n"); + + AES_DBG(" *_* step 1\n"); + tfm = + crypto_alloc_ablkcipher("cbc-des3-fh", + CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, 0); + if (IS_ERR(tfm)) { + AES_DBG("aes_test: failed to alloc cipher!\n"); + return -1; + } + + AES_DBG(" *_* step 2\n"); + algo = crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm)); + init_completion(&result.completion); + + AES_DBG(" *_* step 3\n"); + crypto_ablkcipher_setkey(tfm, (u8 *) key, 24); + + AES_DBG(" *_* step 4\n"); + req = ablkcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) { + AES_DBG(KERN_ERR "alg: skcipher: Failed to allocate request " + "for %s\n", algo); + return -1; + } + + AES_DBG(" *_* step 5\n"); + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + tcrypt_complete, &result); + + AES_DBG(" *_* step 6\n"); + data = xbuf[0]; + dst_data = dst_xbuf[0]; + + //encrypt + memcpy(data, plain_des_tri_cbc_text, 24); + memset(dst_data, 0, 24); + sg_init_one(&sg[0], data, 24); + sg_init_one(&dst_sg[0], dst_data, 24); + + AES_DBG(" *_* step 7\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 24, (void *)iv); + + AES_DBG(" *_* step 8\n"); + crypto_ablkcipher_encrypt(req); + + wait_for_completion(&result.completion); + + if (memcmp(dst_data, cipher_des_tri_cbc_text, 24)) + AES_PRINT_RESULT(" encrypt error....\n"); + else + AES_PRINT_RESULT(" encrypt ok....\n"); + + //decrypt + memcpy(data, cipher_des_tri_cbc_text, 24); + memset(dst_data, 0, 24); + sg_init_one(&sg[0], data, 24); + sg_init_one(&dst_sg[0], dst_data, 24); + + AES_DBG(" *_* step 8\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, 24, (void *)iv); + + AES_DBG(" *_* step 9\n"); + crypto_ablkcipher_decrypt(req); + + wait_for_completion(&result.completion); + + if (memcmp(dst_data, plain_des_tri_cbc_text, 24)) + AES_PRINT_RESULT(" decrypt error....\n"); + else + AES_PRINT_RESULT(" decrypt ok....\n"); + + return 0; + +} + +#if(0) + +typedef struct +{ + unsigned int base; + void * vbase; + unsigned int size; +}MEM_INFO; +typedef struct { + MEM_INFO mem; + unsigned char *remap_base; /**<已用大小*/ +} RW_MEM_INFO; + + +static unsigned char aes_128_key_buf[] = { + 0x2b,0x7e,0x15,0x16, 0x28,0xae,0xd2,0xa6, 0xab,0xf7,0x15,0x88, 0x09,0xcf,0x4f,0x3c, +}; +static unsigned char plain_aes_128_text[] = { + 0x6b,0xc1,0xbe,0xe2, 0x2e,0x40,0x9f,0x96, 0xe9,0x3d,0x7e,0x11, 0x73,0x93,0x17,0x2a, + 0xae,0x2d,0x8a,0x57, 0x1e,0x03,0xac,0x9c, 0x9e,0xb7,0x6f,0xac, 0x45,0xaf,0x8e,0x51, + 0x30,0xc8,0x1c,0x46, 0xa3,0x5c,0xe4,0x11, 0xe5,0xfb,0xc1,0x19, 0x1a,0x0a,0x52,0xef, + 0xf6,0x9f,0x24,0x45, 0xdf,0x4f,0x9b,0x17, 0xad,0x2b,0x41,0x7b, 0xe6,0x6c,0x37,0x10, +}; + +static unsigned char cipher_aes_128_text[] = { + 0x3A,0xD7,0x7B,0xB4, 0x0D,0x7A,0x36,0x60, 0xA8,0x9E,0xCA,0xF3, 0x24,0x66,0xEF,0x97, + 0xf5,0xd3,0xd5,0x85, 0x03,0xb9,0x69,0x9d, 0xe7,0x85,0x89,0x5a, 0x96,0xfd,0xba,0xaf, + 0x43,0xb1,0xcd,0x7f, 0x59,0x8e,0xce,0x23, 0x88,0x1b,0x00,0xe3, 0xed,0x03,0x06,0x88, + 0x7b,0x0c,0x78,0x5e, 0x27,0xe8,0xad,0x3f, 0x82,0x23,0x20,0x71, 0x04,0x72,0x5d,0xd4, +}; + +int aes_128_ecb_encrypt(char *key_128,RW_MEM_INFO in, + RW_MEM_INFO out,unsigned int data_len_align16){ + + static char *xbuf; + static char *dst_xbuf; + static struct crypto_ablkcipher *tfm; + static struct ablkcipher_request *req; + static malloc_flag = 0; + const char *algo; + struct scatterlist sg[8]; + struct scatterlist dst_sg[8]; + void *data; + void *dst_data; + struct tcrypt_result wait_result; + +//malloc buf... + if(malloc_flag != 0){ + goto work_go; + } + malloc_flag = 1; + xbuf = (void *)__get_free_page(GFP_KERNEL); + if (!xbuf) { + printk("no pages.\n"); + return -1; + } + + dst_xbuf = (void *)__get_free_page(GFP_KERNEL); + if (!dst_xbuf) { + free_page((unsigned long)xbuf); + printk("no pages.\n"); + return -1; + } + + tfm = + crypto_alloc_ablkcipher("ecb-aes-fh", + CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, 0); + if (IS_ERR(tfm)) { + printk("aes_test: failed to alloc cipher!\n"); + free_page((unsigned long)xbuf); + free_page((unsigned long)dst_xbuf); + return -1; + } + req = ablkcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) { + printk(KERN_ERR "alg: skcipher: Failed to allocate request " + "for %s\n", algo); + return -1; + } + + +work_go: + printk("aes self test get in...\n"); + printk(" *_* step 1\n"); + + printk(" *_* step 2\n"); + algo = crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm)); + init_completion(&wait_result.completion); + + printk(" *_* step 3\n"); + crypto_ablkcipher_setkey(tfm, (u8 *)key_128, 16); + + printk(" *_* step 4\n"); + + + printk(" *_* step 5\n"); + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + tcrypt_complete, &wait_result); + + printk(" *_* step 6\n"); + data = xbuf; + dst_data = dst_xbuf; + + //encrypt + memcpy(data, in.remap_base, data_len_align16); + //memset(dst_data, 0, data_len_align16); + sg_init_one(&sg[0], data, data_len_align16); + sg_init_one(&dst_sg[0], dst_data, data_len_align16); + + printk(" *_* step 7\n"); + ablkcipher_request_set_crypt(req, sg, dst_sg, data_len_align16, NULL); + + printk(" *_* step 8\n"); + crypto_ablkcipher_encrypt(req); + + wait_for_completion(&wait_result.completion); + + memcpy(out.remap_base, dst_data, data_len_align16); + + return 0; + +} +#endif + + + +void fh_aes_self_test_all(void) +{ + unsigned char temp_buf[64] = {0}; + int i; + pr_info("aes cbc128 self test go...\n"); + fh_aes_cbc128_self_test(); + pr_info("aes ecb256 self test go...\n"); + fh_aes_ecb256_self_test(); + pr_info("aes ctr192 self test go...\n"); + fh_aes_ofb256_self_test(); + pr_info("aes ofb 256 self test go...\n"); + fh_aes_ofb256_self_test(); + pr_info("des ecb self test go...\n"); + fh_des_ecb_self_test(); + pr_info("des cbc self test go...\n"); + fh_des_cbc_self_test(); + pr_info("des ofb self test go...\n"); + fh_des_ofb_self_test(); + pr_info("des tri ecb self test go...\n"); + fh_des_tri_ecb_self_test(); + pr_info("des tri cbc self test go...\n"); + fh_des_tri_cbc_self_test(); +#if(0) + RW_MEM_INFO in; + RW_MEM_INFO out; + in.remap_base = &plain_aes_128_text[0]; + out.remap_base = &temp_buf[0]; + + pr_info("chenjn self test go.....\n"); + + aes_128_ecb_encrypt(&aes_128_key_buf[0], in, + out,64); + for (i = 0; i < sizeof(temp_buf); i++) + printk("cipher data[%d]:0x%x\n",i, temp_buf[i]); + +#endif + +} + +#endif diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 25cf327c..76f36670 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -89,6 +89,25 @@ config DW_DMAC Support the Synopsys DesignWare AHB DMA controller. This can be integrated in chips such as the Atmel AT32ap7000. +config FH_DMAC + tristate "FH DesignWare AHB DMA support" + depends on HAVE_CLK + select DMA_ENGINE + + help + Support the Synopsys DesignWare AHB DMA controller. This + can be integrated in chips such as the FullHan. + +if FH_DMAC + +config FH_DMAC_MISC + bool "FH DMAC Misc Device Enable" + default y + help + FH DMAC Misc Device Enable + +endif + config AT_HDMAC tristate "Atmel AHB DMA support" depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 @@ -271,5 +290,7 @@ config DMATEST help Simple DMA test client. Say N unless you're debugging a DMA Device driver. - endif + + + diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 836095ab..252d297a 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o obj-$(CONFIG_PL330_DMA) += pl330.o obj-$(CONFIG_PCH_DMA) += pch_dma.o obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o +obj-$(CONFIG_FH_DMAC) += fh_dmac.o \ No newline at end of file diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 8bcb15fb..ce1de9b4 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -45,6 +45,9 @@ * See Documentation/dmaengine.txt for more details */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include #include #include #include @@ -61,9 +64,9 @@ #include static DEFINE_MUTEX(dma_list_mutex); +static DEFINE_IDR(dma_idr); static LIST_HEAD(dma_device_list); static long dmaengine_ref_count; -static struct idr dma_idr; /* --- sysfs implementation --- */ @@ -170,7 +173,8 @@ static struct class dma_devclass = { #define dma_device_satisfies_mask(device, mask) \ __dma_device_satisfies_mask((device), &(mask)) static int -__dma_device_satisfies_mask(struct dma_device *device, dma_cap_mask_t *want) +__dma_device_satisfies_mask(struct dma_device *device, + const dma_cap_mask_t *want) { dma_cap_mask_t has; @@ -260,10 +264,13 @@ enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie) do { status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); if (time_after_eq(jiffies, dma_sync_wait_timeout)) { - printk(KERN_ERR "dma_sync_wait_timeout!\n"); + pr_err("%s: timeout!\n", __func__); return DMA_ERROR; } - } while (status == DMA_IN_PROGRESS); + if (status != DMA_IN_PROGRESS) + break; + cpu_relax(); + } while (1); return status; } @@ -311,7 +318,7 @@ static int __init dma_channel_table_init(void) } if (err) { - pr_err("dmaengine: initialization failure\n"); + pr_err("initialization failure\n"); for_each_dma_cap_mask(cap, dma_cap_mask_all) if (channel_table[cap]) free_percpu(channel_table[cap]); @@ -331,6 +338,20 @@ struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type) } EXPORT_SYMBOL(dma_find_channel); +/* + * net_dma_find_channel - find a channel for net_dma + * net_dma has alignment requirements + */ +struct dma_chan *net_dma_find_channel(void) +{ + struct dma_chan *chan = dma_find_channel(DMA_MEMCPY); + if (chan && !is_dma_copy_aligned(chan->device, 1, 1, 1)) + return NULL; + + return chan; +} +EXPORT_SYMBOL(net_dma_find_channel); + /** * dma_issue_pending_all - flush all pending operations across all channels */ @@ -442,7 +463,8 @@ static void dma_channel_rebalance(void) } } -static struct dma_chan *private_candidate(dma_cap_mask_t *mask, struct dma_device *dev, +static struct dma_chan *private_candidate(const dma_cap_mask_t *mask, + struct dma_device *dev, dma_filter_fn fn, void *fn_param) { struct dma_chan *chan; @@ -484,7 +506,8 @@ static struct dma_chan *private_candidate(dma_cap_mask_t *mask, struct dma_devic * @fn: optional callback to disposition available channels * @fn_param: opaque parameter to pass to dma_filter_fn */ -struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param) +struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, + dma_filter_fn fn, void *fn_param) { struct dma_device *device, *_d; struct dma_chan *chan = NULL; @@ -505,12 +528,12 @@ struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, v err = dma_chan_get(chan); if (err == -ENODEV) { - pr_debug("%s: %s module removed\n", __func__, - dma_chan_name(chan)); + pr_debug("%s: %s module removed\n", + __func__, dma_chan_name(chan)); list_del_rcu(&device->global_node); } else if (err) - pr_err("dmaengine: failed to get %s: (%d)\n", - dma_chan_name(chan), err); + pr_debug("%s: failed to get %s: (%d)\n", + __func__, dma_chan_name(chan), err); else break; if (--device->privatecnt == 0) @@ -520,13 +543,34 @@ struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, v } mutex_unlock(&dma_list_mutex); - pr_debug("%s: %s (%s)\n", __func__, chan ? "success" : "fail", + pr_debug("%s: %s (%s)\n", + __func__, + chan ? "success" : "fail", chan ? dma_chan_name(chan) : NULL); return chan; } EXPORT_SYMBOL_GPL(__dma_request_channel); +#if 0 +/** + * dma_request_slave_channel - try to allocate an exclusive slave channel + * @dev: pointer to client device structure + * @name: slave channel name + */ +struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name) +{ + /* If device-tree is present get slave info from here */ + if (dev->of_node) + return of_dma_request_slave_channel(dev->of_node, name); + + /* If device was enumerated by ACPI get slave info from here */ + if (ACPI_HANDLE(dev)) + return acpi_dma_request_slave_chan_by_name(dev, name); + return NULL; +} +EXPORT_SYMBOL_GPL(dma_request_slave_channel); +#endif void dma_release_channel(struct dma_chan *chan) { mutex_lock(&dma_list_mutex); @@ -563,8 +607,8 @@ void dmaengine_get(void) list_del_rcu(&device->global_node); break; } else if (err) - pr_err("dmaengine: failed to get %s: (%d)\n", - dma_chan_name(chan), err); + pr_debug("%s: failed to get %s: (%d)\n", + __func__, dma_chan_name(chan), err); } } @@ -647,19 +691,19 @@ static bool device_has_all_tx_types(struct dma_device *device) static int get_dma_id(struct dma_device *device) { int rc; + int dma_id; - idr_retry: - if (!idr_pre_get(&dma_idr, GFP_KERNEL)) - return -ENOMEM; mutex_lock(&dma_list_mutex); - rc = idr_get_new(&dma_idr, NULL, &device->dev_id); - mutex_unlock(&dma_list_mutex); - if (rc == -EAGAIN) - goto idr_retry; - else if (rc != 0) - return rc; - return 0; + if (!idr_pre_get(&dma_idr, GFP_KERNEL)) + return -ENOMEM; + + rc = idr_get_new(&dma_idr, NULL, &dma_id); + if (rc >= 0) + device->dev_id = dma_id; + + mutex_unlock(&dma_list_mutex); + return rc < 0 ? rc : 0; } /** @@ -692,12 +736,12 @@ int dma_async_device_register(struct dma_device *device) !device->device_prep_dma_interrupt); BUG_ON(dma_has_cap(DMA_SG, device->cap_mask) && !device->device_prep_dma_sg); - BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) && - !device->device_prep_slave_sg); BUG_ON(dma_has_cap(DMA_CYCLIC, device->cap_mask) && !device->device_prep_dma_cyclic); BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) && !device->device_control); + BUG_ON(dma_has_cap(DMA_INTERLEAVE, device->cap_mask) && + !device->device_prep_interleaved_dma); BUG_ON(!device->device_alloc_chan_resources); BUG_ON(!device->device_free_chan_resources); @@ -1000,7 +1044,7 @@ dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx) while (tx->cookie == -EBUSY) { if (time_after_eq(jiffies, dma_sync_wait_timeout)) { pr_err("%s timeout waiting for descriptor submission\n", - __func__); + __func__); return DMA_ERROR; } cpu_relax(); @@ -1049,8 +1093,6 @@ EXPORT_SYMBOL_GPL(dma_run_dependencies); static int __init dma_bus_init(void) { - idr_init(&dma_idr); - mutex_init(&dma_list_mutex); return class_register(&dma_devclass); } arch_initcall(dma_bus_init); diff --git a/drivers/dma/dmaengine.h b/drivers/dma/dmaengine.h new file mode 100644 index 00000000..17f983a4 --- /dev/null +++ b/drivers/dma/dmaengine.h @@ -0,0 +1,89 @@ +/* + * The contents of this file are private to DMA engine drivers, and is not + * part of the API to be used by DMA engine users. + */ +#ifndef DMAENGINE_H +#define DMAENGINE_H + +#include +#include + +/** + * dma_cookie_init - initialize the cookies for a DMA channel + * @chan: dma channel to initialize + */ +static inline void dma_cookie_init(struct dma_chan *chan) +{ + chan->cookie = DMA_MIN_COOKIE; + chan->completed_cookie = DMA_MIN_COOKIE; +} + +/** + * dma_cookie_assign - assign a DMA engine cookie to the descriptor + * @tx: descriptor needing cookie + * + * Assign a unique non-zero per-channel cookie to the descriptor. + * Note: caller is expected to hold a lock to prevent concurrency. + */ +static inline dma_cookie_t dma_cookie_assign(struct dma_async_tx_descriptor *tx) +{ + struct dma_chan *chan = tx->chan; + dma_cookie_t cookie; + + cookie = chan->cookie + 1; + if (cookie < DMA_MIN_COOKIE) + cookie = DMA_MIN_COOKIE; + tx->cookie = chan->cookie = cookie; + + return cookie; +} + +/** + * dma_cookie_complete - complete a descriptor + * @tx: descriptor to complete + * + * Mark this descriptor complete by updating the channels completed + * cookie marker. Zero the descriptors cookie to prevent accidental + * repeated completions. + * + * Note: caller is expected to hold a lock to prevent concurrency. + */ +static inline void dma_cookie_complete(struct dma_async_tx_descriptor *tx) +{ + BUG_ON(tx->cookie < DMA_MIN_COOKIE); + tx->chan->completed_cookie = tx->cookie; + tx->cookie = 0; +} + +/** + * dma_cookie_status - report cookie status + * @chan: dma channel + * @cookie: cookie we are interested in + * @state: dma_tx_state structure to return last/used cookies + * + * Report the status of the cookie, filling in the state structure if + * non-NULL. No locking is required. + */ +static inline enum dma_status dma_cookie_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *state) +{ + dma_cookie_t used, complete; + + used = chan->cookie; + complete = chan->completed_cookie; + barrier(); + if (state) { + state->last = complete; + state->used = used; + state->residue = 0; + } + return dma_async_is_complete(cookie, complete, used); +} + +static inline void dma_set_residue(struct dma_tx_state *state, u32 residue) +{ + if (state) + state->residue = residue; +} + +#endif diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h deleted file mode 100644 index c3419518..00000000 --- a/drivers/dma/dw_dmac_regs.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Driver for the Synopsys DesignWare AHB DMA Controller - * - * Copyright (C) 2005-2007 Atmel Corporation - * Copyright (C) 2010-2011 ST Microelectronics - * - * 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 - -#define DW_DMA_MAX_NR_CHANNELS 8 - -/* - * Redefine this macro to handle differences between 32- and 64-bit - * addressing, big vs. little endian, etc. - */ -#define DW_REG(name) u32 name; u32 __pad_##name - -/* Hardware register definitions. */ -struct dw_dma_chan_regs { - DW_REG(SAR); /* Source Address Register */ - DW_REG(DAR); /* Destination Address Register */ - DW_REG(LLP); /* Linked List Pointer */ - u32 CTL_LO; /* Control Register Low */ - u32 CTL_HI; /* Control Register High */ - DW_REG(SSTAT); - DW_REG(DSTAT); - DW_REG(SSTATAR); - DW_REG(DSTATAR); - u32 CFG_LO; /* Configuration Register Low */ - u32 CFG_HI; /* Configuration Register High */ - DW_REG(SGR); - DW_REG(DSR); -}; - -struct dw_dma_irq_regs { - DW_REG(XFER); - DW_REG(BLOCK); - DW_REG(SRC_TRAN); - DW_REG(DST_TRAN); - DW_REG(ERROR); -}; - -struct dw_dma_regs { - /* per-channel registers */ - struct dw_dma_chan_regs CHAN[DW_DMA_MAX_NR_CHANNELS]; - - /* irq handling */ - struct dw_dma_irq_regs RAW; /* r */ - struct dw_dma_irq_regs STATUS; /* r (raw & mask) */ - struct dw_dma_irq_regs MASK; /* rw (set = irq enabled) */ - struct dw_dma_irq_regs CLEAR; /* w (ack, affects "raw") */ - - DW_REG(STATUS_INT); /* r */ - - /* software handshaking */ - DW_REG(REQ_SRC); - DW_REG(REQ_DST); - DW_REG(SGL_REQ_SRC); - DW_REG(SGL_REQ_DST); - DW_REG(LAST_SRC); - DW_REG(LAST_DST); - - /* miscellaneous */ - DW_REG(CFG); - DW_REG(CH_EN); - DW_REG(ID); - DW_REG(TEST); - - /* optional encoded params, 0x3c8..0x3 */ -}; - -/* Bitfields in CTL_LO */ -#define DWC_CTLL_INT_EN (1 << 0) /* irqs enabled? */ -#define DWC_CTLL_DST_WIDTH(n) ((n)<<1) /* bytes per element */ -#define DWC_CTLL_SRC_WIDTH(n) ((n)<<4) -#define DWC_CTLL_DST_INC (0<<7) /* DAR update/not */ -#define DWC_CTLL_DST_DEC (1<<7) -#define DWC_CTLL_DST_FIX (2<<7) -#define DWC_CTLL_SRC_INC (0<<7) /* SAR update/not */ -#define DWC_CTLL_SRC_DEC (1<<9) -#define DWC_CTLL_SRC_FIX (2<<9) -#define DWC_CTLL_DST_MSIZE(n) ((n)<<11) /* burst, #elements */ -#define DWC_CTLL_SRC_MSIZE(n) ((n)<<14) -#define DWC_CTLL_S_GATH_EN (1 << 17) /* src gather, !FIX */ -#define DWC_CTLL_D_SCAT_EN (1 << 18) /* dst scatter, !FIX */ -#define DWC_CTLL_FC(n) ((n) << 20) -#define DWC_CTLL_FC_M2M (0 << 20) /* mem-to-mem */ -#define DWC_CTLL_FC_M2P (1 << 20) /* mem-to-periph */ -#define DWC_CTLL_FC_P2M (2 << 20) /* periph-to-mem */ -#define DWC_CTLL_FC_P2P (3 << 20) /* periph-to-periph */ -/* plus 4 transfer types for peripheral-as-flow-controller */ -#define DWC_CTLL_DMS(n) ((n)<<23) /* dst master select */ -#define DWC_CTLL_SMS(n) ((n)<<25) /* src master select */ -#define DWC_CTLL_LLP_D_EN (1 << 27) /* dest block chain */ -#define DWC_CTLL_LLP_S_EN (1 << 28) /* src block chain */ - -/* Bitfields in CTL_HI */ -#define DWC_CTLH_DONE 0x00001000 -#define DWC_CTLH_BLOCK_TS_MASK 0x00000fff - -/* Bitfields in CFG_LO. Platform-configurable bits are in */ -#define DWC_CFGL_CH_PRIOR_MASK (0x7 << 5) /* priority mask */ -#define DWC_CFGL_CH_PRIOR(x) ((x) << 5) /* priority */ -#define DWC_CFGL_CH_SUSP (1 << 8) /* pause xfer */ -#define DWC_CFGL_FIFO_EMPTY (1 << 9) /* pause xfer */ -#define DWC_CFGL_HS_DST (1 << 10) /* handshake w/dst */ -#define DWC_CFGL_HS_SRC (1 << 11) /* handshake w/src */ -#define DWC_CFGL_MAX_BURST(x) ((x) << 20) -#define DWC_CFGL_RELOAD_SAR (1 << 30) -#define DWC_CFGL_RELOAD_DAR (1 << 31) - -/* Bitfields in CFG_HI. Platform-configurable bits are in */ -#define DWC_CFGH_DS_UPD_EN (1 << 5) -#define DWC_CFGH_SS_UPD_EN (1 << 6) - -/* Bitfields in SGR */ -#define DWC_SGR_SGI(x) ((x) << 0) -#define DWC_SGR_SGC(x) ((x) << 20) - -/* Bitfields in DSR */ -#define DWC_DSR_DSI(x) ((x) << 0) -#define DWC_DSR_DSC(x) ((x) << 20) - -/* Bitfields in CFG */ -#define DW_CFG_DMA_EN (1 << 0) - -#define DW_REGLEN 0x400 - -enum dw_dmac_flags { - DW_DMA_IS_CYCLIC = 0, -}; - -struct dw_dma_chan { - struct dma_chan chan; - void __iomem *ch_regs; - u8 mask; - u8 priority; - bool paused; - - spinlock_t lock; - - /* these other elements are all protected by lock */ - unsigned long flags; - dma_cookie_t completed; - struct list_head active_list; - struct list_head queue; - struct list_head free_list; - struct dw_cyclic_desc *cdesc; - - unsigned int descs_allocated; -}; - -static inline struct dw_dma_chan_regs __iomem * -__dwc_regs(struct dw_dma_chan *dwc) -{ - return dwc->ch_regs; -} - -#define channel_readl(dwc, name) \ - readl(&(__dwc_regs(dwc)->name)) -#define channel_writel(dwc, name, val) \ - writel((val), &(__dwc_regs(dwc)->name)) - -static inline struct dw_dma_chan *to_dw_dma_chan(struct dma_chan *chan) -{ - return container_of(chan, struct dw_dma_chan, chan); -} - -struct dw_dma { - struct dma_device dma; - void __iomem *regs; - struct tasklet_struct tasklet; - struct clk *clk; - - u8 all_chan_mask; - - struct dw_dma_chan chan[0]; -}; - -static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw) -{ - return dw->regs; -} - -#define dma_readl(dw, name) \ - readl(&(__dw_regs(dw)->name)) -#define dma_writel(dw, name, val) \ - writel((val), &(__dw_regs(dw)->name)) - -#define channel_set_bit(dw, reg, mask) \ - dma_writel(dw, reg, ((mask) << 8) | (mask)) -#define channel_clear_bit(dw, reg, mask) \ - dma_writel(dw, reg, ((mask) << 8) | 0) - -static inline struct dw_dma *to_dw_dma(struct dma_device *ddev) -{ - return container_of(ddev, struct dw_dma, dma); -} - -/* LLI == Linked List Item; a.k.a. DMA block descriptor */ -struct dw_lli { - /* values that are not changed by hardware */ - dma_addr_t sar; - dma_addr_t dar; - dma_addr_t llp; /* chain to next lli */ - u32 ctllo; - /* values that may get written back: */ - u32 ctlhi; - /* sstat and dstat can snapshot peripheral register state. - * silicon config may discard either or both... - */ - u32 sstat; - u32 dstat; -}; - -struct dw_desc { - /* FIRST values the hardware uses */ - struct dw_lli lli; - - /* THEN values for driver housekeeping */ - struct list_head desc_node; - struct list_head tx_list; - struct dma_async_tx_descriptor txd; - size_t len; -}; - -static inline struct dw_desc * -txd_to_dw_desc(struct dma_async_tx_descriptor *txd) -{ - return container_of(txd, struct dw_desc, txd); -} diff --git a/drivers/dma/fh_dmac.c b/drivers/dma/fh_dmac.c new file mode 100644 index 00000000..314b33d6 --- /dev/null +++ b/drivers/dma/fh_dmac.c @@ -0,0 +1,1846 @@ +/* + * Core driver for the Synopsys DesignWare DMA Controller + * + * Copyright (C) 2007-2008 Atmel Corporation + * Copyright (C) 2010-2011 ST Microelectronics + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dmaengine.h" +#include + +/* + * This supports the Synopsys "DesignWare AHB Central DMA Controller", + * (FH_ahb_dmac) which is used with various AMBA 2.0 systems (not all + * of which use ARM any more). See the "Databook" from Synopsys for + * information beyond what licensees probably provide. + * + * The driver has currently been tested only with the Atmel AT32AP7000, + * which does not support descriptor writeback. + */ + +static inline unsigned int fhc_get_dms(struct fh_dma_slave *slave) +{ + return slave ? slave->dst_master : 0; +} + +static inline unsigned int fhc_get_sms(struct fh_dma_slave *slave) +{ + return slave ? slave->src_master : 1; +} + +static inline void fhc_set_masters(struct fh_dma_chan *fhc) +{ + struct fh_dma *fhd = to_fh_dma(fhc->chan.device); + struct fh_dma_slave *dms = fhc->chan.private; + unsigned char mmax = fhd->nr_masters - 1; + + if (fhc->request_line == ~0) { + fhc->src_master = min_t(unsigned char, mmax, fhc_get_sms(dms)); + fhc->dst_master = min_t(unsigned char, mmax, fhc_get_dms(dms)); + } +} + +#define FHC_DEFAULT_CTLLO(_chan) ({ \ + struct fh_dma_chan *_fhc = to_fh_dma_chan(_chan); \ + struct dma_slave_config *_sconfig = &_fhc->dma_sconfig; \ + bool _is_slave = is_slave_direction(_fhc->direction); \ + u8 _smsize = _is_slave ? _sconfig->src_maxburst : \ + FH_DMA_MSIZE_16; \ + u8 _dmsize = _is_slave ? _sconfig->dst_maxburst : \ + FH_DMA_MSIZE_16; \ + \ + (FHC_CTLL_DST_MSIZE(_dmsize) \ + | FHC_CTLL_SRC_MSIZE(_smsize) \ + | FHC_CTLL_LLP_D_EN \ + | FHC_CTLL_LLP_S_EN \ + | FHC_CTLL_DMS(_fhc->dst_master) \ + | FHC_CTLL_SMS(_fhc->src_master)); \ + }) + +#define FHC_DEFAULT_CTLLO_OLD(private) ({ \ + struct fh_dma_slave *__slave = (private); \ + int dms = __slave ? __slave->dst_master : 0; \ + int sms = __slave ? __slave->src_master : 1; \ + u8 smsize = __slave ? __slave->src_msize : FH_DMA_MSIZE_16; \ + u8 dmsize = __slave ? __slave->dst_msize : FH_DMA_MSIZE_16; \ + \ + (FHC_CTLL_DST_MSIZE(dmsize) \ + | FHC_CTLL_SRC_MSIZE(smsize) \ + | FHC_CTLL_LLP_D_EN \ + | FHC_CTLL_LLP_S_EN \ + | FHC_CTLL_DMS(dms) \ + | FHC_CTLL_SMS(sms)); \ + }) + +/* + * Number of descriptors to allocate for each channel. This should be + * made configurable somehow; preferably, the clients (at least the + * ones using slave transfers) should be able to give us a hint. + */ +#define NR_DESCS_PER_CHANNEL 4096 + +/*----------------------------------------------------------------------*/ + +static struct device *chan2dev(struct dma_chan *chan) +{ + return &chan->dev->device; +} +static struct device *chan2parent(struct dma_chan *chan) +{ + return chan->dev->device.parent; +} + +static struct fh_desc *fhc_first_active(struct fh_dma_chan *fhc) +{ + return to_fh_desc(fhc->active_list.next); +} + +static struct fh_desc *fhc_desc_get(struct fh_dma_chan *fhc) +{ + struct fh_desc *desc, *_desc; + struct fh_desc *ret = NULL; + unsigned int i = 0; + unsigned long flags; + + spin_lock_irqsave(&fhc->lock, flags); + list_for_each_entry_safe(desc, _desc, &fhc->free_list, desc_node) { + i++; + if (async_tx_test_ack(&desc->txd)) { + list_del(&desc->desc_node); + ret = desc; + break; + } + dev_dbg(chan2dev(&fhc->chan), "desc %p not ACKed\n", desc); + } + spin_unlock_irqrestore(&fhc->lock, flags); + + dev_vdbg(chan2dev(&fhc->chan), "scanned %u descriptors on freelist\n", i); + + return ret; +} + +/* + * Move a descriptor, including any children, to the free list. + * `desc' must not be on any lists. + */ +static void fhc_desc_put(struct fh_dma_chan *fhc, struct fh_desc *desc) +{ + unsigned long flags; + + if (desc) { + struct fh_desc *child; + + spin_lock_irqsave(&fhc->lock, flags); + list_for_each_entry(child, &desc->tx_list, desc_node) + dev_vdbg(chan2dev(&fhc->chan), + "moving child desc %p to freelist\n", + child); + list_splice_init(&desc->tx_list, &fhc->free_list); + dev_vdbg(chan2dev(&fhc->chan), "moving desc %p to freelist\n", desc); + list_add(&desc->desc_node, &fhc->free_list); + spin_unlock_irqrestore(&fhc->lock, flags); + } +} + +static void fhc_initialize(struct fh_dma_chan *fhc) +{ + struct fh_dma *fhd = to_fh_dma(fhc->chan.device); + struct fh_dma_slave *dms = fhc->chan.private; + u32 cfghi = FHC_CFGH_FIFO_MODE; + u32 cfglo = FHC_CFGL_CH_PRIOR(fhc->priority); + + if (fhc->initialized == true) + return; + + if (dms) { + cfghi = dms->cfg_hi; + cfglo |= dms->cfg_lo & ~FHC_CFGL_CH_PRIOR_MASK; + } else { + if (fhc->direction == DMA_MEM_TO_DEV) + cfghi = FHC_CFGH_DST_PER(fhc->request_line); + else if (fhc->direction == DMA_DEV_TO_MEM) + cfghi = FHC_CFGH_SRC_PER(fhc->request_line); + } + + channel_writel(fhc, CFG_LO, cfglo); + channel_writel(fhc, CFG_HI, cfghi); + + /* Enable interrupts */ + channel_set_bit(fhd, MASK.XFER, fhc->mask); + channel_set_bit(fhd, MASK.BLOCK, fhc->mask); + channel_set_bit(fhd, MASK.ERROR, fhc->mask); + + fhc->initialized = true; +} + +/*----------------------------------------------------------------------*/ + +static inline unsigned int fhc_fast_fls(unsigned long long v) +{ + /* + * We can be a lot more clever here, but this should take care + * of the most common optimization. + */ + if (!(v & 7)) + return 3; + else if (!(v & 3)) + return 2; + else if (!(v & 1)) + return 1; + return 0; +} + +static inline void fhc_dump_chan_regs(struct fh_dma_chan *fhc) +{ + dev_err(chan2dev(&fhc->chan), + " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n", + channel_readl(fhc, SAR), + channel_readl(fhc, DAR), + channel_readl(fhc, LLP), + channel_readl(fhc, CTL_HI), + channel_readl(fhc, CTL_LO)); +} + +static inline void fhc_chan_disable(struct fh_dma *fhd, struct fh_dma_chan *fhc) +{ + channel_clear_bit(fhd, CH_EN, fhc->mask); + while (dma_readl(fhd, CH_EN) & fhc->mask) + cpu_relax(); +} + +/*----------------------------------------------------------------------*/ + +/* Perform single block transfer */ +static inline void fhc_do_single_block(struct fh_dma_chan *fhc, + struct fh_desc *desc) +{ + struct fh_dma *fhd = to_fh_dma(fhc->chan.device); + u32 ctllo; + + /* Software emulation of LLP mode relies on interrupts to continue + * multi block transfer. */ + ctllo = desc->lli.ctllo | FHC_CTLL_INT_EN; + + channel_writel(fhc, SAR, desc->lli.sar); + channel_writel(fhc, DAR, desc->lli.dar); + channel_writel(fhc, CTL_LO, ctllo); + channel_writel(fhc, CTL_HI, desc->lli.ctlhi); + channel_set_bit(fhd, CH_EN, fhc->mask); + + /* Move pointer to next descriptor */ + fhc->tx_node_active = fhc->tx_node_active->next; +} + +/* Called with fhc->lock held and bh disabled */ +static void fhc_dostart(struct fh_dma_chan *fhc, struct fh_desc *first) +{ + struct fh_dma *fhd = to_fh_dma(fhc->chan.device); + unsigned long was_soft_llp; + + /* ASSERT: channel is idle */ + if (dma_readl(fhd, CH_EN) & fhc->mask) { + dev_err(chan2dev(&fhc->chan), + "BUG: Attempted to start non-idle channel\n"); + fhc_dump_chan_regs(fhc); + + /* The tasklet will hopefully advance the queue... */ + return; + } + + if (fhc->nollp) { + was_soft_llp = test_and_set_bit(FH_DMA_IS_SOFT_LLP, + &fhc->flags); + if (was_soft_llp) { + dev_err(chan2dev(&fhc->chan), + "BUG: Attempted to start new LLP transfer " + "inside ongoing one\n"); + return; + } + + fhc_initialize(fhc); + + fhc->residue = first->total_len; + fhc->tx_node_active = &first->tx_list; + + /* Submit first block */ + fhc_do_single_block(fhc, first); + + return; + } + + fhc_initialize(fhc); + + channel_writel(fhc, LLP, first->txd.phys); + channel_writel(fhc, CTL_LO, + FHC_CTLL_LLP_D_EN | FHC_CTLL_LLP_S_EN); + channel_writel(fhc, CTL_HI, 0); + channel_set_bit(fhd, CH_EN, fhc->mask); +} + +/*----------------------------------------------------------------------*/ + +static void +fhc_descriptor_complete(struct fh_dma_chan *fhc, struct fh_desc *desc, + bool callback_required) +{ + dma_async_tx_callback callback = NULL; + void *param = NULL; + struct dma_async_tx_descriptor *txd = &desc->txd; + struct fh_desc *child; + unsigned long flags; + + dev_vdbg(chan2dev(&fhc->chan), "descriptor %u complete\n", txd->cookie); + + spin_lock_irqsave(&fhc->lock, flags); + dma_cookie_complete(txd); + if (callback_required) { + callback = txd->callback; + param = txd->callback_param; + } + + /* async_tx_ack */ + list_for_each_entry(child, &desc->tx_list, desc_node) + async_tx_ack(&child->txd); + async_tx_ack(&desc->txd); + + list_splice_init(&desc->tx_list, &fhc->free_list); + list_move(&desc->desc_node, &fhc->free_list); + + if (!is_slave_direction(fhc->direction)) { + struct device *parent = chan2parent(&fhc->chan); + if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) { + if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE) + dma_unmap_single(parent, desc->lli.dar, + desc->total_len, DMA_FROM_DEVICE); + else + dma_unmap_page(parent, desc->lli.dar, + desc->total_len, DMA_FROM_DEVICE); + } + if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) { + if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE) + dma_unmap_single(parent, desc->lli.sar, + desc->total_len, DMA_TO_DEVICE); + else + dma_unmap_page(parent, desc->lli.sar, + desc->total_len, DMA_TO_DEVICE); + } + } + + spin_unlock_irqrestore(&fhc->lock, flags); + + if (callback) + callback(param); +} + +static void fhc_complete_all(struct fh_dma *fhd, struct fh_dma_chan *fhc) +{ + struct fh_desc *desc, *_desc; + LIST_HEAD(list); + unsigned long flags; + + spin_lock_irqsave(&fhc->lock, flags); + if (dma_readl(fhd, CH_EN) & fhc->mask) { + dev_err(chan2dev(&fhc->chan), + "BUG: XFER bit set, but channel not idle!\n"); + + /* Try to continue after resetting the channel... */ + fhc_chan_disable(fhd, fhc); + } + + /* + * Submit queued descriptors ASAP, i.e. before we go through + * the completed ones. + */ + list_splice_init(&fhc->active_list, &list); + if (!list_empty(&fhc->queue)) { + list_move(fhc->queue.next, &fhc->active_list); + fhc_dostart(fhc, fhc_first_active(fhc)); + } + + spin_unlock_irqrestore(&fhc->lock, flags); + + list_for_each_entry_safe(desc, _desc, &list, desc_node) + fhc_descriptor_complete(fhc, desc, true); +} + +/* Returns how many bytes were already received from source */ +static inline u32 fhc_get_sent(struct fh_dma_chan *fhc) +{ + u32 ctlhi = channel_readl(fhc, CTL_HI); + u32 ctllo = channel_readl(fhc, CTL_LO); + + return (ctlhi & FHC_CTLH_BLOCK_TS_MASK) * (1 << (ctllo >> 4 & 7)); +} + +static void fhc_scan_descriptors(struct fh_dma *fhd, struct fh_dma_chan *fhc) +{ + dma_addr_t llp; + struct fh_desc *desc, *_desc; + struct fh_desc *child; + u32 status_xfer; + unsigned long flags; + + spin_lock_irqsave(&fhc->lock, flags); + /* + * Clear block interrupt flag before scanning so that we don't + * miss any, and read LLP before RAW_XFER to ensure it is + * valid if we decide to scan the list. + */ + dma_writel(fhd, CLEAR.BLOCK, fhc->mask); + llp = channel_readl(fhc, LLP); + status_xfer = dma_readl(fhd, RAW.XFER); + + if (status_xfer & fhc->mask) { + /* Everything we've submitted is done */ + dma_writel(fhd, CLEAR.XFER, fhc->mask); + if (test_bit(FH_DMA_IS_SOFT_LLP, &fhc->flags)) { + struct list_head *head, *active = fhc->tx_node_active; + + /* + * We are inside first active descriptor. + * Otherwise something is really wrong. + */ + desc = fhc_first_active(fhc); + + head = &desc->tx_list; + if (active != head) { + /* Update desc to reflect last sent one */ + if (active != head->next) + desc = to_fh_desc(active->prev); + + fhc->residue -= desc->len; + + child = to_fh_desc(active); + + /* Submit next block */ + fhc_do_single_block(fhc, child); + + spin_unlock_irqrestore(&fhc->lock, flags); + return; + } + + /* We are done here */ + clear_bit(FH_DMA_IS_SOFT_LLP, &fhc->flags); + } + fhc->residue = 0; + + spin_unlock_irqrestore(&fhc->lock, flags); + + fhc_complete_all(fhd, fhc); + return; + } + + if (list_empty(&fhc->active_list)) { + fhc->residue = 0; + spin_unlock_irqrestore(&fhc->lock, flags); + return; + } + + if (test_bit(FH_DMA_IS_SOFT_LLP, &fhc->flags)) { + dev_vdbg(chan2dev(&fhc->chan), "%s: soft LLP mode\n", __func__); + spin_unlock_irqrestore(&fhc->lock, flags); + return; + } + + dev_vdbg(chan2dev(&fhc->chan), "%s: llp=0x%llx\n", __func__, + (unsigned long long)llp); + + list_for_each_entry_safe(desc, _desc, &fhc->active_list, desc_node) { + /* Initial residue value */ + fhc->residue = desc->total_len; + + /* Check first descriptors addr */ + if (desc->txd.phys == llp) { + spin_unlock_irqrestore(&fhc->lock, flags); + return; + } + + /* Check first descriptors llp */ + if (desc->lli.llp == llp) { + /* This one is currently in progress */ + fhc->residue -= fhc_get_sent(fhc); + spin_unlock_irqrestore(&fhc->lock, flags); + return; + } + + fhc->residue -= desc->len; + list_for_each_entry(child, &desc->tx_list, desc_node) { + if (child->lli.llp == llp) { + /* Currently in progress */ + fhc->residue -= fhc_get_sent(fhc); + spin_unlock_irqrestore(&fhc->lock, flags); + return; + } + fhc->residue -= child->len; + } + + /* + * No descriptors so far seem to be in progress, i.e. + * this one must be done. + */ + spin_unlock_irqrestore(&fhc->lock, flags); + fhc_descriptor_complete(fhc, desc, true); + spin_lock_irqsave(&fhc->lock, flags); + } + + dev_err(chan2dev(&fhc->chan), + "BUG: All descriptors done, but channel not idle!\n"); + + /* Try to continue after resetting the channel... */ + fhc_chan_disable(fhd, fhc); + + if (!list_empty(&fhc->queue)) { + list_move(fhc->queue.next, &fhc->active_list); + fhc_dostart(fhc, fhc_first_active(fhc)); + } + spin_unlock_irqrestore(&fhc->lock, flags); +} + +static inline void fhc_dump_lli(struct fh_dma_chan *fhc, struct fh_lli *lli) +{ + dev_crit(chan2dev(&fhc->chan), " desc: s0x%x d0x%x l0x%x c0x%x:%x\n", + lli->sar, lli->dar, lli->llp, lli->ctlhi, lli->ctllo); + +} + +static void fhc_handle_error(struct fh_dma *fhd, struct fh_dma_chan *fhc) +{ + struct fh_desc *bad_desc; + struct fh_desc *child; + unsigned long flags; + + fhc_scan_descriptors(fhd, fhc); + + spin_lock_irqsave(&fhc->lock, flags); + + /* + * The descriptor currently at the head of the active list is + * borked. Since we don't have any way to report errors, we'll + * just have to scream loudly and try to carry on. + */ + bad_desc = fhc_first_active(fhc); + list_del_init(&bad_desc->desc_node); + list_move(fhc->queue.next, fhc->active_list.prev); + + /* Clear the error flag and try to restart the controller */ + dma_writel(fhd, CLEAR.ERROR, fhc->mask); + if (!list_empty(&fhc->active_list)) + fhc_dostart(fhc, fhc_first_active(fhc)); + + /* + * WARN may seem harsh, but since this only happens + * when someone submits a bad physical address in a + * descriptor, we should consider ourselves lucky that the + * controller flagged an error instead of scribbling over + * random memory locations. + */ + dev_WARN(chan2dev(&fhc->chan), "Bad descriptor submitted for DMA!\n" + " cookie: %d\n", bad_desc->txd.cookie); + fhc_dump_lli(fhc, &bad_desc->lli); + list_for_each_entry(child, &bad_desc->tx_list, desc_node) + fhc_dump_lli(fhc, &child->lli); + + spin_unlock_irqrestore(&fhc->lock, flags); + + /* Pretend the descriptor completed successfully */ + fhc_descriptor_complete(fhc, bad_desc, true); +} + +/* --------------------- Cyclic DMA API extensions -------------------- */ + +inline dma_addr_t fh_dma_get_src_addr(struct dma_chan *chan) +{ + struct fh_dma_chan *fhc = to_fh_dma_chan(chan); + return channel_readl(fhc, SAR); +} +EXPORT_SYMBOL(fh_dma_get_src_addr); + +inline dma_addr_t fh_dma_get_dst_addr(struct dma_chan *chan) +{ + struct fh_dma_chan *fhc = to_fh_dma_chan(chan); + return channel_readl(fhc, DAR); +} +EXPORT_SYMBOL(fh_dma_get_dst_addr); + +/* Called with fhc->lock held and all DMAC interrupts disabled */ +static void fhc_handle_cyclic(struct fh_dma *fhd, struct fh_dma_chan *fhc, + u32 status_err, u32 status_xfer, u32 status_block) +{ + unsigned long flags; + + if (status_block & fhc->mask) { + void (*callback) (void *param); + void *callback_param; + + dev_vdbg(chan2dev(&fhc->chan), "new cyclic period llp 0x%08x\n", + channel_readl(fhc, LLP)); + dma_writel(fhd, CLEAR.BLOCK, fhc->mask); + + callback = fhc->cdesc->period_callback; + callback_param = fhc->cdesc->period_callback_param; + + if (callback) + callback(callback_param); + } + + /* + * Error and transfer complete are highly unlikely, and will most + * likely be due to a configuration error by the user. + */ + if (unlikely(status_err & fhc->mask) || + unlikely(status_xfer & fhc->mask)) { + int i; + + dev_err(chan2dev(&fhc->chan), "cyclic DMA unexpected %s " + "interrupt, stopping DMA transfer\n", + status_xfer ? "xfer" : "error"); + + spin_lock_irqsave(&fhc->lock, flags); + + fhc_dump_chan_regs(fhc); + + fhc_chan_disable(fhd, fhc); + + /* Make sure DMA does not restart by loading a new list */ + channel_writel(fhc, LLP, 0); + channel_writel(fhc, CTL_LO, 0); + channel_writel(fhc, CTL_HI, 0); + + dma_writel(fhd, CLEAR.ERROR, fhc->mask); + dma_writel(fhd, CLEAR.XFER, fhc->mask); + dma_writel(fhd, CLEAR.BLOCK, fhc->mask); + + for (i = 0; i < fhc->cdesc->periods; i++) + fhc_dump_lli(fhc, &fhc->cdesc->desc[i]->lli); + + spin_unlock_irqrestore(&fhc->lock, flags); + } +} + +/* ------------------------------------------------------------------------- */ + +static void fh_dma_tasklet(unsigned long data) +{ + struct fh_dma *fhd = (struct fh_dma *)data; + struct fh_dma_chan *fhc; + u32 status_xfer; + u32 status_err; + u32 status_block; + int i; + + status_xfer = dma_readl(fhd, RAW.XFER); + status_block = dma_readl(fhd, RAW.BLOCK); + status_err = dma_readl(fhd, RAW.ERROR); + + dev_vdbg(fhd->dma.dev, "%s: status_err=%x\n", __func__, status_err); + + for (i = 0; i < fhd->dma.chancnt; i++) { + fhc = &fhd->chan[i]; + if (test_bit(FH_DMA_IS_CYCLIC, &fhc->flags)) + fhc_handle_cyclic(fhd, fhc, status_err, + status_xfer, status_block); + else if (status_err & (1 << i)) + fhc_handle_error(fhd, fhc); + else if (status_xfer & (1 << i)) + fhc_scan_descriptors(fhd, fhc); + } + + /* + * Re-enable interrupts. + */ + channel_set_bit(fhd, MASK.XFER, fhd->all_chan_mask); + channel_set_bit(fhd, MASK.BLOCK, fhd->all_chan_mask); + channel_set_bit(fhd, MASK.ERROR, fhd->all_chan_mask); +} + +static irqreturn_t fh_dma_interrupt(int irq, void *dev_id) +{ + struct fh_dma *fhd = dev_id; + u32 status; + + dev_vdbg(fhd->dma.dev, "%s: status=0x%x\n", __func__, + dma_readl(fhd, STATUS_INT)); + + /* + * Just disable the interrupts. We'll turn them back on in the + * softirq handler. + */ + channel_clear_bit(fhd, MASK.XFER, fhd->all_chan_mask); + channel_clear_bit(fhd, MASK.BLOCK, fhd->all_chan_mask); + channel_clear_bit(fhd, MASK.ERROR, fhd->all_chan_mask); + + status = dma_readl(fhd, STATUS_INT); + if (status) { + dev_err(fhd->dma.dev, + "BUG: Unexpected interrupts pending: 0x%x\n", + status); + + /* Try to recover */ + channel_clear_bit(fhd, MASK.XFER, (1 << 8) - 1); + channel_clear_bit(fhd, MASK.BLOCK, (1 << 8) - 1); + channel_clear_bit(fhd, MASK.SRC_TRAN, (1 << 8) - 1); + channel_clear_bit(fhd, MASK.DST_TRAN, (1 << 8) - 1); + channel_clear_bit(fhd, MASK.ERROR, (1 << 8) - 1); + } + + tasklet_schedule(&fhd->tasklet); + + return IRQ_HANDLED; +} + +/*----------------------------------------------------------------------*/ + +static dma_cookie_t fhc_tx_submit(struct dma_async_tx_descriptor *tx) +{ + struct fh_desc *desc = txd_to_fh_desc(tx); + struct fh_dma_chan *fhc = to_fh_dma_chan(tx->chan); + dma_cookie_t cookie; + unsigned long flags; + + spin_lock_irqsave(&fhc->lock, flags); + cookie = dma_cookie_assign(tx); + + /* + * REVISIT: We should attempt to chain as many descriptors as + * possible, perhaps even appending to those already submitted + * for DMA. But this is hard to do in a race-free manner. + */ + if (list_empty(&fhc->active_list)) { + dev_vdbg(chan2dev(tx->chan), "%s: started %u\n", __func__, + desc->txd.cookie); + list_add_tail(&desc->desc_node, &fhc->active_list); + fhc_dostart(fhc, fhc_first_active(fhc)); + } else { + dev_vdbg(chan2dev(tx->chan), "%s: queued %u\n", __func__, + desc->txd.cookie); + + list_add_tail(&desc->desc_node, &fhc->queue); + } + + spin_unlock_irqrestore(&fhc->lock, flags); + + return cookie; +} + +static struct dma_async_tx_descriptor * +fhc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, + size_t len, unsigned long flags) +{ + struct fh_dma_chan *fhc = to_fh_dma_chan(chan); + struct fh_dma *fhd = to_fh_dma(chan->device); + struct fh_desc *desc; + struct fh_desc *first; + struct fh_desc *prev; + size_t xfer_count; + size_t offset; + unsigned int src_width; + unsigned int dst_width; + unsigned int data_width; + u32 ctllo; + + dev_vdbg(chan2dev(chan), + "%s: d0x%llx s0x%llx l0x%zx f0x%lx\n", __func__, + (unsigned long long)dest, (unsigned long long)src, + len, flags); + + if (unlikely(!len)) { + dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__); + return NULL; + } + + fhc->direction = DMA_MEM_TO_MEM; + + data_width = min_t(unsigned int, fhd->data_width[fhc->src_master], + fhd->data_width[fhc->dst_master]); + + src_width = dst_width = min_t(unsigned int, data_width, + fhc_fast_fls(src | dest | len)); + + ctllo = FHC_DEFAULT_CTLLO(chan) + | FHC_CTLL_DST_WIDTH(dst_width) + | FHC_CTLL_SRC_WIDTH(src_width) + | FHC_CTLL_DST_INC + | FHC_CTLL_SRC_INC + | FHC_CTLL_FC_M2M; + prev = first = NULL; + + for (offset = 0; offset < len; offset += xfer_count << src_width) { + xfer_count = min_t(size_t, (len - offset) >> src_width, + fhc->block_size); + + desc = fhc_desc_get(fhc); + if (!desc) + goto err_desc_get; + + desc->lli.sar = src + offset; + desc->lli.dar = dest + offset; + desc->lli.ctllo = ctllo; + desc->lli.ctlhi = xfer_count; + desc->len = xfer_count << src_width; + + if (!first) { + first = desc; + } else { + prev->lli.llp = desc->txd.phys; + list_add_tail(&desc->desc_node, + &first->tx_list); + } + prev = desc; + } + + if (flags & DMA_PREP_INTERRUPT) + /* Trigger interrupt after last block */ + prev->lli.ctllo |= FHC_CTLL_INT_EN; + + prev->lli.llp = 0; + first->txd.flags = flags; + first->total_len = len; + + return &first->txd; + +err_desc_get: + fhc_desc_put(fhc, first); + return NULL; +} + +static struct dma_async_tx_descriptor * +fhc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sg_len, enum dma_transfer_direction direction, + unsigned long flags, void *context) +{ + struct fh_dma_chan *fhc = to_fh_dma_chan(chan); + struct fh_dma *fhd = to_fh_dma(chan->device); + struct dma_slave_config *sconfig = &fhc->dma_sconfig; + struct fh_desc *prev; + struct fh_desc *first; + u32 ctllo; + dma_addr_t reg; + unsigned int reg_width; + unsigned int mem_width; + unsigned int data_width; + unsigned int i; + struct scatterlist *sg; + size_t total_len = 0; + struct fh_dma_pri *fh_pri = (struct fh_dma_pri *)context; + dev_vdbg(chan2dev(chan), "%s\n", __func__); + + if (unlikely(!is_slave_direction(direction) || !sg_len)) + return NULL; + + fhc->direction = direction; + + prev = first = NULL; + + switch (direction) { + case DMA_MEM_TO_DEV: + reg_width = __fls(sconfig->dst_addr_width); + reg = sconfig->dst_addr; + if(!fh_pri){ + ctllo = (FHC_DEFAULT_CTLLO(chan) + | FHC_CTLL_DST_WIDTH(reg_width) + | FHC_CTLL_DST_FIX + | FHC_CTLL_SRC_INC); + } + else{ + ctllo = (FHC_DEFAULT_CTLLO(chan) | FHC_CTLL_DST_WIDTH(reg_width)); + ctllo |= fh_pri->sinc << 9; + ctllo |= fh_pri->dinc << 7; + } + + ctllo |= sconfig->device_fc ? FHC_CTLL_FC(FH_DMA_FC_P_M2P) : + FHC_CTLL_FC(FH_DMA_FC_D_M2P); + + data_width = fhd->data_width[fhc->src_master]; + + for_each_sg(sgl, sg, sg_len, i) { + struct fh_desc *desc; + u32 len, dlen, mem; + + mem = sg_dma_address(sg); + len = sg_dma_len(sg); + + mem_width = min_t(unsigned int, + data_width, fhc_fast_fls(mem | len)); + +slave_sg_todev_fill_desc: + desc = fhc_desc_get(fhc); + if (!desc) { + dev_err(chan2dev(chan), + "not enough descriptors available\n"); + goto err_desc_get; + } + + desc->lli.sar = mem; + desc->lli.dar = reg; + desc->lli.ctllo = ctllo | FHC_CTLL_SRC_WIDTH(mem_width); + if ((len >> mem_width) > fhc->block_size) { + dlen = fhc->block_size << mem_width; + mem += dlen; + len -= dlen; + } else { + dlen = len; + len = 0; + } + + desc->lli.ctlhi = dlen >> mem_width; + desc->len = dlen; + + if (!first) { + first = desc; + } else { + prev->lli.llp = desc->txd.phys; + list_add_tail(&desc->desc_node, + &first->tx_list); + } + prev = desc; + total_len += dlen; + + if (len) + goto slave_sg_todev_fill_desc; + } + break; + case DMA_DEV_TO_MEM: + reg_width = __fls(sconfig->src_addr_width); + reg = sconfig->src_addr; + + if(!fh_pri){ + ctllo = (FHC_DEFAULT_CTLLO(chan) + | FHC_CTLL_SRC_WIDTH(reg_width) + | FHC_CTLL_DST_INC + | FHC_CTLL_SRC_FIX); + } + else{ + ctllo = (FHC_DEFAULT_CTLLO(chan) | FHC_CTLL_SRC_WIDTH(reg_width)); + ctllo |= fh_pri->sinc << 9; + ctllo |= fh_pri->dinc << 7; + } + + + ctllo |= sconfig->device_fc ? FHC_CTLL_FC(FH_DMA_FC_P_P2M) : + FHC_CTLL_FC(FH_DMA_FC_D_P2M); + + data_width = fhd->data_width[fhc->dst_master]; + + for_each_sg(sgl, sg, sg_len, i) { + struct fh_desc *desc; + u32 len, dlen, mem; + + mem = sg_dma_address(sg); + len = sg_dma_len(sg); + + mem_width = min_t(unsigned int, + data_width, fhc_fast_fls(mem | len)); + +slave_sg_fromdev_fill_desc: + desc = fhc_desc_get(fhc); + if (!desc) { + dev_err(chan2dev(chan), + "not enough descriptors available\n"); + goto err_desc_get; + } + + desc->lli.sar = reg; + desc->lli.dar = mem; + desc->lli.ctllo = ctllo | FHC_CTLL_DST_WIDTH(mem_width); + if ((len >> reg_width) > fhc->block_size) { + dlen = fhc->block_size << reg_width; + mem += dlen; + len -= dlen; + } else { + dlen = len; + len = 0; + } + desc->lli.ctlhi = dlen >> reg_width; + desc->len = dlen; + + if (!first) { + first = desc; + } else { + prev->lli.llp = desc->txd.phys; + list_add_tail(&desc->desc_node, + &first->tx_list); + } + prev = desc; + total_len += dlen; + + if (len) + goto slave_sg_fromdev_fill_desc; + } + break; + default: + return NULL; + } + + if (flags & DMA_PREP_INTERRUPT) + /* Trigger interrupt after last block */ + prev->lli.ctllo |= FHC_CTLL_INT_EN; + + prev->lli.llp = 0; + first->total_len = total_len; + + return &first->txd; + +err_desc_get: + fhc_desc_put(fhc, first); + return NULL; +} + +/* + * Fix sconfig's burst size according to fh_dmac. We need to convert them as: + * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. + * + * NOTE: burst size 2 is not supported by controller. + * + * This can be done by finding least significant bit set: n & (n - 1) + */ +static inline void convert_burst(u32 *maxburst) +{ + if (*maxburst > 1) + *maxburst = fls(*maxburst) - 2; + else + *maxburst = 0; +} + +static int +set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig) +{ + struct fh_dma_chan *fhc = to_fh_dma_chan(chan); + + /* Check if chan will be configured for slave transfers */ + if (!is_slave_direction(sconfig->direction)) + return -EINVAL; + + memcpy(&fhc->dma_sconfig, sconfig, sizeof(*sconfig)); + fhc->direction = sconfig->direction; + + /* Take the request line from slave_id member */ + if (fhc->request_line == ~0) + fhc->request_line = sconfig->slave_id; + + convert_burst(&fhc->dma_sconfig.src_maxburst); + convert_burst(&fhc->dma_sconfig.dst_maxburst); + + return 0; +} + +static inline void fhc_chan_pause(struct fh_dma_chan *fhc) +{ + u32 cfglo = channel_readl(fhc, CFG_LO); + unsigned int count = 20; /* timeout iterations */ + + channel_writel(fhc, CFG_LO, cfglo | FHC_CFGL_CH_SUSP); + while (!(channel_readl(fhc, CFG_LO) & FHC_CFGL_FIFO_EMPTY) && count--) + udelay(2); + + fhc->paused = true; +} + +static inline void fhc_chan_resume(struct fh_dma_chan *fhc) +{ + u32 cfglo = channel_readl(fhc, CFG_LO); + + channel_writel(fhc, CFG_LO, cfglo & ~FHC_CFGL_CH_SUSP); + + fhc->paused = false; +} + +static int fhc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) +{ + struct fh_dma_chan *fhc = to_fh_dma_chan(chan); + struct fh_dma *fhd = to_fh_dma(chan->device); + struct fh_desc *desc, *_desc; + unsigned long flags; + LIST_HEAD(list); + + if (cmd == DMA_PAUSE) { + spin_lock_irqsave(&fhc->lock, flags); + + fhc_chan_pause(fhc); + + spin_unlock_irqrestore(&fhc->lock, flags); + } else if (cmd == DMA_RESUME) { + if (!fhc->paused) + return 0; + + spin_lock_irqsave(&fhc->lock, flags); + + fhc_chan_resume(fhc); + + spin_unlock_irqrestore(&fhc->lock, flags); + } else if (cmd == DMA_TERMINATE_ALL) { + spin_lock_irqsave(&fhc->lock, flags); + + clear_bit(FH_DMA_IS_SOFT_LLP, &fhc->flags); + + fhc_chan_disable(fhd, fhc); + + fhc_chan_resume(fhc); + + /* active_list entries will end up before queued entries */ + list_splice_init(&fhc->queue, &list); + list_splice_init(&fhc->active_list, &list); + + spin_unlock_irqrestore(&fhc->lock, flags); + + /* Flush all pending and queued descriptors */ + list_for_each_entry_safe(desc, _desc, &list, desc_node) + fhc_descriptor_complete(fhc, desc, false); + } else if (cmd == DMA_SLAVE_CONFIG) { + return set_runtime_config(chan, (struct dma_slave_config *)arg); + } else { + return -ENXIO; + } + + return 0; +} + +static inline u32 fhc_get_residue(struct fh_dma_chan *fhc) +{ + unsigned long flags; + u32 residue; + + spin_lock_irqsave(&fhc->lock, flags); + + residue = fhc->residue; + if (test_bit(FH_DMA_IS_SOFT_LLP, &fhc->flags) && residue) + residue -= fhc_get_sent(fhc); + + spin_unlock_irqrestore(&fhc->lock, flags); + return residue; +} + +static enum dma_status +fhc_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, + struct dma_tx_state *txstate) +{ + struct fh_dma_chan *fhc = to_fh_dma_chan(chan); + enum dma_status ret; + + ret = dma_cookie_status(chan, cookie, txstate); + if (ret != DMA_SUCCESS) { + fhc_scan_descriptors(to_fh_dma(chan->device), fhc); + + ret = dma_cookie_status(chan, cookie, txstate); + } + + if (ret != DMA_SUCCESS) + dma_set_residue(txstate, fhc_get_residue(fhc)); + + if (fhc->paused) + return DMA_PAUSED; + + return ret; +} + +static void fhc_issue_pending(struct dma_chan *chan) +{ + struct fh_dma_chan *fhc = to_fh_dma_chan(chan); + + if (!list_empty(&fhc->queue)) + fhc_scan_descriptors(to_fh_dma(chan->device), fhc); +} + +static int fhc_alloc_chan_resources(struct dma_chan *chan) +{ + struct fh_dma_chan *fhc = to_fh_dma_chan(chan); + struct fh_dma *fhd = to_fh_dma(chan->device); + struct fh_desc *desc; + int i; + unsigned long flags; + + dev_vdbg(chan2dev(chan), "%s\n", __func__); + + /* ASSERT: channel is idle */ + if (dma_readl(fhd, CH_EN) & fhc->mask) { + dev_dbg(chan2dev(chan), "DMA channel not idle?\n"); + return -EIO; + } + + dma_cookie_init(chan); + + /* + * NOTE: some controllers may have additional features that we + * need to initialize here, like "scatter-gather" (which + * doesn't mean what you think it means), and status writeback. + */ + + fhc_set_masters(fhc); + + spin_lock_irqsave(&fhc->lock, flags); + i = fhc->descs_allocated; + while (fhc->descs_allocated < NR_DESCS_PER_CHANNEL) { + dma_addr_t phys; + + spin_unlock_irqrestore(&fhc->lock, flags); + + desc = dma_pool_alloc(fhd->desc_pool, GFP_ATOMIC, &phys); + if (!desc) + goto err_desc_alloc; + + memset(desc, 0, sizeof(struct fh_desc)); + + INIT_LIST_HEAD(&desc->tx_list); + dma_async_tx_descriptor_init(&desc->txd, chan); + desc->txd.tx_submit = fhc_tx_submit; + desc->txd.flags = DMA_CTRL_ACK; + desc->txd.phys = phys; + + fhc_desc_put(fhc, desc); + + spin_lock_irqsave(&fhc->lock, flags); + i = ++fhc->descs_allocated; + } + + spin_unlock_irqrestore(&fhc->lock, flags); + + dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n", __func__, i); + + return i; + +err_desc_alloc: + dev_info(chan2dev(chan), "only allocated %d descriptors\n", i); + + return i; +} + +static void fhc_free_chan_resources(struct dma_chan *chan) +{ + struct fh_dma_chan *fhc = to_fh_dma_chan(chan); + struct fh_dma *fhd = to_fh_dma(chan->device); + struct fh_desc *desc, *_desc; + unsigned long flags; + LIST_HEAD(list); + + dev_dbg(chan2dev(chan), "%s: descs allocated=%u\n", __func__, + fhc->descs_allocated); + + /* ASSERT: channel is idle */ + BUG_ON(!list_empty(&fhc->active_list)); + BUG_ON(!list_empty(&fhc->queue)); + BUG_ON(dma_readl(to_fh_dma(chan->device), CH_EN) & fhc->mask); + + spin_lock_irqsave(&fhc->lock, flags); + list_splice_init(&fhc->free_list, &list); + fhc->descs_allocated = 0; + fhc->initialized = false; + fhc->request_line = ~0; + + /* Disable interrupts */ + channel_clear_bit(fhd, MASK.XFER, fhc->mask); + channel_clear_bit(fhd, MASK.BLOCK, fhc->mask); + channel_clear_bit(fhd, MASK.ERROR, fhc->mask); + + spin_unlock_irqrestore(&fhc->lock, flags); + + list_for_each_entry_safe(desc, _desc, &list, desc_node) { + dev_vdbg(chan2dev(chan), " freeing descriptor %p\n", desc); + dma_pool_free(fhd->desc_pool, desc, desc->txd.phys); + } + + dev_vdbg(chan2dev(chan), "%s: done\n", __func__); +} + + +/* --------------------- Cyclic DMA API extensions -------------------- */ + +/** + * fh_dma_cyclic_start - start the cyclic DMA transfer + * @chan: the DMA channel to start + * + * Must be called with soft interrupts disabled. Returns zero on success or + * -errno on failure. + */ +int fh_dma_cyclic_start(struct dma_chan *chan) +{ + struct fh_dma_chan *fhc = to_fh_dma_chan(chan); + struct fh_dma *fhd = to_fh_dma(fhc->chan.device); + unsigned long flags; + + if (!test_bit(FH_DMA_IS_CYCLIC, &fhc->flags)) { + dev_err(chan2dev(&fhc->chan), "missing prep for cyclic DMA\n"); + return -ENODEV; + } + + spin_lock_irqsave(&fhc->lock, flags); + + /* Assert channel is idle */ + if (dma_readl(fhd, CH_EN) & fhc->mask) { + dev_err(chan2dev(&fhc->chan), + "BUG: Attempted to start non-idle channel\n"); + fhc_dump_chan_regs(fhc); + spin_unlock_irqrestore(&fhc->lock, flags); + return -EBUSY; + } + + dma_writel(fhd, CLEAR.ERROR, fhc->mask); + dma_writel(fhd, CLEAR.XFER, fhc->mask); + dma_writel(fhd, CLEAR.BLOCK, fhc->mask); + + fhc_initialize(fhc); + + /* Setup DMAC channel registers */ + channel_writel(fhc, LLP, fhc->cdesc->desc[0]->txd.phys); + channel_writel(fhc, CTL_LO, FHC_CTLL_LLP_D_EN | FHC_CTLL_LLP_S_EN); + channel_writel(fhc, CTL_HI, 0); + + channel_set_bit(fhd, CH_EN, fhc->mask); + + spin_unlock_irqrestore(&fhc->lock, flags); + + return 0; +} +EXPORT_SYMBOL(fh_dma_cyclic_start); + +/** + * fh_dma_cyclic_stop - stop the cyclic DMA transfer + * @chan: the DMA channel to stop + * + * Must be called with soft interrupts disabled. + */ +void fh_dma_cyclic_stop(struct dma_chan *chan) +{ + struct fh_dma_chan *fhc = to_fh_dma_chan(chan); + struct fh_dma *fhd = to_fh_dma(fhc->chan.device); + unsigned long flags; + + spin_lock_irqsave(&fhc->lock, flags); + + fhc_chan_disable(fhd, fhc); + + spin_unlock_irqrestore(&fhc->lock, flags); +} +EXPORT_SYMBOL(fh_dma_cyclic_stop); + +/** + * fh_dma_cyclic_prep - prepare the cyclic DMA transfer + * @chan: the DMA channel to prepare + * @buf_addr: physical DMA address where the buffer starts + * @buf_len: total number of bytes for the entire buffer + * @period_len: number of bytes for each period + * @direction: transfer direction, to or from device + * + * Must be called before trying to start the transfer. Returns a valid struct + * fh_cyclic_desc if successful or an ERR_PTR(-errno) if not successful. + */ +struct fh_cyclic_desc *fh_dma_cyclic_prep(struct dma_chan *chan, + dma_addr_t buf_addr, size_t buf_len, size_t period_len, + enum dma_transfer_direction direction) +{ + struct fh_dma_chan *fhc = to_fh_dma_chan(chan); + struct fh_dma_slave *fhs = chan->private; + struct fh_cyclic_desc *cdesc; + struct fh_cyclic_desc *retval = NULL; + struct fh_desc *desc; + struct fh_desc *last = NULL; + unsigned long was_cyclic; + unsigned int reg_width; + unsigned int periods; + unsigned int i; + unsigned long flags; + + spin_lock_irqsave(&fhc->lock, flags); + if (fhc->nollp) { + spin_unlock_irqrestore(&fhc->lock, flags); + dev_dbg(chan2dev(&fhc->chan), + "channel doesn't support LLP transfers\n"); + return ERR_PTR(-EINVAL); + } + + if (!list_empty(&fhc->queue) || !list_empty(&fhc->active_list)) { + spin_unlock_irqrestore(&fhc->lock, flags); + dev_dbg(chan2dev(&fhc->chan), + "queue and/or active list are not empty\n"); + return ERR_PTR(-EBUSY); + } + + was_cyclic = test_and_set_bit(FH_DMA_IS_CYCLIC, &fhc->flags); + spin_unlock_irqrestore(&fhc->lock, flags); + if (was_cyclic) { + dev_dbg(chan2dev(&fhc->chan), + "channel already prepared for cyclic DMA\n"); + return ERR_PTR(-EBUSY); + } + + retval = ERR_PTR(-EINVAL); + + reg_width = fhs->reg_width; + + if (unlikely(!is_slave_direction(direction))) + goto out_err; + + fhc->direction = direction; + + periods = buf_len / period_len; + + /* Check for too big/unaligned periods and unaligned DMA buffer. */ + if (period_len > (fhc->block_size << reg_width)) + goto out_err; + if (unlikely(period_len & ((1 << reg_width) - 1))) + goto out_err; + if (unlikely(buf_addr & ((1 << reg_width) - 1))) + goto out_err; + + retval = ERR_PTR(-ENOMEM); + + if (periods > NR_DESCS_PER_CHANNEL) + goto out_err; + + cdesc = kzalloc(sizeof(struct fh_cyclic_desc), GFP_KERNEL); + if (!cdesc) + goto out_err; + + cdesc->desc = kzalloc(sizeof(struct fh_desc *) * periods, GFP_KERNEL); + if (!cdesc->desc) + goto out_err_alloc; + + for (i = 0; i < periods; i++) { + desc = fhc_desc_get(fhc); + if (!desc) + goto out_err_desc_get; + + switch (direction) { + case DMA_MEM_TO_DEV: + desc->lli.dar = fhs->tx_reg; + desc->lli.sar = buf_addr + (period_len * i); + desc->lli.ctllo = (FHC_DEFAULT_CTLLO_OLD(chan->private) + | FHC_CTLL_DST_WIDTH(reg_width) + | FHC_CTLL_SRC_WIDTH(reg_width) + | FHC_CTLL_DST_FIX + | FHC_CTLL_SRC_INC + | FHC_CTLL_FC(fhs->fc) + | FHC_CTLL_INT_EN); + + break; + case DMA_DEV_TO_MEM: + desc->lli.dar = buf_addr + (period_len * i); + desc->lli.sar = fhs->rx_reg; + desc->lli.ctllo = (FHC_DEFAULT_CTLLO_OLD(chan->private) + | FHC_CTLL_SRC_WIDTH(reg_width) + | FHC_CTLL_DST_WIDTH(reg_width) + | FHC_CTLL_DST_INC + | FHC_CTLL_SRC_FIX + | FHC_CTLL_FC(fhs->fc) + | FHC_CTLL_INT_EN); + + + break; + default: + break; + } + + desc->lli.ctlhi = (period_len >> reg_width); + cdesc->desc[i] = desc; + + if (last) + { + last->lli.llp = desc->txd.phys; + dma_sync_single_for_device(chan2parent(chan), + last->txd.phys, + sizeof(last->lli), + DMA_TO_DEVICE); + } + + last = desc; + } + + /* Let's make a cyclic list */ + last->lli.llp = cdesc->desc[0]->txd.phys; + dma_sync_single_for_device(chan2parent(chan), last->txd.phys, + sizeof(last->lli), DMA_TO_DEVICE); + + dev_dbg(chan2dev(&fhc->chan), "cyclic prepared buf 0x%llx len %zu " + "period %zu periods %d\n", (unsigned long long)buf_addr, + buf_len, period_len, periods); + + cdesc->periods = periods; + fhc->cdesc = cdesc; + + return cdesc; + +out_err_desc_get: + while (i--) + fhc_desc_put(fhc, cdesc->desc[i]); +out_err_alloc: + kfree(cdesc); +out_err: + clear_bit(FH_DMA_IS_CYCLIC, &fhc->flags); + return (struct fh_cyclic_desc *)retval; +} +EXPORT_SYMBOL(fh_dma_cyclic_prep); + +/** + * fh_dma_cyclic_free - free a prepared cyclic DMA transfer + * @chan: the DMA channel to free + */ +void fh_dma_cyclic_free(struct dma_chan *chan) +{ + struct fh_dma_chan *fhc = to_fh_dma_chan(chan); + struct fh_dma *fhd = to_fh_dma(fhc->chan.device); + struct fh_cyclic_desc *cdesc = fhc->cdesc; + int i; + unsigned long flags; + + dev_dbg(chan2dev(&fhc->chan), "%s\n", __func__); + + if (!cdesc) + return; + + spin_lock_irqsave(&fhc->lock, flags); + + fhc_chan_disable(fhd, fhc); + + dma_writel(fhd, CLEAR.ERROR, fhc->mask); + dma_writel(fhd, CLEAR.XFER, fhc->mask); + dma_writel(fhd, CLEAR.BLOCK, fhc->mask); + + spin_unlock_irqrestore(&fhc->lock, flags); + + for (i = 0; i < cdesc->periods; i++) + fhc_desc_put(fhc, cdesc->desc[i]); + + kfree(cdesc->desc); + kfree(cdesc); + + clear_bit(FH_DMA_IS_CYCLIC, &fhc->flags); +} +EXPORT_SYMBOL(fh_dma_cyclic_free); + +/*----------------------------------------------------------------------*/ + +static void fh_dma_off(struct fh_dma *fhd) +{ + int i; + + dma_writel(fhd, CFG, 0); + + channel_clear_bit(fhd, MASK.XFER, fhd->all_chan_mask); + channel_clear_bit(fhd, MASK.BLOCK, fhd->all_chan_mask); + channel_clear_bit(fhd, MASK.SRC_TRAN, fhd->all_chan_mask); + channel_clear_bit(fhd, MASK.DST_TRAN, fhd->all_chan_mask); + channel_clear_bit(fhd, MASK.ERROR, fhd->all_chan_mask); + + while (dma_readl(fhd, CFG) & FH_CFG_DMA_EN) + cpu_relax(); + + for (i = 0; i < fhd->dma.chancnt; i++) + fhd->chan[i].initialized = false; +} + +static int fh_dma_probe(struct platform_device *pdev) +{ + struct fh_dma_platform_data *pdata; + struct resource *io; + struct fh_dma *fhd; + size_t size; + void __iomem *regs; + bool autocfg; + unsigned int fh_params; + unsigned int nr_channels; + unsigned int max_blk_size = 0; + int irq; + int err; + int i; + + io = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!io) + return -EINVAL; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + if (!request_mem_region(io->start, FH_REGLEN, pdev->dev.driver->name)) + return -EBUSY; + + regs = ioremap(io->start, FH_REGLEN); + if (!regs) { + err = -ENOMEM; + goto err_release_r; + } + + /* Apply default dma_mask if needed */ + if (!pdev->dev.dma_mask) { + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + } + + fh_params = dma_read_byaddr(regs, FH_PARAMS); + autocfg = fh_params >> FH_PARAMS_EN & 0x1; + + dev_dbg(&pdev->dev, "FH_PARAMS: 0x%08x\n", fh_params); + + pdata = dev_get_platdata(&pdev->dev); + + if (!pdata && autocfg) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + /* Fill platform data with the default values */ + pdata->is_private = true; + pdata->chan_allocation_order = CHAN_ALLOCATION_ASCENDING; + pdata->chan_priority = CHAN_PRIORITY_ASCENDING; + } else if (!pdata || pdata->nr_channels > FH_DMA_MAX_NR_CHANNELS) + return -EINVAL; + + if (autocfg) + nr_channels = (fh_params >> FH_PARAMS_NR_CHAN & 0x7) + 1; + else + nr_channels = pdata->nr_channels; + + size = sizeof(struct fh_dma) + nr_channels * sizeof(struct fh_dma_chan); + fhd = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!fhd) + return -ENOMEM; + + fhd->clk = clk_get(&pdev->dev, "ahb_clk"); + if (IS_ERR(fhd->clk)) + return PTR_ERR(fhd->clk); + clk_enable(fhd->clk); + + fhd->regs = regs; + + /* Get hardware configuration parameters */ + if (autocfg) { + max_blk_size = dma_readl(fhd, MAX_BLK_SIZE); + + fhd->nr_masters = (fh_params >> FH_PARAMS_NR_MASTER & 3) + 1; + for (i = 0; i < fhd->nr_masters; i++) { + fhd->data_width[i] = + (fh_params >> FH_PARAMS_DATA_WIDTH(i) & 3) + 2; + } + } else { + fhd->nr_masters = pdata->nr_masters; + memcpy(fhd->data_width, pdata->data_width, 4); + } + + /* Calculate all channel mask before DMA setup */ + fhd->all_chan_mask = (1 << nr_channels) - 1; + + /* Force dma off, just in case */ + fh_dma_off(fhd); + + /* Disable BLOCK interrupts as well */ + channel_clear_bit(fhd, MASK.BLOCK, fhd->all_chan_mask); + + err = devm_request_irq(&pdev->dev, irq, fh_dma_interrupt, 0, + "fh_dmac", fhd); + if (err) + return err; + + platform_set_drvdata(pdev, fhd); + + /* Create a pool of consistent memory blocks for hardware descriptors */ + fhd->desc_pool = dmam_pool_create("fh_dmac_desc_pool", &pdev->dev, + sizeof(struct fh_desc), 4, 0); + if (!fhd->desc_pool) { + dev_err(&pdev->dev, "No memory for descriptors dma pool\n"); + return -ENOMEM; + } + + tasklet_init(&fhd->tasklet, fh_dma_tasklet, (unsigned long)fhd); + + INIT_LIST_HEAD(&fhd->dma.channels); + for (i = 0; i < nr_channels; i++) { + struct fh_dma_chan *fhc = &fhd->chan[i]; + int r = nr_channels - i - 1; + + fhc->chan.device = &fhd->dma; + dma_cookie_init(&fhc->chan); + if (pdata->chan_allocation_order == CHAN_ALLOCATION_ASCENDING) + list_add_tail(&fhc->chan.device_node, + &fhd->dma.channels); + else + list_add(&fhc->chan.device_node, &fhd->dma.channels); + + /* 7 is highest priority & 0 is lowest. */ + if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING) + fhc->priority = r; + else + fhc->priority = i; + + fhc->ch_regs = &__fh_regs(fhd)->CHAN[i]; + spin_lock_init(&fhc->lock); + fhc->mask = 1 << i; + + INIT_LIST_HEAD(&fhc->active_list); + INIT_LIST_HEAD(&fhc->queue); + INIT_LIST_HEAD(&fhc->free_list); + + channel_clear_bit(fhd, CH_EN, fhc->mask); + + fhc->direction = DMA_TRANS_NONE; + fhc->request_line = ~0; + + /* Hardware configuration */ + if (autocfg) { + unsigned int fhc_params; + + fhc_params = dma_read_byaddr(regs + r * sizeof(u32), + FHC_PARAMS); + + dev_dbg(&pdev->dev, "FHC_PARAMS[%d]: 0x%08x\n", i, + fhc_params); + + /* Decode maximum block size for given channel. The + * stored 4 bit value represents blocks from 0x00 for 3 + * up to 0x0a for 4095. */ + fhc->block_size = + (4 << ((max_blk_size >> 4 * i) & 0xf)) - 1; + fhc->nollp = + (fhc_params >> FHC_PARAMS_MBLK_EN & 0x1) == 0; + } else { + fhc->block_size = pdata->block_size; + + /* Check if channel supports multi block transfer */ + channel_writel(fhc, LLP, 0xfffffffc); + fhc->nollp = + (channel_readl(fhc, LLP) & 0xfffffffc) == 0; + channel_writel(fhc, LLP, 0); + } + } + + /* Clear all interrupts on all channels. */ + dma_writel(fhd, CLEAR.XFER, fhd->all_chan_mask); + dma_writel(fhd, CLEAR.BLOCK, fhd->all_chan_mask); + dma_writel(fhd, CLEAR.SRC_TRAN, fhd->all_chan_mask); + dma_writel(fhd, CLEAR.DST_TRAN, fhd->all_chan_mask); + dma_writel(fhd, CLEAR.ERROR, fhd->all_chan_mask); + + dma_cap_set(DMA_MEMCPY, fhd->dma.cap_mask); + dma_cap_set(DMA_SLAVE, fhd->dma.cap_mask); + if (pdata->is_private) + dma_cap_set(DMA_PRIVATE, fhd->dma.cap_mask); + fhd->dma.dev = &pdev->dev; + fhd->dma.device_alloc_chan_resources = fhc_alloc_chan_resources; + fhd->dma.device_free_chan_resources = fhc_free_chan_resources; + + fhd->dma.device_prep_dma_memcpy = fhc_prep_dma_memcpy; + + fhd->dma.device_prep_slave_sg = fhc_prep_slave_sg; + fhd->dma.device_control = fhc_control; + + fhd->dma.device_tx_status = fhc_tx_status; + fhd->dma.device_issue_pending = fhc_issue_pending; + + dma_writel(fhd, CFG, FH_CFG_DMA_EN); + + err = dma_async_device_register(&fhd->dma); + + if(err) + pr_err("dma register failed, ret %d\n", err); + + dev_info(&pdev->dev, "FH DMA Controller, %d channels\n", + nr_channels); + + return 0; + +err_release_r: + release_resource(io); + return err; +} + +static int fh_dma_remove(struct platform_device *pdev) +{ + struct fh_dma *fhd = platform_get_drvdata(pdev); + struct fh_dma_chan *fhc, *_fhc; + + fh_dma_off(fhd); + dma_async_device_unregister(&fhd->dma); + + tasklet_kill(&fhd->tasklet); + + list_for_each_entry_safe(fhc, _fhc, &fhd->dma.channels, + chan.device_node) { + list_del(&fhc->chan.device_node); + channel_clear_bit(fhd, CH_EN, fhc->mask); + } + + return 0; +} + +static void fh_dma_shutdown(struct platform_device *pdev) +{ + struct fh_dma *fhd = platform_get_drvdata(pdev); + + fh_dma_off(fhd); + clk_disable(fhd->clk); +} + +static int fh_dma_suspend_noirq(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fh_dma *fhd = platform_get_drvdata(pdev); + + fh_dma_off(fhd); + clk_disable(fhd->clk); + + return 0; +} + +static int fh_dma_resume_noirq(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fh_dma *fhd = platform_get_drvdata(pdev); + + clk_enable(fhd->clk); + dma_writel(fhd, CFG, FH_CFG_DMA_EN); + + return 0; +} + +static const struct dev_pm_ops fh_dma_dev_pm_ops = { + .suspend_noirq = fh_dma_suspend_noirq, + .resume_noirq = fh_dma_resume_noirq, + .freeze_noirq = fh_dma_suspend_noirq, + .thaw_noirq = fh_dma_resume_noirq, + .restore_noirq = fh_dma_resume_noirq, + .poweroff_noirq = fh_dma_suspend_noirq, +}; + +static struct platform_driver fh_dma_driver = { + .probe = fh_dma_probe, + .remove = fh_dma_remove, + .shutdown = fh_dma_shutdown, + .driver = { + .name = "fh_dmac", + .pm = &fh_dma_dev_pm_ops, + }, +}; + +static int __init fh_dma_init(void) +{ + return platform_driver_register(&fh_dma_driver); +} +subsys_initcall(fh_dma_init); + +static void __exit fh_dma_exit(void) +{ + platform_driver_unregister(&fh_dma_driver); +} +module_exit(fh_dma_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("FH DMA Controller driver"); diff --git a/drivers/dma/fh_dmac_regs.h b/drivers/dma/fh_dmac_regs.h new file mode 100644 index 00000000..8ca1589f --- /dev/null +++ b/drivers/dma/fh_dmac_regs.h @@ -0,0 +1,236 @@ +/* + * Driver for the Synopsys DesignWare AHB DMA Controller + * + * Copyright (C) 2005-2007 Atmel Corporation + * Copyright (C) 2010-2011 ST Microelectronics + * + * 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 + +#define FH_DMA_MAX_NR_CHANNELS 8 + +/* + * Redefine this macro to handle differences between 32- and 64-bit + * addressing, big vs. little endian, etc. + */ +#define FH_REG(name) u32 name; u32 __pad_##name + +/* Hardware register definitions. */ +struct fh_dma_chan_regs { + FH_REG(SAR); /* Source Address Register */ + FH_REG(DAR); /* Destination Address Register */ + FH_REG(LLP); /* Linked List Pointer */ + u32 CTL_LO; /* Control Register Low */ + u32 CTL_HI; /* Control Register High */ + FH_REG(SSTAT); + FH_REG(DSTAT); + FH_REG(SSTATAR); + FH_REG(DSTATAR); + u32 CFG_LO; /* Configuration Register Low */ + u32 CFG_HI; /* Configuration Register High */ + FH_REG(SGR); + FH_REG(DSR); +}; + +struct fh_dma_irq_regs { + FH_REG(XFER); + FH_REG(BLOCK); + FH_REG(SRC_TRAN); + FH_REG(DST_TRAN); + FH_REG(ERROR); +}; + +struct fh_dma_regs { + /* per-channel registers */ + struct fh_dma_chan_regs CHAN[FH_DMA_MAX_NR_CHANNELS]; + + /* irq handling */ + struct fh_dma_irq_regs RAW; /* r */ + struct fh_dma_irq_regs STATUS; /* r (raw & mask) */ + struct fh_dma_irq_regs MASK; /* rw (set = irq enabled) */ + struct fh_dma_irq_regs CLEAR; /* w (ack, affects "raw") */ + + FH_REG(STATUS_INT); /* r */ + + /* software handshaking */ + FH_REG(REQ_SRC); + FH_REG(REQ_DST); + FH_REG(SGL_REQ_SRC); + FH_REG(SGL_REQ_DST); + FH_REG(LAST_SRC); + FH_REG(LAST_DST); + + /* miscellaneous */ + FH_REG(CFG); + FH_REG(CH_EN); + FH_REG(ID); + FH_REG(TEST); + + /* optional encoded params, 0x3c8..0x3 */ +}; + +/* Bitfields in CTL_LO */ +#define FHC_CTLL_INT_EN (1 << 0) /* irqs enabled? */ +#define FHC_CTLL_DST_WIDTH(n) ((n)<<1) /* bytes per element */ +#define FHC_CTLL_SRC_WIDTH(n) ((n)<<4) +#define FHC_CTLL_DST_INC (0<<7) /* DAR update/not */ +#define FHC_CTLL_DST_DEC (1<<7) +#define FHC_CTLL_DST_FIX (2<<7) +#define FHC_CTLL_SRC_INC (0<<9) /* SAR update/not */ +#define FHC_CTLL_SRC_DEC (1<<9) +#define FHC_CTLL_SRC_FIX (2<<9) +#define FHC_CTLL_DST_MSIZE(n) ((n)<<11) /* burst, #elements */ +#define FHC_CTLL_SRC_MSIZE(n) ((n)<<14) +#define FHC_CTLL_S_GATH_EN (1 << 17) /* src gather, !FIX */ +#define FHC_CTLL_D_SCAT_EN (1 << 18) /* dst scatter, !FIX */ +#define FHC_CTLL_FC(n) ((n) << 20) +#define FHC_CTLL_FC_M2M (0 << 20) /* mem-to-mem */ +#define FHC_CTLL_FC_M2P (1 << 20) /* mem-to-periph */ +#define FHC_CTLL_FC_P2M (2 << 20) /* periph-to-mem */ +#define FHC_CTLL_FC_P2P (3 << 20) /* periph-to-periph */ +/* plus 4 transfer types for peripheral-as-flow-controller */ +#define FHC_CTLL_DMS(n) ((n)<<23) /* dst master select */ +#define FHC_CTLL_SMS(n) ((n)<<25) /* src master select */ +#define FHC_CTLL_LLP_D_EN (1 << 27) /* dest block chain */ +#define FHC_CTLL_LLP_S_EN (1 << 28) /* src block chain */ + +/* Bitfields in CTL_HI */ +#define FHC_CTLH_DONE 0x00001000 +#define FHC_CTLH_BLOCK_TS_MASK 0x00000fff + +/* Bitfields in CFG_LO. Platform-configurable bits are in */ +#define FHC_CFGL_CH_PRIOR_MASK (0x7 << 5) /* priority mask */ +#define FHC_CFGL_CH_PRIOR(x) ((x) << 5) /* priority */ +#define FHC_CFGL_CH_SUSP (1 << 8) /* pause xfer */ +#define FHC_CFGL_FIFO_EMPTY (1 << 9) /* pause xfer */ +#define FHC_CFGL_HS_DST (1 << 10) /* handshake w/dst */ +#define FHC_CFGL_HS_SRC (1 << 11) /* handshake w/src */ +#define FHC_CFGL_MAX_BURST(x) ((x) << 20) +#define FHC_CFGL_RELOAD_SAR (1 << 30) +#define FHC_CFGL_RELOAD_DAR (1 << 31) + +/* Bitfields in CFG_HI. Platform-configurable bits are in */ +#define FHC_CFGH_DS_UPD_EN (1 << 5) +#define FHC_CFGH_SS_UPD_EN (1 << 6) + +/* Bitfields in SGR */ +#define FHC_SGR_SGI(x) ((x) << 0) +#define FHC_SGR_SGC(x) ((x) << 20) + +/* Bitfields in DSR */ +#define FHC_DSR_DSI(x) ((x) << 0) +#define FHC_DSR_DSC(x) ((x) << 20) + +/* Bitfields in CFG */ +#define FH_CFG_DMA_EN (1 << 0) + +#define FH_REGLEN 0x400 + +enum fh_dmac_flags { + FH_DMA_IS_CYCLIC = 0, +}; + +struct fh_dma_chan { + struct dma_chan chan; + void __iomem *ch_regs; + u8 mask; + u8 priority; + bool paused; + bool initialized; + spinlock_t lock; + + /* these other elements are all protected by lock */ + unsigned long flags; + dma_cookie_t completed; + struct list_head active_list; + struct list_head queue; + struct list_head free_list; + struct fh_cyclic_desc *cdesc; + + unsigned int descs_allocated; + +}; + +static inline struct fh_dma_chan_regs __iomem * +__fhc_regs(struct fh_dma_chan *fhc) +{ + return fhc->ch_regs; +} + +#define channel_readl(fhc, name) \ + readl(&(__fhc_regs(fhc)->name)) +#define channel_writel(fhc, name, val) \ + writel((val), &(__fhc_regs(fhc)->name)) + +static inline struct fh_dma_chan *to_fh_dma_chan(struct dma_chan *chan) +{ + return container_of(chan, struct fh_dma_chan, chan); +} + +struct fh_dma { + struct dma_device dma; + void __iomem *regs; + struct tasklet_struct tasklet; + struct clk *clk; + + u8 all_chan_mask; + + struct fh_dma_chan chan[0]; +}; + +static inline struct fh_dma_regs __iomem *__fh_regs(struct fh_dma *fh) +{ + return fh->regs; +} + +#define dma_readl(fh, name) \ + readl(&(__fh_regs(fh)->name)) +#define dma_writel(fh, name, val) \ + writel((val), &(__fh_regs(fh)->name)) + +#define channel_set_bit(fh, reg, mask) \ + dma_writel(fh, reg, ((mask) << 8) | (mask)) +#define channel_clear_bit(fh, reg, mask) \ + dma_writel(fh, reg, ((mask) << 8) | 0) + +static inline struct fh_dma *to_fh_dma(struct dma_device *ddev) +{ + return container_of(ddev, struct fh_dma, dma); +} + +/* LLI == Linked List Item; a.k.a. DMA block descriptor */ +struct fh_lli { + /* values that are not changed by hardware */ + u32 sar; + u32 dar; + u32 llp; /* chain to next lli */ + u32 ctllo; + /* values that may get written back: */ + u32 ctlhi; + /* sstat and dstat can snapshot peripheral register state. + * silicon config may discard either or both... + */ + u32 sstat; + u32 dstat; +}; + +struct fh_desc { + /* FIRST values the hardware uses */ + struct fh_lli lli; + + /* THEN values for driver housekeeping */ + struct list_head desc_node; + struct list_head tx_list; + struct dma_async_tx_descriptor txd; + size_t len; +}; + +static inline struct fh_desc * +txd_to_fh_desc(struct dma_async_tx_descriptor *txd) +{ + return container_of(txd, struct fh_desc, txd); +} diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2967002a..3780557d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -85,6 +85,11 @@ config GPIO_IT8761E tristate "IT8761E GPIO support" help Say yes here to support GPIO functionality of IT8761E super I/O chip. + +config GPIO_FH + tristate "FH GPIO support" + help + Say yes here to support GPIO functionality of FH. config GPIO_EXYNOS4 def_bool y diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index b605f8ec..3562c0f9 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o obj-$(CONFIG_GPIO_CS5535) += cs5535-gpio.o obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o obj-$(CONFIG_GPIO_IT8761E) += it8761e_gpio.o +obj-$(CONFIG_GPIO_FH) += fh_gpio.o obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o diff --git a/drivers/gpio/fh_gpio.c b/drivers/gpio/fh_gpio.c new file mode 100644 index 00000000..b3257211 --- /dev/null +++ b/drivers/gpio/fh_gpio.c @@ -0,0 +1,507 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct fh_gpio_chip *fh_gpio0, *fh_gpio1; + +static inline void __iomem* gpio_to_base(unsigned int gpio) +{ + if (gpio >= 32 && gpio < 64) + { + return fh_gpio1->base; + } + else if(gpio < 32) + { + return fh_gpio0->base; + } + else + { + pr_err("ERROR: incorrect GPIO num\n"); + return NULL; + } +} + +static int _set_gpio_irq_type(unsigned int gpio, unsigned int type) +{ + u32 int_type, int_polarity; + u32 bit = gpio % 32; + void __iomem* base; + base = gpio_to_base(gpio); + + switch (type & IRQF_TRIGGER_MASK) { + case IRQ_TYPE_EDGE_BOTH: + int_type = GPIO_INT_TYPE_EDGE; + // toggle trigger + if (FH_GPIO_GetValue((u32)base, bit)) + int_polarity = GPIO_INT_POL_LOW; + else + int_polarity = GPIO_INT_POL_HIGH; + break; + case IRQ_TYPE_EDGE_RISING: + int_type = GPIO_INT_TYPE_EDGE; + int_polarity = GPIO_INT_POL_HIGH; + break; + case IRQ_TYPE_EDGE_FALLING: + int_type = GPIO_INT_TYPE_EDGE; + int_polarity = GPIO_INT_POL_LOW; + break; + case IRQ_TYPE_LEVEL_HIGH: + int_type = GPIO_INT_TYPE_LEVEL; + int_polarity = GPIO_INT_POL_HIGH; + break; + case IRQ_TYPE_LEVEL_LOW: + int_type = GPIO_INT_TYPE_LEVEL; + int_polarity = GPIO_INT_POL_LOW; + break; + case IRQ_TYPE_NONE: + return 0; + default: + return -EINVAL; + } + FH_GPIO_SetInterruptType((u32)base, bit, int_type); + FH_GPIO_SetInterruptPolarity((u32)base, bit, int_polarity); + return 0; +} + +int fh_set_gpio_irq(struct gpio_irq_info * info) +{ + void __iomem* base; + base = gpio_to_base(info->irq_gpio); + + return _set_gpio_irq_type(info->irq_gpio, info->irq_type); +} +EXPORT_SYMBOL(fh_set_gpio_irq); + +void fh_irq_enable(unsigned int gpio) +{ + void __iomem* base; + int gpio_num = gpio % 32; + base = gpio_to_base(gpio); + + FH_GPIO_EnableInterrupt((u32)base, gpio_num, TRUE); +} +EXPORT_SYMBOL(fh_irq_enable); + +void fh_irq_disable(unsigned int gpio) +{ + void __iomem* base; + int gpio_num = gpio % 32; + base = gpio_to_base(gpio); + + FH_GPIO_EnableInterrupt((u32)base, gpio_num, FALSE); +} +EXPORT_SYMBOL(fh_irq_disable); + +void fh_clear_gpio_irq(int gpio_id) +{ + void __iomem* base; + int gpio_num = gpio_id % 32; + base = gpio_to_base(gpio_id); + + FH_GPIO_ClearInterrupt((u32)base, gpio_num); +} +EXPORT_SYMBOL(fh_clear_gpio_irq); + + +static inline void __iomem* irq_to_controller(struct irq_data* d) +{ + struct fh_gpio_chip *fh_gpio = irq_data_get_irq_chip_data(d); + + if (likely(d->irq >= NR_INTERNAL_IRQS)) + return fh_gpio->base; + pr_err("irq num: %d is not a gpio irq!\n", d->irq); + return 0; +} + +static void gpio_irq_ack(struct irq_data* d) +{ + void __iomem* base; + struct fh_gpio_chip *fh_gpio = irq_data_get_irq_chip_data(d); + base = irq_to_controller(d); + + FH_GPIO_ClearInterrupt((u32)base, d->irq - NR_INTERNAL_IRQS - fh_gpio->chip.base); +} + +static void gpio_irq_enable(struct irq_data *d) +{ + void __iomem* base; + struct fh_gpio_chip *fh_gpio = irq_data_get_irq_chip_data(d); + base = irq_to_controller(d); + + FH_GPIO_EnableInterrupt((u32)base, d->irq - NR_INTERNAL_IRQS - fh_gpio->chip.base, TRUE); +} + +static void gpio_irq_disable(struct irq_data *d) +{ + void __iomem* base; + struct fh_gpio_chip *fh_gpio = irq_data_get_irq_chip_data(d); + base = irq_to_controller(d); + + FH_GPIO_EnableInterrupt((u32)base, d->irq - NR_INTERNAL_IRQS - fh_gpio->chip.base, FALSE); +} + +static void gpio_irq_mask(struct irq_data *d) +{ + void __iomem* base; + struct fh_gpio_chip *fh_gpio = irq_data_get_irq_chip_data(d); + base = irq_to_controller(d); + + FH_GPIO_EnableInterruptMask((u32)base, d->irq - NR_INTERNAL_IRQS - fh_gpio->chip.base, TRUE); +} + +static void gpio_irq_unmask(struct irq_data *d) +{ + void __iomem* base; + struct fh_gpio_chip *fh_gpio = irq_data_get_irq_chip_data(d); + base = irq_to_controller(d); + + FH_GPIO_EnableInterruptMask((u32)base, d->irq - NR_INTERNAL_IRQS - fh_gpio->chip.base, FALSE); +} + +static int gpio_irq_type(struct irq_data *d, unsigned int type) +{ + void __iomem* base; + base = irq_to_controller(d); + + return _set_gpio_irq_type(d->irq - NR_INTERNAL_IRQS, type); +} + +#ifdef CONFIG_PM + +static int gpio_irq_set_wake(struct irq_data *d, unsigned value) +{ + struct fh_gpio_chip *fh_gpio = irq_data_get_irq_chip_data(d); + + if (unlikely(d->irq >= NR_IRQS)) + return -EINVAL; + + if (value) + fh_gpio->gpio_wakeups |= (1 << (d->irq - NR_INTERNAL_IRQS - fh_gpio->chip.base)); + else + fh_gpio->gpio_wakeups &= ~(1 << (d->irq - NR_INTERNAL_IRQS - fh_gpio->chip.base)); + + return 0; +} + +void fh_gpio_irq_suspend(void) +{ + fh_gpio0->gpio_backups = FH_GPIO_GetEnableInterrupts((u32)fh_gpio0->base); + fh_gpio1->gpio_backups = FH_GPIO_GetEnableInterrupts((u32)fh_gpio1->base); + + FH_GPIO_SetEnableInterrupts((u32)fh_gpio0->base, fh_gpio0->gpio_wakeups); + FH_GPIO_SetEnableInterrupts((u32)fh_gpio1->base, fh_gpio1->gpio_wakeups); +} + +void fh_gpio_irq_resume(void) +{ + FH_GPIO_SetEnableInterrupts((u32)fh_gpio0->base, fh_gpio0->gpio_backups); + FH_GPIO_SetEnableInterrupts((u32)fh_gpio1->base, fh_gpio1->gpio_backups); +} + +#else +#define gpio_irq_set_wake NULL +#endif + +static struct irq_chip gpio_irqchip = { + .name = "FH_GPIO_INTC", + .irq_ack = gpio_irq_ack, + .irq_enable = gpio_irq_enable, + .irq_disable = gpio_irq_disable, + .irq_mask = gpio_irq_mask, + .irq_unmask = gpio_irq_unmask, + .irq_set_type = gpio_irq_type, + .irq_set_wake = gpio_irq_set_wake, +}; + +static void gpio_toggle_trigger(unsigned int gpio, unsigned int offs) +{ + u32 int_polarity; + int gpio_num = gpio % 32; + void __iomem* base = gpio_to_base(gpio); + + if (FH_GPIO_GetValue((u32)base, gpio)) + int_polarity = GPIO_INT_POL_LOW; + else + int_polarity = GPIO_INT_POL_HIGH; + + printk(">>>>> do trigger gpio=%d, set polarity=%x\n", offs, int_polarity); + FH_GPIO_SetInterruptPolarity((u32)base, gpio_num, int_polarity); +} + +static inline u32 irq_get_trigger_type(unsigned int irq) +{ + struct irq_data *d = irq_get_irq_data(irq); + return d ? irqd_get_trigger_type(d) : 0; +} + +static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + struct irq_data *irqdata = irq_desc_get_irq_data(desc); + struct irq_chip *irqchip = irq_data_get_irq_chip(irqdata); + struct fh_gpio_chip *fh_gpio = irq_data_get_irq_chip_data(irqdata); + u32 irq_status; + int gpio_num, gpio; + + irq_status = FH_GPIO_GetInterruptStatus((u32)fh_gpio->base); + + if (unlikely(irq_status == 0)) { + pr_err("gpio irq status is zero.\n"); + return; + } + + /* temporarily mask (level sensitive) parent IRQ */ + irqchip->irq_mask(irqdata); + + gpio_num = fls(irq_status) - 1; + + FH_GPIO_ClearInterrupt((u32)fh_gpio->base, gpio_num); + + gpio = gpio_num + fh_gpio->chip.base; + + generic_handle_irq(gpio_to_irq(gpio)); + + if ((irq_get_trigger_type(gpio_to_irq(gpio)) & IRQ_TYPE_SENSE_MASK) + == IRQ_TYPE_EDGE_BOTH) + gpio_toggle_trigger(gpio, gpio_num); + + irqchip->irq_unmask(irqdata); + /* now it may re-trigger */ +} + +/* + * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpio_lock_class; + +static void fh_gpio_irq_init(struct platform_device *pdev) +{ + int i, gpio_irq; + struct fh_gpio_chip *plat_data; + + plat_data = pdev->dev.platform_data; + + for (i = 0; i < 32; i++) { + gpio_irq = i + NR_INTERNAL_IRQS + 32 * pdev->id; + irq_set_lockdep_class(gpio_irq, &gpio_lock_class); + irq_set_chip_and_handler(gpio_irq, &gpio_irqchip, handle_simple_irq); + set_irq_flags(gpio_irq, IRQF_VALID); + irq_set_chip_data(gpio_irq, plat_data); + } + + irq_set_chip_data(plat_data->irq, plat_data); + irq_set_chained_handler(plat_data->irq, gpio_irq_handler); + enable_irq_wake(plat_data->irq); +} + +static int chip_to_irq(struct gpio_chip *c, unsigned offset) +{ + struct fh_gpio_chip* chip; + chip = container_of(c, struct fh_gpio_chip, chip); + return offset + NR_INTERNAL_IRQS + chip->chip.base; +} + +static int chip_gpio_get(struct gpio_chip *c, unsigned offset) +{ + u32 bit = offset % 32; + struct fh_gpio_chip* chip; + chip = container_of(c, struct fh_gpio_chip, chip); + + if(offset / 32) + return FH_GPIOB_GetValue((u32)chip->base, bit); + else + return FH_GPIO_GetValue((u32)chip->base, bit); +} + +static void chip_gpio_set(struct gpio_chip *c, unsigned offset, int val) +{ + u32 bit = offset % 32; + struct fh_gpio_chip* chip; + chip = container_of(c, struct fh_gpio_chip, chip); + if(offset / 32) + FH_GPIOB_SetValue((u32)chip->base, bit, val); + else + FH_GPIO_SetValue((u32)chip->base, bit, val); +} + +static int chip_direction_input(struct gpio_chip *c, unsigned offset) +{ + u32 bit = offset % 32; + unsigned long flags; + struct fh_gpio_chip* chip; + chip = container_of(c, struct fh_gpio_chip, chip); + spin_lock_irqsave(&chip->lock, flags); + if(offset / 32) + FH_GPIOB_SetDirection((u32)chip->base, bit, GPIO_DIR_INPUT); + else + FH_GPIO_SetDirection((u32)chip->base, bit, GPIO_DIR_INPUT); + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val) +{ + u32 bit = offset % 32; + unsigned long flags; + struct fh_gpio_chip* chip; + chip = container_of(c, struct fh_gpio_chip, chip); + + spin_lock_irqsave(&chip->lock, flags); + if(offset / 32) + { + FH_GPIOB_SetDirection((u32)chip->base, bit, GPIO_DIR_OUTPUT); + FH_GPIOB_SetValue((u32)chip->base, bit, val); + } + else + { + FH_GPIO_SetDirection((u32)chip->base, bit, GPIO_DIR_OUTPUT); + FH_GPIO_SetValue((u32)chip->base, bit, val); + } + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +void fh_gpio_set(int gpio_id, int value) +{ + __gpio_set_value(gpio_id, value); +} +EXPORT_SYMBOL(fh_gpio_set); + +int fh_gpio_get(int gpio_id, int* value) +{ + *value = __gpio_get_value(gpio_id); + return 0; +} +EXPORT_SYMBOL(fh_gpio_get); + +int fh_gpio_reset(int gpio_id) +{ + return 0; +} +EXPORT_SYMBOL(fh_gpio_reset); + +static int __devinit fh_gpio_probe(struct platform_device *pdev) +{ + struct resource *res; + int err = -EIO; + struct fh_gpio_chip *plat_data; + + /* There are two ways to get the GPIO base address; one is by + * fetching it from MSR_LBAR_GPIO, the other is by reading the + * PCI BAR info. The latter method is easier (especially across + * different architectures), so we'll stick with that for now. If + * it turns out to be unreliable in the face of crappy BIOSes, we + * can always go back to using MSRs.. */ + + plat_data = pdev->dev.platform_data; + plat_data->chip.get = chip_gpio_get; + plat_data->chip.set = chip_gpio_set; + plat_data->chip.direction_input = chip_direction_input; + plat_data->chip.direction_output = chip_direction_output; + plat_data->chip.to_irq = chip_to_irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "can't fetch device resource info\n"); + goto done; + } + + if (!request_mem_region(res->start, resource_size(res), pdev->name)) { + dev_err(&pdev->dev, "can't request region\n"); + goto done; + } + + /* set up the driver-specific struct */ + plat_data->base = ioremap(res->start, resource_size(res)); + + if(pdev->id) + fh_gpio1 = plat_data; + else + fh_gpio0 = plat_data; + + plat_data->pdev = pdev; + spin_lock_init(&plat_data->lock); + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + pr_err("%s: ERROR: getting resource failed" + "cannot get IORESOURCE_MEM\n", __func__); + goto release_region; + } + plat_data->irq = res->start; + + /* finally, register with the generic GPIO API */ + err = gpiochip_add(&plat_data->chip); + if (err) { + pr_err("GPIO support load fail.\n"); + goto release_region; + } + + fh_gpio_irq_init(pdev); + pr_debug("GPIO support successfully loaded.\n\tBase Addr: 0x%p\n", + plat_data->base); + + return 0; + +release_region: + release_region(res->start, resource_size(res)); +done: + return err; +} + +static int __devexit fh_gpio_remove(struct platform_device *pdev) +{ + struct resource *r; + int err; + struct fh_gpio_chip *plat_data; + + plat_data = pdev->dev.platform_data; + err = gpiochip_remove(&plat_data->chip); + if (err) { + dev_err(&pdev->dev, "unable to remove gpio_chip\n"); + return err; + } + + iounmap(plat_data->base); + + r = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_region(r->start, resource_size(r)); + return 0; +} + +static struct platform_driver fh_gpio_driver = { + .driver = { + .name = GPIO_NAME, + .owner = THIS_MODULE, + }, + .probe = fh_gpio_probe, + .remove = __devexit_p(fh_gpio_remove), +}; + +static int __init fh_gpio_init(void) +{ + return platform_driver_register(&fh_gpio_driver); +} + +static void __exit fh_gpio_exit(void) +{ + platform_driver_unregister(&fh_gpio_driver); +} + +module_init(fh_gpio_init); +module_exit(fh_gpio_exit); + +MODULE_AUTHOR("QIN"); +MODULE_DESCRIPTION("FH GPIO Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform: FH"); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 646068e5..82347f92 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -298,7 +298,18 @@ config I2C_AT91 documented way to issue repeated START conditions, as needed to support combined I2C messages. Use the i2c-gpio driver unless your system can cope with those limitations. + +config I2C_FH_INTERRUPT + tristate "FH I2C Driver with Interrupt" + help + This supports the use of the I2C interface on Fullhan + processors. + + Only master mode is supported. + This driver can also be built as a module. If so, the module + will be called + config I2C_AU1550 tristate "Au1550/Au1200 SMBus interface" depends on SOC_AU1550 || SOC_AU1200 diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index e6cf294d..93dbee32 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -82,5 +82,6 @@ obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o obj-$(CONFIG_I2C_STUB) += i2c-stub.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o +obj-$(CONFIG_I2C_FH_INTERRUPT) += i2c_fh_interrupt.o ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG diff --git a/drivers/i2c/busses/i2c_fh_interrupt.c b/drivers/i2c/busses/i2c_fh_interrupt.c new file mode 100644 index 00000000..0c027f09 --- /dev/null +++ b/drivers/i2c/busses/i2c_fh_interrupt.c @@ -0,0 +1,928 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#define FH_I2C_DEBUG + +#ifdef FH_I2C_DEBUG +#define PRINT_DBG(fmt, args...) printk(fmt, ## args) +#else +#define PRINT_DBG(fmt, args...) do { } while (0) +#endif + +/* + * Registers offset + */ +#define DW_IC_CON 0x0 +#define DW_IC_TAR 0x4 +#define DW_IC_DATA_CMD 0x10 +#define DW_IC_SS_SCL_HCNT 0x14 +#define DW_IC_SS_SCL_LCNT 0x18 +#define DW_IC_FS_SCL_HCNT 0x1c +#define DW_IC_FS_SCL_LCNT 0x20 +#define DW_IC_INTR_STAT 0x2c +#define DW_IC_INTR_MASK 0x30 +#define DW_IC_RAW_INTR_STAT 0x34 +#define DW_IC_RX_TL 0x38 +#define DW_IC_TX_TL 0x3c +#define DW_IC_CLR_INTR 0x40 +#define DW_IC_CLR_RX_UNDER 0x44 +#define DW_IC_CLR_RX_OVER 0x48 +#define DW_IC_CLR_TX_OVER 0x4c +#define DW_IC_CLR_RD_REQ 0x50 +#define DW_IC_CLR_TX_ABRT 0x54 +#define DW_IC_CLR_RX_DONE 0x58 +#define DW_IC_CLR_ACTIVITY 0x5c +#define DW_IC_CLR_STOP_DET 0x60 +#define DW_IC_CLR_START_DET 0x64 +#define DW_IC_CLR_GEN_CALL 0x68 +#define DW_IC_ENABLE 0x6c +#define DW_IC_STATUS 0x70 +#define DW_IC_TXFLR 0x74 +#define DW_IC_RXFLR 0x78 +#define DW_IC_COMP_PARAM_1 0xf4 +#define DW_IC_TX_ABRT_SOURCE 0x80 + +#define DW_IC_CON_MASTER 0x1 +#define DW_IC_CON_SPEED_STD 0x2 +#define DW_IC_CON_SPEED_FAST 0x4 +#define DW_IC_CON_10BITADDR_MASTER 0x10 +#define DW_IC_CON_RESTART_EN 0x20 +#define DW_IC_CON_SLAVE_DISABLE 0x40 + +#define DW_IC_INTR_RX_UNDER 0x001 +#define DW_IC_INTR_RX_OVER 0x002 +#define DW_IC_INTR_RX_FULL 0x004 +#define DW_IC_INTR_TX_OVER 0x008 +#define DW_IC_INTR_TX_EMPTY 0x010 +#define DW_IC_INTR_RD_REQ 0x020 +#define DW_IC_INTR_TX_ABRT 0x040 +#define DW_IC_INTR_RX_DONE 0x080 +#define DW_IC_INTR_ACTIVITY 0x100 +#define DW_IC_INTR_STOP_DET 0x200 +#define DW_IC_INTR_START_DET 0x400 +#define DW_IC_INTR_GEN_CALL 0x800 + +#define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \ + DW_IC_INTR_TX_EMPTY | \ + DW_IC_INTR_TX_ABRT | \ + DW_IC_INTR_STOP_DET) + +#define DW_IC_STATUS_ACTIVITY 0x1 +#define DW_IC_STATUS_MASTER_ACTIVITY 0x20 + +#define DW_IC_ERR_TX_ABRT 0x1 + +/* + * status codes + */ +#define STATUS_IDLE 0x0 +#define STATUS_WRITE_IN_PROGRESS 0x1 +#define STATUS_READ_IN_PROGRESS 0x2 + +#define TIMEOUT 20 /* ms */ + +/* + * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register + * + * only expected abort codes are listed here + * refer to the datasheet for the full list + */ +#define ABRT_7B_ADDR_NOACK 0 +#define ABRT_10ADDR1_NOACK 1 +#define ABRT_10ADDR2_NOACK 2 +#define ABRT_TXDATA_NOACK 3 +#define ABRT_GCALL_NOACK 4 +#define ABRT_GCALL_READ 5 +#define ABRT_SBYTE_ACKDET 7 +#define ABRT_SBYTE_NORSTRT 9 +#define ABRT_10B_RD_NORSTRT 10 +#define ABRT_MASTER_DIS 11 +#define ARB_LOST 12 + +#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK) +#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK) +#define DW_IC_TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK) +#define DW_IC_TX_ABRT_TXDATA_NOACK (1UL << ABRT_TXDATA_NOACK) +#define DW_IC_TX_ABRT_GCALL_NOACK (1UL << ABRT_GCALL_NOACK) +#define DW_IC_TX_ABRT_GCALL_READ (1UL << ABRT_GCALL_READ) +#define DW_IC_TX_ABRT_SBYTE_ACKDET (1UL << ABRT_SBYTE_ACKDET) +#define DW_IC_TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT) +#define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT) +#define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS) +#define DW_IC_TX_ARB_LOST (1UL << ARB_LOST) + +#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \ + DW_IC_TX_ABRT_10ADDR1_NOACK | \ + DW_IC_TX_ABRT_10ADDR2_NOACK | \ + DW_IC_TX_ABRT_TXDATA_NOACK | \ + DW_IC_TX_ABRT_GCALL_NOACK) + +static char *abort_sources[] = { + [ABRT_7B_ADDR_NOACK] = + "slave address not acknowledged (7bit mode)", + [ABRT_10ADDR1_NOACK] = + "first address byte not acknowledged (10bit mode)", + [ABRT_10ADDR2_NOACK] = + "second address byte not acknowledged (10bit mode)", + [ABRT_TXDATA_NOACK] = + "data not acknowledged", + [ABRT_GCALL_NOACK] = + "no acknowledgement for a general call", + [ABRT_GCALL_READ] = + "read after general call", + [ABRT_SBYTE_ACKDET] = + "start byte acknowledged", + [ABRT_SBYTE_NORSTRT] = + "trying to send start byte when restart is disabled", + [ABRT_10B_RD_NORSTRT] = + "trying to read when restart is disabled (10bit mode)", + [ABRT_MASTER_DIS] = + "trying to use disabled adapter", + [ARB_LOST] = + "lost arbitration", +}; + +/** + * struct fh_i2c_dev - private i2c-designware data + * @dev: driver model device node + * @base: IO registers pointer + * @cmd_complete: tx completion indicator + * @lock: protect this struct and IO registers + * @clk: input reference clock + * @cmd_err: run time hadware error code + * @msgs: points to an array of messages currently being transferred + * @msgs_num: the number of elements in msgs + * @msg_write_idx: the element index of the current tx message in the msgs + * array + * @tx_buf_len: the length of the current tx buffer + * @tx_buf: the current tx buffer + * @msg_read_idx: the element index of the current rx message in the msgs + * array + * @rx_buf_len: the length of the current rx buffer + * @rx_buf: the current rx buffer + * @msg_err: error status of the current transfer + * @status: i2c master status, one of STATUS_* + * @abort_source: copy of the TX_ABRT_SOURCE register + * @irq: interrupt number for the i2c master + * @adapter: i2c subsystem adapter node + * @tx_fifo_depth: depth of the hardware tx fifo + * @rx_fifo_depth: depth of the hardware rx fifo + */ +struct fh_i2c_dev { + struct device *dev; + void __iomem *base; + struct completion cmd_complete; + struct mutex lock; + struct clk *clk; + int cmd_err; + struct i2c_msg *msgs; + int msgs_num; + int msg_write_idx; + u32 tx_buf_len; + u8 *tx_buf; + int msg_read_idx; + u32 rx_buf_len; + u8 *rx_buf; + int msg_err; + unsigned int status; + u32 abort_source; + int irq; + struct i2c_adapter adapter; + unsigned int tx_fifo_depth; + unsigned int rx_fifo_depth; +}; + + +static int i2c_fh_wait_master_not_active(struct fh_i2c_dev *dev) +{ + int timeout = 200; //2000 us + + while (I2c_IsActiveMst( dev->base)) + { + if (timeout <= 0) + { + dev_warn(dev->dev, "timeout waiting for master not active\n"); + return -ETIMEDOUT; + } + timeout--; + udelay(10); + } + + return 0; +} + +static u32 +i2c_fh_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset) +{ + /* + * DesignWare I2C core doesn't seem to have solid strategy to meet + * the tHD;STA timing spec. Configuring _HCNT based on tHIGH spec + * will result in violation of the tHD;STA spec. + */ + if (cond) + /* + * Conditional expression: + * + * IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH + * + * This is based on the DW manuals, and represents an ideal + * configuration. The resulting I2C bus speed will be + * faster than any of the others. + * + * If your hardware is free from tHD;STA issue, try this one. + */ + return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset; + else + /* + * Conditional expression: + * + * IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf) + * + * This is just experimental rule; the tHD;STA period turned + * out to be proportinal to (_HCNT + 3). With this setting, + * we could meet both tHIGH and tHD;STA timing specs. + * + * If unsure, you'd better to take this alternative. + * + * The reason why we need to take into account "tf" here, + * is the same as described in i2c_fh_scl_lcnt(). + */ + return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset; +} + +static u32 i2c_fh_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) +{ + /* + * Conditional expression: + * + * IC_[FS]S_SCL_LCNT + 1 >= IC_CLK * (tLOW + tf) + * + * DW I2C core starts counting the SCL CNTs for the LOW period + * of the SCL clock (tLOW) as soon as it pulls the SCL line. + * In order to meet the tLOW timing spec, we need to take into + * account the fall time of SCL signal (tf). Default tf value + * should be 0.3 us, for safety. + */ + return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset; +} + +/** + * i2c_fh_init() - initialize the designware i2c master hardware + * @dev: device private data + * + * This functions configures and enables the I2C master. + * This function is called during I2C init function, and in case of timeout at + * run time. + */ +static void i2c_fh_init(struct fh_i2c_dev *dev) +{ + u32 input_clock_khz = clk_get_rate(dev->clk) / 1000; + u32 ic_con, hcnt, lcnt; + + /* Disable the adapter */ + i2c_fh_wait_master_not_active(dev); + I2c_DisEnable((unsigned int)dev->base); + + /* set standard and fast speed deviders for high/low periods */ + + /* Standard-mode */ + hcnt = i2c_fh_scl_hcnt(input_clock_khz, + 40, /* tHD;STA = tHIGH = 4.0 us */ + 3, /* tf = 0.3 us */ + 0, /* 0: DW default, 1: Ideal */ + 0); /* No offset */ + lcnt = i2c_fh_scl_lcnt(input_clock_khz, + 47, /* tLOW = 4.7 us */ + 3, /* tf = 0.3 us */ + 0); /* No offset */ + I2c_SetSsHcnt( dev->base ,hcnt); + I2c_SetSsLcnt( dev->base ,lcnt); + pr_info("\tClock: %dkhz, Standard-mode HCNT:LCNT = %d:%d\n", input_clock_khz, hcnt, lcnt); + + /* Fast-mode */ + hcnt = i2c_fh_scl_hcnt(input_clock_khz, + 6, /* tHD;STA = tHIGH = 0.6 us */ + 3, /* tf = 0.3 us */ + 0, /* 0: DW default, 1: Ideal */ + 0); /* No offset */ + lcnt = i2c_fh_scl_lcnt(input_clock_khz, + 13, /* tLOW = 1.3 us */ + 3, /* tf = 0.3 us */ + 0); /* No offset */ + I2c_SetFsHcnt( dev->base ,hcnt); + I2c_SetFsLcnt( dev->base ,lcnt); + //dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); + + /* Configure Tx/Rx FIFO threshold levels */ + + I2c_SetTxRxTl(dev->base ,dev->tx_fifo_depth - 1,0); + /* configure the i2c master */ + ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | + /*DW_IC_CON_RESTART_EN |*/ DW_IC_CON_SPEED_FAST;/// DW_IC_CON_SPEED_STD; + I2c_SetCon(dev->base,ic_con); + +} + +/* + * Waiting for bus not busy + */ +static int i2c_fh_wait_bus_not_busy(struct fh_i2c_dev *dev) +{ + int timeout = TIMEOUT; + + while (I2c_IsActiveMst( dev->base)) { + if (timeout <= 0) { + dev_warn(dev->dev, "timeout waiting for bus ready\n"); + return -ETIMEDOUT; + } + timeout--; + msleep(1); + } + + return 0; +} + +static void i2c_fh_xfer_init(struct fh_i2c_dev *dev) +{ + struct i2c_msg *msgs = dev->msgs; + u32 ic_con; + + /* Disable the adapter */ + i2c_fh_wait_master_not_active(dev); + I2c_DisEnable((unsigned int)dev->base); + + /* set the slave (target) address */ + I2c_SetDeviceId(dev->base,msgs[dev->msg_write_idx].addr); + + /* if the slave address is ten bit address, enable 10BITADDR */ + ic_con = I2c_GetCon(dev->base); + if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) + ic_con |= DW_IC_CON_10BITADDR_MASTER; + else + ic_con &= ~DW_IC_CON_10BITADDR_MASTER; + I2c_SetCon(dev->base,ic_con); + + /* Enable the adapter */ + I2c_Enable(dev->base); + + /* Enable interrupts */ + I2c_SetIntrMask(dev->base,DW_IC_INTR_DEFAULT_MASK); + +} + +/* + * Initiate (and continue) low level master read/write transaction. + * This function is only called from i2c_fh_isr, and pumping i2c_msg + * messages into the tx buffer. Even if the size of i2c_msg data is + * longer than the size of the tx buffer, it handles everything. + */ +static void +i2c_fh_xfer_msg(struct fh_i2c_dev *dev) +{ + struct i2c_msg *msgs = dev->msgs; + u32 intr_mask, cmd; + int tx_limit, rx_limit; + u32 addr = msgs[dev->msg_write_idx].addr; + u32 buf_len = dev->tx_buf_len; + u8 *buf = dev->tx_buf;; + + PRINT_DBG("i2c_fh_xfer_msg start, dev->msgs_num: %d\n", dev->msgs_num); + + intr_mask = DW_IC_INTR_DEFAULT_MASK; + + for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) + { + /* + * if target address has changed, we need to + * reprogram the target address in the i2c + * adapter when we are done with this transfer + */ + if (msgs[dev->msg_write_idx].addr != addr) { + dev_err(dev->dev, + "%s: invalid target address\n", __func__); + dev->msg_err = -EINVAL; + break; + } + + if (msgs[dev->msg_write_idx].len == 0) { + dev_err(dev->dev, + "%s: invalid message length\n", __func__); + dev->msg_err = -EINVAL; + break; + } + + if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) + { + /* new i2c_msg */ + buf = msgs[dev->msg_write_idx].buf; + buf_len = msgs[dev->msg_write_idx].len; + + PRINT_DBG("new msg: len: %d, buf: 0x%x\n", buf_len, buf[0]); + } + + tx_limit = dev->tx_fifo_depth - I2c_GetTxTl(dev->base ); + rx_limit = dev->rx_fifo_depth - I2c_GetRxTl(dev->base ); + + while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) + { + if (msgs[dev->msg_write_idx].flags & I2C_M_RD) + { + cmd = 0x100; + rx_limit--; + } + else + { + cmd = *buf++; + } + + tx_limit--; buf_len--; + + if(!buf_len) + cmd |= 0x200; + + I2c_Write(dev->base, cmd); + } + PRINT_DBG("\n"); + + dev->tx_buf = buf; + dev->tx_buf_len = buf_len; + + if (buf_len > 0) + { + /* more bytes to be written */ + dev->status |= STATUS_WRITE_IN_PROGRESS; + break; + } + else + { + dev->status &= ~STATUS_WRITE_IN_PROGRESS; + } + } + + /* + * If i2c_msg index search is completed, we don't need TX_EMPTY + * interrupt any more. + */ + + if (dev->msg_write_idx == dev->msgs_num) + intr_mask &= ~DW_IC_INTR_TX_EMPTY; + + if (dev->msg_err) + intr_mask = 0; + + I2c_SetIntrMask(dev->base,intr_mask); + +} + +static void +i2c_fh_read(struct fh_i2c_dev *dev) +{ + struct i2c_msg *msgs = dev->msgs; + int rx_valid; + + for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) + { + u32 len; + u8 *buf; + + if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD)) + continue; + + if (!(dev->status & STATUS_READ_IN_PROGRESS)) + { + len = msgs[dev->msg_read_idx].len; + buf = msgs[dev->msg_read_idx].buf; + } + else + { + PRINT_DBG("STATUS_READ_IN_PROGRESS\n"); + len = dev->rx_buf_len; + buf = dev->rx_buf; + } + + rx_valid = I2c_GetRxFLR(dev->base); + + if(rx_valid == 0) + { + PRINT_DBG("rx_valid == 0\n"); + } + + for (; len > 0 && rx_valid > 0; len--, rx_valid--) + { + *buf++ = I2c_Read(dev->base); + } + + PRINT_DBG("i2c_fh_read, len: %d, buf[0]: 0x%x\n", msgs[dev->msg_read_idx].len, msgs[dev->msg_read_idx].buf[0]); + + if (len > 0) + { + PRINT_DBG("len > 0\n"); + dev->status |= STATUS_READ_IN_PROGRESS; + dev->rx_buf_len = len; + dev->rx_buf = buf; + return; + } else + dev->status &= ~STATUS_READ_IN_PROGRESS; + } +} + +static int i2c_fh_handle_tx_abort(struct fh_i2c_dev *dev) +{ + unsigned long abort_source = dev->abort_source; + int i; + + if (abort_source & DW_IC_TX_ABRT_NOACK) { + for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) + { + PRINT_DBG( + "%s: %s\n", __func__, abort_sources[i]); + } + return -EREMOTEIO; + } + + for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources)) + dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]); + + if (abort_source & DW_IC_TX_ARB_LOST) + return -EAGAIN; + else if (abort_source & DW_IC_TX_ABRT_GCALL_READ) + return -EINVAL; /* wrong msgs[] data */ + else + return -EIO; +} + +/* + * Prepare controller for a transaction and call i2c_fh_xfer_msg + */ +static int +i2c_fh_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct fh_i2c_dev *dev = i2c_get_adapdata(adap); + int ret; + + PRINT_DBG("-------i2c, %s: msgs: %d\n", __func__, num); + + mutex_lock(&dev->lock); + + INIT_COMPLETION(dev->cmd_complete); + dev->msgs = msgs; + dev->msgs_num = num; + dev->cmd_err = 0; + dev->msg_write_idx = 0; + dev->msg_read_idx = 0; + dev->msg_err = 0; + dev->status = STATUS_IDLE; + dev->abort_source = 0; + + ret = i2c_fh_wait_bus_not_busy(dev); + if (ret < 0) + { + goto done; + } + + /* start the transfers */ + i2c_fh_xfer_init(dev); + + /* wait for tx to complete */ + ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ); + if (ret == 0) { + dev_err(dev->dev, "controller timed out\n"); + i2c_fh_init(dev); + ret = -ETIMEDOUT; + goto done; + } else if (ret < 0) + goto done; + + if (dev->msg_err) + { + PRINT_DBG("dev->msg_err\n"); + ret = dev->msg_err; + goto done; + } + + /* no error */ + if (likely(!dev->cmd_err)) { + /* Disable the adapter */ + i2c_fh_wait_master_not_active(dev); + I2c_DisEnable(dev->base); + ret = num; + goto done; + } + + /* We have an error */ + if (dev->cmd_err == DW_IC_ERR_TX_ABRT) + { + PRINT_DBG("dev->cmd_err == DW_IC_ERR_TX_ABRT\n"); + ret = i2c_fh_handle_tx_abort(dev); + goto done; + } + + ret = -EIO; + +done: + PRINT_DBG("buf: 0x%x\n", dev->msgs[num - 1].buf[0]); + mutex_unlock(&dev->lock); + + return ret; +} + +static u32 i2c_fh_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK; +} + +static u32 i2c_fh_read_clear_intrbits(struct fh_i2c_dev *dev) +{ + u32 stat; + + /* + * The IC_INTR_STAT register just indicates "enabled" interrupts. + * Ths unmasked raw version of interrupt status bits are available + * in the IC_RAW_INTR_STAT register. + * + * That is, + * stat = readl(IC_INTR_STAT); + * equals to, + * stat = readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK); + * + * The raw version might be useful for debugging purposes. + */ + stat = readl(dev->base + DW_IC_INTR_STAT); + + /* + * Do not use the IC_CLR_INTR register to clear interrupts, or + * you'll miss some interrupts, triggered during the period from + * readl(IC_INTR_STAT) to readl(IC_CLR_INTR). + * + * Instead, use the separately-prepared IC_CLR_* registers. + */ + if (stat & DW_IC_INTR_RX_UNDER) + I2c_ClrIntr(dev->base,DW_IC_CLR_RX_UNDER); + if (stat & DW_IC_INTR_RX_OVER) + I2c_ClrIntr(dev->base , DW_IC_CLR_RX_OVER); + if (stat & DW_IC_INTR_TX_OVER) + I2c_ClrIntr(dev->base , DW_IC_CLR_TX_OVER); + if (stat & DW_IC_INTR_RD_REQ) + I2c_ClrIntr(dev->base , DW_IC_CLR_RD_REQ); + if (stat & DW_IC_INTR_TX_ABRT) { + /* + * The IC_TX_ABRT_SOURCE register is cleared whenever + * the IC_CLR_TX_ABRT is read. Preserve it beforehand. + */ + dev->abort_source = readl(dev->base + DW_IC_TX_ABRT_SOURCE); + I2c_ClrIntr(dev->base , DW_IC_CLR_TX_ABRT); + } + if (stat & DW_IC_INTR_RX_DONE) + I2c_ClrIntr(dev->base ,DW_IC_CLR_RX_DONE); + if (stat & DW_IC_INTR_ACTIVITY) + I2c_ClrIntr(dev->base ,DW_IC_CLR_ACTIVITY); + if (stat & DW_IC_INTR_STOP_DET) + I2c_ClrIntr(dev->base , DW_IC_CLR_STOP_DET); + if (stat & DW_IC_INTR_START_DET) + I2c_ClrIntr(dev->base , DW_IC_CLR_START_DET); + if (stat & DW_IC_INTR_GEN_CALL) + I2c_ClrIntr(dev->base , DW_IC_CLR_GEN_CALL); + + return stat; +} + +/* + * Interrupt service routine. This gets called whenever an I2C interrupt + * occurs. + */ +static irqreturn_t i2c_fh_isr(int this_irq, void *dev_id) +{ + struct fh_i2c_dev *dev = dev_id; + u32 stat; + + stat = i2c_fh_read_clear_intrbits(dev); + PRINT_DBG("-----------i2c, %s: stat=0x%x\n", __func__, stat); + + if (stat & DW_IC_INTR_TX_ABRT) + { + PRINT_DBG("DW_IC_INTR_TX_ABRT\n"); + dev->cmd_err |= DW_IC_ERR_TX_ABRT; + dev->status = STATUS_IDLE; + + /* + * Anytime TX_ABRT is set, the contents of the tx/rx + * buffers are flushed. Make sure to skip them. + */ + I2c_SetIntrMask( dev->base,DW_IC_INTR_NONE); + goto tx_aborted; + } + + if (stat & DW_IC_INTR_RX_FULL) + { + PRINT_DBG("i2c_fh_read\n"); + i2c_fh_read(dev); + } + + if (stat & DW_IC_INTR_TX_EMPTY) + { + PRINT_DBG("i2c_fh_xfer_msg\n"); + i2c_fh_xfer_msg(dev); + } + + /* + * No need to modify or disable the interrupt mask here. + * i2c_fh_xfer_msg() will take care of it according to + * the current transmit status. + */ + +tx_aborted: + if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) + complete(&dev->cmd_complete); + + return IRQ_HANDLED; +} + +static struct i2c_algorithm i2c_fh_algo = +{ + .master_xfer = i2c_fh_xfer, + .functionality = i2c_fh_func, +}; + +static int __devinit fh_i2c_probe(struct platform_device *pdev) +{ + struct fh_i2c_dev *dev; + struct i2c_adapter *adap; + struct resource *mem, *ioarea; + int irq, r; + + pr_info("I2C driver:\n\tplatform registration... "); + + /* NOTE: driver uses the static register mapping */ + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + { + dev_err(&pdev->dev, "no mem resource?\n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + { + dev_err(&pdev->dev, "no irq resource?\n"); + return irq; /* -ENXIO */ + } + + ioarea = request_mem_region(mem->start, resource_size(mem), + pdev->name); + if (!ioarea) + { + dev_err(&pdev->dev, "I2C region already claimed\n"); + return -EBUSY; + } + + dev = kzalloc(sizeof(struct fh_i2c_dev), GFP_KERNEL); + if (!dev) + { + r = -ENOMEM; + goto err_release_region; + } + + init_completion(&dev->cmd_complete); + mutex_init(&dev->lock); + dev->dev = get_device(&pdev->dev); + dev->irq = irq; + platform_set_drvdata(pdev, dev); + + if(pdev->id) + dev->clk = clk_get(NULL, "i2c1_clk"); + else + dev->clk = clk_get(NULL, "i2c0_clk"); + + + if (IS_ERR(dev->clk)) + { + r = -ENODEV; + goto err_free_mem; + } + clk_enable(dev->clk); + + dev->base = ioremap(mem->start, resource_size(mem)); + if (dev->base == NULL) + { + dev_err(&pdev->dev, "failure mapping io resources\n"); + r = -ENOMEM; + goto err_unuse_clocks; + } + { + dev->tx_fifo_depth = I2c_GetTxFifoDepth(dev->base); + dev->rx_fifo_depth = I2c_GetRxFifoDepth(dev->base); + } + i2c_fh_init(dev); + + pr_info("\ttx fifo depth: %d, rx fifo depth: %d\n", dev->tx_fifo_depth, dev->rx_fifo_depth); + + I2c_SetIntrMask( dev->base,DW_IC_INTR_NONE); /* disable IRQ */ + r = request_irq(dev->irq, i2c_fh_isr, IRQF_DISABLED, pdev->name, dev); + if (r) + { + dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); + goto err_iounmap; + } + + adap = &dev->adapter; + i2c_set_adapdata(adap, dev); + adap->owner = THIS_MODULE; + adap->class = I2C_CLASS_HWMON; + strlcpy(adap->name, "FH I2C adapter", + sizeof(adap->name)); + adap->algo = &i2c_fh_algo; + adap->dev.parent = &pdev->dev; + + adap->nr = pdev->id; + r = i2c_add_numbered_adapter(adap); + if (r) { + dev_err(&pdev->dev, "failure adding adapter\n"); + goto err_free_irq; + } + + pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n" + "\t\tIO base addr: 0x%p)\n", "I2C", pdev->name, + pdev->id, dev->irq, dev->base); + + return 0; + +err_free_irq: + free_irq(dev->irq, dev); +err_iounmap: + iounmap(dev->base); +err_unuse_clocks: + clk_disable(dev->clk); + clk_put(dev->clk); + dev->clk = NULL; +err_free_mem: + platform_set_drvdata(pdev, NULL); + put_device(&pdev->dev); + kfree(dev); +err_release_region: + release_mem_region(mem->start, resource_size(mem)); + + return r; +} + +static int __devexit fh_i2c_remove(struct platform_device *pdev) +{ + struct fh_i2c_dev *dev = platform_get_drvdata(pdev); + struct resource *mem; + + platform_set_drvdata(pdev, NULL); + i2c_del_adapter(&dev->adapter); + put_device(&pdev->dev); + + clk_disable(dev->clk); + clk_put(dev->clk); + dev->clk = NULL; + i2c_fh_wait_master_not_active(dev); + writel(0, dev->base + DW_IC_ENABLE); + free_irq(dev->irq, dev); + kfree(dev); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mem->start, resource_size(mem)); + return 0; +} + +static struct platform_driver fh_i2c_driver = +{ + .remove = __devexit_p(fh_i2c_remove), + .driver = + { + .name = "fh_i2c", + .owner = THIS_MODULE, + }, +}; + +static int __init fh_i2c_init_driver(void) +{ + return platform_driver_probe(&fh_i2c_driver, fh_i2c_probe); +} +module_init(fh_i2c_init_driver); + +static void __exit fh_i2c_exit_driver(void) +{ + platform_driver_unregister(&fh_i2c_driver); +} +module_exit(fh_i2c_exit_driver); + +MODULE_AUTHOR("QIN"); +MODULE_ALIAS("platform:fh"); +MODULE_DESCRIPTION("FH I2C bus adapter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 35464744..9d4eb336 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -157,6 +157,8 @@ config INTEL_MID_PTI an Intel Atom (non-netbook) mobile device containing a MIPI P1149.7 standard implementation. + + config SGI_IOC4 tristate "SGI IOC4 Base IO support" depends on PCI @@ -404,6 +406,60 @@ config EP93XX_PWM To compile this driver as a module, choose M here: the module will be called ep93xx_pwm. +config FH_I2S_SLAVE + depends on ARCH_FH8830 || ARCH_FH8833 + tristate "FH I2S SLAVE MODE support" + default n + +config FH_I2S_MASTER + depends on ARCH_FH8833 + tristate "FH I2S MASTER MODE support" + default n + + + + +config FH_PINCTRL + tristate "FH Pinctrl support" + default n + help + To compile this driver as a module, choose M here: the module will + be called. + + +config FH_SADC + depends on ARCH_FULLHAN + tristate "FH SADC support" + help + To compile this driver as a module, choose M here: the module will + be called fh_sadc. + + HW para:10bits precision, 8 channels, 5M clk in. + one conversion need almost (12/5M *1)second + + +config FH_FIRMWARE_LOADER + tristate "Enable FH firmware loader" + default m + help + enable firmware loader + +config FH_EFUSE + tristate "FH EFUSE support" + help + To compile this driver as a module, choose M here: the module will + be called fh_efuse. + + HW para:60 bytes could be programmed. + the "efuse2aes map" is fixed by hardware..EX. 0~4 : aes key0, 5~8 : aes key1. + +config FH_CLK_MISC + tristate "FH clk miscdev support" + default n + help + To compile this driver as a module, choose M here: the module will + be called. + config DS1682 tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm" depends on I2C && EXPERIMENTAL diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 5f03172c..f12fef3c 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o 0bj-$(CONFIG_INTEL_MID_PTI) += pti.o obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o +obj-$(CONFIG_ATMEL_ACW) += atmel-acw.o obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o obj-$(CONFIG_BMP085) += bmp085.o obj-$(CONFIG_ICS932S401) += ics932s401.o @@ -31,6 +32,15 @@ obj-$(CONFIG_ISL29003) += isl29003.o obj-$(CONFIG_ISL29020) += isl29020.o obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o +obj-$(CONFIG_FH_PINCTRL) += fh_pinctrl_dev.o +obj-$(CONFIG_FH_I2S_MASTER) += fh_dw_i2s.o +obj-$(CONFIG_FH_I2S_SLAVE) += fh_i2s.o +obj-$(CONFIG_FH_SADC) += fh_sadc.o + +obj-$(CONFIG_FH_FIRMWARE_LOADER) += fh_fw_loader.o + +obj-$(CONFIG_FH_EFUSE) += fh_efuse.o + obj-$(CONFIG_DS1682) += ds1682.o obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o obj-$(CONFIG_C2PORT) += c2port/ @@ -46,3 +56,5 @@ obj-y += ti-st/ obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o obj-y += lis3lv02d/ obj-y += carma/ +obj-$(CONFIG_FH_DMAC_MISC) += fh_dma_miscdev.o +obj-$(CONFIG_FH_CLK_MISC) += fh_clk_miscdev.o diff --git a/drivers/misc/fh_clk_miscdev.c b/drivers/misc/fh_clk_miscdev.c new file mode 100644 index 00000000..a6a7ca90 --- /dev/null +++ b/drivers/misc/fh_clk_miscdev.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fh_clk_miscdev.h" + +//#define FH_CLK_DEBUG + +#if defined(FH_CLK_DEBUG) +#define PRINT_CLK_DBG(fmt, args...) \ + do \ + { \ + printk("FH_CLK_DEBUG: "); \ + printk(fmt, ##args); \ + } while (0) +#else +#define PRINT_CLK_DBG(fmt, args...) \ + do \ + { \ + } while (0) +#endif + +static int fh_clk_miscdev_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int fh_clk_miscdev_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static long fh_clk_miscdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret = -ENODEV; + struct clk *clk; + struct clk_usr uclk; + + if (unlikely(_IOC_TYPE(cmd) != CLK_IOCTL_MAGIC)) + { + pr_err("%s: ERROR: incorrect magic num %d (error: %d)\n", + __func__, _IOC_TYPE(cmd), -ENOTTY); + return -ENOTTY; + } + + if (unlikely(_IOC_NR(cmd) > CLK_IOCTL_MAXNR)) + { + pr_err("%s: ERROR: incorrect cmd num %d (error: %d)\n", + __func__, _IOC_NR(cmd), -ENOTTY); + return -ENOTTY; + } + + if (_IOC_DIR(cmd) & _IOC_READ) + { + ret = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + } + else if(_IOC_DIR(cmd) & _IOC_WRITE) + { + ret = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + } + + if(ret) + { + pr_err("%s: ERROR: user space access is not permitted %d (error: %d)\n", + __func__, _IOC_NR(cmd), -EACCES); + return -EACCES; + } + + if (copy_from_user((void *)&uclk, (void __user *)arg, + sizeof(struct clk_usr))) + return -EFAULT; + + switch(cmd) + { + case ENABLE_CLK: + clk = clk_get(NULL, uclk.name); + if(!IS_ERR(clk)) + { + clk_enable(clk); + ret = 0; + } + break; + case DISABLE_CLK: + clk = clk_get(NULL, uclk.name); + if(!IS_ERR(clk)) + { + clk_disable(clk); + ret = 0; + } + break; + case SET_CLK_RATE: + clk = clk_get(NULL, uclk.name); + ret = PTR_ERR(clk); + if(!IS_ERR(clk)) + { + ret = clk_set_rate(clk, uclk.frequency); + } + PRINT_CLK_DBG("%s, set clk: %s, rate: %lu\n", + __func__, uclk.name, uclk.frequency); + break; + case GET_CLK_RATE: + clk = clk_get(NULL, uclk.name); + ret = PTR_ERR(clk); + if(!IS_ERR(clk)) + { + uclk.frequency = clk_get_rate(clk); + ret = 0; + } + PRINT_CLK_DBG("%s, get clk: %s, rate: %lu\n",__func__, + uclk.name, uclk.frequency); + if (copy_to_user((void __user *)arg, (void *)&uclk, + sizeof(struct clk_usr))) + return -EFAULT; + } + + + return ret; +} + +static const struct file_operations fh_clk_fops = +{ + .owner = THIS_MODULE, + .open = fh_clk_miscdev_open, + .release = fh_clk_miscdev_release, + .unlocked_ioctl = fh_clk_miscdev_ioctl, +}; + +static struct miscdevice fh_clk_miscdev = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = DEVICE_NAME, + .fops = &fh_clk_fops, +}; + +int __init fh_clk_miscdev_init(void) +{ + int err; + + err = misc_register(&fh_clk_miscdev); + + if(err < 0) + { + pr_err("%s: ERROR: %s registration failed, ret=%d", + __func__, DEVICE_NAME, err); + return -ENXIO; + } + + pr_info("CLK misc driver init successfully\n"); + return 0; +} + + +static void __exit fh_clk_miscdev_exit(void) +{ + misc_deregister(&fh_clk_miscdev); +} +module_init(fh_clk_miscdev_init); +module_exit(fh_clk_miscdev_exit); + +MODULE_AUTHOR("QIN"); +MODULE_DESCRIPTION("Misc Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform: FH"); diff --git a/drivers/misc/fh_clk_miscdev.h b/drivers/misc/fh_clk_miscdev.h new file mode 100644 index 00000000..ce405554 --- /dev/null +++ b/drivers/misc/fh_clk_miscdev.h @@ -0,0 +1,10 @@ + +#ifndef FH_CLK_MISCDEV_H_ +#define FH_CLK_MISCDEV_H_ + +#include + +#define DEVICE_NAME "fh_clk_miscdev" + + +#endif /* FH_CLK_MISCDEV_H_ */ diff --git a/drivers/misc/fh_dma_miscdev.c b/drivers/misc/fh_dma_miscdev.c new file mode 100644 index 00000000..7fad61de --- /dev/null +++ b/drivers/misc/fh_dma_miscdev.c @@ -0,0 +1,363 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "fh_dma_miscdev.h" + +#define MEMCPY_UNIT (4095 * 4 * 64) //4095 xfer * 32-bit * 64 desc + +//#define FH_DMA_DEBUG + +#ifdef FH_DMA_DEBUG +#define PRINT_DMA_DBG(fmt, args...) \ + do \ + { \ + printk("FH_DMA_DEBUG: "); \ + printk(fmt, ## args); \ + } \ + while(0) +#else +#define PRINT_DMA_DBG(fmt, args...) do { } while (0) +#endif + + +static void fh_dma_callback(void *data) +{ + PRINT_DMA_DBG("dma transfer done, end=%lu\n", jiffies); + complete(data); +} + +static int kick_off_dma(struct dma_chan *channel, unsigned int src_offset, unsigned int dst_offset, unsigned int size) +{ + int ret; + struct completion cmp; + struct dma_async_tx_descriptor *dma_tx_desc = NULL; + struct dma_device *dma_dev = channel->device; + dma_cookie_t cookie; + unsigned long timeout; + unsigned long flag; + + flag = DMA_CTRL_ACK | DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SKIP_SRC_UNMAP; + + PRINT_DMA_DBG("try to copy 0x%x bytes: 0x%x --> 0x%x\n", MEMCPY_UNIT, src_offset, dst_offset); + + dma_tx_desc = dma_dev->device_prep_dma_memcpy(channel, dst_offset, src_offset, size, flag); + + PRINT_DMA_DBG("device_prep_dma_memcpy end\n"); + + if(!dma_tx_desc) + { + pr_err("ERROR: %s, device_prep_dma_memcpy fail\n", __func__); + ret = -ENODEV; + return ret; + } + + init_completion(&cmp); + dma_tx_desc->callback = fh_dma_callback; + dma_tx_desc->callback_param = &cmp; + PRINT_DMA_DBG("tx_submit start\n"); + cookie = dma_tx_desc->tx_submit(dma_tx_desc); + PRINT_DMA_DBG("tx_submit end\n"); + if (dma_submit_error(cookie)) + { + pr_err("ERROR: %s, tx_submit fail\n", __func__); + ret = -ENODEV; + return ret; + } + PRINT_DMA_DBG("dma_async_issue_pending start\n"); + dma_async_issue_pending(channel); + PRINT_DMA_DBG("dma_async_issue_pending end, %d\n", DMA_MEMCPY_TIMEOUT); + + timeout = wait_for_completion_timeout(&cmp, msecs_to_jiffies(DMA_MEMCPY_TIMEOUT)); + + PRINT_DMA_DBG("wait_for_completion_timeout end, timeout: %lu\n", timeout); + + if(!timeout) + { + pr_err("ERROR: %s, dma transfer fail, timeout\n", __func__); + ret = -ENODEV; + return ret; + } + + ret = dma_async_is_tx_complete(channel, cookie, NULL, NULL); + + if(ret) + { + pr_err("ERROR: %s, dma transfer fail, incorrect status: %d\n", __func__, ret); + ret = -ENODEV; + return ret; + } + + return 0; +} + + +static int fh_dma_start_transfer(struct dma_chan *channel, struct dma_memcpy* memcpy) +{ + int ret; + unsigned int i; + + for(i=0; isize / MEMCPY_UNIT; i++) + { + ret = kick_off_dma(channel, memcpy->src_addr_phy + MEMCPY_UNIT*i, memcpy->dst_addr_phy + MEMCPY_UNIT*i, MEMCPY_UNIT); + if(ret) + { + return ret; + } + } + + ret = kick_off_dma(channel, memcpy->src_addr_phy + MEMCPY_UNIT*i, memcpy->dst_addr_phy + MEMCPY_UNIT*i, memcpy->size % MEMCPY_UNIT); + return ret; +} + + +static bool chan_filter(struct dma_chan *chan, void *param) +{ + struct dma_memcpy* memcpy = param; + PRINT_DMA_DBG("chan_filter, channel id: %d\n", memcpy->chan_id); + if(memcpy->chan_id < 0) + { + return false; + } + + if(memcpy->chan_id == chan->chan_id) + { + return true; + } + else + { + return false; + } + +} + +static int fh_dma_memcpy(struct dma_memcpy* memcpy) +{ + //fixme: ioctl should be atomic, otherwise channel will be changed. + struct dma_chan *dma_channel; + dma_cap_mask_t mask; + int ret; + + PRINT_DMA_DBG("fh_dma_memcpy start\n"); + PRINT_DMA_DBG("ioctl, memcpy->size: 0x%x\n", memcpy->size); + + + PRINT_DMA_DBG("fh_dma_request_channel start\n"); + dma_cap_zero(mask); + PRINT_DMA_DBG("dma_cap_zero end\n"); + dma_cap_set(DMA_MEMCPY, mask); + PRINT_DMA_DBG("dma_cap_set end\n"); + + dma_channel = dma_request_channel(mask, chan_filter, memcpy); + + PRINT_DMA_DBG("dma_request_channel finished, channel_addr: 0x%x\n", (u32)dma_channel); + + if(!dma_channel) + { + pr_err("ERROR: %s, No Channel Available, channel: %d\n", __func__, memcpy->chan_id); + return -EBUSY; + } + memcpy->chan_id = dma_channel->chan_id; + PRINT_DMA_DBG("dma channel name: %s\n", dma_chan_name(dma_channel)); + + ret = fh_dma_start_transfer(dma_channel, memcpy); + + if(ret) + { + pr_err("ERROR: %s, DMA Xfer Failed\n", __func__); + } + + dma_channel->device->device_free_chan_resources(dma_channel); + dma_release_channel(dma_channel); + + return ret; +} + +static long fh_dma_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct dma_memcpy memcpy; + + + if (unlikely(_IOC_TYPE(cmd) != DMA_IOCTL_MAGIC)) + { + pr_err("%s: ERROR: incorrect magic num %d (error: %d)\n", + __func__, _IOC_TYPE(cmd), -ENOTTY); + return -ENOTTY; + } + + if (unlikely(_IOC_NR(cmd) > DMA_IOCTL_MAXNR)) + { + pr_err("%s: ERROR: incorrect cmd num %d (error: %d)\n", + __func__, _IOC_NR(cmd), -ENOTTY); + return -ENOTTY; + } + + if (_IOC_DIR(cmd) & _IOC_READ) + { + ret = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + } + else if(_IOC_DIR(cmd) & _IOC_WRITE) + { + ret = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + } + + if(ret) + { + pr_err("%s: ERROR: user space access is not permitted %d (error: %d)\n", + __func__, _IOC_NR(cmd), -EACCES); + return -EACCES; + } + + switch(cmd) + { + + case DMA_MEMCOPY: + if(copy_from_user((void *)&memcpy, + (void __user *)arg, + sizeof(struct dma_memcpy))) + { + return -EFAULT; + } + ret = fh_dma_memcpy(&memcpy); + break; + } + + return ret; +} + +static int fh_dma_open(struct inode *inode, struct file *file) +{ + PRINT_DMA_DBG("fh_dma_open\n"); + return 0; +} + +static int fh_dma_release(struct inode *inode, struct file *filp) +{ + PRINT_DMA_DBG("fh_dma_release\n"); + return 0; +} + + +static void *v_seq_start(struct seq_file *s, loff_t *pos) +{ + static unsigned long counter = 0; + if (*pos == 0) + return &counter; + else + { + *pos = 0; + return NULL; + } +} + +static void *v_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + (*pos)++; + return NULL; +} + +static void v_seq_stop(struct seq_file *s, void *v) +{ + +} + +static int v_seq_show(struct seq_file *sfile, void *v) +{ + + seq_printf(sfile, "\nISP Status\n"); + seq_printf(sfile, "\nCTRL: \n"); + +#if 0 + int i; + u32 data; + seq_printf(sfile, "ipf reg:\n"); + for(i=0; i<10; i++) + { + data = GET_IPF_REG_V(i*4); + seq_printf(sfile, "0x%05x, 0x%08x\n", i*4, data); + } +#endif + + return 0; +} + +static const struct seq_operations fh_dma_seq_ops = +{ + .start = v_seq_start, + .next = v_seq_next, + .stop = v_seq_stop, + .show = v_seq_show +}; + +static int isp_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &fh_dma_seq_ops); +} + +static struct file_operations fh_dma_proc_ops = +{ + .owner = THIS_MODULE, + .open = isp_proc_open, + .read = seq_read, +}; + +static const struct file_operations fh_dma_fops = +{ + .owner = THIS_MODULE, + .open = fh_dma_open, + .release = fh_dma_release, + .unlocked_ioctl = fh_dma_ioctl, +}; + +static struct miscdevice fh_dma_device = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = DEVICE_NAME, + .fops = &fh_dma_fops, +}; + +static int __init fh_dma_init(void) +{ + int ret; + struct proc_dir_entry *proc_file; + ret = misc_register(&fh_dma_device); + + if(ret < 0) + { + pr_err("%s: ERROR: %s registration failed", + __func__, DEVICE_NAME); + return -ENXIO; + } + + proc_file = create_proc_entry(PROC_FILE, 0644, NULL); + + if (proc_file) + proc_file->proc_fops = &fh_dma_proc_ops; + else + pr_err("%s: ERROR: %s proc file create failed", + __func__, DEVICE_NAME); + + + return ret; +} + +static void __exit fh_dma_exit(void) +{ + remove_proc_entry(PROC_FILE, NULL); + misc_deregister(&fh_dma_device); +} +module_init(fh_dma_init); +module_exit(fh_dma_exit); + +MODULE_AUTHOR("QIN"); +MODULE_DESCRIPTION("Misc Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform: FH"); diff --git a/drivers/misc/fh_dma_miscdev.h b/drivers/misc/fh_dma_miscdev.h new file mode 100644 index 00000000..c294c331 --- /dev/null +++ b/drivers/misc/fh_dma_miscdev.h @@ -0,0 +1,32 @@ + +#ifndef FH_DMA_MISCDEV_H_ +#define FH_DMA_MISCDEV_H_ + +#include + + +#define DEVICE_NAME "fh_dma_misc" +#define PROC_FILE "driver/dma_misc" + +#define DMA_IOCTL_MAGIC 'd' +#define RESERVERD _IO(DMA_IOCTL_MAGIC, 0) +#define REQUEST_CHANNEL _IOWR(DMA_IOCTL_MAGIC, 1, __u32) +#define DMA_MEMCOPY _IOWR(DMA_IOCTL_MAGIC, 2, __u32) + +#define DMA_IOCTL_MAXNR 14 + +#define DMA_MEMCPY_TIMEOUT 5000 //msec + +struct dma_memcpy +{ + int chan_id; + void *src_addr_vir; + void *dst_addr_vir; + unsigned int size; + unsigned int src_addr_phy; + unsigned int dst_addr_phy; +}; + + + +#endif /* FH_DMA_MISCDEV_H_ */ diff --git a/drivers/misc/fh_dw_i2s.c b/drivers/misc/fh_dw_i2s.c new file mode 100644 index 00000000..e9d4689f --- /dev/null +++ b/drivers/misc/fh_dw_i2s.c @@ -0,0 +1,1624 @@ +/**@file + * @Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd. + * @brief + * + * @author fullhan + * @date 2016-7-15 + * @version V1.0 + * @version V1.1 modify code style + * @note: misc audio driver for fh8830 embedded audio codec. + * @note History: + * @note