aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-2.6.28
diff options
context:
space:
mode:
authorFlorian Boor <florian.boor@kernelconcepts.de>2010-08-30 00:31:48 +0200
committerFlorian Boor <florian.boor@kernelconcepts.de>2010-08-30 00:37:12 +0200
commit4824de3bbf903219f8b23d67ee65b850631a8490 (patch)
treecf70b91fe102d602d5f02d7bfd19125c14d205c8 /recipes/linux/linux-2.6.28
parent9cd92740e6df11b40912e9c4c5374bbf7db84a11 (diff)
downloadopenembedded-4824de3bbf903219f8b23d67ee65b850631a8490.tar.gz
linux: 2.6.28 patch and workarounds for smartqv7.
Diffstat (limited to 'recipes/linux/linux-2.6.28')
-rw-r--r--recipes/linux/linux-2.6.28/smartqv7/defconfig1515
-rw-r--r--recipes/linux/linux-2.6.28/smartqv7/smartqv7-git.patch220559
2 files changed, 222074 insertions, 0 deletions
diff --git a/recipes/linux/linux-2.6.28/smartqv7/defconfig b/recipes/linux/linux-2.6.28/smartqv7/defconfig
new file mode 100644
index 0000000000..c9ba2f0323
--- /dev/null
+++ b/recipes/linux/linux-2.6.28/smartqv7/defconfig
@@ -0,0 +1,1515 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.28
+# Tue Nov 10 14:34:35 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_GENERIC_TIME is not set
+# CONFIG_GENERIC_CLOCKEVENTS is not set
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=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_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_UID16 is not set
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+# CONFIG_BUG is not set
+# CONFIG_ELF_CORE is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+# CONFIG_SHMEM is not set
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=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_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF 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_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX 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_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM is not set
+CONFIG_ARCH_TCC=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# TCC Core Type
+#
+CONFIG_ARCH_TCC8900=y
+CONFIG_TCC_R_AX=y
+# CONFIG_TCC_R_XX is not set
+
+#
+# TCC Board Type
+#
+CONFIG_MACH_TCC8900=y
+CONFIG_DRAM_DDR2=y
+# CONFIG_DRAM_MDDR is not set
+# CONFIG_RAM_128MB is not set
+CONFIG_RAM_256MB=y
+# CONFIG_HD720p_LEVEL41 is not set
+# CONFIG_HD720p_LEVEL51 is not set
+# CONFIG_HD1080p_LEVEL41 is not set
+CONFIG_HD1080p_LEVEL51=y
+CONFIG_TCC_STRING="tcc8900"
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_PABRT_NOIFAR=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
+
+#
+# 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_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT=y
+CONFIG_HZ=200
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_UNEVICTABLE_LRU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttySAC0,115200n8 root=/dev/ndda1 rw rootwait splash quiet"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+# 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 is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=m
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+
+#
+# Dynamic Power Management
+#
+CONFIG_DPM=y
+CONFIG_DPM_PROCFS=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE 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 is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_NETFILTER_ADVANCED is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_NF_DEFRAG_IPV4 is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED 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=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIBTUSB=m
+# CONFIG_BT_HCIBTSDIO is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+CONFIG_WIRELESS=y
+CONFIG_CFG80211=m
+CONFIG_NL80211=y
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+CONFIG_WIRELESS_EXT=y
+# CONFIG_WIRELESS_EXT_SYSFS is not set
+CONFIG_MAC80211=m
+
+#
+# Rate control algorithm selection
+#
+CONFIG_MAC80211_RC_PID=y
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT_PID=y
+# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
+CONFIG_MAC80211_RC_DEFAULT="pid"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_LEDS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+# CONFIG_IEEE80211_CRYPT_CCMP is not set
+# CONFIG_IEEE80211_CRYPT_TKIP is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+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 is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_TCC_NAND_V6 is not set
+CONFIG_TCC_NAND_V7=y
+CONFIG_MISC_DEVICES=y
+CONFIG_SMARTQV_ENCRYPT=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# 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_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD 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_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_SMC911X 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_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+# CONFIG_LIBERTAS is not set
+# CONFIG_LIBERTAS_THINFIRM is not set
+CONFIG_MARVELL_8686_SDIO=m
+CONFIG_MARVELL_8686_PROC_FS=y
+CONFIG_MARVELL_8686_DEBUG=y
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_RT2X00 is not set
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SMSC95XX=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=m
+# CONFIG_WAN is not set
+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=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_PPPOL2TP=m
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=800
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+CONFIG_TOUCHSCREEN_TCCTS=y
+# CONFIG_LCD01 is not set
+# CONFIG_LCD11 is not set
+CONFIG_LCD10=y
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+CONFIG_INPUT_UINPUT=m
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_TCC=y
+CONFIG_SERIAL_TCC_CONSOLE=y
+# CONFIG_SERIAL_TCC_DMA is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_TCC_CKC_IOCTL=y
+CONFIG_TCC_USER_INTR=y
+CONFIG_TCC_BL=y
+CONFIG_TCC_POWER_CTL=y
+# CONFIG_LCD_4 is not set
+CONFIG_LCD_7=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
+# CONFIG_I2C_HELPER_AUTO is not set
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# 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_GPIO=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+CONFIG_I2C_TCC=y
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_TCC_I2C_WM8731 is not set
+CONFIG_TCC_I2C_WM8987=y
+CONFIG_TCC_I2C_PCA953X=y
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_TCC8900=y
+CONFIG_FB_TCC_A070VW04=y
+# CONFIG_FB_TCC_TD043MTEX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_CENTER=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_USB is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_TCC_SOC=y
+CONFIG_SND_TCC_SOC_I2S=y
+# CONFIG_SND_TCC_SOC_BOARD_WM8731 is not set
+# CONFIG_SND_TCC_SOC_BOARD_WM8581 is not set
+CONFIG_SND_TCC_SOC_BOARD_WM8987=y
+CONFIG_AUDIO_CODEC_PROCFS=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_WM8987=y
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=m
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_COMPAT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_BRIGHT is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DELL is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# Telechips DWC OTG Controller Drivers
+#
+CONFIG_TCC_DWC_OTG=m
+CONFIG_TCC_DWC_OTG_DUAL_ROLE=y
+# CONFIG_TCC_DWC_OTG_DEVICE_ONLY is not set
+# CONFIG_TCC_DWC_OTG_HOST_ONLY is not set
+# CONFIG_TCC_DWC_OTG_DEBUG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+#
+
+#
+# see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_EZUSB is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+CONFIG_USB_SERIAL_OPTION=m
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+CONFIG_USB_GADGET_TCC_OTG=y
+CONFIG_USB_TCC_OTG=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+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_TCC_SDHC=y
+CONFIG_MMC_TCC_SDHC_CORE0=y
+CONFIG_MMC_TCC_SDHC_CORE1=y
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_NEW_LEDS=y
+# CONFIG_LEDS_CLASS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON 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_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 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_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# 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_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_TCC=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="cp437"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_AUFS_FS=m
+CONFIG_AUFS_BRANCH_MAX_127=y
+# CONFIG_AUFS_BRANCH_MAX_511 is not set
+# CONFIG_AUFS_BRANCH_MAX_1023 is not set
+# CONFIG_AUFS_BRANCH_MAX_32767 is not set
+CONFIG_AUFS_HINOTIFY=y
+# CONFIG_AUFS_RDU is not set
+# CONFIG_AUFS_SHWH is not set
+# CONFIG_AUFS_BR_RAMFS is not set
+# CONFIG_AUFS_DEBUG is not set
+CONFIG_AUFS_BDEV_LOOP=y
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# 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=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+
+#
+# Tracers
+#
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# 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
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# 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=m
+# 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=m
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=m
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=m
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/recipes/linux/linux-2.6.28/smartqv7/smartqv7-git.patch b/recipes/linux/linux-2.6.28/smartqv7/smartqv7-git.patch
new file mode 100644
index 0000000000..d077008ba0
--- /dev/null
+++ b/recipes/linux/linux-2.6.28/smartqv7/smartqv7-git.patch
@@ -0,0 +1,220559 @@
+diff --git a/Documentation/ABI/testing/debugfs-aufs b/Documentation/ABI/testing/debugfs-aufs
+new file mode 100644
+index 0000000..4110b94
+--- /dev/null
++++ b/Documentation/ABI/testing/debugfs-aufs
+@@ -0,0 +1,40 @@
++What: /debug/aufs/si_<id>/
++Date: March 2009
++Contact: J. R. Okajima <hooanon05@yahoo.co.jp>
++Description:
++ Under /debug/aufs, a directory named si_<id> is created
++ per aufs mount, where <id> is a unique id generated
++ internally.
++
++What: /debug/aufs/si_<id>/xib
++Date: March 2009
++Contact: J. R. Okajima <hooanon05@yahoo.co.jp>
++Description:
++ It shows the consumed blocks by xib (External Inode Number
++ Bitmap), its block size and file size.
++ When the aufs mount option 'noxino' is specified, it
++ will be empty. About XINO files, see
++ Documentation/filesystems/aufs/aufs.5 in detail.
++
++What: /debug/aufs/si_<id>/xino0, xino1 ... xinoN
++Date: March 2009
++Contact: J. R. Okajima <hooanon05@yahoo.co.jp>
++Description:
++ It shows the consumed blocks by xino (External Inode Number
++ Translation Table), its link count, block size and file
++ size.
++ When the aufs mount option 'noxino' is specified, it
++ will be empty. About XINO files, see
++ Documentation/filesystems/aufs/aufs.5 in detail.
++
++What: /debug/aufs/si_<id>/xigen
++Date: March 2009
++Contact: J. R. Okajima <hooanon05@yahoo.co.jp>
++Description:
++ It shows the consumed blocks by xigen (External Inode
++ Generation Table), its block size and file size.
++ If CONFIG_AUFS_EXPORT is disabled, this entry will not
++ be created.
++ When the aufs mount option 'noxino' is specified, it
++ will be empty. About XINO files, see
++ Documentation/filesystems/aufs/aufs.5 in detail.
+diff --git a/Documentation/ABI/testing/sysfs-aufs b/Documentation/ABI/testing/sysfs-aufs
+new file mode 100644
+index 0000000..ca49330
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-aufs
+@@ -0,0 +1,25 @@
++What: /sys/fs/aufs/si_<id>/
++Date: March 2009
++Contact: J. R. Okajima <hooanon05@yahoo.co.jp>
++Description:
++ Under /sys/fs/aufs, a directory named si_<id> is created
++ per aufs mount, where <id> is a unique id generated
++ internally.
++
++What: /sys/fs/aufs/si_<id>/br0, br1 ... brN
++Date: March 2009
++Contact: J. R. Okajima <hooanon05@yahoo.co.jp>
++Description:
++ It shows the abolute path of a member directory (which
++ is called branch) in aufs, and its permission.
++
++What: /sys/fs/aufs/si_<id>/xi_path
++Date: March 2009
++Contact: J. R. Okajima <hooanon05@yahoo.co.jp>
++Description:
++ It shows the abolute path of XINO (External Inode Number
++ Bitmap, Translation Table and Generation Table) file
++ even if it is the default path.
++ When the aufs mount option 'noxino' is specified, it
++ will be empty. About XINO files, see
++ Documentation/filesystems/aufs/aufs.5 in detail.
+diff --git a/Makefile b/Makefile
+index 71e98e9..1f805ad 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ VERSION = 2
+ PATCHLEVEL = 6
+ SUBLEVEL = 28
+-EXTRAVERSION =
++#EXTRAVERSION = .10
+ NAME = Erotic Pickled Herring
+
+ # *DOCUMENTATION*
+@@ -190,8 +190,10 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+ # Default value for CROSS_COMPILE is not to prefix executables
+ # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
+ export KBUILD_BUILDHOST := $(SUBARCH)
+-ARCH ?= $(SUBARCH)
+-CROSS_COMPILE ?=
++ARCH ?= arm
++#CROSS_COMPILE ?= /opt/arm-2009q1/bin/arm-none-linux-gnueabi-
++CROSS_COMPILE ?= /opt/armv6/codesourcery/bin/arm-none-linux-gnueabi-
++#CROSS_COMPILE ?= /opt/codesourcery/bin/arm-none-linux-gnueabi-
+
+ # Architecture as present in compile.h
+ UTS_MACHINE := $(ARCH)
+@@ -338,9 +340,9 @@ LINUXINCLUDE := -Iinclude \
+
+ KBUILD_CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE)
+
++#Debug KERNEL
+ KBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
+- -fno-strict-aliasing -fno-common \
+- -Werror-implicit-function-declaration
++ -fno-strict-aliasing -fno-common
+ KBUILD_AFLAGS := -D__ASSEMBLY__
+
+ # Read KERNELRELEASE from include/config/kernel.release (if it exists)
+@@ -521,6 +523,21 @@ ifneq (CONFIG_FRAME_WARN,0)
+ KBUILD_CFLAGS += $(call cc-option,-Wframe-larger-than=${CONFIG_FRAME_WARN})
+ endif
+
++ifeq ($(CONFIG_ARCH_TCC), y)
++# KBUILD_CFLAGS += -D_TCC_ -D_LINUX_
++ KBUILD_CPPFLAGS += -D_TCC_ -D_LINUX_
++ ARCH_DIR := $(TCC_STRING)
++endif
++
++ifeq ($(CONFIG_TCC_R_AX), y)
++ KBUILD_CFLAGS += -DTCC_R_AX
++ KBUILD_CPPFLAGS += -DTCC_R_AX
++endif
++ifeq ($(CONFIG_TCC_R_XX), y)
++ KBUILD_CFLAGS += -DTCC_R_XX
++ KBUILD_CPPFLAGS += -DTCC_R_XX
++endif
++
+ # Force gcc to behave correct even for buggy distributions
+ # Arch Makefiles may override this setting
+ KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector)
+@@ -682,6 +699,7 @@ quiet_cmd_vmlinux__ ?= LD $@
+ # Generate new vmlinux version
+ quiet_cmd_vmlinux_version = GEN .version
+ cmd_vmlinux_version = set -e; \
++ if [ ! -d .svn ]; then\
+ if [ ! -r .version ]; then \
+ rm -f .version; \
+ echo 1 >.version; \
+@@ -689,6 +707,9 @@ quiet_cmd_vmlinux_version = GEN .version
+ mv .version .old_version; \
+ expr 0$$(cat .old_version) + 1 >.version; \
+ fi; \
++ else\
++ echo $(shell svnversion -n .) >.version;\
++ fi;\
+ $(MAKE) $(build)=init
+
+ # Generate System.map
+@@ -1181,6 +1202,7 @@ $(clean-dirs):
+ $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@)
+
+ clean: archclean $(clean-dirs)
++ @rm -f linux.rom
+ $(call cmd,rmdirs)
+ $(call cmd,rmfiles)
+ @find . $(RCS_FIND_IGNORE) \
+@@ -1215,6 +1237,9 @@ distclean: mrproper
+ -o -name '.*.rej' -o -size 0 \
+ -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \
+ -type f -print | xargs rm -f
++ @find $(srctree) $(RCS_FIND_IGNORE) \
++ \( -name 'tcc' \) \
++ -type l -print | xargs rm -f
+
+
+ # Packaging of the kernel to various formats
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 9722f8b..1ab1281 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -34,7 +34,7 @@ config SYS_SUPPORTS_APM_EMULATION
+
+ config GENERIC_GPIO
+ bool
+- default n
++ default y
+
+ config GENERIC_TIME
+ bool
+@@ -549,6 +549,12 @@ config ARCH_MSM
+ interface to the ARM9 modem processor which runs the baseband stack
+ and controls some vital subsystems (clock and power control, etc).
+
++config ARCH_TCC
++ bool "Telechips TCC8900"
++ help
++ Support for the following Telechips TCC series SoCs:
++ TCC8900.
++
+ endchoice
+
+ source "arch/arm/mach-clps711x/Kconfig"
+@@ -627,6 +633,10 @@ source "arch/arm/mach-ks8695/Kconfig"
+
+ source "arch/arm/mach-msm/Kconfig"
+
++if ARCH_TCC
++source "arch/arm/mach-tcc8900/Kconfig"
++endif
++
+ # Definitions to make life easier
+ config ARCH_ACORN
+ bool
+@@ -808,7 +818,7 @@ config HZ
+ default 200 if ARCH_EBSA110 || ARCH_S3C2410
+ default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER
+ default AT91_TIMER_HZ if ARCH_AT91
+- default 100
++ default 200
+
+ config AEABI
+ bool "Use the ARM EABI to compile the kernel"
+@@ -1037,7 +1047,7 @@ endmenu
+
+ menu "CPU Power Management"
+
+-if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA)
++if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA || ARCH_TCC)
+
+ source "drivers/cpufreq/Kconfig"
+
+@@ -1171,6 +1181,8 @@ menu "Power management options"
+
+ source "kernel/power/Kconfig"
+
++source "drivers/dpm/Kconfig"
++
+ config ARCH_SUSPEND_POSSIBLE
+ def_bool y
+
+diff --git a/arch/arm/Makefile b/arch/arm/Makefile
+index bd6e281..79ec63c 100644
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -94,6 +94,9 @@ CHECKFLAGS += -D__arm__
+ head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
+ textofs-y := 0x00008000
+
++ machine-$(CONFIG_ARCH_TCC) := tcc8900
++ plat-$(CONFIG_ARCH_TCC) := tcc
++ textofs-$(CONFIG_ARCH_TCC) := 0x00100000
+ machine-$(CONFIG_ARCH_RPC) := rpc
+ machine-$(CONFIG_ARCH_EBSA110) := ebsa110
+ machine-$(CONFIG_ARCH_CLPS7500) := clps7500
+diff --git a/arch/arm/configs/SmartV5_defconfig b/arch/arm/configs/SmartV5_defconfig
+new file mode 100644
+index 0000000..3968036
+--- /dev/null
++++ b/arch/arm/configs/SmartV5_defconfig
+@@ -0,0 +1,1515 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.28
++# Tue Nov 10 14:36:48 2009
++#
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_GENERIC_TIME is not set
++# CONFIG_GENERIC_CLOCKEVENTS is not set
++CONFIG_MMU=y
++# CONFIG_NO_IOPORT is not set
++CONFIG_GENERIC_HARDIRQS=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_ILOG2_U32 is not set
++# CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_LOCK_KERNEL=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++# CONFIG_CGROUPS is not set
++# CONFIG_GROUP_SCHED is not set
++# CONFIG_SYSFS_DEPRECATED_V2 is not set
++CONFIG_RELAY=y
++# CONFIG_NAMESPACES is not set
++# CONFIG_BLK_DEV_INITRD is not set
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++# CONFIG_UID16 is not set
++CONFIG_SYSCTL_SYSCALL=y
++# CONFIG_KALLSYMS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++# CONFIG_BUG is not set
++# CONFIG_ELF_CORE is not set
++# CONFIG_COMPAT_BRK is not set
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_ANON_INODES=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++# CONFIG_SHMEM is not set
++CONFIG_AIO=y
++CONFIG_VM_EVENT_COUNTERS=y
++# CONFIG_SLUB_DEBUG is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++# CONFIG_MARKERS is not set
++CONFIG_HAVE_OPROFILE=y
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_RT_MUTEXES=y
++CONFIG_TINY_SHMEM=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_KMOD=y
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF 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_AS is not set
++# CONFIG_IOSCHED_DEADLINE is not set
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_CLASSIC_RCU=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IMX 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_L7200 is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_NS9XXX is not set
++# CONFIG_ARCH_LOKI is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_ARCH_MSM is not set
++CONFIG_ARCH_TCC=y
++
++#
++# Boot options
++#
++
++#
++# Power management
++#
++
++#
++# TCC Core Type
++#
++CONFIG_ARCH_TCC8900=y
++CONFIG_TCC_R_AX=y
++# CONFIG_TCC_R_XX is not set
++
++#
++# TCC Board Type
++#
++CONFIG_MACH_TCC8900=y
++CONFIG_DRAM_DDR2=y
++# CONFIG_DRAM_MDDR is not set
++# CONFIG_RAM_128MB is not set
++CONFIG_RAM_256MB=y
++# CONFIG_HD720p_LEVEL41 is not set
++# CONFIG_HD720p_LEVEL51 is not set
++# CONFIG_HD1080p_LEVEL41 is not set
++CONFIG_HD1080p_LEVEL51=y
++CONFIG_TCC_STRING="tcc8900"
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_V6=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v6=y
++CONFIG_CPU_ABRT_EV6=y
++CONFIG_CPU_PABRT_NOIFAR=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
++
++#
++# 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_OUTER_CACHE is not set
++
++#
++# Bus support
++#
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_PREEMPT=y
++CONFIG_HZ=200
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++CONFIG_ARCH_FLATMEM_HAS_HOLES=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_DISCONTIGMEM_MANUAL is not set
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_UNEVICTABLE_LRU is not set
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttySAC0,115200n8 root=/dev/ndda1 rw rootwait splash quiet"
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++
++#
++# CPU Power Management
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++# CONFIG_CPU_FREQ_DEBUG is not set
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++CONFIG_CPU_FREQ_GOV_USERSPACE=m
++CONFIG_CPU_FREQ_GOV_ONDEMAND=m
++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
++# 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 is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_MISC=m
++
++#
++# Power management options
++#
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_APM_EMULATION is not set
++
++#
++# Dynamic Power Management
++#
++CONFIG_DPM=y
++CONFIG_DPM_PROCFS=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=m
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_FIB_HASH=y
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE 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 is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++# CONFIG_INET_LRO is not set
++# CONFIG_INET_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++# CONFIG_NETFILTER_ADVANCED is not set
++
++#
++# Core Netfilter Configuration
++#
++# CONFIG_NETFILTER_NETLINK_LOG is not set
++# CONFIG_NF_CONNTRACK is not set
++CONFIG_NETFILTER_XTABLES=m
++# CONFIG_NETFILTER_XT_TARGET_MARK is not set
++# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
++# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
++# CONFIG_NETFILTER_XT_MATCH_MARK is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_SCHED 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=m
++CONFIG_BT_L2CAP=m
++CONFIG_BT_SCO=m
++CONFIG_BT_RFCOMM=m
++CONFIG_BT_RFCOMM_TTY=y
++CONFIG_BT_BNEP=m
++CONFIG_BT_BNEP_MC_FILTER=y
++CONFIG_BT_BNEP_PROTO_FILTER=y
++CONFIG_BT_HIDP=m
++
++#
++# Bluetooth device drivers
++#
++CONFIG_BT_HCIBTUSB=m
++# CONFIG_BT_HCIBTSDIO is not set
++# CONFIG_BT_HCIUART is not set
++# CONFIG_BT_HCIBCM203X is not set
++# CONFIG_BT_HCIBPA10X is not set
++# CONFIG_BT_HCIBFUSB is not set
++# CONFIG_BT_HCIVHCI is not set
++# CONFIG_AF_RXRPC is not set
++# CONFIG_PHONET is not set
++CONFIG_WIRELESS=y
++CONFIG_CFG80211=m
++CONFIG_NL80211=y
++# CONFIG_WIRELESS_OLD_REGULATORY is not set
++CONFIG_WIRELESS_EXT=y
++# CONFIG_WIRELESS_EXT_SYSFS is not set
++CONFIG_MAC80211=m
++
++#
++# Rate control algorithm selection
++#
++CONFIG_MAC80211_RC_PID=y
++CONFIG_MAC80211_RC_MINSTREL=y
++CONFIG_MAC80211_RC_DEFAULT_PID=y
++# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
++CONFIG_MAC80211_RC_DEFAULT="pid"
++# CONFIG_MAC80211_MESH is not set
++# CONFIG_MAC80211_LEDS is not set
++# CONFIG_MAC80211_DEBUG_MENU is not set
++CONFIG_IEEE80211=m
++# CONFIG_IEEE80211_DEBUG is not set
++CONFIG_IEEE80211_CRYPT_WEP=m
++# CONFIG_IEEE80211_CRYPT_CCMP is not set
++# CONFIG_IEEE80211_CRYPT_TKIP is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++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 is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=m
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=2
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_TCC_NAND_V6 is not set
++CONFIG_TCC_NAND_V7=y
++CONFIG_MISC_DEVICES=y
++CONFIG_SMARTQV_ENCRYPT=y
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_C2PORT is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=m
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=m
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=m
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++# 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_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_ATA is not set
++# CONFIG_MD 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_PHYLIB is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=m
++# CONFIG_AX88796 is not set
++# CONFIG_SMC91X is not set
++# CONFIG_DM9000 is not set
++# CONFIG_SMC911X 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_NETDEV_1000 is not set
++# CONFIG_NETDEV_10000 is not set
++
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++CONFIG_WLAN_80211=y
++# CONFIG_LIBERTAS is not set
++# CONFIG_LIBERTAS_THINFIRM is not set
++CONFIG_MARVELL_8686_SDIO=m
++CONFIG_MARVELL_8686_PROC_FS=y
++CONFIG_MARVELL_8686_DEBUG=y
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_USB_NET_RNDIS_WLAN is not set
++# CONFIG_RTL8187 is not set
++# CONFIG_MAC80211_HWSIM is not set
++# CONFIG_P54_COMMON is not set
++# CONFIG_IWLWIFI_LEDS is not set
++# CONFIG_HOSTAP is not set
++# CONFIG_B43 is not set
++# CONFIG_B43LEGACY is not set
++# CONFIG_ZD1211RW is not set
++# CONFIG_RT2X00 is not set
++
++#
++# USB Network Adapters
++#
++CONFIG_USB_CATC=m
++CONFIG_USB_KAWETH=m
++CONFIG_USB_PEGASUS=m
++CONFIG_USB_RTL8150=m
++CONFIG_USB_USBNET=m
++CONFIG_USB_NET_AX8817X=m
++CONFIG_USB_NET_CDCETHER=m
++CONFIG_USB_NET_DM9601=m
++CONFIG_USB_NET_SMSC95XX=m
++CONFIG_USB_NET_GL620A=m
++CONFIG_USB_NET_NET1080=m
++CONFIG_USB_NET_PLUSB=m
++CONFIG_USB_NET_MCS7830=m
++CONFIG_USB_NET_RNDIS_HOST=m
++CONFIG_USB_NET_CDC_SUBSET=m
++CONFIG_USB_ALI_M5632=y
++CONFIG_USB_AN2720=y
++CONFIG_USB_BELKIN=y
++CONFIG_USB_ARMLINUX=y
++CONFIG_USB_EPSON2888=y
++CONFIG_USB_KC2190=y
++CONFIG_USB_NET_ZAURUS=m
++# CONFIG_WAN is not set
++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=m
++CONFIG_PPP_MPPE=m
++CONFIG_PPPOE=m
++CONFIG_PPPOL2TP=m
++# CONFIG_SLIP is not set
++CONFIG_SLHC=m
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=800
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ATKBD is not set
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++CONFIG_KEYBOARD_GPIO=y
++CONFIG_INPUT_MOUSE=y
++# CONFIG_MOUSE_PS2 is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++# CONFIG_TOUCHSCREEN_FUJITSU is not set
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_INEXIO is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++# CONFIG_TOUCHSCREEN_PENMOUNT is not set
++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
++# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
++CONFIG_TOUCHSCREEN_TCCTS=y
++# CONFIG_LCD01 is not set
++# CONFIG_LCD11 is not set
++CONFIG_LCD10=y
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_ATI_REMOTE is not set
++# CONFIG_INPUT_ATI_REMOTE2 is not set
++# CONFIG_INPUT_KEYSPAN_REMOTE is not set
++# CONFIG_INPUT_POWERMATE is not set
++# CONFIG_INPUT_YEALINK is not set
++# CONFIG_INPUT_CM109 is not set
++CONFIG_INPUT_UINPUT=m
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_DEVKMEM is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_TCC=y
++CONFIG_SERIAL_TCC_CONSOLE=y
++# CONFIG_SERIAL_TCC_DMA is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++CONFIG_UNIX98_PTYS=y
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_NVRAM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_TCC_CKC_IOCTL=y
++CONFIG_TCC_USER_INTR=y
++CONFIG_TCC_BL=y
++CONFIG_TCC_POWER_CTL=y
++CONFIG_LCD_4=y
++# CONFIG_LCD_7 is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_CHARDEV=m
++# CONFIG_I2C_HELPER_AUTO is not set
++
++#
++# I2C Algorithms
++#
++CONFIG_I2C_ALGOBIT=y
++# 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_GPIO=y
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_SIMTEC is not set
++CONFIG_I2C_TCC=y
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_STUB is not set
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_DS1682 is not set
++# CONFIG_AT24 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_PCF8575 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_MAX6875 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_TCC_I2C_WM8731 is not set
++CONFIG_TCC_I2C_WM8987=y
++CONFIG_TCC_I2C_PCA953X=y
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_I2C_DEBUG_CHIP is not set
++# CONFIG_SPI is not set
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_THERMAL_HWMON is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM8350_I2C is not set
++
++#
++# Multimedia devices
++#
++
++#
++# Multimedia core support
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++# CONFIG_VIDEO_MEDIA is not set
++
++#
++# Multimedia drivers
++#
++# CONFIG_DAB is not set
++
++#
++# Graphics support
++#
++# CONFIG_VGASTATE is not set
++CONFIG_VIDEO_OUTPUT_CONTROL=m
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++# CONFIG_FB_TILEBLITTING is not set
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_S1D13XXX is not set
++CONFIG_FB_TCC8900=y
++# CONFIG_FB_TCC_A070VW04 is not set
++CONFIG_FB_TCC_TD043MTEX=y
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_MB862XX is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
++
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++CONFIG_LOGO=y
++CONFIG_LOGO_CENTER=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_LOGO_LINUX_CLUT224=y
++CONFIG_SOUND=y
++CONFIG_SOUND_OSS_CORE=y
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++# CONFIG_SND_SEQUENCER is not set
++CONFIG_SND_OSSEMUL=y
++CONFIG_SND_MIXER_OSS=y
++CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
++# CONFIG_SND_DYNAMIC_MINORS is not set
++# CONFIG_SND_SUPPORT_OLD_API is not set
++# CONFIG_SND_VERBOSE_PROCFS is not set
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++# CONFIG_SND_DRIVERS is not set
++# CONFIG_SND_ARM is not set
++# CONFIG_SND_USB is not set
++CONFIG_SND_SOC=y
++CONFIG_SND_TCC_SOC=y
++CONFIG_SND_TCC_SOC_I2S=y
++# CONFIG_SND_TCC_SOC_BOARD_WM8731 is not set
++# CONFIG_SND_TCC_SOC_BOARD_WM8581 is not set
++CONFIG_SND_TCC_SOC_BOARD_WM8987=y
++CONFIG_AUDIO_CODEC_PROCFS=y
++# CONFIG_SND_SOC_ALL_CODECS is not set
++CONFIG_SND_SOC_WM8987=y
++# CONFIG_SOUND_PRIME is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=m
++# CONFIG_HID_DEBUG is not set
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=m
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++CONFIG_USB_KBD=m
++CONFIG_USB_MOUSE=m
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_COMPAT is not set
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_BRIGHT is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DELL is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_THRUSTMASTER_FF is not set
++# CONFIG_ZEROPLUS_FF is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++# CONFIG_USB_DEVICE_CLASS is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++CONFIG_USB_SUSPEND=y
++CONFIG_USB_OTG=y
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# Telechips DWC OTG Controller Drivers
++#
++CONFIG_TCC_DWC_OTG=m
++CONFIG_TCC_DWC_OTG_DUAL_ROLE=y
++# CONFIG_TCC_DWC_OTG_DEVICE_ONLY is not set
++# CONFIG_TCC_DWC_OTG_HOST_ONLY is not set
++# CONFIG_TCC_DWC_OTG_DEBUG is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
++# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HWA_HCD is not set
++# CONFIG_USB_GADGET_MUSB_HDRC is not set
++
++#
++# USB Device Class drivers
++#
++CONFIG_USB_ACM=m
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
++#
++
++#
++# see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=m
++# CONFIG_USB_STORAGE_DEBUG is not set
++CONFIG_USB_STORAGE_DATAFAB=y
++CONFIG_USB_STORAGE_FREECOM=y
++CONFIG_USB_STORAGE_ISD200=y
++CONFIG_USB_STORAGE_DPCM=y
++CONFIG_USB_STORAGE_USBAT=y
++CONFIG_USB_STORAGE_SDDR09=y
++CONFIG_USB_STORAGE_SDDR55=y
++CONFIG_USB_STORAGE_JUMPSHOT=y
++CONFIG_USB_STORAGE_ALAUDA=y
++CONFIG_USB_STORAGE_ONETOUCH=y
++CONFIG_USB_STORAGE_KARMA=y
++CONFIG_USB_STORAGE_CYPRESS_ATACB=y
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++CONFIG_USB_SERIAL=m
++# CONFIG_USB_EZUSB is not set
++CONFIG_USB_SERIAL_GENERIC=y
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_ARK3116 is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_CH341 is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_CP2101 is not set
++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++# CONFIG_USB_SERIAL_FTDI_SIO is not set
++# CONFIG_USB_SERIAL_FUNSOFT is not set
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
++# CONFIG_USB_SERIAL_GARMIN is not set
++# CONFIG_USB_SERIAL_IPW is not set
++# CONFIG_USB_SERIAL_IUU is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_MOS7720 is not set
++# CONFIG_USB_SERIAL_MOS7840 is not set
++# CONFIG_USB_SERIAL_MOTOROLA is not set
++# CONFIG_USB_SERIAL_NAVMAN is not set
++# CONFIG_USB_SERIAL_PL2303 is not set
++# CONFIG_USB_SERIAL_OTI6858 is not set
++# CONFIG_USB_SERIAL_SPCP8X5 is not set
++# CONFIG_USB_SERIAL_HP4X is not set
++# CONFIG_USB_SERIAL_SAFE is not set
++# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
++# CONFIG_USB_SERIAL_TI is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++CONFIG_USB_SERIAL_OPTION=m
++# CONFIG_USB_SERIAL_OMNINET is not set
++# CONFIG_USB_SERIAL_DEBUG is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_BERRY_CHARGE is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGET is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_VST is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_SELECTED=y
++CONFIG_USB_GADGET_TCC_OTG=y
++CONFIG_USB_TCC_OTG=y
++# CONFIG_USB_GADGET_AT91 is not set
++# CONFIG_USB_GADGET_ATMEL_USBA is not set
++# CONFIG_USB_GADGET_FSL_USB2 is not set
++# CONFIG_USB_GADGET_LH7A40X is not set
++# CONFIG_USB_GADGET_OMAP is not set
++# CONFIG_USB_GADGET_PXA25X is not set
++# CONFIG_USB_GADGET_PXA27X is not set
++# CONFIG_USB_GADGET_S3C2410 is not set
++# CONFIG_USB_GADGET_M66592 is not set
++# CONFIG_USB_GADGET_AMD5536UDC is not set
++# CONFIG_USB_GADGET_FSL_QE is not set
++# CONFIG_USB_GADGET_NET2280 is not set
++# CONFIG_USB_GADGET_GOKU is not set
++# CONFIG_USB_GADGET_DUMMY_HCD is not set
++CONFIG_USB_GADGET_DUALSPEED=y
++# CONFIG_USB_ZERO is not set
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_GADGETFS is not set
++CONFIG_USB_FILE_STORAGE=m
++# CONFIG_USB_FILE_STORAGE_TEST is not set
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++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_TCC_SDHC=y
++CONFIG_MMC_TCC_SDHC_CORE0=y
++CONFIG_MMC_TCC_SDHC_CORE1=y
++# CONFIG_MEMSTICK is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_NEW_LEDS=y
++# CONFIG_LEDS_CLASS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGERS=y
++# CONFIG_LEDS_TRIGGER_TIMER is not set
++# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
++# CONFIG_LEDS_TRIGGER_DEFAULT_ON 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_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 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_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++
++#
++# SPI RTC drivers
++#
++
++#
++# 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_BQ4802 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# on-CPU RTC drivers
++#
++CONFIG_RTC_DRV_TCC=y
++# CONFIG_DMADEVICES is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_UIO is not set
++
++#
++# File systems
++#
++# CONFIG_EXT2_FS is not set
++CONFIG_EXT3_FS=y
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_JBD=y
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++CONFIG_FUSE_FS=m
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=m
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++# CONFIG_MSDOS_FS is not set
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="cp437"
++CONFIG_NTFS_FS=m
++# CONFIG_NTFS_DEBUG is not set
++CONFIG_NTFS_RW=y
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_CONFIGFS_FS=m
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_AUFS_FS=m
++CONFIG_AUFS_BRANCH_MAX_127=y
++# CONFIG_AUFS_BRANCH_MAX_511 is not set
++# CONFIG_AUFS_BRANCH_MAX_1023 is not set
++# CONFIG_AUFS_BRANCH_MAX_32767 is not set
++CONFIG_AUFS_HINOTIFY=y
++# CONFIG_AUFS_RDU is not set
++# CONFIG_AUFS_SHWH is not set
++# CONFIG_AUFS_BR_RAMFS is not set
++# CONFIG_AUFS_DEBUG is not set
++CONFIG_AUFS_BDEV_LOOP=y
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=m
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=m
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=m
++# CONFIG_SUNRPC_REGISTER_V4 is not set
++# CONFIG_RPCSEC_GSS_KRB5 is not set
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++# CONFIG_NLS_ISO8859_1 is not set
++# 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_KERNEL is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_RCU_CPU_STALL_DETECTOR is not set
++# CONFIG_LATENCYTOP is not set
++# CONFIG_SYSCTL_SYSCALL_CHECK is not set
++CONFIG_HAVE_FUNCTION_TRACER=y
++
++#
++# Tracers
++#
++# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_DEBUG_USER is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_FIPS is not set
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_MANAGER=m
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=m
++# 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
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++# 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=m
++# 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=m
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=m
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++CONFIG_CRYPTO_HW=y
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=m
++CONFIG_CRC_CCITT=m
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=m
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++CONFIG_ZLIB_INFLATE=m
++CONFIG_ZLIB_DEFLATE=m
++CONFIG_PLIST=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
+diff --git a/arch/arm/configs/SmartV5_initramfs_defconfig b/arch/arm/configs/SmartV5_initramfs_defconfig
+new file mode 100644
+index 0000000..5a44041
+--- /dev/null
++++ b/arch/arm/configs/SmartV5_initramfs_defconfig
+@@ -0,0 +1,1471 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.28
++# Mon Aug 17 16:10:25 2009
++#
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_GENERIC_TIME is not set
++# CONFIG_GENERIC_CLOCKEVENTS is not set
++CONFIG_MMU=y
++# CONFIG_NO_IOPORT is not set
++CONFIG_GENERIC_HARDIRQS=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_ILOG2_U32 is not set
++# CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++# CONFIG_CGROUPS is not set
++# CONFIG_GROUP_SCHED is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++CONFIG_RELAY=y
++CONFIG_NAMESPACES=y
++# CONFIG_UTS_NS is not set
++# CONFIG_IPC_NS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE="../rootfs"
++CONFIG_INITRAMFS_ROOT_UID=0
++CONFIG_INITRAMFS_ROOT_GID=0
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++# CONFIG_EMBEDDED is not set
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_KALLSYMS_EXTRA_PASS=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_VM_EVENT_COUNTERS=y
++CONFIG_SLUB_DEBUG=y
++# CONFIG_COMPAT_BRK is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++# CONFIG_MARKERS is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++CONFIG_MODULE_SRCVERSION_ALL=y
++CONFIG_KMOD=y
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF 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_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_CLASSIC_RCU=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IMX 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_L7200 is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_NS9XXX is not set
++# CONFIG_ARCH_LOKI is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_ARCH_MSM is not set
++CONFIG_ARCH_TCC=y
++
++#
++# Boot options
++#
++
++#
++# Power management
++#
++
++#
++# TCC Core Type
++#
++CONFIG_ARCH_TCC8900=y
++CONFIG_TCC_R_AX=y
++# CONFIG_TCC_R_XX is not set
++
++#
++# TCC Board Type
++#
++CONFIG_MACH_TCC8900=y
++# CONFIG_RAM_128MB is not set
++CONFIG_RAM_256MB=y
++# CONFIG_HD720p_LEVEL41 is not set
++# CONFIG_HD720p_LEVEL51 is not set
++CONFIG_HD1080p_LEVEL41=y
++# CONFIG_HD1080p_LEVEL51 is not set
++CONFIG_TCC_STRING="tcc8900"
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_V6=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v6=y
++CONFIG_CPU_ABRT_EV6=y
++CONFIG_CPU_PABRT_NOIFAR=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
++
++#
++# 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_OUTER_CACHE is not set
++
++#
++# Bus support
++#
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_PREEMPT is not set
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++CONFIG_ARCH_FLATMEM_HAS_HOLES=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_DISCONTIGMEM_MANUAL is not set
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_UNEVICTABLE_LRU is not set
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttySAC0,115200n8 rdinit=/sbin/init"
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_NWFPE_XP is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_VFP=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++CONFIG_BINFMT_AOUT=y
++CONFIG_BINFMT_MISC=y
++
++#
++# Power management options
++#
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_APM_EMULATION is not set
++
++#
++# Dynamic Power Management
++#
++CONFIG_DPM=y
++CONFIG_DPM_PROCFS=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_FIB_HASH=y
++CONFIG_IP_PNP=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++CONFIG_IP_PNP_RARP=y
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE 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 is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++# CONFIG_INET_LRO is not set
++# CONFIG_INET_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_SCHED 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_PHONET is not set
++CONFIG_WIRELESS=y
++CONFIG_CFG80211=m
++CONFIG_NL80211=y
++CONFIG_WIRELESS_OLD_REGULATORY=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WIRELESS_EXT_SYSFS=y
++CONFIG_MAC80211=m
++
++#
++# Rate control algorithm selection
++#
++CONFIG_MAC80211_RC_PID=y
++CONFIG_MAC80211_RC_MINSTREL=y
++CONFIG_MAC80211_RC_DEFAULT_PID=y
++# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
++CONFIG_MAC80211_RC_DEFAULT="pid"
++# CONFIG_MAC80211_MESH is not set
++CONFIG_MAC80211_LEDS=y
++# CONFIG_MAC80211_DEBUG_MENU is not set
++CONFIG_IEEE80211=m
++# CONFIG_IEEE80211_DEBUG is not set
++CONFIG_IEEE80211_CRYPT_WEP=m
++# CONFIG_IEEE80211_CRYPT_CCMP is not set
++# CONFIG_IEEE80211_CRYPT_TKIP is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++CONFIG_DEBUG_DEVRES=y
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_CONNECTOR is not set
++# CONFIG_MTD 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
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=2
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++CONFIG_CDROM_PKTCDVD=y
++CONFIG_CDROM_PKTCDVD_BUFFERS=8
++# CONFIG_CDROM_PKTCDVD_WCACHE is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_TCC_NAND_V6 is not set
++CONFIG_TCC_NAND_V7=y
++# CONFIG_MISC_DEVICES is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++CONFIG_SCSI_MULTI_LUN=y
++# 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_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_ATA is not set
++# CONFIG_MD 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 is not set
++# CONFIG_VETH is not set
++# CONFIG_PHYLIB is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_AX88796 is not set
++# CONFIG_SMC91X is not set
++# CONFIG_DM9000 is not set
++# CONFIG_SMC911X 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_NETDEV_1000 is not set
++# CONFIG_NETDEV_10000 is not set
++
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++CONFIG_WLAN_80211=y
++# CONFIG_LIBERTAS is not set
++# CONFIG_LIBERTAS_THINFIRM is not set
++CONFIG_MARVELL_8686_SDIO=m
++# CONFIG_MARVELL_8686_PROC_FS is not set
++# CONFIG_MARVELL_8686_DEBUG is not set
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_USB_NET_RNDIS_WLAN is not set
++# CONFIG_RTL8187 is not set
++# CONFIG_MAC80211_HWSIM is not set
++# CONFIG_P54_COMMON is not set
++# CONFIG_IWLWIFI_LEDS is not set
++# CONFIG_HOSTAP is not set
++# CONFIG_B43 is not set
++# CONFIG_B43LEGACY is not set
++# CONFIG_ZD1211RW is not set
++# CONFIG_RT2X00 is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_WAN is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++CONFIG_INPUT_FF_MEMLESS=y
++# CONFIG_INPUT_POLLDEV is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++CONFIG_KEYBOARD_GPIO=y
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++# CONFIG_TOUCHSCREEN_FUJITSU is not set
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_INEXIO is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++# CONFIG_TOUCHSCREEN_PENMOUNT is not set
++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
++# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
++CONFIG_TOUCHSCREEN_TCCTS=y
++# CONFIG_LCD01 is not set
++# CONFIG_LCD11 is not set
++CONFIG_LCD10=y
++# 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_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_DEVKMEM is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_TCC=y
++CONFIG_SERIAL_TCC_CONSOLE=y
++CONFIG_SERIAL_TCC_DMA=y
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++CONFIG_UNIX98_PTYS=y
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_NVRAM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_TCC_CKC_IOCTL=y
++CONFIG_TCC_USER_INTR=y
++CONFIG_TCC_BL=y
++CONFIG_LCD_4=y
++# CONFIG_LCD_7 is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_HELPER_AUTO is not set
++
++#
++# I2C Algorithms
++#
++CONFIG_I2C_ALGOBIT=y
++# 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_GPIO=y
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_SIMTEC is not set
++CONFIG_I2C_TCC=y
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_STUB is not set
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_DS1682 is not set
++# CONFIG_AT24 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_PCF8575 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_MAX6875 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_TCC_I2C_WM8731 is not set
++CONFIG_TCC_I2C_WM8987=y
++CONFIG_TCC_I2C_PCA953X=y
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_I2C_DEBUG_CHIP is not set
++# CONFIG_SPI is not set
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_THERMAL_HWMON is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM8350_I2C is not set
++
++#
++# Multimedia devices
++#
++
++#
++# Multimedia core support
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++# CONFIG_VIDEO_MEDIA is not set
++
++#
++# Multimedia drivers
++#
++# CONFIG_DAB is not set
++
++#
++# Graphics support
++#
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_S1D13XXX is not set
++CONFIG_FB_TCC8900=y
++# CONFIG_FB_TCC_A070VW04 is not set
++CONFIG_FB_TCC_TD043MTEX=y
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_MB862XX is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
++
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_LOGO_LINUX_CLUT224=y
++CONFIG_SOUND=y
++CONFIG_SOUND_OSS_CORE=y
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++# CONFIG_SND_SEQUENCER is not set
++CONFIG_SND_OSSEMUL=y
++CONFIG_SND_MIXER_OSS=y
++CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
++# CONFIG_SND_DYNAMIC_MINORS is not set
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++CONFIG_SND_DRIVERS=y
++# CONFIG_SND_DUMMY is not set
++# CONFIG_SND_MTPAV is not set
++# CONFIG_SND_SERIAL_U16550 is not set
++# CONFIG_SND_MPU401 is not set
++CONFIG_SND_ARM=y
++CONFIG_SND_USB=y
++# CONFIG_SND_USB_AUDIO is not set
++# CONFIG_SND_USB_CAIAQ is not set
++CONFIG_SND_SOC=y
++CONFIG_SND_TCC_SOC=y
++CONFIG_SND_TCC_SOC_I2S=y
++# CONFIG_SND_TCC_SOC_BOARD_WM8731 is not set
++# CONFIG_SND_TCC_SOC_BOARD_WM8581 is not set
++CONFIG_SND_TCC_SOC_BOARD_WM8987=y
++CONFIG_AUDIO_CODEC_PROCFS=y
++# CONFIG_SND_SOC_ALL_CODECS is not set
++CONFIG_SND_SOC_WM8987=y
++# CONFIG_SOUND_PRIME is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++CONFIG_HID_DEBUG=y
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# Special HID drivers
++#
++CONFIG_HID_COMPAT=y
++CONFIG_HID_A4TECH=y
++CONFIG_HID_APPLE=y
++CONFIG_HID_BELKIN=y
++CONFIG_HID_BRIGHT=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++CONFIG_HID_DELL=y
++CONFIG_HID_EZKEY=y
++CONFIG_HID_GYRATION=y
++CONFIG_HID_LOGITECH=y
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++CONFIG_HID_PANTHERLORD=y
++# CONFIG_PANTHERLORD_FF is not set
++CONFIG_HID_PETALYNX=y
++CONFIG_HID_SAMSUNG=y
++CONFIG_HID_SONY=y
++CONFIG_HID_SUNPLUS=y
++# CONFIG_THRUSTMASTER_FF is not set
++# CONFIG_ZEROPLUS_FF is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++# CONFIG_USB_DEVICE_CLASS is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++CONFIG_USB_SUSPEND=y
++CONFIG_USB_OTG=y
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# Telechips DWC OTG Controller Drivers
++#
++CONFIG_TCC_DWC_OTG=y
++CONFIG_TCC_DWC_OTG_DUAL_ROLE=y
++# CONFIG_TCC_DWC_OTG_DEVICE_ONLY is not set
++# CONFIG_TCC_DWC_OTG_HOST_ONLY is not set
++# CONFIG_TCC_DWC_OTG_DEBUG is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
++# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HWA_HCD is not set
++# CONFIG_USB_GADGET_MUSB_HDRC is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
++#
++
++#
++# see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_DPCM is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++CONFIG_USB_SERIAL=m
++# CONFIG_USB_EZUSB is not set
++# CONFIG_USB_SERIAL_GENERIC is not set
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_ARK3116 is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_CH341 is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_CP2101 is not set
++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++# CONFIG_USB_SERIAL_FTDI_SIO is not set
++# CONFIG_USB_SERIAL_FUNSOFT is not set
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
++# CONFIG_USB_SERIAL_GARMIN is not set
++# CONFIG_USB_SERIAL_IPW is not set
++# CONFIG_USB_SERIAL_IUU is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_MOS7720 is not set
++# CONFIG_USB_SERIAL_MOS7840 is not set
++# CONFIG_USB_SERIAL_MOTOROLA is not set
++# CONFIG_USB_SERIAL_NAVMAN is not set
++# CONFIG_USB_SERIAL_PL2303 is not set
++# CONFIG_USB_SERIAL_OTI6858 is not set
++# CONFIG_USB_SERIAL_SPCP8X5 is not set
++# CONFIG_USB_SERIAL_HP4X is not set
++# CONFIG_USB_SERIAL_SAFE is not set
++# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
++# CONFIG_USB_SERIAL_TI is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++# CONFIG_USB_SERIAL_OPTION is not set
++# CONFIG_USB_SERIAL_OMNINET is not set
++# CONFIG_USB_SERIAL_DEBUG is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_BERRY_CHARGE is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGET is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_VST is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_SELECTED=y
++CONFIG_USB_GADGET_TCC_OTG=y
++CONFIG_USB_TCC_OTG=y
++# CONFIG_USB_GADGET_AT91 is not set
++# CONFIG_USB_GADGET_ATMEL_USBA is not set
++# CONFIG_USB_GADGET_FSL_USB2 is not set
++# CONFIG_USB_GADGET_LH7A40X is not set
++# CONFIG_USB_GADGET_OMAP is not set
++# CONFIG_USB_GADGET_PXA25X is not set
++# CONFIG_USB_GADGET_PXA27X is not set
++# CONFIG_USB_GADGET_S3C2410 is not set
++# CONFIG_USB_GADGET_M66592 is not set
++# CONFIG_USB_GADGET_AMD5536UDC is not set
++# CONFIG_USB_GADGET_FSL_QE is not set
++# CONFIG_USB_GADGET_NET2280 is not set
++# CONFIG_USB_GADGET_GOKU is not set
++# CONFIG_USB_GADGET_DUMMY_HCD is not set
++CONFIG_USB_GADGET_DUALSPEED=y
++# CONFIG_USB_ZERO is not set
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_GADGETFS is not set
++CONFIG_USB_FILE_STORAGE=m
++# CONFIG_USB_FILE_STORAGE_TEST is not set
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++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_TCC_SDHC=y
++CONFIG_MMC_TCC_SDHC_CORE0=y
++# CONFIG_MMC_TCC_SDHC_CORE1 is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_NEW_LEDS=y
++# CONFIG_LEDS_CLASS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGERS=y
++# CONFIG_LEDS_TRIGGER_TIMER is not set
++# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
++# CONFIG_LEDS_TRIGGER_DEFAULT_ON 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=y
++# 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_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 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_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++
++#
++# SPI RTC drivers
++#
++
++#
++# 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_BQ4802 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# on-CPU RTC drivers
++#
++CONFIG_RTC_DRV_TCC=y
++# CONFIG_DMADEVICES is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_UIO is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_JBD=y
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_DNOTIFY is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++CONFIG_FUSE_FS=y
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++CONFIG_JOLIET=y
++# CONFIG_ZISOFS is not set
++CONFIG_UDF_FS=y
++CONFIG_UDF_NLS=y
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++# CONFIG_MSDOS_FS is not set
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++# CONFIG_SUNRPC_REGISTER_V4 is not set
++CONFIG_RPCSEC_GSS_KRB5=y
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++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=y
++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 is not set
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_UNUSED_SYMBOLS=y
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++CONFIG_DETECT_SOFTLOCKUP=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_TIMER_STATS is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_DEBUG_ON is not set
++# CONFIG_SLUB_STATS is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_SG is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_CPU_STALL_DETECTOR is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP is not set
++# CONFIG_SYSCTL_SYSCALL_CHECK is not set
++CONFIG_HAVE_FUNCTION_TRACER=y
++
++#
++# Tracers
++#
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_CONTEXT_SWITCH_TRACER is not set
++# CONFIG_BOOT_TRACER is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_DEBUG_USER is not set
++# CONFIG_DEBUG_ERRORS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_ICEDCC is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_FIPS is not set
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++CONFIG_CRYPTO_CBC=y
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=m
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++# 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=m
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=m
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=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_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++CONFIG_CRYPTO_HW=y
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++CONFIG_CRC_ITU_T=y
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
+diff --git a/arch/arm/configs/SmartV5_ramdisk_defconfig b/arch/arm/configs/SmartV5_ramdisk_defconfig
+new file mode 100644
+index 0000000..3b3e147
+--- /dev/null
++++ b/arch/arm/configs/SmartV5_ramdisk_defconfig
+@@ -0,0 +1,1469 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.28
++# Thu Sep 17 18:45:58 2009
++#
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_GENERIC_TIME is not set
++# CONFIG_GENERIC_CLOCKEVENTS is not set
++CONFIG_MMU=y
++# CONFIG_NO_IOPORT is not set
++CONFIG_GENERIC_HARDIRQS=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_ILOG2_U32 is not set
++# CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++# CONFIG_CGROUPS is not set
++# CONFIG_GROUP_SCHED is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++CONFIG_RELAY=y
++CONFIG_NAMESPACES=y
++# CONFIG_UTS_NS is not set
++# CONFIG_IPC_NS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++# CONFIG_EMBEDDED is not set
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_KALLSYMS_EXTRA_PASS=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_VM_EVENT_COUNTERS=y
++CONFIG_SLUB_DEBUG=y
++# CONFIG_COMPAT_BRK is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++# CONFIG_MARKERS is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++CONFIG_MODULE_SRCVERSION_ALL=y
++CONFIG_KMOD=y
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF 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_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_CLASSIC_RCU=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IMX 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_L7200 is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_NS9XXX is not set
++# CONFIG_ARCH_LOKI is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_ARCH_MSM is not set
++CONFIG_ARCH_TCC=y
++
++#
++# Boot options
++#
++
++#
++# Power management
++#
++
++#
++# TCC Core Type
++#
++CONFIG_ARCH_TCC8900=y
++CONFIG_TCC_R_AX=y
++# CONFIG_TCC_R_XX is not set
++
++#
++# TCC Board Type
++#
++CONFIG_MACH_TCC8900=y
++# CONFIG_RAM_128MB is not set
++CONFIG_RAM_256MB=y
++# CONFIG_HD720p_LEVEL41 is not set
++# CONFIG_HD720p_LEVEL51 is not set
++# CONFIG_HD1080p_LEVEL41 is not set
++CONFIG_HD1080p_LEVEL51=y
++CONFIG_TCC_STRING="tcc8900"
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_V6=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v6=y
++CONFIG_CPU_ABRT_EV6=y
++CONFIG_CPU_PABRT_NOIFAR=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
++
++#
++# 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_OUTER_CACHE is not set
++
++#
++# Bus support
++#
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_PREEMPT is not set
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++CONFIG_ARCH_FLATMEM_HAS_HOLES=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_DISCONTIGMEM_MANUAL is not set
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_UNEVICTABLE_LRU is not set
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="root=/dev/ram rw initrd=0x40700000,0x1000000 init=/linuxrc console=ttySAC0"
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_FREQ is not set
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_NWFPE_XP is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_VFP=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++CONFIG_BINFMT_AOUT=y
++CONFIG_BINFMT_MISC=y
++
++#
++# Power management options
++#
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_APM_EMULATION is not set
++
++#
++# Dynamic Power Management
++#
++CONFIG_DPM=y
++CONFIG_DPM_PROCFS=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_FIB_HASH=y
++CONFIG_IP_PNP=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++CONFIG_IP_PNP_RARP=y
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE 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 is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++# CONFIG_INET_LRO is not set
++# CONFIG_INET_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_SCHED 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_PHONET is not set
++CONFIG_WIRELESS=y
++CONFIG_CFG80211=m
++CONFIG_NL80211=y
++CONFIG_WIRELESS_OLD_REGULATORY=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WIRELESS_EXT_SYSFS=y
++CONFIG_MAC80211=m
++
++#
++# Rate control algorithm selection
++#
++CONFIG_MAC80211_RC_PID=y
++CONFIG_MAC80211_RC_MINSTREL=y
++CONFIG_MAC80211_RC_DEFAULT_PID=y
++# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
++CONFIG_MAC80211_RC_DEFAULT="pid"
++# CONFIG_MAC80211_MESH is not set
++CONFIG_MAC80211_LEDS=y
++# CONFIG_MAC80211_DEBUG_MENU is not set
++CONFIG_IEEE80211=m
++# CONFIG_IEEE80211_DEBUG is not set
++CONFIG_IEEE80211_CRYPT_WEP=m
++# CONFIG_IEEE80211_CRYPT_CCMP is not set
++# CONFIG_IEEE80211_CRYPT_TKIP is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++CONFIG_DEBUG_DEVRES=y
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_CONNECTOR is not set
++# CONFIG_MTD 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
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=2
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++CONFIG_CDROM_PKTCDVD=y
++CONFIG_CDROM_PKTCDVD_BUFFERS=8
++# CONFIG_CDROM_PKTCDVD_WCACHE is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_TCC_NAND_V6 is not set
++CONFIG_TCC_NAND_V7=m
++# CONFIG_MISC_DEVICES is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++CONFIG_SCSI_MULTI_LUN=y
++# 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_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_ATA is not set
++# CONFIG_MD 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 is not set
++# CONFIG_VETH is not set
++# CONFIG_PHYLIB is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_AX88796 is not set
++# CONFIG_SMC91X is not set
++# CONFIG_DM9000 is not set
++# CONFIG_SMC911X 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_NETDEV_1000 is not set
++# CONFIG_NETDEV_10000 is not set
++
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++CONFIG_WLAN_80211=y
++# CONFIG_LIBERTAS is not set
++# CONFIG_LIBERTAS_THINFIRM is not set
++CONFIG_MARVELL_8686_SDIO=m
++# CONFIG_MARVELL_8686_PROC_FS is not set
++# CONFIG_MARVELL_8686_DEBUG is not set
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_USB_NET_RNDIS_WLAN is not set
++# CONFIG_RTL8187 is not set
++# CONFIG_MAC80211_HWSIM is not set
++# CONFIG_P54_COMMON is not set
++# CONFIG_IWLWIFI_LEDS is not set
++# CONFIG_HOSTAP is not set
++# CONFIG_B43 is not set
++# CONFIG_B43LEGACY is not set
++# CONFIG_ZD1211RW is not set
++# CONFIG_RT2X00 is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_WAN is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++CONFIG_INPUT_FF_MEMLESS=y
++# CONFIG_INPUT_POLLDEV is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++CONFIG_KEYBOARD_GPIO=y
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++# CONFIG_TOUCHSCREEN_FUJITSU is not set
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_INEXIO is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++# CONFIG_TOUCHSCREEN_PENMOUNT is not set
++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
++# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
++CONFIG_TOUCHSCREEN_TCCTS=y
++# CONFIG_LCD01 is not set
++# CONFIG_LCD11 is not set
++CONFIG_LCD10=y
++# 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_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_DEVKMEM is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_TCC=y
++CONFIG_SERIAL_TCC_CONSOLE=y
++CONFIG_SERIAL_TCC_DMA=y
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++CONFIG_UNIX98_PTYS=y
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_NVRAM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_TCC_CKC_IOCTL=y
++CONFIG_TCC_USER_INTR=y
++CONFIG_TCC_BL=y
++CONFIG_LCD_4=y
++# CONFIG_LCD_7 is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_HELPER_AUTO is not set
++
++#
++# I2C Algorithms
++#
++CONFIG_I2C_ALGOBIT=y
++# 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_GPIO=y
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_SIMTEC is not set
++CONFIG_I2C_TCC=y
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_STUB is not set
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_DS1682 is not set
++# CONFIG_AT24 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_PCF8575 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_MAX6875 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_TCC_I2C_WM8731 is not set
++CONFIG_TCC_I2C_WM8987=y
++CONFIG_TCC_I2C_PCA953X=y
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_I2C_DEBUG_CHIP is not set
++# CONFIG_SPI is not set
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_THERMAL_HWMON is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM8350_I2C is not set
++
++#
++# Multimedia devices
++#
++
++#
++# Multimedia core support
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++# CONFIG_VIDEO_MEDIA is not set
++
++#
++# Multimedia drivers
++#
++# CONFIG_DAB is not set
++
++#
++# Graphics support
++#
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_S1D13XXX is not set
++CONFIG_FB_TCC8900=y
++# CONFIG_FB_TCC_A070VW04 is not set
++CONFIG_FB_TCC_TD043MTEX=y
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_MB862XX is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
++
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_LOGO_LINUX_CLUT224=y
++CONFIG_SOUND=y
++# CONFIG_SOUND_OSS_CORE is not set
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++# CONFIG_SND_SEQUENCER is not set
++# CONFIG_SND_MIXER_OSS is not set
++# CONFIG_SND_PCM_OSS is not set
++# CONFIG_SND_DYNAMIC_MINORS is not set
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++CONFIG_SND_DRIVERS=y
++# CONFIG_SND_DUMMY is not set
++# CONFIG_SND_MTPAV is not set
++# CONFIG_SND_SERIAL_U16550 is not set
++# CONFIG_SND_MPU401 is not set
++CONFIG_SND_ARM=y
++CONFIG_SND_USB=y
++# CONFIG_SND_USB_AUDIO is not set
++# CONFIG_SND_USB_CAIAQ is not set
++CONFIG_SND_SOC=y
++CONFIG_SND_TCC_SOC=y
++CONFIG_SND_TCC_SOC_I2S=y
++# CONFIG_SND_TCC_SOC_BOARD_WM8731 is not set
++# CONFIG_SND_TCC_SOC_BOARD_WM8581 is not set
++CONFIG_SND_TCC_SOC_BOARD_WM8987=y
++CONFIG_AUDIO_CODEC_PROCFS=y
++# CONFIG_SND_SOC_ALL_CODECS is not set
++CONFIG_SND_SOC_WM8987=y
++# CONFIG_SOUND_PRIME is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++CONFIG_HID_DEBUG=y
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# Special HID drivers
++#
++CONFIG_HID_COMPAT=y
++CONFIG_HID_A4TECH=y
++CONFIG_HID_APPLE=y
++CONFIG_HID_BELKIN=y
++CONFIG_HID_BRIGHT=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++CONFIG_HID_DELL=y
++CONFIG_HID_EZKEY=y
++CONFIG_HID_GYRATION=y
++CONFIG_HID_LOGITECH=y
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++CONFIG_HID_PANTHERLORD=y
++# CONFIG_PANTHERLORD_FF is not set
++CONFIG_HID_PETALYNX=y
++CONFIG_HID_SAMSUNG=y
++CONFIG_HID_SONY=y
++CONFIG_HID_SUNPLUS=y
++# CONFIG_THRUSTMASTER_FF is not set
++# CONFIG_ZEROPLUS_FF is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++# CONFIG_USB_DEVICE_CLASS is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++CONFIG_USB_SUSPEND=y
++CONFIG_USB_OTG=y
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# Telechips DWC OTG Controller Drivers
++#
++CONFIG_TCC_DWC_OTG=y
++CONFIG_TCC_DWC_OTG_DUAL_ROLE=y
++# CONFIG_TCC_DWC_OTG_DEVICE_ONLY is not set
++# CONFIG_TCC_DWC_OTG_HOST_ONLY is not set
++# CONFIG_TCC_DWC_OTG_DEBUG is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
++# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HWA_HCD is not set
++# CONFIG_USB_GADGET_MUSB_HDRC is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
++#
++
++#
++# see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_DPCM is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++CONFIG_USB_SERIAL=m
++# CONFIG_USB_EZUSB is not set
++# CONFIG_USB_SERIAL_GENERIC is not set
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_ARK3116 is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_CH341 is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_CP2101 is not set
++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++# CONFIG_USB_SERIAL_FTDI_SIO is not set
++# CONFIG_USB_SERIAL_FUNSOFT is not set
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
++# CONFIG_USB_SERIAL_GARMIN is not set
++# CONFIG_USB_SERIAL_IPW is not set
++# CONFIG_USB_SERIAL_IUU is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_MOS7720 is not set
++# CONFIG_USB_SERIAL_MOS7840 is not set
++# CONFIG_USB_SERIAL_MOTOROLA is not set
++# CONFIG_USB_SERIAL_NAVMAN is not set
++# CONFIG_USB_SERIAL_PL2303 is not set
++# CONFIG_USB_SERIAL_OTI6858 is not set
++# CONFIG_USB_SERIAL_SPCP8X5 is not set
++# CONFIG_USB_SERIAL_HP4X is not set
++# CONFIG_USB_SERIAL_SAFE is not set
++# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
++# CONFIG_USB_SERIAL_TI is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++# CONFIG_USB_SERIAL_OPTION is not set
++# CONFIG_USB_SERIAL_OMNINET is not set
++# CONFIG_USB_SERIAL_DEBUG is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_BERRY_CHARGE is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGET is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_VST is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_SELECTED=y
++CONFIG_USB_GADGET_TCC_OTG=y
++CONFIG_USB_TCC_OTG=y
++# CONFIG_USB_GADGET_AT91 is not set
++# CONFIG_USB_GADGET_ATMEL_USBA is not set
++# CONFIG_USB_GADGET_FSL_USB2 is not set
++# CONFIG_USB_GADGET_LH7A40X is not set
++# CONFIG_USB_GADGET_OMAP is not set
++# CONFIG_USB_GADGET_PXA25X is not set
++# CONFIG_USB_GADGET_PXA27X is not set
++# CONFIG_USB_GADGET_S3C2410 is not set
++# CONFIG_USB_GADGET_M66592 is not set
++# CONFIG_USB_GADGET_AMD5536UDC is not set
++# CONFIG_USB_GADGET_FSL_QE is not set
++# CONFIG_USB_GADGET_NET2280 is not set
++# CONFIG_USB_GADGET_GOKU is not set
++# CONFIG_USB_GADGET_DUMMY_HCD is not set
++CONFIG_USB_GADGET_DUALSPEED=y
++# CONFIG_USB_ZERO is not set
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_GADGETFS is not set
++CONFIG_USB_FILE_STORAGE=m
++# CONFIG_USB_FILE_STORAGE_TEST is not set
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++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_TCC_SDHC=y
++CONFIG_MMC_TCC_SDHC_CORE0=y
++# CONFIG_MMC_TCC_SDHC_CORE1 is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_NEW_LEDS=y
++# CONFIG_LEDS_CLASS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGERS=y
++# CONFIG_LEDS_TRIGGER_TIMER is not set
++# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
++# CONFIG_LEDS_TRIGGER_DEFAULT_ON 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=y
++# 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_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 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_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++
++#
++# SPI RTC drivers
++#
++
++#
++# 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_BQ4802 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# on-CPU RTC drivers
++#
++CONFIG_RTC_DRV_TCC=y
++# CONFIG_DMADEVICES is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_UIO is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_JBD=y
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_DNOTIFY is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++CONFIG_FUSE_FS=y
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++CONFIG_JOLIET=y
++# CONFIG_ZISOFS is not set
++CONFIG_UDF_FS=y
++CONFIG_UDF_NLS=y
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++# CONFIG_MSDOS_FS is not set
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_AUFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++# CONFIG_SUNRPC_REGISTER_V4 is not set
++CONFIG_RPCSEC_GSS_KRB5=y
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++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=y
++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 is not set
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_UNUSED_SYMBOLS=y
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++CONFIG_DETECT_SOFTLOCKUP=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_TIMER_STATS is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_DEBUG_ON is not set
++# CONFIG_SLUB_STATS is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_SG is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_CPU_STALL_DETECTOR is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP is not set
++# CONFIG_SYSCTL_SYSCALL_CHECK is not set
++CONFIG_HAVE_FUNCTION_TRACER=y
++
++#
++# Tracers
++#
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_CONTEXT_SWITCH_TRACER is not set
++# CONFIG_BOOT_TRACER is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_DEBUG_USER is not set
++# CONFIG_DEBUG_ERRORS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_ICEDCC is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_FIPS is not set
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++CONFIG_CRYPTO_CBC=y
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=m
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++# 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=m
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=m
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=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_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++CONFIG_CRYPTO_HW=y
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++CONFIG_CRC_ITU_T=y
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
+diff --git a/arch/arm/configs/SmartV7_defconfig b/arch/arm/configs/SmartV7_defconfig
+new file mode 100644
+index 0000000..c9ba2f0
+--- /dev/null
++++ b/arch/arm/configs/SmartV7_defconfig
+@@ -0,0 +1,1515 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.28
++# Tue Nov 10 14:34:35 2009
++#
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_GENERIC_TIME is not set
++# CONFIG_GENERIC_CLOCKEVENTS is not set
++CONFIG_MMU=y
++# CONFIG_NO_IOPORT is not set
++CONFIG_GENERIC_HARDIRQS=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_ILOG2_U32 is not set
++# CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_LOCK_KERNEL=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++# CONFIG_CGROUPS is not set
++# CONFIG_GROUP_SCHED is not set
++# CONFIG_SYSFS_DEPRECATED_V2 is not set
++CONFIG_RELAY=y
++# CONFIG_NAMESPACES is not set
++# CONFIG_BLK_DEV_INITRD is not set
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++# CONFIG_UID16 is not set
++CONFIG_SYSCTL_SYSCALL=y
++# CONFIG_KALLSYMS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++# CONFIG_BUG is not set
++# CONFIG_ELF_CORE is not set
++# CONFIG_COMPAT_BRK is not set
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_ANON_INODES=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++# CONFIG_SHMEM is not set
++CONFIG_AIO=y
++CONFIG_VM_EVENT_COUNTERS=y
++# CONFIG_SLUB_DEBUG is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++# CONFIG_MARKERS is not set
++CONFIG_HAVE_OPROFILE=y
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_RT_MUTEXES=y
++CONFIG_TINY_SHMEM=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_KMOD=y
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF 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_AS is not set
++# CONFIG_IOSCHED_DEADLINE is not set
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_CLASSIC_RCU=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IMX 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_L7200 is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_NS9XXX is not set
++# CONFIG_ARCH_LOKI is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_ARCH_MSM is not set
++CONFIG_ARCH_TCC=y
++
++#
++# Boot options
++#
++
++#
++# Power management
++#
++
++#
++# TCC Core Type
++#
++CONFIG_ARCH_TCC8900=y
++CONFIG_TCC_R_AX=y
++# CONFIG_TCC_R_XX is not set
++
++#
++# TCC Board Type
++#
++CONFIG_MACH_TCC8900=y
++CONFIG_DRAM_DDR2=y
++# CONFIG_DRAM_MDDR is not set
++# CONFIG_RAM_128MB is not set
++CONFIG_RAM_256MB=y
++# CONFIG_HD720p_LEVEL41 is not set
++# CONFIG_HD720p_LEVEL51 is not set
++# CONFIG_HD1080p_LEVEL41 is not set
++CONFIG_HD1080p_LEVEL51=y
++CONFIG_TCC_STRING="tcc8900"
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_V6=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v6=y
++CONFIG_CPU_ABRT_EV6=y
++CONFIG_CPU_PABRT_NOIFAR=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
++
++#
++# 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_OUTER_CACHE is not set
++
++#
++# Bus support
++#
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_PREEMPT=y
++CONFIG_HZ=200
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++CONFIG_ARCH_FLATMEM_HAS_HOLES=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_DISCONTIGMEM_MANUAL is not set
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_UNEVICTABLE_LRU is not set
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttySAC0,115200n8 root=/dev/ndda1 rw rootwait splash quiet"
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++
++#
++# CPU Power Management
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++# CONFIG_CPU_FREQ_DEBUG is not set
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++CONFIG_CPU_FREQ_GOV_USERSPACE=m
++CONFIG_CPU_FREQ_GOV_ONDEMAND=m
++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
++# 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 is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_MISC=m
++
++#
++# Power management options
++#
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_APM_EMULATION is not set
++
++#
++# Dynamic Power Management
++#
++CONFIG_DPM=y
++CONFIG_DPM_PROCFS=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=m
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_FIB_HASH=y
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE 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 is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++# CONFIG_INET_LRO is not set
++# CONFIG_INET_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++# CONFIG_NETFILTER_ADVANCED is not set
++
++#
++# Core Netfilter Configuration
++#
++# CONFIG_NETFILTER_NETLINK_LOG is not set
++# CONFIG_NF_CONNTRACK is not set
++CONFIG_NETFILTER_XTABLES=m
++# CONFIG_NETFILTER_XT_TARGET_MARK is not set
++# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
++# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
++# CONFIG_NETFILTER_XT_MATCH_MARK is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_SCHED 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=m
++CONFIG_BT_L2CAP=m
++CONFIG_BT_SCO=m
++CONFIG_BT_RFCOMM=m
++CONFIG_BT_RFCOMM_TTY=y
++CONFIG_BT_BNEP=m
++CONFIG_BT_BNEP_MC_FILTER=y
++CONFIG_BT_BNEP_PROTO_FILTER=y
++CONFIG_BT_HIDP=m
++
++#
++# Bluetooth device drivers
++#
++CONFIG_BT_HCIBTUSB=m
++# CONFIG_BT_HCIBTSDIO is not set
++# CONFIG_BT_HCIUART is not set
++# CONFIG_BT_HCIBCM203X is not set
++# CONFIG_BT_HCIBPA10X is not set
++# CONFIG_BT_HCIBFUSB is not set
++# CONFIG_BT_HCIVHCI is not set
++# CONFIG_AF_RXRPC is not set
++# CONFIG_PHONET is not set
++CONFIG_WIRELESS=y
++CONFIG_CFG80211=m
++CONFIG_NL80211=y
++# CONFIG_WIRELESS_OLD_REGULATORY is not set
++CONFIG_WIRELESS_EXT=y
++# CONFIG_WIRELESS_EXT_SYSFS is not set
++CONFIG_MAC80211=m
++
++#
++# Rate control algorithm selection
++#
++CONFIG_MAC80211_RC_PID=y
++CONFIG_MAC80211_RC_MINSTREL=y
++CONFIG_MAC80211_RC_DEFAULT_PID=y
++# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
++CONFIG_MAC80211_RC_DEFAULT="pid"
++# CONFIG_MAC80211_MESH is not set
++# CONFIG_MAC80211_LEDS is not set
++# CONFIG_MAC80211_DEBUG_MENU is not set
++CONFIG_IEEE80211=m
++# CONFIG_IEEE80211_DEBUG is not set
++CONFIG_IEEE80211_CRYPT_WEP=m
++# CONFIG_IEEE80211_CRYPT_CCMP is not set
++# CONFIG_IEEE80211_CRYPT_TKIP is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++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 is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=m
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=2
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_TCC_NAND_V6 is not set
++CONFIG_TCC_NAND_V7=y
++CONFIG_MISC_DEVICES=y
++CONFIG_SMARTQV_ENCRYPT=y
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_C2PORT is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=m
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=m
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=m
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++# 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_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_ATA is not set
++# CONFIG_MD 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_PHYLIB is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=m
++# CONFIG_AX88796 is not set
++# CONFIG_SMC91X is not set
++# CONFIG_DM9000 is not set
++# CONFIG_SMC911X 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_NETDEV_1000 is not set
++# CONFIG_NETDEV_10000 is not set
++
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++CONFIG_WLAN_80211=y
++# CONFIG_LIBERTAS is not set
++# CONFIG_LIBERTAS_THINFIRM is not set
++CONFIG_MARVELL_8686_SDIO=m
++CONFIG_MARVELL_8686_PROC_FS=y
++CONFIG_MARVELL_8686_DEBUG=y
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_USB_NET_RNDIS_WLAN is not set
++# CONFIG_RTL8187 is not set
++# CONFIG_MAC80211_HWSIM is not set
++# CONFIG_P54_COMMON is not set
++# CONFIG_IWLWIFI_LEDS is not set
++# CONFIG_HOSTAP is not set
++# CONFIG_B43 is not set
++# CONFIG_B43LEGACY is not set
++# CONFIG_ZD1211RW is not set
++# CONFIG_RT2X00 is not set
++
++#
++# USB Network Adapters
++#
++CONFIG_USB_CATC=m
++CONFIG_USB_KAWETH=m
++CONFIG_USB_PEGASUS=m
++CONFIG_USB_RTL8150=m
++CONFIG_USB_USBNET=m
++CONFIG_USB_NET_AX8817X=m
++CONFIG_USB_NET_CDCETHER=m
++CONFIG_USB_NET_DM9601=m
++CONFIG_USB_NET_SMSC95XX=m
++CONFIG_USB_NET_GL620A=m
++CONFIG_USB_NET_NET1080=m
++CONFIG_USB_NET_PLUSB=m
++CONFIG_USB_NET_MCS7830=m
++CONFIG_USB_NET_RNDIS_HOST=m
++CONFIG_USB_NET_CDC_SUBSET=m
++CONFIG_USB_ALI_M5632=y
++CONFIG_USB_AN2720=y
++CONFIG_USB_BELKIN=y
++CONFIG_USB_ARMLINUX=y
++CONFIG_USB_EPSON2888=y
++CONFIG_USB_KC2190=y
++CONFIG_USB_NET_ZAURUS=m
++# CONFIG_WAN is not set
++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=m
++CONFIG_PPP_MPPE=m
++CONFIG_PPPOE=m
++CONFIG_PPPOL2TP=m
++# CONFIG_SLIP is not set
++CONFIG_SLHC=m
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=800
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ATKBD is not set
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++CONFIG_KEYBOARD_GPIO=y
++CONFIG_INPUT_MOUSE=y
++# CONFIG_MOUSE_PS2 is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++# CONFIG_TOUCHSCREEN_FUJITSU is not set
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_INEXIO is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++# CONFIG_TOUCHSCREEN_PENMOUNT is not set
++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
++# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
++CONFIG_TOUCHSCREEN_TCCTS=y
++# CONFIG_LCD01 is not set
++# CONFIG_LCD11 is not set
++CONFIG_LCD10=y
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_ATI_REMOTE is not set
++# CONFIG_INPUT_ATI_REMOTE2 is not set
++# CONFIG_INPUT_KEYSPAN_REMOTE is not set
++# CONFIG_INPUT_POWERMATE is not set
++# CONFIG_INPUT_YEALINK is not set
++# CONFIG_INPUT_CM109 is not set
++CONFIG_INPUT_UINPUT=m
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_DEVKMEM is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_TCC=y
++CONFIG_SERIAL_TCC_CONSOLE=y
++# CONFIG_SERIAL_TCC_DMA is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++CONFIG_UNIX98_PTYS=y
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_NVRAM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_TCC_CKC_IOCTL=y
++CONFIG_TCC_USER_INTR=y
++CONFIG_TCC_BL=y
++CONFIG_TCC_POWER_CTL=y
++# CONFIG_LCD_4 is not set
++CONFIG_LCD_7=y
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_CHARDEV=m
++# CONFIG_I2C_HELPER_AUTO is not set
++
++#
++# I2C Algorithms
++#
++CONFIG_I2C_ALGOBIT=y
++# 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_GPIO=y
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_SIMTEC is not set
++CONFIG_I2C_TCC=y
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_STUB is not set
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_DS1682 is not set
++# CONFIG_AT24 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_PCF8575 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_MAX6875 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_TCC_I2C_WM8731 is not set
++CONFIG_TCC_I2C_WM8987=y
++CONFIG_TCC_I2C_PCA953X=y
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_I2C_DEBUG_CHIP is not set
++# CONFIG_SPI is not set
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_THERMAL_HWMON is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM8350_I2C is not set
++
++#
++# Multimedia devices
++#
++
++#
++# Multimedia core support
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++# CONFIG_VIDEO_MEDIA is not set
++
++#
++# Multimedia drivers
++#
++# CONFIG_DAB is not set
++
++#
++# Graphics support
++#
++# CONFIG_VGASTATE is not set
++CONFIG_VIDEO_OUTPUT_CONTROL=m
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++# CONFIG_FB_TILEBLITTING is not set
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_S1D13XXX is not set
++CONFIG_FB_TCC8900=y
++CONFIG_FB_TCC_A070VW04=y
++# CONFIG_FB_TCC_TD043MTEX is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_MB862XX is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
++
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++CONFIG_LOGO=y
++CONFIG_LOGO_CENTER=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_LOGO_LINUX_CLUT224=y
++CONFIG_SOUND=y
++CONFIG_SOUND_OSS_CORE=y
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++# CONFIG_SND_SEQUENCER is not set
++CONFIG_SND_OSSEMUL=y
++CONFIG_SND_MIXER_OSS=y
++CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
++# CONFIG_SND_DYNAMIC_MINORS is not set
++# CONFIG_SND_SUPPORT_OLD_API is not set
++# CONFIG_SND_VERBOSE_PROCFS is not set
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++# CONFIG_SND_DRIVERS is not set
++# CONFIG_SND_ARM is not set
++# CONFIG_SND_USB is not set
++CONFIG_SND_SOC=y
++CONFIG_SND_TCC_SOC=y
++CONFIG_SND_TCC_SOC_I2S=y
++# CONFIG_SND_TCC_SOC_BOARD_WM8731 is not set
++# CONFIG_SND_TCC_SOC_BOARD_WM8581 is not set
++CONFIG_SND_TCC_SOC_BOARD_WM8987=y
++CONFIG_AUDIO_CODEC_PROCFS=y
++# CONFIG_SND_SOC_ALL_CODECS is not set
++CONFIG_SND_SOC_WM8987=y
++# CONFIG_SOUND_PRIME is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=m
++# CONFIG_HID_DEBUG is not set
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=m
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++CONFIG_USB_KBD=m
++CONFIG_USB_MOUSE=m
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_COMPAT is not set
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_BRIGHT is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DELL is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_THRUSTMASTER_FF is not set
++# CONFIG_ZEROPLUS_FF is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++# CONFIG_USB_DEVICE_CLASS is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++CONFIG_USB_SUSPEND=y
++CONFIG_USB_OTG=y
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# Telechips DWC OTG Controller Drivers
++#
++CONFIG_TCC_DWC_OTG=m
++CONFIG_TCC_DWC_OTG_DUAL_ROLE=y
++# CONFIG_TCC_DWC_OTG_DEVICE_ONLY is not set
++# CONFIG_TCC_DWC_OTG_HOST_ONLY is not set
++# CONFIG_TCC_DWC_OTG_DEBUG is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
++# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HWA_HCD is not set
++# CONFIG_USB_GADGET_MUSB_HDRC is not set
++
++#
++# USB Device Class drivers
++#
++CONFIG_USB_ACM=m
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
++#
++
++#
++# see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=m
++# CONFIG_USB_STORAGE_DEBUG is not set
++CONFIG_USB_STORAGE_DATAFAB=y
++CONFIG_USB_STORAGE_FREECOM=y
++CONFIG_USB_STORAGE_ISD200=y
++CONFIG_USB_STORAGE_DPCM=y
++CONFIG_USB_STORAGE_USBAT=y
++CONFIG_USB_STORAGE_SDDR09=y
++CONFIG_USB_STORAGE_SDDR55=y
++CONFIG_USB_STORAGE_JUMPSHOT=y
++CONFIG_USB_STORAGE_ALAUDA=y
++CONFIG_USB_STORAGE_ONETOUCH=y
++CONFIG_USB_STORAGE_KARMA=y
++CONFIG_USB_STORAGE_CYPRESS_ATACB=y
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++CONFIG_USB_SERIAL=m
++# CONFIG_USB_EZUSB is not set
++CONFIG_USB_SERIAL_GENERIC=y
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_ARK3116 is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_CH341 is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_CP2101 is not set
++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++# CONFIG_USB_SERIAL_FTDI_SIO is not set
++# CONFIG_USB_SERIAL_FUNSOFT is not set
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
++# CONFIG_USB_SERIAL_GARMIN is not set
++# CONFIG_USB_SERIAL_IPW is not set
++# CONFIG_USB_SERIAL_IUU is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_MOS7720 is not set
++# CONFIG_USB_SERIAL_MOS7840 is not set
++# CONFIG_USB_SERIAL_MOTOROLA is not set
++# CONFIG_USB_SERIAL_NAVMAN is not set
++# CONFIG_USB_SERIAL_PL2303 is not set
++# CONFIG_USB_SERIAL_OTI6858 is not set
++# CONFIG_USB_SERIAL_SPCP8X5 is not set
++# CONFIG_USB_SERIAL_HP4X is not set
++# CONFIG_USB_SERIAL_SAFE is not set
++# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
++# CONFIG_USB_SERIAL_TI is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++CONFIG_USB_SERIAL_OPTION=m
++# CONFIG_USB_SERIAL_OMNINET is not set
++# CONFIG_USB_SERIAL_DEBUG is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_BERRY_CHARGE is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGET is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_VST is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_SELECTED=y
++CONFIG_USB_GADGET_TCC_OTG=y
++CONFIG_USB_TCC_OTG=y
++# CONFIG_USB_GADGET_AT91 is not set
++# CONFIG_USB_GADGET_ATMEL_USBA is not set
++# CONFIG_USB_GADGET_FSL_USB2 is not set
++# CONFIG_USB_GADGET_LH7A40X is not set
++# CONFIG_USB_GADGET_OMAP is not set
++# CONFIG_USB_GADGET_PXA25X is not set
++# CONFIG_USB_GADGET_PXA27X is not set
++# CONFIG_USB_GADGET_S3C2410 is not set
++# CONFIG_USB_GADGET_M66592 is not set
++# CONFIG_USB_GADGET_AMD5536UDC is not set
++# CONFIG_USB_GADGET_FSL_QE is not set
++# CONFIG_USB_GADGET_NET2280 is not set
++# CONFIG_USB_GADGET_GOKU is not set
++# CONFIG_USB_GADGET_DUMMY_HCD is not set
++CONFIG_USB_GADGET_DUALSPEED=y
++# CONFIG_USB_ZERO is not set
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_GADGETFS is not set
++CONFIG_USB_FILE_STORAGE=m
++# CONFIG_USB_FILE_STORAGE_TEST is not set
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++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_TCC_SDHC=y
++CONFIG_MMC_TCC_SDHC_CORE0=y
++CONFIG_MMC_TCC_SDHC_CORE1=y
++# CONFIG_MEMSTICK is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_NEW_LEDS=y
++# CONFIG_LEDS_CLASS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGERS=y
++# CONFIG_LEDS_TRIGGER_TIMER is not set
++# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
++# CONFIG_LEDS_TRIGGER_DEFAULT_ON 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_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 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_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++
++#
++# SPI RTC drivers
++#
++
++#
++# 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_BQ4802 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# on-CPU RTC drivers
++#
++CONFIG_RTC_DRV_TCC=y
++# CONFIG_DMADEVICES is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_UIO is not set
++
++#
++# File systems
++#
++# CONFIG_EXT2_FS is not set
++CONFIG_EXT3_FS=y
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_JBD=y
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++CONFIG_FUSE_FS=m
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=m
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++# CONFIG_MSDOS_FS is not set
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="cp437"
++CONFIG_NTFS_FS=m
++# CONFIG_NTFS_DEBUG is not set
++CONFIG_NTFS_RW=y
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_CONFIGFS_FS=m
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_AUFS_FS=m
++CONFIG_AUFS_BRANCH_MAX_127=y
++# CONFIG_AUFS_BRANCH_MAX_511 is not set
++# CONFIG_AUFS_BRANCH_MAX_1023 is not set
++# CONFIG_AUFS_BRANCH_MAX_32767 is not set
++CONFIG_AUFS_HINOTIFY=y
++# CONFIG_AUFS_RDU is not set
++# CONFIG_AUFS_SHWH is not set
++# CONFIG_AUFS_BR_RAMFS is not set
++# CONFIG_AUFS_DEBUG is not set
++CONFIG_AUFS_BDEV_LOOP=y
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=m
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=m
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=m
++# CONFIG_SUNRPC_REGISTER_V4 is not set
++# CONFIG_RPCSEC_GSS_KRB5 is not set
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++# CONFIG_NLS_ISO8859_1 is not set
++# 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=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_KERNEL is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_RCU_CPU_STALL_DETECTOR is not set
++# CONFIG_LATENCYTOP is not set
++# CONFIG_SYSCTL_SYSCALL_CHECK is not set
++CONFIG_HAVE_FUNCTION_TRACER=y
++
++#
++# Tracers
++#
++# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_DEBUG_USER is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_FIPS is not set
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_MANAGER=m
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=m
++# 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
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++# 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=m
++# 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=m
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=m
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++CONFIG_CRYPTO_HW=y
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=m
++CONFIG_CRC_CCITT=m
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=m
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++CONFIG_ZLIB_INFLATE=m
++CONFIG_ZLIB_DEFLATE=m
++CONFIG_PLIST=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
+diff --git a/arch/arm/configs/SmartV7_initramfs_defconfig b/arch/arm/configs/SmartV7_initramfs_defconfig
+new file mode 100644
+index 0000000..500da3d
+--- /dev/null
++++ b/arch/arm/configs/SmartV7_initramfs_defconfig
+@@ -0,0 +1,1472 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.28
++# Thu Aug 27 19:32:38 2009
++#
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_GENERIC_TIME is not set
++# CONFIG_GENERIC_CLOCKEVENTS is not set
++CONFIG_MMU=y
++# CONFIG_NO_IOPORT is not set
++CONFIG_GENERIC_HARDIRQS=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_ILOG2_U32 is not set
++# CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++# CONFIG_CGROUPS is not set
++# CONFIG_GROUP_SCHED is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++CONFIG_RELAY=y
++CONFIG_NAMESPACES=y
++# CONFIG_UTS_NS is not set
++# CONFIG_IPC_NS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE="../rootfs"
++CONFIG_INITRAMFS_ROOT_UID=0
++CONFIG_INITRAMFS_ROOT_GID=0
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++# CONFIG_EMBEDDED is not set
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_KALLSYMS_EXTRA_PASS=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_VM_EVENT_COUNTERS=y
++CONFIG_SLUB_DEBUG=y
++# CONFIG_COMPAT_BRK is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++# CONFIG_MARKERS is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++CONFIG_MODULE_SRCVERSION_ALL=y
++CONFIG_KMOD=y
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF 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_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_CLASSIC_RCU=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IMX 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_L7200 is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_NS9XXX is not set
++# CONFIG_ARCH_LOKI is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_ARCH_MSM is not set
++CONFIG_ARCH_TCC=y
++
++#
++# Boot options
++#
++
++#
++# Power management
++#
++
++#
++# TCC Core Type
++#
++CONFIG_ARCH_TCC8900=y
++CONFIG_TCC_R_AX=y
++# CONFIG_TCC_R_XX is not set
++
++#
++# TCC Board Type
++#
++CONFIG_MACH_TCC8900=y
++# CONFIG_RAM_128MB is not set
++CONFIG_RAM_256MB=y
++# CONFIG_HD720p_LEVEL41 is not set
++# CONFIG_HD720p_LEVEL51 is not set
++CONFIG_HD1080p_LEVEL41=y
++# CONFIG_HD1080p_LEVEL51 is not set
++CONFIG_TCC_STRING="tcc8900"
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_V6=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v6=y
++CONFIG_CPU_ABRT_EV6=y
++CONFIG_CPU_PABRT_NOIFAR=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
++
++#
++# 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_OUTER_CACHE is not set
++
++#
++# Bus support
++#
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_PREEMPT is not set
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++CONFIG_ARCH_FLATMEM_HAS_HOLES=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_DISCONTIGMEM_MANUAL is not set
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_UNEVICTABLE_LRU is not set
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttySAC0,115200n8 rdinit=/sbin/init"
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_FREQ is not set
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_NWFPE_XP is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_VFP=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++CONFIG_BINFMT_AOUT=y
++CONFIG_BINFMT_MISC=y
++
++#
++# Power management options
++#
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_APM_EMULATION is not set
++
++#
++# Dynamic Power Management
++#
++CONFIG_DPM=y
++CONFIG_DPM_PROCFS=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_FIB_HASH=y
++CONFIG_IP_PNP=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++CONFIG_IP_PNP_RARP=y
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE 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 is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++# CONFIG_INET_LRO is not set
++# CONFIG_INET_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_SCHED 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_PHONET is not set
++CONFIG_WIRELESS=y
++CONFIG_CFG80211=m
++CONFIG_NL80211=y
++CONFIG_WIRELESS_OLD_REGULATORY=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WIRELESS_EXT_SYSFS=y
++CONFIG_MAC80211=m
++
++#
++# Rate control algorithm selection
++#
++CONFIG_MAC80211_RC_PID=y
++CONFIG_MAC80211_RC_MINSTREL=y
++CONFIG_MAC80211_RC_DEFAULT_PID=y
++# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
++CONFIG_MAC80211_RC_DEFAULT="pid"
++# CONFIG_MAC80211_MESH is not set
++CONFIG_MAC80211_LEDS=y
++# CONFIG_MAC80211_DEBUG_MENU is not set
++CONFIG_IEEE80211=m
++# CONFIG_IEEE80211_DEBUG is not set
++CONFIG_IEEE80211_CRYPT_WEP=m
++# CONFIG_IEEE80211_CRYPT_CCMP is not set
++# CONFIG_IEEE80211_CRYPT_TKIP is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++CONFIG_DEBUG_DEVRES=y
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_CONNECTOR is not set
++# CONFIG_MTD 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
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=2
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++CONFIG_CDROM_PKTCDVD=y
++CONFIG_CDROM_PKTCDVD_BUFFERS=8
++# CONFIG_CDROM_PKTCDVD_WCACHE is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_TCC_NAND_V6 is not set
++CONFIG_TCC_NAND_V7=y
++# CONFIG_MISC_DEVICES is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++CONFIG_SCSI_MULTI_LUN=y
++# 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_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_ATA is not set
++# CONFIG_MD 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 is not set
++# CONFIG_VETH is not set
++# CONFIG_PHYLIB is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_AX88796 is not set
++# CONFIG_SMC91X is not set
++# CONFIG_DM9000 is not set
++# CONFIG_SMC911X 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_NETDEV_1000 is not set
++# CONFIG_NETDEV_10000 is not set
++
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++CONFIG_WLAN_80211=y
++# CONFIG_LIBERTAS is not set
++# CONFIG_LIBERTAS_THINFIRM is not set
++CONFIG_MARVELL_8686_SDIO=m
++# CONFIG_MARVELL_8686_PROC_FS is not set
++# CONFIG_MARVELL_8686_DEBUG is not set
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_USB_NET_RNDIS_WLAN is not set
++# CONFIG_RTL8187 is not set
++# CONFIG_MAC80211_HWSIM is not set
++# CONFIG_P54_COMMON is not set
++# CONFIG_IWLWIFI_LEDS is not set
++# CONFIG_HOSTAP is not set
++# CONFIG_B43 is not set
++# CONFIG_B43LEGACY is not set
++# CONFIG_ZD1211RW is not set
++# CONFIG_RT2X00 is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_WAN is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++CONFIG_INPUT_FF_MEMLESS=y
++# CONFIG_INPUT_POLLDEV is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++CONFIG_KEYBOARD_GPIO=y
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++# CONFIG_TOUCHSCREEN_FUJITSU is not set
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_INEXIO is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++# CONFIG_TOUCHSCREEN_PENMOUNT is not set
++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
++# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
++CONFIG_TOUCHSCREEN_TCCTS=y
++# CONFIG_LCD01 is not set
++# CONFIG_LCD11 is not set
++CONFIG_LCD10=y
++# 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_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_DEVKMEM is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_TCC=y
++CONFIG_SERIAL_TCC_CONSOLE=y
++CONFIG_SERIAL_TCC_DMA=y
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++CONFIG_UNIX98_PTYS=y
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_NVRAM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_TCC_CKC_IOCTL=y
++CONFIG_TCC_USER_INTR=y
++CONFIG_TCC_BL=y
++# CONFIG_LCD_4 is not set
++CONFIG_LCD_7=y
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_HELPER_AUTO is not set
++
++#
++# I2C Algorithms
++#
++CONFIG_I2C_ALGOBIT=y
++# 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_GPIO=y
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_SIMTEC is not set
++CONFIG_I2C_TCC=y
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_STUB is not set
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_DS1682 is not set
++# CONFIG_AT24 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_PCF8575 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_MAX6875 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_TCC_I2C_WM8731 is not set
++CONFIG_TCC_I2C_WM8987=y
++CONFIG_TCC_I2C_PCA953X=y
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_I2C_DEBUG_CHIP is not set
++# CONFIG_SPI is not set
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_THERMAL_HWMON is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM8350_I2C is not set
++
++#
++# Multimedia devices
++#
++
++#
++# Multimedia core support
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++# CONFIG_VIDEO_MEDIA is not set
++
++#
++# Multimedia drivers
++#
++# CONFIG_DAB is not set
++
++#
++# Graphics support
++#
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_S1D13XXX is not set
++CONFIG_FB_TCC8900=y
++CONFIG_FB_TCC_A070VW04=y
++# CONFIG_FB_TCC_TD043MTEX is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_MB862XX is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
++
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_LOGO_LINUX_CLUT224=y
++CONFIG_SOUND=y
++CONFIG_SOUND_OSS_CORE=y
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++# CONFIG_SND_SEQUENCER is not set
++CONFIG_SND_OSSEMUL=y
++CONFIG_SND_MIXER_OSS=y
++CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
++# CONFIG_SND_DYNAMIC_MINORS is not set
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++CONFIG_SND_DRIVERS=y
++# CONFIG_SND_DUMMY is not set
++# CONFIG_SND_MTPAV is not set
++# CONFIG_SND_SERIAL_U16550 is not set
++# CONFIG_SND_MPU401 is not set
++CONFIG_SND_ARM=y
++CONFIG_SND_USB=y
++# CONFIG_SND_USB_AUDIO is not set
++# CONFIG_SND_USB_CAIAQ is not set
++CONFIG_SND_SOC=y
++CONFIG_SND_TCC_SOC=y
++CONFIG_SND_TCC_SOC_I2S=y
++# CONFIG_SND_TCC_SOC_BOARD_WM8731 is not set
++# CONFIG_SND_TCC_SOC_BOARD_WM8581 is not set
++CONFIG_SND_TCC_SOC_BOARD_WM8987=y
++CONFIG_AUDIO_CODEC_PROCFS=y
++# CONFIG_SND_SOC_ALL_CODECS is not set
++CONFIG_SND_SOC_WM8987=y
++# CONFIG_SOUND_PRIME is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++CONFIG_HID_DEBUG=y
++CONFIG_HIDRAW=y
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++CONFIG_USB_HIDDEV=y
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_COMPAT is not set
++CONFIG_HID_A4TECH=y
++CONFIG_HID_APPLE=y
++CONFIG_HID_BELKIN=y
++CONFIG_HID_BRIGHT=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++CONFIG_HID_DELL=y
++CONFIG_HID_EZKEY=y
++CONFIG_HID_GYRATION=y
++CONFIG_HID_LOGITECH=y
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++CONFIG_HID_PANTHERLORD=y
++# CONFIG_PANTHERLORD_FF is not set
++CONFIG_HID_PETALYNX=y
++CONFIG_HID_SAMSUNG=y
++CONFIG_HID_SONY=y
++CONFIG_HID_SUNPLUS=y
++# CONFIG_THRUSTMASTER_FF is not set
++# CONFIG_ZEROPLUS_FF is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++# CONFIG_USB_DEVICE_CLASS is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++CONFIG_USB_SUSPEND=y
++CONFIG_USB_OTG=y
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# Telechips DWC OTG Controller Drivers
++#
++CONFIG_TCC_DWC_OTG=y
++CONFIG_TCC_DWC_OTG_DUAL_ROLE=y
++# CONFIG_TCC_DWC_OTG_DEVICE_ONLY is not set
++# CONFIG_TCC_DWC_OTG_HOST_ONLY is not set
++# CONFIG_TCC_DWC_OTG_DEBUG is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
++# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HWA_HCD is not set
++# CONFIG_USB_GADGET_MUSB_HDRC is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
++#
++
++#
++# see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_DPCM is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++CONFIG_USB_SERIAL=m
++# CONFIG_USB_EZUSB is not set
++CONFIG_USB_SERIAL_GENERIC=y
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_ARK3116 is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_CH341 is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_CP2101 is not set
++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++# CONFIG_USB_SERIAL_FTDI_SIO is not set
++# CONFIG_USB_SERIAL_FUNSOFT is not set
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
++# CONFIG_USB_SERIAL_GARMIN is not set
++# CONFIG_USB_SERIAL_IPW is not set
++# CONFIG_USB_SERIAL_IUU is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_MOS7720 is not set
++# CONFIG_USB_SERIAL_MOS7840 is not set
++# CONFIG_USB_SERIAL_MOTOROLA is not set
++# CONFIG_USB_SERIAL_NAVMAN is not set
++# CONFIG_USB_SERIAL_PL2303 is not set
++# CONFIG_USB_SERIAL_OTI6858 is not set
++# CONFIG_USB_SERIAL_SPCP8X5 is not set
++# CONFIG_USB_SERIAL_HP4X is not set
++# CONFIG_USB_SERIAL_SAFE is not set
++# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
++# CONFIG_USB_SERIAL_TI is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++CONFIG_USB_SERIAL_OPTION=m
++# CONFIG_USB_SERIAL_OMNINET is not set
++# CONFIG_USB_SERIAL_DEBUG is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_BERRY_CHARGE is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGET is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_VST is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_SELECTED=y
++CONFIG_USB_GADGET_TCC_OTG=y
++CONFIG_USB_TCC_OTG=y
++# CONFIG_USB_GADGET_AT91 is not set
++# CONFIG_USB_GADGET_ATMEL_USBA is not set
++# CONFIG_USB_GADGET_FSL_USB2 is not set
++# CONFIG_USB_GADGET_LH7A40X is not set
++# CONFIG_USB_GADGET_OMAP is not set
++# CONFIG_USB_GADGET_PXA25X is not set
++# CONFIG_USB_GADGET_PXA27X is not set
++# CONFIG_USB_GADGET_S3C2410 is not set
++# CONFIG_USB_GADGET_M66592 is not set
++# CONFIG_USB_GADGET_AMD5536UDC is not set
++# CONFIG_USB_GADGET_FSL_QE is not set
++# CONFIG_USB_GADGET_NET2280 is not set
++# CONFIG_USB_GADGET_GOKU is not set
++# CONFIG_USB_GADGET_DUMMY_HCD is not set
++CONFIG_USB_GADGET_DUALSPEED=y
++# CONFIG_USB_ZERO is not set
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_GADGETFS is not set
++CONFIG_USB_FILE_STORAGE=m
++# CONFIG_USB_FILE_STORAGE_TEST is not set
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++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_TCC_SDHC=y
++CONFIG_MMC_TCC_SDHC_CORE0=y
++# CONFIG_MMC_TCC_SDHC_CORE1 is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_NEW_LEDS=y
++# CONFIG_LEDS_CLASS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGERS=y
++# CONFIG_LEDS_TRIGGER_TIMER is not set
++# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
++# CONFIG_LEDS_TRIGGER_DEFAULT_ON 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=y
++# 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_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 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_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++
++#
++# SPI RTC drivers
++#
++
++#
++# 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_BQ4802 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# on-CPU RTC drivers
++#
++CONFIG_RTC_DRV_TCC=y
++# CONFIG_DMADEVICES is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_UIO is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_JBD=y
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_DNOTIFY is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++CONFIG_FUSE_FS=y
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++CONFIG_JOLIET=y
++# CONFIG_ZISOFS is not set
++CONFIG_UDF_FS=y
++CONFIG_UDF_NLS=y
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++# CONFIG_MSDOS_FS is not set
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++# CONFIG_SUNRPC_REGISTER_V4 is not set
++CONFIG_RPCSEC_GSS_KRB5=y
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++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=y
++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 is not set
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_UNUSED_SYMBOLS=y
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++CONFIG_DETECT_SOFTLOCKUP=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_TIMER_STATS is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_DEBUG_ON is not set
++# CONFIG_SLUB_STATS is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_SG is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_CPU_STALL_DETECTOR is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP is not set
++# CONFIG_SYSCTL_SYSCALL_CHECK is not set
++CONFIG_HAVE_FUNCTION_TRACER=y
++
++#
++# Tracers
++#
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_CONTEXT_SWITCH_TRACER is not set
++# CONFIG_BOOT_TRACER is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_DEBUG_USER is not set
++# CONFIG_DEBUG_ERRORS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_ICEDCC is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_FIPS is not set
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++CONFIG_CRYPTO_CBC=y
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=m
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++# 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=m
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=m
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=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_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++CONFIG_CRYPTO_HW=y
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++CONFIG_CRC_ITU_T=y
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
+diff --git a/arch/arm/configs/SmartV7_ramdisk_defconfig b/arch/arm/configs/SmartV7_ramdisk_defconfig
+new file mode 100644
+index 0000000..8956b6b
+--- /dev/null
++++ b/arch/arm/configs/SmartV7_ramdisk_defconfig
+@@ -0,0 +1,1469 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.28
++# Thu Sep 17 18:15:58 2009
++#
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_GENERIC_TIME is not set
++# CONFIG_GENERIC_CLOCKEVENTS is not set
++CONFIG_MMU=y
++# CONFIG_NO_IOPORT is not set
++CONFIG_GENERIC_HARDIRQS=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_ILOG2_U32 is not set
++# CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++# CONFIG_CGROUPS is not set
++# CONFIG_GROUP_SCHED is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++CONFIG_RELAY=y
++CONFIG_NAMESPACES=y
++# CONFIG_UTS_NS is not set
++# CONFIG_IPC_NS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++# CONFIG_EMBEDDED is not set
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_KALLSYMS_EXTRA_PASS=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_VM_EVENT_COUNTERS=y
++CONFIG_SLUB_DEBUG=y
++# CONFIG_COMPAT_BRK is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++# CONFIG_MARKERS is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++CONFIG_MODULE_SRCVERSION_ALL=y
++CONFIG_KMOD=y
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF 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_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_CLASSIC_RCU=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IMX 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_L7200 is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_NS9XXX is not set
++# CONFIG_ARCH_LOKI is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_ARCH_MSM is not set
++CONFIG_ARCH_TCC=y
++
++#
++# Boot options
++#
++
++#
++# Power management
++#
++
++#
++# TCC Core Type
++#
++CONFIG_ARCH_TCC8900=y
++CONFIG_TCC_R_AX=y
++# CONFIG_TCC_R_XX is not set
++
++#
++# TCC Board Type
++#
++CONFIG_MACH_TCC8900=y
++# CONFIG_RAM_128MB is not set
++CONFIG_RAM_256MB=y
++# CONFIG_HD720p_LEVEL41 is not set
++# CONFIG_HD720p_LEVEL51 is not set
++# CONFIG_HD1080p_LEVEL41 is not set
++CONFIG_HD1080p_LEVEL51=y
++CONFIG_TCC_STRING="tcc8900"
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_V6=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v6=y
++CONFIG_CPU_ABRT_EV6=y
++CONFIG_CPU_PABRT_NOIFAR=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
++
++#
++# 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_OUTER_CACHE is not set
++
++#
++# Bus support
++#
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_PREEMPT is not set
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++CONFIG_ARCH_FLATMEM_HAS_HOLES=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_DISCONTIGMEM_MANUAL is not set
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_UNEVICTABLE_LRU is not set
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="root=/dev/ram rw initrd=0x40700000,0x1000000 init=/linuxrc console=ttySAC0"
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_FREQ is not set
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_NWFPE_XP is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_VFP=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++CONFIG_BINFMT_AOUT=y
++CONFIG_BINFMT_MISC=y
++
++#
++# Power management options
++#
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_APM_EMULATION is not set
++
++#
++# Dynamic Power Management
++#
++CONFIG_DPM=y
++CONFIG_DPM_PROCFS=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_FIB_HASH=y
++CONFIG_IP_PNP=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++CONFIG_IP_PNP_RARP=y
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE 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 is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++# CONFIG_INET_LRO is not set
++# CONFIG_INET_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_SCHED 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_PHONET is not set
++CONFIG_WIRELESS=y
++CONFIG_CFG80211=m
++CONFIG_NL80211=y
++CONFIG_WIRELESS_OLD_REGULATORY=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WIRELESS_EXT_SYSFS=y
++CONFIG_MAC80211=m
++
++#
++# Rate control algorithm selection
++#
++CONFIG_MAC80211_RC_PID=y
++CONFIG_MAC80211_RC_MINSTREL=y
++CONFIG_MAC80211_RC_DEFAULT_PID=y
++# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
++CONFIG_MAC80211_RC_DEFAULT="pid"
++# CONFIG_MAC80211_MESH is not set
++CONFIG_MAC80211_LEDS=y
++# CONFIG_MAC80211_DEBUG_MENU is not set
++CONFIG_IEEE80211=m
++# CONFIG_IEEE80211_DEBUG is not set
++CONFIG_IEEE80211_CRYPT_WEP=m
++# CONFIG_IEEE80211_CRYPT_CCMP is not set
++# CONFIG_IEEE80211_CRYPT_TKIP is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++CONFIG_DEBUG_DEVRES=y
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_CONNECTOR is not set
++# CONFIG_MTD 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
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=2
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++CONFIG_CDROM_PKTCDVD=y
++CONFIG_CDROM_PKTCDVD_BUFFERS=8
++# CONFIG_CDROM_PKTCDVD_WCACHE is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_TCC_NAND_V6 is not set
++CONFIG_TCC_NAND_V7=m
++# CONFIG_MISC_DEVICES is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++CONFIG_SCSI_MULTI_LUN=y
++# 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_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_ATA is not set
++# CONFIG_MD 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 is not set
++# CONFIG_VETH is not set
++# CONFIG_PHYLIB is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_AX88796 is not set
++# CONFIG_SMC91X is not set
++# CONFIG_DM9000 is not set
++# CONFIG_SMC911X 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_NETDEV_1000 is not set
++# CONFIG_NETDEV_10000 is not set
++
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++CONFIG_WLAN_80211=y
++# CONFIG_LIBERTAS is not set
++# CONFIG_LIBERTAS_THINFIRM is not set
++CONFIG_MARVELL_8686_SDIO=m
++# CONFIG_MARVELL_8686_PROC_FS is not set
++# CONFIG_MARVELL_8686_DEBUG is not set
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_USB_NET_RNDIS_WLAN is not set
++# CONFIG_RTL8187 is not set
++# CONFIG_MAC80211_HWSIM is not set
++# CONFIG_P54_COMMON is not set
++# CONFIG_IWLWIFI_LEDS is not set
++# CONFIG_HOSTAP is not set
++# CONFIG_B43 is not set
++# CONFIG_B43LEGACY is not set
++# CONFIG_ZD1211RW is not set
++# CONFIG_RT2X00 is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_WAN is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++CONFIG_INPUT_FF_MEMLESS=y
++# CONFIG_INPUT_POLLDEV is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++CONFIG_KEYBOARD_GPIO=y
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++# CONFIG_TOUCHSCREEN_FUJITSU is not set
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_INEXIO is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++# CONFIG_TOUCHSCREEN_PENMOUNT is not set
++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
++# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
++CONFIG_TOUCHSCREEN_TCCTS=y
++# CONFIG_LCD01 is not set
++# CONFIG_LCD11 is not set
++CONFIG_LCD10=y
++# 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_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_DEVKMEM is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_TCC=y
++CONFIG_SERIAL_TCC_CONSOLE=y
++CONFIG_SERIAL_TCC_DMA=y
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++CONFIG_UNIX98_PTYS=y
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_NVRAM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_TCC_CKC_IOCTL=y
++CONFIG_TCC_USER_INTR=y
++CONFIG_TCC_BL=y
++# CONFIG_LCD_4 is not set
++CONFIG_LCD_7=y
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_HELPER_AUTO is not set
++
++#
++# I2C Algorithms
++#
++CONFIG_I2C_ALGOBIT=y
++# 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_GPIO=y
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_SIMTEC is not set
++CONFIG_I2C_TCC=y
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_STUB is not set
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_DS1682 is not set
++# CONFIG_AT24 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_PCF8575 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_MAX6875 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_TCC_I2C_WM8731 is not set
++CONFIG_TCC_I2C_WM8987=y
++CONFIG_TCC_I2C_PCA953X=y
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_I2C_DEBUG_CHIP is not set
++# CONFIG_SPI is not set
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_THERMAL_HWMON is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM8350_I2C is not set
++
++#
++# Multimedia devices
++#
++
++#
++# Multimedia core support
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++# CONFIG_VIDEO_MEDIA is not set
++
++#
++# Multimedia drivers
++#
++# CONFIG_DAB is not set
++
++#
++# Graphics support
++#
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_S1D13XXX is not set
++CONFIG_FB_TCC8900=y
++CONFIG_FB_TCC_A070VW04=y
++# CONFIG_FB_TCC_TD043MTEX is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_MB862XX is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
++
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_LOGO_LINUX_CLUT224=y
++CONFIG_SOUND=y
++# CONFIG_SOUND_OSS_CORE is not set
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++# CONFIG_SND_SEQUENCER is not set
++# CONFIG_SND_MIXER_OSS is not set
++# CONFIG_SND_PCM_OSS is not set
++# CONFIG_SND_DYNAMIC_MINORS is not set
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++CONFIG_SND_DRIVERS=y
++# CONFIG_SND_DUMMY is not set
++# CONFIG_SND_MTPAV is not set
++# CONFIG_SND_SERIAL_U16550 is not set
++# CONFIG_SND_MPU401 is not set
++CONFIG_SND_ARM=y
++CONFIG_SND_USB=y
++# CONFIG_SND_USB_AUDIO is not set
++# CONFIG_SND_USB_CAIAQ is not set
++CONFIG_SND_SOC=y
++CONFIG_SND_TCC_SOC=y
++CONFIG_SND_TCC_SOC_I2S=y
++# CONFIG_SND_TCC_SOC_BOARD_WM8731 is not set
++# CONFIG_SND_TCC_SOC_BOARD_WM8581 is not set
++CONFIG_SND_TCC_SOC_BOARD_WM8987=y
++CONFIG_AUDIO_CODEC_PROCFS=y
++# CONFIG_SND_SOC_ALL_CODECS is not set
++CONFIG_SND_SOC_WM8987=y
++# CONFIG_SOUND_PRIME is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++CONFIG_HID_DEBUG=y
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# Special HID drivers
++#
++CONFIG_HID_COMPAT=y
++CONFIG_HID_A4TECH=y
++CONFIG_HID_APPLE=y
++CONFIG_HID_BELKIN=y
++CONFIG_HID_BRIGHT=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++CONFIG_HID_DELL=y
++CONFIG_HID_EZKEY=y
++CONFIG_HID_GYRATION=y
++CONFIG_HID_LOGITECH=y
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++CONFIG_HID_PANTHERLORD=y
++# CONFIG_PANTHERLORD_FF is not set
++CONFIG_HID_PETALYNX=y
++CONFIG_HID_SAMSUNG=y
++CONFIG_HID_SONY=y
++CONFIG_HID_SUNPLUS=y
++# CONFIG_THRUSTMASTER_FF is not set
++# CONFIG_ZEROPLUS_FF is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++# CONFIG_USB_DEVICE_CLASS is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++CONFIG_USB_SUSPEND=y
++CONFIG_USB_OTG=y
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# Telechips DWC OTG Controller Drivers
++#
++CONFIG_TCC_DWC_OTG=y
++CONFIG_TCC_DWC_OTG_DUAL_ROLE=y
++# CONFIG_TCC_DWC_OTG_DEVICE_ONLY is not set
++# CONFIG_TCC_DWC_OTG_HOST_ONLY is not set
++# CONFIG_TCC_DWC_OTG_DEBUG is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
++# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HWA_HCD is not set
++# CONFIG_USB_GADGET_MUSB_HDRC is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
++#
++
++#
++# see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_DPCM is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++CONFIG_USB_SERIAL=m
++# CONFIG_USB_EZUSB is not set
++# CONFIG_USB_SERIAL_GENERIC is not set
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_ARK3116 is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_CH341 is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_CP2101 is not set
++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++# CONFIG_USB_SERIAL_FTDI_SIO is not set
++# CONFIG_USB_SERIAL_FUNSOFT is not set
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
++# CONFIG_USB_SERIAL_GARMIN is not set
++# CONFIG_USB_SERIAL_IPW is not set
++# CONFIG_USB_SERIAL_IUU is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_MOS7720 is not set
++# CONFIG_USB_SERIAL_MOS7840 is not set
++# CONFIG_USB_SERIAL_MOTOROLA is not set
++# CONFIG_USB_SERIAL_NAVMAN is not set
++# CONFIG_USB_SERIAL_PL2303 is not set
++# CONFIG_USB_SERIAL_OTI6858 is not set
++# CONFIG_USB_SERIAL_SPCP8X5 is not set
++# CONFIG_USB_SERIAL_HP4X is not set
++# CONFIG_USB_SERIAL_SAFE is not set
++# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
++# CONFIG_USB_SERIAL_TI is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++# CONFIG_USB_SERIAL_OPTION is not set
++# CONFIG_USB_SERIAL_OMNINET is not set
++# CONFIG_USB_SERIAL_DEBUG is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_BERRY_CHARGE is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGET is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_VST is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_SELECTED=y
++CONFIG_USB_GADGET_TCC_OTG=y
++CONFIG_USB_TCC_OTG=y
++# CONFIG_USB_GADGET_AT91 is not set
++# CONFIG_USB_GADGET_ATMEL_USBA is not set
++# CONFIG_USB_GADGET_FSL_USB2 is not set
++# CONFIG_USB_GADGET_LH7A40X is not set
++# CONFIG_USB_GADGET_OMAP is not set
++# CONFIG_USB_GADGET_PXA25X is not set
++# CONFIG_USB_GADGET_PXA27X is not set
++# CONFIG_USB_GADGET_S3C2410 is not set
++# CONFIG_USB_GADGET_M66592 is not set
++# CONFIG_USB_GADGET_AMD5536UDC is not set
++# CONFIG_USB_GADGET_FSL_QE is not set
++# CONFIG_USB_GADGET_NET2280 is not set
++# CONFIG_USB_GADGET_GOKU is not set
++# CONFIG_USB_GADGET_DUMMY_HCD is not set
++CONFIG_USB_GADGET_DUALSPEED=y
++# CONFIG_USB_ZERO is not set
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_GADGETFS is not set
++CONFIG_USB_FILE_STORAGE=m
++# CONFIG_USB_FILE_STORAGE_TEST is not set
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++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_TCC_SDHC=y
++CONFIG_MMC_TCC_SDHC_CORE0=y
++# CONFIG_MMC_TCC_SDHC_CORE1 is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_NEW_LEDS=y
++# CONFIG_LEDS_CLASS is not set
++
++#
++# LED drivers
++#
++
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGERS=y
++# CONFIG_LEDS_TRIGGER_TIMER is not set
++# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
++# CONFIG_LEDS_TRIGGER_DEFAULT_ON 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=y
++# 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_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 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_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++
++#
++# SPI RTC drivers
++#
++
++#
++# 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_BQ4802 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# on-CPU RTC drivers
++#
++CONFIG_RTC_DRV_TCC=y
++# CONFIG_DMADEVICES is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_UIO is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_JBD=y
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_DNOTIFY is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++CONFIG_FUSE_FS=y
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++CONFIG_JOLIET=y
++# CONFIG_ZISOFS is not set
++CONFIG_UDF_FS=y
++CONFIG_UDF_NLS=y
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++# CONFIG_MSDOS_FS is not set
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_AUFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++# CONFIG_SUNRPC_REGISTER_V4 is not set
++CONFIG_RPCSEC_GSS_KRB5=y
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++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=y
++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 is not set
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_UNUSED_SYMBOLS=y
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++CONFIG_DETECT_SOFTLOCKUP=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_TIMER_STATS is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_DEBUG_ON is not set
++# CONFIG_SLUB_STATS is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_SG is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_CPU_STALL_DETECTOR is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP is not set
++# CONFIG_SYSCTL_SYSCALL_CHECK is not set
++CONFIG_HAVE_FUNCTION_TRACER=y
++
++#
++# Tracers
++#
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_CONTEXT_SWITCH_TRACER is not set
++# CONFIG_BOOT_TRACER is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_DEBUG_USER is not set
++# CONFIG_DEBUG_ERRORS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_ICEDCC is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_FIPS is not set
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++CONFIG_CRYPTO_CBC=y
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=m
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++# 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=m
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=m
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=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_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++CONFIG_CRYPTO_HW=y
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++CONFIG_CRC_ITU_T=y
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
+diff --git a/arch/arm/configs/tcc8900_defconfig b/arch/arm/configs/tcc8900_defconfig
+new file mode 100644
+index 0000000..62b225b
+--- /dev/null
++++ b/arch/arm/configs/tcc8900_defconfig
+@@ -0,0 +1,1422 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.28
++# Fri Sep 4 12:18:28 2009
++#
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++# CONFIG_GENERIC_GPIO is not set
++# CONFIG_GENERIC_TIME is not set
++# CONFIG_GENERIC_CLOCKEVENTS is not set
++CONFIG_MMU=y
++# CONFIG_NO_IOPORT is not set
++CONFIG_GENERIC_HARDIRQS=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_ILOG2_U32 is not set
++# CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++# CONFIG_CGROUPS is not set
++# CONFIG_GROUP_SCHED is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++CONFIG_RELAY=y
++CONFIG_NAMESPACES=y
++# CONFIG_UTS_NS is not set
++# CONFIG_IPC_NS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++# CONFIG_EMBEDDED is not set
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_KALLSYMS_EXTRA_PASS=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++# CONFIG_COMPAT_BRK is not set
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_ANON_INODES=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_SLUB_DEBUG=y
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++# CONFIG_MARKERS is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++CONFIG_MODULE_SRCVERSION_ALL=y
++CONFIG_KMOD=y
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF 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_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_CLASSIC_RCU=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IMX 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_L7200 is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_NS9XXX is not set
++# CONFIG_ARCH_LOKI is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_ARCH_MSM is not set
++CONFIG_ARCH_TCC=y
++
++#
++# Boot options
++#
++
++#
++# Power management
++#
++
++#
++# TCC Core Type
++#
++CONFIG_ARCH_TCC8900=y
++CONFIG_TCC_R_AX=y
++# CONFIG_TCC_R_XX is not set
++
++#
++# TCC Board Type
++#
++CONFIG_MACH_TCC8900=y
++CONFIG_DRAM_DDR2=y
++# CONFIG_DRAM_MDDR is not set
++# CONFIG_RAM_128MB is not set
++CONFIG_RAM_256MB=y
++# CONFIG_HD720p_LEVEL41 is not set
++# CONFIG_HD720p_LEVEL51 is not set
++# CONFIG_HD1080p_LEVEL41 is not set
++CONFIG_HD1080p_LEVEL51=y
++CONFIG_TCC_STRING="tcc8900"
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_V6=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v6=y
++CONFIG_CPU_ABRT_EV6=y
++CONFIG_CPU_PABRT_NOIFAR=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
++
++#
++# 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_OUTER_CACHE is not set
++
++#
++# Bus support
++#
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_PREEMPT is not set
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++CONFIG_ARCH_FLATMEM_HAS_HOLES=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_DISCONTIGMEM_MANUAL is not set
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_UNEVICTABLE_LRU is not set
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="root=/dev/ram rw initrd=0x40700000,0x1000000 init=/linuxrc console=ttySAC0"
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_NWFPE_XP is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_VFP=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++CONFIG_BINFMT_AOUT=y
++CONFIG_BINFMT_MISC=y
++
++#
++# Power management options
++#
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_APM_EMULATION is not set
++
++#
++# Dynamic Power Management
++#
++CONFIG_DPM=y
++CONFIG_DPM_PROCFS=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_FIB_HASH=y
++CONFIG_IP_PNP=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++CONFIG_IP_PNP_RARP=y
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE 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 is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++# CONFIG_INET_LRO is not set
++# CONFIG_INET_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_SCHED 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_PHONET is not set
++# CONFIG_WIRELESS is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++CONFIG_DEBUG_DEVRES=y
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_CONNECTOR is not set
++# CONFIG_MTD 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
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=2
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++CONFIG_CDROM_PKTCDVD=y
++CONFIG_CDROM_PKTCDVD_BUFFERS=8
++# CONFIG_CDROM_PKTCDVD_WCACHE is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MISC_DEVICES is not set
++CONFIG_HAVE_IDE=y
++CONFIG_IDE=y
++
++#
++# Please see Documentation/ide/ide.txt for help/info on IDE drives
++#
++# CONFIG_BLK_DEV_IDE_SATA is not set
++CONFIG_IDE_GD=y
++CONFIG_IDE_GD_ATA=y
++# CONFIG_IDE_GD_ATAPI is not set
++CONFIG_BLK_DEV_IDECD=y
++CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y
++# CONFIG_BLK_DEV_IDETAPE is not set
++# CONFIG_BLK_DEV_IDESCSI is not set
++CONFIG_IDE_TASK_IOCTL=y
++CONFIG_IDE_PROC_FS=y
++
++#
++# IDE chipset support/bugfixes
++#
++CONFIG_BLK_DEV_PLATFORM=y
++# CONFIG_BLK_DEV_PATA_TCC89X is not set
++# CONFIG_BLK_DEV_IDEDMA is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++CONFIG_SCSI_MULTI_LUN=y
++# 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_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++CONFIG_ATA=y
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_SATA_PMP=y
++CONFIG_ATA_SFF=y
++# CONFIG_SATA_MV is not set
++CONFIG_SATA_TCC=y
++# CONFIG_MD 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 is not set
++# CONFIG_VETH is not set
++# CONFIG_PHYLIB is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_AX88796 is not set
++# CONFIG_SMC91X is not set
++# CONFIG_DM9000 is not set
++# CONFIG_ENC28J60 is not set
++# CONFIG_SMC911X 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_NETDEV_1000 is not set
++# CONFIG_NETDEV_10000 is not set
++
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++# CONFIG_WLAN_80211 is not set
++# CONFIG_IWLWIFI_LEDS is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_WAN is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++CONFIG_INPUT_FF_MEMLESS=y
++# CONFIG_INPUT_POLLDEV is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++# CONFIG_TOUCHSCREEN_ADS7846 is not set
++# CONFIG_TOUCHSCREEN_FUJITSU is not set
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_INEXIO is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++# CONFIG_TOUCHSCREEN_PENMOUNT is not set
++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
++# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
++CONFIG_TOUCHSCREEN_TCCTS=y
++# CONFIG_LCD01 is not set
++CONFIG_LCD11=y
++# CONFIG_LCD10 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_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_DEVKMEM is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_TCC=y
++CONFIG_SERIAL_TCC_CONSOLE=y
++CONFIG_SERIAL_TCC_DMA=y
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++CONFIG_UNIX98_PTYS=y
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_NVRAM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_TCC_CKC_IOCTL=y
++CONFIG_TCC_USER_INTR=y
++CONFIG_TCC_BL=y
++CONFIG_TCC_POWER_CTL=y
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_HELPER_AUTO 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_OCORES is not set
++# CONFIG_I2C_SIMTEC is not set
++CONFIG_I2C_TCC=y
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_STUB is not set
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_DS1682 is not set
++# CONFIG_AT24 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_PCF8575 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_MAX6875 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++CONFIG_TCC_I2C_WM8731=y
++CONFIG_TCC_I2C_PCA953X=y
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_I2C_DEBUG_CHIP is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_BITBANG is not set
++
++#
++# Telechips GPSB (General Purpose Serial Bus) Controller Drivers
++#
++# CONFIG_SPI_TCC_MASTER is not set
++CONFIG_TSIF_TCC_SLAVE=y
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_AT25 is not set
++CONFIG_SPI_SPIDEV=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_THERMAL_HWMON is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM8350_I2C is not set
++
++#
++# Multimedia devices
++#
++
++#
++# Multimedia core support
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++# CONFIG_VIDEO_MEDIA is not set
++
++#
++# Multimedia drivers
++#
++# CONFIG_DAB is not set
++
++#
++# Graphics support
++#
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_S1D13XXX is not set
++CONFIG_FB_TCC8900=y
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_MB862XX is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
++
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_LOGO_LINUX_CLUT224=y
++CONFIG_SOUND=y
++# CONFIG_SOUND_OSS_CORE is not set
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++# CONFIG_SND_SEQUENCER is not set
++# CONFIG_SND_MIXER_OSS is not set
++# CONFIG_SND_PCM_OSS is not set
++# CONFIG_SND_DYNAMIC_MINORS is not set
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++CONFIG_SND_DRIVERS=y
++# CONFIG_SND_DUMMY is not set
++# CONFIG_SND_MTPAV is not set
++# CONFIG_SND_SERIAL_U16550 is not set
++# CONFIG_SND_MPU401 is not set
++CONFIG_SND_ARM=y
++CONFIG_SND_SPI=y
++CONFIG_SND_USB=y
++# CONFIG_SND_USB_AUDIO is not set
++# CONFIG_SND_USB_CAIAQ is not set
++CONFIG_SND_SOC=y
++CONFIG_SND_TCC_SOC=y
++CONFIG_SND_TCC_SOC_I2S=y
++CONFIG_SND_TCC_SOC_BOARD_WM8731=y
++# CONFIG_SND_TCC_SOC_BOARD_WM8581 is not set
++# CONFIG_SND_SOC_ALL_CODECS is not set
++CONFIG_SND_SOC_WM8731=y
++# CONFIG_SOUND_PRIME is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++CONFIG_HID_DEBUG=y
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# Special HID drivers
++#
++CONFIG_HID_COMPAT=y
++CONFIG_HID_A4TECH=y
++CONFIG_HID_APPLE=y
++CONFIG_HID_BELKIN=y
++CONFIG_HID_BRIGHT=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++CONFIG_HID_DELL=y
++CONFIG_HID_EZKEY=y
++CONFIG_HID_GYRATION=y
++CONFIG_HID_LOGITECH=y
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++CONFIG_HID_PANTHERLORD=y
++# CONFIG_PANTHERLORD_FF is not set
++CONFIG_HID_PETALYNX=y
++CONFIG_HID_SAMSUNG=y
++CONFIG_HID_SONY=y
++CONFIG_HID_SUNPLUS=y
++# CONFIG_THRUSTMASTER_FF is not set
++# CONFIG_ZEROPLUS_FF is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++# CONFIG_USB_DEVICE_CLASS is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++CONFIG_USB_SUSPEND=y
++CONFIG_USB_OTG=y
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# Telechips DWC OTG Controller Drivers
++#
++CONFIG_TCC_DWC_OTG=y
++CONFIG_TCC_DWC_OTG_DUAL_ROLE=y
++# CONFIG_TCC_DWC_OTG_DEVICE_ONLY is not set
++# CONFIG_TCC_DWC_OTG_HOST_ONLY is not set
++# CONFIG_TCC_DWC_OTG_DEBUG is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
++# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HWA_HCD is not set
++# CONFIG_USB_GADGET_MUSB_HDRC is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
++#
++
++#
++# see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_DPCM is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_BERRY_CHARGE is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGET is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_VST is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_SELECTED=y
++CONFIG_USB_GADGET_TCC_OTG=y
++CONFIG_USB_TCC_OTG=y
++# CONFIG_USB_GADGET_AT91 is not set
++# CONFIG_USB_GADGET_ATMEL_USBA is not set
++# CONFIG_USB_GADGET_FSL_USB2 is not set
++# CONFIG_USB_GADGET_LH7A40X is not set
++# CONFIG_USB_GADGET_OMAP is not set
++# CONFIG_USB_GADGET_PXA25X is not set
++# CONFIG_USB_GADGET_PXA27X is not set
++# CONFIG_USB_GADGET_S3C2410 is not set
++# CONFIG_USB_GADGET_M66592 is not set
++# CONFIG_USB_GADGET_AMD5536UDC is not set
++# CONFIG_USB_GADGET_FSL_QE is not set
++# CONFIG_USB_GADGET_NET2280 is not set
++# CONFIG_USB_GADGET_GOKU is not set
++# CONFIG_USB_GADGET_DUMMY_HCD is not set
++CONFIG_USB_GADGET_DUALSPEED=y
++# CONFIG_USB_ZERO is not set
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_GADGETFS is not set
++CONFIG_USB_FILE_STORAGE=m
++# CONFIG_USB_FILE_STORAGE_TEST is not set
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++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_TCC_SDHC=y
++CONFIG_MMC_TCC_SDHC_CORE0=y
++# CONFIG_MMC_TCC_SDHC_CORE1 is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_NEW_LEDS 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=y
++# 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_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 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_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++
++#
++# SPI RTC drivers
++#
++# 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
++
++#
++# 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_BQ4802 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# on-CPU RTC drivers
++#
++CONFIG_RTC_DRV_TCC=y
++# CONFIG_DMADEVICES is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_UIO is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_JBD=y
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_DNOTIFY is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++CONFIG_FUSE_FS=y
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++CONFIG_JOLIET=y
++# CONFIG_ZISOFS is not set
++CONFIG_UDF_FS=y
++CONFIG_UDF_NLS=y
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++# CONFIG_MSDOS_FS is not set
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++# CONFIG_SUNRPC_REGISTER_V4 is not set
++CONFIG_RPCSEC_GSS_KRB5=y
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++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=y
++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 is not set
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_UNUSED_SYMBOLS=y
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++CONFIG_DETECT_SOFTLOCKUP=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_TIMER_STATS is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_DEBUG_ON is not set
++# CONFIG_SLUB_STATS is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_SG is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_CPU_STALL_DETECTOR is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP is not set
++# CONFIG_SYSCTL_SYSCALL_CHECK is not set
++CONFIG_HAVE_FUNCTION_TRACER=y
++
++#
++# Tracers
++#
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_CONTEXT_SWITCH_TRACER is not set
++# CONFIG_BOOT_TRACER is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_DEBUG_USER is not set
++# CONFIG_DEBUG_ERRORS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_ICEDCC is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_FIPS is not set
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++CONFIG_CRYPTO_CBC=y
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++# CONFIG_CRYPTO_ECB is not set
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++# 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 is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=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_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++CONFIG_CRYPTO_HW=y
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++CONFIG_CRC_ITU_T=y
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
+diff --git a/arch/arm/configs/tcc8900_wifi_defconfig b/arch/arm/configs/tcc8900_wifi_defconfig
+new file mode 100644
+index 0000000..e2f4046
+--- /dev/null
++++ b/arch/arm/configs/tcc8900_wifi_defconfig
+@@ -0,0 +1,1453 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.28
++# Wed Aug 5 16:39:32 2009
++#
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++# CONFIG_GENERIC_GPIO is not set
++# CONFIG_GENERIC_TIME is not set
++# CONFIG_GENERIC_CLOCKEVENTS is not set
++CONFIG_MMU=y
++# CONFIG_NO_IOPORT is not set
++CONFIG_GENERIC_HARDIRQS=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_ILOG2_U32 is not set
++# CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++# CONFIG_CGROUPS is not set
++# CONFIG_GROUP_SCHED is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++CONFIG_RELAY=y
++CONFIG_NAMESPACES=y
++# CONFIG_UTS_NS is not set
++# CONFIG_IPC_NS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++# CONFIG_EMBEDDED is not set
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_KALLSYMS_EXTRA_PASS=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++# CONFIG_COMPAT_BRK is not set
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_ANON_INODES=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_SLUB_DEBUG=y
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++# CONFIG_MARKERS is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++# CONFIG_TINY_SHMEM is not set
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++CONFIG_MODULE_SRCVERSION_ALL=y
++CONFIG_KMOD=y
++CONFIG_BLOCK=y
++# CONFIG_LBD is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_LSF 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_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_CLASSIC_RCU=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IMX 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_L7200 is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_NS9XXX is not set
++# CONFIG_ARCH_LOKI is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_ARCH_MSM is not set
++CONFIG_ARCH_TCC=y
++
++#
++# Boot options
++#
++
++#
++# Power management
++#
++
++#
++# TCC Core Type
++#
++CONFIG_ARCH_TCC8900=y
++CONFIG_TCC_R_AX=y
++# CONFIG_TCC_R_XX is not set
++
++#
++# TCC Board Type
++#
++CONFIG_MACH_TCC8900=y
++# CONFIG_RAM_128MB is not set
++CONFIG_RAM_256MB=y
++CONFIG_DRAM_DDR2=y
++# CONFIG_DRAM_MDDR is not set
++CONFIG_HD720p_LEVEL41=y
++# CONFIG_HD720p_LEVEL51 is not set
++# CONFIG_HD1080p_LEVEL41 is not set
++# CONFIG_HD1080p_LEVEL51 is not set
++CONFIG_TCC_STRING="tcc8900"
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_V6=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v6=y
++CONFIG_CPU_ABRT_EV6=y
++CONFIG_CPU_PABRT_NOIFAR=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
++
++#
++# 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_OUTER_CACHE is not set
++
++#
++# Bus support
++#
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_PREEMPT is not set
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++CONFIG_ARCH_FLATMEM_HAS_HOLES=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_DISCONTIGMEM_MANUAL is not set
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_RESOURCES_64BIT is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_UNEVICTABLE_LRU is not set
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="root=/dev/ram rw initrd=0x40700000,0x1000000 init=/linuxrc console=ttySAC0"
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_NWFPE_XP is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_VFP=y
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++CONFIG_BINFMT_AOUT=y
++CONFIG_BINFMT_MISC=y
++
++#
++# Power management options
++#
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_APM_EMULATION is not set
++
++#
++# Dynamic Power Management
++#
++CONFIG_DPM=y
++CONFIG_DPM_PROCFS=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=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=y
++# CONFIG_NET_KEY_MIGRATE is not set
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_FIB_HASH=y
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++CONFIG_IP_PNP_RARP=y
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE 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 is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++# CONFIG_INET_LRO is not set
++# CONFIG_INET_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++CONFIG_TCP_MD5SIG=y
++# CONFIG_IPV6 is not set
++CONFIG_NETWORK_SECMARK=y
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_NETFILTER_ADVANCED=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
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER 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_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
++
++#
++# 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
++
++#
++# Network testing
++#
++CONFIG_NET_PKTGEN=y
++# 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_PHONET is not set
++CONFIG_WIRELESS=y
++CONFIG_CFG80211=y
++CONFIG_NL80211=y
++CONFIG_WIRELESS_OLD_REGULATORY=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WIRELESS_EXT_SYSFS=y
++CONFIG_MAC80211=y
++
++#
++# Rate control algorithm selection
++#
++CONFIG_MAC80211_RC_PID=y
++# CONFIG_MAC80211_RC_MINSTREL is not set
++CONFIG_MAC80211_RC_DEFAULT_PID=y
++# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
++CONFIG_MAC80211_RC_DEFAULT="pid"
++# CONFIG_MAC80211_MESH is not set
++# CONFIG_MAC80211_LEDS is not set
++# CONFIG_MAC80211_DEBUG_MENU is not set
++CONFIG_IEEE80211=y
++CONFIG_IEEE80211_DEBUG=y
++CONFIG_IEEE80211_CRYPT_WEP=y
++CONFIG_IEEE80211_CRYPT_CCMP=y
++CONFIG_IEEE80211_CRYPT_TKIP=y
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++CONFIG_DEBUG_DEVRES=y
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_CONNECTOR is not set
++# CONFIG_MTD 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
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=2
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++CONFIG_CDROM_PKTCDVD=y
++CONFIG_CDROM_PKTCDVD_BUFFERS=8
++# CONFIG_CDROM_PKTCDVD_WCACHE is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MISC_DEVICES is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++CONFIG_SCSI_MULTI_LUN=y
++# 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_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_ATA is not set
++# CONFIG_MD 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 is not set
++# CONFIG_VETH is not set
++# CONFIG_PHYLIB is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_AX88796 is not set
++# CONFIG_SMC91X is not set
++# CONFIG_DM9000 is not set
++# CONFIG_ENC28J60 is not set
++# CONFIG_SMC911X 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_NETDEV_1000 is not set
++# CONFIG_NETDEV_10000 is not set
++
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++CONFIG_WLAN_80211=y
++# CONFIG_LIBERTAS is not set
++# CONFIG_LIBERTAS_THINFIRM is not set
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_USB_NET_RNDIS_WLAN is not set
++# CONFIG_RTL8187 is not set
++# CONFIG_MAC80211_HWSIM is not set
++# CONFIG_P54_COMMON is not set
++# CONFIG_IWLWIFI_LEDS is not set
++# CONFIG_HOSTAP is not set
++# CONFIG_B43 is not set
++# CONFIG_B43LEGACY is not set
++# CONFIG_ZD1211RW is not set
++# CONFIG_RT2X00 is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_WAN is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++CONFIG_INPUT_FF_MEMLESS=y
++# CONFIG_INPUT_POLLDEV is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++CONFIG_KEYBOARD_ATKBD=y
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++# CONFIG_TOUCHSCREEN_ADS7846 is not set
++# CONFIG_TOUCHSCREEN_FUJITSU is not set
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_INEXIO is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++# CONFIG_TOUCHSCREEN_PENMOUNT is not set
++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
++# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
++CONFIG_TOUCHSCREEN_TCCTS=y
++# CONFIG_LCD01 is not set
++# CONFIG_LCD11 is not set
++CONFIG_LCD10=y
++# 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_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++# CONFIG_VT_HW_CONSOLE_BINDING is not set
++# CONFIG_DEVKMEM is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_TCC=y
++CONFIG_SERIAL_TCC_CONSOLE=y
++CONFIG_SERIAL_TCC_DMA=y
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++CONFIG_UNIX98_PTYS=y
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_NVRAM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_TCC_CKC_IOCTL=y
++CONFIG_TCC_USER_INTR=y
++CONFIG_TCC_BL=y
++CONFIG_TCC_POWER_CTL=y
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_HELPER_AUTO 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_OCORES is not set
++# CONFIG_I2C_SIMTEC is not set
++CONFIG_I2C_TCC=y
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_STUB is not set
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_DS1682 is not set
++# CONFIG_AT24 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_PCF8575 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_MAX6875 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++CONFIG_TCC_I2C_WM8731=y
++CONFIG_TCC_I2C_PCA953X=y
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_I2C_DEBUG_CHIP is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_BITBANG is not set
++# CONFIG_SPI_TCC_MASTER is not set
++CONFIG_TSIF_TCC_SLAVE=y
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_AT25 is not set
++CONFIG_SPI_SPIDEV=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_THERMAL_HWMON is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM8350_I2C is not set
++
++#
++# Multimedia devices
++#
++
++#
++# Multimedia core support
++#
++# CONFIG_VIDEO_DEV is not set
++# CONFIG_DVB_CORE is not set
++# CONFIG_VIDEO_MEDIA is not set
++
++#
++# Multimedia drivers
++#
++# CONFIG_DAB is not set
++
++#
++# Graphics support
++#
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_S1D13XXX is not set
++CONFIG_FB_TCC8900=y
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_MB862XX is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
++
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_LOGO_LINUX_CLUT224=y
++# CONFIG_SOUND is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++CONFIG_HID_DEBUG=y
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# Special HID drivers
++#
++CONFIG_HID_COMPAT=y
++CONFIG_HID_A4TECH=y
++CONFIG_HID_APPLE=y
++CONFIG_HID_BELKIN=y
++CONFIG_HID_BRIGHT=y
++CONFIG_HID_CHERRY=y
++CONFIG_HID_CHICONY=y
++CONFIG_HID_CYPRESS=y
++CONFIG_HID_DELL=y
++CONFIG_HID_EZKEY=y
++CONFIG_HID_GYRATION=y
++CONFIG_HID_LOGITECH=y
++# CONFIG_LOGITECH_FF is not set
++# CONFIG_LOGIRUMBLEPAD2_FF is not set
++CONFIG_HID_MICROSOFT=y
++CONFIG_HID_MONTEREY=y
++CONFIG_HID_PANTHERLORD=y
++# CONFIG_PANTHERLORD_FF is not set
++CONFIG_HID_PETALYNX=y
++CONFIG_HID_SAMSUNG=y
++CONFIG_HID_SONY=y
++CONFIG_HID_SUNPLUS=y
++# CONFIG_THRUSTMASTER_FF is not set
++# CONFIG_ZEROPLUS_FF is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++# CONFIG_USB_DEVICE_CLASS is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++CONFIG_USB_SUSPEND=y
++CONFIG_USB_OTG=y
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# Telechips DWC OTG Controller Drivers
++#
++CONFIG_TCC_DWC_OTG=y
++CONFIG_TCC_DWC_OTG_DUAL_ROLE=y
++# CONFIG_TCC_DWC_OTG_DEVICE_ONLY is not set
++# CONFIG_TCC_DWC_OTG_HOST_ONLY is not set
++# CONFIG_TCC_DWC_OTG_DEBUG is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
++# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HWA_HCD is not set
++# CONFIG_USB_GADGET_MUSB_HDRC is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
++#
++
++#
++# see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_DPCM is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_BERRY_CHARGE is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGET is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_VST is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_SELECTED=y
++CONFIG_USB_GADGET_TCC_OTG=y
++CONFIG_USB_TCC_OTG=y
++# CONFIG_USB_GADGET_AT91 is not set
++# CONFIG_USB_GADGET_ATMEL_USBA is not set
++# CONFIG_USB_GADGET_FSL_USB2 is not set
++# CONFIG_USB_GADGET_LH7A40X is not set
++# CONFIG_USB_GADGET_OMAP is not set
++# CONFIG_USB_GADGET_PXA25X is not set
++# CONFIG_USB_GADGET_PXA27X is not set
++# CONFIG_USB_GADGET_S3C2410 is not set
++# CONFIG_USB_GADGET_M66592 is not set
++# CONFIG_USB_GADGET_AMD5536UDC is not set
++# CONFIG_USB_GADGET_FSL_QE is not set
++# CONFIG_USB_GADGET_NET2280 is not set
++# CONFIG_USB_GADGET_GOKU is not set
++# CONFIG_USB_GADGET_DUMMY_HCD is not set
++CONFIG_USB_GADGET_DUALSPEED=y
++# CONFIG_USB_ZERO is not set
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_GADGETFS is not set
++CONFIG_USB_FILE_STORAGE=m
++# CONFIG_USB_FILE_STORAGE_TEST is not set
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++CONFIG_MMC=y
++CONFIG_MMC_DEBUG=y
++# CONFIG_MMC_UNSAFE_RESUME is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++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_TCC_SDHC=y
++CONFIG_MMC_TCC_SDHC_CORE0=y
++# CONFIG_MMC_TCC_SDHC_CORE1 is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_NEW_LEDS 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=y
++# 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_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 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_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++
++#
++# SPI RTC drivers
++#
++# 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
++
++#
++# 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_BQ4802 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# on-CPU RTC drivers
++#
++CONFIG_RTC_DRV_TCC=y
++# CONFIG_DMADEVICES is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_UIO is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_JBD=y
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_DNOTIFY is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++CONFIG_FUSE_FS=y
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++CONFIG_JOLIET=y
++# CONFIG_ZISOFS is not set
++CONFIG_UDF_FS=y
++CONFIG_UDF_NLS=y
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++# CONFIG_MSDOS_FS is not set
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++# CONFIG_SUNRPC_REGISTER_V4 is not set
++CONFIG_RPCSEC_GSS_KRB5=y
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++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=y
++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 is not set
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_UNUSED_SYMBOLS=y
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++CONFIG_DETECT_SOFTLOCKUP=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
++CONFIG_SCHED_DEBUG=y
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_TIMER_STATS is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_DEBUG_ON is not set
++# CONFIG_SLUB_STATS is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_SG is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_CPU_STALL_DETECTOR is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP is not set
++# CONFIG_SYSCTL_SYSCALL_CHECK is not set
++CONFIG_HAVE_FUNCTION_TRACER=y
++
++#
++# Tracers
++#
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_CONTEXT_SWITCH_TRACER is not set
++# CONFIG_BOOT_TRACER is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_DEBUG_USER is not set
++# CONFIG_DEBUG_ERRORS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_ICEDCC is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_FIPS is not set
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++CONFIG_CRYPTO_CBC=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
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++CONFIG_CRYPTO_MICHAEL_MIC=y
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 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_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++CONFIG_CRYPTO_HW=y
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++CONFIG_CRC_ITU_T=y
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
+diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
+index 39d949b..ecab89b 100644
+--- a/arch/arm/include/asm/mach/map.h
++++ b/arch/arm/include/asm/mach/map.h
+@@ -26,6 +26,7 @@ struct map_desc {
+ #define MT_HIGH_VECTORS 8
+ #define MT_MEMORY 9
+ #define MT_ROM 10
++#define MT_MEMORY_TCC 11
+
+ #ifdef CONFIG_MMU
+ extern void iotable_init(struct map_desc *, int);
+diff --git a/arch/arm/include/asm/mach/time.h b/arch/arm/include/asm/mach/time.h
+index b2cc1fc..880b390 100644
+--- a/arch/arm/include/asm/mach/time.h
++++ b/arch/arm/include/asm/mach/time.h
+@@ -41,8 +41,31 @@ struct sys_timer {
+ #ifndef CONFIG_GENERIC_TIME
+ unsigned long (*offset)(void);
+ #endif
++#ifdef CONFIG_NO_IDLE_HZ
++ struct dyn_tick_timer *dyn_tick;
++#endif
++};
++
++#ifdef CONFIG_NO_IDLE_HZ
++
++#define DYN_TICK_ENABLED (1 << 1)
++
++struct dyn_tick_timer {
++ spinlock_t lock;
++ unsigned int state; /* Current state */
++ int (*enable)(void); /* Enables dynamic tick */
++ int (*disable)(void); /* Disables dynamic tick */
++ void (*reprogram)(unsigned long); /* Reprograms the timer */
++ int (*handler)(int, void *);
+ };
+
++void timer_dyn_reprogram(void);
++#else
++#define timer_dyn_reprogram() do { } while (0)
++#endif
++
++
++
+ extern struct sys_timer *system_timer;
+ extern void timer_tick(void);
+
+diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
+index 21e17dc..6e493dc 100644
+--- a/arch/arm/kernel/head.S
++++ b/arch/arm/kernel/head.S
+@@ -1,9 +1,13 @@
+ /*
+ * linux/arch/arm/kernel/head.S
+ *
+- * Copyright (C) 1994-2002 Russell King
+- * Copyright (c) 2003 ARM Limited
+- * All Rights Reserved
++ * Author: <linux@telechips.com>
++ * Modified: 10th Jun, 2009
++ *
++ * Copyright (C) 1994-2002 Russell King
++ * Copyright (c) 2003 ARM Limited
++ * Copyright (C) 2008-2009 Telechips
++ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+@@ -38,7 +42,7 @@
+ * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000.
+ */
+ #if (KERNEL_RAM_VADDR & 0xffff) != 0x8000
+-#error KERNEL_RAM_VADDR must start at 0xXXXX8000
++@#error KERNEL_RAM_VADDR must start at 0xXXXX8000
+ #endif
+
+ .globl swapper_pg_dir
+@@ -76,15 +80,71 @@
+ */
+ .section ".text.head", "ax"
+ ENTRY(stext)
++ b __startup__
++
++ /*
++ *************************************************************************
++ * Telechips data
++ *************************************************************************
++ */
++ .word 0xffff0106 /* HardwareID */
++ FirmwareVersion:
++ .word 0x3A726556 /* Ver: */
++ .word 0x34333231 /* 1234 */
++ FirmwareCheckSum:
++ .word 0x00000000 /* Firmware CRC32 Value Until 128Kbyte */
++ DACVersion:
++ .word 0x00000000 /* Not Used Area - Reserved */
++ FirmwareCheckSumEnd:
++ .word 0x00000000 /* Firmware CRC32 Value From 128Kbye to End */
++ FirmwareSize:
++ .word 0x00000000 /* Firmware Total Size */
++ SerialNumber:
++ .word 0x00000000 /* SN[3:0] */
++ .word 0x00000000 /* SN[7:4] */
++ .word 0x00000000 /* SN[11:8] */
++ .word 0x00000000 /* SN[15:12] */
++ .word 0x00000000 /* SN[19:16] */
++ .word 0x00000000 /* SN[23:20] */
++ .word 0x00000000 /* SN[27:24] */
++ .word 0x00000000 /* SN[31:28] */
++ .word 0x00000000 /* SN[35:32] */
++ .word 0x00000000 /* SN[39:36] */
++ .word 0x00000000 /* SN[43:40] */
++ .word 0x00000000 /* SN[47:44] */
++ .word 0x00000000 /* SN[51:48] */
++ .word 0x00000000 /* SN[55:52] */
++ .word 0x00000000 /* SN[59:56] */
++ .word 0x00000000 /* SN[63:60] */
++
++__startup__:
+ msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
+ @ and irqs disabled
+ mrc p15, 0, r9, c0, c0 @ get processor id
+ bl __lookup_processor_type @ r5=procinfo r9=cpuid
+ movs r10, r5 @ invalid processor (r5=0)?
+ beq __error_p @ yes, error 'p'
++
++ mov r0, r9 @ print CPU_TYPE
++@ bl printhex8
++ mov r0, #','
++@ bl printch
++
++#if defined(CONFIG_MACH_TCC8900)
++ ldr r1, =0xfa0 @ Machine type = TCC8900 , actually this value should comes from bootloader
++#elif defined(CONFIG_MACH_TCC9100)
++ ldr r1, =0xfa1 @ Machine type = TCC9100
++#elif defined(CONFIG_MACH_TCC9200)
++ ldr r1, =0xfa2 @ Machine type = TCC9200
++#endif
++
+ bl __lookup_machine_type @ r5=machinfo
+ movs r8, r5 @ invalid machine (r5=0)?
+ beq __error_a @ yes, error 'a'
++
++ movs r0, r5 @ print MACH_TYPE
++@ bl printhex8
++
+ bl __vet_atags
+ bl __create_page_tables
+
+diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
+index 2f3eb79..4e566e4 100644
+--- a/arch/arm/kernel/irq.c
++++ b/arch/arm/kernel/irq.c
+@@ -109,10 +109,13 @@ static struct irq_desc bad_irq_desc = {
+ * come via this function. Instead, they should provide their
+ * own 'handler'
+ */
++extern inline void arch_idle_off(void);
+ asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
+ {
+ struct pt_regs *old_regs = set_irq_regs(regs);
+
++ arch_idle_off();
++
+ irq_enter();
+
+ /*
+diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
+index 1f1eecc..949813a 100644
+--- a/arch/arm/kernel/setup.c
++++ b/arch/arm/kernel/setup.c
+@@ -673,11 +673,44 @@ static int __init customize_machine(void)
+ }
+ arch_initcall(customize_machine);
+
++unsigned int TCC_VPU_SIZE;
++EXPORT_SYMBOL(TCC_VPU_SIZE);
++
+ void __init setup_arch(char **cmdline_p)
+ {
+ struct tag *tags = (struct tag *)&init_tags;
+ struct machine_desc *mdesc;
+ char *from = default_command_line;
++
++ /*
++ * Telechips Board Memory Setting
++ * - refer to arch/arm/mach-tcc8900/include/mach/memory.h
++ */
++ unsigned long mem_flag = *(volatile unsigned long *)(phys_to_virt(0x40200000));
++ printk(KERN_ERR "mem_flag = %d\n", mem_flag);
++ switch(mem_flag) {
++ case 0:
++ strcat(default_command_line, " mem=214M");
++ TCC_VPU_SIZE = 24;
++ break;
++ case 1:
++ strcat(default_command_line, " mem=188M");
++ TCC_VPU_SIZE = 50;
++ break;
++ case 2:
++ strcat(default_command_line, " mem=138M");
++ TCC_VPU_SIZE = 100;
++ break;
++ case 3:
++ strcat(default_command_line, " mem=194M");
++ TCC_VPU_SIZE = 44;
++ break;
++ default:
++ printk(KERN_NOTICE "mem_flag was setted wrong\n");
++ strcat(default_command_line, " mem=214M");
++ TCC_VPU_SIZE = 24;
++ break;
++ }
+
+ setup_processor();
+ mdesc = setup_machine(machine_arch_type);
+@@ -831,7 +864,13 @@ static int c_show(struct seq_file *m, void *v)
+ seq_puts(m, "\n");
+
+ seq_printf(m, "Hardware\t: %s\n", machine_name);
++#if defined(CONFIG_TCC_R_AX)
++ seq_printf(m, "Revision\t: %s\n", "AX");
++#elif defined(CONFIG_TCC_R_XX)
++ seq_printf(m, "Revision\t: %s\n", "XX");
++#else
+ seq_printf(m, "Revision\t: %04x\n", system_rev);
++#endif
+ seq_printf(m, "Serial\t\t: %08x%08x\n",
+ system_serial_high, system_serial_low);
+
+diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
+index c68b44a..126e645 100644
+--- a/arch/arm/kernel/time.c
++++ b/arch/arm/kernel/time.c
+@@ -367,6 +367,108 @@ static struct sysdev_class timer_sysclass = {
+ .resume = timer_resume,
+ };
+
++#ifdef CONFIG_NO_IDLE_HZ
++static int timer_dyn_tick_enable(void)
++{
++ struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
++ unsigned long flags;
++ int ret = -ENODEV;
++
++ if (dyn_tick) {
++ spin_lock_irqsave(&dyn_tick->lock, flags);
++ ret = 0;
++ if (!(dyn_tick->state & DYN_TICK_ENABLED)) {
++ ret = dyn_tick->enable();
++
++ if (ret == 0)
++ dyn_tick->state |= DYN_TICK_ENABLED;
++ }
++ spin_unlock_irqrestore(&dyn_tick->lock, flags);
++ }
++
++ return ret;
++}
++
++static int timer_dyn_tick_disable(void)
++{
++ struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
++ unsigned long flags;
++ int ret = -ENODEV;
++
++ if (dyn_tick) {
++ spin_lock_irqsave(&dyn_tick->lock, flags);
++ ret = 0;
++ if (dyn_tick->state & DYN_TICK_ENABLED) {
++ ret = dyn_tick->disable();
++
++ if (ret == 0)
++ dyn_tick->state &= ~DYN_TICK_ENABLED;
++ }
++ spin_unlock_irqrestore(&dyn_tick->lock, flags);
++ }
++
++ return ret;
++}
++
++/*
++ * Reprogram the system timer for at least the calculated time interval.
++ * This function should be called from the idle thread with IRQs disabled,
++ * immediately before sleeping.
++ */
++void timer_dyn_reprogram(void)
++{
++ struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
++ unsigned long next, seq, flags;
++
++ if (!dyn_tick)
++ return;
++
++ spin_lock_irqsave(&dyn_tick->lock, flags);
++ if (dyn_tick->state & DYN_TICK_ENABLED) {
++ next = next_timer_interrupt();
++ do {
++ seq = read_seqbegin(&xtime_lock);
++ dyn_tick->reprogram(next - jiffies);
++ } while (read_seqretry(&xtime_lock, seq));
++ }
++ spin_unlock_irqrestore(&dyn_tick->lock, flags);
++}
++
++static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
++{
++ return sprintf(buf, "%i\n",
++ (system_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1);
++}
++
++static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf,
++ size_t count)
++{
++ unsigned int enable = simple_strtoul(buf, NULL, 2);
++
++ if (enable)
++ timer_dyn_tick_enable();
++ else
++ timer_dyn_tick_disable();
++
++ return count;
++}
++static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick);
++
++/*
++ * dyntick=enable|disable
++ */
++static char dyntick_str[4] __initdata = "";
++
++static int __init dyntick_setup(char *str)
++{
++ if (str)
++ strlcpy(dyntick_str, str, sizeof(dyntick_str));
++ return 1;
++}
++
++__setup("dyntick=", dyntick_setup);
++#endif
++
+ static int __init timer_init_sysfs(void)
+ {
+ int ret = sysdev_class_register(&timer_sysclass);
+@@ -374,6 +476,18 @@ static int __init timer_init_sysfs(void)
+ system_timer->dev.cls = &timer_sysclass;
+ ret = sysdev_register(&system_timer->dev);
+ }
++#ifdef CONFIG_NO_IDLE_HZ
++ if (ret == 0 && system_timer->dyn_tick) {
++ ret = sysdev_create_file(&system_timer->dev, &attr_dyn_tick);
++
++ /*
++ * Turn on dynamic tick after calibrate delay
++ * for correct bogomips
++ */
++ if (ret == 0 && dyntick_str[0] == 'e')
++ ret = timer_dyn_tick_enable();
++ }
++#endif
+
+ return ret;
+ }
+diff --git a/arch/arm/mach-tcc8900/Kconfig b/arch/arm/mach-tcc8900/Kconfig
+new file mode 100644
+index 0000000..5649917
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/Kconfig
+@@ -0,0 +1,107 @@
++# arch/arm/mach-tcc8900/Kconfig
++# Copyright 2009 Telechips
++# License under GPLv2
++
++comment "TCC Core Type"
++ depends on ARCH_TCC
++
++config ARCH_TCC8900
++ bool "TCC Based System"
++ depends on ARCH_TCC
++
++choice
++ prompt "TCC Revision type"
++ depends on ARCH_TCC8900
++ default TCC_R_AX
++ help
++ Select Revision type
++config TCC_R_AX
++ bool "Revision AX"
++ depends on ARCH_TCC && ARCH_TCC8900
++config TCC_R_XX
++ bool "Revision XX"
++ depends on ARCH_TCC && ARCH_TCC8900
++endchoice
++
++
++comment "TCC Board Type"
++ depends on ARCH_TCC && ARCH_TCC8900
++
++config MACH_TCC8900
++ bool "TCC8900"
++ depends on ARCH_TCC && ARCH_TCC8900
++ default y
++ help
++ Support for the TCC8900 demo board, Say Y here if you
++ have such a device.
++
++choice
++ prompt "DRAM Type"
++ depends on ARCH_TCC8900
++ default DRAM_DDR2
++ help
++ Select DRAM Type
++config DRAM_DDR2
++ bool "DRAM_DDR2"
++ help
++ Select DRAM DDR2
++config DRAM_MDDR
++ bool "DRAM_MDDR"
++ help
++ Select DRAM MDDR
++endchoice
++
++
++choice
++ prompt "RAM Size"
++ depends on ARCH_TCC8900
++ default RAM_256MB
++ help
++ Select DRAM Spec
++config RAM_128MB
++ bool "128MB"
++ help
++ Select DRAM size 128MB
++config RAM_256MB
++ bool "256MB"
++ depends on DRAM_DDR2
++ help
++ Select DRAM size 256MB
++endchoice
++
++
++choice
++ prompt "HD Spec"
++ depends on ARCH_TCC8900
++ default HD1080p_LEVEL51
++ help
++ Select HD and LEVEL spec
++config HD720p_LEVEL41
++ bool "HD720p_LEVEL41"
++ help
++ Select HD720p and LEVEL 4.1
++config HD720p_LEVEL51
++ bool "HD720p_LEVEL51"
++ help
++ Select HD720p and LEVEL 5.1
++config HD1080p_LEVEL41
++ bool "HD1080p_LEVEL41"
++ help
++ Select HD1080p and LEVEL 4.1
++config HD1080p_LEVEL51
++ bool "HD1080p_LEVEL51"
++ depends on RAM_256MB
++ help
++ Select HD1080p and LEVEL 5.1
++endchoice
++
++
++config TCC_STRING
++ string "Default dir name"
++ depends on ARCH_TCC8900
++ default "tcc8900"
++ help
++ "tcc8900"
++ Default dir name for MACH_TCC8900
++ Don't edit!!!
++
+diff --git a/arch/arm/mach-tcc8900/Makefile b/arch/arm/mach-tcc8900/Makefile
+new file mode 100644
+index 0000000..97c5099
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/Makefile
+@@ -0,0 +1,53 @@
++#
++# Makefile for the linux kernel.
++#
++# Common support
++obj-$(CONFIG_ARCH_TCC) += io.o irq.o devices.o time.o tca_ckc.o idle.o gpio.o
++
++# Specific board support
++obj-$(CONFIG_MACH_TCC8900) += board-tcc8900.o
++
++
++ifeq ($(CONFIG_ARCH_TCC),y)
++$(shell ln -fsn $(CONFIG_TCC_STRING) $(srctree)/arch/arm/mach-tcc8900/tcc)
++endif
++
++ifeq ($(CONFIG_DRAM_DDR2), y)
++file_1 = tcc_ckcddr2_141to190.c
++file_2 = tcc_ckcddr2_200to290.c
++file_3 = tcc_ckcddr2_300to330.c
++tmp_file = tcc_ckcddr2.newfile
++endif
++ifeq ($(CONFIG_DRAM_MDDR), y)
++file_1 = tcc_ckcmddr_100to160.c
++file_2 = tcc_ckcmddr_20to90.c
++tmp_file = tcc_ckcmddr.newfile
++endif
++
++from_str ='0xB'
++to_str ='0xF'
++
++ifeq ($(CONFIG_DRAM_DDR2), y)
++$(shell sed 's/${from_str}/${to_str}/g' $(srctree)/arch/arm/mach-tcc8900/tcc/$(file_1) > $(srctree)/arch/arm/mach-tcc8900/tcc/${tmp_file})
++$(shell mv -f $(srctree)/arch/arm/mach-tcc8900/tcc/${tmp_file} $(srctree)/arch/arm/mach-tcc8900/tcc/$(file_1))
++$(shell sed 's/${from_str}/${to_str}/g' $(srctree)/arch/arm/mach-tcc8900/tcc/$(file_2) > $(srctree)/arch/arm/mach-tcc8900/tcc/${tmp_file})
++$(shell mv -f $(srctree)/arch/arm/mach-tcc8900/tcc/${tmp_file} $(srctree)/arch/arm/mach-tcc8900/tcc/$(file_2))
++$(shell sed 's/${from_str}/${to_str}/g' $(srctree)/arch/arm/mach-tcc8900/tcc/$(file_3) > $(srctree)/arch/arm/mach-tcc8900/tcc/${tmp_file})
++$(shell mv -f $(srctree)/arch/arm/mach-tcc8900/tcc/${tmp_file} $(srctree)/arch/arm/mach-tcc8900/tcc/$(file_3))
++endif
++ifeq ($(CONFIG_DRAM_MDDR), y)
++$(shell sed 's/${from_str}/${to_str}/g' $(srctree)/arch/arm/mach-tcc8900/tcc/$(file_1) > $(srctree)/arch/arm/mach-tcc8900/tcc/${tmp_file})
++$(shell mv -f $(srctree)/arch/arm/mach-tcc8900/tcc/${tmp_file} $(srctree)/arch/arm/mach-tcc8900/tcc/$(file_1))
++$(shell sed 's/${from_str}/${to_str}/g' $(srctree)/arch/arm/mach-tcc8900/tcc/$(file_2) > $(srctree)/arch/arm/mach-tcc8900/tcc/${tmp_file})
++$(shell mv -f $(srctree)/arch/arm/mach-tcc8900/tcc/${tmp_file} $(srctree)/arch/arm/mach-tcc8900/tcc/$(file_2))
++endif
++
++ifeq ($(CONFIG_DRAM_DDR2), y)
++obj-$(CONFIG_ARCH_TCC) += tcc_ckc_ctrl.o tcc/arm_ioctlutil.o tcc/tcc_ckcddr2_141to190.o tcc/tcc_ckcddr2_200to290.o tcc/tcc_ckcddr2_300to330.o
++endif
++ifeq ($(CONFIG_DRAM_MDDR), y)
++obj-$(CONFIG_ARCH_TCC) += tcc_ckc_ctrl.o tcc/arm_ioctlutil.o tcc/tcc_ckcmddr_100to160.o tcc/tcc_ckcmddr_20to90.o
++endif
++
++obj-$(CONFIG_PM) += pm.o pm_asm.o
++
+diff --git a/arch/arm/mach-tcc8900/Makefile.boot b/arch/arm/mach-tcc8900/Makefile.boot
+new file mode 100644
+index 0000000..dd6c7a8
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/Makefile.boot
+@@ -0,0 +1,3 @@
++ zreladdr-y := 0x10008000
++params_phys-y := 0x10000100
++initrd_phys-y := 0x10800000
+diff --git a/arch/arm/mach-tcc8900/board-tcc8900.c b/arch/arm/mach-tcc8900/board-tcc8900.c
+new file mode 100644
+index 0000000..638d63d
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/board-tcc8900.c
+@@ -0,0 +1,98 @@
++/* lnux/arch/arm/mach-tcc8900/board-tcc8900.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 10th Feb, 2009
++ * Description:
++ *
++ * Copyright (C) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++
++#include <linux/spi/spi.h>
++#include <linux/i2c.h>
++
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/flash.h>
++
++#include <bsp.h>
++#include <mach/common.h>
++#include <hhtech_gpio.h>
++#include <mach/gpio.h>
++#include <plat/pm.h>
++
++extern void __init tcc8900_irq_init(void);
++extern void __init tcc8900_map_common_io(void);
++
++
++static struct spi_board_info tcc8900_spi0_board_info[] = {
++ {
++ .modalias = "spidev",
++ .bus_num = 0,
++ .chip_select = 0,
++ .max_speed_hz = 40 * 1000 * 1000,
++ },
++};
++
++static struct spi_board_info tcc8900_spi1_board_info[] = {
++ {
++ .modalias = "spidev",
++ .bus_num = 1,
++ .chip_select = 0,
++ .max_speed_hz = 40 * 1000 * 1000,
++ },
++};
++
++static struct i2c_board_info __initdata tcc8900_i2c_board_info[] = {
++ {
++// I2C_BOARD_INFO("tps65011", 0x48),
++// .type = "",
++// .addr = 0xff,
++// .irq = IRQ_EINT20,
++ }
++};
++
++static void tcc8900_power_off(void)
++{
++ gpio_direction_output(GPIO_SPEAKER_EN, 0);
++ gpio_direction_output(GPIO_PWR_EN, 0);
++}
++
++static void __init tcc8900_map_io(void)
++{
++ pm_power_off = tcc8900_power_off;
++ tcc8900_map_common_io();
++ tcc8902_pm_init();
++}
++
++static void __init tcc8900_init_irq(void)
++{
++ tcc8900_irq_init();
++// tcc8900_gpio_init();
++}
++
++static void __init tcc8900_init_machine(void)
++{
++ spi_register_board_info(tcc8900_spi0_board_info, ARRAY_SIZE(tcc8900_spi0_board_info));
++ spi_register_board_info(tcc8900_spi1_board_info, ARRAY_SIZE(tcc8900_spi1_board_info));
++ i2c_register_board_info(-1, tcc8900_i2c_board_info, ARRAY_SIZE(tcc8900_i2c_board_info));
++}
++
++MACHINE_START(TCC8900, "Telechips TCC8900 Demo Board")
++ /* Maintainer: Telechips Linux BSP Team <linux@telechips.com> */
++ .phys_io = 0xf0000000,
++ .io_pg_offst = ((0xf0000000) >> 18) & 0xfffc,
++ .boot_params = PHYS_OFFSET + 0x00000100,
++ .map_io = tcc8900_map_io,
++ .init_irq = tcc8900_init_irq,
++ .init_machine = tcc8900_init_machine,
++ .timer = &tcc8900_timer,
++MACHINE_END
+diff --git a/arch/arm/mach-tcc8900/devices.c b/arch/arm/mach-tcc8900/devices.c
+new file mode 100644
+index 0000000..51068f0
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/devices.c
+@@ -0,0 +1,861 @@
++/*
++ * linux/arch/arm/mach-tcc8900/devices.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 10th Feb, 2009
++ * Description:
++ *
++ * Copyright (C) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <asm/mach-types.h>
++#include <asm/mach/map.h>
++
++#include <bsp.h>
++#include <mach/ohci.h>
++
++#include <linux/dm9000.h>
++#include <linux/i2c-gpio.h>
++#include <linux/gpio_keys.h>
++#include <linux/input.h>
++
++#include <hhtech_gpio.h>
++#include <mach/gpio.h>
++
++/*----------------------------------------------------------------------
++ * Device : Touch Driver resource
++ * Description: tcc8900_touch_resources
++ *----------------------------------------------------------------------*/
++#if defined(CONFIG_TOUCHSCREEN_TCCTS) || defined(CONFIG_TOUCHSCREEN_TCCTS_MODULE)
++static struct resource tcc8900_touch_resources[] = {
++ [0] = {
++ .start = 0xF05F4000,
++ .end = 0xF05F4000 + 0x20,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_TSADC,
++ .end = INT_TSADC,
++ .flags = IORESOURCE_IRQ,
++ },
++ [2] = {
++ .start = INT_EI2,
++ .end = INT_EI2,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device tcc8900_touchscreen_device = {
++ .name = "tcc-ts",
++ .id = -1,
++ .resource = tcc8900_touch_resources,
++ .num_resources = ARRAY_SIZE(tcc8900_touch_resources),
++};
++
++static inline void tcc8900_init_touch_ts(void)
++{
++ platform_device_register(&tcc8900_touchscreen_device);
++}
++#endif /* CONFIG_TOUCHSCREEN_TCCTS */
++
++static struct platform_device hhtech_gpio_device = {
++ .name = "hhtech_gpio",
++ .id = -1,
++ .resource = NULL,
++ .num_resources = 0,
++};
++
++static inline void tcc8900_init_hhtech_gpio(void)
++{
++ platform_device_register(&hhtech_gpio_device);
++}
++
++/*----------------------------------------------------------------------
++ * Device : DM9000 resource
++ * Description: tcc8900_dm9000_resources
++ *----------------------------------------------------------------------*/
++#if defined(CONFIG_TCC_DM9000) || defined(CONFIG_TCC_DM9000_MODULE)
++static struct resource tcc8900_dm9000_resource[] = {
++ [0] = {
++ .start = (0xF05C0000),
++ .end = (0xF05C0000)+ 0x3,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = (0xF05C0000)+ 0x4,
++ .end = (0xF05C0000)+ 0x4 + 0x3f,
++ .flags = IORESOURCE_MEM,
++ },
++ [2] = {
++ .start = INT_EI4,
++ .end = INT_EI4,
++ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
++ }
++
++};
++
++/* for the moment we limit ourselves to 16bit IO until some
++ * better IO routines can be written and tested
++*/
++static struct dm9000_plat_data bast_dm9000_platdata = {
++ .flags = DM9000_PLATF_8BITONLY,
++};
++
++static struct platform_device tcc8900_dm9000_device = {
++ .name = "dm9000",
++ .id = 0,
++ .num_resources = ARRAY_SIZE(tcc8900_dm9000_resource),
++ .resource = tcc8900_dm9000_resource,
++ .dev = {
++ .platform_data = &bast_dm9000_platdata,
++ }
++};
++
++static inline void tcc8900_init_dm9000(void)
++{
++ platform_device_register(&tcc8900_dm9000_device);
++}
++#endif
++
++
++/*----------------------------------------------------------------------
++ * Device : DM9000 resource
++ * Description: tcc8900_dm9ks_resources
++ *----------------------------------------------------------------------*/
++#if defined(CONFIG_DM9KS) || defined(CONFIG_DM9KS_MODULE)
++static struct platform_device tcc8900_dm9ks_device = {
++ .name = "dm9ks",
++ .id = -1,
++};
++
++static inline void tcc8900_init_dm9ks(void)
++{
++ platform_device_register(&tcc8900_dm9ks_device);
++}
++#endif
++
++
++/*----------------------------------------------------------------------
++ * Device : RTC resource
++ * Description: tcc8900_rtc_resources
++ *----------------------------------------------------------------------*/
++#if defined(CONFIG_RTC_DRV_TCC) || defined(CONFIG_RTC_DRV_TCC_MODULE)
++static struct resource tcc8900_rtc_resource[] = {
++ [0] = {
++ .start = 0xF05F2000,
++ .end = 0xF05F20FF,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_RTC,
++ .end = INT_RTC,
++ .flags = IORESOURCE_IRQ,
++ }
++};
++
++static struct platform_device tcc8900_rtc_device = {
++ .name = "tcc-rtc",
++ .id = -1,
++ .resource = tcc8900_rtc_resource,
++ .num_resources = ARRAY_SIZE(tcc8900_rtc_resource),
++ .dev = {
++ .platform_data = NULL,
++ }
++};
++
++static inline void tcc8900_init_rtc(void)
++{
++ platform_device_register(&tcc8900_rtc_device);
++}
++#endif /* CONFIG_RTC_DRV_TCC */
++
++
++#if defined(CONFIG_I2C_TCC) || defined(CONFIG_I2C_TCC_MODULE)
++/*----------------------------------------------------------------------
++ * Device : I2C resource
++ * Description: tcc8900_i2c_resources has master0 and master1
++ *----------------------------------------------------------------------*/
++static struct resource tcc8900_i2c_resources[] = {
++ [0] = {
++ .start = 0xF0530000, /* I2C master ch0 base address */
++ .end = 0xF0530040, /* I2C master ch1 base address */
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = 50, /* I2C ch0 50Kbps */
++ .end = 50, /* I2C ch1 50Kbps */
++ .flags = IORESOURCE_MEM,
++ },
++// [1] = {
++// .start = INT_I2C, /* I2C master ch[0,1] irq number */
++// .end = INT_I2C, /* I2C ch1 irq number */
++// .flags = IORESOURCE_IRQ,
++// },
++
++ /* SMU_I2C */
++ [2] = {
++ .start = 0xF0405000, /* SMU_I2C master ch0 SATA-PHY base address */
++ .end = 0xF0405040, /* SMU_I2C master ch1 HDMI-PHY base address */
++ .flags = IORESOURCE_MEM,
++ },
++ [3] = {
++ .start = 100, /* SMU_I2C ch0 100Kbps */
++ .end = 100, /* SMU_I2C ch1 100Kbps */
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++static struct platform_device tcc8900_i2c_device = {
++ .name = "tcc-i2c",
++ .id = -1,
++ .resource = tcc8900_i2c_resources,
++ .num_resources = ARRAY_SIZE(tcc8900_i2c_resources),
++};
++
++static inline void tcc8900_init_i2c(void)
++{
++ platform_device_register(&tcc8900_i2c_device);
++}
++#endif
++
++
++/*----------------------------------------------------------------------
++ * Device : I2C GPIO resource
++ * Description:
++ *----------------------------------------------------------------------*/
++
++#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
++static struct i2c_gpio_platform_data pdata = {
++ .sda_pin = TCC_GPD6,
++ .sda_is_open_drain = 0,
++ .scl_pin = TCC_GPD5,
++ .scl_is_open_drain = 0,
++ .udelay = 50, /* ~100 kHz */
++};
++
++static struct platform_device tcc8900_i2c_gpio_device = {
++ .name = "i2c-gpio",
++ .id = 4,
++ .dev.platform_data = &pdata,
++};
++
++static void tcc8900_init_i2c_gpio()
++{
++ platform_device_register(&tcc8900_i2c_gpio_device);
++}
++#endif
++
++/*----------------------------------------------------------------------
++ * Device : LCD Frame Buffer resource
++ * Description:
++ *----------------------------------------------------------------------*/
++static u64 tcc8900_device_lcd_dmamask = 0xffffffffUL;
++struct platform_device tcc8900_lcd_device = {
++ .name = "tccxxx-lcd",
++ .id = -1,
++ .dev = {
++ .dma_mask = &tcc8900_device_lcd_dmamask,
++// .coherent_dma_mask = 0xffffffffUL
++ }
++};
++
++static inline void tcc8900_init_lcd(void)
++{
++ platform_device_register(&tcc8900_lcd_device);
++}
++
++
++/*----------------------------------------------------------------------
++ * Device : Serial-ATA resource
++ * Description:
++ *----------------------------------------------------------------------*/
++#if defined(CONFIG_SATA_TCC) || defined(CONFIG_SATA_TCC_MODULE)
++static struct resource sata_resources[] = {
++ [0] = {
++ .start = 0xF0560000,
++ .end = 0xF0560800,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_SATA,
++ .end = INT_SATA,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device tcc8900_sata_device = {
++ .name = "tcc-sata",
++ .id = 0,
++ .resource = sata_resources,
++ .num_resources = ARRAY_SIZE(sata_resources),
++};
++
++static inline void tcc8900_init_sata(void)
++{
++ platform_device_register(&tcc8900_sata_device);
++}
++#endif
++
++
++/*----------------------------------------------------------------------
++ * Device : SPI(GPSB) Master resource
++ * Description:
++ *----------------------------------------------------------------------*/
++#if defined(CONFIG_SPI_TCC_MASTER) || defined(CONFIG_SPI_TCC_MASTER_MODULE)
++static struct resource spi0_resources[] = {
++ [0] = {
++ .start = 0xF0536000,
++ .end = 0xF0536038,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_GPSB0_DMA,
++ .end = INT_GPSB0_DMA,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device tcc8900_spi0_device = {
++ .name = "tcc-spi",
++ .id = 0,
++ .resource = spi0_resources,
++ .num_resources = ARRAY_SIZE(spi0_resources),
++};
++
++static struct resource spi1_resources[] = {
++ [0] = {
++ .start = 0xF0536100,
++ .end = 0xF0536138,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_GPSB1_DMA,
++ .end = INT_GPSB1_DMA,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device tcc8900_spi1_device = {
++ .name = "tcc-spi",
++ .id = 1,
++ .resource = spi1_resources,
++ .num_resources = ARRAY_SIZE(spi1_resources),
++};
++
++static inline void tcc8900_init_spi(void)
++{
++ platform_device_register(&tcc8900_spi0_device);
++ platform_device_register(&tcc8900_spi1_device);
++}
++#endif
++
++
++/*----------------------------------------------------------------------
++ * Device : SPI(TSIF) Slave resource
++ * Description:
++ *----------------------------------------------------------------------*/
++#if defined(CONFIG_TSIF_TCC_SLAVE) || defined(CONFIG_TSIF_TCC_SLAVE_MODULE)
++static struct platform_device tcc_tsif_device = {
++ .name = "tcc-tsif",
++ .id = -1,
++};
++
++static inline void tcc8900_init_tsif(void)
++{
++ platform_device_register(&tcc_tsif_device);
++}
++#endif
++
++
++/*----------------------------------------------------------------------
++ * Device : SD/MMC resource
++ * Description: tcc8900_mmc_core0_resource
++ * tcc8900_mmc_core1_resource
++ *----------------------------------------------------------------------*/
++#if defined(CONFIG_MMC_TCC_SDHC_CORE0) || defined(CONFIG_MMC_TCC_SDHC_CORE0_MODULE)
++static u64 tcc8900_device_mmc0_dmamask = 0xffffffffUL;
++static struct resource tcc8900_mmc_core0_resource[] = {
++ [0] = {
++ .start = 0xF05A0000,
++ .end = 0xF05A00FF,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_SD0,
++ .end = INT_SD0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++struct platform_device tcc8900_mmc0_device = {
++ .name = "tcc-sdhc0",
++ .id = 0,
++ .num_resources = ARRAY_SIZE(tcc8900_mmc_core0_resource),
++ .resource = tcc8900_mmc_core0_resource,
++ .dev = {
++ .dma_mask = &tcc8900_device_mmc0_dmamask,
++ .coherent_dma_mask = 0xffffffffUL
++ }
++};
++#endif
++
++#if defined(CONFIG_MMC_TCC_SDHC_CORE1) || defined(CONFIG_MMC_TCC_SDHC_CORE1_MODULE)
++static u64 tcc8900_device_mmc1_dmamask = 0xffffffffUL;
++static struct resource tcc8900_mmc_core1_resource[] = {
++ [0] = {
++ .start = 0xF05A0200,
++ .end = 0xF05A02FF,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_SD1,
++ .end = INT_SD1,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++struct platform_device tcc8900_mmc1_device = {
++ .name = "tcc-sdhc1",
++ .id = 1,
++ .num_resources = ARRAY_SIZE(tcc8900_mmc_core1_resource),
++ .resource = tcc8900_mmc_core1_resource,
++ .dev = {
++ .dma_mask = &tcc8900_device_mmc1_dmamask,
++ .coherent_dma_mask = 0xffffffffUL
++ }
++};
++#endif
++
++#if defined(CONFIG_MMC_TCC_SDHC) || defined(CONFIG_MMC_TCC_SDHC_MODULE)
++static inline void tcc8900_init_mmc(void)
++{
++#if defined(CONFIG_MMC_TCC_SDHC_CORE0)
++ platform_device_register(&tcc8900_mmc0_device);
++#endif
++#if defined(CONFIG_MMC_TCC_SDHC_CORE1)
++ platform_device_register(&tcc8900_mmc1_device);
++#endif
++}
++#endif
++
++
++/*----------------------------------------------------------------------
++ * Device : UART resource
++ * Description: uart0_resources
++ * uart1_resources
++ * uart2_resources (not used)
++ * uart3_resources (not used)
++ * uart4_resources (not used)
++ * uart5_resources (not used)
++ *----------------------------------------------------------------------*/
++static struct resource uart0_resources[] = {
++ /* PA -> VA */
++ [0] = {
++ .start = 0xF0532000,
++ .end = 0xF05320FF,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_UART0,
++ .end = INT_UART0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device tcc8900_uart0_device = {
++ .name = "tcc8900-uart",
++ .id = 0,
++ .resource = uart0_resources,
++ .num_resources = ARRAY_SIZE(uart0_resources),
++};
++
++static struct resource uart1_resources[] = {
++ [0] = {
++ .start = 0xF0532100,
++ .end = 0xF05321FF,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_UART1,
++ .end = INT_UART1,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device tcc8900_uart1_device = {
++ .name = "tcc8900-uart",
++ .id = 1,
++ .resource = uart1_resources,
++ .num_resources = ARRAY_SIZE(uart1_resources),
++};
++
++#if 0
++static struct resource uart2_resources[] = {
++ [0] = {
++ .start = 0xF0532200,
++ .end = 0xF05322FF,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_UART2,
++ .end = INT_UART2,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device tcc8900_uart2_device = {
++ .name = "tcc8900-uart",
++ .id = 2,
++ .resource = uart2_resources,
++ .num_resources = ARRAY_SIZE(uart2_resources),
++};
++
++static struct resource uart3_resources[] = {
++ [0] = {
++ .start = 0xF0532300,
++ .end = 0xF05323FF,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_UART3,
++ .end = INT_UART3,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device tcc8900_uart3_device = {
++ .name = "tcc8900-uart",
++ .id = 3,
++ .resource = uart3_resources,
++ .num_resources = ARRAY_SIZE(uart3_resources),
++};
++
++static struct resource uart4_resources[] = {
++ [0] = {
++ .start = 0xF0532400,
++ .end = 0xF05324FF,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_UART4,
++ .end = INT_UART4,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device tcc8900_uart4_device = {
++ .name = "tcc8900-uart",
++ .id = 4,
++ .resource = uart4_resources,
++ .num_resources = ARRAY_SIZE(uart4_resources),
++};
++
++static struct resource uart5_resources[] = {
++ [0] = {
++ .start = 0xF0532500,
++ .end = 0xF05325FF,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_UART5,
++ .end = INT_UART5,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device tcc8900_uart5_device = {
++ .name = "tcc8900-uart",
++ .id = 5,
++ .resource = uart5_resources,
++ .num_resources = ARRAY_SIZE(uart5_resources),
++};
++#endif
++
++static inline void tcc8900_init_uart(void)
++{
++ platform_device_register(&tcc8900_uart0_device);
++#if 0
++ platform_device_register(&tcc8900_uart1_device);
++ platform_device_register(&tcc8900_uart2_device);
++ platform_device_register(&tcc8900_uart3_device);
++ platform_device_register(&tcc8900_uart4_device);
++ platform_device_register(&tcc8900_uart5_device);
++#endif
++}
++
++
++/*----------------------------------------------------------------------
++ * Device : USB HOST1.1 OHCI resource
++ * Description: tcc8900_ohci_resources
++ *----------------------------------------------------------------------*/
++ #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
++ static u64 tcc8900_device_ohci_dmamask = 0xffffffffUL;
++
++ static struct resource tcc8900_ohci_resources[] = {
++ [0] = {
++ .start = 0xF0500000,
++ .end = 0xF050005C,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_U11H,
++ .end = INT_U11H,
++ .flags = IORESOURCE_IRQ,
++ }
++};
++
++static struct platform_device ohci_device = {
++ .name = "tcc-ohci",
++ .id = -1,
++ .num_resources = ARRAY_SIZE(tcc8900_ohci_resources),
++ .resource = tcc8900_ohci_resources,
++ .dev = {
++ .dma_mask = &tcc8900_device_ohci_dmamask,
++ .coherent_dma_mask = 0xffffffff,
++ },
++};
++
++static int tcc8900_ohci_init(struct device *dev)
++{
++ return 0;
++}
++
++static struct tccohci_platform_data tcc8900_ohci_platform_data = {
++ .port_mode = USBOHCI_PPM_PERPORT,
++ .init = tcc8900_ohci_init,
++};
++
++void __init tcc_set_ohci_info(struct tccohci_platform_data *info)
++{
++ ohci_device.dev.platform_data = info;
++}
++
++static inline void tcc8900_init_usbhost(void)
++{
++ platform_device_register(&ohci_device);
++ tcc_set_ohci_info(&tcc8900_ohci_platform_data);
++}
++#endif /*CONFIG_USB_OHCI_HCD || CONFIG_USB_OHCI_HCD_MODULE*/
++
++
++/*----------------------------------------------------------------------
++ * Device : USB DWC OTG resource
++ * Description: dwc_otg_resources
++ *----------------------------------------------------------------------*/
++#if defined(CONFIG_TCC_DWC_OTG) || defined(CONFIG_TCC_DWC_OTG_MODULE)
++static u64 tcc8900_dwc_otg_dmamask = 0xffffffffUL;
++static struct resource dwc_otg_resources[] = {
++ [0] = {
++ .start = 0xF0550000,
++ .end = 0xF0550100,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = INT_UOTG,
++ .end = INT_UOTG,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device tcc8900_dwc_otg_device = {
++ .name = "dwc_otg",
++ .id = 0,
++ .resource = dwc_otg_resources,
++ .num_resources = ARRAY_SIZE(dwc_otg_resources),
++ .dev = {
++ .dma_mask = &tcc8900_dwc_otg_dmamask,
++ .coherent_dma_mask = 0xffffffff,
++ },
++};
++
++static inline void tcc8900_init_dwc_otg(void)
++{
++ int ret;
++ ret = platform_device_register(&tcc8900_dwc_otg_device);
++}
++#endif
++
++static struct gpio_keys_button hhmid_buttons[] = {
++#if defined (CONFIG_LCD_4)
++ {
++ .gpio = TCC_GPD19,
++ .code = KEY_PAGEUP,
++ .desc = "Button 3",
++ .active_low = 1,
++ .debounce_interval = 5,
++ },
++ {
++ .gpio = TCC_GPD18,
++ .code = KEY_LEFTALT,
++ .desc = "Button 1",
++ .active_low = 1,
++ .debounce_interval = 5,
++ },
++ {
++ .gpio = TCC_GPD17,
++ .code = KEY_PAGEDOWN,
++ .desc = "Button 2",
++ .active_low = 1,
++ .debounce_interval = 5,
++ },
++ {
++ .gpio = TCC_GPF10,
++ .code = KEY_POWER,
++ .desc = "Button 0",
++ .active_low = 1,
++ .debounce_interval = 5,
++ },
++#else
++
++ {
++ .gpio = TCC_GPD17,
++ .code = KEY_PAGEUP,
++ .desc = "Button 5",
++ .active_low = 1,
++ .debounce_interval = 5,
++ },
++
++ {
++ .gpio = TCC_GPD16,
++ .code = KEY_PAGEDOWN,
++ .desc = "Button 4",
++ .active_low = 1,
++ .debounce_interval = 5,
++ },
++
++ {
++ .gpio = TCC_GPD15,
++ .code = KEY_LEFTALT,
++ .desc = "Button 3",
++ .active_low = 1,
++ .debounce_interval = 5,
++ },
++ {
++ .gpio = TCC_GPD18,
++ .code = KEY_ENTER,
++ .desc = "Button 1",
++ .active_low = 1,
++ .debounce_interval = 5,
++ },
++ {
++ .gpio = TCC_GPD19,
++ .code = KEY_ESC,
++ .desc = "Button 2",
++ .active_low = 1,
++ .debounce_interval = 5,
++ },
++ {
++ .gpio = TCC_GPF10,
++ .code = KEY_POWER,
++ .desc = "Button 0",
++ .active_low = 1,
++ .debounce_interval = 5,
++ },
++#endif
++};
++
++//static struct gpio_keys_platform_data hhmid_button_data __initdata = {
++static struct gpio_keys_platform_data hhmid_button_data = {
++ .buttons = hhmid_buttons,
++ .nbuttons = ARRAY_SIZE(hhmid_buttons),
++};
++
++static struct platform_device hhmid_button_device = {
++ .name = "gpio-keys",
++ .id = 0,
++ .num_resources = 0,
++ .dev = {
++ .platform_data = &hhmid_button_data,
++ }
++};
++
++static inline void tcc8900_init_hhmid_button(void)
++{
++ int ret;
++ ret = platform_device_register(&hhmid_button_device);
++}
++/*
++ * This gets called after board-specific INIT_MACHINE, and initializes most
++ * on-chip peripherals accessible on this board (except for few like USB):
++ *
++ * (a) Does any "standard config" pin muxing needed. Board-specific
++ * code will have muxed GPIO pins and done "nonstandard" setup;
++ * that code could live in the boot loader.
++ * (b) Populating board-specific platform_data with the data drivers
++ * rely on to handle wiring variations.
++ * (c) Creating platform devices as meaningful on this board and
++ * with this kernel configuration.
++ *
++ * Claiming GPIOs, and setting their direction and initial values, is the
++ * responsibility of the device drivers. So is responding to probe().
++ *
++ * Board-specific knowlege like creating devices or pin setup is to be
++ * kept out of drivers as much as possible. In particular, pin setup
++ * may be handled by the boot loader, and drivers should expect it will
++ * normally have been done by the time they're probed.
++ */
++static int __init tcc8900_init_devices(void)
++{
++ tcc8900_init_hhtech_gpio();
++
++#if defined(CONFIG_I2C_TCC) || defined(CONFIG_I2C_TCC_MODULE)
++ tcc8900_init_i2c();
++#endif
++
++#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
++ tcc8900_init_i2c_gpio();
++#endif
++
++#if defined(CONFIG_TCC_DM9000) || defined(CONFIG_TCC_DM9000_MODULE)
++ tcc8900_init_dm9000();
++#endif
++#if defined(CONFIG_DM9KS) || defined(CONFIG_DM9KS_MODULE)
++ tcc8900_init_dm9ks();
++#endif
++
++#if defined(CONFIG_RTC_DRV_TCC) || defined(CONFIG_RTC_DRV_TCC_MODULE)
++ tcc8900_init_rtc();
++#endif
++
++ tcc8900_init_uart();
++ tcc8900_init_lcd();
++
++#if defined(CONFIG_SPI_TCC_MASTER) || defined(CONFIG_SPI_TCC_MASTER_MODULE)
++ tcc8900_init_spi();
++#endif
++#if defined(CONFIG_TSIF_TCC_SLAVE) || defined(CONFIG_TSIF_TCC_SLAVE_MODULE)
++ tcc8900_init_tsif();
++#endif
++
++#if defined(CONFIG_TOUCHSCREEN_TCCTS) || defined(CONFIG_TOUCHSCREEN_TCCTS_MODULE)
++ tcc8900_init_touch_ts();
++#endif
++
++#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
++ tcc8900_init_usbhost();
++#endif
++#if defined(CONFIG_TCC_DWC_OTG) || defined(CONFIG_TCC_DWC_OTG_MODULE)
++ tcc8900_init_dwc_otg();
++#endif
++
++#if defined(CONFIG_MMC_TCC_SDHC) || defined(CONFIG_MMC_TCC_SDHC_MODULE)
++ tcc8900_init_mmc();
++#endif
++
++#if defined(CONFIG_SATA_TCC) || defined(CONFIG_SATA_TCC_MODULE)
++ tcc8900_init_sata();
++#endif
++
++ tcc8900_init_hhmid_button();
++
++ return 0;
++}
++
++arch_initcall(tcc8900_init_devices);
+diff --git a/arch/arm/mach-tcc8900/gpio.c b/arch/arm/mach-tcc8900/gpio.c
+new file mode 100644
+index 0000000..a4c80d5
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/gpio.c
+@@ -0,0 +1,192 @@
++/*
++ * linux/arch/arm/mach-tcc8900/gpio.c
++ *
++ * Support functions for TCC8900 GPIO
++ *
++ * Copyright (C) 2009 Telechips
++ * Written by linux <linux@telechips.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/sysdev.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++
++#include <mach/gpio.h>
++#include <mach/irqs.h>
++#include <mach/hardware.h>
++
++#include <asm/irq.h>
++#include <asm/mach/irq.h>
++#include <asm-generic/gpio.h> /* cansleep wrappers */
++
++void tcc_gpio_cfgpin(unsigned int pin, unsigned int function, unsigned int out)
++{
++ unsigned long mask, fn_val, flags, offs, fn_offs, fn_num, en_val;
++ void __iomem *base, *en_addr, *fn_addr;
++
++ base = (void __iomem *)tcc_p2v(HwGPIO_BASE);
++ base += TCC_GPIO_BASE(pin) * 0x40;
++ offs = TCC_GPIO_OFFSET(pin);
++ fn_num = offs / 8; // Get port configuration register number
++ en_addr = base + 0x4; // Get output enable register address
++ fn_addr = base + 0x24 + fn_num * 4; // Get port configuration register adrress
++ fn_offs = (offs % 8) * 4; // Get offset in port configuration register
++ mask = 0xF << fn_offs;
++
++ local_irq_save(flags);
++ local_irq_disable();
++ fn_val = __raw_readl(fn_addr);
++ fn_val &= ~mask;
++ fn_val |= (function << fn_offs);
++ __raw_writel(fn_val, fn_addr);
++ // When configured into gpio function
++ if(function == 0) {
++ en_val = __raw_readl(en_addr);
++ if(out) // output
++ en_val |= (1 << offs);
++ else
++ en_val &= ~(1 << offs);
++ __raw_writel(en_val, en_addr);
++ }
++
++ local_irq_restore(flags);
++}
++
++EXPORT_SYMBOL(tcc_gpio_cfgpin);
++
++unsigned int tcc_gpio_getcfg(unsigned int pin)
++{
++ void __iomem *base, *fn_addr;
++ unsigned long mask, offs, fn_offs, fn_num;
++
++ base = (void __iomem *)tcc_p2v(HwGPIO_BASE);
++ base += TCC_GPIO_BASE(pin) * 0x40;
++ offs = TCC_GPIO_OFFSET(pin);
++ fn_num = offs / 8; // Get port configuration register number
++ fn_addr = base + 0x24 + fn_num * 4; // Get port configuration register adrress
++ fn_offs = (offs % 8) * 4; // Get offset in port configuration register
++ mask = 0xF << fn_offs;
++
++ return ((__raw_readl(fn_addr) & mask) >> fn_offs);
++}
++
++EXPORT_SYMBOL(tcc_gpio_getcfg);
++
++/* 0: pull-up/down disabled, 1: pull-up enabled, 2: pull-down enabled */
++void tcc_gpio_pullup(unsigned int pin, unsigned int to)
++{
++ unsigned long offs = TCC_GPIO_OFFSET(pin);
++ unsigned long flags, up, mask, pd_num, pd_offs;
++ void __iomem *base, *pd_addr;
++
++ base = (void __iomem *)tcc_p2v(HwGPIO_BASE);
++ base += TCC_GPIO_BASE(pin) * 0x40;
++ pd_num = offs / 16; // Get pull-up/down function register number
++ pd_addr = base + 0x1C + pd_num * 4; // Get pull-up/down function register adrress
++ pd_offs = (offs % 16) * 2; // Get offset in pull-up/down function register
++
++ mask = 0x3 << pd_offs;
++
++ local_irq_save(flags);
++ local_irq_disable();
++
++ up = __raw_readl(pd_addr);
++ up &= ~mask;
++ up |= to << pd_offs;
++ __raw_writel(up, pd_addr);
++
++ local_irq_restore(flags);
++}
++
++EXPORT_SYMBOL(tcc_gpio_pullup);
++
++void tcc_gpio_setpin(unsigned int pin, unsigned int to)
++{
++ void __iomem *base;
++ unsigned long offs = TCC_GPIO_OFFSET(pin);
++ unsigned long flags;
++ unsigned long dat;
++
++ base = (void __iomem *)tcc_p2v(HwGPIO_BASE);
++ base += TCC_GPIO_BASE(pin) * 0x40;
++ local_irq_save(flags);
++ local_irq_disable();
++
++ dat = __raw_readl(base);
++ dat &= ~(1 << offs);
++ dat |= to << offs;
++ __raw_writel(dat, base);
++
++ local_irq_restore(flags);
++}
++
++EXPORT_SYMBOL(tcc_gpio_setpin);
++
++unsigned int tcc_gpio_getpin(unsigned int pin)
++{
++ void __iomem *base;
++ unsigned long offs = TCC_GPIO_OFFSET(pin);
++ unsigned long dat;
++
++ base = (void __iomem *)tcc_p2v(HwGPIO_BASE);
++ base += TCC_GPIO_BASE(pin) * 0x40;
++ dat = __raw_readl(base);
++ dat &= (1 << offs);
++ return (dat >> offs);
++}
++
++EXPORT_SYMBOL(tcc_gpio_getpin);
++
++int tcc_gpio_direction_input(unsigned int gpio)
++{
++ tcc_gpio_cfgpin(gpio, 0, TCC_GPIO_INPUT);
++ tcc_gpio_pullup(gpio, 0); // pull-up/down disable
++
++ return 0;
++}
++EXPORT_SYMBOL(tcc_gpio_direction_input);
++
++int tcc_gpio_direction_output(unsigned int gpio, int value)
++{
++ tcc_gpio_cfgpin(gpio, 0, TCC_GPIO_OUTPUT);
++
++ /* REVISIT can we write the value first, to avoid glitching? */
++ tcc_gpio_setpin(gpio, value);
++
++ return 0;
++}
++EXPORT_SYMBOL(tcc_gpio_direction_output);
++
++int gpio_to_irq(unsigned int pin)
++{
++ switch(pin)
++ {
++ case TCC_GPD15:
++ return 8;
++ case TCC_GPD16:
++ return 9;
++ case TCC_GPD17:
++ return 11;
++ case TCC_GPD18:
++ return 12;
++ case TCC_GPD19:
++ return 13;
++ case TCC_GPF10:
++ return 14;
++ }
++ return 0;
++}
++EXPORT_SYMBOL(gpio_to_irq);
++
++int __init tcc8900_gpio_init(void)
++{
++ return 0;
++}
+diff --git a/arch/arm/mach-tcc8900/idle.c b/arch/arm/mach-tcc8900/idle.c
+new file mode 100644
+index 0000000..d77265d
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/idle.c
+@@ -0,0 +1,49 @@
++/*
++ * linux/arch/arm/mach-tcc8900/idle.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: June 10, 2008
++ * Description: TCC89/91/92 idle function
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++#include <asm/atomic.h>
++#include <asm/mach-types.h>
++#include <mach/hardware.h>
++#include <bsp.h>
++
++volatile static PCKC pCKC = (volatile PCKC)tcc_p2v(HwCLK_BASE);
++volatile static unsigned int bCLK0CTRL;
++volatile unsigned int idle_expired;
++
++inline void tcc_idle(void)
++{
++ idle_expired = 1;
++ local_irq_enable();
++ bCLK0CTRL = pCKC->CLK0CTRL;
++ pCKC->CLK0CTRL |= (Hw20|0xFF00);
++ while (idle_expired);
++ pCKC->CLK0CTRL = bCLK0CTRL;
++ local_irq_disable();
++}
++
++inline void arch_idle_off(void)
++{
++ idle_expired = 0;
++}
++
++/* end of file */
+diff --git a/arch/arm/mach-tcc8900/include/bsp.h b/arch/arm/mach-tcc8900/include/bsp.h
+new file mode 100644
+index 0000000..7b3fe3b
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/bsp.h
+@@ -0,0 +1,62 @@
++/****************************************************************************
++* FileName : bsp.h
++* Description :
++****************************************************************************
++*
++* TCC Version : 1.0
++* Copyright (c) Telechips, Inc.
++* ALL RIGHTS RESERVED
++*
++****************************************************************************/
++
++#ifndef __BSP_H__
++#define __BSP_H__
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#if defined(_LINUX_)
++#ifndef VOLATILE
++#define VOLATILE
++#endif
++#include <mach/reg_physical.h>
++#include <mach/bsp_cfg.h>
++#include <mach/globals.h>
++#include <mach/tca_ckc.h>
++#include <linux/tcc_pwm.h>
++#include <linux/tcc_ll.h>
++#else
++
++#ifndef VOLATILE
++#define VOLATILE volatile
++#endif
++
++//system os header file
++#include <system_type.h>
++
++//argument structur and define file
++#include <args.h>
++
++//globals macro, defines file
++#include <globals.h>
++
++//bsp option config file
++#include <bsp_cfg.h>
++
++//Physical Base address file
++#include <reg_physical.h>
++
++//Kernel Ioctl
++#include <ioctl_code.h>
++#include <ioctl_ckcstr.h>
++#include <ioctl_gpiostr.h>
++#include <ioctl_pwrstr.h>
++#endif
++
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif // __BSP_H__
+diff --git a/arch/arm/mach-tcc8900/include/hhtech_gpio.h b/arch/arm/mach-tcc8900/include/hhtech_gpio.h
+new file mode 100644
+index 0000000..c14cf19
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/hhtech_gpio.h
+@@ -0,0 +1,77 @@
++/****************************************************************
++ * $ID: hhtech_gpio.h 三, 18 2月 2009 10:16:56 +0800 wk $ *
++ * *
++ * Description: *
++ * *
++ * Maintainer: wk@hhcn.com *
++ * *
++ * CopyRight (c) 2009 HHTech *
++ * www.hhcn.com, www.hhcn.org *
++ * All rights reserved. *
++ * *
++ * This file is free software; *
++ * you are free to modify and/or redistribute it *
++ * under the terms of the GNU General Public Licence (GPL). *
++ * *
++ * Last modified: 二, 08 12月 2009 19:02:55 +0800 by duanius #
++ ****************************************************************/
++
++#ifndef __HHTECH_GPIO_H
++#define __HHTECH_GPIO_H
++
++/*======================================================================
++ * GPIO
++ */
++
++//SD
++#define GPIO_SD_WP TCC_GPF12 /* SD write protect detect, 1:protected */
++#define GPIO_SD_DETE TCC_GPF13 /* SD insert detect, 0:inserted */
++
++//USB
++#if defined(CONFIG_LCD_4)
++#define GPIO_USB_HOSTPWR_EN TCC_GPF25 /* USB Host drv Enable 1:open 0:off */
++#else
++#define GPIO_USB_HOSTPWR_EN TCC_GPA2 /* USB Host drv Enable 1:open 0:off */
++#endif
++#define GPIO_USB_EN TCC_GPA15 /* USB Improving voltage Enable, 1:open 0:off */
++#define GPIO_USB_OTGDRV_EN TCC_GPA12 /* USB otg drv Enable, 1:open 0:off */
++
++//Headphone and Speaker
++#define GPIO_HEADPHONE_S TCC_GPD7 /* Headphone insert detect, 0:inserted */
++#define GPIO_SPEAKER_EN TCC_GPD8 /* Speaker Enable 0:off 1:open */
++
++//Charging
++#define GPIO_DC_DETE TCC_GPF8 /* DC insert Detect, 0:inserted */
++#define GPIO_CHARG_S1 TCC_GPF1 /* Charging status 1,*/
++#define GPIO_CHARG_S2 TCC_GPF2 /* Charging status 2,*/
++#define GPIO_CHARGER_EN TCC_GPF0 /* Quick charging mode enable, 1:open */
++
++//System Power
++#define GPIO_PWR_EN TCC_GPF6 /* System power control, 0:off 1:open */
++#define GPIO_PWR_HOLD TCC_GPF10 /* System power detect, 0:detected */
++
++//TVOUT
++#define GPIO_TVOUT_EN TCC_GPD9 /* Video TVOUT control, 1:open */
++
++//Wifi
++#define GPIO_WIFI_EN TCC_GPB15 /* Wifi power control, 1:on */
++
++//HDMI
++#define GPIO_HDMI_EN TCC_GPF25 /* HDMI power control, 1:on */
++#define GPIO_HDMIPWR_EN TCC_GPF4
++#define GPIO_HDMI_HPD TCC_GPA14 /* HDMI line insert Detect, 1:inserted */
++
++//LED
++#if defined(CONFIG_LCD_4)
++#define GPIO_LED1_EN TCC_GPE6 /* Green LED, 0:on */
++#define GPIO_LED2_EN TCC_GPE7 /* Red LED, 0:on */
++#else
++#define GPIO_LED1_EN TCC_GPE7 /* Green LED, 0:on */
++#define GPIO_LED2_EN TCC_GPE6 /* Red LED, 0:on */
++#endif
++
++//LCD
++#define GPIO_LCD_BACKLIGHT_EN TCC_GPA5 /* LCD backlight control, 1:on */
++#define GPIO_LCD_PWR_EN TCC_GPA4 /* LCD power control, 1:on */
++#endif
++
+diff --git a/arch/arm/mach-tcc8900/include/mach/TCC89x_Physical.h b/arch/arm/mach-tcc8900/include/mach/TCC89x_Physical.h
+new file mode 100644
+index 0000000..496a801
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/TCC89x_Physical.h
+@@ -0,0 +1,1164 @@
++/****************************************************************************
++ * FileName : TCC89x_Physical.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++/****************************************************************************
++
++ Revision History
++
++ ****************************************************************************
++
++ ****************************************************************************/
++
++/************************************************************************
++* TCC89x Internal Register Definition File
++************************************************************************/
++#ifndef __TCC89x_H__
++#define __TCC89x_H__
++
++
++/************************************************************************
++* Bit Field Definition
++************************************************************************/
++#define Hw37 (1LL << 37)
++#define Hw36 (1LL << 36)
++#define Hw35 (1LL << 35)
++#define Hw34 (1LL << 34)
++#define Hw33 (1LL << 33)
++#define Hw32 (1LL << 32)
++#define Hw31 0x80000000
++#define Hw30 0x40000000
++#define Hw29 0x20000000
++#define Hw28 0x10000000
++#define Hw27 0x08000000
++#define Hw26 0x04000000
++#define Hw25 0x02000000
++#define Hw24 0x01000000
++#define Hw23 0x00800000
++#define Hw22 0x00400000
++#define Hw21 0x00200000
++#define Hw20 0x00100000
++#define Hw19 0x00080000
++#define Hw18 0x00040000
++#define Hw17 0x00020000
++#define Hw16 0x00010000
++#define Hw15 0x00008000
++#define Hw14 0x00004000
++#define Hw13 0x00002000
++#define Hw12 0x00001000
++#define Hw11 0x00000800
++#define Hw10 0x00000400
++#define Hw9 0x00000200
++#define Hw8 0x00000100
++#define Hw7 0x00000080
++#define Hw6 0x00000040
++#define Hw5 0x00000020
++#define Hw4 0x00000010
++#define Hw3 0x00000008
++#define Hw2 0x00000004
++#define Hw1 0x00000002
++#define Hw0 0x00000001
++#define HwZERO 0x00000000
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 2 SMU & PMU_V0.00 Dec.11 2008
++********************************************************************************/
++/************************************************************************
++* 1. Clock Controller Register Define (Base Addr = 0xF0400000) // R/W
++************************************************************************/
++//---------------------------------------------------------------------------------------------
++//31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
++// |CFGEN|MODE | NCKOE/DPRD |
++//15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
++// NCKOE/DMIN | NCKOE/DMAX | NCKOE/DCDIV | | CKSEL |
++//----------------------------------------------------------------------------------------------
++#define HwCLK_BASE *(volatile unsigned long *)0xF0400000
++#define HwCKC ((PCKC)&HwCLK_BASE)
++
++/************************************************************************
++* 2. Vectored Priority Interrupt Controller Register Map(Base Addr = 0xF0401000)
++************************************************************************/
++#define HwPIC_BASE *(volatile unsigned long *)0xF0401000
++#define HwVIC_BASE *(volatile unsigned long *)0xF0401200
++#define HwPIC ((PPIC)&HwPIC_BASE)
++#define HwVIC ((PVIC)&HwVIC_BASE)
++
++
++// Interrupt Enable 0
++#define HwINT0_EHI0 Hw31 // R/W, External Host Interface0 Interrupt Enable
++#define HwINT0_ECC Hw30 // R/W, ECC Interrupt Enable
++#define HwINT0_DMA Hw29 // R/W, DMA Controller Interrupt Enable
++#define HwINT0_TSADC Hw28 // R/W, TSADC Interrupt Enable
++#define HwINT0_G2D Hw27 // R/W, Graphic Engine 2D Hardware Interrupt Enable
++#define HwINT0_3DMMU Hw26 // R/W, 3D MMU Interrupt Enable
++#define HwINT0_3DGP Hw25 // R/W, 3D Geometary Interrupt Enable
++#define HwINT0_3DPP Hw24 // R/W, 3D Pixel Processor Interrupt Enable
++#define HwINT0_VCDC Hw23 // R/W, Video CODEC Interrupt Enable
++#define HwINT0_JPGD Hw22 // R/W, JPEG Decoder Interrupt Enable
++#define HwINT0_JPGE Hw21 // R/W, JPEG Encoder Interrupt Enable
++#define HwINT0_VIPET Hw20 // R/W, VIPET Controller Interrupt Enable
++#define HwINT0_LCD1 Hw19 // R/W, LCD Controller1 Interrupt Enable
++#define HwINT0_LCD0 Hw18 // R/W, LCD Controller0 Interrupt Enable
++#define HwINT0_CAM Hw17 // R/W, Camera Interrupt Enable
++#define HwINT0_SC1 Hw16 // R/W, Mem-to-Mem Scaler1 Interrupt Enable
++#define HwINT0_SC0 Hw15 // R/W, Mem-to-Mem Scaler0 Interrupt Enable
++#define HwINT0_EI11 Hw14 // R/W, External Interrupt11 Enable
++#define HwINT0_EI10 Hw13 // R/W, External Interrupt10 Enable
++#define HwINT0_EI9 Hw12 // R/W, External Interrupt9 Enable
++#define HwINT0_EI8 Hw11 // R/W, External Interrupt8 Enable
++#define HwINT0_EI7 Hw10 // R/W, External Interrupt7 Enable
++#define HwINT0_EI6 Hw9 // R/W, External Interrupt6 Enable
++#define HwINT0_EI5 Hw8 // R/W, External Interrupt5 Enable
++#define HwINT0_EI4 Hw7 // R/W, External Interrupt4 Enable
++#define HwINT0_EI3 Hw6 // R/W, External Interrupt3 Enable
++#define HwINT0_EI2 Hw5 // R/W, External Interrupt2 Enable
++#define HwINT0_EI1 Hw4 // R/W, External Interrupt1 Enable
++#define HwINT0_EI0 Hw3 // R/W, External Interrupt0 Enable
++#define HwINT0_SMUI2C Hw2 // R/W, SMU_I2C Interrupt Enable
++#define HwINT0_TC1 Hw1 // R/W, Timer1 Interrupt Enable
++#define HwINT0_TC0 Hw0 // R/W, Timer0 Interrupt Enable
++
++// Interrupt Enable 1
++#define HwINT1_AEIRQ Hw31 // R/W, Not maskable error ARM DMA interrupt enable
++#define HwINT1_ASIRQ Hw30 // R/W, Secure ARM DMA select interrupt enable
++#define HwINT1_AIRQ Hw29 // R/W, Non secure ARM DMA interrupt enable
++#define HwINT1_APMU Hw28 // R/W, ARM System Metrics interrupt enable
++#define HwINT1_AUDIO Hw27 // R/W, AUDIO interrupt enable
++#define HwINT1_ADMA Hw26 // R/W, AUDIO DMA interrupt enable
++#define HwINT1_DAITX Hw25 // R/W, DAI transmit interrupt enable
++#define HwINT1_DAIRX Hw24 // R/W, DAI receive interrupt enable
++#define HwINT1_CDRX Hw23 // R/W, CDIF receive interrupt enable
++#define HwINT1_TSIF1 Hw22 // R/W, TS interface 1 interrupt enable
++#define HwINT1_TSIF0 Hw21 // R/W, TS interface 0 interrupt enable
++#define HwINT1_GPS2 Hw20 // R/W, GPS AGPS interrupt enable
++#define HwINT1_GPS1 Hw19 // R/W, GPS TCXO expired interrupt enable
++#define HwINT1_GPS0 Hw18 // R/W, GPS RTC expired interrupt enable
++#define HwINT1_NotUsed Hw17 // R/W, Reserved
++#define HwINT1_UOTG Hw16 // R/W, USB 2.0 OTG interrupt enable
++#define HwINT1_UART Hw15 // R/W, UART interrupt enable
++#define HwINT1_SPDTX Hw14 // R/W, SPDIF transmitter interrupt enable
++#define HwINT1_SD1 Hw13 // R/W, SD/MMC 1 interrupt enable
++#define HwINT1_SD0 Hw12 // R/W, SD/MMC 0 interrupt enable
++#define HwINT1_RTC Hw11 // R/W, RTC interrupt enable
++#define HwINT1_RMT Hw10 // R/W, Remote Control interrupt enable
++#define HwINT1_NFC Hw9 // R/W, Nand flash controller interrupt enable
++#define HwINT1_MS Hw8 // R/W, Memory Stick interrupt enable
++#define HwINT1_MPEFEC Hw7 // R/W, MPEFEC interrupt enable
++#define HwINT1_I2C Hw6 // R/W, I2C interrupt enable
++#define HwINT1_HDD Hw5 // R/W, HDD controller interrupt enable
++#define HwINT1_GPSB Hw4 // R/W, GPSB Interrupt Enable
++#define HwINT1_NotUsed1 Hw3 // R/W, Reserved
++#define HwINT1_HDMI Hw2 // R/W, HDMI interrupt enable
++#define HwINT1_NotUsed2 Hw1 // R/W, Reserved
++#define HwINT1_EHI1 Hw0 // R/W, External Host Interface1 Interrupt Enable
++
++#define HwALLMSK_FIQ Hw1 // FIQ mask register
++#define HwALLMSK_IRQ Hw0 // IRQ mask register
++
++/***********************************************************************
++* 3. Timer/Counter Register Map (Base Address = 0xF0403000)
++************************************************************************/
++#define HwTMR_BASE *(volatile unsigned long *)0xF0403000 // Timer/Counter Base Register
++
++/***********************************************************************
++* 4. PMU(POWER MANAGEMENT UNIT) Register Map (Base Address = 0xF0404000)
++************************************************************************/
++#define HwPMU_BASE *(volatile unsigned long *)0xF0404000 //R/W PMU Control Register
++
++/*******************************************************************************
++* 5. SMUI2C Controller Register Define (Base Addr = 0xF0405000)
++********************************************************************************/
++#define HwSMU_I2CMASTER0_BASE *(volatile unsigned long *)0xF0405000
++#define HwSMU_I2CMASTER1_BASE *(volatile unsigned long *)0xF0405040
++#define HwSMU_I2CICLK_BASE *(volatile unsigned long *)0xF0405080 //I2C_SCL divider Regist
++#define HwI2CSTATUS_BASE *(volatile unsigned long *)0xF05300C0
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 3 GPIO_V0.00 Dec.11 2008
++********************************************************************************/
++/************************************************************************
++* 1. GPIO Register Map (Base Address = 0xF0102000)
++************************************************************************/
++#define HwGPIO_BASE *(volatile unsigned long *)0xF0102000 //
++#define HwGPIOA_BASE *(volatile unsigned long *)0xF0102000 //
++#define HwGPIOB_BASE *(volatile unsigned long *)0xF0102040 //
++#define HwGPIOC_BASE *(volatile unsigned long *)0xF0102080 //
++#define HwGPIOD_BASE *(volatile unsigned long *)0xF01020C0 //
++#define HwGPIOE_BASE *(volatile unsigned long *)0xF0102100 //
++#define HwGPIOF_BASE *(volatile unsigned long *)0xF0102140 //
++#define HwEINTSEL_BASE *(volatile unsigned long *)0xF0102180 //
++#define HwGPIO ((PGPIO)&HwGPIO_BASE)
++#define HwGPIOA ((PGPION)&HwGPIOA_BASE)
++#define HwGPIOB ((PGPION)&HwGPIOB_BASE)
++#define HwGPIOC ((PGPION)&HwGPIOC_BASE)
++#define HwGPIOD ((PGPION)&HwGPIOD_BASE)
++#define HwGPIOE ((PGPION)&HwGPIOE_BASE)
++#define HwGPIOF ((PGPION)&HwGPIOF_BASE)
++#define HwEINTSEL ((PGPIOINT)&HwEINTSEL_BASE)
++
++#define HwPORTCFG_GPFN0(X) ((X)<<0) // 0~3
++#define HwPORTCFG_GPFN0_MASK (0xF) // HwPORTCFG_GPFN0(15)
++#define HwPORTCFG_GPFN1(X) ((X)<<4) // 4~7
++#define HwPORTCFG_GPFN1_MASK (0xF<<4) // HwPORTCFG_GPFN1(15)
++#define HwPORTCFG_GPFN2(X) ((X)<<8) // 8~11
++#define HwPORTCFG_GPFN2_MASK (0xF<<8) // HwPORTCFG_GPFN2(15)
++#define HwPORTCFG_GPFN3(X) ((X)<<12) // 12~15
++#define HwPORTCFG_GPFN3_MASK (0xF<<12) // HwPORTCFG_GPFN3(15)
++#define HwPORTCFG_GPFN4(X) ((X)<<16) // 16~19
++#define HwPORTCFG_GPFN4_MASK (0xF<<16) // HwPORTCFG_GPFN4(15)
++#define HwPORTCFG_GPFN5(X) ((X)<<20) // 20~23
++#define HwPORTCFG_GPFN5_MASK (0xF<<20) // HwPORTCFG_GPFN5(15)
++#define HwPORTCFG_GPFN6(X) ((X)<<24) // 24~27
++#define HwPORTCFG_GPFN6_MASK (0xF<<24) // HwPORTCFG_GPFN6(15)
++#define HwPORTCFG_GPFN7(X) ((X)<<28) // 28~31
++#define HwPORTCFG_GPFN7_MASK (0xF<<28) // HwPORTCFG_GPFN7(15)
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 4 CORE & MEMORY BUS_V0.00 Dec.11 2008
++********************************************************************************/
++/************************************************************************
++* 3. DRAM CONTROLLER Register Map (Base Address = 0xF0301000)
++************************************************************************/
++#define HwDRAM_BASE *(volatile unsigned long *)0xF0301000 //
++#define HwDRAMM0_BASE *(volatile unsigned long *)0xF0301000 //
++#define HwDRAMM1_BASE *(volatile unsigned long *)0xF0302000 //
++#define HwDRAMMISC_BASE *(volatile unsigned long *)0xF0303000 //
++#define HwDRAMPHY_BASE *(volatile unsigned long *)0xF0304400 //
++#define HwDRAMMEMBUS_BASE *(volatile unsigned long *)0xF0305004 //
++
++/************************************************************************
++* 4-1. MISC CORE BUS CONFIGURATION REGISTERS (Base Addr = 0xF0101000)
++************************************************************************/
++#define HwCORECFG_BASE *(volatile unsigned long *)0xF0101000
++
++/************************************************************************
++* 4-2. Virtual MMU Table Register Define (Base Addr = 0xF7000000)
++************************************************************************/
++#define HwVMT_BASE *(volatile unsigned long *)0x20000000 // VMT Base Regiseter
++#define HwREGION_BASE *(volatile unsigned long *)0xF0600000 // R/W, Configuration Register for Region 0
++
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 5 IO BUS_V0.00 Dec.11 2008
++********************************************************************************/
++/*******************************************************************************
++* 4. Memory Stick Host Controller Register Define (Base Addr = 0xF0590000)
++********************************************************************************/
++#define HwSMSHC_BASE *(volatile unsigned long *)0xF0590000
++#define HwPORTCFG_BASE *(volatile unsigned long *)0xF05F1000
++
++/********************************************************************************
++* 5. SD/SDIO/MMC/CE-ATA Host Controller Register Define (Base Addr = 0xF05A0000)
++********************************************************************************/
++#define HwSDCORE0SLOT0_BASE *(volatile unsigned long *)0xF05A0000 // Core 0 Slot 0
++#define HwSDCORE0SLOT1_BASE *(volatile unsigned long *)0xF05A0100 // Core 0 Slot 1
++#define HwSDCORE1SLOT2_BASE *(volatile unsigned long *)0xF05A0200 // Core 1 Slot 2
++#define HwSDCORE1SLOT3_BASE *(volatile unsigned long *)0xF05A0300 // Core 1 Slot 3
++
++// Channel Control Register
++#define HwSDCHCTRL_BASE *(volatile unsigned long *)0xF05A0800 // R/W 0x0000 SD/MMC port control register
++
++/*******************************************************************************
++* 6. NAND Flash Controller(NFC) Register Define (Base Addr = 0xF05B0000)
++********************************************************************************/
++#define HwNFC_BASE *(volatile unsigned long *)0xF05B0000
++#define HwNFC ((PNFC)&HwNFC_BASE)
++
++// NFC Control Register
++#define HwNFC_CTRL_RDYIEN_EN Hw31 // Nand Flash Ready Interrupt Enable
++#define HwNFC_CTRL_RDYIEN_DIS ~Hw31 // Nand Flash Ready Interrupt Disable
++#define HwNFC_CTRL_PROGIEN_EN Hw30 // Nand Flash Program Interrupt Enable
++#define HwNFC_CTRL_PROGIEN_DIS ~Hw30 // Nand Flash Program Interrupt Disable
++#define HwNFC_CTRL_READIEN_EN Hw29 // Nand Flash Read Interrupt Enable
++#define HwNFC_CTRL_READIEN_DIS ~Hw29 // Nand Flash Read Interrupt Disable
++#define HwNFC_CTRL_DEN_EN Hw28 // Nand Flash DMA Request Enable
++#define HwNFC_CTRL_DEN_DIS ~Hw28 // Nand Flash DMA Request Disable
++#define HwNFC_CTRL_FS_RDY Hw27 // FIFO status is Ready to write and read in FIFO
++#define HwNFC_CTRL_FS_BUSY ~Hw27 // FIFO status is Busy to write and read in FIFO
++#define HwNFC_CTRL_BW_16 Hw26 // Bus width = 8bit
++#define HwNFC_CTRL_BW_8 HwZERO // Bus width = 16bit
++#define HwNFC_CTRL_CS3SEL_1 Hw25 // Nand Flash nCS3 is High (Disabled)
++#define HwNFC_CTRL_CS3SEL_0 HwZERO // Nand Flash nCS3 is Low (Enabled)
++#define HwNFC_CTRL_CS2SEL_1 Hw24 // Nand Flash nCS2 is High (Disabled)
++#define HwNFC_CTRL_CS2SEL_0 HwZERO // Nand Flash nCS2 is Low (Enabled)
++#define HwNFC_CTRL_CS1SEL_1 Hw23 // Nand Flash nCS1 is High (Disabled)
++#define HwNFC_CTRL_CS1SEL_0 HwZERO // Nand Flash nCS1 is Low (Enabled)
++#define HwNFC_CTRL_CS0SEL_1 Hw22 // Nand Flash nCS0 is High (Disabled)
++#define HwNFC_CTRL_CS0SEL_0 HwZERO // Nand Flash nCS0 is Low (Enabled)
++#define HwNFC_CTRL_CFG_nCS3 HwNFC_CTRL_CS3SEL_1
++#define HwNFC_CTRL_CFG_nCS2 HwNFC_CTRL_CS2SEL_1
++#define HwNFC_CTRL_CFG_nCS1 HwNFC_CTRL_CS1SEL_1
++#define HwNFC_CTRL_CFG_nCS0 HwNFC_CTRL_CS0SEL_1
++#define HwNFC_CTRL_CSnSEL(X) ((X)*Hw22) // Nand Flash nCS[3:0] Set
++#define HwNFC_CTRL_CFG_NOACT HwNFC_CTRL_CSnSEL(15)
++#define HwNFC_CTRL_RDY_RDY Hw21 // External Nand Flash Controller is Ready
++#define HwNFC_CTRL_RDY_BUSY ~Hw21 // External Nand Flash Controller is Busy
++#define HwNFC_CTRL_BSIZE(X) ((X)*Hw19)
++#define HwNFC_CTRL_BSIZE_1 HwNFC_CTRL_BSIZE(0) // 1Read/Write
++#define HwNFC_CTRL_BSIZE_2 HwNFC_CTRL_BSIZE(1) // 2Read/Write
++#define HwNFC_CTRL_BSIZE_4 HwNFC_CTRL_BSIZE(2) // 4Read/Write
++#define HwNFC_CTRL_BSIZE_8 HwNFC_CTRL_BSIZE(3) // 8Read/Write
++#define HwNFC_CTRL_BSIZE_MASK HwNFC_CTRL_BSIZE(3)
++#define HwNFC_CTRL_PSIZE(X) ((X)*Hw16)
++#define HwNFC_CTRL_PSIZE_256 HwNFC_CTRL_PSIZE(0) // 1 Page = 256 Half-Word
++#define HwNFC_CTRL_PSIZE_512 HwNFC_CTRL_PSIZE(1) // 1 Page = 512 Byte
++#define HwNFC_CTRL_PSIZE_1024 HwNFC_CTRL_PSIZE(2) // 1 Page = 1024 Half-Word
++#define HwNFC_CTRL_PSIZE_2048 HwNFC_CTRL_PSIZE(3) // 1 Page = 2048 Byte
++#define HwNFC_CTRL_PSIZE_4096 HwNFC_CTRL_PSIZE(4) // 1 Page = 4096 Byte
++#define HwNFC_CTRL_PSIZE_MASK HwNFC_CTRL_PSIZE(7)
++#define HwNFC_CTRL_MASK_EN Hw15 // Address/Command Mask Enable
++#define HwNFC_CTRL_CADDR Hw12 // Number of Address Cycle
++#define HwNFC_CTRL_bSTP(X) ((X)*Hw8) // Number of Base cycle for Setup Time
++#define HwNFC_CTRL_bSTP_MASK HwNFC_CTRL_bSTP(15)
++#define HwNFC_CTRL_bPW(X) ((X)*Hw4) // Number of Base cycle for Pulse Width
++#define HwNFC_CTRL_bPW_MASK HwNFC_CTRL_bPW(15)
++#define HwNFC_CTRL_bHLD(X) ((X)*Hw0) // Number of Base cycle for Hold Time
++#define HwNFC_CTRL_bHLD_MASK HwNFC_CTRL_bHLD(15)
++
++#define HwNFC_IREQ_FLAG2 Hw6 //
++#define HwNFC_IREQ_FLAG1 Hw5 //
++#define HwNFC_IREQ_FLAG0 Hw4 //
++#define HwNFC_IREQ_IRQ2 Hw2 // Ready Interrupt
++#define HwNFC_IREQ_IRQ1 Hw1 // Program Interrupt
++#define HwNFC_IREQ_IRQ0 Hw0 // Reading Interrupt
++
++/*******************************************************************************
++* 7. Static Memory Controller(SMC) Register Define (Base Addr = 0xF05F0000)
++********************************************************************************/
++#define HwSMC_BASE *(volatile unsigned long *)0xF05F0000
++#define HwSMC_STATUS *(volatile unsigned long *)0xF05F0000 // R/W Unknown Status Register
++#define HwSMC_CSNCFG0 *(volatile unsigned long *)0xF05F0020 // R 0x4b40_3183 External Chip Select0 Config Register
++#define HwSMC_CSNCFG1 *(volatile unsigned long *)0xF05F0024 // R/W 0x4b40_1104 External Chip Select1 Config Register
++#define HwSMC_CSNCFG2 *(volatile unsigned long *)0xF05F0028 // W 0x4b40_4082 External Chip Select2 Config Register
++#define HwSMC_CSNCFG3 *(volatile unsigned long *)0xF05F002C // R/W 0x4b40_20C5 External Chip Select3 Config. Register
++#define HwSMC_CSNOFFSET *(volatile unsigned long *)0xF05F0030 // R/W 0x0 Wapping Address Mode OFFSET Register
++#define HwSMC_INDIRADDR *(volatile unsigned long *)0xF05F0034 // R/W 0x0 Indirect Address
++
++/*******************************************************************************
++* 8. External Device Interface (EDI) Register Define (Base Addr = 0xF05F6000)
++********************************************************************************/
++#define HwEDI_BASE *(volatile unsigned long *)0xF05F6000
++#define HwEDI ((PEDI)&HwEDI_BASE)
++
++/*******************************************************************************
++* 9. IDE Controller Register Define (Base Addr = 0xF0520000)
++********************************************************************************/
++#define HwIDE_BASE *(volatile unsigned long *)0xF0520000
++
++/*******************************************************************************
++* 10. SATA Interface Register Define (Base Addr = 0xF0560000)
++********************************************************************************/
++#define HwSATA_BASE *(volatile unsigned long *)0xF0560000
++//SCR5-SCR15 0x38-0x60 32 See description 0x0 Reserved for SATA Dependencies: Reads to these locations return zeros; writes have no effect
++
++/*******************************************************************************
++* 11-1. Audio DMA Controller Register Define (Base Addr = 0xF0533000)
++********************************************************************************/
++#define HwADMA_BASE *(volatile unsigned long *)0xF0533000
++
++/*******************************************************************************
++* 11-2. DAI Register Define (Base Addr = 0xF0534000)
++********************************************************************************/
++#define HwADMA_DAIBASE *(volatile unsigned long *)0xF0534000
++
++/*******************************************************************************
++* 11-3. CDIF Register Define (Base Addr = 0xF0534000)
++********************************************************************************/
++#define HwADMA_CDIFBASE *(volatile unsigned long *)0xF0534080
++
++/*******************************************************************************
++* 11-4. SPDIF Register Define (Base Addr = 0xF0535000/0xF0535800)
++********************************************************************************/
++#define HwADMA_SPDIFTXBASE *(volatile unsigned long *)0xF0535000
++
++/*******************************************************************************
++* 12-1. DAI Register Define (Base Addr = 0xF0537000
++********************************************************************************/
++#define HwDAI_BASE *(volatile unsigned long *)0xF0537000
++
++/*******************************************************************************
++* 12-2. CDIF Register Define (Base Addr = 0xF0537000
++********************************************************************************/
++#define HwCDIF_BASE *(volatile unsigned long *)0xF0537080
++
++/*******************************************************************************
++* 13. SPDIF Register Define (Base Addr = 0xF0538000)
++********************************************************************************/
++#define HwSPDIF_BASE *(volatile unsigned long *)0xF0538000
++
++/*******************************************************************************
++* 14-1. USB1.1 HOST Controller & Transceiver (Base Addr = 0xF0500000)
++********************************************************************************/
++#define HwUSBHOST_BASE *(volatile unsigned long *)0xF0500000
++
++/*******************************************************************************
++* 14-2 USB1.1 HOST Configuration Register (Base Addr = 0xF05F5000)
++********************************************************************************/
++#define HwUSBHOSTCFG_BASE *(volatile unsigned long *)0xF05F5000
++
++/*******************************************************************************
++* 15-1. USB2.0 OTG Controller Define (Base Addr = 0xF0550000)
++********************************************************************************/
++#define HwUSB20OTG_BASE *(volatile unsigned long *)0xF0550000
++
++/*******************************************************************************
++* 15-2. USB OTG Configuration Register Define (Base Addr = 0xF05F5000)
++********************************************************************************/
++#define HwUSBOTGCFG_BASE *(volatile unsigned long *)0xF05F5000
++
++/*******************************************************************************
++* 15-3. USB PHY Configuration Register Define (Base Addr = 0xF05F5028)
++********************************************************************************/
++#define HwUSBPHYCFG_BASE *(volatile unsigned long *)0xF05F5028
++
++/*******************************************************************************
++* 16. External Host Interface Register Define (Base Addr = 0xF0570000/0xF0580000)
++********************************************************************************/
++#define HwEHICS0_BASE *(volatile unsigned long *)0xF0570000
++#define HwEHICS1_BASE *(volatile unsigned long *)0xF0580000
++
++/*******************************************************************************
++* 17. General Purpose Serial Bus (GPSB) Register Define (Base Addr = 0xF0538000)
++********************************************************************************/
++#if 0
++#define HwGPSBCH0_BASE *(volatile unsigned long *)0xF0057000
++#define HwGPSBCH1_BASE *(volatile unsigned long *)0xF0057100
++#define HwGPSBCH2_BASE *(volatile unsigned long *)0xF0057200
++#define HwGPSBCH3_BASE *(volatile unsigned long *)0xF0057300
++#define HwGPSBCH4_BASE *(volatile unsigned long *)0xF0057400
++#define HwGPSBCH5_BASE *(volatile unsigned long *)0xF0057500
++#define HwGPSBPORTCFG_BASE *(volatile unsigned long *)0xF0057800
++#define HwGPSBPIDTABLE_BASE *(volatile unsigned long *)0xF0057F00
++
++#define HwGPSB_PIDT(X) *(volatile unsigned long *)(0xF0057F00+(X)*4) // R/W, PID Table Register
++#define HwGPSB_PIDT_CH2 Hw31 // Channel 2 enable
++#define HwGPSB_PIDT_CH1 Hw30 // Channel 1 enable
++#define HwGPSB_PIDT_CH0 Hw29 // Channel 0 enable
++#else
++#define HwGPSBCH0_BASE *(volatile unsigned long *)0xF0536000
++#define HwGPSBCH1_BASE *(volatile unsigned long *)0xF0536100
++#define HwGPSBCH2_BASE *(volatile unsigned long *)0xF0536200
++#define HwGPSBCH3_BASE *(volatile unsigned long *)0xF0536300
++#define HwGPSBCH4_BASE *(volatile unsigned long *)0xF0536400
++#define HwGPSBCH5_BASE *(volatile unsigned long *)0xF0536500
++#define HwGPSBPORTCFG_BASE *(volatile unsigned long *)0xF0536800
++#define HwGPSBPIDTABLE_BASE *(volatile unsigned long *)0xF0536F00
++
++#define HwGPSB_PIDT(X) *(volatile unsigned long *)(0xF0536F00+(X)*4) // R/W, PID Table Register
++#define HwGPSB_PIDT_CH2 Hw31 // Channel 2 enable
++#define HwGPSB_PIDT_CH1 Hw30 // Channel 1 enable
++#define HwGPSB_PIDT_CH0 Hw29 // Channel 0 enable
++#endif
++
++/*******************************************************************************
++* 18. The Transport Stream Interface (TSIF) Register Define (Base Addr = 0xF0538000)
++********************************************************************************/
++#define HwTSIF_BASE *(volatile unsigned long *)0xF053B000
++#define HwTSIFPORTSEL_BASE *(volatile unsigned long *)0xF053B800
++
++/*******************************************************************************
++* 19. GPS Interface Register Define (Base Addr = )
++********************************************************************************/
++
++
++/*******************************************************************************
++* 20. Remote Control Interface Register Define (Base Addr = 0xF05F3000)
++********************************************************************************/
++#define HwREMOCON_BASE *(volatile unsigned long *)0xF05F3000
++
++
++/*******************************************************************************
++* 21. I2C Controller Register Define (Base Addr = 0xF0530000)
++********************************************************************************/
++#define HwI2CMASTER0_BASE *(volatile unsigned long *)0xF0530000
++#define HwI2CMASTER1_BASE *(volatile unsigned long *)0xF0530040
++#define HwI2CSLAVE_BASE *(volatile unsigned long *)0xF0530080
++#define HwI2CSTATUS_BASE *(volatile unsigned long *)0xF05300C0
++
++#define HwI2CMASTER0 ((PSMUI2CMASTER)&HwI2CMASTER0_BASE)
++#define HwI2CMASTER1 ((PSMUI2CMASTER)&HwI2CMASTER1_BASE)
++
++/*******************************************************************************
++* 22. UART Controller Register Define (Base Addr = 0xF0538000)
++********************************************************************************/
++#define HwUARTCH0_BASE *(volatile unsigned long *)0xF0532000
++#define HwUARTCH1_BASE *(volatile unsigned long *)0xF0532100
++#define HwUARTCH2_BASE *(volatile unsigned long *)0xF0532200
++#define HwUARTCH3_BASE *(volatile unsigned long *)0xF0532300
++#define HwUARTCH4_BASE *(volatile unsigned long *)0xF0532400
++#define HwUARTCH5_BASE *(volatile unsigned long *)0xF0532500
++#define HwUARTPORTMUX_BASE *(volatile unsigned long *)0xF0532600
++
++/*******************************************************************************
++* 23. CAN Controller Register Define (Base Addr = 0xF0531000)
++********************************************************************************/
++#define HwCAN_BASE *(volatile unsigned long *)0xF0531000
++
++/*******************************************************************************
++* 24. DMA Controller Register Define (Base Addr = 0xF0540000)
++********************************************************************************/
++#define HwGDMA0_BASE *(volatile unsigned long *)0xF0540000
++#define HwGDMA1_BASE *(volatile unsigned long *)0xF0540100
++#define HwGDMA2_BASE *(volatile unsigned long *)0xF0540200
++#define HwGDMA3_BASE *(volatile unsigned long *)0xF0540300
++
++/*******************************************************************************
++* 25. Real Time Clock(RTC) Register Define (Base Addr = 0xF05F2000)
++********************************************************************************/
++#define HwRTC_BASE *(volatile unsigned long *)0xF05F2000
++
++/*******************************************************************************
++* 26. TouchScreen ADC (TSADC) Register Define (Base Addr = 0xF05F4000)
++********************************************************************************/
++#define HwTSADC_BASE *(volatile unsigned long *)0xF05F4000
++
++/*******************************************************************************
++* 27. Error Correction Code Register Define (Base Addr = 0xF0539000)
++********************************************************************************/
++#define HwECC_BASE *(volatile unsigned long *)0xF0539000
++
++// ECC Control
++#define HwECC_CTRL_IEN_MECC16_EN Hw20 // MLC ECC16 Decoding Interrupt Enable
++#define HwECC_CTRL_IEN_MECC16_DIS ~Hw20 // MLC ECC16 Decoding Interrupt Disable
++#define HwECC_CTRL_IEN_MECC14_EN Hw19 // MLC ECC14 Decoding Interrupt Enable
++#define HwECC_CTRL_IEN_MECC14_DIS ~Hw19 // MLC ECC14 Decoding Interrupt Disable
++#define HwECC_CTRL_IEN_MECC12_EN Hw18 // MLC ECC12 Decoding Interrupt Enable
++#define HwECC_CTRL_IEN_MECC12_DIS ~Hw18 // MLC ECC12 Decoding Interrupt Disable
++#define HwECC_CTRL_IEN_MECC8_EN Hw17 // MLC ECC8 Decoding Interrupt Enable
++#define HwECC_CTRL_IEN_MECC8_DIS ~Hw17 // MLC ECC8 Decoding Interrupt Disable
++#define HwECC_CTRL_IEN_MECC4_EN Hw16 // MLC ECC4 Decoding Interrupt Enable
++#define HwECC_CTRL_IEN_MECC4_DIS ~Hw16 // MLC ECC4 Decoding Interrupt Disable
++
++// ECC Disable
++#define HwECC_CTRL_EN_SLCEN Hw2 // SLC ECC Encoding Enable
++#define HwECC_CTRL_EN_SLCDE (Hw2|Hw0) // SLC ECC Decoding Enable
++#define HwECC_CTRL_EN_MCL4EN (Hw2|Hw1) // MLC ECC4 Encoding Enable
++#define HwECC_CTRL_EN_MCL4DE (Hw2|Hw1|Hw0) // MLC ECC4 Decoding Enable
++#define HwECC_CTRL_EN_MCL8EN (Hw3) // MLC ECC8 Encoding Enable
++#define HwECC_CTRL_EN_MCL8DE (Hw3|Hw0) // MLC ECC8 Decoding Enable
++#define HwECC_CTRL_EN_MCL12EN (Hw3|Hw1) // MLC ECC12 Encoding Enable
++#define HwECC_CTRL_EN_MCL12DE (Hw3|Hw1|Hw0) // MLC ECC12 Decoding Enable
++#define HwECC_CTRL_EN_MCL14EN (Hw3|Hw2) // MLC ECC14 Encoding Enable
++#define HwECC_CTRL_EN_MCL14DE (Hw3|Hw2|Hw0) // MLC ECC14 Decoding Enable
++#define HwECC_CTRL_EN_MCL16EN (Hw3|Hw2|Hw1) // MLC ECC16 Encoding Enable
++#define HwECC_CTRL_EN_MCL16DE (Hw3|Hw2|Hw1|Hw0) // MLC ECC16 Decoding Enable
++#define HwECC_CTRL_EN_DIS ~(Hw3|Hw2|Hw1|Hw0) // ECC Disable
++
++// ECC Error Number
++#define HwERR_NUM_ERR1 Hw0 // Correctable Error(SLC), Error Occurred(MLC3), 1 Error Occurred(MLC4)
++#define HwERR_NUM_ERR2 Hw1 // 2 Error Occurred(MLC4)
++#define HwERR_NUM_ERR3 (Hw1|Hw0) // 3 Error Occurred(MLC4)
++#define HwERR_NUM_ERR4 Hw2 // 4 Error Occurred(MLC4)
++#define HwERR_NUM_ERR5 (Hw2|Hw0) // 5 Error Occurred(MLC4)
++#define HwERR_NUM_ERR6 (Hw2|Hw1) // 5 Error Occurred(MLC4)
++#define HwERR_NUM_ERR7 (Hw2|Hw1|Hw0) // 5 Error Occurred(MLC4)
++#define HwERR_NUM_ERR8 Hw3 // 5 Error Occurred(MLC4)
++#define HwERR_NUM_ERR9 (Hw3|Hw0) // 5 Error Occurred(MLC4)
++#define HwERR_NUM_ERR10 (Hw3|Hw1) // 5 Error Occurred(MLC4)
++#define HwERR_NUM_ERR11 (Hw3|Hw1|Hw0) // 5 Error Occurred(MLC4)
++#define HwERR_NUM_ERR12 (Hw3|Hw2) // 5 Error Occurred(MLC4)
++#define HwERR_NUM_ERR13 (Hw3|Hw2|Hw0) // 5 Error Occurred(MLC4)
++#define HwERR_NUM_ERR14 (Hw3|Hw2|Hw1) // 5 Error Occurred(MLC4)
++#define HwERR_NUM_ERR15 (Hw3|Hw2|Hw1|Hw0) // 5 Error Occurred(MLC4)
++#define HwERR_NUM_ERR16 Hw4 // 5 Error Occurred(MLC4)
++#define HwERR_NUM_NOERR HwZERO // No Error
++#define HwERR_NUM_CORIMP (Hw1|Hw0) // Correction Impossible(SLC, MLC4)
++
++// ECC Interrupt Control
++#define HwECC_IREQ_SEF Hw17 // SLC ECC Encoding Flag Register
++#define HwECC_IREQ_SDF Hw16 // SLC ECC Decoding Flag Register
++#define HwECC_IREQ_M4EF Hw19 // MLC ECC4 Encoding Flag Register
++#define HwECC_IREQ_M4DF Hw18 // MLC ECC4 Decoding Flag Register
++#define HwECC_IREQ_M8EF Hw21 // MLC ECC8 Encoding Flag Register
++#define HwECC_IREQ_M8DF Hw20 // MLC ECC8 Decoding Flag Register
++#define HwECC_IREQ_M12EF Hw23 // MLC ECC12 Encoding Flag Register
++#define HwECC_IREQ_M12DF Hw22 // MLC ECC12 Decoding Flag Register
++#define HwECC_IREQ_M14EF Hw25 // MLC ECC14 Encoding Flag Register
++#define HwECC_IREQ_M14DF Hw24 // MLC ECC14 Decoding Flag Register
++#define HwECC_IREQ_M16EF Hw27 // MLC ECC16 Encoding Flag Register
++#define HwECC_IREQ_M16DF Hw26 // MLC ECC16 Decoding Flag Register
++#define HwECC_IREQ_M4DI Hw2 // MLC ECC4 Decoding Interrupt Request Register
++#define HwECC_IREQ_M8DI Hw4 // MLC ECC8 Decoding Interrupt Request Register
++#define HwECC_IREQ_M12DI Hw6 // MLC ECC12 Decoding Interrupt Request Register
++#define HwECC_IREQ_M14DI Hw8 // MLC ECC14 Decoding Interrupt Request Register
++#define HwECC_IREQ_M16DI Hw10 // MLC ECC16 Decoding Interrupt Request Register
++#define HwECC_IREQ_CLR (Hw27|Hw26|Hw25|Hw24|Hw23|Hw22|Hw21|Hw20|Hw19|Hw18|Hw17|Hw16|Hw10|Hw8|Hw6|Hw4|Hw2)
++
++/*******************************************************************************
++* 28. Multi-Protocol Encapsulation Forward Error Correction (MPEFEC)
++* Register Define (Base Addr = 0xF0510000)
++********************************************************************************/
++#define HwMPEFEC_BASE *(volatile unsigned long *)0xF0510000
++
++/*******************************************************************************
++* 29. IOBUS Configuration Register Define (Base Addr = 0xF05F5000)
++********************************************************************************/
++#define HwIOBUSCFG_BASE *(volatile unsigned long *)0xF05F5000
++#define HwIOBUSCFG ((PIOBUSCFG)&HwIOBUSCFG_BASE)
++
++// IOBUS AHB 0
++#define HwIOBUSCFG_USB Hw1 // USB2.0 OTG
++#define HwIOBUSCFG_IDE Hw2 // IDE Controller
++#define HwIOBUSCFG_DMA Hw3 // DMA Controller
++#define HwIOBUSCFG_SD Hw4 // SD/MMC Controller
++#define HwIOBUSCFG_MS Hw6 // Memory Stick Controller
++#define HwIOBUSCFG_I2C Hw7 // I2C Controller
++#define HwIOBUSCFG_NFC Hw8 // NFC Controller
++#define HwIOBUSCFG_EHI0 Hw9 // External Host Interface 0
++#define HwIOBUSCFG_EHI1 Hw10 // External Host Interface 1
++#define HwIOBUSCFG_UART0 Hw11 // UART Controller 0
++#define HwIOBUSCFG_UART1 Hw12 // UART Controller 1
++#define HwIOBUSCFG_UART2 Hw13 // UART Controller 2
++#define HwIOBUSCFG_UART3 Hw14 // UART Controller 3
++#define HwIOBUSCFG_UART4 Hw15 // UART Controller 4
++#define HwIOBUSCFG_UART5 Hw16 // UART Controller 5
++#define HwIOBUSCFG_GPSB0 Hw17 // GPSB Controller 0
++#define HwIOBUSCFG_GPSB1 Hw18 // GPSB Controller 1
++#define HwIOBUSCFG_GPSB2 Hw19 // GPSB Controller 2
++#define HwIOBUSCFG_GPSB3 Hw20 // GPSB Controller 3
++#define HwIOBUSCFG_GPSB4 Hw21 // GPSB Controller 4
++#define HwIOBUSCFG_GPSB5 Hw22 // GPSB Controller 5
++#define HwIOBUSCFG_DAI Hw23 // DAI/CDIF Interface
++#define HwIOBUSCFG_ECC Hw24 // ECC Calculator
++#define HwIOBUSCFG_SPDIF Hw25 // SPDIF Tx Controller
++#define HwIOBUSCFG_RTC Hw26 // RTC
++#define HwIOBUSCFG_TSADC Hw27 // TSADC Controller
++#define HwIOBUSCFG_GPS Hw28 // GPS Interface
++#define HwIOBUSCFG_ADMA Hw31 // Audio DMA Controller
++
++// IOBUS AHB 1
++#define HwIOBUSCFG_MPE Hw0 // MPE_FEC
++#define HwIOBUSCFG_TSIF Hw1 // TSIF
++#define HwIOBUSCFG_SRAM Hw2 // SRAM Controller
++
++#define HwIOBUSCFG_STORAGE_ECC ~(Hw17|Hw16) // Storage Bus
++#define HwIOBUSCFG_STORAGE_AHB_BUS1 Hw16 // I/O bus
++#define HwIOBUSCFG_STORAGE_AHB_BUS2 Hw17 // General purpose SRAM or DTCM
++#define HwIOBUSCFG_STORAGE_NFC (Hw17|Hw16) // Main processor data bus
++
++/************************************************************************
++* Channel 0 Memory Controller Register Define (Base Addr = 0xF1000000)
++************************************************************************/
++#define HwEMC_BASE *(volatile unsigned long *)0xF1000000 // External Memory Controller Base Register
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 6 DDI_BUS_V0.00 Dec.11 2008
++********************************************************************************/
++/************************************************************************
++* 4. LCD INTERFACE Register Define (Base Addr = 0xF0200000)
++************************************************************************/
++#define HwLCDC0_BASE *(volatile unsigned long *)0xF0200000 // LCDC0 Control Base Register
++#define HwLCDLUT0_BASE *(volatile unsigned long *)0xF0200400 // LCD LUT 0 Base Register
++#define HwLCDC1_BASE *(volatile unsigned long *)0xF0204000 // LCDC1 Control Base Register
++#define HwLCDLUT1_BASE *(volatile unsigned long *)0xF0204400 // LCD LUT 1 Base Register
++
++/************************************************************************
++* 5. LCD System Interface Register Define (Base Addr = 0xF0200400)
++************************************************************************/
++#define HwLCDSI_BASE *(volatile unsigned long *)0xF020C400 // LCDSI Base Register
++
++/***********************************************************************
++* 6. Memory to Memory Scaler Register Define (Base Addr = 0xF0210000/0xF0220000)
++************************************************************************/
++#define HwM2MSCALER0_BASE *(volatile unsigned long *)0xF0210000
++#define HwM2MSCALER1_BASE *(volatile unsigned long *)0xF0220000
++
++/************************************************************************
++* 7. NTSC/PAL ENCODER Composite Output Register Define (Base Addr = 0xF0240000)
++************************************************************************/
++#define HwTVE_BASE *(volatile unsigned long *)0xF0240000 // TV Encoder Base Register
++
++/************************************************************************
++* 8. HDMI Register Define (Base Addr = 0xF0254000)
++************************************************************************/
++//Controller register base address
++#define HwHDMICTRL_BASE *(volatile unsigned long *)0xF0254000 //Controller register base address
++
++//HDMI register base address
++#define HwHDMICORE_BASE *(volatile unsigned long *)0xF0255000
++
++//AES register base address
++#define HwHDMIAES_BASE *(volatile unsigned long *)0xF0256000 //AES register base address
++
++//SPDIF Receiver register base address
++#define HwHDMISPDIF_BASE *(volatile unsigned long *)0xF0257000
++
++//I2S Receiver register base address
++#define HwHDMII2S_BASE *(volatile unsigned long *)0xF0258000
++
++ //CEC register base address
++#define HwHDMICEC_BASE *(volatile unsigned long *)0xF0259000
++
++/***********************************************************************
++* 9-1. Camera Interface Register Define (Base Addr = 0xF0230000)
++************************************************************************/
++#define HwCIF_BASE *(volatile unsigned long *)0xF0230000 // CIF Base Register
++#define HwCIF ((PCIF)&HwCIF_BASE)
++
++// Input Image Color/Pattern Configuration 1
++#define HwICPCR1_ON Hw31 // On/Off on CIF >> 0:Can't operate CIF , 1:Operating CIF
++#define HwICPCR1_PWD Hw30 // Power down mode in camera >> 0:Disable, 1:Power down mode , This power down mode is connected the PWDN of camera sensor
++#define HwICPCR1_BPS Hw23 // Bypass Scaler >> 0:Non, 1:Bypass
++#define HwICPCR1_POL Hw21 // PXCLK Polarity >> 0:Positive edge, 1:Negative edge
++#define HwICPCR1_SKPF (Hw20|Hw19|Hw18) // Skip Frame >> 0~7 #Frames skips [20:18]
++#define HwICPCR1_M420_ZERO HwZERO // Format Convert (YUV422->YUV420) , Not-Convert
++#define HwICPCR1_M420_ODD Hw17 // converted in odd line skip
++#define HwICPCR1_M420_EVEN (Hw17|Hw16) // converted in even line skip
++#define HwICPCR1_BP Hw15 // Bypass
++#define HwICPCR1_BBS_LSB8 Hw14 // When bypass 16bits mode, LSB 8bits are stored in first
++#define HwICPCR1_C656 Hw13 // Convert 656 format 0:Disable, 1:Enable
++#define HwICPCR1_CP_RGB Hw12 // RGB(555,565,bayer) color pattern
++#define HwICPCR1_PF_444 HwZERO // 4:4:4 format
++#define HwICPCR1_PF_422 Hw10 // 4:2:2 format
++#define HwICPCR1_PF_420 Hw11 // 4:2:0 format or RGB(555,565,bayer) mode
++#define HwICPCR1_RGBM_BAYER HwZERO // Bayer RGB Mode
++#define HwICPCR1_RGBM_RGB555 Hw8 // RGB555 Mode
++#define HwICPCR1_RGBM_RGB565 Hw9 // RGB565 Mode
++#define HwICPCR1_RGBBM_16 HwZERO // 16bit mode
++#define HwICPCR1_RGBBM_8DISYNC Hw6 // 8bit disable sync
++#define HwICPCR1_RGBBM_8 Hw7 // 8bit mode
++#define HwICPCR1_CS_RGBMG HwZERO // 555RGB:RGB(MG), 565RGB:RGB, 444/422/420:R/Cb/U first, Bayer RGB:BG->GR, CCIR656:YCbYCr
++#define HwICPCR1_CS_RGBLG Hw4 // 555RGB:RGB(LG), 565RGB:RGB, 444/422/420:R/Cb/U first, Bayer RGB:GR->BG, CCIR656:YCrYCb
++#define HwICPCR1_CS_BGRMG Hw5 // 555RGB:BGR(MG), 565RGB:BGR, 444/422/420:B/Cr/V first, Bayer RGB:RG->GB, CCIR656:CbYCrY
++#define HwICPCR1_CS_BGRLG (Hw5|Hw4) // 555RGB:BGR(LG), 565RGB:BGR, 444/422/420:B/Cr/V first, Bayer RGB:GB->RG, CCIR656:CrYCbY
++#define HwICPCR1_BO_SW Hw2 // Switch the MSB/LSB 8bit Bus
++#define HwICPCR1_HSP_HIGH Hw1 // Active high
++#define HwICPCR1_VSP_HIGH Hw0 // Active high
++
++// CCIR656 Format Configuration 1
++#define Hw656FCR1_PSL_1ST HwZERO // The status word is located the first byte of EAV & SAV
++#define Hw656FCR1_PSL_2ND Hw25 // The status word is located the second byte of EAV & SAV
++#define Hw656FCR1_PSL_3RD Hw26 // The status word is located the third byte of EAV & SAV
++#define Hw656FCR1_PSL_4TH (Hw26|Hw25) // The status word is located the forth byte of EAV & SAV
++ //FPV [23:16] 0x00FF0000, SPV [15:8] 0x0000FF00, TPV [7:0] 0x000000FF
++// CMOSIF DMA Configuratin 1
++#define HwCDCR1_TM_INC Hw3 // INC Transfer
++#define HwCDCR1_LOCK_ON Hw2 // Lock Transfer
++#define HwCDCR1_BS_1 HwZERO // The DMA transfers the image data as 1 word to memory
++#define HwCDCR1_BS_2 Hw0 // The DMA transfers the image data as 2 word to memory
++#define HwCDCR1_BS_4 Hw1 // The DMA transfers the image data as 4 word to memory
++#define HwCDCR1_BS_8 (Hw1|Hw0) // The DMA transfers the image data as 8 word to memory (default)
++
++// FIFO Status
++#define HwFIFOSTATE_CLR Hw21 // Clear FIFO states, 1:Clear, 0:Not Clear
++#define HwFIFOSTATE_REO Hw19 // Overlay FIFO Read ERROR, 1:The empty signal of input overlay FIFO and read enable signal are High, 0:The empty signal of overlay FIFO is low, or empty is High and read enable signal is Low.
++#define HwFIFOSTATE_REV Hw18 // V(B) Channel FiFO Read ERROR, 1:The empty signal of input V(B) channel FIFO and read enable signal are High, 0:The empty signal of V(B) channel FIFO is Low, or empty is High and read enable signal is Low.
++#define HwFIFOSTATE_REU Hw17 // U(R) Channel FiFO Read ERROR, 1:The empty signal of input U(R) channel FIFO and read enable signal are High, 0:The empty signal of U(R) channel FIFO is Low, or empty is High and read enable signal is Low.
++#define HwFIFOSTATE_REY Hw16 // Y(G) Channel FiFO Read ERROR, 1:The empty signal of input Y(G) channel FIFO and read enable signal are High, 0:The empty signal of Y(G) channel FIFO is Low, or empty is High and read enable signal is Low.
++#define HwFIFOSTATE_WEO Hw13 // Overlay FIFO Write ERROR, 1:The full signal of overlay FIFO and write enable signal are High, 0:The full signal of overlay FIFO is Low, or full is High and write enable signal is Low.
++#define HwFIFOSTATE_WEV Hw12 // V(B) Channel FiFO Write ERROR, 1:The full signal of V(B) channel FIFO and write enable signal are High, 0:The full signal of V(B) channel FIFO is Low, or full is High and write enable signal is Low.
++#define HwFIFOSTATE_WEU Hw11 // U(R) Channel FiFO Write ERROR, 1:The full signal of U(R) channel FIFO and write enable signal are High, 0:The full signal of U(R) channel FIFO is Low, or full is High and write enable signal is Low.
++#define HwFIFOSTATE_WEY Hw10 // Y(G) Channel FiFO Write ERROR, 1:The full signal of Y channel FIFO and write enable signal are High, 0:The full signal of Y channel FIFO is Low, or full is High and write enable signal is Low.
++#define HwFIFOSTATE_EO Hw8 // Overlay FIFO Empty Signal, 1:The state of overlay FIFO is empty, 0:The state of overlay FIFO is non-empty.
++#define HwFIFOSTATE_EV Hw7 // V(B) Channel FiFO Empty Signal, 1:The state of V(B) channel FIFO is empty, 0:The state of V(B) channel FIFO is non-empty.
++#define HwFIFOSTATE_EU Hw6 // U(R) Channel FiFO Empty Signal, 1:The state of U(R) channel FIFO is empty, 0:The state of U(R) channel FIFO is non-empty.
++#define HwFIFOSTATE_EY Hw5 // Y(G) Channel FiFO Empty Signal, 1:The state of Y channel FIFO is empty, 0:The state of Y channel FIFO is non-empty.
++#define HwFIFOSTATE_FO Hw3 // Overlay FiFO FULL Signal, 1:The state of overlay FIFO is full, 0:The state of overlay FIFO is non-full.
++#define HwFIFOSTATE_FV Hw2 // V(B) Channel FiFO FULL Signal, 1:The state of V(B) channel FIFO is full, 0:The state of V(B) channel FIFO is non-full.
++#define HwFIFOSTATE_FU Hw1 // U(R) Channel FiFO FULL Signal, 1:The state of U(R) channel FIFO is full, 0:The state of U(R) channel FIFO is non-full.
++#define HwFIFOSTATE_FY Hw0 // Y(G) Channel FiFO FULL Signal, 1:The state of Y(G) channel FIFO is full, 0:The state of Y(G) channel FIFO is non-full.
++
++// Interrupt & CIF Operating
++#define HwCIRQ_IEN Hw31 // Interrupt Enable 0:interrupt disable, 1:interrupt enable
++#define HwCIRQ_URV Hw30 // Update Register in VSYNC 0:Register is update without VSYNC , 1:When VSYNC is posedge, register is updated.
++#define HwCIRQ_ITY Hw29 // Interrupt Type 0:Pulse type, 1:Hold-up type when respond signal(ICR) is high
++#define HwCIRQ_ICR Hw28 // Interrupt Clear 0:.... , 1:Interrupt Clear (using ITY is Hold-up type)
++#define HwCIRQ_MVN Hw26 // Mask interrupt of VS negative edge, 0:Don't mask, 1:Mask
++#define HwCIRQ_MVP Hw25 // Mask interrupt of VS positive edge, 0:Don't mask, 1:Mask
++#define HwCIRQ_MVIT Hw24 // Mask interrupt of VCNT Interrupt, 0:Don't mask, 1:Mask
++#define HwCIRQ_MSE Hw23 // Mask interrupt of Scaler Error, 0:Don't mask, 1:Mask
++#define HwCIRQ_MSF Hw22 // Mask interrupt of Scaler finish, 0:Don't mask, 1:Mask
++#define HwCIRQ_MENS Hw21 // Mask interrupt of Encoding start, 0:Don't mask, 1:Mask
++#define HwCIRQ_MRLV Hw20 // Mask interrupt of Rolling V address, 0:Don't mask, 1:Mask
++#define HwCIRQ_MRLU Hw19 // Mask interrupt of Rolling U address, 0:Don't mask, 1:Mask
++#define HwCIRQ_MRLY Hw18 // Mask interrupt of Rolling Y address, 0:Don't mask, 1:Mask
++#define HwCIRQ_MSCF Hw17 // Mask interrupt of Capture frame, 0:Don't mask, 1:Mask
++#define HwCIRQ_MSOF Hw16 // Mask interrupt of Stored one frame, 0:Don't mask, 1:Mask
++#define HwCIRQ_VSS Hw12 // Status of vertical sync, Non-vertical sync blank area.
++#define HwCIRQ_VN Hw10 // VS negative, 0:-, 1:When VS is generated if negative edge
++#define HwCIRQ_VP Hw9 // VS positive, 0:-, 1:When VS is generated if positive edge
++#define HwCIRQ_VIT Hw8 // VCNT Interrupt, 0:-, 1:When VCNT is generated....
++#define HwCIRQ_SE Hw7 // Scaler Error, 0:-, 1:When Scale operation is not correct.
++#define HwCIRQ_SF Hw6 // Scaler Finish, 0:-, 1:When Scale operation is finished
++#define HwCIRQ_ENS Hw5 // Encoding start status, 0:-, 1:When Y address is bigger than encoding start address, this bit is high
++#define HwCIRQ_ROLV Hw4 // Rolling V address status, 0:-, 1:If V address is move to start address, this bit is high
++#define HwCIRQ_ROLU Hw3 // Rolling U address starus, 0:-, 1:If U address is move to start address, this bit is high
++#define HwCIRQ_ROLY Hw2 // Rolling Y address starus, 0:-, 1:If Y address is move to start address, this bit is high
++#define HwCIRQ_SCF Hw1 // Stored captured frame, 0:-, 1:If Captured frame is stored, this bit is high
++#define HwCIRQ_SOF Hw0 // Stored One frame, 0-, 1:If one frame if stored, this bit is high.
++
++// Overlay Control 1
++#define HwOCTRL1_OCNT_MAX (Hw29|Hw28|Hw27|Hw26|Hw25|Hw24) //[28:24] Overlay Count FIFO (Hw27|Hw26|Hw25|Hw24|Hw23)
++#define HwOCTRL1_OM_BLOCK Hw16 // Overlay Method 0:Full image overlay, 1:Block image overlay , Full image overlay mode, overlay image size is equal to the input image size.
++#define HwOCTRL1_OE_EN Hw12 // Overlay enable 0:Disable, 1:Enable
++#define HwOCTRL1_XR1_100 Hw10 // XOR in AP1 is 3 (100%) 0:XOR operation, 1:100% , When AP1 is 3 and CEN & AEN is 1, We select the 100% alpha value or XOR.
++#define HwOCTRL1_XR0_100 Hw9 // XOR in AP0 is 3 (100%) 0:XOR operation, 1:100% , When AP0 is 3 and CEN & AEN is 1, We select the 100% alpha value or XOR.
++#define HwOCTRL1_AP1_25 HwZERO // Alpha Value in alpha is 1 // 25%
++#define HwOCTRL1_AP1_50 Hw6 // Alpha Value in alpha is 1 // 50%
++#define HwOCTRL1_AP1_75 Hw7 // Alpha Value in alpha is 1 // 75%
++#define HwOCTRL1_AP1_100 (Hw7|Hw6) // Alpha Value in alpha is 1 // 100% or XOR operation (for XR value)
++#define HwOCTRL1_AP0_25 HwZERO // Alpha Value in alpha is 0 // 25%
++#define HwOCTRL1_AP0_50 Hw4 // Alpha Value in alpha is 0 // 50%
++#define HwOCTRL1_AP0_75 Hw5 // Alpha Value in alpha is 0 // 75%
++#define HwOCTRL1_AP0_100 (Hw5|Hw4) // Alpha Value in alpha is 0 // 100% or XOR operation
++ // When 565RGB and AEN, alpha value is depend on AP0 value.
++#define HwOCTRL1_AEN_EN Hw2 // Alpha enable 0:Disable, 1:Enable
++#define HwOCTRL1_CEN_EN Hw0 // Chroma key enable 0:Disable, 1:Enable
++
++// Overlay Control 2
++#define HwOCTRL2_CONV Hw3 // Color Converter Enable 0:Disable, 1:Enable
++#define HwOCTRL2_RGB_565 HwZERO // RGB mode 565RGB
++#define HwOCTRL2_RGB_555 Hw1 // RGB mode 555RGB
++#define HwOCTRL2_RGB_444 Hw2 // RGB mode 444RGB
++#define HwOCTRL2_RGB_332 (Hw2|Hw1) // RGB mode 332RGB
++#define HwOCTRL2_MD Hw0 // Color Mode 0:YUV Color, 1:RGB color
++
++// Overlay Control 3 -- KEY Value
++#define HwOCTRL3_KEYR_MAX 0x00FF0000 // Chroma-key value R(U), Chroea-key value in R(U) channel, Default value is 0x00
++#define HwOCTRL3_KEYG_MAX 0x0000FF00 // Chroma-key value G(Y), Chroea-key value in G(Y) channel, Default value is 0x00
++#define HwOCTRL3_KEYB_MAX 0x000000FF // Chroma-key value B(V), Chroea-key value in B(V) channel, Default value is 0x00
++
++// Overlay Control 4 -- Mask KEY Value
++#define HwOCTRL4_MKEYR_MAX 0x00FF0000 // Mask Chroma-key value R(U), Chroea-key value in R(U) channel, Default value is 0x00
++#define HwOCTRL4_MKEYG_MAX 0x0000FF00 // Mask Chroma-key value G(Y), Chroea-key value in G(Y) channel, Default value is 0x00
++#define HwOCTRL4_MKEYB_MAX 0x000000FF // Mask Chroma-key value B(V), Chroea-key value in B(V) channel, Default value is 0x00
++
++// Camera Down Scaler
++#define HwCDS_SFH_1 HwZERO // Horizontal Scale Factor, 1/1 down scale
++#define HwCDS_SFH_2 Hw4 // Horizontal Scale Factor, 1/2 down scale
++#define HwCDS_SFH_4 Hw5 // Horizontal Scale Factor, 1/4 down scale
++#define HwCDS_SFH_8 (Hw5|Hw4) // Horizontal Scale Factor, 1/8 down scale
++#define HwCDS_SFV_1 HwZERO // Vertical Scale Factor, 1/1 down scale
++#define HwCDS_SFV_2 Hw2 // Vertical Scale Factor, 1/2 down scale
++#define HwCDS_SFV_4 Hw3 // Vertical Scale Factor, 1/4 down scale
++#define HwCDS_SFV_8 (Hw3|Hw2) // Vertical Scale Factor, 1/8 down scale
++#define HwCDS_SEN_EN Hw0 // Scale enable, 0:Disable, 1:enable
++
++// CMOSIF Capture mode1
++#define HwCCM1_ENCNUM 0xF0000000 // Encode INT number (using CAP mode) [31:28], value area (0~15), Encode interrupt number
++#define HwCCM1_ROLNUMV 0x0F000000 // Rolling number in V (using CAP mode) [27:24], value area (0~15), Rolling number
++#define HwCCM1_ROLNUMU 0x00F00000 // Rolling number in U (using CAP mode) [23:20], value area (0~15), Rolling number
++#define HwCCM1_ROLNUMY 0x000F0000 // Rolling number in Y (using CAP mode) [19:16], value area (0~15), Rolling number
++#define HwCCM1_CB Hw10 // Capture Busy, 0:-, 1:Capture busy
++#define HwCCM1_EIT Hw9 // Encodig INT count, 0:Always 1 pulse, 1:Counting encoding INT
++#define HwCCM1_UES Hw8 // Using Encoding Start Address, 0:disable, 1:Enable
++#define HwCCM1_SKIPNUM 0x000000F0 // Skip frame number (using CAP mode) [7:4], value area (0~15), Skip frame number
++#define HwCCM1_RLV Hw3 // Rolling address V, 0:disable, 1:Enable
++#define HwCCM1_RLU Hw2 // Rolling address U, 0:disable, 1:Enable
++#define HwCCM1_RLY Hw1 // Rolling address Y, 0:disable, 1:Enable
++#define HwCCM1_CAP Hw0 // Image Capture, 0:Normal, 1:Image Capture
++
++// CMOSIF Capture mode2
++#define HwCCM2_VCNT 0x000000F0 // Description (Using CAP mode) [7:4], Threshold line counter in interrupt 1:16 line, 2:32 line, 3: 48 line...
++#define HwCCM2_VEN Hw0 // VCNT folling enable (Using CAP mode) 0:Normal(?) Disalbe¾Æ´Ñ°¡?, 1:Enable
++
++// CMOSIF R2Y confiquration
++#define HwCR2Y_FMT (Hw4|Hw3|Hw2|Hw1) // FMT[4:1] 0000 -> Input format 16bit 565RGB(RGB sequence) ÀÚ¼¼ÇÑ »çÇ× 750A CIF SPEC. 1-22
++#define HwCR2Y_EN Hw0 // R2Y Enable, 0:disable, 1:Enable
++
++// CMOSIF Current Line Count
++#define HwCCLC_LCNT 0x0000FFFF // LCNT[15:0] Current Line Count
++
++
++
++/***********************************************************************
++* 9-2. Effect Register Define (Base Addr = 0xF0230100)
++************************************************************************/
++#define HwCEM_BASE *(volatile unsigned long *)0xF0230100 //W/R 0x00000000 Effect mode register
++#define HwCEM ((PEFFECT)&HwCEM_BASE)
++
++// CMOSIF Effect mode
++#define HwCEM_UVS Hw15 // UV Swap 0:u-v-u-v sequence, 1:v-u-v-u sequence
++#define HwCEM_VB Hw14 // V Bias (V channel value offset), 0:disable, 1:Enable
++#define HwCEM_UB Hw13 // U Bias (U channel value offset), 0:disable, 1:Enable
++#define HwCEM_YB Hw12 // Y Bias (Y channel value offset), 0:disable, 1:Enable
++#define HwCEM_YCS Hw11 // YC Swap 0:u-y-v-y sequence, 1:y-u-y-v sequence
++#define HwCEM_IVY Hw10 // Invert Y, 0:disable, 1:Enable
++#define HwCEM_STC Hw9 // Strong C, 0:disable, 1:Enable
++#define HwCEM_YCL Hw8 // Y Clamp (Y value clipping), 0:disable, 1:Enable
++#define HwCEM_CS Hw7 // C Select (Color filter), 0:disable, 1:Enable(Color filter)
++#define HwCEM_SKT Hw6 // Sketch Enable, 0:disable, 1:Enable
++#define HwCEM_EMM Hw5 // Emboss mode, 0:Positive emboss, 1:Negative emboss
++#define HwCEM_EMB Hw4 // Emboss, 0:disable, 1:Enable
++#define HwCEM_NEGA Hw3 // Negative mode, 0:disable, 1:Enable
++#define HwCEM_GRAY Hw2 // Gray mode, 0:disable, 1:Enable
++#define HwCEM_SEPI Hw1 // Sepia mode, 0:disable, 1:Enable
++#define HwCEM_NOR Hw0 // Normal mode, 0:Effect mode, 1:Normal mode
++
++// CMOSIF Sepia UV Setting
++#define HwHwCSUV_SEPIA_U 0x0000FF00 // SEPIA_U[15:8] U channel threshold value for sepia
++#define HwHwCSUV_SEPIA_V 0x000000FF // SEPIA_V[7:0] V channel threshold value for sepia
++
++// CMOSIF Color selection
++#define HwCCS_USTART 0xFF000000 // USTART [31:24] Color filter range start point of U channel
++#define HwCCS_UEND 0x00FF0000 // UEND [23:16] Color filter range end point of U channel
++#define HwCCS_VSTART 0x0000FF00 // VSTART [15:8] Color filter range start point of V channel
++#define HwCCS_VEND 0x000000FF // VEND [7:0] Color filter range end point of V channel
++
++// CMOSIF H-filter coefficent
++#define HwCHFC_COEF0 0x00FF0000 // COEF0 [23:16] Horizontal filter coefficient0 for emboss or sketch
++#define HwCHFC_COEF1 0x0000FF00 // COEF1 [15:8] Horizontal filter coefficient1 for emboss or sketch
++#define HwCHFC_COEF2 0x000000FF // COEF2 [7:0] Horizontal filter coefficient2 for emboss or sketch
++
++// CMOSIF Sketch threshold
++#define HwCST_THRESHOLD 0x000000FF // Sketch [7:0] Sketch threshold
++
++// CMOSIF Clamp threshold
++#define HwCCT_THRESHOLD 0x000000FF // Clamp [7:0] Clamp threshold
++
++// CMOSIF BIAS
++#define HwCBR_YBIAS 0x00FF0000 // Y_BIAS [23:16] Y value offset
++#define HwCBR_UBIAS 0x0000FF00 // U_BIAS [15:8] U value offset
++#define HwCBR_VBIAS 0x000000FF // V_BIAS [7:0] V value offset
++
++// CMOSIF Image size
++#if defined (SENSOR_3M) || defined (SENSOR_5M)
++#define HwCEIS_HSIZE 0x0FFF0000 // HSIZE [26:16] Horizontal size of input image
++#else
++#define HwCEIS_HSIZE 0x07FF0000 // HSIZE [26:16] Horizontal size of input image
++#endif
++#define HwCEIS_VSIZE 0x000007FF // VSIZE [10:0] Vertical size of input image
++
++#define HwCIC_H2H_WAIT 0xFFFF0000 // H2H_WAIT [31:16] Horizontal sync (hs)to hs wait cycle
++#define HwCIC_STB_CYCLE 0x0000FF00 // STB_CYCLE [15:8] CCIR strobe cycle, Minimum Value of STB_CYCLE is 4.
++#define HwCIC_INP_WAIT (Hw6|Hw5|Hw4) // INP_WAIT [6:4] ???????????????
++#define HwCIC_INPR Hw3 // ???????????????
++#define HwCIC_FA Hw2 // Flush all
++#define HwCIC_INE Hw1 // Inpath Enalbe, 0:disable, 1:Enable
++#define HwCIC_INP Hw0 // Inpath Mode, 0:Camera mode, 1:Memory mode
++
++// Y°ªÀº 32Àüü¸¦ ´Ù ¼¼ÆÃÇϵµ·Ï ÇÏ°í U, V°ªÀº »óÀ§ 4bit´Â »ý·«Çصµ cif¿¡¼­ address¸¦ ÃßÁ¤ÇÏ´Â °ÍÀÌ °¡´ÉÇÏ´Ù.
++// HwCISA1_SRC_BASE´Â Y°ª¸¸ 4ºñÆ® ´õ Á¸ÀçÇؼ­ ±¸º°ÇØ ³õÀº °ÍÀÓ ,, ½ÇÁ¦·Î »ç¿ëÇÒ °æ¿ì ±×³É 32 address¸¦ ÇÒ´ç ÇÑ´Ù.
++// CMOSIF INPATH Source address in Y channel
++#define HwCISA1_SRC_BASE 0xF0000000 // SRC_BASE [31:28] Source base address (31 down to 28 bit assign in base address)
++#define HwCISA1_SRC_BASE_Y 0x0FFFFFFF // SRC_BASE_Y [27:0] Source base address in Y channel (27 down to 0 bit assign in bass address)
++
++// CMOSIF INPATH Source address in U channel
++#define HwCISA2_SRC_TYPE_422SEQ0 HwZERO // 0: (4:2:2 SEQ0)
++#define HwCISA2_SRC_TYPE_422SEQ1 Hw28 // 1: (4:2:2 SEQ1)
++#define HwCISA2_SRC_TYPE_422SEPA Hw29 // 2: (4:2:2 Separate)
++#define HwCISA2_SRC_TYPE_420SEPA (Hw29|Hw28) // 3: (4:2:0 Separate)
++#define HwCISA2_SRC_BASE_U 0x0FFFFFFF // SRC_BASE_U [27:0] Source base address in U channal (27 down to 0 bit assign in base address)
++
++// CMOSIF INPATH Source address in V channel
++#define HwCISA3_SRC_BASE_V 0x0FFFFFFF // SRC_BASE_V [27:0] Source base address in V channal (27 down to 0 bit assign in base address)
++
++
++// CMOSIF INPATH Source image offset
++//#define HwCISO_SRC_OFFSET_H 0x0FFF0000 // SRC_OFFSET_H [27:16] source address offset in H
++//#define HwCISO_SRC_OFFSET_V 0x00000FFF // SRC_OFFSET_V [11:0] source address offset in V
++#define HwCISO_SRC_OFFSET_Y 0x0FFF0000 // SRC_OFFSET_Y [27:16] source address offset in Y channel
++#define HwCISO_SRC_OFFSET_C 0x00000FFF // SRC_OFFSET_C [11:0] source address offset in C channel
++
++// CMOSIF INPATH Source image size
++#define HwCISS_SRC_HSIZE 0x0FFF0000 // SRC_HSIZE [27:16] Horizontal size in source image
++#define HwCISS_SRC_VSIZE 0x00000FFF // SRC_VSIZE [11:0] Vertical size in source image
++
++
++// CMOSIF INPATH Destination image size
++#define HwCIDS_DST_HSIZE 0x0FFF0000 // DST_HSIZE [27:16] Horizontal size in destination image
++#define HwCIDS_DST_VSIZE 0x00000FFF // DST_VSIZE [11:0] Vertical size in destination image
++
++// HSCALE = SRC_HSIZE*256/DST_HSIZE
++// VSCALE = SRC_VSIZE*256/DST_VSIZE
++// CMOSIF INPATH Target scale
++#define HwCIS_HSCALE 0x3FFF0000 // HSCALE [29:16] Horizontal scale factor
++#define HwCIS_VSCALE 0x00003FFF // VSCALE [13:0] Vertical scale factor
++
++
++
++/***********************************************************************
++* 9-3. Scaler Register Define (Base Addr = 0xF0230200)
++************************************************************************/
++#define HwCSC_BASE *(volatile unsigned long *)0xF0230200 //W/R 0x00000000 Scaler configuration
++#define HwCSC ((PCIFSCALER)&HwCSC_BASE)
++
++// Scaler configuration
++#define HwSCC_EN Hw0 // Scaler Enable 0:disable, 1:Enable
++
++// HSCALE = SRC_HSIZE*256/DST_HSIZE
++// VSCALE = SRC_VSIZE*256/DST_VSIZE
++// Scale factor
++#define HwSCSF_HSCALE 0x3FFF0000 // HSCALE [29:16] Horizontal scale factor
++#define HwSCSF_VSCALE 0x00003FFF // VSCALE [13:0] Vertical scale factor
++
++// Image offset
++#define HwSCSO_OFFSET_H 0x0FFF0000 // H [27:16] Horizontal offset
++#define HwSCSO_OFFSET_V 0x00000FFF // V [11:0] Vertical offset
++
++// Source image size
++#define HwSCSS_HSIZE 0x0FFF0000 // H [27:16] Horizontal size in source image
++#define HwSCSS_VSIZE 0x00000FFF // V [11:0] Vertical size in source image
++
++// Destination image size
++#define HwSCDS_HSIZE 0x0FFF0000 // H [27:16] Horizontal size in destination image
++#define HwSCDS_VSIZE 0x00000FFF // V [11:0] Vertical size in destination image
++
++/***********************************************************************
++* 10. Video and Image Quality Enhancer Register Define (Base Addr = 0xF0230200)
++************************************************************************/
++#define HwVIQE_BASE *(volatile unsigned long *)0xF0252000
++
++/***********************************************************************
++* 11. LVDS Register Define (Base Addr = 0xF0230200)
++************************************************************************/
++#define HwDDI_CONFIG_BASE *(volatile unsigned long *)0xF0251000
++#define HwDDI_CONFIG ((PDDICONFIG)&HwDDI_CONFIG_BASE)
++
++// HDMI Control register
++#define HwDDIC_HDMI_CTRL_EN Hw15
++#define HwDDIC_HDMI_CTRL_SEL_LCDC0 HwZERO
++#define HwDDIC_HDMI_CTRL_SEL_LCDC1 Hw14
++#define HwDDIC_HDMI_CTRL_RST_HDMI Hw0
++#define HwDDIC_HDMI_CTRL_RST_SPDIF Hw1
++#define HwDDIC_HDMI_CTRL_RST_TMDS Hw2
++#define HwDDIC_HDMI_CTRL_RST_NOTUSE Hw3
++
++// Power Down
++#define HwDDIC_PWDN_HDMI Hw8 // HDMI Interface
++#define HwDDIC_PWDN_DDIC Hw7 // DDIBUS Cache
++#define HwDDIC_PWDN_MSCL1 Hw6 // Memory Scaler 1
++#define HwDDIC_PWDN_MSCL0 Hw5 // Memory Scaler 0
++#define HwDDIC_PWDN_LCDSI Hw4 // LCDSI Interface
++#define HwDDIC_PWDN_LCDC1 Hw3 // LCD 1 Interface
++#define HwDDIC_PWDN_LCDC0 Hw2 // LCD 0 Interface
++#define HwDDIC_PWDN_VIQE Hw1 // Video Image Quality Enhancer
++#define HwDDIC_PWDN_CIF Hw0 // Camera Interface
++
++// Soft Reset
++#define HwDDIC_SWRESET_HDMI Hw8 // HDMI Interface
++#define HwDDIC_SWRESET_DDIC Hw7 // DDIBUS Cache
++#define HwDDIC_SWRESET_MSCL1 Hw6 // Memory Scaler 1
++#define HwDDIC_SWRESET_MSCL0 Hw5 // Memory Scaler 0
++#define HwDDIC_SWRESET_LCDSI Hw4 // LCDSI Interface
++#define HwDDIC_SWRESET_LCDC1 Hw3 // LCD 1 Interface
++#define HwDDIC_SWRESET_LCDC0 Hw2 // LCD 0 Interface
++#define HwDDIC_SWRESET_VIQE Hw1 // Video Image Quality Enhancer
++#define HwDDIC_SWRESET_CIF Hw0 // Camera Interface
++
++#define HwDDI_CACHE_BASE *(volatile unsigned long *)0xF0250000
++#define HwDDI_CACHE ((PDDICACHE)&HwDDI_CACHE_BASE)
++
++// DDI CACHE Control
++#define HwDDIC_CTRL_BW Hw31
++#define HwDDIC_CTRL_CIF_DMA Hw25
++#define HwDDIC_CTRL_VIQE_DMA2_2 Hw24
++#define HwDDIC_CTRL_VIQE_DMA2_1 Hw23
++#define HwDDIC_CTRL_VIQE_DMA2_0 Hw22
++#define HwDDIC_CTRL_VIQE_DMA1_2 Hw21
++#define HwDDIC_CTRL_VIQE_DMA1_1 Hw20
++#define HwDDIC_CTRL_VIQE_DMA1_0 Hw19
++#define HwDDIC_CTRL_VIQE_DMA0_2 Hw18
++#define HwDDIC_CTRL_VIQE_DMA0_1 Hw17
++#define HwDDIC_CTRL_VIQE_DMA0_0 Hw16
++#define HwDDIC_CTRL_MSCL1_DMA2 Hw15
++#define HwDDIC_CTRL_MSCL1_DMA1 Hw14
++#define HwDDIC_CTRL_MSCL1_DMA0 Hw13
++#define HwDDIC_CTRL_MSCL0_DMA2 Hw12
++#define HwDDIC_CTRL_MSCL0_DMA1 Hw11
++#define HwDDIC_CTRL_MSCL0_DMA0 Hw10
++#define HwDDIC_CTRL_LCD1_DMA2 Hw9
++#define HwDDIC_CTRL_LCD1_DMA1 Hw8
++#define HwDDIC_CTRL_LCD1_DMA0_2 Hw7
++#define HwDDIC_CTRL_LCD1_DMA0_1 Hw6
++#define HwDDIC_CTRL_LCD1_DMA0_0 Hw5
++#define HwDDIC_CTRL_LCD0_DMA2 Hw4
++#define HwDDIC_CTRL_LCD0_DMA1 Hw3
++#define HwDDIC_CTRL_LCD0_DMA0_2 Hw2
++#define HwDDIC_CTRL_LCD0_DMA0_1 Hw1
++#define HwDDIC_CTRL_LCD0_DMA0_0 Hw0
++
++// DDI CACHE Configuration
++#define HwDDIC_CFG_CIF_DMA (25)
++#define HwDDIC_CFG_VIQE_DMA2_2 (24)
++#define HwDDIC_CFG_VIQE_DMA2_1 (23)
++#define HwDDIC_CFG_VIQE_DMA2_0 (22)
++#define HwDDIC_CFG_VIQE_DMA1_2 (21)
++#define HwDDIC_CFG_VIQE_DMA1_1 (20)
++#define HwDDIC_CFG_VIQE_DMA1_0 (19)
++#define HwDDIC_CFG_VIQE_DMA0_2 (18)
++#define HwDDIC_CFG_VIQE_DMA0_1 (17)
++#define HwDDIC_CFG_VIQE_DMA0_0 (16)
++#define HwDDIC_CFG_MSCL1_DMA2 (15)
++#define HwDDIC_CFG_MSCL1_DMA1 (14)
++#define HwDDIC_CFG_MSCL1_DMA0 (13)
++#define HwDDIC_CFG_MSCL0_DMA2 (12)
++#define HwDDIC_CFG_MSCL0_DMA1 (11)
++#define HwDDIC_CFG_MSCL0_DMA0 (10)
++#define HwDDIC_CFG_LCD1_DMA2 (9)
++#define HwDDIC_CFG_LCD1_DMA1 (8)
++#define HwDDIC_CFG_LCD1_DMA0_2 (7)
++#define HwDDIC_CFG_LCD1_DMA0_1 (6)
++#define HwDDIC_CFG_LCD1_DMA0_0 (5)
++#define HwDDIC_CFG_LCD0_DMA2 (4)
++#define HwDDIC_CFG_LCD0_DMA1 (3)
++#define HwDDIC_CFG_LCD0_DMA0_2 (2)
++#define HwDDIC_CFG_LCD0_DMA0_1 (1)
++#define HwDDIC_CFG_LCD0_DMA0_0 (0)
++
++#define HwDDIC_CFG_MASK (0x1F)
++#define HwDDIC_CFG26(X) ((X)<<16)
++#define HwDDIC_CFG27(X) ((X)<<24)
++#define HwDDIC_CFG28(X) ((X))
++#define HwDDIC_CFG29(X) ((X)<<8)
++#define HwDDIC_CFG30(X) ((X)<<16)
++#define HwDDIC_CFG31(X) ((X)<<24)
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 7 VIDEO BUS_V0.00 Dec.11 2008
++********************************************************************************/
++/***********************************************************************
++* 4. VIDEO CODEC Register Define (Base Addr = 0x0xF0700000)
++************************************************************************/
++#define HwVIDEOCODEC_BASE *(volatile unsigned long *)0xF0700000
++
++/***********************************************************************
++* 5. JPEG CODEC Register Define (Base Addr = 0x0xF0710000/0xF0720000)
++************************************************************************/
++#define HwJPEGDECODER_BASE *(volatile unsigned long *)0xF0710000
++#define HwJPEGENCODER_BASE *(volatile unsigned long *)0xF0720000
++#define HwVIDEOCACHE_BASE *(volatile unsigned long *)0xF0701000
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 8 GRAPHIC BUS_V0.00 Dec.11 2008
++********************************************************************************/
++/***********************************************************************
++* 4. Overlay Mixer Register Define (Base Addr = 0xF0010000)
++************************************************************************/
++#define HwOVERLAYMIXER_BASE *(volatile unsigned long *)0xF0010000
++
++/*******************************************************************************
++* 5-1. 2D/3D GPU
++*
++* Pixel Processor Register Map Register Define (Base Addr = 0xF0000000)
++********************************************************************************/
++#define HwPIXELPROCESSOR_BASE *(volatile unsigned long *)0xF0000000
++
++/*******************************************************************************
++* 5-2. Geometry Processor Register Map Register Define (Base Addr = 0xF0000000)
++********************************************************************************/
++#define HwGEOMETRYPROCESSOR_BASE *(volatile unsigned long *)0xF0002000
++
++/*******************************************************************************
++* 5-3. MMU Configuration Register Define (Base Addr = 0xF0003000)
++********************************************************************************/
++#define HwMMUCONFIG_BASE *(volatile unsigned long *)0xF0003000
++
++/*******************************************************************************
++* 5-4. GRPBUS Configuration Register Define (Base Addr = 0xF0004000)
++********************************************************************************/
++#define HwGRPBUS_BASE *(volatile unsigned long *)0xF0004000
++
++/*******************************************************************************
++* 5-5. GRPBUS BWRAP Register Define (Base Addr = 0xF0005000)
++********************************************************************************/
++#define HwGRPBUSBWRAP_BASE *(volatile unsigned long *)0xF0005000
++
++#endif
+diff --git a/arch/arm/mach-tcc8900/include/mach/TCC89x_Structures.h b/arch/arm/mach-tcc8900/include/mach/TCC89x_Structures.h
+new file mode 100644
+index 0000000..381d0cd
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/TCC89x_Structures.h
+@@ -0,0 +1,3276 @@
++/****************************************************************************
++ * FileName : TCC89x_Structures.h
++ * Description :
++ ****************************************************************************
++*
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++*
++ ****************************************************************************/
++
++
++/************************************************************************
++* TCC89x Internal Register Definition File
++************************************************************************/
++#ifndef __TCC89xSTRUCTURES_H__
++#define __TCC89xSTRUCTURES_H__
++
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 2 SMU & PMU_V0.00 Dec.11 2008
++********************************************************************************/
++/************************************************************************
++* 1. Clock Controller Register Define (Base Addr = 0xF0400000) // R/W
++************************************************************************/
++//---------------------------------------------------------------------------------------------
++//31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
++// |CFGEN|MODE | NCKOE/DPRD |
++//15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
++// NCKOE/DMIN | NCKOE/DMAX | NCKOE/DCDIV | | CKSEL |
++//----------------------------------------------------------------------------------------------
++//CLK_BASE *(volatile unsigned long *)0xF0400000
++
++typedef struct _CKC{
++ volatile unsigned int CLK0CTRL; // 0x00 R/W 0x2FFFF4 CPU & Bus Clock0 Control Register
++ volatile unsigned int CLK1CTRL; // 0x04 R/W 0x2FFFF4 CPU & Bus Clock1 Control Register
++ volatile unsigned int CLK2CTRL; // 0x08 R/W 0x2FFFF4 CPU & Bus Clock2 Control Register
++ volatile unsigned int CLK3CTRL; // 0x0C R/W 0x2FFFF4 CPU & Bus Clock3 Control Register
++ volatile unsigned int CLK4CTRL; // 0x10 R/W 0x2FFFF4 CPU & Bus Clock4 Control Register
++ volatile unsigned int CLK5CTRL; // 0x14 R/W 0x2FFFF4 CPU & Bus Clock5 Control Register
++ volatile unsigned int CLK6CTRL; // 0x18 R/W 0x2FFFF4 CPU & Bus Clock6 Control Register
++ volatile unsigned int CLK7CTRL; // 0x1C R/W 0x2FFFF4 CPU & Bus Clock 7Control Register
++ volatile unsigned int PLL0CFG; // 0x20 R/W 0x8010FA03 PLL0 Configuration Register
++ volatile unsigned int PLL1CFG; // 0x24 R/W 0x80009603 PLL1 Configuration Register
++ volatile unsigned int PLL2CFG; // 0x28 R/W 0x80007D03 PLL2 Configuration Register
++ volatile unsigned int PLL3CFG; // 0x2C R/W 0x80009603 PLL3 Configuration Register
++ volatile unsigned int CLKDIVC; // 0x30 R/W 0x81818181 PLL Divider Configuration Register
++ volatile unsigned int CLKDIVC1; // 0x34 R/W 0x00008181 External Clock Divider Configuration Register
++ volatile unsigned int CLKDIVC2; //- 0x38 Reserved
++ volatile unsigned int CLKDIVC3; //- 0x3C Reserved
++ volatile unsigned int SWRESETPRD; // 0x40 R/W 0x000000FF Software Reset Period Register
++ volatile unsigned int SWRESET; // 0x44 R/W 0x00000000 Software Reset Control Register
++ volatile unsigned int NOTDEFINE0[14]; //- 0x48-0x7C Reserved
++ volatile unsigned int PCLK_TCX; // 0x80 R/W 0x00014000 Timer Counter 0 Oscillator-Clock Control Register
++ volatile unsigned int PCLK_TCT; // 0x84 R/W 0x00014000 Timer Counter 0 Clock Control Register
++ volatile unsigned int PCLK_TCZ; // 0x88 R/W 0x00014000 Timer Counter 1 Clock Control Register
++ volatile unsigned int PCLK_LCD0; // 0x8C R/W 0x00014000 LCD0 Clock Control Register
++ volatile unsigned int PCLK_LCD1; // 0x90 R/W 0x00014000 LCD1 Clock Control Register
++ volatile unsigned int PCLK_LCDSI; // 0x94 R/W 0x00014000 LCDSI Clock Control Register
++ volatile unsigned int PCLK_CIFMC; // 0x98 R/W 0x00014000 Control Register for CIF Internal Clock
++ volatile unsigned int PCLK_CIFSC; // 0x9C R/W 0x00014000 Control Register for CIF Scaler Clock
++ volatile unsigned int PCLK_OUT0; // 0xA0 R/W 0x00014000 Control Register for External Clock Output 0
++ volatile unsigned int PCLK_OUT1; // 0xA4 R/W 0x00014000 Control Register for External Clock Output 1
++ volatile unsigned int PCLK_HDMI; // 0xA8 R/W 0x00014000 Control Register for HDMI PHY Input Clock
++ volatile unsigned int PCLK_USB11H; // 0xAC R/W 0x00014000 Control Register for USB 1.1 Host
++ volatile unsigned int PCLK_SDMMC0; // 0xB0 R/W 0x00014000 Control Register for SD/MMC Channel 0
++ volatile unsigned int PCLK_MSTICK; // 0xB4 R/W 0x00014000 Memory Stick Clock Control Register
++ volatile unsigned int PCLK_I2C; // 0xB8 R/W 0x00014000 I2C Clock Control Register
++ volatile unsigned int PCLK_UART0; // 0xBC R/W 0x00014000 UART0 Clock Control Register
++ volatile unsigned int PCLK_UART1; // 0xC0 R/W 0x00014000 UART1 Clock Control Register
++ volatile unsigned int PCLK_UART2; // 0xC4 R/W 0x00014000 UART2 Clock Control Register
++ volatile unsigned int PCLK_UART3; // 0xC8 R/W 0x00014000 UART3 Clock Control Register
++ volatile unsigned int PCLK_UART4; // 0xCC R/W 0x00014000 UART4 Clock Control Register
++ volatile unsigned int PCLK_UART5; // 0xD0 R/W 0x00014000 UART5 Clock Control Register
++ volatile unsigned int PCLK_GPSB0; // 0xD4 R/W 0x00014000 Control Register for GPSB Channel 0
++ volatile unsigned int PCLK_GPSB1; // 0xD8 R/W 0x00014000 Control Register for GPSB Channel 1
++ volatile unsigned int PCLK_GPSB2; // 0xDC R/W 0x00014000 Control Register for GPSB Channel 2
++ volatile unsigned int PCLK_GPSB3; // 0xE0 R/W 0x00014000 Control Register for GPSB Channel 3
++ volatile unsigned int PCLK_GPSB4; // 0x0E4 R/W 0x14000000 Control Register for GPSB Channel 4
++ volatile unsigned int PCLK_GPSB5; // 0xE8 R/W 0x00014000 Control Register for GPSB Channel 5
++ volatile unsigned int PCLK_ADC; // 0xEC R/W 0x00014000 Control Register for ADC (Touch Screen)
++ volatile unsigned int PCLK_SPDIF; // 0xF0 R/W 0x00140000 Control Register for SPDIF
++ volatile unsigned int PCLK_EHI0; // 0xF4 R/W 0x00140000 Control Register for EHI Channel 0
++ volatile unsigned int PCLK_EHI1; // 0x0F8 R/W 0x14000000 Control Register for EHI Channel 1
++ volatile unsigned int PCLK_AUD; // 0xFC R/W 0x00014000 Control Register for Audio DMA
++ volatile unsigned int PCLK_CAN ; // 0x100 R/W 0x00014000 Control Register for CAN
++ volatile unsigned int NOTDEFINE1; // 0x104 R/W 0x00140000 Reserved
++ volatile unsigned int PCLK_SDMMC1; // 0x108 R/W 0x00014000 Control Register for SD/MMC Channel 1
++ volatile unsigned int NOTDEFINE2; // 0x10C R/W 0x00014000 Reserved
++ volatile unsigned int PCLK_DAI ; // 0x110 R/W 0x00014000 Control Register for DAI (DAI Only)
++}CKC, *PCKC;
++
++/************************************************************************
++* 2. Vectored Priority Interrupt Controller Register Map(Base Addr = 0xF0401000)
++************************************************************************/
++//#define HwPIC_BASE *(volatile unsigned long *)0xF0401000
++typedef struct _PIC{
++ volatile unsigned int IEN0; // 0x000 R/W 0x00000000 Interrupt Enable0 Register
++ volatile unsigned int IEN1; // 0x004 R/W 0x00000000 Interrupt Enable1 Register
++ volatile unsigned int CLR0; // 0x008 R/W 0x00000000 Interrupt Clear0 Register
++ volatile unsigned int CLR1; // 0x00C R/W 0x00000000 Interrupt Clear1 Register
++ volatile unsigned int STS0; // 0x010 R Unknown Interrupt Status0 Register
++ volatile unsigned int STS1; // 0x014 R Unknown Interrupt Status1 Register
++ volatile unsigned int SEL0; // 0x018 R/W 0x00000000 IRQ or FIR Selection0 Register
++ volatile unsigned int SEL1; // 0x01C R/W 0x00000000 IRQ or FIR Selection1 Register
++ volatile unsigned int SRC0; // 0x020 R Unknown Source Interrupt Status0 Register
++ volatile unsigned int SRC1; // 0x024 R Unknown Source Interrupt Status1 Register
++ volatile unsigned int MSTS0; // 0x028 R 0x00000000 Masked Status0 Register
++ volatile unsigned int MSTS1; // 0x02C R 0x00000000 Masked Status1 Register
++ volatile unsigned int TIG0; // 0x030 R/W 0x00000000 Test Interrupt Generation0 Register
++ volatile unsigned int TIG1; // 0x034 R/W 0x00000000 Test Interrupt Generation1 Register
++ volatile unsigned int POL0; // 0x038 R/W 0x00000000 Interrupt Polarity0 Register
++ volatile unsigned int POL1; // 0x03C R/W 0x00000000 Interrupt Polarity1 Register
++ volatile unsigned int IRQ0; // 0x040 R 0x00000000 IRQ Raw Status0 Register
++ volatile unsigned int IRQ1; // 0x044 R 0x00000000 IRQ Raw Status1 Register
++ volatile unsigned int FIQ0; // 0x048 R Unknown FIQ Status0 Register
++ volatile unsigned int FIQ1; // 0x04C R Unknown FIQ Status1 Register
++ volatile unsigned int MIRQ0; // 0x050 R 0x00000000 Masked IRQ Status0 Register
++ volatile unsigned int MIRQ1; // 0x054 R 0x00000000 Masked IRQ Status1 Register
++ volatile unsigned int MFIQ0; // 0x058 R 0x00000000 Masked FIQ Status0 Register
++ volatile unsigned int MFIQ1; // 0x05C R 0x00000000 Masked FIQ Status1 Register
++ volatile unsigned int MODE0; // 0x060 R/W 0x00000000 Trigger Mode0 Register ? Level or Edge
++ volatile unsigned int MODE1; // 0x064 R/W 0x00000000 Trigger Mode1 Register ? Level or Edge
++ volatile unsigned int SYNC0; // 0x068 R/W 0xFFFFFFFF Synchronization Enable0 Register
++ volatile unsigned int SYNC1; // 0x06C R/W 0xFFFFFFFF Synchronization Enable1 Register
++ volatile unsigned int WKEN0; // 0x070 R/W 0x00000000 Wakeup Event Enable0 Register
++ volatile unsigned int WKEN1; // 0x074 R/W 0x00000000 Wakeup Event Enable1 Register
++ volatile unsigned int MODEA0; // 0x078 R/W 0x00000000 Both Edge or Single Edge0 Register
++ volatile unsigned int MODEA1; // 0x07C R/W 0x00000000 Both Edge or Single Edge1 Register
++ volatile unsigned int NOTDEFINE0[32]; //- 0x80-0xFC Reserved
++ volatile unsigned int INTMSK0; // 0x100 R/W 0xFFFFFFFF Interrupt Output Masking0 Register
++ volatile unsigned int INTMSK1; // 0x104 R/W 0xFFFFFFFF Interrupt Output Masking1 Register
++ volatile unsigned int ALLMSK; // 0x108 R/W 0x00000003 All Mask Register
++}PIC, *PPIC;
++
++//#define HwVIC_BASE *(volatile unsigned long *)0xF0401200
++typedef struct _VIC{
++ volatile unsigned int VAIRQ; // 0x200 R 0x800000XX IRQ Vector Register
++ volatile unsigned int VAFIQ; // 0x204 R 0x800000XX FIQ Vector Register
++ volatile unsigned int VNIRQ; // 0x208 R 0x800000XX IRQ Vector Number Register
++ volatile unsigned int VNFIQ; // 0x20C R 0x800000XX FIQ Vector Number Register
++ volatile unsigned int VCTRL; // 0x210 R/W 0x00000000 Vector Control Register
++ volatile unsigned int NOTDEFINE0[3]; // 0x214-0x218-0x21c Reserved
++ volatile unsigned int PRIO0; // 0x220 R/W 0x03020100 Priorities for Interrupt 0 ~ 3
++ volatile unsigned int PRIO1; // 0x224 R/W 0x07060504 Priorities for Interrupt 4 ~ 7
++ volatile unsigned int PRIO2; // 0x228 R/W 0x0B0A0908 Priorities for Interrupt 8 ~ 11
++ volatile unsigned int PRIO3; // 0x22C R/W 0x0F0E0D0C Priorities for Interrupt 12 ~ 15
++ volatile unsigned int PRIO4; // 0x230 R/W 0x13121110 Priorities for Interrupt 16 ~ 19
++ volatile unsigned int PRIO5; // 0x234 R/W 0x17161514 Priorities for Interrupt 20 ~ 23
++ volatile unsigned int PRIO6; // 0x238 R/W 0x1B1A1918 Priorities for Interrupt 24 ~ 27
++ volatile unsigned int PRIO7; // 0x23C R/W 0x1F1E1D1C Priorities for Interrupt 28 ~ 31
++ volatile unsigned int PRIO8; // 0x220 R/W 0x23222120 Priorities for Interrupt 32 ~ 35
++ volatile unsigned int PRIO9; // 0x224 R/W 0x27262524 Priorities for Interrupt 36 ~ 39
++ volatile unsigned int PRIO10; // 0x228 R/W 0x2B2A2928 Priorities for Interrupt 40 ~ 43
++ volatile unsigned int PRIO11; // 0x22C R/W 0x2F2E2D2C Priorities for Interrupt 44 ~ 47
++ volatile unsigned int PRIO12; // 0x230 R/W 0x33323130 Priorities for Interrupt 48 ~ 51
++ volatile unsigned int PRIO13; // 0x234 R/W 0x37363534 Priorities for Interrupt 52 ~ 55
++ volatile unsigned int PRIO14; // 0x238 R/W 0x3B3A3938 Priorities for Interrupt 56 ~ 59
++ volatile unsigned int PRIO15; // 0x23C R/W 0x3F3E3D3C Priorities for Interrupt 60 ~ 63
++
++}VIC, *PVIC;
++
++/***********************************************************************
++* 3. Timer/Counter Register Map (Base Address = 0xF0403000)
++************************************************************************/
++//#define HwTMR_BASE *(volatile unsigned long *)0xF0403000 // Timer/Counter Base Register
++typedef struct _TIMER{
++ volatile unsigned int TCFG0; // 0x00 R/W 0x00 Timer/Counter 0 Configuration Register
++ volatile unsigned int TCNT0; // 0x04 R/W 0x0000 Timer/Counter 0 Counter Register
++ volatile unsigned int TREF0; // 0x08 R/W 0xFFFF Timer/Counter 0 Reference Register
++ volatile unsigned int TMREF0; // 0x0C R/W 0x0000 Timer/Counter 0 Middle Reference Register
++ volatile unsigned int TCFG1; // 0x10 R/W 0x00 Timer/Counter 1 Configuration Register
++ volatile unsigned int TCNT1; // 0x14 R/W 0x0000 Timer/Counter 1 Counter Register
++ volatile unsigned int TREF1; // 0x18 R/W 0xFFFF Timer/Counter 1 Reference Register
++ volatile unsigned int TMREF1; // 0x1C R/W 0x0000 Timer/Counter 1 Middle Reference Register
++ volatile unsigned int TCFG2; // 0x20 R/W 0x00 Timer/Counter 2 Configuration Register
++ volatile unsigned int TCNT2; // 0x24 R/W 0x0000 Timer/Counter 2 Counter Register
++ volatile unsigned int TREF2; // 0x28 R/W 0xFFFF Timer/Counter 2 Reference Register
++ volatile unsigned int TMREF2; // 0x2C R/W 0x0000 Timer/Counter 2 Middle Reference Register
++ volatile unsigned int TCFG3; // 0x30 R/W 0x00 Timer/Counter 3 Configuration Register
++ volatile unsigned int TCNT3; // 0x34 R/W 0x0000 Timer/Counter 3 Counter Register
++ volatile unsigned int TREF3; // 0x38 R/W 0xFFFF Timer/Counter 3 Reference Register
++ volatile unsigned int TMREF3; // 0x3C R/W 0x0000 Timer/Counter 3 Middle Reference Register
++ volatile unsigned int TCFG4; // 0x40 R/W 0x00 Timer/Counter 4 Configuration Register
++ volatile unsigned int TCNT4; // 0x44 R/W 0x00000 Timer/Counter 4 Counter Register
++ volatile unsigned int TREF4; // 0x48 R/W 0xFFFFF Timer/Counter 4 Reference Register
++ volatile unsigned int NOTDEFINE0;
++ volatile unsigned int TCFG5; // 0x50 R/W 0x00 Timer/Counter 5 Configuration Register
++ volatile unsigned int TCNT5; // 0x54 R/W 0x00000 Timer/Counter 5 Counter Register
++ volatile unsigned int TREF5; // 0x58 R/W 0xFFFFF Timer/Counter 5 Reference Register
++ volatile unsigned int NOTDEFINE1;
++ volatile unsigned int TIREQ; // 0x60 R/W 0x0000 Timer/Counter n Interrupt Request Register
++ volatile unsigned int NOTDEFINE2[3];
++ volatile unsigned int TWDCFG; // 0x70 R/W 0x0000 Reserved
++ volatile unsigned int TWDCLR; // 0x74 W - Reserved
++ volatile unsigned int NOTDEFINE3[2];
++ volatile unsigned int TC32EN; // 0x80 R/W 0x00007FFF 32-bit Counter Enable / Pre-scale Value
++ volatile unsigned int TC32LDV; // 0x84 R/W 0x00000000 32-bit Counter Load Value
++ volatile unsigned int TC32CMP0; // 0x88 R/W 0x00000000 32-bit Counter Match Value 0
++ volatile unsigned int TC32CMP1; // 0x8C R/W 0x00000000 32-bit Counter Match Value 1
++ volatile unsigned int TC32PCNT; // 0x90 R/W - 32-bit Counter Current Value (pre-scale counter)
++ volatile unsigned int TC32MCNT; // 0x94 R/W - 32-bit Counter Current Value (main counter)
++ volatile unsigned int TC32IRQ; // 0x98 R/W 0x0000---- 32-bit Counter Interrupt Control
++
++}TIMER, *PTIMER;
++
++typedef struct _TIMERN{
++ volatile unsigned int TCFG; // 0x000 R/W Timer/Counter Configuration Register
++ volatile unsigned int TCNT; // 0x004 R/W Timer/Counter Counter Register
++ volatile unsigned int TREF; // 0x008 R/W Timer/Counter Reference Register
++ volatile unsigned int TMREF; // 0x00C R/W Timer/Counter Middle Reference Register
++} TIMERN, *PTIMERN;
++
++/***********************************************************************
++* 4. PMU(POWER MANAGEMENT UNIT) Register Map (Base Address = 0xF0404000)
++************************************************************************/
++//#define HwCONTROL *(volatile unsigned long *)0xF0404000 //R/W PMU Control Register
++#define PMU_PWROFF *(volatile unsigned long *)0xF0404018
++typedef struct _PMU{
++ volatile unsigned int CONTROL; // 0x00 R/W PMU Control Register
++ volatile unsigned int WKUPEN ; // 0x04 R/W Wakeup Enable Configuration Register
++ volatile unsigned int WKUPPOL ; // 0x08 R/W Wakeup Polarity Configuration Register
++ volatile unsigned int WATCHDOG; // 0x0C R/W Watchdog Control Register
++ volatile unsigned int CONFIG0 ; // 0x10 R/W Boot Configuration Register
++ volatile unsigned int USERSTS ; // 0x14 R/W Status Register
++ volatile unsigned int PWROFF ; // 0x18 R/W Power-Off Control Register
++} PMU, *PPMU;
++
++
++
++/*******************************************************************************
++* 5. SMUI2C Controller Register Define (Base Addr = 0xF0405000)
++********************************************************************************/
++//#define HwSMU_I2CMASTER0_BASE *(volatile unsigned long*)0xF0405000
++//#define HwSMU_I2CMASTER1_BASE *(volatile unsigned long*)0xF0405040
++//#define HwSMU_I2CICLK_BASE *(volatile unsigned long*)0xF0405080 //I2C_SCL divider Regist
++typedef struct _SMUI2CMASTER{
++ volatile unsigned int PRES; // 0x00 R/W 0xFFFF Clock Prescale register
++ volatile unsigned int CTRL; // 0x04 R/W 0x0000 Control Register
++ volatile unsigned int TXR; // 0x08 W 0x0000 Transmit Register
++ volatile unsigned int CMD; // 0x0C W 0x0000 Command Register
++ volatile unsigned int RXR; // 0x10 R 0x0000 Receive Register
++ volatile unsigned int SR; // 0x14 R 0x0000 Status register
++ volatile unsigned int TIME; // 0x18 R/W 0x0000 Timing Control Register
++} SMUI2CMASTER, *PSMUI2CMASTER;
++
++typedef struct _SMUI2CICLK{
++ volatile unsigned int ICLK; // 0x00 R/W 0xFFFF Clock Prescale register
++} SMUI2CICLK, *PSMUI2CICLK;
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 3 GPIO_V0.00 Dec.11 2008
++********************************************************************************/
++/************************************************************************
++* 1. GPIO Register Map (Base Address = 0xF0102000)
++************************************************************************/
++/*
++#define HwGPIO_BASE *(volatile unsigned long *)0xF0102000 //
++#define HwGPIOA_BASE *(volatile unsigned long *)0xF0102000 //
++#define HwGPIOB_BASE *(volatile unsigned long *)0xF0102040 //
++#define HwGPIOC_BASE *(volatile unsigned long *)0xF0102080 //
++#define HwGPIOD_BASE *(volatile unsigned long *)0xF01020C0 //
++#define HwGPIOE_BASE *(volatile unsigned long *)0xF0102100 //
++#define HwGPIOF_BASE *(volatile unsigned long *)0xF0102140 //
++#define HwEINTSEL_BASE *(volatile unsigned long *)0xF0102180 //
++*/
++typedef struct _GPIO{
++ volatile unsigned int GPADAT; // 0x000 R/W 0x00000000 GPA Data Register
++ volatile unsigned int GPAEN; // 0x004 R/W 0x00000000 GPA Output Enable Register
++ volatile unsigned int GPASET; // 0x008 W - OR function on GPA Output Data
++ volatile unsigned int GPACLR; // 0x00C W - BIC function on GPA Output Data
++ volatile unsigned int GPAXOR; // 0x010 W - XOR function on GPA Output Data
++ volatile unsigned int GPACD0; // 0x014 W 0x55555555 Driver strength Control 0 on GPA Output Data
++ volatile unsigned int GPACD1; // 0x018 W 0x00000000 Driver strength Control 1 on GPA Output Data
++ volatile unsigned int GPAPD0; // 0x01C W 0x55555555 Pull-Up/Down function on GPA Output Data
++ volatile unsigned int GPAPD1; // 0x020 W 0x00000000 Pull-Up/Down function on GPA Output Data
++ volatile unsigned int GPAFN0; // 0x024 W 0x00000000 Port Configuration on GPA Output Data
++ volatile unsigned int GPAFN1; // 0x028 W 0x00000000 Port Configuration on GPA Output Data
++ volatile unsigned int GPAFN2; // 0x02C W 0x00000000 Port Configuration on GPA Output Data
++ volatile unsigned int GPAFN3; // 0x030 W 0x00000000 Port Configuration on GPA Output Data
++ volatile unsigned int NOTDEFINE0[3]; // 0x034-0x03C Reserved
++ volatile unsigned int GPBDAT; // 0x040 R/W 0x00000000 GPB Data Register
++ volatile unsigned int GPBEN; // 0x044 R/W 0x00000000 GPB Output Enable Register
++ volatile unsigned int GPBSET; // 0x048 W - OR function on GPB Output Data
++ volatile unsigned int GPBCLR; // 0x04C W - BIC function on GPB Output Data
++ volatile unsigned int GPBXOR; // 0x050 W - XOR function on GPB Output Data
++ volatile unsigned int GPBCD0; // 0x054 W 0x55555555 Driver strength Control 0 on GPB Output Data
++ volatile unsigned int GPBCD1; // 0x058 W 0x00000000 Driver strength Control 1 on GPB Output Data
++ volatile unsigned int GPBPD0; // 0x05C W 0x55555555 Pull-Up/Down function on GPB Output Data
++ volatile unsigned int GPBPD1; // 0x060 W 0x00000000 Pull-Up/Down function on GPB Output Data
++ volatile unsigned int GPBFN0; // 0x064 W 0x00000000 Port Configuration on GPB Output Data
++ volatile unsigned int GPBFN1; // 0x068 W 0x00000000 Port Configuration on GPB Output Data
++ volatile unsigned int GPBFN2; // 0x06C W 0x00000000 Port Configuration on GPB Output Data
++ volatile unsigned int GPBFN3; // 0x070 W 0x00000000 Port Configuration on GPB Output Data
++ volatile unsigned int NOTDEFINE1[3]; // 0x074-0x07C Reserved
++ volatile unsigned int GPCDAT; // 0x080 R/W 0x00000000 GPC Data Register
++ volatile unsigned int GPCEN; // 0x084 R/W 0x00000000 GPC Output Enable Register
++ volatile unsigned int GPCSET; // 0x088 W - OR function on GPC Output Data
++ volatile unsigned int GPCCLR; // 0x08C W - BIC function on GPC Output Data
++ volatile unsigned int GPCXOR; // 0x090 W - XOR function on GPC Output Data
++ volatile unsigned int GPCCD0; // 0x094 W 0x55555555 Driver strength Control 0 on GPC Output Data
++ volatile unsigned int GPCCD1; // 0x098 W 0x00000000 Driver strength Control 1 on GPC Output Data
++ volatile unsigned int GPCPD0; // 0x09C W 0x55555555 Pull-Up/Down function on GPC Output Data
++ volatile unsigned int GPCPD1; // 0x0A0 W 0x00000000 Pull-Up/Down function on GPC Output Data
++ volatile unsigned int GPCFN0; // 0x0A4 W 0x00000000 Port Configuration on GPC Output Data
++ volatile unsigned int GPCFN1; // 0x0A8 W 0x00000000 Port Configuration on GPC Output Data
++ volatile unsigned int GPCFN2; // 0x0AC W 0x00000000 Port Configuration on GPC Output Data
++ volatile unsigned int GPCFN3; // 0x0B0 W 0x00000000 Port Configuration on GPC Output Data
++ volatile unsigned int NOTDEFINE2[3]; // 0x0B4-0x0BC Reserved
++ volatile unsigned int GPDDAT; // 0x0C0 R/W 0x00000000 GPD Data Register
++ volatile unsigned int GPDEN; // 0x0C4 R/W 0x00000000 GPD Output Enable Register
++ volatile unsigned int GPDSET; // 0x0C8 W - OR function on GPD Output Data
++ volatile unsigned int GPDCLR; // 0x0CC W - BIC function on GPD Output Data
++ volatile unsigned int GPDXOR; // 0x0D0 W - XOR function on GPD Output Data
++ volatile unsigned int GPDCD0; // 0x0D4 W 0x55555555 Driver strength Control 0 on GPD Output Data
++ volatile unsigned int GPDCD1; // 0x0D8 W 0x00000000 Driver strength Control 1 on GPD Output Data
++ volatile unsigned int GPDPD0; // 0x0DC W 0x55555555 Pull-Up/Down function on GPD Output Data
++ volatile unsigned int GPDPD1; // 0x0E0 W 0x00000000 Pull-Up/Down function on GPD Output Data
++ volatile unsigned int GPDFN0; // 0x0E4 W 0x00000000 Port Configuration on GPD Output Data
++ volatile unsigned int GPDFN1; // 0x0E8 W 0x00000000 Port Configuration on GPD Output Data
++ volatile unsigned int GPDFN2; // 0x0EC W 0x00000000 Port Configuration on GPD Output Data
++ volatile unsigned int GPDFN3; // 0x0F0 W 0x00000000 Port Configuration on GPD Output Data
++ volatile unsigned int NOTDEFINE3[3]; // 0x0F4-0x0FC Reserved
++ volatile unsigned int GPEDAT; // 0x100 R/W 0x00000000 GPE Data Register
++ volatile unsigned int GPEEN; // 0x104 R/W 0x00000000 GPE Output Enable Register
++ volatile unsigned int GPESET; // 0x108 W - OR function on GPE Output Data
++ volatile unsigned int GPECLR; // 0x10C W - BIC function on GPE Output Data
++ volatile unsigned int GPEXOR; // 0x110 W - XOR function on GPE Output Data
++ volatile unsigned int GPECD0; // 0x114 W 0x55555555 Driver strength Control 0 on GPE Output Data
++ volatile unsigned int GPECD1; // 0x118 W 0x00000000 Driver strength Control 1 on GPE Output Data
++ volatile unsigned int GPEPD0; // 0x11C W 0x55555555 Pull-Up/Down function on GPE Output Data
++ volatile unsigned int GPEPD1; // 0x120 W 0x00000000 Pull-Up/Down function on GPE Output Data
++ volatile unsigned int GPEFN0; // 0x124 W 0x00000000 Port Configuration on GPE Output Data
++ volatile unsigned int GPEFN1; // 0x128 W 0x00000000 Port Configuration on GPE Output Data
++ volatile unsigned int GPEFN2; // 0x12C W 0x00000000 Port Configuration on GPE Output Data
++ volatile unsigned int GPEFN3; // 0x130 W 0x00000000 Port Configuration on GPE Output Data
++ volatile unsigned int NOTDEFINE4[3]; // 0x134-0x13C Reserved
++ volatile unsigned int GPFDAT; // 0x140 R/W 0x00000000 GPF Data Register
++ volatile unsigned int GPFEN; // 0x144 R/W 0x00000000 GPF Output Enable Register
++ volatile unsigned int GPFSET; // 0x148 W - OR function on GPF Output Data
++ volatile unsigned int GPFCLR; // 0x14C W - BIC function on GPF Output Data
++ volatile unsigned int GPFXOR; // 0x150 W - XOR function on GPF Output Data
++ volatile unsigned int GPFCD0; // 0x154 W 0x55555555 Driver strength Control 0 on GPF Output Data
++ volatile unsigned int GPFCD1; // 0x158 W 0x00000000 Driver strength Control 1 on GPF Output Data
++ volatile unsigned int GPFPD0; // 0x15C W 0x55555555 Pull-Up/Down function on GPF Output Data
++ volatile unsigned int GPFPD1; // 0x160 W 0x00000000 Pull-Up/Down function on GPF Output Data
++ volatile unsigned int GPFFN0; // 0x164 W 0x00000000 Port Configuration on GPF Output Data
++ volatile unsigned int GPFFN1; // 0x168 W 0x00000000 Port Configuration on GP Output Data
++ volatile unsigned int GPFFN2; // 0x16C W 0x00000000 Port Configuration on GPF Output Data
++ volatile unsigned int GPFFN3; // 0x170 W 0x00000000 Port Configuration on GPF Output Data
++ volatile unsigned int NOTDEFINE5[4]; // 0x174-0x17C Reserved
++ volatile unsigned int EINTSEL0; // 0x184 R/W 0x00000000 External Interrupt Select Register 01
++ volatile unsigned int EINTSEL1; // 0x188 R/W 0x00000000 External Interrupt Select Register 1
++ volatile unsigned int EINTSEL2; // 0x18C R/W 0x00000000 External Interrupt Select Register 2
++ volatile unsigned int MON; // 0x190 R/W 0x00000000 System Monitor Enable Register
++ volatile unsigned int ECID0; // 0x194 R/W 0x00000000 CID output Register
++ volatile unsigned int ECID1; // 0x198 R - CID serial input Register
++ volatile unsigned int ECID2; // 0x19C R - CID parallel input 0 Register
++ volatile unsigned int ECID3; // 0x1A0 R - CID parallel input 1 Register
++}GPIO, *PGPIO;
++
++typedef struct _GPION{
++ volatile unsigned int GPDAT; // 0x000 R/W GPA Data Register
++ volatile unsigned int GPEN; // 0x004 R/W GPA Output Enable Register
++ volatile unsigned int GPSET; // 0x008 W OR function on GPA Output Data
++ volatile unsigned int GPCLR; // 0x00C W BIC function on GPA Output Data
++ volatile unsigned int GPXOR; // 0x010 W XOR function on GPA Output Data
++ volatile unsigned int GPCD0; // 0x014 W Driver strength Control 0 on GPA Output Data
++ volatile unsigned int GPCD1; // 0x018 W Driver strength Control 1 on GPA Output Data
++ volatile unsigned int GPPD0; // 0x01C W Pull-Up/Down function on GPA Output Data
++ volatile unsigned int GPPD1; // 0x020 W Pull-Up/Down function on GPA Output Data
++ volatile unsigned int GPFN0; // 0x024 W Port Configuration on GPA Output Data
++ volatile unsigned int GPFN1; // 0x028 W Port Configuration on GPA Output Data
++ volatile unsigned int GPFN2; // 0x02C W Port Configuration on GPA Output Data
++ volatile unsigned int GPFN3; // 0x030 W Port Configuration on GPA Output Data
++} GPION, *PGPION;
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 4 CORE & MEMORY BUS_V0.00 Dec.11 2008
++********************************************************************************/
++/************************************************************************
++* 3. DRAM CONTROLLER Register Map (Base Address = 0xF0301000)
++************************************************************************/
++/*
++#define HwDRAM_BASE *(volatile unsigned long *)0xF0301000 //
++#define HwDRAMM0_BASE *(volatile unsigned long *)0xF0301000 //
++#define HwDRAMM1_BASE *(volatile unsigned long *)0xF0302000 //
++#define HwDRAMMISC_BASE *(volatile unsigned long *)0xF0303000 //
++#define HwDRAMPHY_BASE *(volatile unsigned long *)0xF0304000 //
++#define HwDRAMMEMBUS_BASE *(volatile unsigned long *)0xF0305004 //
++*/
++typedef struct _DRAM{
++ volatile unsigned int STAT; // 0x000 RO - Status Register
++ volatile unsigned int CMD; // 0x004 WO - Command Register
++ volatile unsigned int DCMD; // 0x008 WO - Direct COmmnad Register
++ volatile unsigned int CFG; // 0x00C R/W 0x00010020 Configuration Register
++ volatile unsigned int REF; // 0x010 R/W 0x00000A60 Refresh Period Register
++ volatile unsigned int CAS; // 0x014 R/W 0x00000006 CAS Latency Register
++ volatile unsigned int DQSS; // 0x018 R/W 0x00000001 t_dqss Register
++ volatile unsigned int MRD; // 0x01C R/W 0x00000002 t_mrd Register
++ volatile unsigned int RAS; // 0x020 R/W 0x00000007 t_ras Register
++ volatile unsigned int RC; // 0x024 R/W 0x0000000B t_rc Register
++ volatile unsigned int RCD; // 0x028 R/W 0x0000001D t_rcd Register
++ volatile unsigned int RFC; // 0x02C R/W 0x000000212 t_rfc Register
++ volatile unsigned int RP; // 0x030 R/W 0x0000001D t_rp Register
++ volatile unsigned int RRD; // 0x034 R/W 0x00000002 t_rrd Register
++ volatile unsigned int WR; // 0x038 R/W 0x00000003 t_wr Register
++ volatile unsigned int WTR; // 0x03C R/W 0x00000002 t_wtr Register
++ volatile unsigned int XP; // 0x040 R/W 0x00000001 t_xp Register
++ volatile unsigned int XSR; // 0x044 R/W 0x0000000A t_xsr Register
++ volatile unsigned int ESR; // 0x048 R/W 0x00000014 t_esr Register
++ volatile unsigned int CFG2; // 0x04C R/W - Memory_cfg2 Register
++ volatile unsigned int CFG3; // 0x050 R/W 0x00000007 Memory_cfg3 Register
++ volatile unsigned int NOTDEFINE0[43]; // - 0x054- 0x0FC Reserved
++ volatile unsigned int ID0; // 0x100 R/W 0x00000000 AXI ID0 configuration Register
++ volatile unsigned int ID1; // 0x104 R/W 0x00000000 AXI ID1 configuration Register
++ volatile unsigned int ID2; // 0x108 R/W 0x00000000 AXI ID2 configuration Register
++ volatile unsigned int ID3; // 0x10C R/W 0x00000000 AXI ID3 configuration Register
++ volatile unsigned int ID4; // 0x110 R/W 0x00000000 AXI ID4 configuration Register
++ volatile unsigned int ID5; // 0x114 R/W 0x00000000 AXI ID5 configuration Register
++ volatile unsigned int ID6; // 0x118 R/W 0x00000000 AXI ID6 configuration Register
++ volatile unsigned int ID7; // 0x11C R/W 0x00000000 AXI ID7 configuration Register
++ volatile unsigned int ID8; // 0x120 R/W 0x00000000 AXI ID8 configuration Register
++ volatile unsigned int ID9; // 0x124 R/W 0x00000000 AXI ID9 configuration Register
++ volatile unsigned int ID10; // 0x128 R/W 0x00000000 AXI ID10 configuration Register
++ volatile unsigned int ID11; // 0x12C R/W 0x00000000 AXI ID11 configuration Register
++ volatile unsigned int ID12; // 0x130 R/W 0x00000000 AXI ID12 configuration Register
++ volatile unsigned int ID13; // 0x134 R/W 0x00000000 AXI ID13 configuration Register
++ volatile unsigned int ID14; // 0x138 R/W 0x00000000 AXI ID14 configuration Register
++ volatile unsigned int ID15; // 0x13C R/W 0x00000000 AXI ID15 configuration Register
++ volatile unsigned int NOTDEFINE1[48]; // - 0x140- 0x1FC Reserved
++ volatile unsigned int CH0; // 0x200 R/W 0x0000FF00 CHIP ID0 configuration Register
++ volatile unsigned int CH1; // 0x204 R/W 0x0000FF00 CHIP ID1 configuration Register
++ volatile unsigned int CH2; // 0x208 R/W 0x0000FF00 CHIP ID2 configuration Register
++ volatile unsigned int CH3; // 0x20C R/W 0x0000FF00 CHIP ID3 configuration Register
++}DRAM, *PDRAM;
++
++typedef struct _DRAMMX{
++ volatile unsigned int M0STAT; // 0x000 RO - Status Register
++ volatile unsigned int M0CMD; // 0x004 WO - Command Register
++ volatile unsigned int M0DCMD; // 0x008 WO - Direct COmmnad Register
++ volatile unsigned int M0CFG; // 0x00C R/W 0x00010020 Configuration Register
++ volatile unsigned int M0REF; // 0x010 R/W 0x00000A60 Refresh Period Register
++ volatile unsigned int M0CAS; // 0x014 R/W 0x00000006 CAS Latency Register
++ volatile unsigned int M0DQSS; // 0x018 R/W 0x00000001 t_dqss Register
++ volatile unsigned int M0MRD; // 0x01C R/W 0x00000002 t_mrd Register
++ volatile unsigned int M0RAS; // 0x020 R/W 0x00000007 t_ras Register
++ volatile unsigned int M0RC; // 0x024 R/W 0x0000000B t_rc Register
++ volatile unsigned int M0RCD; // 0x028 R/W 0x0000001D t_rcd Register
++ volatile unsigned int M0RFC; // 0x02C R/W 0x000000212 t_rfc Register
++ volatile unsigned int M0RP; // 0x030 R/W 0x0000001D t_rp Register
++ volatile unsigned int M0RRD; // 0x034 R/W 0x00000002 t_rrd Register
++ volatile unsigned int M0WR; // 0x038 R/W 0x00000003 t_wr Register
++ volatile unsigned int M0WTR; // 0x03C R/W 0x00000002 t_wtr Register
++ volatile unsigned int M0XP; // 0x040 R/W 0x00000001 t_xp Register
++ volatile unsigned int M0XSR; // 0x044 R/W 0x0000000A t_xsr Register
++ volatile unsigned int M0ESR; // 0x048 R/W 0x00000014 t_esr Register
++ volatile unsigned int M0CFG2; // 0x04C R/W - Memory_cfg2 Register
++ volatile unsigned int M0CFG3; // 0x050 R/W 0x00000007 Memory_cfg3 Register
++ volatile unsigned int NOTDEFINE0[43]; // - 0x054- 0x0FC Reserved
++ volatile unsigned int M0ID0; // 0x100 R/W 0x00000000 AXI ID0 configuration Register
++ volatile unsigned int M0ID1; // 0x104 R/W 0x00000000 AXI ID1 configuration Register
++ volatile unsigned int M0ID2; // 0x108 R/W 0x00000000 AXI ID2 configuration Register
++ volatile unsigned int M0ID3; // 0x10C R/W 0x00000000 AXI ID3 configuration Register
++ volatile unsigned int M0ID4; // 0x110 R/W 0x00000000 AXI ID4 configuration Register
++ volatile unsigned int M0ID5; // 0x114 R/W 0x00000000 AXI ID5 configuration Register
++ volatile unsigned int M0ID6; // 0x118 R/W 0x00000000 AXI ID6 configuration Register
++ volatile unsigned int M0ID7; // 0x11C R/W 0x00000000 AXI ID7 configuration Register
++ volatile unsigned int M0ID8; // 0x120 R/W 0x00000000 AXI ID8 configuration Register
++ volatile unsigned int M0ID9; // 0x124 R/W 0x00000000 AXI ID9 configuration Register
++ volatile unsigned int M0ID10; // 0x128 R/W 0x00000000 AXI ID10 configuration Register
++ volatile unsigned int M0ID11; // 0x12C R/W 0x00000000 AXI ID11 configuration Register
++ volatile unsigned int M0ID12; // 0x130 R/W 0x00000000 AXI ID12 configuration Register
++ volatile unsigned int M0ID13; // 0x134 R/W 0x00000000 AXI ID13 configuration Register
++ volatile unsigned int M0ID14; // 0x138 R/W 0x00000000 AXI ID14 configuration Register
++ volatile unsigned int M0ID15; // 0x13C R/W 0x00000000 AXI ID15 configuration Register
++ volatile unsigned int NOTDEFINE1[48]; // - 0x140- 0x1FC Reserved
++ volatile unsigned int M0CH0; // 0x200 R/W 0x0000FF00 CHIP ID0 configuration Register
++ volatile unsigned int M0CH1; // 0x204 R/W 0x0000FF00 CHIP ID1 configuration Register
++ volatile unsigned int M0CH2; // 0x208 R/W 0x0000FF00 CHIP ID2 configuration Register
++ volatile unsigned int M0CH3; // 0x20C R/W 0x0000FF00 CHIP ID3 configuration Register
++ volatile unsigned int NOTDEFINE2[892]; // - 0x1210- 0x1FFC Reserved
++ //0xF0302000
++ volatile unsigned int M1STAT; // 0x000 RO - Status Register
++ volatile unsigned int M1CMD; // 0x004 WO - Command Register
++ volatile unsigned int M1DCMD; // 0x008 WO - Direct COmmnad Register
++ volatile unsigned int M1CFG; // 0x00C R/W 0x00010020 Configuration Register
++ volatile unsigned int M1REF; // 0x010 R/W 0x00000A60 Refresh Period Register
++ volatile unsigned int M1CAS; // 0x014 R/W 0x00000006 CAS Latency Register
++ volatile unsigned int M1DQSS; // 0x018 R/W 0x00000001 t_dqss Register
++ volatile unsigned int M1MRD; // 0x01C R/W 0x00000002 t_mrd Register
++ volatile unsigned int M1RAS; // 0x020 R/W 0x00000007 t_ras Register
++ volatile unsigned int M1RC; // 0x024 R/W 0x0000000B t_rc Register
++ volatile unsigned int M1RCD; // 0x028 R/W 0x0000001D t_rcd Register
++ volatile unsigned int M1RFC; // 0x02C R/W 0x000000212 t_rfc Register
++ volatile unsigned int M1RP; // 0x030 R/W 0x0000001D t_rp Register
++ volatile unsigned int M1RRD; // 0x034 R/W 0x00000002 t_rrd Register
++ volatile unsigned int M1WR; // 0x038 R/W 0x00000003 t_wr Register
++ volatile unsigned int M1WTR; // 0x03C R/W 0x00000002 t_wtr Register
++ volatile unsigned int M1XP; // 0x040 R/W 0x00000001 t_xp Register
++ volatile unsigned int M1XSR; // 0x044 R/W 0x0000000A t_xsr Register
++ volatile unsigned int M1ESR; // 0x048 R/W 0x00000014 t_esr Register
++ volatile unsigned int M1CFG2; // 0x04C R/W - Memory_cfg2 Register
++ volatile unsigned int M1CFG3; // 0x050 R/W 0x00000007 Memory_cfg3 Register
++ volatile unsigned int NOTDEFINE3[43]; // - 0x054- 0x0FC Reserved
++ volatile unsigned int M1ID0; // 0x100 R/W 0x00000000 AXI ID0 configuration Register
++ volatile unsigned int M1ID1; // 0x104 R/W 0x00000000 AXI ID1 configuration Register
++ volatile unsigned int M1ID2; // 0x108 R/W 0x00000000 AXI ID2 configuration Register
++ volatile unsigned int M1ID3; // 0x10C R/W 0x00000000 AXI ID3 configuration Register
++ volatile unsigned int M1ID4; // 0x110 R/W 0x00000000 AXI ID4 configuration Register
++ volatile unsigned int M1ID5; // 0x114 R/W 0x00000000 AXI ID5 configuration Register
++ volatile unsigned int M1ID6; // 0x118 R/W 0x00000000 AXI ID6 configuration Register
++ volatile unsigned int M1ID7; // 0x11C R/W 0x00000000 AXI ID7 configuration Register
++ volatile unsigned int M1ID8; // 0x120 R/W 0x00000000 AXI ID8 configuration Register
++ volatile unsigned int M1ID9; // 0x124 R/W 0x00000000 AXI ID9 configuration Register
++ volatile unsigned int M1ID10; // 0x128 R/W 0x00000000 AXI ID10 configuration Register
++ volatile unsigned int M1ID11; // 0x12C R/W 0x00000000 AXI ID11 configuration Register
++ volatile unsigned int M1ID12; // 0x130 R/W 0x00000000 AXI ID12 configuration Register
++ volatile unsigned int M1ID13; // 0x134 R/W 0x00000000 AXI ID13 configuration Register
++ volatile unsigned int M1ID14; // 0x138 R/W 0x00000000 AXI ID14 configuration Register
++ volatile unsigned int M1ID15; // 0x13C R/W 0x00000000 AXI ID15 configuration Register
++ volatile unsigned int NOTDEFINE4[48]; // - 0x140- 0x1FC Reserved
++ volatile unsigned int M1CH0; // 0x200 R/W 0x0000FF00 CHIP ID0 configuration Register
++ volatile unsigned int M1CH1; // 0x204 R/W 0x0000FF00 CHIP ID1 configuration Register
++ volatile unsigned int M1CH2; // 0x208 R/W 0x0000FF00 CHIP ID2 configuration Register
++ volatile unsigned int M1CH3; // 0x20C R/W 0x0000FF00 CHIP ID3 configuration Register
++}DRAMMX, *PDRAMMX;
++
++typedef struct _DRAMPHY{
++ volatile unsigned int REG0; // 0x400 R/W 0x00000000 PHY Mode Control Register
++ volatile unsigned int REG1; // 0x404 R/ RW 0x00000018 DLL Control & Status Register
++ volatile unsigned int REG2; // 0x408 R/W 0x00000000 DLL Phase Detector configuration Register
++ volatile unsigned int REG3; // 0x40C R/W 0x00000000 Gate Control Register
++ volatile unsigned int REG4; // 0x410 R/W 0x00000000 Read Data Slice 0 Control Register
++ volatile unsigned int REG5; // 0x414 R/W 0x00000000 Read Data Slice 1 Control Register
++ volatile unsigned int REG6; // 0x418 RO 0x00000000 Read Data Slice 2 Control Register
++ volatile unsigned int REG7; // 0x41C R/W 0x00000000 Read Data Slice 3 Control Register
++ volatile unsigned int REG8; // 0x420 R/W 0x00000000 CLK Delay Register
++ volatile unsigned int REG9; // 0x424 R/W 0x00000000 DLL Force Lock Value Register
++ volatile unsigned int REG10; // 0x428 R/W 0x00000000 ZQ Calibration Control Register
++ volatile unsigned int REG11; // 0x42C RO 0x00000000 ZQ Calibration Status Register
++ volatile unsigned int REG12; // 0x430 R/W 0x00000000 Read Delay Register
++}DRAMPHY, *PDRAMPHY;
++
++typedef struct _DRAMMISC{
++ volatile unsigned int M0CFG0; //0x00 R/W 0x80400000 SDR/DDR SDRAM Controller Configuration Register 0
++ volatile unsigned int M0CFG1; //0x04 R/RW 0x00000018 SDR/DDR SDRAM Controller Configuration Register 1
++ volatile unsigned int NOTDEFINE0[2]; // 0x08-0x0C Reserved
++ volatile unsigned int M1CFG0; //0x10 R/W 0x80000000 DDR2 SDRAM Controller Configuration Register 0
++ volatile unsigned int M1CFG1; //0x14 R/W 0x00000000 DDR2 SDRAM Controller Configuration Register 1
++ volatile unsigned int NOTDEFINE1[2]; // - 0x18- 0x1C Reserved
++ volatile unsigned int COMMON; //0x20 R/W 0x00010103 Common Control Register
++ volatile unsigned int PHYCTRL; //0x24 R/W 0x00000000 SDRAM PHY Control Register
++ volatile unsigned int PHYTSTS; //0x28 RO 0x00000000 SDRAM PHY Status Register
++ volatile unsigned int IOCFG; //0x2C R/W 0x00000000 SDRAM IO Control Register
++}DRAMMISC, *PDRAMMISC;
++
++typedef struct _DRAMMEMBUS{
++ volatile unsigned int CKDOWN; //0x04 RW 0x00000000 Clock Enable control over memory bus com-ponents
++}DRAMMEMBUS, *PDRAMMEMBUS;
++
++/************************************************************************
++* 4-1. MISC CORE BUS CONFIGURATION REGISTERS (Base Addr = 0xF0101000)
++************************************************************************/
++//#define HwCORECFG_BASE *(volatile unsigned long *)0xF0101000 ************************************************************************/
++typedef struct _MISCCOREBUS{
++ volatile unsigned int CORECFG; //R/W 0x90000000 Core Bus Configuration Register
++}MISCCOREBUS, *PMISCCOREBUS;
++
++/************************************************************************
++* 4-2. Virtual MMU Table Register Define (Base Addr = 0xF7000000)
++************************************************************************/
++//#define HwVMT_BASE *(volatile unsigned long *)0x20000000 // VMT Base Regiseter
++//#define HwREGION_BASE *(volatile unsigned long *)0xF7000000 // R/W, Configuration Register for Region 0
++
++typedef struct _VMTREGION{
++ volatile unsigned int REGION0; // 0x00 R/W - Configuration Register for Region 0
++ volatile unsigned int REGION1; // 0x04 R/W - Configuration Register for Region 1
++ volatile unsigned int REGION2; // 0x08 R/W - Configuration Register for Region 2
++ volatile unsigned int REGION3; // 0x0C R/W - Configuration Register for Region 3
++ volatile unsigned int REGION4; // 0x10 R/W - Configuration Register for Region 4
++ volatile unsigned int REGION5; // 0x14 R/W - Configuration Register for Region 5
++ volatile unsigned int REGION6; // 0x18 R/W - Configuration Register for Region 6
++ volatile unsigned int REGION7; // 0x1C R/W - Configuration Register for Region 7
++}VMTREGION, *PVMTREGION;
++
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 5 IO BUS_V0.00 Dec.11 2008
++********************************************************************************/
++/*******************************************************************************
++* 4. Memory Stick Host Controller Register Define (Base Addr = 0xF0590000)
++********************************************************************************/
++//#define HwSMSHC_BASE *(volatile unsigned long*)0xF0590000
++//#define HwSMSHCPORTCFG_BASE *(volatile unsigned long*)0xF05F1000
++typedef struct _SMSHC{
++ volatile unsigned int MS_CONTROL_PROGRAMCOUNTREG; // 0x00 // R/W 0x0070_1000
++ volatile unsigned int MS_SYSTEMREG; // 0x04 // R/W 0x0800_XXXX
++ volatile unsigned int MS_FLAGREG; // 0x08 // R 0x4000_XXXX
++ volatile unsigned int MS_MEMORY_CONTROLREG; // 0x0C // R/W 0x0001_7000
++ volatile unsigned int MS_GENERALREG01; // 0x10 // R/W 0x8000_9000
++ volatile unsigned int MS_GENERALREG23; // 0x14 // R/W 0xA000_B000
++ volatile unsigned int MS_GENERALREG45; // 0x18 // R/W 0xC000_D000
++ volatile unsigned int MS_TIMERREG; // 0x1C // R 0xE000XXXX
++ volatile unsigned int MS_INSTRUCTIONREG; // 0x20 // R/W 0xXXXX_XXXX
++ volatile unsigned int MS_GENERALDATAFIFO; // 0x24 // R/W 0x0000_0000
++ volatile unsigned int MS_PAGEBUFFER; // 0x28 // R/W 0xXXXX_XXXX
++ volatile unsigned int MS_VERSIONREG; // 0x2C // R 0xXXXX_XXXX
++ volatile unsigned int MS_MSHC_COMMANDREG; // 0x30 // R/W 0x0000_XXXX
++ volatile unsigned int MS_MSHC_DATAREG; // 0x34 // R/W 0x0000_0000
++ volatile unsigned int MS_MSHC_STATUSREG; // 0x38 // R 0x1000_XXXX
++ volatile unsigned int MS_MSHC_SYSTEMREG; // 0x3C // R/W 0x20A5_XXXX
++ volatile unsigned int MS_MSHC_USERCUSTOMREG; // 0x40 // R 0x0220_XXXX
++ volatile unsigned int MS_MSHC_FIFOCTRLREG; // 0x44 // R/W 0x0001_XXXX
++ volatile unsigned int NOTDEFINE0; //
++ volatile unsigned int MS_MSHC_DMACTRLREG; // 0x4C // R/W 0x0000_XXXX
++}SMSHC, *PSMSHC;
++
++typedef struct _SMSHCPORTCFG{
++ volatile unsigned int MS_PORTCFG; // 0xF05F1000 // R/W 0x00000000
++ volatile unsigned int MS_PORTDLY; // 0xF05F1004 // R/W 0x00000000
++}SMSHCPORTCFG, *PSMSHCPORTCFG;
++
++/*******************************************************************************
++* 5. SD/SDIO/MMC/CE-ATA Host Controller Register Define (Base Addr = 0xF0590000)
++********************************************************************************/
++/*
++#define HwSDCORE0SLOT0_BASE *(volatile unsigned long*)0xF05A0000 // Core 0 Slot 0
++#define HwSDCORE0SLOT1_BASE *(volatile unsigned long*)0xF05A0100 // Core 0 Slot 1
++#define HwSDCORE1SLOT2_BASE *(volatile unsigned long*)0xF05A0200 // Core 1 Slot 2
++#define HwSDCORE1SLOT3_BASE *(volatile unsigned long*)0xF05A0300 // Core 1 Slot 3
++#define HwSDCHCTRL_BASE *(volatile unsigned long*)0xF05A0800 // Channel Control Register
++*/
++typedef struct _SDHOST{
++ volatile unsigned short SDMA; // 0x000 R/W 0x0000 SDMA System Address
++ volatile unsigned short NOTDEFINE0; // 0x002
++ volatile unsigned short BSIZE; // 0x004 R/W 0x0000 Block Size
++ volatile unsigned short BCNT; // 0x006 R/W 0x0000 Block Count
++ volatile unsigned short ARG; // 0x008 R/W 0x0000 Argument
++ volatile unsigned short NOTDEFINE1; // 0x00A
++ volatile unsigned short TMODE; // 0x00C R/W 0x0000 Transfer Mode
++ volatile unsigned short CMD; // 0x00E R/W 0x0000 Command
++ volatile unsigned short RESP0; // 0x010 R 0x0000 Response0
++ volatile unsigned short RESP1; // 0x012 R 0x0000 Response1
++ volatile unsigned short RESP2; // 0x014 R 0x0000 Response2
++ volatile unsigned short RESP3; // 0x016 R 0x0000 Response3
++ volatile unsigned short RESP4; // 0x018 R 0x0000 Response4
++ volatile unsigned short RESP5; // 0x01A R 0x0000 Response5
++ volatile unsigned short RESP6; // 0x01C R 0x0000 Response6
++ volatile unsigned short RESP7; // 0x01E R 0x0000 Response7
++ volatile unsigned short DATAL; // 0x020 R/W - Buffer Data Port(Low)
++ volatile unsigned short DATAH; // 0x022 R/W - Buffer Data Port(High)
++ volatile unsigned short STATEL; // 0x024 R 0x0000 Present State(Low)
++ volatile unsigned short STATEH; // 0x026 R 0x0000 Present State(High)
++ volatile unsigned short CONTL; // 0x028 R/W 0x0000 Power Control / Host Control
++ volatile unsigned short CONTH; // 0x02A R/W 0x0000 Wakeup Control / Block Gap Control
++ volatile unsigned short CLK; // 0x02C R/W 0x0000 Clock Control
++ volatile unsigned short TIME; // 0x02E R/W 0x0000 Software Reset / Timeout Control
++ volatile unsigned short STSL; // 0x030 R 0x0000 Normal Interrupt Status(Low)
++ volatile unsigned short STSH; // 0x032 R 0x0000 Normal Interrupt Status(High)
++ volatile unsigned short STSENL; // 0x034 R/W 0x0000 Normal Interrupt Status Enable(Low)
++ volatile unsigned short STSENH; // 0x036 R/W 0x0000 Normal Interrupt Status Enable(High)
++ volatile unsigned short INTENL; // 0x038 R/W 0x0000 Normal Interrupt Signal Enable(Low)
++ volatile unsigned short INTENH; // 0x03A R/W 0x0000 Normal Interrupt Signal Enable(High)
++ volatile unsigned short CMD12ERR; // 0x03C R 0x0000 Auto CMD12 Error Status
++ volatile unsigned short NOTDEFINE2; // 0x03E
++ volatile unsigned short CAPL; // 0x040 R 0x30B0 Capabilities(Low)
++ volatile unsigned short CAPH; // 0x042 R 0x69EF Capabilities(High)
++ volatile unsigned short NOTDEFINE3[2]; // 0x044, 0x046
++ volatile unsigned short CURL; // 0x048 R 0x0001 Maximum Current Capabilities(Low)
++ volatile unsigned short CURH; // 0x04A R 0x0000 Maximum Current Capabilities(High)
++ volatile unsigned short NOTDEFINE4[2]; // 0x04C, 0x04E
++ volatile unsigned short FORCEL; // 0x050 W 0x0000 Force event for AutoCmd12 Error
++ volatile unsigned short FORCEH; // 0x052 W 0x0000 Force event for Error Interrupt Status
++ volatile unsigned short AUDIO_DMAERR; // 0x054 R/W 0x0000 AUDIO DMA Error Status
++ volatile unsigned short NOTDEFINE5; // 0x056
++ volatile unsigned short ADDR0; // 0x058 R/W 0x0000 AUDIO DMA Address[15:0]
++ volatile unsigned short ADDR1; // 0x05A R/W 0x0000 AUDIO DMA Address[31:16]
++ volatile unsigned short ADDR2; // 0x05C R/W 0x0000 AUDIO DMA Address[47:32]
++ volatile unsigned short ADDR3; // 0x05E R/W 0x0000 AUDIO DMA Address[63:48]
++ volatile unsigned short NOTDEFINE6[78]; // 0x060~0x0FA
++ volatile unsigned short SLOT; // 0x0FC R 0x0000 Slot Interrupt Status
++ volatile unsigned short VERSION; // 0x0FE R 0x0002 Host Controller Version
++}SDHOST, *PSDHOST;
++
++typedef struct _SDCHCTRL{
++ volatile unsigned int SDPORTCTRL; // 0x00 R/W 0x0000 SD/MMC port control register
++ volatile unsigned int SDPORTDLY0; // 0x04 R/W 0x0000 SD/MMC output delay control register
++ volatile unsigned int SDPORTDLY1; // 0x08 R/W 0x0000 SD/MMC output delay control register
++ volatile unsigned int SDPORTDLY2; // 0x0C R/W 0x0000 SD/MMC output delay control register
++ volatile unsigned int SDPORTDLY3; // 0x10 R/W 0x0000 SD/MMC output delay control register
++}SDCHCTRL, *PSDCHCTRL;
++
++
++/*******************************************************************************
++* 6. NAND Flash Controller(NFC) Register Define (Base Addr = 0xF05B0000)
++********************************************************************************/
++//#define HwNFC_BASE *(volatile unsigned long*)0xF05B0000
++
++typedef struct _NFC{
++ volatile unsigned int NFC_CMD; // 0x000 W NAND Flash Command Register
++ volatile unsigned int NFC_LADDR; // 0x004 W NAND Flash Linear Address Register
++ volatile unsigned int NFC_BADDR; // 0x008 W NAND Flash Block Address Register
++ volatile unsigned int NFC_SADDR; // 0x00C W NAND Flash Signal Address Register
++ volatile unsigned int NFC_WDATA; // 0x01x R/W NAND Flash Word Data Register
++ volatile unsigned int NOTDEFINE0[3]; // 0x01x R/W NAND Flash Word Data Register
++ volatile unsigned int NFC_LDATA; // 0x02x/3x R/W NAND Flash Linear Data Register
++ volatile unsigned int NOTDEFINE1[7]; // 0x01x R/W NAND Flash Word Data Register
++ volatile unsigned int NFC_SDATA; // 0x040 R/W NAND Flash Single Data Register
++ volatile unsigned int NOTDEFINE2[3]; // 0x044 Not Used
++ volatile unsigned int NFC_CTRL; // 0x050 R/W NAND Flash Control Register
++ volatile unsigned int NFC_PSTART; // 0x054 W NAND Flash Program Start Register
++ volatile unsigned int NFC_RSTART; // 0x058 W NAND Flash Read Start Register
++ volatile unsigned int NFC_DSIZE; // 0x05C R/W NAND Flash Data Size Register
++ volatile unsigned int NFC_IREQ; // 0x060 R/W NAND Flash Interrupt Request Register
++ volatile unsigned int NFC_RST; // 0x064 W NAND Flash Controller Reset Register
++ volatile unsigned int NFC_CTRL1; // 0x068 R/W NAND Flash Control Register 1
++ volatile unsigned int NOTDEFINE3; // 0x06C Not Used
++ volatile unsigned int NFC_MDATA[4]; // 0x07x R/W NAND Flash Multiple Data Register
++}NFC, *PNFC;
++
++/*******************************************************************************
++* 7. Static Memory Controller(SMC) Register Define (Base Addr = 0xF05F0000)
++********************************************************************************/
++//#define HwSMC_BASE *(volatile unsigned long*)0xF05F0000
++typedef struct _SMC{
++ volatile unsigned int STATUS; // 0x00 R/W Unknown Status Register
++ volatile unsigned int NOTDEFINE0[7];
++ volatile unsigned int CSNCFG0; // 0x20 R 0x4b40_3183 External Chip Select0 Config Register
++ volatile unsigned int CSNCFG1; // 0x24 R/W 0x4b40_1104 External Chip Select1 Config Register
++ volatile unsigned int CSNCFG2; // 0x28 W 0x4b40_4082 External Chip Select2 Config Register
++ volatile unsigned int CSNCFG3; // 0x2C R/W 0x4b40_20C5 External Chip Select3 Config. Register
++ volatile unsigned int CSNOFFSET; // 0x30 R/W 0x0 Wapping Address Mode OFFSET Register
++ volatile unsigned int INDIRADDR; // 0x34 R/W 0x0 Indirect Address
++}SMC, *PSMC;
++
++/*******************************************************************************
++* 8. External Device Interface (EDI) Register Define (Base Addr = 0xF05F6000)
++********************************************************************************/
++//#define HwEDI_BASE *(volatile unsigned long*)0xF05F6000
++
++typedef struct _EDI{
++ volatile unsigned int EDI_CTRL; // 0x00 R/W 0x00000000 EDI Control Register.
++ volatile unsigned int EDI_CSNCFG0; // 0x04 R/W 0x00543210 EDI CSN Configuration Register 0.
++ volatile unsigned int EDI_CSNCFG1; // 0x08 R/W 0x00BA9876 EDI CSN Configuration Register 1.
++ volatile unsigned int NOTDEFINE0[2]; // Reserved 0x0C R/W - -
++ volatile unsigned int EDI_RDYCFG; // 0x14 R/W 0x76543210 EDI Ready Configuration Register
++ volatile unsigned int NOTDEFINE1[2]; // Reserved 0x18 R/W 0x00000000 EDI Time-Out Configuration Register 0
++ volatile unsigned int EDI_REQOFF; // 0x20 R/W 0x00000000 EDI Request OFF Flag register
++}EDI, *PEDI;
++
++/*******************************************************************************
++* 9. IDE Controller Register Define (Base Addr = 0xF0520000)
++********************************************************************************/
++//#define HwIDE_BASE *(volatile unsigned long*)0xF05F6000
++
++typedef struct _IDE{
++ volatile unsigned int CS00; // 0x00 R/W - PIO CS0n Access Register
++ volatile unsigned int CS01; // 0x04
++ volatile unsigned int CS02; // 0x08
++ volatile unsigned int CS03; // 0x0C
++ volatile unsigned int CS04; // 0x10
++ volatile unsigned int CS05; // 0x14
++ volatile unsigned int CS06; // 0x18
++ volatile unsigned int CS07; // 0x1C
++ volatile unsigned int CS10; // 0x20 R/W - PIO CS1n Access Register
++ volatile unsigned int CS11; // 0x24
++ volatile unsigned int CS12; // 0x28
++ volatile unsigned int CS13; // 0x2C
++ volatile unsigned int CS14; // 0x30
++ volatile unsigned int CS15; // 0x34
++ volatile unsigned int CS16; // 0x38
++ volatile unsigned int CS17; // 0x3C
++ volatile unsigned int PIOCTRL; // 0x40 R/W 0x00600000 PIO Mode Control Register
++ volatile unsigned int UDMACTRL; // 0x44 R/W 0x00000000 UDMA Mode Control Register
++ volatile unsigned int IDMACTRL; // 0x48 R/W 0x00000000 IDMA Control Register
++ volatile unsigned int IDMASA; // 0x4C R/W 0x00000000 IDMA Source Address Register
++ volatile unsigned int IDMASP; // 0x50 R/W 0x00000000 IDMA Source Parameter Register
++ volatile unsigned int IDMACSA; // 0x54 R 0x00000000 IDMA Current Source Address Register
++ volatile unsigned int IDMADA; // 0x58 R/W 0x00000000 IDMA Destination Address Register
++ volatile unsigned int IDMADP; // 0x5C R/W 0x00000000 IDMA Destination Parameter Register
++ volatile unsigned int IDMACDA; // 0x60 R 0x00000000 IDMA Current Destination Address Register
++ volatile unsigned int IDEINT; // 0x64 R/W 0x0000_0000 IDE Interrupt Register
++ volatile unsigned int UDMATCNT; // 0x68 R/W 0x00FF_FFFF UDMA Transfer Counter Register
++ volatile unsigned int UDMAIN; // 0x6C R - UDMA-IN Access Register
++ volatile unsigned int UDMAOUT; // 0x70 W - UDMA-OUT Access register
++ volatile unsigned int UDMACRC; // 0x74 R 0x0000_4ABA UDMA CRC Register
++ volatile unsigned int UDMACTCNT; // 0x78 R 0x00FF_FFFF UDMA Current Transfer Counter Register
++}IDE, *PIDE;
++
++
++/*******************************************************************************
++* 10. SATA Interface Register Define (Base Addr = 0xF0560000)
++********************************************************************************/
++//#define HwSATA_BASE *(volatile unsigned long*)0xF0560000
++
++typedef struct _SATA{
++ volatile unsigned int CDR0; // 0x00 16 RO/WO - Data register in PIO mode Dependencies: Read-only for PIO read/receive operation, write-only for PIO write/transmit operation
++ volatile unsigned int CDR1; // 0x04 8/8/8 RO/WO/WO 0xFF/0x00/0x00 Error register Feature Register(currnet value) Feature Expanded Register(previouis value)
++ volatile unsigned int CDR2; // 0x08 8/8 R/W 0xFF Sector count register (current value) Sector count expanded register (previous value)
++ volatile unsigned int CDR3; // 0x0C 8/8 R/W 0xFF Sector number register (current value) Sector number expanded register (previous value)
++ volatile unsigned int CDR4; // 0x10 8/8 R/W 0xFF Cylinder low register (current value) Cylinder low expanded register (previous value)
++ volatile unsigned int CDR5; // 0x14 8/8 R/W 0xFF Cylinder high register (current value) Cylinder high expanded register (previous value)
++ volatile unsigned int CDR6; // 0x18 8 R/W 0xEF Device/ Head register
++ volatile unsigned int CDR7; // 0x1C 8/8 RO/WO 0x7F/0x00 Status register Dependencies: Value is 0x7F on power-up, then 0x80 when device presence is detected via PHY READY condition. Command register
++ volatile unsigned int CLR0; // 0x20 8/8 RO/WO 0x7F/0x00 Alternative status register Dependencies: Value is 0x7F on power-up, then 0x80 when device presence is detected via PHY READY condition. Device control register
++ volatile unsigned int SCR0; // 0x24 32 RO 0x0 SStatus Register
++ volatile unsigned int SCR1; // 0x28 32 R/W 0x0 SError Register
++ volatile unsigned int SCR2; // 0x2C 32 R/W 0x0 SControl Register
++ volatile unsigned int SCR3; // 0x30 32 R/W 0x0 SActive Register
++ volatile unsigned int SCR4; // 0x34 32 R/W 0x0 Snotification Register
++ volatile unsigned int SCR5; // 0x38
++ volatile unsigned int SCR6; // 0x3C
++ volatile unsigned int SCR7; // 0x40
++ volatile unsigned int SCR8; // 0x44
++ volatile unsigned int SCR9; // 0x48
++ volatile unsigned int SCR10; // 0x4C
++ volatile unsigned int SCR11; // 0x50
++ volatile unsigned int SCR12; // 0x54
++ volatile unsigned int SCR13; // 0x58
++ volatile unsigned int SCR14; // 0x5C
++ volatile unsigned int SCR15; // 0x60 See description 0x0 Reserved for SATA Dependencies: Reads to these locations return zeros; writes have no effect
++ volatile unsigned int FPTAGR; // 0x64 32 RO 0x0 First Party DMA tag Register
++ volatile unsigned int FPBOR; // 0x68 32 RO 0x0 First Party DMA buffer offset Register
++ volatile unsigned int FPTCR; // 0x6C 32 RO 0x0 First Party DMA transfer count Register
++ volatile unsigned int DMACR; // 0x70 32 R/W 0x0 DMA Control Register
++ volatile unsigned int DBTSR; // 0x74 32 R/W 0x0014 _0010 DMA Burst Transaction Size register
++ volatile unsigned int INTPR; // 0x78 32 R/W 0x0 Interrupt Pending Register
++ volatile unsigned int INTMR; // 0x7C 32 RO 0x0 Interrupt Mask Register
++ volatile unsigned int ERRMR; // 0x80 32 RO 0x0 Error Mask Register
++ volatile unsigned int LLCR; // 0x84 32 R/W 0x0000 _0007 Link Layer Control Register
++ volatile unsigned int NOTDEFINE0[222]; //0x88 ~ 0x3FC
++ volatile unsigned int DMADR[256]; // 0x400-0x7FC FIFO Location in DMA mode
++}SATA, *PSATA;
++
++
++/*******************************************************************************
++* 11-1. Audio DMA Controller Register Define (Base Addr = 0xF0533000)
++********************************************************************************/
++//#define HwADMA_BASE *(volatile unsigned long*)0xF0533000
++
++typedef struct _ADMA{
++ volatile unsigned int RxDaDar; // 0x00 R/W 0x00000000 DAI Rx (Right) Data Destination Address
++ volatile unsigned int RxDaParam; // 0x04 R/W 0x00000000 DAI Rx Parameters
++ volatile unsigned int RxDaTCnt; // 0x08 R/W 0x00000000 DAI Rx Transmission Counter Register
++ volatile unsigned int RxDaCdar; // 0x0C R 0x00000000 DAI Rx (Right) Data Current Destination Address
++ volatile unsigned int RxCdDar; // 0x10 R/W 0x00000000 CDIF(SPDIF) Rx (Right) Data Destination Address
++ volatile unsigned int RxCdParam; // 0x14 R/W 0x00000000 CDIF(SPDIF) Rx Parameters
++ volatile unsigned int RxCdTCnt; // 0x18 R/W 0x00000000 CDIF(SPDIF) Rx Transmission Counter Register
++ volatile unsigned int RxCdCdar; // 0x1C R 0x00000000 CDIF(SPDIF) Rx (Right) Data Current Destination Address
++ volatile unsigned int NOTDEFINE0[2];
++ volatile unsigned int RxDaDarL; // 0x28 R/W 0x00000000 DAI Rx Left Data Destination Address
++ volatile unsigned int RxDaCdarL; // 0x2C R 0x00000000 DAI Rx Left Data Current Destination Address
++ volatile unsigned int RxCdDarL; // 0x30 R/W 0x00000000 CDIF(SPDIF) Rx Left Data Destination Address
++ volatile unsigned int RxCdCdarL; // 0x34 R 0x00000000 CDIF(SPDIF) Rx Left Data Current Destination Address
++ volatile unsigned int TransCtrl; // 0x38 R/W 0x0000AA00 DMA Transfer Control Register
++ volatile unsigned int RptCtrl; // 0x3C R/W 0x00000000 DMA Repeat Control Register
++ volatile unsigned int TxDaSar; // 0x40 R/W 0x00000000 DAI Tx (Right) Data Source Address
++ volatile unsigned int TxDaParam; // 0x44 R/W 0x00000000 DAI Tx Parameters
++ volatile unsigned int TxDaTCnt; // 0x48 R/W 0x00000000 DAI Tx Transmission Counter Register
++ volatile unsigned int TxDaCsar; // 0x4C R 0x00000000 DAI Tx (Right) Data Current Source Address
++ volatile unsigned int TxSpSar; // 0x50 R/W 0x00000000 SPDIF Tx (Right) Data Source Address
++ volatile unsigned int TxSpParam; // 0x54 R/W 0x00000000 SPDIF Tx Parameters
++ volatile unsigned int TxSpTCnt; // 0x58 R/W 0x00000000 SPDIF Tx Transmission Counter Register
++ volatile unsigned int TxSpCsar; // 0x5C R 0x00000000 SPDIF Tx (Right) Data Current Source Address
++ volatile unsigned int NOTDEFINE1[2];
++ volatile unsigned int TxDaSarL; // 0x68 R/W 0x00000000 DAI Tx Left Data Source Address
++ volatile unsigned int TxDaCsarL; // 0x6C R 0x00000000 DAI Tx Left Data Current Source Address
++ volatile unsigned int TxSpSarL; // 0x70 R/W 0x00000000 SPDIF Tx Left Data Source Address
++ volatile unsigned int TxSpCsarL; // 0x74 R 0x00000000 SPDIF Tx Left Data Current Source address
++ volatile unsigned int ChCtrl; // 0x78 R/W 0x00008000 DMA Channel Control Register
++ volatile unsigned int IntStatus; // 0x7C R/W 0x00000000 DMA Interrupt Status Register
++ volatile unsigned int GIntReq; // 0x80 R/W 0x00000000 General Interrupt Request
++ volatile unsigned int GIntStatus; // 0x84 R 0x00000000 General Interrupt Status
++ volatile unsigned int NOTDEFINE2[6];
++ volatile unsigned int RxDaDar1; // 0x100 R/W 0x00000000 DAI1 Rx (Right) Data Destination Address
++ volatile unsigned int RxDaDar2; // 0x104 R/W 0x00000000 DAI2 Rx (Right) Data Destination Address
++ volatile unsigned int RxDaDar3; // 0x108 R/W 0x00000000 DAI3 Rx (Right) Data Destination Address
++ volatile unsigned int RxDaCar1; // 0x10C R 0x00000000 DAI1 Rx (Right) Data Current Destination Address
++ volatile unsigned int RxDaCar2; // 0x110 R 0x00000000 DAI2 Rx (Right) Data Current Destination Address
++ volatile unsigned int RxDaCar3; // 0x114 R 0x00000000 DAI3 Rx (Right) Data Current Destination Address
++ volatile unsigned int RxDaDarL1; // 0x118 R/W 0x00000000 DAI1 Rx Left Data Destination Address
++ volatile unsigned int RxDaDarL2; // 0x11C R/W 0x00000000 DAI2 Rx Left Data Destination Address
++ volatile unsigned int RxDaDarL3; // 0x120 R/W 0x00000000 DAI3 Rx Left Data Destination Address
++ volatile unsigned int RxDaCarL1; // 0x124 R 0x00000000 DAI1 Rx Left Data Current Destination Address
++ volatile unsigned int RxDaCarL2; // 0x128 R 0x00000000 DAI2 Rx Left Data Current Destination Address
++ volatile unsigned int RxDaCarL3; // 0x12C R 0x00000000 DAI3 Rx Left Data Current Destination Address
++ volatile unsigned int TxDaSar1; // 0x130 R/W 0x00000000 DAI1 Tx (Right) Data Source Address
++ volatile unsigned int TxDaSar2; // 0x134 R/W 0x00000000 DAI2 Tx (Right) Data Source Address
++ volatile unsigned int TxDaSar3; // 0x138 R/W 0x00000000 DAI3 Tx (Right) Data Source Address
++ volatile unsigned int TxDaCsar1; // 0x13C R 0x00000000 DAI1 Tx (Right) Data Current Source Address
++ volatile unsigned int TxDaCsar2; // 0x140 R 0x00000000 DAI2 Tx (Right) Data Current Source Address
++ volatile unsigned int TxDaCsar3; // 0x144 R 0x00000000 DAI3 Tx (Right) Data Current Source Address
++ volatile unsigned int TxDaDarL1; // 0x148 R/W 0x00000000 DAI1 Tx Left Data Source Address
++ volatile unsigned int TxDaDarL2; // 0x14C R/W 0x00000000 DAI2 Tx Left Data Source Address
++ volatile unsigned int TxDaDarL3; // 0x150 R/W 0x00000000 DAI3 Tx Left Data Source Address
++ volatile unsigned int TxDaCarL1; // 0x154 R 0x00000000 DAI1 Tx Left Data Current Source Address
++ volatile unsigned int TxDaCarL2; // 0x158 R 0x00000000 DAI2 Tx Left Data Current Source Address
++ volatile unsigned int TxDaCarL3; // 0x15C R 0x00000000 DAI3 Tx Left Data Current Source Address
++}ADMA, *PADMA;
++
++
++/*******************************************************************************
++* 11-2. DAI Register Define (Base Addr = 0xF0534000)
++********************************************************************************/
++//#define HwADMA_DAIBASE *(volatile unsigned long*)0xF0534000
++
++typedef struct _ADMADAI{
++ volatile unsigned int DADIR0; // 0x00 R - Digital Audio Input Register 0
++ volatile unsigned int DADIR1; // 0x04 R - Digital Audio Input Register 1
++ volatile unsigned int DADIR2; // 0x08 R - Digital Audio Input Register 2
++ volatile unsigned int DADIR3; // 0x0C R - Digital Audio Input Register 3
++ volatile unsigned int DADIR4; // 0x10 R - Digital Audio Input Register 4
++ volatile unsigned int DADIR5; // 0x14 R - Digital Audio Input Register 5
++ volatile unsigned int DADIR6; // 0x18 R - Digital Audio Input Register 6
++ volatile unsigned int DADIR7; // 0x1C R - Digital Audio Input Register 7
++ volatile unsigned int DADOR0; // 0x20 R/W - Digital Audio Output Register 0
++ volatile unsigned int DADOR1; // 0x24 R/W - Digital Audio Output Register 1
++ volatile unsigned int DADOR2; // 0x28 R/W - Digital Audio Output Register 2
++ volatile unsigned int DADOR3; // 0x2C R/W - Digital Audio Output Register 3
++ volatile unsigned int DADOR4; // 0x30 R/W - Digital Audio Output Register 4
++ volatile unsigned int DADOR5; // 0x34 R/W - Digital Audio Output Register 5
++ volatile unsigned int DADOR6; // 0x38 R/W - Digital Audio Output Register 6
++ volatile unsigned int DADOR7; // 0x3C R/W - Digital Audio Output Register 7
++ volatile unsigned int DAMR; // 0x40 R/W 0x00000000 Digital Audio Mode Register
++ volatile unsigned int DAVC; // 0x44 R/W 0x0000 Digital Audio Volume Control Register
++ volatile unsigned int MCCR0; // 0x48 R/W 0x00000000 Multi Channel Control Register 0
++ volatile unsigned int MCCR1; // 0x4C R/W 0x00000000 Multi Channel Control Register 1
++}ADMADAI, *PADMADAI;
++
++
++
++/*******************************************************************************
++* 11-3. CDIF Register Define (Base Addr = 0xF0534000)
++********************************************************************************/
++//#define HwADMA_CDIFBASE *(volatile unsigned long*)0xF0534080
++
++typedef struct _ADMACDIF{
++ volatile unsigned int CDDI_0; // 0x80 R CD Digital Audio Input Register 0
++ volatile unsigned int CDDI_1; // 0x84 R CD Digital Audio Input Register 1
++ volatile unsigned int CDDI_2; // 0x88 R CD Digital Audio Input Register 2
++ volatile unsigned int CDDI_3; // 0x8C R CD Digital Audio Input Register 3
++ volatile unsigned int CDDI_4; // 0x90 R CD Digital Audio Input Register 4
++ volatile unsigned int CDDI_5; // 0x94 R CD Digital Audio Input Register 5
++ volatile unsigned int CDDI_6; // 0x98 R CD Digital Audio Input Register 6
++ volatile unsigned int CDDI_7; // 0x9C R CD Digital Audio Input Register 7
++ volatile unsigned int CICR; // 0xA0 R/W 0x0000 CD Interface Control Register
++}ADMACDIF, *PADMACDIF;
++
++
++/*******************************************************************************
++* 11-4. ADMA_SPDIF Register Define (Base Addr = 0xF0535000/0xF0535800)
++********************************************************************************/
++//#define HwADMA_SPDIFTXBASE *(volatile unsigned long*)0xF0535000
++//#define HwADMA_SPDIFRXBASE *(volatile unsigned long*)0xF0535800
++
++typedef struct _ADMASPDIFTX{
++ volatile unsigned int TxVersion; // 0x00 R 0x00003111 Version Register
++ volatile unsigned int TxConfig; // 0x04 R/W 0x00000000 Configuration Register
++ volatile unsigned int TxChStat; // 0x08 R/W 0x00000000 Channel Status Control Register
++ volatile unsigned int TxIntMask; // 0x0C R/W 0x00000000 Interrupt Mask Register
++ volatile unsigned int TxIntStat; // 0x10 R/W 0x00000000 Interrupt Status Register
++ volatile unsigned int NOTDEFINE0[27];
++ volatile unsigned int UserData[24]; // 0x80~0xDC W - User Data Buffer
++ volatile unsigned int NOTDEFINE1[8];
++ volatile unsigned int ChStatus[24]; // 0x100~0x15C W - Channel Status Buffer
++ volatile unsigned int NOTDEFINE2[40];
++ volatile unsigned int TxBuffer[128]; // 0x200~0x23C W - Transmit Data Buffer
++ volatile unsigned int DMACFG; // 0x400 R/W 0x00000007 Additional Configuration for DMA
++ //volatile unsigned int NOTDEFINE4[159];
++ //volatile unsigned int CSBUDB[24]; // 0x680~0x6DC W - Merged Window for CSB/UDB
++}ADMASPDIFTX, *PADMASPDIFTX;
++
++typedef union _RXCAP{
++ volatile unsigned int RxCapCtln[16]; // 0x840~0x87C(even) W 0x00000000 Channel Status Capture Control Register
++ volatile unsigned int RxCapn[16]; // 0x840~0x87C(odd) W 0x00000000 Captured Channel Status / user bit
++}RXCAP;
++
++typedef struct _ADMASPDIFRX{
++ volatile unsigned int RxVersion; // 0x800 R 0x00080111 Version Register
++ volatile unsigned int RxConfig; // 0x804 R/W 0x00000000 Configuration Register
++ volatile unsigned int RxStatus; // 0x808 R 0x00000000 Signal Status Buffer
++ volatile unsigned int RxIntMask; // 0x80C R/W 0x00000000 Interrupt Mask Register
++ volatile unsigned int RxIntStat; // 0x810 R/W 0x00000000 Interrupt Status register
++ volatile unsigned int NOTDEFINE0[11];
++ RXCAP RxCap;
++ //volatile unsigned int RxCapCtln[16]; // 0x840~0x87C(even) W 0x00000000 Channel Status Capture Control Register
++ //volatile unsigned int RxCapn[16]; // 0x840~0x87C(odd) W 0x00000000 Captured Channel Status / user bit
++ volatile unsigned int RxBuffer[8]; // 0xA00~0xA1C W - Receive Data Buffer
++}ADMASPDIFRX, *PADMASPDIFRX;
++
++
++/*******************************************************************************
++* 12-1. DAI Register Define (Base Addr = 0xF0537000
++********************************************************************************/
++//#define HwDAI_BASE *(volatile unsigned long*)0xF0537000
++typedef struct _DAI{
++ volatile unsigned int DADI_L0; // 0x00 R - Digital Audio Left Input Register 0
++ volatile unsigned int DADI_R0; // 0x04 R - Digital Audio Right Input Register 0
++ volatile unsigned int DADI_L1; // 0x08 R - Digital Audio Left Input Register 1
++ volatile unsigned int DADI_R1; // 0x0C R - Digital Audio Right Input Register 1
++ volatile unsigned int DADI_L2; // 0x10 R - Digital Audio Left Input Register 2
++ volatile unsigned int DADI_R2; // 0x14 R - Digital Audio Right Input Register 2
++ volatile unsigned int DADI_L3; // 0x18 R - Digital Audio Left Input Register 3
++ volatile unsigned int DADI_R3; // 0x1C R - Digital Audio Right Input Register 3
++ volatile unsigned int DADO_L0; // 0x20 R/W - Digital Audio Left Output Register 0
++ volatile unsigned int DADO_R0; // 0x24 R/W - Digital Audio Right Output Register 0
++ volatile unsigned int DADO_L1; // 0x28 R/W - Digital Audio Left Output Register 1
++ volatile unsigned int DADO_R1; // 0x2C R/W - Digital Audio Right Output Register 1
++ volatile unsigned int DADO_L2; // 0x30 R/W - Digital Audio Left Output Register 2
++ volatile unsigned int DADO_R2; // 0x34 R/W - Digital Audio Right Output Register 2
++ volatile unsigned int DADO_L3; // 0x38 R/W - Digital Audio Left Output Register 3
++ volatile unsigned int DADO_R3; // 0x3C R/W - Digital Audio Right Output Register 3
++ volatile unsigned int DAMR; // 0x40 R/W 0x00000000 Digital Audio Mode Register
++ volatile unsigned int DAVC; // 0x44 R/W 0x0000 Digital Audio Volume Control Register
++}DAI, *PDAI;
++
++/*******************************************************************************
++* 12-2. CDIF Register Define (Base Addr = 0xF0537000
++********************************************************************************/
++//#define HwCDIF_BASE *(volatile unsigned long*)0xF0537080
++typedef struct _CDIF{
++ volatile unsigned int CDDI_0; // 0x80 R CD Digital Audio Input Register 0
++ volatile unsigned int CDDI_1; // 0x84 R CD Digital Audio Input Register 1
++ volatile unsigned int CDDI_2; // 0x88 R CD Digital Audio Input Register 2
++ volatile unsigned int CDDI_3; // 0x8C R CD Digital Audio Input Register 3
++ volatile unsigned int CICR; // 0x90 R/W 0x0000 CD Interface Control Register
++}CDIF, *PCDIF;
++
++
++/*******************************************************************************
++* 13. SPDIF Register Define (Base Addr = 0xF0538000)
++********************************************************************************/
++//#define HwSPDIF_BASE *(volatile unsigned long*)0xF0538000
++typedef struct _SPDIF{
++ volatile unsigned int TxVersion; // 0x00 R Version Register
++ volatile unsigned int TxConfig; // 0x04 R/W Configuration Register
++ volatile unsigned int TxChStat; // 0x08 R/W Channel Status Control Register
++ volatile unsigned int TxIntMask; // 0x0C R/W Interrupt Mask Register
++ volatile unsigned int TxIntStat; // 0x10 R/W Interrupt Status Register
++ volatile unsigned int UserData[24]; // 0x80~0xDC W - User Data Buffer
++ volatile unsigned int ChStatus[24]; // 0x100~0x15C W - Channel Status Buffer
++ volatile unsigned int TxBuffer[128]; // 0x200~0x3FC W - Transmit Data Buffer
++ volatile unsigned int DMACFG; // 0x400 R/W - Additional Configuration for DMA
++}SPDIF, *PSPDIF;
++
++
++/*******************************************************************************
++* 14-1. USB1.1 HOST Controller & Transceiver (Base Addr = 0xF0500000)
++********************************************************************************/
++//#define HwUSBHOST_BASE *(volatile unsigned long*)0xF0500000
++typedef struct _USBHOST11{
++ volatile unsigned int HcRevision; // 0x00 R 0x00000010
++ volatile unsigned int HcControl; // 0x04 R/W 0x00000000
++ volatile unsigned int HcCommandStatus; // 0x08 R 0x00000000
++ volatile unsigned int HcInterruptStatus; // 0x0C R 0x00000000
++ volatile unsigned int HcInterruptEnable; // 0x10 R/W 0x00000000
++ volatile unsigned int HcInterruptDisable; // 0x14 W 0x00000000
++ volatile unsigned int HcHCCA; // 0x18 R/W 0x00000000
++ volatile unsigned int HcPeriodCurrentED; // 0x1C R 0x00000000
++ volatile unsigned int HcControlHeadED; // 0x20 R/W 0x00000000
++ volatile unsigned int HcControlCurrentED; // 0x24 R/W 0x00000000
++ volatile unsigned int HcBulkHeadED; // 0x28 R/W 0x00000000
++ volatile unsigned int HcBulkCurrentED; // 0x2C R/W 0x00000000
++ volatile unsigned int HcDoneHead; // 0x30 R 0x00000000
++ volatile unsigned int HcRmInterval; // 0x34 R/W 0x00002EDF
++ volatile unsigned int HcFmRemaining; // 0x38 R/W 0x00000000
++ volatile unsigned int HcFmNumber; // 0x3C R/W 0x00000000
++ volatile unsigned int HcPeriodStart; // 0x40 R/W 0x00000000
++ volatile unsigned int HcLSThreshold; // 0x44 R/W 0x00000628
++ volatile unsigned int HcRhDescriptorA; // 0x48 R/W 0x02001202
++ volatile unsigned int HcRhDescriptorB; // 0x4C R/W 0x00000000
++ volatile unsigned int HcRhStatus; // 0x50 R/W 0x00000000
++ volatile unsigned int HcRhPortStatus1; // 0x54 R/W 0x00000100
++ volatile unsigned int HcRhPortStatus2; // 0x58 R/W 0x00000100
++}USBHOST11, *PUSBHOST11;
++
++
++/*******************************************************************************
++* 14-2. USB1.1 HOST Configuration Register (Base Addr = 0xF05F5000)
++********************************************************************************/
++//#define HwUSBHOSTCFG_BASE *(volatile unsigned long*)0xF05F5000
++typedef struct _USBHOST11CFG{
++ volatile unsigned int NOTDEFINE0;
++ volatile unsigned int USB11H; // 0x4 R/W 0x00000010 USB1.1 Host Configuration register
++}USBHOST11CFG, *PUSBHOST11CFG;
++
++
++/*******************************************************************************
++* 15-1. USB2.0 OTG Controller Define (Base Addr = 0xF0550000)
++********************************************************************************/
++//#define HwUSB20OTG_BASE *(volatile unsigned long*)0xF0550000
++typedef struct _USB20OTG{
++ // Core Global CSR Map
++ volatile unsigned int GOTGCTL; // 0x000 R/W OTG Control and Status Register
++ volatile unsigned int GOTGINT; // 0x004 OTG Interrupt Register
++ volatile unsigned int GAHBCFG; // 0x008 Core AHB Configuration Register
++ volatile unsigned int GUSBCFG; // 0x00C Core USB Configuration register
++ volatile unsigned int GRSTCTL; // 0x010 Core Reset Register
++ volatile unsigned int GINTSTS; // 0x014 Core Interrupt Register
++ volatile unsigned int GINTMSK; // 0x018 Core Interrupt Mask Register
++ volatile unsigned int GRXSTSR; // 0x01C Receive Status Debug Read register(Read Only)
++ volatile unsigned int GRXSTSP; // 0x020 Receive Status Read /Pop register(Read Only)
++ volatile unsigned int GRXFSIZ; // 0x024 Receive FIFO Size Register
++ volatile unsigned int GNPTXFSIZ; // 0x028 Non-periodic Transmit FIFO Size register
++ volatile unsigned int GNPTXSTS; // 0x02C Non-periodic Transmit FIFO/Queue Status register (Read Only)
++ volatile unsigned int NOTDEFINE0[3]; // 0x030~ Reserved
++ volatile unsigned int GUID; // 0x03C User ID Register
++ volatile unsigned int NOTDEFINE1; // 0x040 Reserved
++ volatile unsigned int GHWCFG1; // 0x044 User HW Config1 Register(Read Only)
++ volatile unsigned int GHWCFG2; // 0x048 User HW Config2 Register(Read Only)
++ volatile unsigned int GHWCFG3; // 0x04C User HW Config3 Register(Read Only)
++ volatile unsigned int GHWCFG4; // 0x050 User HW Config4 Register(Read Only)
++ volatile unsigned int NOTDEFINE2[43]; // 0x054~ Reserved
++ volatile unsigned int HPTXFSIZ; // 0x100 Host Periodic Transmit FIFO Size Register
++ volatile unsigned int DIEPTXFn[15]; // 0x104~ Device IN Endpoint Transmit FIFO Size register
++ volatile unsigned int NOTDEFINE3[176]; // 0x140~ Reserved
++ // Host Mode CSR Map
++ volatile unsigned int HCFG; // 0x400 Host Configuration Register
++ volatile unsigned int HFIR; // 0x404 Host Frame Interval Register
++ volatile unsigned int HFNUM; // 0x408 Host Frame Number/Frame Time Remaining register
++ volatile unsigned int NOTDEFINE4; // 0x40C Reserved
++ volatile unsigned int HPTXSTS; // 0x410 Host Periodic Transmit FIFO/Queue Status Register
++ volatile unsigned int HAINT; // 0x414 Host All Channels Interrupt Register
++ volatile unsigned int HAINTMSK; // 0x418 Host All Channels Interrupt Mask register
++ volatile unsigned int NOTDEFINE5[9]; // 0x41C~ Not Used
++ volatile unsigned int HPRT; // 0x440 Host Port Control and Status register
++ volatile unsigned int NOTDEFINE6[47]; // 0x444~ Reserved
++ volatile unsigned int HCCHARn; // 0x500 Host Channel 0 Characteristics Register
++ volatile unsigned int HCSPLTn; // 0x504 Host Channel 0 Split Control Register
++ volatile unsigned int HCINTn; // 0x508 Host Channel 0 Interrupt Register
++ volatile unsigned int HCINTMSKn; // 0x50C Host Channel 0 Interrupt Mask Register
++ volatile unsigned int HCTSIZn; // 0x510 Host Channel 0 Transfer Size Register
++ volatile unsigned int HCDMAn; // 0x514 Host Channel 0 DMA Address Register
++ volatile unsigned int NOTDEFINE7[2]; // 0x518~ Reserved
++ volatile unsigned int HCH1[8]; // 0x520~ Host Channel 1 Registers
++ volatile unsigned int HCH2[8]; // 0x540~ Host Channel 2 Registers
++ volatile unsigned int HCH3[8]; // 0x560~ Host Channel 3 Registers
++ volatile unsigned int HCH4[8]; // 0x580~ Host Channel 4 Registers
++ volatile unsigned int HCH5[8]; // 0x5A0~ Host Channel 5 Registers
++ volatile unsigned int HCH6[8]; // 0x5C0~ Host Channel 6 Registers
++ volatile unsigned int HCH7[8]; // 0x5E0~ Host Channel 7 Registers
++ volatile unsigned int HCH8[8]; // 0x600~ Host Channel 8 Registers
++ volatile unsigned int HCH9[8]; // 0x620~ Host Channel 9 Registers
++ volatile unsigned int HCH10[8]; // 0x640~ Host Channel 10 Registers
++ volatile unsigned int HCH11[8]; // 0x660~ Host Channel 11 Registers
++ volatile unsigned int HCH12[8]; // 0x680~ Host Channel 12 Registers
++ volatile unsigned int HCH13[8]; // 0x6A0~ Host Channel 13 Registers
++ volatile unsigned int HCH14[8]; // 0x6C0~ Host Channel 14 Registers
++ volatile unsigned int HCH15[8]; // 0x6E0~ Host Channel 15 Registers
++ volatile unsigned int NOTDEFINE8[64]; // 0x700~ Reserved
++ // Device Mode CSR Map
++ volatile unsigned int DCFG; // 0x800 Device Configuration Register
++ volatile unsigned int DCTL; // 0x804 Device Control Register
++ volatile unsigned int DSTS; // 0x808 Device Status Register (Read Only)
++ volatile unsigned int NOTDEFINE9; // 0x80C Reserved
++ volatile unsigned int DIEPMSK; // 0x810 Device IN Endpoint Common Interrupt Mask Register
++ volatile unsigned int DOEPMSK; // 0x814 Device OUT Endpoint Common Interrupt Mask register
++ volatile unsigned int DAINT; // 0x818 Device All Endpoints Interrupt Register
++ volatile unsigned int DAINTMSK; // 0x81C Device All Endpoints Interrupt Mask Register
++ volatile unsigned int NOTDEFINE10[2]; // 0x820~ Reserved
++ volatile unsigned int DVBUSDIS; // 0x828 Device VBUS Discharge Time Register
++ volatile unsigned int DVBUSPULSE; // 0x82C Device VBUS Pulsing Time register
++ volatile unsigned int DTHRCTL; // 0x830 Device Threshold Control register
++ volatile unsigned int DIEPEMPMSK; // 0x834 Device IN Endpoint FIFO Empty Interrupt Mask register
++ volatile unsigned int NOTDEFINE11[50]; // 0x838~ Reserved
++
++ volatile unsigned int DIEPCTL0; // 0x900 Device Control IN Endpoint 0 Control Register
++ volatile unsigned int NOTDEFINE12; // 0x904 Reserved
++ volatile unsigned int DIEPINT0; // 0x908 Device IN Endpoint 0 Interrupt Register
++ volatile unsigned int NOTDEFINE13; // 0x90C Reserved
++ volatile unsigned int DIEPTSIZ0; // 0x910 Device IN Endpoint 0 Transfer Size register
++ volatile unsigned int DIEPDMA0; // 0x914 Device IN Endpoint 0 DMA Address Register
++ volatile unsigned int DTXFSTS0; // 0x918 Device IN Endpoint Transmit FIFO Status Register
++ volatile unsigned int NOTDEFINE14; // 0x91C Reserved
++
++ volatile unsigned int DEVINENDPT[15][8]; // 0x920~ Device IN Endpoint 1~15 Registers
++ volatile unsigned int DOEPCTL0; // 0xB00 Device Control OUT Endpoint 0 Control register
++ volatile unsigned int NOTDEFINE15; // 0xB04 Reserved
++ volatile unsigned int DOEPINT0; // 0xB08 Device OUT Endpoint 0 Interrupt Register
++ volatile unsigned int NOTDEFINE16; // 0xB0C Reserved
++ volatile unsigned int DOEPTSIZ0; // 0xB10 Device OUT Endpoint 0 Transfer Size Register
++ volatile unsigned int DOEPDMA0; // 0xB14 Device OUT Endpoint 0 DMA Address register
++ volatile unsigned int NOTDEFINE17[2]; // 0xB18~ Reserved
++ volatile unsigned int DEVOUTENDPT[15][8]; // 0xB20~ Device OUT Endpoint 1~15 Registers
++ volatile unsigned int NOTDEFINE18[64]; // 0xD00~ Reserved
++ // Power and Clock Gating CSR Map
++ volatile unsigned int PCGCR; // 0xE00 Power and Clock Gating Control Register
++ volatile unsigned int NOTDEFINE19[127]; // 0xE04~ Reserved
++ // Data FIFO(DFIFO) Access Register Map
++ volatile unsigned int DFIFOENDPT[16][1024]; // 0x1000~ Device IN Endpoint 0~16/Host Out Channel 0~16: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT0[1024]; // 0x1000~ Device IN Endpoint 0/Host Out Channel 0: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT1[1024]; // 0x2000~ Device IN Endpoint 1/Host Out Channel 1: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT2[1024]; // 0x3000~ Device IN Endpoint 2/Host Out Channel 2: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT3[1024]; // 0x4000~ Device IN Endpoint 3/Host Out Channel 3: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT4[1024]; // 0x5000~ Device IN Endpoint 4/Host Out Channel 4: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT5[1024]; // 0x6000~ Device IN Endpoint 5/Host Out Channel 5: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT6[1024]; // 0x7000~ Device IN Endpoint 6/Host Out Channel 6: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT7[1024]; // 0x8000~ Device IN Endpoint 7/Host Out Channel 7: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT8[1024]; // 0x9000~ Device IN Endpoint 8/Host Out Channel 8: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT9[1024]; // 0xA000~ Device IN Endpoint 9/Host Out Channel 9: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT10[1024]; // 0xB000~ Device IN Endpoint 10/Host Out Channel 10: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT11[1024]; // 0xC000~ Device IN Endpoint 11/Host Out Channel 11: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT12[1024]; // 0xD000~ Device IN Endpoint 12/Host Out Channel 12: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT13[1024]; // 0xE000~ Device IN Endpoint 13/Host Out Channel 13: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT14[1024]; // 0xF000~ Device IN Endpoint 14/Host Out Channel 14: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT15[1024]; // 0x10000~ Device IN Endpoint 15/Host Out Channel 15: DFIFO Write/Read Access
++}USB20OTG, *PUSB20OTG;
++
++typedef struct _USBOTG{
++ // Core Global CSR Map
++ volatile unsigned int GOTGCTL; // 0x000 R/W OTG Control and Status Register
++ volatile unsigned int GOTGINT; // 0x004 OTG Interrupt Register
++ volatile unsigned int GAHBCFG; // 0x008 Core AHB Configuration Register
++ volatile unsigned int GUSBCFG; // 0x00C Core USB Configuration register
++ volatile unsigned int GRSTCTL; // 0x010 Core Reset Register
++ volatile unsigned int GINTSTS; // 0x014 Core Interrupt Register
++ volatile unsigned int GINTMSK; // 0x018 Core Interrupt Mask Register
++ volatile unsigned int GRXSTSR; // 0x01C Receive Status Debug Read register(Read Only)
++ volatile unsigned int GRXSTSP; // 0x020 Receive Status Read /Pop register(Read Only)
++ volatile unsigned int GRXFSIZ; // 0x024 Receive FIFO Size Register
++ volatile unsigned int GNPTXFSIZ; // 0x028 Non-periodic Transmit FIFO Size register
++ volatile unsigned int GNPTXSTS; // 0x02C Non-periodic Transmit FIFO/Queue Status register (Read Only)
++ volatile unsigned int NOTDEFINE0[3]; // 0x030~ Reserved
++ volatile unsigned int GUID; // 0x03C User ID Register
++ volatile unsigned int NOTDEFINE1; // 0x040 Reserved
++ volatile unsigned int GHWCFG1; // 0x044 User HW Config1 Register(Read Only)
++ volatile unsigned int GHWCFG2; // 0x048 User HW Config2 Register(Read Only)
++ volatile unsigned int GHWCFG3; // 0x04C User HW Config3 Register(Read Only)
++ volatile unsigned int GHWCFG4; // 0x050 User HW Config4 Register(Read Only)
++ volatile unsigned int NOTDEFINE2[43]; // 0x054~ Reserved
++ volatile unsigned int HPTXFSIZ; // 0x100 Host Periodic Transmit FIFO Size Register
++ volatile unsigned int DIEPTXFn[15]; // 0x104~ Device IN Endpoint Transmit FIFO Size register
++ volatile unsigned int NOTDEFINE3[176]; // 0x140~ Reserved
++ // Host Mode CSR Map
++ volatile unsigned int HCFG; // 0x400 Host Configuration Register
++ volatile unsigned int HFIR; // 0x404 Host Frame Interval Register
++ volatile unsigned int HFNUM; // 0x408 Host Frame Number/Frame Time Remaining register
++ volatile unsigned int NOTDEFINE4; // 0x40C Reserved
++ volatile unsigned int HPTXSTS; // 0x410 Host Periodic Transmit FIFO/Queue Status Register
++ volatile unsigned int HAINT; // 0x414 Host All Channels Interrupt Register
++ volatile unsigned int HAINTMSK; // 0x418 Host All Channels Interrupt Mask register
++ volatile unsigned int NOTDEFINE5[9]; // 0x41C~ Not Used
++ volatile unsigned int HPRT; // 0x440 Host Port Control and Status register
++ volatile unsigned int NOTDEFINE6[47]; // 0x444~ Reserved
++ volatile unsigned int HCCHARn; // 0x500 Host Channel 0 Characteristics Register
++ volatile unsigned int HCSPLTn; // 0x504 Host Channel 0 Split Control Register
++ volatile unsigned int HCINTn; // 0x508 Host Channel 0 Interrupt Register
++ volatile unsigned int HCINTMSKn; // 0x50C Host Channel 0 Interrupt Mask Register
++ volatile unsigned int HCTSIZn; // 0x510 Host Channel 0 Transfer Size Register
++ volatile unsigned int HCDMAn; // 0x514 Host Channel 0 DMA Address Register
++ volatile unsigned int NOTDEFINE7[2]; // 0x518~ Reserved
++ volatile unsigned int HCH1[8]; // 0x520~ Host Channel 1 Registers
++ volatile unsigned int HCH2[8]; // 0x540~ Host Channel 2 Registers
++ volatile unsigned int HCH3[8]; // 0x560~ Host Channel 3 Registers
++ volatile unsigned int HCH4[8]; // 0x580~ Host Channel 4 Registers
++ volatile unsigned int HCH5[8]; // 0x5A0~ Host Channel 5 Registers
++ volatile unsigned int HCH6[8]; // 0x5C0~ Host Channel 6 Registers
++ volatile unsigned int HCH7[8]; // 0x5E0~ Host Channel 7 Registers
++ volatile unsigned int HCH8[8]; // 0x600~ Host Channel 8 Registers
++ volatile unsigned int HCH9[8]; // 0x620~ Host Channel 9 Registers
++ volatile unsigned int HCH10[8]; // 0x640~ Host Channel 10 Registers
++ volatile unsigned int HCH11[8]; // 0x660~ Host Channel 11 Registers
++ volatile unsigned int HCH12[8]; // 0x680~ Host Channel 12 Registers
++ volatile unsigned int HCH13[8]; // 0x6A0~ Host Channel 13 Registers
++ volatile unsigned int HCH14[8]; // 0x6C0~ Host Channel 14 Registers
++ volatile unsigned int HCH15[8]; // 0x6E0~ Host Channel 15 Registers
++ volatile unsigned int NOTDEFINE8[64]; // 0x700~ Reserved
++ // Device Mode CSR Map
++ volatile unsigned int DCFG; // 0x800 Device Configuration Register
++ volatile unsigned int DCTL; // 0x804 Device Control Register
++ volatile unsigned int DSTS; // 0x808 Device Status Register (Read Only)
++ volatile unsigned int NOTDEFINE9; // 0x80C Reserved
++ volatile unsigned int DIEPMSK; // 0x810 Device IN Endpoint Common Interrupt Mask Register
++ volatile unsigned int DOEPMSK; // 0x814 Device OUT Endpoint Common Interrupt Mask register
++ volatile unsigned int DAINT; // 0x818 Device All Endpoints Interrupt Register
++ volatile unsigned int DAINTMSK; // 0x81C Device All Endpoints Interrupt Mask Register
++ volatile unsigned int NOTDEFINE10[2]; // 0x820~ Reserved
++ volatile unsigned int DVBUSDIS; // 0x828 Device VBUS Discharge Time Register
++ volatile unsigned int DVBUSPULSE; // 0x82C Device VBUS Pulsing Time register
++ volatile unsigned int DTHRCTL; // 0x830 Device Threshold Control register
++ volatile unsigned int DIEPEMPMSK; // 0x834 Device IN Endpoint FIFO Empty Interrupt Mask register
++ volatile unsigned int NOTDEFINE11[50]; // 0x838~ Reserved
++
++ //volatile unsigned int DIEPCTL0; // 0x900 Device Control IN Endpoint 0 Control Register
++ //volatile unsigned int NOTDEFINE12; // 0x904 Reserved
++ //volatile unsigned int DIEPINT0; // 0x908 Device IN Endpoint 0 Interrupt Register
++ //volatile unsigned int NOTDEFINE13; // 0x90C Reserved
++ //volatile unsigned int DIEPTSIZ0; // 0x910 Device IN Endpoint 0 Transfer Size register
++ //volatile unsigned int DIEPDMA0; // 0x914 Device IN Endpoint 0 DMA Address Register
++ //volatile unsigned int DTXFSTS0; // 0x918 Device IN Endpoint Transmit FIFO Status Register
++ //volatile unsigned int NOTDEFINE14; // 0x91C Reserved
++
++ volatile unsigned int DEVINENDPT[16][8]; // 0x900~ Device IN Endpoint 1~15 Registers
++
++ //volatile unsigned int DOEPCTL0; // 0xB00 Device Control OUT Endpoint 0 Control register
++ //volatile unsigned int NOTDEFINE15; // 0xB04 Reserved
++ //volatile unsigned int DOEPINT0; // 0xB08 Device OUT Endpoint 0 Interrupt Register
++ //volatile unsigned int NOTDEFINE16; // 0xB0C Reserved
++ //volatile unsigned int DOEPTSIZ0; // 0xB10 Device OUT Endpoint 0 Transfer Size Register
++ //volatile unsigned int DOEPDMA0; // 0xB14 Device OUT Endpoint 0 DMA Address register
++ //volatile unsigned int NOTDEFINE17[2]; // 0xB18~ Reserved
++
++ volatile unsigned int DEVOUTENDPT[16][8]; // 0xB00~ Device OUT Endpoint 1~15 Registers
++ volatile unsigned int NOTDEFINE18[64]; // 0xD00~ Reserved
++
++ // Power and Clock Gating CSR Map
++ volatile unsigned int PCGCR; // 0xE00 Power and Clock Gating Control Register
++ volatile unsigned int NOTDEFINE19[127]; // 0xE04~ Reserved
++ // Data FIFO(DFIFO) Access Register Map
++ volatile unsigned int DFIFOENDPT[16][1024]; // 0x1000~ Device IN Endpoint 0~16/Host Out Channel 0~16: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT0[1024]; // 0x1000~ Device IN Endpoint 0/Host Out Channel 0: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT1[1024]; // 0x2000~ Device IN Endpoint 1/Host Out Channel 1: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT2[1024]; // 0x3000~ Device IN Endpoint 2/Host Out Channel 2: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT3[1024]; // 0x4000~ Device IN Endpoint 3/Host Out Channel 3: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT4[1024]; // 0x5000~ Device IN Endpoint 4/Host Out Channel 4: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT5[1024]; // 0x6000~ Device IN Endpoint 5/Host Out Channel 5: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT6[1024]; // 0x7000~ Device IN Endpoint 6/Host Out Channel 6: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT7[1024]; // 0x8000~ Device IN Endpoint 7/Host Out Channel 7: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT8[1024]; // 0x9000~ Device IN Endpoint 8/Host Out Channel 8: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT9[1024]; // 0xA000~ Device IN Endpoint 9/Host Out Channel 9: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT10[1024]; // 0xB000~ Device IN Endpoint 10/Host Out Channel 10: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT11[1024]; // 0xC000~ Device IN Endpoint 11/Host Out Channel 11: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT12[1024]; // 0xD000~ Device IN Endpoint 12/Host Out Channel 12: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT13[1024]; // 0xE000~ Device IN Endpoint 13/Host Out Channel 13: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT14[1024]; // 0xF000~ Device IN Endpoint 14/Host Out Channel 14: DFIFO Write/Read Access
++ //volatile unsigned int DFIFOENDPT15[1024]; // 0x10000~ Device IN Endpoint 15/Host Out Channel 15: DFIFO Write/Read Access
++}USBOTG, *PUSBOTG;
++/*******************************************************************************
++* 15-2. USB OTG Configuration Register Define (Base Addr = 0xF05F5000)
++********************************************************************************/
++//#define HwUSBOTGCFG_BASE *(volatile unsigned long*)0xF05F5000
++typedef struct _USBOTGCFG{
++ volatile unsigned int OTGCR; // 0x000 R/W USBOTG Configuration Register
++ volatile unsigned int OTGID; // 0x004 R/W USBOTG ID Register
++ volatile unsigned int NOTUSED[8]; // 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x20, 0x24
++ volatile unsigned int UPCR0; // 0x028 R/W USB PHY Configuration Register0
++ volatile unsigned int UPCR1; // 0x02C R/W USB PHY Configuration Register1
++ volatile unsigned int UPCR2; // 0x030 R/W USB PHY Configuration Register2
++ volatile unsigned int UPCR3; // 0x034 R/W USB PHY Configuration Register3
++}USBOTGCFG, *PUSBOTGCFG;
++
++/*******************************************************************************
++* 15-3. USB PHY Configuration Register Define (Base Addr = 0xF05F5028)
++********************************************************************************/
++//#define HwUSBPHYCFG_BASE *(volatile unsigned long*)0xF05F5028
++typedef struct _USBPHYCFG
++{
++ volatile unsigned int UPCR0; // 0x028 R/W USB PHY Configuration Register0
++ volatile unsigned int UPCR1; // 0x02C R/W USB PHY Configuration Register1
++ volatile unsigned int UPCR2; // 0x030 R/W USB PHY Configuration Register2
++ volatile unsigned int UPCR3; // 0x034 R/W USB PHY Configuration Register3
++}USBPHYCFG, *PUSBPHYCFG;
++
++
++/*******************************************************************************
++* 16. External Host Interface Register Define (Base Addr = 0xF0570000/0xF0580000)
++********************************************************************************/
++//#define HwEHICS0_BASE *(volatile unsigned long*)0xF0570000
++//#define HwEHICS1_BASE *(volatile unsigned long*)0xF0580000
++
++typedef struct _EHI{
++ volatile unsigned int EHST; //0x00 R/W R/W 0x00000080 Status register
++ volatile unsigned int EHIINT; //0x04 R/W R/W 0x00000000 Internal interrupt control register
++ volatile unsigned int EHEINT; //0x08 R/W R/W 0x00000000 External interrupt control register
++ volatile unsigned int EHA; //0x0C R R/W 0x00000000 Address register
++ volatile unsigned int EHAM; //0x10 R/W R 0x00000000 Address masking register
++ volatile unsigned int EHD; //0x14 R/W R/W 0x00000000 Data register
++ volatile unsigned int EHSEM; //0x18 R/W R/W 0x00000000 Semaphore register
++ volatile unsigned int EHCFG; //0x1C R/W R/W 0x00000000 Configuration registers
++ volatile unsigned int EHIND; //0x20 R W 0x00000000 Index register
++ volatile unsigned int EHRWCS; //0x24 R R/W 0x00000000 Read/Write Control/Status register
++}EHI, *PEHI;
++
++/*******************************************************************************
++* 17. General Purpose Serial Bus (GPSB) Register Define (Base Addr = 0xF0057000)
++********************************************************************************/
++/*
++#define HwGPSBCH0_BASE *(volatile unsigned long*)0xF0057000
++#define HwGPSBCH1_BASE *(volatile unsigned long*)0xF0057100
++#define HwGPSBCH2_BASE *(volatile unsigned long*)0xF0057200
++#define HwGPSBCH3_BASE *(volatile unsigned long*)0xF0057300
++#define HwGPSBCH4_BASE *(volatile unsigned long*)0xF0057400
++#define HwGPSBCH5_BASE *(volatile unsigned long*)0xF0057500
++#define HwGPSBPORTCFG_BASE *(volatile unsigned long*)0xF0057800
++#define HwGPSBPIDTABLE_BASE *(volatile unsigned long*)0xF0057F00
++*/
++
++typedef struct _GPSB{
++ volatile unsigned int PORT; // 0x000 R/W 0x0000 Data port
++ volatile unsigned int STAT; // 0x004 R/W 0x0000 Status register
++ volatile unsigned int INTEN; // 0x008 R/W 0x0000 Interrupt enable
++ volatile unsigned int MODE; // 0x00C R/W 0x0004 Mode register
++ volatile unsigned int CTRL; // 0x010 R/W 0x0000 Control register
++ volatile unsigned int EVTCTRL; // 0x014 R/W 0x0000 Counter & Ext. Event Control
++ volatile unsigned int CCV; // 0x018 R 0x0000 Counter Current Value
++ volatile unsigned int NOTDEFINE0;
++ volatile unsigned int TXBASE; // 0x020 R/W 0x0000 TX base address register
++ volatile unsigned int RXBASE; // 0x024 R/W 0x0000 RX base address register
++ volatile unsigned int PACKET; // 0x028 R/W 0x0000 Packet register
++ volatile unsigned int DMACTR; // 0x02C R/W 0x0000 DMA control register
++ volatile unsigned int DMASTR; // 0x030 R/W 0x0000 DMA status register
++ volatile unsigned int DMAICR; // 0x034 R/W 0x0000 DMA interrupt control register
++}GPSB, *PGPSB;
++
++
++typedef struct _GPSBPORTCFG{
++ volatile unsigned int PCFG0; // 0x800 R/W 0x03020100 Port Configuration Register 0
++ volatile unsigned int PCFG1; // 0x804 R/W 0x00000504 Port Configuration Port Config Register 1
++ volatile unsigned int CIRQST; // 0x808 R 0x0000 Channel IRQ Status Register
++}GPSBPORTCFG, *PGPSBPORTCFG;
++
++
++typedef struct _GPSBPIDTABLE{
++ volatile unsigned int PIDT[0x80/4]; // 0xF00 R/W PID Table
++}GPSBPIDTABLE, *PGPSBPIDTABLE;
++
++
++/*******************************************************************************
++* 18. The Transport Stream Interface (TSIF) Register Define (Base Addr = 0xF0538000)
++********************************************************************************/
++//#define HwTSIF_BASE *(volatile unsigned long*)0xF053B000
++//#define HwTSIFPORTSEL_BASE *(volatile unsigned long*)0xF053B800
++
++typedef struct _TSIF{
++ volatile unsigned int TSDI; //0x00 R 0x0000 TSIF Input Data Register
++ volatile unsigned int TSCR; //0x04 R/W 0x0000 TSIF Control Register
++ volatile unsigned int TSPID; //0x08 R/W 0x0000 TSIF PID Register
++ volatile unsigned int TSCTRL; //0x10 R/W 0x0000 TSIF Interrupt Control Register
++ volatile unsigned int TSSTS; //0x10(14) R 0x0000 TSIF Interrupt Status Register(Test)
++}TSIF, *PTSIF;
++
++typedef struct _TSIFPORTSEL{
++ volatile unsigned int TSCHS; //0x800 R/W 0x0000 TSIF Channel(Port) Select Register
++}TSIFPORTSEL, *PTSIFPORTSEL;
++
++/*******************************************************************************
++* 19. GPS Interface Register Define (Base Addr = )
++********************************************************************************/
++
++
++/*******************************************************************************
++* 20. Remote Control Interface Register Define (Base Addr = 0xF05F3000)
++********************************************************************************/
++//#define HwREMOCON_BASE *(volatile unsigned long*)0xF05F3000
++
++typedef struct _REMOTECON{
++ volatile unsigned int TXADDR; // 0x00 R/W 0x0000 IR Data Transfer Address
++ volatile unsigned int CMD; // 0x04 R/W 0x0000 Command Register
++ volatile unsigned int CTRL; // 0x08 R/W 0x0000 Control Register
++ volatile unsigned int STA; // 0x0C W 0x0000 Status register
++ volatile unsigned int NOTDEFINE0[13];
++ volatile unsigned int CLKDIV; // 0x40 R 0x0000 Clock Divide Register
++}REMOTECON, *PREMOTECON;
++
++
++/*******************************************************************************
++* 21. I2C Controller Register Define (Base Addr = 0xF0530000)
++********************************************************************************/
++/*
++#define HwI2CMASTER0_BASE *(volatile unsigned long*)0xF0530000
++#define HwI2CMASTER1_BASE *(volatile unsigned long*)0xF0530040
++#define HwI2CSLAVE_BASE *(volatile unsigned long*)0xF0530080
++#define HwI2CSTATUS_BASE *(volatile unsigned long*)0xF05300C0
++*/
++
++typedef struct _I2CMASTER{
++ volatile unsigned int PRES; // 0x00 R/W 0xFFFF Clock Prescale register
++ volatile unsigned int CTRL; // 0x04 R/W 0x0000 Control Register
++ volatile unsigned int TXR; // 0x08 W 0x0000 Transmit Register
++ volatile unsigned int CMD; // 0x0C W 0x0000 Command Register
++ volatile unsigned int RXR; // 0x10 R 0x0000 Receive Register
++ volatile unsigned int SR; // 0x14 R 0x0000 Status register
++ volatile unsigned int TIME; // 0x18 R/W 0x0000 Timing Control Register
++}I2CMASTER, *PI2CMASTER;
++
++typedef struct _I2C{
++ volatile unsigned int PRES0; // 0x00 R/W 0xFFFF Clock Prescale register
++ volatile unsigned int CTRL0; // 0x04 R/W 0x0000 Control Register
++ volatile unsigned int TXR0; // 0x08 W 0x0000 Transmit Register
++ volatile unsigned int CMD0; // 0x0C W 0x0000 Command Register
++ volatile unsigned int RXR0; // 0x10 R 0x0000 Receive Register
++ volatile unsigned int SR0; // 0x14 R 0x0000 Status register
++ volatile unsigned int TIME0; // 0x18 R/W 0x0000 Timing Control Register
++ volatile unsigned int NOTUSING[9]; // 1c, 20, 24,28,2c,30,34,38,3c,
++ volatile unsigned int PRES1; // 0x40 R/W 0xFFFF Clock Prescale register
++ volatile unsigned int CTRL1; // 0x44 R/W 0x0000 Control Register
++ volatile unsigned int TXR1; // 0x48 W 0x0000 Transmit Register
++ volatile unsigned int CMD1; // 0x4C W 0x0000 Command Register
++ volatile unsigned int RXR1; // 0x50 R 0x0000 Receive Register
++ volatile unsigned int SR1; // 0x54 R 0x0000 Status register
++ volatile unsigned int TIME1; // 0x58 R/W 0x0000 Timing Control Register
++ volatile unsigned int NOTUSING1[26];
++ volatile unsigned int IRQSTR; // 0xC0 R 0x00000000 IRQ Status Register
++}I2C, *PI2C;
++
++typedef struct _SMUI2C{
++ volatile unsigned int PRES0; // 0x00 R/W 0xFFFF Clock Prescale register
++ volatile unsigned int CTRL0; // 0x04 R/W 0x0000 Control Register
++ volatile unsigned int TXR0; // 0x08 W 0x0000 Transmit Register
++ volatile unsigned int CMD0; // 0x0C W 0x0000 Command Register
++ volatile unsigned int RXR0; // 0x10 R 0x0000 Receive Register
++ volatile unsigned int SR0; // 0x14 R 0x0000 Status register
++ volatile unsigned int TIME0; // 0x18 R/W 0x0000 Timing Control Register
++ volatile unsigned int NOTUSING[9]; // 1c, 20, 24,28,2c,30,34,38,3c,
++ volatile unsigned int PRES1; // 0x40 R/W 0xFFFF Clock Prescale register
++ volatile unsigned int CTRL1; // 0x44 R/W 0x0000 Control Register
++ volatile unsigned int TXR1; // 0x48 W 0x0000 Transmit Register
++ volatile unsigned int CMD1; // 0x4C W 0x0000 Command Register
++ volatile unsigned int RXR1; // 0x50 R 0x0000 Receive Register
++ volatile unsigned int SR1; // 0x54 R 0x0000 Status register
++ volatile unsigned int TIME1; // 0x58 R/W 0x0000 Timing Control Register
++ volatile unsigned int NOTUSING1[10];
++ volatile unsigned int IRQSTR; // 0x80 R 0x00000000 IRQ Status Register
++}SMUI2C, *PSMUI2C;
++
++typedef struct _I2CSLAVE{
++ volatile unsigned int PORT; // 0x80 R/W - Data Access port (TX/RX FIFO)
++ volatile unsigned int CTL; // 0x84 R/W 0x00000000 Control register
++ volatile unsigned int ADDR; // 0x88 W 0x00000000 Address register
++ volatile unsigned int INT; // 0x8C W 0x00000000 Interrupt Enable Register
++ volatile unsigned int STAT; // 0x90 R 0x00000000 Status Register
++ volatile unsigned int NOTDEFINE0[2];
++ volatile unsigned int MBF; // 0x9C R/W 0x00000000 Buffer Valid Flag
++ volatile unsigned int MB0; // 0xA0 R/W 0x00000000 Data Buffer 0 (Byte 3 ~ 0)
++ volatile unsigned int MB1; // 0xA4 R/W 0x00000000 Data Buffer 1 (Byte 7 ~ 4)
++}I2CSLAVE, *PI2CSLAVE;
++
++typedef struct _I2CSTATUS{
++ volatile unsigned int IRQSTR; // 0xC0 R 0x00000000 IRQ Status Register
++}I2CSTATUS, *PI2CSTATUS;
++
++
++/*******************************************************************************
++* 22. UART Controller Register Define (Base Addr = 0xF0538000)
++********************************************************************************/
++/*
++#define HwUARTCH0_BASE *(volatile unsigned long*)0xF0532000
++#define HwUARTCH1_BASE *(volatile unsigned long*)0xF0532100
++#define HwUARTCH2_BASE *(volatile unsigned long*)0xF0532200
++#define HwUARTCH3_BASE *(volatile unsigned long*)0xF0532300
++#define HwUARTCH4_BASE *(volatile unsigned long*)0xF0532400
++#define HwUARTCH5_BASE *(volatile unsigned long*)0xF0532500
++#define HwUARTPORTMUX_BASE *(volatile unsigned long*)0xF0532600
++*/
++typedef union _UARTREG1{
++ volatile unsigned int RBR; // 0x00 R Unknown Receiver Buffer Register(DLAB = 0)
++ volatile unsigned int THR; // 0x00 W 0x00 Transmitter Holding Register (DLAB=0)
++ volatile unsigned int DLL; // 0x00 R/W 0x00 Divisor Latch (LSB) (DLAB=1)
++}UARTREG1;
++
++typedef union _UARTREG2{
++ volatile unsigned int IER; // 0x04 R/W 0x00 Interrupt Enable Register (DLAB=0)
++ volatile unsigned int DLM; // 0x04 R/W 0x00 Divisor Latch (MSB) (DLAB=1)
++}UARTREG2;
++
++typedef union _UARTREG3{
++ volatile unsigned int IIR; // 0x08 R Unknown Interrupt Ident. Register (DLAB=0)
++ volatile unsigned int FCR; // 0x08 W 0xC0 FIFO Control Register (DLAB=1)
++}UARTREG3;
++
++typedef struct _UART{
++/*
++ volatile unsigned int RBR; // 0x00 R Unknown Receiver Buffer Register(DLAB = 0)
++ volatile unsigned int THR; // 0x00 W 0x00 Transmitter Holding Register (DLAB=0)
++ volatile unsigned int DLL; // 0x00 R/W 0x00 Divisor Latch (LSB) (DLAB=1)
++ volatile unsigned int IER; // 0x04 R/W 0x00 Interrupt Enable Register (DLAB=0)
++ volatile unsigned int DLM; // 0x04 R/W 0x00 Divisor Latch (MSB) (DLAB=1)
++ volatile unsigned int IIR; // 0x08 R Unknown Interrupt Ident. Register (DLAB=0)
++ volatile unsigned int FCR; // 0x08 W 0xC0 FIFO Control Register (DLAB=1)
++*/
++ UARTREG1 REG1;
++ UARTREG2 REG2;
++ UARTREG3 REG3;
++ volatile unsigned int LCR; // 0x0C R/W 0x03 Line Control Register
++ volatile unsigned int MCR; // 0x10 R/W 0x00 MODEM Control Register
++ volatile unsigned int LSR; // 0x14 R Unknown Line Status Register
++ volatile unsigned int MSR; // 0x18 R Unknown MODEM Status Register
++ volatile unsigned int SCR; // 0x1C R/W 0x00 Scratch Register
++ volatile unsigned int AFT; // 0x20 R/W 0x00 AFC Trigger Level Register
++ volatile unsigned int UCR; // 0x24 R/W 0x00 UART Control register
++ volatile unsigned int NOTDEFINE0[6];
++ volatile unsigned int SRBR; // 0x40 R Unknown Rx Buffer Register
++ volatile unsigned int STHR; // 0x44 W 0x00 Transmitter Holding Register
++ volatile unsigned int SDLL; // 0x48 R/W 0x00 Divisor Latch (LSB)
++ volatile unsigned int SDLM; // 0x4C R/W 0x00 Divisor Latch (MSB)
++ volatile unsigned int SIER; // 0x50 R/W 0x00 Interrupt Enable register
++ volatile unsigned int NOTDEFINE1[3];
++ volatile unsigned int SCCR; // 0x60 R/W 0x00 Smart Card Control Register
++ volatile unsigned int STC; // 0x64 R/W 0x00 Smart Card TX Count register
++ volatile unsigned int NOTDEFINE2[6];
++ volatile unsigned int IRCFG; // 0x80 R/W 0x00 IRDA Configuration Register
++}UART, *PUART;
++
++
++typedef struct _UARTPORTMUX{
++ volatile unsigned int CHSEL; // 0x00 R/W 0x3210 Channel Selection Register
++ volatile unsigned int CHST; // 0x00 R 0x0000 Channel Status Register
++}UARTPORTMUX, *PUARTPORTMUX;
++
++
++/*******************************************************************************
++* 23. CAN Controller Register Define (Base Addr = 0xF0531000)
++********************************************************************************/
++//#define HwCAN_BASE 0xF0531000
++
++typedef struct _CANCTRL{
++ volatile unsigned int CANCTRLREG; // CAN Control Register 0x00 0x0001
++ volatile unsigned int CANSTATUS; // Status Register 0x04 0x0000
++ volatile unsigned int CANERRORCNT; // Error Counter 0x08 0x0000 Read only
++ volatile unsigned int CANBITTIMING; // Bit Timing Register 0x0C 0x2301 Write enabled by CCE
++ volatile unsigned int CANINTREG; // Interrupt Register 0x10 0x0000 Read only
++ volatile unsigned int CANTESTREG; // Test Register 0x14 0x00 & 0br0000000 1) Write enabled by Test
++ volatile unsigned int CANBRPEXTREG; // Extenstion Register 0x18 0x0000 Write enabled by CCE
++ volatile unsigned int NOTDEFINE0; // __reserved 0x1C 3)
++ volatile unsigned int CANIF1CMDREQ; // Command Request 0x20 0x0001
++ volatile unsigned int CANIF1CMDMSK; // Command Mask 0x24 0x0000
++ volatile unsigned int CANIF1MSK1; // IF1 Mask1 0x28 0xFFFF
++ volatile unsigned int CANIF1MSK2; // IF1 Mask2 0x2C 0xFFFF
++ volatile unsigned int CANIF1ARBIT1; // IF1 Arbitration 1 0x30 0x0000
++ volatile unsigned int CANIF1ARBIT2; // IF1 Arbitration 2 0x34 0x0000
++ volatile unsigned int CANIF1MSGCTL; // IF1 Message Control 0x38 0x0000
++ volatile unsigned int CANIF1DTA1; // IF1 Data A 1 0x3C 0x0000
++ volatile unsigned int CANIF1DTA2; // IF1 Data A 2 0x40 0x0000
++ volatile unsigned int CANIF1DTB1; // IF1 Data B 1 0x44 0x0000
++ volatile unsigned int CANIF1DTB2; // IF1 Data B 2 0x48 0x0000
++ volatile unsigned int NOTDEFINE1[13]; // __reserved 0x50-0x7C 3)
++ volatile unsigned int CANIF2CMDREQ; // Command Request 0x80 0x0001
++ volatile unsigned int CANIF2CMDMSK; // Command Mask 0x84 0x0000
++ volatile unsigned int CANIF2MSK1; // IF1 Mask1 0x88 0xFFFF
++ volatile unsigned int CANIF2MSK2; // IF1 Mask2 0x8C 0xFFFF
++ volatile unsigned int CANIF2ARBIT1; // IF1 Arbitration 1 0x90 0x0000
++ volatile unsigned int CANIF2ARBIT2; // IF1 Arbitration 2 0x94 0x0000
++ volatile unsigned int CANIF2MSGCTL; // IF1 Message Control 0x98 0x0000
++ volatile unsigned int CANIF2DTA1; // IF1 Data A 1 0x9C 0x0000
++ volatile unsigned int CANIF2DTA2; // IF1 Data A 2 0xA0 0x0000
++ volatile unsigned int CANIF2DTB1; // IF1 Data B 1 0xA4 0x0000
++ volatile unsigned int CANIF2DTB2; // IF1 Data B 2 0xA8 0x0000
++ volatile unsigned int NOTDEFINE2[20]; // __reserved 0xAC-0xFC 3)
++ volatile unsigned int CANTRSREQ1; // Transmission Requrest 1 0x100 0x0000 Read only
++ volatile unsigned int CANTRSREQ2; // Transmission Request 2 0x104 0x0000 Read only
++ volatile unsigned int NOTDEFINE3[5]; // __reserved 0x108-0x11C 3)
++ volatile unsigned int CANNEWDT1; // New Data 1 0x120 0x0000 Read only
++ volatile unsigned int CANNEWDT2; // New Data 2 0x124 0x0000 Read only
++ volatile unsigned int NOTDEFINE4[5]; // __reserved 0x128-0x13C 3)
++ volatile unsigned int CANINTPEND1; // Interrupt Pending 1 0x140 0x0000 Read only
++ volatile unsigned int CANINTPEND2; // Interrupt Pending 2 0x144 0x0000 Read only
++ volatile unsigned int NOTDEFINE5[5]; // __reserved 0x148-0x15C 3)
++ volatile unsigned int CANMSGVALID1; // Message Valid 1 0x160 0x0000 Read only
++ volatile unsigned int CANMSGVALID3; // Message Valid 2 0x164 0x0000 Read only
++ volatile unsigned int NOTDEFINE6[5]; // __reserved 0x168-0x17C
++
++}CANCTRL, *PCANCTRL;
++
++
++
++
++/*******************************************************************************
++* 24. DMA Controller Register Define (Base Addr = 0xF0540000)
++********************************************************************************/
++/*
++#define HwGDMA0_BASE *(volatile unsigned long *)0xF0540000
++#define HwGDMA1_BASE *(volatile unsigned long *)0xF0540100
++#define HwGDMA2_BASE *(volatile unsigned long *)0xF0540200
++#define HwGDMA3_BASE *(volatile unsigned long *)0xF0540300
++*/
++typedef struct _GDMACTRL{
++ volatile unsigned int ST_SADR0; // 0x00 R/W 0x00000000 Start Address of Source Block
++ volatile unsigned int SPARAM0; // 0x04 R/W 0x00000000 Parameter of Source Block
++ volatile unsigned int NOTDEFINE0; // 0x08
++ volatile unsigned int C_SADR0; // 0x0C R 0x00000000 Current Address of Source Block
++ volatile unsigned int ST_DADR0; // 0x10 R/W 0x00000000 Start Address of Destination Block
++ volatile unsigned int DPARAM0; // 0x14 R/W 0x00000000 Parameter of Destination Block
++ volatile unsigned int NOTDEFINE1; // 0x18
++ volatile unsigned int C_DADR0; // 0x1C R 0x00000000 Current Address of Destination Block
++ volatile unsigned int HCOUNT0; // 0x20 R/W 0x00000000 Initial and Current Hop count
++ volatile unsigned int CHCTRL0; // 0x24 R/W 0x00000000 Channel Control Register
++ volatile unsigned int RPTCTRL0; // 0x28 R/W 0x00000000 Repeat Control Register
++ volatile unsigned int EXTREQ0; // 0x2C R/W 0x00000000 External DMA Request Register
++ volatile unsigned int ST_SADR1; // 0x30 R/W 0x00000000 Start Address of Source Block
++ volatile unsigned int SPARAM1; // 0x34 R/W 0x00000000 Parameter of Source Block
++ volatile unsigned int NOTDEFINE2; // 0x38
++ volatile unsigned int C_SADR1; // 0x3C R 0x00000000 Current Address of Source Block
++ volatile unsigned int ST_DADR1; // 0x40 R/W 0x00000000 Start Address of Destination Block
++ volatile unsigned int DPARAM1; // 0x44 R/W 0x00000000 Parameter of Destination Block
++ volatile unsigned int NOTDEFINE3; // 0x48
++ volatile unsigned int C_DADR1; // 0x4C R 0x00000000 Current Address of Destination Block
++ volatile unsigned int HCOUNT1; // 0x50 R/W 0x00000000 Initial and Current Hop count
++ volatile unsigned int CHCTRL1; // 0x54 R/W 0x00000000 Channel Control Register
++ volatile unsigned int RPTCTRL1; // 0x58 R/W 0x00000000 Repeat Control Register
++ volatile unsigned int EXTREQ1; // 0x5C R/W 0x00000000 External DMA Request Register
++ volatile unsigned int ST_SADR2; // 0x60 R/W 0x00000000 Start Address of Source Block
++ volatile unsigned int SPARAM2; // 0x64/ R/W 0x00000000 Parameter of Source Block
++ volatile unsigned int NOTDEFINE4; // 0x68
++ volatile unsigned int C_SADR2; // 0x6C R 0x00000000 Current Address of Source Block
++ volatile unsigned int ST_DADR2; // 0x70 R/W 0x00000000 Start Address of Destination Block
++ volatile unsigned int DPARAM2; // 0x74/ R/W 0x00000000 Parameter of Destination Block
++ volatile unsigned int NOTDEFINE5; // 0x78
++ volatile unsigned int C_DADR2; // 0x7C R 0x00000000 Current Address of Destination Block
++ volatile unsigned int HCOUNT2; // 0x80 R/W 0x00000000 Initial and Current Hop count
++ volatile unsigned int CHCTRL2; // 0x84 R/W 0x00000000 Channel Control Register
++ volatile unsigned int RPTCTRL2; // 0x88 R/W 0x00000000 Repeat Control Register
++ volatile unsigned int EXTREQ2; // 0x8C R/W 0x00000000 External DMA Request Register
++ volatile unsigned int CHCONFIG; // 0x90 R/W 0x00000000 Channel Configuration Register
++}GDMACTRL, *PGDMACTRL;
++
++
++typedef struct _GDMANCTRL{
++ volatile unsigned int ST_SADR; // 0x000 R/W Start Address of Source Block
++ volatile unsigned int SPARAM[2]; // 0x004~ R/W Parameter of Source Block
++ volatile unsigned int C_SADR; // 0x00C R Current Address of Source Block
++ volatile unsigned int ST_DADR; // 0x010 R/W Start Address of Destination Block
++ volatile unsigned int DPARAM[2]; // 0x014~ R/W Parameter of Destination Block
++ volatile unsigned int C_DADR; // 0x01C R Current Address of Destination Block
++ volatile unsigned int HCOUNT; // 0x020 R/W Initial and Current Hop count
++ volatile unsigned int CHCTRL; // 0x024 R/W Channel Control Register
++ volatile unsigned int RPTCTRL; // 0x028 R/W Repeat Control Register
++ volatile unsigned int EXTREQ; // 0x02C R/W External DMA Request Register
++} GDMANCTRL, *PGDMANCTRL;
++
++/*******************************************************************************
++* 25. Real Time Clock(RTC) Register Define (Base Addr = 0xF05F2000)
++********************************************************************************/
++//#define HwRTC_BASE *(volatile unsigned long*)0xF05F2000
++
++typedef struct _RTC{
++ volatile unsigned int RTCCON; // 0x00 R/W 0x00 RTC Control Register
++ volatile unsigned int INTCON; // 0x04 R/W - RTC Interrupt Control Register
++ volatile unsigned int RTCALM; // 0x08 R/W - RTC Alarm Control Register
++ volatile unsigned int ALMSEC; // 0x0C R/W - Alarm Second Data Register
++
++ volatile unsigned int ALMMIN; // 0x10 R/W - Alarm Minute Data Register
++ volatile unsigned int ALMHOUR; // 0x14 R/W - Alarm Hour Data Register
++ volatile unsigned int ALMDATE; // 0x18 R/W - Alarm Date Data Register
++ volatile unsigned int ALMDAY; // 0x1C R/W - Alarm Day of Week Data Register
++
++ volatile unsigned int ALMMON; // 0x20 R/W - Alarm Month Data Register
++ volatile unsigned int ALMYEAR; // 0x24 R/W - Alarm Year Data Register
++ volatile unsigned int BCDSEC; // 0x28 R/W - BCD Second Register
++ volatile unsigned int BCDMIN; // 0x2C R/W - BCD Minute Register
++
++ volatile unsigned int BCDHOUR; // 0x30 R/W - BCD Hour Register
++ volatile unsigned int BCDDATE; // 0x34 R/W - BCD Date Register
++ volatile unsigned int BCDDAY; // 0x38 R/W - BCD Day of Week Register
++ volatile unsigned int BCDMON; // 0x3C R/W - BCD Month Register
++
++ volatile unsigned int BCDYEAR; // 0x40 R/W - BCD Year Register
++ volatile unsigned int RTCIM; // 0x44 R/W - RTC Interrupt Mode Register
++ volatile unsigned int RTCPEND; // 0x48 R/W - RTC Interrupt Pending Register
++ volatile unsigned int RTCSTR; // 0x48 R/W - RTC Interrupt Pending Register
++}RTC, *PRTC;
++
++
++/*******************************************************************************
++* 26. TouchScreen ADC (TSADC) Register Define (Base Addr = 0xF05F4000)
++********************************************************************************/
++//#define HwTSADC_BASE *(volatile unsigned long*)0xF05F4000
++typedef struct _TSADC{
++ volatile unsigned int ADCCON; // 0x00 R/W 0x00003FC4 ADC Control Register
++ volatile unsigned int ADCTSC; // 0x04 R/W 0x00000058 ADC Touch Screen Control Register
++ volatile unsigned int ADCDLY; // 0x08 R/W 0x000000FF ADC Start or Interval Delay Register
++ volatile unsigned int ADCDAT0; // 0x0C R - ADC Conversion Data Register
++ volatile unsigned int ADCDAT1; // 0x10 R - ADC Conversion Data Register
++ volatile unsigned int ADCUPDN; // 0x14 R/W 0x00000000 Stylus Up or Down Interrupt Register
++ volatile unsigned int ADCCLRINT; // 0x18 W - Clear ADC Interrrupt
++ volatile unsigned int NOTDEFINE0; // 0x1C - - Reserved
++ volatile unsigned int ADCCLRUPDN; // 0x20 W - Clear Pen UP/DOWN Interrupt
++}TSADC, *PTSADC;
++
++
++/*******************************************************************************
++* 27. Error Correction Code Register Define (Base Addr = 0xF0539000)
++********************************************************************************/
++//#define HwECC_BASE *(volatile unsigned long*)0xF0539000
++//#define HwECCERRADDR_BASE *(volatile unsigned long*)0xF0539050
++
++//=================================================================================
++// ECC Code Register
++//=================================================================================
++typedef struct _ECC{
++ volatile unsigned int ECC_CTRL; // 0x000 R/W ECC Control Register
++ volatile unsigned int ECC_BASE; // 0x004 R/W Base Address for ECC Calculation
++ volatile unsigned int ECC_MASK; // 0x008 R/W Address mask for ECC area.
++ volatile unsigned int ECC_CLEAR; // 0x00C R/W ECC Clear
++ volatile unsigned int ECC_CODE0; // 0x010 R/W 1st ECC Code Register
++ volatile unsigned int ECC_CODE1; // 0x014 R/W 2nd ECC Code Register
++ volatile unsigned int ECC_CODE2; // 0x018 R/W 3rd ECC Code Register
++ volatile unsigned int ECC_CODE3; // 0x01C R/W 4th ECC Code Register
++ volatile unsigned int ECC_CODE4; // 0x020 R/W 5th ECC Code Register
++ volatile unsigned int ECC_CODE5; // 0x024 R/W 6th ECC Code Register
++ volatile unsigned int ECC_CODE6; // 0x028 R/W 7th ECC Code Register
++ volatile unsigned int ECC_CODE7; // 0x02C R/W 8th ECC Code Register
++ volatile unsigned int ECC_CODE8; // 0x030 R/W 9th ECC Code Register
++ volatile unsigned int ECC_CODE9; // 0x034 R/W 10th ECC Code Register
++ volatile unsigned int ECC_CODE10; // 0x038 R/W 11th ECC Code Register
++ volatile unsigned int ECC_CODE11; // 0x03C R/W 12th ECC Code Register
++ volatile unsigned int ECC_CODE12; // 0x040 R/W 13th ECC Code Register
++ volatile unsigned int ECC_CODE13; // 0x044 R/W 14th ECC Code Register
++ volatile unsigned int ECC_CODE14; // 0x048 R/W 15th ECC Code Register
++ volatile unsigned int ECC_CODE15; // 0x04C R/W 16th ECC Code register
++ volatile unsigned int ECC_EADDR0; // 0x050 R ECC Error Address Register0
++ volatile unsigned int ECC_EADDR1; // 0x054 R ECC Error Address Register1
++ volatile unsigned int ECC_EADDR2; // 0x058 R ECC Error Address Register2
++ volatile unsigned int ECC_EADDR3; // 0x05C R ECC Error Address Register3
++ volatile unsigned int ECC_EADDR4; // 0x060 R ECC Error Address Register4
++ volatile unsigned int ECC_EADDR5; // 0x064 R ECC Error Address Register5
++ volatile unsigned int ECC_EADDR6; // 0x068 R ECC Error Address Register6
++ volatile unsigned int ECC_EADDR7; // 0x06C R ECC Error Address Register7
++ volatile unsigned int ECC_EADDR8; // 0x070 R ECC Error Address Register8
++ volatile unsigned int ECC_EADDR9; // 0x074 R ECC Error Address Register9
++ volatile unsigned int ECC_EADDR10; // 0x078 R ECC Error Address Register10
++ volatile unsigned int ECC_EADDR11; // 0x07C R ECC Error Address Register11
++ volatile unsigned int ECC_EADDR12; // 0x080 R ECC Error Address Register12
++ volatile unsigned int ECC_EADDR13; // 0x084 R ECC Error Address Register13
++ volatile unsigned int ECC_EADDR14; // 0x088 R ECC Error Address Register14
++ volatile unsigned int ECC_EADDR15; // 0x08C R ECC Error Address Register15
++ volatile unsigned int ERRNUM; // 0x090 R ECC Error Number
++ volatile unsigned int ECC_IREQ; // 0x094 R/W ECC Interrupt Control Register
++}ECC, *PECC;
++
++typedef struct _SLCECC{
++ volatile unsigned int ECC_CTRL; // 0x00 R/W 0x00000000 ECC Control Register
++ volatile unsigned int ECC_BASE; // 0x04 R/W 0x00000000 Base Address for ECC Calculation
++ volatile unsigned int ECC_MASK; // 0x08 R/W 0x00000000 Address mask for ECC area.
++ volatile unsigned int ECC_CLEAR; // 0x0C R/W ECC Clear
++ volatile unsigned int SECC_0; // 0x10 R/W 0x00000000 1st SLC ECC Code Register
++ volatile unsigned int SECC_1; // 0x14 R/W 0x00000000 2nd SLC ECC Code Register
++ volatile unsigned int SECC_2; // 0x18 R/W 0x00000000 3rd SLC ECC Code Register
++ volatile unsigned int SECC_3; // 0x1C R/W 0x00000000 4th SLC ECC Code Register
++ volatile unsigned int SECC_4; // 0x20 R/W 0x00000000 5th SLC ECC Code Register
++ volatile unsigned int SECC_5; // 0x24 R/W 0x00000000 6th SLC ECC Code Register
++ volatile unsigned int SECC_6; // 0x28 R/W 0x00000000 7th SLC ECC Code Register
++ volatile unsigned int SECC_7; // 0x2C R/W 0x00000000 8th SLC ECC Code Register
++ volatile unsigned int SECC_8; // 0x30 R/W 0x00000000 9th SLC ECC Code Register
++ volatile unsigned int SECC_9; // 0x34 R/W 0x00000000 10th SLC ECC Code Register
++ volatile unsigned int SECC_10; // 0x38 R/W 0x00000000 11th SLC ECC Code Register
++ volatile unsigned int SECC_11; // 0x3C R/W 0x00000000 12th SLC ECC Code Register
++ volatile unsigned int SECC_12; // 0x40 R/W 0x00000000 13th SLC ECC Code Register
++ volatile unsigned int SECC_13; // 0x44 R/W 0x00000000 14th SLC ECC Code Register
++ volatile unsigned int SECC_14; // 0x48 R/W 0x00000000 15th SLC ECC Code Register
++ volatile unsigned int SECC_15; // 0x4C R/W 0x00000000 16th SLC ECC Code register
++
++}SLCECC, *PSLCECC;
++
++typedef struct _MLCECC4{
++ volatile unsigned int ECC_CTRL; // 0x00 R/W 0x00000000 ECC Control Register
++ volatile unsigned int ECC_BASE; // 0x04 R/W 0x00000000 Base Address for ECC Calculation
++ volatile unsigned int ECC_MASK; // 0x08 R/W 0x00000000 Address mask for ECC area.
++ volatile unsigned int ECC_CLEAR; // 0x0C R/W ECC Clear
++ volatile unsigned int MECC4_0; // 0x10 R/W 0x00000000 1st MLC ECC4 Code Register
++ volatile unsigned int MECC4_1; // 0x14 R/W 0x00000000 2nd MLC ECC4 Code register
++
++}MLCECC4, *PMLCECC4;
++
++typedef struct _MLCECC8{
++ volatile unsigned int ECC_CTRL; // 0x00 R/W 0x00000000 ECC Control Register
++ volatile unsigned int ECC_BASE; // 0x04 R/W 0x00000000 Base Address for ECC Calculation
++ volatile unsigned int ECC_MASK; // 0x08 R/W 0x00000000 Address mask for ECC area.
++ volatile unsigned int ECC_CLEAR; // 0x0C R/W ECC Clear
++ volatile unsigned int MECC8_0; // 0x10 R/W 0x00000000 1st MLC ECC8 Code Register
++ volatile unsigned int MECC8_1; // 0x14 R/W 0x00000000 2nd MLC ECC8 Code Register
++ volatile unsigned int MECC8_2; // 0x18 R/W 0x00000000 3rd MLC ECC8 Code Register
++ volatile unsigned int MECC8_3; // 0x1C R/W 0x00000000 4th MLC ECC8 Code Register
++}MLCECC8, *PMLCECC8;
++
++
++typedef struct _MLCECC12{
++ volatile unsigned int ECC_CTRL; // 0x00 R/W 0x00000000 ECC Control Register
++ volatile unsigned int ECC_BASE; // 0x04 R/W 0x00000000 Base Address for ECC Calculation
++ volatile unsigned int ECC_MASK; // 0x08 R/W 0x00000000 Address mask for ECC area.
++ volatile unsigned int ECC_CLEAR; // 0x0C R/W ECC Clear
++ volatile unsigned int MECC12_0; // 0x10 R/W 0x00000000 1st MLC ECC12 Code Register
++ volatile unsigned int MECC12_1; // 0x14 R/W 0x00000000 2nd MLC ECC12 Code Register
++ volatile unsigned int MECC12_2; // 0x18 R/W 0x00000000 3rd MLC ECC12 Code Register
++ volatile unsigned int MECC12_3; // 0x1C R/W 0x00000000 4th MLC ECC12 Code Register
++ volatile unsigned int MECC12_4; // 0x20 R/W 0x00000000 5th MLC ECC12 Code Register
++}MLCECC12, *PMLCECC12;
++
++
++typedef struct _MLCECC14{
++ volatile unsigned int ECC_CTRL; // 0x00 R/W 0x00000000 ECC Control Register
++ volatile unsigned int ECC_BASE; // 0x04 R/W 0x00000000 Base Address for ECC Calculation
++ volatile unsigned int ECC_MASK; // 0x08 R/W 0x00000000 Address mask for ECC area.
++ volatile unsigned int ECC_CLEAR; // 0x0C R/W ECC Clear
++ volatile unsigned int MECC14_0; // 0x10 R/W 0x00000000 1st MLC ECC14 Code Register
++ volatile unsigned int MECC14_1; // 0x14 R/W 0x00000000 2nd MLC ECC14 Code Register
++ volatile unsigned int MECC14_2; // 0x18 R/W 0x00000000 3rd MLC ECC14 Code Register
++ volatile unsigned int MECC14_3; // 0x1C R/W 0x00000000 4th MLC ECC14 Code Register
++ volatile unsigned int MECC14_4; // 0x20 R/W 0x00000000 5th MLC ECC14 Code Register
++ volatile unsigned int MECC14_5; // 0x24 R/W 0x00000000 6th MLC ECC14 Code Register
++}MLCECC14, *PMLCECC14;
++
++
++typedef struct _MLCECC16{
++ volatile unsigned int ECC_CTRL; // 0x00 R/W 0x00000000 ECC Control Register
++ volatile unsigned int ECC_BASE; // 0x04 R/W 0x00000000 Base Address for ECC Calculation
++ volatile unsigned int ECC_MASK; // 0x08 R/W 0x00000000 Address mask for ECC area.
++ volatile unsigned int ECC_CLEAR; // 0x0C R/W ECC Clear
++ volatile unsigned int MECC16_0; // 0x10 R/W 0x00000000 1st MLC ECC16 Code Register
++ volatile unsigned int MECC16_1; // 0x14 R/W 0x00000000 2nd MLC ECC16 Code Register
++ volatile unsigned int MECC16_2; // 0x18 R/W 0x00000000 3rd MLC ECC16 Code Register
++ volatile unsigned int MECC16_3; // 0x1C R/W 0x00000000 4th MLC ECC16 Code Register
++ volatile unsigned int MECC16_4; // 0x20 R/W 0x00000000 5th MLC ECC16 Code Register
++ volatile unsigned int MECC16_5; // 0x24 R/W 0x00000000 6th MLC ECC16 Code Register
++ volatile unsigned int MECC16_6; // 0x28 R/W 0x00000000 7th MLC ECC16 Code Register
++}MLCECC16, *PMLCECC16;
++
++//=================================================================================
++// ECC Error Address Register
++//=================================================================================
++typedef struct _SLCECCERRADDR{
++ volatile unsigned int SECC_EADDR0; // 0x50 R 0x00000000 SLC ECC Error Address Register0
++ volatile unsigned int SECC_EADDR1; // 0x54 R 0x00000000 SLC ECC Error Address Register1
++ volatile unsigned int SECC_EADDR2; // 0x58 R 0x00000000 SLC ECC Error Address Register2
++ volatile unsigned int SECC_EADDR3; // 0x5C R 0x00000000 SLC ECC Error Address Register3
++ volatile unsigned int SECC_EADDR4; // 0x60 R 0x00000000 SLC ECC Error Address Register4
++ volatile unsigned int SECC_EADDR5; // 0x64 R 0x00000000 SLC ECC Error Address Register5
++ volatile unsigned int SECC_EADDR6; // 0x68 R 0x00000000 SLC ECC Error Address Register6
++ volatile unsigned int SECC_EADDR7; // 0x6C R 0x00000000 SLC ECC Error Address Register7
++ volatile unsigned int SECC_EADDR8; // 0x70 R 0x00000000 SLC ECC Error Address Register8
++ volatile unsigned int SECC_EADDR9; // 0x74 R 0x00000000 SLC ECC Error Address Register9
++ volatile unsigned int SECC_EADDR10; // 0x78 R 0x00000000 SLC ECC Error Address Register10
++ volatile unsigned int SECC_EADDR11; // 0x7C R 0x00000000 SLC ECC Error Address Register11
++ volatile unsigned int SECC_EADDR12; // 0x80 R 0x00000000 SLC ECC Error Address Register12
++ volatile unsigned int SECC_EADDR13; // 0x84 R 0x00000000 SLC ECC Error Address Register13
++ volatile unsigned int SECC_EADDR14; // 0x88 R 0x00000000 SLC ECC Error Address Register14
++ volatile unsigned int SECC_EADDR15; // 0x8C R 0x00000000 SLC ECC Error Address Register15
++ volatile unsigned int ERRNUM; // 0x90 R 0x00000000 ECC Error Number
++ volatile unsigned int ECC_IREQ; // 0x94 R/W 0x00000000 ECC Interrupt Control Register
++}SLCECCERRADDR, *PSLCECCERRADDR;
++
++
++typedef struct _MLCECC4ERRADDR{
++ volatile unsigned int MECC4_EADDR0; // 0x50 R 0x00000000 MLC ECC Error Address Register0
++ volatile unsigned int MECC4_EADDR1; // 0x54 R 0x00000000 MLC ECC Error Address Register1
++ volatile unsigned int MECC4_EADDR2; // 0x58 R 0x00000000 MLC ECC Error Address Register2
++ volatile unsigned int MECC4_EADDR3; // 0x5C R 0x00000000 MLC ECC Error Address Register3
++ volatile unsigned int NOTDEFINE0[12];
++ volatile unsigned int ERRNUM; // 0x90 R 0x00000000 ECC Error Number
++ volatile unsigned int ECC_IREQ; // 0x94 R/W 0x00000000 ECC Interrupt Control Register
++}MLCECC4ERRADDR, *PMLCECC4ERRADDR;
++
++
++typedef struct _MLCECC8ERRADDR{
++ volatile unsigned int MECC8_EADDR0; // 0x50 R 0x00000000 MLC ECC8 Error Address Register0
++ volatile unsigned int MECC8_EADDR1; // 0x54 R 0x00000000 MLC ECC8 Error Address Register1
++ volatile unsigned int MECC8_EADDR2; // 0x58 R 0x00000000 MLC ECC8 Error Address Register2
++ volatile unsigned int MECC8_EADDR3; // 0x5C R 0x00000000 MLC ECC8 Error Address Register3
++ volatile unsigned int MECC8_EADDR4; // 0x60 R 0x00000000 MLC ECC8 Error Address Register4
++ volatile unsigned int MECC8_EADDR5; // 0x64 R 0x00000000 MLC ECC8 Error Address Register5
++ volatile unsigned int MECC8_EADDR6; // 0x68 R 0x00000000 MLC ECC8 Error Address Register6
++ volatile unsigned int MECC8_EADDR7; // 0x6C R 0x00000000 MLC ECC8 Error Address Register7
++ volatile unsigned int NOTDEFINE0[8];
++ volatile unsigned int ERRNUM; // 0x90 R 0x00000000 ECC Error Number
++ volatile unsigned int ECC_IREQ; // 0x94 R/W 0x00000000 ECC Interrupt Control Register
++}MLCECC8ERRADDR, *PMLCECC8ERRADDR;
++
++
++typedef struct _MLCECC12ERRADDR{
++ volatile unsigned int MECC12_EADDR0; // 0x50 R 0x00000000 MLC ECC12 Error Address Register0
++ volatile unsigned int MECC12_EADDR1; // 0x54 R 0x00000000 MLC ECC12 Error Address Register1
++ volatile unsigned int MECC12_EADDR2; // 0x58 R 0x00000000 MLC ECC12 Error Address Register2
++ volatile unsigned int MECC12_EADDR3; // 0x5C R 0x00000000 MLC ECC12 Error Address Register3
++ volatile unsigned int MECC12_EADDR4; // 0x60 R 0x00000000 MLC ECC12 Error Address Register4
++ volatile unsigned int MECC12_EADDR5; // 0x64 R 0x00000000 MLC ECC12 Error Address Register5
++ volatile unsigned int MECC12_EADDR6; // 0x68 R 0x00000000 MLC ECC12 Error Address Register6
++ volatile unsigned int MECC12_EADDR7; // 0x6C R 0x00000000 MLC ECC12 Error Address Register7
++ volatile unsigned int MECC12_EADDR8; // 0x70 R 0x00000000 MLC ECC12 Error Address Register8
++ volatile unsigned int MECC12_EADDR9; // 0x74 R 0x00000000 MLC ECC12 Error Address Register9
++ volatile unsigned int MECC12_EADDR10; // 0x78 R 0x00000000 MLC ECC12 Error Address Register10
++ volatile unsigned int MECC12_EADDR11; // 0x7C R 0x00000000 MLC ECC12 Error Address Register11
++ volatile unsigned int NOTDEFINE0[4];
++ volatile unsigned int ERRNUM; // 0x90 R 0x00000000 ECC Error Number
++ volatile unsigned int ECC_IREQ; // 0x94 R/W 0x00000000 ECC Interrupt Control Register
++}MLCECC12ERRADDR, *PMLCECC12ERRADDR;
++
++typedef struct _MLCECC14ERRADDR{
++ volatile unsigned int MECC14_EADDR0; // 0x50 R 0x00000000 MLC ECC14 Error Address Register0
++ volatile unsigned int MECC14_EADDR1; // 0x54 R 0x00000000 MLC ECC14 Error Address Register1
++ volatile unsigned int MECC14_EADDR2; // 0x58 R 0x00000000 MLC ECC14 Error Address Register2
++ volatile unsigned int MECC14_EADDR3; // 0x5C R 0x00000000 MLC ECC14 Error Address Register3
++ volatile unsigned int MECC14_EADDR4; // 0x60 R 0x00000000 MLC ECC14 Error Address Register4
++ volatile unsigned int MECC14_EADDR5; // 0x64 R 0x00000000 MLC ECC14 Error Address Register5
++ volatile unsigned int MECC14_EADDR6; // 0x68 R 0x00000000 MLC ECC14 Error Address Register6
++ volatile unsigned int MECC14_EADDR7; // 0x6C R 0x00000000 MLC ECC14 Error Address Register7
++ volatile unsigned int MECC14_EADDR8; // 0x70 R 0x00000000 MLC ECC14 Error Address Register8
++ volatile unsigned int MECC14_EADDR9; // 0x74 R 0x00000000 MLC ECC14 Error Address Register9
++ volatile unsigned int MECC14_EADDR10; // 0x78 R 0x00000000 MLC ECC14 Error Address Register10
++ volatile unsigned int MECC14_EADDR11; // 0x7C R 0x00000000 MLC ECC14 Error Address Register11
++ volatile unsigned int MECC14_EADDR12; // 0x80 R 0x00000000 MLC ECC14 Error Address Register12
++ volatile unsigned int MECC14_EADDR13; // 0x84 R 0x00000000 MLC ECC14 Error Address Register13
++ volatile unsigned int NOTDEFINE0[2];
++ volatile unsigned int ERRNUM; // 0x90 R 0x00000000 ECC Error Number
++ volatile unsigned int ECC_IREQ; // 0x94 R/W 0x00000000 ECC Interrupt Control Register
++}MLCECC14ERRADDR, *PMLCECC14ERRADDR;
++
++typedef struct _MLCECC16ERRADDR{
++ volatile unsigned int MECC16_EADDR0; // 0x50 R 0x00000000 MLC ECC16 Error Address Register0
++ volatile unsigned int MECC16_EADDR1; // 0x54 R 0x00000000 MLC ECC16 Error Address Register1
++ volatile unsigned int MECC16_EADDR2; // 0x58 R 0x00000000 MLC ECC16 Error Address Register2
++ volatile unsigned int MECC16_EADDR3; // 0x5C R 0x00000000 MLC ECC16 Error Address Register3
++ volatile unsigned int MECC16_EADDR4; // 0x60 R 0x00000000 MLC ECC16 Error Address Register4
++ volatile unsigned int MECC16_EADDR5; // 0x64 R 0x00000000 MLC ECC16 Error Address Register5
++ volatile unsigned int MECC16_EADDR6; // 0x68 R 0x00000000 MLC ECC16 Error Address Register6
++ volatile unsigned int MECC16_EADDR7; // 0x6C R 0x00000000 MLC ECC16 Error Address Register7
++ volatile unsigned int MECC16_EADDR8; // 0x70 R 0x00000000 MLC ECC16 Error Address Register8
++ volatile unsigned int MECC16_EADDR9; // 0x74 R 0x00000000 MLC ECC16 Error Address Register9
++ volatile unsigned int MECC16_EADDR10; // 0x78 R 0x00000000 MLC ECC16 Error Address Register10
++ volatile unsigned int MECC16_EADDR11; // 0x7C R 0x00000000 MLC ECC16 Error Address Register11
++ volatile unsigned int MECC16_EADDR12; // 0x80 R 0x00000000 MLC ECC16 Error Address Register12
++ volatile unsigned int MECC16_EADDR13; // 0x84 R 0x00000000 MLC ECC16 Error Address Register13
++ volatile unsigned int MECC16_EADDR14; // 0x88 R 0x00000000 MLC ECC16 Error Address Register14
++ volatile unsigned int MECC16_EADDR15; // 0x8C R 0x00000000 MLC ECC16 Error Address Register15
++ volatile unsigned int ERRNUM; // 0x90 R 0x00000000 ECC Error Number
++ volatile unsigned int ECC_IREQ; // 0x94 R/W 0x00000000 ECC Interrupt Control Register
++}MLCECC16ERRADDR, *PMLCECC16ERRADDR;
++
++
++/*******************************************************************************
++* 28. Multi-Protocol Encapsulation Forward Error Correction (MPEFEC)
++* Register Define (Base Addr = 0xF0510000)
++********************************************************************************/
++//#define HwMPEFEC_BASE *(volatile unsigned long*)0xF0510000
++
++typedef struct _MPEFEC{
++ volatile unsigned int MERR; // 0x00 R/W 0x00000000 MPE_FEC Enable/ RESET [1] -> MPE_FEC Enable [0] -> MPE_FEC RESET
++ volatile unsigned int MSR; // 0x04 W 0x00000000 MPE_FEC Start (Auto clear)
++ volatile unsigned int MFRNR; // 0x08 R/W 0x03FF03FF [25:16] active row number -1 : MPE Frame Áß ¸î°³ÀÇ row´ÜÀ§·Î MEPFEC¸¦ µ¿ÀÛ½ÃÅ°´ÂÁö ¼³Á¤ ÇÔ [9:0] MPE Frame ÀÇ row -1 °³¼ö
++ volatile unsigned int MDSAR; // 0x0C R/W 0x00000000 Datagram ÀÌ ÀúÀåµÇ¾î ÀÖ´Â memoryÀÇ start address Memory Data Source Address
++ volatile unsigned int EFR; // 0x10 R/W 0x00000000 Erasure flag ÀÌ ÀúÀåµÇ¾îÀÖ´Â memoryÀÇ start address
++ volatile unsigned int MCR; // 0x14 R/W 0x00014000 MPE_FEC Control [25] ->Ç×»ó 0 À̾î¾ß ÇÔ [24] -> erasure_on(erasure»ç¿ë 1¡¯b1) [22:16] -> eras_thres(erasure°¡eras_thresº¸´Ù Å©¸é erasure ¸¦ »ç¿ëÇÏÁö¾ÊÀ½) [15:8] -> stuffing_len [6:0] -> puncturing_len
++ volatile unsigned int MSTR; // 0x18 R 0x00000000 MPE_FEC Status [1] -> mpe_done [0] -> mpe_over
++ volatile unsigned int MIER; // 0x1C R 0x00000000 MPE_FEC IRQ Enable [1] -> mpe_done IRQ Enable [0] -> mpe_over IRQ Enable
++ volatile unsigned int MICR; // 0x20 W 0x00000000 MPE_FEC IRQ_clear [1] -> mpe_done IRQ clear [0] -> mpe_over IRQ clear
++ volatile unsigned int MARR; // 0x24 R/W 0x03FF0000 MPE Frame Áß ¸î¹ø° row ºÎÅÍ MPEFEC ¸¦ ÇÒ °ÍÀÎÁö ¼³Á¤ÇÔ [9:0] start row number [25:16] end row number
++ volatile unsigned int ECNT; // 0x28 R/W 0x00000000 MPEFECs º¹±¸µÈ Error °³¼ö
++ volatile unsigned int NOTDEFINE0[3]; // 0x34-0x3C R/W Reserved
++}MPEFEC, *PMPEFEC;
++
++
++/*******************************************************************************
++* 29. IOBUS Configuration Register Define (Base Addr = 0xF05F5000)
++********************************************************************************/
++//#define HwIOBUSCFG_BASE *(volatile unsigned long*)0xF05F5000
++
++typedef struct _IOBUSCFG{
++ volatile unsigned int USBOTG; // 0x00 Refer to USB OTG Configuration Register (OTGCR) in 15.2 register Description for USB 2.0 OTG Controller USB OTG Configuration register (OTGCR)USB OTG Configuration Register (OTGCR)USB OTG Configuration register (OTGCR)USB OTG Configuration Register (OTGCR)USB OTG Configuration Register (OTGCR).
++ volatile unsigned int USB11H; // 0x04 Refer to USB 1.1 Host Configuration Register (USB11H) in 14.2 register Description for USB 1.1 Host Controller & Transceiver¡±
++ volatile unsigned int IOBAPB; // 0x08 IOBUS APB wait counter register
++ volatile unsigned int STORAGE; // 0x0C Storage Device Configuration Register
++ volatile unsigned int HCLKEN0; // 0x10 IOBUS AHB clock enable Register 0
++ volatile unsigned int HCLKEN1; // 0x14 IOBUS AHB clock enable Register 1
++ volatile unsigned int HCLKMEN; // 0x18 DMA AHB clock mask enable Register
++ volatile unsigned int NOTDEFINE0; // 0x1C Reserved
++ volatile unsigned int HRSTEN0; // 0x20 IOBUS AHB Hreset Control register 0
++ volatile unsigned int HRSTEN1; // 0x24 IOBUS AHB Hreset Control register 1
++ volatile unsigned int USBOTG0; // 0x28 Refer to USB PHY Configuration Register0 (UPCR0) in 15.2 register Description for USB 2.0 OTG Controller
++ volatile unsigned int USBOTG1; // 0x2C Refer to USB PHY Configuration Register1 (UPCR1) in 15.2 register Description for USB 2.0 OTG Controller
++ volatile unsigned int USBOTG2; // 0x30 Refer to USB PHY Configuration Register2 (UPCR2) in 15.2 register Description for USB 2.0 OTG Controller
++ volatile unsigned int USBOTG3; // 0x34 Refer to USB PHY Configuration Register3 (UPCR3) in 15.2 register Description for USB 2.0 OTG Controller
++ volatile unsigned int IO_A2X; // 0x38 IOBUS AHB2AXI Control Register
++}IOBUSCFG, *PIOBUSCFG;
++
++
++
++/************************************************************************
++* Channel 0 Memory Controller Register Define (Base Addr = 0xF1000000)
++************************************************************************/
++//#define HwEMC_BASE *(volatile unsigned long *)0xF1000000 // External Memory Controller Base Register
++typedef struct _EMC{
++ volatile unsigned int SDCFG; // 0x00 R/W 0x6A484C00 SDRAM Configuration Register
++ volatile unsigned int SDFSM; // 0x04 R 0x00000000 SDRAM FSM Status Register
++ volatile unsigned int MCFG; // 0x08 R/W 0x01000042 Miscellaneous Configuration Register
++ volatile unsigned int TST; // 0x0C W 0x00000000 Should not write to this ? it¡¯s for TEST
++ volatile unsigned int CSCFG0; // 0x10 R/W 0x468AC809 External Chip Select 0 Config. Register (CSN_CS0)
++ volatile unsigned int NOTDEFINE0[2]; // 0x14 R/W 0x508AD01A Reserved - 0x18 R/W 0x608AD03A Reserved
++ volatile unsigned int CSCFG3; // 0x1C R/W 0x728AD01A External Chip Select 3 Config. Register (CSN_NOR)
++ volatile unsigned int CLKCFG; // 0x20 R/W 0x00000A05 Memory Controller Version & Periodic Clock Enable Count Register
++ volatile unsigned int SDCMD; // 0x24 R/W - SDRAM Command Write Register
++ volatile unsigned int SDCFG1; // 0x28 R/W 0xFFFFFFFF Extra SDRAM Configuration Register
++}EMC, *PEMC;
++
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 6 DDI_BUS_V0.00 Dec.11 2008
++********************************************************************************/
++/************************************************************************
++* 4. LCD INTERFACE Register Define (Base Addr = 0xF0200000)
++************************************************************************/
++//#define HwLCDC0_BASE *(volatile unsigned long *)0xF0200000 // LCDC0 Control Base Register
++//#define HwLCDC1_BASE *(volatile unsigned long *)0xF0204000 // LCDC1 Control Base Register
++
++typedef struct _LCDC{
++ volatile unsigned int LCTRL; // 0x00 R/W 0x00000000 LCD Control Register
++ volatile unsigned int LBC; // 0x04 R/W 0x00000000 LCD Background Color Register
++ volatile unsigned int LCLKDIV; // 0x08 R/W 0x00000000 LCD Clock Divider Register
++ volatile unsigned int LHTIME1; // 0x0C R/W 0x00000000 LCD Horizontal Timing Register 1
++ volatile unsigned int LHTIME2; // 0x10 R/W 0x00000000 LCD Horizontal Timing Register 2
++ volatile unsigned int LVTIME1; // 0x14 R/W 0x00000000 LCD Vertical Timing Register 1
++ volatile unsigned int LVTIME2; // 0x18 R/W 0x00000000 LCD Vertical Timing Register 2
++ volatile unsigned int LVTIME3; // 0x1C R/W 0x00000000 LCD Vertical Timing Register 3
++ volatile unsigned int LVTIME4; // 0x20 R/W 0x00000000 LCD Vertical Timing Register 4
++ volatile unsigned int LLUTR; // 0x24 R/W 0x00000000 LCD Lookup Register for Red
++ volatile unsigned int LLUTG; // 0x28 R/W 0x00000000 LCD Lookup Register for Green
++ volatile unsigned int LLUTB; // 0x2C R/W 0x00000000 LCD Lookup Register for Blue
++ volatile unsigned int LDP7L; // 0x30 R/W 0x4d2b3401 LCD Modulo 7 Dithering Pattern (low)
++ volatile unsigned int LDP7H; // 0x34 R/W 0x0000003f LCD Modulo 7 Dithering Pattern (high)
++ volatile unsigned int LDP5; // 0x38 R/W 0x1d0b0610 LCD Modulo 5 Dithering Pattern Register
++ volatile unsigned int LDP4; // 0x3C R/W 0x00000768 LCD Modulo 4 Dithering Pattern Register
++ volatile unsigned int LDP3; // 0x40 R/W 0x00000034 LCD 3-bit Dithering Pattern Register
++ volatile unsigned int LCP1; // 0x44 R/W 0x000000ff LCD Clipping Register1
++ volatile unsigned int LCP2; // 0x48 R/W 0x000000ff LCD Clipping Register2
++ volatile unsigned int LDS; // 0x4C R/W 0x00000000 LCD Display Size Register
++ volatile unsigned int LSTATUS; // 0x50 R/CLR 0x00000000 LCD Status Register
++ volatile unsigned int LIM; // 0x54 R/W 0x0000001f LCD Interrupt Register.
++ volatile unsigned int LGR0; // 0x58 R/W 0x00000000 LCD Gamma Correction Register 0 for Red Color
++ volatile unsigned int LGR1; // 0x5C R/W 0x00000000 LCD Gamma Correction Register 1 for Red Color
++ volatile unsigned int LGG0; // 0x60 R/W 0x00000000 LCD Gamma Correction Register 0 for Green Color
++ volatile unsigned int LGG1; // 0x64 R/W 0x00000000 LCD Gamma Correction Register 1 for Green Color
++ volatile unsigned int LGB0; // 0x68 R/W 0x00000000 LCD Gamma Correction Register 0 for Blue Color
++ volatile unsigned int LGB1; // 0x6C R/W 0x00000000 LCD Gamma Correction Register 1 for Blue Color
++ volatile unsigned int LENH; // 0x70 R/W 0x00000020 LCD Color Enhancement Register
++ volatile unsigned int NOTDEFINE0; // 0x74
++ volatile unsigned int LI0C; // 0x78 R/W 0x00000000 LCD Image 0 Control Register
++ volatile unsigned int LI0P; // 0x7C R/W 0x00000000 LCD Image 0 Position Register
++ volatile unsigned int LI0S; // 0x80 R/W 0x00000000 LCD Image 0 Size Register
++ volatile unsigned int LI0BA0; // 0x84 R/W 0x00000000 LCD Image 0 Base Address 0 Register.
++ volatile unsigned int LI0CA; // 0x88 R/W 0x00000000 LCD Image 0 Current Address Register.
++ volatile unsigned int LI0BA1; // 0x8C R/W 0x00000000 LCD Image 0 Base Address 1 Register
++ volatile unsigned int LI0BA2; // 0x90 R/W 0x00000000 LCD Image 0 Base Address 2 Register
++ volatile unsigned int LI0O; // 0x94 R/W 0x00000000 LCD Image 0 Offset Register
++ volatile unsigned int LI0SR; // 0x98 R/W 0x00000000 LCD Image 0 Scale ratio
++ volatile unsigned int LI0A; // 0x9C R/W 0x00000000 LCD Image 0 Alpha Configuration Register
++ volatile unsigned int LI0KR; // 0xA0 R/W 0x00000000 LCD Image 0 Keying Register for RED or LUMA(Y)
++ volatile unsigned int LI0KG; // 0xA4 R/W 0x00000000 LCD Image 0 Keying Register for BLUE or CHROMA(Cb)
++ volatile unsigned int LI0KB; // 0xA8 R/W 0x00000000 LCD Image 0 Keying Register for GREEN or CHROMA(Cr)
++ volatile unsigned int LI0EN; // 0xAC R/W 0x00000000 LCD Image 0 Enhancement Register
++ volatile unsigned int LI1C; // 0xB0 R/W 0x00000000 LCD Image 1 Control Register
++ volatile unsigned int LI1P; // 0xB4 R/W 0x00000000 LCD Image 1 Position Register
++ volatile unsigned int LI1S; // 0xB8 R/W 0x00000000 LCD Image 1 Size Register
++ volatile unsigned int LI1BA0; // 0xBC R/W 0x00000000 LCD Image 1 Base Address 0 Register.
++ volatile unsigned int LI1CA; // 0xC0 R/W 0x00000000 LCD Image 1 Current Address Register.
++ volatile unsigned int LI1BA1; // 0xC4 R/W 0x00000000 Not Used
++ volatile unsigned int LI1BA2; // 0xC8 R/W 0x00000000 Not Used
++ volatile unsigned int LI1O; // 0xCC R/W 0x00000000 LCD Image 1 Offset Register
++ volatile unsigned int LI1SR; // 0xD0 R/W 0x00000000 LCD Image 1 Scale ratio-
++ volatile unsigned int LI1A; // 0xD4 R/W 0x00000000 LCD Image 1 Alpha Configuration Register
++ volatile unsigned int LI1KR; // 0xD8 R/W 0x00000000 LCD Image 1 Keying Register for RED or LUMA(Y)
++ volatile unsigned int LI1KG; // 0xDC R/W 0x00000000 LCD Image 1 Keying Register for BLUE or CHROMA(Cb)
++ volatile unsigned int LI1KB; // 0xE0 R/W 0x00000000 LCD Image 1 Keying Register for GREEN or CHROMA(Cr)
++ volatile unsigned int LI1EN; // 0xE4 R/W 0x00000000 LCD Image 1 Enhancement Register
++ volatile unsigned int LI2C; // 0xE8 R/W 0x00000000 LCD Image 2 Control Register
++ volatile unsigned int LI2P; // 0xEC R/W 0x00000000 LCD Image 2 Position Register
++ volatile unsigned int LI2S; // 0xF0 R/W 0x00000000 LCD Image 2 Size Register
++ volatile unsigned int LI2BA0; // 0xF4 R/W 0x00000000 LCD Image 2 Base Address 0 Register.
++ volatile unsigned int LI2CA; // 0xF8 R/W 0x00000000 LCD Image 2 Current Address Register.
++ volatile unsigned int LI2BA1; // 0xFC R/W 0x00000000 Not Used
++ volatile unsigned int LI2BA2; // 0x100 R/W 0x00000000 Not Used
++ volatile unsigned int LI2O; // 0x104 R/W 0x00000000 LCD Image 2 Offset Register
++ volatile unsigned int LI2SR; // 0x108 R/W 0x00000000 LCD Image 2 Scale ratio
++ volatile unsigned int LI2A; // 0x10C R/W 0x00000000 LCD Image 2 Alpha Register
++ volatile unsigned int LI2KR; // 0x110 R/W 0x00000000 LCD Image 2 Keying Register for RED or LUMA(Y)
++ volatile unsigned int LI2KG; // 0x114 R/W 0x00000000 LCD Image 2 Keying Register for BLUE or CHROMA(Cb)
++ volatile unsigned int LI2KB; // 0x118 R/W 0x00000000 LCD Image 2 Keying Register for GREEN or CHROMA(Cr)
++ volatile unsigned int LI2EN; // 0x11C R/W 0x00000000 LCD Image 2 Enhancement Register
++ volatile unsigned int LUTIDX; // 0x120 Lookup Table index Register
++
++}LCDC, *PLCDC;
++
++
++//#define HwLCDLUT0_BASE *(volatile unsigned long *)0xF0200400 // LCD LUT 0 Base Register
++//#define HwLCDLUT1_BASE *(volatile unsigned long *)0xF0204400 // LCD LUT 1 Base Register
++
++typedef struct _LUT_TYPE{
++ volatile unsigned char BCr; // [7:0]
++ volatile unsigned char GCb; // [15:8]
++ volatile unsigned char RY; // [23:16]
++ volatile unsigned char dummy; // [31:24]]
++}LUT_TYPE, *PLUT_TYPE;
++
++typedef struct _LCDLUT{
++ volatile LUT_TYPE LUTDAT[256]; // 0x400 ~ 0x7FF
++}LCDLUT, *PLCDLUT;
++
++
++/************************************************************************
++* 5. LCD System Interface Register Define (Base Addr = 0xF020C400)
++************************************************************************/
++//#define HwLCDSI_BASE *(volatile unsigned long *)0xF020C400 // LCDSI Base Register
++
++typedef struct _LCDSI0{
++ volatile unsigned int CTRL0; // 0x400 R/W 0x00000000 Control register for LCDSI
++}LCDSI0, *PLCDSI0;
++
++typedef struct _LCDSI1{
++ volatile unsigned int CTRL1; // 0x800 R/W 0xA0229011 Control register for nCS0 when RS=0(for core access)
++ volatile unsigned int CTRL2; // 0x804 R/W 0xA0429021 Control register for nCS0 when RS=1(for core access)
++ volatile unsigned int CTRL3; // 0x808 R/W 0xA0129009 Control register for nCS1 when RS=0(for core access)
++ volatile unsigned int CTRL4; // 0x80C R/W 0xA0229011 Control register for nCS1 when RS=1(for core access)
++ volatile unsigned int CS0RS0; // 0x810 R/W -if this register is read or written, reading or writing operations are generated on nCS0 while RS = 0.
++ volatile unsigned int NOTDEFINE0; // 0x814
++ volatile unsigned int CS0RS1; // 0x818 R/W -if this register is read or written, reading or writing operations are generated on nCS0 while RS = 1.
++ volatile unsigned int NOTDEFINE1; // 0x81C
++ volatile unsigned int CS1RS0; // 0x820 R/W -if this register is read or written, reading or writing operations are generated on nCS1 while RS = 0.
++ volatile unsigned int NOTDEFINE2; // 0x824
++ volatile unsigned int CS1RS1; // 0x828 R/W -if this register is read or written, reading or writing operations are generated on nCS1 while RS = 1.
++ volatile unsigned int NOTDEFINE3; // 0x82C
++ volatile unsigned int CTRL5; // 0x830 R/W 0xA0229011 Control register for nCS0 when RS=0(for lcd access)
++ volatile unsigned int CTRL6; // 0x834 R/W 0xA0429021 Control register for nCS0 when RS=1(for lcd access)
++ volatile unsigned int CTRL7; // 0x838 R/W 0xA0129009 Control register for nCS1 when RS=0(for lcd access)
++ volatile unsigned int CTRL8; // 0x83C R/W 0xA0229011 Control register for nCS1 when RS=1(for lcd access)
++}LCDSI1, *PLCDSI1;
++
++
++/***********************************************************************
++* 6. Memory to Memory Scaler Register Define (Base Addr = 0xF0210000/0xF0220000)
++************************************************************************/
++//#define HwM2MSCALER1_BASE *(volatile unsigned long *)0xF0251000
++//#define HwM2MSCALER1_BASE *(volatile unsigned long *)0xF0252000
++typedef struct _M2MSCALER{
++ volatile unsigned int SRCBASEY; // 0x000 R/W 0x00000000 Scaler source base address for Y
++ volatile unsigned int SRCBASEU; // 0x004 R/W 0x00000000 Scaler source base address for U (Cb)
++ volatile unsigned int SRCBASEV; // 0x008 R/W 0x00000000 Scaler source base address for V (Cr)
++ volatile unsigned int SRCSIZE; // 0x00c R/W 0x00000000 Source image size register
++ volatile unsigned int SRCOFF; // 0x010 R/W 0x00000000 Source image line offset register
++ volatile unsigned int SRCCFG; // 0x014 R/W 0x00000000 Source image configuration register
++ volatile unsigned int NOTDEFINE0[2];
++ volatile unsigned int DSTBASEY; // 0x020 R/W 0x00000000 Scaler destination base address for Y
++ volatile unsigned int DSTBASEU; // 0x024 R/W 0x00000000 Scaler destination base address for U (Cb)
++ volatile unsigned int DSTBASEV; // 0x028 R/W 0x00000000 Scaler destination base address for V (Cr)
++ volatile unsigned int DSTSIZE; // 0x02c R/W 0x00000000 Destination image size register
++ volatile unsigned int DSTOFF; // 0x030 R/W 0x00000000 Destination image line offset register
++ volatile unsigned int DSTCFG; // 0x034 R/W 0x00000000 Destination image configuration register
++ volatile unsigned int NOTDEFINE1[2];
++ volatile unsigned int MSCINF; // 0x040 R/W 0x00000000 Scaling information register
++ volatile unsigned int MSCCTR; // 0x044 R/W 0x00000000 Scaler control register
++ volatile unsigned int MSCSTR; // 0x048 R/W 0x00000000 Scaler status register
++ volatile unsigned int HSTROBE; // 0x04C R/W 0x000A0002 Horizontal Strobe Timing Control Register
++ volatile unsigned int DSTRMCNT; // 0x050 R/W 0x00000000 Destination Rolling Status Register
++ volatile unsigned int CRCNT; // 0x054 R 0x00000000 Destination Rolling Status Register
++ volatile unsigned int CLIP0; // 0x058 R/W 0x00000000 RGB-to-YCbCr Clipping Configuration Register 0
++ volatile unsigned int CLIP1; // 0x05C R/W 0x000000FF RGB-to-YCbCr Clipping Configuration Register 1
++ volatile unsigned int VSTROBE; // 0x060 R/W 0x0000000A Vertical Strobe Timing Control Register
++}M2MSCALER, *PM2MSCALER;
++
++
++/************************************************************************
++* 7. NTSC/PAL ENCODER Composite Output Register Define (Base Addr = 0xF9000000)
++************************************************************************/
++//#define HwTVE_BASE *(volatile unsigned long *)0xF9000000 // TV Encoder Base Register
++typedef struct _NTSCPAL{
++ volatile unsigned int STATA; //0x00
++ volatile unsigned int ECMDA; //0x04
++ volatile unsigned int ECMDB; //0x08
++ volatile unsigned int GLK; //0x0C
++ volatile unsigned int SCH; //0x10
++ volatile unsigned int HUE; //0x14
++ volatile unsigned int SAT; //0x18
++ volatile unsigned int CONT; //0x1C
++ volatile unsigned int BRIGHT; //0x20
++ volatile unsigned int FSC_ADJM; //0x24
++ volatile unsigned int FSC_ADJL; //0x28
++ volatile unsigned int ECMDC; //0x2C
++ volatile unsigned int NOTDEFINE0[4]; //0x30, 34, 38, 3C
++ volatile unsigned int DACSEL; //0x40
++ volatile unsigned int NOTDEFINE1[3]; //0x44, 48, 4C
++ volatile unsigned int DACPD; //0x50
++ volatile unsigned int NOTDEFINE2[11]; //0x54, 58, 5C, 60, 64, 68, 6C, 70, 74, 78, 7C
++ volatile unsigned int ICNTL; //0x80
++ volatile unsigned int HVOFFST; //0x84
++ volatile unsigned int HOFFST; //0x88
++ volatile unsigned int VOFFST; //0x8C
++ volatile unsigned int HSVSO; //0x90
++ volatile unsigned int HSOE; //0x94
++ volatile unsigned int HSOB; //0x98
++ volatile unsigned int VSOB; //0x9C
++ volatile unsigned int VSOE; //0xA0
++}NTSCPAL, *PNTSCPAL;
++
++typedef struct _NTSCPALOP{
++ volatile unsigned int VENCON; //0xF9080000
++ volatile unsigned int VENCIF; //0xF9080004
++}NTSCPALOP, *PNTSCPALOP;
++
++/************************************************************************
++* 8. HDMI Register Define (Base Addr = 0xF0254000)
++************************************************************************/
++//#define HwHDMICTRL_BASE *(volatile unsigned long *)0xF0254000 //Controller register base address
++typedef struct _HDMICTRL{
++ volatile unsigned int INTC_CON; // 0x0000 R/W Interrupt Control Register 0x00
++ volatile unsigned int INTC_FLAG; // 0x0004 R/W Interrupt Flag Register 0x00
++ volatile unsigned int AESKEY_VALID; // 0x0008 R aeskey_valid Register 0x00
++ volatile unsigned int HPD; // 0x000C R HPD signal 0x00
++}HDMICTRL, *PHDMICTRL;
++
++//#define HwHDMICORE_BASE *(volatile unsigned long *)0xF0255000
++typedef struct _HDMICORE{
++ volatile unsigned int HDMI_CON_0; // 0x0000 R/W HDMI system control register 0 0x00
++ volatile unsigned int HDMI_CON_1; // 0x0004 R/W HDMI system control register 1 0x00
++ volatile unsigned int HDMI_CON_2; // 0x0008 R/W HDMI system control register 2 0x00
++ volatile unsigned int NOTDEFINE_; // 0x000C
++ volatile unsigned int STATUS; // 0x0010 R/W HDMI system status register 0x00
++ volatile unsigned int PHY_STATUS; // 0x0014 R PHY status register 0x00
++ volatile unsigned int NOTDEFINE0[2]; // 0x18, 0x1C
++ volatile unsigned int STATUS_EN; // 0x0020 R/W HDMI system status enable register 0x00
++ volatile unsigned int NOTDEFINE1[3]; // 0x24, 0x28, 0x2C
++ volatile unsigned int HPD; // 0x0030 R/W HPD control register 0x00
++ volatile unsigned int NOTDEFINE2[3]; // 0x34, 0x38, 0x3C
++ volatile unsigned int MODE_SEL; // 0x0040 R/W HDMI/DVI mode selection 0x00
++ volatile unsigned int ENC_EN; // 0x0044 R/W HDCP encryption enable register 0x00
++ volatile unsigned int NOTDEFINE3[2]; // 0x48, 0x4C
++//Video Related Registers
++ volatile unsigned int BLUE_SCREEN_0; // 0x0050 R/W Pixel values for blue screen 0x00
++ volatile unsigned int BLUE_SCREEN_1; // 0x0054 R/W Pixel values for blue screen 0x00
++ volatile unsigned int BLUE_SCREEN_2; // 0x0058 R/W Pixel values for blue screen 0x00
++ volatile unsigned int NOTDEFINE4; // 0x5C
++ volatile unsigned int HDMI_YMAX; // 0x0060 R/W Maximum Y (or "R,G,B)" pixel value 0x00
++ volatile unsigned int HDMI_YMIN; // 0x0064 R/W Minimum Y (or "R,G,B)" pixel value 0x00
++ volatile unsigned int HDMI_CMAX; // 0x0068 R/W Maximum Cb/Cr pixel value 0x00
++ volatile unsigned int HDMI_CMIN; // 0x006C R/W Minimum Cb/Cr pixel value 0x00
++ volatile unsigned int NOTDEFINE5[12]; // 0x70~0x9C
++ volatile unsigned int H_BLANK[2]; // 0x00A0 ,0x00A4 R/W Horizontal blanking setting 0x00
++ volatile unsigned int NOTDEFINE6[2]; // 0xA8 0xAC
++ volatile unsigned int V_BLANK[3]; // 0x00B0,0x00B4, 0x00B8 R/W Vertical blanking setting 0x00
++ volatile unsigned int NOTDEFINE7[2]; // 0xB8 0xBC
++ volatile unsigned int H_V_LINE[3]; // 0x00C0,0x00C4, 0x00C8 R/W Horizontal line & vertical line setting 0x00
++ volatile unsigned int NOTDEFINE8[6]; // 0xCC, 0xD0, 0xD4, 0xD8, 0xDC, 0xE0
++ volatile unsigned int VSYNC_POL; // 0x00E4 R/W Vertical sync polarity control register 0x00
++ volatile unsigned int INT_PRO_MODE ; // 0x00E8 R/W Interlace/Progressive control register 0x00
++ volatile unsigned int NOTDEFINE9[9]; // 0xEC, 0xF0, 0xF4, 0xF8, 0xFC, 0x100, 0x104, 0x108, 0x10C
++ volatile unsigned int V_BLANK_F[3]; // 0x0110,0x0114, 0x0118 R/W Vertical blanking setting for bottom field 0x00
++ volatile unsigned int NOTDEFINE10; // 0x011C
++ volatile unsigned int H_SYNC_GEN[3] ; // 0x0120,0x0124 ,0x0128 R/W Horizontal sync generation setting 0x00
++ volatile unsigned int NOTDEFINE11; // 0x012C
++ volatile unsigned int V_SYNC_GEN1[3]; // 0x0130,0x0134,0x0138 R/W Vertical sync generation for top field or frame 0x01
++ volatile unsigned int NOTDEFINE12; // 0x013C
++ volatile unsigned int V_SYNC_GEN2[3]; // 0x0140,0x0144,0x0148 R/W Vertical sync generation for bottom field - vertical position 0x01
++ volatile unsigned int NOTDEFINE13; // 0x014C
++ volatile unsigned int V_SYNC_GEN3[3]; // 0x0150,0x0154,0x0158 R/W Vertical sync generation for bottom field - horizontal position 0x01
++ volatile unsigned int NOTDEFINE14; // 0x015C
++//Audio Related Registers
++ volatile unsigned int ASP_CON; // 0x0160 R/W ASP packet control register 0x00
++ volatile unsigned int ASP_SP_FLAT; // 0x0164 R/W ASP packet sp_flat bit control 0x00
++ volatile unsigned int NOTDEFINE15[2]; // 0x0168,0x016C
++ volatile unsigned int ASP_CHCFG[4]; // 0x0170,0x0174,0x0178,0x017C R/W ASP audio channel configuration 0x04
++ volatile unsigned int ACR_CON; // 0x0180 R/W ACR packet control register 0x00
++ volatile unsigned int ACR_MCTS[3]; // 0x0184,0x0188,0x018C R/W Measured CTS value 0x01
++ volatile unsigned int ACR_CTS[3]; // 0x0190,0x0194,0x0198 R/W CTS value for fixed CTS transmission mode. 0xe8
++ volatile unsigned int NOTDEFINE16; // 0x019C
++ volatile unsigned int ACR_N[3]; // 0x01A0,0x01A4,0x01A8 R/W N value for ACR packet 0xe8
++ volatile unsigned int NOTDEFINE17; // 0x01AC
++ volatile unsigned int ACR_LSB2; // 0x01B0 R/W Alternate LSB for fixed CTS transmission mode 0x00
++ volatile unsigned int ACR_TXCNT; // 0x01B4 R/W Number of ACR packet transmission per frame 0x1f
++ volatile unsigned int ACR_TXINTERVAL; // 0x01B8 R/W Interval for ACR packet transmission 0x63
++ volatile unsigned int ACR_CTS_OFFSET; // 0x01BC R/W CTS offset for measured CTS mode 0x00
++//Packet Related Registers
++ volatile unsigned int GCP_CON ; // 0x01C0 R/W ACR packet control register 0x00
++ volatile unsigned int NOTDEFINE18[3]; // 0x01C4,0x01C8,0x01CC,
++ volatile unsigned int GCP_BYTE[3]; // 0x01D0,0x01D4,0x01D8 R/W GCP packet body 0x00
++ volatile unsigned int NOTDEFINE19; // 0x01DC,
++ volatile unsigned int ACP_CON; // 0x01E0 R/W ACP packet control register 0x00
++ volatile unsigned int NOTDEFINE20[3]; // 0x01E4,0x01E8,0x01EC,
++ volatile unsigned int ACP_TYPE; // 0x01F0 R/W ACP packet header 0x00
++ volatile unsigned int NOTDEFINE21[3]; // 0x01F4,0x01F8,0x01FC,
++ volatile unsigned int ACP_DATA[17]; // 0x0200~0x0240 R/W ACP packet body 0x00
++ volatile unsigned int NOTDEFINE22[3]; // 0x0244,0x0248,0x024C,
++ volatile unsigned int ISRC_CON; // 0x0250 R/W ACR packet control register 0x00
++ volatile unsigned int NOTDEFINE23[4]; // 0x0254,0x0258,0x025C,0x0260
++ volatile unsigned int ISRC1_HEADER1; // 0x0264 R/W ISCR1 packet header 0x00
++ volatile unsigned int NOTDEFINE24[2]; // 0x0268,0x026C,
++ volatile unsigned int ISRC1_DATA[16]; // 0x0270~0x02AC R/W ISRC1 packet body 0x00
++ volatile unsigned int ISRC2_DATA[16]; // 0x02B0~0x02EC R/W ISRC2 packet body 0x00
++ volatile unsigned int NOTDEFINE25[4]; // 0x02F0,0x02F4,0x02F8,0x2FC
++
++ volatile unsigned int AVI_CON; // 0x0300 R/W AVI packet control register 0x00
++ volatile unsigned int NOTDEFINE26[3]; // 0x0304,0x0308,0x030c
++ volatile unsigned int AVI_CHECK_SUM; // 0x0310 R/W AVI packet checksum 0x00
++ volatile unsigned int NOTDEFINE27[3]; // 0x0314,0x0318,0x031c
++ volatile unsigned int AVI_BYTE[13]; // 0x0320~0x0350 R/W AVI packet body 0x00
++ volatile unsigned int NOTDEFINE28[3]; // 0x0354,0x0358,0x035c
++ volatile unsigned int AUI_CON; // 0x0360 R/W AUI packet control register 0x00
++ volatile unsigned int NOTDEFINE29[3]; // 0x0364,0x0368,0x036c
++ volatile unsigned int AUI_CHECK_SUM; // 0x0370 R/W AUI packet checksum 0x00
++ volatile unsigned int NOTDEFINE30[3]; // 0x0374,0x0378,0x037c
++ volatile unsigned int AUI_BYTE[5]; // 0x0380~0x0390 R/W AUI packet body 0x00
++ volatile unsigned int NOTDEFINE31[3]; // 0x0394,0x0398,0x039c
++
++ volatile unsigned int MPG_CON; // 0x03A0 R/W ACR packet control register 0x00
++ volatile unsigned int NOTDEFINE32[3]; // 0x03A4,0x03A8,0x03Ac
++ volatile unsigned int MPG_CHECK_SUM; // 0x03B0 R/W MPG packet checksum 0x00
++ volatile unsigned int NOTDEFINE33[3]; // 0x03B4,0x03B8,0x03Bc
++
++ volatile unsigned int MPG_BYTE[5]; // 0x03C0~0x03D0 R/W MPG packet body 0x00
++ volatile unsigned int NOTDEFINE34[11]; // 0x03D4,0x03D8,0x03Dc
++ // 0x03E0,
++ // 0x03F
++ volatile unsigned int SPD_CON; // 0x0400 R/W SPD packet control register 0x00
++ volatile unsigned int NOTDEFINE35[3]; // 0x0344,0x0348,0x034c
++ volatile unsigned int SPD_HEADER0; // 0x0410~ R/W SPD packet header 0x00
++ volatile unsigned int SPD_HEADER1; // 0x0414 R/W SPD packet header 0x00
++ volatile unsigned int SPD_HEADER2; // 0x0418 R/W SPD packet header 0x00
++ volatile unsigned int NOTDEFINE36; // 0x041C
++ volatile unsigned int SPD_DATA[28]; // 0x0420~0x048C R/W SPD packet body 0x00
++
++//HDCP Related Registes
++ volatile unsigned int GAMUT_CON; // 0x0500 R/W GAMUT packet control register 0x00
++ volatile unsigned int GAMUT_HEADER0; // 0x0504 R/W GAMUT packet header 0x00
++ volatile unsigned int GAMUT_HEADER1; // 0x0508 R/W GAMUT packet header 0x00
++ volatile unsigned int GAMUT_HEADER2; // 0x050C R/W GAMUT packet header 0x00
++ volatile unsigned int GAMUT_DATA[28]; // 0x0510~0x057C R/W GAMUT packet body 0x00
++ volatile unsigned int NOTDEFINE37[16]; // 0x0580~
++ // 0x0590,~
++ // 0x05A0~
++ // 0x05B0~
++ volatile unsigned int DC_CONTROL; // 0x05C0 R/W Deep Color Control Register 0x00
++ volatile unsigned int VIDEO_PATTERN_GEN; // 0x05C4 R/W Video Pattern Generation Register 0x00
++ volatile unsigned int HPD_GEN ; // 0x05C8 R/W HPD Duration value register 0x01
++ volatile unsigned int NOTDEFINE38[113]; // 0x05CC
++ // 0x05D0,
++ // 0x05E0
++ // 0x05F0
++
++ volatile unsigned int HDCP_SHA1[20]; // 0x0600~0x064C R/W SHA-1 value from repeater 0x00
++ volatile unsigned int HDCP_KSV_LIST[5]; // 0x0650~0x0660 R/W KSV list from repeater 0x00
++
++ volatile unsigned int HDCP_KSV_LIST_CON; // 0x0664 R/W KSV list control 0x00
++ volatile unsigned int NOTDEFINE39[2]; // 0x0668,0x066C
++ volatile unsigned int HDCP_SHA_RESULT; // 0x0670 R/W SHA-1 checking result register 0x00
++ volatile unsigned int NOTDEFINE40[3]; // 0x0674,0x0678,0x067c
++ volatile unsigned int HDCP_CTRL1; // 0x0680 R/W HDCP control register1 0x00
++ volatile unsigned int HDCP_CTRL2; // 0x0684 R/W HDCP control register2 0x00
++ volatile unsigned int NOTDEFINE41[2]; // 0x0688,0x068c
++ volatile unsigned int HDCP_CHECK_RESULT; // 0x0690 R/W Ri and Pj value checking result 0x00
++ volatile unsigned int NOTDEFINE42[3]; // 0x0394,0x0398,0x039c
++ volatile unsigned int HDCP_BKSV[5]; // 0x06A0~0x06B0 R/W KSV of Rx 0x00
++ volatile unsigned int NOTDEFINE43[3]; // 0x06B4,0x06B8,0x06Bc
++
++ volatile unsigned int HDCP_AKSV[5]; //0x06C0~ 0x06D0 R/W KSV of Tx 0x00
++ volatile unsigned int NOTDEFINE44[3]; // 0x06D4,0x06D8,0x06Dc
++ volatile unsigned int HDCP_An[8]; // 0x06E0~ 0x06FC R/W An value 0x00
++ volatile unsigned int HDCP_BCAPS; // 0x0700 R/W BCAPS from Rx 0x00
++ volatile unsigned int NOTDEFINE45[3]; // 0x0704,0x0708,0x070c
++ volatile unsigned int HDCP_BSTATUS_0; // 0x0710 R/W BSTATUS from Rx 0x00
++ volatile unsigned int HDCP_BSTATUS_1; // 0x0714 R/W BSTATUS from Rx 0x00
++ volatile unsigned int NOTDEFINE46[10]; // 0x0718,0x071c
++ // 0x0720,
++ // 0x0730
++ volatile unsigned int HDCP_Ri_0; // 0x0740 R/W Ri value of Tx 0x00
++ volatile unsigned int HDCP_Ri_1; // 0x0744 R/W Ri value of Tx 0x00
++ volatile unsigned int NOTDEFINE47[13]; // 0x0748
++ // 0x0750,
++ // 0x0760,
++ // 0x0770
++ volatile unsigned int HDCP_I2C_INT; // 0x0780 R/W I2C interrupt flag 0x00
++ volatile unsigned int NOTDEFINE48[3]; // 0x0784,0x0788,0x078c
++
++ volatile unsigned int HDCP_AN_INT; // 0x0790 R/W An value ready interrupt flag 0x00
++ volatile unsigned int NOTDEFINE49[3]; // 0x0794,0x0798,0x079c
++
++ volatile unsigned int HDCP_WATCGDOG_INT; // 0x07A0 R/W Wachdog interrupt flag 0x00
++ volatile unsigned int NOTDEFINE50[3]; // 0x07A4,0x07A8,0x07Ac
++
++ volatile unsigned int HDCP_Ri_INT; // 0x07B0 R/W Ri value update interrupt flag 0x00
++ volatile unsigned int NOTDEFINE51[7]; // 0x07B4,0x07B8,0x07Bc
++ // 0x07C0,
++ volatile unsigned int HDCP_Ri_Compare_0; // 0x07D0 R/W HDCP Ri Interrupt Frame number index register 0 0x80
++ volatile unsigned int HDCP_Ri_Compare_1; // 0x07D4 R/W HDCP Ri Interrupt Frame number index register 1 0x7f
++ volatile unsigned int NOTDEFINE52[2]; // 0x07D8,0x07Dc
++
++ volatile unsigned int HDCP_Frame_Count; // 0x07E0 R Current value of the frame count index in the hardware 0x00
++}HDMICORE, *PHDMICORE;
++
++//AES register base address
++//fHDMIAES_BASE *(volatile unsigned long *)0xF0256000 //AES register base address
++typedef struct _HDMIAES{
++ volatile unsigned int AES_START; // 0x0000 R/W AES_START 0x00
++ volatile unsigned int NOTDEFINE0[7]; // 0x0004,0x0008,0x000c
++ // 0x0010,
++ volatile unsigned int AES_DATA_SIZE_L; // 0x0020 R/W AES_DATA_SIZE_L 0x20
++ volatile unsigned int AES_DATA_SIZE_H; // 0x0024 R/W AES_DATA_SIZE_H 0x01
++ volatile unsigned int NOTDEFINE1[6]; // 0x0028,0x002c
++ // 0x0030
++ volatile unsigned int AES_DATA; // 0x0040 W AES_DATA -
++}HDMIAES, *PHDMIAES;
++
++//SPDIF Receiver register base address
++//#define HwHDMISPDIF_BASE *(volatile unsigned long *)0xF0257000
++typedef struct _HDMISPDIF{
++ volatile unsigned int SPDIFIN_CLK_CTRL; // 0x0000 R/W SPDIFIN Clock Control Register 0x02
++ volatile unsigned int SPDIFIN_OP_CTRL; // 0x0004 R/W SPDIFIN Operation Control Register 1 0x00
++ volatile unsigned int SPDIFIN_IRQ_MASK; // 0x0008 R/W SPDIFIN Interrupt Request Mask Register 0x00
++ volatile unsigned int SPDIFIN_IRQ_STATUS; // 0x000C R/W SPDIFIN Interrupt Request Status Register 0x00
++ volatile unsigned int SPDIFIN_CONFIG_1; // 0x0010 R/W SPDIFIN Configuration Register 1 0x02
++ volatile unsigned int SPDIFIN_CONFIG_2; // 0x0014 R/W SPDIFIN Configuration Register 2 0x00
++ volatile unsigned int NOTDEFINE0[2]; // 0x0018 0x001C - Reserved -
++ volatile unsigned int SPDIFIN_USER_VALUE_1; // 0x0020 R SPDIFIN User Value Register 1 0x00
++ volatile unsigned int SPDIFIN_USER_VALUE_2; // 0x0024 R SPDIFIN User Value Register 2 0x00
++ volatile unsigned int SPDIFIN_USER_VALUE_3; // 0x0028 R SPDIFIN User Value Register 3 0x00
++ volatile unsigned int SPDIFIN_USER_VALUE_4; // 0x002C R SPDIFIN User Value Register 4 0x00
++ volatile unsigned int SPDIFIN_CH_STATUS_0_1; // 0x0030 R SPDIFIN Channel Status Register 0-1 0x00
++ volatile unsigned int SPDIFIN_CH_STATUS_0_2; // 0x0034 R SPDIFIN Channel Status Register 0-2 0x00
++ volatile unsigned int SPDIFIN_CH_STATUS_0_3; // 0x0038 R SPDIFIN Channel Status Register 0-3 0x00
++ volatile unsigned int SPDIFIN_CH_STATUS_0_4; // 0x003C R SPDIFIN Channel Status Register 0-4 0x00
++ volatile unsigned int SPDIFIN_CH_STATUS_1; // 0x0040 R SPDIFIN Channel Status Register 1 0x00
++ volatile unsigned int NOTDEFINE1; // 0x0044 - Reserved -
++ volatile unsigned int SPDIFIN_FRAME_PERIOD_1; // 0x0048 R SPDIFIN Frame Period Register 1 0x00
++ volatile unsigned int SPDIFIN_FRAME_PERIOD_2; // 0x004C R SPDIFIN Frame Period Register 2 0x00
++ volatile unsigned int SPDIFIN_Pc_INFO_1; // 0x0050 R SPDIFIN Pc Info Register 1 0x00
++ volatile unsigned int SPDIFIN_Pc_INFO_2; // 0x0054 R SPDIFIN Pc Info Register 2 0x00
++ volatile unsigned int SPDIFIN_Pd_INFO_1; // 0x0058 R SPDIFIN Pd Info Register 1 0x00
++ volatile unsigned int SPDIFIN_Pd_INFO_2; // 0x005C R SPDIFIN Pd Info Register 2 0x00
++ volatile unsigned int SPDIFIN_DATA_BUF_0_1; // 0x0060 R SPDIFIN Data Buffer Register 0_1 0x00
++ volatile unsigned int SPDIFIN_DATA_BUF_0_2; // 0x0064 R SPDIFIN Data Buffer Register 0_2 0x00
++ volatile unsigned int SPDIFIN_DATA_BUF_0_3; // 0x0068 R SPDIFIN Data Buffer Register 0_3 0x00
++ volatile unsigned int SPDIFIN_USER_BUF_0; // 0x006C R SPDIFIN User Buffer Register 0 0x00
++ volatile unsigned int SPDIFIN_DATA_BUF_1_1; // 0x0070 R SPDIFIN Data Buffer Register 1_1 0x00
++ volatile unsigned int SPDIFIN_DATA_BUF_1_2; // 0x0074 R SPDIFIN Data Buffer Register 1_2 0x00
++ volatile unsigned int SPDIFIN_DATA_BUF_1_3; // 0x0078 R SPDIFIN Data Buffer Register 1_3 0x00
++ volatile unsigned int SPDIFIN_USER_BUF_1; // 0x007C R SPDIFIN User Buffer Register 1 0x00
++}HDMISPDIF, *PHDMISPDIF;
++
++//I2S Receiver register base address
++//#define HwHDMII2S_BASE *(volatile unsigned long *)0xF0258000
++typedef struct _HDMII2S{
++ volatile unsigned int I2S_CLK_CON; // 0x0000 R/W I2S Clock Enable Register 0x00
++ volatile unsigned int I2S_CON_1; // 0x0004 R/W I2S Control Register 1 0x00
++ volatile unsigned int I2S_CON_2; // 0x0008 R/W I2S Control Register 2 0x00
++ volatile unsigned int I2S_PIN_SEL_0; // 0x000C R/W I2S Input Pin Selection Register 0 0x77
++ volatile unsigned int I2S_PIN_SEL_1; // 0x0010 R/W I2S Input Pin Selection Register 1 0x77
++ volatile unsigned int I2S_PIN_SEL_2; // 0x0014 R/W I2S Input Pin Selection Register 2 0x77
++ volatile unsigned int I2S_PIN_SEL_3; // 0x0018 R/W I2S Input Pin Selection Register 3 0x07
++ volatile unsigned int I2S_DSD_CON; // 0x001C R/W I2S DSD Control Register 0x02
++ volatile unsigned int I2S_MUX_CON; // 0x0020 R/W I2S In/Mux Control Register 0x60
++ volatile unsigned int I2S_CH_ST_CON; // 0x0024 R/W I2S Channel Status Control Register 0x00
++ volatile unsigned int I2S_CH_ST_0; // 0x0028 R/W I2S Channel Status Block 0 0x00
++ volatile unsigned int I2S_CH_ST_1; // 0x002C R/W I2S Channel Status Block 1 0x00
++ volatile unsigned int I2S_CH_ST_2; // 0x0030 R/W I2S Channel Status Block 2 0x00
++ volatile unsigned int I2S_CH_ST_3; // 0x0034 R/W I2S Channel Status Block 3 0x00
++ volatile unsigned int I2S_CH_ST_4; // 0x0038 R/W I2S Channel Status Block 4 0x00
++ volatile unsigned int I2S_CH_ST_SH_0; // 0x003C R I2S Channel Status Block Shadow Register 0 0x00
++ volatile unsigned int I2S_CH_ST_SH_1; // 0x0040 R I2S Channel Status Block Shadow Register 1 0x00
++ volatile unsigned int I2S_CH_ST_SH_2; // 0x0044 R I2S Channel Status Block Shadow Register 2 0x00
++ volatile unsigned int I2S_CH_ST_SH_3; // 0x0048 R I2S Channel Status Block Shadow Register 3 0x00
++ volatile unsigned int I2S_CH_ST_SH_4; // 0x004C R I2S Channel Status Block Shadow Register 4 0x00
++ volatile unsigned int I2S_VD_DATA; // 0x0050 R/W I2S Audio Sample Validity Register 0x00
++ volatile unsigned int I2S_MUX_CH; // 0x0054 R/W I2S Channel Enable Register 0x03
++ volatile unsigned int I2S_MUX_CUV; // 0x0058 R/W I2S CUV Enable Register 0x03
++ volatile unsigned int I2S_IRQ_MASK; // 0x005C R/W I2S Interrupt Request Mask Register 0x03
++ volatile unsigned int I2S_IRQ_STATUS; // 0x0060 R/W I2S Interrupt Request Status Register 0x00
++ volatile unsigned int I2S_CH0_L_0; // 0x0064 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH0_L_1; // 0x0068 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH0_L_2; // 0x006C R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH0_L_3; // 0x0070 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH0_R_0; // 0x0074 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH0_R_1; // 0x0078 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH0_R_2; // 0x007C R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH0_R_3; // 0x0080 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH1_L_0; // 0x0084 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH1_L_1; // 0x0088 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH1_L_2; // 0x008C R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH1_L_3; // 0x0090 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH1_R_0; // 0x0094 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH1_R_1; // 0x0098 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH1_R_2; // 0x009C R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH1_R_3; // 0x00A0 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH2_L_0; // 0x00A4 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH2_L_1; // 0x00A8 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH2_L_2; // 0x00AC R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH2_L_3; // 0x00B0 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH2_R_0; // 0x00B4 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH2_R_1; // 0x00B8 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH2_R_2; // 0x00BC R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_Ch2_R_3; // 0x00C0 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH3_L_0; // 0x00C4 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH3_L_1; // 0x00C8 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH3_L_2; // 0x00CC R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH3_R_0; // 0x00D0 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH3_R_1; // 0x00D4 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CH3_R_2; // 0x00D8 R I2S PCM Output Data Register 0x00
++ volatile unsigned int I2S_CUV_L_R; // 0x00DC R I2S CUV Output Data Register 0x00
++}HDMII2S, *PHDMII2S;
++
++ //CEC register base address
++//#define HwHDMICEC_BASE *(volatile unsigned long *)0xF0259000
++typedef struct _HDMICEC{
++ volatile unsigned int CEC_TX_STATUS_0; // 0x0000 R CEC Tx status register 0. 0x00
++ volatile unsigned int CEC_TX_STATUS_1; // 0x0004 R CEC Tx status register 1. Number of blocks transferred. 0x00
++ volatile unsigned int CEC_RX_STATUS_0; // 0x0008 R CEC Rx status register 0. 0x00
++ volatile unsigned int CEC_RX_STATUS_1; // 0x000C R CEC Rx status register 1. Number of blocks received. 0x00
++ volatile unsigned int CEC_INTR_MASK; // 0x0010 R/W CEC interrupt mask register 0x00
++ volatile unsigned int CEC_INTR_CLEAR; // 0x0014 R/W CEC interrupt clear register 0x00
++ volatile unsigned int NOTDEFINE0[2]; // 0x0018 0x001C - Reserved -
++ volatile unsigned int CEC_LOGIC_ADDR; // 0x0020 R/W HDMI Tx logical address register 0x0F
++ volatile unsigned int NOTDEFINE1[3]; // 0x0024 0x0028, 0x002C - Reserved -
++ volatile unsigned int CEC_DIVISOR_0; // 0x0030 R/W Clock divisor for 0.05ms period count ([7:0] of 32-bit) 0x00
++ volatile unsigned int CEC_DIVISOR_1; // 0x0034 R/W Clock divisor for 0.05ms period count ([15:8] of 32-bit) 0x00
++ volatile unsigned int CEC_DIVISOR_2; // 0x0038 R/W Clock divisor for 0.05ms period count ([23:16] of 32-bit) 0x00
++ volatile unsigned int CEC_DIVISOR_3; // 0x003C R/W Clock divisor for 0.05ms period count ([31:24] of 32-bit) 0x00
++//CEC Tx related Registers
++ volatile unsigned int CEC_TX_CTRL; // 0x0040 R/W CEC Tx control register 0x10
++ volatile unsigned int CEC_TX_BYTE_NUM; // 0x0044 R/W Number of blocks in a message to be transferred 0x00
++ volatile unsigned int NOTDEFINE2[6]; // 0x0048 0x004C - Reserved -
++ // 0x0050
++ volatile unsigned int CEC_TX_STATUS_2; // 0x0060 R CEC Tx status register 2 0x00
++ volatile unsigned int CEC_TX_STATUS_3; // 0x0064 R CEC Tx status register 3 0x00
++ volatile unsigned int NOTDEFINE3[6]; // 0x0068 0x006C - Reserved -
++ // 0x0070
++ volatile unsigned int NOTDEFINE4[3]; // 0x0074 0x0078, 0x007C - Reserved -
++ volatile unsigned int CEC_TX_BUFFER[16]; // 0x0080 ~ 0x00BC R/W Byte #0 ~ #15 of CEC message to be transferred. (#0 is transferred 1st ) 0x00
++//CEC Rx related Registers
++ volatile unsigned int CEC_RX_CTRL; // 0x00C0 R/W CEC Rx control register 0x00
++ volatile unsigned int NOTDEFINE5[7]; // 0x00C4 0x00C8, 0x00CC - Reserved -
++ // 0x00D0
++ volatile unsigned int CEC_RX_STATUS_2; // 0x00E0 R CEC Rx status register 2 0x00
++ volatile unsigned int CEC_RX_STATUS_3; // 0x00E4 R CEC Rx status register 3eived 1st ) 0x00
++ volatile unsigned int NOTDEFINE6[2]; // 0x00E8, 0x00EC - Reserved -
++ volatile unsigned int CEC_RX_BUFFER[16]; // 0x0100 ~ 0x013C R Byte #0 ~ #15 of CEC message received (#0 is received 1st ) 0x00
++}HDMICEC, *PHDMICEC;
++
++/***********************************************************************
++* 9-1. Camera Interface Register Define (Base Addr = 0xF0230000)
++************************************************************************/
++//#define HwCIF_BASE *(volatile unsigned long *)0xF0230000 // CIF Base Register
++typedef struct _CIF{
++ volatile unsigned int ICPCR1; // 0x00 W/R 0x00000000 Input Image Color/Pattern Configuration Register 1
++ volatile unsigned int CCIR656FCR1; // 0x04 W/R 0x06ff0000 CCIR656 Format Configuration Register 1
++ volatile unsigned int CCIR656FCR2; // 0x08 W/R 0x010b CCIR656 Format Configuration Register 2
++ volatile unsigned int IIS; // 0x0C W/R 0x00000000 Input Image Size
++ volatile unsigned int IIW1; // 0x10 W/R 0x00000000 Input Image Windowing 1
++ volatile unsigned int IIW2; // 0x14 W/R 0x00000000 Input Image Windowing 2
++ volatile unsigned int CDCR1; // 0x18 W/R 0x0003 DMA Configuration Register 1
++ volatile unsigned int CDCR2; // 0x1C W/R 0x00000000 DMA Configuration Register 2
++ volatile unsigned int CDCR3; // 0x20 W/R 0x00000000 DMA Configuration Register 3
++ volatile unsigned int CDCR4; // 0x24 W/R 0x00000000 DMA Configuration Register 4
++ volatile unsigned int CDCR5; // 0x28 W/R 0x00000000 DMA Configuration Register 5
++ volatile unsigned int CDCR6; // 0x2C W/R 0x00000000 DMA Configuration Register 6
++ volatile unsigned int CDCR7; // 0x30 W/R 0x00000000 DMA Configuration Register 7
++ volatile unsigned int CDCR8; // 0x34 W/R 0x00000000 DMA Configuration Register 7
++ volatile unsigned int FIFOSTATE; // 0x38 R 0x00000000 FIFO Status Register
++ volatile unsigned int CIRQ; // 0x3C W/R 0x00000000 Interrupt & Status register
++ volatile unsigned int OCTRL1; // 0x40 W/R 0x37000000 Overlay Control 1
++ volatile unsigned int OCTRL2; // 0x44 W/R 0x00000000 Overlay Control 2
++ volatile unsigned int OCTRL3; // 0x48 W/R 0x00000000 Overlay Control 3
++ volatile unsigned int OCTRL4; // 0x4C W/R 0x00000000 Overlay Control 4
++ volatile unsigned int OIS; // 0x50 W/R 0x00000000 Overlay Image Size
++ volatile unsigned int OIW1; // 0x54 W/R 0x00000000 Overlay Image Windowing 1
++ volatile unsigned int OIW2; // 0x58 W/R 0x00000000 Overlay Image Windowing 2
++ volatile unsigned int COBA; // 0x5C W/R 0x00000000 Overlay Base Address
++ volatile unsigned int COBO; // 0x60 W/R 0x00000000 Overlay Base Address Offset
++ volatile unsigned int CDS; // 0x64 W/R 0x00000000 Camera Down Scaler
++ volatile unsigned int CCM1; // 0x68 W/R 0x00000000 Capture Mode Configuration 1
++ volatile unsigned int CCM2; // 0x6C W/R 0x00000000 Capture Mode Configuration 2
++ volatile unsigned int CESA; // 0x70 W/R 0x00000000 Point Encoding Start Address
++ volatile unsigned int CR2Y; // 0x74 W/R 0x00000000 RGB2YUV Format converter Configuration
++ volatile unsigned int CCYA; // 0x78 R - Current Y Address
++ volatile unsigned int CCUA; // 0x7C R - Current U Address
++ volatile unsigned int CCVA; // 0x80 R - Current V Address
++ volatile unsigned int CCLC; // 0x84 R Current Line count
++}CIF, *PCIF;
++
++/***********************************************************************
++* 9-2. Effect Register Define (Base Addr = 0xF0230100)
++************************************************************************/
++//#define HwCEM_BASE *(volatile unsigned long *)0xF0230100 //W/R 0x00000000 Effect mode register
++
++typedef struct _EFFECT{
++ volatile unsigned int CEM; // 0x00 W/R 0x00000000 Effect mode register
++ volatile unsigned int CSUV; // 0x04 W/R 0x00000000 Sepia UV setting
++ volatile unsigned int CCS; // 0x08 W/R 0x00000000 Color selection register
++ volatile unsigned int CHFC; // 0x0C W/R 0x00000000 H-filter coefficent0
++ volatile unsigned int CST; // 0x10 W/R 0x00000000 Sketch threshold register
++ volatile unsigned int CCT; // 0x14 W/R 0x00000000 Clamp threshold register
++ volatile unsigned int CBR; // 0x18 W/R 0x00000000 BIAS register
++ volatile unsigned int CEIS; // 0x1C W/R 0x00000000 Image size register
++ volatile unsigned int NOTDEFINE0[8]; // 0x20, 24, 28, 2C, 30, 34, 38, 3C,
++ volatile unsigned int INPATH_CTRL; // 0x40 W/R 0x00000000 Inpath configuration
++ volatile unsigned int CISA1; // 0x44 W/R 0x00000000 Source address in Y channel
++ volatile unsigned int CISA2; // 0x48 W/R 0x00000000 Source address in U channel
++ volatile unsigned int CISA3; // 0x4C W/R 0x00000000 Source address in V channel
++ volatile unsigned int CISS; // 0x50 W/R 0x00000000 Source image size
++ volatile unsigned int CISO; // 0x54 W/R 0x00000000 Source image offset
++ volatile unsigned int CIDS; // 0x58 W/R 0x00000000 Destination image size
++ volatile unsigned int CIS; // 0x5C W/R 0x00000000 Target scale
++}EFFECT, *PEFFECT;
++
++/***********************************************************************
++* 9-3. Scaler Register Define (Base Addr = 0xF0230200)
++************************************************************************/
++//#define HwCSC_BASE *(volatile unsigned long *)0xF0230200 //W/R 0x00000000 Scaler configuration
++typedef struct _CIFSCALER{
++ volatile unsigned int CSC; // 0x00 W/R 0x00000000 Scaler configuration
++ volatile unsigned int CSSF; // 0x04 W/R 0x00000000 Scale factor
++ volatile unsigned int CSSO; // 0x08 W/R 0x00000000 Image offset
++ volatile unsigned int CSSS; // 0x0C W/R 0x00000000 Source image size
++ volatile unsigned int CSDS; // 0x10 W/R 0x00000000 Destination image size
++}CIFSCALER, *PCIFSCALER;
++
++
++
++/***********************************************************************
++* 10. Video and Image Quality Enhancer Register Define (Base Addr = 0xF0230200)
++************************************************************************/
++//#define HwVIQE_BASE *(volatile unsigned long *)0xF0252000
++typedef struct _VIQE{
++ volatile unsigned int CTRL; // 0x000 R/W 0x00000000 VIQE General Control Register
++ volatile unsigned int SIZE; // 0x004 R/W 0x00000000 VIQE SIZE Register
++ volatile unsigned int TIMEGEN; // 0x008 R/W 0x00000000 VIQE Time Generator Register
++ volatile unsigned int LUMADLY; // 0x00C R/W 0x00000000 VIQE Luma Delay Register
++ volatile unsigned int IMGCONF; // 0x010 R/W 0x00000000 VIQE Image Configuration Register
++ volatile unsigned int IMGFMT; // 0x014 R/W 0x00000000 VIQE Image Format Register
++ volatile unsigned int MISCC; // 0x018 R/W 0x00000000 VIQE Misc, Control Register
++ volatile unsigned int FRMC; // 0x01C R/W 0x00000000 VIQE Frame Control Register
++ volatile unsigned int INT; // 0x020 R/W 0x00000000 VIQE Interrupt Register
++ volatile unsigned int INTMASK; // 0x024 R/W 0x00000000 VIQE Interrupt Mask register
++ volatile unsigned int NOTDEFINE0[5];
++ volatile unsigned int VERSION; // 0x03c R 0x4d2b3401 VIQE Version register
++ volatile unsigned int NOTDEFINE1[16];
++ volatile unsigned int DI_CTRL; // 0x080 R/W 0x00000000 De-interlacer Control Register
++ volatile unsigned int DI_ENGINE0; // 0x084 R/W 0x00000000 De-interlacer Engine 0 Register
++ volatile unsigned int DI_ENGINE1; // 0x088 R/W 0x00000000 De-interlacer Engine 1 Register
++ volatile unsigned int PD_THRES0; // 0x08C R/W 0x00000000 De-interlacer Pulldown Threshold 0 Register
++ volatile unsigned int PD_THRES1; // 0x090 R/W 0x00000000 De-interlacer Pulldown Threshold 1 Register
++ volatile unsigned int PD_JUDDER; // 0x094 R/W 0x00000000 De-interlacer Pulldown Judder Register
++ volatile unsigned int DI_MISCC; // 0x098 R/W 0x00000000 De-interlacer Misc. Control register
++ volatile unsigned int NOTDEFINE2;
++ volatile unsigned int DI_STATUS; // 0x0A0 R De-interlacer Status Register
++ volatile unsigned int PD_STATUS; // 0x0A4 R De-interlacer Pulldown Status Register
++ volatile unsigned int DI_REGION0; // 0x0A8 R/W 0x00000000 De-interlacer Region 0 Register
++ volatile unsigned int DI_REGION1; // 0x0AC R/W 0x00000000 De-interlacer Region 1 register
++ volatile unsigned int NOTDEFINE3[3];
++ volatile unsigned int DI_INT; // 0x0BC R/W 0x00000000 De-interlacer Interrupt Register
++ volatile unsigned int NOTDEFINE4[16];
++
++ volatile unsigned int DN_C_H_Y0; // 0x100 R/W 0xbfffffa4 Temporal De-noiser horizontal coefficient #0 in luminance
++ volatile unsigned int DN_C_H_Y1; // 0x104 R/W 0x15556aaa Temporal De-noiser horizontal coefficient #1 in luminance
++ volatile unsigned int DN_C_V_Y0; // 0x108 R/W 0xaaaaaaa4 Temporal De-noiser vertical coefficient #0 in luminance
++ volatile unsigned int DN_C_V_Y1; // 0x10C R/W 0x15556aaa Temporal De-noiser vertical coefficient #1 in luminance
++ volatile unsigned int DN_C_T_Y0; // 0x110 R/W 0xaaaaaaa4 Temporal De-noiser temporal coefficient #0 in luminance
++ volatile unsigned int DN_C_T_Y1; // 0x114 R/W 0x15556aaa Temporal De-noiser temporal coefficient #1 in luminance
++ volatile unsigned int DN_C_H_C0; // 0x118 R/W 0xbfffffa4 Temporal De-noiser horizontal coefficient #0 in chrominance
++ volatile unsigned int DN_C_H_C1; // 0x11C R/W 0x15556aaa Temporal De-noiser horizontal coefficient #1 in chrominance
++ volatile unsigned int DN_C_V_C0; // 0x120 R/W 0xaaaaaaa4 Temporal De-noiser vertical coefficient #0 in chrominance
++ volatile unsigned int DN_C_V_C1; // 0x124 R/W 0x15556aaa Temporal De-noiser vertical coefficient #1 in chrominance
++ volatile unsigned int DN_C_T_C0; // 0x128 R/W 0xaaaaaaa4 Temporal De-noiser temporal coefficient #0 in chrominance
++ volatile unsigned int DN_C_T_C1; // 0x12C R/W 0x15556aaa Temporal De-noiser temporal coefficient #1 in chrominance
++ volatile unsigned int DN_STATE0_TEM; // 0x130 R/W 0x00000000 Temporal De-noiser count states and int. mask
++ volatile unsigned int DN_STATE1_TEM; // 0x134 R - Temporal De-noiser count states
++ volatile unsigned int DN_DIV_IMG_TEM; // 0x138 R/W 0x00000168 Temporal De-noiser image divide
++ volatile unsigned int NOTDEFINE5;
++ volatile unsigned int DN_C_SPA_Y0; // 0x140 R/W 0x12320e0a Spatial De-noiser coefficient #0 in luminance
++ volatile unsigned int DN_C_SPA_Y1; // 0x144 R/W 0x373c051d Spatial De-noiser coefficient #1 in luminance
++ volatile unsigned int DN_C_SPA_Y2; // 0x148 R/W 0x4a0640ff Spatial De-noiser coefficient #2 in luminance
++ volatile unsigned int DN_C_SPA_Y3; // 0x14C R/W 0x003100fb Spatial De-noiser coefficient #3 in luminance
++ volatile unsigned int DN_C_SPA_C0; // 0x150 R/W 0x12190805 Spatial De-noiser coefficient #0 in chrominance
++ volatile unsigned int DN_C_SPA_C1; // 0x154 R/W 0x373c0507 Spatial De-noiser coefficient #1 in chrominance
++ volatile unsigned int DN_C_SPA_C2; // 0x158 R/W 0x4a0640ff Spatial De-noiser coefficient #2 in chrominance
++ volatile unsigned int DN_C_SPA_C3; // 0x15C R/W 0x003100fb Spatial De-noiser coefficient #3 in chrominance
++ volatile unsigned int DN_FIFOSTATE; // 0x160 R/W 0x00000000 De-noiser FIFO states
++ volatile unsigned int DN_STATE0_SPA; // 0x164 R/W 0x00000000 Spatial De-noiser count states and int.mask
++ volatile unsigned int DN_STATE1_SPA; // 0x168 R - Spatial De-noiser count states
++ volatile unsigned int DN_CTRL; // 0x16C R/W 0x00000000 De-noiser FIFO and coefficient ctrl
++ volatile unsigned int DN_DIV_IMG_SPA; // 0x170 R/W 0x00000168 Spatial De-noiser image divide
++ volatile unsigned int NOTDEFINE6[3];
++
++ volatile unsigned int RD_IMG0_BASE0; // 0x180 R/W 0x00000000 RDMA image #0 base address in Y channel
++ volatile unsigned int RD_IMG0_BASE1; // 0x184 R/W 0x00000000 RDMA image #0 base address in U channel
++ volatile unsigned int RD_IMG0_BASE2; // 0x188 R/W 0x00000000 RDMA image #0 base address in V channel
++ volatile unsigned int RD_IMG0_OFS; // 0x18C R/W 0x00000000 RDMA image #0 address offset
++ volatile unsigned int RD_IMG1_BASE0; // 0x190 R/W 0x00000000 RDMA image #1 base address in Y channel
++ volatile unsigned int RD_IMG1_BASE1; // 0x194 R/W 0x00000000 RDMA image #1 base address in U channel
++ volatile unsigned int RD_IMG1_BASE2; // 0x198 R/W 0x00000000 RDMA image #1 base address in V channel
++ volatile unsigned int RD_IMG1_OFS; // 0x19C R/W 0x00000000 RDMA image #1 address offset
++ volatile unsigned int RD_IMG2_BASE0_0; // 0x1A0 R/W 0x00000000 RDMA decomp. data #0 base address in Y channel
++ volatile unsigned int RD_IMG2_BASE1_0; // 0x1A4 R/W 0x00000000 RDMA decomp. data #0 base address in U channel
++ volatile unsigned int RD_IMG2_BASE2_0; // 0x1A8 R/W 0x00000000 RDMA decomp. data #0 base address in V channel
++ volatile unsigned int RD_IMG2_BASE0_1; // 0x1AC R/W 0x00000000 RDMA decomp. data #1 base address in Y channel
++ volatile unsigned int RD_IMG2_BASE1_1; // 0x1B0 R/W 0x00000000 RDMA decomp. data #1 base address in U channel
++ volatile unsigned int RD_IMG2_BASE2_1; // 0x1B4 R/W 0x00000000 RDMA decomp. data #1 base address in V channel
++ volatile unsigned int RD_CUR_ADDR0; // 0x1B8 R - RDMA image #0 current address
++ volatile unsigned int RD_CUR_ADDR1; // 0x1BC R - RDMA image #1 current address
++ volatile unsigned int RD_CUR_ADDR2; // 0x1C0 R - RDMA decomp. data current address
++ volatile unsigned int RD_FIFOSTATE; // 0x1C4 R/W 0x00000000 RDMA FIFO States
++ volatile unsigned int RD_LINE_STATE0; // 0x1C8 R - RDMA count states #0
++ volatile unsigned int RD_LINE_STATE1; // 0x1CC R/W 0x00000000 RDMA count states #1
++ volatile unsigned int RD_CTRL; // 0x1D0 R/W 0x00000000 RDMA control register
++ volatile unsigned int RD_COMP_PL0; // 0x1D4 R/W 0x00000000 RDMA decomp. data number in Y channel
++ volatile unsigned int RD_COMP_PL1; // 0x1D8 R/W 0x00000000 RDMA decomp. data number in C channel
++ volatile unsigned int NOTDEFINE7[9];
++
++ volatile unsigned int CD_BASE0_0; // 0x200 R/W 0x00000000 Comp. DMA #0 base address in Y channel
++ volatile unsigned int CD_BASE1_0; // 0x204 R/W 0x00000000 Comp. DMA #0 base address in U channel
++ volatile unsigned int CD_BASE2_0; // 0x208 R/W 0x00000000 Comp. DMA #0 base address in V channel
++ volatile unsigned int CD_BASE0_1; // 0x20C R/W 0x00000000 Comp. DMA #1 base address in Y channel
++ volatile unsigned int CD_BASE1_1; // 0x210 R/W 0x00000000 Comp. DMA #1 base address in U channel
++ volatile unsigned int CD_BASE2_1; // 0x214 R/W 0x00000000 Comp. DMA #1 base address in V channel
++ volatile unsigned int CD_CUR_ADDR; // 0x218 R - Comp. DMA current address
++ volatile unsigned int CD_STATE; // 0x21C R/W 0x00000000 Comp. DMA states
++ volatile unsigned int CD_CTRL; // 0x220 R/W 0x00000000 Comp. DMA control register
++ volatile unsigned int NOTDEFINE8[3];
++ volatile unsigned int CD_HUFF_CNT0; // 0x230 R - Comp. DMA compressed data count in Y channel
++ volatile unsigned int CD_HUFF_CNT1; // 0x234 R - Comp. DMA compressed data count in U channel
++ volatile unsigned int CD_HUFF_CNT2; // 0x238 R Comp. DMA compressed data count in V channel
++ volatile unsigned int NOTDEFINE9[17];
++
++ volatile unsigned int OD_BASE0; // 0x280 R/W 0x00000000 ODMA base address in Y channel
++ volatile unsigned int OD_BASE1; // 0x284 R/W 0x00000000 ODMA base address in U channel
++ volatile unsigned int OD_BASE2; // 0x288 R/W 0x00000000 ODMA base address in V channel
++ volatile unsigned int OD_SIZE; // 0x28C R/W 0x00000000 ODMA image size
++ volatile unsigned int OD_OFS; // 0x290 R/W 0x00000000 ODMA address offset
++ volatile unsigned int OD_CFG; // 0x294 R/W 0x00000000 ODMA image type
++ volatile unsigned int NOTDEFINE10[3];
++ volatile unsigned int OD_CTRL; // 0x2A4 R/W 0x00000000 ODMA control register
++ volatile unsigned int OD_STATE; // 0x2A8 R/W 0x00000000 ODMA States
++ volatile unsigned int NOTDEFINE11[85];
++
++ volatile unsigned int GM_CTRL; // 0x400 R/W 0x00000000 Gamut-mapper Control Register
++ volatile unsigned int GM_STATUS; // 0x404 R/W 0x00000000 Gamut-mapper Status Register
++ volatile unsigned int GM_REGION0; // 0x408 R/W 0x00000000 Gamut-mapper Region 0 Register
++ volatile unsigned int GM_REGION1; // 0x40C R/W 0x00000000 Gamut-mapper Region 1 register
++ volatile unsigned int NOTDEFINE12[3];
++ volatile unsigned int GM_INT; // 0x41C R/W 0x00000000 Gamut-mapper Interrupt Register
++ volatile unsigned int NOTDEFINE13[120];
++
++ volatile unsigned int HI_CTRL; // 0x600 R/W 0x00000000 Histogram Control Register
++ volatile unsigned int HI_STATUS; // 0x604 R/W 0x00000000 Histogram Status Register
++ volatile unsigned int HI_CONFIG; // 0x608 R/W 0x00000000 Histogram Configuration Register
++ volatile unsigned int HI_REGION0; // 0x60C R/W 0x00000000 Histogram Region 0 Register
++ volatile unsigned int HI_REGION1; // 0x610 R/W 0x00000000 Histogram Region 1 register
++ volatile unsigned int NOTDEFINE14[2];
++ volatile unsigned int HI_INT; // 0x61C R/W 0x00000000 Histogram Interrupt Register
++ volatile unsigned int HI_SEGS[4]; // 0x620 ~ 0x62C R/W 0x00000000 Histogram Segments Register
++ volatile unsigned int HI_CDFS[4]; // 0x630 ~ 0x63C R 0x00000000 Histogram CDF Register
++ volatile unsigned int HI_CNTS[8]; // 0x640 ~ 0x65C R 0x00000000 Histogram CNT Register
++ volatile unsigned int HI_SCALE[4]; // 0x660 ~ 0x66C R/W 0x00000000 Histogram Scale Register
++ volatile unsigned int HI_LUTS[64]; // 0x700 ~ 0x7FC R/W 0x00000000 Histogram LUT Table register
++}VIQE, *PVIQE;
++
++
++
++/***********************************************************************
++* 11. DDI_CONFIG/DDI_CACHE Register Define (Base Addr = 0xF0251000)
++************************************************************************/
++//#define HwDDI_CONFIG_BASE *(volatile unsigned long *)0xF0251000
++//#define HwDDI_CACHE_BASE *(volatile unsigned long *)0xF0250000
++
++typedef struct _DDICONFIG{
++ volatile unsigned int NTSCPAL_SEL; // 0x000 R/W 0x00000001 NTSCPAL_Encoder select
++ volatile unsigned int LVDS_CTRL; // 0x004 R/W 0x04444443 LVDS Control register
++ volatile unsigned int LVDS_TXO_SEL0; // 0x008 R/W 0x03020100 LVDS TXOUT select #0
++ volatile unsigned int LVDS_TXO_SEL1; // 0x00C R/W 0x09080504 LVDS TXOUT select #1
++ volatile unsigned int LVDS_TXO_SEL2; // 0x010 R/W 0x0D0C0B0A LVDS TXOUT select #2
++ volatile unsigned int LVDS_TXO_SEL3; // 0x014 R/W 0x13121110 LVDS TXOUT select #3
++ volatile unsigned int LVDS_TXO_SEL4; // 0x018 R/W 0x1A191514 LVDS TXOUT select #4
++ volatile unsigned int LVDS_TXO_SEL5; // 0x01C R/W 0x0E070618 LVDS TXOUT select #5
++ volatile unsigned int LVDS_TXO_SEL6; // 0x020 R/W 0x1B17160F LVDS TXOUT select #6
++ volatile unsigned int LVDS_TXO_SEL7; // 0x024 R/W 0x1F1E1F1E LVDS TXOUT select #7
++ volatile unsigned int LVDS_TXO_SEL8; // 0x028 R/W 0x001E1F1E LVDS TXOUT select #8
++ volatile unsigned int HDMI_CTRL; // 0x02C R/W 0x00000002 HDMI Control register
++ volatile unsigned int PWDN; // 0x030 R/W 0x00000000 Power Down
++ volatile unsigned int SWRESET; // 0x034 R/W 0x00000000 Soft Reset
++ volatile unsigned int ON_THE_FLY; // 0x038 R/W 0x00000000 On-The-Fly mode
++ volatile unsigned int NOTDEFINE0;
++ volatile unsigned int HDMI_AES; // 0x040 R/W 0x00000000 HDMI AES
++ volatile unsigned int HDMI_AES_DATA0; // 0x044 RW 0x00000000 HDMI AES DATA #0
++ volatile unsigned int HDMI_AES_DATA1; // 0x048 R/W 0x00000000 HDMI AES DATA #1
++ volatile unsigned int HDMI_AES_HW0; // 0x050 R/W 0x00000000 HDMI AES HW #0
++ volatile unsigned int HDMI_AES_HW1; // 0x054 R/W 0x00000000 HDMI AES HW #1
++ volatile unsigned int HDMI_AES_HW2; // 0x058 R/W 0x00000000 HDMI AES HW #2
++}DDICONFIG, *PDDICONFIG;
++
++
++// Where is DDI_CONGIF in DataSheet ??
++
++typedef struct _DDICACHE{
++ volatile unsigned int DDIC_CTRL; // 0x000 R/W 0x00000000 DDI_CACHE Control
++ volatile unsigned int DDIC_CFG0; // 0x004 R/W 0x00000000 DDI_CACHE Configuration #0
++ volatile unsigned int DDIC_CFG1; // 0x008 R/W 0x00000000 DDI_CACHE Configuration #1
++}DDICACHE, *PDDICACHE;
++
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 7 VIDEO BUS_V0.00 Dec.11 2008
++********************************************************************************/
++/***********************************************************************
++* 4. VIDEO CODEC Register Define (Base Addr = 0x0xF0700000)
++************************************************************************/
++//#define HwVIDEOCODEC_BASE *(volatile unsigned long*)0xF0700000
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 7 VIDEO BUS_V0.00 Dec.11 2008
++********************************************************************************/
++/*******************************************************************************
++* 5-1. JPEG Encoder Register Define (Base Addr = 0xF0720000)
++********************************************************************************/
++//#define HwJPEGDECODER_BASE *(volatile unsigned long*)0xF0710000
++//#define HwJPEGENCODER_BASE *(volatile unsigned long*)0xF0720000
++//#define HwVIDEOCACHE_BASE *(volatile unsigned long*)0xF0701000
++typedef struct _JPEGENCODER{
++ volatile unsigned int NOTDEFINE0; // 0x000
++ volatile unsigned int JP_MOD; // 0x004 R/W ALL 0x00000000 JPEG codec mode register
++ volatile unsigned int JP_INT_MASK; // 0x008 R/W ALL 0x0000001f Interrupt mask register
++ volatile unsigned int JP_INT_LEVEL; // 0x00c R/W SLV 0x000000ff FIFO interrupt level register
++ volatile unsigned int JP_TRG_MOD; // 0x010 R/W ALL 0x00000000 Polling or Interrupt mode selection register
++ volatile unsigned int NOTDEFINE1[3];
++ volatile unsigned int R_YBUF_ADDR; // 0x020 R/W JP 0x00000000 Raw data buffer Y address register
++ volatile unsigned int R_UBUF_ADDR; // 0x024 R/W JP 0x00000000 Raw data buffer U address register
++ volatile unsigned int R_VBUF_ADDR; // 0x028 R/W JP 0x00000000 Raw data V address register
++ volatile unsigned int R_BUF_INFO; // 0x02c R/W JP 0x00000000 Raw data buffer information register
++ volatile unsigned int JP_SIZE; // 0x030 R/W JP 0x00000000 Image size information register
++ volatile unsigned int JP_CHROMA; // 0x034 R/W JP 0x00000000 Image format information register
++ volatile unsigned int JP_CBUF_ADDR; // 0x38 R/W JP 0x00000000 Coded data buffer address register
++ volatile unsigned int JP_CBUF_SIZE; // 0x03c R/W JP 0x00000fff Coded data buffer size register
++ volatile unsigned int NOTDEFINE2[12];
++ volatile unsigned int JP_START; // 0x070 W ALL 0x00000000 Codec start command register
++ volatile unsigned int NOTDEFINE3[3];
++ volatile unsigned int JP_SBUF_WCNT; // 0x080 R/W MST 0x00000000 Source buffer write count register
++ volatile unsigned int JP_SBUF_RCNT; // 0x084 R MST 0x00000000 Source buffer read count register
++ volatile unsigned int JP_DBUF_WCNT; // 0x088 R MST 0x00000000 Destination buffer write count register
++ volatile unsigned int JP_DBUF_RCNT; // 0x08c R/W MST 0x00000000 Destination buffer read count register
++ volatile unsigned int JP_IFIFO_ST; // 0x090 R SLV 0x00000000 Input FIFO status register
++ volatile unsigned int JP_OFIFO_ST; // 0x094 R SLV 0x00000000 Output FIFO status register
++ volatile unsigned int NOTDEFINE4[2];
++ volatile unsigned int JP_INT_FLAG; // 0x0a0 R ALL 0x00000000 Interrupt flag register
++ volatile unsigned int JP_INT_ACK; // 0x0a4 R ALL 0x00000000 Interrupt ack register
++ volatile unsigned int NOTDEFINE5[10];
++ volatile unsigned int JP_IFIFO_WD; // 0x0c0 W SLV 0x00000000 Input FIFO write data register
++ volatile unsigned int NOTDEFINE6[7];
++ volatile unsigned int JP_OFIFO_RD; // 0x0e0 R SLV 0x00000000 Output FIFO read data register
++ volatile unsigned int NOTDEFINE7[7];
++ volatile unsigned int JPC_QTAB0[64]; // 0x100 - W JPC 0x00000000 Encoder Q table 0 (64 entries)
++ volatile unsigned int JPC_QTAB1[64]; // 0x200 - W JPC 0x00000000 Encoder Q table 1 (64 entries)
++}JPEGENCODER, *PJPEGENCODER;
++
++/*******************************************************************************
++* 5-2. JPEG Decoder Register Define (Base Addr = 0xF0710000)
++********************************************************************************/
++typedef struct _JPEGDECODER{
++ volatile unsigned int NOTDEFINE0; // 0x000
++ volatile unsigned int JP_MOD; // 0x004 R/W ALL 0x00000000 JPEG codec mode register
++ volatile unsigned int JP_INT_MASK; // 0x008 R/W ALL 0x0000001f Interrupt mask register
++ volatile unsigned int JP_INT_LEVEL; // 0x00c R/W SLV 0x000000ff FIFO interrupt level register
++ volatile unsigned int JP_TRG_MOD; // 0x010 R/W ALL 0x00000000 Polling or Interrupt mode selection register
++ volatile unsigned int R_YBUF_ADDR; // 0x020 R/W JP 0x00000000 Raw data buffer Y address register
++ volatile unsigned int R_UBUF_ADDR; // 0x024 R/W JP 0x00000000 Raw data buffer U address register
++ volatile unsigned int R_VBUF_ADDR; // 0x028 R/W JP 0x00000000 Raw data V address register
++ volatile unsigned int R_BUF_INFO; // 0x02c R/W JP 0x00000000 Raw data buffer information register
++ volatile unsigned int JP_SIZE; // 0x030 R/W JP 0x00000000 Image size information register
++ volatile unsigned int JP_CHROMA; // 0x034 R/W JP 0x00000000 Image format information register
++ volatile unsigned int JP_CBUF_ADDR; // 0x38 R/W JP 0x00000000 Coded data buffer address register
++ volatile unsigned int JP_CBUF_SIZE; // 0x03c R/W JP 0x00000fff Coded data buffer size register
++ volatile unsigned int NOTDEFINE1[4];
++ volatile unsigned int JPD_TBL_ID; // 0x050 R/W JPD 0x00000000 Decoder table index register
++ volatile unsigned int JPD_RST_INTV; // 0x054 R/W JPD 0x00000000 Decoder reset interval register
++ volatile unsigned int JPD_OUT_SCL; // 0x058 R/W JPD 0x00000000 Decoder output scaling register
++ volatile unsigned int NOTDEFINE2[5];
++ volatile unsigned int JP_START; // 0x070 W ALL 0x00000000 Codec start command register
++ volatile unsigned int NOTDEFINE3[3];
++ volatile unsigned int JP_SBUF_WCNT; // 0x080 R/W MST 0x00000000 Source buffer write count register
++ volatile unsigned int JP_SBUF_RCNT; // 0x084 R MST 0x00000000 Source buffer read count register
++ volatile unsigned int JP_DBUF_WCNT; // 0x088 R MST 0x00000000 Destination buffer write count register
++ volatile unsigned int JP_DBUF_RCNT; // 0x08c R/W MST 0x00000000 Destination buffer read count register
++ volatile unsigned int JP_IFIFO_ST; // 0x090 R SLV 0x00000000 Input FIFO status register
++ volatile unsigned int JP_OFIFO_ST; // 0x094 R SLV 0x00000000 Output FIFO status register
++ volatile unsigned int NOTDEFINE4[2];
++ volatile unsigned int JP_INT_FLAG; // 0x0a0 R ALL 0x00000000 Interrupt flag register
++ volatile unsigned int JP_INT_ACK; // 0x0a4 R ALL 0x00000000 Interrupt ack register
++ volatile unsigned int NOTDEFINE5[6];
++ volatile unsigned int JP_IFIFO_WD; // 0x0c0 W SLV 0x00000000 Input FIFO write data register
++ volatile unsigned int NOTDEFINE6[7];
++ volatile unsigned int JP_OFIFO_RD; // 0x0e0 R SLV 0x00000000 Output FIFO read data register
++ volatile unsigned int NOTDEFINE7[135];
++ volatile unsigned int JPD_IQTAB0[64]; // 0x300 - W JPD 0x00000000 Decoder IQ table 0 (64 entries)
++ volatile unsigned int JPD_IQTAB1[64]; // 0x400 - W JPD 0x00000000 Decoder IQ table 1 (64 entires)
++ volatile unsigned int JPD_IQTAB2[64]; // 0x500 - W JPD 0x00000000 Decoder IQ table 2 (64 entires)
++ volatile unsigned int JPD_HT_DC0_C[16]; // 0x600 - W JPD 0x00000000 Decoder huffman table (dc0 code, 16 entreis)
++ volatile unsigned int JPD_HT_AC0_C[16]; // 0x640 - W JPD 0x00000000 Decoder huffman table (ac0 code, 16 entreis)
++ volatile unsigned int JPD_HT_DC1_C[16]; // 0x680 - W JPD 0x00000000 Decoder huffman table (dc1 code, 16 entreis)
++ volatile unsigned int JPD_HT_AC1_C[16]; // 0x6c0 - W JPD 0x00000000 Decoder huffman table (ac1 code, 16 entreis)
++ volatile unsigned int JPD_HT_DC0_A[16]; // 0x700 - W JPD 0x00000000 Decoder huffman table (dc0 addr, 16 entreis)
++ volatile unsigned int JPD_HT_AC0_A[16]; // 0x740 - W JPD 0x00000000 Decoder huffman table (ac0 addr, 16 entreis)
++ volatile unsigned int JPD_HT_DC1_A[16]; // 0x780 - W JPD 0x00000000 Decoder huffman table (dc1 addr, 16 entreis)
++ volatile unsigned int JPD_HT_AC1_A[16]; // 0x7c0 - W JPD 0x00000000 Decoder huffman table (ac1 addr, 16 entreis)
++ volatile unsigned int JPD_HT_DC0_V[12]; // 0x800 - W JPD 0x00000000 Decoder huffman table (dc0 var, 12 entreis)
++ volatile unsigned int JPD_HT_AC0_V[162]; // 0x840 - W JPD 0x00000000 Decoder huffman table (ac0 var, 162 entreis)
++ volatile unsigned int NOTDEFINE8[78];
++ volatile unsigned int JPD_HT_DC1_V[12]; // 0xc00 - W JPD 0x00000000 Decoder huffman table (dc1 var, 12 entreis)
++ volatile unsigned int NOTDEFINE9[4];
++ volatile unsigned int JPD_HT_AC1_V[162]; // 0xc40 - W JPD 0x00000000 Decoder huffman table (ac1 var, 162 entreis)
++}JPEGDECODER, *PJPEGDECODER;
++
++
++/*******************************************************************************
++* TCC8900_DataSheet_PART 8 GRAPHIC BUS_V0.00 Dec.11 2008
++********************************************************************************/
++/***********************************************************************
++* 4. Overlay Mixer Register Define (Base Addr = 0xF6000000)
++************************************************************************/
++//#define HwOVERLAYMIXER_BASE *(volatile unsigned long *)0xF6000000
++typedef struct _OVERLAYMIXER{
++ volatile unsigned int FCH0_SADDR0; // 0x00 R/W 0x00000000 Front-End Channel 0 Source Address 0
++ volatile unsigned int FCH0_SADDR1; // 0x04 R/W 0x00000000 Front-End Channel 0 Source Address 1
++ volatile unsigned int FCH0_SADDR2; // 0x08 R/W 0x00000000 Front-End Channel 0 Source Address 2
++ volatile unsigned int FCH0_SFSIZE; // 0x0C R/W 0x00000000 Front-End Channel 0 Source Frame Pixel Size
++ volatile unsigned int FCH0_SOFF; // 0x10 R/W 0x00000000 Front-End Channel 0 Source Pixel Offset
++ volatile unsigned int FCH0_SISIZE; // 0x14 R/W 0x00000000 Front-End Channel 0 Source Image Pixel Size
++ volatile unsigned int FCH0_WOFF; // 0x18 R/W 0x00000000 Front-End Channel 0 Window Pixel Offset
++ volatile unsigned int FCH0_SCTRL; // 0x1C R/W 0x00000000 Front-End Channel 0 Control
++ volatile unsigned int FCH1_SADDR0; // 0x20 R/W 0x00000000 Front-End Channel 1 Source Address 0
++ volatile unsigned int FCH1_SADDR1; // 0x24 R/W 0x00000000 Front-End Channel 1 Source Address 1
++ volatile unsigned int FCH1_SADDR2; // 0x28 R/W 0x00000000 Front-End Channel 1 Source Address 2
++ volatile unsigned int FCH1_SFSIZE; // 0x2C R/W 0x00000000 Front-End Channel 1 Source Frame Pixel Size
++ volatile unsigned int FCH1_SOFF; // 0x30 R/W 0x00000000 Front-End Channel 1 Source Pixel Offset
++ volatile unsigned int FCH1_SISIZE; // 0x34 R/W 0x00000000 Front-End Channel 1 Source Image Pixel Size
++ volatile unsigned int FCH1_WOFF; // 0x38 R/W 0x00000000 Front-End Channel 1 Window Pixel Offset
++ volatile unsigned int FCH1_SCTRL; // 0x3C R/W 0x00000000 Front-End Channel 1 Control
++ volatile unsigned int FCH2_SADDR0; // 0x40 R/W 0x00000000 Front-End Channel 1 Source Address 0
++ volatile unsigned int FCH2_SADDR1; // 0x44 R/W 0x00000000 Front-End Channel 1 Source Address 1
++ volatile unsigned int FCH2_SADDR2; // 0x48 R/W 0x00000000 Front-End Channel 1 Source Address 2
++ volatile unsigned int FCH2_SFSIZE; // 0x4C R/W 0x00000000 Front-End Channel 1 Source Frame Pixel Size
++ volatile unsigned int FCH2_SOFF; // 0x50 R/W 0x00000000 Front-End Channel 1 Source Pixel Offset
++ volatile unsigned int FCH2_SISIZE; // 0x54 R/W 0x00000000 Front-End Channel 1 Source Image Pixel Size
++ volatile unsigned int FCH2_WOFF; // 0x58 R/W 0x00000000 Front-End Channel 1 Window Pixel Offset
++ volatile unsigned int FCH2_SCTRL; // 0x5C R/W 0x00000000 Front-End Channel 1 Control
++ volatile unsigned int S0_CHROMA; // 0x60 R/W 0x00000000 Source 0 Chroma-Key Parameter
++ volatile unsigned int S0_PAR; // 0x64 R/W 0x00000000 Source 0 Arithmetic Parameter
++ volatile unsigned int S1_CHROMA; // 0x68 R/W 0x00000000 Source 1 Chroma-Key Parameter
++ volatile unsigned int S1_PAR; // 0x6C R/W 0x00000000 Source 1 Arithmetic Parameter
++ volatile unsigned int S2_CHROMA; // 0x70 R/W 0x00000000 Source 2 Chroma-Key Parameter
++ volatile unsigned int S2_PAR; // 0x74 R/W 0x00000000 Source 2 Arithmetic Parameter
++ volatile unsigned int S_CTRL; // 0x78 R/W 0x00000000 Source Control Register
++ volatile unsigned int NOTDEFINE0; // 0x7C - - Reserved
++ volatile unsigned int OP0_PAT; // 0x80 R/W 0x00000000 Source Operator 0 Pattern
++ volatile unsigned int OP1_PAT; // 0x84 R/W 0x00000000 Source Operator 1 Pattern
++ volatile unsigned int OP_CTRL; // 0x88 R/W 0x00000000 Source Operation Control Register
++ volatile unsigned int NOTDEFINE1; // 0x8C - - Reserved
++ volatile unsigned int BCH_DADDR0; // 0x90 R/W 0x00000000 Back-End Channel Destination Address 0
++ volatile unsigned int BCH_DADDR1; // 0x94 R/W 0x00000000 Back -End Channel Destination Address 1
++ volatile unsigned int BCH_DADDR2; // 0x98 R/W 0x00000000 Back -End Channel Destination Address 2
++ volatile unsigned int BCH_DFSIZE; // 0x9C R/W 0x00000000 Back -End Channel Destination Frame Pixel Size
++ volatile unsigned int BCH_DOFF; // 0xA0 R/W 0x00000000 Back -End Channel Destination Pixel Offset
++ volatile unsigned int BCH_DCTRL; // 0xA4 R/W 0x00000000 Back -End Channel Control
++
++ volatile unsigned int NOTDEFINE2[2]; // 0xA8 - 0xAF - - Reserved
++ volatile unsigned int BCH_DDMAT0; // 0xB0 R/W 0x00000000 Back-End Channel Destination Dither Matrix 0
++ volatile unsigned int BCH_DDMAT1; // 0xB4 R/W 0x00000000 Back-End Channel Destination Dither Matrix 1
++ volatile unsigned int BCH_DDMAT2; // 0xB8 R/W 0x00000000 Back-End Channel Destination Dither Matrix 2
++ volatile unsigned int BCH_DDMAT3; // 0xBC R/W 0x00000000 Back-End Channel Destination Dither Matrix 3
++ volatile unsigned int OM_CTRL; // 0xC0 R/W 0x00000000 Overlay Mixer Control
++ volatile unsigned int OM_IREQ; // 0xC4 R/W 0x00000000 Overlay Mixer Interrupt Request
++ volatile unsigned int NOTDEFINE3[206]; // 0xC8 - 0x3FF - - Reserved
++
++ volatile unsigned int FCH0_LUT[256]; // 0x400 ? 0x7FF R/W - Front-End Channel 0 Lookup Table
++ volatile unsigned int FCH1_LUT[256]; // 0x800 ? 0xBFF R/W - Front-End Channel 1 Lookup Table
++ volatile unsigned int FCH2_LUT[256]; // 0xC00 ? 0xFFF R/W - Front-End Channel 2 Lookup Table
++}OVERLAYMIXER, *POVERLAYMIXER;
++
++
++/*******************************************************************************
++* 5-1. 2D/3D GPU
++*
++* Pixel Processor Register Map Register Define (Base Addr = 0xF0000000)
++********************************************************************************/
++// #define HwPIXELPROCESSOR_BASE *(volatile unsigned long *)0xF0000000
++typedef struct _GPUPIXELPROCESSOR{
++ volatile unsigned int REND_LIST_ADDR; // 0x0000 R/W 0x00000000 Renderer List Address
++ volatile unsigned int REND_RSW_BASE; // 0x0004 R/W 0x00000000 Renderer State Word Base Address
++ volatile unsigned int REND_VERTEX_BASE; // 0x0008 R/W 0x00000000 Renderer Vertex Base Address
++ volatile unsigned int FEATURE_ENABLE; // 0x000C R/W 0x00000002 Feature Enable
++ volatile unsigned int Z_CLEAR_VALUE; // 0x0010 R/W 0x00000009 Z Clear Value
++ volatile unsigned int STENCIL_CLEAR_VALUE; // 0x0014 R/W 0x00000000 Stencil Clear value
++ volatile unsigned int ABGR_CLEAR_VALUE_0; // 0x0018 R/W 0x00000000 ABGR Clear Value 0
++ volatile unsigned int ABGR_CLEAR_VALUE_1; // 0x001C R/W 0x00000000 ABGR Clear Value 1
++ volatile unsigned int ABGR_CLEAR_VALUE_2; // 0x0020 R/W 0x00000000 ABGR Clear Value 2
++ volatile unsigned int ABGR_CLEAR_VALUE_3; // 0x0024 R/W 0x00000000 ABGR Clear Value 3
++ volatile unsigned int BOUNDING_BOX_LEFT_RIGHT; // 0x0028 R/W 0x00000000 Bounding Box left Right
++ volatile unsigned int BOUNDING_BOX_BOTTOM; // 0x002C R/W 0x00000000 Bounding Box Bottom
++ volatile unsigned int FS_STACK_ADDR; // 0x0030 R/W 0x00000000 FS Stack Address
++ volatile unsigned int FS_STACK_SIZE_AND_INIT_VAL; // 0x0034 R/W 0x00000000 FS Stack Size and Initial Value
++ volatile unsigned int ORIGIN_OFFSET_X; // 0x0040 R/W 0x00000000 Origin Offset X
++ volatile unsigned int ORIGIN_OFFSET_Y; // 0x0044 R/W 0x00000000 Origin Offset Y
++ volatile unsigned int SUBPIXEL_SPECIFIER; // 0x0048 R/W 0x00000075 Subpixel Specifier
++ volatile unsigned int TIEBREAK_MODE; // 0x004C R/W 0x00000000 Tiebreak mode Register
++ volatile unsigned int NOTDEFINE0[44];
++ volatile unsigned int WB0_SOURCE_SELECT; // 0x0100 R/W 0x00000000 WB0 Source Select
++ volatile unsigned int WB0_TARGET_ADDR; // 0x0104 R/W 0x00000000 WB0 Target Addres
++ volatile unsigned int WB0_TARGET_PIXEL_FORMAT; // 0x0108 R/W 0x00000000 WB0 Target Pixel Format
++ volatile unsigned int WB0_TARGET_AA_FORMAT; // 0x010C R/W 0x00000000 WB0 Target AA Format
++ volatile unsigned int WB0_TARGET_LAYOUT; // 0x0110 R/W 0x00000000 WB0 Target Layout
++ volatile unsigned int WB0_TARGET_SCANLINE_LENGTH; // 0x0114 R/W 0x00000000 WB0 Target Scanline length
++ volatile unsigned int WB0_TARGET_FLAGS; // 0x0118 R/W 0x00000000 WB0 Target Flags
++ volatile unsigned int WB0_MRT_ENABLE; // 0x011C R/W 0x00000000 WB0 MRT Enagle
++ volatile unsigned int WB0_MRT_OFFSET; // 0x0120 R/W 0x00000000 WB0 MRT Offset
++ volatile unsigned int WB0_GLOBAL_TEST_ENABLE; // 0x0124 R/W 0x00000000 WB0 Global Test Enable
++ volatile unsigned int WB0_GLOBAL_TEST_REF_VALUE; // 0x0128 R/W 0x00000000 WB0 Global Test Reference
++ volatile unsigned int WB0_GLOBAL_TEST_CMP_FUNC; // 0x012C R/W 0x00000000 WB0 Global Test Compare Function
++ volatile unsigned int NOTDEFINE1[52];
++ volatile unsigned int WB1_SOURCE_SELECT; // 0x0200 R/W 0x00000000 WB1 Source Select
++ volatile unsigned int WB1_TARGET_ADDR; // 0x0204 R/W 0x00000000 WB1 Target Addres
++ volatile unsigned int WB1_TARGET_PIXEL_FORMAT; // 0x0208 R/W 0x00000000 WB1 Target Pixel Format
++ volatile unsigned int WB1_TARGET_AA_FORMAT; // 0x020C R/W 0x00000000 WB1 Target AA Format
++ volatile unsigned int WB1_TARGET_LAYOUT; // 0x0210 R/W 0x00000000 WB1 Target Layout
++ volatile unsigned int WB1_TARGET_SCANLINE_LENGTH; // 0x0214 R/W 0x00000000 WB1 Target Scanline length
++ volatile unsigned int WB1_TARGET_FLAGS; // 0x0218 R/W 0x00000000 WB1 Target Flags
++ volatile unsigned int WB1_MRT_ENABLE; // 0x021C R/W 0x00000000 WB1 MRT Enagle
++ volatile unsigned int WB1_MRT_OFFSET; // 0x0220 R/W 0x00000000 WB1 MRT Offset
++ volatile unsigned int WB1_GLOBAL_TEST_ENABLE; // 0x0224 R/W 0x00000000 WB1 Global Test Enable
++ volatile unsigned int WB1_GLOBAL_TEST_REF_VALUE; // 0x0228 R/W 0x00000000 WB1 Global Test Reference
++ volatile unsigned int WB1_GLOBAL_TEST_CMP_FUNC; // 0x022C R/W 0x00000000 WB1 Global Test Compare Function
++ volatile unsigned int NOTDEFINE2[52];
++ volatile unsigned int WB2_SOURCE_SELECT; // 0x0300 R/W 0x00000000 WB2 Source Select
++ volatile unsigned int WB2_TARGET_ADDR; // 0x0304 R/W 0x00000000 WB2 Target Addres
++ volatile unsigned int WB2_TARGET_PIXEL_FORMAT; // 0x0308 R/W 0x00000000 WB2 Target Pixel Format
++ volatile unsigned int WB2_TARGET_AA_FORMAT; // 0x030C R/W 0x00000000 WB2 Target AA Format
++ volatile unsigned int WB2_TARGET_LAYOUT; // 0x0310 R/W 0x00000000 WB2 Target Layout
++ volatile unsigned int WB2_TARGET_SCANLINE_LENGTH; // 0x0314 R/W 0x00000000 WB2 Target Scanline length
++ volatile unsigned int WB2_TARGET_FLAGS; // 0x0318 R/W 0x00000000 WB2 Target Flags
++ volatile unsigned int WB2_MRT_ENABLE; // 0x031C R/W 0x00000000 WB2 MRT Enagle
++ volatile unsigned int WB2_MRT_OFFSET; // 0x0320 R/W 0x00000000 WB2 MRT Offset
++ volatile unsigned int WB2_GLOBAL_TEST_ENABLE; // 0x0324 R/W 0x00000000 WB2 Global Test Enable
++ volatile unsigned int WB2_GLOBAL_TEST_REF_VALUE; // 0x0328 R/W 0x00000000 WB2 Global Test Reference
++ volatile unsigned int WB2_GLOBAL_TEST_CMP_FUNC; // 0x032C R/W 0x00000000 WB2 Global Test Compare Function
++ volatile unsigned int NOTDEFINE3[820];
++ volatile unsigned int VERSION; // 0x1000 R 0xC8070005 Version
++ volatile unsigned int CURRENT_REND_LIST_ADDR; // 0x1004 R/W 0x00000000 Current Renderer List Address
++ volatile unsigned int STATUS; // 0x1008 R/W 0x00000000 Status
++ volatile unsigned int CTRL_MGMT; // 0x100C W N/A Control Management
++ volatile unsigned int INT_RAWSTAT; // 0x1020 R/W 0x00000000 Interrupt Rawstat
++ volatile unsigned int INT_CLEAR; // 0x1024 W N/A Interrupt Clear
++ volatile unsigned int INT_MASK; // 0x1028 RW 0x00001FF Interrupt Mask
++ volatile unsigned int INT_STATUS; // 0x102c R 0x00000000 Interrupt Status
++ volatile unsigned int WRITE_BOUNDARY_ENABLE; // 0x1040 R/W 0x00000000 Write Boundary Enable
++ volatile unsigned int WRITE_BOUNDARY_LOW; // 0x1044 R/W 0x00000000 Write Boundary Low
++ volatile unsigned int WRITE_BOUNDARY_HIGH; // 0x1048 R/W 0x00000000 Write Boundary High
++ volatile unsigned int WRITE_BOUNDARY_ADDRESS; // 0x104C R 0x00000000 Write Boundary Address
++ volatile unsigned int BUS_ERROR_STATUS; // 0x1050 R 0x00000000 Bus Error Status
++ volatile unsigned int WATCHDOG_DISABLE; // 0x1060 R/W 0x00000000 Watchdog Disable
++ volatile unsigned int WATCHDOG_TIMEOUT; // 0x1064 R/W 0x000F4240 Watchdog Timeout
++ volatile unsigned int PERF_CNT_0_ENABLE; // 0x1080 R/W 0x00000000 Performance Counter 0 Enable
++ volatile unsigned int PERF_CNT_0_SRC; // 0x1084 R/W 0x00000000 Performance Counter 0 SRC
++ volatile unsigned int PERF_CNT_0_LIMIT; // 0x1088 R/W 0x00000000 Performance Counter 0 Limit
++ volatile unsigned int PERF_CNT_0_VALUE; // 0x108C R/W 0x00000000 Performance Counter 0 Value
++ volatile unsigned int PERF_CNT_1_ENABLE; // 0x10A0 R/W 0x00000000 Performance Counter 1 Enable
++ volatile unsigned int PERF_CNT_1_SRC; // 0x10A4 R/W 0x00000000 Performance Counter 1 SRC
++ volatile unsigned int PERF_CNT_1_LIMIT; // 0x10A8 R/W 0x00000000 Performance Counter 1 Limit
++ volatile unsigned int PERF_CNT_1_VALUE; // 0x10AC R/W 0x00000000 Performance Counter 1 Value
++}GPUPIXELPROCESSOR,*PGPUPIXELPROCESSOR;
++
++/*******************************************************************************
++* 5-2. Geometry Processor Register Map Register Define (Base Addr = 0xF0000000)
++********************************************************************************/
++//#define HwGEOMETRYPROCESSOR_BASE *(volatile unsigned long *)0xF0002000
++typedef struct _GPUGEOMETRYPROCESSOR{
++ volatile unsigned int CONTR_REG_VSCL_START_ADDR; // 0x2000 R/W 0x00000000 Control Register VSCL Start Address
++ volatile unsigned int CONTR_REG_VSCL_END_ADDR; // 0x2004 R/W 0x00000000 Control Register VSCL End Address
++ volatile unsigned int CONTR_REG_PLBCL_START_ADDR; // 0x2008 R/W 0x00000000 Control Register PLBCL Start Address
++ volatile unsigned int CONTR_REG_PLBCL_END_ADDR; // 0x200C R/W 0x00000000 Control Register PLBCL End Address
++ volatile unsigned int CONTR_REG_PLB_ALLOC_START_ADDR; // 0x2010 R/W 0x00000000 Control Register PLB Allocate Start Address
++ volatile unsigned int CONTR_REG_PLB_ALLOC_END_ADDR; // 0x2014 R/W 0x00000000 Control Register PLB Allocate End Address
++ volatile unsigned int CONTR_REG_CMD; // 0x2020 W N/A Control Register Command
++ volatile unsigned int CONTR_REG_INT_RAWSTAT; // 0x2024 R/W 0x00000000 Control Register Interrupt Rawstat
++ volatile unsigned int CONTR_REG_INT_CLEAR; // 0x2028 W N/A Control Register Interrupt Clear
++ volatile unsigned int CONTR_REG_INT_MASK; // 0x202C R/W 0x00000000 Control Register Interrupt Mask
++ volatile unsigned int CONTR_REG_INT_STAT; // 0x2030 R 0x00000000 Control Register Interrupt Status
++ volatile unsigned int CONTR_REG_WRITE_BOUND_LOW; // 0x2034 R/W 0x00000000 Control Register Write Boundary Low
++ volatile unsigned int CONTR_REG_WRITE_BOUND_HIGH; // 0x2038 R/W 0xFFFFFF00 Control Register Write Boundary High
++ volatile unsigned int CONTR_REG_PERF_CNT_0_ENABLE; // 0x203C R/W 0x00000000 Control Register Performance Counter 0 Enable
++ volatile unsigned int CONTR_REG_PERF_CNT_1_ENABLE; // 0x2040 R/W 0x00000000 Control Register Performance Counter 1 Enable
++ volatile unsigned int CONTR_REG_PERF_CNT_0_SRC; // 0x2044 R/W 0x00000000 Control Register Performance Counter 0 Source
++ volatile unsigned int CONTR_REG_PERF_CNT_1_SRC; // 0x2048 R/W 0x00000000 Control Register Performance Counter 1 Source
++ volatile unsigned int CONTR_REG_PERF_CNT_0_VAL; // 0x204C R 0x00000000 Control Register Performance Counter 0 Value
++ volatile unsigned int CONTR_REG_PERF_CNT_1_VAL; // 0x2050 R 0x00000000 Control Register Performance Counter 1 Value
++ volatile unsigned int CONTR_REG_PERF_CNT_0_LIMIT; // 0x2054 R/W 0x00000000 Control Register Performance Counter 0 Limit
++ volatile unsigned int CONTR_REG_PERF_CNT_1_LIMIT; // 0x2058 R/W 0x00000000 Control Register Performance Counter 1 Limit
++ volatile unsigned int CONTR_REG_STATUS; // 0x2068 R 0x00000000 Control Register Status
++ volatile unsigned int CONTR_REG_VERSION; // 0x206C R 0x0A070005 Control Register VERSION
++ volatile unsigned int CONTR_REG_VSCL_INITIAL_ADDR; // 0x2080 R 0x00000000 Control Register VSCL Initial Address
++ volatile unsigned int CONTR_REG_PLBCL_INITIAL_ADDR; // 0x2084 R 0x00000000 Control Register PLBCL Initial Address
++ volatile unsigned int CONTR_REG_WRITE_BOUNDARY_ERROR_ADDR;// 0x2088 R 0x00000000 Control Register Write Error Address
++ volatile unsigned int CONTR_REG_AXI_BUS_ERROR_STAT; // 0x2094 R 0x00000000 Control AXI Bus Error Status
++ volatile unsigned int CONTR_REG_WATCHDOG_DISABLE; // 0x20A0 R/W 0x00000000 Control Register Watchdog Disable
++ volatile unsigned int CONTR_REG_WATCHDOG_TIMEOUT; // 0x20A4 R/W 0x000F4240 Control Register Watchdog Timeout
++}GPUGEOMETRYPROCESSOR, *PGPUGEOMETRYPROCESSOR;
++
++
++// MaliGP2 PLB Configuration Register Map
++//#define HwPLBCFG_BASE *(volatile unsigned long*)0xFFFFFFFF
++typedef struct _GPUPLBCFG{
++ volatile unsigned char PLB_CONF_REG_VERTEX_ARRAY_ADDR; // 0x0100 W 0x00000000 PLB Configuration Register Vertex Array Address
++ volatile unsigned char PLB_CONF_REG_INDEX_ARRAY_ADDR; // 0x0101 W 0x00000000 PLB Configuration Register Index Array Address
++ volatile unsigned char PLB_CONF_REG_POINT_SIZE_ADDR; // 0x0102 W 0x00000000 PLB Configuration Register Point Size Address
++ volatile unsigned char PLB_CONF_REG_HEAP_START_ADDR; // 0x0103 W 0x00000000 PLB Configuration Register Heap Start Address
++ volatile unsigned char PLB_CONF_REG_HEAP_END_ADDR; // 0x0104 W 0x00000000 PLB Configuration Register Heap End Address
++ volatile unsigned char PLB_CONF_REG_VIEWPORT_TO; // 0x0105 W 0x00000000 PLB Configuration Register Viewport Top
++ volatile unsigned char PLB_CONF_REG_VIEWPORT_BOTTOM; // 0x0106 W 0x00000000 PLB Configuration Register Viewport Bottom
++ volatile unsigned char PLB_CONF_REG_VIEWPORT_LEFT; // 0x0107 W 0x00000000 PLB Configuration Register Viewport Left
++ volatile unsigned char PLB_CONF_REG_VIEWPORT_RIGHT; // 0x0108 W 0x00000000 PLB Configuration Register Viewport Right
++ volatile unsigned char PLB_CONF_REG_SCREENSIZE; // 0x0109 W 0x00000000 PLB Configuration Register Screen Size
++ volatile unsigned char PLB_CONF_REG_OFFSET_VERTEX_ARRAY;// 0x010A W 0x00000000 PLB Configuration Register Offset Vertex Array
++ volatile unsigned char PLB_CONF_REG_PARAMS; // 0x010B W 0x00000000 PLB Configuration Register Parameters
++ volatile unsigned char PLB_CONF_REG_TILE_SIZE; // 0x010C W 0x00000000 PLB Configuration Register Tile Size
++ volatile unsigned char PLB_CONF_REG_POchar_SIZE; // 0x010D W 0x00000000 PLB Configuration Register Pochar Size
++ volatile unsigned char PLB_CONF_REG_Z_NEAR; // 0x010E W 0x00000000 PLB Configuration Register Z Near
++ volatile unsigned char PLB_CONF_REG_Z_FAR; // 0x010F W 0x3F800000 PLB Configuration Register Z Far
++}GPUPLBCFG, *PGPUPLBCFG;
++
++
++// MaliGP2 Vertex Shader Register Map
++//#define HwGPUVERTEXSHADER_BASE *(volatile unsigned long*)0xFFFFFFFF
++typedef union _VSCFGREG1{
++ //volatile unsigned char VS_CONF_REG_INP_ADDR[32]; // 0x0000-0x001E W 0x00000000 VS Configuration Register Input Address
++ //volatile unsigned char VS_CONF_REG_INP_SPEC[32]; // 0x0001-0x001F W 0x0000003F VS Configuration Register Input Specifier
++ volatile unsigned char ADDR[32]; // 0x0000-0x001E W 0x00000000 VS Configuration Register Input Address
++ volatile unsigned char SPEC[32]; // 0x0001-0x001F W 0x0000003F VS Configuration Register Input Specifier
++}VSCFGREG;
++/*
++typedef union _VSCFGREG2{
++ volatile unsigned char ADDR[32]; // 0x0020-0x003E W 0x00000000 VS Configuration Register Output Address
++ volatile unsigned char SPEC[32]; // 0x0021-0x003F W 0x0000003F VS Configuration Register Output Specifier
++}VSCFGREG2;
++*/
++typedef struct _GPUVERTEXSHADER{
++ VSCFGREG VS_CONF_REG_INP;
++ VSCFGREG VS_CONF_REG_OUTP;
++ volatile unsigned char VS_CONF_REG_PROG_PARAM; // 0x0040 W 0x00000000 VS Configuration Register Program Parameter Create
++ volatile unsigned char VS_CONF_REG_PREFETCH; // 0x0041 W 0x00000000 VS Configuration Register Prefetch
++ volatile unsigned char VS_CONF_REG_OPMOD; // 0x0042 W 0x0F000000 VS Configuration Register OPMOD
++ volatile unsigned char VS_CONF_REG_VERTICES_ALT_STRIDE; // 0x0043 W 0x00000000 VS Configuration Register Vertices Alternative Stride
++ volatile unsigned char VS_CONF_REG_INPUT_ALT_STRIDE_0; // 0x0044 W 0x00000000 VS Configuration Register Input Alternative Stride 0
++ volatile unsigned char VS_CONF_REG_INPUT_ALT_STRIDE_1; // 0x0045 W 0x00000000 VS Configuration Register Input Alternative Stride 1
++ volatile unsigned char VS_CONF_REG_INPUT_ALT_STRIDE_2; // 0x0046 W 0x00000000 VS Configuration Register Input Alternative Stride 2
++ volatile unsigned char VS_CONF_REG_INPUT_ALT_STRIDE_3; // 0x0047 W 0x00000000 VS Configuration Register Input Alternative Stride 3
++ volatile unsigned char VS_CONF_REG_OUTPUT_ALT_STRIDE_0; // 0x0048 W 0x00000000 VS Configuration Register Output Alternative Stride 0
++ volatile unsigned char VS_CONF_REG_OUTPUT_ALT_STRIDE_1; // 0x0049 W 0x00000000 VS Configuration Register Output Alternative Stride 1
++ volatile unsigned char VS_CONF_REG_OUTPUT_ALT_STRIDE_2; // 0x004A W 0x00000000 VS Configuration Register Output Alternative Stride 2
++ volatile unsigned char VS_CONF_REG_OUTPUT_ALT_STRIDE_3; // 0x004B W 0x00000000 VS Configuration Register Output Alternative Stride 3
++}GPUVERTEXSHADER, *PGPUVERTEXSHADER;
++
++
++/*******************************************************************************
++* 5-3. MMU Configuration Register Define (Base Addr = 0xF0003000)
++********************************************************************************/
++//#define HwMMUCONFIG_BASE *(volatile unsigned long *)0xF0003000
++typedef struct _GPUMMUCONFIG{
++ volatile unsigned int MMU_DTE_ADDR; // 0x3000 R/W 0x00000000 MMU Current Page Table Address
++ volatile unsigned int MMU_STATUS; // 0x3004 R 0x00000018 MMU Status
++ volatile unsigned int MMU_COMMAND; // 0x3008 W N/A MMU Command
++ volatile unsigned int MMU_PAGE_FAULT_ADDR; // 0x300C R 0x00000000 MMU Logical Address of Last Page Fault
++ volatile unsigned int MMU_ZAP_ONE_LINE; // 0x3010 W N/A MMU Zap Cache Line
++ volatile unsigned int MMU_INT_RAWSTA; // 0x3014 R/W 0x00000000 MMU Raw Interrupt Status
++ volatile unsigned int MMU_INT_CLEAR; // 0x3018 W N/A MMU Interrupt Clear
++ volatile unsigned int MMU_INT_MASK; // 0x301C R/W 0x00000000 MMU Interrupt Mask
++ volatile unsigned int MMU_INT_STATUS; // 0x3020 R 0x00000000 MMU Interrup Status
++}GPUMMUCONFIG, *PGPUMMUCONFIG;
++
++/*******************************************************************************
++* 5-4. GRPBUS Configuration Register Define (Base Addr = 0xF0004000)
++********************************************************************************/
++//#define HwGRPBUS_BASE *(volatile unsigned long *)0xF0004000
++typedef struct _GPUGRPBUSCONFIG{
++ volatile unsigned int GRPBUS_PWRDOWN; // 0x0000 R/W 0x00000000 Graphics bus power down
++ volatile unsigned int GRPBUS_SWRESET; // 0x0004 R/W 0x00000000 Graphics bus software reset
++ volatile unsigned int GRPBUS_MALI_IDLE; // 0x0008 R/W 0x00000002 Mali idle configration
++}GPUGRPBUSCONFIG, *PGPUGRPBUSCONFIG;
++
++/*******************************************************************************
++* 5-5. GRPBUS BWRAP Register Define (Base Addr = 0xF0005000)
++********************************************************************************/
++//#define HwGRPBUSBWRAP_BASE *(volatile unsigned long *)0xF0005000
++typedef struct _GPUGRPBUSBWRAP{
++ volatile unsigned int GRPBUS_BWRAPCTRL; // 0x0000 R/W 0x00000000 Graphics bus bwrap control
++}GPUGRPBUSBWRAP, *PGPUGRPBUSBWRAP;
++
++
++
++
++#endif
+diff --git a/arch/arm/mach-tcc8900/include/mach/bsp_cfg.h b/arch/arm/mach-tcc8900/include/mach/bsp_cfg.h
+new file mode 100644
+index 0000000..9b972a9
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/bsp_cfg.h
+@@ -0,0 +1,32 @@
++/****************************************************************************
++* FileName : bsp_cfg.h
++* Description :
++****************************************************************************
++*
++* TCC Version : 1.0
++* Copyright (c) Telechips, Inc.
++* ALL RIGHTS RESERVED
++*
++****************************************************************************/
++
++#ifndef __BSP_CFG_H__
++#define __BSP_CFG_H__
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++//loglevel option
++#define TC_LOG_OPTION (TC_ERROR | TC_LOG )
++#define TC_LOG_LEVEL(a) ((TC_LOG_OPTION)&(a))
++
++#if defined(_LINUX_)
++# define tc_debug pr_debug
++#endif
++
++//
++#ifdef __cplusplus
++}
++#endif
++
++#endif // __BSP_CFG_H__
+diff --git a/arch/arm/mach-tcc8900/include/mach/common.h b/arch/arm/mach-tcc8900/include/mach/common.h
+new file mode 100644
+index 0000000..7359670
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/common.h
+@@ -0,0 +1,36 @@
++/*
++ * linux/include/asm-arm/arch-tcc8900/common.h
++ *
++ * Author: <linux@telechips.com>
++ * Created: June 10, 2008
++ * Description: Header for code common to all Telechips TCC8900/TCC83x machines.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef __ARCH_ARM_MACH_TCC8900_COMMON_H
++#define __ARCH_ARM_MACH_TCC8900_COMMON_H
++
++struct sys_timer;
++
++extern struct sys_timer tcc8900_timer;
++
++#endif /* __ARCH_ARM_MACH_TCC8900_COMMON_H */
+diff --git a/arch/arm/mach-tcc8900/include/mach/ddr.h b/arch/arm/mach-tcc8900/include/mach/ddr.h
+new file mode 100644
+index 0000000..7895bfe
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/ddr.h
+@@ -0,0 +1,95 @@
++/***************************************************************************************
++* FileName : ddr2.h
++* Description : TCBOOT DDR Configuration File
++****************************************************************************************
++*
++* TCC Board Support Package
++* Copyright (c) Telechips, Inc.
++* ALL RIGHTS RESERVED
++*
++****************************************************************************************/
++
++
++#ifndef __DDR_CONFIG_H__
++#define __DDR_CONFIG_H__
++
++/***********************************************************
++* DRAM config
++* CS BANK CAS_Latency CAS/RAS Size MaxClock PartNumber Vendor
++* [DDR2]
++* DRAM_TYPE1 : 1, 2, 5, 10/13 (16bit x 64 x 2) 128MB, 330Mhz K4T51163QG-HCE6(EVB 0.1) SAMSUNG
++* DRAM_TYPE2 : 1, 2, 6, 10/13 (16bit x 64 x 4) 128MB, 400Mhz H5PS5162FPR S2C- 415A (EVB 1.0), HYNIX
++* H5PS5162FFR S6C-915A HYNIX
++* DRAM_TYPE3 : 1, 3, 5, 10/13 (16bit x 128 x 2) 256MB, 400Mhz K4T1G164QE-HCE7 SAMSUNG
++* 330Mhz K4T1G164QQ-HCE6 SAMSUNG
++* DRAM_TYPE4 : 1, 3, 6, 10/13 (16bit x 128 x 2) 256MB, 400Mhz K4T1G1643QG-HCF7 SAMSUNG
++*
++* [TEST Only]
++* DRAM_TYPE5 : 1, 2, 5, 10/14 (8bit x 64 x 4) 256MB, 330Mhz E5108AG-6E-E ELPIDA
++* DRAM_TYPE6 : 2, 2, 6, 10/13 (16bit x 64 x 4) 256MB, 400Mhz H5PS5162FFR S6C-915A HYNIX
++* [MDDR]
++* DRAM_TYPE7 : 1, 2, 3, 10/13 (16bit x 64 x 2) 128MB, 166Mhz H5MS516DFR J3M-919A HYNIX
++* DRAM_TYPE8 : 1, 2, 3, 10/14 (16bit x 128 x 2) 256MB, 166Mhz H5MS1G62MFP J3M-902A HYNIX
++************************************************************/
++/*--------------*
++ * DDR Type *
++ *--------------*/
++//#define DRAM_TYPE1
++//#define DRAM_TYPE2
++#define DRAM_TYPE3
++//#define DRAM_TYPE4
++//#define DRAM_TYPE5
++//#define DRAM_TYPE6
++//#define DRAM_TYPE7
++//#define DRAM_TYPE8
++
++#if defined(DRAM_TYPE1)
++# define DRAM_DDR2
++# define DRAM_BANK2
++# define DRAM_CAS5
++#endif
++
++#if defined(DRAM_TYPE2)
++# define DRAM_DDR2
++# define DRAM_BANK2
++# define DRAM_CAS6
++#endif
++
++#if defined(DRAM_TYPE3)
++# define DRAM_DDR2
++# define DRAM_BANK3
++# define DRAM_CAS5
++#endif
++
++#if defined(DRAM_TYPE4)
++# define DRAM_DDR2
++# define DRAM_BANK3
++# define DRAM_CAS6
++#endif
++
++#if defined(DRAM_TYPE5)
++# define DRAM_DDR2
++# define DRAM_BANK2
++# define DRAM_CAS5
++#endif
++
++#if defined(DRAM_TYPE6)
++# define DRAM_DDR2
++# define DRAM_BANK2
++# define DRAM_CAS6
++#endif
++
++#if defined(DRAM_TYPE7)
++# define DRAM_MDDR
++# define DRAM_BANK2
++# define DRAM_CAS3
++#endif
++
++#if defined(DRAM_TYPE8)
++# define DRAM_MDDR
++# define DRAM_BANK2
++# define DRAM_CAS3
++#endif
++
++#endif /* __DDR_CONFIG_H__ */
++/************* end of file *************************************************************/
+diff --git a/arch/arm/mach-tcc8900/include/mach/debug-macro.S b/arch/arm/mach-tcc8900/include/mach/debug-macro.S
+new file mode 100644
+index 0000000..dccd599
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/debug-macro.S
+@@ -0,0 +1,40 @@
++/*
++ * linux/include/asm-arm/arch-tcc8900/debug-macro.S
++ *
++ * Based on: linux/arch/arm/kernel/debug.S by Ben Dooks
++ * Author: <linux@telechips.com>
++ * Created: February 10, 2009
++ * Description: Debugging macro include header
++ *
++ * Copyright (C) 1994-1999 Russell King
++ * Copyright (C) 2009 Telechips
++ *
++ * 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.
++ *
++ */
++
++ .macro addruart,rx
++ mrc p15, 0, \rx, c1, c0
++ tst \rx, #1 @ MMU enabled?
++ moveq \rx, #0xf0000000 @ physical base address
++ movne \rx, #0xf0000000 @ virtual base
++ orr \rx, \rx, #0x00530000 @ debug port UART0
++ orr \rx, \rx, #0x2000 @ debug port UART0 0xf00532000
++ .endm
++
++ .macro senduart,rd,rx
++ strb \rd, [\rx]
++ .endm
++
++ .macro busyuart,rd,rx
++ .endm
++
++ .macro waituart,rd,rx
++1001:
++ ldr \rd, [\rx, #0x14]
++ tst \rd, #0x20
++
++ beq 1001b
++ .endm
+diff --git a/arch/arm/mach-tcc8900/include/mach/dma.h b/arch/arm/mach-tcc8900/include/mach/dma.h
+new file mode 100644
+index 0000000..c4c9d3c
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/dma.h
+@@ -0,0 +1,27 @@
++/*
++ * arch/arm/mach-tcc8900/include/mach/dma.h
++ *
++ * Written by <linux@telechips.com>
++ * Modified: March 10, 2009
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
+diff --git a/arch/arm/mach-tcc8900/include/mach/entry-macro.S b/arch/arm/mach-tcc8900/include/mach/entry-macro.S
+new file mode 100644
+index 0000000..7ddbfda
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/entry-macro.S
+@@ -0,0 +1,66 @@
++/*
++ * include/asm-arm/arch-tcc8900/entry-macro.S
++ *
++ * Author : <linux@telechips.com>
++ * Created: Feb 10, 2009
++ * Description: Low-level IRQ helper macros for OMAP-based platforms
++ *
++ * Copyright (C) 2009 Telechips
++ *
++ * 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 <mach/hardware.h>
++#include <mach/irqs.h>
++
++ .macro disable_fiq
++ .endm
++
++ .macro get_irqnr_preamble, base, tmp
++ .endm
++
++ .macro arch_ret_to_user, tmp1, tmp2
++ .endm
++
++ /* tcc8900 dependent code */
++ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
++ ldr \base, =0xF0401000 @ load base address of IRQ registers
++
++ /* A intr */
++ ldr \irqstat, [\base, #0x50] /* MIRQ0 */
++ cmp \irqstat, #0
++ bne 1001f /* jump to check A-intr */
++
++ /* B intr */
++ ldr \irqstat, [\base, #0x54] /* MIRQ1 */
++ cmp \irqstat, #0
++ beq 1002f /* jump to exit macro. cannot find the intr number. (something wrong) */
++
++ /* get B-intr num */
++ mov \irqnr, #0 @@ start here B
++1102: ands \tmp, \irqstat, #1
++ moveq \irqstat, \irqstat, LSR #1
++ addeq \irqnr, \irqnr, #1
++ beq 1102b
++ add \irqnr, \irqnr, #32
++ b 1002f
++
++
++ /* get A-intr num */
++1001: mov \irqnr, #0 @@ start here A
++1101: ands \tmp, \irqstat, #1
++ moveq \irqstat, \irqstat, LSR #1
++ addeq \irqnr, \irqnr, #1
++ beq 1101b
++ @@ work out which irq (if any) we got
++
++ @@ ADD Register #2
++
++
++1002: /* exit */
++ @@ exit here, Z flag unset if IRQ
++ .endm
++
++ .macro irq_prio_table
++ .endm
+diff --git a/arch/arm/mach-tcc8900/include/mach/globals.h b/arch/arm/mach-tcc8900/include/mach/globals.h
+new file mode 100644
+index 0000000..a98b52e
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/globals.h
+@@ -0,0 +1,443 @@
++/****************************************************************************
++* FileName : globals.h
++* Description :
++****************************************************************************
++*
++* TCC Version : 1.0
++* Copyright (c) Telechips, Inc.
++* ALL RIGHTS RESERVED
++*
++****************************************************************************/
++
++//using only global defines, macros.. etc - If you want using this file contact to RYU
++
++#ifndef __GLOBALS_H__
++#define __GLOBALS_H__
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++//Log Level
++#define TC_ERROR 0x00000001
++#define TC_LOG 0x00000002
++#define TC_TRACE 0x00000004
++#define TC_DEBUG 0x00000008
++
++ //system info
++#define IOCTL_PLATFORM_TYPE (L"PLATFORM_TYPE")
++#define IOCTL_PLATFORM_OEM (L"PLATFORM_OEM")
++
++//------------------------------------------------------------------------------
++// Define: IOCTL_PROCESSOR_VENDOR/NAME/CORE
++//
++// Defines the processor information
++//
++
++#define IOCTL_PROCESSOR_VENDOR (L"Telechips")
++#define IOCTL_PROCESSOR_NAME (L"TCC89X")
++#define IOCTL_PROCESSOR_CORE (L"ARM11")
++
++//------------------------------------------------------------------------------
++//
++// Define: IOCTL_PROCESSOR_INSTRUCTION_SET
++//
++// Defines the processor instruction set information
++//
++#define IOCTL_PROCESSOR_INSTRUCTION_SET (0)
++#define IOCTL_PROCESSOR_CLOCK_SPEED 266*1000
++
++//macro defines
++/************************************************************************************************
++* MACRO *
++************************************************************************************************/
++#ifndef BITSET
++#define BITSET(X, MASK) ( (X) |= (unsigned int)(MASK) )
++#endif
++#ifndef BITSCLR
++#define BITSCLR(X, SMASK, CMASK) ( (X) = ((((unsigned int)(X)) | ((unsigned int)(SMASK))) & ~((unsigned int)(CMASK))) )
++#endif
++#ifndef BITCSET
++#define BITCSET(X, CMASK, SMASK) ( (X) = ((((unsigned int)(X)) & ~((unsigned int)(CMASK))) | ((unsigned int)(SMASK))) )
++#endif
++#ifndef BITCLR
++#define BITCLR(X, MASK) ( (X) &= ~((unsigned int)(MASK)) )
++#endif
++#ifndef BITXOR
++#define BITXOR(X, MASK) ( (X) ^= (unsigned int)(MASK) )
++#endif
++#ifndef ISZERO
++#define ISZERO(X, MASK) ( ! (((unsigned int)(X)) & ((unsigned int)(MASK))) )
++#endif
++
++#ifndef ENABLE
++#define ENABLE 1
++#endif
++#ifndef DISABLE
++#define DISABLE 0
++#endif
++
++#ifndef ON
++#define ON 1
++#endif
++#ifndef OFF
++#define OFF 0
++#endif
++
++#ifndef FALSE
++#define FALSE 0
++#endif
++#ifndef TRUE
++#define TRUE 1
++#endif
++
++#define HwVMT_SZ(X) (((X)-1)*Hw12)
++ #define SIZE_4GB 32
++ #define SIZE_2GB 31
++ #define SIZE_1GB 30
++ #define SIZE_512MB 29
++ #define SIZE_256MB 28
++ #define SIZE_128MB 27
++ #define SIZE_64MB 26
++ #define SIZE_32MB 25
++ #define SIZE_16MB 24
++ #define SIZE_8MB 23
++ #define SIZE_4MB 22
++ #define SIZE_2MB 21
++ #define SIZE_1MB 20
++ #define HwVMT_REGION_AP_ALL (Hw11+Hw10)
++ #define HwVMT_DOMAIN(X) ((X)*Hw5)
++ #define HwVMT_REGION_EN Hw9 // Region Enable Register
++ #define HwVMT_CACHE_ON Hw3 // Cacheable Register
++ #define HwVMT_CACHE_OFF HwZERO
++ #define HwVMT_BUFF_ON Hw2 // Bufferable Register
++ #define HwVMT_BUFF_OFF HwZERO
++
++ #define HwVMT_REGION0_EN Hw9 // Region Enable Register
++ #define HwVMT_REGION0_CA Hw3 // Cacheable Register
++ #define HwVMT_REGION0_BU Hw2 // Bufferable Register
++
++/************************************************************************************************
++* ENUM *
++************************************************************************************************/
++/***************************************CLOCK****************************************************/
++ enum
++ {
++ IDLE_PRIORITY = 0, // Don't Return IDLE_PRIORITY
++ LOW_PRIORITY,
++ MID_PRIORITY,
++ HIGH_PRIORITY,
++ MAX_PRIORITY,
++
++ CLOCK_PRIORITY_NUM,
++ //}stCKC_PRIORITY;
++ };
++
++//CKC Enum
++ enum{ /* CLKCTRL Clock Source */
++ DIRECTPLL0=0,
++ DIRECTPLL1,
++ DIRECTPLL2,
++ DIRECTPLL3,
++ DIRECTXIN,
++ DIVIDPLL0,
++ DIVIDPLL1,
++ DIRECTXTIN,
++ };
++
++ enum{ /* Peri. Clock Source */
++ PCDIRECTPLL0=0,
++ PCDIRECTPLL1,
++ PCDIRECTPLL2,
++ PCDIRECTPLL3,
++ PCDIRECTXIN,
++ PCDIVIDPLL0,
++ PCDIVIDPLL1,
++ PCDIVIDPLL2,
++ PCDIVIDPLL3,
++ PCDIRECTXTIN,
++ PCEXITERNAL, // 10
++ PCDIVIDXIN_HDMITMDS,
++ PCDIVIDXTIN_HDMIPCLK,
++ PCHDMI, // 27Mhz
++ PCSATA, // 25Mhz
++ PCUSBPHY, // 48Mhz
++ };
++
++ enum{ /* Peri. Clock Source */
++ PDCO = 0,
++ PDIVIDER,
++ };
++
++ enum {/* Peri. Name */
++ PERI_TCX = 0,
++ PERI_TCT,
++ PERI_TCZ,
++ PERI_LCD0,
++ PERI_LCD1,
++ PERI_LCDSI,
++ PERI_CIFMC,
++ PERI_CIFSC,
++ PERI_OUT0,
++ PERI_OUT1,
++ PERI_HDMI,
++ PERI_USB11H,
++ PERI_SDMMC0,
++ PERI_MSTICK,
++ PERI_I2C,
++ PERI_UART0,
++ PERI_UART1,
++ PERI_UART2,
++ PERI_UART3,
++ PERI_UART4,
++ PERI_UART5,
++ PERI_GPSB0,
++ PERI_GPSB1,
++ PERI_GPSB2,
++ PERI_GPSB3,
++ PERI_GPSB4,
++ PERI_GPSB5,
++ PERI_ADC,
++ PERI_SPDIF,
++ PERI_EHI0,
++ PERI_EHI1,
++ PERI_AUD,
++ PERI_CAN,
++ PERI_Reserved0,
++ PERI_SDMMC1,
++ PERI_Reserved1,
++ PERI_DAI,
++ };
++
++ enum{/*for PWROFF Register*/
++ PMU_VIDEODAC = 0,
++ PMU_HDMIPHY,
++ PMU_LVDSPHY,
++ PMU_USBNANOPHY,
++ PMU_SATAPHY,
++ PMU_MEMORYBUS,
++ PMU_VIDEOBUS,
++ PMU_DDIBUS,
++ PMU_GRAPHICBUS,
++ PMU_IOBUS,
++ };
++
++ enum{/* for SWRESET */
++ RESET_CPU = 0,
++ RESET_DDIBUS,
++ RESET_MEMBUS,
++ RESET_GRAPBUS,
++ RESET_IOBUS,
++ RESET_VIDEOBUS,
++ RESET_VIDEOCORE,
++ RESET_SMU,
++ };
++
++ enum {/* clock divider (div+1) */
++ CLKDIV0 = 0,
++ CLKDIV2 ,
++ CLKDIV3 ,
++ CLKDIV4 ,
++ CLKDIVNONCHANGE,
++ };
++
++ enum {
++ CLKCTRL0 = 0, //FCORE_CPU
++ CLKCTRL1, //FBUS_DDI
++ CLKCTRL2, //FMEM_BUS
++ CLKCTRL3, //FBUS_GRP
++ CLKCTRL4, //FBUS_IOB
++ CLKCTRL5, //FBUS_VBUS
++ CLKCTRL6, //FBUS_VCODEC
++ CLKCTRL7, //FBUS_SMU
++ };
++
++ enum {
++ NORMAL_MD = 0,
++ DYNAMIC_MD,
++ };
++
++ enum {
++ RB_USB11H = 0,
++ RB_USB20OTG,
++ RB_IDECONTROLLER,
++ RB_DMACONTROLLER ,
++ RB_SDMMCCONTROLLER ,
++ RB_SATAHCONTROLLER ,
++ RB_MEMORYSTICKCONTROLLER ,
++ RB_I2CCONTROLLER ,
++ RB_NFCCONTROLLER ,
++ RB_EXTHCONTROLLER0 ,
++ RB_EXTHCONTROLLER1 , //10
++ RB_UARTCONTROLLER0 ,
++ RB_UARTCONTROLLER1 ,
++ RB_UARTCONTROLLER2 ,
++ RB_UARTCONTROLLER3 ,
++ RB_UARTCONTROLLER4 ,
++ RB_UARTCONTROLLER5 ,
++ RB_GPSBCONTROLLER0 ,
++ RB_GPSBCONTROLLER1 ,
++ RB_GPSBCONTROLLER2 ,
++ RB_GPSBCONTROLLER3 , //20
++ RB_GPSBCONTROLLER4 ,
++ RB_GPSBCONTROLLER5 ,
++ RB_DAICDIFCONTROLLER ,
++ RB_ECCCONTROLLER ,
++ RB_SPDIFTXCONTROLLER,
++ RB_RTCCONTROLLER ,
++ RB_TSADCCONTROLLER,
++ RB_GPSCONTROLLER ,
++ RB_RESERVEDCONTROLLER,
++ RB_CANCONTROLLER,
++ RB_ADMACONTROLLER, // 31
++
++ RB_MPE_FECCONTROLLER,
++ RB_TSIFCONTROLLER,
++ RB_SRAMCONTROLLER,
++
++ RB_ALLPERIPERALS,
++
++ };
++
++ enum{ /* Fmbus Step */
++ FMBUS_141Mhz=0,
++ FMBUS_145Mhz,
++ FMBUS_150Mhz,
++ FMBUS_160Mhz,
++ FMBUS_170Mhz,
++ FMBUS_180Mhz,
++ FMBUS_190Mhz,
++ FMBUS_200Mhz,
++ FMBUS_210Mhz,
++ FMBUS_220Mhz,
++ FMBUS_230Mhz,
++ FMBUS_240Mhz,
++ FMBUS_250Mhz,
++ FMBUS_260Mhz,
++ FMBUS_270Mhz,
++ FMBUS_280Mhz,
++ FMBUS_290Mhz,
++ FMBUS_300Mhz,
++ FMBUS_312Mhz,
++ FMBUS_320Mhz,
++ FMBUS_330Mhz,
++
++ FMBUS_STEPMAX,
++ };
++
++ enum{ /* ddi Power Down Field */
++ DDIPWDN_CIF = 0,
++ DDIPWDN_VIQE,
++ DDIPWDN_LCDC0,
++ DDIPWDN_LCDC1,
++ DDIPWDN_LCDSI,
++ DDIPWDN_MSCL0,
++ DDIPWDN_MSCL1,
++ DDIPWDN_DDIC,
++ DDIPWDN_HDMI,
++ DDIPWDN_STEPMAX,
++ };
++
++ enum{ /* ETC Power Down Field */
++ ETC_USBPHYOFF = 0,
++ ETC_USBPHYON,
++ ETC_3DGPUOFF,
++ ETC_3DGPUON,
++ ETC_OVERLAYMIXEROFF,
++ ETC_OVERLAYMIXERON ,
++
++ ETC_STEPMAX,
++
++ };
++
++#define ETCMASK_USBPHYOFF 0x00000001
++#define ETCMASK_USBPHYON 0x00000002
++#define ETCMASK_3DGPUOFF 0x00000004
++#define ETCMASK_3DGPUON 0x00000008
++#define ETCMASK_OVERLAYMIXEROFF 0x00000010
++#define ETCMASK_OVERLAYMIXERON 0x00000020
++
++/***************************************Interrup****************************************************/
++enum {
++ IRQ_TC0 =0, // 0 0x0 Timer 0 interrupt enable
++ IRQ_TC1, // 1 0x0 Timer 1 interrupt enable
++ IRQ_SMUI2C, // 2 0x0 SMU_I2C interrupt enable
++ IRQ_EI0, // 3 0x0 External interrupt 0 enable
++ IRQ_EI1, // 4 0x0 External interrupt 1 enable
++ IRQ_EI2, // 5 0x0 External interrupt 2 enable
++ IRQ_EI3, // 6 0x0 External interrupt 3 enable
++ IRQ_EI4, // 7 0x0 External interrupt 4 enable
++ IRQ_EI5, // 8 0x0 External interrupt 5 enable
++ IRQ_EI6, // 9 0x0 External interrupt 6 enable
++ IRQ_EI7, // 10 0x0 External interrupt 7 enable
++ IRQ_EI8, // 11 0x0 External interrupt 8 enable
++ IRQ_EI9, // 12 0x0 External interrupt 9 enable
++ IRQ_EI10, // 13 0x0 External interrupt 10 enable
++ IRQ_EI11, // 14 0x0 External interrupt 11 enable
++ IRQ_SC0, // 15 0x0 Mem-to-Mem scaler 0 interrupt enable
++ IRQ_SC1, // 16 0x0 Mem-to-Mem scaler 0 interrupt enable
++ IRQ_CAM, // 17 0x0 Camera interrupt enable
++ IRQ_LCD0, // 18 0x0 LCD controller 0 interrupt enable
++ IRQ_LCD1, // 19 0x0 LCD controller 1 interrupt enable
++ IRQ_VIPET, // 20 0x0 VIPET controller interrupt enable Note: the interrupt request signal is active low. 21 JPGE RW 0x0 JPEG Encoder interrupt enable
++ IRQ_JPGE, // 21 0x0 JPEG Decoder interrupt enable
++ IRQ_JPGD, // 22 0x0 JPEG Decoder interrupt enable
++ IRQ_VCDC, // 23 0x0 Video CODEC interrupt enable
++ IRQ_3DPP, // 24 0x0 3D Pixel Processor interrupt enable
++ IRQ_3DGP, // 25 0x0 3D Geometry Processor interrupt enable
++ IRQ_3DMMU, // 26 0x0 3D MMU interrupt enable
++ IRQ_G2D, // 27 0x0 Graphic Engine 2D Hardware Interrupt Enable
++ IRQ_TSADC, // 28 0x0 TSADC interrupt enable
++ IRQ_DMA, // 29 0x0 DMA controller interrupt enable
++ IRQ_ECC, // 30 0x0 ECC interrupt enable
++ IRQ_EHI0, // 31 0x0 External interrupt 0 enable
++ IRQ_EHI1, // 32 0x0 External interrupt 1 enable
++ IRQ_CAN, // 33 0x0 CAN interrupt enable
++ IRQ_HDMI, // 34 0x0 HDMI interrupt enable
++ IRQ_SATA, // 35 0x0 SATA Host interrupt enable
++ IRQ_GPSB, // 36 0x0 GPSB Interrupt Enable
++ IRQ_HDD, // 37 0x0 HDD controller interrupt enable
++ IRQ_I2C, // 38 0x0 I2C interrupt enable
++ IRQ_MPEFEC, // 39 0x0 MPEFEC interrupt enable
++ IRQ_MS, // 40 0x0 Memory Stick interrupt enable
++ IRQ_NFC, // 41 0x0 Nand flash controller interrupt enable
++ IRQ_RMT, // 42 0x0 Remote Control interrupt enable
++ IRQ_RTC, // 43 0x0 RTC interrupt enable
++ IRQ_SD0, // 44 0x0 SD/MMC 0 interrupt enable
++ IRQ_SD1, // 45 0x0 SD/MMC 1 interrupt enable
++ IRQ_SPDTX, // 46 0x0 SPDIF transmitter interrupt enable
++ IRQ_UART, // 47 0x0 UART interrupt enable
++ IRQ_UOTG, // 48 0x0 USB 2.0 OTG interrupt enable
++ IRQ_U11H, // 49 0x0 USB 1.1 host interrupt enable
++ IRQ_GPS0, // 50 0x0 GPS RTC expired interrupt enable
++ IRQ_GPS1, // 51 0x0 GPS TCXO expired interrupt enable
++ IRQ_GPS2, // 52 0x0 GPS AGPS interrupt enable
++ IRQ_TSIF0, // 53 0x0 TS interface 0 interrupt enable
++ IRQ_TSIF1, // 54 0x0 TS interface 1 interrupt enable
++ IRQ_CDRX, // 55 0x0 CDIF receive interrupt enable
++ IRQ_DAIRX, // 56 0x0 DAI receive interrupt enable
++ IRQ_DAITX, // 57 0x0 DAI transmit interrupt enable
++ IRQ_ADMA, // 58 0x0 AUDIO DMA interrupt enable
++ IRQ_AUDIO, // 59 0x0 AUDIO interrupt enable
++ IRQ_APMU, // 60 0x0 ARM System Metrics interrupt enable Note: the interrupt request signal is active low.
++ IRQ_AIRQ, // 61 0x0 Non secure ARM DMA interrupt enable Note: the interrupt request signal is active low.
++ IRQ_ASIRQ, // 62 0x0 Secure ARM DMA select interrupt enable Note: the interrupt request signal is active low.
++ IRQ_AEIRQ, // 63 0x0 Not maskable error ARM DMA interrupt enable Note: the interrupt request signal is active low.
++};
++
++typedef struct _rtctime {
++ unsigned int wYear;
++ unsigned int wMonth;
++ unsigned int wDayOfWeek;
++ unsigned int wDay;
++ unsigned int wHour;
++ unsigned int wMinute;
++ unsigned int wSecond;
++ unsigned int wMilliseconds;
++} rtctime;
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif // __GLOBALS_H__
+diff --git a/arch/arm/mach-tcc8900/include/mach/gpio.h b/arch/arm/mach-tcc8900/include/mach/gpio.h
+new file mode 100644
+index 0000000..f973bac
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/gpio.h
+@@ -0,0 +1,711 @@
++/*
++ * arch/arm/mach-tcc8900/include/mach/gpio.h
++ *
++ * Written by <linux@telechips.com>
++ * Modified: March 10, 2009
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/kernel.h>
++#include <mach/TCC89x_Physical.h>
++#include <asm/irq.h>
++
++/* configure GPIO ports A..F */
++#define TCC_GPIOREG(x) ((x) + HWGPIO_BASE)
++
++/* GPIO */
++#define TCC_GPIONO(bank,offset) ((bank) + (offset))
++
++#define TCC_GPIO_BANKA (32*0)
++#define TCC_GPIO_BANKB (32*1)
++#define TCC_GPIO_BANKC (32*2)
++#define TCC_GPIO_BANKD (32*3)
++#define TCC_GPIO_BANKE (32*4)
++#define TCC_GPIO_BANKF (32*5)
++
++#define TCC_GPIO_INPUT (0)
++#define TCC_GPIO_OUTPUT (1)
++#define TCC_GPIO_BASE(pin) ((pin & ~31) >> 5)
++#define TCC_GPIO_OFFSET(pin) (pin & 31)
++
++/* GPA : 16 in/out port */
++#define TCC_GPADAT TCC_GPIOREG(0x00)
++#define TCC_GPAEN TCC_GPIOREG(0x04)
++#define TCC_GPASET TCC_GPIOREG(0x08)
++#define TCC_GPACLR TCC_GPIOREG(0x0C)
++#define TCC_GPAXOR TCC_GPIOREG(0x10)
++#define TCC_GPACD0 TCC_GPIOREG(0x14)
++#define TCC_GPACD1 TCC_GPIOREG(0x18)
++#define TCC_GPAPD0 TCC_GPIOREG(0x1C)
++#define TCC_GPAPD1 TCC_GPIOREG(0x20)
++#define TCC_GPAFN0 TCC_GPIOREG(0x24)
++#define TCC_GPAFN1 TCC_GPIOREG(0x28)
++#define TCC_GPAFN2 TCC_GPIOREG(0x2C)
++#define TCC_GPAFN3 TCC_GPIOREG(0x30)
++
++#define TCC_GPA0 TCC_GPIONO(TCC_GPIO_BANKA, 0)
++#define TCC_GPA0_GPIO (0)
++#define TCC_GPA0_SCL0 (1)
++
++#define TCC_GPA1 TCC_GPIONO(TCC_GPIO_BANKA, 1)
++#define TCC_GPA1_GPIO (0)
++#define TCC_GPA1_SDA0 (1)
++
++#define TCC_GPA2 TCC_GPIONO(TCC_GPIO_BANKA, 2)
++#define TCC_GPA2_GPIO (0)
++#define TCC_GPA2_CLK_OUT0 (1)
++
++#define TCC_GPA3 TCC_GPIONO(TCC_GPIO_BANKA, 3)
++#define TCC_GPA3_GPIO (0)
++#define TCC_GPA3_CLK_OUT1 (1)
++
++#define TCC_GPA4 TCC_GPIONO(TCC_GPIO_BANKA, 4)
++#define TCC_GPA4_GPIO (0)
++#define TCC_GPA4_WDTRSTO (1)
++#define TCC_GPA4_TCO0 (2)
++
++#define TCC_GPA5 TCC_GPIONO(TCC_GPIO_BANKA, 5)
++#define TCC_GPA5_GPIO (0)
++#define TCC_GPA5_IRDI (1)
++#define TCC_GPA5_TCO1 (2)
++
++#define TCC_GPA6 TCC_GPIONO(TCC_GPIO_BANKA, 6)
++#define TCC_GPA6_GPIO (0)
++#define TCC_GPA6_HDMI_CECO (1)
++#define TCC_GPA6_TCO2 (2)
++#define TCC_GPA6_EDIXA19 (6)
++
++#define TCC_GPA7 TCC_GPIONO(TCC_GPIO_BANKA, 7)
++#define TCC_GPA7_GPIO (0)
++#define TCC_GPA7_HDMI_CECI (1)
++#define TCC_GPA7_TCO3 (2)
++#define TCC_GPA7_EDIXA20 (6)
++
++#define TCC_GPA8 TCC_GPIONO(TCC_GPIO_BANKA, 8)
++#define TCC_GPA8_GPIO (0)
++#define TCC_GPA8_SCL1 (1)
++
++#define TCC_GPA9 TCC_GPIONO(TCC_GPIO_BANKA, 9)
++#define TCC_GPA9_GPIO (0)
++#define TCC_GPA9_SCL1 (1)
++
++#define TCC_GPA10 TCC_GPIONO(TCC_GPIO_BANKA, 10)
++#define TCC_GPA10_GPIO (0)
++#define TCC_GPA10_CBCLK0 (1)
++#define TCC_GPA10_CBCLK1 (2)
++
++#define TCC_GPA11 TCC_GPIONO(TCC_GPIO_BANKA, 11)
++#define TCC_GPA11_GPIO (0)
++#define TCC_GPA11_CLRCK0 (1)
++#define TCC_GPA11_CLRCK1 (2)
++
++#define TCC_GPA12 TCC_GPIONO(TCC_GPIO_BANKA, 12)
++#define TCC_GPA12_GPIO (0)
++#define TCC_GPA12_CDATA0 (1)
++#define TCC_GPA12_CDATA1 (2)
++
++#define TCC_GPA13 TCC_GPIONO(TCC_GPIO_BANKA, 13)
++#define TCC_GPA13_GPIO (0)
++#define TCC_GPA13_EXTCLK1 (1)
++
++#define TCC_GPA14 TCC_GPIONO(TCC_GPIO_BANKA, 14)
++#define TCC_GPA14_GPIO (0)
++#define TCC_GPA14_HDMI_HPD (1)
++#define TCC_GPA14_TCO4 (2)
++
++#define TCC_GPA15 TCC_GPIONO(TCC_GPIO_BANKA, 15)
++#define TCC_GPA15_GPIO (0)
++#define TCC_GPA15_UTM_DRVVBUS (1)
++#define TCC_GPA15_TCO5 (2)
++
++/* GPB : 32 in/out port */
++#define TCC_GPBDAT TCC_GPIOREG(0x40)
++#define TCC_GPBEN TCC_GPIOREG(0x44)
++#define TCC_GPBSET TCC_GPIOREG(0x48)
++#define TCC_GPBCLR TCC_GPIOREG(0x4C)
++#define TCC_GPBXOR TCC_GPIOREG(0x50)
++#define TCC_GPBCD0 TCC_GPIOREG(0x54)
++#define TCC_GPBCD1 TCC_GPIOREG(0x58)
++#define TCC_GPBPD0 TCC_GPIOREG(0x5C)
++#define TCC_GPBPD1 TCC_GPIOREG(0x60)
++#define TCC_GPBFN0 TCC_GPIOREG(0x64)
++#define TCC_GPBFN1 TCC_GPIOREG(0x68)
++#define TCC_GPBFN2 TCC_GPIOREG(0x6C)
++#define TCC_GPBFN3 TCC_GPIOREG(0x70)
++
++#define TCC_GPB0 TCC_GPIONO(TCC_GPIO_BANKB, 0)
++#define TCC_GPB0_GPIO (0)
++#define TCC_GPB0_EDIXD8 (1)
++#define TCC_GPB0_SD_D0_5 (2)
++#define TCC_GPB0_MS_D0_5 (3)
++
++#define TCC_GPB1 TCC_GPIONO(TCC_GPIO_BANKB, 1)
++#define TCC_GPB1_GPIO (0)
++#define TCC_GPB1_EDIXD9 (1)
++#define TCC_GPB1_SD_D1_5 (2)
++#define TCC_GPB1_MS_D1_5 (3)
++
++#define TCC_GPB2 TCC_GPIONO(TCC_GPIO_BANKB, 2)
++#define TCC_GPB2_GPIO (0)
++#define TCC_GPB2_EDIXD10 (1)
++#define TCC_GPB2_SD_D2_5 (2)
++#define TCC_GPB2_MS_D2_5 (3)
++
++#define TCC_GPB3 TCC_GPIONO(TCC_GPIO_BANKB, 3)
++#define TCC_GPB3_GPIO (0)
++#define TCC_GPB3_EDIXD11 (1)
++#define TCC_GPB3_SD_D3_5 (2)
++#define TCC_GPB3_MS_D3_5 (3)
++
++#define TCC_GPB4 TCC_GPIONO(TCC_GPIO_BANKB, 4)
++#define TCC_GPB4_GPIO (0)
++#define TCC_GPB4_EDIXD4 (1)
++#define TCC_GPB4_SD_D4_5 (2)
++#define TCC_GPB4_MS_D4_5 (3)
++
++#define TCC_GPB5 TCC_GPIONO(TCC_GPIO_BANKB, 5)
++#define TCC_GPB5_GPIO (0)
++
++#define TCC_GPB6 TCC_GPIONO(TCC_GPIO_BANKB, 6)
++#define TCC_GPB6_GPIO (0)
++
++#define TCC_GPB7 TCC_GPIONO(TCC_GPIO_BANKB, 7)
++#define TCC_GPB7_GPIO (0)
++
++#define TCC_GPB8 TCC_GPIONO(TCC_GPIO_BANKB, 8)
++#define TCC_GPB8_GPIO (0)
++
++#define TCC_GPB9 TCC_GPIONO(TCC_GPIO_BANKB, 9)
++#define TCC_GPB9_GPIO (0)
++
++#define TCC_GPB10 TCC_GPIONO(TCC_GPIO_BANKB, 10)
++#define TCC_GPB10_GPIO (0)
++
++#define TCC_GPB11 TCC_GPIONO(TCC_GPIO_BANKB, 11)
++#define TCC_GPB11_GPIO (0)
++
++#define TCC_GPB12 TCC_GPIONO(TCC_GPIO_BANKB, 12)
++#define TCC_GPB12_GPIO (0)
++
++#define TCC_GPB13 TCC_GPIONO(TCC_GPIO_BANKB, 13)
++#define TCC_GPB13_GPIO (0)
++
++#define TCC_GPB14 TCC_GPIONO(TCC_GPIO_BANKB, 14)
++#define TCC_GPB14_GPIO (0)
++
++#define TCC_GPB15 TCC_GPIONO(TCC_GPIO_BANKB, 15)
++#define TCC_GPB15_GPIO (0)
++
++#define TCC_GPB16 TCC_GPIONO(TCC_GPIO_BANKB, 16)
++#define TCC_GPB16_GPIO (0)
++
++#define TCC_GPB17 TCC_GPIONO(TCC_GPIO_BANKB, 17)
++#define TCC_GPB17_GPIO (0)
++
++#define TCC_GPB18 TCC_GPIONO(TCC_GPIO_BANKB, 18)
++#define TCC_GPB18_GPIO (0)
++
++#define TCC_GPB19 TCC_GPIONO(TCC_GPIO_BANKB, 19)
++#define TCC_GPB19_GPIO (0)
++
++#define TCC_GPB20 TCC_GPIONO(TCC_GPIO_BANKB, 20)
++#define TCC_GPB20_GPIO (0)
++
++#define TCC_GPB21 TCC_GPIONO(TCC_GPIO_BANKB, 21)
++#define TCC_GPB21_GPIO (0)
++
++#define TCC_GPB22 TCC_GPIONO(TCC_GPIO_BANKB, 22)
++#define TCC_GPB22_GPIO (0)
++
++#define TCC_GPB23 TCC_GPIONO(TCC_GPIO_BANKB, 23)
++#define TCC_GPB23_GPIO (0)
++
++#define TCC_GPB24 TCC_GPIONO(TCC_GPIO_BANKB, 24)
++#define TCC_GPB24_GPIO (0)
++
++#define TCC_GPB25 TCC_GPIONO(TCC_GPIO_BANKB, 25)
++#define TCC_GPB25_GPIO (0)
++
++#define TCC_GPB26 TCC_GPIONO(TCC_GPIO_BANKB, 26)
++#define TCC_GPB26_GPIO (0)
++
++#define TCC_GPB27 TCC_GPIONO(TCC_GPIO_BANKB, 27)
++#define TCC_GPB27_GPIO (0)
++
++#define TCC_GPB28 TCC_GPIONO(TCC_GPIO_BANKB, 28)
++#define TCC_GPB28_GPIO (0)
++
++#define TCC_GPB29 TCC_GPIONO(TCC_GPIO_BANKB, 29)
++#define TCC_GPB29_GPIO (0)
++
++#define TCC_GPB30 TCC_GPIONO(TCC_GPIO_BANKB, 30)
++#define TCC_GPB30_GPIO (0)
++
++#define TCC_GPB31 TCC_GPIONO(TCC_GPIO_BANKB, 31)
++#define TCC_GPB31_GPIO (0)
++
++/* GPC : 32 in/out port */
++#define TCC_GPCDAT TCC_GPIOREG(0x80)
++#define TCC_GPCEN TCC_GPIOREG(0x84)
++#define TCC_GPCSET TCC_GPIOREG(0x88)
++#define TCC_GPCCLR TCC_GPIOREG(0x8C)
++#define TCC_GPCXOR TCC_GPIOREG(0x90)
++#define TCC_GPCCD0 TCC_GPIOREG(0x94)
++#define TCC_GPCCD1 TCC_GPIOREG(0x98)
++#define TCC_GPCPD0 TCC_GPIOREG(0x9C)
++#define TCC_GPCPD1 TCC_GPIOREG(0xA0)
++#define TCC_GPCFN0 TCC_GPIOREG(0xA4)
++#define TCC_GPCFN1 TCC_GPIOREG(0xA8)
++#define TCC_GPCFN2 TCC_GPIOREG(0xAC)
++#define TCC_GPCFN3 TCC_GPIOREG(0xB0)
++
++#define TCC_GPC0 TCC_GPIONO(TCC_GPIO_BANKC, 0)
++#define TCC_GPC0_GPIO (0)
++
++#define TCC_GPC1 TCC_GPIONO(TCC_GPIO_BANKC, 1)
++#define TCC_GPC1_GPIO (0)
++
++#define TCC_GPC2 TCC_GPIONO(TCC_GPIO_BANKC, 2)
++#define TCC_GPC2_GPIO (0)
++
++#define TCC_GPC3 TCC_GPIONO(TCC_GPIO_BANKC, 3)
++#define TCC_GPC3_GPIO (0)
++
++#define TCC_GPC4 TCC_GPIONO(TCC_GPIO_BANKC, 4)
++#define TCC_GPC4_GPIO (0)
++
++#define TCC_GPC5 TCC_GPIONO(TCC_GPIO_BANKC, 5)
++#define TCC_GPC5_GPIO (0)
++
++#define TCC_GPC6 TCC_GPIONO(TCC_GPIO_BANKC, 6)
++#define TCC_GPC6_GPIO (0)
++
++#define TCC_GPC7 TCC_GPIONO(TCC_GPIO_BANKC, 7)
++#define TCC_GPC7_GPIO (0)
++
++#define TCC_GPC8 TCC_GPIONO(TCC_GPIO_BANKC, 8)
++#define TCC_GPC8_GPIO (0)
++
++#define TCC_GPC9 TCC_GPIONO(TCC_GPIO_BANKC, 9)
++#define TCC_GPC9_GPIO (0)
++
++#define TCC_GPC10 TCC_GPIONO(TCC_GPIO_BANKC, 10)
++#define TCC_GPC10_GPIO (0)
++
++#define TCC_GPC11 TCC_GPIONO(TCC_GPIO_BANKC, 11)
++#define TCC_GPC11_GPIO (0)
++
++#define TCC_GPC12 TCC_GPIONO(TCC_GPIO_BANKC, 12)
++#define TCC_GPC12_GPIO (0)
++
++#define TCC_GPC13 TCC_GPIONO(TCC_GPIO_BANKC, 13)
++#define TCC_GPC13_GPIO (0)
++
++#define TCC_GPC14 TCC_GPIONO(TCC_GPIO_BANKC, 14)
++#define TCC_GPC14_GPIO (0)
++
++#define TCC_GPC15 TCC_GPIONO(TCC_GPIO_BANKC, 15)
++#define TCC_GPC15_GPIO (0)
++
++#define TCC_GPC16 TCC_GPIONO(TCC_GPIO_BANKC, 16)
++#define TCC_GPC16_GPIO (0)
++
++#define TCC_GPC17 TCC_GPIONO(TCC_GPIO_BANKC, 17)
++#define TCC_GPC17_GPIO (0)
++
++#define TCC_GPC18 TCC_GPIONO(TCC_GPIO_BANKC, 18)
++#define TCC_GPC18_GPIO (0)
++
++#define TCC_GPC19 TCC_GPIONO(TCC_GPIO_BANKC, 19)
++#define TCC_GPC19_GPIO (0)
++
++#define TCC_GPC20 TCC_GPIONO(TCC_GPIO_BANKC, 20)
++#define TCC_GPC20_GPIO (0)
++
++#define TCC_GPC21 TCC_GPIONO(TCC_GPIO_BANKC, 21)
++#define TCC_GPC21_GPIO (0)
++
++#define TCC_GPC22 TCC_GPIONO(TCC_GPIO_BANKC, 22)
++#define TCC_GPC22_GPIO (0)
++
++#define TCC_GPC23 TCC_GPIONO(TCC_GPIO_BANKC, 23)
++#define TCC_GPC23_GPIO (0)
++
++#define TCC_GPC24 TCC_GPIONO(TCC_GPIO_BANKC, 24)
++#define TCC_GPC24_GPIO (0)
++
++#define TCC_GPC25 TCC_GPIONO(TCC_GPIO_BANKC, 25)
++#define TCC_GPC25_GPIO (0)
++
++#define TCC_GPC26 TCC_GPIONO(TCC_GPIO_BANKC, 26)
++#define TCC_GPC26_GPIO (0)
++
++#define TCC_GPC27 TCC_GPIONO(TCC_GPIO_BANKC, 27)
++#define TCC_GPC27_GPIO (0)
++
++#define TCC_GPC28 TCC_GPIONO(TCC_GPIO_BANKC, 28)
++#define TCC_GPC28_GPIO (0)
++
++#define TCC_GPC29 TCC_GPIONO(TCC_GPIO_BANKC, 29)
++#define TCC_GPC29_GPIO (0)
++
++#define TCC_GPC30 TCC_GPIONO(TCC_GPIO_BANKC, 30)
++#define TCC_GPC30_GPIO (0)
++
++#define TCC_GPC31 TCC_GPIONO(TCC_GPIO_BANKC, 31)
++#define TCC_GPC31_GPIO (0)
++
++/* GPD : 32 in/out port */
++#define TCC_GPDDAT TCC_GPIOREG(0xC0)
++#define TCC_GPDEN TCC_GPIOREG(0xC4)
++#define TCC_GPDSET TCC_GPIOREG(0xC8)
++#define TCC_GPDCLR TCC_GPIOREG(0xCC)
++#define TCC_GPDXOR TCC_GPIOREG(0xD0)
++#define TCC_GPDCD0 TCC_GPIOREG(0xD4)
++#define TCC_GPDCD1 TCC_GPIOREG(0xD8)
++#define TCC_GPDPD0 TCC_GPIOREG(0xDC)
++#define TCC_GPDPD1 TCC_GPIOREG(0xE0)
++#define TCC_GPDFN0 TCC_GPIOREG(0xE4)
++#define TCC_GPDFN1 TCC_GPIOREG(0xE8)
++#define TCC_GPDFN2 TCC_GPIOREG(0xEC)
++#define TCC_GPDFN3 TCC_GPIOREG(0xF0)
++
++#define TCC_GPD0 TCC_GPIONO(TCC_GPIO_BANKD, 0)
++#define TCC_GPD0_GPIO (0)
++
++#define TCC_GPD1 TCC_GPIONO(TCC_GPIO_BANKD, 1)
++#define TCC_GPD1_GPIO (0)
++
++#define TCC_GPD2 TCC_GPIONO(TCC_GPIO_BANKD, 2)
++#define TCC_GPD2_GPIO (0)
++
++#define TCC_GPD3 TCC_GPIONO(TCC_GPIO_BANKD, 3)
++#define TCC_GPD3_GPIO (0)
++
++#define TCC_GPD4 TCC_GPIONO(TCC_GPIO_BANKD, 4)
++#define TCC_GPD4_GPIO (0)
++
++#define TCC_GPD5 TCC_GPIONO(TCC_GPIO_BANKD, 5)
++#define TCC_GPD5_GPIO (0)
++
++#define TCC_GPD6 TCC_GPIONO(TCC_GPIO_BANKD, 6)
++#define TCC_GPD6_GPIO (0)
++
++#define TCC_GPD7 TCC_GPIONO(TCC_GPIO_BANKD, 7)
++#define TCC_GPD7_GPIO (0)
++
++#define TCC_GPD8 TCC_GPIONO(TCC_GPIO_BANKD, 8)
++#define TCC_GPD8_GPIO (0)
++
++#define TCC_GPD9 TCC_GPIONO(TCC_GPIO_BANKD, 9)
++#define TCC_GPD9_GPIO (0)
++
++#define TCC_GPD10 TCC_GPIONO(TCC_GPIO_BANKD, 10)
++#define TCC_GPD10_GPIO (0)
++
++#define TCC_GPD11 TCC_GPIONO(TCC_GPIO_BANKD, 11)
++#define TCC_GPD11_GPIO (0)
++
++#define TCC_GPD12 TCC_GPIONO(TCC_GPIO_BANKD, 12)
++#define TCC_GPD12_GPIO (0)
++
++#define TCC_GPD13 TCC_GPIONO(TCC_GPIO_BANKD, 13)
++#define TCC_GPD13_GPIO (0)
++
++#define TCC_GPD14 TCC_GPIONO(TCC_GPIO_BANKD, 14)
++#define TCC_GPD14_GPIO (0)
++
++#define TCC_GPD15 TCC_GPIONO(TCC_GPIO_BANKD, 15)
++#define TCC_GPD15_GPIO (0)
++
++#define TCC_GPD16 TCC_GPIONO(TCC_GPIO_BANKD, 16)
++#define TCC_GPD16_GPIO (0)
++
++#define TCC_GPD17 TCC_GPIONO(TCC_GPIO_BANKD, 17)
++#define TCC_GPD17_GPIO (0)
++
++#define TCC_GPD18 TCC_GPIONO(TCC_GPIO_BANKD, 18)
++#define TCC_GPD18_GPIO (0)
++
++#define TCC_GPD19 TCC_GPIONO(TCC_GPIO_BANKD, 19)
++#define TCC_GPD19_GPIO (0)
++
++#define TCC_GPD20 TCC_GPIONO(TCC_GPIO_BANKD, 20)
++#define TCC_GPD20_GPIO (0)
++
++#define TCC_GPD21 TCC_GPIONO(TCC_GPIO_BANKD, 21)
++#define TCC_GPD21_GPIO (0)
++
++#define TCC_GPD22 TCC_GPIONO(TCC_GPIO_BANKD, 22)
++#define TCC_GPD22_GPIO (0)
++
++#define TCC_GPD23 TCC_GPIONO(TCC_GPIO_BANKD, 23)
++#define TCC_GPD23_GPIO (0)
++
++#define TCC_GPD24 TCC_GPIONO(TCC_GPIO_BANKD, 24)
++#define TCC_GPD24_GPIO (0)
++
++#define TCC_GPD25 TCC_GPIONO(TCC_GPIO_BANKD, 25)
++#define TCC_GPD25_GPIO (0)
++
++/* GPE : 32 in/out port */
++#define TCC_GPEDAT TCC_GPIOREG(0x100)
++#define TCC_GPEEN TCC_GPIOREG(0x104)
++#define TCC_GPESET TCC_GPIOREG(0x108)
++#define TCC_GPECLR TCC_GPIOREG(0x10C)
++#define TCC_GPEXOR TCC_GPIOREG(0x110)
++#define TCC_GPECD0 TCC_GPIOREG(0x114)
++#define TCC_GPECD1 TCC_GPIOREG(0x118)
++#define TCC_GPEPD0 TCC_GPIOREG(0x11C)
++#define TCC_GPEPD1 TCC_GPIOREG(0x120)
++#define TCC_GPEFN0 TCC_GPIOREG(0x124)
++#define TCC_GPEFN1 TCC_GPIOREG(0x128)
++#define TCC_GPEFN2 TCC_GPIOREG(0x12C)
++#define TCC_GPEFN3 TCC_GPIOREG(0x130)
++
++#define TCC_GPE0 TCC_GPIONO(TCC_GPIO_BANKE, 0)
++#define TCC_GPE0_GPIO (0)
++
++#define TCC_GPE1 TCC_GPIONO(TCC_GPIO_BANKE, 1)
++#define TCC_GPE1_GPIO (0)
++
++#define TCC_GPE2 TCC_GPIONO(TCC_GPIO_BANKE, 2)
++#define TCC_GPE2_GPIO (0)
++
++#define TCC_GPE3 TCC_GPIONO(TCC_GPIO_BANKE, 3)
++#define TCC_GPE3_GPIO (0)
++
++#define TCC_GPE4 TCC_GPIONO(TCC_GPIO_BANKE, 4)
++#define TCC_GPE4_GPIO (0)
++
++#define TCC_GPE5 TCC_GPIONO(TCC_GPIO_BANKE, 5)
++#define TCC_GPE5_GPIO (0)
++
++#define TCC_GPE6 TCC_GPIONO(TCC_GPIO_BANKE, 6)
++#define TCC_GPE6_GPIO (0)
++
++#define TCC_GPE7 TCC_GPIONO(TCC_GPIO_BANKE, 7)
++#define TCC_GPE7_GPIO (0)
++
++#define TCC_GPE8 TCC_GPIONO(TCC_GPIO_BANKE, 8)
++#define TCC_GPE8_GPIO (0)
++
++#define TCC_GPE9 TCC_GPIONO(TCC_GPIO_BANKE, 9)
++#define TCC_GPE9_GPIO (0)
++
++#define TCC_GPE10 TCC_GPIONO(TCC_GPIO_BANKE, 10)
++#define TCC_GPE10_GPIO (0)
++
++#define TCC_GPE11 TCC_GPIONO(TCC_GPIO_BANKE, 11)
++#define TCC_GPE11_GPIO (0)
++
++#define TCC_GPE12 TCC_GPIONO(TCC_GPIO_BANKE, 12)
++#define TCC_GPE12_GPIO (0)
++
++#define TCC_GPE13 TCC_GPIONO(TCC_GPIO_BANKE, 13)
++#define TCC_GPE13_GPIO (0)
++
++#define TCC_GPE14 TCC_GPIONO(TCC_GPIO_BANKE, 14)
++#define TCC_GPE14_GPIO (0)
++
++#define TCC_GPE15 TCC_GPIONO(TCC_GPIO_BANKE, 15)
++#define TCC_GPE15_GPIO (0)
++
++#define TCC_GPE16 TCC_GPIONO(TCC_GPIO_BANKE, 16)
++#define TCC_GPE16_GPIO (0)
++
++#define TCC_GPE17 TCC_GPIONO(TCC_GPIO_BANKE, 17)
++#define TCC_GPE17_GPIO (0)
++
++#define TCC_GPE18 TCC_GPIONO(TCC_GPIO_BANKE, 18)
++#define TCC_GPE18_GPIO (0)
++
++#define TCC_GPE19 TCC_GPIONO(TCC_GPIO_BANKE, 19)
++#define TCC_GPE19_GPIO (0)
++
++#define TCC_GPE20 TCC_GPIONO(TCC_GPIO_BANKE, 20)
++#define TCC_GPE20_GPIO (0)
++
++#define TCC_GPE21 TCC_GPIONO(TCC_GPIO_BANKE, 21)
++#define TCC_GPE21_GPIO (0)
++
++#define TCC_GPE22 TCC_GPIONO(TCC_GPIO_BANKE, 22)
++#define TCC_GPE22_GPIO (0)
++
++#define TCC_GPE23 TCC_GPIONO(TCC_GPIO_BANKE, 23)
++#define TCC_GPE23_GPIO (0)
++
++#define TCC_GPE24 TCC_GPIONO(TCC_GPIO_BANKE, 24)
++#define TCC_GPE24_GPIO (0)
++
++#define TCC_GPE25 TCC_GPIONO(TCC_GPIO_BANKE, 25)
++#define TCC_GPE25_GPIO (0)
++
++#define TCC_GPE26 TCC_GPIONO(TCC_GPIO_BANKE, 26)
++#define TCC_GPE26_GPIO (0)
++
++#define TCC_GPE27 TCC_GPIONO(TCC_GPIO_BANKE, 27)
++#define TCC_GPE27_GPIO (0)
++
++#define TCC_GPE28 TCC_GPIONO(TCC_GPIO_BANKE, 28)
++#define TCC_GPE28_GPIO (0)
++
++#define TCC_GPE29 TCC_GPIONO(TCC_GPIO_BANKE, 29)
++#define TCC_GPE29_GPIO (0)
++
++#define TCC_GPE30 TCC_GPIONO(TCC_GPIO_BANKE, 30)
++#define TCC_GPE30_GPIO (0)
++
++#define TCC_GPE31 TCC_GPIONO(TCC_GPIO_BANKE, 31)
++#define TCC_GPE31_GPIO (0)
++
++/* GPF : 32 in/out port */
++#define TCC_GPFDAT TCC_GPIOREG(0x140)
++#define TCC_GPFEN TCC_GPIOREG(0x144)
++#define TCC_GPFSET TCC_GPIOREG(0x148)
++#define TCC_GPFCLR TCC_GPIOREG(0x14C)
++#define TCC_GPFXOR TCC_GPIOREG(0x150)
++#define TCC_GPFCD0 TCC_GPIOREG(0x154)
++#define TCC_GPFCD1 TCC_GPIOREG(0x158)
++#define TCC_GPFPD0 TCC_GPIOREG(0x15C)
++#define TCC_GPFPD1 TCC_GPIOREG(0x160)
++#define TCC_GPFFN0 TCC_GPIOREG(0x164)
++#define TCC_GPFFN1 TCC_GPIOREG(0x168)
++#define TCC_GPFFN2 TCC_GPIOREG(0x16C)
++#define TCC_GPFFN3 TCC_GPIOREG(0x170)
++
++#define TCC_GPF0 TCC_GPIONO(TCC_GPIO_BANKF, 0)
++#define TCC_GPF0_GPIO (0)
++
++#define TCC_GPF1 TCC_GPIONO(TCC_GPIO_BANKF, 1)
++#define TCC_GPF1_GPIO (0)
++
++#define TCC_GPF2 TCC_GPIONO(TCC_GPIO_BANKF, 2)
++#define TCC_GPF2_GPIO (0)
++
++#define TCC_GPF3 TCC_GPIONO(TCC_GPIO_BANKF, 3)
++#define TCC_GPF3_GPIO (0)
++
++#define TCC_GPF4 TCC_GPIONO(TCC_GPIO_BANKF, 4)
++#define TCC_GPF4_GPIO (0)
++
++#define TCC_GPF5 TCC_GPIONO(TCC_GPIO_BANKF, 5)
++#define TCC_GPF5_GPIO (0)
++
++#define TCC_GPF6 TCC_GPIONO(TCC_GPIO_BANKF, 6)
++#define TCC_GPF6_GPIO (0)
++
++#define TCC_GPF7 TCC_GPIONO(TCC_GPIO_BANKF, 7)
++#define TCC_GPF7_GPIO (0)
++
++#define TCC_GPF8 TCC_GPIONO(TCC_GPIO_BANKF, 8)
++#define TCC_GPF8_GPIO (0)
++
++#define TCC_GPF9 TCC_GPIONO(TCC_GPIO_BANKF, 9)
++#define TCC_GPF9_GPIO (0)
++
++#define TCC_GPF10 TCC_GPIONO(TCC_GPIO_BANKF, 10)
++#define TCC_GPF10_GPIO (0)
++
++#define TCC_GPF11 TCC_GPIONO(TCC_GPIO_BANKF, 11)
++#define TCC_GPF11_GPIO (0)
++
++#define TCC_GPF12 TCC_GPIONO(TCC_GPIO_BANKF, 12)
++#define TCC_GPF12_GPIO (0)
++
++#define TCC_GPF13 TCC_GPIONO(TCC_GPIO_BANKF, 13)
++#define TCC_GPF13_GPIO (0)
++
++#define TCC_GPF14 TCC_GPIONO(TCC_GPIO_BANKF, 14)
++#define TCC_GPF14_GPIO (0)
++
++#define TCC_GPF15 TCC_GPIONO(TCC_GPIO_BANKF, 15)
++#define TCC_GPF15_GPIO (0)
++
++#define TCC_GPF16 TCC_GPIONO(TCC_GPIO_BANKF, 16)
++#define TCC_GPF16_GPIO (0)
++
++#define TCC_GPF17 TCC_GPIONO(TCC_GPIO_BANKF, 17)
++#define TCC_GPF17_GPIO (0)
++
++#define TCC_GPF18 TCC_GPIONO(TCC_GPIO_BANKF, 18)
++#define TCC_GPF18_GPIO (0)
++
++#define TCC_GPF19 TCC_GPIONO(TCC_GPIO_BANKF, 19)
++#define TCC_GPF19_GPIO (0)
++
++#define TCC_GPF20 TCC_GPIONO(TCC_GPIO_BANKF, 20)
++#define TCC_GPF20_GPIO (0)
++
++#define TCC_GPF21 TCC_GPIONO(TCC_GPIO_BANKF, 21)
++#define TCC_GPF21_GPIO (0)
++
++#define TCC_GPF22 TCC_GPIONO(TCC_GPIO_BANKF, 22)
++#define TCC_GPF22_GPIO (0)
++
++#define TCC_GPF23 TCC_GPIONO(TCC_GPIO_BANKF, 23)
++#define TCC_GPF23_GPIO (0)
++
++#define TCC_GPF24 TCC_GPIONO(TCC_GPIO_BANKF, 24)
++#define TCC_GPF24_GPIO (0)
++
++#define TCC_GPF25 TCC_GPIONO(TCC_GPIO_BANKF, 25)
++#define TCC_GPF25_GPIO (0)
++
++#define TCC_GPF26 TCC_GPIONO(TCC_GPIO_BANKF, 26)
++#define TCC_GPF26_GPIO (0)
++
++#define TCC_GPF27 TCC_GPIONO(TCC_GPIO_BANKF, 27)
++#define TCC_GPF27_GPIO (0)
++
++#define gpio_set_pin(gpio, function) tcc_gpio_cfgpin(gpio, function, 0)
++#define gpio_get_pin(gpio) tcc_gpio_getcfg(gpio)
++#define gpio_pullup(gpio, to) tcc_gpio_pullup(gpio, to)
++#define gpio_get_value(gpio) tcc_gpio_getpin(gpio)
++#define gpio_set_value(gpio, value) tcc_gpio_setpin(gpio, value)
++#define gpio_direction_input(gpio) tcc_gpio_direction_input(gpio)
++#define gpio_direction_output(gpio, value) tcc_gpio_direction_output(gpio, value)
++
++extern void tcc_gpio_cfgpin(unsigned int pin, unsigned int function, unsigned int out);
++extern unsigned int tcc_gpio_getcfg(unsigned int pin);
++extern void tcc_gpio_pullup(unsigned int pin, unsigned int to);
++extern void tcc_gpio_setpin(unsigned int pin, unsigned int to);
++extern unsigned int tcc_gpio_getpin(unsigned int pin);
++extern int tcc_gpio_direction_input(unsigned int gpio);
++extern int tcc_gpio_direction_output(unsigned int gpio, int value);
++
++#if 0
++static inline int gpio_request(unsigned int gpio, const char *label)
++{
++ return 0;
++}
++
++static inline void gpio_free(unsigned int gpio)
++{
++ return;
++}
++#else// XXX: mhfan
++#define gpio_request(...) (0)
++#define gpio_free(...)
++#endif
++
++#include <asm-generic/gpio.h>
+diff --git a/arch/arm/mach-tcc8900/include/mach/hardware.h b/arch/arm/mach-tcc8900/include/mach/hardware.h
+new file mode 100644
+index 0000000..d30ef32
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/hardware.h
+@@ -0,0 +1,65 @@
++/*
++ * linux/include/asm-arm/arch-tcc8900/hardware.h
++ *
++ * Rewritten by: <linux@telechips.com>
++ * Modifiedd: June 10, 2008
++ * Description: Hardware definitions for TCC8900 processors and boards
++ * Author: RidgeRun, Inc. Greg Lonnon <glonnon@ridgerun.com>
++ * Reorganized for Linux-2.6 by Tony Lindgren <tony@atomide.com>
++ * and Dirk Behme <dirk.behme@de.bosch.com>
++ *
++ * Copyright (C) 2001 RidgeRun, Inc.
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * NOTE: Please put device driver specific defines into a separate header
++ * file for each driver.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef __ASM_ARCH_TCC8900_HARDWARE_H
++#define __ASM_ARCH_TCC8900_HARDWARE_H
++
++#include <asm/sizes.h>
++#ifndef __ASSEMBLER__
++#include <asm/types.h>
++#endif
++#include <mach/io.h>
++
++/*
++ * ----------------------------------------------------------------------------
++ * Clocks
++ * ----------------------------------------------------------------------------
++ */
++#define CLKGEN_REG_BASE (0xfffece00)
++#define ARM_CKCTL (CLKGEN_REG_BASE + 0x0)
++#define ARM_IDLECT1 (CLKGEN_REG_BASE + 0x4)
++#define ARM_IDLECT2 (CLKGEN_REG_BASE + 0x8)
++#define ARM_EWUPCT (CLKGEN_REG_BASE + 0xC)
++#define ARM_RSTCT1 (CLKGEN_REG_BASE + 0x10)
++#define ARM_RSTCT2 (CLKGEN_REG_BASE + 0x14)
++#define ARM_SYSST (CLKGEN_REG_BASE + 0x18)
++#define ARM_IDLECT3 (CLKGEN_REG_BASE + 0x24)
++
++/* DPLL control registers */
++#define DPLL_CTL (0xfffecf00)
++
++#endif /* __ASM_ARCH_TCC8900_HARDWARE_H */
+diff --git a/arch/arm/mach-tcc8900/include/mach/io.h b/arch/arm/mach-tcc8900/include/mach/io.h
+new file mode 100644
+index 0000000..4592fa9
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/io.h
+@@ -0,0 +1,73 @@
++/*
++ * linux/include/asm-arm/arch-tcc89x/io.h
++ *
++ * Based on: linux/include/asm-arm/arch-sa1100/io.h
++ * Author : <linux@telechips.com>
++ * Description: IO definitions for TCC8900 processors and boards
++ *
++ * Copyright (C) 1997-1999 Russell King
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef __ASM_ARM_ARCH_IO_H__
++#define __ASM_ARM_ARCH_IO_H__
++
++#include <mach/hardware.h>
++
++#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) ((void __iomem *)(PCIO_BASE + (a)))
++#define __mem_pci(a) (a)
++
++/*
++ * ----------------------------------------------------------------------------
++ * I/O mapping
++ * ----------------------------------------------------------------------------
++ */
++#define PCIO_BASE 0
++
++#define IO_PHYS 0xF0000000
++#define IO_OFFSET 0x00000000 /* Virtual IO = 0xf0000000 */
++#define IO_SIZE 0x100000
++#define IO_VIRT (IO_PHYS - IO_OFFSET)
++#define IO_ADDRESS(pa) ((pa) - IO_OFFSET)
++#define io_p2v(pa) ((pa) - IO_OFFSET)
++#define io_v2p(va) ((va) + IO_OFFSET)
++
++/* Physical value to Virtual Address */
++#define tcc_p2v(pa) ((unsigned int)(&pa) - IO_OFFSET)
++
++#define tcc_readb(a) (*(volatile unsigned char *)IO_ADDRESS(a))
++#define tcc_readw(a) (*(volatile unsigned short *)IO_ADDRESS(a))
++#define tcc_readl(a) (*(volatile unsigned int *)IO_ADDRESS(a))
++
++#define tcc_writeb(v,a) (*(volatile unsigned char *)IO_ADDRESS(a) = (v))
++#define tcc_writew(v,a) (*(volatile unsigned short *)IO_ADDRESS(a) = (v))
++#define tcc_writel(v,a) (*(volatile unsigned int *)IO_ADDRESS(a) = (v))
++
++#endif /*__ASM_ARM_ARCH_IO_H__*/
+diff --git a/arch/arm/mach-tcc8900/include/mach/ioctl_ckcstr.h b/arch/arm/mach-tcc8900/include/mach/ioctl_ckcstr.h
+new file mode 100644
+index 0000000..b521130
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/ioctl_ckcstr.h
+@@ -0,0 +1,86 @@
++/****************************************************************************
++ * FileName : ioctl_ckcstr.h
++ * Description :
++ ****************************************************************************
++*
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++*
++ ****************************************************************************/
++
++
++/************************************************************************************************
++* Revision History *
++* *
++* Version : 1.0 : 2009, 2, 04 *
++************************************************************************************************/
++
++#ifndef __IOCTL_STR_H__
++#define __IOCTL_STR_H__
++
++
++//#include "bsp.h"
++
++
++// For CKC Controller
++typedef struct _stckcioctl{
++ unsigned int ioctlcode;
++ //Reset or bus Enable name
++ unsigned int prbname;
++ //Peri Clock
++ unsigned int pckcname;
++ unsigned int pckcenable;
++ unsigned int pckcsource;
++ unsigned int pckcfreq;
++ //PLL Cllock
++ unsigned int pllchannel;
++ unsigned int pllvalue;
++ unsigned int P;
++ unsigned int M;
++ unsigned int S;
++ //CPU Cllock
++ unsigned int cpuvalue;
++ //BUS Cllock
++ unsigned int busvalue;
++ //mode
++ unsigned int mode; // Enable, Disable, ahalf, athird
++
++ unsigned int priority;
++
++ unsigned int cpudivider;
++ unsigned int pmuoffname;
++
++ unsigned int bspmax;
++ //Fbus Clock
++ unsigned int fbusname;
++ unsigned int fbusenable;
++ unsigned int fbussource;
++ unsigned int fbusfreq;
++
++ //DDI PWDN
++ unsigned int ddipdname;
++
++ //ETC Block
++ unsigned int etcblock;
++
++
++}stckcioctl;
++
++
++typedef struct _stckcinfo{
++ unsigned int currentbusfreq;
++ unsigned int currentsysfreq;
++ unsigned int currentcpufreq;
++ int pckcfreq; //return etc frequency
++ unsigned int validpll[30];
++ int retVal;
++ unsigned int currentpriority;
++
++ unsigned int state;
++
++ int fbusfreq;
++
++}stckcinfo;
++
++#endif /* __IOCTL_STR_H__ */
+diff --git a/arch/arm/mach-tcc8900/include/mach/irqs.h b/arch/arm/mach-tcc8900/include/mach/irqs.h
+new file mode 100644
+index 0000000..82efdaf
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/irqs.h
+@@ -0,0 +1,158 @@
++/* linux/include/asm-arm/arch-tcc8900/irqs.h
++ *
++ * Author: <linux@telechips.com>
++ * Created: Mach 10, 2009
++ * Copyright (C) 2009- Telechips
++ *
++ * 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
++ */
++
++#ifndef __ASM_ARCH_TCC_IRQS_H
++#define __ASM_ARCH_TCC_IRQS_H
++
++/*
++ * IRQ numbers for interrupt handler
++ */
++
++#define INT_TC0 0
++#define INT_TC1 1
++#define INT_SMUI2C 2
++#define INT_EI0 3
++#define INT_EI1 4
++#define INT_EI2 5
++#define INT_EI3 6
++#define INT_EI4 7
++#define INT_EI5 8
++#define INT_EI6 9
++#define INT_EI7 10
++#define INT_EI8 11
++#define INT_EI9 12
++#define INT_EI10 13
++#define INT_EI11 14
++#define INT_SC0 15
++#define INT_SC1 16
++#define INT_CAM 17
++#define INT_LCD0 18
++#define INT_LCD1 19
++#define INT_VIPET 20
++#define INT_JPGE 21
++#define INT_JPGD 22
++#define INT_VCDC 23
++#define INT_3DPP 24
++#define INT_3DGP 25
++#define INT_3DMMU 26
++#define INT_G2D 27
++#define INT_TSADC 28
++#define INT_DMA 29
++#define INT_ECC 30
++#define INT_EHI0 31
++#define INT_EHI1 32
++#define INT_CAN 33
++#define INT_HDMI 34
++#define INT_SATA 35
++#define INT_GPSB 36
++#define INT_HDD 37
++#define INT_I2C 38
++#define INT_MPEFEC 39
++#define INT_MS 40
++#define INT_NFC 41
++#define INT_RMT 42
++#define INT_RTC 43
++#define INT_SD0 44
++#define INT_SD1 45
++#define INT_SPDTX 46
++#define INT_UART 47
++#define INT_UOTG 48
++#define INT_U11H 49
++#define INT_GPS0 50
++#define INT_GPS1 51
++#define INT_GPS2 52
++#define INT_TSIF0 53
++#define INT_TSIF1 54
++#define INT_CDRX 55
++#define INT_DAIRX 56
++#define INT_DAITX 57
++#define INT_ADMA 58
++#define INT_AUDIO 59
++#define INT_APMU 60
++#define INT_AIRQ 61
++#define INT_ASIRQ 62
++#define INT_AEIRQ 63
++
++/*
++ * IRQ_UT numbers for UART[0:5]
++ */
++#define INT_UT_BASE 64
++#define INT_UART0 (0 + INT_UT_BASE)
++#define INT_UART1 (1 + INT_UT_BASE)
++#define INT_UART2 (2 + INT_UT_BASE)
++#define INT_UART3 (3 + INT_UT_BASE)
++#define INT_UART4 (4 + INT_UT_BASE)
++#define INT_UART5 (5 + INT_UT_BASE)
++
++/*
++ * GPSB-IRQ numbers for GPSB0 & GPSB0
++ */
++#define INT_GPSB0_BASE 70
++#define INT_GPSB0_DMA (0 + INT_GPSB0_BASE)
++#define INT_GPSB1_DMA (1 + INT_GPSB0_BASE)
++#define INT_GPSB2_DMA (2 + INT_GPSB0_BASE)
++
++#define INT_GPSB0_CORE (3 + INT_GPSB0_BASE)
++#define INT_GPSB1_CORE (4 + INT_GPSB0_BASE)
++#define INT_GPSB2_CORE (5 + INT_GPSB0_BASE)
++#define INT_GPSB3_CORE (6 + INT_GPSB0_BASE)
++#define INT_GPSB4_CORE (7 + INT_GPSB0_BASE)
++#define INT_GPSB5_CORE (8 + INT_GPSB0_BASE)
++
++/*
++ * DMA-IRQ numbers
++ */
++#define INT_DMA0_BASE 79
++#define INT_DMA0_CH0 (0 + INT_DMA0_BASE)
++#define INT_DMA0_CH1 (1 + INT_DMA0_BASE)
++#define INT_DMA0_CH2 (2 + INT_DMA0_BASE)
++#define INT_DMA1_CH0 (3 + INT_DMA0_BASE)
++#define INT_DMA1_CH1 (4 + INT_DMA0_BASE)
++#define INT_DMA1_CH2 (5 + INT_DMA0_BASE)
++#define INT_DMA2_CH0 (6 + INT_DMA0_BASE)
++#define INT_DMA2_CH1 (7 + INT_DMA0_BASE)
++#define INT_DMA2_CH2 (8 + INT_DMA0_BASE)
++#define INT_DMA3_CH0 (9 + INT_DMA0_BASE)
++#define INT_DMA3_CH1 (10 + INT_DMA0_BASE)
++#define INT_DMA3_CH2 (11 + INT_DMA0_BASE)
++
++/*
++ * TC0-IRQ numbers for Timer/Counter 0~5
++ */
++#define INT_TC0_BASE 91
++#define INT_TC0_TI0 (0 + INT_TC0_BASE)
++#define INT_TC0_TI1 (1 + INT_TC0_BASE)
++#define INT_TC0_TI2 (2 + INT_TC0_BASE)
++#define INT_TC0_TI3 (3 + INT_TC0_BASE)
++#define INT_TC0_TI4 (4 + INT_TC0_BASE)
++#define INT_TC0_TI5 (5 + INT_TC0_BASE)
++
++/*
++ * NR_IRQ:
++ */
++#define NR_IRQS ((INT_AEIRQ + 1)\
++ + (INT_UART5 - INT_UT_BASE + 1)\
++ + (INT_GPSB5_CORE - INT_GPSB0_BASE + 1)\
++ + (INT_DMA3_CH2 - INT_DMA0_BASE + 1)\
++ + (INT_TC0_TI5 - INT_TC0_BASE + 1))
++
++#endif /* ASM_ARCH_TCC_IRQS_H */
++
+diff --git a/arch/arm/mach-tcc8900/include/mach/memory.h b/arch/arm/mach-tcc8900/include/mach/memory.h
+new file mode 100644
+index 0000000..f6a3713
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/memory.h
+@@ -0,0 +1,106 @@
++/*
++ * linux/include/asm-arm/arch-tcc8900/memory.h
++ *
++ * Based on: linux/include/asm-arm/arch-intergrator/memory.h
++ * Author: Greg Lonnon <glonnon@ridgerun.com>
++ * Rewritten by: <linux@telechips.com>
++ * Modified: Feb 10, 2009
++ * Description: Memory map for TCC8900
++ *
++ * Copyright (C) 1999 ARM Limited
++ * Copyright (C) 2000 RidgeRun, Inc.
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef __ASM_ARCH_MEMORY_H
++#define __ASM_ARCH_MEMORY_H
++
++/*
++ * Physical DRAM offset.
++ */
++#define PHYS_OFFSET UL(0x40200000)
++
++/*
++ * Free Mem Size
++ * mem=[size]
++ * size = Total RAM size - Total Reserved RAM size
++ * Total RAM size = CONFIG_RAM_XXXMB
++ * Totla Reserved RAM size = FB reserved size + Video Codec reserved size
++ */
++#define CAL_VPU_OFFSET(ram_size, vpu_size) ( (0x40000000+ram_size) - (vpu_size*1024*1024) )
++#if defined(CONFIG_RAM_128MB)
++ #define TCC_RAM_TOTAL_SIZE 0x08000000
++
++ #if defined(CONFIG_HD720p_LEVEL41)
++ #define TCC_MEM_SIZE " mem=86M"
++ #elif defined(CONFIG_HD720p_LEVEL51)
++ #define TCC_MEM_SIZE " mem=60M"
++ #elif defined(CONFIG_HD1080p_LEVEL41)
++ #define TCC_MEM_SIZE " mem=66M"
++ #elif defined(CONFIG_HD1080p_LEVEL51)
++ #error "[not support HD1080p_LEVEL51] Check menuconfig->System Type->A/V Spec"
++ #else
++ #error "[undefine A/V spec] Check menuconfig->System Type->A/V Spec"
++ #endif
++
++
++#elif defined(CONFIG_RAM_256MB)
++ #define TCC_RAM_TOTAL_SIZE 0x10000000
++
++ #if defined(CONFIG_HD720p_LEVEL41)
++ #define TCC_MEM_SIZE " mem=214M"
++ #elif defined(CONFIG_HD720p_LEVEL51)
++ #define TCC_MEM_SIZE " mem=188M"
++ #elif defined(CONFIG_HD1080p_LEVEL41)
++ #define TCC_MEM_SIZE " mem=194M"
++ #elif defined(CONFIG_HD1080p_LEVEL51)
++ #define TCC_MEM_SIZE " mem=138M"
++ #else
++ #error "[undefine A/V spec] Check menuconfig->System Type->A/V Spec"
++ #endif
++
++#else
++ #error "[undefine MEM size] Check menuconfig->System Type->RAM Spec"
++#endif
++
++/*
++ * Frame buffer memory define
++ */
++#define TCC_FB0_SIZE (8*1024*1024) // 8MB
++#define TCC_FB1_SIZE (4*1024*1024) // 4MB
++#define TCC_FB2_SIZE (4*1024*1024) // 4MB
++
++/*
++ * Size of DMA-consistent memory region. Must be multiple of 2M,
++ * between 2MB and 14MB inclusive.
++ */
++#ifndef CONSISTENT_DMA_SIZE
++#define CONSISTENT_DMA_SIZE (SZ_2M)
++#endif
++
++
++#define __virt_to_bus(x) __virt_to_phys(x)
++#define __bus_to_virt(x) __phys_to_virt(x)
++
++#endif
++
+diff --git a/arch/arm/mach-tcc8900/include/mach/ohci.h b/arch/arm/mach-tcc8900/include/mach/ohci.h
+new file mode 100644
+index 0000000..6ec9451
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/ohci.h
+@@ -0,0 +1,241 @@
++/*
++ * linux/include/asm-arm/arch-tcc79x/ohci.h
++ *
++ * Author: <linux@telechips.com>
++ * Created: June 10, 2008
++ * Description: ohci definition for TCC79x
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#ifndef ASMARM_ARCH_OHCI_H
++#define ASMARM_ARCH_OHCI_H
++
++
++// fields and bits for uhcrev: HCI Spec Revision
++#define USBOHCI_UHCREV_OHCISPEC1_0_A 0x10
++
++// fields and bits for uhchcon: Control register
++#define USBOHCI_UHCCON_CBSR_MASK ( 0x3u << 0 )
++
++#define USBOHCI_UHCCON_CBSR_PLE ( 2u << 2 )
++#define USBOHCI_UHCCON_CBSR_IE ( 3u << 2 )
++#define USBOHCI_UHCCON_CBSR_CLE ( 4u << 2 )
++#define USBOHCI_UHCCON_CBSR_BLE ( 5u << 2 )
++
++#define USBOHCI_UHCCON_HCFS_MASK ( 0x3u << 6 )
++
++#define USBOHCI_UHCCON_CBSR_IR ( 8u << 2 )
++#define USBOHCI_UHCCON_CBSR_RWC ( 9u << 2 )
++#define USBOHCI_UHCCON_CBSR_RWE ( 10u << 2 )
++
++// for the HCFS field
++#define USBOHCI_UHCCON_HCFS_USBRESET ( 0u << 6 )
++#define USBOHCI_UHCCON_HCFS_USBRESUME ( 1u << 6 )
++#define USBOHCI_UHCCON_HCFS_USBOPERATIONAL ( 2u << 6 )
++#define USBOHCI_UHCCON_HCFS_USBSUSPEND ( 3u << 6 )
++
++
++// fields and bits for uhccoms: Command Status
++#define USBOHCI_UHCCOMS_HCR ( 1u << 0)
++#define USBOHCI_UHCCOMS_CLF ( 1u << 1 )
++#define USBOHCI_UHCCOMS_BLF ( 1u << 2 )
++#define USBOHCI_UHCCOMS_OCR ( 1u << 3 )
++
++#define USBOHCI_UHCCOMS_SOC_MASK ( 0x3u << 16 )
++
++
++
++// fields and bits for uhcints: Interrupt Status
++// fields and bits for uhcinte: Interrupt Enable Control register
++// fields and bits for uhcintd: Interrupt Disable Control register
++#define USBOHCI_UHCINT_SO ( 1u << 0 )
++#define USBOHCI_UHCINT_WDH ( 1u << 1 )
++#define USBOHCI_UHCINT_SF ( 1u << 2 )
++#define USBOHCI_UHCINT_RD ( 1u << 3 )
++#define USBOHCI_UHCINT_UE ( 1u << 4 )
++#define USBOHCI_UHCINT_FNO ( 1u << 5 )
++#define USBOHCI_UHCINT_RHSC ( 1u << 6 )
++#define USBOHCI_UHCINT_OC ( 1u << 30 )
++#define USBOHCI_UHCINT_MIE ( 1u << 31 )
++
++// fields and bits for uhchcca: Host controller Communication Area
++#define USBOHCI_UHCHCCA_MASK ( 0xfffffffu << 8 )
++
++// fields and bits for uhcpced: Period Current Endpoint Descriptor
++#define USBOHCI_UHCPCED_MASK ( 0xffffffffu << 4 )
++
++// fields and bits for uhcched: Control Head Endpoint Descriptor register
++#define USBOHCI_UHCCHED_MASK ( 0xffffffffu << 4 )
++
++// fields and bits for uhccced: Control Current Endpoint Descriptor register
++#define USBOHCI_UHCCCED_MASK ( 0xffffffffu << 4 )
++
++// fields and bits for uhcbhed: Bulk Head Endpoint Descriptor register
++#define USBOHCI_UHCBHED_MASK ( 0xffffffffu << 4 )
++
++// fields and bits for uhcbced: Bulk Current Endpoint Descriptor register
++#define USBOHCI_UHCBCED_MASK ( 0xffffffffu << 4 )
++
++// fields and bits for uhcdhead: Done head register
++#define USBOHCI_UHCDHED_MASK ( 0xffffffffu << 4 ) // should be "DHTD" because its a transfer descriptor
++
++// fields and bits for uhcfmi: Frame Interval register
++#define USBOHCI_UHCFMI_FI_MASK ( 0x3fffu << 0 )
++#define USBOHCI_UHCFMI_FSMPS_MASK ( 0x7fffu << 16 )
++#define USBOHCI_UHCFMI_FIT ( 1u << 31 )
++
++// fields and bits for uhcfmr: Frame Remaining register
++#define USBOHCI_UHCFMR_FR_MASK ( 0x3fffu << 0 )
++#define USBOHCI_UHCFMI_FRT ( 1u << 31 )
++
++// fields and bits for uhcfmn: Frame Number register
++#define USBOHCI_UHCFMN_FN_MASK ( 0xffffu << 0 )
++
++// fields and bits for uhcpers: Periodic Start register
++#define USBOHCI_UHCPERS_PS_MASK ( 0x3fffu << 0 )
++
++// fields and bits for uhclst: Low Speed Threshold register
++#define USBOHCI_UHCPLST_LST_MASK ( 0xfffu << 0 )
++
++// fields and bits for uhcrhda: Root Hub Descriptor A register
++#define USBOHCI_UHCRHDA_NDP_MASK ( 0xffu << 0 )
++
++#define USBOHCI_UHCRHDA_PSM ( 1u << 8 )
++#define USBOHCI_UHCRHDA_NPS ( 1u << 9 )
++#define USBOHCI_UHCRHDA_DT ( 1u << 10 )
++#define USBOHCI_UHCRHDA_OCPM ( 1u << 11 )
++#define USBOHCI_UHCRHDA_NOCP ( 1u << 12 )
++
++#define USBOHCI_UHCRHDA_POTPGT_MASK ( 0xffu << 24 )
++
++// fields and bits for uhcrhdb: Root Hub Descriptor B register
++#define USBOHCI_UHCRHDB_DR_MASK ( 0xffffu << 0 )
++#define USBOHCI_UHCRHDB_PPCM_MASK ( 0xffffu << 16 )
++
++// fields and bits for uhcrhs: Root Hub Status register
++#define USBOHCI_UHCRHS_LPS ( 1u << 0 ) // meaning on read
++#define USBOHCI_UHCRHS_CGP ( 1u << 0 ) // meaining on write
++#define USBOHCI_UHCRHS_OCI ( 1u << 1 )
++#define USBOHCI_UHCRHS_DRWE ( 1u << 15 ) // meaning on read
++#define USBOHCI_UHCRHS_SRWE ( 1u << 15 ) // meaning on write
++#define USBOHCI_UHCRHS_LPSC ( 1u << 16 ) // meaning on read
++#define USBOHCI_UHCRHS_SGP ( 1u << 16 ) // meaning on write
++#define USBOHCI_UHCRHS_OCIC ( 1u << 17 )
++#define USBOHCI_UHCRHS_CRWE ( 1u << 31 )
++
++// fields and bits for uhcrhps1: Root Hub Port 1 Status register
++// fields and bits for uhcrhps2: Root Hub Port 2 Status register
++#define USBOHCI_UHCRHPS_CCS ( 1u << 0 )
++#define USBOHCI_UHCRHPS_PES ( 1u << 1 )
++#define USBOHCI_UHCRHPS_PSS ( 1u << 2 )
++#define USBOHCI_UHCRHPS_POCI ( 1u << 3 )
++#define USBOHCI_UHCRHPS_PRS ( 1u << 4 )
++#define USBOHCI_UHCRHPS_PPS ( 1u << 8 )
++#define USBOHCI_UHCRHPS_LSDA ( 1u << 9 ) // meaning on read
++#define USBOHCI_UHCRHPS_CPP ( 1u << 9 ) // meaning on write
++#define USBOHCI_UHCRHPS_CSC ( 1u << 16 )
++#define USBOHCI_UHCRHPS_PESC ( 1u << 17 )
++#define USBOHCI_UHCRHPS_PSSC ( 1u << 18 )
++#define USBOHCI_UHCRHPS_POCIC ( 1u << 19 )
++#define USBOHCI_UHCRHPS_PRSC ( 1u << 20 )
++
++// fields and bits for uhcstat: USB Host Status
++#define USBOHCI_UHCSTAT_RWUE ( 1u << 7 )
++#define USBOHCI_UHCSTAT_HBA ( 1u << 8 )
++#define USBOHCI_UHCSTAT_HTA ( 1u << 10 )
++#define USBOHCI_UHCSTAT_UPS1 ( 1u << 11 )
++#define USBOHCI_UHCSTAT_UPS2 ( 1u << 12 )
++#define USBOHCI_UHCSTAT_UPRI ( 1u << 13 )
++#define USBOHCI_UHCSTAT_SBTAI ( 1u << 14 )
++#define USBOHCI_UHCSTAT_SBMAI ( 1u << 15 )
++
++// fields and bits for uhchr: USB Host Reset
++// UHCHR host reset register bit positions
++#define USBOHCI_UHCHR_SSEP1 ( 1u << 10) // Sleep Standby Enable: enable/disable port1 SE receivers & power supply
++#define USBOHCI_UHCHR_SSEP0 ( 1u << 9) // Sleep Standby Enable: enable/disable port1 SE receivers & power supply
++#define USBOHCI_UHCHR_PCPL ( 1u << 7) // Power CONTROL Polarity: Control polarity of Power Enable signals output to the MAX1693EUB USB Power Switch
++#define USBOHCI_UHCHR_PSPL ( 1u << 6) // Power SENSE Polarity: Control polarity of Over-current Indicator signals input from the MAX1693EUB USB Power Switch
++#define USBOHCI_UHCHR_SSE ( 1u << 5) // Sleep Standby Enable: enable/disable both ports SE receivers & power supply
++#define USBOHCI_UHCHR_UIT ( 1u << 4) // USB Interrupt Test: Enable Interrupt Test Mode and UHCHIT register
++#define USBOHCI_UHCHR_SSDC ( 1u << 3) // Simulation Scale Down Clock: When 1, internal 1 mSec timer changes to 1 uSec to speed up simulations
++#define USBOHCI_UHCHR_CGR ( 1u << 2) // Clock Generation Reset: When 0, resets the OHCI Clock Generation block (DPLL). Used only in simulation
++#define USBOHCI_UHCHR_FHR ( 1u << 1) // Force Host controller Reset: When 1, resets OHCI core. Must be held high for 10 uSeconds, then cleared
++#define USBOHCI_UHCHR_FSBIR ( 1u << 0) // Force System Bus Interface Reset: When 1, resets the logic that interfaces to the system bus, DMA, etc. Auto clears after three system bus clocks.
++
++// fields and bits for uhchie: USB Host Interrupt Enable
++#define USBOHCI_UHCIE_RWIE ( 1u << 7 )
++#define USBOHCI_UHCIE_HBAIE ( 1u << 8 )
++#define USBOHCI_UHCIE_TAIE ( 1u << 10 )
++#define USBOHCI_UHCIE_UPS1IE ( 1u << 11 )
++#define USBOHCI_UHCIE_UPS2IE ( 1u << 12 )
++#define USBOHCI_UHCIE_UPRIE ( 1u << 13 )
++
++
++// fields and bits for uhchit: USB Host Interrupt Test
++#define USBOHCI_UHCIT_RWIT ( 1u << 7 )
++#define USBOHCI_UHCIT_BAT ( 1u << 8 )
++#define USBOHCI_UHCIT_IRQT ( 1u << 9 )
++#define USBOHCI_UHCIT_TAT ( 1u << 10 )
++#define USBOHCI_UHCIT_UPS1T ( 1u << 11 )
++#define USBOHCI_UHCIT_UPS2T ( 1u << 12 )
++#define USBOHCI_UHCIT_UPRT ( 1u << 13 )
++#define USBOHCI_UHCIT_STAT ( 1u << 14 )
++#define USBOHCI_UHCIT_SMAT ( 1u << 15 )
++
++
++
++// root hub descriptor A information
++#define USBOHCI_UHCRHDA_PSM_PERPORT 1
++
++
++#define INT_CTRL_BASE 0xF3001000
++#define IEN_REG_OFFSET 0x0
++#define CLR_REG_OFFSET 0x4
++#define SEL_REG_OFFSET 0xC
++#define POL_REG_OFFSET 0x1C
++
++#define CLK_CTRL_BASE 0xF3000000
++#define BCLK_CTRL_OFFSET 0x18
++#define SWRESET_CTRL_OFFSET 0x1C
++
++#define HwBCLK *(volatile unsigned long *)(CLK_CTRL_BASE+BCLK_CTRL_OFFSET)
++
++#define IO_CKC_BUS_UBH 0x00000001
++#define IO_CKC_BUS_UBD 0x00000002
++
++
++
++struct device;
++
++struct tccohci_platform_data {
++ int (*init)(struct device *);
++ void (*exit)(struct device *);
++
++ int port_mode;
++#define USBOHCI_PPM_NPS 1
++#define USBOHCI_PPM_GLOBAL 2
++#define USBOHCI_PPM_PERPORT 3
++#define USBOHCI_PPM_MIXED 4
++
++ int power_budget;
++};
++
++extern void tcc_set_ohci_info(struct tccohci_platform_data *info);
++
++#endif
+diff --git a/arch/arm/mach-tcc8900/include/mach/reg_physical.h b/arch/arm/mach-tcc8900/include/mach/reg_physical.h
+new file mode 100644
+index 0000000..529a296
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/reg_physical.h
+@@ -0,0 +1,38 @@
++/****************************************************************************
++* FileName : reg_physical.h
++* Description :
++****************************************************************************
++*
++* TCC Version : 1.0
++* Copyright (c) Telechips, Inc.
++* ALL RIGHTS RESERVED
++*
++****************************************************************************/
++
++#ifndef __REG_PHYSICAL_H__
++#define __REG_PHYSICAL_H__
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/*
++#if defined(TCC89X)
++ #include "TCC89x_Physical.h"
++ #include "TCC89x_Structures.h"
++#elif defined(TCC91X)
++ #include "TCC91x_Physical.h"
++ #include "TCC91x_Structures.h"
++#elif defined(TCC92X)
++ #include "TCC92x_Physical.h"
++ #include "TCC92x_Structures.h"
++#endif
++*/
++#include "TCC89x_Physical.h"
++#include "TCC89x_Structures.h"
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif // __REG_PHYSICAL_H__
+diff --git a/arch/arm/mach-tcc8900/include/mach/system.h b/arch/arm/mach-tcc8900/include/mach/system.h
+new file mode 100644
+index 0000000..2dbc2a0
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/system.h
+@@ -0,0 +1,54 @@
++/*
++ * linux/arch/arm/mach-tcc8900/include/mach
++ *
++ * Author: <linux@telechips.com>
++ * Created: June 10, 2008
++ * Description: LINUX SYSTEM FUNCTIONS for TCC83x
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#ifndef __ASM_ARCH_SYSTEM_H
++#define __ASM_ARCH_SYSTEM_H
++#include <linux/clk.h>
++
++#include <asm/mach-types.h>
++#include <mach/hardware.h>
++
++#include <bsp.h>
++
++extern inline void tcc_idle(void);
++
++static inline void arch_idle(void)
++{
++ tcc_idle();
++}
++
++static inline void arch_reset(char mode)
++{
++ volatile PPMU pPMU = (volatile PPMU)(tcc_p2v(HwPMU_BASE)); //0xF0404000
++ volatile PIOBUSCFG pIOBUSCFG = (volatile PIOBUSCFG)(tcc_p2v(HwIOBUSCFG_BASE)); //0xF05F5000
++
++ pIOBUSCFG->HCLKEN0 = -1;
++ pIOBUSCFG->HCLKEN1 = -1;
++
++ while (1) {
++ pPMU->WATCHDOG = (Hw31 + 0x1);
++ }
++}
++
++#endif
+diff --git a/arch/arm/mach-tcc8900/include/mach/system_type.h b/arch/arm/mach-tcc8900/include/mach/system_type.h
+new file mode 100644
+index 0000000..7941705
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/system_type.h
+@@ -0,0 +1,32 @@
++/****************************************************************************
++* FileName : system.h
++* Description :
++****************************************************************************
++*
++* TCC Version : 1.0
++* Copyright (c) Telechips, Inc.
++* ALL RIGHTS RESERVED
++*
++****************************************************************************/
++
++#ifndef __SYSTEM_H__
++#define __SYSTEM_H__
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++ //wince
++#include <windows.h>
++#include <nkintr.h>
++#include <halether.h>
++#include <oal.h>
++
++ //linux
++
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif // __SYSTEM_H__
+\ No newline at end of file
+diff --git a/arch/arm/mach-tcc8900/include/mach/tca_ckc.h b/arch/arm/mach-tcc8900/include/mach/tca_ckc.h
+new file mode 100644
+index 0000000..cdb8315
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/tca_ckc.h
+@@ -0,0 +1,178 @@
++/****************************************************************************
++ * FileName : tca_ckc.h
++ * Description :
++ ****************************************************************************
++*
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++*
++ ****************************************************************************/
++
++
++/************************************************************************************************
++* Revision History *
++* *
++* Version : 1.0 : 2009, 2, 04 *
++************************************************************************************************/
++
++#ifndef __TCA_CKC_H__
++#define __TCA_CKC_H__
++
++//#include "bsp.h"
++
++#if defined(_LINUX_)
++#ifndef VOLATILE
++#define VOLATILE
++#endif
++#else
++#ifndef VOLATILE
++#define VOLATILE volatile
++#endif
++#endif
++
++/************************************************************************************************
++* MACRO *
++************************************************************************************************/
++
++/************************************************************************************************
++* DEFINE *
++************************************************************************************************/
++/************************************************************************************************
++* ENUM *
++************************************************************************************************/
++/****************************************************************************************
++* FUNCTION :void tca_ckc_init(void)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE void tca_ckc_init(void);
++
++/****************************************************************************************
++* FUNCTION :unsigned int tca_ckc_getpll(unsigned int ch)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE unsigned int tca_ckc_getpll(unsigned int ch);
++
++/****************************************************************************************
++* FUNCTION :unsigned int tca_ckc_getcpu(void)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE unsigned int tca_ckc_getcpu(void);
++
++/****************************************************************************************
++* FUNCTION :unsigned int tca_ckc_getbus(void)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE unsigned int tca_ckc_getbus(void);
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_setfbusctrl(unsigned int clkname,unsigned int isenable,unsigned int freq, unsigned int sor)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE void tca_ckc_setfbusctrl(unsigned int clkname,unsigned int isenable,unsigned int md,unsigned int freq, unsigned int sor);
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_getfbusctrl(unsigned int clkname)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE int tca_ckc_getfbusctrl(unsigned int clkname);
++
++/****************************************************************************************
++* FUNCTION :int tca_ckc_setpll(unsigned int pll, unsigned int ch)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE int tca_ckc_setpll(unsigned int pll, unsigned int ch);
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_validpll(unsigned int * pvalidpll)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE void tca_ckc_validpll(unsigned int * pvalidpll);
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_setpmupwroff( unsigned int periname , unsigned int isenable)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE void tca_ckc_setpmupwroff( unsigned int periname , unsigned int isenable);
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_getpmupwroff( unsigned int pmuoffname)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE int tca_ckc_getpmupwroff( unsigned int pmuoffname);
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_setperi(unsigned int periname,unsigned int isenable, unsigned int freq, unsigned int sor)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE void tca_ckc_setperi(unsigned int periname,unsigned int isenable, unsigned int freq, unsigned int sor);
++
++/****************************************************************************************
++* FUNCTION : int tca_ckc_getperi(unsigned int periname)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE int tca_ckc_getperi(unsigned int periname);
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_setcpu(unsigned int n)
++* DESCRIPTION : n is n/16
++* example : CPU == PLL : n=16 - CPU == PLL/2 : n=8
++* ***************************************************************************************/
++extern VOLATILE void tca_ckc_setcpu(unsigned int n);
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_setswresetprd(unsigned int prd)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE void tca_ckc_setswresetprd(unsigned int prd);
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_setswreset(unsigned int lfbusname, unsigned int mode)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE void tca_ckc_setswreset(unsigned int lfbusname, unsigned int mode);
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_set_iobus_swreset(unsigned int sel)
++* DESCRIPTION :
++* ***************************************************************************************/
++
++extern VOLATILE unsigned int tca_ckc_set_iobus_swreset(unsigned int sel, unsigned int mode);
++
++/****************************************************************************************
++* FUNCTION : int tca_ckc_setiobus(unsigned int sel, unsigned int mode)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE int tca_ckc_setiobus(unsigned int sel, unsigned int mode);
++/****************************************************************************************
++* FUNCTION : int tca_ckc_getiobus(unsigned int sel)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE int tca_ckc_getiobus(unsigned int sel);
++
++/****************************************************************************************
++* FUNCTION : int tca_ckc_setsmui2c(unsigned int freq)
++* DESCRIPTION :
++* ***************************************************************************************/
++extern VOLATILE void tca_ckc_setsmui2c(unsigned int freq);
++/****************************************************************************************
++* FUNCTION : int tca_ckc_getsmui2c(void)
++* DESCRIPTION : unit : 100Hz
++* ***************************************************************************************/
++extern VOLATILE int tca_ckc_getsmui2c(void);
++
++/****************************************************************************************
++* FUNCTION : void tca_ckc_setddipwdn(unsigned int lpwdn , unsigned int lmode)
++* DESCRIPTION : Power Down Register of DDI_CONFIG
++* ***************************************************************************************/
++extern void tca_ckc_setddipwdn(unsigned int lpwdn , unsigned int lmode);
++/****************************************************************************************
++* FUNCTION : int tca_ckc_getddipwdn(unsigned int lpwdn)
++* DESCRIPTION : Power Down Register of DDI_CONFIG
++* ***************************************************************************************/
++extern int tca_ckc_getddipwdn(unsigned int lpwdn);
++
++#endif /* __TCA_CKC_H__ */
++
++
++
+diff --git a/arch/arm/mach-tcc8900/include/mach/tcc_ckc_ctrl.h b/arch/arm/mach-tcc8900/include/mach/tcc_ckc_ctrl.h
+new file mode 100644
+index 0000000..aa2a10c
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/tcc_ckc_ctrl.h
+@@ -0,0 +1,60 @@
++/* linux/arch/arm/mach-tcc8900/include/mach/tcc_ckc_ctrl.h
++
++ * Author: <linux@telechips.com>
++ * Created: June 10, 2008
++ * Description: Header for code common to all Telechips TCC8900/TCC83x machines.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef _TCC_CKC_CTRL_H
++#define _TCC_CKC_CTRL_H
++
++#include <linux/tcc_ioctl.h>
++
++extern int arm_changestack(void);
++extern void arm_restorestack(unsigned int rst);
++
++extern void ckc_set_peri(struct ckc_ioctl st);
++extern int ckc_get_peri(struct ckc_ioctl st);
++extern int ckc_set_peribus(struct ckc_ioctl st);
++extern int ckc_get_peribus(struct ckc_ioctl st);
++extern void ckc_set_periswreset(struct ckc_ioctl st);
++extern void ckc_set_fbusswreset(struct ckc_ioctl st);
++extern void ckc_set_cpu(struct ckc_ioctl st);
++extern void ckc_set_smui2c(struct ckc_ioctl st);
++extern unsigned int ckc_get_cpu(struct ckc_ioctl st);
++extern unsigned int ckc_get_bus(struct ckc_ioctl st);
++extern void ckc_get_validpllinfo(struct ckc_ioctl st);
++extern void ckc_set_fbus(struct ckc_ioctl st);
++extern int ckc_get_fbus(struct ckc_ioctl st);
++extern void ckc_set_pmupower(struct ckc_ioctl st);
++extern void ckc_get_pmupower(struct ckc_ioctl st);
++extern void ckc_get_clockinfo(struct ckc_ioctl st);
++extern void ckc_set_changefbus(struct ckc_ioctl st);
++extern void ckc_set_changemem(struct ckc_ioctl st);
++extern void ckc_set_changecpu(struct ckc_ioctl st);
++extern void ckc_set_ddipwdn(struct ckc_ioctl st);
++extern void ckc_get_ddipwdn(struct ckc_ioctl st);
++extern void ckc_set_etcblock(struct ckc_ioctl st);
++
++#endif /* _TCC_CKC_CTRL_H*/
++
+diff --git a/arch/arm/mach-tcc8900/include/mach/tcc_pca953x.h b/arch/arm/mach-tcc8900/include/mach/tcc_pca953x.h
+new file mode 100644
+index 0000000..c554f6e
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/tcc_pca953x.h
+@@ -0,0 +1,210 @@
++/*
++ * linux/arch/arm/mach-tcc8900/include/mach/tcc_pca953x.h
++ *
++ * Author: <linux@telechips.com>
++ * Created: 21th March, 2009
++ * Description: Tcc250 Driver
++ *
++ * Copyright (c) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * ===============================================================================================
++ * USAGE
++ * =======
++ *
++ * Use "tcc_pca953x_setup()" function for management port status.
++ *
++ * 1. read operation
++ *
++ * int tcc_pca953x_setup(int slave, int name, int direction, int value, int mode);
++ *
++ * parameters
++ * ----------
++ * int slave - PCA953x I2C slave address
++ * int name - fixed 0
++ * int direction - direction of port [OUTPUT/INPUT]
++ * int value - fixed 0
++ * int mode - fixed GET_VALUE
++ *
++ * return value
++ * ------------
++ * int rd_buf - 16bit read data returned, -1 is fail
++ *
++ * example
++ * -------
++ * // read PCA9539_U2_SLAVE_ADDR port0 and port1
++ * int rd_buf = tcc_pca953x_setup(PCA9539_U2_SLAVE_ADDR, 0, OUTPUT, 0, GET_VALUE);
++ *
++ * 2. write operation
++ *
++ * int tcc_pca953x_setup(int slave, int name, int direction, int value, int mode);
++ *
++ * parameters
++ * ----------
++ * int slave - PCA953x I2C slave address
++ * int name - control port name, see "Expanded GPIO port map"
++ * int direction - direction of port [OUTPUT/INPUT]
++ * int value - output mode only. set port value [HIGH/LOW]
++ * int mode - [SET_DIRECTION/SET_VALUE] or [SET_DIRECTION|SET_VALUE]
++ *
++ * return value
++ * ------------
++ * int rd_buf - 1 is success, -1 is fail
++ *
++ * example
++ * -------
++ * + set port direction
++ * // PCA9539_U2_SLAVE_ADDR, ETH_RST, Output mode
++ * tcc_pca953x_setup(PCA9539_U2_SLAVE_ADDR, ETH_RST, OUTPUT, 0, SET_DIRECTION);
++ *
++ * + set port value (output mode only)
++ * // PCA9539_U2_SLAVE_ADDR, ETH_RST, Output High
++ * tcc_pca953x_setup(PCA9539_U2_SLAVE_ADDR, ETH_RST, OUTPUT, HIGH, SET_VALUE);
++ *
++ * + set both (direction & value)
++ * // PCA9539_U2_SLAVE_ADDR, ETH_RST, Output mode, Output Low
++ * tcc_pca953x_setup(PCA9539_U2_SLAVE_ADDR, ETH_RST, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++ *
++ * 3. direct read/write
++ * + read
++ * tcc_pca953x_read(PCA9539_U2_SLAVE_ADDR, PCA9539_OUTPUT_0, &buf[0]);
++ * tcc_pca953x_read(PCA9539_U2_SLAVE_ADDR, PCA9539_OUTPUT_1, &buf[1]);
++ * printk("PCA9539_U2_SLAVE_ADDR port0(%x), port1(%x)", buf[0], buf[1]);
++ *
++ * + write each port
++ * buf[0] = PCA9539_OUTPUT_0;
++ * buf[1] = 0x12;
++ * tcc_pca953x_write(PCA9539_U2_SLAVE_ADDR, &buf[0], 2);
++ * buf[0] = PCA9539_OUTPUT_1;
++ * buf[1] = 0x34;
++ * tcc_pca953x_write(PCA9539_U2_SLAVE_ADDR, &buf[0], 2);
++ *
++ * + write all port
++ * buf[0] = PCA9539_OUTPUT_0;
++ * buf[1] = 0x12;
++ * buf[2] = 0x34;
++ * tcc_pca953x_write(PCA9539_U3_SLAVE_ADDR, &buf[0], 3);
++ *
++ * ===============================================================================================
++ */
++#ifndef __PCA953X_H__
++#define __PCA953X_H__
++
++#include <bsp.h>
++
++
++/*
++ * EXPORT_SYMBOL
++ */
++extern int tcc_pca953x_setup(int slave, int name, int direction, int value, int mode);
++extern int tcc_pca953x_read(int slave, unsigned char cmd, unsigned char *rd_buf);
++extern int tcc_pca953x_write(int slave, const unsigned char *wr_buf, int count);
++
++/*
++ * PCA953x I2C slave address
++ */
++#define PCA9539_U2_SLAVE_ADDR 0x77
++#define PCA9539_U3_SLAVE_ADDR 0x74
++#define PCA9538_U4_SLAVE_ADDR 0x70
++
++/*
++ * Port setup mode
++ */
++#define GET_VALUE 0x0001
++#define SET_DIRECTION 0x0010
++#define SET_VALUE 0x0100
++
++/*
++ * Port direction & value
++ */
++#define INPUT 1
++#define OUTPUT 0
++#define HIGH 1
++#define LOW 0
++
++/*
++ * Expanded GPIO port map
++ */
++/* PCA9539 U2 */
++//PORT0
++#define ETH_RST Hw0 // DNP : Ethernet Controller Reset
++#define DXB0_RST Hw1 // DMB, DAB Reset
++#define CAM_RST Hw2 // DNP : Camera Module Reset
++#define CAS_RST Hw3 // DNP : CAS Reset
++#define AUTH_RST Hw4 // iPod Auth Reset
++#define FM_RST Hw5 // FM Transceiver Reset
++#define RTC_RST Hw6 // DNP : RTC Reset
++#define SATA_ON Hw6 // SATA_ON
++#define BT_WAKE Hw7 // DNP : Bluetooth Wakeup
++#define HDMI_ON Hw7 // HDMI_ON
++//PORT1
++#define DXB0_IRQ Hw8 // INPUT
++#define BT_HWAKE Hw9 // INPUT : Bluetooth Host Wakeup
++#define FM_IRQ Hw10 // INPUT : FM Receiver IRQ
++#define CP_READY Hw11 // INPUT : iPod CP Ready
++#define DXB_GP0 Hw12 // DXBGP0
++#define CAM_FL_EN Hw13 // DNP : Camera Flash Light En/Disable
++#define LCD_BL_EN Hw13 // DNP : LCD Backlight En/Disable
++#define MUTE_CTL Hw14 // Audio Mute Control
++#define CAS_GP Hw15 // CASGP
++#define TV_SLEEP Hw15 // DNP : TV Sleep Signal
++#define HDD_RST Hw15 // DNP : HDD Reset
++
++/* PCA9539 U3 */
++//PORT0
++#define ATAPI_ON Hw0 // IDE Disk Interface
++#define LCD_ON Hw1 // LCD Power
++#define LVDSIVT_ON Hw2 // LVDS Inverter
++#define CAM_ON Hw3 // Camera Module Power
++#define CODEC_ON Hw4 // External Audio CODEC
++#define FMTC_ON Hw5 // FM Transceiver
++#define SD0_ON Hw6 // SD Card Slot 0
++#define SD1_ON Hw7 // SD Card Slot 1
++//PORT1
++#define BT_ON Hw8 // Bluetooth
++#define CAS_ON Hw9 // CAS
++#define CAN_ON Hw10 // CAN Interface Controller
++#define ETH_ON Hw11 // Ethernet Controller
++#define DXB_ON Hw12 // DMB, DAB Power
++#define iPOD_ON Hw13 // iPOD Connection Power
++#define PWR_GP4 Hw14 // GPIO4 Power
++#define LVDS_LP_CTRL Hw15 // LVDS LCD Controller
++
++/* PCA9538 U4 */
++//PORT0
++#define DVBUS_ON Hw0 // USB Device VBUS
++#define HVBUS_ON Hw1 // USB Host VBUS
++#define HDMI_LVDS_ON Hw2 // HDMI_LVDS Interface Power
++#define PWR_GP0 Hw3 // GPIO0 Power
++#define PWR_GP2 Hw4 // GPIO2 Power
++#define PWR_GP3 Hw5 // GPIO3 Power
++#define VCORE_CTL Hw6 // Core Voltage Power
++#define PWR_GP1 Hw7 // GPIO1 Power
++
++/*
++ * PCA953x command
++ */
++enum pca9539_cmd
++{
++ PCA9539_INPUT_0 = 0,
++ PCA9539_INPUT_1 = 1,
++ PCA9539_OUTPUT_0 = 2,
++ PCA9539_OUTPUT_1 = 3,
++ PCA9539_INVERT_0 = 4,
++ PCA9539_INVERT_1 = 5,
++ PCA9539_DIRECTION_0 = 6,
++ PCA9539_DIRECTION_1 = 7,
++};
++
++enum pca9538_cmd
++{
++ PCA9538_INPUT_0 = 0,
++ PCA9538_OUTPUT_0 = 1,
++ PCA9538_INVERT_0 = 2,
++ PCA9538_DIRECTION_0 = 3,
++};
++
++#endif /*__PCA953X_H__*/
+diff --git a/arch/arm/mach-tcc8900/include/mach/timex.h b/arch/arm/mach-tcc8900/include/mach/timex.h
+new file mode 100644
+index 0000000..8ff927f
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/timex.h
+@@ -0,0 +1,31 @@
++/*
++ * linux/include/asm-arm/arch-tcc8900/timex.h
++ *
++ * Author: Greg Lonnon <glonnon@ridgerun.com>
++ * Modified: <linux@telechips.com>
++ *
++ * Copyright (C) 2000 RidgeRun, Inc.
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#define CLOCK_TICK_RATE (HZ * 100000UL)
+diff --git a/arch/arm/mach-tcc8900/include/mach/uncompress.h b/arch/arm/mach-tcc8900/include/mach/uncompress.h
+new file mode 100644
+index 0000000..f72cb50
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/uncompress.h
+@@ -0,0 +1,45 @@
++/*
++ * linux/include/asm-arm/arch-tcc83x/uncompress.h
++ *
++ * Author: <source@mvista.com>
++ * Modified: <linux@telechips.com>
++ * Modified: June 10, 2008
++ * Description: Serial port stubs for kernel decompress status messages
++ *
++ * 2004 (c) MontaVista Software, Inc.
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * 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 <linux/types.h>
++#include <linux/serial_reg.h>
++
++unsigned int system_rev;
++
++#define ID_MASK 0x7fff
++
++static void putc(int c)
++{
++ volatile u8 * uart = 0;
++ int shift = 2;
++
++ /*
++ * Now, xmit each character
++ */
++ while (!(uart[UART_LSR << shift] & UART_LSR_THRE))
++ barrier();
++ uart[UART_TX << shift] = c;
++}
++
++static inline void flush(void)
++{
++}
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_setup()
++#define arch_decomp_wdog()
+diff --git a/arch/arm/mach-tcc8900/include/mach/vmalloc.h b/arch/arm/mach-tcc8900/include/mach/vmalloc.h
+new file mode 100644
+index 0000000..b47ade6
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/include/mach/vmalloc.h
+@@ -0,0 +1,25 @@
++/*
++ * linux/include/asm-arm/arch-tcc8900/vmalloc.h
++ *
++ * Author: <linux@telechips.com>
++ * Created: Feb 10, 2009
++ *
++ * Copyright (C) 2000 Russell King.
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * 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
++ */
++#define VMALLOC_END (PAGE_OFFSET + 0x20000000)
++
+diff --git a/arch/arm/mach-tcc8900/io.c b/arch/arm/mach-tcc8900/io.c
+new file mode 100644
+index 0000000..7ba1689
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/io.c
+@@ -0,0 +1,100 @@
++/*
++ * linux/arch/arm/mach-tcc8900/io.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 10th February, 2008
++ * Description: tcc8900 mapping code
++ *
++ * Copyright (C) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++
++#include <asm/tlb.h>
++#include <asm/mach/map.h>
++#include <asm/io.h>
++
++#include <bsp.h>
++
++/*
++ * The machine specific code may provide the extra mapping besides the
++ * default mapping provided here.
++ */
++static struct map_desc tcc8900_io_desc[] __initdata = {
++ {
++ .virtual = 0xF0000000,
++ .pfn = __phys_to_pfn(0xF0000000),
++ .length = 0x100000,
++ .type = MT_DEVICE
++ },
++ {
++ .virtual = 0xF0100000,
++ .pfn = __phys_to_pfn(0xF0100000),
++ .length = 0x100000,
++ .type = MT_DEVICE
++ },
++ {
++ .virtual = 0xF0200000,
++ .pfn = __phys_to_pfn(0xF0200000),
++ .length = 0x100000,
++ .type = MT_DEVICE
++ },
++ {
++ .virtual = 0xF0300000,
++ .pfn = __phys_to_pfn(0xF0300000),
++ .length = 0x100000,
++ .type = MT_DEVICE
++ },
++ {
++ .virtual = 0xF0400000,
++ .pfn = __phys_to_pfn(0xF0400000),
++ .length = 0x100000,
++ .type = MT_DEVICE
++ },
++ {
++ .virtual = 0xF0500000,
++ .pfn = __phys_to_pfn(0xF0500000),
++ .length = 0x100000,
++ .type = MT_DEVICE
++ },
++ {
++ .virtual = 0xF0600000,
++ .pfn = __phys_to_pfn(0xF0600000),
++ .length = 0x100000,
++ .type = MT_DEVICE
++ },
++ {
++ .virtual = 0xF0700000,
++ .pfn = __phys_to_pfn(0xF0700000),
++ .length = 0x100000,
++ .type = MT_DEVICE
++ },
++ {
++ .virtual = 0xEFF00000,
++ .pfn = __phys_to_pfn(0x10000000),
++ .length = 0x100000,
++ .type = MT_MEMORY_TCC
++ },
++};
++
++
++/*
++ * Maps common IO regions for tcc8900.
++ */
++void __init tcc8900_map_common_io(void)
++{
++ iotable_init(tcc8900_io_desc, ARRAY_SIZE(tcc8900_io_desc));
++
++ /* Normally devicemaps_init() would flush caches and tlb after
++ * mdesc->map_io(), but we must also do it here because of the CPU
++ * revision check below.
++ */
++ local_flush_tlb_all();
++ flush_cache_all();
++}
+diff --git a/arch/arm/mach-tcc8900/irq.c b/arch/arm/mach-tcc8900/irq.c
+new file mode 100644
+index 0000000..8a485ff
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/irq.c
+@@ -0,0 +1,595 @@
++/*
++ * linux/arch/arm/mach-tcc8900/irq.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 10th February, 2009
++ * Description: Interrupt handler for Telechips TCC8900 chipset
++ *
++ * Copyright (C) Telechips, Inc.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/ptrace.h>
++
++#include <linux/agpgart.h>
++#include <linux/types.h>
++
++#include <asm/irq.h>
++#include <asm/mach/irq.h>
++#include <asm/io.h>
++
++#include <mach/gpio.h>
++#include <bsp.h>
++
++// Global
++static volatile PGPIO pGPIO;
++static volatile PPIC pPIC;
++static volatile PVIC pVIC;
++static volatile PGPSBPORTCFG pPGPSBPORTCFG;
++static volatile PUARTPORTMUX pUARTPORTMUX;
++static volatile PGDMACTRL pPGDMACTRL0, pPGDMACTRL1, pPGDMACTRL2, pPGDMACTRL3;
++static volatile PTIMER pTIMER;
++
++
++/******************************************
++ * Disable IRQ
++ *
++ * If mask_ack exist, this is not called.
++ *****************************************/
++static void tcc8900_mask_irq(unsigned int irq)
++{
++ if (irq < 32) {
++ BITCLR(pPIC->INTMSK0, (1 << irq));
++ } else {
++ BITCLR(pPIC->INTMSK1, (1 << (irq - 32)));
++ }
++}
++
++static void tcc8900_mask_irq_uart(unsigned int irq)
++{
++ if (irq != INT_UART) {
++ BITCLR(pPIC->INTMSK1, Hw15);
++ }
++}
++
++static void tcc8900_mask_irq_gpsb(unsigned int irq)
++{
++ if (irq != INT_GPSB) {
++ BITCLR(pPIC->INTMSK1, Hw4);
++ }
++}
++
++static void tcc8900_mask_irq_dma(unsigned int irq)
++{
++ if (irq != INT_DMA) {
++ BITCLR(pPIC->INTMSK0, Hw29);
++ }
++}
++
++static void tcc8900_mask_irq_tc0(unsigned int irq)
++{
++ if (irq != INT_TC0) {
++ BITCLR(pPIC->INTMSK0, Hw0);
++ }
++}
++
++/******************************************
++ * Enable IRQ
++ *****************************************/
++static void tcc8900_irq_enable(unsigned int irq)
++{
++ if (irq < 32) {
++ BITSET(pPIC->CLR0, (1 << irq));
++ BITSET(pPIC->IEN0, (1 << irq));
++ BITSET(pPIC->INTMSK0, (1 << irq));
++ } else {
++ BITSET(pPIC->CLR1, (1 << (irq - 32)));
++ BITSET(pPIC->IEN1, (1 << (irq - 32)));
++ BITSET(pPIC->INTMSK1, (1 << (irq - 32)));
++ }
++}
++
++static void tcc8900_unmask_irq(unsigned int irq)
++{
++ if (irq < 32) {
++ BITSET(pPIC->INTMSK0, (1 << irq));
++ BITSET(pPIC->CLR0, (1 << irq));
++ } else {
++ BITSET(pPIC->INTMSK1, (1 << (irq - 32)));
++ BITSET(pPIC->CLR1, (1 << (irq - 32)));
++ }
++}
++static void tcc8900_unmask_irq_uart(unsigned int irq)
++{
++ if (irq != INT_UART) {
++ BITSET(pPIC->INTMSK1, Hw15);
++ }
++}
++static void tcc8900_unmask_irq_gpsb(unsigned int irq)
++{
++ if (irq != INT_GPSB) {
++ BITSET(pPIC->INTMSK1, Hw4);
++ }
++}
++static void tcc8900_unmask_irq_dma(unsigned int irq)
++{
++ if (irq != INT_DMA) {
++ BITSET(pPIC->INTMSK0, Hw29);
++ }
++}
++
++static void tcc8900_unmask_irq_tc0(unsigned int irq)
++{
++ if (irq != INT_TC0) {
++ BITSET(pPIC->INTMSK0, Hw0);
++ }
++}
++
++/******************************************
++ * Ack IRQ (Disable IRQ)
++ *****************************************/
++
++static void tcc8900_irq_disable(unsigned int irq)
++{
++ if (irq < 32){
++ BITCLR(pPIC->IEN0, (1 << irq));
++ BITCLR(pPIC->INTMSK0, (1 << irq));
++ } else {
++ BITCLR(pPIC->IEN1, (1 << (irq - 32)));
++ BITCLR(pPIC->INTMSK1, (1 << (irq - 32)));
++ }
++}
++
++
++static void tcc8900_mask_ack_irq(unsigned int irq)
++{
++ if (irq < 32){
++ BITCLR(pPIC->INTMSK0, (1 << irq));
++ } else {
++ BITCLR(pPIC->INTMSK1, (1 << (irq - 32)));
++ }
++}
++
++static void tcc8900_mask_ack_irq_uart(unsigned int irq)
++{
++ if (irq != INT_UART) {
++ BITCLR(pPIC->INTMSK1, Hw15);
++ }
++}
++
++static void tcc8900_mask_ack_irq_gpsb(unsigned int irq)
++{
++ if (irq != INT_GPSB) {
++ BITCLR(pPIC->INTMSK1, Hw4);
++ }
++}
++
++static void tcc8900_mask_ack_irq_dma(unsigned int irq)
++{
++ if (irq != INT_DMA) {
++ BITCLR(pPIC->INTMSK0, Hw29);
++ }
++}
++
++static void tcc8900_mask_ack_irq_tc0(unsigned int irq)
++{
++ if (irq != INT_TC0) {
++ BITCLR(pPIC->INTMSK0, Hw0);
++ }
++}
++
++/******************************************
++ * wake IRQ
++ *****************************************/
++static int tcc8900_wake_irq(unsigned int irq, unsigned int enable)
++{
++ return 0;
++}
++
++static int tcc8900_wake_irq_uart(unsigned int irq, unsigned int enable)
++{
++ return 0;
++}
++
++static int tcc8900_wake_irq_gpsb(unsigned int irq, unsigned int enable)
++{
++ return 0;
++}
++
++static int tcc8900_wake_irq_dma(unsigned int irq, unsigned int enable)
++{
++ return 0;
++}
++
++static int tcc8900_wake_irq_tc0(unsigned int irq, unsigned int enable)
++{
++ return 0;
++}
++
++static void tcc8900_irq_dummy(unsigned int irq)
++{
++}
++
++static void tcc8900_irq_uart_handler(unsigned irq, struct irq_desc *desc)
++{
++ if (pUARTPORTMUX->CHST & Hw0) {
++ irq = INT_UART0;
++ } else if (pUARTPORTMUX->CHST & Hw1) {
++ irq = INT_UART1;
++ } else if (pUARTPORTMUX->CHST & Hw2) {
++ irq = INT_UART2;
++ } else if (pUARTPORTMUX->CHST & Hw3) {
++ irq = INT_UART3;
++ } else if (pUARTPORTMUX->CHST & Hw4) {
++ irq = INT_UART4;
++ } else if (pUARTPORTMUX->CHST & Hw5) {
++ irq = INT_UART5;
++ } else {
++ //BITSET(pPIC->INTMSK1 , Hw15); // using INTMSK
++ BITSET(pPIC->CLR1, Hw15);
++ goto out;
++ }
++
++ desc = irq_desc + irq;
++ desc_handle_irq(irq, desc);
++out:
++ return;
++}
++
++static void tcc8900_irq_gpsb_handler(unsigned irq, struct irq_desc *desc)
++{
++ if (pPGPSBPORTCFG->CIRQST & Hw3) {
++ irq = INT_GPSB1_DMA;
++ } else if (pPGPSBPORTCFG->CIRQST & Hw1) {
++ irq = INT_GPSB0_DMA;
++ } else if (pPGPSBPORTCFG->CIRQST & Hw5) {
++ irq = INT_GPSB2_DMA;
++ } else if (pPGPSBPORTCFG->CIRQST & Hw3) {
++ irq = INT_GPSB0_CORE;
++ } else if (pPGPSBPORTCFG->CIRQST & Hw0) {
++ irq = INT_GPSB1_CORE;
++ } else if (pPGPSBPORTCFG->CIRQST & Hw2) {
++ irq = INT_GPSB2_CORE;
++ } else if (pPGPSBPORTCFG->CIRQST & Hw6) {
++ irq = INT_GPSB3_CORE;
++ } else if (pPGPSBPORTCFG->CIRQST & Hw8) {
++ irq = INT_GPSB4_CORE;
++ } else if (pPGPSBPORTCFG->CIRQST & Hw10) {
++ irq = INT_GPSB5_CORE;
++ } else {
++ //BITSET(pPIC->INTMSK1 , Hw4); // using INTMSK
++ BITSET(pPIC->CLR1, Hw4);
++ goto out;
++ }
++
++ desc = irq_desc + irq;
++ desc_handle_irq(irq, desc);
++out:
++ return;
++}
++
++static void tcc8900_irq_dma_handler(unsigned irq, struct irq_desc *desc)
++{
++ if (pPGDMACTRL0->CHCONFIG & (Hw18|Hw17|Hw16)) {
++ if (pPGDMACTRL0->CHCONFIG & Hw16) {
++ irq = INT_DMA0_CH0;
++ } else if (pPGDMACTRL0->CHCONFIG & Hw17) {
++ irq = INT_DMA0_CH1;
++ } else if (pPGDMACTRL0->CHCONFIG & Hw18) {
++ irq = INT_DMA0_CH2;
++ } else {
++ goto out1;
++ }
++ } else if (pPGDMACTRL1->CHCONFIG & (Hw18|Hw17|Hw16)) {
++ if (pPGDMACTRL1->CHCONFIG & Hw16) {
++ irq = INT_DMA1_CH0;
++ } else if (pPGDMACTRL1->CHCONFIG & Hw17) {
++ irq = INT_DMA1_CH1;
++ } else if (pPGDMACTRL1->CHCONFIG & Hw18) {
++ irq = INT_DMA1_CH2;
++ } else {
++ goto out1;
++ }
++
++ } else if (pPGDMACTRL2->CHCONFIG & (Hw18|Hw17|Hw16)) {
++ if (pPGDMACTRL2->CHCONFIG & Hw16) {
++ irq = INT_DMA2_CH0;
++ } else if (pPGDMACTRL2->CHCONFIG & Hw17) {
++ irq = INT_DMA2_CH1;
++ } else if (pPGDMACTRL2->CHCONFIG & Hw18) {
++ irq = INT_DMA2_CH2;
++ } else {
++ goto out1;
++ }
++
++ } else if (pPGDMACTRL3->CHCONFIG & (Hw18|Hw17|Hw16)) {
++ if (pPGDMACTRL3->CHCONFIG & Hw16) {
++ irq = INT_DMA3_CH0;
++ } else if (pPGDMACTRL3->CHCONFIG & Hw17) {
++ irq = INT_DMA3_CH1;
++ } else if (pPGDMACTRL3->CHCONFIG & Hw18) {
++ irq = INT_DMA3_CH2;
++ } else {
++ goto out1;
++ }
++
++ } else {
++out1:
++ BITSET(pPIC->CLR0, Hw29);
++ goto out2;
++ }
++
++ desc = irq_desc + irq;
++ desc_handle_irq(irq, desc);
++out2:
++ return;
++}
++
++static void tcc8900_irq_tc0_handler(unsigned irq, struct irq_desc *desc)
++{
++ if (pTIMER->TIREQ & Hw0) {
++ irq = INT_TC0_TI0;
++ } else if (pTIMER->TIREQ & Hw1) {
++ irq = INT_TC0_TI1;
++ } else if (pTIMER->TIREQ & Hw2) {
++ irq = INT_TC0_TI2;
++ } else if (pTIMER->TIREQ & Hw3) {
++ irq = INT_TC0_TI3;
++ } else if (pTIMER->TIREQ & Hw4) {
++ irq = INT_TC0_TI4;
++ } else if (pTIMER->TIREQ & Hw5) {
++ irq = INT_TC0_TI5;
++ } else {
++ //BITSET(pPIC->INTMSK1 , Hw0); // using INTMSK
++ BITSET(pPIC->CLR0, Hw0);
++ goto out;
++ }
++
++ desc = irq_desc + irq;
++ desc_handle_irq(irq, desc);
++out:
++ return;
++}
++
++
++static struct irq_chip tcc8900_irq_chip = {
++ .name = "IRQ",
++ .enable = tcc8900_irq_enable,
++ .disable = tcc8900_irq_disable,
++ .ack = tcc8900_mask_ack_irq,
++ .mask_ack = tcc8900_mask_ack_irq,
++ .mask = tcc8900_mask_irq,
++ .unmask = tcc8900_unmask_irq,
++ .set_wake = tcc8900_wake_irq,
++};
++
++static struct irq_chip tcc8900_irq_uart_chip = {
++ .name = "IRQ_UART",
++ .enable = tcc8900_irq_dummy,
++ .disable = tcc8900_irq_dummy,
++ .ack = tcc8900_mask_ack_irq_uart,
++ .mask_ack = tcc8900_mask_ack_irq_uart,
++ .mask = tcc8900_mask_irq_uart,
++ .unmask = tcc8900_unmask_irq_uart,
++ .set_wake = tcc8900_wake_irq_uart,
++};
++
++static struct irq_chip tcc8900_irq_gpsb_chip = {
++ .name = "IRQ_GPSB",
++ .enable = tcc8900_irq_dummy,
++ .disable = tcc8900_irq_dummy,
++ .ack = tcc8900_mask_ack_irq_gpsb,
++ .mask_ack = tcc8900_mask_ack_irq_gpsb,
++ .mask = tcc8900_mask_irq_gpsb,
++ .unmask = tcc8900_unmask_irq_gpsb,
++ .set_wake = tcc8900_wake_irq_gpsb,
++};
++
++static struct irq_chip tcc8900_irq_dma_chip = {
++ .name = "IRQ_DMA",
++ .enable = tcc8900_irq_dummy,
++ .disable = tcc8900_irq_dummy,
++ .ack = tcc8900_mask_ack_irq_dma,
++ .mask_ack = tcc8900_mask_ack_irq_dma,
++ .mask = tcc8900_mask_irq_dma,
++ .unmask = tcc8900_unmask_irq_dma,
++ .set_wake = tcc8900_wake_irq_dma,
++};
++
++static struct irq_chip tcc8900_irq_tc0_chip = {
++ .name = "IRQ_TC0",
++ .enable = tcc8900_irq_dummy,
++ .disable = tcc8900_irq_dummy,
++ .ack = tcc8900_mask_ack_irq_tc0,
++ .mask_ack = tcc8900_mask_ack_irq_tc0,
++ .mask = tcc8900_mask_irq_tc0,
++ .unmask = tcc8900_unmask_irq_tc0,
++ .set_wake = tcc8900_wake_irq_tc0,
++};
++
++void __init tcc8900_irq_init(void)
++{
++ int irqno;
++
++ printk("%s\n", __func__);
++
++ //reset interrupt
++ pGPIO = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
++ pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++ pVIC = (volatile PVIC)tcc_p2v(HwVIC_BASE);
++ pPGPSBPORTCFG = (volatile PGPSBPORTCFG)tcc_p2v(HwGPSBPORTCFG_BASE);
++ pUARTPORTMUX = (volatile PUARTPORTMUX)tcc_p2v(HwUARTPORTMUX_BASE);
++ pPGDMACTRL0 = (volatile PGDMACTRL)tcc_p2v(HwGDMA0_BASE);
++ pPGDMACTRL1 = (volatile PGDMACTRL)tcc_p2v(HwGDMA1_BASE);
++ pPGDMACTRL2 = (volatile PGDMACTRL)tcc_p2v(HwGDMA2_BASE);
++ pPGDMACTRL3 = (volatile PGDMACTRL)tcc_p2v(HwGDMA3_BASE);
++ pTIMER = (volatile PTIMER)tcc_p2v(HwTMR_BASE);
++
++
++ /* ADD IOREMAP */
++
++ //clear IEN Field
++ BITCLR(pPIC->IEN0 , 0xFFFFFFFF); // All Interrupt Disable
++ BITCLR(pPIC->IEN1 , 0xFFFFFFFF); // All Interrupt Disable
++
++ //clear SEL Field
++ BITSET(pPIC->SEL0 , 0xFFFFFFFF); //using IRQ
++ BITSET(pPIC->SEL1 , 0xFFFFFFFF); //using IRQ
++
++ //clear TIG Field
++ BITCLR(pPIC->TIG0 , 0xFFFFFFFF); //Test Interrupt Disable
++ BITCLR(pPIC->TIG1 , 0xFFFFFFFF); //Test Interrupt Disable
++
++ //clear POL Field
++ BITCLR(pPIC->POL0 , 0xFFFFFFFF); //Default ACTIVE Low
++ BITCLR(pPIC->POL1 , 0xFFFFFFFF); //Default ACTIVE Low
++
++ //clear MODE Field
++ BITSET(pPIC->MODE0 , 0xFFFFFFFF); //Trigger Mode - Level Trigger Mode
++ BITSET(pPIC->MODE1 , 0xFFFFFFFF); //Trigger Mode - Level Trigger Mode
++
++ //clear SYNC Field
++ BITSET(pPIC->SYNC0 , 0xFFFFFFFF); //SYNC Enable
++ BITSET(pPIC->SYNC1 , 0xFFFFFFFF); //SYNC Enable
++
++ //clear WKEN Field
++ BITCLR(pPIC->WKEN0 , 0xFFFFFFFF); //Wakeup all disable
++ BITCLR(pPIC->WKEN1 , 0xFFFFFFFF); //Wakeup all disable
++
++ //celar MODEA Field
++ BITCLR(pPIC->MODEA0 , 0xFFFFFFFF); //both edge - all disable
++ BITCLR(pPIC->MODEA1 , 0xFFFFFFFF); //both edge - all disable
++
++ //clear INTMSK Field
++ BITCLR(pPIC->INTMSK0 , 0xFFFFFFFF); //not using INTMSK
++ BITCLR(pPIC->INTMSK1 , 0xFFFFFFFF); //not using INTMSK
++
++ //clear ALLMSK Field
++ BITCSET(pPIC->ALLMSK , 0xFFFFFFFF, 0x1); //using only IRQ
++
++ /* Install the interrupt handlers */
++ for(irqno = INT_TC0; irqno <= INT_AEIRQ; irqno++)
++ {
++ if (irqno == INT_UART) {
++ set_irq_chip(INT_UART, &tcc8900_irq_uart_chip);
++ set_irq_chained_handler(INT_UART, tcc8900_irq_uart_handler);
++ } else if (irqno == INT_GPSB) {
++ set_irq_chip(INT_GPSB, &tcc8900_irq_gpsb_chip);
++ set_irq_chained_handler(INT_GPSB, tcc8900_irq_gpsb_handler);
++ } else if (irqno == INT_DMA) {
++ set_irq_chip(INT_DMA, &tcc8900_irq_dma_chip);
++ set_irq_chained_handler(INT_DMA, tcc8900_irq_dma_handler);
++ } else if (irqno == INT_TC0) {
++ set_irq_chip(INT_TC0, &tcc8900_irq_tc0_chip);
++ set_irq_chained_handler(INT_TC0, tcc8900_irq_tc0_handler);
++ } else {
++ set_irq_chip(irqno, &tcc8900_irq_chip);
++ set_irq_handler(irqno, handle_level_irq);
++ set_irq_flags(irqno, IRQF_VALID);
++ }
++ }
++
++ /* Install the interrupt UART Group handlers */
++ for (irqno = INT_UART0; irqno <= INT_UART5; irqno++) {
++ set_irq_chip(irqno, &tcc8900_irq_uart_chip);
++ set_irq_handler(irqno, handle_level_irq);
++ set_irq_flags(irqno, IRQF_VALID);
++ }
++
++ /* Install the interrupt GPSB Group handlers */
++ for (irqno = INT_GPSB0_DMA; irqno <= INT_GPSB5_CORE; irqno++) {
++ set_irq_chip(irqno, &tcc8900_irq_gpsb_chip);
++ set_irq_handler(irqno, handle_level_irq);
++ set_irq_flags(irqno, IRQF_VALID);
++ }
++
++ /* Install the interrupt DMA Group handlers */
++ for (irqno = INT_DMA0_CH0; irqno <= INT_DMA3_CH2; irqno++) {
++ set_irq_chip(irqno, &tcc8900_irq_dma_chip);
++ set_irq_handler(irqno, handle_level_irq);
++ set_irq_flags(irqno, IRQF_VALID);
++ }
++
++ /* Install the interrupt TC0 Group handlers */
++ for (irqno = INT_TC0_TI0; irqno <= INT_TC0_TI5; irqno++) {
++ set_irq_chip(irqno, &tcc8900_irq_tc0_chip);
++ set_irq_handler(irqno, handle_level_irq);
++ set_irq_flags(irqno, IRQF_VALID);
++ }
++
++
++ /* IEN SET */
++ BITSET(pPIC->IEN1, Hw15); /* UART */
++ BITSET(pPIC->INTMSK1, Hw15); /* UART */
++ BITSET(pPIC->IEN1, Hw4); /* GPSB */
++ BITSET(pPIC->INTMSK1, Hw4); /* GPSB */
++ BITSET(pPIC->IEN0, Hw29); /* DMA */
++ BITSET(pPIC->INTMSK0, Hw29); /* DMA */
++ BITSET(pPIC->IEN0, Hw0); /* TC0 */
++ BITSET(pPIC->INTMSK0, Hw0);
++
++ BITCSET(pGPIO->EINTSEL2, Hw6-Hw0, 26<<0);
++ BITSET(pPIC->INTMSK0, 1<<INT_EI8);
++ BITCLR(pPIC->MODE0, 1<<INT_EI8);
++ BITSET(pPIC->POL0, 1<<INT_EI8);
++ BITSET(pPIC->MODEA0, 1<<INT_EI8);
++ gpio_direction_input(TCC_GPD17);
++
++ BITCSET(pGPIO->EINTSEL2, Hw14-Hw8, 27<<8);
++ BITSET(pPIC->INTMSK0, 1<<INT_EI9);
++ BITCLR(pPIC->MODE0, 1<<INT_EI9);
++ BITSET(pPIC->POL0, 1<<INT_EI9);
++ BITSET(pPIC->MODEA0, 1<<INT_EI9);
++ gpio_direction_input(TCC_GPD18);
++ gpio_direction_input(TCC_GPE4);
++
++ BITCSET(pGPIO->EINTSEL2, Hw22-Hw16, 28<<16);
++ BITSET(pPIC->INTMSK0, 1<<INT_EI10);
++ BITCLR(pPIC->MODE0, 1<<INT_EI10);
++ BITSET(pPIC->POL0, 1<<INT_EI10);
++ BITSET(pPIC->MODEA0, 1<<INT_EI10);
++ gpio_direction_input(TCC_GPD19);
++
++ BITCSET(pGPIO->EINTSEL2, Hw30-Hw24, 38<<24);
++ BITSET(pPIC->INTMSK0, 1<<INT_EI11);
++ BITCLR(pPIC->MODE0, 1<<INT_EI11);
++ BITSET(pPIC->POL0, 1<<INT_EI11);
++ BITSET(pPIC->MODEA0, 1<<INT_EI11);
++ gpio_direction_input(TCC_GPF10);
++
++#if defined (CONFIG_LCD_7)
++ BITCSET(pGPIO->EINTSEL1, Hw14-Hw8, 24<<8);
++ BITSET(pPIC->INTMSK0, 1<<INT_EI5);
++ BITCLR(pPIC->MODE0, 1<<INT_EI5);
++ BITSET(pPIC->POL0, 1<<INT_EI5);
++ BITSET(pPIC->MODEA0, 1<<INT_EI5);
++ gpio_direction_input(TCC_GPD15);
++
++ BITCSET(pGPIO->EINTSEL1, Hw22-Hw16, 25<<16);
++ BITSET(pPIC->INTMSK0, 1<<INT_EI6);
++ BITCLR(pPIC->MODE0, 1<<INT_EI6);
++ BITSET(pPIC->POL0, 1<<INT_EI6);
++ BITSET(pPIC->MODEA0, 1<<INT_EI6);
++ gpio_direction_input(TCC_GPD16);
++#endif
++}
++
++/* end of file */
+diff --git a/arch/arm/mach-tcc8900/pm.c b/arch/arm/mach-tcc8900/pm.c
+new file mode 100644
+index 0000000..969ba94
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/pm.c
+@@ -0,0 +1,1088 @@
++/*
++ * arch/arm/mach-tcc8900/pm.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: October, 2009
++ * Description: LINUX POWER MANAGEMENT FUNCTIONS
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * 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
++ *
++ *
++ * ChangeLog:
++ *
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/pm.h>
++#include <linux/syscalls.h> // sys_sync()
++#include <linux/io.h>
++#include <asm/tlbflush.h>
++#include <asm/cacheflush.h> // local_flush_tlb_all(), flush_cache_all();
++
++#include <bsp.h>
++#include <hhtech_gpio.h>
++#include <mach/gpio.h>
++#include "pm.h"
++
++#include <linux/suspend.h>
++
++#define BUS_CONTROL
++
++#define GPIOSIZE (16 * 6 + 8)
++#define SRAM_ADDR_STANDBY 0xEFF00000
++unsigned long bkreg[GPIOSIZE];
++
++typedef void (* lpfunc)(int);
++static lpfunc lpSelfRefresh;
++
++extern void IO_ARM_SaveREG(int sram_addr, unsigned int p89reg, void *);
++extern void Awake_address(void);
++extern void tca_bkl_powerup(unsigned int tmr_vaddr, unsigned int gpio_vaddr);
++
++
++static void tcc_gpio_default(unsigned int gpio_vaddr)
++{
++ PGPIO pGPIO = (PGPIO)gpio_vaddr;
++
++ /* GPC */
++ pGPIO->GPCDAT = 0x0000000; // 0x080 R/W 0x00000000 GPC Data Register
++ pGPIO->GPCEN = 0xFFFFFFFF; // 0x084 R/W 0x00000000 GPC Output Enable Register
++
++ //pGPIO->GPCPD1 &= ~Hw6; //pull - up remove
++ //pGPIO->GPCPD1 &= ~Hw7; //pull - down remove
++
++ pGPIO->GPCPD0 = 0; //pull - up
++ pGPIO->GPCPD1 = 0; //pull - up
++
++ pGPIO->GPCFN0 = 0x00000000; // 0x0A4 W 0x00000000 Port Configuration on GPC Output Data
++ pGPIO->GPCFN1 = 0x00000000; // 0x0A8 W 0x00000000 Port Configuration on GPC Output Data
++ pGPIO->GPCFN2 = 0x00000000; // 0x0AC W 0x00000000 Port Configuration on GPC Output Data
++ pGPIO->GPCFN3 = 0x00000000; // 0x0B0 W 0x00000000 Port Configuration on GPC Output Data
++
++ /* GPD */
++ pGPIO->GPDDAT = 0x00000000; // 0x0C0 R/W 0x00000000 GPD Data Register
++ pGPIO->GPDEN = 0x00000000; // 0x0C4 R/W 0x00000000 GPD Output Enable Register
++ pGPIO->GPDFN0 = 0x00000000; // 0x0E4 W 0x00000000 Port Configuration on GPD Output Data
++ pGPIO->GPDFN1 = 0x00000000; // 0x0E8 W 0x00000000 Port Configuration on GPD Output Data
++ pGPIO->GPDFN2 = 0x00000000; // 0x0EC W 0x00000000 Port Configuration on GPD Output Data
++ pGPIO->GPDFN3 = 0x00000000; // 0x0F0 W 0x00000000 Port Configuration on GPD Output Data
++
++ /* GPE */
++ pGPIO->GPEDAT = 0x00000000; // 0x100 R/W 0x00000000 GPE Data Register
++ pGPIO->GPEEN = 0x0F000000; // 0x104 R/W 0x00000000 GPE Output Enable Register
++ pGPIO->GPEFN0 = 0x00000000; // 0x124 W 0x00000000 Port Configuration on GPE Output Data
++ pGPIO->GPEFN1 = 0x00000000; // 0x128 W 0x00000000 Port Configuration on GPE Output Data
++ pGPIO->GPEFN2 = 0x00000000; // 0x12C W 0x00000000 Port Configuration on GPE Output Data
++ pGPIO->GPEFN3 = 0x00000000; // 0x130 W 0x00000000 Port Configuration on GPE Output Data
++
++ /* GPF */
++ pGPIO->GPFDAT = 0x00000000|Hw6; // 0x140 R/W 0x00000000 GPF Data Register
++ pGPIO->GPFEN = 0xffffffff; // 0x144 R/W 0x00000000 GPF Output Enable Register
++ pGPIO->GPFFN0 = 0x00000000; // 0x164 W 0x00000000 Port Configuration on GPF Output Data
++ pGPIO->GPFFN1 = 0x00000000; // 0x168 W 0x00000000 Port Configuration on GP Output Data
++ pGPIO->GPFFN2 = 0x00000000; // 0x16C W 0x00000000 Port Configuration on GPF Output Data
++ pGPIO->GPFFN3 = 0x00000000; // 0x170 W 0x00000000 Port Configuration on GPF Output Data
++
++ /* EXTEND */
++ pGPIO->EINTSEL0 = 0x00000000; // 0x184 R/W 0x00000000 External Interrupt Select Register 01
++ pGPIO->EINTSEL1 = 0x00000000; // 0x188 R/W 0x00000000 External Interrupt Select Register 1
++ pGPIO->EINTSEL2 = 0x00000000; // 0x18C R/W 0x00000000 External Interrupt Select Register 2
++ pGPIO->MON = 0x00000000; // 0x190 R/W 0x00000000 System Monitor Enable Register
++ pGPIO->ECID0 = 0x00000000; // 0x194 R/W 0x00000000 CID output Register
++ pGPIO->ECID1 = 0x00000000; // 0x198 R - CID serial input Register
++ pGPIO->ECID2 = 0x00000000; // 0x19C R - CID parallel input 0 Register
++ pGPIO->ECID3 = 0x00000000;
++}
++
++static void tcc_init_console(void)
++{
++ PUART pUART = (PUART)tcc_p2v(HwUARTCH0_BASE);
++ PGPIO pGPIO = (PGPIO)tcc_p2v(HwGPIO_BASE);
++
++ pUART->LCR = Hw4 | Hw2 | Hw1 | Hw0;
++ pUART->LCR &= ~Hw7; //HwUART0_LCR_DLAB_OFF; //HwUART1_LCR_DLAB_OFF;
++ pUART->REG2.IER = 0;
++ pUART->LCR |= Hw7; //HwUART0_LCR_DLAB_ON;
++ pUART->REG3.FCR = Hw5|Hw4|Hw2|Hw1|Hw0; //HwUART0_FCR_TXFR_EN | HwUART0_FCR_RXFR_EN | HwUART0_FCR_FE_EN;
++ pUART->REG1.DLL = 28;
++ pUART->REG2.DLM = 0;
++ pUART->LCR &= ~Hw7;
++ pUART->REG2.IER = Hw0;
++
++ pGPIO->GPEEN |= (Hw1|Hw0);
++ pGPIO->GPEFN0 |= (Hw4|Hw0); // UTXD0, URXD0
++}
++
++static void tcc_store_gpio(unsigned int gpio_vaddr)
++{
++ int i = 0;
++ PGPIO pGPIO = (PGPIO)gpio_vaddr;
++
++ for(i = 0 ; i < GPIOSIZE-8 ; i++ ) {
++ switch (i % 16) {
++ case 2:
++ case 3:
++ case 4:
++ case 13:
++ case 14:
++ case 15:
++ break;
++ default:
++ bkreg[i] = *((volatile unsigned int *)(gpio_vaddr + 4 * i));
++ break;
++ }
++ }
++
++ bkreg[GPIOSIZE-8] = pGPIO->EINTSEL0;
++ bkreg[GPIOSIZE-8+1] = pGPIO->EINTSEL1;
++ bkreg[GPIOSIZE-8+2] = pGPIO->EINTSEL2;
++ bkreg[GPIOSIZE-8+3] = pGPIO->MON;
++ bkreg[GPIOSIZE-8+4] = pGPIO->ECID0;
++
++ tcc_gpio_default(gpio_vaddr);
++}
++
++static void tcc_restore_gpio(unsigned int gpio_vaddr)
++{
++ int i = 0;
++ PGPIO pGPIO = (PGPIO)gpio_vaddr;
++
++ for (i = 0; i < GPIOSIZE-8; i++) {
++ switch (i % 16) {
++ case 2:
++ case 3:
++ case 4:
++ case 13:
++ case 14:
++ case 15:
++ break;
++ default:
++ *((volatile unsigned int *)(gpio_vaddr + 4 * i)) = bkreg[i];
++ break;
++ }
++ }
++
++ pGPIO->EINTSEL0 = bkreg[GPIOSIZE-8];
++ pGPIO->EINTSEL1 = bkreg[GPIOSIZE-8+1];
++ pGPIO->EINTSEL2 = bkreg[GPIOSIZE-8+2];
++ pGPIO->MON = bkreg[GPIOSIZE-8+3];
++ pGPIO->ECID0 = bkreg[GPIOSIZE-8+4];
++}
++
++
++/*****************************************************************************
++* Function Name : tca_off_sdramselfrefresh()
++* DRAM into Self Refresh
++******************************************************************************/
++static void ddr2_self_refresh(void)
++{
++ volatile unsigned int nCount = 0;
++
++ *(volatile unsigned long *)0xF0102004 |= Hw2; // GPIOADAT == corebus
++ nCount = *(volatile unsigned long *)0xF0102000;
++
++ /* Enter Self-Refresh Mode */
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2) // Wait PL34X_STATUS_PAUSED
++ ;
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=3) // Wait PL34X_STATUS_LOWPOWER
++ ;
++
++ /* To prevent input leakage */
++ *(volatile unsigned long *)0xF0304400 |= 0x00000004;
++ /* DLL OFF */
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ nCount = ((*(volatile unsigned long *)0xF030200C) & ~(0x00004000));
++ *(volatile unsigned long *)0xF030200C = nCount| (1<<14); // Stop-MCLK Enter Self-refresh mode
++
++ for (nCount = 1600; nCount > 0; nCount --) // Wait
++ ;
++
++ *(volatile unsigned long *)0xF0400000 = 0x002ffff4; // CKC-CLKCTRL0 - set cpu clk to XIN
++ *(volatile unsigned long *)0xF0400004 = 0x00200014; // CKC-CLKCTRL1 - set display clk to XIN
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // CKC-CLKCTRL2 - set memory clk to XIN
++ *(volatile unsigned long *)0xF040000c = 0x00200014; // CKC-CLKCTRL3 - set graphic clk to XIN
++ *(volatile unsigned long *)0xF0400010 = 0x00200014; // CKC-CLKCTRL4 - set io clk to XIN
++
++ *(volatile unsigned long *)0xF0400014 = 0x00200014; // CKC-CLKCTRL5 - set video bus clk to XIN
++ *(volatile unsigned long *)0xF0400018 = 0x00200014; // CKC-CLKCTRL6 - set video core clk to XIN
++ *(volatile unsigned long *)0xF040001c = 0x00200014; // CKC-CLKCTRL7 - set SMU clk to XIN
++
++#if 0
++*(volatile unsigned long *)0xF0404000 |= 0x00000002; // PMU-CONTROL - Power Off
++#endif
++
++ *(volatile unsigned long *)0xF0400020 &= ~0x80000000; // CKC-PLL0CFG - PLL disable
++ *(volatile unsigned long *)0xF0400024 &= ~0x80000000; // CKC-PLL1CFG - PLL disable
++ *(volatile unsigned long *)0xF0400028 &= ~0x80000000; // CKC-PLL2CFG - PLL disable
++ *(volatile unsigned long *)0xF040002c &= ~0x80000000; // CKC-PLL3CFG - PLL disable
++
++#if 0
++*(volatile unsigned long *)0xF0404001 = 0x00000000;
++*(volatile unsigned long *)0xF0404002 = 0x00000000;
++*(volatile unsigned long *)0xF0404008 = 0x00000000;
++*(volatile unsigned long *)0xF0404020 = 0x00000000;
++*(volatile unsigned long *)0xF0404000 |= 0x00000002; // PMU-CONTROL - Power Off
++#endif
++
++ while (1) {
++ *(volatile unsigned long *)0xF0102000 &= ~Hw2;
++ *(volatile unsigned long *)0xF0102000 &= ~Hw2;
++ }
++}
++
++/*****************************************************************************
++* Function Name : suspend_mode_on()
++******************************************************************************/
++//static void suspend_mode_on(void)
++void suspend_mode_on(void)
++{
++ volatile unsigned int nCount = 0;
++
++ TCC_REG *p89reg;
++ unsigned int *pVaddr;
++ unsigned int *pPaddr;
++
++ CKC *ckc = (CKC *)tcc_p2v(HwCLK_BASE);
++ PIC *pic = (PIC *)tcc_p2v(HwPIC_BASE);
++ VIC *vic = (VIC *)tcc_p2v(HwVIC_BASE);
++ TIMER *timer = (TIMER *)tcc_p2v(HwTMR_BASE);
++ PMU *pmu = (PMU *)tcc_p2v(HwPMU_BASE);
++ GPIO *gpio = (GPIO *)tcc_p2v(HwGPIO_BASE);
++ //DRAM *dram= (DRAM *)tcc_p2v(HwDRAM_BASE);
++ //DRAMMX *drammx= (DRAMMX *)tcc_p2v(HwDRAM_BASE);
++ //DRAMPHY *dramphy= (DRAMPHY *)tcc_p2v(HwDRAMPHY_BASE);
++ //DRAMMISC *drammisc= (DRAMMISC *)tcc_p2v(HwDRAMMISC_BASE);
++ //DRAMMEMBUS *drammembus= (DRAMMEMBUS *)tcc_p2v(HwDRAMMEMBUS_BASE);
++ MISCCOREBUS *misccorebus= (MISCCOREBUS *)tcc_p2v(HwCORECFG_BASE);
++ IOBUSCFG *iobuscfg= (IOBUSCFG *)tcc_p2v(HwIOBUSCFG_BASE);
++ TSADC *tsadc = (TSADC *)tcc_p2v(HwTSADC_BASE);
++
++ VMTREGION *vmtregion = (VMTREGION *)tcc_p2v(HwREGION_BASE); //twkwon
++
++ //SMUI2CMASTER *smui2cmaster0 = (SMUI2CMASTER*)tcc_p2v(HwSMU_I2CMASTER0_BASE);
++ //SMUI2CMASTER *smui2cmaster1 = (SMUI2CMASTER*)tcc_p2v(HwSMU_I2CMASTER1_BASE);
++ //SMUI2CICLK *smui2ciclk = (SMUI2CICLK*)tcc_p2v(HwSMU_I2CICLK_BASE);
++
++ DDICONFIG *ddiconfig = (DDICONFIG*)tcc_p2v(HwDDI_CONFIG_BASE);
++ DDICACHE *ddicache = (DDICACHE*)tcc_p2v(HwDDI_CACHE_BASE);
++
++ USBHOST11 *usbhost11 = (USBHOST11*)tcc_p2v(HwUSBHOST_BASE);
++ USBHOST11CFG *usbhost11cfg = (USBHOST11CFG*)tcc_p2v(HwUSBHOSTCFG_BASE);
++
++ //USB20OTG *usb20otg = (USB20OTG*)tcc_p2v(HwUSB20OTG_BASE);
++ //USBOTGCFG *usbotgconfig = (USBOTGCFG*)tcc_p2v(HwUSBOTGCFG_BASE);
++ //USBPHYCFG *usbphycfg = (USBPHYCFG*)tcc_p2v(HwUSBPHYCFG_BASE);
++
++ RTC *rtc = (RTC *)tcc_p2v(HwRTC_BASE);
++ //NFC *nfc = (NFC *)tcc_p2v(HwNFC_BASE);
++ //LCDC *lcdc0 = (LCDC *)tcc_p2v(HwLCDC0_BASE);
++ //LCDC *lcdc1 = (LCDC *)tcc_p2v(HwLCDC1_BASE);
++
++ //M2MSCALER *m2mscaler0 = (M2MSCALER *)tcc_p2v(HwM2MSCALER0_BASE);
++ //M2MSCALER *m2mscaler1 = (M2MSCALER *)tcc_p2v(HwM2MSCALER1_BASE);
++
++ UARTPORTMUX *uartportmux = (UARTPORTMUX *)tcc_p2v(HwUARTPORTMUX_BASE);
++
++/*
++ * BACKUP REGISTER
++ */
++ pPaddr = ioremap_nocache(DRAM_PHYS_ADDRESS, PAGE_ALIGN(sizeof(unsigned int)));
++ pVaddr = ioremap_nocache(DRAM_VIRT_ADDRESS, PAGE_ALIGN(sizeof(unsigned int)));
++ p89reg = ioremap_nocache(DRAM_DATA_ADDRESS, PAGE_ALIGN(sizeof(TCC_REG)));
++
++ /* backup iobus state */
++ p89reg->backup_peri_iobus0 = *(volatile unsigned long *)0xF05F5010;
++ p89reg->backup_peri_iobus1 = *(volatile unsigned long *)0xF05F5014;
++ /* all peri io bus on */
++ *(volatile unsigned long *)0xF05F5010 = 0xFFFFFFFF;
++ *(volatile unsigned long *)0xF05F5014 |= 0x7;
++
++ memcpy(&p89reg->ckc, ckc, sizeof(CKC));
++ memcpy(&p89reg->pic, pic, sizeof(PIC));
++ memcpy(&p89reg->vic, vic, sizeof(VIC));
++ memcpy(&p89reg->timer, timer, sizeof(TIMER));
++ memcpy(&p89reg->pmu, pmu, sizeof(PMU));
++ memcpy(&p89reg->gpio, gpio, sizeof(GPIO));
++ //memcpy(&p89reg->dram, dram, sizeof(DRAM));
++ //memcpy(&p89reg->drammx, drammx, sizeof(DRAMMX));
++ //memcpy(&p89reg->dramphy, dramphy, sizeof(DRAMPHY));
++ //memcpy(&p89reg->drammisc, drammisc, sizeof(DRAMMISC));
++ //memcpy(&p89reg->drammembus, drammembus, sizeof(DRAMMEMBUS));
++ memcpy(&p89reg->misccorebus, misccorebus, sizeof(MISCCOREBUS));
++ memcpy(&p89reg->iobuscfg, iobuscfg, sizeof(IOBUSCFG));
++ memcpy(&p89reg->tsadc, tsadc, sizeof(TSADC));
++
++ memcpy(&p89reg->vmtregion, vmtregion, sizeof(VMTREGION)); //twkwon
++
++ //memcpy(&p89reg->smui2cmaster0, smui2cmaster0, sizeof(SMUI2CMASTER));
++ //memcpy(&p89reg->smui2cmaster1, smui2cmaster1, sizeof(SMUI2CMASTER));
++ //memcpy(&p89reg->smui2ciclk, smui2ciclk, sizeof(SMUI2CICLK));
++ memcpy(&p89reg->ddiconfig, ddiconfig, sizeof(DDICONFIG));
++ memcpy(&p89reg->ddicache, ddicache, sizeof(DDICACHE));
++
++ memcpy(&p89reg->usbhost11, usbhost11, sizeof(USBHOST11));
++ memcpy(&p89reg->usbhost11cfg, usbhost11cfg, sizeof(USBHOST11CFG));
++ //memcpy(&p89reg->usb20otg, usb20otg, sizeof(USB20OTG));
++ //memcpy(&p89reg->usbotgconfig, usbotgconfig, sizeof(USBOTGCFG));
++ //memcpy(&p89reg->usbphycfg, usbphycfg, sizeof(USBPHYCFG));
++
++ memcpy(&p89reg->rtc, rtc, sizeof(RTC));
++ //memcpy(&p89reg->nfc, nfc, sizeof(NFC));
++
++ //memcpy(&p89reg->lcdc0, lcdc0, sizeof(LCDC));
++ //memcpy(&p89reg->lcdc1, lcdc1, sizeof(LCDC));
++ //memcpy(&p89reg->m2mscaler0, m2mscaler0, sizeof(M2MSCALER));
++ //memcpy(&p89reg->m2mscaler1, m2mscaler1, sizeof(M2MSCALER));
++
++ memcpy(&p89reg->uartportmux,uartportmux,sizeof(UARTPORTMUX));
++
++ p89reg->uMASK = BSP_SUSPEND_MASK;
++ *pVaddr = (unsigned int)p89reg;
++ *pPaddr = DRAM_DATA_ADDRESS;
++
++#if 0
++ /* flush TLB and I/D cache */
++ local_flush_tlb_all();
++ flush_cache_all();
++ IO_ARM_SaveREG(0x10000000, p89reg, Awake_address);
++#else
++ IO_ARM_SaveREG(SRAM_ADDR_STANDBY, (unsigned int)p89reg, Awake_address);
++#endif
++
++ __asm__ __volatile__ ("nop\n");
++
++/*
++ * RESTORE REGISTER
++ */
++ for (nCount = 100; nCount > 0; nCount --)
++ ;
++
++ /* all peri io bus on */
++ *(volatile unsigned long *)0xF05F5010 = 0xFFFFFFFF;
++ *(volatile unsigned long *)0xF05F5014 |= 0x7;
++
++ ckc = (CKC *)tcc_p2v(HwCLK_BASE);
++ pic = (PIC *)tcc_p2v(HwPIC_BASE);
++ vic = (VIC *)tcc_p2v(HwVIC_BASE);
++ timer = (TIMER *)tcc_p2v(HwTMR_BASE);
++ pmu = (PMU *)tcc_p2v(HwPMU_BASE);
++ gpio = (GPIO *)tcc_p2v(HwGPIO_BASE);
++ //dram= (DRAM *)tcc_p2v(HwDRAM_BASE);
++ //drammx= (DRAMMX *)tcc_p2v(HwDRAM_BASE);
++ //dramphy= (DRAMPHY *)tcc_p2v(HwDRAMPHY_BASE);
++ //drammisc= (DRAMMISC *)tcc_p2v(HwDRAMMISC_BASE);
++ //drammembus= (DRAMMEMBUS *)tcc_p2v(HwDRAMMEMBUS_BASE);
++ misccorebus= (MISCCOREBUS *)tcc_p2v(HwCORECFG_BASE);
++ iobuscfg= (IOBUSCFG *)tcc_p2v(HwIOBUSCFG_BASE);
++ tsadc = (TSADC *)tcc_p2v(HwTSADC_BASE);
++
++ vmtregion = (VMTREGION *)tcc_p2v(HwREGION_BASE); //twkwon
++ //usbphycfg = (USBPHYCFG *)tcc_p2v(HwUSBPHYCFG_BASE);
++
++ //smui2cmaster0 = (SMUI2CMASTER*)tcc_p2v(HwSMU_I2CMASTER0_BASE);
++ //smui2cmaster1 = (SMUI2CMASTER*)tcc_p2v(HwSMU_I2CMASTER1_BASE);
++ //smui2ciclk = (SMUI2CICLK*)tcc_p2v(HwSMU_I2CICLK_BASE);
++
++ ddiconfig = (DDICONFIG*)tcc_p2v(HwDDI_CONFIG_BASE);
++ ddicache = (DDICACHE*)tcc_p2v(HwDDI_CACHE_BASE);
++
++ usbhost11 = (USBHOST11*)tcc_p2v(HwUSBHOST_BASE);
++ usbhost11cfg = (USBHOST11CFG*)tcc_p2v(HwUSBHOSTCFG_BASE);
++
++ //usb20otg = (USB20OTG*)tcc_p2v(HwUSB20OTG_BASE);
++ //usbotgconfig = (USBOTGCFG*)tcc_p2v(HwUSBOTGCFG_BASE);
++ //usbphycfg = (USBPHYCFG*)tcc_p2v(HwUSBPHYCFG_BASE);
++
++ rtc = (RTC *)tcc_p2v(HwRTC_BASE);
++ //nfc = (NFC *)tcc_p2v(HwNFC_BASE);
++ //lcdc0 = (LCDC *)tcc_p2v(HwLCDC0_BASE);
++ //lcdc1 = (LCDC *)tcc_p2v(HwLCDC1_BASE);
++
++ //m2mscaler0 = (M2MSCALER *)tcc_p2v(HwM2MSCALER0_BASE);
++ //m2mscaler1 = (M2MSCALER *)tcc_p2v(HwM2MSCALER1_BASE);
++
++ uartportmux = (UARTPORTMUX *)tcc_p2v(HwUARTPORTMUX_BASE);
++
++ memcpy(ckc, &p89reg->ckc, sizeof(CKC));
++ memcpy(pic, &p89reg->pic, sizeof(PIC));
++ memcpy(vic, &p89reg->vic, sizeof(VIC));
++ memcpy(timer, &p89reg->timer, sizeof(TIMER));
++ memcpy(pmu, &p89reg->pmu, sizeof(PMU));
++ memcpy(gpio, &p89reg->gpio, sizeof(GPIO));
++ //memcpy(dram, &p89reg->dram, sizeof(DRAM));
++ //memcpy(drammx, &p89reg->drammx, sizeof(DRAMMX));
++ //memcpy(dramphy, &p89reg->dramphy, sizeof(DRAMPHY));
++ //memcpy(drammisc, &p89reg->drammisc, sizeof(DRAMMISC));
++ //memcpy(drammembus, &p89reg->drammembus, sizeof(DRAMMEMBUS));
++ memcpy(misccorebus, &p89reg->misccorebus, sizeof(MISCCOREBUS));
++ memcpy(iobuscfg, &p89reg->iobuscfg, sizeof(IOBUSCFG));
++
++ memcpy(tsadc, &p89reg->tsadc, sizeof(TSADC));
++
++ memcpy(vmtregion, &p89reg->vmtregion, sizeof(VMTREGION)); //twkwon
++
++ //memcpy(smui2cmaster0, &p89reg->smui2cmaster0, sizeof(SMUI2CMASTER));
++ //memcpy(smui2cmaster1, &p89reg->smui2cmaster1, sizeof(SMUI2CMASTER));
++ //memcpy(smui2ciclk, &p89reg->smui2ciclk, sizeof(SMUI2CICLK));
++ memcpy(ddiconfig, &p89reg->ddiconfig, sizeof(DDICONFIG));
++ memcpy(ddicache, &p89reg->ddicache, sizeof(DDICACHE));
++
++ memcpy(usbhost11, &p89reg->usbhost11, sizeof(USBHOST11));
++ memcpy(usbhost11cfg, &p89reg->usbhost11cfg, sizeof(USBHOST11CFG));
++ //memcpy(usb20otg, &p89reg->usb20otg, sizeof(USB20OTG));
++ //memcpy(usbotgconfig, &p89reg->usbotgconfig, sizeof(USBOTGCFG));
++ //memcpy(usbphycfg, &p89reg->usbphycfg, sizeof(USBPHYCFG));
++
++ memcpy(rtc, &p89reg->rtc, sizeof(RTC));
++ //memcpy(nfc, &p89reg->nfc, sizeof(NFC));
++
++ //memcpy(lcdc0, &p89reg->lcdc0, sizeof(LCDC));
++ //memcpy(lcdc1, &p89reg->lcdc1, sizeof(LCDC));
++ //memcpy(m2mscaler0, &p89reg->m2mscaler0, sizeof(M2MSCALER));
++ //memcpy(m2mscaler1, &p89reg->m2mscaler1, sizeof(M2MSCALER));
++
++ memcpy(uartportmux, &p89reg->uartportmux, sizeof(UARTPORTMUX));
++
++ //all peri io bus restore
++ *(volatile unsigned long *)0xF05F5010 = p89reg->backup_peri_iobus0;
++ *(volatile unsigned long *)0xF05F5014 = p89reg->backup_peri_iobus1;
++
++ iounmap(pPaddr);
++ iounmap(pVaddr);
++ iounmap(p89reg);
++}
++
++/************************************************************************************************
++* FUNCTION : sleep_mode_on
++* DESCRIPTION : This Function have to be executed in SRAM.
++* All Registers related to Clock are Backed up.
++************************************************************************************************/
++static void sleep_mode_on(int type)
++{
++ volatile unsigned int nCount = 0;
++
++ unsigned long *lPLL0, *lPLL1, *lPLL2, *lPLL3;
++ unsigned long *lFBUS_CORE, *lFBUS_MEM, *lFBUS_DDI, *lFBUS_GRP, *lFBUS_IOB, *lFBUS_VBUS, *lFBUS_VCODEC, *lFBUS_SMU;
++ unsigned long *i, *pPCK, *BAKPCK;
++
++ unsigned long *BACK4, *BACK5; //for pmu backup
++
++ int lmem_div = 0;
++ int lmem_source = 0;
++ int tmpread = *(volatile unsigned long *)0xF0400008;
++
++ tmpread &= ~0x00200000;
++ lmem_source = tmpread & 0xf;
++ tmpread &= 0xf0;
++
++ while (tmpread) {
++ tmpread -= 16;
++ lmem_div++;
++ }
++
++ lmem_div += 1;
++
++ /* Let CPU Speed Lower, Low Clock Operation */
++ /* Assign Registers to Pointers */
++ lPLL0 = (unsigned long *)(SRAM_ADDR_VAR);
++ lPLL1 = (unsigned long *)(SRAM_ADDR_VAR + 0x04);
++ lPLL2 = (unsigned long *)(SRAM_ADDR_VAR + 0x08);
++ lPLL3 = (unsigned long *)(SRAM_ADDR_VAR + 0x0C);
++ BACK4 = (unsigned long *)(SRAM_ADDR_VAR + 0x10);
++ BACK5 = (unsigned long *)(SRAM_ADDR_VAR + 0x14);
++ lFBUS_CORE = (unsigned long *)(SRAM_ADDR_VAR + 0x18);
++ lFBUS_MEM = (unsigned long *)(SRAM_ADDR_VAR + 0x1C);
++ lFBUS_DDI = (unsigned long *)(SRAM_ADDR_VAR + 0x20);
++ lFBUS_GRP = (unsigned long *)(SRAM_ADDR_VAR + 0x24);
++ lFBUS_IOB = (unsigned long *)(SRAM_ADDR_VAR + 0x28);
++ lFBUS_VBUS = (unsigned long *)(SRAM_ADDR_VAR + 0x30);
++ lFBUS_VCODEC = (unsigned long *)(SRAM_ADDR_VAR + 0x34);
++ lFBUS_SMU = (unsigned long *)(SRAM_ADDR_VAR + 0x38);
++ i = (unsigned long *)(SRAM_ADDR_VAR + 0x3C);
++ BAKPCK = (unsigned long *)(SRAM_ADDR_VAR + 0x40);
++
++ *lFBUS_CORE = *(volatile unsigned long *)0xF0400000;
++ *lFBUS_DDI = *(volatile unsigned long *)0xF0400004;
++ *lFBUS_MEM = *(volatile unsigned long *)0xF0400008;
++ *lFBUS_GRP = *(volatile unsigned long *)0xF040000C;
++ *lFBUS_IOB = *(volatile unsigned long *)0xF0400010;
++ *lFBUS_VBUS = *(volatile unsigned long *)0xF0400014;
++ *lFBUS_VCODEC = *(volatile unsigned long *)0xF0400018;
++ *lFBUS_SMU = *(volatile unsigned long *)0xF040001C;
++
++ *lPLL0 = *(volatile unsigned long *)0xF0400020;
++ *lPLL1 = *(volatile unsigned long *)0xF0400024;
++ *lPLL2 = *(volatile unsigned long *)0xF0400028;
++ *lPLL3 = *(volatile unsigned long *)0xF040002c;
++
++ /* Save All of PCK_XXX Register */
++ pPCK = (unsigned long *)(0xF0400080);
++
++ for (*i = 0; *i < 37; (*i)++ ) {
++ BAKPCK[*i] = *pPCK;
++ if (((BAKPCK[*i] & 0x1f000000) != 0x14000000)) {
++ *pPCK = (BAKPCK[*i] & ~0x10000000);
++ }
++ pPCK++;
++ }
++
++ *BACK4 = *(volatile unsigned long *)0xF0404004;
++ *BACK5 = *(volatile unsigned long *)0xF0404000;
++ *BACK5 = *(volatile unsigned long *)0xF0240050;
++
++ *BACK4 = (*(volatile unsigned long *)0xF0404018) & 0xFF;
++
++ /* Enter Self-Refresh Mode */
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2) //Wait PL34X_STATUS_PAUSED
++ ;
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=3) // Wait PL34X_STATUS_LOWPOWER
++ ;
++
++ /* To prevent input leakage */
++ *(volatile unsigned long *)0xF0304400 |= 0x00000004;
++
++ /* DLL OFF */
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302c &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ nCount = ((*(volatile unsigned long *)0xF030200C) & ~(0x00004000));
++ *(volatile unsigned long *)0xF030200C = nCount| (1<<14); // Stop-MCLK Enter Self-refresh mode
++
++ /* DRAM controller power down */
++ *(volatile unsigned long *)0xF030302C =0x3fff;
++ *(volatile unsigned long *)0xF030302C &= ~Hw14;
++ for (nCount = 0; nCount < 10; nCount++)
++ ;
++ *(volatile unsigned long *)0xF0304400 = 0x2;
++ for (nCount = 0; nCount < 10; nCount++)
++ ;
++ *(volatile unsigned long *)0xF0304404 &= ~(Hw0|Hw1);
++ *(volatile unsigned long *)0xF0304428 &= ~(Hw0|Hw1);
++ *(volatile unsigned long *)0xF0304428 |= Hw12;
++ *(volatile unsigned long *)0xF0304428 |= Hw0;
++
++ *(volatile unsigned long *)0xF0304400 = 0x6;
++
++ for (nCount = 800; nCount > 0; nCount --) // Wait
++ ;
++ for (nCount = 800; nCount > 0; nCount --) // Wait
++ ;
++
++ *(volatile unsigned long *)0xF0400000 = 0x002ffff4; // CKC-CLKCTRL0 - set cpu clk to XIN
++ *(volatile unsigned long *)0xF0400004 = 0x00200014; // CKC-CLKCTRL1 - set display clk to XIN
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // CKC-CLKCTRL2 - set memory clk to XIN
++
++ *(volatile unsigned long *)0xF040000c = 0x00200014; // CKC-CLKCTRL3 - set graphic clk to XIN
++ *(volatile unsigned long *)0xF0400010 = 0x00200014; // CKC-CLKCTRL4 - set io clk to XIN
++
++ *(volatile unsigned long *)0xF0400014 = 0x00200014; // CKC-CLKCTRL5 - set video bus clk to XIN
++ *(volatile unsigned long *)0xF0400018 = 0x00200014; // CKC-CLKCTRL6 - set video core clk to XIN
++ *(volatile unsigned long *)0xF040001c = 0x00200014; // CKC-CLKCTRL7 - set SMU clk to XIN
++
++ *(volatile unsigned long *)0xF0400020 &= ~0x80000000; // CKC-PLL0CFG - PLL disable
++ *(volatile unsigned long *)0xF0400024 &= ~0x80000000; // CKC-PLL1CFG - PLL disable
++ *(volatile unsigned long *)0xF0400028 &= ~0x80000000; // CKC-PLL2CFG - PLL disable
++ *(volatile unsigned long *)0xF040002c &= ~0x80000000; // CKC-PLL3CFG - PLL disable
++
++ for (nCount = 100; nCount > 0 ;nCount --); // Wait
++
++ /* go power down mode...... */
++
++ *(volatile unsigned long *)0xF01020EC &= ~(0x00000f00);
++ *(volatile unsigned long *)0xF01020C4 &= ~(0x00040000);
++
++ if(type == 0)
++ {
++ *(volatile unsigned long *)0xF0404008 = 0x00002800; // PMU-WKUPPOL - SRCS[15](GPIO A3) active low
++ *(volatile unsigned long *)0xF0404004 = 0x00002800; // PMU-WKUPEN - SRCS[15](GPIO A3) enable
++ }else if(type == 1)
++ {
++ *(volatile unsigned long *)0xF0404008 = 0x00000800;
++ *(volatile unsigned long *)0xF0404004 = 0x00000800;
++
++ }else if(type == 2)
++ {
++ *(volatile unsigned long *)0xF0404008 = 0x00002000;
++ *(volatile unsigned long *)0xF0404004 = 0x00002000;
++ }else
++ {
++ *(volatile unsigned long *)0xF0404008 = 0x00002800;
++ *(volatile unsigned long *)0xF0404004 = 0x00002800;
++ }
++
++#ifdef BUS_CONTROL
++ *(volatile unsigned long *)0xF0240050 |= Hw0;
++ *(volatile unsigned long *)0xF0404018 &= ~0x1F;
++ for (nCount = 5000; nCount > 0; nCount --) // delay
++ ;
++ *(volatile unsigned long *)0xF0404018 |= 0x1F;
++
++ /* Video Bus, DDi Bus, Graphic Bus, IO Bus off */
++ /* SWRESET ON */
++// *(volatile unsigned long *)0xF0400044 |= Hw6|Hw5; // Graphic Bus
++// *(volatile unsigned long *)0xF0400044 |= Hw3; // Video Bus
++// *(volatile unsigned long *)0xF0400044 |= Hw1; // Ddi Bus
++// for (nCount = 5000; nCount > 0; nCount --) // delay
++// ;
++
++ /* pmu disable */
++// *(volatile unsigned long *)0xF0404018 |= Hw8; // Graphic Bus
++// *(volatile unsigned long *)0xF0404018 |= Hw6; // Video Bus
++// *(volatile unsigned long *)0xF0404018 |= Hw7; // Ddi Bus
++
++ for (nCount = 1000; nCount > 0; nCount --) // Wait
++ ;
++#endif
++
++ *(volatile unsigned long *)0xF0404000 |= 0x00000004; // PMU-CONTROL - Power Down(BSP default)
++ for (nCount = 10; nCount > 0; nCount --) // Wait
++ ;
++
++ *(volatile unsigned long *)0xF0400020 = *lPLL0;
++ *(volatile unsigned long *)0xF0400024 = *lPLL1;
++ *(volatile unsigned long *)0xF0400028 = *lPLL2;
++ *(volatile unsigned long *)0xF040002c = *lPLL3;
++
++ /* wakeup start */
++#ifdef BUS_CONTROL
++ for (nCount = 1000; nCount > 0; nCount --) // Wait
++ ;
++ /* pmu disable */
++// *(volatile unsigned long *)0xF0404018 &= ~Hw8; // Graphic Bus
++// *(volatile unsigned long *)0xF0404018 &= ~Hw6; // Video Bus
++// *(volatile unsigned long *)0xF0404018 &= ~Hw7; // Ddi Bus
++// for (nCount = 10000; nCount > 0; nCount --) // delay
++// ;
++
++ /* SWRESET OFF */
++// *(volatile unsigned long *)0xF0400044 &= ~(Hw6|Hw5); // Graphic Bus
++// *(volatile unsigned long *)0xF0400044 &= ~(Hw3); // Video Bus
++// *(volatile unsigned long *)0xF0400044 &= ~(Hw1); // Ddi Bus
++ *(volatile unsigned long *)0xF0404018 = *BACK4;
++ *(volatile unsigned long *)0xF0240050 = *BACK5;
++#endif
++
++ for (nCount = 10; nCount > 0; nCount --) // Wait
++ ;
++
++ *(volatile unsigned long *)0xF0400000 = *lFBUS_CORE;
++ *(volatile unsigned long *)0xF0400008 = *lFBUS_MEM;
++
++ pPCK = (unsigned long*)(0xF0400080);
++
++ for((*i) = 0; (*i) < 37; (*i)++) {
++ *pPCK++ = BAKPCK[*i];
++ }
++
++ for (nCount = 0x100; nCount > 0; nCount --) // Wait
++ ;
++
++ *(volatile unsigned long *)0xF0400004 = *lFBUS_DDI;
++ *(volatile unsigned long *)0xF040000C = *lFBUS_GRP;
++ *(volatile unsigned long *)0xF0400010 = *lFBUS_IOB;
++ *(volatile unsigned long *)0xF0400014 = *lFBUS_VBUS;
++ *(volatile unsigned long *)0xF0400018 = *lFBUS_VCODEC;
++ *(volatile unsigned long *)0xF040001C = *lFBUS_SMU;
++
++ /* Exit Self-Refresh Mode */
++ *(volatile unsigned long *)0xF030200C &= ~(0x00004000);
++ *(volatile unsigned long *)0xF0304400 &= ~(0x00000004);
++
++ //*(volatile unsigned long *)0xF0302004 = 0x00000002; // PL341_WakeUP
++ //while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++ //*(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ //while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++ //*(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ //while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++ //*(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ //while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=3); // Wait PL34X_STATUS_LOWPOWER
++
++ /* DLL ON */
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++ *(volatile unsigned long *)0xF0303020 |= 0x00000001; // Common Register AXI_SEL
++ *(volatile unsigned long *)0xF0303020 |= 0x00000002; // Common Register IO_SEL
++ *(volatile unsigned long *)0xF0303024 &= ~(0x00000100); // PHYCTRL Seletct DDR2
++
++ *(volatile unsigned long *)0xF0304400 = 0x0;
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLL-On
++
++ /* 330Mhz */
++ if (lmem_div == 1) {
++ if ((*lPLL0/1) >= 400 && lmem_source == 0) {
++ *(volatile unsigned long *)0xF0304408 = 0x00001212; // DLLPDCFG
++ } else {
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++ }
++ } else {
++ if ((*lPLL0/2) >= 400 && lmem_source == 0) {
++ *(volatile unsigned long *)0xF0304408 = 0x00001212; // DLLPDCFG
++ } else {
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++ }
++ }
++
++
++ //*(volatile unsigned long *)0xF0304408 = 0x00001414; // DLLPDCFG
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLL-On, DLL-Start
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)) // Wait DLL Lock
++ ;
++
++ *(volatile unsigned long *)0xF0304424 = 0x35; // DLL Force Lock Value Register
++ *(volatile unsigned long *)0xF030440C = 0x6; // Gate Control
++
++ if (lmem_div == 1) {
++ if ((*lPLL0/1) >= 400 && lmem_source == 0) {
++ *(volatile unsigned long *)0xF0304430 = 0x1; // uRDDELAY Read Delay Register
++ } else {
++ *(volatile unsigned long *)0xF0304430 = 0x4; // uRDDELAY Read Delay Register
++ }
++ } else {
++ if ((*lPLL0/2) >= 400 && lmem_source == 0) {
++ *(volatile unsigned long *)0xF0304430 = 0x1; // uRDDELAY Read Delay Register
++ } else {
++ *(volatile unsigned long *)0xF0304430 = 0x4; // uRDDELAY Read Delay Register
++ }
++ }
++
++ /*
++ *(volatile unsigned long *)0xF0304428 = 0
++ | (0x1 << 0) // Calibration Start
++ | (0x0 << 1) // Update Calibration
++ | (0x0 << 2) // Override ctrl_force_impp[2:0]/impn[2:0]
++ | (0x2 << 3) // Calibration PULL-UP forced value
++ | (0x5 << 6) // Calibration PULL-DOWN forced value
++ | (0x0 << 9) // On-Die Termination Resistor Value Selection
++ | (0x1 << 12) // Termination Selection : 0 for disable
++ | (0x4 << 13) // Drive Strength
++ | (0x0 << 16) // Periodic Calibration
++ | (0x3 << 17) // Update Counter Load Value
++ ;
++ */
++
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ /* ZQCalWait */
++ while (((*(volatile unsigned long *)0xF030442C & (0x00000001)) != (0x00000001)))
++ ;
++
++ /* ZQCalUpdate */
++ *(volatile unsigned long *)0xF0304428 |= 0x00000002;
++ *(volatile unsigned long *)0xF0304428 &= ~0x00000002;
++ /* END DLL On */
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL341_WakeUP
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3) != 2) //Wait PL34X_STATUS_PAUSED
++ ;
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3) != 0) //Wait PL34X_STATUS_CONFIG
++ ;
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3) != 1) //Wait PL34X_STATUS_READY
++ ;
++}
++
++/************************************************************************************************
++* FUNCTION : copy_func_to_sram
++*
++* DESCRIPTION : This Function copies sleep_mode_on Function to SRAM.
++* mode 0: sleep mode, mode 1: suspend mode
++*
++************************************************************************************************/
++extern int noneed_respond;
++extern int sleep_type;
++extern void set_hdmi_en(int sw);
++static void copy_func_to_sram(int mode)
++{
++ volatile unsigned int *fPtr, *p;
++ int i, hdmi_change = 0;
++
++ PTIMER vTimerAddr = (PTIMER)((unsigned int)&HwTMR_BASE);
++ PGPIO vGpioAddr = (PGPIO)((unsigned int)&HwGPIO_BASE);
++ /*
++ * copy function sleep_mode_on to SRAM
++ */
++
++ if (1) {
++ fPtr = (volatile unsigned int *)sleep_mode_on;
++ lpSelfRefresh = (lpfunc)SRAM_ADDR_STANDBY;
++ p = (volatile unsigned int *)SRAM_ADDR_STANDBY;
++
++ for (i = 0; i < SRAM_FUNC_SIZE; i++) {
++ *(p++) = *(fPtr++);
++ }
++
++ while (--i)
++ ;
++
++ if(gpio_get_value(GPIO_HDMI_EN))
++ {
++ hdmi_change = 1;
++ set_hdmi_en(0);
++ }
++
++ noneed_respond = 1;// ignore first touch when wakeup
++
++ *(volatile unsigned long *)0xF0102024 &= ~(0xff0000);// set gpio func
++ *(volatile unsigned long *)0xF0102004 |= 0x30;// set GPIOA4 and GPIOA5 as output
++ *(volatile unsigned long *)0xF0102000 &= ~(0x30);//turn off lcd power and backlight
++
++ // Jump to SRAM excute self-refresh mode
++ lpSelfRefresh(sleep_type);
++
++ *(volatile unsigned long *)0xF0102000 |= 0x10;//turn on a4
++ tca_bkl_powerup((unsigned int)vTimerAddr,(unsigned int)vGpioAddr);//turn on backlight
++
++ if(hdmi_change)
++ set_hdmi_en(1);
++
++ } else if (mode == BSP_SUSPEND_KEY) {
++ fPtr = (volatile unsigned int *)ddr2_self_refresh;
++ p = (volatile unsigned int *)SRAM_ADDR_STANDBY;
++
++ for (i = 0; i < SRAM_FUNC_SIZE; i++) {
++ *(p++) = *(fPtr++);
++ }
++
++ while (--i)
++ ;
++
++ suspend_mode_on();
++ }
++}
++
++void enter_sleep_mode(void)
++{
++ unsigned int temp;
++ PGPIO pGPIO = (PGPIO)tcc_p2v(HwGPIO_BASE);
++
++ volatile PLCDC pLCDC_BASE0 = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++ volatile PLCDC pLCDC_BASE1 = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++
++// tcc_store_gpio((unsigned int)pGPIO);
++
++ temp = *(volatile unsigned long *)0xF0102024; // GPIOAFN == corebus
++ temp = *(volatile unsigned long *)0xF0102004; //
++ temp = *(volatile unsigned long *)0xF0230000;
++ temp = *(volatile unsigned long *)0xF0404018;
++ temp = *(volatile unsigned long *)0xF0400044;
++
++ temp = *(volatile unsigned long *)0xF0400000;
++ temp = *(volatile unsigned long *)0xF0400004;
++ temp = *(volatile unsigned long *)0xF0400008;
++ temp = *(volatile unsigned long *)0xF040000c;
++ temp = *(volatile unsigned long *)0xF0400010;
++ temp = *(volatile unsigned long *)0xF0400014;
++ temp = *(volatile unsigned long *)0xF0400018;
++ temp = *(volatile unsigned long *)0xF040001c;
++
++ temp = *(volatile unsigned long *)0xF0240050;
++ temp = *(volatile unsigned long *)0xF030302C;
++ temp = *(volatile unsigned long *)0xF0304400;
++ temp = *(volatile unsigned long *)0xF0304404;
++ temp = *(volatile unsigned long *)0xF0304428;
++
++ pLCDC_BASE1->LCTRL &= ~Hw0;
++// pLCDC_BASE0->LCTRL &= ~Hw0;
++
++ copy_func_to_sram(BSP_SLEEP_KEY);
++
++ pLCDC_BASE1->LCTRL |= Hw0;
++
++// tcc_restore_gpio((unsigned int)pGPIO);
++
++ tcc_init_console();
++}
++EXPORT_SYMBOL(enter_sleep_mode);
++
++void enter_suspend_mode(void)
++{
++ unsigned int temp;
++
++ temp = *(volatile unsigned long *)0xF0400000; // pll0 == corebus
++ temp = *(volatile unsigned long *)0xF0102024; // GPIOAFN == corebus
++ temp = *(volatile unsigned long *)0xF0102004; // GPIOAEN == corebus
++ temp = *(volatile unsigned long *)0xF0102000; // GPIOADAT == corebus
++
++ temp = *(volatile unsigned long *)0xF05F5010; // iobus
++ temp = *(volatile unsigned long *)0xF05F5014; // iobus
++
++#if 1
++// test
++ temp = *(volatile unsigned long *)0xF0302004; // PL341_PAUSE
++ temp = *(volatile unsigned long *)0xF0302000; // Wait PL34X_STATUS_PAUSED
++ temp = *(volatile unsigned long *)0xF0304400;
++ temp = *(volatile unsigned long *)0xF0304404; // DLL-0FF,DLL-Stop running
++ temp = *(volatile unsigned long *)0xF0304428; // Calibration Start,Update Calibration
++ temp = *(volatile unsigned long *)0xF030302C; //SDRAM IO Control Register Gatein Signal Power Down
++ temp = *(volatile unsigned long *)0xF030200C;
++ temp = *(volatile unsigned long *)0xF0400004; // CKC-CLKCTRL1 - set display clk to XIN
++ temp = *(volatile unsigned long *)0xF0400008; // CKC-CLKCTRL2 - set memory clk to XIN
++ temp = *(volatile unsigned long *)0xF040000c; // CKC-CLKCTRL3 - set graphic clk to XIN
++ temp = *(volatile unsigned long *)0xF0400010; // CKC-CLKCTRL4 - set io clk to XIN
++ temp = *(volatile unsigned long *)0xF0400014; // CKC-CLKCTRL5 - set video bus clk to XIN
++ temp = *(volatile unsigned long *)0xF0400018; // CKC-CLKCTRL6 - set video core clk to XIN
++ temp = *(volatile unsigned long *)0xF040001c; // CKC-CLKCTRL7 - set SMU clk to XIN
++ temp = *(volatile unsigned long *)0xF0400020; // CKC-PLL0CFG - PLL disable
++ temp = *(volatile unsigned long *)0xF0400024; // CKC-PLL1CFG - PLL disable
++ temp = *(volatile unsigned long *)0xF0400028; // CKC-PLL2CFG - PLL disable
++ temp = *(volatile unsigned long *)0xF040002c; // CKC-PLL3CFG - PLL disable
++#endif
++
++ copy_func_to_sram(BSP_SUSPEND_KEY);
++}
++
++#if 0
++/************************************************************************************************
++* FUNCTION : tcc_pm
++*
++* DESCRIPTION : It is called by Power key driver.
++*
++************************************************************************************************/
++int tcc_pm(int mode)
++{
++ int err = 0;
++ unsigned long save_cpsr;
++ // PTIMER vTimerAddr = (PTIMER)((unsigned int)&HwTMR_BASE);
++ // PGPIO vGpioAddr = (PGPIO)((unsigned int)&HwGPIO_BASE);
++
++ /*
++ * all filesystem flush especially SD/MMC
++ */
++ sys_sync();
++
++ /*
++ * send SUSPEND message to all platform driver
++ */
++ err = device_suspend(PMSG_SUSPEND);
++ if (err){
++ printk("device_suspend() fail\n");
++ goto exit;
++ }
++
++ /*
++ * Before enter Power Down Mode, MUST mask CPSR Irq bit
++ */
++ local_irq_save(save_cpsr);
++ local_irq_disable();
++
++ if (mode == BSP_SUSPEND_KEY) {
++ enter_suspend_mode();
++ } else if (mode == BSP_SLEEP_KEY) {
++ enter_sleep_mode();
++ }
++
++ /*
++ * backlight ON
++ */
++ //tca_bkl_init((unsigned int)vTimerAddr, (unsigned int)vGpioAddr);
++ //tca_bkl_powerup((unsigned int)vTimerAddr,(unsigned int)vGpioAddr);
++
++ /*
++ * console init
++ */
++ tcc_init_console();
++
++ /*
++ * restore CPSR Irq bit
++ */
++ local_irq_restore(save_cpsr);
++
++ /*
++ * send RESUME message to all platform driver
++ */
++ device_resume(PMSG_RESUME);
++
++exit:
++ return err;
++}
++EXPORT_SYMBOL(tcc_pm);
++#endif
++
++#if 0 /* comment by csduan */
++#define TCC_PM_STATE_NORMAL 0x249
++static int tcc_power_state = TCC_PM_STATE_NORMAL;
++static int tcc_pm_enter(suspend_state_t state)
++{
++ if (tcc_power_state == BSP_SUSPEND_KEY) {
++ enter_suspend_mode();
++ } else if (tcc_power_state == BSP_SLEEP_KEY) {
++ enter_sleep_mode();
++ }
++
++ tcc_init_console();
++ return 0;
++}
++
++static int tcc_pm_begin(suspend_state_t state)
++{
++ return 0;
++}
++
++static int tcc_pm_prepare(void)
++{
++ return 0;
++}
++
++static void tcc_pm_finish(void)
++{
++}
++
++static struct platform_suspend_ops tcc_pm_ops = {
++ .valid = suspend_valid_only_mem,
++ .begin = tcc_pm_begin,
++ .prepare = tcc_pm_prepare,
++ .enter = tcc_pm_enter,
++ .finish = tcc_pm_finish,
++};
++
++static void tcc_pm_power_off(void)
++{
++ while (1)
++ ;
++}
++
++static int __init tcc_pm_init(void)
++{
++ pm_power_off = tcc_pm_power_off;
++ suspend_set_ops(&tcc_pm_ops);
++ return 0;
++}
++__initcall(tcc_pm_init);
++
++#endif /* comment by csduan */
+diff --git a/arch/arm/mach-tcc8900/pm.h b/arch/arm/mach-tcc8900/pm.h
+new file mode 100644
+index 0000000..4008b26
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/pm.h
+@@ -0,0 +1,186 @@
++/*
++ * arch/arm/mach-tcc8900/pm.h
++ *
++ * Author: <linux@telechips.com>
++ * Created: April 21, 2008
++ * Description: LINUX POWER MANAGEMENT FUNCTIONS
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * 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
++ *
++ */
++#ifndef __TCC_PM_H__
++#define __TCC_PM_H__
++
++#define BSP_SUSPEND_MASK 0x424E4654 /* "TFNB" */
++
++#define BSP_SUSPEND_KEY 0x2491
++#define BSP_SLEEP_KEY 0x2492
++
++/* SRAM (on-chip 16KB) addr: physical 0x10000000 -> virtual 0xEFF00000 */
++#define SRAM_ADDR_STANDBY 0xEFF00000
++#define SRAM_ADDR_VAR 0xEFF01000
++#define SRAM_FUNC_SIZE 0x300
++
++/* SDRAM start address for backup (kernel start - MMU(1MB) - 1MB) */
++#define DRAM_PHYS_ADDRESS 0x40100000
++#define DRAM_VIRT_ADDRESS 0x40100004
++#define DRAM_DATA_ADDRESS 0x40100008
++
++
++
++typedef struct _TCC_REG_{
++ unsigned int uMASK; // 0x00
++
++ unsigned int SleepState_WakeAddr; // 0x04
++
++ unsigned int SleepState_SYSCTL; // 0x08
++ unsigned int SleepState_MMUTTB0; // 0x0C
++ unsigned int SleepState_MMUTTB1; // 0x10
++ unsigned int SleepState_MMUTTBCTL; // 0x14
++ unsigned int SleepState_MMUDOMAIN; // 0x18
++
++ unsigned int SleepState_SVC_SP; // 0x1C
++ unsigned int SleepState_SVC_SPSR; // 0x20
++ unsigned int SleepState_FIQ_SPSR; // 0x24
++ unsigned int SleepState_FIQ_R8; // 0x28
++ unsigned int SleepState_FIQ_R9; // 0x2C
++ unsigned int SleepState_FIQ_R10; // 0x30
++ unsigned int SleepState_FIQ_R11; // 0x34
++ unsigned int SleepState_FIQ_R12; // 0x38
++ unsigned int SleepState_FIQ_SP; // 0x3C
++ unsigned int SleepState_FIQ_LR; // 0x40
++ unsigned int SleepState_ABT_SPSR; // 0x44
++ unsigned int SleepState_ABT_SP; // 0x48
++ unsigned int SleepState_ABT_LR; // 0x4C
++ unsigned int SleepState_IRQ_SPSR; // 0x50
++ unsigned int SleepState_IRQ_SP; // 0x54
++ unsigned int SleepState_IRQ_LR; // 0x58
++ unsigned int SleepState_UND_SPSR; // 0x5C
++ unsigned int SleepState_UND_SP; // 0x60
++ unsigned int SleepState_UND_LR; // 0x64
++ unsigned int SleepState_SYS_SP; // 0x68
++ unsigned int SleepState_SYS_LR; // 0x70
++
++ unsigned int SleepState_SVC_LR; // 0x7C
++ unsigned int temp; // 0x80
++
++ CKC ckc;
++ PIC pic;
++ VIC vic;
++ TIMER timer;
++ PMU pmu;
++
++ //SMUI2CMASTER smui2cmaster0;
++ //SMUI2CMASTER smui2cmaster1;
++ //SMUI2CICLK smui2ciclk;
++
++ GPIO gpio;
++ //DRAM dram;
++ //DRAMMX drammx;
++ //DRAMPHY dramphy;
++ //DRAMMISC drammisc;
++ //DRAMMEMBUS drammembus;
++ MISCCOREBUS misccorebus;
++ VMTREGION vmtregion;
++ //SMSHC smshc;
++ //SMSHCPORTCFG smshcportcfg;
++ //SDHOST sdhost;
++ //SDCHCTRL sdchctrl;
++ //NFC nfc;
++ //SMC smc;
++ //EDI edi;
++ //IDE ide;
++ //SATA sata;
++ //ADMA adma;
++ //ADMADAI admadai;
++ //ADMACDIF admacdif;
++ //ADMASPDIFTX admaspdiftx;
++ //RXCAP rxcap;
++ //ADMASPDIFRX admaspdifrx
++ //DAI dai;
++ //CDIF cdif;
++ //SPDIF spdif;
++
++ USBHOST11 usbhost11;
++ USBHOST11CFG usbhost11cfg;
++ //USB20OTG usb20otg;
++ //USBOTG usbotg;
++ //USBOTGCFG usbotgconfig;
++ //USBPHYCFG usbphycfg;
++
++ //EHI ehi;
++ //GPSB gpsb;
++ //GPSBPIDTABLE gpsbpidtable;
++ //TSIF tsif;
++ //TSIFPORTSEL tsifportsel;
++ //REMOTECON remotecon;
++ //I2CMASTER i2cmaster;
++ //I2C i2c;
++ //I2CSLAVE i2cslave;
++ //I2CSTATUS i2cstatus;
++ //UART uart0;
++ //UART uart1;
++ //UART uart2;
++ //UART uart3;
++ //UART uart4;
++ //UART uart5;
++ UARTPORTMUX uartportmux;
++ //CANCTRL canctrl;
++ //GDMACTRL gdmactrl0;
++ //GDMACTRL gdmactrl1;
++ //GDMACTRL gdmactrl2;
++ //GDMACTRL gdmactrl3;
++ RTC rtc;
++ TSADC tsadc;
++ //ECC ecc;
++ //SLCECC slcecc;
++ //MPEFEC mpefec
++ IOBUSCFG iobuscfg;
++ //EMC emc;
++ //LCDC lcdc0;
++ //LCDC lcdc1;
++ //LCDSI0 lcdsi0;
++ //LCDSI1 lcdsi1;
++ //M2MSCALER m2mscaler0;
++ //M2MSCALER m2mscaler1;
++ //NTSCPAL ntscpal;
++ //HDMICTRL hdmictrl;
++ //HDMICORE hdmicore;
++ //HDMIAES hdmiaes;
++ //HDMISPDIF hdmispdif;
++ //HDMII2S hdmii2s;
++ //HDMICEC hdmicec;
++ //CIF cif;
++ //EFFECT effect;
++ //CIFSACLER cifsacler;
++ //VIQE viqe;
++ DDICONFIG ddiconfig;
++ DDICACHE ddicache;
++ //JPEGENCODER jpegencoder;
++ //JPEGDECODER jpegdecoder;
++ //OVERLAYMIXER overlaymixer;
++ //GPUPIXELPROCESSOR gpupixelprocessor;
++ //GPUGEOMETRYPROCESSOR gpugeometryprocessor;
++ //GPUPLBCFG gpuplbcfg;
++ //GPUMMUCONFIG gpummuconfig;
++ //GPUGRPBUSCONFIG gpugrpbusconfig;
++ //GPUGRPBUSBWRAP gpugrpbusbwrap;
++ volatile unsigned int backup_peri_iobus0;
++ volatile unsigned int backup_peri_iobus1;
++} TCC_REG, *PTCC_REG;
++
++#endif /*__TCC_PM_H__*/
+diff --git a/arch/arm/mach-tcc8900/pm_asm.S b/arch/arm/mach-tcc8900/pm_asm.S
+new file mode 100644
+index 0000000..aacce2a
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/pm_asm.S
+@@ -0,0 +1,283 @@
++/*
++ * linux/arch/arm/mach-tcc8900/pm_asm.S
++ *
++ * Author: <linux@telechips.com>
++ * Created: October, 2009
++ * Description: LINUX POWER MANAGEMENT FUNCTIONS
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <linux/linkage.h>
++#include <asm/ptrace.h>
++
++
++#define Mode_USR 0x10
++#define Mode_FIQ 0x11
++#define Mode_IRQ 0x12
++#define Mode_SVC 0x13
++#define Mode_ABT 0x17
++#define Mode_UND 0x1B
++#define Mode_SYS 0x1F
++#define Mode_MASK 0x1F
++#define NOINT 0xC0
++#define I_Bit 0x80
++#define F_Bit 0x40
++
++#define SYSCTL_SBZ_MASK 0xCC1A0000
++#define SYSCTL_SBO_MASK 0x00000070
++#define MMUTTB_SBZ_MASK 0x00001FE0 // for 8KB Boundary Size of TTB0
++
++ .text
++
++/*
++ * IO_ARM_SaveREG
++ * --------------
++ *
++ * Save ARM registers, MMU data and MODE data for suspend mode.
++ *
++ * input parameters:
++ * r0: SRAM_ADDR_STANDBY
++ * r1: TCC_REG
++ * r2: Awake_address
++ */
++
++ENTRY(IO_ARM_SaveREG)
++ @ address of sdram_self_refresh() (r0)
++ mov r12, r0
++
++ @ Save register state
++ stmdb sp!, {r4-r12}
++ stmdb sp!, {lr}
++ str r2, [r1, #0x4] // save resume function address (virtual)
++ mov r3, r1 // r1 (&p89reg) -> r3
++
++
++@
++@ Save MMU to DRAM
++@
++
++ @ CP15 System Control Register
++ mrc p15, 0, r2, c1, c0, 0 // load r2 with System Control Register
++ ldr r0, =SYSCTL_SBZ_MASK // Should Be Zero Mask for System Control Register
++ bic r2, r2, r0
++ ldr r0, =SYSCTL_SBO_MASK // Should Be One Mask for System Control Register
++ orr r2, r2, r0
++ str r2, [r3, #0x08] // [SleepState_SYSCTL]
++
++ @ CP15 TTB Register0
++ mrc p15, 0, r2, c2, c0, 0 // load r2 with TTB Register0
++ ldr r0, =MMUTTB_SBZ_MASK // Should Be Zero Mask for TTB Register0
++ bic r2, r2, r0
++ str r2, [r3, #0x0C] // [SleepState_MMUTTB0]
++
++ @ CP15 TTB Register1
++ mrc p15, 0, r2, c2, c0, 1 // load r2 with TTB Register1
++// ldr r0, =MMUTTB_SBZ_MASK // Should Be Zero Mask for TTB Register1
++// bic r2, r2, r0
++ str r2, [r3, #0x10] // [SleepState_MMUTTB1]
++
++ @ CP15 TTB Control Register
++ mrc p15, 0, r2, c2, c0, 2 // load r2 with TTB Control Register
++// ldr r0, =MMUTTB_CTLSBZ_MASK // Should Be Zero Mask for TTB Register0
++// bic r2, r2, r0
++ str r2, [r3, #0x14] // [SleepState_MMUTTBCTL]
++
++ @ CP15 Domain Access Control Register
++ mrc p15, 0, r2, c3, c0, 0 // load r2 with Domain Access Control Register
++ str r2, [r3, #0x18] // [SleepState_MMUDOMAIN]
++
++
++@
++@ Save CPU register to DRAM
++@
++
++ @ Supervisor mode CPU Register
++ str sp, [r3, #0x1C] // [SleepState_SVC_SP]
++ mrs r2, spsr // Status Register
++ str r2, [r3, #0x20] // [SleepState_SVC_SPSR]
++
++ add r3, r1, #0x24
++
++ @ FIQ mode CPU Registers
++ mov r1, #Mode_FIQ | NOINT // Enter FIQ mode, no interrupts
++ msr cpsr, r1
++ mrs r2, spsr // Status Register
++ stmia r3!, {r2, r8-r12, sp, lr} // Store FIQ mode registers [SleepState_FIQ_SPSR~SleepState_FIQ_LR]
++
++ @ Abort mode CPU Registers
++ mov r1, #Mode_ABT | NOINT // Enter ABT mode, no interrupts
++ msr cpsr, r1
++ mrs r0, spsr // Status Register
++ stmia r3!, {r0, sp, lr} // Store ABT mode Registers [SleepState_ABT_SPSR~SleepState_ABT_LR]
++
++ @ IRQ mode CPU Registers
++ mov r1, #Mode_IRQ | NOINT // Enter IRQ mode, no interrupts
++ msr cpsr, r1
++ mrs r0, spsr // Status Register
++ stmia r3!, {r0, sp, lr} // Store the IRQ Mode Registers [SleepState_IRQ_SPSR~SleepState_IRQ_LR]
++
++ @Undefined mode CPU Registers
++ mov r1, #Mode_UND | NOINT // Enter UND mode, no interrupts
++ msr cpsr, r1
++ mrs r0, spsr // Status Register
++ stmia r3!, {r0, sp, lr} // Store the UND mode Registers [SleepState_UND_SPSR~SleepState_UND_LR]
++
++ @ System(User) mode CPU Registers
++ mov r1, #Mode_SYS | NOINT // Enter SYS mode, no interrupts
++ msr cpsr, r1
++ stmia r3!, {sp, lr} // Store the SYS mode Registers [SleepState_SYS_SP, SleepState_SYS_LR]
++
++ @ Return to SVC mode
++ mov r1, #Mode_SVC | NOINT // Back to SVC mode, no interrupts
++ msr cpsr, r1
++
++ ldr r2, [sp]
++ str r2, [r3], #4
++
++ bl IO_ARM_CleanCACHE
++
++ nop
++ nop
++ nop
++
++#if 0
++ ldr r0, =0x00050078
++ mcr p15, 0, r0, c1, c0, 0 // Disable Cache/MMU Control
++ nop
++ nop
++ nop
++ nop
++ nop
++ nop
++ nop
++ nop
++ nop
++#endif
++
++ @ jump to power-off code.
++ mov pc, r12 // jump to self-refresh code
++ENDPROC(IO_ARM_SaveREG)
++
++
++/*
++ * Awake_address
++ * --------------
++ *
++ * Restore CPU Register from Sleep Data Area in DRAM
++ * r3 : p89reg ioremap virtual address, r3 is assigned by IO_ARM_RestoreREG in bootloader
++ */
++ENTRY(Awake_address)
++ @ FIQ mode CPU Registers
++ mov r1, #Mode_FIQ | NOINT // Enter FIQ mode, no interrupts
++ msr cpsr, r1
++ ldr r0, [r3, #0x24]
++ msr spsr, r0
++ ldr r8, [r3, #0x28]
++ ldr r9, [r3, #0x2C]
++ ldr r10,[r3, #0x30]
++ ldr r11,[r3, #0x34]
++ ldr r12,[r3, #0x38]
++ ldr sp, [r3, #0x3C]
++ ldr lr, [r3, #0x40]
++
++ @ Abort mode CPU Registers
++ mov r1, #Mode_ABT | I_Bit // Enter ABT mode, no IRQ - FIQ is available
++ msr cpsr, r1
++ ldr r0, [r3, #0x44]
++ msr spsr, r0
++ ldr sp, [r3, #0x48]
++ ldr lr, [r3, #0x4C]
++
++ @ IRQ mode CPU Registers
++ mov r1, #Mode_IRQ | I_Bit // Enter IRQ mode, no IRQ - FIQ is available
++ msr cpsr, r1
++ ldr r0, [r3, #0x50]
++ msr spsr, r0
++ ldr sp, [r3, #0x54]
++ ldr lr, [r3, #0x58]
++
++ @ Undefined mode CPU Registers
++ mov r1, #Mode_UND | I_Bit // Enter UND mode, no IRQ - FIQ is available
++ msr cpsr, r1
++ ldr r0, [r3, #0x5C]
++ msr spsr, r0
++ ldr sp, [r3, #0x60]
++ ldr lr, [r3, #0x64]
++
++ @ System(User) mode CPU Registers
++ mov r1, #Mode_SYS | I_Bit // Enter SYS mode, no IRQ - FIQ is available
++ msr cpsr, r1
++ ldr sp, [r3, #0x68]
++ ldr lr, [r3, #0x6C]
++
++ @ Supervisor mode CPU Registers
++ mov r1, #Mode_SVC | I_Bit // Enter SVC mode, no IRQ - FIQ is available
++ msr cpsr, r1
++ ldr r0, [r3, #0x20]
++ msr spsr, r0
++ ldr sp, [r3, #0x1C]
++
++
++ @ Pop SVC Register from our Stack
++ ldr lr, [sp], #4
++ ldmia sp!, {r4-r12}
++
++ @ Return to PM functions
++ mov pc, lr
++ENDPROC(Awake_address)
++
++
++/*
++ * Clean & Flush Cache
++ * -------------------
++ */
++ENTRY(IO_ARM_CleanCACHE)
++ stmdb r13!, {lr}
++
++ bl IO_ARM_CleanDCACHE
++
++ cmp r0, #0
++ movne r0, #0 @ Drain Write Buffer
++ mcrne p15, 0, r0, c7, c10, 4
++
++ ldmia r13!, {pc}
++ENDPROC(IO_ARM_CleanCACHE)
++
++
++ENTRY(IO_ARM_CleanDCACHE)
++ stmdb r13!, {r0-r2, lr}
++
++ mov r1, #0 @ r1 - way (0~3)
++l01:
++ mov r1, r1, lsl #30
++ mov r2, #0 @ r2 - set index (128 set : 0~0x1000)
++l02:
++ orr r0, r1, r2 @ set index (way & set)
++ mcr p15, 0, r0, c7, c10, 2 @ clean cache (using index)
++ add r2, r2, #0x20 @ cache block size : 32 Bytes
++ cmp r2, #0x1000 @ cache set size : 4 KBytes
++ bne l02 @ loop until done
++
++ mov r1, r1, lsr #30
++ add r1, r1, #1
++ cmp r1, #4 @ cache way size : 4
++ bne l01
++
++ ldmia r13!, {r0-r2, pc}
++ENDPROC(IO_ARM_CleanDCACHE)
+\ No newline at end of file
+diff --git a/arch/arm/mach-tcc8900/tca_ckc.c b/arch/arm/mach-tcc8900/tca_ckc.c
+new file mode 100644
+index 0000000..78d2635
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/tca_ckc.c
+@@ -0,0 +1,1174 @@
++/****************************************************************************
++ * FileName : tca_ckc.c
++ * Description :
++ ****************************************************************************
++*
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++*
++ ****************************************************************************/
++
++
++#if defined(_LINUX_)
++# include <bsp.h>
++# include <asm/io.h>
++# include <linux/mm.h> // for PAGE_ALIGN
++# include <linux/kernel.h>
++# include <linux/module.h>
++# ifndef VOLATILE
++# define VOLATILE
++# endif
++#else
++# include <bsp.h>
++# include "oal_memory.h"
++# include "tca_ckc.h"
++# ifndef VOLATILE
++# define VOLATILE volatile
++# endif
++#endif
++
++typedef struct {
++ unsigned uFpll;
++ unsigned char P, M, S, dummy;
++} sfPLL;
++
++#define PLLFREQ(P, M, S) (( 120000 * (M) ) / (P) ) >> (S) // 100Hz Unit..
++#define FPLL_t(P, M, S) PLLFREQ(P,M,S), P, M, S
++// PLL table for XIN=12MHz
++ // P, M, S
++sfPLL pIO_CKC_PLL[] =
++{
++ {FPLL_t(3, 78, 1)} // 156MHz
++ ,{FPLL_t(3, 120, 1)} // 240 MHz
++ ,{FPLL_t(3, 135, 1)} // 270.0 MHz
++ ,{FPLL_t(2, 52, 0)} // 312 MHz
++ ,{FPLL_t(3, 95, 0)} // 380 MHz
++ ,{FPLL_t(1, 39, 0)} // 468 MHz
++ ,{FPLL_t(1, 40, 0)} // 480 MHz
++ ,{FPLL_t(1, 44, 0)} // 528 MHz
++ ,{FPLL_t(2, 104, 0)} // 624 MHz
++ ,{FPLL_t(2, 116, 0)} // 696 MHz
++
++
++};
++
++sfPLL pIO_CKC_PLL0[] =
++{
++ {FPLL_t(2, 176, 3)} // 132 MHz
++ , {FPLL_t(2, 192, 3)} // 144 MHz
++ , {FPLL_t(3, 146, 2)} // 146 MHz
++ , {FPLL_t(1, 30, 1)} // 180 MHz
++ , {FPLL_t(3, 95, 1)} // 190 MHz
++ , {FPLL_t(1, 32, 1)} // 192 MHz
++ , {FPLL_t(3, 202, 2)} // 202 MHz
++ , {FPLL_t(2, 144, 2)} // 216 MHz
++ , {FPLL_t(2, 148, 2)} // 222 MHz
++ , {FPLL_t(3, 230, 2)} // 230 MHz
++ ,{FPLL_t(2, 216, 2)} // 324 MHz
++ ,{FPLL_t(2, 144, 1)} // 432 MHz
++ ,{FPLL_t(2, 162, 1)} // 486 MHz
++ ,{FPLL_t(2, 180, 1)} // 540 MHz
++ ,{FPLL_t(2, 200, 1)} // 600 MHz
++};
++
++#define NUM_PLL (sizeof(pIO_CKC_PLL)/sizeof(sfPLL))
++#define NUM_PLL0 (sizeof(pIO_CKC_PLL0)/sizeof(sfPLL))
++
++#define tca_wait() { volatile int i; for (i=0; i<0x2000; i++); }
++
++#if defined(_LINUX_)
++ #define iomap_p2v(x) (x)
++#else
++// #define iomap_p2v(x) (x & ~0x40000000) //0xF0400000 -> 0xB04
++ #define iomap_p2v(x) (OALPAtoVA(x,FALSE)) //0xF0400000 -> 0xB04
++#endif
++
++/****************************************************************************************
++* Global Variable
++* ***************************************************************************************/
++PCKC pCKC ;
++PPMU pPMU ;
++PIOBUSCFG pIOBUSCFG;
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_init(void)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE void tca_ckc_init(void)
++{
++ pCKC = (PCKC)(iomap_p2v((unsigned int)&HwCLK_BASE)); //0xF0400000
++ pPMU = (PPMU)(iomap_p2v((unsigned int)&HwPMU_BASE)); //0xF0404000
++ pIOBUSCFG = (PIOBUSCFG)(iomap_p2v((unsigned int)&HwIOBUSCFG_BASE)); //0xF05F5000
++
++}
++/****************************************************************************************
++* FUNCTION :unsigned int tca_ckc_getpll(unsigned int ch)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE unsigned int tca_ckc_getpll(unsigned int ch)
++{
++ volatile unsigned tPLL;
++ volatile unsigned tPLLCFG;
++ unsigned iP=0, iM=0, iS=0;
++
++ switch(ch)
++ {
++ case DIRECTPLL0:
++ tPLLCFG = pCKC->PLL0CFG;
++ break;
++ case DIRECTPLL1:
++ tPLLCFG = pCKC->PLL1CFG;
++ break;
++ case DIRECTPLL2:
++ tPLLCFG = pCKC->PLL2CFG;
++ break;
++ case DIRECTPLL3:
++ tPLLCFG = pCKC->PLL3CFG;
++ break;
++ }
++
++ //Fpll Clock
++ iS = (tPLLCFG & 0x7000000) >> 24;
++ iM = (tPLLCFG & 0xFFF00) >> 8;
++ iP = (tPLLCFG & 0x0003F) >> 0;
++
++ tPLL= (((120000 * iM )/ iP) >> (iS));
++
++ return tPLL;
++
++}
++
++/****************************************************************************************
++* FUNCTION :unsigned int tca_ckc_getcpu(void)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE unsigned int tca_ckc_getcpu(void)
++{
++ unsigned int lcpu = 0;
++ unsigned int lconfig = 0;
++ unsigned int lcnt = 0;
++ unsigned int li = 0;
++ unsigned int lclksource = 0;
++
++ lconfig = ((pCKC->CLK0CTRL & (Hw20-Hw4))>>4);
++
++ for(li = 0; li < 16; li++)
++ {
++ if((lconfig & Hw0) == 1)
++ lcnt++;
++ lconfig = (lconfig >> 1);
++ }
++
++ switch(pCKC->CLK0CTRL & (Hw3-Hw0)) // Check CPU Source
++ {
++ case PCDIRECTPLL0 :
++ lclksource = tca_ckc_getpll(0);
++ break;
++ case PCDIRECTPLL1 :
++ lclksource = tca_ckc_getpll(1);
++ break;
++ case PCDIRECTPLL2 :
++ lclksource = tca_ckc_getpll(2);
++ break;
++ case PCDIRECTPLL3 :
++ lclksource = tca_ckc_getpll(3);
++ break;
++ case PCDIRECTXIN :
++ lclksource = 120000;
++ break;
++ case PCHDMI :
++ lclksource = 270000;
++ break;
++ case PCSATA :
++ lclksource = 250000;
++ break;
++ case PCUSBPHY:
++ lclksource = 480000;
++ break;
++ default :
++ lclksource = tca_ckc_getpll(1);
++ break;
++ }
++
++ if(pCKC->CLK0CTRL & Hw20) // Dynamic Mode
++ {
++ lcnt = pCKC->CLK0CTRL & (Hw8-Hw4);
++ lcnt = lcnt>>4;
++ lcpu = (lclksource / lcnt);
++ }
++ else
++ lcpu = (lclksource * lcnt)/16;
++
++ return lcpu;
++}
++
++/****************************************************************************************
++* FUNCTION :unsigned int tca_ckc_getbus(void)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE unsigned int tca_ckc_getbus(void)
++{
++ unsigned int lbus = 0;
++ unsigned int lconfig = 0;
++ unsigned int lclksource = 0;
++
++ lconfig = ((pCKC->CLK2CTRL & (Hw8-Hw4))>>4);
++
++ switch(pCKC->CLK2CTRL & (Hw3-Hw0)) // Check CPU Source
++ {
++ case PCDIRECTPLL0 :
++ lclksource = tca_ckc_getpll(0);
++ break;
++ case PCDIRECTPLL1 :
++ lclksource = tca_ckc_getpll(1);
++ break;
++ case PCDIRECTPLL2 :
++ lclksource = tca_ckc_getpll(2);
++ break;
++ case PCDIRECTPLL3 :
++ lclksource = tca_ckc_getpll(3);
++ break;
++ case PCDIRECTXIN :
++ lclksource = 120000;
++ break;
++ case PCHDMI :
++ lclksource = 270000;
++ break;
++ case PCSATA :
++ lclksource = 250000;
++ break;
++ case PCUSBPHY:
++ lclksource = 480000;
++ break;
++ default :
++ lclksource = tca_ckc_getpll(1);
++ break;
++ }
++
++ lbus = lclksource /(lconfig+1);
++
++ return lbus;
++}
++
++/****************************************************************************************
++* FUNCTION :static unsigned int tca_ckc_setclkctrlx(unsigned int isenable,unsigned int md,unsigned int config,unsigned int sel)
++* DESCRIPTION : not ctrl 0 and ctrl 2 (CPU, BUS CTRL)
++* ***************************************************************************************/
++VOLATILE static unsigned int tca_ckc_gclkctrlx(unsigned int isenable,unsigned int md,unsigned int config,unsigned int sel)
++{
++ unsigned int retVal = 0;
++
++ retVal = ((isenable?1:0)<<21)|(md<<20)|(config<<4)|(sel<<0);
++
++ return retVal;
++}
++
++/****************************************************************************************
++* FUNCTION :static unsigned int tca_ckc_clkctrly(unsigned int isenable,unsigned int md,unsigned int config,unsigned int sel)
++* DESCRIPTION : ctrl 0 and ctrl 2 (CPU and BUS CTRL)
++* config is divider (md = 0)
++* ***************************************************************************************/
++VOLATILE static unsigned int tca_ckc_gclkctrly(unsigned int isenable,unsigned int md,unsigned int config,unsigned int sel, unsigned int ch)
++{
++ unsigned int retVal = 0;
++// md = 0; // Normal Mode
++
++ if(ch == CLKCTRL0)
++ {
++ switch(config)
++ {
++ case CLKDIV0:
++ config = 0xFFFF; // 1111111111111111b 16/16
++ break;
++ case CLKDIV2:
++ config = 0xAAAA; // 1010101010101010b 8/16
++ break;
++ case CLKDIV3:
++ config = 0x9249; // 1001001001001001b 6/16
++ break;
++ case CLKDIV4:
++ config = 0x8888; // 1000100010001000b 4/16
++ break;
++ case CLKDIVNONCHANGE:
++ config = 0xFFFF; // 1111111111111111b
++ break;
++ default:
++ config = 0xFFFF; // 1111111111111111b
++ break;
++ }
++ }
++
++ if(config == CLKDIVNONCHANGE)
++ {
++ if(ch == 0) // Fcpu
++ retVal = (pCKC->CLK0CTRL & (Hw20-Hw4));
++ else // Fmem_bus
++ retVal = (pCKC->CLK2CTRL & (Hw20-Hw4));
++
++ retVal |= ((isenable?1:0)<<21)|(md<<20)|(sel<<0);
++
++ }
++ else
++ retVal = ((isenable?1:0)<<21)|(md<<20)|(config<<4)|(sel<<0);
++
++ return retVal;
++}
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_setfbusctrl(unsigned int clkname,unsigned int isenable,unsigned int freq, unsigned int sor)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE void tca_ckc_setfbusctrl(unsigned int clkname,unsigned int isenable,unsigned int md,unsigned int freq, unsigned int sor)
++{
++ volatile unsigned *pCLKCTRL;
++ unsigned int clkdiv = 0;
++ unsigned int clksource = 0;
++ unsigned int lconfig = 0;
++
++ pCLKCTRL =(volatile unsigned *)((&pCKC->CLK0CTRL)+clkname);
++
++ switch(sor)
++ {
++ case DIRECTPLL0 :
++ clksource = tca_ckc_getpll(0);
++ break;
++ case DIRECTPLL1 :
++ clksource = tca_ckc_getpll(1);
++ break;
++ case DIRECTPLL2 :
++ clksource = tca_ckc_getpll(2);
++ break;
++ case DIRECTPLL3 :
++ clksource = tca_ckc_getpll(3);
++ break;
++ case DIRECTXIN:
++ clksource = 120000;
++ break;
++ default :
++ clksource = tca_ckc_getpll(1);
++ break;
++ }
++
++ if (freq != 0)
++ {
++ clkdiv = (clksource + (freq>>1)) / freq ; // should be even number of division factor
++ clkdiv -= 1;
++ }
++ else
++ clkdiv = 1;
++
++ if(clkdiv == CLKDIV0) // The config value should not be "ZERO" = 1/(config+1)
++ clkdiv = 1;
++
++
++ if(md == DYNAMIC_MD && !(clkname == CLKCTRL0 || clkname == CLKCTRL2))
++ {
++ /*
++ CONFIG[3:0] : Curretn Divisor(Read-only)
++ CONFIG[7:4] : Max. Divisor
++ CONFIG[11:8] : Min. Divisor
++ CONFIG[15:12] : Update Cycle Period
++ */
++ lconfig = (clkdiv<<8); //Min. Divisor
++ clkdiv = 10; //Max. Divisor
++ lconfig |= ((clkdiv<<4)| 0xF000); // Min. Divisor = Max. Divisor/2, Update Cycle Period = F
++
++ clkdiv = lconfig;
++ }
++
++ if(clkname == CLKCTRL0 || clkname == CLKCTRL2)
++ {
++ *pCLKCTRL = tca_ckc_gclkctrly(isenable,md,clkdiv,sor,clkname);
++ }
++ else
++ {
++ if(isenable == 0)
++ *pCLKCTRL &= ~Hw21;
++ else
++ *pCLKCTRL = tca_ckc_gclkctrlx(isenable,md,clkdiv,sor);
++ }
++
++}
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_getfbusctrl(unsigned int clkname)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE int tca_ckc_getfbusctrl(unsigned int clkname)
++{
++ volatile unsigned *pCLKCTRL;
++ unsigned int lcheck = 0;
++ unsigned int lmd = 0;
++ unsigned int lconfig = 0;
++ unsigned int lsel = 0;
++ unsigned int clksource = 0;
++
++ pCLKCTRL =(volatile unsigned *)((&pCKC->CLK0CTRL)+clkname);
++
++ lcheck = ((*pCLKCTRL >> 21) & Hw0);
++ lmd = ((*pCLKCTRL >> 20) & Hw0);
++ lconfig = ((*pCLKCTRL >> 4) & 0xF);
++ lsel = ((*pCLKCTRL) & 0x7);
++
++ if(!lcheck || (clkname == CLKCTRL0 || clkname == CLKCTRL2))
++ return -1;
++
++ if(lmd == 0)
++ {
++ switch(lsel)
++ {
++ case DIRECTPLL0 :
++ clksource = tca_ckc_getpll(0);
++ break;
++ case DIRECTPLL1 :
++ clksource = tca_ckc_getpll(1);
++ break;
++ case DIRECTPLL2 :
++ clksource = tca_ckc_getpll(2);
++ break;
++ case DIRECTPLL3 :
++ clksource = tca_ckc_getpll(3);
++ break;
++ case DIRECTXIN:
++ clksource = 120000;
++ break;
++ default :
++ clksource = tca_ckc_getpll(1);
++ break;
++ }
++
++ }
++ else
++ return -1;
++
++ return (clksource / (lconfig+1));
++}
++
++/****************************************************************************************
++* FUNCTION :static unsigned int tca_ckc_setpllxcfg(unsigned int isEnable, int P, int M, int S)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE static unsigned int tca_ckc_gpllxcfg(unsigned int isenable, unsigned int p, unsigned int m, unsigned int s)
++{
++ unsigned int retVal = Hw31;//Disable
++
++ if(isenable > 0)
++ {
++ retVal = (s<<24)|(m<<8)|(p<<0);
++ retVal |= Hw31; //Enable
++ }
++
++ return retVal;
++}
++
++/****************************************************************************************
++* FUNCTION :static void tca_ckc_pll(unsigned int p, unsigned int m, unsigned int s,unsigned int ch)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE static void tca_ckc_pll(unsigned int p, unsigned int m, unsigned int s,unsigned int ch)
++{
++ volatile unsigned *pPLLCFG;
++
++ pPLLCFG =(volatile unsigned *)((&pCKC->PLL0CFG)+ch);
++
++ if(ch == 0) // PLL0 is System Clock Source
++ {
++ // Change System Clock Souce --> XIN (12Mhz)
++ // pCKC->CLK0CTRL = tca_ckc_gclkctrly(ENABLE,NORMAL_MD,CLKDIVNONCHANGE,DIRECTXIN,0);
++ pCKC->CLK0CTRL = tca_ckc_gclkctrly(ENABLE,NORMAL_MD,CLKDIVNONCHANGE,DIRECTPLL2,0);
++ tca_wait();
++ }
++
++ //Disable PLL
++ *pPLLCFG &= ~Hw31;
++ //Set PMS
++ *pPLLCFG = tca_ckc_gpllxcfg(ENABLE,p,m,s);
++ //Enable PLL
++ *pPLLCFG |= Hw31;
++ tca_wait();
++ //Restore System Clock Source
++ if(ch == 0)
++ {
++ //pCKC->CLK2CTRL = tca_ckc_gclkctrly(ENABLE,NORMAL_MD,CLKDIVNONCHANGE,DIRECTPLL0,2);
++ pCKC->CLK0CTRL = tca_ckc_gclkctrly(ENABLE,NORMAL_MD,CLKDIVNONCHANGE,DIRECTPLL0,0);
++ }
++
++}
++
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_validpll(unsigned int * pvalidpll)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE void tca_ckc_validpll(unsigned int * pvalidpll)
++{
++ unsigned int uCnt;
++ sfPLL *pPLL;
++
++ pPLL = &pIO_CKC_PLL[0];
++ for (uCnt = 0; uCnt < NUM_PLL; uCnt ++, pPLL ++)
++ {
++ *pvalidpll = pPLL->uFpll ;
++ pvalidpll++;
++ }
++};
++
++/****************************************************************************************
++* FUNCTION :int tca_ckc_setpll(unsigned int pll, unsigned int ch)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE int tca_ckc_setpll(unsigned int pll, unsigned int ch)
++{
++ unsigned uCnt;
++ int retVal = -1;
++ unsigned int num_pll;
++
++ sfPLL *pPLL;
++
++ if(pll != 0 )
++ {
++ if(ch == 0)
++ {
++ pPLL = &pIO_CKC_PLL0[0];
++ num_pll = NUM_PLL0;
++ }
++ else
++ {
++ pPLL = &pIO_CKC_PLL[0];
++ num_pll = NUM_PLL;
++ }
++
++ for (uCnt = 0; uCnt < num_pll; uCnt ++, pPLL ++)
++ if (pPLL->uFpll == pll)
++ break;
++
++ if (uCnt < num_pll)
++ {
++ tca_ckc_pll(pPLL->P,pPLL->M ,pPLL->S,ch);
++ retVal = 0;
++ return 1;
++ }
++ }
++
++ return -1;
++}
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_setcpu(unsigned int n)
++* DESCRIPTION : n is n/16
++* example : CPU == PLL : n=16 - CPU == PLL/2 : n=8
++* ***************************************************************************************/
++VOLATILE void tca_ckc_setcpu(unsigned int n)
++{
++ unsigned int lckc0ctrl;
++ unsigned int lindex[] = {0x0,0x8000,0x8008,0x8808,0x8888,0xA888,0xA8A8,0xAAA8,0xAAAA,
++ 0xECCC,0xEECC,0xEEEC,0xEEEE,0xFEEE,0xFFEE,0xFFFE,0xFFFF};
++
++
++ lckc0ctrl = pCKC->CLK0CTRL;
++ lckc0ctrl &= ~(Hw20-Hw4);
++ lckc0ctrl |= (lindex[n] << 4);
++
++ pCKC->CLK0CTRL = lckc0ctrl;
++}
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_setpmupwroff( unsigned int periname , unsigned int isenable)
++* DESCRIPTION : PMU Block : Power Off Register
++* PMU_VIDEODAC
++* PMU_HDMIPHY
++* PMU_LVDSPHY
++* PMU_USBNANOPHY
++* PMU_SATAPHY
++* PMU_MEMORYBUS
++* PMU_VIDEOBUS
++* PMU_DDIBUS
++* PMU_GRAPHICBUS
++* PMU_IOBUS
++* ***************************************************************************************/
++VOLATILE void tca_ckc_setpmupwroff( unsigned int periname , unsigned int isenable)
++{
++ unsigned int retVal = 0;
++
++ switch(periname)
++ {
++ case PMU_VIDEODAC:
++ retVal = (Hw0);
++ break;
++ case PMU_HDMIPHY:
++ retVal = (Hw1);
++ break;
++ case PMU_LVDSPHY:
++ retVal = (Hw2);
++ break;
++ case PMU_USBNANOPHY:
++ retVal = (Hw3);
++ break;
++ case PMU_SATAPHY:
++ retVal = (Hw4);
++ break;
++ case PMU_MEMORYBUS:
++ retVal = (Hw5);
++ break;
++ case PMU_VIDEOBUS:
++ retVal = (Hw6);
++ break;
++ case PMU_DDIBUS:
++ retVal = (Hw7);
++ break;
++ case PMU_GRAPHICBUS:
++ retVal = (Hw8);
++ break;
++ case PMU_IOBUS:
++ retVal = (Hw9);
++ break;
++ default:
++ break;
++ }
++
++ if(isenable)
++ pPMU->PWROFF &= ~(retVal);
++ else
++ pPMU->PWROFF |= (retVal);
++
++}
++/****************************************************************************************
++* FUNCTION :void tca_ckc_getpmupwroff( unsigned int pmuoffname)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE int tca_ckc_getpmupwroff( unsigned int pmuoffname)
++{
++ unsigned int retVal = 0;
++
++ switch(pmuoffname)
++ {
++ case PMU_VIDEODAC:
++ retVal = (pPMU->PWROFF >> 0) & Hw0;
++ break;
++ case PMU_HDMIPHY:
++ retVal = (pPMU->PWROFF >> 1) & Hw0;
++ break;
++ case PMU_LVDSPHY:
++ retVal = (pPMU->PWROFF >> 2) & Hw0;
++ break;
++ case PMU_USBNANOPHY:
++ retVal = (pPMU->PWROFF >> 3) & Hw0;
++ break;
++ case PMU_SATAPHY:
++ retVal = (pPMU->PWROFF >> 4) & Hw0;
++ break;
++ case PMU_MEMORYBUS:
++ retVal = (pPMU->PWROFF >> 5) & Hw0;
++ break;
++ case PMU_VIDEOBUS:
++ retVal = (pPMU->PWROFF >> 6) & Hw0;
++ break;
++ case PMU_DDIBUS:
++ retVal = (pPMU->PWROFF >> 7) & Hw0;
++ break;
++ case PMU_GRAPHICBUS:
++ retVal = (pPMU->PWROFF >> 8) & Hw0;
++ break;
++ case PMU_IOBUS:
++ retVal = (pPMU->PWROFF >> 9) & Hw0;
++ break;
++ default:
++ break;
++ }
++
++ return retVal;
++}
++
++/****************************************************************************************
++* FUNCTION :static unsigned int tca_ckc_setpckxxx(unsigned int isenable, unsigned int sel, unsigned int div)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE static unsigned int tca_ckc_gpckxxx(unsigned int isenable, unsigned int sel, unsigned int div)
++{
++ unsigned int retVal = Hw28; //Enable
++
++ if(isenable > 0)
++ {
++ retVal = ((isenable?1:0)<<28)|(sel<<24)|(div<<0);
++ }
++
++ return retVal;
++}
++
++/****************************************************************************************
++* FUNCTION :static unsigned int tca_ckc_setpckyyy(unsigned int isenable, unsigned int sel, unsigned int div)
++* DESCRIPTION : md (1: divider Mode, 0:DCO Mode)
++* ***************************************************************************************/
++VOLATILE static unsigned int tca_ckc_gpckyyy(unsigned int isenable, unsigned int md, unsigned int sel, unsigned int div)
++{
++ unsigned int retVal = Hw28;//Enable
++
++ if(isenable > 0)
++ {
++ retVal = (md<<31)|((isenable?1:0)<<28)|(sel<<24)|(div<<0);
++ }
++
++ return retVal;
++}
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_setperi(unsigned int periname,unsigned int isenable, unsigned int freq, unsigned int sor)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE void tca_ckc_setperi(unsigned int periname,unsigned int isenable, unsigned int freq, unsigned int sor)
++{
++ unsigned uPll;
++ unsigned int clkdiv = 0;
++ unsigned int lclksource = 0;
++ unsigned int clkmode = 1;
++
++ volatile unsigned *pPERI;
++ pPERI =(volatile unsigned *)((&pCKC->PCLK_TCX)+periname);
++
++ switch(sor)
++ {
++ case PCDIRECTPLL0 :
++ lclksource = tca_ckc_getpll(0);
++ break;
++ case PCDIRECTPLL1 :
++ lclksource = tca_ckc_getpll(1);
++ break;
++ case PCDIRECTPLL2 :
++ lclksource = tca_ckc_getpll(2);
++ break;
++ case PCDIRECTPLL3 :
++ lclksource = tca_ckc_getpll(3);
++ break;
++ case PCDIRECTXIN :
++ lclksource = 120000;
++ break;
++ case PCHDMI :
++ lclksource = 270000;
++ break;
++ case PCSATA :
++ lclksource = 250000;
++ break;
++ case PCUSBPHY:
++ lclksource = 480000;
++ break;
++ default :
++ lclksource = tca_ckc_getpll(1);
++ break;
++ }
++
++ if (freq != 0)
++ {
++ clkdiv = (lclksource + (freq>>1)) / freq ; // should be even number of division factor
++ clkdiv -= 1;
++ }
++ else
++ clkdiv = 0;
++
++ if(periname == PERI_ADC || periname == PERI_SPDIF ||periname == PERI_AUD || periname == PERI_DAI)
++ {
++ if(periname == PERI_DAI)
++ {
++ clkmode = 0; // DCO Mode
++ clkdiv = (freq *32768);
++ uPll = lclksource;
++ clkdiv = clkdiv/uPll;
++ clkdiv <<= 1;
++ clkdiv = clkdiv + 1;
++ }
++
++ *pPERI = tca_ckc_gpckyyy(isenable,clkmode,sor,clkdiv);
++ }
++ else
++ {
++ *pPERI = tca_ckc_gpckxxx(isenable,sor,clkdiv);
++
++ }
++}
++
++/****************************************************************************************
++* FUNCTION : static int tca_ckc_gperi(unsigned int lclksrc, unsigned int ldiv,unsigned int lmd)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE static int tca_ckc_gperi(unsigned int lclksrc, unsigned int ldiv,unsigned int lmd)
++{
++ if(lmd == 1)
++ {
++ if(lclksrc == PCDIRECTXIN)
++ return 120000/(ldiv+1);
++ else if(lclksrc == PCDIRECTPLL0){
++ return (tca_ckc_getpll(0)/(ldiv+1));
++ }
++ else if(lclksrc == PCDIRECTPLL1){
++ return (tca_ckc_getpll(1)/(ldiv+1));
++ }
++ else if(lclksrc == PCDIRECTPLL2){
++ return (tca_ckc_getpll(2)/(ldiv+1));
++ }
++ else if(lclksrc == PCDIRECTPLL3){
++ return (tca_ckc_getpll(3)/(ldiv+1));
++ }
++ else if(lclksrc == PCHDMI){
++ return (270000/(ldiv+1));
++ }
++ else if(lclksrc == PCSATA){
++ return (250000/(ldiv+1));
++ }
++ else if(lclksrc == PCUSBPHY){
++ return (480000/(ldiv+1));
++ }
++ else
++ return -1; // Not Support Others
++
++ }
++ else
++ return -1; // TO DO
++}
++
++/****************************************************************************************
++* FUNCTION : int tca_ckc_getperi(unsigned int periname)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE int tca_ckc_getperi(unsigned int periname)
++{
++ unsigned int lreg = 0;
++ unsigned int lmd = 1; // DIVIDER mode
++ unsigned int lclksrc = 0;
++ unsigned int ldiv = 0;
++
++ lreg =*(volatile unsigned *)((&pCKC->PCLK_TCX)+periname);
++ lclksrc = (lreg&0xF000000)>>24;
++
++ if(periname == PERI_ADC || periname == PERI_SPDIF ||periname == PERI_AUD || periname == PERI_DAI)
++ {
++ lmd = (lreg&0x80000000);
++ ldiv = (lreg & 0xFFFF);
++ return tca_ckc_gperi(lclksrc, ldiv,lmd);
++ }
++ else
++ {
++ ldiv = (lreg & 0xFFF);
++ return tca_ckc_gperi(lclksrc, ldiv,1);
++ }
++}
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_setswresetprd(unsigned int prd)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE void tca_ckc_setswresetprd(unsigned int prd)
++{
++ pCKC->SWRESETPRD = prd<<0;
++}
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_set_iobus_swreset(unsigned int sel, unsigned int mode)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE unsigned int tca_ckc_set_iobus_swreset(unsigned int sel, unsigned int mode)
++{
++ unsigned int lindex[] = {Hw0,Hw1,Hw2,Hw3,Hw4,Hw5,Hw6,Hw7,Hw8,Hw9,Hw10,Hw11,Hw12,Hw13,Hw14,Hw15
++ ,Hw16,Hw17,Hw18,Hw19,Hw20,Hw21,Hw22,Hw23,Hw24,Hw25,Hw26,Hw27,Hw28,Hw29,Hw30,Hw31};
++
++ unsigned int lrb_min;
++ unsigned int lrb_max;
++ unsigned int lrb_seperate;
++
++ lrb_min = RB_USB11H;
++ lrb_max = RB_ALLPERIPERALS;
++ lrb_seperate = RB_ADMACONTROLLER;
++
++ if(sel < lrb_min || sel >= lrb_max)
++ {
++ return 0;
++ }
++
++ if(sel > lrb_seperate)
++ {
++ sel -= (lrb_seperate+1);
++
++ if(mode)
++ pIOBUSCFG->HRSTEN1 |= lindex[sel];
++ else
++ pIOBUSCFG->HRSTEN1 &= ~lindex[sel];
++ }
++ else
++ {
++ if(mode)
++ pIOBUSCFG->HRSTEN0 |= lindex[sel];
++ else
++ pIOBUSCFG->HRSTEN0 &= ~lindex[sel];
++ }
++
++ return 1;
++}
++
++/****************************************************************************************
++* FUNCTION :void tca_ckc_setswreset(unsigned int lfbusname, unsigned int mode)
++* DESCRIPTION :
++* ***************************************************************************************/
++
++VOLATILE void tca_ckc_setswreset(unsigned int lfbusname, unsigned int mode)
++{
++ unsigned int hIndex[] = {Hw0,Hw1,Hw2,Hw3,Hw4,Hw5,Hw6,Hw7};
++
++ if(mode)
++ pCKC->SWRESET |= hIndex[lfbusname];
++ else
++ pCKC->SWRESET &= ~(hIndex[lfbusname]);
++}
++/****************************************************************************************
++* FUNCTION : int tca_ckc_setiobus(unsigned int sel, unsigned int mode)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE int tca_ckc_setiobus(unsigned int sel, unsigned int mode)
++{
++ unsigned int lindex[] = {Hw0,Hw1,Hw2,Hw3,Hw4,Hw5,Hw6,Hw7,Hw8,Hw9,Hw10,Hw11,Hw12,Hw13,Hw14,Hw15
++ ,Hw16,Hw17,Hw18,Hw19,Hw20,Hw21,Hw22,Hw23,Hw24,Hw25,Hw26,Hw27,Hw28,Hw29,Hw30,Hw31};
++
++ unsigned int lrb_min;
++ unsigned int lrb_max;
++ unsigned int lrb_seperate;
++
++ lrb_min = RB_USB11H;
++ lrb_max = RB_ALLPERIPERALS;
++ lrb_seperate = RB_ADMACONTROLLER;
++
++ if(sel < lrb_min || sel >= lrb_max)
++ {
++ return -1;
++ }
++
++ if(sel > lrb_seperate)
++ {
++ sel -= (lrb_seperate+1);
++
++ if(mode)
++ pIOBUSCFG->HCLKEN1 |= lindex[sel];
++ else
++ pIOBUSCFG->HCLKEN1 &= ~lindex[sel];
++ }
++ else
++ {
++ if(mode)
++ pIOBUSCFG->HCLKEN0 |= lindex[sel];
++ else
++ pIOBUSCFG->HCLKEN0 &= ~lindex[sel];
++ }
++
++ return 1;
++}
++
++/****************************************************************************************
++* FUNCTION : int tca_ckc_getiobus(unsigned int sel)
++* DESCRIPTION :
++* ***************************************************************************************/
++VOLATILE int tca_ckc_getiobus(unsigned int sel)
++{
++ unsigned int lindex[] = {Hw0,Hw1,Hw2,Hw3,Hw4,Hw5,Hw6,Hw7,Hw8,Hw9,Hw10,Hw11,Hw12,Hw13,Hw14,Hw15
++ ,Hw16,Hw17,Hw18,Hw19,Hw20,Hw21,Hw22,Hw23,Hw24,Hw25,Hw26,Hw27,Hw28,Hw29,Hw30,Hw31};
++ unsigned int lrb_min;
++ unsigned int lrb_max;
++ unsigned int lrb_seperate;
++ int lretVal = 0;
++
++ lrb_min = RB_USB11H;
++ lrb_max = RB_ALLPERIPERALS;
++ lrb_seperate = RB_ADMACONTROLLER;
++
++
++ if(sel < lrb_min || sel >= lrb_max)
++ {
++ return -1;
++ }
++
++ if(sel > lrb_seperate)
++ {
++ sel -= (lrb_seperate+1);
++
++ lretVal = (pIOBUSCFG->HCLKEN1 & lindex[sel]) ;
++
++ }
++ else
++ {
++ lretVal = (pIOBUSCFG->HCLKEN0 & lindex[sel]) ;
++ }
++
++ if(lretVal != 0)
++ lretVal = 1; // Enable
++
++ return lretVal;
++}
++
++/****************************************************************************************
++* FUNCTION : int tca_ckc_setsmui2c(unsigned int freq)
++* DESCRIPTION : unit : 100Hz
++* ***************************************************************************************/
++VOLATILE void tca_ckc_setsmui2c(unsigned int freq)
++{
++ PSMUI2CICLK lSMUICLK;
++ unsigned int lclkctrl7=0;
++ unsigned int lsel=0;
++ unsigned int lclksource=0;
++ unsigned int lclkdiv=0;
++
++ lSMUICLK = (PSMUI2CICLK)(iomap_p2v((unsigned int)&HwSMU_I2CICLK_BASE)); //0xF0400000
++ lclkctrl7 = (unsigned int)pCKC->CLK7CTRL;
++
++ lsel = (lclkctrl7 & 7);
++
++ if(((lclkctrl7 >>20) & Hw0) == 0 ) // Normal Mode
++ {
++ switch(lsel)
++ {
++ case DIRECTPLL0:
++ lclksource = tca_ckc_getpll(0);
++ break;
++ case DIRECTPLL1:
++ lclksource = tca_ckc_getpll(1);
++ break;
++ case DIRECTPLL2:
++ lclksource = tca_ckc_getpll(2);
++ break;
++ case DIRECTPLL3:
++ lclksource = tca_ckc_getpll(3);
++ break;
++ default :
++ lclksource = tca_ckc_getpll(1);
++ break;
++
++ }
++ }
++
++ if (freq != 0)
++ {
++ lclkdiv = (lclksource + (freq>>1)) / freq ; // should be even number of division factor
++ lSMUICLK->ICLK = (Hw31|lclkdiv);
++ }
++ else
++ {
++ lclkdiv = 0;
++ lSMUICLK->ICLK = 0;
++ }
++
++
++}
++/****************************************************************************************
++* FUNCTION : int tca_ckc_getsmui2c(void)
++* DESCRIPTION : unit : 100Hz
++* ***************************************************************************************/
++VOLATILE int tca_ckc_getsmui2c(void)
++{
++ PSMUI2CICLK lSMUICLK;
++ unsigned int lclkctrl7;
++ unsigned int lsel;
++ unsigned int lclksource;
++ unsigned int lclkdiv;
++
++ lSMUICLK = (PSMUI2CICLK)(iomap_p2v((unsigned int)&HwSMU_I2CICLK_BASE)); //0xF0400000
++ lclkctrl7 = (unsigned int)pCKC->CLK7CTRL;
++
++ lsel = (lclkctrl7 & 7);
++
++ if(((lclkctrl7 >>20) & Hw0) == 0 ) // Normal Mode
++ {
++ switch(lsel)
++ {
++ case DIRECTPLL0:
++ lclksource = tca_ckc_getpll(0);
++ break;
++ case DIRECTPLL1:
++ lclksource = tca_ckc_getpll(1);
++ break;
++ case DIRECTPLL2:
++ lclksource = tca_ckc_getpll(2);
++ break;
++ case DIRECTPLL3:
++ lclksource = tca_ckc_getpll(3);
++ break;
++ default :
++ lclksource = tca_ckc_getpll(1);
++ break;
++
++ }
++ lclkdiv = (lclkctrl7 & 0xFFFF);
++
++ if (lclkdiv != 0)
++ {
++ return (lclksource / lclkdiv) ;
++ }
++ else
++ return -1;
++ }
++ else
++ return -1;
++
++}
++
++/****************************************************************************************
++* FUNCTION : void tca_ckc_setddipwdn(unsigned int lpwdn , unsigned int lmode)
++* DESCRIPTION : Power Down Register of DDI_CONFIG
++* ***************************************************************************************/
++void tca_ckc_setddipwdn(unsigned int lpwdn , unsigned int lmode)
++{
++ PDDICONFIG lDDIPWDN;
++ unsigned int lindex[] = {Hw0,Hw1,Hw2,Hw3,Hw4,Hw5,Hw6,Hw7,Hw8};
++
++ lDDIPWDN = (PDDICONFIG)(iomap_p2v((unsigned int)&HwDDI_CONFIG_BASE)); //0xF0400000
++
++ if(lmode) // Normal
++ lDDIPWDN->PWDN &= ~lindex[lpwdn];
++ else // Power Down
++ lDDIPWDN->PWDN |= lindex[lpwdn];
++
++}
++/****************************************************************************************
++* FUNCTION : int tca_ckc_getddipwdn(unsigned int lpwdn)
++* DESCRIPTION : Power Down Register of DDI_CONFIG
++* ***************************************************************************************/
++int tca_ckc_getddipwdn(unsigned int lpwdn)
++{
++ PDDICONFIG lDDIPWDN;
++ unsigned int lindex[] = {Hw0,Hw1,Hw2,Hw3,Hw4,Hw5,Hw6,Hw7,Hw8};
++
++ lDDIPWDN = (PDDICONFIG)(iomap_p2v((unsigned int)&HwDDI_CONFIG_BASE)); //0xF0400000
++
++ return (lDDIPWDN->PWDN & lindex[lpwdn]);
++}
++
++
++/****************************************************************************************
++* EXPORT_SYMBOL clock functions for Linux
++* ***************************************************************************************/
++#if defined(_LINUX_)
++EXPORT_SYMBOL(tca_ckc_init);
++EXPORT_SYMBOL(tca_ckc_getpll);
++EXPORT_SYMBOL(tca_ckc_getcpu);
++EXPORT_SYMBOL(tca_ckc_getbus);
++//EXPORT_SYMBOL(tca_ckc_gclkctrlx);
++//EXPORT_SYMBOL(tca_ckc_gclkctrly);
++EXPORT_SYMBOL(tca_ckc_setfbusctrl);
++EXPORT_SYMBOL(tca_ckc_getfbusctrl);
++//EXPORT_SYMBOL(tca_ckc_gpllxcfg);
++//EXPORT_SYMBOL(tca_ckc_pll);
++EXPORT_SYMBOL(tca_ckc_validpll);
++EXPORT_SYMBOL(tca_ckc_setpll);
++EXPORT_SYMBOL(tca_ckc_setpmupwroff);
++EXPORT_SYMBOL(tca_ckc_getpmupwroff);
++//EXPORT_SYMBOL(tca_ckc_gpckxxx);
++//EXPORT_SYMBOL(tca_ckc_gpckyyy);
++EXPORT_SYMBOL(tca_ckc_setperi);
++//EXPORT_SYMBOL(tca_ckc_gperi);
++EXPORT_SYMBOL(tca_ckc_getperi);
++EXPORT_SYMBOL(tca_ckc_setswresetprd);
++EXPORT_SYMBOL(tca_ckc_set_iobus_swreset);
++EXPORT_SYMBOL(tca_ckc_setswreset);
++EXPORT_SYMBOL(tca_ckc_setiobus);
++EXPORT_SYMBOL(tca_ckc_getiobus);
++EXPORT_SYMBOL(tca_ckc_setsmui2c);
++EXPORT_SYMBOL(tca_ckc_getsmui2c);
++EXPORT_SYMBOL(tca_ckc_setddipwdn);
++EXPORT_SYMBOL(tca_ckc_getddipwdn);
++#endif
++
++/* end of file */
+diff --git a/arch/arm/mach-tcc8900/tcc b/arch/arm/mach-tcc8900/tcc
+new file mode 120000
+index 0000000..c3a8743
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/tcc
+@@ -0,0 +1 @@
++tcc8900
+\ No newline at end of file
+diff --git a/arch/arm/mach-tcc8900/tcc8900/arm_ioctlutil.S b/arch/arm/mach-tcc8900/tcc8900/arm_ioctlutil.S
+new file mode 100644
+index 0000000..07d6ffc
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/tcc8900/arm_ioctlutil.S
+@@ -0,0 +1,23 @@
++/***************************************************************************************
++* FileName : arm_ioctlutil.s
++****************************************************************************************
++*
++* TCC Board Support Package
++* Copyright (c) Telechips, Inc.
++* ALL RIGHTS RESERVED
++*
++****************************************************************************************/
++ .global arm_changestack
++arm_changestack:
++ mov r0, r13
++// ldr r13, =0xF0A03FA0 // 0x10000000 ~ 0x10003FFF SRAM(16KB)
++ ldr r13, =0xEFF03FFC // 0x10000000 ~ 0x10003FFF SRAM(16KB)
++ mov pc, lr
++
++ .global arm_restorestack
++arm_restorestack:
++ mov r13, r0
++ mov pc, lr
++
++
++/************* end of file *************************************************************/
+diff --git a/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_141to190.c b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_141to190.c
+new file mode 100644
+index 0000000..7eb81d9
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_141to190.c
+@@ -0,0 +1,2259 @@
++#include "tcc_ckcddr2_141to190.h"
++
++#if !defined(DRAM_MDDR)
++
++#define DRAM_ODTOFF
++
++
++#define Hw13 0x00002000
++#define DRAM_AUTOPD_ENABLE Hw13
++#define DRAM_AUTOPD_PERIOD 7<<7 // must larger than CAS latency
++#define DRAM_SET_AUTOPD DRAM_AUTOPD_ENABLE|DRAM_AUTOPD_PERIOD
++
++void init_clockchange125Mhz(void)
++{
++ unsigned int lpll1 =500;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =4; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00007D03; // pms - pllout_480M
++ *(volatile unsigned long *)0xF0400024= 0x80007D03; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000|DRAM_SET_AUTOPD;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012|DRAM_SET_AUTOPD; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ // 1 Tick = 2.5ns
++ *(volatile unsigned long *)0xF0302020 = 0x0000000D; // tRAS - 45ns
++ *(volatile unsigned long *)0xF0302024 = 0x00000011; // tRC - 60ns
++ *(volatile unsigned long *)0xF0302028 = 0x00000205; // tRCD - 15ns
++ *(volatile unsigned long *)0xF030202c = 0x00001B1E; // tRFC - 105ns
++ *(volatile unsigned long *)0xF0302030 = 0x00000205; // tRP - 15ns
++ *(volatile unsigned long *)0xF0302034 = 0x00000005; // tRRD
++ *(volatile unsigned long *)0xF0302038 = 0x00000006; // tWR
++ *(volatile unsigned long *)0xF030203c = 0x00000003; // tWTR
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00003E3E; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ //*(volatile unsigned long *) 0xF0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ // *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00080362; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ // *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00080262; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++ #if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++
++}
++
++void init_clockchange130Mhz(void)
++{
++ unsigned int lpll1 =260;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x01008203; // pms - pllout_276M
++ *(volatile unsigned long *)0xF0400024= 0x81008203; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ // 1 Tick = 2.5ns
++ *(volatile unsigned long *)0xF0302020 = 0x0000000D; // tRAS - 45ns
++ *(volatile unsigned long *)0xF0302024 = 0x00000011; // tRC - 60ns
++ *(volatile unsigned long *)0xF0302028 = 0x00000205; // tRCD - 15ns
++ *(volatile unsigned long *)0xF030202c = 0x00001B1E; // tRFC - 105ns
++ *(volatile unsigned long *)0xF0302030 = 0x00000205; // tRP - 15ns
++ *(volatile unsigned long *)0xF0302034 = 0x00000005; // tRRD
++ *(volatile unsigned long *)0xF0302038 = 0x00000006; // tWR
++ *(volatile unsigned long *)0xF030203c = 0x00000003; // tWTR
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00003E3E; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ //*(volatile unsigned long *) 0xF0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ // *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00080362; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ // *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00080262; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++void init_clockchange135Mhz(void)
++{
++ unsigned int lpll1 =540;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =4; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00002D01; // pms - pllout_540M
++ *(volatile unsigned long *)0xF0400024= 0x80002D01; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ *(volatile unsigned long *)0xF0302020 = 0x0000000D; // tRAS - 45ns
++ *(volatile unsigned long *)0xF0302024 = 0x00000011; // tRC - 60ns
++ *(volatile unsigned long *)0xF0302028 = 0x00000205; // tRCD - 15ns
++ *(volatile unsigned long *)0xF030202c = 0x00001B1E; // tRFC - 105ns
++ *(volatile unsigned long *)0xF0302030 = 0x00000205; // tRP - 15ns
++ *(volatile unsigned long *)0xF0302034 = 0x00000005; // tRRD
++ *(volatile unsigned long *)0xF0302038 = 0x00000006; // tWR
++ *(volatile unsigned long *)0xF030203c = 0x00000003; // tWTR
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00003E3E; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ //*(volatile unsigned long *) 0xF0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ // *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00080362; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ // *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00080262; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++ #if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++void init_clockchange141Mhz(void)
++{
++ unsigned int lpll1 =282;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x01002F01; // pms - pllout_276M
++ *(volatile unsigned long *)0xF0400024= 0x81002F01; // pll pwr on
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000|DRAM_SET_AUTOPD;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012|DRAM_SET_AUTOPD; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0302008 = 0x00090002; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ //*(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//145Mhz
++void init_clockchange145Mhz(void)
++{
++ unsigned int lpll1 =580;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =4; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00009103; // pms - pllout_580M
++ *(volatile unsigned long *)0xF0400024= 0x80009103; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//150Mhz
++void init_clockchange150Mhz(void)
++{
++ unsigned int lpll1 =600;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =4; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00003201; // pms - pllout_600M
++ *(volatile unsigned long *)0xF0400024= 0x80003201; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//160Mhz
++void init_clockchange160Mhz(void)
++{
++ unsigned int lpll1 =320;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00005003; // pms - pllout_320M
++ *(volatile unsigned long *)0xF0400024= 0x80005003; // pll pwr on
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//170Mhz
++void init_clockchange170Mhz(void)
++{
++ unsigned int lpll1 =340;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00005503; // pms - pllout_320M
++ *(volatile unsigned long *)0xF0400024= 0x80005503; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//180Mhz
++void init_clockchange180Mhz(void)
++{
++ unsigned int lpll1 =360;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00001E01; // pms - pllout_320M
++ *(volatile unsigned long *)0xF0400024= 0x80001E01; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//190Mhz
++void init_clockchange190Mhz(void)
++{
++ unsigned int lpll1 =380;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00005F03; // pms - pllout_320M
++ *(volatile unsigned long *)0xF0400024= 0x80005F03; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++#endif
+diff --git a/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_141to190.h b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_141to190.h
+new file mode 100644
+index 0000000..9c9a80a
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_141to190.h
+@@ -0,0 +1,23 @@
++#if defined(_LINUX_)
++ #include <mach/ddr.h>
++#else
++ #include "windows.h"
++
++ #include "bsp.h"
++ #include "tca_ckc.h"
++#endif
++
++
++#if !defined(DRAM_MDDR)
++extern void init_clockchange125Mhz(void);
++extern void init_clockchange130Mhz(void);
++extern void init_clockchange135Mhz(void);
++extern void init_clockchange141Mhz(void);
++extern void init_clockchange145Mhz(void);
++extern void init_clockchange150Mhz(void);
++extern void init_clockchange160Mhz(void);
++extern void init_clockchange170Mhz(void);
++extern void init_clockchange180Mhz(void);
++extern void init_clockchange190Mhz(void);
++#endif
++
+diff --git a/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_200to290.c b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_200to290.c
+new file mode 100644
+index 0000000..9a0ff32
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_200to290.c
+@@ -0,0 +1,2287 @@
++#include "tcc_ckcddr2_200to290.h"
++
++#if !defined(DRAM_MDDR)
++
++//200Mhz
++void init_clockchange200Mhz(void)
++{
++ unsigned int lpll1 =400;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00006403; // pms - pllout_400M
++ *(volatile unsigned long *)0xF0400024= 0x80006403; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//210Mhz
++void init_clockchange210Mhz(void)
++{
++ unsigned int lpll1 =420;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00002301; // pms - pllout_420M
++ *(volatile unsigned long *)0xF0400024= 0x80002301; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//220Mhz
++void init_clockchange220Mhz(void)
++{
++ unsigned int lpll1 =440;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00006E03; // pms - pllout_600M
++ *(volatile unsigned long *)0xF0400024= 0x80006E03; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//230Mhz
++void init_clockchange230Mhz(void)
++{
++ unsigned int lpll1 =460;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00007303; // pms - pllout_320M
++ *(volatile unsigned long *)0xF0400024= 0x80007303; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//240Mhz
++void init_clockchange240Mhz(void)
++{
++ unsigned int lpll1 =480;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00002801; // pms - pllout_480M
++ *(volatile unsigned long *)0xF0400024= 0x80002801; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//250Mhz
++void init_clockchange250Mhz(void)
++{
++ unsigned int lpll1 =500;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00007D03; // pms - pllout_320M
++ *(volatile unsigned long *)0xF0400024= 0x80007D03; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//260Mhz
++void init_clockchange260Mhz(void)
++{
++ unsigned int lpll1 =520;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00008203; // pms - pllout_520M
++ *(volatile unsigned long *)0xF0400024= 0x80008203; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++
++//270Mhz
++void init_clockchange270Mhz(void)
++{
++ unsigned int lpll1 =540;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00002D01; // pms - pllout_520M
++ *(volatile unsigned long *)0xF0400024= 0x80002D01; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++
++//280Mhz
++void init_clockchange280Mhz(void)
++{
++ unsigned int lpll1 =560;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00008C03; // pms - pllout_560M
++ *(volatile unsigned long *)0xF0400024= 0x80008C03; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle+1; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle+1; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = (((lcycle+1-3)<<8) | (lcycle+1)); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = (((lcycle+1-3)<<8) | (lcycle+1)); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle+1; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle+1; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle+1; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++
++
++//290Mhz
++void init_clockchange290Mhz(void)
++{
++ unsigned int lpll1 =580;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00009103; // pms - pllout_580M
++ *(volatile unsigned long *)0xF0400024= 0x80009103; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = ((lcycle-3)<<8 | lcycle); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = ((lcycle-3)<<8 | lcycle); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = ((lcycle-3)<<8 | lcycle); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++#endif
+diff --git a/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_200to290.h b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_200to290.h
+new file mode 100644
+index 0000000..dcd04a9
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_200to290.h
+@@ -0,0 +1,24 @@
++#if defined(_LINUX_)
++ #include <bsp.h>
++ #include <mach/ddr.h>
++#else
++ #include "windows.h"
++
++ #include "bsp.h"
++ #include "tca_ckc.h"
++#endif
++
++
++#if !defined(DRAM_MDDR)
++
++extern void init_clockchange200Mhz(void);
++extern void init_clockchange210Mhz(void);
++extern void init_clockchange220Mhz(void);
++extern void init_clockchange230Mhz(void);
++extern void init_clockchange240Mhz(void);
++extern void init_clockchange250Mhz(void);
++extern void init_clockchange260Mhz(void);
++extern void init_clockchange270Mhz(void);
++extern void init_clockchange280Mhz(void);
++extern void init_clockchange290Mhz(void);
++#endif
+diff --git a/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_300to330.c b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_300to330.c
+new file mode 100644
+index 0000000..a3569cd
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_300to330.c
+@@ -0,0 +1,934 @@
++#include "tcc_ckcddr2_300to330.h"
++
++#if !defined(DRAM_MDDR)
++
++#define DRAM_AUTOPD_ENABLE Hw13
++#define DRAM_AUTOPD_PERIOD 7<<7 // must larger than CAS latency
++#define DRAM_SET_AUTOPD DRAM_AUTOPD_ENABLE|DRAM_AUTOPD_PERIOD
++
++//300Mhz
++void init_clockchange300Mhz(void)
++{
++ unsigned int lpll1 =600;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00003201; // pms - pllout_600M
++ *(volatile unsigned long *)0xF0400024= 0x80003201; // pll pwr on
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = ((lcycle-3)<<8 | lcycle); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = ((lcycle-3)<<8 | lcycle); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = ((lcycle-3)<<8 | lcycle); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//312Mhz
++void init_clockchange312Mhz(void)
++{
++ unsigned int lpll1 =624;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00006802; // pms - pllout_624M
++ *(volatile unsigned long *)0xF0400024= 0x80006802; // pll pwr on
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = ((lcycle-3)<<8 | lcycle); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = ((lcycle-3)<<8 | lcycle); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = ((lcycle-3)<<8 | lcycle); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//320Mhz
++void init_clockchange320Mhz(void)
++{
++ unsigned int lpll1 =640;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x0000A003; // pms - pllout_640M
++ *(volatile unsigned long *)0xF0400024= 0x8000A003; // pll pwr on
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000;
++// memory arb. end
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000445; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = ((lcycle-3)<<8 | lcycle); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = ((lcycle-3)<<8 | lcycle); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = ((lcycle-3)<<8 | lcycle); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++}
++
++//330Mhz
++void init_clockchange330Mhz(void)
++{
++ unsigned int lpll1 =660;
++ unsigned int lmem_source =1; // 0 : PLL0 , 1 : PLL1
++ unsigned int lmem_div =2; // Fmbus 130Mhz
++
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ i = 1600;
++ while(i)
++ i--;
++
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ i = 2400;
++ while(i)
++ i--;
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00006E02; // pms - pllout_660M
++ *(volatile unsigned long *)0xF0400024= 0x80006E02; // pll pwr on
++
++ i = 3200;
++ while(i)
++ i--;
++
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++ i = 3200;
++ while(i)
++ i--;
++
++//Init DDR2
++ *(volatile unsigned long *) 0xF0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xF0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000|DRAM_SET_AUTOPD;
++// memory arb. end
++// *(volatile unsigned long *) 0xF0303000 |= 0x80800000; // bit23 enable -synopt enable
++// *(volatile unsigned long *) 0xF0303010 |= 0x80800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xF030200C = 0x00150012|DRAM_SET_AUTOPD; // config0 cas 10bit, ras 13bit
++ *(volatile unsigned long *)0xF0302010 = 0x00000507; // refresh
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xF030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xF030204c=0x00000541; // config2 - SOC
++#endif
++
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302014 = 0x0000000C; // cas_latency - 5
++#else
++ *(volatile unsigned long *)0xF0302014 = 0x0000000A; // cas_latency - 5
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++
++ ldiv = 10000/(lpll1/lmem_div);
++
++ lcycle = 450/ldiv;
++ *(volatile unsigned long *)0xF0302020 = lcycle; // tRAS - 45ns
++ lcycle = 600/ldiv;
++ *(volatile unsigned long *)0xF0302024 = lcycle; // tRC - 60ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302028 = ((lcycle-3)<<8 | lcycle); // tRCD - 15ns
++ lcycle = 1050/ldiv;
++ *(volatile unsigned long *)0xF030202c = ((lcycle-3)<<8 | lcycle); // tRFC - 105ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302030 = ((lcycle-3)<<8 | lcycle); // tRP - 15ns
++ lcycle = 100/ldiv;
++ *(volatile unsigned long *)0xF0302034 = lcycle; // tRRD - 10ns
++ lcycle = 150/ldiv;
++ *(volatile unsigned long *)0xF0302038 = lcycle; // tWR - 15ns
++ lcycle = 75/ldiv;
++ *(volatile unsigned long *)0xF030203c = lcycle; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP - min 2tCK
++
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ i = 3200;
++ while(i)
++ i--;
++
++ *(volatile unsigned long *)0xF0302200 = 0x000040f0; //256MB config_chip0
++ // *(volatile unsigned long *)0xF0302200 = 0x000040f8; //128MB config_chip0 //soc1-3
++
++ i = 3200;
++ while(i)
++ i--;
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++ *(volatile unsigned long *)0xF0303020 = 0x00010103; // emccfg_config0
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xF0304430=0x00000004; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xF0304430=0x00000004; // RDDELAY - SOC
++ #endif
++
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = 0x0006e551;
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = 0x0006e553; // ZQCTRL
++ #endif
++
++ i = 3200;
++ while(i)
++ i--;
++
++ *(volatile unsigned long *)0xF0304428 = 0x0006e551; // ZQCTRL
++
++ i = 3200;
++ while(i)
++ i--;
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xF0302008=0x00040000; // dir_cmd
++ i--;
++ }
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++#endif
++
++#if defined(DRAM_ODTOFF)
++
++#else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register //soc1-3
++#endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++
++ i = 1600;
++ while(i)
++ i--;
++}
++
++#endif
+diff --git a/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_300to330.h b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_300to330.h
+new file mode 100644
+index 0000000..28d2e44
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcddr2_300to330.h
+@@ -0,0 +1,19 @@
++#if defined(_LINUX_)
++ #include <bsp.h>
++ #include <mach/ddr.h>
++#else
++ #include "windows.h"
++
++ #include "bsp.h"
++ #include "tca_ckc.h"
++#endif
++
++
++#if !defined(DRAM_MDDR)
++
++extern void init_clockchange300Mhz(void);
++extern void init_clockchange312Mhz(void);
++extern void init_clockchange320Mhz(void);
++extern void init_clockchange330Mhz(void);
++#endif
++
+diff --git a/arch/arm/mach-tcc8900/tcc8900/tcc_ckcmddr_100to160.c b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcmddr_100to160.c
+new file mode 100644
+index 0000000..849d8e2
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcmddr_100to160.c
+@@ -0,0 +1,1403 @@
++#include "tcc_ckcmddr_100to160.h"
++
++#if defined(DRAM_MDDR)
++
++//141Mhz
++void init_clockchange100Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00006403; // pms - pllout_400M
++ *(volatile unsigned long *)0xB0400024= 0x80006403; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++#else
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++#endif
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++void init_clockchange105Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00002301; // pms - pllout_420M
++ *(volatile unsigned long *)0xB0400024= 0x80002301; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++#else
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++#endif
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++}
++
++//145Mhz
++void init_clockchange110Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00006E03; // pms - pllout_440M
++ *(volatile unsigned long *)0xB0400024= 0x80006E03; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++#else
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++#endif
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++void init_clockchange115Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00007303; // pms - pllout_460M
++ *(volatile unsigned long *)0xB0400024= 0x80007303; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++#else
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++#endif
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++//150Mhz
++void init_clockchange120Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00002801; // pms - pllout_480M
++ *(volatile unsigned long *)0xB0400024= 0x80002801; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++#else
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++#endif
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++void init_clockchange125Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00007D03; // pms - pllout_500M
++ *(volatile unsigned long *)0xB0400024= 0x80007D03; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++#else
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++#endif
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++//160Mhz
++
++void init_clockchange130Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 2
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x01008203; // pms - pllout_260M
++ *(volatile unsigned long *)0xB0400024= 0x81008203; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++#else
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++#endif
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++void init_clockchange135Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00002D01; // pms - pllout_540M
++ *(volatile unsigned long *)0xB0400024= 0x80002D01; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++#else
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++#endif
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++}
++
++
++//170Mhz
++void init_clockchange140Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00008C03; // pms - pllout_560M
++ *(volatile unsigned long *)0xB0400024= 0x80008C03; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++#else
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++#endif
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++void init_clockchange145Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00009103; // pms - pllout_580M
++ *(volatile unsigned long *)0xB0400024= 0x80009103; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++#else
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++#endif
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++//150Mhz
++void init_clockchange150Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00003201; // pms - pllout_600M
++ *(volatile unsigned long *)0xB0400024= 0x80003201; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++#else
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++#endif
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++}
++void init_clockchange156Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 2
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00001A01; // pms - pllout_312M
++ *(volatile unsigned long *)0xB0400024= 0x80001A01; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++//#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++//#else
++// *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++//#endif
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++void init_clockchange160Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 2
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00005003; // pms - pllout_320M
++ *(volatile unsigned long *)0xB0400024= 0x80005003; // pms - pllout_320M
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++#else
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++#endif
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++#endif
++
+diff --git a/arch/arm/mach-tcc8900/tcc8900/tcc_ckcmddr_100to160.h b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcmddr_100to160.h
+new file mode 100644
+index 0000000..ad0efe9
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcmddr_100to160.h
+@@ -0,0 +1,27 @@
++#if defined(_LINUX_)
++ #include <bsp.h>
++ #include <mach/ddr.h>
++#else
++#include "windows.h"
++
++#include "bsp.h"
++#include "tca_ckc.h"
++#endif
++
++#if defined(DRAM_MDDR)
++
++extern void init_clockchange100Mhz(void);
++extern void init_clockchange105Mhz(void);
++extern void init_clockchange110Mhz(void);
++extern void init_clockchange115Mhz(void);
++extern void init_clockchange120Mhz(void);
++extern void init_clockchange125Mhz(void);
++extern void init_clockchange130Mhz(void);
++extern void init_clockchange135Mhz(void);
++extern void init_clockchange140Mhz(void);
++extern void init_clockchange145Mhz(void);
++extern void init_clockchange150Mhz(void);
++extern void init_clockchange156Mhz(void);
++extern void init_clockchange160Mhz(void);
++#endif
++
+diff --git a/arch/arm/mach-tcc8900/tcc8900/tcc_ckcmddr_20to90.c b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcmddr_20to90.c
+new file mode 100644
+index 0000000..a57a7fb
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcmddr_20to90.c
+@@ -0,0 +1,1570 @@
++#include "tcc_ckcmddr_20to90.h"
++
++#if defined(DRAM_MDDR)
++void init_clockchange25Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++//PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x02006503; // pms - pllout_101M
++ *(volatile unsigned long *)0xB0400024= 0x82006503; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 3; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 4; // tRC 60ns
++
++ *(volatile unsigned long *)0xB0301028 = 0x14; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x87; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x14; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x2; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x2; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x1; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x2; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 8; // tXSR 120ns
++
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *) 0xB0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++ *(volatile unsigned long *)0xB0301008 = 0x00000022; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++//30.5Mhz
++void init_clockchange30Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 8
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++//PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x01007A03; // pms - pllout_244M
++ *(volatile unsigned long *)0xB0400024= 0x81007A03; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 3; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 4; // tRC 60ns
++
++ *(volatile unsigned long *)0xB0301028 = 0x14; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x87; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x14; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x2; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x2; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x1; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x2; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 8; // tXSR 120ns
++
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++
++ *(volatile unsigned long *) 0xB0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++ *(volatile unsigned long *)0xB0301008 = 0x00000022; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++//35.25Mhz
++void init_clockchange35Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 8
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++//PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x01002F01; // pms - pllout_282M
++ *(volatile unsigned long *)0xB0400024= 0x81002F01; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 3; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 4; // tRC 60ns
++
++ *(volatile unsigned long *)0xB0301028 = 0x14; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x87; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x14; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x2; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x2; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x1; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x2; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 8; // tXSR 120ns
++
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++
++ *(volatile unsigned long *) 0xB0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++ *(volatile unsigned long *)0xB0301008 = 0x00000022; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++void init_clockchange40Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 8
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++//PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00005003; // pms - pllout_320M
++ *(volatile unsigned long *)0xB0400024= 0x80005003; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 3; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 4; // tRC 60ns
++
++ *(volatile unsigned long *)0xB0301028 = 0x14; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x87; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x14; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x2; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x2; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x1; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x2; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 8; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++
++ *(volatile unsigned long *) 0xB0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++ *(volatile unsigned long *)0xB0301008 = 0x00000022; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++void init_clockchange45Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++//PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x01001E01; // pms - pllout_180M
++ *(volatile unsigned long *)0xB0400024= 0x81001E01; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 3; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 4; // tRC 60ns
++
++ *(volatile unsigned long *)0xB0301028 = 0x14; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x87; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x14; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x2; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x2; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x1; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x2; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 8; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++
++ *(volatile unsigned long *) 0xB0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++ *(volatile unsigned long *)0xB0301008 = 0x00000022; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++void init_clockchange50Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 8
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++//PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00006403; // pms - pllout_400M
++ *(volatile unsigned long *)0xB0400024= 0x80006403; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 3; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 4; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x14; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x66; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x14; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000002; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 8; // tXSR 120ns
++
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ *(volatile unsigned long *) 0xB0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++ *(volatile unsigned long *)0xB0301008 = 0x00000022; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++
++void init_clockchange55Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 8
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++//PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00006E03; // pms - pllout_440M
++ *(volatile unsigned long *)0xB0400024= 0x80006E03; // pll pwr on
++
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 3; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 4; // tRC 60ns
++
++ *(volatile unsigned long *)0xB0301028 = 0x14; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x87; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x14; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x2; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x2; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x1; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x2; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 8; // tXSR 120ns
++
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++
++ *(volatile unsigned long *) 0xB0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++ *(volatile unsigned long *)0xB0301008 = 0x00000022; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++void init_clockchange60Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 8
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++//PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00002801; // pms - pllout_480M
++ *(volatile unsigned long *)0xB0400024= 0x80002801; // pll pwr on
++
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 4; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 5; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x14; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0xE7; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x14; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000002; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 10; // tXSR 120ns
++
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++
++ *(volatile unsigned long *) 0xB0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++ *(volatile unsigned long *)0xB0301008 = 0x00000022; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++void init_clockchange65Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 8
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++//PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00008203; // pms - pllout_520M
++ *(volatile unsigned long *)0xB0400024= 0x80008203; // pll pwr on
++
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 4; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 5; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x14; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0xE7; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x14; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000002; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 10; // tXSR 120ns
++
++
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++
++ *(volatile unsigned long *) 0xB0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++ *(volatile unsigned long *)0xB0301008 = 0x00000022; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++void init_clockchange70Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++//PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x01002F01; // pms - pllout_282M
++ *(volatile unsigned long *)0xB0400024= 0x81002F01; // pll pwr on
++
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 4; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 9; // tRC 60ns
++
++ *(volatile unsigned long *)0xB0301028 = 0x14; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x18F; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x14; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000002; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 20; // tXSR 120ns
++
++
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++
++ *(volatile unsigned long *) 0xB0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++ *(volatile unsigned long *)0xB0301008 = 0x00000022; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++void init_clockchange75Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 8
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++//PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00003201; // pms - pllout_600M
++ *(volatile unsigned long *)0xB0400024= 0x80003201; // pll pwr on
++
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 4; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 9; // tRC 60ns
++
++ *(volatile unsigned long *)0xB0301028 = 0x14; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x18F; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x14; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000002; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 20; // tXSR 120ns
++
++
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++
++ *(volatile unsigned long *) 0xB0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++ *(volatile unsigned long *)0xB0301008 = 0x00000022; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++void init_clockchange80Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++//PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00005003; // pms - pllout_320M
++ *(volatile unsigned long *)0xB0400024= 0x80005003; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 3; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 5; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x14; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x66; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x14; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 10; // tXSR 120ns
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++
++ *(volatile unsigned long *) 0xB0304404 &= ~(0x00000003); // DLLCTRL - DLL OFF, Not Useing DLL
++ *(volatile unsigned long *)0xB0301008 = 0x00000022; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++ *(volatile unsigned long *)0xB0301008 = 0x00040022;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++}
++
++void init_clockchange85Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++//PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00005503; // pms - pllout_340M
++ *(volatile unsigned long *)0xB0400024= 0x80005503; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++//190Mhz
++void init_clockchange90Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00001E01; // pms - pllout_360M
++ *(volatile unsigned long *)0xB0400024= 0x80001E01; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++//Change MEM Source
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++
++void init_clockchange95Mhz(void)
++{
++ #define lchange_source 2
++ #define lchange_div 4
++
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #define lmem_div 4
++
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xB0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xB0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xB0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xB0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xB030302C &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lchange_div-1) << 4)|lchange_source); // CKC-CLKCTRL2 - Mem
++
++ //PLL1
++ *(volatile unsigned long *)0xB0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xB0400024= 0x00005F03; // pms - pllout_380M
++ *(volatile unsigned long *)0xB0400024= 0x80005F03; // pll pwr on
++
++//Init DDR2
++ *(volatile unsigned long *)0xB030100C = 0x00210012; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++
++ *(volatile unsigned long *) 0xB0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xB0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xB030104C= 0x000002D1;
++ *(volatile unsigned long *)0xB0301010 = 0x000003E8; // refresh_prd = 1000
++
++#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xB0301014 = 0x00000006; // cas_latency = 3
++#else
++ *(volatile unsigned long *)0xB0301014 = 0x00000004; // cas_latency = 2
++#endif
++
++ *(volatile unsigned long *)0xB030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xB0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xB0301024 = 0x0000000F; // tRC 60ns
++ *(volatile unsigned long *)0xB0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xB030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xB0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xB0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xB0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xB030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xB0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xB0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xB0301048 = 0x00000032; // tESR=200
++
++ *(volatile unsigned long *)0xB0301200 = 0x000040F0; // Chip 0
++
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xB030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xB0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++
++ *(volatile unsigned long *)0xB0301008 = 0x00000032; //MRS
++ *(volatile unsigned long *)0xB0301008 = 0x000a0000;//EMRS
++ *(volatile unsigned long *)0xB0301008 = 0x00080032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++ *(volatile unsigned long *)0xB0301008 = 0x00040032;
++
++//Change MEM Source
++
++
++ *(volatile unsigned long *)0xB0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++
++
++ *(volatile unsigned long *) 0xB0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xB0301000) & (0x03)) != 1); // Wait until READY
++
++}
++#endif
+diff --git a/arch/arm/mach-tcc8900/tcc8900/tcc_ckcmddr_20to90.h b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcmddr_20to90.h
+new file mode 100644
+index 0000000..96b719d
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/tcc8900/tcc_ckcmddr_20to90.h
+@@ -0,0 +1,29 @@
++
++#if defined(_LINUX_)
++ #include <bsp.h>
++ #include <mach/ddr.h>
++#else
++#include "windows.h"
++
++#include "bsp.h"
++#include "tca_ckc.h"
++#endif
++
++#if defined(DRAM_MDDR)
++extern void init_clockchange25Mhz(void);
++extern void init_clockchange30Mhz(void);
++extern void init_clockchange35Mhz(void);
++extern void init_clockchange40Mhz(void);
++extern void init_clockchange45Mhz(void);
++extern void init_clockchange50Mhz(void);
++extern void init_clockchange55Mhz(void);
++extern void init_clockchange60Mhz(void);
++extern void init_clockchange65Mhz(void);
++extern void init_clockchange70Mhz(void);
++extern void init_clockchange75Mhz(void);
++extern void init_clockchange80Mhz(void);
++extern void init_clockchange85Mhz(void);
++extern void init_clockchange90Mhz(void);
++extern void init_clockchange95Mhz(void);
++#endif
++
+diff --git a/arch/arm/mach-tcc8900/tcc_ckc_ctrl.c b/arch/arm/mach-tcc8900/tcc_ckc_ctrl.c
+new file mode 100644
+index 0000000..37eea99
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/tcc_ckc_ctrl.c
+@@ -0,0 +1,803 @@
++/*
++ * linux/arch/arm/mach-tcc8900/tcc_ckc_ctrl.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 10th February, 2009
++ * Description: Interrupt handler for Telechips TCC8900 chipset
++ *
++ * Copyright (C) Telechips, Inc.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <asm/uaccess.h>
++#include <mach/hardware.h>
++#include <asm/tlbflush.h>
++#include <asm/cacheflush.h>
++#include <linux/spinlock.h>
++#include <linux/sched.h>
++#include <linux/tick.h>
++#include <linux/time.h>
++
++#if defined(CONFIG_MACH_TCC8900)
++#include <bsp.h>
++#include <linux/tcc_ioctl.h>
++#include <mach/tcc_ckc_ctrl.h>
++#include "tcc/tcc_ckcddr2_141to190.h"
++#include "tcc/tcc_ckcddr2_200to290.h"
++#include "tcc/tcc_ckcddr2_300to330.h"
++#include "tcc/tcc_ckcmddr_100to160.h"
++#include "tcc/tcc_ckcmddr_20to90.h"
++#endif
++
++#if 0
++//#define dbg(x...) printk(KERN_DEBUG "tcc uart: ");
++#define dbg printk
++#else /* no debug */
++#define dbg(x...) do {} while(0)
++#endif
++
++#define FBUS_STEP_NUM 34
++#define FCORE_STEP_NUM 60
++
++typedef void (*lpfunc)(void);
++lpfunc lpSelfRefresh;
++//#define SRAM_COPY_ADDR 0xF0800000
++#define SRAM_COPY_ADDR 0xEFF00000
++#define SRAM_COPY_FUNC_SIZE 0x600
++
++unsigned int retstack = 0;
++unsigned long flags;
++
++unsigned int FbusStepValue[FBUS_STEP_NUM] = {
++ 2640000, // PLL3
++ 2340000,
++ 1760000, // PLL3
++ 1560000,
++ 1320000, // PLL3
++ 1170000,
++ 1056000, // PLL3
++ 936000,
++ 880000, // PLL3
++ 780000,
++ 754285, // PLL3
++ 668571,
++ 660000, // PLL3
++ 586666, // PLL3
++ 585000,
++ 528000, // PLL3
++ 520000,
++ 480000, // PLL3
++ 468000,
++ 440000, // PLL3
++ 425454,
++ 406153, // PLL3
++ 390000,
++ 377142, // PLL3
++ 360000,
++ 352000, // PLL3
++ 334285,
++ 330000, // PLL3
++ 312000,
++ 292500,
++ 60000, // XIN
++ 30000, // XIN
++ 10000, // XIN
++};
++
++unsigned int FcoreStepValue[FCORE_STEP_NUM] = {
++ 5400000,
++ 5062500,4860000,4725000,4556250,4387500,4252500,4050000,3948750,3780000,3712500,
++ 3645000,3510000,3375000,3240000,3037500,2970000,2835000,2700000,2632500,2430000,
++ 2362500,2227500,2160000,2025000,1890000,1822500,1750000,1687500,1620000,1518750,
++ 1485000,1417500,1350000 ,1215000,1125000,1080000,1012500, 960000 ,945000, 907500 ,
++ 883750 ,840000 , 810000 ,787500 ,757500 ,730000 ,712500 ,660000 ,631250,607500 ,
++ 577500 ,540000 , 495000 ,450000 ,405000 ,378750 ,360000 ,330000 ,270000
++};
++
++unsigned int FcorePllValue[FCORE_STEP_NUM] = {
++ 5400000,
++ 5400000, 4860000, 5400000, 4860000, 5400000, 4860000, 4320000, 4860000, 4320000, 5400000,
++ 4860000, 4320000, 5400000, 3240000, 3240000, 4320000, 3240000, 5400000, 3240000, 3240000,
++ 5400000, 3240000, 2160000, 2160000, 2160000, 3240000, 2160000, 5400000, 2160000, 4860000,
++ 2160000,3240000, 2160000, 2160000, 1800000, 2160000, 3240000, 1920000, 2160000, 1320000,
++ 2020000, 1920000, 2160000, 1800000, 2020000, 1460000, 1900000, 1320000, 2020000, 3240000,
++ 1320000, 1440000, 1320000, 1440000, 2160000, 2020000, 1440000,1320000,1440000,
++};
++
++unsigned int FcoreDividerValue[FCORE_STEP_NUM] = {
++ 16,
++ 15, 16, 14, 15, 13, 14, 15, 13, 14, 11,
++ 12, 13, 10, 16, 15, 11, 14, 8, 13, 12,
++ 7, 11, 16, 15, 14, 9, 13, 5, 12 , 5,
++ 11, 7, 10, 9, 10, 8, 5, 8, 7, 11,
++ 7, 7, 6, 7, 6, 8, 6, 8, 5, 3,
++ 7, 6, 6, 5, 3, 3, 4, 4, 3
++
++};
++
++
++
++
++void ckc_delay(unsigned int cnt)
++{
++ volatile unsigned int count;
++ count = cnt*10000;
++ while(count--);
++}
++
++
++void ckc_etcblock(unsigned int lMask)
++{
++ volatile PUSBOTGCFG pOTGCFG = (volatile PUSBOTGCFG)tcc_p2v(HwUSBOTGCFG_BASE);
++ volatile PGPUGRPBUSCONFIG pGPUGRPBUSCONFIG = (volatile PGPUGRPBUSCONFIG)tcc_p2v(HwGRPBUS_BASE);
++
++// Disable
++ if(lMask & ETCMASK_USBPHYOFF)
++ {
++ dbg("%s: ETC_USBPHYOFF\n", __func__);
++ BITCSET(pOTGCFG->UPCR2,Hw10|Hw9,Hw9);
++ pOTGCFG->UPCR0 = 0x4840;
++ pOTGCFG->UPCR0 = 0x6940;
++ }
++
++ if(lMask & ETCMASK_3DGPUOFF)
++ {
++ dbg("%s: ETCMASK_3DGPUOFF\n", __func__);
++ pGPUGRPBUSCONFIG->GRPBUS_PWRDOWN |= Hw0;
++ }
++
++ if(lMask & ETCMASK_OVERLAYMIXEROFF)
++ {
++ dbg("%s: ETCMASK_OVERLAYMIXEROFF\n", __func__);
++ pGPUGRPBUSCONFIG->GRPBUS_PWRDOWN |= Hw1;
++ }
++
++//Enable
++ if(lMask & ETCMASK_OVERLAYMIXERON)
++ {
++ dbg("%s: ETCMASK_OVERLAYMIXEROFF\n", __func__);
++ pGPUGRPBUSCONFIG->GRPBUS_PWRDOWN &= ~Hw1;
++ }
++
++ if(lMask & ETCMASK_3DGPUON)
++ {
++ dbg("%s: ETCMASK_3DGPUON\n", __func__);
++ pGPUGRPBUSCONFIG->GRPBUS_PWRDOWN &= ~Hw0;
++ }
++
++ if(lMask & ETCMASK_USBPHYON)
++ {
++ dbg("%s: ETC_USBPHYON\n", __func__);
++ BITCSET(pOTGCFG->UPCR2,Hw10|Hw9,0);
++ pOTGCFG->UPCR0 = 0x2842;
++ }
++}
++
++
++void int_alldisable(void)
++{
++ /*
++ volatile unsigned int count;
++ count = 1;
++ while(count--);
++ */
++ local_irq_save(flags);
++ local_irq_disable();
++
++}
++
++void int_restore(void)
++{
++ /*
++ volatile unsigned int count;
++ count = 1;
++ while(count--);
++ */
++
++ local_irq_restore(flags);
++}
++
++
++
++static void init_copychangeclock(unsigned int lbusvalue)
++{
++
++ volatile unsigned int *fptr;
++ volatile unsigned int *p;
++ int i;
++
++#if defined(CONFIG_DRAM_DDR2)
++ if(lbusvalue == 1250000)
++ fptr = (volatile unsigned int*)init_clockchange125Mhz;
++ else if(lbusvalue == 1300000)
++ fptr = (volatile unsigned int*)init_clockchange130Mhz;
++ else if(lbusvalue == 1350000)
++ fptr = (volatile unsigned int*)init_clockchange135Mhz;
++ else if(lbusvalue == 1410000)
++ fptr = (volatile unsigned int*)init_clockchange141Mhz;
++ else if(lbusvalue == 1450000)
++ fptr = (volatile unsigned int*)init_clockchange145Mhz;
++ else if(lbusvalue == 1500000)
++ fptr = (volatile unsigned int*)init_clockchange150Mhz;
++ else if(lbusvalue == 1600000)
++ fptr = (volatile unsigned int*)init_clockchange160Mhz;
++ else if(lbusvalue == 1700000)
++ fptr = (volatile unsigned int*)init_clockchange170Mhz;
++ else if(lbusvalue == 1800000)
++ fptr = (volatile unsigned int*)init_clockchange180Mhz;
++ else if(lbusvalue == 1900000)
++ fptr = (volatile unsigned int*)init_clockchange190Mhz;
++ else if(lbusvalue == 2000000)
++ fptr = (volatile unsigned int*)init_clockchange200Mhz;
++ else if(lbusvalue == 2100000)
++ fptr = (volatile unsigned int*)init_clockchange210Mhz;
++ else if(lbusvalue == 2200000)
++ fptr = (volatile unsigned int*)init_clockchange220Mhz;
++ else if(lbusvalue == 2300000)
++ fptr = (volatile unsigned int*)init_clockchange230Mhz;
++ else if(lbusvalue == 2400000)
++ fptr = (volatile unsigned int*)init_clockchange240Mhz;
++ else if(lbusvalue == 2500000)
++ fptr = (volatile unsigned int*)init_clockchange250Mhz;
++ else if(lbusvalue == 2600000)
++ fptr = (volatile unsigned int*)init_clockchange260Mhz;
++ else if(lbusvalue == 2700000)
++ fptr = (volatile unsigned int*)init_clockchange270Mhz;
++ else if(lbusvalue == 2800000)
++ fptr = (volatile unsigned int*)init_clockchange280Mhz;
++ else if(lbusvalue == 2900000)
++ fptr = (volatile unsigned int*)init_clockchange290Mhz;
++ else if(lbusvalue == 3000000)
++ fptr = (volatile unsigned int*)init_clockchange300Mhz;
++ else if(lbusvalue == 3120000)
++ fptr = (volatile unsigned int*)init_clockchange312Mhz;
++ else if(lbusvalue == 3200000)
++ fptr = (volatile unsigned int*)init_clockchange320Mhz;
++ else if(lbusvalue == 3300000)
++ fptr = (volatile unsigned int*)init_clockchange330Mhz;
++ else
++ fptr = (volatile unsigned int*)init_clockchange190Mhz;
++
++#elif defined(CONFIG_DRAM_MDDR)
++ if(lbusvalue == 250000) // idle
++ fptr = (volatile unsigned int*)init_clockchange25Mhz;
++ else if(lbusvalue == 305000)
++ fptr = (volatile unsigned int*)init_clockchange30Mhz;
++ else if(lbusvalue == 352500)
++ fptr = (volatile unsigned int*)init_clockchange35Mhz;
++ else if(lbusvalue == 400000)
++ fptr = (volatile unsigned int*)init_clockchange40Mhz;
++ else if(lbusvalue == 450000)
++ fptr = (volatile unsigned int*)init_clockchange45Mhz;
++ else if(lbusvalue == 500000)
++ fptr = (volatile unsigned int*)init_clockchange50Mhz;
++ else if(lbusvalue == 550000)
++ fptr = (volatile unsigned int*)init_clockchange55Mhz;
++ else if(lbusvalue == 600000)
++ fptr = (volatile unsigned int*)init_clockchange60Mhz;
++ else if(lbusvalue == 650000)
++ fptr = (volatile unsigned int*)init_clockchange65Mhz;
++ else if(lbusvalue == 705000)
++ fptr = (volatile unsigned int*)init_clockchange70Mhz;
++ else if(lbusvalue == 750000)
++ fptr = (volatile unsigned int*)init_clockchange75Mhz;
++ else if(lbusvalue == 800000)
++ fptr = (volatile unsigned int*)init_clockchange80Mhz;
++ else if(lbusvalue == 850000)
++ fptr = (volatile unsigned int*)init_clockchange85Mhz;
++ else if(lbusvalue == 900000)
++ fptr = (volatile unsigned int*)init_clockchange90Mhz;
++ else if(lbusvalue == 950000)
++ fptr = (volatile unsigned int*)init_clockchange95Mhz;
++ else if(lbusvalue == 1000000)
++ fptr = (volatile unsigned int*)init_clockchange100Mhz;
++ else if(lbusvalue == 1050000)
++ fptr = (volatile unsigned int*)init_clockchange105Mhz;
++ else if(lbusvalue == 1100000)
++ fptr = (volatile unsigned int*)init_clockchange110Mhz;
++ else if(lbusvalue == 1150000)
++ fptr = (volatile unsigned int*)init_clockchange115Mhz;
++ else if(lbusvalue == 1200000)
++ fptr = (volatile unsigned int*)init_clockchange120Mhz;
++ else if(lbusvalue == 1250000)
++ fptr = (volatile unsigned int*)init_clockchange125Mhz;
++ else if(lbusvalue == 1300000)
++ fptr = (volatile unsigned int*)init_clockchange130Mhz;
++ else if(lbusvalue == 1350000)
++ fptr = (volatile unsigned int*)init_clockchange135Mhz;
++ else if(lbusvalue == 1400000)
++ fptr = (volatile unsigned int*)init_clockchange140Mhz;
++ else if(lbusvalue == 1450000)
++ fptr = (volatile unsigned int*)init_clockchange145Mhz;
++ else if(lbusvalue == 1500000)
++ fptr = (volatile unsigned int*)init_clockchange150Mhz;
++ else if(lbusvalue == 1560000)
++ fptr = (volatile unsigned int*)init_clockchange156Mhz;
++ else if(lbusvalue == 1600000)
++ fptr = (volatile unsigned int*)init_clockchange160Mhz;
++ else
++ fptr = (volatile unsigned int*)init_clockchange160Mhz;
++#endif
++
++
++ lpSelfRefresh = (lpfunc)(SRAM_COPY_ADDR);
++
++ p = (volatile unsigned int*)SRAM_COPY_ADDR;
++
++ for (i = 0;i < (SRAM_COPY_FUNC_SIZE);i++)
++ {
++ *p = *fptr;
++ p++;
++ fptr++;
++ }
++
++ while(--i);
++
++ // Jump to Function Start Point
++ lpSelfRefresh();
++}
++
++void memchange(unsigned int freq)
++{
++ volatile PLCDC pLCDC_BASE0 = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++ volatile PLCDC pLCDC_BASE1 = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ volatile PTIMER pTIMER = (volatile PTIMER)tcc_p2v(HwTMR_BASE);
++
++ // Off LCD
++ pLCDC_BASE1->LCTRL &= ~Hw0;
++ pLCDC_BASE0->LCTRL &= ~Hw0;
++
++ int_alldisable();
++ local_flush_tlb_all();
++ flush_cache_all();
++
++ pTIMER->TC32EN &= ~Hw24;
++
++ retstack = arm_changestack();
++
++ init_copychangeclock(freq);
++
++ arm_restorestack(retstack);
++
++ pTIMER->TC32EN |= Hw24;
++
++ int_restore();
++
++ // LCDC Power Up
++// pLCDC_BASE0->LCTRL |= Hw0;
++ pLCDC_BASE1->LCTRL |= Hw0;
++ *(volatile unsigned long *)0xF0200000 &= ~(0x1);//disable LCD0
++}
++
++int tcc_ckc_change_cpu(unsigned int cpuvalue)
++{
++ unsigned int i, validFlag;
++
++ int_alldisable();
++
++ for(i = 0; i < FCORE_STEP_NUM; i++)
++ {
++ if(cpuvalue == FcoreStepValue[i]) {
++ validFlag = 1;
++ break;
++ }
++ }
++
++ if(validFlag == 1)
++ {
++ // Change pll
++ if(tca_ckc_getpll(0) != FcorePllValue[i])
++ tca_ckc_setpll(FcorePllValue[i],0);
++ tca_ckc_setcpu(FcoreDividerValue[i]);
++ }
++ int_restore();
++
++ return validFlag == 1 ? 0 : 1;
++}
++EXPORT_SYMBOL(tcc_ckc_change_cpu);
++
++void ckc_set_peri(struct ckc_ioctl st)
++{
++ int_alldisable();
++ tca_ckc_setperi(st.in_ckc.pckcname, st.in_ckc.pckcenable,
++ st.in_ckc.pckcfreq, st.in_ckc.pckcsource);
++ int_restore();
++}
++
++int ckc_get_peri(struct ckc_ioctl st)
++{
++ return tca_ckc_getperi(st.in_ckc.pckcname);
++}
++
++int ckc_set_peribus(struct ckc_ioctl st)
++{
++ return tca_ckc_setiobus(st.in_ckc.prbname, st.in_ckc.mode);
++}
++
++int ckc_get_peribus(struct ckc_ioctl st)
++{
++ return tca_ckc_getiobus(st.in_ckc.prbname);
++}
++
++void ckc_set_periswreset(struct ckc_ioctl st)
++{
++ tca_ckc_set_iobus_swreset(st.in_ckc.prbname, OFF);
++ tca_ckc_set_iobus_swreset(st.in_ckc.prbname, ON);
++}
++
++void ckc_set_fbusswreset(struct ckc_ioctl st)
++{
++ tca_ckc_setswreset(st.in_ckc.fbusname, ON);
++ ckc_delay(100);
++ tca_ckc_setswreset(st.in_ckc.fbusname, OFF);
++}
++
++void ckc_set_cpu(struct ckc_ioctl st)
++{
++ int_alldisable();
++
++ tca_ckc_setcpu(st.in_ckc.cpudivider);
++ st.out_ckc.currentsysfreq = tca_ckc_getpll(0);
++ st.out_ckc.currentcpufreq = tca_ckc_getcpu();
++ st.out_ckc.currentbusfreq = tca_ckc_getbus();
++
++ int_restore();
++}
++
++void ckc_set_smui2c(struct ckc_ioctl st)
++{
++ tca_ckc_setsmui2c(st.in_ckc.pckcfreq);
++}
++
++unsigned int ckc_get_cpu(struct ckc_ioctl st)
++{
++ return tca_ckc_getcpu();
++}
++
++unsigned int ckc_get_bus(struct ckc_ioctl st)
++{
++ return tca_ckc_getbus();
++}
++
++void ckc_get_validpllinfo(struct ckc_ioctl st)
++{
++ tca_ckc_validpll(st.out_ckc.validpll);
++}
++
++void ckc_set_fbus(struct ckc_ioctl st)
++{
++ tca_ckc_setfbusctrl(st.in_ckc.fbusname, st.in_ckc.fbusenable,
++ st.in_ckc.mode, st.in_ckc.fbusfreq,
++ st.in_ckc.fbussource);
++}
++
++int ckc_get_fbus(struct ckc_ioctl st)
++{
++ return tca_ckc_getfbusctrl(st.in_ckc.fbusname);
++
++}
++
++void ckc_set_pmupower(struct ckc_ioctl st)
++{
++#if defined(CONFIG_TCC_R_AX)
++ if(st.in_ckc.mode == 0)
++ {
++ st.in_ckc.fbusenable = DISABLE;
++ st.in_ckc.mode = NORMAL_MD;
++ tca_ckc_setfbusctrl(st.in_ckc.fbusname, st.in_ckc.fbusenable, st.in_ckc.mode, st.in_ckc.fbusfreq, st.in_ckc.fbussource);
++ tca_ckc_setswreset(st.in_ckc.fbusname,ON);
++ ckc_delay(100);
++ tca_ckc_setswreset(st.in_ckc.fbusname,OFF);
++ tca_ckc_setpmupwroff(st.in_ckc.pmuoffname, st.in_ckc.fbusenable);
++ } else {
++ tca_ckc_setswreset(st.in_ckc.fbusname,ON);
++ ckc_delay(100);
++ tca_ckc_setswreset(st.in_ckc.fbusname,OFF);
++ tca_ckc_setpmupwroff(st.in_ckc.pmuoffname,ENABLE);
++
++ st.in_ckc.fbusenable = ENABLE;
++ st.in_ckc.mode = NORMAL_MD;
++ tca_ckc_setfbusctrl(st.in_ckc.fbusname,st.in_ckc.fbusenable,st.in_ckc.mode,st.in_ckc.fbusfreq,st.in_ckc.fbussource);
++ }
++#endif
++}
++
++void ckc_get_pmupower(struct ckc_ioctl st)
++{
++ tca_ckc_getpmupwroff(st.in_ckc.pmuoffname);
++}
++
++void ckc_get_clockinfo(struct ckc_ioctl st)
++{
++ st.out_ckc.currentsysfreq = tca_ckc_getpll(0);
++ st.out_ckc.currentcpufreq = tca_ckc_getcpu();
++ st.out_ckc.currentbusfreq = tca_ckc_getbus();
++}
++
++void ckc_set_changefbus(struct ckc_ioctl st)
++{
++ int i, validFlag;
++ // Except : FCORE_CPU, FMEM_BUS, FBUS_IOB
++ // Change Fbus : FBUS_DDI, FBUS_GRP, FBUS_VBUS, FBUS_VCODEC, FBUS_SMU
++ //
++ int_alldisable();
++ local_flush_tlb_all();
++ flush_cache_all();
++
++ if(st.in_ckc.fbusname != CLKCTRL0 && st.in_ckc.fbusname != CLKCTRL2 )
++ {
++ //if(st.in_ckc.fbusfreq == 60000 || st.in_ckc.fbusfreq == 0)
++ if( st.in_ckc.fbusfreq == 0)
++ {
++#if defined(CONFIG_TCC_R_AX)
++ st.in_ckc.fbusenable = DISABLE;
++ st.in_ckc.mode = NORMAL_MD;
++
++ if(st.in_ckc.fbusname == CLKCTRL1)
++ {
++ st.in_ckc.pmuoffname = PMU_DDIBUS;
++ validFlag = 0;
++ }
++ else if(st.in_ckc.fbusname == CLKCTRL5)
++ {
++ st.in_ckc.pmuoffname = PMU_VIDEOBUS;
++ validFlag = 1;
++ }
++ else if(st.in_ckc.fbusname == CLKCTRL3)
++ {
++ st.in_ckc.pmuoffname = PMU_GRAPHICBUS;
++ validFlag = 1;
++ }
++ else
++ validFlag = 0;
++
++ if(validFlag == 1)
++ {
++ if(st.in_ckc.fbusname == CLKCTRL5)
++ {
++ tca_ckc_setswreset(CLKCTRL5,ON);
++ tca_ckc_setswreset(CLKCTRL6,ON);
++
++ ckc_delay(10);
++ tca_ckc_setfbusctrl(st.in_ckc.fbusname,st.in_ckc.fbusenable,st.in_ckc.mode,st.in_ckc.fbusfreq,st.in_ckc.fbussource);
++
++ tca_ckc_setpmupwroff(PMU_VIDEOBUS,DISABLE);
++ }
++ else
++ {
++ tca_ckc_setswreset(st.in_ckc.fbusname,ON);
++ ckc_delay(10);
++ tca_ckc_setfbusctrl(st.in_ckc.fbusname,st.in_ckc.fbusenable,st.in_ckc.mode,st.in_ckc.fbusfreq,st.in_ckc.fbussource);
++ tca_ckc_setpmupwroff(st.in_ckc.pmuoffname,DISABLE);
++ }
++
++ if(st.in_ckc.fbusname == CLKCTRL5)
++ {
++ tca_ckc_setswreset(CLKCTRL6,OFF);
++ tca_ckc_setswreset(CLKCTRL5,OFF);
++ }
++ else
++ tca_ckc_setswreset(st.in_ckc.fbusname,OFF);
++
++ }
++ else
++ {
++ tca_ckc_setswreset(st.in_ckc.fbusname,ON);
++ ckc_delay(10);
++ tca_ckc_setfbusctrl(st.in_ckc.fbusname,st.in_ckc.fbusenable,st.in_ckc.mode,st.in_ckc.fbusfreq,st.in_ckc.fbussource);
++ tca_ckc_setswreset(st.in_ckc.fbusname,OFF);
++ }
++ #else
++ //tca_ckc_setswreset(st.in_ckc.fbusname);
++ validFlag = 1;
++ tca_ckc_setfbusctrl(st.in_ckc.fbusname,ENABLE,NORMAL_MD,60000,DIRECTXIN);
++ #endif
++ }
++ else
++ {
++#if defined(CONFIG_TCC_R_AX)
++ if(st.in_ckc.fbusname == CLKCTRL1)
++ {
++ st.in_ckc.pmuoffname = PMU_DDIBUS;
++ validFlag = 0;
++ }
++ else if(st.in_ckc.fbusname == CLKCTRL5)
++ {
++ st.in_ckc.pmuoffname = PMU_VIDEOBUS;
++ validFlag = 1;
++ }
++ else if(st.in_ckc.fbusname == CLKCTRL3)
++ {
++ st.in_ckc.pmuoffname = PMU_GRAPHICBUS;
++ validFlag = 1;
++ }
++ else
++ validFlag = 0;
++
++ if(validFlag == 1)
++ {
++ if(st.in_ckc.fbusname == CLKCTRL5)
++ {
++ tca_ckc_setswreset(CLKCTRL5,ON);
++ tca_ckc_setswreset(CLKCTRL6,ON);
++ tca_ckc_setpmupwroff(PMU_VIDEOBUS,ENABLE);
++ }
++ else
++ {
++ tca_ckc_setswreset(st.in_ckc.fbusname,ON);
++ tca_ckc_setpmupwroff(st.in_ckc.pmuoffname,ENABLE);
++ }
++
++ ckc_delay(100);
++ if(st.in_ckc.fbusname == CLKCTRL5)
++ {
++ tca_ckc_setswreset(CLKCTRL6,OFF);
++ tca_ckc_setswreset(CLKCTRL5,OFF);
++ }
++ else
++ tca_ckc_setswreset(st.in_ckc.fbusname,OFF);
++ }
++ #endif
++ {
++ //validFlag = 0;
++ for(i = 0; i < FBUS_STEP_NUM; i++)
++ {
++ if(st.in_ckc.fbusfreq == FbusStepValue[i] || st.in_ckc.fbusfreq == 3300000)
++ {
++ validFlag = 1;
++ break;
++ }
++ }
++
++ if( validFlag == 1)
++ {
++ if(i <= 12)
++ {
++ if((i%2) == 1)
++ st.in_ckc.fbussource = DIRECTPLL2;
++ else
++ st.in_ckc.fbussource = DIRECTPLL3;
++ }
++ else
++ {
++ if(i >= FBUS_STEP_NUM-3)
++ {
++ st.in_ckc.fbussource = DIRECTXIN;
++ }
++ else if(i == (FBUS_STEP_NUM-4))
++ {
++ st.in_ckc.fbussource = DIRECTPLL2;
++ }
++ else
++ {
++ if((i%2) == 1)
++ st.in_ckc.fbussource = DIRECTPLL3;
++ else
++ st.in_ckc.fbussource = DIRECTPLL2;
++ }
++ }
++ }
++ }
++
++ if( validFlag == 1)
++ {
++ st.in_ckc.fbusenable = ENABLE;
++ st.in_ckc.mode = NORMAL_MD;
++ tca_ckc_setfbusctrl(st.in_ckc.fbusname,st.in_ckc.fbusenable,st.in_ckc.mode,st.in_ckc.fbusfreq,st.in_ckc.fbussource);
++ }
++ }
++ int_restore();
++ }
++}
++
++void ckc_set_changemem(struct ckc_ioctl st)
++{
++ volatile PLCDC pLCDC_BASE0 = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++ volatile PLCDC pLCDC_BASE1 = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ volatile PTIMER pTIMER = (volatile PTIMER)tcc_p2v(HwTMR_BASE);
++
++ // Off LCD
++ pLCDC_BASE1->LCTRL &= ~Hw0;
++ pLCDC_BASE0->LCTRL &= ~Hw0;
++
++ int_alldisable();
++ local_flush_tlb_all();
++ flush_cache_all();
++
++ pTIMER->TC32EN &= ~Hw24;
++
++ retstack = arm_changestack();
++
++ init_copychangeclock(st.in_ckc.busvalue);
++
++ arm_restorestack(retstack);
++
++ pTIMER->TC32EN |= Hw24;
++
++ int_restore();
++
++ // LCDC Power Up
++ pLCDC_BASE0->LCTRL |= Hw0;
++ pLCDC_BASE1->LCTRL |= Hw0;
++}
++
++void ckc_set_changecpu(struct ckc_ioctl st)
++{
++ int i, validFlag;
++
++ int_alldisable();
++
++ for(i = 0; i < FCORE_STEP_NUM; i++)
++ {
++ if(st.in_ckc.cpuvalue == FcoreStepValue[i]) {
++ validFlag = 1;
++ break;
++ }
++ }
++
++ if( validFlag == 1)
++ {
++ // Change pll
++ if(tca_ckc_getpll(0) != FcorePllValue[i])
++ tca_ckc_setpll(FcorePllValue[i],0);
++
++ tca_ckc_setcpu(FcoreDividerValue[i]);
++ }
++ int_restore();
++}
++
++void ckc_set_ddipwdn(struct ckc_ioctl st)
++{
++ tca_ckc_setddipwdn(st.in_ckc.ddipdname, st.in_ckc.mode);
++}
++
++void ckc_get_ddipwdn(struct ckc_ioctl st)
++{
++ st.out_ckc.retVal = tca_ckc_getddipwdn(st.in_ckc.ddipdname);
++}
++
++void ckc_set_etcblock(struct ckc_ioctl st)
++{
++ ckc_etcblock(st.in_ckc.etcblock);
++}
++
++
++EXPORT_SYMBOL(ckc_set_peri);
++EXPORT_SYMBOL(ckc_get_peri);
++EXPORT_SYMBOL(ckc_set_peribus);
++EXPORT_SYMBOL(ckc_get_peribus);
++EXPORT_SYMBOL(ckc_set_periswreset);
++EXPORT_SYMBOL(ckc_set_fbusswreset);
++EXPORT_SYMBOL(ckc_set_cpu);
++EXPORT_SYMBOL(ckc_set_smui2c);
++EXPORT_SYMBOL(ckc_get_cpu);
++EXPORT_SYMBOL(ckc_get_bus);
++EXPORT_SYMBOL(ckc_get_validpllinfo);
++EXPORT_SYMBOL(ckc_set_fbus);
++EXPORT_SYMBOL(ckc_get_fbus);
++EXPORT_SYMBOL(ckc_set_pmupower);
++EXPORT_SYMBOL(ckc_get_pmupower);
++EXPORT_SYMBOL(ckc_get_clockinfo);
++EXPORT_SYMBOL(ckc_set_changefbus);
++EXPORT_SYMBOL(ckc_set_changemem);
++EXPORT_SYMBOL(ckc_set_changecpu);
++EXPORT_SYMBOL(ckc_set_ddipwdn);
++EXPORT_SYMBOL(ckc_get_ddipwdn);
++EXPORT_SYMBOL(ckc_set_etcblock);
+diff --git a/arch/arm/mach-tcc8900/time.c b/arch/arm/mach-tcc8900/time.c
+new file mode 100644
+index 0000000..a561b96
+--- /dev/null
++++ b/arch/arm/mach-tcc8900/time.c
+@@ -0,0 +1,135 @@
++/*
++ * linux/arch/arm/mach-tcc8900/time.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 10th Feb, 2009
++ * Description: TCC8900 Timers
++ *
++ * Copyright (C) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++/*
++ * Returns elapsed usecs since last system timer interrupt
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#include <linux/irq.h> // for setup_irq()
++#include <linux/mm.h> // for PAGE_ALIGN
++
++#include <asm/io.h>
++#include <asm/leds.h>
++#include <asm/mach/time.h>
++
++#include <bsp.h>
++
++#include <linux/tcc_ll.h>
++
++#define TCC_TIMER_FREQ (12 * 1000 * 1000) /* 12M */
++#define TCC_ENABLE_BIT(X) (1 << (X))
++
++#if (TCC_TIMER_FREQ < (1000 * 1000))
++# define PRESCALE_TO_MICROSEC(X) ((X) * ((1000 * 1000) / (TCC_TIMER_FREQ)))
++#else
++# define PRESCALE_TO_MICROSEC(X) ((X) / ((TCC_TIMER_FREQ) / (1000 * 1000)))
++#endif
++
++// Global
++static volatile PTIMER pTIMER;
++static volatile PPIC pPIC;
++
++/*
++ * Returns elapsed usecs since last system timer interrupt
++ */
++static unsigned long tcc8900_timer_gettimeoffset(void)
++{
++ return PRESCALE_TO_MICROSEC(pTIMER->TC32PCNT);
++}
++
++static irqreturn_t tcc8900_timer_interrupt(int irq, void *dev_id)
++{
++ timer_tick();
++
++ BITSET(pPIC->CLR0, TCC_ENABLE_BIT(irq));
++ if(pTIMER->TC32IRQ & Hw31)
++ BITSET(pTIMER->TC32IRQ, Hw31);
++
++ return IRQ_HANDLED;
++}
++
++static struct irqaction tcc8900_timer_irq = {
++ .name = "TC1_timer",
++ .flags = IRQF_DISABLED | IRQF_TIMER,
++ .handler = tcc8900_timer_interrupt,
++};
++
++/*
++ * Scheduler clock - returns current time in nanosec units.
++ */
++unsigned long long sched_clock(void)
++{
++ return ((unsigned long long)jiffies) * (1000000000llu / HZ);
++}
++
++
++/*
++ * Timer Initialization
++ */
++static void __init tcc8900_timer_init(void)
++{
++ unsigned int cpu_clk;
++ unsigned int bus_clk;
++
++ init_pwm_list();
++ tca_ckc_init();
++ cpu_clk = (unsigned int)tca_ckc_getcpu();
++ bus_clk = (unsigned int)tca_ckc_getbus();
++
++ pTIMER = (volatile PTIMER)tcc_p2v(HwTMR_BASE);
++ pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++
++ printk(" ### CORE CLOCK (%u Hz), BUS CLOCK (%u Hz) ###\n", cpu_clk * 100, bus_clk * 100);
++
++ BITCLR(pTIMER->TC32EN, Hw24);
++ pTIMER->TC32EN = TCC_TIMER_FREQ / HZ;
++ pTIMER->TC32LDV = 0;
++ BITSET(pTIMER->TC32IRQ, Hw19);
++ BITSET(pTIMER->TC32EN, Hw24);
++
++ BITSET(pPIC->SEL0, TCC_ENABLE_BIT(INT_TC1));
++ BITSET(pPIC->IEN0, TCC_ENABLE_BIT(INT_TC1));
++ BITSET(pPIC->INTMSK0, TCC_ENABLE_BIT(INT_TC1));
++ BITSET(pPIC->MODEA0, TCC_ENABLE_BIT(INT_TC1));
++ //BITCLR(pPIC->CLR0, TCC_ENABLE_BIT(INT_TC1));
++
++ setup_irq(INT_TC1, &tcc8900_timer_irq);
++}
++
++struct sys_timer tcc8900_timer = {
++ .init = tcc8900_timer_init,
++ .offset = tcc8900_timer_gettimeoffset,
++};
+diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
+index ab5f7a2..91cf6fd 100644
+--- a/arch/arm/mm/Kconfig
++++ b/arch/arm/mm/Kconfig
+@@ -400,7 +400,8 @@ config CPU_FEROCEON_OLD_ID
+ # ARMv6
+ config CPU_V6
+ bool "Support ARM V6 processor"
+- depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3 || ARCH_MSM || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176
++ depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3 || ARCH_MSM || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || MACH_TCC8900 || MACH_TCC9200
++ default y if ARCH_TCC
+ default y if ARCH_MX3
+ default y if ARCH_MSM
+ select CPU_32v6
+diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
+index 82c4b42..e93766d 100644
+--- a/arch/arm/mm/init.c
++++ b/arch/arm/mm/init.c
+@@ -485,6 +485,9 @@ void __init mem_init(void)
+ datapages = &_end - &__data_start;
+ initpages = &__init_end - &__init_begin;
+
++ printk("_etext:0x%p, _text:0x%p, _end:0x%p, __data_start:0x%p, __init_end:0x%p, __init_begin:0x%p\n", \
++ &_etext, &_text, &_end, &__data_start, &__init_end, &__init_begin);
++
+ #ifndef CONFIG_DISCONTIGMEM
+ max_mapnr = virt_to_page(high_memory) - mem_map;
+ #endif
+diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
+index 7f36c82..af2e310 100644
+--- a/arch/arm/mm/mmu.c
++++ b/arch/arm/mm/mmu.c
+@@ -238,6 +238,10 @@ static struct mem_type mem_types[] = {
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
+ .domain = DOMAIN_KERNEL,
+ },
++ [MT_MEMORY_TCC] = {
++ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_UNCACHED,
++ .domain = DOMAIN_KERNEL,
++ },
+ [MT_ROM] = {
+ .prot_sect = PMD_TYPE_SECT,
+ .domain = DOMAIN_KERNEL,
+@@ -571,6 +575,8 @@ void __init create_mapping(struct map_desc *md)
+ const struct mem_type *type;
+ pgd_t *pgd;
+
++ printk("create_mapping:0x%lx->0x%lx(0x%lx)\n", __pfn_to_phys(md->pfn), md->virtual, md->length);
++
+ if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
+ printk(KERN_WARNING "BUG: not creating mapping for "
+ "0x%08llx at 0x%08lx in user region\n",
+diff --git a/arch/arm/plat-tcc/Makefile b/arch/arm/plat-tcc/Makefile
+new file mode 100644
+index 0000000..e7242fc
+--- /dev/null
++++ b/arch/arm/plat-tcc/Makefile
+@@ -0,0 +1,12 @@
++
++#obj-$(CONFIG_TCA_CKC) += tca_ckc.o
++
++#obj-$(CONFIG_TCA_PM) += tcc_pm.o
++#ifeq ($(CONFIG_PM),y)
++#obj-$(CONFIG_TCA_PM) += tcc_asm.o
++#endif
++#
++obj-$(CONFIG_PM) += tcc_pm.o
++obj-$(CONFIG_DPM) += tcc_dpm.o
++obj-$(CONFIG_CPU_FREQ) += tcc_cpufreq.o
++
+diff --git a/arch/arm/plat-tcc/include/plat/dpm.h b/arch/arm/plat-tcc/include/plat/dpm.h
+new file mode 100644
+index 0000000..f7afb18
+--- /dev/null
++++ b/arch/arm/plat-tcc/include/plat/dpm.h
+@@ -0,0 +1,169 @@
++/*
++ * include/asm-arm/arch-tcc79x/dpm.h
++ *
++ * Author: <linux@telechips.com>
++ * Created: June 10, 2008
++ * Description: DPM for Telechips
++ *
++ * 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
++ *
++ * Copyright (C) 2002-2004, MontaVista Software <source@mvista.com>
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * Initially based on include/asm-arm/arch-omap/omap_dpm.h
++ */
++
++#ifndef __ASM_ARCH_DPM_H__
++#define __ASM_ARCH_DPM_H__
++
++#include <bsp.h>
++
++#include <asm/io.h>
++#include <asm/timex.h>
++
++/*!
++ * machine dependent operating state
++ *
++ * An operating state is a cpu execution state that has implications for power
++ * management. The DPM will select operating points based largely on the
++ * current operating state.
++ *
++ * DPM_STATES is the number of supported operating states. Valid operating
++ * states are from 0 to DPM_STATES-1 but when setting an operating state the
++ * kernel should only specify a state from the set of "base states" and should
++ * do so by name. During the context switch the new operating state is simply
++ * extracted from current->dpm_state.
++ *
++ * task states:
++ *
++ * APIs that reference task states use the range -(DPM_TASK_STATE_LIMIT + 1)
++ * through +DPM_TASK_STATE_LIMIT. This value is added to DPM_TASK_STATE to
++ * obtain the downward or upward adjusted task state value. The
++ * -(DPM_TASK_STATE_LIMIT + 1) value is interpreted specially, and equates to
++ * DPM_NO_STATE.
++ *
++ * Tasks inherit their task operating states across calls to
++ * fork(). DPM_TASK_STATE is the default operating state for all tasks, and is
++ * inherited from init. Tasks can change (or have changed) their tasks states
++ * using the DPM_SET_TASK_STATE variant of the sys_dpm() system call.
++ */
++#define DPM_IDLE_TASK_STATE 0
++#define DPM_IDLE_STATE 1
++#define DPM_SLEEP_STATE 2
++#define DPM_BASE_STATES 3
++
++#define DPM_TASK_STATE_LIMIT 4
++#define DPM_TASK_STATE (DPM_BASE_STATES + DPM_TASK_STATE_LIMIT) /* 7 */
++#define DPM_STATES (DPM_TASK_STATE + DPM_TASK_STATE_LIMIT + 1) /* 11 */
++#define DPM_TASK_STATES (DPM_STATES - DPM_BASE_STATES) /* 5 */
++
++#define DPM_STATE_NAMES \
++{ "idle-task", "idle", "sleep", \
++ "task-4", "task-3", "task-2", "task-1",\
++ "task", \
++ "task+1", "task+2", "task+3", "task+4" \
++}
++
++
++#define DPM_PARAM_NAMES \
++{ "sys_cpu",\
++ "sys_bus",\
++ "fbus_grp",\
++ "fbus_vbus",\
++ "fbus_vcodec",\
++ "fbus_smu",\
++ "fbus_ddi",\
++ "fbus_iobus",\
++ "peri_lcd",\
++ "peri_sata",\
++ "peri_otg",\
++ "peri_ohci",\
++ "peri_userintr",\
++ "peri_tvout",\
++ "peri_hdmi",\
++ "peri_sdhc",\
++}
++
++
++/*!
++ * MD operating point parameters
++ */
++enum {
++ DPM_MD_CORE_CPU, /* 0 */
++ DPM_MD_CORE_BUS, /* 1 */
++ DPM_MD_FBUS_GRP, /* 2 */
++ DPM_MD_FBUS_VBUS, /* 3 */
++ DPM_MD_FBUS_VCODEC, /* 4 */
++ DPM_MD_FBUS_SMU, /* 5 */
++ DPM_MD_FBUS_DDI, /* 6 */
++ DPM_MD_FBUS_IOBUS, /* 7 */
++ DPM_MD_PERI_LCD, /* 8 */
++ DPM_MD_PERI_SATA, /* 9 */
++ DPM_MD_PERI_OTG, /* 10 */
++ DPM_MD_PERI_OHCI, /* 11 */
++ DPM_MD_PERI_USERINTR, /* 12 */
++ DPM_MD_PERI_TVOUT, /* 13 */
++ DPM_MD_PERI_HDMI, /* 14 */
++ DPM_MD_PERI_SDHC, /* 15 */
++ DPM_MD_MAX,
++};
++
++#define DPM_PP_NBR DPM_MD_MAX
++
++
++#ifndef __ASSEMBLER__
++
++#include <linux/types.h>
++#include <linux/proc_fs.h>
++
++#define DPM_MD_STATS
++typedef __u64 dpm_md_count_t;
++typedef __u64 dpm_md_time_t;
++
++
++#define dpm_time() get_cycles()
++#define dpm_time_to_usec(ticks) ({ \
++ unsigned long long quot = (unsigned long long) ticks * 10; \
++ do_div(quot, (unsigned long) (1000*2)); \
++ quot; })
++
++
++/*!
++ * Instances of this structure define valid Innovator operating points for DPM.
++ * Voltages are represented in mV, and frequencies are represented in KHz.
++ */
++/* TODO */
++/* Operating Points */
++struct dpm_md_opt {
++ unsigned int sys_cpu; /* 0 */
++ unsigned int sys_bus; /* 1 */
++ unsigned int fbus_grp; /* 2 */
++ unsigned int fbus_vbus; /* 3 */
++ unsigned int fbus_vcodec; /* 4 */
++ unsigned int fbus_smu; /* 5 */
++ unsigned int fbus_ddi; /* 6 */
++ unsigned int fbus_iobus; /* 7 */
++ unsigned int peri_lcd; /* 8 */
++ unsigned int peri_sata; /* 9 */
++ unsigned int peri_otg; /* 10 */
++ unsigned int peri_ohci; /* 11 */
++ unsigned int peri_userintr; /* 12 */
++ unsigned int peri_tvout; /* 13 */
++ unsigned int peri_hdmi; /* 14 */
++ unsigned int peri_sdhc; /* 15 */
++};
++
++#endif /* __ASSEMBLER__ */
++#endif /* __ASM_ARCH_DPM_H__ */
+diff --git a/arch/arm/plat-tcc/include/plat/pm.h b/arch/arm/plat-tcc/include/plat/pm.h
+new file mode 100644
+index 0000000..2a98f50
+--- /dev/null
++++ b/arch/arm/plat-tcc/include/plat/pm.h
+@@ -0,0 +1,34 @@
++/****************************************************************
++ * $ID: pm.h 六, 29 8月 2009 16:53:28 +0800 root $ *
++ * *
++ * Description: *
++ * *
++ * Maintainer: ·¶Ã;Ô(Meihui Fan) <mhfan@ustc.edu> *
++ * *
++ * CopyRight (c) 2009 HHTech *
++ * www.hhcn.com, www.hhcn.org *
++ * All rights reserved. *
++ * *
++ * This file is free software; *
++ * you are free to modify and/or redistribute it *
++ * under the terms of the GNU General Public Licence (GPL). *
++ * *
++ * Last modified: 六, 29 8月 2009 16:54:15 +0800 by root #
++ ****************************************************************/
++#ifndef PM_H
++#define PM_H
++
++#ifdef CONFIG_PM
++
++extern __init int tcc8902_pm_init(void);
++
++#else
++
++static inline int tcc8902_pm_init(void)
++{
++ return 0;
++}
++#endif
++
++#endif//PM_H
++/********************** End Of File: pm.h **********************/
+diff --git a/arch/arm/plat-tcc/tcc_cpufreq.c b/arch/arm/plat-tcc/tcc_cpufreq.c
+new file mode 100644
+index 0000000..ca5ca78
+--- /dev/null
++++ b/arch/arm/plat-tcc/tcc_cpufreq.c
+@@ -0,0 +1,125 @@
++/****************************************************************
++ * $ID: tcc_cpufreq.c 四, 27 8月 2009 11:39:10 +0800 root $ *
++ * *
++ * Description: CPU frequency scaling for TCC8902 *
++ * *
++ * Maintainer: (Guoqiang Wang) <gqwang@hhcn.com> *
++ * *
++ * CopyRight (c) 2009 HHTech *
++ * www.hhcn.com, www.hhcn.org *
++ * All rights reserved. *
++ * *
++ * This file is free software; *
++ * you are free to modify and/or redistribute it *
++ * under the terms of the GNU General Public Licence (GPL). *
++ * *
++ * Last modified: 一, 26 10月 2009 12:08:06 +0800 by root #
++ ****************************************************************/
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/cpufreq.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <asm/io.h>
++#include <asm/system.h>
++#include <linux/tcc_ioctl.h>
++#include <mach/tcc_pca953x.h>
++
++#define KHZ_T 1000
++
++extern unsigned int tca_ckc_getcpu(void);
++extern int tcc_ckc_change_cpu(unsigned int cpuvalue);
++static struct cpufreq_frequency_table tcc8902_freq_table[] = {
++ {0, 540000},
++ {1, 506250},
++ {2, 405000},
++ {3, 324000},
++ {4, 216000},
++ {5, 108000},
++ {6, 54000},
++ {0, CPUFREQ_TABLE_END},
++};
++
++int tcc8902_verify_speed(struct cpufreq_policy *policy)
++{
++ if (policy->cpu)
++ return -EINVAL;
++ return cpufreq_frequency_table_verify(policy, tcc8902_freq_table);
++}
++
++unsigned int tcc8902_getspeed(unsigned int cpu)
++{
++ unsigned long rate;
++
++ if (cpu)
++ return 0;
++
++ //rate = clk_get_rate(mpu_clk) / KHZ_T;
++ printk("!!!tcc8902_getspeed\n");
++ rate = tca_ckc_getcpu() / 10;
++
++ return rate;
++}
++
++static int tcc8902_target(struct cpufreq_policy *policy,
++ unsigned int target_freq,
++ unsigned int relation)
++{
++ struct cpufreq_freqs freqs;
++ int ret = 0;
++ unsigned long arm_clk;
++ unsigned int index;
++
++ freqs.old = tca_ckc_getcpu() / 10;
++ if (cpufreq_frequency_table_target(policy, tcc8902_freq_table, target_freq, relation, &index))
++ return -EINVAL;
++
++ arm_clk = tcc8902_freq_table[index].frequency;
++ freqs.new = arm_clk;
++ freqs.cpu = 0;
++
++ if(freqs.new == freqs.old)
++ return 0;
++
++ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
++ ret = tcc_ckc_change_cpu(freqs.new * 10);
++ //ret = clk_set_rate(mpu_clk, freqs.new * KHZ_T);
++ if(ret != 0)
++ printk("frequency scaling error\n");
++
++ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
++ return ret;
++}
++
++static int __init tcc8902_cpu_init(struct cpufreq_policy *policy)
++{
++ if (policy->cpu != 0)
++ return -EINVAL;
++ policy->cur = tca_ckc_getcpu() / 10;
++ cpufreq_frequency_table_get_attr(tcc8902_freq_table, policy->cpu);
++ policy->cpuinfo.transition_latency = KHZ_T; //1us
++
++ return cpufreq_frequency_table_cpuinfo(policy, tcc8902_freq_table);
++}
++
++static struct cpufreq_driver tcc8902_driver = {
++ .flags = CPUFREQ_STICKY,
++ .verify = tcc8902_verify_speed,
++ .target = tcc8902_target,
++ .get = tcc8902_getspeed,
++ .init = tcc8902_cpu_init,
++ .name = "tcc8902",
++ .owner = THIS_MODULE,
++};
++
++static int __init tcc8902_cpufreq_init(void)
++{
++ return cpufreq_register_driver(&tcc8902_driver);
++}
++
++late_initcall(tcc8902_cpufreq_init);
++
++/****************** End Of File: tcc_cpufreq.c ******************/
+diff --git a/arch/arm/plat-tcc/tcc_dpm.c b/arch/arm/plat-tcc/tcc_dpm.c
+new file mode 100644
+index 0000000..2609ced
+--- /dev/null
++++ b/arch/arm/plat-tcc/tcc_dpm.c
+@@ -0,0 +1,896 @@
++/*
++ * arch/arm/plat-tcc/tcc_dpm.c DPM support for Telecips Chips
++ *
++ * Author: <linux@telechips.com>
++ * Created: 10th Jun, 2008
++ * Description: tcc clock control functions.
++ *
++ * 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
++ *
++ * Copyright (C) 2002, 2004 MontaVista Software <source@mvista.com>.
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * Based on code by Matthew Locke, Dmitry Chigirev, and Bishop Brock.
++ */
++
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/kmod.h>
++#include <linux/module.h>
++#include <linux/stat.h>
++#include <linux/string.h>
++#include <linux/device.h>
++#include <linux/pm.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++
++#include <asm/hardirq.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++#include <asm/processor.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/mach-types.h>
++#include <mach/hardware.h>
++#include <mach/system.h>
++#include <asm/mach/time.h>
++
++#include <bsp.h>
++#include <linux/dpm.h>
++#include <plat/dpm.h>
++#include <mach/tcc_ckc_ctrl.h>
++
++#if 0
++#define dbg printk
++#define DEBUG
++#else /* no debug */
++#define dbg(x...) do {} while(0)
++#endif
++
++static int cur_lcd;
++static int cur_sata;
++static int cur_otg;
++static int cur_ohci;
++static int cur_userintr;
++static int cur_tvout;
++static int cur_hdmi;
++static int cur_sdhc;
++
++static void
++set_cpu_clock(unsigned int sys_cpu)
++{
++ struct ckc_ioctl st;
++#ifdef DEBUG
++ int cpu = 0;
++#endif
++
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++ st.in_ckc.cpuvalue = sys_cpu ;
++
++ ckc_set_changecpu(st);
++
++#ifdef DEBUG
++ cpu = ckc_get_cpu(st);
++ dbg("[%s] cpu = %d\n", __func__, cpu);
++#endif
++}
++
++static int
++get_cpu_clock(void)
++{
++#ifdef DEBUG
++ int cpu = 0;
++#endif
++ struct ckc_ioctl st;
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++#ifdef DEBUG
++ cpu = ckc_get_cpu(st);
++ dbg("[%s] cpu = %d \n", __func__, cpu);
++ return cpu;
++#else
++ return ckc_get_cpu(st);
++#endif
++ return 0;
++}
++
++static void
++set_bus_clock(unsigned int sys_bus)
++{
++ struct ckc_ioctl st;
++#ifdef DEBUG
++ int bus = 0;
++#endif
++
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++ st.in_ckc.busvalue = sys_bus ;
++
++ ckc_set_changemem(st);
++#ifdef DEBUG
++ bus = ckc_get_bus(st);
++ dbg("[%s] bus = %d\n", __func__, bus);
++#endif
++}
++
++
++static int
++get_bus_clock(void)
++{
++#ifdef DEBUG
++ int bus = 0;
++#endif
++ struct ckc_ioctl st;
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++#ifdef DEBUG
++ bus = ckc_get_bus(st);
++ dbg("[%s] bus = %d \n", __func__, bus);
++ return bus;
++#else
++ return ckc_get_bus(st);
++#endif
++ return 0;
++}
++
++static void
++set_grp_clock(unsigned int fbus_grp)
++{
++ struct ckc_ioctl st;
++#ifdef DEBUG
++ int grp = 0;
++#endif
++
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++ st.in_ckc.fbusname = CLKCTRL3;
++ st.in_ckc.fbusfreq = fbus_grp;
++
++ ckc_set_changefbus(st);
++#ifdef DEBUG
++ grp = ckc_get_fbus(st);
++ dbg("[%s] grp = %d\n", __func__, grp);
++#endif
++}
++
++
++static int
++get_grp_clock(void)
++{
++#ifdef DEBUG
++ int grp = 0;
++#endif
++ struct ckc_ioctl st;
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++ st.in_ckc.fbusname = CLKCTRL3;
++#ifdef DEBUG
++ grp = ckc_get_fbus(st);
++ dbg("[%s] grp = %d \n", __func__, grp);
++ return grp;
++#else
++ return ckc_get_fbus(st);
++#endif
++ return 0;
++}
++
++static void
++set_vbus_clock(unsigned int fbus_vbus)
++{
++ struct ckc_ioctl st;
++#ifdef DEBUG
++ int vbus = 0;
++#endif
++
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++ st.in_ckc.fbusname = CLKCTRL5;
++ st.in_ckc.fbusfreq = fbus_vbus;
++
++ ckc_set_changefbus(st);
++#ifdef DEBUG
++ vbus = ckc_get_fbus(st);
++ dbg("[%s] vbus = %d\n", __func__, vbus);
++#endif
++}
++
++
++static int
++get_vbus_clock(void)
++{
++#ifdef DEBUG
++ int vbus = 0;
++#endif
++ struct ckc_ioctl st;
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++ st.in_ckc.fbusname = CLKCTRL5;
++#ifdef DEBUG
++ vbus = ckc_get_fbus(st);
++ dbg("[%s] vbus = %d \n", __func__, vbus);
++ return vbus;
++#else
++ return ckc_get_fbus(st);
++#endif
++ return 0;
++}
++
++static void
++set_vcodec_clock(unsigned int fbus_vcodec)
++{
++ struct ckc_ioctl st;
++#ifdef DEBUG
++ int vcodec = 0;
++#endif
++
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++ st.in_ckc.fbusname = CLKCTRL6;
++ st.in_ckc.fbusfreq = fbus_vcodec;
++
++ ckc_set_changefbus(st);
++#ifdef DEBUG
++ vcodec = ckc_get_fbus(st);
++ dbg("[%s] vcodec = %d\n", __func__, vcodec);
++#endif
++}
++
++
++static int
++get_vcodec_clock(void)
++{
++#ifdef DEBUG
++ int vcodec = 0;
++#endif
++ struct ckc_ioctl st;
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++ st.in_ckc.fbusname = CLKCTRL6;
++#ifdef DEBUG
++ vcodec = ckc_get_fbus(st);
++ dbg("[%s] vcodec = %d \n", __func__, vcodec);
++ return vcodec;
++#else
++ return ckc_get_fbus(st);
++#endif
++ return 0;
++}
++
++
++static void
++set_smu_clock(unsigned int fbus_smu)
++{
++ struct ckc_ioctl st;
++#ifdef DEBUG
++ int smu = 0;
++#endif
++
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++ st.in_ckc.fbusname = CLKCTRL1;
++ st.in_ckc.fbusfreq = fbus_smu;
++
++ ckc_set_changefbus(st);
++#ifdef DEBUG
++ smu = ckc_get_fbus(st);
++ dbg("[%s] smu = %d\n", __func__, smu);
++#endif
++}
++
++
++static int
++get_smu_clock(void)
++{
++#ifdef DEBUG
++ int smu = 0;
++#endif
++ struct ckc_ioctl st;
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++ st.in_ckc.fbusname = CLKCTRL1;
++#ifdef DEBUG
++ smu = ckc_get_fbus(st);
++ dbg("[%s] smu = %d \n", __func__, smu);
++ return smu;
++#else
++ return ckc_get_fbus(st);
++#endif
++ return 0;
++}
++
++
++static void
++set_ddi_clock(unsigned int fbus_ddi)
++{
++ struct ckc_ioctl st;
++#ifdef DEBUG
++ int ddi = 0;
++#endif
++
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++ st.in_ckc.fbusname = CLKCTRL7;
++ st.in_ckc.fbusfreq = fbus_ddi;
++
++ ckc_set_changefbus(st);
++#ifdef DEBUG
++ ddi = ckc_get_fbus(st);
++ dbg("[%s] ddi = %d\n", __func__, ddi);
++#endif
++}
++
++
++static int
++get_ddi_clock(void)
++{
++#ifdef DEBUG
++ int ddi = 0;
++#endif
++ struct ckc_ioctl st;
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++ st.in_ckc.fbusname = CLKCTRL7;
++#ifdef DEBUG
++ ddi = ckc_get_fbus(st);
++ dbg("[%s] ddi = %d \n", __func__, ddi);
++ return ddi;
++#else
++ return ckc_get_fbus(st);
++#endif
++ return 0;
++}
++
++
++static void
++set_iobus_clock(unsigned int fbus_iobus)
++{
++ struct ckc_ioctl st;
++#ifdef DEBUG
++ int iobus = 0;
++#endif
++
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++ st.in_ckc.fbusname = CLKCTRL4;
++ st.in_ckc.fbusfreq = fbus_iobus;
++
++ ckc_set_changefbus(st);
++#ifdef DEBUG
++ iobus = ckc_get_fbus(st);
++ dbg("[%s] iobus = %d\n", __func__, iobus);
++#endif
++}
++
++
++static int
++get_iobus_clock(void)
++{
++#ifdef DEBUG
++ int iobus = 0;
++#endif
++ struct ckc_ioctl st;
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++ st.in_ckc.fbusname = CLKCTRL4;
++#ifdef DEBUG
++ iobus = ckc_get_fbus(st);
++ dbg("[%s] iobus = %d \n", __func__, iobus);
++ return iobus;
++#else
++ return ckc_get_fbus(st);
++#endif
++ return 0;
++}
++
++
++static void
++set_lcd_clock(unsigned int peri_lcd)
++{
++ stpwrinfo out;
++
++ memset(&out, 0, sizeof(stpwrinfo));
++ if(peri_lcd == ENABLE) {
++ dbg("[%s] LCD ON\n",__func__);
++ callback_pwm_node(DEVICE_LCD , PWR_CMD_ON, &(out));
++ } else if(peri_lcd == DISABLE){
++ dbg("[%s] LCD OFF\n", __func__);
++ callback_pwm_node(DEVICE_LCD , PWR_CMD_OFF, &(out));
++ }
++ cur_lcd = peri_lcd;
++}
++
++static int
++get_lcd_clock(void)
++{
++#ifdef DEBUG
++ if(cur_lcd == ENABLE)
++ dbg("[%s] LCD ON\n", __func__);
++ else if(cur_lcd == DISABLE)
++ dbg("[%s] LCD OFF\n", __func__);
++#endif
++ return cur_lcd;
++}
++
++static void
++set_sata_clock(unsigned int peri_sata)
++{
++ stpwrinfo out;
++
++ memset(&out, 0, sizeof(stpwrinfo));
++ if(peri_sata== ENABLE) {
++ dbg("[%s] SATA ON\n", __func__);
++ callback_pwm_node(DEVICE_SATA, PWR_CMD_ON, &(out));
++ } else if(peri_sata== DISABLE){
++ dbg("[%s] SATA OFF\n", __func__);
++ callback_pwm_node(DEVICE_SATA, PWR_CMD_OFF, &(out));
++ }
++ cur_sata = peri_sata;
++}
++
++static int
++get_sata_clock(void)
++{
++#ifdef DEBUG
++ if(cur_sata == ENABLE)
++ dbg("[%s] SATA ON\n", __func__);
++ else if(cur_sata == DISABLE)
++ dbg("[%s] SATA OFF\n", __func__);
++#endif
++ return cur_sata;
++}
++
++
++
++static void
++set_otg_clock(unsigned int peri_otg)
++{
++ stpwrinfo out;
++
++ memset(&out, 0, sizeof(stpwrinfo));
++ if(peri_otg== ENABLE) {
++ dbg("[%s] OTG ON\n", __func__);
++ callback_pwm_node(DEVICE_OTG, PWR_CMD_ON, &(out));
++ } else if(peri_otg== DISABLE){
++ dbg("[%s] OTG OFF\n", __func__);
++ callback_pwm_node(DEVICE_OTG, PWR_CMD_OFF, &(out));
++ }
++ cur_otg = peri_otg;
++}
++
++static int
++get_otg_clock(void)
++{
++#ifdef DEBUG
++ if(cur_otg == ENABLE)
++ dbg("[%s] OTG ON\n", __func__);
++ else if(cur_otg == DISABLE)
++ dbg("[%s] OTG OFF\n", __func__);
++#endif
++ return cur_otg;
++}
++
++
++static void
++set_ohci_clock(unsigned int peri_ohci)
++{
++ stpwrinfo out;
++
++ memset(&out, 0, sizeof(stpwrinfo));
++ if(peri_ohci== ENABLE) {
++ dbg("[%s] OHCI ON\n", __func__);
++ callback_pwm_node(DEVICE_OHCI, PWR_CMD_ON, &(out));
++ } else if(peri_ohci== DISABLE){
++ dbg("[%s] OHCI OFF\n", __func__);
++ callback_pwm_node(DEVICE_OHCI, PWR_CMD_OFF, &(out));
++ }
++ cur_ohci = peri_ohci;
++}
++
++static int
++get_ohci_clock(void)
++{
++#ifdef DEBUG
++ if(cur_ohci == ENABLE)
++ dbg("[%s] OHCI ON\n", __func__);
++ else if(cur_ohci == DISABLE)
++ dbg("[%s] OHCI OFF\n", __func__);
++#endif
++ return cur_ohci;
++}
++
++
++static void
++set_userintr_clock(unsigned int peri_userintr)
++{
++ stpwrinfo out;
++
++ memset(&out, 0, sizeof(stpwrinfo));
++ if(peri_userintr== ENABLE) {
++ dbg("[%s] USERINTR ON\n", __func__);
++ callback_pwm_node(DEVICE_USERINTR, PWR_CMD_ON, &(out));
++ } else if(peri_userintr== DISABLE){
++ dbg("[%s] USERINTR OFF\n", __func__);
++ callback_pwm_node(DEVICE_USERINTR, PWR_CMD_OFF, &(out));
++ }
++ cur_userintr = peri_userintr;
++}
++
++static int
++get_userintr_clock(void)
++{
++#ifdef DEBUG
++ if(cur_userintr == ENABLE)
++ dbg("[%s] USERINTR ON\n", __func__);
++ else if(cur_userintr == DISABLE)
++ dbg("[%s] USERINTR OFF\n", __func__);
++#endif
++ return cur_userintr;
++}
++
++
++static void
++set_tvout_clock(unsigned int peri_tvout)
++{
++ stpwrinfo out;
++
++ memset(&out, 0, sizeof(stpwrinfo));
++ if(peri_tvout == ENABLE) {
++ dbg("[%s] TVOUT ON\n",__func__);
++ callback_pwm_node(DEVICE_TVOUT , PWR_CMD_ON, &(out));
++ } else if(peri_tvout == DISABLE){
++ dbg("[%s] TVOUT OFF\n", __func__);
++ callback_pwm_node(DEVICE_TVOUT , PWR_CMD_OFF, &(out));
++ }
++ cur_tvout = peri_tvout;
++}
++
++static int
++get_tvout_clock(void)
++{
++#ifdef DEBUG
++ if(cur_tvout == ENABLE)
++ dbg("[%s] TVOUT ON\n", __func__);
++ else if(cur_tvout == DISABLE)
++ dbg("[%s] TVOUT OFF\n", __func__);
++#endif
++ return cur_tvout;
++}
++
++static void
++set_hdmi_clock(unsigned int peri_hdmi)
++{
++ stpwrinfo out;
++
++ memset(&out, 0, sizeof(stpwrinfo));
++ if(peri_hdmi == ENABLE) {
++ dbg("[%s] HDMI ON\n",__func__);
++ callback_pwm_node(DEVICE_HDMI , PWR_CMD_ON, &(out));
++ } else if(peri_hdmi == DISABLE){
++ dbg("[%s] HDMI OFF\n", __func__);
++ callback_pwm_node(DEVICE_HDMI , PWR_CMD_OFF, &(out));
++ }
++ cur_hdmi = peri_hdmi;
++}
++
++static int
++get_hdmi_clock(void)
++{
++#ifdef DEBUG
++ if(cur_hdmi == ENABLE)
++ dbg("[%s] HDMI ON\n", __func__);
++ else if(cur_hdmi == DISABLE)
++ dbg("[%s] HDMI OFF\n", __func__);
++#endif
++ return cur_hdmi;
++}
++
++
++static void
++set_sdhc_clock(unsigned int peri_sdhc)
++{
++ stpwrinfo out;
++
++ memset(&out, 0, sizeof(stpwrinfo));
++ if(peri_sdhc == ENABLE) {
++ dbg("[%s] SDHC ON\n",__func__);
++ callback_pwm_node(DEVICE_SDHC , PWR_CMD_ON, &(out));
++ } else if(peri_sdhc == DISABLE){
++ dbg("[%s] SDHC OFF\n", __func__);
++ callback_pwm_node(DEVICE_SDHC , PWR_CMD_OFF, &(out));
++ }
++ cur_sdhc = peri_sdhc;
++}
++
++static int
++get_sdhc_clock(void)
++{
++#ifdef DEBUG
++ if(cur_sdhc == ENABLE)
++ dbg("[%s] SDHC ON\n", __func__);
++ else if(cur_sdhc == DISABLE)
++ dbg("[%s] SDHC OFF\n", __func__);
++#endif
++ return cur_sdhc;
++}
++
++
++
++int
++dpm_tcc_init_opt(struct dpm_opt *opt)
++{
++ int sys_cpu = opt->pp[DPM_MD_CORE_CPU];
++ int sys_bus = opt->pp[DPM_MD_CORE_BUS];
++ int fbus_grp = opt->pp[DPM_MD_FBUS_GRP];
++ int fbus_vbus = opt->pp[DPM_MD_FBUS_VBUS];
++ int fbus_vcodec = opt->pp[DPM_MD_FBUS_VCODEC];
++ int fbus_smu = opt->pp[DPM_MD_FBUS_SMU];
++ int fbus_ddi = opt->pp[DPM_MD_FBUS_DDI];
++ int fbus_iobus = opt->pp[DPM_MD_FBUS_IOBUS];
++ int peri_lcd = opt->pp[DPM_MD_PERI_LCD];
++ int peri_sata = opt->pp[DPM_MD_PERI_SATA];
++ int peri_otg = opt->pp[DPM_MD_PERI_OTG];
++ int peri_ohci = opt->pp[DPM_MD_PERI_OHCI];
++ int peri_userintr = opt->pp[DPM_MD_PERI_USERINTR];
++ int peri_tvout = opt->pp[DPM_MD_PERI_TVOUT];
++ int peri_hdmi = opt->pp[DPM_MD_PERI_HDMI];
++ int peri_sdhc = opt->pp[DPM_MD_PERI_SDHC];
++
++ struct dpm_md_opt *md_opt = &opt->md_opt;
++
++ md_opt->sys_cpu = sys_cpu;
++ md_opt->sys_bus = sys_bus;
++ md_opt->fbus_grp = fbus_grp;
++ md_opt->fbus_vbus = fbus_vbus;
++ md_opt->fbus_vcodec = fbus_vcodec;
++ md_opt->fbus_smu = fbus_smu;
++ md_opt->fbus_ddi = fbus_ddi;
++ md_opt->fbus_iobus = fbus_iobus;
++ md_opt->peri_lcd = peri_lcd;
++ md_opt->peri_sata = peri_sata;
++ md_opt->peri_otg = peri_otg;
++ md_opt->peri_ohci = peri_ohci;
++ md_opt->peri_userintr = peri_userintr;
++ md_opt->peri_tvout = peri_tvout;
++ md_opt->peri_hdmi = peri_hdmi;
++ md_opt->peri_sdhc = peri_sdhc;
++
++ return 0;
++}
++
++int
++dpm_tcc_set_opt(struct dpm_opt *cur, struct dpm_opt *new)
++{
++ struct dpm_md_opt *md_cur, *md_new;
++ md_cur = &cur->md_opt;
++ md_new = &new->md_opt;
++
++ // system core cpu clock
++ dbg("[%d]: md_cur->sys_cpu = %d",__LINE__, md_cur->sys_cpu);
++ dbg("[%d]: md_new->sys_cpu = %d\n",__LINE__, md_new->sys_cpu);
++ if(md_cur->sys_cpu != md_new->sys_cpu)
++ {
++ set_cpu_clock(md_new->sys_cpu);
++ }
++
++ // system bus clock
++ dbg("[%d]: md_cur->sys_bus = %d",__LINE__, md_cur->sys_bus);
++ dbg("[%d]: md_new->sys_bus = %d\n",__LINE__, md_new->sys_bus);
++ if(md_cur->sys_bus != md_new->sys_bus)
++ {
++ set_bus_clock(md_new->sys_bus);
++ }
++
++ // system fbus grp clock
++ dbg("[%d]: md_cur->fbus_grp = %d",__LINE__, md_cur->fbus_grp);
++ dbg("[%d]: md_new->fbus_grp = %d\n",__LINE__, md_new->fbus_grp);
++ if(md_cur->fbus_grp != md_new->fbus_grp)
++ {
++ set_grp_clock(md_new->fbus_grp);
++ }
++
++ // system fbus vbus clock
++ dbg("[%d]: md_cur->fbus_vbus = %d",__LINE__, md_cur->fbus_vbus);
++ dbg("[%d]: md_new->fbus_vbus = %d\n",__LINE__, md_new->fbus_vbus);
++ if(md_cur->fbus_vbus != md_new->fbus_vbus)
++ {
++ set_vbus_clock(md_new->fbus_vbus);
++ }
++
++ // system fbus vcodec clock
++ dbg("[%d]: md_cur->fbus_vcodec = %d",__LINE__, md_cur->fbus_vcodec);
++ dbg("[%d]: md_new->fbus_vcodec = %d\n",__LINE__, md_new->fbus_vcodec);
++ if(md_cur->fbus_vcodec != md_new->fbus_vcodec)
++ {
++ set_vcodec_clock(md_new->fbus_vcodec);
++ }
++
++ // system fbus smu clock
++ dbg("[%d]: md_cur->fbus_smu = %d",__LINE__, md_cur->fbus_smu);
++ dbg("[%d]: md_new->fbus_smu = %d\n",__LINE__, md_new->fbus_smu);
++ if(md_cur->fbus_smu != md_new->fbus_smu)
++ {
++ set_smu_clock(md_new->fbus_smu);
++ }
++
++
++ // system fbus ddi clock
++ dbg("[%d]: md_cur->fbus_ddi = %d",__LINE__, md_cur->fbus_ddi);
++ dbg("[%d]: md_new->fbus_ddi = %d\n",__LINE__, md_new->fbus_ddi);
++ if(md_cur->fbus_ddi != md_new->fbus_ddi)
++ {
++ set_ddi_clock(md_new->fbus_ddi);
++ }
++
++ // system fbus iobus clock
++ dbg("[%d]: md_cur->fbus_iobus = %d",__LINE__, md_cur->fbus_iobus);
++ dbg("[%d]: md_new->fbus_iobus = %d\n",__LINE__, md_new->fbus_iobus);
++ if(md_cur->fbus_iobus != md_new->fbus_iobus)
++ {
++ set_iobus_clock(md_new->fbus_iobus);
++ }
++
++
++ // peri lcd clock
++ dbg("[%d]: md_cur->peri_lcd = %d",__LINE__, md_cur->peri_lcd);
++ dbg("[%d]: md_new->peri_lcd = %d\n",__LINE__, md_new->peri_lcd);
++ if(md_cur->peri_lcd != md_new->peri_lcd)
++ {
++ set_lcd_clock(md_new->peri_lcd);
++ }
++
++ // peri sata clock
++ dbg("[%d]: md_cur->peri_sata = %d",__LINE__, md_cur->peri_sata);
++ dbg("[%d]: md_new->peri_sata = %d\n",__LINE__, md_new->peri_sata);
++ if(md_cur->peri_sata != md_new->peri_sata)
++ {
++ set_sata_clock(md_new->peri_sata);
++ }
++
++ // peri otg clock
++ dbg("[%d]: md_cur->peri_otg = %d",__LINE__, md_cur->peri_otg);
++ dbg("[%d]: md_new->peri_otg = %d\n",__LINE__, md_new->peri_otg);
++ if(md_cur->peri_otg != md_new->peri_otg)
++ {
++ set_otg_clock(md_new->peri_otg);
++ }
++
++ // peri ohci clock
++ dbg("[%d]: md_cur->peri_ohci = %d",__LINE__, md_cur->peri_ohci);
++ dbg("[%d]: md_new->peri_ohci = %d\n",__LINE__, md_new->peri_ohci);
++ if(md_cur->peri_ohci != md_new->peri_ohci)
++ {
++ set_ohci_clock(md_new->peri_ohci);
++ }
++
++ // peri userintr clock
++ dbg("[%d]: md_cur->peri_userintr = %d",__LINE__, md_cur->peri_userintr);
++ dbg("[%d]: md_new->peri_userintr = %d\n",__LINE__, md_new->peri_userintr);
++ if(md_cur->peri_userintr != md_new->peri_userintr)
++ {
++ set_userintr_clock(md_new->peri_userintr);
++ }
++
++ // peri tvout clock
++ dbg("[%d]: md_cur->peri_tvout = %d",__LINE__, md_cur->peri_tvout);
++ dbg("[%d]: md_new->peri_tvout = %d\n",__LINE__, md_new->peri_tvout);
++ if(md_cur->peri_tvout != md_new->peri_tvout)
++ {
++ set_tvout_clock(md_new->peri_tvout);
++ }
++
++
++ // peri hdmi clock
++ dbg("[%d]: md_cur->peri_hdmi = %d",__LINE__, md_cur->peri_hdmi);
++ dbg("[%d]: md_new->peri_hdmi = %d\n",__LINE__, md_new->peri_hdmi);
++ if(md_cur->peri_hdmi != md_new->peri_hdmi)
++ {
++ set_hdmi_clock(md_new->peri_hdmi);
++ }
++
++
++ // peri sdhc clock
++ dbg("[%d]: md_cur->peri_sdhc = %d",__LINE__, md_cur->peri_sdhc);
++ dbg("[%d]: md_new->peri_sdhc = %d\n",__LINE__, md_new->peri_sdhc);
++ if(md_cur->peri_sdhc != md_new->peri_sdhc)
++ {
++ set_sdhc_clock(md_new->peri_sdhc);
++ }
++
++
++ return 0;
++}
++
++/* Fully determine the current machine-dependent operating point, and fill in a
++ structure presented by the caller. This should only be called when the
++ dpm_sem is held. This call can return an error if the system is currently at
++ an operating point that could not be constructed by dpm_md_init_opt(). */
++
++int
++dpm_tcc_get_opt(struct dpm_opt *opt)
++{
++ struct dpm_md_opt *md_opt = &opt->md_opt;
++
++ md_opt->sys_cpu = get_cpu_clock();
++ md_opt->sys_bus = get_bus_clock();
++ md_opt->fbus_grp = get_grp_clock();
++ md_opt->fbus_vbus = get_vbus_clock();
++ md_opt->fbus_vcodec = get_vcodec_clock();
++ md_opt->fbus_smu = get_smu_clock();
++ md_opt->fbus_ddi = get_ddi_clock();
++ md_opt->fbus_iobus = get_iobus_clock();
++ md_opt->peri_lcd = get_lcd_clock();
++ md_opt->peri_sata= get_sata_clock();
++ md_opt->peri_otg= get_otg_clock();
++ md_opt->peri_ohci= get_ohci_clock();
++ md_opt->peri_userintr= get_userintr_clock();
++ md_opt->peri_tvout = get_tvout_clock();
++ md_opt->peri_hdmi = get_hdmi_clock();
++ md_opt->peri_sdhc = get_sdhc_clock();
++
++ return 0;
++}
++
++
++/****************************************************************************
++ * DPM Idle Handler
++ ****************************************************************************/
++
++static void (*orig_idle)(void);
++
++void dpm_tcc_idle(void)
++{
++ extern void default_idle(void);
++
++ if (orig_idle)
++ orig_idle();
++ else {
++ local_irq_disable();
++ if (!need_resched()) {
++ timer_dyn_reprogram();
++ arch_idle();
++ }
++ local_irq_enable();
++ }
++}
++
++/****************************************************************************
++ * Initialization/Exit
++ ****************************************************************************/
++
++extern void (*pm_idle)(void);
++
++static void
++dpm_tcc_startup(void)
++{
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++ /*
++ if (pm_idle != dpm_idle) {
++ orig_idle = pm_idle;
++ pm_idle = dpm_idle;
++ }
++ */
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++}
++
++static void
++dpm_tcc_cleanup(void)
++{
++ dbg("%s:%d\n", __func__, __LINE__);
++ pm_idle = orig_idle;
++}
++
++int __init
++dpm_tcc_init(void)
++{
++ printk("Telechips Dynamic Power Management.\n");
++ dpm_md.init_opt = dpm_tcc_init_opt;
++ dpm_md.set_opt = dpm_tcc_set_opt;
++ dpm_md.get_opt = dpm_tcc_get_opt;
++ dpm_md.check_constraint = dpm_default_check_constraint;
++ dpm_md.idle = dpm_tcc_idle;
++ dpm_md.startup = dpm_tcc_startup;
++ dpm_md.cleanup = dpm_tcc_cleanup;
++
++ return 0;
++}
++
++__initcall(dpm_tcc_init);
++
+diff --git a/arch/arm/plat-tcc/tcc_pm.c b/arch/arm/plat-tcc/tcc_pm.c
+new file mode 100644
+index 0000000..2a242f3
+--- /dev/null
++++ b/arch/arm/plat-tcc/tcc_pm.c
+@@ -0,0 +1,96 @@
++/****************************************************************
++ * $ID: tcc_pm.c 六, 29 8月 2009 16:38:08 +0800 root $ *
++ * *
++ * Description: TCC8902 Power Manager (Suspend-To-RAM) support *
++ * *
++ * Maintainer: Guoqiang Wang <gqwang@hhcn.com> *
++ * *
++ * CopyRight (c) 2009 HHTech *
++ * www.hhcn.com, www.hhcn.org *
++ * All rights reserved. *
++ * *
++ * This file is free software; *
++ * you are free to modify and/or redistribute it *
++ * under the terms of the GNU General Public Licence (GPL). *
++ * *
++ * Last modified: 一, 07 12月 2009 16:05:41 +0800 by duanius #
++ ****************************************************************/
++#include <linux/init.h>
++#include <linux/suspend.h>
++#include <linux/errno.h>
++#include <linux/time.h>
++#include <linux/jiffies.h>
++#include <linux/interrupt.h>
++#include <linux/crc32.h>
++#include <linux/ioport.h>
++#include <linux/delay.h>
++#include <linux/serial_core.h>
++#include <linux/platform_device.h>
++#include <asm/cacheflush.h>
++#include <asm/io.h>
++#include <asm/mach/time.h>
++#include <asm/mach/irq.h>
++#include <linux/rtc.h>
++
++extern void selfrefresh_test(void);
++
++/* tcc8902_pm_enter
++ *
++ * central control for sleep/resume process
++*/
++extern void enter_sleep_mode(void);
++static int tcc8902_pm_enter(suspend_state_t state)
++{
++ unsigned long regs_save[16];
++ unsigned int tmp;
++
++ /* ensure the debug is initialised (if enabled) */
++ if (state != PM_SUSPEND_MEM) {
++ printk(KERN_ERR "error: only PM_SUSPEND_MEM supported\n");
++ return -EINVAL;
++ }
++
++ printk("selfrefresh_test\n");
++ enter_sleep_mode();
++
++ return 0;
++}
++
++/*
++ * Called after processes are frozen, but before we shut down devices.
++ */
++static int tcc8902_pm_prepare(suspend_state_t state)
++{
++ return 0;
++}
++
++/*
++ * Called after devices are re-setup, but before processes are thawed.
++ */
++static int tcc8902_pm_finish(suspend_state_t state)
++{
++ return 0;
++}
++
++static struct platform_suspend_ops tcc8902_pm_ops = {
++ .prepare = tcc8902_pm_prepare,
++ .enter = tcc8902_pm_enter,
++ .finish = tcc8902_pm_finish,
++ .valid = suspend_valid_only_mem,
++};
++
++/* tcc8902_pm_init
++ *
++ * Attach the power management functions. This should be called
++ * from the board specific initialisation if the board supports
++ * it.
++*/
++
++int __init tcc8902_pm_init(void)
++{
++ printk("TCC8902 Power Management, (c) 2009 HHCN \n");
++
++ suspend_set_ops(&tcc8902_pm_ops);
++ return 0;
++}
++/******************** End Of File: tcc_pm.c ********************/
+diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
+index 43aa202..df01e83 100644
+--- a/arch/arm/tools/mach-types
++++ b/arch/arm/tools/mach-types
+@@ -1899,3 +1899,7 @@ rut100 MACH_RUT100 RUT100 1908
+ asusp535 MACH_ASUSP535 ASUSP535 1909
+ htcraphael MACH_HTCRAPHAEL HTCRAPHAEL 1910
+ sygdg1 MACH_SYGDG1 SYGDG1 1911
++
++tcc8900 MACH_TCC8900 TCC8900 4000
++tcc9100 MACH_TCC9100 TCC9100 4001
++tcc9200 MACH_TCC9200 TCC9200 4002
+diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h
+index c85860b..8de86e4 100644
+--- a/arch/arm/vfp/vfp.h
++++ b/arch/arm/vfp/vfp.h
+@@ -377,6 +377,6 @@ struct op {
+ u32 flags;
+ };
+
+-#ifdef CONFIG_SMP
++#if defined(CONFIG_SMP) || defined(CONFIG_PM)
+ extern void vfp_save_state(void *location, u32 fpexc);
+ #endif
+diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
+index a62dcf7..c92a08b 100644
+--- a/arch/arm/vfp/vfphw.S
++++ b/arch/arm/vfp/vfphw.S
+@@ -101,9 +101,12 @@ ENTRY(vfp_support_entry)
+ VFPFSTMIA r4, r5 @ save the working registers
+ VFPFMRX r5, FPSCR @ current status
+ tst r1, #FPEXC_EX @ is there additional state to save?
+- VFPFMRX r6, FPINST, NE @ FPINST (only if FPEXC.EX is set)
+- tstne r1, #FPEXC_FP2V @ is there an FPINST2 to read?
+- VFPFMRX r8, FPINST2, NE @ FPINST2 if needed (and present)
++ beq 1f
++ VFPFMRX r6, FPINST @ FPINST (only if FPEXC.EX is set)
++ tst r1, #FPEXC_FP2V @ is there an FPINST2 to read?
++ beq 1f
++ VFPFMRX r8, FPINST2 @ FPINST2 if needed (and present)
++1:
+ stmia r4, {r1, r5, r6, r8} @ save FPEXC, FPSCR, FPINST, FPINST2
+ @ and point r4 at the word at the
+ @ start of the register dump
+@@ -117,9 +120,12 @@ no_old_VFP_process:
+ @ FPEXC is in a safe state
+ ldmia r10, {r1, r5, r6, r8} @ load FPEXC, FPSCR, FPINST, FPINST2
+ tst r1, #FPEXC_EX @ is there additional state to restore?
+- VFPFMXR FPINST, r6, NE @ restore FPINST (only if FPEXC.EX is set)
+- tstne r1, #FPEXC_FP2V @ is there an FPINST2 to write?
+- VFPFMXR FPINST2, r8, NE @ FPINST2 if needed (and present)
++ beq 1f
++ VFPFMXR FPINST, r6 @ restore FPINST (only if FPEXC.EX is set)
++ tst r1, #FPEXC_FP2V @ is there an FPINST2 to write?
++ beq 1f
++ VFPFMXR FPINST2, r8 @ FPINST2 if needed (and present)
++1:
+ VFPFMXR FPSCR, r5 @ restore status
+
+ check_for_exception:
+@@ -166,7 +172,7 @@ process_exception:
+ @ retry the faulted instruction
+ ENDPROC(vfp_support_entry)
+
+-#ifdef CONFIG_SMP
++#if defined(CONFIG_SMP) || defined(CONFIG_PM)
+ ENTRY(vfp_save_state)
+ @ Save the current VFP state
+ @ r0 - save location
+@@ -175,9 +181,12 @@ ENTRY(vfp_save_state)
+ VFPFSTMIA r0, r2 @ save the working registers
+ VFPFMRX r2, FPSCR @ current status
+ tst r1, #FPEXC_EX @ is there additional state to save?
+- VFPFMRX r3, FPINST, NE @ FPINST (only if FPEXC.EX is set)
+- tstne r1, #FPEXC_FP2V @ is there an FPINST2 to read?
+- VFPFMRX r12, FPINST2, NE @ FPINST2 if needed (and present)
++ beq 1f
++ VFPFMRX r3, FPINST @ FPINST (only if FPEXC.EX is set)
++ tst r1, #FPEXC_FP2V @ is there an FPINST2 to read?
++ beq 1f
++ VFPFMRX r12, FPINST2 @ FPINST2 if needed (and present)
++1:
+ stmia r0, {r1, r2, r3, r12} @ save FPEXC, FPSCR, FPINST, FPINST2
+ mov pc, lr
+ ENDPROC(vfp_save_state)
+diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
+index c0d2c9b..7a818a0 100644
+--- a/arch/arm/vfp/vfpmodule.c
++++ b/arch/arm/vfp/vfpmodule.c
+@@ -322,6 +322,61 @@ static void vfp_enable(void *unused)
+ set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11));
+ }
+
++#ifdef CONFIG_PM
++#include <linux/sysdev.h>
++
++int vfp_pm_suspend(struct sys_device *dev, pm_message_t state)
++{
++ struct thread_info *ti = current_thread_info();
++ u32 fpexc = fmrx(FPEXC);
++
++ /* if vfp is on, then save state for resumption */
++ if (fpexc & FPEXC_EN) {
++ printk(KERN_DEBUG "%s: saving vfp state\n", __func__);
++ vfp_save_state(&ti->vfpstate, fpexc);
++
++ /* disable, just in case */
++ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
++ }
++
++ /* clear any information we had about last context state */
++ memset(last_VFP_context, 0, sizeof(last_VFP_context));
++
++ return 0;
++}
++
++int vfp_pm_resume(struct sys_device *dev)
++{
++ /* ensure we have access to the vfp */
++ vfp_enable(NULL);
++
++ /* and disable it to ensure the next usage restores the state */
++ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
++
++ return 0;
++}
++
++static struct sysdev_class vfp_pm_sysclass = {
++ .name = "vfp",
++ .suspend = vfp_pm_suspend,
++ .resume = vfp_pm_resume,
++};
++
++static struct sys_device vfp_pm_sysdev = {
++ .cls = &vfp_pm_sysclass,
++};
++
++static void vfp_pm_init(void)
++{
++ sysdev_class_register(&vfp_pm_sysclass);
++ sysdev_register(&vfp_pm_sysdev);
++}
++
++
++#else
++static inline void vfp_pm_init(void) { }
++#endif /* CONFIG_PM */
++
+ #include <linux/smp.h>
+
+ /*
+@@ -365,6 +420,7 @@ static int __init vfp_init(void)
+ vfp_vector = vfp_support_entry;
+
+ thread_register_notifier(&vfp_notifier_block);
++ vfp_pm_init();
+
+ /*
+ * We detected VFP, and the support code is
+diff --git a/drivers/Kconfig b/drivers/Kconfig
+index 2f557f5..b1eae9d 100644
+--- a/drivers/Kconfig
++++ b/drivers/Kconfig
+@@ -107,4 +107,6 @@ source "drivers/uio/Kconfig"
+ source "drivers/xen/Kconfig"
+
+ source "drivers/staging/Kconfig"
++
++source "drivers/dpm/Kconfig"
+ endmenu
+diff --git a/drivers/Makefile b/drivers/Makefile
+index fceb71a..c560b88 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -6,6 +6,8 @@
+ #
+
+ obj-y += gpio/
++obj-y += i2c/
++obj-$(CONFIG_SPI) += spi/
+ obj-$(CONFIG_PCI) += pci/
+ obj-$(CONFIG_PARISC) += parisc/
+ obj-$(CONFIG_RAPIDIO) += rapidio/
+@@ -34,6 +36,7 @@ obj-$(CONFIG_FB_INTEL) += video/intelfb/
+ obj-y += serial/
+ obj-$(CONFIG_PARPORT) += parport/
+ obj-y += base/ block/ misc/ mfd/ net/ media/
++obj-$(CONFIG_DPM) += dpm/
+ obj-$(CONFIG_NUBUS) += nubus/
+ obj-$(CONFIG_ATM) += atm/
+ obj-y += macintosh/
+@@ -47,7 +50,6 @@ obj-$(CONFIG_UIO) += uio/
+ obj-y += cdrom/
+ obj-y += auxdisplay/
+ obj-$(CONFIG_MTD) += mtd/
+-obj-$(CONFIG_SPI) += spi/
+ obj-$(CONFIG_PCCARD) += pcmcia/
+ obj-$(CONFIG_DIO) += dio/
+ obj-$(CONFIG_SBUS) += sbus/
+@@ -66,7 +68,6 @@ obj-$(CONFIG_GAMEPORT) += input/gameport/
+ obj-$(CONFIG_INPUT) += input/
+ obj-$(CONFIG_I2O) += message/
+ obj-$(CONFIG_RTC_LIB) += rtc/
+-obj-y += i2c/
+ obj-$(CONFIG_W1) += w1/
+ obj-$(CONFIG_POWER_SUPPLY) += power/
+ obj-$(CONFIG_HWMON) += hwmon/
+diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
+index 421b7c7..790cab2 100644
+--- a/drivers/ata/Kconfig
++++ b/drivers/ata/Kconfig
+@@ -724,5 +724,13 @@ config PATA_BF54X
+
+ If unsure, say N.
+
++config SATA_TCC
++ bool "Telechips SATA support (TCC8900 only)"
++ default y
++ help
++ Telechips Serial ATA.
++
++ If unsure, say N.
++
+ endif # ATA_SFF
+ endif # ATA
+diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
+index 674965f..6486672 100644
+--- a/drivers/ata/Makefile
++++ b/drivers/ata/Makefile
+@@ -18,6 +18,7 @@ obj-$(CONFIG_SATA_MV) += sata_mv.o
+ obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
+ obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
+ obj-$(CONFIG_SATA_FSL) += sata_fsl.o
++obj-$(CONFIG_SATA_TCC) += sata_snps.o
+
+ obj-$(CONFIG_PATA_ALI) += pata_ali.o
+ obj-$(CONFIG_PATA_AMD) += pata_amd.o
+diff --git a/drivers/ata/sata_snps.c b/drivers/ata/sata_snps.c
+new file mode 100644
+index 0000000..0ad9d38
+--- /dev/null
++++ b/drivers/ata/sata_snps.c
+@@ -0,0 +1,1294 @@
++/*
++ * linux/drivers/ata/sata_snps.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 1st April, 2009
++ * Description: Driver for SATA Host Controller
++ *
++ * Copyright (c) 2009 Telechips, Inc.
++ * Copyright (c) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <scsi/scsi_host.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi.h>
++#include <linux/libata.h>
++#include <linux/platform_device.h>
++
++#include <mach/TCC89x_Physical.h>
++#include <mach/TCC89x_Structures.h>
++#include <bsp.h>
++#include <mach/hardware.h>
++#include <mach/irqs.h>
++#include <mach/tca_ckc.h>
++#include <linux/workqueue.h>
++#include <linux/time.h>
++#include <linux/kthread.h>
++#include <mach/tcc_pca953x.h>
++
++#include "sata_snps.h"
++
++#define DRV_NAME "tcc_sata"
++#define DRV_VERSION "0.1"
++
++//#define jprintk(f, a...) printk("---J--- [%s:%d] " f, __func__, __LINE__, ##a)
++#define jprintk(f, a...)
++
++//#define sata_printk(f, a...) printk("---sata--- [%s:%d] " f, __func__, __LINE__, ##a)
++#define sata_printk(f, a...)
++
++#if defined(CONFIG_TCC_R_AX)
++#define __RX_TEST_DBTSR__ 8
++#define __TX_TEST_DBTSR__ 8
++//#define HSATA_DMA_DBTSR_VAL (((__RX_TEST_DBTSR__) << 16) | ((__TX_TEST_DBTSR__) << 0))
++#define HSATA_DMA_DBTSR_VAL (((__RX_TEST_DBTSR__) << 16) | ((254 - 8) << 0))
++#elif defined(CONFIG_TCC_R_XX)
++#define __RX_TEST_DBTSR__ 1
++#define __TX_TEST_DBTSR__ 1
++#define HSATA_DMA_DBTSR_VAL (((__RX_TEST_DBTSR__) << 16) | ((__TX_TEST_DBTSR__) << 0))
++#else
++#error "Undefined TCC8900 revision type !!!"
++#endif
++
++#define WAIT_TIME_FOR_DMA_DONE (1000 * 10)
++
++static void tcc_exec_command_by_tag(struct ata_port *ap, const struct ata_taskfile *tf, u8 tag);
++static void tcc_sata_setup_port(struct ata_ioports *port, void __iomem *base);
++
++
++static struct task_struct *start_sata_thread(int (*threadfn)(void *data),
++ struct tcc_sata_dev *tcc_dev,
++ const char namefmt[])
++{
++ struct task_struct *ret_task = NULL;
++ if (tcc_dev) {
++ tcc_dev->is_continue = 1;
++ ret_task = kthread_run(threadfn, tcc_dev, namefmt);
++ if (IS_ERR(ret_task)) {
++ tcc_dev->is_continue = 0;
++ ret_task = NULL;
++ printk("[%s:%d] cannot run kernel_thread !!!! \n", __func__, __LINE__);
++ }
++ }
++ return ret_task;
++}
++
++static void stop_sata_thread(struct tcc_sata_dev *tcc_dev)
++{
++ if (tcc_dev) {
++ tcc_dev->is_continue = 0;
++ if (tcc_dev->fetch_task) {
++ wake_up(&(tcc_dev->job_wait_q));
++ kthread_stop(tcc_dev->fetch_task);
++ tcc_dev->fetch_task = NULL;
++ }
++ }
++}
++
++static void tcc_start_dma(GDMANCTRL *reg)
++{
++ BITSET(reg->CHCTRL, Hw0 | Hw2);
++}
++
++static void tcc_stop_dma(GDMANCTRL *reg)
++{
++ BITCLR(reg->CHCTRL, Hw0 | Hw2);
++}
++
++static int init_tx_dma(GDMANCTRL *reg, unsigned long fifo)
++{
++ if (reg) {
++ BITCLR(reg->CHCTRL, Hw0);
++
++ reg->ST_DADR = fifo;
++
++ (reg->DPARAM)[0] = 0xFFFFE000 | 4; // fifo mask
++ //(reg->DPARAM)[0] = 0; // fifo mask
++ (reg->SPARAM)[0] = 0x0 | 4;
++
++ reg->CHCTRL &= 0x00000001;
++
++#if (__TX_TEST_DBTSR__ == 8)
++ BITSET(reg->CHCTRL, (Hw3 | Hw5 | Hw6 | Hw7 | Hw8 | Hw9 | Hw12));
++#elif (__TX_TEST_DBTSR__ == 4)
++ BITSET(reg->CHCTRL, (Hw3 | Hw5 | Hw7 | Hw8 | Hw9 | Hw12));
++#elif (__TX_TEST_DBTSR__ == 2)
++ BITSET(reg->CHCTRL, (Hw3 | Hw5 | Hw6 | Hw8 | Hw9 | Hw12));
++#else
++ BITSET(reg->CHCTRL, (Hw3 | Hw5 | Hw8 | Hw9 | Hw12));
++#endif
++ /* clear DRI at RPTCTRL */
++ BITCLR(reg->RPTCTRL, Hw31);
++
++ BITSET(reg->EXTREQ, Hw14);
++
++ return 0;
++ }
++ return -1;
++}
++
++static int init_rx_dma(GDMANCTRL *reg, unsigned long fifo)
++{
++ if (reg) {
++ BITCLR(reg->CHCTRL, Hw0);
++
++ reg->ST_SADR = fifo;
++
++ (reg->SPARAM)[0] = 0xFFFFE000 | 4; // fifo mask
++ //(reg->SPARAM)[0] = 0; // fifo mask
++ (reg->DPARAM)[0] = 0x0 | 4;
++
++ reg->CHCTRL &= 0x00000001;
++
++#if (__RX_TEST_DBTSR__ == 8)
++ BITSET(reg->CHCTRL, (Hw3 | Hw5 | Hw6 | Hw7 | Hw8 | Hw9));
++#elif (__RX_TEST_DBTSR__ == 4)
++ BITSET(reg->CHCTRL, (Hw3 | Hw5 | Hw7 | Hw8 | Hw9));
++#elif (__RX_TEST_DBTSR__ == 2)
++ BITSET(reg->CHCTRL, (Hw3 | Hw5 | Hw6 | Hw8 | Hw9));
++#else
++ BITSET(reg->CHCTRL, (Hw3 | Hw5 | Hw8 | Hw9));
++#endif
++ /* clear DRI at RPTCTRL */
++ BITCLR(reg->RPTCTRL, Hw31);
++
++ BITSET(reg->EXTREQ, Hw13);
++ return 0;
++ }
++ return -1;
++}
++
++#if 0
++static void set_tx_dma(GDMANCTRL *reg, unsigned long dma_addr, unsigned int length)
++{
++ reg->ST_SADR = dma_addr;
++ reg->HCOUNT = length / (4 * __TX_TEST_DBTSR__);
++}
++#else
++static void set_tx_dma(struct tcc_sata_dev *tcc_dev, struct tcc_sg_list * p_list)
++{
++ tcc_dev->is_tx_complete = 0;
++ tcc_dev->is_last_tx = (p_list->flags & _TCC_DMA_END_) ? 1 : 0;
++
++ tcc_dev->dma_tx_reg->ST_SADR = p_list->dma_addr;
++ tcc_dev->dma_tx_reg->HCOUNT = p_list->length / (4 * __TX_TEST_DBTSR__);
++}
++#endif
++
++#if 0
++static void set_rx_dma(GDMANCTRL *reg, unsigned long dma_addr, unsigned int length)
++{
++ reg->ST_DADR = dma_addr;
++ reg->HCOUNT = length / (4 * __RX_TEST_DBTSR__);
++}
++#else
++static void set_rx_dma(struct tcc_sata_dev *tcc_dev, struct tcc_sg_list * p_list)
++{
++ tcc_dev->is_rx_complete = 0;
++ tcc_dev->is_last_rx = (p_list->flags & _TCC_DMA_END_) ? 1 : 0;
++
++ tcc_dev->dma_rx_reg->ST_DADR = p_list->dma_addr;
++ tcc_dev->dma_rx_reg->HCOUNT = p_list->length / (4 * __RX_TEST_DBTSR__);
++}
++#endif
++
++/*
++ * success: return value => (ret == 0)
++ * fail : return value => (ret != 0)
++ */
++static int confirm_dma_job(struct tcc_dma_Q *h)
++{
++ if (h) {
++ if (h->top != h->pre) {
++ h->top = h->pre;
++ return 1;
++ }
++ return 0;
++ }
++ return -1;
++}
++
++/*
++ * success: return value => (ret == 0)
++ * fail : return value => (ret != 0)
++ */
++static int flush_dma_job(struct tcc_dma_Q *h)
++{
++ if (h) {
++ h->pre = h->bottom = h->top = 0;
++ return 0;
++ }
++ return -1;
++}
++
++/*
++ * success: return value => (ret == 0)
++ * fail : return value => (ret != 0)
++ */
++static int push_dma_job(struct tcc_dma_Q *h, unsigned int dma_addr, unsigned int len, int flags)
++{
++ if (h) {
++ h->sg_list[h->pre].dma_addr = dma_addr;
++ h->sg_list[h->pre].length = len;
++ h->sg_list[h->pre].flags = flags;
++
++ if (h->pre + 1 >= TCC_SG_LIST_MAX) {
++ h->pre = 0;
++ } else {
++ h->pre++;
++ }
++
++ if (h->pre == h->bottom) {
++ printk("!!!!!!!!!!!! overflow !!!!!!!!!!!!!!!!!\n");
++ }
++ return 0;
++ }
++ return -1;
++}
++
++/*
++ * success: return value => (ret > 0)
++ * empty : return value => (ret == 0)
++ * fail : return value => (ret < 0)
++ */
++static int pop_dma_job(struct tcc_dma_Q *h, struct tcc_sg_list *p)
++{
++ if (h && p) {
++ if (h->top != h->bottom) {
++ memcpy(p, &(h->sg_list[h->bottom]), sizeof(struct tcc_sg_list));
++ if (h->bottom + 1 >= TCC_SG_LIST_MAX) {
++ h->bottom = 0;
++ } else {
++ h->bottom++;
++ }
++ return 1;
++ }
++ return 0;
++ }
++ return -1;
++}
++
++static void wait_for_bits(volatile PSATA pSata, int ret_on_rst, int timeout_val, int exp_val, int mask, int *matched)
++{
++ int timeout_cnt = 0, error = 0;
++ int failed;
++ int rdata = 0, i = 0;
++ int phy_sig_det_w = 1;
++
++ *matched = 0;
++
++ // wait for busy, and Drq to be cleared.
++ // or timeout or reset, if checking reset
++ while ((timeout_cnt < timeout_val)
++ && !*matched && (error == 0)
++ && !(!phy_sig_det_w && ret_on_rst)) {
++ rdata = pSata->CDR7;
++ failed = 0;
++
++ for (i = 0; i <= 31; i = i + 1) {
++ if ((((mask >> i) & 1) == 1) && (((rdata >> i) & 1) != ((exp_val >> i) & 1))) {
++ failed = 1;
++ }
++ }
++
++ if (failed == 0) {
++ *matched = 1;
++ }
++
++ // After bits matched, check for error
++ if (*matched) {
++ if (((rdata & 0xff) != 0x7f) // we're not in Power on reset
++ && (((rdata >> CDR7_ERR) & 1) == 1)) // we do have error bit set
++ {
++ error = 1;
++ }
++ } else {
++ timeout_cnt = timeout_cnt + 1;
++ }
++
++ }
++
++ if ((ret_on_rst == 1) && !phy_sig_det_w) {
++ printk("wait_for_bits: detected a Non recov err, while waiting for bits on reg 0x%x\n",
++ 0x1C);
++ } else if (timeout_cnt >= timeout_val) {
++ printk("wait_for_bits: Timeout waiting reg at address '0x%x' to equal '0x%x'\n",
++ 0x1C, exp_val );
++ } else {
++ printk("wait_for_bits: Got register at address '0x%x' reg expected_value='0x%x', actual='0x%x'\n",
++ 0x1C, exp_val, rdata);
++ }
++}
++
++static void wait_for_bsydrq(volatile PSATA pSata, int ret_on_rst, int timeout_val, int *matched)
++{
++ int exp_val = 0;
++ int mask = 0x88;
++
++ wait_for_bits(pSata, ret_on_rst, timeout_val, exp_val, mask, matched);
++}
++
++static int prog_host_speed(volatile PSATA pSata, int speed, int *spd_ok)
++{
++ int spd_select;
++ int reset;
++ int reg_data;
++ //int i;
++ int ret_on_rst;
++ int timeout_val;
++ int matched;
++
++ // Initialize
++ ret_on_rst = 0;
++ //timeout_val = 1000000; // Must Be Huge For Speed Negotiation
++ timeout_val = 1000000; // Must Be Huge For Speed Negotiation
++
++ // Set speed
++ spd_select = (speed == 2) ? 0x2 : 0x1;
++
++ // Reset Device with correct speed
++ reset = 1;
++ reg_data = (spd_select << 4) | reset;
++
++ // Write SCR2 with speed and reset
++ pSata->SCR2 = reg_data;
++
++ // Need to wait a few clocks of slowest
++ //mdelay(1);
++ mdelay(10);
++
++ // Set normal operation & correct speed
++ reset = 0;
++ reg_data = spd_select << 4 | reset;
++ //HwSATA->nSCR2 = reg_data;
++ pSata->SCR2 = reg_data;
++
++ // Wait for BSY & DRQ to be cleared
++ wait_for_bsydrq(pSata, ret_on_rst, timeout_val, &matched);
++
++ if (matched) {
++ printk("prog_host_speed: Host Speed selected [speed:%d] SCR0[0x%X]\n",
++ speed, pSata->SCR0);
++ *spd_ok = 1;
++ return 0;
++ } else {
++ printk("prog_host_speed: TIMEOUT - Host Speed timed out waiting for speed change! [speed:%d], SCR0[0x%X]\n",
++ speed, pSata->SCR0);
++ *spd_ok = 0;
++ }
++ return -1;
++}
++
++static int tcc_sata_hw_init(unsigned long sata_base)
++{
++ int spd_ok = 0;
++ volatile PSATA pSata = (volatile PSATA)sata_base;
++
++ if (prog_host_speed(pSata, 2, &spd_ok) == 0) {
++ return 0;
++ } else if (prog_host_speed(pSata, 1, &spd_ok) == 0) {
++ return 0;
++ }
++ return -1;
++}
++
++static int tcc_sata_check_atapi_dma(struct ata_queued_cmd *qc)
++{
++ u8 cmnd = qc->scsicmd->cmnd[0];
++
++ switch (cmnd) {
++ case READ_10:
++ case READ_12:
++ case READ_16:
++ case WRITE_10:
++ case WRITE_12:
++ case WRITE_16:
++ //printk("ATAPI DMA OK ~~~[0x%X]\n", cmnd);
++ return 0;
++
++ default:
++ //printk("ATAPI DMA FAIL [0x%X] ~~~\n", cmnd);
++ return -1;
++ }
++}
++
++static irqreturn_t tcc_dma_isr(int irq, void *dev_id)
++{
++ struct ata_host *host = (struct ata_host *)dev_id;
++ struct tcc_sata_dev *tcc_dev = host->private_data;
++
++ struct tcc_sg_list list;
++ if (irq == tcc_dev->dma_rx_irq) {
++ tcc_dev->dma_rx_reg->CHCTRL |= Hw3;
++ tcc_stop_dma(tcc_dev->dma_rx_reg);
++
++ if (tcc_dev->is_last_rx) {
++ tcc_dev->is_rx_complete = 1;
++ wake_up(&(tcc_dev->rx_dma_wait_q));
++ } else {
++ if (pop_dma_job(&(tcc_dev->dma_q), &list) > 0) {
++ if (list.flags & _TCC_DMA_RX_) {
++ set_rx_dma(tcc_dev, &list);
++ tcc_start_dma(tcc_dev->dma_rx_reg);
++ }
++ } else {
++ printk("something wrong !!!!!!!!!!!!!!!!!!!! [%s:%d]\n", __func__, __LINE__);
++ tcc_dev->is_rx_complete = 1;
++ wake_up(&(tcc_dev->rx_dma_wait_q));
++ }
++ }
++ } else if (irq == tcc_dev->dma_tx_irq) {
++ tcc_dev->dma_tx_reg->CHCTRL |= Hw3;
++ tcc_stop_dma(tcc_dev->dma_tx_reg);
++ if (tcc_dev->is_last_tx) {
++ writel(HSATA_DMACR_TXRX_CLEAR, tcc_dev->membase + HSATA_DMACR_REG); /* rx/tx disable */
++ tcc_dev->is_tx_complete = 1;
++ wake_up(&(tcc_dev->tx_dma_wait_q));
++ } else {
++ if (pop_dma_job(&(tcc_dev->dma_q), &list) > 0) {
++ if (list.flags & _TCC_DMA_TX_) {
++ set_tx_dma(tcc_dev, &list);
++ tcc_start_dma(tcc_dev->dma_tx_reg);
++ }
++ } else {
++ printk("something wrong !!!!!!!!!!!!!!!!!!!! [%s:%d]\n", __func__, __LINE__);
++ tcc_dev->is_tx_complete = 1;
++ wake_up(&(tcc_dev->tx_dma_wait_q));
++ }
++ }
++ }
++ return IRQ_HANDLED;
++}
++
++static void tcc_port_stop(struct ata_port *ap)
++{
++ struct tcc_sata_dev *tcc_dev = ap->host->private_data;
++
++ if (tcc_dev) {
++ stop_sata_thread(tcc_dev);
++ free_irq(tcc_dev->dma_tx_irq, ap->host);
++ free_irq(tcc_dev->dma_rx_irq, ap->host);
++
++ if (tcc_dev->membase) {
++ iounmap(tcc_dev->membase);
++ kfree(tcc_dev);
++ }
++ }
++ ap->host->private_data = NULL;
++}
++
++static int fetch_dma_thread(void *arg)
++{
++ struct tcc_sata_dev *tcc_dev = (struct tcc_sata_dev *)arg;
++ int ret = 0;
++
++ sata_printk("### start kernel thread ###\n");
++ if (tcc_dev) {
++ struct tcc_sg_list list;
++ do {
++ ret = wait_event_interruptible_timeout(tcc_dev->job_wait_q,
++ (tcc_dev->dma_q.top != tcc_dev->dma_q.bottom) || !(tcc_dev->is_continue),
++ msecs_to_jiffies(1000));
++ while (tcc_dev->is_continue) {
++ if (pop_dma_job(&(tcc_dev->dma_q), &list) > 0) {
++ sata_printk("--- DMA [%s] dma_addr[0x%X], len[%d], flags[0x%X]\n",
++ list.flags & _TCC_DMA_RX_ ? "RX" : "TX", list.dma_addr, list.length, list.flags);
++
++ //ret = readl(tcc_dev->membase + HSATA_DBTSR_REG);
++ //printk("before Rx/Tx DBTSR_REG[0x%X], dma HCOUNT[0x%X]\n", ret, tcc_dev->dma_rx_reg->HCOUNT);
++
++ if (list.flags & _TCC_DMA_START_) {
++ //printk("--- start DMA [%s] dma_addr[0x%X], len[%d], flags[0x%X]\n",
++ // list.flags & _TCC_DMA_RX_ ? "RX" : "TX", list.dma_addr, list.length, list.flags);
++
++ writel(HSATA_DMACR_TXRX_CLEAR, tcc_dev->membase + HSATA_DMACR_REG); /* rx/tx disable */
++ writel(HSATA_DMA_DBTSR_VAL, tcc_dev->membase + HSATA_DBTSR_REG);
++
++ writel((list.flags & _TCC_DMA_RX_) ? HSATA_DMACR_RX_EN : HSATA_DMACR_TX_EN,
++ tcc_dev->membase + HSATA_DMACR_REG);
++ if (list.flags & _TCC_DMA_RX_) {
++ set_rx_dma(tcc_dev, &list);
++ tcc_start_dma(tcc_dev->dma_rx_reg);
++ if (wait_event_interruptible_timeout((tcc_dev->rx_dma_wait_q),
++ tcc_dev->is_rx_complete,
++ msecs_to_jiffies(WAIT_TIME_FOR_DMA_DONE)) == 0) {
++ tcc_stop_dma(tcc_dev->dma_rx_reg);
++ flush_dma_job(&(tcc_dev->dma_q));
++ ret = readl(tcc_dev->membase + HSATA_DBTSR_REG);
++ printk("[%s:%d] RX wait_event timeout (%dms) !!!\n",
++ __func__, __LINE__, WAIT_TIME_FOR_DMA_DONE);
++ printk("rx DBTSR_REG[0x%X], dma HCOUNT[0x%X]\n", ret, tcc_dev->dma_rx_reg->HCOUNT);
++ }
++ } else {
++ set_tx_dma(tcc_dev, &list);
++ tcc_start_dma(tcc_dev->dma_tx_reg);
++ if (wait_event_interruptible_timeout((tcc_dev->tx_dma_wait_q),
++ tcc_dev->is_tx_complete,
++ msecs_to_jiffies(WAIT_TIME_FOR_DMA_DONE)) == 0) {
++ tcc_stop_dma(tcc_dev->dma_tx_reg);
++ flush_dma_job(&(tcc_dev->dma_q));
++ ret = readl(tcc_dev->membase + HSATA_DBTSR_REG);
++ printk("[%s:%d] TX wait_event timeout (%dms) !!!\n",
++ __func__, __LINE__, WAIT_TIME_FOR_DMA_DONE);
++ printk("tx DBTSR_REG[0x%X], dma HCOUNT[0x%X]\n", ret, tcc_dev->dma_tx_reg->HCOUNT);
++ }
++ }
++ } else {
++ flush_dma_job(&(tcc_dev->dma_q));
++ printk("[%s:%d] mismatch q-list !!!\n", __func__, __LINE__);
++ }
++ } else {
++ break;
++ }
++ }
++ } while (!kthread_should_stop());
++ }
++ sata_printk("### end kernel thread ###\n");
++ return 0;
++}
++
++static int tcc_port_start(struct ata_port *ap)
++{
++ volatile u32 val32;
++ struct tcc_sata_dev *tcc_dev = NULL;
++ volatile PPIC pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++ int ret = 0;
++ unsigned long sata_base = 0;
++ unsigned long tx_base = (unsigned long)tcc_p2v(HwGDMA2_BASE);
++ unsigned long rx_base = (unsigned long)tcc_p2v(HwGDMA3_BASE);
++ unsigned long mmio_base_addr = (unsigned long)(ap->private_data);
++
++ tcc_dev = kmalloc(sizeof(struct tcc_sata_dev), GFP_KERNEL);
++ if (tcc_dev) {
++ memset(tcc_dev, 0, sizeof(struct tcc_sata_dev));
++ tcc_dev->membase = ioremap_nocache(mmio_base_addr, 0x800);
++ tcc_sata_setup_port(&ap->ioaddr, tcc_dev->membase);
++ ap->host->private_data = tcc_dev;
++ } else {
++ printk("[%s:%d] cannot allocate 'tcc_dev struct' \n", __func__, __LINE__);
++ return -1;
++ }
++ HSATA_ENABLE_INTERRUPTS(tcc_dev);
++
++ tcc_dev->dma_tx_reg = (GDMANCTRL *)(tx_base + 0x60);
++ tcc_dev->dma_rx_reg = (GDMANCTRL *)(rx_base + 0x60);
++
++ tcc_dev->dma_tx_irq = INT_DMA2_CH2;
++ tcc_dev->dma_rx_irq = INT_DMA3_CH2;
++
++ BITSET(pPIC->MODE0, Hw29); // level-trigger
++ BITCLR(pPIC->POL0, Hw29); // active-high
++
++ init_waitqueue_head(&(tcc_dev->job_wait_q));
++ init_waitqueue_head(&(tcc_dev->tx_dma_wait_q));
++ init_waitqueue_head(&(tcc_dev->rx_dma_wait_q));
++
++ init_rx_dma(tcc_dev->dma_rx_reg, TCC_DMADR_REG_ADDR);
++ init_tx_dma(tcc_dev->dma_tx_reg, TCC_DMADR_REG_ADDR);
++ writel(HSATA_DMACR_TXMODE_BIT, tcc_dev->membase + HSATA_DMACR_REG); /* disable */
++
++ tcc_dev->fetch_task = start_sata_thread(fetch_dma_thread, tcc_dev, "tcc_sata_task");
++ if (tcc_dev->fetch_task == NULL) {
++ return -1;
++ }
++
++ ret = request_irq(tcc_dev->dma_rx_irq,
++ tcc_dma_isr,
++ IRQF_SHARED, /* flags */
++ "HSATA-DMA-RX", /* in /proc/interrupts */
++ ap->host); /* user data passed to ISR */
++ if (!ret) {
++ ret = request_irq(tcc_dev->dma_tx_irq,
++ tcc_dma_isr,
++ IRQF_SHARED, /* flags */
++ "HSATA-DMA-TX", /* in /proc/interrupts */
++ ap->host); /* user data passed to ISR */
++ if (!ret) {
++ sata_base = (unsigned long)tcc_p2v(HwSATA_BASE);
++ tcc_sata_hw_init(sata_base);
++
++ writel(HSATA_DMA_DBTSR_VAL, tcc_dev->membase + HSATA_DBTSR_REG);
++
++ val32 = readl(tcc_dev->membase + HSATA_SCR0_REG);
++ switch (HSATA_SCR0_SPD_GET(val32)) {
++ case 0x0:
++ printk("Rx_DBTSR[%d] Tx_DBTSR[%d] **** NO NEGOTIATED SPEED!!! ****\n", __RX_TEST_DBTSR__, __TX_TEST_DBTSR__);
++ break;
++ case 0x1:
++ printk("Rx_DBTSR[%d] Tx_DBTSR[%d] **** GEN I RATE NEGOTIATED ****\n", __RX_TEST_DBTSR__, __TX_TEST_DBTSR__);
++ break;
++ case 0x2:
++ printk("Rx_DBTSR[%d] Tx_DBTSR[%d] **** GEN II RATE NEGOTIATED ****\n", __RX_TEST_DBTSR__, __TX_TEST_DBTSR__);
++ break;
++ }
++ return 0;
++ } else {
++ printk("ERROR rx request_irq ret[%d]\n", ret);
++ free_irq(tcc_dev->dma_rx_irq, ap->host);
++ }
++ } else {
++ printk("ERROR tx request_irq ret[%d]\n", ret);
++ }
++ return -1;
++}
++
++
++static int tcc_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
++{
++ if (sc_reg > SCR_CONTROL) {
++ return -EINVAL;
++ }
++ *val = readl((void *)link->ap->ioaddr.scr_addr + (sc_reg * 4));
++ return 0;
++}
++
++static int tcc_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
++{
++ if (sc_reg > SCR_CONTROL) {
++ return -EINVAL;
++ }
++ writel(val, (void *)link->ap->ioaddr.scr_addr + (sc_reg * 4));
++ return 0;
++}
++
++static void tcc_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
++
++ sata_printk("TFLAGS: %s %s %s %s\n",
++ (tf->flags & ATA_TFLAG_LBA48) ? "LBA48" : "NOT-LBA48",
++ (tf->flags & ATA_TFLAG_ISADDR) ? "ISADDR" : "",
++ (tf->flags & ATA_TFLAG_DEVICE) ? "DEVICE" : "",
++ (tf->flags & ATA_TFLAG_WRITE) ? "WRITE" : "READ");
++ sata_printk("CTL: %s %s %s\n",
++ (tf->ctl & ATA_HOB) ? "HOB" : "NOT-HOB",
++ (tf->ctl & ATA_SRST) ? "SRST" : "NOT-SRST",
++ (tf->ctl & ATA_NIEN) ? "NIEN" : "INTERRUPTS-ENABLED");
++
++ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
++ sata_printk("hob: feat=0x%X nsect=0x%X, lba:0x%X 0x%X 0x%X\n",
++ tf->hob_feature,
++ tf->hob_nsect,
++ tf->hob_lbal,
++ tf->hob_lbam,
++ tf->hob_lbah);
++ }
++
++ if (is_addr) {
++ sata_printk("feat=0x%X nsect=0x%X, lba:0x%X 0x%X 0x%X\n",
++ tf->feature,
++ tf->nsect,
++ tf->lbal,
++ tf->lbam,
++ tf->lbah);
++ }
++
++ if (tf->flags & ATA_TFLAG_DEVICE) {
++ sata_printk("ATA_TFLAG_DEVICE device=0x%X (%s)\n", tf->device,
++ (tf->device & ATA_LBA) ? "LBA" : "CHS");
++ }
++
++ if (!is_addr) {
++ sata_printk("is_addr=%d\n", is_addr);
++ }
++
++ ata_sff_tf_load(ap, tf);
++}
++
++static void tcc_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
++{
++ jprintk(" nsect=0x%X, lba:0x%X 0x%X 0x%X device=0x%x\n",
++ tf->nsect, tf->lbal, tf->lbam, tf->lbah, tf->device);
++
++ if (tf->flags & ATA_TFLAG_LBA48) {
++ jprintk("hob: feat=0x%X nsect=0x%X, lba:0x%X 0x%X 0x%X\n",
++ tf->hob_feature, tf->hob_nsect, tf->hob_lbal,
++ tf->hob_lbam, tf->hob_lbah);
++ }
++
++ ata_sff_tf_read(ap, tf);
++}
++
++static struct scsi_host_template tcc_sata_sht = {
++ ATA_BMDMA_SHT(DRV_NAME),
++};
++
++static u8 tcc_stat_check_status(struct ata_port *ap)
++{
++ return ioread8(ap->ioaddr.status_addr);
++}
++
++static void tcc_dma_setup_noexec_by_tag(struct ata_queued_cmd *qc, u8 tag)
++{
++ //struct tcc_sata_dev *tcc_dev = qc->ap->host->private_data;
++ jprintk("DMA SETUP tag=%d id=%d [%s]\n", tag, qc->ap->print_id, (qc->dma_dir == DMA_TO_DEVICE) ? "WRITE" : "READ");
++}
++
++static void tcc_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ tcc_exec_command_by_tag(ap, tf, 0);
++}
++
++static void tcc_dma_setup_by_tag(struct ata_queued_cmd *qc, u8 tag)
++{
++ tcc_dma_setup_noexec_by_tag(qc, tag);
++ tcc_exec_command(qc->ap, &qc->tf);
++}
++
++
++void tcc_dma_setup(struct ata_queued_cmd *qc)
++{
++ //struct tcc_sata_dev *tcc_dev = qc->ap->host->private_data;
++ tcc_dma_setup_by_tag(qc, 0);
++
++}
++
++void tcc_dma_start_by_tag(struct ata_queued_cmd *qc, u8 tag)
++{
++ struct tcc_sata_dev *tcc_dev = qc->ap->host->private_data;
++
++ confirm_dma_job(&(tcc_dev->dma_q));
++ wake_up(&(tcc_dev->job_wait_q));
++}
++
++
++static void tcc_dma_start(struct ata_queued_cmd *qc)
++{
++ tcc_exec_command(qc->ap, &qc->tf);
++ tcc_dma_start_by_tag(qc, 0);
++}
++
++void tcc_dma_stop(struct ata_queued_cmd *qc)
++{
++ struct tcc_sata_dev *tcc_dev = qc->ap->host->private_data;
++ if (qc->dma_dir != DMA_TO_DEVICE) {
++ writel(HSATA_DMACR_TXRX_CLEAR, tcc_dev->membase + HSATA_DMACR_REG); /* rx/tx disable */
++ } else {
++ //writel(HSATA_DMACR_TXRX_CLEAR, tcc_dev->membase + HSATA_DMACR_REG); /* rx/tx disable */
++ }
++}
++
++
++u8 tcc_dma_status(struct ata_port *ap)
++{
++ //struct tcc_sata_dev *tcc_dev = qc->ap->host->private_data;
++ return ATA_DMA_INTR;
++}
++
++void tcc_irq_clear(struct ata_port *ap)
++{
++ /* read status reg to clear interrupt in controller */
++ ata_sff_check_status(ap);
++}
++
++static void tcc_exec_command_by_tag(struct ata_port *ap, const struct ata_taskfile *tf, u8 tag)
++{
++ struct ata_host *host = ap->host;
++ struct tcc_sata_dev *tcc_dev = host->private_data;
++ volatile u32 val32;
++
++ switch (tf->command) {
++ case ATA_CMD_CHK_POWER:
++ jprintk("ATA_CMD_CHK_POWER - tag=%d\n", tag); break;
++ case ATA_CMD_EDD:
++ jprintk("ATA_CMD_EDD - tag=%d\n", tag); break;
++ case ATA_CMD_FLUSH:
++ jprintk("ATA_CMD_FLUSH - tag=%d\n", tag); break;
++ case ATA_CMD_FLUSH_EXT:
++ jprintk("ATA_CMD_FLUSH_EXT - tag=%d\n", tag); break;
++ case ATA_CMD_ID_ATA:
++ jprintk("ATA_CMD_ID_ATA - tag=%d\n", tag); break;
++ case ATA_CMD_ID_ATAPI:
++ jprintk("ATA_CMD_ID_ATAPI - tag=%d\n", tag); break;
++ case ATA_CMD_READ:
++ jprintk("ATA_CMD_READ - tag=%d\n", tag); break;
++ case ATA_CMD_READ_EXT:
++ jprintk("ATA_CMD_READ_EXT - tag=%d\n", tag); break;
++ case ATA_CMD_WRITE:
++ jprintk("ATA_CMD_WRITE - tag=%d\n", tag); break;
++ case ATA_CMD_WRITE_EXT:
++ jprintk("ATA_CMD_WRITE_EXT - tag=%d\n", tag); break;
++ case ATA_CMD_PIO_READ:
++ jprintk("ATA_CMD_PIO_READ - tag=%d\n", tag); break;
++ case ATA_CMD_PIO_READ_EXT:
++ jprintk("ATA_CMD_PIO_READ_EXT - tag=%d\n", tag); break;
++ case ATA_CMD_PIO_WRITE:
++ jprintk("ATA_CMD_PIO_WRITE - tag=%d\n", tag); break;
++ case ATA_CMD_PIO_WRITE_EXT:
++ jprintk("ATA_CMD_PIO_WRITE_EXT - tag=%d\n", tag); break;
++ case ATA_CMD_SET_FEATURES:
++ jprintk("ATA_CMD_SET_FEATURES - tag=%d\n", tag); break;
++ case ATA_CMD_PACKET:
++ jprintk("ATA_CMD_PACKET - tag=%d\n", tag); break;
++ case HSATA_CMD_QWRITE:
++ jprintk("HSATA_CMD_QWRITE - tag=%d\n", tag); break;
++ case HSATA_CMD_QREAD:
++ jprintk("HSATA_CMD_QREAD - tag=%d\n", tag); break;
++ default:
++ jprintk("ATA_CMD_??? (0x%X)\n", tf->command); break;
++ }
++
++ val32 = readl(tcc_dev->membase + HSATA_SERROR_REG);
++ jprintk("SERROR=0x%X\n", val32 );
++ writel(val32, tcc_dev->membase + HSATA_SERROR_REG);
++ val32 = readl(tcc_dev->membase + HSATA_INTPR_REG);
++ jprintk("INTPR=0x%x\n", val32);
++
++ ata_sff_exec_command(ap, tf);
++}
++
++void tcc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag)
++{
++ struct scatterlist *sg = qc->sg; /* include/asm-arm/scatterlist.h */
++ struct ata_port *ap = qc->ap;
++ struct tcc_sata_dev *tcc_dev = ap->host->private_data;
++ unsigned int nelem;
++ int dir, flags = _TCC_DMA_START_;
++ unsigned int fis_len = 0, dma_addr = 0, sg_len = 0, offset = 0, len = 0;
++
++ if (!(qc->flags & ATA_QCFLAG_DMAMAP)) {
++ jprintk("NO DMA - exiting\n");
++ return;
++ }
++
++#if 0
++ assert(sg != NULL);
++ assert(qc->n_elem > 0);
++#endif
++
++ dir = qc->dma_dir;
++
++ jprintk("QC PREP id=%d dma dir=%s n_elem=%d\n",
++ qc->ap->print_id, (dir == DMA_FROM_DEVICE) ? "FROM_DEVICE" : "TO_DEVICE", qc->n_elem);
++
++ for (nelem = qc->n_elem; nelem; nelem--) {
++ dma_addr = (unsigned int)sg_dma_address(sg);
++ sg_len = sg_dma_len(sg);
++ while (sg_len) {
++
++ flags |= ((dir == DMA_TO_DEVICE) ? _TCC_DMA_TX_ : _TCC_DMA_RX_);
++
++ offset = dma_addr & 0xFFFF;
++ len = sg_len;
++
++ if ((offset + sg_len) > 0x10000) {
++ printk("overflow !!!!!!!!!! offset[%u], sg_len[%u]\n", offset, sg_len);
++ len = 0x10000 - offset;
++ }
++
++ if ((fis_len + len) > 8192) {
++ sata_printk("SPLITTING: fis_len=%d/0x%x len=%d/0x%x\n", fis_len, fis_len, len, len);
++ len = (8192 - fis_len);
++ fis_len = 0;
++ } else {
++ fis_len += len;
++ }
++
++ if (fis_len == 8192) {
++ fis_len = 0;
++ }
++
++ sata_printk("+++ DMA sg nelem=%d dma_addr=0x%X sg_len=%d [%s]\n",
++ qc->n_elem, dma_addr, sg_len, (dir == DMA_TO_DEVICE) ? "TX" : "RX");
++
++ sg_len -= len;
++ if ((sg_len == 0) && (nelem == 1)) {
++ flags |= _TCC_DMA_END_;
++ sata_printk("********* LAST DMA LIST *********\n");
++ }
++
++ push_dma_job(&(tcc_dev->dma_q), dma_addr, len, flags);
++ dma_addr += len;
++ flags = 0;
++ }
++ sg++;
++ }
++}
++
++static void tcc_qc_prep(struct ata_queued_cmd *qc)
++{
++ if (!(qc->flags & ATA_QCFLAG_DMAMAP)) {
++ return;
++ }
++ tcc_qc_prep_by_tag(qc, 0);
++}
++
++
++static unsigned int tcc_qc_issue_prot(struct ata_queued_cmd *qc)
++{
++ jprintk("id=%d\n", qc->ap->print_id);
++
++ /* see promise driver also */
++ switch (qc->tf.protocol) {
++ case ATA_PROT_DMA:
++ jprintk("ATA_PROT_DMA\n");
++ break;
++ case ATA_PROT_PIO:
++ jprintk("ATA_PROT_PIO\n");
++ break;
++ }
++ return ata_sff_qc_issue(qc);
++}
++
++static struct ata_port_operations tcc_sata_ops = {
++ //.inherits = &ata_bmdma_port_ops,
++ //.inherits = &sata_pmp_port_ops,
++
++ .inherits = &ata_sff_port_ops,
++ .mode_filter = ata_bmdma_mode_filter,
++ .bmdma_setup = tcc_dma_setup,
++ .bmdma_start = tcc_dma_start,
++ .bmdma_stop = tcc_dma_stop,
++ .bmdma_status = tcc_dma_status,
++
++ .sff_exec_command = tcc_exec_command,
++
++ .sff_tf_load = tcc_tf_load,
++ .sff_tf_read = tcc_tf_read,
++ .sff_check_status = tcc_stat_check_status,
++ .check_atapi_dma = tcc_sata_check_atapi_dma,
++
++ .scr_read = tcc_scr_read,
++ .scr_write = tcc_scr_write,
++
++ .port_start = tcc_port_start,
++ .port_stop = tcc_port_stop,
++ .sff_irq_clear = tcc_irq_clear,
++
++ .qc_prep = tcc_qc_prep,
++ .qc_issue = tcc_qc_issue_prot,
++
++};
++
++static void tcc_sata_setup_port(struct ata_ioports *port, void __iomem *base)
++{
++ port->cmd_addr = base + 0x00;
++ port->data_addr = base + 0x00;
++
++
++ port->error_addr = base + 0x04;
++ port->feature_addr = base + 0x04;
++
++ port->nsect_addr = base + 0x08;
++
++ port->lbal_addr = base + 0x0c;
++ port->lbam_addr = base + 0x10;
++ port->lbah_addr = base + 0x14;
++
++ port->device_addr = base + 0x18;
++
++ port->command_addr = base + 0x1c;
++ port->status_addr = base + 0x1c;
++
++ port->altstatus_addr = base + 0x20;
++ port->ctl_addr = base + 0x20;
++
++ {
++ unsigned long sata_base = (unsigned long)tcc_p2v(HwGDMA2_BASE);
++ sata_base += 0x60;
++ port->bmdma_addr = (void __iomem *)(sata_base); /* we better never use this */
++ }
++ port->scr_addr = base + 0x24;
++
++}
++
++static const struct ata_port_info sata_tcc_port_info[] = {
++ {
++ .flags = (ATA_FLAG_SATA /* loik ??? flags */
++ | ATA_FLAG_NO_LEGACY /* no legacy mode check */
++ //| ATA_FLAG_SRST /* use ATA SRST, not E.D.D. */
++ | ATA_FLAG_MMIO), /* use MMIO, not PortIO */
++
++ .pio_mask = 0x1f, /* pio0-4 - IDENTIFY DEVICE word 63 */
++ .udma_mask = 0x7f, /* udma0-6 - IDENTIFY DEVICE word 88 */
++ //.mwdma_mask = 0x07, /* mwdma0-2 - IDENTIFY DEVICE word 64 */
++ .port_ops = &tcc_sata_ops,
++ },
++};
++
++static irqreturn_t tcc_sata_isr(int irq, void *dev_id)
++{
++ struct ata_host *host = (struct ata_host *)dev_id;
++ struct tcc_sata_dev *tcc_dev = host->private_data;
++ struct ata_port *ap;
++ volatile u32 intpr;
++ volatile u32 val32;
++ unsigned int handled = 0;
++ unsigned int i;
++ u32 err_interrupt;
++ u8 tag;
++ volatile u32 sactive, tmp;
++ struct ata_queued_cmd *qc;
++ //unsigned long flags;
++
++ //spin_lock_irqsave(&host->lock, flags);
++
++ ap = host->ports[0];
++
++ intpr = readl(tcc_dev->membase + HSATA_INTPR_REG);
++ jprintk("INTPR=0x%x\n", intpr);
++
++ if (intpr & HSATA_INTMR_ERRM_BIT) {
++ val32 = readl(tcc_dev->membase + HSATA_SERROR_REG);
++ sata_printk("============> SERROR=0x%08x INTPR=0x%x\n", val32, intpr);
++ writel(val32, tcc_dev->membase + HSATA_SERROR_REG); /* to clear */
++ writel(HSATA_INTMR_ERRM_BIT, tcc_dev->membase + HSATA_INTPR_REG); /* to clear */
++ err_interrupt = 1;
++ handled = 1;
++ goto DONE;
++ } else {
++ err_interrupt = 0;
++ }
++
++ tmp = readl(tcc_dev->membase + HSATA_SACTIVE_REG);
++ jprintk("SACTIVE=0x%x\n", tmp);
++
++ if (intpr & HSATA_INTMR_NEWFP_BIT) {
++ writel(HSATA_INTMR_NEWFP_BIT, tcc_dev->membase + HSATA_INTPR_REG); /* to clear */
++ tag = ((u8)readl(tcc_dev->membase + HSATA_FPTAGR_REG)) & 0x1f;
++ sata_printk("============> NEWFP tag=%d\n", tag);
++ handled = 1;
++ goto DONE;
++ }
++
++ if (intpr & HSATA_INTMR_DMAT_BIT) {
++ writel(HSATA_INTMR_DMAT_BIT, tcc_dev->membase + HSATA_INTPR_REG); /* to clear */
++ sata_printk("============> HSATA_INTMR_DMAT_BIT\n");
++ handled = 1;
++ goto DONE;
++ }
++ if (intpr & HSATA_INTMR_PMABORT) {
++ writel(HSATA_INTMR_PMABORT, tcc_dev->membase + HSATA_INTPR_REG); /* to clear */
++ sata_printk("============> HSATA_INTMR_PMABORT\n");
++ handled = 1;
++ goto DONE;
++ }
++ if (intpr & HSATA_INTMR_NEWBIST_BIT) {
++ writel(HSATA_INTMR_NEWBIST_BIT, tcc_dev->membase + HSATA_INTPR_REG); /* to clear */
++ sata_printk("============> HSATA_INTMR_NEWBIST_BIT\n");
++ handled = 1;
++ goto DONE;
++ }
++ if (intpr & HSATA_INTMR_PRIMERR_BIT) {
++ writel(HSATA_INTMR_PRIMERR_BIT, tcc_dev->membase + HSATA_INTPR_REG); /* to clear */
++ sata_printk("============> HSATA_INTMR_PRIMERR_BIT\n");
++ handled = 1;
++ goto DONE;
++ }
++ if (intpr & HSATA_INTMR_CMDABORT_BIT) {
++ writel(HSATA_INTMR_CMDABORT_BIT, tcc_dev->membase + HSATA_INTPR_REG); /* to clear */
++ sata_printk("============> HSATA_INTMR_CMDABORT_BIT\n");
++ handled = 1;
++ goto DONE;
++ }
++ if (intpr & HSATA_INTMR_CMDGOOD_BIT) {
++ writel(HSATA_INTMR_CMDGOOD_BIT, tcc_dev->membase + HSATA_INTPR_REG); /* to clear */
++ jprintk("============> HSATA_INTMR_CMDGOOD_BIT\n");
++ handled = 1;
++ goto DONE;
++ }
++
++ sactive = readl(tcc_dev->membase + HSATA_SACTIVE_REG); /* remaining pending */
++ if (sactive) {
++ sata_printk("UNEXPECTED SACTIVE??? sactive=0x%x\n", sactive );
++ }
++
++ for (i = 0; i < host->n_ports; i++) {
++ struct ata_port *ap;
++
++ ap = host->ports[i];
++ if (ap &&
++ !(ap->flags & ATA_FLAG_DISABLED)) {
++
++ qc = ata_qc_from_tag(ap, ap->link.active_tag);
++ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
++ (qc->flags & ATA_QCFLAG_ACTIVE)) {
++ handled |= ata_sff_host_intr(ap, qc);
++ }
++ }
++ }
++
++ sata_printk("====================> INTR DONE\n");
++ if (handled == 0) {
++ sata_printk("handled error !!!!!!!!! \n");
++ if ((qc = ata_qc_from_tag(ap, ap->link.active_tag))) {
++ ata_qc_complete(qc);
++ }
++ ata_sff_check_status(ap);
++ handled = 1;
++ }
++
++ //spin_unlock_irqrestore(&host->lock, flags);
++DONE:
++ return IRQ_RETVAL(handled);
++}
++
++static int tcc_sata_remove(struct platform_device *pdev)
++{
++ struct ata_host *host = platform_get_drvdata(pdev);
++ //struct tcc_sata_dev *tcc_dev = NULL;
++
++ if (host) {
++ ata_host_detach(host);
++ }
++ return 0;
++}
++
++static int __init tcc_sata_probe(struct platform_device *pdev)
++{
++ const struct ata_port_info *ppi[] = { &(sata_tcc_port_info[0]), NULL };
++ struct ata_host *host;
++ int n_ports;
++ struct resource *res;
++ struct ata_port *ap = NULL;
++ int irq = -1;
++ PPMU p_pmu = (PPMU)tcc_p2v(HwPMU_BASE);
++ volatile PPIC pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++
++ printk("TCC SATA version " DRV_VERSION "\n");
++
++ BITCLR(p_pmu->PWROFF, Hw4); // SATA popwer on
++ tca_ckc_setiobus(RB_SATAHCONTROLLER, 1);
++
++ BITSET(pPIC->SEL1, 1 << (INT_SATA - 32));
++ BITSET(pPIC->MODE1, 1 << (INT_SATA - 32));
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (res == NULL) {
++ return -EINVAL;
++ }
++ irq = platform_get_irq(pdev, 0);
++
++ /* allocate host */
++ n_ports = 1;
++ host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
++ if (!host) {
++ return -ENOMEM;
++ }
++
++ ap = host->ports[0];
++ ap->private_data = (void *)(res->start);
++ platform_set_drvdata(pdev, host);
++
++ return ata_host_activate(host, irq, tcc_sata_isr, IRQF_SHARED, &tcc_sata_sht);
++ //return ata_host_activate(host, irq, ata_sff_interrupt, IRQF_SHARED, &tcc_sata_sht);
++}
++
++static struct platform_driver tcc_sata_driver = {
++ .probe = tcc_sata_probe,
++ .remove = tcc_sata_remove,
++ .driver = {
++ .name = "tcc-sata",
++ .owner = THIS_MODULE,
++ },
++};
++
++#ifdef CONFIG_SATA_TCC
++static stpwrinfo sata_pwrinfo = { PWR_STATUS_ON };
++/**********************************************************************
++ * [The condition of SATA power control ]
++ * 1 The Main-Board must be greater than version 1.0 or equal.
++ * 2 And you need to fix the Main-Board. (refer to the schematic)
++ * ********************************************************************/
++static int sata_pwr_ctl(void *h_private, int cmd, void *p_out)
++{
++ int ret = -EINVAL;
++ PPMU p_pmu = (PPMU)tcc_p2v(HwPMU_BASE);
++
++ switch (cmd) {
++ case PWR_CMD_OFF:
++ sata_printk("PWR_CMD_OFF command ==> [%d]\n", cmd);
++ if (sata_pwrinfo.status == PWR_STATUS_ON) {
++ platform_driver_unregister(&tcc_sata_driver);
++ tcc_pca953x_setup(PCA9539_U2_SLAVE_ADDR, SATA_ON, OUTPUT, LOW, SET_DIRECTION | SET_VALUE);
++ BITSET(p_pmu->PWROFF, Hw4); // SATA popwer off
++ tca_ckc_setiobus(RB_SATAHCONTROLLER, 0);
++ sata_pwrinfo.status = PWR_STATUS_OFF;
++ ret = 0;
++ } else {
++ //printk("already SATA power is ON !!!\n");
++ ret = 0;
++ }
++ break;
++ case PWR_CMD_ON:
++ sata_printk("PWR_CMD_ON command ==> [%d]\n", cmd);
++ if (sata_pwrinfo.status == PWR_STATUS_OFF) {
++ tcc_pca953x_setup(PCA9539_U2_SLAVE_ADDR, SATA_ON, OUTPUT, HIGH, SET_DIRECTION | SET_VALUE);
++ if (platform_driver_register(&tcc_sata_driver) == 0) {
++ sata_pwrinfo.status = PWR_STATUS_ON;
++ ret = 0;
++ } else {
++ ret = -EIO;
++ tcc_pca953x_setup(PCA9539_U2_SLAVE_ADDR, SATA_ON, OUTPUT, LOW, SET_DIRECTION | SET_VALUE);
++ BITSET(p_pmu->PWROFF, Hw4); // SATA popwer off
++ tca_ckc_setiobus(RB_SATAHCONTROLLER, 0);
++ printk("cannot register a SATA driver !!!\n");
++ }
++ } else {
++ //printk("already SATA power is OFF !!!\n");
++ ret = 0;
++ }
++ break;
++ case PWR_CMD_GETSTATUS:
++ sata_printk("PWR_CMD_GETSTATUS command ==> [%d]\n", cmd);
++ memcpy(p_out, &sata_pwrinfo, sizeof(stpwrinfo));
++ ret = 0;
++ break;
++ /*
++ case PWR_CMD_MAX:
++ printk("PWR_CMD_MAX command ==> [%d]\n", cmd);
++ break;
++ */
++ default:
++ printk("unknown pwr command !!! ==> [%d]\n", cmd);
++ break;
++ }
++ return ret;
++}
++#endif
++
++static int __init tcc_sata_init(void)
++{
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, PWR_GP4, OUTPUT, HIGH, SET_DIRECTION | SET_VALUE);
++ tcc_pca953x_setup(PCA9539_U2_SLAVE_ADDR, SATA_ON, OUTPUT, HIGH, SET_DIRECTION | SET_VALUE);
++#ifdef CONFIG_SATA_TCC
++ sata_pwrinfo.status = PWR_STATUS_ON;
++ insert_pwm_node(DEVICE_SATA, sata_pwr_ctl, NULL);
++#endif
++ //return platform_driver_probe(&tcc_sata_driver, tcc_sata_probe);
++ return platform_driver_register(&tcc_sata_driver);
++}
++
++static void __exit tcc_sata_exit(void)
++{
++ PPMU p_pmu = (PPMU)tcc_p2v(HwPMU_BASE);
++#ifdef CONFIG_SATA_TCC
++ remove_pwm_node(DEVICE_SATA);
++#endif
++ platform_driver_unregister(&tcc_sata_driver);
++
++ BITSET(p_pmu->PWROFF, Hw4); // SATA popwer off
++ tca_ckc_setiobus(RB_SATAHCONTROLLER, 0);
++ tcc_pca953x_setup(PCA9539_U2_SLAVE_ADDR, SATA_ON, OUTPUT, LOW, SET_DIRECTION | SET_VALUE);
++}
++
++MODULE_AUTHOR("Telechips");
++MODULE_DESCRIPTION("TCC SATA controller");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
++module_init(tcc_sata_init);
++module_exit(tcc_sata_exit);
++
+diff --git a/drivers/ata/sata_snps.h b/drivers/ata/sata_snps.h
+new file mode 100644
+index 0000000..ee35d1b
+--- /dev/null
++++ b/drivers/ata/sata_snps.h
+@@ -0,0 +1,157 @@
++
++#ifndef __SATA_SNPS_H__
++#define __SATA_SNPS_H__
++
++/*
++ * HSATA Registers
++ */
++#define TCC_SATA_BASE_ADDR 0xF0560000
++#define HSATA_MEM_BASE TCC_SATA_BASE_ADDR
++
++
++#define HSATA_SCR0_REG 0x0024
++#define HSATA_SCR0_SPD_GET(v) (((v) & 0x000000f0) >> 4)
++#define HSATA_SCR1_REG 0x0028
++#define HSATA_SCR2_REG 0x002C
++#define HSATA_SCR3_REG 0x0030
++#define HSATA_SCR4_REG 0x0034
++
++#define HSATA_SSTATUS_REG HSATA_SCR0_REG
++#define HSATA_SERROR_REG HSATA_SCR1_REG
++#define HSATA_SERROR_ERR_BITS 0x0000ffff
++#define HSATA_SCONTROL_REG HSATA_SCR2_REG
++#define HSATA_SACTIVE_REG HSATA_SCR3_REG
++#define HSATA_SNOTIFICATION_REG HSATA_SCR4_REG
++
++#define HSATA_FPTAGR_REG 0x0064
++#define HSATA_FPBOR_REG 0x0068
++#define HSATA_FPTCR_REG 0x006C
++#define HSATA_DMACR_REG 0x0070
++
++#if 1
++#define HSATA_DMACR_TXMODE_BIT 0x04
++#define HSATA_DMACR_TX_EN 0x01 | HSATA_DMACR_TXMODE_BIT
++#define HSATA_DMACR_RX_EN 0x02 | HSATA_DMACR_TXMODE_BIT
++#define HSATA_DMACR_TXRX_EN 0x03 | HSATA_DMACR_TXMODE_BIT
++#define HSATA_DMACR_TXRX_CLEAR HSATA_DMACR_TXMODE_BIT
++#else
++#define HSATA_DMACR_TXMODE_BIT 0x00
++#define HSATA_DMACR_TX_EN 0x01 | HSATA_DMACR_TXMODE_BIT
++#define HSATA_DMACR_RX_EN 0x02 | HSATA_DMACR_TXMODE_BIT
++#define HSATA_DMACR_TXRX_EN 0x03 | HSATA_DMACR_TXMODE_BIT
++#define HSATA_DMACR_TXRX_CLEAR HSATA_DMACR_TXMODE_BIT
++#endif
++
++
++
++#define HSATA_DBTSR_REG 0x0074
++#define HSATA_INTPR_REG 0x0078
++//#define HSATA_INTPR_ERR_BIT 0x00000008
++//#define HSATA_INTPR_FP_BIT 0x00000002 /* new DMA setup FIS arrived */
++#define HSATA_INTMR_REG 0x007C
++
++
++
++#define HSATA_INTMR_DMAT_BIT Hw0
++#define HSATA_INTMR_NEWFP_BIT Hw1
++#define HSATA_INTMR_PMABORT Hw2
++#define HSATA_INTMR_ERRM_BIT Hw3
++#define HSATA_INTMR_NEWBIST_BIT Hw4
++#define HSATA_INTMR_PRIMERR_BIT Hw5
++#define HSATA_INTMR_CMDABORT_BIT Hw6
++#define HSATA_INTMR_CMDGOOD_BIT Hw7
++
++#define TCC_INTR_CHECK_BIT (HSATA_INTMR_DMAT_BIT \
++ | HSATA_INTMR_NEWFP_BIT \
++ | HSATA_INTMR_PMABORT \
++ | HSATA_INTMR_ERRM_BIT \
++ | HSATA_INTMR_NEWBIST_BIT \
++ | HSATA_INTMR_PRIMERR_BIT \
++ | HSATA_INTMR_CMDABORT_BIT \
++ | HSATA_INTMR_CMDGOOD_BIT)
++
++
++
++#define HSATA_ERRMR_REG 0x0080
++#define HSATA_LLCR_REG 0x0084
++#define HSATA_PHYCR_REG 0x0088
++#define HSATA_PHYSR_REG 0x008C
++#define HSATA_RXBISTPD_REG 0x0090
++#define HSATA_RXBISTD1_REG 0x0094
++#define HSATA_RXBISTD2_REG 0x0098
++#define HSATA_TXBISTPD_REG 0x009C
++#define HSATA_TXBISTD1_REG 0x00A0
++#define HSATA_TXBISTD2_REG 0x00A4
++#define HSATA_BISTCR_REG 0x00A8
++#define HSATA_BISTFCTR_REG 0x00AC
++#define HSATA_BISTSR_REG 0x00B0
++#define HSATA_BISTDECR_REG 0x00B4
++
++#define HSATA_TESTR_REG 0x00F4
++#define HSATA_VERSONR_REG 0x00F8
++#define HSATA_IDR_REG 0x00FC
++
++#define HSATA_CMD_QWRITE 0x61 /* these don't seem to be defined in ata.h/libata.h */
++#define HSATA_CMD_QREAD 0x60
++
++
++#define TCC_DMADR_REG 0x0400
++#define TCC_DMADR_REG_ADDR (HSATA_MEM_BASE + TCC_DMADR_REG)
++
++
++#define HSATA_ENABLE_INTERRUPTS(tcc_dev) \
++ { \
++ volatile u32 val32; \
++ /* enable all err interrupts */ \
++ /* COMRESET clears reg INTMR so .. see where this func is called */ \
++ writel( 0xffffffff, tcc_dev->membase + HSATA_ERRMR_REG ); \
++ val32 = readl( tcc_dev->membase + HSATA_INTMR_REG ); \
++ writel( val32 | TCC_INTR_CHECK_BIT, \
++ tcc_dev->membase + HSATA_INTMR_REG ); \
++ val32 = readl( tcc_dev->membase + HSATA_INTMR_REG ); \
++ jprintk("INTMR=0x%x", val32);\
++ }
++
++
++#define TCC_QCMD_MAX 128
++#define TCC_SG_LIST_MAX (TCC_QCMD_MAX * 8)
++
++#define _TCC_DMA_TX_ 0x01
++#define _TCC_DMA_RX_ 0x02
++#define _TCC_DMA_END_ 0x04
++#define _TCC_DMA_START_ 0x08
++
++
++#define CDR7_ERR 0
++
++struct tcc_sg_list {
++ unsigned int dma_addr;
++ unsigned int length;
++ int flags;
++};
++
++struct tcc_dma_Q {
++ struct tcc_sg_list sg_list[TCC_SG_LIST_MAX];
++ int top, bottom, pre;
++};
++
++struct tcc_sata_dev {
++ void __iomem *membase;
++ GDMANCTRL *dma_tx_reg, *dma_rx_reg;
++ int dma_tx_irq, dma_rx_irq;
++
++ struct tcc_dma_Q dma_q;
++ int is_rx_complete, is_tx_complete;
++ int is_last_rx, is_last_tx;
++ wait_queue_head_t job_wait_q;
++ wait_queue_head_t tx_dma_wait_q;
++ wait_queue_head_t rx_dma_wait_q;
++ int is_continue;
++ struct task_struct *fetch_task;
++};
++
++
++
++
++#endif /*__SATA_SNPS_H__*/
++
+diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
+index 911208b..205a2dd 100644
+--- a/drivers/base/power/Makefile
++++ b/drivers/base/power/Makefile
+@@ -1,6 +1,7 @@
+ obj-$(CONFIG_PM) += sysfs.o
+ obj-$(CONFIG_PM_SLEEP) += main.o
+ obj-$(CONFIG_PM_TRACE_RTC) += trace.o
++obj-$(CONFIG_DPM) += power-dpm.o
+
+ ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
+ ccflags-$(CONFIG_PM_VERBOSE) += -DDEBUG
+diff --git a/drivers/base/power/power-dpm.c b/drivers/base/power/power-dpm.c
+new file mode 100644
+index 0000000..b184b85
+--- /dev/null
++++ b/drivers/base/power/power-dpm.c
+@@ -0,0 +1,464 @@
++/*
++ * power-dpm.c -- Dynamic Power Management LDM power hooks
++ *
++ * (c) 2003 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 <linux/device.h>
++#include <linux/pm.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/notifier.h>
++#include <linux/list.h>
++
++#include "power.h"
++#include <plat/dpm.h>
++#include <linux/dpm.h>
++
++/*
++ * power hotplug events
++ */
++#if 0
++#define dbg printk
++#else /* no debug */
++#define dbg(x...) do {} while(0)
++#endif
++
++#define BUFFER_SIZE 1024 /* should be enough memory for the env */
++#define NUM_ENVP 32 /* number of env pointers */
++static unsigned long sequence_num;
++static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED;
++
++void power_event(char *eventstr)
++{
++ char *argv [3];
++ char **envp = NULL;
++ char *buffer = NULL;
++ char *scratch;
++ int i = 0;
++ int retval;
++ unsigned long seq;
++
++ if (!uevent_helper[0])
++ return;
++
++ envp = kmalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
++ if (!envp)
++ return;
++ memset (envp, 0x00, NUM_ENVP * sizeof (char *));
++
++ buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
++ if (!buffer)
++ goto exit;
++
++ argv [0] = uevent_helper;
++ argv [1] = "power";
++ argv [2] = 0;
++
++ /* minimal command environment */
++ envp [i++] = "HOME=/";
++ envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
++
++ scratch = buffer;
++
++ envp [i++] = scratch;
++ scratch += sprintf(scratch, "ACTION=event") + 1;
++
++ spin_lock(&sequence_lock);
++ seq = sequence_num++;
++ spin_unlock(&sequence_lock);
++
++ envp [i++] = scratch;
++ scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1;
++ envp [i++] = scratch;
++ scratch += sprintf(scratch, "EVENT=%s", eventstr) + 1;
++
++ pr_debug ("%s: %s %s %s %s %s %s %s\n", __FUNCTION__, argv[0], argv[1],
++ envp[0], envp[1], envp[2], envp[3], envp[4]);
++ retval = call_usermodehelper (argv[0], argv, envp, 0);
++ if (retval)
++ pr_debug ("%s - call_usermodehelper returned %d\n",
++ __FUNCTION__, retval);
++
++exit:
++ kfree(buffer);
++ kfree(envp);
++ return;
++}
++
++void device_power_event(struct device * dev, char *eventstr)
++{
++ char *argv [3];
++ char **envp = NULL;
++ char *buffer = NULL;
++ char *scratch;
++ int i = 0;
++ int retval;
++ unsigned long seq;
++
++ if (!uevent_helper[0])
++ return;
++
++ envp = kmalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
++ if (!envp)
++ return;
++ memset (envp, 0x00, NUM_ENVP * sizeof (char *));
++
++ buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
++ if (!buffer)
++ goto exit;
++
++ argv [0] = uevent_helper;
++ argv [1] = "power";
++ argv [2] = 0;
++
++ /* minimal command environment */
++ envp [i++] = "HOME=/";
++ envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
++
++ scratch = buffer;
++
++ envp [i++] = scratch;
++ scratch += sprintf(scratch, "ACTION=device-event") + 1;
++
++ spin_lock(&sequence_lock);
++ seq = sequence_num++;
++ spin_unlock(&sequence_lock);
++
++ envp [i++] = scratch;
++ scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1;
++ envp [i++] = scratch;
++ scratch += sprintf(scratch, "DEVICE=%s", dev->bus_id) + 1;
++ envp [i++] = scratch;
++ scratch += sprintf(scratch, "EVENT=%s", eventstr) + 1;
++ envp [i++] = scratch;
++ scratch += sprintf(scratch, "SUBSYSTEM=power") + 1;
++
++ pr_debug ("%s: %s %s %s %s %s %s %s %s %s\n", __FUNCTION__, argv[0], argv[1],
++ envp[0], envp[1], envp[2], envp[3], envp[4], envp[5],
++ envp[6]);
++ retval = call_usermodehelper (argv[0], argv, envp, 0);
++ if (retval)
++ pr_debug ("%s - call_usermodehelper returned %d\n",
++ __FUNCTION__, retval);
++
++exit:
++ kfree(buffer);
++ kfree(envp);
++ return;
++}
++
++/*
++ * Device constraints
++ */
++
++#ifdef CONFIG_DPM
++LIST_HEAD(dpm_constraints);
++DECLARE_MUTEX(dpm_constraints_sem);
++
++void assert_constraints(struct constraints *constraints)
++{
++ if (! constraints || constraints->asserted)
++ return;
++
++ down(&dpm_constraints_sem);
++ constraints->asserted = 1;
++ list_add_tail(&constraints->entry, &dpm_constraints);
++ up(&dpm_constraints_sem);
++
++ /* DPM-PM-TODO: Check against DPM state. */
++
++}
++
++
++void deassert_constraints(struct constraints *constraints)
++{
++ if (! constraints || ! constraints->asserted)
++ return;
++
++ down(&dpm_constraints_sem);
++ constraints->asserted = 0;
++ list_del_init(&constraints->entry);
++ up(&dpm_constraints_sem);
++}
++
++
++EXPORT_SYMBOL(assert_constraints);
++EXPORT_SYMBOL(deassert_constraints);
++
++static ssize_t
++constraints_show(struct device * dev, struct device_attribute *attr,
++ char * buf)
++{
++ int i, cnt = 0;
++
++ if (dev->constraints) {
++ for (i = 0; i < dev->constraints->count; i++) {
++ cnt += sprintf(buf + cnt,"%s: min=%d max=%d\n",
++ dpm_param_names[dev->constraints->param[i].id],
++ dev->constraints->param[i].min,
++ dev->constraints->param[i].max);
++ }
++
++ cnt += sprintf(buf + cnt,"asserted=%s violations=%d\n",
++ dev->constraints->asserted ?
++ "yes" : "no", dev->constraints->violations);
++ } else {
++ cnt += sprintf(buf + cnt,"none\n");
++ }
++
++ return cnt;
++}
++
++static ssize_t
++constraints_store(struct device * dev, struct device_attribute *attr,
++ const char * buf, size_t count)
++{
++ int num_args, paramid, min, max;
++ int cidx;
++ const char *cp, *paramname;
++ int paramnamelen;
++ int provisional = 0;
++ int ret = 0;
++
++ if (!dev->constraints) {
++ if (! (dev->constraints = kmalloc(sizeof(struct constraints),
++ GFP_KERNEL)))
++ return -EINVAL;
++
++ memset(dev->constraints, 0,
++ sizeof(struct constraints));
++ provisional = 1;
++ }
++
++ cp = buf;
++ while((cp - buf < count) && *cp && (*cp == ' '))
++ cp++;
++
++ paramname = cp;
++
++ while((cp - buf < count) && *cp && (*cp != ' '))
++ cp++;
++
++ paramnamelen = cp - paramname;
++ num_args = sscanf(cp, "%d %d", &min, &max);
++
++ if (num_args != 2) {
++ printk("DPM: Need 2 integer parameters for constraint min/max.\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ for (paramid = 0; paramid < DPM_PP_NBR; paramid++) {
++ if (strncmp(paramname, dpm_param_names[paramid], paramnamelen) == 0)
++ break;
++ }
++
++ if (paramid >= DPM_PP_NBR) {
++ printk("DPM: Unknown power parameter name in device constraints\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ for (cidx = 0; cidx < dev->constraints->count; cidx++)
++ /*
++ * If the new range overlaps an existing range,
++ * modify the existing one.
++ */
++
++ if ((dev->constraints->param[cidx].id == paramid) &&
++ ((max == -1) ||
++ (max >= dev->constraints->param[cidx].min)) &&
++ ((min == -1) ||
++ (min <= dev->constraints->param[cidx].max)))
++ break;
++
++ if (cidx >= DPM_CONSTRAINT_PARAMS_MAX) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ /* Error if max is less than min */
++ if (max < min) {
++ printk("DPM: Max value of the constraint should not be less than min\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ dev->constraints->param[cidx].id = paramid;
++ dev->constraints->param[cidx].max = max;
++ dev->constraints->param[cidx].min = min;
++
++ if (cidx == dev->constraints->count)
++ dev->constraints->count++;
++
++ /* New constraints should start off with same state as power
++ state */
++ if (provisional && (dev->power.power_state.event == PM_EVENT_ON))
++ assert_constraints(dev->constraints);
++
++out:
++
++ if (provisional && (ret < 0)) {
++ kfree(dev->constraints);
++ dev->constraints = NULL;
++ }
++
++ return ret < 0 ? ret : count;
++}
++
++DEVICE_ATTR(constraints,S_IWUSR | S_IRUGO,
++ constraints_show,constraints_store);
++
++#else /* CONFIG_DPM */
++void assert_constraints(struct constraints *constraints)
++{
++}
++
++void deassert_constraints(struct constraints *constraints)
++{
++}
++#endif /* CONFIG_DPM */
++
++#ifdef CONFIG_DPM
++
++#if 0
++/*
++ * Driver scale callbacks
++ */
++
++static struct notifier_block *dpm_scale_notifier_list[SCALE_MAX];
++static DECLARE_MUTEX(dpm_scale_sem);
++
++/* This function may be called by the platform frequency scaler before
++ or after a frequency change, in order to let drivers adjust any
++ clocks or calculations for the new frequency. */
++
++void dpm_driver_scale(int level, struct dpm_opt *newop)
++{
++ atomic_notifier_call_chain(&dpm_scale_notifier_list[level], level, newop);
++ up(&dpm_scale_sem);
++}
++
++void dpm_register_scale(struct notifier_block *nb, int level)
++{
++ down(&dpm_scale_sem);
++ atomic_notifier_chain_register(&dpm_scale_notifier_list[level], nb);
++ up(&dpm_scale_sem);
++}
++
++void dpm_unregister_scale(struct notifier_block *nb, int level)
++{
++ down(&dpm_scale_sem);
++ atomic_notifier_chain_unregister(&dpm_scale_notifier_list[level], nb);
++ up(&dpm_scale_sem);
++}
++#endif
++
++
++int dpm_constraint_rejects = 0;
++
++//EXPORT_SYMBOL(dpm_default_check_constraint);
++int
++dpm_default_check_constraint(struct constraint_param *param,
++ struct dpm_opt *opt)
++{
++ return (opt->pp[param->id] == -1) ||
++ ((param->min == -1 || opt->pp[param->id] >= param->min) &&
++ (param->max == -1 || opt->pp[param->id] <= param->max));
++}
++
++static int
++dpm_check_a_constraint(struct constraints *constraints, struct dpm_opt *opt)
++{
++ int i;
++ int failid = -1;
++ int ppconstraint[DPM_PP_NBR];
++
++
++ if (! constraints || !constraints->asserted)
++ return 1;
++
++ /*
++ * ppconstraint[ppid] == 0 means power param has not been checked
++ * for a constraint
++ * == -1 means power param has matched a constraint
++ * > 0 means constraint #n-1 mismatched
++ *
++ * failid == pp id of (a) failed constraint
++ */
++
++ memset(ppconstraint, 0, sizeof(ppconstraint));
++
++ for (i = 0; i < constraints->count; i++) {
++ struct constraint_param *param = &constraints->param[i];
++
++ if (! dpm_md_check_constraint(param, opt)) {
++ if (ppconstraint[param->id] == 0) {
++ failid = param->id;
++ ppconstraint[failid] = i+1;
++ }
++ } else
++ ppconstraint[param->id] = -1;
++ }
++
++ if ((failid >= 0) && (ppconstraint[failid] > 0)) {
++#ifdef CONFIG_DPM_TRACE
++ struct constraint_param *param =
++ &constraints->param[ppconstraint[failid]-1];
++
++ dpm_trace(DPM_TRACE_CONSTRAINT_ASSERTED,
++ param->id, param->min, param->max,
++ opt);
++#endif
++ return 0;
++ }
++
++ return 1;
++}
++
++int dpm_check_constraints(struct dpm_opt *opt)
++{
++ struct list_head * entry;
++ int valid = 1;
++
++ list_for_each(entry,&dpm_constraints) {
++ struct constraints *constraints =
++ list_entry(entry, struct constraints, entry);
++ if (!dpm_check_a_constraint(constraints, opt)) {
++ constraints->violations++;
++ dpm_constraint_rejects++;
++ valid = 0;
++ }
++ }
++
++ return valid;
++}
++
++int dpm_show_opconstraints(struct dpm_opt *opt, char * buf)
++{
++#ifdef CONFIG_PM
++ struct list_head * entry;
++ int len = 0;
++
++ list_for_each_prev(entry,&dpm_list) {
++ struct device * dev = to_device(entry);
++
++ if (!dpm_check_a_constraint(dev->constraints, opt)) {
++ len += sprintf(buf + len, "%s/%s\n", dev->bus->name,
++ dev->bus_id);
++ }
++ }
++
++ return len;
++#else /* CONFIG_PM */
++ return 0;
++#endif /* CONFIG_PM */
++}
++
++#endif /* CONFIG_DPM */
+diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
+index 0344a8a..6aa4cd5 100644
+--- a/drivers/block/Kconfig
++++ b/drivers/block/Kconfig
+@@ -446,4 +446,6 @@ config BLK_DEV_HD
+
+ If unsure, say N.
+
++source "drivers/block/tcc/Kconfig"
++
+ endif # BLK_DEV
+diff --git a/drivers/block/Makefile b/drivers/block/Makefile
+index 204332b..98b42f4 100644
+--- a/drivers/block/Makefile
++++ b/drivers/block/Makefile
+@@ -32,3 +32,6 @@ obj-$(CONFIG_BLK_DEV_UB) += ub.o
+ obj-$(CONFIG_BLK_DEV_HD) += hd.o
+
+ obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o
++
++obj-$(CONFIG_TCC_NAND_V6) += tcc/
++obj-$(CONFIG_TCC_NAND_V7) += tcc/
+diff --git a/drivers/block/tcc/Kconfig b/drivers/block/tcc/Kconfig
+new file mode 100644
+index 0000000..6c3b059
+--- /dev/null
++++ b/drivers/block/tcc/Kconfig
+@@ -0,0 +1,13 @@
++choice
++ prompt "TCC nand flash support"
++ depends on ARCH_TCC
++ default TCC_NAND_V7
++ ---help---
++
++config TCC_NAND_V6
++ tristate "TCC nand flash driver V6"
++
++config TCC_NAND_V7
++ tristate "TCC nand flash driver V7"
++
++endchoice
+diff --git a/drivers/block/tcc/Makefile b/drivers/block/tcc/Makefile
+new file mode 100644
+index 0000000..b3c0814
+--- /dev/null
++++ b/drivers/block/tcc/Makefile
+@@ -0,0 +1,33 @@
++DEF_NAND := -D_LINUX_
++DEF_NAND += -DUSE_V_ADDRESS
++DEF_NAND += -DNAND_INCLUDE
++DEF_NAND += -DNAND_BOOT_INCLUDE
++DEF_NAND += -D_NAND_DEVICE_CONFIG_
++DEF_NAND += -DINTERNAL_HIDDEN_STORAGE_INCLUDE
++DEF_NAND += -DECC_TEST
++
++ifeq ($(CONFIG_ARCH_TCC8900), y)
++DEF_NAND += -DTCC89XX -DTCC89X -DTCC8900
++TCC_ARCH = TCC8900
++endif
++
++ifneq ($(CONFIG_TCC_NAND_V6),)
++NAND_VER := V6005
++obj-$(CONFIG_TCC_NAND_V6) := $(TCC_ARCH)_nand.o
++$(TCC_ARCH)_nand-objs := nand_drv.o nand_io_v6.o
++endif
++
++ifneq ($(CONFIG_TCC_NAND_V7),)
++NAND_VER := V7014
++DEF_NAND += -DNAND_BOOT_REV
++obj-$(CONFIG_TCC_NAND_V7) := $(TCC_ARCH)_nand.o
++$(TCC_ARCH)_nand-objs := nand_drv_v7.o nand_io_v7.o
++endif
++
++NAND_INC = drivers/block/tcc/inc
++EXTRA_CFLAGS += $(DEF_NAND) -I$(NAND_INC) -I$(NAND_INC)/fwdn -I$(NAND_INC)/tnftl
++
++LIBS = libtnftl/libtnftl_$(NAND_VER)_$(TCC_ARCH).o
++
++$(TCC_ARCH)_nand-objs += kernel_nand_drv.o nand_crc.o nand_buffer.o fwupgrade.o init_ddr2.o init_mddr.o $(LIBS)
++
+diff --git a/drivers/block/tcc/fwupgrade.c b/drivers/block/tcc/fwupgrade.c
+new file mode 100644
+index 0000000..e2f6c64
+--- /dev/null
++++ b/drivers/block/tcc/fwupgrade.c
+@@ -0,0 +1,598 @@
++/****************************************************************************
++ * FileName : Fwupgrade.c
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++#if defined(_LINUX_) || defined(_WINCE_)
++#include <mach/globals.h>
++#include "IO_TCCXXX.h"
++#include "TC_File.h"
++#include "browse.h"
++//#include "fwdn_protocol.h"
++#include "fwupgrade.h"
++//#include "usb.h"
++#include "FSAPP.h"
++#include "nand_drv.h"
++#endif
++
++#if defined (NKUSE)
++#include "windows.h"
++#include "stdlib.h"
++#elif defined (__KERNEL__)
++#include <linux/string.h>
++#endif
++
++//unsigned int gMAX_ROMSIZE; //twkwon: Initialize????
++
++#if 0
++const unsigned int CRC32_TABLE[256] = {
++ 0x00000000, 0x90910101, 0x91210201, 0x01B00300,
++ 0x92410401, 0x02D00500, 0x03600600, 0x93F10701,
++ 0x94810801, 0x04100900, 0x05A00A00, 0x95310B01,
++ 0x06C00C00, 0x96510D01, 0x97E10E01, 0x07700F00,
++ 0x99011001, 0x09901100, 0x08201200, 0x98B11301,
++ 0x0B401400, 0x9BD11501, 0x9A611601, 0x0AF01700,
++ 0x0D801800, 0x9D111901, 0x9CA11A01, 0x0C301B00,
++ 0x9FC11C01, 0x0F501D00, 0x0EE01E00, 0x9E711F01,
++ 0x82012001, 0x12902100, 0x13202200, 0x83B12301,
++ 0x10402400, 0x80D12501, 0x81612601, 0x11F02700,
++ 0x16802800, 0x86112901, 0x87A12A01, 0x17302B00,
++ 0x84C12C01, 0x14502D00, 0x15E02E00, 0x85712F01,
++ 0x1B003000, 0x8B913101, 0x8A213201, 0x1AB03300,
++ 0x89413401, 0x19D03500, 0x18603600, 0x88F13701,
++ 0x8F813801, 0x1F103900, 0x1EA03A00, 0x8E313B01,
++ 0x1DC03C00, 0x8D513D01, 0x8CE13E01, 0x1C703F00,
++ 0xB4014001, 0x24904100, 0x25204200, 0xB5B14301,
++ 0x26404400, 0xB6D14501, 0xB7614601, 0x27F04700,
++ 0x20804800, 0xB0114901, 0xB1A14A01, 0x21304B00,
++ 0xB2C14C01, 0x22504D00, 0x23E04E00, 0xB3714F01,
++ 0x2D005000, 0xBD915101, 0xBC215201, 0x2CB05300,
++ 0xBF415401, 0x2FD05500, 0x2E605600, 0xBEF15701,
++ 0xB9815801, 0x29105900, 0x28A05A00, 0xB8315B01,
++ 0x2BC05C00, 0xBB515D01, 0xBAE15E01, 0x2A705F00,
++ 0x36006000, 0xA6916101, 0xA7216201, 0x37B06300,
++ 0xA4416401, 0x34D06500, 0x35606600, 0xA5F16701,
++ 0xA2816801, 0x32106900, 0x33A06A00, 0xA3316B01,
++ 0x30C06C00, 0xA0516D01, 0xA1E16E01, 0x31706F00,
++ 0xAF017001, 0x3F907100, 0x3E207200, 0xAEB17301,
++ 0x3D407400, 0xADD17501, 0xAC617601, 0x3CF07700,
++ 0x3B807800, 0xAB117901, 0xAAA17A01, 0x3A307B00,
++ 0xA9C17C01, 0x39507D00, 0x38E07E00, 0xA8717F01,
++ 0xD8018001, 0x48908100, 0x49208200, 0xD9B18301,
++ 0x4A408400, 0xDAD18501, 0xDB618601, 0x4BF08700,
++ 0x4C808800, 0xDC118901, 0xDDA18A01, 0x4D308B00,
++ 0xDEC18C01, 0x4E508D00, 0x4FE08E00, 0xDF718F01,
++ 0x41009000, 0xD1919101, 0xD0219201, 0x40B09300,
++ 0xD3419401, 0x43D09500, 0x42609600, 0xD2F19701,
++ 0xD5819801, 0x45109900, 0x44A09A00, 0xD4319B01,
++ 0x47C09C00, 0xD7519D01, 0xD6E19E01, 0x46709F00,
++ 0x5A00A000, 0xCA91A101, 0xCB21A201, 0x5BB0A300,
++ 0xC841A401, 0x58D0A500, 0x5960A600, 0xC9F1A701,
++ 0xCE81A801, 0x5E10A900, 0x5FA0AA00, 0xCF31AB01,
++ 0x5CC0AC00, 0xCC51AD01, 0xCDE1AE01, 0x5D70AF00,
++ 0xC301B001, 0x5390B100, 0x5220B200, 0xC2B1B301,
++ 0x5140B400, 0xC1D1B501, 0xC061B601, 0x50F0B700,
++ 0x5780B800, 0xC711B901, 0xC6A1BA01, 0x5630BB00,
++ 0xC5C1BC01, 0x5550BD00, 0x54E0BE00, 0xC471BF01,
++ 0x6C00C000, 0xFC91C101, 0xFD21C201, 0x6DB0C300,
++ 0xFE41C401, 0x6ED0C500, 0x6F60C600, 0xFFF1C701,
++ 0xF881C801, 0x6810C900, 0x69A0CA00, 0xF931CB01,
++ 0x6AC0CC00, 0xFA51CD01, 0xFBE1CE01, 0x6B70CF00,
++ 0xF501D001, 0x6590D100, 0x6420D200, 0xF4B1D301,
++ 0x6740D400, 0xF7D1D501, 0xF661D601, 0x66F0D700,
++ 0x6180D800, 0xF111D901, 0xF0A1DA01, 0x6030DB00,
++ 0xF3C1DC01, 0x6350DD00, 0x62E0DE00, 0xF271DF01,
++ 0xEE01E001, 0x7E90E100, 0x7F20E200, 0xEFB1E301,
++ 0x7C40E400, 0xECD1E501, 0xED61E601, 0x7DF0E700,
++ 0x7A80E800, 0xEA11E901, 0xEBA1EA01, 0x7B30EB00,
++ 0xE8C1EC01, 0x7850ED00, 0x79E0EE00, 0xE971EF01,
++ 0x7700F000, 0xE791F101, 0xE621F201, 0x76B0F300,
++ 0xE541F401, 0x75D0F500, 0x7460F600, 0xE4F1F701,
++ 0xE381F801, 0x7310F900, 0x72A0FA00, 0xE231FB01,
++ 0x71C0FC00, 0xE151FD01, 0xE0E1FE01, 0x7070FF00
++};
++#else
++extern const unsigned CRC32_TABLE[];
++#endif
++
++typedef void ROM_Upgrade(unsigned char *, unsigned int, unsigned int, unsigned char *);
++ROM_Upgrade *pROMUpgradeFunc;
++
++extern int TCDB_SaveDBHeader(unsigned char ucAssociation, int iPartID);
++extern void ResetSystem(void);
++
++
++#define MAXBUFFSIZE 16*1024 //
++
++extern int gSDUpgrading;
++
++unsigned char gBuffer[MAXBUFFSIZE];
++
++#if defined(_WINCE_) || defined(_LINUX_)
++///////////////////////////////////////////////////////////////////////////////////
++//
++// Function : FWUG_GetTempBuffer()
++//
++// Description : Get temporary buffer to store data
++//
++///////////////////////////////////////////////////////////////////////////////////
++char *FWUG_GetTempBuffer(unsigned int *uiBufSize)
++{
++#if defined (NKUSE) || defined(__KERNEL__)
++ *uiBufSize = MAXBUFFSIZE;
++ return gBuffer;
++#else
++ if (gSDUpgrading == 1)
++ {
++ *uiBufSize = MAXBUFFSIZE;
++ return gBuffer;
++ }
++ else
++ {
++ *uiBufSize = FSAPP_GetMaxCopySize();
++ return FSAPP_GetFileBuffer();
++ }
++#endif
++}
++
++///////////////////////////////////////////////////////////////////////////////////
++//
++// Function : FWUG_CheckBattery
++//
++// Description : Check Battery
++//
++///////////////////////////////////////////////////////////////////////////////////
++int FWUG_CheckBattery(void)
++{
++#ifdef BATTERY_INCLUDE
++ unsigned int batteryValue = 0;
++ unsigned int Emergencycount = 0;
++ int i;
++
++ for(i=0; i<20; i++)
++ {
++ batteryValue = BATTERY_GetBatteryVoltage();
++ if(batteryValue < 110)
++ Emergencycount++;
++
++ if(Emergencycount > 10)
++ {
++ SerialWriteString("BAT too low!!");
++ CAPP_ReturnSetClock(); // 20041207
++ return 0;
++ }
++
++ TC_TimeDly(10);
++ }
++#endif
++ return 1;
++}
++
++#if !defined(__KERNEL__)
++/**************************************************************************
++* FUNCTION NAME :
++* unsigned int FWUG_CheckROMFileCRC
++*
++* DESCRIPTION :
++* INPUT:
++*
++* OUTPUT:
++*
++* REMARK :
++**************************************************************************/
++unsigned int FWUG_CheckROMFileCRC(int iFilehandle, unsigned char *buf, unsigned int uiBufSize)
++{
++ unsigned int i;
++ unsigned int uiROMFileSize;
++ unsigned int uiVerifyCRC;
++ unsigned int uiTempCRC;
++ unsigned int uiCRCSize;
++ unsigned int uiCnt;
++ unsigned int uiMode;
++
++ uiROMFileSize = 0x00;
++ uiVerifyCRC = 0x00;
++ uiTempCRC = 0x00;
++
++ memset( buf, 0x00, uiBufSize );
++ TC_Read( iFilehandle, buf, 32 ); //header size
++
++ uiTempCRC |= ( buf[27] & 0x000000FF) << 24;
++ uiTempCRC |= ( buf[26] & 0x000000FF) << 16;
++ uiTempCRC |= ( buf[25] & 0x000000FF) << 8;
++ uiTempCRC |= ( buf[24] & 0x000000FF) ;
++
++ uiROMFileSize |= ( buf[31] & 0x000000FF) << 24;
++ uiROMFileSize |= ( buf[30] & 0x000000FF) << 16;
++ uiROMFileSize |= ( buf[29] & 0x000000FF) << 8;
++ uiROMFileSize |= ( buf[28] & 0x000000FF) ;
++
++ TC_Seek( iFilehandle, 0, TC_SEEK_SET );
++
++ if (uiBufSize < uiROMFileSize )
++ {
++ uiCnt = ( uiROMFileSize + ( uiBufSize - 1)) / uiBufSize;
++ for ( i = 0; i < uiCnt ; i++ )
++ {
++ if ( i == (uiCnt -1 ))
++ uiCRCSize = ( uiROMFileSize - uiBufSize * (uiCnt - 1));
++ else
++ uiCRCSize = uiBufSize;
++
++ TC_Read( iFilehandle, buf, uiCRCSize );
++
++ if ( i == 0 )
++ uiMode = 1;
++ else
++ uiMode = 2;
++
++ uiVerifyCRC = CalCRC_ROMFile(buf, uiCRCSize, uiVerifyCRC, uiMode);
++
++ }
++ }
++ else
++ {
++ TC_Read( iFilehandle, buf, uiROMFileSize );
++
++ uiMode = 1;
++ uiVerifyCRC = CalCRC_ROMFile( buf, uiROMFileSize, uiVerifyCRC, uiMode);
++ }
++
++ TC_Seek( iFilehandle, 0, TC_SEEK_SET );
++
++ if ( uiTempCRC != uiVerifyCRC )
++ return 1;
++ else
++ return SUCCESS;
++}
++#endif
++
++///////////////////////////////////////////////////////////////////////////////////
++//
++// Function : FWUG_MainFunc
++//
++// Description : Main function to upgrade Firmware
++//
++///////////////////////////////////////////////////////////////////////////////////
++#if !defined(__KERNEL__)
++int FWUG_MainFunc(int hFile, int iFileSize)
++#else
++/* if Linux Kernel */
++int FWUG_MainFunc(char *rom_buf, unsigned int uiROMFileSize)
++#endif
++{
++ unsigned int iRev;
++ unsigned int uiBufSize;
++ unsigned char *buf;
++
++ unsigned int i;
++ unsigned int uRemainSize, uReadSize;
++ unsigned int dwBlockOffSet, dwPageOffSet;
++ unsigned int nStBlockOffSet, nStPageOffSet;
++ unsigned char GMC_Num;
++ unsigned char FlagofNewSizeBigger;
++ unsigned int nSecureMode = DISABLE;
++
++#if !defined(__KERNEL__)
++ unsigned int uiROMFileSize;
++ unsigned int iFilehandle;
++ #if defined(NKUSE)
++ iFilehandle = TC_Open((char*)hFile, NULL, NULL, NULL);
++#else
++ iFilehandle = hFile;
++ #endif
++#else
++ unsigned int rom_offset;
++#endif
++
++ //===============================================================
++ // Check condition for FW Upgrade
++ //===============================================================
++ if((buf = FWUG_GetTempBuffer(&uiBufSize))==0)
++ {
++ return ERR_FWUG_NOT_EXISTMEMORY;
++ }
++
++#if !defined(__KERNEL__)
++/* if Linux Kernel, already crc checked in tccbox */
++ iRev = FWUG_CheckROMFileCRC( iFilehandle, buf, uiBufSize );
++ if ( iRev != SUCCESS )
++ {
++ return -1;
++ }
++#endif
++
++ if(!FWUG_CheckBattery())
++ {
++ return ERR_FWUG_FAIL_BATCHECK;
++ }
++
++ //===============================================================
++ // UPGRADE - NANDFLASH
++ //===============================================================
++
++ /* Setting Intial Parameters */
++#if !defined(__KERNEL__)
++ uiROMFileSize = TC_Length(iFilehandle);
++#endif
++
++ #ifdef TNFTL_V7_INCLUDE
++ FWUG_NAND_SetEnableNandBootOnlyMode( ENABLE );
++ FWUG_NAND_SetNBAreaEndPBAdd(TNFTL_MAX_BLOCK_NUM_OF_NBAREA); // Physical Block Num
++ #endif
++
++ #if defined(FWUG_V2_INCLUDE)
++ nSecureMode = FWUG_NAND_GetFlagOfUseSecureMode();
++ #endif
++
++ /* PreProcess before write code */
++ if (( iRev = FWUG_NAND_PreProcess( uiROMFileSize, &FlagofNewSizeBigger )) != SUCCESS )
++ {
++ goto FWUG_FAIL;
++ }
++
++
++ /* Write CODE Data */
++ for ( i = 0 ; i < 2; ++i )
++ {
++ uRemainSize = uiROMFileSize;
++#if !defined(__KERNEL__)
++ TC_Seek( iFilehandle, 0, TC_SEEK_SET );
++#else
++ rom_offset = 0;
++#endif
++
++ if ( FlagofNewSizeBigger == TRUE )
++ GMC_Num = ( i == 0 ) ? FIRST : SECOND;
++ else
++ GMC_Num = ( i == 0 ) ? SECOND : FIRST;
++
++ #if defined(FWUG_V1_INCLUDE)
++ if (( iRev = FWUG_NAND_WriteCodePreProcess( GMC_Num, uiROMFileSize, &nStBlockOffSet, &nStPageOffSet )) != SUCCESS )
++ #elif defined(FWUG_V2_INCLUDE)
++ if (( iRev = FWUG_NAND_WriteCodePreProcess( GMC_Num, uiROMFileSize, &nStBlockOffSet, &nStPageOffSet, nSecureMode )) != SUCCESS )
++ #endif
++ {
++ goto FWUG_FAIL;
++ }
++
++ while ((int)uRemainSize > 0)
++ {
++ uReadSize = ( uRemainSize >= uiBufSize ) ? uiBufSize : uRemainSize;
++#if !defined(__KERNEL__)
++ uReadSize = TC_Read( iFilehandle, buf, uReadSize );
++#else
++ memcpy(buf, rom_buf + rom_offset, uReadSize);
++ rom_offset += uReadSize;
++#endif
++
++#ifdef TNFTL_V7_INCLUDE
++ if (( iRev = FWUG_NAND_WriteCodeNAND( GMC_Num, nStBlockOffSet, nStPageOffSet, buf, uReadSize, &dwBlockOffSet, &dwPageOffSet, nSecureMode )) != SUCCESS )
++#else
++ if (( iRev = FWUG_NAND_WriteCodeNAND( nStBlockOffSet, nStPageOffSet, buf, uReadSize, &dwBlockOffSet, &dwPageOffSet, nSecureMode )) != SUCCESS )
++#endif
++ {
++ goto FWUG_FAIL;
++ }
++ nStBlockOffSet = dwBlockOffSet;
++ nStPageOffSet = dwPageOffSet;
++ uRemainSize -= uReadSize;
++ }
++
++ if (( iRev = FWUG_NAND_WriteCodePostProcess( GMC_Num, nStBlockOffSet, nStPageOffSet )) != SUCCESS )
++ {
++ goto FWUG_FAIL;
++ }
++ }
++
++ /* PostProcess after write code */
++ if (( iRev = FWUG_NAND_PostProcess((void*)0, TRUE, nSecureMode )) != SUCCESS )
++ {
++ goto FWUG_FAIL;
++ }
++
++ //===============================================================
++ // CLOSE
++ //===============================================================
++#if !defined(__KERNEL__)
++#if defined(NKUSE)
++ TC_Close(iFilehandle);
++#endif
++#endif
++
++ if (TC_ISERR(iRev))
++ {
++ return -1;
++ }
++
++ return SUCCESS;
++
++FWUG_FAIL:
++ return iRev;
++}
++
++#endif
++
++/**************************************************************************
++* FUNCTION NAME :
++* unsigned int FWUG_CalcCrc(unsigned int *base, unsigned int length, unsigned int *crctable);
++*
++* DESCRIPTION :
++* INPUT:
++* base =
++* crctable =
++* length =
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++unsigned int FWUG_CalcCrc(unsigned int *base, unsigned int length, const unsigned int *crctable)
++{
++ unsigned int crcout = 0;
++ unsigned int cnt, i, code, tmp;
++
++ for(cnt=0; cnt<length; cnt++)
++ {
++ code = base[cnt];
++ for(i=0; i<4; i++)
++ {
++ tmp = code^crcout;
++ crcout = (crcout>>8)^crctable[tmp&0xFF];
++ code = code >> 8;
++ }
++ }
++ return crcout;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* unsigned int FWUG_CalcCrc8(unsigned char *base, unsigned int length, unsigned int *crctable);
++*
++* DESCRIPTION :
++* INPUT:
++* base =
++* crctable =
++* length =
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++unsigned int FWUG_CalcCrc8(unsigned char *base, unsigned int length, const unsigned int *crctable)
++{
++ unsigned int crcout = 0;
++ unsigned int cnt;
++ unsigned char code, tmp;
++
++ for(cnt=0; cnt<length; cnt++)
++ {
++ code = base[cnt];
++ tmp = code^crcout;
++ crcout = (crcout>>8)^crctable[tmp&0xFF];
++ }
++ return crcout;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* unsigned int FWUG_CalcCrcI(unsigned uCRCIN, unsigned *base, unsigned int length, unsigned int *crctable);
++*
++* DESCRIPTION :
++* INPUT:
++* base =
++* crctable =
++* length =
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++unsigned int FWUG_CalcCrcI(unsigned uCRCIN, unsigned *base, unsigned int length, const unsigned int *crctable)
++{
++ unsigned int crcout = uCRCIN;
++ unsigned int cnt, i, code, tmp;
++
++ for(cnt=0; cnt<length; cnt++)
++ {
++ code = base[cnt];
++ for(i=0; i<4; i++)
++ {
++ tmp = code^crcout;
++ crcout = (crcout>>8)^crctable[tmp&0xFF];
++ code = code >> 8;
++ }
++ }
++ return crcout;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* unsigned int FWUG_CalcCrc8I(unsigned uCRCIN, unsigned char *base, unsigned int length, unsigned int *crctable);
++*
++* DESCRIPTION :
++* INPUT:
++* base =
++* crctable =
++* length =
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++unsigned int FWUG_CalcCrc8I(unsigned uCRCIN, unsigned char *base, unsigned int length, const unsigned int *crctable)
++{
++ unsigned int crcout = uCRCIN;
++ unsigned int cnt;
++ unsigned char code, tmp;
++
++ for(cnt=0; cnt<length; cnt++)
++ {
++ code = base[cnt];
++ tmp = code^crcout;
++ crcout = (crcout>>8)^crctable[tmp&0xFF];
++ }
++ return crcout;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* unsigned int CalCRC_ROMFile(unsigned int *pBuffer,unsigned int size,unsigned int crcout, unsigned int mode);
++*
++* DESCRIPTION :
++* INPUT:
++* crcout =
++* mode =
++* pBuffer =
++* size =
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++unsigned int CalCRC_ROMFile(unsigned int *pBuffer,unsigned int size,unsigned int crcout, unsigned int mode)
++{
++
++ unsigned int cnt, i, code, tmp;
++ unsigned int CrcRegion;
++
++
++ CrcRegion = (size>>2);
++
++ for(cnt=0; cnt<CrcRegion; cnt++)
++ {
++ code = pBuffer[cnt];
++ if(mode==0 || mode==1)
++ {
++ if(cnt == 4 || cnt == 5)
++ {
++ continue;
++ }
++ }
++ if(mode==1)
++ {
++ if(cnt==6)
++ {
++ code = 0x00000000;
++ }
++ }
++
++
++ for(i=0; i<4; i++)
++ {
++ tmp = code^crcout;
++ crcout = (crcout>>8)^CRC32_TABLE[tmp&0xFF];
++ code = code >> 8;
++ }
++ }
++
++ return crcout;
++}
++
++/************* end of file *************************************************************/
+diff --git a/drivers/block/tcc/inc/common.h b/drivers/block/tcc/inc/common.h
+new file mode 100644
+index 0000000..d15bfd8
+--- /dev/null
++++ b/drivers/block/tcc/inc/common.h
+@@ -0,0 +1,23 @@
++#ifndef __COMMON_H__
++#define __COMMON_H__
++
++#include <config.h>
++
++#if defined(TCC8900)
++#include <mach/TCC89x_Physical.h>
++#include <mach/TCC89x_Structures.h>
++#else
++#error "Not defined Chips..."
++#endif
++
++#include <mach/globals.h>
++
++/*
++ * Macro
++ */
++#define read_reg(a) (*(volatile unsigned long *)a)
++#define write_reg(v, a) (*(volatile unsigned long *)a = v)
++
++
++#endif /* __COMMON_H__ */
++
+diff --git a/drivers/block/tcc/inc/config.h b/drivers/block/tcc/inc/config.h
+new file mode 100644
+index 0000000..fd48ceb
+--- /dev/null
++++ b/drivers/block/tcc/inc/config.h
+@@ -0,0 +1,56 @@
++/***************************************************************************************
++* FileName : config.h
++* Description : NAND Configuration File
++****************************************************************************************
++*
++* TCC Board Support Package
++* Copyright (c) Telechips, Inc.
++* ALL RIGHTS RESERVED
++*
++****************************************************************************************/
++
++
++#ifndef __CONFIG_H__
++#define __CONFIG_H__
++
++#include <def_tcc.h>
++#include <mach/ddr.h>
++
++/***************************************************************************************
++* TCC8900 specific config
++****************************************************************************************/
++#if defined(TCC8900)
++
++#define TCC_ARCH "TCC8900"
++
++#if defined(_BOARD_VERSION_TCC8900_WINCE_LINUX_DEMO_V01_)
++#define TCC_BOARD "TCC8900_WINCE_LINUX_DEMO_V0.1"
++#endif
++
++/***************************************************************************************
++* ERROR: Undefined target
++****************************************************************************************/
++#else
++ #error "Undefined Target"
++#endif
++
++
++/***************************************************************************************
++* ETC.
++****************************************************************************************/
++/*---------------------------------
++ * DRIVER TYPE
++ *---------------------------------
++ */
++#define KERNEL_DRIVER /* kernel module driver */
++
++
++/*---------------------------------
++ * Default
++ *---------------------------------
++ */
++#define PRINTF printk
++
++
++#endif /* __CONFIG_H__ */
++/************* end of file *************************************************************/
+diff --git a/drivers/block/tcc/inc/def_tcc.h b/drivers/block/tcc/inc/def_tcc.h
+new file mode 100644
+index 0000000..b22123f
+--- /dev/null
++++ b/drivers/block/tcc/inc/def_tcc.h
+@@ -0,0 +1,6 @@
++#ifdef NAND_BOOT_REV
++#define NAND_VER "V7014"
++#else
++#define NAND_VER "V6005"
++#endif
++
+diff --git a/drivers/block/tcc/inc/fwdn/Disk.h b/drivers/block/tcc/inc/fwdn/Disk.h
+new file mode 100644
+index 0000000..5bdff47
+--- /dev/null
++++ b/drivers/block/tcc/inc/fwdn/Disk.h
+@@ -0,0 +1,314 @@
++/****************************************************************************
++ * FileName : Disk.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#ifndef __DISK_H__
++#define __DISK_H__
++
++/*******************************************************************************
++ * DISK Interface Error Code Macro
++ ******************************************************************************/
++#define _ERR(x) (0x80000000 | (x))
++#define ENOTSUPPORT _ERR(0x10) // Function does not support
++#define EINITFAIL _ERR(0x11) // Device Initialization Failed
++
++/*****************************************************************************
++ * disk device type enumeration value
++ *****************************************************************************/
++typedef enum
++{
++ DISK_DEVICE_HDD=0,
++ DISK_DEVICE_NAND,
++ DISK_DEVICE_NAND_HD,
++ DISK_DEVICE_UHP,
++ DISK_DEVICE_TRIFLASH,
++ DISK_DEVICE_MMC,
++ DISK_DEVICE_MS,
++ DISK_DEVICE_TRIFLASH_HD,
++ #ifdef EXTERNAL_HIDDEN_STORAGE_INCLUDE
++ DISK_DEVICE_MMC_HD,
++ #endif
++ MAX_DEVICE_NUM
++}DISK_DEVICE;
++
++#define DISK_DEVICE_INTERNAL 1
++
++/*****************************************************************************
++ * disk device property and sub-property enumeration value
++ *****************************************************************************/
++typedef enum
++{
++ DISK_DEVICE_UNLOCK=0,
++ DISK_DEVICE_LOCK
++}DISK_LOCK_FLAG;
++
++typedef enum
++{
++ DISK_STATE_NOTMOUNTED,
++ DISK_STATE_MOUNTSUCCEED,
++ DISK_STATE_MOUNTERR
++}DISK_MOUNT_STATE;
++
++typedef enum
++{
++ DISK_STATE_FREE,
++ DISK_STATE_BUSY
++}DISK_BUSY_STATE;
++
++typedef enum
++{
++ DISK_STATE_INIT,
++ DISK_STATE_POWERON,
++ DISK_STATE_POWEROFF,
++ DISK_STATE_STANDBY,
++ DISK_STATE_IDLE,
++ DISK_STATE_SLEEP,
++ DISK_STATE_RESET
++}DISK_POWER_STATE;
++
++typedef enum
++{
++ DISK_MSC_DRV_NOT_SUPPORT,
++ DISK_MSC_DRV_SUPPORT
++}DISK_MSC_DRV_STATE;
++
++typedef enum
++{
++ DISK_MOUNT_TYPE_INTERNAL,
++ DISK_MOUNT_TYPE_EXTERNAL,
++ DISK_MOUNT_TYPE_MAXIUM
++}DISK_MOUNT_TYPE_STATE;
++
++typedef struct
++{
++ const char *Name;
++ DISK_LOCK_FLAG LockFlag;
++ DISK_DEVICE DiskType;
++ DISK_MOUNT_STATE MountState;
++ DISK_BUSY_STATE BusyState;
++ DISK_MSC_DRV_STATE MSCDrvSupport;
++ DISK_MOUNT_TYPE_STATE DrvMountType;
++ int PartitionIndex;
++}DISK_PROPERTY;
++
++/*******************************************************************************
++ * DISK Interface Function Type Definitions
++ ******************************************************************************/
++typedef int (*tDeviceRwFunctions)(int, unsigned long, unsigned short, void *);
++
++typedef int (*tDeviceWriteMultiStartFunctions)(unsigned long, unsigned long);
++typedef int (*tDeviceWriteMultiFunctions)(int, unsigned long, unsigned short, void *);
++typedef int (*tDeviceWriteMultiStopFunctions)(void);
++
++typedef int (*tDeviceReadMultiStartFunctions)(unsigned long, unsigned long);
++typedef int (*tDeviceReadMultiFunctions)(int, unsigned long, unsigned short, void *);
++typedef int (*tDeviceReadMultiStopFunctions)(void);
++
++typedef unsigned long (*tDeviceHiddenRWFunctions)(unsigned long , unsigned short, unsigned char *);
++typedef int (*tDeviceHiddenClearPageFunctions)(unsigned long , unsigned long);
++
++typedef int (*tDeviceIoctlFunctions)(int, void *);
++
++/*******************************************************************************
++ * DISK Interface Function Definitions
++ ******************************************************************************/
++typedef struct DeviceDriverStruct
++{
++ DISK_PROPERTY Property;
++ tDeviceRwFunctions ReadSector;
++ tDeviceRwFunctions WriteSector;
++ tDeviceReadMultiStartFunctions ReadMultiStart;
++ tDeviceReadMultiFunctions ReadMultiSector;
++ tDeviceReadMultiStopFunctions ReadMultiStop;
++ tDeviceWriteMultiStartFunctions WriteMultiStart;
++ tDeviceWriteMultiFunctions WriteMultiSector;
++ tDeviceWriteMultiStopFunctions WriteMultiStop;
++ tDeviceHiddenRWFunctions HDReadSector;
++ tDeviceHiddenRWFunctions HDWriteSector;
++ tDeviceHiddenClearPageFunctions HDClearSector;
++ tDeviceIoctlFunctions Ioctl;
++}tDeviceDriver;
++
++/*******************************************************************************
++ * DISK Ioctl Function List ( Enumeration Value )
++ *
++ * DEV_INITIALIZE
++ * Initialize Variable , Register and Hardware
++ *
++ * DEV_GET_DISKINFO
++ * Get the environmant variables like head, cylinder, sector ...
++ *
++ * DEV_FORMAT_DISK
++ * low level format command ( if it necessary )
++ *
++ * DEV_ERASE_INIT
++ * prepare erasing command
++ *
++ * DEV_ERASE_BLOCK
++ * erase sector command
++ *
++ * DEV_ERASE_CLOSE
++ * finish erasing command
++ *
++ * DEV_WRITEBACK_ON_IDLE
++ * flush data cache command while system is in idle state
++ ******************************************************************************/
++
++#define YES 1
++#define NO 0
++
++#define TC_LOWLEVEL_YES 1
++#define TC_LOWLEVEL_NO 0
++
++/*******************************************************************************
++ * DISK Ioctl DEV_GET_DISKINFO Function Parameter structure
++ ******************************************************************************/
++typedef struct ioctl_diskinfo_t
++{
++ unsigned short head;
++ unsigned short cylinder;
++ unsigned short sector;
++ unsigned short sector_size;
++ unsigned int Total_sectors;
++}ioctl_diskinfo_t;
++
++/*******************************************************************************
++ * DISK Ioctl DEV_ERASE_INIT Function Parameter structure
++ ******************************************************************************/
++typedef struct ioctl_diskeraseinit_t
++{
++ unsigned short sector_per_cluster;
++ unsigned long data_start_sector;
++}ioctl_diskeraseinit_t;
++
++/*******************************************************************************
++ * DISK Ioctl DEV_ERASE_BLOCK Function Parameter structure
++ ******************************************************************************/
++typedef struct ioctl_diskerase_t
++{
++ unsigned long current_cluster;
++ unsigned long content_fat;
++}ioctl_diskerase_t;
++
++/*******************************************************************************
++ * DISK Ioctl DEV_HIDDEN_CLEAR_PAGE Function Parameter structure
++ ******************************************************************************/
++// typedef struct ioctl_diskhdclear_t {
++// unsigned long start_page;
++// unsigned long end_page;
++// }ioctl_diskhdclear_t;
++
++/*******************************************************************************
++ * DISK Ioctl DEV_HIDDEN_READ/WRITE_PAGE Function Parameter structure
++ ******************************************************************************/
++typedef struct ioctl_diskhdread4_t
++{
++ unsigned long start_page;
++ unsigned long page_offset;
++ unsigned long read_size;
++ unsigned char *buff;
++}ioctl_diskhdread4_t;
++
++/*******************************************************************************
++ * DISK Ioctl DEV_BOOTCODE_READ/WRITE_PAGE Function Parameter structure
++ ******************************************************************************/
++typedef struct ioctl_diskrwpage_t
++{
++ unsigned long start_page;
++ unsigned long rw_size;
++ unsigned char *buff;
++}ioctl_diskrwpage_t;
++
++
++
++
++/*******************************************************************************
++ * DISK Interface Function Definitions
++ ******************************************************************************/
++
++int DISK_FindDisk(int drv_type);
++int DISK_ReadSector(int drv_type, int lun, unsigned long lba_addr, unsigned short nSector, void *buff);
++int DISK_WriteSector(int drv_type, int lun, unsigned long lba_addr, unsigned short nSector, void *buff);
++
++int DISK_ReadMultiStart(int drv_type, int lba_addr, int size);
++int DISK_ReadMultiSector(int drv_type, int lun, unsigned long lba_addr, unsigned short nSector, void *buff);
++int DISK_ReadMultiStop(int drv_type);
++
++int DISK_WriteMultiStart(int drv_type, int lba_addr, int size);
++int DISK_WriteMultiSector(int drv_type, int lun, unsigned long lba_addr, unsigned short nSector, void *buff);
++int DISK_WriteMultiStop(int drv_type);
++
++int DISK_HDReadSector(unsigned int drv_type, unsigned long page_addr, unsigned short count, unsigned char *buff);
++int DISK_HDWriteSector(unsigned int drv_type, unsigned long page_addr, unsigned short count, unsigned char *buff);
++int DISK_HDClearSector(unsigned int drv_type, unsigned long start_page_addr, unsigned long end_page_addr);
++
++int DISK_Ioctl(unsigned int drv_type, int function, void *param);
++int DISK_GetTotalDiskCount(void);
++int DISK_GetDiskType(int index);
++int DISK_GetDiskTypeByPartID(int PartID );
++int DISK_GetSupportMSCDrive(int index );
++int DISK_GetDiskMountType(int index );
++int DISK_SetState(DISK_DEVICE disk, DISK_MOUNT_STATE state);
++int DISK_GetState(DISK_DEVICE disk);
++int DISK_SetDiskPartitionIndex(DISK_DEVICE disk, int index);
++int DISK_GetDiskPartitionIndex(DISK_DEVICE disk);
++int DISK_SetBusyState(DISK_DEVICE disk, DISK_BUSY_STATE busyFlag);
++int DISK_GetBusyState(DISK_DEVICE disk);
++
++extern unsigned char *DISK_GetDeviceName(DISK_DEVICE disk);
++extern unsigned int DISK_GetDeviceStatus(int iDeviceNum,int iUSBMode,int iExtDevice);
++
++
++/*******************************************************************************
++ * DISK List Array pre-definition ( in disk.c)
++ ******************************************************************************/
++extern tDeviceDriver DiskList[];
++extern const unsigned int DISK_DefaultDriveType;
++
++typedef enum
++{
++ /* Do Not Change below functions*/
++ DEV_INITIALIZE = 0,
++ DEV_MOUNT,
++ DEV_GET_DISKINFO,
++ DEV_FORMAT_DISK,
++ DEV_ERASE_INIT,
++ DEV_ERASE_BLOCK,
++ DEV_ERASE_CLOSE,
++ DEV_WRITEBACK_ON_IDLE,
++ /* You can add new function from here */
++ DEV_HIDDEN_READ_PAGE_4,
++ DEV_GET_MAXMULTISECTOR,
++ DEV_SET_POWER,
++ DEV_GET_POWER,
++ DEV_BOOTCODE_READ_PAGE,
++ DEV_BOOTCODE_WRITE_PAGE,
++ DEV_SERIAL_PROCESS,
++ DEV_GET_MAX_SECTOR_PER_BLOCK,
++ DEV_GET_INSERTED,
++ DEV_GET_INITED,
++ DEV_GET_WRITE_PROTECT,
++ DEV_SET_REMOVED,
++ DEV_GET_PREV_STATUS,
++ DEV_GET_PLAYABLE_STATUS,
++ DEV_STOP_TRANSFER,
++ DEV_TELL_DATASTARTSECTOR,
++ DEV_CHECK_CRC_NANDBOOT_IMAGE_ROM,
++ DEV_GET_HIDDEN_SIZE,
++ DEV_GET_SUPPORT_FAT_FORMAT, /* [1429] */
++ DEV_FORCE_FLUSH_CACHE_DATA,
++ DEV_SET_ALIGEN_CACHE,
++ DEV_SET_MULTISECTOR, // twkwon: Han DR
++ DEV_SET_HIDDEN_SIZE,
++ DEV_END_OF_FUNCTION
++}IOCTL_FUNCTIONS;
++
++#endif // __DISK_H__
++/* end of file */
++
+diff --git a/drivers/block/tcc/inc/fwdn/FSAPP.h b/drivers/block/tcc/inc/fwdn/FSAPP.h
+new file mode 100644
+index 0000000..285c387
+--- /dev/null
++++ b/drivers/block/tcc/inc/fwdn/FSAPP.h
+@@ -0,0 +1,130 @@
++/*****************************************************************************/
++// File System refer for K-FileSystem
++// FSAPP.C
++// Copyright 2003 Telechips, Inc.
++//
++// 2004. 06. 4
++/*****************************************************************************/
++#ifndef __FSAPP_H__
++#define __FSAPP_H__
++
++#if defined(_LINUX_)
++#include <fwdn/file.h>
++#include <fwdn/Disk.h>
++#elif defined(_WINCE_)
++#include "file.h"
++#include "Disk.h"
++#endif
++
++#ifndef CLEAR
++#define CLEAR 0
++#endif
++#ifndef DIRTY
++#define DIRTY 1
++#endif
++
++//=============================================================================
++//*
++//*
++//* [ EXTERNAL DEFINATION ]
++//*
++//*
++//=============================================================================
++#define _NOTMUSICFILE -1
++// DEFINITION FOR MAXIMUM HANDLE OF FILES OR DIRECTORIES
++#define MAX_HANDLE 5
++#define MAX_FD MAX_HANDLE
++#define MAX_DIR 2
++// DEFAULT FILE FORMAT
++#define DEFAULT_ROOT_ENTRY_COUNT 512 // normal number of the root entry count
++#define HIDDEN_SIZE 31 // NAND, UFD etc... But NOT HDD
++
++#define ENTRY_SIZE 32 // 1 entry size [byte]
++#define ENTRY_CHUNK 11
++#define ENTRY_BUFFER_SIZE (ENTRY_CHUNK * ENTRY_SIZE)
++
++#define FSAPP_MAX_PART_NUMBER 10 //driveInfo[FSAPP_MAX_PART_NUMBER] / physicalDrvType[FSAPP_MAX_PART_NUMBER]
++
++//=============================================================================
++//*
++//*
++//* [ EXTERNAL VARIABLE DEFINE ]
++//*
++//*
++//=============================================================================
++
++extern int totalHdlr;
++extern int gDiskIdleTime;
++
++extern FDstruc fd[MAX_FD];
++extern HANDLERstruc fhandler[MAX_HANDLE];
++extern FDIRENTstruc fdir[MAX_DIR];
++extern unsigned char physicalDrvType[FSAPP_MAX_PART_NUMBER];
++
++//=============================================================================
++//*
++//*
++//* [ FUCTIONS DEFINE ]
++//*
++//*
++//=============================================================================
++extern void FAT_InitDriveInfo( void );
++extern int FAT_InitFS( void );
++extern void FAT_InitVariable( void );
++extern int FAT_MountDrive(int drvTypeID, unsigned int lun);
++extern int FAT_UnmountDrive(int drvTypeID);
++extern void FAT_InitializeForFlexibility(unsigned char valueOfHandle, unsigned char *entryBufferPointer, HANDLERstruc *fhandlerStruc,
++ unsigned char valueOfFd, FDstruc *fdStruc, unsigned char valueOfDir, FDIRENTstruc *fdirStruc);
++
++extern int FSAPP_InitDiskDevice( int DeviceID );
++extern int FSAPP_GetMaxCopySize( void );
++extern unsigned char *FSAPP_GetFileBuffer( void );
++extern void FSAPP_InitializeFS( void );
++extern unsigned long FSAPP_GetDiskSector( unsigned char drvType, DISKINFOstruc *disk );
++
++extern int FSAPP_Get_part_id(unsigned char drvType, unsigned char mount);
++
++extern int FSAPP_disk_RWsector(int drvTypeID, unsigned char drv_num,unsigned long LBA_addr, unsigned short nSector, void *buff, unsigned char RWflag);
++extern int FSAPP_diskIoctl_DEV_GET_MAXMULTISECTOR(int drvTypeID, unsigned short *nSector);
++extern int FSAPP_diskIoctl_DEV_ERASE_INIT(int drvTypeID, unsigned char secPerClus, unsigned long dataStartSec);
++extern int FSAPP_diskIoctl_DEV_ERASE_BLOCK(int drvTypeID, unsigned long currCluster, unsigned long contentFAT);
++extern int FSAPP_diskIoctl_DEV_ERASE_CLOSE(int drvTypeID);
++extern int FSAPP_diskIoctl_DEV_SET_MULTISECTOR(int drvTypeID, unsigned short *max_multi_sector);
++extern int FSAPP_diskIoctl_DEV_TELL_DATASTARTSECTOR(int drvTypeID, unsigned long int data_start_sector);
++extern int FSAPP_diskIoctl_DEV_GET_MAX_SECTOR_PER_BLOCK(int drvTypeID, unsigned short int *SpB);
++extern int FSAPP_diskIoctl_DEV_STOP_TRANSFER(int drvTypeID);
++
++extern int FSAPP_DISK_WriteMultiStart(int drvTypeID, int lba_addr, int size);
++extern int FSAPP_DISK_WriteMultiSector(int drvTypeID, int lun, unsigned long lba_addr, unsigned short nSector, void *buff);
++extern int FSAPP_DISK_ReadMultiStart(int drvTypeID, int lba_addr, int size);
++extern int FSAPP_DISK_ReadMultiSector(int drvTypeID, int lun, unsigned long lba_addr, unsigned short nSector, void *buff);
++extern int FSAPP_DISK_ReadMultiStop(int drvTypeID);
++extern int FSAPP_DISK_WriteMultiStop(int drvTypeID);
++
++extern int FSAPP_physicalStorage_HDD(int drvTypeID);
++
++extern int FSAPP_ReadSector_Common(int drvTypeID, int lun, unsigned long lba_addr, unsigned short nSector, void *buff);
++extern int FSAPP_WriteSector_Common(int drvTypeID, int lun, unsigned long lba_addr, unsigned short nSector, void *buff, unsigned char FormatFlag);
++
++extern int FSAPP_getUsedClus_PS(int drvTypeID, int partID, unsigned FAT1_PhySector, unsigned short nSector);
++extern int FSAPP_cleanFATcache_PS(int drvTypeID, int partID, unsigned long FAT2_PhySector, unsigned long FAT_Sector, unsigned char *sbuffer);
++extern int FSAPP_changeFATcache_PS(int drvTypeID, int partID, unsigned long FAT1_PhySector, unsigned int Offset_Sector, unsigned char *fatBuff);
++extern int FSAPP_fatWriteClus_PS(int drvTypeID, unsigned short nCount, unsigned long sector_addr, unsigned short nSector, unsigned short multi_sector, int multi_byte, unsigned char *temp_buff);
++extern unsigned int FSAPP_FormatClear_PS(int drvTypeID, unsigned long sectorPerFAT, unsigned int nSector, unsigned char *pBuff, void *SecBuff);
++
++extern unsigned int FSAPP_FormatDrive( DISK_DEVICE diskDevice, unsigned int *multiPartition_SectorSize, unsigned int *validFAT);
++
++extern int FSAPP_FormatRootEntry_PS(int drvTypeID, int halfEntryNum, unsigned nSector, unsigned char writeVolume, void *pBuff, unsigned char *BS_VolLab);
++
++extern unsigned int FSAPP_decide_MakeMBR(int drvTypeID, unsigned char SecPerClus, unsigned int *numOfSecPR, unsigned int *validFAT, void *pBuff, struct _DISK_INFO *disk);
++extern unsigned char FSAPP_decide_DrvNum(int drvTypeID);
++extern int Initialize_FileSystem(DISK_DEVICE mDeviceNum, int partID);
++
++
++
++extern unsigned char *FSAPP_SetVolumeLabel(unsigned int partID, void* VolLab);
++extern unsigned char *FSAPP_GetVolumeLabel(unsigned int partID);
++
++extern unsigned int FSAPP_PartitionWrite(DISK_DEVICE diskDevice, unsigned int partitionID, unsigned int lba, void *pBuff, unsigned short nSector);
++extern unsigned int FSAPP_PartitionRead(DISK_DEVICE diskDevice, unsigned int partitionID, unsigned int lba, void *pBuff, unsigned short nSector);
++#endif
+diff --git a/drivers/block/tcc/inc/fwdn/KFSutils.h b/drivers/block/tcc/inc/fwdn/KFSutils.h
+new file mode 100644
+index 0000000..9dd3f77
+--- /dev/null
++++ b/drivers/block/tcc/inc/fwdn/KFSutils.h
+@@ -0,0 +1,23 @@
++
++/****************************************************************************
++ * FileName : KFSutils.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++
++extern char upperChar(char ch);
++extern char lowerChar(char ch);
++extern int printNum(char *sNum, int value);
++extern int str_cmp(void *sA, void *sB);
++extern int str_cmp16(void *sA, void *sB);
++extern int str_len(void *pStr);
++extern int mem_cmp(void *sA, void *sB, int len);
++extern void* mem_cpy(void *pDes, void *pSrc, long size);
++extern void* mem_cpyw(void *pDes, void *pSrc, long size);
++extern void* mem_set(void *pDes, unsigned char value, long size);
+diff --git a/drivers/block/tcc/inc/fwdn/TC_File.h b/drivers/block/tcc/inc/fwdn/TC_File.h
+new file mode 100644
+index 0000000..9c4d7b2
+--- /dev/null
++++ b/drivers/block/tcc/inc/fwdn/TC_File.h
+@@ -0,0 +1,164 @@
++/****************************************************************************
++ * FileName : TC_File.h
++ * Description : File System Abstraction Layer
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++#ifndef __TC_File_H__
++#define __TC_File_H__
++
++#if defined(_LINUX_)
++ #include <fwdn/file.h>
++ #include <fwdn/Disk.h>
++#elif defined(_WINCE_)
++ #include "file.h"
++ #include "Disk.h"
++#endif
++
++#ifndef _UINT8_
++ #define _UINT8_
++ typedef unsigned char UINT8;
++#endif
++
++typedef int TC_STAT;
++typedef unsigned long long TC_U64;
++typedef unsigned int TC_U32;
++typedef unsigned short TC_U16;
++typedef unsigned char TC_U8;
++
++typedef signed long long TC_S64;
++typedef signed int TC_S32;
++typedef signed short TC_S16;
++typedef signed char TC_S8;
++
++typedef char * TC_STR8;
++#ifndef _CHAR_
++ #define _CHAR_
++ typedef char CHAR;
++#endif
++
++typedef struct {
++ unsigned char second;
++ unsigned char minute;
++ unsigned char hour;
++ unsigned char day;
++ unsigned char date;
++ unsigned char month;
++ unsigned short year;
++} TC_DATETIME;
++
++
++typedef unsigned long _dev_t;
++typedef unsigned short _ino_t;
++typedef long _off_t;
++typedef unsigned long _mode_t;
++typedef unsigned long _time_t;
++
++typedef struct// _stat
++{
++ _dev_t st_dev; /* device */
++ _ino_t st_ino; /* inode */
++ _mode_t st_mode; /* protection */
++ short st_nlink; /* number of hard links */
++ short st_uid; /* user ID of owner */
++ short st_gid; /* group ID of owner */
++ _dev_t st_rdev; /* device type (if inode device) */
++ _off_t st_size; /* total size, in bytes */
++ _time_t st_atime; /* time of last access */
++ _time_t st_mtime; /* time of last modification */
++ _time_t st_ctime; /* time of last change */
++} stat;
++
++ #define TC_O_RDONLY 0x0000
++ #define TC_O_WRONLY 0x0001
++ #define TC_O_RDWR 0x0002
++ #define TC_O_APPEND 0x0008
++ #define TC_O_CREAT 0x0100
++ #define TC_O_TRUNC 0x0200
++
++/* File creation permissions for open */
++/* Note: OCTAL */
++ #define TC_A_READ 0000400 /* Write permitted */
++ #define TC_A_WRITE 0000200 /* Read permitted. (Always true anyway)*/
++ #define TC_SUCCESS 0
++ typedef TC_S32 TC_DRIVE;
++ typedef int TC_DIR;
++ typedef int TC_PDIR;
++ typedef FDIRENTstruc TC_DS;
++ typedef DIRENTstruc TC_DENTRY;
++
++ #define TC_ISDIRSP(X) (0)
++
++ #define TC_StartDrive 1/* DISK_DEVICE_INTERNAL */
++ #define TC_DriveNum uNDRIVES
++
++ #define TC_INTERNAL_DRIVE(X) (0)
++
++ #define TC_UFD_DEVICE DISK_DEVICE_UHP
++ #define TC_HDD_DEVICE DISK_DEVICE_HDD
++ #define TC_NAND_DEVICE DISK_DEVICE_NAND
++ #define TC_TRIFLASH_DEVICE DISK_DEVICE_TRIFLASH
++ #define TC_SDMMC_DEVICE DISK_DEVICE_MMC
++ #define TC_ISINTDRIVE(X) ((X) == TC_StartDrive)
++
++ #define TC_Set_Drive(X, Y) ((X) = (Y))
++ #define TC_Inc_Drive(X, Y) ((X) += (Y))
++ #define TC_Get_DriveNo(X) ((X))
++
++ #define TC_Get_Attribute(X) ((X)->type)
++ #define TC_Get_Cluster(X, Y) ((X)->startCluster)
++ #define TC_Get_Size(X, Y) ((X)->fileSize)
++ #define TC_Get_LFN(X) ((X)->lFileName)
++ #define TC_Get_SFName(X) ((X)->sFileName)
++ #define TC_Get_SFext(X) ((X)->sFileName+9)
++
++ #define TC_A_RDONLY FILE_READ_ONLY
++ #define TC_A_HIDDEN FILE_HIDDEN
++ #define TC_A_SYSTEM FILE_SYSTEM
++ #define TC_A_VOLUME FILE_VOLUME_ID
++ #define TC_A_DIRENT FILE_DIRECTORY
++ #define TC_A_ARCHIVE FILE_ARCHIVE
++ #define TC_A_NORMAL FILE_NORMAL
++
++ #define TC_MAX_PATH 255
++ #define TC_MAX_DIR MAX_DIR
++
++#define TC_ISERR(X) ((signed)(X) < 0)
++#define TC_ISOK(X) ((signed)(X) >= 0)
++
++#define TC_ISHERR(X) ((signed)(X) < 0)
++#define TC_ISHOK(X) ((signed)(X) >= 0)
++
++#define TC_ISRWERR(X) ((signed)(X) <= 0)
++
++#define TC_SEEK_SET 0
++#define TC_SEEK_CUR 1
++#define TC_SEEK_END 2
++
++#define TC_LOWLEVEL_YES 1
++#define TC_LOWLEVEL_NO 0
++
++#define UNDEFINED_HANDLE (-1)
++
++TC_STAT TC_Open(char *name, TC_U32 uFlag, TC_U32 uMode, TC_U32 uDirNum);
++TC_S32 TC_Read(TC_S32 iHandle, void *pBuff, TC_S32 iCount);
++TC_S32 TC_Write(TC_S32 iHandle, void *pBuff, TC_S32 iCount);
++TC_S32 TC_Seek(TC_S32 iHandle, TC_S32 iOffset, TC_S32 iOrigin);
++TC_STAT TC_Close(TC_S32 iHandle);
++TC_S32 TC_Length(TC_S32 iHandle);
++TC_STAT TC_DeleteIndex(TC_U32 uIndex, TC_U32 uDirNum);
++TC_STAT TC_Make_Dir(TC_STR8 pName, TC_U32 uDirNum);
++TC_STAT TC_SyncDrives(TC_S32 uDriveNo, TC_U32 uNum);
++TC_U32 TC_Get_FileIndex(TC_S32 iHandle, TC_U32 uDirNum);
++TC_STAT TC_Set_Current_Dir(TC_S32 iPartID, TC_STR8 pPath, TC_U32 uDirNum);
++TC_STAT TC_CloseNGetFileProperty(TC_S32 iHandle, unsigned int *iFileProperty);
++
++//ENHANCED_DELETION_SPEED
++
++ #endif
++/* end of file */
+diff --git a/drivers/block/tcc/inc/fwdn/browse.h b/drivers/block/tcc/inc/fwdn/browse.h
+new file mode 100644
+index 0000000..f87724f
+--- /dev/null
++++ b/drivers/block/tcc/inc/fwdn/browse.h
+@@ -0,0 +1,455 @@
++/*******************************************************************************
++***
++*** TELECHIPS.
++***
++***
++***
++*******************************************************************************/
++#ifndef _BROWSE_H_
++#define _BROWSE_H_
++
++#if defined(_LINUX_)
++#include <common.h>
++#endif
++
++//#ifndef _MAIN_H_
++// #include "main.h"
++//#endif
++
++#define ROOTDIR 0
++#define _MUSICFILE 1
++#define _NOTMUSICFILE -1
++
++#define WITHNULL 0
++
++#define _DIR 0
++#define _FILE 1
++//#define _DONOTUSE 2
++
++#ifndef KILO
++#define KILO 1024
++#endif
++
++// Error Message
++enum {
++ BRWS_NO_ERROR = 0,
++ BRWS_ERROR_NODIR,
++ BRWS_ERROR_NOFILE,
++ BRWS_ERROR_CANTGO,
++ BRWS_ERROR_UNDEF_ATTR,
++ BRWS_ERROR_INVALID_INDEX,
++ BRWS_ERROR_FAILE_DELETE,
++ BRWS_ERROR_UHP_BUSY,
++ BRWS_UNDEF_ERROR
++};
++
++enum{
++BRWS_EXT_MP3,
++#ifdef MTX_INCLUDE
++BRWS_EXT_MTX,
++#endif
++#ifdef WMA_INCLUDE
++BRWS_EXT_WMA,
++#ifdef TRUSTED_FLASH_INCLUDE
++BRWS_EXT_SMA,
++#endif
++#endif
++#ifdef MP2_INCLUDE
++BRWS_EXT_MP2,
++#endif
++#ifdef OGG_INCLUDE
++BRWS_EXT_OGG,
++#endif
++#ifdef EAACPlus_INCLUDE
++BRWS_EXT_EAACPlus_AAC,
++BRWS_EXT_EAACPlus_M4A,
++BRWS_EXT_EAACPlus_MP4,
++BRWS_EXT_EAACPlus_ADIF,
++BRWS_EXT_EAACPlus_ADTS,
++BRWS_EXT_EAACPlus_3GP,
++#endif
++#ifdef WAV_INCLUDE
++BRWS_EXT_WAV,
++#endif
++#ifdef MP4_INCLUDE
++BRWS_EXT_MP4,
++#endif
++#ifdef WMV_INCLUDE
++BRWS_EXT_WMV,
++#ifdef TRUSTED_FLASH_INCLUDE
++BRWS_EXT_SMV,
++#endif
++#endif
++#if defined(JPG_INCLUDE) || defined (MULTI_CODEC_INCLUDE)
++BRWS_EXT_JPG,
++#endif
++#if defined(PNG_INCLUDE)
++BRWS_EXT_PNG,
++#endif
++#if defined(BMP_INCLUDE)
++BRWS_EXT_BMP,
++#endif
++#if defined(GIF_INCLUDE)
++BRWS_EXT_GIF,
++#endif
++#ifdef AUDIBLE_INCLUDE
++BRWS_EXT_AA,
++#endif
++#if defined (MULTI_CODEC_INCLUDE)
++BRWS_EXT_TXT,
++#endif
++#ifdef M3U_INCLUDE
++BRWS_EXT_M3U,
++#endif
++#if defined(MTP_CUSTOM_IMAGE_INCLUDE)
++BRWS_EXT_FIL,
++#endif
++#ifdef RHAPSODY_INCLUDE
++BRWS_EXT_XML,
++#endif
++BRWS_EXT_MAX
++};
++
++/* Start - skott 's code */
++#define MAX_PLAYLIST_NUM 1*KILO
++
++// 2M Buffer config
++#ifdef BRWS_STR_NAND_INCLUDE
++#define BRWS_NAME_BUFFER_SIZE (4096)
++#elif defined(MTP_INCLUDE)
++#define BRWS_NAME_BUFFER_SIZE (256)
++#else
++#define BRWS_NAME_BUFFER_SIZE (KILO*KILO*2)
++#endif
++#define MAX_INDEX_LIST_NUM 1*KILO
++
++#ifdef MTP_INCLUDE
++#define MAX_FOLDER_NUM MTPDB_DEVICE_FOLDER_MAX
++#define MAX_MUSICFILE_NUM MTPDB_DEVICE_FILE_MAX
++#else
++#define MAX_FOLDER_NUM 2*KILO
++#define MAX_MUSICFILE_NUM 1*KILO
++#endif
++
++
++typedef enum
++{
++ DB_NOT_USED =0,
++ DB_USED
++#ifdef MTP_INCLUDE
++ ,DB_BE_DELETED
++#endif
++}DB_USAGE_TYPE;
++
++
++
++/* Status Define
++==================================================================
++|B7 | B6 | B5 | B4 | B3 / B2 | B1 | B0 |
++==================================================================
++|reserved | Reference | Reference | AlbumJacket | Protection | Protection Status |
++| | Flag | member flag| Exist Flag | Status | |
++==================================================================
++*/
++typedef struct{
++ unsigned int ucMotherIndex;
++ unsigned int ucFileIndex;
++ unsigned char ucAttr;
++ unsigned char ucPartition_ID;
++ unsigned char ucStatus;
++ unsigned char ucCodec;
++#ifndef MTP_INCLUDE
++ unsigned int ucShortFileName;
++ unsigned int ucLongFileName;
++ unsigned char fLfn;
++ unsigned char dummy[3];
++#else
++ unsigned long ulCluster; //start cluster in FAT
++ unsigned short usCRC16FileName; //verify filename
++//MTPDB2DB-->
++ unsigned short usPacketOffset;
++//<--MTPDB2DB
++#ifdef VIDEOART_INCLUDE
++ unsigned int AlbumArtIndex;
++#else
++ unsigned short AlbumArtIndex;
++#endif
++ unsigned short ObjectFormat;
++
++#ifdef MEDIA_RESUME_INCLUDE
++ unsigned short usLastTimeSec;
++#endif
++
++#endif
++}_FILE_LIST_TYPE,*pFILE_LIST_TYPE;
++
++typedef struct{
++ unsigned short ucFileCount; // Total File Number
++ unsigned short ucFolderCount; // Total Folder Number
++ unsigned int ucMotherIndex; // Mother Index Number
++ unsigned int ucFolderIndex; // The order of folder in entry field like 1st, 2nd ..
++ unsigned long ulCluster; // Start Cluster in FAT
++ unsigned char ucPartition_ID; // Partition ID
++ unsigned char fUsed; // Used or Not used
++#ifndef MTP_INCLUDE
++ unsigned int ucShortFolderName;
++ unsigned int ucLongFolderName;
++ unsigned char fLfn;
++ unsigned char dummy[3];
++#else
++ unsigned short usCRC16FileName; //verify filename
++//MTPDB2DB-->
++ unsigned short usPacketOffset;
++//<--MTPDB2DB
++ unsigned char ucStatus;
++ unsigned char ReferenceCount;
++#endif
++}_FOLDER_LIST_TYPE,*pFOLDER_LIST_TYPE;
++
++
++typedef struct{
++ unsigned char ucName[9]; // Disk name
++ unsigned char ucUsed; // Used or not
++ unsigned char ucDeviceType; // Device type from enum DISK_DEVICE
++ unsigned char ucPartID; // Partition ID
++ unsigned int uiFolderNum; // Total folder number in disk
++ unsigned int uiFileNum; // Total file number in disk
++ unsigned int uiRootIndex; // Root index at stTotalFolderList[]
++// unsigned char dummy;
++}_DEVICE_TYPE_INFO;
++
++#define BRWS_MAKE_LIST_OF_FOLDER 0x01
++#define BRWS_MAKE_LIST_OF_FILE 0x02
++#define BRWS_MAKE_LIST_OF_ALL BRWS_MAKE_LIST_OF_FOLDER | BRWS_MAKE_LIST_OF_FILE
++
++#define BRWS_MAKE_PLAY_LIST_ALL 0x80
++#define BRWS_MAKE_PLAY_LIST_SIMAGE 0x40
++#define BRWS_MAKE_PLAY_LIST_TEXT 0x20
++#define BRWS_MAKE_PLAY_LIST_MPG4 0x10
++#define BRWS_MAKE_PLAY_LIST_AUDIO 0x08
++#define BRWS_MAKE_PLAY_LIST_M3U 0x04
++
++#define BRWS_SEARCH_ALL_FOLDER -1
++
++#define BRWS_NAME_AREA_SIZE 4096
++
++enum
++{
++ FOLDER_RECORD = 10,
++#ifdef _RECORD_SUB_FOLDER_INCLUDE_
++ #ifdef _RECORD_SUB_FOLDER_LINEIN_INCLUDE_
++ FOLDER_RECORD_LINEIN,
++ #endif
++ #ifdef _RECORD_SUB_FOLDER_FM_INCLUDE_
++ FOLDER_RECORD_FM,
++ #endif
++ #ifdef _RECORD_SUB_FOLDER_VOICE_INCLUDE_
++ FOLDER_RECORD_VOICE,
++ #endif
++ #ifdef _RECORD_SUB_FOLDER_CAM_INCLUDE_
++ FOLDER_RECORD_CAM,
++ #endif
++ #ifdef _RECORD_SUB_FOLDER_TV_INCLUDE_
++ FOLDER_RECORD_TV,
++ #endif
++#endif
++ FOLDER_PHOTO,
++ FOLDER_AUDIBLE,
++ FOLDER_CONFIG,
++ FOLDER_ROOT,
++ FOLDER_DEFAULT,
++ FOLDER_UNKNOWN
++};
++
++#ifdef _RECORD_SUB_FOLDER_INCLUDE_
++typedef enum
++{
++#ifdef _RECORD_SUB_FOLDER_LINEIN_INCLUDE_
++ RECORD_FOLDER_LINEIN,
++#endif
++#ifdef _RECORD_SUB_FOLDER_FM_INCLUDE_
++ RECORD_FOLDER_FM,
++#endif
++#ifdef _RECORD_SUB_FOLDER_VOICE_INCLUDE_
++ RECORD_FOLDER_VOICE,
++#endif
++#ifdef _RECORD_SUB_FOLDER_CAM_INCLUDE_
++ RECORD_FOLDER_CAM,
++#endif
++#ifdef _RECORD_SUB_FOLDER_TV_INCLUDE_
++ RECORD_FOLDER_TV,
++#endif
++ RECORD_SUB_FOLDER_UNKNOWN,
++ RECORD_SUB_FOLDER_MAX = RECORD_SUB_FOLDER_UNKNOWN
++}RECORD_SUB_FOLDER_TYPE;
++#endif
++
++
++/*--------------------------------------------------------------
++ Folder Index Function
++----------------------------------------------------------------*/
++extern unsigned int BRWS_GetRecordFileIndex(void);
++extern unsigned int BRWS_GetRecordFolderIndex(void);
++extern unsigned int BRWS_GetRecordFolderCluster(void);
++#ifdef _RECORD_SUB_FOLDER_INCLUDE_
++extern unsigned int BRWS_GetRecordSubFolderIndex(unsigned int rec_sub_type);
++extern unsigned int BRWS_GetRecordSubFolderCluster(unsigned int rec_sub_type);
++#endif
++extern unsigned int BRWS_GetCurrFolderIndex(void);
++extern void BRWS_SaveFolderIndex(unsigned int iIndex);
++
++
++/*--------------------------------------------------------------
++ Functions for making File List
++
++ name : BRWS_MakePlayList
++----------------------------------------------------------------*/
++extern unsigned int BRWS_MakePlayList(int uiTotalIndex, unsigned short *ptrList, unsigned char ucMode );
++
++extern unsigned int BRWS_FindFileNumInPlayList(int uiTotalIndex, unsigned int uiDBIndex, unsigned char ucMode );
++
++
++/*--------------------------------------------------------------
++Get Count Value Function
++----------------------------------------------------------------*/
++extern unsigned int BRWS_GetTotalFolderNum( void );
++extern unsigned int BRWS_GetTotalFileCount( void );
++
++/*--------------------------------------------------------------
++utility Function
++----------------------------------------------------------------*/
++extern int BRWS_FindMusicFile(const char *filename, int mode);
++extern int BRWS_CorrectDirName(char *path);
++extern void BRWS_CharCopy(const char *input, char *output, int num);
++extern int BRWS_CharNICmp(const char *src1, const char *src2, int cmplen);
++extern int BRWS_IsReadOnly(int attr);
++
++/*--------------------------------------------------------------
++Check the main device if config folder is existed. if not existing config folder, create it.
++----------------------------------------------------------------*/
++extern int BRWS_CheckConfigFolderIs(int iPartID, int dir_num);
++
++/*--------------------------------------------------------------
++Audible function
++----------------------------------------------------------------*/
++#ifdef AUDIBLE_INCLUDE
++extern int BRWS_CheckAudibleFolderIs(int);
++#endif
++/*--------------------------------------------------------------
++Recoding function
++----------------------------------------------------------------*/
++extern int BRWS_CheckRecodingFolderIs(int);
++extern int BRWS_ChangeRecodingFolder(void);
++extern int BRWS_UpdateRecodingDB(void);
++
++/*--------------------------------------------------------------
++Check File Attrive Function
++----------------------------------------------------------------*/
++extern int BRWS_CheckFileAttrive(unsigned int uiFileIdx);
++
++
++/*--------------------------------------------------------------
++Format Drive Function
++
++----------------------------------------------------------------*/
++extern int BRWS_FormatDrive(unsigned short mode, int iPartID);
++
++
++/*--------------------------------------------------------------
++Delete File Function
++----------------------------------------------------------------*/
++extern int BRWS_DeleteFile(unsigned int uiCurrFileNum, unsigned int uiFolderIdx);
++
++/*---------------------------------------------------------------------
++ BRWS_ReProfilingMTPUIDB
++-----------------------------------------------------------------------*/
++extern int BRWS_ReProfilingMTPUIDB(void);
++
++/*--------------------------------------------------------------
++Copy File Function
++----------------------------------------------------------------*/
++extern int BRWS_CopyFile(unsigned int uiSrcFileIndex, unsigned int uiDstFolderIndex);
++
++/*--------------------------------------------------------------
++Check Disk WP Status
++----------------------------------------------------------------*/
++extern int BRWS_CheckWPStatus(int part_ID);
++
++/*--------------------------------------------------------------
++Check CRC of Image on NAND Disk
++----------------------------------------------------------------*/
++#ifdef NAND_BOOT_INCLUDE
++extern int BRWS_CheckCRCOfNANDBOOT( void );
++#endif
++
++/*--------------------------------------------------------------
++ Change Folder usign cluster
++----------------------------------------------------------------*/
++extern int BRWS_CheckIsFolderRoot( unsigned int uiIndex );
++
++extern int BRWS_ChangeBackgroundFolder( unsigned int uiTotalIndex );
++
++extern int BRWS_ChangeFolder( unsigned int uiTotalIndex );
++
++extern int BRWS_InitializeCurrFolderList(unsigned int uiTotalIndex, unsigned short *ptrList, unsigned char ucMode );
++
++extern int BRWS_InitializeDeviceList(unsigned short *ptrList);
++
++/*--------------------------------------------------------------
++Folder Name Function
++----------------------------------------------------------------*/
++extern unsigned char *BRWS_GetFolderName( unsigned int uiIndex, unsigned char *fLfn);
++extern unsigned char *BRWS_GetFileName( unsigned int uiFileIndex, unsigned char *fLfn);
++
++/*--------------------------------------------------------------
++ Search all file and folder in Selected Folder
++----------------------------------------------------------------*/
++
++extern int BRWS_SearchFolder(int iPartID, unsigned int uiTotalIndex);
++
++/*--------------------------------------------------------------
++ Make Folder and File List DataBase
++ : using BRWS_SearchFolder();
++
++----------------------------------------------------------------*/
++extern void BRWS_InitializeFolderDB( void );
++
++extern int BRWS_AddDevice( unsigned char *ucName, unsigned char ucType );
++extern int BRWS_RefreshMainDevice( void );
++
++extern int BRWS_SaveBRWSDB(void);
++extern int BRWS_LoadBRWSDB(void);
++extern int BRWS_DelBRWSDB(void);
++
++#ifdef BRWS_STR_NAND_INCLUDE
++extern unsigned char *BRWS_GetNameString(unsigned int Offset);
++extern void BRWS_InitNameStringArea(unsigned int uiStartAddr,unsigned int uiSectorSize);
++extern void BRWS_CleanNameString(unsigned char *ucSrcString,unsigned int uiOffset);
++#endif
++extern void BRWS_PutNameString(unsigned char *ucSrcString,unsigned int uiOffset,unsigned char ucNameChar);
++extern unsigned char BRWS_GetDeviceStatus(unsigned int uiIndex);
++extern unsigned int BRWS_GetDefaultDevice(void);
++extern void BRWS_SetDefaultDevice(unsigned int uiDefaultDevice);
++extern unsigned int BRWS_GetDeviceCount(void);
++extern unsigned int BRWS_GetTotalDeviceCount(void);
++extern void BRWS_RemoveDevice(unsigned char ucDeviceType);
++extern unsigned char BRWS_GetFilePartID(unsigned int uiFileIndex);
++/* End - skott 's code */
++
++ extern int BRWS_CHeckFFREWSeekStatus(void);
++
++extern int BRWS_IsTAGJPGCodec(int iCurrentCodec);
++extern int BRWS_IsMP3MP2Codec(int iCurrentCodec);
++extern int BRWS_IsAudibleCodec(int iCurrentCodec);
++extern int BRWS_IsImageCodec(int iCurrentCodec);
++extern int BRWS_IsBackgroundImageCodec(unsigned int uiBackgroundCodec);
++extern int BRWS_IsEAACPlusCodec(int iCurrentCodec);
++extern int BRWS_IsVideoCodec(int iCurrentCodec);
++extern int BRWS_IsWMVVideoCodec(int iCurrentCodec);
++extern int BRWS_IsDrmCodec(int iCurrentCodec);
++extern void BRWS_FILE_OpenDir(int iCurrentCodec, unsigned int uiTotalIndex) ;
++extern void BRWS_DisplayProgressFile(int iStartIndex, unsigned int Count,unsigned int MaxFileNum);
++extern unsigned long BRWS_GetFileCluster(int index);
++
++#endif
++
+diff --git a/drivers/block/tcc/inc/fwdn/fat.h b/drivers/block/tcc/inc/fwdn/fat.h
+new file mode 100644
+index 0000000..075ebc1
+--- /dev/null
++++ b/drivers/block/tcc/inc/fwdn/fat.h
+@@ -0,0 +1,740 @@
++/*****************************************************************************/
++//
++// Definition for FAT Application using Telechips Software.
++//
++// Copyright 2008 Telechips, Inc.
++//
++/*****************************************************************************/
++
++#include "FSAPP.h"
++
++#ifndef __FAT_H__
++#define __FAT_H__
++
++//=============================================================================
++//*
++//*
++//* [ ERROR CODE ENUMERATION ]
++//*
++//*
++//=============================================================================
++enum
++{
++ FS_SUCCESS = 0,
++ FS_FAIL,
++
++ ERR_FS_NOT_VALID_MBR,
++ ERR_FS_NOT_READ_MBR,
++ ERR_FS_NOT_FORMATTED,
++ ERR_FS_NOT_DELETE_FILE,
++ ERR_FS_NOT_DELETE_DIR,
++ ERR_FS_NOT_FIND_PARTITION_INFO,
++ ERR_FS_NOT_VALID_FAT_TYPE,
++ ERR_FS_NOT_VALID_READ_BOOTSECTOR,
++ ERR_FS_INVALID_SECTOR_SIZE,
++ ERR_FS_NOT_VALID_CLUSTER_PARAMETER,
++ ERR_FS_NOT_READ_SECTOR,
++ ERR_FS_NOT_WRITE_SECTOR,
++ ERR_FS_NOT_GET_LOGDRV_INFO,
++ ERR_FS_NOT_GET_PREVIOUS_DIR,
++ ERR_FS_NOT_GET_NEXT_CLUSTER,
++ ERR_FS_NOT_GET_PREV_CLUSTER,
++ ERR_FS_NOT_GET_EMPTY_CLUSTER,
++ ERR_FS_NOT_GET_INFO_FILEORDIR,
++ ERR_FS_NOT_GET_TOTAL_FILEORDIR,
++ ERR_FS_NOT_GET_PARENT_DIR_CLUSTER,
++ ERR_FS_NOT_FIND_DIR_CLUSTER_WITHDIRNAME,
++ ERR_FS_NOT_CREATE_DIRECTORY,
++ ERR_FS_NOT_DIRECTORY_CLUSTER,
++ ERR_FS_NOT_UPDATE_ENTRY,
++ ERR_FS_NOT_GET_FILEINFO_WITHFILENAME,
++ ERR_FS_NOT_OPEN_FAT_CHCHE,
++ ERR_FS_NOT_FLUSH_FAT_CACHE,
++ ERR_FS_NOT_SAME_FAT1_FAT2,
++ ERR_FS_NOT_READY_VIRTUAL_FAT1_FORSMC,
++ ERR_FS_NOT_READ_FROM_VIRTUAL_FAT1_FORSMC,
++ ERR_FS_NOT_WRITE_FAT_CONTENT_TO_VIRTUAL_FAT1_FORSMC,
++ ERR_FS_FAILED_READ_SECTOR,
++ ERR_FS_FAILED_FORMAT,
++ ERR_FS_PARAMETER_GET_DRV_PARTITON,
++ ERR_FS_NOT_VALID_PARAMETER
++};
++
++
++//=============================================================================
++//*
++//*
++//* [ EXTERNAL DEFINATION ]
++//*
++//*
++//=============================================================================
++#define FAT_BOOTSIG 0xAA55
++
++// Some useful cluster numbers
++#define FAT_MSDOSFSROOT 0 /* cluster 0 means the root dir */
++#define FAT_CLUST_FREE 0 /* cluster 0 also means a free cluster */
++#define FAT_CLUST_RSRVD 0xfffffff6 /* reserved cluster range */
++#define FAT_CLUST_BAD 0xfffffff7 /* a cluster with a defect */
++#define FAT_CLUST_EOFS 0xfffffff8 /* start of eof cluster range */
++#define FAT_CLUST_EOFE 0xffffffff /* end of eof cluster range */
++
++#define FAT12_MASK 0x00000fff /* mask for 12 bit cluster numbers */
++#define FAT16_MASK 0x0000ffff /* mask for 16 bit cluster numbers */
++#define FAT32_MASK 0x0fffffff /* mask for FAT32 cluster numbers */
++
++#define FAT12_EOFS 0x0FF8
++#define FAT16_EOFS 0xFFF8
++#define FAT32_EOFS 0x0FFFFFF8
++// Partition Type used in the partition record
++#define PART_TYPE_UNKNOWN 0x00
++#define PART_TYPE_FAT12 0x01
++#define PART_TYPE_DOSFAT16 0x04
++#define PART_TYPE_EXTDOS 0x05
++#define PART_TYPE_FAT16 0x06
++#define PART_TYPE_FAT32 0x0B
++#define PART_TYPE_FAT32LBA 0x0C
++#define PART_TYPE_FAT16LBA 0x0E
++#define PART_TYPE_EXTDOSLBA 0x0F
++
++#define FS_MAX_SHIFT_FACTOR 17
++
++#define DRIVE0 0
++#define MAX_MULTI_SECTOR 32 // 32 SECTORS
++#define MAX_MULTI_BYTE 16384 // 16 [Kbyte] = 512[byte] * 32
++#define MAX_SECTOR_SIZE 4096 // [byte] = maximum bytes per sector
++#define MAX_CLUSTER_SIZE 65536 // 512(byte) * 128(sec)
++
++#define FAT_BOOTSIG 0xAA55
++#define EXTENDED_BOOTSIG 0x29
++
++#define FAT12 2
++#define FAT16 1
++#define FAT32 0
++
++#define FAT_DIR_EMPTY 0x00 // directory entry is free. never been used.
++#define FAT_DIR_E5 0x05 // value for 0xE5. because 0xE5 is a real char in KANJI
++#define FAT_DIR_DELETED 0xE5 // this directory entry is free.
++
++#define ATTR_NORMAL 0x00 // normal file
++#define ATTR_READ_ONLY 0x01 // file is read only
++#define ATTR_HIDDEN 0x02 // file is hidden
++#define ATTR_SYSTEM 0x04 // file is a system file
++#define ATTR_VOLUME_ID 0x08 // entry is a volume label
++#define ATTR_DIRECTORY 0x10 // entry is a directory name
++#define ATTR_ARCHIVE 0x20 // file is new or modified
++#define ATTR_LONG_NAME 0x0F // this is a long file name entry
++
++#define LCASE_BASE 0x08 // filename base in lower case
++#define LCASE_EXT 0x10 // filename extension in lower case
++
++#define DIR_ENTRY_PER_SECTOR 0x10 // 16 = 512/32
++
++#define LAST_LONG_ENTRY 0x40 // mask for the last dir entry
++#define LDIR_ORD_MAX 0x3F // Max. count of LDIR_Ord
++
++#define LDIR_CHAR_PER_ENTRY 13 // Number of character of a long dir entry.
++#define LDIR_MAX_CHAR 255 // max. number of character of the long file name
++#define MAX_ROOT_ENTRY_COUNT 1024 // max. number of the root entry count
++
++#define FAT_CACHE_SECTOR 3 // 3 sectors = 512 * 3 [byte]
++
++// LOCK FLAG OF THE FILE SYSTEM TEMPORARY BUFFER
++#define LOCK_BUFF 0x0001
++#define UNLOCK_BUFF 0x0000
++#define DIRTY_BIT 0x0100
++
++// MAXIMUM NUMBER OF PARTITIONS
++#define FS_MAX_PART_NUMBER FSAPP_MAX_PART_NUMBER
++
++#define START_YEAR 1980 // Year 1980
++
++#define FILE_OP_WRITE 0x00010000 // write file
++#define FILE_OP_OPEN 0x00000001 // opened file
++#define FILE_OP_CH_SIZE 0x00020000 // changed file size
++#define FILE_OP_UP_ENT 0x00100000 // update short entry. else create new entry
++
++#define ADDITION 1
++#define SUBTRACTION 2
++// special option
++#define _NEW_WRITE_ENTRY
++
++
++//=============================================================================
++//*
++//*
++//* [ STRUCT DEFINE ]
++//*
++//*
++//=============================================================================
++
++///////////////////////////////////////////////////////////////////////////////
++///////////////////////// MBR ///////////////////////////////////////////
++///////////////////////////////////////////////////////////////////////////////
++// FOR EACH PARTITION ENTRY INFORMATION(16 BYTES) STRUCTURE
++#if defined(_WINCE_)
++#pragma pack(1)
++typedef struct _PARTITION_INFO // length 16 bytes partion entry information
++#elif defined(_LINUX_)
++typedef struct _PARTITION_INFO // length 16 bytes partion entry information
++#endif
++{
++
++ unsigned char boot_id; // Bootable? 0=no , 128(0x80) = yes
++ unsigned char begin_head; // beginning head number
++ unsigned char begin_sector; // beginning sector number
++ unsigned short begin_cylinder; // 10bit number [high 2bit], with high 2bits put in begin sector
++ unsigned char system_id; // Operating System type indicator code
++ unsigned char end_head; // ending head number
++ unsigned char end_sector; // ending sector numer
++ unsigned short end_cylinder; // 10bit number [high 2bit] , with high 2bits put in end sector
++ unsigned long relative_first_sector; // first sector relative to start of disk
++ unsigned long number_sector_partition; // number of sectors in partion
++
++
++#if defined(_WINCE_)
++}PARTINFOstruc;
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed)) PARTINFOstruc;
++#endif
++
++
++
++// FOR EACH PARTITION AREA ALL DATA STRUCTURE
++#if defined(_WINCE_)
++#pragma pack(1)
++struct _MBR_INFO
++#elif defined(_LINUX_)
++struct _MBR_INFO
++#endif
++{
++
++ PARTINFOstruc parts[4];
++ unsigned short signature; // two signature bytes (2 bytes)
++
++
++#if defined(_WINCE_)
++};
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed));
++#endif
++///////////////////////////////////////////////////////////////////////////////
++///////////////////////////////////////////////////////////////////////////////
++
++
++
++
++///////////////////////////////////////////////////////////////////////////////
++///////////////////////// PBR ///////////////////////////////////////////
++///////////////////////////////////////////////////////////////////////////////
++// COMMON BPB SPEC. FOR FAT16/32. (36 BYTES)
++#if defined(_WINCE_)
++#pragma pack(1)
++struct _BPB
++#elif defined(_LINUX_)
++struct _BPB
++#endif
++{
++
++ unsigned char BS_jmpBoot[3]; // jump instruction to boot code. 0xE9xxx or 0xEBxx90
++ char BS_OEMName[8]; // OEM name and version
++ unsigned short BPB_BytsPerSec; // Count of bytes per sector. default 512
++ unsigned char BPB_SecPerClus; // Number of sectors per cluster
++ unsigned short BPB_RsvdSecCnt; // Number of reserved sectors
++ unsigned char BPB_NumFATs; // Count of FAT data on the volume. default 2
++ unsigned short BPB_RootEntCnt; // Number of the Root directory entries. FAT32 = 0
++ unsigned short BPB_TotSec16; // 16 bit total count of sector < 65536. FAT32 = 0
++ unsigned char BPB_Media; // media discriptor. 0xF8 --> "Fixed Disk"
++ unsigned short BPB_FATSz16; // Number of sectors per FAT
++ unsigned short BPB_SecPerTrk; // sector per track
++ unsigned short BPB_NumHeads; // Number of heads
++ unsigned long BPB_HiddSec; // count of hidden sectors
++ unsigned long BPB_TotSec32; // total count of sectors on the volume.
++
++
++#if defined(_WINCE_)
++};
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed));
++#endif
++
++
++
++// EXTENDED BS(BOOT SECTOR) SPEC. FOR FAT16/32. (26 BYTES)
++#if defined(_WINCE_)
++#pragma pack(1)
++struct _EXTENDED_BS
++#elif defined(_LINUX_)
++struct _EXTENDED_BS
++#endif
++{
++
++ unsigned char BS_DrvNum; // drive number : HDD(0x80), FDD(0x00)
++ unsigned char BS_Reserved1; // reserved(used by Windows NT)
++ unsigned char BS_BootSig; // Extended boot signature (0x29)
++ unsigned char BS_VolID[4]; // Volume serial number
++ char BS_VolLab[11]; // Volume label
++ char BS_FilSysType[8]; // FS type string "FAT12","FAT16","FAT"
++
++
++#if defined(_WINCE_)
++};
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed));
++#endif
++
++
++
++// BPB SPEC. FOR FAT32 ONLY. (54 BYTES)
++#if defined(_WINCE_)
++#pragma pack(1)
++struct _BPB_FAT32
++#elif defined(_LINUX_)
++struct _BPB_FAT32
++#endif
++{
++
++ unsigned long BPB_FATSz32; // Number of sectors per FAT for FAT32
++ unsigned short BPB_ExtFlags; // extended flags
++ unsigned short BPB_FSVer; // FAT file system version.
++ unsigned long BPB_RootClus; // starting cluster number of the root directory.
++ unsigned short BPB_FSInfo; // sector number of FSINFO structure. Usually 1.
++ unsigned short BPB_BkBootSec; // backup boot sector. Usually 6.
++ unsigned char BPB_Reserved[12]; // reserved for future expansion. Must be all zero.
++ unsigned char BS_DrvNum;
++ unsigned char BS_Reserved1;
++ unsigned char BS_BootSig;
++ unsigned char BS_VolID[4];
++ char BS_VolLab[11]; // Volume label
++ char BS_FilSysType[8]; // Reserved 12 bytes for future expansion. all zeros.
++
++
++#if defined(_WINCE_)
++};
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed));
++#endif
++
++
++
++// BS(BOOT SECTOR) AND BPB(BIOS PARAMETER BLOCK) STRUCTURE FOR FAT32
++#if defined(_WINCE_)
++#pragma pack(1)
++typedef struct _BSBPB_INFO
++#elif defined(_LINUX_)
++typedef struct _BSBPB_INFO
++#endif
++{
++
++ struct _BPB BPB_data; // Common BPB data (25 bytes)
++ struct _BPB_FAT32 BPB_FAT32; // Extended BPB Info. for FAT32 only. (28 bytes)
++ struct _EXTENDED_BS BS_extended; // Extended BS for FAT12/16 (26 bytes)
++
++
++#if defined(_WINCE_)
++}BSBPBstruc;
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed)) BSBPBstruc;
++#endif
++
++
++
++// BS(BOOT SECTOR) AND BPB(BIOS PARAMETER BLOCK) STRUCTURE FOR FAT12/16
++#if defined(_WINCE_)
++#pragma pack(1)
++typedef struct _BSBPB1216_INFO
++#elif defined(_LINUX_)
++typedef struct _BSBPB1216_INFO
++#endif
++{
++
++ struct _BPB BPB_data; // Common BPB data (25 bytes)
++ struct _EXTENDED_BS BS_extended; // Extended BS for FAT12/16 (26 bytes)
++
++
++#if defined(_WINCE_)
++}BSBPB1216struc;
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed)) BSBPB1216struc;
++#endif
++///////////////////////////////////////////////////////////////////////////////
++///////////////////////////////////////////////////////////////////////////////
++
++
++
++
++///////////////////////////////////////////////////////////////////////////////
++///////////////////// Reserved Area(FSInfo) /////////////////////////////
++///////////////////////////////////////////////////////////////////////////////
++// FAT32 FSINFO SECTOR STRUCTURE & BACKUP BOOT SECTOR.
++#if defined(_WINCE_)
++#pragma pack(1)
++typedef struct _FSINFO_SECTOR // for FAT32 FSInfo
++#elif defined(_LINUX_)
++typedef struct _FSINFO_SECTOR // for FAT32 FSInfo
++#endif
++{
++
++
++ unsigned long FSI_LeadSig; // lead signature for FSInfo. Usually 0x41615252
++ unsigned char FSI_Reserved1[480]; // reserved field. initial value is all zeros.
++ unsigned long FSI_StrucSig; // usually 0x61417272 in spec.
++ unsigned long FSI_Free_Count; // (free cluster count on the volume) <= (volume cluster count)
++ unsigned long FSI_Nxt_Free; // next available cluster number. typically last cluster no.
++ unsigned char FSI_Reserved2[12]; // reserved for future expansion. all zeros.
++ unsigned long FSI_TrailSig; // trail signature = 0xAA550000 for FSInfo Sector.
++
++
++#if defined(_WINCE_)
++}FSINFOstruc;
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed)) FSINFOstruc;
++#endif
++///////////////////////////////////////////////////////////////////////////////
++///////////////////////////////////////////////////////////////////////////////
++
++
++
++
++///////////////////////////////////////////////////////////////////////////////
++///////////////////// Logical Drv Structure /////////////////////////////
++///////////////////////////////////////////////////////////////////////////////
++#if defined(_WINCE_)
++#pragma pack(1)
++typedef struct _DRIVE_INFO
++#elif defined(_LINUX_)
++typedef struct _DRIVE_INFO
++#endif
++{
++
++ struct _PARTITION_INFO part; // partition info : 18 Bytes
++ struct _BSBPB_INFO BS;
++
++ unsigned char Drv_Type; // 0: HDD, 1: MMC/SD, 2: USB_DRV, 3: NAND_DRV
++ unsigned char FAT_Type; // 0: FAT32 1: FAT16 2:FAT32
++ unsigned short LUN; // logical unit number
++ unsigned short part_index; // logical partition or drive index(number).
++ unsigned long nCluster; // Temporary Variable for Disk Size
++ unsigned long FAT1StartSector; // FAT1 Start Sector
++ unsigned long FAT2StartSector; // FAT2 Start Sector
++ unsigned long FATSize; // FAT Size
++ unsigned long FirstDataSector; // Cluster Start Sector 2TH CLUSTER
++ unsigned long DirStartSector; // Root Start Sector
++ unsigned long DataSec; // Total Data Sector
++ unsigned long CountofClusters; // Total Count of clusters
++ unsigned long ClusterSize; // Cluster Byte Size
++ unsigned short ClusterShift; // Cluster Shift Factor Size
++ unsigned short BytsPerSecShift; // Sector Bytes Shift Factor Size
++ unsigned short SecPerClusShift; // Sectors Per Cluster Shift Factor Size
++ unsigned long UsedClusters; // Used total data capacity [byte]
++
++
++#if defined(_WINCE_)
++}DRIVE_INFOstruc;
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed)) DRIVE_INFOstruc;
++#endif
++///////////////////////////////////////////////////////////////////////////////
++///////////////////////////////////////////////////////////////////////////////
++
++
++
++
++///////////////////////////////////////////////////////////////////////////////
++////////////////////// File Entry Structure /////////////////////////////
++///////////////////////////////////////////////////////////////////////////////
++// FAT DIRECTORY ENTRY STRUCTURE(32 BYTES DATA).
++#if defined(_WINCE_)
++#pragma pack(1)
++typedef struct _FAT_DIR_ENTRY // FAT 32 bytes for directory entry
++#elif defined(_LINUX_)
++typedef struct _FAT_DIR_ENTRY // FAT 32 bytes for directory entry
++#endif
++{
++
++ unsigned char Name[8]; // file name field
++ unsigned char Extension[3]; // file extension field
++ unsigned char Attr; // File attributes
++ unsigned char NTRes; // reserved for Windows NT VFAT lower case flags.
++ unsigned char CrtTimeTenth; // Millisecond stamp at file creation time. 0-199/(2 sec)
++ unsigned short CrtTime; // Time file was created.
++ unsigned short CrtDate; // Date file was created.
++ unsigned short LstAccDate; // Last access date.
++ unsigned short FstClusHI; // High word of this entry's first cluster number. zero for FAT12/16.
++ unsigned short WrtTime; // Time of last write.
++ unsigned short WrtDate; // Date of last write.
++ unsigned short FstClusLO; // Low word of this entry's first cluster number.
++ unsigned long FileSize; // this file's size in bytes.
++
++
++#if defined(_WINCE_)
++}ENTRY_INFO;
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed)) ENTRY_INFO;
++#endif
++
++
++
++// FAT LONG DIRECTORY ENTRY STRUCTURE.
++#if defined(_WINCE_)
++#pragma pack(1)
++typedef struct _FAT_LONG_DIR_ENTRY // FAT 32 bytes for long directory entry
++#elif defined(_LINUX_)
++typedef struct _FAT_LONG_DIR_ENTRY // FAT 32 bytes for long directory entry
++#endif
++{
++
++ unsigned char LDIR_Ord; // order of this entry in the sequence of long dir entries.
++ char LDIR_Name1[10]; // char 1-5 of the long-name sub-component
++ unsigned char LDIR_Attr; // Attributes - must be ATTR_LONG_NAME(0x0F)
++ unsigned char LDIR_Type; // If zero, this entry is a sub-component of a long name.
++ unsigned char LDIR_Chksum; // checksum of name in the short dir entry
++ char LDIR_Name2[12]; // char 6-11 of the long-name sub-component
++ unsigned short LDIR_FstClusLO; // must be zero.
++ char LDIR_Name3[4]; // char 12-13 of the long-name sub-component
++
++
++#if defined(_WINCE_)
++}FAT_LDIR;
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed)) FAT_LDIR;
++#endif
++
++
++
++// FAT32 DIRECTORY ENTRY.
++typedef struct _FAT32DIRENT
++{
++ union
++ {
++ ENTRY_INFO s;
++ FAT_LDIR l;
++ }entry;
++}FAT32DIRENTstruc;
++
++
++
++// FILE OR DIRECTORY ENTRY POSITION STRUCTURE
++#if defined(_WINCE_)
++#pragma pack(1)
++typedef struct _FAT_ENTRY_POS
++#elif defined(_LINUX_)
++typedef struct _FAT_ENTRY_POS
++#endif
++{
++
++ int entryOffset;
++ int entrySectorOffset;
++ unsigned long dirCluster;
++ short entryCount;
++
++
++#if defined(_WINCE_)
++}ENTPOSstruc;
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed)) ENTPOSstruc;
++#endif
++///////////////////////////////////////////////////////////////////////////////
++///////////////////////////////////////////////////////////////////////////////
++
++
++
++
++///////////////////////////////////////////////////////////////////////////////
++////////////////////// FAT Cache Structure //////////////////////////////
++///////////////////////////////////////////////////////////////////////////////
++// FAT CACHE CONTROL
++#if defined(_WINCE_)
++#pragma pack(1)
++typedef struct _FAT_CACHE
++#elif defined(_LINUX_)
++typedef struct _FAT_CACHE
++#endif
++{
++
++ unsigned int InCache;
++ int drvTypeID;
++ int partID;
++ unsigned short status;
++
++
++#if defined(_WINCE_)
++}FATCACHEstruc;
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed)) FATCACHEstruc;
++#endif
++///////////////////////////////////////////////////////////////////////////////
++///////////////////////////////////////////////////////////////////////////////
++
++
++
++
++///////////////////////////////////////////////////////////////////////////////
++//////// Lock/Unlock struc. of Entry Sector bufferEntry ///////////////
++///////////////////////////////////////////////////////////////////////////////
++// ENTRY SECTOR BUFFER CONTROL
++#if defined(_WINCE_)
++#pragma pack(1)
++typedef struct _SECTOR_BUFF
++#elif defined(_LINUX_)
++typedef struct _SECTOR_BUFF
++#endif
++{
++
++ unsigned int InSector; // sector buffer address
++ int part_id; // partition index
++ unsigned short status; // lock or dirty bit
++
++
++#if defined(_WINCE_)
++}SECBUFFstruc;
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed)) SECBUFFstruc;
++#endif
++///////////////////////////////////////////////////////////////////////////////
++///////////////////////////////////////////////////////////////////////////////
++
++
++
++struct _FDIRENT;
++struct _FD;
++struct _DISK_INFO;
++
++//=============================================================================
++//*
++//*
++//* [ EXTERNAL VARIABLE DEFINE ]
++//*
++//*
++//=============================================================================
++//FAT File System Global Variables.
++extern int fat_total_partition; // total partition counter
++extern unsigned short fat_valid_partition; // primary & logical partition counter.
++
++extern unsigned char max_handle;
++extern unsigned char max_fd;
++extern unsigned char max_dir;
++extern HANDLERstruc *fHandler;
++extern FDstruc *fD;
++extern FDIRENTstruc *fDir;
++
++extern unsigned int fat_sbuffer[];
++extern unsigned short fat_cache[(512 * FAT_CACHE_SECTOR) >> 1]; // fat cache buffer = 512 bytes * 3
++
++extern DRIVE_INFOstruc driveInfo[FS_MAX_PART_NUMBER]; // current drive information
++extern FATCACHEstruc fatCache;
++extern SECBUFFstruc secBuffer;
++
++extern unsigned char *entry_buffer; // entry chunk buffer
++
++// FILE DATE & TIME DEFINITION
++extern volatile unsigned short file_year; // initial value = 1980
++extern volatile unsigned char file_month; // initial value = 1
++extern volatile unsigned char file_day; // initial value = 1
++extern volatile unsigned char file_hours; // initial value = 0
++extern volatile unsigned char file_min; // initial value = 0
++extern volatile unsigned char file_sec; // initial value = 0
++
++
++//=============================================================================
++//*
++//*
++//* [ FUCTIONS DEFINE ]
++//*
++//*
++//=============================================================================
++extern int FAT_GetNextCluster(int drvTypeID, int partID, unsigned long curr_cluster, unsigned long *next_cluster, void *fat_buff);
++extern int FAT_SetNextCluster(int drvTypeID, int partID, unsigned long curr_cluster, unsigned long next_cluster, void *fat_buff);
++extern unsigned long FAT_ReadEntrySector(int drvTypeID, int partID, unsigned long dir_cluster, unsigned long SectorIndex, void *buff);
++extern unsigned long FAT_ReadDirSector(int drvTypeID, int partID, unsigned long dir_cluster, unsigned long SectorIndex, void *buff, int *preSkip);
++extern int FAT_FindFileEntryWithID(int drvTypeID, unsigned long dirCluster, int file_id, struct _FDIRENT *pFDir);
++extern int FAT_FindFileEntryWithEntryOffset(int drvTypeID, int partID, unsigned long dirCluster, int file_id, struct _FDIRENT *pFDir);
++extern int FAT_FindDirEntryWithID(int drvTypeID, unsigned long dirCluster, int dir_id, struct _FDIRENT *pFDir);
++extern int FAT_FindDirEntryWithEntryOffset(int drvTypeID, int partID, unsigned long dirCluster, int dir_id, struct _FDIRENT *pDir);
++extern int FAT_GetDirContents(int drvTypeID, int partID, unsigned long start_cluster, int *file_count, int *subdir_count); // 0923
++extern int FAT_GetParentDirEntry(int drvTypeID, int partID, struct _FDIRENT *pDir, unsigned long dir_cluster);
++extern int FAT_FindDirEntryWithCluster(int drvTypeID, int partID, unsigned long start_cluster, unsigned long dir_cluster, struct _FDIRENT *pDir);
++extern int FAT_ReadCluster(int drvTypeID, int partID, unsigned short nSector, unsigned long currCluster, unsigned long offset, unsigned char *pBuff, int nRead, int clusterSize);
++extern int FAT_WriteCluster(int drvTypeID, int partID, unsigned short nSector, unsigned long currCluster, unsigned long offset, unsigned char *pBuff, int nWrite, int clusterSize);
++extern int FAT_GetEmptyCluster(int drvTypeID, int partID, unsigned long curr_cluster, unsigned long *Empty_Clus, void *fat_buff);
++extern int FAT_MakeSubDir(int drvTypeID, int partID, char *pName, unsigned long dirCluster, int option);
++extern int FAT_GetFreeEntryCount(int drvTypeID, int partID, unsigned long dirCluster, int *entryOffset,
++ int *entrySectorOffset, unsigned long *entryCluster, int entryNeeds );
++extern unsigned long FAT_GetFileStartCluster(int drvTypeID, int partID, unsigned long curr_cluster);
++extern int FAT_WriteEntrySector(int drvTypeID, int partID, unsigned long dir_cluster, int entrySectorOffset, void *buff);
++extern unsigned long FAT_WriteSector(int drvTypeID, int partID, unsigned long dir_cluster, int SectorIndex, void *buff);
++extern int FAT_ClearFileCluster(int drvTypeID, int partID, unsigned long curr_cluster, void *buff);
++extern int FAT_DeleteFileEntry(int drvTypeID, int partID, unsigned long dir_cluster, int sector_offset, int entry_offset, void *pBuff);
++extern int FAT_UpdateFATCache(void *buff);
++extern int FAT_MakeEmptyEntry(int drvTypeID, int partID, unsigned long uwStrCluster, int *npEntryOffset, int *npEntrySecOffset, unsigned long *lpEntryCluster, int entryNeeds );
++extern int FAT_MakeNewFD(int drvTypeID, struct _FDIRENT *pDir, char *pName, struct _FD *pFD);
++extern int FAT_MountDrive(int drvTypeID, unsigned int lun);
++extern int FAT_UnmountDrive(int drvTypeID);
++
++extern int FAT_MakeShortEntryFile(int drvTypeID, int partID, struct _FD *pFD, unsigned char *dir_ent);
++extern int FAT_FindShortFile(int drvTypeID, int partID, unsigned long dir_cluster, char *pName, struct _FDIRENT *pFDir);
++extern int FAT_readdir(int drvTypeID, int partID, unsigned long dir_cluster, struct _FDIRENT *pFDir, int mode, void *entry_buff);
++extern int FAT_GetEntryData(int drvTypeID, int partID, ENTPOSstruc *pEntPos, void *pBuff);
++extern unsigned char FAT_ChkSum(unsigned char *pFcbName);
++extern int FAT_FormatFAT(int drvTypeID, unsigned int partID, unsigned char SecPerClus,
++ void *SecBuff, struct _DISK_INFO *disk, unsigned char writeVolume);
++extern int FAT_FormatFAT32(int drvTypeID, unsigned int partID, unsigned char SecPerClus,
++ void *SecBuff, struct _DISK_INFO *disk, unsigned char writeVolume);
++extern void FAT_InitVariable(void);
++extern void FAT_InitDriveInfo(void);
++extern unsigned long FAT_ArithmeticOperationForCluster(int partID, int nCluster, char arithOperator);
++extern int FAT_UpdateEntryCountToCache(int drvTypeID, unsigned long dir_cluster, int nCount);
++extern void FAT_SetReservedSector(unsigned long sector_addr);
++extern unsigned long FAT_ReadTotalSectorFromHidden(unsigned long *);
++extern int FAT_GetUsedClusters(int drvTypeID, int partID);
++extern int FAT_MakeDotEntry(int drvTypeID, int partID, unsigned long start_cluster, unsigned long parent_cluster);
++extern int FAT_ClearCluster(int drvTypeID, int partID, unsigned long curr_cluster);
++extern unsigned long FAT_ReadSector(int drvTypeID, int partID, unsigned long dir_cluster, unsigned long SectorIndex, void *buff);
++
++extern int _FAT_MakeNewFD(struct _FDIRENT *pDir, char *pName, struct _FD *pFD);
++
++
++extern int drv_WriteSector(int drvTypeID, unsigned long LBA_addr, unsigned short nSector, void *buff);
++extern int drv_ReadSector(int drvTypeID, unsigned long LBA_addr, unsigned short nSector, void *buff);
++extern void lockSecBuff(void);
++extern void unlockSecBuff(void);
++extern void lockFATBuff(void);
++extern void unlockFATBuff(void);
++extern unsigned short makeWrtDate(unsigned short year, unsigned char month, unsigned char day);
++extern unsigned short makeWrtTime(unsigned char hours, unsigned char min, unsigned char sec);
++
++extern int check_free_entry(int drvTypeID, int partID, unsigned long dir_cluster, int *entryOffset, int *entrySectorOffset, unsigned long *entryCluster, int nEntry);
++extern int str_cmpu(void *sA, void *sB);
++extern int str_len16(void *pString);
++extern int find_DirEntry(int drvTypeID, int partID, unsigned long startCluster, unsigned char *pFileName);
++extern int makeShortName(void *pN, void *sN, int num_tail, unsigned short type);
++extern int makeDirEntry(void *sName, unsigned char attr, unsigned long entry_cluster, unsigned char *dir_ent);
++
++extern int FAT_getUsedClus_Common(int drvTypeID, int partID, unsigned short nSector, unsigned long FAT1_PhySector);
++extern int FAT_fatCache_Common(int drvTypeID, int partID, unsigned long FAT2_PhySector, unsigned long FAT_Sector, unsigned short nSector, unsigned char *sbuffer, unsigned char RWflag);
++extern unsigned int FAT_Format_ClearCommon(int drvTypeID, int sectorPerFAT, unsigned long nSector, unsigned char *pBuff, void *SecBuff, unsigned char multiFlag);
++extern int FAT_FormatRE_Common(int drvTypeID, int halfEntryNum, unsigned nSector, unsigned char writeVolume, void *pBuff, unsigned char *BS_VolLab);
++
++extern unsigned int FAT_makeMBR(int drvTypeID, unsigned int *numOfSecPR, unsigned int *validFAT, unsigned char SecPerClus, void *pBuff, struct _DISK_INFO *disk);
++
++extern int FAT_CheckDirContentsExist(int drvTypeID, int partID, unsigned long start_cluster, int *file_count, int *subdir_count);
++extern short getLongEntryName(int drvTypeID, int partID, struct _FDIRENT *pFDir, unsigned long sector_offset, int entry_offset, struct _FAT_LONG_DIR_ENTRY *entry, void *buff);
++extern unsigned long cluster2sector(int partID, unsigned long cluster);
++
++extern int FDISK_PartitionWrite(int drvTypeID, unsigned int partitionID, unsigned int relativeLBA, void *pBuff, unsigned short nSector);
++extern int FDISK_PartitionRead(int drvTypeID, unsigned int partitionID, unsigned int relativeLBA, void *pBuff, unsigned short nSector);
++
++#endif // __FAT_H__
+diff --git a/drivers/block/tcc/inc/fwdn/file.h b/drivers/block/tcc/inc/fwdn/file.h
+new file mode 100644
+index 0000000..c7e395d
+--- /dev/null
++++ b/drivers/block/tcc/inc/fwdn/file.h
+@@ -0,0 +1,284 @@
++/*****************************************************************************/
++// File Defition for Telechips Software.
++//
++// Copyright 2008 Telechips, Inc.
++//
++/*****************************************************************************/
++
++#ifndef __FILE_H__
++#define __FILE_H__
++
++//=============================================================================
++//*
++//*
++//* [ EXTERNAL DEFINATION ]
++//*
++//*
++//=============================================================================
++#define ROOT_DIR_ID 0xFFFF0000
++
++// FILE ACCESS MODE
++#define FILE_ACCESSMASK 0x07
++#define FILE_READ 0x00 /* File Read Only */
++#define FILE_WRITE 0x01 /* File Write Only */
++#define FILE_REWRITE 0x02 /* File Read/Write */
++#define FILE_COPY 0x10
++
++#define FILE_OEXIST 0x00010000 /* Open Existing File */
++#define FILE_OTRUNC 0x00020000 /* Truncate Existing File */
++#define FILE_OAPPEND 0x00040000 /* Open Exisging File at EOF */
++#define FILE_OCREAT 0x00100000 /* Create Unexisting File */
++
++// FILE ATTRIBUTE
++#define FILE_NORMAL 0x00
++#define FILE_READ_ONLY 0x01
++#define FILE_HIDDEN 0x02
++#define FILE_SYSTEM 0x04
++#define FILE_VOLUME_ID 0x08
++#define FILE_DIRECTORY 0x10
++#define FILE_ARCHIVE 0x20
++
++// FILE CREATE OPTION
++#define FILE_NO_TILDE 0x0100 /* do not make file with numeric-tail */
++#define FILE_NO_CMP 0x0200
++
++// REFERENCE POINT OF FILE POINTER.
++#define FSEEK_SET 0 // file beginning
++#define FSEEK_CUR 1 // current FP position
++#define FSEEK_END 2 // file ending
++
++#define FILE_FIND_FIRST 0x00
++#define FILE_FIND_NEXT 0x01
++#define FILE_SKIP_LFN 0x02
++#define FILE_SAVE_S_ENTRY 0x04
++
++//=============================================================================
++//*
++//*
++//* [ ERROR CODE ENUMERATION ]
++//*
++//*
++//=============================================================================
++typedef enum
++{
++ ERR_FS_FAIL = -1,
++ ERR_FS_FULL_ROOT_ENTRY = -2
++} FS_ERROR;
++
++//=============================================================================
++//*
++//*
++//* [ STRUCT DEFINE ]
++//*
++//*
++//=============================================================================
++typedef struct _HANDLER // FILE HANDLER STRUCTURE.
++{
++ int lock; // used handle
++ unsigned long usage; // Usage of this handle. Read, Write, Copy etc...
++ unsigned char *pEntry; // entry chunk pointer
++ short nEntry; // number of entry in entry chunk data. 32 [byte]
++}HANDLERstruc;
++
++typedef struct _FD // FILE DESCRIPTOR STRUCTURE.
++{
++ int part_id; // current partition index
++ int file_id; // file id in a parent directory. NOT used anymore.
++ unsigned long dirCluster; // number of the start cluster of a parent directory
++
++ char lFileName[258]; // long file or dir name
++ char sFileName[13]; // short file or dir name
++ long fileSize; // file size [byte].
++ unsigned long startCluster; // number of the start cluster of a file or directory
++
++ int pre_clusterCnt;
++ unsigned long cntCluster;
++
++ int entryOffset; // short entry offset(slot) in current sector
++ int entrySectorOffset; // current sector number in current directory
++ unsigned long entryCluster; // just debugging
++
++ unsigned long clusterSize; // cluster size of the current partition [byte]
++ unsigned short type; // file type or attribute. (READ ONLY, HIDDEN, SYSTEM, DIRECTORY, ARCHIVE)
++ unsigned long mode; // Access Mode of file. (READ, WRITE, REWRITE)
++ unsigned long offset; // file pointer [byte]
++ int refCnt; // referenct flag. lower 16 bit : referenct count, upper 16 bit : dirty bit
++}FDstruc;
++
++typedef struct _FDIRENT // FILE OR DIRECTORY ENTRY STRUCTURE.
++{
++ char lFileName[258]; // long file name
++ char sFileName[13]; // short file name
++ unsigned char ref;
++ long fileSize; // file size [byte]
++ unsigned short type; // file attribute.
++
++ unsigned long startCluster; // cluster of the current file or directory
++ unsigned long parentCluster; // cluster of the parent directory
++
++ int entryOffset; // short entry offset(slot) in current sector
++ int entrySectorOffset; // current sector number in current directory
++ unsigned long entryCluster; // just debugging
++
++ int file_cnt; // file count. only valid when FILE_Refresh() was excuted.
++ int subdir_cnt; // sub-directory(folder) count. only valid when FILE_Refresh() was excuted.
++ int part_id; // current partition index
++ short entryCount; // total entry count
++}FDIRENTstruc;
++
++// SHORT DIRECTORY ENTRY STRUCTURE(32 BYTES DATA).
++#if defined(_WINCE_)
++#pragma pack(1)
++typedef struct _SFN_DIR_ENTRY // FAT 32 bytes for directory entry
++#elif defined(_LINUX_)
++typedef struct _SFN_DIR_ENTRY // FAT 32 bytes for directory entry
++#endif
++{
++ unsigned char Name[8];
++ unsigned char Extension[3];
++ unsigned char Attr;
++ unsigned char NTRes;
++ unsigned char CrtTimeTenth;
++ unsigned short CrtTime;
++ unsigned short CrtDate;
++ unsigned short LstAccDate;
++ unsigned short FstClusHI;
++ unsigned short WrtTime;
++ unsigned short WrtDate;
++ unsigned short FstClusLO;
++ unsigned long FileSize;
++#if defined(_WINCE_)
++}SFN_INFO;
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed)) SFN_INFO;
++#endif
++
++
++#if defined(_WINCE_)
++#pragma pack()
++typedef struct _DIRENT // FILE OR DIRECTORY ENTRY STRUCTURE. - for FILE_ReadDir()
++#elif defined(_LINUX_)
++typedef struct _DIRENT // FILE OR DIRECTORY ENTRY STRUCTURE. - for FILE_ReadDir()
++#endif
++{
++ SFN_INFO sEntry; // short entry slot
++ char *lFileName; // pointer of the long file name
++ char *sFileName; // pointer of the short file name
++ unsigned char LFNflag; // 0: no LFN, 1: has LFN
++ unsigned short type; // file attribute. file or directory
++ unsigned long startCluster; // cluster of the directory or file
++ unsigned int offset;
++ int part_id; // current partition index
++#if defined(_WINCE_)
++}DIRENTstruc;
++#pragma pack()
++#elif defined(_LINUX_)
++}DIRENTstruc;
++#endif
++
++#ifndef _DISKINFOstruc_
++#define _DISKINFOstruc_
++#if defined(_WINCE_)
++#pragma pack(1)
++typedef struct _DISK_INFO // DISK INFORMATION STRUCTURE. - for File_Format()
++#elif defined(_LINUX_)
++typedef struct _DISK_INFO // DISK INFORMATION STRUCTURE. - for File_Format()
++#endif
++{
++ unsigned short head;
++ unsigned short cylinder;
++ unsigned short sector;
++ unsigned short sector_size;
++#if defined(_WINCE_)
++}DISKINFOstruc;
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed)) DISKINFOstruc;
++#endif
++#endif //#ifndef _DISKINFOstruc_
++
++
++#if defined(_WINCE_)
++#pragma pack(1)
++typedef struct _DRV_INFO // PARTITION (OR DRIVE) SIMPLE INFORMATION
++#elif defined(_LINUX_)
++typedef struct _DRV_INFO // PARTITION (OR DRIVE) SIMPLE INFORMATION
++#endif
++{
++ unsigned char Drv_Type; // HDD_DRV, MMC_DRV, USB_DRV, NAND_DRV
++ unsigned char FAT_Type; // FAT32, FAT16, FAT32
++ unsigned short part_id; // logical partition or drive index(number).
++ unsigned short BytsPerSec; // Count of bytes per sector. normally 512
++ unsigned long ClusterSize; // Cluster Byte Size
++ unsigned long CountofClusters; // total number of clusters
++ unsigned long UsedClusters; // Used total data capacity [byte]
++#if defined(_WINCE_)
++}DRVINFOstruc;
++#pragma pack()
++#elif defined(_LINUX_)
++} __attribute__((packed)) DRVINFOstruc;
++#endif
++
++//=============================================================================
++//*
++//*
++//* [ FUCTIONS DEFINE ]
++//*
++//*
++//=============================================================================
++extern FDstruc *FILE_pGetFD(int nFD);
++extern FDIRENTstruc *FILE_pGetDIR(int dir_num);
++extern FDIRENTstruc *FILE_pGetFDir(int nFDir);
++extern int FILE_InitSystem(void);
++extern int FILE_Write(int nHandle, void *pBuff, int size); // write a file
++extern int FILE_OpenDirByEntryId(int drvTypeID, int partID, int dir_id, int dir_num); // open directory.
++extern int FILE_MakeDir(char *pName, int dir_num); // make sub-directory
++extern int FILE_MakeDirWithHDAttr(char *pName, int dir_num); // make sub-directory with HIDDEN attribute
++extern int FILE_MakeHideDir(char *pName, int dir_num);
++extern int FILE_Create(char *pName, unsigned short type, int dir_num); // create a file.
++extern int FILE_CreateLFN(void *pName, unsigned short type, int dir_num); // create a file that name has unicode
++extern int FILE_RemoveByEntryId(int dir_num, int file_id); // remove a file
++extern int FILE_Change2ParentDir(int dir_num); //change directory to parent directory
++extern int FILE_Refresh(int dir_num); // reload current directory information
++extern unsigned long FILE_TotalDiskCluster(int drvTypeID);
++extern unsigned long FILE_AvailableDiskCluster(int drvTypeID); // get free size of the current drive
++extern unsigned long FILE_GetClusterSize(int drvTypeID);
++extern int FILE_OpenName(char *pName, char *mode, int dir_num);
++extern int FILE_OpenDirName(char *pName, char *mode, int dir_num);
++extern int FILE_ReadDir(int mode, int dir_num, FDIRENTstruc *pFDir, DIRENTstruc *pEnt);
++extern void FILE_InitFDIRstruc(FDIRENTstruc *pFDir);
++extern int FILE_OpenDirWithCluster(int partID, unsigned long dir_cluster, int dir_num);
++extern int FILE_Copy(int dir_num, int sHandle, long *copy_status);
++extern int FILE_Format(int drvTypeID, int partID, unsigned char writeVolume,
++ unsigned char SecPerClus, unsigned int CntOfClus, struct _DISK_INFO *disk);
++
++extern int FILE_FormatMBR(int drvTypeID, unsigned char writeVolume, unsigned char SecPerClus, unsigned int *numOfSecPR, unsigned int *validFAT, struct _DISK_INFO *disk);
++
++
++extern int FILE_DiskInfo(int partID, DRVINFOstruc *pDrive);
++extern int FILE_GetValidPartNum(void);
++extern int FILE_RemoveDirByEntryId(int dir_num, int dir_id);
++extern int FILE_RemoveWithHandle(int dir_num, int nHandle);
++extern void FILE_UpdateDate(unsigned short year, unsigned char month, unsigned char day);
++extern void FILE_UpdateTime(unsigned char hours, unsigned char min, unsigned char sec);
++extern int FILE_CheckRootDir(int dir_num);
++extern int FILE_GetUsedClusters(int drvTypeID);
++extern int FILE_RenameLFN(int nHandle, void *pName, int dir_num);
++extern int FILE_OpenDirOnlySearch(int partID, unsigned long dir_cluster, int dir_num);
++
++
++#ifdef NED_INCLUDE
++#include "NED/NED_FS.H"
++#else
++extern int FILE_OpenByEntryId(int file_id, unsigned long mode, int dir_num); // open a file. get handle
++extern int FILE_Close(int nHandle); // close a file. return handle
++extern int FILE_Read(int nHandle, void *pBuff, int size); // read a file
++extern int FILE_Seek(int nHandle, long offset, int whence); // move file pointer.
++extern int FILE_Read_bs(int nHandle, void *pBuff, int size); // special function
++extern long FILE_Tell(int nHandle); // get a current file pointer
++extern int FILE_Length(int nHandle); // get a current file size
++#endif
++
++#endif
++
+diff --git a/drivers/block/tcc/inc/fwdn/fwdn_drv_v3.h b/drivers/block/tcc/inc/fwdn/fwdn_drv_v3.h
+new file mode 100644
+index 0000000..8471c96
+--- /dev/null
++++ b/drivers/block/tcc/inc/fwdn/fwdn_drv_v3.h
+@@ -0,0 +1,172 @@
++/****************************************************************************
++ * FileName : Fwdn_drv_v3.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++#ifndef _FWDN_DRV_V3_H_
++#define _FWDN_DRV_V3_H_
++
++#if defined(_LINUX_)
++#include <tnftl/nand_drv.h>
++#elif defined(_WINCE_)
++#include "nand_drv.h"
++#endif
++
++enum
++{
++ ERR_FWDN_DRV_WRONG_PARAMETER = 0x10000000,
++ ERR_FWDN_DRV_DISK_IOCTRL_DEV_INITIALIZE,
++ ERR_FWDN_DRV_DISK_COMPARE,
++ ERR_FWDN_DRV_DISK_WRITE,
++ ERR_FWDN_DRV_DISK_READ,
++};
++
++enum
++{
++ FWDN_DRV_TARGET_NAND = 1,
++ FWDN_DRV_TARGET_NOR,
++ FWDN_DRV_TARGET_TRIFLASH,
++ FWDN_DRV_TARGET_EEPROM,
++ FWDN_DRV_TARGET_SFLASH,
++ FWDN_DRV_TARGET_HDD
++};
++
++enum
++{
++ FWDN_DISK_NONE,
++ FWDN_DISK_HDD,
++ FWDN_DISK_MMC,
++ FWDN_DISK_UHP,
++ FWDN_DISK_NAND,
++ FWDN_DISK_TRIFLASH,
++ FWDN_DISK_NOR,
++ FWDN_DISK_SFLASH,
++ FWDN_DISK_MAX
++};
++
++enum
++{
++ SN_NOT_EXIST = 0,
++ SN_VALID_16,
++ SN_INVALID_16,
++ SN_VALID_32,
++ SN_INVALID_32
++};
++
++
++typedef int (*fpFWDN_DRV_FirmwareWrite_ReadFromHost)(unsigned char *buff, unsigned int size, unsigned int srcAddr, unsigned int percent);
++typedef int (*FXN_FWDN_DRV_RquestData)(unsigned char *buff, unsigned int size);
++typedef unsigned int (*FXN_FWDN_DRV_ReadFromHost)(void *buff, unsigned int size);
++typedef unsigned int (*FXN_FWDN_DRV_SendToHost)(void *buff, unsigned int size);
++
++typedef struct _tag_DeviceInfoType {
++ unsigned int DefaultDiskType; // Default Disk Type. nand, tri-flash, hdd ...
++ unsigned int DevSerialNumberType; // Device Serial Number type SN_NOT_EXIST..
++ unsigned char DevSerialNumber[32];
++} FWDN_DEVICE_INFORMATION, *pFWDN_DEVICE_INFORMATION;
++
++typedef struct _tag_NAND_HiddenSizeInfo {
++ unsigned int HiddenPageSize; // Default Hidden Area Pages
++ unsigned int MultiHiddenAreaNum; // Multi Hidden Num
++ unsigned int MultiHiddenSize[8]; // Multi Hidden Configuration
++ unsigned int ROAreaSize;
++} NAND_HIDDEN_INFO, *pNAND_HIDDEN_INFO;
++
++typedef struct _tag_NAND_DISK_INFO_T {
++ unsigned int bootSize_MB;
++ unsigned int totalSize_MB;
++ unsigned int multiHiddenSystemSize_MB;
++} NAND_DISK_INFO_T;
++
++typedef struct __NAND_DeviceInfo {
++ unsigned short int DevID[8];
++ unsigned int MediaNums; // Media Number of NANDFLASH
++ unsigned int MAX_ROMSize;
++ unsigned int ExtendedPartitionNum;
++ unsigned int ExtPartitionSize[12];
++ unsigned int ExtPartitionWCacheNum[12];
++ unsigned int ROAreaSize;
++ unsigned short int PBpV; // Physical all Block Number
++ unsigned short int PpB; // Page Number Per Block
++ unsigned short int PageSize; // Page Size
++ unsigned short int SpareSize;
++} NAND_DEVICE_INFO, *pNAND_DEVICE_INFO;
++
++#ifdef TRIFLASH_INCLUDE
++#define MMC_DISK_MAX_HIDDEN_NUMBER 4
++
++typedef struct _tag_MMC_DISK_INFO_T {
++ unsigned int nTotalSector;
++ unsigned int nBootSector;
++ unsigned int nHiddenNum;
++ unsigned int nHiddenSector[MMC_DISK_MAX_HIDDEN_NUMBER];
++ unsigned int nBytePerSector;
++} MMC_DISK_INFO_T;
++#endif
++//==============================================================
++//
++// Global Variables
++//
++//==============================================================
++extern FWDN_DEVICE_INFORMATION FWDN_DeviceInformation;
++extern unsigned int gFWDN_DRV_ErrorCode;
++
++#define FWDN_DRV_GetErrorCode() gFWDN_DRV_ErrorCode
++#define FWDN_DRV_ClearErrorCode() gFWDN_DRV_ErrorCode = 0
++#define FWDN_DRV_SetErrorCode(a) gFWDN_DRV_ErrorCode = a
++
++//==============================================================
++//
++// Function Prototypes
++//
++//==============================================================
++void initSourcePosition(void);
++int setSourcePosition(int offset);
++
++void FWDN_InitCACHE(void);
++void FWDN_SetRWSize(unsigned long uSize);
++
++void FWDN_DRV_SaveSdCfg(unsigned int sdCfg);
++unsigned int FWDN_DRV_GetSdCfg(void);
++pFWDN_DEVICE_INFORMATION FWDN_DRV_GetDeviceInfo(void);
++int FWDN_DRV_SerialNumberWrite(unsigned char *serial, unsigned int overwrite);
++int FWDN_DRV_FirmwareWrite(unsigned int fwSize, unsigned int TargetMemType, fpFWDN_DRV_FirmwareWrite_ReadFromHost fFWDN_DRV_FirmwareWrite_ReadFromHost);
++int FWDN_DRV_FirmwareWrite_Read(unsigned char *buff, unsigned int size, unsigned int percent);
++
++void FWDN_DRV_DISK_Select(unsigned char fwdnDiskType);
++int FWDN_DRV_DISK_Init(TNFTL_CALLBACK_HANDLER pCallBackHandler, unsigned int stage, void *pInfo, unsigned short infoSize);
++void FWDN_DRV_DISK_InfoRead(void *pDiskInfo, unsigned char *pSize);
++
++int FWDN_DRV_DISK_Read(unsigned int lba, unsigned int size, FXN_FWDN_DRV_SendToHost fxnFwdnDrvSendToHost);
++int FWDN_DRV_DISK_Write(unsigned int lba, unsigned int size, FXN_FWDN_DRV_ReadFromHost fxnFwdnDrvReadFromHost);
++
++void FWDN_DRV_DISK_Hidden_InfoRead(void *pInfo, unsigned char *pSize);
++int FWDN_DRV_DISK_Hidden_Clean(void);
++int FWDN_DRV_DISK_Hidden_Write(unsigned int index, unsigned int startpage, unsigned int sizebyte, FXN_FWDN_DRV_RquestData fxnFwdnDrvRequestData);
++int FWDN_DRV_DISK_MTD_Write(unsigned int startpage, unsigned int sizebyte, FXN_FWDN_DRV_ReadFromHost fxnFwdnDrvReadFromHost);
++
++int FWDN_DRV_DISK_DATA_Partition(void *pMultiPartitionSizeArray, unsigned int length);
++int FWDN_DRV_DISK_DATA_Image_Write(unsigned int nPartitionID, unsigned int offset, unsigned int size, FXN_FWDN_DRV_RquestData fxnFwdnDrvRequestData);
++int FWDN_DRV_DISK_FS_Mount(unsigned int partID);
++int FWDN_DRV_DISK_FS_Format(unsigned int partID, char *volumeParam);
++int FWDN_DRV_DISK_FS_MkDir(unsigned char *name);
++int FWDN_DRV_DISK_FS_ChDir(unsigned char *name);
++int FWDN_DRV_DISK_FS_FileWrite(unsigned char *name, unsigned int size, FXN_FWDN_DRV_RquestData fxnFwdnDrvRequestData);
++
++unsigned char FWDN_DRV_DISK_DUMP_InfoRead(unsigned char *pBuf);
++int FWDN_DRV_DISK_DUMP_BlockRead(unsigned int Param0, unsigned int Param1, unsigned int Param2, FXN_FWDN_DRV_SendToHost fxnFwdnDrvSendToHost);
++
++unsigned int FWDN_FNT_SetSN(unsigned char* ucTempData, unsigned int uiSNOffset);
++void FWDN_FNT_VerifySN(unsigned char* ucTempData, unsigned int uiSNOffset);
++void FWDN_FNT_InsertSN(unsigned char *pSerialNumber);
++unsigned char FWDN_DRV_FirmwareMemoryType(void);
++#endif // _FWDN_DRV_H_
++
++/* end of file */
++
+diff --git a/drivers/block/tcc/inc/fwdn/fwdn_drv_v7.h b/drivers/block/tcc/inc/fwdn/fwdn_drv_v7.h
+new file mode 100644
+index 0000000..ffd38bf
+--- /dev/null
++++ b/drivers/block/tcc/inc/fwdn/fwdn_drv_v7.h
+@@ -0,0 +1,158 @@
++/****************************************************************************
++ * FileName : Fwdn_drv_v7.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++#ifndef _FWDN_DRV_V7_H_
++#define _FWDN_DRV_V7_H_
++
++#define FWDN_DEVICE_INIT_BITMAP_LOW_FORMAT (1<<0)
++#define FWDN_DEVICE_INIT_BITMAP_DUMP (1<<1)
++#define FWDN_DEVICE_INIT_BITMAP_UPDATE (1<<2)
++#define FWDN_DEVICE_INIT_BITMAP_LOW_FORMAT_LEVEL2 (1<<3)
++
++enum
++{
++ ERR_FWDN_DRV_WRONG_PARAMETER = 0x10000000,
++ ERR_FWDN_DRV_IOCTRL_DEV_INITIALIZE,
++ ERR_FWDN_DRV_AREA_WRITE_COMPARE,
++ ERR_FWDN_DRV_RESET_NOT_SUPPORT,
++ ERR_FWDN_DRV_INSUFFICIENT_MEMORY,
++ ERR_FWDN_DRV_AREA_WRITE,
++ ERR_FWDN_DRV_AREA_READ,
++};
++
++enum
++{
++ FWDN_DISK_NONE,
++ FWDN_DISK_HDD,
++ FWDN_DISK_MMC,
++ FWDN_DISK_UHP,
++ FWDN_DISK_NAND,
++ FWDN_DISK_TRIFLASH,
++ FWDN_DISK_NOR,
++ FWDN_DISK_SFLASH,
++ FWDN_DISK_MAX
++};
++
++enum
++{
++ SN_NOT_EXIST = 0,
++ SN_VALID_16,
++ SN_INVALID_16,
++ SN_VALID_32,
++ SN_INVALID_32
++};
++
++
++typedef int (*FXN_FWDN_DRV_FirmwareWrite_ReadFromHost)(unsigned char *buff, unsigned int size, unsigned int srcAddr, unsigned int percent);
++typedef unsigned int (*FXN_FWDN_DRV_ReadFromHost)(void *buff, unsigned int size);
++typedef unsigned int (*FXN_FWDN_DRV_SendToHost)(void *buff, unsigned int size);
++typedef void (*FXN_FWDN_DRV_Response_RequestData)(unsigned int dataSize);
++typedef int (*FXN_FWDN_DRV_RquestData)(unsigned char *buff, unsigned int size);
++typedef void (*FXN_FWDN_DRV_SendStatus)(unsigned int param0, unsigned int param1, unsigned int param2);
++typedef void (*FXN_FWDN_DRV_Progress)( unsigned int percent );
++
++typedef struct _tag_FWDN_AREA_T {
++ unsigned int nSector;
++ char name[16];
++} FWDN_AREA_T;
++
++#define FWDN_AREA_LIST_MAX 20
++typedef struct _tag_DeviceInfoType {
++ unsigned int DevSerialNumberType; // Device Serial Number type SN_NOT_EXIST..
++ unsigned char DevSerialNumber[32];
++ FWDN_AREA_T area[FWDN_AREA_LIST_MAX]; // Default Area = area[0]
++} FWDN_DEVICE_INFORMATION, *pFWDN_DEVICE_INFORMATION;
++
++typedef struct _tag_NAND_HiddenSizeInfo {
++ unsigned int HiddenNum; // Total Hidden Area Num
++ unsigned int HiddenPageSize[12]; // Each Hidden Area's Size
++ unsigned int RO_PageSize;
++} NAND_PARTITION_INFO, *pNAND_HIDDEN_INFO;
++
++ typedef struct __NAND_DeviceInfo {
++ unsigned short int DevID[8];
++ unsigned int MediaNums; // Media Number of NANDFLASH
++ unsigned int MAX_ROMSize;
++ unsigned int ExtendedPartitionNum;
++ unsigned int ExtPartitionSize[12];
++ unsigned int ExtPartitionWCacheNum[12];
++ unsigned int ROAreaSize;
++ unsigned short int PBpV; // Physical all Block Number
++ unsigned short int PpB; // Page Number Per Block
++ unsigned short int PageSize; // Page Size
++ unsigned short int SpareSize;
++} NAND_DEVICE_INFO, *pNAND_DEVICE_INFO;
++
++typedef struct _tag_NAND_DISK_INFO_T {
++ unsigned int bootSize_MB;
++ unsigned int diskSize_MB;
++} NAND_DISK_INFO_T;
++
++//==============================================================
++//
++// Global Variables
++//
++//==============================================================
++extern FWDN_DEVICE_INFORMATION FWDN_DeviceInformation;
++extern unsigned int gFWDN_DRV_ErrorCode;
++
++#define FWDN_DRV_GetErrorCode() gFWDN_DRV_ErrorCode
++#define FWDN_DRV_ClearErrorCode() gFWDN_DRV_ErrorCode = 0
++#define FWDN_DRV_SetErrorCode(a) gFWDN_DRV_ErrorCode = a
++
++//==============================================================
++//
++// Function Prototypes
++//
++//==============================================================
++void initSourcePosition(void);
++
++//void FWDN_CheckOption(void);
++
++// for Device
++void FWDN_DRV_Reset(void);
++int FWDN_DRV_SessionStart(void);
++int FWDN_DRV_SessionEnd(unsigned int bSuccess);
++int FWDN_DRV_Init(unsigned int bmFlag, const FXN_FWDN_DRV_Progress fxnFwdnDrvProgress, char *message, unsigned int messageSize);
++pFWDN_DEVICE_INFORMATION FWDN_DRV_GetDeviceInfo(void);
++int FWDN_DRV_SerialNumberWrite(unsigned char *serial, unsigned int overwrite);
++int FWDN_DRV_FirmwareWrite(unsigned int fwSize, FXN_FWDN_DRV_FirmwareWrite_ReadFromHost fxnFWDN_DRV_FirmwareWrite_ReadFromHost);
++int FWDN_DRV_FirmwareWrite_Read(unsigned char *buff, unsigned int size, unsigned int percent);
++
++#if 0//TNFTL_V7_INCLUDE
++int FWDN_DRV_NAND_GANG_Format(void);
++int FWDN_DRV_NAND_GANG_Write( NAND_PART_INFO *sNandPartInfo, FXN_FWDN_DRV_RquestData fxnFwdnDrvRequestData );
++#endif
++
++// for Disk
++int FWDN_DRV_AREA_Write(char *name, unsigned int lba, unsigned int nSector, FXN_FWDN_DRV_RquestData fxnFwdnDrvRequestData);
++int FWDN_DRV_AREA_CalcCRC( char *name
++ ,unsigned int lba
++ ,unsigned int nSector
++ ,unsigned int *pCrc
++ ,FXN_FWDN_DRV_SendStatus fxnFwdnDrvSendStatus );
++
++unsigned char FWDN_DRV_DUMP_InfoRead(void *pBuf);
++int FWDN_DRV_DUMP_BlockRead(unsigned int Param0, unsigned int Param1, unsigned int Param2,
++ FXN_FWDN_DRV_Response_RequestData fxnFwdnDrvResponseRequestData,
++ FXN_FWDN_DRV_SendToHost fxnFwdnDrvSendToHost);
++int FWDN_DRV_DUMP_BlockWrite(unsigned int Param0, unsigned int Param1, unsigned int Param2,
++ FXN_FWDN_DRV_Response_RequestData fxnFwdnDrvResponseRequestData,
++ FXN_FWDN_DRV_ReadFromHost fxnFwdnDrvReadFromHost);
++
++unsigned int FWDN_FNT_SetSN(unsigned char* ucTempData, unsigned int uiSNOffset);
++void FWDN_FNT_VerifySN(unsigned char* ucTempData, unsigned int uiSNOffset);
++void FWDN_FNT_InsertSN(unsigned char *pSerialNumber);
++unsigned char FWDN_DRV_FirmwareStorageID(void);
++#endif // _FWDN_DRV_V7_H_
++
++/* end of file */
++
+diff --git a/drivers/block/tcc/inc/fwdn/fwdn_protocol_v3.h b/drivers/block/tcc/inc/fwdn/fwdn_protocol_v3.h
+new file mode 100644
+index 0000000..f330e29
+--- /dev/null
++++ b/drivers/block/tcc/inc/fwdn/fwdn_protocol_v3.h
+@@ -0,0 +1,117 @@
++#ifndef __FWDN_PROTOCOL_V2__
++#define __FWDN_PROTOCOL_V2__
++
++////////////////////////////////////////////////////////////////////////////
++//
++// FWDN Protocol V3
++//
++////////////////////////////////////////////////////////////////////////////
++
++////////////////////////////////////////////////////////////////////////////
++// FWDN Command
++////////////////////////////////////////////////////////////////////////////
++#define FWDN_CMD_NONE 0x0000
++#define FWDN_CMD_UBS_PING 0x0001
++#define FWDN_CMD_UBS_INITCODE_LOAD 0x0002
++#define FWDN_CMD_UBS_ROM_LOAD 0x0003
++
++#define FWDN_CMD_PING 0x0100
++#define FWDN_CMD_DEVICE_RESET 0x0101
++#define FWDN_CMD_DEVICE_SETTING 0x0102
++#define FWDN_CMD_DEVICE_INFO_READ 0x0103
++#define FWDN_CMD_SERIAL_NUMBER_WRITE 0x0104
++#define FWDN_CMD_FIRMWARE_WRITE 0x0105
++#define FWDN_CMD_SESSION_START 0x0106
++#define FWDN_CMD_SESSION_END 0x0107
++
++#define FWDN_CMD_DISK_SELECT 0x0200
++#define FWDN_CMD_DISK_INIT 0x0201
++#define FWDN_CMD_DISK_INFO_READ 0x0202
++
++#define FWDN_CMD_DISK_HIDDEN_INFO_READ 0x0210
++#define FWDN_CMD_DISK_HIDDEN_CLEAN 0x0211
++#define FWDN_CMD_DISK_HIDDEN_WRITE 0x0212
++#define FWDN_CMD_DISK_HIDDEN_READ 0x0213
++#define FWDN_CMD_DISK_MTD_WRITE 0x0214
++
++#define FWDN_CMD_DISK_DATA_PARTITION 0x0220
++#define FWDN_CMD_DISK_DATA_READ 0x0221
++#define FWDN_CMD_DISK_DATA_WRITE 0x0222
++#define FWDN_CMD_DISK_DATA_IMAGE_WRITE 0x0223
++
++#define FWDN_CMD_DISK_DATA_FS_MOUNT 0x0230
++#define FWDN_CMD_DISK_DATA_FS_FORMAT 0x0231
++#define FWDN_CMD_DISK_DATA_FS_MKDIR 0x0232
++#define FWDN_CMD_DISK_DATA_FS_CHDIR 0x0233
++#define FWDN_CMD_DISK_DATA_FS_FILE_WRITE 0x0234
++
++#define FWDN_CMD_DISK_DUMP_INFO_READ 0x0240
++#define FWDN_CMD_DISK_DUMP_BLOCK_READ 0x0241
++
++#define FWDN_CMD_TEST_SEND 0x0300
++#define FWDN_CMD_TEST_RECEIVE 0x0301
++
++#define FWDN_CMD_TNFTL_V5_DEBUG 0x0F00
++
++
++////////////////////////////////////////////////////////////////////////////
++// FWDN Response Ack Type
++////////////////////////////////////////////////////////////////////////////
++#define FWDN_RSP_NACK 0x00
++#define FWDN_RSP_ACK 0x01
++#define FWDN_RSP_NYET 0x02
++
++
++////////////////////////////////////////////////////////////////////////////
++// FWDN Command / Response Signatures
++////////////////////////////////////////////////////////////////////////////
++#define FWDN_COMMAND_SIGNATURE 0x43445746L //"FWDC" ; FWDn Command
++#define FWDN_RESPONSE_SIGNATURE 0x52445746L //"FWDR" ; FWDn Response
++
++
++#define FWDN_EXTRA_RSP_MAX_SIZE 0xFF
++
++#if defined(_WINCE_)
++#pragma pack(push, 1)
++#endif
++
++typedef struct _tag_FWDN_COMMAND_T
++{
++ unsigned long Signature;
++ unsigned short CmdType;
++ unsigned short ExtraCmdSize;
++ unsigned long DataSize;
++ unsigned long Param0;
++ unsigned long Param1;
++ unsigned long Param2;
++
++#if defined(_LINUX_)
++} __attribute__((packed)) FWDN_COMMAND_T;
++#else
++} FWDN_COMMAND_T;
++#endif
++
++typedef struct _tag_FWDN_RESPONSE_T
++{
++ unsigned long Signature;
++ unsigned short CmdType;
++ unsigned char AckType;
++ unsigned char ExtraRspSize;
++ unsigned long DataSize;
++ unsigned long Param0;
++ unsigned long Param1;
++ unsigned long Param2;
++
++#if defined(_LINUX_)
++} __attribute__((packed)) FWDN_RESPONSE_T;
++#else
++} FWDN_RESPONSE_T;
++#endif
++
++#if defined(_WINCE_)
++#pragma pack(pop)
++#endif
++
++void FWDN_PROT_CheckCommand(void);
++
++#endif //__FWDN_PROTOCOL_V2__
+diff --git a/drivers/block/tcc/inc/fwdn/fwdn_protocol_v7.h b/drivers/block/tcc/inc/fwdn/fwdn_protocol_v7.h
+new file mode 100644
+index 0000000..a09e0dc
+--- /dev/null
++++ b/drivers/block/tcc/inc/fwdn/fwdn_protocol_v7.h
+@@ -0,0 +1,121 @@
++#ifndef __FWDN_PROTOCOL_V7__
++#define __FWDN_PROTOCOL_V7__
++
++////////////////////////////////////////////////////////////////////////////
++//
++// FWDN Protocol V7
++//
++////////////////////////////////////////////////////////////////////////////
++#define FEATURE_FWDN_COMM_VTC
++
++
++////////////////////////////////////////////////////////////////////////////
++// FWDN Command
++////////////////////////////////////////////////////////////////////////////
++#define FWDN_CMD_NONE 0x0000
++
++#define FWDN_CMD_UBS_PING 0x0001
++#define FWDN_CMD_UBS_INITCODE_LOAD 0x0002
++#define FWDN_CMD_UBS_ROM_LOAD 0x0003
++
++#define FWDN_CMD_DEVICE_RESET 0x0100
++#define FWDN_CMD_DEVICE_PING 0x0101
++#define FWDN_CMD_DEVICE_INIT 0x0102
++#define FWDN_CMD_DEVICE_INFO_READ 0x0103
++#define FWDN_CMD_DEVICE_SESSION_START 0x0104
++#define FWDN_CMD_DEVICE_SESSION_END 0x0105
++#define FWDN_CMD_DEVICE_SERIAL_NUMBER_WRITE 0x0106
++#define FWDN_CMD_DEVICE_FIRMWARE_WRITE 0x0107
++
++#define FWDN_CMD_AREA_INFO_READ 0x0200
++#define FWDN_CMD_AREA_WRITE 0x0201
++#define FWDN_CMD_AREA_READ 0x0202
++#define FWDN_CMD_AREA_CALC_CRC 0x0203
++
++#define FWDN_CMD_DUMP_INFO_READ 0x0300
++#define FWDN_CMD_DUMP_BLOCK_READ 0x0301
++#define FWDN_CMD_DUMP_BLOCK_WRITE 0x0302
++
++#define FWDN_CMD_TNFTL_V5_DEBUG 0x0F00
++
++#define FWDN_CMD_NAND_GANG_CLEAR 0x1000
++#define FWDN_CMD_NAND_GANG_WRITE 0x1001
++
++#define FWDN_CMD_TEST_SEND 0xEF00
++#define FWDN_CMD_TEST_RECEIVE 0xEF01
++
++/////////////////////////////////////////////////////////
++// 0xF000 ~ 0xFFFF is reserved for vendor
++/////////////////////////////////////////////////////////
++
++
++////////////////////////////////////////////////////////////////////////////
++// FWDN Response Ack Type
++////////////////////////////////////////////////////////////////////////////
++#define FWDN_RSP_NACK 0x00
++#define FWDN_RSP_ACK 0x01
++#define FWDN_RSP_NYET 0x02
++
++
++////////////////////////////////////////////////////////////////////////////
++// FWDN Command / Response Signatures
++////////////////////////////////////////////////////////////////////////////
++#define FWDN_COMMAND_SIGNATURE 0x43445746L //"FWDC" ; FWDn Command
++#define FWDN_RESPONSE_SIGNATURE 0x52445746L //"FWDR" ; FWDn Response
++
++
++#define FWDN_EXTRA_RSP_MAX_SIZE 0xFF
++
++
++#if defined(_WINCE_)
++#pragma pack(push, 1)
++#endif
++
++typedef struct _tag_FWDN_COMMAND_T
++{
++ unsigned long Signature;
++ unsigned short CmdType;
++ unsigned short SubCmdType;
++ unsigned long ExtraCmdSize;
++ unsigned long Param0;
++ unsigned long Param1;
++ unsigned long Param2;
++ unsigned long Param3;
++ unsigned long Param4;
++
++#if defined(_LINUX_)
++} __attribute__((packed)) FWDN_COMMAND_T;
++#else
++} FWDN_COMMAND_T;
++#endif
++
++typedef struct _tag_FWDN_RESPONSE_T
++{
++ unsigned long Signature;
++ unsigned short CmdType;
++ unsigned char AckType;
++ unsigned char reserved;
++ unsigned long DataSize;
++ unsigned long Param0;
++ unsigned long Param1;
++ unsigned long Param2;
++
++#if defined(_LINUX_)
++} __attribute__((packed)) FWDN_RESPONSE_T;
++#else
++} FWDN_RESPONSE_T;
++#endif
++
++#if defined(_WINCE_)
++#pragma pack(pop)
++#endif
++
++typedef enum {
++ FWDN_COMM_VTC,
++ FWDN_COMM_CDC
++} FWDN_COMM_T;
++
++void FWDN_PROT_SetComm(FWDN_COMM_T commType);
++void FWDN_PROT_CheckCommand(void);
++
++#endif //__FWDN_PROTOCOL_V4__
+diff --git a/drivers/block/tcc/inc/fwdn/fwupgrade.h b/drivers/block/tcc/inc/fwdn/fwupgrade.h
+new file mode 100644
+index 0000000..3ee0915
+--- /dev/null
++++ b/drivers/block/tcc/inc/fwdn/fwupgrade.h
+@@ -0,0 +1,178 @@
++/****************************************************************************
++ * FileName : fwupgrade.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#ifndef _FWUPGRADE_H_
++#define _FWUPGRADE_H_
++
++#if defined(_LINUX_)
++#include <common.h>
++//#include <fwdn/main.h>
++#elif defined(_WINCE_)
++//#include "main.h"
++#endif
++
++//**********************************************************************
++//* Define FWUG Library version for ChipSet
++//**********************************************************************
++#if 0
++#if defined(NU_FILE_INCLUDE)
++ #if defined(TCC78X)
++ #define FWUG_V1_INCLUDE
++ #else
++ #define FWUG_V2_INCLUDE
++ #endif
++#else /* K-FILESYSTEM */
++#define FWUG_V1_INCLUDE
++#endif
++#else
++ #define FWUG_V2_INCLUDE //twkwon
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ General DEFINE & TYPEDEF ]
++//*
++//*
++//*****************************************************************************
++#ifndef ON
++#define ON 0x01
++#endif
++#ifndef OFF
++#define OFF 0x00
++#endif
++#ifndef DISABLE
++#define DISABLE 0
++#endif
++#ifndef ENABLE
++#define ENABLE 1
++#endif
++#ifndef FALSE
++#define FALSE 0
++#endif
++#ifndef TRUE
++#define TRUE (!FALSE)
++#endif
++#ifndef NULL
++#define NULL (0)
++#endif
++
++#if 0
++#ifndef U8
++typedef unsigned char U8;
++#endif
++#ifndef U16
++typedef unsigned short int U16;
++#endif
++#ifndef U32
++typedef unsigned int U32;
++#endif
++#endif
++
++enum
++{
++ FIRST = 0,
++ SECOND,
++ REPETITIONNUM
++};
++
++//*****************************************************************************
++//*
++//*
++//* [ ERROR CODE ENUMERATION ]
++//*
++//*
++//*****************************************************************************
++#ifndef SUCCESS
++#define SUCCESS 0
++#endif
++
++typedef enum
++{
++ ERR_FWUG_NOT_EXISTMEMORY = 0x1000,
++ ERR_FWUG_FAIL_OPENROMFILE,
++ ERR_FWUG_FAIL_CLOSEROMFILE,
++ ERR_FWUG_FAIL_READROMFILE,
++ ERR_FWUG_CANCEL_FWUPGRADE,
++ ERR_FWUG_FAIL_BATCHECK,
++ ERR_FWUG_FAIL_ROMFILESIZEBIG,
++ ERR_FWUG_FAIL_GETGOODBLOCKLIST,
++ ERR_FWUG_NOT_EXISTSERIALNUM,
++ ERR_FWUG_FAIL_GMCDATAWRITE,
++ ERR_FWUG_FAIL_GMCSPAREWRITE,
++ ERR_FWUG_FAIL_CODEDATAWRITE,
++ ERR_FWUG_FAIL_CODESPAREWRITE,
++ ERR_FWUG_FAIL_MCDATAWRITE,
++ ERR_FWUG_FAIL_MCSPAREWRITE,
++ ERR_FWUG_FAIL_FWUPGRADE,
++ ERR_FWUG_FAIL_CHECK_TFLASH,
++ ERR_FWUG_FAIL_SCAN_TFLASH,
++ ERR_FWUG_FAIL_CODEWRITETFLASH,
++ ERR_FWUG_FAIL_CODEREADTFLASH,
++ ERR_FWUG_FAIL_HEADERWRITETFLASH,
++ ERR_FWUG_FAIL_HEADERREADTFLASH,
++ ERR_FWUG_FAIL
++} FWUG_ERROR;
++
++typedef int (*fFWUG_ReadDATA)(unsigned int uDest, unsigned int uSize, unsigned int percent);
++
++extern const unsigned int CRC32_TABLE[];
++
++//*****************************************************************************
++//*
++//*
++//* [ EXTERNAL FUCTIONS DEFINE ]
++//*
++//*
++//*****************************************************************************
++extern unsigned char gFW_FirmwareDevice, gFW_SerialNumberDevice;
++
++extern char *FWUG_GetTempBuffer(unsigned int *uiBufSize);
++extern int FWUG_ReadDATA(unsigned int uDest, void *uHandler, unsigned int uSize, unsigned int percent);
++extern unsigned int CalCRC_ROMFile(unsigned int *pBuffer,unsigned int size,unsigned int crcout, unsigned int mode);
++extern int FWUG_VerifySerialNumber(unsigned char* ucBuf, unsigned int uiOffset);
++
++extern unsigned int FWUG_CalcCrc(unsigned int *base, unsigned int length, const unsigned int *crctable);
++extern unsigned int FWUG_CalcCrc8(unsigned char *base, unsigned int length, const unsigned int *crctable);
++extern unsigned int FWUG_CalcCrcI(unsigned uCRCIN, unsigned *base, unsigned int length, const unsigned int *crctable);
++extern unsigned int FWUG_CalcCrc8I(unsigned uCRCIN, unsigned char *base, unsigned int length, const unsigned int *crctable);
++
++/* TFLASH */
++extern unsigned int FwdnReadTriflashFirmware(unsigned int master);
++extern int FwdnWriteTriflashFirmware(unsigned uFWSize);
++extern int FwdnGetTriflashSerial(void);
++extern int FwdnSetTriflashSerial(unsigned char *ucData, unsigned int overwrite);
++extern int FwdnClearTriflashHiddenArea(void);
++/* HDD */
++extern int FwdnClearHddHiddenArea(void);
++/* NOR */
++extern unsigned int FwdnReadNorFlashFirmware(unsigned int master);
++extern int FwdnWriteNorFlashFirmware(unsigned uFWSize);
++extern int FwdnGetNorSerial(void);
++extern int FwdnSetNorSerial(unsigned char *ucData, unsigned int overwrite);
++/* NAND */
++extern unsigned int FwdnReadNandFirmware(unsigned int master);
++extern int FwdnWriteNandFirmware(unsigned uFWSize);
++extern int FwdnGetNandSerial(void);
++extern int FwdnSetNandSerial(unsigned char *ucData, unsigned int overwrite);
++extern int FwdnClearNandHiddenArea(unsigned int start, unsigned int pagesize);
++extern void FWDN_FNT_VerifySN(unsigned char* ucTempData, unsigned int uiSNOffset);
++/* SFLASH */
++extern unsigned int FwdnReadSFlashFirmware(unsigned int master);
++extern int FwdnWriteSFlashFirmware(unsigned uSFBase, unsigned uFWBase, unsigned int uiROMFileSize);
++extern int FwdnGetSFlashSerial(void);
++extern int FwdnSetSFlashSerial(unsigned char *ucData, unsigned int overwrite);
++/* EEPROM */
++extern int FwdnWriteEEPROMFirmware(unsigned uFWSize);
++
++#endif // _FWUPGRADE_H_
++
++/* end of file */
++
+diff --git a/drivers/block/tcc/inc/fwdn/fwupgrade_NAND_v6.h b/drivers/block/tcc/inc/fwdn/fwupgrade_NAND_v6.h
+new file mode 100644
+index 0000000..6f6a31c
+--- /dev/null
++++ b/drivers/block/tcc/inc/fwdn/fwupgrade_NAND_v6.h
+@@ -0,0 +1,162 @@
++/****************************************************************************
++ * FileName : fwupgrade_NAND.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#ifndef _FWUPGRADE_NAND_H_
++#define _FWUPGRADE_NAND_H_
++
++#if defined(NAND_BOOT_REV)
++ #if defined(_LINUX_)
++ #include <tnftl/tnftl_v7.h>
++ #elif defined(_WINCE_)
++ #include "tnftl_v7.h"
++ #else
++ #include "tnftl_v7.h"
++ #endif
++#else
++ #if defined(_LINUX_)
++ #include <tnftl/tnftl_v6.h>
++ #elif defined(_WINCE_)
++ #include "tnftl_v6.h"
++ #else
++ #include "tnftl_v6.h"
++ #endif
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ General DEFINE & TYPEDEF ]
++//*
++//*
++//*****************************************************************************
++#ifndef ON
++#define ON 0x01
++#endif
++#ifndef OFF
++#define OFF 0x00
++#endif
++#ifndef DISABLE
++#define DISABLE 0
++#endif
++#ifndef ENABLE
++#define ENABLE 1
++#endif
++#ifndef FALSE
++#define FALSE 0
++#endif
++#ifndef TRUE
++#define TRUE 1
++#endif
++#ifndef NAND_TYPE_PURE_NAND
++#define NAND_TYPE_PURE_NAND 0
++#endif
++#ifndef NAND_TYPE_LBA_NAND
++#define NAND_TYPE_LBA_NAND 1
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ EXTERNAL GLOBAL VARIABLE DEFINE ]
++//*
++//*
++//*****************************************************************************
++#define BIG 0x04
++#define SMALL 0x00
++#define PARALLEL 0x08
++#define SERIAL 0x00
++
++#define EXTENDED_PAGE 0x80
++#define NORMAL_PAGE 0x00
++#define WIDE_SPARE 0x08
++#define NORMAL_SPARE 0x00
++
++#define MAX_GOOD_BLOCK_LIST_LEN (759*2)
++
++#if defined(TNFTL_V5_INCLUDE) || defined(TNFTL_V6_INCLUDE)
++#define FWUG_NAND_IO_READPAGE NAND_IO_ReadNBPage
++#define FWUG_NAND_IO_WRITEPAGE NAND_IO_WriteNBPage
++#else
++#define FWUG_NAND_IO_READPAGE NAND_IO_ReadPage
++#define FWUG_NAND_IO_WRITEPAGE NAND_IO_WritePage
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ ERROR CODE ENUMERATION ]
++//*
++//*
++//*****************************************************************************
++#ifndef SUCCESS
++#define SUCCESS 0
++#endif
++
++typedef enum
++{
++ ERR_FWUG_NAND_WRONG_PARAMETER = 0x0C000000,
++ ERR_FWUG_NAND_FAILED_GET_INFO_GMC,
++ ERR_FWUG_NAND_FAILED_GET_SDCFG_FROM_MC,
++ ERR_FWUG_NAND_FAILED_READY_NB_AREA,
++ ERR_FWUG_NAND_FAILED_COPY_IMAGE,
++ ERR_FWUG_NAND_FAILED_SET_START_ADDRESS_IN_GMC,
++ ERR_FWUG_NAND_FAILED_WRITE_MASTER_CLUSTER,
++ ERR_FWUG_NAND_FAILED_ROMFILESIZE_OVER,
++ ERR_FWUG_NAND_FAILED_CHECK_CRC_ROMCODE,
++ ERR_FWUG_NAND_FAILED_WRITE_CODE_DATA,
++ ERR_FWUG_NAND_FAILED_WRITE_MC_DATA,
++ ERR_FWUG_NAND_FAILED_WRITE_GMC_DATA,
++ ERR_FWUG_NAND_FAILED_NO_BMP,
++ ERR_FWUG_NAND_FAILED_NOT_EXIST_NANDBOOT_AREA,
++ ERR_FWUG_NAND_FAILED_CHECK_CRC_MC,
++ ERR_FWUG_NAND_FAILED_NOT_EXIST_NANDBOOT_SIG,
++ ERR_FWUG_NAND_FAILED_NOT_EXIST_MC_DATA,
++ ERR_FWUG_NAND_FAILED_MEM_INITCODESIZE_OVER
++} FWUG_NAND_ERROR;
++
++//*****************************************************************************
++//*
++//*
++//* [ EXTERNAL FUCTIONS DEFINE ]
++//*
++//*
++//*****************************************************************************
++extern void FWUG_NAND_SetEnableNandBootOnlyMode( U32 value );
++extern void FWUG_NAND_SetParameterForMC( U32 uiSDRAMConfig, U32 uiStExeAddr );
++extern void FWUG_NAND_SetFlagOfUseSecureMode( U32 nValue );
++extern U32 FWUG_NAND_GetFlagOfUseSecureMode( void );
++extern U8 FWUG_NAND_GetCurrentNANDType( void );
++extern FWUG_NAND_ERROR FWUG_NAND_SetNBAreaEndPBAdd( U32 nPhyBlockAddr );
++extern FWUG_NAND_ERROR FWUG_NAND_ClearHDArea( void );
++extern FWUG_NAND_ERROR FWUG_NAND_PreProcess( U32 uiROMFileSize, U8* pFlagNewBig );
++extern FWUG_NAND_ERROR FWUG_NAND_PostProcess( U8* nSNBuf, U32 nSNMode, U32 nSecureMode );
++extern FWUG_NAND_ERROR FWUG_NAND_WriteCodePreProcess( U8 ucNum, U32 uiROMFileSize, U32 *rStBlockOffSet, U32 *rStPageOffSet, U32 nSecureMode );
++#ifdef TNFTL_V7_INCLUDE
++extern FWUG_NAND_ERROR FWUG_NAND_WriteCodeNAND( U16 nRomNum, U32 nStBlockOffSet, U32 nStPageOffSet, U8 *WriteBufAddr, U32 iBufSize, U32 *rBlockOffSet, U32 *rPageOffSet, U32 nSecureMode );
++#else
++extern FWUG_NAND_ERROR FWUG_NAND_WriteCodeNAND( U32 nStBlockOffSet, U32 nStPageOffSet, U8* WriteBufAddr, U32 iBufSize, U32 *rBlockOffSet, U32 *rPageOffSet, U32 nSecureMode );
++#endif
++extern FWUG_NAND_ERROR FWUG_NAND_WriteCodePostProcess( U8 ucNum, U32 nStBlockOffSet, U32 nStPageOffSet );
++extern FWUG_NAND_ERROR FWUG_NAND_GetSerialNumberNAND( U8* nSID );
++extern unsigned int FWUG_NAND_CRCUpdate(unsigned char * pBuffer, unsigned int nBufferSize, unsigned int StCRCout, unsigned int nMode, unsigned int nRemainSize);
++
++extern FWUG_NAND_ERROR FWUG_NAND_LBA_GetSerialNumberNAND( U8* nSID );
++extern void FWUG_NAND_LBA_InitVariable(U32 nCrc128k, U32 nCrc256k);
++extern FWUG_NAND_ERROR FWUG_NAND_LBA_WriteCodePreProcess(U8 ucNum, U32 uiROMFileSize, U32 * rStBlockOffSet, U32 * rStPageOffSet, U32 nSecureMode);
++extern FWUG_NAND_ERROR FWUG_NAND_LBA_WriteCodeNAND(U32 nStBlockOffSet, U32 nStPageOffSet, U8 * WriteBufAddr, U32 iBufSize, U32 * rBlockOffSet, U32 * rPageOffSet, U32 nSecureMode);
++extern FWUG_NAND_ERROR FWUG_NAND_LBA_WriteMC(unsigned char ucNum);
++extern FWUG_NAND_ERROR FWUG_NAND_LBA_WriteGMC(U8 * nSNBuf, U32 nSNMode, U32 nSecureMode);
++extern FWUG_NAND_ERROR FWUG_NAND_LBA_WriteCodetoVFP(U32 nSectorAddr, U8 * WriteBufAddr, U32 iBufSize, U32 * rSectorAddr, U32 nSecureMode);
++extern FWUG_NAND_ERROR FWUG_NAND_LBA_PostProcess(U8 nMode);
++
++#endif // _FWUPGRADE_NAND_H_
++
++/* end of file */
++
+diff --git a/drivers/block/tcc/inc/tnftl/IO_TCCXXX.h b/drivers/block/tcc/inc/tnftl/IO_TCCXXX.h
+new file mode 100644
+index 0000000..cb049bd
+--- /dev/null
++++ b/drivers/block/tcc/inc/tnftl/IO_TCCXXX.h
+@@ -0,0 +1,3872 @@
++/************************************************************************
++* TELECHIPS Digital Audio Player
++* ------------------------------------------------
++*
++* FUNCTION :
++* MODEL : TCCXXX
++* CPU NAME : TCCXXX
++* SOURCE : IO_TCCXXX.h
++*
++* START DATE : FEB. 16. 2009
++* MODIFY DATE : FEB. 16. 2009
++* DEVISION : DEPT. SYSTEM 3 GROUP
++* : TELECHIPS, INC.
++************************************************************************/
++
++
++/****************************************************************************
++ Revision History
++ ****************************************************************************
++
++ 2009/02/16 : .
++
++ ****************************************************************************/
++
++
++#ifndef __IO_TCCXXX_H
++#define __IO_TCCXXX_H
++
++#if defined(_LINUX_)
++#include <common.h>
++#endif
++
++//#define USE_IO_DEBUG
++
++#if (defined(SDRAM_SIZE) && (SDRAM_SIZE > 0x200000))
++#define DBG_MAXSTR_TX 0x100000
++#else
++#define DBG_MAXSTR_TX 0x10
++#endif
++#define DBG_BUFMASK_TX (DBG_MAXSTR_TX - 1)
++#define DBG_MAXSTR_RX 0x10
++
++//#define USE_DOMEASURE
++//#define CHECK_SPEED
++#define LOW_FREQ_PLL_INCLUDE
++
++// Select EHI Slave System among the followings.
++ //#define EHIS_TCC77X
++ #define EHIS_TCC75X
++
++//#include "main.h"
++
++#ifdef TCC92XX
++#include "TCC92xx_Physical.h"
++#include "TCC92xx_Structures.h"
++#elif defined(TCC89XX)
++#if defined(_LINUX_)
++#include <mach/TCC89x_Physical.h>
++#include <mach/TCC89x_Structures.h>
++#elif defined(_WINCE_)
++#include "TCC89x_Physical.h"
++#include "TCC89x_Structures.h"
++#endif
++#elif defined(TCC79XX)
++#include "TCC79xx.h"
++#else
++#error "-- Not defined chip models --"
++#endif
++
++
++#ifdef TCC79XX
++ #define HwSDR_FIX 0x07282000
++ #define HwSDR_RFR 0
++ #define HwSDCFG_P0 HwSDCFG
++ #define HwSDCFG_P1 HwSDCFG
++#elif defined(TCC92XX) || defined(TCC89XX)
++ #define HwSDR_FIX 0x07282000
++ #define HwSDR_RFR 0
++ #define HwSDCFG_P0 HwSDCFG
++ #define HwSDCFG_P1 HwSDCFG
++#endif
++
++#define HwSDR_RBC HwSDCFG_AM_RBC
++
++#define HwSDR_CL3 HwSDCFG_CL
++
++// SDRAM BusWidth
++#define HwSDR_X16 Hw30
++#define HwSDR_X32 HwZERO
++
++// SDRAM Size (Col, Row Address bus width)
++#define HwSDR_2MB (HwSDCFG_CW8 + HwSDCFG_RW11)
++#define HwSDR_4MB (HwSDCFG_CW8 + HwSDCFG_RW11)
++#define HwSDR_8MB (HwSDCFG_CW8 + HwSDCFG_RW12)
++#define HwSDR_16MB (HwSDCFG_CW9 + HwSDCFG_RW12)
++#define HwSDR_32MB (HwSDCFG_CW9 + HwSDCFG_RW13)
++#define HwSDR_64MB (HwSDCFG_CW10 + HwSDCFG_RW13)
++
++
++#if (defined(TELECHIPS_SV) && !defined(USE_IO_DEBUG))
++ //#define USE_IO_DEBUG
++#endif
++
++#ifndef SET
++ #define SET 1
++#endif
++#ifndef CLR
++ #define CLR 0
++#endif
++
++#if defined(_LINUX_)
++#ifndef _U32_
++#define _U32_
++ typedef unsigned int U32;
++#endif
++#ifndef _U16_
++#define _U16_
++ typedef unsigned short U16;
++#endif
++#ifndef _U8_
++#define _U8_
++ typedef unsigned char U8;
++#endif
++#ifndef WINVER
++ #ifndef _BOOL_
++ #define _BOOL_
++ typedef unsigned int BOOL;
++ #endif
++#endif
++#else
++#ifndef U32
++ typedef unsigned int U32;
++#endif
++#ifndef U16
++ typedef unsigned short U16;
++#endif
++#ifndef U8
++ typedef unsigned char U8;
++#endif
++
++#ifndef WINVER
++ #ifndef BOOL
++ typedef unsigned int BOOL;
++ #endif
++#endif
++#endif
++
++#ifndef S32
++ typedef signed int S32;
++#endif
++#ifndef S16
++ typedef signed short S16;
++#endif
++#ifndef S8
++ typedef signed char S8;
++#endif
++
++typedef int (*ICallBack)(int num);
++
++/* =============================
++ General Bit Operator
++ ============================= */
++// Bit manipulation macro that is modifying its argument. (task type)
++#ifndef BITSET
++#define BITSET(X, MASK) ( (X) |= (U32)(MASK) )
++#endif
++#ifndef BITSCLR
++#define BITSCLR(X, SMASK, CMASK) ( (X) = ((((U32)(X)) | ((U32)(SMASK))) & ~((U32)(CMASK))) )
++#endif
++#ifndef BITCSET
++#define BITCSET(X, CMASK, SMASK) ( (X) = ((((U32)(X)) & ~((U32)(CMASK))) | ((U32)(SMASK))) )
++#endif
++#ifndef BITCLR
++#define BITCLR(X, MASK) ( (X) &= ~((U32)(MASK)) )
++#endif
++#ifndef BITXOR
++#define BITXOR(X, MASK) ( (X) ^= (U32)(MASK) )
++#endif
++
++// Bit manipulation macro that is not modifying its argument. (function type)
++#ifndef fBITSET
++#define fBITSET(X, MASK) ( (X) | (U32)(MASK) )
++#endif
++#ifndef fBITSCLR
++#define fBITSCLR(X, SMASK, CMASK) ( ((((U32)(X)) | ((U32)(SMASK))) & ~((U32)(CMASK))) )
++#endif
++#ifndef fBITCSET
++#define fBITCSET(X, CMASK, SMASK) ( ((((U32)(X)) & ~((U32)(CMASK))) | ((U32)(SMASK))) )
++#endif
++#ifndef fBITCLR
++#define fBITCLR(X, MASK) ( (X) & ~((U32)(MASK)) )
++#endif
++#ifndef fBITXOR
++#define fBITXOR(X, MASK) ( (X) ^ (U32)(MASK) )
++#endif
++
++#ifndef ISSET
++#define ISSET(X, MASK) ( (U32)(X) & ((U32)(MASK)) )
++#endif
++#ifndef IS
++#define IS(X, MASK) ( (U32)(X) & ((U32)(MASK)) )
++#endif
++#ifndef ISONE
++#define ISONE(X, MASK) ( (U32)(X) & ((U32)(MASK)) )
++#endif
++
++#ifndef ISALLONE
++#define ISALLONE(X, MASK) ( ((U32)(X) & ((U32)(MASK))) == ((U32)(MASK)) )
++#endif
++
++#ifndef ISCLR
++#define ISCLR(X, MASK) ( !(((U32)(X)) & ((U32)(MASK))) )
++#endif
++#ifndef ISZERO
++#define ISZERO(X, MASK) ( !(((U32)(X)) & ((U32)(MASK))) )
++#endif
++#ifndef ISNOT
++#define ISNOT(X, MASK) ( !(((U32)(X)) & ((U32)(MASK))) )
++#endif
++
++#ifndef BYTE_OF
++#define BYTE_OF(X) ( *(volatile unsigned char *)(&(X)) )
++#endif
++#ifndef SHORT_OF
++#define SHORT_OF(X) ( *(volatile short *)(&(X)) )
++#endif
++#ifndef HWORD_OF
++#define HWORD_OF(X) ( *(volatile unsigned short *)(&(X)) )
++#endif
++#ifndef WORD_OF
++#define WORD_OF(X) ( *(volatile unsigned int *)(&(X)) )
++#endif
++
++#ifndef byte_of
++#define byte_of(X) ( *(volatile unsigned char *)((X)) )
++#endif
++#ifndef short_of
++#define short_of(X) ( *(volatile short *)((X)) )
++#endif
++#ifndef hword_of
++#define hword_of(X) ( *(volatile unsigned short *)((X)) )
++#endif
++#ifndef word_of
++#define word_of(X) ( *(volatile unsigned int *)((X)) )
++#endif
++
++#define CkWaitPLLLOCK() { while (ISCLR(HwPLLMODE, Hw20)); }
++
++#define SBase(X) Load$$ ## X ## $$Base
++#define DBase(X) Image$$ ## X ## $$Base
++#define SSize(X) Image$$ ## X ## $$Length
++#define ZIBase(X) Image$$ ## X ## $$ZI$$Base
++#define ZISize(X) Image$$ ## X ## $$ZI$$Length
++#define Region(X) &SBase(X), &DBase(X), &SSize(X), &ZIBase(X), &ZISize(X)
++#define ExternRegion(X) SBase(X), DBase(X), SSize(X), ZIBase(X), ZISize(X)
++
++
++/************************************************************************
++* Clock Controller
++************************************************************************/
++typedef struct {
++ unsigned uFpll;
++ unsigned char P, M, S, dummy;
++} sPLL;
++
++
++enum {
++ XIN_FREQ_120000,
++ XIN_FREQ_480000
++};
++
++enum {
++ IO_CKC_Ftimerx = 0,
++ IO_CKC_Ftimert,
++ IO_CKC_Ftimerz,
++ IO_CKC_Flcd0,
++ IO_CKC_Flcd1,
++ IO_CKC_Flcdsi, // 5
++ IO_CKC_Fcifmc,
++ IO_CKC_Fcifsc,
++ IO_CKC_Fout0,
++ IO_CKC_Fout1,
++ IO_CKC_Fhdmi, // 10
++ IO_CKC_Fdummy,
++ IO_CKC_Fsdmmc0,
++ IO_CKC_Fmstick,
++ IO_CKC_Fi2c,
++ IO_CKC_Fuart0, // 15
++ IO_CKC_Fuart1,
++ IO_CKC_Fuart2,
++ IO_CKC_Fuart3,
++ IO_CKC_Fuart4,
++ IO_CKC_Fuart5, // 20
++ IO_CKC_Fgpsb0,
++ IO_CKC_Fgpsb1,
++ IO_CKC_Fgpsb2,
++ IO_CKC_Fgpsb3,
++ IO_CKC_Fgpsb4, // 25
++ IO_CKC_Fgpsb5,
++ IO_CKC_Fadc,
++ IO_CKC_Fspdif,
++ IO_CKC_Fehi0,
++ IO_CKC_Fehi1, // 30
++ IO_CKC_Faud,
++ IO_CKC_Fdummy1,
++ IO_CKC_Fdummy2,
++ IO_CKC_Fsdmmc1,
++ IO_CKC_Fdummy3, // 35
++ IO_CKC_Fdai,
++
++ IO_CKC_Flast
++};
++
++
++/**********************************************************
++* void IO_CKC_WaitPLL(void);
++* Input :
++* Return :
++* Description : Loop waiting PLL locked.
++**********************************************************/
++#define IO_CKC_WaitPLL() { int i; for (i=0; i<0x1000; i++); }
++
++
++/**********************************************************
++* void IO_CKC_EnableBUS(unsigned X);
++* Input : X = Bitmap dedicated to each peripheral
++* Return :
++* Description : Enable(1) the bus clock fed to each peripheral.
++* The other bus clocks are not influenced.
++**********************************************************/
++#define IO_CKC_EnableBUS(X) (BITSET(HwIOBUSCFG->HCLKEN0, (X)))
++#define IO_CKC_EnableBUS1(X) (BITSET(HwIOBUSCFG->HCLKEN1, (X)))
++
++/**********************************************************
++* Derivatives of IO_CKC_EnableBUS() function.
++* Input :
++* Return :
++* Description : Enable the bus clock fed to each peripheral.
++**********************************************************/
++#define IO_CKC_EnableBUS_USB() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_USB))
++#define IO_CKC_EnableBUS_IDE() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_IDE))
++#define IO_CKC_EnableBUS_DMA() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_DMA))
++#define IO_CKC_EnableBUS_SDC() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_SD))
++#define IO_CKC_EnableBUS_MS() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_MS))
++#define IO_CKC_EnableBUS_I2C() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_I2C))
++#define IO_CKC_EnableBUS_NFC() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_NFC))
++#define IO_CKC_EnableBUS_EHI0() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_EHI0))
++#define IO_CKC_EnableBUS_EHI1() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_EHI1))
++#define IO_CKC_EnableBUS_UART0() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_UART0))
++#define IO_CKC_EnableBUS_UART1() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_UART1))
++#define IO_CKC_EnableBUS_UART2() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_UART2))
++#define IO_CKC_EnableBUS_UART3() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_UART3))
++#define IO_CKC_EnableBUS_UART4() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_UART4))
++#define IO_CKC_EnableBUS_UART5() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_UART5))
++#define IO_CKC_EnableBUS_GPSB0() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_GPSB0))
++#define IO_CKC_EnableBUS_GPSB1() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_GPSB1))
++#define IO_CKC_EnableBUS_GPSB2() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_GPSB2))
++#define IO_CKC_EnableBUS_GPSB3() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_GPSB3))
++#define IO_CKC_EnableBUS_GPSB4() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_GPSB4))
++#define IO_CKC_EnableBUS_GPSB5() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_GPSB5))
++#define IO_CKC_EnableBUS_DAI() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_DAI))
++#define IO_CKC_EnableBUS_ECC() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_ECC))
++#define IO_CKC_EnableBUS_SPDIF() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_SPDIF))
++#define IO_CKC_EnableBUS_RTC() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_RTC))
++#define IO_CKC_EnableBUS_TSADC() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_TSADC))
++#define IO_CKC_EnableBUS_GPS() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_GPS))
++#define IO_CKC_EnableBUS_ADMA() (BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_ADMA))
++#define IO_CKC_EnableBUS_MPE() (BITSET(HwIOBUSCFG->HCLKEN1, HwIOBUSCFG_MPE))
++#define IO_CKC_EnableBUS_TSIF() (BITSET(HwIOBUSCFG->HCLKEN1, HwIOBUSCFG_TSIF))
++#define IO_CKC_EnableBUS_SRAM() (BITSET(HwIOBUSCFG->HCLKEN1, HwIOBUSCFG_SRAM))
++
++
++/**********************************************************
++* void IO_CKC_DisableBUS(unsigned X);
++* Input : X = Bitmap dedicated to each peripheral
++* Return :
++* Description : Disable(1) the bus clock fed to each peripheral.
++* The other bus clocks are not influenced.
++**********************************************************/
++#define IO_CKC_DisableBUS(X) (BITCLR(HwIOBUSCFG->HCLKEN0, X))
++#define IO_CKC_DisableBUS1(X) (BITCLR(HwIOBUSCFG->HCLKEN1, (X)))
++
++/**********************************************************
++* Derivatives of IO_CKC_DisableBUS() function.
++* Input :
++* Return :
++* Description : Disable the bus clock fed to each peripheral.
++**********************************************************/
++#define IO_CKC_DisableBUS_USB() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_USB))
++#define IO_CKC_DisableBUS_IDE() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_IDE))
++#define IO_CKC_DisableBUS_DMA() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_DMA))
++#define IO_CKC_DisableBUS_SDC() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_SD))
++#define IO_CKC_DisableBUS_MS() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_MS))
++#define IO_CKC_DisableBUS_I2C() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_I2C))
++#define IO_CKC_DisableBUS_NFC() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_NFC))
++#define IO_CKC_DisableBUS_EHI0() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_EHI0))
++#define IO_CKC_DisableBUS_EHI1() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_EHI1))
++#define IO_CKC_DisableBUS_UART0() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_UART0))
++#define IO_CKC_DisableBUS_UART1() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_UART1))
++#define IO_CKC_DisableBUS_UART2() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_UART2))
++#define IO_CKC_DisableBUS_UART3() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_UART3))
++#define IO_CKC_DisableBUS_UART4() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_UART4))
++#define IO_CKC_DisableBUS_UART5() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_UART5))
++#define IO_CKC_DisableBUS_GPSB0() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_GPSB0))
++#define IO_CKC_DisableBUS_GPSB1() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_GPSB1))
++#define IO_CKC_DisableBUS_GPSB2() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_GPSB2))
++#define IO_CKC_DisableBUS_GPSB3() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_GPSB3))
++#define IO_CKC_DisableBUS_GPSB4() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_GPSB4))
++#define IO_CKC_DisableBUS_GPSB5() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_GPSB5))
++#define IO_CKC_DisableBUS_DAI() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_DAI))
++#define IO_CKC_DisableBUS_ECC() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_ECC))
++#define IO_CKC_DisableBUS_SPDIF() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_SPDIF))
++#define IO_CKC_DisableBUS_RTC() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_RTC))
++#define IO_CKC_DisableBUS_TSADC() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_TSADC))
++#define IO_CKC_DisableBUS_GPS() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_GPS))
++#define IO_CKC_DisableBUS_ADMA() (BITCLR(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_ADMA))
++#define IO_CKC_DisableBUS_MPE() (BITCLR(HwIOBUSCFG->HCLKEN1, HwIOBUSCFG_MPE))
++#define IO_CKC_DisableBUS_TSIF() (BITCLR(HwIOBUSCFG->HCLKEN1, HwIOBUSCFG_TSIF))
++#define IO_CKC_DisableBUS_SRAM() (BITCLR(HwIOBUSCFG->HCLKEN1, HwIOBUSCFG_SRAM))
++
++// IOBUS AHB 0
++#define IO_CKC_BUS_USB HwIOBUSCFG_USB
++#define IO_CKC_BUS_IDE HwIOBUSCFG_IDE
++#define IO_CKC_BUS_DMA HwIOBUSCFG_DMA
++#define IO_CKC_BUS_SD HwIOBUSCFG_SD
++#define IO_CKC_BUS_MS HwIOBUSCFG_MS
++#define IO_CKC_BUS_I2C HwIOBUSCFG_I2C
++#define IO_CKC_BUS_NFC HwIOBUSCFG_NFC
++#define IO_CKC_BUS_EHI0 HwIOBUSCFG_EHI0
++#define IO_CKC_BUS_EHI1 HwIOBUSCFG_EHI1
++#define IO_CKC_BUS_UART0 HwIOBUSCFG_UART0
++#define IO_CKC_BUS_UART1 HwIOBUSCFG_UART1
++#define IO_CKC_BUS_UART2 HwIOBUSCFG_UART2
++#define IO_CKC_BUS_UART3 HwIOBUSCFG_UART3
++#define IO_CKC_BUS_UART4 HwIOBUSCFG_UART4
++#define IO_CKC_BUS_UART5 HwIOBUSCFG_UART5
++#define IO_CKC_BUS_GPSB0 HwIOBUSCFG_GPSB0
++#define IO_CKC_BUS_GPSB1 HwIOBUSCFG_GPSB1
++#define IO_CKC_BUS_GPSB2 HwIOBUSCFG_GPSB2
++#define IO_CKC_BUS_GPSB3 HwIOBUSCFG_GPSB3
++#define IO_CKC_BUS_GPSB4 HwIOBUSCFG_GPSB4
++#define IO_CKC_BUS_GPSB5 HwIOBUSCFG_GPSB5
++#define IO_CKC_BUS_DAI HwIOBUSCFG_DAI
++#define IO_CKC_BUS_ECC HwIOBUSCFG_ECC
++#define IO_CKC_BUS_SPDIF HwIOBUSCFG_SPDIF
++#define IO_CKC_BUS_RTC HwIOBUSCFG_RTC
++#define IO_CKC_BUS_TSADC HwIOBUSCFG_TSADC
++#define IO_CKC_BUS_GPS HwIOBUSCFG_GPS
++#define IO_CKC_BUS_ADMA HwIOBUSCFG_ADMA
++
++// IOBUS AHB 1
++#define IO_CKC_BUS_MPE HwIOBUSCFG_MPE
++#define IO_CKC_BUS_TSIF HwIOBUSCFG_TSIF
++#define IO_CKC_BUS_SRAM HwIOBUSCFG_SRAM
++
++
++/**********************************************************
++* void IO_CKC_SWRST(unsigned X);
++* Input : X = Bitmap dedicated to each peripheral
++* Return :
++* Description : Make a reset signal for each peripheral.
++* Set a corresponding bit field to make a reset signal to each peripheral.
++**********************************************************/
++#ifdef TCC92XX
++#else /* TCC92XX */
++#define IO_CKC_SWRST(X) (HwSWRESET = (X))
++#endif /* TCC92XX */
++
++#ifndef _LINUX_
++#pragma warning( push )
++#pragma warning( disable: 4341 ) // enum --> unsigned longlong...X
++#pragma warning( disable: 4309 )
++#endif
++enum {
++ IO_CKC_TMRX = Hw0,
++ IO_CKC_TMRT = Hw1,
++ IO_CKC_TMRZ = Hw2,
++ IO_CKC_LCD0 = Hw3,
++ IO_CKC_LCD1 = Hw4,
++ IO_CKC_LCDSI = Hw5,
++ IO_CKC_CIFMC = Hw6,
++ IO_CKC_CIFSC = Hw7,
++ IO_CKC_OUT0 = Hw8,
++ IO_CKC_OUT1 = Hw9,
++ IO_CKC_HDMI = Hw10,
++ IO_CKC_SDMMC0 = Hw12,
++ IO_CKC_MSTICK = Hw13,
++ IO_CKC_I2C = Hw14,
++ IO_CKC_UART0 = Hw15,
++ IO_CKC_UART1 = Hw16,
++ IO_CKC_UART2 = Hw17,
++ IO_CKC_UART3 = Hw18,
++ IO_CKC_UART4 = Hw19,
++ IO_CKC_UART5 = Hw20,
++ IO_CKC_GPSB0 = Hw21,
++ IO_CKC_GPSB1 = Hw22,
++ IO_CKC_GPSB2 = Hw23,
++ IO_CKC_GPSB3 = Hw24,
++ IO_CKC_GPSB4 = Hw25,
++ IO_CKC_GPSB5 = Hw26,
++ IO_CKC_ADC = Hw27, // PCK_YYY
++ IO_CKC_SPDIF = Hw28, // PCK_YYY
++ IO_CKC_EHI0 = Hw29,
++ IO_CKC_EHI1 = Hw30,
++ IO_CKC_AUD = Hw31, // PCK_YYY
++ IO_CKC_SDMMC1 = Hw34,
++ IO_CKC_DAI = Hw36 // PCK_YYY
++};
++#ifndef _LINUX_
++#pragma warning( pop )
++#endif
++
++#define IO_CKC_EnableClock(x) \
++{ \
++ if ((x) & IO_CKC_TMRX) \
++ BITSET(HwCKC->PCLK_TCX, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_TMRT) \
++ BITSET(HwCKC->PCLK_TCT, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_TMRZ) \
++ BITSET(HwCKC->PCLK_TCZ, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_LCD0) \
++ BITSET(HwCKC->PCLK_LCD0, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_LCD1) \
++ BITSET(HwCKC->PCLK_LCD1, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_LCDSI) \
++ BITSET(HwCKC->PCLK_LCDSI, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_CIFMC) \
++ BITSET(HwCKC->PCLK_CIFMC, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_CIFSC) \
++ BITSET(HwCKC->PCLK_CIFSC, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_OUT0) \
++ BITSET(HwCKC->PCLK_OUT0, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_OUT1) \
++ BITSET(HwCKC->PCLK_OUT1, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_HDMI) \
++ BITSET(HwCKC->PCLK_HDMI, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_SDMMC0) \
++ BITSET(HwCKC->PCLK_SDMMC0, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_MSTICK) \
++ BITSET(HwCKC->PCLK_MSTICK, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_I2C) \
++ BITSET(HwCKC->PCLK_I2C, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_UART0) \
++ BITSET(HwCKC->PCLK_UART0, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_UART1) \
++ BITSET(HwCKC->PCLK_UART1, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_UART2) \
++ BITSET(HwCKC->PCLK_UART2, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_UART3) \
++ BITSET(HwCKC->PCLK_UART3, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_UART4) \
++ BITSET(HwCKC->PCLK_UART4, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_UART5) \
++ BITSET(HwCKC->PCLK_UART5, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_GPSB0) \
++ BITSET(HwCKC->PCLK_GPSB0, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_GPSB1) \
++ BITSET(HwCKC->PCLK_GPSB1, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_GPSB2) \
++ BITSET(HwCKC->PCLK_GPSB2, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_GPSB3) \
++ BITSET(HwCKC->PCLK_GPSB3, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_GPSB4) \
++ BITSET(HwCKC->PCLK_GPSB4, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_GPSB5) \
++ BITSET(HwCKC->PCLK_GPSB5, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_ADC) \
++ BITSET(HwCKC->PCLK_ADC, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_SPDIF) \
++ BITSET(HwCKC->PCLK_SPDIF, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_EHI0) \
++ BITSET(HwCKC->PCLK_EHI0, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_EHI1) \
++ BITSET(HwCKC->PCLK_EHI1, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_AUD) \
++ BITSET(HwCKC->PCLK_AUD, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_SDMMC1) \
++ BITSET(HwCKC->PCLK_SDMMC1, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_DAI) \
++ BITSET(HwCKC->PCLK_DAI, HwPCK_EN_EN); \
++}
++
++#define IO_CKC_DisableClock(x) \
++{ \
++ if ((x) & IO_CKC_TMRX) \
++ BITCLR(HwCKC->PCLK_TCX, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_TMRT) \
++ BITCLR(HwCKC->PCLK_TCT, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_TMRZ) \
++ BITCLR(HwCKC->PCLK_TCZ, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_LCD0) \
++ BITCLR(HwCKC->PCLK_LCD0, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_LCD1) \
++ BITCLR(HwCKC->PCLK_LCD1, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_LCDSI) \
++ BITCLR(HwCKC->PCLK_LCDSI, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_CIFMC) \
++ BITCLR(HwCKC->PCLK_CIFMC, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_CIFSC) \
++ BITCLR(HwCKC->PCLK_CIFSC, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_OUT0) \
++ BITCLR(HwCKC->PCLK_OUT0, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_OUT1) \
++ BITCLR(HwCKC->PCLK_OUT1, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_HDMI) \
++ BITCLR(HwCKC->PCLK_HDMI, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_SDMMC0) \
++ BITCLR(HwCKC->PCLK_SDMMC0, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_MSTICK) \
++ BITCLR(HwCKC->PCLK_MSTICK, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_I2C) \
++ BITCLR(HwCKC->PCLK_I2C, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_UART0) \
++ BITCLR(HwCKC->PCLK_UART0, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_UART1) \
++ BITCLR(HwCKC->PCLK_UART1, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_UART2) \
++ BITCLR(HwCKC->PCLK_UART2, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_UART3) \
++ BITCLR(HwCKC->PCLK_UART3, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_UART4) \
++ BITCLR(HwCKC->PCLK_UART4, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_UART5) \
++ BITCLR(HwCKC->PCLK_UART5, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_GPSB0) \
++ BITCLR(HwCKC->PCLK_GPSB0, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_GPSB1) \
++ BITCLR(HwCKC->PCLK_GPSB1, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_GPSB2) \
++ BITCLR(HwCKC->PCLK_GPSB2, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_GPSB3) \
++ BITCLR(HwCKC->PCLK_GPSB3, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_GPSB4) \
++ BITCLR(HwCKC->PCLK_GPSB4, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_GPSB5) \
++ BITCLR(HwCKC->PCLK_GPSB5, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_ADC) \
++ BITCLR(HwCKC->PCLK_ADC, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_SPDIF) \
++ BITCLR(HwCKC->PCLK_SPDIF, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_EHI0) \
++ BITCLR(HwCKC->PCLK_EHI0, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_EHI1) \
++ BITCLR(HwCKC->PCLK_EHI1, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_AUD) \
++ BITCLR(HwCKC->PCLK_AUD, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_SDMMC1) \
++ BITCLR(HwCKC->PCLK_SDMMC1, HwPCK_EN_EN); \
++ if ((x) & IO_CKC_DAI) \
++ BITCLR(HwCKC->PCLK_DAI, HwPCK_EN_EN); \
++}
++
++
++/************************************************************************
++* Function Declaration (Clock Controller)
++************************************************************************/
++/**********************************************************
++* void IO_CKC_EnterStandbyInt(unsigned uMode)
++*
++* Input : uMode = wake-up event selection
++* 0 : using XIN clock (that means program stops here until wake-up event is occurred.)
++* In this mode, only external interrupt can wake up system. but may be unstable while waking up.
++* NOT RECOMMENDED.
++* non-zero : using XTIN clock.
++* In this mode, program continues but polling predefined wake-up interrupt.
++* the wake-up interrupt can be defined by this value of 'uMode'
++* this represents bitmap of wake-up interrupt sources.
++* Return :
++* Description : Enter Standby Mode (All clocks except XTIN are stopped.)
++* This function is located in IO_LIB_INT area and
++* it should be located in the internal SRAM.
++*********************************************************/
++void IO_CKC_EnterStandbyInt(unsigned uMode);
++
++enum
++{
++ SPEED_MODE_0 = 0,
++ #ifdef SPEED_MODE_INCLUDE
++ SPEED_MODE_1,
++ SPEED_MODE_2,
++ SPEED_MODE_3,
++ #endif
++ MAX_SPEED_MODE
++};
++
++typedef struct {
++ unsigned uFmaxpll;
++ unsigned uFmaxcpu;
++ unsigned uFmaxbus;
++ unsigned uFpll[3]; // for 32KHz, 44.1KHz, 48KHz
++
++ /*for chaning max clock by speed mode
++ */
++ unsigned uHighpll; //unit : 100hz
++ unsigned short uHighcpu; //unit : Mhz
++ unsigned short uHighbus; //unit : Mhz
++} sIO_CKC_SPD_MODE;
++
++/**********************************************************
++* void IO_CKC_InitVariable(int iFmax, int iHmax);
++*
++* Input : iFmax = Maximum frequency of CPU clock (100Hz unit)
++* iHmax = Maximum frequency of BUS clock (100Hz unit)
++* Return :
++* Description : Initialize Global Variables for Clock Driver
++**********************************************************/
++#if defined(TCC79XX) || defined(TCC92XX) || defined(TCC89XX)
++ #define IO_CKC_Fmaxcpu PLL_FREQ
++ #define IO_CKC_Fmaxbus (PLL_FREQ/2)
++
++ #define IO_CKC_Fxin 120000
++
++ #define IO_CKC_Fpll_32KHz PLL_FREQ
++ #define IO_CKC_Fpll_44KHz PLL_FREQ
++ #define IO_CKC_Fpll_48KHz PLL_FREQ
++#endif
++
++/**********************************************************
++* void IO_CKC_InitDRV(void);
++*
++* Input :
++* Output :
++* Return :
++*
++* Description : Initialize Global Variables for Clock Driver
++**********************************************************/
++void IO_CKC_InitDRV(void);
++
++/**********************************************************
++* void IO_CKC_DisablePLL(unsigned uCH)
++*
++* Input : uCH = Channel of PLL (0 or 1)
++* Output :
++* Return :
++*
++* Description :
++*
++**********************************************************/
++void IO_CKC_DisablePLL(unsigned uCH);
++
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int IO_CKC_SelectSpeedMode(unsigned uSpeedMode);
++*
++* DESCRIPTION : Select System Speed Mode (Supported only by pull-up the supply voltage for CORE)
++*
++* INPUT:
++* uSpeedMode = Index of Speed Mode. (Refer sIO_CKC_SpeedMode[] Table)
++*
++* OUTPUT: int - Return Type
++* = -1 : Requested Speed Mode is not supported.
++* = 0 : Mode change successful.
++*
++* REMARK: created on 2007/6/28 22:31:46
++**************************************************************************/
++int IO_CKC_SelectSpeedMode(unsigned uSpeedMode);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* unsigned IO_CKC_CalcBUS4CYCLE(unsigned uNewBusFreq);
++*
++* DESCRIPTION : Map real bus clock frequency to reference bus clock frequency
++* Reference bus clock frequency should be always higher or equal than real bus clock
++* to insert marginal cycles for stability.
++*
++* INPUT:
++* uNewBusFreq = Real bus frequency
++*
++* OUTPUT: unsigned - Return Type
++* = Reference bus frequency
++*
++**************************************************************************/
++unsigned IO_CKC_CalcBUS4CYCLE(unsigned uNewBusFreq);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* unsigned IO_CKC_SetCYCLE(unsigned uNewBusFreq, unsigned uPosition);
++*
++* DESCRIPTION : Set Cycle Parameter for Peripherals which use Bus Clock.
++*
++* INPUT:
++* uNewBusFreq = New Bus Clock Frequency (100 Hz unit)
++* uPosition = Indicate position of calling this function
++* 1 : Before changing Bus Clock, 2 : After changing Bus Clock
++*
++* OUTPUT: unsigned - Return Type
++* = Old Bus Clock Frequency
++* (not real bus clock but reference bus clock for calculating cycle parameters)
++*
++**************************************************************************/
++unsigned IO_CKC_SetCYCLE(unsigned uNewBusFreq, unsigned uPosition);
++
++/**********************************************************
++* void IO_CKC_AdjustClock(int Fmax, int Vmax, int Hmax, int Fmin, int Vmin, int Hmin, int iFclk, int iVclk, int iHclk);
++*
++* Description : Increasing/Decreasing System Clock (CPU, VCORE, BUS)
++* (iFclk, iVclk, iHclk) means division/multiplication factor (not frequency)
++*
++* INPUT:
++* Fmax = Maximum Frequency for CPU clock
++* Vmax = Maximum Frequency for VCORE clock
++* Hmax = Maximum Frequency for BUS clock
++* Fmin = Minimum Frequency for CPU clock
++* Vmin = Minimum Frequency for VCORE clock
++* Hmin = Minimum Frequency for BUS clock
++* iFclk = CPU clock delta index (1~15 for increasing clock, -1~-15 for decreasing clock, 0 for holding)
++* iVclk = VCore clock delta index (1~15 for increasing clock, -1~-15 for decreasing clock, 0 for holding)
++* iHclk = BUS clock delta index (1~31 for increasing clock, -1~-31 for decreasing clock, 0 for holding)
++*
++* Assumption : Source clock (XIN or PLL) must be alive.
++* Output :
++* Return :
++*
++**********************************************************/
++void IO_CKC_AdjustClock(int Fmax, int Vmax, int Hmax, int Fmin, int Vmin, int Hmin, int iFclk, int iVclk, int iHclk);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* unsigned IO_CKC_GetCurrentBUSClock4Cycle(void);
++*
++* DESCRIPTION : Returns current reference bus clock frequency
++* All the peripherals (like NAND, NOR, HDD, etc.) use bus clock
++* should refer this value to calculate cycle parameters.
++*
++* INPUT:
++* None
++*
++* OUTPUT: unsigned - Return Type
++* = current reference bus clock frequency
++*
++**************************************************************************/
++unsigned IO_CKC_GetCurrentBUSClock4Cycle(void);
++
++/**********************************************************
++* void IO_CKC_InitPLL(unsigned uCH, unsigned uPLL);
++*
++* Input : uPLL = target frequency of PLL (100Hz unit)
++* Return :
++* Description : call IO_CKC_SetPLL() according to frequency value
++* currently supported frequency. (default = 240MHz)
++* 240MHz, 120MHz, 248.5714MHz, 203.1428MHz
++* 221.1428MHz, 196.5MHz
++*
++* After PLL set, it is tryed to maintain the frequencies of all clocks.
++* If certain clock is not possible to be maintained,
++* the clock frequency is set as close as previous one.
++**********************************************************/
++void IO_CKC_InitPLL(unsigned uCH, unsigned uPLL);
++
++/**********************************************************
++* void IO_CKC_SetPLL(unsigned uCH, int iP, int iM, int iS);
++*
++* Input : iP, iM, iS
++* Return :
++* Description : Set PLL according to PMS value, and wait until PLL is stable.
++* Fpll = Fxin * (iM + 8) / ((iP + 2) * 2^iS)
++* (The combination of (P, M, S) should be confirmed before used)
++*
++* After PLL set, It is tryed to maintain the frequencies of all clocks.
++* If certain clock is not possible to be maintained,
++* the clock frequency is set as close as previous one.
++**********************************************************/
++void IO_CKC_SetPLL(unsigned uCH, int iP, int iM, int iS);
++
++/**********************************************************
++* void IO_CKC_SetClock(unsigned uPLLCH, unsigned uCKCCH, int iFclk)
++*
++* Input : uPLLCH = PLL channel index
++* uCKCCH = Clock channel index
++* iFclk = Freq. of uCKCCH Unit., 100Hz unit
++* Assumption : Source clock (XIN or PLL) must be alive.
++* (If XTIN is currently used, make sure XIN or PLL alive before calling this function)
++* Return :
++* Description : Set System Clock
++* If target frequency exceeds its own max frequency (gCKC_Fmax]),
++* the uIO_CKC_error flag is incremented, and system clock is not changed.
++* If the frequency requested can not be set exactly,
++* this function set the frequency as close as possible.
++* (refer to the datasheet for possible system clock relationship.)
++* The system clock source is selected according to the following rule.
++* 1) if (Fclk >= Fpll) PLL is selected.
++* 2) if (Fclk > Fxin) PLL divider is selected.
++* 3) if (Fclk == Fxin) XIN is selected.
++* 4) if (Fclk > Fxtin) XIN divider is selected.
++* 5) if (Fclk == Fxtin) XTIN is selected.
++* 6) other case, XTIN divider is selected.
++**********************************************************/
++void IO_CKC_SetClock(unsigned uPLLCH, unsigned uCKCCH, int iFclk);
++
++/**********************************************************
++* void void IO_CKC_SetClockMul(unsigned uPLLCH, unsigned uCKCCH, int iSdiv, int iFdiv, int iSrc)
++*
++* Input : uPLLCH = PLL channel index
++* uCKCCH = Clock channel index
++* iSdiv = System clock division (= Fpll / Fsys)
++* iFdiv = Fsys / Fclk (can be one of 2~32)
++* iSrc = Fsys clock source selection
++* Assumption : Source clock (XIN/XTIN/PLL) must be alive.
++* Output :
++* Return :
++*
++* Description : Set Clock.
++**********************************************************/
++void IO_CKC_SetClockMul(unsigned uPLLCH, unsigned uCKCCH, int iSdiv, int iFdiv, int iSrc);
++
++/**********************************************************
++* unsigned IO_CKC_GetMinimumBusClock(unsigned uLCTRL);
++*
++* Input : LCDC LCTRL value ( register or variable )
++* Assumption :
++* Output :
++* Return : minimum bus clock frequency (100 Hz unit)
++*
++* Description : Get minimum bus clock frequency.
++**********************************************************/
++unsigned IO_CKC_GetMinimumBusClock(unsigned uLCTRL);
++
++/**********************************************************
++* void IO_CKC_SetClockDiv(int iFclk, int iHclk, int iSrc);
++*
++* Input : iFclk = Division Factor for CPU clock (acquired by Fsrc / Fcpu)
++* iHclk = Division Factor for BUS clock (acquired by Fcpu / Fbus)
++* iSrc = Clock source definition (same as CKSEL[2:0] of HwCLKCTRL register)
++* Assumption : Source clock (XIN/PLL/XTIN) must be alive.
++* (If XTIN is currently used, make sure XIN or PLL alive before calling this function)
++* Return :
++* Description : Set System Clock (CPU, BUS) as follows.
++* Frequency of CPU clock (Fcpu) = Fsrc / iFclk. (Fsrc = Frequency of source clock selected by iSrc parameter)
++* Frequency of BUS clock (Fbus) = Fcpu / iHclk.
++**********************************************************/
++#ifdef CPU_CLOCK_DIV_USED
++void IO_CKC_SetClockDiv(int iFdiv, int iHdiv, int iCCKdiv, int iSrc);
++#else
++void IO_CKC_SetClockDiv(int iFdiv, int iHdiv, int iSrc);
++#endif
++
++/**********************************************************
++* unsigned IO_CKC_GetCurrentBUSClock(void);
++*
++* Input :
++* Return : Frequency of Current BUS Clock (100Hz unit)
++* Description : Return the current bus clock frequency
++**********************************************************/
++unsigned IO_CKC_GetCurrentBUSClock(void);
++
++/**********************************************************
++* void IO_CKC_EnterHalt(unsigned uSDEN);
++*
++* Input : uSDEN = option for SDRAM control
++* 0 = don't touch sdram
++* 1 = control SDRAM, (enter self-refresh mode during halt)
++* Return :
++* Description : Enter Halt Mode
++* In Halt mode, only CPU halts until interrupt request occurred.
++************************************************************/
++void IO_CKC_EnterHalt(unsigned uSDEN);
++void IO_CKC_EnterHalt_Main(void);
++void IO_CKC_EnterHalt_End(void);
++
++/**********************************************************
++* void IO_CKC_SetRefreshClock(int iFreq);
++*
++* Input : iFreq = Frequency of Refresh Clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Return :
++* Description : Set Refresh clock frequency and Enable refresh clock
++* It is assumed that the BUS clock freq is larger than half of XIN frequency.
++* The refresh clock is implicitely driven by XIN clock.
++***********************************************************/
++void IO_CKC_SetRefreshClock(int iFreq);
++
++/**********************************************************
++* void IO_CKC_SetUSBHostClock(void);
++*
++* Input :
++* Return :
++* Description : Enable USB Host Clock, it is fixed to use XIN as USB Host clock
++***********************************************************/
++void IO_CKC_SetUSBHostClock(void);
++
++/**********************************************************
++* void IO_CKC_SetI2CClock(int iFreq);
++*
++* Input : iFreq = Frequency of I2C Main Clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Return :
++* Description : Set frequency and Enable I2C main Clock
++* The real I2C clock (SCL) frequency is determined by prescale register of I2C block.
++* The I2C main clock is implicitely driven by XIN clock.
++***********************************************************/
++void IO_CKC_SetI2CClock(int iFreq);
++
++/**********************************************************
++* void IO_CKC_SetMSCClock(int iFreq);
++*
++* Input : iFreq = Frequency of MemoryStic Controller clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Return :
++* Description : Set frequency and Enable Memory Stick Controller Clock
++* The memory stic controller clock is implicitely driven by PLL clock.
++***********************************************************/
++void IO_CKC_SetMSCClock(int iFreq);
++
++/**********************************************************
++* void IO_CKC_SetUA0Clock(int iFreq);
++* void IO_CKC_SetUA1Clock(int iFreq);
++* void IO_CKC_SetUA2Clock(int iFreq);
++* void IO_CKC_SetUA3Clock(int iFreq);
++*
++* Input : iFreq = Frequency of UART clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Return :
++* Description : Set frequency and Enable UART Clock
++* The baud rate of UART is determined by DL register of UART block
++* The UART clock is implicitely driven by PLL clock.
++***********************************************************/
++void IO_CKC_SetUartClock(int iCH, int iFreq);
++void IO_CKC_SetUA0Clock(int iFreq);
++void IO_CKC_SetUA1Clock(int iFreq);
++void IO_CKC_SetUA2Clock(int iFreq);
++void IO_CKC_SetUA3Clock(int iFreq);
++
++/**********************************************************
++* void IO_CKC_SetTimerTClock(int iFreq);
++*
++* Input : iFreq = Frequency of Timer-T clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Return :
++* Description : Set frequency and Enable Timer-T Clock
++* The timer-T clock manages 6 timer/counters
++* (refer to datasheet)
++* The Timer-T clock is implicitely driven by XIN clock.
++***********************************************************/
++void IO_CKC_SetTimerTClock(int iFreq);
++
++/**********************************************************
++* void IO_CKC_SetGSIOClock(int iFreq);
++*
++* Input : iFreq = Frequency of GSIO base clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Return :
++* Description : Set frequency and Enable GSIO base clock
++* The real GSIO clock (SCK) is determined by speed control field of GSCRx register.
++* (refer to datasheet)
++***********************************************************/
++void IO_CKC_SetGSIOClock(int iFreq);
++
++
++/**********************************************************
++* void IO_TC32_SetTIMER(unsigned uCTRL, unsigned uFreq, unsigned uLOADVAL, unsigned uCMP0, unsigned uCMP1);
++*
++* Input : uCTRL = TC32 Control Register (HwTC32EN) value except Pre-scale value.
++* uICTRL = TC32 Interrupt Control Register (HwTC32IRQ) value.
++* uFreq = TC32 counting frequency to set up pre-scale value. (TC32 clock should be set ahead)
++* uLOADVAL = load value (HwTC32LDV)
++* uCMP0 = Match value 0 (HwTC32CMP0).
++* uCMP1 = Match value 1 (HwTC32CMP1).
++* Return :
++* Description : Set TC32 timer (timer is enabled if uFreq > 0, or timer is disabled)
++* If uFreq < Freq(TimerZ clock), then TC32 is counted by TimerZ clock directly.
++**********************************************************/
++void IO_TC32_SetTIMER(unsigned uCTRL, unsigned uICTRL, unsigned uFreq, unsigned uLOADVAL, unsigned uCMP0, unsigned uCMP1);
++
++/**********************************************************
++* void IO_CKC_SetTimerZClock(int iFreq);
++*
++* Input : iFreq = Frequency of Timer-Z clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Return :
++* Description : Set frequency and Enable Timer-Z Clock
++* The timer-Z clock manages TC32 counter block
++* (refer to datasheet)
++* The Timer-Z clock is implicitely driven by XTIN clock.
++***********************************************************/
++void IO_CKC_SetTimerZClock(int iFreq);
++
++/**********************************************************
++* void IO_CKC_SetTimerXClock(int iFreq);
++*
++* Input : iFreq = Frequency of Timer-X clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Return :
++* Description : Set frequency and Enable Timer-X Clock
++* The timer-X clock manages watchdog counter block
++* (refer to datasheet)
++* The Timer-X clock is implicitely driven by XIN clock.
++***********************************************************/
++void IO_CKC_SetTimerXClock(int iFreq);
++
++/**********************************************************
++* void IO_CKC_SetDAIClock(int iFreq);
++*
++* Input : iFreq = Frequency of DAI Main Clock (100Hz unit)
++* Clock disabled if iFreq == 0.
++* Return :
++* Description : Set frequency and Enable DAI Clock
++* The DAI clock should be set appropriately according to audio sampling rate.
++***********************************************************/
++void IO_CKC_SetDAIClock(int iFreq);
++
++/**********************************************************
++* unsigned IO_CKC_GetPLLClock(int iFreq);
++*
++* Input : iFreq = Frequency of Audio Sampling Clock (Hz unit)
++* Return : Frequency of PLL (100Hz unit)
++* Description : Get frequency of PLL that is capable to generate iFreq.
++* Unsupported audio sampling rate is regarded as 44100 Hz.
++* Audio Sampling Rate PLL frequency
++* =========================
++* 44100 Hz & related 203.1428 MHz
++* 48000 Hz & related 221.1428 MHz
++* 32000 Hz & related 196.5000 MHz
++***********************************************************/
++unsigned IO_CKC_GetPLLClock(int iFreq);
++
++/**********************************************************
++* unsigned IO_CKC_GetDAIClock(int iFreq, int iOSR);
++*
++* Input : iFreq = Frequency of Audio Sampling Clock (Hz unit)
++* iOSR = Over Sampling Rate. (ex. 256, 384)
++* Return : Frequency of DAI Clock (100Hz unit)
++* Description : Get frequency of DAI clock that is fit to iFreq audio frequency.
++***********************************************************/
++unsigned IO_CKC_GetDAIClock(int iFreq, int iOSR);
++
++/**********************************************************
++* void IO_CKC_SetADCClock(int iFreq);
++*
++* Input : iFreq = Frequency of ADC Clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Return :
++* Description : Set frequency and Enable ADC Clock
++* The ADC clock is implicitely driven by XIN clock.
++***********************************************************/
++void IO_CKC_SetADCClock(int iFreq);
++
++/**********************************************************
++* void IO_CKC_SetSDMMCClock(int iCH, int iFreq);
++*
++* Input : iCH = SD/MMC channel index
++* iFreq = Frequency of SDMMC Clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Output :
++* Return :
++*
++* Description : Set frequency and Enable Clock
++***********************************************************/
++//void IO_CKC_SetSDMMCClock(int iCH, int iFreq);
++
++/**********************************************************
++* void IO_CKC_SetLCDClock(int iCH, int iFreq)
++*
++* Input : iCH = LCD channel index
++* iFreq = Frequency of LCD Clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Output :
++* Return :
++*
++* Description : Set frequency and Enable Clock
++***********************************************************/
++void IO_CKC_SetLCDClock(int iCH, int iFreq);
++
++/**********************************************************
++* void IO_CKC_SetEHIClock(int iFreq, int iCS);
++*
++* Input : iFreq = Frequency of EHI Clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* iCS = EHI Channel ( 0 or 1 )
++* Output :
++* Return :
++*
++* Description : Set frequency and Enable Clock
++***********************************************************/
++void IO_CKC_SetEHIClock(int iFreq, int iCS);
++
++
++#ifdef CAMERA_INCLUDE
++/**********************************************************
++* void IO_CKC_SetCAMClock(int iFreq);
++*
++* Input : iFreq = Frequency of CAM Clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Output :
++* Return :
++*
++* Description : Set frequency and Enable Clock
++***********************************************************/
++void IO_CKC_SetCAMClock(int iFreq);
++
++/**********************************************************
++* void IO_CKC_SetCAMScalerClock(int iFreq);
++*
++* Input : iFreq = Frequency of CAM Scaler Clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Output :
++* Return :
++*
++* Description : Set frequency and Enable Clock
++***********************************************************/
++void IO_CKC_SetCAMScalerClock(int iFreq);
++#endif
++
++/**********************************************************
++* void IO_CKC_SetSPDIFClock(int iFreq);
++*
++* Input : iFreq = Frequency of SPDIF Clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Output :
++* Return :
++*
++* Description : Set frequency and Enable Clock
++***********************************************************/
++void IO_CKC_SetSPDIFClock(int iFreq);
++
++/**********************************************************
++* void IO_CKC_SetSPI0Clock(int iFreq);
++* void IO_CKC_SetSPI1Clock(int iFreq);
++* void IO_CKC_SetSPI2Clock(int iFreq);
++* void IO_CKC_SetSPI3Clock(int iFreq);
++*
++* Input : iFreq = Frequency of SPIS Clock, 100Hz unit
++* Clock disabled if iFreq == 0.
++* Output :
++* Return :
++*
++* Description : Set frequency and Enable Clock
++***********************************************************/
++void IO_CKC_SetSPI0Clock(int iFreq);
++void IO_CKC_SetSPI1Clock(int iFreq);
++void IO_CKC_SetSPI2Clock(int iFreq);
++void IO_CKC_SetSPI3Clock(int iFreq);
++
++/**********************************************************
++* void IO_CKC_UpdateFPERI(unsigned uPeri, unsigned uFperi);
++*
++* Input : uPeri = Index of peripheral clock frequency table.
++* uFperi = New Frequency value.
++* Output :
++* Return :
++*
++* Description : updates pIO_CKC_Fpll table with new frequency.
++***********************************************************/
++void IO_CKC_UpdateFPERI(unsigned uPeri, unsigned uFperi);
++
++
++extern unsigned uIO_CKC_Fpll[]; // Current PLL Frequency, 100Hz unit
++extern unsigned uIO_CKC_Fsys[];
++extern unsigned uIO_CKC_Fclk[]; // Current Frequency, 100Hz unit
++extern unsigned uTMODE0; // image of HwTMODE register.
++extern unsigned uTMODE1; // image of HwTMODE register.
++extern unsigned pIO_CKC_Fperi[]; // Current Peripheral Frequency, 100Hz unit
++extern const sPLL pIO_CKC_PLL[]; // PLL Setting (PMS) Table
++extern unsigned uIO_CKC_FrzClk; // Freeze CPU, BUS Clock
++extern unsigned uIO_CKC_Fmax[]; // Fclk Max Frequency, 100Hz unit
++extern unsigned uIO_CKC_CurSpeedSet; // Current Speed Mode
++extern unsigned uIO_CKC_Fbus4cycle; // Reference Bus Frequency & Period for calculating cycle parameter
++
++/************************************************************************
++* ARM
++************************************************************************/
++/**********************************************************
++* unsigned IO_ARM_DrainWBInt(void);
++*
++* Input : none
++* Return : 0
++* Description : Drain Write Buffer
++* This function is located in IO_LIB_INT area and
++* it should be located in the internal SRAM.
++**********************************************************/
++unsigned IO_ARM_DrainWBInt(void);
++
++/**********************************************************
++* unsigned IO_ARM_CleanCACHEInt(unsigned uDrainWB);
++*
++* Input : uDrainWB = Write Buffer control
++* 1 = Execute Drain Write Buffer
++* Return : 0
++* Description : Clean Data cache and/or Drain Write Buffer
++* This function is located in IO_LIB_INT area and
++* it should be located in the internal SRAM.
++**********************************************************/
++unsigned IO_ARM_CleanCACHEInt(unsigned uDrainWB);
++
++/**********************************************************
++* int IO_ARM_LockICACHE(void *pFPTRstart, void *pFPTRend);
++*
++* Input : pFPTRstart = function start address for locking
++* pFPTRend = function end address for locking
++* Return : -1 = if error
++* n = lock index (n >= 0)
++* Description : Lock the object function into I cache
++* The locked region
++* starts from (pFPTRstart & ~0x7F) and and at (pFPTRend | 0x7F).
++**********************************************************/
++int IO_ARM_LockICACHE(void *pFPTRstart, void *pFPTRend);
++
++/**********************************************************
++* unsigned IO_ARM_DrainWB(void);
++*
++* Input : none
++* Return : 0
++* Description : Drain Write Buffer
++**********************************************************/
++unsigned IO_ARM_DrainWB(void);
++
++/**********************************************************
++* unsigned IO_ARM_CleanCACHE(unsigned uDrainWB);
++*
++* Input : uDrainWB = Write Buffer control
++* 1 = Drain write buffer
++* 0 = Don't drain write buffer
++* Return : 0
++* Description : Clean Data cache (and Drain Write Buffer)
++**********************************************************/
++unsigned IO_ARM_CleanCACHE(unsigned uDrainWB);
++
++/**********************************************************
++* unsigned IO_ARM_SetMMU(unsigned uMMU);
++*
++* Input : uMMU = MMU control register value
++* Hw16 = DTCM control (1 = to enable)
++* Hw12 = ICache control (1 = to enable)
++* Hw2 = DCache control (1 = to enable)
++* Hw0 = Protection control (1 = to enable)
++* Return : same as input
++* Description : Set MMU control register
++**********************************************************/
++unsigned IO_ARM_SetMMU(unsigned);
++
++/**********************************************************
++* unsigned IO_ARM_GetMMU(void);
++*
++* Input : None
++* Return : current MMU control register (C1 register) value
++* Hw16 = DTCM control (1 = enabled)
++* Hw12 = ICache control (1 = enabled)
++* Hw2 = DCache control (1 = enabled)
++* Hw0 = Protection control (1 = enabled)
++* Description : Get current MMU control register (C1 register)
++**********************************************************/
++unsigned IO_ARM_GetMMU(void);
++
++/**********************************************************
++* unsigned IO_ARM_ClearMMU(unsigned);
++*
++* Input : Flag for MMU control
++* Hw16 = DTCM control (1 = to disable)
++* Hw12 = ICache control (1 = to disable)
++* Hw2 = DCache control (1 = to disable)
++* Hw0 = Protection control (1 = to disable)
++* Return : MMU Settings before modifying
++* Description : Clear MMU control flags according to argument
++**********************************************************/
++unsigned IO_ARM_ClearMMU(unsigned);
++
++/**********************************************************
++* unsigned IO_ARM_FlushCACHE(void);
++*
++* Input : None
++* Return : 0
++* Description : Flush Data & Instruction Cache
++**********************************************************/
++unsigned IO_ARM_FlushCACHE(void);
++
++/**********************************************************
++* unsigned IO_ARM_FlushICACHE(void);
++*
++* Input : None
++* Return : 0
++* Description : Flush Instruction Cache
++**********************************************************/
++unsigned IO_ARM_FlushICACHE(void);
++
++/**********************************************************
++* unsigned IO_ARM_FlushDCACHE(void);
++*
++* Input : None
++* Return : 0
++* Description : Flush Data Cache
++**********************************************************/
++unsigned IO_ARM_FlushDCACHE(void);
++
++/**********************************************************
++* unsigned IO_ARM_GetICACHE(void);
++*
++* Input : None
++* Return : Current region flags for Inst Cache
++* HwX : Region X flag (1 = instruction cache enabled)
++* Description : Set Region flags for Inst Cache
++**********************************************************/
++unsigned IO_ARM_GetICACHE(void);
++
++/**********************************************************
++* unsigned IO_ARM_GetDCACHE(void);
++*
++* Input : None
++* Return : Current region flags for Data Cache
++* HwX : Region X flag (1 = data cache enabled)
++* Description : Set Region flags for Data Cache
++**********************************************************/
++unsigned IO_ARM_GetDCACHE(void);
++
++/**********************************************************
++* unsigned IO_ARM_GetWB(void);
++*
++* Input : None
++* Return : Current region flags for Write Buffering
++* HwX : Region X flag (1 = write buffer enabled)
++* Description : Get Region flags for Write Buffering
++**********************************************************/
++unsigned IO_ARM_GetWB(void);
++
++/**********************************************************
++* unsigned IO_ARM_SetCPSR(unsigned uCPSR);
++*
++* Input : uCPSR = value for new CPSR
++* Return : same as uCPSR
++* Description : Set the CPSR as uCPSR value
++**********************************************************/
++unsigned IO_ARM_SetCPSR(unsigned uCPSR);
++
++/**********************************************************
++* unsigned IO_ARM_GetCPSR(void);
++*
++* Input : None
++* Return : the CPSR register value
++* Description : Get the CPSR register value
++**********************************************************/
++unsigned IO_ARM_GetCPSR(void);
++
++/**********************************************************
++* unsigned IO_ARM_SetINT(unsigned uCPSR);
++*
++* Description : same as IO_ARM_SetCPSR()
++**********************************************************/
++unsigned IO_ARM_SetINT(unsigned uCPSR);
++
++/**********************************************************
++* unsigned IO_ARM_GetINT(void);
++*
++* Description : same as IO_ARM_GetCPSR()
++**********************************************************/
++unsigned IO_ARM_GetINT(void);
++
++/**********************************************************
++* unsigned IO_ARM_EnableFIQ(void);
++*
++* Input : None
++* Return : old CPSR (before FIQ enabled)
++* Description : Enable FIQ
++**********************************************************/
++unsigned IO_ARM_EnableFIQ(void);
++
++/**********************************************************
++* unsigned IO_ARM_DisableFIQ(void);
++*
++* Input : None
++* Return : old CPSR (before FIQ disabled)
++* Description : Disable FIQ
++**********************************************************/
++unsigned IO_ARM_DisableFIQ(void);
++
++/**********************************************************
++* unsigned IO_ARM_EnableIRQ(void);
++*
++* Input : None
++* Return : old CPSR (before IRQ enabled)
++* Description : Enable IRQ
++**********************************************************/
++unsigned IO_ARM_EnableIRQ(void);
++
++/**********************************************************
++* unsigned IO_ARM_DisableIRQ(void);
++*
++* Input : None
++* Return : old CPSR (before IRQ disabled)
++* Description : Disable IRQ
++**********************************************************/
++unsigned IO_ARM_DisableIRQ(void);
++
++/**********************************************************
++* unsigned IO_ARM_EnableINT(void);
++*
++* Input : None
++* Return : old CPSR (before Interrupt enabled)
++* Description : Enable IRQ/FIQ Interrupt
++**********************************************************/
++unsigned IO_ARM_EnableINT(void);
++
++/**********************************************************
++* unsigned IO_ARM_DisableINT(void);
++*
++* Input : None
++* Return : old CPSR (before Interrupt disabled)
++* Description : Disable IRQ/FIQ Interrupt
++**********************************************************/
++unsigned IO_ARM_DisableINT(void);
++
++/************************************************************************
++* Interrupt Controller
++************************************************************************/
++extern void IOS_INT_HandleIRQ0(int inum);
++extern void IOS_INT_HandleIRQ1(int inum);
++extern void IOS_INT_HandleIRQ2(int inum);
++extern void IOS_INT_HandleIRQ3(int inum);
++extern void IOS_INT_HandleIRQ4(int inum);
++extern void IOS_INT_HandleIRQ5(int inum);
++extern void IOS_INT_HandleIRQ6(int inum);
++extern void IOS_INT_HandleIRQ7(int inum);
++extern void IOS_INT_HandleIRQ8(int inum);
++extern void IOS_INT_HandleIRQ9(int inum);
++extern void IOS_INT_HandleIRQ10(int inum);
++extern void IOS_INT_HandleIRQ11(int inum);
++extern void IOS_INT_HandleIRQ12(int inum);
++extern void IOS_INT_HandleIRQ13(int inum);
++extern void IOS_INT_HandleIRQ14(int inum);
++extern void IOS_INT_HandleIRQ15(int inum);
++extern void IOS_INT_HandleIRQ16(int inum);
++extern void IOS_INT_HandleIRQ17(int inum);
++extern void IOS_INT_HandleIRQ18(int inum);
++extern void IOS_INT_HandleIRQ19(int inum);
++extern void IOS_INT_HandleIRQ20(int inum);
++extern void IOS_INT_HandleIRQ21(int inum);
++extern void IOS_INT_HandleIRQ22(int inum);
++extern void IOS_INT_HandleIRQ23(int inum);
++extern void IOS_INT_HandleIRQ24(int inum);
++extern void IOS_INT_HandleIRQ25(int inum);
++extern void IOS_INT_HandleIRQ26(int inum);
++extern void IOS_INT_HandleIRQ27(int inum);
++extern void IOS_INT_HandleIRQ28(int inum);
++extern void IOS_INT_HandleIRQ29(int inum);
++extern void IOS_INT_HandleIRQ30(int inum);
++extern void IOS_INT_HandleIRQ31(int inum);
++
++/**********************************************************
++; unsigned IO_INT_EnableINT(void)
++;
++; Input : None
++; Return : HwALLMSK before Interrupt Enabled
++;
++; Description : Enable IRQ/FIQ Interrupt
++**********************************************************/
++unsigned IO_INT_EnableINT(void);
++
++/**********************************************************
++; unsigned IO_INT_EnableIRQ(void)
++;
++; Input : None
++; Return : HwALLMSK before Interrupt Enabled
++;
++; Description : Enable IRQ Interrupt
++**********************************************************/
++unsigned IO_INT_EnableIRQ(void);
++
++/**********************************************************
++; unsigned IO_INT_EnableFIQ(void)
++;
++; Input : None
++; Return : HwALLMSK before Interrupt Enabled
++;
++; Description : Enable FIQ Interrupt
++**********************************************************/
++unsigned IO_INT_EnableFIQ(void);
++
++/**********************************************************
++; unsigned IO_INT_DisableINT(void)
++;
++; Input : None
++; Return : HwALLMSK before Interrupt Disabled
++;
++; Description : Disable IRQ/FIQ Interrupt
++**********************************************************/
++unsigned IO_INT_DisableINT(void);
++
++/**********************************************************
++; unsigned IO_INT_DisableIRQ(void)
++;
++; Input : None
++; Return : HwALLMSK before Interrupt Disabled
++;
++; Description : Disable IRQ Interrupt
++**********************************************************/
++unsigned IO_INT_DisableIRQ(void);
++
++/**********************************************************
++; unsigned IO_INT_DisableFIQ(void)
++;
++; Input : None
++; Return : HwALLMSK before Interrupt Disabled
++;
++; Description : Disable FIQ Interrupt
++**********************************************************/
++unsigned IO_INT_DisableFIQ(void);
++
++/**********************************************************
++; unsigned IO_INT_RestoreINT(unsigned uMSK)
++;
++; Input : uMSK = Mask value for HwALLMSK
++; Return : uMSK
++;
++; Description : Restore IRQ/FIQ Interrupt
++**********************************************************/
++unsigned IO_INT_RestoreINT(unsigned uMSK);
++
++/************************************************************************
++* Memory Controller
++************************************************************************/
++/**********************************************************
++* void IO_MC_SetCFGInt(unsigned uCS, unsigned uValue);
++*
++* Input : uCS = 0~4
++* uValue = register value for corresponding chip select
++* Return :
++* Description : Set the corresponding memory configuration register (HwCSCFG0~3, HwSDCFG)
++* This function is located in IO_LIB_INT area and
++* it should be located in the internal SRAM.
++**********************************************************/
++void IO_MC_SetCFGInt(unsigned uCS, unsigned uValue);
++
++/************************************************************************
++* DMA Controller
++************************************************************************/
++enum {
++ IO_DMA_CH0,
++ IO_DMA_CH1,
++ IO_DMA_CH2,
++ IO_DMA_CH3,
++ IO_DMA_CH4,
++ IO_DMA_CH5,
++ IO_DMA_CH6,
++ IO_DMA_CH7,
++ IO_DMA_CH8,
++ IO_DMA_CH9,
++ IO_DMA_CH10,
++ IO_DMA_CH11,
++ IO_DMA_CH_MAX
++};
++
++#if defined(TCC79XX) || defined(TCC92XX) || defined(TCC89XX)
++ #define IO_DMA_PORTCFG_NFC_READ 0
++ #define IO_DMA_PORTCFG_NFC_WRITE 0
++#endif
++
++#define IO_DMA_EnableDMA(X) { BITSET(((sHwDMA *)(X))->CHCTRL, HwCHCTRL_EN_EN); }
++#define IO_DMA_DisableDMA(X) { BITSET(((sHwDMA *)(X))->CHCTRL, HwCHCTRL_EN_EN); }
++
++/**********************************************************
++* void IO_DMA_SetCTRL(unsigned uCH, unsigned uCHCTRL);
++*
++* Input : uCH = Channel number (0~2)
++* uValue = DMA control register value of corresponding channel
++* Return :
++* Description : Set the corresponding DMA control register (HwCHCTRL0~1 in General DMA, HwCHCTRL0 in Storage DMA)
++**********************************************************/
++PGDMACTRL IO_DMA_SetCTRL(unsigned uCH, unsigned uCHCTRL);
++
++/**********************************************************
++* void IO_DMA_SetDMA(unsigned uCH, void *pSRC, unsigned uSPARAM,
++* void *pDST, unsigned uDPARAM,
++* unsigned uCHCTRL, unsigned uSize);
++* Input : uCH = Channel number (0~2)
++* pSRC = source address
++* uSPARAM = source parameter
++* pDST = destination address
++* uDPARAM = destination parameter
++* uCHCTRL = DMA control register
++* uSize = Transfer size (in byte unit)
++* Return :
++* Description : Set the DMA (and start to transfer)
++**********************************************************/
++#ifdef TCC79XX
++sHwDMA *IO_DMA_SetDMA(
++ unsigned uCH,
++ void *pSRC, unsigned uSPARAM,
++ void *pDST, unsigned uDPARAM,
++ unsigned uCHCTRL,
++ unsigned uREQSRC, // added for TCC83XX 2007.9.13
++ unsigned uSize
++ );
++
++sHwDMA *IO_DMA_SetDMA_NAND(
++ unsigned uCH,
++ void *pSRC, unsigned uSPARAM,
++ void *pDST, unsigned uDPARAM,
++ unsigned uCHCTRL,
++ unsigned uEXTREQ,
++ unsigned uSize
++);
++#endif
++
++
++#define HwCHCTRL_CONT_C Hw15 // DMA transfer begins from C_SADR/C_DADR Address. It must be used after the former transfer has been executed, so that C_SADR and C_DADR contain a meaningful value.
++#define HwCHCTRL_CONT_ST (0) // DMA trnaster begins from ST_SADR/ST_DADR Address
++#define HwCHCTRL_DTM_EN Hw14 // Differential Transfer Mode Enable
++#define HwCHCTRL_DTM_ON Hw14 // Differential Transfer Mode Enable
++#define HwCHCTRL_DTM_OFF (0) // Differential Transfer Mode Disable
++#define HwCHCTRL_SYNC_ON Hw13 // Synchronize HardWare Request
++#define HwCHCTRL_SYNC_OFF (0) // Do not Synchronize HardWare Request
++#define HwCHCTRL_SYNC_EN Hw13 // Synchronize Hardware Request
++#define HwCHCTRL_HRD_W Hw12 // ACK/EOT signals are issued When DMA-Write Operation
++#define HwCHCTRL_LOCK_EN Hw11 // DMA transfer executed with lock transfer
++#define HwCHCTRL_BST_NOARB Hw10 // DMA transfer executed with no arbitration(burst operation)
++#define HwCHCTRL_HRD_WR Hw12 // ACK/EOT signals are issued When DMA-Write Operation
++#define HwCHCTRL_HRD_RD (0) // ACK/EOT signals are issued When DMA-Read Operation
++#define HwCHCTRL_LOCK_ON Hw11 // DMA transfer executed with lock transfer
++#define HwCHCTRL_LOCK_OFF (0) //
++#define HwCHCTRL_BST_BURST Hw10 // DMA transfer executed with no arbitration(burst operation)
++#define HwCHCTRL_BST_ARB (0) // DMA transfer executed wth arbitration
++#define HwCHCTRL_TYPE_SINGE (0) // SINGLE transfer with edge-triggered detection
++#define HwCHCTRL_TYPE_HW Hw8 // HW Transfer
++#define HwCHCTRL_TYPE_SW Hw9 // SW transfer
++#define HwCHCTRL_TYPE_SINGL (Hw9|Hw8) // SINGLE transfer with level-triggered detection
++#define HwCHCTRL_TYPE_SL (Hw9|Hw8) // SINGLE transfer with level-triggered detection
++#define HwCHCTRL_TYPE_SE HwZERO // SINGLE transfer with edge-triggered detection
++
++#define HwCHCTRL_BSIZE_1 (0) // 1 Burst transfer consists of 1 read or write cycle
++#define HwCHCTRL_BSIZE_2 Hw6 // 1 Burst transfer consists of 2 read or write cycles
++#define HwCHCTRL_BSIZE_4 Hw7 // 1 Burst transfer consists of 4 read or write cycles
++#define HwCHCTRL_BSIZE_8 (Hw6|Hw7) // 1 Burst transfer consists of 8 read or write cycles
++
++#define HwCHCTRL_WSIZE_8 (0) // Each cycle read or write 8bit data
++#define HwCHCTRL_WSIZE_16 Hw4 // Each cycle read or write 16bit data
++#define HwCHCTRL_WSIZE_32 Hw5 // Each cycle read or write 32bit data
++
++#define HwCHCTRL_FLAG Hw3 // Clears FLAG to 0
++#define HwCHCTRL_IEN_ON Hw2 // At the same time the FLAG goes to 1, DMA interrupt request is generated
++#define HwCHCTRL_IEN_EN Hw2 // At the same time the FLAG goes to 1, DMA interrupt request is generated
++#define HwCHCTRL_IEN_OFF ~Hw2 //
++#define HwCHCTRL_REP_EN Hw1 // The DMA channel remains enabled
++#define HwCHCTRL_REP_DIS ~Hw1 // After all of hop transfer has executed, the DMA channel is disabled
++#define HwCHCTRL_EN_ON Hw0 // DMA channel is Enabled
++#define HwCHCTRL_EN_OFF ~Hw0 // DMA channel is terminated and disabled/*}}}*/
++#define HwCHCTRL_EN_EN Hw0 // DMA channel is enabled. If software type transfer is selected, this bit generates DMA request directly, or if hardware type transfer is used, the selected interrupt request flag generate DMA request
++
++
++/************************************************************************
++* ECC Controller
++************************************************************************/
++#define IO_ECC_DisableECC() { HwECC_CTRL &= HwECC_CTRL_SE_DIS; }
++#define IO_ECC_EnableECC() { HwECC_CTRL |= HwECC_CTRL_SE_EN; }
++
++/**********************************************************
++* int IO_ECC_CheckSLC(unsigned char *pcDATA, unsigned char *pcSPARE);
++*
++* Input : pcDATA = start address of data block
++* pcSPARE = start address of spare block
++* Return : 0 = no error or correctable error
++* -1 = uncorrectable error
++* Description : Check ECC and Correct Data Error
++************************************************************/
++int IO_ECC_CheckSLC(unsigned char *pcDATA, unsigned char *pcSPARE);
++
++/************************************************************************
++* NAND Flash Controller
++************************************************************************/
++#define HwNAND_CMD (pHwND->CMD)
++#define HwNAND_LADR (pHwND->LADR)
++#define HwNAND_DATA (pHwND->WDATA.D32)
++#define HwNAND_SDATA ((cIO_NFC_MEM) ? pHwND->WDATA.D8 : pHwND->SDATA.D32)
++#define HwNAND_SADR (pHwND->SADR)
++
++#define ECC_BASEPAGE ((unsigned)&HwNAND_DATA)
++
++typedef struct { // NAND Request Structure
++ unsigned CTRL;
++ unsigned PADDR; // Physical Address
++ unsigned NFCCFG; // image of HwNFC_CTRL register for corresponding request
++ unsigned *PBUF; // Pointer for Page Data
++ void *SBUF; // Pointer for Spare Data
++} sNFC_REQ;
++
++typedef struct { // NAND Request Master Structure
++ unsigned uSEMA; // Semaphore
++ sNFC_REQ *pReqHead; // request is poped from here.
++ sNFC_REQ *pReqTail; // request is pushed to here.
++} sNFC_REQMST;
++
++#define REQ_FAIL ((sNFC_REQ *)(-1))
++
++// sNFC_REQ.CTRL bit-field definition
++//-----------------------------------------------------------------------------------
++#define REQ_INACTIVE (Hw31) // Inactive, or End of Write Request (1)
++#define REQ_EOR (Hw30) // End of Read Request, but not copied yet. (1)
++#define REQ_ECCERR (Hw29) // Uncorrectable ECC error occurred. (1)
++#define REQ_SPARE (Hw28) // Start from the spare area. (1)
++//-----------------------------------------------------------------------------------
++#define REQ_DISABLE_MK (Hw27) // Disable Writing ECC MARK in data transfer (1)
++#define REQ_ECCEN (Hw26) // Calc ECC in data transfer (1)
++#define REQ_EOW (Hw25) // End of Write Request, but not check OK bit yet. (1)
++#define REQ_WOK (Hw24) // Write OK Flag (1)
++//-----------------------------------------------------------------------------------
++#define REQ_SKIPHCMD (Hw23) // Skip header command process (1)
++#define REQ_SKIPTCMD (Hw22) // Skip tail command process (1)
++#define REQ_SKIPCMD (Hw23|Hw22)
++#define REQ_CPBACK (Hw21) // Copy-Back Enabled. (1)
++#define REQ_CPBACKW (Hw20) // Copy-Back with partial writing. (1)
++//-----------------------------------------------------------------------------------
++#define REQ_SKIP10 (Hw19) // Skip 0x10 command in writePAGE. (1)
++#define REQ_ERASEBLK (Hw18) // Erase Block command. (1)
++#define REQ_PRO_SPARE (Hw17) // Process spare area. (1)
++//-----------------------------------------------------------------------------------
++#define REQ_READY (Hw12) // All settings for Request is ready (1)
++#define REQ_DSIZE_MASK (REQ_READY - 1) // [11:0] = Data Size
++#define REQ_DSIZE(X) ((X)&(REQ_DSIZE_MASK))
++
++// uCS bit-field definition
++#define REQ_CSMASK 0x0000000F
++
++enum { IO_NFC_READ = 0, IO_NFC_WRITE = Hw15};
++
++void IO_NFC_InitDRV(void);
++void IO_NFC_OpenREQ(sNFC_REQ *pReq, unsigned uMaxNFC);
++void IO_NFC_CloseREQ(void);
++void IO_NFC_PopREQ(sNFC_REQ *pReq);
++void IO_NFC_EnableREQ(sNFC_REQ *pReq);
++void IO_NFC_IRQHandler(void);
++void IO_NFC_StartREAD(sNFC_REQ *pReq);
++void IO_NFC_ReadPAGE(unsigned *pBuffer, unsigned uDSize);
++void IO_NFC_ReadDATA(unsigned char *pBuffer, unsigned uDSize);
++int IO_NFC_CopyPAGE(unsigned char *pDest, unsigned *pSrc, unsigned uSize);
++sNFC_REQ *IO_NFC_PushRREQ(unsigned uCS, unsigned uPage, unsigned uColumn, unsigned *pSpare, unsigned uSize);
++void IO_NFC_StartWRITE(sNFC_REQ *pReq);
++void IO_NFC_WritePAGE(unsigned *pBuffer, unsigned uDSize);
++void IO_NFC_WriteDATA(unsigned char *pBuffer, unsigned uDSize);
++sNFC_REQ *IO_NFC_PushWREQ( unsigned uCS, unsigned uPage, unsigned uColumn,
++ unsigned *pData, unsigned char *pSpare, unsigned uSize);
++int IO_NFC_CheckWOK(sNFC_REQ *pReq);
++unsigned IO_NFC_LookupID(unsigned uDID);
++unsigned IO_NFC_SetCONFIG(unsigned uType);
++unsigned IO_NFC_MakeNFC(unsigned uCS);
++unsigned IO_NFC_GetID(unsigned uCS);
++unsigned IO_NFC_ResetNAND(unsigned uCS);
++void IO_NFC_SetCYCLE(void);
++void IO_NFC_WaitEOT(sNFC_REQ *pReq);
++
++extern unsigned uIO_NFC_CONFIG, uIO_NFC_MASK;
++extern unsigned char cIO_NFC_MEM;
++extern PNFC pIO_NFC_HwND;
++
++#define IO_NFC_MakeMASK(uCS) ((uIO_NFC_CONFIG & (Hw14 << (uCS*16))) ? 0xFFFF : 0xFF)
++
++#define IO_NFC_SetNFC(uCS) \
++{ \
++ if (cIO_NFC_MEM) \
++ HwCSCFG2 = IO_NFC_MakeNFC(uCS); \
++ else \
++ HwNFC_CTRL = IO_NFC_MakeNFC(uCS); \
++}
++
++#ifdef TCC79XX
++ #if defined(TCC7900_BOARD)
++ #define GPIO_ND_nCS HwPORTCFG2
++ #define GPIO_ND_nCS1Bit Hw5
++ #define GPIO_ND_nCS0Bit Hw4
++ #define GPIO_ND_nWP HwPORTCFG2
++ #define GPIO_ND_nWPBit Hw2
++ #define GPIO_ND_RDY HwPORTCFG2
++ #define GPIO_ND_RDYBit Hw3
++ #define GPIO_NFC_nWP HwPORTCFG2
++ #define GPIO_NFC_nWPBit Hw17
++ #elif defined(TCC792X_BOARD)
++ #define GPIO_ND_nCS HwPORTCFG2
++ #define GPIO_ND_nCS1Bit Hw9
++ #define GPIO_ND_nCS0Bit Hw8
++ #define GPIO_ND_RDY HwPORTCFG2
++ #define GPIO_ND_RDYBit Hw14
++ #endif
++#elif defined(TCC92XX) || defined(TCC89XX)
++ #if defined(TCC9200_BOARD)
++ #define GPIO_ND_nCS HwPORTCFG2
++ #define GPIO_ND_nCS1Bit Hw9
++ #define GPIO_ND_nCS0Bit Hw8
++ #define GPIO_ND_RDY HwPORTCFG2
++ #define GPIO_ND_RDYBit Hw14
++ #endif
++#endif
++
++#define IO_NFC_DisableCS() \
++{ \
++ if (cIO_NFC_MEM) \
++ BITSET(GPIO_ND_nCS, GPIO_ND_nCS1Bit|GPIO_ND_nCS0Bit); \
++ else \
++ BITSET(HwNFC_CTRL, HwNFC_CTRL_CFG_NOACT); \
++}
++
++#define IO_NFC_EnableCS(uCS) \
++{ \
++ if (cIO_NFC_MEM) \
++ BITSCLR(GPIO_ND_nCS, (uCS) ? GPIO_ND_nCS0Bit: GPIO_ND_nCS1Bit, (uCS) ? GPIO_ND_nCS1Bit: GPIO_ND_nCS0Bit); \
++ else \
++ BITSCLR(HwNFC_CTRL, (uCS) ? Hw22: Hw23, (uCS) ? Hw23 : Hw22); \
++}
++
++#define IO_NFC_DisableWP() \
++{ \
++ if (cIO_NFC_MEM) \
++ BITSET(GPIO_ND_nWP, GPIO_ND_nWPBit); \
++ else \
++ BITSET(GPIO_NFC_nWP, GPIO_NFC_nWPBit); \
++}
++
++#define IO_NFC_EnableWP() \
++{ \
++ if (cIO_NFC_MEM) \
++ BITCLR(GPIO_ND_nWP, GPIO_ND_nWPBit); \
++ else \
++ BITCLR(GPIO_NFC_nWP, GPIO_NFC_nWPBit); \
++}
++
++#define IO_NFC_NotREADY() \
++ ( (cIO_NFC_MEM) ? ISZERO(GPIO_ND_RDY, GPIO_ND_RDYBit) : ISZERO(HwNFC_CTRL, HwNFC_CTRL_RDY_RDY))
++
++#define IO_NFC_WaitSTARDY() { ; }
++
++void IO_NFC_WaitREADY(void);
++void IO_NFC_WaitREADYForWriteCommand(void);
++
++#define IO_NFC_WaitDONE(X) { while (ISZERO(HwNFC_IREQ, (X))); }
++
++#define USE_NFC_DMA
++#define USE_NFC_FIFO // only meaningful when "USE_NFC_DMA" is defined.
++
++/************************************************************************
++* DTCM Allocation Manager
++************************************************************************/
++//#define USE_DYNAMIC_DTCM
++
++#if defined(TCC79XX)
++ #define DTCM_BASE 0xA0000000
++ #define DTCM_LIMIT 0xA0002000
++ #define DTCM_SIZE (DTCM_LIMIT - DTCM_BASE)
++ #define ITCM_SIZE 0x00001000
++ #define IO_USB_BUFFER0_BASE (DTCM_BASE + 0x1800)
++ #define IO_USB_BUFFER1_BASE (DTCM_BASE + 0x1A00)
++ #define IO_NFC_BUFFER0_BASE (DTCM_BASE + 0x1C00)
++ #define IO_NFC_BUFFER1_BASE (DTCM_BASE + 0x1E00)
++#elif defined(TCC92XX) || defined(TCC89XX)
++ #define DTCM_BASE 0xA0000000
++ #define DTCM_LIMIT 0xA0004000
++ #define DTCM_SIZE (DTCM_LIMIT - DTCM_BASE)
++ #define ITCM_SIZE 0x00004000
++ #define IO_USB_BUFFER0_BASE (DTCM_BASE + 0x1800)
++ #define IO_USB_BUFFER1_BASE (DTCM_BASE + 0x1A00)
++ #define IO_NFC_BUFFER0_BASE (DTCM_BASE + 0x1C00)
++ #define IO_NFC_BUFFER1_BASE (DTCM_BASE + 0x1E00)
++#endif
++
++
++#define IO_HDD_BUFFER_BASE IO_NFC_BUFFER0_BASE
++
++#ifdef USE_DYNAMIC_DTCM
++ #define DTCM_MaskSize (8 * sizeof(unsigned)) // bit width of uDTCM_MAT[] table
++ #define DTCM_Mask ((unsigned)((1 << DTCM_MaskSize) - 1)) // mask pattern of uDTCM_MAT[] table
++ #define DTCM_SIZE 4096
++ #define DTCM_AUNIT 64 // minimum allocation unit.
++ #define DTCM_MAXBULK (DTCM_SIZE / DTCM_AUNIT) // maximum concurrent allocation.
++ #define DTCM_MATSIZE ((DTCM_SIZE / DTCM_AUNIT) / DTCM_MaskSize) // Bitmap table for each chunk (1 = used, 0 = not-used)
++#endif
++
++void IO_DTCM_InitDRV(void);
++void *IO_DTCM_Malloc(unsigned uDSize);
++void IO_DTCM_Free(void *pSrc, unsigned uDSize);
++
++unsigned IO_DTCM_AllocMAT(unsigned uASize);
++unsigned IO_DTCM_FindFMAX(void);
++
++
++/************************************************************************
++* SRAM ADDR
++************************************************************************/
++#ifdef TCC79XX
++ #define SRAM_BASE 0x00000000
++ #define SRAM_LIMIT 0x00010000
++#elif defined(TCC92XX) || defined(TCC89XX)
++ #define SRAM_BASE 0x10000000
++ #define SRAM_LIMIT 0x00004000
++#endif
++
++/************************************************************************
++* Interrupt Controller
++************************************************************************/
++#ifdef TCC92XX
++
++ // Interrupt Enable 0
++/*
++ #define IO_INT_EHI0 HwINT0_EHI0
++ #define IO_INT_ECC HwINT0_ECC
++ #define IO_INT_DMA HwINT0_DMA
++ #define IO_INT_TSADC HwINT0_TSADC
++ #define IO_INT_G2D HwINT0_G2D
++ #define IO_INT_3DMMU HwINT0_3DMMU
++ #define IO_INT_3DGP HwINT0_3DGP
++ #define IO_INT_3DPP HwINT0_3DPP
++ #define IO_INT_VCDC HwINT0_VCDC
++ #define IO_INT_JPGD HwINT0_JPGD
++ #define IO_INT_JPGE HwINT0_JPGE
++ #define IO_INT_VIPET HwINT0_VIPET
++ #define IO_INT_LCD1 HwINT0_LCD1
++ #define IO_INT_LCD0 HwINT0_LCD0
++ #define IO_INT_CAM HwINT0_CAM
++ #define IO_INT_SC1 HwINT0_SC1
++ #define IO_INT_SC0 HwINT0_SC0
++ #define IO_INT_EI11 HwINT0_EI11
++ #define IO_INT_EI10 HwINT0_EI10
++ #define IO_INT_EI9 HwINT0_EI9
++ #define IO_INT_EI8 HwINT0_EI8
++ #define IO_INT_EI7 HwINT0_EI7
++ #define IO_INT_EI6 HwINT0_EI6
++ #define IO_INT_EI5 HwINT0_EI5
++ #define IO_INT_EI4 HwINT0_EI4
++ #define IO_INT_EI3 HwINT0_EI3
++ #define IO_INT_EI2 HwINT0_EI2
++ #define IO_INT_EI1 HwINT0_EI1
++ #define IO_INT_EI0 HwINT0_EI0
++ #define IO_INT_SMUI2C HwINT0_SMUI2C
++ #define IO_INT_TC1 HwINT0_TC1
++ #define IO_INT_TC0 HwINT0_TC0
++*/
++ enum {
++ IO_INT_nTC0, // 0
++ IO_INT_nTC1,
++ IO_INT_nSMUI2C,
++ IO_INT_nEI0,
++ IO_INT_nEI1,
++ IO_INT_nEI2, // 5
++ IO_INT_nEI3,
++ IO_INT_nEI4,
++ IO_INT_nEI5,
++ IO_INT_nEI6,
++ IO_INT_nEI7, // 10
++ IO_INT_nEI8,
++ IO_INT_nEI9,
++ IO_INT_nEI10,
++ IO_INT_nEI11,
++ IO_INT_nSC0, // 15
++ IO_INT_nSC1,
++ IO_INT_nCAM,
++ IO_INT_nLCD0,
++ IO_INT_nLCD1,
++ IO_INT_nVIPET, // 20
++ IO_INT_nJPGE,
++ IO_INT_nJPGD,
++ IO_INT_nVCDC,
++ IO_INT_n3DPP,
++ IO_INT_n3DGP, // 25
++ IO_INT_n3DMMU,
++ IO_INT_nG2D,
++ IO_INT_nTSADC,
++ IO_INT_nDMA,
++ IO_INT_nECC, // 30
++ IO_INT_nEHI0
++ };
++
++ // Interrupt Enable 1
++/*
++ #define IO_INT_AEIRQ HwINT1_AEIRQ
++ #define IO_INT_ASIRQ HwINT1_ASIRQ
++ #define IO_INT_AIRQ HwINT1_AIRQ
++ #define IO_INT_APMU HwINT1_APMU
++ #define IO_INT_AUDIO HwINT1_AUDIO
++ #define IO_INT_ADMA HwINT1_ADMA
++ #define IO_INT_DAITX HwINT1_DAITX
++ #define IO_INT_DAIRX HwINT1_DAIRX
++ #define IO_INT_CDRX HwINT1_CDRX
++ #define IO_INT_TSIF1 HwINT1_TSIF1
++ #define IO_INT_TSIF0 HwINT1_TSIF0
++ #define IO_INT_GPS2 HwINT1_GPS2
++ #define IO_INT_GPS1 HwINT1_GPS1
++ #define IO_INT_GPS0 HwINT1_GPS0
++ #define IO_INT_UOTG HwINT1_UOTG
++ #define IO_INT_UART HwINT1_UART
++ #define IO_INT_SPDTX HwINT1_SPDTX
++ #define IO_INT_SD1 HwINT1_SD1
++ #define IO_INT_SD0 HwINT1_SD0
++ #define IO_INT_RTC HwINT1_RTC
++ #define IO_INT_RMT HwINT1_RMT
++ #define IO_INT_NFG HwINT1_NFC
++ #define IO_INT_MS HwINT1_MS
++ #define IO_INT_MPEFEC HwINT1_MPEFEC
++ #define IO_INT_I2C HwINT1_I2C
++ #define IO_INT_HDD HwINT1_HDD
++ #define IO_INT_GPSB HwINT1_GPSB
++ #define IO_INT_HDMI HwINT1_HDMI
++ #define IO_INT_EHI1 HwINT1_EHI1
++*/
++ enum {
++ IO_INT_nEHI1, // 0
++ IO_INT_nNotUsed0,
++ IO_INT_nHDMI,
++ IO_INT_nNotUsed1,
++ IO_INT_nGPSB,
++ IO_INT_nHDD, // 5
++ IO_INT_nI2C,
++ IO_INT_nMPEFEC,
++ IO_INT_nMS,
++ IO_INT_nNFC,
++ IO_INT_nRMT, // 10
++ IO_INT_nRTC,
++ IO_INT_nSD0,
++ IO_INT_nSD1,
++ IO_INT_nSPDTX,
++ IO_INT_nUART, // 15
++ IO_INT_nUOTG,
++ IO_INT_nNotUsed2,
++ IO_INT_nGPS0,
++ IO_INT_nGPS1,
++ IO_INT_nGPS2, // 20
++ IO_INT_nTSIF0,
++ IO_INT_nTSIF1,
++ IO_INT_nCDRX,
++ IO_INT_nDAIRX,
++ IO_INT_nDAITX, // 25
++ IO_INT_nADMA,
++ IO_INT_nAUDIO,
++ IO_INT_nAPMU,
++ IO_INT_nAIRQ,
++ IO_INT_nASIRQ, // 30
++ IO_INT_nAEIRQ,
++ };
++
++#elif defined(TCC79XX)
++ #define IO_INT_HwIEN HwIEN
++ #define IO_INT_HwISTS HwSTS
++ #define IO_INT_HwMSTS HwMSTS
++ #define IO_INT_HwICLR HwCLR
++ #define IO_INT_HwISEL HwSEL
++ #define IO_INT_HwTMODE HwMODE
++ #define IO_INT_HwPOL HwPOL
++ #define IO_INT_HwEXT0 HwINT_EI0
++ #define IO_INT_HwEXT1 HwINT_EI1
++ #define IO_INT_HwEXT2 HwINT_EI2
++ #define IO_INT_HwEXT3 HwINT_EI3
++ #define IO_INT_HwRTC HwINT_RTC
++ #define IO_INT_HwGPSB HwINT_GPSB
++ #define IO_INT_HwGPSB_CH0 HwINT_GPSB
++ #define IO_INT_HwGPSB_CH1 HwINT_GPSB
++ #define IO_INT_HwGPSB_CH2 HwINT_GPSB
++ #define IO_INT_HwGPSB_CH3 HwINT_GPSB
++ #define IO_INT_HwTIMER (HwINT_TC1 | HwINT_TC0)
++ #define IO_INT_HwTC0 HwINT_TC0
++ #define IO_INT_HwTC1 HwINT_TC1
++ #define IO_INT_HwSCORE HwINT_SCORE
++ #define IO_INT_HwSPDTX HwINT_SPDTX
++ #define IO_INT_HwSEL0 HwINT_SEL0
++ #define IO_INT_HwSEL1 HwINT_SEL1
++ #define IO_INT_HwSC HwINT_SC
++ #define IO_INT_HwI2C HwINT_I2C
++ #define IO_INT_HwDAIRX HwINT_DAIRX
++ #define IO_INT_HwDAITX HwINT_DAITX
++ #define IO_INT_HwCDIF HwINT_CDRX
++ #define IO_INT_HwEHI HwINT_HPI
++ #define IO_INT_HwUART HwINT_UT
++ #define IO_INT_HwUART0 HwINT_UT
++ #define IO_INT_HwUART1 HwINT_UT
++ #define IO_INT_HwSEL2 HwINT_SEL2
++ #define IO_INT_HwG2D HwINT_G2D
++ #define IO_INT_HwUSBD HwINT_UD
++ #define IO_INT_HwUSBH HwINT_UH
++ #define IO_INT_HwDMA HwINT_DMA
++ #define IO_INT_HwDMA_CH0 HwINT_DMA
++ #define IO_INT_HwDMA_CH1 HwINT_DMA
++ #define IO_INT_HwDMA_CH2 HwINT_DMA
++ #define IO_INT_HwHDD HwINT_HDD
++ #define IO_INT_HwSEL3 HwINT_SEL3
++ #define IO_INT_HwNFC HwINT_NFC
++ #define IO_INT_HwSDMMC HwINT_SD
++ #define IO_INT_HwCAM HwINT_CAM
++ #define IO_INT_HwLCD HwINT_LCD
++ #define IO_INT_HwADC HwINT_ADC
++ #define IO_INT_HwSEL4 HwINT_SEL4
++ #define IO_INT_HwGSIO 0
++
++ #define IO_INT_HwVIDEO HwINT_SEL0
++ #define IO_INT_HwEXT5 HwINT_SEL1
++ #define IO_INT_HwEHI1 HwINT_SEL2
++ #define IO_INT_HwMSC HwINT_SEL3
++ #define IO_INT_HwEXT7 HwINT_SEL4
++ #define IO_INT_HwUSBDMA HwINT_SEL4
++
++ enum {
++ IO_INT_nEI0, // 0
++ IO_INT_nEI1,
++ IO_INT_nEI2,
++ IO_INT_nEI3,
++ IO_INT_nRTC,
++ IO_INT_nGPSB, // 5
++ IO_INT_nTC0,
++ IO_INT_nTC1,
++ IO_INT_nVCORE,
++ IO_INT_nSPDTX,
++ IO_INT_nVIDEO, // 10
++ IO_INT_nEI5,
++ IO_INT_nSC,
++ IO_INT_nI2C,
++ IO_INT_nDAIRX,
++ IO_INT_nDAITX, // 15
++ IO_INT_nCDRX,
++ IO_INT_nEHI,
++ IO_INT_nUT0,
++ IO_INT_nEHI1,
++ IO_INT_nUDMA, // 20
++ IO_INT_nUD,
++ IO_INT_nUH,
++ IO_INT_nDMA,
++ IO_INT_nHDD,
++ IO_INT_nMS, // 25
++ IO_INT_nNFC,
++ IO_INT_nSD,
++ IO_INT_nCAM,
++ IO_INT_nLCD,
++ IO_INT_nADC, // 30
++ IO_INT_nUSBDMA
++ };
++#endif
++
++#if 0
++#define IO_INT_EnableIRQ(X) \
++ { \
++ BITSET(IO_INT_HwISEL, X); \
++ BITSET(IO_INT_HwIEN, X); \
++ }
++#define IO_INT_DisableIRQ(X) \
++ { \
++ BITCLR(HwIEN, X); \
++ }
++#endif
++/************************************************************************
++* EHI Controller
++************************************************************************/
++#define EHI_MD_68 HwEHCFG_MD_68
++#define EHI_MD_80 HwEHCFG_MD_80
++#define EHI_USE_MASK Hw1
++#define EHI_BW_8 HwEHCFG_BW_8
++#define EHI_BW_16 HwEHCFG_BW_16
++#define EHI_USE_RDY HwEHCFG_RDYE_RDY
++#define EHI_USE_IRQ HwEHCFG_RDYE_IRQ
++#define EHI_HIGH_RDY HwZERO
++#define EHI_LOW_RDY HwEHCFG_RDYP
++
++extern unsigned uEHI_CSCFG, uEHI_TACC;
++extern volatile unsigned *pEHI_CSCFG;
++
++#ifdef EHIS_TCC77X
++ #define EHIS_HwEHST 0x90000800 // R/W, Status register
++ #define EHIS_HwEHIINT 0x90000804 // R/W, Internal interrupt control register
++ #define EHIS_HwEHEINT 0x90000808 // R/W, External interrupt control register
++ #define EHIS_HwEHA 0x9000080C // R/W, Address register
++ #define EHIS_HwEHAM 0x90000810 // R, Address masking register
++ #define EHIS_HwEHD 0x90000814 // R/W, Data register
++ #define EHIS_HwEHSEM 0x90000818 // R/W, Semaphore register
++ #define EHIS_HwEHCFG 0x9000081C // R/W, Configuration register
++ #define EHIS_HwEHIND 0x90000820 // W, Index register
++ #define EHIS_HwEHRWCS 0x90000824 // R/W, Read/Write Control/Status register
++#endif
++
++#ifdef EHI_MASTER
++ /**********************************************************
++ * void IO_EHI_InitDRV(unsigned uCONFIG, unsigned uCS, unsigned uMask);
++ *
++ * Input : uCONFIG = Configuration Parameter
++ * Hw0 = 68000 (1), x86 (0) interface
++ * Hw1 = Use Mask (1), Don't used Mask (0)
++ * Hw2 = 8bit (1), 16bit (0) interface
++ * Hw3 = used as Ready signal (1), used as Interrupt signal (0)
++ * Hw4 = Active Low Ready signal (1), Active High Ready signal (0)
++ * uCS = Chip Select number for EHI slave (0~3)
++ * uMask = Address Mask Pattern.
++ * Return :
++ * Description : Initialize EHI I/F module at the Master Site.
++ ************************************************************/
++ void IO_EHI_InitDRV(unsigned uCONFIG, unsigned uCS, unsigned uMask);
++
++ /**********************************************************
++ * unsigned IO_EHI_SetSPEED(unsigned uTAcc);
++ *
++ * Input : uTAcc = Access time in nano second
++ * Output :
++ * Return : previous CSCFG value
++ *
++ * Description : Set EHI Access parameter
++ ************************************************************/
++ unsigned IO_EHI_SetSPEED(unsigned uTAcc);
++
++ /**********************************************************
++ * unsigned IO_EHI_IncSPEED(int iTAccDelta);
++ *
++ * Input : iTAccDelta = Increment(+)/Decrement(-) of Access time in nano second
++ * Output :
++ * Return : Old TAcc
++ *
++ * Description : Increment EHI Access parameter
++ ************************************************************/
++ unsigned IO_EHI_IncSPEED(int iTAccDelta);
++
++ /**********************************************************
++ * void IO_EHI_WriteREG(unsigned uADDR, unsigned uDATA, unsigned uSize);
++ *
++ * Input : uADDR = Address of EHI Register
++ * uDATA = Data for EHI Register
++ * uSize = Register Size in byte.
++ * Return :
++ * Description : Write EHI Register
++ ************************************************************/
++ void IO_EHI_WriteREG(unsigned uADDR, unsigned uDATA, unsigned uSize);
++
++ /**********************************************************
++ * unsigned IO_EHI_ReadREG(unsigned uADDR, unsigned uSize);
++ *
++ * Input : uADDR = Address of EHI Register
++ * uSize = Register Size in byte.
++ * Return : Register value
++ * Description : Read EHI Register
++ ************************************************************/
++ unsigned IO_EHI_ReadREG(unsigned uADDR, unsigned uSize);
++
++ /**********************************************************
++ * unsigned IO_EHI_ReadST(void);
++ *
++ * Input :
++ * Output :
++ * Return : EHST value
++ *
++ * Description : Read EHST Register
++ ************************************************************/
++ unsigned IO_EHI_ReadST(void);
++
++ /**********************************************************
++ * unsigned IO_EHI_WriteDATA(unsigned uADDR, unsigned uParam1, unsigned uParam2);
++ *
++ * Input : uADDR = Address of EHI Slave memory.
++ * uParam1 = Pointer or Data value to write.
++ * uParam2
++ * [31] = Non-continuous(0), Continuous(1)
++ * [30:0] = Data amount to Transfer (word unit)
++ * Return : 0
++ * Description : Write data to Memory of Slave
++ ************************************************************/
++ unsigned IO_EHI_WriteDATA(unsigned uADDR, unsigned uParam1, unsigned uParam2);
++
++ /**********************************************************
++ * unsigned IO_EHI_ReadDATA(unsigned uADDR, unsigned uParam1, unsigned uParam2);
++ *
++ * Input : uADDR = Address of EHI Slave memory.
++ * uParam1 = Pointer to store read data.
++ * uParam2
++ * [31] = Non-continuous (0), Continuous (1) transfer.
++ * [30:0] = Data amount to Transfer (word unit)
++ * Return : Data value read or Pointer to bulk of data read.
++ * Description : Read data from Memory of Slave
++ ************************************************************/
++ unsigned IO_EHI_ReadDATA(unsigned uADDR, unsigned uParam1, unsigned uParam2);
++#else
++ /**********************************************************
++ * void IO_EHI_InitDRVS(unsigned uCONFIG);
++ *
++ * Input : uCONFIG = Configuration Parameter
++ * Hw0 = 68000 (1), x86 (0) interface
++ * Hw2 = 8bit (1), 16bit (0) interface
++ * Hw3 = used as Ready signal (1), used as Interrupt signal (0)
++ * Hw4 = Active Low Ready signal (1), Active High Ready signal (0)
++ * Return :
++ * Description : Initialize EHI I/F module at the Slave Site.
++ ************************************************************/
++ void IO_EHI_InitDRVS(unsigned uCONFIG);
++#endif
++
++
++/************************************************************************
++* Timer/Counter
++************************************************************************/
++#if defined(TCC92XX)
++ #define IO_TMR_IREQT0 HwTIREQ_TI0
++ #define IO_TMR_IREQT1 HwTIREQ_TI1
++ #define IO_TMR_IREQT2 HwTIREQ_TI2
++ #define IO_TMR_IREQT3 HwTIREQ_TI3
++ #define IO_TMR_IREQT4 HwTIREQ_TI4
++ #define IO_TMR_IREQT5 HwTIREQ_TI5
++ #define IO_TMR_ClearTIREQ(X) { HwTMR->TIREQ = 1 << (X); }
++#else
++#ifdef TCC79XX
++ #define IO_TMR_IREQT0 HwTIREQ_TI0
++ #define IO_TMR_IREQT1 HwTIREQ_TI1
++ #define IO_TMR_IREQT2 HwTIREQ_TI2
++ #define IO_TMR_IREQT3 HwTIREQ_TI3
++ #define IO_TMR_IREQT4 HwTIREQ_TI4
++ #define IO_TMR_IREQT5 HwTIREQ_TI5
++#endif
++#define IO_TMR_ClearTIREQ(X) { HwTIREQ = 1 << (X); }
++#endif
++
++/**********************************************************
++* void IO_TMR_SetTIMER(unsigned uCH, unsigned uCTRL, unsigned uTREF, unsigned uTMREF);
++*
++* Input : uCH = Select timer channel. 0~5 is available.
++* uCTRL = Timer Control Register (HwTCFG) value.
++* uTREF = Timer Reference Register (HwTREF) value.
++* uTMREF = Timer Middle Reference Register (HwTMREF) value.
++* Return :
++* Description : Set and Enable a Timer/Counter (timer is automatically enabled regardless of uCTRL value)
++**********************************************************/
++void IO_TMR_SetTIMER(unsigned uCH, unsigned uCTRL, unsigned uTREF, unsigned uTMREF);
++
++/**********************************************************
++* unsigned IO_TMR_GetTIMER(unsigned uCH);
++*
++* Input : uCH = Select timer channel. 0~5 is available.
++* Return : Current TCNT value.
++* Description : Get the current count value of channel.
++**********************************************************/
++unsigned IO_TMR_GetTIMER(unsigned uCH);
++
++/**********************************************************
++* void IO_TMR_DisableTIMER(unsigned uCH);
++*
++* Input : uCH = Select timer channel. 0~5 is available.
++* Return :
++* Description : Disable a Timer
++**********************************************************/
++void IO_TMR_DisableTIMER(unsigned uCH);
++
++/**********************************************************
++* void IO_TMR_EnableTIMER(unsigned uCH);
++*
++* Input : uCH = Select timer channel. 0~5 is available.
++* Return :
++* Description : Enable a Timer
++**********************************************************/
++void IO_TMR_EnableTIMER(unsigned uCH);
++
++#define DBG_MAX_MEASURE 32
++#define START_MEASURE 1
++#define STOP_MEASURE 0
++
++typedef struct
++{
++ unsigned uStamp; // Time Stamp value at the start time.
++ char *pDescription; // Timer description string.
++ unsigned uPreCH; // Bitmap of Channels that must to be enabled ahead to measure this channel.
++ unsigned uMin; // 1tic ~= 2.67us
++ unsigned uMax; // 1tic ~= 2.67us
++ unsigned long long uSum; // summation of duration
++ unsigned uNum; // Number of durations measured. The average duration is acquired by (uSum / uNum)
++} sDBG_Timer;
++
++extern sDBG_Timer DBG_Timer[DBG_MAX_MEASURE];
++extern unsigned uMEA_CTRL, uMEA_STATE;
++
++/**********************************************************
++* void IO_TMR_InitMEASURE(unsigned uCH);
++*
++* Input : uCH = Select a channel for initialize. (0xFFFFFFFF, 0 ~ 31 are possible, 0xFFFFFFFF means all of channel)
++* (this is not same as physical timer channel number. this uses TIMER channel 4 only)
++* Return :
++* Description : Initialize MEASURE variables.
++* If all of channel should be initialized, use -1 as channel number.
++**********************************************************/
++void IO_TMR_InitMEASURE(unsigned uCH);
++
++/**********************************************************
++* void IO_TMR_StartMEASURE(unsigned uCH, char *pDescriptor);
++*
++* Input : uCH = Select a channel for measure. (0 ~ 31 are possible)
++* (this is not same as physical timer channel number. this uses TIMER channel 4 only)
++* pDescriptor = string for describing this channel.
++* Return :
++* Description : Start the timer for measuring a duration.
++* This uses only timer/counter 4.
++* It can measure the min/max/avg time duration of certain operation with limited period.
++**********************************************************/
++void IO_TMR_StartMEASURE(unsigned uCH, unsigned uPreCH, char *pDescriptor);
++void IO_TMR_StopMEASURE(unsigned uCH);
++void IO_TMR_StartMEASURE_NoIRQCnt(unsigned uCH, unsigned uPreCH, char *pDescriptor);
++unsigned IO_TMR_StopMEASURE_NoIRQCnt(unsigned uCH);
++
++/**********************************************************
++* void IO_TMR_FinishMEASURE(unsigned uCH);
++*
++* Input : uCH = Select a channel for measure. (0 ~ 31 are possible)
++* (this is not same as physical timer channel number. this uses TIMER channel 4 only)
++* Return :
++* Description : Finish the timer for measuring a duration.
++* This uses only timer/counter 4.
++* It stops measuring, and update min/max/sum/num field.
++**********************************************************/
++void IO_TMR_FinishMEASURE(unsigned uCH);
++
++/**********************************************************
++* void IO_TMR_GetMEASURE(unsigned uCH, unsigned *pAvg, unsigned *pNum, unsigned *pMin, unsigned *pMax);
++*
++* Input : uCH = Select a channel for measure. (0 ~ 31 are possible)
++* (this is not same as physical timer channel number. this uses TIMER channel 4 only)
++* pAvg = pointer for containing average time
++* pNum = pointer for containing number of times
++* pMin = pointer for containing minimum time
++* pMax = pointer for containing maximum time
++* *) all pointers can be zero not to contain values.
++* Return :
++* Description :
++**********************************************************/
++void IO_TMR_GetMEASURE(unsigned uCH, unsigned *pAvg, unsigned *pNum, unsigned *pMin, unsigned *pMax);
++
++// Time Duration Meter
++#ifndef USE_DOMEASURE
++ #define DoMEASURE(CH, ONOFF, PreCH, Descriptor) {;}
++#else
++ #define DoMEASURE(CH, ONOFF, PreCH, Descriptor) \
++ { \
++ if (uMEA_CTRL & (1 << (CH))) \
++ { \
++ if ((ONOFF) != 0) \
++ IO_TMR_StartMEASURE(CH, PreCH, Descriptor); \
++ else \
++ IO_TMR_FinishMEASURE(CH); \
++ } \
++ }
++#endif
++
++/**********************************************************
++* unsigned int IO_TMR_Get32bitValue(void);
++*
++* Input :
++* Return : 32-bit Counter Current Value (main counter)
++* Description :
++**********************************************************/
++unsigned int IO_TMR_Get32bitValue(void);
++
++
++/************************************************************************
++* UART Controller
++************************************************************************/
++
++/**********************************************************
++*
++* void IO_UART_Test(unsigned uCH);
++*
++* Input : uCH = channel number (0~2)
++* Output :
++* Return :
++*
++* Description : Test UART functions.
++**********************************************************/
++void IO_UART_Test(unsigned uCH);
++
++/**********************************************************
++*
++* void IO_UART_Init(unsigned uCH);
++*
++* Input : uCH = channel number (0~2)
++* Output :
++* Return :
++*
++* Description : Initialize UART registers and UART Clocks.
++**********************************************************/
++void IO_UART_Init(unsigned uCH);
++
++/**********************************************************
++*
++* void IO_UART_WriteString(unsigned uCH, const char *ccptrString)
++*
++* Input : uCH = channel number (0~2)
++* ccptrString = string to print
++* Output :
++* Return :
++*
++* Description : print argument string considering '\n' as '\r'+'n'.
++**********************************************************/
++void IO_UART_WriteString(unsigned uCH, const char *ccptrString);
++
++/**********************************************************
++*
++* void IO_UART_WriteByte(unsigned uCH, char cChar)
++*
++* Input : uCH = channel number (0~2)
++* cChar = character to print
++* Output :
++* Return :
++*
++* Description : Print one character. Consider '\n' as '\r' + '\n'.
++**********************************************************/
++void IO_UART_WriteByte(unsigned uCH, char cChar);
++
++/**********************************************************
++*
++* int IO_UART_InputByte(unsigned uCH, char *cptrChar)
++*
++* Input : uCH = channel number (0~2)
++* cptrChar = pointer for receiving character
++* Output :
++* Return : 0 = there is no input.
++* 1 = there exist at least one byte and it is contained at the *cptrChar.
++* Description : Check there is at least one character in buffer, and if exist, store the code to *cptrChar and return 1.
++* Or return 0.
++**********************************************************/
++int IO_UART_InputByte(unsigned uCH, char *cptrChar);
++
++/**********************************************************
++*
++* void IO_UART0_PutExtChar(unsigned uCH, const unsigned char cucChar)
++*
++* Input : uCH = channel number (0~2)
++* cucChar = character code
++* Output : Send one character
++* Return :
++*
++* Description : Print cucChar if cucChar is printable code or print '.' character.
++**********************************************************/
++void IO_UART_PutExtChar(unsigned uCH, const unsigned char cucChar);
++
++/**********************************************************
++*
++* char IO_UART_GetChar(unsigned uCH)
++*
++* Input : uCH = channel number (0~2)
++* Output :
++* Return : Received character
++*
++* Description : Wait until at least one character is received & return the code with echoing.
++**********************************************************/
++char IO_UART_GetChar(unsigned uCH);
++
++/**********************************************************
++*
++* char IO_UART_GetCh(unsigned uCH)
++*
++* Input : uCH = channel number (0~2)
++* Output :
++* Return : Received character
++*
++* Description : Wait until at least one character is received & return the code without echoing.
++**********************************************************/
++char IO_UART_GetCh(unsigned uCH);
++
++
++/************************************************************************
++* RTC Controller
++************************************************************************/
++typedef struct {
++ unsigned char second; // (0 ~ 59)
++ unsigned char minute; // (0 ~ 59)
++ unsigned char hour; // (0 ~ 23)
++ unsigned char day; // Day of Week (SUN=0, MON, TUE, WED, THR, FRI, SAT=6)
++
++ unsigned char date; // (1 ~ 28,29,30,31)
++ unsigned char month; // (1 ~ 12)
++ unsigned short year;
++} IO_RTC_DATETIME;
++
++/**********************************************************************************
++* unsigned IO_RTC_Init(unsigned uWUPolarity);
++*
++* Input :
++* Return : 0
++* Description : Initialize RTC, RTC is disabled.
++* This function should not be called in normal case.
++**********************************************************************************/
++unsigned IO_RTC_Init(unsigned uWUPolarity);
++
++/**********************************************************************************
++* unsigned IO_RTC_Start(void);
++*
++* Input :
++* Return : value of RTCCON register after enabled.
++* Description : RTC starts to operate.
++**********************************************************************************/
++unsigned IO_RTC_Start(void);
++
++/**********************************************************************************
++* unsigned IO_RTC_Stop(void);
++*
++* Input :
++* Return : value of RTCCON register after disabled.
++* Description : RTC stops to operate.
++**********************************************************************************/
++unsigned IO_RTC_Stop(void);
++
++/**********************************************************************************
++* unsigned IO_RTC_SetCON(unsigned uRTCCON);
++*
++* Input : uRTCCON = value for RTCCON register.
++* Return : value of RTCCON register after updated.
++* Description : Set RTCCON register as wanted value.
++**********************************************************************************/
++unsigned IO_RTC_SetCON(unsigned uRTCCON);
++
++/**********************************************************************************
++* unsigned IO_RTC_GetTIME(IO_RTC_DATETIME *pTime);
++* Input : pTime = structure for getting RTC Time. (each element has decimal (non-BCD) value.)
++* Return : 0 = OK
++* 1 = Read value has some error, and pTime contains predefined initial values
++* for calling IO_RTC_SetTIME();
++* Description : Get current time of RTC.
++* RTC has no power-on reset feature, it has random value after power-on.
++* It is reported by return value of 1 so user must re-set the current time.
++**********************************************************************************/
++unsigned IO_RTC_GetTIME(IO_RTC_DATETIME *pTime);
++
++/**********************************************************************************
++* unsigned IO_RTC_IsValidTime(void);
++*
++* Input : void
++* Return : 0 = OK
++* 1 = Read value has some error
++* Description :This function is made to check whether current time setteing is correct or not
++* Maybe this function will be called by only the Janus core and will be used for setting
++* current RTC state(SET or UNSET).
++**********************************************************************************/
++unsigned IO_RTC_IsValidTime(void);
++
++/**********************************************************************************
++* unsigned IO_RTC_SetTIME(RTC_APP_DATETIME *pTime);
++*
++* Input : pTime = structure for setting RTC Time (refer to IO_RTC_GetTIME())
++* Return : 0
++* Description :
++**********************************************************************************/
++unsigned IO_RTC_SetTIME(IO_RTC_DATETIME *pTime);
++
++/**********************************************************************************
++* unsigned IO_RTC_SetBCDALARM(IO_RTC_DATETIME *pTime, unsigned uCON);
++*
++* Input : pTime = structure for setting RTC Time. (each element has BCD format)
++* uCON = same as HwRTCALM register map (refer to datasheet)
++* Return : 0
++* Description : Set ALARM time. It is not supported all combination of ALARM time.
++**********************************************************************************/
++unsigned IO_RTC_SetBCDALARM(IO_RTC_DATETIME *pTime, unsigned uCON);
++
++/**********************************************************************************
++* unsigned IO_RTC_GetBCDTIME(RTC_APP_DATETIME *pTime);
++*
++* Input : pTime = structure for getting RTC Time. (BCD format)
++* Return : 0
++* Description : The current time is stored to structure pointed by pTime.
++**********************************************************************************/
++unsigned IO_RTC_GetBCDTIME(IO_RTC_DATETIME *pTime);
++
++/**********************************************************************************
++* unsigned IO_RTC_SetBCDTIME(RTC_APP_DATETIME *pTime);
++*
++* Input : pTime = structure for setting RTC Time. (BCD format)
++* Return : 0
++* Description :
++**********************************************************************************/
++unsigned IO_RTC_SetBCDTIME(IO_RTC_DATETIME *pTime);
++
++/**********************************************************************************
++* unsigned IO_RTC_BCD2DEC( unsigned nBCD );
++*
++* Input : nBCD = BCD format value
++* Return : Equivalent value of hexa-decimal format
++* Description :
++**********************************************************************************/
++unsigned IO_RTC_BCD2DEC( unsigned nBCD );
++
++/**********************************************************************************
++* unsigned IO_RTC_DEC2BCD( unsigned uDEC );
++*
++* Input : nDEC = hexa-decimal format value
++* Return : Equivalent value of BCD format
++* Description :
++**********************************************************************************/
++unsigned IO_RTC_DEC2BCD( unsigned nDEC );
++
++/**********************************************************************************
++* unsigned IO_RTC_SetALARM(IO_RTC_DATETIME *pTime);
++*
++* Input : pTime = structure for setting RTC Time. (Hexa-decimal format)
++* Output :
++* Return : 0 = OK
++* Description :
++**********************************************************************************/
++unsigned IO_RTC_SetALARM(IO_RTC_DATETIME *pTime);
++
++/**********************************************************************************
++* unsigned IO_RTC_GetALARM(IO_RTC_DATETIME *pTime);
++*
++* Input : pTime = structure for setting RTC Time. (Hexa-decimal format)
++* Output :
++* Return : 0 = OK
++* Description :
++**********************************************************************************/
++unsigned IO_RTC_GetALARM(IO_RTC_DATETIME *pTime);
++
++/**********************************************************************************
++* unsigned IO_RTC_WriteREG(volatile unsigned *pReg, unsigned uValue);
++*
++* Input : pReg = Register Address (BCD register address)
++* uValue = Register Value
++* Return : Register Value after writing.
++* Description :
++**********************************************************************************/
++unsigned IO_RTC_WriteREG(volatile unsigned *pReg, unsigned uValue);
++
++/**********************************************************************************
++* unsigned IO_RTC_GetBCDALARM(RTC_APP_DATETIME *pTime);
++*
++* Input : pTime = structure for setting RTC Time. (BCD format)
++* Output :
++* Return : HwRTCALM value
++* Description :
++**********************************************************************************/
++unsigned IO_RTC_GetBCDALARM(IO_RTC_DATETIME *pTime);
++
++/**************************************************************************
++ FUNCTION NAME : IO_RTC_DisableALMINT
++
++ DESCRIPTION : Disable Alarm Interrupt (ALMINT)
++
++ INPUT : void - Parameter
++ OUTPUT : void - Return Type
++ REMARK :
++**************************************************************************/
++void IO_RTC_DisableALMINT(void);
++
++/**********************************************************************************
++* unsigned IO_RTC_SetWKUP(IO_RTC_DATETIME *pTime, unsigned uActiveMode);
++*
++* Input : pTime = structure for setting RTC Time. (Hexa-decimal format)
++* uActiveMode : 1 = PMWKUP is active HIGH, 0 = PMWKUP is active LOW
++* Output :
++* Return : 0 = OK
++* Description : Set Wakeup Time. (System can be powered off & rebooted by wake-up signal)
++**********************************************************************************/
++unsigned IO_RTC_SetWKUP(IO_RTC_DATETIME *pTime, unsigned uActiveMode);
++
++
++
++/************************************************************************
++* Debug Monitor
++************************************************************************/
++// Print Character for time stamp.
++#define ST_ON '1'
++#define ST_OFF '0'
++#ifndef WINVER
++#ifdef USE_IO_DEBUG
++ //----------definition for GLOBAL monitoring ([7:0] are allocated)
++ #define IO_DBG_Init IO_DBG_Init_
++ #define IO_DBG_Printf IO_DBG_Printf_
++ #define IO_DBG_SerialPrintf IO_DBG_SerialPrintf_
++ #define IO_DBG_Putc IO_DBG_Putc_
++ #define IO_DBG_TIME HwTCNT4
++
++ //----------definition for GLOBAL monitoring ([-:0] are allocated)
++ #define DBG_CTRL_USBD Hw0
++ #define DBG_CTRL_NFC Hw1
++ #define DBG_CTRL_DTCM Hw2
++ #define DBG_CTRL_SSFDC Hw3
++ #define DBG_CTRL_SSFDC_DRV Hw4
++ #define DBG_CTRL_FILE Hw5
++ #define DBG_CTRL_FAT Hw6
++ #define DBG_CTRL_MP3DEC Hw7
++ //----------stamp definition ([31:-] are allocated)
++ #define DBG_CTRL_STAMP0 Hw31
++ #define DBG_CTRL_STAMP1 Hw30
++ #define DBG_CTRL_STAMP2 Hw29
++ #define DBG_CTRL_STAMP3 Hw28
++ #define DBG_CTRL_STAMP4 Hw27
++ #define DBG_CTRL_STAMP5 Hw26
++ #define DBG_CTRL_STAMP6 Hw25
++ #define DBG_CTRL_STAMP7 Hw24
++#else
++ // Disable All of monitoring functions
++ #define IO_DBG_Init() {;}
++ #define IO_DBG_Printf(...)
++ #define IO_DBG_SerialPrintf(...)
++ #define IO_DBG_Putc
++ #define IO_DBG_TIME 0
++
++ #define DBG_CTRL_USBD 0
++ #define DBG_CTRL_NFC 0
++ #define DBG_CTRL_DTCM 0
++ #define DBG_CTRL_SSFDC 0
++ #define DBG_CTRL_SSFDC_DRV 0
++ #define DBG_CTRL_FILE 0
++ #define DBG_CTRL_FAT 0
++ #define DBG_CTRL_MP3DEC 0
++ #define DBG_CTRL_STAMP0 0
++ #define DBG_CTRL_STAMP1 0
++ #define DBG_CTRL_STAMP2 0
++ #define DBG_CTRL_STAMP3 0
++ #define DBG_CTRL_STAMP4 0
++ #define DBG_CTRL_STAMP5 0
++ #define DBG_CTRL_STAMP6 0
++ #define DBG_CTRL_STAMP7 0
++#endif
++#endif
++#ifdef CHECK_SPEED
++ // Stamp for
++ #define MakeSTAMP0(X) {if (uDBG_CTRL & DBG_CTRL_STAMP0) IO_DBG_Printf("[%05x]T0(%c)\n", IO_DBG_TIME, X);}
++
++ // Stamp for SSFDC_FS_WriteSector() execution time.
++ #define MakeSTAMP1(X) {if (uDBG_CTRL & DBG_CTRL_STAMP1) IO_DBG_Printf("[%05x]T1(%c)\n", IO_DBG_TIME, X);}
++
++ // Stamp for SSFDC_WriteSector() execution time.
++ #define MakeSTAMP2(X) {if (uDBG_CTRL & DBG_CTRL_STAMP2) IO_DBG_Printf("[%05x]T2(%c)\n", IO_DBG_TIME, X);}
++
++ // Stamp for read_file() or write_file() execution time.
++ #define MakeSTAMP3(X) {if (uDBG_CTRL & DBG_CTRL_STAMP3) IO_DBG_Printf("[%05x]T3(%c)\n", IO_DBG_TIME, X);}
++
++ // Stamp for
++ #define MakeSTAMP4(X) {if (uDBG_CTRL & DBG_CTRL_STAMP4) IO_DBG_Printf("[%05x]T4(%c)\n", IO_DBG_TIME, X);}
++
++ // Stamp for DISK_WriteSector() execution time.
++ #define MakeSTAMP5(X) {if (uDBG_CTRL & DBG_CTRL_STAMP5) IO_DBG_Printf("[%05x]T5(%c)\n", IO_DBG_TIME, X);}
++
++ // Stamp for pure NAND Data transfer execution time.
++ #define MakeSTAMP6(X) {if (uDBG_CTRL & DBG_CTRL_STAMP6) IO_DBG_Printf("[%05x]T6(%c)\n", IO_DBG_TIME, X);}
++
++ // Stamp for SSFDC_IO_R/W() execution time.
++ #define MakeSTAMP7(X) {if (uDBG_CTRL & DBG_CTRL_STAMP7) IO_DBG_Printf("[%05x]T7(%c)\n", IO_DBG_TIME, X);}
++#else
++ #define MakeSTAMP0(X) {;}
++ #define MakeSTAMP1(X) {;}
++ #define MakeSTAMP2(X) {;}
++ #define MakeSTAMP3(X) {;}
++ #define MakeSTAMP4(X) {;}
++ #define MakeSTAMP5(X) {;}
++ #define MakeSTAMP6(X) {;}
++ #define MakeSTAMP7(X) {;}
++#endif
++
++// definition for USB device monitoring
++#define IO_USBD_Printf if (uDBG_CTRL & DBG_CTRL_USBD) IO_DBG_Printf
++#define IO_USBD_Putc(x) if (uDBG_CTRL & DBG_CTRL_USBD) IO_DBG_Putc(x)
++// definition for NFC monitoring
++#define IO_NFC_Printf if (uDBG_CTRL & DBG_CTRL_NFC) IO_DBG_Printf
++#define IO_NFC_Putc(x) if (uDBG_CTRL & DBG_CTRL_NFC) IO_DBG_Putc(x)
++// definition for DTCM monitoring
++#define IO_DTCM_Printf if (uDBG_CTRL & DBG_CTRL_DTCM) IO_DBG_Printf
++#define IO_DTCM_Putc(x) if (uDBG_CTRL & DBG_CTRL_DTCM) IO_DBG_Putc(x)
++// definition for SSFDC monitoring
++#define IO_SSFDC_Printf if (uDBG_CTRL & DBG_CTRL_SSFDC) IO_DBG_Printf
++#define IO_SSFDC_Putc(x) if (uDBG_CTRL & DBG_CTRL_SSFDC) IO_DBG_Putc(x)
++// definition for SSFDC_DRV monitoring
++#define IO_SSFDC_DRV_Printf if (uDBG_CTRL & DBG_CTRL_SSFDC_DRV) IO_DBG_Printf
++#define IO_SSFDC_DRV_Putc(x) if (uDBG_CTRL & DBG_CTRL_SSFDC_DRV) IO_DBG_Putc(x)
++// definition for FILE monitoring
++#define IO_FILE_Printf if (uDBG_CTRL & DBG_CTRL_FILE) IO_DBG_Printf
++#define IO_FILE_Putc(x) if (uDBG_CTRL & DBG_CTRL_FILE) IO_DBG_Putc(x)
++// definition for FAT monitoring
++#define IO_FAT_Printf if (uDBG_CTRL & DBG_CTRL_FAT) IO_DBG_Printf
++#define IO_FAT_Putc(x) if (uDBG_CTRL & DBG_CTRL_FAT) IO_DBG_Putc(x)
++// definition for MP3DEC monitoring
++#define IO_MP3DEC_Printf if (uDBG_CTRL & DBG_CTRL_MP3DEC) IO_DBG_Printf
++#define IO_MP3DEC_Putc(x) if (uDBG_CTRL & DBG_CTRL_MP3DEC) IO_DBG_Putc(x)
++
++void IO_DBG_Printf_(char *format, ...);
++void IO_DBG_SerialPrintf_(char *format, ...);
++void IO_DBG_Sprintf(char *dst, char *format, ...);
++void IO_DBG_Putc_(char c);
++void IO_DBG_Init_(void);
++
++extern const unsigned IO_DBG_CRC_TABLE[256];
++unsigned IO_DBG_CalcCRC32_s(unsigned crc_in, unsigned data, unsigned size);
++
++/**********************************************************************************
++* int stod(char *s);
++*
++* Input : s = string of decimal or hexa-decimal format
++* Return : converted value equivalent with s.
++* Description : if input string starts from "0x", it is regarded as hexa-decimal format,
++* or it is regarded as decimal format.
++**********************************************************************************/
++int stod(char *s);
++
++extern char cDBG_txbuf[]; // all of string that is printed by IO_DBG_Printf() is stored at this buffer.
++ // this is ring type buffer.
++extern char cDBG_rxbuf[];
++extern char *p_prtbuf, cDirectPrint;
++extern unsigned uDBG_CTRL, uDBG_txbuf_length;
++
++
++/************************************************************************
++* UART
++************************************************************************/
++
++#ifdef TCC92XX
++// Should be fixed.
++/*
++ #define IO_UART_CH 0
++
++ #define IO_UART_LSR(X) (((X) == 0) ? HwUART0_UTLSR : ((X) == 1) ? HwUART1_LSR : HwUART2_UTLSR)
++ #define IO_UART_RCVD Hw0
++ #define IO_UART_TF(X) (((X) == 0) ? HwUART0_UTLSR_TF_NOSTR : ((X) == 1) ? HwUART1_LSR_THRE_ON : HwUART2_UTLSR_TF_NOSTR)
++ #define IO_UART_RXD(X) (((X) == 0) ? HwUART0_UTRXD : ((X) == 1) ? HwUART1_RBR : HwUART2_UTRXD)
++ #define IO_UART_TXD(X) (((X) == 0) ? HwUART0_UTTXD : ((X) == 1) ? HwUART1_THR : HwUART2_UTTXD)
++ #define IO_UART_WaitTXRDY(X) \
++ { \
++ if ((X) == 0) \
++ while (ISONE(HwUART0_UTLSR, HwUART0_UTLSR_TF_NOSTR)); \
++ else if ((X) == 1) \
++ while (ISZERO(HwUART1_LSR, HwUART1_LSR_THRE_ON)); \
++ else if ((X) == 2) \
++ while (ISONE(HwUART2_UTLSR, HwUART2_UTLSR_TF_NOSTR)); \
++ }
++ #define IO_UART_WaitRXRDY(X) \
++ { \
++ if ((X) == 0) \
++ while (ISZERO(HwUART0_UTLSR, HwUART0_UTLSR_RA_RECV)); \
++ else if ((X) == 1) \
++ while (ISZERO(HwUART1_LSR, HwUART1_LSR_DR_ON)); \
++ else if ((X) == 2) \
++ while (ISZERO(HwUART2_UTLSR, HwUART2_UTLSR_RA_RECV)); \
++ }
++ #define IO_UART_RXRDY(X) ( ((X) == 0) ? HwUART0_UTLSR & IO_UART_RCVD : \
++ ((X) == 1) ? HwUART1_LSR & IO_UART_RCVD : HwUART2_UTLSR & IO_UART_RCVD )
++ #define IO_UART_LSR_ERR(X) ( ((X) == 0) ? (HwUART0_UTLSR_FE_ERR | HwUART0_UTLSR_PE_ERR) : \
++ ((X) == 1) ? (HwUART1_LSR_FE_ON | HwUART1_LSR_PE_ON) : \
++ (HwUART2_UTLSR_FE_ERR | HwUART2_UTLSR_PE_ERR) )
++ #define IO_UART_ERR_Frame(X) ( ((X) == 0) ? HwUART0_UTLSR_FE_ERR : \
++ ((X) == 1) ? HwUART1_LSR_FE_ON : HwUART2_UTLSR_FE_ERR )
++ #define IO_UART_ERR_Parity(X) ( ((X) == 0) ? HwUART0_UTLSR_PE_ERR : \
++ ((X) == 1) ? HwUART1_LSR_PE_ON : HwUART2_UTLSR_PE_ERR )
++*/
++#endif
++
++void IO_UART_Test(unsigned uCH);
++void IO_UART_Init(unsigned uCH);
++void IO_UART_WriteString(unsigned uCH, const char *ccptrString);
++void IO_UART_WriteByte(unsigned uCH, char cChar);
++int IO_UART_InputByte(unsigned uCH, char *cptrChar);
++void IO_UART_PutExtChar(unsigned uCH, const unsigned char cucChar);
++char IO_UART_GetChar(unsigned uCH);
++char IO_UART_GetCh(unsigned uCH);
++
++/************************************************************************
++* GSIO & SPIS
++************************************************************************/
++
++#define IO_GSIO_HwEN Hw31
++#define IO_GSIO_HwMSB1ST Hw30
++#define IO_GSIO_HwLSB1ST HwZERO
++#define IO_GSIO_HwWSIZE(X) (((X)-1)*Hw26)
++#define IO_GSIO_HwWSDYNAMIC Hw25
++#define IO_GSIO_HwDIV(X) ((X) * Hw18)
++#define IO_GSIO_HwWSFIX HwZERO
++#define IO_GSIO_HwPOSSYNC Hw17
++#define IO_GSIO_HwNEGSYNC HwZERO
++#define IO_GSIO_HwMASKLSCK Hw16
++#define IO_GSIO_HwIEN Hw15
++#define IO_GSIO_HwTXDLY(X) ((X)*Hw13)
++#define IO_GSIO_HwFRMACTHIGH Hw12
++#define IO_GSIO_HwFRMACTLOW HwZERO
++#define IO_GSIO_HwFRMST(X) ((X)*Hw6)
++#define IO_GSIO_HwFRMEND(X) ((X)*Hw0)
++
++typedef volatile struct
++{
++ unsigned DO;
++ unsigned DI;
++ unsigned CTRL;
++ unsigned dummy;
++} sHwGSIO;
++
++#define IO_SPIS_HwTXFIFOCNT(X) (((X)-1)*Hw29)
++#define IO_SPIS_HwRXFIFOCNT(X) (((X)-1)*Hw26)
++#define IO_SPIS_HwISRC_RXCFULL (0*Hw8)
++#define IO_SPIS_HwISRC_RXFEMPTY (1*Hw8)
++#define IO_SPIS_HwISRC_RXFFULL (2*Hw8)
++#define IO_SPIS_HwISRC_TXCFULL (4*Hw8)
++#define IO_SPIS_HwISRC_TXFEMPTY (5*Hw8)
++#define IO_SPIS_HwISRC_TXFFULL (6*Hw8)
++#define IO_SPIS_HwMSB1ST Hw5
++#define IO_SPIS_HwLSB1ST HwZERO
++#define IO_SPIS_HwWSIZE(X) (((X)/8-1)*Hw3)
++#define IO_SPIS_HwPOSSYNC Hw2
++#define IO_SPIS_HwNEGSYNC HwZERO
++#define IO_SPIS_HwIEN Hw1
++#define IO_SPIS_HwEN Hw0
++typedef struct
++{
++ unsigned CTRL;
++ unsigned DO;
++ unsigned DI;
++ unsigned dummy;
++} sHwSPIS;
++
++#define IO_GSIO_WaitBUSY(CH, Tout) { Tout = 300; while (ISONE(HwGSGCR, Hw0 << (CH)) && (Tout --)); }
++#define IO_SPIS_IsRXEMPTY(pSPIS) ISONE((pSPIS)->CTRL, HwSPCTRL_EMP_RX)
++#define IO_SPIS_IsRXFULL(pSPIS) ISONE((pSPIS)->CTRL, HwSPCTRL_FUL_RX)
++#define IO_SPIS_WaitRX(pSPIS, Tout) { Tout = 300; while (IO_SPIS_IsRXEMPTY(pSPIS) && (Tout --)); }
++#define IO_SPIS_IsTXEMPTY(pSPIS) ISONE((pSPIS)->CTRL, HwSPCTRL_EMP_TX)
++#define IO_SPIS_IsTXFULL(pSPIS) ISONE((pSPIS)->CTRL, HwSPCTRL_FUL_TX)
++#define IO_SPIS_WaitTX(pSPIS, Tout) { Tout = 300; while (IO_SPIS_IsTXFULL(pSPIS) && (Tout --)); }
++
++/**********************************************************
++* void IO_GSIO_InitCH(unsigned uCH, unsigned uCONTROL, unsigned uSCKfreq);
++*
++* Input : uCH = Select GSIO Master channel. 0~1 is available.
++* uCONTROL = GSIO control flags
++* [31] = Enable(1)
++* [30] = MSB First (1)
++* [29:26] = Word Size (bit unit)
++* [25] = Word size is dynamically controlled by GSDO register (1)
++* [17] = Data transition occurs at the SCK rising (1)
++* [16] = Mask out the last SCK (1)
++* [15] = Enable Interrupt (1)
++* [14:13] = Transmission starting delay (1~3 is available)
++* [12] = FRM is high active pulse
++* [11:6] = FRM pulse start position
++* [5:0] = FRM pulse end position
++* uSCKfreq = GSIO SCK clock frequency
++* Return :
++* Description : Set GSIO host channel
++**********************************************************/
++void IO_GSIO_InitCH(unsigned uCH, unsigned uCONTROL, unsigned uSCKfreq);
++
++/**********************************************************
++* void IO_SPIS_InitCH(unsigned uCH, unsigned uCONTROL);
++*
++* Input : uCH = Select SPI slave channel. 0 is available.
++* uCONTROL = GSIO control flags
++* [31:29] = TX FIFO count
++* [28:26] = RX FIFO count
++* [10:8] = Interrupt Source Selection
++* 0 : RX FIFO Counter Full
++* 1 : RX FIFO Empty
++* 2 : RX FIFO Full
++* 4 : TX FIFO Counter Full
++* 5 : TX FIFO Empty
++* 6 : TX FIFO Full
++* [5] = MSB First (1)
++* [4:3] = Word Size
++* 0 : 8bit, 1 : 16bit, 2 : 24bit, 3 : 32bit
++* [2] = Data transition occurs at the SCK rising (1)
++* [1] = Enable Interrupt (1)
++* [0] = Enable (1)
++* Return :
++* Description : Set SPI slave channel
++**********************************************************/
++void IO_SPIS_InitCH(unsigned uCH, unsigned uCONTROL);
++
++enum
++{
++ LCD_18BIT_SET,
++ LCD_16BIT_SET,
++ LCD_8BIT_SET
++};
++
++
++/************************************************************************
++* Mail Box
++************************************************************************/
++typedef volatile struct {
++ unsigned TXD;
++ unsigned uRsv1[7];
++ unsigned RXD;
++ unsigned uRsv2[7];
++ unsigned CTR;
++ unsigned STR;
++} sMBOX;
++
++enum {
++ MBOX_MAIN,
++ MBOX_SUB
++};
++
++
++/////////////////////////////////////////////
++
++#if !defined(_LINUX_)
++typedef int (*ICallBack)(int num);
++#endif
++
++#define ALIGN_UP(X, Y) (((unsigned int)(X)+(unsigned int)(Y)-1) & ~((unsigned int)(Y)-1))
++
++
++/************************************************************************
++* GPSB
++************************************************************************/
++typedef struct
++{
++ volatile unsigned long *BASE;
++ unsigned uFRM, uSCK, uSDI, uSDO;
++ unsigned uMODE;
++} sGPSBPORT;
++
++typedef struct tag_sGPSBPacket
++{
++ char TxStatus; // 0=Empty, 1=Valid, 2=Sent
++ char RxStatus; // 0=Empty, 1=Wait, 2=Received
++ char dummy[2];
++ unsigned CurSize;
++ unsigned *TxBufBASE;
++ unsigned *RxBufBASE;
++} sGPSBPacket;
++
++typedef struct
++{
++ unsigned short Num; // total number of packet buffer.
++ unsigned short CurNum; // current number of packet buffer.
++ unsigned short Head; // Head
++ unsigned short Tail; // Tail
++ unsigned MaxSize; // Buffer Max size
++ sGPSBPacket *Pkt; // Packet Array
++} sGPSBPKTManager;
++
++typedef struct
++{
++ unsigned char *pBuffer;
++ unsigned short uPktSize;
++ unsigned short uIncSize;
++ int iRemainLength;
++} sGPSBTXManager;
++
++extern sGPSBPKTManager gGPSBPKTManager[2];
++extern sGPSBTXManager gGPSBTXManager[2];
++
++void IO_GPSB_WaitDONE(sGPSBPORT *pPORT);
++void IO_GPSBSW_DelayLOOP(unsigned uDelay);
++void IO_GPSBSW_SetFRM(sGPSBPORT *pPORT, unsigned uValue);
++void IO_GPSBSW_InvFRM(sGPSBPORT *pPORT);
++void IO_GPSBSW_SetSCK(sGPSBPORT *pPORT, unsigned uValue);
++void IO_GPSBSW_InvSCK(sGPSBPORT *pPORT);
++void IO_GPSBSW_SetSDO(sGPSBPORT *pPORT, unsigned uValue);
++unsigned IO_GPSBSW_GetSDI(sGPSBPORT *pPORT);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* IO_GPSB_ConfigPORT(unsigned uCHPort, unsigned uSDO, unsigned uMode);
++*
++* DESCRIPTION : Configure GPSB Channel and its PORT.
++*
++* INPUT:
++* uCHPort = GPSB Channel & I/O Port number
++* [7:0] = channel number (0 or 1)
++* [8] = I/O PORT number for GPSB Channel
++* GPSB channel 0 can use 3 ports. (port number 0 ~ 2 are used)
++* Port 0 : GPIO_E[19:16]
++* Port 1 : GPIO_A[27:24]
++* Port 2 : GPIO_C[15:12]
++* GPSB channel 1 can only use 1 port. (port number 0 is used)
++* Port 0 : GPIO_E[23:20]
++*
++* uSDOSDI = flag for using SDO or SDI pin
++* [1] = 0 : don't use SDO, 1 : use SDO
++* [0] = 0 : don't use SDI, 1 : use SDI
++*
++* uMode = 0 : for setting PORT as H/W, 1 : for setting PORT as GPIO
++*
++* OUTPUT:
++* 0 = Successful
++* -1 = Illegal configuration.
++*
++* REMARK: created on 2006³â 11¿ù 15ÀÏ ¼ö¿äÀÏ ¿ÀÈÄ 9:02:58 by vizirdo
++**************************************************************************/
++int IO_GPSB_ConfigPORT(unsigned uCHPort, unsigned uSDO, unsigned uMode);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void IO_GPSB_InitCH(int iCH, unsigned uMode, unsigned uSCKfreq);
++*
++* DESCRIPTION : Initialize GPSB channel for Master mode only.
++*
++* INPUT:
++* iCH = GPSB Channel & I/O Port number
++* [7:0] = channel number (0 or 1)
++* [8] = I/O PORT number for GPSB Channel
++* GPSB channel 0 can use 3 ports. (port number 0 ~ 2 are used)
++* Port 0 : GPIO_E[19:16]
++* Port 1 : GPIO_A[27:24]
++* Port 2 : GPIO_C[15:12]
++* GPSB channel 1 can only use 1 port. (port number 0 is used)
++* Port 0 : GPIO_E[23:20]
++*
++* uMode = Mode control
++* [20] : PCS (0 = CS active low, 1 = CS active high)
++* [17] : PD (0 = RX data on rising edge SCK & TX data on falling edge SCK)
++* (1 = RX data on falling edge SCK & TX data on rising edge SCK)
++* [16] : PCK (0 = SCK starts from 0, 1 = SCK starts from 1)
++* [7] : Data shifting direction control. (0 = MSB first, 1 = LSB first)
++*
++* uSCKfreq = SCK frequency (with 100 Hz unit)
++* uSW = 0 for H/W mode, 1 for S/W mode.
++*
++* OUTPUT: void - Return Type
++*
++* REMARK: created on 2006³â 8¿ù 7ÀÏ ¿ù¿äÀÏ ¿ÀÀü 11:35:56 by vizirdo
++**************************************************************************/
++void IO_GPSB_InitCH(int iCH, unsigned uMode, unsigned uSCKfreq, unsigned uSW);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* unsigned IO_GPSB_SendCMD(int iCH, unsigned uCmd, unsigned uCmdBitSize, unsigned uContinuous);
++*
++* DESCRIPTION : Send Command through GPSB port.
++*
++* INPUT:
++* iCH = channel number. (negative for using S/W SPI routine)
++* uCmd = command value
++* uCmdBitSize = bit size of command value.
++* uContinuous = flag for controlling nCS line.
++* if zero, nCS line goes to inactive state after the command value is sent.
++* if non-zero, nCS line remains in active state so additional process for the command can follow.
++*
++* OUTPUT: unsigned - Return Type
++* = response of command
++*
++* REMARK: created on 2006³â 8¿ù 7ÀÏ ¿ù¿äÀÏ ¿ÀÀü 11:36:57 by vizirdo
++**************************************************************************/
++unsigned IO_GPSB_SendCMD(int iCH, unsigned uCmd, unsigned uCmdBitSize, unsigned uContinuous);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* unsigned IO_GPSB_TRxPKT(int iCH, void *pTxBuf, void *pRxBuf, unsigned uLength);
++*
++* DESCRIPTION : Transmit & Receive a packet data.
++*
++* INPUT:
++* iCH = GPSB Channel & I/O Port number (same as IO_GPSB_InitCH)
++* pRxBuf = base address of received data.
++* pTxBuf = base address of transmitting data.
++* uLength = data size (byte unit)
++*
++* OUTPUT: unsigned - Return Type
++* = 0
++*
++* REMARK: created on 2006³â 12¿ù 21ÀÏ ¸ñ¿äÀÏ ¿ÀÈÄ 11:04:33 by vizirdo
++**************************************************************************/
++unsigned IO_GPSB_TRxPKT(int iCH, void *pTxBuf, void *pRxBuf, unsigned uLength);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* unsigned IO_GPSB_SendDATA(int iCH, unsigned char *pData, unsigned uLength, unsigned uBitConfig);
++*
++* DESCRIPTION : Send data through GPSB port
++*
++* INPUT:
++* iCH = channel number. (negative for using S/W SPI routine)
++* pData = pointer of data to send.
++* uLength = length of data to send.
++* uBitConfig = bit size of GPSB port.
++*
++* OUTPUT: unsigned - Return Type
++* =
++*
++* REMARK: created on 2006³â 8¿ù 7ÀÏ ¿ù¿äÀÏ ¿ÀÀü 11:42:47 by vizirdo
++**************************************************************************/
++unsigned IO_GPSB_SendDATA(int iCH, unsigned char *pData, unsigned uLength, unsigned uBitConfig);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* unsigned IO_GPSB_RecvDATA(int iCH, unsigned char *pData, unsigned uLength, unsigned uBitConfig);
++*
++* DESCRIPTION : Receive data through GPSB port
++*
++* INPUT:
++* iCH = channel number. (negative for using S/W SPI routine)
++* pData = pointer of data to receive.
++* uLength = length of data to receive.
++* uBitConfig =
++*
++* OUTPUT: unsigned - Return Type
++* =
++*
++* REMARK: created on 2006³â 8¿ù 7ÀÏ ¿ù¿äÀÏ ¿ÀÀü 11:44:32 by vizirdo
++**************************************************************************/
++unsigned IO_GPSB_RecvDATA(int iCH, unsigned char *pData, unsigned uLength, unsigned uBitConfig);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void IO_GPSBS_InitCH(int iCH, unsigned uSDO, unsigned uMode);
++*
++* DESCRIPTION : Initialize GPSB channel for slave mode.
++*
++* INPUT:
++* iCH = GPSB Channel & I/O Port number
++* [7:0] = channel number (0 or 1)
++* [8] = I/O PORT number for GPSB Channel
++* GPSB channel 0 can use 3 ports. (port number 0 ~ 2 are used)
++* Port 0 : GPIO_E[19:16]
++* Port 1 : GPIO_A[27:24]
++* Port 2 : GPIO_C[15:12]
++* GPSB channel 1 can only use 1 port. (port number 0 is used)
++* Port 0 : GPIO_E[23:20]
++*
++* uSDOSDI = flag for using SDO or SDI pin
++* [1] = 0 : don't use SDO, 1 : use SDO
++* [0] = 0 : don't use SDI, 1 : use SDI
++*
++* uMode = GPSB Mode Selection
++* [17] = SDI capture control
++* 0 : SDI captured at rising edge SCK
++* 1 : SDI captured at falling edge SCK
++* [16] = SCK polarity control
++* 0 : SCKI is not inverted
++* 1 : SCKI is inverted
++* [15:14] = should be 3
++* [12:8] = Bit width - 1
++* [7] = 0 : MSB first, 1 : LSB first
++* [4] = 1 : continuous transfer mode
++* [2] = should be 1
++* [0] = 0 : SPI, 1 : SSP
++*
++* OUTPUT: void - Return Type
++*
++* REMARK: created on 2006³â 11¿ù 16ÀÏ ¸ñ¿äÀÏ ¿ÀÈÄ 6:27:55 by vizirdo
++**************************************************************************/
++void IO_GPSBS_InitCH(int iCH, unsigned uSDO, unsigned uMode);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int IO_GPSBS_ConfigDMA(unsigned uCH, unsigned uINTEN, unsigned uDMACTR,
++* unsigned uPacketSize, unsigned uPacketNum);
++*
++* DESCRIPTION : Configurate a GPSB DMA setting for Transmit/Receive data.
++* GPSB & DMA operation is not yet enabled.
++*
++* INPUT:
++* uCH = channel number (0 or 1)
++* uDMACTR = DMACTR register value
++* uINTEN = INTEN register value
++* uPacketNum = number of packets
++* uPacketSize = packet size (byte unit)
++*
++* OUTPUT: int - Return Type
++* = 0 : successful
++* = negative : failure
++*
++* REMARK: created on 2006³â 12¿ù 21ÀÏ ¸ñ¿äÀÏ ¿ÀÈÄ 11:08:46 by vizirdo
++**************************************************************************/
++int IO_GPSBS_ConfigDMA(unsigned uCH, unsigned uINTEN, unsigned uDMACTR,
++ unsigned uPacketSize, unsigned uPacketNum);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int IO_GPSBS_StartRXDMA(unsigned uCH, unsigned uINTMode, unsigned uINTEN, unsigned uDMACTR,
++* unsigned uPacketSize, unsigned uPacketNum, unsigned *pBuffer);
++*
++* DESCRIPTION : Start GPSB RX DMA at slave mode.
++*
++* INPUT:
++* uCH = GPSB channel number (0 or 1)
++* uINTMode = 0 : use edge triggered interrupt, 1 : use level triggered interrupt
++* uINTEN = GPSB.INTEN register value
++* uDMACTR = GPSB.DMACTR register value
++* uPacketSize = 1 packet size in bytes
++* uPacketNum = number of packets which RX DMA manipulate.
++* pBuffer = base of buffer to store RX data
++*
++* OUTPUT: int - Return Type
++* = 0 : setup is successful.
++* = -1 : illegal parameter
++*
++* REMARK: created on 2006³â 11¿ù 16ÀÏ ¸ñ¿äÀÏ ¿ÀÈÄ 9:29:16 by vizirdo
++**************************************************************************/
++int IO_GPSBS_StartRXDMA(unsigned uCH, unsigned uINTMode, unsigned uINTEN, unsigned uDMACTR,
++ unsigned uPacketSize, unsigned uPacketNum, unsigned *pBuffer);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void IO_GPSBS_EnablePKTDMA(unsigned uCH, unsigned uPktSize, unsigned *pTxBase, unsigned *pRxBase);
++*
++* DESCRIPTION : Enable GPSB & DMA Operation for packet data transfer.
++*
++* INPUT:
++* uCH = GPSB channel number (0 or 1)
++* uPktSize = packet size (in bytes)
++* pTxBase = base address of transmitting data buffer
++* pRxBase = base address of receiving data buffer
++*
++* OUTPUT: void - Return Type
++*
++* REMARK: created on 2006³â 12¿ù 21ÀÏ ¸ñ¿äÀÏ ¿ÀÈÄ 11:11:50 by vizirdo
++**************************************************************************/
++void IO_GPSBS_EnablePKTDMA(unsigned uCH, unsigned uPktSize, unsigned *pTxBase, unsigned *pRxBase);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void IO_GPSBS_EnableDMA(unsigned uCH, unsigned *pTxBase, unsigned *pRxBase);
++*
++* DESCRIPTION : Enable GPSB & DMA Operation for data transfer.
++*
++* INPUT:
++* uCH = GPSB channel number (0 or 1)
++* pTxBase = base address of transmitting data buffer
++* pRxBase = base address of receiving data buffer
++*
++* OUTPUT: void - Return Type
++*
++* REMARK: created on 2006³â 12¿ù 21ÀÏ ¸ñ¿äÀÏ ¿ÀÈÄ 11:11:50 by vizirdo
++**************************************************************************/
++void IO_GPSBS_EnableDMA(unsigned uCH, unsigned *pTxBase, unsigned *pRxBase);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void IO_GPSBS_DisableDMA(unsigned uCH);
++*
++* DESCRIPTION : Disable DMA Operation
++*
++* INPUT:
++* uCH = GPSB channel number (0 or 1)
++*
++* OUTPUT: void - Return Type
++*
++* REMARK: created on 2007/1/25 11:24:46 by vizirdo
++**************************************************************************/
++void IO_GPSBS_DisableDMA(unsigned uCH);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void IO_GPSBS_PauseCH(int iCH);
++*
++* DESCRIPTION : Disable H/W Channel.
++*
++* INPUT:
++* iCH = channel number (0 or 1)
++*
++* OUTPUT: void - Return Type
++*
++* REMARK: created on 2006³â 11¿ù 17ÀÏ ±Ý¿äÀÏ ¿ÀÀü 12:25:30 by vizirdo
++**************************************************************************/
++void IO_GPSBS_PauseCH(int iCH);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* unsigned IO_GPSBS_CheckDATA(int iCH);
++*
++* DESCRIPTION : Check whether RX FIFO is empty or not.
++*
++* INPUT:
++* iCH = channel number (0 or 1)
++*
++* OUTPUT: unsigned - Return Type
++* = 0 : RX FIFO is empty
++* = 1 : RX FIFO is not empty
++*
++* REMARK: created on 2006³â 11¿ù 18ÀÏ Åä¿äÀÏ ¿ÀÈÄ 6:40:50 by vizirdo
++**************************************************************************/
++unsigned IO_GPSBS_CheckDATA(int iCH);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* unsigned IO_GPSBS_GetDATA(int iCH);
++*
++* DESCRIPTION : Read RX FIFO
++*
++* INPUT:
++* iCH = channel number (0 or 1)
++*
++* OUTPUT: unsigned - Return Type
++* = RX FIFO data.
++*
++* REMARK: created on 2006³â 11¿ù 18ÀÏ Åä¿äÀÏ ¿ÀÈÄ 6:41:38 by vizirdo
++**************************************************************************/
++unsigned IO_GPSBS_GetDATA(int iCH);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* unsigned IO_GPSBS_SetDATA(int iCH, unsigned uData);
++*
++* DESCRIPTION : Send 1 word to master
++*
++* INPUT:
++* iCH = GPSB Channel number (0 or 1)
++* uData = Word value
++*
++* OUTPUT: unsigned - Return Type
++* = FIFO valid count
++*
++* REMARK: created on 2007/1/25 11:25:53 by vizirdo
++**************************************************************************/
++unsigned IO_GPSBS_SetDATA(int iCH, unsigned uData);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* unsigned IO_GPSBS_IsValidPKT(unsigned uCH);
++*
++* DESCRIPTION : Check Packet Buffer is empty or not.
++*
++* INPUT:
++* uCH = channel number (0 or 1)
++*
++* OUTPUT: unsigned - Return Type
++* = 0 : Empty, 1 : Not empty
++*
++* REMARK: created on 2006³â 12¿ù 14ÀÏ ¸ñ¿äÀÏ ¿ÀÈÄ 9:37:16 by vizirdo
++**************************************************************************/
++unsigned IO_GPSBS_IsValidPKT(unsigned uCH);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* unsigned IO_GPSBS_IsFullPKT(unsigned uCH);
++*
++* DESCRIPTION : Check Packet Buffer is full or not.
++*
++* INPUT:
++* uCH = channel number (0 or 1)
++*
++* OUTPUT: unsigned - Return Type
++* = 0 : Not full, 1 : Full
++*
++* REMARK: created on 2006³â 12¿ù 14ÀÏ ¸ñ¿äÀÏ ¿ÀÈÄ 9:45:53 by vizirdo
++**************************************************************************/
++unsigned IO_GPSBS_IsFullPKT(unsigned uCH);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int IO_GPSBS_CheckEmptyPKT(unsigned uCH, char **ppRxBuf, char **ppTxBuf);
++*
++* DESCRIPTION : Check if there exist an empty packet buffer.
++*
++* INPUT:
++* uCH = channel number (0 or 1)
++* ppRxBuf = pointer to store base address of receiving data (NULL if not needed)
++* ppTxBuf = pointer to store base address of transmitting data (NULL if not needed)
++*
++* OUTPUT: int - Return Type
++* = 1 : there exist an empty packet buffer, and its address is stored to ppRxBuf, ppTxBuf
++*
++* REMARK: created on 2006³â 12¿ù 21ÀÏ ¸ñ¿äÀÏ ¿ÀÈÄ 11:17:36 by vizirdo
++**************************************************************************/
++int IO_GPSBS_CheckEmptyPKT(unsigned uCH, char **ppRxBuf, char **ppTxBuf);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int IO_GPSBS_PushPKT(unsigned uCH, unsigned char *pTxPKT, unsigned uSize);
++*
++* DESCRIPTION : Push a packet into packet buffer.
++* If pTxPkt == NULL, this packet only receives RX data.
++*
++* INPUT:
++* uCH = channel number (0 or 1)
++* pTxPKT = base address of transmitting data (NULL if not needed
++* uSize = size of data (in bytes)
++*
++* OUTPUT: int - Return Type
++* = 0 : successful
++* = negative : push failed
++*
++* REMARK: created on 2006³â 12¿ù 21ÀÏ ¸ñ¿äÀÏ ¿ÀÈÄ 11:20:32 by vizirdo
++**************************************************************************/
++int IO_GPSBS_PushPKT(unsigned uCH, unsigned char *pTxPKT, unsigned uSize);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int IO_GPSBS_CheckValidPKT(unsigned uCH, char **ppRxBuf, char **ppTxBuf);
++*
++* DESCRIPTION : Check if there exist a valid packet buffer
++*
++* INPUT:
++* uCH = channel number (0 or 1)
++* ppRxBuf = pointer to store base address of receiving data (NULL if not needed)
++* ppTxBuf = pointer to store base address of transmitting data (NULL if not needed)
++*
++* OUTPUT: int - Return Type
++* = 1 : there exist an valid packet buffer, and its address is stored to ppRxBuf, ppTxBuf
++* = 0 : there is no valid packet. (packet is empty)
++*
++* REMARK: created on 2006³â 12¿ù 21ÀÏ ¸ñ¿äÀÏ ¿ÀÈÄ 11:24:29 by vizirdo
++**************************************************************************/
++int IO_GPSBS_CheckValidPKT(unsigned uCH, char **ppRxBuf, char **ppTxBuf);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int IO_GPSBS_PopPKT(unsigned uCH, sHwGPSB *pHwGPSB, char *pRxBuf);
++*
++* DESCRIPTION : Pop a packet data and process next packet buffer. if packet buffer is empty,
++* GPSB & DMA operation is disabled.
++*
++* INPUT:
++* uCH = channel number (0 or 1)
++* pHwGPSB = register base address for channel 0 or 1
++* pRxBuf = base address to store just received packet data.
++*
++* OUTPUT: unsigned - Return Type
++* = 0 : there is no data.
++* = 1 : last packet is just processed. GPSB & DMA operation is disabled
++* = 2 : next packet operation starts.
++*
++* REMARK: created on 2006³â 12¿ù 21ÀÏ ¸ñ¿äÀÏ ¿ÀÈÄ 11:42:25 by vizirdo
++**************************************************************************/
++int IO_GPSBS_PopPKT(unsigned uCH, PGPSB pHwGPSB, char *pRxBuf);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int IO_GPSBS_FlushPKT(unsigned uCH);
++*
++* DESCRIPTION : Remove existing all valid packet data
++*
++* INPUT:
++* uCH = channel number (0 or 1)
++*
++* OUTPUT: int - Return Type
++* = 0 : successful
++*
++* REMARK: created on 2006³â 12¿ù 22ÀÏ ±Ý¿äÀÏ ¿ÀÈÄ 2:24:50 by vizirdo
++**************************************************************************/
++int IO_GPSBS_FlushPKT(unsigned uCH);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int IO_GPSBS_InsertPIDEntry(unsigned *pPIDTable, unsigned uPIDLength, int iIndex, unsigned uPIDValue, unsigned uPIDMask);
++*
++* DESCRIPTION : Insert PID entry at PID table
++*
++* INPUT:
++* pPIDTable = base address of PID table
++* uPIDLength = PID table length (0 ~ 63 is valid)
++* iIndex = index of PID table to insert. (if invalid index is used, search empty entry and insert at that index)
++* uPIDValue = PID bit field value
++* uPIDMask = PID Mask bit field value (1 = Masking Enabled, 0 = Masking Disabled)
++*
++* uPIDMask & uPIDValue Format
++* [14] = PayLoad Start bit
++* [13] = Error Flag bit
++* [12:0] = PID value
++*
++* OUTPUT: int - Return Type
++* = 0 ~ (uPIDLength-1) : index value which is selected to insert.
++* = -1 : there is no empty entry
++**************************************************************************/
++int IO_GPSBS_InsertPIDEntry(unsigned *pPIDTable, unsigned uPIDLength, int iIndex, unsigned uPIDValue, unsigned uPIDMask);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int IO_GPSBS_RemovePIDEntry(unsigned *pPIDTable, unsigned uPIDLength, int iIndex, unsigned uPIDValue, unsigned uPIDMask);
++*
++* DESCRIPTION : Remove PID entry at PID Table
++*
++* INPUT:
++* pPIDTable = base address of PID table
++* uPIDLength = PID table length (0 ~ 63 is valid)
++* iIndex = index of PID table to remove.
++* (if invalid index is used, search matched entry with uPIDValue, uPIDMask and remove that entry)
++* uPIDValue = PID bit field value
++* uPIDMask = PID Mask bit field value (1 = Masking Enabled, 0 = Masking Disabled)
++*
++* uPIDMask & uPIDValue Format
++* [14] = PayLoad Start bit
++* [13] = Error Flag bit
++* [12:0] = PID value
++*
++* OUTPUT: int - Return Type
++* = 0 ~ (uPIDLength-1) : index value which is removed.
++* = -1 : there is no matched entry
++**************************************************************************/
++int IO_GPSBS_RemovePIDEntry(unsigned *pPIDTable, unsigned uPIDLength, int iIndex, unsigned uPIDValue, unsigned uPIDMask);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void IO_GPSBS_StartTSIF(unsigned uCH, unsigned *pPIDTable, unsigned uPIDLength, unsigned uMatchPID, unsigned uMatchSync,
++* unsigned *pBuffer, unsigned uPacketSize, unsigned uPacketNum);
++*
++* DESCRIPTION : Start TS I/F DMA mode
++*
++* INPUT:
++* uCH = GPSB Channel Number (0 or 1)
++* pPIDTable = base address of PID table
++* uPIDLength = entry size of PID table (1 ~ 64)
++* uMatchPID = 1 : PID filtering is enabled
++* uMatchSync = 1 : Sync byte matching is enabled
++* pBuffer = base address of RX DMA buffer (= uPacketSize * uPacketNum)
++* uPacketSize = packet size of RX DMA buffer
++* uPacketNum = packet number of RX DMA buffer
++*
++* OUTPUT: void - Return Type
++**************************************************************************/
++void IO_GPSBS_StartTSIF(unsigned uCH, unsigned *pPIDTable, unsigned uPIDLength, unsigned uMatchPID, unsigned uMatchSync,
++ unsigned *pBuffer, unsigned uPacketSize, unsigned uPacketNum);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int IO_GPSBS_CalcPKTConfig(unsigned uSize, unsigned uPktSize, unsigned *pPktNum);
++*
++* DESCRIPTION : Calculate packet number for uSize & uPktSize.
++*
++* INPUT:
++* uSize = Entire data size
++* uPktSize = 1 packet size
++* pPktNum = pointer to store calculated packet number.
++*
++* OUTPUT: int - Return Type
++* = 1 : uSize is larger than maximum transfer size.
++* = 0 : uSize is less or equal than maximum transfer size.
++*
++* REMARK: created on 2007/1/25 12:7:0 by vizirdo
++**************************************************************************/
++int IO_GPSBS_CalcPKTConfig(unsigned uSize, unsigned uPktSize, unsigned *pPktNum);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int IO_GPSBS_SendDATA(unsigned uCH, unsigned char *pBuffer, unsigned uSize, unsigned uPktSize);
++*
++* DESCRIPTION : Transmit bulk of data in slave mode.
++*
++* INPUT:
++* uCH = GPSB channel (0 or 1)
++* pBuffer = base address of bulk data.
++* uSize = size of bulk data.
++* uPktSize = 1 packet size for transmitting bulk of data.
++* The Host should have idle time (~= 5ms) at every maximum transfer unit (= uPktSize * 32)
++* and must read uPktSize unit.
++*
++* OUTPUT: int - Return Type
++* = 0 : Transfer begins
++* = negative : invalid parameter
++*
++* REMARK: created on 2007/1/25 12:51:55 by vizirdo
++**************************************************************************/
++int IO_GPSBS_SendDATA(unsigned uCH, unsigned char *pBuffer, unsigned uSize, unsigned uPktSize);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int IO_GPSBS_GetRemainLength(unsigned uCH);
++*
++* DESCRIPTION : Get the size of data remains.
++*
++* INPUT:
++* uCH = GPSB Channel (0 or 1)
++*
++* OUTPUT: int - Return Type
++* = Size of Data remains.
++*
++* REMARK: created on 2007/1/25 12:56:38 by vizirdo
++**************************************************************************/
++int IO_GPSBS_GetRemainLength(unsigned uCH);
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int IO_GPSBS_SendNextDATA(unsigned uCH);
++*
++* DESCRIPTION : Process next transfer for sending bulk of data.
++*
++* INPUT:
++* uCH = GPSB Channel (0 or 1)
++*
++* OUTPUT: int - Return Type
++* = 0 : Transfer finished
++* = 1 : Next packet is ready to be transferred
++*
++* REMARK: created on 2007/1/25 12:58:4 by vizirdo
++**************************************************************************/
++int IO_GPSBS_SendNextDATA(unsigned uCH);
++
++
++#endif /* __IO_TCCXXX_H */
+diff --git a/drivers/block/tcc/inc/tnftl/TC_DRV.h b/drivers/block/tcc/inc/tnftl/TC_DRV.h
+new file mode 100644
+index 0000000..dc516a8
+--- /dev/null
++++ b/drivers/block/tcc/inc/tnftl/TC_DRV.h
+@@ -0,0 +1,1700 @@
++/****************************************************************************
++ * FileName : TC_DRV.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++#ifndef __TC_DRV_H__
++#define __TC_DRV_H__
++
++#ifndef __IO_TCCXXX_H
++#if defined(_LINUX_)
++#include <tnftl/IO_TCCXXX.h>
++#elif defined(_WINCE_)
++#include "IO_TCCXXX.h"
++#endif
++#endif
++
++//#include "TCCresource.h"
++
++/*==============================================================================
++ General DMA
++ ==============================================================================*/
++
++#define DRV_GDMA_MAX_HANDLE 27
++
++// GDMA Driver Function Definition
++enum
++{
++ DRV_GDMA_FUNC_INIT, // Driver Initialization : Argument = None
++ DRV_GDMA_FUNC_PROCESS_INTERRUPT, // Process DMA Interrupt : Argument = None
++
++ DRV_GDMA_FUNC_OPEN, // Open Handle : Argument = (Channel Number, *sDRV_GDMA)
++ DRV_GDMA_FUNC_INSTALL_HANDLER, // Install DMA Interrupt Handler : Argument = (Channel, NewHandler, [* OldHandler])
++ DRV_GDMA_FUNC_UNINSTALL_HANDLER, // UnInstall DMA Interrupt Handler : Argument = (Channel)
++
++ DRV_GDMA_FUNC_SETCFG, // Configuration for DMA : Argument = (Handle, ConfigValue, ReqSel)
++ DRV_GDMA_FUNC_PARSECFG, // Parse for DMA Configuration : parameter should be set ahead in structure : Argument = (Handle)
++ DRV_GDMA_FUNC_GETHwDMA, // Get HwDMA Base Address : Argument = (Handle, *sHwDMA)
++ DRV_GDMA_FUNC_ISACTIVE, // Check Activated State : Argument = (Handle)
++ DRV_GDMA_FUNC_SETREG, // Setup DMA Register : Argument = (Handle, SrcBase, SrcInc, SrcMask, DstBase, DstInc, DstMask, DataSize)
++ DRV_GDMA_FUNC_START, // Start DMA Transfer : Argument = (Handle, SrcBase, SrcInc, SrcMask, DstBase, DstInc, DstMask, DataSize)
++ DRV_GDMA_FUNC_WAITDONE, // Wait DMA Transfer Done : Argument = (Handle, [TimeOut Value], [TimeDelay(), TimeDelayFactor])
++ DRV_GDMA_FUNC_WAITDONE_STOP, // Wait DMA Transfer Done & Stop DMA : Argument = (Handle, [TimeOut Value], [TimeDelay(), TimeDelayFactor])
++ DRV_GDMA_FUNC_PAUSE, // Pause DMA Operation : Argument = (Handle)
++ DRV_GDMA_FUNC_CONTINUE, // Continue DMA Operation : Argument = (Handle)
++ DRV_GDMA_FUNC_STOP, // Stop DMA Operation -> This channel goes to IDLE state : Argument = (Handle)
++ DRV_GDMA_FUNC_CLOSE, // Close DMA Channel from User : Argument = (Handle)
++ DRV_GDMA_FUNC_MAX
++};
++
++// GDMA Driver Status Definition
++enum
++{
++ DRV_GDMA_STATUS_INVALID, // Not Opened
++ DRV_GDMA_STATUS_IDLE, // Openad but Not Activated
++ DRV_GDMA_STATUS_PAUSE, // Opened & Activated & Pause
++ DRV_GDMA_STATUS_ACTIVE, // Opened & Activated
++ DRV_GDMA_STATUS_MAX
++};
++
++// GDMA Driver Data Structure
++typedef struct
++{
++ U32 CHCFG;
++ U32 REQSEL;
++
++ U8 CHSTS;
++ U8 BufShiftFactor;
++ U32 HwCHCTRL;
++ U32 HwREQSEL;
++#ifdef TCC89XX
++ PGDMACTRL pHwDMA;
++#else
++ sHwDMA *pHwDMA;
++#endif
++} sDRV_GDMA;
++
++// GDMA Driver Return Value Definition
++#define DRV_GDMA_ERROR_YES 1
++#define DRV_GDMA_ERROR_NO 0
++#define DRV_GDMA_ERROR_OK 0
++enum
++{
++ // Error for Driver State
++ DRV_GDMA_ERROR_NOTINIT = (int)0xF0040000, // Non-init Function come before init function
++ DRV_GDMA_ERROR_DUPINIT, // Init function called more than twice
++
++ // Error for Input Parameter
++ DRV_GDMA_ERROR_INVALID_FUNC, // Function Code is out of range
++ DRV_GDMA_ERROR_INVALID_ARGUMENT, // Number of Argument is out of range
++ DRV_GDMA_ERROR_INVALID_HANDLE, // Handle value is out of range
++ DRV_GDMA_ERROR_INVALID_CH, // Channel value is out of range
++
++ // Error for Resource Availability
++ DRV_GDMA_ERROR_NOTAVAILABLE_HANDLE, // No available handle
++ DRV_GDMA_ERROR_NOTAVAILABLE_CH, // No available channel
++
++ // Error for Operating
++ DRV_GDMA_ERROR_TIMEOUT, // Time Out
++ DRV_GDMA_ERROR_NOT_READY,
++ DRV_GDMA_ERROR_NOT_ACTIVE,
++ DRV_GDMA_ERROR_NOT_PAUSE,
++
++ // Error for Illegal State
++ DRV_GDMA_ERROR_INTERNAL, // Internal Bug
++
++ DRV_GDMA_ERROR_MAX
++};
++
++// GDMA Driver Channel Configuration Definition
++#define DRV_GDMA_CFG_SyncHwReq Hw13
++#define DRV_GDMA_CFG_ASyncHwReq 0
++#define DRV_GDMA_CFG_AckAtWrite Hw12 // HwCHCTRL_HRD
++#define DRV_GDMA_CFG_AckAtRead 0
++#define DRV_GDMA_CFG_LockTransfer Hw11 // HwCHCTRL_LOCK
++#define DRV_GDMA_CFG_NoArbitration Hw10 // HwCHCTRL_BST
++#define DRV_GDMA_CFG_Arbitration 0
++#define DRV_GDMA_CFG_StartBy_SHIFT 8
++#define DRV_GDMA_CFG_StartBy(X) ((X)<<DRV_GDMA_CFG_StartBy_SHIFT)
++#define DRV_GDMA_CFG_StartByHwReqEdge DRV_GDMA_CFG_StartBy(0)
++#define DRV_GDMA_CFG_StartByHwReqLevel DRV_GDMA_CFG_StartBy(3)
++#define DRV_GDMA_CFG_StartBySwReq DRV_GDMA_CFG_StartBy(2)
++#define DRV_GDMA_CFG_StartBy_MASK DRV_GDMA_CFG_StartBy(3)
++#define DRV_GDMA_CFG_ReadBW_8Bit (0*Hw6)
++#define DRV_GDMA_CFG_ReadBW_16Bit (1*Hw6)
++#define DRV_GDMA_CFG_ReadBW_32Bit (2*Hw6)
++#define DRV_GDMA_CFG_WriteBW_8Bit (0*Hw4)
++#define DRV_GDMA_CFG_WriteBW_16Bit (1*Hw4)
++#define DRV_GDMA_CFG_WriteBW_32Bit (2*Hw4)
++#define DRV_GDMA_CFG_InterruptEnable Hw2 // HwCHCTRL_IEN
++#define DRV_GDMA_CFG_RepeatEver Hw1 // HwCHCTRL_REP
++
++#define DRV_GDMA_CFG_1HopUnit_SHIFT 14
++#define DRV_GDMA_CFG_1HopUnit(X) ((X)<<DRV_GDMA_CFG_1HopUnit_SHIFT)
++#define DRV_GDMA_CFG_1HopUnit_1Byte DRV_GDMA_CFG_1HopUnit(0)
++#define DRV_GDMA_CFG_1HopUnit_2Byte DRV_GDMA_CFG_1HopUnit(1)
++#define DRV_GDMA_CFG_1HopUnit_4Byte DRV_GDMA_CFG_1HopUnit(2)
++#define DRV_GDMA_CFG_1HopUnit_8Byte DRV_GDMA_CFG_1HopUnit(3)
++#define DRV_GDMA_CFG_1HopUnit_16Byte DRV_GDMA_CFG_1HopUnit(4)
++#define DRV_GDMA_CFG_1HopUnit_32Byte DRV_GDMA_CFG_1HopUnit(5)
++#define DRV_GDMA_CFG_1HopUnit_MASK DRV_GDMA_CFG_1HopUnit(7)
++#define DRV_GDMA_CFG_1HopUnit_Auto Hw17
++
++#define DRV_GDMA_CFG_BufNum_SHIFT 18
++#define DRV_GDMA_CFG_BufNum(X) ((X)<<DRV_GDMA_CFG_BufNum_SHIFT)
++#define DRV_GDMA_CFG_BufNum_1 DRV_GDMA_CFG_BufNum(0) // Single Buffering (DMA Interrupt Occurs after entire buffer is processed)
++#define DRV_GDMA_CFG_BufNum_2 DRV_GDMA_CFG_BufNum(1) // Double Buffering (DMA Interrupt Occurs after Half of buffer is processed)
++#define DRV_GDMA_CFG_BufNum_4 DRV_GDMA_CFG_BufNum(2) // Quad Buffering (DMA Interrupt Occurs after 1/4 of buffer is processed)
++#define DRV_GDMA_CFG_BufNum_8 DRV_GDMA_CFG_BufNum(3)
++#define DRV_GDMA_CFG_BufNum_16 DRV_GDMA_CFG_BufNum(4)
++#define DRV_GDMA_CFG_BufNum_32 DRV_GDMA_CFG_BufNum(5)
++#define DRV_GDMA_CFG_BufNum_64 DRV_GDMA_CFG_BufNum(6)
++#define DRV_GDMA_CFG_BufNum_128 DRV_GDMA_CFG_BufNum(7)
++#define DRV_GDMA_CFG_BufNum_256 DRV_GDMA_CFG_BufNum(8)
++#define DRV_GDMA_CFG_BufNum_512 DRV_GDMA_CFG_BufNum(9)
++#define DRV_GDMA_CFG_BufNum_1024 DRV_GDMA_CFG_BufNum(10)
++#define DRV_GDMA_CFG_BufNum_2048 DRV_GDMA_CFG_BufNum(11)
++#define DRV_GDMA_CFG_BufNum_4096 DRV_GDMA_CFG_BufNum(12)
++#define DRV_GDMA_CFG_BufNum_8192 DRV_GDMA_CFG_BufNum(13)
++#define DRV_GDMA_CFG_BufNum_16384 DRV_GDMA_CFG_BufNum(14)
++#define DRV_GDMA_CFG_BufNum_32768 DRV_GDMA_CFG_BufNum(15)
++#define DRV_GDMA_CFG_BufNum_MASK DRV_GDMA_CFG_BufNum(15)
++
++// GDMA Driver H/W Request Selection Definition
++#define DRV_GDMA_HwREQ_ECC Hw0
++#define DRV_GDMA_HwREQ_NFC Hw1
++#define DRV_GDMA_HwREQ_DAI_TX Hw2
++#define DRV_GDMA_HwREQ_DAI_RX Hw3
++#define DRV_GDMA_HwREQ_CDIF_RX Hw4
++#define DRV_GDMA_HwREQ_UART0_TX Hw5
++#define DRV_GDMA_HwREQ_UART0_RX Hw6
++#define DRV_GDMA_HwREQ_UART1_TX Hw7
++#define DRV_GDMA_HwREQ_UART1_RX Hw8
++#define DRV_GDMA_HwREQ_UART2_TX Hw9
++#define DRV_GDMA_HwREQ_UART2_RX Hw10
++#define DRV_GDMA_HwREQ_UART3_TX Hw11
++#define DRV_GDMA_HwREQ_UART3_RX Hw12
++
++extern S32 DRV_GDMA(U32 Func, U32 ArgN, ...);
++
++/*==============================================================================
++ Timer
++ ==============================================================================*/
++
++#define DRV_TMR_MAX_HANDLE 10
++enum
++{
++
++ DRV_TMR_FUNC_INIT,
++ DRV_TMR_FUNC_OPEN,
++ DRV_TMR_FUNC_SETCFG,
++ DRV_TMR_FUNC_CLOSE,
++ DRV_TMR_FUNC_START,
++ DRV_TMR_FUNC_ENABLE,
++ DRV_TMR_FUNC_DISABLE,
++
++ DRV_TMR_FUNC_MAX
++};
++
++
++// GDMA Driver Return Value Definition
++#define DRV_TMR_ERROR_YES 1
++#define DRV_TMR_ERROR_NO 0
++#define DRV_TMR_ERROR_OK 0
++
++enum
++{
++ // Error for Driver State
++ DRV_TMR_ERROR_NOTINIT = (int)0xF0040000, // Non-init Function come before init function
++ DRV_TMR_ERROR_DUPINIT, // Init function called more than twice
++
++ // Error for Input Parameter
++ DRV_TMR_ERROR_INVALID_FUNC, // Function Code is out of range
++ DRV_TMR_ERROR_INVALID_ARGUMENT, // Number of Argument is out of range
++ DRV_TMR_ERROR_INVALID_HANDLE, // Handle value is out of range
++ DRV_TMR_ERROR_INVALID_CH, // Channel value is out of range
++
++ // Error for Resource Availability
++ DRV_TMR_ERROR_NOTAVAILABLE_HANDLE, // No available handle
++ DRV_TMR_ERROR_NOTAVAILABLE_CH, // No available channel
++
++ // Error for Operating
++ DRV_TMR_ERROR_TIMEOUT, // Time Out
++ DRV_TMR_ERROR_NOT_READY,
++ DRV_TMR_ERROR_NOT_ACTIVE,
++ DRV_TMR_ERROR_NOT_PAUSE,
++
++ // Error for Illegal State
++ DRV_TMR_ERROR_INTERNAL, // Internal Bug
++
++ DRV_TMR_ERROR_MAX
++};
++
++// GDMA Driver Status Definition
++enum
++{
++ DRV_TMR_STATUS_INVALID, // Not Opened
++ DRV_TMR_STATUS_IDLE, // Openad but Not Activated
++ DRV_TMR_STATUS_PAUSE, // Opened & Activated & Pause
++ DRV_TMR_STATUS_ACTIVE, // Opened & Activated
++ DRV_TMR_STATUS_MAX
++};
++
++typedef struct
++{
++ U32 CHTCFG;
++ U32 CHTREF;
++ U32 CHTMREF;
++ U8 CHSTS;
++
++ U32 HwCHTCFG;
++ U32 HwCHTREF;
++ U32 HwCHTMREF;
++
++#ifdef TCC89XX
++ PTIMERN pHwTMR;
++#else
++ sHwTMR *pHwTMR;
++#endif
++
++}sDRV_TMR;
++
++#define TIMER_INT_ENABLE 1
++#define TIMER_INT_DISABLE 0
++
++
++#define DRV_TMR_CFG_ContinuousMode 0
++#define DRV_TMR_CFG_OneTimeMode Hw9
++#define DRV_TMR_CFG_TCKDIVIDE2 0*Hw4
++#define DRV_TMR_CFG_TCKDIVIDE4 1*Hw4
++#define DRV_TMR_CFG_TCKDIVIDE8 2*Hw4
++#define DRV_TMR_CFG_TCKDIVIDE16 3*Hw4
++#define DRV_TMR_CFG_TCKDIVIDE32 4*Hw4
++#define DRV_TMR_CFG_TCKDIVIDE1024 5*Hw4
++#define DRV_TMR_CFG_TCKDIVIDE4096 6*Hw4
++#define DRV_TMR_CFG_TCKEXTERNAL 7*Hw4
++#define DRV_TMR_CFG_InterruptEnable Hw3
++#define DRV_TMR_CFG_InterruptDisable 0
++#define DRV_TMR_CFG_PWMEnable Hw2
++#define DRV_TMR_CFG_PWMDisable 0
++#define DRV_TMR_CFG_TCNTnSartCountTREFn Hw1
++#define DRV_TMR_CFG_TCNTnStartCountZero 0
++#define DRV_TMR_CFG_TimerEnable Hw0
++#define DRV_TMR_CFG_TimerDisable 0
++
++extern S32 DRV_TIMER(U32 Func, U32 ArgN, ...);
++
++/*==============================================================================
++ UART
++ ==============================================================================*/
++
++#define DRV_UART_MAX_HANDLE 10
++
++// UART Driver Function Definition
++enum
++{
++ DRV_UART_FUNC_INIT, // UART Driver Initialization : Argument = None
++ DRV_UART_FUNC_PROCESS_INTERRUPT, // Process UART Interrupt : Argument = [Channel]
++
++ DRV_UART_FUNC_OPEN, // Open Handle : Argument = (Channel Number, [Port Number], *sDRV_UART)
++ DRV_UART_FUNC_INSTALL_HANDLER, // Install UART Interrupt Handler : Argument = (Channel, NewHandler, [* OldHandler])
++ DRV_UART_FUNC_UNINSTALL_HANDLER, // UnInstall UART Interrupt Handler : Argument = (Channel)
++
++ DRV_UART_FUNC_GETHwUART, // Get HwUART Base Address : Argument = (Handle, *sHwUART)
++ DRV_UART_FUNC_SETCFG, // Configurate UART : Argument = (Handle, Fuart, Baud, Interrupt, FifoCtrl, LineCtrl, AutoFlowControl)
++ DRV_UART_FUNC_SENDDATA, // Send Data using UART Channel : Argument = (Handle, Byte)
++ DRV_UART_FUNC_RCVDATA, // Receive Data using UART Channel : Argument = (Handle, *Byte)
++ DRV_UART_FUNC_OPENDMA, // Set Registers for DMA Operation : Argument = (Handle, TriggerLevel, ParityFlag, StopBitNum, WordLength)
++ DRV_UART_FUNC_CLOSEDMA, // Set Registers for Normal Operation : Argument = (Handle)
++
++ DRV_UART_FUNC_START, // Start Handle : Argument = (Handle)
++ DRV_UART_FUNC_STOP, // Stop Handle : Argument = (Handle)
++ DRV_UART_FUNC_CLOSE, // Close Handle : Argument = (Handle)
++
++ DRV_UART_FUNC_SC_OPEN, // Open Smart Card Interface : Argument = (Handle)
++ DRV_UART_FUNC_SC_CLOSE, // Close Smart Card Interface : Argument = (Handle)
++ DRV_UART_FUNC_SC_RESET, // Reset Smart Card Interface : Argument = (Handle, pATRData, pATRLength)
++ DRV_UART_FUNC_SC_SENDDATA, // Send Data to Smart Card : Argument = (Handle, pData, Length)
++ DRV_UART_FUNC_SC_RCVDATA, // Receive Data from Smart Card : Argument = (Handle, pData, Length)
++
++ DRV_UART_FUNC_MAX
++};
++
++// UART Driver Status Definition
++enum
++{
++ DRV_UART_STATUS_INVALID, // Not Opened
++ DRV_UART_STATUS_IDLE, // Openad but Not Activated
++ DRV_UART_STATUS_PAUSE, // Opened & Activated & Pause
++ DRV_UART_STATUS_ACTIVE, // Opened & Activated
++ DRV_UART_STATUS_MAX
++};
++
++// UART Driver Data Structure
++typedef struct
++{
++ U32 BAUD; // Baud Rate
++ U8 IER; // Interrupt Enable Register
++ U8 FCR; // FIFO Control Register
++ U8 LCR; // Line Control Register
++ U8 AFT; // Auto Flow Control Trigger Level Register
++ U32 Fuart; // UART Main Clock Frequency
++ U32 SCCTRL; // UART Smart Card Control
++ U32 SCCLK; // UART Smart Card Clock
++
++ U8 CHSTS; // Handle Status
++ U8 CHANNEL; // Channel Number
++ U8 PORT; // Port Number
++#ifdef TCC89XX
++ PUART pHwUART; // Base Address
++#else
++ sHwUART *pHwUART; // Base Address
++#endif
++} sDRV_UART;
++
++// UART Driver Buffer structure for Smart Card
++#define IO_UART_RX_BUFFER_SIZE (1<<8)
++#define IO_UART_TX_BUFFER_SIZE (1<<3)
++typedef struct
++{
++ U16 usTXHead, usTXTail;
++ U16 usRXHead, usRXTail;
++ U8 sRX_Buffer[IO_UART_RX_BUFFER_SIZE];
++ U8 sTX_Buffer[IO_UART_TX_BUFFER_SIZE];
++} sDRV_UART_BUF;
++
++// UART Driver Return Value Definition
++#define DRV_UART_ERROR_YES 1
++#define DRV_UART_ERROR_NO 0
++#define DRV_UART_ERROR_OK 0
++enum
++{
++ // Error for Driver State
++ DRV_UART_ERROR_NOTINIT = (int)0xF0055000, // Non-init Function come before init function
++ DRV_UART_ERROR_DUPINIT, // Init function called more than twice
++
++ // Error for Input Parameter
++ DRV_UART_ERROR_INVALID_FUNC, // Function Code is out of range
++ DRV_UART_ERROR_INVALID_ARGUMENT, // Number of Argument is out of range
++ DRV_UART_ERROR_INVALID_HANDLE, // Handle value is out of range
++ DRV_UART_ERROR_INVALID_CH, // Channel value is out of range
++
++ // Error for Resource Availability
++ DRV_UART_ERROR_NOTAVAILABLE_HANDLE, // No available handle
++ DRV_UART_ERROR_NOTAVAILABLE_CH, // No available channel
++
++ // Error for Receiving Operation
++ DRV_UART_ERROR_RCV_READY, // Data is not ready
++ DRV_UART_ERROR_RCV_FRAMING, // Received Data doesn't have a valid stop bit
++ DRV_UART_ERROR_RCV_PARITY, // Received Data doesn't have a correct even/odd parity
++
++ // Error for Illegal State
++ DRV_UART_ERROR_INTERNAL, // Internal Bug
++
++ DRV_UART_ERROR_MAX
++};
++
++// UART Channel Number Definition
++enum
++{
++ DRV_UART_CH0 = 0,
++ DRV_UART_CH1,
++ DRV_UART_CH2,
++ DRV_UART_CH3,
++ DRV_UART_CHMAX
++};
++
++// UART Port Number Definition
++enum
++{
++ DRV_UART_PORT0 = 0,
++ DRV_UART_PORT1,
++ DRV_UART_PORT2,
++ DRV_UART_PORT3,
++ DRV_UART_PORT4,
++ DRV_UART_PORT5,
++ DRV_UART_PORTMAX
++};
++
++// UART Line Parity Definition
++enum
++{
++ DRV_UART_PARITY_NONE = 0,
++ DRV_UART_PARITY_ODD,
++ DRV_UART_PARITY_EVEN,
++ DRV_UART_PARITY_MAX
++};
++
++// UART Buffer Definition
++enum
++{
++ DRV_UART_BUFFER_TX = 0,
++ DRV_UART_BUFFER_RX,
++ DRV_UART_BUFFER_TXRX,
++ DRV_UART_BUFFER_MAX
++};
++
++// UART Smart Card Control Definition
++enum
++{
++ DRV_UART_SCCTRL_OFF = 0,
++ DRV_UART_SCCTRL_ON,
++ DRV_UART_SCCTRL_MAX
++};
++
++// UART Interrupt Definition for Smart Card
++enum
++{
++ DRV_UART_SCINT_DISABLE = 0,
++ DRV_UART_SCINT_ENABLE,
++ DRV_UART_SCINT_NOCHANGE,
++ DRV_UART_SCINT_MAX
++};
++
++// UART Application Definition
++enum
++{
++ DRV_UART_APP_DEBUG = 0, // Debugging by using tbench
++ DRV_UART_APP_BLUETOOTH, // Bluetooth
++ DRV_UART_APP_SMARTCARD, // SmartCard Interface
++ DRV_UART_APP_COMMAND, // Command Interpreter for Module Solution
++ DRV_UART_APP_MAX
++};
++
++// UART Driver Channel Configuration Definition
++#define DRV_UART_IER_EnableMSI Hw3
++#define DRV_UART_IER_DisableMSI 0
++#define DRV_UART_IER_EnableRcvLSI Hw2
++#define DRV_UART_IER_DisableRcvLSI 0
++#define DRV_UART_IER_EnableTXI Hw1
++#define DRV_UART_IER_DisableTXI 0
++#define DRV_UART_IER_EnableRXI Hw0
++#define DRV_UART_IER_DisableRXI 0
++
++#define DRV_UART_FCR_RxTriggerLvl_SHIFT 6
++#define DRV_UART_FCR_RxTriggerLvl(X) ((X)<<DRV_UART_FCR_RxTriggerLvl_SHIFT)
++#define DRV_UART_FCR_RxTriggerLvl_01 DRV_UART_FCR_RxTriggerLvl(0)
++#define DRV_UART_FCR_RxTriggerLvl_04 DRV_UART_FCR_RxTriggerLvl(1)
++#define DRV_UART_FCR_RxTriggerLvl_08 DRV_UART_FCR_RxTriggerLvl(2)
++#define DRV_UART_FCR_RxTriggerLvl_14 DRV_UART_FCR_RxTriggerLvl(3)
++#define DRV_UART_FCR_TxWindowLvl_SHIFT 4
++#define DRV_UART_FCR_TxWindowLvl(X) ((X)<<DRV_UART_FCR_TxWindowLvl_SHIFT)
++#define DRV_UART_FCR_TxWindowLvl_16 DRV_UART_FCR_TxWindowLvl(0)
++#define DRV_UART_FCR_TxWindowLvl_08 DRV_UART_FCR_TxWindowLvl(1)
++#define DRV_UART_FCR_TxWindowLvl_04 DRV_UART_FCR_TxWindowLvl(2)
++#define DRV_UART_FCR_TxWindowLvl_01 DRV_UART_FCR_TxWindowLvl(3)
++#define DRV_UART_FCR_EnableDMA Hw3
++#define DRV_UART_FCR_DisableDMA 0
++#define DRV_UART_FCR_TxFifoReset Hw2
++#define DRV_UART_FCR_RxFifoReset Hw1
++#define DRV_UART_FCR_EnableFifo Hw0
++#define DRV_UART_FCR_DisableFifo 0
++
++#define DRV_UART_LCR_AccessDivisor Hw7
++#define DRV_UART_LCR_NotAccessDivisor 0
++#define DRV_UART_LCR_EnableBreak Hw6
++#define DRV_UART_LCR_DisableBreak 0
++#define DRV_UART_LCR_EnableStickParity Hw5
++#define DRV_UART_LCR_DisableStickParity 0
++#define DRV_UART_LCR_EnableEvenParity Hw4
++#define DRV_UART_LCR_EnableOddParity 0
++#define DRV_UART_LCR_EnableParity Hw3
++#define DRV_UART_LCR_DisableParity 0
++#define DRV_UART_LCR_OneStopBit Hw2
++#define DRV_UART_LCR_TwoStopBit 0
++#define DRV_UART_LCR_WordLength_SHIFT 0
++#define DRV_UART_LCR_WordLength(X) ((X)<<DRV_UART_LCR_WordLength_SHIFT)
++#define DRV_UART_LCR_WordLength_5Bit DRV_UART_LCR_WordLength(0)
++#define DRV_UART_LCR_WordLength_6Bit DRV_UART_LCR_WordLength(1)
++#define DRV_UART_LCR_WordLength_7Bit DRV_UART_LCR_WordLength(2)
++#define DRV_UART_LCR_WordLength_8Bit DRV_UART_LCR_WordLength(3)
++
++// UART SmartCard Clock Definition
++#define DRV_UART_SCCLK 60000 // 6.0 MHz
++// UART SmartCard Clock Conversion Factor Definition
++#define DRV_UART_SCCLK_FACTOR 372
++// UART SmartCard Delay Time Definition
++#define DRV_UART_SC_DELAY_TIME 4000 // 4.0 ms
++
++extern S32 DRV_UART(U32 Func, U32 ArgN, ...);
++
++/*==============================================================================
++ GPSB
++ ==============================================================================*/
++
++#define DRV_GPSB_MAX_HANDLE 10
++
++// GPSB Driver Function Definition
++enum
++{
++ DRV_GPSB_FUNC_INIT, // GPSB Driver Initialization : Argument = None
++ DRV_GPSB_FUNC_PROCESS_INTERRUPT, // Process GPSB Interrupt : Argument = None
++
++ DRV_GPSB_FUNC_OPEN, // Open Handle : Argument = (Channel Number, Port Number, *sDRV_GPSB)
++ DRV_GPSB_FUNC_INSTALL_HANDLER, // Install Handler : Argument = (Channel, NewHandler, [* OldHandler])
++ DRV_GPSB_FUNC_UNINSTALL_HANDLER, // Install Handler : Argument = (Channel)
++
++ DRV_GPSB_FUNC_GETHwGPSB, // Get HwGPSB Base Address : Argument = (Handle, *sHwGPSB)
++ DRV_GPSB_FUNC_SETCFG, // Configurate GPSB : Argument = (Handle, MODE, SCKFREQ, SWCTRL, SDOSDI)
++ DRV_GPSB_FUNC_SENDDATA, // Send Data using GPSB Channel : Argument = (Handle, Cmd, *Buffer, Length, BitWidth)
++ DRV_GPSB_FUNC_RCVDATA, // Receive Data using GPSB Channel : Argument = (Handle, Cmd, *Buffer, Length, BitWidth)
++ DRV_GPSB_FUNC_UPDATEPID, // Update PID Table = (Handle, *PIDTable)
++ DRV_GPSB_FUNC_OPENDMA, // Set Registers for DMA Operation : Argument = (Handle)
++ DRV_GPSB_FUNC_CLOSEDMA, // Set Registers for Normal Operation : Argument = (Handle)
++ DRV_GPSB_FUNC_STARTDMA, // Set Registers for Starting DMA Operation : Argument = (Handle, DMADir, PktSize, PktNum, *TxBuf, *RxBuf, FIFOThr, ContMode)
++ DRV_GPSB_FUNC_STOPDMA, // Set Registers for Stopping DMA Operation : Argument = (Handle)
++
++ DRV_GPSB_FUNC_START, // Start Handle : Argument = (Handle)
++ DRV_GPSB_FUNC_STOP, // Stop Handle : Argument = (Handle)
++ DRV_GPSB_FUNC_CLOSE, // Close Handle : Argument = (Handle)
++
++ DRV_GPSB_FUNC_MAX
++};
++
++// GPSB Driver Status Definition
++enum
++{
++ DRV_GPSB_STATUS_INVALID, // Not Opened
++ DRV_GPSB_STATUS_IDLE, // Openad but Not Activated
++ DRV_GPSB_STATUS_PAUSE, // Opened & Activated & Pause
++ DRV_GPSB_STATUS_ACTIVE, // Opened & Activated
++ DRV_GPSB_STATUS_MAX
++};
++
++// GPSB DMA Mode Information Structure
++typedef struct
++{
++ U8 DMAMode; // DMA Mode - Normal, MPEG2-TS
++ U8 PIDMatch; // PID Match Control - 0: Disable, 1: Enable
++ U8 SyncMatch; // Sync Byte Match Control - 0: Disable, 1: Enable
++ U8 PIDNum; // Number of PID
++} sGPSB_DMA;
++
++// GPSB Driver Data Structure
++typedef struct
++{
++ U32 MODE; // Mode Register
++ U32 SCKFREQ; // SCK Frequency
++ U8 SWCTRL; // Control Setting
++ U8 SDOSDI; // Output/Input Use Setting
++ U8 CHSTS; // Handle Status
++ U8 CHANNEL; // Channel Number
++ U8 PORT; // Port Number
++ sGPSB_DMA DMAMODE; // DMA Mode Information
++#ifdef TCC89XX
++ PGPSB *pHwGPSB; // Base Address
++#else
++ sHwGPSB *pHwGPSB; // Base Address
++#endif
++} sDRV_GPSB;
++
++// GPSB Driver Return Value Definition
++#define DRV_GPSB_ERROR_YES 1
++#define DRV_GPSB_ERROR_NO 0
++#define DRV_GPSB_ERROR_OK 0
++enum
++{
++ // Error for Driver State
++ DRV_GPSB_ERROR_NOTINIT = (int)0xF0057400, // Non-init Function come before init function
++ DRV_GPSB_ERROR_DUPINIT, // Init function called more than twice
++
++ // Error for Input Parameter
++ DRV_GPSB_ERROR_INVALID_FUNC, // Function Code is out of range
++ DRV_GPSB_ERROR_INVALID_ARGUMENT, // Number of Argument is out of range
++ DRV_GPSB_ERROR_INVALID_HANDLE, // Handle value is out of range
++ DRV_GPSB_ERROR_INVALID_CH, // Channel value is out of range
++
++ // Error for Resource Availability
++ DRV_GPSB_ERROR_NOTAVAILABLE_HANDLE, // No available handle
++ DRV_GPSB_ERROR_NOTAVAILABLE_CH, // No available channel
++
++ // Error for Illegal State
++ DRV_GPSB_ERROR_INTERNAL, // Internal Bug
++
++ DRV_GPSB_ERROR_MAX
++};
++
++// GPSB Channel Control Method Definition
++enum
++{
++ DRV_GPSB_CTRL_HW = 0,
++ DRV_GPSB_CTRL_SW,
++ DRV_GPSB_CTRL_MAX
++};
++#define DRV_GPSB_SwCtrlMode(X) ((X)&0x3F)
++
++// GPSB Tx/Rx Swap Mode Definition
++#define DRV_GPSB_SWAP_TX Hw6
++#define DRV_GPSB_SWAP_RX Hw7
++
++#define DRV_GPSB_SwapMode(X) ((X) & (DRV_GPSB_SWAP_TX | DRV_GPSB_SWAP_RX))
++#define DRV_GPSB_SwapMode_Tx(X) (((X) & DRV_GPSB_SWAP_TX) ? 1 : 0)
++#define DRV_GPSB_SwapMode_Rx(X) (((X) & DRV_GPSB_SWAP_RX) ? 1 : 0)
++
++// GPSB Channel Master/Slave Definition
++enum
++{
++ DRV_GPSB_MODE_MASTER = 0,
++ DRV_GPSB_MODE_SLAVE,
++ DRV_GPSB_MODE_MAX
++};
++
++// GPSB Channel I/O Definition
++enum
++{
++ DRV_GPSB_SDOSDI_NOUSE = 0,
++ DRV_GPSB_SDOSDI_SDI,
++ DRV_GPSB_SDOSDI_SDO,
++ DRV_GPSB_SDOSDI_ALLUSE,
++ DRV_GPSB_SDOSDI_MAX
++};
++
++// GPSB Channel Number Definition
++enum
++{
++ DRV_GPSB_CH0 = 0,
++ DRV_GPSB_CH1,
++#if defined(TCC79XX) ||defined(TCC89XX)
++ DRV_GPSB_CH2,
++ DRV_GPSB_CH3,
++#endif
++#if defined(TCC89XX)
++ DRV_GPSB_CH4,
++ DRV_GPSB_CH5,
++#endif
++ DRV_GPSB_CHMAX
++};
++
++// GPSB Port Number Definition
++enum
++{
++ DRV_GPSB_PORT0 = 0,
++ DRV_GPSB_PORT1,
++ DRV_GPSB_PORT2,
++#if defined(TCC79XX) ||defined(TCC89XX)
++ DRV_GPSB_PORT3,
++ DRV_GPSB_PORT4,
++ DRV_GPSB_PORT5,
++ DRV_GPSB_PORT6,
++ DRV_GPSB_PORT7,
++ DRV_GPSB_PORT8,
++ DRV_GPSB_PORT9,
++ DRV_GPSB_PORT10,
++#endif
++#if defined(TCC89XX)
++ DRV_GPSB_PORT11,
++ DRV_GPSB_PORT12,
++#endif
++ DRV_GPSB_PORTMAX
++};
++
++// GPSB DMA Mode Definition
++enum
++{
++ DRV_GPSB_DMAMODE_NOR = 0,
++ DRV_GPSB_DMAMODE_TS,
++ DRV_GPSB_DMAMODE_MAX
++};
++
++// GPSB DMA Transfer Direction Definition
++enum
++{
++ DRV_GPSB_DMA_RECEIVE = 0,
++ DRV_GPSB_DMA_TRANSMIT,
++ DRV_GPSB_DMA_MAX
++};
++
++// GPSB Driver Channel Mode Definition
++#define DRV_GPSB_MODE_Divisor_SHIFT 24
++#define DRV_GPSB_MODE_Divisor(X) ((X)<<DRV_GPSB_MODE_Divisor_SHIFT)
++#define DRV_GPSB_MODE_MRecoverTime_2SCKO Hw23
++#define DRV_GPSB_MODE_MRecoverTime_SCKO 0
++#define DRV_GPSB_MODE_MHoldTime_2SCKO Hw22
++#define DRV_GPSB_MODE_MHoldTime_SCKO 0
++#define DRV_GPSB_MODE_MSetupTime_2SCKO Hw21
++#define DRV_GPSB_MODE_MSetupTime_SCKO 0
++#define DRV_GPSB_MODE_CSActiveHigh Hw20
++#define DRV_GPSB_MODE_CSActiveLow 0
++#define DRV_GPSB_MODE_CMDActiveHigh Hw19
++#define DRV_GPSB_MODE_CMDActiveLow 0
++#define DRV_GPSB_MODE_TransRisingEdge Hw18
++#define DRV_GPSB_MODE_TransFallingEdge 0
++#define DRV_GPSB_MODE_RcvRisingEdge Hw17
++#define DRV_GPSB_MODE_RcvFallingEdge 0
++#define DRV_GPSB_MODE_SCKPolCtrl_High Hw16
++#define DRV_GPSB_MODE_SCKPolCtrl_Low 0
++#define DRV_GPSB_MODE_ClearRcvFifoCount Hw15
++#define DRV_GPSB_MODE_ClearTransFifoCount Hw14
++#define DRV_GPSB_MODE_BitWidth_SHIFT 8
++#define DRV_GPSB_MODE_BitWidth(X) ((X)<<DRV_GPSB_MODE_BitWidth_SHIFT)
++#define DRV_GPSB_MODE_DataShiftLSBFirst Hw7
++#define DRV_GPSB_MODE_DataShiftMSBFirst 0
++#define DRV_GPSB_MODE_EnableLoopBack Hw6
++#define DRV_GPSB_MODE_DisableLoopBack 0
++#define DRV_GPSB_MODE_EnableContTrans Hw4
++#define DRV_GPSB_MODE_DisableContTrans 0
++#define DRV_GPSB_MODE_EnableOperation Hw3
++#define DRV_GPSB_MODE_DisableOperation 0
++#define DRV_GPSB_MODE_SlaveMode Hw2
++#define DRV_GPSB_MODE_MasterMode 0
++#define DRV_GPSB_MODE_OpMode_SHIFT 0
++#define DRV_GPSB_MODE_OpMode(X) ((X)<<DRV_GPSB_MODE_OpMode_SHIFT)
++#define DRV_GPSB_MODE_OpMod_SPI DRV_GPSB_MODE_OpMode(0)
++#define DRV_GPSB_MODE_OpMod_SSP DRV_GPSB_MODE_OpMode(1)
++
++// GPSB PID Table Definition
++#define DRV_GPSB_PID_MAX_NUM 32
++#define DRV_GPSB_PID_VALUE_MASK 0x1FFF
++
++extern S32 DRV_GPSB(U32 Func, U32 ArgN, ...);
++
++
++/*==============================================================================
++ I2C
++ ==============================================================================*/
++int DDI_I2C_Initialize(void);
++int DDI_I2C_Terminate(void);
++int DDI_I2C_Write(unsigned int uiFlag, unsigned int uiHbyte, unsigned int uiLbyte);
++int DDI_I2C_Read(unsigned int uiFlag, unsigned int uiHbyte, unsigned int uiLbyte);
++
++#define DRV_I2CM_MAX_HANDLE 10
++#define DRV_I2CS_MAX_HANDLE 10
++
++#define DRV_I2C_MASTER 1
++#define DRV_I2C_SLAVE 2
++
++#define DRV_I2C_MODE_8BIT 1
++#define DRV_I2C_MODE_16BIT 2
++
++#define DRV_IO_I2CM_CH0 0
++#define DRV_IO_I2CM_CH1 1
++
++#define DRV_IO_I2C_PORT0 0
++#define DRV_IO_I2C_PORT1 1
++
++enum
++{
++
++ DRV_I2C_FUNC_INIT,
++ DRV_I2C_FUNC_OPEN,
++ DRV_I2C_FUNC_SETCFG,
++ DRV_I2C_FUNC_INSTALL_HANDLER,
++ DRV_I2C_FUNC_UNINSTALL_HANDLER,
++ DRV_I2C_FUNC_PROCESS_INTERRUPT,
++ DRV_I2C_FUNC_CLOSE,
++ DRV_I2C_FUNC_START,
++ DRV_I2C_FUNC_WRITE,
++ DRV_I2C_FUNC_READ,
++
++ DRV_I2C_FUNC_MAX
++};
++
++
++// I2C Driver Return Value Definition
++#define DRV_I2C_ERROR_YES 1
++#define DRV_I2C_ERROR_NO 0
++#define DRV_I2C_ERROR_OK 0
++
++enum
++{
++ // Error for Driver State
++ DRV_I2C_ERROR_NOTINIT = (int)0xF0040000, // Non-init Function come before init function
++ DRV_I2C_ERROR_DUPINIT, // Init function called more than twice
++
++ // Error for Input Parameter
++ DRV_I2C_ERROR_INVALID_FUNC, // Function Code is out of range
++ DRV_I2C_ERROR_INVALID_ARGUMENT, // Number of Argument is out of range
++ DRV_I2C_ERROR_INVALID_HANDLE, // Handle value is out of range
++ DRV_I2C_ERROR_INVALID_CH, // Channel value is out of range
++
++ // Error for Resource Availability
++ DRV_I2C_ERROR_NOTAVAILABLE_HANDLE, // No available handle
++ DRV_I2C_ERROR_NOTAVAILABLE_CH, // No available channel
++
++ // Error for Operating
++ DRV_I2C_ERROR_TIMEOUT, // Time Out
++ DRV_I2C_ERROR_NOT_READY,
++ DRV_I2C_ERROR_NOT_ACTIVE,
++ DRV_I2C_ERROR_NOT_PAUSE,
++
++ // Error for Illegal State
++ DRV_I2C_ERROR_INTERNAL, // Internal Bug
++
++ DRV_I2C_ERROR_MAX
++};
++
++// I2C Driver Status Definition
++enum
++{
++ DRV_I2C_STATUS_INVALID, // Not Opened
++ DRV_I2C_STATUS_IDLE, // Openad but Not Activated
++ DRV_I2C_STATUS_PAUSE, // Opened & Activated & Pause
++ DRV_I2C_STATUS_ACTIVE, // Opened & Activated
++ DRV_I2C_STATUS_MAX
++};
++
++typedef struct
++{
++ U32 CHPRES;
++ U32 CHCTRL;
++ U8 CHSTS;
++
++ U32 SlaveAddr;
++ U32 PORT;
++ U32 BitMode;
++
++ U32 HWPRES;
++ U32 HWCTRL;
++ U32 HWSR;
++ U32 HWTR;
++
++#ifdef TCC89XX
++ I2CMASTER *pHwI2CM;
++#else
++ sHwI2CM *pHwI2CM;
++#endif
++
++}sDRV_I2CM;
++
++typedef struct
++{
++ U32 CHCTL;
++ U32 CHADDR;
++ U32 CHINT;
++
++ U8 CHSTS;
++
++ U32 HwDPORT;
++ U32 HwCTL;
++ U32 HwADDR;
++ U32 HwINT;
++ U32 HwSTAT;
++ U32 HwMBF;
++ U32 HwMB0;
++ U32 HwMB1;
++
++#ifdef TCC89XX
++ PI2CSLAVE pHwI2CS;
++#else
++ sHwI2CS *pHwI2CS;
++#endif
++
++}sDRV_I2CS;
++
++#define DRV_I2CM_SCL_400KHz 4000
++#define DRV_I2CM_SCL_260KHz 2600
++#define DRV_I2CM_SCL_200KHz 2000
++#define DRV_I2CM_SCL_160KHz 1600
++#define DRV_I2CM_SCL_133KHz 1330
++#define DRV_I2CM_SCL_100KHz 1000
++
++#define DRV_I2CM_CTR_I2CCoreEnable Hw7
++#define DRV_I2CM_CTR_I2CCoreDisable 0
++#define DRV_I2CM_CTR_I2CCoreInterruptEnable Hw6
++#define DRV_I2CM_CTR_I2CCoreInterruptDisable 0
++#define DRV_I2CM_CTR_I2CDataWidth8Bit 0
++#define DRV_I2CM_CTR_I2CDataWidth16Bit Hw5
++
++#define DRV_I2CM_CMD_STA_Enable Hw7
++#define DRV_I2CM_CMD_STA_Disable 0
++#define DRV_I2CM_CMD_STO_Enable Hw6
++#define DRV_I2CM_CMD_STO_Disable 0
++#define DRV_I2CM_CMD_RD_Enable Hw5
++#define DRV_I2CM_CMD_RD_Disable 0
++#define DRV_I2CM_CMD_WR_Enable Hw4
++#define DRV_I2CM_CMD_WR_Disable 0
++#define DRV_I2CM_CMD_ACK_Enable Hw3
++#define DRV_I2CM_CMD_ACK_Disable 0
++#define DRV_I2CM_CMD_LATCH_Enable 1
++#define DRV_I2CM_CMD_LATCH_Disable 0
++
++#define DRV_I2CS_CTL_0Master_1Master 0
++#define DRV_I2CS_CTL_0Slave_1Master Hw30
++#define DRV_I2CS_CTL_0Master_1Slave Hw31
++#define DRV_I2CS_CTL_RXFIFOThreshold1 Hw8
++#define DRV_I2CS_CTL_FIFO_Clear Hw2
++#define DRV_I2CS_CTL_I2CSlaveCoreEnable Hw0
++#define DRV_I2CS_CTL_I2CSlaveCoreDisable 0
++
++#define DRV_I2CS_INT_STAT_R_BYTE Hw27 // All byte of data buffer has been read by a master
++#define DRV_I2CS_INT_STAT_W_BYTE Hw26 // All byte of data buffer has been written by a master
++#define DRV_I2CS_INT_STAT_R_BUFF Hw25 // Data buffer has been read by a master
++#define DRV_I2CS_INT_STAT_W_BUFF Hw24 // Data buffer has been written by a master
++#define DRV_I2CS_INT_STAT_TXUR Hw23 // TX FIFO under run
++#define DRV_I2CS_INT_STAT_RXOR Hw22 // RX FIFO over run
++#define DRV_I2CS_INT_STAT_TXB Hw21 // TX bus cycle started with TX FIFO empty
++#define DRV_I2CS_INT_STAT_RXF Hw20 // RX FIFO full
++#define DRV_I2CS_INT_STAT_TXE Hw19 // TX FIFO empty
++#define DRV_I2CS_INT_STAT_RXNE Hw18 // RX FIFO not empty
++#define DRV_I2CS_INT_STAT_TXL Hw17 // TX FIFO Level (TXVC <= TXTH)
++#define DRV_I2CS_INT_STAT_RXL Hw16 // RX FIFO Level (RXVC <= RXTH)
++
++#define DRV_I2CS_INT_EN_R_BYTE Hw11 // All byte of data buffer has been read by a master
++#define DRV_I2CS_INT_EN_W_BYTE Hw10 // All byte of data buffer has been written by a master
++#define DRV_I2CS_INT_EN_R_BUFF Hw9 // Data buffer has been read by a master
++#define DRV_I2CS_INT_EN_W_BUFF Hw8 // Data buffer has been written by a master
++#define DRV_I2CS_INT_EN_TXUR Hw7 // TX FIFO under run
++#define DRV_I2CS_INT_EN_RXOR Hw6 // RX FIFO over run
++#define DRV_I2CS_INT_EN_TXB Hw5 // TX bus cycle started with TX FIFO empty
++#define DRV_I2CS_INT_EN_RXF Hw4 // RX FIFO full
++#define DRV_I2CS_INT_EN_TXE Hw3 // TX FIFO empty
++#define DRV_I2CS_INT_EN_RXNE Hw2 // RX FIFO not empty
++#define DRV_I2CS_INT_EN_TXL Hw1 // TX FIFO Level (TXVC <= TXTH)
++#define DRV_I2CS_INT_EN_RXL Hw0 // RX FIFO Level (RXVC <= RXTH)
++
++// I2C Master
++extern S32 DRV_I2CM(U32 Func, U32 ArgN, ...);
++
++// I2C Slave
++extern S32 DRV_I2CS( U32 Func, U32 ArgN, ... );
++
++
++/*==============================================================================
++ GPSB
++ ==============================================================================*/
++#if 0
++#define DRV_GPSB_MAX_HANDLE 10
++
++// GPSB Driver Function Definition
++enum
++{
++ DRV_GPSB_FUNC_INIT, // GPSB Driver Initialization : Argument = None
++ DRV_GPSB_FUNC_PROCESS_INTERRUPT, // Process GPSB Interrupt : Argument = None
++
++ DRV_GPSB_FUNC_OPEN, // Open Handle : Argument = (Channel Number, Port Number, *sDRV_GPSB)
++ DRV_GPSB_FUNC_INSTALL_HANDLER, // Install Handler : Argument = (Channel, NewHandler, [* OldHandler])
++ DRV_GPSB_FUNC_UNINSTALL_HANDLER, // Install Handler : Argument = (Channel)
++
++ DRV_GPSB_FUNC_GETHwGPSB, // Get HwGPSB Base Address : Argument = (Handle, *sHwGPSB)
++ DRV_GPSB_FUNC_SETCFG, // Configurate GPSB : Argument = (Handle, MODE, SCKFREQ, SWCTRL, SDOSDI)
++ DRV_GPSB_FUNC_SENDDATA, // Send Data using GPSB Channel : Argument = (Handle, Cmd, *Buffer, Length, BitWidth)
++ DRV_GPSB_FUNC_RCVDATA, // Receive Data using GPSB Channel : Argument = (Handle, Cmd, *Buffer, Length, BitWidth)
++ DRV_GPSB_FUNC_UPDATEPID, // Update PID Table = (Handle, *PIDTable)
++ DRV_GPSB_FUNC_OPENDMA, // Set Registers for DMA Operation : Argument = (Handle)
++ DRV_GPSB_FUNC_CLOSEDMA, // Set Registers for Normal Operation : Argument = (Handle)
++ DRV_GPSB_FUNC_STARTDMA, // Set Registers for Starting DMA Operation : Argument = (Handle, DMADir, PktSize, PktNum, *TxBuf, *RxBuf, FIFOThr, ContMode)
++ DRV_GPSB_FUNC_STOPDMA, // Set Registers for Stopping DMA Operation : Argument = (Handle)
++
++ DRV_GPSB_FUNC_START, // Start Handle : Argument = (Handle)
++ DRV_GPSB_FUNC_STOP, // Stop Handle : Argument = (Handle)
++ DRV_GPSB_FUNC_CLOSE, // Close Handle : Argument = (Handle)
++
++ DRV_GPSB_FUNC_MAX
++};
++
++// GPSB Driver Status Definition
++enum
++{
++ DRV_GPSB_STATUS_INVALID, // Not Opened
++ DRV_GPSB_STATUS_IDLE, // Openad but Not Activated
++ DRV_GPSB_STATUS_PAUSE, // Opened & Activated & Pause
++ DRV_GPSB_STATUS_ACTIVE, // Opened & Activated
++ DRV_GPSB_STATUS_MAX
++};
++
++// GPSB DMA Mode Information Structure
++typedef struct
++{
++ U8 DMAMode; // DMA Mode - Normal, MPEG2-TS
++ U8 PIDMatch; // PID Match Control - 0: Disable, 1: Enable
++ U8 SyncMatch; // Sync Byte Match Control - 0: Disable, 1: Enable
++ U8 PIDNum; // Number of PID
++} sGPSB_DMA;
++
++// GPSB Driver Data Structure
++typedef struct
++{
++ U32 MODE; // Mode Register
++ U32 SCKFREQ; // SCK Frequency
++ U8 SWCTRL; // Control Setting
++ U8 SDOSDI; // Output/Input Use Setting
++ U8 CHSTS; // Handle Status
++ U8 CHANNEL; // Channel Number
++ U8 PORT; // Port Number
++ sGPSB_DMA DMAMODE; // DMA Mode Information
++ sHwGPSB *pHwGPSB; // Base Address
++} sDRV_GPSB;
++
++// GPSB Driver Return Value Definition
++#define DRV_GPSB_ERROR_YES 1
++#define DRV_GPSB_ERROR_NO 0
++#define DRV_GPSB_ERROR_OK 0
++enum
++{
++ // Error for Driver State
++ DRV_GPSB_ERROR_NOTINIT = (int)0xF0057400, // Non-init Function come before init function
++ DRV_GPSB_ERROR_DUPINIT, // Init function called more than twice
++
++ // Error for Input Parameter
++ DRV_GPSB_ERROR_INVALID_FUNC, // Function Code is out of range
++ DRV_GPSB_ERROR_INVALID_ARGUMENT, // Number of Argument is out of range
++ DRV_GPSB_ERROR_INVALID_HANDLE, // Handle value is out of range
++ DRV_GPSB_ERROR_INVALID_CH, // Channel value is out of range
++
++ // Error for Resource Availability
++ DRV_GPSB_ERROR_NOTAVAILABLE_HANDLE, // No available handle
++ DRV_GPSB_ERROR_NOTAVAILABLE_CH, // No available channel
++
++ // Error for Illegal State
++ DRV_GPSB_ERROR_INTERNAL, // Internal Bug
++
++ DRV_GPSB_ERROR_MAX
++};
++
++// GPSB Channel Control Method Definition
++enum
++{
++ DRV_GPSB_CTRL_HW = 0,
++ DRV_GPSB_CTRL_SW,
++ DRV_GPSB_CTRL_MAX
++};
++#define DRV_GPSB_SwCtrlMode(X) ((X)&0x3F)
++
++// GPSB Tx/Rx Swap Mode Definition
++#define DRV_GPSB_SWAP_TX Hw6
++#define DRV_GPSB_SWAP_RX Hw7
++
++#define DRV_GPSB_SwapMode(X) ((X) & (DRV_GPSB_SWAP_TX | DRV_GPSB_SWAP_RX))
++#define DRV_GPSB_SwapMode_Tx(X) (((X) & DRV_GPSB_SWAP_TX) ? 1 : 0)
++#define DRV_GPSB_SwapMode_Rx(X) (((X) & DRV_GPSB_SWAP_RX) ? 1 : 0)
++
++// GPSB Channel Master/Slave Definition
++enum
++{
++ DRV_GPSB_MODE_MASTER = 0,
++ DRV_GPSB_MODE_SLAVE,
++ DRV_GPSB_MODE_MAX
++};
++
++// GPSB Channel I/O Definition
++enum
++{
++ DRV_GPSB_SDOSDI_NOUSE = 0,
++ DRV_GPSB_SDOSDI_SDI,
++ DRV_GPSB_SDOSDI_SDO,
++ DRV_GPSB_SDOSDI_ALLUSE,
++ DRV_GPSB_SDOSDI_MAX
++};
++
++// GPSB Channel Number Definition
++enum
++{
++ DRV_GPSB_CH0 = 0,
++ DRV_GPSB_CH1,
++#ifdef TCC79XX
++ DRV_GPSB_CH2,
++ DRV_GPSB_CH3,
++#endif
++ DRV_GPSB_CHMAX
++};
++
++// GPSB Port Number Definition
++enum
++{
++ DRV_GPSB_PORT0 = 0,
++ DRV_GPSB_PORT1,
++ DRV_GPSB_PORT2,
++#ifdef TCC79XX
++ DRV_GPSB_PORT3,
++ DRV_GPSB_PORT4,
++ DRV_GPSB_PORT5,
++ DRV_GPSB_PORT6,
++ DRV_GPSB_PORT7,
++ DRV_GPSB_PORT8,
++ DRV_GPSB_PORT9,
++ DRV_GPSB_PORT10,
++#endif
++ DRV_GPSB_PORTMAX
++};
++
++// GPSB DMA Mode Definition
++enum
++{
++ DRV_GPSB_DMAMODE_NOR = 0,
++ DRV_GPSB_DMAMODE_TS,
++ DRV_GPSB_DMAMODE_MAX
++};
++
++// GPSB DMA Transfer Direction Definition
++enum
++{
++ DRV_GPSB_DMA_RECEIVE = 0,
++ DRV_GPSB_DMA_TRANSMIT,
++ DRV_GPSB_DMA_MAX
++};
++
++// GPSB Driver Channel Mode Definition
++#define DRV_GPSB_MODE_Divisor_SHIFT 24
++#define DRV_GPSB_MODE_Divisor(X) ((X)<<DRV_GPSB_MODE_Divisor_SHIFT)
++#define DRV_GPSB_MODE_MRecoverTime_2SCKO Hw23
++#define DRV_GPSB_MODE_MRecoverTime_SCKO 0
++#define DRV_GPSB_MODE_MHoldTime_2SCKO Hw22
++#define DRV_GPSB_MODE_MHoldTime_SCKO 0
++#define DRV_GPSB_MODE_MSetupTime_2SCKO Hw21
++#define DRV_GPSB_MODE_MSetupTime_SCKO 0
++#define DRV_GPSB_MODE_CSActiveHigh Hw20
++#define DRV_GPSB_MODE_CSActiveLow 0
++#define DRV_GPSB_MODE_CMDActiveHigh Hw19
++#define DRV_GPSB_MODE_CMDActiveLow 0
++#define DRV_GPSB_MODE_TransRisingEdge Hw18
++#define DRV_GPSB_MODE_TransFallingEdge 0
++#define DRV_GPSB_MODE_RcvRisingEdge Hw17
++#define DRV_GPSB_MODE_RcvFallingEdge 0
++#define DRV_GPSB_MODE_SCKPolCtrl_High Hw16
++#define DRV_GPSB_MODE_SCKPolCtrl_Low 0
++#define DRV_GPSB_MODE_ClearRcvFifoCount Hw15
++#define DRV_GPSB_MODE_ClearTransFifoCount Hw14
++#define DRV_GPSB_MODE_BitWidth_SHIFT 8
++#define DRV_GPSB_MODE_BitWidth(X) ((X)<<DRV_GPSB_MODE_BitWidth_SHIFT)
++#define DRV_GPSB_MODE_DataShiftLSBFirst Hw7
++#define DRV_GPSB_MODE_DataShiftMSBFirst 0
++#define DRV_GPSB_MODE_EnableLoopBack Hw6
++#define DRV_GPSB_MODE_DisableLoopBack 0
++#define DRV_GPSB_MODE_EnableContTrans Hw4
++#define DRV_GPSB_MODE_DisableContTrans 0
++#define DRV_GPSB_MODE_EnableOperation Hw3
++#define DRV_GPSB_MODE_DisableOperation 0
++#define DRV_GPSB_MODE_SlaveMode Hw2
++#define DRV_GPSB_MODE_MasterMode 0
++#define DRV_GPSB_MODE_OpMode_SHIFT 0
++#define DRV_GPSB_MODE_OpMode(X) ((X)<<DRV_GPSB_MODE_OpMode_SHIFT)
++#define DRV_GPSB_MODE_OpMod_SPI DRV_GPSB_MODE_OpMode(0)
++#define DRV_GPSB_MODE_OpMod_SSP DRV_GPSB_MODE_OpMode(1)
++
++// GPSB PID Table Definition
++#define DRV_GPSB_PID_MAX_NUM 32
++#define DRV_GPSB_PID_VALUE_MASK 0x1FFF
++
++extern S32 DRV_GPSB(U32 Func, U32 ArgN, ...);
++#endif
++
++/*==============================================================================
++ 2D DMA (TCC78x)
++ ==============================================================================*/
++#define LCD_ROT0L 0
++#define LCD_ROT90L 1
++#define LCD_ROT180L 2
++#define LCD_ROT270L 3
++#define LCD_MIR_ROT0L 10
++#define LCD_MIR_ROT90L 11
++#define LCD_MIR_ROT180L 12
++#define LCD_MIR_ROT270L 13
++
++
++#ifdef TCC79XX
++/*==============================================================================
++ NTSC/PAL Encoder
++ ==============================================================================*/
++
++#define DRV_TVE_MAX_HANDLE 2
++
++// TVE Driver Function Definition
++enum
++{
++ DRV_TVE_FUNC_INIT, // TVE Driver Initialization : Argument = None
++ DRV_TVE_FUNC_PROCESS_INTERRUPT, // Process TVE Interrupt : Argument = None
++
++ DRV_TVE_FUNC_OPEN, // Open Handle : Argument = (*sDRV_TVE)
++ DRV_TVE_FUNC_GETHwTVE, // Get HwTVE Base Address : Argument = (Handle, *sHwTVE)
++ DRV_TVE_FUNC_SETCFG, // Configurate TVE : Argument = (Handle, TVMode)
++
++ DRV_TVE_FUNC_START, // Start Operation : Argument = (Handle)
++ DRV_TVE_FUNC_STOP, // Stop Handle : Argument = (Handle)
++ DRV_TVE_FUNC_CLOSE, // Close Handle : Argument = (Handle)
++
++ DRV_TVE_FUNC_ADJ, //Adjust Video : Argument = (Handle)
++
++ DRV_TVE_FUNC_MAX
++};
++
++// TVE Driver Status Definition
++enum
++{
++ DRV_TVE_STATUS_INVALID, // Not Opened
++ DRV_TVE_STATUS_IDLE, // Openad but Not Activated
++ DRV_TVE_STATUS_PAUSE, // Opened & Activated & Pause
++ DRV_TVE_STATUS_ACTIVE, // Opened & Activated
++ DRV_TVE_STATUS_MAX
++};
++
++// TVE Driver Data Structure
++typedef struct
++{
++ U8 TVMODE; // Output Mode : NTSC or PAL
++ U8 CGMSCTRL; // CGMS Control : ON or OFF
++ U32 CGMSDATA; // CGMS Data : 20 bits
++ U8 CHSTS; // Handle Status
++ sHwTVE *pHwTVE; // Base Address
++} sDRV_TVE;
++
++typedef volatile struct {
++ unsigned VENCON;
++ unsigned VENCIF;
++} sHwTVECON;
++
++// TVE Mode Control Register Definition - ECMDA, ECMDB, ECMDC Register
++#define SET_TVE_MODE_PWDN_ENABLE 0x00000001
++#define SET_TVE_MODE_PWDN_DISABLE 0x00000002
++#define SET_TVE_MODE_FDRST_RELATIONSHIP 0x00000004
++#define SET_TVE_MODE_FDRST_FREERUNNING 0x00000008
++#define SET_TVE_MODE_FSCSEL_NTSC 0x00000010
++#define SET_TVE_MODE_FSCSEL_PALX 0x00000020
++#define SET_TVE_MODE_FSCSEL_PALM 0x00000040
++#define SET_TVE_MODE_FSCSEL_PALCN 0x00000080
++#define SET_TVE_MODE_PEDESTAL_ENABLE 0x00000100
++#define SET_TVE_MODE_PEDESTAL_DISABLE 0x00000200
++#define SET_TVE_MODE_PIXEL_601 0x00000400
++#define SET_TVE_MODE_PIXEL_SQUARE 0x00000800
++#define SET_TVE_MODE_OUTPUT_525LINES 0x00001000
++#define SET_TVE_MODE_OUTPUT_625LINES 0x00002000
++#define SET_TVE_MODE_PHALT_NTSC 0x00004000
++#define SET_TVE_MODE_PHALT_PAL 0x00008000
++
++#define SET_TVE_MODE_VBIBLANK_BLACK 0x00010000
++#define SET_TVE_MODE_VBIBLANK_BYPASS 0x00020000
++#define SET_TVE_MODE_CHROMABW_LOW 0x00040000
++#define SET_TVE_MODE_CHROMABW_MEDIUM 0x00080000
++#define SET_TVE_MODE_CHROMABW_HIGH 0x00100000
++#define SET_TVE_MODE_LUMABW_LOW 0x00200000
++#define SET_TVE_MODE_LUMABW_MEDIUM 0x00400000
++#define SET_TVE_MODE_LUMABW_HIGH 0x00800000
++
++#define SET_TVE_MODE_CSYNC_ENABLE 0x01000000
++#define SET_TVE_MODE_CSYNC_DISABLE 0x02000000
++#define SET_TVE_MODE_CSOUTPUT_CSYNC 0x04000000
++#define SET_TVE_MODE_CSOUTPUT_KEYCLAMP 0x08000000
++#define SET_TVE_MODE_CSOUTPUT_KEYPULSE 0x10000000
++#define SET_TVE_MODE_RGBSYNC_NOSYNC 0x20000000
++#define SET_TVE_MODE_RGBSYNC_RGB 0x40000000
++#define SET_TVE_MODE_RGBSYNC_G 0x80000000
++
++// TVE Clock Generator Register Definition - GLK Register
++#define SET_TVE_GLK_CRYSTAL_27MHZ 0x00000001
++#define SET_TVE_GLK_CRYSTAL_24MHZ 0x00000002
++#define SET_TVE_GLK_RESET_ENABLE 0x00000004
++#define SET_TVE_GLK_RESET_DISABLE 0x00000008
++#define SET_TVE_GLK_SOURCE_INT 0x00000010
++#define SET_TVE_GLK_SOURCE_RTCO 0x00000020
++#define SET_TVE_GLK_SOURCE_CLKI 0x00000040
++#define SET_TVE_GLK_PL_ACTIVELOW 0x00000080
++#define SET_TVE_GLK_PL_ACTIVEHIGH 0x00000100
++
++// TVE DAC Control Register Definition - DACSEL, DACPD Register
++#define SET_TVE_DAC_OUTPUT_CODE0 0x00000001
++#define SET_TVE_DAC_OUTPUT_CVBS 0x00000002
++#define SET_TVE_DAC_PWDN_ENABLE 0x00000004
++#define SET_TVE_DAC_PWDN_DISABLE 0x00000008
++
++// TVE SYNC Control Register Definition - ICNTL Register
++#define SET_TVE_SYNC_ODD_ACTIVELOW 0x00000001
++#define SET_TVE_SYNC_ODD_ACTIVEHIGH 0x00000002
++#define SET_TVE_SYNC_VSYNC_ACTIVELOW 0x00000004
++#define SET_TVE_SYNC_VSYNC_ACTIVEHIGH 0x00000008
++#define SET_TVE_SYNC_HSYNC_ACTIVELOW 0x00000010
++#define SET_TVE_SYNC_HSYNC_ACTIVEHIGH 0x00000020
++#define SET_TVE_SYNC_LATCH_VSFALLING 0x00000040
++#define SET_TVE_SYNC_LATCH_VSRISING 0x00000080
++#define SET_TVE_SYNC_VSOUTOUT_MID 0x00000100
++#define SET_TVE_SYNC_VSOUTOUT_START 0x00000200
++#define SET_TVE_SYNC_ISYNC_FSI 0x00000400
++#define SET_TVE_SYNC_ISYNC_HVFSI 0x00000800
++#define SET_TVE_SYNC_ISYNC_HVSI 0x00001000
++#define SET_TVE_SYNC_ISYNC_VFSI 0x00002000
++#define SET_TVE_SYNC_ISYNC_VSI 0x00004000
++#define SET_TVE_SYNC_ISYNC_ESAV_L 0x00008000
++#define SET_TVE_SYNC_ISYNC_ESAV_FI 0x00010000
++#define SET_TVE_SYNC_ISYNC_FREE 0x00020000
++
++// TVE VBI Control Register Definition - VCTRL Register
++#define SET_TVE_VCTRL_VBICTL_NONE 0x00000001
++#define SET_TVE_VCTRL_VBICTL_10LINE 0x00000002
++#define SET_TVE_VCTRL_VBICTL_1LINE 0x00000004
++#define SET_TVE_VCTRL_VBICTL_2LINE 0x00000008
++#define SET_TVE_VCTRL_CAP_ODD_ENABLE 0x00000010
++#define SET_TVE_VCTRL_CAP_ODD_DISABLE 0x00000020
++#define SET_TVE_VCTRL_CAP_EVEN_ENABLE 0x00000040
++#define SET_TVE_VCTRL_CAP_EVEN_DISABLE 0x00000080
++#define SET_TVE_VCTRL_CGMS_ODD_ENABLE 0x00000100
++#define SET_TVE_VCTRL_CGMS_ODD_DISABLE 0x00000200
++#define SET_TVE_VCTRL_CGMS_EVEN_ENABLE 0x00000400
++#define SET_TVE_VCTRL_CGMS_EVEN_DISABLE 0x00000800
++#define SET_TVE_VCTRL_WSCREEN_ENABLE 0x00001000
++#define SET_TVE_VCTRL_WSCREEN_DISABLE 0x00002000
++
++// TVE Connection and I/F Control Definition - VENCON, VENCIF Register
++#define SET_TVE_CONIF_CON_ENABLE 0x00000001
++#define SET_TVE_CONIF_CON_DISABLE 0x00000002
++#define SET_TVE_CONIF_FMT_CINLSB 0x00000004
++#define SET_TVE_CONIF_FMT_CINMSB 0x00000008
++
++// TVE Setting Value Definition
++enum
++{
++ DRV_TVE_SET_SCH = 0,
++ DRV_TVE_SET_HUE,
++ DRV_TVE_SET_SAT,
++ DRV_TVE_SET_CONT,
++ DRV_TVE_SET_BRIGHT,
++ DRV_TVE_SET_FSC,
++ DRV_TVE_SET_INPUT,
++ DRV_TVE_SET_HOFFSET,
++ DRV_TVE_SET_VOFFSET,
++ DRV_TVE_SET_HSOE,
++ DRV_TVE_SET_HSOB,
++ DRV_TVE_SET_VSOB,
++ DRV_TVE_SET_VSOE,
++ DRV_TVE_SET_VSOST,
++ DRV_TVE_SET_NOVRST
++};
++
++// TVE Input Format Definition
++enum
++{
++ DRV_TVE_INPUT_BW16_27MHZ = 0,
++ DRV_TVE_INPUT_BW16_13P5MHZ,
++ DRV_TVE_INPUT_BW8_13P5MHZ
++};
++
++// TVE Ouput Mode Definition
++enum
++{
++ DRV_TVE_OUTPUT_NTSC = 0,
++ DRV_TVE_OUTPUT_PAL,
++ DRV_TVE_OUTPUT_MAX
++};
++
++// TVE Ouput Mode Definition
++enum
++{
++ DRV_TVE_CGMS_OFF = 0,
++ DRV_TVE_CGMS_ON,
++ DRV_TVE_CGMS_MAX
++};
++
++// TVE Driver Return Value Definition
++#define DRV_TVE_ERROR_YES 1
++#define DRV_TVE_ERROR_NO 0
++#define DRV_TVE_ERROR_OK 0
++enum
++{
++ // Error for Driver State
++ DRV_TVE_ERROR_NOTINIT = (int)0xF9000000, // Non-init Function come before init function
++ DRV_TVE_ERROR_DUPINIT, // Init function called more than twice
++
++ // Error for Input Parameter
++ DRV_TVE_ERROR_INVALID_FUNC, // Function Code is out of range
++ DRV_TVE_ERROR_INVALID_ARGUMENT, // Number of Argument is out of range
++ DRV_TVE_ERROR_INVALID_HANDLE, // Handle value is out of range
++ DRV_TVE_ERROR_INVALID_RESPONSE, // No Response
++
++ // Error for Resource Availability
++ DRV_TVE_ERROR_NOTAVAILABLE_HANDLE, // No available handle
++
++ // Error for Illegal State
++ DRV_TVE_ERROR_INTERNAL, // Internal Bug
++
++ DRV_TVE_ERROR_MAX
++};
++
++extern S32 DRV_TVE(U32 Func, U32 ArgN, ...);
++
++/*==============================================================================
++ AUDIO
++ ==============================================================================*/
++/*---------------------------------------------------------------------
++ DDI_AUD_Set_EQ_FreqVal
++
++Description
++ Fix input equation value to global variable
++Parameters
++ uiFreqValue : input value
++Returns
++ None
++ -----------------------------------------------------------------------*/
++void DDI_AUD_Set_EQ_FreqVal(unsigned int uiFreqValue );
++
++/*---------------------------------------------------------------------
++ DDI_AUD_Get_EQ_FreqVal
++
++Description
++ Get input equation value to global variable
++Parameters
++ None
++Returns
++ uiFreqValue
++ -----------------------------------------------------------------------*/
++unsigned int DDI_AUD_Get_EQ_FreqVal(void);
++
++/*---------------------------------------------------------------------
++ UI_DRV_Get_EQ_FreqVal
++
++Description
++ Get input equation value to global variable
++Parameters
++ None
++Returns
++ uiFreqValue
++ -----------------------------------------------------------------------*/
++unsigned int DDI_AUD_Get_EQBandInst(void);
++
++/**********************************************************
++*
++* Function of
++*
++* DDI_AUD_CopyMono
++*
++* Input : pSrc = pointer of mono PCM data
++ size = size of PCM data
++
++* Output :
++ pLeft = pointer of left output
++ pRight = pointer of right output
++
++* Return : none
++*
++* Description :
++**********************************************************/
++void DDI_AUD_CopyMono( short *pSrc, short *pLeft, short *pRight, unsigned int size );
++
++/**********************************************************
++*
++* Function of
++*
++* DDI_AUD_CopyStereo
++*
++* Input : pSrc = pointer of stero PCM data
++ size = size of PCM data
++
++* Output :
++ pLeft = pointer of left output
++ pRight = pointer of right output
++
++* Return : none
++*
++* Description :
++**********************************************************/
++void DDI_AUD_CopyStereo( short *pSrc, short *pLeft, short *pRight, unsigned int size );
++
++/**********************************************************
++*
++* Function of
++*
++* DDI_AUD_Terminate
++*
++* Input :
++* Output :
++* Return : none
++*
++* Description :
++**********************************************************/
++void DDI_AUD_Terminate(void);
++
++/**********************************************************
++*
++* Function of
++*
++* DDI_AUD_Initialize
++*
++* Input : iSampleFreq = Sampling frequency
++ iChannel = number of audio channel
++* Output :
++* Return : none
++*
++* Description :
++**********************************************************/
++void DDI_AUD_Initialize( int iSampleFreq, int iChannel );
++
++/**********************************************************
++*
++* Function of
++*
++* DDI_AUD_Output
++*
++* Input : pSrc = pointer of PCM data
++ iSize = size of PCM data
++ iChannel = number of audio channel
++
++* Output :
++* Return : none
++*
++* Description :
++**********************************************************/
++void DDI_AUD_Output( short *pSrc, int iSize, int iChannel );
++
++/**********************************************************
++*
++* Function of
++*
++* DDI_AUD_MuteOn
++*
++* Input : none
++* Output : none
++* Return : none
++*
++* Description :
++**********************************************************/
++void DDI_AUD_MuteOn(void);
++
++/**********************************************************
++*
++* Function of
++*
++* DDI_AUD_MuteOff
++*
++* Input : none
++* Output : none
++* Return : none
++*
++* Description :
++**********************************************************/
++void DDI_AUD_MuteOff(void);
++
++/**********************************************************
++*
++* Function of
++*
++* DDI_AUD_SetVolume
++*
++* Input : cVol = value of volume level
++* Output : none
++* Return : none
++*
++* Description :
++**********************************************************/
++void DDI_AUD_SetVolume( unsigned char cVol );
++
++/**********************************************************
++*
++* Function of
++*
++* DDI_AUD_DisableEffect
++*
++* Input : none
++* Output : none
++* Return : none
++*
++* Description :
++**********************************************************/
++void DDI_AUD_DisableEffect(void);
++
++/**********************************************************
++*
++* Function of
++*
++* DDI_AUD_SetEffectEQ
++*
++* Input : iSampleFreq
++ pEqValue = pointer of effect value
++* Output : none
++* Return : none
++*
++* Description :
++**********************************************************/
++void DDI_AUD_SetEffectEQ(unsigned int iSampleFreq );
++
++/*---------------------------------------------------------------------
++ DDI_AUD_ApplyEqualizerMode
++
++Description
++ Set the EQ mode
++Parameters
++ ucEQMode : selected mode by user
++Returns
++ None
++ -----------------------------------------------------------------------*/
++void DDI_AUD_ApplyEqualizerMode(U8 ucEQMode);
++
++/**********************************************************
++*
++* Function of
++*
++* DDI_AUD_SetSrsWow
++*
++* Input : iSampleFreq
++ iSrs = value of SRS effect
++ iWow = value of WOW effect
++* Output : none
++* Return : none
++*
++* Description :
++**********************************************************/
++void DDI_AUD_SetSrsWow( int iSampleFreq, int iSrs, int iWow);
++
++
++/*==============================================================================
++ SMARTCARD
++ ==============================================================================*/
++
++/**********************************************************
++* int DDI_SC_Initialize(void);
++*
++* Input :
++* Output :
++* Return : 0 = initialize successful
++* negative = initialize failed.
++*
++* Description : Initialize SC library & Create SEMA.
++**********************************************************/
++int DDI_SC_Initialize(void);
++
++/**********************************************************
++* int DDI_SC_Open(void);
++*
++* Input :
++* Output :
++* Return : 0 = Open successful, -1 = Open failed.
++*
++* Description : Establish New SC connection.
++**********************************************************/
++int DDI_SC_Open(void);
++
++/**********************************************************
++* int DDI_SC_Close(void);
++*
++* Input :
++* Output :
++* Return : 0 = Close successful
++*
++* Description : Close SC connection.
++**********************************************************/
++int DDI_SC_Close(void);
++
++/**********************************************************
++* int DDI_SC_Reset(void *pATR, unsigned *pATRLength);
++*
++* Input : pATR = pointer for storing ATR string
++* pATRLength = pointer for storing ATR string length
++* Output :
++* Return : 0 = Reset successful
++*
++* Description : Reset SmartCard & Get ATR string.
++**********************************************************/
++int DDI_SC_Reset(void *pATR, unsigned *pATRLength);
++
++/**********************************************************
++* int DDI_SC_SendRcv(void *pSend, unsigned uSendLength, void *pRcv, unsigned uRcvLength);
++*
++* Input : pSend = pointer of command string
++* uSendLength = length of command string
++* pRcv = pointer for storing response string
++* uRcvLength = length of response string.
++* Output :
++* Return : 0 = Send & Receiving is successful.
++* -1 = Response string is not good.
++*
++* Description : Send command string to SmartCard & Receive response string from SmartCard.
++**********************************************************/
++int DDI_SC_SendRcv(void *pSend, unsigned uSendLength, void *pRcv, unsigned uRcvLength);
++
++#endif
++
++#endif
++
++/* end of file */
++
+diff --git a/drivers/block/tcc/inc/tnftl/Typedefine.h b/drivers/block/tcc/inc/tnftl/Typedefine.h
+new file mode 100644
+index 0000000..1c50cc9
+--- /dev/null
++++ b/drivers/block/tcc/inc/tnftl/Typedefine.h
+@@ -0,0 +1,52 @@
++/****************************************************************************
++ * FileName : Typedefine.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++typedef unsigned long UNSIGNED;
++typedef long SIGNED;
++typedef unsigned char DATA_ELEMENT;
++typedef DATA_ELEMENT OPTION;
++typedef DATA_ELEMENT BOOLEAN;
++typedef int STATUS;
++typedef unsigned char UNSIGNED_CHAR;
++#ifndef _CHAR_
++#define _CHAR_
++typedef char CHAR;
++#endif
++typedef unsigned int UNSIGNED_INT;
++typedef int INT;
++typedef unsigned long * UNSIGNED_PTR;
++typedef unsigned char * BYTE_PTR;
++#define VOID void
++
++#ifndef _INT8_
++#define _INT8_
++typedef char INT8;
++#endif
++#ifndef _UINT8_
++#define _UINT8_
++typedef unsigned char UINT8;
++#endif
++#ifndef _INT16_
++#define _INT16_
++typedef signed short INT16;
++#endif
++#ifndef _UINT16_
++#define _UINT16_
++typedef unsigned short UINT16;
++#endif
++#ifndef _INT32_
++#define _INT32_
++typedef signed long INT32;
++#endif
++#ifndef _UINT32_
++#define _UINT32_
++typedef unsigned long UINT32;
++#endif
+diff --git a/drivers/block/tcc/inc/tnftl/kernel_nand_drv.h b/drivers/block/tcc/inc/tnftl/kernel_nand_drv.h
+new file mode 100644
+index 0000000..16d4070
+--- /dev/null
++++ b/drivers/block/tcc/inc/tnftl/kernel_nand_drv.h
+@@ -0,0 +1,138 @@
++/****************************************************************************
++ * FileName : Kernel_nand_drv.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#ifndef __TCC_NDD_H
++#define __TCC_NDD_H
++
++#include "nand_drv.h"
++#include "IO_TCCXXX.h"
++
++//*****************************************************************************
++//*
++//*
++//* [ INTERNAL DEFINATION ]
++//*
++//*
++//*****************************************************************************
++
++//===================================================================
++// IOCTL
++//===================================================================
++#define IOCTL_NDD_GET_INFO _IO(NDD_DEV_MAJOR, 1)
++#define IOCTL_NDD_MULTI_HD_WRITE _IO(NDD_DEV_MAJOR, 2)
++#define IOCTL_NDD_MULTI_HD_READ _IO(NDD_DEV_MAJOR, 3)
++#define IOCTL_NDD_BOOT_WRITE _IO(NDD_DEV_MAJOR, 4)
++#define IOCTL_NDD_HD_WRITE _IO(NDD_DEV_MAJOR, 5)
++#define IOCTL_NDD_HD_READ _IO(NDD_DEV_MAJOR, 6)
++#define IOCTL_NDD_ALIGN_CACHE _IO(NDD_DEV_MAJOR, 7)
++#define IOCTL_NDD_GET_SERIALNUMBER _IO(NDD_DEV_MAJOR, 8)
++
++#define INTR_MODE_NORMAL 0
++#define INTR_MODE_READ_PAGE 1
++#define INTR_MODE_READ_ECC 2
++#define INTR_MODE_WRITE_PAGE 3
++#define INTR_MODE_WRITE_ECC 4
++
++#define NDD_RB_INTR_MODE_NORMAL 0
++#define NDD_RB_INTR_MODE_READ 1
++#define NDD_RB_INTR_MODE_WRITE 2
++
++
++//*****************************************************************************
++//*
++//*
++//* [ INTERNAL STRUCT DEFINE ]
++//*
++//*
++//*****************************************************************************
++typedef struct _nand_priv_data_t
++{
++ struct task_struct *thread;
++ struct request_queue *req;
++ struct scatterlist *sg;
++} nand_priv_data_t;
++
++struct dma_buf
++{
++ void *v_addr;
++ unsigned int dma_addr;
++ int buf_size;
++};
++
++struct ndd_data
++{
++ loff_t i_size;
++};
++
++struct ndd_hidden_info
++{
++ unsigned int DriveNum; // # of multi-hidden area (0~2) - ONLY multi hidden
++ unsigned int HiddenAddress; // start page offset
++ unsigned int SectorNum; // write/read page size
++ unsigned char *DataBuffer; // buffer
++ unsigned int DataBufferSize; // buffer size
++};
++
++struct ndd_boot_info
++{
++ char *buf; // bootloader buffer
++ unsigned int len; // bootloader length
++};
++
++typedef struct __tag_ndd_dev
++{
++ int size;
++ u8 *data;
++ short users;
++ short media_change;
++ struct request_queue *queue;
++ spinlock_t lock;
++ struct gendisk *gd;
++ struct timer_list timer;
++ char *buf;
++ ndd_work_info *nand_work_info;
++}Device;
++
++typedef struct __tag_NAND_intr_info_rb
++{
++ PNFC p_nfc;
++ PGPIO p_gpio;
++ PPIC pPIC;
++ wait_queue_head_t nd_busy_wait_q;
++ int is_nd_busy_complete;
++ int irq;
++ U32 current_nr_sectors;
++ U32 nSectorIndex;
++ U32 nPageIndex;
++ U16 nStartPPage;
++ U16 nReadPPSize;
++ U16 nCurrPPage;
++ U8 intr_mode;
++ U8 *nPageBuffer;
++ U8 *nSpareBuffer;
++ U8 *nEccBuffer;
++ U8 *nStuffPageBuffer;
++ NAND_IO_DEVINFO *nDevInfo;
++ ndd_work_info *nWorkInfo;
++ struct request_queue *request_q;
++ struct request *req;
++} nand_intr_info_rb;
++
++typedef struct __tag_NAND_intr_info
++{
++ PNFC p_nfc;
++ wait_queue_head_t tx_wait_q;
++ wait_queue_head_t rx_wait_q;
++ int is_rx_complete;
++ int is_tx_complete;
++ int irq;
++} nand_intr_info;
++
++#endif
+diff --git a/drivers/block/tcc/inc/tnftl/nand_drv.h b/drivers/block/tcc/inc/tnftl/nand_drv.h
+new file mode 100644
+index 0000000..18b4498
+--- /dev/null
++++ b/drivers/block/tcc/inc/tnftl/nand_drv.h
+@@ -0,0 +1,296 @@
++/****************************************************************************
++ * FileName : nand_drv.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#ifndef __NAND_H
++#define __NAND_H
++
++//#include "main.h"
++
++//**********************************************************************
++//* Define NAND Driver version for ChipSet
++//**********************************************************************
++#if defined(NAND_BOOT_REV)
++#define TNFTL_V7_INCLUDE
++#else // K-FILESYSTEM
++#define TNFTL_V6_INCLUDE
++#endif
++
++//**********************************************************************
++//* Include Header
++//**********************************************************************
++#if defined(_LINUX_) || defined(_WINCE_)
++#if defined(TNFTL_V7_INCLUDE)
++#include "tnftl_v7.h"
++#include "fwupgrade_NAND_v6.h"
++#elif defined(TNFTL_V6_INCLUDE)
++#include "tnftl_v6.h"
++#include "fwupgrade_NAND_v6.h"
++#endif
++#endif
++
++#if defined(USB_INCLUDE) && defined(FWDN_INCLUDE)
++#ifdef TNFTL_V5_INCLUDE
++#include "MASS_SCSI.h"
++#include "VTC.h"
++#include "Fwdn_protocol_v2.h"
++#define TNFTL_DEBUG_INCLUDE
++#else
++#include "fwdn_protocol.h"
++#endif
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ General DEFINE & TYPEDEF ]
++//*
++//*
++//*****************************************************************************
++#ifndef DISABLE
++#define DISABLE 0
++#endif
++#ifndef ENABLE
++#define ENABLE 1
++#endif
++#ifndef FALSE
++#define FALSE 0
++#endif
++#ifndef TRUE
++#define TRUE 1
++#endif
++
++#ifndef _U8_
++#define _U8_
++typedef unsigned char U8;
++#endif
++#ifndef _U16_
++#define _U16_
++typedef unsigned short int U16;
++#endif
++#ifndef _U32_
++#define _U32_
++typedef unsigned int U32;
++#endif
++#ifndef _BOOL_
++#define _BOOL_
++typedef unsigned int BOOL;
++#endif
++
++#ifndef NOT_SUPPORT_NAND
++#define NOT_SUPPORT_NAND 0xFFFF
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ ERROR CODE ENUMERATION ]
++//*
++//*
++//*****************************************************************************
++#ifndef SUCCESS
++#define SUCCESS 0
++#endif
++
++typedef enum
++{
++ ERR_NAND_FAILED_GET_DEVICE_INFO = 0xA300000,
++ ERR_NAND_INIT_FAILED,
++ ERR_NAND_WRONG_PARAMETER
++} NAND_ERROR;
++
++//*****************************************************************************
++//*
++//*
++//* [ INTERNAL DEFINATION ]
++//*
++//*
++//*****************************************************************************
++#define MAX_NAND_DRIVE 1
++#define NAND_DRV_0 0
++
++#if defined( TNFTL_V7_INCLUDE )
++ #define TNFTL_ZONE_NUM_FOR_PRIMARY_PARTITION 32
++ #if defined(_LINUX_) || defined(_WINCE_)
++ #define TNFTL_ZONE_NUM_FOR_EXTENDED_PARTITION 32
++ #else
++ #define TNFTL_ZONE_NUM_FOR_EXTENDED_PARTITION 1
++ #endif
++
++ #define TNFTL_WCACHE_NUM_For_PRIMARY_PARTITION 12
++ #define TNFTL_WCACHE_NUM_For_EXTENDED_PARTITION 2
++
++ #define TNFTL_LPT_BLK_NUM_For_PRIMARY_PARTITION TNFTL_ZONE_NUM_FOR_PRIMARY_PARTITION
++ #define TNFTL_LPT_BLK_NUM_For_EXTENDED_PARTITION TNFTL_ZONE_NUM_FOR_EXTENDED_PARTITION
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ #define TNFTL_EXTENDED_PARTITION_MAX_NUM 4
++ #define TNFTL_EXTENDED_PARTITION_NUM 1
++ #define TNFTL_EXTENDED_PARTITION_SIZE_MB 1
++ #else
++ #ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++ #define TNFTL_EXTENDED_PARTITION_MAX_NUM 1
++ #define TNFTL_EXTENDED_PARTITION_NUM 1
++ #else
++ #define TNFTL_EXTENDED_PARTITION_MAX_NUM 1
++ #define TNFTL_EXTENDED_PARTITION_NUM 0
++ #endif
++ #endif
++#else
++ #define TNFTL_ZONE_NUM_FOR_DATA_AREA 32
++ #if defined(_LINUX_) || defined(_WINCE_)
++ #define TNFTL_ZONE_NUM_FOR_HIDDEN_AREA 32
++ #else
++ #define TNFTL_ZONE_NUM_FOR_HIDDEN_AREA 1
++ #endif
++
++ #if defined( TNFTL_V5_INCLUDE ) || defined(TNFTL_V6_INCLUDE)
++ #define TNFTL_WCACHE_NUM_For_DATA_AREA 12
++ #else
++ #define TNFTL_WCACHE_NUM_For_DATA_AREA 8
++ #endif
++ #define TNFTL_WCACHE_NUM_For_HIDDEN_AREA 2
++
++ #define TNFTL_LPT_BLK_NUM_For_DATA_AREA TNFTL_ZONE_NUM_FOR_DATA_AREA
++ #define TNFTL_LPT_BLK_NUM_For_HIDDEN_AREA TNFTL_ZONE_NUM_FOR_HIDDEN_AREA
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ #define TNFTL_MULTI_HIDDEN_AREA_MAX_NUM 3
++ #define TNFTL_MULTI_HIDDEN_AREA_NUM 3
++ #define INTERNAL_HIDDEN_STORAGE_SIZE_MB 1
++ #else
++ #ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++ #define TNFTL_MULTI_HIDDEN_AREA_MAX_NUM 1
++ #define TNFTL_MULTI_HIDDEN_AREA_NUM 1
++ #else
++ #define TNFTL_MULTI_HIDDEN_AREA_MAX_NUM 1
++ #define TNFTL_MULTI_HIDDEN_AREA_NUM 0
++ #endif
++ #endif
++#endif
++
++#define NAND_DRVINFO_SAVE 0
++#define NAND_DRVINFO_LOAD 1
++
++//===========================================================
++//
++// Common
++//
++//===========================================================
++#define NAND_TYPE_PURE_NAND 0
++#define NAND_TYPE_LBA_NAND 1
++
++#define TNFTL_MAX_SUPPORT_RCACHE_MEMORY_SIZE 32768
++#define TNFTL_MAX_SUPPORT_ALIGNCACHE_MEMORY_SIZE 32768
++
++#define MAX_ROMSIZE_NAND 0x200000
++
++#define NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE 4096
++#define NAND_HIDDEN_DRIVE_DEFAULT_TOTAL_SECTOR_SIZE ((2*1024*1024UL)/512UL)
++
++#define MAX_ROMSIZE_NAND 0x200000
++
++#define TCC_NAND_TRACE_ALL 0x0F
++#define TCC_NAND_TRACE_DRV_WRITE 0x01
++#define TCC_NAND_TRACE_DRV_READ 0x02
++#define TCC_NAND_TRACE_DRV_ALL 0x03
++#define TCC_NAND_TRACE_TNFTL_ALL 0x07
++#define TCC_NAND_TRACE_OFF 0x00
++
++//*****************************************************************************
++//*
++//*
++//* [ INTERNAL STRUCT DEFINE ]
++//*
++//*
++//*****************************************************************************
++typedef struct __tag_NAND_DrvInfo
++{
++ unsigned short int DrvStatus; // Status of Drive
++
++ unsigned long int TotalDiskSector; // Total Disk Sector
++ unsigned short int Cylinder;
++ unsigned short int Head;
++ unsigned char Sector;
++
++ TNFTL_DRVINFO *NFTLDrvInfo; // NFTL Driver
++} NAND_DRVINFO;
++
++#if defined( TNFTL_V7_INCLUDE )
++typedef struct __tag_TNFTL_ExtPartitionSizeInfo
++{
++ unsigned int ExtendedPartitionNum;
++ unsigned int ExtPartitionSize[12];
++ unsigned int ROAreaSize;
++} TNFTL_EXT_PART_INFO;
++#else
++typedef struct __tag_TNFTL_HiddenSizeInfo
++{
++ unsigned int HiddenPageSize; // Default Hidden Area Pages
++ unsigned int MultiHiddenAreaNum; // Multi Hidden Num
++ unsigned int MultiHiddenSize[8]; // Multi Hidden Configuration
++ unsigned int ROAreaSize;
++} TNFTL_HIDDEN_INFO;
++#endif
++
++#if defined( TNFTL_V7_INCLUDE )
++//*****************************************************************************
++//*
++//*
++//* [ EXTERNAL VARIABLE DEFINE ]
++//*
++//*
++//*****************************************************************************
++extern NAND_DRVINFO gNAND_DrvInfo[MAX_NAND_DRIVE];
++extern TNFTL_EXT_PART_INFO gTNFTL_ExtPartitionInfo[MAX_NAND_DRIVE];
++extern NAND_IO_DEVINFO* gLBA_DevInfo[4];
++#else
++extern NAND_DRVINFO gNAND_DrvInfo[MAX_NAND_DRIVE];
++extern TNFTL_HIDDEN_INFO gTNFTL_HiddenInfo[MAX_NAND_DRIVE];
++extern NAND_IO_DEVINFO* gLBA_DevInfo[4];
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ EXTERNAL FUCTIONS DEFINE ]
++//*
++//*
++//*****************************************************************************
++extern void NAND_Init( void );
++extern void NAND_InitHiddenInfo( void );
++extern void NAND_SetFlagOfChangeAreaSize( unsigned char On_Off );
++extern int NAND_LowLevelFormat( int mode );
++
++extern NAND_ERROR NAND_InitDrive( int nDrvNo );
++
++extern int NAND_ReadSector( int nDrvNo, U32 LBA, U32 nSecSize, void* nReadBuffer );
++extern int NAND_WriteSector( int nDrvNo, U32 LBA, U32 nSecSize, void* nWriteBuffer );
++extern int NAND_HDReadPage( U32 nHDPageAddr, U32 nPageSize, void* nReadBuffer );
++extern int NAND_HDWritePage( U32 nHDPageAddr, U32 nPageSize, void* nWriteBuffer );
++extern int NAND_PhyReadPage( U32 nBlkAddr, U16 nPageAddr, U16 nCSorder, void* nReadBuffer );
++extern int NAND_Ioctl( int function, void *param );
++
++extern int NAND_ReadMultiSectorStart( U32 LBA, U32 nSecSize );
++extern int NAND_ReadMultiSectorStop( void );
++extern int NAND_WriteMultiSectorStart( U32 LBA, U32 nSecSize );
++extern int NAND_WriteMultiSectorStop( void );
++extern int NAND_HDClearPages( U32 nHDStPageAddr, U32 nHDEdPageAddr );
++
++extern int NAND_ReadSectorIRQ( int nDrvNo, ndd_work_info* nand_work_info );
++extern int NAND_WriteSectorIRQ( int nDrvNo, ndd_work_info* nand_work_info );
++extern int NAND_HDReadSector( int nDrvNo, U32 LBA, U32 nSecSize, void* nReadBuffer );
++extern int NAND_HDWriteSector( int nDrvNo, U32 LBA, U32 nSecSize, void* nWriteBuffer );
++extern int NAND_HDIoctl( int function, void *param );
++
++extern U16 NAND_GetSerialNumber( U8* rSerialNumber, U16 nSize );
++extern U16 NAND_GetUniqueID( U8* rSerialNumber, U16 nSize );
++extern TNFTL_ERROR NAND_SetUartDebug( unsigned int on_off );
++#endif
++
+diff --git a/drivers/block/tcc/inc/tnftl/nand_io_v6.h b/drivers/block/tcc/inc/tnftl/nand_io_v6.h
+new file mode 100644
+index 0000000..aab4abf
+--- /dev/null
++++ b/drivers/block/tcc/inc/tnftl/nand_io_v6.h
+@@ -0,0 +1,828 @@
++/**************************************************************************************
++ *
++ * TELECHIPS Co.
++ *
++ * 6th floor Corad Bldg 1000-12 Daechi-dong, KangNam-ku, Seoul, Korea
++ * ====================================================================================
++ *
++ * Name: Hyun-Chul Hong
++ * Phone: 82-2-3443-6792
++ * E-mail: hchong@telechips.com
++ *
++ * FILE NAME: NAND_IO.H
++ *
++ * DESCRIPTION:
++ * This is a Header File for NANDFLASH IO Interface
++ *
++ *
++ * FILE HISTORY:
++ * Date: 2005.04.19 Start source coding By Hyunchul Hong
++ *
++ **************************************************************************************/
++#ifndef __NAND_IO_H
++#define __NAND_IO_H
++
++//*****************************************************************************
++//*
++//*
++//* [ Specific DEFINE ]
++//*
++//*
++//*****************************************************************************
++#if defined(TCC83XX) && defined(_WINCE_)
++// In the case of LINUX, it is defined config.h
++#define NAND_2CS_ONLY
++#define NAND_8BIT_ONLY
++#else
++//#define NAND_2CS_ONLY
++//#define NAND_8BIT_ONLY
++#endif
++
++//**********************************************************************
++//* Define Dev Board
++//**********************************************************************
++//#define TCC9200S_BOARD // TCC9200S ND_RDY: GPIO_B31
++#define TCC89_92_BOARD // TCC89/91/9200 ND_RDY: GPIO_B28 - EDI - NFC_CTRL
++
++//**********************************************************************
++//* Define ECC Algorithm for ChipSet
++//**********************************************************************
++#if defined(TCC77X) || defined(TCC87XX) || defined(TCC82XX) || defined(TCC78X) || defined(TCC83XX) || defined(TCC79XX)
++#define ECC_TYPE_RS
++#elif defined(TCC81XX) || defined(TCC80XX) || defined(TCC92XX) || defined(TCC89XX)
++#define ECC_TYPE_BCH
++#endif
++
++#if defined(USE_V_ADDRESS)
++ #if defined(_LINUX_)
++ #define ND_TRACE printk
++ #elif defined(_WINCE_)
++ //#define ND_TRACE(a) RETAILMSG(1, a)
++ //#define ND_TRACE2(a) NKDbgPrintfW(a)
++ #endif
++#else
++ #if defined(_LINUX_)
++ #define ND_TRACE printf
++ #elif defined(_WINCE_)
++ #define ND_TRACE B_RETAILMSG
++ #endif
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ General DEFINE & TYPEDEF ]
++//*
++//*
++//*****************************************************************************
++//===================================================================
++//
++// DRIVER SIGNATURE
++//
++//===================================================================
++#define SIGBYAHONG 'S','I','G','B','Y','A','H','O','N','G','_'
++
++#define NAND_IO_SIGNATURE 'N','A','N','D','_','I','O','_'
++#define TNFTL_SIGNATURE 'T','N','F','T','L','_'
++
++#if defined(_WINCE_)
++#define SIGN_OS 'W','I','N','C','E','_'
++#elif defined(_LINUX_)
++#define SIGN_OS 'L','I','N','U','X','_'
++#else
++#define SIGN_OS 'N','U','_'
++#endif
++
++#if defined(TCC77X)
++#define SIGN_CHIPSET 'T','C','C','7','7','X','X','_'
++#elif defined(TCC78X)
++#define SIGN_CHIPSET 'T','C','C','7','8','X','X','_'
++#elif defined(TCC79X)
++#define SIGN_CHIPSET 'T','C','C','7','9','X','X','_'
++#elif defined(TCC81XX)
++#define SIGN_CHIPSET 'T','C','C','8','1','X','X','_'
++#elif defined(TCC82XX)
++#define SIGN_CHIPSET 'T','C','C','8','2','X','X','_'
++#elif defined(TCC83XX)
++#define SIGN_CHIPSET 'T','C','C','8','3','X','X','_'
++#elif defined(TCC87XX)
++#define SIGN_CHIPSET 'T','C','C','8','7','X','X','_'
++#elif defined(TCC89XX)
++#define SIGN_CHIPSET 'T','C','C','8','9','X','X','_'
++#elif defined(TCC91XX)
++#define SIGN_CHIPSET 'T','C','C','9','1','X','X','_'
++#elif defined(TCC92XX)
++#define SIGN_CHIPSET 'T','C','C','9','2','X','X','_'
++#else
++#error
++#endif
++
++#ifndef DISABLE
++#define DISABLE 0
++#endif
++#ifndef ENABLE
++#define ENABLE 1
++#endif
++#ifndef FALSE
++#define FALSE 0
++#endif
++#ifndef TRUE
++#define TRUE 1
++#endif
++#ifndef NULL
++#define NULL 0
++#endif
++
++#if defined(_LINUX_)
++#ifndef _U8_
++#define _U8_
++typedef unsigned char U8;
++#endif
++#ifndef _U16_
++#define _U16_
++typedef unsigned short int U16;
++#endif
++#ifndef _U32_
++#define _U32_
++typedef unsigned int U32;
++#endif
++#ifndef _BOOL_
++#define _BOOL_
++typedef unsigned int BOOL;
++#endif
++#else
++#ifndef U8
++typedef unsigned char U8;
++#endif
++#ifndef U16
++typedef unsigned short int U16;
++#endif
++#ifndef U32
++typedef unsigned int U32;
++#endif
++#ifndef _BOOL_
++typedef unsigned int BOOL;
++#endif
++#endif
++
++#ifndef DWORD_BYTE
++typedef union {
++ unsigned long DWORD;
++ unsigned short int WORD[2];
++ unsigned char BYTE[4];
++} DWORD_BYTE;
++#endif
++
++#ifndef BITSET
++#define BITSET(X, MASK) ( (X) |= (U32)(MASK) )
++#endif
++#ifndef BITSCLR
++#define BITSCLR(X, SMASK, CMASK) ( (X) = ((((U32)(X)) | ((U32)(SMASK))) & ~((U32)(CMASK))) )
++#endif
++#ifndef BITCSET
++#define BITCSET(X, CMASK, SMASK) ( (X) = ((((U32)(X)) & ~((U32)(CMASK))) | ((U32)(SMASK))) )
++#endif
++#ifndef BITCLR
++#define BITCLR(X, MASK) ( (X) &= ~((U32)(MASK)) )
++#endif
++#ifndef BITXOR
++#define BITXOR(X, MASK) ( (X) ^= (U32)(MASK) )
++#endif
++#ifndef ISZERO
++#define ISZERO(X, MASK) ( ! (((U32)(X)) & ((U32)(MASK))) )
++#endif
++#ifndef BYTE_OF
++#define BYTE_OF(X) ( *(volatile unsigned char *)(&(X)) )
++#endif
++#ifndef HWORD_OF
++#define HWORD_OF(X) ( *(volatile unsigned short *)(&(X)) )
++#endif
++#ifndef WORD_OF
++#define WORD_OF(X) ( *(volatile unsigned int *)(&(X)) )
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ ERROR CODE ENUMERATION ]
++//*
++//*
++//*****************************************************************************
++#ifndef SUCCESS
++#define SUCCESS 0
++#endif
++
++typedef enum
++{
++ ERR_NAND_IO_FAILED_GET_DEVICE_INFO = 0xA100000,
++ ERR_NAND_IO_FAILED_CORRECTION_SLC_ECC,
++ ERR_NAND_IO_FAILED_CORRECTION_MLC_ECC,
++ ERR_NAND_IO_FAILED_GET_SHIFT_FACTOR_FOR_MULTIPLY,
++ ERR_NAND_IO_FAILED_GET_FACTORY_BAD_MARK_OF_PBLOCK,
++ ERR_NAND_IO_READ_STATUS_GENERAL_FAIL,
++ ERR_NAND_IO_TIME_OUT_READ_STATUS,
++ ERR_NAND_IO_WRONG_PARAMETER,
++ ERR_NAND_IO_WRONG_PARAMETER_ROW_COL_ADDRESS,
++ ERR_NAND_IO_NOT_READY_DEVICE_IO,
++ ERR_NAND_IO_FAILED_WRITE,
++ ERR_NAND_IO_NOT_EXIST_LBA_HEADBLOCK,
++ ERR_NAND_IO_FAILED_LBA_PARTITION_CHANGE
++} NAND_IO_ERROR;
++
++//*****************************************************************************
++//*
++//*
++//* [ INTERNAL DEFINATION ]
++//*
++//*
++//*****************************************************************************
++
++/* Maker Information of supported NANDFLASH */
++enum SUPPORT_MAKER_NAND
++{
++ SAMSUNG = 0,
++ TOSHIBA,
++ HYNIX,
++ ST,
++ MICRON,
++ MAX_SUPPORT_MAKER_NAND
++};
++
++enum SUPPORT_MAKER_LBA_NAND
++{
++ TOSHIBA_LBA = 0,
++ MAX_SUPPORT_MAKER_LBA_NAND
++};
++
++enum LBA_NAND_HIDDEN_INFO
++{
++ //==============================================
++ // VFP Size [ 4Byte ] 0
++ // MDP Size [ 4Byte ] 1
++ // Hidden Size [ 4Byte ] 2
++ // Multi-Hidden Num [ 4Byte ] 3
++ // Multi-Hidden Size[ 4Byte ] 4~10
++ //==============================================
++ ENUM_LBA_VFP_SECTOR_SIZE = 0,
++ ENUM_LBA_MDP_SECTOR_SIZE,
++ ENUM_LBA_HIDDEN_SECTOR_SIZE,
++ ENUM_LBA_MULTI_HIDDEN_NUM,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_0,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_1,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_2,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_3,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_4,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_5,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_6,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_7,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_8,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_9
++};
++
++#define SAMSUNG_NAND_MAKER_ID 0xEC
++#define TOSHIBA_NAND_MAKER_ID 0x98
++#define HYNIX_NAND_MAKER_ID 0xAD
++#define ST_NAND_MAKER_ID 0x20
++#define MICRON_NAND_MAKER_ID 0x2C
++
++#define MAX_SUPPORT_SAMSUNG_NAND 24
++#define MAX_SUPPORT_TOSHIBA_NAND 16
++#define MAX_SUPPORT_HYNIX_NAND 23
++#define MAX_SUPPORT_ST_NAND 13
++#define MAX_SUPPORT_MICRON_NAND 10
++
++/* LBA NAND FLASH */
++#define MAX_SUPPORT_TOSHIBA_LBA_NAND 3
++
++/* Media Attribute */
++#define A_08BIT 0x00000001 // 8Bit BUS
++#define A_BIG 0x00000002 // Big Page Size
++#define A_SMALL 0x00000004 // Small Page Size
++#define A_16BIT 0x00000008 // 16Bit BUS
++#define A_SLC 0x00000010 // Single Layer Cell
++#define A_MLC 0x00000020 // Multi Layer Cell
++#define A_MLC_8BIT 0x00000040 // 8Bit MLC ECC
++#define A_MLC_12BIT 0x00000080 // 12Bit MLC ECC
++
++#define A_PARALLEL 0x00000100 // Parallel Composition
++#define A_DATA_WITDH_08BIT 0x00000200 // Data 8Bit Bus
++#define A_DATA_WITDH_16BIT 0x00000400 // Data 16Bit Bus
++
++#define S_NOR 0x00010000 // NORMAL [ ReadID, Reset, Read, Page Program, Block Erase, Read Status ]
++#define S_CB 0x00020000 // COPY BACK
++#define S_CP 0x00040000 // CACHE PROGRAM
++#define S_MP 0x00080000 // MULTI PLANE
++#define S_MP2 0x00100000 // MULTI PLANE
++#define S_MCP 0x00200000 // MULTI PLANE CACHE
++#define S_IL 0x00400000 // INTER LEAVE
++#define S_EIL 0x00800000 // EXTERNAL INTER LEAVE
++#define S_EPW 0x01000000 // EXCEPT PARTIAL WRITE
++#define S_NPW 0x02000000 // Not-Support PARTIAL WRITE
++#define S_MP_READ 0x04000000 // MULTI PLANE READ
++#define S_LBA 0x08000000 // LBA NAND
++
++#define NAND_IO_MAX_SUPPORT_DRIVER 2
++
++#define NAND_IO_SERIAL_COMBINATION_MODE 0x00
++#define NAND_IO_PARALLEL_COMBINATION_MODE 0x01
++
++#if defined(NAND_2CS_ONLY)
++#define NAND_IO_DRV0_START_CS 0
++#define NAND_IO_DRV0_END_CS 1
++#else
++#define NAND_IO_DRV0_START_CS 0
++#define NAND_IO_DRV0_END_CS 3
++#endif
++
++#define ECC_OFF 0
++#define ECC_ON 1
++#define SLC_ECC_TYPE 0x0001 // 10 Byte
++#define MLC_ECC_4BIT_TYPE 0x0002 // BCH: 7 Byte( 52 bit) turn: 2, byte remain: 3, register mask: 0x0F
++#define MLC_ECC_8BIT_TYPE 0x0004 // BCH:13 Byte (104 bit) turn: 4, byte remain: 1, register mask: 0xFF
++#define MLC_ECC_12BIT_TYPE 0x0010 // BCH:20 Byte (156 bit) turn: 5, byte remain: 4, register mask: 0x0F
++#define MLC_ECC_14BIT_TYPE 0x0020 // BCH:23 Byte (184 bit) turn: 6, byte remain: 3, register mask: 0xFF
++#define MLC_ECC_16BIT_TYPE 0x0040 // BCH:26 Byte (207 bit)turn: 7, byte remain: 2, register mask: 0x7F
++
++//----------------------------------------------------------------------
++// TNFTL R/W Area Spare Date
++//----------------------------------------------------------------------
++// Block Area & Type 1Byte : 0xFF
++// Block Parameter 2Byte
++// Logical Block Address 3Byte : 0x0 ~ 0xFFFFFE
++//----------------------------------------------------------------------
++// Spare Data Total 6Byte
++//----------------------------------------------------------------------
++
++//----------------------------------------------------------------------
++// TNFTL R/O Area Spare Date
++//----------------------------------------------------------------------
++// Block Area & Type 1Byte : 0xFF
++// Rom Image Num 2Byte
++// Rom Image LBA 3Byte : 0x0 ~ 0xFFFFFE
++//----------------------------------------------------------------------
++// Spare Data Total 6Byte
++//----------------------------------------------------------------------
++
++
++// 512 Page + 16 Spare : SLC / 4 Bit ECC
++typedef struct {
++ U8 SpareData0[4]; // 4 Bytes Spare data
++ U8 Temp; // 1 Bytes Temp
++ U8 BadMark; // 1 Bytes bad mark
++ U8 SpareData1[2]; // 2 Bytes Spare data
++ U8 PageECC[8]; // 8 Bytes Spare ECC --> 4Bit ECC
++} SLC_512Page_4BitECC_Spare;
++
++// 2048 Page + 64 Spare : 4 Bit ECC
++typedef struct {
++ U8 BadMark; // 1 Bytes bad mark
++ U8 Temp; // 1 Bytes Temp
++ U8 SpareECC[10]; // 8 Bytes Spare ECC --> 4Bit ECC
++ U8 SpareData[12]; // 12 bytes Spare data
++ U8 PageECC[4][10]; // 40 Bytes Page ECC
++} MLC_2KPage_4BitECC_Spare;
++
++// 4096 Page + 128 Spare : 4 Bit ECC
++typedef struct {
++ U8 BadMark; // 1 Bytes bad mark
++ U8 Temp; // 1 Bytes Temp
++ U8 SpareECC[10]; // 10 Bytes Spare ECC --> 4Bit ECC
++ U8 SpareData[20]; // 20 bytes Spare data
++ U8 PageECC[8][10]; // 80 Bytes Page ECC
++} MLC_4KPage_4BitECC_Spare;
++
++// 4096 Page + 218 Spare : 8/12 Bit ECC
++typedef struct {
++ U8 BadMark; // 1 Bytes bad mark
++ U8 Temp; // 1 Bytes Temp
++ U8 SpareECC[20]; // 20 Bytes Spare ECC --> 8 / 12 Bit ECC
++ U8 SpareData[36]; // 36 bytes Spare data
++ U8 PageECC[8][20]; //160 Bytes Page ECC
++} MLC_4KPage_8_12BitECC_Spare;
++
++// 8192 Page + 436 Spare : 16 Bit ECC
++typedef struct {
++ U8 BadMark; // 1 Bytes bad mark
++ U8 Temp; // 1 Bytes Temp
++ U8 SpareECC[8]; // 8 Bytes Spare ECC --> 4 bit ECC
++ U8 SpareData[10]; // 10 bytes Spare data
++ U8 PageECC[16][26]; //416 Bytes Page ECC
++} MLC_4KPage_16BitECC_Spare;
++
++#ifdef ECC_TYPE_RS
++#define TYPE_ECC_FOR_1BIT_SLC_NANDFLASH MLC_ECC_4BIT_TYPE
++#define TYPE_ECC_FOR_4BIT_MLC_NANDFLASH MLC_ECC_4BIT_TYPE
++#define TYPE_ECC_FOR_8BIT_MLC_NANDFLASH MLC_ECC_8BIT_TYPE
++#define ECC_SHIFT_DATASIZE 16
++#else
++#define TYPE_ECC_FOR_1BIT_SLC_NANDFLASH MLC_ECC_4BIT_TYPE
++#define TYPE_ECC_FOR_4BIT_MLC_NANDFLASH MLC_ECC_4BIT_TYPE
++#define TYPE_ECC_FOR_8BIT_MLC_NANDFLASH MLC_ECC_12BIT_TYPE
++#define TYPE_ECC_FOR_12BIT_MLC_NANDFLASH MLC_ECC_12BIT_TYPE
++#define TYPE_ECC_FOR_14BIT_MLC_NANDFLASH MLC_ECC_14BIT_TYPE
++#define TYPE_ECC_FOR_16BIT_MLC_NANDFLASH MLC_ECC_16BIT_TYPE
++#define ECC_SHIFT_DATASIZE 4
++#endif
++
++#define TNFTL_READ_SPARE_ON 0
++#define TNFTL_READ_SPARE_OFF 1
++
++#define NAND_MCU_ACCESS 0
++#define NAND_DMA_ACCESS 1
++
++#define NAND_NORMAL_BUFFER 0
++#define NAND_SERIAL_CHAIN_BUFFER 1
++
++
++#define ECC_DECODE 0
++#define ECC_ENCODE 1
++#define INTER_LEAVE_OFF 0
++#define INTER_LEAVE_ON 1
++#define MULTI_PLANE_MID_PAGE 0
++#define MULTI_PLANE_LAST_PAGE 1
++#define MULTI_PLANE_GOOD_BLOCK 0
++#define MULTI_PLANE_BAD_BLOCK 1
++
++#define NAND_IO_BSA_OK 0x0000
++#define NAND_IO_BSA_BAD_SERIAL 0x0001
++#define NAND_IO_BSA_BAD_BLOCK1_PARALLEL 0x0010
++#define NAND_IO_BSA_BAD_BLOCK2_PARALLEL 0x0100
++#define NAND_IO_BSA_FAIL_OTHER_REASON 0x1000
++
++#define NAND_IO_STATUS_FAIL_CS0_SERIAL 0x0001
++#define NAND_IO_STATUS_FAIL_CS0_PARALLEL 0x0010
++#define NAND_IO_STATUS_FAIL_CS1_PARALLEL 0x0100
++
++#define NAND_IO_LOG_COLUMN_IN_PAGE 0
++#define NAND_IO_LOG_COLUMN_IN_SPARE 1
++
++/* LBA NAND DEFINATION : [STATUS READ 2] */
++#define NAND_LBA_PNP 0x00
++#define NAND_LBA_BCM 0x02
++#define NAND_LBA_VFP 0x04
++#define NAND_LBA_MDP 0x06
++
++#define NAND_LBA_DATA_AREA 0x16
++#define NAND_LBA_HIDDEN_AREA 0x26
++#define NAND_LBA_MULTI_HIDDEN_AREA_0 0x36
++#define NAND_LBA_MULTI_HIDDEN_AREA_1 0x46
++#define NAND_LBA_MULTI_HIDDEN_AREA_2 0x56
++
++#define NAND_POWER_SAVE_ENABLE 0x01
++#define NAND_HIGH_SPEED_ENABLE 0x08
++
++#define NAND_ADDRESS_OUT_OF_RANGE_ERROR 0x10
++#define NAND_COMMAND_PARAMETER_ERROR 0x40
++
++/* LBA NAND Transfer Protocol 1 */
++#define NAND_PROT1_512x1 0x01
++#define NAND_PROT1_512x4 0x02
++#define NAND_PROT1_512x8 0x04
++
++#define NAND_PROT1_528x1 0x21
++#define NAND_PROT1_528x4 0x22
++#define NAND_PROT1_528x8 0x24
++
++#define NAND_PROT1_SPARE_INCLUDE 0x20
++#define NAND_PROT1_SECTOR_COUNT_MASK 0x07
++
++#define NAND_PROT1_NoCRC_NoECC 0x00
++#define NAND_PROT1_CRC 0x40
++#define NAND_PROT1_ECC_CHECK_ONLY 0x80
++#define NAND_PROT1_ECC_CORRECT 0xC0
++
++/* LBA NAND Transfer Protocol 2 */
++#define NAND_PROT2_READ_TYPE_A 0x00
++#define NAND_PROT2_READ_TYPE_B 0x02
++#define NAND_PROT2_READ_TYPE_C 0x03
++
++#define NAND_PROT2_WRITE_TYPE_A 0x00
++#define NAND_PROT2_WRITE_TYPE_B 0x04
++
++#define NAND_LBA_MAX_SUPPORT_MHD_AREA_NUM 10
++
++typedef void (*NAND_LBA_CALLBACK_HANDLER) ( U16 nDrvNo, U16 nStatusCode, U32 wParam );
++#define NAND_LBA_CALLBACK_LCD_FORMAT_PROCESS 0x04
++
++
++/* HardWare relevant variables */
++#define PAGE_ECC_OFF 0
++#define PAGE_ECC_ON 1
++
++#define NAND_IO_SPARE_SIZE_BIG 32
++#define NAND_IO_SPARE_SIZE_SMALL 8
++
++#define NAND_IO_NFC_BUS 0
++#define NAND_IO_MEM_BUS 1
++
++#define NAND_IO_DATA_WITDH_8BIT 0
++#define NAND_IO_DATA_WITDH_16BIT 1
++
++#if 0 /* 09.03.16 */
++#if defined(_LINUX_) || defined(_WINCE_)
++ #ifdef USE_V_ADDRESS
++ #if defined(_LINUX_)
++ #define NAND_IO_HwCMD *(volatile unsigned long*)0xF00B0000 //( gNAND_IO_pHwND->CMD )
++ #define NAND_IO_HwLADR *(volatile unsigned long*)0xF00B0004 //( gNAND_IO_pHwND->LADR )
++ #define NAND_IO_HwDATA *(volatile unsigned long*)0xF00B0010 //( gNAND_IO_pHwND->WDATA.D32 )
++ #define NAND_IO_HwSDATA *(volatile unsigned long*)0xF00B0040 //(/*( gNAND_IO_DataBusType == NAND_IO_MEM_BUS ) ? gNAND_IO_pHwND->WDATA.D8 : */gNAND_IO_pHwND->SDATA.D32 )
++ #define NAND_IO_HwSADR *(volatile unsigned long*)0xF00B000C //( gNAND_IO_pHwND->SADR )
++ #define NAND_IO_HwECCBASEPAGE 0xF00B0010 //((unsigned)&NAND_IO_HwDATA)
++ #elif defined(_WINCE_)
++ #define NAND_IO_HwCMD *(volatile unsigned long*)0xB00B0000 //( gNAND_IO_pHwND->CMD )
++ #define NAND_IO_HwLADR *(volatile unsigned long*)0xB00B0004 //( gNAND_IO_pHwND->LADR )
++ #define NAND_IO_HwDATA *(volatile unsigned long*)0xB00B0010 //( gNAND_IO_pHwND->WDATA.D32 )
++ #define NAND_IO_HwSDATA *(volatile unsigned long*)0xB00B0040 //(/*( gNAND_IO_DataBusType == NAND_IO_MEM_BUS ) ? gNAND_IO_pHwND->WDATA.D8 : */gNAND_IO_pHwND->SDATA.D32 )
++ #define NAND_IO_HwSADR *(volatile unsigned long*)0xB00B000C //( gNAND_IO_pHwND->SADR )
++ #define NAND_IO_HwECCBASEPAGE 0xF00B0010 //((unsigned)&NAND_IO_HwDATA)
++ #endif
++ #else // MAKEBOOTLOADER
++ #define NAND_IO_HwCMD *(volatile unsigned long*)0xF00B0000 //( gNAND_IO_pHwND->CMD )
++ #define NAND_IO_HwLADR *(volatile unsigned long*)0xF00B0004 //( gNAND_IO_pHwND->LADR )
++ #define NAND_IO_HwDATA *(volatile unsigned long*)0xF00B0010 //( gNAND_IO_pHwND->WDATA.D32 )
++ #define NAND_IO_HwSDATA *(volatile unsigned long*)0xF00B0040 //(/*( gNAND_IO_DataBusType == NAND_IO_MEM_BUS ) ? gNAND_IO_pHwND->WDATA.D8 : */gNAND_IO_pHwND->SDATA.D32 )
++ #define NAND_IO_HwSADR *(volatile unsigned long*)0xF00B000C //( gNAND_IO_pHwND->SADR )
++ #define NAND_IO_HwECCBASEPAGE 0xF00B0010 //((unsigned)&NAND_IO_HwDATA)
++ #endif
++#else
++ #define NAND_IO_HwNFC_CMD ( gNAND_IO_pHwNFC->NFC_CMD ) // 0x000 W NAND Flash Command Register
++ #define NAND_IO_HwNFC_LADDR ( gNAND_IO_pHwNFC->NFC_LADDR ) // 0x004 W NAND Flash Linear Address Register
++ #define NAND_IO_HwNFC_BADDR ( gNAND_IO_pHwNFC->NFC_BADDR ) // 0x008 W NAND Flash Block Address Register
++ #define NAND_IO_HwNFC_SADDR ( gNAND_IO_pHwNFC->NFC_SADDR ) // 0x00C W NAND Flash Signal Address Register
++ #define NAND_IO_HwNFC_WDATA ( gNAND_IO_pHwNFC->NFC_WDATA[0] ) // 0x01x R/W NAND Flash Word Data Register
++ #define NAND_IO_HwNFC_LDATA ( gNAND_IO_pHwNFC->NFC_LDATA[0] ) // 0x02x/3x R/W NAND Flash Linear Data Register
++ #define NAND_IO_HwNFC_SDATA ( gNAND_IO_pHwNFC->NFC_SDATA ) // 0x040 R/W NAND Flash Single Data Register
++ #define NAND_IO_HwNFC_CTRL ( gNAND_IO_pHwNFC->NFC_CTRL ) // 0x050 R/W NAND Flash Control Register
++ #define NAND_IO_HwNFC_PSTART ( gNAND_IO_pHwNFC->NFC_PSTART ) // 0x054 W NAND Flash Program Start Register
++ #define NAND_IO_HwNFC_RSTART ( gNAND_IO_pHwNFC->NFC_RSTART ) // 0x058 W NAND Flash Read Start Register
++ #define NAND_IO_HwNFC_DSIZE ( gNAND_IO_pHwNFC->NFC_DSIZE ) // 0x05C R/W NAND Flash Data Size Register
++ #define NAND_IO_HwNFC_IREQ ( gNAND_IO_pHwNFC->NFC_IREQ ) // 0x060 R/W NAND Flash Interrupt Request Register
++ #define NAND_IO_HwNFC_RST ( gNAND_IO_pHwNFC->NFC_RST ) // 0x064 W NAND Flash Controller Reset Register
++ #define NAND_IO_HwNFC_CTRL1 ( gNAND_IO_pHwNFC->NFC_CTRL1 ) // 0x068 R/W NAND Flash Control Register 1
++ #define NAND_IO_HwNFC_MDATA ( gNAND_IO_pHwNFC->NFC_MDATA[0] ) // 0x07x R/W NAND Flash Multiple Data Register
++ #define NAND_IO_HwECCBASEPAGE ((unsigned)&NAND_IO_HwNFC_WDATA)
++#endif
++#endif /* 0 */
++
++
++#if defined(_LINUX_) || defined(_WINCE_)
++#if defined(TCC89XX) || defined(TCC92XX)
++#define NAND_IO_HwCMD_PA *(volatile unsigned long*)0xF05B0000 //( gNAND_IO_pHwND->CMD )
++#define NAND_IO_HwLADR_PA *(volatile unsigned long*)0xF05B0004 //( gNAND_IO_pHwND->LADR )
++#define NAND_IO_HwDATA_PA *(volatile unsigned long*)0xF05B0010 //( gNAND_IO_pHwND->WDATA.D32 )
++#define NAND_IO_HwLDATA_PA *(volatile unsigned long*)0xF05B0020 //( gNAND_IO_pHwND->LDATA )
++#define NAND_IO_HwSDATA_PA *(volatile unsigned long*)0xF05B0040 //(/*( gNAND_IO_DataBusType == NAND_IO_MEM_BUS ) ? gNAND_IO_pHwND->WDATA.D8 : */gNAND_IO_pHwND->SDATA.D32 )
++#define NAND_IO_HwSADR_PA *(volatile unsigned long*)0xF05B000C //( gNAND_IO_pHwND->SADR )
++#endif
++#endif
++
++#if defined(TCC92XX)
++#define NAND_IO_NFC_nWP HwGPIOB->GPDAT
++#define NAND_IO_NFC_nWPBit Hw22
++#elif defined(TCC89XX)
++#define NAND_IO_NFC_nWP HwGPIOB->GPDAT
++#define NAND_IO_NFC_nWPBit Hw31
++#endif
++#define NAND_IO_STATUS_ENABLE 0x0001
++#define NAND_IO_STATUS_INTERLEAVING_MASK 0x00F0
++#define NAND_IO_STATUS_INTERLEAVING_CHIP1 0x0010
++#define NAND_IO_STATUS_INTERLEAVING_CHIP2 0x0020
++#define NAND_IO_STATUS_INTERLEAVING_CHIP3 0x0040
++#define NAND_IO_STATUS_INTERLEAVING_CHIP4 0x0080
++
++#define NAND_IO_DISTRICT_0 0x0001
++#define NAND_IO_DISTRICT_1 0x0002
++
++#define NAND_IO_DMA_WRITE 0x0001
++#define NAND_IO_DMA_READ 0x0002
++//*****************************************************************************
++//*
++//*
++//* [ INTERNAL STRUCT DEFINE ]
++//*
++//*
++//*****************************************************************************
++typedef struct __tag_NAND_IO_ECCSizeInfo
++{
++ unsigned int EncodeFlag;
++ unsigned int DecodeFlag;
++ unsigned int ErrorNum;
++ unsigned char ErrorCodeNum; // Register Num
++ unsigned char *All_FF_512_ECC_Code;
++} NAND_IO_ECC_INFO;
++
++typedef struct __tag_NAND_IO_WriteStatus
++{
++ unsigned char ChipNo;
++ unsigned char BlockStatus;
++ unsigned int ErrorPHYPageAddr;
++} NAND_IO_WRITESTATUS;
++
++typedef struct __tag_NAND_IO_BadBlockAddr
++{
++ unsigned char BlockStatus[4];
++ unsigned int BadBlkPHYAddr[4];
++} NAND_IO_BADBLOCK;
++
++typedef struct __tag_NAND_IO_Cycle
++{
++ unsigned char STP;
++ unsigned char PW;
++ unsigned char HLD;
++ unsigned int RegValue;
++} NAND_IO_CYCLE;
++
++typedef struct __tag_NAND_IO_DeviceCode
++{
++ unsigned short int Code[6]; // Factory ID code
++} NAND_IO_DEVID;
++
++typedef struct __tag_NAND_IO_LBADevInfo
++{
++ unsigned char Usable;
++
++ unsigned char CurrentMode;
++ unsigned long int CurrentSectorSize;
++
++ unsigned char HighSpeedMode;
++ unsigned char PowerSaveMode;
++ unsigned char TransProtocol1;
++ unsigned char TransProtocol2;
++ unsigned char SectorCount;
++ unsigned char DataTransferCheck;
++ unsigned char FlagOfChangeTotalSectorSize;
++
++ unsigned long int VFPSectorSize; // NBArea
++
++ unsigned long int MDPSectorSize; // RWArea Totla Sector Size
++ unsigned long int DTAreaSectorSize; // RWArea
++ unsigned long int HDAreaSectorSize; // RWArea
++ unsigned long int HDAreaAddrOffSet;
++
++ unsigned long int MHDAreaNums; // Multi Hidden Area Num
++ unsigned long int MHDAreaSectorSize[NAND_LBA_MAX_SUPPORT_MHD_AREA_NUM];
++ unsigned long int MHDAreaAddrOffSet[NAND_LBA_MAX_SUPPORT_MHD_AREA_NUM];
++
++} NAND_IO_LBADEVINFO;
++
++typedef struct __tag_NAND_IO_Feature
++{
++ NAND_IO_DEVID DeviceID; // Maker & Device ID Code
++ unsigned short int PBpV; // Physical all Block Number
++ unsigned short int BBpZ; // Total Bad Block in one ZONE
++ unsigned short int PpB; // Page Number Per Block
++ unsigned short int PageSize; // Page Size
++ unsigned short int SpareSize; // Spare Size
++ unsigned short int ColCycle; // Column Address Cycle
++ unsigned short int RowCycle; // Row Address Cycle
++ unsigned short int WCtime; // Write Cyclte time
++ unsigned short int WriteSTP;
++ unsigned short int WriteWP;
++ unsigned short int WriteHLD;
++ unsigned short int ReadSTP;
++ unsigned short int ReadPW;
++ unsigned short int ReadHLD;
++ unsigned long int MediaType; // Chracters of NANDFLASH
++} NAND_IO_FEATURE;
++
++typedef struct __tag_NAND_IO_DevInfo
++{
++ NAND_IO_FEATURE Feature; // Feature of NANDFLASH
++ unsigned short int IoStatus; // IO Status
++ unsigned short int ChipNo; // ChipSelect Number
++ unsigned short int CmdMask; // Command Mask Bit
++ unsigned short int EccType; // Type of ECC [ SLC , MLC4 ]
++ unsigned short int EccDataSize;
++
++ unsigned short int PPages; // Total Partial Page [512+16Bytes]
++
++ unsigned short int DistrictNum;
++ unsigned short int ShiftDistrictNum;
++
++ unsigned short int ExtInterleaveUsable;
++
++ unsigned short int ShiftPBpV;
++ unsigned short int ShiftPpB;
++ unsigned short int ShiftPageSize;
++ unsigned short int ShiftPPages;
++
++ unsigned short int PageUniteMode;
++ unsigned short int RemapPpB; // Physical Page Number Per FTL 1Block
++ unsigned short int RemapPageOffset; // Next FTL Block Page Offset
++ unsigned short int RemapRatioBSize; // Physical Block Number Per FTL 1Block
++ unsigned long int RemapRatioPSize; // Physical Block Number Per FTL 1Block
++
++ unsigned short int ShiftRemapPpB;
++ unsigned short int ShiftRemapPageOffset;
++ unsigned short int ShiftRemapRatioBSize;
++ unsigned short int ShiftRemapRatioPSize;
++
++ unsigned long int RemapPageWeight[4];
++
++ NAND_IO_WRITESTATUS WriteStatus;
++
++ NAND_IO_BADBLOCK BadBlockInfo;
++ NAND_IO_LBADEVINFO LBAInfo;
++} NAND_IO_DEVINFO;
++
++typedef struct __tag_NAND_IO_MakerInfo
++{
++ unsigned short int MaxSupportNAND[MAX_SUPPORT_MAKER_NAND];
++ unsigned short int MakerID[MAX_SUPPORT_MAKER_NAND];
++ NAND_IO_FEATURE* DevInfo[MAX_SUPPORT_MAKER_NAND];
++} NAND_IO_MAKERINFO;
++
++
++typedef struct __tag_NAND_IO_LBAMakerInfo
++{
++ unsigned short int MaxSupportNAND[MAX_SUPPORT_MAKER_LBA_NAND];
++ unsigned short int MakerID[MAX_SUPPORT_MAKER_LBA_NAND];
++ NAND_IO_FEATURE* DevInfo[MAX_SUPPORT_MAKER_LBA_NAND];
++} NAND_IO_LBA_MAKERINFO;
++
++//*****************************************************************************
++//*
++//*
++//* [ EXTERNAL VARIABLE DEFINE ]
++//*
++//*
++//*****************************************************************************
++extern const NAND_IO_MAKERINFO NAND_SupportMakerInfo;
++extern const NAND_IO_LBA_MAKERINFO LBA_NAND_SupportMakerInfo;
++
++extern const NAND_IO_FEATURE SAMSUNG_NAND_DevInfo[MAX_SUPPORT_SAMSUNG_NAND];
++extern const NAND_IO_FEATURE TOSHIBA_NAND_DevInfo[MAX_SUPPORT_TOSHIBA_NAND];
++extern const NAND_IO_FEATURE HYNIX_NAND_DevInfo[MAX_SUPPORT_HYNIX_NAND];
++extern const NAND_IO_FEATURE ST_NAND_DevInfo[MAX_SUPPORT_ST_NAND];
++extern const NAND_IO_FEATURE MICRON_NAND_DevInfo[MAX_SUPPORT_MICRON_NAND];
++
++extern const NAND_IO_FEATURE TOSHIBA_LBA_NAND_DevInfo[MAX_SUPPORT_TOSHIBA_LBA_NAND];
++
++//*****************************************************************************
++//*
++//*
++//* [ EXTERNAL FUCTIONS DEFINE ]
++//*
++//*
++//*****************************************************************************
++extern NAND_IO_ERROR NAND_IO_CallBackChangeWCtime( unsigned short int TotalMediaNum, NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_SetCycle( NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_GetDeviceInfo( U16 nChipNo, NAND_IO_DEVINFO *nDevInfo );
++extern U32 NAND_IO_GetBUSTypeOfDataIO( void );
++extern void NAND_IO_Init( void );
++extern void NAND_IO_Reset( U16 nChipNo, int nMode );
++extern void NAND_IO_ResetForReadID( U16 nChipNo, int nMode );
++extern void NAND_IO_ReadID( U16 nChipNo, NAND_IO_DEVID *nDeviceCode, int nMode );
++
++extern NAND_IO_ERROR NAND_IO_ReadSpare( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8 *nSpareBuffer );
++extern NAND_IO_ERROR NAND_IO_ReadPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_ReadPageMTD( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_ReadNBPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_ReadTwoPlanePage(NAND_IO_DEVINFO * nDevInfo, U32 nPageAddr, U32 nSecondPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 * nPageBuffer, U8 * nSpareBuffer, int nEccOnOff);
++extern NAND_IO_ERROR NAND_IO_ReadTwoPlaneLastPage(NAND_IO_DEVINFO * nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 * nPageBuffer, U8 * nSpareBuffer, int nEccOnOff);
++extern NAND_IO_ERROR NAND_IO_ReadUserSizePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nColumnAddr, U32 nReadSize, U8 *nReadBuffer );
++extern NAND_IO_ERROR NAND_IO_ReadChainPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8 *nPageBuffer, U8 *nSpareBuffer, int nMode );
++extern NAND_IO_ERROR NAND_IO_ReadGoldenPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8 *nPageBuffer, U8 *nSpareBuffer );
++
++extern NAND_IO_ERROR NAND_IO_WriteSpare( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8* nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_WritePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_WritePageMTD( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_WriteNBPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_WriteCachePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_WriteTwoPlanePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_WriteTwoPlaneLastPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8* nSpareBuffer, int LastPage, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_WriteUserSizePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nColumnAddr, U32 nWriteSize, U8 *nWriteBuffer );
++
++extern NAND_IO_ERROR NAND_IO_WriteChainPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8 *nPageBuffer, U8 *nSpareBuffer, int nMode );
++extern NAND_IO_ERROR NAND_IO_WriteGoldenPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8 *nPageBuffer, U8 *nSpareBuffer );
++
++extern NAND_IO_ERROR NAND_IO_CopyBackPage( NAND_IO_DEVINFO *nDevInfo, U32 nDesPageAddr, U32 nSrcPageAddr );
++extern NAND_IO_ERROR NAND_IO_CopyBackTwoPlanePage( NAND_IO_DEVINFO *nDevInfo, U32 nDesPageAddr, U32 nSrcPageAddr );
++
++extern NAND_IO_ERROR NAND_IO_EraseBlock( NAND_IO_DEVINFO *nDevInfo, U32 nBlockPageAddr, int nFormatMode );
++extern NAND_IO_ERROR NAND_IO_EraseBlockForTwoPlane( NAND_IO_DEVINFO *nDevInfo, U32 nBlockPageAddr, int nFormatMode );
++
++extern NAND_IO_ERROR NAND_IO_GetFactoryBadMarkOfPBlock( NAND_IO_DEVINFO *nDevInfo, U32 nBlockPageAddr );
++extern NAND_IO_ERROR NAND_IO_GetUID( NAND_IO_DEVINFO *nDevInfo, U16 *nCmd, U8 *rReadData );
++extern NAND_IO_ERROR NAND_IO_WaitBusyCheckForWriteEnd( NAND_IO_DEVINFO *nDevInfo );
++
++extern NAND_IO_ERROR NAND_IO_LBA_SetCallBackHandler( NAND_LBA_CALLBACK_HANDLER pCallBackHandler );
++extern U32 NAND_IO_LBA_GetSerialNumber( NAND_IO_DEVINFO *nDevInfo, U8* nPageBuffer, U8* rSerialNumber, U16 nSize );
++extern NAND_IO_ERROR NAND_IO_LBA_PowerSaveMode( NAND_IO_DEVINFO *nDevInfo, int nOnOff );
++extern NAND_IO_ERROR NAND_IO_LBA_DeviceReboot( NAND_IO_DEVINFO *nDevInfo );
++
++extern NAND_IO_ERROR NAND_IO_LBA_GetDeviceInfo( NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_LBA_Init( NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_LBA_ReadSectorBy4Byte( NAND_IO_DEVINFO *nDevInfo, U8 nPartition, U32 nSectorAddr, U16 nOffset, U16 nReadSize, U8 *nReadBuffer );
++extern NAND_IO_ERROR NAND_IO_LBA_ReadSector( NAND_IO_DEVINFO *nDevInfo, U8 nPartition, U32 nSectorAddr, U16 nSecSize, U8 *nReadBuffer );
++extern NAND_IO_ERROR NAND_IO_LBA_WriteSector( NAND_IO_DEVINFO *nDevInfo,U8 nPartition, U32 nSectorAddr, U16 nSecSize, U8 *nWriteBuffer );
++extern NAND_IO_ERROR NAND_IO_LBA_AREAClear( NAND_IO_DEVINFO *nDevInfo, U8 nPartition );
++extern NAND_IO_ERROR NAND_IO_LBA_ModeChange( NAND_IO_DEVINFO *nDevInfo, int nMode );
++extern NAND_IO_ERROR NAND_IO_LBA_ScanHeaderOfVFP( NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_LBA_MakeHeaderOfVFP( NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_LBA_Read2Status( NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_LBA_GetTotalSecAndCHS( NAND_IO_DEVINFO *nDevInfo, int nPartition, U32 *rTotalSec, U16 *rCylinder, U16 *rHead, U8 *rSector );
++extern NAND_IO_ERROR NAND_IO_LBA_CacheFlush( NAND_IO_DEVINFO *nDevInfo );
++
++#endif
++
+diff --git a/drivers/block/tcc/inc/tnftl/nand_io_v7.h b/drivers/block/tcc/inc/tnftl/nand_io_v7.h
+new file mode 100644
+index 0000000..aa12d22
+--- /dev/null
++++ b/drivers/block/tcc/inc/tnftl/nand_io_v7.h
+@@ -0,0 +1,970 @@
++ /****************************************************************************
++ * FileName : nand_io_v7.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#ifndef __NAND_IO_H
++#define __NAND_IO_H
++
++#if defined(USE_V_ADDRESS)
++ #if defined(_LINUX_)
++ #define __USE_NAND_ISR__
++ //#define __USE_NAND_ISR_WRITE__
++ #elif defined(_WINCE_)
++ //#define __USE_NAND_ISR__
++ #endif
++#endif
++
++//#define NAND_GPIO_DEBUG
++
++//*****************************************************************************
++//*
++//*
++//* [ Specific DEFINE ]
++//*
++//*
++//*****************************************************************************
++#if defined(TCC83XX) && defined(_WINCE_)
++// In the case of LINUX, it is defined config.h
++#define NAND_2CS_ONLY
++#define NAND_8BIT_ONLY
++#elif defined(_LINUX_)
++#define NAND_2CS_ONLY // for IDE CS#
++#define NAND_8BIT_ONLY
++#else
++//#define NAND_2CS_ONLY
++//#define NAND_8BIT_ONLY
++#endif
++
++//**********************************************************************
++//* Define Dev Board
++//**********************************************************************
++//#define TCC9200S_BOARD // TCC9200S ND_RDY: GPIO_B31
++#define TCC89_92_BOARD // TCC89/91/9200 ND_RDY: GPIO_B28 - EDI - NFC_CTRL
++
++#ifdef TCC9200S_BOARD // ND_RDY: B31, ND_WP: B22
++#define TCC_NAND_RDY_B31
++//#define TCC_NAND_RDY_B28
++#define TCC_NAND_WP_B22
++//#define TCC_NAND_WP_B31
++#endif
++
++#ifdef TCC89_92_BOARD // ND_RDY: B28, ND_WP: B31
++#define TCC_NAND_RDY_B28
++//#define TCC_NAND_RDY_B31
++#define TCC_NAND_WP_B31
++//#define TCC_NAND_WP_B22
++#endif
++
++//**********************************************************************
++//* Define IRQ
++//**********************************************************************
++#define NAND_IRQ_NFC IRQ_NFC
++
++#ifdef TCC89_92_BOARD
++#define NAND_IRQ_READY IRQ_EI0 // External interrupt 3
++#else
++#define NAND_IRQ_READY IRQ_EI0
++#endif
++
++//**********************************************************************
++//* Define ECC Algorithm for ChipSet
++//**********************************************************************
++#if defined(TCC77X) || defined(TCC87XX) || defined(TCC82XX) || defined(TCC78X) || defined(TCC83XX) || defined(TCC79XX)
++#define ECC_TYPE_RS
++#elif defined(TCC81XX) || defined(TCC80XX) || defined(TCC92XX) || defined(TCC89XX)
++#define ECC_TYPE_BCH
++#endif
++
++#if defined(USE_V_ADDRESS)
++ #if defined(_LINUX_)
++ #define ND_TRACE printk
++ //#define n_printk(f, a...) printk("[%s:%d] " f, __func__, __LINE__, ##a)
++ #define n_printk(f, a...)
++ #elif defined(_WINCE_)
++ #define ND_TRACE printf
++// #define ND_TRACE
++ #endif
++#else
++ #if defined(_LINUX_)
++ #define ND_TRACE printf
++ #elif defined(_WINCE_)
++ #define ND_TRACE B_RETAILMSG
++ #else
++ #define ND_TRACE uart_send_printf
++ #endif
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ General DEFINE & TYPEDEF ]
++//*
++//*
++//*****************************************************************************
++//===================================================================
++//
++// DRIVER SIGNATURE
++//
++//===================================================================
++#define SIGBYAHONG 'S','I','G','B','Y','A','H','O','N','G','_'
++
++#define NAND_IO_SIGNATURE 'N','A','N','D','_','I','O','_'
++#define TNFTL_SIGNATURE 'T','N','F','T','L','_'
++
++#if defined(_WINCE_)
++#define SIGN_OS 'W','I','N','C','E','_'
++#elif defined(_LINUX_)
++#define SIGN_OS 'L','I','N','U','X','_'
++#else
++#define SIGN_OS 'N','U','_'
++#endif
++
++#if defined(TCC77X)
++#define SIGN_CHIPSET 'T','C','C','7','7','X','X','_'
++#elif defined(TCC78X)
++#define SIGN_CHIPSET 'T','C','C','7','8','X','X','_'
++#elif defined(TCC79X)
++#define SIGN_CHIPSET 'T','C','C','7','9','X','X','_'
++#elif defined(TCC81XX)
++#define SIGN_CHIPSET 'T','C','C','8','1','X','X','_'
++#elif defined(TCC82XX)
++#define SIGN_CHIPSET 'T','C','C','8','2','X','X','_'
++#elif defined(TCC83XX)
++#define SIGN_CHIPSET 'T','C','C','8','3','X','X','_'
++#elif defined(TCC87XX)
++#define SIGN_CHIPSET 'T','C','C','8','7','X','X','_'
++#elif defined(TCC89XX)
++#define SIGN_CHIPSET 'T','C','C','8','9','X','X','_'
++#elif defined(TCC91XX)
++#define SIGN_CHIPSET 'T','C','C','9','1','X','X','_'
++#elif defined(TCC92XX)
++#define SIGN_CHIPSET 'T','C','C','9','2','X','X','_'
++#else
++#error
++#endif
++
++#ifndef DISABLE
++#define DISABLE 0
++#endif
++#ifndef ENABLE
++#define ENABLE 1
++#endif
++#ifndef FALSE
++#define FALSE 0
++#endif
++#ifndef TRUE
++#define TRUE 1
++#endif
++#ifndef NULL
++#define NULL 0
++#endif
++
++#if defined(_LINUX_)
++#ifndef _U8_
++#define _U8_
++typedef unsigned char U8;
++#endif
++#ifndef _U16_
++#define _U16_
++typedef unsigned short int U16;
++#endif
++#ifndef _U32_
++#define _U32_
++typedef unsigned int U32;
++#endif
++#ifndef _BOOL_
++#define _BOOL_
++typedef unsigned int BOOL;
++#endif
++#else
++#ifndef U8
++typedef unsigned char U8;
++#endif
++#ifndef U16
++typedef unsigned short int U16;
++#endif
++#ifndef U32
++typedef unsigned int U32;
++#endif
++#ifndef _BOOL_
++typedef unsigned int BOOL;
++#endif
++#endif
++
++#ifndef DWORD_BYTE
++typedef union {
++ unsigned long DWORD;
++ unsigned short int WORD[2];
++ unsigned char BYTE[4];
++} DWORD_BYTE;
++#endif
++
++#ifndef BITSET
++#define BITSET(X, MASK) ( (X) |= (U32)(MASK) )
++#endif
++#ifndef BITSCLR
++#define BITSCLR(X, SMASK, CMASK) ( (X) = ((((U32)(X)) | ((U32)(SMASK))) & ~((U32)(CMASK))) )
++#endif
++#ifndef BITCSET
++#define BITCSET(X, CMASK, SMASK) ( (X) = ((((U32)(X)) & ~((U32)(CMASK))) | ((U32)(SMASK))) )
++#endif
++#ifndef BITCLR
++#define BITCLR(X, MASK) ( (X) &= ~((U32)(MASK)) )
++#endif
++#ifndef BITXOR
++#define BITXOR(X, MASK) ( (X) ^= (U32)(MASK) )
++#endif
++#ifndef ISZERO
++#define ISZERO(X, MASK) ( ! (((U32)(X)) & ((U32)(MASK))) )
++#endif
++#ifndef BYTE_OF
++#define BYTE_OF(X) ( *(volatile unsigned char *)(&(X)) )
++#endif
++#ifndef HWORD_OF
++#define HWORD_OF(X) ( *(volatile unsigned short *)(&(X)) )
++#endif
++#ifndef WORD_OF
++#define WORD_OF(X) ( *(volatile unsigned int *)(&(X)) )
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ ERROR CODE ENUMERATION ]
++//*
++//*
++//*****************************************************************************
++#ifndef SUCCESS
++#define SUCCESS 0
++#endif
++
++typedef enum
++{
++ ERR_NAND_IO_FAILED_GET_DEVICE_INFO = 0xA100000,
++ ERR_NAND_IO_FAILED_CORRECTION_SLC_ECC,
++ ERR_NAND_IO_FAILED_CORRECTION_MLC_ECC,
++ ERR_NAND_IO_FAILED_GET_SHIFT_FACTOR_FOR_MULTIPLY,
++ ERR_NAND_IO_FAILED_GET_FACTORY_BAD_MARK_OF_PBLOCK,
++ ERR_NAND_IO_READ_STATUS_GENERAL_FAIL,
++ ERR_NAND_IO_TIME_OUT_READ_STATUS,
++ ERR_NAND_IO_WRONG_PARAMETER,
++ ERR_NAND_IO_WRONG_PARAMETER_ROW_COL_ADDRESS,
++ ERR_NAND_IO_NOT_READY_DEVICE_IO,
++ ERR_NAND_IO_FAILED_WRITE,
++ ERR_NAND_IO_NOT_EXIST_LBA_HEADBLOCK,
++ ERR_LBA_NOT_EXIST_MEDIA_NUM_INFO,
++ ERR_LBA_NOT_EXIST_NANDFLASH,
++ ERR_NAND_IO_FAILED_LBA_GET_MEDIA_UID,
++ ERR_NAND_IO_FAILED_LBA_PARTITION_CHANGE,
++ ERR_LBA_FAILED_CONVERT_LBA_ADDR
++} NAND_IO_ERROR;
++
++//*****************************************************************************
++//*
++//*
++//* [ INTERNAL DEFINATION ]
++//*
++//*
++//*****************************************************************************
++
++/* Maker Information of supported NANDFLASH */
++enum SUPPORT_MAKER_NAND
++{
++ SAMSUNG = 0,
++ TOSHIBA,
++ HYNIX,
++ ST,
++ MICRON,
++ INTEL,
++ MAX_SUPPORT_MAKER_NAND
++};
++
++enum SUPPORT_MAKER_LBA_NAND
++{
++ TOSHIBA_LBA = 0,
++ MAX_SUPPORT_MAKER_LBA_NAND
++};
++
++enum LBA_NAND_HIDDEN_INFO
++{
++ //==============================================
++ // VFP Size [ 4Byte ] 0
++ // MDP Size [ 4Byte ] 1
++ // Hidden Size [ 4Byte ] 2
++ // Multi-Hidden Num [ 4Byte ] 3
++ // Multi-Hidden Size[ 4Byte ] 4~10
++ //==============================================
++ ENUM_LBA_VFP_SECTOR_SIZE = 0,
++ ENUM_LBA_MDP_SECTOR_SIZE,
++ ENUM_LBA_HIDDEN_SECTOR_SIZE,
++ ENUM_LBA_MULTI_HIDDEN_NUM,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_0,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_1,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_2,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_3,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_4,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_5,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_6,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_7,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_8,
++ ENUM_LBA_MULTI_HIDDEN_SIZE_9
++};
++
++#define SAMSUNG_NAND_MAKER_ID 0xEC
++#define TOSHIBA_NAND_MAKER_ID 0x98
++#define HYNIX_NAND_MAKER_ID 0xAD
++#define ST_NAND_MAKER_ID 0x20
++#define MICRON_NAND_MAKER_ID 0x2C
++#define INTEL_NAND_MAKER_ID 0x89
++
++#define MAX_SUPPORT_SAMSUNG_NAND 28
++#define MAX_SUPPORT_TOSHIBA_NAND 17
++#define MAX_SUPPORT_HYNIX_NAND 27
++#define MAX_SUPPORT_ST_NAND 15
++#define MAX_SUPPORT_MICRON_NAND 13
++#define MAX_SUPPORT_INTEL_NAND 1
++
++/* LBA NAND FLASH */
++#define MAX_SUPPORT_TOSHIBA_LBA_NAND 3
++
++/* Media Attribute */
++#define A_08BIT 0x00000001 // 8Bit BUS
++#define A_BIG 0x00000002 // Big Page Size
++#define A_SMALL 0x00000004 // Small Page Size
++#define A_16BIT 0x00000008 // 16Bit BUS
++#define A_SLC 0x00000010 // Single Layer Cell
++#define A_MLC 0x00000020 // Multi Layer Cell
++#define A_MLC_8BIT 0x00000040 // 8Bit MLC ECC
++#define A_MLC_12BIT 0x00000080 // 12Bit MLC ECC
++#define A_MLC_16BIT 0x00000100 // 16Bit MLC ECC
++
++#define A_PARALLEL 0x00000200 // Parallel Composition
++#define A_DATA_WITDH_08BIT 0x00000400 // Data 8Bit Bus
++#define A_DATA_WITDH_16BIT 0x00000800 // Data 16Bit Bus
++
++#define S_NOR 0x00010000 // NORMAL [ ReadID, Reset, Read, Page Program, Block Erase, Read Status ]
++#define S_CB 0x00020000 // COPY BACK
++#define S_CP 0x00040000 // CACHE PROGRAM
++#define S_MP 0x00080000 // MULTI PLANE
++#define S_MP2 0x00100000 // MULTI PLANE
++#define S_MCP 0x00200000 // MULTI PLANE CACHE
++#define S_IL 0x00400000 // INTER LEAVE
++#define S_EIL 0x00800000 // EXTERNAL INTER LEAVE
++#define S_EPW 0x01000000 // EXCEPT PARTIAL WRITE
++#define S_NPW 0x02000000 // Not-Support PARTIAL WRITE
++#define S_MP_READ 0x04000000 // MULTI PLANE READ
++#define S_LBA 0x08000000 // LBA NAND
++#define S_RAND_IO 0x10000000 // Random Data In/Out
++#define S_EB 0x20000000 // Extend Block
++
++#define NAND_IO_NORMAL_PAGE_PROGRAM 0x00000001
++#define NAND_IO_CACHE_PROGRAM_1ST 0x00000002
++#define NAND_IO_CACHE_PROGRAM_2ND 0x00000004
++#define NAND_IO_TWO_PLANE_PAGE_PROGAM_1ST 0x00000010
++#define NAND_IO_TWO_PLANE_PAGE_PROGAM_2ND 0x00000020
++
++#define NAND_IO_NORMAL_READ 0x00000001
++#define NAND_IO_CACHE_READ 0x00000002
++#define NAND_IO_TWO_PLANE_READ_1ST 0x00000010
++#define NAND_IO_TWO_PLANE_READ_2ND 0x00000020
++#define NAND_IO_TWO_PLANE_MID_PAGE 0x00000100
++#define NAND_IO_TWO_PLANE_LAST_PAGE 0x00000200
++
++
++#define NAND_IO_MAX_SUPPORT_DRIVER 2
++
++#define NAND_IO_SERIAL_COMBINATION_MODE 0x00
++#define NAND_IO_PARALLEL_COMBINATION_MODE 0x01
++
++#if defined(NAND_2CS_ONLY)
++#define NAND_IO_DRV0_START_CS 0
++#define NAND_IO_DRV0_END_CS 1
++#else
++#define NAND_IO_DRV0_START_CS 0
++#define NAND_IO_DRV0_END_CS 3
++#endif
++
++#define ECC_OFF 0
++#define ECC_ON 1
++#define ECC_ON_NON_CACHE_BUF 3
++
++#define SLC_ECC_TYPE 0x0001 // 10 Byte
++#define MLC_ECC_4BIT_TYPE 0x0002 // BCH: 7 Byte( 52 bit) turn: 2, byte remain: 3, register mask: 0x0F
++#define MLC_ECC_8BIT_TYPE 0x0004 // BCH:13 Byte (104 bit) turn: 4, byte remain: 1, register mask: 0xFF
++#define MLC_ECC_12BIT_TYPE 0x0010 // BCH:20 Byte (156 bit) turn: 5, byte remain: 4, register mask: 0x0F
++#define MLC_ECC_14BIT_TYPE 0x0020 // BCH:23 Byte (184 bit) turn: 6, byte remain: 3, register mask: 0xFF
++#define MLC_ECC_16BIT_TYPE 0x0040 // BCH:26 Byte (207 bit)turn: 7, byte remain: 2, register mask: 0x7F
++
++#define NAND_IO_SPARE_SIZE_BIG 16
++#define NAND_IO_SPARE_SIZE_SMALL 8
++
++
++#define PAGE_ECC_OFF 0
++#define PAGE_ECC_ON 1
++
++//----------------------------------------------------------------------
++// TNFTL R/W Area Spare Date
++//----------------------------------------------------------------------
++// Block Area & Type 1Byte : 0xFF
++// Block Parameter 2Byte
++// Logical Block Address 3Byte : 0x0 ~ 0xFFFFFE
++//----------------------------------------------------------------------
++// Spare Data Total 6Byte
++//----------------------------------------------------------------------
++
++//----------------------------------------------------------------------
++// TNFTL R/O Area Spare Date
++//----------------------------------------------------------------------
++// Block Area & Type 1Byte : 0xFF
++// Rom Image Num 2Byte
++// Rom Image LBA 3Byte : 0x0 ~ 0xFFFFFE
++//----------------------------------------------------------------------
++// Spare Data Total 6Byte
++//----------------------------------------------------------------------
++
++
++// 512 Page + 16 Spare : SLC / 4 Bit ECC
++typedef struct {
++ U8 SpareData0[4]; // 4 Bytes Spare data
++ U8 Temp; // 1 Bytes Temp
++ U8 BadMark; // 1 Bytes bad mark
++ U8 SpareData1[2]; // 2 Bytes Spare data
++ U8 PageECC[8]; // 8 Bytes Spare ECC --> 4Bit ECC
++} SLC_512Page_4BitECC_Spare;
++
++// 2048 Page + 64 Spare : 4 Bit ECC
++typedef struct {
++ U8 BadMark; // 1 Bytes bad mark
++ U8 Temp; // 1 Bytes Temp --> Parallel Bad Mark reserved
++ U8 SpareData[14]; // 14 bytes Spare data
++ U8 PageECC[4][8]; // 32 Bytes Spare ECC --> 4Bit ECC
++ U8 SpareECC[8]; // 8 Byte
++} MLC_2KPage_4BitECC_Spare;
++
++// 4096 Page + 128 Spare : 4 Bit ECC
++typedef struct {
++ U8 BadMark; // 1 Bytes bad mark
++ U8 Temp; // 1 Bytes Temp --> Parallel Bad Mark reserved
++ U8 SpareData[14]; // 14 bytes Spare data
++ U8 PageECC[8][8]; // 64 Bytes Spare ECC --> 4Bit ECC
++ U8 SpareECC[8]; // 8 Byte
++} MLC_4KPage_4BitECC_Spare;
++
++// 4096 Page + 218 Spare : 8/12 Bit ECC
++typedef struct {
++ U8 BadMark; // 1 Bytes bad mark
++ U8 Temp; // 1 Bytes Temp --> Parallel Bad Mark reserved
++ U8 SpareData[14]; // 14 bytes Spare data
++ U8 PageECC[8][20]; //160 Bytes Spare ECC --> 4Bit ECC
++ U8 SpareECC[20]; // 20 Byte
++} MLC_4KPage_8_12BitECC_Spare;
++
++// 8192 Page + 436 Spare : 16 Bit ECC
++typedef struct {
++ U8 BadMark; // 1 Bytes bad mark
++ U8 Temp; // 1 Bytes Temp
++ U8 SpareData[10]; // 10 bytes Spare data
++ U8 PageECC[16][26]; //416 Bytes Page ECC
++ U8 SpareECC[8]; // 8 Bytes Spare ECC --> 4 bit ECC
++} MLC_4KPage_16BitECC_Spare;
++
++
++#define TYPE_SPARE_FOR_512_16_NANDFLASH 0
++#define TYPE_SPARE_FOR_2048_64_NANDFLASH 1
++#define TYPE_SPARE_FOR_4096_128_NANDFLASH 2
++#define TYPE_SPARE_FOR_4096_218_NANDFLASH 3
++
++#ifdef ECC_TYPE_RS
++#define TYPE_ECC_FOR_1BIT_SLC_NANDFLASH MLC_ECC_4BIT_TYPE
++#define TYPE_ECC_FOR_4BIT_MLC_NANDFLASH MLC_ECC_4BIT_TYPE
++#define TYPE_ECC_FOR_8BIT_MLC_NANDFLASH MLC_ECC_8BIT_TYPE
++#define ECC_SHIFT_DATASIZE 16
++#else
++#define TYPE_ECC_FOR_1BIT_SLC_NANDFLASH SLC_ECC_TYPE
++#define TYPE_ECC_FOR_4BIT_MLC_NANDFLASH MLC_ECC_4BIT_TYPE
++#define TYPE_ECC_FOR_8BIT_MLC_NANDFLASH MLC_ECC_12BIT_TYPE
++#define TYPE_ECC_FOR_12BIT_MLC_NANDFLASH MLC_ECC_12BIT_TYPE
++#define TYPE_ECC_FOR_14BIT_MLC_NANDFLASH MLC_ECC_14BIT_TYPE
++#define TYPE_ECC_FOR_16BIT_MLC_NANDFLASH MLC_ECC_16BIT_TYPE
++#define ECC_SHIFT_DATASIZE 4
++#endif
++
++#define TNFTL_READ_SPARE_ON 0
++#define TNFTL_READ_SPARE_OFF 1
++
++#define NAND_MCU_ACCESS 0
++#define NAND_DMA_ACCESS 1
++
++#define NAND_NORMAL_BUFFER 0
++#define NAND_SERIAL_CHAIN_BUFFER 1
++
++
++#define ECC_DECODE 0
++#define ECC_ENCODE 1
++#define INTER_LEAVE_OFF 0
++#define INTER_LEAVE_ON 1
++#define MULTI_PLANE_NORMAL_PAGE 0
++#define MULTI_PLANE_START_PAGE 1
++#define MULTI_PLANE_MID_PAGE 2
++#define MULTI_PLANE_LAST_PAGE 3
++#define MULTI_PLANE_STUFF_PAGE 4
++#define MULTI_PLANE_GOOD_BLOCK 0
++#define MULTI_PLANE_BAD_BLOCK 1
++
++#define NAND_IO_BSA_OK 0x0000
++#define NAND_IO_BSA_BAD_SERIAL 0x0001
++#define NAND_IO_BSA_BAD_BLOCK1_PARALLEL 0x0010
++#define NAND_IO_BSA_BAD_BLOCK2_PARALLEL 0x0100
++#define NAND_IO_BSA_FAIL_OTHER_REASON 0x1000
++
++#define NAND_IO_STATUS_FAIL_CS0_SERIAL 0x0001
++#define NAND_IO_STATUS_FAIL_CS0_PARALLEL 0x0010
++#define NAND_IO_STATUS_FAIL_CS1_PARALLEL 0x0100
++
++#define NAND_IO_LOG_COLUMN_IN_PAGE 0
++#define NAND_IO_LOG_COLUMN_IN_SPARE 1
++
++/* LBA NAND DEFINATION : [STATUS READ 2] */
++#define LBA_MAX_SUPPORT_MULTI_NANDFLASH 4
++#define NAND_LBA_PNP 0x00
++#define NAND_LBA_BCM 0x02
++#define NAND_LBA_VFP 0x04
++#define NAND_LBA_MDP 0x06
++
++#define NAND_LBA_DATA_AREA 0x16
++#define NAND_LBA_HIDDEN_AREA 0x26
++#define NAND_LBA_MULTI_HIDDEN_AREA_0 0x36
++#define NAND_LBA_MULTI_HIDDEN_AREA_1 0x46
++#define NAND_LBA_MULTI_HIDDEN_AREA_2 0x56
++
++#define NAND_POWER_SAVE_ENABLE 0x01
++#define NAND_HIGH_SPEED_ENABLE 0x08
++
++#define NAND_ADDRESS_OUT_OF_RANGE_ERROR 0x10
++#define NAND_COMMAND_PARAMETER_ERROR 0x40
++
++/* LBA NAND Transfer Protocol 1 */
++#define NAND_PROT1_512x1 0x01
++#define NAND_PROT1_512x4 0x02
++#define NAND_PROT1_512x8 0x04
++
++#define NAND_PROT1_528x1 0x21
++#define NAND_PROT1_528x4 0x22
++#define NAND_PROT1_528x8 0x24
++
++#define NAND_PROT1_SPARE_INCLUDE 0x20
++#define NAND_PROT1_SECTOR_COUNT_MASK 0x07
++
++#define NAND_PROT1_NoCRC_NoECC 0x00
++#define NAND_PROT1_CRC 0x40
++#define NAND_PROT1_ECC_CHECK_ONLY 0x80
++#define NAND_PROT1_ECC_CORRECT 0xC0
++
++/* LBA NAND Transfer Protocol 2 */
++#define NAND_PROT2_READ_TYPE_A 0x00
++#define NAND_PROT2_READ_TYPE_B 0x02
++#define NAND_PROT2_READ_TYPE_C 0x03
++
++#define NAND_PROT2_WRITE_TYPE_A 0x00
++#define NAND_PROT2_WRITE_TYPE_B 0x04
++
++#define NAND_LBA_SYS_SECTION 2
++#define NAND_LBA_MAX_NANDFLASH_UID_SIZE 16
++#define NAND_LBA_MAX_SUPPORT_MHD_AREA_NUM 10
++
++typedef void (*NAND_LBA_CALLBACK_HANDLER) ( U16 nDrvNo, U16 nStatusCode, U32 wParam );
++#define NAND_LBA_CALLBACK_LCD_FORMAT_PROCESS 0x04
++
++
++/* HardWare relevant variables */
++
++#define NAND_IO_NFC_BUS 0
++#define NAND_IO_MEM_BUS 1
++
++#define NAND_IO_DATA_WITDH_8BIT 0
++#define NAND_IO_DATA_WITDH_16BIT 1
++
++
++
++#if defined(_LINUX_) || defined(_WINCE_)
++#if defined(TCC89XX) || defined(TCC92XX)
++#define NAND_IO_HwCMD_PA *(volatile unsigned long*)0xF05B0000 //( gNAND_IO_pHwND->CMD )
++#define NAND_IO_HwLADR_PA *(volatile unsigned long*)0xF05B0004 //( gNAND_IO_pHwND->LADR )
++#define NAND_IO_HwDATA_PA *(volatile unsigned long*)0xF05B0010 //( gNAND_IO_pHwND->WDATA.D32 )
++#define NAND_IO_HwLDATA_PA *(volatile unsigned long*)0xF05B0020 //( gNAND_IO_pHwND->LDATA )
++#define NAND_IO_HwSDATA_PA *(volatile unsigned long*)0xF05B0040 //(/*( gNAND_IO_DataBusType == NAND_IO_MEM_BUS ) ? gNAND_IO_pHwND->WDATA.D8 : */gNAND_IO_pHwND->SDATA.D32 )
++#define NAND_IO_HwSADR_PA *(volatile unsigned long*)0xF05B000C //( gNAND_IO_pHwND->SADR )
++#endif
++#endif
++
++#if defined(TCC_NAND_WP_B22)
++#define NAND_IO_NFC_nWP HwGPIOB->GPDAT
++#define NAND_IO_NFC_nWPBit Hw22
++#elif defined(TCC_NAND_WP_B31)
++#define NAND_IO_NFC_nWP HwGPIOB->GPDAT
++#define NAND_IO_NFC_nWPBit Hw31
++#endif
++#define NAND_IO_STATUS_ENABLE 0x0001
++#define NAND_IO_STATUS_INTERLEAVING_MASK 0x00F0
++#define NAND_IO_STATUS_INTERLEAVING_CHIP1 0x0010
++#define NAND_IO_STATUS_INTERLEAVING_CHIP2 0x0020
++#define NAND_IO_STATUS_INTERLEAVING_CHIP3 0x0040
++#define NAND_IO_STATUS_INTERLEAVING_CHIP4 0x0080
++
++#define NAND_IO_DISTRICT_0 0x0001
++#define NAND_IO_DISTRICT_1 0x0002
++
++#define NAND_IO_DMA_WRITE 0x0001
++#define NAND_IO_DMA_READ 0x0002
++
++#define NAND_SB_BOOT_PAGE_SIZE 260
++#define NAND_SB_BOOT_PAGE_ECC_SIZE 288
++
++//*****************************************************************************
++//*
++//*
++//* [ INTERNAL STRUCT DEFINE ]
++//*
++//*
++//*****************************************************************************
++#define GMC_NAND_NOMAL_BOOT_TYPE 0x54435342 // TCSB
++#define GMC_NAND_SECURE_BOOT_TYPE 0x54435353 // TCSS
++
++typedef struct __tag_NAND_GOLDEN_INFO
++{
++ U32 Signature;
++ U16 PageSize;
++ U16 SpareSize;
++ U16 Ppage;
++ U16 PpB;
++ U32 PpBforAddress;
++ U16 EccType;
++ U16 EccDataSize;
++ U32 TargetAddress; // Working Address
++ U32 BootLoaderSize;
++ U32 LastBlockPpB;
++ U16 RomCopyNum;
++ U16 RomBlockNum;
++ U32 RomCRC;
++ U32 BlockUppuerLimit;
++ U32 BlockLowerLimit;
++//---------------------------------- 44Byte
++ U32 GoldenInfoCRC;
++ U32 SecureData[4];
++} NAND_GOLDEN_INFO;
++
++typedef struct __tag_NAND_BOOTLOADER_INFO
++{
++ U16 BL_ColCycle;
++ U16 BL_RowCycle;
++ U32 BL_ReadCycle;
++ U32 BL_MediaType;
++ U32 BL_SpareDataSize;
++ U32 BL_TargetAddress; // Working Address
++ U32 BL_MemInitCodeSize;
++ U32 BL_MemInitCodePpB;
++ U32 BL_RomFileSize;
++ U16 BL_RomCopyNum;
++ U16 BL_RomBlockNum;
++ U32 BL_BlockUppuerLimit;
++ U32 BL_BlockLowerLimit;
++ U32 BL_LastBlockPpB;
++ U32 BL_RomFileCRC;
++} NAND_BOOTLOADER_INFO;
++
++typedef struct __tag_NAND_IO_ECCSizeInfo
++{
++ unsigned int EncodeFlag;
++ unsigned int DecodeFlag;
++ unsigned int ErrorNum;
++ unsigned char EccDataSize;
++ unsigned char *All_FF_512_ECC_Code;
++} NAND_IO_ECC_INFO;
++
++typedef struct __tag_NAND_IO_WriteStatus
++{
++ unsigned char ChipNo;
++ unsigned char BlockStatus;
++ unsigned int ErrorPHYPageAddr;
++} NAND_IO_WRITESTATUS;
++
++typedef struct __tag_NAND_IO_BadBlockAddr
++{
++ unsigned char BlockStatus[4];
++ unsigned int BadBlkPHYAddr[4];
++} NAND_IO_BADBLOCK;
++
++typedef struct __tag_NAND_IO_Cycle
++{
++ unsigned char STP;
++ unsigned char PW;
++ unsigned char HLD;
++ unsigned int RegValue;
++} NAND_IO_CYCLE;
++
++typedef struct __tag_NAND_IO_DeviceCode
++{
++ unsigned short int Code[6]; // Factory ID code
++} NAND_IO_DEVID;
++
++typedef struct __tag_NAND_IO_LBADevInfo
++{
++ unsigned char Usable;
++
++ unsigned char CurrentMode;
++ unsigned long int CurrentSectorSize;
++
++ unsigned char HighSpeedMode;
++ unsigned char PowerSaveMode;
++ unsigned char TransProtocol1;
++ unsigned char TransProtocol2;
++ unsigned char SectorCount;
++ unsigned char DataTransferCheck;
++ unsigned char FlagOfChangeTotalSectorSize;
++ unsigned char MediaUniqueID[NAND_LBA_MAX_NANDFLASH_UID_SIZE];
++
++ unsigned long int VFPSectorSize; // NBArea
++
++ unsigned long int MDPSectorSize; // RWArea Totla Sector Size
++
++ unsigned long int DTAreaSectorSize; // RWArea
++ unsigned long int DTAreaAddrOffSet;
++
++ unsigned long int HDAreaSectorSize; // RWArea
++ unsigned long int HDAreaAddrOffSet;
++
++ unsigned long int MHDAreaNums; // Multi Hidden Area Num
++ unsigned long int MHDAreaSectorSize[NAND_LBA_MAX_SUPPORT_MHD_AREA_NUM];
++ unsigned long int MHDAreaAddrOffSet[NAND_LBA_MAX_SUPPORT_MHD_AREA_NUM];
++
++} NAND_IO_LBADEVINFO;
++
++typedef struct __tag_NAND_IO_Feature
++{
++ NAND_IO_DEVID DeviceID; // Maker & Device ID Code
++ unsigned short int PBpV; // Physical all Block Number
++ unsigned short int BBpZ; // Total Bad Block in one ZONE
++ unsigned short int PpB; // Page Number Per Block
++ unsigned short int PageSize; // Page Size
++ unsigned short int SpareSize; // Spare Size
++ unsigned short int ColCycle; // Column Address Cycle
++ unsigned short int RowCycle; // Row Address Cycle
++ unsigned short int WCtime; // Write Cyclte time
++ unsigned short int WriteSTP;
++ unsigned short int WriteWP;
++ unsigned short int WriteHLD;
++ unsigned short int ReadSTP;
++ unsigned short int ReadPW;
++ unsigned short int ReadHLD;
++ unsigned long int MediaType; // Chracters of NANDFLASH
++} NAND_IO_FEATURE;
++
++typedef struct __tag_NAND_IO_DevInfo
++{
++ NAND_IO_FEATURE Feature; // Feature of NANDFLASH
++ unsigned short int IoStatus; // IO Status
++ unsigned short int ChipNo; // ChipSelect Number
++ unsigned short int CmdMask; // Command Mask Bit
++ unsigned short int EccType; // Type of ECC [ SLC , MLC4 ]
++ unsigned short int EccDataSize;
++ unsigned short int EccWholeDataSize;
++
++ unsigned short int PPages; // Total Partial Page [512+16Bytes]
++
++ unsigned short int DistrictNum;
++ unsigned short int ShiftDistrictNum;
++
++ unsigned short int ExtInterleaveUsable;
++
++ unsigned short int ShiftPBpV;
++ unsigned short int ShiftPpB;
++ unsigned short int ShiftPageSize;
++ unsigned short int ShiftPPages;
++
++ unsigned short int PageUniteMode;
++ unsigned short int RemapPpB; // Physical Page Number Per FTL 1Block
++ unsigned short int RemapPageOffset; // Next FTL Block Page Offset
++ unsigned short int RemapRatioBSize; // Physical Block Number Per FTL 1Block
++ unsigned long int RemapRatioPSize; // Physical Block Number Per FTL 1Block
++
++ unsigned short int ShiftRemapPpB;
++ unsigned short int ShiftRemapPageOffset;
++ unsigned short int ShiftRemapRatioBSize;
++ unsigned short int ShiftRemapRatioPSize;
++
++ unsigned long int RemapPageWeight[4];
++
++ unsigned long int PrePageAddr;
++ unsigned short int PreStartPPage;
++ unsigned short int PreChipNo;
++
++ unsigned char DirectRead;
++ NAND_IO_WRITESTATUS WriteStatus;
++
++ NAND_IO_BADBLOCK BadBlockInfo;
++ NAND_IO_LBADEVINFO LBAInfo;
++} NAND_IO_DEVINFO;
++
++#define MAX_NAND_WORK_SECTOR_NUM 512
++
++typedef struct __tag_WriteStuffInfo {
++ unsigned short int StuffInfoNum;
++ unsigned short int StartPPageNo[MAX_NAND_WORK_SECTOR_NUM];
++ unsigned short int SectorSize[MAX_NAND_WORK_SECTOR_NUM];
++ unsigned char *nStuffPageBuffer;
++} ndd_stuff_info;
++
++typedef struct __tag_NanddWorkInfo {
++ unsigned int SectorNum; // Total Sector Num
++ unsigned int StartSector;
++ unsigned int BufferAddr[MAX_NAND_WORK_SECTOR_NUM];
++
++ unsigned int PhyPageNum;
++ unsigned int PhyPageAddr[MAX_NAND_WORK_SECTOR_NUM];
++ unsigned char ChipNo[MAX_NAND_WORK_SECTOR_NUM];
++ unsigned short int StartPPageNo[1024];
++ unsigned short int PPageSize[1024]; // TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE_PER_1BLOCK
++ unsigned int FTLPPage;
++ unsigned char PageWriteFunc[1024];
++ ndd_stuff_info StuffInfo;
++ unsigned char *nSpareBuffer;
++ NAND_IO_DEVINFO *nDevInfo;
++} ndd_work_info;
++
++typedef struct __tag_NAND_IO_MakerInfo
++{
++ unsigned short int MaxSupportNAND[MAX_SUPPORT_MAKER_NAND];
++ unsigned short int MakerID[MAX_SUPPORT_MAKER_NAND];
++ NAND_IO_FEATURE* DevInfo[MAX_SUPPORT_MAKER_NAND];
++} NAND_IO_MAKERINFO;
++
++
++typedef struct __tag_NAND_IO_LBAMakerInfo
++{
++ unsigned short int MaxSupportNAND[MAX_SUPPORT_MAKER_LBA_NAND];
++ unsigned short int MakerID[MAX_SUPPORT_MAKER_LBA_NAND];
++ NAND_IO_FEATURE* DevInfo[MAX_SUPPORT_MAKER_LBA_NAND];
++} NAND_IO_LBA_MAKERINFO;
++
++//*****************************************************************************
++//*
++//*
++//* [ EXTERNAL VARIABLE DEFINE ]
++//*
++//*
++//*****************************************************************************
++extern const NAND_IO_MAKERINFO NAND_SupportMakerInfo;
++extern const NAND_IO_LBA_MAKERINFO LBA_NAND_SupportMakerInfo;
++
++extern const NAND_IO_FEATURE SAMSUNG_NAND_DevInfo[MAX_SUPPORT_SAMSUNG_NAND];
++extern const NAND_IO_FEATURE TOSHIBA_NAND_DevInfo[MAX_SUPPORT_TOSHIBA_NAND];
++extern const NAND_IO_FEATURE HYNIX_NAND_DevInfo[MAX_SUPPORT_HYNIX_NAND];
++extern const NAND_IO_FEATURE ST_NAND_DevInfo[MAX_SUPPORT_ST_NAND];
++extern const NAND_IO_FEATURE MICRON_NAND_DevInfo[MAX_SUPPORT_MICRON_NAND];
++
++extern const NAND_IO_FEATURE TOSHIBA_LBA_NAND_DevInfo[MAX_SUPPORT_TOSHIBA_LBA_NAND];
++
++//*****************************************************************************
++//*
++//*
++//* [ EXTERNAL FUCTIONS DEFINE ]
++//*
++//*
++//*****************************************************************************
++extern NAND_IO_ERROR NAND_IO_CallBackChangeWCtime( unsigned short int TotalMediaNum, NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_SetCycle( NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_GetDeviceInfo( U16 nChipNo, NAND_IO_DEVINFO *nDevInfo );
++extern U32 NAND_IO_GetBUSTypeOfDataIO( void );
++extern void NAND_IO_Init( void );
++extern void NAND_IO_Reset( U16 nChipNo, int nMode );
++extern void NAND_IO_ResetForReadID( U16 nChipNo, int nMode );
++extern void NAND_IO_ReadID( U16 nChipNo, NAND_IO_DEVID *nDeviceCode, int nMode );
++
++extern NAND_IO_ERROR NAND_IO_ReadSpare( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8 *nSpareBuffer );
++extern NAND_IO_ERROR NAND_IO_ReadPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_ReadPhyPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_ReadPageMTD(NAND_IO_DEVINFO * nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 * nPageBuffer, U8 * nSpareBuffer, int nEccOnOff);
++extern NAND_IO_ERROR NAND_IO_ReadTwoPlanePage(NAND_IO_DEVINFO * nDevInfo, U32 nPageAddr, U32 nSecondPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 * nPageBuffer, U8 * nSpareBuffer, int nEccOnOff);
++extern NAND_IO_ERROR NAND_IO_ReadTwoPlaneLastPage(NAND_IO_DEVINFO * nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 * nPageBuffer, U8 * nSpareBuffer, int nEccOnOff);
++extern NAND_IO_ERROR NAND_IO_ReadUserSizePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nColumnAddr, U32 nReadSize, U8 *nReadBuffer );
++
++extern NAND_IO_ERROR NAND_IO_WriteSpare( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8* nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_WritePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_WritePageMTD(NAND_IO_DEVINFO * nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 * nPageBuffer, U8 * nSpareBuffer, int nEccOnOff);
++extern NAND_IO_ERROR NAND_IO_WriteCachePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_WriteTwoPlanePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_WriteTwoPlaneLastPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8* nSpareBuffer, int LastPage, int nEccOnOff );
++extern NAND_IO_ERROR NAND_IO_WriteUserSizePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nColumnAddr, U32 nWriteSize, U8 *nWriteBuffer );
++extern NAND_IO_ERROR NAND_IO_MakeBootBinary( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer );
++
++extern NAND_IO_ERROR NAND_IO_CopyBackPage( NAND_IO_DEVINFO *nDevInfo, U32 nDesPageAddr, U32 nSrcPageAddr );
++extern NAND_IO_ERROR NAND_IO_CopyBackTwoPlanePage( NAND_IO_DEVINFO *nDevInfo, U32 nDesPageAddr, U32 nSrcPageAddr );
++
++extern NAND_IO_ERROR NAND_IO_EraseBlock( NAND_IO_DEVINFO *nDevInfo, U32 nBlockPageAddr, int nFormatMode );
++extern NAND_IO_ERROR NAND_IO_EraseBlockForTwoPlane( NAND_IO_DEVINFO *nDevInfo, U32 nBlockPageAddr, int nFormatMode );
++
++extern NAND_IO_ERROR NAND_IO_GetFactoryBadMarkOfPBlock( NAND_IO_DEVINFO *nDevInfo, U32 nBlockPageAddr );
++extern NAND_IO_ERROR NAND_IO_GetUID( NAND_IO_DEVINFO *nDevInfo, U16 *nCmd, U8 *rReadData );
++extern NAND_IO_ERROR NAND_IO_WaitBusyCheckForWriteEnd( NAND_IO_DEVINFO *nDevInfo );
++
++extern NAND_IO_ERROR NAND_IO_EncDecodeBinary( unsigned int nEncDec, unsigned int nEccType, unsigned int nDataSize, U8 *nPageBuffer, U8 *nEccBuffer );
++extern void NAND_IO_SetInterLeavePageAddr(U32 nPageAddr );
++extern void NAND_IO_SetInterleaveStatus( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr );
++
++extern NAND_IO_ERROR NAND_IO_IRQ_ReadPagePreProcess( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U32 *rEccBuffer, U16 nChipNo );
++extern void NAND_IO_IRQ_ReadPagePostProcess( void );
++extern void NAND_IO_IRQ_Read512DataPreProcess( NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_IRQ_Read512DataPostProcess( NAND_IO_DEVINFO *nDevInfo, U8* nPageBuffer, U8* nSpareBuffer );
++
++extern NAND_IO_ERROR NAND_IO_IRQ_WritePagePreProcess( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U8 *nSpareBuffer, U32 *rEccBuffer, U16 nChipNo, U8 nWriteMode );
++extern void NAND_IO_IRQ_WritePageMidProcess( NAND_IO_DEVINFO *nDevInfo, U8 nWriteMode );
++extern void NAND_IO_IRQ_WritePagePostProcess( void );
++void NAND_IO_IRQ_Write512DataPreProcess( NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_IRQ_Write512DataPostProcess( NAND_IO_DEVINFO *nDevInfo, U8* nECCBuffer );
++
++extern NAND_IO_ERROR NAND_IO_IRQ_ExtInterruptClear(unsigned int irq);
++
++extern void NAND_IO_IRQ_ReadyBusySet( void );
++extern void NAND_IO_IRQ_ReadyBusyClear( void );
++
++extern void NAND_IO_IRQ_SetupDMA( void *pDST, int nMode );
++extern void NAND_IO_IRQ_SetupDMAForSpare( int nDSize );
++
++extern void NAND_IO_WriteColAddr( U32 nColumnAddr, NAND_IO_DEVINFO *nDevInfo );
++extern void NAND_IO_SetCommCycleTime( void );
++extern void NAND_IO_SetReadCycleTime(void);
++extern NAND_IO_ERROR NAND_IO_WriteSpareData( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nPageEccOnOff );
++#if defined (NAND_LBA_INCLUDE)
++extern NAND_IO_ERROR NAND_IO_LBA_SetCallBackHandler( NAND_LBA_CALLBACK_HANDLER pCallBackHandler );
++extern NAND_IO_ERROR NAND_IO_LBA_GetSerialNumber( NAND_IO_DEVINFO *nDevInfo, U8* nPageBuffer, U8* rSerialNumber, U16 nSize );
++extern NAND_IO_ERROR NAND_IO_LBA_PowerSaveMode( NAND_IO_DEVINFO *nDevInfo, int nOnOff );
++extern NAND_IO_ERROR NAND_IO_LBA_HighSpeedMode( NAND_IO_DEVINFO *nDevInfo, int nOnOff );
++extern NAND_IO_ERROR NAND_IO_LBA_DeviceReboot( NAND_IO_DEVINFO *nDevInfo );
++
++extern NAND_IO_ERROR NAND_IO_LBA_GetDeviceInfo( U16 nChipNo, NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_LBA_GetDeviceMDPSectorSize( NAND_IO_DEVINFO *nDevInfo, unsigned long int *rTotalSector );
++extern NAND_IO_ERROR NAND_IO_LBA_GetDeviceMediaNums( U16 *rMediaOrder );
++extern NAND_IO_ERROR NAND_IO_LBA_Init( U16 nChipNo, NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_LBA_InitDrive( NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_LBA_ReadSectorBy4Byte( NAND_IO_DEVINFO *nDevInfo, U8 nPartition, U32 nSectorAddr, U16 nOffset, U16 nReadSize, U8 *nReadBuffer );
++extern NAND_IO_ERROR NAND_IO_LBA_ReadSector( NAND_IO_DEVINFO *nDevInfo, U8 nPartition, U32 nSectorAddr, U16 nSecSize, U8 *nReadBuffer );
++extern NAND_IO_ERROR NAND_IO_LBA_ReadSysSectionOfVFP( NAND_IO_DEVINFO *nDevInfo, U32 nStarAddr, U32 nReadByteSize, U8 *nPageBuffer );
++extern NAND_IO_ERROR NAND_IO_LBA_WriteSector( NAND_IO_DEVINFO *nDevInfo,U8 nPartition, U32 nSectorAddr, U16 nSecSize, U8 *nWriteBuffer );
++extern NAND_IO_ERROR NAND_IO_LBA_WriteSysSectionOfVFP( NAND_IO_DEVINFO *nDevInfo, U32 nStarAddr, U32 nWriteByteSize, U8 *nPageBuffer );
++extern NAND_IO_ERROR NAND_IO_LBA_AREAClear( NAND_IO_DEVINFO *nDevInfo, U8 nPartition );
++extern NAND_IO_ERROR NAND_IO_LBA_ModeChange( NAND_IO_DEVINFO *nDevInfo, int nMode );
++extern NAND_IO_ERROR NAND_IO_LBA_ScanHeaderOfVFP( NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_LBA_MakeHeaderOfVFP( NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_LBA_Read2Status( NAND_IO_DEVINFO *nDevInfo );
++extern NAND_IO_ERROR NAND_IO_LBA_GetTotalSecAndCHS( NAND_IO_DEVINFO *nDevInfo, int nPartition, U32 *rTotalSec, U16 *rCylinder, U16 *rHead, U8 *rSector );
++extern NAND_IO_ERROR NAND_IO_LBA_CacheFlush( NAND_IO_DEVINFO *nDevInfo );
++#endif //NAND_LBA_INCLUDE
++
++#endif
++
+diff --git a/drivers/block/tcc/inc/tnftl/tnftl_v6.h b/drivers/block/tcc/inc/tnftl/tnftl_v6.h
+new file mode 100644
+index 0000000..930bdc8
+--- /dev/null
++++ b/drivers/block/tcc/inc/tnftl/tnftl_v6.h
+@@ -0,0 +1,614 @@
++/**************************************************************************************
++ *
++ * TELECHIPS Co.
++ *
++ * 6th floor Corad Bldg 1000-12 Daechi-dong, KangNam-ku, Seoul, Korea
++ * ====================================================================================
++ *
++ * Name: Hyun-Chul Hong
++ * Phone: 82-2-3443-6792
++ * E-mail: hchong@telechips.com
++ *
++ * FILE NAME: TNFTL.H
++ *
++ * DESCRIPTION:
++ * This is a Header File for TNFTL [ Telechips Nand Flash Translation Layer ]
++ *
++ *
++ * FILE HISTORY:
++ * Date: 2005.04.19 Start source coding By Hyunchul Hong
++ *
++ **************************************************************************************/
++#ifndef __TNFTL_H
++#define __TNFTL_H
++
++#if defined(_LINUX_)
++#include <tnftl/nand_io_v6.h>
++#elif defined(_WINCE_)
++#include "nand_io_v6.h"
++#else
++#include "nand_io_v6.h"
++#endif
++#if defined(TCC92XX) || defined(TCC89XX)
++#define TNFTL_V6_INCLUDE
++#elif defined(TCC82XX)||defined(TCC83XX)||defined(TCC79X) || defined(TCC81XX) || defined(TCC80XX)
++#define TNFTL_V5_INCLUDE
++#else
++#define TNFTL_V4_INCLUDE
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ General DEFINE & TYPEDEF ]
++//*
++//*
++//*****************************************************************************
++#ifndef NOT_USED
++#define NOT_USED 0
++#endif
++#ifndef USED
++#define USED 1
++#endif
++#ifndef DISABLE
++#define DISABLE 0
++#endif
++#ifndef ENABLE
++#define ENABLE 1
++#endif
++#ifndef FALSE
++#define FALSE 0
++#endif
++#ifndef TRUE
++#define TRUE 1
++#endif
++#ifndef NULL
++#define NULL 0
++#endif
++#ifndef TNFTL_U16_NULL
++#define TNFTL_U16_NULL 0xFFFF
++#endif
++#ifndef TNFTL_U32_NULL
++#define TNFTL_U32_NULL 0xFFFFFFFF
++#endif
++
++#ifndef _U8_
++#define _U8_
++typedef unsigned char U8;
++#endif
++#ifndef _U16_
++#define _U16_
++typedef unsigned short int U16;
++#endif
++#ifndef _U32_
++#define _U32_
++typedef unsigned int U32;
++#endif
++#ifndef _BOOL_
++#define _BOOL_
++typedef unsigned int BOOL;
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ ERROR CODE ENUMERATION ]
++//*
++//*
++//*****************************************************************************
++#ifndef SUCCESS
++#define SUCCESS 0
++#endif
++
++typedef enum
++{
++ ERR_TNFTL_NO_EXIST_NAND_FLASH = 0xA200000,
++ ERR_TNFTL_NO_BMP,
++ ERR_TNFTL_NOT_READY_IO,
++ ERR_TNFTL_NOT_READY_AREA,
++ ERR_TNFTL_NOT_EXIST_NANDFLASH,
++ ERR_TNFTL_NOT_EXIST_MEDIA_NUM_INFO,
++ ERR_TNFTL_NOT_HAVE_ENOUGH_ZONE_BLOCK,
++ ERR_TNFTL_NOT_EXIST_HIDDEN_HEADBLOCK,
++ ERR_TNFTL_NOT_EXIST_NANDBOOT_AREA,
++ ERR_TNFTL_NOT_HIDDEN_WRITE_CACHE_BLOCK,
++ ERR_TNFTL_NOT_EXIST_DATA_IN_WRITE_CACHE_PAGE_BLOCK,
++ ERR_TNFTL_NOT_FRESH_NANDFLASH,
++ ERR_TNFTL_NOT_EXIST_FTL_BAD_BLOCK_INFO,
++ ERR_TNFTL_FAILED_CHECK_BMP,
++ ERR_TNFTL_FAILED_GET_REAL_PAGE_ADDR,
++ ERR_TNFTL_FAILED_ALLOCATE_MEM_AND_LINK_DRIVER,
++ ERR_TNFTL_FAILED_GOLDEN_PAGE,
++ ERR_TNFTL_FAILED_GET_SHIFT_FACTOR_FOR_MULTIPLY,
++ ERR_TNFTL_FAILED_GET_EMPTY_RAW_BLOCK,
++ ERR_TNFTL_FAILED_MAKE_BMP,
++ ERR_TNFTL_FAILED_GET_MEDIA_UID,
++ ERR_TNFTL_FAILED_GET_MEDIA_SID,
++ ERR_TNFTL_FAILED_GET_PBLOCK_STATUS_ON_BMP,
++ ERR_TNFTL_FAILED_GET_NANDBOOT_AREA,
++ ERR_TNFTL_FAILED_MAKE_HIDDEN_LBT_BLOCK,
++ ERR_TNFTL_FAILED_GET_EMPTY_HIDDEN_BLOCK,
++ ERR_TNFTL_FAILED_MAKE_HIDDEN_AREA,
++ ERR_TNFTL_FAILED_GET_FTL_PAGE_ADDRESS_OF_SECTOR_ADDRESS,
++ ERR_TNFTL_FAILED_GET_HIDDEN_WRITE_CACHE_NUMBER,
++ ERR_TNFTL_FAILED_GET_HIDDEN_WRITE_MAINPB_INFO,
++ ERR_TNFTL_FAILED_GET_EMPTY_FTL_BLOCK_FOR_WRITE_CACHE,
++ ERR_TNFTL_FAILED_GET_EMPTY_FTL_BLOCK,
++ ERR_TNFTL_FAILED_GET_EMPTY_PHYSICAL_BLOCK,
++ ERR_TNFTL_FAILED_GET_LPTSCAN_BUFFER,
++ ERR_TNFTL_TRY_ERASE_0TH_BLOCK,
++ ERR_TNFTL_OVERSIZE_ZONES,
++ ERR_TNFTL_WRONG_PARAMETER,
++ ERR_TNFTL_WCACHE_FORCE_FLUSH,
++ ERR_TNFTL_PBLOCK_IS_BAD_BLOCK,
++ ERR_TNFTL_LPT_CORRUPTED_SEG_NO,
++ ERR_TNFTL_CORRUPTED_HIDDEN_AREA,
++ ERR_TNFTL_SET_OVER_HIDDEN_PAGE_SIZE,
++ ERR_TNFTL_OVERSIZE_MULTIHIDDEN_NUM,
++ ERR_TNFTL_HAVE_MANY_BAD_BLOCKS_IN_ZONE,
++ ERR_TNFTL_MEDIA_HAVE_OVERSIZE_BAD_BLOCKS,
++ ERR_TNFTL_IMPOSSIBLE_TO_SET_SIZE_OF_DATA_AREA,
++ ERR_TNFTL_NANDBOOT_AREA_OVER_SIZE,
++ ERR_TNFTL_HIDDEN_AREA_OVER_SIZE,
++ ERR_TNFTL_DEBUG_WRONG_PARAMETER,
++ ERR_TNFTL_DEBUG_WRONG_COMMAND_PARAMETERS,
++ ERR_TNFTL_DEBUG_WRONG_RECEIVED_SECTOR_DATA,
++ ERR_TNFTL_DEBUG_WRONG_SEND_SECTOR_DATA,
++ ERR_TNFTL_WRONG_CRC_CODE_NANDBOOT_ROMFILE,
++ ERR_TNFTL_WRONG_MATCH_UID_NBAREA,
++ ERR_TNFTL_OVERSIZE_PPAGE_NUM,
++ ERR_TNFTL_OVERSIZE_MTD_AREA_SIZE
++} TNFTL_ERROR;
++
++//*****************************************************************************
++//*
++//*
++//* [ INTERNAL DEFINATION ]
++//*
++//*
++//*****************************************************************************
++#define TNFTL_MAX_SUPPORT_DRIVER 2
++#define TNFTL_MAX_SUPPORT_MULTI_NANDFLASH 4
++#define TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE 16384 // 4096*2(Parallel)*2(MultiPlane)
++#define TNFTL_MAX_SUPPORT_NAND_IO_SPARE_SIZE 512 // 128*4
++#define TNFTL_MAX_SUPPORT_NAND_IO_SECTOR_SIZE_PER_1PAGE 32 // 16384 / 512
++#define TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE_PER_1BLOCK 512 // PpB * 2 (Multi-Plane) * 2 (InterLeave)
++#define TNFTL_MAX_SUPPORT_MULTI_PLANE 4
++#define TNFTL_MAX_SUPPORT_SHIFT_MULTI_PLANE 2
++#define TNFTL_MAX_SUPPORT_BAD_BLOCKS_IN_1ZONE 20
++#define TNFTL_MAX_SUPPORT_NB_AND_HD_AREA_BLOCK_SIZE 900 // 900 Blocks
++#define TNFTL_MAX_VALID_BAD_BLOCK_PER_1ZONE 40
++#define TNFTL_MAX_SUPPORT_ZONE 32
++#define TNFTL_MAX_SUPPORT_NAND_PPAGE_NUM 32
++
++#define TNFTL_PLANE_0 0
++#define TNFTL_PLANE_1 1
++#define TNFTL_PLANE_2 2
++#define TNFTL_PLANE_3 3
++
++#define TNFTL_PHY_BLOCKS_1ZONE 1024
++#define TNFTL_PHY_BLOCKS_1ZONE_SHIFT 10 // 2^10 = 1024
++
++#define TNFTL_BMP_HEADER_SIZE 8 // 8Bytes
++#define TNFTL_BMP_FLAGS_IN_1BYTE 4 // Flag Size is 2Bit
++#define TNFTL_BMP_FLAGS_IN_1BYTE_SHIFT 2 // Shift Factor
++#define TNFTL_BMP_START_PAGE 2
++#define TNFTL_BMP_BAD_BLOCK_CACHE_SIZE 64 // 64*2 = 128Bytes
++#define TNFTL_BMP_STATUS_OK 0x0000
++#define TNFTL_BMP_STATUS_FAIL_NO_BMP1_SERIAL 0x0001
++#define TNFTL_BMP_STATUS_FAIL_NO_BMP1_PARALLEL 0x0010
++#define TNFTL_BMP_STATUS_FAIL_NO_BMP2_PARALLEL 0x0100
++#define TNFTL_BMP_STATUS_FAIL_OTHER_REASON 0x1000
++
++#define TNFTL_BSA_SCAN_BY_FACTORY_MARK 0
++#define TNFTL_BSA_SCAN_BY_CHECK_PATTERN 1
++#define TNFTL_BSA_GET_BY_BMP 0
++#define TNFTL_BSA_GET_BY_CHECK 1
++#define TNFTL_BSA_GET_BY_SPARE 2
++#define TNFTL_BSA_GET_BY_FTLBBINFO 3
++
++#define TNFTL_LPT_NOT_CHANGED 0x00
++#define TNFTL_LPT_CHANGED 0x01
++#define TNFTL_LPT_TABLE_VALUES_1PAGE 128
++#define TNFTL_LPT_TABLE_VALUES_1PAGE_SHIFT 7
++#define TNFTL_LPT_TABLE_PAGES_1BLOCK 8
++#define TNFTL_LPT_TABLE_PAGES_1BLOCK_SHIFT 3
++#define TNFTL_LPT_TABLE_VALUES_1BLOCK 1024
++#define TNFTL_LPT_TABLE_VALUES_1BLOCK_SHIFT 10
++#define TNFTL_LPT_TABLE_DATA_START_PAGE 1
++
++#define TNFTL_MAX_SERIAL_NUMBER_SIZE 32
++#define TNFTL_MAX_NANDFLASH_SID_SIZE 32
++#define TNFTL_MAX_NANDFLASH_UID_SIZE 16
++
++#define TNFTL_HIDDEN_DEFAULT_TOTAL_SECTOR_SIZE 6083
++#define TNFTL_HIDDEN_DEFAULT_SPARE_BLOCK_SIZE 8
++#define TNFTL_HIDDEN_BLOCK_SIZE_FOR_SYSTEM_BLOCK 3 // HEAD 1 + LBT BLOCK 2
++
++#define TNFTL_MAX_SUPPORT_MULTI_HIDDEN_AREA_NUM 10
++
++#define TNFTL_BAA_INVALID_BLOCK_MARK1 0xFF
++#define TNFTL_BAA_INVALID_BLOCK_MARK2 0xEE
++#define TNFTL_BAA_INVALID_ADDRESS 0xFFFFFE
++#define TNFTL_INVALID_LOG_ADDRESS 0xFFFFFFEE
++
++#define TNFTL_BLOCK_AREA_MASK 0xF0
++#define TNFTL_BLOCK_AREA_DATA_AREA 0x10
++#define TNFTL_BLOCK_AREA_HIDDEN_AREA 0x20
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA0 0x30
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA1 0x40
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA2 0x50
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA3 0x60
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA4 0x70
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA5 0x80
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA6 0x90
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA7 0xA0
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA8 0xB0
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA9 0xC0
++#define TNFTL_BLOCK_AREA_NANDBOOT_AREA 0xE0
++
++#define TNFTL_BLOCK_TYPE_MASK 0x0F
++#define TNFTL_BLOCK_TYPE_HEADER 0x01
++#define TNFTL_BLOCK_TYPE_LBT 0x02
++#define TNFTL_BLOCK_TYPE_DATA 0x03
++#define TNFTL_BLOCK_TYPE_WRITE_CACHE_PAGE 0x05
++#define TNFTL_BLOCK_TYPE_WRITE_CACHE_PAGE_2 0x06
++#define TNFTL_BLOCK_TYPE_WRITE_CACHE_SUB 0x07
++
++#define TNFTL_BLOCK_TYPE_WRITE_CACHE_PAGE_SERIAL 0x08
++#define TNFTL_BLOCK_TYPE_WRITE_CACHE_PAGE_2_SERIAL 0x09
++
++#define TNFTL_WRITE_CACHE_PAGE_OFFSET 0x01
++
++#define TNFTL_READ_SECTOR_FROM_NULL_BLOCK 0x00
++#define TNFTL_READ_SECTOR_FROM_MAIN_BLOCK 0x01
++#define TNFTL_READ_SECTOR_FROM_WCACHE_SUB_BLOCK 0x02
++#define TNFTL_READ_SECTOR_FROM_WCACHE_PAGE_BLOCK 0x03
++#define TNFTL_WRITE_SECTOR_TO_MAIN_BLOCK 0x04
++#define TNFTL_WRITE_SECTOR_TO_WCACHE_SUB_BLOCK 0x05
++#define TNFTL_WRITE_SECTOR_TO_WCACHE_PAGE_BLOCK 0x06
++
++#define TNFTL_FORMAT_AREA_QUICK_LEVEL 0x00
++#define TNFTL_FORMAT_AREA_LOW_LEVEL 0x01
++#define TNFTL_FORMAT_RWAREA_QUICK_LEVEL 0x02
++#define TNFTL_FORMAT_INTERNAL_QUICK_LEVEL 0x03
++
++typedef void (*TNFTL_CALLBACK_HANDLER) ( U16 nDrvNo, U16 nStatusCode, U32 wParam );
++#define TNFTL_CALLBACK_LCD_MAKE_HIDDEN_PAGE_START 0x00
++#define TNFTL_CALLBACK_LCD_MAKE_HIDDEN_PAGE_PROCESS 0x01
++#define TNFTL_CALLBACK_LCD_MAKE_HIDDEN_PAGE_STOP 0x02
++#define TNFTL_CALLBACK_LCD_FORMAT_START 0x03
++#define TNFTL_CALLBACK_LCD_FORMAT_PROCESS 0x04
++#define TNFTL_CALLBACK_LCD_FORMAT_STOP 0x05
++#define TNFTL_CALLBACK_LCD_BMP_UPDATE_START 0x06
++#define TNFTL_CALLBACK_LCD_BMP_UPDATE_PROCESS 0x07
++#define TNFTL_CALLBACK_LCD_BMP_UPDATE_STOP 0x08
++
++#define PHY_BAD_BLOCK_MASK 0xFF000000
++#define PHY_BAD_BLOCK_0 0x01000000
++#define PHY_BAD_BLOCK_1 0x02000000
++#define PHY_BAD_BLOCK_2 0x04000000
++#define PHY_BAD_BLOCK_3 0x08000000
++#define PHY_BAD_BLOCK_4 0x10000000
++#define PHY_BAD_BLOCK_5 0x20000000
++#define PHY_BAD_BLOCK_6 0x40000000
++#define PHY_BAD_BLOCK_7 0x80000000
++
++#define WCACHE_NORMAL_USED_MODE 0x00
++#define WCACHE_FORCE_SETUP_MODE 0x01
++
++#define WCACHE_SERIAL_PAGE_MODE 0x00
++#define WCACHE_NORMAL_PAGE_MODE 0x01
++
++#define RCACHE_HIT_SLOT_ENTRY 0x00
++#define RCACHE_NOHIT_SLOT_ENTRY 0x01
++#define RCACHE_MAKE_NEW_SLOT_ENTRY 0x02
++
++#define TNFTL_SECURE_SIZE 0x20000 // 128KBytes
++
++//*****************************************************************************
++//*
++//*
++//* [ INTERNAL STRUCT DEFINE ]
++//*
++//*
++//*****************************************************************************
++typedef void (*TNFTL_FUNC1)(void);
++typedef void (*TNFTL_FUNC2)(unsigned int, unsigned int);
++typedef void (*TNFTL_FUNC3)(unsigned int);
++
++typedef unsigned long int TNFTL_LPT_TABLE_VALUE;
++typedef unsigned long int TNFTL_LPT_BLOCK;
++typedef unsigned long int TNFTL_RCACHE_SLOT;
++
++typedef struct __tag_TNFTL_LPT
++{
++ unsigned short int Usable;
++ unsigned short int Changed;
++ unsigned short int SegNo;
++ unsigned short int MaxTableBlkNums;
++ unsigned short int CurrentPlane;
++ TNFTL_LPT_BLOCK *BlkNo;
++ TNFTL_LPT_TABLE_VALUE Tables[TNFTL_LPT_TABLE_VALUES_1BLOCK];
++
++} TNFTL_LPT;
++
++typedef struct __tag_TNFTL_MAINPB_INFO
++{
++ unsigned short int Used;
++ unsigned long int LBNo;
++ unsigned long int MainPBNo;
++ unsigned short int WrEndPage;
++} TNFTL_MAINPB_INFO;
++
++typedef struct __tag_TNFTL_ALIGNCACHE_INFO
++{
++ unsigned short int Usable;
++ unsigned short int CurUsedSecSize;
++ unsigned long int StartSecAddr;
++ unsigned long int LimitSecSize;
++
++} TNFTL_ALIGNCACHE_INFO;
++
++typedef struct __tag_TNFTL_READ_CACHE
++{
++ unsigned short int Used;
++ unsigned short int OneSlotSize;
++ unsigned short int ShiftOneSlotSize;
++ unsigned short int HitEntryPos;
++ unsigned short int lastSlotNo;
++ unsigned short int MaxSlotNums;
++ unsigned long int MaxMemorySize;
++
++ TNFTL_RCACHE_SLOT *Entry;
++} TNFTL_RCACHE;
++
++
++typedef struct __tag_TNFTL_WRITE_CACHE
++{
++ unsigned short int Used;
++ unsigned short int CacheNo;
++
++ unsigned short int PageCacheMode;
++
++ unsigned long int UsedNo;
++ unsigned long int LBNo;
++ unsigned long int MainPBNo;
++ unsigned long int SubPBNo;
++ unsigned long int PagePBNo;
++ unsigned long int PagePBNo2;
++
++ unsigned long int nPoint;
++
++ unsigned short int MainPBWrEndPage;
++ unsigned short int SubPBWrEndPage;
++ unsigned short int PagePBWrEndPage;
++
++ unsigned short int PageLastPBPageNo;
++
++ unsigned short int PagePBStatus[TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE_PER_1BLOCK * 2];
++
++} TNFTL_WCACHE;
++
++typedef struct __tag_TNFTL_RO_AREA
++{
++ unsigned short int Usable;
++ unsigned long int BlkAreaCode;
++
++ unsigned long int StPB; // Start Block Number [ FTL Blcok Addr ]
++ unsigned long int EdPB; // End Block Number [ FTL Blcok Addr ]
++ unsigned long int PBpV; // Physical Block Size
++
++ unsigned long int StPBAddr; // Start Phy Block Addr
++ unsigned long int EdPBAddr; // End Phy Block Addr
++
++} TNFTL_RO_AREA;
++
++typedef struct __tag_TNFTL_RW_AREA
++{
++ unsigned short int Usable;
++ unsigned long int BlkAreaCode;
++ unsigned long int HeaderBlkAddr;
++
++ unsigned long int PBpV; // Physical Blocks
++ unsigned long int DataPBpV; // Area Data Block Size
++ unsigned long int DataPPpV; // Area Data Page Size
++ unsigned long int TotalSectorSize;
++ unsigned short int FlagOfChangeTotalSectorSize;
++ unsigned short int LptNums; // Area Needs LPT Number
++ unsigned short int WCacheNums; // Write Cache Number
++ unsigned short int WCacheMode;
++ unsigned long int WCacheDataStartLBNo;
++
++ unsigned short int MainPBInfoNums; // Main page info Number
++
++ unsigned short int RCacheUsable;
++ unsigned short int DrvStatus; // Status of Drive
++ unsigned long int TotalDiskSector; // Total Disk Sector
++ unsigned short int Cylinder;
++ unsigned short int Head;
++ unsigned char Sector;
++
++ TNFTL_LPT Lpt;
++ TNFTL_MAINPB_INFO *MainPBInfo;
++ TNFTL_WCACHE *WCaches;
++ TNFTL_RCACHE RCaches;
++
++ unsigned char *ReadCacheBuffer;
++} TNFTL_RW_AREA;
++
++typedef struct __tag_TNFTL_DRVINFO
++{
++ TNFTL_RO_AREA NBArea; // NANDBOOT Area
++ TNFTL_RW_AREA DTArea; // Data Area
++ TNFTL_RW_AREA HDArea; // Hidden Area
++ TNFTL_RW_AREA *MultiHDArea; // Multi Hidden Area
++
++ TNFTL_ALIGNCACHE_INFO AlignCache;
++
++ unsigned short int MultiHiddendNums; // Multi Hidden Area Num
++
++ unsigned char NANDType;
++ unsigned short int IoStatus;
++ unsigned short int IoDrvNo;
++ unsigned short int IoStCS;
++ unsigned short int IoEdCS;
++ unsigned short int IoBMPFlag; // Flag of BMP
++ unsigned long int DrvReturnValue;
++
++ unsigned long int PBpV; // Physical all Blocks
++ unsigned short int BBpZ; // Bad Blocks per 1ZONE
++ unsigned short int PpB; // Pages Per Block
++ unsigned short int PageSize; // PageSize
++ unsigned short int SpareSize; // SpareSize
++ unsigned short int PPages; // Total Partial Pages [ 512+16Bytes ]
++ unsigned short int ShiftPpB; // Shift Factor of Pages Per Block
++ unsigned short int ShiftPPages; // Shift Factor of Total Partial Pages
++
++ unsigned long int RwAreaStBlk; // RW Area Start Block Addr
++ unsigned long int RwAreaEdBlk; // RW Area End Block Addr
++ unsigned long int ROAreaSize; // RO Area Size
++ unsigned long int ROAreaBlkNum;
++ unsigned short int RWAreaFormatFlag;
++
++ unsigned short int MPlanePpB; // FTLInfo->PpB >> FTLInfo->ShiftMPlane
++ unsigned short int ILMPlanePpB; // FTLInfo->PpB >> 2
++ unsigned short int MPlane; // Multi Plane Num
++ unsigned short int ShiftMPlane; // Shift Factor of Multi Plane
++ unsigned long int RoundMPlane;
++ unsigned long int RemainMPlane;
++ unsigned long int LPTBufferSize;
++
++ unsigned short int LPT_Values_1Page;
++ unsigned short int LPT_Values_1Page_Shift;
++ unsigned short int LPT_Pages_1Block;
++ unsigned short int LPT_Pages_1Block_Shift;
++ unsigned short int LPT_Block_PPage;
++
++ unsigned short int FTLBadBlockStatus;
++ unsigned long int FTLBadBlockNum;
++ unsigned long int FTLBadBlock[TNFTL_MAX_VALID_BAD_BLOCK_PER_1ZONE * TNFTL_MAX_SUPPORT_ZONE];
++
++ unsigned short int MediaNums;
++ unsigned short int ShiftMediaNums;
++ unsigned short int MediaBadBlockNum[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++
++ unsigned short int ECCStatus;
++
++ unsigned char MediaSizeOfSerialID;
++ unsigned char MediaSizeOfUniqueID;
++ unsigned char MediaSerialID[TNFTL_MAX_NANDFLASH_SID_SIZE];
++ unsigned char MediaUniqueID[TNFTL_MAX_NANDFLASH_UID_SIZE];
++ unsigned long int MediaTotalFTLPageAddr[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++ unsigned long int MediaTotalFTLBlkAddr[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++ unsigned short int MediaRatioPSize[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++ unsigned short int MediaRatioBSize[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++ unsigned short int MediaRatioShiftPSize[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++ unsigned short int MediaRatioShiftBSize[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++ unsigned long int StPBForGetEmptyPB[TNFTL_MAX_SUPPORT_MULTI_PLANE];
++ NAND_IO_DEVINFO MediaDevInfo[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++
++ unsigned char *FTLPageBuffer;
++ unsigned char *AlignCacheBuffer;
++ unsigned int *LPTBuffer;
++
++} TNFTL_DRVINFO;
++
++//*****************************************************************************
++//*
++//*
++//* [ EXTERNAL VARIABLE DEFINE ]
++//*
++//*
++//*****************************************************************************
++
++
++
++//*****************************************************************************
++//*
++//*
++//* [ EXTERNAL FUCTIONS DEFINE ]
++//*
++//*
++//*****************************************************************************
++extern void TNFTL_SetROAreaSize( TNFTL_DRVINFO * FTLInfo, int nROAreaSize );
++
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForDriver( U16 nDrvNo, TNFTL_DRVINFO *nMDrvInfo, TNFTL_DRVINFO **nPDrvInfo );
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForLPT( U16 nDrvNo, TNFTL_RW_AREA *nArea, TNFTL_LPT_BLOCK *nLptTableBlk, U32 nLptTableBlkSize );
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForWCACHE( U16 nDrvNo, TNFTL_RW_AREA *nArea, TNFTL_WCACHE *nWCaches, U32 nWCacheNum );
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForRCACHE( U16 nDrvNo, TNFTL_RW_AREA *nArea, TNFTL_RCACHE_SLOT *nRCacheSlots );
++
++
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForMainPBInfo( U16 nDrvNo, TNFTL_RW_AREA *nArea, TNFTL_MAINPB_INFO *nMainPBInfo, U32 nMainPBInfoNum );
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForPageBuffer( U16 nDrvNo, U8 *nPageBuffer );
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForRCacheBuffer( U16 nDrvNo, TNFTL_RW_AREA *nArea, U8 *nPageBuffer, U32 nBufferSize );
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForAlignCacheBuffer( U16 nDrvNo, U8 *nPageBuffer, U32 nBufferSize );
++
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForMakeLPT( U16 nDrvNo, U32 *nLPTBuffer, U32 nBufferSize );
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForMultiHidden( U16 nDrvNo, TNFTL_RW_AREA *nArea );
++extern TNFTL_ERROR TNFTL_SetStEdOfCS( U16 nDrvNo, U16 nStartCS, U16 nEndCS );
++extern TNFTL_ERROR TNFTL_SetMultiHiddenNums( U16 nDrvNo, U16 nMHiddenNums );
++
++extern void TNFTL_DEBUG_Init( void );
++extern void TNFTL_DEBUG_Init_Function( TNFTL_FUNC1 nFUNC1, TNFTL_FUNC2 nFUNC2, TNFTL_FUNC2 nFUNC3, TNFTL_FUNC2 nFUNC4, TNFTL_FUNC2 nFUNC5, TNFTL_FUNC3 nFUNC6, TNFTL_FUNC1 nFUNC7, TNFTL_FUNC1 nFUNC8);
++
++extern TNFTL_ERROR TNFTL_DEBUG_VTCParser( void* nVTCCmd );
++extern void TNFTL_Init( U16 nDrvNo );
++extern TNFTL_ERROR TNFTL_InitDrive( TNFTL_DRVINFO *FTLInfo );
++extern TNFTL_ERROR TNFTL_CheckIsExistBMP( TNFTL_DRVINFO *FTLInfo );
++
++extern TNFTL_ERROR TNFTL_AlignCacheFlush( TNFTL_DRVINFO *FTLInfo );
++
++extern U32 TNFTL_AREAGetTotalSectorSize( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea );
++extern TNFTL_ERROR TNFTL_AREAGetTotalSecAndCHS( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, U32 *rTotalSec, U16 *rCylinder, U16 *rHead, U8 *rSector );
++extern TNFTL_ERROR TNFTL_AREASetTotalSectorSize( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, U32 nTotalSectorSize );
++extern TNFTL_ERROR TNFTL_AREAReadSectorBy4Byte( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, U32 nSectorAddr, U16 nOffset, U16 nReadSize, U8 *nReadBuffer );
++extern TNFTL_ERROR TNFTL_AREAReadSector( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, U32 nSectorAddr, U32 nSecSize, U8 *nReadBuffer );
++extern TNFTL_ERROR TNFTL_AREAWriteSector( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, U32 nSectorAddr, U32 nSecSize, U8 *nWriteBuffer );
++extern TNFTL_ERROR TNFTL_AREAFormat( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, U16 nFormatLevel );
++extern TNFTL_ERROR TNFTL_NBGetCRCOfImageFile( TNFTL_DRVINFO *FTLInfo, U32 nFlagSelfChecking, U32 *nOrgCRCcode1, U32 *nOrgCRCcode2, U32 *nRomFileSize, U32 *rRstCRCcode1, U32 *rRstCRCcode2 );
++extern TNFTL_ERROR TNFTL_NBGetCRCValueOfImageFile( TNFTL_DRVINFO *FTLInfo, U32 *nOrgCRCcode1, U32 *nOrgCRCcode2, U32 *nRomFileSize );
++extern TNFTL_ERROR TNFTL_NBGetSizeOfImageFile( TNFTL_DRVINFO *FTLInfo, U32 *nRomFileSize ) ;
++extern void TNFTL_WCacheSetDataStartSector( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, unsigned int nDataStartSector );
++
++extern U16 TNFTL_GetSerialNumber( TNFTL_DRVINFO *FTLInfo, U8* rSerialNumber, U16 nSize );
++extern void TNFTL_SetFlagOfChangeTotalSecSize( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, U16 on_off );
++
++extern TNFTL_ERROR TNFTL_IOReadPhyPage( TNFTL_DRVINFO *FTLInfo, U32 nBlkAddr, U32 nPageAddr, U16 nCSorder, U8 *nReadBuffer );
++extern __inline TNFTL_ERROR TNFTL_IOReadSpare( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U8 *nSpareBuffer );
++#ifndef RVDS
++extern __inline TNFTL_ERROR TNFTL_IOReadPage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++#endif
++extern __inline TNFTL_ERROR TNFTL_IOReadPageForSignature( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++
++extern __inline TNFTL_ERROR TNFTL_IOReadTwoPlanePage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nReadOption, int nEccOnOff );
++extern __inline TNFTL_ERROR TNFTL_IOReadTwoPlaneLastPage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++#ifndef RVDS
++extern __inline TNFTL_ERROR TNFTL_IOReadUserSizePage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nColumnAddr, U32 nReadSize, U8 *nReadBuffer );
++#endif
++extern __inline TNFTL_ERROR TNFTL_IOWritePage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern __inline TNFTL_ERROR TNFTL_IOWriteTwoPlanePage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern __inline TNFTL_ERROR TNFTL_IOWriteTwoPlaneLastPage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int LastPage, int nEccOnOff );
++extern __inline TNFTL_ERROR TNFTL_IOWriteCachePage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern __inline TNFTL_ERROR TNFTL_IOWriteCacheLastPage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern __inline TNFTL_ERROR TNFTL_IOWriteUserSizePage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nColumnAddr, U32 nWriteSize, U8 *nWriteBuffer );
++extern __inline TNFTL_ERROR TNFTL_IOWriteSpare( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U8 *nSpareBuffer );
++
++extern __inline TNFTL_ERROR TNFTL_IOCopyBackPage( TNFTL_DRVINFO *FTLInfo, U32 nDesFTLPageAddr, U32 nSrcFTLPageAddr, U8 *nPageBuffer, U8 *nSpareBuffer );
++extern __inline TNFTL_ERROR TNFTL_IOEraseBlock( TNFTL_DRVINFO *FTLInfo, U32 nFTLBlkAddr, int nFormatMode );
++extern __inline TNFTL_ERROR TNFTL_IOCopyBackTwoPlanePage( TNFTL_DRVINFO *FTLInfo, U32 nDesFTLPageAddr, U32 nSrcFTLPageAddr, U8 *nPageBuffer, U8 *nSpareBuffer );
++
++extern TNFTL_ERROR TNFTL_GoldenPageWrite( TNFTL_DRVINFO *FTLInfo, U32 nStarAddr, U32 nWriteByteSize, U8 *nPageBuffer );
++extern TNFTL_ERROR TNFTL_GoldenPageRead( TNFTL_DRVINFO *FTLInfo, U32 nStarAddr, U32 nReadByteSize, U8 *nPageBuffer );
++extern TNFTL_ERROR TNFTL_SizeofGoldenPage( TNFTL_DRVINFO *FTLInfo );
++
++extern TNFTL_ERROR TNFTL_SetCallBackHandler( TNFTL_CALLBACK_HANDLER pCallBackHandler );
++extern TNFTL_ERROR TNFTL_SetUartDebug( unsigned int on_off );
++extern TNFTL_ERROR TNFTL_BMPRefresh( TNFTL_DRVINFO *FTLInfo );
++
++extern TNFTL_ERROR TNFTL_SetUseAreaReadCacheMode( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, unsigned int on_off );
++extern TNFTL_ERROR TNFTL_SetUseAlignCacheMode( TNFTL_DRVINFO *FTLInfo, unsigned int on_off );
++
++
++#endif
++
+diff --git a/drivers/block/tcc/inc/tnftl/tnftl_v7.h b/drivers/block/tcc/inc/tnftl/tnftl_v7.h
+new file mode 100644
+index 0000000..d39380b
+--- /dev/null
++++ b/drivers/block/tcc/inc/tnftl/tnftl_v7.h
+@@ -0,0 +1,667 @@
++/**************************************************************************************
++ *
++ * TELECHIPS Co.
++ *
++ * 6th floor Corad Bldg 1000-12 Daechi-dong, KangNam-ku, Seoul, Korea
++ * ====================================================================================
++ *
++ * Name: Hyun-Chul Hong
++ * Phone: 82-2-3443-6792
++ * E-mail: hchong@telechips.com
++ *
++ * FILE NAME: TNFTL.H
++ *
++ * DESCRIPTION:
++ * This is a Header File for TNFTL [ Telechips Nand Flash Translation Layer ]
++ *
++ *
++ * FILE HISTORY:
++ * Date: 2005.04.19 Start source coding By Hyunchul Hong
++ *
++ **************************************************************************************/
++#ifndef __TNFTL_H
++#define __TNFTL_H
++
++#if defined(_LINUX_)
++#include <tnftl/nand_io_v7.h>
++#elif defined(_WINCE_)
++#include "nand_io_v7.h"
++#else
++#include "nand_io_v7.h"
++#endif
++
++#if defined(TCC92XX) || defined(TCC89XX)
++#if defined(NAND_BOOT_REV)
++#define TNFTL_V7_INCLUDE
++#else
++#define TNFTL_V6_INCLUDE
++#endif
++#elif defined(TCC82XX)||defined(TCC83XX)||defined(TCC79X) || defined(TCC81XX) || defined(TCC80XX)
++#define TNFTL_V5_INCLUDE
++#else
++#define TNFTL_V4_INCLUDE
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ General DEFINE & TYPEDEF ]
++//*
++//*
++//*****************************************************************************
++#ifndef NOT_USED
++#define NOT_USED 0
++#endif
++#ifndef USED
++#define USED 1
++#endif
++#ifndef DISABLE
++#define DISABLE 0
++#endif
++#ifndef ENABLE
++#define ENABLE 1
++#endif
++#ifndef FALSE
++#define FALSE 0
++#endif
++#ifndef TRUE
++#define TRUE 1
++#endif
++#ifndef NULL
++#define NULL 0
++#endif
++#ifndef TNFTL_U16_NULL
++#define TNFTL_U16_NULL 0xFFFF
++#endif
++#ifndef TNFTL_U32_NULL
++#define TNFTL_U32_NULL 0xFFFFFFFF
++#endif
++
++#ifndef _U8_
++#define _U8_
++typedef unsigned char U8;
++#endif
++#ifndef _U16_
++#define _U16_
++typedef unsigned short int U16;
++#endif
++#ifndef _U32_
++#define _U32_
++typedef unsigned int U32;
++#endif
++#ifndef _BOOL_
++#define _BOOL_
++typedef unsigned int BOOL;
++#endif
++
++//*****************************************************************************
++//*
++//*
++//* [ ERROR CODE ENUMERATION ]
++//*
++//*
++//*****************************************************************************
++#ifndef SUCCESS
++#define SUCCESS 0
++#endif
++
++typedef enum
++{
++ ERR_TNFTL_NO_EXIST_NAND_FLASH = 0xA200000,
++ ERR_TNFTL_NO_BMP,
++ ERR_TNFTL_NOT_READY_IO,
++ ERR_TNFTL_NOT_READY_AREA,
++ ERR_TNFTL_NOT_EXIST_NANDFLASH,
++ ERR_TNFTL_NOT_EXIST_MEDIA_NUM_INFO,
++ ERR_TNFTL_NOT_HAVE_ENOUGH_ZONE_BLOCK,
++ ERR_TNFTL_NOT_EXIST_HIDDEN_HEADBLOCK,
++ ERR_TNFTL_NOT_EXIST_NANDBOOT_AREA,
++ ERR_TNFTL_NOT_HIDDEN_WRITE_CACHE_BLOCK,
++ ERR_TNFTL_NOT_EXIST_DATA_IN_WRITE_CACHE_PAGE_BLOCK,
++ ERR_TNFTL_NOT_FRESH_NANDFLASH,
++ ERR_TNFTL_NOT_EXIST_FTL_BAD_BLOCK_INFO,
++ ERR_TNFTL_FAILED_CHECK_BMP,
++ ERR_TNFTL_FAILED_GET_REAL_PAGE_ADDR,
++ ERR_TNFTL_FAILED_ALLOCATE_MEM_AND_LINK_DRIVER,
++ ERR_TNFTL_FAILED_GOLDEN_PAGE,
++ ERR_TNFTL_FAILED_GET_SHIFT_FACTOR_FOR_MULTIPLY,
++ ERR_TNFTL_FAILED_GET_EMPTY_RAW_BLOCK,
++ ERR_TNFTL_FAILED_MAKE_BMP,
++ ERR_TNFTL_FAILED_GET_MEDIA_UID,
++ ERR_TNFTL_FAILED_GET_MEDIA_SID,
++ ERR_TNFTL_FAILED_GET_PBLOCK_STATUS_ON_BMP,
++ ERR_TNFTL_FAILED_GET_NANDBOOT_AREA,
++ ERR_TNFTL_FAILED_MAKE_HIDDEN_LBT_BLOCK,
++ ERR_TNFTL_FAILED_GET_EMPTY_HIDDEN_BLOCK,
++ ERR_TNFTL_FAILED_MAKE_HIDDEN_AREA,
++ ERR_TNFTL_FAILED_GET_FTL_PAGE_ADDRESS_OF_SECTOR_ADDRESS,
++ ERR_TNFTL_FAILED_GET_HIDDEN_WRITE_CACHE_NUMBER,
++ ERR_TNFTL_FAILED_GET_HIDDEN_WRITE_MAINPB_INFO,
++ ERR_TNFTL_FAILED_GET_EMPTY_FTL_BLOCK_FOR_WRITE_CACHE,
++ ERR_TNFTL_FAILED_GET_EMPTY_FTL_BLOCK,
++ ERR_TNFTL_FAILED_GET_EMPTY_PHYSICAL_BLOCK,
++ ERR_TNFTL_FAILED_GET_LPTSCAN_BUFFER,
++ ERR_TNFTL_TRY_ERASE_0TH_BLOCK,
++ ERR_TNFTL_OVERSIZE_ZONES,
++ ERR_TNFTL_WRONG_PARAMETER,
++ ERR_TNFTL_WCACHE_FORCE_FLUSH,
++ ERR_TNFTL_PBLOCK_IS_BAD_BLOCK,
++ ERR_TNFTL_LPT_CORRUPTED_SEG_NO,
++ ERR_TNFTL_CORRUPTED_HIDDEN_AREA,
++ ERR_TNFTL_SET_OVER_HIDDEN_PAGE_SIZE,
++ ERR_TNFTL_OVERSIZE_MULTIHIDDEN_NUM,
++ ERR_TNFTL_HAVE_MANY_BAD_BLOCKS_IN_ZONE,
++ ERR_TNFTL_MEDIA_HAVE_OVERSIZE_BAD_BLOCKS,
++ ERR_TNFTL_IMPOSSIBLE_TO_SET_SIZE_OF_DATA_AREA,
++ ERR_TNFTL_NANDBOOT_AREA_OVER_SIZE,
++ ERR_TNFTL_HIDDEN_AREA_OVER_SIZE,
++ ERR_TNFTL_DEBUG_WRONG_PARAMETER,
++ ERR_TNFTL_DEBUG_WRONG_COMMAND_PARAMETERS,
++ ERR_TNFTL_DEBUG_WRONG_RECEIVED_SECTOR_DATA,
++ ERR_TNFTL_DEBUG_WRONG_SEND_SECTOR_DATA,
++ ERR_TNFTL_WRONG_CRC_CODE_NANDBOOT_ROMFILE,
++ ERR_TNFTL_WRONG_MATCH_UID_NBAREA,
++ ERR_TNFTL_OVERSIZE_PPAGE_NUM,
++ ERR_TNFTL_OVERSIZE_MTD_AREA_SIZE
++} TNFTL_ERROR;
++
++
++#define TNFTL_MAX_BLOCK_NUM_OF_NBAREA 100
++
++//*****************************************************************************
++//*
++//*
++//* [ INTERNAL DEFINATION ]
++//*
++//*
++//*****************************************************************************
++#define TNFTL_MAX_SUPPORT_DRIVER 2
++#define TNFTL_MAX_SUPPORT_MULTI_NANDFLASH 4
++#define TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE 32768 // 8192*2(Parallel)*2(MultiPlane)
++#define TNFTL_MAX_SUPPORT_NAND_IO_SPARE_SIZE 2048 // 436(:=512)*4
++#define TNFTL_MAX_SUPPORT_NAND_IO_SECTOR_SIZE_PER_1PAGE 32 // 16384 / 512
++#define TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE_PER_1BLOCK 1024 // PpB * 2 (Multi-Plane) * 2 (InterLeave)
++#define TNFTL_MAX_SUPPORT_MULTI_PLANE 4
++#define TNFTL_MAX_SUPPORT_SHIFT_MULTI_PLANE 2
++#define TNFTL_MAX_SUPPORT_BAD_BLOCKS_IN_1ZONE 20
++#define TNFTL_MAX_SUPPORT_NB_AND_HD_AREA_BLOCK_SIZE 900 // 900 Blocks
++#define TNFTL_MAX_VALID_BAD_BLOCK_PER_1ZONE 40
++#define TNFTL_MAX_SUPPORT_ZONE 32
++#define TNFTL_MAX_SUPPORT_NAND_PPAGE_NUM 32
++
++#define TNFTL_PLANE_0 0
++#define TNFTL_PLANE_1 1
++#define TNFTL_PLANE_2 2
++#define TNFTL_PLANE_3 3
++
++#define TNFTL_PHY_BLOCKS_1ZONE 1024
++#define TNFTL_PHY_BLOCKS_1ZONE_SHIFT 10 // 2^10 = 1024
++
++#define TNFTL_BMP_HEADER_SIZE 4 // 4Bytes
++#define TNFTL_BMP_FLAGS_IN_1BYTE 4 // Flag Size is 2Bit
++#define TNFTL_BMP_FLAGS_IN_1BYTE_SHIFT 2 // Shift Factor
++#define TNFTL_BMP_START_PAGE 2
++#define TNFTL_BMP_BAD_BLOCK_CACHE_SIZE 64 // 64*2 = 128Bytes
++#define TNFTL_BMP_STATUS_OK 0x0000
++#define TNFTL_BMP_STATUS_FAIL_NO_BMP1_SERIAL 0x0001
++#define TNFTL_BMP_STATUS_FAIL_NO_BMP1_PARALLEL 0x0010
++#define TNFTL_BMP_STATUS_FAIL_NO_BMP2_PARALLEL 0x0100
++#define TNFTL_BMP_STATUS_FAIL_OTHER_REASON 0x1000
++#define TNFTL_BMP_STATUS_GANG_WRITE_NAND 0x2000
++
++#define TNFTL_BSA_SCAN_BY_FACTORY_MARK 0
++#define TNFTL_BSA_SCAN_BY_CHECK_PATTERN 1
++#define TNFTL_BSA_GET_BY_BMP 0
++#define TNFTL_BSA_GET_BY_CHECK 1
++#define TNFTL_BSA_GET_BY_SPARE 2
++#define TNFTL_BSA_GET_BY_FTLBBINFO 3
++
++#define TNFTL_LPT_NOT_CHANGED 0x00
++#define TNFTL_LPT_CHANGED 0x01
++#define TNFTL_LPT_TABLE_VALUES_1PAGE 128
++#define TNFTL_LPT_TABLE_VALUES_1PAGE_SHIFT 7
++#define TNFTL_LPT_TABLE_PAGES_1BLOCK 8
++#define TNFTL_LPT_TABLE_PAGES_1BLOCK_SHIFT 3
++#define TNFTL_LPT_TABLE_VALUES_1BLOCK 1024
++#define TNFTL_LPT_TABLE_VALUES_1BLOCK_SHIFT 10
++#define TNFTL_LPT_TABLE_DATA_START_PAGE 1
++
++#define TNFTL_MAX_SERIAL_NUMBER_SIZE 32
++#define TNFTL_MAX_NANDFLASH_SID_SIZE 32
++#define TNFTL_MAX_NANDFLASH_UID_SIZE 16
++
++#define TNFTL_HIDDEN_DEFAULT_TOTAL_SECTOR_SIZE 6083
++#define TNFTL_HIDDEN_DEFAULT_SPARE_BLOCK_SIZE 8
++#define TNFTL_HIDDEN_BLOCK_SIZE_FOR_SYSTEM_BLOCK 3 // HEAD 1 + LBT BLOCK 2
++
++#define TNFTL_MAX_SUPPORT_MULTI_HIDDEN_AREA_NUM 10
++
++#define TNFTL_BAA_INVALID_BLOCK_MARK1 0xFF
++#define TNFTL_BAA_INVALID_BLOCK_MARK2 0xEE
++#define TNFTL_BAA_INVALID_ADDRESS 0xFFFFFE
++#define TNFTL_INVALID_LOG_ADDRESS 0xFFFFFFEE
++
++#define TNFTL_BLOCK_AREA_MASK 0xF0
++#define TNFTL_BLOCK_AREA_DATA_AREA 0x10
++#define TNFTL_BLOCK_AREA_HIDDEN_AREA 0x20
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA0 0x30
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA1 0x40
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA2 0x50
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA3 0x60
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA4 0x70
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA5 0x80
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA6 0x90
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA7 0xA0
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA8 0xB0
++#define TNFTL_BLOCK_AREA_MULTI_HIDDEN_AREA9 0xC0
++#define TNFTL_BLOCK_AREA_NANDBOOT_AREA 0xE0
++
++
++#define TNFTL_BLOCK_AREA_PRIMARY_PARTITION 0x10
++
++#define TNFTL_BLOCK_AREA_EXTENDED_PARTITION_0 0x20
++#define TNFTL_BLOCK_AREA_EXTENDED_PARTITION_1 0x30
++#define TNFTL_BLOCK_AREA_EXTENDED_PARTITION_2 0x40
++#define TNFTL_BLOCK_AREA_EXTENDED_PARTITION_3 0x50
++#define TNFTL_BLOCK_AREA_EXTENDED_PARTITION_4 0x60
++#define TNFTL_BLOCK_AREA_EXTENDED_PARTITION_5 0x70
++#define TNFTL_BLOCK_AREA_EXTENDED_PARTITION_6 0x80
++#define TNFTL_BLOCK_AREA_EXTENDED_PARTITION_7 0x90
++#define TNFTL_BLOCK_AREA_EXTENDED_PARTITION_8 0xA0
++#define TNFTL_BLOCK_AREA_EXTENDED_PARTITION_9 0xB0
++#define TNFTL_BLOCK_AREA_EXTENDED_PARTITION_10 0xC0
++#define TNFTL_BLOCK_AREA_EXTENDED_PARTITION_11 0xD0
++
++
++#define TNFTL_BLOCK_TYPE_MASK 0x0F
++#define TNFTL_BLOCK_TYPE_HEADER 0x01
++#define TNFTL_BLOCK_TYPE_LBT 0x02
++#define TNFTL_BLOCK_TYPE_DATA 0x03
++#define TNFTL_BLOCK_TYPE_WRITE_CACHE_PAGE 0x05
++#define TNFTL_BLOCK_TYPE_WRITE_CACHE_PAGE_2 0x06
++#define TNFTL_BLOCK_TYPE_WRITE_CACHE_SUB 0x07
++#define TNFTL_BLOCK_TYPE_WRITE_CACHE_PAGE_SERIAL 0x08
++#define TNFTL_BLOCK_TYPE_WRITE_CACHE_PAGE_2_SERIAL 0x09
++
++
++#define TNFTL_BLOCK_TYPE_NB_MASTER 0x01
++#define TNFTL_BLOCK_TYPE_NB_DATA 0x03
++#define TNFTL_BLOCK_TYPE_NB_BOOTLOADER 0x04
++
++
++#define TNFTL_WRITE_CACHE_PAGE_OFFSET 0x01
++
++#define TNFTL_READ_SECTOR_FROM_NULL_BLOCK 0x00
++#define TNFTL_READ_SECTOR_FROM_MAIN_BLOCK 0x01
++#define TNFTL_READ_SECTOR_FROM_WCACHE_SUB_BLOCK 0x02
++#define TNFTL_READ_SECTOR_FROM_WCACHE_PAGE_BLOCK 0x03
++#define TNFTL_WRITE_SECTOR_TO_MAIN_BLOCK 0x04
++#define TNFTL_WRITE_SECTOR_TO_WCACHE_SUB_BLOCK 0x05
++#define TNFTL_WRITE_SECTOR_TO_WCACHE_PAGE_BLOCK 0x06
++
++#define TNFTL_FORMAT_AREA_QUICK_LEVEL 0x00
++#define TNFTL_FORMAT_AREA_LOW_LEVEL 0x01
++
++typedef void (*TNFTL_CALLBACK_HANDLER) ( U16 nDrvNo, U16 nStatusCode, U32 wParam );
++#define TNFTL_CALLBACK_LCD_MAKE_HIDDEN_PAGE_START 0x00
++#define TNFTL_CALLBACK_LCD_MAKE_HIDDEN_PAGE_PROCESS 0x01
++#define TNFTL_CALLBACK_LCD_MAKE_HIDDEN_PAGE_STOP 0x02
++#define TNFTL_CALLBACK_LCD_FORMAT_START 0x03
++#define TNFTL_CALLBACK_LCD_FORMAT_PROCESS 0x04
++#define TNFTL_CALLBACK_LCD_FORMAT_STOP 0x05
++#define TNFTL_CALLBACK_LCD_BMP_UPDATE_START 0x06
++#define TNFTL_CALLBACK_LCD_BMP_UPDATE_PROCESS 0x07
++#define TNFTL_CALLBACK_LCD_BMP_UPDATE_STOP 0x08
++
++#define PHY_BAD_BLOCK_MASK 0xFF000000
++#define PHY_BAD_BLOCK_0 0x01000000
++#define PHY_BAD_BLOCK_1 0x02000000
++#define PHY_BAD_BLOCK_2 0x04000000
++#define PHY_BAD_BLOCK_3 0x08000000
++#define PHY_BAD_BLOCK_4 0x10000000
++#define PHY_BAD_BLOCK_5 0x20000000
++#define PHY_BAD_BLOCK_6 0x40000000
++#define PHY_BAD_BLOCK_7 0x80000000
++
++#define WCACHE_NORMAL_USED_MODE 0x00
++#define WCACHE_FORCE_SETUP_MODE 0x01
++
++#define WCACHE_SERIAL_PAGE_MODE 0x00
++#define WCACHE_NORMAL_PAGE_MODE 0x01
++
++#define RCACHE_HIT_SLOT_ENTRY 0x00
++#define RCACHE_NOHIT_SLOT_ENTRY 0x01
++#define RCACHE_MAKE_NEW_SLOT_ENTRY 0x02
++
++#define TNFTL_SECURE_SIZE 0x20000 // 128KBytes
++
++//*****************************************************************************
++//*
++//*
++//* [ INTERNAL STRUCT DEFINE ]
++//*
++//*
++//*****************************************************************************
++typedef void (*TNFTL_FUNC1)(void);
++typedef void (*TNFTL_FUNC2)(unsigned int, unsigned int);
++typedef void (*TNFTL_FUNC3)(unsigned int);
++
++typedef unsigned long int TNFTL_LPT_TABLE_VALUE;
++typedef unsigned long int TNFTL_LPT_BLOCK;
++typedef unsigned long int TNFTL_RCACHE_SLOT;
++
++typedef struct __tag_TNFTL_INIT_INFO
++{
++ U8 SerialNumber[64];
++ U8 BMPSignature[4];
++ U32 ExtendedPartitionNo; // Extended Partition Number
++ U32 ExtendedPartitionSectorSize[10];
++ U32 ROAreaSize;
++ U32 ROAreaStPB;
++} TNFTL_INIT_INFO;
++
++typedef struct __tag_TNFTL_PAGE_INFO
++{
++ unsigned int PageIndex;
++ unsigned long int FTLPageAddr[TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE_PER_1BLOCK];
++ unsigned short int StartPPageNo[TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE_PER_1BLOCK];
++ unsigned short int PPageSize[TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE_PER_1BLOCK];
++} TNFTL_PAGE_INFO;
++
++typedef struct __tag_TNFTL_LPT
++{
++ unsigned short int Usable;
++ unsigned short int Changed;
++ unsigned short int SegNo;
++ unsigned short int MaxTableBlkNums;
++ unsigned short int CurrentPlane;
++ TNFTL_LPT_BLOCK *BlkNo;
++ TNFTL_LPT_TABLE_VALUE Tables[TNFTL_LPT_TABLE_VALUES_1BLOCK];
++
++} TNFTL_LPT;
++
++typedef struct __tag_TNFTL_MAINPB_INFO
++{
++ unsigned short int Used;
++ unsigned long int LBNo;
++ unsigned long int MainPBNo;
++ unsigned short int WrEndPage;
++} TNFTL_MAINPB_INFO;
++
++typedef struct __tag_TNFTL_ALIGNCACHE_INFO
++{
++ unsigned short int Usable;
++ unsigned short int CurUsedSecSize;
++ unsigned long int StartSecAddr;
++ unsigned long int LimitSecSize;
++
++} TNFTL_ALIGNCACHE_INFO;
++
++typedef struct __tag_TNFTL_READ_CACHE
++{
++ unsigned short int Used;
++ unsigned short int OneSlotSize;
++ unsigned short int ShiftOneSlotSize;
++ unsigned short int HitEntryPos;
++ unsigned short int lastSlotNo;
++ unsigned short int MaxSlotNums;
++ unsigned long int MaxMemorySize;
++
++ TNFTL_RCACHE_SLOT *Entry;
++} TNFTL_RCACHE;
++
++
++typedef struct __tag_TNFTL_WRITE_CACHE
++{
++ unsigned short int Used;
++ unsigned short int CacheNo;
++
++ unsigned short int PageCacheMode;
++
++ unsigned long int UsedNo;
++ unsigned long int LBNo;
++ unsigned long int MainPBNo;
++ unsigned long int SubPBNo;
++ unsigned long int PagePBNo;
++ unsigned long int PagePBNo2;
++
++ unsigned long int nPoint;
++
++ unsigned short int MainPBWrEndPage;
++ unsigned short int SubPBWrEndPage;
++ unsigned short int PagePBWrEndPage;
++
++ unsigned short int PageLastPBPageNo;
++
++ unsigned short int PagePBStatus[TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE_PER_1BLOCK * 2];
++
++} TNFTL_WCACHE;
++
++typedef struct __tag_TNFTL_RO_AREA
++{
++ unsigned short int Usable;
++ unsigned long int BlkAreaCode;
++
++ unsigned long int StPB; // Start Block Number [ FTL Blcok Addr ]
++ unsigned long int EdPB; // End Block Number [ FTL Blcok Addr ]
++ unsigned long int PBpV; // Physical Block Size
++
++ unsigned long int StPBAddr; // Start Phy Block Addr
++ unsigned long int EdPBAddr; // End Phy Block Addr
++
++} TNFTL_RO_AREA;
++
++typedef struct __tag_TNFTL_RW_AREA
++{
++ unsigned short int Usable;
++ unsigned long int BlkAreaCode;
++ unsigned long int HeaderBlkAddr;
++
++ unsigned long int PBpV; // Physical Blocks
++ unsigned long int DataPBpV; // Area Data Block Size
++ unsigned long int DataPPpV; // Area Data Page Size
++ unsigned long int TotalSectorSize;
++ unsigned short int FlagOfChangeTotalSectorSize;
++ unsigned short int LptNums; // Area Needs LPT Number
++ unsigned short int WCacheNums; // Write Cache Number
++ unsigned short int WCacheMode;
++ unsigned long int WCacheDataStartLBNo;
++
++ unsigned short int MainPBInfoNums; // Main page info Number
++
++ unsigned short int RCacheUsable;
++ unsigned short int DrvStatus; // Status of Drive
++ unsigned long int TotalDiskSector; // Total Disk Sector
++ unsigned short int Cylinder;
++ unsigned short int Head;
++ unsigned char Sector;
++
++ TNFTL_LPT Lpt;
++ TNFTL_MAINPB_INFO *MainPBInfo;
++ TNFTL_WCACHE *WCaches;
++ TNFTL_RCACHE RCaches;
++
++ unsigned char *ReadCacheBuffer;
++} TNFTL_RW_AREA;
++
++typedef struct __tag_TNFTL_DRVINFO
++{
++ TNFTL_RO_AREA NBArea; // NANDBOOT Area
++ TNFTL_RW_AREA PriPartition; // Primary Partition
++ TNFTL_RW_AREA *ExtPartition; // Extended Partition[n]
++
++ TNFTL_ALIGNCACHE_INFO AlignCache;
++
++ unsigned short int ExtendedPartitionNo; // Extended Partition Number
++ unsigned char FlagOfChangePartition;
++
++
++ unsigned char NANDType;
++ unsigned short int IoStatus;
++ unsigned short int IoDrvNo;
++ unsigned short int IoStCS;
++ unsigned short int IoEdCS;
++ unsigned short int IoBMPFlag; // Flag of BMP
++ unsigned long int DrvReturnValue;
++
++
++
++ unsigned long int PBpV; // Physical all Blocks
++ unsigned short int BBpZ; // Bad Blocks per 1ZONE
++ unsigned short int PpB; // Pages Per Block
++ unsigned short int PageSize; // PageSize
++ unsigned short int SpareSize; // SpareSize
++ unsigned short int PPages; // Total Partial Pages [ 512+16Bytes ]
++ unsigned short int ShiftPpB; // Shift Factor of Pages Per Block
++ unsigned short int ShiftPPages; // Shift Factor of Total Partial Pages
++
++ unsigned long int RwAreaStBlk; // RW Area Start Block Addr
++ unsigned long int RwAreaEdBlk; // RW Area End Block Addr
++ unsigned long int ROAreaSize; // RO Area Size
++ unsigned long int ROAreaStPB;
++ unsigned long int ROAreaBlkNum;
++ unsigned short int RWAreaFormatFlag;
++
++ unsigned short int MPlanePpB; // FTLInfo->PpB >> FTLInfo->ShiftMPlane
++ unsigned short int ILMPlanePpB; // FTLInfo->PpB >> 2
++ unsigned short int MPlane; // Multi Plane Num
++ unsigned short int ShiftMPlane; // Shift Factor of Multi Plane
++ unsigned long int RoundMPlane;
++ unsigned long int RemainMPlane;
++ unsigned long int LPTBufferSize;
++
++ unsigned short int LPT_Values_1Page;
++ unsigned short int LPT_Values_1Page_Shift;
++ unsigned short int LPT_Pages_1Block;
++ unsigned short int LPT_Pages_1Block_Shift;
++ unsigned short int LPT_Block_PPage;
++
++ unsigned short int FTLBadBlockStatus;
++ unsigned long int FTLBadBlockNum;
++ unsigned long int FTLBadBlock[TNFTL_MAX_VALID_BAD_BLOCK_PER_1ZONE * TNFTL_MAX_SUPPORT_ZONE];
++
++ unsigned short int MediaNums;
++ unsigned short int ShiftMediaNums;
++ unsigned short int MediaBadBlockNum[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++
++ unsigned short int ECCStatus;
++
++ unsigned char MediaSizeOfSerialID;
++ unsigned char MediaSizeOfUniqueID;
++ unsigned char MediaSerialID[TNFTL_MAX_NANDFLASH_SID_SIZE];
++ unsigned char MediaUniqueID[TNFTL_MAX_NANDFLASH_UID_SIZE];
++ unsigned long int MediaTotalFTLPageAddr[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++ unsigned long int MediaTotalFTLBlkAddr[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++ unsigned short int MediaRatioPSize[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++ unsigned short int MediaRatioBSize[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++ unsigned short int MediaRatioShiftPSize[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++ unsigned short int MediaRatioShiftBSize[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++ unsigned long int StPBForGetEmptyPB[TNFTL_MAX_SUPPORT_MULTI_PLANE];
++ NAND_IO_DEVINFO MediaDevInfo[TNFTL_MAX_SUPPORT_MULTI_NANDFLASH];
++
++ TNFTL_PAGE_INFO FTLPageInfo;
++ unsigned char *FTLPageBuffer;
++ unsigned char *AlignCacheBuffer;
++ unsigned int *LPTBuffer;
++
++} TNFTL_DRVINFO;
++
++//*****************************************************************************
++//*
++//*
++//* [ EXTERNAL VARIABLE DEFINE ]
++//*
++//*
++//*****************************************************************************
++
++
++
++//*****************************************************************************
++//*
++//*
++//* [ EXTERNAL FUCTIONS DEFINE ]
++//*
++//*
++//*****************************************************************************
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForDriver( U16 nDrvNo, TNFTL_DRVINFO *nMDrvInfo, TNFTL_DRVINFO **nPDrvInfo );
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForLPT( U16 nDrvNo, TNFTL_RW_AREA *nArea, TNFTL_LPT_BLOCK *nLptTableBlk, U32 nLptTableBlkSize );
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForWCACHE( U16 nDrvNo, TNFTL_RW_AREA *nArea, TNFTL_WCACHE *nWCaches, U32 nWCacheNum );
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForRCACHE( U16 nDrvNo, TNFTL_RW_AREA *nArea, TNFTL_RCACHE_SLOT *nRCacheSlots );
++
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForMainPBInfo( U16 nDrvNo, TNFTL_RW_AREA *nArea, TNFTL_MAINPB_INFO *nMainPBInfo, U32 nMainPBInfoNum );
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForPageBuffer( U16 nDrvNo, U8 *nPageBuffer );
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForRCacheBuffer( U16 nDrvNo, TNFTL_RW_AREA *nArea, U8 *nPageBuffer, U32 nBufferSize );
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForAlignCacheBuffer( U16 nDrvNo, U8 *nPageBuffer, U32 nBufferSize );
++
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForMakeLPT( U16 nDrvNo, U32 *nLPTBuffer, U32 nBufferSize );
++extern TNFTL_ERROR TNFTL_AllocMemAndLinkForExtendedPartition( U16 nDrvNo, TNFTL_RW_AREA *nArea );
++extern TNFTL_ERROR TNFTL_SetStEdOfCS( U16 nDrvNo, U16 nStartCS, U16 nEndCS );
++extern TNFTL_ERROR TNFTL_SetExtendedPartitionNums( U16 nDrvNo, U16 nExtPartitionNums );
++
++extern TNFTL_ERROR TNFTL_ScanDevice( TNFTL_DRVINFO *FTLInfo );
++extern void TNFTL_SetNBAreaEndPBAddr( int nPhyBlockAddr );
++extern void TNFTL_SetROAreaSize(TNFTL_DRVINFO * FTLInfo, int nROAreaSize, int nROAreaUsable);
++extern void TNFTL_SetAreaProtectFlag( int value );
++
++extern void TNFTL_DEBUG_Init( void );
++extern void TNFTL_DEBUG_Init_Function( TNFTL_FUNC1 nFUNC1, TNFTL_FUNC2 nFUNC2, TNFTL_FUNC2 nFUNC3, TNFTL_FUNC2 nFUNC4, TNFTL_FUNC2 nFUNC5, TNFTL_FUNC3 nFUNC6, TNFTL_FUNC1 nFUNC7, TNFTL_FUNC1 nFUNC8);
++
++extern TNFTL_ERROR TNFTL_DEBUG_VTCParser( void* nVTCCmd );
++extern void TNFTL_Init( U16 nDrvNo );
++extern TNFTL_ERROR TNFTL_InitDrive( TNFTL_DRVINFO *FTLInfo );
++extern TNFTL_ERROR TNFTL_CheckIsExistBMP( TNFTL_DRVINFO *FTLInfo );
++
++extern TNFTL_ERROR TNFTL_AlignCacheFlush( TNFTL_DRVINFO *FTLInfo );
++
++extern U32 TNFTL_AREAGetTotalSectorSize( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea );
++extern TNFTL_ERROR TNFTL_AREAGetTotalSecAndCHS( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, U32 *rTotalSec, U16 *rCylinder, U16 *rHead, U8 *rSector );
++extern TNFTL_ERROR TNFTL_AREASetTotalSectorSize( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, U32 nTotalSectorSize );
++extern TNFTL_ERROR TNFTL_AREAReadSectorBy4Byte( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, U32 nSectorAddr, U16 nOffset, U16 nReadSize, U8 *nReadBuffer );
++extern TNFTL_ERROR TNFTL_AREAReadSector( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, U32 nSectorAddr, U32 nSecSize, U8 *nReadBuffer );
++extern TNFTL_ERROR TNFTL_AREAReadSectorIRQ( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, ndd_work_info *nWorkInfo );
++extern TNFTL_ERROR TNFTL_AREAWriteSector( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, U32 nSectorAddr, U32 nSecSize, U8 *nWriteBuffer );
++extern TNFTL_ERROR TNFTL_AREAWriteSectorIRQ( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, ndd_work_info *nWorkInfo );
++extern TNFTL_ERROR TNFTL_AREAFormat( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, U16 nFormatLevel );
++extern TNFTL_ERROR TNFTL_NBGetCRCOfImageFile( TNFTL_DRVINFO *FTLInfo, U32 nFlagSelfChecking, U32 *nOrgCRCcode1, U32 *nOrgCRCcode2, U32 *nRomFileSize, U32 *rRstCRCcode1, U32 *rRstCRCcode2 );
++extern TNFTL_ERROR TNFTL_NBGetCRCValueOfImageFile( TNFTL_DRVINFO *FTLInfo, U32 *nOrgCRCcode1, U32 *nOrgCRCcode2, U32 *nRomFileSize );
++extern TNFTL_ERROR TNFTL_NBGetSizeOfImageFile( TNFTL_DRVINFO *FTLInfo, U32 *nRomFileSize ) ;
++extern void TNFTL_WCacheSetDataStartSector( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, unsigned int nDataStartSector );
++
++extern U16 TNFTL_GetSerialNumber( TNFTL_DRVINFO *FTLInfo, U8* rSerialNumber, U16 nSize );
++extern void TNFTL_SetFlagOfChangePartition( TNFTL_DRVINFO *FTLInfo, U16 on_off );
++
++
++extern TNFTL_ERROR TNFTL_IOReadPhyPage( TNFTL_DRVINFO *FTLInfo, U32 nBlkAddr, U32 nPageAddr, U16 nCSorder, U8 *nReadBuffer );
++extern __inline TNFTL_ERROR TNFTL_IOReadSpare( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U8 *nSpareBuffer );
++extern __inline TNFTL_ERROR TNFTL_IOReadPage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern __inline TNFTL_ERROR TNFTL_IOReadPageForSignature( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++
++extern __inline TNFTL_ERROR TNFTL_IOReadTwoPlanePage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nReadOption, int nEccOnOff );
++extern __inline TNFTL_ERROR TNFTL_IOReadTwoPlaneLastPage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern __inline TNFTL_ERROR TNFTL_IOReadUserSizePage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nColumnAddr, U32 nReadSize, U8 *nReadBuffer );
++extern __inline TNFTL_ERROR TNFTL_IOWritePage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern __inline TNFTL_ERROR TNFTL_IOWriteTwoPlanePage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern __inline TNFTL_ERROR TNFTL_IOWriteTwoPlaneLastPage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int LastPage, int nEccOnOff );
++extern __inline TNFTL_ERROR TNFTL_IOWriteCachePage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern __inline TNFTL_ERROR TNFTL_IOWriteCacheLastPage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++extern __inline TNFTL_ERROR TNFTL_IOWriteUserSizePage( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U16 nColumnAddr, U32 nWriteSize, U8 *nWriteBuffer );
++extern __inline TNFTL_ERROR TNFTL_IOWriteSpare( TNFTL_DRVINFO *FTLInfo, U32 nFTLPageAddr, U8 *nSpareBuffer );
++
++extern __inline TNFTL_ERROR TNFTL_IOCopyBackPage( TNFTL_DRVINFO *FTLInfo, U32 nDesFTLPageAddr, U32 nSrcFTLPageAddr, U8 *nPageBuffer, U8 *nSpareBuffer );
++extern __inline TNFTL_ERROR TNFTL_IOEraseBlock( TNFTL_DRVINFO *FTLInfo, U32 nFTLBlkAddr, int nFormatMode );
++extern __inline TNFTL_ERROR TNFTL_IOCopyBackTwoPlanePage( TNFTL_DRVINFO *FTLInfo, U32 nDesFTLPageAddr, U32 nSrcFTLPageAddr, U8 *nPageBuffer, U8 *nSpareBuffer );
++
++extern TNFTL_ERROR TNFTL_GoldenPageWrite( TNFTL_DRVINFO *FTLInfo, U32 nStarAddr, U32 nWriteByteSize, U8 *nPageBuffer );
++extern TNFTL_ERROR TNFTL_GoldenPageRead( TNFTL_DRVINFO *FTLInfo, U32 nStarAddr, U32 nReadByteSize, U8 *nPageBuffer );
++extern U32 TNFTL_SizeofGoldenPage( TNFTL_DRVINFO *FTLInfo );
++
++extern TNFTL_ERROR TNFTL_SetCallBackHandler( TNFTL_CALLBACK_HANDLER pCallBackHandler );
++extern TNFTL_ERROR TNFTL_SetUartDebug( unsigned int on_off );
++extern TNFTL_ERROR TNFTL_BMPRefresh( TNFTL_DRVINFO *FTLInfo );
++
++extern TNFTL_ERROR TNFTL_SetUseAreaReadCacheMode( TNFTL_DRVINFO *FTLInfo, TNFTL_RW_AREA *nArea, unsigned int on_off );
++extern TNFTL_ERROR TNFTL_SetUseAlignCacheMode( TNFTL_DRVINFO *FTLInfo, unsigned int on_off );
++
++
++#endif
++
+diff --git a/drivers/block/tcc/init_ddr2.c b/drivers/block/tcc/init_ddr2.c
+new file mode 100644
+index 0000000..c2be81a
+--- /dev/null
++++ b/drivers/block/tcc/init_ddr2.c
+@@ -0,0 +1,1142 @@
++/****************************************************************************
++ * FileName : init_MEM.c
++ * Description : Init code for TCC8900 DDRAM
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#if defined(_WINCE_)
++#include "bsp.h"
++#elif defined(_LINUX_)
++#include <common.h>
++#include <def_tcc.h>
++#endif
++
++#if defined(DRAM_DDR2)
++
++#define DDR2_SETRCD(x) (x>3? (((x-3)<<8)| x ) : ((1<<8) | x))
++#define DDR2_SETRFC(x) (x>3? (((x-3)<<8)| x ) : ((0<<8) | x))
++#define DDR2_SETRP(x) (x>3? (((x-3)<<8)| x ) : ((1<<8) | x))
++
++#define DRAM_AUTOPD_ENABLE Hw13
++#define DRAM_AUTOPD_PERIOD 7<<7 // must larger than CAS latency
++#define DRAM_SET_AUTOPD DRAM_AUTOPD_ENABLE|DRAM_AUTOPD_PERIOD
++
++#define repeat(n) { volatile int i; for (i=0; i<=n; i++); }
++#define DDR_DELAY 1
++/****************************************************************************************
++* FUNCTION :void InitRoutine_Start(void)
++* DESCRIPTION :
++* ***************************************************************************************/
++ /*-------------------
++ PLL0 m p s
++ ------------------
++ 600 200 2 1
++ 500 250 3 1
++ 480 160 2 1
++ 480 400 3 2
++ ---------------------*/
++ /*-------------------
++ PLL1 m p s
++ ------------------
++ 560 140 3 0
++ 520 130 3 0
++ 500 125 3 0
++ 480 40 1 0
++ ---------------------*/
++#pragma optimize( "g", off )
++
++volatile void InitRoutine_Start(void)
++{
++ volatile int i;
++ // 44.0 ms
++ //Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++ // DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302c &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ i = 1600;
++ while(i)
++ i--;
++ // 37.7 ms
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400000 = 0x002ffff4; // XI - corebus
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++//PLL0
++ *(volatile unsigned long *)0xf0400020= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400020= 0x0100C802; // pms - pllout_600M
++ *(volatile unsigned long *)0xF0400020= 0x8100C802; // pll pwr on
++
++//PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00008c03; // pms - pllout_560M
++ *(volatile unsigned long *)0xF0400024= 0x80008c03; // pll pwr on
++
++ //PLL2
++ *(volatile unsigned long *)0xF0400028= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400028= 0x00002701; // pms - pllout_468M
++ *(volatile unsigned long *)0xF0400028= 0x80002701; // pll pwr on
++
++ i = 3200;
++ while(i)
++ i--;
++ *(volatile unsigned long *)0xF0400000 = 0x002AAAA0; // 300Mhz
++ *(volatile unsigned long *)0xF0400008 = 0x00200030; // 150Mhz
++ *(volatile unsigned long *)0xF0400010 = 0x00200022; // CKC-CLKCTRL4 - I/O BUS
++ i = 3200;
++ while(i)
++ i--;
++
++ *(volatile unsigned long *) 0xf0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xf0302004=0x00000004; // PL341_CONFIGURE
++
++// memory arb.
++ *(volatile unsigned long *) 0xf030200c=0x00140000|DRAM_SET_AUTOPD; // config0 - qos master bits set
++// memory arb. end
++#if defined(DRAM_ROW14)
++ // ELPIDA
++ *(volatile unsigned long *)0xF030200C = 0x0015001A|DRAM_SET_AUTOPD; // config0 cas 10bit, ras 13bit
++#else
++ // Samsung/ Hynix
++ *(volatile unsigned long *)0xF030200C = 0x00150012|DRAM_SET_AUTOPD; // config0 cas 10bit, ras 13bit
++#endif
++
++ *(volatile unsigned long *) 0xf0302010=0x00000445; // refresh
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xf030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xf030204c=0x00000541; // config2 - SOC
++#endif
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xf0302014=0x0000000C; // cas_latency
++#else
++ *(volatile unsigned long *) 0xf0302014=0x0000000A; // cas_latency
++#endif
++
++ *(volatile unsigned long *) 0xf030201c=0x00000003; // tMRD
++
++ //New
++ // 1 Tick = 2.5ns
++ *(volatile unsigned long *)0xF0302020 = 0x0000000D; // tRAS - 45ns
++ *(volatile unsigned long *)0xF0302024 = 0x00000011; // tRC - 60ns
++ *(volatile unsigned long *)0xF0302028 = 0x00000205; // tRCD - 15ns
++ *(volatile unsigned long *)0xF030202c = 0x00001B1E; // tRFC - 105ns
++ *(volatile unsigned long *)0xF0302030 = 0x00000205; // tRP - 15ns
++ *(volatile unsigned long *)0xF0302034 = 0x00000005; // tRRD
++ *(volatile unsigned long *)0xF0302038 = 0x00000006; // tWR
++ *(volatile unsigned long *)0xF030203c = 0x00000003; // tWTR
++ *(volatile unsigned long *)0xF0302040 = 0x00000003; // tXP
++ *(volatile unsigned long *)0xF0302044 = 0x00000022; // tXSR
++ *(volatile unsigned long *)0xF0302048 = 0x000000FA; // tESR
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++
++ //i = 3200;
++ //while(i)
++ // i--;
++ // 1CS
++ #if defined(DRAM_SIZE_128)
++ *(volatile unsigned long *) 0xf0302200=0x000040F8; // config_chip0 - CS0 - 0x40000000~0x47ffffff
++ #endif
++ #if defined(DRAM_SIZE_256)
++ *(volatile unsigned long *) 0xf0302200=0x000040F0; // config_chip0 - CS0 - 0x40000000~0x47ffffff
++ #endif
++ #if defined(DRAM_SIZE_512)
++ *(volatile unsigned long *) 0xf0302200=0x000040E0; // config_chip0 -
++ #endif
++
++ i = 3200;
++ while(i)
++ i--;
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xf0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xf0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ //*(volatile unsigned long *) 0xf030302c=0x00004000; // SSTL
++ *(volatile unsigned long *)0xF030302C = 0x7FFF; // SSTL SDRAM IO Control Register
++
++ // - SOC
++ // *(volatile unsigned long *) 0xf0303004 |= 0x00800000; // bit23 enable -synopt enable
++#if defined(DRAM_ROW14)
++ *(volatile unsigned long *) 0xf0303020=0x00010107; // emccfg_config0
++#else
++ *(volatile unsigned long *) 0xf0303020=0x00010103; // emccfg_config0
++#endif
++
++ *(volatile unsigned long *) 0xf0303024=0x00000000; // phyctrl
++ *(volatile unsigned long *) 0xf0304400=0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *) 0xf0304404=0x00000001; // DLLCTRL - DLL ON
++ *(volatile unsigned long *) 0xf0304408=0x00001717; // DLLPDCFG (200Mhz)
++ *(volatile unsigned long *) 0xf0304404=0x00000003; // DLLCTRL - DLL ON, DLL start
++ while (!((*(volatile unsigned long *)0xF0304404) & (3<<3))); // Wait until PDFL == 1
++
++ *(volatile unsigned long *) 0xf0304424=0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *) 0xf030440c=0x00000006; // GATECTRL
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xf0304430=0x00000006; // RDDELAY - SOC
++ #else
++ *(volatile unsigned long *) 0xf0304430=0x00000005; // RDDELAY - SOC
++ #endif
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *) 0xf0304428=0x00069151; // ZQCTRL
++ #else
++ *(volatile unsigned long *) 0xf0304428=0x00068151; // ZQCTRL
++ #endif
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *) 0xf0304428=0x00069153; // ZQCTRL
++ #else
++ *(volatile unsigned long *) 0xf0304428=0x00068153; // ZQCTRL
++ #endif
++ i = 3200;
++ while(i)
++ i--;
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *) 0xf0304428=0x00069151; // ZQCTRL
++ #else
++ *(volatile unsigned long *) 0xf0304428=0x00068151; // ZQCTRL
++ #endif
++ //i = 3200;
++ //while(i)
++ // i--;
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xf0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xf0302000) & (0x03)) != 0); // Wait until CONFIGURE
++// CS0 Command Initialize...
++ *(volatile unsigned long *) 0xf0302008=0x000c0000; // dir_cmd
++ *(volatile unsigned long *) 0xf0302008=0x00000000; // dir_cmd
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *) 0xf0302008=0x000a0000; // dir_cmd
++ *(volatile unsigned long *) 0xf0302008=0x000b0000; // dir_cmd
++ *(volatile unsigned long *) 0xf0302008=0x00090000; // dir_cmd
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xf0302008=0x00080962; // dir_cmd - SOC
++#else
++ *(volatile unsigned long *) 0xf0302008=0x00080952; // dir_cmd - SOC
++#endif
++ *(volatile unsigned long *) 0xf0302008=0x00000000; // dir_cmd
++
++ // repeat 100
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *) 0xf0302008=0x00040000; // dir_cmd
++ i--;
++ }
++ // repeat end
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xf0302008=0x00080862; // dir_cmd
++#else
++ *(volatile unsigned long *) 0xf0302008=0x00080852; // dir_cmd
++#endif
++ #if defined(DRAM_ODTOFF)
++
++ #else
++ *(volatile unsigned long *) 0xf0302008=0x00090380; // dir_cmd
++ //*(volatile unsigned long *) 0xf0302008=0x00090000; // dir_cmd
++ *(volatile unsigned long *) 0xf0302008=0x00090004; // dir_cmd //soc1-3
++ #endif
++
++ *(volatile unsigned long *) 0xf0302004=0x00000000; // PL341_GO
++}
++#pragma optimize( "g", on )
++
++volatile void InitRoutine_End(void)
++{
++
++}
++
++#if !defined(NKUSE) && !defined(__KERNEL__)
++/*=========================================================================================================================
++*
++* Used Boot Loader
++*
++==========================================================================================================================*/
++void init_clock(void)
++{
++ PCKC lCKC = (CKC *)&HwCLK_BASE;
++ PPMU lPMU = (PMU *)&HwPMU_BASE;
++ PNTSCPAL lNTSCPAL=(PNTSCPAL)&HwTVE_BASE;
++ volatile unsigned int nCount = 0;
++
++ tca_ckc_init();
++
++ // Set PLL - default PLL: PLL1,PLL2,PLL3 Disable
++ // Change PLL Value
++ tca_ckc_setpll(4680000,2); // 240 *2 100hz -SDMMC
++ tca_ckc_setpll(5280000,3); // 156 *2 100hz
++
++ //CLKDIVC0/1
++ lCKC->CLKDIVC = 0x01010101;
++ lCKC->CLKDIVC1 = 0x01010101;
++
++#if defined(TCC_R_AX)
++ tca_ckc_setswreset(RESET_VIDEOBUS, ON);
++ tca_ckc_setswreset(RESET_VIDEOCORE, ON);
++ #if !defined(TCC_MAX_FGRP_INCLUDE)
++ tca_ckc_setswreset(RESET_GRAPBUS, ON);
++ #endif
++#endif
++
++ tca_ckc_setfbusctrl(CLKCTRL1,ENABLE,NORMAL_MD,2640000,DIRECTPLL3);/*FBUS_DDI 240 MHz*/
++ tca_ckc_setfbusctrl(CLKCTRL4,ENABLE,NORMAL_MD,1560000,DIRECTPLL2);/*FBUS_IOB 166 MHz */
++#if defined(TCC_R_AX)
++ tca_ckc_setfbusctrl(CLKCTRL5,DISABLE,NORMAL_MD,60000,DIRECTXIN);/*FBUS_VBUS 215 MHz */ //2640000 , 1760000
++ tca_ckc_setfbusctrl(CLKCTRL6,DISABLE,NORMAL_MD,60000,DIRECTXIN);/*FBUS_VCODEC 160 MHz */ //2340000 , 1560000
++#else
++ tca_ckc_setfbusctrl(CLKCTRL5,ENABLE,NORMAL_MD,60000,DIRECTXIN);/*FBUS_VBUS 215 MHz */ //2640000 , 1760000
++ tca_ckc_setfbusctrl(CLKCTRL6,ENABLE,NORMAL_MD,60000,DIRECTXIN);/*FBUS_VCODEC 160 MHz */ //2340000 , 1560000
++#endif
++
++
++#if defined(FMBUS_330MHZ_INCLUDE) || defined(FMBUS_360MHZ_INCLUDE) || defined(FMBUS_400MHZ_INCLUDE)
++#if defined(TCC_R_AX)
++ #if defined(TCC_MAX_FGRP_INCLUDE)
++ tca_ckc_setfbusctrl(CLKCTRL3,ENABLE,NORMAL_MD,2640000,DIRECTPLL3);/*FBUS_GRP */
++ #else
++ tca_ckc_setfbusctrl(CLKCTRL3,DISABLE,NORMAL_MD,60000,DIRECTXIN);/*FBUS_GRP */
++ #endif
++#else
++ tca_ckc_setfbusctrl(CLKCTRL3,ENABLE,NORMAL_MD,2640000,DIRECTPLL3);/*FBUS_GRP */
++#endif
++ tca_ckc_setfbusctrl(CLKCTRL7,ENABLE,NORMAL_MD,1760000,DIRECTPLL3);/*FBUS_SMU */
++#else
++#if defined(TCC_R_AX)
++ #if defined(TCC_MAX_FGRP_INCLUDE)
++ tca_ckc_setfbusctrl(CLKCTRL3,ENABLE,NORMAL_MD,2340000,DIRECTPLL2);/*FBUS_GRP 190 MHz */
++ #else
++ tca_ckc_setfbusctrl(CLKCTRL3,DISABLE,NORMAL_MD,60000,DIRECTXIN);/*FBUS_GRP 190 MHz */
++ #endif
++#else
++ tca_ckc_setfbusctrl(CLKCTRL3,ENABLE,NORMAL_MD,2340000,DIRECTPLL2);/*FBUS_GRP 190 MHz */
++#endif
++ tca_ckc_setfbusctrl(CLKCTRL7,ENABLE,NORMAL_MD,1170000,DIRECTPLL2);/*FBUS_SMU 125 MHz */
++#endif
++
++ // Enable Peri.
++ lPMU->CONTROL |= Hw16; // Touch ADC Power Enable
++ nCount = 10;
++ for ( ; nCount > 0 ; nCount --); // delay
++ lNTSCPAL->DACPD |= Hw0;
++
++ lPMU->PWROFF &= ~Hw0; // Video Dac(TVOUT)
++ nCount = 500;
++ for ( ; nCount > 0 ; nCount --); // delay
++ lPMU->PWROFF |=(Hw0
++ |Hw1 // HDMI PHY
++ |Hw2 // LVDS
++ |Hw4 //SATA PHY
++#if defined(TCC_R_AX)
++ |Hw6 // Video Bus
++ #if !defined(TCC_MAX_FGRP_INCLUDE)
++ |Hw8
++ #endif
++#endif
++ ); // HDMI Phy,LVDS Phy,SATA Phy , Video Bus , Graphic Bus
++
++#if defined(TCC_R_AX)
++ tca_ckc_setswreset(RESET_VIDEOCORE, OFF);
++ tca_ckc_setswreset(RESET_VIDEOBUS, OFF);
++ #if !defined(TCC_MAX_FGRP_INCLUDE)
++ tca_ckc_setswreset(RESET_GRAPBUS, OFF);
++ #endif
++#endif
++// init Peri. Clock
++ tca_ckc_setperi(PERI_TCZ,ENABLE,120000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_ADC,ENABLE,120000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_I2C,ENABLE,40000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_UART0,ENABLE,520000,PCDIRECTPLL2);
++ tca_ckc_setperi(PERI_LCD1,ENABLE,1560000,PCDIRECTPLL2);
++
++ tca_ckc_setperi(PERI_LCD0,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_LCDSI,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_CIFMC,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_CIFSC,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_OUT0,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_OUT1,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_HDMI,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_SDMMC0,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_MSTICK,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_UART1,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_UART2,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_UART3,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_UART4,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_UART5,DISABLE,10000,PCDIRECTXIN);
++
++ tca_ckc_setperi(PERI_GPSB0,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_GPSB1,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_GPSB2,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_GPSB3,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_GPSB4,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_GPSB5,DISABLE,10000,PCDIRECTXIN);
++
++// tca_ckc_setperi(PERI_SPDIF,ENABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_EHI0,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_EHI1,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_CAN,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_SDMMC1,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_DAI,DISABLE,10000,PCDIRECTXIN);
++
++// init Io Bus
++ tca_ckc_setiobus(RB_USB11H, DISABLE);
++ tca_ckc_setiobus(RB_IDECONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_SDMMCCONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_SATAHCONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_MEMORYSTICKCONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_EXTHCONTROLLER0, DISABLE);
++ tca_ckc_setiobus(RB_EXTHCONTROLLER1, DISABLE);
++ tca_ckc_setiobus(RB_UARTCONTROLLER1, DISABLE);
++ tca_ckc_setiobus(RB_UARTCONTROLLER2, DISABLE);
++ tca_ckc_setiobus(RB_UARTCONTROLLER3, DISABLE);
++ tca_ckc_setiobus(RB_UARTCONTROLLER4, DISABLE);
++ tca_ckc_setiobus(RB_UARTCONTROLLER5, DISABLE);
++ tca_ckc_setiobus(RB_GPSBCONTROLLER0, DISABLE);
++ tca_ckc_setiobus(RB_GPSBCONTROLLER1, DISABLE);
++ tca_ckc_setiobus(RB_GPSBCONTROLLER2, DISABLE);
++ tca_ckc_setiobus(RB_GPSBCONTROLLER3, DISABLE);
++ tca_ckc_setiobus(RB_GPSBCONTROLLER4, DISABLE);
++ tca_ckc_setiobus(RB_GPSBCONTROLLER5, DISABLE);
++ tca_ckc_setiobus(RB_SPDIFTXCONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_GPSCONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_CANCONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_MPE_FECCONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_TSIFCONTROLLER, DISABLE);
++// tca_ckc_setiobus(RB_SRAMCONTROLLER, DISABLE);
++
++// init ddi Pwdn
++ tca_ckc_setddipwdn(DDIPWDN_CIF, DISABLE);
++ tca_ckc_setddipwdn(DDIPWDN_VIQE, DISABLE);
++ tca_ckc_setddipwdn(DDIPWDN_LCDC0, DISABLE);
++ tca_ckc_setddipwdn(DDIPWDN_MSCL0, DISABLE);
++ tca_ckc_setddipwdn(DDIPWDN_MSCL1, DISABLE);
++ tca_ckc_setddipwdn(DDIPWDN_HDMI, DISABLE);
++
++
++}
++
++/*
++* Example
++* ------------------------------------------------------------------------------------------------------------------------------
++* define HIGH_VOLTAGE_CLOCK_INCLUDE
++*
++* 1. Core 600Mhz, Mem 400Mhz
++* #define lpll0 800
++* #define lpll1 660
++* #define lmem_source 0 // 0 : PLL0 , 1 : PLL1
++* #define lcore_div 12 // (lpll0 * lcore_div)/16 - refer DataSheet CKC Block
++* #define lmem_div 2 // if lmem_source is 0, lpll0/lmem_div = Mem Bus / if lmem_source is 0, lpll0/lmem_div = Mem Bus
++*
++* 2. Core 600Mhz, Mem 330Mhz
++* #define lpll0 600
++* #define lpll1 660
++* #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++* #define lcore_div 16 // (lpll0 * lcore_div)/16 - refer DataSheet CKC Block
++* #define lmem_div 2 // if lmem_source is 0, lpll0/lmem_div = Mem Bus / if lmem_source is 1, lpll1/lmem_div = Mem Bus
++* 3. Core 506Mhz, Mem 330Mhz
++* #define lpll0 540
++* #define lpll1 660
++* #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++* #define lcore_div 15 // (lpll0 * lcore_div)/16 - refer DataSheet CKC Block
++* #define lmem_div 2 // if lmem_source is 0, lpll0/lmem_div = Mem Bus / if lmem_source is 1, lpll1/lmem_div = Mem Bus
++* ------------------------------------------------------------------------------------------------------------------------------
++* 4. Core 600Mhz, Mem 280Mhz
++* #define lpll0 600
++* #define lpll1 560
++* #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++* #define lcore_div 16 // (lpll0 * lcore_div)/16 - refer DataSheet CKC Block
++* #define lmem_div 2 // if lmem_source is 0, lpll0/lmem_div = Mem Bus / if lmem_source is 1, lpll1/lmem_div = Mem Bus
++*
++* 5. Core 506Mhz, Mem 280Mhz
++* #define lpll0 540
++* #define lpll1 560
++* #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++* #define lcore_div 15 // (lpll0 * lcore_div)/16 - refer DataSheet CKC Block
++* #define lmem_div 2 // if lmem_source is 0, lpll0/lmem_div = Mem Bus / if lmem_source is 0, lpll0/lmem_div = Mem Bus
++* ------------------------------------------------------------------------------------------------------------------------------
++*/
++volatile void init_bootddr(void)
++{
++
++#if defined(FMBUS_400MHZ_INCLUDE)
++ #define lpll0 800
++ #define lpll1 540
++ #define lmem_source 0
++
++// Core
++ #if defined(FCPU_506MHZ_INCLUDE)
++ #define lcore_div 10
++ #elif defined(FCPU_600MHZ_INCLUDE)
++ #define lcore_div 12
++ #else
++ #define lcore_div 10
++ #endif
++
++#elif defined(FMBUS_360MHZ_INCLUDE) && defined(FCPU_720MHZ_INCLUDE)
++ #define lpll0 720
++ #define lpll1 540
++ #define lmem_source 0
++
++// Core
++ #define lcore_div 16
++
++#elif defined(FMBUS_352MHZ_INCLUDE) && defined(FCPU_704MHZ_INCLUDE)
++ #define lpll0 704
++ #define lpll1 540
++ #define lmem_source 0
++
++// Core
++ #define lcore_div 16
++
++#else // FMBUS 330 or 280 Mhz
++
++// Core
++ #if defined(FCPU_506MHZ_INCLUDE)
++ #define lpll0 540
++ #define lcore_div 15 // refer DataSheet CKC Block
++ #elif defined(FCPU_600MHZ_INCLUDE)
++ #define lpll0 600
++ #define lcore_div 16 // refer DataSheet CKC Block
++ #else
++ #define lpll0 540
++ #define lcore_div 15 // refer DataSheet CKC Block
++ #endif
++// Mbus
++ #if defined(FMBUS_280MHZ_INCLUDE)
++ #define lpll1 560
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #elif defined(FMBUS_330MHZ_INCLUDE)
++ #define lpll1 660
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #elif defined(FMBUS_300MHZ_INCLUDE)
++ #define lpll1 540
++ #define lmem_source 0 // 0 : PLL0 , 1 : PLL1
++ #else
++ #define lpll1 560
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++ #endif
++
++#endif
++
++ #define lmem_div 2
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++ unsigned int lindex[17];
++ lindex[0] = 0x0;
++ lindex[1] = 0x8000;
++ lindex[2] = 0x8008;
++ lindex[3] = 0x8808;
++ lindex[4] = 0x8888;
++ lindex[5] = 0xA888;
++ lindex[6] = 0xA8A8;
++ lindex[7] = 0xAAA8;
++ lindex[8] = 0xAAAA;
++ lindex[9] = 0xECCC;
++ lindex[10] = 0xEECC;
++ lindex[11] = 0xEEEC;
++ lindex[12] = 0xEEEE;
++ lindex[13] = 0xFEEE;
++ lindex[14] = 0xFFEE;
++ lindex[15] = 0xFFFE;
++ lindex[16] = 0xFFFF;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302c &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ i = 1600;
++ while(i)
++ i--;
++
++//Clock Change
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400000 = 0x002ffff4; // XI - corebus
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ i = 2400;
++ while(i)
++ i--;
++ //PLL0
++ *(volatile unsigned long *)0xf0400020= 0x0000fa03; // pll pwr off
++ if(lpll0 == 800)
++ {
++ *(volatile unsigned long *)0xF0400020= 0x01019003; // pms - pllout_800M
++ *(volatile unsigned long *)0xF0400020= 0x81019003; // pll pwr on
++ }
++ else if(lpll0 == 720)
++ {
++ *(volatile unsigned long *)0xF0400020= 0x0100F002; // pms - pllout_720M
++ *(volatile unsigned long *)0xF0400020= 0x8100F002; // pll pwr on
++ }
++ else if(lpll0 == 704)
++ {
++ *(volatile unsigned long *)0xF0400020= 0x01016003; // pms - pllout_704M
++ *(volatile unsigned long *)0xF0400020= 0x81016003; // pll pwr on
++ }
++ else if(lpll0 == 600)
++ {
++ *(volatile unsigned long *)0xF0400020= 0x0100C802; // pms - pllout_600M
++ *(volatile unsigned long *)0xF0400020= 0x8100C802; // pll pwr on
++ }
++ else if(lpll0 == 540)
++ {
++ *(volatile unsigned long *)0xF0400020= 0x0100B402; // pms - pllout_540M
++ *(volatile unsigned long *)0xF0400020= 0x8100B402; // pll pwr on
++ }
++ else if(lpll0 == 400)
++ {
++ *(volatile unsigned long *)0xF0400020= 0x02019003; // pms - pllout_400M
++ *(volatile unsigned long *)0xF0400020= 0x82019003; // pll pwr on
++ }
++ else if(lpll0 == 216)
++ {
++ *(volatile unsigned long *)0xF0400020= 0x02009002; // pms - pllout_216M
++ *(volatile unsigned long *)0xF0400020= 0x82009002; // pll pwr on
++ }
++ else
++ {
++ *(volatile unsigned long *)0xF0400020= 0x0100C802; // pms - pllout_600M
++ *(volatile unsigned long *)0xF0400020= 0x8100C802; // pll pwr on
++ }
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ if(lpll1 == 660)
++ {
++ *(volatile unsigned long *)0xF0400024= 0x00006E02; // pms - pllout_660M
++ *(volatile unsigned long *)0xF0400024= 0x80006E02; // pll pwr on
++ }
++ else if(lpll1 == 560)
++ {
++ *(volatile unsigned long *)0xF0400024= 0x00008c03; // pms - pllout_560M
++ *(volatile unsigned long *)0xF0400024= 0x80008c03; // pll pwr on
++ }
++ else if(lpll1 == 540)
++ {
++ *(volatile unsigned long *)0xF0400024= 0x00002D01; // pms - pllout_540M
++ *(volatile unsigned long *)0xF0400024= 0x80002D01; // pll pwr on
++ }
++ else if(lpll1 == 282)
++ {
++ *(volatile unsigned long *)0xF0400024= 0x01002F01; // pms - pllout_560M
++ *(volatile unsigned long *)0xF0400024= 0x81002F01; // pll pwr on
++ }
++ else
++ {
++ *(volatile unsigned long *)0xF0400024= 0x00008c03; // pms - pllout_560M
++ *(volatile unsigned long *)0xF0400024= 0x80008c03; // pll pwr on
++ }
++
++ i = 3200;
++ while(i)
++ i--;
++ *(volatile unsigned long *)0xF0400000 = (0x00200000 | (lindex[lcore_div] << 4)); // CKC-CLKCTRL0 - Core
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++ i = 3200;
++ while(i)
++ i--;
++
++//Init DDR2
++ *(volatile unsigned long *) 0xf0302004=0x00000003; // PL341_PAUSE
++ *(volatile unsigned long *) 0xf0302004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++// memory arb.
++ *(volatile unsigned long *)0xF030200C |= 0x00140000|DRAM_SET_AUTOPD;
++/*
++ *(volatile unsigned long *) 0xf0302100=0x0000002b; // (10<<2)(1<<1)(1<<0) - video codec + jpeg encoder
++ *(volatile unsigned long *) 0xf0302104=0x0000002b; // (10<<2)(1<<1)(1<<0) - video cache + jpeg decoder
++ *(volatile unsigned long *) 0xf0302108=0x00000017; // (5<<2)(1<<1)(1<<0) - video codec secondary
++ *(volatile unsigned long *) 0xf030210c=0x00000017; // (5<<2)(1<<1)(1<<0) - io bus
++ *(volatile unsigned long *) 0xf0302110=0x0000000f; // (3<<2)(1<<1)(1<<1) - lcd
++ *(volatile unsigned long *) 0xf0302114=0x0000000f; // (3<<2)(1<<1)(1<<1) - lcd_mscl
++ *(volatile unsigned long *) 0xf0302118=0x00000017; // (5<<2)(1<<1)(1<<1) - VIQE
++ *(volatile unsigned long *) 0xf030211c=0x00000007; // (1<<2)(1<<1)(1<<1) - ddi cache
++ *(volatile unsigned long *) 0xf0302124=0x0000003f; // (15<<2)(1<<1)(1<<1) - ARM DMA bus
++ *(volatile unsigned long *) 0xf0302128=0x0000003f; // (15<<2)(1<<1)(1<<1) - ARM data bus
++ *(volatile unsigned long *) 0xf030212c=0x0000002b; // (10<<2)(1<<1)(1<<1) - ARM instruction
++ *(volatile unsigned long *) 0xf0302130=0x0000003f; // (15<<2)(1<<1)(1<<1) - overlay mixer
++ *(volatile unsigned long *) 0xf0302134=0x0000003f; // (15<<2)(1<<1)(1<<1) - overlay mixer
++ *(volatile unsigned long *) 0xf0302138=0x0000003f; // (15<<2)(1<<1)(1<<1) - overlay mixer
++ *(volatile unsigned long *) 0xf030213c=0x0000002b; // (10<<2)(1<<1)(1<<1) - 3d
++*/
++// memory arb. end
++ *(volatile unsigned long *) 0xF0303000 |= 0x80800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xF0303010 |= 0x80800000; // bit23 enable -synopt enable
++
++#if defined(DRAM_ROW14)
++ // ELPIDA
++ *(volatile unsigned long *)0xF030200C = 0x0015001A|DRAM_SET_AUTOPD; // config0 cas 10bit, ras 13bit
++#else
++// Samsung/ Hynix
++ *(volatile unsigned long *)0xF030200C = 0x00150012|DRAM_SET_AUTOPD; // config0 cas 10bit, ras 13bit
++#endif
++
++#if defined(FMBUS_280MHZ_INCLUDE)
++ *(volatile unsigned long *)0xF0302010 = 2184; // refresh
++#elif defined(FMBUS_300MHZ_INCLUDE)
++ *(volatile unsigned long *)0xF0302010 = 2340; // refresh
++#elif defined(FMBUS_330MHZ_INCLUDE)
++ *(volatile unsigned long *)0xF0302010 = 2574; // refresh
++#elif defined(FMBUS_352MHZ_INCLUDE)
++ *(volatile unsigned long *)0xF0302010 = 2746; // refresh
++#elif defined(FMBUS_360MHZ_INCLUDE)
++ *(volatile unsigned long *)0xF0302010 = 2808; // refresh
++#elif defined(FMBUS_400MHZ_INCLUDE)
++ *(volatile unsigned long *)0xF0302010 = 3120; // refresh
++#else
++ *(volatile unsigned long *)0xF0302010 = 2184; // refresh
++#endif
++
++#if defined(DRAM_BANK3)
++ *(volatile unsigned long *) 0xf030204c=0x00000571; // config2 - SOC
++#else
++ *(volatile unsigned long *) 0xf030204c=0x00000541; // config2 - SOC
++#endif
++
++
++#if defined(DRAM_CAS6)
++ *(volatile unsigned long *) 0xf0302014=0x0000000C; // cas_latency
++#else
++ *(volatile unsigned long *) 0xf0302014=0x0000000A; // cas_latency
++#endif
++
++ *(volatile unsigned long *)0xF030201c = 0x00000003; // tMRD
++ #if defined(FMBUS_400MHZ_INCLUDE)
++ *(volatile unsigned long *)0xF0302020 = 18; // tRAS - 45ns
++ *(volatile unsigned long *)0xF0302024 = 24; // tRC - 60ns
++ *(volatile unsigned long *)0xF0302028 = DDR2_SETRCD(6);//((3)<<8 |6); // tRCD - 15ns
++
++ #if defined(DRAM_TYPE1) || defined(DRAM_TYPE2) || defined(DRAM_TYPE6)
++ *(volatile unsigned long *)0xF030202c = DDR2_SETRFC(42);// tRFC - 105ns
++ #endif
++ #if defined(DRAM_TYPE3) || defined(DRAM_TYPE4) || defined(DRAM_TYPE10)
++ *(volatile unsigned long *)0xF030202c = DDR2_SETRFC(51);// tRFC - 127.5ns
++ #endif
++ *(volatile unsigned long *)0xF0302030 = DDR2_SETRP(6);// tRP - 15ns
++ *(volatile unsigned long *)0xF0302034 = 4; // tRRD - 10ns
++ *(volatile unsigned long *)0xF0302038 = 6; // tWR - 15ns
++ *(volatile unsigned long *)0xF030203c = 3; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 3; // tXP - min 2tCK
++ #if defined(DRAM_TYPE1) || defined(DRAM_TYPE2) || defined(DRAM_TYPE6)
++ *(volatile unsigned long *)0xF0302044 = 46; // tXSR - tXSNR
++ #endif
++ #if defined(DRAM_TYPE3) || defined(DRAM_TYPE4) || defined(DRAM_TYPE10)
++ *(volatile unsigned long *)0xF0302044 = 55; // tXSR - tXSNR
++ #endif
++ *(volatile unsigned long *)0xF0302054 = 0x0000191c; // tFAW
++
++ #elif defined(FMBUS_360MHZ_INCLUDE)
++ *(volatile unsigned long *)0xF0302020 = 17; // tRAS - 45ns
++ *(volatile unsigned long *)0xF0302024 = 22; // tRC - 60ns
++ *(volatile unsigned long *)0xF0302028 = DDR2_SETRCD(6);//((3)<<8 |6); // tRCD - 15ns
++
++ #if defined(DRAM_TYPE1) || defined(DRAM_TYPE2) || defined(DRAM_TYPE6)
++ *(volatile unsigned long *)0xF030202c = DDR2_SETRFC(37);// tRFC - 105ns
++ #endif
++ #if defined(DRAM_TYPE3) || defined(DRAM_TYPE4) || defined(DRAM_TYPE10)
++ *(volatile unsigned long *)0xF030202c = DDR2_SETRFC(46);// tRFC - 127.5ns
++ #endif
++ *(volatile unsigned long *)0xF0302030 = DDR2_SETRP(6);// tRP - 15ns
++ *(volatile unsigned long *)0xF0302034 = 4; // tRRD - 10ns
++ *(volatile unsigned long *)0xF0302038 = 6; // tWR - 15ns
++ *(volatile unsigned long *)0xF030203c = 3; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 3; // tXP - min 2tCK
++
++ #if defined(DRAM_TYPE1) || defined(DRAM_TYPE2) || defined(DRAM_TYPE6)
++ *(volatile unsigned long *)0xF0302044 = 42; // tXSR - tXSNR
++ #endif
++ #if defined(DRAM_TYPE3) || defined(DRAM_TYPE4) || defined(DRAM_TYPE10)
++ *(volatile unsigned long *)0xF0302044 = 50; // tXSR - tXSNR
++ #endif
++ *(volatile unsigned long *)0xF0302054 = 0x0000191c; // tFAW
++ #elif defined(FMBUS_352MHZ_INCLUDE)
++ *(volatile unsigned long *)0xF0302020 = 16; // tRAS - 45ns
++ *(volatile unsigned long *)0xF0302024 = 22; // tRC - 60ns
++ *(volatile unsigned long *)0xF0302028 = DDR2_SETRCD(6);//((3)<<8 |6); // tRCD - 15ns
++
++ #if defined(DRAM_TYPE1) || defined(DRAM_TYPE2) || defined(DRAM_TYPE6)
++ *(volatile unsigned long *)0xF030202c = DDR2_SETRFC(37);// tRFC - 105ns
++ #endif
++ #if defined(DRAM_TYPE3) || defined(DRAM_TYPE4) || defined(DRAM_TYPE10)
++ *(volatile unsigned long *)0xF030202c = DDR2_SETRFC(45);// tRFC - 127.5ns
++ #endif
++ *(volatile unsigned long *)0xF0302030 = DDR2_SETRP(6);// tRP - 15ns
++ *(volatile unsigned long *)0xF0302034 = 4; // tRRD - 10ns
++ *(volatile unsigned long *)0xF0302038 = 6; // tWR - 15ns
++ *(volatile unsigned long *)0xF030203c = 3; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 3; // tXP - min 2tCK
++
++ #if defined(DRAM_TYPE1) || defined(DRAM_TYPE2) || defined(DRAM_TYPE6)
++ *(volatile unsigned long *)0xF0302044 = 41; // tXSR - tXSNR
++ #endif
++ #if defined(DRAM_TYPE3) || defined(DRAM_TYPE4) || defined(DRAM_TYPE10)
++ *(volatile unsigned long *)0xF0302044 = 49; // tXSR - tXSNR
++ #endif
++ *(volatile unsigned long *)0xF0302054 = 0x0000191c; // tFAW
++ #elif defined(FMBUS_330MHZ_INCLUDE)
++ *(volatile unsigned long *)0xF0302020 = 15; // tRAS - 45ns
++ *(volatile unsigned long *)0xF0302024 = 20; // tRC - 60ns
++ *(volatile unsigned long *)0xF0302028 = DDR2_SETRCD(5);// tRCD - 15ns
++
++ #if defined(DRAM_TYPE1) || defined(DRAM_TYPE2) || defined(DRAM_TYPE6)
++ *(volatile unsigned long *)0xF030202c = DDR2_SETRFC(35);// tRFC - 105ns
++ #endif
++ #if defined(DRAM_TYPE3) || defined(DRAM_TYPE4) || defined(DRAM_TYPE10)
++ *(volatile unsigned long *)0xF030202c = DDR2_SETRFC(42);// tRFC - 127.5ns
++ #endif
++ *(volatile unsigned long *)0xF0302030 = DDR2_SETRP(5);// tRP - 15ns
++ *(volatile unsigned long *)0xF0302034 = 4; // tRRD - 10ns
++ *(volatile unsigned long *)0xF0302038 = 5; // tWR - 15ns
++ *(volatile unsigned long *)0xF030203c = 3; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 3; // tXP - min 2tCK
++
++ #if defined(DRAM_TYPE1) || defined(DRAM_TYPE2) || defined(DRAM_TYPE6)
++ *(volatile unsigned long *)0xF0302044 = 38; // tXSR - tXSNR
++ #endif
++ #if defined(DRAM_TYPE3) || defined(DRAM_TYPE4) || defined(DRAM_TYPE10)
++ *(volatile unsigned long *)0xF0302044 = 46; // tXSR - tXSNR
++ #endif
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++ #elif defined(FMBUS_300MHZ_INCLUDE)
++ *(volatile unsigned long *)0xF0302020 = 14; // tRAS - 45ns
++ *(volatile unsigned long *)0xF0302024 = 18; // tRC - 60ns
++ *(volatile unsigned long *)0xF0302028 = DDR2_SETRCD(5);// tRCD - 15ns
++
++ #if defined(DRAM_TYPE1) || defined(DRAM_TYPE2) || defined(DRAM_TYPE6)
++ *(volatile unsigned long *)0xF030202c = DDR2_SETRFC(32);// tRFC - 105ns
++ #endif
++ #if defined(DRAM_TYPE3) || defined(DRAM_TYPE4) || defined(DRAM_TYPE10)
++ *(volatile unsigned long *)0xF030202c = DDR2_SETRFC(39);// tRFC - 127.5ns
++ #endif
++ *(volatile unsigned long *)0xF0302030 = DDR2_SETRP(5);// tRP - 15ns
++ *(volatile unsigned long *)0xF0302034 = 3; // tRRD - 10ns
++ *(volatile unsigned long *)0xF0302038 = 5; // tWR - 15ns
++ *(volatile unsigned long *)0xF030203c = 3; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 3; // tXP - min 2tCK
++
++ #if defined(DRAM_TYPE1) || defined(DRAM_TYPE2) || defined(DRAM_TYPE6)
++ *(volatile unsigned long *)0xF0302044 = 35; // tXSR - tXSNR
++ #endif
++ #if defined(DRAM_TYPE3) || defined(DRAM_TYPE4) || defined(DRAM_TYPE10)
++ *(volatile unsigned long *)0xF0302044 = 42; // tXSR - tXSNR
++ #endif
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++ #elif defined(FMBUS_280MHZ_INCLUDE)
++ *(volatile unsigned long *)0xF0302020 = 13; // tRAS - 45ns
++ *(volatile unsigned long *)0xF0302024 = 17; // tRC - 60ns
++ *(volatile unsigned long *)0xF0302028 = DDR2_SETRCD(5);// tRCD - 15ns
++
++ #if defined(DRAM_TYPE1) || defined(DRAM_TYPE2) || defined(DRAM_TYPE6)
++ *(volatile unsigned long *)0xF030202c = DDR2_SETRFC(30);// tRFC - 105ns
++ #endif
++ #if defined(DRAM_TYPE3) || defined(DRAM_TYPE4) || defined(DRAM_TYPE10)
++ *(volatile unsigned long *)0xF030202c = DDR2_SETRFC(36);// tRFC - 127.5ns
++ #endif
++ *(volatile unsigned long *)0xF0302030 = DDR2_SETRP(5);// tRP - 15ns
++ *(volatile unsigned long *)0xF0302034 = 3; // tRRD - 10ns
++ *(volatile unsigned long *)0xF0302038 = 5; // tWR - 15ns
++ *(volatile unsigned long *)0xF030203c = 3; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 3; // tXP - min 2tCK
++
++ #if defined(DRAM_TYPE1) || defined(DRAM_TYPE2) || defined(DRAM_TYPE6)
++ *(volatile unsigned long *)0xF0302044 = 33; // tXSR - tXSNR
++ #endif
++ #if defined(DRAM_TYPE3) || defined(DRAM_TYPE4) || defined(DRAM_TYPE10)
++ *(volatile unsigned long *)0xF0302044 = 39; // tXSR - tXSNR
++ #endif
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++ #else
++ *(volatile unsigned long *)0xF0302020 = 13; // tRAS - 45ns
++ *(volatile unsigned long *)0xF0302024 = 17; // tRC - 60ns
++ *(volatile unsigned long *)0xF0302028 = DDR2_SETRCD(5);// tRCD - 15ns
++
++ #if defined(DRAM_TYPE1) || defined(DRAM_TYPE2) || defined(DRAM_TYPE6)
++ *(volatile unsigned long *)0xF030202c = DDR2_SETRFC(30);// tRFC - 105ns
++ #endif
++ #if defined(DRAM_TYPE3) || defined(DRAM_TYPE4) || defined(DRAM_TYPE10)
++ *(volatile unsigned long *)0xF030202c = DDR2_SETRFC(36);// tRFC - 127.5ns
++ #endif
++ *(volatile unsigned long *)0xF0302030 = DDR2_SETRP(5);// tRP - 15ns
++ *(volatile unsigned long *)0xF0302034 = 3; // tRRD - 10ns
++ *(volatile unsigned long *)0xF0302038 = 5; // tWR - 15ns
++ *(volatile unsigned long *)0xF030203c = 3; // tWTR - 7.5ns
++ *(volatile unsigned long *)0xF0302040 = 3; // tXP - min 2tCK
++
++ #if defined(DRAM_TYPE1) || defined(DRAM_TYPE2) || defined(DRAM_TYPE6)
++ *(volatile unsigned long *)0xF0302044 = 33; // tXSR - tXSNR
++ #endif
++ #if defined(DRAM_TYPE3) || defined(DRAM_TYPE4) || defined(DRAM_TYPE10)
++ *(volatile unsigned long *)0xF0302044 = 39; // tXSR - tXSNR
++ #endif
++ *(volatile unsigned long *)0xF0302054 = 0x00001619; // tFAW
++ #endif
++ *(volatile unsigned long *)0xF0302048 = 200; // tESR
++
++ i = 3200;
++ while(i)
++ i--;
++
++ // 1CS
++ #if defined(DRAM_SIZE_128)
++ *(volatile unsigned long *) 0xf0302200=0x000040F8; // config_chip0 - CS0 - 0x40000000~0x47ffffff
++ #endif
++ #if defined(DRAM_SIZE_256)
++ *(volatile unsigned long *) 0xf0302200=0x000040F0; // config_chip0 - CS0 - 0x40000000~0x47ffffff
++ #endif
++ #if defined(DRAM_SIZE_512)
++ *(volatile unsigned long *) 0xf0302200=0x000040E0; // config_chip0 -
++ #endif
++
++ i = 3200;
++ while(i)
++ i--;
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 3); // Wait until SLEEP
++
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++
++
++
++#if defined(DRAM_ROW14)
++ *(volatile unsigned long *) 0xF0303020=0x00010107; // emccfg_config0
++#else
++ *(volatile unsigned long *) 0xF0303020=0x00010103; // emccfg_config0
++#endif
++ *(volatile unsigned long *)0xF0303024 = 0x00000000; // SDRAM PHY Control Register
++ *(volatile unsigned long *)0xF0304400 = 0x00000000; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++#if defined(FMBUS_352MHZ_INCLUDE) || defined(FMBUS_360MHZ_INCLUDE) ||defined(FMBUS_400MHZ_INCLUDE)
++ *(volatile unsigned long *)0xF0304408 = 0x00001212; // DLLPDCFG
++#else
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++#endif
++
++
++ *(volatile unsigned long *)0xF0304404 = 0x00000003; // DLLCTRL
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000006; // GATECTRL
++#if defined(DRAM_CAS6) //soc1-3
++ *(volatile unsigned long *) 0xf0304430=0x00000006; // RDDELAY - SOC
++#else
++ *(volatile unsigned long *) 0xf0304430=0x00000005; // RDDELAY - SOC
++#endif
++
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++ i = 3200;
++ while(i)
++ i--;
++ #if defined(DRAM_ODTOFF)
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #else
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (0 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ #endif
++ i = 3200;
++ while(i)
++ i--;
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL34X_WAKEUP
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0302000) & (0x03)) != 0); // Wait until CONFIGURE
++
++ *(volatile unsigned long *)0xF0302008 = 0x000c0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000a0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x000b0000; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090000; // Direct COmmnad Register
++
++#if defined(FMBUS_352MHZ_INCLUDE) || defined(FMBUS_360MHZ_INCLUDE) ||defined(FMBUS_400MHZ_INCLUDE)
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080B62; // Direct COmmnad Register
++ #else
++ *(volatile unsigned long *)0xF0302008 = 0x00080B52; // Direct COmmnad Register
++ #endif
++#else
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080962; // Direct COmmnad Register
++ #else
++ *(volatile unsigned long *)0xF0302008 = 0x00080952; // Direct COmmnad Register
++ #endif
++#endif
++
++ *(volatile unsigned long *)0xF0302008 = 0x00000000; // Direct COmmnad Register
++
++ //i = 100;
++ i = 200; //soc1-3
++ while(i)
++ {
++ *(volatile unsigned long *) 0xf0302008=0x00040000; // dir_cmd
++ *(volatile unsigned long *) 0xf0302008=0x00040000; // dir_cmd //soc1-3
++ i--;
++ }
++
++#if defined(FMBUS_352MHZ_INCLUDE) || defined(FMBUS_360MHZ_INCLUDE) ||defined(FMBUS_400MHZ_INCLUDE)
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080A62; // Direct COmmnad Register
++ #else
++ *(volatile unsigned long *)0xF0302008 = 0x00080A52; // Direct COmmnad Register
++ #endif
++#else
++ #if defined(DRAM_CAS6)
++ *(volatile unsigned long *)0xF0302008 = 0x00080862; // Direct COmmnad Register
++ #else
++ *(volatile unsigned long *)0xF0302008 = 0x00080852; // Direct COmmnad Register
++ #endif
++#endif
++
++
++ #if defined(DRAM_ODTOFF)
++
++ #else
++ *(volatile unsigned long *)0xF0302008 = 0x00090380; // Direct COmmnad Register
++ *(volatile unsigned long *)0xF0302008 = 0x00090004; // Direct COmmnad Register //soc1-3
++ #endif
++
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++ i = 1600;
++ while(i)
++ i--;
++
++}
++
++typedef void (*lpfunc)();
++lpfunc lpSelfRefresh;
++
++void init_copybootddr(void)
++{
++ #define SRAM_ADDR_STANDBY 0x10000400
++ #define SRAM_FUNC_SIZE 0x900
++ volatile unsigned int *fptr;
++ volatile unsigned int *p;
++ int i;
++ unsigned int lstack = 0;
++
++ fptr = (volatile unsigned int*)init_bootddr;
++ lpSelfRefresh = (lpfunc)(SRAM_ADDR_STANDBY);
++
++ p = (volatile unsigned int*)SRAM_ADDR_STANDBY;
++
++ for (i = 0;i < (SRAM_FUNC_SIZE);i++)
++ {
++ *p = *fptr;
++ p++;
++ fptr++;
++ }
++
++ while(--i);
++
++ // Jump to Function Start Point
++ lpSelfRefresh();
++}
++#endif //!defined(NKUSE) && !defined(__KERNEL__)
++#endif //defined(DRAM_DDR2)
++
++/************* end of file *************************************************************/
++
+diff --git a/drivers/block/tcc/init_mddr.c b/drivers/block/tcc/init_mddr.c
+new file mode 100644
+index 0000000..ec223a2
+--- /dev/null
++++ b/drivers/block/tcc/init_mddr.c
+@@ -0,0 +1,808 @@
++/****************************************************************************
++ * FileName : init_MEM.c
++ * Description : Init code for TCC8900 DDRAM
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#if defined(_WINCE_)
++#include "bsp.h"
++#elif defined(_LINUX_)
++#include <common.h>
++#include <def_tcc.h>
++#endif
++
++#if defined(DRAM_MDDR)
++#define DRAM_AUTOPD_ENABLE Hw13
++#define DRAM_AUTOPD_PERIOD 4<<7 // must larger than CAS latency
++#define DRAM_SET_AUTOPD DRAM_AUTOPD_ENABLE|DRAM_AUTOPD_PERIOD
++
++#define repeat(n) { volatile int i; for (i=0; i<=n; i++); }
++#define DDR_DELAY 1
++/****************************************************************************************
++* FUNCTION :void InitRoutine_Start(void)
++* DESCRIPTION :
++* ***************************************************************************************/
++ /*-------------------
++ PLL0 m p s
++ ------------------
++ 600 200 2 1
++ 500 250 3 1
++ 480 160 2 1
++ 480 400 3 2
++ ---------------------*/
++ /*-------------------
++ PLL1 m p s
++ ------------------
++ 560 140 3 0
++ 520 130 3 0
++ 500 125 3 0
++ 480 40 1 0
++ ---------------------*/
++#pragma optimize( "g", off )
++
++volatile void InitRoutine_Start(void)
++{
++ volatile unsigned int i;
++ //*(volatile unsigned long *)0xF0101000 |= 0x00800000;
++
++ // 44.0 ms
++//Enter Mode
++ *(volatile unsigned long *)0xF0301004 = 0x00000003; // PL340_PAUSE
++ while (((*(volatile unsigned long *)0xF0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0301004 = 0x00000004; // PL340_Configure
++ while (((*(volatile unsigned long *)0xF0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302c &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++ i = 1600;
++ while(i)
++ i--;
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *)0xF0301008 = 0x00040000;
++ i--;
++ } // repeat end
++ // 37.7 ms
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400000 = 0x002ffff4; // XI - corebus
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++//PLL0
++ *(volatile unsigned long *)0xF0400020= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400020= 0x0100C802; // pms - pllout_600M
++ *(volatile unsigned long *)0xF0400020= 0x8100C802; // pll pwr on
++//PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400024= 0x00008c03; // pms - pllout_560M
++ *(volatile unsigned long *)0xF0400024= 0x80008c03; // pll pwr on
++
++//PLL2
++// *(volatile unsigned long *)0xF0400028= 0x0000fa03; // pll pwr off
++// *(volatile unsigned long *)0xF0400028= 0x00002701; // pms - pllout_468M
++// *(volatile unsigned long *)0xF0400028= 0x80002701; // pll pwr on
++ i = 3200;
++ while(i)
++ i--;
++ *(volatile unsigned long *)0xF0400000 = 0x002AAAA0; // 300Mhz
++ *(volatile unsigned long *)0xF0400008 = 0x00200030; // 150Mhz
++ *(volatile unsigned long *)0xF0400010 = 0x00200022; // CKC-CLKCTRL4 - I/O BUS
++ i = 3200;
++ while(i)
++ i--;
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *)0xF0301008 = 0x00040000;
++ i--;
++ } // repeat end
++
++ *(volatile unsigned long *)0xF0301004 = 0x00000004; // PL340_Configure
++ while (((*(volatile unsigned long *)0xF0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++ // MEMCFG0
++#if defined(DRAM_ROW14)
++ // clumn_bits=3, row_bits=2, ap_bit=0, mem_burst=2,active.chips=0
++ *(volatile unsigned long *)0xF030100c = 0x0001001A|DRAM_SET_AUTOPD;
++#else
++ #if defined(DRAM_COL9)
++ // clumn_bits=1, row_bits=2, ap_bit=0, mem_burst=2,active.chips=0
++ *(volatile unsigned long *)0xF030100c = 0x00010011|DRAM_SET_AUTOPD;
++ #else
++ // clumn_bits=2, row_bits=2, ap_bit=0, mem_burst=2,active.chips=0
++ *(volatile unsigned long *)0xF030100c = 0x00010012|DRAM_SET_AUTOPD;
++ #endif
++#endif
++
++ // MEMCFG1
++ // mem_width=1, mem_type=3,read_delay=1, Sync = 1
++ *(volatile unsigned long *)0xF030104c = 0x000002d1;
++ *(volatile unsigned long *)0xF0301010 = 0x000003e8; // refresh_prd = 1000
++ *(volatile unsigned long *)0xF0301014 = 0x00000006; // cas_latency = 3
++ *(volatile unsigned long *)0xF030101C = 0x00000002; // tMRD=3
++ *(volatile unsigned long *)0xF0301020 = 0x00000005; // tRAS=6
++ *(volatile unsigned long *)0xF0301024 = 0x00000007; // tRC=11
++// *(volatile unsigned long *)0xF0301028 = 0x00000003; // tRCD=3<<3|5<<0
++ *(volatile unsigned long *)0xF0301028 = 0x0000000B; // tRCD=3<<3|5<<0
++// *(volatile unsigned long *)0xF030102c = 0x00000B0E; // tRFC=(19<<5|21<<0)
++ *(volatile unsigned long *)0xF030102c = 0x0000016E; // tRFC=(B<<5|E<<0)
++// *(volatile unsigned long *)0xF0301030 = 0x00000003; // tRP=3<<3|5<<0
++ *(volatile unsigned long *)0xF0301030 = 0x0000000B; // tRP=3<<3|5<<0
++ *(volatile unsigned long *)0xF0301034 = 0x00000001; // tRRD=2
++ *(volatile unsigned long *)0xF0301038 = 0x00000002; // tWR=5
++ *(volatile unsigned long *)0xF030103c = 0x00000001; // tWTR=4
++ *(volatile unsigned long *)0xF0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xF0301044 = 0x00000012; // tXSR=14
++ *(volatile unsigned long *)0xF0301048 = 0x00000032; // tESR=200
++ // CHIP0 address_match=0x40, address_mask=0x40
++ // 1CS
++ #if defined(DRAM_SIZE_64)
++ *(volatile unsigned long *) 0xF0301200=0x000040FC; // config_chip0 - CS0 - 0x40000000~0x47ffffff
++ #endif
++ #if defined(DRAM_SIZE_128)
++ *(volatile unsigned long *) 0xF0301200=0x000040F8; // config_chip0 - CS0 - 0x40000000~0x47ffffff
++ #endif
++ #if defined(DRAM_SIZE_256)
++ *(volatile unsigned long *) 0xF0301200=0x000040F0; // config_chip0 - CS0 - 0x40000000~0x47ffffff
++ #endif
++
++/*
++ i = 3200;
++ while(i)
++ i--;
++*/
++ *(volatile unsigned long *)0xF030302C = 0x3FFF;
++
++ //HwEMCCFG->uCONFIG0.bReg.AXI_SEL = 0;
++ //HwEMCCFG->uCONFIG0.bReg.IO_SEL = 1;
++ *(volatile unsigned long *)0xF0303020 = 0x00010102;
++ //HwEMCCFG->uPHYCTRL.bReg.PL340_SEL = 1;
++ *(volatile unsigned long *)0xF0303024 = 0x00000100;
++// *(volatile unsigned long *)0xF030302C = 0x00000000;
++ //SSTL_IO_Init (IO_CMOS)
++ *(volatile unsigned long *) 0xF0304400=0x00000002; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *) 0xF0304404=0x00004d69; // DLLCTRL - DLL ON
++ *(volatile unsigned long *) 0xF0304408=0x00002f2f; // DLLPDCFG (200Mhz)
++ *(volatile unsigned long *) 0xF0304404=0x000047d3; // DLLCTRL - DLL ON, DLL start
++ while (!((*(volatile unsigned long *)0xF0304404) & (3<<3))); // Wait until PDFL == 1
++
++ *(volatile unsigned long *) 0xF0304424=0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *) 0xF030440c=0x00000003; // GATECTRL
++ *(volatile unsigned long *) 0xF0304430=0x00000004; // RDDELAY - SOC
++ *(volatile unsigned long *) 0xF0304428=0x0006F151; // ZQCTRL Termination Selection : 0 for disable
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++
++ *(volatile unsigned long *) 0xF0304428=0x0006F153; // ZQCTRL Termination Selection : 0 for disable
++/*
++ i = 3200;
++ while(i)
++ i--;
++ */
++ *(volatile unsigned long *) 0xF0304428=0x0006F151; // ZQCTRL Termination Selection : 0 for disable
++ //i = 3200;
++ //while(i)
++ // i--;
++
++ //HwPL340->direct_cmd =
++ *(volatile unsigned long *)0xF0301008 = 0x00000032; // ECMD : 0 , MCMD : 00 - Prechargeall
++ *(volatile unsigned long *)0xF0301008 = 0x000a0000; // ECMD : 0 , MCMD : 10 - Modereg or extended modereg access -------EMRS
++ *(volatile unsigned long *)0xF0301008 = 0x00080032; //ECMD : 0 , MCMD : 10 - Modereg or extended modereg access --------MRS
++
++
++ i = 50;
++ while(i)
++ {
++ *(volatile unsigned long *)0xF0301008 = 0x00040032;
++ i--;
++ *(volatile unsigned long *)0xF0301008 = 0x00040032;
++ }
++
++
++ *(volatile unsigned long *) 0xF0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xF0301000) & (0x03)) != 1); // Wait until READY
++
++}
++#pragma optimize( "g", on )
++
++volatile void InitRoutine_End(void)
++{
++
++}
++#ifndef NKUSE
++/*=========================================================================================================================
++*
++* Used Boot Loader
++*
++==========================================================================================================================*/
++void init_clock(void)
++{
++ PCKC lCKC = (CKC *)&HwCLK_BASE;
++ PPMU lPMU = (PMU *)&HwPMU_BASE;
++ PNTSCPAL lNTSCPAL=(PNTSCPAL)&HwTVE_BASE;
++ volatile unsigned int nCount = 0;
++
++
++ tca_ckc_init();
++
++ // Set PLL - default PLL: PLL1,PLL2,PLL3 Disable
++ // Change PLL Value
++ tca_ckc_setpll(4680000,2); // 240 *2 100hz -SDMMC
++ tca_ckc_setpll(5280000,3); // 156 *2 100hz
++
++ //CLKDIVC0/1
++ lCKC->CLKDIVC = 0x01010101;
++ lCKC->CLKDIVC1 = 0x01010101;
++
++#if defined(TCC_R_AX)
++ tca_ckc_setswreset(RESET_VIDEOBUS, ON);
++ tca_ckc_setswreset(RESET_VIDEOCORE, ON);
++ #if !defined(TCC_MAX_FGRP_INCLUDE)
++ tca_ckc_setswreset(RESET_GRAPBUS, ON);
++ #endif
++#endif
++
++ tca_ckc_setfbusctrl(CLKCTRL1,ENABLE,NORMAL_MD,2340000,DIRECTPLL2);/*FBUS_DDI 240 MHz */
++#if defined(TCC_R_AX)
++ #if defined(TCC_MAX_FGRP_INCLUDE)
++ tca_ckc_setfbusctrl(CLKCTRL3,ENABLE,NORMAL_MD,2340000,DIRECTPLL2);/*FBUS_GRP 190 MHz */
++ #else
++ tca_ckc_setfbusctrl(CLKCTRL3,DISABLE,NORMAL_MD,60000,DIRECTXIN);/*FBUS_GRP 190 MHz */
++ #endif
++#else
++ tca_ckc_setfbusctrl(CLKCTRL3,ENABLE,NORMAL_MD,2340000,DIRECTPLL2);/*FBUS_GRP 190 MHz */
++#endif
++ tca_ckc_setfbusctrl(CLKCTRL4,ENABLE,NORMAL_MD,1560000,DIRECTPLL2);/*FBUS_IOB 166 MHz */
++
++#if defined(TCC_R_AX)
++ tca_ckc_setfbusctrl(CLKCTRL5,DISABLE,NORMAL_MD,60000,DIRECTXIN);/*FBUS_VBUS 215 MHz */ //2640000 , 1760000
++ tca_ckc_setfbusctrl(CLKCTRL6,DISABLE,NORMAL_MD,60000,DIRECTXIN);/*FBUS_VCODEC 160 MHz */ //2340000 , 1560000
++#else
++ tca_ckc_setfbusctrl(CLKCTRL5,ENABLE,NORMAL_MD,60000,DIRECTXIN);/*FBUS_VBUS 215 MHz */ //2640000 , 1760000
++ tca_ckc_setfbusctrl(CLKCTRL6,ENABLE,NORMAL_MD,60000,DIRECTXIN);/*FBUS_VCODEC 160 MHz */ //2340000 , 1560000
++#endif
++ tca_ckc_setfbusctrl(CLKCTRL7,ENABLE,NORMAL_MD,1170000,DIRECTPLL2);/*FBUS_SMU 125 MHz */
++
++ // Enable Peri.
++ lPMU->CONTROL |= Hw16; // Touch ADC Power Enable
++ nCount = 10;
++ for ( ; nCount > 0 ; nCount --); // delay
++ lNTSCPAL->DACPD |= Hw0;
++
++ lPMU->PWROFF &= ~Hw0; // Video Dac(TVOUT)
++ nCount = 500;
++ for ( ; nCount > 0 ; nCount --); // delay
++
++ lPMU->PWROFF |=(Hw0 // Video Dac(TVOUT)
++ |Hw1 // HDMI PHY
++ |Hw2 // LVDS
++ |Hw4 //SATA PHY
++#if defined(TCC_R_AX)
++ |Hw6 // Video Bus
++ #if !defined(TCC_MAX_FGRP_INCLUDE)
++ |Hw8
++ #endif
++#endif
++ ); // HDMI Phy,LVDS Phy,SATA Phy , Video Bus , Graphic Bus
++
++#if defined(TCC_R_AX)
++ tca_ckc_setswreset(RESET_VIDEOCORE, OFF);
++ tca_ckc_setswreset(RESET_VIDEOBUS, OFF);
++ #if !defined(TCC_MAX_FGRP_INCLUDE)
++ tca_ckc_setswreset(RESET_GRAPBUS, OFF);
++ #endif
++#endif
++
++// init Peri. Clock
++ tca_ckc_setperi(PERI_TCZ,ENABLE,120000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_ADC,ENABLE,120000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_I2C,ENABLE,40000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_UART0,ENABLE,520000,PCDIRECTPLL2);
++ tca_ckc_setperi(PERI_LCD1,ENABLE,1560000,PCDIRECTPLL2);
++
++ tca_ckc_setperi(PERI_LCD0,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_LCDSI,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_CIFMC,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_CIFSC,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_OUT0,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_OUT1,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_HDMI,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_SDMMC0,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_MSTICK,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_UART1,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_UART2,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_UART3,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_UART4,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_UART5,DISABLE,10000,PCDIRECTXIN);
++
++ tca_ckc_setperi(PERI_GPSB0,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_GPSB1,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_GPSB2,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_GPSB3,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_GPSB4,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_GPSB5,DISABLE,10000,PCDIRECTXIN);
++
++// tca_ckc_setperi(PERI_SPDIF,ENABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_EHI0,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_EHI1,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_CAN,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_SDMMC1,DISABLE,10000,PCDIRECTXIN);
++ tca_ckc_setperi(PERI_DAI,DISABLE,10000,PCDIRECTXIN);
++
++// init Io Bus
++ tca_ckc_setiobus(RB_USB11H, DISABLE);
++ tca_ckc_setiobus(RB_IDECONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_SDMMCCONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_SATAHCONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_MEMORYSTICKCONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_EXTHCONTROLLER0, DISABLE);
++ tca_ckc_setiobus(RB_EXTHCONTROLLER1, DISABLE);
++ tca_ckc_setiobus(RB_UARTCONTROLLER1, DISABLE);
++ tca_ckc_setiobus(RB_UARTCONTROLLER2, DISABLE);
++ tca_ckc_setiobus(RB_UARTCONTROLLER3, DISABLE);
++ tca_ckc_setiobus(RB_UARTCONTROLLER4, DISABLE);
++ tca_ckc_setiobus(RB_UARTCONTROLLER5, DISABLE);
++ tca_ckc_setiobus(RB_GPSBCONTROLLER0, DISABLE);
++ tca_ckc_setiobus(RB_GPSBCONTROLLER1, DISABLE);
++ tca_ckc_setiobus(RB_GPSBCONTROLLER2, DISABLE);
++ tca_ckc_setiobus(RB_GPSBCONTROLLER3, DISABLE);
++ tca_ckc_setiobus(RB_GPSBCONTROLLER4, DISABLE);
++ tca_ckc_setiobus(RB_GPSBCONTROLLER5, DISABLE);
++ tca_ckc_setiobus(RB_SPDIFTXCONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_GPSCONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_CANCONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_MPE_FECCONTROLLER, DISABLE);
++ tca_ckc_setiobus(RB_TSIFCONTROLLER, DISABLE);
++// tca_ckc_setiobus(RB_SRAMCONTROLLER, DISABLE);
++
++// init ddi Pwdn
++ tca_ckc_setddipwdn(DDIPWDN_CIF, DISABLE);
++ tca_ckc_setddipwdn(DDIPWDN_VIQE, DISABLE);
++ tca_ckc_setddipwdn(DDIPWDN_LCDC0, DISABLE);
++ tca_ckc_setddipwdn(DDIPWDN_MSCL0, DISABLE);
++ tca_ckc_setddipwdn(DDIPWDN_MSCL1, DISABLE);
++ tca_ckc_setddipwdn(DDIPWDN_HDMI, DISABLE);
++
++
++}
++
++/*
++* Example
++* ------------------------------------------------------------------------------------------------------------------------------
++* define HIGH_VOLTAGE_CLOCK_INCLUDE
++*
++* 1. Core 600Mhz, Mem 400Mhz
++* #define lpll0 800
++* #define lpll1 660
++* #define lmem_source 0 // 0 : PLL0 , 1 : PLL1
++* #define lcore_div 12 // (lpll0 * lcore_div)/16 - refer DataSheet CKC Block
++* #define lmem_div 2 // if lmem_source is 0, lpll0/lmem_div = Mem Bus / if lmem_source is 0, lpll0/lmem_div = Mem Bus
++*
++* 2. Core 600Mhz, Mem 330Mhz
++* #define lpll0 600
++* #define lpll1 660
++* #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++* #define lcore_div 16 // (lpll0 * lcore_div)/16 - refer DataSheet CKC Block
++* #define lmem_div 2 // if lmem_source is 0, lpll0/lmem_div = Mem Bus / if lmem_source is 1, lpll1/lmem_div = Mem Bus
++* 3. Core 506Mhz, Mem 330Mhz
++* #define lpll0 540
++* #define lpll1 660
++* #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++* #define lcore_div 15 // (lpll0 * lcore_div)/16 - refer DataSheet CKC Block
++* #define lmem_div 2 // if lmem_source is 0, lpll0/lmem_div = Mem Bus / if lmem_source is 1, lpll1/lmem_div = Mem Bus
++* ------------------------------------------------------------------------------------------------------------------------------
++* 4. Core 600Mhz, Mem 280Mhz
++* #define lpll0 600
++* #define lpll1 560
++* #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++* #define lcore_div 16 // (lpll0 * lcore_div)/16 - refer DataSheet CKC Block
++* #define lmem_div 2 // if lmem_source is 0, lpll0/lmem_div = Mem Bus / if lmem_source is 1, lpll1/lmem_div = Mem Bus
++*
++* 5. Core 506Mhz, Mem 280Mhz
++* #define lpll0 540
++* #define lpll1 560
++* #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++* #define lcore_div 15 // (lpll0 * lcore_div)/16 - refer DataSheet CKC Block
++* #define lmem_div 2 // if lmem_source is 0, lpll0/lmem_div = Mem Bus / if lmem_source is 0, lpll0/lmem_div = Mem Bus
++* ------------------------------------------------------------------------------------------------------------------------------
++*/
++#pragma optimize( "g", off )
++
++void init_bootddr(void)
++{
++ #define lmem_source 1 // 0 : PLL0 , 1 : PLL1
++// Core
++ #if defined(FCPU_337MHZ_INCLUDE)
++ #define lpll0 540
++ #define lcore_div 10 // refer DataSheet CKC Block
++ #elif defined(FCPU_506MHZ_INCLUDE)
++ #define lpll0 540
++ #define lcore_div 15 // refer DataSheet CKC Block
++ #elif defined(FCPU_600MHZ_INCLUDE)
++ #define lpll0 600
++ #define lcore_div 16 // refer DataSheet CKC Block
++ #else
++ #define lpll0 540
++ #define lcore_div 15 // refer DataSheet CKC Block
++ #endif
++// Mbus
++ #if defined(FMBUS_180MHZ_INCLUDE)
++ #define lpll1 360
++ #elif defined(FMBUS_160MHZ_INCLUDE)
++ #define lpll1 320
++ #elif defined(FMBUS_133MHZ_INCLUDE)
++ #define lpll1 266
++ #else
++ #define lpll1 266
++ #endif
++
++
++ #define lmem_div 2
++ volatile unsigned int i = 0;
++ unsigned int ldiv = 0;
++ unsigned int lcycle = 0;
++ unsigned int lindex[17];
++ lindex[0] = 0x0;
++ lindex[1] = 0x8000;
++ lindex[2] = 0x8008;
++ lindex[3] = 0x8808;
++ lindex[4] = 0x8888;
++ lindex[5] = 0xA888;
++ lindex[6] = 0xA8A8;
++ lindex[7] = 0xAAA8;
++ lindex[8] = 0xAAAA;
++ lindex[9] = 0xECCC;
++ lindex[10] = 0xEECC;
++ lindex[11] = 0xEEEC;
++ lindex[12] = 0xEEEE;
++ lindex[13] = 0xFEEE;
++ lindex[14] = 0xFFEE;
++ lindex[15] = 0xFFFE;
++ lindex[16] = 0xFFFF;
++
++//Enter Mode
++ *(volatile unsigned long *)0xF0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0301000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0301004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++// DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302c &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ i = 1600;
++ while(i)
++ i--;
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *)0xF0301008 = 0x00040000;
++ i--;
++ } // repeat end
++
++
++//Clock Change
++ *(volatile unsigned long *)0xF0400030 = 0x01010101;
++ *(volatile unsigned long *)0xF0400034 = 0x01010101;
++
++ *(volatile unsigned long *)0xF0400000 = 0x002ffff4; // XI - corebus
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // XI - memebus
++
++ i = 2400;
++ while(i)
++ i--;
++
++ //PLL0
++ *(volatile unsigned long *)0xF0400020= 0x0000fa03; // pll pwr off
++
++ if(lpll0 == 600)
++ {
++ *(volatile unsigned long *)0xF0400020= 0x0100C802; // pms - pllout_600M
++ *(volatile unsigned long *)0xF0400020= 0x8100C802; // pll pwr on
++ }
++ else if(lpll0 == 540)
++ {
++ *(volatile unsigned long *)0xF0400020= 0x0100B402; // pms - pllout_540M
++ *(volatile unsigned long *)0xF0400020= 0x8100B402; // pll pwr on
++ }
++ else if(lpll0 == 400)
++ {
++ *(volatile unsigned long *)0xF0400020= 0x02019003; // pms - pllout_400M
++ *(volatile unsigned long *)0xF0400020= 0x82019003; // pll pwr on
++ }
++ else
++ {
++ *(volatile unsigned long *)0xF0400020= 0x0100C802; // pms - pllout_600M
++ *(volatile unsigned long *)0xF0400020= 0x8100C802; // pll pwr on
++ }
++
++ //PLL1
++ *(volatile unsigned long *)0xF0400024= 0x0000fa03; // pll pwr off
++ if(lpll1 == 360)
++ {
++ *(volatile unsigned long *)0xF0400024= 0x00001E01; // pms - pllout_360M
++ *(volatile unsigned long *)0xF0400024= 0x80001E01; // pll pwr on
++ }
++ else if(lpll1 == 320)
++ {
++ *(volatile unsigned long *)0xF0400024= 0x00005003; // pms - pllout_320M
++ *(volatile unsigned long *)0xF0400024= 0x80005003; // pll pwr on
++ }
++ else if(lpll1 == 266)
++ {
++ *(volatile unsigned long *)0xF0400024= 0x01008503; // pms - pllout_266M
++ *(volatile unsigned long *)0xF0400024= 0x81008503; // pll pwr on
++ }
++ else
++ {
++ *(volatile unsigned long *)0xF0400024= 0x01008503; // pms - pllout_266M
++ *(volatile unsigned long *)0xF0400024= 0x81008503; // pll pwr on
++ }
++
++//PLL2
++ *(volatile unsigned long *)0xF0400028= 0x0000fa03; // pll pwr off
++ *(volatile unsigned long *)0xF0400028= 0x00002701; // pms - pllout_468M
++ *(volatile unsigned long *)0xF0400028= 0x80002701; // pll pwr on
++
++ i = 3200;
++ while(i)
++ i--;
++ *(volatile unsigned long *)0xF0400000 = (0x00200000 | (lindex[lcore_div] << 4)); // CKC-CLKCTRL0 - Core
++ *(volatile unsigned long *)0xF0400008 = (0x00200000 | ((lmem_div-1) << 4)|lmem_source); // CKC-CLKCTRL2 - Mem
++ i = 3200;
++ while(i)
++ i--;
++
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *)0xF0301008 = 0x00040000;
++ i--;
++ }
++
++//Init mDDR
++// memory arb.
++/*
++ *(volatile unsigned long *)0xF030100C |= 0x00140000;
++ *(volatile unsigned long *) 0xF0301100=0x0000002b; // (10<<2)(1<<1)(1<<0) - video codec + jpeg encoder
++ *(volatile unsigned long *) 0xF0301104=0x0000002b; // (10<<2)(1<<1)(1<<0) - video cache + jpeg decoder
++ *(volatile unsigned long *) 0xF0301108=0x00000017; // (5<<2)(1<<1)(1<<0) - video codec secondary
++ *(volatile unsigned long *) 0xF030110c=0x00000017; // (5<<2)(1<<1)(1<<0) - io bus
++ *(volatile unsigned long *) 0xF0301110=0x0000000f; // (3<<2)(1<<1)(1<<1) - lcd
++ *(volatile unsigned long *) 0xF0301114=0x0000000f; // (3<<2)(1<<1)(1<<1) - lcd_mscl
++ *(volatile unsigned long *) 0xF0301118=0x00000017; // (5<<2)(1<<1)(1<<1) - VIQE
++ *(volatile unsigned long *) 0xF030111c=0x00000007; // (1<<2)(1<<1)(1<<1) - ddi cache
++ *(volatile unsigned long *) 0xF0301124=0x0000003f; // (15<<2)(1<<1)(1<<1) - ARM DMA bus
++ *(volatile unsigned long *) 0xF0301128=0x0000003f; // (15<<2)(1<<1)(1<<1) - ARM data bus
++ *(volatile unsigned long *) 0xF030112c=0x0000002b; // (10<<2)(1<<1)(1<<1) - ARM instruction
++ *(volatile unsigned long *) 0xF0301130=0x0000003f; // (15<<2)(1<<1)(1<<1) - overlay mixer
++ *(volatile unsigned long *) 0xF0301134=0x0000003f; // (15<<2)(1<<1)(1<<1) - overlay mixer
++ *(volatile unsigned long *) 0xF0301138=0x0000003f; // (15<<2)(1<<1)(1<<1) - overlay mixer
++ *(volatile unsigned long *) 0xF030113c=0x0000002b; // (10<<2)(1<<1)(1<<1) - 3d
++*/
++// memory arb. end
++
++ i = 100;
++ while(i)
++ {
++ *(volatile unsigned long *)0xF0301008 = 0x00040000;
++ i--;
++ }
++
++ *(volatile unsigned long *) 0xF0301004=0x00000004; // PL341_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0301000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++
++#if defined(DRAM_ROW14)
++ // clumn_bits=3, row_bits=2, ap_bit=0, mem_burst=2,active.chips=0
++ *(volatile unsigned long *)0xF030100C = 0x0021001A|DRAM_SET_AUTOPD; // config0 cas 10bit, ras 13bit , AP bit 10, Burst 4, 2chips
++#else
++ #if defined(DRAM_COL9)
++ // clumn_bits=1, row_bits=2, ap_bit=0, mem_burst=2,active.chips=0
++ *(volatile unsigned long *)0xF030100c = 0x00210011|DRAM_SET_AUTOPD;
++ #else
++ // clumn_bits=2, row_bits=2, ap_bit=0, mem_burst=2,active.chips=0
++ *(volatile unsigned long *)0xF030100c = 0x00210012|DRAM_SET_AUTOPD;
++ #endif
++#endif
++
++
++ *(volatile unsigned long *) 0xF0303000 |= 0x00800000; // bit23 enable -synopt enable
++ *(volatile unsigned long *) 0xF0303010 |= 0x00800000; // bit23 enable -synopt enable
++
++ *(volatile unsigned long *)0xF030104C= 0x000002D1;
++
++ *(volatile unsigned long *)0xF0301010 = 0x000003E8; // refresh_prd = 1000
++
++
++
++#if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xF0301014 = 0x00000006; // cas_latency = 3
++#else
++ *(volatile unsigned long *)0xF0301014 = 0x00000004; // cas_latency = 2
++#endif
++
++ *(volatile unsigned long *)0xF030101C = 0x00000002; // tMRD 2tck
++ *(volatile unsigned long *)0xF0301020 = 0x0000000A; // tRAS 42ns
++ *(volatile unsigned long *)0xF0301024 = 0x0000000F; // tRC 60ns
++// *(volatile unsigned long *)0xF0301028 = 0x00000014; // tRCD 18ns
++ *(volatile unsigned long *)0xF0301028 = 0x0000000C; // tRCD 18ns
++// *(volatile unsigned long *)0xF030102c = 0x00000E11; // tRFC 72ns
++ *(volatile unsigned long *)0xF030102c = 0x000001D1; // tRFC 72ns
++// *(volatile unsigned long *)0xF0301030 = 0x00000014; // tRP 18ns
++ *(volatile unsigned long *)0xF0301030 = 0x0000000C; // tRP 18ns
++ *(volatile unsigned long *)0xF0301034 = 0x00000001; // tRRD 12ns
++ *(volatile unsigned long *)0xF0301038 = 0x00000002; // tWR 15ns
++ *(volatile unsigned long *)0xF030103c = 0x00000001; // tWTR 1tck
++ *(volatile unsigned long *)0xF0301040 = 0x00000002; // tXP=3
++ *(volatile unsigned long *)0xF0301044 = 0x00000016; // tXSR 120ns
++ *(volatile unsigned long *)0xF0301048 = 0x00000032; // tESR=200
++
++ i = 3200;
++ while(i)
++ i--;
++
++ // 1CS
++ #if defined(DRAM_SIZE_64)
++ *(volatile unsigned long *) 0xF0301200=0x000040FC; // config_chip0 - CS0 - 0x40000000~0x47ffffff
++ #endif
++ #if defined(DRAM_SIZE_128)
++ *(volatile unsigned long *) 0xF0301200=0x000040F8; // config_chip0 - CS0 - 0x40000000~0x47ffffff
++ #endif
++ #if defined(DRAM_SIZE_256)
++ *(volatile unsigned long *) 0xF0301200=0x000040F0; // config_chip0 - CS0 - 0x40000000~0x47ffffff
++ #endif
++
++ i = 3200;
++ while(i)
++ i--;
++
++#if !defined(DRAM_TYPE9)
++ *(volatile unsigned long *)0xF0301004 = 0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xF0301000) & (0x03)) != 1); // Wait until READY
++
++ *(volatile unsigned long *)0xF0301004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0301000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0301004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0301000) & (0x03)) != 3); // Wait until SLEEP
++#endif
++ *(volatile unsigned long *)0xF030302c &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++ *(volatile unsigned long *)0xF0303020 &= ~(0x00000001); // SW ? AXI_SEL = 0
++ *(volatile unsigned long *)0xF0303020 |= 0x00000002; // SW ? IO_SEL = 1;
++ *(volatile unsigned long *)0xF0303024 = 0x00000100; // Hw8 SDR/mDDR/DDR
++
++
++ *(volatile unsigned long *)0xF0304400 = 0x00000002; // DDR2PHY_PHYMODE
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLLCTRL
++
++ *(volatile unsigned long *) 0xF0304408=0x00002020; // DLLPDCFG (145 ~ 180Mhz)
++
++ *(volatile unsigned long *) 0xF0304404=0x00000003; // DLLCTRL - DLL ON, DLL start
++ while (!((*(volatile unsigned long *)0xF0304404) & (3<<3) == 0x18)); // Wait until PDFL == 1
++ *(volatile unsigned long *)0xF0304424 = 0x00000035; // DLLFORCELOCK
++ *(volatile unsigned long *)0xF030440C = 0x00000003; // GATECTRL
++ *(volatile unsigned long *)0xF0304430 = 0x00000001; // RDDELAY
++
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ while (!((*(volatile unsigned long *)0xF030442c) & (1))); // Wait until Calibration completion without error
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (1 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++ *(volatile unsigned long *)0xF0304428 = (3 << 17) // PRD_CAL
++ | (0 << 16) // PRD_CEN
++ | (7 << 13) // DRV_STR
++ | (1 << 12) // TERM_DIS
++ | (2 << 9) // ODT(PHY) value
++ | (5 << 6) // PULL UP
++ | (2 << 3) // PULL DOWN
++ | (0 << 2) // ZQ
++ | (0 << 1) // UPDATE
++ | (1 << 0); // CAL_START
++
++ i = 3200;
++ while(i)
++ i--;
++#if !defined(DRAM_TYPE9)
++ *(volatile unsigned long *)0xF0301004 = 0x00000002; // PL340_WAKEUP
++ while (((*(volatile unsigned long *)0xF0301000) & (0x03)) != 2); // Wait until PAUSE
++
++ *(volatile unsigned long *)0xF0301004 = 0x00000004; // PL340_CONFIGURE
++ while (((*(volatile unsigned long *)0xF0301000) & (0x03)) != 0); // Wait until CONFIGURE
++#endif
++
++ #if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xF0301008 = 0x00000032; //MRS
++ #else
++ *(volatile unsigned long *)0xF0301008 = 0x00000022; //MRS
++ #endif
++
++ *(volatile unsigned long *)0xF0301008 = 0x000a0000;//EMRS
++ #if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xF0301008 = 0x00080032;
++ #else
++ *(volatile unsigned long *)0xF0301008 = 0x00080022;
++ #endif
++
++ // repeat 100
++ i = 100;
++ while(i)
++ {
++ #if defined(DRAM_CAS3)
++ *(volatile unsigned long *)0xF0301008 = 0x00040032;
++ #else
++ *(volatile unsigned long *)0xF0301008 = 0x00040022;
++ #endif
++ i--;
++ } // repeat end
++
++ *(volatile unsigned long *) 0xF0301004=0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xF0301000) & (0x03)) != 1); // Wait until READY
++
++}
++#pragma optimize( "g", on )
++
++typedef void (*lpfunc)();
++lpfunc lpSelfRefresh;
++
++void init_copybootddr(void)
++{
++ #define SRAM_ADDR_STANDBY 0x10000400
++ #define SRAM_FUNC_SIZE 0x900
++ volatile unsigned int *fptr;
++ volatile unsigned int *p;
++ int i;
++ unsigned int lstack = 0;
++
++ fptr = (volatile unsigned int*)init_bootddr;
++ lpSelfRefresh = (lpfunc)(SRAM_ADDR_STANDBY);
++
++ p = (volatile unsigned int*)SRAM_ADDR_STANDBY;
++
++ for (i = 0;i < (SRAM_FUNC_SIZE);i++)
++ {
++ *p = *fptr;
++ p++;
++ fptr++;
++ }
++
++ while(--i);
++
++ // Jump to Function Start Point
++ lpSelfRefresh();
++}
++
++#endif // NKUSE
++#endif //defined(DRAM_MDDR)
++
++/************* end of file *************************************************************/
++
++
+diff --git a/drivers/block/tcc/kernel_nand_drv.c b/drivers/block/tcc/kernel_nand_drv.c
+new file mode 100644
+index 0000000..dd9c37c
+--- /dev/null
++++ b/drivers/block/tcc/kernel_nand_drv.c
+@@ -0,0 +1,1663 @@
++/*
++ * TITLE: LINUX NAND DRIVER
++ * CORE TYPE: TCCXXX
++ * DRIVER TYPE: kernel module
++ * NAME: tccXXX_nand.ko
++ *
++ * @Copyright 2008 Telechips, Inc.
++ * SYS4-3 Team Linux <linux@telechips.com>
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++
++#include <linux/ctype.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/fcntl.h>
++#include <linux/vmalloc.h>
++#include <linux/genhd.h>
++#include <linux/blkdev.h>
++#include <linux/hdreg.h>
++#include <linux/blkpg.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/irq.h>
++#include <asm/scatterlist.h>
++#include <asm/mach-types.h>
++#include <asm/memory.h>
++#include <asm/dma.h>
++
++#include "kernel_nand_drv.h"
++#include "Disk.h"
++
++#include <linux/tcc_ioctl.h>
++
++#define NDD_DEV_NAME "ndd"
++#define NDD_DEV_MAJOR 240
++#define MAX_NDD_DEV MAX_NAND_DRIVE // # of NAND device: 1
++#define NDD_MAX_PARTITIONS 5 // Max # of partitions: 4
++
++#define __USE_TCC_NAND_WORK_Q__
++
++#ifdef __USE_TCC_NAND_WORK_Q__
++#include <linux/workqueue.h>
++#include <linux/slab.h>
++#include <linux/kthread.h>
++nand_priv_data_t tcc_nand_data[MAX_NDD_DEV];
++#endif
++
++//=============================================================================
++//*
++//*
++//* [ CONST DATA DEFINE ]
++//*
++//*
++//=============================================================================
++struct dma_buf dma_t;
++static int ndevices = 2;
++module_param(ndevices, int, 0);
++#ifdef __USE_NAND_ISR__
++nand_intr_info_rb nand_intr_rb;
++nand_intr_info nand_intr;
++#endif
++
++//=============================================================================
++//*
++//*
++//* [ GLOBAL VARIABLE DEFINE ]
++//*
++//*
++//=============================================================================
++#ifdef __USE_NAND_ISR__
++int ndd_isr_rb_enable_flag = NDD_RB_INTR_MODE_NORMAL;
++#endif
++
++//=============================================================================
++//*
++//*
++//* [ LOCAL FUNCTIONS DEFINE ]
++//*
++//*
++//=============================================================================
++static int ndd_ioctl (struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long arg);
++static int ndd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
++static int ndd_open(struct block_device *bdev, fmode_t mode);
++static int ndd_release(struct gendisk *disk, fmode_t mode);
++#ifdef __USE_NAND_ISR__
++static int nand_isr_read( struct request_queue *request_q, struct request *req );
++#ifdef __USE_NAND_ISR_WRITE__
++static int nand_isr_write( struct request_queue *request_q, struct request *req );
++#endif
++#endif
++static void ndd_request(struct request_queue *q);
++static void ndd_transfer(Device *dev, unsigned long sector, unsigned long nsect, char *buffer, int write);
++#ifdef __USE_NAND_ISR__
++static void ndd_get_phypageinfo( ndd_work_info *nand_work_info, int nMode );
++#endif
++
++static Device ndd_dev[MAX_NDD_DEV];
++static struct block_device_operations ndd_fops =
++{
++ .owner = THIS_MODULE,
++ .open = ndd_open,
++ .release = ndd_release,
++ .ioctl = ndd_ioctl,
++ .getgeo = ndd_getgeo,
++};
++
++//=============================================================================
++//*
++//*
++//* [ EXTERN VARIABLE & FUNCTIONS DEFINE ]
++//*
++//*
++//=============================================================================
++extern unsigned char *gNAND_PageBuffer;
++extern unsigned char gNAND_PartitionInfoLoadFlag;
++extern int FWUG_MainFunc(char *rom_buf, int iFileSize);
++
++#ifdef __USE_TCC_NAND_WORK_Q__
++static int tcc_nand_issue(void *d)
++{
++ nand_priv_data_t *nand_priv = (nand_priv_data_t *)d;
++ #ifdef __USE_NAND_ISR__
++ unsigned int i = 0;
++ #endif
++ unsigned int idx = 0, sector = 0;
++ int first = 1;
++ int xfer = 0;
++ struct request_queue *q = nand_priv->req;
++
++ #ifdef __USE_NAND_ISR_WRITE__
++ unsigned char *pSpareBuffer, *pStuffPageBuffer;
++ #endif
++
++ do {
++ struct request *req = NULL;
++
++ spin_lock_irq(q->queue_lock);
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (!blk_queue_plugged(q)) {
++ req = elv_next_request(q);
++ }
++ spin_unlock_irq(q->queue_lock);
++
++ if (!req) {
++ first = 1;
++ if (kthread_should_stop()) {
++ set_current_state(TASK_RUNNING);
++ break;
++ }
++ schedule();
++ continue;
++ }
++
++ set_current_state(TASK_RUNNING);
++ {
++ Device *dev = req->rq_disk->private_data;
++ if (!blk_fs_request(req)) {
++ end_request(req, 0);
++ } else {
++#ifdef __USE_NAND_ISR__
++ /* read */
++ if (!rq_data_dir(req))
++ {
++ i = req->sector;
++ n_printk("Read_Sector:[%d]-[%lu-%d]\n",i, req->nr_sectors, req->current_nr_sectors);
++
++ if ( ( req->nr_sectors > 8 ) && ( first == 1 ) )
++ {
++ n_printk("\n--IRQ_READ");
++ for ( i = 0; i < req->current_nr_sectors; ++i )
++ dev->nand_work_info->BufferAddr[ i ] = (unsigned int )( req->buffer + (i << 9));
++
++ dev->nand_work_info->StartSector = req->sector;
++ dev->nand_work_info->SectorNum = req->nr_sectors;
++
++ //========================================
++ // get phy page addr info
++ //========================================
++ ndd_get_phypageinfo( dev->nand_work_info, 0 );
++
++ // Read Start
++ nand_isr_read( q, req );
++
++ first = 1;
++ }
++ else
++ {
++ first = 0;
++ n_printk("\n--NORMAL_READ");
++
++ ndd_transfer(dev, req->sector, req->current_nr_sectors, req->buffer, 0);
++
++ if (req->current_nr_sectors == req->nr_sectors)
++ first = 1;
++ }
++
++ end_request(req, 1);
++ }
++ else
++ {
++ #ifdef __USE_NAND_ISR_WRITE__
++ /* write */
++ pSpareBuffer = dev->nand_work_info->nSpareBuffer;
++ pStuffPageBuffer = dev->nand_work_info->StuffInfo.nStuffPageBuffer;
++
++ i = req->sector;
++ n_printk("Write_Sector:[%d]-[%lu-%d]\n",i, req->nr_sectors, req->current_nr_sectors);
++
++ if ( ( req->nr_sectors > 8 ) && ( req->current_nr_sectors == 8 ) && ( first == 1 ) )
++ {
++ n_printk("\n--IRQ_WRITE");
++ for ( i = 0; i < req->current_nr_sectors; ++i )
++ dev->nand_work_info->BufferAddr[ i ] = (unsigned int )( req->buffer + (i << 9));
++
++ dev->nand_work_info->StartSector = req->sector;
++ dev->nand_work_info->SectorNum = req->nr_sectors;
++
++ //========================================
++ // get phy page addr info
++ //========================================
++ ndd_get_phypageinfo( dev->nand_work_info, 1 );
++ dev->nand_work_info->nSpareBuffer = pSpareBuffer;
++ dev->nand_work_info->StuffInfo.nStuffPageBuffer = pStuffPageBuffer;
++
++ n_printk("\n[PhyPageNum:%d]:", dev->nand_work_info->PhyPageNum );
++ for ( i = 0; i < dev->nand_work_info->PhyPageNum; ++i )
++ n_printk(",%d", dev->nand_work_info->PPageSize[i] );
++
++ n_printk("\n");
++
++ // Write Start
++ nand_isr_write( q, req );
++
++ dev->nand_work_info->nSpareBuffer = pSpareBuffer;
++ dev->nand_work_info->StuffInfo.nStuffPageBuffer = pStuffPageBuffer;
++
++ first = 1;
++ }
++ else
++ {
++ if (first)
++ {
++ idx = 0;
++ first = 0;
++ xfer = 0;
++ sector = req->sector;
++ }
++
++ memcpy(&dev->buf[idx * 512], req->buffer, req->current_nr_sectors * 512);
++ idx += req->current_nr_sectors;
++
++ if (req->current_nr_sectors == req->nr_sectors) {
++ xfer = 1;
++ }
++
++ if (xfer) {
++ ndd_transfer(dev, sector, idx, dev->buf, 1);
++ first = 1;
++ }
++ }
++ end_request(req, 1);
++ #else
++ if (first)
++ {
++ idx = 0;
++ first = 0;
++ xfer = 0;
++ sector = req->sector;
++ }
++
++ memcpy(&dev->buf[idx * 512], req->buffer, req->current_nr_sectors * 512);
++ idx += req->current_nr_sectors;
++
++ if (req->current_nr_sectors == req->nr_sectors) {
++ xfer = 1;
++ }
++
++ if (xfer) {
++ ndd_transfer(dev, sector, idx, dev->buf, 1);
++ first = 1;
++ }
++ end_request(req, 1);
++ #endif /* 0 */
++ }
++#else
++ /* read */
++ if (!rq_data_dir(req)) {
++ if (first) {
++ idx = 0;
++ ndd_transfer(dev, req->sector, req->nr_sectors, dev->buf, 0);
++ first = 0;
++ }
++
++ memcpy(req->buffer, &dev->buf[idx * 512], req->current_nr_sectors * 512);
++ idx += req->current_nr_sectors;
++
++ if (req->current_nr_sectors == req->nr_sectors) {
++ first = 1;
++ }
++ end_request(req, 1);
++
++ /* write */
++ } else {
++ if (first) {
++ idx = 0;
++ first = 0;
++ xfer = 0;
++ sector = req->sector;
++ }
++ memcpy(&dev->buf[idx * 512], req->buffer, req->current_nr_sectors * 512);
++ idx += req->current_nr_sectors;
++
++ if (req->current_nr_sectors == req->nr_sectors) {
++ xfer = 1;
++ }
++
++ if (xfer) {
++ ndd_transfer(dev, sector, idx, dev->buf, 1);
++ first = 1;
++ }
++ end_request(req, 1);
++ }
++#endif
++ }
++
++ }
++ } while (1);
++
++ return 0;
++}
++#endif
++
++static int ndd_ioctl(struct block_device *bdev, struct file *filp, unsigned int cmd, unsigned long arg)
++{
++ switch (cmd) {
++ case IOCTL_NDD_MULTI_HD_WRITE:
++ {
++ struct ndd_hidden_info param;
++ if (copy_from_user(&param, (void *)arg, sizeof(struct ndd_hidden_info))) {
++ printk("[tcc_nand] IOCTL_NDD_MULTI_HD_WRITE copy_from_user(struct) fail\n");
++ return -EFAULT;
++ }
++ if (!access_ok(VERIFY_READ, param.DataBuffer, param.DataBufferSize)) {
++ printk("[tcc_nand] IOCTL_NDD_MULTI_HD_WRITE verify buf fail\n");
++ return -EFAULT;
++ }
++ if (NAND_HDWriteSector(param.DriveNum, param.HiddenAddress, param.SectorNum, param.DataBuffer)) {
++ printk("[tcc_nand] IOCTL_NDD_MULTI_HD_WRITE write fail\n");
++ return -EFAULT;
++ }
++ break;
++ }
++ case IOCTL_NDD_MULTI_HD_READ:
++ {
++ struct ndd_hidden_info param, *temp;
++ char *buf;
++ temp = (struct ndd_hidden_info *)arg;
++ if (copy_from_user(&param, (void *)arg, sizeof(struct ndd_hidden_info))) {
++ printk("[tcc_nand] IOCTL_NDD_MULTI_HD_READ copy_from_user(struct) fail\n");
++ return -EFAULT;
++ }
++ buf = kmalloc(param.DataBufferSize, GFP_KERNEL);
++ if (!buf) {
++ printk("[tcc_nand] IOCTL_NDD_MULTI_HD_READ kmalloc fail\n");
++ return -EFAULT;
++ }
++ if (NAND_HDReadSector(param.DriveNum, param.HiddenAddress, param.SectorNum, buf)) {
++ printk("[tcc_nand] IOCTL_NDD_MULTI_HD_READ read fail\n");
++ kfree(buf);
++ return -EFAULT;
++ }
++ if (copy_to_user(temp->DataBuffer, buf, temp->DataBufferSize)) {
++ printk("[tcc_nand] IOCTL_NDD_MULTI_HD_READ copy_to_user(buffer) fail\n");
++ kfree(buf);
++ return -EFAULT;
++ }
++ kfree(buf);
++ break;
++ }
++ case IOCTL_NDD_BOOT_WRITE:
++ {
++ struct ndd_boot_info param;
++ if (copy_from_user(&param, (void *)arg, sizeof(struct ndd_boot_info))) {
++ printk("[tcc_nand] IOCTL_NDD_BOOT_UPDATE copy_from_user(struct) fail\n");
++ return -EFAULT;
++ }
++ if (!access_ok(VERIFY_READ, param.buf, param.len)) {
++ printk("[tcc_nand] IOCTL_NDD_BOOT_UPDATE verify buf fail\n");
++ return -EFAULT;
++ }
++ if (FWUG_MainFunc(param.buf, param.len)) {
++ printk("[tcc_nand] IOCTL_NDD_BOOT_UPDATE update fail\n");
++ return -EFAULT;
++ }
++ break;
++ }
++ case IOCTL_NDD_HD_WRITE:
++ {
++ struct ndd_hidden_info param;
++ if (copy_from_user(&param, (void *)arg, sizeof(struct ndd_hidden_info))) {
++ printk("[tcc_nand] IOCTL_NDD_HD_WRITE copy_from_user(struct) fail\n");
++ return -EFAULT;
++ }
++ if (!access_ok(VERIFY_READ, param.DataBuffer, param.DataBufferSize)) {
++ printk("[tcc_nand] IOCTL_NDD_HD_WRITE verify buf fail\n");
++ return -EFAULT;
++ }
++ if (NAND_HDWritePage(param.HiddenAddress, param.SectorNum, param.DataBuffer)) {
++ printk("[tcc_nand] IOCTL_NDD_HD_WRITE write fail\n");
++ return -EFAULT;
++ }
++ break;
++ }
++ case IOCTL_NDD_HD_READ:
++ {
++ struct ndd_hidden_info param, *temp;
++ char *buf;
++ temp = (struct ndd_hidden_info *)arg;
++ if (copy_from_user(&param, (void *)arg, sizeof(struct ndd_hidden_info))) {
++ printk("[tcc_nand] IOCTL_NDD_HD_READ copy_from_user(struct) fail\n");
++ return -EFAULT;
++ }
++ buf = kmalloc(param.DataBufferSize, GFP_KERNEL);
++ if (!buf) {
++ printk("[tcc_nand] IOCTL_NDD_HD_READ kmalloc fail\n");
++ return -EFAULT;
++ }
++ if (NAND_HDReadPage(param.HiddenAddress, param.SectorNum, buf)) {
++ printk("[tcc_nand] IOCTL_NDD_HD_READ write fail\n");
++ kfree(buf);
++ return -EFAULT;
++ }
++ if (copy_to_user(temp->DataBuffer, buf, temp->DataBufferSize)) {
++ printk("[tcc_nand] IOCTL_NDD_HD_READ copy_to_user(buffer) fail\n");
++ kfree(buf);
++ return -EFAULT;
++ }
++ kfree(buf);
++ break;
++ }
++
++ /* for USB MSC */
++ case IOCTL_NDD_GET_INFO:
++ {
++ struct ndd_data ndata;
++ void __user *uarg = (void __user *) arg;
++ ndata.i_size = i_size_read(filp->f_mapping->host);
++ if (copy_to_user(uarg, &ndata, sizeof(ndata)))
++ return -EFAULT;
++ break;
++ }
++
++ case IOCTL_NDD_ALIGN_CACHE:
++ {
++ NAND_Ioctl(DEV_SET_ALIGEN_CACHE,(void *)arg);
++ break;
++ }
++
++ case IOCTL_NDD_GET_SERIALNUMBER:
++ {
++ if ( !NAND_GetSerialNumber((unsigned char* )arg, 32 ))
++ return -EFAULT;
++ break;
++ }
++ case IOCTL_STORAGE_PING:
++ {
++ // ping
++ break;
++ }
++ case IOCTL_STORAGE_DIRECT_READ:
++ {
++ struct storage_direct sdArg;
++ unsigned int sector, nsect;
++ void *buf;
++ sector_t start_sect, nr_sects;
++
++ if (copy_from_user(&sdArg, (void __user *)arg, sizeof(struct storage_direct))) {
++ printk("[tcc_nand] IOCTL_STORAGE_DIRECT_READ copy_from_user(struct) fail\n");
++ return -EFAULT;
++ }
++
++ sector = sdArg.pos>>9;
++ nsect = sdArg.count>>9;
++ start_sect = bdev->bd_part->start_sect; /* start sector of partition */
++ nr_sects = bdev->bd_part->nr_sects; /* # sector of partition */
++ sector += start_sect;
++
++ if (sdArg.user_space) {
++ printk("[tcc_nand] IOCTL_STORAGE_DIRECT_READ access from user space is not supported yet.\n");
++ return -EFAULT;
++ } else {
++ buf = sdArg.buf;
++ }
++ if ((sector + nsect) > (start_sect + nr_sects)) {
++ printk("beyond-end read (%d + %d >= %lu)\n", sector, nsect, (long unsigned int)(start_sect + nr_sects));
++ return -EFAULT;
++ }
++ if (NAND_ReadSector(0, sector, nsect, buf)) {
++ printk("[tcc_nand] IOCTL_STORAGE_DIRECT_READ read fail\n");
++ return -EFAULT;
++ }
++
++ sdArg.pos += sdArg.count;
++ sdArg.actual = sdArg.count;
++ if (copy_to_user((void __user *)arg, &sdArg, sizeof(struct storage_direct))) {
++ printk("[tcc_nand] IOCTL_STORAGE_DIRECT_READ copy_to_user(struct) fail\n");
++ return -EFAULT;
++ }
++ break;
++ }
++ case IOCTL_STORAGE_DIRECT_WRITE:
++ {
++ struct storage_direct sdArg;
++ unsigned int sector, nsect;
++ void *buf;
++ sector_t start_sect, nr_sects;
++
++ if (copy_from_user(&sdArg, (void __user *)arg, sizeof(struct storage_direct))) {
++ printk("[tcc_nand] IOCTL_STORAGE_DIRECT_WRITE copy_from_user(struct) fail\n");
++ return -EFAULT;
++ }
++
++ sector = sdArg.pos>>9;
++ nsect = sdArg.count>>9;
++ start_sect = bdev->bd_part->start_sect; /* start sector of partition */
++ nr_sects = bdev->bd_part->nr_sects; /* # sector of partition */
++ sector += start_sect;
++
++ if (sdArg.user_space) {
++ printk("[tcc_nand] IOCTL_STORAGE_DIRECT_WRITE access from user space is not supported yet.\n");
++ return -EFAULT;
++ } else {
++ buf = sdArg.buf;
++ }
++ if ((sector + nsect) > (start_sect + nr_sects)) {
++ printk("beyond-end write (%d + %d >= %lu)\n", sector, nsect, (long unsigned int)(start_sect + nr_sects));
++ return -EFAULT;
++ }
++ if (NAND_WriteSector(0, sector, nsect, buf)) {
++ printk("[tcc_nand] IOCTL_STORAGE_DIRECT_WRITE write fail\n");
++ return -EFAULT;
++ }
++
++ sdArg.pos += sdArg.count;
++ sdArg.actual = sdArg.count;
++ if (copy_to_user((void __user *)arg, &sdArg, sizeof(struct storage_direct)))
++ {
++ printk("[tcc_nand] IOCTL_STORAGE_DIRECT_WRITE copy_to_user(struct) fail\n");
++ return -EFAULT;
++ }
++ break;
++ }
++ default:
++ printk("[tcc_nand] ioctl (0x%x)\n", cmd);
++ return -ENOIOCTLCMD;
++ break;
++ }
++
++ return 0;
++}
++
++static int ndd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
++{
++ geo->cylinders = gNAND_DrvInfo[0].Cylinder;
++ geo->heads = gNAND_DrvInfo[0].Head;
++ geo->sectors = gNAND_DrvInfo[0].Sector;
++ geo->start = get_start_sect(bdev);
++
++ return 0;
++}
++
++static int ndd_open(struct block_device *bdev, fmode_t mode)
++{
++ Device *dev = bdev->bd_disk->private_data;
++
++ spin_lock(&dev->lock);
++ dev->users++;
++ spin_unlock(&dev->lock);
++
++ return 0;
++}
++
++static int ndd_release(struct gendisk *disk, fmode_t mode)
++{
++ Device *dev = disk->private_data;
++
++ spin_lock(&dev->lock);
++ dev->users--;
++ spin_unlock(&dev->lock);
++
++ return 0;
++}
++
++#ifdef __USE_NAND_ISR__
++static int nand_get_next_req( struct request_queue *q, struct request *req )
++{
++ unsigned int i;
++
++ end_request(req, 1);
++
++ spin_lock_irq(q->queue_lock);
++ if (!blk_queue_plugged(q))
++ {
++ req = elv_next_request(q);
++ }
++ spin_unlock_irq(q->queue_lock);
++
++ i = req->sector;
++ n_printk("-req--:[%d]-[%lu-%d]\n",i, req->nr_sectors, req->current_nr_sectors);
++
++ return 0;
++}
++
++static irqreturn_t nand_isr_rb(int irq, void *dev_id)
++{
++ #ifdef __USE_NAND_ISR_WRITE__
++ unsigned int i;
++ unsigned int ret;
++ unsigned int rEccBuffer;
++ unsigned char *pPhy_Buffer;
++ #endif
++
++ if( ndd_isr_rb_enable_flag == NDD_RB_INTR_MODE_READ )
++ {
++ //==========================================
++ // R/B Interrupt Clear
++ //==========================================
++ ndd_isr_rb_enable_flag = NDD_RB_INTR_MODE_NORMAL;
++ NAND_IO_IRQ_ReadyBusyClear();
++ n_printk("[Read]Ready Interrupt\n");
++ #ifdef NAND_GPIO_DEBUG
++ BITCLR(nand_intr_rb.p_gpio->GPFDAT, Hw21);
++ #endif
++
++ // NAND Ready--------------------------------------------------------------
++ nand_intr_rb.intr_mode = INTR_MODE_READ_ECC;
++
++ NAND_IO_IRQ_SetupDMAForSpare( nand_intr_rb.nDevInfo->EccWholeDataSize );
++ }
++ #ifdef __USE_NAND_ISR_WRITE__
++ else if ( ndd_isr_rb_enable_flag == NDD_RB_INTR_MODE_WRITE )
++ {
++ //==========================================
++ // R/B Interrupt Clear
++ //==========================================
++ ndd_isr_rb_enable_flag = NDD_RB_INTR_MODE_NORMAL;
++ NAND_IO_IRQ_ReadyBusyClear();
++ n_printk("[Write]Ready Interrupt\n");
++ #ifdef NAND_GPIO_DEBUG
++ BITCLR(nand_intr_rb.p_gpio->GPFDAT, Hw21);
++ #endif
++
++ NAND_IO_IRQ_WritePagePostProcess();
++
++ nand_intr_rb.nPageIndex += 1;
++
++ if ( nand_intr_rb.nPageIndex == nand_intr_rb.nWorkInfo->PhyPageNum )
++ {
++ n_printk("[%d]Page Write Complete--Wake Up\n", nand_intr_rb.nWorkInfo->PhyPageNum );
++
++ nand_intr_rb.intr_mode = INTR_MODE_NORMAL;
++ nand_intr_rb.is_nd_busy_complete = 1;
++ #ifdef NAND_GPIO_DEBUG
++ BITSET(nand_intr_rb.p_gpio->GPFDAT, Hw17);
++ #endif
++ wake_up(&(nand_intr_rb.nd_busy_wait_q));
++ return IRQ_HANDLED;
++ }
++ else
++ {
++ if ( nand_intr_rb.current_nr_sectors == 0 )
++ {
++ n_printk("\n");
++ nand_get_next_req( nand_intr_rb.request_q, nand_intr_rb.req );
++
++ for ( i = 0; i < nand_intr_rb.req->current_nr_sectors; ++i )
++ {
++ nand_intr_rb.nWorkInfo->BufferAddr[ nand_intr_rb.nSectorIndex + i ] = (unsigned int )( nand_intr_rb.req->buffer + (i << 9));
++ }
++
++ nand_intr_rb.current_nr_sectors = nand_intr_rb.req->current_nr_sectors;
++ }
++
++ nand_intr_rb.nStartPPage = 0;//nWorkInfo->StartPPageNo[0];
++ nand_intr_rb.nReadPPSize = nand_intr_rb.nWorkInfo->FTLPPage;//PPageSize[0];
++ nand_intr_rb.intr_mode = INTR_MODE_WRITE_PAGE;
++ nand_intr_rb.nCurrPPage = 0;
++
++ ret = NAND_IO_IRQ_WritePagePreProcess( nand_intr_rb.nDevInfo,
++ nand_intr_rb.nWorkInfo->PhyPageAddr[nand_intr_rb.nPageIndex],
++ nand_intr_rb.nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex],
++ nand_intr_rb.nSpareBuffer, &rEccBuffer,
++ nand_intr_rb.nWorkInfo->ChipNo[nand_intr_rb.nPageIndex],
++ nand_intr_rb.nWorkInfo->PageWriteFunc[nand_intr_rb.nPageIndex] );
++ if (ret != SUCCESS)
++ {
++ printk("\nNAND_IO_IRQ_WritePagePreProcess - ERROR!!!!!" );
++ }
++ nand_intr_rb.nEccBuffer = (unsigned char*)rEccBuffer;
++
++ nand_intr_rb.intr_mode = INTR_MODE_WRITE_PAGE;
++ NAND_IO_IRQ_Write512DataPreProcess(nand_intr_rb.nDevInfo); // ECC Setup
++
++ if (( nand_intr_rb.nCurrPPage >= nand_intr_rb.nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex] ) &&
++ ( nand_intr_rb.nCurrPPage < nand_intr_rb.nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex] + nand_intr_rb.nWorkInfo->PPageSize[nand_intr_rb.nPageIndex] ))
++ {
++ pPhy_Buffer = (unsigned char*)virt_to_phys((unsigned char*)nand_intr_rb.nWorkInfo->BufferAddr[nand_intr_rb.nSectorIndex] );
++ ++nand_intr_rb.nSectorIndex;
++ }
++ else
++ {
++ if ( nand_intr_rb.nWorkInfo->PageWriteFunc[nand_intr_rb.nPageIndex] == MULTI_PLANE_STUFF_PAGE )
++ {
++ n_printk("CurrPPage:%d - StartPPage:%d, Size:%d", nand_intr_rb.nCurrPPage, nand_intr_rb.nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex], nand_intr_rb.nWorkInfo->PPageSize[nand_intr_rb.nPageIndex] );
++ n_printk("StuffPageCopy:0x%x\n", nand_intr_rb.nWorkInfo->StuffInfo.nStuffPageBuffer );
++ memcpy( dma_t.v_addr, nand_intr_rb.nWorkInfo->StuffInfo.nStuffPageBuffer, 512 );
++ nand_intr_rb.nWorkInfo->StuffInfo.nStuffPageBuffer += 512;
++ pPhy_Buffer = (unsigned char*)dma_t.dma_addr;
++ }
++ else
++ {
++ //null page
++ n_printk("[%s:%d] Null Page Write!!!\n", __func__, __LINE__);
++ memset( dma_t.v_addr, 0xFF, 512 );
++ pPhy_Buffer = (unsigned char*)dma_t.dma_addr;
++ }
++ }
++
++ NAND_IO_IRQ_SetupDMA((U8*)pPhy_Buffer, NAND_IO_DMA_WRITE );
++ }
++ }
++ #endif
++ else
++ {
++ BITSET(nand_intr_rb.pPIC->IEN0, ( 1 << NAND_IRQ_READY ));
++ BITCLR(nand_intr_rb.pPIC->IRQ0, ( 1 << NAND_IRQ_READY ));
++
++ printk("Dumy-Ready Interrupt-!!!!!!!!!!!!!!!!\n");
++
++ }
++
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t nand_isr(int irq, void *dev_id)
++{
++ unsigned int i;
++ unsigned int current_req_sector, nPPageSize;
++ unsigned char *pPhy_Buffer;
++ nand_intr_info *p_nand = (nand_intr_info *)dev_id;
++ unsigned int ColumnAddr;
++ U32 rEccBuffer;
++ #ifdef __USE_NAND_ISR_WRITE__
++ U32 ret;
++ #endif
++
++ n_printk("start---------> pNFC->NFC_IREQ [0x%08X]\n", p_nand->p_nfc->NFC_IREQ);
++ //===============================================
++ // DMA Read IRQ
++ //===============================================
++ if (p_nand->p_nfc->NFC_IREQ & Hw0)
++ {
++ BITSET(p_nand->p_nfc->NFC_IREQ, Hw0);
++
++ #ifdef NAND_GPIO_DEBUG
++ BITCLR(nand_intr_rb.p_gpio->GPFDAT, Hw21);
++ #endif
++
++ if ( nand_intr_rb.intr_mode == INTR_MODE_NORMAL )
++ {
++ n_printk("RX interrupt in nand \n");
++
++ //BITSET(p_nand->p_nfc->NFC_IREQ, Hw0);
++ p_nand->is_rx_complete = 1;
++ //wake_up(&(p_nand->rx_wait_q));
++ }
++ else if ( nand_intr_rb.intr_mode == INTR_MODE_READ_PAGE )
++ {
++ n_printk("PostProcess_Page:%d\n\n", (nand_intr_rb.nReadPPSize) );
++ // ECC Correction
++ NAND_IO_IRQ_Read512DataPostProcess( nand_intr_rb.nDevInfo, (U8*)nand_intr_rb.nWorkInfo->BufferAddr[nand_intr_rb.nSectorIndex], nand_intr_rb.nEccBuffer); // 11us
++ nand_intr_rb.nSectorIndex += 1;
++ nand_intr_rb.nEccBuffer += nand_intr_rb.nDevInfo->EccDataSize;
++ nand_intr_rb.nReadPPSize -= 1;
++ nand_intr_rb.current_nr_sectors -= 1;
++
++ if ( nand_intr_rb.nReadPPSize )
++ {
++ //-------------------------
++ // Next PPage Read
++ //-------------------------
++ n_printk("Read_DMA_Page:%d\n", nand_intr_rb.nReadPPSize );
++ NAND_IO_IRQ_Read512DataPreProcess( nand_intr_rb.nDevInfo );
++
++ if ( nand_intr_rb.current_nr_sectors == 0 )
++ {
++ n_printk("\n");
++ nand_get_next_req( nand_intr_rb.request_q, nand_intr_rb.req );
++
++ for ( i = 0; i < nand_intr_rb.req->current_nr_sectors; ++i )
++ {
++ nand_intr_rb.nWorkInfo->BufferAddr[ nand_intr_rb.nSectorIndex + i ] = (unsigned int )( nand_intr_rb.req->buffer + (i << 9));
++ }
++
++ nand_intr_rb.current_nr_sectors = nand_intr_rb.req->current_nr_sectors;
++ }
++
++ // DMA Setup & Start
++ pPhy_Buffer = (unsigned char*)virt_to_phys((unsigned char*)nand_intr_rb.nWorkInfo->BufferAddr[nand_intr_rb.nSectorIndex] );
++ NAND_IO_IRQ_SetupDMA((void*)pPhy_Buffer, NAND_IO_DMA_READ );
++ }
++ else
++ {
++ //BITSET(p_nand->p_nfc->NFC_IREQ, Hw0);
++
++ nand_intr_rb.nPageIndex += 1;
++ if ( nand_intr_rb.nPageIndex == nand_intr_rb.nWorkInfo->PhyPageNum )
++ {
++ n_printk("[%d]Page Read Complete--Wake Up\n", nand_intr_rb.nWorkInfo->PhyPageNum );
++
++ nand_intr_rb.intr_mode = INTR_MODE_NORMAL;
++ nand_intr_rb.is_nd_busy_complete = 1;
++ #ifdef NAND_GPIO_DEBUG
++ BITSET(nand_intr_rb.p_gpio->GPFDAT, Hw17);
++ #endif
++ wake_up(&(nand_intr_rb.nd_busy_wait_q));
++ return IRQ_HANDLED;
++ }
++ else
++ {
++ current_req_sector = nand_intr_rb.current_nr_sectors;
++
++ while( nand_intr_rb.nWorkInfo->PhyPageAddr[nand_intr_rb.nPageIndex] == TNFTL_U32_NULL )
++ {
++ n_printk("NULL Page Memset\n");
++
++ if ( nand_intr_rb.nWorkInfo->PPageSize[nand_intr_rb.nPageIndex] <= current_req_sector )
++ nPPageSize = nand_intr_rb.nWorkInfo->PPageSize[nand_intr_rb.nPageIndex];
++ else
++ nPPageSize = current_req_sector;
++
++ for ( i = 0; i < nPPageSize; ++i )
++ {
++ memset( (void*)nand_intr_rb.nWorkInfo->BufferAddr[ nand_intr_rb.nSectorIndex ], 0xFF, 512 );
++ nand_intr_rb.nSectorIndex += 1;
++ current_req_sector -= 1;
++ }
++
++ nand_intr_rb.nPageIndex += 1;
++
++ if( nand_intr_rb.nPageIndex == nand_intr_rb.nWorkInfo->PhyPageNum )
++ {
++ n_printk("[%d]Page Read Complete--Wake Up\n", nand_intr_rb.nWorkInfo->PhyPageNum );
++
++ nand_intr_rb.intr_mode = INTR_MODE_NORMAL;
++ nand_intr_rb.is_nd_busy_complete = 1;
++ #ifdef NAND_GPIO_DEBUG
++ BITSET(nand_intr_rb.p_gpio->GPFDAT, Hw17);
++ #endif
++ wake_up(&(nand_intr_rb.nd_busy_wait_q));
++ return IRQ_HANDLED;
++ }
++
++ if ( current_req_sector == 0 )
++ {
++ n_printk("\n");
++ nand_get_next_req( nand_intr_rb.request_q, nand_intr_rb.req );
++
++ for ( i = 0; i < nand_intr_rb.req->current_nr_sectors; ++i )
++ {
++ nand_intr_rb.nWorkInfo->BufferAddr[ nand_intr_rb.nSectorIndex + i ] = (unsigned int )( nand_intr_rb.req->buffer + (i << 9));
++ }
++
++ nand_intr_rb.current_nr_sectors = nand_intr_rb.req->current_nr_sectors;
++ current_req_sector = nand_intr_rb.current_nr_sectors;
++ }
++ }
++
++ if ( nand_intr_rb.nPageIndex == nand_intr_rb.nWorkInfo->PhyPageNum )
++ {
++ n_printk("[%d]Page Read Complete--Wake Up\n", nand_intr_rb.nWorkInfo->PhyPageNum );
++ nand_intr_rb.intr_mode = INTR_MODE_NORMAL;
++ nand_intr_rb.is_nd_busy_complete = 1;
++ #ifdef NAND_GPIO_DEBUG
++ BITSET(nand_intr_rb.p_gpio->GPFDAT, Hw17);
++ #endif
++ wake_up(&(nand_intr_rb.nd_busy_wait_q));
++ return IRQ_HANDLED;
++ }
++
++ n_printk("Read Page Start+++++++++++\n");
++ n_printk("[%d/%d]Page Read -- Next Page Read Start\n", nand_intr_rb.nPageIndex, nand_intr_rb.nWorkInfo->PhyPageNum );
++
++ //==================================================
++ // Set Work Info
++ //==================================================
++ // nand_intr_rb.nDevInfo->ChipNo = nand_intr_rb.nWorkInfo->ChipNo[ nand_intr_rb.nPageIndex ];
++ nand_intr_rb.nStartPPage = nand_intr_rb.nWorkInfo->StartPPageNo[ nand_intr_rb.nPageIndex ];
++ nand_intr_rb.nReadPPSize = nand_intr_rb.nWorkInfo->PPageSize[ nand_intr_rb.nPageIndex ];
++ nand_intr_rb.intr_mode = INTR_MODE_READ_ECC;
++
++ //===================================================
++ // Read PreProcess
++ //===================================================
++ NAND_IO_IRQ_ReadPagePreProcess( nand_intr_rb.nDevInfo,
++ nand_intr_rb.nWorkInfo->PhyPageAddr[nand_intr_rb.nPageIndex],
++ nand_intr_rb.nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex],
++ &rEccBuffer,
++ nand_intr_rb.nWorkInfo->ChipNo[ nand_intr_rb.nPageIndex ]);
++
++ nand_intr_rb.nEccBuffer = (unsigned char*)rEccBuffer;
++
++ ndd_isr_rb_enable_flag = NDD_RB_INTR_MODE_READ;
++ NAND_IO_IRQ_ReadyBusySet();
++ }
++ }
++ }
++ else if ( nand_intr_rb.intr_mode == INTR_MODE_READ_ECC )
++ {
++ n_printk("Read_ECC_Data Complete\n\n" );
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ /* Command Random Data Output [ 0x05 ] for Advance NandFlash */
++ nand_intr_rb.p_nfc->NFC_CMD = nand_intr_rb.nDevInfo->CmdMask & 0x0505;
++
++ ColumnAddr = ( nand_intr_rb.nStartPPage<< 9 );
++ ColumnAddr = ( nand_intr_rb.nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (ColumnAddr >> 1) : ColumnAddr;
++
++ NAND_IO_WriteColAddr( ColumnAddr, nand_intr_rb.nDevInfo );
++
++ /* Command Random Data Output [ 0xE0 ] for Advance NandFlash */
++ nand_intr_rb.p_nfc->NFC_CMD = nand_intr_rb.nDevInfo->CmdMask & 0xE0E0;
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ nand_intr_rb.intr_mode = INTR_MODE_READ_PAGE;
++ n_printk("Read_DMA_Page:%d\n", nand_intr_rb.nReadPPSize );
++ NAND_IO_IRQ_Read512DataPreProcess( nand_intr_rb.nDevInfo );
++
++ if ( nand_intr_rb.current_nr_sectors == 0 )
++ {
++ n_printk("\n");
++ nand_get_next_req( nand_intr_rb.request_q, nand_intr_rb.req );
++
++ for ( i = 0; i < nand_intr_rb.req->current_nr_sectors; ++i )
++ {
++ nand_intr_rb.nWorkInfo->BufferAddr[ nand_intr_rb.nSectorIndex + i ] = (unsigned int )( nand_intr_rb.req->buffer + (i << 9));
++ }
++
++ nand_intr_rb.current_nr_sectors = nand_intr_rb.req->current_nr_sectors;
++ }
++
++ // DMA Setup & Start
++ pPhy_Buffer = (unsigned char*)virt_to_phys( (unsigned char*)nand_intr_rb.nWorkInfo->BufferAddr[nand_intr_rb.nSectorIndex] );
++ NAND_IO_IRQ_SetupDMA((void*)pPhy_Buffer, NAND_IO_DMA_READ );
++ }
++ }
++ else if (p_nand->p_nfc->NFC_IREQ & Hw1)
++ {
++ BITSET(p_nand->p_nfc->NFC_IREQ, Hw1);
++ n_printk("TX interrupt in nand \n");
++ //p_nand->is_tx_complete = 1;
++ #ifdef __USE_NAND_ISR_WRITE__
++ //===============================================
++ // DMA Write IRQ
++ //===============================================
++ if ( nand_intr_rb.intr_mode == INTR_MODE_WRITE_PAGE )
++ {
++ NAND_IO_IRQ_Write512DataPostProcess(nand_intr_rb.nDevInfo, nand_intr_rb.nEccBuffer);
++ nand_intr_rb.nEccBuffer += nand_intr_rb.nDevInfo->EccDataSize;
++ nand_intr_rb.nCurrPPage += 1;
++ nand_intr_rb.nReadPPSize -= 1;
++ nand_intr_rb.current_nr_sectors -= 1;
++
++ if ( nand_intr_rb.nReadPPSize )
++ {
++ //======================
++ // Next PPage Writ
++ //======================
++// if ( nand_intr_rb.current_nr_sectors == 0 )
++ if (( nand_intr_rb.current_nr_sectors == 0 ) &&
++ ( nand_intr_rb.req->current_nr_sectors == nand_intr_rb.nWorkInfo->FTLPPage ) &&
++ (nand_intr_rb.req->current_nr_sectors != nand_intr_rb.req->nr_sectors))
++ {
++ n_printk("\n");
++ nand_get_next_req( nand_intr_rb.request_q, nand_intr_rb.req );
++
++ for ( i = 0; i < nand_intr_rb.req->current_nr_sectors; ++i )
++ {
++ nand_intr_rb.nWorkInfo->BufferAddr[ nand_intr_rb.nSectorIndex + i ] = (unsigned int )( nand_intr_rb.req->buffer + (i << 9));
++ }
++
++ nand_intr_rb.current_nr_sectors = nand_intr_rb.req->current_nr_sectors;
++ }
++
++ n_printk("Write_DMA_Page:%d\n", nand_intr_rb.nReadPPSize );
++
++ nand_intr_rb.intr_mode = INTR_MODE_WRITE_PAGE;
++ NAND_IO_IRQ_Write512DataPreProcess(nand_intr_rb.nDevInfo); // ECC Setup
++
++ if (( nand_intr_rb.nCurrPPage >= nand_intr_rb.nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex] ) &&
++ ( nand_intr_rb.nCurrPPage < ( nand_intr_rb.nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex] + nand_intr_rb.nWorkInfo->PPageSize[nand_intr_rb.nPageIndex] )))
++ {
++ pPhy_Buffer = (unsigned char*)virt_to_phys((unsigned char*)nand_intr_rb.nWorkInfo->BufferAddr[nand_intr_rb.nSectorIndex] );
++ ++nand_intr_rb.nSectorIndex;
++ }
++ else
++ {
++ if ( nand_intr_rb.nWorkInfo->PageWriteFunc[nand_intr_rb.nPageIndex] == MULTI_PLANE_STUFF_PAGE )
++ {
++ n_printk("CurrPPage:%d - StartPPage:%d, Size:%d", nand_intr_rb.nCurrPPage, nand_intr_rb.nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex], nand_intr_rb.nWorkInfo->PPageSize[nand_intr_rb.nPageIndex] );
++ n_printk("StuffPageCopy:0x%x\n", nand_intr_rb.nWorkInfo->StuffInfo.nStuffPageBuffer );
++ memcpy( dma_t.v_addr, nand_intr_rb.nWorkInfo->StuffInfo.nStuffPageBuffer, 512 );
++ nand_intr_rb.nWorkInfo->StuffInfo.nStuffPageBuffer += 512;
++ pPhy_Buffer = (unsigned char*)dma_t.dma_addr;
++ }
++ else
++ {
++ //null page
++ n_printk("[%s:%d] Null Page Write!!!\n", __func__, __LINE__);
++ memset( dma_t.v_addr, 0xFF, 512 );
++ pPhy_Buffer = (unsigned char*)dma_t.dma_addr;
++ }
++ }
++
++ NAND_IO_IRQ_SetupDMA((U8*)pPhy_Buffer, NAND_IO_DMA_WRITE );
++ }
++ else
++ {
++ //======================
++ // Write Spare
++ //======================
++ n_printk("Write Spare + ECC Data\n");
++ NAND_IO_WriteSpareData(nand_intr_rb.nDevInfo, nand_intr_rb.nWorkInfo->nSpareBuffer, PAGE_ECC_ON );
++ nand_intr_rb.nWorkInfo->nSpareBuffer += 16;
++ NAND_IO_IRQ_WritePageMidProcess( nand_intr_rb.nDevInfo, nand_intr_rb.nWorkInfo->PageWriteFunc[nand_intr_rb.nPageIndex] );
++
++ if ( !( ( nand_intr_rb.nDevInfo->Feature.MediaType & S_IL ) || ( nand_intr_rb.nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ {
++ ndd_isr_rb_enable_flag = NDD_RB_INTR_MODE_WRITE;
++ NAND_IO_IRQ_ReadyBusySet();
++ return IRQ_HANDLED;
++ }
++
++ if (( nand_intr_rb.nWorkInfo->PageWriteFunc[nand_intr_rb.nPageIndex] == MULTI_PLANE_NORMAL_PAGE ) ||
++ ( nand_intr_rb.nWorkInfo->PageWriteFunc[nand_intr_rb.nPageIndex] == MULTI_PLANE_STUFF_PAGE ) ||
++ ( nand_intr_rb.nWorkInfo->PageWriteFunc[nand_intr_rb.nPageIndex] == MULTI_PLANE_MID_PAGE ) ||
++ ( nand_intr_rb.nWorkInfo->PageWriteFunc[nand_intr_rb.nPageIndex] == MULTI_PLANE_LAST_PAGE ))
++ {
++ NAND_IO_SetInterleaveStatus( nand_intr_rb.nDevInfo, nand_intr_rb.nWorkInfo->PhyPageAddr[nand_intr_rb.nPageIndex] );
++ NAND_IO_SetInterLeavePageAddr( nand_intr_rb.nWorkInfo->PhyPageAddr[nand_intr_rb.nPageIndex] );
++ }
++
++ // Next PPage Write Start~~~~~
++ NAND_IO_IRQ_WritePagePostProcess();
++
++ nand_intr_rb.nPageIndex += 1;
++
++ if ( nand_intr_rb.nPageIndex == nand_intr_rb.nWorkInfo->PhyPageNum )
++ {
++ n_printk("[%d]Page Write Complete--Wake Up\n", nand_intr_rb.nWorkInfo->PhyPageNum );
++
++ nand_intr_rb.intr_mode = INTR_MODE_NORMAL;
++ nand_intr_rb.is_nd_busy_complete = 1;
++ #ifdef NAND_GPIO_DEBUG
++ BITSET(nand_intr_rb.p_gpio->GPFDAT, Hw17);
++ #endif
++ wake_up(&(nand_intr_rb.nd_busy_wait_q));
++ return IRQ_HANDLED;
++ }
++ else
++ {
++ if ( nand_intr_rb.current_nr_sectors == 0 )
++ {
++ n_printk("\n");
++ nand_get_next_req( nand_intr_rb.request_q, nand_intr_rb.req );
++
++ for ( i = 0; i < nand_intr_rb.req->current_nr_sectors; ++i )
++ {
++ nand_intr_rb.nWorkInfo->BufferAddr[ nand_intr_rb.nSectorIndex + i ] = (unsigned int )( nand_intr_rb.req->buffer + (i << 9));
++ }
++
++ nand_intr_rb.current_nr_sectors = nand_intr_rb.req->current_nr_sectors;
++ }
++
++ nand_intr_rb.nStartPPage = 0;//nWorkInfo->StartPPageNo[0];
++ nand_intr_rb.nReadPPSize = nand_intr_rb.nWorkInfo->FTLPPage;//PPageSize[0];
++ nand_intr_rb.intr_mode = INTR_MODE_WRITE_PAGE;
++ nand_intr_rb.nCurrPPage = 0;
++
++ ret = NAND_IO_IRQ_WritePagePreProcess( nand_intr_rb.nDevInfo,
++ nand_intr_rb.nWorkInfo->PhyPageAddr[nand_intr_rb.nPageIndex],
++ nand_intr_rb.nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex],
++ nand_intr_rb.nSpareBuffer, &rEccBuffer,
++ nand_intr_rb.nWorkInfo->ChipNo[nand_intr_rb.nPageIndex],
++ nand_intr_rb.nWorkInfo->PageWriteFunc[nand_intr_rb.nPageIndex] );
++ if (ret != SUCCESS)
++ {
++ printk("\nNAND_IO_IRQ_WritePagePreProcess - ERROR!!!!!" );
++ }
++ nand_intr_rb.nEccBuffer = (unsigned char*)rEccBuffer;
++
++ nand_intr_rb.intr_mode = INTR_MODE_WRITE_PAGE;
++ NAND_IO_IRQ_Write512DataPreProcess(nand_intr_rb.nDevInfo); // ECC Setup
++
++ if (( nand_intr_rb.nCurrPPage >= nand_intr_rb.nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex] ) &&
++ ( nand_intr_rb.nCurrPPage < nand_intr_rb.nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex] + nand_intr_rb.nWorkInfo->PPageSize[nand_intr_rb.nPageIndex] ))
++ {
++ pPhy_Buffer = (unsigned char*)virt_to_phys((unsigned char*)nand_intr_rb.nWorkInfo->BufferAddr[nand_intr_rb.nSectorIndex] );
++ ++nand_intr_rb.nSectorIndex;
++ }
++ else
++ {
++ if ( nand_intr_rb.nWorkInfo->PageWriteFunc[nand_intr_rb.nPageIndex] == MULTI_PLANE_STUFF_PAGE )
++ {
++ n_printk("CurrPPage:%d - StartPPage:%d, Size:%d", nand_intr_rb.nCurrPPage, nand_intr_rb.nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex], nand_intr_rb.nWorkInfo->PPageSize[nand_intr_rb.nPageIndex] );
++ //n_printk("StuffPageCopy:0x%x\n", nand_intr_rb.nWorkInfo->StuffInfo.nStuffPageBuffer );
++ memcpy( dma_t.v_addr, nand_intr_rb.nWorkInfo->StuffInfo.nStuffPageBuffer, 512 );
++ nand_intr_rb.nWorkInfo->StuffInfo.nStuffPageBuffer += 512;
++ pPhy_Buffer = (unsigned char*)dma_t.dma_addr;
++ }
++ else
++ {
++ //null page
++ printk("[%s:%d] Error!!!\n", __func__, __LINE__);
++ pPhy_Buffer = NULL;
++ }
++ }
++
++ NAND_IO_IRQ_SetupDMA((U8*)pPhy_Buffer, NAND_IO_DMA_WRITE );
++ }
++ return IRQ_HANDLED;
++ }
++ }
++ else
++ #endif
++ {
++ printk("unknown TX interrupt in nand !!!\n");
++ }
++ }
++ else
++ {
++ printk("unknown interrupt in nand !!!\n");
++ }
++
++ return IRQ_HANDLED;
++}
++
++#ifdef __USE_NAND_ISR_WRITE__
++static int nand_isr_write( struct request_queue *request_q, struct request *req )
++{
++ unsigned int current_req_sector;
++ int ret = 0;
++ unsigned char *pPhy_Buffer;
++ U32 rEccBuffer;
++ Device *dev;
++ ndd_work_info *nWorkInfo;
++
++ dev = req->rq_disk->private_data;
++ nWorkInfo = dev->nand_work_info;
++
++ n_printk("Nand Write Start+++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n");
++
++ #ifdef NAND_GPIO_DEBUG /* 09.12.22 */
++ BITSET(nand_intr_rb.p_gpio->GPFDAT, Hw16);
++ #endif /* NAND_GPIO_DEBUG */
++
++ //==================================================
++ // Set Work Info
++ //==================================================
++ nand_intr_rb.nDevInfo = nWorkInfo->nDevInfo;
++ nand_intr_rb.nStartPPage = 0;//nWorkInfo->StartPPageNo[0];
++ nand_intr_rb.nReadPPSize = nWorkInfo->FTLPPage;//PPageSize[0];
++ nand_intr_rb.intr_mode = INTR_MODE_WRITE_PAGE;
++ nand_intr_rb.nSectorIndex = 0;
++ nand_intr_rb.nPageIndex = 0;
++ nand_intr_rb.nCurrPPage = 0;
++ nand_intr_rb.nWorkInfo = nWorkInfo;
++ nand_intr_rb.request_q = request_q;
++ nand_intr_rb.req = req;
++ nand_intr_rb.current_nr_sectors = req->current_nr_sectors;
++
++ current_req_sector = nand_intr_rb.current_nr_sectors;
++
++ if ( nand_intr_rb.nPageIndex == nand_intr_rb.nWorkInfo->PhyPageNum )
++ return 0;
++
++ ret = NAND_IO_IRQ_WritePagePreProcess( nand_intr_rb.nDevInfo,
++ nWorkInfo->PhyPageAddr[nand_intr_rb.nPageIndex],
++ nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex],
++ nand_intr_rb.nSpareBuffer, &rEccBuffer,
++ nWorkInfo->ChipNo[nand_intr_rb.nPageIndex],
++ nWorkInfo->PageWriteFunc[nand_intr_rb.nPageIndex] );
++ if (ret != SUCCESS)
++ {
++ printk("\nNAND_IO_IRQ_WritePagePreProcess - ERROR!!!!!" );
++ }
++ nand_intr_rb.nEccBuffer = (unsigned char*)rEccBuffer;
++
++ nand_intr_rb.intr_mode = INTR_MODE_WRITE_PAGE;
++ NAND_IO_IRQ_Write512DataPreProcess(nand_intr_rb.nDevInfo); // ECC Setup
++
++ if (( nand_intr_rb.nCurrPPage >= nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex] ) &&
++ ( nand_intr_rb.nCurrPPage < nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex] + nWorkInfo->PPageSize[nand_intr_rb.nPageIndex] ))
++ {
++ n_printk("\n");
++
++ pPhy_Buffer = (unsigned char*)virt_to_phys((unsigned char*)nWorkInfo->BufferAddr[nand_intr_rb.nSectorIndex] );
++ ++nand_intr_rb.nSectorIndex;
++ }
++ else
++ {
++ if ( nWorkInfo->PageWriteFunc[nand_intr_rb.nPageIndex] == MULTI_PLANE_STUFF_PAGE )
++ {
++ n_printk("CurrPPage:%d - StartPPage:%d, Size:%d", nand_intr_rb.nCurrPPage, nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex], nWorkInfo->PPageSize[nand_intr_rb.nPageIndex] );
++ n_printk("StuffPageCopy:0x%x\n", nWorkInfo->StuffInfo.nStuffPageBuffer );
++ memcpy( dma_t.v_addr, nWorkInfo->StuffInfo.nStuffPageBuffer, 512 );
++ nWorkInfo->StuffInfo.nStuffPageBuffer += 512;
++ pPhy_Buffer = (unsigned char*)dma_t.dma_addr;
++ }
++ else
++ {
++ //null page
++ printk("[%s:%d] Error!!!\n", __func__, __LINE__);
++ pPhy_Buffer = NULL;
++ }
++ }
++
++ NAND_IO_IRQ_SetupDMA((U8*)pPhy_Buffer, NAND_IO_DMA_WRITE );
++
++ ret = wait_event_interruptible(nand_intr_rb.nd_busy_wait_q, nand_intr_rb.is_nd_busy_complete );
++ if (ret){
++ printk("[%s:%d] wait Nand Read Page Error!!!\n", __func__, __LINE__);
++ ret = -1;
++ }
++
++ req = nand_intr_rb.req;
++
++ #ifdef NAND_GPIO_DEBUG
++ BITCLR(nand_intr_rb.p_gpio->GPFDAT, Hw17);
++ #endif
++
++ n_printk("Nand Read Complete & wake_up------------------------------------------ \n\n");
++ NAND_IO_IRQ_ReadPagePostProcess();
++
++ #ifdef NAND_GPIO_DEBUG /* 09.12.22 */
++ BITCLR(nand_intr_rb.p_gpio->GPFDAT, Hw16);
++ #endif /* NAND_GPIO_DEBUG */
++
++ nand_intr_rb.is_nd_busy_complete = 0;
++ return ret;
++}
++#endif
++
++static int nand_isr_read( struct request_queue *request_q, struct request *req )
++{
++ unsigned int i;
++ unsigned int current_req_sector;
++ unsigned int nPPageSize;
++ int ret = 0;
++ U32 rEccBuffer;
++ Device *dev;
++ ndd_work_info *nWorkInfo;
++
++ dev = req->rq_disk->private_data;
++ nWorkInfo = dev->nand_work_info;
++
++ n_printk("Nand Read Start+++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n");
++
++ #ifdef NAND_GPIO_DEBUG /* 09.12.22 */
++ BITSET(nand_intr_rb.p_gpio->GPFDAT, Hw16);
++ #endif /* NAND_GPIO_DEBUG */
++
++ //==================================================
++ // Set Work Info
++ //==================================================
++ nand_intr_rb.nDevInfo = nWorkInfo->nDevInfo;
++ nand_intr_rb.nStartPPage = nWorkInfo->StartPPageNo[0];
++ nand_intr_rb.nReadPPSize = nWorkInfo->PPageSize[0];
++ nand_intr_rb.intr_mode = INTR_MODE_READ_ECC;
++ nand_intr_rb.nSectorIndex = 0;
++ nand_intr_rb.nPageIndex = 0;
++ nand_intr_rb.nWorkInfo = nWorkInfo;
++ nand_intr_rb.request_q = request_q;
++ nand_intr_rb.req = req;
++ nand_intr_rb.current_nr_sectors = req->current_nr_sectors;
++
++ current_req_sector = nand_intr_rb.current_nr_sectors;
++ //===================================================
++ // Read PreProcess
++ //===================================================
++ while( nWorkInfo->PhyPageAddr[nand_intr_rb.nPageIndex] == TNFTL_U32_NULL )
++ {
++ if ( nWorkInfo->PPageSize[nand_intr_rb.nPageIndex] <= current_req_sector )
++ nPPageSize = nWorkInfo->PPageSize[nand_intr_rb.nPageIndex];
++ else
++ nPPageSize = current_req_sector;
++
++ for ( i = 0; i < nPPageSize; ++i )
++ {
++ n_printk("Null Page memset\n");
++
++ memset( (void*)nWorkInfo->BufferAddr[ nand_intr_rb.nSectorIndex ], 0xFF, 512 );
++ nand_intr_rb.nSectorIndex += 1;
++ current_req_sector -= 1;
++ }
++
++ nand_intr_rb.nPageIndex += 1;
++
++ if( nand_intr_rb.nPageIndex == nand_intr_rb.nWorkInfo->PhyPageNum )
++ return 0;
++
++ if ( current_req_sector == 0 )
++ {
++ n_printk("\n");
++
++ nand_get_next_req( request_q, nand_intr_rb.req );
++
++ for ( i = 0; i < nand_intr_rb.req->current_nr_sectors; ++i )
++ {
++ dev->nand_work_info->BufferAddr[ nand_intr_rb.nSectorIndex + i ] = (unsigned int )( nand_intr_rb.req->buffer + (i << 9));
++ }
++
++ nand_intr_rb.current_nr_sectors = nand_intr_rb.req->current_nr_sectors;
++ current_req_sector = nand_intr_rb.current_nr_sectors;
++ }
++ }
++
++ if ( nand_intr_rb.nPageIndex == nand_intr_rb.nWorkInfo->PhyPageNum )
++ return 0;
++
++ ret = NAND_IO_IRQ_ReadPagePreProcess( nand_intr_rb.nDevInfo,
++ nWorkInfo->PhyPageAddr[nand_intr_rb.nPageIndex],
++ nWorkInfo->StartPPageNo[nand_intr_rb.nPageIndex],
++ &rEccBuffer,
++ nWorkInfo->ChipNo[nand_intr_rb.nPageIndex] );
++
++ if (ret != SUCCESS)
++ {
++ printk("\nNAND_IO_IRQ_ReadPagePreProcess - ERROR!!!!!" );
++ }
++ nand_intr_rb.nEccBuffer = (unsigned char*)rEccBuffer;
++
++ ndd_isr_rb_enable_flag = NDD_RB_INTR_MODE_READ;
++ NAND_IO_IRQ_ReadyBusySet();
++
++ ret = wait_event_interruptible(nand_intr_rb.nd_busy_wait_q, nand_intr_rb.is_nd_busy_complete );
++ if (ret){
++ printk("[%s:%d] wait Nand Read Page Error!!!\n", __func__, __LINE__);
++ ret = -1;
++ }
++
++ req = nand_intr_rb.req;
++
++ #ifdef NAND_GPIO_DEBUG
++ BITCLR(nand_intr_rb.p_gpio->GPFDAT, Hw17);
++ #endif
++
++ n_printk("Nand Read Complete & wake_up------------------------------------------ \n\n");
++ NAND_IO_IRQ_ReadPagePostProcess();
++
++ #ifdef NAND_GPIO_DEBUG /* 09.12.22 */
++ BITCLR(nand_intr_rb.p_gpio->GPFDAT, Hw16);
++ #endif /* NAND_GPIO_DEBUG */
++
++ nand_intr_rb.is_nd_busy_complete = 0;
++ return ret;
++}
++
++#endif
++
++static void ndd_request(struct request_queue *q)
++{
++#ifdef __USE_TCC_NAND_WORK_Q__
++ nand_priv_data_t *nq = (nand_priv_data_t *)q->queuedata;
++ wake_up_process(nq->thread);
++#else
++ struct request *req;
++
++ while((req = elv_next_request(q)) != NULL) {
++ Device *dev = req->rq_disk->private_data;
++ if( !blk_fs_request(req)) {
++ end_request(req,0);
++ } else {
++ ndd_transfer(dev, req->sector,
++ req->current_nr_sectors,
++ req->buffer, rq_data_dir(req));
++ end_request(req,1);
++ }
++ }
++#endif
++}
++
++static void ndd_transfer(Device *dev, unsigned long sector,
++ unsigned long nsect, char *buffer, int write)
++{
++ if( (sector + nsect) > dev->size ) {
++ printk(KERN_NOTICE "beyond-end write (%lu %lu %d)\n",
++ sector, nsect, dev->size);
++ return;
++ }
++
++ if(write) {
++ //printk("|");
++ NAND_WriteSector(0, sector, nsect, buffer);
++ } else {
++ //printk("-");
++ NAND_ReadSector(0, sector, nsect, buffer);
++ }
++}
++
++#ifdef __USE_NAND_ISR__
++static void ndd_get_phypageinfo( ndd_work_info *nand_work_info, int nMode )
++{
++ n_printk("\n");
++ if ( nMode == 0 )
++ NAND_ReadSectorIRQ(0, nand_work_info );
++ else
++ NAND_WriteSectorIRQ(0, nand_work_info );
++}
++#endif
++
++static int __init ndd_init(void)
++{
++ int res, i;
++ int ret = 0;
++
++ #ifdef __USE_NAND_ISR__
++ nand_intr_rb.p_nfc = (PNFC)tcc_p2v(HwNFC_BASE);
++ nand_intr_rb.p_gpio = (PGPIO)tcc_p2v(HwGPIO_BASE);
++ nand_intr_rb.pPIC =(PPIC)tcc_p2v(HwPIC_BASE);
++
++ init_waitqueue_head(&(nand_intr_rb.nd_busy_wait_q));
++ nand_intr_rb.is_nd_busy_complete = 0;
++ nand_intr_rb.irq = NAND_IRQ_READY;
++
++ ndd_isr_rb_enable_flag = NDD_RB_INTR_MODE_NORMAL;
++ #if 1 /* 010.01.12 */
++ BITSET(nand_intr_rb.pPIC->IEN0, ( 1 << NAND_IRQ_READY ));
++ BITCLR(nand_intr_rb.pPIC->CLR0, ( 1 << NAND_IRQ_READY ));
++ BITCLR(nand_intr_rb.pPIC->MODE0, ( 1 << NAND_IRQ_READY ));
++ #else
++ NAND_IO_IRQ_Mask(NAND_IRQ_READY);
++ NAND_IO_IRQ_Disable(NAND_IRQ_READY);
++ NAND_IO_IRQ_ExtInterruptClear(NAND_IRQ_READY);
++ #endif /* 0 */
++ ret = request_irq(nand_intr_rb.irq,
++ nand_isr_rb,
++ IRQF_DISABLED, /* flags */
++ "nand-isr-rb", /* in /proc/interrupts */
++ &nand_intr_rb); /* user data passed to ISR */
++ if (ret) {
++ printk("[%s:%d] cannot request irq !!!\n", __func__, __LINE__);
++ return -1;
++ }
++
++ nand_intr.p_nfc = (PNFC)tcc_p2v(HwNFC_BASE);
++
++ init_waitqueue_head(&(nand_intr.tx_wait_q));
++ init_waitqueue_head(&(nand_intr.rx_wait_q));
++ nand_intr.is_rx_complete = nand_intr.is_tx_complete = 0;
++ nand_intr.irq = NAND_IRQ_NFC;
++
++ ret = request_irq(nand_intr.irq,
++ nand_isr,
++ IRQF_DISABLED, /* flags */
++ "nand-isr", /* in /proc/interrupts */
++ &nand_intr); /* user data passed to ISR */
++ if (ret) {
++ printk("[%s:%d] cannot request irq !!!\n", __func__, __LINE__);
++ return -1;
++ }
++ #endif
++
++ #ifdef NAND_GPIO_DEBUG
++ BITCSET(nand_intr_rb.p_gpio->GPFFN2, 0x0FF000FF, 0x00000000);
++ BITSET(nand_intr_rb.p_gpio->GPFEN, Hw16);
++ BITSET(nand_intr_rb.p_gpio->GPFEN, Hw17);
++ BITSET(nand_intr_rb.p_gpio->GPFEN, Hw21);
++ BITSET(nand_intr_rb.p_gpio->GPFEN, Hw22);
++
++ // Clear
++ BITCLR(nand_intr_rb.p_gpio->GPFDAT, Hw16);
++ BITCLR(nand_intr_rb.p_gpio->GPFDAT, Hw17);
++ BITCLR(nand_intr_rb.p_gpio->GPFDAT, Hw21);
++ BITCLR(nand_intr_rb.p_gpio->GPFDAT, Hw22);
++ #endif
++
++ /* DMA alloc */
++ dma_t.buf_size = 1536;
++ dma_t.v_addr = dma_alloc_writecombine(0, dma_t.buf_size, &dma_t.dma_addr, GFP_KERNEL);
++
++ gNAND_PageBuffer = (unsigned char *)( ((unsigned int)gNAND_PageBuffer + 8) & 0xFFFFFFF8 );
++
++ for (i = 0; i < MAX_NDD_DEV ; i++)
++ {
++ NAND_Ioctl(DEV_INITIALIZE, NULL);
++
++ res = register_blkdev(NDD_DEV_MAJOR, NDD_DEV_NAME);
++ if (res < 0) {
++ printk(KERN_WARNING "ndd: unable to get major number.\n");
++ goto out;
++ }
++
++ ndd_dev[i].size = gNAND_DrvInfo[i].TotalDiskSector;
++ ndd_dev[i].data = kmalloc(sizeof(Device), GFP_KERNEL); //size should be less than 128*1024
++ ndd_dev[i].nand_work_info = kmalloc(sizeof(ndd_work_info), GFP_KERNEL);
++ ndd_dev[i].buf = kmalloc((sizeof(char) * 256 * 512), GFP_KERNEL);
++
++ #ifdef __USE_NAND_ISR_WRITE__
++ ndd_dev[i].nand_work_info->nSpareBuffer = kmalloc((sizeof(char) * 16 * MAX_NAND_WORK_SECTOR_NUM), GFP_KERNEL);
++ ndd_dev[i].nand_work_info->StuffInfo.nStuffPageBuffer = kmalloc((sizeof(char) * 512 * 32 * 4), GFP_KERNEL);
++
++ if (!ndd_dev[i].data ||
++ !ndd_dev[i].buf ||
++ !ndd_dev[i].nand_work_info ||
++ !ndd_dev[i].nand_work_info->nSpareBuffer ||
++ !ndd_dev[i].nand_work_info->StuffInfo.nStuffPageBuffer)
++ {
++ printk("ndd: Unable to allocate NAND device structure.\n");
++ goto out;
++ }
++ #else
++ if (!ndd_dev[i].data ||
++ !ndd_dev[i].buf ||
++ !ndd_dev[i].nand_work_info)
++ {
++ printk("ndd: Unable to allocate NAND device structure.\n");
++ goto out;
++ }
++ #endif
++
++ memset(ndd_dev[i].data, 0, sizeof(Device));
++
++ // init gendisk
++ ndd_dev[i].gd = alloc_disk(NDD_MAX_PARTITIONS);
++ if (!ndd_dev[i].gd) {
++ printk("ndd: allocate gendisk failed.\n");
++ goto out;
++ }
++
++ spin_lock_init(&(ndd_dev[i].lock));
++ ndd_dev[i].queue = blk_init_queue(ndd_request, &(ndd_dev[i].lock));
++ ndd_dev[i].gd->major = NDD_DEV_MAJOR;
++ ndd_dev[i].gd->first_minor = i * NDD_MAX_PARTITIONS;
++ ndd_dev[i].gd->fops = &ndd_fops;
++ ndd_dev[i].gd->private_data = &ndd_dev[i];
++ sprintf(ndd_dev[i].gd->disk_name, "ndd%c", 'a' + i);
++ set_capacity(ndd_dev[i].gd, gNAND_DrvInfo[0].TotalDiskSector);
++ ndd_dev[i].gd->queue = ndd_dev[i].queue;
++
++// ndd_dev[i].queue->queue_flags |= (1<<QUEUE_FLAG_WRITEFULL) | (1<<QUEUE_FLAG_READFULL) | (1<<QUEUE_FLAG_ELVSWITCH);
++
++ tcc_nand_data[i].req = ndd_dev[i].queue;
++ ndd_dev[i].queue->queuedata = &(tcc_nand_data[i]);
++ // add gendisk
++
++ tcc_nand_data[i].sg = kmalloc(sizeof(struct scatterlist) *
++ 128, GFP_KERNEL);
++ if (!tcc_nand_data[i].sg) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ sg_init_table(tcc_nand_data[i].sg, 128);
++
++
++ #ifdef __USE_TCC_NAND_WORK_Q__
++ tcc_nand_data[i].thread = kthread_run(tcc_nand_issue, &(tcc_nand_data[i]), ndd_dev[i].gd->disk_name);
++ if (IS_ERR(tcc_nand_data[i].thread)) {
++ printk("[%s:%d] cannot run kernel_thread !!!! \n", __func__, __LINE__);
++ goto out;
++ }
++ #endif
++ add_disk(ndd_dev[i].gd);
++ }
++
++ printk("[tcc_nand] init ndd(%s, %s)\n", TCC_ARCH, NAND_VER);
++ return 0;
++
++out:
++ if (dma_t.v_addr) {
++ dma_free_writecombine(0, dma_t.buf_size, dma_t.v_addr, dma_t.dma_addr);
++ }
++ memset(&dma_t, 0, sizeof(struct dma_buf));
++
++ for (i = 0; i < MAX_NDD_DEV; i++) {
++ if (tcc_nand_data[i].thread) {
++ kthread_stop(tcc_nand_data[i].thread);
++ tcc_nand_data[i].thread = NULL;
++ }
++ memset(&(tcc_nand_data[i]), 0, sizeof(nand_priv_data_t));
++
++ if (ndd_dev[i].data) { kfree(ndd_dev[i].data); }
++ if (ndd_dev[i].nand_work_info) { kfree(ndd_dev[i].nand_work_info); }
++ if (ndd_dev[i].buf) { kfree(ndd_dev[i].buf); }
++ #ifdef __USE_NAND_ISR_WRITE__
++ if (ndd_dev[i].nand_work_info->nSpareBuffer) { kfree(ndd_dev[i].nand_work_info->nSpareBuffer);}
++ if (ndd_dev[i].nand_work_info->StuffInfo.nStuffPageBuffer) { kfree(ndd_dev[i].nand_work_info->StuffInfo.nStuffPageBuffer);}
++ #endif
++ memset(&(ndd_dev[i]), 0, sizeof(Device));
++ }
++
++ return -1;
++}
++
++static void __exit ndd_exit(void)
++{
++ int i;
++ printk("[tcc_nand]: exit ndd\n");
++
++ #ifdef __USE_TCC_NAND_WORK_Q__
++ for (i = 0; i < MAX_NDD_DEV; i++) {
++ if (tcc_nand_data[i].thread) {
++ kthread_stop(tcc_nand_data[i].thread);
++ tcc_nand_data[i].thread = NULL;
++ }
++ memset(&(tcc_nand_data[i]), 0, sizeof(nand_priv_data_t));
++ }
++ #endif
++
++ for(i = 0; i < MAX_NDD_DEV; i++) {
++ del_gendisk(ndd_dev[i].gd);
++ put_disk(ndd_dev[i].gd);
++ blk_cleanup_queue(ndd_dev[i].queue);
++ kfree(ndd_dev[i].data);
++ kfree(ndd_dev[i].nand_work_info);
++ kfree(ndd_dev[i].buf);
++ }
++
++ #ifdef __USE_NAND_ISR__
++ free_irq(nand_intr_rb.irq, &nand_intr_rb);
++ free_irq(nand_intr.irq, &nand_intr);
++ #endif
++
++ //iounmap(virtadr);
++ if (dma_t.v_addr) {
++ dma_free_writecombine(0, dma_t.buf_size, dma_t.v_addr, dma_t.dma_addr);
++ }
++ memset(&dma_t, 0, sizeof(struct dma_buf));
++ unregister_blkdev(NDD_DEV_MAJOR, NDD_DEV_NAME);
++}
++
++
++module_init(ndd_init);
++module_exit(ndd_exit);
++
++MODULE_AUTHOR("Telechips Inc. SYS4-3 twkwon@telechips.com");
++MODULE_DESCRIPTION("TCC NAND driver");
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/block/tcc/libtnftl/libtnftl_V6005_TCC8900.o_shipped b/drivers/block/tcc/libtnftl/libtnftl_V6005_TCC8900.o_shipped
+new file mode 100644
+index 0000000..4de126c
+Binary files /dev/null and b/drivers/block/tcc/libtnftl/libtnftl_V6005_TCC8900.o_shipped differ
+diff --git a/drivers/block/tcc/libtnftl/libtnftl_V7014_TCC8900.o_shipped b/drivers/block/tcc/libtnftl/libtnftl_V7014_TCC8900.o_shipped
+new file mode 100644
+index 0000000..e7eb93c
+Binary files /dev/null and b/drivers/block/tcc/libtnftl/libtnftl_V7014_TCC8900.o_shipped differ
+diff --git a/drivers/block/tcc/nand_buffer.c b/drivers/block/tcc/nand_buffer.c
+new file mode 100644
+index 0000000..0bcb5b0
+--- /dev/null
++++ b/drivers/block/tcc/nand_buffer.c
+@@ -0,0 +1,40 @@
++/****************************************************************************
++ * FileName : nand_buffer.c
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#include "nand_drv.h"
++
++
++#if defined( FWDN_DOWNLOADER_INCLUDE )
++const unsigned char NANDBUF_Library_Version[] = { "SIGBYAHONG_NANDBUF_FWDN_V001000" };
++#elif defined(TCC92XX)
++const unsigned char NANDBUF_Library_Version[] = { "SIGBYAHONG_NANDBUF_TCC92XX_V001000" };
++#elif defined(TCC89XX)
++const unsigned char NANDBUF_Library_Version[] = { "SIGBYAHONG_NANDBUF_TCC89XX_V001000" };
++#endif
++
++//**********************************************************
++//*
++//* Global Variables
++//*
++//**********************************************************
++#if defined(_WINCE_)
++#pragma pack(8)
++unsigned char gNAND_PageBuffer[TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE + TNFTL_MAX_SUPPORT_NAND_IO_SPARE_SIZE];
++unsigned char gNAND_RCacheDTAreaBuffer[TNFTL_MAX_SUPPORT_RCACHE_MEMORY_SIZE];
++unsigned char gNAND_AlignBuffer[TNFTL_MAX_SUPPORT_ALIGNCACHE_MEMORY_SIZE];
++#pragma pack()
++#elif defined(_LINUX_)
++ //NOTE: In the case of LINUX, gNAND_PageBuffer is defined nand_drv.c
++#else
++__align(8) unsigned char gNAND_PageBuffer[TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE + TNFTL_MAX_SUPPORT_NAND_IO_SPARE_SIZE];
++__align(8) unsigned char gNAND_RCacheDTAreaBuffer[TNFTL_MAX_SUPPORT_RCACHE_MEMORY_SIZE];
++__align(8) unsigned char gNAND_AlignBuffer[TNFTL_MAX_SUPPORT_ALIGNCACHE_MEMORY_SIZE];
++#endif
++
+diff --git a/drivers/block/tcc/nand_crc.c b/drivers/block/tcc/nand_crc.c
+new file mode 100644
+index 0000000..6d692b2
+--- /dev/null
++++ b/drivers/block/tcc/nand_crc.c
+@@ -0,0 +1,193 @@
++
++/****************************************************************************
++ * FileName : nand_crc.c
++ * Description :
++ ****************************************************************************
++*
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++*
++ ****************************************************************************/
++const unsigned CRC32_TABLE[256] = {
++ 0x00000000, 0x90910101, 0x91210201, 0x01B00300,
++ 0x92410401, 0x02D00500, 0x03600600, 0x93F10701,
++ 0x94810801, 0x04100900, 0x05A00A00, 0x95310B01,
++ 0x06C00C00, 0x96510D01, 0x97E10E01, 0x07700F00,
++ 0x99011001, 0x09901100, 0x08201200, 0x98B11301,
++ 0x0B401400, 0x9BD11501, 0x9A611601, 0x0AF01700,
++ 0x0D801800, 0x9D111901, 0x9CA11A01, 0x0C301B00,
++ 0x9FC11C01, 0x0F501D00, 0x0EE01E00, 0x9E711F01,
++ 0x82012001, 0x12902100, 0x13202200, 0x83B12301,
++ 0x10402400, 0x80D12501, 0x81612601, 0x11F02700,
++ 0x16802800, 0x86112901, 0x87A12A01, 0x17302B00,
++ 0x84C12C01, 0x14502D00, 0x15E02E00, 0x85712F01,
++ 0x1B003000, 0x8B913101, 0x8A213201, 0x1AB03300,
++ 0x89413401, 0x19D03500, 0x18603600, 0x88F13701,
++ 0x8F813801, 0x1F103900, 0x1EA03A00, 0x8E313B01,
++ 0x1DC03C00, 0x8D513D01, 0x8CE13E01, 0x1C703F00,
++ 0xB4014001, 0x24904100, 0x25204200, 0xB5B14301,
++ 0x26404400, 0xB6D14501, 0xB7614601, 0x27F04700,
++ 0x20804800, 0xB0114901, 0xB1A14A01, 0x21304B00,
++ 0xB2C14C01, 0x22504D00, 0x23E04E00, 0xB3714F01,
++ 0x2D005000, 0xBD915101, 0xBC215201, 0x2CB05300,
++ 0xBF415401, 0x2FD05500, 0x2E605600, 0xBEF15701,
++ 0xB9815801, 0x29105900, 0x28A05A00, 0xB8315B01,
++ 0x2BC05C00, 0xBB515D01, 0xBAE15E01, 0x2A705F00,
++ 0x36006000, 0xA6916101, 0xA7216201, 0x37B06300,
++ 0xA4416401, 0x34D06500, 0x35606600, 0xA5F16701,
++ 0xA2816801, 0x32106900, 0x33A06A00, 0xA3316B01,
++ 0x30C06C00, 0xA0516D01, 0xA1E16E01, 0x31706F00,
++ 0xAF017001, 0x3F907100, 0x3E207200, 0xAEB17301,
++ 0x3D407400, 0xADD17501, 0xAC617601, 0x3CF07700,
++ 0x3B807800, 0xAB117901, 0xAAA17A01, 0x3A307B00,
++ 0xA9C17C01, 0x39507D00, 0x38E07E00, 0xA8717F01,
++ 0xD8018001, 0x48908100, 0x49208200, 0xD9B18301,
++ 0x4A408400, 0xDAD18501, 0xDB618601, 0x4BF08700,
++ 0x4C808800, 0xDC118901, 0xDDA18A01, 0x4D308B00,
++ 0xDEC18C01, 0x4E508D00, 0x4FE08E00, 0xDF718F01,
++ 0x41009000, 0xD1919101, 0xD0219201, 0x40B09300,
++ 0xD3419401, 0x43D09500, 0x42609600, 0xD2F19701,
++ 0xD5819801, 0x45109900, 0x44A09A00, 0xD4319B01,
++ 0x47C09C00, 0xD7519D01, 0xD6E19E01, 0x46709F00,
++ 0x5A00A000, 0xCA91A101, 0xCB21A201, 0x5BB0A300,
++ 0xC841A401, 0x58D0A500, 0x5960A600, 0xC9F1A701,
++ 0xCE81A801, 0x5E10A900, 0x5FA0AA00, 0xCF31AB01,
++ 0x5CC0AC00, 0xCC51AD01, 0xCDE1AE01, 0x5D70AF00,
++ 0xC301B001, 0x5390B100, 0x5220B200, 0xC2B1B301,
++ 0x5140B400, 0xC1D1B501, 0xC061B601, 0x50F0B700,
++ 0x5780B800, 0xC711B901, 0xC6A1BA01, 0x5630BB00,
++ 0xC5C1BC01, 0x5550BD00, 0x54E0BE00, 0xC471BF01,
++ 0x6C00C000, 0xFC91C101, 0xFD21C201, 0x6DB0C300,
++ 0xFE41C401, 0x6ED0C500, 0x6F60C600, 0xFFF1C701,
++ 0xF881C801, 0x6810C900, 0x69A0CA00, 0xF931CB01,
++ 0x6AC0CC00, 0xFA51CD01, 0xFBE1CE01, 0x6B70CF00,
++ 0xF501D001, 0x6590D100, 0x6420D200, 0xF4B1D301,
++ 0x6740D400, 0xF7D1D501, 0xF661D601, 0x66F0D700,
++ 0x6180D800, 0xF111D901, 0xF0A1DA01, 0x6030DB00,
++ 0xF3C1DC01, 0x6350DD00, 0x62E0DE00, 0xF271DF01,
++ 0xEE01E001, 0x7E90E100, 0x7F20E200, 0xEFB1E301,
++ 0x7C40E400, 0xECD1E501, 0xED61E601, 0x7DF0E700,
++ 0x7A80E800, 0xEA11E901, 0xEBA1EA01, 0x7B30EB00,
++ 0xE8C1EC01, 0x7850ED00, 0x79E0EE00, 0xE971EF01,
++ 0x7700F000, 0xE791F101, 0xE621F201, 0x76B0F300,
++ 0xE541F401, 0x75D0F500, 0x7460F600, 0xE4F1F701,
++ 0xE381F801, 0x7310F900, 0x72A0FA00, 0xE231FB01,
++ 0x71C0FC00, 0xE151FD01, 0xE0E1FE01, 0x7070FF00
++};
++
++/************************************************************************************************
++* FUNCTION : int SetKitlMode(int argc, char *argv[])
++*
++* DESCRIPTION :
++*
++************************************************************************************************/
++unsigned long makecrc (unsigned char *s, unsigned n)
++{
++ unsigned long c;
++ static unsigned long crc = (unsigned long)0xffffffffL;
++
++ if (s == 0)
++ {
++ c = 0xffffffffL;
++ }
++ else
++ {
++ c = crc;
++ if (n)
++ {
++ do
++ {
++ c = CRC32_TABLE[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
++ } while (--n);
++ }
++ }
++ crc = c;
++ return c ^ 0xffffffffL;
++}
++
++int VerifyROMFile(unsigned int *pBuffer,unsigned int size )
++{
++ #if defined(NAND_INCLUDE)
++ unsigned int crcout = 0;
++ unsigned int cnt, i, code, tmp;
++ unsigned int First_CrcRegion, Second_CrcRegion;
++
++ First_CrcRegion = (128<<10)>>2; //=32768
++ Second_CrcRegion = (size>>2);
++
++
++ //First CRC Check 0~128kbyte
++ for(cnt=0; cnt<First_CrcRegion; cnt++)
++ {
++ if(cnt == 4 || cnt == 5)
++ continue;
++
++ code = pBuffer[cnt];
++ for(i=0; i<4; i++)
++ {
++ tmp = code^crcout;
++ crcout = (crcout>>8)^CRC32_TABLE[tmp&0xFF];
++ code = code >> 8;
++ }
++ }
++ if(crcout !=pBuffer[4]) return -1;
++
++
++ //Second CRC Check 0~End
++ crcout=0;
++
++ for(cnt=0; cnt<Second_CrcRegion; cnt++)
++ {
++ code = pBuffer[cnt];
++ if(cnt == 4 || cnt == 5 )
++ {
++ continue;
++ }
++ else if(cnt==6){
++ code = 0x00000000;
++ }
++
++ for(i=0; i<4; i++)
++ {
++ tmp = code^crcout;
++ crcout = (crcout>>8)^CRC32_TABLE[tmp&0xFF];
++ code = code >> 8;
++ }
++
++ }
++ if(crcout !=pBuffer[6]) return -1;
++
++ #endif
++
++ return 1;
++}
++
++int VerifyROMFile_128K(unsigned int *pBuffer,unsigned int size )
++{
++
++ unsigned int crcout = 0;
++ unsigned int cnt, i, code, tmp;
++ unsigned int First_CrcRegion, Second_CrcRegion;
++
++ First_CrcRegion = (128<<10)>>2; //=32768
++ Second_CrcRegion = (size>>2);
++
++
++ //First CRC Check 0~128kbyte
++ for(cnt=0; cnt<First_CrcRegion; cnt++)
++ {
++ if(cnt == 4 || cnt == 5)
++ continue;
++
++ code = pBuffer[cnt];
++ for(i=0; i<4; i++)
++ {
++ tmp = code^crcout;
++ crcout = (crcout>>8)^CRC32_TABLE[tmp&0xFF];
++ code = code >> 8;
++ }
++ }
++ if(crcout !=pBuffer[4]) return -1;
++ return 1;
++}
+diff --git a/drivers/block/tcc/nand_drv.c b/drivers/block/tcc/nand_drv.c
+new file mode 100644
+index 0000000..0380f29
+--- /dev/null
++++ b/drivers/block/tcc/nand_drv.c
+@@ -0,0 +1,2117 @@
++/****************************************************************************
++ * FileName : nand_drv.c
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#if defined(_LINUX_)
++#include "common.h"
++#if defined(USE_V_ADDRESS)
++#include <linux/kernel.h>
++#include <linux/string.h>
++#endif
++#endif
++
++#if defined(_LINUX_) || defined(_WINCE_)
++//#include "IO_TCC7XX.h"
++#include "nand_drv.h"
++//#include "Disk.h"
++#include "TC_File.h"
++#else
++#include "Globals.h"
++#include "IO_TCCXXX.h"
++#include "nand_drv.h"
++#include "disk.h"
++#include "FileBufferCtrl.h"
++#include "Assert.h"
++#endif
++
++#ifdef _WINCE_
++#include "bsp.h"
++#include "args.h"
++#endif
++
++#if defined(__NUCLEUS_KERNEL__)
++#include "TC_Kernel.h"
++#endif
++
++#ifdef AUDIOUI_INCLUDE
++#include "AudioUI.H"
++#endif
++
++
++//#define NAND_DRV_PORT_DEBUG
++
++#ifdef BOOTCRCCHEK
++ typedef struct _BootCRC
++ {
++ unsigned int crc128kchk;
++ unsigned int crcfullchk;
++ unsigned int bootfilesize;
++ }BootCRC;
++#endif
++
++#ifndef WITHOUT_FILESYSTEM
++
++#if defined( FWDN_DOWNLOADER_INCLUDE )
++const unsigned char NANDDRV_Library_Version[] = { "SIGBYAHONG_NANDDRV_FWDN_V001000" };
++#elif defined(TCC92XX)
++const unsigned char NANDDRV_Library_Version[] = { "SIGBYAHONG_NANDDRV_TCC92XX_V001000" };
++#elif defined(TCC89XX)
++const unsigned char NANDDRV_Library_Version[] = { "SIGBYAHONG_NANDDRV_TCC89XX_V001000" };
++#endif
++
++//=============================================================================
++//*
++//*
++//* [ CONST DATA DEFINE ]
++//*
++//*
++//=============================================================================
++#define NAND_DRV_HIDDEN_INFO_SIZE ( 19 + 8 + 1*4 )
++
++const unsigned char gNAND_HiddenInfoSignature[ NAND_DRV_HIDDEN_INFO_SIZE ] =
++{
++ 'T','N','F','T','L','H','I','D','D','E','N','S','I','Z','E','I','N','F','O',
++
++ #ifndef NU_FILE_INCLUDE
++ #ifdef AUDIOUI_INCLUDE
++ ((unsigned long int)(NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE+AUI_HD_OCCPAGE) >> 0) & 0xFF,
++ ((unsigned long int)(NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE+AUI_HD_OCCPAGE) >> 8) & 0xFF,
++ ((unsigned long int)(NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE+AUI_HD_OCCPAGE) >> 16) & 0xFF,
++ ((unsigned long int)(NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE+AUI_HD_OCCPAGE) >> 24) & 0xFF,
++ #else
++ ((unsigned long int)(NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE) >> 0) & 0xFF,
++ ((unsigned long int)(NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE) >> 8) & 0xFF,
++ ((unsigned long int)(NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE) >> 16) & 0xFF,
++ ((unsigned long int)(NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE)>> 24) & 0xFF,
++ #endif
++ #else
++ ((unsigned long int)(NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE) >> 0) & 0xFF,
++ ((unsigned long int)(NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE) >> 8) & 0xFF,
++ ((unsigned long int)(NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE) >> 16) & 0xFF,
++ ((unsigned long int)(NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE) >> 24) & 0xFF,
++ #endif
++
++ ((unsigned long int)TNFTL_MULTI_HIDDEN_AREA_NUM >> 0) & 0xFF,
++ ((unsigned long int)TNFTL_MULTI_HIDDEN_AREA_NUM >> 8) & 0xFF,
++ ((unsigned long int)TNFTL_MULTI_HIDDEN_AREA_NUM >> 16) & 0xFF,
++ ((unsigned long int)TNFTL_MULTI_HIDDEN_AREA_NUM >> 24) & 0xFF,
++
++ ((unsigned long int)NAND_HIDDEN_DRIVE_DEFAULT_TOTAL_SECTOR_SIZE >> 0) & 0xFF,
++ ((unsigned long int)NAND_HIDDEN_DRIVE_DEFAULT_TOTAL_SECTOR_SIZE >> 8) & 0xFF,
++ ((unsigned long int)NAND_HIDDEN_DRIVE_DEFAULT_TOTAL_SECTOR_SIZE >> 16) & 0xFF,
++ ((unsigned long int)NAND_HIDDEN_DRIVE_DEFAULT_TOTAL_SECTOR_SIZE >> 24) & 0xFF
++};
++
++//=============================================================================
++//*
++//*
++//* [ GLOBAL VARIABLE DEFINE ]
++//*
++//*
++//=============================================================================
++NAND_DRVINFO gNAND_DrvInfo[MAX_NAND_DRIVE];
++TNFTL_HIDDEN_INFO gTNFTL_HiddenInfo[MAX_NAND_DRIVE];
++
++TNFTL_DRVINFO gTNFTL_DrvInfo[MAX_NAND_DRIVE];
++TNFTL_RW_AREA gTNFTL_MULTIHDAreaInfo[MAX_NAND_DRIVE][TNFTL_MULTI_HIDDEN_AREA_MAX_NUM];
++TNFTL_LPT_BLOCK gTNFTL_DTAreaLPTBlk[MAX_NAND_DRIVE][TNFTL_LPT_BLK_NUM_For_DATA_AREA];
++TNFTL_LPT_BLOCK gTNFTL_HDAreaLPTBlk[MAX_NAND_DRIVE][TNFTL_LPT_BLK_NUM_For_HIDDEN_AREA];
++TNFTL_LPT_BLOCK gTNFTL_MULTIHDAreaLPTBlk[MAX_NAND_DRIVE][TNFTL_MULTI_HIDDEN_AREA_MAX_NUM][TNFTL_LPT_BLK_NUM_For_DATA_AREA];
++TNFTL_WCACHE gTNFTL_DTAreaWCache[MAX_NAND_DRIVE][TNFTL_WCACHE_NUM_For_DATA_AREA];
++TNFTL_WCACHE gTNFTL_HDAreaWCache[MAX_NAND_DRIVE][TNFTL_WCACHE_NUM_For_HIDDEN_AREA];
++TNFTL_WCACHE gTNFTL_MULTIHDAreaWCache[MAX_NAND_DRIVE][TNFTL_MULTI_HIDDEN_AREA_MAX_NUM][TNFTL_WCACHE_NUM_For_DATA_AREA];
++
++#if defined( TNFTL_V5_INCLUDE ) || defined(TNFTL_V6_INCLUDE)
++TNFTL_RCACHE_SLOT gTNFTL_DTAreaRCache[MAX_NAND_DRIVE][TNFTL_MAX_SUPPORT_RCACHE_MEMORY_SIZE>>9];
++TNFTL_RCACHE_SLOT gTNFTL_HDAreaRCache[MAX_NAND_DRIVE][TNFTL_MAX_SUPPORT_RCACHE_MEMORY_SIZE>>9];
++TNFTL_RCACHE_SLOT gTNFTL_MULTIHDAreaRCache[MAX_NAND_DRIVE][TNFTL_MULTI_HIDDEN_AREA_MAX_NUM][TNFTL_MAX_SUPPORT_RCACHE_MEMORY_SIZE>>9];
++#endif
++
++TNFTL_MAINPB_INFO gTNFTL_DTAreaMainPBInfo[MAX_NAND_DRIVE][TNFTL_WCACHE_NUM_For_DATA_AREA];
++TNFTL_MAINPB_INFO gTNFTL_HDAreaMainPBInfo[MAX_NAND_DRIVE][TNFTL_WCACHE_NUM_For_HIDDEN_AREA];
++TNFTL_MAINPB_INFO gTNFTL_MULTIHDAreaMainPBInfo[MAX_NAND_DRIVE][TNFTL_MULTI_HIDDEN_AREA_MAX_NUM][TNFTL_WCACHE_NUM_For_DATA_AREA];
++
++NAND_IO_DEVINFO *gLBA_DevInfo;
++
++unsigned char gNAND_UARTDebugFlag = DISABLE;
++unsigned char gNAND_HiddenInfoLoadFlag = DISABLE;
++#if defined(_LINUX_) || defined(_WINCE_)
++unsigned char gNAND_SetFlagOfChangeAreaSize = DISABLE;
++unsigned char gFormatType = TC_LOWLEVEL_YES;
++unsigned int gMAX_ROMSIZE = MAX_ROMSIZE_NAND;
++#else
++unsigned char gNAND_SetFlagOfChangeAreaSize = ENABLE;
++#endif
++
++//=============================================================================
++//*
++//*
++//* [ LOCAL FUNCTIONS DEFINE ]
++//*
++//*
++//=============================================================================
++
++//=============================================================================
++//*
++//*
++//* [ EXTERN VARIABLE & FUNCTIONS DEFINE ]
++//*
++//*
++//=============================================================================
++extern unsigned char NANDBUF_Library_Version[];
++#if defined(_LINUX_)
++unsigned char gNAND_PageBuffer[TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE + TNFTL_MAX_SUPPORT_NAND_IO_SPARE_SIZE] __attribute__((aligned(8)));
++unsigned char gNAND_RCacheDTAreaBuffer[TNFTL_MAX_SUPPORT_RCACHE_MEMORY_SIZE] __attribute__((aligned(8)));
++unsigned char gNAND_AlignBuffer[TNFTL_MAX_SUPPORT_ALIGNCACHE_MEMORY_SIZE] __attribute__((aligned(8)));
++#else
++extern unsigned char gNAND_PageBuffer[TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE + TNFTL_MAX_SUPPORT_NAND_IO_SPARE_SIZE];
++extern unsigned char gNAND_RCacheDTAreaBuffer[TNFTL_MAX_SUPPORT_RCACHE_MEMORY_SIZE];
++extern unsigned char gNAND_AlignBuffer[TNFTL_MAX_SUPPORT_ALIGNCACHE_MEMORY_SIZE];
++#endif
++
++extern NAND_IO_CYCLE WriteCycleTime;
++extern NAND_IO_CYCLE ReadCycleTime;
++extern NAND_IO_CYCLE CommCycleTime;
++extern unsigned int gMaxBusClkMHZ;
++extern unsigned int gCycleTick;
++
++#if !defined(NU_FILE_INCLUDE) && !defined(_LINUX_) && !defined(_WINCE_)
++extern unsigned int fat_cbuffer[];
++#else
++extern unsigned char gFormatType;
++#endif
++
++extern unsigned short usbFirmwareDownloadMode;
++
++#if !defined(FWDN_DOWNLOADER_INCLUDE) && !defined(_LINUX_) && !defined(_WINCE_)
++ #ifdef MTP_INCLUDE
++ extern void* MTPMEM_AllocNandInitBuffer( void );
++ extern unsigned int MTPMEM_GetNandIintBufferSize( void );
++ #else
++ extern char gFileBuffer[RAW_BUFFERSIZE];
++ #endif
++#endif
++
++/******************************************************************************
++*
++* unsigned char* NAND_TellLibraryVersion
++*
++* Input : NONE
++* Output : NONE
++* Return : NONE
++*
++* Description :
++*
++*******************************************************************************/
++unsigned char* NAND_TellLibraryVersion( void )
++{
++ return (unsigned char*)gNAND_HiddenInfoSignature;
++}
++
++/******************************************************************************
++*
++* unsigned char* NAND_DRV_TellLibraryVersion
++*
++* Input : NONE
++* Output : NONE
++* Return : NONE
++*
++* Description :
++*
++*******************************************************************************/
++unsigned char* NAND_DRV_TellLibraryVersion( void )
++{
++ unsigned short int i = 0;
++
++ if ( i )
++ return (unsigned char*)NANDBUF_Library_Version;
++ else
++ return (unsigned char*)NANDDRV_Library_Version;
++}
++
++/*************************************************************************************
++ * NAND_Init
++ *
++ * Description :
++ * Argument :
++ * Return : if it is successed then return 0
++ * if it is failed then return Error Code
++ *
++ *************************************************************************************/
++void NAND_Init( void )
++{
++ #ifdef NAND_LBA_INCLUDE
++ NAND_ERROR res;
++ #endif
++
++ #ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++ unsigned int i;
++ #endif
++
++ #if !defined(NU_FILE_INCLUDE) && !defined(FWDN_DOWNLOADER_INCLUDE) && !defined(_LINUX_) & !defined(_WINCE_)
++ unsigned int BufferSize;
++ #endif
++
++ //=====================================================
++ // Initialize NAND IO & TNFTL Variable
++ //=====================================================
++ NAND_IO_Init();
++
++ //=================================================================
++ // Initialize TNFTL Driver
++ //=================================================================
++ /* Drive #0 */
++ TNFTL_AllocMemAndLinkForDriver( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0], &gNAND_DrvInfo[NAND_DRV_0].NFTLDrvInfo );
++ TNFTL_AllocMemAndLinkForLPT( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].DTArea, &gTNFTL_DTAreaLPTBlk[NAND_DRV_0][0], TNFTL_LPT_BLK_NUM_For_DATA_AREA );
++ TNFTL_AllocMemAndLinkForLPT( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].HDArea, &gTNFTL_HDAreaLPTBlk[NAND_DRV_0][0], TNFTL_LPT_BLK_NUM_For_HIDDEN_AREA );
++ TNFTL_AllocMemAndLinkForWCACHE( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].DTArea, &gTNFTL_DTAreaWCache[NAND_DRV_0][0], TNFTL_WCACHE_NUM_For_DATA_AREA );
++ TNFTL_AllocMemAndLinkForWCACHE( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].HDArea, &gTNFTL_HDAreaWCache[NAND_DRV_0][0], TNFTL_WCACHE_NUM_For_HIDDEN_AREA );
++ #if defined( TNFTL_V5_INCLUDE ) || defined(TNFTL_V6_INCLUDE)
++ TNFTL_AllocMemAndLinkForRCACHE( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].DTArea, &gTNFTL_DTAreaRCache[NAND_DRV_0][0] );
++ TNFTL_AllocMemAndLinkForRCACHE( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].HDArea, &gTNFTL_HDAreaRCache[NAND_DRV_0][0] );
++ #endif
++ TNFTL_AllocMemAndLinkForMainPBInfo( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].DTArea, &gTNFTL_DTAreaMainPBInfo[NAND_DRV_0][0], 2 );
++ TNFTL_AllocMemAndLinkForMainPBInfo( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].HDArea, &gTNFTL_HDAreaMainPBInfo[NAND_DRV_0][0], TNFTL_WCACHE_NUM_For_HIDDEN_AREA );
++ TNFTL_AllocMemAndLinkForMultiHidden( NAND_DRV_0, &gTNFTL_MULTIHDAreaInfo[NAND_DRV_0][0] );
++ TNFTL_SetMultiHiddenNums( NAND_DRV_0, TNFTL_MULTI_HIDDEN_AREA_NUM );
++
++ #ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++ for ( i = 0; i < TNFTL_MULTI_HIDDEN_AREA_NUM; ++i )
++ {
++ TNFTL_AllocMemAndLinkForLPT( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].MultiHDArea[i], &gTNFTL_MULTIHDAreaLPTBlk[NAND_DRV_0][i][0], TNFTL_LPT_BLK_NUM_For_DATA_AREA );
++ TNFTL_AllocMemAndLinkForWCACHE( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].MultiHDArea[i], &gTNFTL_MULTIHDAreaWCache[NAND_DRV_0][i][0], TNFTL_WCACHE_NUM_For_DATA_AREA );
++ TNFTL_AllocMemAndLinkForMainPBInfo( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].MultiHDArea[i], &gTNFTL_MULTIHDAreaMainPBInfo[NAND_DRV_0][i][0], TNFTL_WCACHE_NUM_For_DATA_AREA );
++ #if defined( TNFTL_V5_INCLUDE ) || defined(TNFTL_V6_INCLUDE)
++ TNFTL_AllocMemAndLinkForRCACHE( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].MultiHDArea[i], &gTNFTL_MULTIHDAreaRCache[NAND_DRV_0][i][0] );
++ #endif
++ }
++ #endif
++
++ TNFTL_Init( NAND_DRV_0 );
++ TNFTL_SetStEdOfCS( NAND_DRV_0, NAND_IO_DRV0_START_CS, NAND_IO_DRV0_END_CS );
++
++ TNFTL_AllocMemAndLinkForPageBuffer( NAND_DRV_0, gNAND_PageBuffer );
++ #if defined( TNFTL_V5_INCLUDE ) || defined(TNFTL_V6_INCLUDE)
++ /* RCACHE & ALIGN Cache Buffer Memory Allocation( TNFTL V5 ) */
++ TNFTL_AllocMemAndLinkForRCacheBuffer( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].DTArea, gNAND_RCacheDTAreaBuffer, TNFTL_MAX_SUPPORT_RCACHE_MEMORY_SIZE );
++ TNFTL_SetUseAreaReadCacheMode( gNAND_DrvInfo[NAND_DRV_0].NFTLDrvInfo, &gTNFTL_DrvInfo[NAND_DRV_0].DTArea, ENABLE );
++ TNFTL_AllocMemAndLinkForAlignCacheBuffer( NAND_DRV_0, gNAND_AlignBuffer, TNFTL_MAX_SUPPORT_ALIGNCACHE_MEMORY_SIZE );
++ #endif
++
++ #if !defined(NU_FILE_INCLUDE) && !defined(_LINUX_) && !defined(_WINCE_)
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ #ifdef MTP_INCLUDE
++ BufferSize = MTPMEM_GetNandIintBufferSize() / 4;
++ #else
++ BufferSize = RAW_BUFFERSIZE / 4;
++ #endif
++
++ if ( BufferSize > 65536 / 4 )
++ {
++ #ifdef MTP_INCLUDE
++ TNFTL_AllocMemAndLinkForMakeLPT( NAND_DRV_0, (unsigned char*)MTPMEM_AllocNandInitBuffer(), MTPMEM_GetNandIintBufferSize() / 4 );
++ #else
++ TNFTL_AllocMemAndLinkForMakeLPT( NAND_DRV_0, gFileBuffer, RAW_BUFFERSIZE / 4 );
++ #endif
++ }
++ else
++ {
++ TNFTL_AllocMemAndLinkForMakeLPT( NAND_DRV_0, fat_cbuffer, 65536 / 4 );
++ }
++ #else
++ TNFTL_AllocMemAndLinkForMakeLPT( NAND_DRV_0, fat_cbuffer, 65536 / 4 );
++ #endif
++ #endif
++
++ #ifdef NAND_LBA_INCLUDE
++ gLBA_DevInfo = &gNAND_DrvInfo[0].NFTLDrvInfo->MediaDevInfo[0];
++
++ gLBA_DevInfo->LBAInfo.FlagOfChangeTotalSectorSize = DISABLE;
++ res = NAND_IO_LBA_GetDeviceInfo( gLBA_DevInfo );
++ if ( ( res == SUCCESS ) || ( gLBA_DevInfo->Feature.MediaType & S_LBA ) )
++ gNAND_DrvInfo[0].NFTLDrvInfo->NANDType = NAND_TYPE_LBA_NAND;
++ else
++ gNAND_DrvInfo[0].NFTLDrvInfo->NANDType = NAND_TYPE_PURE_NAND;
++ #else
++ gNAND_DrvInfo[0].NFTLDrvInfo->NANDType = NAND_TYPE_PURE_NAND;
++ #endif
++
++ /* Init TNFTL MSC Debug Monitor */
++ #if !defined(FWDN_DOWNLOADER_INCLUDE) && !defined(_LINUX_) && !defined(_WINCE_)
++ #ifdef TNFTL_DEBUG_INCLUDE
++ TNFTL_DEBUG_Init_Function( MASS_SCSI_InitMSCDebugMonitor,
++ VTC_SendData,
++ VTC_ReceiveData,
++ MASS_BulkOnly_SendData,
++ MASS_BulkOnly_ReceiveData,
++ MASS_SCSI_SetMSCDebugMonitorHandler,
++ FWDN_PROT_ResponseAck,
++ FWDN_PROT_ResponseNack);
++ TNFTL_DEBUG_Init();
++ #endif
++ #endif
++
++ return;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_InitHiddenInfo( void );
++*
++* DESCRIPTION :
++*
++* INPUT : NONE
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_InitHiddenInfo( void )
++{
++ unsigned int i;
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ gTNFTL_HiddenInfo[NAND_DRV_0].HiddenPageSize = 4096;
++ gTNFTL_HiddenInfo[NAND_DRV_0].MultiHiddenAreaNum = 0;
++ gTNFTL_HiddenInfo[NAND_DRV_0].ROAreaSize = 0;
++ #else
++ gTNFTL_HiddenInfo[NAND_DRV_0].HiddenPageSize = NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE;
++ gTNFTL_HiddenInfo[NAND_DRV_0].MultiHiddenAreaNum = TNFTL_MULTI_HIDDEN_AREA_NUM;
++ #endif
++
++ for ( i = 0; i < TNFTL_MULTI_HIDDEN_AREA_MAX_NUM; ++i )
++ gTNFTL_HiddenInfo[NAND_DRV_0].MultiHiddenSize[i] = NAND_HIDDEN_DRIVE_DEFAULT_TOTAL_SECTOR_SIZE;
++
++ gTNFTL_HiddenInfo[NAND_DRV_0].ROAreaSize = 0;
++
++ return;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_SetFlagOfChangeAreaSize( unsigned char On_Off );
++*
++* DESCRIPTION :
++*
++* INPUT :
++* On_Off = ENABLE/DISABLE
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_SetFlagOfChangeAreaSize( unsigned char On_Off )
++{
++ gNAND_SetFlagOfChangeAreaSize = On_Off;
++ return;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_SetHiddenInfoLoagFlag( unsigned char On_Off );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* On_Off = ENABLE/DISABLE
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_SetHiddenInfoLoagFlag( unsigned char On_Off )
++{
++ gNAND_HiddenInfoLoadFlag = On_Off;
++ return;
++}
++
++/******************************************************************************
++*
++* NAND_ERROR NAND_InitDrive
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_ERROR NAND_InitDrive( int nDrvNo )
++{
++ unsigned int i;
++
++ TNFTL_ERROR res;
++ #if defined(NU_FILE_INCLUDE) || defined(_LINUX_) || defined(_WINCE_)
++ void *pointer;
++ #if defined(_LINUX_)
++ unsigned bufSize = 64*1024;
++ static unsigned int Tempbuffer[64*1024];
++ #else
++ unsigned bufSize = 256*1024;
++ static unsigned char Tempbuffer[256*1024];
++ #endif
++ #endif
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ //===============================================================
++ // Check Drive I/O in the FTL Layer
++ //===============================================================
++ gNAND_DrvInfo[nDrvNo].DrvStatus = DISABLE;
++
++ #if defined(NU_FILE_INCLUDE)
++ pointer = TC_Allocate_Memory(bufSize);
++ if (pointer == NULL)
++ return -1;
++ #elif defined(_LINUX_) || defined(_WINCE_)
++ pointer = Tempbuffer;
++ if (pointer == NULL)
++ return -1;
++ #endif
++
++ #if defined(NU_FILE_INCLUDE)|| defined(_LINUX_) || defined(_WINCE_)
++ #if defined(_LINUX_)
++ TNFTL_AllocMemAndLinkForMakeLPT( NAND_DRV_0, pointer, bufSize ); /* [1193] */
++ #else
++ TNFTL_AllocMemAndLinkForMakeLPT( NAND_DRV_0, pointer, bufSize/4 ); /* [1193] */
++ #endif
++ #endif
++
++ if ( gNAND_SetFlagOfChangeAreaSize == DISABLE )
++ TNFTL_SetFlagOfChangeTotalSecSize( gNAND_DrvInfo[0].NFTLDrvInfo, &gNAND_DrvInfo[0].NFTLDrvInfo->HDArea, DISABLE );
++ else
++ TNFTL_SetFlagOfChangeTotalSecSize( gNAND_DrvInfo[0].NFTLDrvInfo, &gNAND_DrvInfo[0].NFTLDrvInfo->HDArea, ENABLE );
++
++ // Check if low-level format option is enabled. /* [1255] */
++ if (usbFirmwareDownloadMode & Hw8)
++ {
++ BITCLR(usbFirmwareDownloadMode, Hw8);
++ TNFTL_BMPRefresh( gNAND_DrvInfo[0].NFTLDrvInfo);
++ }
++
++ //=========================================================
++ // Linux MTD Include
++ //=========================================================
++ TNFTL_SetROAreaSize( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo, gTNFTL_HiddenInfo[NAND_DRV_0].ROAreaSize << 20 );
++ //=========================================================
++
++ res = TNFTL_InitDrive( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo );
++ #ifdef NU_FILE_INCLUDE
++ TC_Deallocate_Memory(pointer);
++ #endif
++
++ #if defined(USE_V_ADDRESS) && defined(_WINCE_)
++ RETAILMSG(1, (TEXT("[NAND ] [BClk %dMHZ][1Tick %d][RE-S:%d,P:%d,H:%d][WR-S:%d,P:%d,H:%d][COM-S:%d,P:%d,H:%d]\n"),
++ gMaxBusClkMHZ,gCycleTick,ReadCycleTime.STP,ReadCycleTime.PW,ReadCycleTime.HLD,
++ WriteCycleTime.STP,WriteCycleTime.PW,WriteCycleTime.HLD,CommCycleTime.STP,CommCycleTime.PW,CommCycleTime.HLD));
++ RETAILMSG(1, (TEXT("[NAND ] [NB Area:%dMB][DT Area:%dMB][HD Area:%dMB]"),
++ //gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->NBArea.PBpV << gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->MediaRatioShiftBSize[0],
++ ( gMAX_ROMSIZE * 2 ) >> 20,
++ gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->DTArea.TotalSectorSize >> 11,
++ gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->HDArea.TotalSectorSize >> 11 ));
++ for ( i = 0; i < gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->MultiHiddendNums; ++i )
++ RETAILMSG(1, (TEXT( "[MH Area%d:%dMB]"), i, gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->MultiHDArea[i].TotalSectorSize >> 11 ));
++ if ( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->ROAreaSize != 0 )
++ RETAILMSG(1, (TEXT( "[MTD Size:%dMB]"), gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->ROAreaSize >> 20 ));
++ RETAILMSG(1, (TEXT("\n")));
++ #else
++ ND_TRACE( "[NAND ] [BClk %dMHZ][1Tick %d][RE-S:%d,P:%d,H:%d][WR-S:%d,P:%d,H:%d][COM-S:%d,P:%d,H:%d]\n",
++ gMaxBusClkMHZ,gCycleTick,ReadCycleTime.STP,ReadCycleTime.PW,ReadCycleTime.HLD,
++ WriteCycleTime.STP,WriteCycleTime.PW,WriteCycleTime.HLD,CommCycleTime.STP,CommCycleTime.PW,CommCycleTime.HLD );
++ ND_TRACE( "[NAND ] [NB Area:%dMB][DT Area:%dMB][HD Area:%dMB]",
++ //gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->NBArea.PBpV << gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->MediaRatioShiftBSize[0],
++ (gMAX_ROMSIZE * 2) >> 20,
++ gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->DTArea.TotalSectorSize >> 11,
++ gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->HDArea.TotalSectorSize >> 11);
++ for ( i = 0; i < gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->MultiHiddendNums; ++i )
++ ND_TRACE( "[MH Area%d:%dMB]", i, gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->MultiHDArea[i].TotalSectorSize >> 11 );
++ if ( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->ROAreaSize != 0 )
++ ND_TRACE("[MTD Size:%dMB]", gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->ROAreaSize >> 20 );
++ ND_TRACE("\n");
++ #endif
++
++ if ( res != SUCCESS )
++ {
++ #if defined(USE_V_ADDRESS)
++ #if defined(_LINUX_)
++ if ( res == ERR_TNFTL_OVERSIZE_MTD_AREA_SIZE )
++ printk("\nError: MTD Area Size is too big...\n");
++ else
++ printk("\nTNFTL_Init_Fail:0x%X", res );
++ #endif
++ #else
++ #if defined(_LINUX_)
++ if ( res == ERR_TNFTL_OVERSIZE_MTD_AREA_SIZE )
++ printf("\nError: MTD Area Size is too big...\n");
++ else
++ printf("\nTNFTL_Init_Fail:0x%X", res );
++ #endif
++ #endif
++ return ERR_NAND_INIT_FAILED;
++ //return res; //original
++ }
++
++ TNFTL_AREAGetTotalSecAndCHS( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo,
++ &gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->DTArea,
++ (U32 *)&gNAND_DrvInfo[nDrvNo].TotalDiskSector,
++ &gNAND_DrvInfo[nDrvNo].Cylinder,
++ &gNAND_DrvInfo[nDrvNo].Head,
++ &gNAND_DrvInfo[nDrvNo].Sector );
++
++ gNAND_DrvInfo[nDrvNo].DrvStatus = ENABLE;
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++
++ gNAND_DrvInfo[nDrvNo].DrvStatus = DISABLE;
++
++ if ( gNAND_SetFlagOfChangeAreaSize == DISABLE )
++ gLBA_DevInfo->LBAInfo.FlagOfChangeTotalSectorSize = DISABLE;
++ else
++ gLBA_DevInfo->LBAInfo.FlagOfChangeTotalSectorSize = ENABLE;
++
++ res = NAND_IO_LBA_Init( gLBA_DevInfo );
++ if ( res != SUCCESS )
++ return ERR_NAND_INIT_FAILED;
++
++ NAND_IO_LBA_GetTotalSecAndCHS( gLBA_DevInfo,
++ NAND_LBA_DATA_AREA,
++ (U32)&gNAND_DrvInfo[nDrvNo].TotalDiskSector,
++ &gNAND_DrvInfo[nDrvNo].Cylinder,
++ &gNAND_DrvInfo[nDrvNo].Head,
++ &gNAND_DrvInfo[nDrvNo].Sector );
++
++ gNAND_DrvInfo[nDrvNo].DrvStatus = ENABLE;
++ #endif
++ }
++
++ return (NAND_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* int NAND_ReadSector
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_ReadSector( int nDrvNo, U32 LBA, U32 nSecSize, void* nReadBuffer )
++{
++ #ifdef NAND_INCLUDE
++ TNFTL_ERROR res = SUCCESS;
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ unsigned long int count;
++ HwTCNT4 = 0;
++ #endif
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ PRINTF( "\n\nNAND_ReadSector( %08d, %08d ) -------------------------- ", LBA, nSecSize );
++ #endif
++
++ #ifdef NAND_DRV_UART_DEBUG
++ #if defined(USE_V_ADDRESS)
++ #if defined(_WINCE_)
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ RETAILMSG(1,(TEXT( "\n\nNAND_ReadSector( %08d, %08d ) -------------------------- "), LBA, nSecSize ));
++ #endif
++ #endif
++ #endif
++ //==============================================================================
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ res = TNFTL_AREAReadSector( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo,
++ &gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->DTArea,
++ LBA, nSecSize, nReadBuffer );
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ res = NAND_IO_LBA_ReadSector( gLBA_DevInfo,
++ NAND_LBA_DATA_AREA,
++ LBA, nSecSize, nReadBuffer);
++ #endif
++ }
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ count = HwTCNT4;
++ PRINTF( "\n[NAND_READ Sector %08d - %05d ] ( %d uS ) -------------------------- ",
++ LBA,
++ nSecSize,
++ (count*267)/100);
++ #endif
++ //==============================================================================
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ PRINTF( " FAIL %08X", res );
++ #endif
++
++ return -1;
++ }
++
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/******************************************************************************
++*
++* int NAND_WriteSector
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_WriteSector( int nDrvNo, U32 LBA, U32 nSecSize, void* nWriteBuffer )
++{
++ #ifdef NAND_INCLUDE
++ TNFTL_ERROR res = SUCCESS;
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ unsigned long int count;
++ HwTCNT4 = 0;
++ #endif
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ PRINTF( "\n\nNAND_WriteSector( %08d, %08d ) -----------------------------------", LBA, nSecSize );
++ #endif
++
++ #ifdef NAND_DRV_UART_DEBUG
++ #if defined(USE_V_ADDRESS)
++ #if defined(_WINCE_)
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ RETAILMSG(1,(TEXT( "\n\nNAND_WriteSector( %08d, %08d ) -------------------------- "), LBA, nSecSize ));
++ #endif
++ #endif
++ #endif
++
++ //==============================================================================
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ res = TNFTL_AREAWriteSector( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo,
++ &gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->DTArea,
++ LBA, nSecSize, nWriteBuffer );
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ res = NAND_IO_LBA_WriteSector( gLBA_DevInfo,
++ NAND_LBA_DATA_AREA,
++ LBA, nSecSize, nWriteBuffer );
++ #endif
++ }
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ count = HwTCNT4;
++ PRINTF( "\n[NAND_WRITE Sector %08d - %05d ] ( %d uS ) -------------------------- ",
++ LBA,
++ nSecSize,
++ (count*267)/100);
++ #endif
++ //==============================================================================
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ PRINTF( "\nFAIL : %08X ", res );
++ #endif
++
++ return -1;
++ }
++
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/******************************************************************************
++*
++* int NAND_HDReadSector
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_HDReadSector( int nDrvNo, U32 LBA, U32 nSecSize, void* nReadBuffer )
++{
++ #ifdef NAND_INCLUDE
++ TNFTL_ERROR res = SUCCESS;
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ #if defined(_LINUX_) || defined(_WINCE_)
++ res = TNFTL_AREAReadSector( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[nDrvNo],
++ LBA, nSecSize, nReadBuffer );
++ #else
++ res = TNFTL_AREAReadSector( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo,
++ &gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->MultiHDArea[0],
++ LBA, nSecSize, nReadBuffer );
++ #endif
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++
++ res = NAND_IO_LBA_ReadSector( gLBA_DevInfo,
++ NAND_LBA_MULTI_HIDDEN_AREA_0,
++ LBA, nSecSize, nReadBuffer);
++ #endif
++ }
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ PRINTF( " FAIL %08X", res );
++ #endif
++
++ return -1;
++ }
++
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/******************************************************************************
++*
++* int NAND_HDWriteSector
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_HDWriteSector( int nDrvNo, U32 LBA, U32 nSecSize, void* nWriteBuffer )
++{
++ #ifdef NAND_INCLUDE
++ TNFTL_ERROR res = SUCCESS;
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ #if defined(_LINUX_) || defined(_WINCE_)
++ res = TNFTL_AREAWriteSector( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[nDrvNo],
++ LBA, nSecSize, nWriteBuffer );
++ #else
++ res = TNFTL_AREAWriteSector( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo,
++ &gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->MultiHDArea[0],
++ LBA, nSecSize, nWriteBuffer );
++ #endif
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ res = NAND_IO_LBA_WriteSector( gLBA_DevInfo,
++ NAND_LBA_MULTI_HIDDEN_AREA_0,
++ LBA, nSecSize, nWriteBuffer );
++ #endif
++ }
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ PRINTF( "\nFAIL : %08X ", res );
++ #endif
++
++ return -1;
++ }
++
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/******************************************************************************
++*
++* int NAND_HDReadPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_HDReadPage( U32 nHDPageAddr, U32 nPageSize, void* nReadBuffer )
++{
++ #ifdef NAND_INCLUDE
++ TNFTL_ERROR res = SUCCESS;
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ unsigned long int count;
++ HwTCNT4 = 0;
++ #endif
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ PRINTF( "\n\nNAND_HDReadPage( %08d, %08d ) -----", nHDPageAddr, nPageSize );
++ #endif
++ //==============================================================================
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ res = TNFTL_AREAReadSector( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->HDArea,
++ nHDPageAddr, nPageSize, nReadBuffer );
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ res = NAND_IO_LBA_ReadSector( gLBA_DevInfo,
++ NAND_LBA_HIDDEN_AREA,
++ nHDPageAddr, nPageSize, nReadBuffer );
++ #endif
++ }
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ count = HwTCNT4;
++ PRINTF( "\n[NAND_HDReadPage %08d - %05d ] ( %d uS ) ---- ",
++ LBA,
++ nSecSize,
++ (count*267)/100);
++ #endif
++ //==============================================================================
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ PRINTF( "\nFAIL : %08X ", res );
++ #endif
++
++ return -1;
++ }
++
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/******************************************************************************
++*
++* int NAND_HDWritePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_HDWritePage( U32 nHDPageAddr, U32 nPageSize, void* nWriteBuffer )
++{
++ #ifdef NAND_INCLUDE
++ TNFTL_ERROR res = SUCCESS;
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ unsigned long int count;
++ HwTCNT4 = 0;
++ #endif
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ PRINTF( "\n\nNAND_HDWritePage( %08d, %08d ) ----", nHDPageAddr, nPageSize );
++ #endif
++ //==============================================================================
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ res = TNFTL_AREAWriteSector( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->HDArea,
++ nHDPageAddr, nPageSize, nWriteBuffer );
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ res = NAND_IO_LBA_WriteSector( gLBA_DevInfo,
++ NAND_LBA_HIDDEN_AREA,
++ nHDPageAddr, nPageSize, nWriteBuffer );
++ #endif
++ }
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ count = HwTCNT4;
++ PRINTF( "\n[NAND_HDWritePage %08d - %05d ] ( %d uS ) ---- ",
++ LBA,
++ nSecSize,
++ (count*267)/100);
++ #endif
++ //==============================================================================
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ PRINTF( "\nFAIL : %08X ", res );
++ #endif
++
++ return -1;
++ }
++
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int NAND_PhyReadPage( U32 nBlkAddr, U16 nPageAddr, U16 nCSorder, void* nReadBuffer );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* nBlkAddr =
++* nCSorder =
++* nPageAddr =
++* nReadBuffer =
++*
++* OUTPUT: int - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++int NAND_PhyReadPage( U32 nBlkAddr, U16 nPageAddr, U16 nCSorder, void* nReadBuffer )
++{
++ TNFTL_ERROR res = SUCCESS;
++ #if defined(NAND_INCLUDE)
++
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ PRINTF( "\nNAND_PhyReadPage( %08d, %08d ) ----", nBlkAddr, nPageAddr );
++ #endif
++
++ #if defined( TNFTL_V5_INCLUDE ) || defined(TNFTL_V6_INCLUDE)
++ res = TNFTL_IOReadPhyPage( gNAND_DrvInfo[0].NFTLDrvInfo,
++ nBlkAddr, nPageAddr,
++ nCSorder, nReadBuffer );
++ #endif
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ PRINTF( "\nFAIL : %08X ", res );
++ #endif
++
++ return -1;
++ }
++ #endif
++
++ return 0;
++}
++
++int NAND_MTD_Init( U32* rMTDStBlk, U32* rMTDEdBlk )
++{
++ unsigned int i;
++ unsigned int nBlockPageAddr;
++ unsigned int nMTDStBlk, nMTDEdBlk;
++ NAND_IO_DEVINFO sDevInfo;
++ NAND_IO_DEVINFO *nDevInfo;
++
++ NAND_IO_GetDeviceInfo( 0, &sDevInfo);
++ nDevInfo = &sDevInfo;
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->IoStatus == DISABLE )
++ return -1;
++
++ nMTDStBlk = nDevInfo->Feature.PBpV - gNAND_DrvInfo[0].NFTLDrvInfo->ROAreaBlkNum;
++ nMTDEdBlk = nDevInfo->Feature.PBpV - 1;
++
++ for ( i = nMTDStBlk; i < nMTDEdBlk; ++i )
++ {
++ nBlockPageAddr = i << nDevInfo->ShiftPpB;
++
++ NAND_IO_EraseBlock( nDevInfo, nBlockPageAddr, INTER_LEAVE_OFF );
++ }
++
++ *rMTDStBlk = nMTDStBlk;
++ *rMTDEdBlk = nMTDEdBlk;
++
++ return 0;
++}
++
++int NAND_MTD_WritePage( U32 nPageAddr, U8* nPageBuffer )
++{
++ unsigned char *nSpareBuffer;
++ NAND_IO_DEVINFO *nDevInfo;
++ NAND_IO_ERROR res;
++
++ nDevInfo = &gNAND_DrvInfo[0].NFTLDrvInfo->MediaDevInfo[0];
++
++ nSpareBuffer = (unsigned char *)nPageBuffer;
++ //nSpareBuffer += nDevInfo->Feature.PageSize;
++ nSpareBuffer += 2048;
++
++ res = NAND_IO_WritePageMTD( nDevInfo,
++ nPageAddr, 0, 4/*nDevInfo->PPages*/,
++ nPageBuffer,
++ nSpareBuffer, ECC_ON );
++ return res;
++}
++
++int NAND_MTD_ReadPage( U32 nPageAddr, U8* nPageBuffer )
++{
++ unsigned char *nSpareBuffer;
++ NAND_IO_DEVINFO *nDevInfo;
++ NAND_IO_ERROR res;
++
++ nDevInfo = &gNAND_DrvInfo[0].NFTLDrvInfo->MediaDevInfo[0];
++
++ nSpareBuffer = (unsigned char *)nPageBuffer;
++ //nSpareBuffer += nDevInfo->Feature.PageSize;
++ nSpareBuffer += 2048;
++
++ res = NAND_IO_ReadPageMTD( nDevInfo,
++ nPageAddr, 0, 4/*nDevInfo->PPages*/,
++ nPageBuffer,
++ nSpareBuffer, ECC_ON );
++ return res;
++}
++
++
++/******************************************************************************
++*
++* int NAND_Ioctl
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_Ioctl( int function, void *param )
++{
++ #if defined(_LINUX_) || defined(_WINCE_) || defined (NAND_LBA_INCLUDE)
++ unsigned int i = 0;
++ #endif
++
++ switch( function )
++ {
++ case DEV_INITIALIZE:
++ {
++ NAND_Init();
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ if ( gNAND_HiddenInfoLoadFlag == DISABLE )
++ NAND_InitHiddenInfo();
++ else
++ TNFTL_SetMultiHiddenNums( NAND_DRV_0, (U16)gTNFTL_HiddenInfo[NAND_DRV_0].MultiHiddenAreaNum );
++ #else
++ NAND_InitHiddenInfo();
++ #endif
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ #ifdef BRWS_STR_NAND_INCLUDE
++ TNFTL_AREASetTotalSectorSize( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->HDArea,
++ gTNFTL_HiddenInfo[NAND_DRV_0].HiddenPageSize
++ + BRWS_NAME_AREA_SIZE
++ #ifndef NU_FILE_INCLUDE
++ #ifdef AUDIOUI_INCLUDE
++ + AUI_HD_OCCPAGE
++ #endif
++ #endif
++ );
++ #else
++ TNFTL_AREASetTotalSectorSize( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->HDArea,
++ gTNFTL_HiddenInfo[NAND_DRV_0].HiddenPageSize
++ #ifndef NU_FILE_INCLUDE
++ #ifdef AUDIOUI_INCLUDE
++ + AUI_HD_OCCPAGE
++ #endif
++ #endif
++ );
++ #endif
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ for ( i = 0; i < gTNFTL_HiddenInfo[NAND_DRV_0].MultiHiddenAreaNum; ++i )
++ {
++ TNFTL_AREASetTotalSectorSize( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[i],
++ gTNFTL_HiddenInfo[NAND_DRV_0].MultiHiddenSize[i] );
++ }
++ #else
++ TNFTL_AREASetTotalSectorSize( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0],
++ gTNFTL_HiddenInfo[NAND_DRV_0].MultiHiddenSize[0] );
++
++ #endif
++
++ gNAND_DrvInfo[0].DrvStatus = DISABLE;
++
++
++ if ( NAND_InitDrive(0) != SUCCESS )
++ return EINITFAIL;
++
++ TNFTL_AREAGetTotalSecAndCHS( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->DTArea,
++ (U32 *)&gNAND_DrvInfo[0].TotalDiskSector,
++ &gNAND_DrvInfo[0].Cylinder,
++ &gNAND_DrvInfo[0].Head,
++ &gNAND_DrvInfo[0].Sector );
++
++ gNAND_DrvInfo[0].DrvStatus = ENABLE;
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++
++ #ifdef BRWS_STR_NAND_INCLUDE
++ gLBA_DevInfo->LBAInfo.HDAreaSectorSize = ( gTNFTL_HiddenInfo[NAND_DRV_0].HiddenPageSize
++ + BRWS_NAME_AREA_SIZE
++ #ifndef NU_FILE_INCLUDE
++ #ifdef AUDIOUI_INCLUDE
++ + AUI_HD_OCCPAGE
++ #endif
++ #endif
++ );
++ #else
++ gLBA_DevInfo->LBAInfo.HDAreaSectorSize = ( gTNFTL_HiddenInfo[NAND_DRV_0].HiddenPageSize
++ #ifndef NU_FILE_INCLUDE
++ #ifdef AUDIOUI_INCLUDE
++ + AUI_HD_OCCPAGE
++ #endif
++ #endif
++ );
++ #endif
++
++ gLBA_DevInfo->LBAInfo.MHDAreaNums = TNFTL_MULTI_HIDDEN_AREA_NUM;
++
++ #ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++ for ( i = 0; i < TNFTL_MULTI_HIDDEN_AREA_NUM; ++i )
++ gLBA_DevInfo->LBAInfo.MHDAreaSectorSize[i] = gTNFTL_HiddenInfo[NAND_DRV_0].MultiHiddenSize[i];
++ #endif
++
++ gNAND_DrvInfo[0].DrvStatus = DISABLE;
++
++ if ( NAND_InitDrive(0) != SUCCESS )
++ return EINITFAIL;
++
++ gNAND_DrvInfo[0].DrvStatus = ENABLE;
++ #endif
++ }
++ }
++ break;
++
++ case DEV_GET_DISKINFO:
++ {
++ ioctl_diskinfo_t *info = (ioctl_diskinfo_t *) param;
++
++ #ifdef NU_FILE_INCLUDE
++ gFormatType = TC_LOWLEVEL_NO;
++ #endif
++ info->cylinder = gNAND_DrvInfo[0].Cylinder;
++ info->head = gNAND_DrvInfo[0].Head;
++ info->sector = gNAND_DrvInfo[0].Sector;
++ info->sector_size = 512;
++ info->Total_sectors = gNAND_DrvInfo[0].TotalDiskSector;
++ }
++ break;
++
++ case DEV_FORMAT_DISK:
++ {
++ unsigned short mode = *((unsigned short *)param);
++
++ #ifdef NU_FILE_INCLUDE
++ gFormatType = TC_LOWLEVEL_NO;
++ #endif
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ TNFTL_AREAFormat( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->DTArea,
++ mode );
++ }
++ #ifdef NAND_LBA_INCLUDE
++ else
++ {
++ // NAND_IO_LBA_AREAClear( gLBA_DevInfo, NAND_LBA_DATA_AREA );
++ }
++ #endif
++
++ return NAND_InitDrive(0);
++ }
++ break;
++
++ case DEV_ERASE_INIT:
++ {
++ ioctl_diskeraseinit_t *erase = (ioctl_diskeraseinit_t *) param;
++ erase = erase;
++ }
++ break;
++
++ case DEV_ERASE_BLOCK:
++ {
++ ioctl_diskerase_t *erase = (ioctl_diskerase_t *) param;
++ erase = erase;
++ }
++ break;
++
++ case DEV_WRITEBACK_ON_IDLE:
++ {
++
++ }
++ break;
++
++ case DEV_ERASE_CLOSE:
++ {
++
++ }
++ break;
++
++ case DEV_HIDDEN_READ_PAGE_4:
++ {
++ ioctl_diskhdread4_t *hd_r = (ioctl_diskhdread4_t *) param;
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ TNFTL_AREAReadSectorBy4Byte( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->HDArea,
++ (U32)hd_r->start_page,
++ (U16)hd_r->page_offset,
++ (U16)hd_r->read_size,
++ hd_r->buff );
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ NAND_IO_LBA_ReadSectorBy4Byte( gLBA_DevInfo,
++ NAND_LBA_VFP,
++ (U32)hd_r->start_page,
++ (U16)hd_r->page_offset,
++ (U16)hd_r->read_size,
++ hd_r->buff );
++ #endif
++ }
++
++ }
++ break;
++ case DEV_SET_POWER:
++ {
++ #ifdef NAND_LBA_INCLUDE
++ unsigned short mode = *((unsigned short *)param);
++ #endif
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ // NOP
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++
++ if ( mode == DISK_STATE_STANDBY )
++ {
++ NAND_IO_LBA_PowerSaveMode( gLBA_DevInfo, DISABLE );
++ }
++ else if ( mode == DISK_STATE_IDLE )
++ {
++ NAND_IO_LBA_PowerSaveMode( gLBA_DevInfo, ENABLE );
++ }
++ #endif
++ }
++ }
++ break;
++ case DEV_GET_MAX_SECTOR_PER_BLOCK:
++ {
++ unsigned short *value = (unsigned short *)param;
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ if ( gNAND_DrvInfo[0].DrvStatus == ENABLE )
++ *value = ( gNAND_DrvInfo[0].NFTLDrvInfo->PpB << gNAND_DrvInfo[0].NFTLDrvInfo->ShiftPPages );
++ else
++ *value = TNFTL_MAX_SUPPORT_NAND_IO_SECTOR_SIZE_PER_1PAGE;
++ }
++ else
++ {
++ *value = 2048; // PpB: 128 * PPage: 16
++ }
++ }
++ break;
++
++ case DEV_TELL_DATASTARTSECTOR:
++ {
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ TNFTL_WCacheSetDataStartSector( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->DTArea,
++ *(unsigned int*)param );
++ }
++
++ break;
++ }
++
++ case DEV_CHECK_CRC_NANDBOOT_IMAGE_ROM:
++ #if defined (BOOTCRCCHEK)
++ {
++ BootCRC *pbootcrc;
++
++ pbootcrc = (BootCRC*)param;
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ return TNFTL_NBGetCRCValueOfImageFile(gNAND_DrvInfo[0].NFTLDrvInfo, &pbootcrc->crc128kchk, &pbootcrc->crcfullchk, &pbootcrc->bootfilesize);
++ }
++ else
++ return 0;
++ }
++ #else
++ {
++ unsigned int nOrgCRCcode1;
++ unsigned int nOrgCRCcode2;
++ unsigned int nRomFileSize;
++ unsigned int rRstCRCcode1;
++ unsigned int rRstCRCcode2;
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ return TNFTL_NBGetCRCOfImageFile( gNAND_DrvInfo[0].NFTLDrvInfo, 1,
++ &nOrgCRCcode1, &nOrgCRCcode2, &nRomFileSize,
++ &rRstCRCcode1, &rRstCRCcode2 );
++ }
++ else
++ return 0;
++ }
++ #endif
++ break;
++ #ifdef TNFTL_V4_INCLUDE
++ case DEV_FORCE_FLUSH_CACHE_DATA:
++ {
++ return TNFTL_WCacheFourceFlushCache_DATA( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->DTArea );
++ }
++ break;
++ #endif
++ #if defined( TNFTL_V5_INCLUDE ) || defined(TNFTL_V6_INCLUDE)
++ case DEV_SET_ALIGEN_CACHE:
++ {
++ unsigned short mode = *((unsigned short *)param);
++ return TNFTL_SetUseAlignCacheMode( gNAND_DrvInfo[0].NFTLDrvInfo, mode );
++ }
++ break;
++ #endif
++ case DEV_GET_WRITE_PROTECT:
++ return 0;
++ break;
++ case DEV_GET_INSERTED:
++ return 1;
++ #ifdef NU_FILE_INCLUDE
++ case DEV_GET_HIDDEN_SIZE:
++ if (gNAND_DrvInfo[0].DrvStatus == ENABLE)
++ *(int *)param = NAND_HIDDEN_DEFAULT_TOTAL_PAGESIZE;
++ else
++ *(int *)param = -1;
++ break;
++ #endif
++ case DEV_GET_INITED:
++ return 1;
++ case DEV_GET_PLAYABLE_STATUS:
++ return 1;
++ default:
++ return ENOTSUPPORT;
++ }
++ #endif
++ return 0; /* SUCCESS */
++}
++
++/******************************************************************************
++*
++* int NAND_HDIoctl
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_HDIoctl( int function, void *param )
++{
++ #if defined(_LINUX_) || defined(_WINCE_)
++ unsigned int i;
++ #endif
++
++ switch( function )
++ {
++ case DEV_INITIALIZE:
++ {
++ NAND_Init();
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ if ( gNAND_HiddenInfoLoadFlag == DISABLE )
++ NAND_InitHiddenInfo();
++ else
++ TNFTL_SetMultiHiddenNums( NAND_DRV_0, (U16)gTNFTL_HiddenInfo[NAND_DRV_0].MultiHiddenAreaNum );
++ #endif
++
++ #ifdef BRWS_STR_NAND_INCLUDE
++ TNFTL_AREASetTotalSectorSize( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->HDArea,
++ gTNFTL_HiddenInfo[NAND_DRV_0].HiddenPageSize
++ + BRWS_NAME_AREA_SIZE
++ #ifndef NU_FILE_INCLUDE
++ #ifdef AUDIOUI_INCLUDE
++ + AUI_HD_OCCPAGE
++ #endif
++ #endif
++ );
++ #else
++ TNFTL_AREASetTotalSectorSize( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->HDArea,
++ gTNFTL_HiddenInfo[NAND_DRV_0].HiddenPageSize
++ #ifndef NU_FILE_INCLUDE
++ #ifdef AUDIOUI_INCLUDE
++ + AUI_HD_OCCPAGE
++ #endif
++ #endif
++ );
++ #endif
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ for ( i = 0; i < gTNFTL_HiddenInfo[NAND_DRV_0].MultiHiddenAreaNum; ++i )
++ {
++ TNFTL_AREASetTotalSectorSize( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[i],
++ gTNFTL_HiddenInfo[NAND_DRV_0].MultiHiddenSize[i] );
++ }
++ #else
++ TNFTL_AREASetTotalSectorSize( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0],
++ NAND_HIDDEN_DRIVE_DEFAULT_TOTAL_SECTOR_SIZE );
++ #endif
++
++ gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0].DrvStatus = DISABLE;
++
++ if ( NAND_InitDrive(0) != SUCCESS )
++ return EINITFAIL;
++
++ TNFTL_AREAGetTotalSecAndCHS( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0],
++ (U32 *)&gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0].TotalDiskSector,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0].Cylinder,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0].Head,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0].Sector );
++
++ gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0].DrvStatus = ENABLE;
++ }
++ break;
++
++ case DEV_GET_DISKINFO:
++ {
++ ioctl_diskinfo_t *info = (ioctl_diskinfo_t *) param;
++
++ info->cylinder = gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0].Cylinder;
++ info->head = gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0].Head;
++ info->sector = gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0].Sector;
++ info->sector_size = 512;
++ }
++ break;
++
++ case DEV_FORMAT_DISK:
++ {
++ unsigned short mode = *((unsigned short *)param);
++
++ TNFTL_AREAFormat( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0],
++ mode );
++
++ return NAND_InitDrive(0);
++ }
++ break;
++
++ case DEV_ERASE_INIT:
++ {
++ ioctl_diskeraseinit_t *erase = (ioctl_diskeraseinit_t *) param;
++ erase = erase;
++ }
++ break;
++
++ case DEV_ERASE_BLOCK:
++ {
++ ioctl_diskerase_t *erase = (ioctl_diskerase_t *) param;
++ erase = erase;
++ }
++ break;
++
++ case DEV_WRITEBACK_ON_IDLE:
++ {
++
++ }
++ break;
++
++ case DEV_ERASE_CLOSE:
++ {
++
++ }
++ break;
++
++ case DEV_HIDDEN_READ_PAGE_4:
++ {
++
++ }
++ break;
++
++ case DEV_GET_MAX_SECTOR_PER_BLOCK:
++ {
++ unsigned short *value = (unsigned short *)param;
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0].DrvStatus == ENABLE )
++ {
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0].TotalDiskSector >
++ (U32)( gNAND_DrvInfo[0].NFTLDrvInfo->PpB << gNAND_DrvInfo[0].NFTLDrvInfo->ShiftPPages ) * 2 )
++ *value = ( gNAND_DrvInfo[0].NFTLDrvInfo->PpB << gNAND_DrvInfo[0].NFTLDrvInfo->ShiftPPages );
++ else
++ *value = TNFTL_MAX_SUPPORT_NAND_IO_SECTOR_SIZE_PER_1PAGE;
++ }
++ else
++ *value = TNFTL_MAX_SUPPORT_NAND_IO_SECTOR_SIZE_PER_1PAGE;
++ }
++ break;
++
++ case DEV_TELL_DATASTARTSECTOR:
++ {
++ TNFTL_WCacheSetDataStartSector( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->MultiHDArea[0],
++ *(unsigned int*)param );
++ break;
++ }
++
++ case DEV_GET_WRITE_PROTECT:
++ return 0;
++ break;
++ case DEV_GET_INSERTED:
++ return 1;
++ case DEV_GET_INITED:
++ return 1;
++ case DEV_GET_PLAYABLE_STATUS:
++ return 1;
++ default:
++ return ENOTSUPPORT;
++ }
++
++ return 0; /* SUCCESS */
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* int NAND_ReadMultiSectorStart( U32 LBA, U16 nSecSize );
++*
++* DESCRIPTION :
++* INPUT:
++* LBA =
++* nSecSize =
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++int NAND_ReadMultiSectorStart( U32 LBA, U32 nSecSize )
++{
++ #ifdef NAND_INCLUDE
++ LBA = 0;
++ nSecSize = 0;
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* int NAND_ReadMultiSectorStop( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++int NAND_ReadMultiSectorStop( void )
++{
++ #ifdef NAND_INCLUDE
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* int NAND_WriteMultiSectorStart( U32 LBA, U16 nSecSize );
++*
++* DESCRIPTION :
++* INPUT:
++* LBA =
++* nSecSize =
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++int NAND_WriteMultiSectorStart( U32 LBA, U32 nSecSize )
++{
++ #ifdef NAND_INCLUDE
++ LBA = 0;
++ nSecSize = 0;
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* int NAND_WriteMultiSectorStop( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++int NAND_WriteMultiSectorStop( void )
++{
++ #ifdef NAND_INCLUDE
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* int NAND_HDClearPages( U32 nHDStPageAddr, U32 nHDEdPageAddr );
++*
++* DESCRIPTION :
++* INPUT:
++* nHDEdPageAddr =
++* nHDStPageAddr =
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++int NAND_HDClearPages( U32 nHDStPageAddr, U32 nHDEdPageAddr )
++{
++ #ifdef NAND_INCLUDE
++ nHDStPageAddr = 0;
++ nHDEdPageAddr = 0;
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/******************************************************************************
++*
++* U16 NAND_GetSerialNumber
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++U16 NAND_GetSerialNumber( U8* rSerialNumber, U16 nSize )
++{
++ #ifdef NAND_INCLUDE
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ return TNFTL_GetSerialNumber( gNAND_DrvInfo[0].NFTLDrvInfo, rSerialNumber, nSize );
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ return NAND_IO_LBA_GetSerialNumber( gLBA_DevInfo, gNAND_PageBuffer, rSerialNumber, nSize );
++ #else
++ return 0;
++ #endif
++ }
++ #else
++ return 0;
++ #endif
++}
++
++/******************************************************************************
++*
++* U16 NAND_GetUniqueID
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++U16 NAND_GetUniqueID( U8* rSerialNumber, U16 nSize )
++{
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ #if defined(NAND_INCLUDE) && !defined(_SDRAMONLY1_)
++ unsigned int uiIDSize;
++
++ uiIDSize = ( nSize < gNAND_DrvInfo[0].NFTLDrvInfo->MediaSizeOfUniqueID ) ? nSize : gNAND_DrvInfo[0].NFTLDrvInfo->MediaSizeOfUniqueID;
++ memcpy((void*)rSerialNumber, (void*)gNAND_DrvInfo[0].NFTLDrvInfo->MediaUniqueID, uiIDSize);
++
++ return (U16)uiIDSize;
++ #else
++ return 0;
++ #endif
++ }
++ else
++ return 0;
++}
++
++/******************************************************************************
++*
++* TNFTL_ERROR NAND_SetUartDebug
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++TNFTL_ERROR NAND_SetUartDebug( unsigned int on_off )
++{
++ gNAND_UARTDebugFlag = (U8)on_off;
++
++ return (TNFTL_ERROR)SUCCESS;
++}
++
++#ifdef NU_FILE_INCLUDE
++/************************************************************************
++* FUNCTION
++*
++* NAND_IO_Open
++*
++* DESCRIPTION
++*
++* This function prepares the NAND Flash for usage by allocating the
++* pages necessary for usage.
++*
++* INPUTS
++*
++* driveno The number assigned to the NAND Flash.
++*
++* OUTPUTS
++*
++* YES Successful Completion.
++* NO Couldn't allocate all of the
++* pages.
++*
++*************************************************************************/
++INT NAND_IO_Open(UINT16 driveno)
++{
++ NU_Obtain_Semaphore(&CAPP_SEM, NU_SUSPEND);
++ NAND_Ioctl(DEV_INITIALIZE, NULL);
++ NU_Release_Semaphore(&CAPP_SEM);
++ return(YES);
++}
++
++#ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++/**************************************************************************
++* FUNCTION NAME :
++* INT NAND_HD_IO_Open(UINT16 driveno);
++*
++* DESCRIPTION :
++* INPUT:
++* driveno =
++*
++* OUTPUT: INT - Return Type
++* =
++* REMARK :
++**************************************************************************/
++INT NAND_HD_IO_Open(UINT16 driveno)
++{
++ NU_Obtain_Semaphore(&CAPP_SEM, NU_SUSPEND);
++ NAND_HDIoctl(DEV_INITIALIZE, NULL);
++ NU_Release_Semaphore(&CAPP_SEM);
++ return(YES);
++}
++#endif //INTERNAL_HIDDEN_STORAGE_INCLUDE
++
++/************************************************************************
++* FUNCTION
++*
++* NAND_IO_RAW_Open
++*
++* DESCRIPTION
++*
++* This function doesn't do anything for the NAND Flash. It is
++* included for devtable consistency.
++*
++* INPUTS
++*
++* None.
++*
++* OUTPUTS
++*
++* None.
++*
++*************************************************************************/
++INT NAND_IO_RAW_Open(UINT16 driveno)
++{
++ return(NO);
++}
++
++#ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++/**************************************************************************
++* FUNCTION NAME :
++* INT NAND_HD_IO_RAW_Open(UINT16 driveno);
++*
++* DESCRIPTION :
++* INPUT:
++* driveno =
++*
++* OUTPUT: INT - Return Type
++* =
++* REMARK :
++**************************************************************************/
++INT NAND_HD_IO_RAW_Open(UINT16 driveno)
++{
++ return(NO);
++}
++#endif //INTERNAL_HIDDEN_STORAGE_INCLUDE
++
++/************************************************************************
++* FUNCTION
++*
++* NAND_IO_Close
++*
++* DESCRIPTION
++*
++* This function deallocates all of the pages associated with the
++* NAND Flash. The actual code here is commented out since we
++* probably don't want to loose the data on a close.
++*
++* INPUTS
++*
++* driveno The number assigned to the NAND Flash.
++*
++* OUTPUTS
++*
++* YES Successful Completion.
++* NO Couldn't allocate all of the
++* pages.
++*
++*************************************************************************/
++INT NAND_IO_Close(UINT16 driveno)
++{
++ return(YES);
++}
++
++#ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++/**************************************************************************
++* FUNCTION NAME :
++* INT NAND_HD_IO_Close(UINT16 driveno) ;
++*
++* DESCRIPTION :
++* INPUT:
++* driveno =
++*
++* OUTPUT: INT - Return Type
++* =
++* REMARK :
++**************************************************************************/
++INT NAND_HD_IO_Close(UINT16 driveno)
++{
++ return(YES);
++}
++#endif //INTERNAL_HIDDEN_STORAGE_INCLUDE
++
++/************************************************************************
++* FUNCTION
++*
++* NAND_IO_ReadWrite
++*
++* DESCRIPTION
++*
++* This function reads or writes data from and to the NAND Flash
++* based on the 'reading' parameter.
++*
++* INPUTS
++*
++* driveno The number assigned to the
++* RAM Disk (not used)
++* block The block number to read or
++* write
++* buffer Pointer to the data to be
++* placed from a read or
++* stored on a write
++* count Number of bytes to be read
++* or written
++* reading Indicates whether or not we
++* are reading or writing
++*
++* OUTPUTS
++*
++* YES Successful Completion.
++* NO Block number is out of range.
++*
++*************************************************************************/
++INT NAND_IO_ReadWrite(UINT16 driveno, UINT32 block, VOID *buffer, UINT16 count, INT reading)
++{
++ int result;
++
++ NU_Obtain_Semaphore(&CAPP_SEM, NU_SUSPEND);
++
++ if(reading)
++ result = NAND_ReadSector(driveno, block, count, buffer);
++ else
++ result = NAND_WriteSector(driveno, block, count, buffer);
++
++ NU_Release_Semaphore(&CAPP_SEM);
++
++ if(!result)
++ return (YES);
++ else
++ return (NO);
++}
++
++#ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++/**************************************************************************
++* FUNCTION NAME :
++* INT NAND_HD_IO_ReadWrite(UINT16 driveno, UINT32 block, VOID *buffer, UINT16 count, INT reading) ;
++*
++* DESCRIPTION :
++* INPUT:
++* block =
++* buffer =
++* count =
++* driveno =
++* reading =
++*
++* OUTPUT: INT - Return Type
++* =
++* REMARK :
++**************************************************************************/
++INT NAND_HD_IO_ReadWrite(UINT16 driveno, UINT32 block, VOID *buffer, UINT16 count, INT reading)
++{
++ int result;
++
++ NU_Obtain_Semaphore(&CAPP_SEM, NU_SUSPEND);
++
++ driveno -= INTERNAL_HIDDEN_STORAGE_START_NO;
++ if(reading)
++ result = NAND_HDReadSector(driveno, block, count, buffer);
++ else
++ result = NAND_HDWriteSector(driveno, block, count, buffer);
++
++ NU_Release_Semaphore(&CAPP_SEM);
++
++ if(!result)
++ return (YES);
++ else
++ return (NO);
++}
++#endif //INTERNAL_HIDDEN_STORAGE_INCLUDE
++
++/************************************************************************
++* FUNCTION
++*
++* NAND_IO_Ioctl
++*
++* DESCRIPTION
++*
++* This function doesn't do anything for the NAND Flash. It is
++* included for devtable consistency.
++*
++* INPUTS
++*
++* None.
++*
++* OUTPUTS
++*
++* None.
++*
++*************************************************************************/
++INT NAND_IO_Ioctl(UINT16 driveno, UINT16 command, VOID *buffer)
++{
++ int result;
++
++ NU_Obtain_Semaphore(&CAPP_SEM, NU_SUSPEND);
++ result = NAND_Ioctl(command, buffer);
++ NU_Release_Semaphore(&CAPP_SEM);
++
++ return result;
++}
++
++#ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++/**************************************************************************
++* FUNCTION NAME :
++* INT NAND_HD_IO_Ioctl(UINT16 driveno, UINT16 command, VOID *buffer);
++*
++* DESCRIPTION :
++* INPUT:
++* buffer =
++* command =
++* driveno =
++*
++* OUTPUT: INT - Return Type
++* =
++* REMARK :
++**************************************************************************/
++INT NAND_HD_IO_Ioctl(UINT16 driveno, UINT16 command, VOID *buffer)
++{
++ int result;
++
++ NU_Obtain_Semaphore(&CAPP_SEM, NU_SUSPEND);
++ result = NAND_HDIoctl(command, buffer);
++ NU_Release_Semaphore(&CAPP_SEM);
++
++ return result;
++}
++#endif //INTERNAL_HIDDEN_STORAGE_INCLUDE
++
++#endif // NU_FILE_INCLUDE
++
++//#endif // WITHOUT_FILESYSTEM
++
++/* end of file */
+diff --git a/drivers/block/tcc/nand_drv_v7.c b/drivers/block/tcc/nand_drv_v7.c
+new file mode 100644
+index 0000000..8d97229
+--- /dev/null
++++ b/drivers/block/tcc/nand_drv_v7.c
+@@ -0,0 +1,2457 @@
++/****************************************************************************
++ * FileName : nand_drv_v7.c
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#if defined(_LINUX_)
++#include "common.h"
++#if defined(USE_V_ADDRESS)
++#include <linux/kernel.h>
++#include <linux/string.h>
++#endif
++#endif
++
++#if defined(_LINUX_) || defined(_WINCE_)
++//#include "IO_TCC7XX.h"
++#include "nand_drv.h"
++//#include "Disk.h"
++#include "TC_File.h"
++#else
++#include "Globals.h"
++#include "IO_TCCXXX.h"
++#include "nand_drv.h"
++#include "disk.h"
++#include "FileBufferCtrl.h"
++#include "Assert.h"
++#endif
++
++#ifdef _WINCE_
++#include "bsp.h"
++#include "args.h"
++#endif
++
++#if defined(__NUCLEUS_KERNEL__)
++#include "TC_Kernel.h"
++#endif
++
++#ifdef AUDIOUI_INCLUDE
++#include "AudioUI.H"
++#endif
++
++//#define NAND_DRV_PORT_DEBUG
++
++//#define TNFTL_READ_CACHE_INCLUDE
++#define TNFTL_ALIGN_CACHE_INCLUDE
++
++#ifdef BOOTCRCCHEK
++ typedef struct _BootCRC
++ {
++ unsigned int crc128kchk;
++ unsigned int crcfullchk;
++ unsigned int bootfilesize;
++ }BootCRC;
++#endif
++
++#ifndef WITHOUT_FILESYSTEM
++
++#if defined( FWDN_DOWNLOADER_INCLUDE )
++const unsigned char NANDDRV_Library_Version[] = { "SIGBYAHONG_NANDDRV_FWDN_V007014" };
++#elif defined(TCC92XX)
++const unsigned char NANDDRV_Library_Version[] = { "SIGBYAHONG_NANDDRV_TCC92XX_V007014" };
++#elif defined(TCC89XX)
++const unsigned char NANDDRV_Library_Version[] = { "SIGBYAHONG_NANDDRV_TCC89XX_V007014" };
++#endif
++
++//=============================================================================
++//*
++//*
++//* [ DEFINITIONS ]
++//*
++//*
++//=============================================================================
++#if defined(_WINCE_)
++#define TNFTL_EXTENDED_PARTITION_MAX_NUM 4
++#define TNFTL_EXTENDED_PARTITION_NUM 2
++
++#define NAND_HIDDEN_0_PAGESIZE (33/*MB*/*1024*2)
++#define NAND_HIDDEN_1_PAGESIZE (3/*MB*/*1024*2) // for LOGO
++#define NAND_HIDDEN_2_PAGESIZE (2/*MB*/*1024*2)
++#define NAND_HIDDEN_3_PAGESIZE (3/*MB*/*1024*2)
++
++#define NAND_RO_AREA_SIZE_MB 0
++#elif defined(_LINUX_)
++#define TNFTL_EXTENDED_PARTITION_MAX_NUM 4
++#define TNFTL_EXTENDED_PARTITION_NUM 1
++
++#define NAND_HIDDEN_0_PAGESIZE (32*1024*2)
++#define NAND_HIDDEN_1_PAGESIZE (1*1024*2)
++#define NAND_HIDDEN_2_PAGESIZE (2*1024*2)
++#define NAND_HIDDEN_3_PAGESIZE (3*1024*2)
++
++#define NAND_RO_AREA_SIZE_MB 0 // MTD Area
++#else
++#ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++#define TNFTL_EXTENDED_PARTITION_MAX_NUM 1
++#define TNFTL_EXTENDED_PARTITION_NUM 1
++
++#define NAND_HIDDEN_0_PAGESIZE (4096)
++#else
++#define TNFTL_EXTENDED_PARTITION_MAX_NUM 1
++#define TNFTL_EXTENDED_PARTITION_NUM 0
++
++#define NAND_RO_AREA_SIZE_MB 0
++#endif
++#endif
++
++//=============================================================================
++//*
++//*
++//* [ CONST DATA DEFINE ]
++//*
++//*
++//=============================================================================
++
++//=============================================================================
++//*
++//*
++//* [ GLOBAL VARIABLE DEFINE ]
++//*
++//*
++//=============================================================================
++NAND_DRVINFO gNAND_DrvInfo[MAX_NAND_DRIVE];
++TNFTL_EXT_PART_INFO gTNFTL_ExtPartitionInfo[MAX_NAND_DRIVE];
++TNFTL_DRVINFO gTNFTL_DrvInfo[MAX_NAND_DRIVE];
++
++TNFTL_RW_AREA gTNFTL_ExtPartitionDrvInfo[MAX_NAND_DRIVE][TNFTL_EXTENDED_PARTITION_MAX_NUM];
++
++TNFTL_LPT_BLOCK gTNFTL_PriPartitionLPTBlk[MAX_NAND_DRIVE][TNFTL_LPT_BLK_NUM_For_PRIMARY_PARTITION];
++TNFTL_LPT_BLOCK gTNFTL_ExtPartitionLPTBlk[MAX_NAND_DRIVE][TNFTL_EXTENDED_PARTITION_MAX_NUM][TNFTL_LPT_BLK_NUM_For_EXTENDED_PARTITION];
++
++TNFTL_WCACHE gTNFTL_PriPartitionWCache[MAX_NAND_DRIVE][TNFTL_WCACHE_NUM_For_PRIMARY_PARTITION];
++TNFTL_WCACHE gTNFTL_ExtPartitionWCache[MAX_NAND_DRIVE][TNFTL_EXTENDED_PARTITION_MAX_NUM][TNFTL_WCACHE_NUM_For_EXTENDED_PARTITION];
++
++#if defined( TNFTL_READ_CACHE_INCLUDE )
++TNFTL_RCACHE_SLOT gTNFTL_PriPartitionRCache[MAX_NAND_DRIVE][TNFTL_MAX_SUPPORT_RCACHE_MEMORY_SIZE>>9];
++TNFTL_RCACHE_SLOT gTNFTL_ExtPartitionRCache[MAX_NAND_DRIVE][TNFTL_EXTENDED_PARTITION_MAX_NUM][TNFTL_MAX_SUPPORT_RCACHE_MEMORY_SIZE>>9];
++#endif
++
++TNFTL_MAINPB_INFO gTNFTL_PriPartitionMainPBInfo[MAX_NAND_DRIVE][TNFTL_WCACHE_NUM_For_PRIMARY_PARTITION];
++TNFTL_MAINPB_INFO gTNFTL_ExtPartitionMainPBInfo[MAX_NAND_DRIVE][TNFTL_EXTENDED_PARTITION_MAX_NUM][TNFTL_WCACHE_NUM_For_EXTENDED_PARTITION];
++
++NAND_IO_DEVINFO* gLBA_DevInfo[LBA_MAX_SUPPORT_MULTI_NANDFLASH];
++
++unsigned char gNAND_UARTDebugFlag = TCC_NAND_TRACE_OFF;
++unsigned char gNAND_PartitionInfoLoadFlag = DISABLE;
++#if defined(_LINUX_) || defined(_WINCE_)
++unsigned char gNAND_SetFlagOfChangeAreaSize = DISABLE;
++unsigned char gFormatType = TC_LOWLEVEL_YES;
++unsigned int gMAX_ROMSIZE = MAX_ROMSIZE_NAND;
++#else
++unsigned char gNAND_SetFlagOfChangeAreaSize = ENABLE;
++#endif
++
++#if defined(_WINCE_)
++tSYSTEM_PARAM *pSYS_PARAM_NAND_DRV;
++#endif
++
++//=============================================================================
++//*
++//*
++//* [ LOCAL FUNCTIONS DEFINE ]
++//*
++//*
++//=============================================================================
++
++//=============================================================================
++//*
++//*
++//* [ EXTERN VARIABLE & FUNCTIONS DEFINE ]
++//*
++//*
++//=============================================================================
++extern unsigned char NANDBUF_Library_Version[];
++#if defined(_LINUX_)
++unsigned char gNAND_PageBuffer[TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE + TNFTL_MAX_SUPPORT_NAND_IO_SPARE_SIZE] __attribute__((aligned(8)));
++unsigned char gNAND_RCacheDTAreaBuffer[TNFTL_MAX_SUPPORT_RCACHE_MEMORY_SIZE] __attribute__((aligned(8)));
++unsigned char gNAND_AlignBuffer[TNFTL_MAX_SUPPORT_ALIGNCACHE_MEMORY_SIZE] __attribute__((aligned(8)));
++#else
++extern unsigned char gNAND_PageBuffer[TNFTL_MAX_SUPPORT_NAND_IO_PAGE_SIZE + TNFTL_MAX_SUPPORT_NAND_IO_SPARE_SIZE];
++extern unsigned char gNAND_RCacheDTAreaBuffer[TNFTL_MAX_SUPPORT_RCACHE_MEMORY_SIZE];
++extern unsigned char gNAND_AlignBuffer[TNFTL_MAX_SUPPORT_ALIGNCACHE_MEMORY_SIZE];
++#endif
++
++extern NAND_IO_CYCLE WriteCycleTime;
++extern NAND_IO_CYCLE ReadCycleTime;
++extern NAND_IO_CYCLE CommCycleTime;
++extern unsigned int gMaxBusClkMHZ;
++extern unsigned int gCycleTick;
++
++#if !defined(NU_FILE_INCLUDE) && !defined(_LINUX_) && !defined(_WINCE_)
++extern unsigned int fat_cbuffer[];
++#else
++extern unsigned char gFormatType;
++#endif
++
++
++#if !defined(FWDN_DOWNLOADER_INCLUDE) && !defined(_LINUX_) && !defined(_WINCE_)
++ #ifdef MTP_INCLUDE
++ extern void* MTPMEM_AllocNandInitBuffer( void );
++ extern unsigned int MTPMEM_GetNandIintBufferSize( void );
++ #else
++ extern char gFileBuffer[RAW_BUFFERSIZE];
++ #endif
++#endif
++
++#if defined(_WINCE_)
++extern void B_RETAILMSG(const char * fmt, ...);
++#endif
++
++/******************************************************************************
++*
++* unsigned char* NAND_TellLibraryVersion
++*
++* Input : NONE
++* Output : NONE
++* Return : NONE
++*
++* Description :
++*
++*******************************************************************************/
++//unsigned char* NAND_TellLibraryVersion( void )
++//{
++// return (unsigned char*)gNAND_HiddenInfoSignature;
++//}
++
++/******************************************************************************
++*
++* unsigned char* NAND_DRV_TellLibraryVersion
++*
++* Input : NONE
++* Output : NONE
++* Return : NONE
++*
++* Description :
++*
++*******************************************************************************/
++unsigned char* NAND_DRV_TellLibraryVersion( void )
++{
++ unsigned short int i = 0;
++
++ if ( i )
++ return (unsigned char*)NANDBUF_Library_Version;
++ else
++ return (unsigned char*)NANDDRV_Library_Version;
++}
++
++/*************************************************************************************
++ * NAND_Init
++ *
++ * Description :
++ * Argument :
++ * Return : if it is successed then return 0
++ * if it is failed then return Error Code
++ *
++ *************************************************************************************/
++void NAND_Init( void )
++{
++ #ifdef NAND_LBA_INCLUDE
++ NAND_ERROR res;
++ #endif
++
++ #ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++ unsigned int i;
++ #endif
++
++ #if !defined(NU_FILE_INCLUDE) && !defined(FWDN_DOWNLOADER_INCLUDE) && !defined(_LINUX_) & !defined(_WINCE_)
++ unsigned int BufferSize;
++ #endif
++
++ //=====================================================
++ // Initialize NAND IO & TNFTL Variable
++ //=====================================================
++ NAND_IO_Init();
++
++ //=================================================================
++ // Initialize TNFTL Driver
++ //=================================================================
++ /* Drive #0 */
++ TNFTL_AllocMemAndLinkForDriver( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0], &gNAND_DrvInfo[NAND_DRV_0].NFTLDrvInfo );
++
++ TNFTL_AllocMemAndLinkForLPT( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].PriPartition, &gTNFTL_PriPartitionLPTBlk[NAND_DRV_0][0], TNFTL_LPT_BLK_NUM_For_PRIMARY_PARTITION );
++ TNFTL_AllocMemAndLinkForWCACHE( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].PriPartition, &gTNFTL_PriPartitionWCache[NAND_DRV_0][0], TNFTL_WCACHE_NUM_For_PRIMARY_PARTITION );
++ #if defined( TNFTL_READ_CACHE_INCLUDE )
++ TNFTL_AllocMemAndLinkForRCACHE( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].PriPartition, &gTNFTL_PriPartitionRCache[NAND_DRV_0][0] );
++ #endif
++ TNFTL_AllocMemAndLinkForMainPBInfo( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].PriPartition, &gTNFTL_PriPartitionMainPBInfo[NAND_DRV_0][0], 2 );
++
++ TNFTL_AllocMemAndLinkForExtendedPartition( NAND_DRV_0, &gTNFTL_ExtPartitionDrvInfo[NAND_DRV_0][0] );
++ TNFTL_SetExtendedPartitionNums( NAND_DRV_0, TNFTL_EXTENDED_PARTITION_NUM );
++
++ #ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++ for ( i = 0; i < TNFTL_EXTENDED_PARTITION_MAX_NUM; ++i )
++ {
++ TNFTL_AllocMemAndLinkForLPT( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].ExtPartition[i], &gTNFTL_ExtPartitionLPTBlk[NAND_DRV_0][i][0], TNFTL_LPT_BLK_NUM_For_EXTENDED_PARTITION );
++ TNFTL_AllocMemAndLinkForWCACHE( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].ExtPartition[i], &gTNFTL_ExtPartitionWCache[NAND_DRV_0][i][0], TNFTL_WCACHE_NUM_For_EXTENDED_PARTITION );
++ TNFTL_AllocMemAndLinkForMainPBInfo( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].ExtPartition[i], &gTNFTL_ExtPartitionMainPBInfo[NAND_DRV_0][i][0], TNFTL_WCACHE_NUM_For_EXTENDED_PARTITION );
++ #if defined( TNFTL_V5_INCLUDE ) || defined(TNFTL_V6_INCLUDE)
++ TNFTL_AllocMemAndLinkForRCACHE( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].ExtPartition[i], &gTNFTL_ExtPartitionRCache[NAND_DRV_0][i][0] );
++ #endif
++ }
++ #endif
++
++ TNFTL_Init( NAND_DRV_0 );
++ TNFTL_SetStEdOfCS( NAND_DRV_0, NAND_IO_DRV0_START_CS, NAND_IO_DRV0_END_CS );
++
++ TNFTL_AllocMemAndLinkForPageBuffer( NAND_DRV_0, gNAND_PageBuffer );
++
++ #if defined( TNFTL_READ_CACHE_INCLUDE )
++ TNFTL_AllocMemAndLinkForRCacheBuffer( NAND_DRV_0, &gTNFTL_DrvInfo[NAND_DRV_0].PriPartition, gNAND_RCacheDTAreaBuffer, TNFTL_MAX_SUPPORT_RCACHE_MEMORY_SIZE );
++ TNFTL_SetUseAreaReadCacheMode( gNAND_DrvInfo[NAND_DRV_0].NFTLDrvInfo, &gTNFTL_DrvInfo[NAND_DRV_0].PriPartition, ENABLE );
++ #endif
++
++ #if defined( TNFTL_ALIGN_CACHE_INCLUDE )
++ TNFTL_AllocMemAndLinkForAlignCacheBuffer( NAND_DRV_0, gNAND_AlignBuffer, TNFTL_MAX_SUPPORT_ALIGNCACHE_MEMORY_SIZE );
++ #endif
++
++ #if !defined(NU_FILE_INCLUDE) && !defined(_LINUX_) && !defined(_WINCE_)
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ #ifdef MTP_INCLUDE
++ BufferSize = MTPMEM_GetNandIintBufferSize() / 4;
++ #else
++ BufferSize = RAW_BUFFERSIZE / 4;
++ #endif
++
++ if ( BufferSize > 65536 / 4 )
++ {
++ #ifdef MTP_INCLUDE
++ TNFTL_AllocMemAndLinkForMakeLPT( NAND_DRV_0, (unsigned char*)MTPMEM_AllocNandInitBuffer(), MTPMEM_GetNandIintBufferSize() / 4 );
++ #else
++ TNFTL_AllocMemAndLinkForMakeLPT( NAND_DRV_0, gFileBuffer, RAW_BUFFERSIZE / 4 );
++ #endif
++ }
++ else
++ {
++ TNFTL_AllocMemAndLinkForMakeLPT( NAND_DRV_0, fat_cbuffer, 65536 / 4 );
++ }
++ #else
++ TNFTL_AllocMemAndLinkForMakeLPT( NAND_DRV_0, fat_cbuffer, 65536 / 4 );
++ #endif
++ #endif
++
++ #ifdef NAND_LBA_INCLUDE
++ gLBA_DevInfo[0] = &gNAND_DrvInfo[0].NFTLDrvInfo->MediaDevInfo[0];
++ gLBA_DevInfo[1] = &gNAND_DrvInfo[0].NFTLDrvInfo->MediaDevInfo[1];
++ gLBA_DevInfo[2] = &gNAND_DrvInfo[0].NFTLDrvInfo->MediaDevInfo[2];
++ gLBA_DevInfo[3] = &gNAND_DrvInfo[0].NFTLDrvInfo->MediaDevInfo[3];
++
++ gLBA_DevInfo[0]->LBAInfo.FlagOfChangeTotalSectorSize = DISABLE;
++ res = NAND_IO_LBA_GetDeviceInfo( 0, gLBA_DevInfo[0] );
++ if ( ( res == SUCCESS ) || ( gLBA_DevInfo[0]->Feature.MediaType & S_LBA ) )
++ gNAND_DrvInfo[0].NFTLDrvInfo->NANDType = NAND_TYPE_LBA_NAND;
++ else
++ gNAND_DrvInfo[0].NFTLDrvInfo->NANDType = NAND_TYPE_PURE_NAND;
++ #else
++ gNAND_DrvInfo[0].NFTLDrvInfo->NANDType = NAND_TYPE_PURE_NAND;
++ #endif
++
++ /* Init TNFTL MSC Debug Monitor */
++ #if !defined(FWDN_DOWNLOADER_INCLUDE) && !defined(_LINUX_) && !defined(_WINCE_)
++ #ifdef TNFTL_DEBUG_INCLUDE
++ TNFTL_DEBUG_Init_Function( MASS_SCSI_InitMSCDebugMonitor,
++ VTC_SendData,
++ VTC_ReceiveData,
++ MASS_BulkOnly_SendData,
++ MASS_BulkOnly_ReceiveData,
++ MASS_SCSI_SetMSCDebugMonitorHandler,
++ FWDN_PROT_ResponseAck,
++ FWDN_PROT_ResponseNack);
++ TNFTL_DEBUG_Init();
++ #endif
++ #endif
++
++ return;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_InitExtPartitionInfo( void );
++*
++* DESCRIPTION :
++*
++* INPUT : NONE
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_InitExtPartitionInfo( void )
++{
++ gTNFTL_ExtPartitionInfo[NAND_DRV_0].ExtendedPartitionNum = TNFTL_EXTENDED_PARTITION_NUM;
++
++#if (TNFTL_EXTENDED_PARTITION_NUM>0)
++ gTNFTL_ExtPartitionInfo[NAND_DRV_0].ExtPartitionSize[0] = NAND_HIDDEN_0_PAGESIZE;
++#endif
++#if (TNFTL_EXTENDED_PARTITION_NUM>1)
++ gTNFTL_ExtPartitionInfo[NAND_DRV_0].ExtPartitionSize[1] = NAND_HIDDEN_1_PAGESIZE;
++#endif
++#if (TNFTL_EXTENDED_PARTITION_NUM>2)
++ gTNFTL_ExtPartitionInfo[NAND_DRV_0].ExtPartitionSize[2] = NAND_HIDDEN_2_PAGESIZE;
++#endif
++#if (TNFTL_EXTENDED_PARTITION_NUM>3)
++ gTNFTL_ExtPartitionInfo[NAND_DRV_0].ExtPartitionSize[3] = NAND_HIDDEN_3_PAGESIZE;
++#endif
++
++ gTNFTL_ExtPartitionInfo[NAND_DRV_0].ROAreaSize = NAND_RO_AREA_SIZE_MB;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_SetFlagOfChangeAreaSize( unsigned char On_Off );
++*
++* DESCRIPTION :
++*
++* INPUT :
++* On_Off = ENABLE/DISABLE
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_SetFlagOfChangeAreaSize( unsigned char On_Off )
++{
++ gNAND_SetFlagOfChangeAreaSize = On_Off;
++ return;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_SetExtPartitionInfoLoagFlag( unsigned char On_Off );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* On_Off = ENABLE/DISABLE
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_SetExtPartitionInfoLoagFlag( unsigned char On_Off )
++{
++ gNAND_PartitionInfoLoadFlag = On_Off;
++ return;
++}
++
++/******************************************************************************
++*
++* NAND_ERROR NAND_InitDrive
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_ERROR NAND_InitDrive( int nDrvNo )
++{
++ unsigned int i = 0;
++ TNFTL_ERROR res;
++ #if defined(NU_FILE_INCLUDE) || defined(_LINUX_) || defined(_WINCE_)
++ void *pointer;
++ #if defined(_LINUX_)
++ unsigned bufSize = 64*1024;
++ static unsigned int Tempbuffer[64*1024];
++ #else
++ unsigned bufSize = 256*1024;
++ static unsigned char Tempbuffer[256*1024];
++ #endif
++ #endif
++
++ unsigned int nTemp;
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ //===============================================================
++ // Check Drive I/O in the FTL Layer
++ //===============================================================
++ gNAND_DrvInfo[nDrvNo].DrvStatus = DISABLE;
++
++ #if defined(NU_FILE_INCLUDE)
++ pointer = TC_Allocate_Memory(bufSize);
++ if (pointer == NULL)
++ return -1;
++ #elif defined(_LINUX_) || defined(_WINCE_)
++ pointer = Tempbuffer;
++ if (pointer == NULL)
++ return -1;
++ #endif
++
++ #if defined(NU_FILE_INCLUDE)|| defined(_LINUX_) || defined(_WINCE_)
++ #if defined(_LINUX_)
++ TNFTL_AllocMemAndLinkForMakeLPT( NAND_DRV_0, pointer, bufSize ); /* [1193] */
++ #else
++ TNFTL_AllocMemAndLinkForMakeLPT( NAND_DRV_0, pointer, bufSize/4 ); /* [1193] */
++ #endif
++ #endif
++
++ if ( gNAND_SetFlagOfChangeAreaSize == DISABLE )
++ TNFTL_SetFlagOfChangePartition( gNAND_DrvInfo[0].NFTLDrvInfo, DISABLE );
++ else
++ {
++ TNFTL_SetFlagOfChangePartition( gNAND_DrvInfo[0].NFTLDrvInfo, ENABLE );
++ TNFTL_SetAreaProtectFlag(DISABLE); // Set Flag Only FWDN_MODE
++ }
++
++ //=========================================================
++ // Linux MTD Include
++ //=========================================================
++ #if defined(_LINUX_) //&& defined(_MTD_IO_INCLUDE_)
++ TNFTL_SetROAreaSize( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo, gTNFTL_ExtPartitionInfo[NAND_DRV_0].ROAreaSize << 20, ENABLE );
++ #else
++ TNFTL_SetROAreaSize( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo, 0, DISABLE );
++ #endif
++
++ #if defined(_WINCE_)
++ #if defined(USE_V_ADDRESS)
++ // Boot Loader - Init Info Restoration
++ if ( pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitStatus == ENABLE )
++ {
++ pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitStatus = DISABLE;
++ return SUCCESS;
++ }
++ #endif
++ #endif
++
++ NAND_IO_GetDeviceInfo( 0, &gNAND_DrvInfo[0].NFTLDrvInfo->MediaDevInfo[0] );
++ nTemp = gMAX_ROMSIZE >> gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->MediaDevInfo[0].ShiftPageSize;
++ nTemp = nTemp >> gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->MediaDevInfo[0].ShiftPpB;
++ nTemp = nTemp << 2;
++ nTemp += 20;
++ TNFTL_SetNBAreaEndPBAddr(nTemp); // 1 ~ n Block No...
++
++ res = TNFTL_InitDrive( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo );
++
++ #if defined(USE_V_ADDRESS) && defined(_WINCE_)
++ //--------------------------
++ // NAND Cycle Info
++ //--------------------------
++ #if 1
++ RETAILMSG(1, (TEXT("[NAND ] [BClk %dMHZ][1Tick %d][RE-S:%d,P:%d,H:%d][WR-S:%d,P:%d,H:%d][COM-S:%d,P:%d,H:%d]\n"),
++ gMaxBusClkMHZ,gCycleTick,ReadCycleTime.STP,ReadCycleTime.PW,ReadCycleTime.HLD,
++ WriteCycleTime.STP,WriteCycleTime.PW,WriteCycleTime.HLD,CommCycleTime.STP,CommCycleTime.PW,CommCycleTime.HLD));
++ #endif
++
++ //--------------------------
++ // NAND Area Size Info
++ //--------------------------
++ #if 0
++ RETAILMSG(1, (TEXT("[NAND ] [NB Area:%dMB][DT Area:%dMB]"),
++ ( gMAX_ROMSIZE * 2 ) >> 20, gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->PriPartition.TotalSectorSize >> 11 ));
++ for ( i = 0; i < gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->ExtendedPartitionNo; ++i )
++ RETAILMSG(1, (TEXT( "[HD Area%d:%dMB]"), i, gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->ExtPartition[i].TotalSectorSize >> 11 ));
++ RETAILMSG(1, (TEXT("\n")));
++ #endif
++
++ //--------------------------
++ // NAND Area Bad Block Info
++ //--------------------------
++ #if 0
++ RETAILMSG(1, (TEXT( "[NAND ] [BadBlockNum: %d]\n"),gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->FTLBadBlockNum ));
++ RETAILMSG(1, (TEXT( "[NAND ] [Blk:")));
++ for ( i = 0; i < gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->FTLBadBlockNum; ++i )
++ RETAILMSG(1, (TEXT( "%d "), ( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->FTLBadBlock[i] & 0x0000FFFF)));
++ RETAILMSG(1, (TEXT("\n")));
++ #endif
++
++ if ( res != SUCCESS )
++ RETAILMSG(1, (TEXT( "\n[NAND ] [NAND_Init_Error:0x%x]\n"), res ));
++ #else
++ //--------------------------
++ // NAND Cycle Info
++ //--------------------------
++ #if 1
++ ND_TRACE( "[NAND ] [BClk %dMHZ][1Tick %d][RE-S:%d,P:%d,H:%d][WR-S:%d,P:%d,H:%d][COM-S:%d,P:%d,H:%d]\n",
++ gMaxBusClkMHZ,gCycleTick,ReadCycleTime.STP,ReadCycleTime.PW,ReadCycleTime.HLD,
++ WriteCycleTime.STP,WriteCycleTime.PW,WriteCycleTime.HLD,CommCycleTime.STP,CommCycleTime.PW,CommCycleTime.HLD );
++ #endif
++
++ //--------------------------
++ // NAND Area Size Info
++ //--------------------------
++ #if 1
++ ND_TRACE( "[NAND ] [NB Area:%dMB][DT Area:%dMB]",
++ (int)(gMAX_ROMSIZE * 2) >> 20,
++ (int)(gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->PriPartition.TotalSectorSize >> 11));
++ for ( i = 0; i < gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->ExtendedPartitionNo; ++i )
++ ND_TRACE( "[HD Area%d:%dMB]", i, (int)gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->ExtPartition[i].TotalSectorSize >> 11 );
++ #if defined(_LINUX_)
++ if ( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->ROAreaSize != 0 )
++ ND_TRACE("[MTD Size:%dMB]", (int)gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->ROAreaSize >> 20 );
++ #endif
++ ND_TRACE("\n");
++ #endif
++
++ //--------------------------
++ // NAND Area Bad Block Info
++ //--------------------------
++ #if 0
++ ND_TRACE( "[NAND ] [BadBlockNum: %d]\n",gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->FTLBadBlockNum );
++ ND_TRACE( "[NAND ] [Blk:");
++ for ( i = 0; i < gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->FTLBadBlockNum; ++i )
++ ND_TRACE( "%d ", ( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->FTLBadBlock[i] & 0x0000FFFF));
++ ND_TRACE("]\n");
++ #endif
++
++ if ( res != SUCCESS )
++ ND_TRACE("\n[NAND ] [NAND_Init_Error:0x%x]\n", res );
++
++ #endif
++
++ #ifdef NU_FILE_INCLUDE
++ TC_Deallocate_Memory(pointer);
++ #endif
++
++ if ( res != SUCCESS )
++ return ERR_NAND_INIT_FAILED;
++ //return res; //original
++
++ TNFTL_AREAGetTotalSecAndCHS( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo,
++ &gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->PriPartition,
++ (U32 *)&gNAND_DrvInfo[nDrvNo].TotalDiskSector,
++ &gNAND_DrvInfo[nDrvNo].Cylinder,
++ &gNAND_DrvInfo[nDrvNo].Head,
++ &gNAND_DrvInfo[nDrvNo].Sector );
++
++ gNAND_DrvInfo[nDrvNo].DrvStatus = ENABLE;
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++
++ gNAND_DrvInfo[nDrvNo].DrvStatus = DISABLE;
++
++ if ( gNAND_SetFlagOfChangeAreaSize == DISABLE )
++ gLBA_DevInfo[0]->LBAInfo.FlagOfChangeTotalSectorSize = DISABLE;
++ else
++ gLBA_DevInfo[0]->LBAInfo.FlagOfChangeTotalSectorSize = ENABLE;
++
++ res = NAND_IO_LBA_InitDrive( *gLBA_DevInfo );
++ if ( res != SUCCESS )
++ return ERR_NAND_INIT_FAILED;
++
++ NAND_IO_LBA_GetTotalSecAndCHS( *gLBA_DevInfo,
++ NAND_LBA_DATA_AREA,
++ (U32)&gNAND_DrvInfo[nDrvNo].TotalDiskSector,
++ &gNAND_DrvInfo[nDrvNo].Cylinder,
++ &gNAND_DrvInfo[nDrvNo].Head,
++ &gNAND_DrvInfo[nDrvNo].Sector );
++
++ gNAND_DrvInfo[nDrvNo].DrvStatus = ENABLE;
++ #endif
++ }
++
++ return (NAND_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* int NAND_ReadSector
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_ReadSector( int nDrvNo, U32 LBA, U32 nSecSize, void* nReadBuffer )
++{
++ #ifdef NAND_INCLUDE
++ TNFTL_ERROR res = SUCCESS;
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ unsigned long int count;
++ HwTCNT4 = 0;
++ #endif
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag & TCC_NAND_TRACE_DRV_READ )
++ ND_TRACE( "\nNAND_ReadSector( %08d, %08d ) ---------------\n ", LBA, nSecSize );
++ #endif
++
++ #ifdef NAND_DRV_UART_DEBUG
++ #if defined(USE_V_ADDRESS)
++ #if defined(_WINCE_)
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ RETAILMSG(1,(TEXT( "\n\nNAND_ReadSector( %08d, %08d ) -------------------------- "), LBA, nSecSize ));
++ #endif
++ #endif
++ #endif
++ //==============================================================================
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ res = TNFTL_AREAReadSector( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo,
++ &gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->PriPartition,
++ LBA, nSecSize, nReadBuffer );
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ res = NAND_IO_LBA_ReadSector( *gLBA_DevInfo,
++ NAND_LBA_DATA_AREA,
++ LBA, nSecSize, nReadBuffer);
++ #endif
++ }
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ count = HwTCNT4;
++ ND_TRACE( "\n[NAND_READ Sector %08d - %05d ] ( %d uS ) -------------------------- ",
++ LBA,
++ nSecSize,
++ (count*267)/100);
++ #endif
++ //==============================================================================
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ ND_TRACE( " FAIL %08X", res );
++ #endif
++
++ return -1;
++ }
++
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/******************************************************************************
++*
++* int NAND_ReadSectorIRQ
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_ReadSectorIRQ( int nDrvNo, ndd_work_info* nand_work_info )
++{
++ #ifdef NAND_INCLUDE
++ TNFTL_ERROR res = SUCCESS;
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_DEBUG
++ #if defined(USE_V_ADDRESS)
++ #if define(LINUX)
++ printk("\nSectorNum:%d ---------------------------------", nand_work_info->SectorNum);
++ for ( i = 0; i < nand_work_info->SectorNum; ++i )
++ printk("\nBuf:0x%X", nand_work_info->BufferAddr[i]);
++
++ printk("\n");
++ #endif
++ #endif
++ #endif
++ //==============================================================================
++ res = TNFTL_AREAReadSectorIRQ( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo,
++ &gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->PriPartition,
++ nand_work_info );
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ ND_TRACE( " FAIL %08X", res );
++ #endif
++
++ ND_TRACE( " FAIL %08X", res );
++
++ return -1;
++ }
++
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/******************************************************************************
++*
++* int NAND_WriteSector
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_WriteSector( int nDrvNo, U32 LBA, U32 nSecSize, void* nWriteBuffer )
++{
++ #ifdef NAND_INCLUDE
++ TNFTL_ERROR res = SUCCESS;
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ unsigned long int count;
++ HwTCNT4 = 0;
++ #endif
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag & TCC_NAND_TRACE_DRV_WRITE )
++ ND_TRACE( "\n\nNAND_WriteSector( %08d, %08d ) -----------------------------------", LBA, nSecSize );
++ #endif
++
++ #ifdef NAND_DRV_UART_DEBUG
++ #if defined(USE_V_ADDRESS)
++ #if defined(_WINCE_)
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ RETAILMSG(1,(TEXT( "\n\nNAND_WriteSector( %08d, %08d ) -------------------------- "), LBA, nSecSize ));
++ #endif
++ #endif
++ #endif
++
++ //==============================================================================
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ res = TNFTL_AREAWriteSector( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo,
++ &gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->PriPartition,
++ LBA, nSecSize, nWriteBuffer );
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ res = NAND_IO_LBA_WriteSector( *gLBA_DevInfo,
++ NAND_LBA_DATA_AREA,
++ LBA, nSecSize, nWriteBuffer );
++ #endif
++ }
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ count = HwTCNT4;
++ ND_TRACE( "\n[NAND_WRITE Sector %08d - %05d ] ( %d uS ) -------------------------- ",
++ LBA,
++ nSecSize,
++ (count*267)/100);
++ #endif
++ //==============================================================================
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ ND_TRACE( "\nFAIL : %08X ", res );
++ #endif
++
++ return -1;
++ }
++
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/******************************************************************************
++*
++* int NAND_WriteSectorIRQ
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_WriteSectorIRQ( int nDrvNo, ndd_work_info* nand_work_info )
++{
++ #ifdef NAND_INCLUDE
++ TNFTL_ERROR res = SUCCESS;
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_DEBUG
++ #if defined(USE_V_ADDRESS)
++ #if define(LINUX)
++ printk("\nSectorNum:%d ---------------------------------", nand_work_info->SectorNum);
++ for ( i = 0; i < nand_work_info->SectorNum; ++i )
++ printk("\nBuf:0x%X", nand_work_info->BufferAddr[i]);
++
++ printk("\n");
++ #endif
++ #endif
++ #endif
++ //==============================================================================
++ res = TNFTL_AREAWriteSectorIRQ( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo,
++ &gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->PriPartition,
++ nand_work_info );
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ ND_TRACE( "\nFAIL : %08X ", res );
++ #endif
++
++ return -1;
++ }
++
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/******************************************************************************
++*
++* int NAND_HDReadSector
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_HDReadSector( int nDrvNo, U32 LBA, U32 nSecSize, void* nReadBuffer )
++{
++ #ifdef NAND_INCLUDE
++ TNFTL_ERROR res = SUCCESS;
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ #if defined(_LINUX_) || defined(_WINCE_)
++ res = TNFTL_AREAReadSector( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[nDrvNo + 1],
++ LBA, nSecSize, nReadBuffer );
++ #else
++ res = TNFTL_AREAReadSector( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo,
++ &gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->ExtPartition[1],
++ LBA, nSecSize, nReadBuffer );
++ #endif
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ res = NAND_IO_LBA_ReadSector( *gLBA_DevInfo,
++ NAND_LBA_MULTI_HIDDEN_AREA_0,
++ LBA, nSecSize, nReadBuffer);
++ #endif
++ }
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ ND_TRACE( " FAIL %08X", res );
++ #endif
++
++ return -1;
++ }
++
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/******************************************************************************
++*
++* int NAND_HDWriteSector
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_HDWriteSector( int nDrvNo, U32 LBA, U32 nSecSize, void* nWriteBuffer )
++{
++ #ifdef NAND_INCLUDE
++ TNFTL_ERROR res = SUCCESS;
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ #if defined(_LINUX_) || defined(_WINCE_)
++ res = TNFTL_AREAWriteSector( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[nDrvNo+1],
++ LBA, nSecSize, nWriteBuffer );
++ #else
++ res = TNFTL_AREAWriteSector( gNAND_DrvInfo[nDrvNo].NFTLDrvInfo,
++ &gNAND_DrvInfo[nDrvNo].NFTLDrvInfo->ExtPartition[1],
++ LBA, nSecSize, nWriteBuffer );
++ #endif
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ res = NAND_IO_LBA_WriteSector( *gLBA_DevInfo,
++ NAND_LBA_MULTI_HIDDEN_AREA_0,
++ LBA, nSecSize, nWriteBuffer );
++ #endif
++ }
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ ND_TRACE( "\nFAIL : %08X ", res );
++ #endif
++
++ return -1;
++ }
++
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/******************************************************************************
++*
++* int NAND_HDReadPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_HDReadPage( U32 nHDPageAddr, U32 nPageSize, void* nReadBuffer )
++{
++ #ifdef NAND_INCLUDE
++ TNFTL_ERROR res = SUCCESS;
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ unsigned long int count;
++ HwTCNT4 = 0;
++ #endif
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ ND_TRACE( "\n\nNAND_HDReadPage( %08d, %08d ) -----", nHDPageAddr, nPageSize );
++ #endif
++ //==============================================================================
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ res = TNFTL_AREAReadSector( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[0],
++ nHDPageAddr, nPageSize, nReadBuffer );
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ res = NAND_IO_LBA_ReadSector( *gLBA_DevInfo,
++ NAND_LBA_HIDDEN_AREA,
++ nHDPageAddr, nPageSize, nReadBuffer );
++ #endif
++ }
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ count = HwTCNT4;
++ ND_TRACE( "\n[NAND_HDReadPage %08d - %05d ] ( %d uS ) ---- ",
++ LBA,
++ nSecSize,
++ (count*267)/100);
++ #endif
++ //==============================================================================
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ ND_TRACE( "\nFAIL : %08X ", res );
++ #endif
++
++ return -1;
++ }
++
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/******************************************************************************
++*
++* int NAND_HDWritePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_HDWritePage( U32 nHDPageAddr, U32 nPageSize, void* nWriteBuffer )
++{
++ #ifdef NAND_INCLUDE
++ TNFTL_ERROR res = SUCCESS;
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ unsigned long int count;
++ HwTCNT4 = 0;
++ #endif
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag & TCC_NAND_TRACE_DRV_WRITE )
++ ND_TRACE( "\n\nNAND_HDWritePage( %08d, %08d ) ----", nHDPageAddr, nPageSize );
++ #endif
++ //==============================================================================
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ res = TNFTL_AREAWriteSector( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[0],
++ nHDPageAddr, nPageSize, nWriteBuffer );
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ res = NAND_IO_LBA_WriteSector( *gLBA_DevInfo,
++ NAND_LBA_HIDDEN_AREA,
++ nHDPageAddr, nPageSize, nWriteBuffer );
++ #endif
++ }
++
++ //=================[ For DEBUG ]================================================
++ #ifdef NAND_DRV_UART_MEASURE
++ count = HwTCNT4;
++ ND_TRACE( "\n[NAND_HDWritePage %08d - %05d ] ( %d uS ) ---- ",
++ LBA,
++ nSecSize,
++ (count*267)/100);
++ #endif
++ //==============================================================================
++
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ ND_TRACE( "\nFAIL : %08X ", res );
++ #endif
++
++ return -1;
++ }
++
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* int NAND_PhyReadPage( U32 nBlkAddr, U16 nPageAddr, U16 nCSorder, void* nReadBuffer );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* nBlkAddr =
++* nCSorder =
++* nPageAddr =
++* nReadBuffer =
++*
++* OUTPUT: int - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++int NAND_PhyReadPage( U32 nBlkAddr, U16 nPageAddr, U16 nCSorder, void* nReadBuffer )
++{
++ TNFTL_ERROR res = SUCCESS;
++ #if defined(NAND_INCLUDE)
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ ND_TRACE( "\nNAND_PhyReadPage( %08d, %08d ) ----", nBlkAddr, nPageAddr );
++ #endif
++
++ res = TNFTL_IOReadPhyPage( gNAND_DrvInfo[0].NFTLDrvInfo,
++ nBlkAddr, nPageAddr,
++ nCSorder, nReadBuffer );
++ if ( res != SUCCESS )
++ {
++ #ifdef NAND_DRV_UART_DEBUG
++ if ( gNAND_UARTDebugFlag == ENABLE )
++ ND_TRACE( "\nFAIL : %08X ", res );
++ #endif
++
++ return -1;
++ }
++ #endif
++
++ return 0;
++}
++
++int NAND_MTD_Init( U32* rMTDStBlk, U32* rMTDEdBlk )
++{
++ unsigned int i;
++ unsigned int nBlockPageAddr;
++ unsigned int nMTDStBlk, nMTDEdBlk;
++ NAND_IO_DEVINFO sDevInfo;
++ NAND_IO_DEVINFO *nDevInfo;
++ NAND_IO_ERROR res;
++
++ NAND_IO_GetDeviceInfo( 0, &sDevInfo);
++ nDevInfo = &sDevInfo;
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->IoStatus == DISABLE )
++ return -1;
++
++ nMTDStBlk = gNAND_DrvInfo[0].NFTLDrvInfo->NBArea.EdPBAddr - gNAND_DrvInfo[0].NFTLDrvInfo->ROAreaBlkNum;
++ nMTDEdBlk = gNAND_DrvInfo[0].NFTLDrvInfo->NBArea.EdPBAddr;
++
++ for ( i = nMTDStBlk; i < nMTDEdBlk; ++i )
++ {
++ nBlockPageAddr = i << nDevInfo->ShiftPpB;
++
++ res = NAND_IO_EraseBlock( nDevInfo, nBlockPageAddr, INTER_LEAVE_OFF );
++ if (res != SUCCESS)
++ ND_TRACE("\nBadBlock:%d", i);
++ }
++
++ *rMTDStBlk = nMTDStBlk;
++ *rMTDEdBlk = nMTDEdBlk;
++
++ return 0;
++}
++
++int NAND_MTD_WritePage( U32 nPageAddr, U8* nPageBuffer )
++{
++ unsigned char *nSpareBuffer;
++ NAND_IO_DEVINFO *nDevInfo;
++ NAND_IO_ERROR res;
++
++ nDevInfo = &gNAND_DrvInfo[0].NFTLDrvInfo->MediaDevInfo[0];
++
++ nSpareBuffer = (unsigned char *)nPageBuffer;
++ nSpareBuffer += 2048;
++
++ res = NAND_IO_WritePageMTD( nDevInfo,
++ nPageAddr, 0, 4/*nDevInfo->PPages*/,
++ nPageBuffer,
++ nSpareBuffer, ECC_ON );
++ return res;
++}
++
++int NAND_MTD_ReadPage( U32 nPageAddr, U8* nPageBuffer )
++{
++ unsigned char *nSpareBuffer;
++ NAND_IO_DEVINFO *nDevInfo;
++ NAND_IO_ERROR res;
++
++ nDevInfo = &gNAND_DrvInfo[0].NFTLDrvInfo->MediaDevInfo[0];
++
++ nSpareBuffer = (unsigned char *)nPageBuffer;
++ nSpareBuffer += 2048;
++
++ res = NAND_IO_ReadPageMTD( nDevInfo,
++ nPageAddr, 0, 4/*nDevInfo->PPages*/,
++ nPageBuffer,
++ nSpareBuffer, ECC_ON );
++ return res;
++}
++
++int NAND_LowLevelFormat( int mode )
++{
++ unsigned int i;
++ unsigned int nMediaNum;
++ NAND_IO_DEVINFO sDevInfo[NAND_IO_DRV0_END_CS+1];
++ NAND_IO_DEVINFO *nDevInfo;
++
++ TNFTL_ERROR res;
++
++ NAND_Init();
++
++ if ( ( mode == 1 ) || ( mode == 2 ) )
++ {
++ for ( i = NAND_IO_DRV0_START_CS; i < (unsigned int)( NAND_IO_DRV0_END_CS + 1 ); ++i )
++ {
++ if ( NAND_IO_GetDeviceInfo( i, &sDevInfo[nMediaNum] ) == SUCCESS )
++ {
++ ++nMediaNum;
++ }
++ else
++ {
++ if ( i == 0 )
++ return ERR_TNFTL_NOT_EXIST_NANDFLASH;
++ }
++ }
++
++ for ( i = 0; i < nMediaNum; ++i )
++ {
++ nDevInfo = &sDevInfo[i];
++
++ NAND_IO_EraseBlock( nDevInfo, 0, INTER_LEAVE_OFF );
++ }
++
++ if ( mode == 2 )
++ TNFTL_SetUseCheckPattern( ENABLE );
++
++ res = TNFTL_BMPRefresh( gNAND_DrvInfo[0].NFTLDrvInfo );
++ if ( res != SUCCESS )
++ return res;
++
++ TNFTL_SetUseCheckPattern( DISABLE );
++ }
++ else if ( mode == 3 )
++ {
++ res = TNFTL_ScanDevice( gNAND_DrvInfo[0].NFTLDrvInfo );
++ if ( res != SUCCESS )
++ return res;
++ }
++
++ return SUCCESS;
++}
++
++#if defined(_WINCE_)
++NAND_ERROR NAND_DriveStatusControl( int nMode )
++{
++ unsigned int nStructureIndex = 0;
++ NAND_ERROR res;
++
++ if ( nMode == NAND_DRVINFO_SAVE )
++ {
++ nStructureIndex = 0;
++
++ memcpy( (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (void*)gNAND_DrvInfo,
++ ( sizeof(NAND_DRVINFO) * MAX_NAND_DRIVE ) );
++ nStructureIndex += ( sizeof(NAND_DRVINFO) * MAX_NAND_DRIVE );
++
++ memcpy( (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (void*)gTNFTL_DrvInfo,
++ ( sizeof(TNFTL_DRVINFO) * MAX_NAND_DRIVE ) );
++ nStructureIndex += ( sizeof(TNFTL_DRVINFO) * MAX_NAND_DRIVE );
++
++
++ memcpy( (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (void*)gTNFTL_ExtPartitionDrvInfo,
++ (( sizeof(TNFTL_RW_AREA) * MAX_NAND_DRIVE ) * TNFTL_EXTENDED_PARTITION_MAX_NUM ) );
++ nStructureIndex += (( sizeof(TNFTL_RW_AREA) * MAX_NAND_DRIVE ) * TNFTL_EXTENDED_PARTITION_MAX_NUM );
++
++
++ memcpy( (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (void*)gTNFTL_PriPartitionLPTBlk,
++ (( sizeof(TNFTL_LPT_BLOCK) * MAX_NAND_DRIVE ) * TNFTL_LPT_BLK_NUM_For_PRIMARY_PARTITION ) );
++ nStructureIndex += (( sizeof(TNFTL_LPT_BLOCK) * MAX_NAND_DRIVE ) * TNFTL_LPT_BLK_NUM_For_PRIMARY_PARTITION );
++
++
++ memcpy( (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (void*)gTNFTL_ExtPartitionLPTBlk,
++ (( sizeof(TNFTL_LPT_BLOCK) * MAX_NAND_DRIVE ) * TNFTL_EXTENDED_PARTITION_MAX_NUM * TNFTL_LPT_BLK_NUM_For_EXTENDED_PARTITION ) );
++ nStructureIndex += (( sizeof(TNFTL_LPT_BLOCK) * MAX_NAND_DRIVE ) * TNFTL_EXTENDED_PARTITION_MAX_NUM * TNFTL_LPT_BLK_NUM_For_EXTENDED_PARTITION );
++
++
++ memcpy( (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (void*)gTNFTL_PriPartitionWCache,
++ (( sizeof(TNFTL_WCACHE) * MAX_NAND_DRIVE ) * TNFTL_WCACHE_NUM_For_PRIMARY_PARTITION ) );
++ nStructureIndex += (( sizeof(TNFTL_WCACHE) * MAX_NAND_DRIVE ) * TNFTL_WCACHE_NUM_For_PRIMARY_PARTITION );
++
++
++ memcpy( (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (void*)gTNFTL_ExtPartitionWCache,
++ (( sizeof(TNFTL_WCACHE) * MAX_NAND_DRIVE ) * TNFTL_EXTENDED_PARTITION_MAX_NUM * TNFTL_WCACHE_NUM_For_EXTENDED_PARTITION ) );
++ nStructureIndex += (( sizeof(TNFTL_WCACHE) * MAX_NAND_DRIVE ) * TNFTL_EXTENDED_PARTITION_MAX_NUM * TNFTL_WCACHE_NUM_For_EXTENDED_PARTITION );
++
++
++ memcpy( (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (void*)gTNFTL_PriPartitionMainPBInfo,
++ (( sizeof(TNFTL_MAINPB_INFO) * MAX_NAND_DRIVE ) * TNFTL_WCACHE_NUM_For_PRIMARY_PARTITION ) );
++ nStructureIndex += (( sizeof(TNFTL_MAINPB_INFO) * MAX_NAND_DRIVE ) * TNFTL_WCACHE_NUM_For_PRIMARY_PARTITION );
++
++
++ memcpy( (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (void*)gTNFTL_ExtPartitionMainPBInfo,
++ (( sizeof(TNFTL_MAINPB_INFO) * MAX_NAND_DRIVE ) * TNFTL_EXTENDED_PARTITION_MAX_NUM * TNFTL_WCACHE_NUM_For_EXTENDED_PARTITION ) );
++
++ res = (NAND_ERROR)SUCCESS;
++ }
++ else if ( nMode == NAND_DRVINFO_LOAD )
++ {
++ // Boot Loader - Init Info Restoration
++ nStructureIndex = 0;
++
++ memcpy( (void*)gNAND_DrvInfo,
++ (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ ( sizeof(NAND_DRVINFO) * MAX_NAND_DRIVE ) );
++ nStructureIndex += ( sizeof(NAND_DRVINFO) * MAX_NAND_DRIVE );
++
++ memcpy( (void*)gTNFTL_DrvInfo,
++ (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ ( sizeof(TNFTL_DRVINFO) * MAX_NAND_DRIVE ) );
++ nStructureIndex += ( sizeof(TNFTL_DRVINFO) * MAX_NAND_DRIVE );
++
++ memcpy( (void*)gTNFTL_ExtPartitionDrvInfo,
++ (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (( sizeof(TNFTL_RW_AREA) * MAX_NAND_DRIVE ) * TNFTL_EXTENDED_PARTITION_MAX_NUM ) );
++ nStructureIndex += (( sizeof(TNFTL_RW_AREA) * MAX_NAND_DRIVE ) * TNFTL_EXTENDED_PARTITION_MAX_NUM );
++
++ memcpy( (void*)gTNFTL_PriPartitionLPTBlk,
++ (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (( sizeof(TNFTL_LPT_BLOCK) * MAX_NAND_DRIVE ) * TNFTL_LPT_BLK_NUM_For_PRIMARY_PARTITION ) );
++ nStructureIndex += (( sizeof(TNFTL_LPT_BLOCK) * MAX_NAND_DRIVE ) * TNFTL_LPT_BLK_NUM_For_PRIMARY_PARTITION );
++
++ memcpy( (void*)gTNFTL_ExtPartitionLPTBlk,
++ (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (( sizeof(TNFTL_LPT_BLOCK) * MAX_NAND_DRIVE ) * TNFTL_EXTENDED_PARTITION_MAX_NUM * TNFTL_LPT_BLK_NUM_For_EXTENDED_PARTITION ) );
++ nStructureIndex += (( sizeof(TNFTL_LPT_BLOCK) * MAX_NAND_DRIVE ) * TNFTL_EXTENDED_PARTITION_MAX_NUM * TNFTL_LPT_BLK_NUM_For_EXTENDED_PARTITION );
++
++ memcpy( (void*)gTNFTL_PriPartitionWCache,
++ (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (( sizeof(TNFTL_WCACHE) * MAX_NAND_DRIVE ) * TNFTL_WCACHE_NUM_For_PRIMARY_PARTITION ) );
++ nStructureIndex += (( sizeof(TNFTL_WCACHE) * MAX_NAND_DRIVE ) * TNFTL_WCACHE_NUM_For_PRIMARY_PARTITION );
++
++ memcpy( (void*)gTNFTL_ExtPartitionWCache,
++ (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (( sizeof(TNFTL_WCACHE) * MAX_NAND_DRIVE ) * TNFTL_EXTENDED_PARTITION_MAX_NUM * TNFTL_WCACHE_NUM_For_EXTENDED_PARTITION ) );
++ nStructureIndex += (( sizeof(TNFTL_WCACHE) * MAX_NAND_DRIVE ) * TNFTL_EXTENDED_PARTITION_MAX_NUM * TNFTL_WCACHE_NUM_For_EXTENDED_PARTITION );
++
++ memcpy( (void*)gTNFTL_PriPartitionMainPBInfo,
++ (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (( sizeof(TNFTL_MAINPB_INFO) * MAX_NAND_DRIVE ) * TNFTL_WCACHE_NUM_For_PRIMARY_PARTITION ) );
++ nStructureIndex += (( sizeof(TNFTL_MAINPB_INFO) * MAX_NAND_DRIVE ) * TNFTL_WCACHE_NUM_For_PRIMARY_PARTITION );
++
++ memcpy( (void*)gTNFTL_ExtPartitionMainPBInfo,
++ (void*)&pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitInfo[nStructureIndex],
++ (( sizeof(TNFTL_MAINPB_INFO) * MAX_NAND_DRIVE ) * TNFTL_EXTENDED_PARTITION_MAX_NUM * TNFTL_WCACHE_NUM_For_EXTENDED_PARTITION ) );
++ res = (NAND_ERROR)SUCCESS;
++ }
++ else
++ {
++ res = ERR_NAND_WRONG_PARAMETER;
++ }
++
++ return res;
++}
++#endif
++
++/******************************************************************************
++*
++* int NAND_Ioctl
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_Ioctl( int function, void *param )
++{
++ #if defined(_LINUX_) || defined(_WINCE_) || defined (NAND_LBA_INCLUDE)
++ unsigned int i = 0;
++ #endif
++
++ switch( function )
++ {
++ case DEV_INITIALIZE:
++ {
++ #if defined(_WINCE_)
++ #if defined(USE_V_ADDRESS)
++ pSYS_PARAM_NAND_DRV = (tSYSTEM_PARAM*)tcc_allocbaseaddress((unsigned int)SYSTEM_PARAM_BASEADDRESS);
++ #else
++ pSYS_PARAM_NAND_DRV = (tSYSTEM_PARAM*)(SYSTEM_PARAM_BASEADDRESS);
++ #endif
++ #endif
++
++ #if defined(_WINCE_)
++ #if defined(USE_V_ADDRESS)
++ if ( pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitStatus == ENABLE )
++ {
++ NAND_DriveStatusControl( NAND_DRVINFO_LOAD );
++ }
++ #endif
++ #endif
++
++ NAND_Init();
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ if ( gNAND_PartitionInfoLoadFlag == DISABLE )
++ NAND_InitExtPartitionInfo();
++ else
++ TNFTL_SetExtendedPartitionNums( NAND_DRV_0, (U16)gTNFTL_ExtPartitionInfo[NAND_DRV_0].ExtendedPartitionNum );
++ #else
++ NAND_InitExtPartitionInfo();
++ #endif
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ #if defined(_WINCE_)
++ #if defined(USE_V_ADDRESS)
++ if ( pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitStatus != ENABLE )
++ #endif
++ #endif
++ {
++ for ( i = 0; i < gTNFTL_ExtPartitionInfo[NAND_DRV_0].ExtendedPartitionNum; ++i )
++ {
++ TNFTL_AREASetTotalSectorSize( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[i],
++ gTNFTL_ExtPartitionInfo[NAND_DRV_0].ExtPartitionSize[i] );
++ }
++
++
++ }
++
++ gNAND_DrvInfo[0].DrvStatus = DISABLE;
++
++ if ( NAND_InitDrive(0) != SUCCESS )
++ return EINITFAIL;
++
++ TNFTL_AREAGetTotalSecAndCHS( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->PriPartition,
++ (U32 *)&gNAND_DrvInfo[0].TotalDiskSector,
++ &gNAND_DrvInfo[0].Cylinder,
++ &gNAND_DrvInfo[0].Head,
++ &gNAND_DrvInfo[0].Sector );
++
++ gNAND_DrvInfo[0].DrvStatus = ENABLE;
++
++ #if defined(_WINCE_)
++ #if defined(USE_V_ADDRESS)
++ // Boot Loader - Init Info Restoration
++ pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitStatus = DISABLE;
++ #else
++ pSYS_PARAM_NAND_DRV->NAND_INFO.sNandInitStatus = ENABLE;
++ NAND_DriveStatusControl( NAND_DRVINFO_SAVE );
++ #endif
++ #endif
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++
++ #ifdef BRWS_STR_NAND_INCLUDE
++ gLBA_DevInfo[0]->LBAInfo.HDAreaSectorSize = ( gTNFTL_ExtPartitionInfo[NAND_DRV_0].ExtPartitionSize[0] + BRWS_NAME_AREA_SIZE
++ #ifndef NU_FILE_INCLUDE
++ #ifdef AUDIOUI_INCLUDE
++ + AUI_HD_OCCPAGE
++ #endif
++ #endif
++ );
++ #else
++ gLBA_DevInfo[0]->LBAInfo.HDAreaSectorSize = ( gTNFTL_ExtPartitionInfo[NAND_DRV_0].ExtPartitionSize[0]
++ #ifndef NU_FILE_INCLUDE
++ #ifdef AUDIOUI_INCLUDE
++ + AUI_HD_OCCPAGE
++ #endif
++ #endif
++ );
++ #endif
++
++ gLBA_DevInfo[0]->LBAInfo.MHDAreaNums = TNFTL_EXTENDED_PARTITION_NUM;
++
++ #ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++ for ( i = 0; i < TNFTL_EXTENDED_PARTITION_NUM - 1; ++i )
++ gLBA_DevInfo[0]->LBAInfo.MHDAreaSectorSize[i+1] = gTNFTL_ExtPartitionInfo[NAND_DRV_0].ExtPartitionSize[i+1];
++ #endif
++
++ gNAND_DrvInfo[0].DrvStatus = DISABLE;
++
++ if ( NAND_InitDrive(0) != SUCCESS )
++ return EINITFAIL;
++
++ gNAND_DrvInfo[0].DrvStatus = ENABLE;
++ #endif
++ }
++ }
++ break;
++
++ case DEV_GET_DISKINFO:
++ {
++ ioctl_diskinfo_t *info = (ioctl_diskinfo_t *) param;
++
++ #ifdef NU_FILE_INCLUDE
++ gFormatType = TC_LOWLEVEL_NO;
++ #endif
++ info->cylinder = gNAND_DrvInfo[0].Cylinder;
++ info->head = gNAND_DrvInfo[0].Head;
++ info->sector = gNAND_DrvInfo[0].Sector;
++ info->sector_size = 512;
++ info->Total_sectors = gNAND_DrvInfo[0].TotalDiskSector;
++ }
++ break;
++
++ case DEV_FORMAT_DISK:
++ {
++ unsigned short mode = *((unsigned short *)param);
++
++ #ifdef NU_FILE_INCLUDE
++ gFormatType = TC_LOWLEVEL_NO;
++ #endif
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ TNFTL_AREAFormat( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->PriPartition,
++ mode );
++ }
++ #ifdef NAND_LBA_INCLUDE
++ else
++ {
++ // NAND_IO_LBA_AREAClear( gLBA_DevInfo, NAND_LBA_DATA_AREA );
++ }
++ #endif
++
++ return NAND_InitDrive(0);
++ }
++ break;
++
++ case DEV_ERASE_INIT:
++ {
++ ioctl_diskeraseinit_t *erase = (ioctl_diskeraseinit_t *) param;
++ erase = erase;
++ }
++ break;
++
++ case DEV_ERASE_BLOCK:
++ {
++ ioctl_diskerase_t *erase = (ioctl_diskerase_t *) param;
++ erase = erase;
++ }
++ break;
++
++ case DEV_WRITEBACK_ON_IDLE:
++ {
++
++ }
++ break;
++
++ case DEV_ERASE_CLOSE:
++ {
++
++ }
++ break;
++
++ case DEV_HIDDEN_READ_PAGE_4:
++ {
++ ioctl_diskhdread4_t *hd_r = (ioctl_diskhdread4_t *) param;
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ TNFTL_AREAReadSectorBy4Byte( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[0],
++ (U32)hd_r->start_page,
++ (U16)hd_r->page_offset,
++ (U16)hd_r->read_size,
++ hd_r->buff );
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ NAND_IO_LBA_ReadSectorBy4Byte( *gLBA_DevInfo,
++ NAND_LBA_VFP,
++ (U32)hd_r->start_page,
++ (U16)hd_r->page_offset,
++ (U16)hd_r->read_size,
++ hd_r->buff );
++ #endif
++ }
++
++ }
++ break;
++ case DEV_SET_POWER:
++ {
++ #ifdef NAND_LBA_INCLUDE
++ unsigned short mode = *((unsigned short *)param);
++ unsigned short int wCSorder;
++ unsigned short int wMediaNums;
++ #endif
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ // NOP
++ }
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ NAND_IO_LBA_GetDeviceMediaNums( &wMediaNums );
++
++ if ( mode == DISK_STATE_STANDBY )
++ {
++ for ( wCSorder = 0; wCSorder < wMediaNums; ++wCSorder )
++ {
++ NAND_IO_LBA_PowerSaveMode( gLBA_DevInfo[wCSorder], DISABLE );
++ NAND_IO_LBA_HighSpeedMode( gLBA_DevInfo[wCSorder], ENABLE );
++ }
++ }
++ else if ( mode == DISK_STATE_IDLE )
++ {
++ for ( wCSorder = 0; wCSorder < wMediaNums; ++wCSorder )
++ {
++ NAND_IO_LBA_PowerSaveMode( gLBA_DevInfo[wCSorder], ENABLE );
++ NAND_IO_LBA_HighSpeedMode( gLBA_DevInfo[wCSorder], DISABLE );
++ }
++ }
++ #endif
++ }
++ }
++ break;
++ case DEV_GET_MAX_SECTOR_PER_BLOCK:
++ {
++ unsigned short *value = (unsigned short *)param;
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ if ( gNAND_DrvInfo[0].DrvStatus == ENABLE )
++ *value = ( gNAND_DrvInfo[0].NFTLDrvInfo->PpB << gNAND_DrvInfo[0].NFTLDrvInfo->ShiftPPages );
++ else
++ *value = TNFTL_MAX_SUPPORT_NAND_IO_SECTOR_SIZE_PER_1PAGE;
++ }
++ else
++ {
++ *value = 2048; // PpB: 128 * PPage: 16
++ }
++ }
++ break;
++
++ case DEV_TELL_DATASTARTSECTOR:
++ {
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ TNFTL_WCacheSetDataStartSector( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->PriPartition,
++ *(unsigned int*)param );
++ }
++
++ break;
++ }
++
++ case DEV_CHECK_CRC_NANDBOOT_IMAGE_ROM:
++#ifdef TODO_NEMO /* 09.04.13 */
++ #if defined (BOOTCRCCHEK)
++ {
++ BootCRC *pbootcrc;
++
++ pbootcrc = (BootCRC*)param;
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ return TNFTL_NBGetCRCValueOfImageFile(gNAND_DrvInfo[0].NFTLDrvInfo, &pbootcrc->crc128kchk, &pbootcrc->crcfullchk, &pbootcrc->bootfilesize);
++ }
++ else
++ return 0;
++ }
++ #else
++ {
++ unsigned int nOrgCRCcode1;
++ unsigned int nOrgCRCcode2;
++ unsigned int nRomFileSize;
++ unsigned int rRstCRCcode1;
++ unsigned int rRstCRCcode2;
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ return TNFTL_NBGetCRCOfImageFile( gNAND_DrvInfo[0].NFTLDrvInfo, 1,
++ &nOrgCRCcode1, &nOrgCRCcode2, &nRomFileSize,
++ &rRstCRCcode1, &rRstCRCcode2 );
++ }
++ else
++ return 0;
++ }
++ #endif
++#endif /* TODO_NEMO */
++ break;
++ #ifdef TNFTL_V4_INCLUDE
++ case DEV_FORCE_FLUSH_CACHE_DATA:
++ {
++ return TNFTL_WCacheFourceFlushCache_DATA( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->PriPartition );
++ }
++ break;
++ #endif
++ #if defined( TNFTL_ALIGN_CACHE_INCLUDE )
++ case DEV_SET_ALIGEN_CACHE:
++ {
++ unsigned short mode = *((unsigned short *)param);
++
++ #if defined(USE_V_ADDRESS)
++ #if defined(_WINCE_)
++ if ( mode == ENABLE )
++ RETAILMSG(0, (TEXT("[NAND ]Align Cache Turn On\r\n")));
++ else
++ RETAILMSG(0, (TEXT("[NAND ]Align Cache Turn Off\r\n")));
++ #else
++ if ( mode == ENABLE )
++ ND_TRACE("\n[NAND ]Align Cache Turn On");
++ else
++ ND_TRACE("\n[NAND ]Align Cache Turn Off");
++ #endif
++ #endif
++
++ return TNFTL_SetUseAlignCacheMode( gNAND_DrvInfo[0].NFTLDrvInfo, mode );
++ }
++ break;
++ #endif
++ case DEV_GET_WRITE_PROTECT:
++ return 0;
++ break;
++ case DEV_GET_INSERTED:
++ return 1;
++ #ifdef NU_FILE_INCLUDE
++ case DEV_GET_HIDDEN_SIZE:
++ if (gNAND_DrvInfo[0].DrvStatus == ENABLE)
++ *(int *)param = NAND_HIDDEN_0_PAGESIZE;
++ else
++ *(int *)param = -1;
++ break;
++ #endif
++ case DEV_GET_INITED:
++ return 1;
++ case DEV_GET_PLAYABLE_STATUS:
++ return 1;
++ default:
++ return ENOTSUPPORT;
++ }
++ #endif
++ return 0; /* SUCCESS */
++}
++
++/******************************************************************************
++*
++* int NAND_HDIoctl
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++int NAND_HDIoctl( int function, void *param )
++{
++ #if defined(_LINUX_) || defined(_WINCE_)
++ unsigned int i;
++ #endif
++
++ switch( function )
++ {
++ case DEV_INITIALIZE:
++ {
++ NAND_Init();
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ if ( gNAND_PartitionInfoLoadFlag == DISABLE )
++ NAND_InitExtPartitionInfo();
++ else
++ TNFTL_SetExtendedPartitionNums( NAND_DRV_0, (U16)gTNFTL_ExtPartitionInfo[NAND_DRV_0].ExtendedPartitionNum );
++ #endif
++
++
++ for ( i = 0; i < gTNFTL_ExtPartitionInfo[NAND_DRV_0].ExtendedPartitionNum; ++i )
++ {
++ TNFTL_AREASetTotalSectorSize( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[i],
++ gTNFTL_ExtPartitionInfo[NAND_DRV_0].ExtPartitionSize[i] );
++ }
++
++ gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[1].DrvStatus = DISABLE;
++
++ if ( NAND_InitDrive(0) != SUCCESS )
++ return EINITFAIL;
++
++ TNFTL_AREAGetTotalSecAndCHS( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[1],
++ (U32 *)&gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[1].TotalDiskSector,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[1].Cylinder,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[1].Head,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[1].Sector );
++
++ gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[1].DrvStatus = ENABLE;
++ }
++ break;
++
++ case DEV_GET_DISKINFO:
++ {
++ ioctl_diskinfo_t *info = (ioctl_diskinfo_t *) param;
++
++ info->cylinder = gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[1].Cylinder;
++ info->head = gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[1].Head;
++ info->sector = gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[1].Sector;
++ info->sector_size = 512;
++ }
++ break;
++
++ case DEV_FORMAT_DISK:
++ {
++ unsigned short mode = *((unsigned short *)param);
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ TNFTL_AREAFormat( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[1],
++ mode );
++ }
++
++ return NAND_InitDrive(0);
++ }
++ break;
++
++ case DEV_ERASE_INIT:
++ {
++ ioctl_diskeraseinit_t *erase = (ioctl_diskeraseinit_t *) param;
++ erase = erase;
++ }
++ break;
++
++ case DEV_ERASE_BLOCK:
++ {
++ ioctl_diskerase_t *erase = (ioctl_diskerase_t *) param;
++ erase = erase;
++ }
++ break;
++
++ case DEV_WRITEBACK_ON_IDLE:
++ {
++
++ }
++ break;
++
++ case DEV_ERASE_CLOSE:
++ {
++
++ }
++ break;
++
++ case DEV_HIDDEN_READ_PAGE_4:
++ {
++
++ }
++ break;
++
++ case DEV_GET_MAX_SECTOR_PER_BLOCK:
++ {
++ unsigned short *value = (unsigned short *)param;
++
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[1].DrvStatus == ENABLE )
++ {
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[1].TotalDiskSector >
++ (U32)( gNAND_DrvInfo[0].NFTLDrvInfo->PpB << gNAND_DrvInfo[0].NFTLDrvInfo->ShiftPPages ) * 2 )
++ *value = ( gNAND_DrvInfo[0].NFTLDrvInfo->PpB << gNAND_DrvInfo[0].NFTLDrvInfo->ShiftPPages );
++ else
++ *value = TNFTL_MAX_SUPPORT_NAND_IO_SECTOR_SIZE_PER_1PAGE;
++ }
++ else
++ *value = TNFTL_MAX_SUPPORT_NAND_IO_SECTOR_SIZE_PER_1PAGE;
++ }
++ break;
++
++ case DEV_TELL_DATASTARTSECTOR:
++ {
++ TNFTL_WCacheSetDataStartSector( gNAND_DrvInfo[0].NFTLDrvInfo,
++ &gNAND_DrvInfo[0].NFTLDrvInfo->ExtPartition[1],
++ *(unsigned int*)param );
++ break;
++ }
++
++ case DEV_GET_WRITE_PROTECT:
++ return 0;
++ break;
++ case DEV_GET_INSERTED:
++ return 1;
++ case DEV_GET_INITED:
++ return 1;
++ case DEV_GET_PLAYABLE_STATUS:
++ return 1;
++ default:
++ return ENOTSUPPORT;
++ }
++
++ return 0; /* SUCCESS */
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* int NAND_ReadMultiSectorStart( U32 LBA, U16 nSecSize );
++*
++* DESCRIPTION :
++* INPUT:
++* LBA =
++* nSecSize =
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++int NAND_ReadMultiSectorStart( U32 LBA, U32 nSecSize )
++{
++ #ifdef NAND_INCLUDE
++ LBA = 0;
++ nSecSize = 0;
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* int NAND_ReadMultiSectorStop( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++int NAND_ReadMultiSectorStop( void )
++{
++ #ifdef NAND_INCLUDE
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* int NAND_WriteMultiSectorStart( U32 LBA, U16 nSecSize );
++*
++* DESCRIPTION :
++* INPUT:
++* LBA =
++* nSecSize =
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++int NAND_WriteMultiSectorStart( U32 LBA, U32 nSecSize )
++{
++ #ifdef NAND_INCLUDE
++ LBA = 0;
++ nSecSize = 0;
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* int NAND_WriteMultiSectorStop( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++int NAND_WriteMultiSectorStop( void )
++{
++ #ifdef NAND_INCLUDE
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* int NAND_HDClearPages( U32 nHDStPageAddr, U32 nHDEdPageAddr );
++*
++* DESCRIPTION :
++* INPUT:
++* nHDEdPageAddr =
++* nHDStPageAddr =
++*
++* OUTPUT: int - Return Type
++* =
++* REMARK :
++**************************************************************************/
++int NAND_HDClearPages( U32 nHDStPageAddr, U32 nHDEdPageAddr )
++{
++ #ifdef NAND_INCLUDE
++ nHDStPageAddr = 0;
++ nHDEdPageAddr = 0;
++ return 0;
++ #else
++ return NOT_SUPPORT_NAND;
++ #endif
++}
++
++/******************************************************************************
++*
++* U16 NAND_GetSerialNumber
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++U16 NAND_GetSerialNumber( U8* rSerialNumber, U16 nSize )
++{
++ #ifdef NAND_INCLUDE
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ return TNFTL_GetSerialNumber( gNAND_DrvInfo[0].NFTLDrvInfo, rSerialNumber, nSize );
++ else
++ {
++ #ifdef NAND_LBA_INCLUDE
++ return NAND_IO_LBA_GetSerialNumber( gLBA_DevInfo, gNAND_PageBuffer, rSerialNumber, nSize );
++ #else
++ return 0;
++ #endif
++ }
++ #else
++ return 0;
++ #endif
++}
++
++/******************************************************************************
++*
++* U16 NAND_GetUniqueID
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++U16 NAND_GetUniqueID( U8* rSerialNumber, U16 nSize )
++{
++ if ( gNAND_DrvInfo[0].NFTLDrvInfo->NANDType == NAND_TYPE_PURE_NAND )
++ {
++ #if defined(NAND_INCLUDE) && !defined(_SDRAMONLY1_)
++ unsigned int uiIDSize;
++
++ uiIDSize = ( nSize < gNAND_DrvInfo[0].NFTLDrvInfo->MediaSizeOfUniqueID ) ? nSize : gNAND_DrvInfo[0].NFTLDrvInfo->MediaSizeOfUniqueID;
++ memcpy((void*)rSerialNumber, (void*)gNAND_DrvInfo[0].NFTLDrvInfo->MediaUniqueID, uiIDSize);
++
++ return (U16)uiIDSize;
++ #else
++ return 0;
++ #endif
++ }
++ else
++ return 0;
++}
++
++/******************************************************************************
++*
++* TNFTL_ERROR NAND_SetUartDebug
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++TNFTL_ERROR NAND_SetUartDebug( unsigned int on_off )
++{
++ gNAND_UARTDebugFlag = (U8)on_off;
++
++ return (TNFTL_ERROR)SUCCESS;
++}
++
++#ifdef NU_FILE_INCLUDE
++/************************************************************************
++* FUNCTION
++*
++* NAND_IO_Open
++*
++* DESCRIPTION
++*
++* This function prepares the NAND Flash for usage by allocating the
++* pages necessary for usage.
++*
++* INPUTS
++*
++* driveno The number assigned to the NAND Flash.
++*
++* OUTPUTS
++*
++* YES Successful Completion.
++* NO Couldn't allocate all of the
++* pages.
++*
++*************************************************************************/
++INT NAND_IO_Open(UINT16 driveno)
++{
++ NU_Obtain_Semaphore(&CAPP_SEM, NU_SUSPEND);
++ NAND_Ioctl(DEV_INITIALIZE, NULL);
++ NU_Release_Semaphore(&CAPP_SEM);
++ return(YES);
++}
++
++#ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++/**************************************************************************
++* FUNCTION NAME :
++* INT NAND_HD_IO_Open(UINT16 driveno);
++*
++* DESCRIPTION :
++* INPUT:
++* driveno =
++*
++* OUTPUT: INT - Return Type
++* =
++* REMARK :
++**************************************************************************/
++INT NAND_HD_IO_Open(UINT16 driveno)
++{
++ NU_Obtain_Semaphore(&CAPP_SEM, NU_SUSPEND);
++ NAND_HDIoctl(DEV_INITIALIZE, NULL);
++ NU_Release_Semaphore(&CAPP_SEM);
++ return(YES);
++}
++#endif //INTERNAL_HIDDEN_STORAGE_INCLUDE
++
++/************************************************************************
++* FUNCTION
++*
++* NAND_IO_RAW_Open
++*
++* DESCRIPTION
++*
++* This function doesn't do anything for the NAND Flash. It is
++* included for devtable consistency.
++*
++* INPUTS
++*
++* None.
++*
++* OUTPUTS
++*
++* None.
++*
++*************************************************************************/
++INT NAND_IO_RAW_Open(UINT16 driveno)
++{
++ return(NO);
++}
++
++#ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++/**************************************************************************
++* FUNCTION NAME :
++* INT NAND_HD_IO_RAW_Open(UINT16 driveno);
++*
++* DESCRIPTION :
++* INPUT:
++* driveno =
++*
++* OUTPUT: INT - Return Type
++* =
++* REMARK :
++**************************************************************************/
++INT NAND_HD_IO_RAW_Open(UINT16 driveno)
++{
++ return(NO);
++}
++#endif //INTERNAL_HIDDEN_STORAGE_INCLUDE
++
++/************************************************************************
++* FUNCTION
++*
++* NAND_IO_Close
++*
++* DESCRIPTION
++*
++* This function deallocates all of the pages associated with the
++* NAND Flash. The actual code here is commented out since we
++* probably don't want to loose the data on a close.
++*
++* INPUTS
++*
++* driveno The number assigned to the NAND Flash.
++*
++* OUTPUTS
++*
++* YES Successful Completion.
++* NO Couldn't allocate all of the
++* pages.
++*
++*************************************************************************/
++INT NAND_IO_Close(UINT16 driveno)
++{
++ return(YES);
++}
++
++#ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++/**************************************************************************
++* FUNCTION NAME :
++* INT NAND_HD_IO_Close(UINT16 driveno) ;
++*
++* DESCRIPTION :
++* INPUT:
++* driveno =
++*
++* OUTPUT: INT - Return Type
++* =
++* REMARK :
++**************************************************************************/
++INT NAND_HD_IO_Close(UINT16 driveno)
++{
++ return(YES);
++}
++#endif //INTERNAL_HIDDEN_STORAGE_INCLUDE
++
++/************************************************************************
++* FUNCTION
++*
++* NAND_IO_ReadWrite
++*
++* DESCRIPTION
++*
++* This function reads or writes data from and to the NAND Flash
++* based on the 'reading' parameter.
++*
++* INPUTS
++*
++* driveno The number assigned to the
++* RAM Disk (not used)
++* block The block number to read or
++* write
++* buffer Pointer to the data to be
++* placed from a read or
++* stored on a write
++* count Number of bytes to be read
++* or written
++* reading Indicates whether or not we
++* are reading or writing
++*
++* OUTPUTS
++*
++* YES Successful Completion.
++* NO Block number is out of range.
++*
++*************************************************************************/
++INT NAND_IO_ReadWrite(UINT16 driveno, UINT32 block, VOID *buffer, UINT16 count, INT reading)
++{
++ int result;
++
++ NU_Obtain_Semaphore(&CAPP_SEM, NU_SUSPEND);
++
++ if(reading)
++ result = NAND_ReadSector(driveno, block, count, buffer);
++ else
++ result = NAND_WriteSector(driveno, block, count, buffer);
++
++ NU_Release_Semaphore(&CAPP_SEM);
++
++ if(!result)
++ return (YES);
++ else
++ return (NO);
++}
++
++#ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++/**************************************************************************
++* FUNCTION NAME :
++* INT NAND_HD_IO_ReadWrite(UINT16 driveno, UINT32 block, VOID *buffer, UINT16 count, INT reading) ;
++*
++* DESCRIPTION :
++* INPUT:
++* block =
++* buffer =
++* count =
++* driveno =
++* reading =
++*
++* OUTPUT: INT - Return Type
++* =
++* REMARK :
++**************************************************************************/
++INT NAND_HD_IO_ReadWrite(UINT16 driveno, UINT32 block, VOID *buffer, UINT16 count, INT reading)
++{
++ int result;
++
++ NU_Obtain_Semaphore(&CAPP_SEM, NU_SUSPEND);
++
++ driveno -= INTERNAL_HIDDEN_STORAGE_START_NO;
++ if(reading)
++ result = NAND_HDReadSector(driveno, block, count, buffer);
++ else
++ result = NAND_HDWriteSector(driveno, block, count, buffer);
++
++ NU_Release_Semaphore(&CAPP_SEM);
++
++ if(!result)
++ return (YES);
++ else
++ return (NO);
++}
++#endif //INTERNAL_HIDDEN_STORAGE_INCLUDE
++
++/************************************************************************
++* FUNCTION
++*
++* NAND_IO_Ioctl
++*
++* DESCRIPTION
++*
++* This function doesn't do anything for the NAND Flash. It is
++* included for devtable consistency.
++*
++* INPUTS
++*
++* None.
++*
++* OUTPUTS
++*
++* None.
++*
++*************************************************************************/
++INT NAND_IO_Ioctl(UINT16 driveno, UINT16 command, VOID *buffer)
++{
++ int result;
++
++ NU_Obtain_Semaphore(&CAPP_SEM, NU_SUSPEND);
++ result = NAND_Ioctl(command, buffer);
++ NU_Release_Semaphore(&CAPP_SEM);
++
++ return result;
++}
++
++#ifdef INTERNAL_HIDDEN_STORAGE_INCLUDE
++/**************************************************************************
++* FUNCTION NAME :
++* INT NAND_HD_IO_Ioctl(UINT16 driveno, UINT16 command, VOID *buffer);
++*
++* DESCRIPTION :
++* INPUT:
++* buffer =
++* command =
++* driveno =
++*
++* OUTPUT: INT - Return Type
++* =
++* REMARK :
++**************************************************************************/
++INT NAND_HD_IO_Ioctl(UINT16 driveno, UINT16 command, VOID *buffer)
++{
++ int result;
++
++ NU_Obtain_Semaphore(&CAPP_SEM, NU_SUSPEND);
++ result = NAND_HDIoctl(command, buffer);
++ NU_Release_Semaphore(&CAPP_SEM);
++
++ return result;
++}
++#endif //INTERNAL_HIDDEN_STORAGE_INCLUDE
++
++#endif // NU_FILE_INCLUDE
++
++//#endif // WITHOUT_FILESYSTEM
++
++/* end of file */
+diff --git a/drivers/block/tcc/nand_io_v6.c b/drivers/block/tcc/nand_io_v6.c
+new file mode 100644
+index 0000000..ba87353
+--- /dev/null
++++ b/drivers/block/tcc/nand_io_v6.c
+@@ -0,0 +1,15820 @@
++/****************************************************************************
++ * FileName : nand_io_v6.c
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#ifndef WITHOUT_FILESYSTEM
++
++#if defined(_LINUX_) || defined(_WINCE_)
++#include "IO_TCCXXX.h"
++#include "nand_io_v6.h"
++#else
++#include "main.h"
++#include "IO_TCCXXX.h"
++#include "nand_io_v6.h"
++#endif
++
++#if defined(_WINCE_)
++#if defined(USE_V_ADDRESS)
++#include "Tcc_ckc.h"
++#include "tcc_gpio.h"
++#else
++#include "Tca_ckc.h"
++#endif
++#include "bsp.h"
++#include "args.h"
++#elif defined(_LINUX_)
++#if defined(USE_V_ADDRESS)
++#include <mach/tca_ckc.h>
++#else
++#include "ckc.h"
++#endif
++#endif
++
++#if defined(TCC89XX) || defined(TCC92XX)
++#if defined(_LINUX_) || defined(_WINCE_)
++#include "TC_DRV.h"
++#else
++#include "TC_DRV.h"
++#endif
++#endif
++
++#if defined(_WINCE_)
++#include "stdlib.h"
++#endif
++
++//=============================================================================
++//
++// Version Signature
++//
++//=============================================================================
++#define NAND_IO_VERSION 'V','6','0','0','6'
++
++static const unsigned char NANDIO_Library_Version[] =
++{
++ SIGBYAHONG,
++ NAND_IO_SIGNATURE,
++ SIGN_OS,
++ SIGN_CHIPSET,
++ NAND_IO_VERSION,
++ NULL
++};
++
++#ifdef UARTCON_INCLUDE
++//#define NAND_IO_ECC_ERROR_LOG
++//#define NAND_IO_UART_MEASURE
++#endif
++
++#if defined(_LINUX_)
++#ifdef KERNEL_DRIVER
++#include <linux/kernel.h>
++#include <linux/string.h>
++//extern void *virtadr;
++struct dma_buf {
++ void *v_addr;
++ unsigned int dma_addr;
++ int buf_size;
++};
++extern struct dma_buf dma_t;
++#else
++#define DMA_ADDR (BSS_OFFSET - 0x00700000)
++#endif
++#else
++// TCC92 NU
++extern unsigned char *gpNandBuffer;
++#endif
++
++#if defined(_LINUX_)
++#define ASM_NOP { \
++ __asm__ __volatile__ ("nop"); \
++ __asm__ __volatile__ ("nop"); \
++ __asm__ __volatile__ ("nop"); \
++ __asm__ __volatile__ ("nop"); \
++ __asm__ __volatile__ ("nop"); \
++ __asm__ __volatile__ ("nop"); \
++}
++#elif defined(_WINCE_)
++volatile int __asm_nop_count = 0;
++#define ASM_NOP { __asm_nop_count++; }
++#else
++#define ASM_NOP { __asm{ NOP }; __asm{ NOP }; __asm{ NOP }; __asm{ NOP }; __asm{ NOP }; __asm{ NOP };}
++#endif
++
++#if defined(_WINCE_)
++#define NAND_IO_USE_DMA_ACCESS
++#elif defined(_LINUX_)
++ #ifdef KERNEL_DRIVER
++ #define NAND_IO_USE_DMA_ACCESS
++// #define NAND_IO_USE_MCU_ACCESS
++ #else
++ #define NAND_IO_USE_DMA_ACCESS
++ #endif
++#else
++#define NAND_IO_USE_DMA_ACCESS
++#endif
++
++#ifdef NAND_IO_USE_DMA_ACCESS
++#define NAND_IO_USE_DMA_DOUBLE_BUF
++#endif
++
++//=============================================================================
++//*
++//*
++//* [ CONST DATA DEFINE ]
++//*
++//*
++//=============================================================================
++const NAND_IO_FEATURE TOSHIBA_NAND_DevInfo[] =
++{
++ //*=======================================================================================================================================================
++ //*[ DEVICE CODE ][ SIZE ][ Cycle ][ ATTRIBUTE ]
++ //*-------------------------------------------------------------------------------------------------------------------------------------------------------
++ //* 1st, 2nd, 3rd, 4th, 5th, 6th, PBpV,BBpZ, PpB, Page,Spare,Col,Low,Twc, Ws, Wp, Wh, Rs, Rp, Rh
++ //*=======================================================================================================================================================
++ // [ 32MB] TC58DVM82A1FT
++ { 0x98, 0x75, 0x00, 0x00, 0x00, 0x00, 2048, 20, 32, 512, 16, 1, 2, 50, 0, 25, 15, 0, 25, 15, A_08BIT|A_SLC |A_SMALL|S_NOR },
++ // [ 64MB] TC58DVM92A1FT
++ { 0x98, 0x76, 0x00, 0x00, 0x00, 0x00, 4096, 20, 32, 512, 16, 1, 3, 50, 0, 25, 15, 0, 25, 15, A_08BIT|A_SLC |A_SMALL|S_NOR },
++ // [ 64MB] TC58NWM9S3B
++ { 0x98, 0xF0, 0x00, 0x00, 0x00, 0x00, 512, 10, 64, 2048, 64, 2, 2, 50, 0, 25, 15, 0, 25, 15, A_08BIT|A_SLC |A_BIG |S_NOR },
++ // [128MB] TC58DVG02A1FT
++ { 0x98, 0x79, 0x00, 0x00, 0x00, 0x00, 8192, 20, 32, 512, 16, 1, 3, 50, 0, 25, 15, 0, 25, 15, A_08BIT|A_SLC |A_SMALL|S_NOR },
++ // [128MB] TC58NVG0S3AFT
++ { 0x98, 0xF1, 0x00, 0x00, 0x00, 0x00, 1024, 20, 64, 2048, 64, 2, 2, 50, 0, 25, 15, 0, 25, 15, A_08BIT|A_SLC |A_BIG |S_NOR },
++ // [256MB] TH58NVG1S3AFT
++ { 0x98, 0xDA, 0x00, 0x00, 0x00, 0x00, 2048, 20, 64, 2048, 64, 2, 3, 50, 0, 25, 15, 0, 25, 15, A_08BIT|A_SLC |A_BIG |S_NOR },
++ // [512MB] THGVN0G4D1DTG00
++ { 0x98, 0xDC, 0x00, 0x15, 0x00, 0x00, 4096, 20, 64, 2048, 64, 2, 3, 50, 0, 25, 15, 0, 35, 15, A_08BIT|A_SLC |A_BIG |S_NOR|S_LBA },
++ // [512MB] TH58NYG2S8C
++ { 0x98, 0xBC, 0x91, 0xD5, 0x49, 0x00, 4096, 20, 64, 2048, 64, 2, 3, 50, 0, 25, 15, 0, 35, 15, A_16BIT|A_SLC |A_BIG |S_NOR },
++ // [512MB] TH58NVG2D4CTG00
++ { 0x98, 0xDC, 0x84, 0xA5, 0x60, 0x00, 2048, 40, 128, 2048, 64, 2, 3, 50, 0, 25, 15, 0, 25, 15, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP2 },
++ // [512MB] TH58NVG2D4BFT00
++ { 0x98, 0xDC, 0x84, 0xA5, 0x54, 0x00, 2048, 40, 128, 2048, 64, 2, 3, 50, 0, 25, 15, 0, 25, 15, A_08BIT|A_MLC |A_BIG |S_NOR },
++ // [ 1GB] TH58NVG3D4BFT00
++ { 0x98, 0xD3, 0x85, 0xA5, 0x58, 0x00, 4096, 40, 128, 2048, 64, 2, 3, 50, 0, 25, 15, 0, 25, 15, A_08BIT|A_MLC |A_BIG |S_NOR },
++ // [ 1GB] TC58NVG3D4CTG00
++ { 0x98, 0xD3, 0x84, 0xA5, 0x66, 0x00, 4096, 40, 128, 2048, 64, 2, 3, 30, 0, 20, 10, 0, 20, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [ 2GB] TH58NVG4D4CFT00 [ 4GB] TH58NVG5D4CTG20
++ { 0x98, 0xD5, 0x85, 0xA5, 0x00, 0x00, 8192, 40, 128, 2048, 64, 2, 3, 30, 0, 20, 10, 0, 20, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [ 1GB] TH58NVG3D1DTG00 // 4k Page
++ { 0x98, 0xD3, 0x94, 0xBA, 0x64, 0x00, 2048, 40, 128, 4096, 218, 2, 3, 30, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP },
++ // [ 2GB] TH58NVG4D1DTG00 [ 4GB] TH58NVG5D1DTG20
++ { 0x98, 0xD5, 0x94, 0x00, 0x00, 0x00, 4096, 40, 128, 4096, 218, 2, 3, 30, 0, 20, 10, 0, 15, 15, A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP },
++ // [ 8GB] TH58NVG6D1DTG20 // 4k Page
++ { 0x98, 0xD7, 0x00, 0x00, 0x00, 0x00, 8192, 40, 128, 4096, 218, 2, 3, 30, 0, 20, 10, 0, 15, 15, A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP }
++};
++
++const NAND_IO_FEATURE TOSHIBA_LBA_NAND_DevInfo[] =
++{
++ //*=======================================================================================================================================================
++ //*[ DEVICE CODE ][ SIZE ][ Cycle ][ ATTRIBUTE ]
++ //*-------------------------------------------------------------------------------------------------------------------------------------------------------
++ //* 1st, 2nd, 3rd, 4th, 5th, 6th, PBpV,BBpZ, PpB, Page,Spare,Col,Low,Twc, Ws, Wp, Wh, Rs, Rp, Rh
++ //*=======================================================================================================================================================
++ // [ 2GB] THGVN0G4D1DTG00
++ { 0x98, 0x21, 0x01, 0x55, 0xAA, 0x00, 8192, 40, 128, 4096, 218, 2, 3, 30, 0, 20, 10, 0, 15, 15, A_08BIT|A_MLC_8BIT|A_BIG |S_NOR|S_MP },
++ // [ 8GB] THGVN1G6D4ELA02
++ { 0x98, 0x21, 0x03, 0x55, 0xAA, 0x00, 8192, 40, 128, 4096, 218, 2, 3, 30, 0, 20, 10, 0, 15, 15, A_08BIT|A_MLC_8BIT|A_BIG |S_NOR|S_MP },
++ // [ 16GB] THGVN1G7D8ELA09
++ { 0x98, 0x21, 0x04, 0x55, 0xAA, 0x00, 8192, 40, 128, 4096, 218, 2, 3, 30, 0, 20, 10, 0, 15, 15, A_08BIT|A_MLC_8BIT|A_BIG |S_NOR|S_MP }
++};
++
++const NAND_IO_FEATURE HYNIX_NAND_DevInfo[] =
++{
++ //*=======================================================================================================================================================
++ //*[ DEVICE CODE ][ SIZE ][ Cycle ][ ATTRIBUTE ]
++ //*-------------------------------------------------------------------------------------------------------------------------------------------------------
++ //* 1st, 2nd, 3rd, 4th, 5th, 6th, PBpV,BBpZ, PpB, Page,Spare,Col,Low,Twc, Ws, Wp, Wh, Rs, Rp, Rh
++ //*=======================================================================================================================================================
++ // [ 32MB] HY27US08561M
++ { 0xAD, 0x75, 0x00, 0x00, 0x00, 0x00, 2048, 20, 32, 512, 16, 1, 2, 50, 0, 35, 15, 0, 35, 15, A_08BIT|A_SLC |A_SMALL|S_NOR|S_CB },
++ // [ 64MB] HY27US08121M
++ { 0xAD, 0x76, 0x00, 0x00, 0x00, 0x00, 4096, 20, 32, 512, 16, 1, 3, 60, 0, 40, 20, 0, 40, 20, A_08BIT|A_SLC |A_SMALL|S_NOR|S_CB },
++ // [ 64MB] HY27SS16122A
++ { 0xAD, 0x46, 0xAD, 0x46, 0xAD, 0x00, 4096, 20, 32, 512, 16, 1, 3, 60, 0, 40, 20, 0, 50, 20, A_16BIT|A_SLC |A_SMALL|S_NOR|S_CB },
++ // [128MB] HY27UA081G1M
++ { 0xAD, 0x79, 0x00, 0x00, 0x00, 0x00, 8192, 20, 32, 512, 16, 1, 3, 60, 0, 40, 15, 0, 40, 15, A_08BIT|A_SLC |A_SMALL|S_NOR|S_CB },
++ // [128MB] HY27UF081G2M, HY27UF081G2A
++ { 0xAD, 0xF1, 0x00, 0x00, 0x00, 0x00, 1024, 20, 64, 2048, 64, 2, 2, 50, 0, 35, 20, 0, 35, 20, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [256MB] HY27UF082G2M, HY27UG082G2M
++ { 0xAD, 0xDA, 0x80, 0x15, 0x00, 0x00, 2048, 20, 64, 2048, 64, 2, 3, 50, 0, 35, 20, 0, 35, 20, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [256MB] HY27UF082G2A
++ { 0xAD, 0xDA, 0x80, 0x1D, 0x00, 0x00, 2048, 20, 64, 2048, 64, 2, 3, 50, 0, 35, 20, 0, 35, 20, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [256MB] HY27UF082G2B
++ { 0xAD, 0xDA, 0x10, 0x95, 0x44, 0x00, 2048, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_SLC |A_BIG |S_NOR|S_MP },
++ // [512MB] HY27UF084G2M
++ { 0xAD, 0xDC, 0x80, 0x95, 0x00, 0x00, 4096, 20, 64, 2048, 64, 2, 3, 30, 0, 20, 10, 0, 20, 10, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [512MB] HY27UF084G2B
++ { 0xAD, 0xDC, 0x10, 0x95, 0x00, 0x00, 4096, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_MP },
++ // [512MB] HY27UG084G2M, HY27UH084G2M
++ { 0xAD, 0xDC, 0x80, 0x15, 0x00, 0x00, 4096, 20, 64, 2048, 64, 2, 3, 60, 0, 35, 20, 0, 35, 20, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [512MB] HY27UT084G2M
++ { 0xAD, 0xDC, 0x84, 0x25, 0x00, 0x00, 2048, 40, 128, 2048, 64, 2, 3, 50, 0, 35, 15, 0, 35, 15, A_08BIT|A_MLC |A_BIG |S_NOR },
++ // [512MB] HY27UT084G2A
++ { 0xAD, 0xDC, 0x14, 0xA5, 0x24, 0x00, 2048, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [ 1GB] HY27UH088G2M
++ { 0xAD, 0xD3, 0x80, 0x15, 0x00, 0x00, 8192, 20, 64, 2048, 64, 2, 3, 60, 0, 35, 20, 0, 35, 20, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [ 1GB] HY27UG088G2M [ 2GB] HY27UH08AG5M
++ { 0xAD, 0xD3, 0xC1, 0x95, 0x00, 0x00, 8192, 20, 64, 2048, 64, 2, 3, 30, 0, 20, 10, 0, 20, 10, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [ 1GB] H27U8G8F2M
++ { 0xAD, 0xD3, 0x10, 0xA6, 0x34, 0x00, 4096, 20, 64, 4096, 128, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_SLC |A_BIG |S_NOR|S_MP },
++ // [ 1GB] HY27UU088G2M
++ { 0xAD, 0xD3, 0x85, 0x25, 0x00, 0x00, 4096, 40, 128, 2048, 64, 2, 3, 50, 0, 35, 15, 0, 35, 15, A_08BIT|A_MLC |A_BIG |S_NOR },
++ // [ 1GB] HY27UT088G2M [ 2GB] HY27UU08AG5M
++ { 0xAD, 0xD3, 0x14, 0xA5, 0x64, 0xAD, 4096, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [ 1GB] HY27UT088G2A
++ { 0xAD, 0xD3, 0x14, 0xA5, 0x34, 0x00, 4096, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [ 4GB] HY27UV08BG5M [ 8GB] HY27UW08CGFM
++ { 0xAD, 0xD5, 0x55, 0xA5, 0x68, 0x00, 8192, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [ 4GB] HY27UV08BG5A
++ { 0xAD, 0xD5, 0x55, 0xA5, 0x38, 0x00, 8192, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [ 2GB] HY27UAG8T2MTR
++ { 0xAD, 0xD5, 0x14, 0xB6, 0x44, 0x00, 4096, 25, 128, 4096, 128, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [ 8GB] HY27UCG8V5MTR
++ { 0xAD, 0xD7, 0x55, 0xB6, 0x48, 0x00, 8192, 25, 128, 4096, 128, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP }
++};
++
++const NAND_IO_FEATURE ST_NAND_DevInfo[] =
++{
++ //*=======================================================================================================================================================
++ //*[ DEVICE CODE ][ SIZE ][ Cycle ][ ATTRIBUTE ]
++ //*-------------------------------------------------------------------------------------------------------------------------------------------------------
++ //* 1st, 2nd, 3rd, 4th, 5th, 6th, PBpV,BBpZ, PpB, Page,Spare,Col,Low,Twc, Ws, Wp, Wh, Rs, Rp, Rh
++ //*=======================================================================================================================================================
++ // [ 32MB] NAND256W3A
++ { 0x20, 0x75, 0x00, 0x00, 0x00, 0x00, 2048, 20, 32, 512, 16, 1, 2, 50, 0, 35, 15, 0, 35, 15, A_08BIT|A_SLC |A_SMALL|S_NOR },
++ // [ 64MB] NAND512W3A
++ { 0x20, 0x76, 0x00, 0x00, 0x00, 0x00, 4096, 20, 32, 512, 16, 1, 3, 50, 0, 35, 15, 0, 35, 15, A_08BIT|A_SLC |A_SMALL|S_NOR },
++ // [128MB] NAND01GW3A
++ { 0x20, 0x79, 0x00, 0x00, 0x00, 0x00, 8192, 20, 32, 512, 16, 1, 3, 50, 0, 35, 20, 0, 25, 20, A_08BIT|A_SLC |A_SMALL|S_NOR|S_CB|S_CP },
++ // [128MB] NAND01GW3B2C
++ { 0x20, 0xF1, 0x00, 0x1D, 0x00, 0x00, 1024, 20, 64, 2048, 64, 2, 2, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_SLC |A_BIG |S_NOR },
++ // [128MB] NAND01GW3B
++ { 0x20, 0xF1, 0x00, 0x00, 0x00, 0x00, 1024, 20, 64, 2048, 64, 2, 2, 50, 0, 35, 20, 0, 35, 20, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [256MB] NAND02GW3B2D
++ { 0x20, 0xDA, 0x10, 0x95, 0x44, 0x00, 2048, 20, 64, 2048, 64, 2, 3, 45, 0, 25, 20, 0, 25, 20, A_08BIT|A_SLC |A_BIG |S_NOR|S_MP },
++ // [256MB] NAND02GW3B
++ { 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 2048, 20, 64, 2048, 64, 2, 3, 50, 0, 35, 20, 0, 35, 20, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [512MB] NAND04GW3B2D
++ { 0x20, 0xDC, 0x10, 0x95, 0x54, 0x00, 4096, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_SLC |A_BIG |S_NOR|S_MP },
++ // [512MB] NAND04GW3B
++ { 0x20, 0xDC, 0x80, 0x95, 0x00, 0x00, 4096, 20, 64, 2048, 64, 2, 3, 50, 0, 35, 20, 0, 35, 20, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [512MB] NAND04GW3C2A
++ { 0x20, 0xDC, 0x84, 0x25, 0x00, 0x00, 2048, 40, 128, 2048, 64, 2, 3, 60, 0, 40, 20, 0, 40, 20, A_08BIT|A_MLC |A_BIG |S_NOR },
++ // [ 1GB] NAND08GW3B2CN6
++ { 0x20, 0xD3, 0x51, 0x95, 0x58, 0x00, 8192, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_SLC |A_BIG |S_NOR|S_MP|S_IL },
++ // [ 1GB] NAND08GW3B
++ { 0x20, 0xD3, 0x85, 0x25, 0x00, 0x00, 8192, 20, 64, 2048, 64, 2, 3, 50, 0, 35, 15, 0, 35, 15, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [ 1GB] NAND08GW3C2A, [ 2GB] NAND16GW3C4A
++ { 0x20, 0xD3, 0x14, 0xA5, 0x00, 0x00, 4096, 20, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP }
++};
++
++const NAND_IO_FEATURE SAMSUNG_NAND_DevInfo[] =
++{
++ //*=======================================================================================================================================================
++ //*[ DEVICE CODE ][ SIZE ][ Cycle ][ ATTRIBUTE ]
++ //*-------------------------------------------------------------------------------------------------------------------------------------------------------
++ //* 1st, 2nd, 3rd, 4th, 5th, 6th, PBpV,BBpZ, PpB, Page,Spare,Col,Low,Twc, Ws, Wp, Wh, Rs, Rp, Rh
++ //*=======================================================================================================================================================
++ // [ 32MB] K9F5608U0B/C/D ~TEST(C) ~TEST(D)
++ { 0xEC, 0x75, 0x00, 0x00, 0x00, 0x00, 2048, 20, 32, 512, 16, 1, 2, 50, 0, 35, 15, 0, 35, 15, A_08BIT|A_SLC |A_SMALL|S_NOR|S_CB },
++ // [ 64MB] K9F1208U0M/A/B
++ { 0xEC, 0x76, 0xA5, 0xC0, 0x00, 0x00, 4096, 20, 32, 512, 16, 1, 3, 50, 0, 35, 15, 0, 35, 15, A_08BIT|A_SLC |A_SMALL|S_NOR|S_CB },
++ // [ 64MB] K9F1208U0C: ~TEST(C) WC: 42 WP: 21 WH: 15
++ { 0xEC, 0x76, 0x5A, 0x3F, 0x00, 0x00, 4096, 20, 32, 512, 16, 1, 3, 50, 0, 35, 15, 0, 35, 15, A_08BIT|A_SLC |A_SMALL|S_NOR },
++ // [128MB] K9K1G08U0M/A/B: ~TEST(B)
++ { 0xEC, 0x79, 0xA5, 0xC0, 0x00, 0x00, 8192, 20, 32, 512, 16, 1, 3, 50, 0, 35, 15, 0, 35, 15, A_08BIT|A_SLC |A_SMALL|S_NOR|S_CB },
++ // [128MB] K9F1G08U0M,A
++ { 0xEC, 0xF1, 0x80, 0x15, 0x40, 0x00, 1024, 20, 64, 2048, 64, 2, 2, 50, 0, 35, 15, 0, 35, 15, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [128MB] K9F1G08U0B
++ { 0xEC, 0xF1, 0x00, 0x95, 0x40, 0x00, 1024, 20, 64, 2048, 64, 2, 2, 50, 0, 35, 15, 0, 35, 15, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB },
++ // [256MB] KBE00S00AB MCP MEMORY - Supply Voltage: Vcc 2.5 ~ 2.9
++ { 0xEC, 0x71, 0x5A, 0x3F, 0x00, 0x00,16384, 20, 32, 512, 16, 1, 3, 50, 0, 35, 15, 0, 35, 15, A_08BIT|A_SLC |A_SMALL|S_NOR },
++ // [256MB] K9F2G08U0M, K9K2G08U0M/A ~TEST(A)
++ { 0xEC, 0xDA, 0x00, 0x15, 0x00, 0x00, 2048, 20, 64, 2048, 64, 2, 3, 50, 0, 35, 15, 0, 35, 15, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [256MB] K9F2G08U0A
++ { 0xEC, 0xDA, 0x10, 0x95, 0x44, 0x00, 2048, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_SLC |A_BIG |S_NOR|S_MP },
++ // [512MB] K9K4G08U0M
++ { 0xEC, 0xDC, 0xC1, 0x15, 0x00, 0x00, 4096, 20, 64, 2048, 64, 2, 3, 30, 0, 20, 10, 0, 20, 10, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [512MB] K9F4G08U0M
++ { 0xEC, 0xDC, 0x10, 0x95, 0x00, 0x00, 4096, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB },
++ // [256MB] K9G2G08U0M
++ { 0xEC, 0xDA, 0x14, 0x25, 0x44, 0x00, 1024, 25, 128, 2048, 64, 2, 3, 30, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [512MB] K9G4G08U0M/A [ 1GB] K9L8G08U1M
++ { 0xEC, 0xDC, 0x14, 0x25, 0x54, 0x00, 2048, 40, 128, 2048, 64, 2, 3, 30, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [512MB] K9G4G08U0B
++ { 0xEC, 0xDC, 0x14, 0xA5, 0x54, 0x00, 2048, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [ 1GB] K9K8G08UOM [ 2GB] K9WAG08U1M
++ { 0xEC, 0xD3, 0x51, 0x95, 0x00, 0x00, 8192, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB },
++ // [ 1GB] K9L8G08UOM [ 2GB] K9HAG08U1M
++ { 0xEC, 0xD3, 0x55, 0x25, 0x00, 0x00, 4096, 40, 128, 2048, 64, 2, 3, 35, 0, 25, 10, 0, 25, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP|S_IL },
++ // [ 1GB] K9G8G08UOM [ 2GB] K9LAG08U1M
++ { 0xEC, 0xD3, 0x14, 0x25, 0x64, 0x00, 4096, 40, 128, 2048, 64, 2, 3, 35, 0, 25, 10, 0, 25, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [ 1GB] K9G8G08UOA/B [ 2GB] K9LAG08U1A
++ { 0xEC, 0xD3, 0x14, 0xA5, 0x64, 0x00, 4096, 25, 128, 2048, 64, 2, 3, 50, 0, 30, 20, 0, 30, 20, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [ 2GB] K9LAG08UOM [ 4GB] K9HBG08U1M [ 8GB] K9MCG08U5M
++ { 0xEC, 0xD5, 0x55, 0x25, 0x68, 0x00, 8192, 40, 128, 2048, 64, 2, 3, 30, 0, 20, 10, 0, 20, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP|S_IL },
++ // [ 2GB] K9LAG08UOA/B
++ { 0xEC, 0xD5, 0x55, 0xA5, 0x68, 0x00, 8192, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP|S_IL },
++ // [ 2GB] K9GAG08UOM // 4K Page
++ { 0xEC, 0xD5, 0x14, 0xB6, 0x74, 0x00, 4096, 25, 128, 4096, 128, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [ 4GB] K9LBG08UOM [ 8GB] K9HCG08U1M [ 16G] K9MDG08U5M
++ { 0xEC, 0xD7, 0x55, 0xB6, 0x78, 0x00, 8192, 25, 128, 4096, 128, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP|S_IL },
++ // [ 2GB] K9GAG08UOD [ 4GB] K9LBG08U1D [ 8GB] K9HCG08U5D
++ { 0xEC, 0xD5, 0x94, 0x29, 0x34, 0x41, 4096, 25, 128, 4096, 218, 2, 3, 30, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MCP },
++ // [ 4GB] K9LBG08UOD [ 8GB] K9HCG08U1D [ 16G] K9MDG08U5D [ 32G] K9PDG08U5D
++ { 0xEC, 0xD7, 0xD5, 0x29, 0x38, 0x41, 8192, 25, 128, 4096, 218, 2, 3, 30, 0, 20, 10, 0, 20, 10, A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP|S_IL }
++};
++
++const NAND_IO_FEATURE MICRON_NAND_DevInfo[] =
++{
++ //*=======================================================================================================================================================
++ //*[ DEVICE CODE ][ SIZE ][ Cycle ][ ATTRIBUTE ]
++ //*-------------------------------------------------------------------------------------------------------------------------------------------------------
++ //* 1st, 2nd, 3rd, 4th, 5th, 6th, PBpV,BBpZ, PpB, Page,Spare,Col,Low,Twc, Ws, Wp, Wh, Rs, Rp, Rh
++ //*=======================================================================================================================================================
++ // [256MB] 29F2G08AAC
++ { 0x2C, 0xDA, 0x00, 0x00, 0x00, 0x00, 2048, 20, 64, 2048, 64, 2, 3, 30, 0, 25, 15, 0, 25, 15, A_08BIT|A_SLC |A_BIG |S_NOR|S_CP },
++ // [512MB] 29F4G08BAC, [ 1GB] 29F8G08FAC
++ { 0x2C, 0xDC, 0x80, 0x15, 0x50, 0x00, 4096, 20, 64, 2048, 64, 2, 3, 30, 0, 25, 15, 0, 25, 15, A_08BIT|A_SLC |A_BIG |S_NOR|S_CP },
++ // [512MB] 29F4G08AAA/C [ 1GB] 29F8G08DAA
++ { 0x2C, 0xDC, 0x90, 0x95, 0x54, 0x00, 4096, 20, 64, 2048, 64, 2, 3, 30, 0, 25, 15, 0, 25, 15, A_08BIT|A_SLC |A_BIG |S_NOR|S_MP },
++ // [ 2GB] 29F16G08FAA
++ { 0x2C, 0xD3, 0xD1, 0x95, 0x58, 0x00, 8192, 20, 64, 2048, 64, 2, 3, 30, 0, 25, 15, 0, 25, 15, A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP },
++ // [ 1GB] 29F08G08MAA [ 2GB] 29F16G08QAA
++ { 0x2C, 0xD3, 0x94, 0xA5, 0x64, 0x00, 4096, 40, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [ 4GB] 29F32G08TAA
++ { 0x2C, 0xD5, 0xD5, 0xA5, 0x68, 0x00, 8192, 40, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC |A_BIG |S_NOR|S_MP },
++ // [ 2GB] 29F16G08MAA [ 4GB] 29F32G08QAA
++ { 0x2C, 0xD5, 0x94, 0x3E, 0x74, 0x00, 4096, 25, 128, 4096, 218, 2, 3, 30, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP },
++ // [ 8GB] 29F64G08TAA
++ { 0x2C, 0xD7, 0xD5, 0x3E, 0x78, 0x00, 8192, 25, 128, 4096, 218, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP|S_IL },
++ // [ 4GB] 29F32G08CBAAA, [ 8GB] 29F64G08CFAAA
++ { 0x2C, 0xD7, 0x94, 0x3E, 0x84, 0x00, 8192, 25, 128, 4096, 218, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC_12BIT |A_BIG |S_NOR|S_MCP },
++ // [ 16GB] 29F128G08CJAA
++ { 0x2C, 0xD9, 0xD5, 0x3E, 0x88, 0x00,16384, 25, 128, 4096, 218, 2, 3, 25, 0, 15, 10, 0, 15, 10, A_08BIT|A_MLC_12BIT |A_BIG |S_NOR|S_MP|S_IL }
++};
++
++const NAND_IO_MAKERINFO NAND_SupportMakerInfo =
++ {
++ // MAXIMUM SUPPORT NANDFLASH
++ MAX_SUPPORT_SAMSUNG_NAND,
++ MAX_SUPPORT_TOSHIBA_NAND,
++ MAX_SUPPORT_HYNIX_NAND,
++ MAX_SUPPORT_ST_NAND,
++ MAX_SUPPORT_MICRON_NAND,
++ // NAND MAKER ID
++ SAMSUNG_NAND_MAKER_ID,
++ TOSHIBA_NAND_MAKER_ID,
++ HYNIX_NAND_MAKER_ID,
++ ST_NAND_MAKER_ID,
++ MICRON_NAND_MAKER_ID,
++ // POINTER OF NANDFLASH INFOMATION
++ (NAND_IO_FEATURE*)SAMSUNG_NAND_DevInfo,
++ (NAND_IO_FEATURE*)TOSHIBA_NAND_DevInfo,
++ (NAND_IO_FEATURE*)HYNIX_NAND_DevInfo,
++ (NAND_IO_FEATURE*)ST_NAND_DevInfo,
++ (NAND_IO_FEATURE*)MICRON_NAND_DevInfo
++};
++
++const NAND_IO_LBA_MAKERINFO LBA_NAND_SupportMakerInfo =
++ {
++ // MAXIMUM SUPPORT NANDFLASH
++ MAX_SUPPORT_TOSHIBA_LBA_NAND,
++ // NAND MAKER ID
++ TOSHIBA_NAND_MAKER_ID,
++ // POINTER OF NANDFLASH INFOMATION
++ (NAND_IO_FEATURE*)TOSHIBA_LBA_NAND_DevInfo
++};
++
++const unsigned char NAND_LBA_VFP_AREA_Signature[] =
++{
++ "NANDLBASIGNATURE"
++};
++
++#define NAND_IO_MAX_SHIFT_FACTOR_FOR_MULTIPLY 16
++const unsigned short int NAND_IO_ShiftFactorForMultiplay[NAND_IO_MAX_SHIFT_FACTOR_FOR_MULTIPLY] =
++{
++ 1, // 1 = 2^0
++ 2, // 2 = 2^1
++ 4, // 4 = 2^2
++ 8, // 8 = 2^3
++ 16, // 16 = 2^4
++ 32, // 32 = 2^5
++ 64, // 64 = 2^6
++ 128, // 128 = 2^7
++ 256, // 256 = 2^8
++ 512, // 512 = 2^9
++ 1024, // 1024 = 2^10
++ 2048, // 2048 = 2^11
++ 4096, // 4096 = 2^12
++ 8192, // 8192 = 2^13
++ 16384, // 16384 = 2^14
++ 32768 // 32768 = 2^15
++};
++
++const unsigned char ALL_FF_ECC_BCH_04BIT_12[30] =
++{
++ 0x48,0xF6,0x3C,0xC9,0xAA,
++ 0x45,0x03,0x00,0x00,0x00,
++
++ 0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,
++
++ 0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00
++};
++
++// BCH 4bit Code: 6.5 Byte
++const unsigned char ALL_FF_ECC_BCH_04BIT_512[30] =
++{
++ 0xEB,0x37,0xCC,0x63,0x96,
++ 0xCA,0x01,0x00,0x00,0x00,
++
++ 0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,
++
++ 0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00
++};
++
++// BCH 8bit Code: 13 Byte
++const unsigned char ALL_FF_ECC_BCH_08BIT_512[30] =
++{
++ 0x08,0x75,0x8B,0x6F,0x48,
++ 0x36,0xA6,0xBC,0x16,0x61,
++ 0x58,0xDB,0x52,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,
++
++ 0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00
++};
++
++// BCH 12bit Code: 19.5 Byte
++const unsigned char ALL_FF_ECC_BCH_12BIT_512[30] =
++{
++ 0x81,0xEC,0xE8,0x4E,0xE3,
++ 0x46,0x44,0xA1,0x3F,0x8A,
++ 0x29,0x06,0xD0,0x90,0x06,
++ 0x76,0x21,0x32,0x3E,0x0F,
++ 0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00
++};
++
++// BCH 14bit Code: 23 Byte
++const unsigned char ALL_FF_ECC_BCH_14BIT_512[25] =
++{
++ 0xFF,0xFF,0xFF,0xFF,0xFF,
++ 0xFF,0xFF,0xFF,0xFF,0xFF,
++ 0xFF,0xFF,0xFF,0xFF,0xFF,
++ 0xFF,0xFF,0xFF,0xFF,0xFF,
++ 0xFF,0xFF,0xFF,0xFF,0xFF
++};
++
++// BCH 16bit Code: 26 Byte
++const unsigned char ALL_FF_ECC_BCH_16BIT_512[30] =
++{
++ 0xFF,0xFF,0xFF,0xFF,0xFF,
++ 0xFF,0xFF,0xFF,0xFF,0xFF,
++ 0xFF,0xFF,0xFF,0xFF,0xFF,
++ 0xFF,0xFF,0xFF,0xFF,0xFF,
++ 0xFF,0xFF,0xFF,0xFF,0xFF,
++ 0xFF,0xFF,0xFF,0xFF,0xFF
++};
++
++//=============================================================================
++//*
++//*
++//* [ GLOBAL VARIABLE DEFINE ]
++//*
++//*
++//=============================================================================
++NAND_IO_CYCLE WriteCycleTime;
++NAND_IO_CYCLE ReadCycleTime;
++NAND_IO_CYCLE CommCycleTime;
++unsigned int gMaxBusClkMHZ;
++unsigned int gCycleTick;
++
++NAND_IO_ECC_INFO gMLC_ECC_4Bit;
++NAND_IO_ECC_INFO gMLC_ECC_8Bit;
++NAND_IO_ECC_INFO gMLC_ECC_12Bit;
++NAND_IO_ECC_INFO gMLC_ECC_14Bit;
++NAND_IO_ECC_INFO gMLC_ECC_16Bit;
++
++
++unsigned int gNAND_IO_DataBusType;
++
++PGPIO pGPIO;
++PNFC pNFC;
++PECC pECC;
++PIOBUSCFG pIOBUSCFG_T;
++#if defined(_WINCE_)
++tSYSTEM_PARAM *pSYS_PARAM;
++#endif
++PGDMANCTRL pNAND_DMA;
++
++unsigned int gInterLeavePageAddr;
++unsigned int gInterLeaveCSNum;
++unsigned short int gInterLeaveIoStatus;
++unsigned int gInterLeaveWriteStatus;
++
++/* Micron Interleaver */
++unsigned int gInterLeaveDie0BlockAddr;
++unsigned int gInterLeaveDie1BlockAddr;
++
++unsigned int gNANDIO_GSELReg;
++unsigned int gNANDIO_GIOCONReg;
++unsigned int gNANDIO_GDATASet;
++unsigned int gNAND_GPIO_ON_OFF = ENABLE;
++
++unsigned int *gpDMA_PhyBuffer0;
++unsigned int *gpDMA_WorkBuffer0;
++unsigned int *gpDMA_PhyBuffer1;
++unsigned int *gpDMA_WorkBuffer1;
++
++NAND_IO_DEVINFO *gDevInfo;
++NAND_IO_DEVINFO rDevInfo;
++
++#if defined(TCC89XX) || defined(TCC92XX)
++int gDRV_GDMA_Handle_NAND;
++sDRV_GDMA gDRV_GDMA_NAND =
++{
++ 0 | DRV_GDMA_CFG_StartByHwReqLevel
++ | DRV_GDMA_CFG_AckAtRead
++ | DRV_GDMA_CFG_Arbitration//| DRV_GDMA_CFG_NoArbitration
++ | DRV_GDMA_CFG_BufNum_1
++ | DRV_GDMA_CFG_1HopUnit_16Byte
++ | DRV_GDMA_CFG_ReadBW_32Bit
++ | DRV_GDMA_CFG_WriteBW_32Bit
++ , DRV_GDMA_HwREQ_NFC
++ , 0,
++};
++#endif
++
++//#define SPEED_CHECK
++#if defined(SPEED_CHECK)
++//#define READ_SPEED_CHECK
++//#define WRITE_SPEED_CHECK
++#endif
++
++#if defined(_WINCE_)
++#pragma pack(8)
++unsigned char gNAND_IO_ShareEccBuffer[ 512 ];
++#pragma pack()
++#elif defined(_LINUX_)
++unsigned char gNAND_IO_ShareEccBuffer[ 512 ] __attribute__((aligned(8)));
++#else
++__align(8) unsigned char gNAND_IO_ShareEccBuffer[ 512 ];
++#endif
++
++NAND_LBA_CALLBACK_HANDLER NAND_IO_LBA_CallBackLcdDisplay;
++
++//=============================================================================
++//*
++//*
++//* [ LOCAL FUNCTIONS DEFINE ]
++//*
++//*
++//=============================================================================
++static __inline void NAND_IO_SetDataWidth( U32 width );
++static __inline void NAND_IO_PreProcess( void );
++static __inline void NAND_IO_PostProcess( void );
++static __inline void NAND_IO_SetBasicCycleTime( void );
++static __inline void NAND_IO_SetCommCycleTime( void );
++static __inline void NAND_IO_SetWriteCycleTime(void);
++static __inline void NAND_IO_SetReadCycleTime(void);
++static __inline void NAND_IO_EnableChipSelect( U16 nChipNo );
++static __inline void NAND_IO_DisableChipSelect( void );
++static __inline void NAND_IO_EnableWriteProtect( void );
++static __inline void NAND_IO_DisableWriteProtect( void );
++static __inline U32 NAND_IO_CheckReadyAndBusy( U16 nChipNo);
++static __inline void NAND_IO_WaitBusy( U16 nChipNo );
++static __inline void NAND_IO_WaitBusyForProgramAndErase( NAND_IO_DEVINFO *nDevInfo );
++static __inline void NAND_IO_WaitBusyForCacheProgram( NAND_IO_DEVINFO *nDevInfo );
++
++static __inline void NAND_IO_ClearInterleaveStatus( NAND_IO_DEVINFO *nDevInfo );
++static __inline void NAND_IO_SetInterleaveStatus( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr );
++
++static __inline void NAND_IO_Delay( void );
++
++static __inline NAND_IO_ERROR NAND_IO_WaitBusyForInterleave( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr );
++static __inline NAND_IO_ERROR NAND_IO_ReadStatus( NAND_IO_DEVINFO *nDevInfo );
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForMultiPlane( NAND_IO_DEVINFO *nDevInfo );
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForCacheProgram( NAND_IO_DEVINFO *nDevInfo );
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForInterleave( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr );
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForInterleaveClear( NAND_IO_DEVINFO *nDevInfo );
++
++static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForRead( U32 nPageAddr, U16 nColumnAddr, U32* rRowAddr, U32* rColumnAddr, NAND_IO_DEVINFO *nDevInfo );
++static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForWrite( U32 nPageAddr, U16 nColumnAddr, U32* rRowAddr, U32* rColumnAddr, NAND_IO_DEVINFO *nDevInfo );
++static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForCBandCP( U32 nPageAddr, U16 nColumnAddr, U32* rRowAddr, U32* rColumnAddr, NAND_IO_DEVINFO *nDevInfo );
++static __inline void NAND_IO_WriteRowColAddr( U32 nRowAddr, U32 nColumnAddr, NAND_IO_DEVINFO *nDevInfo );
++static __inline void NAND_IO_WriteColAddr( U32 nColumnAddr, NAND_IO_DEVINFO *nDevInfo );
++static __inline void NAND_IO_WriteBlockPageAddr( U32 nBlockPageAddr, NAND_IO_DEVINFO *nDevInfo );
++static __inline void NAND_IO_SetNFCBusWidth( NAND_IO_DEVINFO *nDevInfo );
++
++#if defined(NAND_IO_USE_DMA_ACCESS)
++static __inline void NAND_IO_SetupDMA(void * pSRC, unsigned uSrcInc, unsigned uSrcMask, void * pDST, unsigned uDstInc, unsigned uDstMask, int nMode, int nDSize );
++static __inline void NAND_IO_SetupDMADoubleBuf( int nMode, int nDMACh );
++#endif
++static __inline void NAND_IO_SetupECC( U16 nEccOnOff, U16 nEncDec, U16 nEccType, U16 nAccessType, U32 EccBaseAddr );
++
++static __inline NAND_IO_ERROR NAND_IO_EncodeECC( U16 nEccType, U8* nSpareBuffer );
++static __inline NAND_IO_ERROR NAND_IO_EncodeNBECC( U16 nEccType, U8* nSpareBuffer );
++
++static __inline NAND_IO_ERROR NAND_IO_CorrectionSLC( U8* nPageBuffer, U8* nSpareBuffer );
++static __inline NAND_IO_ERROR NAND_IO_CorrectionSLCForNB( U8* nPageBuffer, U8* nSpareBuffer );
++static __inline NAND_IO_ERROR NAND_IO_CorrectionMLC( U16 nEccType, U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize );
++static __inline NAND_IO_ERROR NAND_IO_CorrectionMLCForNB( U8* nPageBuffer, U8* nSpareBuffer );
++static __inline NAND_IO_ERROR NAND_IO_CorrectionMLCForCB( U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize, U16 nBufferMode );
++static __inline NAND_IO_ERROR NAND_IO_CorrectionMLC8ForCB( U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize, U16 nBufferMode );
++static __inline NAND_IO_ERROR NAND_IO_CorrectionMLC12ForCB( U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize, U16 nBufferMode );
++
++static __inline NAND_IO_ERROR NAND_IO_EncodeChainData( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, U8 *nSpareBuffer, int nMode, int nEccOnOff );
++static __inline NAND_IO_ERROR NAND_IO_DecodeChainData( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, U8 *nSpareBuffer, int nMode, int nEccOnOff );
++static __inline NAND_IO_ERROR NAND_IO_EncodeChainDataForGoldenPage( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++static __inline NAND_IO_ERROR NAND_IO_DecodeChainDataForGoldenPage( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++
++static __inline NAND_IO_ERROR NAND_IO_ReadSpareData( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize, U8 *nSpareBuffer );
++static __inline NAND_IO_ERROR NAND_IO_ReadSpareDataECC( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nEccOnOff );
++static __inline NAND_IO_ERROR NAND_IO_ReadSpareDataMTD( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nEccOnOff );
++static __inline NAND_IO_ERROR NAND_IO_Read512DataDoubleBuf( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff, int nSpareOnOff );
++static __inline NAND_IO_ERROR NAND_IO_Read512Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff, int nSpareOnOff );
++static __inline NAND_IO_ERROR NAND_IO_Read528Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++static __inline NAND_IO_ERROR NAND_IO_Read512DataMTD( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff, int nSpareOnOff );
++static __inline NAND_IO_ERROR NAND_IO_ReadUserSizeData( NAND_IO_DEVINFO *nDevInfo, U16 nColumnAddr, U32 nReadSize, U8 *nReadBuffer );
++
++static __inline NAND_IO_ERROR NAND_IO_WriteSpareData( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nEccOnOff );
++static __inline NAND_IO_ERROR NAND_IO_Write512DataDoubleBuf( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++static __inline NAND_IO_ERROR NAND_IO_Write512Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++static __inline NAND_IO_ERROR NAND_IO_Write528Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++static __inline NAND_IO_ERROR NAND_IO_Write512DataMTD( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++
++static __inline NAND_IO_ERROR NAND_IO_WriteUserSizeData( NAND_IO_DEVINFO *nDevInfo, U16 nColumnAddr, U32 nWriteSize, U8 *nWriteBuffer );
++
++static __inline NAND_IO_ERROR NAND_IO_GetShiftValueForFastMultiPly( U16 nValue, U16* rFactor );
++
++static __inline NAND_IO_ERROR NAND_IO_LBA_ReadData( NAND_IO_DEVINFO *nDevInfo, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer );
++static __inline NAND_IO_ERROR NAND_IO_LBA_WriteData( NAND_IO_DEVINFO *nDevInfo, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer );
++static __inline NAND_IO_ERROR NAND_IO_LBA_WriteDummyData( NAND_IO_DEVINFO *nDevInfo, U16 nWritePPSize );
++
++NAND_IO_ERROR NAND_IO_LBA_VFPInitArea( NAND_IO_DEVINFO *nDevInfo );
++NAND_IO_ERROR NAND_IO_LBA_MDPGetTotalSectorSize(NAND_IO_DEVINFO * nDevInfo, unsigned long int * rTotalSector);
++NAND_IO_ERROR NAND_IO_LBA_VFPGetTotalSectorSize(NAND_IO_DEVINFO * nDevInfo, U32 * rTotalSector);
++NAND_IO_ERROR NAND_IO_LBA_VFPChangeSectorSize(NAND_IO_DEVINFO * nDevInfo, U32 nTotalSector);
++NAND_IO_ERROR NAND_IO_LBA_SetTransferProtocol(NAND_IO_DEVINFO * nDevInfo, U8 nProtocol1, U8 nProtocol2);
++NAND_IO_ERROR NAND_IO_LBA_SetBootModeChange( NAND_IO_DEVINFO *nDevInfo, U8 nBootMode );
++NAND_IO_ERROR NAND_IO_LBA_SetRebootCmdChange( NAND_IO_DEVINFO *nDevInfo, U8 nRebootCmd );
++NAND_IO_ERROR NAND_IO_LBA_GetPersistentFunction( NAND_IO_DEVINFO *nDevInfo, U8 *rBootMode, U8 *rRebootCmd );
++NAND_IO_ERROR NAND_IO_LBA_GetTransferProtocol( NAND_IO_DEVINFO *nDevInfo, U8 *rProtocol1, U8 *rProtocol2 );
++NAND_IO_ERROR NAND_IO_LBA_GetBootMode( NAND_IO_DEVINFO *nDevInfo, U8 *rBootMode );
++NAND_IO_ERROR NAND_IO_LBA_HighSpeedMode( NAND_IO_DEVINFO *nDevInfo, int nOnOff );
++NAND_IO_ERROR NAND_IO_LBA_ReadID( NAND_IO_DEVINFO *nDevInfo, NAND_IO_DEVID *nDeviceCode );
++NAND_IO_ERROR NAND_IO_LBA_Reset( NAND_IO_DEVINFO *nDevInfo );
++
++//=============================================================================
++//*
++//*
++//* [ EXTERN VARIABLE & FUNCTIONS DEFINE ]
++//*
++//*
++//=============================================================================
++#if defined(_LINUX_) || defined(_WINCE_)
++int TCC7XX_USBDRV_WriteToQueue( void ){ return 0;}
++extern unsigned int gMAX_ROMSIZE;
++#else
++extern void memcpy(void *pvDest, const void *pvSrc, unsigned long iCount);
++extern void memset(void *pvDest, char cChar, unsigned long iCount);
++extern int memcmp(const void *pvSrc1, const void *pvSrc2, unsigned long iCount);
++extern int TCC7XX_USBDRV_WriteToQueue( void );
++extern unsigned int gMAX_ROMSIZE;
++#endif
++
++#ifndef _LINUX_
++extern unsigned fmemcpy16(void *dest, void *src, unsigned length);
++#endif
++
++#ifdef SPEED_CHECK
++void NAND_IO_GPIO_Toggle( U32 nBitNum )
++{
++ if( pGPIO->GPFDAT & nBitNum )
++ BITCLR(pGPIO->GPFDAT, nBitNum);
++ else
++ BITSET(pGPIO->GPFDAT, nBitNum);
++}
++#endif
++
++#if defined(_WINCE_)
++//extern unsigned int tcc_allocbaseaddress(unsigned int iphysicalbaseaddress, unsigned int isize);
++extern void B_RETAILMSG(const char * fmt, ...);
++#endif
++
++/******************************************************************************
++*
++* unsigned char* NAND_IO_TellLibraryVersion
++*
++* Input : NONE
++* Output : NONE
++* Return : NONE
++*
++* Description :
++*
++*******************************************************************************/
++unsigned char* NAND_IO_TellLibraryVersion( void )
++{
++ return (unsigned char*)NANDIO_Library_Version;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* NAND_IO_ERROR NAND_IO_NANDGPIOControlFlag( unsigned int on_off );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* on_off =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++NAND_IO_ERROR NAND_IO_NANDGPIOControlFlag( unsigned int on_off )
++{
++ gNAND_GPIO_ON_OFF = on_off;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_CallBackChangeWCtime
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_CallBackChangeWCtime( unsigned short int TotalMediaNum, NAND_IO_DEVINFO *nDevInfo )
++{
++ if ( nDevInfo->IoStatus == ENABLE )
++ {
++ //**************************************************************
++ // Case on K9NBG08U5M Samsung NANDFLASH
++ //**************************************************************
++ if ( nDevInfo->Feature.DeviceID.Code[0] == 0xEC &&
++ nDevInfo->Feature.DeviceID.Code[1] == 0xD3 &&
++ nDevInfo->Feature.DeviceID.Code[2] == 0x51 &&
++ nDevInfo->Feature.DeviceID.Code[3] == 0x95 )
++ {
++ if ( TotalMediaNum == 4 )
++ {
++ nDevInfo->Feature.WCtime = 45;
++
++ nDevInfo->Feature.WriteSTP = 0;
++ nDevInfo->Feature.WriteWP = 30;
++ nDevInfo->Feature.WriteHLD = 15;
++
++ nDevInfo->Feature.ReadSTP = 0;
++ nDevInfo->Feature.ReadPW = 30;
++ nDevInfo->Feature.ReadHLD = 15;
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ }
++ //**************************************************************
++ // Case on K9MBG08U5M Samsung NANDFLASH
++ //**************************************************************
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == 0xEC &&
++ nDevInfo->Feature.DeviceID.Code[1] == 0xD3 &&
++ nDevInfo->Feature.DeviceID.Code[2] == 0x55 &&
++ nDevInfo->Feature.DeviceID.Code[3] == 0x25 )
++ {
++ if ( TotalMediaNum == 4 )
++ {
++ nDevInfo->Feature.WCtime = 45;
++
++ nDevInfo->Feature.WriteSTP = 0;
++ nDevInfo->Feature.WriteWP = 30;
++ nDevInfo->Feature.WriteHLD = 15;
++
++ nDevInfo->Feature.ReadSTP = 0;
++ nDevInfo->Feature.ReadPW = 30;
++ nDevInfo->Feature.ReadHLD = 15;
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ }
++ //**************************************************************
++ // Case on K9MCG08U5M Samsung NANDFLASH
++ //**************************************************************
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == 0xEC &&
++ nDevInfo->Feature.DeviceID.Code[1] == 0xD5 &&
++ nDevInfo->Feature.DeviceID.Code[2] == 0x55 &&
++ nDevInfo->Feature.DeviceID.Code[3] == 0x25 &&
++ nDevInfo->Feature.DeviceID.Code[4] == 0x68 )
++ {
++ if ( TotalMediaNum == 4 )
++ {
++ nDevInfo->Feature.WCtime = 45;
++
++ nDevInfo->Feature.WriteSTP = 0;
++ nDevInfo->Feature.WriteWP = 30;
++ nDevInfo->Feature.WriteHLD = 15;
++
++ nDevInfo->Feature.ReadSTP = 0;
++ nDevInfo->Feature.ReadPW = 30;
++ nDevInfo->Feature.ReadHLD = 15;
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ }
++ //**************************************************************
++ // Case on K9MDG08U5M Samsung NANDFLASH
++ //**************************************************************
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == 0xEC &&
++ nDevInfo->Feature.DeviceID.Code[1] == 0xD7 &&
++ nDevInfo->Feature.DeviceID.Code[2] == 0x55 &&
++ nDevInfo->Feature.DeviceID.Code[3] == 0xB6 &&
++ nDevInfo->Feature.DeviceID.Code[4] == 0x78 )
++ {
++ if ( TotalMediaNum == 4 )
++ {
++ nDevInfo->Feature.WCtime = 45;
++
++ nDevInfo->Feature.WriteSTP = 0;
++ nDevInfo->Feature.WriteWP = 30;
++ nDevInfo->Feature.WriteHLD = 15;
++
++ nDevInfo->Feature.ReadSTP = 0;
++ nDevInfo->Feature.ReadPW = 30;
++ nDevInfo->Feature.ReadHLD = 15;
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ }
++ //**************************************************************
++ // Case on K9MDG08U5D Samsung NANDFLASH
++ //**************************************************************
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == 0xEC &&
++ nDevInfo->Feature.DeviceID.Code[1] == 0xD7 &&
++ nDevInfo->Feature.DeviceID.Code[2] == 0xD5 &&
++ nDevInfo->Feature.DeviceID.Code[3] == 0x29 &&
++ nDevInfo->Feature.DeviceID.Code[4] == 0x38 )
++ {
++ if ( TotalMediaNum == 2 )
++ {
++ nDevInfo->Feature.WCtime = 45;
++
++ nDevInfo->Feature.WriteSTP = 0;
++ nDevInfo->Feature.WriteWP = 30;
++ nDevInfo->Feature.WriteHLD = 15;
++
++ nDevInfo->Feature.ReadSTP = 0;
++ nDevInfo->Feature.ReadPW = 30;
++ nDevInfo->Feature.ReadHLD = 15;
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ }
++ //**************************************************************
++ // Case on TH58NVG5D4CTG20 Toshiba NANDFLASH
++ //**************************************************************
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == 0x98 &&
++ nDevInfo->Feature.DeviceID.Code[1] == 0xD5 &&
++ nDevInfo->Feature.DeviceID.Code[2] == 0x85 &&
++ nDevInfo->Feature.DeviceID.Code[3] == 0xA5 )
++ {
++ if ( TotalMediaNum == 2 )
++ {
++ nDevInfo->Feature.WCtime = 30;
++
++ nDevInfo->Feature.WriteSTP = 0;
++ nDevInfo->Feature.WriteWP = 20;
++ nDevInfo->Feature.WriteHLD = 10;
++
++ nDevInfo->Feature.ReadSTP = 0;
++ nDevInfo->Feature.ReadPW = 20;
++ nDevInfo->Feature.ReadHLD = 10;
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ }
++ }
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_SetCycle
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_SetCycle( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int nMaxBusClk;
++ unsigned int nMaxBusClkMHZ;
++ unsigned int nCycleTick;
++ unsigned int nTickRange = 10;
++ unsigned int nDevSTP, nDevPW, nDevHLD;
++ unsigned int nMCycleSTP, nMCyclePW, nMCycleHLD;
++ unsigned int nSCycleSTP, nSCyclePW, nSCycleHLD;
++ int nRemainSTP, nRemainPW, nRemainHLD;
++ int nTempResult;
++ unsigned int nReCompRatioSTP, nReCompRatioHLD, nReCompRatioPW;
++ unsigned int nWrCompRatioSTP, nWrCompRatioHLD, nWrCompRatioPW;
++ unsigned int nCoCompRatioSTP, nCoCompRatioHLD, nCoCompRatioPW;
++ unsigned int nReGateDelay, nWrGateDelay;
++
++ //===================================
++ // Get Max Bus CLK
++ //===================================
++ #ifdef FWDN_DOWNLOADER_INCLUDE
++ nMaxBusClk = 1000000; // 100MHZ
++ #elif defined(TCC89XX) || defined(TCC92XX)
++ {
++ #if defined(_WINCE_)
++ #if defined(USE_V_ADDRESS)
++ nMaxBusClk = tcc_ckc_getfbusctrl(CLKCTRL4);
++ #else
++ tca_ckc_init();
++ nMaxBusClk = tca_ckc_getfbusctrl(CLKCTRL4);
++ #endif
++ #elif defined(_LINUX_)
++ tca_ckc_init();
++ nMaxBusClk = tca_ckc_getfbusctrl(CLKCTRL4);
++ #else
++ //#ifdef CLOCK_ADJUST_ENABLE
++ //nMaxBusClk = IO_CKC_GetCurrentBUSClock4Cycle();
++ //#else
++ //nMaxBusClk = IO_CKC_Fmaxbus; // frequency of 100Hz unit
++ //#endif
++ nMaxBusClk = 1660000;
++
++ #endif
++ }
++ #endif
++
++ if ( nMaxBusClk == 0 )
++ nMaxBusClk = 1660000;
++
++ /* Convert MHZ Value of Max Bus Clock */
++ if (!( nMaxBusClk / 10000 ))
++ return ERR_NAND_IO_WRONG_PARAMETER;
++ nMaxBusClkMHZ = ( nMaxBusClk / 10000 );
++
++ /* Get Cycke Tick */
++ nCycleTick = ( 1000 * nTickRange ) / nMaxBusClkMHZ;
++ if (( 1000 * nTickRange ) % nMaxBusClkMHZ )
++ ++nCycleTick;
++
++ //===================================
++ // Set Cycle
++ //===================================
++
++ /* Basis Setting */
++ #if defined(TCC89XX) || defined(TCC92XX)
++ nReGateDelay = 15;
++ nWrGateDelay = 0;
++ #else
++ nReGateDelay = 15;
++ nWrGateDelay = 0;
++ #endif
++
++ nReCompRatioSTP = 6;
++ nReCompRatioHLD = 0;
++ nReCompRatioPW = 0;
++
++ nWrCompRatioSTP = 6;
++ nWrCompRatioHLD = 0;
++ nWrCompRatioPW = 0;
++
++ nCoCompRatioSTP = 0;
++ nCoCompRatioHLD = 0;
++ nCoCompRatioPW = 0;
++
++ /* Read Cycle */
++ nDevSTP = nDevInfo->Feature.ReadSTP * nTickRange;
++ nDevPW = nDevInfo->Feature.ReadPW * nTickRange;
++ nDevHLD = nDevInfo->Feature.ReadHLD * nTickRange;
++
++ nMCycleSTP = ( nDevSTP / nCycleTick ) + (( nDevSTP && !( nDevSTP / nCycleTick )) ? 1 : 0 );
++ nMCycleHLD = ( nDevHLD / nCycleTick ) + (( nDevHLD && !( nDevHLD / nCycleTick )) ? 1 : 0 );
++ nRemainSTP = ( nMCycleSTP * nCycleTick ) - nDevSTP;
++ nRemainHLD = ( nMCycleHLD * nCycleTick ) - nDevHLD;
++ nSCycleSTP = (( nRemainSTP < 0 ) && ((( nRemainSTP >= 0 ) ? nRemainSTP : -nRemainSTP ) > (int)(( nCycleTick / 10 ) * nReCompRatioSTP ))) ? 1 : 0;
++ nSCycleHLD = (( nRemainHLD < 0 ) && ((( nRemainHLD >= 0 ) ? nRemainHLD : -nRemainHLD ) > (int)(( nCycleTick / 10 ) * nReCompRatioHLD ))) ? 1 : 0;
++ nTempResult = ( nDevPW + ( nReGateDelay * nTickRange )) + (( nRemainSTP >= 0 ) ? 0 : -nRemainSTP ) + (( nRemainHLD >= 0 ) ? 0 : -nRemainHLD );
++ nMCyclePW = ( nTempResult >= (int)nCycleTick ) ? ( nTempResult / nCycleTick ) : 1;
++ nRemainPW = ( nMCyclePW * nCycleTick ) - ( nDevPW + ( nReGateDelay * nTickRange ));
++ nSCyclePW = (( nRemainPW < 0 ) && ((( nRemainPW >= 0 ) ? nRemainPW : -nRemainPW ) > (int)(( nCycleTick / 10 ) * nReCompRatioPW ))) ? 1 : 0;
++
++ ReadCycleTime.STP = (U8)(nMCycleSTP + nSCycleSTP);
++ ReadCycleTime.HLD = (U8)(nMCycleHLD + nSCycleHLD);
++ ReadCycleTime.PW = (U8)(nMCyclePW + nSCyclePW + (( nDevInfo->Feature.MediaType & A_PARALLEL ) ? 1: 0 ));
++
++ /* Write Cycle */
++ nDevSTP = nDevInfo->Feature.WriteSTP * nTickRange;
++ nDevPW = nDevInfo->Feature.WriteWP * nTickRange;
++ nDevHLD = nDevInfo->Feature.WriteHLD * nTickRange;
++
++ nMCycleSTP = ( nDevSTP / nCycleTick ) + (( nDevSTP && !( nDevSTP / nCycleTick )) ? 1 : 0 );
++ nMCycleHLD = ( nDevHLD / nCycleTick ) + (( nDevHLD && !( nDevHLD / nCycleTick )) ? 1 : 0 );
++ nRemainSTP = ( nMCycleSTP * nCycleTick ) - nDevSTP;
++ nRemainHLD = ( nMCycleHLD * nCycleTick ) - nDevHLD;
++ nSCycleSTP = (( nRemainSTP < 0 ) && ((( nRemainSTP >= 0 ) ? nRemainSTP : -nRemainSTP ) > (int)(( nCycleTick / 10 ) * nWrCompRatioSTP ))) ? 1 : 0;
++ nSCycleHLD = (( nRemainHLD < 0 ) && ((( nRemainHLD >= 0 ) ? nRemainHLD : -nRemainHLD ) > (int)(( nCycleTick / 10 ) * nWrCompRatioHLD ))) ? 1 : 0;
++ nTempResult = ( nDevPW + ( nWrGateDelay * nTickRange )) + (( nRemainSTP >= 0 ) ? 0 : -nRemainSTP ) + (( nRemainHLD >= 0 ) ? 0 : -nRemainHLD );
++ nMCyclePW = ( nTempResult >= (int)nCycleTick ) ? ( nTempResult / nCycleTick ) : 1;
++ nRemainPW = ( nMCyclePW * nCycleTick ) - ( nDevPW + ( nWrGateDelay * nTickRange ));
++ nSCyclePW = (( nRemainPW < 0 ) && ((( nRemainPW >= 0 ) ? nRemainPW : -nRemainPW ) > (int)(( nCycleTick / 10 ) * nWrCompRatioPW ))) ? 1 : 0;
++
++ WriteCycleTime.STP = (U8)(nMCycleSTP + nSCycleSTP);
++ WriteCycleTime.HLD = (U8)(nMCycleHLD + nSCycleHLD);
++ WriteCycleTime.PW = (U8)(nMCyclePW + nSCyclePW);
++
++ /* Comm Cycle */
++ nDevSTP = 10 * nTickRange;
++ nDevPW = 80 * nTickRange;
++ nDevHLD = 40 * nTickRange;
++
++ nMCycleSTP = ( nDevSTP / nCycleTick ) + (( nDevSTP && !( nDevSTP / nCycleTick )) ? 1 : 0 );
++ nMCycleHLD = ( nDevHLD / nCycleTick ) + (( nDevHLD && !( nDevHLD / nCycleTick )) ? 1 : 0 );
++ nRemainSTP = ( nMCycleSTP * nCycleTick ) - nDevSTP;
++ nRemainHLD = ( nMCycleHLD * nCycleTick ) - nDevHLD;
++ nSCycleSTP = (( nRemainSTP < 0 ) && ((( nRemainSTP >= 0 ) ? nRemainSTP : -nRemainSTP ) > (int)(( nCycleTick / 10 ) * nCoCompRatioSTP ))) ? 1 : 0;
++ nSCycleHLD = (( nRemainHLD < 0 ) && ((( nRemainHLD >= 0 ) ? nRemainHLD : -nRemainHLD ) > (int)(( nCycleTick / 10 ) * nCoCompRatioHLD ))) ? 1 : 0;
++ nTempResult = ( nDevPW + ( nReGateDelay * nTickRange )) + (( nRemainSTP >= 0 ) ? 0 : -nRemainSTP ) + (( nRemainHLD >= 0 ) ? 0 : -nRemainHLD );
++ nMCyclePW = ( nTempResult >= (int)nCycleTick ) ? ( nTempResult / nCycleTick ) : 1;
++ nRemainPW = ( nMCyclePW * nCycleTick ) - ( nDevPW + ( nReGateDelay * nTickRange ));
++ nSCyclePW = (( nRemainPW < 0 ) && ((( nRemainPW >= 0 ) ? nRemainPW : -nRemainPW ) > (int)(( nCycleTick / 10 ) * nCoCompRatioPW ))) ? 1 : 0;
++
++ CommCycleTime.STP = (U8)(nMCycleSTP + nSCycleSTP);
++ CommCycleTime.HLD = (U8)(nMCycleHLD + nSCycleHLD);
++ CommCycleTime.PW = (U8)(nMCyclePW + nSCyclePW);
++
++ if (WriteCycleTime.STP >= 16)
++ WriteCycleTime.STP = 15;
++ if (WriteCycleTime.PW >= 16)
++ WriteCycleTime.PW = 15;
++ if (WriteCycleTime.HLD >= 16)
++ WriteCycleTime.HLD = 15;
++ if (WriteCycleTime.HLD == 0)
++ WriteCycleTime.HLD = 1;
++
++ if (ReadCycleTime.STP >= 16)
++ ReadCycleTime.STP = 15;
++ if (ReadCycleTime.PW >= 16)
++ ReadCycleTime.PW = 15;
++ if (ReadCycleTime.HLD >= 16)
++ ReadCycleTime.HLD = 15;
++
++ if (CommCycleTime.STP >= 16)
++ CommCycleTime.STP = 15;
++ if (CommCycleTime.PW >= 16)
++ CommCycleTime.PW = 15;
++ if (CommCycleTime.HLD >= 16)
++ CommCycleTime.HLD = 15;
++
++ if ( gNAND_IO_DataBusType == NAND_IO_NFC_BUS )
++ {
++ WriteCycleTime.RegValue = ( WriteCycleTime.STP << 8 ) + ( WriteCycleTime.PW << 4 ) + WriteCycleTime.HLD;
++ ReadCycleTime.RegValue = ( ReadCycleTime.STP << 8 ) + ( ReadCycleTime.PW << 4 ) + ReadCycleTime.HLD;
++ CommCycleTime.RegValue = ( CommCycleTime.STP << 8 ) + ( CommCycleTime.PW << 4 ) + CommCycleTime.HLD;
++ }
++ else if ( gNAND_IO_DataBusType == NAND_IO_MEM_BUS )
++ {
++ #if defined(TCC860x)
++ WriteCycleTime.RegValue = ( WriteCycleTime.STP << 6 ) + ( WriteCycleTime.PW << 3 ) + WriteCycleTime.HLD;
++ ReadCycleTime.RegValue = ( ReadCycleTime.STP << 6 ) + ( ReadCycleTime.PW << 3 ) + ReadCycleTime.HLD;
++ CommCycleTime.RegValue = ( CommCycleTime.STP << 6 ) + ( CommCycleTime.PW << 3 ) + CommCycleTime.HLD;
++ #else
++ WriteCycleTime.RegValue = ( WriteCycleTime.STP << 11 ) + (( WriteCycleTime.PW - 1 ) << 3 ) + WriteCycleTime.HLD;
++ ReadCycleTime.RegValue = ( ReadCycleTime.STP << 11 ) + (( ReadCycleTime.PW - 1 ) << 3 ) + ReadCycleTime.HLD;
++ CommCycleTime.RegValue = ( CommCycleTime.STP << 11 ) + (( CommCycleTime.PW - 1 ) << 3 ) + CommCycleTime.HLD;
++ #endif
++ }
++
++//#if defined(USE_V_ADDRESS)
++// #if defined(_LINUX_)
++// printk("[NAND ] [BClk %dMHZ][1Tick %d][RE-S:%d,P:%d,H:%d][WR-S:%d,P:%d,H:%d][COM-S:%d,P:%d,H:%d]\n",
++// nMaxBusClkMHZ,nCycleTick,ReadCycleTime.STP,ReadCycleTime.PW,ReadCycleTime.HLD,
++// WriteCycleTime.STP,WriteCycleTime.PW,WriteCycleTime.HLD,CommCycleTime.STP,CommCycleTime.PW,CommCycleTime.HLD );
++// #elif defined(_WINCE_)
++// RETAILMSG(1,( TEXT("[NAND ] [BClk %dMHZ][1Tick %d][RE-S:%d,P:%d,H:%d][WR-S:%d,P:%d,H:%d][COM-S:%d,P:%d,H:%d]\n"),
++// nMaxBusClkMHZ,nCycleTick,ReadCycleTime.STP,ReadCycleTime.PW,ReadCycleTime.HLD,
++// WriteCycleTime.STP,WriteCycleTime.PW,WriteCycleTime.HLD,CommCycleTime.STP,CommCycleTime.PW,CommCycleTime.HLD));
++// #endif
++//#else
++// #if defined(_LINUX_)
++// printf("[NAND ] [BClk %dMHZ][1Tick %d][RE-S:%d,P:%d,H:%d][WR-S:%d,P:%d,H:%d][COM-S:%d,P:%d,H:%d]\n",
++// nMaxBusClkMHZ,nCycleTick,ReadCycleTime.STP,ReadCycleTime.PW,ReadCycleTime.HLD,
++// WriteCycleTime.STP,WriteCycleTime.PW,WriteCycleTime.HLD,CommCycleTime.STP,CommCycleTime.PW,CommCycleTime.HLD );
++// #elif defined(_WINCE_)
++// B_RETAILMSG("[NAND ] [BClk %dMHZ][1Tick %d][RE-S:%d,P:%d,H:%d][WR-S:%d,P:%d,H:%d][COM-S:%d,P:%d,H:%d]\n",
++// nMaxBusClkMHZ,nCycleTick,ReadCycleTime.STP,ReadCycleTime.PW,ReadCycleTime.HLD,
++// WriteCycleTime.STP,WriteCycleTime.PW,WriteCycleTime.HLD,CommCycleTime.STP,CommCycleTime.PW,CommCycleTime.HLD );
++// #endif
++//#endif
++
++
++ gMaxBusClkMHZ = nMaxBusClkMHZ;
++ gCycleTick = nCycleTick;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_GetDeviceInfo
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_GetDeviceInfo( U16 nChipNo, NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned short int j,k,l;
++ unsigned char bFindMedia;
++ unsigned char bFindMakerNo;
++ unsigned char bMatchCount;
++ NAND_IO_DEVID sDeviceCode1,sDeviceCode2;
++ NAND_IO_FEATURE *sTempFeatureInfo;
++ NAND_IO_FEATURE *sFindFeatureInfo;
++ NAND_IO_ERROR res;
++
++ bFindMedia = FALSE;
++ nDevInfo->IoStatus = 0;
++ nDevInfo->ChipNo = 0xFF;
++ gInterLeaveCSNum = 0;
++ gInterLeaveIoStatus = 0;
++ gInterLeaveWriteStatus = MULTI_PLANE_GOOD_BLOCK;
++
++ // Init Variable
++ sTempFeatureInfo = (NAND_IO_FEATURE*)NAND_SupportMakerInfo.DevInfo[0];
++ sFindFeatureInfo = (NAND_IO_FEATURE*)NAND_SupportMakerInfo.DevInfo[0];
++
++ //=====================================================================
++ // Search Matched NANDFLASH (x8 Bit Serial NAND)
++ //=====================================================================
++ for ( j = 0; j < 3; ++j ) /* Check Read ID during 3 turn */
++ {
++ //IO_CKC_EnableBUS( IO_CKC_BUS_NFC );
++ // 16Bit NAND Mask Disable
++ BITCLR( pNFC->NFC_CTRL, HwNFC_CTRL_MASK_EN );
++
++ /* Read Device CODE */
++ NAND_IO_ResetForReadID( nChipNo, NAND_IO_SERIAL_COMBINATION_MODE ); // x8 Bit NAND Search
++ NAND_IO_ReadID( nChipNo, &sDeviceCode1, NAND_IO_SERIAL_COMBINATION_MODE ); // x8 Bit NAND Search
++
++ /* Check Maker ID */
++ bFindMakerNo = 0xFF;
++ for ( k = 0; k < MAX_SUPPORT_MAKER_NAND; ++k )
++ {
++ if ( sDeviceCode1.Code[0] == NAND_SupportMakerInfo.MakerID[k] )
++ {
++ bFindMakerNo = (unsigned char)k;
++ sTempFeatureInfo = (NAND_IO_FEATURE*)NAND_SupportMakerInfo.DevInfo[k];
++ break;
++ }
++ }
++
++ if ( bFindMakerNo >= MAX_SUPPORT_MAKER_NAND )
++ continue;
++
++ /* Check Device ID */
++ for ( k = 0; k < NAND_SupportMakerInfo.MaxSupportNAND[bFindMakerNo]; ++k )
++ {
++ bMatchCount = 0;
++
++ for ( l = 0; l < 5; ++l )
++ {
++ if ( sTempFeatureInfo->DeviceID.Code[l+1] == 0x00 )
++ ++bMatchCount;
++ else if ( sDeviceCode1.Code[l+1] == sTempFeatureInfo->DeviceID.Code[l+1] )
++ ++bMatchCount;
++ }
++
++ /* Found NAND Device */
++ if ( bMatchCount >= 5 )
++ {
++ bFindMedia = TRUE;
++ sFindFeatureInfo = sTempFeatureInfo;
++ break;
++ }
++ else
++ ++sTempFeatureInfo;
++ }
++
++ /* Found NAND Device */
++ if ( bFindMedia == TRUE )
++ break;
++ }
++
++ if ( bFindMedia != TRUE )
++ {
++ //=====================================================================
++ // Search Matched NANDFLASH (x16 Bit Serial NAND)
++ //=====================================================================
++ for ( j = 0; j < 3; ++j ) /* Check Read ID during 3 turn */
++ {
++ //IO_CKC_EnableBUS( IO_CKC_BUS_NFC );
++ // 16Bit NAND Mask Enable
++ BITSET( pNFC->NFC_CTRL, HwNFC_CTRL_MASK_EN );
++
++ /* Read Device CODE */
++ NAND_IO_ResetForReadID( nChipNo, NAND_IO_PARALLEL_COMBINATION_MODE ); // x16 Bit NAND Command
++ NAND_IO_ReadID( nChipNo, &sDeviceCode1, NAND_IO_PARALLEL_COMBINATION_MODE ); // x16 Bit NAND Search
++
++ /* Check Maker ID */
++ bFindMakerNo = 0xFF;
++ for ( k = 0; k < MAX_SUPPORT_MAKER_NAND; ++k )
++ {
++ if ( sDeviceCode1.Code[0] == NAND_SupportMakerInfo.MakerID[k] )
++ {
++ bFindMakerNo = (unsigned char)k;
++ sTempFeatureInfo = (NAND_IO_FEATURE*)NAND_SupportMakerInfo.DevInfo[k];
++ break;
++ }
++ }
++
++ if ( bFindMakerNo >= MAX_SUPPORT_MAKER_NAND )
++ continue;
++
++ /* Check Device ID */
++ for ( k = 0; k < NAND_SupportMakerInfo.MaxSupportNAND[bFindMakerNo]; ++k )
++ {
++ bMatchCount = 0;
++
++ for ( l = 0; l < 5; ++l )
++ {
++ if ( sTempFeatureInfo->DeviceID.Code[l+1] == 0x00 )
++ ++bMatchCount;
++ else if ( sDeviceCode1.Code[l+1] == sTempFeatureInfo->DeviceID.Code[l+1] )
++ ++bMatchCount;
++ }
++
++ /* Found NAND Device */
++ if ( bMatchCount >= 5 )
++ {
++ bFindMedia = TRUE;
++ sFindFeatureInfo = sTempFeatureInfo;
++ break;
++ }
++ else
++ ++sTempFeatureInfo;
++ }
++
++ /* Found NAND Device */
++ if ( bFindMedia == TRUE )
++ break;
++ }
++ }
++
++ //=====================================================================
++ // If Media is founded
++ //=====================================================================
++ if ( bFindMedia == TRUE )
++ {
++ /* Get NAND Feature Info */
++ memcpy( (void*)&nDevInfo->Feature,
++ (void*)sFindFeatureInfo,
++ sizeof(NAND_IO_FEATURE) );
++
++ /* Get ECC Type Info */
++ if ( nDevInfo->Feature.MediaType & A_SLC )
++ {
++ nDevInfo->EccType = TYPE_ECC_FOR_1BIT_SLC_NANDFLASH;
++ nDevInfo->EccDataSize = 10;
++
++ if ( nDevInfo->Feature.MediaType & A_16BIT )
++ nDevInfo->EccDataSize = 12;
++ }
++ else if ( nDevInfo->Feature.MediaType & A_MLC )
++ {
++ nDevInfo->EccType = TYPE_ECC_FOR_4BIT_MLC_NANDFLASH;
++ nDevInfo->EccDataSize = 10;
++ }
++ else if ( nDevInfo->Feature.MediaType & A_MLC_8BIT )
++ {
++ nDevInfo->EccType = TYPE_ECC_FOR_8BIT_MLC_NANDFLASH;
++ nDevInfo->EccDataSize = 20;
++ nDevInfo->Feature.SpareSize = 192;
++ }
++ else if ( nDevInfo->Feature.MediaType & A_MLC_12BIT )
++ {
++ nDevInfo->EccType = TYPE_ECC_FOR_12BIT_MLC_NANDFLASH;
++ nDevInfo->EccDataSize = 20;
++ nDevInfo->Feature.SpareSize = 192;
++ }
++
++ if ( nDevInfo->Feature.PageSize == 4096 )
++ nDevInfo->DistrictNum = 1024;
++ else
++ nDevInfo->DistrictNum = 2048;
++
++ //=====================================================================
++ //EXCEPTION: TH58NVG4D1D/5D1DTG20 TH58NVG6D1DTG20
++ //=====================================================================
++ if ( ( nDevInfo->Feature.DeviceID.Code[0]== 0x98 ) && ( nDevInfo->Feature.DeviceID.Code[1] == 0xD5 ) && ( nDevInfo->Feature.DeviceID.Code[2] == 0x94 ))
++ nDevInfo->DistrictNum = 2048;
++
++ if ( ( nDevInfo->Feature.DeviceID.Code[0]== 0x98 ) && ( nDevInfo->Feature.DeviceID.Code[1] == 0xD7 ) )
++ nDevInfo->DistrictNum = 2048;
++
++ if ( nDevInfo->Feature.MediaType & A_08BIT )
++ {
++ #ifndef NAND_8BIT_ONLY
++ /* Check if compositin of NAND is parallel or serial */
++ NAND_IO_ResetForReadID( nChipNo, NAND_IO_PARALLEL_COMBINATION_MODE );
++ NAND_IO_ReadID( nChipNo, &sDeviceCode2, NAND_IO_PARALLEL_COMBINATION_MODE );
++
++ if ( ((sDeviceCode2.Code[0] & 0xFF) == ((sDeviceCode2.Code[0] >> 8) & 0xFF)) &&
++ ((sDeviceCode2.Code[1] & 0xFF) == ((sDeviceCode2.Code[1] >> 8) & 0xFF)) &&
++ ((sDeviceCode2.Code[2] & 0xFF) == ((sDeviceCode2.Code[2] >> 8) & 0xFF)) &&
++ ((sDeviceCode2.Code[3] & 0xFF) == ((sDeviceCode2.Code[3] >> 8) & 0xFF)) &&
++ ((sDeviceCode2.Code[4] & 0xFF) == ((sDeviceCode2.Code[4] >> 8) & 0xFF)) )
++ {
++ nDevInfo->Feature.MediaType |= A_PARALLEL;
++ nDevInfo->Feature.MediaType |= A_DATA_WITDH_16BIT;
++ nDevInfo->Feature.PageSize *= 2;
++ nDevInfo->Feature.SpareSize *= 2;
++
++ if ( ( ( nDevInfo->Feature.MediaType & A_MLC ) || (nDevInfo->Feature.MediaType & A_SLC ) ) && ( nDevInfo->Feature.MediaType & A_BIG ) )
++ {
++ nDevInfo->EccDataSize +=2;
++ }
++
++ nDevInfo->CmdMask = 0xFFFF;
++ }
++ else
++ {
++ nDevInfo->Feature.MediaType |= A_DATA_WITDH_08BIT;
++ nDevInfo->CmdMask = 0x00FF;
++ }
++
++ #else
++ nDevInfo->Feature.MediaType |= A_DATA_WITDH_08BIT;
++ nDevInfo->CmdMask = 0x00FF;
++ #endif
++ }
++ else
++ {
++ //IO_CKC_EnableBUS( IO_CKC_BUS_NFC );
++ // 16Bit NAND Mask Enable
++ BITSET( pNFC->NFC_CTRL, HwNFC_CTRL_MASK_EN );
++ nDevInfo->Feature.MediaType |= A_DATA_WITDH_16BIT;
++ nDevInfo->CmdMask = 0x00FF;
++ }
++
++
++ /* Get Total Partial Page [512+16Bytes] */
++ nDevInfo->PPages = ( nDevInfo->Feature.PageSize / 512 );
++
++ /* Get Shift Factors of PBpV, PpB, PageSize, SpareSize, PPages */
++ res = (NAND_IO_ERROR)SUCCESS;
++ res |= NAND_IO_GetShiftValueForFastMultiPly( nDevInfo->Feature.PBpV, &nDevInfo->ShiftPBpV );
++ res |= NAND_IO_GetShiftValueForFastMultiPly( nDevInfo->Feature.PpB, &nDevInfo->ShiftPpB );
++ res |= NAND_IO_GetShiftValueForFastMultiPly( nDevInfo->Feature.PageSize, &nDevInfo->ShiftPageSize );
++ //res |= NAND_IO_GetShiftValueForFastMultiPly( nDevInfo->Feature.SpareSize, &nDevInfo->ShiftSpareSize );
++ res |= NAND_IO_GetShiftValueForFastMultiPly( nDevInfo->PPages, &nDevInfo->ShiftPPages );
++ res |= NAND_IO_GetShiftValueForFastMultiPly( nDevInfo->DistrictNum, &nDevInfo->ShiftDistrictNum );
++
++ if ( res != SUCCESS )
++ return res;
++
++ for ( j = 0; j < 4; ++j )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[j] = MULTI_PLANE_GOOD_BLOCK;
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[j] = 0xFFFFFFFF;
++ }
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ //=====================================================================
++ // Not Found
++ //=====================================================================
++ else
++ {
++ return ERR_NAND_IO_FAILED_GET_DEVICE_INFO;
++ }
++
++ nDevInfo->IoStatus = NAND_IO_STATUS_ENABLE;
++ nDevInfo->ChipNo = nChipNo;
++
++ //=====================================================================
++ // gDevInfo( Global Variable ) Initialize
++ //=====================================================================
++ if ( nDevInfo->ChipNo == 0 )
++ gDevInfo = (NAND_IO_DEVINFO *)nDevInfo;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* U32 NAND_IO_GetBUSTypeOfDataIO( void )
++*
++* Input : NONE
++* Output : NONE
++* Return : NONE
++*
++* Description : Initialize NAND IO Layer
++*
++*******************************************************************************/
++U32 NAND_IO_GetBUSTypeOfDataIO( void )
++{
++ return gNAND_IO_DataBusType;
++}
++
++void NAND_IO_ECC_InfoInit( void )
++{
++ gMLC_ECC_4Bit.ErrorCodeNum = 2;
++ gMLC_ECC_4Bit.EncodeFlag = HwECC_IREQ_M4EF;
++ gMLC_ECC_4Bit.DecodeFlag = HwECC_IREQ_M4DF;
++ gMLC_ECC_4Bit.ErrorNum = 4;
++ gMLC_ECC_4Bit.All_FF_512_ECC_Code = (U8 *)&ALL_FF_ECC_BCH_04BIT_512;
++
++ gMLC_ECC_8Bit.ErrorCodeNum = 4;
++ gMLC_ECC_8Bit.EncodeFlag = HwECC_IREQ_M8EF;
++ gMLC_ECC_8Bit.DecodeFlag = HwECC_IREQ_M8DF;
++ gMLC_ECC_8Bit.ErrorNum = 8;
++ gMLC_ECC_8Bit.All_FF_512_ECC_Code = (U8 *)&ALL_FF_ECC_BCH_08BIT_512;
++
++ gMLC_ECC_12Bit.ErrorCodeNum = 5;
++ gMLC_ECC_12Bit.EncodeFlag = HwECC_IREQ_M12EF;
++ gMLC_ECC_12Bit.DecodeFlag = HwECC_IREQ_M12DF;
++ gMLC_ECC_12Bit.ErrorNum = 12;
++ gMLC_ECC_12Bit.All_FF_512_ECC_Code = (U8 *)&ALL_FF_ECC_BCH_12BIT_512;
++
++ gMLC_ECC_14Bit.ErrorCodeNum = 6;
++ gMLC_ECC_14Bit.EncodeFlag = HwECC_IREQ_M14EF;
++ gMLC_ECC_14Bit.DecodeFlag = HwECC_IREQ_M14DF;
++ gMLC_ECC_14Bit.ErrorNum = 14;
++ gMLC_ECC_14Bit.All_FF_512_ECC_Code = (U8 *)&ALL_FF_ECC_BCH_14BIT_512;
++
++ gMLC_ECC_16Bit.ErrorCodeNum = 7;
++ gMLC_ECC_16Bit.EncodeFlag = HwECC_IREQ_M16EF;
++ gMLC_ECC_16Bit.DecodeFlag = HwECC_IREQ_M16DF;
++ gMLC_ECC_16Bit.ErrorNum = 16;
++ gMLC_ECC_16Bit.All_FF_512_ECC_Code = (U8 *)&ALL_FF_ECC_BCH_16BIT_512;
++}
++
++void NAND_IO_InitDMABuffer( void )
++{
++ #if defined(_WINCE_)
++ tSYSTEM_PARAM *pSYS_Work_PARAM = (tSYSTEM_PARAM*)(SYSTEM_PARAM_BASEADDRESS);
++ #endif
++
++ #if defined(_WINCE_)
++ gpDMA_PhyBuffer0 = (unsigned int*)pSYS_Work_PARAM->DMA2.CH0_BUFFER; // Working Address
++ gpDMA_WorkBuffer0 = (unsigned int*)pSYS_PARAM->DMA2.CH0_BUFFER; // Physical Address
++ gpDMA_PhyBuffer1 = (unsigned int*)pSYS_Work_PARAM->DMA2.CH1_BUFFER; // Working Address
++ gpDMA_WorkBuffer1 = (unsigned int*)pSYS_PARAM->DMA2.CH1_BUFFER; // Physical Address
++ #elif defined(_LINUX_)
++ #ifdef KERNEL_DRIVER
++ gpDMA_PhyBuffer0 = dma_t.dma_addr;
++ gpDMA_WorkBuffer0 = (unsigned int*)dma_t.v_addr;
++ gpDMA_PhyBuffer1 = (unsigned char*)gpDMA_PhyBuffer0 + 512;
++ gpDMA_WorkBuffer1 = (unsigned char*)gpDMA_WorkBuffer0 + 512;
++ #else
++ gpDMA_PhyBuffer0 = (unsigned int*)DMA_ADDR;
++ gpDMA_WorkBuffer0 = (unsigned int*)DMA_ADDR;
++ gpDMA_PhyBuffer1 = (unsigned int*)DMA_ADDR + 512;
++ gpDMA_WorkBuffer1 = (unsigned int*)DMA_ADDR + 512;
++ #endif
++ #else // NU
++ gpDMA_PhyBuffer0 = (unsigned int*)gpNandBuffer;
++ gpDMA_WorkBuffer0 = (unsigned int*)gpNandBuffer;
++ gpDMA_PhyBuffer1 = (unsigned char*)gpDMA_PhyBuffer0 + 512;
++ gpDMA_WorkBuffer1 = (unsigned char*)gpDMA_WorkBuffer0 + 512;
++ #endif
++}
++
++/******************************************************************************
++*
++* void NAND_IO_Init( void )
++*
++* Input : NONE
++* Output : NONE
++* Return : NONE
++*
++* Description : Initialize NAND IO Layer
++*
++*******************************************************************************/
++void NAND_IO_Init( void )
++{
++ unsigned int i;
++ PEDI pEDI;
++ PPIC pPIC;
++ NAND_IO_DEVINFO sDevInfo;
++ NAND_IO_ERROR res;
++
++ memset( &sDevInfo, 0x00, sizeof(NAND_IO_DEVINFO));
++
++#if defined(USE_V_ADDRESS)
++ #if defined(_LINUX_)
++ pGPIO = (PGPIO)(&HwGPIO_BASE);
++ pEDI = (PEDI)(&HwEDI_BASE);
++ pNFC = (PNFC)(&HwNFC_BASE);
++ pECC = (PECC)(&HwECC_BASE);
++ pIOBUSCFG_T = (PIOBUSCFG)(&HwIOBUSCFG_BASE);
++ pNAND_DMA = (PGDMANCTRL)(&HwGDMA2_BASE);
++ #if defined(_WINCE_)
++ pSYS_PARAM = (ptSYSTEM_PARAM)(&SYSTEM_PARAM_BASEADDRESS);
++ #endif
++ pPIC = (PPIC)(&HwPIC_BASE);
++ #elif defined(_WINCE_)
++ pGPIO = (PGPIO)tcc_allocbaseaddress((unsigned int)&HwGPIO_BASE);
++ pEDI = (PEDI)tcc_allocbaseaddress((unsigned int)&HwEDI_BASE);
++ pNFC = (PNFC)tcc_allocbaseaddress((unsigned int)&HwNFC_BASE);
++ pECC = (PECC)tcc_allocbaseaddress((unsigned int)&HwECC_BASE);
++ pIOBUSCFG_T = (PIOBUSCFG)tcc_allocbaseaddress((unsigned int)&HwIOBUSCFG_BASE);
++ pPIC = (PPIC)tcc_allocbaseaddress((unsigned int)&HwPIC_BASE);
++ pSYS_PARAM = (tSYSTEM_PARAM*)tcc_allocbaseaddress((unsigned int)SYSTEM_PARAM_BASEADDRESS);
++ pNAND_DMA = (PGDMANCTRL)tcc_allocbaseaddress((unsigned int)&HwGDMA2_BASE);
++ #endif
++#else
++ pGPIO = (PGPIO)(&HwGPIO_BASE);
++ pEDI = (PEDI)(&HwEDI_BASE);
++ pNFC = (PNFC)(&HwNFC_BASE);
++ pECC = (PECC)(&HwECC_BASE);
++ pIOBUSCFG_T = (PIOBUSCFG)(&HwIOBUSCFG_BASE);
++ pPIC = (PPIC)(&HwPIC_BASE);
++ #if defined(_WINCE_)
++ pSYS_PARAM = (tSYSTEM_PARAM*)(SYSTEM_PARAM_BASEADDRESS);
++ #endif
++ pNAND_DMA = (PGDMANCTRL)(&HwGDMA2_BASE);
++#endif
++
++ /*************************************/
++ /*Don't remove NAND_IO_Delay Function*/
++ /*************************************/
++ for( i = 0; i < 5000; ++i )
++ NAND_IO_Delay();
++
++ for ( i = 0; i < 2; ++i )
++ {
++ /***********************************/
++ /* Setting NANDFLASH on Memory Bus */
++ /***********************************/
++ if ( i == 0 )
++ {
++ ASM_NOP;
++ }
++ /********************************/
++ /* Setting NANDFLASH on NFC Bus */
++ /********************************/
++ else
++ {
++ #if defined(TCC89XX) || defined(TCC92XX)
++ // Set ECC Code Register Base Address
++ //gHwECC = ( ECC *)(&HwECC_BASE);
++ //gHwECCErrorAddr = ( ECCERRADDR *)(&HwECCERRADDR_BASE);
++ #endif
++
++ //IO_CKC_EnableBUS( IO_CKC_BUS_NFC );
++
++ //volatile unsigned int EDI_CTRL; // 0x00 R/W 0x00000000 EDI Control Register.
++ //volatile unsigned int EDI_CSNCFG0; // 0x04 R/W 0x00543210 EDI CSN Configuration Register 0.
++ //volatile unsigned int EDI_CSNCFG1; // 0x08 R/W 0x00BA9876 EDI CSN Configuration Register 1.
++ //volatile unsigned int NOTDEFINE0[2]; // Reserved 0x0C R/W - -
++ //volatile unsigned int EDI_RDYCFG; // 0x14 R/W 0x76543210 EDI Ready Configuration Register
++ //volatile unsigned int NOTDEFINE1[2]; // Reserved 0x18 R/W 0x00000000 EDI Time-Out Configuration Register 0
++ //volatile unsigned int EDI_REQOFF; // 0x20 R/W 0x00000000 EDI Request OFF Flag register
++
++ pEDI->EDI_RDYCFG = 0x00000001;
++ //pEDI->EDI_CSNCFG0 = 0x00403265;
++ BITCSET(pEDI->EDI_CSNCFG0, 0xFFFF, 0x8765 );
++
++ pGPIO->GPBFN0 = 0x11112222; //NANDXD[7:4]
++ pGPIO->GPBFN1 = 0x00221111; //NANDXD[3:0]
++ pGPIO->GPBFN2 = 0x10111010; //NANDXD[11:8],[7:4]
++ pGPIO->GPBFN3 = 0x00010111; //NANDXD[15:12],[3:0]
++
++ // Write Protect Pin: Output Mode
++ BITSET( pGPIO->GPBEN, NAND_IO_NFC_nWPBit );
++
++ //=================================================
++ // TCC9200S_BOARD NAND Ready/Busy Pin Set
++ /* ND_RDY: GPIO_B31 */
++ //=================================================
++ #if defined(TCC9200S_BOARD)
++ pGPIO->GPBFN3 &= ~0x10000000; // ND_RDY: GPIO_B31
++ BITCLR(pGPIO->GPBEN, Hw31);
++ #endif
++
++ gNAND_IO_DataBusType = NAND_IO_NFC_BUS;
++
++ /* Make Reset */
++ pNFC->NFC_RST = 0;
++
++ /* Set Default NFC Configuration */
++ pNFC->NFC_CTRL = HwNFC_CTRL_DEN_EN |
++ HwNFC_CTRL_CFG_NOACT |
++ HwNFC_CTRL_BSIZE_1 |
++ (4 << 4) | // pw = 5
++ (1 << 0); // hold = 1
++
++ /* GPIO B Arbitration ENABLE */
++ pNFC->NFC_CTRL1 |= Hw31;
++ pNFC->NFC_CTRL1 |= Hw30;
++
++ /* Enable Interrupt */
++ pNFC->NFC_IREQ = 0x77; // Clear Interrupt
++ pPIC->CLR1 = HwINT1_NFC;
++ BITSET( pPIC->SEL1, HwINT1_NFC); // Set NFC as IRQ interrupt
++ BITSET( pPIC->MODE1, HwINT1_NFC ); // Level type for NFC interrupt, IO_INT_HwNFC ); // Level type for NFC interrupt
++
++ //IO_CKC_DisableBUS( IO_CKC_BUS_NFC );
++
++ /* Searching NANDFLASH */
++ res = NAND_IO_GetDeviceInfo( 0, &sDevInfo );
++
++ #ifdef SPEED_CHECK
++ {
++ pGPIO->GPFFN0 = 0xFFFFFFFF;
++ pGPIO->GPFEN = 0xFFFFFFFF;
++ //pGPIO->GPFDAT = 0xFFFFFFFF;
++ pGPIO->GPFDAT = HwZERO;
++ }
++ #endif
++
++ if ( res == SUCCESS )
++ break;
++ }
++ }
++
++ /* Setup Variable about ECC */
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++ pECC->ECC_CTRL = 0x04000000; /* ECC Control Register */
++ pECC->ECC_BASE = pNFC->NFC_WDATA; /* Base Address for ECC Calculation */
++ pECC->ECC_MASK = 0x00000000; /* Address mask for ECC area */
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++
++ memcpy( &rDevInfo, &sDevInfo, sizeof(NAND_IO_DEVINFO) );
++
++ NAND_IO_ECC_InfoInit();
++
++ #ifdef NAND_IO_USE_DMA_ACCESS
++ NAND_IO_InitDMABuffer();
++ #endif
++}
++
++/******************************************************************************
++*
++* void NAND_IO_Reset
++*
++* Input : Chip Select Number
++* Output : NONE
++* Return : NONE
++*
++* Description : Reset NANDFLASH
++*
++*******************************************************************************/
++void NAND_IO_Reset( U16 nChipNo, int nMode )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nChipNo );
++
++ /* Set Data Bus as 16Bit */
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++
++ /* Command RESET [ 0xFF ] */
++ if ( nMode == NAND_IO_PARALLEL_COMBINATION_MODE )
++ pNFC->NFC_CMD = 0xFFFF;
++ else
++ pNFC->NFC_CMD = 0x00FF;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++}
++
++/******************************************************************************
++*
++* void NAND_IO_ResetForReadID
++*
++* Input : Chip Select Number
++* Output : NONE
++* Return : NONE
++*
++* Description : Reset NANDFLASH
++*
++*******************************************************************************/
++void NAND_IO_ResetForReadID( U16 nChipNo, int nMode )
++{
++ unsigned int i,j;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nChipNo );
++
++ /* Set Data Bus as 16Bit */
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++
++ /* Command RESET [ 0xFF ] */
++ if ( nMode == NAND_IO_PARALLEL_COMBINATION_MODE )
++ pNFC->NFC_CMD = 0xFFFF;
++ else
++ pNFC->NFC_CMD = 0x00FF;
++
++ /* Wait until it is ready */
++ for ( i = 0; i < 0x100; ++i )
++ {
++ for ( j = 0; j < 0x80; ++j )
++ {
++ ASM_NOP;
++ }
++ }
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++}
++
++/******************************************************************************
++*
++* void NAND_IO_ReadID
++*
++* Input : Chip Select Number
++* Mode : 0 => Serial Composition , 1 => Parallel Composition
++* Output : NANDFLASH Device Code
++* Return : NONE
++*
++* Description : Get Device Code of NANDFLASH
++*
++*******************************************************************************/
++void NAND_IO_ReadID( U16 nChipNo, NAND_IO_DEVID *nDeviceCode, int nMode )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nChipNo );
++
++ /* Set Data Bus as 16Bit */
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++
++ /* Parallel Composition */
++ if ( nMode == NAND_IO_PARALLEL_COMBINATION_MODE )
++ {
++ pNFC->NFC_CMD = 0x9090; /* Command READ ID [ 0x90 ] */
++ pNFC->NFC_SADDR = 0x0000; /* Address [ 0x00 ] */
++ }
++ /* Serial Composition */
++ else
++ {
++ pNFC->NFC_CMD = 0x0090; /* Command READ ID [ 0x90 ] */
++ pNFC->NFC_SADDR = 0x0000; /* Address [ 0x00 ] */
++ }
++
++ /* Delay : tAR1[READID] Max 200nS */
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++
++ /* Parallel Composition */
++ if ( nMode == NAND_IO_PARALLEL_COMBINATION_MODE )
++ {
++ nDeviceCode->Code[0] = (U16)pNFC->NFC_SDATA;
++ nDeviceCode->Code[1] = (U16)pNFC->NFC_SDATA;
++ nDeviceCode->Code[2] = (U16)pNFC->NFC_SDATA;
++ nDeviceCode->Code[3] = (U16)pNFC->NFC_SDATA;
++ nDeviceCode->Code[4] = (U16)pNFC->NFC_SDATA;
++ nDeviceCode->Code[5] = (U16)pNFC->NFC_SDATA;
++ }
++ /* Serial Composition */
++ else
++ {
++ nDeviceCode->Code[0] = (U8)( pNFC->NFC_SDATA & 0xFF );
++ nDeviceCode->Code[1] = (U8)( pNFC->NFC_SDATA & 0xFF );
++ nDeviceCode->Code[2] = (U8)( pNFC->NFC_SDATA & 0xFF );
++ nDeviceCode->Code[3] = (U8)( pNFC->NFC_SDATA & 0xFF );
++ nDeviceCode->Code[4] = (U8)( pNFC->NFC_SDATA & 0xFF );
++ nDeviceCode->Code[5] = (U8)( pNFC->NFC_SDATA & 0xFF );
++ }
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadSpare
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadSpare( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8 *nSpareBuffer )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ //=============================================
++ // Read Data
++ //=============================================
++
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) << nDevInfo->ShiftPPages ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadSpare;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Read Spare data from NANDFLASH */
++ res = NAND_IO_ReadSpareDataECC( nDevInfo,
++ nSpareBuffer,
++ ECC_ON );
++ if ( res != SUCCESS )
++ goto ErrorReadSpare;
++ }
++ else
++ {
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, 512, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadSpare;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Read Spare data from NANDFLASH */
++ res = NAND_IO_ReadSpareData( nDevInfo,
++ 0,
++ 1,
++ nSpareBuffer );
++ if ( res != SUCCESS )
++ goto ErrorReadSpare;
++ }
++
++
++ErrorReadSpare:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ unsigned int nSpareOnOff;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ) )
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ #ifdef READ_SPEED_CHECK
++ pGPIO->GPFDAT = 0;
++ NAND_IO_GPIO_Toggle(Hw7);
++ #endif
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw5);
++ #endif
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw5);
++ #endif
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif
++
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw4);
++ #endif
++ NAND_IO_EnableWriteProtect();
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw4);
++ #endif
++
++ //=============================================
++ // Read Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++ else
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, ( 528 * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw5);
++ #endif
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw5);
++ #endif
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ /* Read Page Size data from NANDFLASH */
++ nSpareOnOff = TNFTL_READ_SPARE_ON;
++
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF)
++ res = NAND_IO_Read512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #else
++ res = NAND_IO_Read512Data( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #endif
++ }
++ else
++ {
++ /* Read Page Size data from NANDFLASH */
++ res = NAND_IO_Read528Data( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ }
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ErrorReadPage:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw7);
++ #endif
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadNBPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadNBPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ) )
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ //=============================================
++ // Read Data
++ //=============================================
++ /* Generate Row and Column Address */
++ if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++ else
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, nStartPPage * 528, &RowAddr, &ColumnAddr, nDevInfo );
++
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ {
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF)
++ res = NAND_IO_Read512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #else
++ res = NAND_IO_Read512Data( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #endif
++ }
++ else
++ {
++ /* Read Page Size data from NANDFLASH */
++ res = NAND_IO_Read528Data( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ }
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ErrorReadPage:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadPageMTD
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadPageMTD( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ unsigned int nSpareOnOff;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ) )
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ // Read Data
++ //=============================================
++ /* Generate Row and Column Address */
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, nDevInfo->Feature.PageSize, &RowAddr, &ColumnAddr, nDevInfo );
++ else
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, ( nStartPPage << 9 ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ /* Read Page Size data from NANDFLASH */
++ nSpareOnOff = TNFTL_READ_SPARE_ON;
++
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++ res = NAND_IO_ReadSpareDataMTD( nDevInfo, nSpareBuffer, PAGE_ECC_ON );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ /* Command Random Data Output [ 0x05 ] for Advance NandFlash */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0505;
++
++ ColumnAddr = ( nStartPPage << 9 );
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_PARALLEL ) ? (ColumnAddr >> 1) : ColumnAddr;
++
++ NAND_IO_WriteColAddr( ColumnAddr, nDevInfo );
++
++ /* Command Random Data Output [ 0xE0 ] for Advance NandFlash */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xE0E0;
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++ }
++ else if (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL ))
++ {
++ res = NAND_IO_ReadSpareDataMTD( nDevInfo, nSpareBuffer, PAGE_ECC_ON );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, ( nStartPPage << 9 ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++ }
++
++ res = NAND_IO_Read512DataMTD( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ErrorReadPage:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadTwoPlanePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadTwoPlanePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U32 nSecondPageAddr,
++ U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ) )
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ #ifdef READ_SPEED_CHECK
++ pGPIO->GPFDAT = 0;
++ NAND_IO_GPIO_Toggle(Hw7);
++ #endif
++
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_WaitBusyForInterleave( nDevInfo, nPageAddr );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ //=============================================
++ // PRE-Operation
++ //=============================================
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Two-Plane Page Read Command [0x60] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x6060;
++
++ /* Write Row Address: Fixed 'Low' */
++ NAND_IO_WriteBlockPageAddr( 0, nDevInfo );
++
++ /* Two-Plane Page Read Command 2 [0x60] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x6060;
++
++ NAND_IO_WriteBlockPageAddr( nSecondPageAddr, nDevInfo );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif
++
++ //=============================================
++ // Read Data
++ //=============================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ /* Write Col & Row Address: Fixed 'Low' */
++ NAND_IO_WriteRowColAddr( 0, 0, nDevInfo );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0505;
++
++ /* Write Col Address: Valid */
++ NAND_IO_WriteColAddr( ColumnAddr, nDevInfo );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xE0E0;
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ /* Read Page Size data from NANDFLASH */
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF)
++ res = NAND_IO_Read512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #else
++ res = NAND_IO_Read512Data( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #endif
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ErrorReadPage:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw7);
++ #endif
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadTwoPlaneLastPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadTwoPlaneLastPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ) )
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ #ifdef READ_SPEED_CHECK
++ pGPIO->GPFDAT = 0;
++ NAND_IO_GPIO_Toggle(Hw7);
++ #endif
++
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ //=============================================
++ // Read Data
++ //=============================================
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Write Col & Row Address: Col Addr = Fixed 'Low' */
++ NAND_IO_WriteRowColAddr( RowAddr, 0, nDevInfo );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0505;
++
++ /* Write Col Address: Valid */
++ NAND_IO_WriteColAddr( ColumnAddr, nDevInfo );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xE0E0;
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ /* Read Page Size data from NANDFLASH */
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF)
++ res = NAND_IO_Read512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #else
++ res = NAND_IO_Read512Data( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #endif
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ErrorReadPage:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw7);
++ #endif
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadUserSizePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadUserSizePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nColumnAddr, U32 nReadSize, U8 *nReadBuffer )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( (U32)( nColumnAddr + nReadSize ) > (U16)( nDevInfo->Feature.PageSize + nDevInfo->Feature.SpareSize ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ //=============================================
++ // Read UserSize Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, nColumnAddr, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadUserSizePage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ /* Read User Size data from NANDFLASH */
++ res = NAND_IO_ReadUserSizeData( nDevInfo,
++ nColumnAddr,
++ nReadSize,
++ nReadBuffer );
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorReadUserSizePage;
++
++ErrorReadUserSizePage:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadChainPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadChainPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8 *nPageBuffer, U8 *nSpareBuffer, int nMode )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ //=============================================
++ // Read UserSize Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadUserSizePage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ /* Read User Size data from NANDFLASH */
++ res = NAND_IO_ReadUserSizeData( nDevInfo,
++ 0,
++ nDevInfo->Feature.PageSize,
++ nPageBuffer );
++ if ( res != SUCCESS )
++ goto ErrorReadUserSizePage;
++
++ res = NAND_IO_ReadUserSizeData( nDevInfo,
++ 0,
++ nDevInfo->Feature.SpareSize,
++ nSpareBuffer );
++ if ( res != SUCCESS )
++ goto ErrorReadUserSizePage;
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // ECC Decode
++ //=============================================
++ res = NAND_IO_DecodeChainData( nDevInfo,
++ nPageBuffer,
++ nSpareBuffer,
++ nMode, ECC_ON );
++ if ( res != SUCCESS )
++ goto ErrorReadUserSizePage;
++
++ErrorReadUserSizePage:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* NAND_IO_ERROR NAND_IO_ReadGoldenPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8 *nPageBuffer, U8 *nSpareBuffer );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* nDevInfo =
++* nPageAddr =
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadGoldenPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8 *nPageBuffer, U8 *nSpareBuffer )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ //=============================================
++ // Read UserSize Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadUserSizePage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ /* Read User Size data from NANDFLASH */
++ res = NAND_IO_ReadUserSizeData( nDevInfo,
++ 0,
++ nDevInfo->Feature.PageSize,
++ nPageBuffer );
++ if ( res != SUCCESS )
++ goto ErrorReadUserSizePage;
++
++ res = NAND_IO_ReadUserSizeData( nDevInfo,
++ 0,
++ nDevInfo->Feature.SpareSize,
++ nSpareBuffer );
++ if ( res != SUCCESS )
++ goto ErrorReadUserSizePage;
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // ECC Decode
++ //=============================================
++ res = NAND_IO_DecodeChainDataForGoldenPage( nDevInfo,
++ nPageBuffer,
++ nSpareBuffer,
++ ECC_ON );
++
++
++ if ( res != SUCCESS )
++ goto ErrorReadUserSizePage;
++
++ErrorReadUserSizePage:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WriteSpare
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WriteSpare( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U8* nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ {
++ res = NAND_IO_WaitBusyForInterleave( nDevInfo, nPageAddr );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++ }
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Write Data
++ //=============================================
++ /* Generate Row and Column Address */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) << nDevInfo->ShiftPPages ), &RowAddr, &ColumnAddr, nDevInfo );
++ else
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, 512, &RowAddr, &ColumnAddr, nDevInfo );
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ res = NAND_IO_WriteSpareData( nDevInfo, nSpareBuffer, nEccOnOff );
++ else
++ res = NAND_IO_WriteUserSizeData( nDevInfo, (U16)ColumnAddr, 16, nSpareBuffer );
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ {
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWritePage;
++ }
++ }
++ else
++ {
++ NAND_IO_SetInterleaveStatus( nDevInfo, nPageAddr );
++ gInterLeavePageAddr = nPageAddr;
++ }
++ErrorWritePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ NAND_IO_EnableWriteProtect();
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WritePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WritePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ {
++ res = NAND_IO_WaitBusyForInterleave( nDevInfo, nPageAddr );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++ }
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Write Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++ else
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, ( 528 * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF)
++ res = NAND_IO_Write512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #else
++ res = NAND_IO_Write512Data( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #endif
++ }
++ else
++ {
++ res = NAND_IO_Write528Data( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ }
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ {
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWritePage;
++ }
++ }
++ else
++ {
++ NAND_IO_SetInterleaveStatus( nDevInfo, nPageAddr );
++ gInterLeavePageAddr = nPageAddr;
++ }
++
++ErrorWritePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ NAND_IO_EnableWriteProtect();
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WriteNBPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WriteNBPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ {
++ res = NAND_IO_WaitBusyForInterleave( nDevInfo, nPageAddr );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++ }
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Write Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++ else
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, nStartPPage * 528, &RowAddr, &ColumnAddr, nDevInfo );
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ {
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF)
++ res = NAND_IO_Write512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #else
++ res = NAND_IO_Write512Data( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #endif
++ }
++ else
++ {
++ res = NAND_IO_Write528Data( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ }
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ {
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWritePage;
++ }
++ }
++ else
++ {
++ NAND_IO_SetInterleaveStatus( nDevInfo, nPageAddr );
++ gInterLeavePageAddr = nPageAddr;
++ }
++ErrorWritePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ NAND_IO_EnableWriteProtect();
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WritePageMTD
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WritePageMTD( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ {
++ res = NAND_IO_WaitBusyForInterleave( nDevInfo, nPageAddr );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++ }
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Write Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++ else
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, ( 528 * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++ res = NAND_IO_Write512DataMTD( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ }
++ else
++ {
++ res = NAND_IO_Write528Data( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ }
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ {
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWritePage;
++ }
++ }
++ else
++ {
++ NAND_IO_SetInterleaveStatus( nDevInfo, nPageAddr );
++ gInterLeavePageAddr = nPageAddr;
++ }
++
++ErrorWritePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ NAND_IO_EnableWriteProtect();
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WriteCachePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WriteCachePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Write Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF)
++ res = NAND_IO_Write512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #else
++ res = NAND_IO_Write512Data( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #endif
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #2 [ 0x15 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1515;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForCacheProgram( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatusForCacheProgram( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWritePage;
++ }
++
++ErrorWritePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ //NAND_IO_EnableWriteProtect();
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WriteTwoPlanePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WriteTwoPlanePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ unsigned long int dwTempPHYPageAddr;
++ NAND_IO_ERROR res;
++
++ #ifdef WRITE_SPEED_CHECK
++ pGPIO->GPFDAT = 0;
++ NAND_IO_GPIO_Toggle(Hw7);
++ #endif
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ {
++ res = NAND_IO_WaitBusyForInterleave( nDevInfo, nPageAddr );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++ }
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ #ifdef WRITE_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw7);
++ #endif
++
++ //=============================================
++ // Write Data
++ //=============================================
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == HYNIX_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID ) )
++ {
++ if ( ( nDevInfo->Feature.MediaType & A_MLC ) || ( nDevInfo->Feature.MediaType & A_SLC ) )
++ {
++ dwTempPHYPageAddr = ( ( nDevInfo->Feature.PBpV << nDevInfo->ShiftPpB ) >> 1 );
++
++ if ( nPageAddr & dwTempPHYPageAddr )
++ nPageAddr = dwTempPHYPageAddr;
++ else
++ nPageAddr = 0;
++ }
++ }
++
++ #ifdef WRITE_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw7);
++ #endif
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF)
++ res = NAND_IO_Write512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #else
++ res = NAND_IO_Write512Data( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #endif
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Multi Plane Page Program #2 [ 0x11 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1111;
++
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ NAND_IO_WaitBusyForCacheProgram( nDevInfo );
++
++ #ifdef WRITE_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw7);
++ #endif
++
++ErrorWritePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WriteTwoPlaneLastPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WriteTwoPlaneLastPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8* nSpareBuffer, int LastPage, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ #ifdef WRITE_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++
++ //=============================================
++ // Write Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == HYNIX_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID ) )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8181;
++ else if ( ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID ) )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF)
++ res = NAND_IO_Write512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #else
++ res = NAND_IO_Write512Data( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #endif
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #2 [ 0x10 ] */
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID ) )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ else if ( ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID ) )
++ {
++ if ( ( LastPage == MULTI_PLANE_LAST_PAGE ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ else if ( LastPage == MULTI_PLANE_MID_PAGE )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1515;
++ }
++ else if ( ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == HYNIX_NAND_MAKER_ID ) )
++ {
++ if ( nDevInfo->Feature.MediaType & S_MCP )
++ {
++ if ( LastPage == MULTI_PLANE_LAST_PAGE )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ else if ( LastPage == MULTI_PLANE_MID_PAGE )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1515;
++ }
++ else
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ }
++
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ {
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ if ( LastPage == MULTI_PLANE_LAST_PAGE )
++ {
++ res = NAND_IO_ReadStatusForMultiPlane( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWritePage;
++ }
++ }
++ }
++ else
++ {
++ NAND_IO_SetInterleaveStatus( nDevInfo, nPageAddr );
++ gInterLeavePageAddr = nPageAddr;
++ }
++
++ErrorWritePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ //NAND_IO_EnableWriteProtect();
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ #ifdef WRITE_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WriteUserSizePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WriteUserSizePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nColumnAddr, U32 nWriteSize, U8 *nWriteBuffer )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( (U32)( nColumnAddr + nWriteSize ) > (U16)( nDevInfo->Feature.PageSize + nDevInfo->Feature.SpareSize ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Write UserSize Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, nColumnAddr, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorWriteUserSizePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ res = NAND_IO_WriteUserSizeData( nDevInfo,
++ nColumnAddr,
++ nWriteSize,
++ nWriteBuffer );
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWriteUserSizePage;
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWriteUserSizePage;
++ }
++
++ErrorWriteUserSizePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_EnableWriteProtect();
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WriteChainPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WriteChainPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8 *nPageBuffer, U8 *nSpareBuffer, int nMode )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // ECC Encording
++ //=============================================
++ res = NAND_IO_EncodeChainData( nDevInfo, nPageBuffer, nSpareBuffer, nMode, ECC_ON );
++ if ( res != SUCCESS )
++ goto ErrorWriteUserSizePage;
++
++ //=============================================
++ // Write UserSize Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorWriteUserSizePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++
++ //=============================================
++ // Write Data
++ //=============================================
++ res = NAND_IO_WriteUserSizeData( nDevInfo,
++ 0,
++ nDevInfo->Feature.PageSize,
++ nPageBuffer );
++ if ( res != SUCCESS )
++ goto ErrorWriteUserSizePage;
++
++ //=============================================
++ // Write ECC Code
++ //=============================================
++ res = NAND_IO_WriteUserSizeData( nDevInfo,
++ 0,
++ nDevInfo->Feature.SpareSize,
++ nSpareBuffer );
++ if ( res != SUCCESS )
++ goto ErrorWriteUserSizePage;
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWriteUserSizePage;
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWriteUserSizePage;
++ }
++
++ErrorWriteUserSizePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_EnableWriteProtect();
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WriteChainPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WriteGoldenPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8 *nPageBuffer, U8 *nSpareBuffer )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // ECC Encording
++ //=============================================
++ res = NAND_IO_EncodeChainDataForGoldenPage( nDevInfo, nPageBuffer, nSpareBuffer, ECC_ON );
++ if ( res != SUCCESS )
++ goto ErrorWriteUserSizePage;
++
++ //=============================================
++ // Write UserSize Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorWriteUserSizePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++
++ //=============================================
++ // Write Data
++ //=============================================
++ res = NAND_IO_WriteUserSizeData( nDevInfo,
++ 0,
++ nDevInfo->Feature.PageSize,
++ nPageBuffer );
++ if ( res != SUCCESS )
++ goto ErrorWriteUserSizePage;
++
++ //=============================================
++ // Write ECC Code
++ //=============================================
++ res = NAND_IO_WriteUserSizeData( nDevInfo,
++ 0,
++ nDevInfo->Feature.SpareSize,
++ nSpareBuffer );
++ if ( res != SUCCESS )
++ goto ErrorWriteUserSizePage;
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWriteUserSizePage;
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWriteUserSizePage;
++ }
++
++ErrorWriteUserSizePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_EnableWriteProtect();
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_CopyBackPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_CopyBackPage( NAND_IO_DEVINFO *nDevInfo, U32 nDesPageAddr, U32 nSrcPageAddr )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++
++ //=============================================
++ // Read Source Page Address
++ //=============================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ /* Generate Src Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nSrcPageAddr, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* CopyBack Command #1 [ 0x35 ] */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3535;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ //=============================================
++ // Copy Destination Page Address
++ //=============================================
++ /* CopyBack Command #2 */
++ if ( nDevInfo->Feature.MediaType & A_SMALL )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8A8A;
++ else
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8585;
++
++ /* Generate Des Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nDesPageAddr, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Waiting TADL Time 200nS */
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++
++ /* CopyBack Command #3 */
++ if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ // [ 32MB] K9F5608U0C, k9F5608U0B, K9F5608U0A
++ // [ 32MB] K9F5608Q0C, K9F5608Q0B
++ if (( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID ) &&
++ (( nDevInfo->Feature.DeviceID.Code[1] == 0x75 ) || ( nDevInfo->Feature.DeviceID.Code[1] == 0x35 )))
++ {
++ // Nothing
++ }
++ else
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ }
++ else
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ErrorCopyBackPage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_EnableWriteProtect();
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_CopyBackTwoPlanePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_CopyBackTwoPlanePage( NAND_IO_DEVINFO *nDevInfo, U32 nDesPageAddr, U32 nSrcPageAddr )
++{
++ unsigned int nReBlockPageAddr;
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++
++ //=============================================
++ // Read Source Page Address #1
++ //=============================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ /* Generate Src Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nSrcPageAddr, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* CopyBack Command #1 [ 0x35 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3535;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ //=============================================
++ // Read Source Page Address #2
++ //=============================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ /* Generate Src Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nSrcPageAddr + nDevInfo->Feature.PpB, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* CopyBack Command #1 [ 0x35 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3535;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ //=============================================
++ // Copy Destination Page Address
++ //=============================================
++ /* CopyBack Command #2 */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8585;
++
++ if ( nDesPageAddr & ( nDevInfo->Feature.PBpV / 2) * nDevInfo->Feature.PpB )
++ nReBlockPageAddr = (( nDevInfo->Feature.PBpV / 2) * nDevInfo->Feature.PpB);
++ else
++ nReBlockPageAddr = 0;
++
++ /* Generate Des Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nReBlockPageAddr, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Waiting TADL Time 200nS */
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++
++
++ /* CopyBack Command #3 */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1111;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ //=============================================
++ // Copy Destination Page Address
++ //=============================================
++ /* CopyBack Command #2 */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8181;
++
++ /* Generate Des Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nDesPageAddr+ nDevInfo->Feature.PpB, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Waiting TADL Time 200nS */
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++
++
++ /* CopyBack Command #3 */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ErrorCopyBackPage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_EnableWriteProtect();
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_EraseBlock
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_EraseBlock( NAND_IO_DEVINFO *nDevInfo, U32 nBlockPageAddr, int nFormatMode )
++{
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_WaitBusyForInterleave( nDevInfo, nBlockPageAddr );
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Erase Block
++ //=============================================
++
++ /* Command Block Erase #1 [ 0x60 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x6060;
++
++ /* Write Block Address */
++ NAND_IO_WriteBlockPageAddr( nBlockPageAddr, nDevInfo );
++
++ /* Command Erase Block #2 [ 0xD0 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xD0D0;
++
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) || ( nFormatMode == INTER_LEAVE_OFF ) )
++ {
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[nDevInfo->ChipNo] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[nDevInfo->ChipNo] = nBlockPageAddr;
++ goto ErrorEraseBlock;
++ }
++ }
++ else
++ {
++ NAND_IO_SetInterleaveStatus( nDevInfo, nBlockPageAddr );
++ if ( nDevInfo->BadBlockInfo.BlockStatus[nDevInfo->ChipNo] != MULTI_PLANE_BAD_BLOCK )
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[nDevInfo->ChipNo] = nBlockPageAddr;
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ErrorEraseBlock:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ NAND_IO_EnableWriteProtect();
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_EraseBlockForTwoPlane
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_EraseBlockForTwoPlane( NAND_IO_DEVINFO *nDevInfo, U32 nBlockPageAddr, int nFormatMode )
++{
++ unsigned int nReBlockPageAddr;
++ unsigned long int dwTempBlockPageAddr, dwAddSecondPageAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_WaitBusyForInterleave( nDevInfo, nBlockPageAddr );
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Erase Block
++ //=============================================
++ /* Command Block Erase #1 [ 0x60 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x6060;
++
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == HYNIX_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID ) )
++ {
++ dwTempBlockPageAddr = ( ( nDevInfo->Feature.PBpV << nDevInfo->ShiftPpB ) >> 1 );
++
++ if ( nBlockPageAddr & dwTempBlockPageAddr )
++ nReBlockPageAddr = dwTempBlockPageAddr;
++ else
++ nReBlockPageAddr = 0;
++
++ dwAddSecondPageAddr = nDevInfo->Feature.PpB;
++ }
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ {
++ nReBlockPageAddr = nBlockPageAddr;
++ dwAddSecondPageAddr = ( nDevInfo->DistrictNum << nDevInfo->ShiftPpB );
++ }
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID )
++ {
++ nReBlockPageAddr = nBlockPageAddr;
++ dwAddSecondPageAddr = nDevInfo->Feature.PpB;
++ }
++ else
++ {
++ // Local variable Init
++ nReBlockPageAddr = 0;
++ dwAddSecondPageAddr = 0;
++
++ res = ERR_NAND_IO_WRONG_PARAMETER;
++ goto ErrorEraseBlock;
++ }
++
++ /* Write Block Address */
++ NAND_IO_WriteBlockPageAddr( nReBlockPageAddr, nDevInfo ); // <== 1st Block
++
++ /* Command Block Erase #1 [ 0x60 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x6060;
++
++ /* Write Block Address */
++ NAND_IO_WriteBlockPageAddr( nBlockPageAddr + dwAddSecondPageAddr, nDevInfo ); // <== 2nd Block
++
++ /* Command Erase Block #2 [ 0xD0 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xD0D0;
++
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) || ( nFormatMode == INTER_LEAVE_OFF ) )
++ {
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatusForMultiPlane( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ {
++ if ( res == NAND_IO_DISTRICT_0 )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[0] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[0] = nBlockPageAddr;
++ }
++ else if ( res == NAND_IO_DISTRICT_1 )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[1] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[1] = ( nBlockPageAddr + dwAddSecondPageAddr );
++ }
++ }
++ else
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[0] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[0] = nBlockPageAddr;
++ nDevInfo->BadBlockInfo.BlockStatus[1] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[1] = ( nBlockPageAddr + dwAddSecondPageAddr );
++ }
++
++ goto ErrorEraseBlock;
++ }
++ }
++ else
++ {
++ NAND_IO_SetInterleaveStatus( nDevInfo, nBlockPageAddr );
++
++ if ( nDevInfo->Feature.MediaType & S_IL )
++ {
++ //=============================================
++ // Inter Leave
++ //=============================================
++ if ( nBlockPageAddr < (U32)( ( nDevInfo->Feature.PBpV >> 1 ) << nDevInfo->ShiftPpB ) )
++ {
++ if ( nDevInfo->BadBlockInfo.BlockStatus[0] != MULTI_PLANE_BAD_BLOCK )
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[0] = nBlockPageAddr;
++
++ if ( nDevInfo->BadBlockInfo.BlockStatus[1] != MULTI_PLANE_BAD_BLOCK )
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[1] = ( nBlockPageAddr + dwAddSecondPageAddr );
++ }
++ else
++ {
++ if ( nDevInfo->BadBlockInfo.BlockStatus[2] != MULTI_PLANE_BAD_BLOCK )
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[2] = nBlockPageAddr;
++
++ if ( nDevInfo->BadBlockInfo.BlockStatus[3] != MULTI_PLANE_BAD_BLOCK )
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[3] = ( nBlockPageAddr + dwAddSecondPageAddr );
++ }
++ }
++ else if ( nDevInfo->ExtInterleaveUsable == TRUE )
++ {
++ if ( nDevInfo->BadBlockInfo.BlockStatus[0] != MULTI_PLANE_BAD_BLOCK )
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[0] = nBlockPageAddr;
++
++ if ( nDevInfo->BadBlockInfo.BlockStatus[1] != MULTI_PLANE_BAD_BLOCK )
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[1] = ( nBlockPageAddr + dwAddSecondPageAddr );
++ }
++ }
++
++ErrorEraseBlock:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ NAND_IO_EnableWriteProtect();
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_GetFactoryBadMarkOfPBlock
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_GetFactoryBadMarkOfPBlock( NAND_IO_DEVINFO *nDevInfo, U32 nBlockPageAddr )
++{
++ unsigned short int i;
++ unsigned short int wPageSize, wReadSize;
++ unsigned short int wColumnAddr;
++ unsigned short int wPageAddr;
++ unsigned char cBSA[512];
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // Get Factory Bad Mark Page Default
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_MLC )
++ wPageAddr = nDevInfo->Feature.PpB - 1; /*last page*/
++ else
++ wPageAddr = 0; /*First Page*/
++
++ //=============================================
++ // Setting ReadSize & Column Address
++ //=============================================
++ wReadSize = 1;
++ wPageSize = nDevInfo->Feature.PageSize;
++
++ //=============================================
++ // Exception: Micron
++ //=============================================
++ if ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID )
++ {
++ if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ {
++ wPageAddr = 0;
++ wReadSize = nDevInfo->Feature.SpareSize;
++ }
++ else
++ {
++ /*SLC, MLC(4BIT/12BIT)*/
++ wPageAddr = 0;
++ wReadSize = 1;
++ }
++ }
++
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ wPageSize = ( wPageSize >> 1 );
++ wReadSize = ( wReadSize << 1 );
++ }
++
++ if ( wPageSize == 512 ) /* SMALL BLOCK NANDFLASH */
++ wColumnAddr = 517;
++ else if ( wPageSize == 2048 ) /* BIG BLOCK NANDFLAHS */
++ wColumnAddr = 2048;
++ else if ( wPageSize == 4096 ) /* 4K Page BIG BLOCK NANDFLASH */
++ wColumnAddr = 4096;
++ else
++ return ERR_NAND_IO_FAILED_GET_FACTORY_BAD_MARK_OF_PBLOCK;
++
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ wColumnAddr = ( wColumnAddr << 1 );
++
++ /* Read BSA */
++ res = NAND_IO_ReadUserSizePage( nDevInfo,
++ nBlockPageAddr + wPageAddr,
++ wColumnAddr,
++ wReadSize,
++ &cBSA[0] );
++ if ( res != SUCCESS )
++ return res;
++
++ /* Check BSA */
++ res = (NAND_IO_ERROR)SUCCESS;
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ //============================================
++ //PARALLEL: Check Signature(00h) of BadBlock
++ //============================================
++ for( i = 0 ; i < wReadSize; i += 2 )
++ {
++ if ( cBSA[i] != 0xFF )
++ res |= NAND_IO_STATUS_FAIL_CS0_PARALLEL;
++ if ( cBSA[i+1] != 0xFF )
++ res |= NAND_IO_STATUS_FAIL_CS1_PARALLEL;
++
++ if( res != SUCCESS )
++ return res;
++ }
++ }
++ else
++ {
++ //============================================
++ //SERIAL: Check Signature(00h) of BadBlock
++ //============================================
++ for( i = 0 ; i < wReadSize; ++ i )
++ {
++ if ( cBSA[i] != 0xFF )
++ res |= NAND_IO_STATUS_FAIL_CS0_SERIAL;
++
++ if ( res != SUCCESS )
++ return res;
++ }
++ }
++
++ return res;
++
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_GetUID
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_GetUID( NAND_IO_DEVINFO *nDevInfo, U16 *nCmd, U8 *rReadData )
++{
++ unsigned int i;
++ unsigned int RowAddr, ColumnAddr;
++ unsigned char cTempBuffer[512];
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_SetNFCBusWidth(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_EnableWriteProtect();
++
++ /* Command #1 */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & *nCmd;
++ /* Command #2 */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & *(nCmd+1);
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForRead( 0, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorGetUID;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Read Data */
++ res = NAND_IO_ReadUserSizeData( nDevInfo,
++ 0,
++ 512,
++ cTempBuffer );
++ if ( res != SUCCESS )
++ goto ErrorGetUID;
++
++ /* Copy Read Data */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ for ( i = 0; i < 256; ++ i )
++ rReadData[i] = cTempBuffer[i*2+0];
++ }
++ else
++ {
++ for ( i = 0; i < 256; ++ i )
++ rReadData[i] = cTempBuffer[i];
++ }
++
++ErrorGetUID:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ //=============================================
++ // Reset Chip
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_Reset( nDevInfo->ChipNo, NAND_IO_PARALLEL_COMBINATION_MODE );
++ else
++ NAND_IO_Reset( nDevInfo->ChipNo, NAND_IO_SERIAL_COMBINATION_MODE );
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++
++}
++
++//*****************************************************************************
++//*
++//*
++//* [ MISCELLANEOUS Functions of NAND IO ]
++//*
++//*
++//*****************************************************************************
++static __inline void NAND_IO_SetDataWidth( U32 width )
++{
++ if ( width == NAND_IO_DATA_WITDH_8BIT )
++ BITCLR( pNFC->NFC_CTRL, HwNFC_CTRL_BW_16 );
++ else
++ BITSET( pNFC->NFC_CTRL, HwNFC_CTRL_BW_16 );
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_PortControl( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_PortControl( int nOnOff )
++{
++ if ( !( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ {
++ if ( gNAND_GPIO_ON_OFF == ENABLE )
++ {
++ if ( nOnOff == ENABLE )
++ {
++ #if defined(TCC83XX)
++ NAND_IO_SEL_REG = gNANDIO_GSELReg;
++ #endif
++ #if defined(TCC79X)
++ // PORTCFG5 Configuration ( TCC7930S B[0]~B[6] is reserved )
++ // B[0] = NDXD[0]
++ // B[1] = NDXD[1]
++ // B[2] = NDXD[2]
++ // B[3] = NDXD[3]
++ // B[4] = NDXD[4]
++ // B[5] = NDXD[5]
++ // B[6] = NDXD[6]
++ HwPORTCFG5 &= (0xF0000000);
++ HwPORTCFG5 |= (0x01111111);
++
++ // PORTCFG6 Configuration
++ // B[7] = NDXD[7]
++ BITCSET( HwPORTCFG6, HwPORTCFG6_GPIOB7(15), HwPORTCFG6_GPIOB7(1));
++
++ #ifndef NAND_8BIT_ONLY
++ // PORTCFG2 Configuration
++ // F[15:12] = NDXD[15:12]
++ BITCSET( HwPORTCFG2, HwPORTCFG2_HPXD11(15), HwPORTCFG2_HPXD11(2));
++ // F[11:8] = NDXD[11:8]
++ BITCSET( HwPORTCFG2, HwPORTCFG2_HPXD15(15), HwPORTCFG2_HPXD15(2));
++ #endif
++ #endif
++ }
++ else
++ {
++ #if defined(TCC83XX)
++ NAND_IO_SEL_REG = 0;
++ NAND_IO_IOCON_REG |= gNANDIO_GIOCONReg;
++ NAND_IO_GDATA |= gNANDIO_GDATASet;
++ #endif
++ #if defined(TCC79X)
++ // PORTCFG5 Configuration ( TCC7930S B[0]~B[6] is reserved )
++ // B[0] = NDXD[0]
++ // B[1] = NDXD[1]
++ // B[2] = NDXD[2]
++ // B[3] = NDXD[3]
++ // B[4] = NDXD[4]
++ // B[5] = NDXD[5]
++ // B[6] = NDXD[6]
++ HwPORTCFG5 &= (0xF0000000);
++
++ // PORTCFG6 Configuration
++ // B[7] = NDXD[7]
++ BITCSET( HwPORTCFG6, HwPORTCFG6_GPIOB7(15), HwPORTCFG6_GPIOB7(0));
++ HwGPBEN |= 0x000000FF;
++ HwGPBDAT |= 0x000000FF;
++
++ #ifndef NAND_8BIT_ONLY
++ // PORTCFG2 Configuration
++ // F[11:8] = NDXD[11:8]
++ BITCSET( HwPORTCFG2, HwPORTCFG2_HPXD11(15), HwPORTCFG2_HPXD11(1));
++ // F[15:12] = NDXD[15:12]
++ BITCSET( HwPORTCFG2, HwPORTCFG2_HPXD15(15), HwPORTCFG2_HPXD15(1));
++ HwGPFEN |= 0x0000FF00;
++ HwGPFDAT |= 0x0000FF00;
++ #endif
++ #endif
++ }
++ }
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_PreProcess( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_PreProcess( void )
++{
++ NAND_IO_PortControl( ENABLE );
++
++ //IO_CKC_EnableBUS( IO_CKC_BUS_NFC );
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_PostProcess( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_PostProcess( void )
++{
++ //IO_CKC_DisableBUS( IO_CKC_BUS_NFC );
++
++ NAND_IO_PortControl( DISABLE );
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_SetBasicCycleTime( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_SetBasicCycleTime( void )
++{
++ /* SETUP 1 PW 5 HOLD 1 */
++ BITCSET( pNFC->NFC_CTRL, 0xFFF, 0xFFF );
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_SetCommCycleTime(void);
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_SetCommCycleTime(void)
++{
++ BITCSET( pNFC->NFC_CTRL, 0xFFF, CommCycleTime.RegValue );
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_SetWriteCycleTime(void);
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_SetWriteCycleTime(void)
++{
++ BITCSET( pNFC->NFC_CTRL, 0xFFF, WriteCycleTime.RegValue );
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_SetReadCycleTime(void);
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_SetReadCycleTime(void)
++{
++ BITCSET( pNFC->NFC_CTRL, 0xFFF, ReadCycleTime.RegValue );
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_SetNFCBusWidth(NAND_IO_DEVINFO *nDevInfo);
++*
++* DESCRIPTION :
++* INPUT:
++* NAND_IO_DEVINFO Structure Variable Pointer
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_SetNFCBusWidth( NAND_IO_DEVINFO *nDevInfo )
++{
++ if ( nDevInfo->Feature.MediaType & A_08BIT )
++ BITCLR( pNFC->NFC_CTRL, HwNFC_CTRL_MASK_EN );
++ else
++ BITSET( pNFC->NFC_CTRL, HwNFC_CTRL_MASK_EN );
++
++}
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_EnableChipSelect( U16 nChipNo );
++*
++* DESCRIPTION :
++* INPUT:
++* nChipNo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_EnableChipSelect( U16 nChipNo )
++{
++ if ( nChipNo == 0 )
++ {
++ /* NAND_IO_SUPPORT_4CS */
++ #if defined(NAND_2CS_ONLY)
++ BITSCLR( pNFC->NFC_CTRL, HwNFC_CTRL_CFG_nCS1, HwNFC_CTRL_CFG_nCS0 );
++ #else
++ BITSCLR( pNFC->NFC_CTRL, HwNFC_CTRL_CFG_NOACT, HwNFC_CTRL_CFG_nCS0 );
++ #endif
++ }
++ else if ( nChipNo == 1 )
++ {
++ /* NAND_IO_SUPPORT_4CS */
++ #if defined(NAND_2CS_ONLY)
++ BITSCLR( pNFC->NFC_CTRL, HwNFC_CTRL_CFG_nCS0, HwNFC_CTRL_CFG_nCS1 );
++ #else
++ BITSCLR( pNFC->NFC_CTRL, HwNFC_CTRL_CFG_NOACT, HwNFC_CTRL_CFG_nCS1 );
++ #endif
++ }
++ else if ( nChipNo == 2 )
++ {
++ /* NAND_IO_SUPPORT_4CS */
++ BITSCLR( pNFC->NFC_CTRL, HwNFC_CTRL_CFG_NOACT, HwNFC_CTRL_CFG_nCS2 );
++ }
++ else if ( nChipNo == 3 )
++ {
++ /* NAND_IO_SUPPORT_4CS */
++ BITSCLR( pNFC->NFC_CTRL, HwNFC_CTRL_CFG_NOACT, HwNFC_CTRL_CFG_nCS3 );
++ }
++
++ #if defined(_WINCE_) || defined(_LINUX_)
++ //NAND_IO_Delay();
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_DisableChipSelect( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_DisableChipSelect( void )
++{
++ /* NAND_IO_SUPPORT_4CS */
++ #if defined(NAND_2CS_ONLY)
++ BITSET( pNFC->NFC_CTRL, ( HwNFC_CTRL_CFG_nCS0 | HwNFC_CTRL_CFG_nCS1 ) );
++ #else
++ BITSET( pNFC->NFC_CTRL, HwNFC_CTRL_CFG_NOACT );
++ #endif
++
++ #if defined(_WINCE_) || defined(_LINUX_)
++ //NAND_IO_Delay();
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_EnableWriteProtect( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_EnableWriteProtect( void )
++{
++ #if defined(USE_V_ADDRESS)
++ #if defined(_WINCE_)
++ BITCLR( pGPIO->GPBDAT, NAND_IO_NFC_nWPBit );
++ #else
++ BITCLR( NAND_IO_NFC_nWP, NAND_IO_NFC_nWPBit );
++ #endif
++ #else
++ BITCLR( NAND_IO_NFC_nWP, NAND_IO_NFC_nWPBit );
++ #endif
++
++ #if defined(_WINCE_) || defined(_LINUX_)
++ //NAND_IO_Delay();
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_DisableWriteProtect( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_DisableWriteProtect( void )
++{
++ #if defined(USE_V_ADDRESS)
++ #if defined(_WINCE_)
++ BITSET( pGPIO->GPBDAT, NAND_IO_NFC_nWPBit );
++ #else
++ BITSET( NAND_IO_NFC_nWP, NAND_IO_NFC_nWPBit );
++ #endif
++ #else
++ BITSET( NAND_IO_NFC_nWP, NAND_IO_NFC_nWPBit );
++ #endif
++
++ #if defined(_WINCE_) || defined(_LINUX_)
++ //NAND_IO_Delay();
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline U32 NAND_IO_CheckReadyAndBusy( U16 nChipNo );
++*
++* DESCRIPTION :
++* INPUT:
++* nChipNo =
++*
++* OUTPUT: U32 - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline U32 NAND_IO_CheckReadyAndBusy( U16 nChipNo )
++{
++ nChipNo = 0; // Warning
++
++ #if defined(TCC89_92_BOARD)
++ return ISZERO( pNFC->NFC_CTRL, HwNFC_CTRL_RDY_RDY );
++ #else // TCC9200S_BOARD
++ return ISZERO( HwGPIOB->GPDAT, Hw31);
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_WaitBusy( U16 nChipNo );
++*
++* DESCRIPTION :
++* INPUT:
++* nChipNo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_WaitBusy( U16 nChipNo )
++{
++ // Misc. Configuration Register(MCFG)
++ // 0 : represent that READY pin is low
++ // 1 : high
++ // Delay : 200nS
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw13);
++ #endif
++
++ NAND_IO_Delay();
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw13);
++ #endif
++
++ while (NAND_IO_CheckReadyAndBusy( nChipNo ));
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_WaitBusyForProgramAndErase( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_WaitBusyForProgramAndErase( NAND_IO_DEVINFO *nDevInfo )
++{
++ // Misc. Configuration Register(MCFG)
++ // 0 : represent that READY pin is low
++ // 1 : high
++ // Delay : 200nS
++ NAND_IO_Delay();
++
++ while (NAND_IO_CheckReadyAndBusy( nDevInfo->ChipNo ))
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_WaitBusyForCacheProgram( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_WaitBusyForCacheProgram( NAND_IO_DEVINFO *nDevInfo )
++{
++ // Misc. Configuration Register(MCFG)
++ // 0 : represent that READY pin is low
++ // 1 : high
++ // Delay : 200nS
++ NAND_IO_Delay();
++
++ while (NAND_IO_CheckReadyAndBusy( nDevInfo->ChipNo ))
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_WaitBusyForInterleave( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nPageAddr =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_WaitBusyForInterleave( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr )
++{
++ unsigned int ChipNum = 0;
++ NAND_IO_ERROR res;
++
++ NAND_IO_Delay();
++ gInterLeaveWriteStatus = MULTI_PLANE_GOOD_BLOCK;
++
++ if ( gDevInfo->Feature.MediaType & S_IL )
++ {
++ //=============================================
++ // Inter Leave
++ //=============================================
++ if ( gInterLeaveCSNum != nDevInfo->ChipNo )
++ {
++ NAND_IO_EnableChipSelect( (U16)gInterLeaveCSNum );
++ NAND_IO_DisableWriteProtect();
++ nDevInfo->WriteStatus.ChipNo = (U8)gDevInfo->ChipNo;
++
++ while ( NAND_IO_ReadStatusForInterleaveClear( gDevInfo ) )
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++ }
++ else
++ {
++ NAND_IO_EnableChipSelect( (U16)gInterLeaveCSNum );
++ NAND_IO_DisableWriteProtect();
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++
++ while ( NAND_IO_ReadStatusForInterleave( gDevInfo, nPageAddr ) )
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++ }
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ }
++ else if ( nDevInfo->ExtInterleaveUsable == TRUE )
++ {
++ //=============================================
++ // External Inter Leave
++ //=============================================
++ if ( nDevInfo->ChipNo == 0 )
++ ChipNum = NAND_IO_STATUS_INTERLEAVING_CHIP1;
++ else if ( nDevInfo->ChipNo == 1 )
++ ChipNum = NAND_IO_STATUS_INTERLEAVING_CHIP2;
++ else if ( nDevInfo->ChipNo == 2 )
++ ChipNum = NAND_IO_STATUS_INTERLEAVING_CHIP3;
++ else if ( nDevInfo->ChipNo == 3 )
++ ChipNum = NAND_IO_STATUS_INTERLEAVING_CHIP4;
++
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++
++ if ( gInterLeaveIoStatus & (U16)ChipNum )
++ {
++ NAND_IO_WaitBusyForProgramAndErase( gDevInfo );
++ res = NAND_IO_ReadStatus( gDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)gDevInfo->ChipNo;
++ nDevInfo->BadBlockInfo.BlockStatus[gDevInfo->ChipNo] = MULTI_PLANE_BAD_BLOCK;
++ gInterLeaveWriteStatus = MULTI_PLANE_BAD_BLOCK;
++ }
++ gInterLeaveIoStatus &= ~ChipNum;
++ }
++ }
++
++ if ( gInterLeaveWriteStatus == MULTI_PLANE_BAD_BLOCK )
++ {
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = gInterLeavePageAddr;
++ gInterLeaveWriteStatus = MULTI_PLANE_GOOD_BLOCK;
++ res = ERR_NAND_IO_FAILED_WRITE;
++ }
++ else
++ {
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_GOOD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = 0xFFFFFFFF;
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* NAND_IO_ERROR NAND_IO_WaitBusyCheckForWriteEnd( NAND_IO_DEVINFO *nDevInfo )
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++NAND_IO_ERROR NAND_IO_WaitBusyCheckForWriteEnd( NAND_IO_DEVINFO *nDevInfo )
++{
++ NAND_IO_Delay();
++ NAND_IO_PreProcess();
++
++ if ( nDevInfo->Feature.MediaType & S_IL )
++ {
++ //=============================================
++ // Inter Leave
++ //=============================================
++
++ if ( gInterLeaveCSNum != nDevInfo->ChipNo )
++ {
++ NAND_IO_EnableChipSelect( (U16)gInterLeaveCSNum );
++ NAND_IO_DisableWriteProtect();
++
++ while ( NAND_IO_ReadStatusForInterleaveClear( nDevInfo ) )
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ }
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++
++ while ( NAND_IO_ReadStatusForInterleave( nDevInfo, gInterLeavePageAddr ) )
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++ }
++ }
++ else if ( nDevInfo->ExtInterleaveUsable == TRUE )
++ {
++ //=============================================
++ // External Inter Leave
++ //=============================================
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP1 )
++ {
++ NAND_IO_EnableChipSelect( 0 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusy(0);
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP1;
++
++ NAND_IO_DisableChipSelect();
++ }
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP2 )
++ {
++ NAND_IO_EnableChipSelect( 1 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusy(1);
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP2;
++
++ NAND_IO_DisableChipSelect();
++ }
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP3 )
++ {
++ NAND_IO_EnableChipSelect( 2 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusy(2);
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP3;
++
++ NAND_IO_DisableChipSelect();
++ }
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP4 )
++ {
++ NAND_IO_EnableChipSelect( 3 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusy(3);
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP4;
++
++ NAND_IO_DisableChipSelect();
++ }
++ }
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_SetInterleaveStatus( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nPageAddr =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_SetInterleaveStatus( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr )
++{
++
++ if ( nDevInfo->Feature.MediaType & S_IL )
++ {
++ //=============================================
++ // Inter Leave
++ //=============================================
++
++ if ( nPageAddr < (U32)(( ( nDevInfo->Feature.PBpV >> 1 ) << nDevInfo->ShiftPpB ) ))
++ {
++ gInterLeaveIoStatus |= NAND_IO_STATUS_INTERLEAVING_CHIP1;
++ gInterLeaveDie0BlockAddr = nPageAddr;
++ }
++ else
++ {
++ gInterLeaveIoStatus |= NAND_IO_STATUS_INTERLEAVING_CHIP2;
++ gInterLeaveDie1BlockAddr = nPageAddr;
++ }
++ gInterLeaveCSNum = nDevInfo->ChipNo;
++ }
++ else if ( nDevInfo->ExtInterleaveUsable == TRUE )
++ {
++ //=============================================
++ // External Inter Leave
++ //=============================================
++
++ if ( nDevInfo->ChipNo == 0 )
++ gInterLeaveIoStatus |= NAND_IO_STATUS_INTERLEAVING_CHIP1;
++ else if ( nDevInfo->ChipNo == 1 )
++ gInterLeaveIoStatus |= NAND_IO_STATUS_INTERLEAVING_CHIP2;
++ else if ( nDevInfo->ChipNo == 2 )
++ gInterLeaveIoStatus |= NAND_IO_STATUS_INTERLEAVING_CHIP3;
++ else if ( nDevInfo->ChipNo == 3 )
++ gInterLeaveIoStatus |= NAND_IO_STATUS_INTERLEAVING_CHIP4;
++ }
++
++ gDevInfo = (NAND_IO_DEVINFO *)nDevInfo;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_ClearInterleaveStatus( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_ClearInterleaveStatus( NAND_IO_DEVINFO *nDevInfo )
++{
++ NAND_IO_Delay();
++ gInterLeaveWriteStatus = MULTI_PLANE_GOOD_BLOCK;
++
++ if ( gDevInfo->Feature.MediaType & S_IL )
++ {
++ //=============================================
++ // Inter Leave
++ //=============================================
++ NAND_IO_EnableChipSelect( (U16)gInterLeaveCSNum );
++ NAND_IO_DisableWriteProtect();
++
++ while ( NAND_IO_ReadStatusForInterleaveClear( gDevInfo ) )
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ // TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ }
++ else if ( gDevInfo->ExtInterleaveUsable == TRUE )
++ {
++ //=============================================
++ // External Inter Leave
++ //=============================================
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP1 )
++ {
++ NAND_IO_EnableChipSelect( 0 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusyForProgramAndErase( gDevInfo );
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP1;
++
++ NAND_IO_DisableChipSelect();
++ }
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP2 )
++ {
++ NAND_IO_EnableChipSelect( 1 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusyForProgramAndErase( gDevInfo );
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP2;
++
++ NAND_IO_DisableChipSelect();
++ }
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP3 )
++ {
++ NAND_IO_EnableChipSelect( 2 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusyForProgramAndErase( gDevInfo );
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP3;
++
++ NAND_IO_DisableChipSelect();
++ }
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP4 )
++ {
++ NAND_IO_EnableChipSelect( 3 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusyForProgramAndErase( gDevInfo );
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP4;
++
++ NAND_IO_DisableChipSelect();
++ }
++
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_Delay( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_Delay( void )
++{
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_ReadStatus( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadStatus( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int uStatus;
++ unsigned int uCheckBit;
++ unsigned long int timeout;
++ NAND_IO_ERROR res;
++
++ //================================
++ // Command READ STATUS [ 0x70 ]
++ //================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7070;
++
++ // Delay : more than 200nS
++ NAND_IO_Delay();
++
++ //=============================================
++ // DATA BUS WIDTH Setting
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //================================
++ // Read IO Status
++ //================================
++ timeout = 0xFFFFF;
++ while ( timeout )
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x4040;
++
++ /* Check if it is ready */
++ if ( ( uStatus & uCheckBit ) == uCheckBit )
++ break;
++ }
++
++ if ( !timeout )
++ return ERR_NAND_IO_TIME_OUT_READ_STATUS;
++
++ //================================
++ // Check Bit Status
++ //================================
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x0101;
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( uStatus & uCheckBit )
++ {
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ if (uStatus & ( uCheckBit & 0x0100 ) )
++ res |= NAND_IO_STATUS_FAIL_CS1_PARALLEL;
++
++ if (uStatus & ( uCheckBit & 0x0001 ) )
++ res |= NAND_IO_STATUS_FAIL_CS0_PARALLEL;
++ }
++ else
++ {
++ if (uStatus & uCheckBit )
++ res |= NAND_IO_STATUS_FAIL_CS0_SERIAL;
++ }
++ }
++
++ return res;
++
++}
++
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_ReadStatusForMultiPlane( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForMultiPlane( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int uStatus;
++ unsigned int uCheckBit;
++ unsigned long int timeout;
++ NAND_IO_ERROR res;
++
++ //================================
++ // Command READ STATUS [ 0x70 ]
++ //================================
++ if ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7070;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7171;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7070;
++ else
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7070;
++
++ // Delay : more than 200nS
++ NAND_IO_Delay();
++
++ //=============================================
++ // DATA BUS WIDTH Setting
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //================================
++ // Read IO Status
++ //================================
++ timeout = 0xFFFFF;
++ while ( timeout )
++ {
++ /* Micron MultiPlane ReadBusy Check 0x40*/
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x4040;
++
++ /* Check if it is ready */
++ if ( ( uStatus & uCheckBit ) == uCheckBit )
++ break;
++ }
++
++ if ( !timeout )
++ return ERR_NAND_IO_TIME_OUT_READ_STATUS;
++
++ //================================
++ // Check Bit Status
++ //================================
++ if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x0101;
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( uStatus & uCheckBit )
++ {
++ if ( uStatus & ( nDevInfo->CmdMask & 0x0202 ))
++ res = (NAND_IO_ERROR)NAND_IO_DISTRICT_0;
++ else if ( uStatus & ( nDevInfo->CmdMask & 0x0404 ))
++ res = (NAND_IO_ERROR)NAND_IO_DISTRICT_1;
++ }
++ }
++ else
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x0101;
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( uStatus & uCheckBit )
++ {
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ if (uStatus & ( uCheckBit & 0x0100 ) )
++ res |= NAND_IO_STATUS_FAIL_CS1_PARALLEL;
++
++ if (uStatus & ( uCheckBit & 0x0001 ) )
++ res |= NAND_IO_STATUS_FAIL_CS0_PARALLEL;
++ }
++ else
++ {
++ if (uStatus & uCheckBit )
++ res |= NAND_IO_STATUS_FAIL_CS0_SERIAL;
++ }
++ }
++ }
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_ReadStatusForCacheProgram( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForCacheProgram( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int uStatus;
++ unsigned int uCheckBit;
++ unsigned long int timeout;
++ NAND_IO_ERROR res;
++
++ //================================
++ // Command READ STATUS [ 0x70 ]
++ //================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7070;
++
++ // Delay : more than 200nS
++ NAND_IO_Delay();
++
++ //=============================================
++ // DATA BUS WIDTH Setting
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //================================
++ // Read IO Status
++ //================================
++ timeout = 0xFFFFF;
++ while ( timeout )
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ if ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID )
++ uCheckBit = nDevInfo->CmdMask & 0x2020;
++ else
++ uCheckBit = nDevInfo->CmdMask & 0x4040;
++
++ /* Check if it is ready */
++ if ( ( uStatus & uCheckBit ) == uCheckBit )
++ break;
++ }
++
++ if ( !timeout )
++ return ERR_NAND_IO_TIME_OUT_READ_STATUS;
++
++ //================================
++ // Check Bit Status
++ //================================
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x0303;
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( uStatus & uCheckBit )
++ {
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ if (uStatus & ( uCheckBit & 0x0300 ) )
++ res |= NAND_IO_STATUS_FAIL_CS1_PARALLEL;
++
++ if (uStatus & ( uCheckBit & 0x0003 ) )
++ res |= NAND_IO_STATUS_FAIL_CS0_PARALLEL;
++ }
++ else
++ {
++ if (uStatus & uCheckBit )
++ res |= NAND_IO_STATUS_FAIL_CS0_SERIAL;
++ }
++ }
++
++ return res;
++
++}
++
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_ReadStatusForInterleave( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nPageAddr =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForInterleave( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr )
++{
++ unsigned int uStatus;
++ unsigned int uCheckBit;
++ unsigned int ChipNum;
++ unsigned long int timeout;
++ NAND_IO_ERROR res;
++
++ // Delay : more than 200nS
++ NAND_IO_Delay();
++
++ //=============================================
++ // DATA BUS WIDTH Setting
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //================================
++ // Command READ STATUS
++ //================================
++ if ( nPageAddr < (U32)( (nDevInfo->Feature.PBpV >> 1 ) * nDevInfo->Feature.PpB ) )
++ {
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP1 )
++ {
++ if ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF1F1;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF2F2;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7171;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7878;
++ NAND_IO_WriteBlockPageAddr( gInterLeaveDie0BlockAddr, nDevInfo );
++ }
++
++ ChipNum = NAND_IO_STATUS_INTERLEAVING_CHIP1;
++ }
++ else
++ return (NAND_IO_ERROR)SUCCESS;
++ }
++ else
++ {
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP2 )
++ {
++ if ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF2F2;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF3F3;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7171;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7878;
++ NAND_IO_WriteBlockPageAddr( gInterLeaveDie1BlockAddr, nDevInfo );
++ }
++ ChipNum = NAND_IO_STATUS_INTERLEAVING_CHIP2;
++ }
++ else
++ return (NAND_IO_ERROR)SUCCESS;
++ }
++
++ //================================
++ // Read IO Status
++ //================================
++ timeout = 0xFFFFF;
++ while ( timeout )
++ {
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID ) ||
++ ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID ) ||
++ ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID ) )
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x4040;
++
++ /* Check if it is ready */
++ if ( ( uStatus & uCheckBit ) == uCheckBit )
++ {
++ uCheckBit = nDevInfo->CmdMask & 0x0101;
++
++ /* Check if it is Fail */
++ if ( uStatus & uCheckBit )
++ {
++ if ( ChipNum == NAND_IO_STATUS_INTERLEAVING_CHIP1 )
++ {
++ if ( ( nDevInfo->Feature.MediaType & S_MP ) || ( nDevInfo->Feature.MediaType & S_MCP ) )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[0] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BlockStatus[1] = MULTI_PLANE_BAD_BLOCK;
++ }
++ else
++ nDevInfo->BadBlockInfo.BlockStatus[nDevInfo->ChipNo] = MULTI_PLANE_BAD_BLOCK;
++ }
++ else if ( ChipNum == NAND_IO_STATUS_INTERLEAVING_CHIP2 )
++ {
++ if ( ( nDevInfo->Feature.MediaType & S_MP ) || ( nDevInfo->Feature.MediaType & S_MCP ) )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[2] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BlockStatus[3] = MULTI_PLANE_BAD_BLOCK;
++ }
++ else
++ nDevInfo->BadBlockInfo.BlockStatus[nDevInfo->ChipNo] = MULTI_PLANE_BAD_BLOCK;
++ }
++
++ gInterLeaveWriteStatus = MULTI_PLANE_BAD_BLOCK;
++ }
++ break;
++ }
++ }
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x4040;
++
++ /* Check if it is ready */
++ if ( ( uStatus & uCheckBit ) == uCheckBit )
++ {
++ uCheckBit = nDevInfo->CmdMask & 0x0101;
++
++ /* Check if it is Fail */
++ if ( uStatus & uCheckBit )
++ {
++ if ( ChipNum == NAND_IO_STATUS_INTERLEAVING_CHIP1 )
++ {
++ if ( uStatus & ( nDevInfo->CmdMask & 0x0202 ))
++ nDevInfo->BadBlockInfo.BlockStatus[0] = MULTI_PLANE_BAD_BLOCK;
++ else if ( uStatus & ( nDevInfo->CmdMask & 0x0404 ))
++ nDevInfo->BadBlockInfo.BlockStatus[1] = MULTI_PLANE_BAD_BLOCK;
++ }
++ else if ( ChipNum == NAND_IO_STATUS_INTERLEAVING_CHIP2 )
++ {
++ if ( uStatus & ( nDevInfo->CmdMask & 0x0202 ))
++ nDevInfo->BadBlockInfo.BlockStatus[2] = MULTI_PLANE_BAD_BLOCK;
++ else if ( uStatus & ( nDevInfo->CmdMask & 0x0404 ))
++ nDevInfo->BadBlockInfo.BlockStatus[3] = MULTI_PLANE_BAD_BLOCK;
++ }
++
++ gInterLeaveWriteStatus = MULTI_PLANE_BAD_BLOCK;
++ }
++ break;
++ }
++ }
++ }
++
++ if ( !timeout )
++ return ERR_NAND_IO_TIME_OUT_READ_STATUS;
++
++ //================================
++ // SET NAND IO Status
++ //================================
++ switch(ChipNum)
++ {
++ case NAND_IO_STATUS_INTERLEAVING_CHIP1:
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP1;
++ break;
++
++ case NAND_IO_STATUS_INTERLEAVING_CHIP2:
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP2;
++ break;
++ }
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_ReadStatusForInterleaveClear( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForInterleaveClear( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int uStatus;
++ unsigned int uCheckBit;
++ unsigned long int timeout;
++ NAND_IO_ERROR res;
++
++ // Delay : more than 200nS
++ NAND_IO_Delay();
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=============================================
++ // DATA BUS WIDTH Setting
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=============================================
++ // Command READ STATUS - Interleave CHIP 1
++ //=============================================
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP1 )
++ {
++ if ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF1F1;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF2F2;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7171;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7878;
++ NAND_IO_WriteBlockPageAddr( gInterLeaveDie0BlockAddr, nDevInfo );
++ }
++
++ timeout = 0xFFFFF;
++ while ( timeout )
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x4040;
++
++ /* Check if it is ready */
++ if ( ( uStatus & uCheckBit ) == uCheckBit )
++ {
++ uCheckBit = nDevInfo->CmdMask & 0x0101;
++
++ /* Check if it is Fail */
++ if ( uStatus & uCheckBit )
++ {
++ if ( ( nDevInfo->Feature.MediaType & S_MP ) || ( nDevInfo->Feature.MediaType & S_MCP ) )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[0] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BlockStatus[1] = MULTI_PLANE_BAD_BLOCK;
++ }
++ else
++ nDevInfo->BadBlockInfo.BlockStatus[nDevInfo->ChipNo] = MULTI_PLANE_BAD_BLOCK;
++
++ gInterLeaveWriteStatus = MULTI_PLANE_BAD_BLOCK;
++ }
++ break;
++ }
++ }
++
++ if ( !timeout )
++ return ERR_NAND_IO_TIME_OUT_READ_STATUS;
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP1;
++ }
++
++ //=============================================
++ // Command READ STATUS - Interleave CHIP 2
++ //=============================================
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP2 )
++ {
++ if ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF2F2;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF3F3;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7171;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7878;
++ NAND_IO_WriteBlockPageAddr( gInterLeaveDie1BlockAddr, nDevInfo );
++ }
++
++ timeout = 0xFFFFF;
++ while ( timeout )
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x4040;
++
++ /* Check if it is ready */
++ if ( ( uStatus & uCheckBit ) == uCheckBit )
++ {
++ uCheckBit = nDevInfo->CmdMask & 0x0101;
++
++ /* Check if it is Fail */
++ if ( uStatus & uCheckBit )
++ {
++ if ( ( nDevInfo->Feature.MediaType & S_MP ) || ( nDevInfo->Feature.MediaType & S_MCP ) )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[2] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BlockStatus[3] = MULTI_PLANE_BAD_BLOCK;
++ }
++ else
++ nDevInfo->BadBlockInfo.BlockStatus[nDevInfo->ChipNo] = MULTI_PLANE_BAD_BLOCK;
++
++ gInterLeaveWriteStatus = MULTI_PLANE_BAD_BLOCK;
++ }
++ break;
++ }
++ }
++
++ if ( !timeout )
++ return ERR_NAND_IO_TIME_OUT_READ_STATUS;
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP2;
++ }
++
++ if ( !(gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ))
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForRead( U32 nPageAddr, U16 nColumnAddr,
++* U32* rRowAddr, U32* rColumnAddr,
++* NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nColumnAddr =
++* nDevInfo =
++* nPageAddr =
++* rColumnAddr =
++* rRowAddr =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForRead( U32 nPageAddr, U16 nColumnAddr,
++ U32* rRowAddr, U32* rColumnAddr,
++ NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned long int RowAddr;
++ unsigned long int ColumnAddr;
++
++ if ( nColumnAddr > ( nDevInfo->Feature.PageSize + nDevInfo->Feature.SpareSize ) )
++ return ERR_NAND_IO_WRONG_PARAMETER_ROW_COL_ADDRESS;
++
++ //==================================================
++ // Generate Column & Row Address
++ //==================================================
++ if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ // ColumnAddr ADR[7:0] ==> nColumnAddr
++ // RowAddr ADR[25:9] ==> (nPageAddr)*512
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (nColumnAddr>>1) : nColumnAddr;
++ RowAddr = nPageAddr;
++
++ if ( nDevInfo->Feature.MediaType & A_08BIT )
++ {
++ /* Command READ for SMALL NAND */
++ if ( ColumnAddr < 256 )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ ColumnAddr = ColumnAddr;
++ }
++ else if ( ColumnAddr < 512 )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0101;
++ ColumnAddr = ColumnAddr-256;
++ }
++ else
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5050;
++ ColumnAddr = ColumnAddr-512;
++ }
++ }
++ else if ( nDevInfo->Feature.MediaType & A_16BIT )
++ {
++ /* Command READ for SMALL NAND For 16Bit */
++ if ( ColumnAddr < 256 )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ ColumnAddr = ColumnAddr;
++ }
++ else
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5050;
++ ColumnAddr = ColumnAddr;
++ }
++ }
++ }
++ else
++ {
++ /* Command READ [ 0x00 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ // ColumnAddr ADR[11:0] ==> nColumnAddr
++ // RowAddr ADR[31:12] ==> nPageAddr
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (nColumnAddr>>1) : nColumnAddr;
++ RowAddr = nPageAddr;
++
++ }
++
++ *rRowAddr = RowAddr;
++ *rColumnAddr = ColumnAddr;
++
++ return (NAND_IO_ERROR)SUCCESS;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForWrite( U32 nPageAddr, U16 nColumnAddr,
++* U32* rRowAddr, U32* rColumnAddr,
++* NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nColumnAddr =
++* nDevInfo =
++* nPageAddr =
++* rColumnAddr =
++* rRowAddr =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForWrite( U32 nPageAddr, U16 nColumnAddr,
++ U32* rRowAddr, U32* rColumnAddr,
++ NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned long int RowAddr;
++ unsigned long int ColumnAddr;
++
++ if ( nColumnAddr > ( nDevInfo->Feature.PageSize + nDevInfo->Feature.SpareSize ) )
++ return ERR_NAND_IO_WRONG_PARAMETER_ROW_COL_ADDRESS;
++
++ //==================================================
++ // Generate Column & Row Address
++ //==================================================
++ if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ // ColumnAddr ADR[7:0] ==> nColumnAddr
++ // RowAddr ADR[25:9] ==> (nPageAddr)*512
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (nColumnAddr>>1) : nColumnAddr;
++ RowAddr = nPageAddr;
++
++ if ( nDevInfo->Feature.MediaType & A_08BIT )
++ {
++ /* Command READ for SMALL NAND */
++ if ( ColumnAddr < 256 )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ ColumnAddr = ColumnAddr;
++ }
++ else if ( ColumnAddr < 512 )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0101;
++ ColumnAddr = ColumnAddr-256;
++ }
++ else
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5050;
++ ColumnAddr = ColumnAddr-512;
++ }
++ }
++ else if ( nDevInfo->Feature.MediaType & A_16BIT )
++ {
++ /* Command READ for SMALL NAND */
++ if ( ColumnAddr < 256 )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ ColumnAddr = ColumnAddr;
++ }
++ else
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5050;
++ ColumnAddr = ColumnAddr;
++ }
++ }
++ }
++ else
++ {
++ // ColumnAddr ADR[11:0] ==> nColumnAddr
++ // RowAddr ADR[31:12] ==> nPageAddr
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (nColumnAddr>>1) : nColumnAddr;
++ RowAddr = nPageAddr;
++ }
++
++ *rRowAddr = RowAddr;
++ *rColumnAddr = ColumnAddr;
++
++ return (NAND_IO_ERROR)SUCCESS;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForCBandCP( U32 nPageAddr, U16 nColumnAddr,
++* U32* rRowAddr, U32* rColumnAddr,
++* NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nColumnAddr =
++* nDevInfo =
++* nPageAddr =
++* rColumnAddr =
++* rRowAddr =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForCBandCP( U32 nPageAddr, U16 nColumnAddr,
++ U32* rRowAddr, U32* rColumnAddr,
++ NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned long int RowAddr;
++ unsigned long int ColumnAddr;
++
++ if ( nColumnAddr > 0 )
++ return ERR_NAND_IO_WRONG_PARAMETER_ROW_COL_ADDRESS;
++
++ //==================================================
++ // Generate Column & Row Address
++ //==================================================
++ if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ // ColumnAddr ADR[7:0] ==> nColumnAddr
++ // RowAddr ADR[25:9] ==> (nPageAddr)*512
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (nColumnAddr>>1) : nColumnAddr;
++ RowAddr = nPageAddr;
++ ColumnAddr = ColumnAddr;
++ }
++ else
++ {
++ // ColumnAddr ADR[11:0] ==> nColumnAddr
++ // RowAddr ADR[31:12] ==> nPageAddr
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (nColumnAddr>>1) : nColumnAddr;
++ RowAddr = nPageAddr;
++ }
++
++ *rRowAddr = RowAddr;
++ *rColumnAddr = ColumnAddr;
++
++ return (NAND_IO_ERROR)SUCCESS;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_WriteRowColAddr( U32 nRowAddr, U32 nColumnAddr, NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nColumnAddr =
++* nDevInfo =
++* nRowAddr =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_WriteRowColAddr( U32 nRowAddr, U32 nColumnAddr, NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int nTempAddr;
++ unsigned int i;
++
++ //==================================================
++ // Write Column Address
++ //==================================================
++ for ( i = 0; i < nDevInfo->Feature.ColCycle; ++i )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ //NAND_IO_Delay();
++ #endif
++ nTempAddr = nDevInfo->CmdMask & (((nColumnAddr<<8)&0xFF00)|(nColumnAddr&0x00FF));
++ pNFC->NFC_SADDR = nTempAddr;
++
++ //pNFC->NFC_SADDR = nDevInfo->CmdMask & (((nColumnAddr<<8)&0xFF00)|(nColumnAddr&0x00FF));
++ nColumnAddr = nColumnAddr >> 8;
++
++ #if defined(_WINCE_) || defined(_LINUX_)
++ //NAND_IO_Delay();
++ #endif
++ }
++
++ //==================================================
++ // Write Row Address
++ //==================================================
++ nRowAddr = nRowAddr;
++
++ for ( i = 0; i < nDevInfo->Feature.RowCycle; ++i )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ //NAND_IO_Delay();
++ #endif
++ nTempAddr = nDevInfo->CmdMask & (((nRowAddr<<8)&0xFF00)|(nRowAddr&0x00FF));
++ pNFC->NFC_SADDR = nTempAddr;
++
++
++ //pNFC->NFC_SADDR = nDevInfo->CmdMask & (((nRowAddr<<8)&0xFF00)|(nRowAddr&0x00FF));
++ nRowAddr = nRowAddr >> 8;
++
++ #if defined(_WINCE_) || defined(_LINUX_)
++ //NAND_IO_Delay();
++ #endif
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_WriteColAddr( U32 nColumnAddr, NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nColumnAddr =
++* nDevInfo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_WriteColAddr( U32 nColumnAddr, NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int i;
++
++ //==================================================
++ // Write Column Address
++ //==================================================
++ for ( i = 0; i < nDevInfo->Feature.ColCycle; ++i )
++ {
++ pNFC->NFC_SADDR = nDevInfo->CmdMask & (((nColumnAddr<<8)&0xFF00)|(nColumnAddr&0x00FF));
++ nColumnAddr = nColumnAddr >> 8;
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_WriteBlockPageAddr( U32 nBlockPageAddr, NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nBlockPageAddr =
++* nDevInfo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_WriteBlockPageAddr( U32 nBlockPageAddr, NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int i;
++
++ //==================================================
++ // Write Block Address
++ //==================================================
++ for ( i = 0; i < nDevInfo->Feature.RowCycle; ++i )
++ {
++ pNFC->NFC_SADDR = nDevInfo->CmdMask & (((nBlockPageAddr<<8)&0xFF00)|(nBlockPageAddr&0x00FF));
++ nBlockPageAddr = nBlockPageAddr >> 8;
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline void NAND_IO_SetupDMA( void *pSRC, unsigned uSrcInc, unsigned uSrcMask,
++* void *pDST, unsigned uDstInc, unsigned uDstMask, int nMode );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nMode =
++* pDST =
++* pSRC =
++* uDstInc =
++* uDstMask =
++* uSrcInc =
++* uSrcMask =
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++static __inline void NAND_IO_SetupDMA( void *pSRC, unsigned uSrcInc, unsigned uSrcMask,
++ void *pDST, unsigned uDstInc, unsigned uDstMask, int nMode, int nDSize )
++{
++ unsigned int *pDMA_PhyBuffer;
++ unsigned int *pDMA_WorkBuffer;
++ unsigned int nSourceAddr, nDestAddr;
++ unsigned uCHCTRL;
++ unsigned int uTmp;
++
++ #if defined(_WINCE_)
++ tSYSTEM_PARAM *pSYS_Work_PARAM = (tSYSTEM_PARAM*)(SYSTEM_PARAM_BASEADDRESS);
++ #endif
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw15);
++ #endif
++
++ #if defined(_WINCE_)
++ pDMA_PhyBuffer = (unsigned int*)pSYS_Work_PARAM->DMA2.CH0_BUFFER; // Working Address
++ pDMA_WorkBuffer = (unsigned int*)pSYS_PARAM->DMA2.CH0_BUFFER; // Physical Address
++ #elif defined(_LINUX_)
++ #ifdef KERNEL_DRIVER
++ pDMA_PhyBuffer = dma_t.dma_addr;
++ pDMA_WorkBuffer = (unsigned int*)dma_t.v_addr;
++ #else
++ pDMA_PhyBuffer = (unsigned int*)DMA_ADDR;
++ pDMA_WorkBuffer = (unsigned int*)DMA_ADDR;
++ #endif
++ #else // NU
++ pDMA_PhyBuffer = 0x10003000;
++ pDMA_WorkBuffer = 0x10003000;
++ #endif
++
++ // Read Test
++ //pDMA_PhyBuffer = 0x10003000;
++ //pDMA_WorkBuffer = 0x10003000;
++
++ //pDMA_PhyBuffer = pDST;
++ //pDMA_WorkBuffer = pDST;
++
++ if ( nMode == NAND_IO_DMA_WRITE )
++ {
++ // pSRC: Buffer Address
++ // pDST: NFC_LDATA
++
++ BITCSET(pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_8 | HwNFC_CTRL_DEN_EN | HwNFC_CTRL_PSIZE_512 );
++
++ //pSRC --> pDMA_WorkBuffer
++ memcpy( pDMA_WorkBuffer, pSRC, nDSize );
++
++ // Target Physical Address- for DMA H/W Control Set
++ nSourceAddr = (unsigned int)pDMA_PhyBuffer;
++ nDestAddr = (unsigned int)pDST;
++
++ //============================================================
++ // DMA Control Register Set
++ //============================================================
++ uCHCTRL =
++ // HwCHCTRL_SYNC_ON |
++ // HwCHCTRL_HRD_W |
++ HwCHCTRL_BST_BURST |
++ HwCHCTRL_TYPE_SINGL |
++ HwCHCTRL_HRD_WR |
++ // HwCHCTRL_BST_BURST |
++ HwCHCTRL_BSIZE_8 |
++ HwCHCTRL_WSIZE_32 |
++ HwCHCTRL_FLAG |
++ HwCHCTRL_EN_ON |
++ 0;
++
++ }
++ else // NAND_IO_DMA_READ
++ {
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw5);
++ #endif /* READ_SPEED_CHECK */
++
++ // pSRC: NFC_LDATA
++ // pDST: Buffer Address
++
++ BITCSET(pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_8 | HwNFC_CTRL_DEN_EN | HwNFC_CTRL_PSIZE_512 );
++
++ nSourceAddr = (unsigned int)pSRC; // NFC_LDATA Physical Address: ex_TCC89,92XX: 0XF050b0020
++ nDestAddr = (unsigned int)pDMA_PhyBuffer;
++
++ //============================================================
++ // DMA Control Register Set
++ //============================================================
++ uCHCTRL =
++ // HwCHCTRL_SYNC_ON |
++ // HwCHCTRL_HRD_W |
++ HwCHCTRL_BST_BURST |
++ HwCHCTRL_TYPE_SINGL |
++ HwCHCTRL_HRD_RD |
++ // HwCHCTRL_BST_BURST |
++ HwCHCTRL_BSIZE_8 |
++ HwCHCTRL_WSIZE_32 |
++ HwCHCTRL_FLAG |
++ HwCHCTRL_EN_ON |
++ 0;
++ }
++
++ //============================================================
++ // Set Source Address & Source Parameter (mask + increment)
++ //============================================================
++ pNAND_DMA->ST_SADR = nSourceAddr;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ pNAND_DMA->SPARAM[0] = (uSrcInc | (uSrcMask << 4));
++ #else
++ pNAND_DMA->SPARAM = (uSrcInc | (uSrcMask << 4));
++ #endif
++ //============================================================
++ // Set Dest Address & Dest Parameter (mask + increment)
++ //============================================================
++ pNAND_DMA->ST_DADR = nDestAddr;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ pNAND_DMA->DPARAM[0] = (uDstInc | (uDstMask << 4));
++ #else
++ pNAND_DMA->DPARAM = (uDstInc | (uDstMask << 4));
++ #endif
++ //============================================================
++ // Calculate byte size per 1 Hop transfer
++ //============================================================
++ uTmp = (uCHCTRL & (Hw5+Hw4)) >> 4; // calc log2(word size)
++ uTmp = uTmp + ( (uCHCTRL & (Hw7+Hw6)) >> 6); // calc log2(word * burst size)
++
++ //============================================================
++ // Set External DMA Request Register
++ //============================================================
++ pNAND_DMA->EXTREQ = Hw18; // NFC
++
++ //============================================================
++ // Set Hcount
++ //============================================================
++ if (uTmp)
++ pNAND_DMA->HCOUNT = (nDSize + (1 << uTmp) - 1) >> uTmp;
++ else
++ pNAND_DMA->HCOUNT = nDSize;
++
++ //============================================================
++ // Set & Enable DMA
++ //============================================================
++ pNAND_DMA->CHCTRL = uCHCTRL;
++
++ //============================================================
++ // Set NFC DSize & IREQ Clear
++ //============================================================
++ pNFC->NFC_DSIZE = nDSize;
++ pNFC->NFC_IREQ = 0x77; // HwNFC_IREQ_FLAG1;
++
++ //============================================================
++ // DMA Transfer Start
++ //============================================================
++ if ( nMode == NAND_IO_DMA_WRITE )
++ {
++ if ( pNFC->NFC_CTRL1 & Hw31 )
++ BITCLR( pNFC->NFC_CTRL1, Hw31 );
++
++ pNFC->NFC_PSTART = 0;
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ if ( pNFC->NFC_CTRL1 & Hw30 )
++ BITSET( pNFC->NFC_CTRL1, Hw31 );
++ }
++ else
++ {
++ pNFC->NFC_RSTART = 0;
++
++ while ( ISZERO(pNFC->NFC_IREQ, HwNFC_IREQ_FLAG0) );
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw5);
++ #endif /* READ_SPEED_CHECK */
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw4);
++ #endif
++
++ memcpy( pDST, pDMA_WorkBuffer, nDSize );
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw4);
++ #endif
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline void NAND_IO_SetupDMADoubleBuf( int nMode, int nDMACh );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* nDMACh =
++* nMode =
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++static __inline void NAND_IO_SetupDMADoubleBuf( int nMode, int nDMACh )
++{
++ unsigned int *pDMA_PhyBuffer;
++ unsigned int *pDMA_WorkBuffer;
++ unsigned int nSourceAddr, nDestAddr;
++ unsigned uCHCTRL;
++ unsigned int uTmp;
++ unsigned int uSrcInc, uSrcMask;
++ unsigned int uDstInc, uDstMask;
++
++ if ( nMode == NAND_IO_DMA_WRITE )
++ {
++ uSrcInc = 4;
++ uSrcMask = 0;
++ uDstInc = 0;
++ uDstMask = 0;
++ }
++ else
++ {
++ uSrcInc = 0;
++ uSrcMask = 0;
++ uDstInc = 4;
++ uDstMask = 0;
++ }
++
++ if ( nDMACh & 1 )
++ {
++ pDMA_PhyBuffer = gpDMA_PhyBuffer0; // Working Address
++ pDMA_WorkBuffer = gpDMA_WorkBuffer0; // Physical Address
++ }
++ else
++ {
++ pDMA_PhyBuffer = gpDMA_PhyBuffer1; // Working Address
++ pDMA_WorkBuffer = gpDMA_WorkBuffer1; // Physical Address
++ }
++
++ if ( nMode == NAND_IO_DMA_WRITE )
++ {
++ // pSRC: Buffer Address
++ // pDST: NFC_LDATA
++
++ BITCSET(pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_8 | HwNFC_CTRL_DEN_EN | HwNFC_CTRL_PSIZE_512 );
++
++ //pSRC --> pDMA_WorkBuffer
++ //memcpy( pDMA_WorkBuffer, pSRC, 512 );
++
++ // Target Physical Address- for DMA H/W Control Set
++ nSourceAddr = (unsigned int)pDMA_PhyBuffer;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ nDestAddr = (unsigned int)&NAND_IO_HwLDATA_PA;
++ #else
++ nDestAddr = (unsigned int)&pNFC->NFC_LDATA;
++ #endif
++
++ //============================================================
++ // DMA Control Register Set
++ //============================================================
++ uCHCTRL =
++ // HwCHCTRL_SYNC_ON |
++ // HwCHCTRL_HRD_W |
++ HwCHCTRL_BST_BURST |
++ HwCHCTRL_TYPE_SINGL |
++ HwCHCTRL_HRD_WR |
++ // HwCHCTRL_BST_BURST |
++ HwCHCTRL_BSIZE_8 |
++ HwCHCTRL_WSIZE_32 |
++ HwCHCTRL_FLAG |
++ HwCHCTRL_EN_ON |
++ 0;
++
++ }
++ else // NAND_IO_DMA_READ
++ {
++
++ BITCSET(pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_8 | HwNFC_CTRL_DEN_EN | HwNFC_CTRL_PSIZE_512 );
++
++ #if defined(_WINCE_) || defined(_LINUX_)
++ nSourceAddr = (unsigned int)&NAND_IO_HwLDATA_PA; // NFC_LDATA Physical Address: ex_TCC89,92XX: 0XF050b0020
++ #else
++ nSourceAddr = (unsigned int)&pNFC->NFC_LDATA;
++ #endif
++ nDestAddr = (unsigned int)pDMA_PhyBuffer;
++
++ //============================================================
++ // DMA Control Register Set
++ //============================================================
++ uCHCTRL =
++ // HwCHCTRL_SYNC_ON |
++ // HwCHCTRL_HRD_W |
++ HwCHCTRL_BST_BURST |
++ HwCHCTRL_TYPE_SINGL |
++ HwCHCTRL_HRD_RD |
++ // HwCHCTRL_BST_BURST |
++ HwCHCTRL_BSIZE_8 |
++ HwCHCTRL_WSIZE_32 |
++ HwCHCTRL_FLAG |
++ HwCHCTRL_EN_ON |
++ 0;
++ }
++
++ //============================================================
++ // Set Source Address & Source Parameter (mask + increment)
++ //============================================================
++ pNAND_DMA->ST_SADR = nSourceAddr;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ pNAND_DMA->SPARAM[0] = (uSrcInc | (uSrcMask << 4));
++ #else
++ pNAND_DMA->SPARAM = (uSrcInc | (uSrcMask << 4));
++ #endif
++ //============================================================
++ // Set Dest Address & Dest Parameter (mask + increment)
++ //============================================================
++ pNAND_DMA->ST_DADR = nDestAddr;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ pNAND_DMA->DPARAM[0] = (uDstInc | (uDstMask << 4));
++ #else
++ pNAND_DMA->DPARAM = (uDstInc | (uDstMask << 4));
++ #endif
++ //============================================================
++ // Calculate byte size per 1 Hop transfer
++ //============================================================
++ uTmp = (uCHCTRL & (Hw5+Hw4)) >> 4; // calc log2(word size)
++ uTmp = uTmp + ( (uCHCTRL & (Hw7+Hw6)) >> 6); // calc log2(word * burst size)
++
++ //============================================================
++ // Set External DMA Request Register
++ //============================================================
++ pNAND_DMA->EXTREQ = Hw18; // NFC
++
++ //============================================================
++ // Set Hcount
++ //============================================================
++ if (uTmp)
++ pNAND_DMA->HCOUNT = (512 + (1 << uTmp) - 1) >> uTmp;
++ else
++ pNAND_DMA->HCOUNT = 512;
++
++ //============================================================
++ // Set & Enable DMA
++ //============================================================
++ pNAND_DMA->CHCTRL = uCHCTRL;
++
++ //============================================================
++ // Set NFC DSize & IREQ Clear
++ //============================================================
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // HwNFC_IREQ_FLAG1;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_SetupECC( U16 nEccOnOff, U16 nEncDec, U16 nEccType, U32 EccBaseAddr )
++*
++* DESCRIPTION :
++* INPUT:
++* nEccOnOff =
++* nEccType =
++* nEncDec =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_SetupECC( U16 nEccOnOff, U16 nEncDec, U16 nEccType, U16 nAccessType, U32 EccBaseAddr )
++{
++ if ( nEccOnOff == ECC_OFF )
++ {
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ BITCLR(pIOBUSCFG_T->HRSTEN0, Hw24);
++ BITSET(pIOBUSCFG_T->HRSTEN0, Hw24);
++
++ pECC->ECC_BASE = 0xF05B0010; /* Base Address for ECC Calculation */
++ pECC->ECC_MASK = 0x00000000; /* Address mask for ECC area */
++ pECC->ECC_CTRL &= HwECC_CTRL_EN_DIS;
++
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++ }
++ else if ( nEccOnOff == ECC_ON )
++ {
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ if ( nEncDec == ECC_DECODE )
++ {
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++
++ if ( nAccessType == NAND_MCU_ACCESS )
++ {
++ #if defined(TCC83XX)
++ HwECC_SEL = HwECC_SEL_AHB_BUS;
++ #elif defined(TCC79XX)
++ BITCSET(HwSTORAGE, HwSTORAGE_ECCS_MPDBUS, HwSTORAGE_ECCS_MPDBUS);
++ #elif defined(TCC89XX) || defined(TCC92XX)
++ pIOBUSCFG_T->STORAGE = HwIOBUSCFG_STORAGE_NFC;
++ #endif
++ pECC->ECC_BASE = (0x000FFFFF & EccBaseAddr);
++ }
++ else if ( nAccessType == NAND_DMA_ACCESS )
++ {
++ #if defined(TCC83XX)
++ HwECC_SEL = HwECC_SEL_AHB_BUS;
++ #elif defined(TCC79XX)
++ BITCSET(HwSTORAGE, HwSTORAGE_ECCS_MPDBUS, HwSTORAGE_ECCS_IOBUS);
++ #elif defined(TCC92XX) || defined(TCC89XX)
++ pIOBUSCFG_T->STORAGE = HwIOBUSCFG_STORAGE_NFC;
++ #endif
++
++ pECC->ECC_BASE = EccBaseAddr;
++ }
++
++ pECC->ECC_MASK = 0x00000000; /* Address mask for ECC area */
++
++ if ( nEccType == SLC_ECC_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_SLCDE;
++ else if (nEccType == MLC_ECC_4BIT_TYPE )
++ {
++ pECC->ECC_CTRL |= HwECC_CTRL_IEN_MECC4_EN;
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL4DE;
++ }
++ else if (nEccType == MLC_ECC_8BIT_TYPE )
++ {
++ pECC->ECC_CTRL |= HwECC_CTRL_IEN_MECC8_EN;
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL8DE;
++ }
++ else if (nEccType == MLC_ECC_12BIT_TYPE )
++ {
++ #ifdef ECC_TYPE_BCH
++ pECC->ECC_CTRL |= HwECC_CTRL_IEN_MECC12_EN;
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL12DE;
++ #endif
++ }
++ }
++ else if ( nEncDec == ECC_ENCODE )
++ {
++ if ( nAccessType == NAND_MCU_ACCESS )
++ {
++ #if defined(TCC83XX)
++ HwECC_SEL = HwECC_SEL_AHB_BUS;
++ #elif defined(TCC79XX)
++ BITCSET(HwSTORAGE, HwSTORAGE_ECCS_MPDBUS, HwSTORAGE_ECCS_MPDBUS);
++ #elif defined(TCC92XX) || defined(TCC89XX)
++ pIOBUSCFG_T->STORAGE = HwIOBUSCFG_STORAGE_NFC;
++ #endif
++
++ pECC->ECC_BASE = (0x000FFFFF &EccBaseAddr);
++ }
++ else if ( nAccessType == NAND_DMA_ACCESS )
++ {
++ #if defined(TCC83XX)
++ HwECC_SEL = HwECC_SEL_AHB_BUS;
++ #elif defined(TCC79XX)
++ BITCSET(HwSTORAGE, HwSTORAGE_ECCS_MPDBUS, HwSTORAGE_ECCS_IOBUS);
++ #elif defined(TCC92XX) || defined(TCC89XX)
++ pIOBUSCFG_T->STORAGE = HwIOBUSCFG_STORAGE_NFC;
++ #endif
++
++ pECC->ECC_BASE = EccBaseAddr;
++ }
++
++ pECC->ECC_MASK = 0x00000000; /* Address mask for ECC area */
++
++ if ( nEccType == SLC_ECC_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_SLCEN;
++ else if (nEccType == MLC_ECC_4BIT_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL4EN;
++ else if (nEccType == MLC_ECC_8BIT_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL8EN;
++ else if (nEccType == MLC_ECC_12BIT_TYPE )
++ {
++ #ifdef ECC_TYPE_BCH
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL12EN;
++ #endif
++ }
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++
++ }
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_EncodeSLC( U8* nSpareBuffer );
++*
++* DESCRIPTION :
++* INPUT:
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_EncodeECC( U16 nEccType, U8* nSpareBuffer )
++{
++ unsigned int nECC_CODE;
++ unsigned char *pcECC;
++ unsigned int *pSpareDW;
++
++ if ( nEccType == SLC_ECC_TYPE )
++ {
++ //==================================================================
++ // [ TNFTL V1.0 ]
++ //==================================================================
++ // 520th : P64-P8 of ECC Area-1 [ DATA 256-511 ]
++ // 521th : P1024-P128 of ECC Area-1 [ DATA 256-511 ]
++ // 522th : P4-P1 of ECC Area-1 [ DATA 256-511 ]
++ // 525th : P64-P8 of ECC Area-0 [ DATA 0-255 ]
++ // 526th : P1024-P128 of ECC Area-0 [ DATA 0-255 ]
++ // 527th : P4-P1 of ECC Area-0 [ DATA 0-255 ]
++ //==================================================================
++
++ pcECC = (unsigned char* )&pECC->ECC_CODE0;
++
++ /* Area-1 */
++ nSpareBuffer[10] = pcECC[0]; // P4-P1
++ nSpareBuffer[ 9] = pcECC[1]; // P1024-P128
++ nSpareBuffer[ 8] = pcECC[2]; // P64-P8
++
++ /* Area-0 */
++ nSpareBuffer[15] = pcECC[4]; // P4-P1
++ nSpareBuffer[14] = pcECC[5]; // P1024-128
++ nSpareBuffer[13] = pcECC[6]; // P64-P8
++ }
++ else
++ {
++ pSpareDW = (unsigned int *)nSpareBuffer;
++
++ nECC_CODE = pECC->ECC_CODE0;
++ *pSpareDW = nECC_CODE; ++pSpareDW;
++
++ nECC_CODE = pECC->ECC_CODE1;
++ *pSpareDW = nECC_CODE; ++pSpareDW;
++
++ nECC_CODE = pECC->ECC_CODE2;
++ *pSpareDW = nECC_CODE; ++pSpareDW;
++
++ nECC_CODE = pECC->ECC_CODE3;
++ *pSpareDW = nECC_CODE; ++pSpareDW;
++
++ nECC_CODE = pECC->ECC_CODE4;
++ *pSpareDW = nECC_CODE; ++pSpareDW;
++
++ nECC_CODE = pECC->ECC_CODE5;
++ *pSpareDW = nECC_CODE; ++pSpareDW;
++
++ nECC_CODE = pECC->ECC_CODE6;
++ *pSpareDW = nECC_CODE; ++pSpareDW;
++ }
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_EncodeNBECC( U16 nEccType, U8* nSpareBuffer );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* nEccType =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_EncodeNBECC( U16 nEccType, U8* nSpareBuffer )
++{
++ unsigned char* pcECC;
++ unsigned int nMLC_ECC;
++
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ if ( nEccType == SLC_ECC_TYPE )
++ {
++ //==================================================================
++ // [ TNFTL V1.0 ]
++ //==================================================================
++ // 520th : P64-P8 of ECC Area-1 [ DATA 256-511 ]
++ // 521th : P1024-P128 of ECC Area-1 [ DATA 256-511 ]
++ // 522th : P4-P1 of ECC Area-1 [ DATA 256-511 ]
++ // 525th : P64-P8 of ECC Area-0 [ DATA 0-255 ]
++ // 526th : P1024-P128 of ECC Area-0 [ DATA 0-255 ]
++ // 527th : P4-P1 of ECC Area-0 [ DATA 0-255 ]
++ //==================================================================
++ pcECC = (unsigned char*)&pECC->ECC_CODE0;
++
++ /* Area-1 */
++ nSpareBuffer[10] = pcECC[0]; // P4-P1
++ nSpareBuffer[ 9] = pcECC[1]; // P1024-P128
++ nSpareBuffer[ 8] = pcECC[2]; // P64-P8
++
++ /* Area-0 */
++ nSpareBuffer[15] = pcECC[4]; // P4-P1
++ nSpareBuffer[14] = pcECC[5]; // P1024-128
++ nSpareBuffer[13] = pcECC[6]; // P64-P8
++ }
++ else if ( nEccType == MLC_ECC_4BIT_TYPE )
++ {
++ //==================================================================
++ // [ TNFTL V1.0 ]
++ //==================================================================
++ // 512th : MLC ECC 0th Byte
++ // 513th : MLC ECC 1th Byte
++
++ // 514th : MLC ECC 2th Byte
++ // 515th : MLC ECC 3th Byte
++ // 516th : MLC ECC 4th Byte
++ // 517th : MLC ECC 5th Byte
++
++ // 518th : MLC ECC 6th Byte
++ // 519th : MLC ECC 7th Byte
++ // 520th : MLC ECC 8th Byte
++ // 521th : MLC ECC 9th Byte
++ //==================================================================
++
++ /* Sync Delay */
++ ASM_NOP;
++
++ nMLC_ECC = pECC->ECC_CODE0;
++ *(nSpareBuffer + 8) = (U8)nMLC_ECC;
++ *(nSpareBuffer + 9) = (U8)(nMLC_ECC >> 8);
++ *(nSpareBuffer + 10) = (U8)(nMLC_ECC >> 16);
++ *(nSpareBuffer + 11) = (U8)(nMLC_ECC >> 24);
++
++ nMLC_ECC = pECC->ECC_CODE1;
++ *(nSpareBuffer + 12) = (U8)nMLC_ECC;
++ *(nSpareBuffer + 13) = (U8)(nMLC_ECC >> 8);
++ *(nSpareBuffer + 14) = (U8)((nMLC_ECC >> 16) & 0x0F);
++ }
++
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_CorrectionSLC( U8* nPageBuffer, U8* nSpareBuffer );
++*
++* DESCRIPTION :
++* INPUT:
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_CorrectionSLC( U8* nPageBuffer, U8* nSpareBuffer )
++{
++ unsigned int uErrorStatus;
++ unsigned int uSLCECC0, uSLCECC1;
++ NAND_IO_ERROR res;
++
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ //==================================================================
++ // [ TNFTL V1.0 ]
++ //==================================================================
++ // 520th : P64-P8 of ECC Area-1 [ DATA 256-511 ]
++ // 521th : P1024-P128 of ECC Area-1 [ DATA 256-511 ]
++ // 522th : P4-P1 of ECC Area-1 [ DATA 256-511 ]
++ // 525th : P64-P8 of ECC Area-0 [ DATA 0-255 ]
++ // 526th : P1024-P128 of ECC Area-0 [ DATA 0-255 ]
++ // 527th : P4-P1 of ECC Area-0 [ DATA 0-255 ]
++ //==================================================================
++
++ /* Load SLC ECC Code for Area 1 */
++ uSLCECC0 = ( nSpareBuffer[0] << 16 ) +
++ ( nSpareBuffer[1] << 8 ) +
++ ( nSpareBuffer[2] );
++
++ /* Load SLC ECC Code for Area 0 */
++ uSLCECC1 = ( nSpareBuffer[3] << 16 ) +
++ ( nSpareBuffer[4] << 8 ) +
++ ( nSpareBuffer[5] );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Correction Area 0 */
++ pECC->ECC_CODE1 = uSLCECC1;
++ uErrorStatus = pECC->ERRNUM & 0x7;
++
++ if ( uErrorStatus == HwERR_NUM_ERR1 )
++ {
++ nPageBuffer[pECC->ECC_EADDR0 >> 3] ^= (1 << (pECC->ECC_EADDR0 & 0x07));
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ else if ( uErrorStatus != HwERR_NUM_NOERR )
++ {
++ res = ERR_NAND_IO_FAILED_CORRECTION_SLC_ECC;
++ goto ErrorCorrectionSLC;
++ }
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Correction Area 1 */
++ pECC->ECC_CODE0 = uSLCECC0;
++ uErrorStatus = pECC->ERRNUM & 0x7;
++
++ if ( uErrorStatus == HwERR_NUM_ERR1 )
++ {
++ nPageBuffer[pECC->ECC_EADDR0 >> 3] ^= (1 << (pECC->ECC_EADDR0 & 0x07));
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ else if ( uErrorStatus != HwERR_NUM_NOERR )
++ {
++ res = ERR_NAND_IO_FAILED_CORRECTION_SLC_ECC;
++ goto ErrorCorrectionSLC;
++ }
++
++ErrorCorrectionSLC:
++
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_CorrectionMLC12( U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDataSize =
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_CorrectionMLC( U16 nEccType, U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize )
++{
++ unsigned int i;
++ unsigned int uErrAddr;
++ unsigned int uErrorStatus;
++ unsigned int *pSpareDW;
++ #ifdef _LINUX_
++ unsigned char nTempBuf[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nTempBuf[30];
++ #endif
++ NAND_IO_ECC_INFO *pECC_Info;
++ NAND_IO_ERROR res;
++
++ if ( nEccType == MLC_ECC_4BIT_TYPE )
++ pECC_Info = &gMLC_ECC_4Bit;
++ else if ( nEccType == MLC_ECC_8BIT_TYPE )
++ pECC_Info = &gMLC_ECC_8Bit;
++ else if ( nEccType == MLC_ECC_12BIT_TYPE )
++ pECC_Info = &gMLC_ECC_12Bit;
++ else if ( nEccType == MLC_ECC_14BIT_TYPE )
++ pECC_Info = &gMLC_ECC_14Bit;
++ else if ( nEccType == MLC_ECC_16BIT_TYPE )
++ pECC_Info = &gMLC_ECC_16Bit;
++ else
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ memset( nTempBuf, 0xFF, 30 );
++
++ //============================================
++ // Get Buffer Pointer
++ //============================================
++ if ( memcmp( nSpareBuffer, nTempBuf, 30 ) == 0 )
++ {
++ if ( nDataSize == 512 )
++ pSpareDW = (unsigned int *)pECC_Info->All_FF_512_ECC_Code;
++ else if ( nDataSize == 12 )
++ pSpareDW = (unsigned int *)&ALL_FF_ECC_BCH_04BIT_12;
++ else
++ pSpareDW = (unsigned int *)&ALL_FF_ECC_BCH_04BIT_512;
++ }
++ else
++ pSpareDW = (unsigned int *)nSpareBuffer;
++
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ pECC->ECC_CODE0 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE1 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE2 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE3 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE4 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE5 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE6 = *pSpareDW; ++pSpareDW;
++
++
++ /* Sync Delay */
++ ASM_NOP; ASM_NOP; ASM_NOP; ASM_NOP;
++
++ /* Wait MLC ECC Correction */
++ while ( !(pECC->ECC_IREQ & pECC_Info->DecodeFlag ) );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Correction */
++ uErrorStatus = pECC->ERRNUM & 0x1F;
++
++ if ( uErrorStatus > pECC_Info->ErrorNum )
++ {
++ #ifdef NAND_IO_ECC_ERROR_LOG
++ PRINTF("\n\nErrorNum[%02d],DataSize[%03d] - Correction Fail", uErrorStatus, nDataSize );
++ #endif
++ res = ERR_NAND_IO_FAILED_CORRECTION_MLC_ECC;
++ goto ErrorCorrectionMLC;
++ }
++ else if ( uErrorStatus == HwERR_NUM_NOERR )
++ {
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ else
++ {
++ for ( i = 0; i < uErrorStatus; ++i )
++ {
++ uErrAddr = *(unsigned long int*)(&pECC->ECC_EADDR0+i);
++
++ if ( ( uErrAddr >> 3 ) < nDataSize )
++ nPageBuffer[uErrAddr>>3] ^= (1<<(uErrAddr &0x7));
++ }
++ }
++
++ErrorCorrectionMLC:
++ /* Disable MLC ECC */
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_CorrectionSLC( U8* nPageBuffer, U8* nSpareBuffer );
++*
++* DESCRIPTION :
++* INPUT:
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_CorrectionSLCForNB( U8* nPageBuffer, U8* nSpareBuffer )
++{
++ unsigned int uErrorStatus;
++ unsigned int uSLCECC0, uSLCECC1;
++ NAND_IO_ERROR res;
++
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ //==================================================================
++ // [ TNFTL V1.0 ]
++ //==================================================================
++ // 520th : P64-P8 of ECC Area-1 [ DATA 256-511 ]
++ // 521th : P1024-P128 of ECC Area-1 [ DATA 256-511 ]
++ // 522th : P4-P1 of ECC Area-1 [ DATA 256-511 ]
++ // 525th : P64-P8 of ECC Area-0 [ DATA 0-255 ]
++ // 526th : P1024-P128 of ECC Area-0 [ DATA 0-255 ]
++ // 527th : P4-P1 of ECC Area-0 [ DATA 0-255 ]
++ //==================================================================
++
++ /* Load SLC ECC Code for Area 1 */
++ uSLCECC0 = ( nSpareBuffer[ 8] << 16 ) +
++ ( nSpareBuffer[ 9] << 8 ) +
++ ( nSpareBuffer[10] );
++
++ /* Load SLC ECC Code for Area 0 */
++ uSLCECC1 = ( nSpareBuffer[13] << 16 ) +
++ ( nSpareBuffer[14] << 8 ) +
++ ( nSpareBuffer[15] );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Correction Area 0 */
++ pECC->ECC_CODE0 = uSLCECC1;
++ uErrorStatus = pECC->ERRNUM & 0x7;
++
++ if ( uErrorStatus == HwERR_NUM_ERR1 )
++ {
++ nPageBuffer[pECC->ECC_EADDR0 >> 3] ^= (1 << (pECC->ECC_EADDR0 & 0x07));
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ else if ( uErrorStatus != HwERR_NUM_NOERR )
++ {
++ res = ERR_NAND_IO_FAILED_CORRECTION_SLC_ECC;
++ goto ErrorCorrectionSLC;
++ }
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Correction Area 1 */
++ pECC->ECC_CODE0 = uSLCECC0;
++ uErrorStatus = pECC->ERRNUM & 0x7;
++
++ if ( uErrorStatus == HwERR_NUM_ERR1 )
++ {
++ nPageBuffer[pECC->ECC_EADDR0 >> 3] ^= (1 << (pECC->ECC_EADDR0 & 0x07));
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ else if ( uErrorStatus != HwERR_NUM_NOERR )
++ {
++ res = ERR_NAND_IO_FAILED_CORRECTION_SLC_ECC;
++ goto ErrorCorrectionSLC;
++ }
++
++ErrorCorrectionSLC:
++
++ /* Disable SLC ECC */
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_CorrectionMLCForNB( U8* nPageBuffer, U8* nSpareBuffer );
++*
++* DESCRIPTION :
++* INPUT:
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_CorrectionMLCForNB( U8* nPageBuffer, U8* nSpareBuffer )
++{
++ unsigned int i;
++ unsigned int uErrAddr;
++ unsigned int uErrorStatus;
++ NAND_IO_ERROR res;
++
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ //==================================================================
++ // [ TNFTL V1.0 ]
++ //==================================================================
++ // 512th : MLC ECC 0th Byte
++ // 513th : MLC ECC 1th Byte
++
++ // 520th : MLC ECC 2th Byte
++ // 521th : MLC ECC 3th Byte
++ // 522th : MLC ECC 4th Byte
++ // 523th : MLC ECC 5th Byte
++
++ // 524th : MLC ECC 6th Byte
++ // 525th : MLC ECC 7th Byte
++ // 526th : MLC ECC 8th Byte
++ // 527th : MLC ECC 9th Byte
++ //==================================================================
++ pECC->ECC_CODE0 = ( nSpareBuffer[8] ) +
++ ( nSpareBuffer[9] << 8 ) +
++ ( nSpareBuffer[10] << 16 ) +
++ ( nSpareBuffer[11] << 24 );
++
++ pECC->ECC_CODE1 = ( nSpareBuffer[12] ) +
++ ( nSpareBuffer[13] << 8 ) +
++ ( ( nSpareBuffer[14] & 0x0F ) << 16 );
++
++ /* Sync Delay */
++ ASM_NOP;
++
++ /* Wait MLC ECC Correction */
++ while ( !(pECC->ECC_IREQ & HwECC_IREQ_M4DF) );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Correction */
++ uErrorStatus = pECC->ERRNUM & 0x7;
++
++ if ( uErrorStatus > HwERR_NUM_ERR4 )
++ {
++ res = ERR_NAND_IO_FAILED_CORRECTION_MLC_ECC;
++ goto ErrorCorrectionMLC;
++ }
++ else if ( uErrorStatus == HwERR_NUM_NOERR )
++ {
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ else
++ {
++ for ( i = 0; i < uErrorStatus; ++i )
++ {
++ uErrAddr = *(unsigned long int*)(&pECC->ECC_EADDR0+i);
++
++ nPageBuffer[uErrAddr>>3] ^= (1<<(uErrAddr &0x7));
++ }
++ }
++
++ErrorCorrectionMLC:
++
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_CorrectionMLCForCB( U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize, U16 nBufferMode )
++*
++* DESCRIPTION :
++* INPUT:
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_CorrectionMLCForCB( U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize, U16 nBufferMode )
++{
++ unsigned int i;
++ unsigned int uErrAddr;
++ unsigned int uErrorStatus;
++ unsigned int wShiftBufferAddr;
++ NAND_IO_ERROR res;
++
++ if ( nBufferMode == NAND_SERIAL_CHAIN_BUFFER )
++ wShiftBufferAddr = 1;
++ else
++ wShiftBufferAddr = 0;
++
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ //==================================================================
++ // [ TNFTL V1.0 ]
++ //==================================================================
++ // 512th : MLC ECC 0th Byte
++ // 513th : MLC ECC 1th Byte
++
++ // 520th : MLC ECC 2th Byte
++ // 521th : MLC ECC 3th Byte
++ // 522th : MLC ECC 4th Byte
++ // 523th : MLC ECC 5th Byte
++
++ // 524th : MLC ECC 6th Byte
++ // 525th : MLC ECC 7th Byte
++ // 526th : MLC ECC 8th Byte
++ // 527th : MLC ECC 9th Byte
++ //==================================================================
++ pECC->ECC_CODE0 = ( nSpareBuffer[0] ) +
++ ( nSpareBuffer[1] << 8 ) +
++ ( nSpareBuffer[2] << 16 ) +
++ ( nSpareBuffer[3] << 24 );
++
++ pECC->ECC_CODE1 = ( nSpareBuffer[4] ) +
++ ( nSpareBuffer[5] << 8 ) +
++ ( ( nSpareBuffer[6] & 0x0F ) << 16 );
++
++ /* Sync Delay */
++ ASM_NOP;
++ ASM_NOP;
++ ASM_NOP;
++ ASM_NOP;
++ ASM_NOP;
++
++ /* Wait MLC ECC Correction */
++ while ( !(pECC->ECC_IREQ & HwECC_IREQ_M4DF) );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Correction */
++ uErrorStatus = pECC->ERRNUM & 0x7;
++
++ if ( uErrorStatus > HwERR_NUM_ERR4 )
++ {
++ res = ERR_NAND_IO_FAILED_CORRECTION_MLC_ECC;
++ goto ErrorCorrectionMLC;
++ }
++ else if ( uErrorStatus == HwERR_NUM_NOERR )
++ {
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ else
++ {
++ for ( i = 0; i < uErrorStatus; ++i )
++ {
++ uErrAddr = *(unsigned long int*)(&pECC->ECC_EADDR0+i);
++
++ if ( ( uErrAddr >> 3 ) < nDataSize )
++ nPageBuffer[(uErrAddr>>3)<< wShiftBufferAddr] ^= (1<<(uErrAddr &0x7));
++ }
++ }
++
++ErrorCorrectionMLC:
++
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++
++ return res;
++}
++
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_CorrectionMLCForCB( U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize, U16 nBufferMode )
++*
++* DESCRIPTION :
++* INPUT:
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_CorrectionMLC8ForCB( U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize, U16 nBufferMode )
++{
++ unsigned int i;
++ unsigned int uErrAddr;
++ unsigned int uErrorStatus;
++ unsigned int wShiftBufferAddr;
++ //unsigned short *pPageHW;
++ NAND_IO_ERROR res;
++
++ if ( nBufferMode == NAND_SERIAL_CHAIN_BUFFER )
++ wShiftBufferAddr = 1;
++ else
++ wShiftBufferAddr = 0;
++
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ //==================================================================
++ // [ TNFTL V1.0 ]
++ //==================================================================
++ // 512th : MLC ECC 0th Byte
++ // 513th : MLC ECC 1th Byte
++
++ // 520th : MLC ECC 2th Byte
++ // 521th : MLC ECC 3th Byte
++ // 522th : MLC ECC 4th Byte
++ // 523th : MLC ECC 5th Byte
++
++ // 524th : MLC ECC 6th Byte
++ // 525th : MLC ECC 7th Byte
++ // 526th : MLC ECC 8th Byte
++ // 527th : MLC ECC 9th Byte
++ //==================================================================
++
++ /* Load MLC ECC Code */
++ pECC->ECC_CODE0 = ( nSpareBuffer[ 0] ) +
++ ( nSpareBuffer[ 1] << 8 ) +
++ ( nSpareBuffer[ 2] << 16 ) +
++ ( nSpareBuffer[ 3] << 24 );
++
++ pECC->ECC_CODE1 = ( nSpareBuffer[ 4] ) +
++ ( nSpareBuffer[ 5] << 8 ) +
++ ( nSpareBuffer[ 6] << 16 ) +
++ ( nSpareBuffer[ 7] << 24 );
++
++ pECC->ECC_CODE2 = ( nSpareBuffer[ 8] ) +
++ ( nSpareBuffer[ 9] << 8 ) +
++ ( nSpareBuffer[10] << 16 ) +
++ ( nSpareBuffer[11] << 24 );
++
++ pECC->ECC_CODE3 = ( nSpareBuffer[12] );
++
++ /* Sync Delay */
++ ASM_NOP;
++
++ /* Wait MLC ECC Correction */
++ while ( !(pECC->ECC_IREQ & HwECC_IREQ_M8DF) );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Correction */
++ uErrorStatus = pECC->ERRNUM & 0x1F;
++
++ if ( uErrorStatus > HwERR_NUM_ERR8 )
++ {
++ res = ERR_NAND_IO_FAILED_CORRECTION_MLC_ECC;
++ goto ErrorCorrectionMLC;
++ }
++ else if ( uErrorStatus == HwERR_NUM_NOERR )
++ {
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ else
++ {
++ for ( i = 0; i < uErrorStatus; ++i )
++ {
++ uErrAddr = *(unsigned long int*)(&pECC->ECC_EADDR0+i);
++
++ if ( ( uErrAddr >> 3 ) < nDataSize )
++ nPageBuffer[(uErrAddr>>3) << wShiftBufferAddr] ^= (1<<(uErrAddr &0x7));
++ }
++ }
++
++ErrorCorrectionMLC:
++
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_CorrectionMLCForCB( U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize, U16 nBufferMode )
++*
++* DESCRIPTION :
++* INPUT:
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_CorrectionMLC12ForCB( U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize, U16 nBufferMode )
++{
++ NAND_IO_ERROR res = (NAND_IO_ERROR)SUCCESS;
++ unsigned int i;
++ unsigned int uErrAddr;
++ unsigned int uErrorStatus;
++ unsigned int wShiftBufferAddr;
++ unsigned int *pSpareDW;
++
++ if ( nBufferMode == NAND_SERIAL_CHAIN_BUFFER )
++ wShiftBufferAddr = 1;
++ else
++ wShiftBufferAddr = 0;
++
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ /* Load MLC ECC Code */
++ pSpareDW = (unsigned int *)nSpareBuffer;
++
++ pECC->ECC_CODE0 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE1 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE2 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE3 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE4 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE5 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE6 = *pSpareDW; ++pSpareDW;
++
++
++ /* Sync Delay */
++ ASM_NOP;
++
++ /* Wait MLC ECC Correction */
++ while ( !(pECC->ECC_IREQ & HwECC_IREQ_M12DF) );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Correction */
++ uErrorStatus = pECC->ERRNUM & 0x1F;
++
++ if ( uErrorStatus > HwERR_NUM_ERR12 )
++ {
++ res = ERR_NAND_IO_FAILED_CORRECTION_MLC_ECC;
++ goto ErrorCorrectionMLC;
++ }
++ else if ( uErrorStatus == HwERR_NUM_NOERR )
++ {
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ else
++ {
++ for ( i = 0; i < uErrorStatus; ++i )
++ {
++ uErrAddr = *(unsigned long int*)(&pECC->ECC_EADDR0+i);
++
++ if ( ( uErrAddr >> 3 ) < nDataSize )
++ nPageBuffer[(uErrAddr>>3) <<wShiftBufferAddr ] ^= (1<<(uErrAddr &0x7));
++ }
++ }
++
++ErrorCorrectionMLC:
++
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_EncodeChainData( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, U8 *nSpareBuffer, int nMode, int nEccOnOff );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nMode =
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_EncodeChainData( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, U8 *nSpareBuffer, int nMode, int nEccOnOff )
++{
++ unsigned short int i, j;
++ unsigned short int nECCDataSize;
++ unsigned char bAlignAddr;
++ #ifdef _LINUX_
++ unsigned char nECCBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nECCBuffer[30];
++ #endif
++ unsigned char *pPageB, *pSpareB;
++ unsigned char *pDataBuffer,*pSpareBuffer;
++ unsigned char *pDataBuffer2,*pSpareBuffer2;
++ unsigned char *pEccB;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ if ( nEccOnOff == ECC_OFF )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Buffer Mode Setting
++ //=========================================================================
++ nECCDataSize = nDevInfo->EccDataSize;
++
++ if ( ( nDevInfo->Feature.MediaType & A_PARALLEL ) && ( nMode == NAND_SERIAL_CHAIN_BUFFER ) )
++ {
++ bAlignAddr = 1;
++
++ if ( ( ( nDevInfo->Feature.MediaType & A_MLC ) || (nDevInfo->Feature.MediaType & A_SLC ) ) && ( nDevInfo->Feature.MediaType & A_BIG ) )
++ nECCDataSize -= 2;
++ }
++ else
++ bAlignAddr = 0;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ //if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ // NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ //else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++
++ /* Get Data Buffer */
++ pDataBuffer = (unsigned char*)pPageB;
++ pDataBuffer2 = pDataBuffer + 1;
++
++ /* Get Spare Buffer */
++ pSpareBuffer = (unsigned char*)pSpareB;
++ pSpareBuffer2 = pSpareBuffer + 1;
++
++ //----------------------------------------------
++ // Write Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nDevInfo->PPages; ++j )
++ {
++ if ( ( j == ( nDevInfo->PPages >> 1 ) ) && ( bAlignAddr == 1 ) )
++ {
++ pPageB = pDataBuffer2;
++ pSpareBuffer = pSpareBuffer2;
++ }
++
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ if (!( pNFC->NFC_CTRL1 & Hw30 ))
++ {
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ if ( bAlignAddr == 0 )
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ else if ( bAlignAddr == 1 )
++ {
++ uDWordByte.BYTE[0] = *pPageB;pPageB += 2;
++ uDWordByte.BYTE[1] = *pPageB;pPageB += 2;
++ uDWordByte.BYTE[2] = *pPageB;pPageB += 2;
++ uDWordByte.BYTE[3] = *pPageB;pPageB += 2;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ }
++ else
++ {
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ i = 128;
++ do {
++ if ( bAlignAddr == 0 )
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ else if ( bAlignAddr == 1 )
++ {
++ uDWordByte.BYTE[0] = *pPageB;pPageB += 2;
++ uDWordByte.BYTE[1] = *pPageB;pPageB += 2;
++ uDWordByte.BYTE[2] = *pPageB;pPageB += 2;
++ uDWordByte.BYTE[3] = *pPageB;pPageB += 2;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++ }
++
++ //####################################################
++ //####################################################
++
++ /* Adapt type of address */
++ pEccB = (unsigned char*)nECCBuffer;
++
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pEccB );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++ }
++
++ if ( bAlignAddr == 0 )
++ {
++ for ( i = 0; i < nECCDataSize; ++i )
++ {
++ *pSpareBuffer = nECCBuffer[i];
++ pSpareBuffer += 1;
++ }
++ }
++ else if ( bAlignAddr == 1 )
++ {
++ for ( i = 0; i < nECCDataSize; ++i )
++ {
++ *pSpareBuffer = nECCBuffer[i];
++ pSpareBuffer += 2;
++ }
++ }
++ }
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++
++ErrorWrite512Data:
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_EncodeChainDataForGoldenPage( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_EncodeChainDataForGoldenPage( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int i;
++ #ifdef _LINUX_
++ unsigned char nECCBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nECCBuffer[30];
++ #endif
++ unsigned char *pPageB, *pSpareB;
++ unsigned char *pDataBuffer,*pSpareBuffer;
++ unsigned char *pEccB;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ //if ( nEccOnOff == ECC_OFF )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++
++ /* Get Buffer pointer */
++ pDataBuffer = (unsigned char*)pPageB;
++ pSpareBuffer = (unsigned char*)pSpareB;
++
++ //####################################################
++ //# Dummy Write Page Data
++ //####################################################
++
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ pDataBuffer += ( 528 * ( nDevInfo->PPages - 2 ));
++ else
++ pDataBuffer += ( 528 * ( nDevInfo->PPages - 1 ));
++
++ if (!( pNFC->NFC_CTRL1 & Hw30 ))
++ {
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 256 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 256 Page Data */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 256;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = ( 64 ); // 256 byte
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++ uDWordByte.BYTE[0] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[1] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[2] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[3] = *pDataBuffer;++pDataBuffer;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }while(--i);
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ }
++ else
++ {
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 256 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ i = ( 64 ); // 256 byte
++ do {
++ uDWordByte.BYTE[0] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[1] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[2] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[3] = *pDataBuffer;++pDataBuffer;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }while(--i);
++ }
++
++ /* Adapt type of address */
++ pEccB = (unsigned char*)nECCBuffer;
++
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pEccB );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++
++ for ( i = 0; i < nDevInfo->EccDataSize; ++i )
++ {
++ *pDataBuffer = nECCBuffer[i];
++ pDataBuffer += 1;
++ }
++
++/* pDataBuffer += nDevInfo->EccDataSize;*/
++ }
++
++ /* Disable ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //####################################################
++ //####################################################
++
++ //####################################################
++ //# Dummy Write Spare Data
++ //####################################################
++ if (!( pNFC->NFC_CTRL1 & Hw30 ))
++ {
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( nDevInfo->Feature.SpareSize << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write Spare Data */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = nDevInfo->Feature.SpareSize;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = ( nDevInfo->Feature.SpareSize >> 2 );
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }while(--i);
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ }
++ else
++ {
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( nDevInfo->Feature.SpareSize << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ i = ( nDevInfo->Feature.SpareSize >> 2 );
++ do {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }while(--i);
++ }
++
++ //####################################################
++ //####################################################
++
++ pEccB = (unsigned char*)nECCBuffer;
++
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pEccB );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++
++ for ( i = 0; i < nDevInfo->EccDataSize; ++i )
++ {
++ *pDataBuffer = nECCBuffer[i];
++ pDataBuffer += 1;
++ }
++ }
++
++ /* Disable ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++
++ErrorWrite512Data:
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_DecodeChainData( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, U8 *nSpareBuffer, int nMode, int nEccOnOff );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nMode =
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_DecodeChainData( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, U8 *nSpareBuffer, int nMode, int nEccOnOff )
++{
++ unsigned int i,j;
++ unsigned int nECCDataSize;
++ unsigned char bAlignAddr;
++ #ifdef _LINUX_
++ unsigned char nECCBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nECCBuffer[30];
++ #endif
++ unsigned char *pPageB, *pSpareB;
++ unsigned char *pDataBuffer,*pSpareBuffer;
++ unsigned char *pDataBuffer2,*pSpareBuffer2;
++ unsigned char *pEccB;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ //if ( nEccOnOff == ECC_OFF )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ nECCDataSize = nDevInfo->EccDataSize;
++
++ if ( ( nDevInfo->Feature.MediaType & A_PARALLEL ) && ( nMode == NAND_SERIAL_CHAIN_BUFFER ) )
++ {
++ bAlignAddr = 1;
++
++ if ( ( ( nDevInfo->Feature.MediaType & A_MLC ) || (nDevInfo->Feature.MediaType & A_SLC ) ) && ( nDevInfo->Feature.MediaType & A_BIG ) )
++ nECCDataSize -= 2;
++ }
++ else
++ bAlignAddr = 0;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ //if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ // NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ //else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++
++ /* Get Data Buffer */
++ pDataBuffer = (unsigned char*)pPageB;
++ pDataBuffer2 = pDataBuffer + 1;
++
++ /* Adapt type of address */
++ pSpareBuffer = (unsigned char*)pSpareB;
++ pSpareBuffer2 = pSpareBuffer + 1;
++
++ //----------------------------------------------
++ // Read Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nDevInfo->PPages; ++j )
++ {
++ if ( ( j == (U32)( nDevInfo->PPages >> 1 ) ) && ( bAlignAddr == 1 ) )
++ {
++ pPageB = pDataBuffer2;
++ pDataBuffer = pDataBuffer2;
++ pSpareBuffer = pSpareBuffer2;
++ }
++
++ //####################################################
++ //# Read 512 Page Data
++ //####################################################
++ if (!( pNFC->NFC_CTRL1 & Hw30 ))
++ {
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000; // Clear ECC Block
++ }
++
++ /* Read 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ if ( bAlignAddr == 0 )
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ else if ( bAlignAddr == 1 )
++ {
++ uDWordByte.BYTE[0] = *pPageB;pPageB += 2;
++ uDWordByte.BYTE[1] = *pPageB;pPageB += 2;
++ uDWordByte.BYTE[2] = *pPageB;pPageB += 2;
++ uDWordByte.BYTE[3] = *pPageB;pPageB += 2;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ }
++ else
++ {
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++
++ }
++
++ i = 128;
++ do {
++ if ( bAlignAddr == 0 )
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ else if ( bAlignAddr == 1 )
++ {
++ uDWordByte.BYTE[0] = *pPageB;pPageB += 2;
++ uDWordByte.BYTE[1] = *pPageB;pPageB += 2;
++ uDWordByte.BYTE[2] = *pPageB;pPageB += 2;
++ uDWordByte.BYTE[3] = *pPageB;pPageB += 2;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++ }
++
++ //####################################################
++ //####################################################
++
++ /* Adapt type of address */
++ pEccB = (unsigned char*)nECCBuffer;
++
++ if ( bAlignAddr == 0 )
++ {
++ for ( i = 0; i < nECCDataSize; ++i )
++ {
++ nECCBuffer[i] = *pSpareBuffer;
++ pSpareBuffer += 1;
++ }
++ }
++ else if ( bAlignAddr == 1 )
++ {
++ for ( i = 0; i < nECCDataSize; ++i )
++ {
++ nECCBuffer[i] = *pSpareBuffer;
++ pSpareBuffer += 2;
++ }
++ }
++
++ /* Check and Correct ECC code */
++ if ( nEccOnOff == ECC_ON )
++ {
++ if ( nDevInfo->EccType == SLC_ECC_TYPE )
++ {
++ //===================================
++ // SLC ECC Correction
++ //===================================
++ res |= NAND_IO_CorrectionSLC( pDataBuffer, nECCBuffer );
++ }
++ else if ( nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ {
++ //===================================
++ // 4 Bit MLC ECC Correction
++ //===================================
++ if (( nECCBuffer[0] == 0xFF ) && ( nECCBuffer[1] == 0xFF ) &&
++ ( nECCBuffer[2] == 0xFF ) && ( nECCBuffer[3] == 0xFF ) &&
++ ( nECCBuffer[4] == 0xFF ) && ( nECCBuffer[5] == 0xFF ) &&
++ ( nECCBuffer[6] == 0xFF ) && ( nECCBuffer[7] == 0xFF ) &&
++ ( nECCBuffer[8] == 0xFF ) && ( nECCBuffer[9] == 0xFF ))
++ {
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++ }
++ else
++ {
++ if ( bAlignAddr == 0 )
++ {
++ res |= NAND_IO_CorrectionMLCForCB( pDataBuffer, nECCBuffer, 512, NAND_NORMAL_BUFFER );
++ pDataBuffer += 512;
++ }
++ else if ( bAlignAddr == 1 )
++ {
++ res |= NAND_IO_CorrectionMLCForCB( pDataBuffer, nECCBuffer, 512, NAND_SERIAL_CHAIN_BUFFER );
++ }
++ }
++ }
++ else if ( nDevInfo->EccType == MLC_ECC_8BIT_TYPE )
++ {
++ //===================================
++ // 8 Bit MLC ECC Correction
++ //===================================
++ if (( nECCBuffer[ 0] == 0xFF ) && ( nECCBuffer[ 1] == 0xFF ) &&
++ ( nECCBuffer[ 2] == 0xFF ) && ( nECCBuffer[ 3] == 0xFF ) &&
++ ( nECCBuffer[ 4] == 0xFF ) && ( nECCBuffer[ 5] == 0xFF ) &&
++ ( nECCBuffer[ 6] == 0xFF ) && ( nECCBuffer[ 7] == 0xFF ) &&
++ ( nECCBuffer[ 8] == 0xFF ) && ( nECCBuffer[ 9] == 0xFF ) &&
++ ( nECCBuffer[10] == 0xFF ) && ( nECCBuffer[11] == 0xFF ) &&
++ ( nECCBuffer[12] == 0xFF ) && ( nECCBuffer[13] == 0xFF ) &&
++ ( nECCBuffer[14] == 0xFF ) && ( nECCBuffer[15] == 0xFF ) &&
++ ( nECCBuffer[16] == 0xFF ) && ( nECCBuffer[17] == 0xFF ) &&
++ ( nECCBuffer[18] == 0xFF ) && ( nECCBuffer[19] == 0xFF ))
++ {
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++ }
++ else
++ {
++ if ( bAlignAddr == 0 )
++ {
++ res |= NAND_IO_CorrectionMLC8ForCB( pDataBuffer, nECCBuffer, 512, NAND_NORMAL_BUFFER );
++ pDataBuffer += 512;
++ }
++ else if ( bAlignAddr == 1 )
++ {
++ res |= NAND_IO_CorrectionMLC8ForCB( pDataBuffer, nECCBuffer, 512, NAND_SERIAL_CHAIN_BUFFER );
++ pDataBuffer += 1024;
++ }
++ }
++ }
++ else if ( nDevInfo->EccType == MLC_ECC_12BIT_TYPE )
++ {
++ //===================================
++ // 8 Bit MLC ECC Correction
++ //===================================
++ if (( nECCBuffer[ 0] == 0xFF ) && ( nECCBuffer[ 1] == 0xFF ) &&
++ ( nECCBuffer[ 2] == 0xFF ) && ( nECCBuffer[ 3] == 0xFF ) &&
++ ( nECCBuffer[ 4] == 0xFF ) && ( nECCBuffer[ 5] == 0xFF ) &&
++ ( nECCBuffer[ 6] == 0xFF ) && ( nECCBuffer[ 7] == 0xFF ) &&
++ ( nECCBuffer[ 8] == 0xFF ) && ( nECCBuffer[ 9] == 0xFF ) &&
++ ( nECCBuffer[10] == 0xFF ) && ( nECCBuffer[11] == 0xFF ) &&
++ ( nECCBuffer[12] == 0xFF ) && ( nECCBuffer[13] == 0xFF ) &&
++ ( nECCBuffer[14] == 0xFF ) && ( nECCBuffer[15] == 0xFF ) &&
++ ( nECCBuffer[16] == 0xFF ) && ( nECCBuffer[17] == 0xFF ) &&
++ ( nECCBuffer[18] == 0xFF ) && ( nECCBuffer[19] == 0xFF ))
++ {
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++ }
++ else
++ {
++ if ( bAlignAddr == 0 )
++ {
++ res |= NAND_IO_CorrectionMLC12ForCB( pDataBuffer, nECCBuffer, 512, NAND_NORMAL_BUFFER );
++ pDataBuffer += 512;
++ }
++ else if ( bAlignAddr == 1 )
++ {
++ res |= NAND_IO_CorrectionMLC12ForCB( pDataBuffer, nECCBuffer, 512, NAND_SERIAL_CHAIN_BUFFER );
++ pDataBuffer += 1024;
++ }
++ }
++ }
++ }
++ }
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_DecodeChainDataForGoldenPage( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_DecodeChainDataForGoldenPage( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int i;
++ unsigned char *pPageB, *pSpareB;
++ unsigned char *pDataBuffer,*pSpareBuffer;
++ unsigned char *pDataBuffer2,*pSpareBuffer2;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ //if ( nEccOnOff == ECC_OFF )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ pPageB += ( 528 * ( nDevInfo->PPages - 2 ));
++ else
++ pPageB += ( 528 * ( nDevInfo->PPages - 1 ));
++
++ /* Get Data Buffer */
++ pDataBuffer = (unsigned char*)pPageB;
++ pDataBuffer2 = pDataBuffer + 1;
++
++ /* Adapt type of address */
++ pSpareBuffer = (unsigned char*)pSpareB;
++ pSpareBuffer2 = pSpareBuffer + 1;
++
++ //####################################################
++ //# Dummy Write Page Data
++ //####################################################
++ if (!( pNFC->NFC_CTRL1 & Hw30 ))
++ {
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 256 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Dummy Write */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 256;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = (64);
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++ uDWordByte.BYTE[0] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[1] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[2] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[3] = *pDataBuffer;++pDataBuffer;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ }
++ else
++ {
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 256 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ i = (64);
++ do {
++ uDWordByte.BYTE[0] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[1] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[2] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[3] = *pDataBuffer;++pDataBuffer;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }while(--i);
++
++ }
++
++ //####################################################
++ //####################################################
++
++ /* Check and Correct ECC code */
++ if ( nEccOnOff == ECC_ON )
++ {
++ if ( nDevInfo->EccType == SLC_ECC_TYPE )
++ {
++ //===================================
++ // SLC ECC Correction
++ //===================================
++ res |= NAND_IO_CorrectionSLC( pPageB, pDataBuffer );
++
++ pDataBuffer += nDevInfo->EccDataSize;
++ }
++ else if ( nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ {
++ //===================================
++ // 4 Bit MLC ECC Correction
++ //===================================
++ if (( pDataBuffer[0] == 0xFF ) && ( pDataBuffer[1] == 0xFF ) &&
++ ( pDataBuffer[2] == 0xFF ) && ( pDataBuffer[3] == 0xFF ) &&
++ ( pDataBuffer[4] == 0xFF ) && ( pDataBuffer[5] == 0xFF ) &&
++ ( pDataBuffer[6] == 0xFF ) && ( pDataBuffer[7] == 0xFF ) &&
++ ( pDataBuffer[8] == 0xFF ) && ( pDataBuffer[9] == 0xFF ))
++ {
++ pDataBuffer += nDevInfo->EccDataSize;
++
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ ASM_NOP;
++ }
++ else
++ {
++ res |= NAND_IO_CorrectionMLCForCB( pPageB, pDataBuffer, 256, NAND_NORMAL_BUFFER );
++
++ pDataBuffer += nDevInfo->EccDataSize;
++ }
++ }
++ else if ( nDevInfo->EccType == MLC_ECC_8BIT_TYPE )
++ {
++ //===================================
++ // 8 Bit MLC ECC Correction
++ //===================================
++ if (( pDataBuffer[ 0] == 0xFF ) && ( pDataBuffer[ 1] == 0xFF ) &&
++ ( pDataBuffer[ 2] == 0xFF ) && ( pDataBuffer[ 3] == 0xFF ) &&
++ ( pDataBuffer[ 4] == 0xFF ) && ( pDataBuffer[ 5] == 0xFF ) &&
++ ( pDataBuffer[ 6] == 0xFF ) && ( pDataBuffer[ 7] == 0xFF ) &&
++ ( pDataBuffer[ 8] == 0xFF ) && ( pDataBuffer[ 9] == 0xFF ) &&
++ ( pDataBuffer[10] == 0xFF ) && ( pDataBuffer[11] == 0xFF ) &&
++ ( pDataBuffer[12] == 0xFF ) && ( pDataBuffer[13] == 0xFF ) &&
++ ( pDataBuffer[14] == 0xFF ) && ( pDataBuffer[15] == 0xFF ) &&
++ ( pDataBuffer[16] == 0xFF ) && ( pDataBuffer[17] == 0xFF ) &&
++ ( pDataBuffer[18] == 0xFF ) && ( pDataBuffer[19] == 0xFF ))
++ {
++ pDataBuffer += nDevInfo->EccDataSize;
++
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ ASM_NOP;
++ }
++ else
++ {
++ res |= NAND_IO_CorrectionMLC8ForCB( pPageB, pDataBuffer, 256, NAND_NORMAL_BUFFER );
++
++ pDataBuffer += nDevInfo->EccDataSize;
++ }
++ }
++ else if ( nDevInfo->EccType == MLC_ECC_12BIT_TYPE )
++ {
++ //===================================
++ // 8 Bit MLC ECC Correction
++ //===================================
++ if (( pDataBuffer[ 0] == 0xFF ) && ( pDataBuffer[ 1] == 0xFF ) &&
++ ( pDataBuffer[ 2] == 0xFF ) && ( pDataBuffer[ 3] == 0xFF ) &&
++ ( pDataBuffer[ 4] == 0xFF ) && ( pDataBuffer[ 5] == 0xFF ) &&
++ ( pDataBuffer[ 6] == 0xFF ) && ( pDataBuffer[ 7] == 0xFF ) &&
++ ( pDataBuffer[ 8] == 0xFF ) && ( pDataBuffer[ 9] == 0xFF ) &&
++ ( pDataBuffer[10] == 0xFF ) && ( pDataBuffer[11] == 0xFF ) &&
++ ( pDataBuffer[12] == 0xFF ) && ( pDataBuffer[13] == 0xFF ) &&
++ ( pDataBuffer[14] == 0xFF ) && ( pDataBuffer[15] == 0xFF ) &&
++ ( pDataBuffer[16] == 0xFF ) && ( pDataBuffer[17] == 0xFF ) &&
++ ( pDataBuffer[18] == 0xFF ) && ( pDataBuffer[19] == 0xFF ))
++ {
++ pDataBuffer += nDevInfo->EccDataSize;
++
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ ASM_NOP;
++ }
++ else
++ {
++ res |= NAND_IO_CorrectionMLC12ForCB( pPageB, pDataBuffer, 256, NAND_NORMAL_BUFFER );
++ pDataBuffer += nDevInfo->EccDataSize;
++ }
++ }
++ }
++ /* Disable ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //####################################################
++ //# Dummy Write Spare Data
++ //####################################################
++ /* Setup ECC Block */
++ if (!( pNFC->NFC_CTRL1 & Hw30 ))
++ {
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( nDevInfo->Feature.SpareSize << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Dummy Write */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = nDevInfo->Feature.SpareSize;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = ( nDevInfo->Feature.SpareSize >> 2 );
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ }
++ else
++ {
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( nDevInfo->Feature.SpareSize << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ i = ( nDevInfo->Feature.SpareSize >> 2 );
++ do {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }while(--i);
++ }
++
++ //####################################################
++ //####################################################
++
++ /* Check and Correct ECC code */
++ if ( nEccOnOff == ECC_ON )
++ {
++ if ( nDevInfo->EccType == SLC_ECC_TYPE )
++ {
++ //===================================
++ // SLC ECC Correction
++ //===================================
++ res |= NAND_IO_CorrectionSLC( nSpareBuffer, pPageB );
++ }
++ else if ( nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ {
++ //===================================
++ // 4 Bit MLC ECC Correction
++ //===================================
++ if (( pDataBuffer[0] == 0xFF ) && ( pDataBuffer[1] == 0xFF ) &&
++ ( pDataBuffer[2] == 0xFF ) && ( pDataBuffer[3] == 0xFF ) &&
++ ( pDataBuffer[4] == 0xFF ) && ( pDataBuffer[5] == 0xFF ) &&
++ ( pDataBuffer[6] == 0xFF ) && ( pDataBuffer[7] == 0xFF ) &&
++ ( pDataBuffer[8] == 0xFF ) && ( pDataBuffer[9] == 0xFF ))
++ {
++ ASM_NOP;
++ }
++ else
++ {
++ res |= NAND_IO_CorrectionMLCForCB( nSpareBuffer, pDataBuffer, nDevInfo->Feature.SpareSize, NAND_NORMAL_BUFFER );
++ }
++ }
++ else if ( nDevInfo->EccType == MLC_ECC_8BIT_TYPE )
++ {
++ //===================================
++ // 8 Bit MLC ECC Correction
++ //===================================
++ if (( pDataBuffer[ 0] == 0xFF ) && ( pDataBuffer[ 1] == 0xFF ) &&
++ ( pDataBuffer[ 2] == 0xFF ) && ( pDataBuffer[ 3] == 0xFF ) &&
++ ( pDataBuffer[ 4] == 0xFF ) && ( pDataBuffer[ 5] == 0xFF ) &&
++ ( pDataBuffer[ 6] == 0xFF ) && ( pDataBuffer[ 7] == 0xFF ) &&
++ ( pDataBuffer[ 8] == 0xFF ) && ( pDataBuffer[ 9] == 0xFF ) &&
++ ( pDataBuffer[10] == 0xFF ) && ( pDataBuffer[11] == 0xFF ) &&
++ ( pDataBuffer[12] == 0xFF ) && ( pDataBuffer[13] == 0xFF ) &&
++ ( pDataBuffer[14] == 0xFF ) && ( pDataBuffer[15] == 0xFF ) &&
++ ( pDataBuffer[16] == 0xFF ) && ( pDataBuffer[17] == 0xFF ) &&
++ ( pDataBuffer[18] == 0xFF ) && ( pDataBuffer[19] == 0xFF ))
++ {
++ ASM_NOP;
++ }
++ else
++ {
++ res |= NAND_IO_CorrectionMLC8ForCB( nSpareBuffer, pDataBuffer, nDevInfo->Feature.SpareSize, NAND_NORMAL_BUFFER );
++ }
++ }
++ else if ( nDevInfo->EccType == MLC_ECC_12BIT_TYPE )
++ {
++ //===================================
++ // 8 Bit MLC ECC Correction
++ //===================================
++ if (( pDataBuffer[ 0] == 0xFF ) && ( pDataBuffer[ 1] == 0xFF ) &&
++ ( pDataBuffer[ 2] == 0xFF ) && ( pDataBuffer[ 3] == 0xFF ) &&
++ ( pDataBuffer[ 4] == 0xFF ) && ( pDataBuffer[ 5] == 0xFF ) &&
++ ( pDataBuffer[ 6] == 0xFF ) && ( pDataBuffer[ 7] == 0xFF ) &&
++ ( pDataBuffer[ 8] == 0xFF ) && ( pDataBuffer[ 9] == 0xFF ) &&
++ ( pDataBuffer[10] == 0xFF ) && ( pDataBuffer[11] == 0xFF ) &&
++ ( pDataBuffer[12] == 0xFF ) && ( pDataBuffer[13] == 0xFF ) &&
++ ( pDataBuffer[14] == 0xFF ) && ( pDataBuffer[15] == 0xFF ) &&
++ ( pDataBuffer[16] == 0xFF ) && ( pDataBuffer[17] == 0xFF ) &&
++ ( pDataBuffer[18] == 0xFF ) && ( pDataBuffer[19] == 0xFF ))
++ {
++ ASM_NOP;
++ }
++ else
++ {
++ res |= NAND_IO_CorrectionMLC12ForCB( nSpareBuffer, pDataBuffer, nDevInfo->Feature.SpareSize, NAND_NORMAL_BUFFER );
++ }
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ /* Disable ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ return res;
++
++}
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_ReadSpareData( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++* U8 *nSpareBuffer );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nReadPPSize =
++* nSpareBuffer =
++* nStartPPage =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadSpareData( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++ U8 *nSpareBuffer )
++{
++ unsigned int i,j;
++ unsigned char *pSpareB;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Read Spare Data
++ //=========================================================================
++ pSpareB = (unsigned char*)nSpareBuffer;
++
++ //----------------------------------------------
++ // Read Spare Data as 16Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nReadPPSize; ++j )
++ {
++ /* Read 512 Data Area */
++ if ( j != 0 )
++ {
++ i = 128;
++ do {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ } while(--i);
++ }
++
++ /* Read 16Bytes spare data */
++ i = 4;
++ do {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }while(--i);
++ }
++
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_ReadSpareDataECC( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadSpareDataMTD( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nPageEccOnOff )
++{
++ unsigned int i;
++ unsigned int nSpareTotalSize;
++ unsigned int nECCDataSize;
++ unsigned char bAlignAddr;
++ unsigned char *pSpareB = 0;
++ unsigned int *pSpareDW = 0;
++ unsigned char *pSpareBuffer;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ nSpareTotalSize = 32;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nSpareBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ else
++ pSpareB = (unsigned char*)nSpareBuffer;
++
++ if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ //----------------------------------------------
++ // Read Small Page Spare Data: 16Byte
++ //----------------------------------------------
++ i = 4;
++
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ if ( nPageEccOnOff == PAGE_ECC_ON )
++ {
++ memset( gNAND_IO_ShareEccBuffer, 0xFF, 16 );
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)&gNAND_IO_ShareEccBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)&gNAND_IO_ShareEccBuffer[0];
++ else
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = 4;
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++ }
++ }
++
++ return SUCCESS;
++ }
++
++ ///* Setup ECC Block */
++ //#if defined(_WINCE_) || defined(_LINUX_)
++ //NAND_IO_SetupECC( ECC_ON, ECC_DECODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ //#else
++ //NAND_IO_SetupECC( ECC_ON, ECC_DECODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ //#endif
++ //pECC->ECC_CTRL |= ( nSpareTotalSize << ECC_SHIFT_DATASIZE );
++ //pECC->ECC_CLEAR = 0x00000000; // Clear ECC Block
++
++ /* Set Spare Buffer */
++ pSpareBuffer = ( bAlignAddr ) ? (unsigned char*)pSpareDW : (unsigned char*)pSpareB;
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = ( nSpareTotalSize >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++ /* Read 4Bit ECC data */
++ //nReadSize = 8;
++ //
++ ///* Adapt type of address */
++ //pEccB = (unsigned char*)nECCBuffer;
++
++ //----------------------------------------------
++ // Read ECC Code
++ //----------------------------------------------
++ //while ( nReadSize )
++ //{
++ // /* Read as DWORD */
++ // if ( nReadSize >= 4 )
++ // {
++ // uDWordByte.DWORD = WORD_OF(pNFC->NFC_WDATA);
++ // *pEccB = uDWordByte.BYTE[0];++pEccB;
++ // *pEccB = uDWordByte.BYTE[1];++pEccB;
++ // *pEccB = uDWordByte.BYTE[2];++pEccB;
++ // *pEccB = uDWordByte.BYTE[3];++pEccB;
++ // nReadSize -= 4;
++ // }
++ // /* Read as WORD */
++ // else if ( nReadSize >= 2 )
++ // {
++ // *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ // *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ // nReadSize -= 2;
++ // }
++ // /* Read as BYTE */
++ // else
++ // {
++ // *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ // nReadSize -= 1;
++ // }
++ //}
++ //
++ ///* Check and Correct ECC code */
++ ////===================================
++ //// 4 Bit MLC ECC Correction
++ ////===================================
++ //if ( ( nECCBuffer[0] == 0x00 ) && ( nECCBuffer[1] == 0x00 ) &&
++ // ( nECCBuffer[2] == 0x00 ) && ( nECCBuffer[3] == 0x00 ) &&
++ // ( nECCBuffer[4] == 0x00 ) && ( nECCBuffer[5] == 0x00 ) &&
++ // ( nECCBuffer[6] == 0x00 ) && ( nECCBuffer[7] == 0x00 ))
++ //{
++ // res |= NAND_IO_CorrectionMLC( MLC_ECC_4BIT_TYPE, pSpareBuffer, nECCBuffer, nSpareTotalSize );
++ // res |= ERR_NAND_IO_FAILED_CORRECTION_MLC_ECC;
++ //}
++ //else if ( ( nECCBuffer[0] == 0xFF ) && ( nECCBuffer[1] == 0xFF ) &&
++ // ( nECCBuffer[2] == 0xFF ) && ( nECCBuffer[3] == 0xFF ) &&
++ // ( nECCBuffer[4] == 0xFF ) && ( nECCBuffer[5] == 0xFF ) &&
++ // ( nECCBuffer[6] == 0xFF ) && ( nECCBuffer[7] == 0xFF ))
++ // {
++ // ASM_NOP;
++ //}
++ //else
++ //{
++ // res |= NAND_IO_CorrectionMLC( MLC_ECC_4BIT_TYPE, pSpareBuffer, nECCBuffer, nSpareTotalSize );
++ //}
++
++ //=========================================================================
++ // Ecc Clear
++ //=========================================================================
++ //NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++ if ( nDevInfo->Feature.MediaType & A_MLC )
++ nECCDataSize = 8;
++ else if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ nECCDataSize = 20;
++
++ if ( nPageEccOnOff == PAGE_ECC_ON )
++ {
++ memset( gNAND_IO_ShareEccBuffer, 0xFF, ( nECCDataSize << 2 ) );
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)&gNAND_IO_ShareEccBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)&gNAND_IO_ShareEccBuffer[0];
++ else
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = ( ( nECCDataSize << 2) >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++ }
++
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_ReadSpareDataECC( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadSpareDataECC( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int i;
++ unsigned int nReadSize;
++ unsigned char bAlignAddr;
++ unsigned char *pSpareB = 0, *pEccB;
++ unsigned int *pSpareDW = 0;
++ unsigned char *pSpareBuffer;
++ #ifdef _LINUX_
++ unsigned char nECCBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nECCBuffer[30];
++ #endif
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nSpareBuffer & 3 ) ? 0 : 1;
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ // Clear Buffer
++ memset( nSpareBuffer, 0xFF, 16 );
++ memset( nECCBuffer, 0xFF, 30 );
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ else
++ pSpareB = (unsigned char*)nSpareBuffer;
++
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( ECC_ON, ECC_DECODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( ECC_ON, ECC_DECODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 12 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; // Clear ECC Block
++ }
++
++ /* Set Spare Buffer */
++ pSpareBuffer = ( bAlignAddr ) ? (unsigned char*)pSpareDW : (unsigned char*)pSpareB;
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = 3;
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++ /* Read 4Bit ECC data */
++ nReadSize = 10;
++
++ /* Adapt type of address */
++ pEccB = (unsigned char*)nECCBuffer;
++
++ if ( nEccOnOff == ECC_ON )
++ {
++ //----------------------------------------------
++ // Read ECC Code
++ //----------------------------------------------
++ while ( nReadSize )
++ {
++ /* Read as DWORD */
++ if ( nReadSize >= 4 )
++ {
++ uDWordByte.DWORD = WORD_OF(pNFC->NFC_WDATA);
++ *pEccB = uDWordByte.BYTE[0];++pEccB;
++ *pEccB = uDWordByte.BYTE[1];++pEccB;
++ *pEccB = uDWordByte.BYTE[2];++pEccB;
++ *pEccB = uDWordByte.BYTE[3];++pEccB;
++ nReadSize -= 4;
++ }
++ /* Read as WORD */
++ else if ( nReadSize >= 2 )
++ {
++ *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ nReadSize -= 2;
++ }
++ /* Read as BYTE */
++ else
++ {
++ *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ nReadSize -= 1;
++ }
++ }
++
++ /* Check and Correct ECC code */
++ if ( nEccOnOff == ECC_ON )
++ {
++ //===================================
++ // 4 Bit MLC ECC Correction
++ //===================================
++ if ( ( nECCBuffer[0] == 0x00 ) && ( nECCBuffer[1] == 0x00 ) &&
++ ( nECCBuffer[2] == 0x00 ) && ( nECCBuffer[3] == 0x00 ) &&
++ ( nECCBuffer[4] == 0x00 ) && ( nECCBuffer[5] == 0x00 ) &&
++ ( nECCBuffer[6] == 0x00 ) && ( nECCBuffer[7] == 0x00 ) &&
++ ( nECCBuffer[8] == 0x00 ) && ( nECCBuffer[9] == 0x00 ))
++ {
++ res |= NAND_IO_CorrectionMLC( MLC_ECC_4BIT_TYPE, pSpareBuffer, nECCBuffer, 12 );
++ res |= ERR_NAND_IO_FAILED_CORRECTION_MLC_ECC;
++ }
++ else
++ {
++ res |= NAND_IO_CorrectionMLC( MLC_ECC_4BIT_TYPE, pSpareBuffer, nECCBuffer, 12 );
++ }
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ res = (NAND_IO_ERROR)SUCCESS; // ECC Error Check Pass.
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_Read512DataDoubleBuf( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++* U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nReadPPSize =
++* nSpareBuffer =
++* nStartPPage =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_Read512DataDoubleBuf( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff, int nSpareOnOff )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ unsigned char *pPageB = 0, *pSpareB, *pEccB;
++ unsigned int *pPageDW = 0, *pSpareDW;
++ unsigned char *pDataBuffer;
++
++ unsigned char *pPrDataBuffer;
++
++ #ifdef _LINUX_
++ unsigned char nECCBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nECCBuffer[30];
++ #endif
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif /* READ_SPEED_CHECK */
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++ nSpareOnOff = TNFTL_READ_SPARE_ON;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6); //----------------------->> ECC Setup
++ #endif /* READ_SPEED_CHECK */
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ //----------------------------------------------
++ // Read Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nReadPPSize; ++j )
++ {
++ /* Set Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Read 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++ }
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw5);
++ #endif
++
++ /* Read 512 Data Area */
++ i = 128;
++ do {
++ if ( bAlignAddr )
++ {
++ *pPageDW = pNFC->NFC_WDATA;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ *pPageB = uDWordByte.BYTE[2];++pPageB;
++ *pPageB = uDWordByte.BYTE[3];++pPageB;
++ }
++ }while(--i);
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw5);
++ #endif
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++ }
++
++ /* Disable DMA Ahead */
++ /* Start DMA on NFC BUS */
++ NAND_IO_SetupDMADoubleBuf( NAND_IO_DMA_READ, j );
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif
++
++ pNFC->NFC_RSTART = 0;
++
++ if ( j != 0 )
++ {
++ if ( j & 1 )
++ memcpy( pPrDataBuffer, gpDMA_WorkBuffer1, 512 );
++ else
++ memcpy( pPrDataBuffer, gpDMA_WorkBuffer0, 512 );
++ }
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw5);
++ #endif
++ while ( ISZERO(pNFC->NFC_IREQ, HwNFC_IREQ_FLAG0) );
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw5);
++ #endif
++
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw4);
++ #endif
++ if ( j == ( nReadPPSize - 1 ) )
++ {
++ if ( j & 1 )
++ memcpy( pDataBuffer, gpDMA_WorkBuffer0, 512 );
++ else
++ memcpy( pDataBuffer, gpDMA_WorkBuffer1, 512 );
++ }
++ else
++ {
++ pPrDataBuffer = pDataBuffer; // Buffer Pointer Backup
++
++ if ( j & 1 )
++ pDataBuffer =(unsigned char *)gpDMA_WorkBuffer0;
++ else
++ pDataBuffer =(unsigned char *)gpDMA_WorkBuffer1;
++ }
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw4);
++ #endif
++
++ #endif
++ //####################################################
++ //####################################################
++
++ /* Read 'n'Bytes ECC data */
++ i = nDevInfo->EccDataSize;
++
++ // Clear ECC Buffer
++ memset( nECCBuffer, 0xFF, 30 );
++
++ /* Adapt type of address */
++ pEccB = (unsigned char*)nECCBuffer;
++
++ while ( i )
++ {
++ /* Read as DWORD */
++ if ( i >= 4 )
++ {
++ uDWordByte.DWORD = WORD_OF(pNFC->NFC_WDATA);
++ *pEccB = uDWordByte.BYTE[0];++pEccB;
++ *pEccB = uDWordByte.BYTE[1];++pEccB;
++ *pEccB = uDWordByte.BYTE[2];++pEccB;
++ *pEccB = uDWordByte.BYTE[3];++pEccB;
++ i -= 4;
++ }
++ /* Read as WORD */
++ else if ( i >= 2 )
++ {
++ *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ i -= 2;
++ }
++ /* Read as BYTE */
++ else
++ {
++ *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ i -= 1;
++ }
++ }
++
++ /* Check and Correct ECC code */
++ if ( nEccOnOff == ECC_ON )
++ {
++ if ( nDevInfo->EccType == SLC_ECC_TYPE )
++ {
++ //===================================
++ // SLC ECC Correction
++ //===================================
++ res |= NAND_IO_CorrectionSLC( pDataBuffer, nECCBuffer );
++ }
++ else
++ {
++ res |= NAND_IO_CorrectionMLC( nDevInfo->EccType, pDataBuffer, nECCBuffer, 512 );
++ }
++ }
++
++
++ }
++
++ if ( ( nStartPPage + nReadPPSize ) == ( nDevInfo->PPages ) )
++ //if ( nSpareOnOff == TNFTL_READ_SPARE_ON )
++ {
++ //=========================================================================
++ // Read Spare
++ //=========================================================================
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif
++
++ res |= NAND_IO_ReadSpareDataECC( nDevInfo, nSpareBuffer, nEccOnOff );
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif
++
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_Read528Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++* U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nReadPPSize =
++* nSpareBuffer =
++* nStartPPage =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_Read512Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff, int nSpareOnOff )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ unsigned char *pPageB = 0, *pSpareB, *pEccB;
++ unsigned int *pPageDW = 0, *pSpareDW;
++ unsigned char *pDataBuffer;
++ #ifdef _LINUX_
++ unsigned char nECCBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nECCBuffer[30];
++ #endif
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif /* READ_SPEED_CHECK */
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++ nSpareOnOff = TNFTL_READ_SPARE_ON;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6); //----------------------->> ECC Setup
++ #endif /* READ_SPEED_CHECK */
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ //----------------------------------------------
++ // Read Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nReadPPSize; ++j )
++ {
++ /* Set Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Read 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++ }
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw5);
++ #endif
++
++ /* Read 512 Data Area */
++ i = 128;
++ do {
++ if ( bAlignAddr )
++ {
++ *pPageDW = pNFC->NFC_WDATA;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ *pPageB = uDWordByte.BYTE[2];++pPageB;
++ *pPageB = uDWordByte.BYTE[3];++pPageB;
++ }
++ }while(--i);
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw5);
++ #endif
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++ }
++
++ /* Disable DMA Ahead */
++ /* Start DMA on NFC BUS */
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ (void*)pDataBuffer, 4, 0,
++ NAND_IO_DMA_READ, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)&pNFC->NFC_LDATA, 0, 0,
++ (void*)pDataBuffer, 4, 0,
++ NAND_IO_DMA_READ, 512 );
++ #endif
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++ #endif
++ //####################################################
++ //####################################################
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw4);
++ #endif
++
++ /* Read 'n'Bytes ECC data */
++ i = nDevInfo->EccDataSize;
++
++ // Clear ECC Buffer
++ memset( nECCBuffer, 0xFF, 30 );
++
++ /* Adapt type of address */
++ pEccB = (unsigned char*)nECCBuffer;
++
++ while ( i )
++ {
++ /* Read as DWORD */
++ if ( i >= 4 )
++ {
++ uDWordByte.DWORD = WORD_OF(pNFC->NFC_WDATA);
++ *pEccB = uDWordByte.BYTE[0];++pEccB;
++ *pEccB = uDWordByte.BYTE[1];++pEccB;
++ *pEccB = uDWordByte.BYTE[2];++pEccB;
++ *pEccB = uDWordByte.BYTE[3];++pEccB;
++ i -= 4;
++ }
++ /* Read as WORD */
++ else if ( i >= 2 )
++ {
++ *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ i -= 2;
++ }
++ /* Read as BYTE */
++ else
++ {
++ *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ i -= 1;
++ }
++ }
++
++ /* Check and Correct ECC code */
++ if ( nEccOnOff == ECC_ON )
++ {
++ if ( nDevInfo->EccType == SLC_ECC_TYPE )
++ {
++ //===================================
++ // SLC ECC Correction
++ //===================================
++ res |= NAND_IO_CorrectionSLC( pDataBuffer, nECCBuffer );
++ }
++ else
++ {
++ res |= NAND_IO_CorrectionMLC( nDevInfo->EccType, pDataBuffer, nECCBuffer, 512 );
++ }
++ }
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw4); //--------------------------------->> ECC Correction
++ #endif
++ }
++
++ if ( ( nStartPPage + nReadPPSize ) == ( nDevInfo->PPages ) )
++ //if ( nSpareOnOff == TNFTL_READ_SPARE_ON )
++ {
++ //=========================================================================
++ // Read Spare
++ //=========================================================================
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif
++
++ res |= NAND_IO_ReadSpareDataECC( nDevInfo, nSpareBuffer, nEccOnOff );
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw6);
++ #endif
++
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_Read528Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++* U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nReadPPSize =
++* nSpareBuffer =
++* nStartPPage =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_Read528Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0, *pSpareDW = 0;
++ unsigned char *pDataBuffer, *pSpareBuffer;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++ //=========================================================================
++ // Read Data as 512+16Bytes
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ //----------------------------------------------
++ // Read Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nReadPPSize; ++j )
++ {
++ /* Set Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Read 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; // Clear ECC Block
++ }
++
++ /* Read 512 Data Area */
++ i = 128;
++ do {
++ if ( bAlignAddr )
++ {
++ *pPageDW = pNFC->NFC_WDATA;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ *pPageB = uDWordByte.BYTE[2];++pPageB;
++ *pPageB = uDWordByte.BYTE[3];++pPageB;
++ }
++ }while(--i);
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; // Clear ECC Block
++ }
++
++ /* Disable DMA Ahead */
++ //IO_DMA_SetCTRL( IO_DMA_CH2, 0 );
++ //IO_INT_HwICLR = IO_INT_HwDMA_CH2;
++
++ /* Start DMA on NFC BUS */
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ (void*)pDataBuffer, 4, 0,
++ NAND_IO_DMA_READ, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)&pNFC->NFC_LDATA, 0, 0,
++ (void*)pDataBuffer, 4, 0,
++ NAND_IO_DMA_READ, 512 );
++ #endif
++
++ //if ( ISZERO(pDataBuffer,3) ) {
++ // #if defined(_WINCE_)
++ // memcpy( pDataBuffer, (void*)IO_NFC_BUFFER0_BASE, 512 );
++ // #elif defined(_LINUX_)
++ // #ifndef KERNEL_DRIVER
++ // memcpy(pDataBuffer, (void*)IO_NFC_BUFFER0_BASE, 512);
++ // #else
++ // memcpy(pDataBuffer, virtadr, 512);
++ // #endif
++ // #else
++ // fmemcpy16( pDataBuffer, (void*)IO_NFC_BUFFER0_BASE, 512 );
++ // #endif
++ //} else {
++ // #if defined(_WINCE_)
++ // memcpy( pDataBuffer, (void*)IO_NFC_BUFFER0_BASE, 512 );
++ // #elif defined(_LINUX_)
++ // #ifndef KERNEL_DRIVER
++ // memcpy(pDataBuffer, (void*)IO_NFC_BUFFER0_BASE, 512);
++ // #else
++ // memcpy(pDataBuffer, virtadr, 512);
++ // #endif
++ // #else
++ // memcpy( pDataBuffer, (void*)IO_NFC_BUFFER0_BASE, 512 );
++ // #endif
++ //}
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++ #endif
++ //####################################################
++ //####################################################
++
++ /* Set Spare Buffer */
++ pSpareBuffer = ( bAlignAddr ) ? (unsigned char*)pSpareDW : (unsigned char*)pSpareB;
++
++ /* Read 16Bytes spare data */
++ i = 4;
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++ /* Check and Correct ECC code */
++ if ( nEccOnOff == ECC_ON )
++ {
++ //----------------------------------------------------------------------
++ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
++ //----------------------------------------------------------------------
++ // MLC ECC Block Block BSA BAA SLC ECC Area 0 SLC ECC Area 1
++ // [0:1] Param Type [0:1] MLC ECC [2:5] MLC ECC [6:9]
++ //----------------------------------------------------------------------
++ if ( nDevInfo->EccType == SLC_ECC_TYPE )
++ {
++ res |= NAND_IO_CorrectionSLCForNB( pDataBuffer, pSpareBuffer );
++ }
++ else if ( nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ {
++ if (( pSpareBuffer[ 0] == 0xFF ) && ( pSpareBuffer[ 1] == 0xFF ) &&
++ ( pSpareBuffer[ 8] == 0xFF ) && ( pSpareBuffer[ 9] == 0xFF ) &&
++ ( pSpareBuffer[10] == 0xFF ) && ( pSpareBuffer[11] == 0xFF ) &&
++ ( pSpareBuffer[12] == 0xFF ) && ( pSpareBuffer[13] == 0xFF ) &&
++ ( pSpareBuffer[14] == 0xFF ) && ( pSpareBuffer[15] == 0xFF ))
++ {
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++ }
++ else if ( ( pSpareBuffer[ 0] == 0x00 ) &&( pSpareBuffer[ 1] == 0x00 ) &&
++ ( pSpareBuffer[ 2] == 0x00 ) &&( pSpareBuffer[ 3] == 0x00 ) &&
++ ( pSpareBuffer[ 4] == 0x00 ) &&( pSpareBuffer[ 5] == 0x00 ) &&
++ ( pSpareBuffer[ 6] == 0x00 ) &&( pSpareBuffer[ 7] == 0x00 ) &&
++ ( pSpareBuffer[ 8] == 0x00 ) &&( pSpareBuffer[ 9] == 0x00 ) &&
++ ( pSpareBuffer[10] == 0x00 ) &&( pSpareBuffer[11] == 0x00 ) &&
++ ( pSpareBuffer[12] == 0x00 ) &&( pSpareBuffer[13] == 0x00 ) &&
++ ( pSpareBuffer[14] == 0x00 ) &&( pSpareBuffer[15] == 0x00 ))
++ {
++ res |= ERR_NAND_IO_FAILED_CORRECTION_MLC_ECC;
++ }
++ else
++ {
++ res |= NAND_IO_CorrectionMLCForNB( pDataBuffer, pSpareBuffer );
++ }
++ }
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_Read512DataMTD( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++* U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nReadPPSize =
++* nSpareBuffer =
++* nStartPPage =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_Read512DataMTD( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff, int nSpareOnOff )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ unsigned int nECCDataSize;
++ unsigned char *pPageB = 0, *pSpareB;
++ unsigned int *pPageDW = 0, *pSpareDW;
++ unsigned char *pDataBuffer, *pSpareBuffer;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++ nSpareOnOff = TNFTL_READ_SPARE_ON;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ if ( nDevInfo->Feature.MediaType & A_MLC )
++ nECCDataSize = 8;
++ else if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ nECCDataSize = 20;
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ // Set SpareBuffer Pointer =>> ECCBuffer
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ //pSpareB = (unsigned char*)nSpareBuffer;
++ //pSpareB += NAND_IO_SPARE_SIZE_BIG;
++
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //=========================================================================
++ // Empty Page ECCBuffer Pointer Increment
++ //=========================================================================
++ for ( j = 0; j < nStartPPage; ++j )
++ pSpareB += nECCDataSize;
++ }
++
++ //----------------------------------------------
++ // Read Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nReadPPSize; ++j )
++ {
++ /* Set Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Read 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; // Clear ECC Block
++ }
++
++ /* Read 512 Data Area */
++ i = 128;
++ do {
++ if ( bAlignAddr )
++ {
++ *pPageDW = pNFC->NFC_WDATA;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ *pPageB = uDWordByte.BYTE[2];++pPageB;
++ *pPageB = uDWordByte.BYTE[3];++pPageB;
++ }
++ }while(--i);
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; // Clear ECC Block
++ }
++
++
++ /* Start DMA on NFC BUS */
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ (void*)pDataBuffer, 4, 0,
++ NAND_IO_DMA_READ, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)&pNFC->NFC_LDATA, 0, 0,
++ (void*)pDataBuffer, 4, 0,
++ NAND_IO_DMA_READ, 512 );
++ #endif
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++
++ #endif
++ //####################################################
++ //####################################################
++
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ // NOP
++ }
++ else if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ /* Set Spare Buffer */
++ pSpareBuffer = ( bAlignAddr ) ? (unsigned char*)pSpareDW : (unsigned char*)pSpareB;
++
++ /* Read 16Bytes spare data */
++ i = 4;
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++ pSpareB = (unsigned char*)pSpareBuffer;
++ pSpareB += NAND_IO_SPARE_SIZE_SMALL;
++ }
++
++ /* Check and Correct ECC code */
++ if ( nEccOnOff == ECC_ON )
++ {
++ if ( nDevInfo->EccType == SLC_ECC_TYPE )
++ {
++ //===================================
++ // SLC ECC Correction
++ //===================================
++ pSpareBuffer += NAND_IO_SPARE_SIZE_SMALL;
++ res |= NAND_IO_CorrectionSLC( pDataBuffer, pSpareBuffer );
++ }
++ else
++ {
++ res |= NAND_IO_CorrectionMLC( nDevInfo->EccType, pDataBuffer, pSpareB, 512 );
++
++ pSpareB += nECCDataSize;
++ }
++ }
++
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_ReadUserSizeData( NAND_IO_DEVINFO *nDevInfo, U16 nColumnAddr, U32 nReadSize, U8 *nReadBuffer );
++*
++* DESCRIPTION :
++* INPUT:
++* nColumnAddr =
++* nDevInfo =
++* nReadBuffer =
++* nReadSize =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadUserSizeData( NAND_IO_DEVINFO *nDevInfo, U16 nColumnAddr, U32 nReadSize, U8 *nReadBuffer )
++{
++ unsigned int *pSpareDW = 0;
++ unsigned char *pPageB = 0;
++ DWORD_BYTE uDWordByte;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Check Parameter
++ //=========================================================================
++ if ( (U32)( nColumnAddr + nReadSize ) > (U16)( nDevInfo->Feature.PageSize + nDevInfo->Feature.SpareSize ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Read UserSize Data
++ //=========================================================================
++
++ /* Adapt type of address */
++ pPageB = (unsigned char*)nReadBuffer;
++ pSpareDW= (unsigned int*)nReadBuffer;
++ if ( nReadSize >= 4 )
++ {
++ #ifdef USE_NFC_LDATA /* 08.12.17 */
++ /* Read 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = nReadSize;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ {
++ uDWordByte.DWORD = pNFC->NFC_LDATA;
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ *pPageB = uDWordByte.BYTE[2];++pPageB;
++ *pPageB = uDWordByte.BYTE[3];++pPageB;
++ }
++
++ nReadSize -= 4;
++
++ }while(nReadSize);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ }
++ else
++ {
++ #endif
++ while ( nReadSize )
++ {
++ /* Read as DWORD */
++ if ( nReadSize >= 4 )
++ {
++ uDWordByte.DWORD = WORD_OF(pNFC->NFC_WDATA);
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ *pPageB = uDWordByte.BYTE[2];++pPageB;
++ *pPageB = uDWordByte.BYTE[3];++pPageB;
++ nReadSize -= 4;
++ }
++ /* Read as WORD */
++ else if ( nReadSize >= 2 )
++ {
++ uDWordByte.WORD[0] = HWORD_OF(pNFC->NFC_WDATA);
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ nReadSize -= 2;
++ }
++ /* Read as BYTE */
++ else
++ {
++ uDWordByte.BYTE[0] = BYTE_OF(pNFC->NFC_WDATA);
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ nReadSize -= 1;
++ }
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ return (NAND_IO_ERROR)SUCCESS;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_WriteSpareData( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_WriteSpareData( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int i;
++ unsigned int nWriteSize;
++ unsigned char bAlignAddr;
++ unsigned char *pSpareB = 0;
++ unsigned int *pSpareDW = 0;
++ unsigned char *pEccB;
++ #ifdef _LINUX_
++ unsigned char nECCBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nECCBuffer[30];
++ #endif
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of nSpareBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nSpareBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ else
++ pSpareB = (unsigned char*)nSpareBuffer;
++
++ //==============================================================
++ // Write Spare
++ //==============================================================
++ if (!( pNFC->NFC_CTRL1 & Hw30 ))
++ {
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 12 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 12Bytes spare data */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 12;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = 3;
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_LDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ }
++ else
++ {
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 12 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ i = 3;
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++ }
++
++ // Clear ECC Buffer
++ memset( nECCBuffer, 0xFF, 30 );
++
++ /* Adapt type of address */
++ pEccB = (unsigned char*)nECCBuffer;
++
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( MLC_ECC_4BIT_TYPE, pEccB );
++ if ( res != SUCCESS )
++ goto ErrorWriteSpareData;
++ }
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ /* Write 4Bit ECC data */
++ if ( nEccOnOff == ECC_ON )
++ {
++ nWriteSize = 10;
++
++ while ( nWriteSize )
++ {
++ /* Write as DWORD */
++ if ( nWriteSize >= 4 )
++ {
++ uDWordByte.BYTE[0] = *pEccB;++pEccB;
++ uDWordByte.BYTE[1] = *pEccB;++pEccB;
++ uDWordByte.BYTE[2] = *pEccB;++pEccB;
++ uDWordByte.BYTE[3] = *pEccB;++pEccB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ nWriteSize -= 4;
++ }
++ /* Write as WORD */
++ else if ( nWriteSize >= 2 )
++ {
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ nWriteSize -= 2;
++ }
++ /* Write as BYTE */
++ else
++ {
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ nWriteSize -= 1;
++ }
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++
++ErrorWriteSpareData:
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_WriteSpareData( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_WriteSpareDataMTD( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nPageEccOnOff )
++{
++ unsigned int i;
++ unsigned int nSpareTotalSize;
++ unsigned int nECCDataSize;
++ unsigned char bAlignAddr;
++ unsigned char *pSpareB = 0;
++ unsigned int *pSpareDW = 0;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //if ( nDevInfo->Feature.MediaType & A_BIG )
++ // nSpareTotalSize = ( NAND_IO_SPARE_SIZE_BIG + nDevInfo->EccWholeDataSize );
++ //else
++ nSpareTotalSize = 32;
++
++ //=========================================================================
++ // Check Align of nSpareBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nSpareBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ else
++ pSpareB = (unsigned char*)nSpareBuffer;
++
++ if ( nDevInfo->Feature.MediaType & A_MLC )
++ nECCDataSize = 8;
++ else if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ nECCDataSize = 20;
++
++ //==============================================================
++ // Write Spare
++ //==============================================================
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++ ///* Setup ECC Block */
++ //#if defined(_WINCE_) || defined(_LINUX_)
++ //NAND_IO_SetupECC( (U16)ECC_ON, ECC_ENCODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ //#else
++ //NAND_IO_SetupECC( (U16)ECC_ON, ECC_ENCODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ //#endif
++ //pECC->ECC_CTRL |= ( nSpareTotalSize << ECC_SHIFT_DATASIZE );
++ //pECC->ECC_CLEAR = 0x00000000;
++
++ /* Write 12Bytes spare data */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = nSpareTotalSize;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = ( nSpareTotalSize >> 2 );
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_LDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++
++ //// Clear ECC Buffer
++ //memset( nECCBuffer, 0xFF, 8 );
++ //
++ ///* Adapt type of address */
++ //pEccB = (unsigned char*)nECCBuffer;
++ //
++ ///* Load ECC code from ECC block */
++ //res = NAND_IO_EncodeECC( MLC_ECC_4BIT_TYPE, pEccB );
++ //if ( res != SUCCESS )
++ // goto ErrorWriteSpareData;
++ //
++ //NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++ //
++ ///* Write 4Bit ECC data */
++ //nWriteSize = 8;
++ //
++ //while ( nWriteSize )
++ //{
++ // /* Write as DWORD */
++ // if ( nWriteSize >= 4 )
++ // {
++ // uDWordByte.BYTE[0] = *pEccB;++pEccB;
++ // uDWordByte.BYTE[1] = *pEccB;++pEccB;
++ // uDWordByte.BYTE[2] = *pEccB;++pEccB;
++ // uDWordByte.BYTE[3] = *pEccB;++pEccB;
++ // pNFC->NFC_WDATA = uDWordByte.DWORD;
++ // nWriteSize -= 4;
++ // }
++ // /* Write as WORD */
++ // else if ( nWriteSize >= 2 )
++ // {
++ // pNFC->NFC_SDATA = *pEccB;++pEccB;
++ // pNFC->NFC_SDATA = *pEccB;++pEccB;
++ // nWriteSize -= 2;
++ // }
++ // /* Write as BYTE */
++ // else
++ // {
++ // pNFC->NFC_SDATA = *pEccB;++pEccB;
++ // nWriteSize -= 1;
++ // }
++ //}
++
++ if ( nPageEccOnOff == PAGE_ECC_ON )
++ {
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)&gNAND_IO_ShareEccBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)&gNAND_IO_ShareEccBuffer[0];
++ else
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = ( ( nECCDataSize << 2 ) >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++ }
++ }
++ else
++ {
++ i = ( nSpareTotalSize >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ if (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL ))
++ {
++ if ( nPageEccOnOff == PAGE_ECC_ON )
++ {
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)&gNAND_IO_ShareEccBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)&gNAND_IO_ShareEccBuffer[0];
++ else
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = ( ( 8 << nDevInfo->ShiftPPages) >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++ }
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_Write512DataDoubleBuf( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize,
++* U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nSpareBuffer =
++* nStartPPage =
++* nWritePPSize =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_Write512DataDoubleBuf( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ #ifdef _LINUX_
++ unsigned char nDummyPageBuffer[512]__attribute__((aligned(8)));
++ unsigned char nECCBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nDummyPageBuffer[512];
++ unsigned char nECCBuffer[30];
++ #endif
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0, *pSpareDW = 0;
++ unsigned char *pDataBuffer;
++ unsigned char *pEccB;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ //----------------------------------------------
++ // Write Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nWritePPSize; ++j )
++ {
++ /* Get Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ if ( nEccOnOff == ECC_ON )
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_LDATA = *pPageDW;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ if ( nEccOnOff == ECC_ON )
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ if ( j == 0 )
++ memcpy( gpDMA_WorkBuffer1, pDataBuffer, 512 );
++
++ NAND_IO_SetupDMADoubleBuf( NAND_IO_DMA_WRITE, j );
++
++ if ( pNFC->NFC_CTRL1 & Hw31 )
++ BITCLR( pNFC->NFC_CTRL1, Hw31 );
++
++ pNFC->NFC_PSTART = 0;
++
++ if ( j != ( nWritePPSize - 1 ) )
++ {
++ if ( j & 1 )
++ memcpy( gpDMA_WorkBuffer1, (void *)(pDataBuffer + 512), 512 );
++ else
++ memcpy( gpDMA_WorkBuffer0, (void *)(pDataBuffer + 512), 512 );
++ }
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ if ( pNFC->NFC_CTRL1 & Hw30 )
++ BITSET( pNFC->NFC_CTRL1, Hw31 );
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++ #endif
++ //####################################################
++ //####################################################
++
++ // Clear ECC Buffer
++ memset( nECCBuffer, 0xFF, 30 );
++
++ /* Adapt type of address */
++ pEccB = (unsigned char*)nECCBuffer;
++
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pEccB );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++ }
++
++ /* Write 'n'Bytes ECC data */
++ i = nDevInfo->EccDataSize;
++
++ while ( i )
++ {
++ /* Write as DWORD */
++ if ( i >= 4 )
++ {
++ uDWordByte.BYTE[0] = *pEccB;++pEccB;
++ uDWordByte.BYTE[1] = *pEccB;++pEccB;
++ uDWordByte.BYTE[2] = *pEccB;++pEccB;
++ uDWordByte.BYTE[3] = *pEccB;++pEccB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ i -= 4;
++ }
++ /* Write as WORD */
++ else if ( i >= 2 )
++ {
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ i -= 2;
++ }
++ /* Write as BYTE */
++ else
++ {
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ i -= 1;
++ }
++ }
++ }
++
++ //=========================================================================
++ // Empty PPage Write
++ //=========================================================================
++ if ( ( nStartPPage + nWritePPSize ) != ( nDevInfo->PPages ) )
++ {
++ memset( nDummyPageBuffer, 0xFF, 512 );
++ //Write Dummy Data
++ for ( j = 0; j < (U16)( nDevInfo->PPages - ( nStartPPage + nWritePPSize ) ); ++j )
++ {
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do
++ {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++ pNFC->NFC_LDATA = 0xFFFFFFFF;
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)nDummyPageBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)nDummyPageBuffer, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ #endif
++ //####################################################
++ //####################################################
++
++ // Clear ECC Buffer
++ memset( nECCBuffer, 0xFF, 30 );
++
++ /* Adapt type of address */
++ pEccB = (unsigned char*)nECCBuffer;
++
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pEccB );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++ }
++
++ /* Write 'n'Bytes ECC data */
++ i = nDevInfo->EccDataSize;
++
++ while ( i )
++ {
++ if ( i >= 4 )
++ {
++ uDWordByte.BYTE[0] = *pEccB;++pEccB;
++ uDWordByte.BYTE[1] = *pEccB;++pEccB;
++ uDWordByte.BYTE[2] = *pEccB;++pEccB;
++ uDWordByte.BYTE[3] = *pEccB;++pEccB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ i -= 4;
++ }
++ else if ( i >= 2 )
++ {
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ i -= 2;
++ }
++ else
++ {
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ i -= 1;
++ }
++ }
++ }
++ }
++
++ //=========================================================================
++ // Write Spare Data
++ //=========================================================================
++ NAND_IO_WriteSpareData ( nDevInfo, nSpareBuffer, nEccOnOff );
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++
++ErrorWrite512Data:
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_Write512Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize,
++* U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nSpareBuffer =
++* nStartPPage =
++* nWritePPSize =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_Write512Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ #ifdef _LINUX_
++ unsigned char nDummyPageBuffer[512]__attribute__((aligned(8)));
++ unsigned char nECCBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nDummyPageBuffer[512];
++ unsigned char nECCBuffer[30];
++ #endif
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0, *pSpareDW = 0;
++ unsigned char *pDataBuffer;
++ unsigned char *pEccB;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ //----------------------------------------------
++ // Write Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nWritePPSize; ++j )
++ {
++ /* Get Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ if ( nEccOnOff == ECC_ON )
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_LDATA = *pPageDW;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ if ( nEccOnOff == ECC_ON )
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)pDataBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)pDataBuffer, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++ #endif
++ //####################################################
++ //####################################################
++
++ // Clear ECC Buffer
++ memset( nECCBuffer, 0xFF, 30 );
++
++ /* Adapt type of address */
++ pEccB = (unsigned char*)nECCBuffer;
++
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pEccB );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++ }
++
++ /* Write 'n'Bytes ECC data */
++ i = nDevInfo->EccDataSize;
++
++ while ( i )
++ {
++ /* Write as DWORD */
++ if ( i >= 4 )
++ {
++ uDWordByte.BYTE[0] = *pEccB;++pEccB;
++ uDWordByte.BYTE[1] = *pEccB;++pEccB;
++ uDWordByte.BYTE[2] = *pEccB;++pEccB;
++ uDWordByte.BYTE[3] = *pEccB;++pEccB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ i -= 4;
++ }
++ /* Write as WORD */
++ else if ( i >= 2 )
++ {
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ i -= 2;
++ }
++ /* Write as BYTE */
++ else
++ {
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ i -= 1;
++ }
++ }
++ }
++
++ //=========================================================================
++ // Empty PPage Write
++ //=========================================================================
++ if ( ( nStartPPage + nWritePPSize ) != ( nDevInfo->PPages ) )
++ {
++ memset( nDummyPageBuffer, 0xFF, 512 );
++ //Write Dummy Data
++ for ( j = 0; j < (U16)( nDevInfo->PPages - ( nStartPPage + nWritePPSize ) ); ++j )
++ {
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do
++ {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++ pNFC->NFC_LDATA = 0xFFFFFFFF;
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Disable DMA Ahead */
++ //IO_DMA_SetCTRL( IO_DMA_CH2, 0 );
++ //IO_INT_HwICLR = IO_INT_HwDMA_CH2;
++
++ ///* Prepare data */
++ // if ( ISZERO( nDummyPageBuffer, 3 ) ) {
++ // #if defined(_WINCE_)
++ // memcpy( (void*)IO_NFC_BUFFER0_BASE, nDummyPageBuffer, 512 );
++ // #elif defined(_LINUX_)
++ // #ifndef KERNEL_DRIVER
++ // memcpy( (void*)IO_NFC_BUFFER0_BASE, nDummyPageBuffer, 512 );
++ // #else
++ // memcpy( virtadr, nDummyPageBuffer, 512 );
++ // #endif
++ // #else
++ // fmemcpy16( (void*)IO_NFC_BUFFER0_BASE, nDummyPageBuffer, 512 );
++ // #endif
++ // } else {
++ // #if defined(_WINCE_)
++ // memcpy( (void*)IO_NFC_BUFFER0_BASE, nDummyPageBuffer, 512 );
++ // #elif defined(_LINUX_)
++ // #ifndef KERNEL_DRIVER
++ // memcpy( (void*)IO_NFC_BUFFER0_BASE, nDummyPageBuffer, 512 );
++ // #else
++ // memcpy( virtadr, nDummyPageBuffer, 512 );
++ // #endif
++ // #else
++ // memcpy( (void*)IO_NFC_BUFFER0_BASE, nDummyPageBuffer, 512 );
++ // #endif
++ // }
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)nDummyPageBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)nDummyPageBuffer, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ #endif
++ //####################################################
++ //####################################################
++
++ // Clear ECC Buffer
++ memset( nECCBuffer, 0xFF, 30 );
++
++ /* Adapt type of address */
++ pEccB = (unsigned char*)nECCBuffer;
++
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pEccB );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++ }
++
++ /* Write 'n'Bytes ECC data */
++ i = nDevInfo->EccDataSize;
++
++ while ( i )
++ {
++ if ( i >= 4 )
++ {
++ uDWordByte.BYTE[0] = *pEccB;++pEccB;
++ uDWordByte.BYTE[1] = *pEccB;++pEccB;
++ uDWordByte.BYTE[2] = *pEccB;++pEccB;
++ uDWordByte.BYTE[3] = *pEccB;++pEccB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ i -= 4;
++ }
++ else if ( i >= 2 )
++ {
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ i -= 2;
++ }
++ else
++ {
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ i -= 1;
++ }
++ }
++ }
++ }
++
++ //=========================================================================
++ // Write Spare Data
++ //=========================================================================
++ NAND_IO_WriteSpareData ( nDevInfo, nSpareBuffer, nEccOnOff );
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++
++ErrorWrite512Data:
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_Write528Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize,
++* U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nSpareBuffer =
++* nStartPPage =
++* nWritePPSize =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_Write528Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0, *pSpareDW = 0;
++ unsigned char *pDataBuffer, *pSpareBuffer;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++ //=========================================================================
++ // Write Data as 528Bytes
++ //=========================================================================
++
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ //----------------------------------------------
++ // Write Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nWritePPSize; ++j )
++ {
++ /* Get Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_LDATA = *pPageDW;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)pDataBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)pDataBuffer, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++ #endif
++ //####################################################
++ //####################################################
++
++ /* Get Spare Buffer */
++ pSpareBuffer = ( bAlignAddr ) ? (unsigned char*)pSpareDW : (unsigned char*)pSpareB;
++
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeNBECC( nDevInfo->EccType, pSpareBuffer );
++ if ( res != SUCCESS )
++ goto ErrorWrite528Data;
++ }
++
++ /* Write 16Bytes spare data */
++ i = 4;
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ErrorWrite528Data:
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_Write512DataMTD( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize,
++* U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nSpareBuffer =
++* nStartPPage =
++* nWritePPSize =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_Write512DataMTD( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ unsigned int nECCDataSize;
++ #ifdef _LINUX_
++ unsigned char nDummyPageBuffer[512]__attribute__((aligned(8)));
++ #else
++ unsigned char nDummyPageBuffer[512];
++ #endif
++ unsigned int ColumnAddr;
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0, *pSpareDW = 0;
++ unsigned char *pDataBuffer;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ECC_INFO *pECC_Info;
++ NAND_IO_ERROR res;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pPageDW = (unsigned int*)nPageBuffer;
++ else
++ pPageB = (unsigned char*)nPageBuffer;
++
++ if ( nDevInfo->Feature.MediaType & A_MLC )
++ nECCDataSize = 8;
++ else if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ nECCDataSize = 20;
++
++ // Set SpareBuffer Pointer =>> ECCBuffer
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ memset( gNAND_IO_ShareEccBuffer, 0xFF, nECCDataSize << 2 );
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++ }
++ else
++ {
++ pSpareB = (unsigned char*)nSpareBuffer;
++ pSpareB += NAND_IO_SPARE_SIZE_SMALL;
++ }
++
++ //=========================================================================
++ // Empty Page ECCBuffer Pointer Increment
++ //=========================================================================
++ for ( j = 0; j < nStartPPage; ++j )
++ {
++ if ( nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ pECC_Info = &gMLC_ECC_4Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_8BIT_TYPE )
++ pECC_Info = &gMLC_ECC_8Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_12BIT_TYPE )
++ pECC_Info = &gMLC_ECC_12Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_14BIT_TYPE )
++ pECC_Info = &gMLC_ECC_14Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_16BIT_TYPE )
++ pECC_Info = &gMLC_ECC_16Bit;
++ else
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ memcpy( (void*)pSpareB, (void*)pECC_Info->All_FF_512_ECC_Code, nECCDataSize);
++
++ pSpareB += nECCDataSize;
++ }
++
++ //----------------------------------------------
++ // Write Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nWritePPSize; ++j )
++ {
++ /* Get Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ if ( nEccOnOff == ECC_ON )
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_LDATA = *pPageDW;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ if ( nEccOnOff == ECC_ON )
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)pDataBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)pDataBuffer, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++ #endif
++ //####################################################
++ //####################################################
++
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pSpareB );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++ }
++
++ pSpareB += nECCDataSize;
++ }
++
++ //=========================================================================
++ // Empty PPage Write
++ //=========================================================================
++ if ( ( nStartPPage + nWritePPSize ) != ( nDevInfo->PPages ) )
++ {
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ //---------------------------------
++ // Random Data Input [ 0x85 ]
++ //---------------------------------
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8585;
++
++ //---------------------------------
++ // Write Column Address
++ //---------------------------------
++ ColumnAddr = nDevInfo->Feature.PageSize;
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_PARALLEL ) ? (ColumnAddr >> 1) : ColumnAddr;
++ NAND_IO_WriteColAddr( ColumnAddr, nDevInfo );
++
++ //---------------------------------
++ // ECC Data Clear
++ //---------------------------------
++ for ( j = 0; j < (U16)( nDevInfo->PPages - ( nStartPPage + nWritePPSize ) ); ++j )
++ {
++ if ( nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ pECC_Info = &gMLC_ECC_4Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_8BIT_TYPE )
++ pECC_Info = &gMLC_ECC_8Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_12BIT_TYPE )
++ pECC_Info = &gMLC_ECC_12Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_14BIT_TYPE )
++ pECC_Info = &gMLC_ECC_14Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_16BIT_TYPE )
++ pECC_Info = &gMLC_ECC_16Bit;
++ else
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ memcpy( (void*)pSpareB, (void*)pECC_Info->All_FF_512_ECC_Code, nECCDataSize);
++
++ pSpareB += nECCDataSize;
++ }
++ }
++ else
++ {
++ memset( nDummyPageBuffer, 0xFF, 512 );
++ //Write Dummy Data
++ for ( j = 0; j < (U16)( nDevInfo->PPages - ( nStartPPage + nWritePPSize ) ); ++j )
++ {
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do
++ {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++ pNFC->NFC_LDATA = 0xFFFFFFFF;
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)nDummyPageBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)nDummyPageBuffer, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ #endif
++ //####################################################
++ //####################################################
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pSpareB );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++ }
++
++ pSpareB += nECCDataSize;
++ }
++ }
++ }
++
++ //=========================================================================
++ // Write Spare Data
++ //=========================================================================
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ NAND_IO_WriteSpareDataMTD( nDevInfo, nSpareBuffer, PAGE_ECC_ON );
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++
++ErrorWrite512Data:
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_WriteUserSizeData( NAND_IO_DEVINFO *nDevInfo, U16 nColumnAddr, U32 nWriteSize, U8 *nWriteBuffer );
++*
++* DESCRIPTION :
++* INPUT:
++* nColumnAddr =
++* nDevInfo =
++* nWriteBuffer =
++* nWriteSize =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_WriteUserSizeData( NAND_IO_DEVINFO *nDevInfo, U16 nColumnAddr, U32 nWriteSize, U8 *nWriteBuffer )
++{
++ unsigned int *dwPageB;
++ unsigned char *pPageB;
++ DWORD_BYTE uDWordByte;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Check Parameter
++ //=========================================================================
++ if ( (U32)( nColumnAddr + nWriteSize ) > (U32)( nDevInfo->Feature.PageSize + nDevInfo->Feature.SpareSize ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Write UserSize Data
++ //=========================================================================
++ pPageB = (unsigned char*)nWriteBuffer;
++ dwPageB = (unsigned int*)nWriteBuffer;
++
++ if ( nWriteSize >= 4 )
++ {
++ #ifdef USE_NFC_LDATA /* 08.12.17 */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = nWriteSize;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ do {
++ while (!( pNFC->NFC_IREQ & HwNFC_CTRL_FS_RDY ));
++
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ nWriteSize -= 4;
++ }while(nWriteSize);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ }
++ else
++ {
++ #endif
++
++ if ( pNFC->NFC_CTRL1 & Hw31 )
++ BITCLR( pNFC->NFC_CTRL1, Hw31 );
++
++ while ( nWriteSize )
++ {
++ /* Write as DWORD */
++ if ( nWriteSize >= 4 )
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ WORD_OF(pNFC->NFC_WDATA) = uDWordByte.DWORD;
++ nWriteSize -= 4;
++ }
++ /* Write as WORD */
++ else if ( nWriteSize >= 2 )
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ HWORD_OF(pNFC->NFC_WDATA) = uDWordByte.WORD[0];
++ nWriteSize -= 2;
++ }
++ /* Write as BYTE */
++ else
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ BYTE_OF(pNFC->NFC_WDATA) = uDWordByte.BYTE[0];
++ nWriteSize -= 1;
++ }
++ }
++
++ if ( pNFC->NFC_CTRL1 & Hw30 )
++ BITSET( pNFC->NFC_CTRL1, Hw31 );
++
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ return (NAND_IO_ERROR)SUCCESS;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_GetShiftValueForFastMultiPly( U16 nValue, U16* rFactor );
++*
++* DESCRIPTION :
++* INPUT:
++* nValue =
++* rFactor =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_GetShiftValueForFastMultiPly( U16 nValue, U16* rFactor )
++{
++ unsigned short int i;
++
++ *rFactor = 0;
++
++ for ( i = 0; i < NAND_IO_MAX_SHIFT_FACTOR_FOR_MULTIPLY; ++i )
++ {
++ if ( NAND_IO_ShiftFactorForMultiplay[i] == nValue )
++ {
++ *rFactor = i;
++ break;
++ }
++ }
++
++ if ( i >= NAND_IO_MAX_SHIFT_FACTOR_FOR_MULTIPLY )
++ return ERR_NAND_IO_FAILED_GET_SHIFT_FACTOR_FOR_MULTIPLY;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_SetCallBackHandler( NAND_LBA_CALLBACK_HANDLER pCallBackHandler )
++{
++ NAND_IO_LBA_CallBackLcdDisplay = pCallBackHandler;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_GetDeviceInfo( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned short int j,k,l;
++ unsigned char bFindMedia;
++ unsigned char bFindMakerNo;
++ unsigned char bMatchCount;
++ unsigned char rBootMode, rRebootCmd;
++ NAND_IO_DEVID sDeviceCode;
++ NAND_IO_FEATURE *sTempFeatureInfo;
++ NAND_IO_FEATURE *sFindFeatureInfo;
++ NAND_IO_ERROR res;
++
++ bFindMedia = FALSE;
++ sTempFeatureInfo = (NAND_IO_FEATURE*)LBA_NAND_SupportMakerInfo.DevInfo[0];
++ sFindFeatureInfo = (NAND_IO_FEATURE*)LBA_NAND_SupportMakerInfo.DevInfo[0];
++
++ NAND_IO_LBA_DeviceReboot( nDevInfo );
++ res = NAND_IO_GetDeviceInfo( 0, nDevInfo );
++ if ( res != SUCCESS )
++ return ERR_NAND_IO_FAILED_GET_DEVICE_INFO;
++
++ if (!( nDevInfo->Feature.MediaType & S_LBA ))
++ return ERR_NAND_IO_FAILED_GET_DEVICE_INFO;
++
++ res = NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_BCM );
++ if ( res != SUCCESS )
++ {
++ NAND_IO_LBA_DeviceReboot( nDevInfo );
++ res = NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_BCM );
++ if ( res != SUCCESS )
++ return res;
++ }
++
++ NAND_IO_LBA_GetPersistentFunction( nDevInfo, &rBootMode, &rRebootCmd );
++
++ if ( ( rBootMode != 0x22 ) || ( rRebootCmd != 0xAF ))
++ {
++ rBootMode = 0x22;
++ rRebootCmd = 0xAF;
++
++ NAND_IO_LBA_SetBootModeChange( nDevInfo, rBootMode );
++ NAND_IO_LBA_SetRebootCmdChange( nDevInfo, rRebootCmd );
++ NAND_IO_LBA_DeviceReboot( nDevInfo );
++ }
++
++ NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_MDP );
++ NAND_IO_LBA_SetTransferProtocol( nDevInfo, 0x04, 0x00 );
++
++ nDevInfo->LBAInfo.Usable = DISABLE;
++ //=====================================================================
++ // Search Matched NANDFLASH
++ //=====================================================================
++ for ( j = 0; j < 3; ++j ) /* Check Read ID during 3 turn */
++ {
++ /* Read Device CODE */
++ NAND_IO_LBA_ReadID( nDevInfo, &sDeviceCode);
++
++ /* Check Maker ID */
++ bFindMakerNo = 0xFF;
++ for ( k = 0; k < MAX_SUPPORT_MAKER_LBA_NAND; ++k )
++ {
++ if ( sDeviceCode.Code[0] == LBA_NAND_SupportMakerInfo.MakerID[k] )
++ {
++ bFindMakerNo = (unsigned char)k;
++ sTempFeatureInfo = (NAND_IO_FEATURE*)LBA_NAND_SupportMakerInfo.DevInfo[k];
++ break;
++ }
++ }
++
++ if ( bFindMakerNo >= MAX_SUPPORT_MAKER_NAND )
++ continue;
++
++ /* Check Device ID */
++ for ( k = 0; k < LBA_NAND_SupportMakerInfo.MaxSupportNAND[bFindMakerNo]; ++k )
++ {
++ bMatchCount = 0;
++
++ for ( l = 0; l < 4; ++l )
++ {
++ if ( sTempFeatureInfo->DeviceID.Code[l+1] == 0x00 )
++ ++bMatchCount;
++ else if ( sDeviceCode.Code[l+1] == sTempFeatureInfo->DeviceID.Code[l+1] )
++ ++bMatchCount;
++ }
++
++ /* Found NAND Device */
++ if ( bMatchCount >= 4 )
++ {
++ bFindMedia = TRUE;
++ sFindFeatureInfo = sTempFeatureInfo;
++ break;
++ }
++ else
++ ++sTempFeatureInfo;
++ }
++
++ /* Found NAND Device */
++ if ( bFindMedia == TRUE )
++ break;
++ }
++
++ if ( bFindMedia == TRUE )
++ return (NAND_IO_ERROR)SUCCESS;
++ //=====================================================================
++ // Not Found
++ //=====================================================================
++ else
++ return ERR_NAND_IO_FAILED_GET_DEVICE_INFO;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_Init( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned short int j,k,l;
++ unsigned char bFindMedia;
++ unsigned char bFindMakerNo;
++ unsigned char bMatchCount;
++ unsigned char rBootMode, rRebootCmd;
++ NAND_IO_DEVID sDeviceCode;
++ NAND_IO_FEATURE *sTempFeatureInfo;
++ NAND_IO_FEATURE *sFindFeatureInfo;
++ NAND_IO_ERROR res;
++
++ bFindMedia = FALSE;
++ sTempFeatureInfo = (NAND_IO_FEATURE*)LBA_NAND_SupportMakerInfo.DevInfo[0];
++ sFindFeatureInfo = (NAND_IO_FEATURE*)LBA_NAND_SupportMakerInfo.DevInfo[0];
++
++ NAND_IO_LBA_DeviceReboot( nDevInfo );
++ NAND_IO_GetDeviceInfo( 0, nDevInfo );
++
++ res = NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_BCM );
++ if ( res != SUCCESS )
++ {
++ NAND_IO_LBA_DeviceReboot( nDevInfo );
++ res = NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_BCM );
++ if ( res != SUCCESS )
++ return res;
++ }
++
++ NAND_IO_LBA_GetPersistentFunction( nDevInfo, &rBootMode, &rRebootCmd );
++
++ if ( ( rBootMode != 0x22 ) || ( rRebootCmd != 0xAF ))
++ {
++ rBootMode = 0x22;
++ rRebootCmd = 0xAF;
++
++ NAND_IO_LBA_SetBootModeChange( nDevInfo, rBootMode );
++ NAND_IO_LBA_SetRebootCmdChange( nDevInfo, rRebootCmd );
++ NAND_IO_LBA_DeviceReboot( nDevInfo );
++ }
++
++ NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_MDP );
++ NAND_IO_LBA_SetTransferProtocol( nDevInfo, 0x04, 0x00 );
++
++ nDevInfo->LBAInfo.Usable = DISABLE;
++ //=====================================================================
++ // Search Matched NANDFLASH
++ //=====================================================================
++ for ( j = 0; j < 3; ++j ) /* Check Read ID during 3 turn */
++ {
++ /* Read Device CODE */
++ NAND_IO_LBA_ReadID( nDevInfo, &sDeviceCode);
++
++ /* Check Maker ID */
++ bFindMakerNo = 0xFF;
++ for ( k = 0; k < MAX_SUPPORT_MAKER_LBA_NAND; ++k )
++ {
++ if ( sDeviceCode.Code[0] == LBA_NAND_SupportMakerInfo.MakerID[k] )
++ {
++ bFindMakerNo = (unsigned char)k;
++ sTempFeatureInfo = (NAND_IO_FEATURE*)LBA_NAND_SupportMakerInfo.DevInfo[k];
++ break;
++ }
++ }
++
++ if ( bFindMakerNo >= MAX_SUPPORT_MAKER_NAND )
++ continue;
++
++ /* Check Device ID */
++ for ( k = 0; k < LBA_NAND_SupportMakerInfo.MaxSupportNAND[bFindMakerNo]; ++k )
++ {
++ bMatchCount = 0;
++
++ for ( l = 0; l < 4; ++l )
++ {
++ if ( sTempFeatureInfo->DeviceID.Code[l+1] == 0x00 )
++ ++bMatchCount;
++ else if ( sDeviceCode.Code[l+1] == sTempFeatureInfo->DeviceID.Code[l+1] )
++ ++bMatchCount;
++ }
++
++ /* Found NAND Device */
++ if ( bMatchCount >= 4 )
++ {
++ bFindMedia = TRUE;
++ sFindFeatureInfo = sTempFeatureInfo;
++ break;
++ }
++ else
++ ++sTempFeatureInfo;
++ }
++
++ /* Found NAND Device */
++ if ( bFindMedia == TRUE )
++ break;
++ }
++
++ if ( bFindMedia == TRUE )
++ {
++ // Get Protocol
++ NAND_IO_LBA_GetTransferProtocol( nDevInfo, &nDevInfo->LBAInfo.TransProtocol1, &nDevInfo->LBAInfo.TransProtocol2 );
++
++ // Data Format
++ if ( nDevInfo->LBAInfo.TransProtocol1 & NAND_PROT1_SPARE_INCLUDE )
++ nDevInfo->LBAInfo.DataTransferCheck = ENABLE;
++ else
++ nDevInfo->LBAInfo.DataTransferCheck = DISABLE;
++
++ // Sector Count
++ nDevInfo->LBAInfo.SectorCount = ( nDevInfo->LBAInfo.TransProtocol1 & NAND_PROT1_SECTOR_COUNT_MASK );
++
++ if ( nDevInfo->LBAInfo.SectorCount != 1 )
++ nDevInfo->LBAInfo.SectorCount = nDevInfo->LBAInfo.SectorCount << 1;
++
++ // Set Power Save Mode
++ NAND_IO_LBA_PowerSaveMode( nDevInfo, DISABLE );
++
++ // Set High Speed Mode
++ NAND_IO_LBA_HighSpeedMode( nDevInfo, ENABLE );
++
++ NAND_IO_LBA_VFPGetTotalSectorSize( nDevInfo, (U32 *)&nDevInfo->LBAInfo.VFPSectorSize );
++ if ( ( nDevInfo->LBAInfo.VFPSectorSize << 9 ) < gMAX_ROMSIZE )
++ {
++ // LBA Factory Setting values : 8 Mbyte
++ res = NAND_IO_LBA_VFPChangeSectorSize( nDevInfo, gMAX_ROMSIZE >> 9 );
++ if ( res != SUCCESS )
++ return res;
++
++ NAND_IO_LBA_VFPGetTotalSectorSize( nDevInfo, (U32 *)&nDevInfo->LBAInfo.VFPSectorSize );
++ }
++
++ // Get Size Info
++ NAND_IO_LBA_MDPGetTotalSectorSize( nDevInfo, (unsigned long int *)&nDevInfo->LBAInfo.MDPSectorSize );
++
++ res = NAND_IO_LBA_VFPInitArea( nDevInfo );
++ if ( res != SUCCESS )
++ return res;
++
++ nDevInfo->LBAInfo.Usable = ENABLE;
++ }
++ //=====================================================================
++ // Not Found
++ //=====================================================================
++ else
++ {
++ return ERR_NAND_IO_FAILED_GET_DEVICE_INFO;
++ }
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++U32 NAND_IO_LBA_GetSerialNumber( NAND_IO_DEVINFO *nDevInfo, U8* nPageBuffer, U8* rSerialNumber, U16 nSize )
++{
++ unsigned int j;
++ unsigned int dwIDSize;
++ unsigned char ucTempData[64];
++ unsigned char *cPageBuffer;
++ unsigned char *cSpareBuffer;
++ NAND_IO_ERROR res;
++
++ cPageBuffer = &nPageBuffer[0];
++ cSpareBuffer = &nPageBuffer[nDevInfo->Feature.PageSize];
++ nSize = 0;
++
++ NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_BCM );
++
++ res = NAND_IO_ReadGoldenPage( nDevInfo, 0, cPageBuffer, cSpareBuffer );
++ if ( res != SUCCESS)
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ memcpy( ucTempData, &nPageBuffer[ ( 512 + 16 ) * ( nDevInfo->PPages - 1 ) ], 64 );
++
++ dwIDSize = 32;
++
++ for ( j = 0; j < dwIDSize; ++j )
++ rSerialNumber[j] = ucTempData[j];
++
++ return dwIDSize;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_GetTotalSecAndCHS( NAND_IO_DEVINFO *nDevInfo, int nPartition, U32 *rTotalSec, U16 *rCylinder, U16 *rHead, U8 *rSector )
++{
++ unsigned long int nTotalSectorSize;
++ unsigned short int wCurrHead;
++ unsigned short int wCurrCylinder;
++
++ if ( nPartition == NAND_LBA_DATA_AREA )
++ nTotalSectorSize = nDevInfo->LBAInfo.DTAreaSectorSize;
++ else if ( nPartition == NAND_LBA_HIDDEN_AREA )
++ nTotalSectorSize = nDevInfo->LBAInfo.HDAreaSectorSize;
++ else if ( nPartition == NAND_LBA_MDP )
++ nTotalSectorSize = nDevInfo->LBAInfo.MDPSectorSize;
++ else if ( nPartition == NAND_LBA_VFP )
++ nTotalSectorSize = nDevInfo->LBAInfo.VFPSectorSize;
++ else
++ nTotalSectorSize = 0;
++
++ if ( nTotalSectorSize == 0 )
++ {
++ *rTotalSec = 0;
++ *rCylinder = 0;
++ *rHead = 0;
++ *rSector = 0;
++
++ return (NAND_IO_ERROR)SUCCESS;
++ }
++
++ if ( nTotalSectorSize >= (U32)( 1024 * 256 * 64 ) )
++ {
++ *rTotalSec = nTotalSectorSize;
++ *rCylinder = (U16)(nTotalSectorSize / ( 256 * 64 ));
++ *rHead = 256;
++ *rSector = 64;
++ }
++ else
++ {
++ for ( wCurrHead = 2; wCurrHead <= 256; wCurrHead *= 2 )
++ {
++ wCurrCylinder = (U16)(nTotalSectorSize / ( wCurrHead * 64 ));
++
++ if ( wCurrCylinder > 1024 )
++ continue;
++
++ *rTotalSec = (U32)( wCurrCylinder * wCurrHead * 64 );
++ *rCylinder = wCurrCylinder;
++ *rHead = wCurrHead;
++ *rSector = 64;
++
++ break;
++ }
++ }
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_ReadSectorBy4Byte( NAND_IO_DEVINFO *nDevInfo, U8 nPartition, U32 nSectorAddr, U16 nOffset, U16 nReadSize, U8 *nReadBuffer )
++{
++ unsigned short int wCurrPPSize;
++ unsigned short int wFlagFirstSector;
++ unsigned long int dwSectorAddr;
++ unsigned long int dwTotalReadSecSize;
++ unsigned long int nTotalSectorSize;
++ unsigned long int dwSectorAddrOffSet;
++ unsigned char cReadBuffer[512];
++ unsigned char cSpareBuffer[16];
++ unsigned char *pReadBuffer;
++ unsigned char cPartition;
++ NAND_IO_ERROR res;
++
++ //######################################################
++ //# Check Parameter
++ //######################################################
++ if ( nDevInfo->LBAInfo.Usable != ENABLE )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ cPartition = nPartition & 0x0F;
++
++ if ( nDevInfo->LBAInfo.CurrentMode != cPartition )
++ NAND_IO_LBA_ModeChange( nDevInfo, cPartition );
++
++ if ( nPartition == NAND_LBA_DATA_AREA )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.DTAreaSectorSize;
++ dwSectorAddrOffSet = 0;
++ }
++ else if ( nPartition == NAND_LBA_HIDDEN_AREA )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.HDAreaSectorSize;
++ dwSectorAddrOffSet = nDevInfo->LBAInfo.HDAreaAddrOffSet;
++ }
++ else if ( nPartition == NAND_LBA_MULTI_HIDDEN_AREA_0 )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.MHDAreaSectorSize[0];
++ dwSectorAddrOffSet = nDevInfo->LBAInfo.MHDAreaAddrOffSet[0];
++ }
++ else if ( nPartition == NAND_LBA_MDP )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.MDPSectorSize;
++ dwSectorAddrOffSet = 0;
++ }
++ else if ( nPartition == NAND_LBA_VFP )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.VFPSectorSize;
++ dwSectorAddrOffSet = 1;
++ }
++ else
++ {
++ nTotalSectorSize = 0;
++ dwSectorAddrOffSet = 0;
++ return ERR_NAND_IO_WRONG_PARAMETER;
++ }
++
++ if ( ( nSectorAddr + 1 ) > nTotalSectorSize )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ if (( !nReadSize ) || (( nOffset + nReadSize ) > 128 ))
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ pReadBuffer = nReadBuffer;
++
++ wFlagFirstSector = TRUE;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetCommCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ //NAND_IO_DisableWriteProtect();
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //######################################################
++ //# Get Info of Parameter
++ //######################################################
++ dwSectorAddr = nSectorAddr;
++ dwSectorAddr += dwSectorAddrOffSet;
++ dwTotalReadSecSize = 1;
++
++ if ( dwTotalReadSecSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)dwTotalReadSecSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount ;
++
++ //######################################################
++ //# Write Total Sector
++ //######################################################
++
++ while ( dwTotalReadSecSize )
++ {
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ if ( wFlagFirstSector == TRUE )
++ {
++ /* Write Sector Size & Sector Address */
++ pNFC->NFC_SADDR= ( 1 & 0xFF ); // Write Sector Num : SC0
++ pNFC->NFC_SADDR= ( ( 1 >> 8 ) & 0xFF ); // Write Sector Num : SC1
++ pNFC->NFC_SADDR= ( dwSectorAddr & 0xFF ); // Write Sector Addr: AD0
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 8 ) & 0xFF ); // Write Sector Addr: AD1
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 16 ) & 0xFF ); // Write Sector Addr: AD2
++ }
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ NAND_IO_SetReadCycleTime();
++ /* Write Data to NAND FLASH */
++ res = NAND_IO_LBA_ReadData( nDevInfo, wCurrPPSize, cReadBuffer, cSpareBuffer );
++ if ( res != SUCCESS )
++ return res;
++
++ NAND_IO_SetCommCycleTime();
++
++ /* Decrease Write Size */
++ dwTotalReadSecSize -= wCurrPPSize;
++
++ /* Increase Buffer Address */
++ nReadBuffer += ( nDevInfo->LBAInfo.SectorCount << 9 );
++
++ /* Count Next Page Size */
++ if ( dwTotalReadSecSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)dwTotalReadSecSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount;
++
++ if ( nDevInfo->LBAInfo.TransProtocol2 & NAND_PROT2_WRITE_TYPE_B )
++ wFlagFirstSector = FALSE;
++ }
++
++ memcpy( pReadBuffer, &cReadBuffer[nOffset << 2], nReadSize << 2 );
++
++ /* FORCE TO SET WP LOW */
++ //NAND_IO_EnableWriteProtect();
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_ReadSector( NAND_IO_DEVINFO *nDevInfo, U8 nPartition, U32 nSectorAddr, U16 nSecSize, U8 *nReadBuffer )
++{
++ unsigned short int wCurrPPSize;
++ unsigned short int wFlagFirstSector;
++ unsigned long int dwSectorAddr;
++ unsigned long int dwSectorAddrOffSet;
++ unsigned long int dwTotalReadSecSize;
++ unsigned long int nTotalSectorSize;
++ unsigned char cPartition;
++ unsigned char cSpareBuffer[16];
++ NAND_IO_ERROR res;
++
++ //######################################################
++ //# Check Parameter
++ //######################################################
++ if ( nDevInfo->LBAInfo.Usable != ENABLE )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ cPartition = nPartition & 0x0F;
++
++ if ( nDevInfo->LBAInfo.CurrentMode != cPartition )
++ NAND_IO_LBA_ModeChange( nDevInfo, cPartition );
++
++ if ( nPartition == NAND_LBA_DATA_AREA )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.DTAreaSectorSize;
++ dwSectorAddrOffSet = 0;
++ }
++ else if ( nPartition == NAND_LBA_HIDDEN_AREA )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.HDAreaSectorSize;
++ dwSectorAddrOffSet = nDevInfo->LBAInfo.HDAreaAddrOffSet;
++ }
++ else if ( nPartition == NAND_LBA_MULTI_HIDDEN_AREA_0 )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.MHDAreaSectorSize[0];
++ dwSectorAddrOffSet = nDevInfo->LBAInfo.MHDAreaAddrOffSet[0];
++ }
++ else if ( nPartition == NAND_LBA_MDP )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.MDPSectorSize;
++ dwSectorAddrOffSet = 0;
++ }
++ else if ( nPartition == NAND_LBA_VFP )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.VFPSectorSize;
++ dwSectorAddrOffSet = 1;
++ }
++ else
++ {
++ nTotalSectorSize = 0;
++ dwSectorAddrOffSet = 0;
++ return ERR_NAND_IO_WRONG_PARAMETER;
++ }
++
++ if ( ( nSectorAddr + nSecSize ) > nTotalSectorSize )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ wFlagFirstSector = TRUE;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetCommCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ //NAND_IO_DisableWriteProtect();
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //######################################################
++ //# Get Info of Parameter
++ //######################################################
++ dwSectorAddr = nSectorAddr;
++ dwSectorAddr += dwSectorAddrOffSet;
++ dwTotalReadSecSize = nSecSize;
++
++ if ( dwTotalReadSecSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)dwTotalReadSecSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount ;
++
++ //######################################################
++ //# Write Total Sector
++ //######################################################
++
++ while ( dwTotalReadSecSize )
++ {
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ if ( wFlagFirstSector == TRUE )
++ {
++ /* Write Sector Size & Sector Address */
++ pNFC->NFC_SADDR= ( nSecSize & 0xFF ); // Write Sector Num : SC0
++ pNFC->NFC_SADDR= ( ( nSecSize >> 8 ) & 0xFF ); // Write Sector Num : SC1
++ pNFC->NFC_SADDR= ( dwSectorAddr & 0xFF ); // Write Sector Addr: AD0
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 8 ) & 0xFF ); // Write Sector Addr: AD1
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 16 ) & 0xFF ); // Write Sector Addr: AD2
++ }
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ NAND_IO_SetReadCycleTime();
++ /* Write Data to NAND FLASH */
++ res = NAND_IO_LBA_ReadData( nDevInfo, wCurrPPSize, nReadBuffer, cSpareBuffer );
++ if ( res != SUCCESS )
++ return res;
++
++ NAND_IO_SetCommCycleTime();
++
++ /* Decrease Write Size */
++ dwTotalReadSecSize -= wCurrPPSize;
++
++ /* Increase Buffer Address */
++ nReadBuffer += ( nDevInfo->LBAInfo.SectorCount << 9 );
++
++ /* Count Next Page Size */
++ if ( dwTotalReadSecSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)dwTotalReadSecSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount;
++
++ if ( nDevInfo->LBAInfo.TransProtocol2 & NAND_PROT2_WRITE_TYPE_B )
++ wFlagFirstSector = FALSE;
++ }
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xFBFB;
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* FORCE TO SET WP LOW */
++ //NAND_IO_EnableWriteProtect();
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_AREAClear( NAND_IO_DEVINFO *nDevInfo, U8 nPartition )
++{
++ unsigned int nSectorAddr;
++ unsigned short int wCurrPPSize;
++ unsigned short int wFlagFirstSector;
++
++ unsigned short int wOldProcessRate;
++ unsigned short int wProcessRate;
++ unsigned long int nProCessWriteSectorSize;
++
++ unsigned long int dwSectorAddr;
++ unsigned long int dwSectorAddrOffSet;
++ unsigned short int wOnceWriteSectorCount;
++ unsigned long int dwTotalWriteSecSize;
++ unsigned long int nTotalSectorSize;
++ unsigned long int nWriteSectorSize;
++ unsigned char cPartition;
++ NAND_IO_ERROR res;
++
++ //######################################################
++ //# Check Parameter
++ //######################################################
++ if ( nDevInfo->LBAInfo.Usable != ENABLE )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ cPartition = nPartition & 0x0F;
++
++ if ( nDevInfo->LBAInfo.CurrentMode != cPartition )
++ NAND_IO_LBA_ModeChange( nDevInfo, cPartition );
++
++ if ( nPartition == NAND_LBA_DATA_AREA )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.DTAreaSectorSize;
++ dwSectorAddrOffSet = 0;
++ }
++ else if ( nPartition == NAND_LBA_HIDDEN_AREA )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.HDAreaSectorSize;
++ dwSectorAddrOffSet = nDevInfo->LBAInfo.HDAreaAddrOffSet;
++ }
++ else if ( nPartition == NAND_LBA_MULTI_HIDDEN_AREA_0 )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.MHDAreaSectorSize[0];
++ dwSectorAddrOffSet = nDevInfo->LBAInfo.MHDAreaAddrOffSet[0];
++ }
++ else if ( nPartition == NAND_LBA_MDP )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.MDPSectorSize;
++ dwSectorAddrOffSet = 0;
++ }
++ else if ( nPartition == NAND_LBA_VFP )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.VFPSectorSize;
++ dwSectorAddrOffSet = 1;
++ }
++ else
++ {
++ nTotalSectorSize = 0;
++ dwSectorAddrOffSet = 0;
++ return ERR_NAND_IO_WRONG_PARAMETER;
++ }
++
++ // Set Area Clear Sector Address, Size
++ nSectorAddr = 0;
++
++ wFlagFirstSector = TRUE;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetCommCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ //NAND_IO_DisableWriteProtect();
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //######################################################
++ //# Get Info of Parameter
++ //######################################################
++ dwSectorAddr = nSectorAddr;
++ dwSectorAddr += dwSectorAddrOffSet;
++ dwTotalWriteSecSize = nTotalSectorSize;
++
++ if ( dwTotalWriteSecSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)dwTotalWriteSecSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount;
++
++ //######################################################
++ //# Write Total Sector
++ //######################################################
++ wOldProcessRate = 0xFFFF;
++ nWriteSectorSize = 0;
++ nProCessWriteSectorSize = 0;
++ // [ LCD ROUTINE ] ---------------------------------------------------------------------------------------
++ if ( NAND_IO_LBA_CallBackLcdDisplay )
++ NAND_IO_LBA_CallBackLcdDisplay( 0, 0x03, nTotalSectorSize );
++ //--------------------------------------------------------------------------------------------------------
++
++ if ( dwTotalWriteSecSize >= 0x10000 )
++ wOnceWriteSectorCount = 0; // 0x10000
++ else
++ wOnceWriteSectorCount = (U16)dwTotalWriteSecSize;
++
++ while ( dwTotalWriteSecSize )
++ {
++ if ( nWriteSectorSize == 0x10000 )
++ {
++ if ( dwTotalWriteSecSize >= 0x10000 )
++ wOnceWriteSectorCount = 0;
++ else
++ wOnceWriteSectorCount = (U16)dwTotalWriteSecSize;
++
++ nWriteSectorSize = 0;
++ wFlagFirstSector = TRUE;
++ }
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ if ( wFlagFirstSector == TRUE )
++ {
++ /* Write Sector Size & Sector Address */
++ pNFC->NFC_SADDR= ( wOnceWriteSectorCount & 0xFF ); // Write Sector Num : SC0
++ pNFC->NFC_SADDR= ( ( wOnceWriteSectorCount >> 8 ) & 0xFF ); // Write Sector Num : SC1
++ pNFC->NFC_SADDR= ( dwSectorAddr & 0xFF ); // Write Sector Addr: AD0
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 8 ) & 0xFF ); // Write Sector Addr: AD1
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 16 ) & 0xFF ); // Write Sector Addr: AD2
++ }
++
++ NAND_IO_SetWriteCycleTime();
++ /* Write Data to NAND FLASH */
++
++ res = NAND_IO_LBA_WriteDummyData( nDevInfo, wCurrPPSize );
++ if ( res != SUCCESS )
++ return res;
++
++ NAND_IO_SetCommCycleTime();
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Decrease Write Size */
++ dwTotalWriteSecSize -= wCurrPPSize;
++
++ /* Increase Buffer Address */
++ //nWriteBuffer += ( nDevInfo->LBAInfo.SectorCount << 9 );
++ dwSectorAddr += wCurrPPSize;
++ nWriteSectorSize += wCurrPPSize;
++
++ /* Count Next Page Size */
++ if ( dwTotalWriteSecSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)dwTotalWriteSecSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount;
++
++ if ( nDevInfo->LBAInfo.TransProtocol2 & NAND_PROT2_WRITE_TYPE_B )
++ wFlagFirstSector = FALSE;
++
++ wProcessRate = (U16)(( ( nProCessWriteSectorSize + 1 ) * 100 ) / ( nTotalSectorSize + 1 ));
++
++ if ( wOldProcessRate != wProcessRate )
++ {
++ // [ LCD ROUTINE ] ---------------------------------------------------------------------------------------
++ if ( NAND_IO_LBA_CallBackLcdDisplay )
++ NAND_IO_LBA_CallBackLcdDisplay( 0, NAND_LBA_CALLBACK_LCD_FORMAT_PROCESS, wProcessRate );
++ //--------------------------------------------------------------------------------------------------------
++
++ wOldProcessRate = wProcessRate;
++ }
++
++ nProCessWriteSectorSize += wCurrPPSize;
++ }
++
++ // [ LCD ROUTINE ] ---------------------------------------------------------------------------------------
++ if ( NAND_IO_LBA_CallBackLcdDisplay )
++ NAND_IO_LBA_CallBackLcdDisplay( 0, 0x05, 0 );
++ //--------------------------------------------------------------------------------------------------------
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xFBFB;
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* FORCE TO SET WP LOW */
++ //NAND_IO_EnableWriteProtect();
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ /* Cache Flush */
++ NAND_IO_LBA_CacheFlush( nDevInfo );
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_WriteSector( NAND_IO_DEVINFO *nDevInfo, U8 nPartition, U32 nSectorAddr, U16 nSecSize, U8 *nWriteBuffer )
++{
++ unsigned short int wCurrPPSize;
++ unsigned short int wFlagFirstSector;
++ unsigned long int dwSectorAddr;
++ unsigned long int dwSectorAddrOffSet;
++ unsigned long int dwTotalWriteSecSize;
++ unsigned long int nTotalSectorSize;
++ unsigned char cPartition;
++ unsigned char cSpareBuffer[16];
++ NAND_IO_ERROR res;
++
++ //######################################################
++ //# Check Parameter
++ //######################################################
++ if ( nDevInfo->LBAInfo.Usable != ENABLE )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ cPartition = nPartition & 0x0F;
++
++ if ( nDevInfo->LBAInfo.CurrentMode != cPartition )
++ NAND_IO_LBA_ModeChange( nDevInfo, cPartition );
++
++ if ( nPartition == NAND_LBA_DATA_AREA )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.DTAreaSectorSize;
++ dwSectorAddrOffSet = 0;
++ }
++ else if ( nPartition == NAND_LBA_HIDDEN_AREA )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.HDAreaSectorSize;
++ dwSectorAddrOffSet = nDevInfo->LBAInfo.HDAreaAddrOffSet;
++ }
++ else if ( nPartition == NAND_LBA_MULTI_HIDDEN_AREA_0 )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.MHDAreaSectorSize[0];
++ dwSectorAddrOffSet = nDevInfo->LBAInfo.MHDAreaAddrOffSet[0];
++ }
++ else if ( nPartition == NAND_LBA_MDP )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.MDPSectorSize;
++ dwSectorAddrOffSet = 0;
++ }
++ else if ( nPartition == NAND_LBA_VFP )
++ {
++ nTotalSectorSize = nDevInfo->LBAInfo.VFPSectorSize;
++ dwSectorAddrOffSet = 1;
++ }
++ else
++ {
++ nTotalSectorSize = 0;
++ dwSectorAddrOffSet = 0;
++ return ERR_NAND_IO_WRONG_PARAMETER;
++ }
++
++ if ( ( nSectorAddr + nSecSize ) > nTotalSectorSize )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ wFlagFirstSector = TRUE;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetCommCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ //NAND_IO_DisableWriteProtect();
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //######################################################
++ //# Get Info of Parameter
++ //######################################################
++ dwSectorAddr = nSectorAddr;
++ dwSectorAddr += dwSectorAddrOffSet;
++ dwTotalWriteSecSize = nSecSize;
++
++ if ( dwTotalWriteSecSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)dwTotalWriteSecSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount ;
++
++ //######################################################
++ //# Write Total Sector
++ //######################################################
++
++ while ( dwTotalWriteSecSize )
++ {
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ if ( wFlagFirstSector == TRUE )
++ {
++ /* Write Sector Size & Sector Address */
++ pNFC->NFC_SADDR= ( nSecSize & 0xFF ); // Write Sector Num : SC0
++ pNFC->NFC_SADDR= ( ( nSecSize >> 8 ) & 0xFF ); // Write Sector Num : SC1
++ pNFC->NFC_SADDR= ( dwSectorAddr & 0xFF ); // Write Sector Addr: AD0
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 8 ) & 0xFF ); // Write Sector Addr: AD1
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 16 ) & 0xFF ); // Write Sector Addr: AD2
++ }
++
++ NAND_IO_SetWriteCycleTime();
++ /* Write Data to NAND FLASH */
++ res = NAND_IO_LBA_WriteData( nDevInfo, wCurrPPSize, nWriteBuffer, cSpareBuffer );
++ if ( res != SUCCESS )
++ return res;
++
++ NAND_IO_SetCommCycleTime();
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++
++ /* Decrease Write Size */
++ dwTotalWriteSecSize -= wCurrPPSize;
++
++ /* Increase Buffer Address */
++ nWriteBuffer += ( nDevInfo->LBAInfo.SectorCount << 9 );
++
++ /* Count Next Page Size */
++ if ( dwTotalWriteSecSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)dwTotalWriteSecSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount;
++
++ if ( nDevInfo->LBAInfo.TransProtocol2 & NAND_PROT2_WRITE_TYPE_B )
++ wFlagFirstSector = FALSE;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++ }
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xFBFB;
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* FORCE TO SET WP LOW */
++ //NAND_IO_EnableWriteProtect();
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ /* Cache Flush */
++// NAND_IO_LBA_CacheFlush( nDevInfo );
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_VFPInitArea( NAND_IO_DEVINFO *nDevInfo )
++{
++ NAND_IO_ERROR res;
++
++ res = NAND_IO_LBA_ScanHeaderOfVFP( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ res = NAND_IO_LBA_MakeHeaderOfVFP( nDevInfo );
++ if ( res != SUCCESS )
++ return res;
++
++ res = NAND_IO_LBA_ScanHeaderOfVFP( nDevInfo );
++ if ( res != SUCCESS )
++ return res;
++ }
++
++ return res;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_ScanHeaderOfVFP( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int i;
++ unsigned short int wCurrPPSize;
++ unsigned short int wFlagCheckSize;
++ unsigned short int wFlagFirstSector;
++ unsigned long int nHeaderInfoSize;
++ unsigned long int nHeaderAddress;
++ unsigned long int dwSectorAddr;
++ unsigned long int nTotalSectorSize;
++ unsigned short int nInfoOffSet;
++ unsigned int *pPageDW;
++ unsigned char cPageBuffer[512];
++ unsigned char cSpareBuffer[16];
++ unsigned long int dwTotalSectorSize;
++ NAND_IO_ERROR res;
++
++ //######################################################
++ //# Check Parameter
++ //######################################################
++ NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_VFP );
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetCommCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_DisableWriteProtect();
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ wFlagFirstSector = TRUE;
++ nInfoOffSet = 32;
++ nHeaderInfoSize = 1;
++ nHeaderAddress = 0;
++
++ //######################################################
++ //# Get Info of Parameter
++ //######################################################
++ dwSectorAddr = nHeaderAddress;
++ nTotalSectorSize = nHeaderInfoSize;
++
++ if ( nTotalSectorSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)nTotalSectorSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount ;
++
++ //######################################################
++ //# Write Total Sector
++ //######################################################
++ while ( nTotalSectorSize )
++ {
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ if ( wFlagFirstSector == TRUE )
++ {
++ /* Write Sector Size & Sector Address */
++ pNFC->NFC_SADDR= ( nHeaderInfoSize & 0xFF ); // Write Sector Num : SC0
++ pNFC->NFC_SADDR= ( ( nHeaderInfoSize >> 8 ) & 0xFF ); // Write Sector Num : SC1
++ pNFC->NFC_SADDR= ( dwSectorAddr & 0xFF ); // Write Sector Addr: AD0
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 8 ) & 0xFF ); // Write Sector Addr: AD1
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 16 ) & 0xFF ); // Write Sector Addr: AD2
++ }
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ NAND_IO_SetReadCycleTime();
++ /* Write Data to NAND FLASH */
++ res = NAND_IO_LBA_ReadData( nDevInfo, wCurrPPSize, cPageBuffer, cSpareBuffer );
++ if ( res != SUCCESS )
++ return res;
++
++ NAND_IO_SetCommCycleTime();
++
++ /* Decrease Write Size */
++ nTotalSectorSize -= wCurrPPSize;
++
++ /* Increase Buffer Address */
++ //cPageBuffer += ( nDevInfo->LBAInfo.SectorCount << 9 );
++
++ /* Count Next Page Size */
++ if ( nTotalSectorSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)nTotalSectorSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount;
++
++ if ( nDevInfo->LBAInfo.TransProtocol2 & NAND_PROT2_WRITE_TYPE_B )
++ wFlagFirstSector = FALSE;
++ }
++
++ /* FORCE TO SET WP LOW */
++ NAND_IO_EnableWriteProtect();
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ wFlagCheckSize = FALSE;
++
++ // Signature
++ if ( !memcmp( cPageBuffer, (void *)NAND_LBA_VFP_AREA_Signature, sizeof(NAND_LBA_VFP_AREA_Signature) ) )
++ {
++ pPageDW = (U32 *)&cPageBuffer[nInfoOffSet];
++ //==============================================
++ // VFP Size [ 4Byte ] 0
++ // MDP Size [ 4Byte ] 1
++ // Hidden Size [ 4Byte ] 2
++ // Multi-Hidden Num [ 4Byte ] 3
++ // Multi-Hidden Size[ 4Byte ] 4~10
++ //==============================================
++ dwTotalSectorSize = 0;
++
++ if ( nDevInfo->LBAInfo.VFPSectorSize == pPageDW[ENUM_LBA_VFP_SECTOR_SIZE] )
++ {
++ if ( nDevInfo->LBAInfo.FlagOfChangeTotalSectorSize == ENABLE )
++ {
++ if ( ( nDevInfo->LBAInfo.MDPSectorSize == pPageDW[ENUM_LBA_MDP_SECTOR_SIZE] ) &&
++ ( nDevInfo->LBAInfo.HDAreaSectorSize == pPageDW[ENUM_LBA_HIDDEN_SECTOR_SIZE] ) &&
++ ( nDevInfo->LBAInfo.MHDAreaNums == pPageDW[ENUM_LBA_MULTI_HIDDEN_NUM] ) )
++ {
++ wFlagCheckSize = TRUE;
++
++ if ( nDevInfo->LBAInfo.MHDAreaNums > NAND_LBA_MAX_SUPPORT_MHD_AREA_NUM )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ for ( i = 0; i < nDevInfo->LBAInfo.MHDAreaNums; ++i )
++ {
++ if ( nDevInfo->LBAInfo.MHDAreaSectorSize[i] != pPageDW[ENUM_LBA_MULTI_HIDDEN_SIZE_0 + i] )
++ wFlagCheckSize = FALSE;
++ }
++ }
++ else
++ wFlagCheckSize = FALSE;
++ }
++ else // NAND VFP Info Read Only
++ {
++ nDevInfo->LBAInfo.HDAreaSectorSize = pPageDW[ENUM_LBA_HIDDEN_SECTOR_SIZE];
++ nDevInfo->LBAInfo.MHDAreaNums = pPageDW[ENUM_LBA_MULTI_HIDDEN_NUM];
++
++ if ( nDevInfo->LBAInfo.MHDAreaNums > NAND_LBA_MAX_SUPPORT_MHD_AREA_NUM )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ for ( i = 0; i < nDevInfo->LBAInfo.MHDAreaNums; ++i )
++ nDevInfo->LBAInfo.MHDAreaSectorSize[i] = pPageDW[ENUM_LBA_MULTI_HIDDEN_SIZE_0 + i];
++
++ wFlagCheckSize = TRUE;
++ }
++ }
++ else
++ {
++ NAND_IO_LBA_VFPChangeSectorSize( nDevInfo, nDevInfo->LBAInfo.VFPSectorSize );
++ }
++ }
++
++ dwTotalSectorSize = nDevInfo->LBAInfo.HDAreaSectorSize;
++ for ( i = 0; i < nDevInfo->LBAInfo.MHDAreaNums; ++i )
++ dwTotalSectorSize += nDevInfo->LBAInfo.MHDAreaSectorSize[i];
++
++ if ( dwTotalSectorSize > nDevInfo->LBAInfo.MDPSectorSize )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ if ( wFlagCheckSize == FALSE )
++ return ERR_NAND_IO_NOT_EXIST_LBA_HEADBLOCK;
++
++ //==================================
++ // Area Address Offset Setting
++ //==================================
++ // Data Area Address Offset = 0
++ // 0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MDP Size
++ // [ Data Area | Multi Hidden[n], Multi Hidden[n-1], Multi Hidden[0] | Hidden Area ]
++
++ nDevInfo->LBAInfo.DTAreaSectorSize = nDevInfo->LBAInfo.MDPSectorSize;
++
++ nDevInfo->LBAInfo.DTAreaSectorSize -= nDevInfo->LBAInfo.HDAreaSectorSize;
++ nDevInfo->LBAInfo.HDAreaAddrOffSet = nDevInfo->LBAInfo.DTAreaSectorSize;
++
++ for ( i = 0; i < nDevInfo->LBAInfo.MHDAreaNums; ++i )
++ {
++ nDevInfo->LBAInfo.DTAreaSectorSize -= nDevInfo->LBAInfo.MHDAreaSectorSize[i];
++ nDevInfo->LBAInfo.MHDAreaAddrOffSet[i] = nDevInfo->LBAInfo.DTAreaSectorSize;
++ }
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_MakeHeaderOfVFP( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int i;
++ unsigned short int wCurrPPSize;
++ unsigned short int wFlagFirstSector;
++ unsigned long int nHeaderInfoSize;
++ unsigned long int nHeaderAddress;
++ unsigned long int dwSectorAddr;
++ unsigned long int nTotalSectorSize;
++ unsigned short int nInfoOffSet;
++ unsigned int *pPageDW;
++ unsigned char cPageBuffer[512];
++ unsigned char cSpareBuffer[16];
++ NAND_IO_ERROR res;
++
++ //######################################################
++ //# Check Parameter
++ //######################################################
++ NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_VFP );
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetCommCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_DisableWriteProtect();
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++ wFlagFirstSector = TRUE;
++ nInfoOffSet = 32;
++ nHeaderInfoSize = 1;
++ nHeaderAddress = 0;
++
++ //==============================================
++ // Hidden Signature [ 32Byte ]
++ // VFP Size [ 4Byte ] 0
++ // MDP Size [ 4Byte ] 1
++ // Hidden Size [ 4Byte ] 2
++ // Multi-Hidden Num [ 4Byte ] 3
++ // Multi-Hidden Size[ 4Byte ] 4~10
++ //==============================================
++
++ // Page Clear
++ memset( (void*)cPageBuffer, 0xFF, 512 );
++
++ // Signature
++ memcpy( (void*)cPageBuffer, (void*)NAND_LBA_VFP_AREA_Signature, sizeof(NAND_LBA_VFP_AREA_Signature) );
++
++ pPageDW = (U32 *)&cPageBuffer[nInfoOffSet];
++
++ // VFP Size
++ pPageDW[ENUM_LBA_VFP_SECTOR_SIZE] = nDevInfo->LBAInfo.VFPSectorSize;
++
++ // MDP Size
++ pPageDW[ENUM_LBA_MDP_SECTOR_SIZE] = nDevInfo->LBAInfo.MDPSectorSize;
++
++ // Hidden Size
++ pPageDW[ENUM_LBA_HIDDEN_SECTOR_SIZE]= nDevInfo->LBAInfo.HDAreaSectorSize;
++
++ // Multi-Hidden Area Num
++ pPageDW[ENUM_LBA_MULTI_HIDDEN_NUM] = nDevInfo->LBAInfo.MHDAreaNums;
++
++ if ( nDevInfo->LBAInfo.MHDAreaNums > NAND_LBA_MAX_SUPPORT_MHD_AREA_NUM )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ // Multi-Hidden Area Size
++ for ( i = 0; i < nDevInfo->LBAInfo.MHDAreaNums; ++i )
++ pPageDW[ENUM_LBA_MULTI_HIDDEN_SIZE_0 + i] = nDevInfo->LBAInfo.MHDAreaSectorSize[i];
++
++ //######################################################
++ //# Get Info of Parameter
++ //######################################################
++ dwSectorAddr = nHeaderAddress;
++ nTotalSectorSize = nHeaderInfoSize;
++ wFlagFirstSector = TRUE;
++
++ if ( nTotalSectorSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)nTotalSectorSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount ;
++
++ while ( nTotalSectorSize )
++ {
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ if ( wFlagFirstSector == TRUE )
++ {
++ /* Write Sector Size & Sector Address */
++ pNFC->NFC_SADDR= ( nHeaderInfoSize & 0xFF ); // Write Sector Num : SC0
++ pNFC->NFC_SADDR= ( ( nHeaderInfoSize >> 8 ) & 0xFF ); // Write Sector Num : SC1
++ pNFC->NFC_SADDR= ( dwSectorAddr & 0xFF ); // Write Sector Addr: AD0
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 8 ) & 0xFF ); // Write Sector Addr: AD1
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 16 ) & 0xFF ); // Write Sector Addr: AD2
++ }
++
++ NAND_IO_SetWriteCycleTime();
++ /* Write Data to NAND FLASH */
++ res = NAND_IO_LBA_WriteData( nDevInfo, wCurrPPSize, cPageBuffer, cSpareBuffer );
++ if ( res != SUCCESS )
++ return res;
++
++ NAND_IO_SetCommCycleTime();
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++
++ /* Decrease Write Size */
++ nTotalSectorSize -= wCurrPPSize;
++
++ /* Increase Buffer Address */
++ //cPageBuffer += ( nDevInfo->LBAInfo.SectorCount << 9 );
++
++ /* Count Next Page Size */
++ if ( nTotalSectorSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)nTotalSectorSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount;
++
++ if ( nDevInfo->LBAInfo.TransProtocol2 & NAND_PROT2_WRITE_TYPE_B )
++ wFlagFirstSector = FALSE;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++ }
++
++ nDevInfo->LBAInfo.HDAreaAddrOffSet = nDevInfo->LBAInfo.MDPSectorSize - nDevInfo->LBAInfo.HDAreaSectorSize;
++ nDevInfo->LBAInfo.DTAreaSectorSize = nDevInfo->LBAInfo.MDPSectorSize - nDevInfo->LBAInfo.HDAreaSectorSize;
++
++ /* FORCE TO SET WP LOW */
++ NAND_IO_EnableWriteProtect();
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ NAND_IO_LBA_CacheFlush( nDevInfo );
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_MDPGetTotalSectorSize( NAND_IO_DEVINFO *nDevInfo, unsigned long int *rTotalSector )
++{
++ unsigned long int wTotalSector;
++ unsigned char nTemp;
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ pNFC->NFC_SADDR= 0xB0;
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Parallel Composition */
++ wTotalSector = (U8)( pNFC->NFC_SDATA & 0xFF );
++ wTotalSector |= ((U8)( pNFC->NFC_SDATA & 0xFF ) << 8 );
++ wTotalSector |= ((U8)( pNFC->NFC_SDATA & 0xFF ) << 16 );
++ wTotalSector |= ((U8)( pNFC->NFC_SDATA & 0xFF ) << 24 );
++// wTotalSector |= ((U8)( pNFC->NFC_SDATA & 0xFF ) << 32 );
++ nTemp = (U8)( pNFC->NFC_SDATA & 0xFF );
++
++ *rTotalSector = wTotalSector;
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_VFPGetTotalSectorSize( NAND_IO_DEVINFO *nDevInfo, U32 *rTotalSector )
++{
++ unsigned int dwTotalSector;
++
++ dwTotalSector = 0;
++ *rTotalSector = 0;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ pNFC->NFC_SADDR= 0xB5;
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Parallel Composition */
++ dwTotalSector = (U8)( pNFC->NFC_SDATA & 0xFF );
++ dwTotalSector |= ((U8)( pNFC->NFC_SDATA & 0xFF ) << 8 );
++
++ if ( dwTotalSector == 0 )
++ dwTotalSector = 0x10000;
++
++ *rTotalSector = dwTotalSector;
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_VFPChangeSectorSize( NAND_IO_DEVINFO *nDevInfo, U32 nTotalSector )
++{
++ unsigned int dwTotalSector;
++
++ //======================================================================================
++ //
++ // The available rage for the VFP size: [40][00]h(8 Mbyte) ~ [01][00][00]h(32 Mbyte)
++ // VFP AreaSize Min: 16,384 ~ Max: 65,536 sector / 512 sector resolution
++ //
++ // "VFP/MDP ratio = (+1)/(-2)" VFP increases by 1MB, the DMP decreases by 2MB.
++ //
++ //======================================================================================
++ if ( ( nTotalSector < 0x4000 ) || ( nTotalSector > 0x10000 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ /* VFP Size Change Command can only be executed in the VFP mode */
++ NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_VFP );
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus Witdh */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //==============================================
++ // Arrange Sector Resolution
++ //==============================================
++ dwTotalSector = ( ( nTotalSector + 511 ) >> 9 );
++ dwTotalSector = dwTotalSector << 9;
++
++ if ( ( dwTotalSector < 0x4000 ) || ( dwTotalSector > 0x10000 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //==============================================
++ // Set VFP Size
++ //==============================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ pNFC->NFC_SADDR= 0x22;
++
++ pNFC->NFC_SADDR= ( dwTotalSector & 0xFF ); // VFP_Size0: LSB
++ pNFC->NFC_SADDR= ( ( dwTotalSector >> 8 ) & 0xFF ); // VFP_Size1: MSB
++ pNFC->NFC_SADDR= ( 0xFF - ( dwTotalSector & 0xFF ) ); // Inversion of [VFP_Size0] for verification
++ pNFC->NFC_SADDR= ( 0xFF - ( ( dwTotalSector >> 8 ) & 0xFF ) ); // Inversion of [VFP_Size1] fot verification
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_SetTransferProtocol( NAND_IO_DEVINFO *nDevInfo, U8 nProtocol1, U8 nProtocol2 )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //==============================================
++ // Get Protocol 1
++ //==============================================
++ /* Command Partition Change to PNP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0xA2; // cmd
++ pNFC->NFC_SADDR= nProtocol1; // Parameter
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ //==============================================
++ // Get Protocol 2
++ //==============================================
++ /* Command Partition Change to PNP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0xA3; // cmd
++ pNFC->NFC_SADDR= nProtocol2; // Parameter
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_SetBootModeChange( NAND_IO_DEVINFO *nDevInfo, U8 nBootMode )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //==============================================
++ // Get Protocol 1
++ //==============================================
++ /* Command Partition Change to PNP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= nBootMode; // Parameter
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_SetRebootCmdChange( NAND_IO_DEVINFO *nDevInfo, U8 nRebootCmd )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //==============================================
++ // Get Protocol 1
++ //==============================================
++ /* Command Partition Change to PNP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= nRebootCmd; // Parameter
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_GetPersistentFunction( NAND_IO_DEVINFO *nDevInfo, U8 *rBootMode, U8 *rRebootCmd )
++{
++ unsigned char nParameter;
++
++ *rBootMode = 0;
++ *rRebootCmd = 0;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //==============================================
++ // Get Protocol 1
++ //==============================================
++ /* Command Partition Change to PNP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x99; // CMD
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ nParameter = (U8)( pNFC->NFC_SDATA & 0xFF );
++
++ *rBootMode = nParameter;
++
++ nParameter = (U8)( pNFC->NFC_SDATA & 0xFF );
++
++ *rRebootCmd = nParameter;
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_GetTransferProtocol( NAND_IO_DEVINFO *nDevInfo, U8 *rProtocol1, U8 *rProtocol2 )
++{
++ unsigned char nParameter;
++
++ *rProtocol1 = 0;
++ *rProtocol2 = 0;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //==============================================
++ // Get Protocol 1
++ //==============================================
++ /* Command Partition Change to PNP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0xB2; // cmd
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ nParameter = (U8)( pNFC->NFC_SDATA & 0xFF );
++
++ *rProtocol1 = nParameter;
++
++ //==============================================
++ // Get Protocol 2
++ //==============================================
++ /* Command Partition Change to PNP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0xB3; // cmd
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ nParameter = (U8)( pNFC->NFC_SDATA & 0xFF );
++
++ *rProtocol2 = nParameter;
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_GetBusyTime( NAND_IO_DEVINFO *nDevInfo, U8 *rBusyTime )
++{
++ unsigned char dwBusyTime;
++
++ dwBusyTime = 0;
++ *rBusyTime = 0;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ pNFC->NFC_SADDR= 0xB4;
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Parallel Composition */
++ dwBusyTime = (U8)( pNFC->NFC_SDATA & 0xFF );
++
++ *rBusyTime = dwBusyTime;
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_SetBusyTime( NAND_IO_DEVINFO *nDevInfo, U8 nBusyTime )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ pNFC->NFC_SADDR= nBusyTime;
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_GetBootMode( NAND_IO_DEVINFO *nDevInfo, U8 *rBootMode )
++{
++ unsigned char dwBootMode;
++
++ dwBootMode = 0;
++ *rBootMode = 0;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ pNFC->NFC_SADDR= 0x00;
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x99; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Parallel Composition */
++ dwBootMode = (U8)( pNFC->NFC_SDATA & 0xFF );
++
++ *rBootMode = dwBootMode;
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_PowerSaveMode( NAND_IO_DEVINFO *nDevInfo, int nOnOff )
++{
++ //Power Save Mode En,Disable
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ if ( nOnOff == ENABLE )
++ pNFC->NFC_SADDR= 0xBA;
++ else
++ pNFC->NFC_SADDR= 0xBB;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_HighSpeedMode( NAND_IO_DEVINFO *nDevInfo, int nOnOff )
++{
++ // High Speed Write Mode En,Disable
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ if ( nOnOff == ENABLE )
++ pNFC->NFC_SADDR= 0xBC;
++ else
++ pNFC->NFC_SADDR= 0xBD;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ if ( nOnOff == ENABLE )
++ nDevInfo->LBAInfo.HighSpeedMode = ENABLE;
++ else
++ nDevInfo->LBAInfo.HighSpeedMode = DISABLE;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_CacheFlush( NAND_IO_DEVINFO *nDevInfo )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nDevInfo->LBAInfo.CurrentMode == NAND_LBA_BCM )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0xF9; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++ }
++ else
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF9F9;
++ }
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_DeviceReboot( NAND_IO_DEVINFO *nDevInfo )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nDevInfo->LBAInfo.CurrentMode == NAND_LBA_BCM )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0xFD; // CMD
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ }
++ else
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xFDFD;
++ }
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_PNP;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_ReadID( NAND_IO_DEVINFO *nDevInfo, NAND_IO_DEVID *nDeviceCode )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x9292;
++ pNFC->NFC_SADDR = 0x0000; /* Address [ 0x00 ] */
++
++ /* Delay : tAR1[READID] Max 200nS */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++ //ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++
++ /* Parallel Composition */
++ nDeviceCode->Code[0] = (U16)( pNFC->NFC_SDATA & nDevInfo->CmdMask );
++ nDeviceCode->Code[1] = (U16)( pNFC->NFC_SDATA & nDevInfo->CmdMask );
++ nDeviceCode->Code[2] = (U16)( pNFC->NFC_SDATA & nDevInfo->CmdMask );
++ nDeviceCode->Code[3] = (U16)( pNFC->NFC_SDATA & nDevInfo->CmdMask );
++ nDeviceCode->Code[4] = (U16)( pNFC->NFC_SDATA & nDevInfo->CmdMask );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_Reset( NAND_IO_DEVINFO *nDevInfo )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xFFFF;
++ /* Delay : tAR1[READID] Max 200nS */
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xFDFD;
++ /* Delay : tAR1[READID] Max 200nS */
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_PNP;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_ModeChange( NAND_IO_DEVINFO *nDevInfo, int nMode )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nMode == NAND_LBA_PNP )
++ {
++ // Change to BCM
++ if ( ( nDevInfo->LBAInfo.CurrentMode == NAND_LBA_PNP ) || ( nDevInfo->LBAInfo.CurrentMode == NAND_LBA_BCM ) )
++ {
++ //==============================================
++ // Directly Enter BCM (Boot Code Maintenance)
++ //==============================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0xFC; // cmd
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++ }
++ else
++ {
++ /* Command Partition Change to BCM */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0xBF; // cmd
++ pNFC->NFC_SADDR= 0x00; // PassWord 0
++ pNFC->NFC_SADDR= 0x00; // PassWord 1
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++ }
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ // Exit from BCM
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0xFD; // cmd
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ }
++ else if ( nMode == NAND_LBA_BCM )
++ {
++ if ( ( nDevInfo->LBAInfo.CurrentMode == NAND_LBA_PNP ) || ( nDevInfo->LBAInfo.CurrentMode == NAND_LBA_BCM ) )
++ {
++ //==============================================
++ // Directly Enter BCM (Boot Code Maintenance)
++ //==============================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0xFC; // cmd
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++ }
++ else
++ {
++ /* Command Partition Change to BCM */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0xBF; // cmd
++ pNFC->NFC_SADDR= 0x00; // PassWord 0
++ pNFC->NFC_SADDR= 0x00; // PassWord 1
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++ }
++ }
++ else if ( nMode == NAND_LBA_MDP )
++ {
++ /* Command Partition Change to MDP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xFCFC;
++ }
++ else if ( nMode == NAND_LBA_VFP )
++ {
++ /* Command Partition Change to VFP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0xBE; // cmd
++ pNFC->NFC_SADDR= 0xFF; // PassWord 0
++ pNFC->NFC_SADDR= 0xFF; // PassWord 1
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++ }
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ /* Read Status */
++ NAND_IO_LBA_Read2Status( nDevInfo );
++ if ( nDevInfo->LBAInfo.CurrentMode != nMode )
++ return ERR_NAND_IO_FAILED_LBA_PARTITION_CHANGE;
++
++ if ( nMode == NAND_LBA_MDP )
++ {
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_MDP;
++ NAND_IO_LBA_MDPGetTotalSectorSize( nDevInfo, &nDevInfo->LBAInfo.CurrentSectorSize );
++ }
++ else if ( nMode == NAND_LBA_VFP )
++ {
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_VFP;
++ NAND_IO_LBA_VFPGetTotalSectorSize( nDevInfo, (U32 *)&nDevInfo->LBAInfo.CurrentSectorSize );
++ }
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_Read2Status( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int uStatus;
++ NAND_IO_ERROR res;
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //================================
++ // Command READ STATUS [ 0x70 ]
++ //================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7171;
++
++ // Delay : more than 200nS
++ NAND_IO_Delay();
++
++ //=============================================
++ // DATA BUS WIDTH Setting
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //================================
++ // Read IO Status
++ //================================
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uStatus = uStatus & 0x06;
++
++ if ( uStatus == NAND_LBA_PNP )
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_PNP;
++ else if ( uStatus == NAND_LBA_BCM )
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_BCM;
++ else if ( uStatus == NAND_LBA_VFP )
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_VFP;
++ else if ( uStatus == NAND_LBA_MDP )
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_MDP;
++ else
++ res = ERR_NAND_IO_FAILED_LBA_PARTITION_CHANGE;
++
++ if ( nDevInfo->LBAInfo.CurrentMode != NAND_LBA_PNP )
++ {
++ if ( uStatus & NAND_POWER_SAVE_ENABLE )
++ nDevInfo->LBAInfo.PowerSaveMode = ENABLE;
++ else
++ nDevInfo->LBAInfo.PowerSaveMode = DISABLE;
++
++ if ( uStatus & NAND_HIGH_SPEED_ENABLE )
++ nDevInfo->LBAInfo.HighSpeedMode = ENABLE;
++ else
++ nDevInfo->LBAInfo.HighSpeedMode = DISABLE;
++ }
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return res;
++}
++
++static __inline NAND_IO_ERROR NAND_IO_LBA_ReadData( NAND_IO_DEVINFO *nDevInfo, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0, *pSpareDW = 0;
++ unsigned char *pDataBuffer;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ if ( nReadPPSize > nDevInfo->LBAInfo.SectorCount )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Read Data as 512+16Bytes
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ //----------------------------------------------
++ // Read Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nReadPPSize; ++j )
++ {
++ /* Set Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Read 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++
++ /* Read 512 Data Area */
++ i = 128;
++ do {
++ if ( bAlignAddr )
++ {
++ *pPageDW = pNFC->NFC_WDATA;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ *pPageB = uDWordByte.BYTE[2];++pPageB;
++ *pPageB = uDWordByte.BYTE[3];++pPageB;
++ }
++ }while(--i);
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++
++ /* Disable DMA Ahead */
++ //IO_DMA_SetCTRL( IO_DMA_CH2, 0 );
++ //IO_INT_HwICLR = IO_INT_HwDMA_CH2;
++
++ /* Start DMA on NFC BUS */
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ (void*)pDataBuffer, 4, 0,
++ NAND_IO_DMA_READ, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)&pNFC->NFC_LDATA, 0, 0,
++ (void*)pDataBuffer, 4, 0,
++ NAND_IO_DMA_READ, 512 );
++ #endif
++
++ //if ( ISZERO(pDataBuffer,3) ) {
++ // #if defined(_WINCE_)
++ // memcpy( pDataBuffer, (void*)IO_NFC_BUFFER0_BASE, 512 );
++ // #elif defined(_LINUX_)
++ // #ifndef KERNEL_DRIVER
++ // memcpy(pDataBuffer, (void*)IO_NFC_BUFFER0_BASE, 512);
++ // #else
++ // memcpy(pDataBuffer, virtadr, 512);
++ // #endif
++ // #else
++ // fmemcpy16( pDataBuffer, (void*)IO_NFC_BUFFER0_BASE, 512 );
++ // #endif
++ //} else {
++ // #if defined(_WINCE_)
++ // memcpy( pDataBuffer, (void*)IO_NFC_BUFFER0_BASE, 512 );
++ // #elif defined(_LINUX_)
++ // #ifndef KERNEL_DRIVER
++ // memcpy(pDataBuffer, (void*)IO_NFC_BUFFER0_BASE, 512);
++ // #else
++ // memcpy(pDataBuffer, virtadr, 512);
++ // #endif
++ // #else
++ // memcpy( pDataBuffer, (void*)IO_NFC_BUFFER0_BASE, 512 );
++ // #endif
++ //}
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++ #endif
++ //####################################################
++ //####################################################
++ if ( nDevInfo->LBAInfo.DataTransferCheck == ENABLE )
++ {
++ /* Read 16Bytes spare data */
++ i = 4;
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ else
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ return res;
++}
++
++static __inline NAND_IO_ERROR NAND_IO_LBA_WriteData( NAND_IO_DEVINFO *nDevInfo, U16 nWritePPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0, *pSpareDW = 0;
++ unsigned char *pDataBuffer;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ if ( nWritePPSize > nDevInfo->LBAInfo.SectorCount )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Write Data as 528Bytes
++ //=========================================================================
++
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ //----------------------------------------------
++ // Write Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nWritePPSize; ++j )
++ {
++ /* Get Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_LDATA = *pPageDW;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Disable DMA Ahead */
++ //IO_DMA_SetCTRL( IO_DMA_CH2, 0 );
++ //IO_INT_HwICLR = IO_INT_HwDMA_CH2;
++
++ /* Prepare data */
++ //if (ISZERO( pDataBuffer, 3 )) {
++ // #if defined(_WINCE_)
++ // memcpy( (void*)IO_NFC_BUFFER0_BASE, pDataBuffer, 512 );
++ // #elif defined(_LINUX_)
++ // #ifndef KERNEL_DRIVER
++ // memcpy( (void*)IO_NFC_BUFFER0_BASE, pDataBuffer, 512 );
++ // #else
++ // memcpy( virtadr, pDataBuffer, 512 );
++ // #endif
++ // #else
++ // fmemcpy16( (void*)IO_NFC_BUFFER0_BASE, pDataBuffer, 512 );
++ // #endif
++ //} else {
++ // #if defined(_WINCE_)
++ // memcpy( (void*)IO_NFC_BUFFER0_BASE, pDataBuffer, 512 );
++ // #elif defined(_LINUX_)
++ // #ifndef KERNEL_DRIVER
++ // memcpy( (void*)IO_NFC_BUFFER0_BASE, pDataBuffer, 512 );
++ // #else
++ // memcpy( virtadr, pDataBuffer, 512 );
++ // #endif
++ // #else
++ // memcpy( (void*)IO_NFC_BUFFER0_BASE, pDataBuffer, 512 );
++ // #endif
++ //}
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)pDataBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)pDataBuffer, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++ #endif
++ //####################################################
++ //####################################################
++ if ( nDevInfo->LBAInfo.DataTransferCheck == ENABLE )
++ {
++ /* Write 16Bytes spare data */
++ i = 4;
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ else
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_LBA_WriteDummyData( NAND_IO_DEVINFO *nDevInfo, U16 nWritePPSize );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nWritePPSize =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_LBA_WriteDummyData( NAND_IO_DEVINFO *nDevInfo, U16 nWritePPSize )
++{
++ unsigned int i, j;
++ unsigned char nTempBuffer[512];
++ NAND_IO_ERROR res;
++
++ if ( nWritePPSize > nDevInfo->LBAInfo.SectorCount )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //----------------------------------------------
++ // Write Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nWritePPSize; ++j )
++ {
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++ pNFC->NFC_LDATA = 0xFFFFFFFF;
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Disable DMA Ahead */
++ //IO_DMA_SetCTRL( IO_DMA_CH2, 0 );
++ //IO_INT_HwICLR = IO_INT_HwDMA_CH2;
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)nTempBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)nTempBuffer, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ #endif
++ //####################################################
++ //####################################################
++ if ( nDevInfo->LBAInfo.DataTransferCheck == ENABLE )
++ {
++ /* Write 16Bytes spare data */
++ i = 4;
++ do {
++ pNFC->NFC_WDATA = 0xFFFFFFFF;
++ }while(--i);
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ return res;
++}
++
++#endif // WITHOUT_FILESYSTEM
++
++/* end of file */
+diff --git a/drivers/block/tcc/nand_io_v7.c b/drivers/block/tcc/nand_io_v7.c
+new file mode 100644
+index 0000000..19a5bee
+--- /dev/null
++++ b/drivers/block/tcc/nand_io_v7.c
+@@ -0,0 +1,15490 @@
++//=============================================================================
++//* FileName : Nand_io_v7.c
++//* Description :
++//=============================================================================
++//*
++//* TCC Version 1.0
++//* Copyright (c) Telechips, Inc.
++//* ALL RIGHTS RESERVED
++//*
++//=============================================================================
++#ifndef WITHOUT_FILESYSTEM
++
++#if defined(_LINUX_) || defined(_WINCE_)
++#include "IO_TCCXXX.h"
++#include "nand_io_v7.h"
++#else
++#include "main.h"
++#include "IO_TCCXXX.h"
++#include "nand_io_v7.h"
++#endif
++
++#if defined(_WINCE_)
++#if defined(USE_V_ADDRESS)
++#include "Tcc_ckc.h"
++#include "tcc_gpio.h"
++#else
++#include "Tca_ckc.h"
++#endif
++#include "bsp.h"
++#include "args.h"
++#elif defined(_LINUX_)
++#if defined(USE_V_ADDRESS)
++#include <mach/tca_ckc.h>
++#include <mach/irqs.h>
++#else
++#include "ckc.h"
++#endif
++#endif
++
++#if defined(TCC89XX) || defined(TCC92XX)
++#if defined(_LINUX_) || defined(_WINCE_)
++#include "TC_DRV.h"
++#else
++#include "TC_DRV.h"
++#endif
++#endif
++
++#if defined(_WINCE_)
++#include "stdlib.h"
++#endif
++
++//=============================================================================
++//
++// Version Signature
++//
++//=============================================================================
++#define NAND_IO_VERSION 'V','7','0','2','2'
++
++static const unsigned char NANDIO_Library_Version[] =
++{
++ SIGBYAHONG,
++ NAND_IO_SIGNATURE,
++ SIGN_OS,
++ SIGN_CHIPSET,
++ NAND_IO_VERSION,
++ NULL
++};
++
++#ifdef UARTCON_INCLUDE
++//#define NAND_IO_ECC_ERROR_LOG
++//#define NAND_IO_UART_MEASURE
++#endif
++
++#if defined(_LINUX_)
++#ifdef KERNEL_DRIVER
++#include <linux/kernel.h>
++#include <linux/string.h>
++struct dma_buf {
++ void *v_addr;
++ unsigned int dma_addr;
++ int buf_size;
++};
++extern struct dma_buf dma_t;
++#else
++#define DMA_ADDR (BSS_OFFSET - 0x00700000)
++#endif
++#else
++#ifdef _BOOT_LOADER_
++unsigned char *gpNandBuffer;
++#else
++extern unsigned char *gpNandBuffer;
++#endif
++#endif
++
++#if defined(_LINUX_)
++#define ASM_NOP { \
++ __asm__ __volatile__ ("nop"); \
++ __asm__ __volatile__ ("nop"); \
++ __asm__ __volatile__ ("nop"); \
++ __asm__ __volatile__ ("nop"); \
++ __asm__ __volatile__ ("nop"); \
++ __asm__ __volatile__ ("nop"); \
++}
++#elif defined(_WINCE_)
++volatile int __asm_nop_count = 0;
++#define ASM_NOP { __asm_nop_count++; }
++#else
++#define ASM_NOP { __asm{ NOP }; __asm{ NOP }; __asm{ NOP }; __asm{ NOP }; __asm{ NOP }; __asm{ NOP };}
++#endif
++
++#if defined(_WINCE_)
++#define NAND_IO_USE_DMA_ACCESS
++#elif defined(_LINUX_)
++ #ifdef KERNEL_DRIVER
++ #define NAND_IO_USE_DMA_ACCESS
++ #else
++#define NAND_IO_USE_DMA_ACCESS
++//#define NAND_IO_USE_MCU_ACCESS
++ #endif
++#else
++ #ifdef _BOOT_LOADER_
++ #define NAND_IO_USE_MCU_ACCESS
++ #else
++#define NAND_IO_USE_DMA_ACCESS
++#endif
++#endif
++
++#ifdef NAND_IO_USE_DMA_ACCESS
++#define NAND_IO_USE_DMA_DOUBLE_BUF
++#define NAND_IO_USE_DMA_DOUBLE_BUF_WRITE
++#endif
++
++//=============================================================================
++//*
++//*
++//* [ CONST DATA DEFINE ]
++//*
++//*
++//=============================================================================
++const NAND_IO_FEATURE TOSHIBA_NAND_DevInfo[] =
++{
++ //*=======================================================================================================================================================
++ //*[ DEVICE CODE ][ SIZE ][ Cycle ][ ATTRIBUTE ]
++ //*-------------------------------------------------------------------------------------------------------------------------------------------------------
++ //* 1st, 2nd, 3rd, 4th, 5th, 6th, PBpV,BBpZ, PpB, Page,Spare,Col,Low,Twc, Ws, Wp, Wh, Rs, Rp, Rh
++ //*=======================================================================================================================================================
++ // [ 32MB] TC58DVM82A1FT
++ { {{0x98, 0x75, 0x00, 0x00, 0x00, 0x00}}, 2048, 20, 32, 512, 16, 1, 2, 50, 0, 25, 15, 0, 25, 15, (A_08BIT|A_SLC |A_SMALL|S_NOR) },
++ // [ 64MB] TC58DVM92A1FT
++ { {{0x98, 0x76, 0x00, 0x00, 0x00, 0x00}}, 4096, 20, 32, 512, 16, 1, 3, 50, 0, 25, 15, 0, 25, 15, (A_08BIT|A_SLC |A_SMALL|S_NOR) },
++ // [ 64MB] TC58NWM9S3B
++ { {{0x98, 0xF0, 0x00, 0x00, 0x00, 0x00}}, 512, 10, 64, 2048, 64, 2, 2, 50, 0, 25, 15, 0, 25, 15, (A_08BIT|A_SLC |A_BIG |S_NOR) },
++ // [128MB] TC58DVG02A1FT
++ { {{0x98, 0x79, 0x00, 0x00, 0x00, 0x00}}, 8192, 20, 32, 512, 16, 1, 3, 50, 0, 25, 15, 0, 25, 15, (A_08BIT|A_SLC |A_SMALL|S_NOR) },
++ // [128MB] TC58NVG0S3AFT
++ { {{0x98, 0xF1, 0x00, 0x00, 0x00, 0x00}}, 1024, 20, 64, 2048, 64, 2, 2, 50, 0, 25, 15, 0, 25, 15, (A_08BIT|A_SLC |A_BIG |S_NOR) },
++ // [256MB] TH58NVG1S3AFT
++ { {{0x98, 0xDA, 0x00, 0x00, 0x00, 0x00}}, 2048, 20, 64, 2048, 64, 2, 3, 50, 0, 25, 15, 0, 25, 15, (A_08BIT|A_SLC |A_BIG |S_NOR) },
++ // [512MB] THGVN0G4D1DTG00
++ { {{0x98, 0xDC, 0x00, 0x15, 0x00, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 50, 0, 25, 15, 0, 35, 15, (A_08BIT|A_SLC |A_BIG |S_NOR|S_LBA) },
++ // [512MB] TH58NYG2S8C
++ { {{0x98, 0xBC, 0x91, 0xD5, 0x49, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 50, 0, 25, 15, 0, 35, 15, (A_16BIT|A_SLC |A_BIG |S_NOR) },
++ // [512MB] TH58NYG2S8E
++ { {{0x98, 0xBC, 0x90, 0x55, 0x76, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 50, 0, 25, 15, 0, 35, 15, (A_16BIT|A_SLC |A_BIG |S_NOR) },
++ // [512MB] TH58NVG2D4CTG00
++ { {{0x98, 0xDC, 0x84, 0xA5, 0x60, 0x00}}, 2048, 40, 128, 2048, 64, 2, 3, 50, 0, 25, 15, 0, 25, 15, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP2) },
++ // [512MB] TH58NVG2D4BFT00
++ { {{0x98, 0xDC, 0x84, 0xA5, 0x54, 0x00}}, 2048, 40, 128, 2048, 64, 2, 3, 50, 0, 25, 15, 0, 25, 15, (A_08BIT|A_MLC |A_BIG |S_NOR) },
++ // [ 1GB] TH58NVG3D4BFT00
++ { {{0x98, 0xD3, 0x85, 0xA5, 0x58, 0x00}}, 4096, 40, 128, 2048, 64, 2, 3, 50, 0, 25, 15, 0, 25, 15, (A_08BIT|A_MLC |A_BIG |S_NOR) },
++ // [ 1GB] TC58NVG3D4CTG00
++ { {{0x98, 0xD3, 0x84, 0xA5, 0x66, 0x00}}, 4096, 40, 128, 2048, 64, 2, 3, 30, 0, 20, 10, 0, 20, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 2GB] TH58NVG4D4CFT00 [ 4GB] TH58NVG5D4CTG20
++ { {{0x98, 0xD5, 0x85, 0xA5, 0x00, 0x00}}, 8192, 40, 128, 2048, 64, 2, 3, 30, 0, 20, 10, 0, 20, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 1GB] TH58NVG3D1DTG00 // 4k Page
++ { {{0x98, 0xD3, 0x94, 0xBA, 0x64, 0x00}}, 2048, 40, 128, 4096, 218, 2, 3, 30, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP) },
++ // [ 2GB] TH58NVG4D1DTG00 [ 4GB] TH58NVG5D1DTG20
++ { {{0x98, 0xD5, 0x94, 0x00, 0x00, 0x00}}, 4096, 40, 128, 4096, 218, 2, 3, 30, 0, 20, 10, 0, 15, 15, (A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP) },
++ // [ 8GB] TH58NVG6D1DTG20 // 4k Page
++ { {{0x98, 0xD7, 0x00, 0x00, 0x00, 0x00}}, 8192, 40, 128, 4096, 218, 2, 3, 30, 0, 20, 10, 0, 15, 15, (A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP) }
++};
++
++const NAND_IO_FEATURE TOSHIBA_LBA_NAND_DevInfo[] =
++{
++ //*=======================================================================================================================================================
++ //*[ DEVICE CODE ][ SIZE ][ Cycle ][ ATTRIBUTE ]
++ //*-------------------------------------------------------------------------------------------------------------------------------------------------------
++ //* 1st, 2nd, 3rd, 4th, 5th, 6th, PBpV,BBpZ, PpB, Page,Spare,Col,Low,Twc, Ws, Wp, Wh, Rs, Rp, Rh
++ //*=======================================================================================================================================================
++ // [ 2GB] THGVN0G4D1DTG00
++ { {{0x98, 0x21, 0x01, 0x55, 0xAA, 0x00}}, 8192, 40, 128, 4096, 218, 2, 3, 30, 0, 20, 10, 0, 15, 15, (A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP) },
++ // [ 8GB] THGVN1G6D4ELA02
++ { {{0x98, 0x21, 0x03, 0x55, 0xAA, 0x00}}, 8192, 40, 128, 4096, 218, 2, 3, 30, 0, 20, 10, 0, 15, 15, (A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP) },
++ // [ 16GB] THGVN1G7D8ELA09
++ { {{0x98, 0x21, 0x04, 0x55, 0xAA, 0x00}}, 8192, 40, 128, 4096, 218, 2, 3, 30, 0, 20, 10, 0, 15, 15, (A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP) }
++};
++
++const NAND_IO_FEATURE HYNIX_NAND_DevInfo[] =
++{
++ //*=======================================================================================================================================================
++ //*[ DEVICE CODE ][ SIZE ][ Cycle ][ ATTRIBUTE ]
++ //*-------------------------------------------------------------------------------------------------------------------------------------------------------
++ //* 1st, 2nd, 3rd, 4th, 5th, 6th, PBpV,BBpZ, PpB, Page,Spare,Col,Low,Twc, Ws, Wp, Wh, Rs, Rp, Rh
++ //*=======================================================================================================================================================
++ // [ 32MB] HY27US08561M
++ { {{0xAD, 0x75, 0x00, 0x00, 0x00, 0x00}}, 2048, 20, 32, 512, 16, 1, 2, 50, 0, 35, 15, 0, 35, 15, (A_08BIT|A_SLC |A_SMALL|S_NOR|S_CB) },
++ // [ 64MB] HY27US08121M
++ { {{0xAD, 0x76, 0x00, 0x00, 0x00, 0x00}}, 4096, 20, 32, 512, 16, 1, 3, 60, 0, 40, 20, 0, 40, 20, (A_08BIT|A_SLC |A_SMALL|S_NOR|S_CB) },
++ // [ 64MB] HY27SS16122A
++ { {{0xAD, 0x46, 0xAD, 0x46, 0xAD, 0x00}}, 4096, 20, 32, 512, 16, 1, 3, 60, 0, 40, 20, 0, 50, 20, (A_16BIT|A_SLC |A_SMALL|S_NOR|S_CB) },
++ // [128MB] HY27UA081G1M
++ { {{0xAD, 0x79, 0x00, 0x00, 0x00, 0x00}}, 8192, 20, 32, 512, 16, 1, 3, 60, 0, 40, 15, 0, 40, 15, (A_08BIT|A_SLC |A_SMALL|S_NOR|S_CB) },
++ // [128MB] HY27UF081G2M, HY27UF081G2A
++ { {{0xAD, 0xF1, 0x00, 0x00, 0x00, 0x00}}, 1024, 20, 64, 2048, 64, 2, 2, 50, 0, 35, 20, 0, 35, 20, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP ) },
++ // [256MB] HY27UF082G2M, HY27UG082G2M
++ { {{0xAD, 0xDA, 0x80, 0x15, 0x00, 0x00}}, 2048, 20, 64, 2048, 64, 2, 3, 50, 0, 35, 20, 0, 35, 20, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP) },
++ // [256MB] HY27UF082G2A
++ { {{0xAD, 0xDA, 0x80, 0x1D, 0x00, 0x00}}, 2048, 20, 64, 2048, 64, 2, 3, 50, 0, 35, 20, 0, 35, 20, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP ) },
++ // [256MB] HY27UF082G2B
++ { {{0xAD, 0xDA, 0x10, 0x95, 0x44, 0x00}}, 2048, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_SLC |A_BIG |S_NOR|S_MP) },
++ // [512MB] HY27UF084G2M
++ { {{0xAD, 0xDC, 0x80, 0x95, 0x00, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 30, 0, 20, 10, 0, 20, 10, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP) },
++ // [512MB] HY27UF084G2B
++ { {{0xAD, 0xDC, 0x10, 0x95, 0x00, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_MP) },
++ // [512MB] HY27UG084G2M, HY27UH084G2M
++ { {{0xAD, 0xDC, 0x80, 0x15, 0x00, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 60, 0, 35, 20, 0, 35, 20, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP) },
++ // [512MB] HY27UT084G2M
++ { {{0xAD, 0xDC, 0x84, 0x25, 0x00, 0x00}}, 2048, 40, 128, 2048, 64, 2, 3, 50, 0, 35, 15, 0, 35, 15, (A_08BIT|A_MLC |A_BIG |S_NOR) },
++ // [512MB] HY27UT084G2A
++ { {{0xAD, 0xDC, 0x14, 0xA5, 0x24, 0x00}}, 2048, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [512MB] H8BCS0UN0MCR
++ { {{0xAD, 0xBC, 0x10, 0x55, 0x54, 0x00}}, 2048, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 1GB] HY27UH088G2M
++ { {{0xAD, 0xD3, 0x80, 0x15, 0x00, 0x00}}, 8192, 20, 64, 2048, 64, 2, 3, 60, 0, 35, 20, 0, 35, 20, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP) },
++ // [ 1GB] HY27UG088G2M [ 2GB] HY27UH08AG5M
++ { {{0xAD, 0xD3, 0xC1, 0x95, 0x00, 0x00}}, 8192, 20, 64, 2048, 64, 2, 3, 30, 0, 20, 10, 0, 20, 10, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP) },
++ // [ 2GB] HY27UH08AG5B
++ { {{0xAD, 0xD3, 0x51, 0x95, 0x58, 0x00}}, 8192, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_SLC |A_BIG |S_NOR|S_MP) },
++ // [ 1GB] H27U8G8F2M
++ { {{0xAD, 0xD3, 0x10, 0xA6, 0x34, 0x00}}, 4096, 20, 64, 4096, 128, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_SLC |A_BIG |S_NOR|S_MP) },
++ // [ 1GB] HY27UU088G2M
++ { {{0xAD, 0xD3, 0x85, 0x25, 0x00, 0x00}}, 4096, 40, 128, 2048, 64, 2, 3, 50, 0, 35, 15, 0, 35, 15, (A_08BIT|A_MLC |A_BIG |S_NOR) },
++ // [ 1GB] HY27UT088G2M [ 2GB] HY27UU08AG5M
++ { {{0xAD, 0xD3, 0x14, 0xA5, 0x64, 0xAD}}, 4096, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 1GB] HY27UT088G2A
++ { {{0xAD, 0xD3, 0x14, 0xA5, 0x34, 0x00}}, 4096, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 4GB] HY27UV08BG5M [ 8GB] HY27UW08CGFM
++ { {{0xAD, 0xD5, 0x55, 0xA5, 0x68, 0x00}}, 8192, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 4GB] HY27UV08BG5A
++ { {{0xAD, 0xD5, 0x55, 0xA5, 0x38, 0x00}}, 8192, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 2GB] HY27UAG8T2MTR
++ { {{0xAD, 0xD5, 0x14, 0xB6, 0x44, 0x00}}, 4096, 25, 128, 4096, 128, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 8GB] HY27UCG8V5MTR
++ { {{0xAD, 0xD7, 0x55, 0xB6, 0x48, 0x00}}, 8192, 25, 128, 4096, 128, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 4GB] HY27UBG8U5A
++ { {{0xAD, 0xD5, 0x94, 0x25, 0x44, 0x41}}, 4096, 25, 128, 4096, 224, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC_12BIT|A_BIG |S_NOR|S_MCP) },
++ // [ 8GB] HY27UCG8V5A
++ { {{0xAD, 0xD7, 0x95, 0x25, 0x48, 0x41}}, 8192, 25, 128, 4096, 224, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC_12BIT|A_BIG |S_NOR|S_MCP) }
++};
++
++const NAND_IO_FEATURE ST_NAND_DevInfo[] =
++{
++ //*=======================================================================================================================================================
++ //*[ DEVICE CODE ][ SIZE ][ Cycle ][ ATTRIBUTE ]
++ //*-------------------------------------------------------------------------------------------------------------------------------------------------------
++ //* 1st, 2nd, 3rd, 4th, 5th, 6th, PBpV,BBpZ, PpB, Page,Spare,Col,Low,Twc, Ws, Wp, Wh, Rs, Rp, Rh
++ //*=======================================================================================================================================================
++ // [ 32MB] NAND256W3A
++ { {{0x20, 0x75, 0x00, 0x00, 0x00, 0x00}}, 2048, 20, 32, 512, 16, 1, 2, 50, 0, 35, 15, 0, 35, 15, (A_08BIT|A_SLC |A_SMALL|S_NOR) },
++ // [ 64MB] NAND512W3A
++ { {{0x20, 0x76, 0x00, 0x00, 0x00, 0x00}}, 4096, 20, 32, 512, 16, 1, 3, 50, 0, 35, 15, 0, 35, 15, (A_08BIT|A_SLC |A_SMALL|S_NOR) },
++ // [128MB] NAND01GW3A
++ { {{0x20, 0x79, 0x00, 0x00, 0x00, 0x00}}, 8192, 20, 32, 512, 16, 1, 3, 50, 0, 35, 20, 0, 25, 20, (A_08BIT|A_SLC |A_SMALL|S_NOR|S_CB|S_CP) },
++ // [128MB] NAND01GW3B2C
++ { {{0x20, 0xF1, 0x00, 0x1D, 0x00, 0x00}}, 1024, 20, 64, 2048, 64, 2, 2, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_SLC |A_BIG |S_NOR) },
++ // [128MB] NAND01GW3B
++ { {{0x20, 0xF1, 0x00, 0x00, 0x00, 0x00}}, 1024, 20, 64, 2048, 64, 2, 2, 50, 0, 35, 20, 0, 35, 20, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP) },
++ // [256MB] NAND02GW3B2D
++ { {{0x20, 0xDA, 0x10, 0x95, 0x44, 0x00}}, 2048, 20, 64, 2048, 64, 2, 3, 45, 0, 25, 20, 0, 25, 20, (A_08BIT|A_SLC |A_BIG |S_NOR|S_MP) },
++ // [256MB] NAND02GW3B
++ { {{0x20, 0xDA, 0x00, 0x00, 0x00, 0x00}}, 2048, 20, 64, 2048, 64, 2, 3, 50, 0, 35, 20, 0, 35, 20, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP) },
++ // [256MB] NAND02GR4B2DDI6
++ { {{0x20, 0xBA, 0x10, 0x55, 0x44, 0x00}}, 2048, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_16BIT|A_SLC |A_BIG |S_NOR|S_MP) },
++ // [512MB] NAND04GR4B2DDI6
++ { {{0x20, 0xBC, 0x10, 0x55, 0x54, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 45, 0, 30, 15, 0, 30, 15, (A_16BIT|A_SLC |A_BIG |S_NOR|S_MP) },
++ // [512MB] NAND04GW3B2D
++ { {{0x20, 0xDC, 0x10, 0x95, 0x54, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_SLC |A_BIG |S_NOR|S_MP) },
++ // [512MB] NAND04GW3B
++ { {{0x20, 0xDC, 0x80, 0x95, 0x00, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 50, 0, 35, 20, 0, 35, 20, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP) },
++ // [512MB] NAND04GW3C2A
++ { {{0x20, 0xDC, 0x84, 0x25, 0x00, 0x00}}, 2048, 40, 128, 2048, 64, 2, 3, 60, 0, 40, 20, 0, 40, 20, (A_08BIT|A_MLC |A_BIG |S_NOR) },
++ // [ 1GB] NAND08GW3B2CN6
++ { {{0x20, 0xD3, 0x51, 0x95, 0x58, 0x00}}, 8192, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_SLC |A_BIG |S_NOR|S_MP |S_IL) },
++ // [ 1GB] NAND08GW3B
++ { {{0x20, 0xD3, 0x85, 0x25, 0x00, 0x00}}, 8192, 20, 64, 2048, 64, 2, 3, 50, 0, 35, 15, 0, 35, 15, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP) },
++ // [ 1GB] NAND08GW3C2A, [ 2GB] NAND16GW3C4A
++ { {{0x20, 0xD3, 0x14, 0xA5, 0x00, 0x00}}, 4096, 20, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) }
++};
++
++const NAND_IO_FEATURE SAMSUNG_NAND_DevInfo[] =
++{
++ //*=======================================================================================================================================================
++ //*[ DEVICE CODE ][ SIZE ][ Cycle ][ ATTRIBUTE ]
++ //*-------------------------------------------------------------------------------------------------------------------------------------------------------
++ //* 1st, 2nd, 3rd, 4th, 5th, 6th, PBpV,BBpZ, PpB, Page,Spare,Col,Low,Twc, Ws, Wp, Wh, Rs, Rp, Rh
++ //*=======================================================================================================================================================
++ // [ 32MB] K9F5608U0B/C/D ~TEST(C) ~TEST(D)
++ { {{0xEC, 0x75, 0x00, 0x00, 0x00, 0x00}}, 2048, 20, 32, 512, 16, 1, 2, 50, 0, 35, 15, 0, 35, 15, (A_08BIT|A_SLC |A_SMALL|S_NOR|S_CB) },
++ // [ 64MB] K9F1208U0M/A/B
++ { {{0xEC, 0x76, 0xA5, 0xC0, 0x00, 0x00}}, 4096, 20, 32, 512, 16, 1, 3, 50, 0, 35, 15, 0, 35, 15, (A_08BIT|A_SLC |A_SMALL|S_NOR|S_CB) },
++ // [ 64MB] K9F1208U0C: ~TEST(C) WC: 42 WP: 21 WH: 15
++ { {{0xEC, 0x76, 0x5A, 0x3F, 0x00, 0x00}}, 4096, 20, 32, 512, 16, 1, 3, 50, 0, 35, 15, 0, 35, 15, (A_08BIT|A_SLC |A_SMALL|S_NOR) },
++ // [128MB] K9K1G08U0M/A/B: ~TEST(B)
++ { {{0xEC, 0x79, 0xA5, 0xC0, 0x00, 0x00}}, 8192, 20, 32, 512, 16, 1, 3, 50, 0, 35, 15, 0, 35, 15, (A_08BIT|A_SLC |A_SMALL|S_NOR|S_CB) },
++ // [128MB] K9F1G08U0M,A
++ { {{0xEC, 0xF1, 0x80, 0x15, 0x40, 0x00}}, 1024, 20, 64, 2048, 64, 2, 2, 50, 0, 35, 15, 0, 35, 15, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP) },
++ // [128MB] K9F1G08U0C K9F1G08U0B[ Twc:50 Ws: 0 Wp: 35 Wh: 15]
++ { {{0xEC, 0xF1, 0x00, 0x95, 0x40, 0x00}}, 1024, 20, 64, 2048, 64, 2, 2, 50, 0, 35, 15, 0, 35, 15, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB) },
++ // [256MB] KBE00S00AB MCP MEMORY - Supply Voltage: Vcc 2.5 ~ 2.9
++ { {{0xEC, 0x71, 0x5A, 0x3F, 0x00, 0x00}},16384, 20, 32, 512, 16, 1, 3, 50, 0, 35, 15, 0, 35, 15, (A_08BIT|A_SLC |A_SMALL|S_NOR) },
++ // [256MB] K9F2G08U0M, K9K2G08U0M/A ~TEST(A)
++ { {{0xEC, 0xDA, 0x00, 0x15, 0x00, 0x00}}, 2048, 20, 64, 2048, 64, 2, 3, 50, 0, 35, 15, 0, 35, 15, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP) },
++ // [256MB] K9F2G08U0A
++ { {{0xEC, 0xDA, 0x10, 0x95, 0x44, 0x00}}, 2048, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_SLC |A_BIG |S_NOR|S_MP) },
++ // [512MB] K524G2GACB (mddr MCP) YKG038QX
++ { {{0xEC, 0xBC, 0x00, 0x55, 0x54, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 40, 0, 21, 10, 0, 21, 10, (A_16BIT|A_SLC |A_BIG |S_NOR) },
++ // [512MB] K524G2GACB (mddr MCP) YKG040A3
++ { {{0xEC, 0xBC, 0x00, 0x55, 0x56, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 40, 0, 21, 10, 0, 21, 10, (A_16BIT|A_SLC |A_BIG |S_NOR) },
++ // [512MB] K9K4G08U0M
++ { {{0xEC, 0xDC, 0xC1, 0x15, 0x00, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 30, 0, 20, 10, 0, 20, 10, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP) },
++ // [512MB] K9F4G08U0M
++ { {{0xEC, 0xDC, 0x10, 0x95, 0x00, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB) },
++ // [256MB] K9G2G08U0M
++ { {{0xEC, 0xDA, 0x14, 0x25, 0x44, 0x00}}, 1024, 25, 128, 2048, 64, 2, 3, 30, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [512MB] K9G4G08U0M/A [ 1GB] K9L8G08U1M
++ { {{0xEC, 0xDC, 0x14, 0x25, 0x54, 0x00}}, 2048, 40, 128, 2048, 64, 2, 3, 30, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [512MB] K9G4G08U0B
++ { {{0xEC, 0xDC, 0x14, 0xA5, 0x54, 0x00}}, 2048, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 1GB] K9K8G08UOM [ 2GB] K9WAG08U1M
++ { {{0xEC, 0xD3, 0x51, 0x95, 0x00, 0x00}}, 8192, 20, 64, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB) },
++ // [ 1GB] K9L8G08UOM [ 2GB] K9HAG08U1M
++ { {{0xEC, 0xD3, 0x55, 0x25, 0x00, 0x00}}, 4096, 40, 128, 2048, 64, 2, 3, 35, 0, 25, 10, 0, 25, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP|S_IL) },
++ // [ 1GB] K9G8G08UOM [ 2GB] K9LAG08U1M
++ { {{0xEC, 0xD3, 0x14, 0x25, 0x64, 0x00}}, 4096, 40, 128, 2048, 64, 2, 3, 35, 0, 25, 10, 0, 25, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 1GB] K9G8G08UOA/B [ 2GB] K9LAG08U1A
++ { {{0xEC, 0xD3, 0x14, 0xA5, 0x64, 0x00}}, 4096, 25, 128, 2048, 64, 2, 3, 50, 0, 30, 20, 0, 30, 20, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 2GB] K9LAG08UOM [ 4GB] K9HBG08U1M [ 8GB] K9MCG08U5M
++ { {{0xEC, 0xD5, 0x55, 0x25, 0x68, 0x00}}, 8192, 40, 128, 2048, 64, 2, 3, 30, 0, 20, 10, 0, 20, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP|S_IL) },
++ // [ 2GB] K9LAG08UOA/B
++ { {{0xEC, 0xD5, 0x55, 0xA5, 0x68, 0x00}}, 8192, 25, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP|S_IL) },
++ // [ 2GB] K9GAG08UOM // 4K Page
++ { {{0xEC, 0xD5, 0x14, 0xB6, 0x74, 0x00}}, 4096, 25, 128, 4096, 128, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 4GB] K9LBG08UOM [ 8GB] K9HCG08U1M [ 16G] K9MDG08U5M
++ { {{0xEC, 0xD7, 0x55, 0xB6, 0x78, 0x00}}, 8192, 25, 128, 4096, 128, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP|S_IL) },
++ // [ 2GB] K9GAG08UOD [ 4GB] K9LBG08U1D [ 8GB] K9HCG08U5D
++ { {{0xEC, 0xD5, 0x94, 0x29, 0x34, 0x41}}, 4096, 25, 128, 4096, 218, 2, 3, 30, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MCP) },
++ // [ 4GB] K9LBG08UOD [ 8GB] K9HCG08U1D [ 16G] K9MDG08U5D [ 32G] K9PDG08U5D
++ { {{0xEC, 0xD7, 0xD5, 0x29, 0x38, 0x41}}, 8192, 25, 128, 4096, 218, 2, 3, 30, 0, 20, 10, 0, 20, 10, (A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP|S_IL) },
++ // [ 4GB] K9GBG08U0M [ 8GB] K9LCG08U1M [ 16GB] K9HDG08U5M
++ { {{0xEC, 0xD7, 0x94, 0x72, 0x54, 0x42}}, 4096, 20, 128, 8192, 436, 2, 3, 30, 0, 20, 10, 0, 20, 10, (A_08BIT|A_MLC_16BIT |A_BIG |S_NOR|S_MCP) },
++ // [ 32GB] K9PFG08U5M
++ { {{0xEC, 0xDE, 0xD5, 0x72, 0x58, 0x42}}, 8192, 15, 128, 8192, 436, 2, 3, 30, 0, 20, 10, 0, 20, 10, (A_08BIT|A_MLC_16BIT |A_BIG |S_NOR|S_MP|S_IL|S_EB) }
++};
++
++const NAND_IO_FEATURE MICRON_NAND_DevInfo[] =
++{
++ //*=======================================================================================================================================================
++ //*[ DEVICE CODE ][ SIZE ][ Cycle ][ ATTRIBUTE ]
++ //*-------------------------------------------------------------------------------------------------------------------------------------------------------
++ //* 1st, 2nd, 3rd, 4th, 5th, 6th, PBpV,BBpZ, PpB, Page,Spare,Col,Low,Twc, Ws, Wp, Wh, Rs, Rp, Rh
++ //*=======================================================================================================================================================
++ // [256MB] 29F2G08AAC
++ { {{0x2C, 0xDA, 0x00, 0x00, 0x00, 0x00}}, 2048, 20, 64, 2048, 64, 2, 3, 30, 0, 25, 15, 0, 25, 15, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CP) },
++ // [512MB] 29F4G08BAC, [ 1GB] 29F8G08FAC
++ { {{0x2C, 0xDC, 0x80, 0x15, 0x50, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 30, 0, 25, 15, 0, 25, 15, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CP) },
++ // [512MB] 29F4G08AAA/C [ 1GB] 29F8G08DAA
++ { {{0x2C, 0xDC, 0x90, 0x95, 0x54, 0x00}}, 4096, 20, 64, 2048, 64, 2, 3, 30, 0, 25, 15, 0, 25, 15, (A_08BIT|A_SLC |A_BIG |S_NOR|S_MP) },
++ // [ 2GB] 29F16G08FAA
++ { {{0x2C, 0xD3, 0xD1, 0x95, 0x58, 0x00}}, 8192, 20, 64, 2048, 64, 2, 3, 30, 0, 25, 15, 0, 25, 15, (A_08BIT|A_SLC |A_BIG |S_NOR|S_CB|S_CP) },
++ // [ 1GB] MT29F8G08ABA (4Bit/540Bytes)
++ { {{0x2C, 0x38, 0x00, 0x26, 0x85, 0x00}}, 2048, 20, 128, 4096, 224, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_SLC |A_BIG |S_NOR|S_MP) },
++ // [ 1GB] 29F08G08MAA [ 2GB] 29F16G08QAA
++ { {{0x2C, 0xD3, 0x94, 0xA5, 0x64, 0x00}}, 4096, 40, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 4GB] 29F32G08TAA
++ { {{0x2C, 0xD5, 0xD5, 0xA5, 0x68, 0x00}}, 8192, 40, 128, 2048, 64, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC |A_BIG |S_NOR|S_MP) },
++ // [ 2GB] 29F16G08MAA [ 4GB] 29F32G08QAA
++ { {{0x2C, 0xD5, 0x94, 0x3E, 0x74, 0x00}}, 4096, 25, 128, 4096, 218, 2, 3, 30, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP) },
++ // [ 8GB] 29F64G08TAA
++ { {{0x2C, 0xD7, 0xD5, 0x3E, 0x78, 0x00}}, 8192, 25, 128, 4096, 218, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC_8BIT |A_BIG |S_NOR|S_MP|S_IL) },
++ // [ 4GB] 29F32G08CBAAA, [ 8GB] 29F64G08CFAAA
++ { {{0x2C, 0xD7, 0x94, 0x3E, 0x84, 0x00}}, 8192, 25, 128, 4096, 218, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC_12BIT|A_BIG |S_NOR|S_MCP) },
++ // [ 4GB] 29F32G08CBABA, [ 8GB] 29F64G08CFABA
++ { {{0x2C, 0x68, 0x04, 0x46, 0x89, 0x00}}, 4096, 25, 256, 4096, 224, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC_12BIT|A_BIG |S_NOR|S_MCP) },
++ // [ 16GB] 29F128G08CJAA
++ { {{0x2C, 0xD9, 0xD5, 0x3E, 0x88, 0x00}},16384, 25, 128, 4096, 218, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC_12BIT|A_BIG |S_NOR|S_MP|S_IL) },
++ // [ 16GB] 29F128G08CJBA
++ { {{0x2C, 0x88, 0x05, 0xC6, 0x89, 0x00}}, 8192, 25, 256, 4096, 224, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC_12BIT|A_BIG |S_NOR|S_MP|S_IL) }
++};
++
++const NAND_IO_FEATURE INTEL_NAND_DevInfo[] =
++{
++ //*=======================================================================================================================================================
++ //*[ DEVICE CODE ][ SIZE ][ Cycle ][ ATTRIBUTE ]
++ //*-------------------------------------------------------------------------------------------------------------------------------------------------------
++ //* 1st, 2nd, 3rd, 4th, 5th, 6th, PBpV,BBpZ, PpB, Page,Spare,Col,Low,Twc, Ws, Wp, Wh, Rs, Rp, Rh
++ //*=======================================================================================================================================================
++ // [ 4GB] JS29F32G08AAMD1 [ 8GB] JS29F64G08CAMD1 [ 16GB] JS29F16B08JAMD1
++ { {{0x89, 0xD7, 0x94, 0x3E, 0x84, 0x00}}, 8192, 40, 128, 4096, 218, 2, 3, 25, 0, 15, 10, 0, 15, 10, (A_08BIT|A_MLC_12BIT|A_BIG |S_NOR|S_MCP) }
++};
++
++const NAND_IO_MAKERINFO NAND_SupportMakerInfo =
++ {
++ // MAXIMUM SUPPORT NANDFLASH
++ {MAX_SUPPORT_SAMSUNG_NAND,
++ MAX_SUPPORT_TOSHIBA_NAND,
++ MAX_SUPPORT_HYNIX_NAND,
++ MAX_SUPPORT_ST_NAND,
++ MAX_SUPPORT_MICRON_NAND,
++ MAX_SUPPORT_INTEL_NAND},
++ // NAND MAKER ID
++ {SAMSUNG_NAND_MAKER_ID,
++ TOSHIBA_NAND_MAKER_ID,
++ HYNIX_NAND_MAKER_ID,
++ ST_NAND_MAKER_ID,
++ MICRON_NAND_MAKER_ID,
++ INTEL_NAND_MAKER_ID},
++
++ // POINTER OF NANDFLASH INFOMATION
++ {(NAND_IO_FEATURE*)SAMSUNG_NAND_DevInfo,
++ (NAND_IO_FEATURE*)TOSHIBA_NAND_DevInfo,
++ (NAND_IO_FEATURE*)HYNIX_NAND_DevInfo,
++ (NAND_IO_FEATURE*)ST_NAND_DevInfo,
++ (NAND_IO_FEATURE*)MICRON_NAND_DevInfo,
++ (NAND_IO_FEATURE*)INTEL_NAND_DevInfo}
++};
++
++const NAND_IO_LBA_MAKERINFO LBA_NAND_SupportMakerInfo =
++ {
++ // MAXIMUM SUPPORT NANDFLASH
++ {MAX_SUPPORT_TOSHIBA_LBA_NAND},
++ // NAND MAKER ID
++ {TOSHIBA_NAND_MAKER_ID},
++ // POINTER OF NANDFLASH INFOMATION
++ {(NAND_IO_FEATURE*)TOSHIBA_LBA_NAND_DevInfo}
++};
++
++const unsigned char NAND_LBA_VFP_AREA_Signature[] =
++{
++ "NANDLBASIGNATURE"
++};
++
++#define NAND_IO_MAX_SHIFT_FACTOR_FOR_MULTIPLY 16
++
++#if defined (_LINUX_) /* 09.07.24 */
++const unsigned short int NAND_IO_ShiftFactorForMultiplay[NAND_IO_MAX_SHIFT_FACTOR_FOR_MULTIPLY] __attribute__((aligned(8))) =
++{
++ 1, // 1 = 2^0
++ 2, // 2 = 2^1
++ 4, // 4 = 2^2
++ 8, // 8 = 2^3
++ 16, // 16 = 2^4
++ 32, // 32 = 2^5
++ 64, // 64 = 2^6
++ 128, // 128 = 2^7
++ 256, // 256 = 2^8
++ 512, // 512 = 2^9
++ 1024, // 1024 = 2^10
++ 2048, // 2048 = 2^11
++ 4096, // 4096 = 2^12
++ 8192, // 8192 = 2^13
++ 16384, // 16384 = 2^14
++ 32768 // 32768 = 2^15
++};
++
++const unsigned char ALL_FF_ECC_BCH_04BIT_12[28] __attribute__((aligned(8))) =
++{
++ 0x48,0xF6,0x3C,0xC9,0xAA,0x45,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
++};
++
++const unsigned char ALL_FF_ECC_BCH_04BIT_16[28] __attribute__((aligned(8))) =
++{
++ 0xC4,0x2A,0xDC,0xB4,0x25,0xCC,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
++};
++
++const unsigned char ALL_FF_ECC_BCH_01BIT_512[28] __attribute__((aligned(8))) =
++{
++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
++};
++// BCH 4bit Code: 6.5 Byte
++const unsigned char ALL_FF_ECC_BCH_04BIT_512[28] __attribute__((aligned(8))) =
++{
++ 0xEB,0x37,0xCC,0x63,0x96,0xCA,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
++};
++
++// BCH 8bit Code: 13 Byte
++const unsigned char ALL_FF_ECC_BCH_08BIT_512[28] __attribute__((aligned(8))) =
++{
++ 0x08,0x75,0x8B,0x6F,0x48,0x36,0xA6,0xBC,0x16,0x61,0x58,0xDB,0x52,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
++};
++
++// BCH 12bit Code: 19.5 Byte
++const unsigned char ALL_FF_ECC_BCH_12BIT_512[28] __attribute__((aligned(8)))=
++{
++ 0x81,0xEC,0xE8,0x4E,0xE3,0x46,0x44,0xA1,0x3F,0x8A,0x29,0x06,0xD0,0x90,
++ 0x06,0x76,0x21,0x32,0x3E,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
++};
++
++// BCH 14bit Code: 23 Byte
++const unsigned char ALL_FF_ECC_BCH_14BIT_512[28] __attribute__((aligned(8)))=
++{
++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
++};
++
++// BCH 16bit Code: 26 Byte
++const unsigned char ALL_FF_ECC_BCH_16BIT_512[28] __attribute__((aligned(8)))=
++{
++ 0xA6,0x14,0x08,0x76,0xEE,0xFE,0x20,0x10,0x9F,0xA3,0xC5,0x06,0x6D,0xDB,
++ 0xF4,0x51,0xBF,0x38,0x65,0xF8,0xD8,0xC2,0x87,0xFB,0xF1,0x8B,0x00,0x00
++};
++
++#else
++
++const unsigned short int NAND_IO_ShiftFactorForMultiplay[NAND_IO_MAX_SHIFT_FACTOR_FOR_MULTIPLY] =
++{
++ 1, // 1 = 2^0
++ 2, // 2 = 2^1
++ 4, // 4 = 2^2
++ 8, // 8 = 2^3
++ 16, // 16 = 2^4
++ 32, // 32 = 2^5
++ 64, // 64 = 2^6
++ 128, // 128 = 2^7
++ 256, // 256 = 2^8
++ 512, // 512 = 2^9
++ 1024, // 1024 = 2^10
++ 2048, // 2048 = 2^11
++ 4096, // 4096 = 2^12
++ 8192, // 8192 = 2^13
++ 16384, // 16384 = 2^14
++ 32768 // 32768 = 2^15
++};
++
++const unsigned char ALL_FF_ECC_BCH_04BIT_12[28] =
++{
++ 0x48,0xF6,0x3C,0xC9,0xAA,0x45,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
++};
++
++const unsigned char ALL_FF_ECC_BCH_04BIT_16[28] =
++{
++ 0xC4,0x2A,0xDC,0xB4,0x25,0xCC,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
++};
++
++const unsigned char ALL_FF_ECC_BCH_01BIT_512[28] =
++{
++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
++};
++
++// BCH 4bit Code: 6.5 Byte
++const unsigned char ALL_FF_ECC_BCH_04BIT_512[28] =
++{
++ 0xEB,0x37,0xCC,0x63,0x96,0xCA,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
++};
++
++// BCH 8bit Code: 13 Byte
++const unsigned char ALL_FF_ECC_BCH_08BIT_512[28] =
++{
++ 0x08,0x75,0x8B,0x6F,0x48,0x36,0xA6,0xBC,0x16,0x61,0x58,0xDB,0x52,0x00,
++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
++};
++
++// BCH 12bit Code: 19.5 Byte
++const unsigned char ALL_FF_ECC_BCH_12BIT_512[28] =
++{
++ 0x81,0xEC,0xE8,0x4E,0xE3,0x46,0x44,0xA1,0x3F,0x8A,0x29,0x06,0xD0,0x90,
++ 0x06,0x76,0x21,0x32,0x3E,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
++};
++
++// BCH 14bit Code: 23 Byte
++const unsigned char ALL_FF_ECC_BCH_14BIT_512[28] =
++{
++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
++};
++
++// BCH 16bit Code: 26 Byte
++const unsigned char ALL_FF_ECC_BCH_16BIT_512[28] =
++{
++ 0xA6,0x14,0x08,0x76,0xEE,0xFE,0x20,0x10,0x9F,0xA3,0xC5,0x06,0x6D,0xDB,
++ 0xF4,0x51,0xBF,0x38,0x65,0xF8,0xD8,0xC2,0x87,0xFB,0xF1,0x8B,0x00,0x00
++};
++
++#endif
++
++//=============================================================================
++//*
++//*
++//* [ GLOBAL VARIABLE DEFINE ]
++//*
++//*
++//=============================================================================
++NAND_IO_CYCLE WriteCycleTime;
++NAND_IO_CYCLE ReadCycleTime;
++NAND_IO_CYCLE CommCycleTime;
++unsigned int gMaxBusClkMHZ;
++unsigned int gCycleTick;
++
++NAND_IO_ECC_INFO gMLC_ECC_1Bit;
++NAND_IO_ECC_INFO gMLC_ECC_4Bit;
++NAND_IO_ECC_INFO gMLC_ECC_8Bit;
++NAND_IO_ECC_INFO gMLC_ECC_12Bit;
++NAND_IO_ECC_INFO gMLC_ECC_14Bit;
++NAND_IO_ECC_INFO gMLC_ECC_16Bit;
++
++unsigned int gNAND_IO_DataBusType;
++
++PGPIO pGPIO;
++PNFC pNFC;
++PECC pECC;
++PIOBUSCFG pIOBUSCFG_T;
++PPIC pPIC;
++#if defined(_WINCE_)
++tSYSTEM_PARAM *pSYS_PARAM;
++#endif
++PGDMANCTRL pNAND_DMA;
++
++unsigned int gInterLeavePageAddr;
++unsigned int gInterLeaveCSNum;
++unsigned short int gInterLeaveIoStatus;
++unsigned int gInterLeaveWriteStatus;
++
++/* Micron Interleaver */
++unsigned int gInterLeaveDie0BlockAddr;
++unsigned int gInterLeaveDie1BlockAddr;
++
++unsigned int gNANDIO_GSELReg;
++unsigned int gNANDIO_GIOCONReg;
++unsigned int gNANDIO_GDATASet;
++unsigned int gNAND_GPIO_ON_OFF = ENABLE;
++
++unsigned int *gpDMA_PhyBuffer0;
++unsigned int *gpDMA_WorkBuffer0;
++unsigned int *gpDMA_PhyBuffer1;
++unsigned int *gpDMA_WorkBuffer1;
++
++NAND_IO_DEVINFO *gDevInfo;
++NAND_IO_DEVINFO rDevInfo;
++
++#if defined(TCC89XX) || defined(TCC92XX)
++int gDRV_GDMA_Handle_NAND;
++sDRV_GDMA gDRV_GDMA_NAND =
++{
++ 0 | DRV_GDMA_CFG_StartByHwReqLevel
++ | DRV_GDMA_CFG_AckAtRead
++ | DRV_GDMA_CFG_Arbitration//| DRV_GDMA_CFG_NoArbitration
++ | DRV_GDMA_CFG_BufNum_1
++ | DRV_GDMA_CFG_1HopUnit_16Byte
++ | DRV_GDMA_CFG_ReadBW_32Bit
++ | DRV_GDMA_CFG_WriteBW_32Bit
++ , DRV_GDMA_HwREQ_NFC
++ , 0,
++};
++#endif
++
++#if defined(USE_V_ADDRESS) && defined(_WINCE_)
++DWORD gNFC_IRQ_Intr;
++DWORD gEXT_IRQ_Intr;
++HANDLE gNFC_IRQ_Handle = NULL;
++HANDLE gEXT_IRQ_Handle = NULL;
++#endif
++
++//#define SPEED_CHECK
++#if defined(SPEED_CHECK)
++//#define READ_SPEED_CHECK
++//#define WRITE_SPEED_CHECK
++#endif
++
++#if defined(_WINCE_)
++#pragma pack(8)
++unsigned char gNAND_IO_ShareEccBuffer[ 1024 ];
++unsigned char gNAND_IO_TempBuffer[ 32 ];
++#pragma pack()
++#elif defined(_LINUX_)
++#if defined(USE_V_ADDRESS)
++unsigned char *gNAND_IO_ShareEccBuffer;
++unsigned char *gNAND_IO_ShareEccBuffer_w;
++#else
++unsigned char gNAND_IO_ShareEccBuffer[ 1024 ] __attribute__((aligned(8)));
++#endif
++unsigned char gNAND_IO_TempBuffer[ 32 ] __attribute__((aligned(8)));
++#else
++__align(8) unsigned char gNAND_IO_ShareEccBuffer[ 1024 ];
++__align(8) unsigned char gNAND_IO_TempBuffer[ 32 ];
++#endif
++
++NAND_LBA_CALLBACK_HANDLER NAND_IO_LBA_CallBackLcdDisplay;
++
++//=============================================================================
++//*
++//*
++//* [ LOCAL FUNCTIONS DEFINE ]
++//*
++//*
++//=============================================================================
++static __inline void NAND_IO_SetDataWidth( U32 width );
++static __inline void NAND_IO_PreProcess( void );
++static __inline void NAND_IO_PostProcess( void );
++static __inline void NAND_IO_SetBasicCycleTime( void );
++static __inline void NAND_IO_SetWriteCycleTime(void);
++static __inline void NAND_IO_EnableChipSelect( U16 nChipNo );
++static __inline void NAND_IO_DisableChipSelect( void );
++static __inline void NAND_IO_EnableWriteProtect( void );
++static __inline void NAND_IO_DisableWriteProtect( void );
++static __inline U32 NAND_IO_CheckReadyAndBusy( U16 nChipNo);
++static __inline void NAND_IO_WaitBusy( U16 nChipNo );
++static __inline void NAND_IO_WaitBusyForProgramAndErase( NAND_IO_DEVINFO *nDevInfo );
++static __inline void NAND_IO_WaitBusyForCacheProgram( NAND_IO_DEVINFO *nDevInfo );
++static __inline void NAND_IO_ClearInterleaveStatus( NAND_IO_DEVINFO *nDevInfo );
++static __inline void NAND_IO_Delay( void );
++
++static __inline NAND_IO_ERROR NAND_IO_WaitBusyForInterleave( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr );
++static __inline NAND_IO_ERROR NAND_IO_ReadStatus( NAND_IO_DEVINFO *nDevInfo );
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForMultiPlane( NAND_IO_DEVINFO *nDevInfo );
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForCacheProgram( NAND_IO_DEVINFO *nDevInfo );
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForInterleave( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr );
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForInterleaveClear( NAND_IO_DEVINFO *nDevInfo );
++
++static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForRead( U32 nPageAddr, U16 nColumnAddr, U32* rRowAddr, U32* rColumnAddr, NAND_IO_DEVINFO *nDevInfo );
++static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForWrite( U32 nPageAddr, U16 nColumnAddr, U32* rRowAddr, U32* rColumnAddr, NAND_IO_DEVINFO *nDevInfo );
++static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForCBandCP( U32 nPageAddr, U16 nColumnAddr, U32* rRowAddr, U32* rColumnAddr, NAND_IO_DEVINFO *nDevInfo );
++static __inline void NAND_IO_WriteRowColAddr( U32 nRowAddr, U32 nColumnAddr, NAND_IO_DEVINFO *nDevInfo );
++static __inline void NAND_IO_WriteBlockPageAddr( U32 nBlockPageAddr, NAND_IO_DEVINFO *nDevInfo );
++static __inline void NAND_IO_BusControl( NAND_IO_DEVINFO *nDevInfo );
++
++static __inline void NAND_IO_SetupDMA(void * pSRC, unsigned uSrcInc, unsigned uSrcMask, void * pDST, unsigned uDstInc, unsigned uDstMask, int nMode, int nDSize );
++static __inline void NAND_IO_SetupDMA_kernel(void * pSRC, unsigned uSrcInc, unsigned uSrcMask, void * pDST, unsigned uDstInc, unsigned uDstMask, int nMode, int nDSize );
++static __inline void NAND_IO_SetupDMADoubleBuf( int nMode, int nDMACh );
++
++static __inline void NAND_IO_SetupECC( U16 nEccOnOff, U16 nEncDec, U16 nEccType, U16 nAccessType, U32 EccBaseAddr );
++static __inline NAND_IO_ERROR NAND_IO_EncodeECC( U16 nEccType, U8* nSpareBuffer );
++static __inline NAND_IO_ERROR NAND_IO_CorrectionSLC( U8* nPageBuffer, U8* nSpareBuffer );
++static __inline NAND_IO_ERROR NAND_IO_CorrectionMLC_IRQ( U16 nEccType, U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize );
++static __inline NAND_IO_ERROR NAND_IO_CorrectionMLC( U16 nEccType, U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize );
++static __inline NAND_IO_ERROR NAND_IO_EncodeBootBinary( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, int nEccOnOff );
++
++static __inline NAND_IO_ERROR NAND_IO_ReadSpareData( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nPageEccOnOff );
++static __inline NAND_IO_ERROR NAND_IO_Read512DataDoubleBuf( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff, int nSpareOnOff );
++static __inline NAND_IO_ERROR NAND_IO_Read512Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff, int nSpareOnOff );
++static __inline NAND_IO_ERROR NAND_IO_ReadSpareDataMTD( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nPageEccOnOff );
++static __inline NAND_IO_ERROR NAND_IO_ReadUserSizeData( NAND_IO_DEVINFO *nDevInfo, U16 nColumnAddr, U32 nReadSize, U8 *nReadBuffer );
++static __inline NAND_IO_ERROR NAND_IO_Read512DataMTD( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff, int nSpareOnOff );
++
++static __inline NAND_IO_ERROR NAND_IO_Write512DataDoubleBuf( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++static __inline NAND_IO_ERROR NAND_IO_Write512Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++static __inline NAND_IO_ERROR NAND_IO_WriteUserSizeData( NAND_IO_DEVINFO *nDevInfo, U16 nColumnAddr, U32 nWriteSize, U8 *nWriteBuffer );
++static __inline NAND_IO_ERROR NAND_IO_Write512DataMTD( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++
++static __inline void NAND_IO_CheckForExtendBlockAccess( NAND_IO_DEVINFO *nDevInfo, U32* nPageAddr );
++
++static __inline NAND_IO_ERROR NAND_IO_GetShiftValueForFastMultiPly( U16 nValue, U16* rFactor );
++
++#if defined (NAND_LBA_INCLUDE)
++static __inline void NAND_IO_LBA_WaitBusy( U16 nChipNo );
++static __inline NAND_IO_ERROR NAND_IO_LBA_ReadData_VFP( NAND_IO_DEVINFO *nDevInfo, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer );
++static __inline NAND_IO_ERROR NAND_IO_LBA_ReadData( NAND_IO_DEVINFO *nDevInfo, U16 nReadPPSize, U8 *nPageBuffer, U8 *nSpareBuffer );
++static __inline NAND_IO_ERROR NAND_IO_LBA_WriteData( NAND_IO_DEVINFO *nDevInfo, U16 nWritePPSize, U8 *nPageBuffer, U8 *nSpareBuffer );
++static __inline NAND_IO_ERROR NAND_IO_LBA_WriteDummyData( NAND_IO_DEVINFO *nDevInfo, U16 nWritePPSize );
++
++NAND_IO_ERROR NAND_IO_LBA_ConvertMPPA( NAND_IO_DEVINFO *nDevInfo, U8 nPartition, U32 nSectorAddr, U32 nSecSize, U32 *nConvertAddr, U32 *nConvertSize, U16 *rMediaOrder );
++NAND_IO_ERROR NAND_IO_LBA_VFPInitArea( NAND_IO_DEVINFO *nDevInfo );
++NAND_IO_ERROR NAND_IO_LBA_MDPGetTotalSectorSize(NAND_IO_DEVINFO * nDevInfo, unsigned long int * rTotalSector);
++NAND_IO_ERROR NAND_IO_LBA_VFPGetTotalSectorSize(NAND_IO_DEVINFO * nDevInfo, U32 * rTotalSector);
++NAND_IO_ERROR NAND_IO_LBA_VFPChangeSectorSize(NAND_IO_DEVINFO * nDevInfo, U32 nTotalSector);
++NAND_IO_ERROR NAND_IO_LBA_SetTransferProtocol(NAND_IO_DEVINFO * nDevInfo, U8 nProtocol1, U8 nProtocol2);
++NAND_IO_ERROR NAND_IO_LBA_SetBootModeChange( NAND_IO_DEVINFO *nDevInfo, U8 nBootMode );
++NAND_IO_ERROR NAND_IO_LBA_SetRebootCmdChange( NAND_IO_DEVINFO *nDevInfo, U8 nRebootCmd );
++NAND_IO_ERROR NAND_IO_LBA_SetAreaPartition( NAND_IO_DEVINFO *nDevInfo, NAND_IO_FEATURE * sDevFeatureInfo );
++NAND_IO_ERROR NAND_IO_LBA_GetPersistentFunction( NAND_IO_DEVINFO *nDevInfo, U8 *rBootMode, U8 *rRebootCmd );
++NAND_IO_ERROR NAND_IO_LBA_GetTransferProtocol( NAND_IO_DEVINFO *nDevInfo, U8 *rProtocol1, U8 *rProtocol2 );
++NAND_IO_ERROR NAND_IO_LBA_GetBootMode( NAND_IO_DEVINFO *nDevInfo, U8 *rBootMode );
++NAND_IO_ERROR NAND_IO_LBA_ReadID( NAND_IO_DEVINFO *nDevInfo, NAND_IO_DEVID *nDeviceCode );
++NAND_IO_ERROR NAND_IO_LBA_ReadUID( NAND_IO_DEVINFO *nDevInfo );
++NAND_IO_ERROR NAND_IO_LBA_Reset( NAND_IO_DEVINFO *nDevInfo );
++#endif
++
++//=============================================================================
++//*
++//*
++//* [ EXTERN VARIABLE & FUNCTIONS DEFINE ]
++//*
++//*
++//=============================================================================
++#if defined(_LINUX_) || defined(_WINCE_)
++int TCC7XX_USBDRV_WriteToQueue( void ){ return 0;}
++extern unsigned int gMAX_ROMSIZE;
++#else
++extern void memcpy(void *pvDest, const void *pvSrc, unsigned long iCount);
++extern void memset(void *pvDest, char cChar, unsigned long iCount);
++extern int memcmp(const void *pvSrc1, const void *pvSrc2, unsigned long iCount);
++extern int TCC7XX_USBDRV_WriteToQueue( void );
++extern unsigned int gMAX_ROMSIZE;
++#endif
++
++extern unsigned CRC32_TABLE[];
++
++#ifndef _LINUX_
++extern unsigned fmemcpy16(void *dest, void *src, unsigned length);
++#endif
++
++#ifdef SPEED_CHECK
++void NAND_IO_GPIO_Toggle( U32 nBitNum )
++{
++ if( pGPIO->GPFDAT & nBitNum )
++ BITCLR(pGPIO->GPFDAT, nBitNum);
++ else
++ BITSET(pGPIO->GPFDAT, nBitNum);
++}
++#endif
++
++#if defined(_WINCE_)
++extern void B_RETAILMSG(const char * fmt, ...);
++#endif
++
++/******************************************************************************
++*
++* unsigned char* NAND_IO_TellLibraryVersion
++*
++* Input : NONE
++* Output : NONE
++* Return : NONE
++*
++* Description :
++*
++*******************************************************************************/
++unsigned char* NAND_IO_TellLibraryVersion( void )
++{
++ return (unsigned char*)NANDIO_Library_Version;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* NAND_IO_ERROR NAND_IO_NANDGPIOControlFlag( unsigned int on_off );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* on_off =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++NAND_IO_ERROR NAND_IO_NANDGPIOControlFlag( unsigned int on_off )
++{
++ gNAND_GPIO_ON_OFF = on_off;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_CallBackChangeWCtime
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_CallBackChangeWCtime( unsigned short int TotalMediaNum, NAND_IO_DEVINFO *nDevInfo )
++{
++ if ( nDevInfo->IoStatus == ENABLE )
++ {
++ //**************************************************************
++ // Case on K9NBG08U5M Samsung NANDFLASH
++ //**************************************************************
++ if ( nDevInfo->Feature.DeviceID.Code[0] == 0xEC &&
++ nDevInfo->Feature.DeviceID.Code[1] == 0xD3 &&
++ nDevInfo->Feature.DeviceID.Code[2] == 0x51 &&
++ nDevInfo->Feature.DeviceID.Code[3] == 0x95 )
++ {
++ if ( TotalMediaNum == 4 )
++ {
++ nDevInfo->Feature.WCtime = 45;
++
++ nDevInfo->Feature.WriteSTP = 0;
++ nDevInfo->Feature.WriteWP = 30;
++ nDevInfo->Feature.WriteHLD = 15;
++
++ nDevInfo->Feature.ReadSTP = 0;
++ nDevInfo->Feature.ReadPW = 30;
++ nDevInfo->Feature.ReadHLD = 15;
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ }
++ //**************************************************************
++ // Case on K9MBG08U5M Samsung NANDFLASH
++ //**************************************************************
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == 0xEC &&
++ nDevInfo->Feature.DeviceID.Code[1] == 0xD3 &&
++ nDevInfo->Feature.DeviceID.Code[2] == 0x55 &&
++ nDevInfo->Feature.DeviceID.Code[3] == 0x25 )
++ {
++ if ( TotalMediaNum == 4 )
++ {
++ nDevInfo->Feature.WCtime = 45;
++
++ nDevInfo->Feature.WriteSTP = 0;
++ nDevInfo->Feature.WriteWP = 30;
++ nDevInfo->Feature.WriteHLD = 15;
++
++ nDevInfo->Feature.ReadSTP = 0;
++ nDevInfo->Feature.ReadPW = 30;
++ nDevInfo->Feature.ReadHLD = 15;
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ }
++ //**************************************************************
++ // Case on K9MCG08U5M Samsung NANDFLASH
++ //**************************************************************
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == 0xEC &&
++ nDevInfo->Feature.DeviceID.Code[1] == 0xD5 &&
++ nDevInfo->Feature.DeviceID.Code[2] == 0x55 &&
++ nDevInfo->Feature.DeviceID.Code[3] == 0x25 &&
++ nDevInfo->Feature.DeviceID.Code[4] == 0x68 )
++ {
++ if ( TotalMediaNum == 4 )
++ {
++ nDevInfo->Feature.WCtime = 45;
++
++ nDevInfo->Feature.WriteSTP = 0;
++ nDevInfo->Feature.WriteWP = 30;
++ nDevInfo->Feature.WriteHLD = 15;
++
++ nDevInfo->Feature.ReadSTP = 0;
++ nDevInfo->Feature.ReadPW = 30;
++ nDevInfo->Feature.ReadHLD = 15;
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ }
++ //**************************************************************
++ // Case on K9MDG08U5M Samsung NANDFLASH
++ //**************************************************************
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == 0xEC &&
++ nDevInfo->Feature.DeviceID.Code[1] == 0xD7 &&
++ nDevInfo->Feature.DeviceID.Code[2] == 0x55 &&
++ nDevInfo->Feature.DeviceID.Code[3] == 0xB6 &&
++ nDevInfo->Feature.DeviceID.Code[4] == 0x78 )
++ {
++ if ( TotalMediaNum == 4 )
++ {
++ nDevInfo->Feature.WCtime = 45;
++
++ nDevInfo->Feature.WriteSTP = 0;
++ nDevInfo->Feature.WriteWP = 30;
++ nDevInfo->Feature.WriteHLD = 15;
++
++ nDevInfo->Feature.ReadSTP = 0;
++ nDevInfo->Feature.ReadPW = 30;
++ nDevInfo->Feature.ReadHLD = 15;
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ }
++ //**************************************************************
++ // Case on K9MDG08U5D Samsung NANDFLASH
++ //**************************************************************
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == 0xEC &&
++ nDevInfo->Feature.DeviceID.Code[1] == 0xD7 &&
++ nDevInfo->Feature.DeviceID.Code[2] == 0xD5 &&
++ nDevInfo->Feature.DeviceID.Code[3] == 0x29 &&
++ nDevInfo->Feature.DeviceID.Code[4] == 0x38 )
++ {
++ if ( TotalMediaNum == 2 )
++ {
++ nDevInfo->Feature.WCtime = 45;
++
++ nDevInfo->Feature.WriteSTP = 0;
++ nDevInfo->Feature.WriteWP = 30;
++ nDevInfo->Feature.WriteHLD = 15;
++
++ nDevInfo->Feature.ReadSTP = 0;
++ nDevInfo->Feature.ReadPW = 30;
++ nDevInfo->Feature.ReadHLD = 15;
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ }
++ //**************************************************************
++ // Case on K9MDG08U5D Samsung NANDFLASH
++ //**************************************************************
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == 0xEC &&
++ nDevInfo->Feature.DeviceID.Code[1] == 0xDE &&
++ nDevInfo->Feature.DeviceID.Code[2] == 0xD5 &&
++ nDevInfo->Feature.DeviceID.Code[3] == 0x72 &&
++ nDevInfo->Feature.DeviceID.Code[4] == 0x58 &&
++ nDevInfo->Feature.DeviceID.Code[5] == 0x42)
++ {
++ if ( ( TotalMediaNum >= 2 ) || ( nDevInfo->Feature.MediaType & A_PARALLEL ) )
++ {
++ nDevInfo->Feature.WCtime = 45;
++
++ nDevInfo->Feature.WriteSTP = 0;
++ nDevInfo->Feature.WriteWP = 30;
++ nDevInfo->Feature.WriteHLD = 15;
++
++ nDevInfo->Feature.ReadSTP = 0;
++ nDevInfo->Feature.ReadPW = 30;
++ nDevInfo->Feature.ReadHLD = 15;
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ }
++
++ //**************************************************************
++ // Case on TH58NVG5D4CTG20 Toshiba NANDFLASH
++ //**************************************************************
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == 0x98 &&
++ nDevInfo->Feature.DeviceID.Code[1] == 0xD5 &&
++ nDevInfo->Feature.DeviceID.Code[2] == 0x85 &&
++ nDevInfo->Feature.DeviceID.Code[3] == 0xA5 )
++ {
++ if ( TotalMediaNum == 2 )
++ {
++ nDevInfo->Feature.WCtime = 30;
++
++ nDevInfo->Feature.WriteSTP = 0;
++ nDevInfo->Feature.WriteWP = 20;
++ nDevInfo->Feature.WriteHLD = 10;
++
++ nDevInfo->Feature.ReadSTP = 0;
++ nDevInfo->Feature.ReadPW = 20;
++ nDevInfo->Feature.ReadHLD = 10;
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ }
++ }
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_SetCycle
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_SetCycle( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int nMaxBusClk;
++ unsigned int nMaxBusClkMHZ;
++ unsigned int nCycleTick;
++ unsigned int nTickRange = 10;
++ unsigned int nDevSTP, nDevPW, nDevHLD;
++ unsigned int nMCycleSTP, nMCyclePW, nMCycleHLD;
++ unsigned int nSCycleSTP, nSCyclePW, nSCycleHLD;
++ int nRemainSTP, nRemainPW, nRemainHLD;
++ int nTempResult;
++ unsigned int nReCompRatioSTP, nReCompRatioHLD, nReCompRatioPW;
++ unsigned int nWrCompRatioSTP, nWrCompRatioHLD, nWrCompRatioPW;
++ unsigned int nCoCompRatioSTP, nCoCompRatioHLD, nCoCompRatioPW;
++ unsigned int nReGateDelay, nWrGateDelay;
++
++ //===================================
++ // Get Max Bus CLK
++ //===================================
++ #ifdef FWDN_DOWNLOADER_INCLUDE
++ nMaxBusClk = 1000000; // 100MHZ
++ #elif defined(TCC89XX) || defined(TCC92XX)
++ {
++ #if defined(_WINCE_)
++ #if defined(USE_V_ADDRESS)
++ nMaxBusClk = tcc_ckc_getfbusctrl(CLKCTRL4);
++ #else
++ tca_ckc_init();
++ nMaxBusClk = tca_ckc_getfbusctrl(CLKCTRL4);
++ #endif
++ #elif defined(_LINUX_)
++ tca_ckc_init();
++ nMaxBusClk = tca_ckc_getfbusctrl(CLKCTRL4);
++ #else
++ //#ifdef CLOCK_ADJUST_ENABLE
++ //nMaxBusClk = IO_CKC_GetCurrentBUSClock4Cycle();
++ //#else
++ //nMaxBusClk = IO_CKC_Fmaxbus; // frequency of 100Hz unit
++ //#endif
++ nMaxBusClk = 1660000;
++ #endif
++ }
++ #endif
++
++ if ( nMaxBusClk == 0 )
++ nMaxBusClk = 1660000;
++
++ /* Convert MHZ Value of Max Bus Clock */
++ if (!( nMaxBusClk / 10000 ))
++ return ERR_NAND_IO_WRONG_PARAMETER;
++ nMaxBusClkMHZ = ( nMaxBusClk / 10000 );
++
++ /* Get Cycke Tick */
++ nCycleTick = ( 1000 * nTickRange ) / nMaxBusClkMHZ;
++ if (( 1000 * nTickRange ) % nMaxBusClkMHZ )
++ ++nCycleTick;
++
++ //===================================
++ // Set Cycle
++ //===================================
++
++ /* Basis Setting */
++ #if defined(TCC89XX) || defined(TCC92XX)
++ nReGateDelay = 15;
++ nWrGateDelay = 0;
++ #else
++ nReGateDelay = 15;
++ nWrGateDelay = 0;
++ #endif
++
++ nReCompRatioSTP = 6;
++ nReCompRatioHLD = 0;
++ nReCompRatioPW = 0;
++
++ nWrCompRatioSTP = 6;
++ nWrCompRatioHLD = 0;
++ nWrCompRatioPW = 0;
++
++ nCoCompRatioSTP = 0;
++ nCoCompRatioHLD = 0;
++ nCoCompRatioPW = 0;
++
++ /* Read Cycle */
++ nDevSTP = nDevInfo->Feature.ReadSTP * nTickRange;
++ nDevPW = nDevInfo->Feature.ReadPW * nTickRange;
++ nDevHLD = nDevInfo->Feature.ReadHLD * nTickRange;
++
++ nMCycleSTP = ( nDevSTP / nCycleTick ) + (( nDevSTP && !( nDevSTP / nCycleTick )) ? 1 : 0 );
++ nMCycleHLD = ( nDevHLD / nCycleTick ) + (( nDevHLD && !( nDevHLD / nCycleTick )) ? 1 : 0 );
++ nRemainSTP = ( nMCycleSTP * nCycleTick ) - nDevSTP;
++ nRemainHLD = ( nMCycleHLD * nCycleTick ) - nDevHLD;
++ nSCycleSTP = (( nRemainSTP < 0 ) && ((( nRemainSTP >= 0 ) ? nRemainSTP : -nRemainSTP ) > (int)(( nCycleTick / 10 ) * nReCompRatioSTP ))) ? 1 : 0;
++ nSCycleHLD = (( nRemainHLD < 0 ) && ((( nRemainHLD >= 0 ) ? nRemainHLD : -nRemainHLD ) > (int)(( nCycleTick / 10 ) * nReCompRatioHLD ))) ? 1 : 0;
++ nTempResult = ( nDevPW + ( nReGateDelay * nTickRange )) + (( nRemainSTP >= 0 ) ? 0 : -nRemainSTP ) + (( nRemainHLD >= 0 ) ? 0 : -nRemainHLD );
++ nMCyclePW = ( nTempResult >= (int)nCycleTick ) ? ( nTempResult / nCycleTick ) : 1;
++ nRemainPW = ( nMCyclePW * nCycleTick ) - ( nDevPW + ( nReGateDelay * nTickRange ));
++ nSCyclePW = (( nRemainPW < 0 ) && ((( nRemainPW >= 0 ) ? nRemainPW : -nRemainPW ) > (int)(( nCycleTick / 10 ) * nReCompRatioPW ))) ? 1 : 0;
++
++ ReadCycleTime.STP = (U8)(nMCycleSTP + nSCycleSTP);
++ ReadCycleTime.HLD = (U8)(nMCycleHLD + nSCycleHLD);
++ ReadCycleTime.PW = (U8)(nMCyclePW + nSCyclePW + (( nDevInfo->Feature.MediaType & A_PARALLEL ) ? 1: 0 ));
++
++ /* Write Cycle */
++ nDevSTP = nDevInfo->Feature.WriteSTP * nTickRange;
++ nDevPW = nDevInfo->Feature.WriteWP * nTickRange;
++ nDevHLD = nDevInfo->Feature.WriteHLD * nTickRange;
++
++ nMCycleSTP = ( nDevSTP / nCycleTick ) + (( nDevSTP && !( nDevSTP / nCycleTick )) ? 1 : 0 );
++ nMCycleHLD = ( nDevHLD / nCycleTick ) + (( nDevHLD && !( nDevHLD / nCycleTick )) ? 1 : 0 );
++ nRemainSTP = ( nMCycleSTP * nCycleTick ) - nDevSTP;
++ nRemainHLD = ( nMCycleHLD * nCycleTick ) - nDevHLD;
++ nSCycleSTP = (( nRemainSTP < 0 ) && ((( nRemainSTP >= 0 ) ? nRemainSTP : -nRemainSTP ) > (int)(( nCycleTick / 10 ) * nWrCompRatioSTP ))) ? 1 : 0;
++ nSCycleHLD = (( nRemainHLD < 0 ) && ((( nRemainHLD >= 0 ) ? nRemainHLD : -nRemainHLD ) > (int)(( nCycleTick / 10 ) * nWrCompRatioHLD ))) ? 1 : 0;
++ nTempResult = ( nDevPW + ( nWrGateDelay * nTickRange )) + (( nRemainSTP >= 0 ) ? 0 : -nRemainSTP ) + (( nRemainHLD >= 0 ) ? 0 : -nRemainHLD );
++ nMCyclePW = ( nTempResult >= (int)nCycleTick ) ? ( nTempResult / nCycleTick ) : 1;
++ nRemainPW = ( nMCyclePW * nCycleTick ) - ( nDevPW + ( nWrGateDelay * nTickRange ));
++ nSCyclePW = (( nRemainPW < 0 ) && ((( nRemainPW >= 0 ) ? nRemainPW : -nRemainPW ) > (int)(( nCycleTick / 10 ) * nWrCompRatioPW ))) ? 1 : 0;
++
++ WriteCycleTime.STP = (U8)(nMCycleSTP + nSCycleSTP);
++ WriteCycleTime.HLD = (U8)(nMCycleHLD + nSCycleHLD);
++ WriteCycleTime.PW = (U8)(nMCyclePW + nSCyclePW);
++
++ /* Comm Cycle */
++ nDevSTP = 10 * nTickRange;
++ nDevPW = 80 * nTickRange;
++ nDevHLD = 40 * nTickRange;
++
++ nMCycleSTP = ( nDevSTP / nCycleTick ) + (( nDevSTP && !( nDevSTP / nCycleTick )) ? 1 : 0 );
++ nMCycleHLD = ( nDevHLD / nCycleTick ) + (( nDevHLD && !( nDevHLD / nCycleTick )) ? 1 : 0 );
++ nRemainSTP = ( nMCycleSTP * nCycleTick ) - nDevSTP;
++ nRemainHLD = ( nMCycleHLD * nCycleTick ) - nDevHLD;
++ nSCycleSTP = (( nRemainSTP < 0 ) && ((( nRemainSTP >= 0 ) ? nRemainSTP : -nRemainSTP ) > (int)(( nCycleTick / 10 ) * nCoCompRatioSTP ))) ? 1 : 0;
++ nSCycleHLD = (( nRemainHLD < 0 ) && ((( nRemainHLD >= 0 ) ? nRemainHLD : -nRemainHLD ) > (int)(( nCycleTick / 10 ) * nCoCompRatioHLD ))) ? 1 : 0;
++ nTempResult = ( nDevPW + ( nReGateDelay * nTickRange )) + (( nRemainSTP >= 0 ) ? 0 : -nRemainSTP ) + (( nRemainHLD >= 0 ) ? 0 : -nRemainHLD );
++ nMCyclePW = ( nTempResult >= (int)nCycleTick ) ? ( nTempResult / nCycleTick ) : 1;
++ nRemainPW = ( nMCyclePW * nCycleTick ) - ( nDevPW + ( nReGateDelay * nTickRange ));
++ nSCyclePW = (( nRemainPW < 0 ) && ((( nRemainPW >= 0 ) ? nRemainPW : -nRemainPW ) > (int)(( nCycleTick / 10 ) * nCoCompRatioPW ))) ? 1 : 0;
++
++ CommCycleTime.STP = (U8)(nMCycleSTP + nSCycleSTP);
++ CommCycleTime.HLD = (U8)(nMCycleHLD + nSCycleHLD);
++ CommCycleTime.PW = (U8)(nMCyclePW + nSCyclePW);
++
++ if (WriteCycleTime.STP >= 16)
++ WriteCycleTime.STP = 15;
++ if (WriteCycleTime.PW >= 16)
++ WriteCycleTime.PW = 15;
++ if (WriteCycleTime.HLD >= 16)
++ WriteCycleTime.HLD = 15;
++ if (WriteCycleTime.HLD == 0)
++ WriteCycleTime.HLD = 1;
++
++ if (ReadCycleTime.STP >= 16)
++ ReadCycleTime.STP = 15;
++ if (ReadCycleTime.PW >= 16)
++ ReadCycleTime.PW = 15;
++ if (ReadCycleTime.HLD >= 16)
++ ReadCycleTime.HLD = 15;
++
++ if (CommCycleTime.STP >= 16)
++ CommCycleTime.STP = 15;
++ if (CommCycleTime.PW >= 16)
++ CommCycleTime.PW = 15;
++ if (CommCycleTime.HLD >= 16)
++ CommCycleTime.HLD = 15;
++
++ if ( ReadCycleTime.PW < 2 )
++ ReadCycleTime.PW = 2;
++ if ( ReadCycleTime.HLD < 2 )
++ ReadCycleTime.HLD = 2;
++
++ if ( gNAND_IO_DataBusType == NAND_IO_NFC_BUS )
++ {
++ WriteCycleTime.RegValue = ( WriteCycleTime.STP << 8 ) + ( WriteCycleTime.PW << 4 ) + WriteCycleTime.HLD;
++ ReadCycleTime.RegValue = ( ReadCycleTime.STP << 8 ) + ( ReadCycleTime.PW << 4 ) + ReadCycleTime.HLD;
++ CommCycleTime.RegValue = ( CommCycleTime.STP << 8 ) + ( CommCycleTime.PW << 4 ) + CommCycleTime.HLD;
++ }
++ else if ( gNAND_IO_DataBusType == NAND_IO_MEM_BUS )
++ {
++ #if defined(TCC860x)
++ WriteCycleTime.RegValue = ( WriteCycleTime.STP << 6 ) + ( WriteCycleTime.PW << 3 ) + WriteCycleTime.HLD;
++ ReadCycleTime.RegValue = ( ReadCycleTime.STP << 6 ) + ( ReadCycleTime.PW << 3 ) + ReadCycleTime.HLD;
++ CommCycleTime.RegValue = ( CommCycleTime.STP << 6 ) + ( CommCycleTime.PW << 3 ) + CommCycleTime.HLD;
++ #else
++ WriteCycleTime.RegValue = ( WriteCycleTime.STP << 11 ) + (( WriteCycleTime.PW - 1 ) << 3 ) + WriteCycleTime.HLD;
++ ReadCycleTime.RegValue = ( ReadCycleTime.STP << 11 ) + (( ReadCycleTime.PW - 1 ) << 3 ) + ReadCycleTime.HLD;
++ CommCycleTime.RegValue = ( CommCycleTime.STP << 11 ) + (( CommCycleTime.PW - 1 ) << 3 ) + CommCycleTime.HLD;
++ #endif
++ }
++
++ gMaxBusClkMHZ = nMaxBusClkMHZ;
++ gCycleTick = nCycleTick;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_GetDeviceInfo
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_GetDeviceInfo( U16 nChipNo, NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned short int j,k,l;
++ unsigned char bFindMedia;
++ unsigned char bFindMakerNo;
++ unsigned char bMatchCount;
++ NAND_IO_DEVID sDeviceCode1,sDeviceCode2;
++ NAND_IO_FEATURE *sTempFeatureInfo;
++ NAND_IO_FEATURE *sFindFeatureInfo;
++ NAND_IO_ERROR res;
++
++ bFindMedia = FALSE;
++ nDevInfo->IoStatus = 0;
++ nDevInfo->ChipNo = 0xFF;
++ gInterLeaveCSNum = 0;
++ gInterLeaveIoStatus = 0;
++ gInterLeaveWriteStatus = MULTI_PLANE_GOOD_BLOCK;
++
++ // Init Variable
++ sTempFeatureInfo = (NAND_IO_FEATURE*)NAND_SupportMakerInfo.DevInfo[0];
++ sFindFeatureInfo = (NAND_IO_FEATURE*)NAND_SupportMakerInfo.DevInfo[0];
++
++ //=====================================================================
++ // Search Matched NANDFLASH (x8 Bit Serial NAND)
++ //=====================================================================
++ for ( j = 0; j < 3; ++j ) /* Check Read ID during 3 turn */
++ {
++ //IO_CKC_EnableBUS( IO_CKC_BUS_NFC );
++ // 16Bit NAND Mask Disable
++ BITCLR( pNFC->NFC_CTRL, HwNFC_CTRL_MASK_EN );
++
++ /* Read Device CODE */
++ NAND_IO_ResetForReadID( nChipNo, NAND_IO_SERIAL_COMBINATION_MODE ); // x8 Bit NAND Search
++ NAND_IO_ReadID( nChipNo, &sDeviceCode1, NAND_IO_SERIAL_COMBINATION_MODE ); // x8 Bit NAND Search
++
++ /* Check Maker ID */
++ bFindMakerNo = 0xFF;
++ for ( k = 0; k < MAX_SUPPORT_MAKER_NAND; ++k )
++ {
++ if ( sDeviceCode1.Code[0] == NAND_SupportMakerInfo.MakerID[k] )
++ {
++ bFindMakerNo = (unsigned char)k;
++ sTempFeatureInfo = (NAND_IO_FEATURE*)NAND_SupportMakerInfo.DevInfo[k];
++ break;
++ }
++ }
++
++ if ( bFindMakerNo >= MAX_SUPPORT_MAKER_NAND )
++ continue;
++
++ /* Check Device ID */
++ for ( k = 0; k < NAND_SupportMakerInfo.MaxSupportNAND[bFindMakerNo]; ++k )
++ {
++ bMatchCount = 0;
++
++ for ( l = 0; l < 5; ++l )
++ {
++ if ( sTempFeatureInfo->DeviceID.Code[l+1] == 0x00 )
++ ++bMatchCount;
++ else if ( sDeviceCode1.Code[l+1] == sTempFeatureInfo->DeviceID.Code[l+1] )
++ ++bMatchCount;
++ }
++
++ /* Found NAND Device */
++ if ( bMatchCount >= 5 )
++ {
++ bFindMedia = TRUE;
++ sFindFeatureInfo = sTempFeatureInfo;
++ break;
++ }
++ else
++ ++sTempFeatureInfo;
++ }
++
++ /* Found NAND Device */
++ if ( bFindMedia == TRUE )
++ break;
++ }
++
++ if ( bFindMedia != TRUE )
++ {
++ //=====================================================================
++ // Search Matched NANDFLASH (x16 Bit Serial NAND)
++ //=====================================================================
++ for ( j = 0; j < 3; ++j ) /* Check Read ID during 3 turn */
++ {
++ //IO_CKC_EnableBUS( IO_CKC_BUS_NFC );
++ // 16Bit NAND Mask Enable
++ BITSET( pNFC->NFC_CTRL, HwNFC_CTRL_MASK_EN );
++
++ /* Read Device CODE */
++ NAND_IO_ResetForReadID( nChipNo, NAND_IO_PARALLEL_COMBINATION_MODE ); // x16 Bit NAND Command
++ NAND_IO_ReadID( nChipNo, &sDeviceCode1, NAND_IO_PARALLEL_COMBINATION_MODE ); // x16 Bit NAND Search
++
++ /* Check Maker ID */
++ bFindMakerNo = 0xFF;
++ for ( k = 0; k < MAX_SUPPORT_MAKER_NAND; ++k )
++ {
++ if ( sDeviceCode1.Code[0] == NAND_SupportMakerInfo.MakerID[k] )
++ {
++ bFindMakerNo = (unsigned char)k;
++ sTempFeatureInfo = (NAND_IO_FEATURE*)NAND_SupportMakerInfo.DevInfo[k];
++ break;
++ }
++ }
++
++ if ( bFindMakerNo >= MAX_SUPPORT_MAKER_NAND )
++ {
++ BITCLR( pNFC->NFC_CTRL, HwNFC_CTRL_MASK_EN );
++ continue;
++ }
++ /* Check Device ID */
++ for ( k = 0; k < NAND_SupportMakerInfo.MaxSupportNAND[bFindMakerNo]; ++k )
++ {
++ bMatchCount = 0;
++
++ for ( l = 0; l < 5; ++l )
++ {
++ if ( sTempFeatureInfo->DeviceID.Code[l+1] == 0x00 )
++ ++bMatchCount;
++ else if ( sDeviceCode1.Code[l+1] == sTempFeatureInfo->DeviceID.Code[l+1] )
++ ++bMatchCount;
++ }
++
++ /* Found NAND Device */
++ if ( bMatchCount >= 5 )
++ {
++ bFindMedia = TRUE;
++ sFindFeatureInfo = sTempFeatureInfo;
++ break;
++ }
++ else
++ ++sTempFeatureInfo;
++ }
++
++ /* Found NAND Device */
++ if ( bFindMedia == TRUE )
++ break;
++ else
++ BITCLR( pNFC->NFC_CTRL, HwNFC_CTRL_MASK_EN );
++ }
++ }
++
++ //=====================================================================
++ // If Media is founded
++ //=====================================================================
++ if ( bFindMedia == TRUE )
++ {
++ /* Get NAND Feature Info */
++ memcpy( (void*)&nDevInfo->Feature,
++ (void*)sFindFeatureInfo,
++ sizeof(NAND_IO_FEATURE) );
++
++ /* Get ECC Type Info */
++ if ( nDevInfo->Feature.MediaType & A_SLC )
++ {
++ //nDevInfo->EccType = TYPE_ECC_FOR_1BIT_SLC_NANDFLASH;
++ nDevInfo->EccType = TYPE_ECC_FOR_4BIT_MLC_NANDFLASH;
++ nDevInfo->EccDataSize = 8;
++ }
++ else if ( nDevInfo->Feature.MediaType & A_MLC )
++ {
++ nDevInfo->EccType = TYPE_ECC_FOR_4BIT_MLC_NANDFLASH;
++ nDevInfo->EccDataSize = 8;
++ }
++ else if ( nDevInfo->Feature.MediaType & A_MLC_8BIT )
++ {
++ nDevInfo->EccType = TYPE_ECC_FOR_8BIT_MLC_NANDFLASH;
++ nDevInfo->EccDataSize = 20;
++ nDevInfo->Feature.SpareSize = 192;
++ }
++ else if ( nDevInfo->Feature.MediaType & A_MLC_12BIT )
++ {
++ nDevInfo->EccType = TYPE_ECC_FOR_12BIT_MLC_NANDFLASH;
++ nDevInfo->EccDataSize = 20;
++ nDevInfo->Feature.SpareSize = 192;
++ }
++ else if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ {
++ nDevInfo->EccType = TYPE_ECC_FOR_16BIT_MLC_NANDFLASH;
++ nDevInfo->EccDataSize = 26;
++ nDevInfo->Feature.SpareSize = 436;
++ }
++
++ if ( nDevInfo->Feature.PageSize == 4096 )
++ nDevInfo->DistrictNum = 1024;
++ else
++ nDevInfo->DistrictNum = 2048;
++
++ //=====================================================================
++ //EXCEPTION: TH58NVG4D1D/5D1DTG20 TH58NVG6D1DTG20
++ //=====================================================================
++ if ( ( nDevInfo->Feature.DeviceID.Code[0]== 0x98 ) && ( nDevInfo->Feature.DeviceID.Code[1] == 0xD5 ) && ( nDevInfo->Feature.DeviceID.Code[2] == 0x94 ))
++ nDevInfo->DistrictNum = 2048;
++
++ if ( ( nDevInfo->Feature.DeviceID.Code[0]== 0x98 ) && ( nDevInfo->Feature.DeviceID.Code[1] == 0xD7 ) )
++ nDevInfo->DistrictNum = 2048;
++
++ if ( nDevInfo->Feature.MediaType & A_08BIT )
++ {
++ #ifndef NAND_8BIT_ONLY
++ /* Check if compositin of NAND is parallel or serial */
++ NAND_IO_ResetForReadID( nChipNo, NAND_IO_PARALLEL_COMBINATION_MODE );
++ NAND_IO_ReadID( nChipNo, &sDeviceCode2, NAND_IO_PARALLEL_COMBINATION_MODE );
++
++ if ( ((sDeviceCode2.Code[0] & 0xFF) == ((sDeviceCode2.Code[0] >> 8) & 0xFF)) &&
++ ((sDeviceCode2.Code[1] & 0xFF) == ((sDeviceCode2.Code[1] >> 8) & 0xFF)) &&
++ ((sDeviceCode2.Code[2] & 0xFF) == ((sDeviceCode2.Code[2] >> 8) & 0xFF)) &&
++ ((sDeviceCode2.Code[3] & 0xFF) == ((sDeviceCode2.Code[3] >> 8) & 0xFF)) &&
++ ((sDeviceCode2.Code[4] & 0xFF) == ((sDeviceCode2.Code[4] >> 8) & 0xFF)) )
++ {
++ nDevInfo->Feature.MediaType |= A_PARALLEL;
++ nDevInfo->Feature.MediaType |= A_DATA_WITDH_16BIT;
++ nDevInfo->Feature.PageSize *= 2;
++ nDevInfo->Feature.SpareSize *= 2;
++ nDevInfo->CmdMask = 0xFFFF;
++ }
++ else
++ {
++ nDevInfo->Feature.MediaType |= A_DATA_WITDH_08BIT;
++ nDevInfo->CmdMask = 0x00FF;
++ }
++
++ #else
++ nDevInfo->Feature.MediaType |= A_DATA_WITDH_08BIT;
++ nDevInfo->CmdMask = 0x00FF;
++ #endif
++ }
++ else
++ {
++ //IO_CKC_EnableBUS( IO_CKC_BUS_NFC );
++ // 16Bit NAND Mask Enable
++ BITSET( pNFC->NFC_CTRL, HwNFC_CTRL_MASK_EN );
++ nDevInfo->Feature.MediaType |= A_DATA_WITDH_16BIT;
++ nDevInfo->CmdMask = 0x00FF;
++ }
++
++ /* Get Total Partial Page [512+16Bytes] */
++ nDevInfo->PPages = ( nDevInfo->Feature.PageSize / 512 );
++
++ /* Get Shift Factors of PBpV, PpB, PageSize, SpareSize, PPages */
++ res = (NAND_IO_ERROR)SUCCESS;
++ res |= NAND_IO_GetShiftValueForFastMultiPly( nDevInfo->Feature.PBpV, &nDevInfo->ShiftPBpV );
++ res |= NAND_IO_GetShiftValueForFastMultiPly( nDevInfo->Feature.PpB, &nDevInfo->ShiftPpB );
++ res |= NAND_IO_GetShiftValueForFastMultiPly( nDevInfo->Feature.PageSize, &nDevInfo->ShiftPageSize );
++ res |= NAND_IO_GetShiftValueForFastMultiPly( nDevInfo->PPages, &nDevInfo->ShiftPPages );
++ res |= NAND_IO_GetShiftValueForFastMultiPly( nDevInfo->DistrictNum, &nDevInfo->ShiftDistrictNum );
++
++ nDevInfo->EccWholeDataSize = ( nDevInfo->EccDataSize << nDevInfo->ShiftPPages );
++
++ if ( res != SUCCESS )
++ return res;
++
++ for ( j = 0; j < 4; ++j )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[j] = MULTI_PLANE_GOOD_BLOCK;
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[j] = 0xFFFFFFFF;
++ }
++
++ NAND_IO_SetCycle( nDevInfo );
++ }
++ //=====================================================================
++ // Not Found
++ //=====================================================================
++ else
++ {
++ #if defined(USE_V_ADDRESS) && defined(_WINCE_)
++ #else
++ if ( nChipNo == 0 )
++ {
++ ND_TRACE("\n[NAND ] No NAND device found!!! ID:");
++ for ( j = 0; j < 4; ++j )
++ ND_TRACE("0x%x ", ( sDeviceCode1.Code[j] & 0xFF ) );
++ }
++ #endif
++
++ return ERR_NAND_IO_FAILED_GET_DEVICE_INFO;
++ }
++
++ nDevInfo->IoStatus = NAND_IO_STATUS_ENABLE;
++ nDevInfo->ChipNo = nChipNo;
++
++ //=====================================================================
++ // gDevInfo( Global Variable ) Initialize
++ //=====================================================================
++ if ( nDevInfo->ChipNo == 0 )
++ gDevInfo = (NAND_IO_DEVINFO *)nDevInfo;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* U32 NAND_IO_GetBUSTypeOfDataIO( void )
++*
++* Input : NONE
++* Output : NONE
++* Return : NONE
++*
++* Description : Initialize NAND IO Layer
++*
++*******************************************************************************/
++U32 NAND_IO_GetBUSTypeOfDataIO( void )
++{
++ return gNAND_IO_DataBusType;
++}
++
++void NAND_IO_ECC_InfoInit( void )
++{
++ gMLC_ECC_1Bit.EccDataSize = 7;
++ //gMLC_ECC_1Bit.EncodeFlag = HwECC_IREQ_M1EF;
++ //gMLC_ECC_1Bit.DecodeFlag = HwECC_IREQ_M1DF;
++ gMLC_ECC_1Bit.ErrorNum = 1;
++ gMLC_ECC_1Bit.All_FF_512_ECC_Code = (U8 *)&ALL_FF_ECC_BCH_01BIT_512;
++
++ gMLC_ECC_4Bit.EccDataSize = 7;
++ gMLC_ECC_4Bit.EncodeFlag = HwECC_IREQ_M4EF;
++ gMLC_ECC_4Bit.DecodeFlag = HwECC_IREQ_M4DF;
++ gMLC_ECC_4Bit.ErrorNum = 4;
++ gMLC_ECC_4Bit.All_FF_512_ECC_Code = (U8 *)&ALL_FF_ECC_BCH_04BIT_512;
++
++ gMLC_ECC_8Bit.EccDataSize = 13;
++ gMLC_ECC_8Bit.EncodeFlag = HwECC_IREQ_M8EF;
++ gMLC_ECC_8Bit.DecodeFlag = HwECC_IREQ_M8DF;
++ gMLC_ECC_8Bit.ErrorNum = 8;
++ gMLC_ECC_8Bit.All_FF_512_ECC_Code = (U8 *)&ALL_FF_ECC_BCH_08BIT_512;
++
++ gMLC_ECC_12Bit.EccDataSize = 20;
++ gMLC_ECC_12Bit.EncodeFlag = HwECC_IREQ_M12EF;
++ gMLC_ECC_12Bit.DecodeFlag = HwECC_IREQ_M12DF;
++ gMLC_ECC_12Bit.ErrorNum = 12;
++ gMLC_ECC_12Bit.All_FF_512_ECC_Code = (U8 *)&ALL_FF_ECC_BCH_12BIT_512;
++
++ gMLC_ECC_14Bit.EccDataSize = 23;
++ gMLC_ECC_14Bit.EncodeFlag = HwECC_IREQ_M14EF;
++ gMLC_ECC_14Bit.DecodeFlag = HwECC_IREQ_M14DF;
++ gMLC_ECC_14Bit.ErrorNum = 14;
++ gMLC_ECC_14Bit.All_FF_512_ECC_Code = (U8 *)&ALL_FF_ECC_BCH_14BIT_512;
++
++ gMLC_ECC_16Bit.EccDataSize = 26;
++ gMLC_ECC_16Bit.EncodeFlag = HwECC_IREQ_M16EF;
++ gMLC_ECC_16Bit.DecodeFlag = HwECC_IREQ_M16DF;
++ gMLC_ECC_16Bit.ErrorNum = 16;
++ gMLC_ECC_16Bit.All_FF_512_ECC_Code = (U8 *)&ALL_FF_ECC_BCH_16BIT_512;
++
++ memset( gNAND_IO_TempBuffer, 0xFF, 32 );
++}
++
++void NAND_IO_InitDMABuffer( void )
++{
++ #if defined(_WINCE_)
++ tSYSTEM_PARAM *pSYS_Work_PARAM = (tSYSTEM_PARAM*)(SYSTEM_PARAM_BASEADDRESS);
++ #endif
++
++ #if defined(_WINCE_)
++ gpDMA_PhyBuffer0 = (unsigned int*)pSYS_Work_PARAM->DMA2.CH0_BUFFER; // Working Address
++ gpDMA_WorkBuffer0 = (unsigned int*)pSYS_PARAM->DMA2.CH0_BUFFER; // Physical Address
++ gpDMA_PhyBuffer1 = (unsigned int*)pSYS_Work_PARAM->DMA2.CH1_BUFFER; // Working Address
++ gpDMA_WorkBuffer1 = (unsigned int*)pSYS_PARAM->DMA2.CH1_BUFFER; // Physical Address
++ #elif defined(_LINUX_)
++ #ifdef KERNEL_DRIVER
++ gpDMA_PhyBuffer0 = (unsigned int*)dma_t.dma_addr;
++ gpDMA_WorkBuffer0 = (unsigned int*)dma_t.v_addr;
++ gpDMA_PhyBuffer1 = (unsigned int*)((unsigned char*)gpDMA_PhyBuffer0 + 512);
++ gpDMA_WorkBuffer1 = (unsigned int*)((unsigned char*)gpDMA_WorkBuffer0 + 512);
++ gNAND_IO_ShareEccBuffer_w = (unsigned char*)gpDMA_PhyBuffer1 + 512;
++ gNAND_IO_ShareEccBuffer = (unsigned char*)gpDMA_WorkBuffer1 + 512;
++ #else
++ gpDMA_PhyBuffer0 = (unsigned int*)DMA_ADDR;
++ gpDMA_WorkBuffer0 = (unsigned int*)DMA_ADDR;
++ gpDMA_PhyBuffer1 = (unsigned int*)DMA_ADDR + 512;
++ gpDMA_WorkBuffer1 = (unsigned int*)DMA_ADDR + 512;
++ #endif
++ #else // NU
++ gpDMA_PhyBuffer0 = (unsigned int*)gpNandBuffer;
++ gpDMA_WorkBuffer0 = (unsigned int*)gpNandBuffer;
++ gpDMA_PhyBuffer1 = (unsigned char*)gpDMA_PhyBuffer0 + 512;
++ gpDMA_WorkBuffer1 = (unsigned char*)gpDMA_WorkBuffer0 + 512;
++ #endif
++
++// ND_TRACE("\nDMA_PhyBufferAddr0:0x%X", gpDMA_PhyBuffer0);
++// ND_TRACE("\nDMA_WorkBufferAddr0:0x%X", gpDMA_WorkBuffer0);
++// ND_TRACE("\nDMA_PhyBufferAddr1:0x%X", gpDMA_PhyBuffer1);
++// ND_TRACE("\nDMA_WorkBufferAdd1r:0x%X", gpDMA_WorkBuffer1);
++}
++
++/******************************************************************************
++*
++* void NAND_IO_Init( void )
++*
++* Input : NONE
++* Output : NONE
++* Return : NONE
++*
++* Description : Initialize NAND IO Layer
++*
++*******************************************************************************/
++void NAND_IO_Init( void )
++{
++ unsigned int i;
++ PEDI pEDI;
++ NAND_IO_DEVINFO sDevInfo;
++ NAND_IO_ERROR res;
++
++ memset( &sDevInfo, 0x00, sizeof(NAND_IO_DEVINFO));
++
++#if defined(USE_V_ADDRESS)
++ #if defined(_LINUX_)
++ pGPIO = (PGPIO)(&HwGPIO_BASE);
++ pEDI = (PEDI)(&HwEDI_BASE);
++ pNFC = (PNFC)(&HwNFC_BASE);
++ pECC = (PECC)(&HwECC_BASE);
++ pIOBUSCFG_T = (PIOBUSCFG)(&HwIOBUSCFG_BASE);
++ pNAND_DMA = (PGDMANCTRL)(&HwGDMA2_BASE);
++ #if defined(_WINCE_)
++ pSYS_PARAM = (ptSYSTEM_PARAM)(&SYSTEM_PARAM_BASEADDRESS);
++ #endif
++ pPIC = (PPIC)(&HwPIC_BASE);
++ #elif defined(_WINCE_)
++ pGPIO = (PGPIO)tcc_allocbaseaddress((unsigned int)&HwGPIO_BASE);
++ pEDI = (PEDI)tcc_allocbaseaddress((unsigned int)&HwEDI_BASE);
++ pNFC = (PNFC)tcc_allocbaseaddress((unsigned int)&HwNFC_BASE);
++ pECC = (PECC)tcc_allocbaseaddress((unsigned int)&HwECC_BASE);
++ pIOBUSCFG_T = (PIOBUSCFG)tcc_allocbaseaddress((unsigned int)&HwIOBUSCFG_BASE);
++ pPIC = (PPIC)tcc_allocbaseaddress((unsigned int)&HwPIC_BASE);
++ pSYS_PARAM = (tSYSTEM_PARAM*)tcc_allocbaseaddress((unsigned int)SYSTEM_PARAM_BASEADDRESS);
++ pNAND_DMA = (PGDMANCTRL)tcc_allocbaseaddress((unsigned int)&HwGDMA2_BASE);
++ #endif
++#else
++ pGPIO = (PGPIO)(&HwGPIO_BASE);
++ pEDI = (PEDI)(&HwEDI_BASE);
++ pNFC = (PNFC)(&HwNFC_BASE);
++ pECC = (PECC)(&HwECC_BASE);
++ pIOBUSCFG_T = (PIOBUSCFG)(&HwIOBUSCFG_BASE);
++ pPIC = (PPIC)(&HwPIC_BASE);
++ #if defined(_WINCE_)
++ pSYS_PARAM = (tSYSTEM_PARAM*)(SYSTEM_PARAM_BASEADDRESS);
++ #endif
++ pNAND_DMA = (PGDMANCTRL)(&HwGDMA2_BASE);
++#endif
++
++ /*************************************/
++ /*Don't remove NAND_IO_Delay Function*/
++ /*************************************/
++ for( i = 0; i < 5000; ++i )
++ NAND_IO_Delay();
++
++ for ( i = 0; i < 2; ++i )
++ {
++ /***********************************/
++ /* Setting NANDFLASH on Memory Bus */
++ /***********************************/
++ if ( i == 0 )
++ {
++ ASM_NOP;
++ }
++ /********************************/
++ /* Setting NANDFLASH on NFC Bus */
++ /********************************/
++ else
++ {
++ pEDI->EDI_RDYCFG = 0x00000001;
++ //pEDI->EDI_CSNCFG0 = 0x00403265;
++ BITCSET(pEDI->EDI_CSNCFG0, 0xFFFF, 0x8765 );
++
++ pGPIO->GPBFN0 = 0x11112222; //NANDXD[7:4]
++ pGPIO->GPBFN1 = 0x00221111; //NANDXD[3:0]
++ pGPIO->GPBFN2 = 0x10111010; //NANDXD[11:8],[7:4]
++ pGPIO->GPBFN3 = 0x00010111; //NANDXD[15:12],[3:0]
++
++ // Write Protect Pin: Output Mode
++ BITSET( pGPIO->GPBEN, NAND_IO_NFC_nWPBit );
++
++ //=================================================
++ // TCC9200S_BOARD NAND Ready/Busy Pin Set
++ /* ND_RDY: GPIO_B31 */
++ //=================================================
++ #if defined(TCC_NAND_RDY_B31)
++ pGPIO->GPBFN3 &= ~0x10000000; // ND_RDY: GPIO_B31
++ BITCLR(pGPIO->GPBEN, Hw31);
++ #endif
++
++ #ifdef __USE_NAND_ISR__
++ NAND_IO_IRQ_ReadyBusyClear();
++ #endif
++
++ gNAND_IO_DataBusType = NAND_IO_NFC_BUS;
++
++ /* Make Reset */
++ pNFC->NFC_RST = 0;
++
++ /* Set Default NFC Configuration */
++ #ifdef __USE_NAND_ISR__
++ pNFC->NFC_CTRL = HwNFC_CTRL_PROGIEN_EN |
++ HwNFC_CTRL_READIEN_EN |
++ HwNFC_CTRL_DEN_EN |
++ HwNFC_CTRL_CFG_NOACT |
++ HwNFC_CTRL_BSIZE_1 |
++ (4 << 4) | // pw = 5
++ (1 << 0); // hold = 1
++
++ #else
++ pNFC->NFC_CTRL = HwNFC_CTRL_DEN_EN |
++ HwNFC_CTRL_CFG_NOACT |
++ HwNFC_CTRL_BSIZE_1 |
++ (4 << 4) | // pw = 5
++ (1 << 0); // hold = 1
++ #endif
++
++ /* GPIO B Arbitration ENABLE */
++ pNFC->NFC_CTRL1 |= Hw31;
++ pNFC->NFC_CTRL1 |= Hw30;
++
++ /* Enable Interrupt */
++ pNFC->NFC_IREQ = 0x77; // Clear Interrupt
++ BITSET( pPIC->CLR1,HwINT1_NFC );
++ BITSET( pPIC->SEL1, HwINT1_NFC); // Set NFC as IRQ interrupt
++ BITSET( pPIC->MODE1, HwINT1_NFC ); // Level type for NFC interrupt, IO_INT_HwNFC ); // Level type for NFC interrupt
++
++ //IO_CKC_DisableBUS( IO_CKC_BUS_NFC );
++
++ /* Searching NANDFLASH */
++ res = NAND_IO_GetDeviceInfo( 0, &sDevInfo );
++
++ #ifdef NAND_GPIO_DEBUG
++ BITCSET(pGPIO->GPFFN2, 0x0FF000FF, 0x00000000);
++ BITSET(pGPIO->GPFEN, Hw16);
++ BITSET(pGPIO->GPFEN, Hw17);
++ BITSET(pGPIO->GPFEN, Hw21);
++ BITSET(pGPIO->GPFEN, Hw22);
++
++ // Clear
++ BITCLR(pGPIO->GPFDAT, Hw16);
++ BITCLR(pGPIO->GPFDAT, Hw17);
++ BITCLR(pGPIO->GPFDAT, Hw21);
++ BITCLR(pGPIO->GPFDAT, Hw22);
++ #endif
++
++ if ( res == SUCCESS )
++ break;
++ }
++ }
++
++ /* Setup Variable about ECC */
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++ pECC->ECC_CTRL = 0x04000000; /* ECC Control Register */
++ pECC->ECC_BASE = pNFC->NFC_WDATA; /* Base Address for ECC Calculation */
++ pECC->ECC_MASK = 0x00000000; /* Address mask for ECC area */
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++
++ memcpy( &rDevInfo, &sDevInfo, sizeof(NAND_IO_DEVINFO) );
++
++ NAND_IO_ECC_InfoInit();
++
++ #ifdef NAND_IO_USE_DMA_ACCESS
++ NAND_IO_InitDMABuffer();
++ #endif
++}
++
++/******************************************************************************
++*
++* void NAND_IO_Reset
++*
++* Input : Chip Select Number
++* Output : NONE
++* Return : NONE
++*
++* Description : Reset NANDFLASH
++*
++*******************************************************************************/
++void NAND_IO_Reset( U16 nChipNo, int nMode )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nChipNo );
++
++ /* Set Data Bus as 16Bit */
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++
++ /* Command RESET [ 0xFF ] */
++ if ( nMode == NAND_IO_PARALLEL_COMBINATION_MODE )
++ pNFC->NFC_CMD = 0xFFFF;
++ else
++ pNFC->NFC_CMD = 0x00FF;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++}
++
++/******************************************************************************
++*
++* void NAND_IO_ResetForReadID
++*
++* Input : Chip Select Number
++* Output : NONE
++* Return : NONE
++*
++* Description : Reset NANDFLASH
++*
++*******************************************************************************/
++void NAND_IO_ResetForReadID( U16 nChipNo, int nMode )
++{
++ unsigned int i,j;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nChipNo );
++
++ /* Set Data Bus as 16Bit */
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++
++ /* Command RESET [ 0xFF ] */
++ if ( nMode == NAND_IO_PARALLEL_COMBINATION_MODE )
++ pNFC->NFC_CMD = 0xFFFF;
++ else
++ pNFC->NFC_CMD = 0x00FF;
++
++ /* Wait until it is ready */
++ for ( i = 0; i < 0x100; ++i )
++ {
++ for ( j = 0; j < 0x80; ++j )
++ {
++ ASM_NOP;
++ }
++ }
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++}
++
++/******************************************************************************
++*
++* void NAND_IO_ReadID
++*
++* Input : Chip Select Number
++* Mode : 0 => Serial Composition , 1 => Parallel Composition
++* Output : NANDFLASH Device Code
++* Return : NONE
++*
++* Description : Get Device Code of NANDFLASH
++*
++*******************************************************************************/
++void NAND_IO_ReadID( U16 nChipNo, NAND_IO_DEVID *nDeviceCode, int nMode )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nChipNo );
++
++ /* Set Data Bus as 16Bit */
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++
++ /* Parallel Composition */
++ if ( nMode == NAND_IO_PARALLEL_COMBINATION_MODE )
++ {
++ pNFC->NFC_CMD = 0x9090; /* Command READ ID [ 0x90 ] */
++ pNFC->NFC_SADDR = 0x0000; /* Address [ 0x00 ] */
++ }
++ /* Serial Composition */
++ else
++ {
++ pNFC->NFC_CMD = 0x0090; /* Command READ ID [ 0x90 ] */
++ pNFC->NFC_SADDR = 0x0000; /* Address [ 0x00 ] */
++ }
++
++ /* Delay : tAR1[READID] Max 200nS */
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++
++ /* Parallel Composition */
++ if ( nMode == NAND_IO_PARALLEL_COMBINATION_MODE )
++ {
++ nDeviceCode->Code[0] = (U16)pNFC->NFC_SDATA;
++ nDeviceCode->Code[1] = (U16)pNFC->NFC_SDATA;
++ nDeviceCode->Code[2] = (U16)pNFC->NFC_SDATA;
++ nDeviceCode->Code[3] = (U16)pNFC->NFC_SDATA;
++ nDeviceCode->Code[4] = (U16)pNFC->NFC_SDATA;
++ nDeviceCode->Code[5] = (U16)pNFC->NFC_SDATA;
++ }
++ /* Serial Composition */
++ else
++ {
++ nDeviceCode->Code[0] = (U8)( pNFC->NFC_SDATA & 0xFF );
++ nDeviceCode->Code[1] = (U8)( pNFC->NFC_SDATA & 0xFF );
++ nDeviceCode->Code[2] = (U8)( pNFC->NFC_SDATA & 0xFF );
++ nDeviceCode->Code[3] = (U8)( pNFC->NFC_SDATA & 0xFF );
++ nDeviceCode->Code[4] = (U8)( pNFC->NFC_SDATA & 0xFF );
++ nDeviceCode->Code[5] = (U8)( pNFC->NFC_SDATA & 0xFF );
++ }
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadSpare
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadSpare( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U8 *nSpareBuffer )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Data
++ //=============================================
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, nDevInfo->Feature.PageSize, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadSpare;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Read Spare data from NANDFLASH */
++ res = NAND_IO_ReadSpareData( nDevInfo,
++ nSpareBuffer,
++ PAGE_ECC_OFF );
++ if ( res != SUCCESS )
++ goto ErrorReadSpare;
++
++ErrorReadSpare:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ unsigned int nSpareOnOff;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ) )
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ //=============================================
++ // Read Data
++ //=============================================
++ /* Generate Row and Column Address */
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, nDevInfo->Feature.PageSize, &RowAddr, &ColumnAddr, nDevInfo );
++ else
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, ( nStartPPage << 9 ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ /* Read Page Size data from NANDFLASH */
++ nSpareOnOff = TNFTL_READ_SPARE_ON;
++
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++ res = NAND_IO_ReadSpareData( nDevInfo, nSpareBuffer, PAGE_ECC_ON );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ /* Command Random Data Output [ 0x05 ] for Advance NandFlash */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0505;
++
++ ColumnAddr = ( nStartPPage << 9 );
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (ColumnAddr >> 1) : ColumnAddr;
++
++ NAND_IO_WriteColAddr( ColumnAddr, nDevInfo );
++
++ /* Command Random Data Output [ 0xE0 ] for Advance NandFlash */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xE0E0;
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++ }
++ else if (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL ))
++ {
++ res = NAND_IO_ReadSpareData( nDevInfo, nSpareBuffer, PAGE_ECC_ON );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, ( nStartPPage << 9 ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++ }
++
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF)
++ res = NAND_IO_Read512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #else
++ res = NAND_IO_Read512Data( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #endif
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ErrorReadPage:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadPhyPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadPhyPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ unsigned int nSpareOnOff;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ) )
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ //=============================================
++ // Read Data
++ //=============================================
++ /* Generate Row and Column Address */
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, nDevInfo->Feature.PageSize, &RowAddr, &ColumnAddr, nDevInfo );
++ else
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, ( nStartPPage << 9 ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ /* Read Page Size data from NANDFLASH */
++ nSpareOnOff = TNFTL_READ_SPARE_ON;
++
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++ //res = NAND_IO_ReadSpareData( nDevInfo, nSpareBuffer, PAGE_ECC_ON );
++ res = NAND_IO_ReadUserSizeData( nDevInfo, ( nDevInfo->PPages << 9 ), nDevInfo->Feature.SpareSize, nSpareBuffer );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ /* Command Random Data Output [ 0x05 ] for Advance NandFlash */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0505;
++
++ ColumnAddr = ( nStartPPage << 9 );
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (ColumnAddr >> 1) : ColumnAddr;
++
++ NAND_IO_WriteColAddr( ColumnAddr, nDevInfo );
++
++ /* Command Random Data Output [ 0xE0 ] for Advance NandFlash */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xE0E0;
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++ }
++ else if (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL ))
++ {
++ res = NAND_IO_ReadUserSizeData( nDevInfo, ( nDevInfo->PPages << 9 ), nDevInfo->Feature.SpareSize, nSpareBuffer );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, ( nStartPPage << 9 ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++ }
++
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF)
++ res = NAND_IO_Read512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #else
++ res = NAND_IO_Read512Data( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #endif
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ErrorReadPage:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadPageMTD
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadPageMTD( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ unsigned int nSpareOnOff;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ) )
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ //=============================================
++ // Read Data
++ //=============================================
++ /* Generate Row and Column Address */
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, nDevInfo->Feature.PageSize, &RowAddr, &ColumnAddr, nDevInfo );
++ else
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, ( nStartPPage << 9 ), &RowAddr, &ColumnAddr, nDevInfo );
++
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ /* Read Page Size data from NANDFLASH */
++ nSpareOnOff = TNFTL_READ_SPARE_ON;
++
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++ res = NAND_IO_ReadSpareDataMTD( nDevInfo, nSpareBuffer, PAGE_ECC_ON );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ /* Command Random Data Output [ 0x05 ] for Advance NandFlash */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0505;
++
++ ColumnAddr = ( nStartPPage << 9 );
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (ColumnAddr >> 1) : ColumnAddr;
++
++ NAND_IO_WriteColAddr( ColumnAddr, nDevInfo );
++
++ /* Command Random Data Output [ 0xE0 ] for Advance NandFlash */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xE0E0;
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++ }
++ else if (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL ))
++ {
++ res = NAND_IO_ReadSpareDataMTD( nDevInfo, nSpareBuffer, PAGE_ECC_ON );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, ( nStartPPage << 9 ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++ }
++
++ res = NAND_IO_Read512DataMTD( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ErrorReadPage:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadTwoPlanePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadTwoPlanePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U32 nSecondPageAddr,
++ U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ) )
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_WaitBusyForInterleave( nDevInfo, nPageAddr );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ //=============================================
++ // PRE-Operation
++ //=============================================
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Two-Plane Page Read Command [0x60] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x6060;
++
++ /* Write Row Address: Fixed 'Low' */
++ NAND_IO_WriteBlockPageAddr( 0, nDevInfo );
++
++ /* Two-Plane Page Read Command 2 [0x60] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x6060;
++
++ NAND_IO_WriteBlockPageAddr( nSecondPageAddr, nDevInfo );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ //=============================================
++ // Read Data
++ //=============================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ /* Write Col & Row Address: Fixed 'Low' */
++ NAND_IO_WriteRowColAddr( 0, 0, nDevInfo );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0505;
++
++ /* Write Col Address: Valid */
++ NAND_IO_WriteColAddr( ColumnAddr, nDevInfo );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xE0E0;
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ /* Read Page Size data from NANDFLASH */
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF)
++ res = NAND_IO_Read512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #else
++ res = NAND_IO_Read512Data( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #endif
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ErrorReadPage:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadTwoPlaneLastPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadTwoPlaneLastPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ) )
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Data
++ //=============================================
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadPage;
++
++ /* Write Col & Row Address: Col Addr = Fixed 'Low' */
++ NAND_IO_WriteRowColAddr( RowAddr, 0, nDevInfo );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0505;
++
++ /* Write Col Address: Valid */
++ NAND_IO_WriteColAddr( ColumnAddr, nDevInfo );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xE0E0;
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ /* Read Page Size data from NANDFLASH */
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF)
++ res = NAND_IO_Read512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #else
++ res = NAND_IO_Read512Data( nDevInfo,
++ nStartPPage,
++ nReadPPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff,
++ TNFTL_READ_SPARE_ON );
++ #endif
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ErrorReadPage:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_ReadUserSizePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_ReadUserSizePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nColumnAddr, U32 nReadSize, U8 *nReadBuffer )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( (U32)( nColumnAddr + nReadSize ) > (U16)( nDevInfo->Feature.PageSize + nDevInfo->Feature.SpareSize ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ //=============================================
++ // Read UserSize Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, nColumnAddr, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorReadUserSizePage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ /* Read User Size data from NANDFLASH */
++ res = NAND_IO_ReadUserSizeData( nDevInfo,
++ nColumnAddr,
++ nReadSize,
++ nReadBuffer );
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorReadUserSizePage;
++
++ErrorReadUserSizePage:
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WriteSpare
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WriteSpare( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U8* nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ nEccOnOff = 0;
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ {
++ res = NAND_IO_WaitBusyForInterleave( nDevInfo, nPageAddr );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++ }
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Write Data
++ //=============================================
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, nDevInfo->Feature.PageSize, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ res = NAND_IO_WriteSpareData( nDevInfo, nSpareBuffer, PAGE_ECC_OFF );
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ {
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWritePage;
++ }
++ }
++ else
++ {
++ NAND_IO_SetInterleaveStatus( nDevInfo, nPageAddr );
++ gInterLeavePageAddr = nPageAddr;
++ }
++ErrorWritePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ NAND_IO_EnableWriteProtect();
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WritePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WritePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ {
++ res = NAND_IO_WaitBusyForInterleave( nDevInfo, nPageAddr );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++ }
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Write Data
++ //=============================================
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, ( nStartPPage << 9 ), &RowAddr, &ColumnAddr, nDevInfo );
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF_WRITE)
++ res = NAND_IO_Write512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #else
++ res = NAND_IO_Write512Data( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #endif
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ {
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWritePage;
++ }
++ }
++ else
++ {
++ NAND_IO_SetInterleaveStatus( nDevInfo, nPageAddr );
++ gInterLeavePageAddr = nPageAddr;
++ }
++
++ErrorWritePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ NAND_IO_EnableWriteProtect();
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WritePageMTD
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WritePageMTD( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ {
++ res = NAND_IO_WaitBusyForInterleave( nDevInfo, nPageAddr );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++ }
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Write Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, ( ( 512 + nDevInfo->EccDataSize ) * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++ else
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, ( 528 * nStartPPage ), &RowAddr, &ColumnAddr, nDevInfo );
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ res = NAND_IO_Write512DataMTD( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ {
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWritePage;
++ }
++ }
++ else
++ {
++ NAND_IO_SetInterleaveStatus( nDevInfo, nPageAddr );
++ gInterLeavePageAddr = nPageAddr;
++ }
++
++ErrorWritePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ NAND_IO_EnableWriteProtect();
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WriteCachePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WriteCachePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Write Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nPageAddr, ( nStartPPage << 9 ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF_WRITE)
++ res = NAND_IO_Write512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #else
++ res = NAND_IO_Write512Data( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #endif
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #2 [ 0x15 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1515;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForCacheProgram( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatusForCacheProgram( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWritePage;
++ }
++
++ErrorWritePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ //NAND_IO_EnableWriteProtect();
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WriteTwoPlanePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WriteTwoPlanePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8* nSpareBuffer, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ unsigned long int dwTempPHYPageAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ {
++ res = NAND_IO_WaitBusyForInterleave( nDevInfo, nPageAddr );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++ }
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Write Data
++ //=============================================
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == HYNIX_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID ) )
++ {
++ if ( ( nDevInfo->Feature.MediaType & A_MLC ) || ( nDevInfo->Feature.MediaType & A_SLC ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ {
++ dwTempPHYPageAddr = ( ( nDevInfo->Feature.PBpV << nDevInfo->ShiftPpB ) >> 1 );
++
++ if ( nPageAddr & dwTempPHYPageAddr )
++ nPageAddr = dwTempPHYPageAddr;
++ else
++ nPageAddr = 0;
++ }
++ }
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nPageAddr, ( nStartPPage << 9 ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF_WRITE)
++ res = NAND_IO_Write512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #else
++ res = NAND_IO_Write512Data( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #endif
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Multi Plane Page Program #2 [ 0x11 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1111;
++
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ NAND_IO_WaitBusyForCacheProgram( nDevInfo );
++
++ErrorWritePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WriteTwoPlaneLastPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WriteTwoPlaneLastPage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8* nSpareBuffer, int LastPage, int nEccOnOff )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Write Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nPageAddr, ( nStartPPage << 9 ), &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == HYNIX_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID ) )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8181;
++ else if ( ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == INTEL_NAND_MAKER_ID ))
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ #if defined(NAND_IO_USE_DMA_DOUBLE_BUF_WRITE)
++ res = NAND_IO_Write512DataDoubleBuf( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #else
++ res = NAND_IO_Write512Data( nDevInfo,
++ nStartPPage,
++ nWritePPSize,
++ nPageBuffer,
++ nSpareBuffer,
++ nEccOnOff );
++ #endif
++
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWritePage;
++
++ /* Command Page Program #2 [ 0x10 ] */
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID ) )
++ {
++ if ( ( LastPage == MULTI_PLANE_LAST_PAGE ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ else if ( LastPage == MULTI_PLANE_MID_PAGE )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1515;
++ }
++ else
++ {
++ // SAMSUNG, HYNIX, MICRON, INTEL, ST Maker TwoPlane Write Function
++ if ( nDevInfo->Feature.MediaType & S_MCP )
++ {
++ if ( LastPage == MULTI_PLANE_LAST_PAGE )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ else if ( LastPage == MULTI_PLANE_MID_PAGE )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1515;
++ }
++ else
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ }
++
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ {
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ if ( LastPage == MULTI_PLANE_LAST_PAGE )
++ {
++ res = NAND_IO_ReadStatusForMultiPlane( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWritePage;
++ }
++ }
++ }
++ else
++ {
++ NAND_IO_SetInterleaveStatus( nDevInfo, nPageAddr );
++ gInterLeavePageAddr = nPageAddr;
++ }
++
++ErrorWritePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ //NAND_IO_EnableWriteProtect();
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_WriteUserSizePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_WriteUserSizePage( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nColumnAddr, U32 nWriteSize, U8 *nWriteBuffer )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ if ( (U32)( nColumnAddr + nWriteSize ) > (U16)( nDevInfo->Feature.PageSize + nDevInfo->Feature.SpareSize ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Write UserSize Data
++ //=============================================
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, nColumnAddr, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorWriteUserSizePage;
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ /* Write Data to NAND FLASH */
++ res = NAND_IO_WriteUserSizeData( nDevInfo,
++ nColumnAddr,
++ nWriteSize,
++ nWriteBuffer );
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( res != SUCCESS )
++ goto ErrorWriteUserSizePage;
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = nPageAddr;
++ res = ERR_NAND_IO_FAILED_WRITE;
++
++ goto ErrorWriteUserSizePage;
++ }
++
++ErrorWriteUserSizePage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_EnableWriteProtect();
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_MakeBootBinary
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_MakeBootBinary( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer )
++{
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // ECC Encording
++ //=============================================
++ res = NAND_IO_EncodeBootBinary( nDevInfo, nPageBuffer, ECC_ON );
++
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_EnableWriteProtect();
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_CopyBackPage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_CopyBackPage( NAND_IO_DEVINFO *nDevInfo, U32 nDesPageAddr, U32 nSrcPageAddr )
++{
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++
++ //=============================================
++ // Read Source Page Address
++ //=============================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ /* Generate Src Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nSrcPageAddr, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* CopyBack Command #1 [ 0x35 ] */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3535;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ //=============================================
++ // Copy Destination Page Address
++ //=============================================
++ /* CopyBack Command #2 */
++ if ( nDevInfo->Feature.MediaType & A_SMALL )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8A8A;
++ else
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8585;
++
++ /* Generate Des Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nDesPageAddr, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Waiting TADL Time 200nS */
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++
++ /* CopyBack Command #3 */
++ if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ // [ 32MB] K9F5608U0C, k9F5608U0B, K9F5608U0A
++ // [ 32MB] K9F5608Q0C, K9F5608Q0B
++ if (( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID ) &&
++ (( nDevInfo->Feature.DeviceID.Code[1] == 0x75 ) || ( nDevInfo->Feature.DeviceID.Code[1] == 0x35 )))
++ {
++ // Nothing
++ }
++ else
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ }
++ else
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ErrorCopyBackPage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_EnableWriteProtect();
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_CopyBackTwoPlanePage
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_CopyBackTwoPlanePage( NAND_IO_DEVINFO *nDevInfo, U32 nDesPageAddr, U32 nSrcPageAddr )
++{
++ unsigned int nReBlockPageAddr;
++ unsigned int RowAddr, ColumnAddr;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++
++ //=============================================
++ // Read Source Page Address #1
++ //=============================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ /* Generate Src Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nSrcPageAddr, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* CopyBack Command #1 [ 0x35 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3535;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ //=============================================
++ // Read Source Page Address #2
++ //=============================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ /* Generate Src Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nSrcPageAddr + nDevInfo->Feature.PpB, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* CopyBack Command #1 [ 0x35 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3535;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ //=============================================
++ // Copy Destination Page Address
++ //=============================================
++ /* CopyBack Command #2 */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8585;
++
++ if ( nDesPageAddr & ( nDevInfo->Feature.PBpV / 2) * nDevInfo->Feature.PpB )
++ nReBlockPageAddr = (( nDevInfo->Feature.PBpV / 2) * nDevInfo->Feature.PpB);
++ else
++ nReBlockPageAddr = 0;
++
++ /* Generate Des Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nReBlockPageAddr, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Waiting TADL Time 200nS */
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++
++
++ /* CopyBack Command #3 */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1111;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ //=============================================
++ // Copy Destination Page Address
++ //=============================================
++ /* CopyBack Command #2 */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8181;
++
++ /* Generate Des Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nDesPageAddr+ nDevInfo->Feature.PpB, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Waiting TADL Time 200nS */
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++
++
++ /* CopyBack Command #3 */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorCopyBackPage;
++
++ErrorCopyBackPage:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_EnableWriteProtect();
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_EraseBlock
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_EraseBlock( NAND_IO_DEVINFO *nDevInfo, U32 nBlockPageAddr, int nFormatMode )
++{
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nBlockPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_WaitBusyForInterleave( nDevInfo, nBlockPageAddr );
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Erase Block
++ //=============================================
++
++ /* Command Block Erase #1 [ 0x60 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x6060;
++
++ /* Write Block Address */
++ NAND_IO_WriteBlockPageAddr( nBlockPageAddr, nDevInfo );
++
++ /* Command Erase Block #2 [ 0xD0 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xD0D0;
++
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) || ( nFormatMode == INTER_LEAVE_OFF ) )
++ {
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatus( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[nDevInfo->ChipNo] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[nDevInfo->ChipNo] = nBlockPageAddr;
++ goto ErrorEraseBlock;
++ }
++ }
++ else
++ {
++ NAND_IO_SetInterleaveStatus( nDevInfo, nBlockPageAddr );
++ if ( nDevInfo->BadBlockInfo.BlockStatus[nDevInfo->ChipNo] != MULTI_PLANE_BAD_BLOCK )
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[nDevInfo->ChipNo] = nBlockPageAddr;
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ErrorEraseBlock:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ NAND_IO_EnableWriteProtect();
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_EraseBlockForTwoPlane
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_EraseBlockForTwoPlane( NAND_IO_DEVINFO *nDevInfo, U32 nBlockPageAddr, int nFormatMode )
++{
++ unsigned long int dwTempBlockPageAddr, dwAddSecondPageAddr;
++ unsigned long int nReBlockPageAddr = 0;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nBlockPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_WaitBusyForInterleave( nDevInfo, nBlockPageAddr );
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Erase Block
++ //=============================================
++ /* Command Block Erase #1 [ 0x60 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x6060;
++
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == HYNIX_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID ) )
++ {
++ dwTempBlockPageAddr = ( ( nDevInfo->Feature.PBpV << nDevInfo->ShiftPpB ) >> 1 );
++
++ if ( ( nDevInfo->Feature.MediaType & A_SLC ) ||
++ ( nDevInfo->Feature.MediaType & A_MLC ) ||
++ ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ {
++ //---------------------------------------------
++ // SAMSUNG MLC(4BIT) ROW ADDR: FIXED LOW
++ // HYNIX MLC(4BIT, 12BIT) ROW ADDR: FIXED LOW
++ //---------------------------------------------
++ if ( nBlockPageAddr & dwTempBlockPageAddr )
++ nReBlockPageAddr = dwTempBlockPageAddr;
++ else
++ nReBlockPageAddr = 0;
++ }
++ else if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_16BIT ) )
++ {
++ //---------------------------------------------
++ // SAMSUNG MLC(8BIT) ROW ADDR: REAL ADDR
++ //---------------------------------------------
++ nReBlockPageAddr = nBlockPageAddr;
++ }
++ dwAddSecondPageAddr = nDevInfo->Feature.PpB;
++
++ }
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ {
++ nReBlockPageAddr = nBlockPageAddr;
++ dwAddSecondPageAddr = ( nDevInfo->DistrictNum << nDevInfo->ShiftPpB );
++ }
++ else if ( ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == INTEL_NAND_MAKER_ID ) )
++ {
++ nReBlockPageAddr = nBlockPageAddr;
++ dwAddSecondPageAddr = nDevInfo->Feature.PpB;
++ }
++ else
++ {
++ // Local variable Init
++ nReBlockPageAddr = 0;
++ dwAddSecondPageAddr = 0;
++
++ res = ERR_NAND_IO_WRONG_PARAMETER;
++ goto ErrorEraseBlock;
++ }
++
++ /* Write Block Address */
++ NAND_IO_WriteBlockPageAddr( nReBlockPageAddr, nDevInfo ); // <== 1st Block
++
++ /* Command Block Erase #1 [ 0x60 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x6060;
++
++ /* Write Block Address */
++ NAND_IO_WriteBlockPageAddr( nBlockPageAddr + dwAddSecondPageAddr, nDevInfo ); // <== 2nd Block
++
++ /* Command Erase Block #2 [ 0xD0 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xD0D0;
++
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) || ( nFormatMode == INTER_LEAVE_OFF ) )
++ {
++ /* Wait until it is ready */
++ NAND_IO_WaitBusyForProgramAndErase( nDevInfo );
++
++ /* Check Status */
++ res = NAND_IO_ReadStatusForMultiPlane( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ {
++ if ( res == NAND_IO_DISTRICT_0 )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[0] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[0] = nBlockPageAddr;
++ }
++ else if ( res == NAND_IO_DISTRICT_1 )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[1] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[1] = ( nBlockPageAddr + dwAddSecondPageAddr );
++ }
++ }
++ else
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[0] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[0] = nBlockPageAddr;
++ nDevInfo->BadBlockInfo.BlockStatus[1] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[1] = ( nBlockPageAddr + dwAddSecondPageAddr );
++ }
++
++ goto ErrorEraseBlock;
++ }
++ }
++ else
++ {
++ NAND_IO_SetInterleaveStatus( nDevInfo, nBlockPageAddr );
++
++ if ( nDevInfo->Feature.MediaType & S_IL )
++ {
++ //=============================================
++ // Inter Leave
++ //=============================================
++ if ( nBlockPageAddr < (U32)( ( nDevInfo->Feature.PBpV >> 1 ) << nDevInfo->ShiftPpB ) )
++ {
++ if ( nDevInfo->BadBlockInfo.BlockStatus[0] != MULTI_PLANE_BAD_BLOCK )
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[0] = nBlockPageAddr;
++
++ if ( nDevInfo->BadBlockInfo.BlockStatus[1] != MULTI_PLANE_BAD_BLOCK )
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[1] = ( nBlockPageAddr + dwAddSecondPageAddr );
++ }
++ else
++ {
++ if ( nDevInfo->BadBlockInfo.BlockStatus[2] != MULTI_PLANE_BAD_BLOCK )
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[2] = nBlockPageAddr;
++
++ if ( nDevInfo->BadBlockInfo.BlockStatus[3] != MULTI_PLANE_BAD_BLOCK )
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[3] = ( nBlockPageAddr + dwAddSecondPageAddr );
++ }
++ }
++ else if ( nDevInfo->ExtInterleaveUsable == TRUE )
++ {
++ if ( nDevInfo->BadBlockInfo.BlockStatus[0] != MULTI_PLANE_BAD_BLOCK )
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[0] = nBlockPageAddr;
++
++ if ( nDevInfo->BadBlockInfo.BlockStatus[1] != MULTI_PLANE_BAD_BLOCK )
++ nDevInfo->BadBlockInfo.BadBlkPHYAddr[1] = ( nBlockPageAddr + dwAddSecondPageAddr );
++ }
++ }
++
++ErrorEraseBlock:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ NAND_IO_EnableWriteProtect();
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_GetFactoryBadMarkOfPBlock
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_GetFactoryBadMarkOfPBlock( NAND_IO_DEVINFO *nDevInfo, U32 nBlockPageAddr )
++{
++ unsigned short int i;
++ unsigned short int wPageSize, wReadSize;
++ unsigned short int wColumnAddr;
++ unsigned short int wPageAddr;
++ unsigned char cBSA[512];
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nBlockPageAddr );
++
++ //=============================================
++ // Get Factory Bad Mark Page Default
++ //=============================================
++ if ( ( nDevInfo->Feature.MediaType & A_MLC ) ||
++ ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) ||
++ ( nDevInfo->Feature.MediaType & A_MLC_12BIT )||
++ ( nDevInfo->Feature.MediaType & A_MLC_16BIT ) )
++ wPageAddr = nDevInfo->Feature.PpB - 1; /*last page*/
++ else
++ wPageAddr = 0; /*First Page*/
++
++ //=============================================
++ // Setting ReadSize & Column Address
++ //=============================================
++ wReadSize = 1;
++ wPageSize = nDevInfo->Feature.PageSize;
++
++ //=============================================
++ // Exception: Micron
++ //=============================================
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == INTEL_NAND_MAKER_ID ) )
++ {
++ if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ {
++ wPageAddr = 0;
++ wReadSize = nDevInfo->Feature.SpareSize;
++ }
++ else
++ {
++ /*SLC, MLC*/
++ wPageAddr = 0;
++ wReadSize = 1;
++ }
++ }
++
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ wPageSize = ( wPageSize >> 1 );
++ wReadSize = ( wReadSize << 1 );
++ }
++
++ if ( wPageSize == 512 ) /* SMALL BLOCK NANDFLASH */
++ wColumnAddr = 517;
++ else if ( wPageSize == 2048 ) /* BIG BLOCK NANDFLAHS */
++ wColumnAddr = 2048;
++ else if ( wPageSize == 4096 ) /* 4K Page BIG BLOCK NANDFLASH */
++ wColumnAddr = 4096;
++ else if ( wPageSize == 8192 ) /* 4K Page BIG BLOCK NANDFLASH */
++ wColumnAddr = 8192;
++ else
++ return ERR_NAND_IO_FAILED_GET_FACTORY_BAD_MARK_OF_PBLOCK;
++
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ wColumnAddr = ( wColumnAddr << 1 );
++
++ /* Read BSA */
++ res = NAND_IO_ReadUserSizePage( nDevInfo,
++ nBlockPageAddr + wPageAddr,
++ wColumnAddr,
++ wReadSize,
++ &cBSA[0] );
++ if ( res != SUCCESS )
++ return res;
++
++ /* Check BSA */
++ res = (NAND_IO_ERROR)SUCCESS;
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ //============================================
++ //PARALLEL: Check Signature(00h) of BadBlock
++ //============================================
++ for( i = 0 ; i < wReadSize; i += 2 )
++ {
++ if ( cBSA[i] != 0xFF )
++ res |= NAND_IO_STATUS_FAIL_CS0_PARALLEL;
++ if ( cBSA[i+1] != 0xFF )
++ res |= NAND_IO_STATUS_FAIL_CS1_PARALLEL;
++
++ if( res != SUCCESS )
++ return res;
++ }
++ }
++ else
++ {
++ //============================================
++ //SERIAL: Check Signature(00h) of BadBlock
++ //============================================
++ for( i = 0 ; i < wReadSize; ++ i )
++ {
++ if ( cBSA[i] != 0xFF )
++ res |= NAND_IO_STATUS_FAIL_CS0_SERIAL;
++
++ if ( res != SUCCESS )
++ return res;
++ }
++ }
++
++ return res;
++
++}
++
++/******************************************************************************
++*
++* NAND_IO_ERROR NAND_IO_GetUID
++*
++* Input :
++* Output :
++* Return :
++*
++* Description :
++*
++*******************************************************************************/
++NAND_IO_ERROR NAND_IO_GetUID( NAND_IO_DEVINFO *nDevInfo, U16 *nCmd, U8 *rReadData )
++{
++ unsigned int i;
++ unsigned int RowAddr, ColumnAddr;
++ unsigned char cTempBuffer[512];
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_EnableWriteProtect();
++
++ /* Command #1 */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & *nCmd;
++ /* Command #2 */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & *(nCmd+1);
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForRead( 0, 0, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ goto ErrorGetUID;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Read Data */
++ res = NAND_IO_ReadUserSizeData( nDevInfo,
++ 0,
++ 512,
++ cTempBuffer );
++ if ( res != SUCCESS )
++ goto ErrorGetUID;
++
++ /* Copy Read Data */
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ for ( i = 0; i < 256; ++ i )
++ rReadData[i] = cTempBuffer[i*2+0];
++ }
++ else
++ {
++ for ( i = 0; i < 256; ++ i )
++ rReadData[i] = cTempBuffer[i];
++ }
++
++ErrorGetUID:
++ //=============================================
++ // FORCE TO SET WP LOW
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ //=============================================
++ // Reset Chip
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_Reset( nDevInfo->ChipNo, NAND_IO_PARALLEL_COMBINATION_MODE );
++ else
++ NAND_IO_Reset( nDevInfo->ChipNo, NAND_IO_SERIAL_COMBINATION_MODE );
++
++ if ( res != SUCCESS )
++ return res;
++
++ return (NAND_IO_ERROR)SUCCESS;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_CheckForExtendBlockAccess( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_CheckForExtendBlockAccess( NAND_IO_DEVINFO *nDevInfo, U32* nPageAddr )
++{
++ unsigned long int dwPhyBlkNo;
++ unsigned long int dwPhyPageNo;
++ unsigned long int dwPHYPageAddr;
++
++ if ( nDevInfo->Feature.MediaType & S_EB )
++ {
++ dwPHYPageAddr = *nPageAddr;
++ dwPhyBlkNo = dwPHYPageAddr >> nDevInfo->ShiftPpB;
++ dwPhyPageNo = dwPHYPageAddr - ( dwPhyBlkNo << nDevInfo->ShiftPpB );
++
++ if ( dwPhyBlkNo >= ( nDevInfo->Feature.PBpV >> 1 ) )
++ {
++ dwPhyBlkNo += ( nDevInfo->Feature.PBpV >> 1 );
++ dwPHYPageAddr = ( dwPhyBlkNo << nDevInfo->ShiftPpB ) + dwPhyPageNo;
++
++ *nPageAddr = dwPHYPageAddr;
++ }
++ }
++
++}
++
++//*****************************************************************************
++//*
++//*
++//* [ MISCELLANEOUS Functions of NAND IO ]
++//*
++//*
++//*****************************************************************************
++static __inline void NAND_IO_SetDataWidth( U32 width )
++{
++ if ( width == NAND_IO_DATA_WITDH_8BIT )
++ BITCLR( pNFC->NFC_CTRL, HwNFC_CTRL_BW_16 );
++ else
++ BITSET( pNFC->NFC_CTRL, HwNFC_CTRL_BW_16 );
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_PortControl( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_PortControl( int nOnOff )
++{
++ if ( !( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ {
++ if ( gNAND_GPIO_ON_OFF == ENABLE )
++ {
++ if ( nOnOff == ENABLE )
++ {
++ #if defined(TCC83XX)
++ NAND_IO_SEL_REG = gNANDIO_GSELReg;
++ #endif
++ #if defined(TCC79X)
++ // PORTCFG5 Configuration ( TCC7930S B[0]~B[6] is reserved )
++ // B[0] = NDXD[0]
++ // B[1] = NDXD[1]
++ // B[2] = NDXD[2]
++ // B[3] = NDXD[3]
++ // B[4] = NDXD[4]
++ // B[5] = NDXD[5]
++ // B[6] = NDXD[6]
++ HwPORTCFG5 &= (0xF0000000);
++ HwPORTCFG5 |= (0x01111111);
++
++ // PORTCFG6 Configuration
++ // B[7] = NDXD[7]
++ BITCSET( HwPORTCFG6, HwPORTCFG6_GPIOB7(15), HwPORTCFG6_GPIOB7(1));
++
++ #ifndef NAND_8BIT_ONLY
++ // PORTCFG2 Configuration
++ // F[15:12] = NDXD[15:12]
++ BITCSET( HwPORTCFG2, HwPORTCFG2_HPXD11(15), HwPORTCFG2_HPXD11(2));
++ // F[11:8] = NDXD[11:8]
++ BITCSET( HwPORTCFG2, HwPORTCFG2_HPXD15(15), HwPORTCFG2_HPXD15(2));
++ #endif
++ #endif
++ }
++ else
++ {
++ #if defined(TCC83XX)
++ NAND_IO_SEL_REG = 0;
++ NAND_IO_IOCON_REG |= gNANDIO_GIOCONReg;
++ NAND_IO_GDATA |= gNANDIO_GDATASet;
++ #endif
++ #if defined(TCC79X)
++ // PORTCFG5 Configuration ( TCC7930S B[0]~B[6] is reserved )
++ // B[0] = NDXD[0]
++ // B[1] = NDXD[1]
++ // B[2] = NDXD[2]
++ // B[3] = NDXD[3]
++ // B[4] = NDXD[4]
++ // B[5] = NDXD[5]
++ // B[6] = NDXD[6]
++ HwPORTCFG5 &= (0xF0000000);
++
++ // PORTCFG6 Configuration
++ // B[7] = NDXD[7]
++ BITCSET( HwPORTCFG6, HwPORTCFG6_GPIOB7(15), HwPORTCFG6_GPIOB7(0));
++ HwGPBEN |= 0x000000FF;
++ HwGPBDAT |= 0x000000FF;
++
++ #ifndef NAND_8BIT_ONLY
++ // PORTCFG2 Configuration
++ // F[11:8] = NDXD[11:8]
++ BITCSET( HwPORTCFG2, HwPORTCFG2_HPXD11(15), HwPORTCFG2_HPXD11(1));
++ // F[15:12] = NDXD[15:12]
++ BITCSET( HwPORTCFG2, HwPORTCFG2_HPXD15(15), HwPORTCFG2_HPXD15(1));
++ HwGPFEN |= 0x0000FF00;
++ HwGPFDAT |= 0x0000FF00;
++ #endif
++ #endif
++ }
++ }
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_PreProcess( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_PreProcess( void )
++{
++ NAND_IO_PortControl( ENABLE );
++
++ //IO_CKC_EnableBUS( IO_CKC_BUS_NFC );
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_PostProcess( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_PostProcess( void )
++{
++ //IO_CKC_DisableBUS( IO_CKC_BUS_NFC );
++
++ NAND_IO_PortControl( DISABLE );
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_SetBasicCycleTime( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_SetBasicCycleTime( void )
++{
++ /* SETUP 1 PW 5 HOLD 1 */
++ BITCSET( pNFC->NFC_CTRL, 0xFFF, 0xEEE );
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_SetCommCycleTime(void);
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++void NAND_IO_SetCommCycleTime(void)
++{
++ BITCSET( pNFC->NFC_CTRL, 0xFFF, CommCycleTime.RegValue );
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_SetWriteCycleTime(void);
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_SetWriteCycleTime(void)
++{
++ BITCSET( pNFC->NFC_CTRL, 0xFFF, WriteCycleTime.RegValue );
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_SetReadCycleTime(void);
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++void NAND_IO_SetReadCycleTime(void)
++{
++ BITCSET( pNFC->NFC_CTRL, 0xFFF, ReadCycleTime.RegValue );
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_BusControl(NAND_IO_DEVINFO *nDevInfo);
++*
++* DESCRIPTION :
++* INPUT:
++* NAND_IO_DEVINFO Structure Variable Pointer
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_BusControl( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int nMaxBusClk;
++ unsigned int nMaxBusClkMHZ;
++
++ //==============================================
++ // SET NAND I/O CYCLE
++ //==============================================
++ if ( nDevInfo->IoStatus == NAND_IO_STATUS_ENABLE )
++ {
++ #ifdef FWDN_DOWNLOADER_INCLUDE
++ nMaxBusClk = 1000000; // 100MHZ
++ #elif defined(TCC89XX) || defined(TCC92XX)
++ {
++ #if defined(_WINCE_)
++ #if defined(USE_V_ADDRESS)
++ nMaxBusClk = tcc_ckc_getfbusctrl(CLKCTRL4);
++ #else
++ tca_ckc_init();
++ nMaxBusClk = tca_ckc_getfbusctrl(CLKCTRL4);
++ #endif
++ #elif defined(_LINUX_)
++ tca_ckc_init();
++ nMaxBusClk = tca_ckc_getfbusctrl(CLKCTRL4);
++ #else
++ nMaxBusClk = 1660000;
++ #endif
++ }
++ #endif
++
++ if ( nMaxBusClk == 0 )
++ nMaxBusClk = 1660000;
++
++ nMaxBusClkMHZ = ( nMaxBusClk / 10000 );
++
++ if ( ( gMaxBusClkMHZ != 0 ) && ( nMaxBusClkMHZ != gMaxBusClkMHZ ) )
++ NAND_IO_SetCycle( nDevInfo );
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_EnableChipSelect( U16 nChipNo );
++*
++* DESCRIPTION :
++* INPUT:
++* nChipNo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_EnableChipSelect( U16 nChipNo )
++{
++ if ( nChipNo == 0 )
++ {
++ /* NAND_IO_SUPPORT_4CS */
++ #if defined(NAND_2CS_ONLY)
++ BITSCLR( pNFC->NFC_CTRL, HwNFC_CTRL_CFG_nCS1, HwNFC_CTRL_CFG_nCS0 );
++ #else
++ BITSCLR( pNFC->NFC_CTRL, HwNFC_CTRL_CFG_NOACT, HwNFC_CTRL_CFG_nCS0 );
++ #endif
++ }
++ else if ( nChipNo == 1 )
++ {
++ /* NAND_IO_SUPPORT_4CS */
++ #if defined(NAND_2CS_ONLY)
++ BITSCLR( pNFC->NFC_CTRL, HwNFC_CTRL_CFG_nCS0, HwNFC_CTRL_CFG_nCS1 );
++ #else
++ BITSCLR( pNFC->NFC_CTRL, HwNFC_CTRL_CFG_NOACT, HwNFC_CTRL_CFG_nCS1 );
++ #endif
++ }
++ else if ( nChipNo == 2 )
++ {
++ /* NAND_IO_SUPPORT_4CS */
++ BITSCLR( pNFC->NFC_CTRL, HwNFC_CTRL_CFG_NOACT, HwNFC_CTRL_CFG_nCS2 );
++ }
++ else if ( nChipNo == 3 )
++ {
++ /* NAND_IO_SUPPORT_4CS */
++ BITSCLR( pNFC->NFC_CTRL, HwNFC_CTRL_CFG_NOACT, HwNFC_CTRL_CFG_nCS3 );
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_DisableChipSelect( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_DisableChipSelect( void )
++{
++ /* NAND_IO_SUPPORT_4CS */
++ #if defined(NAND_2CS_ONLY)
++ BITSET( pNFC->NFC_CTRL, ( HwNFC_CTRL_CFG_nCS0 | HwNFC_CTRL_CFG_nCS1 ) );
++ #else
++ BITSET( pNFC->NFC_CTRL, HwNFC_CTRL_CFG_NOACT );
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_EnableWriteProtect( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_EnableWriteProtect( void )
++{
++ #if defined(USE_V_ADDRESS)
++ #if defined(_WINCE_)
++ BITCLR( pGPIO->GPBDAT, NAND_IO_NFC_nWPBit );
++ #else
++ BITCLR( NAND_IO_NFC_nWP, NAND_IO_NFC_nWPBit );
++ #endif
++ #else
++ BITCLR( NAND_IO_NFC_nWP, NAND_IO_NFC_nWPBit );
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_DisableWriteProtect( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_DisableWriteProtect( void )
++{
++ #if defined(USE_V_ADDRESS)
++ #if defined(_WINCE_)
++ BITSET( pGPIO->GPBDAT, NAND_IO_NFC_nWPBit );
++ #else
++ BITSET( NAND_IO_NFC_nWP, NAND_IO_NFC_nWPBit );
++ #endif
++ #else
++ BITSET( NAND_IO_NFC_nWP, NAND_IO_NFC_nWPBit );
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline U32 NAND_IO_CheckReadyAndBusy( U16 nChipNo );
++*
++* DESCRIPTION :
++* INPUT:
++* nChipNo =
++*
++* OUTPUT: U32 - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline U32 NAND_IO_CheckReadyAndBusy( U16 nChipNo )
++{
++ nChipNo = 0; // Warning
++
++ #if defined(TCC_NAND_RDY_B28)
++ return ISZERO( pNFC->NFC_CTRL, HwNFC_CTRL_RDY_RDY );
++ #elif defined(TCC_NAND_RDY_B31)
++ return ISZERO( HwGPIOB->GPDAT, Hw31);
++ #else
++ #Error: NAND_IO_CheckReadyAndBusy Pin
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_WaitBusy( U16 nChipNo );
++*
++* DESCRIPTION :
++* INPUT:
++* nChipNo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_WaitBusy( U16 nChipNo )
++{
++ // Misc. Configuration Register(MCFG)
++ // 0 : represent that READY pin is low
++ // 1 : high
++ // Delay : 200nS
++
++ NAND_IO_Delay();
++
++ while (NAND_IO_CheckReadyAndBusy( nChipNo ));
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_WaitBusyForProgramAndErase( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_WaitBusyForProgramAndErase( NAND_IO_DEVINFO *nDevInfo )
++{
++ // Misc. Configuration Register(MCFG)
++ // 0 : represent that READY pin is low
++ // 1 : high
++ // Delay : 200nS
++ NAND_IO_Delay();
++
++ while (NAND_IO_CheckReadyAndBusy( nDevInfo->ChipNo ))
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_WaitBusyForCacheProgram( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_WaitBusyForCacheProgram( NAND_IO_DEVINFO *nDevInfo )
++{
++ // Misc. Configuration Register(MCFG)
++ // 0 : represent that READY pin is low
++ // 1 : high
++ // Delay : 200nS
++ NAND_IO_Delay();
++
++ while (NAND_IO_CheckReadyAndBusy( nDevInfo->ChipNo ))
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_WaitBusyForInterleave( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nPageAddr =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_WaitBusyForInterleave( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr )
++{
++ unsigned int ChipNum = 0;
++ NAND_IO_ERROR res;
++
++ NAND_IO_Delay();
++ gInterLeaveWriteStatus = MULTI_PLANE_GOOD_BLOCK;
++
++ if ( gDevInfo->Feature.MediaType & S_IL )
++ {
++ //=============================================
++ // Inter Leave
++ //=============================================
++ if ( gInterLeaveCSNum != nDevInfo->ChipNo )
++ {
++ NAND_IO_EnableChipSelect( (U16)gInterLeaveCSNum );
++ NAND_IO_DisableWriteProtect();
++ nDevInfo->WriteStatus.ChipNo = (U8)gDevInfo->ChipNo;
++
++ while ( NAND_IO_ReadStatusForInterleaveClear( gDevInfo ) )
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++ }
++ else
++ {
++ NAND_IO_EnableChipSelect( (U16)gInterLeaveCSNum );
++ NAND_IO_DisableWriteProtect();
++ nDevInfo->WriteStatus.ChipNo = (U8)nDevInfo->ChipNo;
++
++ while ( NAND_IO_ReadStatusForInterleave( gDevInfo, nPageAddr ) )
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++ }
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ }
++ else if ( nDevInfo->ExtInterleaveUsable == TRUE )
++ {
++ //=============================================
++ // External Inter Leave
++ //=============================================
++ if ( nDevInfo->ChipNo == 0 )
++ ChipNum = NAND_IO_STATUS_INTERLEAVING_CHIP1;
++ else if ( nDevInfo->ChipNo == 1 )
++ ChipNum = NAND_IO_STATUS_INTERLEAVING_CHIP2;
++ else if ( nDevInfo->ChipNo == 2 )
++ ChipNum = NAND_IO_STATUS_INTERLEAVING_CHIP3;
++ else if ( nDevInfo->ChipNo == 3 )
++ ChipNum = NAND_IO_STATUS_INTERLEAVING_CHIP4;
++
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++
++ if ( gInterLeaveIoStatus & (U16)ChipNum )
++ {
++ NAND_IO_WaitBusyForProgramAndErase( gDevInfo );
++ res = NAND_IO_ReadStatus( gDevInfo );
++ if ( res != SUCCESS )
++ {
++ nDevInfo->WriteStatus.ChipNo = (U8)gDevInfo->ChipNo;
++ nDevInfo->BadBlockInfo.BlockStatus[gDevInfo->ChipNo] = MULTI_PLANE_BAD_BLOCK;
++ gInterLeaveWriteStatus = MULTI_PLANE_BAD_BLOCK;
++ }
++ gInterLeaveIoStatus &= ~ChipNum;
++ }
++ }
++
++ if ( gInterLeaveWriteStatus == MULTI_PLANE_BAD_BLOCK )
++ {
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = gInterLeavePageAddr;
++ gInterLeaveWriteStatus = MULTI_PLANE_GOOD_BLOCK;
++ res = ERR_NAND_IO_FAILED_WRITE;
++ }
++ else
++ {
++ nDevInfo->WriteStatus.BlockStatus = MULTI_PLANE_GOOD_BLOCK;
++ nDevInfo->WriteStatus.ErrorPHYPageAddr = 0xFFFFFFFF;
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* NAND_IO_ERROR NAND_IO_WaitBusyCheckForWriteEnd( NAND_IO_DEVINFO *nDevInfo )
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++NAND_IO_ERROR NAND_IO_WaitBusyCheckForWriteEnd( NAND_IO_DEVINFO *nDevInfo )
++{
++ NAND_IO_Delay();
++ NAND_IO_PreProcess();
++
++ if ( nDevInfo->Feature.MediaType & S_IL )
++ {
++ //=============================================
++ // Inter Leave
++ //=============================================
++
++ if ( gInterLeaveCSNum != nDevInfo->ChipNo )
++ {
++ NAND_IO_EnableChipSelect( (U16)gInterLeaveCSNum );
++ NAND_IO_DisableWriteProtect();
++
++ while ( NAND_IO_ReadStatusForInterleaveClear( nDevInfo ) )
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ }
++ else
++ {
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ NAND_IO_DisableWriteProtect();
++
++ while ( NAND_IO_ReadStatusForInterleave( nDevInfo, gInterLeavePageAddr ) )
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++ }
++ }
++ else if ( nDevInfo->ExtInterleaveUsable == TRUE )
++ {
++ //=============================================
++ // External Inter Leave
++ //=============================================
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP1 )
++ {
++ NAND_IO_EnableChipSelect( 0 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusy(0);
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP1;
++
++ NAND_IO_DisableChipSelect();
++ }
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP2 )
++ {
++ NAND_IO_EnableChipSelect( 1 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusy(1);
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP2;
++
++ NAND_IO_DisableChipSelect();
++ }
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP3 )
++ {
++ NAND_IO_EnableChipSelect( 2 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusy(2);
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP3;
++
++ NAND_IO_DisableChipSelect();
++ }
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP4 )
++ {
++ NAND_IO_EnableChipSelect( 3 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusy(3);
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP4;
++
++ NAND_IO_DisableChipSelect();
++ }
++ }
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_IO_SetInterLeavePageAddr(U32 nPageAddr );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nPageAddr =
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_IO_SetInterLeavePageAddr(U32 nPageAddr )
++{
++ gInterLeavePageAddr = nPageAddr;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_SetInterleaveStatus( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nPageAddr =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++void NAND_IO_SetInterleaveStatus( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr )
++{
++
++ if ( nDevInfo->Feature.MediaType & S_IL )
++ {
++ //=============================================
++ // Inter Leave
++ //=============================================
++
++ if ( nPageAddr < (U32)(( ( nDevInfo->Feature.PBpV >> 1 ) << nDevInfo->ShiftPpB ) ))
++ {
++ gInterLeaveIoStatus |= NAND_IO_STATUS_INTERLEAVING_CHIP1;
++ gInterLeaveDie0BlockAddr = nPageAddr;
++ }
++ else
++ {
++ gInterLeaveIoStatus |= NAND_IO_STATUS_INTERLEAVING_CHIP2;
++ gInterLeaveDie1BlockAddr = nPageAddr;
++ }
++ gInterLeaveCSNum = nDevInfo->ChipNo;
++ }
++ else if ( nDevInfo->ExtInterleaveUsable == TRUE )
++ {
++ //=============================================
++ // External Inter Leave
++ //=============================================
++
++ if ( nDevInfo->ChipNo == 0 )
++ gInterLeaveIoStatus |= NAND_IO_STATUS_INTERLEAVING_CHIP1;
++ else if ( nDevInfo->ChipNo == 1 )
++ gInterLeaveIoStatus |= NAND_IO_STATUS_INTERLEAVING_CHIP2;
++ else if ( nDevInfo->ChipNo == 2 )
++ gInterLeaveIoStatus |= NAND_IO_STATUS_INTERLEAVING_CHIP3;
++ else if ( nDevInfo->ChipNo == 3 )
++ gInterLeaveIoStatus |= NAND_IO_STATUS_INTERLEAVING_CHIP4;
++ }
++
++ gDevInfo = (NAND_IO_DEVINFO *)nDevInfo;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_ClearInterleaveStatus( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_ClearInterleaveStatus( NAND_IO_DEVINFO *nDevInfo )
++{
++ NAND_IO_Delay();
++ gInterLeaveWriteStatus = MULTI_PLANE_GOOD_BLOCK;
++
++ if ( gDevInfo->Feature.MediaType & S_IL )
++ {
++ //=============================================
++ // Inter Leave
++ //=============================================
++ NAND_IO_EnableChipSelect( (U16)gInterLeaveCSNum );
++ NAND_IO_DisableWriteProtect();
++
++ while ( NAND_IO_ReadStatusForInterleaveClear( gDevInfo ) )
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ // TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++
++ NAND_IO_DisableChipSelect();
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ }
++ else if ( gDevInfo->ExtInterleaveUsable == TRUE )
++ {
++ //=============================================
++ // External Inter Leave
++ //=============================================
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP1 )
++ {
++ NAND_IO_EnableChipSelect( 0 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusyForProgramAndErase( gDevInfo );
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP1;
++
++ NAND_IO_DisableChipSelect();
++ }
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP2 )
++ {
++ NAND_IO_EnableChipSelect( 1 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusyForProgramAndErase( gDevInfo );
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP2;
++
++ NAND_IO_DisableChipSelect();
++ }
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP3 )
++ {
++ NAND_IO_EnableChipSelect( 2 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusyForProgramAndErase( gDevInfo );
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP3;
++
++ NAND_IO_DisableChipSelect();
++ }
++
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP4 )
++ {
++ NAND_IO_EnableChipSelect( 3 );
++ NAND_IO_DisableWriteProtect();
++ NAND_IO_WaitBusyForProgramAndErase( gDevInfo );
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP4;
++
++ NAND_IO_DisableChipSelect();
++ }
++
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_Delay( void );
++*
++* DESCRIPTION :
++* INPUT:
++* None
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_Delay( void )
++{
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* NAND_IO_ERROR NAND_IO_IRQ_ReadPagePreProcess( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U32 *rEccBuffer, U16 nChipNo );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nChipNo =
++* nDevInfo =
++* nPageAddr =
++* nStartPPage =
++* rEccBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++NAND_IO_ERROR NAND_IO_IRQ_ReadPagePreProcess( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr, U16 nStartPPage, U32 *rEccBuffer, U16 nChipNo )
++{
++ unsigned int i;
++ unsigned int RowAddr, ColumnAddr;
++ unsigned short int nSpareTotalSize;
++ unsigned char *pSpareB = 0;
++ NAND_IO_ERROR res;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ) )
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP LOW
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) )
++ NAND_IO_ClearInterleaveStatus( nDevInfo );
++ else
++ NAND_IO_EnableChipSelect( nChipNo );
++
++ NAND_IO_EnableWriteProtect();
++
++ //=============================================
++ // Read Data
++ //=============================================
++ // ECC Read
++ if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ nSpareTotalSize = 20;
++ else
++ nSpareTotalSize = 24;
++
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForRead( nPageAddr, nDevInfo->Feature.PageSize + nSpareTotalSize, &RowAddr, &ColumnAddr, nDevInfo );
++ if ( res != SUCCESS )
++ return res;
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Command READ2 [ 0x30 ] for Advance NandFlash */
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++
++ #ifdef NAND_GPIO_DEBUG
++ BITSET(pGPIO->GPFDAT, Hw21);
++ #endif
++
++ /* Change Cycle */
++ NAND_IO_SetReadCycleTime();
++
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ // Set SpareBuffer Pointer =>> ECCBuffer
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //=========================================================================
++ // Empty Page ECCBuffer Pointer Increment
++ //=========================================================================
++ for ( i = 0; i < nStartPPage; ++i )
++ pSpareB += nDevInfo->EccDataSize;
++
++ *rEccBuffer = (unsigned int)pSpareB;
++ }
++
++ return SUCCESS;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_IO_IRQ_ReadPagePostProcess( void );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_IO_IRQ_ReadPagePostProcess( void )
++{
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ //=============================================
++ // Disable Chip Select
++ // PostProcess
++ //=============================================
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_IO_IRQ_Read512DataPreProcess( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_IO_IRQ_Read512DataPreProcess( NAND_IO_DEVINFO *nDevInfo )
++{
++ //==========================================================
++ //
++ // ECC Decode Setup
++ //
++ //==========================================================
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++ pECC->ECC_MASK = 0x00000000; /* Address mask for ECC area */
++
++ if ( nDevInfo->EccType== SLC_ECC_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_SLCDE;
++ else if (nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ {
++ pECC->ECC_CTRL |= HwECC_CTRL_IEN_MECC4_EN;
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL4DE;
++ }
++ else if (nDevInfo->EccType == MLC_ECC_8BIT_TYPE )
++ {
++ pECC->ECC_CTRL |= HwECC_CTRL_IEN_MECC8_EN;
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL8DE;
++ }
++ else if (nDevInfo->EccType == MLC_ECC_12BIT_TYPE )
++ {
++ pECC->ECC_CTRL |= HwECC_CTRL_IEN_MECC12_EN;
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL12DE;
++ }
++ else if (nDevInfo->EccType == MLC_ECC_16BIT_TYPE )
++ {
++ pECC->ECC_CTRL |= HwECC_CTRL_IEN_MECC16_EN;
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL16DE;
++ }
++
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* NAND_IO_ERROR NAND_IO_IRQ_Read512DataPostProcess( NAND_IO_DEVINFO *nDevInfo, U8* nPageBuffer, U8* nSpareBuffer );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++NAND_IO_ERROR NAND_IO_IRQ_Read512DataPostProcess( NAND_IO_DEVINFO *nDevInfo, U8* nPageBuffer, U8* nSpareBuffer )
++{
++ NAND_IO_ERROR res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Check and Correct ECC code */
++ if (( nDevInfo->EccType == SLC_ECC_TYPE ) && ( nDevInfo->Feature.MediaType & A_SMALL ))
++ {
++ //===================================
++ // SLC ECC Correction
++ //===================================
++ nSpareBuffer += NAND_IO_SPARE_SIZE_SMALL;
++ res |= NAND_IO_CorrectionSLC( nPageBuffer, nSpareBuffer );
++ }
++ else
++ {
++ if ( nDevInfo->EccType == SLC_ECC_TYPE )
++ res |= NAND_IO_CorrectionSLC( nPageBuffer, nSpareBuffer );
++ else
++ res |= NAND_IO_CorrectionMLC( nDevInfo->EccType, nPageBuffer, nSpareBuffer, 512 );
++ }
++
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* NAND_IO_ERROR NAND_IO_IRQ_WritePagePreProcess( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++* U16 nStartPPage, U8 *nSpareBuffer, U32 *rEccBuffer, U16 nChipNo, U8 nWriteMode );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nChipNo =
++* nDevInfo =
++* nPageAddr =
++* nSpareBuffer =
++* nStartPPage =
++* nWriteMode =
++* rEccBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++NAND_IO_ERROR NAND_IO_IRQ_WritePagePreProcess( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr,
++ U16 nStartPPage, U8 *nSpareBuffer, U32 *rEccBuffer, U16 nChipNo, U8 nWriteMode )
++{
++ unsigned int j, i;
++ unsigned int RowAddr, ColumnAddr;
++ unsigned long int dwTempPHYPageAddr;
++ unsigned char *pSpareB, *pSpare;
++ NAND_IO_ERROR res;
++ NAND_IO_ECC_INFO *pECC_Info;
++
++ //=============================================
++ // Check Device and Parameter
++ //=============================================
++ if ( !( nDevInfo->IoStatus & NAND_IO_STATUS_ENABLE ))
++ return ERR_NAND_IO_NOT_READY_DEVICE_IO;
++
++ //=============================================
++ // PreProcess
++ // Set Setup Time and Hold Time
++ // Enable Chip Select
++ // FORCE TO SET WP HIGH
++ //=============================================
++ NAND_IO_PreProcess();
++ NAND_IO_BusControl(nDevInfo);
++ NAND_IO_SetCommCycleTime();
++
++ NAND_IO_CheckForExtendBlockAccess( nDevInfo, &nPageAddr );
++
++ //=============================================
++ // Read Status
++ //=============================================
++ /* Wait until it is ready */
++ if ( ( ( gDevInfo->Feature.MediaType & S_IL ) || ( gDevInfo->ExtInterleaveUsable == TRUE ) ) &&
++ ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ) &&
++ ( ( nWriteMode == MULTI_PLANE_START_PAGE ) || (nWriteMode == MULTI_PLANE_NORMAL_PAGE ) || (nWriteMode == MULTI_PLANE_STUFF_PAGE)) )
++ {
++ res = NAND_IO_WaitBusyForInterleave( nDevInfo, nPageAddr );
++ if ( res != SUCCESS )
++ return (NAND_IO_ERROR)res;
++ }
++ else
++ {
++ NAND_IO_EnableChipSelect( nChipNo );
++ NAND_IO_DisableWriteProtect();
++ }
++
++ //=============================================
++ // Write Data
++ //=============================================
++ if ( nWriteMode == MULTI_PLANE_START_PAGE )
++ {
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == HYNIX_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID ) )
++ {
++ if ( ( nDevInfo->Feature.MediaType & A_MLC ) || ( nDevInfo->Feature.MediaType & A_SLC ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ {
++ dwTempPHYPageAddr = ( ( nDevInfo->Feature.PBpV << nDevInfo->ShiftPpB ) >> 1 );
++
++ if ( nPageAddr & dwTempPHYPageAddr )
++ nPageAddr = dwTempPHYPageAddr;
++ else
++ nPageAddr = 0;
++ }
++ }
++ }
++
++ if ( (nWriteMode == MULTI_PLANE_NORMAL_PAGE ) || (nWriteMode == MULTI_PLANE_STUFF_PAGE) )
++ {
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForWrite( nPageAddr, ( nStartPPage << 9 ), &RowAddr, &ColumnAddr, nDevInfo );
++ }
++ else
++ {
++ /* Generate Row and Column Address */
++ res = NAND_IO_GenerateRowColAddrForCBandCP( nPageAddr, ( nStartPPage << 9 ), &RowAddr, &ColumnAddr, nDevInfo );
++ }
++ if ( res != SUCCESS )
++ return (NAND_IO_ERROR)res;
++
++ if ( ( nWriteMode == MULTI_PLANE_MID_PAGE ) || ( nWriteMode == MULTI_PLANE_LAST_PAGE ))
++ {
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == HYNIX_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID ) )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8181;
++ else if ( ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == INTEL_NAND_MAKER_ID ))
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++ }
++ else
++ {
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++ }
++
++ /* Write Row and Column Address */
++ NAND_IO_WriteRowColAddr( RowAddr, ColumnAddr, nDevInfo );
++
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Set SpareBuffer Pointer =>> ECCBuffer
++ //=========================================================================
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ memset( gNAND_IO_ShareEccBuffer, 0xFF, nDevInfo->EccWholeDataSize );
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++ }
++ else
++ {
++ pSpareB = (unsigned char*)nSpareBuffer;
++ pSpareB += NAND_IO_SPARE_SIZE_SMALL;
++ }
++
++ //=========================================================================
++ // Empty Page ECCBuffer Pointer Increment
++ //=========================================================================
++ for ( j = 0; j < nStartPPage; ++j )
++ {
++ if ( nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ pECC_Info = &gMLC_ECC_4Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_8BIT_TYPE )
++ pECC_Info = &gMLC_ECC_8Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_12BIT_TYPE )
++ pECC_Info = &gMLC_ECC_12Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_14BIT_TYPE )
++ pECC_Info = &gMLC_ECC_14Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_16BIT_TYPE )
++ pECC_Info = &gMLC_ECC_16Bit;
++ else
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ {
++ pSpare = (unsigned char*)pSpareB;
++
++ for ( i = 0; i < nDevInfo->EccDataSize; ++i )
++ pSpare[i] = pECC_Info->All_FF_512_ECC_Code[i];
++ }
++ else
++ {
++ memcpy( (void*)pSpareB, (void*)pECC_Info->All_FF_512_ECC_Code, nDevInfo->EccDataSize);
++ }
++
++ pSpareB += nDevInfo->EccDataSize;
++ }
++
++ *rEccBuffer = (unsigned int)pSpareB;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_IO_IRQ_WritePageMidProcess( NAND_IO_DEVINFO *nDevInfo, U8 nWriteMode );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nWriteMode =
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_IO_IRQ_WritePageMidProcess( NAND_IO_DEVINFO *nDevInfo, U8 nWriteMode )
++{
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ if ( nWriteMode == MULTI_PLANE_START_PAGE )
++ {
++ /* Command Multi Plane Page Program #2 [ 0x11 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1111;
++
++ if ( !( ( nDevInfo->Feature.MediaType & S_IL ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) ) )
++ NAND_IO_WaitBusyForCacheProgram( nDevInfo );
++ }
++ else if ( ( nWriteMode == MULTI_PLANE_MID_PAGE ) || ( nWriteMode == MULTI_PLANE_LAST_PAGE ) )
++ {
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID ) )
++ {
++ if ( ( nWriteMode == MULTI_PLANE_LAST_PAGE ) || ( nDevInfo->ExtInterleaveUsable == TRUE ) )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ else if ( nWriteMode == MULTI_PLANE_MID_PAGE )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1515;
++ }
++ else
++ {
++ // SAMSUNG, HYNIX, MICRON, INTEL, ST Maker TwoPlane Write Function
++ if ( nDevInfo->Feature.MediaType & S_MCP )
++ {
++ if ( nWriteMode == MULTI_PLANE_LAST_PAGE )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ else if ( nWriteMode == MULTI_PLANE_MID_PAGE )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1515;
++ }
++ else
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ }
++ }
++ else // normal page
++ {
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_IO_IRQ_WritePagePostProcess( void );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_IO_IRQ_WritePagePostProcess( void )
++{
++ NAND_IO_DisableChipSelect();
++ NAND_IO_PostProcess();
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_IO_IRQ_Write512DataPreProcess( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_IO_IRQ_Write512DataPreProcess( NAND_IO_DEVINFO *nDevInfo )
++{
++ //==========================================================
++ //
++ // ECC Encode Setup
++ //
++ //==========================================================
++ pIOBUSCFG_T->STORAGE = HwIOBUSCFG_STORAGE_NFC;
++ pECC->ECC_BASE = (unsigned int)&NAND_IO_HwLDATA_PA;
++
++ pECC->ECC_MASK = 0x00000000; /* Address mask for ECC area */
++
++ if ( nDevInfo->EccType == SLC_ECC_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_SLCEN;
++ else if (nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL4EN;
++ else if (nDevInfo->EccType == MLC_ECC_8BIT_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL8EN;
++ else if (nDevInfo->EccType == MLC_ECC_12BIT_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL12EN;
++ else if (nDevInfo->EccType == MLC_ECC_16BIT_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL16EN;
++
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* NAND_IO_ERROR NAND_IO_IRQ_Write512DataPostProcess( NAND_IO_DEVINFO *nDevInfo, U8* nECCBuffer );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nECCBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++NAND_IO_ERROR NAND_IO_IRQ_Write512DataPostProcess( NAND_IO_DEVINFO *nDevInfo, U8* nECCBuffer )
++{
++ unsigned int i;
++ #ifdef _LINUX_
++ unsigned char nTempBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nTempBuffer[30];
++ #endif
++ unsigned char *pSpare, *pEccB;
++ NAND_IO_ERROR res = (NAND_IO_ERROR)SUCCESS;
++
++ //============================
++ // Get ECC Code
++ //============================
++ if ( pNFC->NFC_CTRL1 & Hw30 )
++ BITSET( pNFC->NFC_CTRL1, Hw31 );
++
++ /* Load ECC code from ECC block */
++ if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ {
++ pSpare = (unsigned char*)nECCBuffer;
++ pEccB = (unsigned char*)nTempBuffer;
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pEccB );
++ for ( i = 0; i < nDevInfo->EccDataSize; ++i )
++ pSpare[i] = pEccB[i];
++ }
++ else
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, nECCBuffer );
++ }
++
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline void NAND_IO_IRQ_Mask( void );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++static __inline void NAND_IO_IRQ_Mask( void )
++{
++ #ifdef __USE_NAND_ISR__
++ unsigned int irq = NAND_IRQ_NFC;
++ if (irq < 32){
++ BITCLR(pPIC->IEN0, (1 << irq));
++ BITCLR(pPIC->INTMSK0, (1 << irq));
++ } else {
++ BITCLR(pPIC->IEN1, (1 << (irq - 32)));
++ BITCLR(pPIC->INTMSK1, (1 << (irq - 32)));
++ }
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline void NAND_IO_IRQ_UnMask( void );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++static __inline void NAND_IO_IRQ_UnMask( void )
++{
++ #ifdef __USE_NAND_ISR__
++ unsigned int irq = NAND_IRQ_NFC;
++
++ pNFC->NFC_IREQ = 0x77; // HwNFC_IREQ_FLAG1;
++ if (irq < 32) {
++ BITSET(pPIC->INTMSK0, (1 << irq));
++ BITSET(pPIC->CLR0, (1 << irq));
++ BITSET(pPIC->IEN0, (1 << irq));
++ } else {
++ BITSET(pPIC->INTMSK1, (1 << (irq - 32)));
++ BITSET(pPIC->CLR1, (1 << (irq - 32)));
++ BITSET(pPIC->IEN1, (1 << (irq - 32)));
++ }
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* NAND_IO_ERROR NAND_IO_IRQ_ExtInterruptSet(unsigned int irq);
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* irq =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++NAND_IO_ERROR NAND_IO_IRQ_ExtInterruptSet(unsigned int irq)
++{
++ unsigned int RegNum;
++ unsigned char nSource;
++ NAND_IO_ERROR res = (NAND_IO_ERROR)SUCCESS;
++
++ #if defined(TCC_NAND_RDY_B31)
++ nSource = 0x31; // GPIO_B31
++ #else
++ nSource = 0x2E; // GPIO_B28
++ #endif
++
++ if (( irq < 15 ) && ( irq > 2 ))
++ {
++ RegNum = (( irq - 3 ) >> 2 );
++ switch(RegNum)
++ {
++ case 0:
++ BITCLR(pGPIO->EINTSEL0, 0x3F << ( ( irq - 3 ) << 3 ));
++ BITSET(pGPIO->EINTSEL0, nSource << ( ( irq - 3 ) << 3 ));
++ break;
++
++ case 1:
++ BITCLR(pGPIO->EINTSEL1, 0x3F << ( ( irq - 7 ) << 3 ));
++ BITSET(pGPIO->EINTSEL1, nSource << ( ( irq - 7 ) << 3 ));
++ break;
++
++ case 2:
++ BITCLR(pGPIO->EINTSEL2, 0x3F << ( ( irq - 11 ) << 3 ));
++ BITSET(pGPIO->EINTSEL2, nSource << ( ( irq - 11 ) << 3 ));
++ break;
++ }
++
++ res = SUCCESS;
++ }
++ else
++ {
++ res = ERR_NAND_IO_WRONG_PARAMETER;
++ }
++
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* NAND_IO_ERROR NAND_IO_IRQ_ExtInterruptClear(unsigned int irq);
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* irq =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++NAND_IO_ERROR NAND_IO_IRQ_ExtInterruptClear(unsigned int irq)
++{
++ unsigned int RegNum;
++ unsigned char nSource;
++ NAND_IO_ERROR res = (NAND_IO_ERROR)SUCCESS;
++
++ #if defined(TCC_NAND_RDY_B31)
++ nSource = 0x31; // GPIO_B31
++ #else
++ nSource = 0x2E; // GPIO_B28
++ #endif
++
++ if (( irq < 15 ) && ( irq > 2 ))
++ {
++ RegNum = (( irq - 3 ) >> 2 );
++ switch(RegNum)
++ {
++ case 0:
++ BITCLR(pGPIO->EINTSEL0, 0x3F << ( ( irq - 3 ) << 3 ));
++ break;
++
++ case 1:
++ BITCLR(pGPIO->EINTSEL1, 0x3F << ( ( irq - 7 ) << 3 ));
++ break;
++
++ case 2:
++ BITCLR(pGPIO->EINTSEL2, 0x3F << ( ( irq - 11 ) << 3 ));
++ break;
++ }
++
++ BITSET(pPIC->CLR0, (1 << irq));
++ res = SUCCESS;
++ }
++ else
++ {
++ res = ERR_NAND_IO_WRONG_PARAMETER;
++ }
++
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_IO_IRQ_ReadyBusySet( void );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_IO_IRQ_ReadyBusySet( void )
++{
++ pIOBUSCFG_T->STORAGE = HwIOBUSCFG_STORAGE_NFC;
++ pECC->ECC_BASE = (unsigned int)&NAND_IO_HwLDATA_PA;
++
++ #if defined(TCC_NAND_RDY_B28)
++ // Externel intr GPIOB_28 config
++ pGPIO->GPBFN3 &= ~0x00010000; // GPIO_B28 --> Normal GPIO
++ BITCLR(pGPIO->GPBEN, Hw28); // Input Mode
++ BITSET(pPIC->SEL0, (1 << NAND_IRQ_READY)); // Interrupt Select --> IRQ
++ #endif
++
++ BITCLR(pPIC->IEN0, (1 << NAND_IRQ_READY)); // Interrupt Disable
++ BITSET(pPIC->CLR0, (1 << NAND_IRQ_READY)); // Interrupt Status Clear
++
++ NAND_IO_IRQ_ExtInterruptSet(NAND_IRQ_READY);
++
++ BITSET(pPIC->MODE0, (1 << NAND_IRQ_READY)); // Set: Level-triggered, Cler: Edge-triggered
++ BITCLR(pPIC->POL0, (1 << NAND_IRQ_READY)); // Interrupt Set Active-High
++ BITSET(pPIC->CLR0, (1 << NAND_IRQ_READY)); // Interrupt Status Clear
++ BITSET(pPIC->IEN0, (1 << NAND_IRQ_READY)); // Interrupt Enable
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_IO_IRQ_ReadyBusyClear( void );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_IO_IRQ_ReadyBusyClear( void )
++{
++ BITSET(pPIC->CLR0, (1 << NAND_IRQ_READY)); // Interrupt Status Clear
++ NAND_IO_IRQ_ExtInterruptClear(NAND_IRQ_READY);
++ BITCLR(pPIC->IEN0, (1 << NAND_IRQ_READY)); // Interrupt Disable
++
++ #if defined(TCC_NAND_RDY_B31)
++ pGPIO->GPBFN3 &= ~0x10000000; // ND_RDY: GPIO_B31
++ BITCLR(pGPIO->GPBEN, Hw31);
++ #else
++ pGPIO->GPBFN3 |= 0x00010000; // GPIO_B28 --> EDI
++ #endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_IO_IRQ_SetupDMA( void *pDST, int nMode );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nMode =
++* pDST =
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_IO_IRQ_SetupDMA( void *pDST, int nMode )
++{
++ unsigned int nSourceAddr, nDestAddr;
++ unsigned uCHCTRL;
++ unsigned int uTmp;
++ unsigned int uSrcInc, uSrcMask;
++ unsigned int uDstInc, uDstMask;
++
++ if ( nMode == NAND_IO_DMA_WRITE )
++ {
++ uSrcInc = 4;
++ uSrcMask = 0;
++ uDstInc = 0;
++ uDstMask = 0;
++ }
++ else
++ {
++ uSrcInc = 0;
++ uSrcMask = 0;
++ uDstInc = 4;
++ uDstMask = 0;
++ }
++
++ if ( nMode == NAND_IO_DMA_WRITE )
++ {
++ BITCSET(pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_8 | HwNFC_CTRL_DEN_EN | HwNFC_CTRL_PSIZE_512 );
++ // Target Physical Address- for DMA H/W Control Set
++ nSourceAddr = (unsigned int)pDST;
++ nDestAddr = (unsigned int)&NAND_IO_HwLDATA_PA;
++
++ //============================================================
++ // DMA Control Register Set
++ //============================================================
++ uCHCTRL =
++ // HwCHCTRL_SYNC_ON |
++ // HwCHCTRL_HRD_W |
++ HwCHCTRL_BST_BURST |
++ HwCHCTRL_TYPE_SINGL |
++ HwCHCTRL_HRD_WR |
++ // HwCHCTRL_BST_BURST |
++ HwCHCTRL_BSIZE_8 |
++ HwCHCTRL_WSIZE_32 |
++ HwCHCTRL_FLAG |
++ HwCHCTRL_EN_ON |
++ 0;
++ }
++ else
++ {
++ // pSRC: NFC_LDATA
++ // pDST: Buffer Address
++
++ BITCSET(pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_8 | HwNFC_CTRL_DEN_EN | HwNFC_CTRL_PSIZE_512 );
++
++ nSourceAddr = (unsigned int)&NAND_IO_HwLDATA_PA;
++ nDestAddr = (unsigned int)pDST;
++
++ //============================================================
++ // DMA Control Register Set
++ //============================================================
++ uCHCTRL =
++ // HwCHCTRL_SYNC_ON |
++ // HwCHCTRL_HRD_W |
++ HwCHCTRL_BST_BURST |
++ HwCHCTRL_TYPE_SINGL |
++ HwCHCTRL_HRD_RD |
++ // HwCHCTRL_BST_BURST |
++ HwCHCTRL_BSIZE_8 |
++ HwCHCTRL_WSIZE_32 |
++ HwCHCTRL_FLAG |
++ HwCHCTRL_EN_ON |
++ 0;
++ }
++
++ //============================================================
++ // Set Source Address & Source Parameter (mask + increment)
++ //============================================================
++ pNAND_DMA->ST_SADR = nSourceAddr;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ pNAND_DMA->SPARAM[0] = (uSrcInc | (uSrcMask << 4));
++ #else
++ pNAND_DMA->SPARAM = (uSrcInc | (uSrcMask << 4));
++ #endif
++ //============================================================
++ // Set Dest Address & Dest Parameter (mask + increment)
++ //============================================================
++ pNAND_DMA->ST_DADR = nDestAddr;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ pNAND_DMA->DPARAM[0] = (uDstInc | (uDstMask << 4));
++ #else
++ pNAND_DMA->DPARAM = (uDstInc | (uDstMask << 4));
++ #endif
++ //============================================================
++ // Calculate byte size per 1 Hop transfer
++ //============================================================
++ uTmp = (uCHCTRL & (Hw5+Hw4)) >> 4; // calc log2(word size)
++ uTmp = uTmp + ( (uCHCTRL & (Hw7+Hw6)) >> 6); // calc log2(word * burst size)
++
++ //============================================================
++ // Set External DMA Request Register
++ //============================================================
++ pNAND_DMA->EXTREQ = Hw18; // NFC
++
++ //============================================================
++ // Set Hcount
++ //============================================================
++ pNAND_DMA->HCOUNT = 0x10;
++
++ //============================================================
++ // Set & Enable DMA
++ //============================================================
++ pNAND_DMA->CHCTRL = uCHCTRL;
++
++ //============================================================
++ // Set NFC DSize & IREQ Clear
++ //============================================================
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // HwNFC_IREQ_FLAG1;
++
++ //============================================================
++ // DMA Transfer Start
++ //============================================================
++ #ifdef NAND_GPIO_DEBUG
++ BITSET(pGPIO->GPFDAT, Hw21);
++ #endif
++ if ( nMode == NAND_IO_DMA_WRITE )
++ {
++ if ( pNFC->NFC_CTRL1 & Hw31 )
++ BITCLR( pNFC->NFC_CTRL1, Hw31 );
++
++ pNFC->NFC_PSTART = 0;
++}
++ else
++ pNFC->NFC_RSTART = 0;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* void NAND_IO_IRQ_SetupDMAForSpare( int nDSize );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDSize =
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++void NAND_IO_IRQ_SetupDMAForSpare( int nDSize )
++{
++ #if defined(USE_V_ADDRESS) && defined(_LINUX_)
++ unsigned int uTmp;
++ unsigned int *pDMA_PhyBuffer;
++ unsigned int nSourceAddr, nDestAddr;
++ unsigned uCHCTRL;
++
++ pDMA_PhyBuffer = (unsigned int*)gNAND_IO_ShareEccBuffer_w; // Working Address
++
++ BITCSET(pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_8 | HwNFC_CTRL_DEN_EN | HwNFC_CTRL_PSIZE_512 );
++
++ #if defined(_WINCE_) || defined(_LINUX_)
++ nSourceAddr = (unsigned int)&NAND_IO_HwLDATA_PA; // NFC_LDATA Physical Address: ex_TCC89,92XX: 0XF050b0020
++ #else
++ nSourceAddr = (unsigned int)&pNFC->NFC_LDATA;
++ #endif
++ nDestAddr = (unsigned int)pDMA_PhyBuffer;
++
++ //============================================================
++ // DMA Control Register Set
++ //============================================================
++ uCHCTRL =
++// HwCHCTRL_SYNC_ON |
++// HwCHCTRL_HRD_W |
++ HwCHCTRL_BST_BURST |
++ HwCHCTRL_TYPE_SINGL |
++ HwCHCTRL_HRD_RD |
++// HwCHCTRL_BST_BURST |
++ HwCHCTRL_BSIZE_8 |
++ HwCHCTRL_WSIZE_32 |
++ HwCHCTRL_FLAG |
++ HwCHCTRL_EN_ON |
++ 0;
++
++ //============================================================
++ // Set Source Address & Source Parameter (mask + increment)
++ //============================================================
++ pNAND_DMA->ST_SADR = nSourceAddr;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ pNAND_DMA->SPARAM[0] = 0;
++ #else
++ pNAND_DMA->SPARAM = 0;
++ #endif
++ //============================================================
++ // Set Dest Address & Dest Parameter (mask + increment)
++ //============================================================
++ pNAND_DMA->ST_DADR = nDestAddr;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ pNAND_DMA->DPARAM[0] = 0x4;
++ #else
++ pNAND_DMA->DPARAM = 0x4;
++ #endif
++ //============================================================
++ // Calculate byte size per 1 Hop transfer
++ //============================================================
++ uTmp = (uCHCTRL & (Hw5+Hw4)) >> 4; // calc log2(word size)
++ uTmp = uTmp + ( (uCHCTRL & (Hw7+Hw6)) >> 6); // calc log2(word * burst size)
++
++ //============================================================
++ // Set External DMA Request Register
++ //============================================================
++ pNAND_DMA->EXTREQ = Hw18; // NFC
++
++ //============================================================
++ // Set Hcount
++ //============================================================
++ if (uTmp)
++ pNAND_DMA->HCOUNT = (nDSize + (1 << uTmp) - 1) >> uTmp;
++ else
++ pNAND_DMA->HCOUNT = nDSize;
++
++ //============================================================
++ // Set & Enable DMA
++ //============================================================
++ pNAND_DMA->CHCTRL = uCHCTRL;
++
++ //============================================================
++ // Set NFC DSize & IREQ Clear
++ //============================================================
++ pNFC->NFC_DSIZE = nDSize ;
++ pNFC->NFC_IREQ = 0x77; // HwNFC_IREQ_FLAG1;
++
++ //============================================================
++ // DMA Transfer Start
++ //============================================================
++ #ifdef NAND_GPIO_DEBUG
++ BITSET(pGPIO->GPFDAT, Hw21);
++ #endif
++ pNFC->NFC_RSTART = 0;
++#endif
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_ReadStatus( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadStatus( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int uStatus;
++ unsigned int uCheckBit;
++ unsigned long int timeout;
++ NAND_IO_ERROR res;
++
++ //================================
++ // Command READ STATUS [ 0x70 ]
++ //================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7070;
++
++ // Delay : more than 200nS
++ NAND_IO_Delay();
++
++ //=============================================
++ // DATA BUS WIDTH Setting
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //================================
++ // Read IO Status
++ //================================
++ timeout = 0xFFFFF;
++ while ( timeout )
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x4040;
++
++ /* Check if it is ready */
++ if ( ( uStatus & uCheckBit ) == uCheckBit )
++ break;
++ }
++
++ if ( !timeout )
++ return ERR_NAND_IO_TIME_OUT_READ_STATUS;
++
++ //================================
++ // Check Bit Status
++ //================================
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x0101;
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( uStatus & uCheckBit )
++ {
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ if (uStatus & ( uCheckBit & 0x0100 ) )
++ res |= NAND_IO_STATUS_FAIL_CS1_PARALLEL;
++
++ if (uStatus & ( uCheckBit & 0x0001 ) )
++ res |= NAND_IO_STATUS_FAIL_CS0_PARALLEL;
++ }
++ else
++ {
++ if (uStatus & uCheckBit )
++ res |= NAND_IO_STATUS_FAIL_CS0_SERIAL;
++ }
++ }
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_ReadStatusForMultiPlane( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForMultiPlane( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int uStatus;
++ unsigned int uCheckBit;
++ unsigned long int timeout;
++ NAND_IO_ERROR res;
++
++ //================================
++ // Command READ STATUS [ 0x70 ]
++ //================================
++ if ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7070;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7171;
++ else if ( ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == INTEL_NAND_MAKER_ID ) )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7070;
++ else
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7070;
++
++ // Delay : more than 200nS
++ NAND_IO_Delay();
++
++ //=============================================
++ // DATA BUS WIDTH Setting
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //================================
++ // Read IO Status
++ //================================
++ timeout = 0xFFFFF;
++ while ( timeout )
++ {
++ /* Micron MultiPlane ReadBusy Check 0x40*/
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x4040;
++
++ /* Check if it is ready */
++ if ( ( uStatus & uCheckBit ) == uCheckBit )
++ break;
++ }
++
++ if ( !timeout )
++ return ERR_NAND_IO_TIME_OUT_READ_STATUS;
++
++ //================================
++ // Check Bit Status
++ //================================
++ if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x0101;
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( uStatus & uCheckBit )
++ {
++ if ( uStatus & ( nDevInfo->CmdMask & 0x0202 ))
++ res = (NAND_IO_ERROR)NAND_IO_DISTRICT_0;
++ else if ( uStatus & ( nDevInfo->CmdMask & 0x0404 ))
++ res = (NAND_IO_ERROR)NAND_IO_DISTRICT_1;
++ }
++ }
++ else
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x0101;
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( uStatus & uCheckBit )
++ {
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ if (uStatus & ( uCheckBit & 0x0100 ) )
++ res |= NAND_IO_STATUS_FAIL_CS1_PARALLEL;
++
++ if (uStatus & ( uCheckBit & 0x0001 ) )
++ res |= NAND_IO_STATUS_FAIL_CS0_PARALLEL;
++ }
++ else
++ {
++ if (uStatus & uCheckBit )
++ res |= NAND_IO_STATUS_FAIL_CS0_SERIAL;
++ }
++ }
++ }
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_ReadStatusForCacheProgram( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForCacheProgram( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int uStatus;
++ unsigned int uCheckBit;
++ unsigned long int timeout;
++ NAND_IO_ERROR res;
++
++ //================================
++ // Command READ STATUS [ 0x70 ]
++ //================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7070;
++
++ // Delay : more than 200nS
++ NAND_IO_Delay();
++
++ //=============================================
++ // DATA BUS WIDTH Setting
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //================================
++ // Read IO Status
++ //================================
++ timeout = 0xFFFFF;
++ while ( timeout )
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == INTEL_NAND_MAKER_ID ) )
++ uCheckBit = nDevInfo->CmdMask & 0x2020;
++ else
++ uCheckBit = nDevInfo->CmdMask & 0x4040;
++
++ /* Check if it is ready */
++ if ( ( uStatus & uCheckBit ) == uCheckBit )
++ break;
++ }
++
++ if ( !timeout )
++ return ERR_NAND_IO_TIME_OUT_READ_STATUS;
++
++ //================================
++ // Check Bit Status
++ //================================
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x0303;
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( uStatus & uCheckBit )
++ {
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ if (uStatus & ( uCheckBit & 0x0300 ) )
++ res |= NAND_IO_STATUS_FAIL_CS1_PARALLEL;
++
++ if (uStatus & ( uCheckBit & 0x0003 ) )
++ res |= NAND_IO_STATUS_FAIL_CS0_PARALLEL;
++ }
++ else
++ {
++ if (uStatus & uCheckBit )
++ res |= NAND_IO_STATUS_FAIL_CS0_SERIAL;
++ }
++ }
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_ReadStatusForInterleave( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nPageAddr =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForInterleave( NAND_IO_DEVINFO *nDevInfo, U32 nPageAddr )
++{
++ unsigned int uStatus;
++ unsigned int uCheckBit;
++ unsigned int ChipNum;
++ unsigned long int timeout;
++ NAND_IO_ERROR res;
++
++ // Delay : more than 200nS
++ NAND_IO_Delay();
++
++ //=============================================
++ // DATA BUS WIDTH Setting
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //================================
++ // Command READ STATUS
++ //================================
++ if ( nPageAddr < (U32)( ( nDevInfo->Feature.PBpV >> 1 ) * nDevInfo->Feature.PpB ) )
++ {
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP1 )
++ {
++ if ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF1F1;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF2F2;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7171;
++ else if ( ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == INTEL_NAND_MAKER_ID ) )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7878;
++ NAND_IO_WriteBlockPageAddr( gInterLeaveDie0BlockAddr, nDevInfo );
++ }
++
++ ChipNum = NAND_IO_STATUS_INTERLEAVING_CHIP1;
++ }
++ else
++ return (NAND_IO_ERROR)SUCCESS;
++ }
++ else
++ {
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP2 )
++ {
++ if ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF2F2;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF3F3;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7171;
++ else if ( ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == INTEL_NAND_MAKER_ID ) )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7878;
++ NAND_IO_WriteBlockPageAddr( gInterLeaveDie1BlockAddr, nDevInfo );
++ }
++ ChipNum = NAND_IO_STATUS_INTERLEAVING_CHIP2;
++ }
++ else
++ return (NAND_IO_ERROR)SUCCESS;
++ }
++
++ //================================
++ // Read IO Status
++ //================================
++ timeout = 0xFFFFF;
++ while ( timeout )
++ {
++ if ( ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID ) ||
++ ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID ) ||
++ ( nDevInfo->Feature.DeviceID.Code[0] == INTEL_NAND_MAKER_ID ) ||
++ ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID ) )
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x4040;
++
++ /* Check if it is ready */
++ if ( ( uStatus & uCheckBit ) == uCheckBit )
++ {
++ uCheckBit = nDevInfo->CmdMask & 0x0101;
++
++ /* Check if it is Fail */
++ if ( uStatus & uCheckBit )
++ {
++ if ( ChipNum == NAND_IO_STATUS_INTERLEAVING_CHIP1 )
++ {
++ if ( ( nDevInfo->Feature.MediaType & S_MP ) || ( nDevInfo->Feature.MediaType & S_MCP ) )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[0] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BlockStatus[1] = MULTI_PLANE_BAD_BLOCK;
++ }
++ else
++ nDevInfo->BadBlockInfo.BlockStatus[nDevInfo->ChipNo] = MULTI_PLANE_BAD_BLOCK;
++ }
++ else if ( ChipNum == NAND_IO_STATUS_INTERLEAVING_CHIP2 )
++ {
++ if ( ( nDevInfo->Feature.MediaType & S_MP ) || ( nDevInfo->Feature.MediaType & S_MCP ) )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[2] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BlockStatus[3] = MULTI_PLANE_BAD_BLOCK;
++ }
++ else
++ nDevInfo->BadBlockInfo.BlockStatus[nDevInfo->ChipNo] = MULTI_PLANE_BAD_BLOCK;
++ }
++
++ gInterLeaveWriteStatus = MULTI_PLANE_BAD_BLOCK;
++ }
++ break;
++ }
++ }
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x4040;
++
++ /* Check if it is ready */
++ if ( ( uStatus & uCheckBit ) == uCheckBit )
++ {
++ uCheckBit = nDevInfo->CmdMask & 0x0101;
++
++ /* Check if it is Fail */
++ if ( uStatus & uCheckBit )
++ {
++ if ( ChipNum == NAND_IO_STATUS_INTERLEAVING_CHIP1 )
++ {
++ if ( uStatus & ( nDevInfo->CmdMask & 0x0202 ))
++ nDevInfo->BadBlockInfo.BlockStatus[0] = MULTI_PLANE_BAD_BLOCK;
++ else if ( uStatus & ( nDevInfo->CmdMask & 0x0404 ))
++ nDevInfo->BadBlockInfo.BlockStatus[1] = MULTI_PLANE_BAD_BLOCK;
++ }
++ else if ( ChipNum == NAND_IO_STATUS_INTERLEAVING_CHIP2 )
++ {
++ if ( uStatus & ( nDevInfo->CmdMask & 0x0202 ))
++ nDevInfo->BadBlockInfo.BlockStatus[2] = MULTI_PLANE_BAD_BLOCK;
++ else if ( uStatus & ( nDevInfo->CmdMask & 0x0404 ))
++ nDevInfo->BadBlockInfo.BlockStatus[3] = MULTI_PLANE_BAD_BLOCK;
++ }
++
++ gInterLeaveWriteStatus = MULTI_PLANE_BAD_BLOCK;
++ }
++ break;
++ }
++ }
++ }
++
++ if ( !timeout )
++ return ERR_NAND_IO_TIME_OUT_READ_STATUS;
++
++ //================================
++ // SET NAND IO Status
++ //================================
++ switch(ChipNum)
++ {
++ case NAND_IO_STATUS_INTERLEAVING_CHIP1:
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP1;
++ break;
++
++ case NAND_IO_STATUS_INTERLEAVING_CHIP2:
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP2;
++ break;
++ }
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_ReadStatusForInterleaveClear( NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadStatusForInterleaveClear( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int uStatus;
++ unsigned int uCheckBit;
++ unsigned long int timeout;
++ NAND_IO_ERROR res;
++
++ // Delay : more than 200nS
++ NAND_IO_Delay();
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=============================================
++ // DATA BUS WIDTH Setting
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=============================================
++ // Command READ STATUS - Interleave CHIP 1
++ //=============================================
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP1 )
++ {
++ if ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF1F1;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF2F2;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7171;
++ else if ( ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == INTEL_NAND_MAKER_ID ) )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7878;
++ NAND_IO_WriteBlockPageAddr( gInterLeaveDie0BlockAddr, nDevInfo );
++ }
++
++ timeout = 0xFFFFF;
++ while ( timeout )
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x4040;
++
++ /* Check if it is ready */
++ if ( ( uStatus & uCheckBit ) == uCheckBit )
++ {
++ uCheckBit = nDevInfo->CmdMask & 0x0101;
++
++ /* Check if it is Fail */
++ if ( uStatus & uCheckBit )
++ {
++ if ( ( nDevInfo->Feature.MediaType & S_MP ) || ( nDevInfo->Feature.MediaType & S_MCP ) )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[0] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BlockStatus[1] = MULTI_PLANE_BAD_BLOCK;
++ }
++ else
++ nDevInfo->BadBlockInfo.BlockStatus[nDevInfo->ChipNo] = MULTI_PLANE_BAD_BLOCK;
++
++ gInterLeaveWriteStatus = MULTI_PLANE_BAD_BLOCK;
++ }
++ break;
++ }
++ }
++
++ if ( !timeout )
++ return ERR_NAND_IO_TIME_OUT_READ_STATUS;
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP1;
++ }
++
++ //=============================================
++ // Command READ STATUS - Interleave CHIP 2
++ //=============================================
++ if ( gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_CHIP2 )
++ {
++ if ( nDevInfo->Feature.DeviceID.Code[0] == SAMSUNG_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF2F2;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == ST_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF3F3;
++ else if ( nDevInfo->Feature.DeviceID.Code[0] == TOSHIBA_NAND_MAKER_ID )
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7171;
++ else if ( ( nDevInfo->Feature.DeviceID.Code[0] == MICRON_NAND_MAKER_ID ) || ( nDevInfo->Feature.DeviceID.Code[0] == INTEL_NAND_MAKER_ID ) )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7878;
++ NAND_IO_WriteBlockPageAddr( gInterLeaveDie1BlockAddr, nDevInfo );
++ }
++
++ timeout = 0xFFFFF;
++ while ( timeout )
++ {
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uCheckBit = nDevInfo->CmdMask & 0x4040;
++
++ /* Check if it is ready */
++ if ( ( uStatus & uCheckBit ) == uCheckBit )
++ {
++ uCheckBit = nDevInfo->CmdMask & 0x0101;
++
++ /* Check if it is Fail */
++ if ( uStatus & uCheckBit )
++ {
++ if ( ( nDevInfo->Feature.MediaType & S_MP ) || ( nDevInfo->Feature.MediaType & S_MCP ) )
++ {
++ nDevInfo->BadBlockInfo.BlockStatus[2] = MULTI_PLANE_BAD_BLOCK;
++ nDevInfo->BadBlockInfo.BlockStatus[3] = MULTI_PLANE_BAD_BLOCK;
++ }
++ else
++ nDevInfo->BadBlockInfo.BlockStatus[nDevInfo->ChipNo] = MULTI_PLANE_BAD_BLOCK;
++
++ gInterLeaveWriteStatus = MULTI_PLANE_BAD_BLOCK;
++ }
++ break;
++ }
++ }
++
++ if ( !timeout )
++ return ERR_NAND_IO_TIME_OUT_READ_STATUS;
++
++ gInterLeaveIoStatus &= ~NAND_IO_STATUS_INTERLEAVING_CHIP2;
++ }
++
++ if ( !(gInterLeaveIoStatus & NAND_IO_STATUS_INTERLEAVING_MASK ))
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForRead( U32 nPageAddr, U16 nColumnAddr,
++* U32* rRowAddr, U32* rColumnAddr,
++* NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nColumnAddr =
++* nDevInfo =
++* nPageAddr =
++* rColumnAddr =
++* rRowAddr =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForRead( U32 nPageAddr, U16 nColumnAddr,
++ U32* rRowAddr, U32* rColumnAddr,
++ NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned long int RowAddr;
++ unsigned long int ColumnAddr;
++
++ if ( nColumnAddr > ( nDevInfo->Feature.PageSize + nDevInfo->Feature.SpareSize ) )
++ return ERR_NAND_IO_WRONG_PARAMETER_ROW_COL_ADDRESS;
++
++ //==================================================
++ // Generate Column & Row Address
++ //==================================================
++ if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ // ColumnAddr ADR[7:0] ==> nColumnAddr
++ // RowAddr ADR[25:9] ==> (nPageAddr)*512
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (nColumnAddr>>1) : nColumnAddr;
++ RowAddr = nPageAddr;
++
++ if ( nDevInfo->Feature.MediaType & A_08BIT )
++ {
++ /* Command READ for SMALL NAND */
++ if ( ColumnAddr < 256 )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ ColumnAddr = ColumnAddr;
++ }
++ else if ( ColumnAddr < 512 )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0101;
++ ColumnAddr = ColumnAddr-256;
++ }
++ else
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5050;
++ ColumnAddr = ColumnAddr-512;
++ }
++ }
++ else if ( nDevInfo->Feature.MediaType & A_16BIT )
++ {
++ /* Command READ for SMALL NAND For 16Bit */
++ if ( ColumnAddr < 256 )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ ColumnAddr = ColumnAddr;
++ }
++ else
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5050;
++ ColumnAddr = ColumnAddr;
++ }
++ }
++ }
++ else
++ {
++ /* Command READ [ 0x00 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ // ColumnAddr ADR[11:0] ==> nColumnAddr
++ // RowAddr ADR[31:12] ==> nPageAddr
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (nColumnAddr>>1) : nColumnAddr;
++ RowAddr = nPageAddr;
++
++ }
++
++ *rRowAddr = RowAddr;
++ *rColumnAddr = ColumnAddr;
++
++ return (NAND_IO_ERROR)SUCCESS;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForWrite( U32 nPageAddr, U16 nColumnAddr,
++* U32* rRowAddr, U32* rColumnAddr,
++* NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nColumnAddr =
++* nDevInfo =
++* nPageAddr =
++* rColumnAddr =
++* rRowAddr =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForWrite( U32 nPageAddr, U16 nColumnAddr,
++ U32* rRowAddr, U32* rColumnAddr,
++ NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned long int RowAddr;
++ unsigned long int ColumnAddr;
++
++ if ( nColumnAddr > ( nDevInfo->Feature.PageSize + nDevInfo->Feature.SpareSize ) )
++ return ERR_NAND_IO_WRONG_PARAMETER_ROW_COL_ADDRESS;
++
++ //==================================================
++ // Generate Column & Row Address
++ //==================================================
++ if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ // ColumnAddr ADR[7:0] ==> nColumnAddr
++ // RowAddr ADR[25:9] ==> (nPageAddr)*512
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (nColumnAddr>>1) : nColumnAddr;
++ RowAddr = nPageAddr;
++
++ if ( nDevInfo->Feature.MediaType & A_08BIT )
++ {
++ /* Command READ for SMALL NAND */
++ if ( ColumnAddr < 256 )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ ColumnAddr = ColumnAddr;
++ }
++ else if ( ColumnAddr < 512 )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0101;
++ ColumnAddr = ColumnAddr-256;
++ }
++ else
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5050;
++ ColumnAddr = ColumnAddr-512;
++ }
++ }
++ else if ( nDevInfo->Feature.MediaType & A_16BIT )
++ {
++ /* Command READ for SMALL NAND */
++ if ( ColumnAddr < 256 )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ ColumnAddr = ColumnAddr;
++ }
++ else
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5050;
++ ColumnAddr = ColumnAddr;
++ }
++ }
++ }
++ else
++ {
++ // ColumnAddr ADR[11:0] ==> nColumnAddr
++ // RowAddr ADR[31:12] ==> nPageAddr
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (nColumnAddr>>1) : nColumnAddr;
++ RowAddr = nPageAddr;
++ }
++
++ *rRowAddr = RowAddr;
++ *rColumnAddr = ColumnAddr;
++
++ return (NAND_IO_ERROR)SUCCESS;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForCBandCP( U32 nPageAddr, U16 nColumnAddr,
++* U32* rRowAddr, U32* rColumnAddr,
++* NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nColumnAddr =
++* nDevInfo =
++* nPageAddr =
++* rColumnAddr =
++* rRowAddr =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_GenerateRowColAddrForCBandCP( U32 nPageAddr, U16 nColumnAddr,
++ U32* rRowAddr, U32* rColumnAddr,
++ NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned long int RowAddr;
++ unsigned long int ColumnAddr;
++
++ if ( nColumnAddr > 0 )
++ return ERR_NAND_IO_WRONG_PARAMETER_ROW_COL_ADDRESS;
++
++ //==================================================
++ // Generate Column & Row Address
++ //==================================================
++ if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ // ColumnAddr ADR[7:0] ==> nColumnAddr
++ // RowAddr ADR[25:9] ==> (nPageAddr)*512
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (nColumnAddr>>1) : nColumnAddr;
++ RowAddr = nPageAddr;
++ ColumnAddr = ColumnAddr;
++ }
++ else
++ {
++ // ColumnAddr ADR[11:0] ==> nColumnAddr
++ // RowAddr ADR[31:12] ==> nPageAddr
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (nColumnAddr>>1) : nColumnAddr;
++ RowAddr = nPageAddr;
++ }
++
++ *rRowAddr = RowAddr;
++ *rColumnAddr = ColumnAddr;
++
++ return (NAND_IO_ERROR)SUCCESS;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_WriteRowColAddr( U32 nRowAddr, U32 nColumnAddr, NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nColumnAddr =
++* nDevInfo =
++* nRowAddr =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_WriteRowColAddr( U32 nRowAddr, U32 nColumnAddr, NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int nTempAddr;
++ unsigned int i;
++
++ //==================================================
++ // Write Column Address
++ //==================================================
++ for ( i = 0; i < nDevInfo->Feature.ColCycle; ++i )
++ {
++ nTempAddr = nDevInfo->CmdMask & (((nColumnAddr<<8)&0xFF00)|(nColumnAddr&0x00FF));
++ pNFC->NFC_SADDR = nTempAddr;
++
++ nColumnAddr = nColumnAddr >> 8;
++ }
++
++ //==================================================
++ // Write Row Address
++ //==================================================
++ nRowAddr = nRowAddr;
++
++ for ( i = 0; i < nDevInfo->Feature.RowCycle; ++i )
++ {
++ nTempAddr = nDevInfo->CmdMask & (((nRowAddr<<8)&0xFF00)|(nRowAddr&0x00FF));
++ pNFC->NFC_SADDR = nTempAddr;
++
++ nRowAddr = nRowAddr >> 8;
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_WriteColAddr( U32 nColumnAddr, NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nColumnAddr =
++* nDevInfo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++void NAND_IO_WriteColAddr( U32 nColumnAddr, NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int i;
++
++ //==================================================
++ // Write Column Address
++ //==================================================
++ for ( i = 0; i < nDevInfo->Feature.ColCycle; ++i )
++ {
++ pNFC->NFC_SADDR = nDevInfo->CmdMask & (((nColumnAddr<<8)&0xFF00)|(nColumnAddr&0x00FF));
++ nColumnAddr = nColumnAddr >> 8;
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_WriteBlockPageAddr( U32 nBlockPageAddr, NAND_IO_DEVINFO *nDevInfo );
++*
++* DESCRIPTION :
++* INPUT:
++* nBlockPageAddr =
++* nDevInfo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_WriteBlockPageAddr( U32 nBlockPageAddr, NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int i;
++
++ //==================================================
++ // Write Block Address
++ //==================================================
++ for ( i = 0; i < nDevInfo->Feature.RowCycle; ++i )
++ {
++ pNFC->NFC_SADDR = nDevInfo->CmdMask & (((nBlockPageAddr<<8)&0xFF00)|(nBlockPageAddr&0x00FF));
++ nBlockPageAddr = nBlockPageAddr >> 8;
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline void NAND_IO_SetupDMA( void *pSRC, unsigned uSrcInc, unsigned uSrcMask,
++* void *pDST, unsigned uDstInc, unsigned uDstMask, int nMode );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nMode =
++* pDST =
++* pSRC =
++* uDstInc =
++* uDstMask =
++* uSrcInc =
++* uSrcMask =
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++static __inline void NAND_IO_SetupDMA( void *pSRC, unsigned uSrcInc, unsigned uSrcMask,
++ void *pDST, unsigned uDstInc, unsigned uDstMask, int nMode, int nDSize )
++{
++ unsigned int *pDMA_PhyBuffer;
++ unsigned int *pDMA_WorkBuffer;
++ unsigned int nSourceAddr, nDestAddr;
++ unsigned uCHCTRL;
++ unsigned int uTmp;
++
++ #if defined(_WINCE_)
++ tSYSTEM_PARAM *pSYS_Work_PARAM = (tSYSTEM_PARAM*)(SYSTEM_PARAM_BASEADDRESS);
++ #endif
++
++ #if defined(_WINCE_)
++ pDMA_PhyBuffer = (unsigned int*)pSYS_Work_PARAM->DMA2.CH0_BUFFER; // Working Address
++ pDMA_WorkBuffer = (unsigned int*)pSYS_PARAM->DMA2.CH0_BUFFER; // Physical Address
++ #elif defined(_LINUX_)
++ #ifdef KERNEL_DRIVER
++ pDMA_PhyBuffer = (unsigned int*)dma_t.dma_addr;
++ pDMA_WorkBuffer = (unsigned int*)dma_t.v_addr;
++ #else
++ pDMA_PhyBuffer = (unsigned int*)DMA_ADDR;
++ pDMA_WorkBuffer = (unsigned int*)DMA_ADDR;
++ #endif
++ #else // NU
++ pDMA_PhyBuffer = (unsigned int*)0x10003000;
++ pDMA_WorkBuffer = (unsigned int*)0x10003000;
++ #endif
++
++ if ( nMode == NAND_IO_DMA_WRITE )
++ {
++ // pSRC: Buffer Address
++ // pDST: NFC_LDATA
++
++ BITCSET(pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_8 | HwNFC_CTRL_DEN_EN | HwNFC_CTRL_PSIZE_512 );
++
++ //pSRC --> pDMA_WorkBuffer
++ memcpy( pDMA_WorkBuffer, pSRC, nDSize );
++
++ // Target Physical Address- for DMA H/W Control Set
++ nSourceAddr = (unsigned int)pDMA_PhyBuffer;
++ nDestAddr = (unsigned int)pDST;
++
++ //============================================================
++ // DMA Control Register Set
++ //============================================================
++ uCHCTRL =
++ // HwCHCTRL_SYNC_ON |
++ // HwCHCTRL_HRD_W |
++ HwCHCTRL_BST_BURST |
++ HwCHCTRL_TYPE_SINGL |
++ HwCHCTRL_HRD_WR |
++ // HwCHCTRL_BST_BURST |
++ HwCHCTRL_BSIZE_8 |
++ HwCHCTRL_WSIZE_32 |
++ HwCHCTRL_FLAG |
++ HwCHCTRL_EN_ON |
++ 0;
++
++ }
++ else // NAND_IO_DMA_READ
++ {
++ // pSRC: NFC_LDATA
++ // pDST: Buffer Address
++
++ BITCSET(pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_8 | HwNFC_CTRL_DEN_EN | HwNFC_CTRL_PSIZE_512 );
++
++ nSourceAddr = (unsigned int)pSRC; // NFC_LDATA Physical Address: ex_TCC89,92XX: 0XF050b0020
++ nDestAddr = (unsigned int)pDMA_PhyBuffer;
++
++// ND_TRACE("\npDMA_WorkBuffer_Addr:0x%08X / 0x%08X", pDMA_PhyBuffer, pDMA_WorkBuffer );
++
++ //============================================================
++ // DMA Control Register Set
++ //============================================================
++ uCHCTRL =
++ // HwCHCTRL_SYNC_ON |
++ // HwCHCTRL_HRD_W |
++ HwCHCTRL_BST_BURST |
++ HwCHCTRL_TYPE_SINGL |
++ HwCHCTRL_HRD_RD |
++ // HwCHCTRL_BST_BURST |
++ HwCHCTRL_BSIZE_8 |
++ HwCHCTRL_WSIZE_32 |
++ HwCHCTRL_FLAG |
++ HwCHCTRL_EN_ON |
++ 0;
++ }
++
++ //============================================================
++ // Set Source Address & Source Parameter (mask + increment)
++ //============================================================
++ pNAND_DMA->ST_SADR = nSourceAddr;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ pNAND_DMA->SPARAM[0] = (uSrcInc | (uSrcMask << 4));
++ #else
++ pNAND_DMA->SPARAM = (uSrcInc | (uSrcMask << 4));
++ #endif
++ //============================================================
++ // Set Dest Address & Dest Parameter (mask + increment)
++ //============================================================
++ pNAND_DMA->ST_DADR = nDestAddr;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ pNAND_DMA->DPARAM[0] = (uDstInc | (uDstMask << 4));
++ #else
++ pNAND_DMA->DPARAM = (uDstInc | (uDstMask << 4));
++ #endif
++ //============================================================
++ // Calculate byte size per 1 Hop transfer
++ //============================================================
++ uTmp = (uCHCTRL & (Hw5+Hw4)) >> 4; // calc log2(word size)
++ uTmp = uTmp + ( (uCHCTRL & (Hw7+Hw6)) >> 6); // calc log2(word * burst size)
++
++ //============================================================
++ // Set External DMA Request Register
++ //============================================================
++ pNAND_DMA->EXTREQ = Hw18; // NFC
++
++ //============================================================
++ // Set Hcount
++ //============================================================
++ if (uTmp)
++ pNAND_DMA->HCOUNT = (nDSize + (1 << uTmp) - 1) >> uTmp;
++ else
++ pNAND_DMA->HCOUNT = nDSize;
++
++ //============================================================
++ // Set & Enable DMA
++ //============================================================
++ pNAND_DMA->CHCTRL = uCHCTRL;
++
++ //============================================================
++ // Set NFC DSize & IREQ Clear
++ //============================================================
++ pNFC->NFC_DSIZE = nDSize;
++ pNFC->NFC_IREQ = 0x77; // HwNFC_IREQ_FLAG1;
++
++ //============================================================
++ // DMA Transfer Start
++ //============================================================
++ if ( nMode == NAND_IO_DMA_WRITE )
++ {
++ if ( pNFC->NFC_CTRL1 & Hw31 )
++ BITCLR( pNFC->NFC_CTRL1, Hw31 );
++
++ NAND_IO_IRQ_Mask();
++
++ pNFC->NFC_PSTART = 0;
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ NAND_IO_IRQ_UnMask();
++
++ if ( pNFC->NFC_CTRL1 & Hw30 )
++ BITSET( pNFC->NFC_CTRL1, Hw31 );
++ }
++ else
++ {
++ NAND_IO_IRQ_Mask();
++
++ pNFC->NFC_RSTART = 0;
++ while ( ISZERO(pNFC->NFC_IREQ, HwNFC_IREQ_FLAG0) );
++
++ NAND_IO_IRQ_UnMask();
++
++ memcpy( pDST, pDMA_WorkBuffer, nDSize );
++ }
++}
++
++static __inline void NAND_IO_SetupDMA_kernel( void *pSRC, unsigned uSrcInc, unsigned uSrcMask,
++ void *pDST, unsigned uDstInc, unsigned uDstMask, int nMode, int nDSize )
++{
++ unsigned int *pDMA_PhyBuffer;
++ unsigned int *pDMA_WorkBuffer;
++ unsigned int nSourceAddr, nDestAddr;
++ unsigned uCHCTRL;
++ unsigned int uTmp;
++
++ #if defined(_WINCE_)
++ tSYSTEM_PARAM *pSYS_Work_PARAM = (tSYSTEM_PARAM*)(SYSTEM_PARAM_BASEADDRESS);
++ #endif
++
++ #if defined(_WINCE_)
++ pDMA_PhyBuffer = (unsigned int*)pSYS_Work_PARAM->DMA2.CH0_BUFFER; // Working Address
++ pDMA_WorkBuffer = (unsigned int*)pSYS_PARAM->DMA2.CH0_BUFFER; // Physical Address
++ #elif defined(_LINUX_)
++ #ifdef KERNEL_DRIVER
++ pDMA_PhyBuffer = (unsigned int*)dma_t.dma_addr;
++ pDMA_WorkBuffer = (unsigned int*)dma_t.v_addr;
++ #else
++ pDMA_PhyBuffer = (unsigned int*)DMA_ADDR;
++ pDMA_WorkBuffer = (unsigned int*)DMA_ADDR;
++ #endif
++ #else // NU
++ pDMA_PhyBuffer = (unsigned int*)0x10003000;
++ pDMA_WorkBuffer = (unsigned int*)0x10003000;
++ #endif
++
++ if ( nMode == NAND_IO_DMA_WRITE )
++ {
++ // pSRC: Buffer Address
++ // pDST: NFC_LDATA
++
++ BITCSET(pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_8 | HwNFC_CTRL_DEN_EN | HwNFC_CTRL_PSIZE_512 );
++
++ //pSRC --> pDMA_WorkBuffer
++ memcpy( pDMA_WorkBuffer, pSRC, nDSize );
++
++ // Target Physical Address- for DMA H/W Control Set
++ nSourceAddr = (unsigned int)pDMA_PhyBuffer;
++ nDestAddr = (unsigned int)pDST;
++
++ //============================================================
++ // DMA Control Register Set
++ //============================================================
++ uCHCTRL =
++ // HwCHCTRL_SYNC_ON |
++ // HwCHCTRL_HRD_W |
++ HwCHCTRL_BST_BURST |
++ HwCHCTRL_TYPE_SINGL |
++ HwCHCTRL_HRD_WR |
++ // HwCHCTRL_BST_BURST |
++ HwCHCTRL_BSIZE_8 |
++ HwCHCTRL_WSIZE_32 |
++ HwCHCTRL_FLAG |
++ HwCHCTRL_EN_ON |
++ 0;
++
++ }
++ else // NAND_IO_DMA_READ
++ {
++ // pSRC: NFC_LDATA
++ // pDST: Buffer Address
++
++ BITCSET(pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_8 | HwNFC_CTRL_DEN_EN | HwNFC_CTRL_PSIZE_512 );
++
++ nSourceAddr = (unsigned int)pSRC; // NFC_LDATA Physical Address: ex_TCC89,92XX: 0XF050b0020
++// nDestAddr = (unsigned int)pDMA_PhyBuffer;
++ nDestAddr = (unsigned int)pDST;
++
++ //============================================================
++ // DMA Control Register Set
++ //============================================================
++ uCHCTRL =
++ // HwCHCTRL_SYNC_ON |
++ // HwCHCTRL_HRD_W |
++ HwCHCTRL_BST_BURST |
++ HwCHCTRL_TYPE_SINGL |
++ HwCHCTRL_HRD_RD |
++ // HwCHCTRL_BST_BURST |
++ HwCHCTRL_BSIZE_8 |
++ HwCHCTRL_WSIZE_32 |
++ HwCHCTRL_FLAG |
++ HwCHCTRL_EN_ON |
++ 0;
++ }
++
++ //============================================================
++ // Set Source Address & Source Parameter (mask + increment)
++ //============================================================
++ pNAND_DMA->ST_SADR = nSourceAddr;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ pNAND_DMA->SPARAM[0] = (uSrcInc | (uSrcMask << 4));
++ #else
++ pNAND_DMA->SPARAM = (uSrcInc | (uSrcMask << 4));
++ #endif
++
++ //============================================================
++ // Set Dest Address & Dest Parameter (mask + increment)
++ //============================================================
++ pNAND_DMA->ST_DADR = nDestAddr;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ pNAND_DMA->DPARAM[0] = (uDstInc | (uDstMask << 4));
++ #else
++ pNAND_DMA->DPARAM = (uDstInc | (uDstMask << 4));
++ #endif
++
++ //============================================================
++ // Calculate byte size per 1 Hop transfer
++ //============================================================
++ uTmp = (uCHCTRL & (Hw5+Hw4)) >> 4; // calc log2(word size)
++ uTmp = uTmp + ( (uCHCTRL & (Hw7+Hw6)) >> 6); // calc log2(word * burst size)
++
++ //============================================================
++ // Set External DMA Request Register
++ //============================================================
++ pNAND_DMA->EXTREQ = Hw18; // NFC
++
++ //============================================================
++ // Set Hcount
++ //============================================================
++ if (uTmp)
++ pNAND_DMA->HCOUNT = (nDSize + (1 << uTmp) - 1) >> uTmp;
++ else
++ pNAND_DMA->HCOUNT = nDSize;
++
++ //============================================================
++ // Set & Enable DMA
++ //============================================================
++ pNAND_DMA->CHCTRL = uCHCTRL;
++
++ //============================================================
++ // Set NFC DSize & IREQ Clear
++ //============================================================
++ pNFC->NFC_DSIZE = nDSize;
++ pNFC->NFC_IREQ = 0x77; // HwNFC_IREQ_FLAG1;
++
++ //============================================================
++ // DMA Transfer Start
++ //============================================================
++ if ( nMode == NAND_IO_DMA_WRITE )
++ {
++ if ( pNFC->NFC_CTRL1 & Hw31 )
++ BITCLR( pNFC->NFC_CTRL1, Hw31 );
++
++ NAND_IO_IRQ_Mask();
++
++ pNFC->NFC_PSTART = 0;
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ NAND_IO_IRQ_UnMask();
++
++ if ( pNFC->NFC_CTRL1 & Hw30 )
++ BITSET( pNFC->NFC_CTRL1, Hw31 );
++ }
++ else
++ {
++ NAND_IO_IRQ_Mask();
++ pNFC->NFC_RSTART = 0;
++ while ( ISZERO(pNFC->NFC_IREQ, HwNFC_IREQ_FLAG0) );
++ NAND_IO_IRQ_UnMask();
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline void NAND_IO_SetupDMADoubleBuf( int nMode, int nDMACh );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* nDMACh =
++* nMode =
++*
++* OUTPUT: void - Return Type
++*
++**************************************************************************/
++static __inline void NAND_IO_SetupDMADoubleBuf( int nMode, int nDMACh )
++{
++ unsigned int *pDMA_PhyBuffer;
++ unsigned int *pDMA_WorkBuffer;
++ unsigned int nSourceAddr, nDestAddr;
++ unsigned uCHCTRL;
++ unsigned int uTmp;
++ unsigned int uSrcInc, uSrcMask;
++ unsigned int uDstInc, uDstMask;
++
++ if ( nMode == NAND_IO_DMA_WRITE )
++ {
++ uSrcInc = 4;
++ uSrcMask = 0;
++ uDstInc = 0;
++ uDstMask = 0;
++ }
++ else
++ {
++ uSrcInc = 0;
++ uSrcMask = 0;
++ uDstInc = 4;
++ uDstMask = 0;
++ }
++
++ if ( nDMACh & 1 )
++ {
++ pDMA_PhyBuffer = gpDMA_PhyBuffer0; // Working Address
++ pDMA_WorkBuffer = gpDMA_WorkBuffer0; // Physical Address
++ }
++ else
++ {
++ pDMA_PhyBuffer = gpDMA_PhyBuffer1; // Working Address
++ pDMA_WorkBuffer = gpDMA_WorkBuffer1; // Physical Address
++ }
++
++ if ( nMode == NAND_IO_DMA_WRITE )
++ {
++ // pSRC: Buffer Address
++ // pDST: NFC_LDATA
++
++ BITCSET(pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_8 | HwNFC_CTRL_DEN_EN | HwNFC_CTRL_PSIZE_512 );
++
++ //pSRC --> pDMA_WorkBuffer
++ //memcpy( pDMA_WorkBuffer, pSRC, 512 );
++
++ // Target Physical Address- for DMA H/W Control Set
++ nSourceAddr = (unsigned int)pDMA_PhyBuffer;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ nDestAddr = (unsigned int)&NAND_IO_HwLDATA_PA;
++ #else
++ nDestAddr = (unsigned int)&pNFC->NFC_LDATA;
++ #endif
++
++ //============================================================
++ // DMA Control Register Set
++ //============================================================
++ uCHCTRL =
++ // HwCHCTRL_SYNC_ON |
++ // HwCHCTRL_HRD_W |
++ HwCHCTRL_BST_BURST |
++ HwCHCTRL_TYPE_SINGL |
++ HwCHCTRL_HRD_WR |
++ // HwCHCTRL_BST_BURST |
++ HwCHCTRL_BSIZE_8 |
++ HwCHCTRL_WSIZE_32 |
++ HwCHCTRL_FLAG |
++ HwCHCTRL_EN_ON |
++ 0;
++
++ }
++ else // NAND_IO_DMA_READ
++ {
++
++ BITCSET(pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_8 | HwNFC_CTRL_DEN_EN | HwNFC_CTRL_PSIZE_512 );
++
++ #if defined(_WINCE_) || defined(_LINUX_)
++ nSourceAddr = (unsigned int)&NAND_IO_HwLDATA_PA; // NFC_LDATA Physical Address: ex_TCC89,92XX: 0XF050b0020
++ #else
++ nSourceAddr = (unsigned int)&pNFC->NFC_LDATA;
++ #endif
++ nDestAddr = (unsigned int)pDMA_PhyBuffer;
++
++ //============================================================
++ // DMA Control Register Set
++ //============================================================
++ uCHCTRL =
++ // HwCHCTRL_SYNC_ON |
++ // HwCHCTRL_HRD_W |
++ HwCHCTRL_BST_BURST |
++ HwCHCTRL_TYPE_SINGL |
++ HwCHCTRL_HRD_RD |
++ // HwCHCTRL_BST_BURST |
++ HwCHCTRL_BSIZE_8 |
++ HwCHCTRL_WSIZE_32 |
++ HwCHCTRL_FLAG |
++ HwCHCTRL_EN_ON |
++ 0;
++ }
++
++ //============================================================
++ // Set Source Address & Source Parameter (mask + increment)
++ //============================================================
++ pNAND_DMA->ST_SADR = nSourceAddr;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ pNAND_DMA->SPARAM[0] = (uSrcInc | (uSrcMask << 4));
++ #else
++ pNAND_DMA->SPARAM = (uSrcInc | (uSrcMask << 4));
++ #endif
++ //============================================================
++ // Set Dest Address & Dest Parameter (mask + increment)
++ //============================================================
++ pNAND_DMA->ST_DADR = nDestAddr;
++ #if defined(_WINCE_) || defined(_LINUX_)
++ pNAND_DMA->DPARAM[0] = (uDstInc | (uDstMask << 4));
++ #else
++ pNAND_DMA->DPARAM = (uDstInc | (uDstMask << 4));
++ #endif
++ //============================================================
++ // Calculate byte size per 1 Hop transfer
++ //============================================================
++ uTmp = (uCHCTRL & (Hw5+Hw4)) >> 4; // calc log2(word size)
++ uTmp = uTmp + ( (uCHCTRL & (Hw7+Hw6)) >> 6); // calc log2(word * burst size)
++
++ //============================================================
++ // Set External DMA Request Register
++ //============================================================
++ pNAND_DMA->EXTREQ = Hw18; // NFC
++
++ //============================================================
++ // Set Hcount
++ //============================================================
++ if (uTmp)
++ pNAND_DMA->HCOUNT = (512 + (1 << uTmp) - 1) >> uTmp;
++ else
++ pNAND_DMA->HCOUNT = 512;
++
++ //============================================================
++ // Set & Enable DMA
++ //============================================================
++ pNAND_DMA->CHCTRL = uCHCTRL;
++
++ //============================================================
++ // Set NFC DSize & IREQ Clear
++ //============================================================
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // HwNFC_IREQ_FLAG1;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_SetupECC( U16 nEccOnOff, U16 nEncDec, U16 nEccType, U32 EccBaseAddr )
++*
++* DESCRIPTION :
++* INPUT:
++* nEccOnOff =
++* nEccType =
++* nEncDec =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_SetupECC( U16 nEccOnOff, U16 nEncDec, U16 nEccType, U16 nAccessType, U32 EccBaseAddr )
++{
++ if ( nEccOnOff == ECC_OFF )
++ {
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ BITCLR(pIOBUSCFG_T->HRSTEN0, Hw24);
++ BITSET(pIOBUSCFG_T->HRSTEN0, Hw24);
++
++ pECC->ECC_BASE = 0xF05B0010; /* Base Address for ECC Calculation */
++ pECC->ECC_MASK = 0x00000000; /* Address mask for ECC area */
++ pECC->ECC_CTRL &= HwECC_CTRL_EN_DIS;
++
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++ }
++ else if ( nEccOnOff == ECC_ON )
++ {
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ if ( nEncDec == ECC_DECODE )
++ {
++ //==========================================================
++ //
++ // ECC Decode Setup
++ //
++ //==========================================================
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++
++ if ( nAccessType == NAND_MCU_ACCESS )
++ {
++ pIOBUSCFG_T->STORAGE = HwIOBUSCFG_STORAGE_NFC;
++ pECC->ECC_BASE = (0x000FFFFF & EccBaseAddr);
++ }
++ else if ( nAccessType == NAND_DMA_ACCESS )
++ {
++ pIOBUSCFG_T->STORAGE = HwIOBUSCFG_STORAGE_NFC;
++ pECC->ECC_BASE = EccBaseAddr;
++ }
++
++ pECC->ECC_MASK = 0x00000000; /* Address mask for ECC area */
++
++ if ( nEccType == SLC_ECC_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_SLCDE;
++ else if (nEccType == MLC_ECC_4BIT_TYPE )
++ {
++ pECC->ECC_CTRL |= HwECC_CTRL_IEN_MECC4_EN;
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL4DE;
++ }
++ else if (nEccType == MLC_ECC_8BIT_TYPE )
++ {
++ pECC->ECC_CTRL |= HwECC_CTRL_IEN_MECC8_EN;
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL8DE;
++ }
++ else if (nEccType == MLC_ECC_12BIT_TYPE )
++ {
++ pECC->ECC_CTRL |= HwECC_CTRL_IEN_MECC12_EN;
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL12DE;
++ }
++ else if (nEccType == MLC_ECC_16BIT_TYPE )
++ {
++ pECC->ECC_CTRL |= HwECC_CTRL_IEN_MECC16_EN;
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL16DE;
++ }
++ }
++ else if ( nEncDec == ECC_ENCODE )
++ {
++ //==========================================================
++ //
++ // ECC Encode Setup
++ //
++ //==========================================================
++ if ( nAccessType == NAND_MCU_ACCESS )
++ {
++ pIOBUSCFG_T->STORAGE = HwIOBUSCFG_STORAGE_NFC;
++ pECC->ECC_BASE = (0x000FFFFF &EccBaseAddr);
++ }
++ else if ( nAccessType == NAND_DMA_ACCESS )
++ {
++ pIOBUSCFG_T->STORAGE = HwIOBUSCFG_STORAGE_NFC;
++ pECC->ECC_BASE = EccBaseAddr;
++ }
++
++ pECC->ECC_MASK = 0x00000000; /* Address mask for ECC area */
++
++ if ( nEccType == SLC_ECC_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_SLCEN;
++ else if (nEccType == MLC_ECC_4BIT_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL4EN;
++ else if (nEccType == MLC_ECC_8BIT_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL8EN;
++ else if (nEccType == MLC_ECC_12BIT_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL12EN;
++ else if (nEccType == MLC_ECC_16BIT_TYPE )
++ pECC->ECC_CTRL |= HwECC_CTRL_EN_MCL16EN;
++
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++
++ }
++ }
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_EncodeECC( U16 nEccType, U8* nSpareBuffer );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nEccType =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_EncodeECC( U16 nEccType, U8* nSpareBuffer )
++{
++ unsigned int nECC_CODE;
++ unsigned char *pcECC;
++ unsigned int *pSpareDW;
++
++ if ( nEccType == SLC_ECC_TYPE )
++ {
++ //==================================================================
++ // [ TNFTL V1.0 ]
++ //==================================================================
++ // 520th : P64-P8 of ECC Area-1 [ DATA 256-511 ]
++ // 521th : P1024-P128 of ECC Area-1 [ DATA 256-511 ]
++ // 522th : P4-P1 of ECC Area-1 [ DATA 256-511 ]
++ // 525th : P64-P8 of ECC Area-0 [ DATA 0-255 ]
++ // 526th : P1024-P128 of ECC Area-0 [ DATA 0-255 ]
++ // 527th : P4-P1 of ECC Area-0 [ DATA 0-255 ]
++ //==================================================================
++
++ pcECC = (unsigned char* )&pECC->ECC_CODE0;
++
++ /* Area-1 */
++ nSpareBuffer[2] = pcECC[0]; // P4-P1
++ nSpareBuffer[1]= pcECC[1]; // P1024-P128
++ nSpareBuffer[0]= pcECC[2]; // P64-P8
++
++ /* Area-0 */
++ nSpareBuffer[5] = pcECC[4]; // P4-P1
++ nSpareBuffer[4] = pcECC[5]; // P1024-128
++ nSpareBuffer[3] = pcECC[6]; // P64-P8
++ }
++ else
++ {
++ pSpareDW = (unsigned int *)nSpareBuffer;
++
++ nECC_CODE = pECC->ECC_CODE0;
++ *pSpareDW = nECC_CODE; ++pSpareDW;
++
++ nECC_CODE = pECC->ECC_CODE1;
++ *pSpareDW = nECC_CODE; ++pSpareDW;
++
++ nECC_CODE = pECC->ECC_CODE2;
++ *pSpareDW = nECC_CODE; ++pSpareDW;
++
++ nECC_CODE = pECC->ECC_CODE3;
++ *pSpareDW = nECC_CODE; ++pSpareDW;
++
++ nECC_CODE = pECC->ECC_CODE4;
++ *pSpareDW = nECC_CODE; ++pSpareDW;
++
++ nECC_CODE = pECC->ECC_CODE5;
++ *pSpareDW = nECC_CODE; ++pSpareDW;
++
++ nECC_CODE = pECC->ECC_CODE6;
++ *pSpareDW = nECC_CODE; ++pSpareDW;
++ }
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_CorrectionSLC( U8* nPageBuffer, U8* nSpareBuffer );
++*
++* DESCRIPTION :
++* INPUT:
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_CorrectionSLC( U8* nPageBuffer, U8* nSpareBuffer )
++{
++ unsigned int uErrorStatus;
++ unsigned int uSLCECC0, uSLCECC1;
++ NAND_IO_ERROR res;
++
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ //==================================================================
++ // [ TNFTL V1.0 ]
++ //==================================================================
++ // 520th : P64-P8 of ECC Area-1 [ DATA 256-511 ]
++ // 521th : P1024-P128 of ECC Area-1 [ DATA 256-511 ]
++ // 522th : P4-P1 of ECC Area-1 [ DATA 256-511 ]
++ // 525th : P64-P8 of ECC Area-0 [ DATA 0-255 ]
++ // 526th : P1024-P128 of ECC Area-0 [ DATA 0-255 ]
++ // 527th : P4-P1 of ECC Area-0 [ DATA 0-255 ]
++ //==================================================================
++
++ /* Load SLC ECC Code for Area 1 */
++ uSLCECC0 = ( nSpareBuffer[0] << 16 ) +
++ ( nSpareBuffer[1] << 8 ) +
++ ( nSpareBuffer[2] );
++
++ /* Load SLC ECC Code for Area 0 */
++ uSLCECC1 = ( nSpareBuffer[3] << 16 ) +
++ ( nSpareBuffer[4] << 8 ) +
++ ( nSpareBuffer[5] );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Correction Area 0 */
++ pECC->ECC_CODE1 = uSLCECC1;
++ uErrorStatus = pECC->ERRNUM & 0x7;
++
++ if ( uErrorStatus == HwERR_NUM_ERR1 )
++ {
++ nPageBuffer[pECC->ECC_EADDR0 >> 3] ^= (1 << (pECC->ECC_EADDR0 & 0x07));
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ else if ( uErrorStatus != HwERR_NUM_NOERR )
++ {
++ res = ERR_NAND_IO_FAILED_CORRECTION_SLC_ECC;
++ goto ErrorCorrectionSLC;
++ }
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Correction Area 1 */
++ pECC->ECC_CODE0 = uSLCECC0;
++ uErrorStatus = pECC->ERRNUM & 0x7;
++
++ if ( uErrorStatus == HwERR_NUM_ERR1 )
++ {
++ nPageBuffer[pECC->ECC_EADDR0 >> 3] ^= (1 << (pECC->ECC_EADDR0 & 0x07));
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ else if ( uErrorStatus != HwERR_NUM_NOERR )
++ {
++ res = ERR_NAND_IO_FAILED_CORRECTION_SLC_ECC;
++ goto ErrorCorrectionSLC;
++ }
++
++ErrorCorrectionSLC:
++
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++
++ return res;
++
++}
++
++
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_CorrectionMLC_IRQ( U16 nEccType, U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDataSize =
++* nEccType =
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_CorrectionMLC_IRQ( U16 nEccType, U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize )
++{
++ unsigned int i;
++ unsigned int uErrAddr;
++ unsigned int uErrorStatus;
++ unsigned int *pSpareDW;
++
++ NAND_IO_ECC_INFO *pECC_Info;
++ NAND_IO_ERROR res;
++
++ if ( nEccType == MLC_ECC_4BIT_TYPE )
++ pECC_Info = &gMLC_ECC_4Bit;
++ else if ( nEccType == MLC_ECC_8BIT_TYPE )
++ pECC_Info = &gMLC_ECC_8Bit;
++ else if ( nEccType == MLC_ECC_12BIT_TYPE )
++ pECC_Info = &gMLC_ECC_12Bit;
++ else if ( nEccType == MLC_ECC_14BIT_TYPE )
++ pECC_Info = &gMLC_ECC_14Bit;
++ else if ( nEccType == MLC_ECC_16BIT_TYPE )
++ pECC_Info = &gMLC_ECC_16Bit;
++ else
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ pSpareDW = (unsigned int *)nSpareBuffer;
++
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ pECC->ECC_CODE0 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE1 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE2 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE3 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE4 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE5 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE6 = *pSpareDW; ++pSpareDW;
++
++ /* Sync Delay */
++
++ /* Wait MLC ECC Correction */
++ while ( !(pECC->ECC_IREQ & pECC_Info->DecodeFlag ) );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Correction */
++ uErrorStatus = pECC->ERRNUM & 0x1F;
++
++ if ( uErrorStatus > pECC_Info->ErrorNum )
++ {
++ if ( memcmp( nSpareBuffer, gNAND_IO_TempBuffer, pECC_Info->EccDataSize ) == 0 )
++ {
++ //ND_TRACE("[Ecc Decode]: %d byte 0xFF \n", nDataSize );
++ return SUCCESS;
++ }
++
++ #ifdef NAND_IO_ECC_ERROR_LOG
++ PRINTF("\n\nErrorNum[%02d],DataSize[%03d] - Correction Fail", uErrorStatus, nDataSize );
++ #if defined(USE_V_ADDRESS) && defined(_WINCE_)
++ RETAILMSG(1,( TEXT("[NAND ] [ECC Correction Fail]\n")));
++ #else
++ ND_TRACE("[NAND ] [ECC Correction Fail]\n" );
++ #endif
++ #endif
++
++ if ( nDataSize == 512 )
++ {
++ #if defined(USE_V_ADDRESS)
++ ND_TRACE("\n\nErrorNum[%02d],DataSize[%03d] - Correction Fail", uErrorStatus, nDataSize );
++ ND_TRACE("\n\nISR_Data:\n");
++ for ( i = 0; i < nDataSize; ++i )
++ {
++ ND_TRACE("%02X", nPageBuffer[i]);
++ }
++
++ ND_TRACE("\n\nISR_ECC:\n");
++ for ( i = 0; i < 28; ++i )
++ {
++ ND_TRACE("%02X", nSpareBuffer[i]);
++ }
++ #else
++ ND_TRACE("\n\nErrorNum[%d],DataSize[%d] - Correction Fail", uErrorStatus, nDataSize );
++ ND_TRACE("\n\nData:\n");
++ for ( i = 0; i < nDataSize; ++i )
++ {
++ ND_TRACE("%X", nPageBuffer[i]);
++ }
++
++ ND_TRACE("\n\nECC:\n");
++ for ( i = 0; i < 28; ++i )
++ {
++ ND_TRACE("%X", nSpareBuffer[i]);
++ }
++ #endif
++
++ ND_TRACE("\n\n");
++ }
++
++ res = ERR_NAND_IO_FAILED_CORRECTION_MLC_ECC;
++ goto ErrorCorrectionMLC;
++ }
++ else if ( uErrorStatus == HwERR_NUM_NOERR )
++ {
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ else
++ {
++ for ( i = 0; i < uErrorStatus; ++i )
++ {
++ uErrAddr = *(unsigned long int*)(&pECC->ECC_EADDR0+i);
++
++ if ( ( uErrAddr >> 3 ) < nDataSize )
++ nPageBuffer[uErrAddr>>3] ^= (1<<(uErrAddr &0x7));
++ }
++ }
++
++ErrorCorrectionMLC:
++ /* Disable MLC ECC */
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_CorrectionMLC( U16 nEccType, U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDataSize =
++* nEccType =
++* nPageBuffer =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_CorrectionMLC( U16 nEccType, U8* nPageBuffer, U8* nSpareBuffer, U16 nDataSize )
++{
++ unsigned int i;
++ unsigned int uErrAddr;
++ unsigned int uErrorStatus;
++ unsigned int *pSpareDW;
++ #ifdef _LINUX_
++ unsigned char nECCBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nECCBuffer[30];
++ #endif
++
++ NAND_IO_ECC_INFO *pECC_Info;
++ NAND_IO_ERROR res;
++
++ if ( nEccType == MLC_ECC_4BIT_TYPE )
++ pECC_Info = &gMLC_ECC_4Bit;
++ else if ( nEccType == MLC_ECC_8BIT_TYPE )
++ pECC_Info = &gMLC_ECC_8Bit;
++ else if ( nEccType == MLC_ECC_12BIT_TYPE )
++ pECC_Info = &gMLC_ECC_12Bit;
++ else if ( nEccType == MLC_ECC_14BIT_TYPE )
++ pECC_Info = &gMLC_ECC_14Bit;
++ else if ( nEccType == MLC_ECC_16BIT_TYPE )
++ pECC_Info = &gMLC_ECC_16Bit;
++ else
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ for ( i = 0; i < pECC_Info->EccDataSize; ++i )
++ nECCBuffer[i] = nSpareBuffer[i];
++
++ //============================================
++ // Get Buffer Pointer
++ //============================================
++ if ( memcmp( nECCBuffer, gNAND_IO_TempBuffer, pECC_Info->EccDataSize ) == 0 )
++ {
++ if ( nDataSize == 512 )
++ pSpareDW = (unsigned int *)pECC_Info->All_FF_512_ECC_Code;
++ else if ( nDataSize == 12 )
++ pSpareDW = (unsigned int *)&ALL_FF_ECC_BCH_04BIT_12;
++ else if ( nDataSize == 16 )
++ pSpareDW = (unsigned int *)&ALL_FF_ECC_BCH_04BIT_16;
++ else
++ pSpareDW = (unsigned int *)&ALL_FF_ECC_BCH_04BIT_512;
++ }
++ else
++ {
++ pSpareDW = ( unsigned int *)nECCBuffer;
++ }
++
++ //IO_CKC_EnableBUS( IO_CKC_BUS_ECC );
++
++ pECC->ECC_CODE0 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE1 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE2 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE3 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE4 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE5 = *pSpareDW; ++pSpareDW;
++ pECC->ECC_CODE6 = *pSpareDW; ++pSpareDW;
++
++ /* Sync Delay */
++ //ASM_NOP; ASM_NOP; ASM_NOP; ASM_NOP;
++
++ /* Wait MLC ECC Correction */
++ while ( !(pECC->ECC_IREQ & pECC_Info->DecodeFlag ) );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Correction */
++ uErrorStatus = pECC->ERRNUM & 0x1F;
++
++ if ( uErrorStatus > pECC_Info->ErrorNum )
++ {
++ if ( nDataSize == 512 )
++ {
++ #if defined(USE_V_ADDRESS)
++ ND_TRACE("\n\nErrorNum[%02d],DataSize[%03d] - Correction Fail", uErrorStatus, nDataSize );
++ ND_TRACE("\n\nData:\n");
++ for ( i = 0; i < nDataSize; ++i )
++ {
++ ND_TRACE("%02X", nPageBuffer[i]);
++ }
++
++ ND_TRACE("\n\nECC:\n");
++ for ( i = 0; i < 28; ++i )
++ {
++ ND_TRACE("%02X", nSpareBuffer[i]);
++ }
++ #else
++ ND_TRACE("\n\nErrorNum[%d],DataSize[%d] - Correction Fail", uErrorStatus, nDataSize );
++ ND_TRACE("\n\nData:\n");
++ for ( i = 0; i < nDataSize; ++i )
++ {
++ ND_TRACE("%X", nPageBuffer[i]);
++ }
++
++ ND_TRACE("\n\nECC:\n");
++ for ( i = 0; i < 28; ++i )
++ {
++ ND_TRACE("%X", nSpareBuffer[i]);
++ }
++ #endif
++
++ ND_TRACE("\n\n");
++ }
++
++ res = ERR_NAND_IO_FAILED_CORRECTION_MLC_ECC;
++ goto ErrorCorrectionMLC;
++ }
++ else if ( uErrorStatus == HwERR_NUM_NOERR )
++ {
++ res = (NAND_IO_ERROR)SUCCESS;
++ }
++ else
++ {
++ for ( i = 0; i < uErrorStatus; ++i )
++ {
++ uErrAddr = *(unsigned long int*)(&pECC->ECC_EADDR0+i);
++
++ if ( ( uErrAddr >> 3 ) < nDataSize )
++ nPageBuffer[uErrAddr>>3] ^= (1<<(uErrAddr &0x7));
++ }
++ }
++
++ErrorCorrectionMLC:
++ /* Disable MLC ECC */
++ //IO_CKC_DisableBUS( IO_CKC_BUS_ECC );
++
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_EncodeBootBinary( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, int nEccOnOff );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_EncodeBootBinary( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, int nEccOnOff )
++{
++ unsigned int i;
++ #ifdef _LINUX_
++ unsigned char nECCBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nECCBuffer[30];
++ #endif
++ unsigned char *pPageB;
++ unsigned char *pDataBuffer;
++ unsigned char *pEccB;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ //if ( nEccOnOff == ECC_OFF )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ pPageB = (unsigned char*)nPageBuffer;
++
++ /* Get Buffer pointer */
++ pDataBuffer = (unsigned char*)pPageB;
++
++ //####################################################
++ //# Dummy Write Page Data
++ //####################################################
++#if 0 /* 09.07.15 */
++ if (!( pNFC->NFC_CTRL1 & Hw30 ))
++ {
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, MLC_ECC_16BIT_TYPE, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, MLC_ECC_16BIT_TYPE, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( NAND_SB_BOOT_PAGE_SIZE << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000; // Clear ECC Block
++ }
++
++ /* Write 256 Page Data */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = NAND_SB_BOOT_PAGE_SIZE;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ pNFC->NFC_PSTART = 0;
++
++ i = ( NAND_SB_BOOT_PAGE_SIZE >> 2 );
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++ uDWordByte.BYTE[0] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[1] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[2] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[3] = *pDataBuffer;++pDataBuffer;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ }
++ else
++#endif /* 0 */
++ {
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, MLC_ECC_16BIT_TYPE, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, MLC_ECC_16BIT_TYPE, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( NAND_SB_BOOT_PAGE_SIZE << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ i = ( NAND_SB_BOOT_PAGE_SIZE >> 2 );
++ do {
++ uDWordByte.BYTE[0] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[1] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[2] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[3] = *pDataBuffer;++pDataBuffer;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }while(--i);
++ }
++
++ /* Adapt type of address */
++ pEccB = (unsigned char*)nECCBuffer;
++
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( MLC_ECC_16BIT_TYPE, pEccB );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++
++ for ( i = 0; i < 28; ++i ) // MLC_ECC_16BIT_TYPE Data Size = 26Byte
++ {
++ *pDataBuffer = nECCBuffer[i];
++ pDataBuffer += 1;
++ }
++ }
++
++ /* Disable ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ErrorWrite512Data:
++ return res;
++}
++
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_EncodeBootBinary( NAND_IO_DEVINFO *nDevInfo, U8 *nPageBuffer, int nEccOnOff );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++NAND_IO_ERROR NAND_IO_EncDecodeBinary( unsigned int nEncDec, unsigned int nEccType, unsigned int nDataSize, U8 *nPageBuffer, U8 *nEccBuffer )
++{
++ unsigned int i;
++ #ifdef _LINUX_
++ unsigned char nECCTempBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nECCTempBuffer[30];
++ #endif
++ unsigned int nEccDataSize = 0;
++ unsigned char *pPageB;
++ unsigned char *pDataBuffer;
++ unsigned char *pEccBuffer;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ //if ( nEccOnOff == ECC_OFF )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ pPageB = (unsigned char*)nPageBuffer;
++
++ /* Get Buffer pointer */
++ pDataBuffer = (unsigned char*)pPageB;
++
++ pEccBuffer = (unsigned char*)nEccBuffer;
++ //####################################################
++ //# Dummy Write Page Data
++ //####################################################
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)ECC_ON, nEncDec, nEccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)ECC_ON, nEncDec, nEccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( nDataSize << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++
++ i = ( nDataSize >> 2 );
++ do {
++ uDWordByte.BYTE[0] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[1] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[2] = *pDataBuffer;++pDataBuffer;
++ uDWordByte.BYTE[3] = *pDataBuffer;++pDataBuffer;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }while(--i);
++
++ /* Adapt type of address */
++// pEccB = (unsigned char*)nECCTempBuffer;
++
++ if ( nEccType == A_SLC )
++ {
++ nEccDataSize = 8;
++ }
++ else if ( nEccType == A_MLC )
++ {
++ nEccDataSize = 8;
++ }
++ else if ( nEccType == A_MLC_8BIT )
++ {
++ nEccDataSize = 20;
++ }
++ else if ( nEccType == A_MLC_12BIT )
++ {
++ nEccDataSize = 20;
++ }
++ else if ( nEccType == A_MLC_16BIT )
++ {
++ nEccDataSize = 26;
++ }
++
++ /* Load ECC code from ECC block */
++ res = NAND_IO_EncodeECC( nEccType, nECCTempBuffer );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++
++ for ( i = 0; i < nEccDataSize; ++i ) // MLC_ECC_16BIT_TYPE Data Size = 26Byte
++ {
++ *pEccBuffer = nECCTempBuffer[i];
++ pEccBuffer += 1;
++ }
++
++
++ /* Disable ECC Block */
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ErrorWrite512Data:
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_ReadSpareDataECC( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadSpareData( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nPageEccOnOff )
++{
++ unsigned int i;
++ unsigned int nReadSize;
++ unsigned int nSpareTotalSize;
++ unsigned char bAlignAddr;
++ unsigned char *pSpareB = 0, *pEccB;
++ unsigned int *pSpareDW = 0;
++ unsigned char *pSpareBuffer;
++ #ifdef _LINUX_
++ unsigned char nECCBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nECCBuffer[30];
++ #endif
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ nSpareTotalSize = 12;
++ else
++ nSpareTotalSize = 16;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nSpareBuffer & 3 ) ? 0 : 1;
++
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ else
++ pSpareB = (unsigned char*)nSpareBuffer;
++
++ if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ //----------------------------------------------
++ // Read Small Page Spare Data: 16Byte
++ //----------------------------------------------
++ i = 4;
++
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ if ( nPageEccOnOff == PAGE_ECC_ON )
++ {
++ memset( gNAND_IO_ShareEccBuffer, 0xFF, 16 );
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)&gNAND_IO_ShareEccBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)&gNAND_IO_ShareEccBuffer[0];
++ else
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = 4;
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++ }
++ }
++
++ return (NAND_IO_ERROR)SUCCESS;
++ }
++
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( ECC_ON, ECC_DECODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( ECC_ON, ECC_DECODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( nSpareTotalSize << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; // Clear ECC Block
++
++ /* Set Spare Buffer */
++ pSpareBuffer = ( bAlignAddr ) ? (unsigned char*)pSpareDW : (unsigned char*)pSpareB;
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = ( nSpareTotalSize >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++ /* Read 4Bit ECC data */
++ nReadSize = 8;
++
++ /* Adapt type of address */
++ pEccB = (unsigned char*)nECCBuffer;
++
++ //----------------------------------------------
++ // Read ECC Code
++ //----------------------------------------------
++ while ( nReadSize )
++ {
++ /* Read as DWORD */
++ if ( nReadSize >= 4 )
++ {
++ uDWordByte.DWORD = WORD_OF(pNFC->NFC_WDATA);
++ *pEccB = uDWordByte.BYTE[0];++pEccB;
++ *pEccB = uDWordByte.BYTE[1];++pEccB;
++ *pEccB = uDWordByte.BYTE[2];++pEccB;
++ *pEccB = uDWordByte.BYTE[3];++pEccB;
++ nReadSize -= 4;
++ }
++ /* Read as WORD */
++ else if ( nReadSize >= 2 )
++ {
++ *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ nReadSize -= 2;
++ }
++ /* Read as BYTE */
++ else
++ {
++ *pEccB = (unsigned char)pNFC->NFC_SDATA; ++pEccB;
++ nReadSize -= 1;
++ }
++ }
++
++ /* Check and Correct ECC code */
++ //===================================
++ // 4 Bit MLC ECC Correction
++ //===================================
++ if ( ( nECCBuffer[0] == 0x00 ) && ( nECCBuffer[1] == 0x00 ) &&
++ ( nECCBuffer[2] == 0x00 ) && ( nECCBuffer[3] == 0x00 ) &&
++ ( nECCBuffer[4] == 0x00 ) && ( nECCBuffer[5] == 0x00 ) &&
++ ( nECCBuffer[6] == 0x00 ) && ( nECCBuffer[7] == 0x00 ))
++ {
++ res |= NAND_IO_CorrectionMLC( MLC_ECC_4BIT_TYPE, pSpareBuffer, nECCBuffer, (U16)nSpareTotalSize );
++ res |= ERR_NAND_IO_FAILED_CORRECTION_MLC_ECC;
++ }
++ else if ( ( nECCBuffer[0] == 0xFF ) && ( nECCBuffer[1] == 0xFF ) &&
++ ( nECCBuffer[2] == 0xFF ) && ( nECCBuffer[3] == 0xFF ) &&
++ ( nECCBuffer[4] == 0xFF ) && ( nECCBuffer[5] == 0xFF ) &&
++ ( nECCBuffer[6] == 0xFF ) && ( nECCBuffer[7] == 0xFF ))
++ {
++ ASM_NOP;
++ }
++ else
++ {
++ res |= NAND_IO_CorrectionMLC( MLC_ECC_4BIT_TYPE, pSpareBuffer, nECCBuffer, (U16)nSpareTotalSize );
++ }
++
++ //=========================================================================
++ // Ecc Clear
++ //=========================================================================
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ if ( nPageEccOnOff == PAGE_ECC_ON )
++ {
++ //memset( gNAND_IO_ShareEccBuffer, 0xFF, nDevInfo->EccWholeDataSize );
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)&gNAND_IO_ShareEccBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)&gNAND_IO_ShareEccBuffer[0];
++ else
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = ( nDevInfo->EccWholeDataSize >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++ }
++
++// return res;
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_ReadSpareDataECC( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION :
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadSpareDataMTD( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nPageEccOnOff )
++{
++ unsigned int i;
++ unsigned int nSpareTotalSize;
++ unsigned int nECCDataSize = 8;
++ unsigned char bAlignAddr;
++ unsigned char *pSpareB = 0;
++ unsigned int *pSpareDW = 0;
++ unsigned char *pSpareBuffer;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ nSpareTotalSize = 32;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nSpareBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ else
++ pSpareB = (unsigned char*)nSpareBuffer;
++
++ if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ //----------------------------------------------
++ // Read Small Page Spare Data: 16Byte
++ //----------------------------------------------
++ i = 4;
++
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++ if ( nDevInfo->Feature.MediaType & A_PARALLEL )
++ {
++ if ( nPageEccOnOff == PAGE_ECC_ON )
++ {
++ memset( gNAND_IO_ShareEccBuffer, 0xFF, 16 );
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)&gNAND_IO_ShareEccBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)&gNAND_IO_ShareEccBuffer[0];
++ else
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = 4;
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++ }
++ }
++
++ return (NAND_IO_ERROR)SUCCESS;
++ }
++
++ /* Set Spare Buffer */
++ pSpareBuffer = ( bAlignAddr ) ? (unsigned char*)pSpareDW : (unsigned char*)pSpareB;
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = ( nSpareTotalSize >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++ if (( nDevInfo->Feature.MediaType & A_MLC ) || ( nDevInfo->Feature.MediaType & A_SLC ))
++ nECCDataSize = 8;
++ else if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ nECCDataSize = 20;
++ else if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ nECCDataSize = 26;
++
++ if ( nPageEccOnOff == PAGE_ECC_ON )
++ {
++ memset( gNAND_IO_ShareEccBuffer, 0xFF, ( nECCDataSize << 2 ) );
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)&gNAND_IO_ShareEccBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)&gNAND_IO_ShareEccBuffer[0];
++ else
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = ( ( nECCDataSize << 2) >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++ }
++
++ return res;
++}
++
++#if defined(USE_V_ADDRESS) && defined(_WINCE_)
++NAND_IO_ERROR NAND_IO_SetNFC_IRQ_Handle( int nIrq, DWORD nItrID, HANDLE hEvent )
++{
++ if ( nIrq == IRQ_NFC )
++ {
++ gNFC_IRQ_Intr = nItrID;
++ gNFC_IRQ_Handle = hEvent;
++ printf("[-IRQ_NFC:EventH:0x%x]\r\n", gNFC_IRQ_Handle);
++ }
++ else
++ {
++ gEXT_IRQ_Intr = nItrID;
++ gEXT_IRQ_Handle = hEvent;
++ printf("[-IRQ_EI11:EventH:0x%x]\r\n", gEXT_IRQ_Handle);
++ }
++}
++#endif
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_Read512DataDoubleBuf( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++* U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff, int nSpareOnOff );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nReadPPSize =
++* nSpareBuffer =
++* nStartPPage =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_Read512DataDoubleBuf( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff, int nSpareOnOff )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0, *pSpareDW = 0;
++ unsigned char *pDataBuffer, *pSpareBuffer = 0;
++ unsigned char *pPrDataBuffer = 0;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw17);
++ #endif
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++ nSpareOnOff = TNFTL_READ_SPARE_ON;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw17); //----------------------->> ECC Setup
++ #endif /* READ_SPEED_CHECK */
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ // Set SpareBuffer Pointer =>> ECCBuffer
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //=========================================================================
++ // Empty Page ECCBuffer Pointer Increment
++ //=========================================================================
++ for ( j = 0; j < nStartPPage; ++j )
++ pSpareB += nDevInfo->EccDataSize;
++ }
++
++ //----------------------------------------------
++ // Read Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nReadPPSize; ++j )
++ {
++ /* Set Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Read 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++ }
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw21);
++ #endif
++
++ /* Read 512 Data Area */
++ i = 128;
++ do {
++ if ( bAlignAddr )
++ {
++ *pPageDW = pNFC->NFC_WDATA;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ *pPageB = uDWordByte.BYTE[2];++pPageB;
++ *pPageB = uDWordByte.BYTE[3];++pPageB;
++ }
++ }while(--i);
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw21);
++ #endif
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw17);
++ #endif
++
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++ }
++
++ /* Disable DMA Ahead */
++ /* Start DMA on NFC BUS */
++ NAND_IO_SetupDMADoubleBuf( NAND_IO_DMA_READ, j );
++
++ #if defined(USE_V_ADDRESS) && defined(_WINCE_) && defined(__USE_NAND_ISR__)
++
++ #ifdef NAND_GPIO_DEBUG
++ BITSET(pGPIO->GPFDAT, Hw16);
++ #endif
++
++ BITSET(pPIC->CLR1, Hw9); // Interrupt Status Clear
++ InterruptDone(gNFC_IRQ_Intr);
++
++ pNFC->NFC_RSTART = 0;
++
++ if ( pNFC->NFC_IREQ & HwNFC_IREQ_FLAG0 ) //Check Read-Done Flag
++ {
++ BITSET( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG0 ); // Interrupt Clear
++
++ #ifdef NAND_IO_UART_DEBUG
++ ND_TRACE("[NAND]Rx-DMA already complite[%s:%d]\r\n", __FUNCTION__, __LINE__);
++ #endif
++ }
++ else
++ {
++ DWORD nTimeOut = 1; // Unit: Milliseconds
++
++ #ifdef NAND_GPIO_DEBUG
++ BITSET(pGPIO->GPFDAT, Hw17);
++ #endif
++
++ if( WaitForSingleObject( gNFC_IRQ_Handle, nTimeOut) == WAIT_OBJECT_0 )
++ {
++ #ifdef NAND_GPIO_DEBUG
++ BITSET(pGPIO->GPFDAT, Hw21);
++ BITCLR(pGPIO->GPFDAT, Hw21);
++ #endif
++
++ #ifdef NAND_IO_UART_DEBUG
++ ND_TRACE("[NAND]Rx-DMA complite[%s:%d]\r\n", __FUNCTION__, __LINE__);
++ #endif
++ }
++ else
++ {
++ #ifdef NAND_GPIO_DEBUG
++ BITSET(pGPIO->GPFDAT, Hw22);
++ BITCLR(pGPIO->GPFDAT, Hw22);
++ #endif
++ #ifdef NAND_IO_UART_DEBUG
++ ND_TRACE("[NAND]Rx-DMA Wait Time Out[%s:%d]\r\n", __FUNCTION__, __LINE__);
++ #endif
++ }
++ #ifdef NAND_GPIO_DEBUG
++ BITCLR(pGPIO->GPFDAT, Hw17);
++ #endif
++ }
++
++ BITSET( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG0 ); // Interrupt Clear
++ BITSET(pPIC->CLR1, Hw9); // Interrupt Status Clear
++ InterruptDone(gNFC_IRQ_Intr);
++
++ #ifdef NAND_GPIO_DEBUG
++ BITCLR(pGPIO->GPFDAT, Hw16);
++ #endif
++ #else
++
++ NAND_IO_IRQ_Mask();
++ pNFC->NFC_RSTART = 0;
++ #endif
++
++ if ( j == 0 )
++ {
++// memcpy( gNAND_IO_ShareEccBuffer, gpDMA_WorkBuffer0, nDevInfo->EccWholeDataSize );
++ }
++ else
++ {
++ if ( j & 1 )
++ memcpy( pPrDataBuffer, gpDMA_WorkBuffer1, 512 );
++ else
++ memcpy( pPrDataBuffer, gpDMA_WorkBuffer0, 512 );
++ }
++
++
++ #if defined(USE_V_ADDRESS) && defined(_WINCE_) && defined(__USE_NAND_ISR__)
++ // nop
++ #else
++ while ( ISZERO(pNFC->NFC_IREQ, HwNFC_IREQ_FLAG0) );
++ NAND_IO_IRQ_UnMask();
++ #endif
++
++ if ( j == (unsigned int)( nReadPPSize - 1 ) )
++ {
++ if ( j & 1 )
++ memcpy( pDataBuffer, gpDMA_WorkBuffer0, 512 );
++ else
++ memcpy( pDataBuffer, gpDMA_WorkBuffer1, 512 );
++ }
++ else
++ {
++ pPrDataBuffer = pDataBuffer; // Buffer Pointer Backup
++
++ if ( j & 1 )
++ pDataBuffer =(unsigned char *)gpDMA_WorkBuffer0;
++ else
++ pDataBuffer =(unsigned char *)gpDMA_WorkBuffer1;
++ }
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++ #endif
++ //####################################################
++ //####################################################
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ // NOP
++ }
++ else if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ /* Set Spare Buffer */
++ pSpareBuffer = ( bAlignAddr ) ? (unsigned char*)pSpareDW : (unsigned char*)pSpareB;
++
++ /* Read 16Bytes spare data */
++ i = 4;
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++
++ pSpareB = (unsigned char*)pSpareBuffer;
++ pSpareB += NAND_IO_SPARE_SIZE_SMALL;
++ }
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw22);
++ #endif
++
++ /* Check and Correct ECC code */
++ if ( nEccOnOff == ECC_ON )
++ {
++ if (( nDevInfo->EccType == SLC_ECC_TYPE ) && ( nDevInfo->Feature.MediaType & A_SMALL ))
++ {
++ //===================================
++ // SLC ECC Correction
++ //===================================
++ pSpareBuffer += NAND_IO_SPARE_SIZE_SMALL;
++ res |= NAND_IO_CorrectionSLC( pDataBuffer, pSpareBuffer );
++ }
++ else
++ {
++ if ( nDevInfo->EccType == SLC_ECC_TYPE )
++ res |= NAND_IO_CorrectionSLC( pDataBuffer, pSpareB );
++ else
++ res |= NAND_IO_CorrectionMLC( nDevInfo->EccType, pDataBuffer, pSpareB, 512 );
++
++ pSpareB += nDevInfo->EccDataSize;
++ }
++ }
++
++ #ifdef READ_SPEED_CHECK
++ NAND_IO_GPIO_Toggle(Hw22);
++ #endif
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_Read512Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++* U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff, int nSpareOnOff );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nReadPPSize =
++* nSpareBuffer =
++* nStartPPage =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_Read512Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff, int nSpareOnOff )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ unsigned char *pPageB = 0, *pSpareB;
++ unsigned int *pPageDW = 0, *pSpareDW;
++ unsigned char *pDataBuffer, *pSpareBuffer;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++ nSpareOnOff = TNFTL_READ_SPARE_ON;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ // Set SpareBuffer Pointer =>> ECCBuffer
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //=========================================================================
++ // Empty Page ECCBuffer Pointer Increment
++ //=========================================================================
++ for ( j = 0; j < nStartPPage; ++j )
++ pSpareB += nDevInfo->EccDataSize;
++ }
++
++ //----------------------------------------------
++ // Read Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nReadPPSize; ++j )
++ {
++ /* Set Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Read 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++ }
++
++ /* Read 512 Data Area */
++ i = 128;
++ do {
++ if ( bAlignAddr )
++ {
++ *pPageDW = pNFC->NFC_WDATA;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ *pPageB = uDWordByte.BYTE[2];++pPageB;
++ *pPageB = uDWordByte.BYTE[3];++pPageB;
++ }
++ }while(--i);
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; /* Clear ECC Block */
++ }
++
++ /* Start DMA on NFC BUS */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupDMA( (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ (void*)pDataBuffer, 4, 0,
++ NAND_IO_DMA_READ, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)&pNFC->NFC_LDATA, 0, 0,
++ (void*)pDataBuffer, 4, 0,
++ NAND_IO_DMA_READ, 512 );
++ #endif
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++ #endif
++ //####################################################
++ //####################################################
++
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ // NOP
++ }
++ else if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ /* Set Spare Buffer */
++ pSpareBuffer = ( bAlignAddr ) ? (unsigned char*)pSpareDW : (unsigned char*)pSpareB;
++
++ /* Read 16Bytes spare data */
++ i = 4;
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++
++ pSpareB = (unsigned char*)pSpareBuffer;
++ pSpareB += NAND_IO_SPARE_SIZE_SMALL;
++ }
++
++ /* Check and Correct ECC code */
++ if ( nEccOnOff == ECC_ON )
++ {
++ if (( nDevInfo->EccType == SLC_ECC_TYPE ) && ( nDevInfo->Feature.MediaType & A_SMALL ))
++ {
++ //===================================
++ // SLC ECC Correction
++ //===================================
++ pSpareBuffer += NAND_IO_SPARE_SIZE_SMALL;
++ res |= NAND_IO_CorrectionSLC( pDataBuffer, pSpareBuffer );
++ }
++ else
++ {
++ if ( nDevInfo->EccType == SLC_ECC_TYPE )
++ res |= NAND_IO_CorrectionSLC( pDataBuffer, pSpareB );
++ else
++ res |= NAND_IO_CorrectionMLC( nDevInfo->EccType, pDataBuffer, pSpareB, 512 );
++
++ pSpareB += nDevInfo->EccDataSize;
++ }
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_Read512DataMTD( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++* U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION :
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nReadPPSize =
++* nSpareBuffer =
++* nStartPPage =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_Read512DataMTD( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff, int nSpareOnOff )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ unsigned int nECCDataSize = 8;
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0, *pSpareDW = 0;
++ unsigned char *pDataBuffer, *pSpareBuffer = 0;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( ( nStartPPage + nReadPPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++ nSpareOnOff = TNFTL_READ_SPARE_ON;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ if (( nDevInfo->Feature.MediaType & A_MLC ) ||( nDevInfo->Feature.MediaType & A_SLC ))
++ nECCDataSize = 8;
++ else if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ nECCDataSize = 20;
++ else if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ nECCDataSize = 26;
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ // Set SpareBuffer Pointer =>> ECCBuffer
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //=========================================================================
++ // Empty Page ECCBuffer Pointer Increment
++ //=========================================================================
++ for ( j = 0; j < nStartPPage; ++j )
++ pSpareB += nECCDataSize;
++ }
++
++ //----------------------------------------------
++ // Read Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nReadPPSize; ++j )
++ {
++ /* Set Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Read 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; // Clear ECC Block
++ }
++
++ /* Read 512 Data Area */
++ i = 128;
++ do {
++ if ( bAlignAddr )
++ {
++ *pPageDW = pNFC->NFC_WDATA;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ *pPageB = uDWordByte.BYTE[2];++pPageB;
++ *pPageB = uDWordByte.BYTE[3];++pPageB;
++ }
++ }while(--i);
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_DECODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000; // Clear ECC Block
++ }
++
++
++ /* Start DMA on NFC BUS */
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ (void*)pDataBuffer, 4, 0,
++ NAND_IO_DMA_READ, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)&pNFC->NFC_LDATA, 0, 0,
++ (void*)pDataBuffer, 4, 0,
++ NAND_IO_DMA_READ, 512 );
++ #endif
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++
++ #endif
++ //####################################################
++ //####################################################
++
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ // NOP
++ }
++ else if ( nDevInfo->Feature.MediaType & A_SMALL )
++ {
++ /* Set Spare Buffer */
++ pSpareBuffer = ( bAlignAddr ) ? (unsigned char*)pSpareDW : (unsigned char*)pSpareB;
++
++ /* Read 16Bytes spare data */
++ i = 4;
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++ pSpareB = (unsigned char*)pSpareBuffer;
++ pSpareB += NAND_IO_SPARE_SIZE_SMALL;
++ }
++
++ /* Check and Correct ECC code */
++ if ( nEccOnOff == ECC_ON )
++ {
++ if (( nDevInfo->EccType == SLC_ECC_TYPE ) && ( nDevInfo->Feature.MediaType & A_SMALL ))
++ {
++ //===================================
++ // SLC ECC Correction
++ //===================================
++ pSpareBuffer += NAND_IO_SPARE_SIZE_SMALL;
++ res |= NAND_IO_CorrectionSLC( pDataBuffer, pSpareBuffer );
++ }
++ else
++ {
++ if ( nDevInfo->EccType == SLC_ECC_TYPE )
++ res |= NAND_IO_CorrectionSLC( pDataBuffer, pSpareB );
++ else
++ res |= NAND_IO_CorrectionMLC( nDevInfo->EccType, pDataBuffer, pSpareB, 512 );
++
++ pSpareB += nECCDataSize;
++ }
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_ReadUserSizeData( NAND_IO_DEVINFO *nDevInfo, U16 nColumnAddr, U32 nReadSize, U8 *nReadBuffer );
++*
++* DESCRIPTION :
++* INPUT:
++* nColumnAddr =
++* nDevInfo =
++* nReadBuffer =
++* nReadSize =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_ReadUserSizeData( NAND_IO_DEVINFO *nDevInfo, U16 nColumnAddr, U32 nReadSize, U8 *nReadBuffer )
++{
++ unsigned int *pSpareDW = 0;
++ unsigned char *pPageB = 0;
++ DWORD_BYTE uDWordByte;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Check Parameter
++ //=========================================================================
++ if ( (U32)( nColumnAddr + nReadSize ) > (U16)( nDevInfo->Feature.PageSize + nDevInfo->Feature.SpareSize ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Read UserSize Data
++ //=========================================================================
++
++ /* Adapt type of address */
++ pPageB = (unsigned char*)nReadBuffer;
++ pSpareDW= (unsigned int*)nReadBuffer;
++ //if ( nReadSize >= 4 )
++ //{
++ // #ifdef USE_NFC_LDATA /* 08.12.17 */
++ // /* Read 512 Data Area */
++ // BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ // pNFC->NFC_DSIZE = nReadSize;
++ // pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ // pNFC->NFC_PSTART = 0;
++ //
++ // do {
++ // while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++ //
++ // {
++ // uDWordByte.DWORD = pNFC->NFC_LDATA;
++ // *pPageB = uDWordByte.BYTE[0];++pPageB;
++ // *pPageB = uDWordByte.BYTE[1];++pPageB;
++ // *pPageB = uDWordByte.BYTE[2];++pPageB;
++ // *pPageB = uDWordByte.BYTE[3];++pPageB;
++ // }
++ //
++ // nReadSize -= 4;
++ //
++ // }while(nReadSize);
++ //
++ // while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ //}
++ //else
++ //{
++ // #endif
++ while ( nReadSize )
++ {
++ /* Read as DWORD */
++ if ( nReadSize >= 4 )
++ {
++ uDWordByte.DWORD = WORD_OF(pNFC->NFC_WDATA);
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ *pPageB = uDWordByte.BYTE[2];++pPageB;
++ *pPageB = uDWordByte.BYTE[3];++pPageB;
++ nReadSize -= 4;
++ }
++ /* Read as WORD */
++ else if ( nReadSize >= 2 )
++ {
++ uDWordByte.WORD[0] = HWORD_OF(pNFC->NFC_WDATA);
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ nReadSize -= 2;
++ }
++ /* Read as BYTE */
++ else
++ {
++ uDWordByte.BYTE[0] = BYTE_OF(pNFC->NFC_WDATA);
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ nReadSize -= 1;
++ }
++ }
++ //}
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ return (NAND_IO_ERROR)SUCCESS;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_WriteSpareData( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++NAND_IO_ERROR NAND_IO_WriteSpareData( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nPageEccOnOff )
++{
++ unsigned int i;
++ unsigned int nSpareTotalSize;
++ unsigned int nWriteSize;
++ unsigned char bAlignAddr;
++ unsigned char *pSpareB = 0;
++ unsigned int *pSpareDW = 0;
++ unsigned char *pEccB;
++ #ifdef _LINUX_
++ unsigned char nECCBuffer[28]__attribute__((aligned(8)));
++ #else
++ unsigned char nECCBuffer[28];
++ #endif
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ nSpareTotalSize = 12;
++ else
++ nSpareTotalSize = 16;
++
++ //=========================================================================
++ // Check Align of nSpareBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nSpareBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ else
++ pSpareB = (unsigned char*)nSpareBuffer;
++
++ //==============================================================
++ // Write Spare
++ //==============================================================
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++ if (!( pNFC->NFC_CTRL1 & Hw30 ))
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)ECC_ON, ECC_ENCODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)ECC_ON, ECC_ENCODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( nSpareTotalSize << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++
++ /* Write 12Bytes spare data */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = nSpareTotalSize;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++
++ NAND_IO_IRQ_Mask();
++
++ pNFC->NFC_PSTART = 0;
++
++ i = ( nSpareTotalSize >> 2 );
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_LDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ NAND_IO_IRQ_UnMask();
++ }
++ else
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)ECC_ON, ECC_ENCODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)ECC_ON, ECC_ENCODE, MLC_ECC_4BIT_TYPE, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( nSpareTotalSize << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++
++ i = ( nSpareTotalSize >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++ }
++
++ // Clear ECC Buffer
++ memset( nECCBuffer, 0xFF, 8 );
++
++ /* Adapt type of address */
++ pEccB = (unsigned char*)nECCBuffer;
++
++ /* Load ECC code from ECC block */
++ res = NAND_IO_EncodeECC( MLC_ECC_4BIT_TYPE, pEccB );
++ if ( res != SUCCESS )
++ goto ErrorWriteSpareData;
++
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ /* Write 4Bit ECC data */
++ nWriteSize = 8;
++
++ while ( nWriteSize )
++ {
++ /* Write as DWORD */
++ if ( nWriteSize >= 4 )
++ {
++ uDWordByte.BYTE[0] = *pEccB;++pEccB;
++ uDWordByte.BYTE[1] = *pEccB;++pEccB;
++ uDWordByte.BYTE[2] = *pEccB;++pEccB;
++ uDWordByte.BYTE[3] = *pEccB;++pEccB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ nWriteSize -= 4;
++ }
++ /* Write as WORD */
++ else if ( nWriteSize >= 2 )
++ {
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ nWriteSize -= 2;
++ }
++ /* Write as BYTE */
++ else
++ {
++ pNFC->NFC_SDATA = *pEccB;++pEccB;
++ nWriteSize -= 1;
++ }
++ }
++
++ if ( nPageEccOnOff == PAGE_ECC_ON )
++ {
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)&gNAND_IO_ShareEccBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)&gNAND_IO_ShareEccBuffer[0];
++ else
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = ( nDevInfo->EccWholeDataSize >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++ }
++ }
++ else
++ {
++ i = ( nSpareTotalSize >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ if (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL ))
++ {
++ if ( nPageEccOnOff == PAGE_ECC_ON )
++ {
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)&gNAND_IO_ShareEccBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)&gNAND_IO_ShareEccBuffer[0];
++ else
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = ( nDevInfo->EccWholeDataSize >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++ }
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++
++ErrorWriteSpareData:
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_WriteSpareDataMTD( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nPageEccOnOff );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nPageEccOnOff =
++* nSpareBuffer =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_WriteSpareDataMTD( NAND_IO_DEVINFO *nDevInfo, U8 *nSpareBuffer, int nPageEccOnOff )
++{
++ unsigned int i;
++ unsigned int nSpareTotalSize;
++ unsigned int nECCDataSize = 8;
++ unsigned char bAlignAddr;
++ unsigned char *pSpareB = 0;
++ unsigned int *pSpareDW = 0;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ nSpareTotalSize = 32;
++
++ //=========================================================================
++ // Check Align of nSpareBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nSpareBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ else
++ pSpareB = (unsigned char*)nSpareBuffer;
++
++ if (( nDevInfo->Feature.MediaType & A_MLC ) ||( nDevInfo->Feature.MediaType & A_SLC ))
++ nECCDataSize = 8;
++ else if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ nECCDataSize = 20;
++ else if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ nECCDataSize = 26;
++
++ //==============================================================
++ // Write Spare
++ //==============================================================
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++
++ i = ( nSpareTotalSize >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ if ( nPageEccOnOff == PAGE_ECC_ON )
++ {
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)&gNAND_IO_ShareEccBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)&gNAND_IO_ShareEccBuffer[0];
++ else
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = ( ( nECCDataSize << 2 ) >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++ }
++ }
++ else
++ {
++ i = ( nSpareTotalSize >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ if (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL ))
++ {
++ if ( nPageEccOnOff == PAGE_ECC_ON )
++ {
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)&gNAND_IO_ShareEccBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)&gNAND_IO_ShareEccBuffer[0];
++ else
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++
++ //----------------------------------------------
++ // Read Spare Data
++ //----------------------------------------------
++ i = ( ( 8 << nDevInfo->ShiftPPages) >> 2 );
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++ }
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_Write512DataDoubleBuf( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize,
++* U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nSpareBuffer =
++* nStartPPage =
++* nWritePPSize =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_Write512DataDoubleBuf( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ #ifdef _LINUX_
++ unsigned char nDummyPageBuffer[512]__attribute__((aligned(8)));
++ unsigned char nECCBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nDummyPageBuffer[512];
++ unsigned char nECCBuffer[30];
++ #endif
++ unsigned int ColumnAddr;
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0;
++ unsigned char *pDataBuffer;
++ unsigned char *pEccB, *pSpare;
++ #ifdef NAND_IO_USE_MCU_ACCESS
++ DWORD_BYTE uDWordByte;
++ #endif
++ NAND_IO_ECC_INFO *pECC_Info;
++ NAND_IO_ERROR res;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pPageDW = (unsigned int*)nPageBuffer;
++ else
++ pPageB = (unsigned char*)nPageBuffer;
++
++ // Set SpareBuffer Pointer =>> ECCBuffer
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ memset( gNAND_IO_ShareEccBuffer, 0xFF, nDevInfo->EccWholeDataSize );
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++ }
++ else
++ {
++ pSpareB = (unsigned char*)nSpareBuffer;
++ pSpareB += NAND_IO_SPARE_SIZE_SMALL;
++ }
++
++ //=========================================================================
++ // Empty Page ECCBuffer Pointer Increment
++ //=========================================================================
++ for ( j = 0; j < nStartPPage; ++j )
++ {
++ if ( nDevInfo->EccType == SLC_ECC_TYPE )
++ pECC_Info = &gMLC_ECC_1Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ pECC_Info = &gMLC_ECC_4Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_8BIT_TYPE )
++ pECC_Info = &gMLC_ECC_8Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_12BIT_TYPE )
++ pECC_Info = &gMLC_ECC_12Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_14BIT_TYPE )
++ pECC_Info = &gMLC_ECC_14Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_16BIT_TYPE )
++ pECC_Info = &gMLC_ECC_16Bit;
++ else
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ {
++ pSpare = (unsigned char*)pSpareB;
++
++ for ( i = 0; i < nDevInfo->EccDataSize; ++i )
++ pSpare[i] = pECC_Info->All_FF_512_ECC_Code[i];
++ }
++ else
++ {
++ memcpy( (void*)pSpareB, (void*)pECC_Info->All_FF_512_ECC_Code, nDevInfo->EccDataSize);
++ }
++
++ pSpareB += nDevInfo->EccDataSize;
++ }
++
++ //----------------------------------------------
++ // Write Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nWritePPSize; ++j )
++ {
++ /* Get Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ if (!( pNFC->NFC_CTRL1 & Hw30 ))
++ {
++ if ( nEccOnOff == ECC_ON )
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++
++ NAND_IO_IRQ_Mask();
++
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_LDATA = *pPageDW;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ NAND_IO_IRQ_UnMask();
++ }
++ else
++ {
++ if ( nEccOnOff == ECC_ON )
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ i = 128;
++ do {
++
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pPageDW;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++ }
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ if ( nEccOnOff == ECC_ON )
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ if ( j == 0 )
++ memcpy( gpDMA_WorkBuffer1, pDataBuffer, 512 );
++
++ NAND_IO_SetupDMADoubleBuf( NAND_IO_DMA_WRITE, j );
++
++ if ( pNFC->NFC_CTRL1 & Hw31 )
++ BITCLR( pNFC->NFC_CTRL1, Hw31 );
++
++ NAND_IO_IRQ_Mask();
++ pNFC->NFC_PSTART = 0;
++
++ if ( j != (unsigned int)( nWritePPSize - 1 ) )
++ {
++ if ( j & 1 )
++ memcpy( gpDMA_WorkBuffer1, (void *)(pDataBuffer + 512), 512 );
++ else
++ memcpy( gpDMA_WorkBuffer0, (void *)(pDataBuffer + 512), 512 );
++ }
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ NAND_IO_IRQ_UnMask();
++
++ if ( pNFC->NFC_CTRL1 & Hw30 )
++ BITSET( pNFC->NFC_CTRL1, Hw31 );
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++ #endif
++ //####################################################
++ //####################################################
++
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ {
++ pSpare = (unsigned char*)pSpareB;
++ pEccB = (unsigned char*)nECCBuffer;
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pEccB );
++ for ( i = 0; i < nDevInfo->EccDataSize; ++i )
++ pSpare[i] = pEccB[i];
++ }
++ else
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pSpareB );
++ }
++ else
++ {
++ pEccB = (unsigned char*)nECCBuffer;
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pEccB );
++ memcpy( pSpareB, pEccB, NAND_IO_SPARE_SIZE_SMALL );
++ }
++
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++ }
++
++ pSpareB += nDevInfo->EccDataSize;
++ }
++
++ //=========================================================================
++ // Empty PPage Write
++ //=========================================================================
++ if ( ( nStartPPage + nWritePPSize ) != ( nDevInfo->PPages ) )
++ {
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ //---------------------------------
++ // Random Data Input [ 0x85 ]
++ //---------------------------------
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8585;
++
++ //---------------------------------
++ // Write Column Address
++ //---------------------------------
++ ColumnAddr = nDevInfo->Feature.PageSize;
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (ColumnAddr >> 1) : ColumnAddr;
++ NAND_IO_WriteColAddr( ColumnAddr, nDevInfo );
++
++ //---------------------------------
++ // ECC Data Clear
++ //---------------------------------
++ for ( j = 0; j < (U16)( nDevInfo->PPages - ( nStartPPage + nWritePPSize ) ); ++j )
++ {
++ if ( nDevInfo->EccType == SLC_ECC_TYPE )
++ pECC_Info = &gMLC_ECC_1Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ pECC_Info = &gMLC_ECC_4Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_8BIT_TYPE )
++ pECC_Info = &gMLC_ECC_8Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_12BIT_TYPE )
++ pECC_Info = &gMLC_ECC_12Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_14BIT_TYPE )
++ pECC_Info = &gMLC_ECC_14Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_16BIT_TYPE )
++ pECC_Info = &gMLC_ECC_16Bit;
++ else
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ {
++ pSpare = (unsigned char*)pSpareB;
++
++ for ( i = 0; i < nDevInfo->EccDataSize; ++i )
++ pSpare[i] = pECC_Info->All_FF_512_ECC_Code[i];
++ }
++ else
++ {
++ memcpy( (void*)pSpareB, (void*)pECC_Info->All_FF_512_ECC_Code, nDevInfo->EccDataSize);
++ }
++ pSpareB += nDevInfo->EccDataSize;
++ }
++ }
++ else
++ {
++ memset( nDummyPageBuffer, 0xFF, 512 );
++ //Write Dummy Data
++ for ( j = 0; j < (U16)( nDevInfo->PPages - ( nStartPPage + nWritePPSize ) ); ++j )
++ {
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++
++ NAND_IO_IRQ_Mask();
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do
++ {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++ pNFC->NFC_LDATA = 0xFFFFFFFF;
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ NAND_IO_IRQ_UnMask();
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)nDummyPageBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)nDummyPageBuffer, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ #endif
++ //####################################################
++ //####################################################
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pSpareB );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++ }
++
++ pSpareB += nDevInfo->EccDataSize;
++ }
++ }
++ }
++
++ //=========================================================================
++ // Write Spare Data
++ //=========================================================================
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ NAND_IO_WriteSpareData( nDevInfo, nSpareBuffer, PAGE_ECC_ON );
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++
++ErrorWrite512Data:
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_Write512Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize,
++* U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nSpareBuffer =
++* nStartPPage =
++* nWritePPSize =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_Write512Data( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ #ifdef _LINUX_
++ unsigned char nDummyPageBuffer[512]__attribute__((aligned(8)));
++ unsigned char nECCBuffer[30]__attribute__((aligned(8)));
++ #else
++ unsigned char nDummyPageBuffer[512];
++ unsigned char nECCBuffer[30];
++ #endif
++ unsigned int ColumnAddr;
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0;
++ unsigned char *pDataBuffer;
++ unsigned char *pEccB, *pSpare;
++ #ifdef NAND_IO_USE_MCU_ACCESS
++ DWORD_BYTE uDWordByte;
++ #endif
++ NAND_IO_ECC_INFO *pECC_Info;
++ NAND_IO_ERROR res;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pPageDW = (unsigned int*)nPageBuffer;
++ else
++ pPageB = (unsigned char*)nPageBuffer;
++
++ // Set SpareBuffer Pointer =>> ECCBuffer
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ memset( gNAND_IO_ShareEccBuffer, 0xFF, nDevInfo->EccWholeDataSize );
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++ }
++ else
++ {
++ pSpareB = (unsigned char*)nSpareBuffer;
++ pSpareB += NAND_IO_SPARE_SIZE_SMALL;
++ }
++
++ //=========================================================================
++ // Empty Page ECCBuffer Pointer Increment
++ //=========================================================================
++ for ( j = 0; j < nStartPPage; ++j )
++ {
++ if ( nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ pECC_Info = &gMLC_ECC_4Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_8BIT_TYPE )
++ pECC_Info = &gMLC_ECC_8Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_12BIT_TYPE )
++ pECC_Info = &gMLC_ECC_12Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_14BIT_TYPE )
++ pECC_Info = &gMLC_ECC_14Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_16BIT_TYPE )
++ pECC_Info = &gMLC_ECC_16Bit;
++ else
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ {
++ pSpare = (unsigned char*)pSpareB;
++
++ for ( i = 0; i < nDevInfo->EccDataSize; ++i )
++ pSpare[i] = pECC_Info->All_FF_512_ECC_Code[i];
++ }
++ else
++ {
++ memcpy( (void*)pSpareB, (void*)pECC_Info->All_FF_512_ECC_Code, nDevInfo->EccDataSize);
++ }
++
++ pSpareB += nDevInfo->EccDataSize;
++ }
++
++ //----------------------------------------------
++ // Write Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nWritePPSize; ++j )
++ {
++ /* Get Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ if (!( pNFC->NFC_CTRL1 & Hw30 ))
++ {
++ if ( nEccOnOff == ECC_ON )
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++
++ NAND_IO_IRQ_Mask();
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_LDATA = *pPageDW;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ NAND_IO_IRQ_UnMask();
++ }
++ else
++ {
++ if ( nEccOnOff == ECC_ON )
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_WDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ i = 128;
++ do {
++
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pPageDW;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++ }
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ if ( nEccOnOff == ECC_ON )
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)pDataBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)pDataBuffer, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++ #endif
++ //####################################################
++ //####################################################
++
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ {
++ pSpare = (unsigned char*)pSpareB;
++ pEccB = (unsigned char*)nECCBuffer;
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pEccB );
++ for ( i = 0; i < nDevInfo->EccDataSize; ++i )
++ pSpare[i] = pEccB[i];
++ }
++ else
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pSpareB );
++ }
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++ }
++ pSpareB += nDevInfo->EccDataSize;
++ }
++
++ //=========================================================================
++ // Empty PPage Write
++ //=========================================================================
++ if ( ( nStartPPage + nWritePPSize ) != ( nDevInfo->PPages ) )
++ {
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ //---------------------------------
++ // Random Data Input [ 0x85 ]
++ //---------------------------------
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8585;
++
++ //---------------------------------
++ // Write Column Address
++ //---------------------------------
++ ColumnAddr = nDevInfo->Feature.PageSize;
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (ColumnAddr >> 1) : ColumnAddr;
++ NAND_IO_WriteColAddr( ColumnAddr, nDevInfo );
++
++ //---------------------------------
++ // ECC Data Clear
++ //---------------------------------
++ for ( j = 0; j < (U16)( nDevInfo->PPages - ( nStartPPage + nWritePPSize ) ); ++j )
++ {
++ if ( nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ pECC_Info = &gMLC_ECC_4Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_8BIT_TYPE )
++ pECC_Info = &gMLC_ECC_8Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_12BIT_TYPE )
++ pECC_Info = &gMLC_ECC_12Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_14BIT_TYPE )
++ pECC_Info = &gMLC_ECC_14Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_16BIT_TYPE )
++ pECC_Info = &gMLC_ECC_16Bit;
++ else
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ {
++ pSpare = (unsigned char*)pSpareB;
++
++ for ( i = 0; i < nDevInfo->EccDataSize; ++i )
++ pSpare[i] = pECC_Info->All_FF_512_ECC_Code[i];
++ }
++ else
++ {
++ memcpy( (void*)pSpareB, (void*)pECC_Info->All_FF_512_ECC_Code, nDevInfo->EccDataSize);
++ }
++
++ pSpareB += nDevInfo->EccDataSize;
++ }
++ }
++ else
++ {
++ memset( nDummyPageBuffer, 0xFF, 512 );
++ //Write Dummy Data
++ for ( j = 0; j < (U16)( nDevInfo->PPages - ( nStartPPage + nWritePPSize ) ); ++j )
++ {
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++
++ NAND_IO_IRQ_Mask();
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do
++ {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++ pNFC->NFC_LDATA = 0xFFFFFFFF;
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ NAND_IO_IRQ_UnMask();
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)nDummyPageBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)nDummyPageBuffer, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ #endif
++ //####################################################
++ //####################################################
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pSpareB );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++ }
++
++ pSpareB += nDevInfo->EccDataSize;
++ }
++ }
++ }
++
++ //=========================================================================
++ // Write Spare Data
++ //=========================================================================
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ NAND_IO_WriteSpareData( nDevInfo, nSpareBuffer, PAGE_ECC_ON );
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++
++ErrorWrite512Data:
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_Write512DataMTD( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize,
++* U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nEccOnOff =
++* nPageBuffer =
++* nSpareBuffer =
++* nStartPPage =
++* nWritePPSize =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++* REMARK: by nemo
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_Write512DataMTD( NAND_IO_DEVINFO *nDevInfo, U16 nStartPPage, U16 nWritePPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer, int nEccOnOff )
++{
++ unsigned int j;
++ unsigned char bAlignAddr;
++ unsigned int nECCDataSize = 8;
++ #ifdef _LINUX_
++ unsigned char nDummyPageBuffer[512]__attribute__((aligned(8)));
++ #else
++ unsigned char nDummyPageBuffer[512];
++ #endif
++ unsigned int ColumnAddr;
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0;
++ unsigned char *pDataBuffer;
++ #ifdef NAND_IO_USE_MCU_ACCESS
++ unsigned int i;
++ DWORD_BYTE uDWordByte;
++ #endif
++ NAND_IO_ECC_INFO *pECC_Info;
++ NAND_IO_ERROR res;
++
++ if ( ( nStartPPage + nWritePPSize ) > ( nDevInfo->Feature.PageSize >> 9 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nEccOnOff == ECC_ON )
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Get Buffer Pointer
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pPageDW = (unsigned int*)nPageBuffer;
++ else
++ pPageB = (unsigned char*)nPageBuffer;
++
++ if (( nDevInfo->Feature.MediaType & A_MLC ) ||( nDevInfo->Feature.MediaType & A_SLC ))
++ nECCDataSize = 8;
++ else if ( ( nDevInfo->Feature.MediaType & A_MLC_8BIT ) || ( nDevInfo->Feature.MediaType & A_MLC_12BIT ) )
++ nECCDataSize = 20;
++ else if ( nDevInfo->Feature.MediaType & A_MLC_16BIT )
++ nECCDataSize = 26;
++
++
++ // Set SpareBuffer Pointer =>> ECCBuffer
++ if ( ( nDevInfo->Feature.MediaType & A_BIG ) || (( nDevInfo->Feature.MediaType & A_SMALL ) && ( nDevInfo->Feature.MediaType & A_PARALLEL )))
++ {
++ memset( gNAND_IO_ShareEccBuffer, 0xFF, nECCDataSize << 2 );
++ pSpareB = (unsigned char*)&gNAND_IO_ShareEccBuffer[0];
++ }
++ else
++ {
++ pSpareB = (unsigned char*)nSpareBuffer;
++ pSpareB += NAND_IO_SPARE_SIZE_SMALL;
++ }
++
++ //=========================================================================
++ // Empty Page ECCBuffer Pointer Increment
++ //=========================================================================
++ for ( j = 0; j < nStartPPage; ++j )
++ {
++ if ( nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ pECC_Info = &gMLC_ECC_4Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_8BIT_TYPE )
++ pECC_Info = &gMLC_ECC_8Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_12BIT_TYPE )
++ pECC_Info = &gMLC_ECC_12Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_14BIT_TYPE )
++ pECC_Info = &gMLC_ECC_14Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_16BIT_TYPE )
++ pECC_Info = &gMLC_ECC_16Bit;
++ else
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ memcpy( (void*)pSpareB, (void*)pECC_Info->All_FF_512_ECC_Code, nECCDataSize);
++
++ pSpareB += nECCDataSize;
++ }
++
++ //----------------------------------------------
++ // Write Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nWritePPSize; ++j )
++ {
++ /* Get Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ if ( nEccOnOff == ECC_ON )
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++
++ NAND_IO_IRQ_Mask();
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_LDATA = *pPageDW;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_LDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ NAND_IO_IRQ_UnMask();
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ if ( nEccOnOff == ECC_ON )
++ {
++ /* Setup ECC Block */
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE );
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)pDataBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)pDataBuffer, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++ #endif
++ //####################################################
++ //####################################################
++
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pSpareB );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++ }
++
++ pSpareB += nECCDataSize;
++ }
++
++ //=========================================================================
++ // Empty PPage Write
++ //=========================================================================
++ if ( ( nStartPPage + nWritePPSize ) != ( nDevInfo->PPages ) )
++ {
++ if ( nDevInfo->Feature.MediaType & A_BIG )
++ {
++ /* Change Cycle */
++ NAND_IO_SetCommCycleTime();
++
++ //---------------------------------
++ // Random Data Input [ 0x85 ]
++ //---------------------------------
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8585;
++
++ //---------------------------------
++ // Write Column Address
++ //---------------------------------
++ ColumnAddr = nDevInfo->Feature.PageSize;
++ ColumnAddr = ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT ) ? (ColumnAddr >> 1) : ColumnAddr;
++ NAND_IO_WriteColAddr( ColumnAddr, nDevInfo );
++
++ //---------------------------------
++ // ECC Data Clear
++ //---------------------------------
++ for ( j = 0; j < (U16)( nDevInfo->PPages - ( nStartPPage + nWritePPSize ) ); ++j )
++ {
++ if ( nDevInfo->EccType == MLC_ECC_4BIT_TYPE )
++ pECC_Info = &gMLC_ECC_4Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_8BIT_TYPE )
++ pECC_Info = &gMLC_ECC_8Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_12BIT_TYPE )
++ pECC_Info = &gMLC_ECC_12Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_14BIT_TYPE )
++ pECC_Info = &gMLC_ECC_14Bit;
++ else if ( nDevInfo->EccType == MLC_ECC_16BIT_TYPE )
++ pECC_Info = &gMLC_ECC_16Bit;
++ else
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ memcpy( (void*)pSpareB, (void*)pECC_Info->All_FF_512_ECC_Code, nECCDataSize);
++
++ pSpareB += nECCDataSize;
++ }
++ }
++ else
++ {
++ memset( nDummyPageBuffer, 0xFF, 512 );
++ //Write Dummy Data
++ for ( j = 0; j < (U16)( nDevInfo->PPages - ( nStartPPage + nWritePPSize ) ); ++j )
++ {
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_MCU_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++
++ NAND_IO_IRQ_Mask();
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do
++ {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++ pNFC->NFC_LDATA = 0xFFFFFFFF;
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ NAND_IO_IRQ_UnMask();
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Setup ECC Block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ #if defined(_WINCE_) || defined(_LINUX_)
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&NAND_IO_HwLDATA_PA );
++ #else
++ NAND_IO_SetupECC( (U16)nEccOnOff, ECC_ENCODE, nDevInfo->EccType, NAND_DMA_ACCESS, (U32)&pNFC->NFC_LDATA );
++ #endif
++ pECC->ECC_CTRL |= ( 512 << ECC_SHIFT_DATASIZE ); // Data Size...
++ pECC->ECC_CLEAR = 0x00000000;
++ }
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)nDummyPageBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)nDummyPageBuffer, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ #endif
++ //####################################################
++ //####################################################
++ /* Load ECC code from ECC block */
++ if ( nEccOnOff == ECC_ON )
++ {
++ res = NAND_IO_EncodeECC( nDevInfo->EccType, pSpareB );
++ if ( res != SUCCESS )
++ goto ErrorWrite512Data;
++ }
++
++ pSpareB += nECCDataSize;
++ }
++ }
++ }
++
++ //=========================================================================
++ // Write Spare Data
++ //=========================================================================
++ /* Change Cycle */
++ NAND_IO_SetWriteCycleTime();
++
++ NAND_IO_WriteSpareDataMTD( nDevInfo, nSpareBuffer, PAGE_ECC_ON );
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++
++ErrorWrite512Data:
++ return res;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_WriteUserSizeData( NAND_IO_DEVINFO *nDevInfo, U16 nColumnAddr, U32 nWriteSize, U8 *nWriteBuffer );
++*
++* DESCRIPTION :
++* INPUT:
++* nColumnAddr =
++* nDevInfo =
++* nWriteBuffer =
++* nWriteSize =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_WriteUserSizeData( NAND_IO_DEVINFO *nDevInfo, U16 nColumnAddr, U32 nWriteSize, U8 *nWriteBuffer )
++{
++ unsigned int *dwPageB;
++ unsigned char *pPageB;
++ DWORD_BYTE uDWordByte;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ NAND_IO_SetupECC( ECC_OFF, 0, 0, 0, 0 );
++
++ //=========================================================================
++ // Check Parameter
++ //=========================================================================
++ if ( (U32)( nColumnAddr + nWriteSize ) > (U32)( nDevInfo->Feature.PageSize + nDevInfo->Feature.SpareSize ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Write UserSize Data
++ //=========================================================================
++ pPageB = (unsigned char*)nWriteBuffer;
++ dwPageB = (unsigned int*)nWriteBuffer;
++
++ //if ( nWriteSize >= 4 )
++ //{
++ // #ifdef USE_NFC_LDATA /* 08.12.17 */
++ // BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ // pNFC->NFC_DSIZE = nWriteSize;
++ // pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ // pNFC->NFC_PSTART = 0;
++ //
++ // do {
++ // while (!( pNFC->NFC_IREQ & HwNFC_CTRL_FS_RDY ));
++ //
++ // {
++ // uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ // uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ // uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ // uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ // pNFC->NFC_LDATA = uDWordByte.DWORD;
++ // }
++ // nWriteSize -= 4;
++ // }while(nWriteSize);
++ //
++ // while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ //}
++ //else
++ //{
++ // #endif
++ while ( nWriteSize )
++ {
++ /* Write as DWORD */
++ if ( nWriteSize >= 4 )
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ WORD_OF(pNFC->NFC_WDATA) = uDWordByte.DWORD;
++ nWriteSize -= 4;
++ }
++ /* Write as WORD */
++ else if ( nWriteSize >= 2 )
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ HWORD_OF(pNFC->NFC_WDATA) = uDWordByte.WORD[0];
++ nWriteSize -= 2;
++ }
++ /* Write as BYTE */
++ else
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ BYTE_OF(pNFC->NFC_WDATA) = uDWordByte.BYTE[0];
++ nWriteSize -= 1;
++ }
++ }
++ //}
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ return (NAND_IO_ERROR)SUCCESS;
++
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline NAND_IO_ERROR NAND_IO_GetShiftValueForFastMultiPly( U16 nValue, U16* rFactor );
++*
++* DESCRIPTION :
++* INPUT:
++* nValue =
++* rFactor =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++* REMARK :
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_GetShiftValueForFastMultiPly( U16 nValue, U16* rFactor )
++{
++ unsigned short int i;
++
++ *rFactor = 0;
++
++ for ( i = 0; i < NAND_IO_MAX_SHIFT_FACTOR_FOR_MULTIPLY; ++i )
++ {
++ if ( NAND_IO_ShiftFactorForMultiplay[i] == nValue )
++ {
++ *rFactor = i;
++ break;
++ }
++ }
++
++ if ( i >= NAND_IO_MAX_SHIFT_FACTOR_FOR_MULTIPLY )
++ return ERR_NAND_IO_FAILED_GET_SHIFT_FACTOR_FOR_MULTIPLY;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++#if defined (NAND_LBA_INCLUDE)
++NAND_IO_ERROR NAND_IO_LBA_SetCallBackHandler( NAND_LBA_CALLBACK_HANDLER pCallBackHandler )
++{
++ NAND_IO_LBA_CallBackLcdDisplay = pCallBackHandler;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_GetDeviceInfo( U16 nChipNo, NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned short int j,k,l;
++ unsigned char bFindMedia;
++ unsigned char bFindMakerNo;
++ unsigned char bMatchCount;
++ unsigned char rBootMode, rRebootCmd;
++ NAND_IO_DEVID sDeviceCode;
++ NAND_IO_FEATURE *sTempFeatureInfo;
++ NAND_IO_FEATURE *sFindFeatureInfo;
++ NAND_IO_ERROR res;
++
++ bFindMedia = FALSE;
++ sTempFeatureInfo = (NAND_IO_FEATURE*)LBA_NAND_SupportMakerInfo.DevInfo[0];
++ sFindFeatureInfo = (NAND_IO_FEATURE*)LBA_NAND_SupportMakerInfo.DevInfo[0];
++
++ NAND_IO_LBA_DeviceReboot( nDevInfo );
++ res = NAND_IO_GetDeviceInfo( 0, nDevInfo );
++ if ( res != SUCCESS )
++ return ERR_NAND_IO_FAILED_GET_DEVICE_INFO;
++
++ if (!( nDevInfo->Feature.MediaType & S_LBA ))
++ return ERR_NAND_IO_FAILED_GET_DEVICE_INFO;
++
++ res = NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_BCM );
++ if ( res != SUCCESS )
++ {
++ NAND_IO_LBA_DeviceReboot( nDevInfo );
++ res = NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_BCM );
++ if ( res != SUCCESS )
++ return res;
++ }
++
++ NAND_IO_LBA_GetPersistentFunction( nDevInfo, &rBootMode, &rRebootCmd );
++
++ if ( ( rBootMode != 0x22 ) || ( rRebootCmd != 0xAF ))
++ {
++ rBootMode = 0x22;
++ rRebootCmd = 0xAF;
++
++ NAND_IO_LBA_SetBootModeChange( nDevInfo, rBootMode );
++ NAND_IO_LBA_SetRebootCmdChange( nDevInfo, rRebootCmd );
++ NAND_IO_LBA_DeviceReboot( nDevInfo );
++ }
++
++ NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_MDP );
++ NAND_IO_LBA_SetTransferProtocol( nDevInfo, 0x04, 0x00 );
++
++ nDevInfo->LBAInfo.Usable = DISABLE;
++ //=====================================================================
++ // Search Matched NANDFLASH
++ //=====================================================================
++ for ( j = 0; j < 3; ++j ) /* Check Read ID during 3 turn */
++ {
++ /* Read Device CODE */
++ NAND_IO_LBA_ReadID( nDevInfo, &sDeviceCode);
++
++ /* Check Maker ID */
++ bFindMakerNo = 0xFF;
++ for ( k = 0; k < MAX_SUPPORT_MAKER_LBA_NAND; ++k )
++ {
++ if ( sDeviceCode.Code[0] == LBA_NAND_SupportMakerInfo.MakerID[k] )
++ {
++ bFindMakerNo = (unsigned char)k;
++ sTempFeatureInfo = (NAND_IO_FEATURE*)LBA_NAND_SupportMakerInfo.DevInfo[k];
++ break;
++ }
++ }
++
++ if ( bFindMakerNo >= MAX_SUPPORT_MAKER_NAND )
++ continue;
++
++ /* Check Device ID */
++ for ( k = 0; k < LBA_NAND_SupportMakerInfo.MaxSupportNAND[bFindMakerNo]; ++k )
++ {
++ bMatchCount = 0;
++
++ for ( l = 0; l < 4; ++l )
++ {
++ if ( sTempFeatureInfo->DeviceID.Code[l+1] == 0x00 )
++ ++bMatchCount;
++ else if ( sDeviceCode.Code[l+1] == sTempFeatureInfo->DeviceID.Code[l+1] )
++ ++bMatchCount;
++ }
++
++ /* Found NAND Device */
++ if ( bMatchCount >= 4 )
++ {
++ bFindMedia = TRUE;
++ sFindFeatureInfo = sTempFeatureInfo;
++ break;
++ }
++ else
++ ++sTempFeatureInfo;
++ }
++
++ /* Found NAND Device */
++ if ( bFindMedia == TRUE )
++ break;
++ }
++
++ if ( bFindMedia == TRUE )
++ return (NAND_IO_ERROR)SUCCESS;
++ //=====================================================================
++ // Not Found
++ //=====================================================================
++ else
++ return ERR_NAND_IO_FAILED_GET_DEVICE_INFO;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_Init( U16 nChipNo, NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned short int j,k,l;
++ unsigned char bFindMedia;
++ unsigned char bFindMakerNo;
++ unsigned char bMatchCount;
++ unsigned char rBootMode, rRebootCmd;
++ NAND_IO_DEVID sDeviceCode;
++ NAND_IO_FEATURE *sTempFeatureInfo;
++ NAND_IO_FEATURE *sFindFeatureInfo;
++ NAND_IO_ERROR res;
++
++ bFindMedia = FALSE;
++
++ nDevInfo->ChipNo = nChipNo;
++ NAND_IO_LBA_DeviceReboot( nDevInfo );
++ NAND_IO_GetDeviceInfo( nChipNo, nDevInfo );
++
++ res = NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_BCM );
++ if ( res != SUCCESS )
++ {
++ NAND_IO_LBA_DeviceReboot( nDevInfo );
++ res = NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_BCM );
++ if ( res != SUCCESS )
++ return res;
++ }
++
++ NAND_IO_LBA_GetPersistentFunction( nDevInfo, &rBootMode, &rRebootCmd );
++
++ if ( ( rBootMode != 0x22 ) || ( rRebootCmd != 0xAF ))
++ {
++ rBootMode = 0x22;
++ rRebootCmd = 0xAF;
++
++ NAND_IO_LBA_SetBootModeChange( nDevInfo, rBootMode );
++ NAND_IO_LBA_SetRebootCmdChange( nDevInfo, rRebootCmd );
++ NAND_IO_LBA_DeviceReboot( nDevInfo );
++ }
++
++ NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_MDP );
++ NAND_IO_LBA_SetTransferProtocol( nDevInfo, NAND_PROT1_512x1, 0x00 );
++ NAND_IO_LBA_GetTransferProtocol( nDevInfo, &nDevInfo->LBAInfo.TransProtocol1, &nDevInfo->LBAInfo.TransProtocol2 );
++
++ if ( nDevInfo->LBAInfo.TransProtocol1 & NAND_PROT1_SPARE_INCLUDE )
++ nDevInfo->LBAInfo.DataTransferCheck = ENABLE;
++ else
++ nDevInfo->LBAInfo.DataTransferCheck = DISABLE;
++
++ nDevInfo->LBAInfo.SectorCount = ( nDevInfo->LBAInfo.TransProtocol1 & NAND_PROT1_SECTOR_COUNT_MASK );
++
++ if ( nDevInfo->LBAInfo.SectorCount != 1 )
++ nDevInfo->LBAInfo.SectorCount = nDevInfo->LBAInfo.SectorCount << 1;
++
++ nDevInfo->LBAInfo.Usable = DISABLE;
++ //=====================================================================
++ // Search Matched NANDFLASH
++ //=====================================================================
++ for ( j = 0; j < 3; ++j ) /* Check Read ID during 3 turn */
++ {
++ /* Read Device CODE */
++ NAND_IO_LBA_ReadID( nDevInfo, &sDeviceCode);
++
++ /* Check Maker ID */
++ bFindMakerNo = 0xFF;
++ for ( k = 0; k < MAX_SUPPORT_MAKER_LBA_NAND; ++k )
++ {
++ if ( sDeviceCode.Code[0] == LBA_NAND_SupportMakerInfo.MakerID[k] )
++ {
++ bFindMakerNo = (unsigned char)k;
++ sTempFeatureInfo = (NAND_IO_FEATURE*)LBA_NAND_SupportMakerInfo.DevInfo[k];
++ break;
++ }
++ }
++
++ if ( bFindMakerNo >= MAX_SUPPORT_MAKER_NAND )
++ continue;
++
++ /* Check Device ID */
++ for ( k = 0; k < LBA_NAND_SupportMakerInfo.MaxSupportNAND[bFindMakerNo]; ++k )
++ {
++ bMatchCount = 0;
++
++ for ( l = 0; l < 4; ++l )
++ {
++ if ( sTempFeatureInfo->DeviceID.Code[l+1] == 0x00 )
++ ++bMatchCount;
++ else if ( sDeviceCode.Code[l+1] == sTempFeatureInfo->DeviceID.Code[l+1] )
++ ++bMatchCount;
++ }
++
++ /* Found NAND Device */
++ if ( bMatchCount >= 4 )
++ {
++ bFindMedia = TRUE;
++ sFindFeatureInfo = sTempFeatureInfo;
++ break;
++ }
++ else
++ ++sTempFeatureInfo;
++ }
++
++ /* Found NAND Device */
++ if ( bFindMedia == TRUE )
++ break;
++ }
++
++ if ( bFindMedia == TRUE )
++ {
++ // Get UniqueID
++ //NAND_IO_LBA_ReadUID( nDevInfo );
++
++ NAND_IO_LBA_SetTransferProtocol( nDevInfo, NAND_PROT1_512x8, ( NAND_PROT2_WRITE_TYPE_B | NAND_PROT2_READ_TYPE_A ) );
++ NAND_IO_LBA_GetTransferProtocol( nDevInfo, &nDevInfo->LBAInfo.TransProtocol1, &nDevInfo->LBAInfo.TransProtocol2 );
++
++ // Data Format
++ if ( nDevInfo->LBAInfo.TransProtocol1 & NAND_PROT1_SPARE_INCLUDE )
++ nDevInfo->LBAInfo.DataTransferCheck = ENABLE;
++ else
++ nDevInfo->LBAInfo.DataTransferCheck = DISABLE;
++
++ // Sector Count
++ nDevInfo->LBAInfo.SectorCount = ( nDevInfo->LBAInfo.TransProtocol1 & NAND_PROT1_SECTOR_COUNT_MASK );
++
++ if ( nDevInfo->LBAInfo.SectorCount != 1 )
++ nDevInfo->LBAInfo.SectorCount = nDevInfo->LBAInfo.SectorCount << 1;
++
++ NAND_IO_LBA_VFPGetTotalSectorSize( nDevInfo, &nDevInfo->LBAInfo.VFPSectorSize );
++ if ( ( nDevInfo->LBAInfo.VFPSectorSize << 9 ) < gMAX_ROMSIZE )
++ {
++ // LBA Factory Setting values : 8 Mbyte
++ res = NAND_IO_LBA_VFPChangeSectorSize( nDevInfo, gMAX_ROMSIZE >> 9 );
++ if ( res != SUCCESS )
++ return res;
++
++ NAND_IO_LBA_VFPGetTotalSectorSize( nDevInfo, (U32 *)&nDevInfo->LBAInfo.VFPSectorSize );
++ }
++
++ // Get Size Info
++ NAND_IO_LBA_MDPGetTotalSectorSize( nDevInfo, (unsigned long int *)&nDevInfo->LBAInfo.MDPSectorSize );
++
++ res = NAND_IO_LBA_VFPInitArea( nDevInfo );
++ if ( res != SUCCESS )
++ return res;
++
++ nDevInfo->LBAInfo.Usable = ENABLE;
++
++ NAND_IO_LBA_SetAreaPartition( nDevInfo, sFindFeatureInfo );
++ NAND_IO_LBA_PowerSaveMode( nDevInfo, ENABLE );
++ }
++ //=====================================================================
++ // Not Found
++ //=====================================================================
++ else
++ {
++ return ERR_NAND_IO_FAILED_GET_DEVICE_INFO;
++ }
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_InitDrive( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int i;
++
++ gLBACSNums = 0;
++
++ for( i = NAND_IO_DRV0_START_CS; i < NAND_IO_DRV0_END_CS + 1; ++i )
++ {
++ if ( NAND_IO_LBA_Init( i, &nDevInfo[i] ) == SUCCESS )
++ {
++ ++gLBACSNums;
++ NAND_IO_LBA_PowerSaveMode( &nDevInfo[i], DISABLE );
++ NAND_IO_LBA_HighSpeedMode( &nDevInfo[i], ENABLE );
++ }
++ else
++ {
++ if ( i == 0 )
++ return ERR_LBA_NOT_EXIST_NANDFLASH;
++ }
++ }
++
++ if ( gLBACSNums > LBA_MAX_SUPPORT_MULTI_NANDFLASH )
++ return ERR_LBA_NOT_EXIST_MEDIA_NUM_INFO;
++
++ return SUCCESS;
++}
++
++U32 NAND_IO_LBA_GetSerialNumber( NAND_IO_DEVINFO *nDevInfo, U8* nPageBuffer, U8* rSerialNumber, U16 nSize )
++{
++ unsigned int i;
++ unsigned short int wSizeOfSID;
++ unsigned char ucPage[512];
++ unsigned char *cPageBuffer;
++ unsigned char *cSpareBuffer;
++
++ NAND_IO_ERROR res;
++
++ cPageBuffer = &nPageBuffer[0];
++ cSpareBuffer = &nPageBuffer[nDevInfo->Feature.PageSize];
++
++ res = NAND_IO_LBA_ModeChange( &nDevInfo[0], NAND_LBA_BCM );
++ if ( res != SUCCESS )
++ {
++ NAND_IO_LBA_DeviceReboot( nDevInfo );
++ res = NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_BCM );
++ if ( res != SUCCESS )
++ return res;
++ }
++
++ res = NAND_IO_ReadPage( nDevInfo, 0, 0, 4, cPageBuffer, cSpareBuffer, ECC_OFF );
++ if ( res != SUCCESS)
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ if ( nDevInfo[0].Feature.MediaType & A_PARALLEL )
++ memcpy( ucPage, &cPageBuffer[ ( 512 + 16 ) * ( nDevInfo[0].PPages - 2 ) ], 512 );
++ else
++ memcpy( ucPage, &cPageBuffer[ ( 512 + 16 ) * ( nDevInfo[0].PPages - 1 ) ], 512 );
++
++ //=====================================================
++ // Check and Get Serial Number ID
++ //=====================================================
++ /* Get Signature to get sizes of serial number ID */
++ if (!memcmp( &ucPage[20], "ZERO", 4 ))
++ wSizeOfSID = 16;
++ else if ((!memcmp( &ucPage[20], "FWDN", 4 )) || (!memcmp( &ucPage[20], "GANG", 4 )))
++ wSizeOfSID = 32;
++ else
++ wSizeOfSID = 0;
++
++ for ( i = 0; i < ( wSizeOfSID >> 4 ); ++i )
++ memcpy( &rSerialNumber[i*16], &ucPage[i*32], 16 );
++
++ return wSizeOfSID;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_GetTotalSecAndCHS( NAND_IO_DEVINFO *nDevInfo, int nPartition, U32 *rTotalSec, U16 *rCylinder, U16 *rHead, U8 *rSector )
++{
++ unsigned short int i;
++ unsigned short int wCurrHead;
++ unsigned short int wCurrCylinder;
++ unsigned long int nTotalSectorSize;
++
++ nTotalSectorSize = 0;
++
++ if ( nPartition == NAND_LBA_DATA_AREA )
++ {
++ for ( i = 0; i < gLBACSNums; ++i )
++ nTotalSectorSize += nDevInfo[i].LBAInfo.DTAreaSectorSize;
++ }
++ else if ( nPartition == NAND_LBA_HIDDEN_AREA )
++ {
++ for ( i = 0; i < gLBACSNums; ++i )
++ nTotalSectorSize += nDevInfo[i].LBAInfo.HDAreaSectorSize;
++ }
++ else if ( nPartition == NAND_LBA_MULTI_HIDDEN_AREA_0 )
++ {
++ nTotalSectorSize = nDevInfo[0].LBAInfo.MHDAreaSectorSize[0];
++ }
++ else if ( nPartition == NAND_LBA_MDP )
++ {
++ for ( i = 0; i < gLBACSNums; ++i )
++ nTotalSectorSize += nDevInfo[i].LBAInfo.MDPSectorSize;
++ }
++ else if ( nPartition == NAND_LBA_VFP )
++ {
++ for ( i = 0; i < gLBACSNums; ++i )
++ nTotalSectorSize += nDevInfo[i].LBAInfo.VFPSectorSize;
++ }
++
++ if ( nTotalSectorSize == 0 )
++ {
++ *rTotalSec = 0;
++ *rCylinder = 0;
++ *rHead = 0;
++ *rSector = 0;
++
++ return (NAND_IO_ERROR)SUCCESS;
++ }
++
++ if ( nTotalSectorSize >= (U32)( 1024 * 256 * 64 ) )
++ {
++ *rTotalSec = nTotalSectorSize;
++ *rCylinder = (U16)(nTotalSectorSize / ( 256 * 64 ));
++ *rHead = 256;
++ *rSector = 64;
++ }
++ else
++ {
++ for ( wCurrHead = 2; wCurrHead <= 256; wCurrHead *= 2 )
++ {
++ wCurrCylinder = (U16)(nTotalSectorSize / ( wCurrHead * 64 ));
++
++ if ( wCurrCylinder > 1024 )
++ continue;
++
++ *rTotalSec = (U32)( wCurrCylinder * wCurrHead * 64 );
++ *rCylinder = wCurrCylinder;
++ *rHead = wCurrHead;
++ *rSector = 64;
++
++ break;
++ }
++ }
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_ReadSectorBy4Byte( NAND_IO_DEVINFO *nDevInfo, U8 nPartition, U32 nSectorAddr, U16 nOffset, U16 nReadSize, U8 *nReadBuffer )
++{
++ unsigned short int wCSorder;
++ unsigned short int wCurrPPSize, rConvertSize;
++ unsigned short int wFlagFirstSector;
++ unsigned long int dwSectorAddr, rConvertAddr;
++ unsigned long int dwTotalReadSecSize;
++ unsigned char cReadBuffer[512];
++ unsigned char cSpareBuffer[16];
++ unsigned char *pReadBuffer;
++ unsigned char cPartition;
++ NAND_IO_ERROR res;
++
++ //######################################################
++ //# Get Info of Parameter
++ //######################################################
++ dwSectorAddr = nSectorAddr;
++ dwTotalReadSecSize = 1;
++
++ res = NAND_IO_LBA_ConvertMPPA( nDevInfo, nPartition, dwSectorAddr, dwTotalReadSecSize, &rConvertAddr, &rConvertSize, &wCSorder );
++ if ( res != SUCCESS )
++ return res;
++
++ cPartition = nPartition & 0x0F;
++
++ if ( nDevInfo[wCSorder].LBAInfo.CurrentMode != cPartition )
++ NAND_IO_LBA_ModeChange( &nDevInfo[wCSorder], cPartition );
++
++ if (( !nReadSize ) || (( nOffset + nReadSize ) > 128 ))
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //######################################################
++ //# Set High Speed Mode
++ //######################################################
++ NAND_IO_LBA_PowerSaveMode( &nDevInfo[wCSorder], DISABLE );
++ NAND_IO_LBA_HighSpeedMode( &nDevInfo[wCSorder], ENABLE );
++
++ pReadBuffer = nReadBuffer;
++
++ wFlagFirstSector = TRUE;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetCommCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo[wCSorder].ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo[wCSorder].Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( dwTotalReadSecSize < nDevInfo[wCSorder].LBAInfo.SectorCount )
++ wCurrPPSize = dwTotalReadSecSize;
++ else
++ wCurrPPSize = nDevInfo[wCSorder].LBAInfo.SectorCount;
++
++ //######################################################
++ //# Write Total Sector
++ //######################################################
++ pNFC->NFC_CMD = nDevInfo[wCSorder].CmdMask & 0x0000;
++
++ if ( wFlagFirstSector == TRUE )
++ {
++ /* Write Sector Size & Sector Address */
++ pNFC->NFC_SADDR= ( ( wCurrPPSize ) & 0xFF ); // Write Sector Num : SC0
++ pNFC->NFC_SADDR= ( ( wCurrPPSize >> 8 ) & 0xFF ); // Write Sector Num : SC1
++ pNFC->NFC_SADDR= ( ( rConvertAddr ) & 0xFF ); // Write Sector Addr: AD0
++ pNFC->NFC_SADDR= ( ( rConvertAddr >> 8 ) & 0xFF ); // Write Sector Addr: AD1
++ pNFC->NFC_SADDR= ( ( rConvertAddr >> 16 ) & 0xFF ); // Write Sector Addr: AD2
++ pNFC->NFC_SADDR= ( ( rConvertAddr >> 24 ) & 0xFF ); // Write Sector Addr: AD3
++ }
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo[wCSorder].CmdMask & 0x3030;
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo[wCSorder].ChipNo );
++
++ NAND_IO_SetReadCycleTime();
++ /* Write Data to NAND FLASH */
++ res = NAND_IO_LBA_ReadData( &nDevInfo[wCSorder], wCurrPPSize, cReadBuffer, cSpareBuffer );
++ if ( res != SUCCESS )
++ return res;
++
++ NAND_IO_SetCommCycleTime();
++
++ memcpy( pReadBuffer, &cReadBuffer[nOffset << 2], nReadSize << 2 );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ //######################################################
++ //# Set Power Save Mode
++ //######################################################
++ NAND_IO_LBA_PowerSaveMode( &nDevInfo[wCSorder], ENABLE );
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_ReadSector( NAND_IO_DEVINFO *nDevInfo, U8 nPartition, U32 nSectorAddr, U16 nSecSize, U8 *nReadBuffer )
++{
++ unsigned short int wCSorder;
++ unsigned short int wCurrPPSize, rConvertSize;
++ unsigned short int wFlagFirstSector;
++ unsigned long int dwSectorAddr, rConvertAddr;
++ unsigned long int dwTotalReadSecSize;
++ unsigned char cPartition;
++ unsigned char cSpareBuffer[16];
++ NAND_IO_ERROR res;
++
++ //######################################################
++ //# Get Info of Parameter
++ //######################################################
++ dwSectorAddr = nSectorAddr;
++ dwTotalReadSecSize = nSecSize;
++
++ while ( dwTotalReadSecSize )
++ {
++ res = NAND_IO_LBA_ConvertMPPA( nDevInfo, nPartition, dwSectorAddr, dwTotalReadSecSize, &rConvertAddr, &rConvertSize, &wCSorder );
++ if ( res != SUCCESS )
++ return res;
++
++ rConvertSize = dwTotalReadSecSize; // nemo
++
++ //######################################################
++ //# Check Parameter
++ //######################################################
++ if ( nDevInfo[wCSorder].LBAInfo.Usable != ENABLE )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ cPartition = nPartition & 0x0F;
++
++ if ( nDevInfo[wCSorder].LBAInfo.CurrentMode != cPartition )
++ {
++ res = NAND_IO_LBA_ModeChange( &nDevInfo[wCSorder], cPartition );
++ if ( res != SUCCESS )
++ {
++ NAND_IO_LBA_DeviceReboot( &nDevInfo[wCSorder]);
++ NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_MDP );
++ NAND_IO_LBA_SetTransferProtocol( &nDevInfo[wCSorder], NAND_PROT1_512x8, ( NAND_PROT2_WRITE_TYPE_B | NAND_PROT2_READ_TYPE_A ) );
++ res = NAND_IO_LBA_ModeChange( &nDevInfo[wCSorder], cPartition );
++ if ( res != SUCCESS )
++ return res;
++ }
++ }
++
++ //######################################################
++ //# Set High Speed Mode
++ //######################################################
++ //NAND_IO_LBA_PowerSaveMode( &nDevInfo[wCSorder], DISABLE );
++ //NAND_IO_LBA_HighSpeedMode( &nDevInfo[wCSorder], ENABLE );
++
++ wFlagFirstSector = TRUE;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetCommCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo[wCSorder].ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo[wCSorder].Feature.MediaType & A_PARALLEL )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( rConvertSize < nDevInfo[wCSorder].LBAInfo.SectorCount )
++ wCurrPPSize = rConvertSize;
++ else
++ wCurrPPSize = nDevInfo[wCSorder].LBAInfo.SectorCount;
++
++ /* Decrease Write Size */
++ dwSectorAddr += rConvertSize;
++ dwTotalReadSecSize -= rConvertSize;
++
++ //######################################################
++ //# Write Total Sector
++ //######################################################
++ while ( rConvertSize )
++ {
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo[wCSorder].CmdMask & 0x0000;
++
++ if ( wFlagFirstSector == TRUE )
++ {
++ /* Write Sector Size & Sector Address */
++ pNFC->NFC_SADDR= ( ( rConvertSize ) & 0xFF ); // Write Sector Num : SC0
++ pNFC->NFC_SADDR= ( ( rConvertSize >> 8 ) & 0xFF ); // Write Sector Num : SC1
++ pNFC->NFC_SADDR= ( ( rConvertAddr ) & 0xFF ); // Write Sector Addr: AD0
++ pNFC->NFC_SADDR= ( ( rConvertAddr >> 8 ) & 0xFF ); // Write Sector Addr: AD1
++ pNFC->NFC_SADDR= ( ( rConvertAddr >> 16 ) & 0xFF ); // Write Sector Addr: AD2
++ pNFC->NFC_SADDR= ( ( rConvertAddr >> 24 ) & 0xFF ); // Write Sector Addr: AD3
++
++ if ( nDevInfo[wCSorder].LBAInfo.TransProtocol2 & NAND_PROT2_READ_TYPE_B )
++ wFlagFirstSector = FALSE;
++ }
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo[wCSorder].CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_LBA_WaitBusy( nDevInfo[wCSorder].ChipNo );
++
++ NAND_IO_SetReadCycleTime();
++ /* Write Data to NAND FLASH */
++ res = NAND_IO_LBA_ReadData( &nDevInfo[wCSorder], wCurrPPSize, nReadBuffer, cSpareBuffer );
++ if ( res != SUCCESS )
++ return res;
++
++ NAND_IO_SetCommCycleTime();
++
++ rConvertAddr += wCurrPPSize;
++ rConvertSize -= wCurrPPSize;
++
++ /* Increase Buffer Address */
++ nReadBuffer += ( wCurrPPSize << 9 );
++
++ /* Count Next Page Size */
++ if ( rConvertSize < nDevInfo[wCSorder].LBAInfo.SectorCount )
++ wCurrPPSize = rConvertSize;
++ else
++ wCurrPPSize = nDevInfo[wCSorder].LBAInfo.SectorCount;
++ }
++
++ pNFC->NFC_CMD = nDevInfo[wCSorder].CmdMask & 0xFBFB;
++ NAND_IO_WaitBusy( nDevInfo[wCSorder].ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ //######################################################
++ //# Set Power Save Mode
++ //######################################################
++ //NAND_IO_LBA_PowerSaveMode( &nDevInfo[wCSorder], ENABLE );
++ }
++
++ return SUCCESS;
++}
++
++
++NAND_IO_ERROR NAND_IO_LBA_AREAClear( NAND_IO_DEVINFO *nDevInfo, U8 nPartition )
++{
++ unsigned short int i;
++ unsigned int nSectorAddr;
++ unsigned short int wCurrPPSize;
++ unsigned short int wFlagFirstSector;
++
++ unsigned short int wOldProcessRate;
++ unsigned short int wProcessRate;
++ unsigned long int nProCessWriteSectorSize;
++
++ unsigned long int dwSectorAddr;
++ unsigned long int dwSectorAddrOffSet;
++ unsigned short int wOnceWriteSectorCount;
++ unsigned long int dwTotalWriteSecSize;
++ unsigned long int nTotalSectorSize;
++ unsigned long int nWriteSectorSize;
++ unsigned char cPartition;
++ NAND_IO_ERROR res;
++
++ for ( i = 0; i < gLBACSNums; ++i )
++ {
++ NAND_IO_LBA_Init( i, &nDevInfo[i] );
++
++ //######################################################
++ //# Check Parameter
++ //######################################################
++ if ( nDevInfo[i].LBAInfo.Usable != ENABLE )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ cPartition = nPartition & 0x0F;
++
++ if ( nDevInfo[i].LBAInfo.CurrentMode != cPartition )
++ NAND_IO_LBA_ModeChange( &nDevInfo[i], cPartition );
++
++ //######################################################
++ //# Set High Speed Mode
++ //######################################################
++ NAND_IO_LBA_PowerSaveMode( &nDevInfo[i], DISABLE );
++ NAND_IO_LBA_HighSpeedMode( &nDevInfo[i], ENABLE );
++
++ if ( nPartition == NAND_LBA_DATA_AREA )
++ {
++ nTotalSectorSize = nDevInfo[i].LBAInfo.DTAreaSectorSize;
++ dwSectorAddrOffSet = nDevInfo[i].LBAInfo.DTAreaAddrOffSet;
++ }
++ else if ( nPartition == NAND_LBA_HIDDEN_AREA )
++ {
++ nTotalSectorSize = nDevInfo[i].LBAInfo.HDAreaSectorSize;
++ dwSectorAddrOffSet = nDevInfo[i].LBAInfo.HDAreaAddrOffSet;
++ }
++ else if ( nPartition == NAND_LBA_MULTI_HIDDEN_AREA_0 )
++ {
++ nTotalSectorSize = nDevInfo[i].LBAInfo.MHDAreaSectorSize[0];
++ dwSectorAddrOffSet = nDevInfo[i].LBAInfo.MHDAreaAddrOffSet[0];
++ }
++ else if ( nPartition == NAND_LBA_MDP )
++ {
++ nTotalSectorSize = nDevInfo[i].LBAInfo.MDPSectorSize;
++ dwSectorAddrOffSet = 0;
++ }
++ else if ( nPartition == NAND_LBA_VFP )
++ {
++ nTotalSectorSize = nDevInfo[i].LBAInfo.VFPSectorSize;
++ dwSectorAddrOffSet = NAND_LBA_SYS_SECTION;
++ }
++
++ // Set Area Clear Sector Address, Size
++ nSectorAddr = 0;
++
++ wFlagFirstSector = TRUE;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetCommCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo[i].ChipNo );
++
++ //NAND_IO_DisableWriteProtect();
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo[i].Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //######################################################
++ //# Get Info of Parameter
++ //######################################################
++ dwSectorAddr = nSectorAddr;
++ dwSectorAddr += dwSectorAddrOffSet;
++ dwTotalWriteSecSize = nTotalSectorSize;
++
++ if ( dwTotalWriteSecSize < nDevInfo[i].LBAInfo.SectorCount )
++ wCurrPPSize = (U16)dwTotalWriteSecSize;
++ else
++ wCurrPPSize = nDevInfo[i].LBAInfo.SectorCount;
++
++ //######################################################
++ //# Write Total Sector
++ //######################################################
++ wOldProcessRate = 0xFFFF;
++ nWriteSectorSize = 0;
++ nProCessWriteSectorSize = 0;
++ // [ LCD ROUTINE ] ---------------------------------------------------------------------------------------
++ if ( NAND_IO_LBA_CallBackLcdDisplay )
++ NAND_IO_LBA_CallBackLcdDisplay( 0, 0x03, nTotalSectorSize );
++ //--------------------------------------------------------------------------------------------------------
++
++ if ( dwTotalWriteSecSize >= 0x10000 )
++ wOnceWriteSectorCount = 0; // 0x10000
++ else
++ wOnceWriteSectorCount = (U16)dwTotalWriteSecSize;
++
++ while ( dwTotalWriteSecSize )
++ {
++ if ( nWriteSectorSize == 0x10000 )
++ {
++ if ( dwTotalWriteSecSize >= 0x10000 )
++ wOnceWriteSectorCount = 0;
++ else
++ wOnceWriteSectorCount = (U16)dwTotalWriteSecSize;
++
++ nWriteSectorSize = 0;
++ wFlagFirstSector = TRUE;
++ }
++
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo[i].CmdMask & 0x8080;
++
++ if ( wFlagFirstSector == TRUE )
++ {
++ /* Write Sector Size & Sector Address */
++ pNFC->NFC_SADDR= ( wOnceWriteSectorCount & 0xFF ); // Write Sector Num : SC0
++ pNFC->NFC_SADDR= ( ( wOnceWriteSectorCount >> 8 ) & 0xFF ); // Write Sector Num : SC1
++ pNFC->NFC_SADDR= ( dwSectorAddr & 0xFF ); // Write Sector Addr: AD0
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 8 ) & 0xFF ); // Write Sector Addr: AD1
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 16 ) & 0xFF ); // Write Sector Addr: AD2
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 24 ) & 0xFF ); // Write Sector Addr: AD2
++ }
++
++ NAND_IO_SetWriteCycleTime();
++ /* Write Data to NAND FLASH */
++
++ res = NAND_IO_LBA_WriteDummyData( &nDevInfo[i], wCurrPPSize );
++ if ( res != SUCCESS )
++ return res;
++
++ NAND_IO_SetCommCycleTime();
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo[i].CmdMask & 0x1010;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo[i].ChipNo );
++
++ /* Decrease Write Size */
++ dwTotalWriteSecSize -= wCurrPPSize;
++
++ /* Increase Buffer Address */
++ //nWriteBuffer += ( nDevInfo->LBAInfo.SectorCount << 9 );
++ dwSectorAddr += wCurrPPSize;
++ nWriteSectorSize += wCurrPPSize;
++
++ /* Count Next Page Size */
++ if ( dwTotalWriteSecSize < nDevInfo[i].LBAInfo.SectorCount )
++ wCurrPPSize = (U16)dwTotalWriteSecSize;
++ else
++ wCurrPPSize = nDevInfo[i].LBAInfo.SectorCount;
++
++ if ( nDevInfo[i].LBAInfo.TransProtocol2 & NAND_PROT2_WRITE_TYPE_B )
++ wFlagFirstSector = FALSE;
++
++ wProcessRate = (U16)(( ( nProCessWriteSectorSize + 1 ) * 100 ) / ( nTotalSectorSize + 1 ));
++
++ if ( wOldProcessRate != wProcessRate )
++ {
++ // [ LCD ROUTINE ] ---------------------------------------------------------------------------------------
++ if ( NAND_IO_LBA_CallBackLcdDisplay )
++ NAND_IO_LBA_CallBackLcdDisplay( 0, NAND_LBA_CALLBACK_LCD_FORMAT_PROCESS, wProcessRate );
++ //--------------------------------------------------------------------------------------------------------
++
++ wOldProcessRate = wProcessRate;
++ }
++
++ nProCessWriteSectorSize += wCurrPPSize;
++ }
++
++ // [ LCD ROUTINE ] ---------------------------------------------------------------------------------------
++ if ( NAND_IO_LBA_CallBackLcdDisplay )
++ NAND_IO_LBA_CallBackLcdDisplay( 0, 0x05, 0 );
++ //--------------------------------------------------------------------------------------------------------
++
++ pNFC->NFC_CMD = nDevInfo[i].CmdMask & 0xFBFB;
++ NAND_IO_WaitBusy( nDevInfo[i].ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ /* Cache Flush */
++ NAND_IO_LBA_CacheFlush( &nDevInfo[i] );
++
++ //######################################################
++ //# Set Power Save Mode
++ //######################################################
++ NAND_IO_LBA_PowerSaveMode( &nDevInfo[i], ENABLE );
++ }
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_WriteSector( NAND_IO_DEVINFO *nDevInfo, U8 nPartition, U32 nSectorAddr, U16 nSecSize, U8 *nWriteBuffer )
++{
++ unsigned short int wCSorder;
++ unsigned short int wCurrPPSize;
++ unsigned short int wFlagFirstSector;
++ unsigned long int dwSectorAddr, rConvertAddr;
++ unsigned long int dwTotalWriteSecSize, rConvertSize;
++ unsigned char cPartition;
++ unsigned char cSpareBuffer[16];
++ NAND_IO_ERROR res;
++
++ //######################################################
++ //# Get Info of Parameter
++ //######################################################
++ dwSectorAddr = nSectorAddr;
++ dwTotalWriteSecSize = nSecSize;
++
++ while ( dwTotalWriteSecSize )
++ {
++ res = NAND_IO_LBA_ConvertMPPA( nDevInfo, nPartition, dwSectorAddr, dwTotalWriteSecSize, &rConvertAddr, &rConvertSize, &wCSorder );
++ if ( res != SUCCESS )
++ return res;
++
++ //######################################################
++ //# Check Parameter
++ //######################################################
++ if ( nDevInfo[wCSorder].LBAInfo.Usable != ENABLE )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ cPartition = nPartition & 0x0F;
++
++ if ( nDevInfo[wCSorder].LBAInfo.CurrentMode != cPartition )
++ {
++ res = NAND_IO_LBA_ModeChange( &nDevInfo[wCSorder], cPartition );
++ if ( res != SUCCESS )
++ {
++ NAND_IO_LBA_DeviceReboot( &nDevInfo[wCSorder]);
++ NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_MDP );
++ NAND_IO_LBA_SetTransferProtocol( &nDevInfo[wCSorder], NAND_PROT1_512x8, ( NAND_PROT2_WRITE_TYPE_B | NAND_PROT2_READ_TYPE_A ) );
++ res = NAND_IO_LBA_ModeChange( &nDevInfo[wCSorder], cPartition );
++ if ( res != SUCCESS )
++ return res;
++ }
++ }
++
++ //######################################################
++ //# Set High Speed Mode
++ //######################################################
++ NAND_IO_LBA_PowerSaveMode( &nDevInfo[wCSorder], DISABLE );
++ NAND_IO_LBA_HighSpeedMode( &nDevInfo[wCSorder], ENABLE );
++
++ wFlagFirstSector = TRUE;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetCommCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo[wCSorder].ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo[wCSorder].Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( rConvertSize < nDevInfo[wCSorder].LBAInfo.SectorCount )
++ wCurrPPSize = rConvertSize;
++ else
++ wCurrPPSize = nDevInfo[wCSorder].LBAInfo.SectorCount;
++
++ /* Decrease Write Size */
++ dwSectorAddr += rConvertSize;
++ dwTotalWriteSecSize -= rConvertSize;
++
++ //######################################################
++ //# Write Total Sector
++ //######################################################
++ while ( rConvertSize )
++ {
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo[wCSorder].CmdMask & 0x8080;
++
++ if ( wFlagFirstSector == TRUE )
++ {
++ /* Write Sector Size & Sector Address */
++ pNFC->NFC_SADDR= ( rConvertSize & 0xFF ); // Write Sector Num : SC0
++ pNFC->NFC_SADDR= ( ( rConvertSize >> 8 ) & 0xFF ); // Write Sector Num : SC1
++ pNFC->NFC_SADDR= ( rConvertAddr & 0xFF ); // Write Sector Addr: AD0
++ pNFC->NFC_SADDR= ( ( rConvertAddr >> 8 ) & 0xFF ); // Write Sector Addr: AD1
++ pNFC->NFC_SADDR= ( ( rConvertAddr >> 16 ) & 0xFF ); // Write Sector Addr: AD2
++ pNFC->NFC_SADDR= ( ( rConvertAddr >> 24 ) & 0xFF ); // Write Sector Addr: AD2
++
++ if ( nDevInfo[wCSorder].LBAInfo.TransProtocol2 & NAND_PROT2_WRITE_TYPE_B )
++ wFlagFirstSector = FALSE;
++ }
++
++ NAND_IO_SetWriteCycleTime();
++ /* Write Data to NAND FLASH */
++ res = NAND_IO_LBA_WriteData( &nDevInfo[wCSorder], wCurrPPSize, nWriteBuffer, cSpareBuffer );
++ if ( res != SUCCESS )
++ return res;
++
++ NAND_IO_SetCommCycleTime();
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo[wCSorder].CmdMask & 0x1010;
++
++ rConvertAddr += wCurrPPSize;
++ rConvertSize -= wCurrPPSize;
++
++ /* Increase Buffer Address */
++ nWriteBuffer += ( wCurrPPSize << 9 );
++
++ /* Count Next Page Size */
++ if ( rConvertSize < nDevInfo[wCSorder].LBAInfo.SectorCount )
++ wCurrPPSize = rConvertSize;
++ else
++ wCurrPPSize = nDevInfo[wCSorder].LBAInfo.SectorCount;
++
++ /* Wait until it is ready */
++ NAND_IO_LBA_WaitBusy( nDevInfo[wCSorder].ChipNo );
++ }
++
++ pNFC->NFC_CMD = nDevInfo[wCSorder].CmdMask & 0xFBFB;
++ NAND_IO_WaitBusy( nDevInfo[wCSorder].ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ //######################################################
++ //# Set Power Save Mode
++ //######################################################
++ //NAND_IO_LBA_PowerSaveMode( &nDevInfo[wCSorder], ENABLE );
++ }
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_VFPInitArea( NAND_IO_DEVINFO *nDevInfo )
++{
++ NAND_IO_ERROR res;
++
++ res = NAND_IO_LBA_ScanHeaderOfVFP( nDevInfo );
++ if ( res != SUCCESS )
++ {
++ res = NAND_IO_LBA_MakeHeaderOfVFP( nDevInfo );
++ if ( res != SUCCESS )
++ return res;
++
++ res = NAND_IO_LBA_ScanHeaderOfVFP( nDevInfo );
++ if ( res != SUCCESS )
++ return res;
++ }
++
++ return res;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_ScanHeaderOfVFP( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int i;
++ unsigned short int wCurrPPSize;
++ unsigned short int wFlagCheckSize;
++ unsigned short int wFlagFirstSector;
++ unsigned long int nHeaderInfoSize;
++ unsigned long int nHeaderAddress;
++ unsigned long int dwSectorAddr;
++ unsigned long int nTotalSectorSize;
++ unsigned short int nInfoOffSet;
++ unsigned int *pPageDW;
++ unsigned char cPageBuffer[512];
++ unsigned char cSpareBuffer[16];
++ unsigned long int dwTotalSectorSize;
++ NAND_IO_ERROR res;
++
++ //######################################################
++ //# Check Parameter
++ //######################################################
++ NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_VFP );
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetCommCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_DisableWriteProtect();
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ wFlagFirstSector = TRUE;
++ nInfoOffSet = 32;
++ nHeaderInfoSize = 1;
++ nHeaderAddress = 0;
++
++ //######################################################
++ //# Get Info of Parameter
++ //######################################################
++ dwSectorAddr = nHeaderAddress;
++ nTotalSectorSize = nHeaderInfoSize;
++
++ if ( nTotalSectorSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)nTotalSectorSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount ;
++
++ //######################################################
++ //# Write Total Sector
++ //######################################################
++ while ( nTotalSectorSize )
++ {
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ if ( wFlagFirstSector == TRUE )
++ {
++ /* Write Sector Size & Sector Address */
++ pNFC->NFC_SADDR= ( nHeaderInfoSize & 0xFF ); // Write Sector Num : SC0
++ pNFC->NFC_SADDR= ( ( nHeaderInfoSize >> 8 ) & 0xFF ); // Write Sector Num : SC1
++ pNFC->NFC_SADDR= ( dwSectorAddr & 0xFF ); // Write Sector Addr: AD0
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 8 ) & 0xFF ); // Write Sector Addr: AD1
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 16 ) & 0xFF ); // Write Sector Addr: AD2
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 24 ) & 0xFF ); // Write Sector Addr: AD2
++ }
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ NAND_IO_SetReadCycleTime();
++ /* Write Data to NAND FLASH */
++ res = NAND_IO_LBA_ReadData_VFP( nDevInfo, wCurrPPSize, cPageBuffer, cSpareBuffer );
++ if ( res != SUCCESS )
++ return res;
++
++ NAND_IO_SetCommCycleTime();
++
++ /* Decrease Write Size */
++ nTotalSectorSize -= wCurrPPSize;
++
++ /* Increase Buffer Address */
++ //cPageBuffer += ( nDevInfo->LBAInfo.SectorCount << 9 );
++
++ /* Count Next Page Size */
++ if ( nTotalSectorSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)nTotalSectorSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount;
++
++ if ( nDevInfo->LBAInfo.TransProtocol2 & NAND_PROT2_WRITE_TYPE_B )
++ wFlagFirstSector = FALSE;
++ }
++
++ /* FORCE TO SET WP LOW */
++ NAND_IO_EnableWriteProtect();
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ wFlagCheckSize = FALSE;
++
++ // Signature
++ if ( !memcmp( cPageBuffer, (void *)NAND_LBA_VFP_AREA_Signature, sizeof(NAND_LBA_VFP_AREA_Signature) ) )
++ {
++ pPageDW = (U32 *)&cPageBuffer[nInfoOffSet];
++ //==============================================
++ // VFP Size [ 4Byte ] 0
++ // MDP Size [ 4Byte ] 1
++ // Hidden Size [ 4Byte ] 2
++ // Multi-Hidden Num [ 4Byte ] 3
++ // Multi-Hidden Size[ 4Byte ] 4~10
++ //==============================================
++ dwTotalSectorSize = 0;
++
++ if ( nDevInfo->LBAInfo.VFPSectorSize == pPageDW[ENUM_LBA_VFP_SECTOR_SIZE] )
++ {
++ if ( nDevInfo->LBAInfo.FlagOfChangeTotalSectorSize == ENABLE )
++ {
++ if ( ( nDevInfo->LBAInfo.MDPSectorSize == pPageDW[ENUM_LBA_MDP_SECTOR_SIZE] ) &&
++ ( nDevInfo->LBAInfo.HDAreaSectorSize == pPageDW[ENUM_LBA_HIDDEN_SECTOR_SIZE] ) &&
++ ( nDevInfo->LBAInfo.MHDAreaNums == pPageDW[ENUM_LBA_MULTI_HIDDEN_NUM] ) )
++ {
++ wFlagCheckSize = TRUE;
++
++ if ( nDevInfo->LBAInfo.MHDAreaNums > NAND_LBA_MAX_SUPPORT_MHD_AREA_NUM )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ for ( i = 0; i < nDevInfo->LBAInfo.MHDAreaNums; ++i )
++ {
++ if ( nDevInfo->LBAInfo.MHDAreaSectorSize[i] != pPageDW[ENUM_LBA_MULTI_HIDDEN_SIZE_0 + i] )
++ wFlagCheckSize = FALSE;
++ }
++ }
++ else
++ wFlagCheckSize = FALSE;
++ }
++ else // NAND VFP Info Read Only
++ {
++ nDevInfo->LBAInfo.HDAreaSectorSize = pPageDW[ENUM_LBA_HIDDEN_SECTOR_SIZE];
++ nDevInfo->LBAInfo.MHDAreaNums = pPageDW[ENUM_LBA_MULTI_HIDDEN_NUM];
++
++ if ( nDevInfo->LBAInfo.MHDAreaNums > NAND_LBA_MAX_SUPPORT_MHD_AREA_NUM )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ for ( i = 0; i < nDevInfo->LBAInfo.MHDAreaNums; ++i )
++ nDevInfo->LBAInfo.MHDAreaSectorSize[i] = pPageDW[ENUM_LBA_MULTI_HIDDEN_SIZE_0 + i];
++
++ wFlagCheckSize = TRUE;
++ }
++ }
++ else
++ {
++ NAND_IO_LBA_VFPChangeSectorSize( nDevInfo, nDevInfo->LBAInfo.VFPSectorSize );
++ }
++ }
++
++ dwTotalSectorSize = nDevInfo->LBAInfo.HDAreaSectorSize;
++ for ( i = 0; i < nDevInfo->LBAInfo.MHDAreaNums; ++i )
++ dwTotalSectorSize += nDevInfo->LBAInfo.MHDAreaSectorSize[i];
++
++ if ( dwTotalSectorSize > nDevInfo->LBAInfo.MDPSectorSize )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ if ( wFlagCheckSize == FALSE )
++ return ERR_NAND_IO_NOT_EXIST_LBA_HEADBLOCK;
++
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_MakeHeaderOfVFP( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int i;
++ unsigned short int wCurrPPSize;
++ unsigned short int wFlagFirstSector;
++ unsigned long int nHeaderInfoSize;
++ unsigned long int nHeaderAddress;
++ unsigned long int dwSectorAddr;
++ unsigned long int nTotalSectorSize;
++ unsigned short int nInfoOffSet;
++ unsigned int *pPageDW;
++ unsigned char cPageBuffer[512];
++ unsigned char cSpareBuffer[16];
++ NAND_IO_ERROR res;
++
++ //######################################################
++ //# Check Parameter
++ //######################################################
++ NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_VFP );
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetCommCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ NAND_IO_DisableWriteProtect();
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++ wFlagFirstSector = TRUE;
++ nInfoOffSet = 32;
++ nHeaderInfoSize = 1;
++ nHeaderAddress = 0;
++
++ //==============================================
++ // Hidden Signature [ 32Byte ]
++ // VFP Size [ 4Byte ] 0
++ // MDP Size [ 4Byte ] 1
++ // Hidden Size [ 4Byte ] 2
++ // Multi-Hidden Num [ 4Byte ] 3
++ // Multi-Hidden Size[ 4Byte ] 4~10
++ //==============================================
++
++ // Page Clear
++ memset( (void*)cPageBuffer, 0xFF, 512 );
++
++ // Signature
++ memcpy( (void*)cPageBuffer, (void*)NAND_LBA_VFP_AREA_Signature, sizeof(NAND_LBA_VFP_AREA_Signature) );
++
++ pPageDW = (U32 *)&cPageBuffer[nInfoOffSet];
++
++ // VFP Size
++ pPageDW[ENUM_LBA_VFP_SECTOR_SIZE] = nDevInfo->LBAInfo.VFPSectorSize;
++
++ // MDP Size
++ pPageDW[ENUM_LBA_MDP_SECTOR_SIZE] = nDevInfo->LBAInfo.MDPSectorSize;
++
++ // Hidden Size
++ pPageDW[ENUM_LBA_HIDDEN_SECTOR_SIZE]= nDevInfo->LBAInfo.HDAreaSectorSize;
++
++ // Multi-Hidden Area Num
++ pPageDW[ENUM_LBA_MULTI_HIDDEN_NUM] = nDevInfo->LBAInfo.MHDAreaNums;
++
++ if ( nDevInfo->LBAInfo.MHDAreaNums > NAND_LBA_MAX_SUPPORT_MHD_AREA_NUM )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ // Multi-Hidden Area Size
++ for ( i = 0; i < nDevInfo->LBAInfo.MHDAreaNums; ++i )
++ pPageDW[ENUM_LBA_MULTI_HIDDEN_SIZE_0 + i] = nDevInfo->LBAInfo.MHDAreaSectorSize[i];
++
++ //######################################################
++ //# Get Info of Parameter
++ //######################################################
++ dwSectorAddr = nHeaderAddress;
++ nTotalSectorSize = nHeaderInfoSize;
++ wFlagFirstSector = TRUE;
++
++ if ( nTotalSectorSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)nTotalSectorSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount ;
++
++ while ( nTotalSectorSize )
++ {
++ /* Command Page Program #1 [ 0x80 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ if ( wFlagFirstSector == TRUE )
++ {
++ /* Write Sector Size & Sector Address */
++ pNFC->NFC_SADDR= ( nHeaderInfoSize & 0xFF ); // Write Sector Num : SC0
++ pNFC->NFC_SADDR= ( ( nHeaderInfoSize >> 8 ) & 0xFF ); // Write Sector Num : SC1
++ pNFC->NFC_SADDR= ( dwSectorAddr & 0xFF ); // Write Sector Addr: AD0
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 8 ) & 0xFF ); // Write Sector Addr: AD1
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 16 ) & 0xFF ); // Write Sector Addr: AD2
++ pNFC->NFC_SADDR= ( ( dwSectorAddr >> 24 ) & 0xFF ); // Write Sector Addr: AD2
++ }
++
++ NAND_IO_SetWriteCycleTime();
++ /* Write Data to NAND FLASH */
++ res = NAND_IO_LBA_WriteData( nDevInfo, wCurrPPSize, cPageBuffer, cSpareBuffer );
++ if ( res != SUCCESS )
++ return res;
++
++ NAND_IO_SetCommCycleTime();
++
++ /* Command Page Program #2 [ 0x10 ] */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++
++ /* Decrease Write Size */
++ nTotalSectorSize -= wCurrPPSize;
++
++ /* Increase Buffer Address */
++ //cPageBuffer += ( nDevInfo->LBAInfo.SectorCount << 9 );
++
++ /* Count Next Page Size */
++ if ( nTotalSectorSize < nDevInfo->LBAInfo.SectorCount )
++ wCurrPPSize = (U16)nTotalSectorSize;
++ else
++ wCurrPPSize = nDevInfo->LBAInfo.SectorCount;
++
++ if ( nDevInfo->LBAInfo.TransProtocol2 & NAND_PROT2_WRITE_TYPE_B )
++ wFlagFirstSector = FALSE;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++ }
++
++ //nDevInfo->LBAInfo.HDAreaAddrOffSet = nDevInfo->LBAInfo.MDPSectorSize - nDevInfo->LBAInfo.HDAreaSectorSize;
++ //nDevInfo->LBAInfo.DTAreaSectorSize = nDevInfo->LBAInfo.MDPSectorSize - nDevInfo->LBAInfo.HDAreaSectorSize;
++
++ /* FORCE TO SET WP LOW */
++ NAND_IO_EnableWriteProtect();
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ NAND_IO_LBA_CacheFlush( nDevInfo );
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_MDPGetTotalSectorSize( NAND_IO_DEVINFO *nDevInfo, unsigned long int *rTotalSector )
++{
++ unsigned long int wTotalSector;
++ unsigned char nTemp;
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ pNFC->NFC_SADDR= 0xB0;
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Parallel Composition */
++ wTotalSector = (U8)( pNFC->NFC_SDATA & 0xFF );
++ wTotalSector |= ((U8)( pNFC->NFC_SDATA & 0xFF ) << 8 );
++ wTotalSector |= ((U8)( pNFC->NFC_SDATA & 0xFF ) << 16 );
++ wTotalSector |= ((U8)( pNFC->NFC_SDATA & 0xFF ) << 24 );
++// wTotalSector |= ((U8)( pNFC->NFC_SDATA & 0xFF ) << 32 );
++ nTemp = (U8)( pNFC->NFC_SDATA & 0xFF );
++
++ *rTotalSector = wTotalSector;
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_VFPGetTotalSectorSize( NAND_IO_DEVINFO *nDevInfo, U32 *rTotalSector )
++{
++ unsigned int dwTotalSector;
++
++ dwTotalSector = 0;
++ *rTotalSector = 0;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ pNFC->NFC_SADDR= 0xB5;
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Parallel Composition */
++ dwTotalSector = (U8)( pNFC->NFC_SDATA & 0xFF );
++ dwTotalSector |= ((U8)( pNFC->NFC_SDATA & 0xFF ) << 8 );
++
++ if ( dwTotalSector == 0 )
++ dwTotalSector = 0x10000;
++
++ *rTotalSector = dwTotalSector;
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_VFPChangeSectorSize( NAND_IO_DEVINFO *nDevInfo, U32 nTotalSector )
++{
++ unsigned int dwTotalSector;
++
++ //======================================================================================
++ //
++ // The available rage for the VFP size: [40][00]h(8 Mbyte) ~ [01][00][00]h(32 Mbyte)
++ // VFP AreaSize Min: 16,384 ~ Max: 65,536 sector / 512 sector resolution
++ //
++ // "VFP/MDP ratio = (+1)/(-2)" VFP increases by 1MB, the DMP decreases by 2MB.
++ //
++ //======================================================================================
++ if ( ( nTotalSector < 0x4000 ) || ( nTotalSector > 0x10000 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ /* VFP Size Change Command can only be executed in the VFP mode */
++ NAND_IO_LBA_ModeChange( nDevInfo, NAND_LBA_VFP );
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus Witdh */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //==============================================
++ // Arrange Sector Resolution
++ //==============================================
++ dwTotalSector = ( ( nTotalSector + 511 ) >> 9 );
++ dwTotalSector = dwTotalSector << 9;
++
++ if ( ( dwTotalSector < 0x4000 ) || ( dwTotalSector > 0x10000 ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //==============================================
++ // Set VFP Size
++ //==============================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ pNFC->NFC_SADDR= 0x22;
++
++ pNFC->NFC_SADDR= ( dwTotalSector & 0xFF ); // VFP_Size0: LSB
++ pNFC->NFC_SADDR= ( ( dwTotalSector >> 8 ) & 0xFF ); // VFP_Size1: MSB
++ pNFC->NFC_SADDR= ( 0xFF - ( dwTotalSector & 0xFF ) ); // Inversion of [VFP_Size0] for verification
++ pNFC->NFC_SADDR= ( 0xFF - ( ( dwTotalSector >> 8 ) & 0xFF ) ); // Inversion of [VFP_Size1] fot verification
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_SetTransferProtocol( NAND_IO_DEVINFO *nDevInfo, U8 nProtocol1, U8 nProtocol2 )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //==============================================
++ // Get Protocol 1
++ //==============================================
++ /* Command Partition Change to PNP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0xA2; // cmd
++ pNFC->NFC_SADDR= nProtocol1; // Parameter
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ //==============================================
++ // Get Protocol 2
++ //==============================================
++ /* Command Partition Change to PNP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0xA3; // cmd
++ pNFC->NFC_SADDR= nProtocol2; // Parameter
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_SetBootModeChange( NAND_IO_DEVINFO *nDevInfo, U8 nBootMode )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //==============================================
++ // Get Protocol 1
++ //==============================================
++ /* Command Partition Change to PNP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= nBootMode; // Parameter
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_SetRebootCmdChange( NAND_IO_DEVINFO *nDevInfo, U8 nRebootCmd )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //==============================================
++ // Get Protocol 1
++ //==============================================
++ /* Command Partition Change to PNP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= nRebootCmd; // Parameter
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_SetAreaPartition( NAND_IO_DEVINFO *nDevInfo, NAND_IO_FEATURE *sDevFeatureInfo )
++{
++ unsigned int i;
++ unsigned int nBlockOffset;
++
++ //==================================
++ // Area Address Offset Setting
++ //==================================
++ // Data Area Address Offset = 0
++ // 0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MDP Size
++ // [ Multi Hidden[n], Multi Hidden[n-1], Multi Hidden[0] | Hidden Area | Data Area ]
++ nDevInfo->LBAInfo.DTAreaAddrOffSet = 0;
++ nDevInfo->LBAInfo.DTAreaSectorSize = nDevInfo->LBAInfo.MDPSectorSize;
++
++ for ( i = 0; i < nDevInfo->LBAInfo.MHDAreaNums; ++i )
++ {
++ nDevInfo->LBAInfo.DTAreaSectorSize -= nDevInfo->LBAInfo.MHDAreaSectorSize[i];
++ nDevInfo->LBAInfo.MHDAreaAddrOffSet[i] = 0;
++ nDevInfo->LBAInfo.DTAreaAddrOffSet += nDevInfo->LBAInfo.MHDAreaSectorSize[i];
++ if ( i > 0 )
++ nDevInfo->LBAInfo.MHDAreaAddrOffSet[i] = ( nDevInfo->LBAInfo.MHDAreaSectorSize[i-1] + nDevInfo->LBAInfo.MHDAreaAddrOffSet[i-1] );
++ }
++ nDevInfo->LBAInfo.HDAreaAddrOffSet = nDevInfo->LBAInfo.MDPSectorSize - nDevInfo->LBAInfo.DTAreaSectorSize;
++ nDevInfo->LBAInfo.DTAreaSectorSize -= nDevInfo->LBAInfo.HDAreaSectorSize;
++ nDevInfo->LBAInfo.DTAreaAddrOffSet += nDevInfo->LBAInfo.HDAreaSectorSize;
++
++ nBlockOffset = ( nDevInfo->LBAInfo.DTAreaAddrOffSet / ( ( sDevFeatureInfo->PageSize * sDevFeatureInfo->PpB ) >> 9 ) );
++ if ( nDevInfo->LBAInfo.DTAreaAddrOffSet % ( ( sDevFeatureInfo->PageSize * sDevFeatureInfo->PpB ) >> 9 ) )
++ ++nBlockOffset;
++
++ nDevInfo->LBAInfo.DTAreaAddrOffSet += ( ( nBlockOffset * ( ( sDevFeatureInfo->PageSize * sDevFeatureInfo->PpB ) >> 9 ) ) - nDevInfo->LBAInfo.DTAreaAddrOffSet );
++ nDevInfo->LBAInfo.DTAreaSectorSize -= ( ( nBlockOffset * ( ( sDevFeatureInfo->PageSize * sDevFeatureInfo->PpB ) >> 9 ) ) - nDevInfo->LBAInfo.DTAreaAddrOffSet );
++
++ return SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_GetPersistentFunction( NAND_IO_DEVINFO *nDevInfo, U8 *rBootMode, U8 *rRebootCmd )
++{
++ unsigned char nParameter;
++
++ *rBootMode = 0;
++ *rRebootCmd = 0;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //==============================================
++ // Get Protocol 1
++ //==============================================
++ /* Command Partition Change to PNP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x99; // CMD
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ nParameter = (U8)( pNFC->NFC_SDATA & 0xFF );
++
++ *rBootMode = nParameter;
++
++ nParameter = (U8)( pNFC->NFC_SDATA & 0xFF );
++
++ *rRebootCmd = nParameter;
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_GetTransferProtocol( NAND_IO_DEVINFO *nDevInfo, U8 *rProtocol1, U8 *rProtocol2 )
++{
++ unsigned char nParameter;
++
++ *rProtocol1 = 0;
++ *rProtocol2 = 0;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //==============================================
++ // Get Protocol 1
++ //==============================================
++ /* Command Partition Change to PNP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0xB2; // cmd
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ nParameter = (U8)( pNFC->NFC_SDATA & 0xFF );
++
++ *rProtocol1 = nParameter;
++
++ //==============================================
++ // Get Protocol 2
++ //==============================================
++ /* Command Partition Change to PNP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0xB3; // cmd
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ nParameter = (U8)( pNFC->NFC_SDATA & 0xFF );
++
++ *rProtocol2 = nParameter;
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_GetDeviceMDPSectorSize( NAND_IO_DEVINFO *nDevInfo, unsigned long int *rTotalSector )
++{
++ unsigned int i;
++ unsigned long int nTotalSecSize;
++
++ NAND_IO_ERROR res;
++
++ nTotalSecSize = 0;
++
++ for ( i = NAND_IO_DRV0_START_CS; i < NAND_IO_DRV0_END_CS + 1; ++i )
++ {
++ nDevInfo[i].LBAInfo.MDPSectorSize = 0;
++
++ res = NAND_IO_LBA_GetDeviceInfo( i, &nDevInfo[i] );
++ if ( res == SUCCESS )
++ {
++ NAND_IO_LBA_MDPGetTotalSectorSize( nDevInfo, &nDevInfo[i].LBAInfo.MDPSectorSize );
++ nTotalSecSize += nDevInfo[i].LBAInfo.MDPSectorSize;
++ }
++ }
++
++ *rTotalSector = nTotalSecSize;
++
++ return SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_GetBusyTime( NAND_IO_DEVINFO *nDevInfo, U8 *rBusyTime )
++{
++ unsigned char dwBusyTime;
++
++ dwBusyTime = 0;
++ *rBusyTime = 0;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ pNFC->NFC_SADDR= 0xB4;
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Parallel Composition */
++ dwBusyTime = (U8)( pNFC->NFC_SDATA & 0xFF );
++
++ *rBusyTime = dwBusyTime;
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_SetBusyTime( NAND_IO_DEVINFO *nDevInfo, U8 nBusyTime )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ pNFC->NFC_SADDR= nBusyTime;
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_GetBootMode( NAND_IO_DEVINFO *nDevInfo, U8 *rBootMode )
++{
++ unsigned char dwBootMode;
++
++ dwBootMode = 0;
++ *rBootMode = 0;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ pNFC->NFC_SADDR= 0x00;
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x99; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Parallel Composition */
++ dwBootMode = (U8)( pNFC->NFC_SDATA & 0xFF );
++
++ *rBootMode = dwBootMode;
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_PowerSaveMode( NAND_IO_DEVINFO *nDevInfo, int nOnOff )
++{
++ //Power Save Mode En,Disable
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ if ( nOnOff == ENABLE )
++ pNFC->NFC_SADDR= 0xBA;
++ else
++ pNFC->NFC_SADDR= 0xBB;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_HighSpeedMode( NAND_IO_DEVINFO *nDevInfo, int nOnOff )
++{
++ // High Speed Write Mode En,Disable
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ if ( nOnOff == ENABLE )
++ pNFC->NFC_SADDR= 0xBC;
++ else
++ pNFC->NFC_SADDR= 0xBD;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ if ( nOnOff == ENABLE )
++ nDevInfo->LBAInfo.HighSpeedMode = ENABLE;
++ else
++ nDevInfo->LBAInfo.HighSpeedMode = DISABLE;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_CacheFlush( NAND_IO_DEVINFO *nDevInfo )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nDevInfo->LBAInfo.CurrentMode == NAND_LBA_BCM )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0xF9; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++ }
++ else
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xF9F9;
++ }
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_GetDeviceMediaNums( U16 *rMediaOrder )
++{
++ *rMediaOrder = gLBACSNums;
++
++ return SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_ConvertMPPA( NAND_IO_DEVINFO *nDevInfo, U8 nPartition, U32 nSectorAddr, U32 nSecSize, U32 *nConvertAddr, U32 *nConvertSize, U16 *rMediaOrder )
++{
++ unsigned short int i;
++ unsigned short int wOrder;
++ unsigned long int dwBound;
++ unsigned long int dwSectorAddr;
++ unsigned long int nTotalSectorSize[4];
++ unsigned long int nPartitionOffSet[4];
++
++ dwBound = 0;
++ dwSectorAddr = nSectorAddr;
++
++ for ( wOrder = 0; wOrder < gLBACSNums; ++wOrder )
++ {
++ if ( nPartition == NAND_LBA_DATA_AREA )
++ {
++ nTotalSectorSize[wOrder] = nDevInfo[wOrder].LBAInfo.DTAreaSectorSize;
++ nPartitionOffSet[wOrder] = nDevInfo[wOrder].LBAInfo.DTAreaAddrOffSet;
++ }
++ else if ( nPartition == NAND_LBA_HIDDEN_AREA )
++ {
++ nTotalSectorSize[wOrder] = nDevInfo[wOrder].LBAInfo.HDAreaSectorSize;
++ nPartitionOffSet[wOrder] = nDevInfo[wOrder].LBAInfo.HDAreaAddrOffSet;
++ }
++ else if ( nPartition == NAND_LBA_MULTI_HIDDEN_AREA_0 )
++ {
++ nTotalSectorSize[wOrder] = nDevInfo[wOrder].LBAInfo.MHDAreaSectorSize[0];
++ nPartitionOffSet[wOrder] = nDevInfo[wOrder].LBAInfo.MHDAreaAddrOffSet[0];
++ }
++ else if ( nPartition == NAND_LBA_MDP )
++ {
++ nTotalSectorSize[wOrder] = nDevInfo[wOrder].LBAInfo.MDPSectorSize;
++ nPartitionOffSet[wOrder] = 0;
++ }
++ else if ( nPartition == NAND_LBA_VFP )
++ {
++ nTotalSectorSize[wOrder] = nDevInfo[wOrder].LBAInfo.VFPSectorSize;
++ nPartitionOffSet[wOrder] = NAND_LBA_SYS_SECTION;
++ }
++
++ dwBound += nDevInfo[wOrder].LBAInfo.MDPSectorSize;
++ dwSectorAddr += nPartitionOffSet[wOrder];
++
++ if ( dwSectorAddr < dwBound )
++ {
++ *rMediaOrder = wOrder;
++ break;
++ }
++ }
++
++ for ( i = 0; i < wOrder; ++i )
++ dwSectorAddr -= nDevInfo[i].LBAInfo.MDPSectorSize;
++
++ if ( ( nDevInfo[wOrder].LBAInfo.MDPSectorSize - dwSectorAddr ) >= nSecSize )
++ *nConvertSize = nSecSize;
++ else
++ *nConvertSize = ( nDevInfo[wOrder].LBAInfo.MDPSectorSize - dwSectorAddr );
++
++ *nConvertAddr = dwSectorAddr;
++
++ if ( ( dwSectorAddr + *nConvertSize ) > ( nTotalSectorSize[wOrder] + nPartitionOffSet[wOrder] ) )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ return SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_DeviceReboot( NAND_IO_DEVINFO *nDevInfo )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nDevInfo->LBAInfo.CurrentMode == NAND_LBA_BCM )
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0xFD; // CMD
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ }
++ else
++ {
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xFDFD;
++ }
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_PNP;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_ReadID( NAND_IO_DEVINFO *nDevInfo, NAND_IO_DEVID *nDeviceCode )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x9292;
++ pNFC->NFC_SADDR = 0x0000; /* Address [ 0x00 ] */
++
++ /* Delay : tAR1[READID] Max 200nS */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++ //ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++
++ /* Parallel Composition */
++ nDeviceCode->Code[0] = (U16)( pNFC->NFC_SDATA & nDevInfo->CmdMask );
++ nDeviceCode->Code[1] = (U16)( pNFC->NFC_SDATA & nDevInfo->CmdMask );
++ nDeviceCode->Code[2] = (U16)( pNFC->NFC_SDATA & nDevInfo->CmdMask );
++ nDeviceCode->Code[3] = (U16)( pNFC->NFC_SDATA & nDevInfo->CmdMask );
++ nDeviceCode->Code[4] = (U16)( pNFC->NFC_SDATA & nDevInfo->CmdMask );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_Reset( NAND_IO_DEVINFO *nDevInfo )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setup Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xFFFF;
++ /* Delay : tAR1[READID] Max 200nS */
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xFDFD;
++ /* Delay : tAR1[READID] Max 200nS */
++ ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;ASM_NOP;
++
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_PNP;
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_ModeChange( NAND_IO_DEVINFO *nDevInfo, int nMode )
++{
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ if ( nMode == NAND_LBA_PNP )
++ {
++ // Change to BCM
++ if ( ( nDevInfo->LBAInfo.CurrentMode == NAND_LBA_PNP ) || ( nDevInfo->LBAInfo.CurrentMode == NAND_LBA_BCM ) )
++ {
++ //==============================================
++ // Directly Enter BCM (Boot Code Maintenance)
++ //==============================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0xFC; // cmd
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++ }
++ else
++ {
++ /* Command Partition Change to BCM */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0xBF; // cmd
++ pNFC->NFC_SADDR= 0x00; // PassWord 0
++ pNFC->NFC_SADDR= 0x00; // PassWord 1
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++ }
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ // Exit from BCM
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x8080;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0xFD; // cmd
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x1010;
++ }
++ else if ( nMode == NAND_LBA_BCM )
++ {
++ if ( ( nDevInfo->LBAInfo.CurrentMode == NAND_LBA_PNP ) || ( nDevInfo->LBAInfo.CurrentMode == NAND_LBA_BCM ) )
++ {
++ //==============================================
++ // Directly Enter BCM (Boot Code Maintenance)
++ //==============================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0xFC; // cmd
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x3030;
++ }
++ else
++ {
++ /* Command Partition Change to BCM */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0xBF; // cmd
++ pNFC->NFC_SADDR= 0x00; // PassWord 0
++ pNFC->NFC_SADDR= 0x00; // PassWord 1
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++ }
++ }
++ else if ( nMode == NAND_LBA_MDP )
++ {
++ /* Command Partition Change to MDP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0xFCFC;
++ }
++ else if ( nMode == NAND_LBA_VFP )
++ {
++ /* Command Partition Change to VFP */
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x0000;
++
++ pNFC->NFC_SADDR= 0xBE; // cmd
++ pNFC->NFC_SADDR= 0xFF; // PassWord 0
++ pNFC->NFC_SADDR= 0xFF; // PassWord 1
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++ pNFC->NFC_SADDR= 0x00; // Dummy Write
++
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x5757;
++ }
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ /* Read Status */
++ NAND_IO_LBA_Read2Status( nDevInfo );
++ if ( nDevInfo->LBAInfo.CurrentMode != nMode )
++ return ERR_NAND_IO_FAILED_LBA_PARTITION_CHANGE;
++
++ if ( nMode == NAND_LBA_MDP )
++ {
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_MDP;
++ NAND_IO_LBA_MDPGetTotalSectorSize( nDevInfo, &nDevInfo->LBAInfo.CurrentSectorSize );
++ }
++ else if ( nMode == NAND_LBA_VFP )
++ {
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_VFP;
++ NAND_IO_LBA_VFPGetTotalSectorSize( nDevInfo, (U32 *)&nDevInfo->LBAInfo.CurrentSectorSize );
++ }
++
++ return (NAND_IO_ERROR)SUCCESS;
++}
++
++NAND_IO_ERROR NAND_IO_LBA_Read2Status( NAND_IO_DEVINFO *nDevInfo )
++{
++ unsigned int uStatus;
++ NAND_IO_ERROR res;
++
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ /* Pre Process */
++ NAND_IO_PreProcess();
++
++ /* Set Setuo Time and Hold Time */
++ NAND_IO_SetBasicCycleTime();
++
++ /* Enable Chip Select */
++ NAND_IO_EnableChipSelect( nDevInfo->ChipNo );
++
++ /* Set Data Bus as 16Bit */
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //================================
++ // Command READ STATUS [ 0x70 ]
++ //================================
++ pNFC->NFC_CMD = nDevInfo->CmdMask & 0x7171;
++
++ // Delay : more than 200nS
++ NAND_IO_Delay();
++
++ //=============================================
++ // DATA BUS WIDTH Setting
++ //=============================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //================================
++ // Read IO Status
++ //================================
++ uStatus = nDevInfo->CmdMask & pNFC->NFC_SDATA;
++ uStatus = uStatus & 0x0F;
++
++ if ( ( uStatus & 0x06 ) == NAND_LBA_PNP )
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_PNP;
++ else if ( ( uStatus & 0x06 ) == NAND_LBA_BCM )
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_BCM;
++ else if ( ( uStatus & 0x06 ) == NAND_LBA_VFP )
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_VFP;
++ else if ( ( uStatus & 0x06 ) == NAND_LBA_MDP )
++ nDevInfo->LBAInfo.CurrentMode = NAND_LBA_MDP;
++ else
++ res = ERR_NAND_IO_FAILED_LBA_PARTITION_CHANGE;
++
++ if ( nDevInfo->LBAInfo.CurrentMode != NAND_LBA_PNP )
++ {
++ if ( uStatus & NAND_POWER_SAVE_ENABLE )
++ nDevInfo->LBAInfo.PowerSaveMode = ENABLE;
++ else
++ nDevInfo->LBAInfo.PowerSaveMode = DISABLE;
++
++ if ( uStatus & NAND_HIGH_SPEED_ENABLE )
++ nDevInfo->LBAInfo.HighSpeedMode = ENABLE;
++ else
++ nDevInfo->LBAInfo.HighSpeedMode = DISABLE;
++ }
++
++ /* Wait until it is ready */
++ NAND_IO_WaitBusy( nDevInfo->ChipNo );
++
++ /* Disable Chip Select */
++ NAND_IO_DisableChipSelect();
++
++ /* Post Process */
++ NAND_IO_PostProcess();
++
++ return res;
++}
++
++static __inline NAND_IO_ERROR NAND_IO_LBA_ReadData_VFP( NAND_IO_DEVINFO *nDevInfo, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0, *pSpareDW = 0;
++ unsigned char *pDataBuffer, *pPrDataBuffer;
++ unsigned char *pPhy_Buffer;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ if ( nReadPPSize > nDevInfo->LBAInfo.SectorCount )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Read Data as 512+16Bytes
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ //----------------------------------------------
++ // Read Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nReadPPSize; ++j )
++ {
++ /* Set Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++
++#if 1 /* 09.12.21 */
++ /* Read 512 Data Area */
++ i = 128;
++ do {
++ if ( bAlignAddr )
++ {
++ *pPageDW = pNFC->NFC_WDATA;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ *pPageB = uDWordByte.BYTE[2];++pPageB;
++ *pPageB = uDWordByte.BYTE[3];++pPageB;
++ }
++ }while(--i);
++#else
++ //####################################################
++ //# Read 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++
++ /* Read 512 Data Area */
++ i = 128;
++ do {
++ if ( bAlignAddr )
++ {
++ *pPageDW = pNFC->NFC_WDATA;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ *pPageB = uDWordByte.BYTE[2];++pPageB;
++ *pPageB = uDWordByte.BYTE[3];++pPageB;
++ }
++ }while(--i);
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ //
++ ///* Disable DMA Ahead */
++ ////IO_DMA_SetCTRL( IO_DMA_CH2, 0 );
++ ////IO_INT_HwICLR = IO_INT_HwDMA_CH2;
++ //
++ ///* Start DMA on NFC BUS */
++#if 1 /* 09.12.08 */
++ #if defined(_LINUX_) || defined(_WINCE_)
++
++ //if ( nEccOnOff == ECC_ON_NON_CACHE_BUF )
++ //{
++ // pPhy_Buffer = virt_to_phys(pDataBuffer);
++ //
++ // NAND_IO_SetupDMA_kernel( (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ // (void*)pPhy_Buffer, 4, 0,
++ // NAND_IO_DMA_READ, 512 );
++ //}
++ //else
++ NAND_IO_SetupDMA( (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ (void*)pDataBuffer, 4, 0,
++ NAND_IO_DMA_READ, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)&pNFC->NFC_LDATA, 0, 0,
++ (void*)pDataBuffer, 4, 0,
++ NAND_IO_DMA_READ, 512 );
++ #endif
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++#else
++
++
++ /* Disable DMA Ahead */
++ /* Start DMA on NFC BUS */
++ NAND_IO_SetupDMADoubleBuf( NAND_IO_DMA_READ, j );
++
++ pNFC->NFC_RSTART = 0;
++
++ if ( j != 0 )
++ {
++ if ( j & 1 )
++ memcpy( pPrDataBuffer, gpDMA_WorkBuffer1, 512 );
++ else
++ memcpy( pPrDataBuffer, gpDMA_WorkBuffer0, 512 );
++ }
++
++ while ( ISZERO(pNFC->NFC_IREQ, HwNFC_IREQ_FLAG0) );
++
++
++ if ( j == (unsigned int)( nReadPPSize - 1 ) )
++ {
++ if ( j & 1 )
++ memcpy( pDataBuffer, gpDMA_WorkBuffer0, 512 );
++ else
++ memcpy( pDataBuffer, gpDMA_WorkBuffer1, 512 );
++ }
++ else
++ {
++ pPrDataBuffer = pDataBuffer; // Buffer Pointer Backup
++
++ if ( j & 1 )
++ pDataBuffer =(unsigned char *)gpDMA_WorkBuffer0;
++ else
++ pDataBuffer =(unsigned char *)gpDMA_WorkBuffer1;
++ }
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++#endif
++ #endif
++#endif
++ //####################################################
++ //####################################################
++ if ( nDevInfo->LBAInfo.DataTransferCheck == ENABLE )
++ {
++ /* Read 16Bytes spare data */
++ i = 4;
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ else
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ return res;
++}
++
++static __inline NAND_IO_ERROR NAND_IO_LBA_ReadData( NAND_IO_DEVINFO *nDevInfo, U16 nReadPPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0, *pSpareDW = 0;
++ unsigned char *pDataBuffer, *pPrDataBuffer;
++ unsigned char *pPhy_Buffer;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ if ( nReadPPSize > nDevInfo->LBAInfo.SectorCount )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Read Data as 512+16Bytes
++ //=========================================================================
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ //----------------------------------------------
++ // Read Data as 512Bytes repeatly
++ //----------------------------------------------
++#ifdef __USE_NAND_ISR__
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ pPhy_Buffer = virt_to_phys(pDataBuffer);
++ NAND_IO_SetupDMA_kernel( (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ (void*)pPhy_Buffer, 4, 0,
++ NAND_IO_DMA_READ, 512 * nReadPPSize );
++#else
++ for ( j = 0; j < nReadPPSize; ++j )
++ {
++ /* Set Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Read 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++
++ /* Read 512 Data Area */
++ i = 128;
++ do {
++ if ( bAlignAddr )
++ {
++ *pPageDW = pNFC->NFC_WDATA;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pPageB = uDWordByte.BYTE[0];++pPageB;
++ *pPageB = uDWordByte.BYTE[1];++pPageB;
++ *pPageB = uDWordByte.BYTE[2];++pPageB;
++ *pPageB = uDWordByte.BYTE[3];++pPageB;
++ }
++ }while(--i);
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ //
++ ///* Disable DMA Ahead */
++ ////IO_DMA_SetCTRL( IO_DMA_CH2, 0 );
++ ////IO_INT_HwICLR = IO_INT_HwDMA_CH2;
++ //
++ ///* Start DMA on NFC BUS */
++ /* Disable DMA Ahead */
++ /* Start DMA on NFC BUS */
++ NAND_IO_SetupDMADoubleBuf( NAND_IO_DMA_READ, j );
++
++ pNFC->NFC_RSTART = 0;
++
++ if ( j != 0 )
++ {
++ if ( j & 1 )
++ memcpy( pPrDataBuffer, gpDMA_WorkBuffer1, 512 );
++ else
++ memcpy( pPrDataBuffer, gpDMA_WorkBuffer0, 512 );
++ }
++
++ while ( ISZERO(pNFC->NFC_IREQ, HwNFC_IREQ_FLAG0) );
++
++
++ if ( j == (unsigned int)( nReadPPSize - 1 ) )
++ {
++ if ( j & 1 )
++ memcpy( pDataBuffer, gpDMA_WorkBuffer0, 512 );
++ else
++ memcpy( pDataBuffer, gpDMA_WorkBuffer1, 512 );
++ }
++ else
++ {
++ pPrDataBuffer = pDataBuffer; // Buffer Pointer Backup
++
++ if ( j & 1 )
++ pDataBuffer =(unsigned char *)gpDMA_WorkBuffer0;
++ else
++ pDataBuffer =(unsigned char *)gpDMA_WorkBuffer1;
++ }
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++#endif
++ //####################################################
++ //####################################################
++ if ( nDevInfo->LBAInfo.DataTransferCheck == ENABLE )
++ {
++ /* Read 16Bytes spare data */
++ i = 4;
++ do {
++ if ( bAlignAddr )
++ {
++ *pSpareDW = pNFC->NFC_WDATA;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.DWORD = pNFC->NFC_WDATA;
++ *pSpareB = uDWordByte.BYTE[0];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[1];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[2];++pSpareB;
++ *pSpareB = uDWordByte.BYTE[3];++pSpareB;
++ }
++ }while(--i);
++
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ else
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++ }
++#endif
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++* static __inline void NAND_IO_LBA_WaitBusy( U16 nChipNo );
++*
++* DESCRIPTION :
++* INPUT:
++* nChipNo =
++*
++* OUTPUT: void - Return Type
++* REMARK :
++**************************************************************************/
++static __inline void NAND_IO_LBA_WaitBusy( U16 nChipNo )
++{
++ // Misc. Configuration Register(MCFG)
++ // 0 : represent that READY pin is low
++ // 1 : high
++ // Delay : 200nS
++
++ while (NAND_IO_CheckReadyAndBusy( nChipNo ))
++ {
++ #ifndef FWDN_DOWNLOADER_INCLUDE
++ TCC7XX_USBDRV_WriteToQueue();
++ #endif
++ }
++}
++
++static __inline NAND_IO_ERROR NAND_IO_LBA_WriteData( NAND_IO_DEVINFO *nDevInfo, U16 nWritePPSize,
++ U8 *nPageBuffer, U8 *nSpareBuffer )
++{
++ unsigned int i, j;
++ unsigned char bAlignAddr;
++ unsigned char *pPageB = 0, *pSpareB = 0;
++ unsigned int *pPageDW = 0, *pSpareDW = 0;
++ unsigned char *pDataBuffer;
++ DWORD_BYTE uDWordByte;
++ NAND_IO_ERROR res;
++
++ if ( nWritePPSize > nDevInfo->LBAInfo.SectorCount )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // Check Align of PageBuffer Address
++ //=========================================================================
++ bAlignAddr = ( (unsigned int)nPageBuffer & 3 ) ? 0 : 1;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ //=========================================================================
++ // Write Data as 528Bytes
++ //=========================================================================
++
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ {
++ pPageDW = (unsigned int*)nPageBuffer;
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ }
++ else
++ {
++ pPageB = (unsigned char*)nPageBuffer;
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++
++ //----------------------------------------------
++ // Write Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nWritePPSize; ++j )
++ {
++ /* Get Data Buffer */
++ pDataBuffer = ( bAlignAddr ) ? (unsigned char*)pPageDW : (unsigned char*)pPageB;
++
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++
++ /* Write 512 Data Area */
++ //BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ //pNFC->NFC_DSIZE = 512;
++ //pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++ //pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pPageDW;++pPageDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pPageB;++pPageB;
++ uDWordByte.BYTE[1] = *pPageB;++pPageB;
++ uDWordByte.BYTE[2] = *pPageB;++pPageB;
++ uDWordByte.BYTE[3] = *pPageB;++pPageB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ //while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++
++#if 1 /* 09.12.08 */
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)pDataBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)pDataBufferE, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++
++
++#else
++
++
++ if ( j == 0 )
++ memcpy( gpDMA_WorkBuffer1, pDataBuffer, 512 );
++
++ NAND_IO_SetupDMADoubleBuf( NAND_IO_DMA_WRITE, j );
++
++ if ( pNFC->NFC_CTRL1 & Hw31 )
++ BITCLR( pNFC->NFC_CTRL1, Hw31 );
++
++ pNFC->NFC_PSTART = 0;
++
++ if ( j != (unsigned int)( nWritePPSize - 1 ) )
++ {
++ if ( j & 1 )
++ memcpy( gpDMA_WorkBuffer1, (void *)(pDataBuffer + 512), 512 );
++ else
++ memcpy( gpDMA_WorkBuffer0, (void *)(pDataBuffer + 512), 512 );
++ }
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++
++ if ( pNFC->NFC_CTRL1 & Hw30 )
++ BITSET( pNFC->NFC_CTRL1, Hw31 );
++
++ if ( bAlignAddr )
++ pPageDW += 128;
++ else
++ pPageB += 512;
++#endif
++
++ #endif
++ //####################################################
++ //####################################################
++ if ( nDevInfo->LBAInfo.DataTransferCheck == ENABLE )
++ {
++ /* Write 16Bytes spare data */
++ i = 4;
++ do {
++ if ( bAlignAddr )
++ {
++ pNFC->NFC_WDATA = *pSpareDW;++pSpareDW;
++ }
++ else
++ {
++ uDWordByte.BYTE[0] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[1] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[2] = *pSpareB;++pSpareB;
++ uDWordByte.BYTE[3] = *pSpareB;++pSpareB;
++ pNFC->NFC_WDATA = uDWordByte.DWORD;
++ }
++ }while(--i);
++
++ /* Adapt type of address */
++ if ( bAlignAddr )
++ pSpareDW = (unsigned int*)nSpareBuffer;
++ else
++ pSpareB = (unsigned char*)nSpareBuffer;
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ return res;
++}
++
++/**************************************************************************
++* FUNCTION NAME :
++*
++* static __inline NAND_IO_ERROR NAND_IO_LBA_WriteDummyData( NAND_IO_DEVINFO *nDevInfo, U16 nWritePPSize );
++*
++* DESCRIPTION : You can add file description here.
++*
++* INPUT:
++* nDevInfo =
++* nWritePPSize =
++*
++* OUTPUT: NAND_IO_ERROR - Return Type
++* =
++*
++**************************************************************************/
++static __inline NAND_IO_ERROR NAND_IO_LBA_WriteDummyData( NAND_IO_DEVINFO *nDevInfo, U16 nWritePPSize )
++{
++ unsigned int i, j;
++ unsigned char nTempBuffer[512];
++ NAND_IO_ERROR res;
++
++ if ( nWritePPSize > nDevInfo->LBAInfo.SectorCount )
++ return ERR_NAND_IO_WRONG_PARAMETER;
++
++ //=========================================================================
++ // Initial Setting
++ //=========================================================================
++ res = (NAND_IO_ERROR)SUCCESS;
++
++ //=========================================================================
++ // DATA BUS WIDTH Setting
++ //=========================================================================
++ if ( nDevInfo->Feature.MediaType & A_DATA_WITDH_16BIT )
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_16BIT );
++ else
++ NAND_IO_SetDataWidth( NAND_IO_DATA_WITDH_8BIT );
++
++ /* Prepare data */
++ #if defined(_WINCE_)
++ memset( nTempBuffer, 0xFF, 512 );
++ #elif defined(_LINUX_)
++ #ifndef KERNEL_DRIVER
++ memset( nTempBuffer, 0xFF, 512 );
++ #else
++ memset( nTempBuffer, 0xFF, 512 );
++ #endif
++ #else
++ memset( nTempBuffer, 0xFF, 512 );
++ #endif
++
++ //----------------------------------------------
++ // Write Data as 512Bytes repeatly
++ //----------------------------------------------
++ for ( j = 0; j < nWritePPSize; ++j )
++ {
++ //####################################################
++ //# Write 512 Page Data
++ //####################################################
++ //----------------------------------------------
++ // MCU ACCESS
++ //----------------------------------------------
++ #if defined( NAND_IO_USE_MCU_ACCESS )
++
++ /* Write 512 Data Area */
++ BITCSET( pNFC->NFC_CTRL, HwNFC_CTRL_BSIZE_8, HwNFC_CTRL_BSIZE_1 ); // 1R/W Burst Size
++ pNFC->NFC_DSIZE = 512;
++ pNFC->NFC_IREQ = 0x77; // pNFC->NFC_IREQ_FLAG1;
++
++ NAND_IO_IRQ_Mask();
++ pNFC->NFC_PSTART = 0;
++
++ i = 128;
++ do {
++ while (!( pNFC->NFC_CTRL & HwNFC_CTRL_FS_RDY ));
++ pNFC->NFC_LDATA = 0xFFFFFFFF;
++ }while(--i);
++
++ while (ISZERO( pNFC->NFC_IREQ, HwNFC_IREQ_FLAG1 ));
++ NAND_IO_IRQ_UnMask();
++
++ //----------------------------------------------
++ // DMA ACCESS
++ //----------------------------------------------
++ #elif defined( NAND_IO_USE_DMA_ACCESS )
++ /* Disable DMA Ahead */
++ //IO_DMA_SetCTRL( IO_DMA_CH2, 0 );
++ //IO_INT_HwICLR = IO_INT_HwDMA_CH2;
++
++ #if defined(_LINUX_) || defined(_WINCE_)
++ NAND_IO_SetupDMA( (void*)nTempBuffer, 4, 0,
++ (void*)&NAND_IO_HwLDATA_PA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #else
++ NAND_IO_SetupDMA( (void*)nTempBuffer, 4, 0,
++ (void*)&pNFC->NFC_LDATA, 0, 0,
++ NAND_IO_DMA_WRITE, 512 );
++ #endif
++
++ #endif
++ //####################################################
++ //####################################################
++ if ( nDevInfo->LBAInfo.DataTransferCheck == ENABLE )
++ {
++ /* Write 16Bytes spare data */
++ i = 4;
++ do {
++ pNFC->NFC_WDATA = 0xFFFFFFFF;
++ }while(--i);
++ }
++ }
++
++ //=========================================================================
++ // Return
++ //=========================================================================
++ return res;
++}
++#endif // NAND_LBA_INCLUDE
++
++#endif // WITHOUT_FILESYSTEM
++
++/* end of file */
++
+diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
+index 43d6ba8..b0e4bbc 100644
+--- a/drivers/char/Kconfig
++++ b/drivers/char/Kconfig
+@@ -1073,5 +1073,48 @@ config DEVPORT
+
+ source "drivers/s390/char/Kconfig"
+
++config TCC_CKC_IOCTL
++ tristate "Telechips clock io control driver"
++ default y
++ depends on ARCH_TCC
++ help
++ If you say Y here, you can use clock ioctl.
++
++
++
++config TCC_USER_INTR
++ tristate "Telechips User-level interrupt driver"
++ default y
++ depends on ARCH_TCC
++ help
++ If you say Y here, you can use H/W interrupt source.
++ Telechips User-level interrupt driver.
++
++config TCC_BL
++ tristate "Telechips Back-light driver"
++ default y
++ depends on ARCH_TCC
++
++config TCC_POWER_CTL
++ tristate "Telechips power control driver"
++ default y
++ depends on ARCH_TCC
++ help
++ If you say Y here, you can use power ctl driver.
++
++choice
++ prompt "HHTECH MID GPIO"
++ help
++ Select LCD either 4.3'' or 7 ''
++ config LCD_4
++ bool "Support for 4.3 inch LCD"
++ help
++ for HHTECH 4.3 inch, provide sysfs interface to APP
++ config LCD_7
++ bool "Support for 7 inch LCD"
++ help
++ for HHTECH 7 inch LCD
++endchoice
++
+ endmenu
+
+diff --git a/drivers/char/Makefile b/drivers/char/Makefile
+index 438f713..61f510a 100644
+--- a/drivers/char/Makefile
++++ b/drivers/char/Makefile
+@@ -9,6 +9,10 @@ FONTMAPFILE = cp437.uni
+
+ obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o
+
++#Makesure gpio init first
++obj-$(CONFIG_LCD_4) += hhtech_gpio.o
++obj-$(CONFIG_LCD_7) += hhtech_gpio.o
++
+ obj-$(CONFIG_LEGACY_PTYS) += pty.o
+ obj-$(CONFIG_UNIX98_PTYS) += pty.o
+ obj-y += misc.o
+@@ -106,9 +110,17 @@ obj-$(CONFIG_TCG_TPM) += tpm/
+
+ obj-$(CONFIG_PS3_FLASH) += ps3flash.o
+
++obj-y += tcc_ll.o
++obj-$(CONFIG_TCC_POWER_CTL) += tcc_pwm.o
++
+ obj-$(CONFIG_JS_RTC) += js-rtc.o
+ js-rtc-y = rtc.o
+
++obj-$(CONFIG_TCC_CKC_IOCTL) += tcc_ckc_ioctl.o
++obj-$(CONFIG_TCC_USER_INTR) += tcc_intr.o
++obj-$(CONFIG_TCC_BL) += tcc_backlight.o tca_backlight.o
++obj-y += tcc_proc.o tcc_pwrkey.o
++
+ # Files generated that shall be removed upon make clean
+ clean-files := consolemap_deftbl.c defkeymap.c
+
+diff --git a/drivers/char/hhtech_gpio.c b/drivers/char/hhtech_gpio.c
+new file mode 100755
+index 0000000..49de886
+--- /dev/null
++++ b/drivers/char/hhtech_gpio.c
+@@ -0,0 +1,1701 @@
++/*
++ * TCC8900 GPIO Driver
++ *
++ * Copyright (C) 2008 - 2009 HHTECH.
++ *
++ * Author: <wk@hhcn.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this progSoftwareram; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/platform_device.h>
++#include <linux/workqueue.h>
++#include <linux/sysdev.h>
++#include <linux/sysfs.h>
++#include <linux/fs.h>
++#include <linux/delay.h>
++#include <linux/gpio_keys.h>
++#include <linux/interrupt.h>
++#include <linux/suspend.h>
++#include <linux/reboot.h>
++#include <linux/miscdevice.h>
++#include <linux/wait.h>
++#include <linux/poll.h>
++
++#include <asm/io.h>
++#include <hhtech_gpio.h>
++#include <mach/TCC89x_Structures.h>
++#include <mach/globals.h>
++#include <mach/gpio.h>
++
++#include <../drivers/usb/dwc_otg/dwc_otg_driver.h>
++#include <mach/globals.h>
++#include <bsp.h>
++
++#define IRQ_HPD INT_EI3
++#define IRQ_DC INT_EI4
++#define IRQ_HEADPHONE INT_EI7
++#define HPD_MINOR 244 /* Major 10, Minor 244, /dev/tv_hpd */
++
++struct hpd_struct {
++ spinlock_t lock;
++ wait_queue_head_t waitq;
++ atomic_t state;
++};
++static struct hpd_struct hpd_struct;
++static int bluetooth_on;
++
++#if defined(CONFIG_LCD_4)
++static unsigned int system_flag = 2;
++#else
++static unsigned int system_flag = 3;
++#endif
++
++#if defined (CONFIG_LCD_4)
++int choosedevice = 1;
++#else
++int choosedevice = 0;
++#endif
++EXPORT_SYMBOL(choosedevice);
++
++#if defined (CONFIG_LCD_4)
++static struct delayed_work headp_detect_work;
++#endif
++static struct delayed_work battery_work;
++static struct delayed_work shutdown_work;
++int current_battery = 0;
++EXPORT_SYMBOL(current_battery);
++static int user_disable_speaker = 0;
++static int mu350_first_plug_in = 1;
++unsigned long rtc_wakeup_time = 30 * 60;
++EXPORT_SYMBOL(rtc_wakeup_time);
++
++unsigned int wakeup_status = 0; // 0: waked up by external IRQ; 1: waked up by RTC
++EXPORT_SYMBOL(wakeup_status);
++
++extern void lcd_standby(void);
++extern void lcd_normal(void);
++
++/* ################# setting ################## */
++
++// HHTECH set system power enable
++static void set_sys_power(int sw)
++{
++ if (sw)
++ gpio_set_value(GPIO_PWR_EN, 1); //power on
++ else
++ gpio_set_value(GPIO_PWR_EN, 0); //pwoer off
++}
++
++// HHTECH set Charging mode
++static void set_charge_mode(int sw)
++{
++ if (sw)
++ gpio_set_value(GPIO_CHARGER_EN, 1); //860ma
++ else
++ gpio_set_value(GPIO_CHARGER_EN, 0); //200ma
++}
++
++// HHTECH set TV-OUT switch
++static void set_tv_out(int sw)
++{
++ if (sw) {
++ *(volatile unsigned long *)0xF0240004 &= ~0x80;//open clk of TV-OUT
++ gpio_set_value(GPIO_TVOUT_EN, 1); //open
++ } else
++ gpio_set_value(GPIO_TVOUT_EN, 0); //close
++}
++
++// HHTECH set USB system (HOST and OTG) power enable
++void set_usb_syspwr_en(int sw)
++{
++ if (sw)
++ gpio_set_value(GPIO_USB_EN, 1); //open
++ else
++ gpio_set_value(GPIO_USB_EN, 0); //close
++}
++EXPORT_SYMBOL(set_usb_syspwr_en);
++
++// HHTECH set USB HOST power enable
++static void set_usb_hostpwr_en(int sw)
++{
++ if (sw)
++ gpio_set_value(GPIO_USB_HOSTPWR_EN, 1); //open
++ else
++ gpio_set_value(GPIO_USB_HOSTPWR_EN, 0); //close
++}
++
++// HHTECH set USB OTG DRV enable
++void set_usb_otgdrv_en(int sw)
++{
++ if (sw)
++ gpio_set_value(GPIO_USB_OTGDRV_EN, 1); //open
++ else
++ gpio_set_value(GPIO_USB_OTGDRV_EN, 0); //close
++}
++EXPORT_SYMBOL(set_usb_otgdrv_en);
++
++// HHTECH set speaker
++static void set_speaker_en(int sw)
++{
++ if (sw)
++ gpio_set_value(GPIO_SPEAKER_EN, 1); //open
++ else
++ gpio_set_value(GPIO_SPEAKER_EN, 0); //close
++}
++
++// HHTECH set wifi
++static void set_wifi_en(int sw)
++{
++ if (sw)
++ gpio_direction_output(GPIO_WIFI_EN, 1); //open
++ else
++ gpio_direction_output(GPIO_WIFI_EN, 0); //close
++}
++
++// HHTECH set hdmi power
++static void set_hdmipwr_en(int sw)
++{
++ if (sw)
++ {
++ gpio_direction_output(GPIO_HDMIPWR_EN, 0); //hdmi pwr on
++
++// *(volatile unsigned long *)0xF0404018 &= ~0x2;
++ *(volatile unsigned long *)0xF0255000 &= ~(0x2);
++ *(volatile unsigned long *)0xF0255000 |= 0x1;//HDMI ENABLE
++
++ }
++ else
++ {
++ *(volatile unsigned long *)0xF0255000 |= 0x2;
++ *(volatile unsigned long *)0xF0255000 &= ~(0x1);
++// *(volatile unsigned long *)0xF0404018 |= 0x2;
++
++ gpio_direction_output(GPIO_HDMIPWR_EN, 1); //hdmi pwr off
++ }
++}
++
++// HHTECH set hdmi
++void set_hdmi_en(int sw)
++{
++ if (sw)
++ {
++ set_hdmipwr_en(1);
++ gpio_direction_output(GPIO_HDMI_EN, 1); //open
++ gpio_direction_output(GPIO_USB_EN, 1);
++ }
++ else
++ {
++#if defined (CONFIG_LCD_7)
++ gpio_direction_output(GPIO_HDMI_EN, 0); //close
++ set_hdmipwr_en(0);
++ if(choosedevice && !gpio_get_value(GPIO_USB_HOSTPWR_EN))
++ gpio_direction_output(GPIO_USB_EN, 0); // close USB power
++#else
++ set_hdmipwr_en(0);
++ if(!bluetooth_on)
++ {
++ gpio_direction_output(GPIO_HDMI_EN,0);
++ if(!gpio_get_value(GPIO_USB_OTGDRV_EN))
++ gpio_direction_output(GPIO_USB_EN, 0);
++ }
++#endif
++
++
++ }
++}
++EXPORT_SYMBOL(set_hdmi_en);
++
++// HHTECH set led1 and led2
++static void set_led1_en(int sw)
++{
++ if (sw)
++ gpio_direction_output(GPIO_LED1_EN, 0); //turn on
++ else
++ gpio_direction_output(GPIO_LED1_EN, 1); //turn off
++}
++
++static void set_led2_en(int sw)
++{
++ if (sw)
++ gpio_set_value(GPIO_LED2_EN, 0);
++ else
++ gpio_set_value(GPIO_LED2_EN, 1);
++}
++
++/*@@@@@@@@@@@@@@@@@@@@@@@ sysfs interface @@@@@@@@@@@*/
++
++#ifdef CONFIG_SYSFS
++static ssize_t hhtech_sysfs_show_dc(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ strcpy(buf, gpio_get_value(GPIO_DC_DETE) ? "off" : "on");
++ strcat(buf, "\n");
++ return strlen(buf);
++}
++
++static ssize_t hhtech_sysfs_show_sd(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ strcpy(buf, gpio_get_value(GPIO_SD_WP) ? "off" : "on");
++ strcat(buf, "\n");
++ return strlen(buf);
++}
++
++static ssize_t hhtech_sysfs_show_system_flag(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ sprintf(buf, "%d\n", system_flag);
++ return strlen(buf);
++}
++
++static ssize_t hhtech_sysfs_show_headp(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ strcpy(buf, gpio_get_value(GPIO_HEADPHONE_S) ? "on" : "off");
++ strcat(buf, "\n");
++ return strlen(buf);
++}
++
++extern unsigned int tcc_adc_value(unsigned int tcc_adc_port);
++static int read_battery(void)
++{
++ int battery_life = 0, reference_value = 0;
++ static int old_battery_life = 1000, old_reference_value = 1000;
++
++ //ref voltage:2.4V,battery max :4.2V
++ if ((battery_life = tcc_adc_value(0)) == 0)
++ battery_life = old_battery_life;
++ else
++ old_battery_life = battery_life;
++
++ if ((reference_value = tcc_adc_value(1)) == 0)
++ reference_value = old_reference_value;
++ else
++ old_reference_value = reference_value;
++
++#ifdef CONFIG_LCD_4
++ battery_life = (battery_life * 25000) / (reference_value * 42);
++#else
++ battery_life = (battery_life * 24000) / (reference_value * 42);
++#endif
++ return battery_life;
++}
++
++static int get_battery_life(void)
++{
++ int i;
++ int count = 0;
++ int battery_life = 1000;//Default max power
++ int battery_life_sum = 0;
++ for (i = 0; i < 10; i++) {
++ int tmp = read_battery();
++ if (tmp < 700 || tmp > 1000)
++ continue;
++ battery_life_sum += tmp;
++ count++;
++ }
++ if (count)
++ battery_life = battery_life_sum / count;
++ return battery_life;
++}
++
++static unsigned int vpu_core_clock_addr = 0xF0400018;
++static unsigned int vpu_bus_clock_addr = 0xF0400014;
++
++static void shutdown_unused_devices(struct work_struct* work)
++{
++ unsigned int i,reg_val,addr;
++ unsigned long reg_write_value, reg_read_value;
++
++ //disable the uart 1-5
++ for(i = 1; i < 6; i++)
++ {
++ reg_val = *(volatile unsigned long *)(0xf0532008 + 0x100 * i);
++ *(volatile unsigned long *)(0xf0532008 + 0x100 * i) = reg_val & ~1;
++ reg_val = *(volatile unsigned long *)(0xf0532024 + 0x100 * i);
++ *(volatile unsigned long *)(0xf0532024 + 0x100 * i) = reg_val & ~3;
++ }
++
++ *(volatile unsigned long *)0xF053B004 = 0x0;//tsif off
++ *(volatile unsigned long *)0xF0510000 = 0x0;//mpefec off
++ *(volatile unsigned long *)0xF0240004 |= 0x80;//shut down clk of TV-OUT
++ *(volatile unsigned long *)0xF0200000 &= ~(0x1);//disable LCD0
++ *(volatile unsigned long *)0xF0251030 = 0x67;//shut down power of CIF,VIQE,LCDC0,MSCL1
++
++ //below is stop the peri clock
++ for(i = RB_USB11H; i < RB_ALLPERIPERALS; i++)
++ {
++ if((i == 0)||(i == 1)||(i == 3)||(i == 4)||(i == 7)||(i == 8)||(i == 11)||(i == 23)||(i == 24)||(i == 25)||(i == 26)||(i == 27)||(i == 31))
++ continue;
++ tca_ckc_setiobus(i,0);
++ }
++
++ //set the unused devices's source clock to null,start with
++ //LCD0(0x8c),Base Address = 0xF0400000
++ for(i = 0;i < 35; i++)
++ {
++ addr = 0x8c + i * 4;
++ if((addr == 0x90)||(addr == 0x94)||(addr == 0xa8)||(addr == 0xac)||(addr == 0xb0)||(addr == 0xb8)||(addr == 0xbc)||(addr == 0xf0)||(addr == 0xfc)||(addr == 0xec)||(addr == 0x104)||(addr == 0x108)||(addr == 0x10c)||(addr == 0x110))
++ continue;
++ *(volatile unsigned long *)(0xf040008c + i*4) &= ~(0x0f000000);
++ *(volatile unsigned long *)(0xf040008c + i*4) |= 0x0e000000;
++ }
++
++ set_hdmipwr_en(0);
++
++ reg_read_value = *(volatile unsigned int *)vpu_core_clock_addr;
++ reg_write_value = reg_read_value & 0xFFDFFFFF;
++ *((volatile unsigned int *) vpu_core_clock_addr) = (unsigned int)reg_write_value;
++
++ reg_read_value = *(volatile unsigned int *)vpu_bus_clock_addr;
++ reg_write_value = reg_read_value & 0xFFDFFFFF;
++ *((volatile unsigned int *) vpu_bus_clock_addr) = (unsigned int)reg_write_value;
++}
++
++static void battery_update_work(struct work_struct* work)
++{
++ int dc_status, charge_s;
++
++ dc_status = gpio_get_value(GPIO_DC_DETE) ? 0 : 1;
++
++ if(dc_status == 1) {
++ charge_s = (gpio_get_value(GPIO_CHARG_S1)<<1) + gpio_get_value(GPIO_CHARG_S2);
++ if(charge_s == 2)
++ current_battery = 1000;
++ else
++ current_battery = get_battery_life();
++ } else
++ current_battery = get_battery_life();
++ /* Add the current_battery with 40, because the current_battery value of some buggy batteries can't reach 1000 when fullly charged */
++ if(current_battery > 900)
++ current_battery += 40;
++ if(current_battery > 1000)
++ current_battery = 1000;
++ schedule_delayed_work(&battery_work, 30 * HZ);
++}
++
++static ssize_t hhtech_sysfs_show_battery(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ char s[20];
++
++ sprintf(s,"%d", current_battery);
++ strcpy(buf, s);
++ strcat(buf, "\n");
++ return strlen(buf);
++}
++
++static ssize_t hhtech_sysfs_charge_s(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ int s=(gpio_get_value(GPIO_CHARG_S1)<<1) + gpio_get_value(GPIO_CHARG_S2);
++ switch (s) {
++ case 0:
++ strcpy(buf,"0");
++ break;
++ case 1:
++ strcpy(buf,"1");
++ break;
++ case 2:
++ strcpy(buf,"2");
++ break;
++ case 3:
++ strcpy(buf,"3");
++ break;
++ }
++ strcat(buf, "\n");
++ return strlen(buf);
++}
++
++static ssize_t hhtech_sysfs_show_power(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", gpio_get_value(GPIO_PWR_EN));
++}
++
++static ssize_t hhtech_sysfs_store_power(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++// int val = simple_strtoul(buf, NULL, 0);
++ if (len < 1)
++ return -EINVAL;
++
++ if (strnicmp(buf, "on", 2) == 0 || strnicmp(buf, "1", 1) == 0)
++ set_sys_power(1); //poweron
++ else if (strnicmp(buf, "off", 3) == 0 || strnicmp(buf, "0", 1) == 0)
++ set_sys_power(0); //poweroff
++ else
++ return -EINVAL;
++ return len;
++}
++
++extern void memchange(unsigned int freq);
++static unsigned long now_memfreq = 3300000;
++static ssize_t hhtech_sysfs_show_memfreq(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%ld\n", now_memfreq);
++}
++
++static ssize_t hhtech_sysfs_store_memfreq(struct device *dev, struct device_attribute *attr, const char *buf,size_t len)
++{
++ unsigned long value;
++
++ if(len < 1)
++ return -EINVAL;
++
++ if(PMU_PWROFF & 0x80)
++ return len;
++
++ value = simple_strtoul(buf, NULL, 10);
++ now_memfreq = value;
++ memchange(value);
++
++ return len;
++}
++
++static void __iomem *rtc_base;
++static void __iomem *vic_base;
++char wakeup_time[50];
++EXPORT_SYMBOL(wakeup_time);
++extern VOLATILE void tca_alarm_setpmwkup(unsigned int rtcbaseaddresss,unsigned int vicbaseaddresss);
++static ssize_t hhtech_sysfs_show_rtc_wakeup(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ volatile rtctime lpTime;
++ tca_rtc_gettime(rtc_base, (rtctime *)&lpTime);
++ printk(KERN_EMERG"!!!dcs: %d-%d-%d-%d-%d-%d-%d\n",lpTime.wYear,lpTime.wMonth,lpTime.wDayOfWeek,lpTime.wDay,lpTime.wHour,lpTime.wMinute,lpTime.wSecond);
++ return 0;
++}
++static ssize_t hhtech_sysfs_store_rtc_wakeup(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t len)
++{
++ memcpy(wakeup_time,buf,strlen(buf));
++ tca_alarm_setpmwkup((unsigned int)rtc_base,(unsigned int)vic_base);
++ return 0;
++}
++
++//vbus pm ops
++static int vb_st;
++static ssize_t hhtech_sysfs_show_vb(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ vb_st = !!(PMU_PWROFF & 0x40);
++ return snprintf(buf, PAGE_SIZE, "%d\n", vb_st);
++}
++static ssize_t hhtech_sysfs_store_vb(struct device *dev, struct device_attribute *attr, const char *buf,size_t len)
++{
++ int reg_val, value;
++ if(len < 1)
++ return -EINVAL;
++
++ value = simple_strtoul(buf, NULL, 10);
++
++ vb_st = !!(PMU_PWROFF & 0x40);
++
++ if((value) && (!vb_st))
++ {
++ vb_st = value;
++ reg_val = PMU_PWROFF;
++ PMU_PWROFF = (reg_val | 0x40);
++ } else if((!value) && (vb_st))
++ {
++ vb_st = value;
++ reg_val = PMU_PWROFF;
++ PMU_PWROFF = (reg_val & (~0x40));
++ }
++
++ return len;
++}
++
++//dbus pm ops
++char lcd_buff[0x124];
++static int db_st;
++static ssize_t hhtech_sysfs_show_db(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ db_st = !!(PMU_PWROFF & 0x80);
++ return snprintf(buf, PAGE_SIZE, "%d\n", db_st);
++}
++static ssize_t hhtech_sysfs_store_db(struct device *dev, struct device_attribute *attr, const char *buf,size_t len)
++{
++ int value, reg_val;
++
++ if(len < 1)
++ return -EINVAL;
++
++ value = simple_strtoul(buf, NULL, 10);
++
++ db_st = !!(PMU_PWROFF & 0x80);
++
++ if((value) && (!db_st)) {
++ db_st = value;
++
++ memcpy(lcd_buff,(char *)0xF0204000,0x124);
++// gpio_direction_output(GPIO_LCD_PWR_EN, 0);
++// gpio_direction_output(GPIO_LCD_BACKLIGHT_EN, 0);
++
++ reg_val = PMU_PWROFF;
++ PMU_PWROFF = (reg_val | 0x80);
++
++ } else if((!value) && (db_st)) {
++ db_st = value;
++
++ reg_val = PMU_PWROFF;
++ PMU_PWROFF = (reg_val & (~0x80));
++
++ memcpy((char *)0xF0204000,lcd_buff,0x124);
++// gpio_direction_output(GPIO_LCD_PWR_EN, 1);
++// gpio_direction_output(GPIO_LCD_BACKLIGHT_EN, 1);
++
++ }
++
++ return len;
++}
++
++//gbus pm ops
++static int gb_st = 0;
++static unsigned long gbpd;
++static ssize_t hhtech_sysfs_show_gb(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", gb_st);
++}
++static ssize_t hhtech_sysfs_store_gb(struct device *dev, struct device_attribute *attr, const char *buf,size_t len)
++{
++ int value, reg_val;
++
++ if(len < 1)
++ return -EINVAL;
++
++ value = simple_strtoul(buf, NULL, 10);
++
++ if((value) && (!gb_st)) {
++ gb_st = value;
++ gbpd = *(volatile unsigned long *)0xF0004000;
++ *(volatile unsigned long *)0xF0004000 = 0x3;//Graphic Bus Power Down Register
++ reg_val = PMU_PWROFF;
++ PMU_PWROFF = (reg_val | 0x100);
++ } else if((!value) && (gb_st)) {
++ gb_st = value;
++ reg_val = PMU_PWROFF;
++ PMU_PWROFF = (reg_val & (~0x100));
++ *(volatile unsigned long *)0xF0004000 = gbpd;//Graphic Bus Power Down Register
++ }
++
++ return len;
++}
++
++//hdmi ops
++static int hd_st;
++static ssize_t hhtech_sysfs_show_hd(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ hd_st = !!(PMU_PWROFF & 0x2);
++ return snprintf(buf, PAGE_SIZE, "%d\n", hd_st);
++}
++static ssize_t hhtech_sysfs_store_hd(struct device *dev, struct device_attribute *attr, const char *buf,size_t len)
++{
++ int value, reg_val;
++
++ if(len < 1)
++ return -EINVAL;
++
++ value = simple_strtoul(buf, NULL, 10);
++
++ hd_st = !!(PMU_PWROFF & 0x2);
++
++ if((value) && (!hd_st)) {
++ hd_st = value;
++ *(volatile unsigned long *)0xF0255000 |= 0x2;// HDMI POWER DOWN
++ *(volatile unsigned long *)0xF0255000 &= ~(0x1);
++ reg_val = PMU_PWROFF;
++ PMU_PWROFF = (reg_val | 0x2);
++ } else if((!value) && (hd_st)) {
++ hd_st = value;
++ reg_val = PMU_PWROFF;
++ PMU_PWROFF = (reg_val & (~0x2));
++ *(volatile unsigned long *)0xF0255000 &= ~(0x2);//HDMI POWER ON
++ *(volatile unsigned long *)0xF0255000 |= 0x1;//HDMI ENABLE
++ }
++
++ return len;
++}
++
++//iobus pm ops
++static int io_st = 0;
++static ssize_t hhtech_sysfs_show_io(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", io_st);
++}
++static ssize_t hhtech_sysfs_store_io(struct device *dev, struct device_attribute *attr, const char *buf,size_t len)
++{
++ int value, reg_val;
++
++ if(len < 1)
++ return -EINVAL;
++
++ value = simple_strtoul(buf, NULL, 10);
++
++ if(value == 40) {
++ *(volatile unsigned long *)0xF0400010 = 0x2000b2;//change io bus to 40M
++ return len;
++ } else if(value == 156) {
++ *(volatile unsigned long *)0xF0400010 = 0x200022;//change io bus to 156M
++ return len;
++ }
++
++ if((value) && (!io_st)) {
++ io_st = value;
++ reg_val = PMU_PWROFF;
++ PMU_PWROFF = (reg_val | 0x200);
++ } else if((!value) && (io_st)) {
++ io_st = value;
++ reg_val = PMU_PWROFF;
++ PMU_PWROFF = (reg_val & (~0x200));
++ }
++
++ return len;
++}
++
++static unsigned int vpu_bus_codec_addr = 0xF0702000;
++static int vpu_on_st;
++static ssize_t hhtech_sysfs_show_vpu_on(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ if(!!(PMU_PWROFF & 0x40))
++ return snprintf(buf, PAGE_SIZE, "%d\n", 0);
++
++ vpu_on_st = !(*(volatile unsigned long *)vpu_bus_codec_addr & 0x4);
++ return snprintf(buf, PAGE_SIZE, "%d\n", vpu_on_st);
++}
++
++static ssize_t hhtech_sysfs_store_vpu_on(struct device *dev, struct device_attribute *attr, const char *buf,size_t len)
++{
++ unsigned long reg_write_value, reg_read_value;
++ int value;
++
++ if(len < 1)
++ return -EINVAL;
++
++ if(!!(PMU_PWROFF & 0x40))
++ return len;
++
++ value = simple_strtoul(buf, NULL, 10);
++ vpu_on_st = !(*(volatile unsigned long *)vpu_bus_codec_addr & 0x4);
++
++ if(value && !vpu_on_st)
++ {
++ reg_read_value = *(volatile unsigned int *)vpu_bus_codec_addr;
++ reg_write_value = reg_read_value & 0xFFFFFFFB;
++ *((volatile unsigned int *) vpu_bus_codec_addr) = (unsigned int)reg_write_value;
++ reg_read_value = *(volatile unsigned int *)vpu_core_clock_addr;
++ reg_write_value = reg_read_value | ((unsigned int)(1 << 21));
++ *((volatile unsigned int *) vpu_core_clock_addr) = (unsigned int)reg_write_value;
++ reg_read_value = *(volatile unsigned int *)vpu_bus_clock_addr;
++ reg_write_value = reg_read_value | ((unsigned int)(1 << 21));
++ *((volatile unsigned int *) vpu_bus_clock_addr) = (unsigned int)reg_write_value;
++
++ } else if(!value && vpu_on_st) {
++ reg_read_value = *(volatile unsigned int *)vpu_bus_codec_addr;
++ reg_write_value = reg_read_value | (1 << 2);
++ *((volatile unsigned int *) vpu_bus_codec_addr) = (unsigned int)reg_write_value;
++ reg_read_value = *(volatile unsigned int *)vpu_core_clock_addr;
++ reg_write_value = reg_read_value & 0xFFDFFFFF;
++ *((volatile unsigned int *) vpu_core_clock_addr) = (unsigned int)reg_write_value;
++ reg_read_value = *(volatile unsigned int *)vpu_bus_clock_addr;
++ reg_write_value = reg_read_value & 0xFFDFFFFF;
++ *((volatile unsigned int *) vpu_bus_clock_addr) = (unsigned int)reg_write_value;
++ }
++ return len;
++}
++
++//lcd pm ops
++static ssize_t hhtech_sysfs_show_lcd(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", gpio_get_value(GPIO_LCD_PWR_EN));
++}
++static ssize_t hhtech_sysfs_store_lcd(struct device *dev, struct device_attribute *attr, const char *buf,size_t len)
++{
++ int value;
++
++ if(len < 1)
++ return -EINVAL;
++
++ value = simple_strtoul(buf, NULL, 10);
++
++ value = !!value;
++
++ if (!value) {
++ bl_control(0);
++ }
++ gpio_direction_output(GPIO_LCD_PWR_EN, value);
++
++ return len;
++}
++
++int ts_en = 1;
++static ssize_t hhtech_sysfs_show_ts(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", ts_en);
++}
++
++static ssize_t hhtech_sysfs_store_ts(struct device *dev, struct device_attribute *attr, const char *buf, size_t len)
++{
++ if (len < 1)
++ return -EINVAL;
++ ts_en = simple_strtoul(buf, NULL, 10);
++ if (ts_en == 1)
++ bl_control(1);
++ return len;
++}
++
++int video_on = 0;
++EXPORT_SYMBOL(video_on);
++static ssize_t hhtech_sysfs_show_play_video(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", video_on);
++}
++static ssize_t hhtech_sysfs_store_play_video(struct device *dev, struct device_attribute *attr, const char *buf,size_t len)
++{
++ unsigned long reg_read_value, reg_write_value;
++ int value;
++
++ if(len < 1)
++ return -EINVAL;
++
++ value = simple_strtoul(buf, NULL, 10);
++ if(value) {
++ video_on = 1;
++ } else {
++ mdelay(10);
++
++ video_on = 0;
++
++ if(PMU_PWROFF & 0x40)
++ return len;
++
++ if(*(volatile unsigned long *)vpu_bus_codec_addr & 0x4)
++ return len;
++
++ //turn off video codec power and vbus & codec clock
++ reg_read_value = *(volatile unsigned int *)vpu_bus_codec_addr;
++ reg_write_value = reg_read_value | (0xf);
++ *((volatile unsigned int *) vpu_bus_codec_addr) = (unsigned int)reg_write_value;
++ reg_read_value = *(volatile unsigned int *)vpu_core_clock_addr;
++ reg_write_value = reg_read_value & 0xFFDFFFFF;
++ *((volatile unsigned int *) vpu_core_clock_addr) = (unsigned int)reg_write_value;
++ reg_read_value = *(volatile unsigned int *)vpu_bus_clock_addr;
++ reg_write_value = reg_read_value & 0xFFDFFFFF;
++ *((volatile unsigned int *) vpu_bus_clock_addr) = (unsigned int)reg_write_value;
++
++ //turn off video bus power
++ PMU_PWROFF |= 0x40;
++ *(volatile unsigned long *)0xF0200000 &= ~(0x1);//disable LCD0
++ *(volatile unsigned long *)0xF0251030 |= 0x67;//shut down power of CIF,VIQE,LCDC0,MSCL1
++ }
++
++ return len;
++}
++
++//config the wake up method,1 for button,2 for touchscreen,0 for both,set
++//before sleep
++int sleep_type = 0;
++EXPORT_SYMBOL(sleep_type);
++static ssize_t hhtech_sysfs_show_sleep_type(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", sleep_type);
++}
++static ssize_t hhtech_sysfs_store_sleep_type(struct device *dev, struct device_attribute *attr, const char *buf,size_t len)
++{
++ int value;
++
++ if(len < 1)
++ return -EINVAL;
++
++ value = simple_strtoul(buf, NULL, 10);
++ if((value != 0)&&(value != 1)&&(value != 2))
++ value = 0;
++
++ sleep_type = value;
++
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_otgmode(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", choosedevice);
++}
++
++static ssize_t hhtech_sysfs_store_otgmode(struct device *dev, struct device_attribute *attr, const char *buf,size_t len)
++{
++ int value;
++
++ if(len < 1)
++ return -EINVAL;
++
++ value = simple_strtoul(buf, NULL, 10);
++ choosedevice = value;
++
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_charge(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", gpio_get_value(GPIO_CHARGER_EN));
++}
++
++static ssize_t hhtech_sysfs_store_charge(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ if (len < 1)
++ return -EINVAL;
++
++ if (strnicmp(buf, "on", 2) == 0 || strnicmp(buf, "1", 1) == 0)
++ set_charge_mode(1); //860ma
++ else if (strnicmp(buf, "off", 3) == 0 || strnicmp(buf, "0", 1) == 0)
++ set_charge_mode(0); //200ma
++ else
++ return -EINVAL;
++ return len;
++}
++
++extern void tca_bkl_setpowerval(int inValue, unsigned int tmr_vaddr);
++extern void bl_control(bool flag);
++int curblight = 100;
++EXPORT_SYMBOL(curblight);
++
++static ssize_t hhtech_sysfs_show_blight(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", curblight);
++}
++
++static ssize_t hhtech_sysfs_store_blight(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ unsigned long value;
++ PTIMER vTimerAddr;
++
++ if (len < 1)
++ return -EINVAL;
++
++ value = simple_strtoul(buf, NULL, 10);
++ if(value >= 100) value = 99;
++
++ if(!value)
++ {
++ if(curblight)
++ bl_control(0);
++ curblight = 0;
++
++ }else {
++ if(!curblight)
++ bl_control(1);
++ vTimerAddr = (PTIMER)((unsigned int)&HwTMR_BASE);
++ tca_bkl_setpowerval(value,(unsigned int)vTimerAddr);
++ curblight = value;
++ }
++
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_tvout(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", gpio_get_value(GPIO_TVOUT_EN));
++}
++
++static ssize_t hhtech_sysfs_store_tvout(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ if (len < 1)
++ return -EINVAL;
++
++ if (strnicmp(buf, "on", 2) == 0 || strnicmp(buf, "1", 1) == 0)
++ set_tv_out(1); // open tv out
++ else if (strnicmp(buf, "off", 3) == 0 || strnicmp(buf, "0", 1) == 0)
++ set_tv_out(0); // close
++ else
++ return -EINVAL;
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_usbpwr(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", gpio_get_value(GPIO_USB_EN));
++}
++
++static ssize_t hhtech_sysfs_store_usbpwr(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ if (len < 1)
++ return -EINVAL;
++
++ if (strnicmp(buf, "on", 2) == 0 || strnicmp(buf, "1", 1) == 0)
++ set_usb_syspwr_en(1); // USB system power enable
++ else if (strnicmp(buf, "off", 3) == 0 || strnicmp(buf, "0", 1) == 0)
++ set_usb_syspwr_en(0); // disable
++ else
++ return -EINVAL;
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_usbhostpwr(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", gpio_get_value(GPIO_USB_HOSTPWR_EN));
++}
++
++static ssize_t hhtech_sysfs_store_usbhostpwr(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ if (len < 1)
++ return -EINVAL;
++
++ if (strnicmp(buf, "on", 2) == 0 || strnicmp(buf, "1", 1) == 0)
++ {
++ bluetooth_on = 1;
++ set_usb_hostpwr_en(1); // USB system power enable
++ }
++ else if (strnicmp(buf, "off", 3) == 0 || strnicmp(buf, "0", 1) == 0)
++ {
++ bluetooth_on = 0;
++ set_usb_hostpwr_en(0); // disable
++ }
++ else
++ return -EINVAL;
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_usbotgdrv(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", gpio_get_value(GPIO_USB_OTGDRV_EN));
++}
++
++static ssize_t hhtech_sysfs_store_usbotgdrv(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ if (len < 1)
++ return -EINVAL;
++
++ if (strnicmp(buf, "on", 2) == 0 || strnicmp(buf, "1", 1) == 0)
++ set_usb_otgdrv_en(1);
++ else if (strnicmp(buf, "off", 3) == 0 || strnicmp(buf, "0", 1) == 0)
++ set_usb_otgdrv_en(0);
++ else
++ return -EINVAL;
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_speaker(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", gpio_get_value(GPIO_SPEAKER_EN));
++}
++
++static ssize_t hhtech_sysfs_store_speaker(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ if (len < 1)
++ return -EINVAL;
++
++ if (strnicmp(buf, "on", 2) == 0 || strnicmp(buf, "1", 1) == 0) {
++ if (!gpio_get_value(GPIO_HEADPHONE_S))
++ set_speaker_en(1); // speaker enable
++ user_disable_speaker = 0;
++ } else if (strnicmp(buf, "off", 3) == 0 || strnicmp(buf, "0", 1) == 0) {
++ set_speaker_en(0); // disable
++ user_disable_speaker = 1;
++ } else
++ return -EINVAL;
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_wifi(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", gpio_get_value(GPIO_WIFI_EN));
++}
++
++static ssize_t hhtech_sysfs_store_wifi(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ if (len < 1)
++ return -EINVAL;
++
++ if (strnicmp(buf, "on", 2) == 0 || strnicmp(buf, "1", 1) == 0)
++ set_wifi_en(1); // wifi enable
++ else if (strnicmp(buf, "off", 3) == 0 || strnicmp(buf, "0", 1) == 0)
++ set_wifi_en(0); // disable
++ else
++ return -EINVAL;
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_hdmi(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", gpio_get_value(GPIO_HDMI_EN));
++}
++
++static ssize_t hhtech_sysfs_store_hdmi(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ if (len < 1)
++ return -EINVAL;
++
++ if (strnicmp(buf, "on", 2) == 0 || strnicmp(buf, "1", 1) == 0)
++ set_hdmi_en(1); // hdmi enable
++ else if (strnicmp(buf, "off", 3) == 0 || strnicmp(buf, "0", 1) == 0)
++ set_hdmi_en(0); // disable
++ else
++ return -EINVAL;
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_led1(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", !gpio_get_value(GPIO_LED1_EN));
++}
++
++static ssize_t hhtech_sysfs_store_led1(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ if (len < 1)
++ return -EINVAL;
++
++ if (strnicmp(buf, "on", 2) == 0 || strnicmp(buf, "1", 1) == 0)
++ set_led1_en(1);
++ else if (strnicmp(buf, "off", 3) == 0 || strnicmp(buf, "0", 1) == 0)
++ set_led1_en(0);
++ else
++ return -EINVAL;
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_led2(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", !gpio_get_value(GPIO_LED2_EN));
++}
++
++static ssize_t hhtech_sysfs_store_led2(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ if (len < 1)
++ return -EINVAL;
++
++ if (strnicmp(buf, "on", 2) == 0 || strnicmp(buf, "1", 1) == 0)
++ set_led2_en(1);
++ else if (strnicmp(buf, "off", 3) == 0 || strnicmp(buf, "0", 1) == 0)
++ set_led2_en(0);
++ else
++ return -EINVAL;
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_rtc_wk_time(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%ld\n", rtc_wakeup_time);
++}
++
++static ssize_t hhtech_sysfs_store_rtc_wk_time(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ unsigned long value = simple_strtoul(buf, NULL, 10);
++
++ if (len < 1)
++ return -EINVAL;
++
++ if (value < 0 || value > 2 * 60 * 60)
++ return -ERANGE;
++ else
++ rtc_wakeup_time = value;
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_wk_status(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", wakeup_status);
++}
++
++static ssize_t hhtech_sysfs_show_color_brightness(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ unsigned long reg_val;
++ char val;
++
++ reg_val = *(volatile unsigned long *)0xF0204070;
++ val = (reg_val >> 8) & 0xFF;
++ val += 128;
++ return snprintf(buf, PAGE_SIZE, "%d\n", val);
++}
++
++static ssize_t hhtech_sysfs_store_color_brightness(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ unsigned long value = simple_strtoul(buf, NULL, 10);
++ char val;
++
++ value = value > 255 ? 255 : value;
++ val = value - 128;
++
++ if (len < 1)
++ return -EINVAL;
++
++ value = val;
++ value <<= 8;
++ *(volatile unsigned long *)0xF0204070 &= ~0xFF00;
++ *(volatile unsigned long *)0xF0204070 |= value;
++
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_color_contrast(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ unsigned long reg_val;
++ char val;
++
++ reg_val = *(volatile unsigned long *)0xF0204070;
++ val = reg_val & 0xFF;
++ val += 128;
++ return snprintf(buf, PAGE_SIZE, "%d\n", val);
++}
++
++static ssize_t hhtech_sysfs_store_color_contrast(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ unsigned long value = simple_strtoul(buf, NULL, 10);
++ char val;
++ value = value > 255 ? 255 : value;
++ val = value - 128;
++
++ if (len < 1)
++ return -EINVAL;
++
++ value = val;
++ *(volatile unsigned long *)0xF0204070 &= ~0xFF;
++ *(volatile unsigned long *)0xF0204070 |= value;
++
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_image_brightness(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ unsigned long reg_val;
++ char val;
++
++ reg_val = *(volatile unsigned long *)0xF02040AC;
++ val = (reg_val >> 8) & 0xFF;
++ val += 128;
++ return snprintf(buf, PAGE_SIZE, "%d\n", val);
++}
++
++static ssize_t hhtech_sysfs_store_image_brightness(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ unsigned long value = simple_strtoul(buf, NULL, 10);
++ char val = value;
++
++ value = value > 255 ? 255 : value;
++ val = value - 128;
++
++ if (len < 1)
++ return -EINVAL;
++
++ value = val;
++ value <<= 8;
++ *(volatile unsigned long *)0xF02040AC &= ~0xFF00;
++ *(volatile unsigned long *)0xF02040AC |= value;
++
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_image_contrast(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ unsigned long reg_val;
++ char val;
++
++ reg_val = *(volatile unsigned long *)0xF02040AC;
++ val = reg_val & 0xFF;
++ val += 128;
++ return snprintf(buf, PAGE_SIZE, "%d\n", val);
++}
++
++static ssize_t hhtech_sysfs_store_image_contrast(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ unsigned long value = simple_strtoul(buf, NULL, 10);
++ char val;
++
++ value = value > 255 ? 255 : value;
++ val = value - 128;
++
++ if (len < 1)
++ return -EINVAL;
++
++ value = val;
++ *(volatile unsigned long *)0xF02040AC &= ~0xFF;
++ *(volatile unsigned long *)0xF02040AC |= value;
++
++ return len;
++}
++
++static ssize_t hhtech_sysfs_show_mu350_first_plug_in(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", mu350_first_plug_in);
++}
++
++static ssize_t hhtech_sysfs_store_mu350_first_plug_in(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ if (len < 1)
++ return -EINVAL;
++
++ if (strnicmp(buf, "1", 1) == 0)
++ mu350_first_plug_in = 1;
++ else if (strnicmp(buf, "0", 1) == 0) {
++ mu350_first_plug_in = 0;
++ /* first change to device mode, then change to host mode */
++#if defined(CONFIG_LCD_4)
++ set_usb_otgdrv_en(0);
++ set_usb_otgdrv_en(1);
++#else
++ choosedevice = 1;
++ choosedevice = 0;
++#endif
++ }
++ else
++ return -EINVAL;
++ return len;
++}
++
++extern void headp_update_mixer(struct work_struct* work);
++
++/* headphone plug in and out Interrupt handle */
++static irqreturn_t headp_irq(int irq, void *dev_id)
++{
++ volatile PPIC pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++ unsigned int headphone_s = gpio_get_value(GPIO_HEADPHONE_S);
++
++ disable_irq(IRQ_HEADPHONE);
++ BITSET(pPIC->CLR0, 1<<IRQ_HEADPHONE);
++
++ if (user_disable_speaker == 0) {
++ if (headphone_s)
++ gpio_set_value(GPIO_SPEAKER_EN, 0);
++ else
++ gpio_set_value(GPIO_SPEAKER_EN, 1);
++#if defined (CONFIG_LCD_4)
++ cancel_delayed_work(&headp_detect_work);
++ schedule_delayed_work(&headp_detect_work, msecs_to_jiffies(80));
++#endif
++ }
++
++ if (gpio_get_value(GPIO_TVOUT_EN)) {
++ if (headphone_s)
++ atomic_set(&hpd_struct.state, 1);
++ else
++ atomic_set(&hpd_struct.state, 0);
++ wake_up_interruptible(&hpd_struct.waitq);
++ }
++
++ enable_irq(IRQ_HEADPHONE);
++
++ return IRQ_HANDLED;
++}
++
++/* dc plug out Interrupt handle */
++static irqreturn_t dc_irq(int irq, void *dev_id)
++{
++ volatile PPIC pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++
++ disable_irq(IRQ_DC);
++ BITSET(pPIC->CLR0, 1<<IRQ_DC);
++ mdelay(100);
++ battery_update_work(NULL);
++ enable_irq(IRQ_DC);
++
++ return IRQ_HANDLED;
++}
++
++/* hpd plug out Interrupt handle */
++extern void tcc_lcd_on(void);
++extern void tca_lcdc_setimgchenable(int id, unsigned int ch, unsigned int flag);
++static irqreturn_t hpd_irq(int irq, void *dev_id)
++{
++ volatile PPIC pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++ unsigned int hpd_s = gpio_get_value(GPIO_HDMI_HPD);
++
++ disable_irq(IRQ_HPD);
++ BITSET(pPIC->CLR0, 1<<IRQ_HPD);
++ if(hpd_s) {
++ gpio_direction_output(GPIO_USB_EN, 1); // open USB power
++ gpio_direction_output(GPIO_HDMI_EN, 1); // open HDMI power
++ } else {
++ if(gpio_get_value(GPIO_HDMI_EN)) {
++ tca_lcdc_setimgchenable(1, 2, 1); // open FB2 display
++ tcc_lcd_on(); // open LCD controller
++ }
++ }
++ enable_irq(IRQ_HPD);
++
++ return IRQ_HANDLED;
++}
++
++static DEVICE_ATTR(system_flag, 0444, hhtech_sysfs_show_system_flag, NULL);
++static DEVICE_ATTR(headphone_s, 0444, hhtech_sysfs_show_headp, NULL);
++static DEVICE_ATTR(dc_s, 0444, hhtech_sysfs_show_dc, NULL);
++static DEVICE_ATTR(sd_s, 0444, hhtech_sysfs_show_sd, NULL);
++static DEVICE_ATTR(charge_s, 0444,hhtech_sysfs_charge_s , NULL);
++static DEVICE_ATTR(battery_s, 0444, hhtech_sysfs_show_battery, NULL);
++static DEVICE_ATTR(pwr_en, 0666, hhtech_sysfs_show_power, hhtech_sysfs_store_power);
++static DEVICE_ATTR(memfreq, 0666, hhtech_sysfs_show_memfreq, hhtech_sysfs_store_memfreq);
++static DEVICE_ATTR(rtc_wakeup, 0666, hhtech_sysfs_show_rtc_wakeup, hhtech_sysfs_store_rtc_wakeup);
++static DEVICE_ATTR(vb_pwoff, 0666, hhtech_sysfs_show_vb, hhtech_sysfs_store_vb);
++static DEVICE_ATTR(db_pwoff, 0666, hhtech_sysfs_show_db, hhtech_sysfs_store_db);
++static DEVICE_ATTR(gb_pwoff, 0666, hhtech_sysfs_show_gb, hhtech_sysfs_store_gb);
++static DEVICE_ATTR(hd_pwoff, 0666, hhtech_sysfs_show_hd, hhtech_sysfs_store_hd);
++static DEVICE_ATTR(io_pwoff, 0666, hhtech_sysfs_show_io, hhtech_sysfs_store_io);
++static DEVICE_ATTR(vpu_on, 0666, hhtech_sysfs_show_vpu_on, hhtech_sysfs_store_vpu_on);
++static DEVICE_ATTR(lcd_on, 0666, hhtech_sysfs_show_lcd, hhtech_sysfs_store_lcd);
++static DEVICE_ATTR(ts_en, 0666, hhtech_sysfs_show_ts, hhtech_sysfs_store_ts);
++static DEVICE_ATTR(play_video, 0666, hhtech_sysfs_show_play_video , hhtech_sysfs_store_play_video);
++static DEVICE_ATTR(sleep_tp, 0666, hhtech_sysfs_show_sleep_type , hhtech_sysfs_store_sleep_type);
++static DEVICE_ATTR(otg_mode, 0666, hhtech_sysfs_show_otgmode, hhtech_sysfs_store_otgmode);
++static DEVICE_ATTR(charge_en, 0666, hhtech_sysfs_show_charge, hhtech_sysfs_store_charge);
++static DEVICE_ATTR(backlight_level, 0666,hhtech_sysfs_show_blight, hhtech_sysfs_store_blight);
++static DEVICE_ATTR(tvout_en, 0666,hhtech_sysfs_show_tvout, hhtech_sysfs_store_tvout);
++static DEVICE_ATTR(usbpwr_en, 0666, hhtech_sysfs_show_usbpwr, hhtech_sysfs_store_usbpwr);
++static DEVICE_ATTR(usbhostpwr_en, 0666, hhtech_sysfs_show_usbhostpwr, hhtech_sysfs_store_usbhostpwr);
++static DEVICE_ATTR(usbotgdrv_en, 0666, hhtech_sysfs_show_usbotgdrv, hhtech_sysfs_store_usbotgdrv);
++static DEVICE_ATTR(speaker_en, 0666, hhtech_sysfs_show_speaker, hhtech_sysfs_store_speaker);
++static DEVICE_ATTR(wifi_en, 0666, hhtech_sysfs_show_wifi, hhtech_sysfs_store_wifi);
++static DEVICE_ATTR(hdmi_en, 0666, hhtech_sysfs_show_hdmi, hhtech_sysfs_store_hdmi);
++static DEVICE_ATTR(led1_en, 0666, hhtech_sysfs_show_led1, hhtech_sysfs_store_led1);
++static DEVICE_ATTR(led2_en, 0666, hhtech_sysfs_show_led2, hhtech_sysfs_store_led2);
++static DEVICE_ATTR(rtc_wk_time, 0666, hhtech_sysfs_show_rtc_wk_time, hhtech_sysfs_store_rtc_wk_time);
++static DEVICE_ATTR(wk_status, 0666, hhtech_sysfs_show_wk_status, NULL);
++static DEVICE_ATTR(color_brightness, 0666, hhtech_sysfs_show_color_brightness, hhtech_sysfs_store_color_brightness);
++static DEVICE_ATTR(color_contrast, 0666, hhtech_sysfs_show_color_contrast, hhtech_sysfs_store_color_contrast);
++static DEVICE_ATTR(image_brightness, 0666, hhtech_sysfs_show_image_brightness, hhtech_sysfs_store_image_brightness);
++static DEVICE_ATTR(image_contrast, 0666, hhtech_sysfs_show_image_contrast, hhtech_sysfs_store_image_contrast);
++static DEVICE_ATTR(mu350_first_plug_in, 0666, hhtech_sysfs_show_mu350_first_plug_in, hhtech_sysfs_store_mu350_first_plug_in);
++
++static struct attribute *attrs[] = {
++ &dev_attr_system_flag.attr,
++ &dev_attr_headphone_s.attr,
++ &dev_attr_dc_s.attr,
++ &dev_attr_sd_s.attr,
++ &dev_attr_charge_s.attr,
++ &dev_attr_battery_s.attr,
++ &dev_attr_pwr_en.attr,
++ &dev_attr_memfreq.attr,
++ &dev_attr_rtc_wakeup.attr,
++ &dev_attr_vb_pwoff.attr,
++ &dev_attr_db_pwoff.attr,
++ &dev_attr_gb_pwoff.attr,
++ &dev_attr_hd_pwoff.attr,
++ &dev_attr_io_pwoff.attr,
++ &dev_attr_vpu_on.attr,
++ &dev_attr_lcd_on.attr,
++ &dev_attr_ts_en.attr,
++ &dev_attr_play_video.attr,
++ &dev_attr_sleep_tp.attr,
++#if defined(CONFIG_LCD_7)
++ &dev_attr_otg_mode.attr,
++#endif
++ &dev_attr_charge_en.attr,
++ &dev_attr_backlight_level.attr,
++ &dev_attr_tvout_en.attr,
++ &dev_attr_usbpwr_en.attr,
++ &dev_attr_usbhostpwr_en.attr,
++ &dev_attr_usbotgdrv_en.attr,
++ &dev_attr_speaker_en.attr,
++ &dev_attr_wifi_en.attr,
++ &dev_attr_hdmi_en.attr,
++ &dev_attr_led1_en.attr,
++ &dev_attr_led2_en.attr,
++ &dev_attr_rtc_wk_time.attr,
++ &dev_attr_wk_status.attr,
++ &dev_attr_color_brightness.attr,
++ &dev_attr_color_contrast.attr,
++ &dev_attr_image_brightness.attr,
++ &dev_attr_image_contrast.attr,
++ &dev_attr_mu350_first_plug_in.attr,
++ NULL,
++};
++
++static struct attribute_group attr_group = {
++ .attrs = attrs,
++};
++
++static int hhtech_gpio_sysfs_register(struct device* dev)
++{
++ return sysfs_create_group(&dev->kobj, &attr_group);
++}
++#else
++static int hhtech_gpio_sysfs_register(struct device* dev)
++{
++ return 0;
++}
++#endif
++
++ssize_t hpd_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
++{
++ ssize_t retval;
++
++ if (wait_event_interruptible(hpd_struct.waitq, atomic_read(&hpd_struct.state) != -1))
++ return -ERESTARTSYS;
++
++ spin_lock_irq(&hpd_struct.lock);
++ retval = put_user(atomic_read(&hpd_struct.state), (unsigned int __user *) buffer);
++ atomic_set(&hpd_struct.state, -1);
++ spin_unlock_irq(&hpd_struct.lock);
++
++ return retval;
++}
++
++unsigned int hpd_poll(struct file *file, poll_table *wait)
++{
++ poll_wait(file, &hpd_struct.waitq, wait);
++
++ if (atomic_read(&hpd_struct.state) != -1)
++ return POLLIN | POLLRDNORM;
++
++ return 0;
++}
++
++static const struct file_operations hpd_fops =
++{
++ .owner = THIS_MODULE,
++ .open = NULL,
++ .release = NULL,
++ .read = hpd_read,
++ .poll = hpd_poll,
++};
++
++static struct miscdevice hpd_misc_device =
++{
++ HPD_MINOR,
++ "tv_hpd",
++ &hpd_fops,
++};
++
++extern void memchange(unsigned int freq);
++static int hhtech_gpio_probe(struct platform_device *pdev)
++{
++ int retval;
++ volatile PGPIO pGPIO = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
++ volatile PPIC pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++
++ retval = hhtech_gpio_sysfs_register(&pdev->dev);
++ if (retval < 0) {
++ printk(KERN_ERR "Create sys fs fail\n");
++ return -1;
++ }
++
++ rtc_base = (void __iomem *)tcc_p2v(HwRTC_BASE);
++ vic_base = (void __iomem *)tcc_p2v(HwVIC_BASE);
++
++ gpio_direction_input(GPIO_SD_WP);
++ gpio_direction_input(GPIO_HEADPHONE_S);
++ gpio_direction_input(GPIO_DC_DETE);
++ gpio_direction_input(GPIO_CHARG_S1);
++ gpio_direction_input(GPIO_CHARG_S2);
++ gpio_direction_input(GPIO_PWR_HOLD);
++ gpio_direction_input(GPIO_HDMI_HPD);
++
++ gpio_direction_output(GPIO_USB_EN, 0); //close
++ gpio_direction_output(GPIO_USB_HOSTPWR_EN, 0); //close
++
++ gpio_direction_output(GPIO_USB_OTGDRV_EN, 0); //close
++ gpio_direction_output(GPIO_CHARGER_EN, 0); //200ma
++ gpio_direction_output(GPIO_TVOUT_EN, 0); //close
++ gpio_direction_output(GPIO_WIFI_EN, 1); //open
++ gpio_direction_output(GPIO_HDMI_EN, 0); //close
++ gpio_direction_output(GPIO_LED1_EN, 0); //turn on
++ if (NULL == strstr(saved_command_line, "rdinit"))
++ gpio_direction_output(GPIO_LED2_EN, 1); //turn off
++ else
++ gpio_direction_output(GPIO_LED2_EN, 0); //turn on
++
++ /* Set GPIOD[7](18) to the interrupt source of INT_EI7 */
++ BITCSET(pGPIO->EINTSEL1, Hw30-Hw24, 18<<24);
++ BITSET(pPIC->INTMSK0, 1<<IRQ_HEADPHONE); // unmask the interrupt
++ BITCLR(pPIC->MODE0, 1<<IRQ_HEADPHONE); // set interrupt as edge-triggered mode
++ BITSET(pPIC->MODEA0, 1<<IRQ_HEADPHONE); // set interrupt as both edge triggered mode
++ if (gpio_get_value(GPIO_HEADPHONE_S)) // headphone inserted
++ gpio_direction_output(GPIO_SPEAKER_EN, 0); // close speaker
++ else // headphone out
++ gpio_direction_output(GPIO_SPEAKER_EN, 1); // open speaker
++
++ /* Set GPIOF[8](39) to the interrupt source of INT_EI4 */
++ BITCSET(pGPIO->EINTSEL1, Hw7-Hw0, 39);
++ BITSET(pPIC->INTMSK0, 1<<IRQ_DC); // unmask the interrupt
++ BITCLR(pPIC->MODE0, 1<<IRQ_DC); // set interrupt as edge-triggered mode
++
++ /* Set GPIOA[14](14) to the interrupt source of INT_EI3 */
++ BITCSET(pGPIO->EINTSEL0, Hw31-Hw24, 14<<24);
++ BITSET(pPIC->INTMSK0, 1<<IRQ_HPD); // unmask the interrupt
++ BITCLR(pPIC->MODE0, 1<<IRQ_HPD); // set interrupt as edge-triggered mode
++ BITSET(pPIC->MODEA0, 1<<IRQ_HPD); // set interrupt as both edge triggered mode
++
++ if (misc_register(&hpd_misc_device))
++ {
++ printk(KERN_WARNING "TV_HPD: Couldn't register device 10, %d.\n", HPD_MINOR);
++ return -EBUSY;
++ }
++ init_waitqueue_head(&hpd_struct.waitq);
++ spin_lock_init(&hpd_struct.lock);
++ atomic_set(&hpd_struct.state, -1);
++
++ retval = request_irq(IRQ_HEADPHONE, headp_irq,
++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "Headphone detect", NULL);
++ if (retval) {
++ printk(KERN_ERR "Request headphone detect fail\n");
++ goto error1;
++ }
++
++ retval = request_irq(IRQ_DC, dc_irq, IRQF_TRIGGER_FALLING, "DC detect", NULL);
++ if (retval) {
++ printk(KERN_ERR "Request dc detect fail\n");
++ goto error1;
++ }
++
++ retval = request_irq(IRQ_HPD, hpd_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "HPD detect", NULL);
++ if (retval) {
++ printk(KERN_ERR "Request HPD detect fail\n");
++ goto error1;
++ }
++
++#if defined (CONFIG_LCD_4)
++ INIT_DELAYED_WORK(&headp_detect_work, headp_update_mixer);
++ headp_update_mixer(NULL);
++#endif
++ INIT_DELAYED_WORK(&battery_work, battery_update_work);
++ INIT_DELAYED_WORK(&shutdown_work,shutdown_unused_devices);
++// battery_update_work(NULL);
++ schedule_delayed_work(&battery_work, 4 * HZ);
++ schedule_delayed_work(&shutdown_work, 30 * HZ);
++
++ memchange(3300000);
++ mdelay(50);
++
++ return 0;
++
++error1:
++ return retval;
++}
++
++static int hhtech_gpio_remove(struct platform_device *dev)
++{
++ misc_deregister(&hpd_misc_device);
++ free_irq(IRQ_HEADPHONE, NULL);
++ free_irq(IRQ_DC, NULL);
++ return 0;
++}
++
++#ifdef CONFIG_PM
++#define SAVE_ITEM(x) \
++ { .reg = (unsigned long)(x) }
++struct sleep_save_phy {
++ unsigned long reg;
++ unsigned long val;
++};
++static struct sleep_save_phy save_gpio[] = {
++ SAVE_ITEM(GPIO_USB_HOSTPWR_EN),
++ SAVE_ITEM(GPIO_USB_OTGDRV_EN),
++ SAVE_ITEM(GPIO_USB_EN),
++};
++
++static void gpio_do_save(struct sleep_save_phy *ptr, int count)
++{
++ for (; count > 0; count--, ptr++)
++ ptr->val = gpio_get_value(ptr->reg);
++}
++
++static void gpio_do_load(struct sleep_save_phy *ptr, int count)
++{
++ for (; count > 0; count--, ptr++)
++ gpio_set_value(ptr->reg, ptr->val);
++}
++
++static int hhtech_gpio_suspend(struct platform_device *dev, pm_message_t state)
++{
++ disable_irq(IRQ_DC);
++ /* Becareful: MMC must be suspended after this driver */
++ set_wifi_en(0);
++ /* Close USB Power */
++ gpio_do_save(save_gpio, ARRAY_SIZE(save_gpio));
++ set_usb_hostpwr_en(0);
++ set_usb_otgdrv_en(0);
++ set_usb_syspwr_en(0);
++ set_charge_mode(1);
++ if(!user_disable_speaker)
++ set_speaker_en(0);
++
++ return 0;
++}
++extern void __iomem *tcc_rtc_base;
++
++#define RTCPEND 0x48
++#define TCC_INTP_ALM (1<<6)
++
++static int hhtech_gpio_resume(struct platform_device *dev)
++{
++ int dc_status;
++
++ if(!user_disable_speaker)
++ set_speaker_en(1);
++ set_charge_mode(0);
++ dc_status = gpio_get_value(GPIO_DC_DETE) ? 0 : 1;
++ wakeup_status = 0;
++
++ /*if (0 == dc_status) {
++ if (get_battery_life() < 833) // battery volume < 3.5 V
++ set_sys_power(0);
++ if (readb(tcc_rtc_base + RTCPEND) & TCC_INTP_ALM)
++ wakeup_status = 1;
++ }*/
++
++ gpio_do_load(save_gpio, ARRAY_SIZE(save_gpio));
++ set_wifi_en(1);
++ enable_irq(IRQ_DC);
++ return 0;
++}
++#else
++#define hhtech_gpio_suspend NULL
++#define hhtech_gpio_resume NULL
++#endif
++
++
++static struct platform_driver hhtech_gpio = {
++ .probe = hhtech_gpio_probe,
++ .remove = hhtech_gpio_remove,
++ .suspend = hhtech_gpio_suspend,
++ .resume = hhtech_gpio_resume,
++ .driver = {
++ .name = "hhtech_gpio",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init hhtech_gpio_init(void)
++{
++ user_disable_speaker = 0;
++ return platform_driver_register(&hhtech_gpio);
++}
++
++static void __exit hhtech_gpio_exit(void)
++{
++ platform_driver_unregister(&hhtech_gpio);
++}
++
++module_init(hhtech_gpio_init);
++module_exit(hhtech_gpio_exit);
++
++MODULE_AUTHOR("gqwang");
++MODULE_DESCRIPTION("TCC8900 GPIO driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/char/mem.c b/drivers/char/mem.c
+index 6431f69..f5c9be1 100644
+--- a/drivers/char/mem.c
++++ b/drivers/char/mem.c
+@@ -791,7 +791,7 @@ static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
+
+ static int open_port(struct inode * inode, struct file * filp)
+ {
+- return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
++ return 0;
+ }
+
+ #define zero_lseek null_lseek
+diff --git a/drivers/char/tca_backlight.c b/drivers/char/tca_backlight.c
+new file mode 100644
+index 0000000..483a3db
+--- /dev/null
++++ b/drivers/char/tca_backlight.c
+@@ -0,0 +1,133 @@
++
++/****************************************************************************
++ * FileName : tca_backlight.c
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++/*****************************************************************************
++*
++* Header Files Include
++*
++******************************************************************************/
++#include "bsp.h"
++#include "tca_backlight.h"
++
++/*****************************************************************************
++*
++* Defines
++*
++******************************************************************************/
++#define BKL_LEVEL_MAX (50)
++/*****************************************************************************
++*
++* structures
++*
++******************************************************************************/
++
++/*****************************************************************************
++*
++* Variables
++*
++******************************************************************************/
++
++/*****************************************************************************
++*
++* Functions
++*
++******************************************************************************/
++
++/*****************************************************************************
++* Function Name : tca_bkl_init()
++******************************************************************************/
++void tca_bkl_init(unsigned int tmr_vaddr, unsigned int gpio_vaddr)
++{
++ PTIMER vTimerAddr = (PTIMER) tmr_vaddr;
++ PGPIO vGpioAddr = (PGPIO) gpio_vaddr;
++
++ vTimerAddr->TCFG1 = 0x124;
++ vTimerAddr->TREF1 = BKL_LEVEL_MAX;
++ vTimerAddr->TMREF1= BKL_LEVEL_MAX;
++ vTimerAddr->TCFG1 = 0x125;
++
++ BITCSET(vGpioAddr->GPAFN0, Hw24-Hw20, Hw21);
++ BITSET(vGpioAddr->GPAEN,Hw5);
++ BITSET(vGpioAddr->GPADAT,Hw5);
++}
++
++/*****************************************************************************
++* Function Name : tca_bkl_powerup()
++******************************************************************************/
++void tca_bkl_powerup(unsigned int tmr_vaddr, unsigned int gpio_vaddr)
++{
++
++ //PTIMER vTimerAddr = (PTIMER) tmr_vaddr;
++ PGPIO vGpioAddr = (PGPIO) gpio_vaddr;
++
++ BITCSET(vGpioAddr->GPAFN0,Hw24-Hw20,Hw21);//set GPIO_A5 as TCO1 Mode
++ BITSET(vGpioAddr->GPAEN,Hw5);
++ BITSET(vGpioAddr->GPADAT,Hw5);
++}
++
++/*****************************************************************************
++* Function Name : tca_bkl_powerdown()
++******************************************************************************/
++void tca_bkl_powerdown(unsigned int tmr_vaddr, unsigned int gpio_vaddr)
++{
++
++ //PTIMER vTimerAddr = (PTIMER) tmr_vaddr;
++ PGPIO vGpioAddr = (PGPIO) gpio_vaddr;
++
++ //BL ON/OFF config
++ BITCLR(vGpioAddr->GPAFN0,Hw24-Hw20);//clear GPIO_A5 as TCO1 Mode
++ BITSET(vGpioAddr->GPAEN,Hw5);
++ BITCLR(vGpioAddr->GPADAT,Hw5);
++}
++
++
++/*****************************************************************************
++* Function Name : tca_bkl_setpowerval()
++******************************************************************************/
++void tca_bkl_setpowerval(int inValue, unsigned int tmr_vaddr)
++{
++ PTIMER vTimerAddr = (PTIMER) tmr_vaddr;
++
++ if(inValue <= 0)
++ inValue=1;
++
++ if(inValue > 100)
++ inValue=100;
++
++ vTimerAddr->TMREF1 = (BKL_LEVEL_MAX*inValue)/100;
++}
++
++
++/*****************************************************************************
++* Function Name : tca_bkl_getpowerval()
++******************************************************************************/
++int tca_bkl_getpowerval(unsigned int tmr_vaddr)
++{
++ int outValue=0;
++ PTIMER vTimerAddr = (PTIMER) tmr_vaddr;
++
++ outValue = (int)((100*vTimerAddr->TMREF1)/BKL_LEVEL_MAX);
++
++ return outValue;
++}
++
++/*****************************************************************************
++* Function Name : tca_bkl_getpowerval()
++******************************************************************************/
++int tca_bkl_gettmrref(unsigned int tmr_vaddr)
++{
++ int tmrref=0;
++ PTIMER vTimerAddr = (PTIMER) tmr_vaddr;
++
++ tmrref = vTimerAddr->TMREF1;
++
++ return tmrref;
++}
+diff --git a/drivers/char/tca_backlight.h b/drivers/char/tca_backlight.h
+new file mode 100644
+index 0000000..ed72857
+--- /dev/null
++++ b/drivers/char/tca_backlight.h
+@@ -0,0 +1,74 @@
++/****************************************************************************
++ * FileName : tca_backlight.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++#ifndef __TCA_BKL_H__
++#define __TCA_BKL_H__
++
++/*****************************************************************************
++*
++* Defines
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* Enum
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* Type Defines
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* Structures
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* External Variables
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* External Functions
++*
++******************************************************************************/
++#ifdef __cplusplus
++extern
++"C" {
++#endif
++
++void tca_bkl_init(unsigned int tmr_vaddr, unsigned int gpio_vaddr);
++void tca_bkl_powerup(unsigned int tmr_vaddr, unsigned int gpio_vaddr);
++void tca_bkl_powerdown(unsigned int tmr_vaddr, unsigned int gpio_vaddr);
++
++void tca_bkl_setpowerval(int inValue, unsigned int tmr_vaddr);
++int tca_bkl_getpowerval(unsigned int tmr_vaddr);
++
++int tca_bkl_gettmrref(unsigned int tmr_vaddr);
++
++#ifdef __cplusplus
++ }
++#endif
++
++#endif //__TCA_BKL_H__
++
+diff --git a/drivers/char/tcc_backlight.c b/drivers/char/tcc_backlight.c
+new file mode 100644
+index 0000000..dca0e56
+--- /dev/null
++++ b/drivers/char/tcc_backlight.c
+@@ -0,0 +1,426 @@
++/*
++ * linux/drivers/char/tcc_backlight.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 10th Jun, 2008
++ * Description: Telechips Linux BACK-LIGHT DRIVER
++ *
++ * Copyright (c) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/moduleparam.h>
++#include <linux/fs.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <hhtech_gpio.h>
++#include <mach/TCC89x_Structures.h>
++#include <mach/globals.h>
++#include <mach/gpio.h>
++#include <linux/delay.h>
++
++#if CONFIG_MACH_TCC8900
++#include <bsp.h>
++#endif
++
++#include "tca_backlight.h"
++
++#define BL_DEV_NAME "bl"
++#define BL_DEV_MAJOR 244
++
++#define IOCTL_BL_OFF _IO(BL_DEV_MAJOR, 1)
++#define IOCTL_BL_ON _IO(BL_DEV_MAJOR, 2)
++#define IOCTL_BL_GET_LEVEL _IO(BL_DEV_MAJOR, 3)
++#define IOCTL_BL_SET_LEVEL _IO(BL_DEV_MAJOR, 4)
++
++#include <mach/tcc_pca953x.h>
++#include <linux/tcc_ll.h>
++#include <linux/tcc_pwm.h>
++
++static stpwrinfo gLCDPwrInfo = {PWR_STATUS_ON};
++static stpwrinfo gBKLPwrInfo = {PWR_STATUS_ON};
++
++int pwr_ioctl_lcd(int onoff)
++{
++ /*
++ * LCD_ON off (gpio expand)
++ * LCDC on/off
++ * LCDC power down
++ * LCD Backlight on/off
++ * LCD data line
++ *
++ * (for lcdc1-rgbif)
++ */
++
++ static int flag=1;
++
++ PGPIO pGPIO;
++ PLCDC pLCDC[2];
++ PDDICONFIG pDDICfg;
++
++ pGPIO = (PGPIO)((unsigned int)&HwGPIO_BASE);
++ pLCDC[0] = (PLCDC)((unsigned int)&HwLCDC0_BASE);
++ pLCDC[1] = (PLCDC)((unsigned int)&HwLCDC1_BASE);
++ pDDICfg = (PDDICONFIG)((unsigned int)&HwDDI_CONFIG_BASE);
++
++
++ if (onoff)
++ { // On
++
++ if (flag)
++ return 0;
++
++ //@ LCD_ON (gpio expand)
++ // high
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, Hw1 /*LCD_ON */, OUTPUT, HIGH, SET_DIRECTION|SET_VALUE);
++
++ //@ RGB Interface
++ // rgb interface
++ BITSET(pGPIO->GPCFN0, 0x55555555); //LCDC1 RGB Interface
++ BITSET(pGPIO->GPCFN1, 0x55555555);
++ BITSET(pGPIO->GPCFN2, 0x55555555);
++ BITCSET(pGPIO->GPCFN3, (Hw16-Hw0), 0x5555);
++
++ //@ LCDC
++ // lcdc pwdn disable
++ BITCLR(pDDICfg->PWDN, Hw3); // lcdc1
++ // lcdc enable
++ BITSET(pLCDC[1]->LCTRL, Hw0);
++
++ //@ LCD_DISP
++ // high
++ BITSET(pGPIO->GPCDAT, Hw28);
++
++ //@ Backlight
++ // tco mode
++ BITCSET(pGPIO->GPAFN0, Hw32-Hw28, 2<<28);
++
++ flag = 1;
++
++ gLCDPwrInfo.status = PWR_STATUS_ON;
++ }
++ else
++ { // Off
++ if (!flag)
++ return 0;
++
++ //@ LCD_ON (gpio expand)
++ // low
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, Hw1 /*LCD_ON */, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++
++ //@LCDC0
++ #if (1)
++ // if lcdc0 enable ..
++ if (pLCDC[0]->LCTRL & Hw0)
++ {
++ if (pDDICfg->PWDN & Hw2)
++ BITCLR(pDDICfg->PWDN, Hw2); // lcdc0 - pwdn disable
++
++ // lcdc0 disable
++ BITCLR(pLCDC[0]->LCTRL, Hw0);
++ while (pLCDC[0]->LSTATUS & Hw30) { {volatile int ttt;for(ttt=0;ttt<0x5000;ttt++);} }; // BUSY
++ }
++
++ if (!(pDDICfg->PWDN & Hw2))
++ {
++ // lcdc0 pwdn enable
++ BITSET(pDDICfg->PWDN, Hw2); // lcdc0
++ }
++ #endif
++
++ //@ Backlight
++ // gpio output low
++ BITCLR(pGPIO->GPADAT, Hw7);
++ BITSET(pGPIO->GPAEN, Hw7);
++ BITCLR(pGPIO->GPAFN0, Hw32-Hw28);
++
++ //@ LCDC
++ // lcdc disable
++ BITCLR(pLCDC[1]->LCTRL, Hw0);
++ while (pLCDC[1]->LSTATUS & Hw30) { {volatile int ttt;for(ttt=0;ttt<0x5000;ttt++);} }; // BUSY
++
++ // lcdc pwdn enable
++ // BITSET(pDDICfg->PWDN, Hw2); // lcdc0
++ BITSET(pDDICfg->PWDN, Hw3); // lcdc1
++
++ //@ RGB Interface
++ // gpio output low
++ BITCLR(pGPIO->GPCDAT, Hw28-Hw0); // low
++ BITSET(pGPIO->GPCEN , Hw28-Hw0); // ouput
++ BITSET(pGPIO->GPCFN0, HwZERO);
++ BITSET(pGPIO->GPCFN1, HwZERO);
++ BITSET(pGPIO->GPCFN2, HwZERO);
++ BITCSET(pGPIO->GPCFN3, (Hw16-Hw0), HwZERO);
++
++ //@ LCD_DISP
++ // low
++ BITCLR(pGPIO->GPCDAT, Hw28);
++
++ flag = 0;
++
++ gLCDPwrInfo.status = PWR_STATUS_OFF;
++ }
++
++ return 0;
++}
++
++static void bl_init(void)
++{
++ PTIMER vTimerAddr = (PTIMER)((unsigned int)&HwTMR_BASE);
++ PGPIO vGpioAddr = (PGPIO)((unsigned int)&HwGPIO_BASE);
++
++ tca_bkl_init((unsigned int)vTimerAddr, (unsigned int)vGpioAddr);
++ gBKLPwrInfo.status = PWR_STATUS_ON;
++}
++
++extern void memchange(unsigned int freq);
++extern int video_on;
++extern int noneed_respond;
++extern unsigned char wm8987_is_playing;
++static int ddi_off_mode = 0;
++static int bl_count = 3;//not use turn-off ddi_bus way until finish the init
++static int mem_bus_freq_change = 0, io_bus_freq_change = 0;
++void bl_control(bool flag)
++{
++ int device_conn;
++
++ PTIMER vTimerAddr = (PTIMER)((unsigned int)&HwTMR_BASE);
++ PGPIO vGpioAddr = (PGPIO)((unsigned int)&HwGPIO_BASE);
++
++ if(bl_count)
++ bl_count--;
++
++ if (flag) {
++ if(ddi_off_mode)
++ *(volatile unsigned long *)0xF0204000 |= 0x1;
++
++ noneed_respond = 0;
++ ddi_off_mode = 0;
++ gpio_direction_output(GPIO_LCD_PWR_EN, 1);
++
++ if(mem_bus_freq_change)
++ {
++ memchange(3300000);// change mem bus to 330m
++ mdelay(50);
++ }
++
++ if(io_bus_freq_change)
++ *(volatile unsigned long *)0xF0400010 = 0x200022;//change io bus to 156M
++
++ mem_bus_freq_change = io_bus_freq_change = 0;
++
++ tca_bkl_powerup((unsigned int)vTimerAddr,(unsigned int)vGpioAddr);
++ gBKLPwrInfo.status = PWR_STATUS_ON;
++
++ } else {
++ noneed_respond = 1;
++ tca_bkl_powerdown((unsigned int)vTimerAddr,(unsigned int)vGpioAddr);
++ gBKLPwrInfo.status = PWR_STATUS_OFF;
++
++ device_conn = ((0x90000 & *(volatile unsigned long *)0xF0550000) == 0x90000);//check if has a otg-device connection
++
++ if(!device_conn && !unlikely(bl_count) && !gpio_get_value(GPIO_HDMI_EN) && !gpio_get_value(GPIO_TVOUT_EN))
++ {
++ *(volatile unsigned long *)0xF0400010 = 0x2000b2;//change io bus to 40M
++ io_bus_freq_change = 1;
++
++ mdelay(1);
++ /* when wm8987 is playing audio, don't decrease mem bus.
++ * because change mem bus back later will produce click and pop noise */
++ if(!wm8987_is_playing) {
++ memchange(1250000);//change mem bus to 125m
++ mdelay(50);
++ mem_bus_freq_change = 1;
++ }
++ }
++ gpio_direction_output(GPIO_LCD_PWR_EN, 0);
++ *(volatile unsigned long *)0xF0200000 &= ~(0x1);
++
++ if((!bl_count)&&(!video_on)&&(!gpio_get_value(GPIO_HDMI_EN))&&(!gpio_get_value(GPIO_TVOUT_EN)))
++ {
++ ddi_off_mode = 1;
++ *(volatile unsigned long *)0xF0204000 &= ~(0x1);
++ }
++ }
++}
++EXPORT_SYMBOL(bl_control);
++
++static int tcc_bl_ioctl(struct inode *inode, struct file *filp,
++ unsigned int cmd, unsigned long arg)
++{
++ unsigned long bl_val;
++
++ PTIMER vTimerAddr = (PTIMER)((unsigned int)&HwTMR_BASE);
++ //PGPIO vGpioAddr = (PGPIO)((unsigned int)&HwGPIO_BASE);
++
++
++ switch (cmd) {
++ case IOCTL_BL_OFF:
++ bl_control(false);
++ break;
++ case IOCTL_BL_ON:
++ bl_control(true);
++ break;
++ case IOCTL_BL_GET_LEVEL:
++ bl_val = tca_bkl_getpowerval((unsigned int)vTimerAddr);
++ copy_to_user((void *)arg, (const void *)&bl_val, sizeof(unsigned long));
++ break;
++ case IOCTL_BL_SET_LEVEL:
++ copy_from_user((void *)&bl_val, (const void *)arg, sizeof(unsigned long));
++ if (bl_val < 0)
++ bl_val = 1;
++
++ tca_bkl_setpowerval(bl_val, (unsigned int)vTimerAddr);
++ break;
++ default:
++ printk("bl: unrecognized ioctl (0x%x)\n", cmd);
++ return -EINVAL;
++ break;
++ }
++
++ return 0;
++}
++
++static int tcc_bl_release(struct inode *inode, struct file *filp)
++{
++ return 0;
++}
++
++static int tcc_bl_open(struct inode *inode, struct file *filp)
++{
++ return 0;
++}
++
++struct file_operations tcc_bl_fops =
++{
++ .owner = THIS_MODULE,
++ .open = tcc_bl_open,
++ .release = tcc_bl_release,
++ .ioctl = tcc_bl_ioctl,
++};
++
++
++//static char *g_lcd_private = "hello world";
++static int lcd_pwr_ctl(void *h_private, int cmd, void *p_out)
++{
++ int ret = 0;
++// if (h_private) {
++// printk("private handle [%s] \n", (char *)h_private);
++// }
++
++ switch (cmd) {
++ case PWR_CMD_OFF:
++ pwr_ioctl_lcd(0);
++ if (p_out)
++ {
++ memcpy(p_out, &gLCDPwrInfo, sizeof(stpwrinfo));
++ }
++ break;
++ case PWR_CMD_ON:
++ pwr_ioctl_lcd(1);
++ if (p_out)
++ {
++ memcpy(p_out, &gLCDPwrInfo, sizeof(stpwrinfo));
++ }
++ break;
++ case PWR_CMD_GETSTATUS:
++ if (p_out)
++ {
++ memcpy(p_out, &gLCDPwrInfo, sizeof(stpwrinfo));
++ }
++ else
++ {
++ ret = -EINVAL;
++ }
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ return ret;
++}
++
++static int bkl_pwr_ctl(void *h_private, int cmd, void *p_out)
++{
++ int ret = 0;
++
++ switch (cmd) {
++ case PWR_CMD_OFF:
++ bl_control(0);
++ if (p_out)
++ {
++ memcpy(p_out, &gBKLPwrInfo, sizeof(stpwrinfo));
++ }
++ break;
++ case PWR_CMD_ON:
++ bl_control(1);
++ if (p_out)
++ {
++ memcpy(p_out, &gBKLPwrInfo, sizeof(stpwrinfo));
++ }
++ break;
++ case PWR_CMD_GETSTATUS:
++ if (p_out)
++ {
++ memcpy(p_out, &gBKLPwrInfo, sizeof(stpwrinfo));
++ }
++ else
++ {
++ ret = -EINVAL;
++ }
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ return ret;
++}
++
++static int __init tcc_bl_init(void)
++{
++ int res;
++
++ res = register_chrdev(BL_DEV_MAJOR, BL_DEV_NAME, &tcc_bl_fops);
++ if (res < 0)
++ return res;
++
++ insert_pwm_node(DEVICE_LCD, lcd_pwr_ctl, NULL);
++ insert_pwm_node(DEVICE_BACKLIGHT, bkl_pwr_ctl, NULL);
++
++ bl_init();
++
++ printk("bl: init\n");
++ return 0;
++}
++
++static void __exit tcc_bl_exit(void)
++{
++ remove_pwm_node(DEVICE_LCD);
++ remove_pwm_node(DEVICE_BACKLIGHT);
++ unregister_chrdev(BL_DEV_MAJOR, BL_DEV_NAME);
++ printk("bl: exit\n");
++}
++
++module_init(tcc_bl_init);
++module_exit(tcc_bl_exit);
++
++MODULE_AUTHOR("Telechips Inc. SYS4-3 linux@telechips.com");
++MODULE_DESCRIPTION("TCCxxx back-light driver");
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/char/tcc_ckc_ioctl.c b/drivers/char/tcc_ckc_ioctl.c
+new file mode 100644
+index 0000000..57e6a74
+--- /dev/null
++++ b/drivers/char/tcc_ckc_ioctl.c
+@@ -0,0 +1,295 @@
++/*
++ * File: drivers/char/tcc_ioctl.c
++ *
++ * Created: June 10, 2008
++ * Copyright (C) 2008-2009 Telechips <linux@telechips.com>
++ * Description: User-level Clock Control IOCTL driver
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <asm/uaccess.h>
++#include <linux/ioctl.h>
++#include <mach/hardware.h>
++#include <asm/tlbflush.h>
++#include <asm/cacheflush.h>
++#include <linux/spinlock.h>
++#include <linux/sched.h>
++#include <linux/tick.h>
++#include <linux/time.h>
++
++#include <linux/init.h>
++#include <mach/tcc_ckc_ctrl.h>
++
++#define DEV_NAME "tcc-ioctl-ckc"
++#define BUF_LEN 80
++
++#if 0
++//#define dbg(x...) printk(KERN_DEBUG "tcc uart: ");
++#define dbg printk
++#else /* no debug */
++#define dbg(x...) do {} while(0)
++#endif
++
++static int tcc_open(struct inode *inode, struct file *file)
++{
++ return 0;
++}
++
++static int tcc_release(struct inode *inode, struct file *file)
++{
++ return 0;
++}
++
++int tcc_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ struct ckc_ioctl st;
++
++ memset(&st, 0, sizeof(struct ckc_ioctl));
++
++ switch(cmd)
++ {
++ case IOCTL_CKC_SET_PERI: // Set Peri Clock
++ dbg("%s: IOCTL_CKC_SET_PERI\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++
++ ckc_set_peri(st);
++ break;
++
++ case IOCTL_CKC_GET_PERI:
++ dbg("%s: IOCTL_CKC_GET_PERI\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ st.out_ckc.pckcfreq = ckc_get_peri(st);
++ if(copy_to_user((void *)arg, &st, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ break;
++
++ case IOCTL_CKC_SET_PERIBUS:
++ dbg("%s: IOCTL_CKC_SET_PERIBUS\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ st.out_ckc.retVal = ckc_set_peribus(st); // Enable or eisable
++ break;
++
++ case IOCTL_CKC_GET_PERIBUS:// Get io Bus State
++ dbg("%s: IOCTL_CKC_GET_PERIBUS\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ st.out_ckc.retVal = ckc_get_peribus(st);
++ if(copy_to_user((void *)arg, &st, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ break;
++
++ case IOCTL_CKC_SET_PERISWRESET:
++ dbg("%s: IOCTL_CKC_SET_PERISWRESET\n", __func__);
++ if(copy_from_user((void *)arg, &st, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ ckc_set_periswreset(st);
++ break;
++
++ case IOCTL_CKC_SET_FBUSSWRESET:
++ dbg("%s: IOCTL_CKC_SET_FBUSSWRESET\n", __func__);
++ if(copy_from_user((void *)arg, &st, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ ckc_set_fbusswreset(st);
++ break;
++
++ case IOCTL_CKC_SET_CPU:
++ dbg("%s: IOCTL_CKC_SET_CPU\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ ckc_set_cpu(st);
++ break;
++
++ case IOCTL_CKC_SET_SMUI2C:
++ dbg("%s: IOCTL_CKC_SET_SMUI2C\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ ckc_set_smui2c(st);
++ break;
++
++ case IOCTL_CKC_GET_CPU:
++ dbg("%s: IOCTL_CKC_GET_CPU\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ st.out_ckc.currentcpufreq = ckc_get_cpu(st);
++ if(copy_to_user((void *)arg, &st, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ break;
++
++ case IOCTL_CKC_GET_BUS:
++ dbg("%s: IOCTL_CKC_GET_BUS\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ st.out_ckc.currentbusfreq = ckc_get_bus(st);
++ if(copy_to_user((void *)arg, &st, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ break;
++
++ case IOCTL_CKC_GET_VALIDPLLINFO:
++ dbg("%s: IOCTL_CKC_GET_VALIDPLLINFO\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ ckc_get_validpllinfo(st);
++ if(copy_to_user((void *)arg, &st, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ break;
++
++ case IOCTL_CKC_SET_FBUS:
++ dbg("%s: IOCTL_CKC_SET_FBUS\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ ckc_set_fbus(st);
++ break;
++
++ case IOCTL_CKC_GET_FBUS:
++ dbg("%s: IOCTL_CKC_GET_FBUS\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ st.out_ckc.fbusfreq = ckc_get_fbus(st);
++ if(copy_to_user((void *)arg, &st, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ break;
++
++ case IOCTL_CKC_SET_PMUPOWER:
++ dbg("%s: IOCTL_CKC_SET_FBUS\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ ckc_set_pmupower(st);
++ break;
++
++ case IOCTL_CKC_GET_PMUPOWER:
++ dbg("%s: IOCTL_CKC_GET_PMUPOWER\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ ckc_get_pmupower(st);
++ if(copy_to_user((void *)arg, &st, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ break;
++
++ case IOCTL_CKC_GET_CLOCKINFO:
++ dbg("%s: IOCTL_CKC_GET_CLOCKINFO\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ ckc_get_clockinfo(st);
++ if(copy_to_user((void *)arg, &st, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ break;
++
++ case IOCTL_CKC_SET_CHANGEFBUS:
++ {
++ dbg("%s: IOCTL_CKC_SET_CHANGEFBUS\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++
++ ckc_set_changefbus(st);
++ break;
++ }
++
++ case IOCTL_CKC_SET_CHANGEMEM:
++ {
++ dbg("%s: IOCTL_CKC_SET_CHANGEMEM\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++
++ ckc_set_changemem(st);
++ break;
++ }
++
++ case IOCTL_CKC_SET_CHANGECPU:
++ dbg("%s: IOCTL_CKC_SET_CHANGECPU\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ ckc_set_changecpu(st);
++ break;
++
++ case IOCTL_CKC_SET_DDIPWDN:
++ dbg("%s: IOCTL_CKC_SET_DDIPWDN\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++
++ ckc_set_ddipwdn(st);
++ break;
++
++ case IOCTL_CKC_GET_DDIPWDN:
++ dbg("%s: IOCTL_CKC_GET_DDIPWDN\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++
++ ckc_get_ddipwdn(st);
++
++ if(copy_to_user((void *)arg, &st, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++ break;
++
++ case IOCTL_CKC_SET_ETCBLOCK:
++ dbg("%s: IOCTL_CKC_SET_ETCBLOCK\n", __func__);
++ if(copy_from_user(&st, (void *)arg, sizeof(struct ckc_ioctl)))
++ return -EFAULT;
++
++ ckc_set_etcblock(st);
++ break;
++
++
++ default :
++ break;
++ }
++
++ return 0;
++}
++
++struct file_operations tcc_fops = {
++ .owner = THIS_MODULE,
++ .ioctl = tcc_ioctl,
++ .open = tcc_open,
++ .release = tcc_release,
++};
++
++
++int init_module(void)
++{
++ int ret;
++
++ ret = register_chrdev(MAJOR_NUM, DEV_NAME, &tcc_fops);
++
++ if(ret < 0){
++ dbg(KERN_ALERT " %s failed with %d\n", "fail to register the character device", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++void cleanup_module(void)
++{
++ unregister_chrdev(MAJOR_NUM, DEV_NAME);
++}
++
++
++module_init(init_module);
++module_exit(cleanup_module);
++
++
++MODULE_AUTHOR("Telechips Inc. <linux@telechips.com>");
++MODULE_DESCRIPTION("TCC Clock IOCTL driver");
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/char/tcc_intr.c b/drivers/char/tcc_intr.c
+new file mode 100644
+index 0000000..0fc2656
+--- /dev/null
++++ b/drivers/char/tcc_intr.c
+@@ -0,0 +1,578 @@
++/*
++ * linux/drivers/char/tcc_intr.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 31th March, 2009
++ * Description: User-level interrupt Driver
++ *
++ * Copyright (c) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/fs.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/fcntl.h>
++
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/time.h>
++#include <linux/timer.h>
++#include <linux/poll.h>
++
++#include <asm/uaccess.h>
++#include <asm/io.h>
++
++#include <bsp.h>
++#include <mach/irqs.h>
++#include <linux/tcc_intr.h>
++
++//#define DBG_GPIO
++#ifdef DBG_GPIO
++#define TEST_GPIO(x) test_gpio(x)
++#else
++#define TEST_GPIO(x)
++#endif
++
++#define TCC_INTR_VERSION "2.1"
++#define TCC_INTR_DEV_NAME "tcc_intr"
++
++#define VIPC_TIG0 *(volatile long *)0xF0401030
++
++typedef struct _tcc_intr_data_t {
++ wait_queue_head_t wq;
++ spinlock_t lock;
++ unsigned int count;
++ unsigned int irq;
++ unsigned int irq_bit;
++ volatile PPIC irq_regs;
++} tcc_intr_data_t;
++
++
++/*
++ * TEST GPIO FUNCTION
++ */
++#ifdef DBG_GPIO
++static int status;
++static void test_gpio(int flag)
++{
++ if (flag == 0) {
++ // gpio low
++ BITCLR(*(volatile unsigned int *)0xF0102100, Hw22); // low
++ } else if (flag == 1) {
++ // gpio high
++ BITSET(*(volatile unsigned int *)0xF0102100, Hw22); // high
++ } else if (flag == 2) {
++ // toggle
++ if (status) {
++ BITCLR(*(volatile unsigned int *)0xF0102100, Hw22); // low
++ status = 0;
++ } else {
++ BITSET(*(volatile unsigned int *)0xF0102100, Hw22); // high
++ status = 1;
++ }
++ } else if (flag == 3) {
++ // gpio init
++ // GPIO_E22 - CAM_HS - JH2[5]
++ BITCLR(*(volatile unsigned int *)0xF010212C, Hw28-Hw24); // GPIO_E22
++ BITSET(*(volatile unsigned int *)0xF0102104, Hw22); // output
++ BITCLR(*(volatile unsigned int *)0xF0102100, Hw22); // low
++
++ BITCLR(*(volatile unsigned int *)0xF0102130, Hw16-Hw12); // GPIO_E26
++ BITSET(*(volatile unsigned int *)0xF0102104, Hw26); // output
++ BITCLR(*(volatile unsigned int *)0xF0102100, Hw26); // low
++ } else {
++ }
++}
++#endif
++
++/*
++ * Video Codec Interface.
++ */
++static void init_vc_interrupt(tcc_intr_data_t *tcc_intr)
++{
++#if 0
++ BITCLR(tcc_intr->irq_regs->MODE0, tcc_intr->irq_bit); // edge-triggered
++ BITCLR(tcc_intr->irq_regs->MODEA0, tcc_intr->irq_bit); // single-edge
++ BITSET(tcc_intr->irq_regs->POL0, tcc_intr->irq_bit); // active-low
++#endif
++#if 0
++ BITSET(tcc_intr->irq_regs->MODE0, tcc_intr->irq_bit); // level-triggered
++ BITSET(tcc_intr->irq_regs->POL0, tcc_intr->irq_bit); // active-low
++#endif
++ BITCLR(tcc_intr->irq_regs->MODE0, tcc_intr->irq_bit); // edge-triggered
++ BITCLR(tcc_intr->irq_regs->MODEA0, tcc_intr->irq_bit); // single-edge
++ BITCLR(tcc_intr->irq_regs->POL0, tcc_intr->irq_bit); // active-high
++}
++
++static irqreturn_t vc_handler(int irq, void *dev_id)
++{
++ tcc_intr_data_t *tcc_intr = dev_id;
++
++ spin_lock_irq(&(tcc_intr->lock));
++ tcc_intr->count++;
++ spin_unlock_irq(&(tcc_intr->lock));
++
++ wake_up_interruptible(&(tcc_intr->wq));
++
++ return IRQ_HANDLED;
++}
++
++/*
++ * Mem to Mem Scaler Interface.
++ */
++static void init_sc_interrupt(tcc_intr_data_t *tcc_intr)
++{
++ BITCLR(tcc_intr->irq_regs->MODE0, tcc_intr->irq_bit); // edge-triggered
++ BITCLR(tcc_intr->irq_regs->MODEA0, tcc_intr->irq_bit); // single-edge
++ BITSET(tcc_intr->irq_regs->POL0, tcc_intr->irq_bit); // active-low
++}
++
++static irqreturn_t sc_handler(int irq, void *dev_id)
++{
++ tcc_intr_data_t *tcc_intr = dev_id;
++
++ spin_lock_irq(&(tcc_intr->lock));
++ tcc_intr->count++;
++ spin_unlock_irq(&(tcc_intr->lock));
++
++ wake_up_interruptible(&(tcc_intr->wq));
++
++ return IRQ_HANDLED;
++}
++
++/*
++ * BroadCasting DXB Interface.
++ */
++static void init_bc_interrupt(tcc_intr_data_t *tcc_intr)
++{
++ PGPIO pGPIO = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
++
++ /* DXB1_IRQ - GPIO_A11 - ExINT3 */
++ BITCLR(pGPIO->GPAFN1, Hw16-Hw12); // gpio
++ BITCLR(pGPIO->GPAEN, Hw11); // input mode
++ //BITCSET(pGPIO->GPAPD0, Hw23, Hw22); // pull-up driving
++
++ BITCSET(pGPIO->EINTSEL0, Hw30-Hw24, (11<<24));
++
++ /* Int trigger setting */
++ BITCLR(tcc_intr->irq_regs->MODE0, tcc_intr->irq_bit); // edge-triggered
++ BITCLR(tcc_intr->irq_regs->MODEA0, tcc_intr->irq_bit); // single-edge
++ BITCLR(tcc_intr->irq_regs->POL0, tcc_intr->irq_bit); // active-high
++}
++
++static irqreturn_t bc_handler(int irq, void *dev_id)
++{
++ tcc_intr_data_t *tcc_intr = dev_id;
++
++ spin_lock_irq(&(tcc_intr->lock));
++ tcc_intr->count++;
++ spin_unlock_irq(&(tcc_intr->lock));
++
++ wake_up_interruptible(&(tcc_intr->wq));
++
++ return IRQ_HANDLED;
++}
++
++///////////////////////////////////////////////////////////////////////////
++//
++static long io_interrupt(tcc_intr_data_t *tcc_intr, long flag)
++{
++ /* NOTE: irq_regs->XXX0, XXX1 */
++ long ret = 0;
++ if (flag == 0) {
++ BITSET(tcc_intr->irq_regs->CLR0, tcc_intr->irq_bit); // clear intr
++ BITCLR(tcc_intr->irq_regs->INTMSK0, tcc_intr->irq_bit); // disable intr
++ } else if (flag == 1) {
++ BITSET(tcc_intr->irq_regs->CLR0, tcc_intr->irq_bit);
++ BITSET(tcc_intr->irq_regs->INTMSK0, tcc_intr->irq_bit); // enable intr
++ } else if (flag == 2) {
++ ret = (tcc_intr->irq_regs->INTMSK0 & tcc_intr->irq_bit)?1:0; // get int-mask status
++ } else {
++ ret = -1;
++ }
++ return ret;
++}
++
++static unsigned int intr_poll(struct file *filp, poll_table *wait)
++{
++ tcc_intr_data_t *tcc_intr = (tcc_intr_data_t *)filp->private_data;
++
++ if (tcc_intr == NULL)
++ return -EFAULT;
++
++ if (tcc_intr->count > 0) {
++ spin_lock_irq(&(tcc_intr->lock));
++ tcc_intr->count--;
++ spin_unlock_irq(&(tcc_intr->lock));
++ return (POLLIN | POLLRDNORM);
++ }
++
++ poll_wait(filp, &(tcc_intr->wq), wait);
++
++ if (tcc_intr->count > 0) {
++ spin_lock_irq(&(tcc_intr->lock));
++ tcc_intr->count--;
++ spin_unlock_irq(&(tcc_intr->lock));
++ return (POLLIN | POLLRDNORM);
++ } else {
++ return 0;
++ }
++}
++
++static int intr_ioctl(struct inode *inode, struct file *filp,
++ unsigned int cmd, unsigned long arg)
++{
++ unsigned long data;
++ tcc_intr_data_t *tcc_intr = (tcc_intr_data_t *)filp->private_data;
++
++ switch (cmd) {
++ case IOCTL_INTR_SET:
++ if (copy_from_user((void *)&data, (const void *)arg, sizeof(data)))
++ return -EFAULT;
++ if (data == 0 || data == 1) io_interrupt(tcc_intr, data);
++ else return -EFAULT;
++ break;
++ case IOCTL_INTR_GET:
++ data = io_interrupt(tcc_intr, 2);
++ if (copy_to_user((void *)arg, (const void *)&data, sizeof(data)))
++ return -EFAULT;
++ break;
++ default:
++ printk("tcc_intr(%d): unrecognized ioctl (0x%x)\n", MINOR(inode->i_rdev), cmd);
++ return -EINVAL;
++ break;
++ }
++
++ return 0;
++}
++
++static int intr_test_ioctl(struct inode *inode, struct file *filp,
++ unsigned int cmd, unsigned long arg)
++{
++ unsigned long data;
++
++ switch (cmd) {
++ case IOCTL_INTR_TEST:
++ if (copy_from_user((void *)&data, (const void *)arg, sizeof(data))) {
++ return -EFAULT;
++ } else {
++ if (data == 1) {
++ BITSET(VIPC_TIG0, (1 << INT_VCDC));
++ } else if (data == 2) {
++ BITSET(VIPC_TIG0, (1 << INT_SC0));
++ } else if (data == 3) {
++ BITSET(VIPC_TIG0, (1 << INT_EI3));
++ } else if (data == 4) {
++ BITSET(VIPC_TIG0, (1 << INT_SC1));
++ } else {
++ return -EFAULT;
++ }
++ }
++ break;
++ default:
++ printk("tcc_intr(%d): unrecognized ioctl (0x%x)\n", MINOR(inode->i_rdev), cmd);
++ return -EINVAL;
++ break;
++ }
++
++ return 0;
++}
++
++static int intr_release(struct inode *inode, struct file *filp)
++{
++ tcc_intr_data_t *tcc_intr = (tcc_intr_data_t *)filp->private_data;
++
++ free_irq(tcc_intr->irq, tcc_intr);
++
++ /* DXB1_IRQ-GPIO_A11-ExINT3 -> set GPIO output low */
++ if (tcc_intr->irq == INT_EI3) {
++ PGPIO pGPIO = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
++ BITCLR(pGPIO->GPAFN1, Hw16-Hw12);
++ BITSET(pGPIO->GPAEN, Hw11);
++ BITCLR(pGPIO->GPADAT, Hw11);
++ }
++
++ kfree(tcc_intr);
++
++ return 0;
++}
++
++///////////////////////////////////////////////////////////////////////////
++//
++static int intr_sc_open(struct inode *inode, struct file *filp)
++{
++ int ret = 0;
++ tcc_intr_data_t *sc_data = NULL;
++
++ sc_data = (tcc_intr_data_t *)kmalloc(sizeof(tcc_intr_data_t), GFP_KERNEL);
++ if (sc_data == NULL) {
++ ret = -ENOMEM;
++ goto error;
++ }
++ memset(sc_data, 0, sizeof(tcc_intr_data_t));
++
++ spin_lock_init(&(sc_data->lock));
++ init_waitqueue_head(&(sc_data->wq));
++ sc_data->irq = INT_SC0;
++ sc_data->irq_bit = (1 << INT_SC0);
++ sc_data->irq_regs = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++
++ init_sc_interrupt(sc_data);
++ ret = request_irq(sc_data->irq, sc_handler, IRQF_DISABLED, TCC_INTR_DEV_M2M_SCALER, sc_data);
++ if (ret) {
++ ret = -EFAULT;
++ goto error;
++ }
++
++ filp->private_data = (void *)sc_data;
++
++ return 0;
++error:
++ if (sc_data)
++ kfree(sc_data);
++ return ret;
++}
++
++static int intr_sc1_open(struct inode *inode, struct file *filp)
++{
++ int ret = 0;
++ tcc_intr_data_t *sc_data = NULL;
++
++ sc_data = (tcc_intr_data_t *)kmalloc(sizeof(tcc_intr_data_t), GFP_KERNEL);
++ if (sc_data == NULL) {
++ ret = -ENOMEM;
++ goto error;
++ }
++ memset(sc_data, 0, sizeof(tcc_intr_data_t));
++
++ spin_lock_init(&(sc_data->lock));
++ init_waitqueue_head(&(sc_data->wq));
++ sc_data->irq = INT_SC1;
++ sc_data->irq_bit = (1 << INT_SC1);
++ sc_data->irq_regs = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++
++ init_sc_interrupt(sc_data);
++ ret = request_irq(sc_data->irq, sc_handler, IRQF_DISABLED, TCC_INTR_DEV_M2M_SCALER1, sc_data);
++ if (ret) {
++ ret = -EFAULT;
++ goto error;
++ }
++
++ filp->private_data = (void *)sc_data;
++
++ return 0;
++error:
++ if (sc_data)
++ kfree(sc_data);
++ return ret;
++}
++
++static int intr_vc_open(struct inode *inode, struct file *filp)
++{
++ int ret = 0;
++ tcc_intr_data_t *vc_data = NULL;
++
++ vc_data = (tcc_intr_data_t *)kmalloc(sizeof(tcc_intr_data_t), GFP_KERNEL);
++ if (vc_data == NULL) {
++ ret = -ENOMEM;
++ goto error;
++ }
++ memset(vc_data, 0, sizeof(tcc_intr_data_t));
++
++ spin_lock_init(&(vc_data->lock));
++ init_waitqueue_head(&(vc_data->wq));
++ vc_data->irq = INT_VCDC;
++ vc_data->irq_bit = (1 << INT_VCDC);
++ vc_data->irq_regs = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++
++ init_vc_interrupt(vc_data);
++ ret = request_irq(vc_data->irq, vc_handler, IRQF_DISABLED, TCC_INTR_DEV_VIDEO_CODEC, vc_data);
++ if (ret) {
++ ret = -EFAULT;
++ goto error;
++ }
++
++ filp->private_data = (void *)vc_data;
++
++ return 0;
++error:
++ if (vc_data)
++ kfree(vc_data);
++ return ret;
++}
++
++static int intr_bc_open(struct inode *inode, struct file *filp)
++{
++ int ret = 0;
++ tcc_intr_data_t *bc_data = NULL;
++
++ bc_data = (tcc_intr_data_t *)kmalloc(sizeof(tcc_intr_data_t), GFP_KERNEL);
++ if (bc_data == NULL) {
++ ret = -ENOMEM;
++ goto error;
++ }
++ memset(bc_data, 0, sizeof(tcc_intr_data_t));
++
++ spin_lock_init(&(bc_data->lock));
++ init_waitqueue_head(&(bc_data->wq));
++ bc_data->irq = INT_EI3;
++ bc_data->irq_bit = (1 << INT_EI3);
++ bc_data->irq_regs = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++
++ init_bc_interrupt(bc_data);
++ ret = request_irq(bc_data->irq, bc_handler, IRQF_DISABLED, TCC_INTR_DEV_BROADCAST, bc_data);
++ if (ret) {
++ ret = -EFAULT;
++ goto error;
++ }
++
++ filp->private_data = (void *)bc_data;
++
++ return 0;
++error:
++ if (bc_data)
++ kfree(bc_data);
++ return ret;
++}
++
++/*------------------------------------------------------------------------------
++ * User-level interrupt Power on/off control
++ * TODO: need something?
++ */
++static stpwrinfo pwrinfo = {PWR_STATUS_ON};
++static int intr_pwr_ctl(void *h_private, int cmd, void *p_out)
++{
++ switch (cmd) {
++ case PWR_CMD_OFF:
++ //printk("PWR_CMD_OFF command ==> [%d]\n", cmd);
++ if (pwrinfo.status == PWR_STATUS_OFF) {
++ return 0;
++ }
++ pwrinfo.status = PWR_STATUS_OFF;
++ break;
++ case PWR_CMD_ON:
++ //printk("PWR_CMD_ON command ==> [%d]\n", cmd);
++ if (pwrinfo.status == PWR_STATUS_ON) {
++ return 0;
++ }
++ pwrinfo.status = PWR_STATUS_ON;
++ break;
++ case PWR_CMD_GETSTATUS:
++ //printk("PWR_CMD_GETSTATUS command ==> [%d], status:[%d]\n", cmd, pwrinfo.status);
++ memcpy(p_out, &pwrinfo, sizeof(stpwrinfo));
++ break;
++ default:
++ //printk("unknown pwr command !!! ==> [%d]\n", cmd);
++ return -EINVAL;
++ break;
++ }
++ return 0;
++}
++
++
++struct file_operations intr_vc_fops =
++{
++ .owner = THIS_MODULE,
++ .poll = intr_poll,
++ .ioctl = intr_ioctl,
++ .open = intr_vc_open,
++ .release = intr_release,
++};
++
++struct file_operations intr_sc_fops =
++{
++ .owner = THIS_MODULE,
++ .poll = intr_poll,
++ .ioctl = intr_ioctl,
++ .open = intr_sc_open,
++ .release = intr_release,
++};
++
++struct file_operations intr_sc1_fops =
++{
++ .owner = THIS_MODULE,
++ .poll = intr_poll,
++ .ioctl = intr_ioctl,
++ .open = intr_sc1_open,
++ .release = intr_release,
++};
++
++struct file_operations intr_bc_fops =
++{
++ .owner = THIS_MODULE,
++ .poll = intr_poll,
++ .ioctl = intr_ioctl,
++ .open = intr_bc_open,
++ .release = intr_release,
++};
++
++struct file_operations intr_test_fops =
++{
++ .owner = THIS_MODULE,
++ .ioctl = intr_test_ioctl,
++};
++
++static int tcc_intr_open(struct inode *inode, struct file *filp)
++{
++ switch (MINOR(inode->i_rdev)) {
++ case 1: filp->f_op = &intr_vc_fops; break;
++ case 2: filp->f_op = &intr_sc_fops; break;
++ case 3: filp->f_op = &intr_bc_fops; break;
++ case 4: filp->f_op = &intr_test_fops; break;
++ case 5: filp->f_op = &intr_sc1_fops; break;
++ default : return -ENXIO;
++ }
++
++ if (filp->f_op && filp->f_op->open)
++ return filp->f_op->open(inode, filp);
++
++ return 0;
++}
++
++struct file_operations tcc_intr_fops =
++{
++ .owner = THIS_MODULE,
++ .open = tcc_intr_open,
++};
++
++static int __init tcc_intr_init(void)
++{
++ int res;
++
++ res = register_chrdev(TCC_INTR_DEV_MAJOR, TCC_INTR_DEV_NAME, &tcc_intr_fops);
++ if (res < 0)
++ return res;
++
++ /* add power control functions */
++ insert_pwm_node(DEVICE_USERINTR, intr_pwr_ctl, NULL);
++
++ printk("tcc_intr: init (ver %s)\n", TCC_INTR_VERSION);
++ return 0;
++}
++
++static void __exit tcc_intr_exit(void)
++{
++ unregister_chrdev(TCC_INTR_DEV_MAJOR, TCC_INTR_DEV_NAME);
++
++ /* remove power control functions */
++ remove_pwm_node(DEVICE_USERINTR);
++
++ printk("tcc_intr: exit\n");
++}
++
++
++module_init(tcc_intr_init);
++module_exit(tcc_intr_exit);
++
++MODULE_AUTHOR("Telechips Inc. SYS4-3 linux@telechips.com");
++MODULE_DESCRIPTION("Telechips user level interrut driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/char/tcc_ll.c b/drivers/char/tcc_ll.c
+new file mode 100644
+index 0000000..8b7b78c
+--- /dev/null
++++ b/drivers/char/tcc_ll.c
+@@ -0,0 +1,256 @@
++/*
++ * linux/drivers/char/tcc_ll.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 21th August, 2009
++ * Description: Telechips linked list
++ *
++ * Copyright (c) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/types.h>
++
++#include <linux/tcc_ll.h>
++
++#define jprintk printk
++
++static void copy_data_node(data_node_t *dst, data_node_t *src)
++{
++ if (dst && src) {
++ dst->id = get_node_id(src);
++ dst->callback = get_node_cb(src);
++ dst->h_pri = get_node_pri(src);
++ }
++}
++
++/* data_node_t functions */
++static data_node_t *new_node(data_node_t *p_node)
++{
++ data_node_t *p = NULL;
++
++ if (p_node) {
++ p = (data_node_t *)kmalloc(sizeof(data_node_t), GFP_KERNEL);
++ if (p) {
++ memset(p, 0, sizeof(data_node_t));
++ copy_data_node(p, p_node);
++ }
++ }
++ return p;
++}
++
++static data_node_t *free_node(data_node_t *p_node)
++{
++ if (p_node) {
++ kfree(p_node);
++ }
++ return NULL;
++}
++
++/************************************/
++
++
++int init_ll(list_handle_t *h)
++{
++ if (h) {
++ memset(h, 0, sizeof(list_handle_t));
++ return 0;
++ }
++ return -1;
++}
++
++static void set_pos_node(list_handle_t *h, int pos)
++{
++ if (h) {
++ int i = 0;
++ for (h->p_pos = h->p_head; h->p_pos; h->p_pos = get_next_node(h->p_pos)) {
++ i++;
++ if (i > pos) { break; }
++ }
++ }
++}
++
++int insert_ll(list_handle_t *h, data_node_t *p_node)
++{
++ if (h) {
++ data_node_t *p = new_node(p_node);
++
++ if (p) {
++ if (!(h->p_head)) {
++ h->p_head = h->p_tail = h->p_pos = p;
++ } else {
++ set_next_node(h->p_tail, p);
++ h->p_tail = p;
++ }
++ (h->node_cnt)++;
++ return 0;
++ }
++ }
++ return -1;
++}
++
++int remove_internal_ll(list_handle_t *h, data_node_t *p_pre, data_node_t *p)
++{
++ if (h && p) {
++ if ((p == h->p_head) || (p == h->p_tail)) {
++ if (p == h->p_head) {
++ h->p_head = get_next_node(p);
++ }
++ if (p == h->p_tail) {
++ h->p_tail = p_pre;
++ if (h->p_tail) {
++ set_next_node(h->p_tail, NULL);
++ }
++ }
++ } else {
++ set_next_node(p_pre, get_next_node(p));
++ }
++
++ if (p == h->p_pos) {
++ h->p_pos = get_next_node(h->p_pos);
++ if (h->p_pos == NULL) {
++ h->p_pos = h->p_head;
++ }
++ }
++ p = free_node(p);
++
++ if (h->node_cnt > 0) {
++ h->node_cnt--;
++ } else {
++ printk("h->node_cnt error ...\n");
++ }
++ return 0;
++ }
++ return -1;
++}
++
++int remove_ll(list_handle_t *h, unsigned int id)
++{
++ int ret = -1;
++ if (h) {
++ data_node_t *p, *p_pre = NULL;
++ for (p = h->p_head; p; p = get_next_node(p)) {
++ if (p->id == id) {
++ ret = remove_internal_ll(h, p_pre, p);
++ break;
++ }
++ p_pre = p;
++ }
++ }
++ return ret;
++}
++
++void remove_all_ll(list_handle_t *h)
++{
++ if (h) {
++ for (h->p_tail = h->p_head; h->p_tail; h->p_tail = h->p_head) {
++ h->p_head = get_next_node(h->p_head);
++ free_node(h->p_tail);
++ }
++ h->p_head = h->p_tail = h->p_pos = NULL;
++ h->node_cnt = 0;
++ }
++}
++
++data_node_t *find_by_id(list_handle_t *h, unsigned int id)
++{
++ data_node_t *p = NULL;
++
++ if (h) {
++ set_pos_node(h, 0);
++ for (p = h->p_pos; p; p = get_next_node(p)) {
++ if (p->id == id) { return p; }
++ }
++ }
++ return NULL;
++}
++
++
++
++typedef struct power_man {
++ list_handle_t tcc_pwm_list;
++ struct mutex mutex;
++} power_man_t;
++
++static power_man_t pwr_man;
++
++int init_pwm_list(void)
++{
++ int ret = -1;
++ memset(&pwr_man, 0, sizeof(pwr_man));
++ ret = init_ll(&(pwr_man.tcc_pwm_list));
++ mutex_init(&(pwr_man.mutex));
++ return ret;
++}
++EXPORT_SYMBOL(init_pwm_list);
++
++int insert_pwm_node(unsigned int id, power_control_t func, void *h_pri)
++{
++ int ret = -1;
++ list_handle_t *h = &(pwr_man.tcc_pwm_list);
++ if (h && func) {
++ mutex_lock(&(pwr_man.mutex));
++ if (!find_by_id(h, id)) {
++ data_node_t node;
++
++ memset(&node, 0, sizeof(node));
++ node.id = id;
++ node.callback = func;
++ node.h_pri = h_pri;
++
++ ret = insert_ll(h, &node);
++ } else {
++ printk("--- err --- already exist dev-node !!! -> id[%d]\n", id);
++ }
++ mutex_unlock(&(pwr_man.mutex));
++ }
++ return ret;
++}
++EXPORT_SYMBOL(insert_pwm_node);
++
++int remove_pwm_node(unsigned int id)
++{
++ int ret = -1;
++ list_handle_t *h = &(pwr_man.tcc_pwm_list);
++ mutex_lock(&(pwr_man.mutex));
++ ret = remove_ll(h, id);
++ mutex_unlock(&(pwr_man.mutex));
++ return ret;
++}
++EXPORT_SYMBOL(remove_pwm_node);
++
++//int callback_pwm_node(stpwrioctl *p_arg)
++int callback_pwm_node(unsigned int id, unsigned int cmd, void *p_info)
++{
++ int ret = -1;
++ list_handle_t *h = &(pwr_man.tcc_pwm_list);
++ if (h) {
++ data_node_t *p_node = NULL;
++
++ mutex_lock(&(pwr_man.mutex));
++ p_node = find_by_id(h, id);
++ if (p_node) {
++ jprintk("call dev-callback -> id[%d]\n", p_node->id);
++ if (p_node->callback) {
++ ret = p_node->callback(get_node_pri(p_node), cmd, p_info);
++ } else {
++ printk("callback is NULL !!! -> id[%d]\n", p_node->id);
++ }
++ } else {
++ printk("--- err --- cannot find dev-node !!! -> id[%d]\n", id);
++ }
++ mutex_unlock(&(pwr_man.mutex));
++ }
++ return ret;
++}
++EXPORT_SYMBOL(callback_pwm_node);
++
++
+diff --git a/drivers/char/tcc_proc.c b/drivers/char/tcc_proc.c
+new file mode 100644
+index 0000000..b3e2525
+--- /dev/null
++++ b/drivers/char/tcc_proc.c
+@@ -0,0 +1,95 @@
++#include <linux/module.h>
++#include <linux/tty.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/proc_fs.h>
++#include <linux/sched.h>
++#include <asm/uaccess.h>
++
++#include <mach/memory.h>
++
++#define MODULE_NAME "tcc"
++#define VCODEC_ADDR "vcodec_addr"
++#define VCODEC_SIZE "vcodec_size"
++#define ADDR_LEN 10
++
++char vcodec_addr_data[ADDR_LEN + 1];
++char vcodec_size_data[ADDR_LEN + 1];
++
++static struct proc_dir_entry *tcc_proc, *vcodec_addr, *vcodec_size;
++
++static int proc_read_vcodec_addr(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len;
++ char *vcodec_addr_data = (char *)data;
++ len = sprintf(page, "%s", vcodec_addr_data);
++ return len;
++}
++
++static int proc_read_vcodec_size(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len;
++ char *vcodec_size_data = (char *)data;
++ len = sprintf(page, "%s", vcodec_size_data);
++ return len;
++}
++
++extern unsigned int TCC_VPU_SIZE;
++#define TCC_VPU_OFFSET CAL_VPU_OFFSET(TCC_RAM_TOTAL_SIZE, TCC_VPU_SIZE)
++
++static int init_tccproc(void)
++{
++ int rv = 0;
++
++ tcc_proc = proc_mkdir(MODULE_NAME, NULL);
++ if (tcc_proc == NULL) {
++ rv = -ENOMEM;
++ goto out;
++ }
++
++ vcodec_addr = create_proc_entry(VCODEC_ADDR, 0444, tcc_proc);
++ vcodec_size = create_proc_entry(VCODEC_SIZE, 0444, tcc_proc);
++ if (vcodec_addr == NULL || vcodec_size == NULL) {
++ rv = -ENOMEM;
++ goto error;
++ }
++
++ /*
++ * Set VPU start address & size
++ */
++ sprintf(vcodec_addr_data, "0x%08x", TCC_VPU_OFFSET);
++ sprintf(vcodec_size_data, "%d", TCC_VPU_SIZE);
++
++ vcodec_addr->data = vcodec_addr_data;
++ vcodec_addr->read_proc = proc_read_vcodec_addr;
++ vcodec_addr->owner = THIS_MODULE;
++
++ vcodec_size->data = vcodec_size_data;
++ vcodec_size->read_proc = proc_read_vcodec_size;
++ vcodec_size->owner = THIS_MODULE;
++
++ printk("%s proc filesystem initialised\n", MODULE_NAME);
++
++ return 0;
++error:
++ remove_proc_entry(VCODEC_ADDR, tcc_proc);
++ remove_proc_entry(VCODEC_SIZE, tcc_proc);
++out:
++ return rv;
++}
++
++static void cleanup_tccproc(void)
++{
++ remove_proc_entry(VCODEC_ADDR, tcc_proc);
++ remove_proc_entry(VCODEC_SIZE, tcc_proc);
++}
++
++module_init(init_tccproc);
++module_exit(cleanup_tccproc);
++
++MODULE_AUTHOR("<linux@telechips.com>");
++MODULE_DESCRIPTION("Telechips Proc Filesystem");
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/char/tcc_pwm.c b/drivers/char/tcc_pwm.c
+new file mode 100644
+index 0000000..ba405d4
+--- /dev/null
++++ b/drivers/char/tcc_pwm.c
+@@ -0,0 +1,118 @@
++/*
++ * linux/drivers/char/tcc_intr.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 31th March, 2009
++ * Description: User-level interrupt Driver
++ *
++ * Copyright (c) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/fs.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/fcntl.h>
++
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/time.h>
++#include <linux/timer.h>
++#include <linux/poll.h>
++
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <bsp.h>
++
++#include <linux/tcc_pwm.h>
++#include <linux/tcc_pwm_ioctl.h>
++#include <linux/tcc_ll.h>
++
++
++#define TCC_PWM_DEV_NAME "tcc-pwm"
++#define TCC_PWM_VERSION "0.1"
++
++
++static int tcc_pwm_ioctl(struct inode *inode, struct file *filp,
++ unsigned int cmd, unsigned long arg)
++{
++ int ret = -1;
++ pwr_ioctl_param_t data;
++
++ switch (cmd) {
++ case IOCTL_PWR_CONTROL:
++ if (copy_from_user((void *)&data, (const void *)arg, sizeof(pwr_ioctl_param_t))) {
++ printk("(%s:%d) cannot copy data from user !!!\n", __func__, __LINE__);
++ return -EFAULT;
++ }
++
++ ret = callback_pwm_node(data.in.deviceid, data.in.cmd, &(data.out));
++ if (ret == 0) {
++ if (copy_to_user((void *)arg, (const void *)&data, sizeof(pwr_ioctl_param_t))) {
++ printk("(%s:%d) cannot copy data to user !!!\n", __func__, __LINE__);
++ return -EFAULT;
++ }
++ }
++
++ break;
++ default:
++ printk("(%s:%d) unknown ioctl cmd (0x%x)\n", __func__, __LINE__, cmd);
++ return -EINVAL;
++ break;
++ }
++
++ return ret;
++}
++
++static int tcc_pwm_release(struct inode *inode, struct file *filp)
++{
++ return 0;
++}
++
++
++static int tcc_pwm_open(struct inode *inode, struct file *filp)
++{
++ return 0;
++}
++
++struct file_operations tcc_pwm_fops =
++{
++ .owner = THIS_MODULE,
++ .ioctl = tcc_pwm_ioctl,
++ .open = tcc_pwm_open,
++ .release = tcc_pwm_release,
++};
++
++static int __init tcc_pwm_init(void)
++{
++ int res;
++
++ res = register_chrdev(TCC_PWM_DEV_MAJOR, TCC_PWM_DEV_NAME, &tcc_pwm_fops);
++ if (res < 0)
++ return res;
++
++ printk("tcc_pwm: init (ver %s)\n", TCC_PWM_VERSION);
++ return 0;
++}
++
++static void __exit tcc_pwm_exit(void)
++{
++ unregister_chrdev(TCC_PWM_DEV_MAJOR, TCC_PWM_DEV_NAME);
++ printk("tcc_pwm: exit\n");
++}
++
++
++module_init(tcc_pwm_init);
++module_exit(tcc_pwm_exit);
++
++MODULE_AUTHOR("Telechips Inc. SYS4-3 linux@telechips.com");
++MODULE_DESCRIPTION("Telechips power control driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/char/tcc_pwrkey.c b/drivers/char/tcc_pwrkey.c
+new file mode 100644
+index 0000000..ec62582
+--- /dev/null
++++ b/drivers/char/tcc_pwrkey.c
+@@ -0,0 +1,501 @@
++/*
++ * linux/drivers/char/tcc_pwrkey.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: July 7, 2009
++ * Description: Power Key Driver for Telechips Boards.
++ *
++ * Copyright (C) 2009 Telechips
++ *
++ * 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
++ *
++ *
++ * ChangeLog:
++ *
++ * July, 2009 : Added Sleep Test functions
++ *
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/moduleparam.h>
++#include <linux/fs.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++
++#include <linux/interrupt.h>
++#include <linux/workqueue.h>
++#include <mach/io.h>
++#include <asm/tlbflush.h>
++#include <asm/cacheflush.h>
++
++#include <bsp.h>
++#include <hhtech_gpio.h>
++#include <mach/gpio.h>
++
++#define PM_DEV_NAME "pwr"
++#define PM_DEV_MAJOR 201
++
++extern int plat_tcc_pm(int mode);
++
++extern int arm_changestack(void);
++extern void arm_restorestack(unsigned int rst);
++
++#define SRAM_ADDR_VAR 0xEFF00600
++#define SRAM_ADDR_STANDBY 0xEFF00000
++#define SRAM_FUNC_SIZE 0x600
++
++/*****************************************************************************
++* Function Name : tca_off_sleep()
++******************************************************************************/
++volatile static void tca_off_sleep(int type)
++{
++
++ volatile unsigned int nCount = 0;
++
++ unsigned long *lPLL0,*lPLL1, *lPLL2, *lPLL3, *BACK4, *BACK5, *BACK6, *BACK7;
++ unsigned long *lFBUS_CORE,*lFBUS_MEM, *lFBUS_DDI,*lFBUS_GRP, *lFBUS_IOB, *lFBUS_VBUS, *lFBUS_VCODEC, *lFBUS_SMU;
++ unsigned long *i, *j, *pPCK, *BAKPCK;
++
++ int lmem_div = 0;
++ int lmem_source = 0;
++ int tmpread = *(volatile unsigned long *)0xF0400008;
++ int count = 0;
++
++ tmpread &= ~0x00200000;
++ lmem_source = tmpread & 0xf;
++ tmpread &= 0xf0;
++
++
++ while(tmpread){
++ tmpread -= 16;
++ lmem_div++;
++ }
++
++ lmem_div += 1;
++
++
++
++ // Let CPU Speed Lower, Low Clock Operation
++ // Assign Registers to Pointers
++ lPLL0 = (unsigned long*)(SRAM_ADDR_VAR);
++ lPLL1 = (unsigned long*)(SRAM_ADDR_VAR+0x04);
++ lPLL2 = (unsigned long*)(SRAM_ADDR_VAR+0x08);
++ lPLL3 = (unsigned long*)(SRAM_ADDR_VAR+0x0C);
++ BACK4 = (unsigned long*)(SRAM_ADDR_VAR+0x10);
++ BACK5 = (unsigned long*)(SRAM_ADDR_VAR+0x14);
++ lFBUS_CORE = (unsigned long*)(SRAM_ADDR_VAR+0x18);
++ lFBUS_MEM = (unsigned long*)(SRAM_ADDR_VAR+0x1C);
++ lFBUS_DDI = (unsigned long*)(SRAM_ADDR_VAR+0x20);
++ lFBUS_GRP = (unsigned long*)(SRAM_ADDR_VAR+0x24);
++ lFBUS_IOB = (unsigned long*)(SRAM_ADDR_VAR+0x28);
++ lFBUS_VBUS = (unsigned long*)(SRAM_ADDR_VAR+0x30);
++ lFBUS_VCODEC = (unsigned long*)(SRAM_ADDR_VAR+0x34);
++ lFBUS_SMU = (unsigned long*)(SRAM_ADDR_VAR+0x38);
++ i = (unsigned long*)(SRAM_ADDR_VAR+0x3C);
++ BAKPCK = (unsigned long*)(SRAM_ADDR_VAR+0x40);
++
++ *lFBUS_CORE = *(volatile unsigned long *)0xF0400000 ;
++ *lFBUS_DDI = *(volatile unsigned long *)0xF0400004;
++ *lFBUS_MEM = *(volatile unsigned long *)0xF0400008;
++ *lFBUS_GRP = *(volatile unsigned long *)0xF040000C;
++ *lFBUS_IOB = *(volatile unsigned long *)0xF0400010;
++ *lFBUS_VBUS = *(volatile unsigned long *)0xF0400014;
++ *lFBUS_VCODEC = *(volatile unsigned long *)0xF0400018;
++ *lFBUS_SMU = *(volatile unsigned long *)0xF040001C;
++
++ *lPLL0 = *(volatile unsigned long *)0xF0400020;
++ *lPLL1 = *(volatile unsigned long *)0xF0400024;
++ *lPLL2 = *(volatile unsigned long *)0xF0400028;
++ *lPLL3 = *(volatile unsigned long *)0xF040002c;
++
++ // Save All of PCK_XXX Register
++ pPCK = (unsigned long*)(0xF0400080);
++
++ for( *i=0; *i<37; (*i)++ )
++ {
++ BAKPCK[*i] = *pPCK;
++ if(((BAKPCK[*i] & 0x1f000000) != 0x14000000) ){
++ *pPCK = (BAKPCK[*i] & ~0x10000000);
++ }
++ pPCK ++;
++ }
++
++ *BACK4 = *(volatile unsigned long *)0xF0404004;
++ *BACK5 = *(volatile unsigned long *)0xF0404000;
++
++
++ //Enter Self-Refresh Mode
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=3); // Wait PL34X_STATUS_LOWPOWER
++
++ // To prevent input leakage
++ *(volatile unsigned long *)0xF0304400 |= 0x00000004;
++ // DLL OFF
++ *(volatile unsigned long *)0xF0304404 &= ~(0x00000003); // DLL-0FF,DLL-Stop running
++ *(volatile unsigned long *)0xF0304428 &= ~(0x00000003); // Calibration Start,Update Calibration
++ *(volatile unsigned long *)0xF030302c &= ~(0x00004000); //SDRAM IO Control Register Gatein Signal Power Down
++
++ nCount = ((*(volatile unsigned long *)0xF030200C) & ~(0x00004000));
++ *(volatile unsigned long *)0xF030200C = nCount| (1<<14); // Stop-MCLK Enter Self-refresh mode
++
++
++ nCount = 800;
++ for ( ; nCount > 0 ; nCount --); // Wait
++ nCount = 800;
++ for ( ; nCount > 0 ; nCount --); // Wait
++
++ *(volatile unsigned long *)0xF0400000 = 0x002ffff4; // CKC-CLKCTRL0 - set cpu clk to XIN
++ *(volatile unsigned long *)0xF0400004 = 0x00200014; // CKC-CLKCTRL1 - set display clk to XIN
++ *(volatile unsigned long *)0xF0400008 = 0x00200014; // CKC-CLKCTRL2 - set memory clk to XIN
++
++
++ *(volatile unsigned long *)0xF040000c = 0x00200014; // CKC-CLKCTRL3 - set graphic clk to XIN
++ *(volatile unsigned long *)0xF0400010 = 0x00200014; // CKC-CLKCTRL4 - set io clk to XIN
++
++ *(volatile unsigned long *)0xF0400014 = 0x00200014; // CKC-CLKCTRL5 - set video bus clk to XIN
++ *(volatile unsigned long *)0xF0400018 = 0x00200014; // CKC-CLKCTRL6 - set video core clk to XIN
++ *(volatile unsigned long *)0xF040001c = 0x00200014; // CKC-CLKCTRL7 - set SMU clk to XIN
++
++
++ *(volatile unsigned long *)0xF0400020 &= ~0x80000000; // CKC-PLL0CFG - PLL disable
++ *(volatile unsigned long *)0xF0400024 &= ~0x80000000; // CKC-PLL1CFG - PLL disable
++ *(volatile unsigned long *)0xF0400028 &= ~0x80000000; // CKC-PLL2CFG - PLL disable
++ *(volatile unsigned long *)0xF040002c &= ~0x80000000; // CKC-PLL3CFG - PLL disable
++
++
++ //go power down mode......
++
++// *(volatile unsigned long *)0xF0102024 &= ~(0x0000f000); //
++// *(volatile unsigned long *)0xF0102004 &= ~(0x00000008); //
++
++ *(volatile unsigned long *)0xF01020EC &= ~(0x00000f00);
++ *(volatile unsigned long *)0xF01020C4 &= ~(0x00040000);
++
++
++ // *(volatile unsigned long *)0xF0404000 |= 0x00000010; // PMU-CONTROL - Download ITCM boot code
++
++// *(volatile unsigned long *)0xF0404000 |= 0x00000008; // PMU-CONTROL - Deep Power-Down
++
++// *(volatile unsigned long *)0xF0404000 |= 0x80000000; // PMU-CONTROL - I/O Retension Enable
++
++ if(type == 0)
++ {
++ *(volatile unsigned long *)0xF0404008 = 0x00002800; // PMU-WKUPPOL - SRCS[15](GPIO A3) active low
++ *(volatile unsigned long *)0xF0404004 = 0x00002800; // PMU-WKUPEN - SRCS[15](GPIO A3) enable
++ }else if(type == 1)
++ {
++ *(volatile unsigned long *)0xF0404008 = 0x00000800;
++ *(volatile unsigned long *)0xF0404004 = 0x00000800;
++
++ }else if(type == 2)
++ {
++ *(volatile unsigned long *)0xF0404008 = 0x00002000;
++ *(volatile unsigned long *)0xF0404004 = 0x00002000;
++ }
++
++
++#if 0 /* comment by csduan */
++ *(volatile unsigned long *)0xf0240050 |= 0x1;
++ nCount = 5000;
++ for ( ; nCount > 0 ; nCount --); // delay
++ //SWRESET ON
++ *(volatile unsigned long *)0xf0400044 |= 0x2;//Ddi Bus
++ nCount = 5000;
++ for ( ; nCount > 0 ; nCount --); // delay
++ //pmu disable
++ *(volatile unsigned long *)0xf0404018 |= 0x80;//Ddi Bus
++ nCount = 1000;
++ for ( ; nCount > 0 ; nCount --); // Wait
++
++#endif /* comment by csduan */
++
++ *(volatile unsigned long *)0xF0404000 |= 0x00000004; // PMU-CONTROL - Power Off
++
++
++ //wakeup start
++
++ nCount = 10;
++ for ( ; nCount > 0 ; nCount --); // Wait
++
++ *(volatile unsigned long *)0xF0400020 = *lPLL0;
++ *(volatile unsigned long *)0xF0400024 = *lPLL1;
++ *(volatile unsigned long *)0xF0400028 = *lPLL2;
++ *(volatile unsigned long *)0xF040002c = *lPLL3;
++
++#if 0 /* comment by csduan */
++ nCount = 1000;
++ for ( ; nCount > 0 ; nCount --); // Wait
++ //pmu disable
++ *(volatile unsigned long *)0xf0404018 &= ~(0x80);//Ddi Bus
++ nCount = 10000;
++ for ( ; nCount > 0 ; nCount --); // delay
++ //SWRESET OFF
++ *(volatile unsigned long *)0xf0400044 &= ~(0x2);//Ddi Bus
++ *(volatile unsigned long *)0xf0240050 &= ~(0x1);
++
++#endif /* comment by csduan */
++
++ nCount = 10;
++ for ( ; nCount > 0 ; nCount --); // Wait
++
++ *(volatile unsigned long *)0xF0400000 = *lFBUS_CORE ;
++ *(volatile unsigned long *)0xF0400008 = *lFBUS_MEM;
++ /*
++ for (nCount=0;nCount<10;nCount++)
++ *(volatile unsigned long *)0xF0302008 = 0x00040000; // Direct COmmnad Register
++ */
++
++ pPCK = (unsigned long*)(0xF0400080);
++
++ for( (*i)=0; (*i)<37; (*i)++)
++ *pPCK++ = BAKPCK[*i];
++
++ nCount = 0x100;
++ for ( ; nCount > 0 ; nCount --); // Wait
++
++ *(volatile unsigned long *)0xF0400004 = *lFBUS_DDI;
++ *(volatile unsigned long *)0xF040000C = *lFBUS_GRP;
++ *(volatile unsigned long *)0xF0400010 = *lFBUS_IOB;
++ *(volatile unsigned long *)0xF0400014 = *lFBUS_VBUS;
++ *(volatile unsigned long *)0xF0400018 = *lFBUS_VCODEC;
++ *(volatile unsigned long *)0xF040001C = *lFBUS_SMU;
++
++ //Exit Self-Refresh Mode
++ // Exit SelfRefresh
++ *(volatile unsigned long *)0xF030200C &= ~(0x00004000);
++ *(volatile unsigned long *)0xF0304400 &= ~(0x00000004);
++
++ /*
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL341_WakeUP
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++ *(volatile unsigned long *)0xF0302004 = 0x00000003; // PL341_PAUSE
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++ *(volatile unsigned long *)0xF0302004 = 0x00000001; // PL341_SLEEP
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=3); // Wait PL34X_STATUS_LOWPOWER
++ */
++
++ // DLL ON
++ *(volatile unsigned long *)0xF030302C |= 0x00004000; // SSTL SDRAM IO Control Register
++ *(volatile unsigned long *)0xF0303020 |= 0x00000001; // Common Register AXI_SEL
++ *(volatile unsigned long *)0xF0303020 |= 0x00000002; // Common Register IO_SEL
++ *(volatile unsigned long *)0xF0303024 &= ~(0x00000100); // PHYCTRL Seletct DDR2
++
++ *(volatile unsigned long *)0xF0304400 = 0x0;
++ *(volatile unsigned long *)0xF0304404 = 0x00000001; // DLL-On
++ //330Mhz
++ if(lmem_div == 1){
++ if((*lPLL0/1) >= 400 && lmem_source == 0)
++ *(volatile unsigned long *)0xF0304408 = 0x00001212; // DLLPDCFG
++ else
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++ }
++ else{
++ if((*lPLL0/2) >= 400 && lmem_source == 0)
++ *(volatile unsigned long *)0xF0304408 = 0x00001212; // DLLPDCFG
++ else
++ *(volatile unsigned long *)0xF0304408 = 0x00001717; // DLLPDCFG
++ }
++
++
++// *(volatile unsigned long *)0xF0304408 = 0x00001414; // DLLPDCFG
++ *(volatile unsigned long *)0xF0304404 = (0x00000003); // DLL-On, DLL-Start
++ while (((*(volatile unsigned long *)0xF0304404) & (0x00000018)) != (0x00000018)); // Wait DLL Lock
++
++ *(volatile unsigned long *)0xF0304424 = 0x35; // DLL Force Lock Value Register
++ *(volatile unsigned long *)0xF030440C = 0x6; // Gate Control
++
++ if(lmem_div == 1){
++ if((*lPLL0/1) >= 400 && lmem_source == 0)
++ *(volatile unsigned long *)0xF0304430 = 0x1; // uRDDELAY Read Delay Register
++ else
++ *(volatile unsigned long *)0xF0304430 = 0x4; // uRDDELAY Read Delay Register
++ }
++ else{
++
++ if((*lPLL0/2) >= 400 && lmem_source == 0)
++ *(volatile unsigned long *)0xF0304430 = 0x1; // uRDDELAY Read Delay Register
++ else
++ *(volatile unsigned long *)0xF0304430 = 0x4; // uRDDELAY Read Delay Register
++
++ }
++
++
++ //DBG_PRINT ("ZQ Cal ...");
++ *(volatile unsigned long *)0xF0304428 = 0
++ | (0x1 << 0) // Calibration Start
++ | (0x0 << 1) // Update Calibration
++ | (0x0 << 2) // Override ctrl_force_impp[2:0]/impn[2:0]
++ | (0x2 << 3) // Calibration PULL-UP forced value
++ | (0x5 << 6) // Calibration PULL-DOWN forced value
++ | (0x0 << 9) // On-Die Termination Resistor Value Selection
++ | (0x0 << 12) // Termination Selection : 0 for disable
++ | (0x7 << 13) // Drive Strength
++ | (0x0 << 16) // Periodic Calibration
++ | (0x3 << 17) // Update Counter Load Value
++ ;
++ //ZQCalWait
++ while (((*(volatile unsigned long *)0xF030442C & (0x00000001)) != (0x00000001)));
++
++ //ZQCalUpdate
++ *(volatile unsigned long *)0xF0304428 |= 0x00000002;
++ *(volatile unsigned long *)0xF0304428 &= ~0x00000002;
++ // END DLL On
++
++ *(volatile unsigned long *)0xF0302004 = 0x00000002; // PL341_WakeUP
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=2); //Wait PL34X_STATUS_PAUSED
++ *(volatile unsigned long *)0xF0302004 = 0x00000004; // PL341_Configure
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=0); //Wait PL34X_STATUS_CONFIG
++ *(volatile unsigned long *)0xF0302004 = 0x00000000; // PL341_GO
++ while (((*(volatile unsigned long *)0xF0302000) & 0x3)!=1); //Wait PL34X_STATUS_READY
++
++}
++typedef void (*lpfunc)(int);
++static lpfunc sleep;
++extern int noneed_respond;
++volatile static void tca_off_copysram(int type)
++{
++ // Setup Pointer
++ volatile unsigned int *fptr;
++ volatile unsigned int *p;
++ int i;
++ unsigned int lstack = 0;
++
++ PTIMER vTimerAddr = (PTIMER)((unsigned int)&HwTMR_BASE);
++ PGPIO vGpioAddr = (PGPIO)((unsigned int)&HwGPIO_BASE);
++
++ // Copy Function Contents to SRAM
++ fptr = (volatile unsigned int*)tca_off_sleep;
++ // Copy Function Contents to SRAM
++ sleep = (lpfunc)(SRAM_ADDR_STANDBY);
++
++ p = (volatile unsigned int*)SRAM_ADDR_STANDBY;
++
++ for (i = 0;i < (SRAM_FUNC_SIZE);i++)
++ {
++ *p = *fptr;
++ p++;
++ fptr++;
++ }
++
++ while(--i);
++
++ // Jump to Function Start Point
++
++ noneed_respond = 1;// ignore first touch when wakeup
++
++ *(volatile unsigned long *)0xF0102024 &= ~(0xff0000);// set gpio func
++ *(volatile unsigned long *)0xF0102004 |= 0x30;// set GPIOA4 and GPIOA5 as output
++ *(volatile unsigned long *)0xF0102000 &= ~(0x30);//turn off lcd power and backlight
++
++ sleep(type);
++
++ *(volatile unsigned long *)0xF0102000 |= 0x10;//turn on a4
++ tca_bkl_powerup((unsigned int)vTimerAddr,(unsigned int)vGpioAddr);//turn on backlight
++}
++extern int sleep_type;
++void selfrefresh_test(void)
++{
++ unsigned long flags;
++ unsigned int retstack = 0;
++ volatile PLCDC pLCDC_BASE0 = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++ volatile PLCDC pLCDC_BASE1 = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ volatile PTIMER pTIMER = (volatile PTIMER)tcc_p2v(HwTMR_BASE);
++
++ // Off LCD
++ pLCDC_BASE1->LCTRL &= ~Hw0;
++ pLCDC_BASE0->LCTRL &= ~Hw0;
++
++ int_alldisable();
++ local_flush_tlb_all();
++ flush_cache_all();
++
++ pTIMER->TC32EN &= ~Hw24;
++
++ retstack = arm_changestack();
++
++ tca_off_copysram(sleep_type);
++
++ arm_restorestack(retstack);
++
++ pTIMER->TC32EN |= Hw24;
++ int_restore();
++
++ // LCDC Power Up
++// pLCDC_BASE0->LCTRL |= Hw0;
++ pLCDC_BASE1->LCTRL |= Hw0;
++}
++
++
++
++static int tcc_pwrkey_ioctl(struct inode *inode, struct file *filp,
++ unsigned int cmd, unsigned long arg)
++{
++ return 0;
++}
++
++static int tcc_pwrkey_release(struct inode *inode, struct file *filp)
++{
++ return 0;
++}
++
++int tcc_pwrkey_open(struct inode *inode, struct file *filp)
++{
++ selfrefresh_test();
++ return 0;
++}
++
++struct file_operations tcc_pwrkey_fops =
++{
++ .owner = THIS_MODULE,
++ .open = tcc_pwrkey_open,
++ .ioctl = tcc_pwrkey_ioctl,
++ .release = tcc_pwrkey_release,
++};
++
++
++
++static int __init pwrkey_init(void)
++{
++ int res;
++
++ res = register_chrdev(PM_DEV_MAJOR, PM_DEV_NAME, &tcc_pwrkey_fops);
++ if (res < 0)
++ return res;
++
++ printk("pwrkey: init\n");
++ return 0;
++}
++
++static void __exit pwrkey_exit(void)
++{
++ unregister_chrdev(PM_DEV_MAJOR, PM_DEV_NAME);
++ printk("pwrkey: exit\n");
++}
++
++module_init(pwrkey_init);
++module_exit(pwrkey_exit);
++
++MODULE_AUTHOR("Telechips Inc. <linux@telechips.com>");
++MODULE_DESCRIPTION("TCC Power Button driver");
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/dpm/Kconfig b/drivers/dpm/Kconfig
+new file mode 100644
+index 0000000..73d4624
+--- /dev/null
++++ b/drivers/dpm/Kconfig
+@@ -0,0 +1,29 @@
++#
++# Dynamic Power Management
++#
++menu "Dynamic Power Management"
++
++config DPM
++ bool "Dynamic Power Management"
++ help
++ Enable Dynamic Power Management, if implemented for your platform.
++ DPM conserves power by adjusting power parameters according to
++ system state (such as idle, running a high-power-usage task, etc.)
++ and enables associated power management features such as device
++ constraints on power parameters. DPM relies on power policy and
++ machine-dependent power operating points and such to be configured
++ from userspace after boot.
++
++ If in doubt, say N.
++
++config DPM_PROCFS
++ bool "Enable old DPM /proc interface (deprecated)"
++ depends on DPM && PROC_FS
++ help
++ This enables the /proc/driver/dpm interface for controlling
++ DPM. Please note that it is recommended to use the sysfs
++ interface instead (which is built automatically).
++
++ If in doubt, say N.
++
++endmenu
+diff --git a/drivers/dpm/Makefile b/drivers/dpm/Makefile
+new file mode 100644
+index 0000000..1e0c5f1
+--- /dev/null
++++ b/drivers/dpm/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the kernel DPM driver.
++#
++
++obj-$(CONFIG_DPM) += dpm.o dpm-idle.o dpm-ui.o
++obj-$(CONFIG_DPM_PROCFS) += proc.o
++
+diff --git a/drivers/dpm/dpm-idle.c b/drivers/dpm/dpm-idle.c
+new file mode 100644
+index 0000000..b170067
+--- /dev/null
++++ b/drivers/dpm/dpm-idle.c
+@@ -0,0 +1,174 @@
++/*
++ *
++ * 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
++ *
++ * Copyright (C) 2002, MontaVista Software <source@mvista.com>.
++ *
++ * Based on ibm405lp_dpm.c by Bishop Brock, Copyright (C) 2002,
++ * International Business Machines Corporation.
++ */
++
++#include <linux/dpm.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/kmod.h>
++#include <linux/module.h>
++#include <linux/proc_fs.h>
++#include <linux/stat.h>
++#include <linux/string.h>
++
++#include <asm/delay.h>
++#include <asm/hardirq.h>
++#include <asm/page.h>
++#include <asm/processor.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#if 0
++#define dbg printk
++#else /* no debug */
++#define dbg(x...) do {} while(0)
++#endif
++
++/****************************************************************************
++ * DPM Idle Handler
++ ****************************************************************************/
++
++/*
++ The idle handler is one of the most important parts of DPM, as very
++ significant amounts of energy are saved by moving to a low-power idle state
++ whenever possible. The basic coding of the core of this routine is simply:
++
++ dpm_set_os(DPM_IDLE_STATE);
++ machine-dependent-idle-routine();
++ dpm_set_os(DPM_IDLE_TASK_STATE);
++
++ The added complexity found here is introduced to avoid unnecessary work, and
++ especially to reduce the latencies associated with going in and out of idle.
++ Idle power can be greatly reduced by moving to a very low-frequency
++ operating point, but we also need to be aware of the impact on interrupt
++ latencies. The DPM implementation of idle attempts to balance these
++ competing needs.
++
++ We support 2 "idle" states: DPM_IDLE_TASK_STATE and DPM_IDLE_STATE. The
++ idle thread is marked as a "no-state" task, so that operating point changes
++ are not automatically made when the idle thread is scheduled. The
++ "idle-task" state is used for the majority of the idle thread. Interrupts
++ that occur during idle are handled in this state as well. The "idle" state
++ is only entered from the idle-task state, and only for the express purpose
++ of allowing an ultra-low-power operating point.
++
++ The introduction of the idle-task state supports a stepped voltage and
++ frequency scaling at idle. On the IBM 405LP we would not want to go from,
++ e.g., 266/133 @ 1.8 V directly to 8/8 @ 1.0 V and back. Why not? Because
++ we would get "stuck" at 8MHz even though we need to wake up and resume
++ useful work, e.g., we would have to set the 266/133 operating point while
++ running at 8/8. So instead when going idle first step down to idle-task,
++ e.g., 100/50 @ 1.0 V, and then step down to e.g. 8/8 to halt. The interrupt
++ that takes us out of idle takes us back to idle-task (100/50) for interrupt
++ processing and the potential return to 266/133.
++
++ The best policies for this implementation will be able to transition between
++ idle-task and idle without voltage scaling or driver notification. In these
++ cases the transitions are handled with minimal latency by simple frequency
++ scaling. */
++
++static inline void
++quick_idle(void)
++{
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++ dpm_quick_enter_state(DPM_IDLE_STATE);
++ dpm_md_idle();
++ dpm_quick_enter_state(DPM_IDLE_TASK_STATE);
++}
++
++static void
++full_idle(struct dpm_opt *idle_task_opt, struct dpm_opt *idle_opt)
++{
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++ dpm_quick_enter_state(DPM_IDLE_STATE);
++#ifdef CONFIG_DPM_STATS
++ dpm_update_stats(&idle_opt->stats, &idle_task_opt->stats);
++#endif
++ dpm_set_opt(idle_opt, DPM_SYNC);
++ dpm_md_idle();
++ dpm_set_opt(idle_task_opt, DPM_SYNC);
++ dpm_quick_enter_state(DPM_IDLE_TASK_STATE);
++#ifdef CONFIG_DPM_STATS
++ dpm_update_stats(&idle_task_opt->stats, &idle_opt->stats);
++#endif
++}
++
++
++/* If DPM is currently disabled here we simply do the standard
++ idle wait.
++
++ If we're not actually in DPM_IDLE_TASK_STATE, we need to go back and get
++ into this state. This could happen in rare instances - an interrupt between
++ dpm_set_os() and the critical section.
++
++ If we are not yet at the idle-task operating point, or if there is no
++ difference between idle-task and idle, we can enter/exit the idle state
++ quickly since it's only for statistical purposes. This is also true if for
++ some reason we can't get the DPM lock, since obviously an asynchronous event
++ is going to have to occur to clear the lock, and this event is going to take
++ us out of idle.
++
++ Otherwise the full idle shutdown is done. */
++
++
++void
++dpm_idle(void)
++{
++ unsigned long flags;
++ struct dpm_opt *idle_task_opt, *idle_opt;
++
++ current->dpm_state = DPM_NO_STATE;
++ dpm_set_os(DPM_IDLE_TASK_STATE);
++ local_irq_save(flags);
++
++ if (! need_resched()) {
++ if (!dpm_enabled) {
++ dpm_md_idle();
++
++ } else if (dpm_active_state != DPM_IDLE_TASK_STATE) {
++
++
++ } else {
++ idle_task_opt = dpm_choose_opt(dpm_active_policy,
++ DPM_IDLE_TASK_STATE);
++ idle_opt = dpm_choose_opt(dpm_active_policy,
++ DPM_IDLE_STATE);
++
++ if (dpm_trylock()) {
++ dpm_md_idle();
++ } else {
++
++ if ((dpm_active_opt != idle_task_opt) ||
++ (idle_task_opt == idle_opt)) {
++
++ quick_idle();
++ dpm_unlock();
++ } else {
++ dpm_unlock();
++ full_idle(idle_task_opt, idle_opt);
++ }
++ }
++ }
++ }
++ local_irq_restore(flags);
++}
++
+diff --git a/drivers/dpm/dpm-ui.c b/drivers/dpm/dpm-ui.c
+new file mode 100644
+index 0000000..88cb546
+--- /dev/null
++++ b/drivers/dpm/dpm-ui.c
+@@ -0,0 +1,1378 @@
++/*
++ * drivers/dpm/dpm-ui.c - userspace interface to Dynamic Power Management
++ *
++ * (c) 2003 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 <linux/dpm.h>
++#include <linux/device.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/kobject.h>
++#include <linux/sysfs.h>
++#include <linux/sched.h>
++
++#include <plat/dpm.h>
++#include <bsp.h>
++
++
++#if 0
++#define dbg printk
++#else /* no debug */
++#define dbg(x...) do {} while(0)
++#endif
++
++/* Common sysfs/proc support */
++
++char *dpm_state_names[DPM_STATES] = DPM_STATE_NAMES;
++char *dpm_param_names[DPM_PP_NBR] = DPM_PARAM_NAMES;
++
++#define MAXTOKENS 80
++
++static int
++tokenizer(char **tbuf, const char *userbuf, ssize_t n, char **tokptrs,
++ int maxtoks)
++{
++ char *cp, *tok;
++ char *whitespace = " \t\r\n";
++ int ntoks = 0;
++
++ if (!(cp = kmalloc(n + 1, GFP_KERNEL)))
++ return -ENOMEM;
++
++ *tbuf = cp;
++ memcpy(cp, userbuf, n);
++ cp[n] = '\0';
++
++ do {
++ cp = cp + strspn(cp, whitespace);
++ tok = strsep(&cp, whitespace);
++ if ((*tok == '\0') || (ntoks == maxtoks))
++ break;
++ tokptrs[ntoks++] = tok;
++ } while(cp);
++
++ return ntoks;
++}
++
++
++/* SysFS Interface */
++
++#define dpm_attr(_name,_prefix) \
++static struct kobj_attribute _prefix##_attr = { \
++ .attr = { \
++ .name = __stringify(_name), \
++ .mode = 0644, \
++ }, \
++ .show = _prefix##_show, \
++ .store = _prefix##_store, \
++}
++
++
++static void dpm_kobj_release(struct kobject *kobj)
++{
++ /*
++ * No sysfs/kobject state to release, DPM layer will handle the
++ * the containing object.
++ */
++
++ return;
++}
++
++/*
++ * Top-level control
++ */
++
++static ssize_t dpm_control_show(struct kobject *dpm_kobj, struct kobj_attribute *attr, char * buf)
++{
++ unsigned long flags;
++ ssize_t len = 0;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (dpm_lock_interruptible())
++ return -ERESTARTSYS;
++
++ if (!dpm_enabled) {
++ len += sprintf(buf, "disabled\n");
++ } else {
++ spin_lock_irqsave(&dpm_policy_lock, flags);
++ len += sprintf(buf,"enabled %s %d %s %s %s\n",
++ dpm_active_policy->name,
++ dpm_active_state,
++ dpm_state_names[dpm_active_state],
++ dpm_classopt_name(dpm_active_policy,
++ dpm_active_state),
++ dpm_active_opt ? dpm_active_opt->name : "[none]");
++ spin_unlock_irqrestore(&dpm_policy_lock, flags);
++ }
++
++ dpm_unlock();
++ return len;
++}
++
++static ssize_t dpm_control_store(struct kobject *dpm_kobj, struct kobj_attribute *attr, const char * buf,
++ size_t n)
++{
++ int error = 0;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (strncmp(buf, "init", 4) == 0) {
++ error = dynamicpower_init();
++ } else if (strncmp(buf, "enable", 6) == 0) {
++ error = dynamicpower_enable();
++ } else if (strncmp(buf, "disable", 7) == 0) {
++ error = dynamicpower_disable();
++ } else if (strncmp(buf, "terminate", 9) == 0) {
++ error = dynamicpower_terminate();
++ } else
++ error = -EINVAL;
++
++ return error ? error : n;
++}
++
++dpm_attr(control,dpm_control);
++
++static struct attribute * g[] = {
++ &dpm_control_attr.attr,
++ NULL,
++};
++
++static struct attribute_group dpm_attr_group = {
++ .attrs = g,
++};
++
++/* kset to create /sys/dpm/ */
++static struct kobject *dpm_kobj;
++static struct kset *dpm_kset;
++
++/*
++ * policy
++ */
++
++struct dpm_policy_attribute {
++ struct attribute attr;
++ ssize_t (*show)(struct kobject * kobj, char * buf);
++ ssize_t (*store)(struct kobject * kobj, const char * buf, size_t count);
++};
++
++#define to_policy(obj) container_of(obj,struct dpm_policy,kobj)
++#define to_policy_attr(_attr) container_of(_attr,struct dpm_policy_attribute,attr)
++
++static struct kobject *dpm_policy_kobj;
++/*
++static struct kobject dpm_policy_kobj = {
++ .kset = &dpm_kset,
++};
++*/
++
++static ssize_t policy_control_show(struct kobject *dpm_kobj, struct kobj_attribute *attr, char * buf)
++{
++ ssize_t len = 0;
++ struct list_head * p;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (dpm_lock_interruptible())
++ return -ERESTARTSYS;
++
++ len += sprintf(buf + len, "policies: ");
++
++ list_for_each(p, &dpm_policies) {
++ len += sprintf(buf + len, "%s ",
++ ((struct dpm_policy *)
++ list_entry(p, struct dpm_policy, list))->name);
++ }
++
++ len += sprintf(buf + len, "\n");
++ dpm_unlock();
++ return len;
++}
++
++static ssize_t policy_control_store(struct kobject *dpm_kobj, struct kobj_attribute *attr, const char * buf,
++ size_t n)
++{
++ int error = 0;
++ char *tbuf = NULL;
++ char *token[MAXTOKENS];
++ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS);
++
++ if (ntoks <= 0) {
++ error = ntoks;
++ goto out;
++ }
++
++ if (strcmp(token[0],"create") == 0) {
++ error = dpm_create_policy(token[1], &token[2], ntoks - 2);
++ } else if (strcmp(token[0],"set") == 0) {
++ if (ntoks != 2)
++ printk("dpm: policy set requires 1 policy name argument\n");
++ else
++ error = dpm_set_policy(token[1]);
++ } else
++ error = -EINVAL;
++
++ out:
++ if (tbuf)
++ kfree(tbuf);
++ return error ? error : n;
++}
++
++static ssize_t active_policy_show(struct kobject *dpm_kobj, struct kobj_attribute *attr, char * buf)
++{
++ unsigned long flags;
++ ssize_t len = 0;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (dpm_lock_interruptible())
++ return -ERESTARTSYS;
++
++ if (!dpm_enabled || (dpm_active_state == DPM_NO_STATE)) {
++ len += sprintf(buf + len, "[none]\n");
++ } else {
++ spin_lock_irqsave(&dpm_policy_lock, flags);
++ len += sprintf(buf + len,"%s\n",
++ dpm_active_policy->name);
++ spin_unlock_irqrestore(&dpm_policy_lock, flags);
++ }
++
++ dpm_unlock();
++ return len;
++}
++
++static ssize_t active_policy_store(struct kobject *dpm_kobj, struct kobj_attribute *attr, const char * buf,
++ size_t n)
++{
++ int error = 0;
++ char *tbuf = NULL;
++ char *token[MAXTOKENS];
++ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS);
++
++ if (ntoks <= 0) {
++ error = ntoks;
++ goto out;
++ }
++
++ error = dpm_set_policy(token[0]);
++
++ out:
++ if (tbuf)
++ kfree(tbuf);
++ return error ? error : n;
++}
++
++dpm_attr(control,policy_control);
++dpm_attr(active,active_policy);
++
++#ifdef CONFIG_DPM_STATS
++static ssize_t policy_stats_show(struct kobject *dpm_kobj, char * buf)
++{
++ int len = 0;
++ struct dpm_policy *policy;
++ struct list_head *p;
++ unsigned long long total_time;
++
++ if (dpm_lock_interruptible())
++ return -ERESTARTSYS;
++
++ if (!dpm_enabled) {
++ dpm_unlock();
++ len += sprintf(buf + len, "DPM IS DISABLED\n");
++ return len;
++ }
++
++ for (p = dpm_policies.next; p != &dpm_policies; p = p->next) {
++ policy = list_entry(p, struct dpm_policy, list);
++ len += sprintf(buf + len, "policy: %s", policy->name);
++ total_time = policy->stats.total_time;
++ if (policy == dpm_active_policy)
++ total_time += (unsigned long long) dpm_time() -
++ policy->stats.start_time;
++ len += sprintf(buf + len, " ticks: %Lu times: %lu\n",
++ total_time,
++ policy->stats.count);
++ }
++
++ dpm_unlock();
++ return len;
++}
++
++static ssize_t policy_stats_store(struct kobject *dpm_kobj, const char * buf,
++ size_t n)
++{
++ return n;
++}
++
++dpm_attr(stats, policy_stats);
++#endif /* CONFIG_DPM_STATS */
++
++static ssize_t a_policy_control_show(struct kobject * kobj, char * buf)
++{
++ struct dpm_policy *policy = to_policy(kobj);
++ ssize_t len = 0;
++ int i;
++
++ len += sprintf(buf + len, "ops/classes: ");
++
++ for (i = 0; i < DPM_STATES; i++)
++ len += sprintf(buf + len, "%s ", dpm_classopt_name(policy,i));
++
++ len += sprintf(buf + len, "\n");
++ return len;
++}
++
++static ssize_t a_policy_control_store(struct kobject * kobj, const char * buf,
++ size_t n)
++{
++ struct dpm_policy *policy = to_policy(kobj);
++ int error = 0;
++ char *tbuf = NULL;
++ char *token[MAXTOKENS];
++ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS);
++
++ if (ntoks <= 0) {
++ error = ntoks;
++ goto out;
++ }
++
++ if (strcmp(token[0],"destroy") == 0) {
++ dpm_destroy_policy(policy->name);
++ } else
++ error = -EINVAL;
++
++ out:
++ if (tbuf)
++ kfree(tbuf);
++ return error ? error : n;
++}
++
++#define POLICY_STATE_ATTR(index) \
++static ssize_t policy_state ## index ## _show(struct kobject * kobj, \
++ char * buf) \
++{ \
++ ssize_t len = 0; \
++ struct dpm_policy *policy = to_policy(kobj); \
++ len += sprintf(buf + len, "%s\n", policy->classopt[index].opt ? policy->classopt[index].opt->name :policy->classopt[index].class->name ); \
++ return len; \
++} \
++static ssize_t policy_state ## index ## _store(struct kobject * kobj, \
++ const char * buf, \
++ size_t n) \
++{ \
++ struct dpm_policy *policy = to_policy(kobj); \
++ struct dpm_classopt old_classopt; \
++ int ret; \
++ \
++ dpm_lock(); \
++ old_classopt = policy->classopt[index]; \
++ if ((ret = dpm_map_policy_state(policy,index,(char *)buf))) \
++ policy->classopt[index] = old_classopt; \
++ dpm_unlock(); \
++ return ret ? -EINVAL : n; \
++} \
++static struct dpm_policy_attribute policy_state ## index ## _attr = { \
++ .attr = { \
++ .mode = 0644, \
++ }, \
++ .show = policy_state ## index ## _show, \
++ .store = policy_state ## index ## _store, \
++}; \
++
++#define MAX_POLICY_STATES 20
++POLICY_STATE_ATTR(0);
++POLICY_STATE_ATTR(1);
++POLICY_STATE_ATTR(2);
++POLICY_STATE_ATTR(3);
++POLICY_STATE_ATTR(4);
++POLICY_STATE_ATTR(5);
++POLICY_STATE_ATTR(6);
++POLICY_STATE_ATTR(7);
++POLICY_STATE_ATTR(8);
++POLICY_STATE_ATTR(9);
++POLICY_STATE_ATTR(10);
++POLICY_STATE_ATTR(11);
++#if 0
++POLICY_STATE_ATTR(12);
++POLICY_STATE_ATTR(13);
++POLICY_STATE_ATTR(14);
++POLICY_STATE_ATTR(15);
++POLICY_STATE_ATTR(16);
++POLICY_STATE_ATTR(17);
++POLICY_STATE_ATTR(18);
++POLICY_STATE_ATTR(19);
++#endif
++
++static struct dpm_policy_attribute *policy_state_attr[MAX_POLICY_STATES] = {
++ &policy_state0_attr,
++ &policy_state1_attr,
++ &policy_state2_attr,
++ &policy_state3_attr,
++ &policy_state4_attr,
++ &policy_state5_attr,
++ &policy_state6_attr,
++ &policy_state7_attr,
++ &policy_state8_attr,
++ &policy_state9_attr,
++ &policy_state10_attr,
++ &policy_state11_attr,
++#if 0
++ &policy_state12_attr,
++ &policy_state13_attr,
++ &policy_state14_attr,
++ &policy_state15_attr,
++ &policy_state16_attr,
++ &policy_state17_attr,
++ &policy_state18_attr,
++ &policy_state19_attr,
++#endif
++};
++
++static ssize_t
++policy_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
++{
++ struct dpm_policy_attribute * policy_attr = to_policy_attr(attr);
++ ssize_t ret = 0;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (policy_attr->show)
++ ret = policy_attr->show(kobj,buf);
++ return ret;
++}
++
++static ssize_t
++policy_attr_store(struct kobject * kobj, struct attribute * attr,
++ const char * buf, size_t count)
++{
++ struct dpm_policy_attribute * policy_attr = to_policy_attr(attr);
++ ssize_t ret = 0;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (policy_attr->store)
++ ret = policy_attr->store(kobj,buf,count);
++ return ret;
++}
++
++static struct dpm_policy_attribute a_policy_control_attr = {
++ .attr = {
++ .name = "control",
++ .mode = 0644,
++ },
++ .show = a_policy_control_show,
++ .store = a_policy_control_store,
++};
++
++static struct sysfs_ops policy_sysfs_ops = {
++ .show = policy_attr_show,
++ .store = policy_attr_store,
++};
++
++static struct attribute * policy_default_attrs[] = {
++ &a_policy_control_attr.attr,
++ NULL,
++};
++
++static struct kobj_type ktype_policy = {
++ .release = dpm_kobj_release,
++ .sysfs_ops = &policy_sysfs_ops,
++ .default_attrs = policy_default_attrs,
++};
++
++void dpm_sysfs_new_policy(struct dpm_policy *policy)
++{
++ int i;
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ memset(&policy->kobj, 0, sizeof(struct kobject));
++ //policy->kobj.kset = dpm_kobj->kset;
++ /*
++ kobject_set_name(&policy->kobj.kset, policy->name);
++ policy->kobj.parent = &dpm_policy_kobj;
++ policy->kobj.ktype = &ktype_policy;
++ */
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++ kobject_init_and_add(&policy->kobj, &ktype_policy,
++ dpm_policy_kobj, "%s", policy->name );
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++ kobject_uevent(&policy->kobj, KOBJ_ADD);
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ for (i = 0; (i < DPM_STATES) && (i < MAX_POLICY_STATES); i++) {
++ policy_state_attr[i]->attr.name = dpm_state_names[i];
++ sysfs_create_file(&policy->kobj, &policy_state_attr[i]->attr);
++ }
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++ return;
++}
++
++void dpm_sysfs_destroy_policy(struct dpm_policy *policy)
++{
++ kobject_put(&policy->kobj);
++ return;
++}
++
++/*
++ * class
++ */
++
++struct dpm_class_attribute {
++ struct attribute attr;
++ ssize_t (*show)(struct kobject * kobj, char * buf);
++ ssize_t (*store)(struct kobject * kobj, const char * buf, size_t count);
++};
++
++#define to_class(obj) container_of(obj,struct dpm_class,kobj)
++#define to_class_attr(_attr) container_of(_attr,struct dpm_class_attribute,attr)
++
++static ssize_t class_control_show(struct kobject *dpm_kobj, struct kobj_attribute *attr, char * buf)
++{
++ ssize_t len = 0;
++ struct list_head * p;
++
++ len += sprintf(buf + len, "classes: ");
++
++ list_for_each(p, &dpm_classes) {
++ len += sprintf(buf + len, "%s ",
++ ((struct dpm_class *)
++ list_entry(p, struct dpm_class, list))->name);
++ }
++
++ len += sprintf(buf + len, "\nactive: %s\n",
++ (dpm_enabled && dpm_active_class) ?
++ dpm_active_class->name : "[none]");
++ return len;
++}
++
++static ssize_t class_control_store(struct kobject *dpm_kobj, struct kobj_attribute *attr, const char * buf,
++ size_t n)
++{
++ int error = 0;
++ char *tbuf = NULL;
++ char *token[MAXTOKENS];
++ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS);
++
++ if (ntoks <= 0) {
++ error = ntoks;
++ goto out;
++ }
++
++ if (strcmp(token[0],"create") == 0) {
++ if (ntoks < 3)
++ printk("dpm: class create requires 1 name and at least one operating point argument\n");
++ else
++ error = dpm_create_class(token[1], &token[2], ntoks-2);
++ } else
++ error = -EINVAL;
++
++ out:
++ if (tbuf)
++ kfree(tbuf);
++ return error ? error : n;
++}
++
++static struct kobject *dpm_class_kobj;
++
++dpm_attr(control,class_control);
++
++static ssize_t a_class_control_show(struct kobject * kobj, char * buf)
++{
++ ssize_t len = 0;
++ struct dpm_class *class = to_class(kobj);
++ int i;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ len += sprintf(buf + len, "ops: ");
++
++ for (i = 0; i < class->nops; i++)
++ len += sprintf(buf + len, "%s ", class->ops[i]->name);
++
++
++ len += sprintf(buf + len, "\n");
++ return len;
++}
++
++static ssize_t a_class_control_store(struct kobject * kobj, const char * buf,
++ size_t n)
++{
++ return n;
++}
++
++static ssize_t
++class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
++{
++ struct dpm_class_attribute * class_attr = to_class_attr(attr);
++ ssize_t ret = 0;
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (class_attr->show)
++ ret = class_attr->show(kobj,buf);
++ return ret;
++}
++
++static ssize_t
++class_attr_store(struct kobject * kobj, struct attribute * attr,
++ const char * buf, size_t count)
++{
++ struct dpm_class_attribute * class_attr = to_class_attr(attr);
++ ssize_t ret = 0;
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (class_attr->store)
++ ret = class_attr->store(kobj,buf,count);
++ return ret;
++}
++
++static struct dpm_class_attribute a_class_control_attr = {
++ .attr = {
++ .name = "control",
++ .mode = 0644,
++ },
++ .show = a_class_control_show,
++ .store = a_class_control_store,
++};
++
++static struct sysfs_ops class_sysfs_ops = {
++ .show = class_attr_show,
++ .store = class_attr_store,
++};
++
++static struct attribute * class_default_attrs[] = {
++ &a_class_control_attr.attr,
++ NULL,
++};
++
++static struct kobj_type ktype_class = {
++ .release = dpm_kobj_release,
++ .sysfs_ops = &class_sysfs_ops,
++ .default_attrs = class_default_attrs,
++};
++
++void dpm_sysfs_new_class(struct dpm_class *class)
++{
++ memset(&class->kobj, 0, sizeof(struct kobject));
++ class->kobj.kset = dpm_kobj->kset;
++ /*
++ kobject_set_name(&class->kobj.kset, class->name);
++ class->kobj.parent = &dpm_class_kobj;
++ class->kobj.ktype = &ktype_class;
++ */
++ kobject_init_and_add(&class->kobj, &ktype_class,
++ dpm_class_kobj, "%s", class->name);
++
++ kobject_uevent(&class->kobj, KOBJ_ADD);
++ return;
++}
++
++void dpm_sysfs_destroy_class(struct dpm_class *class)
++{
++ kobject_put(&class->kobj);
++ return;
++}
++
++
++/*
++ * op
++ */
++
++struct dpm_op_attribute {
++ struct attribute attr;
++ ssize_t (*show)(struct kobject * kobj, char * buf);
++ ssize_t (*store)(struct kobject * kobj, const char * buf, size_t count);
++};
++
++#define to_op(obj) container_of(obj,struct dpm_opt,kobj)
++#define to_op_attr(_attr) container_of(_attr,struct dpm_op_attribute,attr)
++
++static ssize_t op_control_show(struct kobject *dpm_kobj, struct kobj_attribute *attr, char * buf)
++{
++ unsigned long flags;
++ ssize_t len = 0;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (dpm_lock_interruptible())
++ return -ERESTARTSYS;
++
++ len += sprintf(buf + len, "active: ");
++
++ if (!dpm_enabled) {
++ len += sprintf(buf + len, "[none]\n");
++ } else {
++ spin_lock_irqsave(&dpm_policy_lock, flags);
++ len += sprintf(buf + len,"%s\n",
++ dpm_active_opt ? dpm_active_opt->name : "[none]");
++ spin_unlock_irqrestore(&dpm_policy_lock, flags);
++ }
++
++ dpm_unlock();
++
++ len += sprintf(buf + len, "params: %d\n", DPM_PP_NBR);
++ return len;
++}
++
++static ssize_t op_control_store(struct kobject *dpm_kobj, struct kobj_attribute *attr, const char * buf,
++ size_t n)
++{
++ int error = 0;
++ char *tbuf = NULL;
++ char *token[MAXTOKENS];
++ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS);
++
++ if (ntoks <= 0) {
++ error = ntoks;
++ goto out;
++ }
++
++ if ((strcmp(token[0],"create") == 0) && (ntoks >= 2)) {
++ dpm_md_pp_t pp[DPM_PP_NBR];
++ int i;
++
++ for (i = 0; i < DPM_PP_NBR; i++) {
++ if (i >= ntoks - 2)
++ pp[i] = -1;
++ else
++ pp[i] = simple_strtol(token[i + 2],
++ NULL, 0);
++ }
++
++ error = dpm_create_opt(token[1], pp, DPM_PP_NBR);
++ } else
++ error = -EINVAL;
++
++ out:
++ if (tbuf)
++ kfree(tbuf);
++ return error ? error : n;
++
++}
++
++dpm_attr(control,op_control);
++
++#ifdef CONFIG_DPM_STATS
++static ssize_t op_stats_show(struct kobject *dpm_kobj, char * buf)
++{
++ int len = 0;
++ struct dpm_opt *opt;
++ struct list_head *p;
++ unsigned long long total_time;
++
++ if (dpm_lock_interruptible())
++ return -ERESTARTSYS;
++
++ if (!dpm_enabled) {
++ dpm_unlock();
++ len += sprintf(buf + len, "DPM IS DISABLED\n");
++ return len;
++ }
++
++ for (p = dpm_opts.next; p != &dpm_opts; p = p->next) {
++ opt = list_entry(p, struct dpm_opt, list);
++ len += sprintf(buf + len, "op: %s", opt->name);
++ total_time = opt->stats.total_time;
++ if (opt == dpm_active_opt)
++ total_time += (unsigned long long) dpm_time() -
++ opt->stats.start_time;
++ len += sprintf(buf + len, " ticks: %Lu times: %lu\n",
++ total_time, opt->stats.count);
++ }
++
++ dpm_unlock();
++ return len;
++}
++
++static ssize_t op_stats_store(struct kobject *dpm_kobj, const char * buf,
++ size_t n)
++{
++ return n;
++}
++
++dpm_attr(stats, op_stats);
++#endif /* CONFIG_DPM_STATS */
++
++
++static struct kobject *dpm_op_kobj;
++
++static ssize_t an_op_control_show(struct kobject * kobj, char * buf)
++{
++ ssize_t len = 0;
++ // struct dpm_opt *opt = to_op(kobj);
++
++ len += sprintf(buf + len, "\n");
++ return len;
++}
++
++static ssize_t an_op_control_store(struct kobject * kobj, const char * buf,
++ size_t n)
++{
++ return n;
++}
++
++static struct dpm_op_attribute an_op_control_attr = {
++ .attr = {
++ .name = "control",
++ .mode = 0644,
++ },
++ .show = an_op_control_show,
++ .store = an_op_control_store,
++};
++
++static ssize_t op_force_show(struct kobject * kobj, char * buf)
++{
++ ssize_t len = 0;
++ struct dpm_opt *opt = to_op(kobj);
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++ len += sprintf(buf + len, "%d\n", opt->flags & DPM_OP_FORCE ? 1 : 0);
++ return len;
++}
++
++static ssize_t op_force_store(struct kobject * kobj, const char * buf,
++ size_t n)
++{
++ struct dpm_opt *opt = to_op(kobj);
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ opt->flags = (opt->flags & ~DPM_OP_FORCE) |
++ (simple_strtol(buf, NULL, 0) ? DPM_OP_FORCE : 0);
++ return n;
++}
++
++static struct dpm_op_attribute op_force_attr = {
++ .attr = {
++ .name = "force",
++ .mode = 0644,
++ },
++ .show = op_force_show,
++ .store = op_force_store,
++};
++
++#define OP_PARAM_ATTR(index) \
++static ssize_t op_param ## index ## _show(struct kobject * kobj, char * buf) \
++{ \
++ ssize_t len = 0; \
++ struct dpm_opt *opt = to_op(kobj); \
++ len += sprintf(buf + len, "%d\n", opt->pp[index]); \
++ return len; \
++} \
++static ssize_t op_param ## index ## _store(struct kobject * kobj, const char * buf, \
++ size_t n) \
++{ \
++ struct dpm_opt *opt = to_op(kobj); \
++ int ret, oldval; \
++ \
++ oldval = opt->pp[index]; \
++ opt->pp[index] = simple_strtol(buf, NULL, 0); \
++ ret = dpm_md_init_opt(opt); \
++ if (ret) \
++ opt->pp[index] = oldval; \
++ return ret ? ret : n; \
++} \
++static struct dpm_op_attribute op_param ## index ## _attr = { \
++ .attr = { \
++ .mode = 0644, \
++ }, \
++ .show = op_param ## index ## _show, \
++ .store = op_param ## index ## _store, \
++}; \
++
++#define MAX_OP_PARAMS DPM_MD_MAX
++OP_PARAM_ATTR(0);
++OP_PARAM_ATTR(1);
++OP_PARAM_ATTR(2);
++OP_PARAM_ATTR(3);
++OP_PARAM_ATTR(4);
++OP_PARAM_ATTR(5);
++OP_PARAM_ATTR(6);
++OP_PARAM_ATTR(7);
++OP_PARAM_ATTR(8);
++OP_PARAM_ATTR(9);
++OP_PARAM_ATTR(10);
++OP_PARAM_ATTR(11);
++OP_PARAM_ATTR(12);
++OP_PARAM_ATTR(13);
++OP_PARAM_ATTR(14);
++OP_PARAM_ATTR(15);
++#if 0
++OP_PARAM_ATTR(16);
++OP_PARAM_ATTR(17);
++OP_PARAM_ATTR(18);
++OP_PARAM_ATTR(19);
++#endif
++
++static struct dpm_op_attribute *op_param_attr[MAX_OP_PARAMS] = {
++ &op_param0_attr,
++ &op_param1_attr,
++ &op_param2_attr,
++ &op_param3_attr,
++ &op_param4_attr,
++ &op_param5_attr,
++ &op_param6_attr,
++ &op_param7_attr,
++ &op_param8_attr,
++ &op_param9_attr,
++ &op_param10_attr,
++ &op_param11_attr,
++ &op_param12_attr,
++ &op_param13_attr,
++ &op_param14_attr,
++ &op_param15_attr,
++#if 0
++ &op_param16_attr,
++ &op_param17_attr,
++ &op_param18_attr,
++ &op_param19_attr,
++#endif
++};
++
++static ssize_t
++op_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
++{
++ struct dpm_op_attribute * op_attr = to_op_attr(attr);
++ ssize_t ret = 0;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (op_attr->show)
++ ret = op_attr->show(kobj,buf);
++ return ret;
++}
++
++static ssize_t
++op_attr_store(struct kobject * kobj, struct attribute * attr,
++ const char * buf, size_t count)
++{
++ struct dpm_op_attribute * op_attr = to_op_attr(attr);
++ ssize_t ret = 0;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (op_attr->store)
++ ret = op_attr->store(kobj,buf,count);
++ return ret;
++}
++
++static struct sysfs_ops op_sysfs_ops = {
++ .show = op_attr_show,
++ .store = op_attr_store,
++};
++
++static struct attribute * op_default_attrs[] = {
++ &an_op_control_attr.attr,
++ &op_force_attr.attr,
++ NULL,
++};
++
++static struct kobj_type ktype_op = {
++ .release = dpm_kobj_release,
++ .sysfs_ops = &op_sysfs_ops,
++ .default_attrs = op_default_attrs,
++};
++
++void dpm_sysfs_new_op(struct dpm_opt *opt)
++{
++ int i;
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ memset(&opt->kobj, 0, sizeof(struct kobject));
++ opt->kobj.kset = dpm_kobj->kset;
++ /*
++ kobject_set_name(&opt->kobj.kset, opt->name);
++ opt->kobj.parent = &dpm_op_kobj;
++ opt->kobj.ktype = &ktype_op;
++ */
++ kobject_init_and_add(&opt->kobj, &ktype_op,
++ dpm_op_kobj, "%s", opt->name);
++
++ kobject_uevent(&opt->kobj, KOBJ_ADD);
++
++ for (i = 0; (i < DPM_PP_NBR) && (i < MAX_OP_PARAMS); i++) {
++ op_param_attr[i]->attr.name = dpm_param_names[i];
++ sysfs_create_file(&opt->kobj, &op_param_attr[i]->attr);
++ }
++
++ return;
++}
++
++void dpm_sysfs_destroy_op(struct dpm_opt *opt)
++{
++ kobject_put(&opt->kobj);
++ return;
++}
++
++
++/*
++ * state
++ */
++
++
++static ssize_t state_control_show(struct kobject *dpm_kobj, struct kobj_attribute *attr, char * buf)
++{
++ ssize_t len = 0;
++ int i;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++ len += sprintf(buf + len, "states: ");
++
++ for (i = 0; i < DPM_STATES; i++) {
++ len += sprintf(buf + len, "%s ", dpm_state_names[i]);
++ }
++
++ len += sprintf(buf + len, "\ntask-states: min=%s norm=%s max=%s\n",
++ dpm_state_names[DPM_TASK_STATE - DPM_TASK_STATE_LIMIT],
++ dpm_state_names[DPM_TASK_STATE],
++ dpm_state_names[DPM_TASK_STATE + DPM_TASK_STATE_LIMIT]);
++
++ return len;
++}
++
++static ssize_t state_control_store(struct kobject *dpm_kobj, struct kobj_attribute *attr, const char * buf,
++ size_t n)
++{
++ return -EINVAL;
++}
++
++static ssize_t active_state_show(struct kobject *dpm_kobj, struct kobj_attribute *attr, char * buf)
++{
++ unsigned long flags;
++ ssize_t len = 0;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (dpm_lock_interruptible())
++ return -ERESTARTSYS;
++
++ if (!dpm_enabled || (dpm_active_state == DPM_NO_STATE)) {
++ len += sprintf(buf + len, "[none]\n");
++ } else {
++ spin_lock_irqsave(&dpm_policy_lock, flags);
++ len += sprintf(buf + len,"%s\n",
++ dpm_state_names[dpm_active_state]);
++ spin_unlock_irqrestore(&dpm_policy_lock, flags);
++ }
++
++ dpm_unlock();
++ return len;
++}
++
++static ssize_t active_state_store(struct kobject *dpm_kobj, struct kobj_attribute *attr, const char * buf,
++ size_t n)
++{
++ int error = 0;
++ char *tbuf = NULL;
++ char *token[MAXTOKENS];
++ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS);
++
++ if (ntoks <= 0) {
++ error = ntoks;
++ goto out;
++ }
++
++ error = dpm_set_op_state(token[0]);
++
++ out:
++ if (tbuf)
++ kfree(tbuf);
++ return error ? error : n;
++}
++
++#ifdef CONFIG_DPM_STATS
++static ssize_t state_stats_show(struct kobject *dpm_kobj, char * buf)
++{
++ unsigned long flags;
++ ssize_t len = 0;
++ int i;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ spin_lock_irqsave(&dpm_policy_lock, flags);
++
++ for (i = 0; i < DPM_STATES; i++) {
++ unsigned long long total_time = dpm_state_stats[i].total_time;
++
++ if (i == dpm_active_state)
++ total_time += (unsigned long long) dpm_time() -
++ dpm_state_stats[i].start_time;
++
++ len += sprintf(buf + len, "state: %s", dpm_state_names[i]);
++ len += sprintf(buf + len, " ticks: %Lu",
++ total_time);
++ len += sprintf(buf + len, " times: %lu\n",
++ dpm_state_stats[i].count);
++ }
++
++ spin_unlock_irqrestore(&dpm_policy_lock, flags);
++ return len;
++}
++
++static ssize_t state_stats_store(struct kobject *dpm_kobj, const char * buf,
++ size_t n)
++{
++ return n;
++}
++#endif /* CONFIG_DPM_STATS */
++
++static struct kobject *dpm_state_kobj;
++
++dpm_attr(control, state_control);
++dpm_attr(active, active_state);
++#ifdef CONFIG_DPM_STATS
++dpm_attr(stats, state_stats);
++#endif
++
++struct astate {
++ int index;
++ struct kobject *kobj;
++};
++
++struct astate_attribute {
++ struct attribute attr;
++ ssize_t (*show)(struct kobject * kobj, char * buf);
++ ssize_t (*store)(struct kobject * kobj, const char * buf, size_t count);
++};
++
++#define to_astate(obj) container_of(obj,struct astate,kobj)
++#define to_astate_attr(_attr) container_of(_attr,struct astate_attribute,attr)
++
++static ssize_t
++astate_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
++{
++ struct astate_attribute * astate_attr = to_astate_attr(attr);
++ ssize_t ret = 0;
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (astate_attr->show)
++ ret = astate_attr->show(kobj,buf);
++ return ret;
++}
++
++static ssize_t
++astate_attr_store(struct kobject * kobj, struct attribute * attr,
++ const char * buf, size_t count)
++{
++ struct astate_attribute * astate_attr = to_astate_attr(attr);
++ ssize_t ret = 0;
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (astate_attr->store)
++ ret = astate_attr->store(kobj,buf,count);
++ return ret;
++}
++
++static int show_opconstrains(int state, char *buf)
++{
++ struct dpm_opt *opt;
++ int len = 0;
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (dpm_active_policy->classopt[state].opt) {
++ opt = dpm_active_policy->classopt[state].opt;
++
++ len += dpm_show_opconstraints(opt, buf);
++ }
++ else {
++ int i;
++
++ for (i = 0;
++ i < dpm_active_policy->classopt[state].class->nops; i++) {
++ len += dpm_show_opconstraints(
++ dpm_active_policy->classopt[state].class->ops[i], buf);
++ }
++ }
++
++ return len;
++}
++static ssize_t astate_constraints_show(struct kobject * kobj, char * buf)
++{
++ struct astate *astate = to_astate(kobj);
++ ssize_t len = 0;
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (dpm_enabled && dpm_active_policy)
++ len = show_opconstrains(astate->index, buf);
++
++ return len;
++}
++
++static ssize_t astate_constraints_store(struct kobject * kobj,
++ const char * buf, size_t n)
++{
++ return n;
++}
++
++static struct astate_attribute astate_constraints_attr = {
++ .attr = {
++ .name = "constraints",
++ .mode = 0644,
++ },
++ .show = astate_constraints_show,
++ .store = astate_constraints_store,
++};
++
++static struct sysfs_ops astate_sysfs_ops = {
++ .show = astate_attr_show,
++ .store = astate_attr_store,
++};
++
++static struct attribute * astate_default_attrs[] = {
++ &astate_constraints_attr.attr,
++ NULL,
++};
++
++static struct kobj_type ktype_astate = {
++ .release = dpm_kobj_release,
++ .sysfs_ops = &astate_sysfs_ops,
++ .default_attrs = astate_default_attrs,
++};
++
++static struct astate astate[DPM_STATES];
++
++/*
++ * Init
++ */
++
++
++static int __init dpm_sysfs_init(void)
++{
++ int error, i;
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ dpm_kset = kset_create_and_add("dpm", NULL, NULL);
++ if(!dpm_kset)
++ return -ENOMEM;
++
++#if 1
++ dpm_kobj = kobject_create_and_add("dpm", &dpm_kset->kobj);
++ if(!dpm_kobj)
++ return -ENOMEM;
++#endif
++
++ //error = sysfs_create_group(&dpm_kset->kobj,&dpm_attr_group);
++ error = sysfs_create_group(dpm_kobj,&dpm_attr_group);
++ if(error) {
++ dbg("error creating sysfs files (%d)\n", error);
++ return error;
++ }
++ dpm_policy_kobj = kobject_create_and_add("policy", dpm_kobj);
++ //dpm_policy_kobj = kobject_create_and_add("policy", &dpm_kset->kobj);
++
++ if(!dpm_policy_kobj)
++ goto policy_kobj_err;
++ sysfs_create_file(dpm_policy_kobj, &policy_control_attr.attr);
++ sysfs_create_file(dpm_policy_kobj, &active_policy_attr.attr);
++#ifdef CONFIG_DPM_STATS
++ sysfs_create_file(dpm_policy_kobj, &policy_stats_attr.attr);
++#endif
++ for (i = 0; i < DPM_STATES; i++) {
++ astate[i].index = i;
++ astate[i].kobj = kobject_create_and_add(dpm_state_names[i], dpm_policy_kobj);
++ astate[i].kobj->kset = dpm_kobj->kset;
++ astate[i].kobj->parent = dpm_policy_kobj;
++ astate[i].kobj->ktype = &ktype_policy;
++ }
++
++ dpm_class_kobj = kobject_create_and_add("class", dpm_kobj);
++ //dpm_class_kobj = kobject_create_and_add("class", &dpm_kset->kobj);
++ if(!dpm_class_kobj)
++ goto class_kobj_err;
++ sysfs_create_file(dpm_class_kobj, &class_control_attr.attr);
++ for (i = 0; i < DPM_STATES; i++) {
++ astate[i].index = i;
++ astate[i].kobj = kobject_create_and_add(dpm_state_names[i], dpm_class_kobj);
++ astate[i].kobj->kset = dpm_kobj->kset;
++ astate[i].kobj->parent = dpm_class_kobj;
++ astate[i].kobj->ktype = &ktype_class;
++ }
++
++ dpm_op_kobj = kobject_create_and_add("op", dpm_kobj);
++ //dpm_op_kobj = kobject_create_and_add("op", &dpm_kset->kobj);
++ if(!dpm_op_kobj)
++ goto op_kobj_err;
++ sysfs_create_file(dpm_op_kobj, &op_control_attr.attr);
++#ifdef CONFIG_DPM_STATS
++ sysfs_create_file(dpm_op_kobj, &op_stats_attr.attr);
++#endif
++ for (i = 0; i < DPM_STATES; i++) {
++ astate[i].index = i;
++ astate[i].kobj = kobject_create_and_add(dpm_state_names[i], dpm_op_kobj);
++ astate[i].kobj->kset = dpm_kobj->kset;
++ astate[i].kobj->parent = dpm_op_kobj;
++ astate[i].kobj->ktype = &ktype_op;
++ }
++
++ dpm_state_kobj = kobject_create_and_add("state", dpm_kobj);
++ //dpm_state_kobj = kobject_create_and_add("state", &dpm_kset->kobj);
++ if(!dpm_state_kobj)
++ goto state_kobj_err;
++ sysfs_create_file(dpm_state_kobj, &state_control_attr.attr);
++ sysfs_create_file(dpm_state_kobj, &active_state_attr.attr);
++#ifdef CONFIG_DPM_STATS
++ sysfs_create_file(&dpm_state_kobj, &state_stats_attr.attr);
++#endif
++
++ for (i = 0; i < DPM_STATES; i++) {
++ astate[i].index = i;
++ astate[i].kobj = kobject_create_and_add(dpm_state_names[i], dpm_state_kobj);
++ astate[i].kobj->kset = dpm_kobj->kset;
++ astate[i].kobj->parent = dpm_state_kobj;
++ astate[i].kobj->ktype = &ktype_astate;
++ }
++
++policy_kobj_err:
++ kobject_put(dpm_policy_kobj);
++class_kobj_err:
++ kobject_put(dpm_class_kobj);
++op_kobj_err:
++ kobject_put(dpm_op_kobj);
++state_kobj_err:
++ kobject_put(dpm_state_kobj);
++
++
++ return error;
++}
++
++__initcall(dpm_sysfs_init);
++
++/* /proc interface */
++
++int dpm_set_task_state_by_name(struct task_struct *task, char *buf, ssize_t n)
++{
++ int task_state;
++ int ret = 0;
++ char *tbuf = NULL;
++ char *token[MAXTOKENS];
++ int ntoks = tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS);
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (ntoks <= 0) {
++ ret = ntoks;
++ goto out;
++ }
++
++ for (task_state = DPM_TASK_STATE - DPM_TASK_STATE_LIMIT;
++ task_state <= DPM_TASK_STATE + DPM_TASK_STATE_LIMIT;
++ task_state++)
++ if (strcmp(token[0], dpm_state_names[task_state]) == 0) {
++ task->dpm_state = task_state;
++ if (task == current)
++ dpm_set_os(task_state);
++
++ ret = 0;
++ break;
++ }
++
++out:
++ if (tbuf)
++ kfree(tbuf);
++
++ return ret;
++}
+diff --git a/drivers/dpm/dpm.c b/drivers/dpm/dpm.c
+new file mode 100644
+index 0000000..978e258
+--- /dev/null
++++ b/drivers/dpm/dpm.c
+@@ -0,0 +1,1141 @@
++/*
++ * drivers/dpm/policy.c Dynamic Power Management Policies
++ *
++ * 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
++ *
++ * Copyright (C) 2002, International Business Machines Corporation
++ * All Rights Reserved
++ *
++ * Robert Paulsen
++ * IBM Linux Technology Center
++ * rpaulsen@us.ibm.com
++ * August, 2002
++ *
++ */
++
++/* TODO:
++
++ Rethink init/enable/disable: It may be redundant and/or unsafe
++ Fix initialization and stats
++*/
++
++#include <linux/dpm.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/proc_fs.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/delay.h>
++#include <linux/preempt.h>
++
++#include <linux/semaphore.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#include <bsp.h>
++
++
++#if 0
++#define dbg printk
++#else /* no debug */
++#define dbg(x...) do {} while(0)
++#endif
++
++
++
++#define TRACE
++//#undef TRACE
++#if defined(TRACE)
++#define trace(args...) do { printk("TRACE: "); printk(args); } while(0)
++#else
++#define trace(args...) do {} while(0)
++#endif
++
++struct dpm_md dpm_md;
++
++static struct dpm_opt nop_op = {
++ .name = "[nop]",
++ .flags = DPM_OP_NOP,
++};
++
++unsigned long dpm_compute_lpj(unsigned long ref, u_int div, u_int mult)
++{
++ unsigned long new_jiffy_l, new_jiffy_h;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++ /*
++ * Recalculate loops_per_jiffy. We do it this way to
++ * avoid math overflow on 32-bit machines. Maybe we
++ * should make this architecture dependent? If you have
++ * a better way of doing this, please replace!
++ *
++ * new = old * mult / div
++ */
++ new_jiffy_h = ref / div;
++ new_jiffy_l = (ref % div) / 100;
++ new_jiffy_h *= mult;
++ new_jiffy_l = new_jiffy_l * mult / div;
++
++ return new_jiffy_h + new_jiffy_l * 100;
++}
++
++/****************************************************************************
++
++DPM Synchronization and Operating Point Changes
++===============================================
++
++There are 2 aspects to synchronization in DPM: First, the usual requirement of
++serializing access to shared data structures, and second, the idea of
++synchronizing the operating point and the current operating state. The second
++condition arises because setting an operating point may complete asynchronously
++for a number of reasons, whereas the operating state change that causes the
++operating point change succeeds immediately.
++
++Access to most of the global variables representing the current state of DPM
++and the current policy are protected by a spinlock, dpm_policy_lock. The use
++of this lock appears in only a few critical places.
++
++Setting the operating point, reading the value of the current operating point
++or changing the current policy may only be done while holding the semaphore
++_dpm_lock. Access to the _dpm_lock is abstracted by the dpm_lock() and
++dpm_unlock() calls as explained below. (The semaphore should only be accessed
++this way to simplify future development).
++
++The _dpm_lock must be held (by a call to a dpm_lock function) by any caller of
++the interfaces that set the operating point, change the policy, or enable or
++disable DPM. Note that the corresponding call to dpm_unlock() may be
++explicitly required, or implicit (see dpm_set_opt_async() below).
++
++For simplicity, the calls that create operating points and policies also use
++dpm_lock() and dpm_unlock() to protect access to the non-active policies as
++well. Since these are normally initialization calls, this should not interfere
++with the operation of the system once initialized.
++
++Three interfaces are provided for obtaining the _dpm_lock:
++
++void dpm_lock();
++int dpm_lock_interruptible();
++int dpm_trylock();
++
++dpm_lock_interruptible() returns -ERESTARTSYS if the wait for the _dpm_lock was
++interrupted, and dpm_trylock() returns -EBUSY if the semaphore is currently
++held.
++
++Once the _dpm_lock is held, two interfaces are provided for setting the
++operating point:
++
++int dpm_set_opt_async()
++int dpm_set_opt_sync();
++
++Neither of these interfaces takes parameters since under DPM the operating
++point to select is always implied by the current policy and operating state.
++If the system is already at the correct operating point then no change is
++required or made. To avoid deadlock, the caller must not be holding the
++dpm_policy_lock when either of these calls is made.
++
++dpm_set_opt_async() launches a change in the operating point that will
++potentially terminate asynchronously. This interface never blocks the caller,
++thus there is no guarantee that the system is actually running at the implied
++operating point when control returns to the caller. This call is used by
++dpm_set_os() during an operating state change. Note since this call terminates
++asynchronously, the call to dpm_unlock() is implicitly made when the operating
++point change is complete. I.e., the caller obtains the _dpm_lock with
++dpm_lock(), calls dpm_set_opt_async(), then continues.
++
++dpm_set_opt_sync() launches a synchronous change in the operating point. This
++call will block the caller as necessary during the call, thus it can only be
++issued from a process context. When control returns to the caller, the caller
++can be sure that the implied operating point was set, and that the system is
++currently running at the correct operating point for the given policy and
++operating state. This call is used by dpm_set_policy() and the device
++constraint update code to guarantee that the change to a new policy, or changes
++to operating point classes as a result of device constraits are reflected in
++the operating point.
++
++Note that regardless of whether an operating point change is synchrounous or
++asynchronous, it is still possible that the operating state may change during
++the call. Setting the operating point is (currently) not preemptible,
++therefore at the time that the operating point change is complete, it may no
++longer be the correct operating point for the operating state. This condition
++is always handled by the dpm_set_opt*() routines, which will launch a tasklet
++to re-synchronize the operating point to the operating state.
++
++It is possible that due to poorly designed policies and asynchronous
++termination of operating point changes that the operating point will always lag
++behind the operating state. This is only a performance issue, not a
++correctness issue. Since a valid policy has a valid operating point for every
++operating state, and changes to the policy and changes in devices constraints
++always use dpm_set_opt_sync(), there will never be a case where the current
++operating point does not support device constraints.
++
++****************************************************************************/
++
++/* curently installed policies and operating points */
++LIST_HEAD(dpm_policies);
++LIST_HEAD(dpm_classes);
++LIST_HEAD(dpm_opts);
++
++DECLARE_MUTEX(_dpm_lock);
++spinlock_t dpm_policy_lock = SPIN_LOCK_UNLOCKED;
++
++/* the currently active policy */
++struct dpm_policy *dpm_active_policy;
++
++/* the currently active operating state, class, and operating point */
++dpm_state_t dpm_active_state = DPM_NO_STATE;
++struct dpm_opt *dpm_active_opt;
++struct dpm_class *dpm_active_class;
++
++/* is DPM initialized and enabled? */
++int dpm_enabled;
++int dpm_initialized;
++
++#ifdef CONFIG_DPM_STATS
++#include <asm/div64.h>
++
++struct dpm_stats dpm_state_stats[DPM_STATES];
++
++/*
++ * Start counting DPM stats from the time DPM was enabled... in the case of
++ * operating states the stats are updated from the time userspace is started.
++ */
++
++void
++dpm_stats_reset(void)
++{
++ int i;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ preempt_disable();
++ for (i = 0; i < DPM_STATES; i++) {
++ dpm_state_stats[i].total_time = 0;
++ dpm_state_stats[i].start_time = 0;
++ dpm_state_stats[i].count = 0;
++ }
++
++ if (dpm_active_state != DPM_NO_STATE) {
++ dpm_state_stats[dpm_active_state].start_time = dpm_time();
++ dpm_state_stats[dpm_active_state].count = 1;
++ }
++
++ preempt_enable();
++}
++
++unsigned long long
++dpm_update_stats(struct dpm_stats *new, struct dpm_stats *old)
++{
++ unsigned long long now = dpm_time();
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (old)
++ old->total_time += now - old->start_time;
++
++ if (new) {
++ new->start_time = now;
++ new->count += 1;
++ }
++
++ return now;
++}
++#else
++#define dpm_update_stats(a,b) do {} while (0)
++#define dpm_stats_reset() do {} while (0)
++#endif /* CONFIG_DPM_STATS */
++
++struct dpm_opt *
++dpm_choose_opt(struct dpm_policy *policy, int state)
++{
++ struct dpm_opt *opt = NULL;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (policy->classopt[state].opt) {
++ opt = policy->classopt[state].opt;
++
++ if (! dpm_check_constraints(opt))
++ opt = NULL;
++
++ dpm_active_class = NULL;
++ }
++ else {
++ int i;
++
++ for (i = 0; i < policy->classopt[state].class->nops; i++) {
++ if (dpm_check_constraints(
++ policy->classopt[state].class->ops[i])) {
++ opt = policy->classopt[state].class->ops[i];
++ break;
++ }
++ }
++
++ dpm_active_class = policy->classopt[state].class;
++ }
++
++ return opt;
++}
++
++
++
++/*****************************************************************************
++ * dpm_next_opt() returns the operating point that needs to be activated next,
++ * or NULL if the operating point is up-to-date or the DPM system is disabled.
++ * Since this call looks at the value of the current operating point, it can
++ * only be made when the _dpm_lock is held.
++ *****************************************************************************/
++
++static inline struct dpm_opt *
++dpm_next_opt(void)
++{
++ struct dpm_opt *opt = NULL;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (! spin_trylock(&dpm_policy_lock))
++ return NULL;
++ if (dpm_enabled && dpm_active_state != DPM_NO_STATE) {
++ opt = dpm_choose_opt(dpm_active_policy,dpm_active_state);
++ if (opt == dpm_active_opt)
++ opt = NULL;
++ }
++ spin_unlock(&dpm_policy_lock);
++ return opt;
++}
++
++/*****************************************************************************
++ * Set the operating point implied by the current DPM policy. These calls can
++ * only be made while holding _dpm_lock, and the release of
++ * _dpm_lock is implied by the call (see below).
++ *****************************************************************************/
++
++static struct dpm_opt temp_opt = { name : "[System Operating Point]" };
++
++int
++dpm_set_opt(struct dpm_opt *new, unsigned flags)
++{
++ int error;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (new->flags & DPM_OP_NOP) {
++ if (flags & DPM_UNLOCK)
++ dpm_unlock();
++ return 0;
++ }
++
++ /* Support for setting the operating point when DPM is not running, and
++ setting the first operating point. */
++
++ if (!dpm_enabled || !dpm_active_opt) {
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++ if (dpm_md_get_opt(&temp_opt)) {
++ printk(KERN_ERR "dpm_default_set_opt: "
++ "DPM disabled and system "
++ "operating point is illegal!\n");
++
++ if (flags & DPM_UNLOCK)
++ dpm_unlock();
++ return -EINVAL;
++ }
++ dpm_active_opt = &temp_opt;
++ dpm_active_class = NULL;
++ }
++
++ /*
++ * Remove the IRQ disable since in some cases scheduling is needed
++ * to set an operating point (only sleep mode). The spinlock
++ * should suffice. If the machine-dependent code needs interrupts
++ * turned off during the code used for that platform for that
++ * operating point set sequence then IRQs will need to be disabled
++ * in that code instead.
++ */
++ error = dpm_md.set_opt(dpm_active_opt, new);
++
++ if (error == 0) {
++ dpm_update_stats(&new->stats, &dpm_active_opt->stats);
++ dpm_active_opt = new;
++ mb();
++ }
++
++ if (flags & DPM_UNLOCK)
++ dpm_unlock();
++
++ return error;
++}
++
++/*****************************************************************************
++ * Set operating point asynchronously. The _dpm_lock will be cleared whenever
++ * the change in operating point is complete.
++ *****************************************************************************/
++
++int
++dpm_set_opt_async(void)
++{
++ struct dpm_opt *opt = dpm_next_opt();
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (opt) {
++ dpm_trace(DPM_TRACE_SET_OPT_ASYNC, opt);
++ return dpm_set_opt(opt, DPM_UNLOCK);
++ } else {
++ dpm_trace(DPM_TRACE_SET_OPT_ASYNC, NULL);
++ dpm_unlock();
++ return 0;
++ }
++}
++
++/*****************************************************************************
++ * Set operating point synchronously. The caller must clear _dpm_lock after the
++ * call returns.
++ *****************************************************************************/
++
++int
++dpm_set_opt_sync(void)
++{
++ struct dpm_opt *opt = dpm_next_opt();
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (opt) {
++ dpm_trace(DPM_TRACE_SET_OPT_SYNC, opt);
++ return dpm_set_opt(opt, DPM_SYNC);
++ } else
++ dpm_trace(DPM_TRACE_SET_OPT_SYNC, NULL);
++ return 0;
++}
++
++/*****************************************************************************
++ * Resynchronize the operating state and the operating point without
++ * blocking. If we don't get the lock it doesn't matter, since whenever the
++ * lock holder releases the lock the resynchronization will be tried again.
++ *****************************************************************************/
++
++static inline void
++dpm_resync(void)
++{
++ dpm_trace(DPM_TRACE_RESYNC);
++ if (! dpm_trylock())
++ dpm_set_opt_async();
++}
++
++void
++dpm_resync_task(unsigned long ignore)
++{
++ dpm_resync();
++}
++
++/*****************************************************************************
++ * unlock the DPM
++ *
++ * If the operating point and operating state are not in sync when _dpm_lock is
++ * released, a tasklet is launched to resynchronize them. A tasklet is used
++ * rather than simply calling dpm_set_op directly to avoid deep recursions.
++ * (I'm not sure this has worked, though).
++ *
++ * (The locking functions are inline in dpm_policy.h)
++ *
++ * This is not static since it needs to be called from dpm_policy.c
++ *****************************************************************************/
++
++DECLARE_TASKLET(dpm_resync_tasklet, dpm_resync_task, 0);
++
++void
++dpm_unlock(void)
++{
++ int retry;
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ retry = dpm_next_opt() != NULL;
++ dpm_trace(DPM_TRACE_UNLOCK, retry);
++ up(&_dpm_lock);
++ if (retry)
++ tasklet_schedule(&dpm_resync_tasklet);
++}
++
++/*****************************************************************************
++ * Enter a new operating state for statistical purposes. Returns 1 if the new
++ * state may require a change in operating point and 0 otherwise.
++ *
++ * The normal case that occurs during task scheduling, where we go from task
++ * state to task state, is quickly ignored, as are changes to the
++ * DPM_NO_STATE and changes when DPM is not running. Otherwise,
++ * dpm_enter_state() has advertised that we are in a new state, and indicates
++ * whether an operating point change is required.
++ *
++ * Note the system invariant that the operating point always eventually
++ * catches up with changes to the operating state. This is what makes it
++ * correct here to check for common operating points. We know
++ * that if a common operating point is not the current operating point, it
++ * will be soon.
++ *
++ * The 'quick' variant (in dpm.h) is called out separately to reduce latency
++ * for critical operating state changes where the following are known: 1) The
++ * dpm_policy_lock is held and/or interrupts are properly disabled. 2) DPM is
++ * enabled. 3) The new state is neither DPM_NO_STATE nor the same as the
++ * active state. 4) Any operating point change is being handled elsewhere.
++ *****************************************************************************/
++
++static int
++dpm_enter_state(int new_state)
++{
++ int ret = 0;
++
++ if (! spin_trylock(&dpm_policy_lock)) {
++ dpm_quick_enter_state(new_state);
++ return 0;
++ }
++
++ if ((new_state == dpm_active_state) ||
++ (new_state == DPM_NO_STATE) ||
++ !dpm_enabled) {
++ spin_unlock(&dpm_policy_lock);
++ return ret;
++ }
++
++ if ((dpm_active_policy->classopt[new_state].class !=
++ dpm_active_policy->classopt[dpm_active_state].class) ||
++ (dpm_active_policy->classopt[new_state].opt !=
++ dpm_active_policy->classopt[dpm_active_state].opt))
++ ret = 1;
++
++ dpm_quick_enter_state(new_state);
++ spin_unlock(&dpm_policy_lock);
++ return ret;
++}
++
++
++/*****************************************************************************
++ * set operating state
++ *
++ * This is used by the kernel to inform the DPM that the operating state has
++ * changed and that a new operating point should (possibly) be set as a
++ * result.
++ *
++ * If an operating point change is required it is attempted. If we can't get
++ * the lock here, then the operating point change will be activated when the
++ * current lock holder releases the lock.
++ *****************************************************************************/
++
++void
++dpm_set_os(dpm_state_t new_state)
++{
++ dpm_trace(DPM_TRACE_SET_OS, new_state);
++ if (dpm_enter_state(new_state))
++ dpm_resync();
++}
++
++EXPORT_SYMBOL(dpm_set_os);
++
++/*****************************************************************************
++ * initialize the DPM
++ *****************************************************************************/
++int
++dynamicpower_init(void)
++{
++ trace("in dynamicpower_init\n");
++
++ if (dpm_initialized) {
++ trace("DPM already initialized");
++ return -EALREADY;
++ }
++
++ /* mutex-style semaphore for access to policies and opts */
++ init_MUTEX(&_dpm_lock);
++
++ dpm_active_policy = 0; /* this leaves the DPM temporarily
++ disabled until a policy is
++ activated */
++ dpm_enabled = 0;
++ dpm_initialized = 1;
++ dpm_active_state = DPM_TASK_STATE;
++
++
++ trace("DPM is now initialized\n");
++
++ return 0;
++}
++
++/*****************************************************************************
++ * (temporarily) disable the DPM
++ *****************************************************************************/
++int
++dynamicpower_disable(void)
++{
++ trace("in dynamicpower_disable\n");
++
++ if (! dpm_enabled) {
++ trace("DPM already disabled");
++ return -EALREADY;
++ }
++
++ dpm_lock();
++
++ dpm_enabled = 0;
++ dpm_md_cleanup();
++ dpm_active_opt = NULL;
++ dpm_active_class = NULL;
++
++ dpm_unlock();
++
++ trace("DPM is now disabled\n");
++
++ return 0;
++}
++
++/*****************************************************************************
++ * re-enable the DPM
++ * dpm_enabled = 1 implies that DPM is initialized and there is an active
++ * policy. The 'enable' call is really designed to be used after a temporary
++ * 'disable'. All that's required to start DPM is to initialize it and set a
++ * policy.
++ *****************************************************************************/
++
++/* Need to think through enable/disable */
++
++int
++dynamicpower_enable(void)
++{
++ trace("in dynamicpower_enable\n");
++
++ if (dpm_enabled) {
++ trace("DPM already enabled");
++ return -EALREADY;
++ }
++
++ dpm_lock();
++
++ if (dpm_active_policy) {
++ dpm_enabled = 1;
++ mb();
++ dpm_md_startup();
++ dpm_stats_reset();
++ dpm_set_opt_sync();
++ trace("DPM is now enabled\n");
++ } else {
++ trace("No active policy, dpm_enable is ignored\n");
++ }
++
++ dpm_unlock();
++ return 0;
++}
++
++/*****************************************************************************
++ * Suspend/Resume DPM
++ * The current operating point is saved and restored. This
++ * interface is designed to be used by system suspend/resume code, to safely
++ * save/restore the DPM operating point across a system power-down, where the
++ * firmware may resume the system at a random operating point. This does not
++ * require DPM to be enabled. Note that DPM remains locked across the
++ * suspend/resume.
++ *****************************************************************************/
++
++static struct dpm_opt suspend_opt = { name : "[Suspended Op. Point]" };
++struct dpm_opt *suspended_opt;
++
++int
++dynamicpm_suspend(void)
++{
++ int err;
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ trace("in dpm_suspend\n");
++
++ dpm_lock();
++
++ if (dpm_enabled && dpm_active_opt) {
++ suspended_opt = dpm_active_opt;
++ } else {
++ suspended_opt = &suspend_opt;
++ if ((err = dpm_md_get_opt(suspended_opt))) {
++ printk(KERN_CRIT
++ "DPM can not suspend the current op. point!\n");
++ suspended_opt = NULL;
++ return err;
++ }
++ }
++ return 0;
++}
++
++void
++dynamicpm_resume(void)
++{
++ trace("in dpm_resume\n");
++
++ if (suspended_opt) {
++ dpm_active_opt = NULL; /* Force reinitialization of DPM */
++ dpm_active_class = NULL;
++ dpm_set_opt(suspended_opt, DPM_SYNC);
++ suspended_opt = NULL;
++ }
++ dpm_unlock();
++}
++
++
++/*****************************************************************************
++ * Create a named operating point
++ * The alternate entry point can be used to create anonymous operating points
++ *****************************************************************************/
++
++int
++_dpm_create_opt(struct dpm_opt **p, const char *name,
++ const dpm_md_pp_t * md_pp, int npp)
++{
++ struct dpm_opt *opt;
++ int ret;
++
++ /* get memory for opt */
++ if (!
++ (opt =
++ (struct dpm_opt *) kmalloc(sizeof (struct dpm_opt), GFP_KERNEL))) {
++ return -ENOMEM;
++ }
++ trace("%s @ 0x%08lx\n", name, (unsigned long)opt);
++ memset(opt, 0, sizeof(struct dpm_opt));
++ if (!(opt->name = (char *) kmalloc(strlen(name) + 1, GFP_KERNEL))) {
++ kfree(opt);
++ return -ENOMEM;
++ }
++
++ /* initialize and validate the opt */
++ strcpy(opt->name, name);
++ memcpy(&opt->pp, md_pp, npp * sizeof(dpm_md_pp_t));
++ ret = dpm_md_init_opt(opt);
++ if (ret) {
++ kfree(opt->name);
++ kfree(opt);
++ return ret;
++ }
++ INIT_LIST_HEAD(&opt->list);
++ *p = opt;
++ dpm_sysfs_new_op(opt);
++ return 0;
++}
++
++int
++dpm_create_opt(const char *name, const dpm_md_pp_t * md_pp, int npp)
++{
++ int ret;
++ struct dpm_opt *opt;
++
++ trace("in dpm_create_opt for \"%s\"\n", name);
++
++ dpm_lock();
++
++ /* ensure name is unique */
++ list_find(opt, name, dpm_opts, struct dpm_opt);
++ if (opt) {
++ dpm_unlock();
++ return -EEXIST;
++ }
++
++ /* create the opt */
++ ret = _dpm_create_opt(&opt, name, md_pp, npp);
++
++ /* add opt to our list */
++ if (!ret)
++ list_add(&opt->list, &dpm_opts);
++
++ dpm_unlock();
++ return ret;
++}
++
++/*****************************************************************************
++ * destroy an operating point
++ * Assumes _dpm_lock is held and the opt is no longer needed *anywhere*
++ *****************************************************************************/
++void
++destroy_opt(struct dpm_opt *opt)
++{
++ dpm_sysfs_destroy_op(opt);
++ list_del(&opt->list);
++ kfree(opt->name);
++ kfree(opt);
++}
++
++/*****************************************************************************
++ * create a named class of operating points (to be used to map to an operating
++ * state)
++ *****************************************************************************/
++
++int
++dpm_create_class(const char *name, char **op_names, unsigned nops)
++{
++ int i;
++ struct dpm_class *cls;
++
++ trace("in dpm_create_class for \"%s\"\n", name);
++
++ dpm_lock();
++
++ /* ensure class is not empty */
++ if (nops == 0) {
++ dpm_unlock();
++ return -EINVAL;
++ }
++
++ /* ensure name is unique */
++ list_find(cls, name, dpm_classes, struct dpm_class);
++ if (cls) {
++ dpm_unlock();
++ return -EEXIST;
++ }
++
++ /* get memory for class */
++ cls = (struct dpm_class *) kmalloc(sizeof (struct dpm_class), GFP_KERNEL);
++ if (!cls) {
++ dpm_unlock();
++ return -ENOMEM;
++ }
++ trace("%s @ 0x%08lx\n", name, (unsigned long)cls);
++ memset(cls, 0, sizeof (struct dpm_class));
++ /* get memory for array of pointers to operating points */
++ cls->ops =
++ (struct dpm_opt **) kmalloc(nops * sizeof (struct dpm_opt *),
++ GFP_KERNEL);
++ if (!cls->ops) {
++ kfree(cls);
++ dpm_unlock();
++ return -ENOMEM;
++ }
++
++ /* get memory for class name */
++ cls->name = (char *) kmalloc(strlen(name) + 1, GFP_KERNEL);
++ if (!cls->name) {
++ kfree(cls->ops);
++ kfree(cls);
++ dpm_unlock();
++ return -ENOMEM;
++ }
++
++ /* find named op points and put their pointers in the class */
++ for (i = 0; i < nops; ++i) {
++ struct dpm_opt *opt;
++ list_find(opt, op_names[i], dpm_opts, struct dpm_opt);
++ if (!opt) {
++ kfree(cls->name);
++ kfree(cls->ops);
++ kfree(cls);
++ dpm_unlock();
++ return -ENOENT;
++ }
++ cls->ops[i] = opt;
++ }
++ strcpy(cls->name, name);
++ cls->nops = nops;
++ /* add class to our list */
++ list_add(&cls->list, &dpm_classes);
++
++ dpm_unlock();
++ dpm_sysfs_new_class(cls);
++
++ return 0;
++}
++
++/*****************************************************************************
++ * destroy a class
++ * Assumes _dpm_lock is held and the class is no longer needed *anywhere*
++ *****************************************************************************/
++void
++destroy_class(struct dpm_class *cls)
++{
++ dpm_sysfs_destroy_class(cls);
++ list_del(&cls->list);
++ kfree(cls->ops);
++ kfree(cls->name);
++ kfree(cls);
++}
++
++int
++dpm_map_policy_state(struct dpm_policy *policy, int state, char *classopt)
++{
++ list_find(policy->classopt[state].opt, classopt, dpm_opts,
++ struct dpm_opt);
++
++ if(!policy->classopt[state].opt) {
++ list_find(policy->classopt[state].class, classopt,
++ dpm_classes, struct dpm_class);
++ if(!policy->classopt[state].class)
++ return -1;
++ }
++
++ return 0;
++}
++
++/*****************************************************************************
++ * create power policy
++ *****************************************************************************/
++int
++dpm_create_policy(const char *name, char **classopt_names, int nopts)
++{
++ int i;
++ struct dpm_policy *policy;
++
++ trace("in dpm_install_policy for \"%s\" policy\n", name);
++
++ dpm_lock();
++
++ /* ensure unique name */
++ list_find(policy, name, dpm_policies, struct dpm_policy);
++ if (policy) {
++ dpm_unlock();
++ return -EEXIST;
++ }
++
++ /* get memory for policy */
++ policy =
++ (struct dpm_policy *) kmalloc(sizeof (struct dpm_policy),
++ GFP_KERNEL);
++ if (!policy) {
++ dpm_unlock();
++ return -ENOMEM;
++ }
++ trace("%s @ 0x%08lx\n", name, (unsigned long)policy);
++ memset(policy, 0, sizeof (struct dpm_policy));
++ /* get memory for policy name */
++ policy->name = (char *) kmalloc(strlen(name) + 1, GFP_KERNEL);
++ if (!policy->name) {
++ kfree(policy);
++ dpm_unlock();
++ return -ENOMEM;
++ }
++
++ /* initialize the policy */
++ for (i = 0; i < DPM_STATES; ++i) {
++ if ((i >= nopts) || !classopt_names[i]) {
++ policy->classopt[i].opt = &nop_op;
++ } else {
++ if (dpm_map_policy_state(policy, i, classopt_names[i])
++ < 0) {
++ kfree(policy->name);
++ kfree(policy);
++ dpm_unlock();
++ return -ENOENT;
++ }
++ }
++ }
++ strcpy(policy->name, name);
++
++ /* add policy to our list */
++ list_add(&policy->list, &dpm_policies);
++ dpm_sysfs_new_policy(policy);
++ trace("installed \"%s\" policy\n", name);
++ dpm_unlock();
++ return 0;
++}
++
++/*****************************************************************************
++ * destroy a power policy
++ * Assumes _dpm_lock is held and the policy is no longer needed *anywhere*
++ *****************************************************************************/
++void
++destroy_policy(struct dpm_policy *policy)
++{
++ dpm_sysfs_destroy_policy(policy);
++ list_del(&policy->list);
++ kfree(policy->name);
++ kfree(policy);
++}
++
++/*****************************************************************************
++ * uninstall power policy
++ *****************************************************************************/
++int
++dpm_destroy_policy(const char *name)
++{
++ struct dpm_policy *policy;
++
++ trace("processing destroy request for \"%s\"\n", name);
++
++ dpm_lock();
++
++ /* find the named policy */
++ list_find(policy, name, dpm_policies, struct dpm_policy);
++ if (!policy) {
++ dpm_unlock();
++ return -ENOENT;
++ }
++
++ /* can't uninstall active policy */
++ if (policy == dpm_active_policy) {
++ dpm_unlock();
++ return -EBUSY;
++ }
++
++ /* remove the policy */
++ destroy_policy(policy);
++
++ dpm_unlock();
++ trace("destroyed \"%s\" policy\n", name);
++ return 0;
++}
++
++/*
++ * set active power policy
++ */
++int
++dpm_set_policy(const char *name)
++{
++ struct dpm_policy *new_p;
++
++ trace("in dpm_set_policy for \"%s\" policy\n", name);
++
++ dpm_lock();
++
++ list_find(new_p, name, dpm_policies, struct dpm_policy);
++ if (!new_p) {
++ dpm_trace(DPM_TRACE_SET_POLICY, name, -ENOENT);
++ dpm_unlock();
++ return -ENOENT; /* invalid name */
++ }
++ if (new_p == dpm_active_policy) {
++ dpm_trace(DPM_TRACE_SET_POLICY, name, 0);
++ trace("\"%s\" policy already activated\n", name);
++ dpm_unlock();
++ return 0;
++ }
++
++ dpm_update_stats(&new_p->stats,
++ dpm_active_policy ? &dpm_active_policy->stats
++ : NULL);
++
++ dpm_active_policy = new_p;
++
++ if (! dpm_enabled) {
++ dpm_enabled = 1;
++ dpm_md_startup();
++ dpm_stats_reset();
++ }
++
++ /* Start the policy synchronously */
++
++ mb();
++ dpm_trace(DPM_TRACE_SET_POLICY, name, 0);
++ dpm_set_opt_sync();
++ dpm_unlock();
++
++ return 0;
++}
++
++/*****************************************************************************
++ * set a raw op state
++ *****************************************************************************/
++
++int
++dpm_set_op_state(const char *name)
++{
++ int op_state;
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ for (op_state = 0; op_state < DPM_STATES; op_state++)
++ if (strcmp(dpm_state_names[op_state], name) == 0) {
++ dpm_set_os(op_state);
++ return 0;
++ }
++
++ return -ENOENT;
++}
++
++/*****************************************************************************
++ * terminate the DPM
++ *****************************************************************************/
++int
++dynamicpower_terminate(void)
++{
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++ trace("in dynamicpower_terminate\n");
++
++ if (!dpm_initialized)
++ return 0;
++
++ dpm_lock();
++
++ dpm_md_cleanup();
++
++ dpm_initialized = 0;
++ dpm_enabled = 0;
++ dpm_active_opt = NULL;
++ dpm_active_class = NULL;
++
++ /* destroy all entities */
++ while (!list_empty(&dpm_policies))
++ destroy_policy(list_entry
++ (dpm_policies.next, struct dpm_policy, list));
++ while (!list_empty(&dpm_opts))
++ destroy_opt(list_entry(dpm_opts.next, struct dpm_opt, list));
++ while (!list_empty(&dpm_classes))
++ destroy_class(list_entry(dpm_classes.next, struct dpm_class,
++ list));
++
++
++ mb();
++ dpm_unlock();
++
++ trace("DPM is now terminated\n");
++ printk("Dynamic Power Management is now terminated\n");
++
++ return 0;
++}
++
++EXPORT_SYMBOL(dynamicpower_init);
++EXPORT_SYMBOL(dynamicpower_terminate);
++EXPORT_SYMBOL(dynamicpower_disable);
++EXPORT_SYMBOL(dynamicpower_enable);
++EXPORT_SYMBOL(dpm_create_opt);
++EXPORT_SYMBOL(dpm_create_class);
++EXPORT_SYMBOL(dpm_create_policy);
++EXPORT_SYMBOL(dpm_destroy_policy);
++EXPORT_SYMBOL(dpm_set_policy);
++
++/****************************************************************************
++ * install dynamic power policy support
++ ****************************************************************************/
++static int __init
++dpm_init_module(void)
++{
++ int i;
++
++ /* Set the NOP operating point params to all -1. */
++
++ for (i = 0; i < DPM_PP_NBR; i++)
++ nop_op.pp[i] = -1;
++
++ trace("DPM is now installed\n");
++ return 0;
++}
++
++/****************************************************************************
++ * remove dynamic power policy support
++ ****************************************************************************/
++static void __exit
++dpm_exit_module(void)
++{
++ /* disable power management policy system */
++ dynamicpower_terminate();
++
++ trace("DPM module is now unloaded\n");
++}
++
++module_init(dpm_init_module);
++module_exit(dpm_exit_module);
++
++/*
++ * Local variables:
++ * c-basic-offset: 8
++ * End:
++ */
+diff --git a/drivers/dpm/proc.c b/drivers/dpm/proc.c
+new file mode 100644
+index 0000000..600ef5a
+--- /dev/null
++++ b/drivers/dpm/proc.c
+@@ -0,0 +1,613 @@
++/*
++ * drivers/dpm/proc.c Dynamic Power Management /proc
++ *
++ * 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
++ *
++ * Copyright (C) 2002, International Business Machines Corporation
++ * All Rights Reserved
++ *
++ * Bishop Brock
++ * IBM Research, Austin Center for Low-Power Computing
++ * bcbrock@us.ibm.com
++ * September, 2002
++ *
++ */
++
++#include <linux/dpm.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/proc_fs.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/semaphore.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++
++#include <bsp.h>
++
++
++#define DEBUG
++#ifdef DEBUG
++#define DPRINT(args...) printk(KERN_CRIT args)
++#else
++#define DPRINT(args...) do {} while (0)
++#endif
++
++#if 0
++#define dbg printk
++#else /* no debug */
++#define dbg(x...) do {} while(0)
++#endif
++
++/****************************************************************************
++ * /proc/driver/dpm interfaces
++ *
++ * NB: Some of these are borrowed from the 405LP, and may need to be made
++ * machine independent.
++ ****************************************************************************/
++
++/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++ * /proc/driver/dpm/cmd (Write-Only)
++ *
++ * Writing a string to this file is equivalent to issuing a DPM command.
++ * Currently only one command per "write" is allowed, and there is a maximum on
++ * the number of tokens that will be accepted (PAGE_SIZE / sizeof(char *)).
++ * DPM can be initialized by a linewise copy of a configuration file to this
++ * /proc file.
++ *
++ * DPM Control
++ * -----------
++ *
++ * init : dynamicpower_init()
++ * enable : dynamicpower_enable()
++ * disable : dynamicpower_disable()
++ * terminate : dynamicpower_terminate()
++ *
++ * Policy Control
++ * --------------
++ *
++ * set_policy <policy> : Set the policy by name
++ * set_task_state <pid> <state> : Set the task state for a given pid, 0 = self
++ *
++ * Policy Creation
++ * ---------------
++ *
++ * create_opt <name> <pp0> ... <ppn>
++ * Create a named operating point from DPM_PP_NBR paramaters. All
++ * parameters must be given. Parameter order and meaning are machine
++ * dependent.
++ *
++ * create_class <name> <opt0> [ ... <optn> ]
++ * Create a named class from 1 or more named operating points. All
++ * operating points must be defined before the call.
++ *
++ * create_policy <name> <classopt0> [ ... <classoptn> ]
++ * Create a named policy from DPM_STATES classes or operating
++ * points. All operating points must be defined before the call.
++ * The order is machine dependent.
++ *
++ *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
++
++static void
++pwarn(char *command, int ntoks, char *requirement, int require)
++{
++ printk(KERN_WARNING "/proc/driver/dpm/cmd: "
++ "Command %s requires %s%d arguments - %d were given\n",
++ command, requirement, require - 1, ntoks - 1);
++}
++
++/*****************************************************************************
++ * set a task state
++ *****************************************************************************/
++
++static int
++dpm_set_task_state(pid_t pid, dpm_state_t task_state)
++{
++ struct task_struct *p;
++
++ dbg("(%s)%s:%d\n", __FILE__, __func__, __LINE__);
++
++ if (task_state == -(DPM_TASK_STATE_LIMIT + 1))
++ task_state = DPM_NO_STATE;
++ else if (abs(task_state) > DPM_TASK_STATE_LIMIT) {
++ dpm_trace(DPM_TRACE_SET_TASK_STATE, pid, task_state, -EINVAL);
++ return -EINVAL;
++ } else
++ task_state += DPM_TASK_STATE;
++
++ read_lock(&tasklist_lock);
++
++ if (pid == 0)
++ p = current;
++ else
++ p = find_task_by_vpid(pid);
++
++ if (!p) {
++ read_unlock(&tasklist_lock);
++ dpm_trace(DPM_TRACE_SET_TASK_STATE, pid, task_state, -ENOENT);
++ return -ENOENT;
++ }
++
++ p->dpm_state = task_state;
++ read_unlock(&tasklist_lock);
++
++ dpm_trace(DPM_TRACE_SET_TASK_STATE, pid, task_state, 0);
++
++ if (pid == 0)
++ dpm_set_os(p->dpm_state);
++
++
++ return 0;
++}
++
++
++static int
++write_proc_dpm_cmd (struct file *file, const char *buffer,
++ unsigned long count, void *data)
++{
++ char *buf, *tok, **tokptrs;
++ char *whitespace = " \t\r\n";
++ int ret = 0, ntoks;
++
++ if (current->uid != 0)
++ return -EACCES;
++ if (count == 0)
++ return 0;
++ if (!(buf = kmalloc(count + 1, GFP_KERNEL)))
++ return -ENOMEM;
++ if (copy_from_user(buf, buffer, count)) {
++ ret = -EFAULT;
++ goto out0;
++ }
++
++ buf[count] = '\0';
++
++ if (!(tokptrs = (char **)__get_free_page(GFP_KERNEL))) {
++ ret = -ENOMEM;
++ goto out1;
++ }
++
++ ret = -EINVAL;
++ ntoks = 0;
++ do {
++ buf = buf + strspn(buf, whitespace);
++ tok = strsep(&buf, whitespace);
++ if (*tok == '\0') {
++ if (ntoks == 0) {
++ ret = 0;
++ goto out1;
++ } else
++ break;
++ }
++ if (ntoks == (PAGE_SIZE / sizeof(char **)))
++ goto out1;
++ tokptrs[ntoks++] = tok;
++ } while(buf);
++
++ if (ntoks == 1) {
++ if (strcmp(tokptrs[0], "init") == 0) {
++ ret = dynamicpower_init();
++ } else if (strcmp(tokptrs[0], "enable") == 0) {
++ ret = dynamicpower_enable();
++ } else if (strcmp(tokptrs[0], "disable") == 0) {
++ ret = dynamicpower_disable();
++ } else if (strcmp(tokptrs[0], "terminate") == 0) {
++ ret = dynamicpower_terminate();
++ }
++ } else if (ntoks == 2) {
++ if (strcmp(tokptrs[0], "set_policy") == 0)
++ ret = dpm_set_policy(tokptrs[1]);
++ else if (strcmp(tokptrs[0], "set_state") == 0)
++ ret = dpm_set_op_state(tokptrs[1]);
++ } else {
++ if (strcmp(tokptrs[0], "set_task_state") == 0) {
++ if (ntoks != 3)
++ pwarn("set_task_state", ntoks, "", 3);
++ else
++ ret = dpm_set_task_state(simple_strtol(tokptrs[1],
++ NULL, 0),
++ simple_strtol(tokptrs[2],
++ NULL, 0));
++ } else if (strcmp(tokptrs[0], "create_opt") == 0) {
++ if (ntoks != DPM_PP_NBR + 2)
++ pwarn("create_opt", ntoks,
++ "", DPM_PP_NBR + 2);
++ else {
++ dpm_md_pp_t pp[DPM_PP_NBR];
++ int i;
++
++ for (i = 0; i < DPM_PP_NBR; i++)
++ pp[i] = simple_strtol(tokptrs[i + 2],
++ NULL, 0);
++ ret = dpm_create_opt(tokptrs[1], pp, DPM_PP_NBR);
++ }
++
++ } else if (strcmp(tokptrs[0], "create_class") == 0) {
++ if (ntoks < 3)
++ pwarn("create_class", ntoks, ">= ", 3);
++ else
++ ret = dpm_create_class(tokptrs[1], &tokptrs[2],
++ ntoks - 2);
++
++ } else if (strcmp(tokptrs[0], "create_policy") == 0) {
++ if (ntoks != (DPM_STATES + 2))
++ pwarn("create_policy", ntoks, "",
++ DPM_STATES + 2);
++ else
++ ret = dpm_create_policy(tokptrs[1],
++ &tokptrs[2], ntoks-2);
++ }
++ }
++out1:
++ free_page((unsigned long)tokptrs);
++out0:
++ kfree(buf);
++ if (ret == 0)
++ return count;
++ else
++ return ret;
++}
++
++#ifdef CONFIG_DPM_STATS
++
++/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++ * /proc/driver/dpm/stats (Read-Only)
++ *
++ * Reading this file produces the following line for each defined operating
++ * state:
++ *
++ * state_name total_time count opt_name
++ *
++ * Where:
++ *
++ * state_name = The operating state name.
++ * total_time = The 64-bit number of microseconds spent in this
++ * operating state.
++ * count = The 64-bit number of times this operating state was entered.
++ * opt_name = The name of the operating point currently assigned to this
++ * operating state.
++ *
++ *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
++
++static int
++sprintf_u64(char *buf, int fill, char *s, u64 ul)
++{
++ int len = 0;
++ u32 u, l;
++
++ u = (u32)((ul >> 32) & 0xffffffffU);
++ l = (u32)(ul & 0xffffffffU);
++
++ len += sprintf(buf + len, s);
++ if (fill)
++ len += sprintf(buf + len, "0x%08x%08x", u, l);
++ else {
++ if (u)
++ len += sprintf(buf + len, "0x%x%x", u, l);
++ else
++ len += sprintf(buf + len, "0x%x", l);
++ }
++ return len;
++}
++
++/*****************************************************************************
++ * get statistics for all operating states
++ *****************************************************************************/
++
++int
++dpm_get_os_stats(struct dpm_stats *stats)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&dpm_policy_lock, flags);
++ memcpy(stats, dpm_state_stats, DPM_STATES * sizeof (struct dpm_stats));
++ stats[dpm_active_state].total_time +=
++ dpm_time() - stats[dpm_active_state].start_time;
++ spin_unlock_irqrestore(&dpm_policy_lock, flags);
++ return 0;
++}
++
++static int
++read_proc_dpm_stats(char *page, char **start, off_t offset,
++ int count, int *eof, void *data)
++{
++ int i, len = 0;
++ struct dpm_stats stats[DPM_STATES];
++
++ if (!dpm_enabled) {
++ len += sprintf(page + len, "DPM IS DISABLED\n");
++ *eof = 1;
++ return len;
++ }
++
++ dpm_get_os_stats(stats);
++
++ for (i = 0; i < DPM_STATES; i++) {
++ len += sprintf(page + len, "%20s", dpm_state_names[i]);
++ len += sprintf_u64(page + len, 1, " ",
++ (u64)stats[i].total_time);
++ len += sprintf_u64(page + len, 1, " ", (u64)stats[i].count);
++ len += sprintf(page + len, " %s\n",
++ dpm_classopt_name(dpm_active_policy,i));
++ }
++
++ *eof = 1;
++ return len;
++}
++
++/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++ * /proc/driver/dpm/opt_stats (Read-Only)
++ *
++ * Reading this file produces the following line for each defined operating
++ * point:
++ *
++ * name total_time count
++ *
++ * Where:
++ *
++ * name = The operating point name.
++ * total_time = The 64-bit number of microseconds spent in this
++ * operating state.
++ * count = The 64-bit number of times this operating point was entered.
++ *
++ *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
++
++static int
++read_proc_dpm_opt_stats(char *page, char **start, off_t offset,
++ int count, int *eof, void *data)
++{
++ int len = 0;
++ struct dpm_opt *opt;
++ struct list_head *p;
++ unsigned long long total_time;
++
++ if (dpm_lock_interruptible())
++ return -ERESTARTSYS;
++
++ if (!dpm_enabled) {
++ dpm_unlock();
++ len += sprintf(page + len, "DPM IS DISABLED\n");
++ *eof = 1;
++ return len;
++ }
++
++ for (p = dpm_opts.next; p != &dpm_opts; p = p->next) {
++ opt = list_entry(p, struct dpm_opt, list);
++ len += sprintf(page + len, "%s", opt->name);
++ total_time = opt->stats.total_time;
++ if (opt == dpm_active_opt)
++ total_time += dpm_time() - opt->stats.start_time;
++ len += sprintf_u64(page + len, 0, " ", opt->stats.total_time);
++ len += sprintf_u64(page + len, 0, " ", opt->stats.count);
++ len += sprintf(page + len, "\n");
++ }
++
++ dpm_unlock();
++ *eof = 1;
++ return len;
++}
++#endif /* CONFIG_DPM_STATS */
++
++/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++ * /proc/driver/dpm/state (Read-Only)
++ *
++ * Reading this file produces the following:
++ *
++ * policy_name os os_name os_opt_name opt_name hz
++ *
++ * Where:
++ *
++ * policy_name = The name of the current policy
++ * os = The curret operating state index
++ * os_name = The current operating state name
++ * os_opt_name = The name of the implied operating point for the policy and
++ * state.
++ * opt_name = The name of the actual operating point; may be different if
++ * the operating state and operating point are out of sync.
++ * hz = The frequency of the statistics timer
++ *
++ * If DPM is disabled the line will appear as:
++ *
++ * N/A -1 N/A N/A N/A <hz>
++ *
++ *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
++
++static int
++read_proc_dpm_state(char *page, char **start, off_t offset,
++ int count, int *eof, void *data)
++{
++ unsigned long flags;
++
++ int len = 0;
++
++ if (dpm_lock_interruptible())
++ return -ERESTARTSYS;
++
++ if (!dpm_enabled) {
++ len += sprintf(page + len, "N/A -1 N/A N/A N/A N/A\n");
++ } else {
++
++ spin_lock_irqsave(&dpm_policy_lock, flags);
++ len += sprintf(page + len,"%s %d %s %s %s\n",
++ dpm_active_policy->name,
++ dpm_active_state,
++ dpm_state_names[dpm_active_state],
++ dpm_classopt_name(dpm_active_policy,
++ dpm_active_state),
++ dpm_active_opt ? dpm_active_opt->name : "none");
++ spin_unlock_irqrestore(&dpm_policy_lock, flags);
++ }
++
++ dpm_unlock();
++ *eof = 1;
++ return len;
++}
++
++
++/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++ * /proc/driver/dpm/debug (Read-Only)
++ *
++ * Whatever it needs to be
++ *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
++
++#ifdef DEBUG
++static int
++read_proc_dpm_debug(char *page, char **start, off_t offset,
++ int count, int *eof, void *data)
++{
++ int len = 0;
++
++ len += sprintf(page + len, "No DEBUG info\n");
++ *eof = 1;
++ return len;
++}
++#endif /* DEBUG */
++
++static struct proc_dir_entry *proc_dpm;
++static struct proc_dir_entry *proc_dpm_cmd;
++static struct proc_dir_entry *proc_dpm_state;
++
++#ifdef CONFIG_DPM_STATS
++static struct proc_dir_entry *proc_dpm_stats;
++static struct proc_dir_entry *proc_dpm_opt_stats;
++#endif
++
++#ifdef DEBUG
++static struct proc_dir_entry *proc_dpm_debug;
++#endif
++
++#ifdef CONFIG_DPM_TRACE
++static struct proc_dir_entry *proc_dpm_trace;
++#endif
++
++static int __init
++dpm_proc_init(void)
++{
++ proc_dpm = proc_mkdir("driver/dpm", NULL);
++
++ if (proc_dpm) {
++
++ proc_dpm_cmd =
++ create_proc_entry("cmd",
++ S_IWUSR,
++ proc_dpm);
++ if (proc_dpm_cmd)
++ proc_dpm_cmd->write_proc = write_proc_dpm_cmd;
++
++ proc_dpm_state =
++ create_proc_read_entry("state",
++ S_IRUGO,
++ proc_dpm,
++ read_proc_dpm_state,
++ NULL);
++#ifdef CONFIG_DPM_STATS
++ proc_dpm_stats =
++ create_proc_read_entry("stats",
++ S_IRUGO,
++ proc_dpm,
++ read_proc_dpm_stats,
++ NULL);
++ proc_dpm_opt_stats =
++ create_proc_read_entry("opt_stats",
++ S_IRUGO,
++ proc_dpm,
++ read_proc_dpm_opt_stats,
++ NULL);
++
++#endif /* CONFIG_DPM_STATS */
++
++#ifdef DEBUG
++ proc_dpm_debug =
++ create_proc_read_entry("debug",
++ S_IRUGO,
++ proc_dpm,
++ read_proc_dpm_debug,
++ NULL);
++#endif
++
++#ifdef CONFIG_DPM_TRACE
++ proc_dpm_trace =
++ create_proc_read_entry("trace",
++ S_IWUSR | S_IRUGO,
++ proc_dpm,
++ read_proc_dpm_trace,
++ NULL);
++ if (proc_dpm_trace)
++ proc_dpm_trace->write_proc = write_proc_dpm_trace;
++#endif
++ } else {
++ printk(KERN_ERR "Attempt to create /proc/driver/dpm failed\n");
++
++ }
++ return 0;
++}
++
++static void __exit
++dpm_proc_exit(void)
++{
++ if (proc_dpm_cmd) {
++ remove_proc_entry("cmd", proc_dpm);
++ proc_dpm_cmd = NULL;
++ }
++
++ if (proc_dpm_state) {
++ remove_proc_entry("state", proc_dpm);
++ proc_dpm_state = NULL;
++ }
++
++#ifdef CONFIG_DPM_STATS
++ if (proc_dpm_stats) {
++ remove_proc_entry("stats", proc_dpm);
++ proc_dpm_stats = NULL;
++ }
++
++ if (proc_dpm_opt_stats) {
++ remove_proc_entry("opt_stats", proc_dpm);
++ proc_dpm_opt_stats = NULL;
++ }
++#endif /* CONFIG_DPM_STATS */
++
++#ifdef DEBUG
++ if (proc_dpm_debug) {
++ remove_proc_entry("debug", proc_dpm);
++ proc_dpm_debug = NULL;
++ }
++#endif
++
++#ifdef CONFIG_DPM_TRACE
++ if (proc_dpm_trace) {
++ remove_proc_entry("trace", proc_dpm);
++ proc_dpm_trace = NULL;
++ }
++#endif
++
++ remove_proc_entry("driver/dpm", NULL);
++}
++
++
++
++module_init(dpm_proc_init);
++module_exit(dpm_proc_exit);
++
++/*
++ * Local variables:
++ * c-basic-offset: 8
++ * End:
++ */
++
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index 7f95905..952f821 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -503,6 +503,15 @@ config I2C_VERSATILE
+ This driver can also be built as a module. If so, the module
+ will be called i2c-versatile.
+
++config I2C_TCC
++ bool "Telechips I2C block bus driver"
++ depends on ARCH_TCC
++ default y
++ help
++ If you say yes to this option, support will be included for the
++ I2C interface on the Telechips System-on-Chip.
++ Like TCC8900.
++
+ comment "External I2C/SMBus adapter drivers"
+
+ config I2C_PARPORT
+diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
+index 0c2c4b2..a6e34f0 100644
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -48,6 +48,11 @@ obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
+ obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
+ obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
+
++ifeq ($(CONFIG_ARCH_TCC),y)
++$(shell ln -fsn $(CONFIG_TCC_STRING)/ $(srctree)/drivers/i2c/busses/tcc)
++endif
++obj-$(CONFIG_I2C_TCC) += i2c-tcc.o tcc/tca_i2c.o
++
+ # External I2C/SMBus adapter drivers
+ obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
+ obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
+diff --git a/drivers/i2c/busses/i2c-tcc.c b/drivers/i2c/busses/i2c-tcc.c
+new file mode 100644
+index 0000000..0815344
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-tcc.c
+@@ -0,0 +1,452 @@
++/*
++ * linux/drivers/i2c/busses/i2c-tcc.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 10th Jun, 2008
++ * Description: Telechips I2C Controller
++ *
++ * Copyright (c) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * ----------------------------
++ * for TCC DIBCOM DVB-T module
++ * [M] i2c-core.c, i2c-dev.c
++ * [M] include/linux/i2c-dev.h, include/linux/i2c.h
++ *
++*/
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/i2c-id.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/completion.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++
++#include <asm/io.h>
++
++#include <bsp.h>
++#include "tcc/tca_i2c.h"
++
++
++enum tcc_i2c_state {
++ STATE_IDLE,
++ STATE_START,
++ STATE_READ,
++ STATE_WRITE,
++ STATE_STOP
++};
++
++struct tcc_i2c {
++ spinlock_t lock;
++ wait_queue_head_t wait;
++ volatile struct tcc_i2c_regs *regs;
++ volatile unsigned long IRQSTR;
++ int ch;
++ unsigned int clk;
++
++ struct i2c_msg *msg;
++ unsigned int msg_num;
++ unsigned int msg_idx;
++ unsigned int msg_ptr;
++
++ enum tcc_i2c_state state;
++
++ struct device *dev;
++ struct i2c_adapter adap;
++};
++
++/* tcc_i2c_message_start
++ *
++ * put the start of a message onto the bus
++*/
++static void tcc_i2c_message_start(struct tcc_i2c *i2c, struct i2c_msg *msg)
++{
++ unsigned int addr = (msg->addr & 0x7f) << 1;
++
++ if (msg->flags & I2C_M_RD)
++ addr |= 1;
++ if (msg->flags & I2C_M_REV_DIR_ADDR)
++ addr ^= 1;
++
++ i2c->regs->TXR = addr;
++ i2c->regs->CMD = Hw7 | Hw4;
++}
++
++static int wait_intr(struct tcc_i2c *i2c)
++{
++ unsigned long cnt = 0;
++
++ if (i2c->ch == 0 || i2c->ch == 1) {
++ while (!(tcc_readl(i2c->IRQSTR) & (i2c->ch?Hw1:Hw0))) {
++ cnt++;
++ if (cnt > 100000) {
++ printk("i2c-tcc: time out!\n");
++ return -1;
++ }
++ }
++ } else {
++ /* SMU_I2C wait */
++ while (1) {
++ cnt = i2c->regs->SR;
++ if (!(cnt & Hw1)) break;
++ }
++ for (cnt = 0; cnt <15; cnt++);
++ }
++
++ return 0;
++}
++
++static int recv_i2c(struct tcc_i2c *i2c)
++{
++ int ret, i;
++ dev_dbg(&i2c->adap.dev, "READ [%x][%d]\n", i2c->msg->addr, i2c->msg->len);
++
++ tcc_i2c_message_start(i2c, i2c->msg);
++
++ ret = wait_intr(i2c);
++ if (ret != 0)
++ return ret;
++ BITSET(i2c->regs->CMD, Hw0); /* Clear a pending interrupt */
++
++ for (i = 0; i < i2c->msg->len; i++) {
++ if (i == (i2c->msg->len - 1))
++ i2c->regs->CMD = Hw5 | Hw3;
++ else
++ i2c->regs->CMD = Hw5;
++
++ ret = wait_intr(i2c);
++ if (ret != 0)
++ return ret;
++ BITSET(i2c->regs->CMD, Hw0);
++
++ i2c->msg->buf[i] = (unsigned char) i2c->regs->RXR;
++ }
++
++ i2c->regs->CMD = Hw6;
++
++ ret = wait_intr(i2c);
++ if (ret != 0)
++ return ret;
++ BITSET(i2c->regs->CMD, Hw0);
++
++ return 1;
++}
++
++static int send_i2c(struct tcc_i2c *i2c)
++{
++ int ret, i, no_stop = 0;
++ dev_dbg(&i2c->adap.dev, "SEND [%x][%d]", i2c->msg->addr, i2c->msg->len);
++
++ tcc_i2c_message_start(i2c, i2c->msg);
++
++ ret = wait_intr(i2c);
++ if (ret != 0)
++ return ret;
++ BITSET(i2c->regs->CMD, Hw0); /* Clear a pending interrupt */
++
++ for (i = 0; i < i2c->msg->len; i++) {
++ i2c->regs->TXR = i2c->msg->buf[i];
++ i2c->regs->CMD = Hw4;
++ ret = wait_intr(i2c);
++ if (ret != 0)
++ return ret;
++ BITSET(i2c->regs->CMD, Hw0);
++
++ //i2c->msg->buf[i] = (unsigned char) i2c->regs->RXR; //XXX
++ }
++
++ /*
++ * Check no-stop operation condition (write -> read operation)
++ * 1. DIBCOM
++ * 2. msg_num == 2
++ */
++ if (i2c->msg->flags & I2C_M_DIBCOM_WR_RD)
++ no_stop = 1;
++ if (i2c->msg_num > 1)
++ no_stop = 1;
++
++ if (no_stop == 0) {
++ i2c->regs->CMD = Hw6;
++ ret = wait_intr(i2c);
++ if (ret != 0)
++ return ret;
++ }
++ BITSET(i2c->regs->CMD, Hw0); /* Clear a pending interrupt */
++
++ return 1;
++}
++
++/* tcc_i2c_doxfer
++ *
++ * this starts an i2c transfer
++*/
++static int tcc_i2c_doxfer(struct tcc_i2c *i2c, struct i2c_msg *msgs, int num)
++{
++ int ret, i;
++
++ for (i = 0; i < num; i++) {
++ spin_lock_irq(&i2c->lock);
++ i2c->msg = &msgs[i];
++ i2c->msg->flags = msgs[i].flags;
++ i2c->msg_num = num;
++ i2c->msg_ptr = 0;
++ i2c->msg_idx = 0;
++ i2c->state = STATE_START;
++ spin_unlock_irq(&i2c->lock);
++
++ if (i2c->msg->flags & I2C_M_RD) {
++ ret = recv_i2c(i2c);
++ if (ret != 1)
++ printk("recv_i2c failed\n");
++ } else {
++ ret = send_i2c(i2c);
++ if (ret != 1)
++ printk("send_i2c failed\n");
++ }
++ }
++
++ return ret;
++}
++
++/* tcc_i2c_xfer
++ *
++ * first port of call from the i2c bus code when an message needs
++ * transferring across the i2c bus.
++*/
++static int tcc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
++{
++ struct tcc_i2c *i2c = (struct tcc_i2c *)adap->algo_data;
++ int retry;
++ int ret;
++
++ for (retry = 0; retry < adap->retries; retry++) {
++
++ ret = tcc_i2c_doxfer(i2c, msgs, num);
++
++ if (ret == 1)
++ return num;
++
++ dev_dbg(&i2c->adap.dev, "Retrying transmission (%d)\n", retry);
++
++ udelay(100);
++ }
++
++ return -EREMOTEIO;
++}
++
++static u32 tcc_i2c_func(struct i2c_adapter *adap)
++{
++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
++}
++
++/* i2c bus registration info */
++static const struct i2c_algorithm tcc_i2c_algorithm = {
++ .master_xfer = tcc_i2c_xfer,
++ .functionality = tcc_i2c_func,
++};
++
++/* tcc_i2c_init
++ *
++ * initialize the I2C controller, set the IO lines and frequency
++ */
++static void tcc_i2c_init(struct tcc_i2c *i2c)
++{
++ if (i2c->ch == 0 || i2c->ch == 1) {
++ /* I2C GPIO setting */
++ tca_i2c_setgpio(i2c->ch);
++
++ /* I2C clock setting */
++ tca_i2c_setclock(i2c->ch, i2c->regs, i2c->clk);
++ } else {
++ /* SMU_I2C clock setting */
++ tcc_writel(0x80000000, i2c->IRQSTR);
++
++ i2c->regs->CTRL = 0;
++ i2c->regs->PRES = 4;
++ BITSET(i2c->regs->CTRL, Hw7|Hw6);
++ }
++}
++
++/* tcc83xx_i2c_probe
++ *
++ * called by the bus driver when a suitable device is found
++*/
++static int tcc_i2c_probe(struct platform_device *pdev)
++{
++ struct tcc_i2c *i2c;
++ struct resource *resource_mem, *resource_clk;
++ struct resource *resource_mem_smu_i2c, *resource_clk_smu_i2c;
++ int i, ret;
++
++ resource_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!resource_mem) {
++ dev_err(&pdev->dev, "no mem resource?\n");
++ return -ENODEV;
++ }
++ resource_clk = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!resource_clk) {
++ dev_err(&pdev->dev, "no clk resource?\n");
++ return -ENODEV;
++ }
++
++ /* SMU_I2C */
++ resource_mem_smu_i2c = platform_get_resource(pdev, IORESOURCE_MEM, 2);
++ if (!resource_mem_smu_i2c) {
++ dev_err(&pdev->dev, "no mem resource? (smu_i2c)\n");
++ return -ENODEV;
++ }
++ resource_clk_smu_i2c = platform_get_resource(pdev, IORESOURCE_MEM, 3);
++ if (!resource_clk_smu_i2c) {
++ dev_err(&pdev->dev, "no clk resource? (smu_i2c)\n");
++ return -ENODEV;
++ }
++
++ i2c = kzalloc(sizeof(struct tcc_i2c) * I2C_NUM_OF_CH, GFP_KERNEL);
++ if (!i2c) {
++ ret = -ENOMEM;
++ goto err_nockl;
++ }
++
++ for (i = 0; i < I2C_NUM_OF_CH; i++) {
++ i2c[i].adap.owner = THIS_MODULE;
++ i2c[i].adap.algo = &tcc_i2c_algorithm;
++ i2c[i].adap.retries = 2;
++ sprintf(i2c[i].adap.name, "tcc-i2c-%d", i);
++
++ spin_lock_init(&i2c[i].lock);
++ init_waitqueue_head(&i2c[i].wait);
++
++ if (i == 0) {
++ i2c[i].ch = 0;
++ i2c[i].clk = (unsigned int)resource_clk->start;
++ i2c[i].regs = (volatile struct tcc_i2c_regs *)resource_mem->start;
++ i2c[i].IRQSTR = resource_mem->start + I2C_IRQSTR_OFFSET;
++ } else if (i == 1) {
++ i2c[i].ch = 1;
++ i2c[i].clk = (unsigned int)resource_clk->end;
++ i2c[i].regs = (volatile struct tcc_i2c_regs *)resource_mem->end;
++ i2c[i].IRQSTR = resource_mem->start + I2C_IRQSTR_OFFSET;
++ } else if (i == 2) {
++ i2c[i].ch = 2;
++ i2c[i].clk = (unsigned int)resource_clk_smu_i2c->start;
++ i2c[i].regs = (volatile struct tcc_i2c_regs *)resource_mem_smu_i2c->start;
++ i2c[i].IRQSTR = resource_mem_smu_i2c->start + I2C_ICLK_OFFSET;
++ } else if (i == 3) {
++ i2c[i].ch = 3;
++ i2c[i].clk = (unsigned int)resource_clk_smu_i2c->end;
++ i2c[i].regs = (volatile struct tcc_i2c_regs *)resource_mem_smu_i2c->end;
++ i2c[i].IRQSTR = resource_mem_smu_i2c->start + I2C_ICLK_OFFSET;
++ } else {
++ dev_err(&pdev->dev, "no i2c channel?\n");
++ return -ENODEV;
++ }
++ }
++
++ /* I2C reset */
++ tca_i2c_reset();
++
++ for (i = 0; i < I2C_NUM_OF_CH; i++) {
++ tcc_i2c_init(i2c + i);
++
++ i2c[i].adap.algo_data = i2c + i;
++ i2c[i].adap.dev.parent = &pdev->dev;
++ i2c[i].adap.class = I2C_CLASS_ALL;
++
++ ret = i2c_add_adapter(&i2c[i].adap);
++ if (ret < 0) {
++ printk("tcc-i2c-%d: Failed to add bus\n", i);
++ for (i--; i >= 0; i--)
++ i2c_del_adapter(&i2c[i].adap);
++ goto err_clk;
++ }
++ }
++
++ platform_set_drvdata(pdev, i2c);
++ dev_info(&pdev->dev, "%s: I2C adapter\n", i2c->adap.dev.bus_id);
++
++ return 0;
++
++err_clk:
++ //TODO: I2C peri bus disable
++
++err_nockl:
++ return ret;
++}
++
++static int tcc_i2c_remove(struct platform_device *pdev)
++{
++ int i;
++ struct tcc_i2c *i2c = platform_get_drvdata(pdev);
++
++ platform_set_drvdata(pdev, NULL);
++
++ for (i = 0; i < I2C_NUM_OF_CH; i++)
++ i2c_del_adapter(&i2c[i].adap);
++
++ /* I2C bus & clock disable */
++ tca_ckc_setiobus(RB_I2CCONTROLLER, DISABLE);
++
++ kfree(i2c);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int tcc_i2c_suspend_late(struct platform_device *dev, pm_message_t state)
++{
++ tca_ckc_setiobus(RB_I2CCONTROLLER, DISABLE);
++ return 0;
++}
++
++static int tcc_i2c_resume_early(struct platform_device *dev)
++{
++ struct tcc_i2c *i2c = platform_get_drvdata(dev);
++ int i;
++
++ tca_i2c_reset();
++ for (i = 0; i < I2C_NUM_OF_CH; i++) {
++ tcc_i2c_init(i2c + i);
++ }
++
++ return 0;
++}
++#else
++#define tcc_i2c_suspend_late NULL
++#define tcc_i2c_resume_early NULL
++#endif
++
++/* device driver for platform bus bits */
++
++static struct platform_driver tcc_i2c_driver = {
++ .probe = tcc_i2c_probe,
++ .remove = tcc_i2c_remove,
++ .suspend_late = tcc_i2c_suspend_late,
++ .resume_early = tcc_i2c_resume_early,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "tcc-i2c",
++ },
++};
++
++static int __init tcc_i2c_adap_init(void)
++{
++ return platform_driver_register(&tcc_i2c_driver);
++}
++
++static void __exit tcc_i2c_adap_exit(void)
++{
++ platform_driver_unregister(&tcc_i2c_driver);
++}
++
++module_init(tcc_i2c_adap_init);
++module_exit(tcc_i2c_adap_exit);
++
++MODULE_AUTHOR("Telechips Inc. SYS4-3 linux@telechips.com");
++MODULE_DESCRIPTION("Telechips H/W I2C driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/i2c/busses/tcc b/drivers/i2c/busses/tcc
+new file mode 120000
+index 0000000..a34de28
+--- /dev/null
++++ b/drivers/i2c/busses/tcc
+@@ -0,0 +1 @@
++tcc8900/
+\ No newline at end of file
+diff --git a/drivers/i2c/busses/tcc8900/tca_i2c.c b/drivers/i2c/busses/tcc8900/tca_i2c.c
+new file mode 100644
+index 0000000..69c249d
+--- /dev/null
++++ b/drivers/i2c/busses/tcc8900/tca_i2c.c
+@@ -0,0 +1,82 @@
++/****************************************************************************
++ * FileName : tca_i2c.c
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#include <linux/delay.h>
++
++#include <bsp.h>
++#include "tca_i2c.h"
++
++
++/*****************************************************************************
++* Function Name : tca_i2c_reset()
++* Description: I2C controller reset
++******************************************************************************/
++void tca_i2c_reset(void)
++{
++ tca_ckc_set_iobus_swreset(RB_I2CCONTROLLER, OFF);
++ tca_ckc_set_iobus_swreset(RB_I2CCONTROLLER, ON);
++}
++
++/*****************************************************************************
++* Function Name : tca_i2c_setgpio()
++* Description: I2C port configuration
++* SCL0-GPA0, SDA0-GPA1
++* SCL1-GPA8, SDA1-GPA9
++* input parameter:
++* int ch; // I2C master channel
++******************************************************************************/
++void tca_i2c_setgpio(int ch)
++{
++ volatile struct tcc_gpio *gpio;
++
++ gpio = (volatile struct tcc_gpio *)GPA_BASE;
++
++ switch (ch) {
++ case 0:
++ BITCSET(gpio->FN0, (Hw4-Hw0), Hw0); // GPA[0] function set 1
++ BITCSET(gpio->FN0, (Hw8-Hw4), Hw4); // GPA[1] function set 1
++ break;
++ case 1:
++ BITCSET(gpio->FN1, (Hw4-Hw0), Hw0); // GPA[8] function set 1
++ BITCSET(gpio->FN1, (Hw8-Hw4), Hw4); // GPA[9] function set 1
++ break;
++ default:
++ break;
++ }
++}
++
++/*****************************************************************************
++* Function Name : tca_i2c_setclock()
++* Description: I2C clock configuration
++* input parameter:
++* int ch; // I2C master channel
++******************************************************************************/
++void tca_i2c_setclock(int ch, volatile struct tcc_i2c_regs *i2c_reg, unsigned int i2c_clock)
++{
++ unsigned int i2c_clk_input_freq, prescale;
++
++ /* I2C IO-bus enable */
++ tca_ckc_setiobus(RB_I2CCONTROLLER, ENABLE);
++
++ /* get I2C bus clock
++ * bootloader set I2C bus clock
++ */
++ i2c_clk_input_freq = tca_ckc_getperi(PERI_I2C);
++
++ prescale = ((i2c_clk_input_freq / 10) / (i2c_clock * 5)) - 1;
++ i2c_reg->PRES = prescale;
++ i2c_reg->CTRL = Hw7 | Hw6 | HwZERO; // start enable, stop enable, 8bit mode
++ BITSET(i2c_reg->CMD, Hw0); // clear pending interrupt
++
++ printk("i2c%d SCK(%d) <-- input clk(%dKhz), prescale(%d)\n",
++ ch, i2c_clock, i2c_clk_input_freq, prescale);
++}
++
++/* end of source */
+diff --git a/drivers/i2c/busses/tcc8900/tca_i2c.h b/drivers/i2c/busses/tcc8900/tca_i2c.h
+new file mode 100644
+index 0000000..ec7cd9a
+--- /dev/null
++++ b/drivers/i2c/busses/tcc8900/tca_i2c.h
+@@ -0,0 +1,43 @@
++/****************************************************************************
++ * FileName : tca_i2c.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#ifndef __TCA_I2C_H__
++#define __TCA_I2C_H__
++
++/* Define
++ */
++#define I2C_NUM_OF_CH 4
++#define GPA_BASE 0xF0102000
++
++#define I2C_IRQSTR_OFFSET 0xC0 /* only I2C */
++#define I2C_ICLK_OFFSET 0x80 /* only SMU_I2C */
++
++
++/* register structure
++ */
++#pragma pack(push, 4)
++struct tcc_gpio {
++ volatile unsigned long DAT, EN, SET, CLR, XOR, CD0, CD1, PD0, PD1, FN0, FN1, FN2, FN3;
++};
++
++struct tcc_i2c_regs {
++ volatile unsigned long PRES, CTRL, TXR, CMD, RXR, SR, TR;
++};
++#pragma pack(pop)
++
++
++/* extern functions
++ */
++extern void tca_i2c_reset(void);
++extern void tca_i2c_setgpio(int ch);
++extern void tca_i2c_setclock(int ch, volatile struct tcc_i2c_regs *i2c_reg, unsigned int i2c_clock);
++
++#endif //__TCA_I2C_H__
++
+diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
+index 4c35702..8656232 100644
+--- a/drivers/i2c/chips/Kconfig
++++ b/drivers/i2c/chips/Kconfig
+@@ -185,4 +185,22 @@ config MCU_MPC8349EMITX
+ also register MCU GPIOs with the generic GPIO API, so you'll able
+ to use MCU pins as GPIOs.
+
++config TCC_I2C_WM8731
++ bool "Telechips WM8731 Codec chip"
++ help
++ If you say yes here you get support for the Telechips board's
++ WM8731 Codec chip.
++
++config TCC_I2C_WM8987
++ bool "Telechips WM8987 Codec chip"
++ help
++ If you say yes here you get support for the Telechips board's
++ WM8987 Codec chip.
++
++config TCC_I2C_PCA953X
++ bool "Telechips PCA953X GPIO Expansion chip"
++ help
++ If you say yes here you get support for the Telechips board's
++ PCA9538 and PCA9539 GPIO Expansion chips.
++
+ endmenu
+diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
+index 23d2a31..4e3a984 100644
+--- a/drivers/i2c/chips/Makefile
++++ b/drivers/i2c/chips/Makefile
+@@ -23,6 +23,8 @@ obj-$(CONFIG_TPS65010) += tps65010.o
+ obj-$(CONFIG_MENELAUS) += menelaus.o
+ obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
+ obj-$(CONFIG_MCU_MPC8349EMITX) += mcu_mpc8349emitx.o
++obj-$(CONFIG_TCC_I2C_WM8731) += tcc_wm8731.o
++obj-$(CONFIG_TCC_I2C_PCA953X) += tcc_pca953x.o
+
+ ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
+ EXTRA_CFLAGS += -DDEBUG
+diff --git a/drivers/i2c/chips/tcc_pca953x.c b/drivers/i2c/chips/tcc_pca953x.c
+new file mode 100644
+index 0000000..0d12014
+--- /dev/null
++++ b/drivers/i2c/chips/tcc_pca953x.c
+@@ -0,0 +1,259 @@
++/*
++ * linux/drivers/i2c/chips/tcc_pca953x.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 31th March, 2009
++ * Description: Tcc250 Driver
++ *
++ * Copyright (c) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * ====================================
++ * Description
++ * -----------
++ * Slave chip: two PCA9539, one PCA9538
++ * Slave address: PCA9539_U2: 0x77 // 1110 1HH[R/W]
++ * PCA9539_U3: 0x74 // 1110 1LL[R/W]
++ * PCA9538_U4: 0x70 // 1110 0LL[R/W]
++ * EXPORT_SYMBOL(tcc_pca953x_read);
++ * EXPORT_SYMBOL(tcc_pca953x_write);
++ * EXPORT_SYMBOL(tcc_pca953x_setup);
++ * ====================================
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <mach/tcc_pca953x.h>
++
++
++static unsigned short probe_i2c[] = {0, PCA9539_U2_SLAVE_ADDR, I2C_CLIENT_END}; /* { i2c_num, i2c_addr } */
++static unsigned short dummy[] = {I2C_CLIENT_END};
++
++static struct i2c_client_address_data addr_data = {
++ .normal_i2c = dummy,
++ .probe = probe_i2c,
++ .ignore = dummy,
++};
++
++static struct i2c_driver pca953x_i2c_driver;
++struct i2c_client *pca953x_i2c_client;
++//EXPORT_SYMBOL(pca953x_i2c_client);
++
++static int pca953x_i2c_probe(struct i2c_adapter *adap, int addr, int kind)
++{
++ struct i2c_client *i2c;
++
++ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
++ if (!i2c)
++ return -ENOMEM;
++
++ strcpy(i2c->name, "PCA953X");
++ i2c->flags = 0;
++ i2c->addr = addr;
++ i2c->adapter = adap;
++ i2c->driver = &pca953x_i2c_driver;
++
++ pca953x_i2c_client = i2c;
++
++ return i2c_attach_client(i2c);
++}
++
++static int pca953x_i2c_detach(struct i2c_client *client)
++{
++ i2c_detach_client(client);
++ kfree(pca953x_i2c_client);
++ return 0;
++}
++
++static int pca953x_i2c_attach(struct i2c_adapter *adap)
++{
++ return i2c_probe(adap, &addr_data, pca953x_i2c_probe);
++}
++
++static struct i2c_driver pca953x_i2c_driver = {
++ .driver = {
++ .name = "PCA953X",
++ .owner = THIS_MODULE,
++ },
++ .id = 1,
++ .attach_adapter = pca953x_i2c_attach,
++ .detach_client = pca953x_i2c_detach,
++};
++
++static int __init pca953x_i2c_init(void)
++{
++ return i2c_add_driver(&pca953x_i2c_driver);
++}
++
++static void __exit pca953x_i2c_exit(void)
++{
++ i2c_del_driver(&pca953x_i2c_driver);
++}
++module_init(pca953x_i2c_init);
++module_exit(pca953x_i2c_exit);
++
++MODULE_AUTHOR("Telechips Inc. SYS4-3 linux@telechips.com");
++MODULE_DESCRIPTION("PCA953x I2C driver");
++MODULE_LICENSE("GPL");
++
++/*------------------------------------------------------------------------
++ * PCA953X Control APIs
++ *
++ *------------------------------------------------------------------------
++ */
++int tcc_pca953x_read(int slave, unsigned char cmd, unsigned char *rd_buf)
++{
++ struct i2c_adapter *adap = pca953x_i2c_client->adapter;
++ struct i2c_msg msgs[2];
++ int ret;
++
++ /* write port_nr */
++ msgs[0].addr = slave;
++ msgs[0].flags = pca953x_i2c_client->flags & I2C_M_TEN;
++ msgs[0].len = 1;
++ msgs[0].buf = &cmd;
++
++ /* read port */
++ msgs[1].addr = slave;
++ msgs[1].flags = pca953x_i2c_client->flags & I2C_M_TEN;
++ msgs[1].flags |= I2C_M_RD;
++ msgs[1].len = 1;
++ msgs[1].buf = rd_buf;
++
++ ret = i2c_transfer(adap, msgs, 2);
++ if (ret != 1) {
++ return -1;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(tcc_pca953x_read);
++
++int tcc_pca953x_write(int slave, const unsigned char *wr_buf, int count)
++{
++ struct i2c_adapter *adap = pca953x_i2c_client->adapter;
++ struct i2c_msg msgs;
++ int ret;
++
++ msgs.addr = slave;
++ msgs.flags = pca953x_i2c_client->flags & I2C_M_TEN;
++ msgs.len = count;
++ msgs.buf = (__u8 *)wr_buf;
++ ret = i2c_transfer(adap, &msgs, 1);
++ if (ret != 1) {
++ return -1;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(tcc_pca953x_write);
++
++int tcc_pca953x_setup(int slave, int name, int direction, int value, int mode)
++{
++#if 0 /* comment by csduan */
++ int ret = 0, port_nr = 0, port[2], conf[2];
++ unsigned char buf[2];
++
++ switch (slave) {
++ case PCA9539_U2_SLAVE_ADDR:
++ port_nr = 2;
++ port[0] = direction ? PCA9539_INPUT_0 : PCA9539_OUTPUT_0;
++ port[1] = direction ? PCA9539_INPUT_1 : PCA9539_OUTPUT_1;
++ conf[0] = PCA9539_DIRECTION_0;
++ conf[1] = PCA9539_DIRECTION_1;
++ break;
++
++ case PCA9539_U3_SLAVE_ADDR:
++ port_nr = 2;
++ port[0] = direction ? PCA9539_INPUT_0 : PCA9539_OUTPUT_0;
++ port[1] = direction ? PCA9539_INPUT_1 : PCA9539_OUTPUT_1;
++ conf[0] = PCA9539_DIRECTION_0;
++ conf[1] = PCA9539_DIRECTION_1;
++ break;
++
++ case PCA9538_U4_SLAVE_ADDR:
++ port_nr = 1;
++ port[0] = direction ? PCA9538_INPUT_0 : PCA9538_OUTPUT_0;
++ conf[0] = PCA9538_DIRECTION_0;
++ break;
++
++ default:
++ break;
++ }
++
++ /*
++ * GET_VALUE is read only
++ */
++ if (GET_VALUE == mode) {
++ ret |= tcc_pca953x_read(slave, port[0], &buf[0]);
++ if (port_nr == 2) {
++ ret |= tcc_pca953x_read(slave, port[1], &buf[1]);
++ } else {
++ buf[1] = 0;
++ }
++
++ if (ret) ret = -1;
++ else ret = ((buf[1] << 8) | buf[0]) & 0x0000ffff;
++ return ret;
++ }
++
++ /*
++ * What port number?
++ */
++ if (name >= Hw0 && name <= Hw7) {
++ port_nr = 0;
++ } else if (name >= Hw8 && name <= Hw15) {
++ port_nr = 1;
++ name >>= 8;
++ } else {
++ return -1;
++ }
++
++ /*
++ * Set direction
++ */
++ if (SET_DIRECTION & mode) {
++ tcc_pca953x_read(slave, conf[port_nr], &buf[0]);
++ if (INPUT == direction) {
++ buf[1] = buf[0] | name;
++ } else if (OUTPUT == direction) {
++ buf[1] = buf[0] & ~name;
++ } else {
++ return -1;
++ }
++
++ buf[0] = conf[port_nr];
++ ret = tcc_pca953x_write(slave, &buf[0], 2);
++ if (ret == -1)
++ return -1;
++ }
++
++ /*
++ * Set value
++ */
++ if (SET_VALUE & mode) {
++ tcc_pca953x_read(slave, port[port_nr], &buf[0]);
++ if (HIGH == value) {
++ buf[1] = buf[0] | name;
++ } else if (LOW == value) {
++ buf[1] = buf[0] & ~name;
++ } else {
++ return -1;
++ }
++
++ buf[0] = port[port_nr];
++ tcc_pca953x_write(slave, &buf[0], 2);
++ if (ret == -1)
++ return -1;
++ }
++#endif /* comment by csduan */
++
++ return 0;
++}
++EXPORT_SYMBOL(tcc_pca953x_setup);
++
+diff --git a/drivers/i2c/chips/tcc_wm8731.c b/drivers/i2c/chips/tcc_wm8731.c
+new file mode 100644
+index 0000000..1fb8ef4
+--- /dev/null
++++ b/drivers/i2c/chips/tcc_wm8731.c
+@@ -0,0 +1,99 @@
++/*
++ * linux/drivers/i2c/chips/wm8731.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 21th March, 2009
++ * Description: Tcc250 Driver
++ *
++ * Copyright (c) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * ====================================
++ * Description
++ * -----------
++ * Slave chip: WM8731
++ * Slave address: 0x1a
++ * EXPORT_SYMBOL(wm8731_i2c_client)
++ * ====================================
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/i2c.h>
++
++#define WM8731_SLAVE_ADDR 0x1a
++static unsigned short probe_i2c[] = {0, WM8731_SLAVE_ADDR, I2C_CLIENT_END}; /* { i2c_num, i2c_addr } */
++static unsigned short dummy[] = {I2C_CLIENT_END};
++
++static struct i2c_client_address_data addr_data = {
++ .normal_i2c = dummy,
++ .probe = probe_i2c,
++ .ignore = dummy,
++};
++
++static struct i2c_driver wm8731_i2c_driver;
++struct i2c_client *wm8731_i2c_client;
++EXPORT_SYMBOL(wm8731_i2c_client);
++
++static int wm8731_i2c_probe(struct i2c_adapter *adap, int addr, int kind)
++{
++ struct i2c_client *i2c;
++
++ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
++ if (!i2c)
++ return -ENOMEM;
++
++ strcpy(i2c->name, "WM8731");
++ i2c->flags = 0;
++ i2c->addr = addr;
++ i2c->adapter = adap;
++ i2c->driver = &wm8731_i2c_driver;
++
++ wm8731_i2c_client = i2c;
++
++ return i2c_attach_client(i2c);
++}
++
++static int wm8731_i2c_detach(struct i2c_client *client)
++{
++ i2c_detach_client(client);
++ kfree(wm8731_i2c_client);
++ return 0;
++}
++
++static int wm8731_i2c_attach(struct i2c_adapter *adap)
++{
++ return i2c_probe(adap, &addr_data, wm8731_i2c_probe);
++}
++
++static struct i2c_driver wm8731_i2c_driver = {
++ .driver = {
++ .name = "WM8731",
++ .owner = THIS_MODULE,
++ },
++ .id = I2C_DRIVERID_WM8731,
++ .attach_adapter = wm8731_i2c_attach,
++ .detach_client = wm8731_i2c_detach,
++};
++
++static int __init wm8731_i2c_init(void)
++{
++ return i2c_add_driver(&wm8731_i2c_driver);
++}
++
++static void __exit wm8731_i2c_exit(void)
++{
++ i2c_del_driver(&wm8731_i2c_driver);
++}
++
++module_init(wm8731_i2c_init);
++module_exit(wm8731_i2c_exit);
++
++MODULE_AUTHOR("Telechips Inc. SYS4-3 linux@telechips.com");
++MODULE_DESCRIPTION("WM8731 I2C driver");
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
+index c6a63f4..5053947 100644
+--- a/drivers/i2c/i2c-core.c
++++ b/drivers/i2c/i2c-core.c
+@@ -1081,6 +1081,9 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
+ msg.flags = client->flags & I2C_M_TEN;
+ msg.len = count;
+ msg.buf = (char *)buf;
++ /* for TCC DIBCOM module */
++ msg.flags |= (client->flags & I2C_M_DIBCOM_MODE);
++ msg.flags |= (client->flags & I2C_M_DIBCOM_WR_RD);
+
+ ret = i2c_transfer(adap, &msg, 1);
+
+@@ -1109,6 +1112,8 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
+ msg.flags |= I2C_M_RD;
+ msg.len = count;
+ msg.buf = buf;
++ /* for TCC DIBCOM module */
++ msg.flags |= (client->flags & I2C_M_DIBCOM_MODE);
+
+ ret = i2c_transfer(adap, &msg, 1);
+
+diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
+index c171988..ee2a828 100644
+--- a/drivers/i2c/i2c-dev.c
++++ b/drivers/i2c/i2c-dev.c
+@@ -179,6 +179,9 @@ static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t c
+ iminor(file->f_path.dentry->d_inode), count);
+
+ ret = i2c_master_send(client,tmp,count);
++ /* for TCC DIBCOM module */
++ if (client->flags & I2C_M_DIBCOM_WR_RD)
++ client->flags &= ~I2C_M_DIBCOM_WR_RD;
+ kfree(tmp);
+ return ret;
+ }
+@@ -378,6 +381,8 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ switch ( cmd ) {
+ case I2C_SLAVE:
+ case I2C_SLAVE_FORCE:
++ /* for TCC DIBCOM module */
++ case I2C_SLAVE_DIBCOM:
+ /* NOTE: devices set up to work with "new style" drivers
+ * can't use I2C_SLAVE, even when the device node is not
+ * bound to a driver. Only I2C_SLAVE_FORCE will work.
+@@ -395,7 +400,18 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ return -EBUSY;
+ /* REVISIT: address could become busy later */
+ client->addr = arg;
++
++ /* for TCC DIBCOM module */
++ if (cmd == I2C_SLAVE_DIBCOM)
++ client->flags |= I2C_M_DIBCOM_MODE;
++
+ return 0;
++
++ /* for TCC DIBCOM module */
++ case I2C_DIBCOM_WR_RD:
++ client->flags |= I2C_M_DIBCOM_WR_RD;
++ break;
++
+ case I2C_TENBIT:
+ if (arg)
+ client->flags |= I2C_M_TEN;
+diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
+index e6857e0..6f770d9 100644
+--- a/drivers/ide/Kconfig
++++ b/drivers/ide/Kconfig
+@@ -727,6 +727,17 @@ config IDE_ARM
+ depends on ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
+ default y
+
++config BLK_DEV_IDE_TCC89X
++ bool
++
++config BLK_DEV_PATA_TCC89X
++ bool "PATA for TCC89x"
++ select BLK_DEV_IDE_TCC89X
++
++#config BLK_DEV_SATA_TCC89X
++# bool "SATA for TCC89x"
++# select BLK_DEV_IDE_TCC89X
++
+ config BLK_DEV_IDE_ICSIDE
+ tristate "ICS IDE interface support"
+ depends on ARM && ARCH_ACORN
+diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
+index 7818d40..456b8fd 100644
+--- a/drivers/ide/Makefile
++++ b/drivers/ide/Makefile
+@@ -20,6 +20,8 @@ obj-$(CONFIG_IDE) += ide-core.o
+
+ obj-$(CONFIG_IDE_ARM) += ide_arm.o
+
++obj-$(CONFIG_BLK_DEV_IDE_TCC89X) += tcc89x_ide.o
++
+ obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o
+ obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o
+ obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o
+diff --git a/drivers/ide/tcc89x_ide.c b/drivers/ide/tcc89x_ide.c
+new file mode 100644
+index 0000000..c84d8b2
+--- /dev/null
++++ b/drivers/ide/tcc89x_ide.c
+@@ -0,0 +1,329 @@
++/*
++ * ARM default IDE host driver
++ *
++ * Copyright (C) 2004 Bartlomiej Zolnierkiewicz
++ * Based on code by: Russell King, Ian Molton and Alexander Schulz.
++ *
++ * May be copied or modified under the terms of the GNU General Public License.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/ide.h>
++#include <linux/delay.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include <bsp.h>
++#include <mach/hardware.h>
++#include <mach/irqs.h>
++#include <mach/tca_ckc.h>
++#include <mach/tcc_pca953x.h>
++
++// Bit 0 CDR7 Access
++#define CDR7_ERR 0
++
++#define DBG_PRINTF printk
++
++#ifdef CONFIG_BLK_DEV_SATA_TCC89X
++static void wait_for_bits(volatile PSATA pSata, int ret_on_rst, int timeout_val, int exp_val, int mask, int *matched)
++{
++ int timeout_cnt = 0, error = 0;
++ int failed;
++ int rdata = 0, i = 0;
++ int phy_sig_det_w = 1;
++
++ //DBG_PRINTF("wait_for_bits: Waiting for register at address 0x%x,to have value=0x%x", addr, exp_val );
++
++ *matched = 0;
++
++ // wait for busy, and Drq to be cleared.
++ // or timeout or reset, if checking reset
++ while ((timeout_cnt < timeout_val)
++ && !*matched && (error == 0)
++ && !(!phy_sig_det_w && ret_on_rst))
++ {
++ rdata = pSata->CDR7;
++
++ //DBG_PRINTF ("!!!!!!actual rdata='0x%x' read at time=%d", rdata, timeout_cnt);
++ failed = 0;
++
++ for (i = 0; i <= 31; i = i + 1) {
++ if ((((mask >> i) & 1) == 1) && (((rdata >> i) & 1) != ((exp_val >> i) & 1))) {
++ // joo DBG_PRINTF("Cmp Fail bit %d: rdata='0x%x' exp_val='0x%x'", i, (rdata>>i)&1, (exp_val>>i)&1);
++ failed = 1;
++ }
++ }
++
++ if (failed == 0) {
++ *matched = 1;
++ }
++
++ // After bits matched, check for error
++ if (*matched) {
++ if (((rdata & 0xff) != 0x7f) // we're not in Power on reset
++ && (((rdata >> CDR7_ERR) & 1) == 1)) // we do have error bit set
++ {
++ // joo DBG_PRINTF("wait_for_bits: detected err, bit 0 of reg at address 0x%x is set", addr);
++ error = 1;
++ }
++ } else {
++ timeout_cnt = timeout_cnt + 1;
++ }
++
++ } // while ((timeout_cnt < timeout_val) &&...
++
++ if ((ret_on_rst == 1) && !phy_sig_det_w) {
++ DBG_PRINTF("wait_for_bits: detected a Non recov err, while waiting for bits on reg 0x%x\n",
++ 0x1C);
++ } else if (timeout_cnt >= timeout_val) {
++ DBG_PRINTF("wait_for_bits: Timeout waiting reg at address '0x%x' to equal '0x%x'\n",
++ 0x1C, exp_val );
++ } else {
++ DBG_PRINTF("wait_for_bits: Got register at address '0x%x' reg expected_value='0x%x', actual='0x%x'\n",
++ 0x1C, exp_val, rdata);
++ }
++}
++
++static void wait_for_bsydrq(volatile PSATA pSata, int ret_on_rst, int timeout_val, int *matched)
++{
++ int exp_val = 0;
++ int mask = 0x88;
++
++ wait_for_bits(pSata, ret_on_rst, timeout_val, exp_val, mask, matched);
++}
++
++static int prog_host_speed(volatile PSATA pSata, int speed, int *spd_ok)
++{
++ int spd_select;
++ int reset;
++ int reg_data;
++ //int i;
++ int ret_on_rst;
++ int timeout_val;
++ int matched;
++
++ // Initialize
++ ret_on_rst = 0;
++ //timeout_val = 1000000; // Must Be Huge For Speed Negotiation
++ timeout_val = 2000000; // Must Be Huge For Speed Negotiation
++ //timeout_val = 0x7FFFFFFF; // Must Be Huge For Speed Negotiation
++
++ // DBG_PRINTF("prog_host_speed: Setting Host Gen Mode = %d", speed);
++
++ // Set speed
++ spd_select = (speed == 2) ? 0x2 : 0x1;
++
++ // Need to wait a hundred clocks of slowest
++ mdelay(1000);
++
++ // Reset Device with correct speed
++ reset = 1;
++ reg_data = (spd_select << 4) | reset;
++
++ // Write SCR2 with speed and reset
++ pSata->SCR2 = reg_data;
++
++ // Need to wait a few clocks of slowest
++ mdelay(100);
++
++ // Set normal operation & correct speed
++ reset = 0;
++ reg_data = spd_select << 4 | reset;
++ //HwSATA->nSCR2 = reg_data;
++ pSata->SCR2 = reg_data;
++
++ // Wait for BSY & DRQ to be cleared
++ wait_for_bsydrq(pSata, ret_on_rst, timeout_val, &matched);
++
++ if (matched) {
++ DBG_PRINTF("prog_host_speed: Host Speed selected [speed:%d]\n", speed);
++ *spd_ok = 1;
++ return 0;
++ } else {
++ printk("prog_host_speed: ERROR - Host Speed timed out waiting for speed change! [speed:%d]\n", speed);
++ *spd_ok = 0;
++ }
++ return -1;
++}
++
++static void tca_sata_port_config(void)
++{
++ volatile PPIC pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++
++ BITSET(pPIC->SEL1, 1 << (INT_SATA - 32));
++ BITSET(pPIC->MODE1, 1 << (INT_SATA - 32));
++}
++
++static int tcc_sata_hw_init(hw_regs_t *p_hw, unsigned long sata_base)
++{
++ int spd_ok = 0, i = 0;
++ volatile PSATA pSata = (volatile PSATA)sata_base;
++
++ memset(p_hw, 0, sizeof(hw_regs_t));
++
++ for (i = 0; i <= 7; i++) {
++ p_hw->io_ports_array[i] = sata_base + (i * 4);
++ }
++ p_hw->io_ports.ctl_addr = sata_base + 0x20;
++ p_hw->irq = INT_SATA;
++
++ if (prog_host_speed(pSata, 2, &spd_ok) == 0) {
++ return 0;
++ } else if (prog_host_speed(pSata, 1, &spd_ok) == 0) {
++ return 0;
++ }
++ return -1;
++}
++#endif
++
++#ifdef CONFIG_BLK_DEV_PATA_TCC89X
++static void tca_pata_pio_config(unsigned long base)
++{
++ volatile PIDE pIDE = NULL;
++ unsigned bus_total_cycle, setup, pw, hold;
++ unsigned int bus_clk = 0;
++
++ pIDE = (volatile PIDE)base;
++
++ bus_clk = tca_ckc_getbus();
++ printk("bus_clk : BUS-%d\n", bus_clk);
++
++ bus_total_cycle = 120 * bus_clk / 10000000L;
++ if (bus_total_cycle <= 10) {
++ setup = 2; // 3 cycle
++ pw = 5; // 6 cycle
++ hold = 0; // 1 cycle
++ } else {
++ bus_total_cycle = bus_total_cycle - 2; // assume Hold = 2
++
++ hold = 1; // 1 means 2 cycles
++ pw = bus_total_cycle * 75 / 100 - 1; // PW = 75% of remain cycles
++ setup = bus_total_cycle - pw - 1; // Stp = 25% of remain cycles
++ }
++
++ printk("@@@ setup[%d], pw[%d]. hold[%d]\n", setup, pw, hold);
++
++ /* PIO mode setting */
++ //h->regs->PIOCTRL = (HwPIOCTRL_SYNC_2 | (setup << 13) | (pw << 7) | (hold << 1));
++ pIDE->PIOCTRL = (Hw22 | (setup << 13) | (pw << 7) | (hold << 1) | Hw0);
++}
++
++static void tca_pata_port_config(void)
++{
++ volatile PGPION pGPIO_F = (volatile PGPION)tcc_p2v(HwGPIOF_BASE);
++ volatile PGPION pGPIO_B = (volatile PGPION)tcc_p2v(HwGPIOB_BASE);
++ volatile PGPION pGPIO_A = (volatile PGPION)tcc_p2v(HwGPIOA_BASE);
++ volatile PGPIO pGPIO = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
++ volatile PPIC pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++
++ /* HDD port config */
++ pGPIO_F->GPFN0 = 0x33333333;
++ pGPIO_F->GPFN1 = 0x33333333;
++ pGPIO_F->GPFN2 = 0x33333333;
++ BITCLR(pGPIO_F->GPFN3, 0xFF);
++ BITSET(pGPIO_F->GPFN3, 0x33);
++
++ /* RESET port config (GPIOB_26) */
++ BITCLR(pGPIO_B->GPFN3, 0xF00);
++ BITSET(pGPIO_B->GPEN, Hw26);
++
++ /* Externel intr GPIOA_12 config */
++ BITCLR(pGPIO_A->GPFN1, 0xF0000);
++ //BITCLR(pGPIO_A->GPEN, Hw12);
++ //BITCLR(pGPIO_A->GPDAT, Hw12);
++ BITCLR(pGPIO_A->GPPD0, Hw24);
++ BITSET(pGPIO_A->GPPD0, Hw25);
++
++ /* EINT setting (GPIOA_12: EINT5) */
++ BITCLR(pGPIO->EINTSEL1, 0x3F << 8);
++ BITSET(pGPIO->EINTSEL1, 12 << 8);
++
++ BITSET(pPIC->SEL0, Hw8);
++ BITCLR(pPIC->POL0, Hw8);
++ BITSET(pPIC->MODE0, Hw8);
++}
++
++static void tca_pata_hw_reset(int deley_ms)
++{
++ volatile PGPION pGPIO_B = (volatile PGPION)tcc_p2v(HwGPIOB_BASE);
++
++ BITSET(pGPIO_B->GPDAT, Hw26);
++ mdelay(1);
++ BITCLR(pGPIO_B->GPDAT, Hw26);
++ mdelay(deley_ms);
++}
++
++static int tcc_pata_hw_init(hw_regs_t *p_hw, unsigned long pata_base)
++{
++ int i;
++ if (p_hw) {
++ tca_pata_hw_reset(500);
++ memset(p_hw, 0, sizeof(hw_regs_t));
++
++ for (i = 0; i <= 7; i++) {
++ p_hw->io_ports_array[i] = pata_base + (i * 4);
++ }
++ p_hw->io_ports.ctl_addr = pata_base + 0x20 + (6 * 4);
++
++ p_hw->irq = INT_EI5;
++ //p_hw->chipset = ide_generic;
++
++ return 0;
++ }
++ return -1;
++}
++#endif
++
++static int __init tcc_ide_init(void)
++{
++ hw_regs_t *hws[] = { NULL, NULL, NULL, NULL };
++ int hw_pos = 0;
++
++#ifdef CONFIG_BLK_DEV_PATA_TCC89X
++ unsigned long pata_base = (unsigned long)tcc_p2v(HwIDE_BASE);
++ hw_regs_t pata_hw;
++#endif
++
++#ifdef CONFIG_BLK_DEV_SATA_TCC89X
++ PPMU p_pmu = (PPMU)tcc_p2v(HwPMU_BASE);
++ unsigned long sata_base = (unsigned long)tcc_p2v(HwSATA_BASE);
++ hw_regs_t sata_hw;
++#endif
++
++ /* PATA */
++#ifdef CONFIG_BLK_DEV_PATA_TCC89X
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, ATAPI_ON, OUTPUT, HIGH, SET_DIRECTION | SET_VALUE);
++ tca_ckc_setiobus(RB_IDECONTROLLER, 1);
++
++ tca_pata_pio_config(pata_base);
++ tca_pata_port_config();
++ if (tcc_pata_hw_init(&pata_hw, pata_base) == 0) {
++ hws[hw_pos] = &pata_hw;
++ hw_pos++;
++ }
++#endif
++
++ /* SATA */
++#ifdef CONFIG_BLK_DEV_SATA_TCC89X
++ BITCLR(p_pmu->PWROFF, Hw4); // SATA Phy enable
++ tca_ckc_setiobus(RB_SATAHCONTROLLER, 1);
++
++ tca_sata_port_config();
++ if (tcc_sata_hw_init(&sata_hw, sata_base) == 0) {
++ hws[hw_pos] = &sata_hw;
++ hw_pos++;
++ }
++#endif
++
++ return ide_host_add(NULL, hws, NULL);
++}
++
++module_init(tcc_ide_init);
++
++MODULE_AUTHOR("linux@telechips.com");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("TCC89X IDE driver");
++
+diff --git a/drivers/input/input.c b/drivers/input/input.c
+index c13ced3..350fb9c 100644
+--- a/drivers/input/input.c
++++ b/drivers/input/input.c
+@@ -252,6 +252,11 @@ static void input_handle_event(struct input_dev *dev,
+ input_pass_event(dev, type, code, value);
+ }
+
++void press_button(struct input_dev *dev,unsigned int type, unsigned int code, int value)
++{
++ input_pass_event(dev, type, code, value);
++}
++EXPORT_SYMBOL(press_button);
+ /**
+ * input_event() - report new input event
+ * @dev: device that generated the event
+diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
+index 05f3f43..cb455b0 100644
+--- a/drivers/input/keyboard/gpio_keys.c
++++ b/drivers/input/keyboard/gpio_keys.c
+@@ -59,7 +59,7 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
+ struct gpio_button_data *bdata = dev_id;
+ struct gpio_keys_button *button = bdata->button;
+
+- BUG_ON(irq != gpio_to_irq(button->gpio));
++// BUG_ON(irq != gpio_to_irq(button->gpio));
+
+ if (button->debounce_interval)
+ mod_timer(&bdata->timer,
+@@ -70,6 +70,9 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
+ return IRQ_HANDLED;
+ }
+
++struct input_dev *touchdev;
++EXPORT_SYMBOL(touchdev);
++
+ static int __devinit gpio_keys_probe(struct platform_device *pdev)
+ {
+ struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+@@ -111,6 +114,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
+ setup_timer(&bdata->timer,
+ gpio_check_button, (unsigned long)bdata);
+
++ touchdev = bdata->input;
+ error = gpio_request(button->gpio, button->desc ?: "gpio_keys");
+ if (error < 0) {
+ pr_err("gpio-keys: failed to request GPIO %d,"
+@@ -267,7 +271,7 @@ static void __exit gpio_keys_exit(void)
+ platform_driver_unregister(&gpio_keys_device_driver);
+ }
+
+-module_init(gpio_keys_init);
++late_initcall(gpio_keys_init);
+ module_exit(gpio_keys_exit);
+
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
+index 3d1ab8f..7877b93 100644
+--- a/drivers/input/touchscreen/Kconfig
++++ b/drivers/input/touchscreen/Kconfig
+@@ -376,4 +376,35 @@ config TOUCHSCREEN_TOUCHIT213
+ To compile this driver as a module, choose M here: the
+ module will be called touchit213.
+
++config TOUCHSCREEN_TCCTS
++ tristate "Telechips adc touchscreen driver"
++ select TCC_TS_CORE
++ depends on ARCH_TCC
++ default y
++ help
++ Say Y here if you have a touchscreen interface using the
++ i2c device.
++
++choice
++ prompt "LCD_TYPE"
++ depends on ARCH_TCC
++ default LCD10
++ help
++ select LCD TYPE
++config LCD01
++ bool "LCD Type 0.1"
++ help
++ select LCD 0.1 TYPE
++config LCD11
++ bool "LCD Type 1.1"
++ help
++ select LCD 1.1 TYPE
++config LCD10
++ bool "LCD Type 1.0"
++ help
++ select LCD 1.0 TYPE
++endchoice
++
++
++
+ endif
+diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
+index 15cf290..9b8e190 100644
+--- a/drivers/input/touchscreen/Makefile
++++ b/drivers/input/touchscreen/Makefile
+@@ -6,6 +6,10 @@
+
+ wm97xx-ts-y := wm97xx-core.o
+
++#ifeq ($(CONFIG_ARCH_TCC),y)
++#$(shell ln -fsn $(CONFIG_TCC_STRING) $(srctree)/drivers/input/touchscreen/tcc)
++#endif
++obj-$(CONFIG_TOUCHSCREEN_TCCTS) += tcc_ts.o
+ obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
+ obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
+ obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
+diff --git a/drivers/input/touchscreen/tcc_ts.c b/drivers/input/touchscreen/tcc_ts.c
+new file mode 100644
+index 0000000..4bb7e70
+--- /dev/null
++++ b/drivers/input/touchscreen/tcc_ts.c
+@@ -0,0 +1,685 @@
++/* linux/drivers/input/touchscreen/tcc-ts.c
++ *
++ * $Id: tcc-ts.c,v 1.3 2007/06/20 04:02:28 ihlee215 Exp $
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/input.h>
++#include <linux/init.h>
++#include <linux/serio.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/sched.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <mach/hardware.h>
++
++#include <bsp.h>
++#include <mach/irqs.h>
++#include <mach/TCC89x_Structures.h>
++#define CONFIG_TOUCHSCREEN_TCC_DEBUG
++//#undef CONFIG_TOUCHSCREEN_TCC_DEBUG
++
++/* For ts->dev.id.version */
++#define TCC_TSVERSION 0x0001
++#define IRQ_NO INT_EI2
++
++#define ECFLG_END (1<<15)
++#define ENABLE_START_EN (1<<0)
++
++
++// ADCTSC
++#define UD_SEN_DOWN (0<<8)
++#define YM_SEN_EN (1<<7)
++#define YP_SEN_DIS (1<<6)
++#define XM_SEN_DIS (0<<5)
++#define XP_SEN_DIS (1<<4)
++#define PULL_UP_EN (0<<3)
++#define AUTO_PST_DIS (0<<2)
++#define AUTO_PST_EN (1<<2)
++#define XY_PST_WAITINT (3<<0)
++#define ADCTSC_AUTO_ADC4 AUTO_PST_EN
++#define ADCTSC_AUTO_ADC5 AUTO_PST_DIS
++
++// ADCCON
++#define ADCCON_ECFLG (1<<15)
++#define ADCCON_SELMUX(x) (((x)&0x7)<<3)
++#define ADCCON_ENABLE_START (1<<0)
++
++#define TOUCH_COLLECT_NR 16 // (TOUCH_COLLECT_NR-TOUCH_VALID_VALUE) must be even
++#define TOUCH_VALID_VALUE 2 // among COLLECT_NR samples, OK should be over
++#define MAX_X 6000
++#define MIN_X 0
++#define MAX_Y 6000
++#define MIN_Y 0
++
++#define PEN_DOWN 1
++#define PEN_RELEASE 0
++
++#define ADCTSC_WAIT_PENDOWN (UD_SEN_DOWN |YM_SEN_EN|YP_SEN_DIS|XM_SEN_DIS|XP_SEN_DIS|PULL_UP_EN|AUTO_PST_DIS|XY_PST_WAITINT)
++
++#define ADCCON (0x00)
++#define ADCTSC (0x04)
++#define ADCDLY (0x08)
++#define ADCDAT0 (0x0C)
++#define ADCDAT1 (0x10)
++#define ADCUPDN (0x14)
++#define ADCCLRINT (0x18)
++#define ADCCLRUPDN (0x20)
++
++#if 0
++//#define dbg(x...) printk(KERN_DEBUG "tcc uart: ");
++#define dbg printk
++#else /* no debug */
++#define dbg(x...) do {} while(0)
++#endif
++
++
++
++/*
++ * Definitions & global arrays.
++ */
++static char *tcc_ts_name = "tcc-ts";
++
++static struct timer_list ts_timer;
++
++/*
++ * Per-touchscreen data.
++ */
++struct tcc_ts {
++ struct input_dev *dev;
++ long x;
++ long y;
++ char phys[32];
++ int pen_status, opened, running, valid;
++ struct mutex mutex;
++ struct work_struct work_q;
++};
++
++static struct tcc_ts *ts;
++static void __iomem *ts_base;
++
++#define D_XPDATA_MASK12(n) ((n)&0xfff)
++#define D_YPDATA_MASK12(n) ((n)&0xfff)
++#define ENABLE_START_EN (1<<0)
++
++#define ADC_DELAY(n) ((n+1)&0xffff)
++#define RESSEL_12BIT (1<<16)
++#define PRESCALER_EN (1<<14)
++#define PRESCALER_VAL(n) (((n)&0xff)<<6)
++#define CLEAR_ADC_INT (0xff)
++#define CLEAR_ADCWK_INT (0xff)
++
++static unsigned long data_for_ADCCON;
++static unsigned long data_for_ADCTSC;
++
++static void tcc_adc_save_SFR_on_ADC(void)
++{
++ data_for_ADCCON = readl(ts_base+ADCCON);
++ data_for_ADCTSC = readl(ts_base+ADCTSC);
++}
++
++static void tcc_adc_restore_SFR_on_ADC(void)
++{
++ writel(data_for_ADCCON, ts_base+ADCCON);
++ writel(data_for_ADCTSC, ts_base+ADCTSC);
++}
++
++unsigned int tcc_adc_value(unsigned int tcc_adc_port)
++{
++ unsigned int adc_return;
++ unsigned long data0;
++ unsigned long data1;
++
++ if (ts_base == NULL)
++ return 0;
++
++ if(ts->running)
++ return 0;
++
++ disable_irq(IRQ_NO);
++
++ if (timer_pending(&ts_timer) || ts->running)
++ goto out;
++
++ if(ADCTSC_WAIT_PENDOWN != readl(ts_base+ADCTSC))
++ goto out;
++
++ del_timer(&ts_timer);
++
++ tcc_adc_save_SFR_on_ADC();
++
++ writel(0x58, ts_base+ADCTSC);
++
++ writel((readl(ts_base+ADCCON)&(~(Hw5|Hw4|Hw3)))|ADCCON_SELMUX(tcc_adc_port), ts_base+ADCCON);
++ udelay(10);
++
++ writel(readl(ts_base+ADCCON)|ADCCON_ENABLE_START, ts_base+ADCCON);
++
++ do {
++ data0 = readl(ts_base+ADCCON);
++ writel(CLEAR_ADC_INT, ts_base + ADCCLRINT);
++ writel(CLEAR_ADCWK_INT, ts_base + ADCCLRUPDN);
++ } while(!(data0 & ADCCON_ECFLG));
++
++ data1 = readl(ts_base+ADCDAT0);
++
++ tcc_adc_restore_SFR_on_ADC();
++
++ adc_return = D_XPDATA_MASK12(data1);
++
++ enable_irq(IRQ_NO);
++
++ return adc_return;
++
++out:
++ enable_irq(IRQ_NO);
++ return 0;
++}
++EXPORT_SYMBOL(tcc_adc_value);
++
++int tea_tch_readadc_auto(int *x, int *y)
++{
++ writel(ADCTSC_AUTO_ADC4, ts_base + ADCTSC);
++ writel(readl(ts_base + ADCCON) | ENABLE_START_EN, ts_base + ADCCON);
++
++ while(readl(ts_base + ADCCON) & ENABLE_START_EN)
++ {
++ ndelay(1);
++ }
++ while (!(readl(ts_base + ADCCON) & ECFLG_END))
++ { // Wait for ADC Conversion Ended
++ ndelay(1);
++ }
++
++ *x = D_XPDATA_MASK12(readl(ts_base + ADCDAT0));
++ *y = D_YPDATA_MASK12(readl(ts_base + ADCDAT1));
++
++ writel(ADCTSC_AUTO_ADC5, ts_base + ADCTSC);
++
++ return 1;
++}
++
++#if 1
++int tea_tch_readadc_test(int *x, int *y)
++{
++
++ unsigned int tmp;
++ volatile PGPIO pGPIO = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
++
++////////////////read x
++ writel(Hw3|Hw0, ts_base + ADCTSC);
++
++ //g_pADCReg->ADCTSC = Hw3|Hw0;
++ //gpio setting - 30 high
++ BITCLR(pGPIO->GPEFN3 ,Hw32-Hw24);//gpio E31, E30 using GPIO Mode
++ BITSET(pGPIO->GPEEN, Hw32-Hw30);//gpio E31, E30 using GPIO Output Mode
++ BITSET(pGPIO->GPEDAT, Hw31); // E31 High
++ BITCLR(pGPIO->GPEDAT, Hw30); // E30 Low
++
++ tmp = readl(ts_base + ADCCON);
++ tmp &= ~(Hw5|Hw4|Hw3);
++ tmp |= (Hw5|Hw3);
++ writel(tmp, ts_base + ADCCON);
++ //BITCSET(readl(ts_base + ADCCON), Hw6-Hw3, Hw5|Hw3);
++
++ writel(readl(ts_base + ADCCON) | ENABLE_START_EN, ts_base + ADCCON);
++
++ //g_pADCReg->ADCCON |= ENABLE_START_EN; // ADC Conversion Start
++
++ while (!(readl(ts_base + ADCCON) & ECFLG_END));
++
++ //read x value
++ *x = D_XPDATA_MASK12(readl(ts_base + ADCDAT0));
++ BITCSET(pGPIO->GPEFN3 ,Hw32-Hw16, Hw28|Hw24|Hw20|Hw16);
++ writel(ADCTSC_AUTO_ADC5, ts_base + ADCTSC);
++
++
++////////////////read y
++ writel(Hw3|Hw1, ts_base + ADCTSC);
++ //gpio setting - 31,28 high
++ BITCLR(pGPIO->GPEFN3 ,Hw24-Hw16);//gpio E29, E28 using GPIO Mode
++ BITSET(pGPIO->GPEEN, Hw30-Hw28);//gpio E29, E28 using GPIO Output Mode
++ BITSET(pGPIO->GPEDAT, Hw29); //
++ BITCLR(pGPIO->GPEDAT, Hw28); //
++
++ tmp = readl(ts_base + ADCCON);
++ tmp &= ~(Hw5|Hw4|Hw3);
++ tmp |= (Hw5|Hw4|Hw3);
++ writel(tmp, ts_base + ADCCON);
++
++ //BITCSET(readl(ts_base + ADCCON),Hw6-Hw3, Hw5|Hw4|Hw3);
++
++ writel(readl(ts_base + ADCCON) | ENABLE_START_EN, ts_base + ADCCON);
++
++ while (!(readl(ts_base + ADCCON) & ECFLG_END));
++
++ //read y value
++ *y = D_YPDATA_MASK12(readl(ts_base + ADCDAT1));
++
++ writel(ADCTSC_AUTO_ADC5, ts_base + ADCTSC);
++ BITCSET(pGPIO->GPEFN3 ,Hw32-Hw16, Hw28|Hw24|Hw20|Hw16);
++
++
++ dbg("[TOUCH] RAW:(x=%d, y=%d)\r\n", *x, *y);
++ return 1;
++
++}
++#endif
++
++
++void tca_touchbubblesort(unsigned int Number[],unsigned int num)
++{
++ int i,j;
++ unsigned int temp;
++ for(i=0 ; i<(int)(num-1) ; i++)
++ {
++ for(j=i+1;j<(int)num;j++)
++ {
++ if(Number[i]>Number[j])
++ {
++ temp = Number[i];
++ Number[i] = Number[j];
++ Number[j] = temp;
++ }
++ }
++ }
++}
++
++
++int tca_getrawdata(int * x, int * y)
++{
++ unsigned int i;
++ unsigned int r_x[TOUCH_COLLECT_NR], r_y[TOUCH_COLLECT_NR];
++// unsigned int validcnt=0;
++// unsigned int index;
++
++ for(i = 0; i < 1; i ++)
++ {
++ int x, y;
++ tea_tch_readadc_test(&x, &y);
++ r_x[i]=x;
++ r_y[i]=y;
++// validcnt++;
++ }
++// tca_touchbubblesort(r_x,3);
++// tca_touchbubblesort(r_y,3);
++
++ *x = r_x[0];
++ *y = r_y[0];
++
++ if((*x <= MAX_X && *x >= MIN_X)&&(*y <= MAX_Y && *y >= MIN_Y))
++ {
++ return 0;
++ }
++ else
++ {
++ return -1;
++ }
++}
++
++
++void tca_tch_poweroff(void)
++{
++ writel(Hw0, ts_base + ADCCLRINT);
++ writel(Hw0, ts_base + ADCCLRUPDN);
++ writel(ADCTSC_WAIT_PENDOWN, ts_base + ADCTSC);
++}
++
++
++
++
++static inline void tcc_pen_release(struct tcc_ts* ts_data, struct input_dev *dev)
++{
++ if (ts_data->pen_status != PEN_RELEASE) {
++ ts_data->pen_status = PEN_RELEASE;
++
++ input_report_key(dev, BTN_TOUCH, PEN_RELEASE);
++ input_report_abs(ts->dev, ABS_PRESSURE, 0);
++ input_sync(dev);
++ /* wake_up_interruptible(&ts->wait_q); */
++ }
++ dbg("PEN UP\n");
++}
++
++static inline void tcc_pen_pressure(struct tcc_ts* ts_data, struct input_dev *dev)
++{
++ ts_data->pen_status = PEN_DOWN;
++
++ input_report_abs(dev, ABS_X, ts->x);
++ input_report_abs(dev, ABS_Y, ts->y);
++ input_report_key(dev, BTN_TOUCH, PEN_DOWN);
++ input_report_abs(ts->dev, ABS_PRESSURE, 1);
++ input_sync(dev);
++
++ dbg("PEN DOWN (%d : %d)\n", ts_data->x, ts_data->y);
++
++ /* wake_up_interruptible(&ts->wait_q); */
++}
++
++extern void press_button(struct input_dev *dev,unsigned int type, unsigned int code, int value);
++extern struct input_dev *touchdev;
++static inline void tcc_pen_backlighton(void) //send a right ctrl event to turn on the backlight
++{
++ press_button(touchdev,1,97,1);
++ press_button(touchdev,0,0,0);
++
++ press_button(touchdev,1,97,0);
++ press_button(touchdev,0,0,0);
++}
++#define ADCDAT0_XPDATA_MASK (0x03FF)
++#define ADCDAT1_YPDATA_MASK (0x03FF)
++
++int noneed_respond = 0;
++EXPORT_SYMBOL(noneed_respond);
++static void ts_fetch_thread(struct work_struct *work)
++{
++ struct tcc_ts* ts_data = container_of(work, struct tcc_ts, work_q);
++ struct input_dev *dev = ts->dev;
++ int flag, valid;
++ int updown;
++ unsigned long data0;
++ unsigned long data1;
++ dbg("%s\n", __func__);
++
++ ts_data->running = 1;
++
++ dbg("(work_q)disable_irq\n");
++ //disable_irq(IRQ_NO);
++
++ data0 = readl(ts_base + ADCDAT0);
++ data1 = readl(ts_base + ADCDAT1);
++
++ updown = (!(data0 & Hw15)) && (!(data1 & Hw15));
++
++ if(!updown){
++#if 0
++ tcc_pen_release(ts_data, dev);
++ ts_data->running = 0;
++ dbg("(work_q_1)enable_irq\n");
++ enable_irq(IRQ_NO);
++ } else {
++ tcc_pen_pressure(ts_data, dev);
++
++ ts_timer.expires = jiffies + 1;
++ add_timer(&ts_timer);
++
++#else
++ if(noneed_respond)
++ tcc_pen_backlighton();
++
++ noneed_respond = 0;
++ tcc_pen_release(ts_data, dev);
++ ts_data->running = 0;
++ dbg("(work_q_1)enable_irq\n");
++ enable_irq(IRQ_NO);
++ }else {
++ flag = tca_getrawdata((int *)&(ts_data->x),(int *)&(ts_data->y));
++ dbg(" (%d, %d)\n", ts_data->x, ts_data->y);
++ tca_tch_poweroff();
++
++ ndelay(1);
++
++ valid = ts_data->x | ts_data->y;
++
++ if ((flag == 0) && valid) {
++ if(noneed_respond == 0)
++ tcc_pen_pressure(ts_data, dev);
++ ts_timer.expires = jiffies + 1;
++ add_timer(&ts_timer);
++ } else {
++ tcc_pen_release(ts_data, dev);
++ ts_data->running = 0;
++ dbg("(work_q_2)enable_irq\n");
++ enable_irq(IRQ_NO);
++ }
++#endif
++ }
++}
++
++
++static irqreturn_t tcc_ts_interrupt(int irqno, void *param)
++{
++ //struct tcc_ts *ts_data = (struct tcc_ts *)param;
++ dbg("%s\n", __func__);
++
++ if (ts->running == 0) {
++ ts->running = 1;
++ dbg("(irq)disable_irq\n");
++ disable_irq(IRQ_NO);
++ ts_timer.expires = jiffies;
++ add_timer(&ts_timer);
++ }
++
++ return IRQ_HANDLED;
++
++}
++
++static void ts_timer_handler(unsigned long data)
++{
++ dbg("%s\n", __func__);
++ if(ts->opened){
++ if (schedule_work(&(ts->work_q)) == 0 ) {
++ dbg("cannot schedule work !!!\n");
++ ts->running = 0;
++ //dbg("(timer)enable_irq\n");
++ enable_irq(IRQ_NO);
++
++ }
++ }else {
++ //dbg("(timer)disable_irq\n");
++ disable_irq(IRQ_NO);
++ }
++}
++
++/*
++ * The functions for inserting/removing us as a module.
++ */
++static int __devinit tcc_ts_probe(struct platform_device *pdev)
++{
++ struct input_dev *input_dev;
++ //struct resource *res;
++ int err = -ENOMEM;
++
++ //PGPIO pGPIO = (GPIO *)&HwGPIO_BASE;
++ //PPIC pPIC = (PIC *)&HwPIC_BASE;
++ volatile PGPIO pGPIO = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
++ volatile PPIC pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++ dbg("%s: probe=%p\n", __func__, pdev);
++
++ /* Enable ADC clock */
++ tca_ckc_setperi(PERI_ADC,ENABLE,390000,PCDIRECTPLL3);
++ tca_ckc_setiobus(RB_TSADCCONTROLLER,1);
++
++ ts_base = (void __iomem *)tcc_p2v(HwTSADC_BASE);
++
++ if (ts_base == NULL) {
++ dbg("failed ioremap()\n");
++ return -ENOMEM;
++ }
++
++ // Set GPE28~GPE31 to touchscreen funtion
++ BITCSET(pGPIO->GPEFN3, Hw32-Hw16, (Hw28|Hw24|Hw20|Hw16));
++ // Set GPE28~GPE31 pull-up/down disabled
++ BITCLR(pGPIO->GPEPD1, Hw32-Hw25);
++
++ // Set GPE24~GPE25 to ADC function
++ BITCSET(pGPIO->GPEFN3, Hw8-Hw0, (Hw4|Hw0));
++ // Set GPE24~GPE25 pull-up/down disabled
++ BITCLR(pGPIO->GPEPD1, Hw19-Hw16);
++
++ /* Initialise ADC registers */
++ writel(ADC_DELAY(10000), ts_base + ADCDLY);
++ writel(RESSEL_12BIT | PRESCALER_EN | PRESCALER_VAL(12), ts_base + ADCCON);
++ writel(ADCTSC_WAIT_PENDOWN, ts_base + ADCTSC);
++ writel(CLEAR_ADC_INT, ts_base + ADCCLRINT);
++ writel(CLEAR_ADCWK_INT, ts_base + ADCCLRUPDN);
++
++ /* Set TSUPDN(58) to the interrupt source of INT_EI2(IRQ_NO)*/
++ BITCSET(pGPIO->EINTSEL0, Hw22-Hw16, 58<<16);
++ BITSET(pPIC->INTMSK0, 1<<IRQ_NO); // Let interrupt pass to IRQ or FIQ
++ BITSET(pPIC->POL0, 1<<IRQ_NO); // When interrupt signal is active-low
++ //BITCLR(pPIC->MODE0, 1<<IRQ_NO);
++
++
++
++ ts = kzalloc(sizeof(struct tcc_ts), GFP_KERNEL);
++ input_dev = input_allocate_device();
++
++ if (!ts || !input_dev) {
++ err = -ENOMEM;
++ goto fail1;
++ }
++
++ ts->running = 0;
++ ts->opened = 1;
++ ts->pen_status = PEN_RELEASE;
++
++ ts->dev = input_dev;
++
++ sprintf(ts->phys, "touchscreen");
++
++ ts->dev->name = tcc_ts_name;
++ ts->dev->phys = ts->phys;
++ ts->dev->id.bustype = BUS_RS232;
++ ts->dev->id.vendor = 0xDEAD;
++ ts->dev->id.product = 0xBEEF;
++ ts->dev->id.version = TCC_TSVERSION;
++ input_dev->dev.parent = &pdev->dev;
++
++ ts->dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
++ //ts->dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
++ ts->dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
++
++ input_set_abs_params(ts->dev, ABS_X, MIN_X, MAX_X, 0, 0);
++ input_set_abs_params(ts->dev, ABS_Y, MIN_Y, MAX_Y, 0, 0);
++ input_set_abs_params(ts->dev, ABS_PRESSURE, 0, 1, 0, 0);
++
++ INIT_WORK(&(ts->work_q), ts_fetch_thread);
++ mutex_init(&(ts->mutex));
++
++ init_timer(&ts_timer);
++ ts_timer.data = (unsigned long)ts;
++ ts_timer.function = ts_timer_handler;
++
++ /* Get irqs */
++ if (request_irq(IRQ_NO, tcc_ts_interrupt, IRQF_DISABLED, "tcc_ts", ts)) {
++ printk(KERN_ERR "tcc_ts.c: Could not allocate ts IRQ_NO !\n");
++ err = -EBUSY;
++ goto fail1;
++ }
++
++ tca_tch_poweroff();
++
++ printk(KERN_INFO "%s got loaded successfully.\n", tcc_ts_name);
++
++ /* All went ok, so register to the input system */
++ err = input_register_device(ts->dev);
++ if (err)
++ goto fail2;
++
++ return 0;
++
++fail2: free_irq(IRQ_NO, ts);
++fail1: input_free_device(input_dev);
++ kfree(ts);
++ return err;
++}
++
++static int tcc_ts_remove(struct platform_device *dev)
++{
++ printk(KERN_INFO "tcc_ts_remove() of TS called !\n");
++
++ ts->opened = 0;
++ dbg("(remove)disable_irq\n");
++ disable_irq(IRQ_NO);
++ del_timer_sync(&ts_timer);
++ flush_scheduled_work();
++
++ free_irq(IRQ_NO, ts->dev);
++
++ input_unregister_device(ts->dev);
++ kfree(ts);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++#if 1
++static int tcc_ts_suspend(struct platform_device *dev, pm_message_t state)
++{
++ *(volatile unsigned long *)0xF05F4018 = Hw0;
++ *(volatile unsigned long *)0xF05F4020 = Hw0;
++ *(volatile unsigned long *)0xF05F4004 |= ADCTSC_WAIT_PENDOWN;
++
++ BITSET(*(volatile unsigned long *)0xF05F4000, (1<<2));
++
++ return 0;
++}
++
++static int tcc_ts_resume(struct platform_device *pdev)
++{
++ BITCLR(*(volatile unsigned long *)0xF05F4000, (1<<2));
++
++ return 0;
++}
++#endif
++#else
++#define tcc_ts_suspend NULL
++#define tcc_ts_resume NULL
++#endif
++
++static struct platform_driver tcc_ts_driver = {
++ .probe = tcc_ts_probe,
++ .remove = tcc_ts_remove,
++ .suspend = tcc_ts_suspend,
++ .resume = tcc_ts_resume,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "tcc-ts",
++ },
++};
++
++static char banner[] __initdata = KERN_INFO "Telechips Touchscreen driver, (c) 2009 Telechips\n";
++
++static int __init tcc_ts_init(void)
++{
++ printk(banner);
++ return platform_driver_register(&tcc_ts_driver);
++}
++
++static void __exit tcc_ts_exit(void)
++{
++ platform_driver_unregister(&tcc_ts_driver);
++}
++
++module_init(tcc_ts_init);
++module_exit(tcc_ts_exit);
++
++MODULE_AUTHOR("linux <linux@telechips.com>");
++MODULE_DESCRIPTION("tcc adc touchscreen driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
+index 47102c2..8317926 100644
+--- a/drivers/media/video/Kconfig
++++ b/drivers/media/video/Kconfig
+@@ -462,6 +462,8 @@ config VIDEO_UPD64083
+
+ endmenu # encoder / decoder chips
+
++source "drivers/media/video/tcccam/Kconfig"
++
+ config VIDEO_VIVI
+ tristate "Virtual Video Driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
+diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
+index 16962f3..78c4bea 100644
+--- a/drivers/media/video/Makefile
++++ b/drivers/media/video/Makefile
+@@ -18,6 +18,8 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
+ obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
+ endif
+
++obj-$(CONFIG_VIDEO_TCCXX_CAMERA) += tcccam/
++
+ obj-$(CONFIG_VIDEO_TUNER) += tuner.o
+
+ obj-$(CONFIG_VIDEO_BT848) += bt8xx/
+diff --git a/drivers/media/video/tcccam/Kconfig b/drivers/media/video/tcccam/Kconfig
+new file mode 100644
+index 0000000..d19fa80
+--- /dev/null
++++ b/drivers/media/video/tcccam/Kconfig
+@@ -0,0 +1,44 @@
++config VIDEO_TCCXX_CAMERA
++ tristate "Telechips TCCXXX Camera support (EXPERIMENTAL)"
++ select VIDEOBUF_GEN
++ select VIDEOBUF_DMA_SG
++ select VIDEOBUF_VMALLOC
++ depends on VIDEO_DEV
++ help
++ V4L2 camera driver support for TCCXXX.
++
++config VIDEO_CAMERA_SENSOR
++ tristate "CAMERA sensor support"
++ depends on VIDEO_TCCXX_CAMERA
++ help
++ camera sensor support
++
++config VIDEO_CAMERA_SENSOR_MT9D112
++ tristate "MT9D112 2MP-sensor support"
++ depends on VIDEO_CAMERA_SENSOR
++ help
++ camera sensor support for 2MP
++
++config VIDEO_CAMERA_SENSOR_MT9D111
++ tristate "MT9D111 2MP-sensor support"
++ depends on VIDEO_CAMERA_SENSOR
++ help
++ camera sensor support for 2MP
++
++config VIDEO_CAMERA_SENSOR_S5K4BAFB
++ tristate "S5K4BAFB 2MP-sensor support"
++ depends on VIDEO_CAMERA_SENSOR
++ help
++ camera sensor support for 2MP
++
++config VIDEO_CAMERA_SENSOR_MV9317
++ tristate "MV9317 3MP-sensor support"
++ depends on VIDEO_CAMERA_SENSOR
++ help
++ camera sensor support for 3MP
++
++config VIDEO_CAMERA_SENSOR_MT9P111
++ tristate "MT9P111 5MP-sensor support"
++ depends on VIDEO_CAMERA_SENSOR
++ help
++ camera sensor support for 5MP
+diff --git a/drivers/media/video/tcccam/Makefile b/drivers/media/video/tcccam/Makefile
+new file mode 100644
+index 0000000..1d80e47
+--- /dev/null
++++ b/drivers/media/video/tcccam/Makefile
+@@ -0,0 +1,13 @@
++# Makefile for TCCxxx camera driver
++
++obj-$(CONFIG_VIDEO_TCCXX_CAMERA) += camera_core.o tcc_cam.o cam.o tdd_cif.o
++obj-$(CONFIG_VIDEO_CAMERA_SENSOR) += sensor_if.o tcc_cam_i2c.o
++obj-$(CONFIG_VIDEO_CAMERA_SENSOR_MT9D111) += mt9d111_2mp.o
++obj-$(CONFIG_VIDEO_CAMERA_SENSOR_MT9D112) += mt9d112_2mp.o
++obj-$(CONFIG_VIDEO_CAMERA_SENSOR_MV9317) += mv9317_3mp.o
++obj-$(CONFIG_VIDEO_CAMERA_SENSOR_S5K4BAFB) += s5k4bafb_2mp.o
++obj-$(CONFIG_VIDEO_CAMERA_SENSOR_MT9P111) += mt9p111_5mp.o
++
++#tcc78xxcamera-objs := $(objs-yy)
++
++EXTRA_CFLAGS = -I$(src)/..
+diff --git a/drivers/media/video/tcccam/cam.c b/drivers/media/video/tcccam/cam.c
+new file mode 100644
+index 0000000..4f1b094
+--- /dev/null
++++ b/drivers/media/video/tcccam/cam.c
+@@ -0,0 +1 @@
++/************************************************************************ * Telechips Multi Media Player * ------------------------------------------------ * * FUNCTION : CAMERA INTERFACE API * MODEL : DMP * CPU NAME : TCCXXX * SOURCE : cam.c * * START DATE : 2006. 4. 17. * MODIFY DATE : * DEVISION : DEPT. SYSTEM 3-2 TEAM * : TELECHIPS, INC. ************************************************************************/ #include <linux/delay.h> #include <mach/hardware.h> #include <asm/io.h> //(CONFIG_ARCH_TCC8900) #include <bsp.h> #include "cam.h" #include "cam_reg.h" #include "sensor_if.h" /********************************************************** * * Function of * * * * Input : * Output : * Return : * * Description : **********************************************************/ void CIF_Open(void) { #if defined(CONFIG_ARCH_TCC8900) BITCLR(HwDDI_CONFIG->PWDN, HwDDIC_PWDN_CIF); #endif //PLL : 154Mhz //192Mhz #if defined(SENSOR_2M) //(CONFIG_ARCH_TCC8900) #if defined(CONFIG_VIDEO_CAMERA_SENSOR_S5K4BAFB) tca_ckc_setperi(PERI_CIFMC, ENABLE, 250000, DIRECTPLL0); tca_ckc_setperi(PERI_CIFSC, ENABLE, 1000000, DIRECTPLL0); // #elif defined(CONFIG_VIDEO_CAMERA_SENSOR_MT9D111) //@storm // tca_ckc_setperi(PERI_CIFMC, ENABLE, 400000, DIRECTPLL0); // tca_ckc_setperi(PERI_CIFSC, ENABLE, 800000, DIRECTPLL0); #elif defined(CONFIG_VIDEO_CAMERA_SENSOR_MT9D112) //@storm // tca_ckc_setperi(PERI_CIFMC, ENABLE, 245000, DIRECTPLL0); tca_ckc_setperi(PERI_CIFMC, ENABLE, 400000, DIRECTPLL0); tca_ckc_setperi(PERI_CIFSC, ENABLE, 2000000, DIRECTPLL0); #else tca_ckc_setperi(PERI_CIFMC, ENABLE, 400000, DIRECTPLL0); tca_ckc_setperi(PERI_CIFSC, ENABLE, 800000, DIRECTPLL0); #endif #elif defined(SENSOR_3M) //(CONFIG_ARCH_TCC8900) //JAZZ: 80Mhz:27.8fps, 70Mhz:23.8fps tca_ckc_setperi(PERI_CIFMC, ENABLE, 900000/*500000*/, DIRECTPLL3); tca_ckc_setperi(PERI_CIFSC, ENABLE, 900000, DIRECTPLL3); #elif defined(SENSOR_5M) tca_ckc_setperi(PERI_CIFMC, ENABLE, 160000, DIRECTPLL2); tca_ckc_setperi(PERI_CIFSC, ENABLE, 1660000, DIRECTPLL3); #endif //(CONFIG_ARCH_TCC8900) BITSET(HwDDI_CONFIG->SWRESET, HwDDIC_SWRESET_CIF); // Reset BITCLR(HwDDI_CONFIG->SWRESET, HwDDIC_SWRESET_CIF); // Normal } /********************************************************** * * Function of * * * * Input : * Output : * Return : * * Description : **********************************************************/ void CIF_Close(void) { //(CONFIG_ARCH_TCC8900) BITCLR(HwCKC->PCLK_CIFMC, Hw28); // Master clk BITCLR(HwCKC->PCLK_CIFSC, Hw28); // Scaler clk BITSET(HwDDI_CONFIG->PWDN, HwDDIC_PWDN_CIF); } /********************************************************** * * Function of * * * * Input : * Output : * Return : * * Description : **********************************************************/ void CIF_ONOFF(unsigned int uiOnOff) { //(CONFIG_ARCH_TCC8900) if(uiOnOff == ON) { BITCSET(HwCIF->ICPCR1, HwICPCR1_ON, (uiOnOff << 31)); } else if(uiOnOff == OFF) { BITCSET(HwCIF->ICPCR1, HwICPCR1_ON, (uiOnOff << 31)); } } /********************************************************** * * Function of * * * Input : * Output : * Return : * * Description : **********************************************************/ void CIF_WaitFrameSync(unsigned int exp_timer) { unsigned int cnt=0; //(CONFIG_ARCH_TCC8900) while((HwCIF->CIRQ & HwCIRQ_SOF) != HwCIRQ_SOF) { msleep(1); cnt++; if(cnt>exp_timer) break; } } void CIF_OpStop(void) { //CIF_WaitFrameSync(200); mdelay(20); CIF_ONOFF(OFF); //(CONFIG_ARCH_TCC8900) BITSET(HwDDI_CONFIG->SWRESET, HwDDIC_SWRESET_CIF); // Reset BITCLR(HwDDI_CONFIG->SWRESET, HwDDIC_SWRESET_CIF); // Normal } /* end of file */
+\ No newline at end of file
+diff --git a/drivers/media/video/tcccam/cam.h b/drivers/media/video/tcccam/cam.h
+new file mode 100644
+index 0000000..914204e
+--- /dev/null
++++ b/drivers/media/video/tcccam/cam.h
+@@ -0,0 +1 @@
++/************************************************************************ * Telechips Multi Media Player * ------------------------------------------------ * * FUNCTION : CAMERA INTERFACE API * MODEL : DMP * CPU NAME : TCCXXX * SOURCE : cam.h * * START DATE : 2008. 4. 17. * MODIFY DATE : * DEVISION : DEPT. SYSTEM 3-2 TEAM * : TELECHIPS, INC. ************************************************************************/ #ifndef _CAM_H_ #define _CAM_H_ //CIF_SET_INFO #define SET_CIF_BYPASS_MODE 0x00000001 #define SET_CIF_BYPASS_BUS 0x00000002 #define SET_CIF_COLOR_PATTERN 0x00000004 #define SET_CIF_PATTERN_FORMAT 0x00000008 #define SET_CIF_RGB_MODE 0x00000010 #define SET_CIF_RGBBIT_MODE 0x00000020 #define SET_CIF_COLOR_SEQUENCE 0x00000040 #define SET_CIF_BUS_ORDER 0x00000080 #define SET_CIF_ALL 0x000000FF //CIF_SET_INFO_II #define SET_CIF_PWDN 0x00000001 #define SET_CIF_BYPASS_SCALER 0x00000002 #define SET_CIF_PXCLK_POL 0x00000004 #define SET_CIF_SKPF 0x00000008 #define SET_CIF_M42_FC 0x00000010 #define SET_CIF_C656 0x00000020 #define SET_CIF_II_ALL 0x0000003F #define SET_CIF_TRANSFER_MODE 0x00000001 #define SET_CIF_TRANSFER_BURST 0x00000002 #define SET_CIF_TRANSFER_LOCK 0x00000004 #define SET_CIF_TRANSFER_ALL 0x00000007 #define SET_CIF_OVERLAY_COUNT 0x00000001 #define SET_CIF_OVERLAY_METHOD 0x00000002 #define SET_CIF_OVERLAY_XOR0 0x00000004 #define SET_CIF_OVERLAY_XOR1 0x00000008 #define SET_CIF_OVERLAY_ALPHA0 0x00000010 #define SET_CIF_OVERLAY_ALPHA1 0x00000020 #define SET_CIF_OVERLAY_ALL 0x0000003F #define SET_CIF_OVERLAY_KEY 0x00000001 #define SET_CIF_OVERLAY_MASKKEY 0x00000002 #define SET_CIF_OVERLAYKEY_ALL 0x00000003 #define SET_CIF_ALPHA_ENABLE 0x00000001 #define SET_CIF_ALPHA_DISABLE 0x00000002 #define SET_CIF_CHROMA_ENABLE 0x00000004 #define SET_CIF_CHROMA_DISABLE 0x00000008 #define SET_CIF_OVERLAY_ENABLE 0x00000010 #define SET_CIF_OVERLAY_DISABLE 0x00000020 #define SET_CIF_COLOR_CONV_ENABLE 0x00000040 #define SET_CIF_COLOR_CONV_DISABLE 0x00000080 //#define SET_CIF_OVERLAY_RGB_MODE 0x00000100 #define SET_CIF_COLOR_MODE_RGB 0x00000200 #define SET_CIF_COLOR_MODE_YUV 0x00000400 #define SET_CIF_CR2Y_FMT 0x00000001 #define SET_CIF_CR2Y_EN 0x00000002 #define SET_CIF_CR2Y_ALL 0x00000003 #define INPUT_IMG 0x00000001 #define OVERLAY_IMG 0x00000002 #define IN_IMG_ROLLING 0x00000004 #define IN_ENC_START_ADDR 0x00000008 #ifndef _82x // CIF_API_INTERRUPT_FEATURE ///////////////////////////////////////////////////////////////////////////// // CIF_SET_INTERRUPT ///////////////////////////////////////////////////////////////////////////// //IEN Hw31 Interrupt Enable 0:interrupt disable, 1:interrupt enable #define SET_CIF_INT_ENABLE 0x00000001 #define SET_CIF_INT_DISABLE 0x00000002 //URV Hw30 Update Register in VSYNC 0:Register is update without VSYNC , 1:When VSYNC is posedge, register is updated. #define SET_CIF_UPDATE_IN_VSYNC 0x00000004 #define SET_CIF_UPDATE_WITHOUT_VSYNC 0x00000008 //ITY Hw29 Interrupt Type 0:Pulse type, 1:Hold-up type when respond signal(ICR) is high #define SET_CIF_INT_TYPE_HOLDUP 0x00000010 #define SET_CIF_INT_TYPE_PULSE 0x00000020 //Hw28 Interrupt Clear 0:.... , 1:Interrupt Clear (using ITY is Hold-up type) //Hw28 #define SET_CIF_INT_HOLD_CLEAR 0x00000040 ///////////////////////////////////////////////////////////////////////////// // CIF_SET_INTERRUPT_MASK ///////////////////////////////////////////////////////////////////////////// //MVN Hw26 // Mask interrupt of VS negative edge, 0:Don't mask, 1:Mask #define SET_CIF_INT_VS_NEGA_MASK 0x00000001 #define SET_CIF_INT_VS_NEGA_NOT_MASK 0x00000002 //MVP Hw25 // Mask interrupt of VS negative edge, 0:Don't mask, 1:Mask #define SET_CIF_INT_VS_POSI_MASK 0x00000004 #define SET_CIF_INT_VS_POSI_NOT_MASK 0x00000008 //MVIT Hw24 // Mask interrupt of VCNT Interrupt, 0:Don't mask, 1:Mask #define SET_CIF_INT_VCNT_MASK 0x00000010 #define SET_CIF_INT_VCNT_NOT_MASK 0x00000020 //MSE Hw23 // Mask interrupt of Scaler Error, 0:Don't mask, 1:Mask #define SET_CIF_INT_SCALER_ERR_MASK 0x00000040 #define SET_CIF_INT_SCALER_ERR_NOT_MASK 0x00000080 //MSF Hw22 // Mask interrupt of Scaler finish, 0:Don't mask, 1:Mask #define SET_CIF_INT_SCALER_FINISH_MASK 0x00000100 #define SET_CIF_INT_SCALER_FINISH_NOT_MASK 0x00000200 //MENS Hw21 // Mask interrupt of Encoding start, 0:Don't mask, 1:Mask #define SET_CIF_INT_ENC_STRT_MASK 0x00000400 #define SET_CIF_INT_ENC_STRT_NOT_MASK 0x00000800 //MRLV Hw20 // Mask interrupt of Rolling V address, 0:Don't mask, 1:Mask #define SET_CIF_INT_ROLL_VADDR_MASK 0x00001000 #define SET_CIF_INT_ROLL_VADDR_NOT_MASK 0x00002000 //MRLU Hw19 // Mask interrupt of Rolling U address, 0:Don't mask, 1:Mask #define SET_CIF_INT_ROLL_UADDR_MASK 0x00004000 #define SET_CIF_INT_ROLL_UADDR_NOT_MASK 0x00008000 //MRLY Hw18 // Mask interrupt of Rolling Y address, 0:Don't mask, 1:Mask #define SET_CIF_INT_ROLL_YADDR_MASK 0x00010000 #define SET_CIF_INT_ROLL_YADDR_NOT_MASK 0x00020000 //MSCF Hw17 // Mask interrupt of Capture frame, 0:Don't mask, 1:Mask #define SET_CIF_INT_CAPTURE_FRM_MASK 0x00040000 #define SET_CIF_INT_CAPTURE_FRM_NOT_MASK 0x00080000 //MSOF Hw16 // Mask interrupt of Stored one frame, 0:Don't mask, 1:Mask #define SET_CIF_INT_STORE_1FRM_MASK 0x00100000 #define SET_CIF_INT_STORE_1FRM_NOT_MASK 0x00200000 #define SET_CIF_INT_ALL_MASK 0x00400000 #define SET_CIF_INT_ALL_CLEAR_MASK 0x00800000 //VSS Hw12 // Status of vertical sync, 0: Non-vertical sync blank area. , 1: vertical sync blank area //#define SET_CIF_INT_VS_STATUS 0x00400000 //#define SET_CIF_INT_NON_VS_STATUS 0x00800000 ////////////////////////////////////////////////////////////////////////////// // CIF_GET_INTERRUPT_STATUS ////////////////////////////////////////////////////////////////////////////// // VSS Hw12 // Status of vertical sync, 0: Non-vertical sync blank area. , 1: vertical sync blank area #define GET_CIF_INT_VS_STATUS 0x00000001 //#define HwCIRQ_VN Hw10 // VS positive, 0:-, 1:When VS is generated if Negative edge #define GET_CIF_INT_NEGA_VS_GEN 0x00000002 //#define HwCIRQ_VP Hw9 // VS positive, 0:-, 1:When VS is generated if positive edge #define GET_CIF_INT_POSI_VS_GEN 0x00000004 //#define HwCIRQ_VIT Hw8 // VCNT Interrupt, 0:-, 1:When VCNT is generated.... #define GET_CIF_INT_VCNT_GEN 0x00000008 //#define HwCIRQ_SE Hw7 // Scaler Error, 0:-, 1:When Scale operation is not correct. #define GET_CIF_INT_SCALER_ERR 0x00000010 //#define HwCIRQ_SF Hw6 // Scaler Finish, 0:-, 1:When Scale operation is finished #define GET_CIF_INT_SCALER_FINISH 0x00000020 //#define HwCIRQ_ENS Hw5 // Encoding start status, 0:-, 1:When Y address is bigger than encoding start address, this bit is high #define GET_CIF_INT_ENC_STRT 0x00000040 //#define HwCIRQ_ROLV Hw4 // Rolling V address status, 0:-, 1:If V address is move to start address, this bit is high #define GET_CIF_INT_ROLL_VADDR_STRT 0x00000080 //#define HwCIRQ_ROLU Hw3 // Rolling U address starus, 0:-, 1:If U address is move to start address, this bit is high #define GET_CIF_INT_ROLL_UADDR_STRT 0x00000100 //#define HwCIRQ_ROLY Hw2 // Rolling Y address starus, 0:-, 1:If Y address is move to start address, this bit is high #define GET_CIF_INT_ROLL_YADDR_STRT 0x00000200 //#define HwCIRQ_SCF Hw1 // Stored captured frame, 0:-, 1:If Captured frame is stored, this bit is high #define GET_CIF_INT_CAPTURE_FRM_STORE 0x00000800 //#define HwCIRQ_SOF Hw0 // Stored One frame, 0-, 1:If one frame if stored, this bit is high. #define GET_CIF_INT_ONEFRAME_STORE 0x00001000 #endif // _82x #define SET_CIF_CLOCK_DIV0 0x00000001 #define SET_CIF_CLOCK_DIV1 0x00000002 #define SET_CIF_CLOCK_DIV2 0x00000004 #define SET_CIF_CLOCK_DIV3 0x00000008 #define SET_CIF_CLOCKPOLHIGH_ENABLE 0x00000010 #define SET_CIF_CLOCKPOLHIGH_DISABLE 0x00000020 #define SET_CIF_CLOCKINT_ENABLE 0x00000040 #define SET_CIF_CLOCKINT_DISABLE 0x00000080 #define SET_CIF_CLOCK_ALL 0x000000FF #define SET_CIF_656_PSL 0x00000001 #define SET_CIF_656_FPV 0x00000002 #define SET_CIF_656_SPV 0x00000004 #define SET_CIF_656_TPV 0x00000008 #define SET_CIF_656_H_BLANK 0x00000010 #define SET_CIF_656_V_BLANK 0x00000020 #define SET_CIF_656_ALL 0x0000003F #define GET_CIF_OVERLAY_READ_ERR 0x00000001 #define GET_CIF_VCH_READ_ERR 0x00000002 #define GET_CIF_UCH_READ_ERR 0x00000004 #define GET_CIF_YCH_READ_ERR 0x00000008 #define GET_CIF_OVERLAY_WRITE_ERR 0x00000010 #define GET_CIF_VCH_WRITE_ERR 0x00000020 #define GET_CIF_UCH_WRITE_ERR 0x00000040 #define GET_CIF_YCH_WRITE_ERR 0x00000080 #define GET_CIF_OVERLAY_EMPTY_ERR 0x00000100 #define GET_CIF_VCH_EMPTY_ERR 0x00000200 #define GET_CIF_UCH_EMPTY_ERR 0x00000400 #define GET_CIF_YCH_EMPTY_ERR 0x00000800 #define GET_CIF_OVERLAY_FULL_ERR 0x00001000 #define GET_CIF_VCH_FULL_ERR 0x00002000 #define GET_CIF_UCH_FULL_ERR 0x00004000 #define GET_CIF_YCH_FULL_ERR 0x00008000 #define SET_CIF_SKIP_NUM 0x00000001 #define SET_CIF_VCNT_NUM 0x00000002 #define SET_CIF_CCM1_ENCNUM 0x00000001 // Encode INT number (using CAP mode) [31:28], value area (0~15), Encode interrupt number #define SET_CIF_CCM1_ROLNUMV 0x00000002 // Rolling number in V (using CAP mode) [27:24], value area (0~15), Rolling number #define SET_CIF_CCM1_ROLNUMU 0x00000004 // Rolling number in U (using CAP mode) [23:20], value area (0~15), Rolling number #define SET_CIF_CCM1_ROLNUMY 0x00000008 // Rolling number in Y (using CAP mode) [19:16], value area (0~15), Rolling number #define SET_CIF_CCM1_CB 0x00000010 // Capture Busy, 0:-, 1:Capture busy #define SET_CIF_EIT_ENC_INT 0x00000001 #define SET_CIF_EIT_ALWAYS_1_PULSE 0x00000002 #define SET_CIF_UES_ENABLE 0x00000004 #define SET_CIF_UES_DISABLE 0x00000008 #define SET_CIF_RLV_ENABLE 0x00000010 #define SET_CIF_RLV_DISABLE 0x00000020 #define SET_CIF_RLU_ENABLE 0x00000040 #define SET_CIF_RLU_DISABLE 0x00000080 #define SET_CIF_RLY_ENABLE 0x00000100 #define SET_CIF_RLY_DISABLE 0x00000200 #define SET_CIF_CAP_ENABLE 0x00000400 #define SET_CIF_CAP_DISABLE 0x00000800 #define SET_CIF_VEN_ENABLE 0x00001000 #define SET_CIF_VEN_DISABLE 0x00002000 #define READ_CIF_CUR_ADDR_Y 0x00000001 #define READ_CIF_CUR_ADDR_U 0x00000002 #define READ_CIF_CUR_ADDR_V 0x00000004 #define READ_CIF_CUR_LINE_CNT 0x00000008 #define SET_CIF_CEM_UVS 0x00000001 // UV Swap 0:u-v-u-v sequence, 1:v-u-v-u sequence #define SET_CIF_CEM_VB 0x00000002 // V Bias (V channel value offset), 0:disable, 1:Enable #define SET_CIF_CEM_UB 0x00000004 // U Bias (U channel value offset), 0:disable, 1:Enable #define SET_CIF_CEM_YB 0x00000008 // Y Bias (Y channel value offset), 0:disable, 1:Enable #define SET_CIF_CEM_YCS 0x00000010 // YC Swap 0:u-y-v-y sequence, 1:y-u-y-v sequence #define SET_CIF_CEM_IVY 0x00000020 // Invert Y, 0:disable, 1:Enable #define SET_CIF_CEM_STC 0x00000040 // Strong C, 0:disable, 1:Enable #define SET_CIF_CEM_YCL 0x00000080 // Y Clamp (Y value clipping), 0:disable, 1:Enable #define SET_CIF_CEM_CS 0x00000100 // C Select (Color filter), 0:disable, 1:Enable(Color filter) #define SET_CIF_CEM_SKT 0x00000200 // Sketch Enable, 0:disable, 1:Enable #define SET_CIF_CEM_EMM 0x00000400 // Emboss mode, 0:Positive emboss, 1:Negative emboss // Only 0 SET ¾Êº»´Ù. #define SET_CIF_CEM_EMB 0x00000800 // Emboss, 0:disable, 1:Enable #define SET_CIF_CEM_NEGA 0x00001000 // Negative mode, 0:disable, 1:Enable #define SET_CIF_CEM_GRAY 0x00002000 // Gray mode, 0:disable, 1:Enable #define SET_CIF_CEM_SEPI 0x00004000 // Sepia mode, 0:disable, 1:Enable #define SET_CIF_CEM_NOR 0x00008000 // Normal mode, 0:Effect mode, 1:Normal mode #define SET_CIF_CEM_ALL_CLEAR 0x00010000 #define SET_CIF_INPATH_H_WAIT 0x00000001 #define SET_CIF_INPATH_S_CYCLE 0x00000002 #define SET_CIF_INPATH_I_WAIT 0x00000004 #define SET_CIF_INPATH_R_ENABLE 0x00000008 #define SET_CIF_INPATH_R_DISABLE 0x00000010 #define SET_CIF_INPATH_FLUSH_ENABLE 0x00000020 #define SET_CIF_INPATH_FLUSH_DISABLE 0x00000040 #define SET_CIF_INPATH_ENABLE 0x00000080 #define SET_CIF_INPATH_DISABLE 0x00000100 #define SET_CIF_INPATH_MEM 0x00000200 #define SET_CIF_INPATH_CAM 0x00000400 #define SET_CIF_INPATH_SRC_SIZE 0x00000001 #define SET_CIF_INPATH_SRC_OFFSET 0x00000002 #define SET_CIF_INPATH_DST_SIZE 0x00000004 #define SET_CIF_INPATH_SCALE 0x00000008 #define SET_CIF_INPATH_ALL 0x0000000F #define SET_CIF_SCALER_ENABLE 1 #define SET_CIF_SCALER_DISABLE 0 #define SET_CIF_SCALER_SRC_SIZE 0x00000001 #define SET_CIF_SCALER_SRC_OFFSET 0x00000002 #define SET_CIF_SCALER_DST_SIZE 0x00000004 #define SET_CIF_SCALER_FACTOR 0x00000008 #define SET_CIF_SCALER_ALL 0x0000000F /* #define SET_SCALE_TYPE_422SEQ0 0 #define SET_SCALE_TYPE_422SEQ1 1 #define SET_SCALE_TYPE_422SEPE 2 #define SET_SCALE_TYPE_INVALID 3 #define SET_SCALE_PATH_TOMEMORY 0 #define SET_SCALE_PATH_TOLCD 1 #define SCALE_BUSY_INT_ENABLE 0 #define SCALE_BUSY_INT_DISABLE 1 #define SCALE_READY_INT_ENABLE 0 #define SCALE_READY_INT_DISABLE 1 #define MSC_CFG_WAIT 0x00000001 #define MSC_CFG_RDY 0x00000002 #define MSC_CFG_PATH 0x00000004 #define MSC_CFG_TYPE 0x00000008 #define MSC_CFG_ALL 0x0000000F #define MSC_CTRL_BUSY_INT_EN 0x00000001 #define MSC_CTRL_BUSY_INT_DIS 0x00000002 #define MSC_CTRL_RDY_INT_EN 0x00000004 #define MSC_CTRL_RDY_INT_DIS 0x00000008 #define MSC_CTRL_EN 0x00000010 #define MSC_CTRL_DIS 0x00000020 #define MSC_CTRL_ROLL_EN 0x00000040 #define MSC_CTRL_ROLL_DIS 0x00000080 #define MSC_CTRL_MIDDLE_EN 0x00000100 #define MSC_CTRL_MIDDLE_DIS 0x00000200 #define MSC_CTRL_ROLL_RESTR_SET 0x00000400 #define MSC_CTRL_ROLL_GOSTOP_EN 0x00000800 #define MSC_CTRL_ROLL_GOSTOP_DIS 0x00001000 #define MSC_CTRL_MIDDLE_GOSTOP_EN 0x00002000 #define MSC_CTRL_MIDDLE_GOSTOP_DIS 0x00004000 #define MSC_CTRL_ROLL_INT_EN 0x00008000 #define MSC_CTRL_ROLL_INT_DIS 0x00010000 #define MSC_CTRL_MIDDLE_INT_EN 0x00020000 #define MSC_CTRL_MIDDLE_INT_DIS 0x00040000 #define MSC_CTRL_ALL 0x0007FFFF */ /* Drivers IDs */ enum { MON = 0, SEQ, AE, AWB, FD, AF, AFM, MODE, JPEG = 9, HG = 11, MON_EXT = 16, SEQ_EXT, AE_EXT, AWB_EXT, FD_EXT, AF_EXT, AFM_EXT, MODE_EXT, JPEG_EXT = 25, HG_EXT }; #define CAM_BW_16BIT 0x00 #define CAM_BW_8BIT 0x01 #define CAM_HSIZE_PREV 320 #define CAM_VSIZE_PREV 240 #define CAM_HSIZE 320 #define CAM_VSIZE 240 #if defined (FEATURE_LCD_128x160) #define CAMLCD_HSIZE 128 #define CAMLCD_VSIZE 160 #elif defined (FEATURE_LCD_176x220) #define CAMLCD_HSIZE 176 #define CAMLCD_VSIZE 220 #define CAMLCD_ROT90_HSIZE 224 #define CAMLCD_ROT90_VSIZE 176 #elif defined (FEATURE_LCD_240x320) #define CAMLCD_HSIZE 240 #define CAMLCD_VSIZE 320 #define CAMLCD_ROT90_HSIZE 320 #define CAMLCD_ROT90_VSIZE 240 #else #define CAMLCD_HSIZE 240 #define CAMLCD_VSIZE 320 #endif #define VOD_HSIZE 176 #define VOD_VSIZE 144 #define CAM_HSIZE_TV 640 #define CAM_VSIZE_TV 480 typedef struct _CIF_CONTROL_INFO { unsigned int uiFlag; unsigned int uiBypass; unsigned int uiBypassBusSel; unsigned int uiColorPattern; unsigned int uiPatternFormat; unsigned int uiRGBMode; unsigned int uiRGBBitMode; unsigned int uiColorSequence; unsigned int uiBusOrder; unsigned int uiOverlayCNT; } CIF_CONTROL_INFO; typedef struct _CIF_TRANSFER_CONFIG { unsigned int uiFlag; unsigned int uiTransMode; unsigned int uiBurst; unsigned int uiLock; } CIF_TRANSFER_CONFIG; typedef struct _CIF_OVERLAY_CONFIG { unsigned int uiFlag; unsigned int uiOverlayCNT; unsigned int uiOverlayMethod; unsigned int uiXOR1; unsigned int uiXOR0; unsigned int uiAlpha1; unsigned int uiAlpha0; } CIF_OVERLAY_CONFIG; typedef struct _CIF_OVERLAY_KEY { unsigned int uiFlag; unsigned int uiKEYR; unsigned int uiKEYG; unsigned int uiKEYB; unsigned int uiMKEYR; unsigned int uiMKEYG; unsigned int uiMKEYB; } CIF_OVERLAY_KEY; typedef struct _CIF_SYNC_POLARITY { unsigned int uiHPolarity; unsigned int uiVpolarity; } CIF_SYNC_POLARITY; typedef struct _CIF_IMAGE_CONFIG { unsigned int uiType; unsigned int uiHsize; unsigned int uiVsize; unsigned int uiHorWindowingStart; unsigned int uiHorWindowingEnd; unsigned int uiVerWindowingStart; unsigned int uiVerWindowingEnd; } CIF_IMAGE_CONFIG; typedef struct _CIF_SCALE_CONFIG { unsigned int uiScaleEnable; unsigned int uiXScale; unsigned int uiYScale; } CIF_SCALE_CONFIG; typedef struct _CIF_BASE_ADDRESS { unsigned int uiType; unsigned int uiBaseAddr0; unsigned int uiBaseAddr1; unsigned int uiBaseAddr2; } CIF_BASE_ADDRESS; typedef struct _CIF_OVERLAY_CONTROL { unsigned int uiFlag; unsigned int uiAlphaEnable; unsigned int uiChromakeyEnable; unsigned int uiOverlayEnable; } CIF_OVERLAY_CONTROL; typedef struct _CIF_INTANDOPERATING_CONTROL { unsigned int uiFlag; unsigned int uiReadOneFrameStatus; } CIF_INTANDOPERATING_CONTROL; extern void CIF_Open(void); extern void CIF_Close(void); extern void CIF_ONOFF(unsigned int uiOnOff); extern void CIF_OpStop (void); extern void CIF_WaitFrameSync(unsigned int exp_timer); #endif
+\ No newline at end of file
+diff --git a/drivers/media/video/tcccam/cam_reg.h b/drivers/media/video/tcccam/cam_reg.h
+new file mode 100644
+index 0000000..573753f
+--- /dev/null
++++ b/drivers/media/video/tcccam/cam_reg.h
+@@ -0,0 +1 @@
++/************************************************************************ * Telechips Multi Media Player * ------------------------------------------------ * * FUNCTION : CAMERA INTERFACE API * MODEL : DMP * CPU NAME : TCCXXX * SOURCE : cam_reg.h * * START DATE : 2008. 4. 17. * MODIFY DATE : * DEVISION : DEPT. SYSTEM 3-2 TEAM * : TELECHIPS, INC. ************************************************************************/ #ifndef _CAM_REG_H_ #define _CAM_REG_H_ #define ON 1 #define OFF 0 #define ENABLE 1 #define DISABLE 0 // 1. On/Off on CIF >> 0:Can't operate CIF , 1:Operating CIF #define CIF_ON 1 #define CIF_OFF 0 // 4. HwICPCR1_POL Hw21 // PXCLK Polarity >> 0:Positive edge, 1:Negative edge #define POSITIVE 1 #define NEGATIVE 0 #define CIF_PWDN_ENABLE 1 #define CIF_PWDN_DISABLE 0 #define CIF_BYPASS_SCALER_ENABLE 1 #define CIF_BYPASS_SCALER_DISABLE 0 #define CIF_PXCLK_NEGATIVE_EDGE 1 #define CIF_PXCLK_POSITIVE_EDGE 0 #define CIF_656CONVERT_ENABLE 1 #define CIF_656CONVERT_DISABLE 0 // 5. HwICPCR1_SKPF // Skip Frame >> 0~7 #Frames skips [20:18] #define FRAME_0 0 #define FRAME_1 1 #define FRAME_2 2 #define FRAME_3 3 #define FRAME_4 4 #define FRAME_5 5 #define FRAME_6 6 #define FRAME_7 7 // 6. // HwICPCR1_M420_ZERO HwZERO // Format Convert (YUV422->YUV420) , Not-Convert // HwICPCR1_M420_ODD Hw17 // converted in odd line skip // 10 // HwICPCR1_M420_EVEN (Hw17|Hw16) // converted in even line skip //11 #define M420_ZERO 0 // YUV422 #define M420_ODD 2 // YUV420 #define M420_EVEN 3 // BP, Hw15, Bypass (Non-Separate) #define SEPARATE 0 #define NON_SEPARATE 1 //#define NON_BYPASS 0 // Not Bypass = Separate //#define BYPASS 1 // Bypass = NON_Separate //BBS, Hw14, Bypass BUS Select #define MSB_FIRST 0 #define LSB_FIRST 1 // CP , Hw12, Color Pattern #define MODE_YUV 0 //Ycbcr(YUV, RGB) #define MODE_RGB 1 // RGB(555,565,bayer) // PF , Hw11,Hw10 , Pattern Format #define FMT444 0 #define FMT422 1 #define FMTRGB 2 // 4:2:0 format or RGB(555,565,bayer) color pattern //RGBM , Hw9,Hw8 , RGB mode #define BAYER_RGB 0 #define RGB555 1 #define RGB565 2 //RGBBM, Hw7,Hw6 , RGB Bit Mode #define MODE16 0 // 16bit mode (4:2:0 Ycbcr/ YUV, RGB555/565, 4:2:2/4:4:4 format) #define MODE8 1 // 8bit non-sync #define MODE8SYNC 2 // 8bit (Bayer/555/565RGB), 8bit enable sync (sync-port) // CS Hw5, Hw4 , Color Sequence #define SEQYUYV 0 #define SEQYVYU 1 #define SEQUYVY 2 #define SEQVYUY 3 //#define SEQ_YBYR 0 //#define SEQ_YRYB 1 //#define SEQ_BYRY 2 //#define SEQ_RYBY 3 // BO Hw2 , BUS Order #define SWICH_BUS 1 #define NON_SWICH_BUS 0 ///////////////////////////////////////////////////////////////////////////// #define ACT_HIGH 1 #define ACT_LOW 0 #define NEGATIVE_EDGE 1 #define POSITIVE_EDGE 0 // Hw0, Hw1, BS , preamble and Status Location #define BURST1 0 #define BURST2 1 #define BURST4 2 #define BURST8 3 // Hw2, LOCK , Lock Transfer #define LOCK_TR 1 #define NON_LOCK_TR 0 // Hw3, TM, Transfer Method #define INC_TRANS 1 #define BURST_TRANS 0 #define OL_RGB_565 0 // RGB mode 565RGB #define OL_RGB_555 1 // RGB mode 555RGB #define OL_RGB_444 2 // RGB mode 444RGB #define OL_RGB_332 3 // RGB mode 332RGB #define D_SCALE1 0 #define D_SCALE2 1 #define D_SCALE4 2 #define D_SCALE8 3 #define RGB_SEQ_16 0 #define BGR_SEQ_16 1 #define RGB_GBG_16 4 #define BGR_GBG_16 5 #define GBG_RGB_16 6 #define GBG_BGR_16 7 #define RGB_SEQ_8_565 8 #define BGR_SEQ_8_565 9 #define RGB_GBG_8_555 12 //C #define BGR_GBG_8_555 13 //D #define GBG_RGB_8_555 14 //E #define GBG_BGR_8_555 15 //F #define FULL_OVERLAY 0 #define BLOCK_OVERLAY 1 #define OP_XOR 0 #define OP_ALPHA 1 #define ALPHA25 0 #define ALPHA50 1 #define ALPHA75 2 #define ALPHA100 3 #define PSL_1ST 0 #define PSL_2ND 1 #define PSL_3RD 2 #define PSL_4TH 3 #define INPATH_422SEQ0 0 #define INPATH_422SEQ1 1 #define INPATH_422SEPA 2 #define INPATH_420SEPA 3 #endif
+\ No newline at end of file
+diff --git a/drivers/media/video/tcccam/camera_core.c b/drivers/media/video/tcccam/camera_core.c
+new file mode 100644
+index 0000000..3e472db
+--- /dev/null
++++ b/drivers/media/video/tcccam/camera_core.c
+@@ -0,0 +1,1032 @@
++/*
++ * drivers/media/video/tcccam/camera_core.c
++ *
++ * Copyright (C) 2008 Telechips, Inc.
++ *
++ * Video-for-Linux (Version 2) camera capture driver for
++ * the OMAP H2 and H3 camera controller.
++ *
++ * Adapted from omap24xx driver written by Andy Lowe (source@mvista.com)
++ * Copyright (C) 2003-2004 MontaVista Software, Inc.
++ *
++ * This package is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * History:
++ *
++ */
++
++#include <linux/autoconf.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/vmalloc.h>
++#include <linux/slab.h>
++#include <linux/proc_fs.h>
++#include <linux/ctype.h>
++#include <linux/pagemap.h>
++#include <linux/mm.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/videodev.h>
++#include <linux/pci.h>
++#include <linux/version.h>
++#include <linux/semaphore.h>
++#include <asm/processor.h>
++#include <linux/dma-mapping.h>
++#include <linux/fb.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ioctl.h>
++
++#include <asm/io.h>
++#include <asm/byteorder.h>
++#include <asm/irq.h>
++
++#include "sensor_if.h"
++#include "camera_hw_if.h"
++#include "camera_core.h"
++#include "tcc_cam.h"
++#include "tdd_cif.h"
++
++
++#if 1
++static int debug = 1;
++#else
++static int debug = 0;
++#endif
++
++#define dprintk(msg...) if (debug) { printk( "Camera_core: " msg); }
++
++
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++#include "tcc83xx_jpeg.h"
++#endif
++
++//(CONFIG_ARCH_TCC8900)
++#include <bsp.h>
++
++#define DRIVER_VERSION "v1.0"
++#define DRIVER_AUTHOR "Telechips.Co.Ltd"
++#define DRIVER_DESC "TCC CAMERA driver"
++
++
++extern struct TCCxxxCIF hardware_data;
++struct v4l2_framebuffer fbuf;
++static struct video_device *vfd;
++static struct v4l2_pix_format pix;
++static unsigned long xclk;
++#ifdef CONFIG_HAS_EARLYSUSPEND
++ static struct early_suspend early_suspend;
++#endif
++
++//int tmp_i2c_add(void);
++//void tmp_i2c_del(void);
++
++//static void camera_core_sgdma_process(struct tcc78xx_camera_device *cam);
++
++/* module parameters */
++static int video_nr = -1; /* video device minor (-1 ==> auto assign) */
++
++/* Maximum amount of memory to use for capture buffers.
++ * Default is 4800KB, enough to double-buffer SXGA.
++ */
++static int capture_mem = 1280*960*2*2;
++
++/*Size of video overlay framebuffer. This determines the maximum image size
++ *that can be previewed. Default is 600KB, enough for sxga.
++ */
++//static int overlay_mem = 320*240*2*2;
++
++#if 0
++
++/* -------------------overlay routines ------------------------------*/
++/* callback routine for overlay DMA completion. We just start another DMA
++ * transfer unless overlay has been turned off
++ */
++
++static void
++camera_core_overlay_callback(void *arg1, void *arg)
++{
++ struct camera_device *cam = (struct camera_device *)arg1;
++ int err;
++ unsigned long irqflags;
++ int i, j;
++ int count, index;
++ unsigned char *fb_buf = phys_to_virt((unsigned long)camera_dev->fbuf.base);
++
++ spin_lock_irqsave(&cam->overlay_lock, irqflags);
++
++ if (!cam->previewing || cam->overlay_cnt == 0) {
++ spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
++ return;
++ }
++
++ --cam->overlay_cnt;
++ sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;
++ sg_dma_len(&cam->overlay_sglist) = cam->pix.sizeimage;
++
++ count = 0;
++ j = ((cam->pix.width - 1) * cam->fbuf.fmt.bytesperline);
++ for (i = 0 ; i < cam->pix.sizeimage; i += cam->pix.bytesperline) {
++ for (index = 0; index < cam->pix.bytesperline; index++) {
++ fb_buf[j] = *(((unsigned char *) cam->overlay_base) +
++ i + index);
++ index++;
++ fb_buf[j + 1] = *(((unsigned char *) cam->overlay_base) + i + index);
++ j = j - cam->fbuf.fmt.bytesperline;
++ }
++ count += 2;
++ j = ((cam->pix.width - 1) * cam->fbuf.fmt.bytesperline) + count;
++ }
++
++ while (cam->overlay_cnt < 2) {
++ err = camera_core_sgdma_queue(cam, &cam->overlay_sglist, 1,
++ camera_core_overlay_callback, NULL);
++ if (err)
++ break;
++ ++cam->overlay_cnt;
++ }
++
++ spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
++
++}
++
++
++static void
++camera_core_start_overlay(struct camera_device *cam)
++{
++ int err;
++ unsigned long irqflags;
++
++ if (!cam->previewing)
++ return;
++
++ spin_lock_irqsave(&cam->overlay_lock, irqflags);
++
++ sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;
++ sg_dma_len(&cam->overlay_sglist)= cam->pix.sizeimage;
++ while (cam->overlay_cnt < 2) {
++ err = camera_core_sgdma_queue(cam, &cam->overlay_sglist, 1,
++ camera_core_overlay_callback, NULL);
++ if (err)
++ break;
++ ++cam->overlay_cnt;
++ }
++
++ spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
++}
++#endif
++
++/* ---------------------------------------------------------------------------- */
++
++int tcc_videobuf_inputenum(struct v4l2_input *input)
++{
++ /* default handler assumes 1 video input (the camera) */
++ int index = input->index;
++
++ memset(input, 0, sizeof(*input));
++ input->index = index;
++
++ if (index > 0)
++ return -EINVAL;
++
++ strlcpy(input->name, "camera", sizeof(input->name));
++ input->type = V4L2_INPUT_TYPE_CAMERA;
++
++ return 0;
++}
++
++int tcc_videobuf_g_input(unsigned int *input)
++{
++ *input = 0;
++
++ return 0;
++}
++
++int tcc_videobuf_s_input(unsigned int *input)
++{
++ if (*input > 0)
++ return -EINVAL;
++
++ return 0;
++}
++
++int tcc_videobuf_g_param(struct v4l2_streamparm *gparam)
++{
++ memset(gparam,0x00,sizeof(*gparam));
++ gparam->parm.capture.capturemode=hardware_data.cif_cfg.oper_mode;
++
++ return 0;
++}
++
++int tcc_videobuf_s_param(struct v4l2_streamparm *sparam)
++{
++ return 0;
++}
++
++int tcc_videobuf_enum_fmt(struct v4l2_fmtdesc *fmt)
++{
++ return sensor_enum_pixformat(fmt);
++}
++
++int tcc_videobuf_try_fmt(struct v4l2_format *fmt)
++{
++ //return sensor_try_format(&fmt->fmt.pix);
++
++ return 0;
++}
++
++int tcc_videobuf_g_fmt(struct v4l2_format *fmt)
++{
++ /* get the current format */
++ memset(&fmt->fmt.pix, 0, sizeof (fmt->fmt.pix));
++ fmt->fmt.pix = pix;
++
++ return 0;
++}
++
++int tcc_videobuf_s_fmt(struct v4l2_format *fmt)
++{
++ unsigned int temp_sizeimage = 0;
++ temp_sizeimage = pix.sizeimage;
++
++ pix.width = fmt->fmt.pix.width;
++ pix.height = fmt->fmt.pix.height;
++
++ return tccxxx_cif_set_resolution(fmt->fmt.pix.pixelformat, fmt->fmt.pix.width, fmt->fmt.pix.height);
++}
++
++int tcc_videobuf_querycap(struct v4l2_capability *cap)
++{
++ memset(cap, 0, sizeof(struct v4l2_capability));
++
++ strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
++ strlcpy(cap->card, vfd->name, sizeof(cap->card));
++
++ cap->bus_info[0] = '\0';
++ cap->version = KERNEL_VERSION(2, 6, 28);
++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
++ V4L2_CAP_VIDEO_OVERLAY |
++ V4L2_CAP_READWRITE |
++ V4L2_CAP_STREAMING;
++
++ return 0;
++}
++
++int tcc_videobuf_g_fbuf(struct v4l2_framebuffer *fargbuf)
++{
++ memcpy(fargbuf,&fbuf,sizeof(struct v4l2_framebuffer));
++
++ return 0;
++}
++
++int tcc_videobuf_s_fbuf(struct v4l2_framebuffer *fargbuf)
++{
++ fbuf.base = fargbuf->base;
++ fbuf.fmt = fargbuf->fmt;
++
++ return 0;
++}
++
++int tcc_videobuf_reqbufs(struct v4l2_requestbuffers *req)
++{
++ if (req->count < 1) {
++ printk("reqbufs: count invalid (%d)\n",req->count);
++ return -EINVAL;
++ }
++
++ if (req->memory != V4L2_MEMORY_MMAP &&
++ req->memory != V4L2_MEMORY_USERPTR &&
++ req->memory != V4L2_MEMORY_OVERLAY)
++ {
++ printk("reqbufs: memory type invalid\n");
++ return -EINVAL;
++ }
++
++ if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ {
++ printk("reqbufs: video type invalid\n");
++ return -EINVAL;
++ }
++
++ if (req->count > TCC_CAMERA_MAX_BUFNBRS)
++ req->count = TCC_CAMERA_MAX_BUFNBRS;
++
++ return tccxxx_cif_buffer_set(req);
++}
++
++
++int tcc_videobuf_querybuf(struct v4l2_buffer *buf)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *)(&hardware_data);
++ struct tccxxx_cif_buffer *cif_buf = data->buf + buf->index;
++ int index = buf->index;
++
++ if (index < 0 || index > data->cif_cfg.pp_num)
++ {
++ printk(KERN_WARNING "querybuf error : index : %d / %d",index, data->cif_cfg.pp_num);
++ return -EINVAL;
++ }
++
++ memset(buf, 0, sizeof(*buf));
++ buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ buf->index = index;
++ buf->flags = V4L2_BUF_FLAG_MAPPED;
++
++ buf->flags |= cif_buf->v4lbuf.flags;
++ buf->field = V4L2_FIELD_NONE;
++ buf->timestamp = cif_buf->v4lbuf.timestamp;
++ buf->sequence = cif_buf->v4lbuf.sequence;
++ buf->memory = V4L2_MEMORY_MMAP;
++ buf->m.offset = data->cif_cfg.preview_buf[index].p_Y;
++ cif_buf->v4lbuf.m.offset = data->cif_cfg.preview_buf[index].p_Y;
++
++ if(data->cif_cfg.fmt == 0) //yuv420
++ {
++ buf->length = PAGE_ALIGN(pix.width*pix.height*2); //»çÀÌÁî¿¡ ¸Â°Ô Á¶Á¤
++ }
++ else
++ {
++// buf->length = PAGE_ALIGN(pix.width*pix.height*3/2); //»çÀÌÁî¿¡ ¸Â°Ô Á¶Á¤
++ buf->length = PAGE_ALIGN(pix.width*pix.height*3/2); //»çÀÌÁî¿¡ ¸Â°Ô Á¶Á¤
++ }
++ cif_buf->v4lbuf.length = buf->length;
++ cif_buf->v4lbuf.index = index;
++
++ dprintk("<%d :: [PA]0x%x / flag: 0x%x >\n", index, (unsigned int)(cif_buf->v4lbuf.m.offset), (unsigned int)(buf->flags));
++
++ return 0;
++}
++
++int tcc_videobuf_qbuf(struct v4l2_buffer *buf)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *)(&hardware_data);
++ struct tccxxx_cif_buffer *cif_buf = data->buf + buf->index;
++ int retval = -EINVAL;
++
++ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EAGAIN;
++
++ if (buf->index < 0 || buf->index >= data->cif_cfg.pp_num)
++ return -EAGAIN;
++
++ if (cif_buf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED)
++ {
++ retval = 0; /* Already queued?? */
++ return -EAGAIN;
++ }
++
++ if (cif_buf->v4lbuf.flags & V4L2_BUF_FLAG_DONE)
++ {
++ retval = 0;
++ return -EAGAIN;
++ }
++
++ cif_buf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
++
++ list_add_tail(&cif_buf->buf_list, &data->list);
++
++ return 0;
++}
++
++int tcc_videobuf_dqbuf(struct v4l2_buffer *buf, struct file *file )
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *)(&hardware_data);
++ struct tccxxx_cif_buffer *cif_buf;
++ int retval = -EINVAL;
++
++ if(data->cif_cfg.esd_restart)
++ {
++ tccxxx_cif_cam_restart(&pix,xclk);
++ }
++
++ if(list_empty(&data->done_list))
++ {
++ if(file->f_flags&O_NONBLOCK)
++ {
++ return -EAGAIN;
++ }
++
++ if(wait_event_interruptible(data->frame_wait,!list_empty(&data->done_list)))
++ {
++ retval = -ERESTARTSYS;
++ return -EAGAIN;
++ }
++
++ /* Should probably recheck !list_empty() here */
++ if(list_empty(&data->done_list))
++ {
++ return -EAGAIN;
++ }
++ }
++ else
++ {
++ dprintk(" list no_empty!! \n");
++ }
++
++ cif_buf = list_entry(data->done_list.next, struct tccxxx_cif_buffer, buf_list);
++ list_del(data->done_list.next);
++
++ cif_buf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
++ memcpy(buf, &(cif_buf->v4lbuf),sizeof(struct v4l2_buffer));
++
++ return 0;
++}
++
++
++int tcc_videobuf_streamon(enum v4l2_buf_type *type)
++{
++ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EAGAIN;
++
++ return tccxxx_cif_start_stream();
++}
++
++//stop capture
++int tcc_videobuf_streamoff(enum v4l2_buf_type *type )
++{
++ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EAGAIN;
++
++ return tccxxx_cif_stop_stream();
++}
++
++int tcc_videobuf_cif_overlay(cif_SuperImpose *overlay)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++
++ memcpy(&(data->cif_cfg.si_overlay), overlay, sizeof(cif_SuperImpose));
++
++ tccxxx_cif_set_overlay();
++
++ return 0;
++}
++
++int tcc_videobuf_user_jpeg_capture(int * Jpeg_quality )
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++ struct tccxxx_cif_buffer *cif_buf;
++
++ while(!list_empty(&data->done_list))
++ {
++ cif_buf = list_entry(data->done_list.next, struct tccxxx_cif_buffer, buf_list);
++ list_del(&cif_buf->buf_list);
++
++ cif_buf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
++ cif_buf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
++
++ list_add_tail(&cif_buf->buf_list, &data->list);
++ }
++ data->done_list.next = &data->done_list;
++ data->cif_cfg.now_frame_num = 0;
++ data->cif_cfg.retry_cnt = 0;
++
++ return tccxxx_cif_capture(*Jpeg_quality);
++
++}
++
++
++int tcc_videobuf_user_get_capture_info(TCCXXX_JPEG_ENC_DATA * Jpeg_data )
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++
++ if(data->cif_cfg.jpg_info.jpg_len != 0)
++ {
++ memcpy((void*)data->cif_cfg.jpg_info.jpg_buf_addr+data->cif_cfg.jpg_info.jpg_len,
++ data->cif_cfg.jpg_info.jpg_hdr_addr,
++ data->cif_cfg.jpg_info.jpg_hdr_len);
++ }
++
++ Jpeg_data->src = data->cif_cfg.jpg_info.jpg_buf_addr;
++ Jpeg_data->bitstream_size = data->cif_cfg.jpg_info.jpg_len;
++ Jpeg_data->header_size = data->cif_cfg.jpg_info.jpg_hdr_len;
++ Jpeg_data->thumb_size = 0;
++ Jpeg_data->width = data->cif_cfg.main_set.target_x;
++ Jpeg_data->height = data->cif_cfg.main_set.target_y;
++
++ return 0;
++}
++
++/* ---------------------------------------------------------------------------- */
++
++
++static int camera_core_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
++{
++ //int err;
++
++ switch (cmd) {
++ case VIDIOC_ENUMINPUT:
++ return tcc_videobuf_inputenum((struct v4l2_input *)arg);
++
++ case VIDIOC_G_INPUT:
++ return tcc_videobuf_g_input((unsigned int*)arg);
++
++ case VIDIOC_S_INPUT:
++ return tcc_videobuf_s_input((unsigned int*)arg);
++
++ case VIDIOC_G_PARM:
++ return tcc_videobuf_g_param((struct v4l2_streamparm*)arg);
++
++ case VIDIOC_S_PARM:
++ return tcc_videobuf_s_param((struct v4l2_streamparm*)arg);
++
++ case VIDIOC_ENUM_FMT:
++ return tcc_videobuf_enum_fmt((struct v4l2_fmtdesc*)arg);
++
++ case VIDIOC_TRY_FMT:
++ return tcc_videobuf_try_fmt((struct v4l2_format*)arg);
++
++ case VIDIOC_G_FMT:
++ return tcc_videobuf_g_fmt((struct v4l2_format*)arg);
++
++ case VIDIOC_S_FMT:
++ return tcc_videobuf_s_fmt((struct v4l2_format*)arg);
++
++ case VIDIOC_QUERYCTRL:
++ return sensor_query_control((struct v4l2_queryctrl *)arg);
++
++ case VIDIOC_G_CTRL:
++ return sensor_get_control((struct v4l2_control *)arg);
++
++ case VIDIOC_S_CTRL:
++ return sensor_set_control((struct v4l2_control *)arg);
++
++ case VIDIOC_QUERYCAP:
++ return tcc_videobuf_querycap((struct v4l2_capability *)arg);
++
++ case VIDIOC_G_FBUF: /* Get the frame buffer parameters */
++ return tcc_videobuf_g_fbuf((struct v4l2_framebuffer *)arg);
++
++ case VIDIOC_S_FBUF: /* set the frame buffer parameters */
++ return tcc_videobuf_s_fbuf((struct v4l2_framebuffer *)arg);
++
++ case VIDIOC_REQBUFS:
++ return tcc_videobuf_reqbufs((struct v4l2_requestbuffers *)arg);
++
++ case VIDIOC_QUERYBUF:
++ return tcc_videobuf_querybuf((struct v4l2_buffer *)arg);
++
++ case VIDIOC_QBUF:
++ return tcc_videobuf_qbuf((struct v4l2_buffer *)arg);
++
++ case VIDIOC_DQBUF:
++ return tcc_videobuf_dqbuf((struct v4l2_buffer *)arg, file);
++
++ case VIDIOC_STREAMON:
++ return tcc_videobuf_streamon((enum v4l2_buf_type *)arg);
++
++ case VIDIOC_STREAMOFF:
++ return tcc_videobuf_streamoff((enum v4l2_buf_type *)arg);
++
++ case VIDIOC_OVERLAY:
++ return -EINVAL;
++
++ case VIDIOC_ENUMSTD:
++ case VIDIOC_G_STD:
++ case VIDIOC_S_STD:
++ case VIDIOC_QUERYSTD:
++ {
++ /* Digital cameras don't have an analog video standard,
++ * so we don't need to implement these ioctls.
++ */
++ return -EINVAL;
++ }
++ case VIDIOC_G_AUDIO:
++ case VIDIOC_S_AUDIO:
++ case VIDIOC_G_AUDOUT:
++ case VIDIOC_S_AUDOUT:
++ {
++ /* we don't have any audio inputs or outputs */
++ return -EINVAL;
++ }
++
++ case VIDIOC_G_JPEGCOMP:
++ case VIDIOC_S_JPEGCOMP:
++ {
++ /* JPEG compression is not supported */
++ return -EINVAL;
++ }
++
++ case VIDIOC_G_TUNER:
++ case VIDIOC_S_TUNER:
++ case VIDIOC_G_MODULATOR:
++ case VIDIOC_S_MODULATOR:
++ case VIDIOC_G_FREQUENCY:
++ case VIDIOC_S_FREQUENCY:
++ {
++ /* we don't have a tuner or modulator */
++ return -EINVAL;
++ }
++
++ case VIDIOC_ENUMOUTPUT:
++ case VIDIOC_G_OUTPUT:
++ case VIDIOC_S_OUTPUT:
++ {
++ /* we don't have any video outputs */
++ return -EINVAL;
++ }
++
++ case VIDIOC_USER_CIF_OVERLAY:
++ return tcc_videobuf_cif_overlay((cif_SuperImpose *)arg);
++
++ case VIDIOC_USER_JPEG_CAPTURE:
++ return tcc_videobuf_user_jpeg_capture((int *)arg);
++
++ case VIDIOC_USER_GET_CAPTURE_INFO:
++ return tcc_videobuf_user_get_capture_info((TCCXXX_JPEG_ENC_DATA *)arg);
++
++ default:
++ {
++ /* unrecognized ioctl */
++ //return -ENOIOCTLCMD;
++ }
++ }
++
++ return 0;
++}
++
++/*
++ * file operations
++ */
++
++static unsigned int camera_core_poll(struct file *file, struct poll_table_struct *wait)
++{
++ poll_wait(file, &(hardware_data.frame_wait), wait);
++
++ if(hardware_data.cif_cfg.cap_status == CAPTURE_DONE)
++ {
++ dprintk("POLL IN ! \r\n");
++ return POLLIN;
++ }
++ else if(hardware_data.cif_cfg.cap_status == CAPTURE_OVERFLOW)
++ {
++ dprintk("POLL ERR ! \r\n");
++ return POLLERR;
++ }
++ //else //cap_status = CAPTURE_NO_INT;
++ // return 0;
++
++ //if (!list_empty(&(hardware_data.done_list)))
++ // return POLLIN | POLLRDNORM;
++
++ return 0;
++
++}
++
++static ssize_t camera_core_read(struct file *file, char *data, size_t count, loff_t *ppos)
++{
++ struct camera_fh *fh = file->private_data;
++ struct tccxxx_camera_device *cam = fh->cam;
++ //int err;
++ //unsigned long irqflags;
++ //long timeout;
++#if 0 /* use video_buf to do capture */
++ int i;
++ for (i = 0; i < 14; i++)
++ videobuf_read_one(file, &fh->vbq, data, count, ppos);
++ i = videobuf_read_one(file, &fh->vbq, data, count, ppos);
++ return i;
++#endif
++
++ if (!cam->capture_base)
++ {
++ cam->capture_base = (unsigned long)dma_alloc_coherent(NULL,
++ cam->pix.sizeimage,
++ (dma_addr_t *) &cam->capture_base_phys,
++ GFP_KERNEL | GFP_DMA);
++ }
++ if (!cam->capture_base)
++ {
++ printk(KERN_ERR CAM_NAME ": cannot allocate capture buffer\n");
++ return 0;
++ }
++#if 0 //MCC
++ spin_lock_irqsave(&cam->capture_lock, irqflags);
++ cam->reading = fh;
++ cam->capture_started = 1;
++ sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys;
++ sg_dma_len(&cam->capture_sglist)= cam->pix.sizeimage;
++ spin_unlock_irqrestore(&cam->capture_lock, irqflags);
++
++ err = camera_core_sgdma_queue(cam, &cam->capture_sglist, 1,
++ camera_core_capture_callback, NULL);
++
++ /* Wait till DMA is completed */
++ timeout = HZ * 10;
++ cam->capture_completed = 0;
++ while (cam->capture_completed == 0) {
++ timeout = interruptible_sleep_on_timeout
++ (&cam->new_video_frame, timeout);
++ if (timeout == 0) {
++ printk(KERN_ERR CAM_NAME ": timeout waiting video frame\n");
++ return -EIO; /* time out */
++ }
++ }
++ /* copy the data to the user buffer */
++ err = copy_to_user(data, (void *)cam->capture_base, cam->pix.sizeimage);
++ return (cam->pix.sizeimage - err);
++#endif
++ return 0;
++}
++
++#if 0
++static void camera_core_vm_open(struct vm_area_struct *vma)
++{
++// long idx = (long)vma->vm_private_data;
++
++// camera_dev->hardware_data.vma_use_count[idx]++;
++}
++
++static void camera_core_vm_close(struct vm_area_struct *vma)
++{
++// long idx = (long)vma->vm_private_data;
++
++// camera_dev->hardware_data->vma_use_count[idx]--;
++}
++
++static struct vm_operations_struct camera_core_vm_ops = {
++ .open = camera_core_vm_open,
++ .close = camera_core_vm_close,
++};
++
++#endif
++
++static int camera_core_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ if(remap_pfn_range(vma,vma->vm_start, vma->vm_pgoff , vma->vm_end - vma->vm_start, vma->vm_page_prot))
++ {
++ return -EAGAIN;
++ }
++
++ vma->vm_ops = NULL;
++ vma->vm_flags |= VM_IO;
++ vma->vm_flags |= VM_RESERVED;
++
++ return 0;
++}
++
++static int camera_core_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++
++ return video_usercopy(inode, file, cmd, arg, camera_core_do_ioctl);
++}
++
++static int camera_core_release(struct inode *inode, struct file *file)
++{
++ printk("camera_core_release \n");
++
++ tccxxx_cif_close();
++ sensor_cleanup();
++
++ // leesw, 2008.03.31, cam power off
++ //PM_CAM_PWR_OFF();
++
++ return 0;
++}
++
++static int camera_core_open(struct inode *inode, struct file *file)
++{
++ int minor = iminor(inode);
++ int status;
++
++ if (!vfd || (vfd->minor != minor))
++ return -ENODEV;
++
++ dprintk("Sensor PWR-ON \n");
++
++ // leesw, 2008.03.31, cam power on
++ //PM_CAM_PWR_ON();
++ msleep(5);
++
++ dprintk("Sensor Device-Init \n");
++
++ /* initialize the sensor and define a default capture format cam->pix */
++ status = sensor_init(&pix);
++ if (status)
++ {
++ TDD_CIF_Termination();
++ printk(KERN_ERR CAM_NAME ": cannot initialize sensor\n");
++
++ // leesw, 2008.03.31, cam power off
++ //PM_CAM_PWR_OFF();
++
++ return status;
++ }
++ //msleep(5);
++
++ dprintk("Sensor Register-Init \n");
++ /* program the sensor for the capture format and rate */
++ if (sensor_configure(&pix,xclk))
++ {
++ printk (KERN_ERR CAM_NAME ": Camera sensor configuration failed\n");
++ return -ENODEV;
++ }
++
++ // ioremap½Ã probe¿¡¼­ ¼öÇà½Ã virtual address problemÀ¸·Î À̵¿.!!
++ if (tccxxx_cif_init())
++ {
++ printk(KERN_ERR CAM_NAME ": cannot initialize interface hardware\n");
++ return -ENODEV;
++ }
++
++ if (tccxxx_cif_open())
++ {
++ printk (KERN_ERR CAM_NAME ": Camera IF configuration failed\n");
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++
++static struct file_operations camera_core_fops =
++{
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .read = camera_core_read,
++ .poll = camera_core_poll,
++ .ioctl = camera_core_ioctl,
++ .mmap = camera_core_mmap,
++ .open = camera_core_open,
++ .release = camera_core_release,
++};
++
++
++#ifdef CONFIG_HAS_EARLYSUSPEND
++static void tcc92xx_camera_early_suspend(struct early_suspend *h);
++static void tcc92xx_camera_late_resume(struct early_suspend *h);
++#endif
++
++static int __init camera_core_probe(struct platform_device *pdev)
++{
++ int status;
++
++ dprintk("camera_core_probe \n");
++
++ /* initialize the video_device struct */
++ vfd = video_device_alloc();
++ if (!vfd)
++ {
++ printk(KERN_ERR CAM_NAME": could not allocate video device struct\n");
++ status = -ENOMEM;
++ goto err0;
++ }
++
++ vfd->release = video_device_release;
++
++ strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
++ //vfd->type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CHROMAKEY;
++
++ /* need to register for a VID_HARDWARE_* ID in videodev.h */
++ vfd->fops = &camera_core_fops;
++// video_set_drvdata(vfd, NULL);
++ vfd->minor = -1;
++
++
++ /* initialize the camera interface */
++/* // ioremap½Ã probe¿¡¼­ ¼öÇà½Ã virtual address problemÀ¸·Î À̵¿.!!
++ status = tccxxx_cif_init();
++ if (status != 0)
++ {
++ printk(KERN_ERR CAM_NAME ": cannot initialize interface hardware\n");
++ status = -ENODEV;
++ goto err1;
++ }
++*/
++
++// platform_set_drvdata(pdev, cam);
++
++ if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0)
++ {
++ printk(KERN_ERR CAM_NAME ": could not register Video for Linux device\n");
++ status = -ENODEV;
++ goto err1;
++ }
++
++ printk(KERN_INFO CAM_NAME ": registered device video%d [v4l2]\n", vfd->minor);
++#ifdef CONFIG_HAS_EARLYSUSPEND
++ early_suspend.suspend = tcc92xx_camera_early_suspend;
++ early_suspend.resume = tcc92xx_camera_late_resume;
++ early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
++ register_early_suspend(&early_suspend);
++#endif
++
++// tmp_i2c_add();
++ return 0;
++
++
++ err1:
++ video_device_release(vfd);
++ err0:
++ return status;
++}
++
++static int camera_core_remove(struct platform_device *pdev)
++{
++ dprintk("camera_core_remove \n");
++
++// tmp_i2c_del();
++ video_unregister_device(vfd);
++ video_device_release(vfd);
++ return 0;
++}
++
++int camera_core_suspend(struct platform_device *pdev, pm_message_t state)
++{
++
++
++ return 0;
++}
++
++
++
++int camera_core_resume(struct platform_device *pdev)
++{
++
++
++
++ return 0;
++}
++
++
++
++
++static struct platform_driver camera_core_driver = {
++ .driver = {
++ .name = CAM_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = camera_core_probe,
++ .remove = camera_core_remove,
++ .suspend = camera_core_suspend,
++ .resume = camera_core_resume,
++};
++
++
++#ifdef CONFIG_HAS_EARLYSUSPEND
++static void tcc92xx_camera_early_suspend(struct early_suspend *h)
++{
++ printk(" %s\n", __func__);
++ camera_core_driver.suspend;
++
++}
++static void tcc92xx_camera_late_resume(struct early_suspend *h)
++{
++ printk(" %s\n", __func__);
++ camera_core_driver.resume;
++}
++
++#endif
++
++
++static struct platform_device camera_core_device = {
++ .name = CAM_NAME,
++ .dev = {
++ .release = NULL,
++ },
++ .id = 0,
++};
++
++void __exit
++camera_core_cleanup(void)
++{
++ dprintk("camera_core_cleanup \n");
++
++ platform_driver_unregister(&camera_core_driver);
++ platform_device_unregister(&camera_core_device);
++
++ return;
++}
++
++static char banner[] __initdata = KERN_INFO "TCCXXX Camera driver initializing\n";
++
++int __init
++camera_core_init(void)
++{
++ dprintk("camera_core_init \n");
++
++ printk(banner);
++ platform_device_register(&camera_core_device);
++ platform_driver_register(&camera_core_driver);
++
++ return 0;
++}
++
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_VERSION(DRIVER_VERSION);
++MODULE_LICENSE("GPL");
++module_param(video_nr, int, 0);
++MODULE_PARM_DESC(video_nr, "Minor number for video device (-1 ==> auto assign)");
++module_param(capture_mem, int, 0);
++MODULE_PARM_DESC(capture_mem, "Maximum amount of memory for capture buffers (default 4800KB)");
++module_init(camera_core_init);
++module_exit(camera_core_cleanup);
++
+diff --git a/drivers/media/video/tcccam/camera_core.h b/drivers/media/video/tcccam/camera_core.h
+new file mode 100644
+index 0000000..a1daac6
+--- /dev/null
++++ b/drivers/media/video/tcccam/camera_core.h
+@@ -0,0 +1,137 @@
++/*
++ * drivers/media/video/tcccam/camera_core.h
++ *
++ * Copyright (C) 2008 Telechips, Inc.
++ *
++ * This package is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#ifndef CAMERA_CORE__H
++#define CAMERA_CORE__H
++
++struct camera_fh;
++
++#include <media/videobuf-dma-sg.h>
++#include <asm/scatterlist.h>
++//#include <linux/wakelock.h>
++#ifdef CONFIG_HAS_EARLYSUSPEND
++#include <linux/earlysuspend.h>
++#endif
++struct tccxxx_camera_device;
++
++typedef void (*dma_callback_t)(void *arg1, void *arg2);
++
++/* per-device data structure */
++struct tccxxx_camera_device {
++ struct device dev;
++ struct video_device *vfd;
++
++ spinlock_t overlay_lock; /* spinlock for overlay DMA counter */
++ int overlay_cnt; /* count of queued overlay DMA xfers */
++ unsigned long overlay_base_phys;
++ unsigned long overlay_base;
++ unsigned long overlay_size;
++
++ spinlock_t vbq_lock; /* spinlock for videobuf queues */
++ unsigned long field_count; /* field counter for videobuf_buffer */
++
++ /* The img_lock is used to serialize access to the image parameters for
++ * overlay and capture. Need to use spin_lock_irq when writing to the
++ * reading, streaming, and previewing parameters. A regular spin_lock
++ * will suffice for all other cases.
++ */
++ spinlock_t img_lock;
++
++ /* We allow reading from at most one filehandle at a time.
++ * non-NULL means reading is in progress.
++ */
++ struct camera_fh *reading;
++ /* We allow streaming from at most one filehandle at a time.
++ * non-NULL means streaming is in progress.
++ */
++ struct camera_fh *streaming;
++ /* We allow previewing from at most one filehandle at a time.
++ * non-NULL means previewing is in progress.
++ */
++ struct camera_fh *previewing;
++
++ /* capture parameters (frame rate, number of buffers) */
++ struct v4l2_captureparm cparm;
++
++ /* This is the frame period actually requested by the user. */
++ struct v4l2_fract nominal_timeperframe;
++
++ /* frequency (in Hz) of camera interface xclk output */
++ unsigned long xclk;
++
++ /* Pointer to the sensor interface ops */
++ struct tcc_camera_sensor *cam_sensor;
++ void *sensor_data;
++
++ /* Pointer to the camera interface hardware ops */
++ struct camera_hardware *cam_hardware;
++ void *hardware_data; //struct TCCxxxCIF
++
++ /* pix defines the size and pixel format of the image captured by the
++ * sensor. This also defines the size of the framebuffers. The
++ * same pool of framebuffers is used for video capture and video
++ * overlay. These parameters are set/queried by the
++ * VIDIOC_S_FMT/VIDIOC_G_FMT ioctls with a CAPTURE buffer type.
++ */
++ struct v4l2_pix_format pix;
++ struct v4l2_pix_format pix2;
++
++ /* crop defines the size and offset of the video overlay source window
++ * within the framebuffer. These parameters are set/queried by the
++ * VIDIOC_S_CROP/VIDIOC_G_CROP ioctls with an OVERLAY buffer type.
++ * The cropping rectangle allows a subset of the captured image to be
++ * previewed. It only affects the portion of the image previewed, not
++ * captured; the entire camera image is always captured.
++ */
++ struct v4l2_rect crop;
++
++ /* win defines the size and offset of the video overlay target window
++ * within the video display. These parameters are set/queried by the
++ * VIDIOC_S_FMT/VIDIOC_G_FMT ioctls with an OVERLAY buffer type.
++ */
++ struct v4l2_window win;
++
++ /* fbuf reflects the size of the video display. It is queried with the
++ * VIDIOC_G_FBUF ioctl. The size of the video display cannot be
++ * changed with the VIDIOC_S_FBUF ioctl.
++ */
++ struct v4l2_framebuffer fbuf;
++
++ /* end of generic stuff, the above should be common to all omaps */
++
++ /* note, 2420 uses videobuf to do caprure, it is more memory efficient
++ we need 1710 and 2420 do capture in the same way */
++ /* Variables to store the capture state */
++ /* Wait till DMA is completed */
++ //wkjung
++ //wait_queue_head_t new_video_frame;
++
++ char capture_completed;
++ char capture_started;
++ spinlock_t capture_lock;
++ unsigned long capture_base;
++ unsigned long capture_base_phys;
++ struct mutex lock;
++ char active;
++};
++
++/* per-filehandle data structure */
++struct camera_fh {
++ struct tccxxx_camera_device *cam;
++ enum v4l2_buf_type type;
++};
++
++#define CAM_NAME "tccxxx-camera"
++
++#endif /* CAMERA_CORE__H */
+diff --git a/drivers/media/video/tcccam/camera_hw_if.h b/drivers/media/video/tcccam/camera_hw_if.h
+new file mode 100644
+index 0000000..9a956de
+--- /dev/null
++++ b/drivers/media/video/tcccam/camera_hw_if.h
+@@ -0,0 +1,22 @@
++/*
++ * drivers/media/video/tcccam/camera_hw_if.h
++ *
++ * Copyright (C) 2008 Telechips, Inc.
++ *
++ * Camera interface to TCC camera capture drivers
++ * Camera interface hardware driver should implement this interface
++ *
++ * This package is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#ifndef TCCXX_CAMERA_HW_IF_H
++#define TCCXX_CAMERA_HW_IF_H
++
++#define LEN_HW_IF_NAME 31
++#endif /* TCC78XX_CAMERA_HW_IF_H */
+diff --git a/drivers/media/video/tcccam/mt9d111_2mp.c b/drivers/media/video/tcccam/mt9d111_2mp.c
+new file mode 100644
+index 0000000..9af8bd4
+--- /dev/null
++++ b/drivers/media/video/tcccam/mt9d111_2mp.c
+@@ -0,0 +1,698 @@
++/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
++
++ CAMERA API M O D U L E
++
++ EDIT HISTORY FOR MODULE
++
++when who what, where, why
++-------- --- -------------------------------------------------------
++10/xx/08 Telechips Created file.
++*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
++
++/*===========================================================================
++
++ INCLUDE FILES FOR MODULE
++
++===========================================================================*/
++#include "sensor_if.h"
++
++#ifdef CONFIG_VIDEO_CAMERA_SENSOR_MT9D111
++
++/* Array of image sizes supported by MT9D111. These must be ordered from
++ * smallest image size to largest.
++ */
++struct capture_size sensor_sizes[] = {
++ { 1600, 1200 }, /* UXGA */
++ { 1280, 960 }, /* SXGA */
++ { 1024, 768 }, /* XGA */
++ { 800, 600 }, /* SVGA */
++ { 640, 480 }, /* VGA */
++ { 320, 240 }, /* QVGA */
++ { 176, 144 }, /* QCIF */
++};
++
++
++/* register initialization tables for sensor */
++/* common sensor register initialization for all image sizes, pixel formats,
++ * and frame rates
++ */
++static struct sensor_reg sensor_common[] = {
++ {0xF0, 0x0000},
++ {0x05, 0x012C}, // HORZ_BLANK_B
++ {0x06, 0x004E}, // VERT_BLANK_B
++ {0x07, 0x044C}, // HORZ_BLANK_A
++ {0x08, 0x0023}, // VERT_BLANK_A
++ {0x20, 0x0300}, // READ_MODE_B
++ {0x21, 0x8000}, // READ_MODE_A
++ {0x66, 0x1802}, // PLL_REG
++ {0x67, 0x0501}, // PLL2_REG
++ {0x65, 0xA000}, // CLOCK_ENABLING
++
++ {0x65, 0x2000}, // CLOCK_ENABLING
++
++ // State Param.
++ {0xF0, 0x0001},
++ {0xC6, 0xA122}, //SEQ_PREVIEW_0_AE
++ {0xC8, 0x0001}, //SEQ_PREVIEW_0_AE
++ {0xC6, 0xA123}, //SEQ_PREVIEW_0_FD
++ {0xC8, 0x0000}, //SEQ_PREVIEW_0_FD
++ {0xC6, 0xA124}, //SEQ_PREVIEW_0_AWB
++ {0xC8, 0x0001}, //SEQ_PREVIEW_0_AWB
++ {0xC6, 0xA125}, //SEQ_PREVIEW_0_AF
++ {0xC8, 0x0000}, //SEQ_PREVIEW_0_AF
++ {0xC6, 0xA126}, //SEQ_PREVIEW_0_HG
++ {0xC8, 0x0001}, //SEQ_PREVIEW_0_HG
++ {0xC6, 0xA127}, //SEQ_PREVIEW_0_FLASH
++ {0xC8, 0x0000}, //SEQ_PREVIEW_0_FLASH
++ {0xC6, 0xA128}, //SEQ_PREVIEW_0_SKIPFRAME
++ {0xC8, 0x0040}, //SEQ_PREVIEW_0_SKIPFRAME
++ {0xC6, 0xA129}, //SEQ_PREVIEW_1_AE
++ {0xC8, 0x0003}, //SEQ_PREVIEW_1_AE
++ {0xC6, 0xA12A}, //SEQ_PREVIEW_1_FD
++ {0xC8, 0x0002}, //SEQ_PREVIEW_1_FD
++ {0xC6, 0xA12B}, //SEQ_PREVIEW_1_AWB
++ {0xC8, 0x0003}, //SEQ_PREVIEW_1_AWB
++ {0xC6, 0xA12C}, //SEQ_PREVIEW_1_AF
++ {0xC8, 0x0000}, //SEQ_PREVIEW_1_AF
++ {0xC6, 0xA12D}, //SEQ_PREVIEW_1_HG
++ {0xC8, 0x0003}, //SEQ_PREVIEW_1_HG
++ {0xC6, 0xA12E}, //SEQ_PREVIEW_1_FLASH
++ {0xC8, 0x0000}, //SEQ_PREVIEW_1_FLASH
++ {0xC6, 0xA12F}, //SEQ_PREVIEW_1_SKIPFRAME
++ {0xC8, 0x0000}, //SEQ_PREVIEW_1_SKIPFRAME
++ {0xC6, 0xA130}, //SEQ_PREVIEW_2_AE
++ {0xC8, 0x0004}, //SEQ_PREVIEW_2_AE
++ {0xC6, 0xA131}, //SEQ_PREVIEW_2_FD
++ {0xC8, 0x0000}, //SEQ_PREVIEW_2_FD
++ {0xC6, 0xA132}, //SEQ_PREVIEW_2_AWB
++ {0xC8, 0x0001}, //SEQ_PREVIEW_2_AWB
++ {0xC6, 0xA133}, //SEQ_PREVIEW_2_AF
++ {0xC8, 0x0000}, //SEQ_PREVIEW_2_AF
++ {0xC6, 0xA134}, //SEQ_PREVIEW_2_HG
++ {0xC8, 0x0001}, //SEQ_PREVIEW_2_HG
++ {0xC6, 0xA135}, //SEQ_PREVIEW_2_FLASH
++ {0xC8, 0x0000}, //SEQ_PREVIEW_2_FLASH
++ {0xC6, 0xA136}, //SEQ_PREVIEW_2_SKIPFRAME
++ {0xC8, 0x0000}, //SEQ_PREVIEW_2_SKIPFRAME
++ {0xC6, 0xA137}, //SEQ_PREVIEW_3_AE
++ {0xC8, 0x0000}, //SEQ_PREVIEW_3_AE
++ {0xC6, 0xA138}, //SEQ_PREVIEW_3_FD
++ {0xC8, 0x0000}, //SEQ_PREVIEW_3_FD
++ {0xC6, 0xA139}, //SEQ_PREVIEW_3_AWB
++ {0xC8, 0x0000}, //SEQ_PREVIEW_3_AWB
++ {0xC6, 0xA13A}, //SEQ_PREVIEW_3_AF
++ {0xC8, 0x0000}, //SEQ_PREVIEW_3_AF
++ {0xC6, 0xA13B}, //SEQ_PREVIEW_3_HG
++ {0xC8, 0x0000}, //SEQ_PREVIEW_3_HG
++ {0xC6, 0xA13C}, //SEQ_PREVIEW_3_FLASH
++ {0xC8, 0x0000}, //SEQ_PREVIEW_3_FLASH
++ {0xC6, 0xA13D}, //SEQ_PREVIEW_3_SKIPFRAME
++ {0xC8, 0x0040}, //SEQ_PREVIEW_3_SKIPFRAME
++ // Sensor Timing Setting (54MHz)
++ {0xC6, 0x2703}, //MODE_OUTPUT_WIDTH_A
++ {0xC8, 0x0320}, //MODE_OUTPUT_WIDTH_A
++ {0xC6, 0x2705}, //MODE_OUTPUT_HEIGHT_A
++ {0xC8, 0x0258}, //MODE_OUTPUT_HEIGHT_A
++ {0xC6, 0x2707}, //MODE_OUTPUT_WIDTH_B
++ {0xC8, 0x0640}, //MODE_OUTPUT_WIDTH_B
++ {0xC6, 0x2709}, //MODE_OUTPUT_HEIGHT_B
++ {0xC8, 0x04B0}, //MODE_OUTPUT_HEIGHT_B
++ {0xC6, 0x270B}, //MODE_CONFIG
++ {0xC8, 0x0030}, //MODE_CONFIG
++ {0xC6, 0x270F}, //MODE_SENSOR_ROW_START_A
++ {0xC8, 0x001C}, //MODE_SENSOR_ROW_START_A
++ {0xC6, 0x2711}, //MODE_SENSOR_COL_START_A
++ {0xC8, 0x003C}, //MODE_SENSOR_COL_START_A
++ {0xC6, 0x2713}, //MODE_SENSOR_ROW_HEIGHT_A
++ {0xC8, 0x04B0}, //MODE_SENSOR_ROW_HEIGHT_A
++ {0xC6, 0x2715}, //MODE_SENSOR_COL_WIDTH_A
++ {0xC8, 0x0640}, //MODE_SENSOR_COL_WIDTH_A
++ {0xC6, 0x2717}, //MODE_SENSOR_X_DELAY_A
++ {0xC8, 0x01AC}, //MODE_SENSOR_X_DELAY_A
++ {0xC6, 0x2719}, //MODE_SENSOR_ROW_SPEED_A
++ {0xC8, 0x0011}, //MODE_SENSOR_ROW_SPEED_A
++ {0xC6, 0x271B}, //MODE_SENSOR_ROW_START_B
++ {0xC8, 0x001C}, //MODE_SENSOR_ROW_START_B
++ {0xC6, 0x271D}, //MODE_SENSOR_COL_START_B
++ {0xC8, 0x003C}, //MODE_SENSOR_COL_START_B
++ {0xC6, 0x271F}, //MODE_SENSOR_ROW_HEIGHT_B
++ {0xC8, 0x04B0}, //MODE_SENSOR_ROW_HEIGHT_B
++ {0xC6, 0x2721}, //MODE_SENSOR_COL_WIDTH_B
++ {0xC8, 0x0640}, //MODE_SENSOR_COL_WIDTH_B
++ {0xC6, 0x2723}, //MODE_SENSOR_X_DELAY_B
++ {0xC8, 0x0359}, //MODE_SENSOR_X_DELAY_B
++ {0xC6, 0x2725}, //MODE_SENSOR_ROW_SPEED_B
++ {0xC8, 0x0011}, //MODE_SENSOR_ROW_SPEED_B
++ {0xC6, 0x2727}, //MODE_CROP_X0_A
++ {0xC8, 0x0000}, //MODE_CROP_X0_A
++ {0xC6, 0x2729}, //MODE_CROP_X1_A
++ {0xC8, 0x0320}, //MODE_CROP_X1_A
++ {0xC6, 0x272B}, //MODE_CROP_Y0_A
++ {0xC8, 0x0000}, //MODE_CROP_Y0_A
++ {0xC6, 0x272D}, //MODE_CROP_Y1_A
++ {0xC8, 0x0258}, //MODE_CROP_Y1_A
++ {0xC6, 0x2735}, //MODE_CROP_X0_B
++ {0xC8, 0x0000}, //MODE_CROP_X0_B
++ {0xC6, 0x2737}, //MODE_CROP_X1_B
++ {0xC8, 0x0640}, //MODE_CROP_X1_B
++ {0xC6, 0x2739}, //MODE_CROP_Y0_B
++ {0xC8, 0x0000}, //MODE_CROP_Y0_B
++ {0xC6, 0x273B}, //MODE_CROP_Y1_B
++ {0xC8, 0x04B0}, //MODE_CROP_Y1_B
++ // Gamma
++
++ {0xC6, 0xA743}, //MODE_GAM_CONT_A
++ {0xC8, 0x0041}, //MODE_GAM_CONT_A
++ {0xC6, 0xA744}, //MODE_GAM_CONT_B
++ {0xC8, 0x0041}, //MODE_GAM_CONT_B
++ {0xC6, 0xA745}, //MODE_GAM_TABLE_A_0
++ {0xC8, 0x0000}, //MODE_GAM_TABLE_A_0
++ {0xC6, 0xA746}, //MODE_GAM_TABLE_A_1
++ {0xC8, 0x0009}, //MODE_GAM_TABLE_A_1
++ {0xC6, 0xA747}, //MODE_GAM_TABLE_A_2
++ {0xC8, 0x0012}, //MODE_GAM_TABLE_A_2
++ {0xC6, 0xA748}, //MODE_GAM_TABLE_A_3
++ {0xC8, 0x0025}, //MODE_GAM_TABLE_A_3
++ {0xC6, 0xA749}, //MODE_GAM_TABLE_A_4
++ {0xC8, 0x0045}, //MODE_GAM_TABLE_A_4
++ {0xC6, 0xA74A}, //MODE_GAM_TABLE_A_5
++ {0xC8, 0x0061}, //MODE_GAM_TABLE_A_5
++ {0xC6, 0xA74B}, //MODE_GAM_TABLE_A_6
++ {0xC8, 0x0075}, //MODE_GAM_TABLE_A_6
++ {0xC6, 0xA74C}, //MODE_GAM_TABLE_A_7
++ {0xC8, 0x0086}, //MODE_GAM_TABLE_A_7
++ {0xC6, 0xA74D}, //MODE_GAM_TABLE_A_8
++ {0xC8, 0x0094}, //MODE_GAM_TABLE_A_8
++ {0xC6, 0xA74E}, //MODE_GAM_TABLE_A_9
++ {0xC8, 0x00A1}, //MODE_GAM_TABLE_A_9
++ {0xC6, 0xA74F}, //MODE_GAM_TABLE_A_10
++ {0xC8, 0x00AE}, //MODE_GAM_TABLE_A_10
++ {0xC6, 0xA750}, //MODE_GAM_TABLE_A_11
++ {0xC8, 0x00B9}, //MODE_GAM_TABLE_A_11
++ {0xC6, 0xA751}, //MODE_GAM_TABLE_A_12
++ {0xC8, 0x00C4}, //MODE_GAM_TABLE_A_12
++ {0xC6, 0xA752}, //MODE_GAM_TABLE_A_13
++ {0xC8, 0x00CF}, //MODE_GAM_TABLE_A_13
++ {0xC6, 0xA753}, //MODE_GAM_TABLE_A_14
++ {0xC8, 0x00D9}, //MODE_GAM_TABLE_A_14
++ {0xC6, 0xA754}, //MODE_GAM_TABLE_A_15
++ {0xC8, 0x00E3}, //MODE_GAM_TABLE_A_15
++ {0xC6, 0xA755}, //MODE_GAM_TABLE_A_16
++ {0xC8, 0x00ED}, //MODE_GAM_TABLE_A_16
++ {0xC6, 0xA756}, //MODE_GAM_TABLE_A_17
++ {0xC8, 0x00F6}, //MODE_GAM_TABLE_A_17
++ {0xC6, 0xA757}, //MODE_GAM_TABLE_A_18
++ {0xC8, 0x00FF}, //MODE_GAM_TABLE_A_18
++ {0xC6, 0xA758}, //MODE_GAM_TABLE_B_0
++ {0xC8, 0x0000}, //MODE_GAM_TABLE_B_0
++ {0xC6, 0xA759}, //MODE_GAM_TABLE_B_1
++ {0xC8, 0x0009}, //MODE_GAM_TABLE_B_1
++ {0xC6, 0xA75A}, //MODE_GAM_TABLE_B_2
++ {0xC8, 0x0012}, //MODE_GAM_TABLE_B_2
++ {0xC6, 0xA75B}, //MODE_GAM_TABLE_B_3
++ {0xC8, 0x0025}, //MODE_GAM_TABLE_B_3
++ {0xC6, 0xA75C}, //MODE_GAM_TABLE_B_4
++ {0xC8, 0x0045}, //MODE_GAM_TABLE_B_4
++ {0xC6, 0xA75D}, //MODE_GAM_TABLE_B_5
++ {0xC8, 0x0061}, //MODE_GAM_TABLE_B_5
++ {0xC6, 0xA75E}, //MODE_GAM_TABLE_B_6
++ {0xC8, 0x0075}, //MODE_GAM_TABLE_B_6
++ {0xC6, 0xA75F}, //MODE_GAM_TABLE_B_7
++ {0xC8, 0x0086}, //MODE_GAM_TABLE_B_7
++ {0xC6, 0xA760}, //MODE_GAM_TABLE_B_8
++ {0xC8, 0x0094}, //MODE_GAM_TABLE_B_8
++ {0xC6, 0xA761}, //MODE_GAM_TABLE_B_9
++ {0xC8, 0x00A1}, //MODE_GAM_TABLE_B_9
++ {0xC6, 0xA762}, //MODE_GAM_TABLE_B_10
++ {0xC8, 0x00AE}, //MODE_GAM_TABLE_B_10
++ {0xC6, 0xA763}, //MODE_GAM_TABLE_B_11
++ {0xC8, 0x00B9}, //MODE_GAM_TABLE_B_11
++ {0xC6, 0xA764}, //MODE_GAM_TABLE_B_12
++ {0xC8, 0x00C4}, //MODE_GAM_TABLE_B_12
++ {0xC6, 0xA765}, //MODE_GAM_TABLE_B_13
++ {0xC8, 0x00CF}, //MODE_GAM_TABLE_B_13
++ {0xC6, 0xA766}, //MODE_GAM_TABLE_B_14
++ {0xC8, 0x00D9}, //MODE_GAM_TABLE_B_14
++ {0xC6, 0xA767}, //MODE_GAM_TABLE_B_15
++ {0xC8, 0x00E3}, //MODE_GAM_TABLE_B_15
++ {0xC6, 0xA768}, //MODE_GAM_TABLE_B_16
++ {0xC8, 0x00ED}, //MODE_GAM_TABLE_B_16
++ {0xC6, 0xA769}, //MODE_GAM_TABLE_B_17
++ {0xC8, 0x00F6}, //MODE_GAM_TABLE_B_17
++ {0xC6, 0xA76A}, //MODE_GAM_TABLE_B_18
++ {0xC8, 0x00FF}, //MODE_GAM_TABLE_B_18
++ // AE Param.
++ {0xC6, 0x276D}, //MODE_FIFO_CONF1_A
++ {0xC8, 0xE0E2}, //MODE_FIFO_CONF1_A
++ {0xC6, 0xA76F}, //MODE_FIFO_CONF2_A
++ {0xC8, 0x00E1}, //MODE_FIFO_CONF2_A
++ {0xC6, 0x2774}, //MODE_FIFO_CONF1_B
++ {0xC8, 0xE0E1}, //MODE_FIFO_CONF1_B
++ {0xC6, 0xA776}, //MODE_FIFO_CONF2_B
++ {0xC8, 0x00E1}, //MODE_FIFO_CONF2_B
++ {0xC6, 0x220B}, //AE_MAX_R12
++ {0xC8, 0x024D}, //AE_MAX_R12
++ {0xC6, 0xA217}, //AE_INDEX_TH23
++ {0xC8, 0x0008}, //AE_INDEX_TH23
++ {0xC6, 0x2228}, //AE_ROWTIME
++ {0xC8, 0x01DB}, //AE_ROWTIME
++ {0xC6, 0x222F}, //AE_R9_STEP
++ {0xC8, 0x0075}, //AE_R9_STEP
++ {0xC6, 0xA408}, //FD_SEARCH_F1_50
++ {0xC8, 0x0016}, //FD_SEARCH_F1_50
++ {0xC6, 0xA409}, //FD_SEARCH_F2_50
++ {0xC8, 0x0018}, //FD_SEARCH_F2_50
++ {0xC6, 0xA40A}, //FD_SEARCH_F1_60
++ {0xC8, 0x001B}, //FD_SEARCH_F1_60
++ {0xC6, 0xA40B}, //FD_SEARCH_F2_60
++ {0xC8, 0x001D}, //FD_SEARCH_F2_60
++ {0xC6, 0x2411}, //FD_R9_STEP60
++ {0xC8, 0x0075}, //FD_R9_STEP60
++ {0xC6, 0x2413}, //FD_R9_STEP50
++ {0xC8, 0x008D}, //FD_R9_STEP50
++ // Initial - Refresh
++ {0xC6, 0xA103}, //SEQ_CMD
++ {0xC8, 0x0005}, //SEQ_CMD
++
++ {0xF0, 0x0001},
++ {0xC6, 0xA103},
++ {0xC8, 0x0006}, //SEQ_CMD
++
++ // Lens Shading
++ {0xF0, 0x0002},
++ {0x80, 0x01F0}, // LENS_CORRECTION_CONTROL
++ {0x81, 0x6432}, // ZONE_BOUNDS_X1_X2
++ {0x82, 0x3296}, // ZONE_BOUNDS_X0_X3
++ {0x83, 0x9664}, // ZONE_BOUNDS_X4_X5
++ {0x84, 0x5028}, // ZONE_BOUNDS_Y1_Y2
++ {0x85, 0x2878}, // ZONE_BOUNDS_Y0_Y3
++ {0x86, 0x7850}, // ZONE_BOUNDS_Y4_Y5
++ {0x87, 0x0000}, // CENTER_OFFSET
++ {0x88, 0x0107}, // FX_RED
++ {0x8B, 0x00B6}, // FY_RED
++ {0x8E, 0x091A}, // DF_DX_RED
++ {0x91, 0x0A98}, // DF_DY_RED
++ {0x94, 0xF615}, // SECOND_DERIV_ZONE_0_RED
++ {0x97, 0x1F22}, // SECOND_DERIV_ZONE_1_RED
++ {0x9A, 0x2D59}, // SECOND_DERIV_ZONE_2_RED
++ {0x9D, 0x464B}, // SECOND_DERIV_ZONE_3_RED
++ {0xA0, 0x4441}, // SECOND_DERIV_ZONE_4_RED
++ {0xA3, 0x5446}, // SECOND_DERIV_ZONE_5_RED
++ {0xA6, 0x0418}, // SECOND_DERIV_ZONE_6_RED
++ {0xA9, 0xF723}, // SECOND_DERIV_ZONE_7_RED
++ {0x89, 0x00C4}, // FX_GREEN
++ {0x8C, 0x007B}, // FY_GREEN
++ {0x8F, 0x09E1}, // DF_DX_GREEN
++ {0x92, 0x0B1C}, // DF_DY_GREEN
++ {0x95, 0x0B19}, // SECOND_DERIV_ZONE_0_GREEN
++ {0x98, 0x1435}, // SECOND_DERIV_ZONE_1_GREEN
++ {0x9B, 0x2646}, // SECOND_DERIV_ZONE_2_GREEN
++ {0x9E, 0x3C36}, // SECOND_DERIV_ZONE_3_GREEN
++ {0xA1, 0x3231}, // SECOND_DERIV_ZONE_4_GREEN
++ {0xA4, 0x4032}, // SECOND_DERIV_ZONE_5_GREEN
++ {0xA7, 0x0D25}, // SECOND_DERIV_ZONE_6_GREEN
++ {0xAA, 0xBAD3}, // SECOND_DERIV_ZONE_7_GREEN
++ {0x8A, 0x00BB}, // FX_BLUE
++ {0x8D, 0x00A0}, // FY_BLUE
++ {0x90, 0x0A11}, // DF_DX_BLUE
++ {0x93, 0x0BCC}, // DF_DY_BLUE
++ {0x96, 0x0E44}, // SECOND_DERIV_ZONE_0_BLUE
++ {0x99, 0x0F2F}, // SECOND_DERIV_ZONE_1_BLUE
++ {0x9C, 0x1D3E}, // SECOND_DERIV_ZONE_2_BLUE
++ {0x9F, 0x3027}, // SECOND_DERIV_ZONE_3_BLUE
++ {0xA2, 0x2725}, // SECOND_DERIV_ZONE_4_BLUE
++ {0xA5, 0x3A24}, // SECOND_DERIV_ZONE_5_BLUE
++ {0xA8, 0x0412}, // SECOND_DERIV_ZONE_6_BLUE
++ {0xAB, 0xEF29}, // SECOND_DERIV_ZONE_7_BLUE
++ {0xAC, 0x8018}, // X2_FACTORS
++ {0xAD, 0x0000}, // GLOBAL_OFFSET_FXY_FUNCTION
++ {0xAE, 0x0000}, // K_FACTOR_IN_K_FX_FY
++ {0xF0, 0x0001},
++ {0x08, 0x01FC}, // COLOR_PIPELINE_CONTROL
++ // AE Target
++ {0xC6, 0xA206}, //AE_TARGET
++ {0xC8, 0x004A}, //AE_TARGET
++ // AWB & CCM Param.
++ {0xC6, 0x2306}, //AWB_CCM_L_0
++ {0xC8, 0x0266}, //AWB_CCM_L_0
++ {0xC6, 0x2308}, //AWB_CCM_L_1
++ {0xC8, 0xFEA1}, //AWB_CCM_L_1
++ {0xC6, 0x230A}, //AWB_CCM_L_2
++ {0xC8, 0x0000}, //AWB_CCM_L_2
++ {0xC6, 0x230C}, //AWB_CCM_L_3
++ {0xC8, 0xFEDF}, //AWB_CCM_L_3
++ {0xC6, 0x230E}, //AWB_CCM_L_4
++ {0xC8, 0x0255}, //AWB_CCM_L_4
++ {0xC6, 0x2310}, //AWB_CCM_L_5
++ {0xC8, 0xFFD7}, //AWB_CCM_L_5
++ {0xC6, 0x2312}, //AWB_CCM_L_6
++ {0xC8, 0xFF31}, //AWB_CCM_L_6
++ {0xC6, 0x2314}, //AWB_CCM_L_7
++ {0xC8, 0xFD96}, //AWB_CCM_L_7
++ {0xC6, 0x2316}, //AWB_CCM_L_8
++ {0xC8, 0x046E}, //AWB_CCM_L_8
++ {0xC6, 0x2318}, //AWB_CCM_L_9
++ {0xC8, 0x0020}, //AWB_CCM_L_9
++ {0xC6, 0x231A}, //AWB_CCM_L_10
++ {0xC8, 0x0035}, //AWB_CCM_L_10
++ {0xC6, 0x231C}, //AWB_CCM_RL_0
++ {0xC8, 0xFF3C}, //AWB_CCM_RL_0
++ {0xC6, 0x231E}, //AWB_CCM_RL_1
++ {0xC8, 0x00B9}, //AWB_CCM_RL_1
++ {0xC6, 0x2320}, //AWB_CCM_RL_2
++ {0xC8, 0x0002}, //AWB_CCM_RL_2
++ {0xC6, 0x2322}, //AWB_CCM_RL_3
++ {0xC8, 0x00D4}, //AWB_CCM_RL_3
++ {0xC6, 0x2324}, //AWB_CCM_RL_4
++ {0xC8, 0xFF77}, //AWB_CCM_RL_4
++ {0xC6, 0x2326}, //AWB_CCM_RL_5
++ {0xC8, 0xFFE1}, //AWB_CCM_RL_5
++ {0xC6, 0x2328}, //AWB_CCM_RL_6
++ {0xC8, 0x00B4}, //AWB_CCM_RL_6
++ {0xC6, 0x232A}, //AWB_CCM_RL_7
++ {0xC8, 0x01D3}, //AWB_CCM_RL_7
++ {0xC6, 0x232C}, //AWB_CCM_RL_8
++ {0xC8, 0xFD3F}, //AWB_CCM_RL_8
++ {0xC6, 0x232E}, //AWB_CCM_RL_9
++ {0xC8, 0x000A}, //AWB_CCM_RL_9
++ {0xC6, 0x2330}, //AWB_CCM_RL_10
++ {0xC8, 0xFFF1}, //AWB_CCM_RL_10
++ {0xC6, 0xA348}, //AWB_GAIN_BUFFER_SPEED
++ {0xC8, 0x0008}, //AWB_GAIN_BUFFER_SPEED
++ {0xC6, 0xA349}, //AWB_JUMP_DIVISOR
++ {0xC8, 0x0002}, //AWB_JUMP_DIVISOR
++ {0xC6, 0xA34A}, //AWB_GAIN_MIN
++ {0xC8, 0x0053}, //AWB_GAIN_MIN
++ {0xC6, 0xA34B}, //AWB_GAIN_MAX
++ {0xC8, 0x00C0}, //AWB_GAIN_MAX
++ {0xC6, 0xA34F}, //AWB_CCM_POSITION_MIN
++ {0xC8, 0x0000}, //AWB_CCM_POSITION_MIN
++ {0xC6, 0xA350}, //AWB_CCM_POSITION_MAX
++ {0xC8, 0x007F}, //AWB_CCM_POSITION_MAX
++ {0xC6, 0xA352}, //AWB_SATURATION
++ {0xC8, 0x0090}, //AWB_SATURATION
++ {0xC6, 0xA35B}, //AWB_STEADY_BGAIN_OUT_MIN
++ {0xC8, 0x0073}, //AWB_STEADY_BGAIN_OUT_MIN
++ {0xC6, 0xA35C}, //AWB_STEADY_BGAIN_OUT_MAX
++ {0xC8, 0x008C}, //AWB_STEADY_BGAIN_OUT_MAX
++ {0xC6, 0xA35D}, //AWB_STEADY_BGAIN_IN_MIN
++ {0xC8, 0x007C}, //AWB_STEADY_BGAIN_IN_MIN
++ {0xC6, 0xA35E}, //AWB_STEADY_BGAIN_IN_MAX
++ {0xC8, 0x0083}, //AWB_STEADY_BGAIN_IN_MAX
++ {0xC6, 0x235F}, //AWB_CNT_PXL_TH
++ {0xC8, 0x0064}, //AWB_CNT_PXL_TH
++ {0xC6, 0xA361}, //AWB_TG_MIN0
++ {0xC8, 0x00E2}, //AWB_TG_MIN0
++ {0xC6, 0xA362}, //AWB_TG_MAX0
++ {0xC8, 0x00F6}, //AWB_TG_MAX0
++ {0xC6, 0xA302}, //AWB_WINDOW_POS
++ {0xC8, 0x0000}, //AWB_WINDOW_POS
++ {0xC6, 0xA303}, //AWB_WINDOW_SIZE
++ {0xC8, 0x00EF}, //AWB_WINDOW_SIZE
++ {0xC6, 0xA103}, //SEQ_CMD
++ {0xC8, 0x0005}, //SEQ_CMD
++
++ {0xF0, 0x0002}, // 2 Page Select
++ // Context B YUV Output Setting
++ {0xC6, 0x270B}, //MODE_CONFIG
++ {0xC8, 0x0030}, //MODE_CONFIG
++ {0xC6, 0xA77E}, //MODE_OUTPUT_FORMAT_B
++ {0xC8, 0x0000}, //MODE_OUTPUT_FORMAT_B
++ {0xC6, 0x2774}, //MODE_FIFO_CONF1_B
++ {0xC8, 0xE5E1}, //MODE_FIFO_CONF1_B
++ {0xC6, 0xA776}, //MODE_FIFO_CONF2_B
++ {0xC8, 0x00E3}, //MODE_FIFO_CONF2_B
++
++
++ {0xF0, 0x0001},
++ {0xC6, 0xA120},
++ {0xC8, 0x0000},
++ {0xC6, 0xA103},
++ {0xC8, 0x0001},
++ {REG_TERM, VAL_TERM}
++};
++
++
++static struct sensor_reg sensor_preview[] = {
++ {0xF0, 0x0001},
++ {0xC6, 0xA120},
++ {0xC8, 0x0000},
++ {0xC6, 0xA103},
++ {0xC8, 0x0001},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_capture[] = {
++ {0xF0, 0x0001},
++ {0xC6, 0x270B},
++ {0xC8, 0x0030},
++ {0xC6, 0xA77E},
++ {0xC8, 0x0000},
++ {0xC6, 0x2774},
++ {0xC8, 0xE5E1},
++ {0xC6, 0xA776},
++ {0xC8, 0x00E3},
++ {0xF0, 0x0001},
++ {0xC6, 0xA120},
++ {0xC8, 0x0002},
++ {0xC6, 0xA103},
++ {0xC8, 0x0002},
++ {REG_TERM, VAL_TERM}
++};
++
++ struct sensor_reg* sensor_reg_common[3] =
++{
++ sensor_common,
++ sensor_preview,
++ sensor_capture
++};
++
++static struct sensor_reg sensor_brightness_0[] = {
++ {0xF0, 0x0001},
++ {0xC6, 0xA206},
++ {0xC8, 0x0025},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_1[] = {
++ {0xF0, 0x0001},
++ {0xC6, 0xA206},
++ {0xC8, 0x0034},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_2[] = {
++ {0xF0, 0x0001},
++ {0xC6, 0xA206},
++ {0xC8, 0x004A},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_3[] = {
++ {0xF0, 0x0001},
++ {0xC6, 0xA206},
++ {0xC8, 0x0069},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_4[] = {
++ {0xF0, 0x0001},
++ {0xC6, 0xA206},
++ {0xC8, 0x0094},
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_brightness[5] =
++{
++ sensor_brightness_0,
++ sensor_brightness_1,
++ sensor_brightness_2,
++ sensor_brightness_3,
++ sensor_brightness_4
++};
++
++
++static struct sensor_reg sensor_awb_auto[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_daylight[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_incandescent[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_fluorescent[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_cloudy[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_sunset[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_awb[6] =
++{
++ sensor_awb_auto,
++ sensor_awb_daylight,
++ sensor_awb_incandescent,
++ sensor_awb_fluorescent,
++ sensor_awb_cloudy,
++ sensor_awb_sunset
++
++};
++
++
++static struct sensor_reg sensor_iso_auto[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_100[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_200[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_400[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_iso[4] =
++{
++ sensor_iso_auto,
++ sensor_iso_100,
++ sensor_iso_200,
++ sensor_iso_400
++};
++
++
++static struct sensor_reg sensor_effect_normal[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_gray[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_negative[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sepia[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sharpness[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sketch[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_effect[6] =
++{
++ sensor_effect_normal,
++ sensor_effect_gray,
++ sensor_effect_negative,
++ sensor_effect_sepia,
++ sensor_effect_sharpness,
++ sensor_effect_sketch,
++};
++
++static struct sensor_reg sensor_reg_flipnone[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_hflip[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_vflip[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_hvflip[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_flip[4] =
++{
++ sensor_reg_flipnone,
++ sensor_reg_hflip,
++ sensor_reg_vflip,
++ sensor_reg_hvflip,
++};
++
++
++static struct sensor_reg sensor_secne_auto[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_night[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_landscape[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_portrait[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_sport[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_scene[5] =
++{
++ sensor_secne_auto,
++ sensor_secne_night,
++ sensor_secne_landscape,
++ sensor_secne_portrait,
++ sensor_secne_sport
++};
++
++static struct sensor_reg sensor_me_mtrix[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_me_center_weighted[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_me_spot[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_metering_exposure[3] =
++{
++ sensor_me_mtrix,
++ sensor_me_center_weighted,
++ sensor_me_spot,
++};
++
++static struct sensor_reg sensor_af_single[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_af_manual[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_af[2] =
++{
++ sensor_af_single,
++ sensor_af_manual,
++};
++
++#endif
++
+diff --git a/drivers/media/video/tcccam/mt9d111_2mp.h b/drivers/media/video/tcccam/mt9d111_2mp.h
+new file mode 100644
+index 0000000..095ff98
+--- /dev/null
++++ b/drivers/media/video/tcccam/mt9d111_2mp.h
+@@ -0,0 +1,63 @@
++/*
++ * drivers/media/video/tcccam/mt9d111_2mp.h
++ *
++ * Register definitions for the mt9d111 CameraChip.
++ *
++ * Author: zzau (zzau@telechips.com)
++ *
++ * Copyright (C) 2008 Telechips, 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.
++ */
++
++#ifndef MT9D111_H
++#define MT9D111_H
++
++/* The MT9D111 I2C sensor chip has a fixed slave address of 0x5D. */
++#define SENSOR_I2C_ADDR 0xBA
++
++#define REG_TERM 0xFF /* terminating list entry for reg */
++#define VAL_TERM 0xFFFF /* terminating list entry for val */
++
++
++// ZOOM Setting!!
++#define PRV_W 800
++#define PRV_H 600
++#define PRV_ZOFFX 8
++#define PRV_ZOFFY 6
++
++#define CAP_W 1600
++#define CAP_H 1200
++#define CAP_ZOFFX 16
++#define CAP_ZOFFY 12
++
++#define CAM_2XMAX_ZOOM_STEP 25
++#define CAM_CAPCHG_WIDTH 800
++
++
++struct sensor_reg {
++ unsigned char reg;
++ unsigned short/*char*/ val[1];
++};
++
++struct capture_size {
++ unsigned long width;
++ unsigned long height;
++};
++
++extern struct capture_size sensor_sizes[];
++
++extern struct sensor_reg* sensor_reg_common[];
++extern struct sensor_reg* sensor_reg_brightness[];
++extern struct sensor_reg* sensor_reg_awb[];
++extern struct sensor_reg* sensor_reg_iso[];
++extern struct sensor_reg* sensor_reg_effect[];
++extern struct sensor_reg* sensor_reg_flip[];
++extern struct sensor_reg* sensor_reg_scene[];
++extern struct sensor_reg* sensor_reg_metering_exposure[];
++extern struct sensor_reg* sensor_reg_af[];
++
++#endif /* MT9D111_H */
++
+diff --git a/drivers/media/video/tcccam/mt9d112_2mp.c b/drivers/media/video/tcccam/mt9d112_2mp.c
+new file mode 100644
+index 0000000..5937478
+--- /dev/null
++++ b/drivers/media/video/tcccam/mt9d112_2mp.c
+@@ -0,0 +1,987 @@
++/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
++
++ CAMERA API M O D U L E
++
++ EDIT HISTORY FOR MODULE
++
++when who what, where, why
++-------- --- -------------------------------------------------------
++10/xx/08 Telechips Created file.
++*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
++
++/*===========================================================================
++
++ INCLUDE FILES FOR MODULE
++
++===========================================================================*/
++#include "sensor_if.h"
++
++#ifdef CONFIG_VIDEO_CAMERA_SENSOR_MT9D112
++
++/* Array of image sizes supported by MT9D112. These must be ordered from
++ * smallest image size to largest.
++ */
++struct capture_size sensor_sizes[] = {
++ { 1600, 1200 }, /* UXGA */
++ { 1280, 960 }, /* SXGA */
++ { 1024, 768 }, /* XGA */
++ { 800, 600 }, /* SVGA */
++ { 640, 480 }, /* VGA */
++ { 320, 240 }, /* QVGA */
++ { 176, 144 }, /* QCIF */
++};
++
++
++/* register initialization tables for sensor */
++/* common sensor register initialization for all image sizes, pixel formats,
++ * and frame rates
++ */
++static struct sensor_reg sensor_common[] = {
++ {0x3216, 0x0008},
++ {0x341E, 0x8F09},
++ {0x341C, 0x0120},
++ {0x341E, 0x8F09},
++ {0x341E, 0x8F08},
++ {0x301A, 0x0ACC},
++ {0x3202, 0x0008},
++ {0x33F4, 0x031D},
++
++ {CAMDLY, 100},
++
++ {0x3044, 0x0540}, //Reserved = 0x540
++ {0x3216, 0x02CF}, //Internal Clock Control = 0x2CF
++ {0x321C, 0x0402}, //OF Control Status = 0x402
++ {0x3212, 0x0001}, //Factory Bypass = 0x1
++
++ {0x338C, 0x2703}, //Output Width (A)
++ {0x3390, 0x0320}, // = 800
++ {0x338C, 0x2705}, //Output Height (A)
++ {0x3390, 0x0258}, // = 600
++ {0x338C, 0x2707}, //Output Width (B)
++ {0x3390, 0x0640}, // = 1600
++ {0x338C, 0x2709}, //Output Height (B)
++ {0x3390, 0x04B2}, // = 1202
++ {0x338C, 0x270D}, //Row Start (A)
++ {0x3390, 0x0000}, // = 0
++ {0x338C, 0x270F}, //Column Start (A)
++ {0x3390, 0x0000}, // = 0
++ {0x338C, 0x2711}, //Row End (A)
++ {0x3390, 0x04BD}, // = 1213
++ {0x338C, 0x2713}, //Column End (A)
++ {0x3390, 0x064D}, // = 1613
++ {0x338C, 0x2715}, //Extra Delay (A)
++ {0x3390, 0x030B}, // = 779
++ {0x338C, 0x2717}, //Row Speed (A)
++ {0x3390, 0x2111}, // = 8465
++ {0x338C, 0x2719}, //Read Mode (A)
++ {0x3390, 0x046C}, // = 1132
++ {0x338C, 0x271B}, //sensor_sample_time_pck (A)
++ {0x3390, 0x024F}, // = 591
++ {0x338C, 0x271D}, //sensor_fine_correction (A)
++ {0x3390, 0x0102}, // = 258
++ {0x338C, 0x271F}, //sensor_fine_IT_min (A)
++ {0x3390, 0x0279}, // = 633
++ {0x338C, 0x2721}, //sensor_fine_IT_max_margin (A)
++ {0x3390, 0x0155}, // = 341
++ {0x338C, 0x2723}, //Frame Lines (A)
++ {0x3390, 0x02EA}, // = 746
++ {0x338C, 0x2725}, //Line Length (A)
++ {0x3390, 0x0824}, // = 2084
++ {0x338C, 0x2727}, //sensor_dac_id_4_5 (A)
++ {0x3390, 0x2020}, // = 8224
++ {0x338C, 0x2729}, //sensor_dac_id_6_7 (A)
++ {0x3390, 0x2020}, // = 8224
++ {0x338C, 0x272B}, //sensor_dac_id_8_9 (A)
++ {0x3390, 0x1020}, // = 4128
++ {0x338C, 0x272D}, //sensor_dac_id_10_11 (A)
++ {0x3390, 0x2007}, // = 8199
++ {0x338C, 0x272F}, //Row Start (B)
++ {0x3390, 0x0004}, // = 4
++ {0x338C, 0x2731}, //Column Start (B)
++ {0x3390, 0x0004}, // = 4
++ {0x338C, 0x2733}, //Row End (B)
++ {0x3390, 0x04BD}, // = 1211 + ?
++ {0x338C, 0x2735}, //Column End (B)
++ {0x3390, 0x064B}, // = 1611
++ {0x338C, 0x2737}, //Extra Delay (B)
++ {0x3390, 0x04C6}, // = 1222
++ {0x338C, 0x2739}, //Row Speed (B)
++ {0x3390, 0x2111}, // = 8465
++ {0x338C, 0x273B}, //Read Mode (B)
++ {0x3390, 0x0024}, // = 36
++ {0x338C, 0x273D}, //sensor_sample_time_pck (B)
++ {0x3390, 0x0120}, // = 288
++ {0x338C, 0x273F}, //sensor_fine_correction (B)
++ {0x3390, 0x00A4}, // = 164
++ {0x338C, 0x2741}, //sensor_fine_IT_min (B)
++ {0x3390, 0x0169}, // = 330 + ?
++ {0x338C, 0x2743}, //sensor_fine_IT_max_margin (B)
++ {0x3390, 0x00A4}, // = 164
++ {0x338C, 0x2745}, //Frame Lines (B)
++ {0x3390, 0x0573}, // = 1395
++ {0x338C, 0x2747}, //Line Length (B)
++ {0x3390, 0x0824}, // = 2084
++ {0x338C, 0x2751}, //Crop_X0 (A)
++ {0x3390, 0x0000}, // = 0
++ {0x338C, 0x2753}, //Crop_X1 (A)
++ {0x3390, 0x0320}, // = 800
++ {0x338C, 0x2755}, //Crop_Y0 (A)
++ {0x3390, 0x0000}, // = 0
++ {0x338C, 0x2757}, //Crop_Y1 (A)
++ {0x3390, 0x0258}, // = 600
++ {0x338C, 0x275F}, //Crop_X0 (B)
++ {0x3390, 0x0000}, // = 0
++ {0x338C, 0x2761}, //Crop_X1 (B)
++ {0x3390, 0x0640}, // = 1600
++ {0x338C, 0x2763}, //Crop_Y0 (B)
++ {0x3390, 0x0000}, // = 0
++ {0x338C, 0x2765}, //Crop_Y1 (B)
++ {0x3390, 0x04B2}, // = 1202
++ {0x338C, 0x222E}, //R9 Step
++ {0x3390, 0x0062}, // = 98
++ {0x338C, 0xA408}, //search_f1_50
++ {0x3390, 0x0011}, // = 17
++ {0x338C, 0xA409}, //search_f2_50
++ {0x3390, 0x0014}, // = 20
++ {0x338C, 0xA40A}, //search_f1_60
++ {0x3390, 0x0015}, // = 21
++ {0x338C, 0xA40B}, //search_f2_60
++ {0x3390, 0x0018}, // = 24
++ {0x338C, 0x2411}, //R9_Step_60_A
++ {0x3390, 0x0062}, // = 98
++ {0x338C, 0x2413}, //R9_Step_50_A
++ {0x3390, 0x0076}, // = 118
++ {0x338C, 0x2415}, //R9_Step_60_B
++ {0x3390, 0x0062}, // = 98
++ {0x338C, 0x2417}, //R9_Step_50_B
++ {0x3390, 0x0076}, // = 118
++ {0x338C, 0xA40D}, //Stat_min
++ {0x3390, 0x0002}, // = 2
++ {0x338C, 0xA410}, //Min_amplitude
++ {0x3390, 0x0001}, // = 1
++ {0x338C, 0xA404}, // MCU_ADDRESS
++ {0x3390, 0x0000}, // FD_MODE
++ {0x338C, 0xA20C}, // MCU_ADDRESS
++ {0x3390, 0x000C}, // AE_MAX_INDEX
++ {0x338C, 0xA215}, // MCU_ADDRESS
++ {0x3390, 0x0008}, // AE_INDEX_TH23
++ {0x338C, 0xA206}, // MCU_ADDRESS
++ {0x3390, 0x0046}, // AE_TARGET
++ {0x338C, 0xA207}, // MCU_ADDRESS
++ {0x3390, 0x000A}, // AE_GATE
++ {0x338C, 0xA202}, // MCU_ADDRESS
++ {0x3390, 0x0033}, // AE_WINDOW_POS
++ {0x338C, 0xA203}, // MCU_ADDRESS
++ {0x3390, 0x0099}, // AE_WINDOW_SIZE
++ {0x338C, 0xA217}, // MCU_ADDRESS
++ {0x3390, 0x00BF}, // AE_WEIGHTS
++
++ // Sequence
++ {0x338C, 0xA13E}, // MCU_ADDRESS
++ {0x3390, 0x0004}, // MCU_DATA_0
++ {0x338C, 0xA13F}, // MCU_ADDRESS
++ {0x3390, 0x000E}, // MCU_DATA_0
++ {0x338C, 0xA140}, // MCU_ADDRESS
++ {0x3390, 0x0004}, // MCU_DATA_0
++ {0x338C, 0xA141}, // MCU_ADDRESS
++ {0x3390, 0x0004}, // MCU_DATA_0
++ {0x338C, 0xA142}, // MCU_ADDRESS
++ {0x3390, 0x0032}, // MCU_DATA_0
++ {0x338C, 0xA143}, // MCU_ADDRESS
++ {0x3390, 0x000F}, // MCU_DATA_0
++ {0x338C, 0xA144}, // MCU_ADDRESS
++ {0x3390, 0x0032}, // MCU_DATA_0
++ {0x338C, 0xA145}, // MCU_ADDRESS
++ {0x3390, 0x0032}, // MCU_DATA_0
++ {0x338C, 0xA146}, // MCU_ADDRESS
++ {0x3390, 0x0005}, // MCU_DATA_0
++ {0x338C, 0xA147}, // MCU_ADDRESS
++ {0x3390, 0x003A}, // MCU_DATA_0
++ {0x338C, 0xA115}, // MCU_ADDRESS
++ {0x3390, 0x006F}, // MCU_DATA_0
++ {0x338C, 0xA118}, // MCU_ADDRESS
++ {0x3390, 0x0080}, // SEQ_LLSAT1
++ {0x338C, 0xA119}, // MCU_ADDRESS
++ {0x3390, 0x0060}, // SEQ_LLSAT2
++ {0x338C, 0xA11C}, // MCU_ADDRESS
++ {0x3390, 0x0003}, // SEQ_LLAPCORR1 : 4 => 3 20080108 edge 3 <- 4
++ {0x338C, 0xA11D}, // MCU_ADDRESS
++ {0x3390, 0x0002}, // SEQ_LLAPCORR2
++ {0x338C, 0xA12C}, // MCU_ADDRESS
++ {0x3390, 0x0003}, // SEQ_PREVIEW_1_AF
++ {0x338C, 0xA130}, // MCU_ADDRESS
++ {0x3390, 0x0000}, // SEQ_PREVIEW_2_AE
++ {0x338C, 0xA132}, // MCU_ADDRESS
++ {0x3390, 0x0000}, // SEQ_PREVIEW_2_AWB
++ {0x338C, 0xA134}, // MCU_ADDRESS
++ {0x3390, 0x0000}, // SEQ_PREVIEW_2_HG
++ {0x338C, 0xA136}, // MCU_ADDRESS
++ {0x3390, 0x0040}, // MCU_DATA_0
++ {0x326C, 0x1511}, // APERTURE_PARAMETERS
++
++ // LSC
++ {0x34CE, 0x81A8}, // LENS_CORRECTION_CONTROL
++ {0x34D0, 0x6432}, // ZONE_BOUNDS_X1_X2
++ {0x34D2, 0x3296}, // ZONE_BOUNDS_X0_X3
++ {0x34D4, 0x9664}, // ZONE_BOUNDS_X4_X5
++ {0x34D6, 0x5028}, // ZONE_BOUNDS_Y1_Y2
++ {0x34D8, 0x2878}, // ZONE_BOUNDS_Y0_Y3
++ {0x34DA, 0x7850}, // ZONE_BOUNDS_Y4_Y5
++ {0x34DC, 0x0000}, // CENTER_OFFSET
++ {0x34DE, 0x0113}, // FX_RED
++ {0x34E6, 0x00BB}, // FY_RED
++ {0x34EE, 0x0955}, // DF_DX_RED
++ {0x34F6, 0x0B48}, // DF_DY_RED
++ {0x3500, 0x2249}, // SECOND_DERIV_ZONE_0_RED
++ {0x3508, 0x1E07}, // SECOND_DERIV_ZONE_1_RED
++ {0x3510, 0x1C33}, // SECOND_DERIV_ZONE_2_RED
++ {0x3518, 0x1D54}, // SECOND_DERIV_ZONE_3_RED
++ {0x3520, 0x2952}, // SECOND_DERIV_ZONE_4_RED
++ {0x3528, 0x2451}, // SECOND_DERIV_ZONE_5_RED
++ {0x3530, 0x0D34}, // SECOND_DERIV_ZONE_6_RED
++ {0x3538, 0x27B2}, // SECOND_DERIV_ZONE_7_RED
++ {0x354C, 0x0045}, // K_FACTOR_IN_K_FX_FY_R_TL
++ {0x3544, 0x0415}, // K_FACTOR_IN_K_FX_FY_R_TR
++ {0x355C, 0x00A5}, // K_FACTOR_IN_K_FX_FY_R_BL
++ {0x3554, 0x0449}, // K_FACTOR_IN_K_FX_FY_R_BR
++ {0x34E0, 0x010C}, // FX_GREEN
++ {0x34E8, 0x0095}, // FY_GREEN
++ {0x34F0, 0x0B02}, // DF_DX_GREEN
++ {0x34F8, 0x0BB5}, // DF_DY_GREEN
++ {0x3502, 0x3C22}, // SECOND_DERIV_ZONE_0_GREEN
++ {0x350A, 0x0B03}, // SECOND_DERIV_ZONE_1_GREEN
++ {0x3512, 0x1646}, // SECOND_DERIV_ZONE_2_GREEN
++ {0x351A, 0x193F}, // SECOND_DERIV_ZONE_3_GREEN
++ {0x3522, 0x2142}, // SECOND_DERIV_ZONE_4_GREEN
++ {0x352A, 0x1A21}, // SECOND_DERIV_ZONE_5_GREEN
++ {0x3532, 0x092A}, // SECOND_DERIV_ZONE_6_GREEN
++ {0x353A, 0x3E71}, // SECOND_DERIV_ZONE_7_GREEN
++ {0x354E, 0x0439}, // K_FACTOR_IN_K_FX_FY_G1_TL
++ {0x3546, 0x00F3}, // K_FACTOR_IN_K_FX_FY_G1_TR
++ {0x355E, 0x0025}, // K_FACTOR_IN_K_FX_FY_G1_BL
++ {0x3556, 0x0173}, // K_FACTOR_IN_K_FX_FY_G1_BR
++ {0x34E4, 0x00D9}, // FX_BLUE
++ {0x34EC, 0x006A}, // FY_BLUE
++ {0x34F4, 0x0B40}, // DF_DX_BLUE
++ {0x34FC, 0x0C75}, // DF_DY_BLUE
++ {0x3506, 0x3A30}, // SECOND_DERIV_ZONE_0_BLUE
++ {0x350E, 0x08FD}, // SECOND_DERIV_ZONE_1_BLUE
++ {0x3516, 0x152F}, // SECOND_DERIV_ZONE_2_BLUE
++ {0x351E, 0x1236}, // SECOND_DERIV_ZONE_3_BLUE
++ {0x3526, 0x1432}, // SECOND_DERIV_ZONE_4_BLUE
++ {0x352E, 0x1011}, // SECOND_DERIV_ZONE_5_BLUE
++ {0x3536, 0x153B}, // SECOND_DERIV_ZONE_6_BLUE
++ {0x353E, 0x3116}, // SECOND_DERIV_ZONE_7_BLUE
++ {0x3552, 0x00A0}, // K_FACTOR_IN_K_FX_FY_B_TL
++ {0x354A, 0x02BB}, // K_FACTOR_IN_K_FX_FY_B_TR
++ {0x3562, 0x0140}, // K_FACTOR_IN_K_FX_FY_B_BL
++ {0x355A, 0x0238}, // K_FACTOR_IN_K_FX_FY_B_BR
++ {0x34E2, 0x0111}, // FX_GREEN2
++ {0x34EA, 0x0085}, // FY_GREEN2
++ {0x34F2, 0x094C}, // DF_DX_GREEN2
++ {0x34FA, 0x0C02}, // DF_DY_GREEN2
++ {0x3504, 0x364A}, // SECOND_DERIV_ZONE_0_GREEN2
++ {0x350C, 0x0C08}, // SECOND_DERIV_ZONE_1_GREEN2
++ {0x3514, 0x1837}, // SECOND_DERIV_ZONE_2_GREEN2
++ {0x351C, 0x1A46}, // SECOND_DERIV_ZONE_3_GREEN2
++ {0x3524, 0x1846}, // SECOND_DERIV_ZONE_4_GREEN2
++ {0x352C, 0x1837}, // SECOND_DERIV_ZONE_5_GREEN2
++ {0x3534, 0x1127}, // SECOND_DERIV_ZONE_6_GREEN2
++ {0x353C, 0x3A1D}, // SECOND_DERIV_ZONE_7_GREEN2
++ {0x3550, 0x0122}, // K_FACTOR_IN_K_FX_FY_G2_TL
++ {0x3548, 0x0054}, // K_FACTOR_IN_K_FX_FY_G2_TR
++ {0x3560, 0x0099}, // K_FACTOR_IN_K_FX_FY_G2_BL
++ {0x3558, 0x0013}, // K_FACTOR_IN_K_FX_FY_G2_BR
++ {0x3540, 0x0001}, // X2_FACTORS
++ {0x3542, 0x0000}, // GLOBAL_OFFSET_FXY_FUNCTION
++ {0x3210, 0x01FC}, // COLOR_PIPELINE_CONTROL
++
++ // Gamma (Programmed)
++ {0x338C, 0xA76D}, // MCU_ADDRESS [MODE_GAM_CONT_A]
++ {0x3390, 0x0042}, // MCU_DATA_0
++ {0x338C, 0xA76E}, // MCU_ADDRESS [MODE_GAM_CONT_B]
++ {0x3390, 0x0042}, // MCU_DATA_0
++ {0x338C, 0xAB04}, // MCU_ADDRESS [HG_MAX_DLEVEL]
++ {0x3390, 0x0018}, // MCU_DATA_0
++ {0x338C, 0xAB05}, // MCU_ADDRESS [HG_PERCENT]
++ {0x3390, 0x0002}, // MCU_DATA_0
++
++ // AWB & CCM
++ {0x338C, 0x2306}, // MCU_ADDRESS [AWB_CCM_L_0]
++ {0x3390, 0x02E1}, // MCU_DATA_0
++ {0x338C, 0x2308}, // MCU_ADDRESS [AWB_CCM_L_1]
++ {0x3390, 0xFE81}, // MCU_DATA_0
++ {0x338C, 0x230A}, // MCU_ADDRESS [AWB_CCM_L_2]
++ {0x3390, 0xFFC9}, // MCU_DATA_0
++ {0x338C, 0x230C}, // MCU_ADDRESS [AWB_CCM_L_3]
++ {0x3390, 0xFF64}, // MCU_DATA_0
++ {0x338C, 0x230E}, // MCU_ADDRESS [AWB_CCM_L_4]
++ {0x3390, 0x02A9}, // MCU_DATA_0
++ {0x338C, 0x2310}, // MCU_ADDRESS [AWB_CCM_L_5]
++ {0x3390, 0xFF41}, // MCU_DATA_0
++ {0x338C, 0x2312}, // MCU_ADDRESS [AWB_CCM_L_6]
++ {0x3390, 0xFF77}, // MCU_DATA_0
++ {0x338C, 0x2314}, // MCU_ADDRESS [AWB_CCM_L_7]
++ {0x3390, 0xFE15}, // MCU_DATA_0
++ {0x338C, 0x2316}, // MCU_ADDRESS [AWB_CCM_L_8]
++ {0x3390, 0x03D7}, // MCU_DATA_0
++ {0x338C, 0x2318}, // MCU_ADDRESS [AWB_CCM_L_9]
++ {0x3390, 0x0024}, // MCU_DATA_0
++ {0x338C, 0x231A}, // MCU_ADDRESS [AWB_CCM_L_10]
++ {0x3390, 0x003C}, // MCU_DATA_0
++ {0x338C, 0x231C}, // MCU_ADDRESS [AWB_CCM_RL_0]
++ {0x3390, 0x0072}, // MCU_DATA_0
++ {0x338C, 0x231E}, // MCU_ADDRESS [AWB_CCM_RL_1]
++ {0x3390, 0xFF68}, // MCU_DATA_0
++ {0x338C, 0x2320}, // MCU_ADDRESS [AWB_CCM_RL_2]
++ {0x3390, 0x002A}, // MCU_DATA_0
++ {0x338C, 0x2322}, // MCU_ADDRESS [AWB_CCM_RL_3]
++ {0x3390, 0x0000}, // MCU_DATA_0
++ {0x338C, 0x2324}, // MCU_ADDRESS [AWB_CCM_RL_4]
++ {0x3390, 0x005D}, // MCU_DATA_0
++ {0x338C, 0x2326}, // MCU_ADDRESS [AWB_CCM_RL_5]
++ {0x3390, 0xFFBA}, // MCU_DATA_0
++ {0x338C, 0x2328}, // MCU_ADDRESS [AWB_CCM_RL_6]
++ {0x3390, 0x005D}, // 94}, // MCU_DATA_0
++ {0x338C, 0x232A}, // MCU_ADDRESS [AWB_CCM_RL_7]
++ {0x3390, 0x0104}, //0C0}, // MCU_DATA_0
++ {0x338C, 0x232C}, // MCU_ADDRESS [AWB_CCM_RL_8]
++ {0x3390, 0xFE68}, //FE75}, // MCU_DATA_0
++ {0x338C, 0x232E}, // MCU_ADDRESS [AWB_CCM_RL_9]
++ {0x3390, 0x001C}, // MCU_DATA_0
++ {0x338C, 0x2330}, // MCU_ADDRESS [AWB_CCM_RL_10]
++ {0x3390, 0xFFEC}, // MCU_DATA_0
++ {0x338C, 0xA348}, // MCU_ADDRESS [AWB_GAIN_BUFFER_SPEED]
++ {0x3390, 0x0008}, // MCU_DATA_0
++ {0x338C, 0xA349}, // MCU_ADDRESS [AWB_JUMP_DIVISOR]
++ {0x3390, 0x0002}, // MCU_DATA_0
++ {0x338C, 0xA34A}, // MCU_ADDRESS [AWB_GAIN_MIN]
++ {0x3390, 0x0060}, // MCU_DATA_0
++ {0x338C, 0xA34B}, // MCU_ADDRESS [AWB_GAIN_MAX]
++ {0x3390, 0x008C}, // MCU_DATA_0
++ {0x338C, 0xA34F}, // MCU_ADDRESS [AWB_CCM_POSITION_MIN]
++ {0x3390, 0x0018}, // MCU_DATA_0
++ {0x338C, 0xA350}, // MCU_ADDRESS [AWB_CCM_POSITION_MAX]
++ {0x3390, 0x0076}, // MCU_DATA_0
++ {0x338C, 0xA352}, // MCU_ADDRESS [AWB_SATURATION]
++ {0x3390, 0x0080}, // MCU_DATA_0
++ {0x338C, 0xA353}, // MCU_ADDRESS [AWB_MODE]
++ {0x3390, 0x0002}, // MCU_DATA_0
++ {0x338C, 0xA35B}, // MCU_ADDRESS [AWB_STEADY_BGAIN_OUT_MIN]
++ {0x3390, 0x0078}, // MCU_DATA_0
++ {0x338C, 0xA35C}, // MCU_ADDRESS [AWB_STEADY_BGAIN_OUT_MAX]
++ {0x3390, 0x0086}, // MCU_DATA_0
++ {0x338C, 0xA35D}, // MCU_ADDRESS [AWB_STEADY_BGAIN_IN_MIN]
++ {0x3390, 0x007E}, // MCU_DATA_0
++ {0x338C, 0xA35E}, // MCU_ADDRESS [AWB_STEADY_BGAIN_IN_MAX]
++ {0x3390, 0x0082}, // MCU_DATA_0
++ {0x338C, 0x235F}, // MCU_ADDRESS [AWB_CNT_PXL_TH]
++ {0x3390, 0x0040}, // MCU_DATA_0
++ {0x338C, 0xA361}, // MCU_ADDRESS [AWB_TG_MIN0]
++ {0x3390, 0x00DB}, // MCU_DATA_0
++ {0x338C, 0xA362}, // MCU_ADDRESS [AWB_TG_MAX0]
++ {0x3390, 0x00E7}, // MCU_DATA_0
++ {0x338C, 0xA302}, // MCU_ADDRESS [AWB_WINDOW_POS]
++ {0x3390, 0x0000}, // MCU_DATA_0
++ {0x338C, 0xA303}, // MCU_ADDRESS [AWB_WINDOW_SIZE]
++ {0x3390, 0x00EF}, // MCU_DATA_0
++ {0x338C, 0xA364}, // MCU_ADDRESS [AWB_KR_L]
++ {0x3390, 0x0098}, // MCU_DATA_0
++ {0x338C, 0xA366}, // MCU_ADDRESS [AWB_KB_L]
++ {0x3390, 0x0088}, // MCU_DATA_0
++ {0x338C, 0xA367}, // MCU_ADDRESS [AWB_KR_R]
++ {0x3390, 0x0072}, // MCU_DATA_0
++ {0x338C, 0xA369}, // MCU_ADDRESS [AWB_KB_R]
++ {0x3390, 0x007A}, // MCU_DATA_0
++ {0x338C, 0xA36B}, // MCU_ADDRESS [AWB_EDGETH_MIN]
++ {0x3390, 0x0004}, // MCU_DATA_0
++
++ // Refresh
++ {0x338C, 0xA103}, // MCU_ADDRESS
++ {0x3390, 0x0006}, // MCU_DATA_0
++ //DELAY=200 ms // OR Wait until state = 3
++ {CAMDLY, 200},
++ //{0xFFFF, 100},
++ //{0xFFFF, 100},
++
++ {0x338C, 0xA103}, // MCU_ADDRESS
++ {0x3390, 0x0005}, // MCU_DATA_0
++ {CAMDLY, 500},
++ //DELAY=500 ms // OR Wait until state = 3
++ //{0xFFFF, 100},
++ //{0xFFFF, 100},
++ //{0xFFFF, 100},
++ //{0xFFFF, 100},
++ //{0xFFFF, 100},
++#if 0
++ // AF Driver - new 08.03 0~100%
++ {0x338C, 0x0400}, // MCU_ADDRESS
++ {0x3390, 0x3C3C}, // MCU_DATA_0
++ {0x3392, 0x3C3C}, // MCU_DATA_1
++ {0x3394, 0x3C3C}, // MCU_DATA_2
++ {0x3396, 0xFE10}, // MCU_DATA_3
++ {0x3398, 0x50EC}, // MCU_DATA_4
++ {0x339A, 0x0CFD}, // MCU_DATA_5
++ {0x339C, 0x0300}, // MCU_DATA_6
++ {0x339E, 0xFE03}, // MCU_DATA_7
++ {0x338C, 0x0410}, // MCU_ADDRESS
++ {0x3390, 0x00C6}, // MCU_DATA_0
++ {0x3392, 0x81E7}, // MCU_DATA_1
++ {0x3394, 0x02FE}, // MCU_DATA_2
++ {0x3396, 0x0300}, // MCU_DATA_3
++ {0x3398, 0xEE00}, // MCU_DATA_4
++ {0x339A, 0xEE00}, // MCU_DATA_5
++ {0x339C, 0xAD00}, // MCU_DATA_6
++ {0x339E, 0xFE03}, // MCU_DATA_7
++ {0x338C, 0x0420}, // MCU_ADDRESS
++ {0x3390, 0x00C6}, // MCU_DATA_0
++ {0x3392, 0x04E7}, // MCU_DATA_1
++ {0x3394, 0x02CC}, // MCU_DATA_2
++ {0x3396, 0x0400}, // MCU_DATA_3
++ {0x3398, 0xFD03}, // MCU_DATA_4
++ {0x339A, 0x02CC}, // MCU_DATA_5
++ {0x339C, 0x0485}, // MCU_DATA_6
++ {0x339E, 0xFD03}, // MCU_DATA_7
++ {0x338C, 0x0430}, // MCU_ADDRESS
++ {0x3390, 0x04FE}, // MCU_DATA_0
++ {0x3392, 0x0300}, // MCU_DATA_1
++ {0x3394, 0x1AEE}, // MCU_DATA_2
++ {0x3396, 0x0018}, // MCU_DATA_3
++ {0x3398, 0xEC04}, // MCU_DATA_4
++ {0x339A, 0xFD03}, // MCU_DATA_5
++ {0x339C, 0x061A}, // MCU_DATA_6
++ {0x339E, 0xEE00}, // MCU_DATA_7
++ {0x338C, 0x0440}, // MCU_ADDRESS
++ {0x3390, 0x18EC}, // MCU_DATA_0
++ {0x3392, 0x06FD}, // MCU_DATA_1
++ {0x3394, 0x0308}, // MCU_DATA_2
++ {0x3396, 0xCC03}, // MCU_DATA_3
++ {0x3398, 0x02ED}, // MCU_DATA_4
++ {0x339A, 0x00CC}, // MCU_DATA_5
++ {0x339C, 0x0001}, // MCU_DATA_6
++ {0x339E, 0xFD10}, // MCU_DATA_7
++ {0x338C, 0x0450}, // MCU_ADDRESS
++ {0x3390, 0x7EC6}, // MCU_DATA_0
++ {0x3392, 0xD130}, // MCU_DATA_1
++ {0x3394, 0xED0A}, // MCU_DATA_2
++ {0x3396, 0xCC00}, // MCU_DATA_3
++ {0x3398, 0x32ED}, // MCU_DATA_4
++ {0x339A, 0x085F}, // MCU_DATA_5
++ {0x339C, 0xED06}, // MCU_DATA_6
++ {0x339E, 0xED04}, // MCU_DATA_7
++ {0x338C, 0x0460}, // MCU_ADDRESS
++ {0x3390, 0xED02}, // MCU_DATA_0
++ {0x3392, 0xED00}, // MCU_DATA_1
++ {0x3394, 0x5CBD}, // MCU_DATA_2
++ {0x3396, 0x0545}, // MCU_DATA_3
++ {0x3398, 0xCE10}, // MCU_DATA_4
++ {0x339A, 0x801C}, // MCU_DATA_5
++ {0x339C, 0x3601}, // MCU_DATA_6
++ {0x339E, 0x1C35}, // MCU_DATA_7
++ {0x338C, 0x0470}, // MCU_ADDRESS
++ {0x3390, 0x011D}, // MCU_DATA_0
++ {0x3392, 0x3501}, // MCU_DATA_1
++ {0x3394, 0xCE10}, // MCU_DATA_2
++ {0x3396, 0x001D}, // MCU_DATA_3
++ {0x3398, 0x7101}, // MCU_DATA_4
++ {0x339A, 0xC6FF}, // MCU_DATA_5
++ {0x339C, 0xBD04}, // MCU_DATA_6
++ {0x339E, 0x8530}, // MCU_DATA_7
++ {0x338C, 0x0480}, // MCU_ADDRESS
++ {0x3390, 0xC60C}, // MCU_DATA_0
++ {0x3392, 0x3A35}, // MCU_DATA_1
++ {0x3394, 0x3937}, // MCU_DATA_2
++ {0x3396, 0x308F}, // MCU_DATA_3
++ {0x3398, 0xC3FF}, // MCU_DATA_4
++ {0x339A, 0xED8F}, // MCU_DATA_5
++ {0x339C, 0x35FE}, // MCU_DATA_6
++ {0x339E, 0x0300}, // MCU_DATA_7
++ {0x338C, 0x0490}, // MCU_ADDRESS
++ {0x3390, 0xE603}, // MCU_DATA_0
++ {0x3392, 0x30E1}, // MCU_DATA_1
++ {0x3394, 0x1322}, // MCU_DATA_2
++ {0x3396, 0x035F}, // MCU_DATA_3
++ {0x3398, 0x2002}, // MCU_DATA_4
++ {0x339A, 0xC601}, // MCU_DATA_5
++ {0x339C, 0xE712}, // MCU_DATA_6
++ {0x339E, 0xE613}, // MCU_DATA_7
++ {0x338C, 0x04A0}, // MCU_ADDRESS
++ {0x3390, 0x4FC3}, // MCU_DATA_0
++ {0x3392, 0x0002}, // MCU_DATA_1
++ {0x3394, 0xED10}, // MCU_DATA_2
++ {0x3396, 0xE613}, // MCU_DATA_3
++ {0x3398, 0xC1FF}, // MCU_DATA_4
++ {0x339A, 0x2614}, // MCU_DATA_5
++ {0x339C, 0x5F4F}, // MCU_DATA_6
++ {0x339E, 0xED0A}, // MCU_DATA_7
++ {0x338C, 0x04B0}, // MCU_ADDRESS
++ {0x3390, 0xED08}, // MCU_DATA_0
++ {0x3392, 0xED06}, // MCU_DATA_1
++ {0x3394, 0xED04}, // MCU_DATA_2
++ {0x3396, 0xED02}, // MCU_DATA_3
++ {0x3398, 0xED00}, // MCU_DATA_4
++ {0x339A, 0x5CBD}, // MCU_DATA_5
++ {0x339C, 0x0545}, // MCU_DATA_6
++ {0x339E, 0x2040}, // MCU_DATA_7
++ {0x338C, 0x04C0}, // MCU_ADDRESS
++ {0x3390, 0x6D13}, // MCU_DATA_0
++ {0x3392, 0x2617}, // MCU_DATA_1
++ {0x3394, 0xCC01}, // MCU_DATA_2
++ {0x3396, 0x03ED}, // MCU_DATA_3
++ {0x3398, 0x0A5F}, // MCU_DATA_4
++ {0x339A, 0x4FED}, // MCU_DATA_5
++ {0x339C, 0x08ED}, // MCU_DATA_6
++ {0x339E, 0x06ED}, // MCU_DATA_7
++ {0x338C, 0x04D0}, // MCU_ADDRESS
++ {0x3390, 0x04ED}, // MCU_DATA_0
++ {0x3392, 0x02ED}, // MCU_DATA_1
++ {0x3394, 0x005C}, // MCU_DATA_2
++ {0x3396, 0xBD05}, // MCU_DATA_3
++ {0x3398, 0x4520}, // MCU_DATA_4
++ {0x339A, 0x25CC}, // MCU_DATA_5
++ {0x339C, 0x0103}, // MCU_DATA_6
++ {0x339E, 0xA310}, // MCU_DATA_7
++ {0x338C, 0x04E0}, // MCU_ADDRESS
++ {0x3390, 0xED0A}, // MCU_DATA_0
++ {0x3392, 0xEC10}, // MCU_DATA_1
++ {0x3394, 0xED08}, // MCU_DATA_2
++ {0x3396, 0x5F4F}, // MCU_DATA_3
++ {0x3398, 0xED06}, // MCU_DATA_4
++ {0x339A, 0xED04}, // MCU_DATA_5
++ {0x339C, 0xED02}, // MCU_DATA_6
++ {0x339E, 0xED00}, // MCU_DATA_7
++ {0x338C, 0x04F0}, // MCU_ADDRESS
++ {0x3390, 0x5CBD}, // MCU_DATA_0
++ {0x3392, 0x0545}, // MCU_DATA_1
++ {0x3394, 0xCE10}, // MCU_DATA_2
++ {0x3396, 0x001D}, // MCU_DATA_3
++ {0x3398, 0x7101}, // MCU_DATA_4
++ {0x339A, 0xCE10}, // MCU_DATA_5
++ {0x339C, 0x801D}, // MCU_DATA_6
++ {0x339E, 0x3601}, // MCU_DATA_7
++ {0x338C, 0x0500}, // MCU_ADDRESS
++ {0x3390, 0x30E6}, // MCU_DATA_0
++ {0x3392, 0x134F}, // MCU_DATA_1
++ {0x3394, 0x175F}, // MCU_DATA_2
++ {0x3396, 0xED0E}, // MCU_DATA_3
++ {0x3398, 0x18FE}, // MCU_DATA_4
++ {0x339A, 0x0300}, // MCU_DATA_5
++ {0x339C, 0x18E6}, // MCU_DATA_6
++ {0x339E, 0x034F}, // MCU_DATA_7
++ {0x338C, 0x0510}, // MCU_ADDRESS
++ {0x3390, 0xED0C}, // MCU_DATA_0
++ {0x3392, 0xE30E}, // MCU_DATA_1
++ {0x3394, 0xCDEE}, // MCU_DATA_2
++ {0x3396, 0x0BEE}, // MCU_DATA_3
++ {0x3398, 0x04AD}, // MCU_DATA_4
++ {0x339A, 0x0030}, // MCU_DATA_5
++ {0x339C, 0x6D12}, // MCU_DATA_6
++ {0x339E, 0x2604}, // MCU_DATA_7
++ {0x338C, 0x0520}, // MCU_ADDRESS
++ {0x3390, 0xC602}, // MCU_DATA_0
++ {0x3392, 0x2002}, // MCU_DATA_1
++ {0x3394, 0xC606}, // MCU_DATA_2
++ {0x3396, 0xFE03}, // MCU_DATA_3
++ {0x3398, 0x00E7}, // MCU_DATA_4
++ {0x339A, 0x05FE}, // MCU_DATA_5
++ {0x339C, 0x0300}, // MCU_DATA_6
++ {0x339E, 0x3C18}, // MCU_DATA_7
++ {0x338C, 0x0530}, // MCU_ADDRESS
++ {0x3390, 0x38E6}, // MCU_DATA_0
++ {0x3392, 0x03E7}, // MCU_DATA_1
++ {0x3394, 0x0418}, // MCU_DATA_2
++ {0x3396, 0xFE03}, // MCU_DATA_3
++ {0x3398, 0x0030}, // MCU_DATA_4
++ {0x339A, 0xE613}, // MCU_DATA_5
++ {0x339C, 0x18E7}, // MCU_DATA_6
++ {0x339E, 0x0330}, // MCU_DATA_7
++ {0x338C, 0x0540}, // MCU_ADDRESS
++ {0x3390, 0xC614}, // MCU_DATA_0
++ {0x3392, 0x3A35}, // MCU_DATA_1
++ {0x3394, 0x3937}, // MCU_DATA_2
++ {0x3396, 0x3C3C}, // MCU_DATA_3
++ {0x3398, 0x3C30}, // MCU_DATA_4
++ {0x339A, 0x6F05}, // MCU_DATA_5
++ {0x339C, 0xA605}, // MCU_DATA_6
++ {0x339E, 0xC601}, // MCU_DATA_7
++ {0x338C, 0x0550}, // MCU_ADDRESS
++ {0x3390, 0xBD05}, // MCU_DATA_0
++ {0x3392, 0xCC30}, // MCU_DATA_1
++ {0x3394, 0xE406}, // MCU_DATA_2
++ {0x3396, 0x2765}, // MCU_DATA_3
++ {0x3398, 0xCC10}, // MCU_DATA_4
++ {0x339A, 0x80ED}, // MCU_DATA_5
++ {0x339C, 0x03E6}, // MCU_DATA_6
++ {0x339E, 0x0586}, // MCU_DATA_7
++ {0x338C, 0x0560}, // MCU_ADDRESS
++ {0x3390, 0x033D}, // MCU_DATA_0
++ {0x3392, 0x05E3}, // MCU_DATA_1
++ {0x3394, 0x03ED}, // MCU_DATA_2
++ {0x3396, 0x031A}, // MCU_DATA_3
++ {0x3398, 0xEE03}, // MCU_DATA_4
++ {0x339A, 0xEC13}, // MCU_DATA_5
++ {0x339C, 0x18ED}, // MCU_DATA_6
++ {0x339E, 0x001A}, // MCU_DATA_7
++ {0x338C, 0x0570}, // MCU_ADDRESS
++ {0x3390, 0xEE03}, // MCU_DATA_0
++ {0x3392, 0xEC11}, // MCU_DATA_1
++ {0x3394, 0x18ED}, // MCU_DATA_2
++ {0x3396, 0x021A}, // MCU_DATA_3
++ {0x3398, 0xEE03}, // MCU_DATA_4
++ {0x339A, 0xEC0F}, // MCU_DATA_5
++ {0x339C, 0x18ED}, // MCU_DATA_6
++ {0x339E, 0x041A}, // MCU_DATA_7
++ {0x338C, 0x0580}, // MCU_ADDRESS
++ {0x3390, 0xEE03}, // MCU_DATA_0
++ {0x3392, 0xEC0D}, // MCU_DATA_1
++ {0x3394, 0x18ED}, // MCU_DATA_2
++ {0x3396, 0x061A}, // MCU_DATA_3
++ {0x3398, 0xEE03}, // MCU_DATA_4
++ {0x339A, 0xEC0B}, // MCU_DATA_5
++ {0x339C, 0x18ED}, // MCU_DATA_6
++ {0x339E, 0x081A}, // MCU_DATA_7
++ {0x338C, 0x0590}, // MCU_ADDRESS
++ {0x3390, 0xEE03}, // MCU_DATA_0
++ {0x3392, 0xEC09}, // MCU_DATA_1
++ {0x3394, 0x18ED}, // MCU_DATA_2
++ {0x3396, 0x0AA6}, // MCU_DATA_3
++ {0x3398, 0x0544}, // MCU_DATA_4
++ {0x339A, 0x8B04}, // MCU_DATA_5
++ {0x339C, 0xC601}, // MCU_DATA_6
++ {0x339E, 0xBD05}, // MCU_DATA_7
++ {0x338C, 0x05A0}, // MCU_ADDRESS
++ {0x3390, 0xCC30}, // MCU_DATA_0
++ {0x3392, 0xA605}, // MCU_DATA_1
++ {0x3394, 0x44A7}, // MCU_DATA_2
++ {0x3396, 0x0286}, // MCU_DATA_3
++ {0x3398, 0x01ED}, // MCU_DATA_4
++ {0x339A, 0x00A6}, // MCU_DATA_5
++ {0x339C, 0x02E6}, // MCU_DATA_6
++ {0x339E, 0x00BD}, // MCU_DATA_7
++ {0x338C, 0x05B0}, // MCU_ADDRESS
++ {0x3390, 0x05CC}, // MCU_DATA_0
++ {0x3392, 0x30E7}, // MCU_DATA_1
++ {0x3394, 0x02EB}, // MCU_DATA_2
++ {0x3396, 0x01FA}, // MCU_DATA_3
++ {0x3398, 0x10B0}, // MCU_DATA_4
++ {0x339A, 0xF710}, // MCU_DATA_5
++ {0x339C, 0xB0E6}, // MCU_DATA_6
++ {0x339E, 0x05CB}, // MCU_DATA_7
++ {0x338C, 0x05C0}, // MCU_ADDRESS
++ {0x3390, 0x02E7}, // MCU_DATA_0
++ {0x3392, 0x05C1}, // MCU_DATA_1
++ {0x3394, 0x0825}, // MCU_DATA_2
++ {0x3396, 0x8538}, // MCU_DATA_3
++ {0x3398, 0x3838}, // MCU_DATA_4
++ {0x339A, 0x3139}, // MCU_DATA_5
++ {0x339C, 0x4D27}, // MCU_DATA_6
++ {0x339E, 0x0458}, // MCU_DATA_7
++ {0x338C, 0x05D0}, // MCU_ADDRESS
++ {0x3390, 0x4A26}, // MCU_DATA_0
++ {0x3392, 0xFC39}, // MCU_DATA_1
++ {0x338C, 0x2003}, // MCU_ADDRESS
++ {0x3390, 0x0400}, // MON_ARG1
++ {0x338C, 0xA002}, // MCU_ADDRESS
++ {0x3390, 0x0001}, // MON_CMD
++ {0x338C, 0xA102}, // MCU_ADDRESS
++ {0x3390, 0x001F}, // SEQ_MODE
++ {0x338C, 0x1070}, // MCU_ADDRESS
++ {0x3390, 0x0302}, // MCU_DATA_0
++ {0x338C, 0x1078}, // MCU_ADDRESS
++ {0x3390, 0x0CFC}, // MCU_DATA_0
++ {0x338C, 0xA505}, // MCU_ADDRESS
++ {0x3390, 0x0000}, // AF_MODE_EX
++ {0x338C, 0xA506}, // MCU_ADDRESS
++ {0x3390, 0x0010}, // AF_NUM_STEPS
++ {0x338C, 0xA514}, // MCU_ADDRESS
++ {0x3390, 0x0000}, // AF_POSITION_0
++ {0x338C, 0xA515}, // MCU_ADDRESS
++ {0x3390, 0x0011}, // AF_POSITION_1
++ {0x338C, 0xA516}, // MCU_ADDRESS
++ {0x3390, 0x0022}, // AF_POSITION_2
++ {0x338C, 0xA517}, // MCU_ADDRESS
++ {0x3390, 0x0033}, // AF_POSITION_3
++ {0x338C, 0xA518}, // MCU_ADDRESS
++ {0x3390, 0x0044}, // AF_POSITION_4
++ {0x338C, 0xA519}, // MCU_ADDRESS
++ {0x3390, 0x0055}, // AF_POSITION_5
++ {0x338C, 0xA51A}, // MCU_ADDRESS
++ {0x3390, 0x0066}, // AF_POSITION_6
++ {0x338C, 0xA51B}, // MCU_ADDRESS
++ {0x3390, 0x0077}, // AF_POSITION_7
++ {0x338C, 0xA51C}, // MCU_ADDRESS
++ {0x3390, 0x0088}, // AF_POSITION_8
++ {0x338C, 0xA51D}, // MCU_ADDRESS
++ {0x3390, 0x0099}, // AF_POSITION_9
++ {0x338C, 0xA51E}, // MCU_ADDRESS
++ {0x3390, 0x00AA}, // AF_POSITION_10
++ {0x338C, 0xA51F}, // MCU_ADDRESS
++ {0x3390, 0x00BB}, // AF_POSITION_11
++ {0x338C, 0xA520}, // MCU_ADDRESS
++ {0x3390, 0x00CC}, // AF_POSITION_12
++ {0x338C, 0xA521}, // MCU_ADDRESS
++ {0x3390, 0x00DD}, // AF_POSITION_13
++ {0x338C, 0xA522}, // MCU_ADDRESS
++ {0x3390, 0x00EE}, // AF_POSITION_14
++ {0x338C, 0xA523}, // MCU_ADDRESS
++ {0x3390, 0x00FE}, // AF_POSITION_15
++ {0x338C, 0xA505}, // MCU_ADDRESS
++ {0x3390, 0x0020}, // AF_MODE_EX
++ {0x338C, 0xA508}, // MCU_ADDRESS
++ {0x3390, 0x0004}, // AF_NUM_STEPS_2
++ {0x338C, 0xA509}, // MCU_ADDRESS
++ {0x3390, 0x0006}, // AF_STEP_SIZE
++
++ {0x338C, 0x1078}, // MCU_ADDRESS
++ {0x3390, 0x0CFC}, // MCU_DATA_0
++ {0x338C, 0x1070}, // MCU_ADDRESS
++ {0x3390, 0x0302}, // GPIO_DATA
++ {0x338C, 0x1074}, // MCU_ADDRESS
++ {0x3390, 0x0002}, // GPIO_OUTPUT_SET
++ {0x338C, 0x107E}, // MCU_ADDRESS
++ {0x3390, 0x0002}, // GPIO_DIR_OUT
++
++ {0x338C, 0xA603}, // MCU_ADDRESS
++ {0x3390, 0x0000}, // AF_STEP_SIZE
++#endif
++ {REG_TERM, VAL_TERM}
++};
++
++
++static struct sensor_reg sensor_preview[] = {
++ {0x338C, 0xA120},
++ {0x3390, 0x0000},
++ {0x338C, 0xA103},
++ {0x3390, 0x0001},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_capture[] = {
++ {0x338C, 0xA120},
++ {0x3390, 0x0002},
++ {0x338C, 0xA103},
++ {0x3390, 0x0002},
++ {REG_TERM, VAL_TERM}
++};
++
++ struct sensor_reg* sensor_reg_common[3] =
++{
++ sensor_common,
++ sensor_preview,
++ sensor_capture
++};
++
++static struct sensor_reg sensor_brightness_0[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_1[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_2[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_3[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_4[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_brightness[5] =
++{
++ sensor_brightness_0,
++ sensor_brightness_1,
++ sensor_brightness_2,
++ sensor_brightness_3,
++ sensor_brightness_4
++};
++
++
++static struct sensor_reg sensor_awb_auto[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_daylight[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_incandescent[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_fluorescent[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_cloudy[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_sunset[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_awb[6] =
++{
++ sensor_awb_auto,
++ sensor_awb_daylight,
++ sensor_awb_incandescent,
++ sensor_awb_fluorescent,
++ sensor_awb_cloudy,
++ sensor_awb_sunset
++
++};
++
++
++static struct sensor_reg sensor_iso_auto[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_100[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_200[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_400[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_iso[4] =
++{
++ sensor_iso_auto,
++ sensor_iso_100,
++ sensor_iso_200,
++ sensor_iso_400
++};
++
++
++static struct sensor_reg sensor_effect_normal[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_gray[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_negative[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sepia[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sharpness[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sketch[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_effect[6] =
++{
++ sensor_effect_normal,
++ sensor_effect_gray,
++ sensor_effect_negative,
++ sensor_effect_sepia,
++ sensor_effect_sharpness,
++ sensor_effect_sketch,
++};
++
++static struct sensor_reg sensor_reg_flipnone[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_hflip[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_vflip[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_hvflip[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_flip[4] =
++{
++ sensor_reg_flipnone,
++ sensor_reg_hflip,
++ sensor_reg_vflip,
++ sensor_reg_hvflip,
++};
++
++
++static struct sensor_reg sensor_secne_auto[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_night[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_landscape[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_portrait[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_sport[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_scene[5] =
++{
++ sensor_secne_auto,
++ sensor_secne_night,
++ sensor_secne_landscape,
++ sensor_secne_portrait,
++ sensor_secne_sport
++};
++
++static struct sensor_reg sensor_me_mtrix[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_me_center_weighted[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_me_spot[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_metering_exposure[3] =
++{
++ sensor_me_mtrix,
++ sensor_me_center_weighted,
++ sensor_me_spot,
++};
++
++static struct sensor_reg sensor_af_single[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_af_manual[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_af[2] =
++{
++ sensor_af_single,
++ sensor_af_manual,
++};
++
++#endif
++
+diff --git a/drivers/media/video/tcccam/mt9d112_2mp.h b/drivers/media/video/tcccam/mt9d112_2mp.h
+new file mode 100644
+index 0000000..326fcb5
+--- /dev/null
++++ b/drivers/media/video/tcccam/mt9d112_2mp.h
+@@ -0,0 +1,64 @@
++/*
++ * drivers/media/video/tcccam/mt9d112_2mp.h
++ *
++ * Register definitions for the mt9d112 CameraChip.
++ *
++ * Author: zzau (zzau@telechips.com)
++ *
++ * Copyright (C) 2008 Telechips, 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.
++ */
++
++#ifndef MT9D112_H
++#define MT9D112_H
++
++/* The MT9D112 I2C sensor chip has a fixed slave address of 0x7A. */
++#define SENSOR_I2C_ADDR 0x7A
++
++#define REG_TERM 0x0000 /* terminating list entry for reg */
++#define VAL_TERM 0x0000 /* terminating list entry for val */
++
++#define CAMDLY 0xFFFF
++
++// ZOOM Setting!!
++#define PRV_W 800
++#define PRV_H 600
++#define PRV_ZOFFX 8
++#define PRV_ZOFFY 6
++
++#define CAP_W 1600
++#define CAP_H 1200
++#define CAP_ZOFFX 16
++#define CAP_ZOFFY 12
++
++#define CAM_2XMAX_ZOOM_STEP 25
++#define CAM_CAPCHG_WIDTH 800
++
++
++struct sensor_reg {
++ unsigned short reg;
++ unsigned short val[1];
++};
++
++struct capture_size {
++ unsigned long width;
++ unsigned long height;
++};
++
++extern struct capture_size sensor_sizes[];
++
++extern struct sensor_reg* sensor_reg_common[];
++extern struct sensor_reg* sensor_reg_brightness[];
++extern struct sensor_reg* sensor_reg_awb[];
++extern struct sensor_reg* sensor_reg_iso[];
++extern struct sensor_reg* sensor_reg_effect[];
++extern struct sensor_reg* sensor_reg_flip[];
++extern struct sensor_reg* sensor_reg_scene[];
++extern struct sensor_reg* sensor_reg_metering_exposure[];
++extern struct sensor_reg* sensor_reg_af[];
++
++#endif /* MT9D112_H */
++
+diff --git a/drivers/media/video/tcccam/mt9p111_5mp.c b/drivers/media/video/tcccam/mt9p111_5mp.c
+new file mode 100644
+index 0000000..297400a
+--- /dev/null
++++ b/drivers/media/video/tcccam/mt9p111_5mp.c
+@@ -0,0 +1,1264 @@
++/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
++
++ CAMERA API M O D U L E
++
++ EDIT HISTORY FOR MODULE
++
++when who what, where, why
++-------- --- -------------------------------------------------------
++10/xx/08 Telechips Created file.
++*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
++
++/*===========================================================================
++
++ INCLUDE FILES FOR MODULE
++
++===========================================================================*/
++#include "sensor_if.h"
++
++#ifdef CONFIG_VIDEO_CAMERA_SENSOR_MT9P111
++
++/* Array of image sizes supported by MV9317. These must be ordered from
++ * smallest image size to largest.
++ */
++struct capture_size sensor_sizes[] = {
++ { 2560, 1920 }, /* QQXGA */
++ { 2048, 1536 }, /* QXGA */
++ { 1600, 1200 }, /* UXGA */
++ { 1280, 720 }, /* SXGA */
++ { 1024, 768 }, /* XGA */
++ { 800, 600 }, /* SVGA */
++ { 640, 480 }, /* VGA */
++ { 320, 240 }, /* QVGA */
++ { 176, 144 }, /* QCIF */
++};
++
++
++/* register initialization tables for sensor */
++/* common sensor register initialization for all image sizes, pixel formats,
++ * and frame rates
++ */
++static struct sensor_reg sensor_common[] = {
++//PART 0 BURST-DATA
++ {0x0010, 0x0120, 0x0070, 0x2025, 0x1111},
++ {0x001E, 0x0777, 0x1111}, // PAD_SLEW_PAD_CONFIG
++ {0x0022, 0x01E0, 0x1111}, // VDD_DIS_COUNTER
++ {0x002A, 0x7FFF, 0x0000, 0x0000, 0x1111},
++ {0x0018, 0x4008, 0x1111}, // STANDBY_CONTROL_AND_STATUS
++ {0x098E, 0x8001, 0x1111}, // LOGICAL_ADDRESS_ACCESS [MON_MODE]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x0982, 0x0000, 0x1111}, // ACCESS_CTL_STAT
++ {0x098A, 0x0838, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xC0F1, 0xC5E1, 0x246A, 0x1280, 0xC4E1, 0xD30E, 0x2069, 0x0000, 0x1111},
++ {0x098A, 0x0848, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x1305, 0x0084, 0x1730, 0x7005, 0xD801, 0x8B41, 0xD900, 0x0D0A, 0x1111},
++ {0x098A, 0x0858, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x0064, 0x8B63, 0xE809, 0xD509, 0xF004, 0x1504, 0x1400, 0x7840, 0x1111},
++ {0x098A, 0x0868, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xD007, 0x0DFB, 0x9004, 0xC4C1, 0x2029, 0x0300, 0x0191, 0x0684, 0x1111},
++ {0x098A, 0x0878, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xFF80, 0x0894, 0xFF80, 0x0838, 0xFF80, 0x0888, 0xFF80, 0x0894, 0x1111},
++ {0x098A, 0x0888, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xFF80, 0x0AA4, 0xFF80, 0x0A10, 0xFF80, 0x0B78, 0x0001, 0x0003, 0x1111},
++ {0x098A, 0x0898, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x0000, 0x0000, 0xC0F1, 0x0DBA, 0x01C4, 0xD167, 0xD067, 0x1952, 0x1111},
++ {0x098A, 0x08A8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x0024, 0x208A, 0x0004, 0x199C, 0x0024, 0xD165, 0x8101, 0x2004, 0x1111},
++ {0x098A, 0x08B8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x8FBE, 0x0100, 0xF0F0, 0xF208, 0x8901, 0x080D, 0x005E, 0xD061, 0x1111},
++ {0x098A, 0x08C8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xD901, 0xA820, 0xC0D1, 0x7EE0, 0xC0F1, 0x08BE, 0x0684, 0xD75C, 0x1111},
++ {0x098A, 0x08D8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x970E, 0x0813, 0x015E, 0xD15C, 0x814E, 0x9239, 0xB734, 0x925A, 0x1111},
++ {0x098A, 0x08E8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xF005, 0xD25A, 0x922A, 0x924B, 0xB734, 0xD653, 0xD558, 0x2053, 0x1111},
++ {0x098A, 0x08F8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x8040, 0x1E40, 0x1064, 0x1E42, 0x10A4, 0xB755, 0xF220, 0x0A0E, 0x1111},
++ {0x098A, 0x0908, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x01E4, 0xD801, 0xD800, 0xAF00, 0x1E3C, 0x1024, 0x8500, 0x8009, 0x1111},
++ {0x098A, 0x0918, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x7860, 0xDF00, 0x8500, 0x8004, 0x7840, 0x8500, 0x8005, 0x7840, 0x1111},
++ {0x098A, 0x0928, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x8500, 0x8006, 0x7840, 0xD045, 0x1E52, 0x1024, 0x208A, 0x0004, 0x1111},
++ {0x098A, 0x0938, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x1E9C, 0x1024, 0x8500, 0x8003, 0x7840, 0xF021, 0x8500, 0x8003, 0x1111},
++ {0x098A, 0x0948, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x7840, 0xD800, 0x163C, 0x1901, 0x2153, 0x00C2, 0x0A25, 0x0153, 0x1111},
++ {0x098A, 0x0958, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x695C, 0xBAC3, 0x0A1D, 0x0153, 0x2942, 0x0202, 0xBAC3, 0xE284, 0x1111},
++ {0x098A, 0x0968, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x29C2, 0x032C, 0x21D3, 0x00EC, 0x21CC, 0x812C, 0x20CA, 0x006C, 0x1111},
++ {0x098A, 0x0978, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xE86A, 0xDF00, 0x0996, 0x01E4, 0x70E9, 0xD032, 0x8800, 0xE809, 0x1111},
++ {0x098A, 0x0988, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x167E, 0x1900, 0xE080, 0x27CA, 0x1061, 0x1E7E, 0x13E4, 0x8500, 0x1111},
++ {0x098A, 0x0998, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x8007, 0x7840, 0x0059, 0x0684, 0xC0F1, 0x0A5A, 0x01C4, 0xD228, 0x1111},
++ {0x098A, 0x09A8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x920E, 0x2051, 0x8180, 0x9212, 0xF205, 0x204F, 0x01C1, 0xB232, 0x1111},
++ {0x098A, 0x09B8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xF004, 0xB8A7, 0x7910, 0xB212, 0xD026, 0x1804, 0x0064, 0xF184, 0x1111},
++ {0x098A, 0x09C8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xC0F1, 0xC5E1, 0xD21E, 0x8A01, 0x9234, 0x9275, 0x0815, 0x009E, 0x1111},
++ {0x098A, 0x09D8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x8A31, 0x8A12, 0x8A73, 0xB908, 0x7905, 0x8A14, 0xBB08, 0x7B05, 0x1111},
++ {0x098A, 0x09E8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x8A00, 0x92AE, 0xB8A2, 0xAA00, 0x0D13, 0x105E, 0xDD05, 0xBD09, 0x1111},
++ {0x098A, 0x09F8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x0D0B, 0x1043, 0xB882, 0xAA00, 0x71A9, 0xD017, 0x1808, 0x0064, 0x1111},
++ {0x098A, 0x0A08, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x180A, 0x00E4, 0x07F9, 0x0644, 0xC0F1, 0x0F82, 0x0664, 0xDA28, 0x1111},
++ {0x098A, 0x0A18, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xD112, 0xD513, 0x76A9, 0x0D16, 0x0664, 0x70C9, 0xD011, 0xA507, 0x1111},
++ {0x098A, 0x0A28, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xD011, 0xA502, 0xD011, 0xA503, 0xD011, 0xA509, 0xD008, 0x07C9, 0x1111},
++ {0x098A, 0x0A38, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x0664, 0xA0C0, 0xFF00, 0x3BC4, 0x0000, 0xFFFF, 0xFF80, 0x0290, 0x1111},
++ {0x098A, 0x0A48, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xFF80, 0x0BF8, 0xFF80, 0x0340, 0xFF80, 0x02D0, 0x8000, 0x0070, 0x1111},
++ {0x098A, 0x0A58, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xFF00, 0x3C3C, 0xFF00, 0x3C00, 0x0000, 0xE758, 0xFF80, 0x0BFC, 0x1111},
++ {0x098A, 0x0A68, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xFF80, 0x089C, 0xFF80, 0x08D0, 0xFF80, 0x09A0, 0xFF80, 0x09C8, 0x1111},
++ {0x098A, 0x0A78, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xC0F1, 0xC5E1, 0x099E, 0xFFE3, 0x7508, 0xD111, 0x79B6, 0x8910, 0x1111},
++ {0x098A, 0x0A88, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x080D, 0x0091, 0xD20F, 0x9201, 0xB886, 0xB201, 0x890F, 0x080D, 0x1111},
++ {0x098A, 0x0A98, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x0111, 0xD00D, 0xD905, 0xB021, 0x0765, 0x0644, 0xC0F1, 0x0EEA, 0x1111},
++ {0x098A, 0x0AA8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x0664, 0xDA34, 0xD709, 0xD60A, 0x75E9, 0x70A9, 0x0D2E, 0x0664, 0x1111},
++ {0x098A, 0x0AB8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x8620, 0xD008, 0xA701, 0x0739, 0x0664, 0xA6A0, 0xFF80, 0x01B0, 0x1111},
++ {0x098A, 0x0AC8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xFF80, 0x05E8, 0xFF80, 0x0698, 0xFF80, 0x0C24, 0x8000, 0x0000, 0x1111},
++ {0x098A, 0x0AD8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xFF80, 0x0A78, 0xC0F1, 0x0EAA, 0x0644, 0x0DAE, 0x0544, 0xD02D, 0x1111},
++ {0x098A, 0x0AE8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xD52D, 0x88D2, 0x08C2, 0x00A4, 0x8D04, 0x7EDB, 0xD72B, 0x218A, 0x1111},
++ {0x098A, 0x0AF8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x0FCF, 0x2805, 0x03BE, 0x2941, 0x7140, 0x208C, 0x8FCF, 0x20CA, 0x1111},
++ {0x098A, 0x0B08, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x0046, 0x1F2E, 0x1024, 0x08A2, 0x00A4, 0x9507, 0xD624, 0x16E3, 0x1111},
++ {0x098A, 0x0B18, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x1082, 0x703A, 0x1660, 0x1104, 0x9507, 0x7148, 0x2186, 0x03FC, 0x1111},
++ {0x098A, 0x0B28, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xB944, 0xBAC3, 0x0876, 0x00A4, 0x165E, 0x1103, 0x6018, 0x7815, 0x1111},
++ {0x098A, 0x0B38, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x0F0E, 0x0664, 0x712A, 0x16E2, 0x1082, 0x2840, 0x0210, 0x1660, 0x1111},
++ {0x098A, 0x0B48, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x1104, 0x9507, 0x7148, 0x2186, 0x03FC, 0xB944, 0xBAC3, 0x084E, 0x1111},
++ {0x098A, 0x0B58, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x00A4, 0x165E, 0x1103, 0x6018, 0x7815, 0x0EE6, 0x0664, 0x712A, 0x1111},
++ {0x098A, 0x0B68, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xB80C, 0x2005, 0x0400, 0x1F32, 0x1024, 0x0675, 0x0644, 0x78E0, 0x1111},
++ {0x098A, 0x0B78, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xC0F1, 0x0E1A, 0x0664, 0xDA38, 0xD10A, 0xD50B, 0x76A9, 0x0BAE, 0x1111},
++ {0x098A, 0x0B88, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x0664, 0x70C9, 0xD009, 0xA503, 0xD009, 0x066D, 0x0664, 0xA0C0, 0x1111},
++ {0x098A, 0x0B98, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xFF80, 0x05D4, 0xFF80, 0x07C8, 0xFF00, 0x3390, 0xFF80, 0x06E4, 0x1111},
++ {0x098A, 0x0BA8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x0000, 0xF170, 0xFF80, 0x0C58, 0xFF80, 0x0ADC, 0x8000, 0x014C, 0x1111},
++ {0x098A, 0x0BB8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0xEA0A, 0x242F, 0x7089, 0x78E0, 0x20A8, 0x0180, 0x1002, 0x0D02, 0x1111},
++ {0x098A, 0x0BC8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x1902, 0x0094, 0x7FE0, 0x7028, 0x7308, 0x1000, 0x0900, 0x7904, 0x1111},
++ {0x098A, 0x0BD8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x7947, 0x1B00, 0x0064, 0x7EE0, 0xEA0A, 0x242F, 0x7089, 0x78E0, 0x1111},
++ {0x098A, 0x0BE8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x20A8, 0x0180, 0x1102, 0x0502, 0x1802, 0x00B4, 0x7FE0, 0x7028, 0x1111},
++ {0x098A, 0x0BF8, 0x1111}, // PHYSICAL_ADDRESS_ACCESS
++ {0x0990, 0x0000, 0x0000, 0x1111},
++ {0x098E, 0x0016, 0x1111}, // LOGICAL_ADDRESS_ACCESS [MON_ADDRESS_LO]
++ {0x0990, 0x0838, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x0002, 0x1111}, // LOGICAL_ADDRESS_ACCESS [MON_CMD]
++
++ {REG_TERM, 0x0050, 0x1111}, //delay 80ms
++
++//PART 1
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x30D4, 0xB080, 0x1111}, // COLUMN_CORRECTION
++ {0x316E, 0xC400, 0x1111}, // DAC_ECL
++ {0x305E, 0x10A0, 0x1111}, // GLOBAL_GAIN
++ {0x3E00, 0x0010, 0x1111}, // SAMP_CONTROL
++ {0x3E02, 0xED02, 0x1111}, // SAMP_ADDR_EN
++ {0x3E04, 0xC88C, 0x1111}, // SAMP_RD1_SIG
++ {0x3E06, 0xC88C, 0x1111}, // SAMP_RD1_SIG_BOOST
++ {0x3E08, 0x700A, 0x1111}, // SAMP_RD1_RST
++ {0x3E0A, 0x701E, 0x1111}, // SAMP_RD1_RST_BOOST
++ {0x3E0C, 0x00FF, 0x1111}, // SAMP_RST1_EN
++ {0x3E0E, 0x00FF, 0x1111}, // SAMP_RST1_BOOST
++ {0x3E10, 0x00FF, 0x1111}, // SAMP_RST1_CLOOP_SH
++ {0x3E12, 0x0000, 0x1111}, // SAMP_RST_BOOST_SEQ
++ {0x3E14, 0xC78C, 0x1111}, // SAMP_SAMP1_SIG
++ {0x3E16, 0x6E06, 0x1111}, // SAMP_SAMP1_RST
++ {0x3E18, 0xA58C, 0x1111}, // SAMP_TX_EN
++ {0x3E1A, 0xA58E, 0x1111}, // SAMP_TX_BOOST
++ {0x3E1C, 0xA58E, 0x1111}, // SAMP_TX_CLOOP_SH
++ {0x3E1E, 0xC0D0, 0x1111}, // SAMP_TX_BOOST_SEQ
++ {0x3E20, 0xEB00, 0x1111}, // SAMP_VLN_EN
++ {0x3E22, 0x00FF, 0x1111}, // SAMP_VLN_HOLD
++ {0x3E24, 0xEB02, 0x1111}, // SAMP_VCL_EN
++ {0x3E26, 0xEA02, 0x1111}, // SAMP_COLCLAMP
++ {0x3E28, 0xEB0A, 0x1111}, // SAMP_SH_VCL
++ {0x3E2A, 0xEC01, 0x1111}, // SAMP_SH_VREF
++ {0x3E2C, 0xEB01, 0x1111}, // SAMP_SH_VBST
++ {0x3E2E, 0x00FF, 0x1111}, // SAMP_SPARE
++ {0x3E30, 0x00F3, 0x1111}, // SAMP_READOUT
++ {0x3E32, 0x3DFA, 0x1111}, // SAMP_RESET_DONE
++ {0x3E34, 0x00FF, 0x1111}, // SAMP_VLN_CLAMP
++ {0x3E36, 0x00F3, 0x1111}, // SAMP_ASC_INT
++ {0x3E38, 0x0000, 0x1111}, // SAMP_RS_CLOOP_SH_R
++ {0x3E3A, 0xF802, 0x1111}, // SAMP_RS_CLOOP_SH
++ {0x3E3C, 0x0FFF, 0x1111}, // SAMP_RS_BOOST_SEQ
++ {0x3E3E, 0xEA10, 0x1111}, // SAMP_TXLO_GND
++ {0x3E40, 0xEB05, 0x1111}, // SAMP_VLN_PER_COL
++ {0x3E42, 0xE5C8, 0x1111}, // SAMP_RD2_SIG
++ {0x3E44, 0xE5C8, 0x1111}, // SAMP_RD2_SIG_BOOST
++ {0x3E46, 0x8C70, 0x1111}, // SAMP_RD2_RST
++ {0x3E48, 0x8C71, 0x1111}, // SAMP_RD2_RST_BOOST
++ {0x3E4A, 0x00FF, 0x1111}, // SAMP_RST2_EN
++ {0x3E4C, 0x00FF, 0x1111}, // SAMP_RST2_BOOST
++ {0x3E4E, 0x00FF, 0x1111}, // SAMP_RST2_CLOOP_SH
++ {0x3E50, 0xE38D, 0x1111}, // SAMP_SAMP2_SIG
++ {0x3E52, 0x8B0A, 0x1111}, // SAMP_SAMP2_RST
++ {0x3E58, 0xEB0A, 0x1111}, // SAMP_PIX_CLAMP_EN
++ {0x3E5C, 0x0A00, 0x1111}, // SAMP_PIX_PULLUP_EN
++ {0x3E5E, 0x00FF, 0x1111}, // SAMP_PIX_PULLDOWN_EN_R
++ {0x3E60, 0x00FF, 0x1111}, // SAMP_PIX_PULLDOWN_EN_S
++ {0x3E90, 0x3C01, 0x1111}, // RST_ADDR_EN
++ {0x3E92, 0x00FF, 0x1111}, // RST_RST_EN
++ {0x3E94, 0x00FF, 0x1111}, // RST_RST_BOOST
++ {0x3E96, 0x3C00, 0x1111}, // RST_TX_EN
++ {0x3E98, 0x3C00, 0x1111}, // RST_TX_BOOST
++ {0x3E9A, 0x3C00, 0x1111}, // RST_TX_CLOOP_SH
++ {0x3E9C, 0xC0E0, 0x1111}, // RST_TX_BOOST_SEQ
++ {0x3E9E, 0x00FF, 0x1111}, // RST_RST_CLOOP_SH
++ {0x3EA0, 0x0000, 0x1111}, // RST_RST_BOOST_SEQ
++ {0x3EA6, 0x3C00, 0x1111}, // RST_PIX_PULLUP_EN
++ {0x3ED8, 0x3057, 0x1111}, // DAC_LD_12_13
++ {0x3172, 0x0113, 0x1111}, // ANALOG_CONTROL2
++ {0x316C, 0xB44F, 0x1111}, // DAC_TXLO
++ {0x316E, 0xC6FF, 0x1111}, // DAC_ECL
++ {0x3ED2, 0xEA0F, 0x1111}, // DAC_LD_6_7
++ {0x3ED4, 0x0004, 0x1111}, // DAC_LD_8_9
++ {0x3EDC, 0x6020, 0x1111}, // DAC_LD_16_17
++ {0x3EE6, 0xA5C0, 0x1111}, // DAC_LD_26_27
++ {0x098E, 0x483A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_Y_ADDR_START]
++ {0x0990, 0x000C, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x483C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_X_ADDR_START]
++ {0x0990, 0x0018, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x483E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_Y_ADDR_END]
++ {0x0990, 0x07B1, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4840, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_X_ADDR_END]
++ {0x0990, 0x0A45, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4842, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_ROW_SPEED]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4844, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_SKIP_X_CORE]
++ {0x0990, 0x0103, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4846, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_SKIP_Y_CORE]
++ {0x0990, 0x0103, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4848, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_SKIP_X_PIPE]
++ {0x0990, 0x0103, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x484A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_SKIP_Y_PIPE]
++ {0x0990, 0x0103, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x484C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_POWER_MODE]
++ {0x0990, 0x00F6, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x484E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_BIN_MODE]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xC850, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_ORIENTATION]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xC851, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_PIXEL_ORDER]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4852, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_FINE_CORRECTION]
++ {0x0990, 0x019C, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4854, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_FINE_ITMIN]
++ {0x0990, 0x0732, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4858, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_COARSE_ITMIN]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x485A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_COARSE_ITMAX_MARGIN]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x485C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_MIN_FRAME_LENGTH_LINES]
++ {0x0990, 0x0423, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x485E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_MAX_FRAME_LENGTH_LINES]
++ {0x0990, 0xFFFF, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4860, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_BASE_FRAME_LENGTH_LINES]
++ {0x0990, 0x0423, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4862, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_MIN_LINE_LENGTH_PCLK]
++ {0x0990, 0x0F06, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4864, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_MAX_LINE_LENGTH_PCLK]
++ {0x0990, 0xFFFE, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4866, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_P4_5_6_DIVIDER]
++ {0x0990, 0x7F7C, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4868, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_FRAME_LENGTH_LINES]
++ {0x0990, 0x0423, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x486A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_LINE_LENGTH_PCK]
++ {0x0990, 0x0F06, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x486C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_OUTPUT_SIZE_WIDTH]
++ {0x0990, 0x0518, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x486E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_OUTPUT_SIZE_HEIGHT]
++ {0x0990, 0x03D4, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4870, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_RX_FIFO_TRIGGER_MARK]
++ {0x0990, 0x0014, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48B8, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_0_JPEG_CONTROL]
++ {0x0990, 0x0004, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48AE, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_0_OUTPUT_FORMAT]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48AA, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_0_IMAGE_WIDTH]
++ {0x0990, 0x0280, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48AC, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_0_IMAGE_HEIGHT]
++ {0x0990, 0x01E0, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4872, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_Y_ADDR_START]
++ {0x0990, 0x0010, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4874, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_X_ADDR_START]
++ {0x0990, 0x001C, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4876, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_Y_ADDR_END]
++ {0x0990, 0x07AF, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4878, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_X_ADDR_END]
++ {0x0990, 0x0A43, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x487A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_ROW_SPEED]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x487C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_SKIP_X_CORE]
++ {0x0990, 0x0101, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x487E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_SKIP_Y_CORE]
++ {0x0990, 0x0101, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4880, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_SKIP_X_PIPE]
++ {0x0990, 0x0101, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4882, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_SKIP_Y_PIPE]
++ {0x0990, 0x0101, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4884, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_POWER_MODE]
++ {0x0990, 0x00F2, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4886, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_BIN_MODE]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xC888, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_ORIENTATION]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xC889, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_PIXEL_ORDER]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x488A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_FINE_CORRECTION]
++ {0x0990, 0x009C, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x488C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_FINE_ITMIN]
++ {0x0990, 0x034A, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4890, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_COARSE_ITMIN]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4892, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_COARSE_ITMAX_MARGIN]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4894, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_MIN_FRAME_LENGTH_LINES]
++ {0x0990, 0x082F, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4896, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_MAX_FRAME_LENGTH_LINES]
++ {0x0990, 0xFFFF, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4898, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_BASE_FRAME_LENGTH_LINES]
++ {0x0990, 0x082F, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x489A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_MIN_LINE_LENGTH_PCLK]
++ {0x0990, 0x10CC, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x489C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_MAX_LINE_LENGTH_PCLK]
++ {0x0990, 0xFFFE, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x489E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_P4_5_6_DIVIDER]
++ {0x0990, 0x7F7C, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48A0, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_FRAME_LENGTH_LINES]
++ {0x0990, 0x082F, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48A2, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_LINE_LENGTH_PCK]
++ {0x0990, 0x10CC, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48A4, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_OUTPUT_SIZE_WIDTH]
++ {0x0990, 0x0A28, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48A6, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_OUTPUT_SIZE_HEIGHT]
++ {0x0990, 0x07A0, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48A8, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_RX_FIFO_TRIGGER_MARK]
++ {0x0990, 0x0014, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48CE, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_1_JPEG_CONTROL]
++ {0x0990, 0x0015, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48C4, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_1_OUTPUT_FORMAT]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48C0, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_1_IMAGE_WIDTH]
++ {0x0990, 0x0A20, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48C2, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_1_IMAGE_HEIGHT]
++ {0x0990, 0x0798, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x301A, 0x10F4, 0x1111}, // RESET_REGISTER
++ {0x301E, 0x0000, 0x1111}, // DATA_PEDESTAL
++ {0x301A, 0x10FC, 0x1111}, // RESET_REGISTER
++ {0x098E, 0xDC33, 0x1111}, // LOGICAL_ADDRESS_ACCESS [SYS_FIRST_BLACK_LEVEL]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xDC35, 0x1111}, // LOGICAL_ADDRESS_ACCESS [SYS_UV_COLOR_BOOST]
++ {0x0990, 0x0400, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x326E, 0x0004, 0x1111}, // LOW_PASS_YUV_FILTER
++ {0x098E, 0x4858, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_COARSE_ITMIN]
++ {0x0990, 0x0002, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4890, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_B_COARSE_ITMIN]
++ {0x0990, 0x0002, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xDC37, 0x1111}, // LOGICAL_ADDRESS_ACCESS [SYS_BRIGHT_COLORKILL]
++ {0x0990, 0x6200, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x35A4, 0x0596, 0x1111}, // BRIGHT_COLOR_KILL_CONTROLS
++ {0x35A2, 0x0094, 0x1111}, // DARK_COLOR_KILL_CONTROLS
++ {0x098E, 0xDC36, 0x1111}, // LOGICAL_ADDRESS_ACCESS [SYS_DARK_COLOR_KILL]
++ {0x0990, 0x2300, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x8404, 0x1111}, // LOGICAL_ADDRESS_ACCESS [SEQ_CMD]
++ {0x0990, 0x0600, 0x1111}, // MCU_VARIABLE_DATA0
++
++ {REG_TERM, 0x0050, 0x1111}, //delay 80ms
++
++//PART 2
++ {0x098E, 0x3C14, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_FADE_TO_BLACK_START_POS]
++ {0x0990, 0xFFFE, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C16, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_FADE_TO_BLACK_END_POS]
++ {0x0990, 0xFFFF, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x32BA, 0x0000, 0x1111}, // RED_OFFSET_TO_CCM
++ {0x32BC, 0x0000, 0x1111}, // GREEN_OFFSET_TO_CCM
++ {0x32BE, 0x0000, 0x1111}, // BLUE_OFFSET_TO_CCM
++ {0x3330, 0x0000, 0x1111}, // OUTPUT_FORMAT_TEST
++ {0x337C, 0x0004, 0x1111}, // YUV_YCBCR_CONTROL
++ {0x337E, 0x0000, 0x1111}, // Y_RGB_OFFSET
++ {0x0010, 0x0320, 0x1111}, // PLL_DIVIDERS
++ {0x0010, 0x0360, 0x1111}, // PLL_DIVIDERS
++ {0x32BA, 0x0000, 0x1111}, // RED_OFFSET_TO_CCM
++ {0x32BC, 0x0000, 0x1111}, // GREEN_OFFSET_TO_CCM
++ {0x32BE, 0x0000, 0x1111}, // BLUE_OFFSET_TO_CCM
++ {0x098E, 0xA00E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_MAX_NUM_AUTOCOR_FUNC_VALUES_TO_CHECK]
++ {0x0990, 0x3200, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2018, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_EXPECTED50HZ_FLICKER_PERIOD_IN_CONTEXT_A]
++ {0x0990, 0x0133, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x201A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_EXPECTED50HZ_FLICKER_PERIOD_IN_CONTEXT_B]
++ {0x0990, 0x0113, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x201C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_EXPECTED60HZ_FLICKER_PERIOD_IN_CONTEXT_A]
++ {0x0990, 0x00FF, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x201E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_EXPECTED60HZ_FLICKER_PERIOD_IN_CONTEXT_B]
++ {0x0990, 0x00E4, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2010, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_MIN_EXPECTED50HZ_FLICKER_PERIOD]
++ {0x0990, 0x0129, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2012, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_MAX_EXPECTED50HZ_FLICKER_PERIOD]
++ {0x0990, 0x013D, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2014, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_MIN_EXPECTED60HZ_FLICKER_PERIOD]
++ {0x0990, 0x00F5, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2016, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_MAX_EXPECTED60HZ_FLICKER_PERIOD]
++ {0x0990, 0x0109, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xA000, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_STATUS]
++ {0x0990, 0x1400, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x3380, 0x0504, 0x1111}, // KERNEL_CONFIG
++ {0x098E, 0xBCB2, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_CDC_DARK_CLUS_SLOPE]
++ {0x0990, 0x2800, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCB3, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_CDC_DARK_CLUS_SATUR]
++ {0x0990, 0x5F00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C46, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_LEFT_CCM_0]
++ {0x0990, 0x0227, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C48, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_LEFT_CCM_1]
++ {0x0990, 0xFEBE, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C4A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_LEFT_CCM_2]
++ {0x0990, 0x0038, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C4C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_LEFT_CCM_3]
++ {0x0990, 0xFFCB, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C4E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_LEFT_CCM_4]
++ {0x0990, 0x014D, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C50, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_LEFT_CCM_5]
++ {0x0990, 0x0006, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C52, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_LEFT_CCM_6]
++ {0x0990, 0xFFC6, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C54, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_LEFT_CCM_7]
++ {0x0990, 0xFED3, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C56, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_LEFT_CCM_8]
++ {0x0990, 0x0284, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C5C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_RIGHT_CCM_0]
++ {0x0990, 0x024A, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C5E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_RIGHT_CCM_1]
++ {0x0990, 0xFF25, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C60, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_RIGHT_CCM_2]
++ {0x0990, 0xFFAE, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C62, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_RIGHT_CCM_3]
++ {0x0990, 0xFFCC, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C64, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_RIGHT_CCM_4]
++ {0x0990, 0x0150, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C66, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_RIGHT_CCM_5]
++ {0x0990, 0x0002, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C68, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_RIGHT_CCM_6]
++ {0x0990, 0xFFFB, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C6A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_RIGHT_CCM_7]
++ {0x0990, 0xFF69, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C6C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_RIGHT_CCM_8]
++ {0x0990, 0x01B9, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C58, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_LEFT_CCM_R2BRATIO]
++ {0x0990, 0x00CD, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2C6E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_RIGHT_CCM_R2BRATIO]
++ {0x0990, 0x0050, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x3240, 0x0012, 0x1111}, // AWB_XY_SCALE
++ {0x3242, 0xF31A, 0x1111}, // AWB_WEIGHT_R0
++ {0x3244, 0xFE36, 0x1111}, // AWB_WEIGHT_R1
++ {0x3246, 0xDF28, 0x1111}, // AWB_WEIGHT_R2
++ {0x3248, 0xD724, 0x1111}, // AWB_WEIGHT_R3
++ {0x324A, 0xE3B5, 0x1111}, // AWB_WEIGHT_R4
++ {0x324C, 0xD587, 0x1111}, // AWB_WEIGHT_R5
++ {0x324E, 0xD3F1, 0x1111}, // AWB_WEIGHT_R6
++ {0x3250, 0x2C8F, 0x1111}, // AWB_WEIGHT_R7
++ {0x098E, 0x3842, 0x1111}, // LOGICAL_ADDRESS_ACCESS [STAT_AWB_GRAY_CHECKER_OFFSET_X]
++ {0x0990, 0x003A, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3844, 0x1111}, // LOGICAL_ADDRESS_ACCESS [STAT_AWB_GRAY_CHECKER_OFFSET_Y]
++ {0x0990, 0x0037, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xAC01, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_MODE]
++ {0x0990, 0xAB00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xAC3C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_MIN_ACCEPTED_PRE_AWB_R2G_RATIO]
++ {0x0990, 0x3900, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xAC3D, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_MAX_ACCEPTED_PRE_AWB_R2G_RATIO]
++ {0x0990, 0x6E00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xAC3E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_MIN_ACCEPTED_PRE_AWB_B2G_RATIO]
++ {0x0990, 0x2800, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xAC3F, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AWB_MAX_ACCEPTED_PRE_AWB_B2G_RATIO]
++ {0x0990, 0x6B00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCDE, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_SYS_THRESHOLD]
++ {0x0990, 0x0400, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCDF, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_STOP_SYS_THRESHOLD]
++ {0x0990, 0x1800, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCE0, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_SYS_GAIN]
++ {0x0990, 0x0400, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCE1, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_STOP_SYS_GAIN]
++ {0x0990, 0x0400, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xB801, 0x1111}, // LOGICAL_ADDRESS_ACCESS [STAT_MODE]
++ {0x0990, 0xE000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xB862, 0x1111}, // LOGICAL_ADDRESS_ACCESS [STAT_BMTRACKING_SPEED]
++ {0x0990, 0x0400, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xB829, 0x1111}, // LOGICAL_ADDRESS_ACCESS [STAT_LL_BRIGHTNESS_METRIC_DIVISOR]
++ {0x0990, 0x1100, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xB863, 0x1111}, // LOGICAL_ADDRESS_ACCESS [STAT_BM_MUL]
++ {0x0990, 0x1700, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xB827, 0x1111}, // LOGICAL_ADDRESS_ACCESS [STAT_AE_EV_SHIFT]
++ {0x0990, 0x0E00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xA409, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_RULE_BASE_TARGET]
++ {0x0990, 0x3800, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C52, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_BRIGHTNESS_METRIC]
++ {0x0990, 0x00E0, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C54, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_END_BRIGHTNESS_METRIC]
++ {0x0990, 0x32B8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C58, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_GAIN_METRIC]
++ {0x0990, 0x012C, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C5A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_END_GAIN_METRIC]
++ {0x0990, 0x106C, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C5E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_APERTURE_GAIN_BM]
++ {0x0990, 0x00FA, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C60, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_END_APERTURE_GAIN_BM]
++ {0x0990, 0x02B2, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C66, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_APERTURE_GM]
++ {0x0990, 0x00FA, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C68, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_END_APERTURE_GM]
++ {0x0990, 0x02B2, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C86, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_FFNR_GM]
++ {0x0990, 0x00C8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C88, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_END_FFNR_GM]
++ {0x0990, 0x0658, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3CBC, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_START_GAIN]
++ {0x0990, 0x0040, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3CBE, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_END_GAIN]
++ {0x0990, 0x01FC, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3CCC, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_START_MAX_GM]
++ {0x0990, 0x00C8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3CCE, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_END_MAX_GM]
++ {0x0990, 0x0633, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C90, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_GRB_GM]
++ {0x0990, 0x00C8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C92, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_END_GRB_GM]
++ {0x0990, 0x0658, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C0E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CURVE_ADJ_START_POS]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C10, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CURVE_ADJ_MID_POS]
++ {0x0990, 0x0002, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C12, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CURVE_ADJ_END_POS]
++ {0x0990, 0x02BC, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3CAA, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_CDC_THR_ADJ_START_POS]
++ {0x0990, 0x32B8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3CAC, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_CDC_THR_ADJ_MID_POS]
++ {0x0990, 0x09B1, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3CAE, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_CDC_THR_ADJ_END_POS]
++ {0x0990, 0x00E0, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3CD8, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_PCR_START_BM]
++ {0x0990, 0x00E0, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3CDA, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_PCR_END_BM]
++ {0x0990, 0x05DC, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC94, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GB_START_THRESHOLD_0]
++ {0x0990, 0x0600, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC95, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GB_START_THRESHOLD_1]
++ {0x0990, 0x0500, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC96, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GB_START_THRESHOLD_2]
++ {0x0990, 0x0600, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC97, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GB_START_THRESHOLD_3]
++ {0x0990, 0x0500, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC9C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GB_END_THRESHOLD_0]
++ {0x0990, 0x0900, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC9D, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GB_END_THRESHOLD_1]
++ {0x0990, 0x0500, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC9E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GB_END_THRESHOLD_2]
++ {0x0990, 0x0900, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC9F, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GB_END_THRESHOLD_3]
++ {0x0990, 0x0500, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x30B6, 0x0001, 0x1111}, // AUTOLR_CONTROL
++ {0x33B0, 0x2A16, 0x1111}, // FFNR_ALPHA_BETA
++ {0x098E, 0xBC8A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_FF_MIX_THRESH_Y]
++ {0x0990, 0x2C00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC8B, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_END_FF_MIX_THRESH_Y]
++ {0x0990, 0xCF00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC8C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_FF_MIX_THRESH_YGAIN]
++ {0x0990, 0x8B00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC8D, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_END_FF_MIX_THRESH_YGAIN]
++ {0x0990, 0xD700, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC8E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_FF_MIX_THRESH_GAIN]
++ {0x0990, 0x7F00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC8F, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_END_FF_MIX_THRESH_GAIN]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x33BA, 0x0086, 0x1111}, // APEDGE_CONTROL
++ {0x33BE, 0x0000, 0x1111}, // UA_KNEE_L
++ {0x33C2, 0x7300, 0x1111}, // UA_WEIGHTS
++ {0x098E, 0xBC62, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_APERTURE_KPGAIN]
++ {0x0990, 0x1900, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC63, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_END_APERTURE_KPGAIN]
++ {0x0990, 0x1F00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC64, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_APERTURE_KNGAIN]
++ {0x0990, 0x1900, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC65, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_END_APERTURE_KNGAIN]
++ {0x0990, 0x1F00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC6A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_APERTURE_INTEGER_GAIN]
++ {0x0990, 0x0400, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC6B, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_END_APERTURE_INTEGER_GAIN]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC6C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_START_APERTURE_EXP_GAIN]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC6D, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_END_APERTURE_EXP_GAIN]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x3284, 0x0000, 0x1111}, // APERTURE_KNEE_VALUES
++ {0x3210, 0x49B0, 0x1111}, // COLOR_PIPELINE_CONTROL
++ {0x098E, 0xBCC0, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_RAMP_START]
++ {0x0990, 0x1F00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCC1, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_RAMP_STOP]
++ {0x0990, 0x0300, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCC2, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_SLOPE_START]
++ {0x0990, 0x1E00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCC3, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_SLOPE_STOP]
++ {0x0990, 0x0100, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCC4, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_THSTART]
++ {0x0990, 0x0A00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCC5, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_THSTOP]
++ {0x0990, 0x1F00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3CBA, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_CONFIG]
++ {0x0990, 0x0009, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3CD0, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_SOBEL_FLAT_START]
++ {0x0990, 0x000A, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3CD2, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_SOBEL_FLAT_STOP]
++ {0x0990, 0x00FE, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3CD4, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_SOBEL_SHARP_START]
++ {0x0990, 0x001E, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3CD6, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_SOBEL_SHARP_STOP]
++ {0x0990, 0x00FF, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCC6, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_SHARPENING_START]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCC7, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_SHARPENING_STOP]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCC8, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_FLATNESS_START]
++ {0x0990, 0x2000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCC9, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_FLATNESS_STOP]
++ {0x0990, 0x4000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCCA, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_TRANSITION_START]
++ {0x0990, 0x0400, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBCCB, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_SFFB_TRANSITION_STOP]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC18, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_0]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC19, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_1]
++ {0x0990, 0x1100, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC1A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_2]
++ {0x0990, 0x2300, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC1B, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_3]
++ {0x0990, 0x3F00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC1C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_4]
++ {0x0990, 0x6700, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC1D, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_5]
++ {0x0990, 0x8500, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC1E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_6]
++ {0x0990, 0x9B00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC1F, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_7]
++ {0x0990, 0xAD00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC20, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_8]
++ {0x0990, 0xBB00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC21, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_9]
++ {0x0990, 0xC700, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC22, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_10]
++ {0x0990, 0xD100, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC23, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_11]
++ {0x0990, 0xDA00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC24, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_12]
++ {0x0990, 0xE100, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC25, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_13]
++ {0x0990, 0xE800, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC26, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_14]
++ {0x0990, 0xEE00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC27, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_15]
++ {0x0990, 0xF300, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC28, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_16]
++ {0x0990, 0xF700, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC29, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_17]
++ {0x0990, 0xFB00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC2A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_CONTRAST_CURVE_18]
++ {0x0990, 0xFF00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC2B, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_0]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC2C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_1]
++ {0x0990, 0x1100, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC2D, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_2]
++ {0x0990, 0x2300, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC2E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_3]
++ {0x0990, 0x3F00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC2F, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_4]
++ {0x0990, 0x6700, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC30, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_5]
++ {0x0990, 0x8500, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC31, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_6]
++ {0x0990, 0x9B00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC32, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_7]
++ {0x0990, 0xAD00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC33, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_8]
++ {0x0990, 0xBB00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC34, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_9]
++ {0x0990, 0xC700, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC35, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_10]
++ {0x0990, 0xD100, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC36, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_11]
++ {0x0990, 0xDA00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC37, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_12]
++ {0x0990, 0xE100, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC38, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_13]
++ {0x0990, 0xE800, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC39, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_14]
++ {0x0990, 0xEE00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC3A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_15]
++ {0x0990, 0xF300, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC3B, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_16]
++ {0x0990, 0xF700, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC3C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_17]
++ {0x0990, 0xFB00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC3D, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NEUTRAL_CURVE_18]
++ {0x0990, 0xFF00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC3E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_0]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC3F, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_1]
++ {0x0990, 0x1800, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC40, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_2]
++ {0x0990, 0x2500, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC41, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_3]
++ {0x0990, 0x3A00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC42, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_4]
++ {0x0990, 0x5900, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC43, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_5]
++ {0x0990, 0x7000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC44, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_6]
++ {0x0990, 0x8100, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC45, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_7]
++ {0x0990, 0x9000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC46, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_8]
++ {0x0990, 0x9E00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC47, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_9]
++ {0x0990, 0xAB00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC48, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_10]
++ {0x0990, 0xB600, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC49, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_11]
++ {0x0990, 0xC100, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC4A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_12]
++ {0x0990, 0xCB00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC4B, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_13]
++ {0x0990, 0xD500, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC4C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_14]
++ {0x0990, 0xDE00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC4D, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_15]
++ {0x0990, 0xE700, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC4E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_16]
++ {0x0990, 0xEF00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC4F, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_17]
++ {0x0990, 0xF700, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xBC50, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_NR_CURVE_18]
++ {0x0990, 0xFF00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x8404, 0x1111}, // LOGICAL_ADDRESS_ACCESS [SEQ_CMD]
++ {0x0990, 0x0600, 0x1111}, // MCU_VARIABLE_DATA0
++
++ {REG_TERM, 0x0050, 0x1111}, //delay 80ms
++
++//PART 3
++ {0x098E, 0x3C14, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_FADE_TO_BLACK_START_POS]
++ {0x0990, 0xFFFE, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x3C16, 0x1111}, // LOGICAL_ADDRESS_ACCESS [LL_GAMMA_FADE_TO_BLACK_END_POS]
++ {0x0990, 0xFFFF, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x31E0, 0x0003, 0x1111}, // PIX_DEF_ID
++ {0x098E, 0x281C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_TRACK_MIN_AGAIN]
++ {0x0990, 0x0040, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2820, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_TRACK_MAX_AGAIN]
++ {0x0990, 0x01FC, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2822, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_TRACK_MIN_DGAIN]
++ {0x0990, 0x0080, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2824, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_TRACK_MAX_DGAIN]
++ {0x0990, 0x0100, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x8404, 0x1111}, // LOGICAL_ADDRESS_ACCESS [SEQ_CMD]
++ {0x0990, 0x0600, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x0018, 0x2008, 0x1111}, // STANDBY_CONTROL_AND_STATUS
++ {0x098E, 0x483A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_Y_ADDR_START]
++ {0x0990, 0x0106, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x483C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_X_ADDR_START]
++ {0x0990, 0x0018, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x483E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_Y_ADDR_END]
++ {0x0990, 0x06B7, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4840, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_X_ADDR_END]
++ {0x0990, 0x0A45, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4842, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_ROW_SPEED]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4844, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_SKIP_X_CORE]
++ {0x0990, 0x0103, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4846, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_SKIP_Y_CORE]
++ {0x0990, 0x0103, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4848, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_SKIP_X_PIPE]
++ {0x0990, 0x0103, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x484A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_SKIP_Y_PIPE]
++ {0x0990, 0x0103, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x484C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_POWER_MODE]
++ {0x0990, 0x00F6, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x484E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_BIN_MODE]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xC850, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_ORIENTATION]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xC851, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_PIXEL_ORDER]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4852, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_FINE_CORRECTION]
++ {0x0990, 0x019C, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4854, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_FINE_ITMIN]
++ {0x0990, 0x0732, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4858, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_COARSE_ITMIN]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x485A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_COARSE_ITMAX_MARGIN]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x485C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_MIN_FRAME_LENGTH_LINES]
++ {0x0990, 0x03E8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x485E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_MAX_FRAME_LENGTH_LINES]
++ {0x0990, 0xFFFF, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4860, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_BASE_FRAME_LENGTH_LINES]
++ {0x0990, 0x03E8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4862, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_MIN_LINE_LENGTH_PCLK]
++ {0x0990, 0x0F06, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4864, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_MAX_LINE_LENGTH_PCLK]
++ {0x0990, 0xFFFE, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4866, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_P4_5_6_DIVIDER]
++ {0x0990, 0x7F7C, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4868, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_FRAME_LENGTH_LINES]
++ {0x0990, 0x03E8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x486A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_LINE_LENGTH_PCK]
++ {0x0990, 0x0F06, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x486C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_OUTPUT_SIZE_WIDTH]
++ {0x0990, 0x0518, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x486E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_OUTPUT_SIZE_HEIGHT]
++ {0x0990, 0x02D8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4870, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_RX_FIFO_TRIGGER_MARK]
++ {0x0990, 0x0014, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48B8, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_0_JPEG_CONTROL]
++ {0x0990, 0x0004, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48AE, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_0_OUTPUT_FORMAT]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48AA, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_0_IMAGE_WIDTH]
++ {0x0990, 0x0500, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48AC, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_0_IMAGE_HEIGHT]
++ {0x0990, 0x02D0, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xA80A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_TRACK_NUM_FRAMES_TO_SKIP]
++ {0x0990, 0x0200, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xA807, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_TRACK_JUMP_DIVISOR]
++ {0x0990, 0x0800, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xA409, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_RULE_BASE_TARGET]
++ {0x0990, 0x4000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2010, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_MIN_EXPECTED50HZ_FLICKER_PERIOD]
++ {0x0990, 0x0122, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2012, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_MAX_EXPECTED50HZ_FLICKER_PERIOD]
++ {0x0990, 0x0118, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2014, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_MIN_EXPECTED60HZ_FLICKER_PERIOD]
++ {0x0990, 0x00D2, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2016, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_MAX_EXPECTED60HZ_FLICKER_PERIOD]
++ {0x0990, 0x0118, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2018, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_EXPECTED50HZ_FLICKER_PERIOD_IN_CONTEXT_A]
++ {0x0990, 0x0133, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x201C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_EXPECTED60HZ_FLICKER_PERIOD_IN_CONTEXT_A]
++ {0x0990, 0x00FF, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2818, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_TRACK_TARGET_INT_TIME_ROWS]
++ {0x0990, 0x03E8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x281A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_TRACK_MAX_INT_TIME_ROWS]
++ {0x0990, 0x03E8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2824, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_TRACK_MAX_DGAIN]
++ {0x0990, 0x0180, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xB829, 0x1111}, // LOGICAL_ADDRESS_ACCESS [STAT_LL_BRIGHTNESS_METRIC_DIVISOR]
++ {0x0990, 0x0A00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x8404, 0x1111}, // LOGICAL_ADDRESS_ACCESS [SEQ_CMD]
++ {0x0990, 0x0600, 0x1111}, // MCU_VARIABLE_DATA0
++
++ {REG_TERM, 0x0050, 0x1111}, //delay 80ms
++
++//PART 4
++ {0x098E, 0x483A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_Y_ADDR_START]
++ {0x0990, 0x0106, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x483C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_X_ADDR_START]
++ {0x0990, 0x0018, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x483E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_Y_ADDR_END]
++ {0x0990, 0x06B7, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4840, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_X_ADDR_END]
++ {0x0990, 0x0A45, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4842, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_ROW_SPEED]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4844, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_SKIP_X_CORE]
++ {0x0990, 0x0103, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4846, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_SKIP_Y_CORE]
++ {0x0990, 0x0103, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4848, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_SKIP_X_PIPE]
++ {0x0990, 0x0103, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x484A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_SKIP_Y_PIPE]
++ {0x0990, 0x0103, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x484C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_POWER_MODE]
++ {0x0990, 0x00F6, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x484E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_BIN_MODE]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xC850, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_ORIENTATION]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xC851, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_PIXEL_ORDER]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4852, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_FINE_CORRECTION]
++ {0x0990, 0x019C, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4854, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_FINE_ITMIN]
++ {0x0990, 0x0732, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4858, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_COARSE_ITMIN]
++ {0x0990, 0x0000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x485A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_COARSE_ITMAX_MARGIN]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x485C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_MIN_FRAME_LENGTH_LINES]
++ {0x0990, 0x03E8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x485E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_MAX_FRAME_LENGTH_LINES]
++ {0x0990, 0xFFFF, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4860, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_BASE_FRAME_LENGTH_LINES]
++ {0x0990, 0x03E8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4862, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_MIN_LINE_LENGTH_PCLK]
++ {0x0990, 0x0F06, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4864, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_MAX_LINE_LENGTH_PCLK]
++ {0x0990, 0xFFFE, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4866, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_P4_5_6_DIVIDER]
++ {0x0990, 0x7F7C, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4868, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_FRAME_LENGTH_LINES]
++ {0x0990, 0x03E8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x486A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_LINE_LENGTH_PCK]
++ {0x0990, 0x0F06, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x486C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_OUTPUT_SIZE_WIDTH]
++ {0x0990, 0x0518, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x486E, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_OUTPUT_SIZE_HEIGHT]
++ {0x0990, 0x02D8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x4870, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_CORE_A_RX_FIFO_TRIGGER_MARK]
++ {0x0990, 0x0014, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48B8, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_0_JPEG_CONTROL]
++ {0x0990, 0x0004, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48AE, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_0_OUTPUT_FORMAT]
++ {0x0990, 0x0001, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48AA, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_0_IMAGE_WIDTH]
++ {0x0990, 0x0500, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x48AC, 0x1111}, // LOGICAL_ADDRESS_ACCESS [CAM_OUTPUT_0_IMAGE_HEIGHT]
++ {0x0990, 0x02D0, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xA80A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_TRACK_NUM_FRAMES_TO_SKIP]
++ {0x0990, 0x0200, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xA807, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_TRACK_JUMP_DIVISOR]
++ {0x0990, 0x0800, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xA409, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_RULE_BASE_TARGET]
++ {0x0990, 0x4000, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2010, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_MIN_EXPECTED50HZ_FLICKER_PERIOD]
++ {0x0990, 0x0122, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2012, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_MAX_EXPECTED50HZ_FLICKER_PERIOD]
++ {0x0990, 0x0118, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2014, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_MIN_EXPECTED60HZ_FLICKER_PERIOD]
++ {0x0990, 0x00D2, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2016, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_MAX_EXPECTED60HZ_FLICKER_PERIOD]
++ {0x0990, 0x0118, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2018, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_EXPECTED50HZ_FLICKER_PERIOD_IN_CONTEXT_A]
++ {0x0990, 0x0133, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x201C, 0x1111}, // LOGICAL_ADDRESS_ACCESS [FD_EXPECTED60HZ_FLICKER_PERIOD_IN_CONTEXT_A]
++ {0x0990, 0x00FF, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2818, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_TRACK_TARGET_INT_TIME_ROWS]
++ {0x0990, 0x03E8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x281A, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_TRACK_MAX_INT_TIME_ROWS]
++ {0x0990, 0x03E8, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x2824, 0x1111}, // LOGICAL_ADDRESS_ACCESS [AE_TRACK_MAX_DGAIN]
++ {0x0990, 0x0180, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0xB829, 0x1111}, // LOGICAL_ADDRESS_ACCESS [STAT_LL_BRIGHTNESS_METRIC_DIVISOR]
++ {0x0990, 0x0A00, 0x1111}, // MCU_VARIABLE_DATA0
++ {0x098E, 0x8404, 0x1111}, // LOGICAL_ADDRESS_ACCESS [SEQ_CMD]
++ {0x0990, 0x0600, 0x1111}, // MCU_VARIABLE_DATA0
++
++ {REG_TERM, 0x0050, 0x1111}, //delay 80ms
++ {REG_TERM, VAL_TERM}
++};
++
++
++static struct sensor_reg sensor_preview[] = {
++ { 0x098E,0x843C, 0x1111},//LOGICAL_ADDRESS_ACCESs[SEQ_STATE_CFG_5_MAX_FRAME_CNT]
++ { 0x0990,0x0100, 0x1111}, //MCU_VARIABLE_DATA0
++ { 0x098E,0x8404, 0x1111}, //LOGICAL_ADDRESS_ACCESS[SEQ_CMD]
++ { 0x0990,0x0100, 0x1111}, //MCU_VARIABLE_DATA0
++ { 0x0016, 0x0647, 0x1111}, // CLOCKS_CONTROL
++
++ {REG_TERM, 0x0080, 0x1111}, //delay 120ms
++
++ {0xC83A, 0x0106, 0x1111},
++ {0xC83E, 0x06B7, 0x1111},
++ {0xC858, 0x0000, 0x1111},
++ {0xC85C, 0x03E8, 0x1111},
++ {0xC860, 0x03E8, 0x1111},
++ {0xC866, 0x7F7C, 0x1111},
++ {0xC868, 0x03E8, 0x1111},
++ {0xC86E, 0x02D8, 0x1111},
++ {0xC8AA, 0x0500, 0x1111},
++ {0xC8AC, 0x02D0, 0x1111},
++ {0xA80A, 0x0002, 0x1111},
++ {0xA807, 0x0008, 0x1111},
++ {0xA409, 0x0040, 0x1111},
++ {0xA010, 0x0122, 0x1111},
++ {0xA012, 0x0118, 0x1111},
++ {0xA014, 0x00D2, 0x1111},
++ {0xA016, 0x0118, 0x1111},
++ {0xA018, 0x0133, 0x1111},
++ {0xA01C, 0x00FF, 0x1111},
++ {0xA81A, 0x03E8, 0x1111},
++ {0xA824, 0x0180, 0x1111},
++ {0xAC09, 0x0035, 0x1111},
++ {0xB829, 0x000A, 0x1111},
++ {0x8404, 0x0006, 0x1111},
++
++ {REG_TERM, 0x0080, 0x1111}, //delay 120ms
++
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_capture[] = {
++ { 0x3CA2, 0x0007, 0x1111}, // TXC_PARAMETERS
++ { 0x098E, 0x5820, 0x1111}, // LOGICAL_ADDRESS_ACCESS [JPEG_JPSS_CTRL_VAR]
++ { 0x0990, 0x4510, 0x1111}, // MCU_VARIABLE_DATA0
++ { 0x098E, 0x8404, 0x1111}, // LOGICAL_ADDRESS_ACCESS [SEQ_CMD]
++ { 0x0990, 0x0600, 0x1111}, // MCU_VARIABLE_DATA0
++
++ {REG_TERM, 0x0080, 0x1111}, //delay 120ms
++
++ { 0x098E,0x843C, 0x1111}, //LOGICAL_ADDRESS_ACCESS[SEQ_STATE_CFG_5_MAX_FRAME_CNT]
++ { 0x0990,0xFF00, 0x1111}, //MCU_VARIABLE_DATA0
++ { 0x098E,0x8404, 0x1111}, //LOGICAL_ADDRESS_ACCESS[SEQ_CMD]
++ { 0x0990,0x0200, 0x1111}, //MCU_VARIABLE_DATA0
++
++ {REG_TERM, 0x0080, 0x1111}, //delay 120ms
++
++ {REG_TERM, VAL_TERM}
++};
++
++ struct sensor_reg* sensor_reg_common[3] =
++{
++ sensor_common,
++ sensor_preview,
++ sensor_capture
++};
++
++static struct sensor_reg sensor_brightness_0[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_1[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_2[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_3[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_4[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_brightness[5] =
++{
++ sensor_brightness_0,
++ sensor_brightness_1,
++ sensor_brightness_2,
++ sensor_brightness_3,
++ sensor_brightness_4
++};
++
++
++static struct sensor_reg sensor_awb_auto[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_daylight[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_incandescent[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_fluorescent[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_cloudy[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_sunset[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_awb[6] =
++{
++ sensor_awb_auto,
++ sensor_awb_daylight,
++ sensor_awb_incandescent,
++ sensor_awb_fluorescent,
++ sensor_awb_cloudy,
++ sensor_awb_sunset
++
++};
++
++
++static struct sensor_reg sensor_iso_auto[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_100[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_200[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_400[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_iso[4] =
++{
++ sensor_iso_auto,
++ sensor_iso_100,
++ sensor_iso_200,
++ sensor_iso_400
++};
++
++
++static struct sensor_reg sensor_effect_normal[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_gray[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_negative[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sepia[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sharpness[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sketch[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_effect[6] =
++{
++ sensor_effect_normal,
++ sensor_effect_gray,
++ sensor_effect_negative,
++ sensor_effect_sepia,
++ sensor_effect_sharpness,
++ sensor_effect_sketch,
++};
++
++
++static struct sensor_reg sensor_reg_flipnone[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_hflip[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_vflip[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_hvflip[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_flip[4] =
++{
++ sensor_reg_flipnone,
++ sensor_reg_hflip,
++ sensor_reg_vflip,
++ sensor_reg_hvflip,
++};
++
++
++static struct sensor_reg sensor_secne_auto[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_night[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_landscape[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_portrait[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_sport[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_scene[5] =
++{
++ sensor_secne_auto,
++ sensor_secne_night,
++ sensor_secne_landscape,
++ sensor_secne_portrait,
++ sensor_secne_sport
++};
++
++static struct sensor_reg sensor_me_mtrix[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_me_center_weighted[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_me_spot[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_metering_exposure[3] =
++{
++ sensor_me_mtrix,
++ sensor_me_center_weighted,
++ sensor_me_spot,
++};
++
++static struct sensor_reg sensor_af_single[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_af_manual[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_af[2] =
++{
++ sensor_af_single,
++ sensor_af_manual,
++};
++#endif
++
+diff --git a/drivers/media/video/tcccam/mt9p111_5mp.h b/drivers/media/video/tcccam/mt9p111_5mp.h
+new file mode 100644
+index 0000000..f092e4c
+--- /dev/null
++++ b/drivers/media/video/tcccam/mt9p111_5mp.h
+@@ -0,0 +1,64 @@
++/*
++ * drivers/media/video/tcccam/mt9p111_5mp.h
++ *
++ * Register definitions for the mv9317 CameraChip.
++ *
++ * Author: zzau (zzau@telechips.com)
++ *
++ * Copyright (C) 2008 Telechips, 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.
++ */
++
++#ifndef MT9P111_H
++#define MT9P111_H
++
++/* The MV9317 I2C sensor chip has a fixed slave address of 0x5D. */
++#define SENSOR_I2C_ADDR 0x78
++
++#define REG_TERM 0x0000 /* terminating list entry for reg */
++#define VAL_TERM 0x0000 /* terminating list entry for val */
++#define VAL_END 0x1111 /* ending entry for val-list */
++
++// ZOOM Setting!!
++#define PRV_W 1280
++#define PRV_H 720
++#define PRV_ZOFFX 8
++#define PRV_ZOFFY 6
++
++#define CAP_W 2560
++#define CAP_H 1920
++#define CAP_ZOFFX 16
++#define CAP_ZOFFY 12
++
++#define CAM_2XMAX_ZOOM_STEP 31
++#define CAM_CAPCHG_WIDTH 1024
++
++
++struct sensor_reg {
++ unsigned short reg;
++ unsigned short val[20];
++};
++
++struct capture_size {
++ unsigned long width;
++ unsigned long height;
++};
++
++extern struct capture_size sensor_sizes[];
++
++extern struct sensor_reg* sensor_reg_common[];
++extern struct sensor_reg* sensor_reg_brightness[];
++extern struct sensor_reg* sensor_reg_awb[];
++extern struct sensor_reg* sensor_reg_iso[];
++extern struct sensor_reg* sensor_reg_effect[];
++extern struct sensor_reg* sensor_reg_flip[];
++extern struct sensor_reg* sensor_reg_scene[];
++extern struct sensor_reg* sensor_reg_metering_exposure[];
++extern struct sensor_reg* sensor_reg_af[];
++
++#endif /* MT9P111_H */
++
++
+diff --git a/drivers/media/video/tcccam/mv9317_3mp.c b/drivers/media/video/tcccam/mv9317_3mp.c
+new file mode 100644
+index 0000000..dbc92a6
+--- /dev/null
++++ b/drivers/media/video/tcccam/mv9317_3mp.c
+@@ -0,0 +1,303 @@
++/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
++
++ CAMERA API M O D U L E
++
++ EDIT HISTORY FOR MODULE
++
++when who what, where, why
++-------- --- -------------------------------------------------------
++10/xx/08 Telechips Created file.
++*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
++
++/*===========================================================================
++
++ INCLUDE FILES FOR MODULE
++
++===========================================================================*/
++#include "sensor_if.h"
++
++#ifdef CONFIG_VIDEO_CAMERA_SENSOR_MV9317
++
++/* Array of image sizes supported by MV9317. These must be ordered from
++ * smallest image size to largest.
++ */
++struct capture_size sensor_sizes[] = {
++ { 2048, 1536 }, /* QXGA */
++ { 1600, 1200 }, /* UXGA */
++ { 1280, 960 }, /* SXGA */
++ { 1024, 768 }, /* XGA */
++ { 800, 600 }, /* SVGA */
++ { 640, 480 }, /* VGA */
++ { 320, 240 }, /* QVGA */
++ { 176, 144 }, /* QCIF */
++};
++
++
++/* register initialization tables for sensor */
++/* common sensor register initialization for all image sizes, pixel formats,
++ * and frame rates
++ */
++static struct sensor_reg sensor_common[] = {
++ {0x07, 0x07}, //XGA
++ {REG_TERM, VAL_TERM}
++};
++
++
++static struct sensor_reg sensor_preview[] = {
++ {0x07, 0x07}, //XGA
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_capture[] = {
++ {0x07, 0x0c}, //QXGA
++ {REG_TERM, VAL_TERM}
++};
++
++ struct sensor_reg* sensor_reg_common[3] =
++{
++ sensor_common,
++ sensor_preview,
++ sensor_capture
++};
++
++static struct sensor_reg sensor_brightness_0[] = {
++ {0x10, 0x83}, //M2
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_1[] = {
++ {0x10, 0x81}, //M1
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_2[] = {
++ {0x10, 0x00}, //DEFAULT
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_3[] = {
++ {0x10, 0x01}, //P1
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_4[] = {
++ {0x10, 0x03}, //P2
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_brightness[5] =
++{
++ sensor_brightness_0,
++ sensor_brightness_1,
++ sensor_brightness_2,
++ sensor_brightness_3,
++ sensor_brightness_4
++};
++
++
++static struct sensor_reg sensor_awb_auto[] = {
++ {0x14, 0x80},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_daylight[] = {
++ {0x14, 0x01}, //Daylight
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_incandescent[] = {
++ {0x14, 0x04}, //A(Incandescent)
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_fluorescent[] = {
++ {0x14, 0x03}, //Cool White Fluorescent
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_cloudy[] = {
++ {0x14, 0x06}, //Cloudy
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_sunset[] = {
++ {0x14, 0x05}, //Horizon(sunset)
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_awb[6] =
++{
++ sensor_awb_auto,
++ sensor_awb_daylight,
++ sensor_awb_incandescent,
++ sensor_awb_fluorescent,
++ sensor_awb_cloudy,
++ sensor_awb_sunset
++
++};
++
++
++static struct sensor_reg sensor_iso_auto[] = {
++ {0x0d, 0x00}, //auto
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_100[] = {
++ {0x0d, 0x01}, //100
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_200[] = {
++ {0x0d, 0x02}, //200
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_400[] = {
++ {0x0d, 0x03}, //400
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_iso[4] =
++{
++ sensor_iso_auto,
++ sensor_iso_100,
++ sensor_iso_200,
++ sensor_iso_400
++};
++
++
++static struct sensor_reg sensor_effect_normal[] = {
++ {0x1f, 0x00}, //NORMAL
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_gray[] = {
++ {0x1f, 0x40}, //BW
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_negative[] = {
++ {0x1f, 0x20}, //NEG_POSITIVE
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sepia[] = {
++ {0x1f, 0x10}, //SEPHIA
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sharpness[] = {
++ {0x1f, 0x02}, //SHARPNESS
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sketch[] = {
++ {0x1f, 0x04}, //SKETCH
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_effect[6] =
++{
++ sensor_effect_normal,
++ sensor_effect_gray,
++ sensor_effect_negative,
++ sensor_effect_sepia,
++ sensor_effect_sharpness,
++ sensor_effect_sketch,
++};
++
++
++static struct sensor_reg sensor_reg_flipnone[] = {
++ {0x09, 0x00}, //NORMAL
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_hflip[] = {
++ {0x09, 0x01}, //MIRROR
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_vflip[] = {
++ {0x09, 0x02}, //FLIP
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_hvflip[] = {
++ {0x09, 0x03}, //MIRROR_FLIP
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_flip[4] =
++{
++ sensor_reg_flipnone,
++ sensor_reg_hflip,
++ sensor_reg_vflip,
++ sensor_reg_hvflip,
++};
++
++
++static struct sensor_reg sensor_secne_auto[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_night[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_landscape[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_portrait[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_sport[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_scene[5] =
++{
++ sensor_secne_auto,
++ sensor_secne_night,
++ sensor_secne_landscape,
++ sensor_secne_portrait,
++ sensor_secne_sport
++};
++
++static struct sensor_reg sensor_me_mtrix[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_me_center_weighted[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_me_spot[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_metering_exposure[3] =
++{
++ sensor_me_mtrix,
++ sensor_me_center_weighted,
++ sensor_me_spot,
++};
++
++static struct sensor_reg sensor_af_single[] = {
++ {0x19, 0x00},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_af_manual[] = {
++ {0x1A, 0x20},
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_af[2] =
++{
++ sensor_af_single,
++ sensor_af_manual,
++};
++#endif
++
+diff --git a/drivers/media/video/tcccam/mv9317_3mp.h b/drivers/media/video/tcccam/mv9317_3mp.h
+new file mode 100644
+index 0000000..b7df0ea
+--- /dev/null
++++ b/drivers/media/video/tcccam/mv9317_3mp.h
+@@ -0,0 +1,64 @@
++/*
++ * drivers/media/video/tcccam/mv9317_3mp.h
++ *
++ * Register definitions for the mv9317 CameraChip.
++ *
++ * Author: zzau (zzau@telechips.com)
++ *
++ * Copyright (C) 2008 Telechips, 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.
++ */
++
++#ifndef MV9317_H
++#define MV9317_H
++
++/* The MV9317 I2C sensor chip has a fixed slave address of 0x5D. */
++#define SENSOR_I2C_ADDR 0x50
++
++#define REG_TERM 0xFF /* terminating list entry for reg */
++#define VAL_TERM 0xFF /* terminating list entry for val */
++
++
++// ZOOM Setting!!
++#define PRV_W 1024
++#define PRV_H 768
++#define PRV_ZOFFX 8
++#define PRV_ZOFFY 6
++
++#define CAP_W 2048
++#define CAP_H 1536
++#define CAP_ZOFFX 16
++#define CAP_ZOFFY 12
++
++#define CAM_2XMAX_ZOOM_STEP 31
++#define CAM_CAPCHG_WIDTH 1024
++
++
++struct sensor_reg {
++ unsigned char reg;
++ unsigned char val[1];
++};
++
++struct capture_size {
++ unsigned long width;
++ unsigned long height;
++};
++
++extern struct capture_size sensor_sizes[];
++
++extern struct sensor_reg* sensor_reg_common[];
++extern struct sensor_reg* sensor_reg_brightness[];
++extern struct sensor_reg* sensor_reg_awb[];
++extern struct sensor_reg* sensor_reg_iso[];
++extern struct sensor_reg* sensor_reg_effect[];
++extern struct sensor_reg* sensor_reg_flip[];
++extern struct sensor_reg* sensor_reg_scene[];
++extern struct sensor_reg* sensor_reg_metering_exposure[];
++extern struct sensor_reg* sensor_reg_af[];
++
++#endif /* MV9317_H */
++
++
+diff --git a/drivers/media/video/tcccam/s5k4bafb_2mp.c b/drivers/media/video/tcccam/s5k4bafb_2mp.c
+new file mode 100644
+index 0000000..d17f408
+--- /dev/null
++++ b/drivers/media/video/tcccam/s5k4bafb_2mp.c
+@@ -0,0 +1,2793 @@
++/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
++
++ CAMERA API M O D U L E
++
++ EDIT HISTORY FOR MODULE
++
++when who what, where, why
++-------- --- -------------------------------------------------------
++10/xx/08 Telechips Created file.
++*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
++
++/*===========================================================================
++
++ INCLUDE FILES FOR MODULE
++
++===========================================================================*/
++#include "sensor_if.h"
++
++#ifdef CONFIG_VIDEO_CAMERA_SENSOR_S5K4BAFB
++
++/* Array of image sizes supported by S5K4BAFB. These must be ordered from
++ * smallest image size to largest.
++ */
++struct capture_size sensor_sizes[] = {
++ { 1600, 1200 }, /* UXGA */
++ { 1280, 960 }, /* SXGA */
++ { 1024, 768 }, /* XGA */
++ { 800, 600 }, /* SVGA */
++ { 640, 480 }, /* VGA */
++ { 320, 240 }, /* QVGA */
++ { 176, 144 }, /* QCIF */
++};
++
++
++/* register initialization tables for sensor */
++/* common sensor register initialization for all image sizes, pixel formats,
++ * and frame rates
++ */
++static struct sensor_reg sensor_common[] = {
++#ifdef TCC_VCORE_30FPS_CAMERASENSOR // // LG, LX600/VX8560 Camera
++ //==========================================================
++ // Name : for s5K4BAFB EVT1(UXGA 1-Chip)
++ // Version : v2.0 UXGA
++ // S/W version : s02
++ // PLL mode : MCLK 24MHz PCLK 32MHz)
++ // AGC gain : s66
++ // FPS : UXGA 7.5fps
++ // Date : 2008.01.11
++ //==========================================================
++
++ //History
++ //Gamma_Lee Àû¿ë
++ //==========================================================
++ // PLL SET
++ //==========================================================
++ {0xfc,0x02},
++ {0x50,0x59}, // Mclk:25M, Pclk:36M
++ {0x51,0x0a}, // s=1, p=25
++ {0x52,0xD0}, // 31 fps,
++
++ //==========================================================
++ // CAMERA INITIAL
++ //==========================================================
++ {0xfc,0x07},
++ {0x66,0x01}, // Watch dog timer [0:off 1:on]
++ {0xfc,0x00},
++ {0x00,0xAA}, // For EDS Check
++ {0x21,0x03},
++ {0xfc,0x01},
++ {0x04,0x01}, // ARM Clock Divider
++ {0xfc,0x07},
++ {0x05,0x00}, // AE initial_HH
++ {0x06,0x00}, // AE initial_HL
++ {0x07,0x8b}, // AE initial_LH
++ {0x08,0xf5}, // AE initial_LL
++ {0x09,0x00},
++ {0x0a,0xb4}, // Rgain initial point
++ {0x0b,0x00},
++ {0x0c,0xea}, // Bgain initial point
++ {0x0d,0x00},
++ {0x0e,0x40}, // Ggain initial point
++ {0xfc,0x00},
++ {0x70,0x02}, // Initial uploading
++
++ //==========================================================
++ // Analog setting
++ //==========================================================
++ {0xfc,0x02},
++ {0x55,0x1E}, // LineADLC on(s551a) off(s550a)
++ {0x56,0x10}, // BPR 16code
++ {0x30,0x82}, // Analog offset (capture =?h)
++ {0x37,0x11}, //17 // Global Gain (default:31)
++ {0x57,0x80}, // LineADLC Roffset
++ {0x58,0x80}, // LineADLC Goffset
++ {0x59,0x80}, // LineADLC offset don't care
++ {0x44,0x64}, // clamp en[6]=1 on
++ {0x4a,0x40}, // clamp level 0011h [7]~[4]
++ {0x2d,0x48}, // double shutter (default:00)
++ {0x4D,0x08}, // Voltage doubler (default:04)
++ {0x4e,0x1a}, // IO current 8mA set
++ {0x4f,0xba}, // IO current 48mA set
++ {0x66,0x41}, // 1st comp current 2uA
++ {0x43,0xEF}, // ec_comp
++ {0x62,0x60}, // LD control CFPN_EN off
++ {0xfc,0x20},
++ {0x09,0x03}, // onejump delay for AE haunting
++
++ //==========================================================//
++ // COMMAND SET //
++ //==========================================================//
++ {0xfc,0x00},
++ {0x20,0x02}, // Change AWB Mode
++ {0x29,0x03}, // Y level
++ {0x2a,0xd0}, //ec}, //
++ {0x2b,0x04}, // C level
++ {0x2c,0x00}, //
++ {0x62,0x02}, // Hue Control Enable
++ {0x6c,0xc0}, // AE target, revised for Flicker
++ {0x6d,0x00},
++// {0x73,0x11}, // Frmae AE Enable , frame rate control, VFR
++ {0x73,0x10}, // Frmae AE Enable , frame rate control, CFR
++ {0x78,0x66}, // AGC Max
++ {0xfc,0x20},
++ {0x16,0x5a}, // AGC frame AE start _for Prevating AE Hunting
++ {0x57,0x18}, // Stable_Frame_AE
++ {0xfc,0x00},
++ {0x83,0x06}, // low condition shutter off Double shutter off
++
++ {0xfc,0x0b},
++ {0x5c,0x65}, // AGC value to start shutter on/off suppress
++ {0x5d,0x65}, // AGC value to start double shutter on/off suppress
++ {0xfc,0x20},
++ {0x25,0x00}, // CINTR Min
++ {0x2a,0x01}, // forbidden
++ {0x2b,0x02}, // For Forbidden Area
++ {0x2c,0x0a},
++ {0x2d,0x00}, // For Forbidden Area
++ {0x2e,0x00},
++ {0x2f,0x05}, // forbidden
++ {0x14,0x80}, // Brightness offset
++ {0x01,0x00}, // Stepless_Off
++ {0x02,0x02}, // Flicker Dgain Mode
++
++ {0xfc,0x07},
++ {0x37,0x08}, // Flicker setting
++ {0xfc,0x00},
++ {0x72,0xac}, // Flicker for 36MHz Revised for Flicker
++ {0x74,0x08}, // flicker 60Hz
++
++ {0xfc,0x01},
++ {0x0c,0x02}, // Full YC Enable
++
++ //==========================================================
++ // Table Set for Sub-Sampling
++ //==========================================================
++ {0xfc,0x03},
++ {0x00,0x06},
++ {0x01,0xe2},
++ {0x05,0x46},
++ {0x07,0xb6},
++ {0x0e,0x04},
++ {0x12,0x03},
++ {0x2c,0x00},
++
++ {0xfc,0x03},
++ {0x3d,0x00}, // POST_HSTART_H
++ {0x3e,0x02}, // POST_HSTART_L
++ {0x3f,0x06}, // POST_HWIDTH_H
++ {0x40,0x40}, // POST_HWIDTH_L
++ {0x41,0x00}, // POST_VSTART_H
++ {0x42,0x02}, // POST_VSTART_L
++ {0x43,0x04}, // POST_VHEIGHT_H
++ {0x44,0xb0}, // POST_VHEIGHT_L
++ {0x45,0x06}, // IMG_HSIZEH
++ {0x46,0x40}, // IMG_HSIZEL
++ {0x47,0x04}, // IMG_VSIZEH
++ {0x48,0xb0}, // IMG_VSIZEL
++ {0x49,0x00}, // PSF
++ {0x4a,0x40}, // MSFXH
++ {0x4b,0x00}, // MSFXL
++ {0x4c,0x40}, // MSFYH
++ {0x4d,0x00}, // MSFYL
++ {0x4e,0x05}, // DW_HSIZEH
++ {0x4f,0x00}, // DW_HSIZEL
++ {0x50,0x03}, // DW_VSIZEH
++ {0x51,0xc0}, // DW_VSIZEL
++ {0x52,0x00}, // STARTXH
++ {0x53,0x00}, // STARTXL
++ {0x54,0x00}, // STARTYH
++ {0x55,0x00}, // STARTYL
++ {0x56,0x05}, // CLIP_HSIZEH
++ {0x57,0x00}, // CLIP_HSIZEL
++ {0x58,0x03}, // CLIP_VSIZEH
++ {0x59,0xc0}, // CLIP_VSIZEL
++ {0x5a,0x00}, // SEL_MAIN
++ {0x5b,0x00}, // HTERMH
++ {0x5c,0x08}, // HTERMM
++ {0x5d,0x9c}, // HTERML
++
++ {0xfc,0x04},
++ {0xc0,0x05}, //04}, //05
++ {0xc1,0x40},
++ {0xc2,0x02},
++ {0xc3,0x87},
++ {0xc4,0x03},
++ {0xc5,0x26},
++ {0xc6,0x02},
++ {0xc7,0x5c},
++ {0xc8,0x01},
++ {0xc9,0x03},
++ {0xca,0x01},
++ {0xcb,0x03},
++ {0xcc,0x08},
++ {0xce,0x01},
++ {0xd2,0x01},
++
++ {0xfc,0x03}, //snap shot: YCbCr order
++ {0x2e,0x01},
++ {0x5e,0x00},
++ {0x8e,0x00},
++ {0xbe,0x00},
++ {0xee,0x00},
++
++ {0xfc,0x04}, //preview : YCbCr order
++ {0x2e,0x01},
++ {0x5e,0x01},
++ {0x8e,0x01},
++ {0xbe,0x01},
++ {0xee,0x00},
++
++ //==========================================================
++ // COLOR MATRIX
++ //==========================================================
++ {0xfc,0x01},
++ {0x51,0x07},
++ {0x52,0x40},
++ {0x53,0xfc},
++ {0x54,0x80},
++ {0x55,0x00},
++ {0x56,0x3f},
++ {0x57,0xfe},
++ {0x58,0x7f},
++ {0x59,0x06},
++ {0x5A,0x6a},
++ {0x5B,0xff},
++ {0x5C,0x18},
++ {0x5D,0xff},
++ {0x5E,0xd7},
++ {0x5F,0xfd},
++ {0x60,0x1c},
++ {0x61,0x07},
++ {0x62,0x0d},
++
++ //==========================================================
++ // EDGE ENHANCEMENT
++ //==========================================================
++ {0xfc,0x0b}, //KF310
++ {0x42,0x50}, //50 //50}, // Edge AGC MIN
++ {0x43,0x60}, //60 //60}, // Edge AGC MAX
++ {0x45,0x0a}, //04 //0a}, //24 // positive gain AGC MIN
++ {0x49,0x06}, //0a //06}, // positive gain AGC MAX
++ {0x4d,0x09}, //10 //0a}, //24 // negative gain AGC MIN
++ {0x51,0x06}, //0a //06}, // negative gain AGC MAX
++ {0xfc,0x05}, //05
++ {0x33,0x08}, //08 // APTCLP
++ {0x34,0x38}, //40 //38}, //24 // APTCLP
++ {0x35,0x0a}, //08 //08}, //04 // APTSC
++ {0x36,0x1a}, //1f //1f}, //0b // ENHANCE
++ {0x3f,0x00}, //00 // NON-LIN
++ {0x42,0x10}, //10 // EGFALL
++ {0x43,0x00}, //00 // HLFALL
++ {0x45,0xa0}, //a0 // EGREF
++ {0x46,0x7a}, //7a // HLREF
++ {0x47,0x40}, //40 // LLREF
++ {0x48,0x0c}, //0c
++ {0x49,0x31}, //31 // CSSEL EGSEL CS_DLY
++ {0x40,0x41}, //41 // Y delay
++
++ //==========================================================
++ // NEW EDGE ENHANCEMENT
++ //==========================================================
++ {0xfc,0x1d},
++ {0x86,0x02},
++ {0x87,0xc0},
++ {0x88,0x03},
++ {0x89,0xc0},
++ {0x8a,0x02},
++ {0x8b,0x00},
++ {0x8c,0x00},
++ {0x8d,0x00},
++ {0x8e,0x00},
++ {0x8f,0xd0},
++ {0x90,0x00},
++ {0x91,0x00},
++ {0x92,0x02},
++ {0x93,0x00},
++ {0x94,0x00},
++ {0x95,0x00},
++ {0x96,0x00},
++ {0x97,0xd0},
++ {0x98,0x00},
++ {0x99,0x00},
++ {0x9a,0x02},
++ {0x9b,0x60},
++ {0x9c,0x00},
++ {0x9d,0x00},
++ {0x9e,0x02},
++ {0x9f,0x60},
++ {0xa0,0x00},
++ {0xa1,0x00},
++ {0xa2,0x09},
++ {0x85,0x01}, // EE_Wide_Luma ON/OFF 1:ON, 0:OFF
++ {0xfc,0x00},
++ {0x89,0x03}, // Edge negative/positive suppress ON
++
++ //==========================================================
++ // GAMMA
++ //==========================================================
++ {0xfc,0x1d},
++ {0x00,0x05},
++ {0x01,0x0a},
++ {0x02,0x33},
++ {0x03,0xbd},
++ {0x04,0x00},
++ {0x05,0x33},
++ {0x06,0x8f},
++ {0x07,0xdc},
++ {0x08,0x15},
++ {0x09,0x56},
++ {0x0a,0x38},
++ {0x0b,0x57},
++ {0x0c,0x74},
++ {0x0d,0x8f},
++ {0x0e,0xaa},
++ {0x0f,0xa9},
++ {0x10,0xc2},
++ {0x11,0xdb},
++ {0x12,0xf3},
++ {0x13,0xaa},
++ {0x14,0x0a},
++ {0x15,0x22},
++ {0x16,0x3d},
++ {0x17,0x57},
++ {0x18,0xff},
++ {0x19,0x6b},
++ {0x1a,0x7a},
++ {0x1b,0x8f},
++ {0x1c,0x9e},
++ {0x1d,0xff},
++ {0x1e,0xa8},
++ {0x1f,0xb8},
++ {0x20,0xc3},
++ {0x21,0xd3},
++ {0x22,0xff},
++ {0x23,0xe0},
++ {0x24,0xeb},
++ {0x25,0xf2},
++ {0x26,0xf8},
++ {0x27,0xff},
++ {0x28,0xfc},
++ {0x29,0xff},
++ {0x2a,0xf0},
++ {0x2b,0x00},
++ {0x2c,0x0a},
++ {0x2d,0x33},
++ {0x2e,0xbd},
++ {0x2f,0x00},
++ {0x30,0x33},
++ {0x31,0x8f},
++ {0x32,0xdc},
++ {0x33,0x15},
++ {0x34,0x56},
++ {0x35,0x38},
++ {0x36,0x57},
++ {0x37,0x74},
++ {0x38,0x8f},
++ {0x39,0xaa},
++ {0x3a,0xa9},
++ {0x3b,0xc2},
++ {0x3c,0xdb},
++ {0x3d,0xf3},
++ {0x3e,0xaa},
++ {0x3f,0x0a},
++ {0x40,0x22},
++ {0x41,0x3d},
++ {0x42,0x57},
++ {0x43,0xff},
++ {0x44,0x6b},
++ {0x45,0x7a},
++ {0x46,0x8f},
++ {0x47,0x9e},
++ {0x48,0xff},
++ {0x49,0xa8},
++ {0x4a,0xb8},
++ {0x4b,0xc3},
++ {0x4c,0xd3},
++ {0x4d,0xff},
++ {0x4e,0xe0},
++ {0x4f,0xeb},
++ {0x50,0xf2},
++ {0x51,0xf8},
++ {0x52,0xff},
++ {0x53,0xfc},
++ {0x54,0xff},
++ {0x55,0xf0},
++ {0x56,0x00},
++ {0x57,0x0a},
++ {0x58,0x33},
++ {0x59,0xbd},
++ {0x5a,0x00},
++ {0x5b,0x33},
++ {0x5c,0x8f},
++ {0x5d,0xdc},
++ {0x5e,0x15},
++ {0x5f,0x56},
++ {0x60,0x38},
++ {0x61,0x57},
++ {0x62,0x74},
++ {0x63,0x8f},
++ {0x64,0xaa},
++ {0x65,0xa9},
++ {0x66,0xc2},
++ {0x67,0xdb},
++ {0x68,0xf3},
++ {0x69,0xaa},
++ {0x6a,0x0a},
++ {0x6b,0x22},
++ {0x6c,0x3d},
++ {0x6d,0x57},
++ {0x6e,0xff},
++ {0x6f,0x6b},
++ {0x70,0x7a},
++ {0x71,0x8f},
++ {0x72,0x9e},
++ {0x73,0xff},
++ {0x74,0xa8},
++ {0x75,0xb8},
++ {0x76,0xc3},
++ {0x77,0xd3},
++ {0x78,0xff},
++ {0x79,0xe0},
++ {0x7a,0xeb},
++ {0x7b,0xf2},
++ {0x7c,0xf8},
++ {0x7d,0xff},
++ {0x7e,0xfc},
++ {0x7f,0xff},
++ {0x80,0xf0},
++
++ //==========================================================
++ // HUE CONTROL
++ //==========================================================
++ {0xfc,0x00},
++ {0x48,0x40}, // 2000K
++ {0x49,0x40},
++ {0x4a,0xF0},
++ {0x4b,0x00},
++ {0x4c,0x40},
++ {0x4d,0x40},
++ {0x4e,0x00},
++ {0x4f,0x00},
++
++ {0x50,0x48}, // 3000K
++ {0x51,0x3e},
++ {0x52,0xf6},
++ {0x53,0x00},
++ {0x54,0x40},
++ {0x55,0x40},
++ {0x56,0x00},
++ {0x57,0xf0},
++
++ {0x58,0x35}, //36}, //3a}, //3d}, //40}, // 5000K
++ {0x59,0x4a}, //40},//3a},//37}, //35},
++ {0x5a,0xfc},
++ {0x5b,0x00},
++ {0x5c,0x40},
++ {0x5d,0x3a},
++ {0x5e,0x00},
++ {0x5f,0x08},//00}, //f8},//f4}, //f0},
++
++ //========================================================== //
++ // SUPPRESS FUNCTION //
++ //========================================================== //
++ {0xfc,0x00},
++ {0x7e,0xf4},
++
++ //========================================================== //
++ // BPR //
++ //========================================================== //
++ {0xfc,0x01},
++ {0x3d,0x10},
++ {0xfc,0x0b},
++ {0x0b,0x00}, // ISP BPR On Start
++ {0x0c,0x40}, // Th13 AGC Min
++ {0x0d,0x5a}, // Th13 AGC Max
++ {0x0e,0x00}, // Th1 Max H for AGCMIN
++ {0x0f,0x15}, // 0822 semi Th1 Max L for AGCMIN
++ {0x10,0x00}, // Th1 Min H for AGCMAX
++ {0x11,0x20}, // 0822 semi Th1 Min L for AGCMAX
++ {0x12,0x00}, // Th3 Max H for AGCMIN
++ {0x13,0x7f}, // Th3 Max L for AGCMIN
++ {0x14,0x03}, // Th3 Min H for AGCMAX
++ {0x15,0xff}, // Th3 Min L for AGCMAX
++ {0x16,0x48}, // Th57 AGC Min
++ {0x17,0x60}, // Th57 AGC Max
++ {0x18,0x00}, // Th5 Max H for AGCMIN
++ {0x19,0x00}, // Th5 Max L for AGCMIN
++ {0x1a,0x00}, // Th5 Min H for AGCMAX
++ {0x1b,0x20}, // Th5 Min L for AGCMAX
++ {0x1c,0x00}, // Th7 Max H for AGCMIN
++ {0x1d,0x00}, // Th7 Max L for AGCMIN
++ {0x1e,0x00}, // Th7 Min H for AGCMAX
++ {0x1f,0x20}, // Th7 Min L for AGCMAX
++
++ //========================================================== //
++ // GR/GB CORRECTION //
++ //========================================================== //
++ {0xfc,0x01},
++ {0x45,0x0c},
++ {0xfc,0x0b},
++ {0x21,0x00}, // Start AGC
++ {0x22,0x05}, // AGCMIN
++ {0x23,0x33}, // AGCMAX
++ {0x24,0x0a}, // G Th AGCMIN
++ {0x25,0x25}, // G Th AGCMAX
++ {0x26,0x0a}, // RB Th AGCMIN
++ {0x27,0x25}, // RB Th AGCMAX
++
++ //==========================================================//
++ // NR //
++ //==========================================================//
++ {0xfc,0x01},
++ {0x4C,0x01}, // NR Enable
++ {0x49,0x15}, // Sig_Th Mult
++ {0x4B,0x0A}, // Pre_Th Mult
++
++ {0xfc,0x0b},
++ {0x28,0x00}, // NR start AGC
++ {0x29,0x00}, // SIG Th AGCMIN H
++ {0x2a,0x14}, // SIG Th AGCMIN L
++ {0x2b,0x00}, // SIG Th AGCMAX H
++ {0x2c,0x14}, // SIG Th AGCMAX L
++ {0x2d,0x00}, // PRE Th AGCMIN H
++ {0x2e,0xc0}, // PRE Th AGCMIN L
++ {0x2f,0x01}, // PRE Th AGCMAX H
++ {0x30,0x00}, // PRE Th AGCMAX L
++ {0x31,0x00}, // POST Th AGCMIN H
++ {0x32,0xd0}, // POST Th AGCMIN L
++ {0x33,0x01}, // POST Th AGCMAX H
++ {0x34,0x10}, // POST Th AGCMAX L
++
++ //========================================================== //
++ // 1D-Y/C-SIGMA-LPF //
++ //========================================================== //
++ {0xfc,0x01},
++ {0x05,0xC0},
++
++ {0xfc,0x0b},
++ {0x35,0x00}, // YLPF start AGC
++ {0x36,0x20}, // YLPF01 AGCMIN
++ {0x37,0x50}, // YLPF01 AGCMAX
++ {0x38,0x00}, // YLPF SIG01 Th AGCMINH
++ {0x39,0x18}, // YLPF SIG01 Th AGCMINL
++ {0x3a,0x00}, // YLPF SIG01 Th AGCMAXH
++ {0x3b,0x40}, // YLPF SIG01 Th AGCMAXH
++ {0x3c,0x20}, // YLPF02 AGCMIN
++ {0x3d,0x50}, // YLPF02 AGCMAX
++ {0x3e,0x00}, // YLPF SIG02 Th AGCMINH
++ {0x3f,0x30}, // YLPF SIG02 Th AGCMINL
++ {0x40,0x00}, // YLPF SIG02 Th AGCMAXH
++ {0x41,0x40}, // YLPF SIG02 Th AGCMAXH
++ {0xd4,0x20}, // CLPF AGCMIN
++ {0xd5,0x50}, // CLPF AGCMAX
++ {0xd6,0xb0}, // CLPF SIG01 Th AGCMIN
++ {0xd7,0xf0}, // CLPF SIG01 Th AGCMAX
++ {0xd8,0xb0}, // CLPF SIG02 Th AGCMIN
++ {0xd9,0xf0}, // CLPF SIG02 Th AGCMAX
++
++ //========================================================== //
++ // COLOR SUPPRESS //
++ //========================================================== //
++ {0xfc,0x0b}, // COLOR SUPPRESS
++ {0x08,0x58}, // Color suppress AGC MIN
++ {0x09,0x04}, // Color suppress MIN H
++ {0x0a,0x00}, // Color suppress MIN L
++
++ //========================================================== //
++ // SHADING //
++ //========================================================== //
++ {0xfc,0x09},
++ //Shading file for 3BAFX
++ //90000 // shading off
++ // DSP9_SH_WIDTH_H
++ {0x01,0x06},
++ {0x02,0x40},
++ // DSP9_SH_HEIGHT_H
++ {0x03,0x04},
++ {0x04,0xB0},
++ // DSP9_SH_XCH_R
++ {0x05,0x03},
++ {0x06,0x20},
++ {0x07,0x02},
++ {0x08,0xa5},
++ // DSP9_SH_XCH_G
++ {0x09,0x03},
++ {0x0A,0x2a},
++ {0x0B,0x02},
++ {0x0C,0x78},
++ // DSP9_SH_XCH_B
++ {0x0D,0x02},
++ {0x0E,0xF9},
++ {0x0F,0x02},
++ {0x10,0x58},
++ // DSP9_SH_Del_eH_R
++ {0x1D,0x80},
++ {0x1E,0x00},
++ {0x1F,0x80},
++ {0x20,0x00},
++ {0x23,0x79},
++ {0x24,0xE6},
++ {0x21,0x82},
++ {0x22,0x9A},
++ // DSP9_SH_Del_eH_G
++ {0x25,0x80},
++ {0x26,0x00},
++ {0x27,0x80},
++ {0x28,0x00},
++ {0x2B,0x79},
++ {0x2C,0xE6},
++ {0x29,0x86},
++ {0x2A,0xBC},
++ // DSP9_SH_Del_eH_B
++ {0x2D,0x79},
++ {0x2E,0xE6},
++ {0x2F,0x78},
++ {0x30,0xBE},
++ {0x33,0x80},
++ {0x34,0x00},
++ {0x31,0x80},
++ {0x32,0x00},
++ //, DSP9_SH_VAL_R0H
++ {0x35,0x01},
++ {0x36,0x00},
++ {0x37,0x01},
++ {0x38,0x10},
++ {0x39,0x01},
++ {0x3A,0x35},
++ {0x3B,0x01},
++ {0x3C,0x68},
++ {0x3D,0x01},
++ {0x3E,0x84},
++ {0x3F,0x01},
++ {0x40,0xA3},
++ {0x41,0x01},
++ {0x42,0xC7},
++ {0x43,0x01},
++ {0x44,0xEC},
++ // DSP9_SH_VAL_G0H
++ {0x45,0x01},
++ {0x46,0x00},
++ {0x47,0x01},
++ {0x48,0x0C},
++ {0x49,0x01},
++ {0x4A,0x29},
++ {0x4B,0x01},
++ {0x4C,0x4D},
++ {0x4D,0x01},
++ {0x4E,0x5F},
++ {0x4F,0x01},
++ {0x50,0x78},
++ {0x51,0x01},
++ {0x52,0x8C},
++ {0x53,0x01},
++ {0x54,0xA7},
++ // DSP9_SH_VAL_B0H
++ {0x55,0x01},
++ {0x56,0x00},
++ {0x57,0x01},
++ {0x58,0x0A},
++ {0x59,0x01},
++ {0x5A,0x23},
++ {0x5B,0x01},
++ {0x5C,0x43},
++ {0x5D,0x01},
++ {0x5E,0x57},
++ {0x5F,0x01},
++ {0x60,0x6A},
++ {0x61,0x01},
++ {0x62,0x7E},
++ {0x63,0x01},
++ {0x64,0x9C},
++ // DSP9_SH_M_R2_R1H
++ {0x65,0x00},
++ {0x66,0xA5},
++ {0x67,0xDF},
++ {0x68,0x02},
++ {0x69,0x97},
++ {0x6A,0x7E},
++ {0x6B,0x05},
++ {0x6C,0xD4},
++ {0x6D,0xDB},
++ {0x6E,0x07},
++ {0x6F,0xEF},
++ {0x70,0xF2},
++ {0x71,0x0A},
++ {0x72,0x5D},
++ {0x73,0xF8},
++ {0x74,0x0D},
++ {0x75,0x1E},
++ {0x76,0xED},
++ {0x77,0x10},
++ {0x78,0x32},
++ {0x79,0xD3},
++ // DSP9_SH_M_R2_G1H
++ {0x7A,0x00},
++ {0x7B,0x87},
++ {0x7C,0x7C},
++ {0x7D,0x02},
++ {0x7E,0x1D},
++ {0x7F,0xEE},
++ {0x80,0x04},
++ {0x81,0xC3},
++ {0x82,0x58},
++ {0x83,0x06},
++ {0x84,0x7B},
++ {0x85,0xAA},
++ {0x86,0x08},
++ {0x87,0x77},
++ {0x88,0xB9},
++ {0x89,0x0A},
++ {0x8A,0xB7},
++ {0x8B,0x87},
++ {0x8C,0x0D},
++ {0x8D,0x3B},
++ {0x8E,0x12},
++ // DSP9_SH_M_R2_B1H
++ {0x8F,0x00},
++ {0x90,0x93},
++ {0x91,0x91},
++ {0x92,0x02},
++ {0x93,0x4E},
++ {0x94,0x42},
++ {0x95,0x05},
++ {0x96,0x30},
++ {0x97,0x15},
++ {0x98,0x07},
++ {0x99,0x0F},
++ {0x9A,0xAB},
++ {0x9B,0x09},
++ {0x9C,0x39},
++ {0x9D,0x09},
++ {0x9E,0x0B},
++ {0x9F,0xAC},
++ {0xA0,0x2F},
++ {0xA1,0x0E},
++ {0xA2,0x69},
++ {0xA3,0x1E},
++ // DSP9_SH_SUB_RR0H
++ {0xA4,0x62},
++ {0xA5,0xC6},
++ {0xA6,0x20},
++ {0xA7,0xEC},
++ {0xA8,0x13},
++ {0xA9,0xC1},
++ {0xAA,0x1E},
++ {0xAB,0x64},
++ {0xAC,0x1A},
++ {0xAD,0x56},
++ {0xAE,0x17},
++ {0xAF,0x3D},
++ {0xB0,0x14},
++ {0xB1,0xCB},
++ // DSP9_SH_SUB_RG0H
++ {0xB2,0x78},
++ {0xB3,0xEE},
++ {0xB4,0x28},
++ {0xB5,0x4F},
++ {0xB6,0x18},
++ {0xB7,0x2F},
++ {0xB8,0x25},
++ {0xB9,0x35},
++ {0xBA,0x20},
++ {0xBB,0x3F},
++ {0xBC,0x1C},
++ {0xBD,0x74},
++ {0xBE,0x19},
++ {0xBF,0x75},
++ // DSP9_SH_SUB_RB0H
++ {0xC0,0x6F},
++ {0xC1,0x07},
++ {0xC2,0x25},
++ {0xC3,0x02},
++ {0xC4,0x16},
++ {0xC5,0x34},
++ {0xC6,0x22},
++ {0xC7,0x29},
++ {0xC8,0x1D},
++ {0xC9,0x9B},
++ {0xCA,0x1A},
++ {0xCB,0x1F},
++ {0xCC,0x17},
++ {0xCD,0x5F},
++
++ {0x00,0x02}, // shading on
++
++ //==========================================================//
++ // X-SHADING //
++ //==========================================================//
++ {0xfc,0x1B}, // X-SHADING
++ {0x80,0x01},
++ {0x81,0x00},
++ {0x82,0x4c},
++ {0x83,0x00},
++ {0x84,0x86},
++ {0x85,0x03},
++ {0x86,0x5e},
++ {0x87,0x00},
++ {0x88,0x07},
++ {0x89,0xa4},
++ {0x90,0x00},
++ {0x91,0xd3},
++ {0x92,0x01},
++ {0x93,0x09},
++ {0x94,0x01},
++ {0x95,0x3a},
++ {0x96,0x01},
++ {0x97,0x5c},
++ {0x98,0x01},
++ {0x99,0x70},
++ {0x9a,0x01},
++ {0x9b,0x5f},
++ {0x9c,0x01},
++ {0x9d,0x2d},
++ {0x9e,0x00},
++ {0x9f,0x9b},
++ {0xa0,0x00},
++ {0xa1,0xbd},
++ {0xa2,0x00},
++ {0xa3,0xd9},
++ {0xa4,0x00},
++ {0xa5,0xf8},
++ {0xa6,0x01},
++ {0xa7,0x05},
++ {0xa8,0x00},
++ {0xa9,0xfd},
++ {0xaa,0x00},
++ {0xab,0xdf},
++ {0xac,0x00},
++ {0xad,0x35},
++ {0xae,0x00},
++ {0xaf,0x33},
++ {0xb0,0x00},
++ {0xb1,0x29},
++ {0xb2,0x00},
++ {0xb3,0x20},
++ {0xb4,0x00},
++ {0xb5,0x2a},
++ {0xb6,0x00},
++ {0xb7,0x38},
++ {0xb8,0x00},
++ {0xb9,0x3d},
++ {0xba,0x07},
++ {0xbb,0xb2},
++ {0xbc,0x07},
++ {0xbd,0x86},
++ {0xbe,0x07},
++ {0xbf,0x54},
++ {0xc0,0x07},
++ {0xc1,0x2b},
++ {0xc2,0x07},
++ {0xc3,0x27},
++ {0xc4,0x07},
++ {0xc5,0x41},
++ {0xc6,0x07},
++ {0xc7,0x6e},
++ {0xc8,0x07},
++ {0xc9,0x4a},
++ {0xca,0x06},
++ {0xcb,0xfe},
++ {0xcc,0x06},
++ {0xcd,0xb5},
++ {0xce,0x06},
++ {0xcf,0x86},
++ {0xd0,0x06},
++ {0xd1,0x73},
++ {0xd2,0x06},
++ {0xd3,0x92},
++ {0xd4,0x06},
++ {0xd5,0xe0},
++
++ {0xfc,0x0b}, // x-shading temp. correlation factor
++ {0xda,0x00}, // t0(3100K)
++ {0xdb,0x9c},
++ {0xdc,0x00}, // tc(5100K)
++ {0xdd,0xd1}, // default eeh
++
++ {0xfc,0x1b},
++ {0x80,0x01}, // X-Shading On
++
++ //=========================================================//
++ // AE WINDOW WEIGHT //
++ //=========================================================//
++ {0xfc,0x00}, // AE WINDOW WEIGHT
++ {0x03,0x4b}, // AE Suppress On
++ {0xfc,0x06},
++ {0x01,0x35}, // UXGA AE Window
++ {0x03,0xc2},
++ {0x05,0x48},
++ {0x07,0xb8},
++ {0x09,0x50},
++ {0x0b,0xbc},
++ {0x0d,0x2c},
++ {0x0f,0x8f},
++ {0x31,0x2a}, // Subsampling AE Window
++ {0x33,0x61},
++ {0x35,0x28},
++ {0x37,0x5c},
++ {0x39,0x4d},
++ {0x3b,0x5a},
++ {0x3d,0x36},
++ {0x3f,0x43},
++
++ {0xfc,0x20},
++ {0x60,0x11},
++ {0x61,0x11},
++ {0x62,0x11},
++ {0x63,0x11},
++ {0x64,0x11},
++ {0x65,0x11},
++ {0x66,0x11},
++ {0x67,0x11},
++ {0x68,0x11},
++ {0x69,0x11},
++ {0x6a,0x11},
++ {0x6b,0x11},
++ {0x6c,0x11},
++ {0x6d,0x11},
++ {0x6e,0x11},
++ {0x6f,0x11},
++ {0x70,0x11},
++ {0x71,0x11},
++ {0x72,0x11},
++ {0x73,0x11},
++ {0x74,0x11},
++ {0x75,0x11},
++ {0x76,0x11},
++ {0x77,0x11},
++
++ //========================================================== //
++ // SAIT AWB //
++ //========================================================== //
++ {0xfc,0x07},
++ {0x3c,0x10}, // AWB cut R min
++ {0x3d,0x10}, // AWB cut B min
++ {0x3e,0x10}, // AWB cut R max
++ {0x3f,0x10}, // AWB cut B max
++
++ {0xfc,0x01},
++ {0xc8,0xe0}, // AWB Y Max
++ {0xfc,0x00},
++ {0x3e,0x10}, // AWB Y_min
++
++ {0xfc,0x00},
++ {0x3e,0x10}, // AWB Y_min Normal
++ {0x3d,0x04}, // AWB Y_min Low
++ {0x32,0x02}, // AWB moving average 8 frame
++ {0x81,0x10}, // AWB G gain suppress Disable
++ {0xbc,0xf0},
++ {0xfc,0x22},
++ {0x8a,0x0a}, // AWB difference threshold check
++ {0x8b,0x03},
++ {0x8c,0x04}, // AWB Min Y Weight check
++ {0x8d,0x06}, // AWB Max Y Weight check
++
++ {0xfc,0x07},
++ {0x97,0x00}, // S/W Y_lowpass Filter OFF
++
++ //=================================
++ // White Point
++ //=================================
++ {0xfc,0x22},
++ {0x01,0xd8}, // D65
++ {0x03,0xa1},
++ {0x05,0xcd}, // 5000K
++ {0x07,0xba},
++ {0x09,0xb0}, // CWF
++ {0x0b,0xe1},
++ {0x0d,0xa0}, // 3000K
++ {0x0f,0xf0},
++ {0x11,0x8f}, // A
++ {0x12,0x00},
++ {0x13,0xfc},
++ {0x15,0x80}, // 2000K
++ {0x16,0x01},
++
++ //=================================
++ // Basic Setting
++ //=================================
++ {0xfc,0x22},
++ {0xA8,0xff},
++ {0xA0,0x01},
++ {0xA1,0x3D},
++ {0xA2,0x0D},
++ {0xA3,0xAD},
++ {0xA4,0x07},
++ {0xA5,0xE7},
++ {0xA6,0x12},
++ {0xA7,0xB7},
++ {0xA9,0x02},
++ {0xAA,0x8A},
++ {0xAB,0x23},
++ {0xAC,0xA2},
++ {0xAD,0x02},
++ {0xAE,0x04},
++ {0xAF,0x09},
++ {0xB0,0x84},
++ {0x94,0x36},
++ {0x95,0xB3},
++ {0x96,0x5E},
++ {0x97,0xE8},
++ {0xD0,0xb0},
++ {0xD1,0x30},
++ {0xD2,0x00},
++ {0xD3,0x21},
++ {0xD4,0xFF}, //Low Temp ÀÎ½Ä ±âÁØ
++ {0xDB,0x30},
++ {0xDC,0x7B},
++ {0xDD,0x21},
++ {0xE7,0x00},
++ {0xE8,0xB8},
++ {0xE9,0x00},
++ {0xEA,0xE0},
++ {0xEB,0x00},
++ {0xEC,0x00},
++ {0xEE,0xa0}, //AWB swing
++
++ //=================================
++ // Pixel Filter Setting
++ //=================================
++ {0xFC,0x07},
++ {0x95,0xCF},
++
++ {0xfc,0x01},
++ {0xd3,0x4f},
++ {0xd4,0x00},
++ {0xd5,0x3a},
++ {0xd6,0x80},
++ {0xd7,0x60},
++ {0xd8,0x00},
++ {0xd9,0x49},
++ {0xda,0x00},
++ {0xdb,0x24},
++ {0xdc,0x4b},
++ {0xdd,0x26},
++ {0xde,0x54},
++ {0xdf,0x20},
++ {0xe0,0xc9},
++ {0xe1,0x19},
++ {0xe2,0x4c},
++ {0xe3,0x31},
++ {0xe4,0x40},
++ {0xe5,0x39},
++ {0xe6,0x40},
++ {0xe7,0x40},
++ {0xe8,0x37},
++ {0xe9,0x40},
++ {0xea,0x22},
++ {0xeb,0x00},
++
++ //=================================
++ // AWB3 - Polygon Region
++ //=================================
++ {0xfc,0x22},
++ {0x18,0x00},
++ {0x19,0x70},
++ {0x1a,0xca},
++ {0x1b,0x00},
++ {0x1c,0x65},
++ {0x1d,0xc9},
++ {0x1e,0x00},
++ {0x1f,0x67},
++ {0x20,0xb4},
++ {0x21,0x00},
++ {0x22,0x80},
++ {0x23,0x92},
++ {0x24,0x00},
++ {0x25,0x9e},
++ {0x26,0x7c},
++ {0x27,0x00},
++ {0x28,0xb3},
++ {0x29,0x6c},
++ {0x2a,0x00},
++ {0x2b,0xcd},
++ {0x2c,0x66},
++ {0x2d,0x00},
++ {0x2e,0xd0},
++ {0x2f,0x6f},
++ {0x30,0x00},
++ {0x31,0xbb},
++ {0x32,0x7a},
++ {0x33,0x00},
++ {0x34,0xac},
++ {0x35,0x86},
++ {0x36,0x00},
++ {0x37,0x95},
++ {0x38,0xa1},
++ {0x39,0x00},
++ {0x3a,0x83},
++ {0x3b,0xc2},
++ {0x3c,0x00},
++ {0x3d,0x00},
++
++ //=================================
++ // Moving Equation Weight
++ //=================================
++ {0xfc,0x22},
++ {0x98,0x07},
++
++ //=================================
++ // EIT Threshold
++ //=================================
++ {0xfc,0x22},
++ {0xb1,0x00}, // Sunny
++ {0xb2,0x03},
++ {0xb3,0x00},
++ {0xb4,0xC1},
++
++ {0xb5,0x00}, // Cloudy
++ {0xb6,0x03},
++ {0xb7,0x00},
++ {0xb9,0xc2},
++
++ {0xd7,0x00}, // Shade
++ {0xd8,0x35},
++ {0xd9,0x20},
++ {0xda,0x81},
++
++ //=================================
++ // Gain Offset
++ //=================================
++ {0xfc,0x00},
++ {0x79,0xf2}, // Global R gain
++ {0x7a,0x0b}, // Global B gain
++
++ {0xfc,0x07},
++ {0x11,0xfe}, // Global G gain
++
++ {0xfc,0x22},
++ {0x58,0x00}, //ff}, //f8}, //f3}, // D65 R Offset
++ {0x59,0xf6}, //f8}, // D65 B Offset
++ {0x5A,0x00}, //ff}, //f9}, //f8}, // 5000K R Offset
++ {0x5B,0xfe}, //00}, // 5000K B Offset
++ {0x5C,0x02}, //00}, // CWF R Offset
++ {0x5D,0x00}, // CWF B Offset
++ {0x5E,0x02}, // 3000K R Offset
++ {0x5F,0x00}, //08}, // 3000K B Offset
++ {0x60,0x04}, // A R Offset
++ {0x61,0x06}, //08}, // A B Offset
++ {0x62,0x0a}, // 2000K R Offset
++ {0x63,0x06}, //08}, // 2000K B Offset
++
++ {0xde,0x00}, // LARGE OBJECT BUG FIX
++ {0xf0,0x6a}, // RB Ratio
++
++ //=================================
++ // Green Stablity Enhance
++ //=================================
++ {0xfc,0x22},
++ {0xb9,0x00},
++ {0xba,0x00},
++ {0xbb,0x00},
++ {0xbc,0x00},
++ {0xe5,0x01},
++ {0xe6,0xff},
++ {0xbd,0x2c},
++ {0x67,0x00},
++
++ //==========================================================
++ // Special Effect
++ //==========================================================
++ //{0xfc,0x07}, // Special Effect
++ //{0x30,0xc0},
++ //{0x31,0x20},
++ //{0x32,0x40},
++ //{0x33,0xc0},
++ //{0x34,0x00},
++ //{0x35,0xb0},
++
++ //==========================================================//
++ // ETC //
++ //==========================================================//
++ {0xfc,0x01},
++ {0x01,0x00}, //01}, // VCK Inversion //for high pclk setting
++ {0x00,0x90}, // sck inv.
++ {0xfc,0x02},
++ {0x03,0x20}, // SCK inv.
++ {0xfc,0x00},
++ {0x02,0x09}, // 800X600
++#else // LG, Matterhorn Camera
++ //==========================================================
++ // PLL SET
++ //==========================================================
++ {0xfc,0x02},
++ {0x50,0x58},//5a},
++ {0x51,0x0a},
++ {0x52,0x80},
++ //==========================================================
++ // CAMERA INITIAL
++ //==========================================================
++ {0xfc,0x07},
++ {0x66,0x01},
++ {0xfc,0x00},
++ {0x00,0xaa}, //for ESD_CHECK
++ {0x21,0x03},
++ {0xfc,0x01},
++ {0x04,0x01},
++ {0xfc,0x02},
++ {0x55,0x1e},
++ {0x56,0x10},
++ {0x57,0x80},
++ {0x58,0x80},
++ {0x59,0x80},
++ {0x2d,0x48},
++ {0x4d,0x08},
++ {0x37,0x17},
++ {0x30,0x82},
++ {0x66,0x41},
++ {0x43,0xef},
++ {0x62,0x60},
++ {0xfc,0x02},
++ {0x4a,0x40},
++ //==========================================================
++ // Table Set for Sub-Sampling
++ //==========================================================
++ {0xfc,0x03},
++ {0x2c,0x00},
++ {0x05,0x46},
++ {0x07,0xb6},
++ {0x0e,0x04},
++ {0x12,0x03},
++ {0xfc,0x04},
++ {0xc2,0x03},
++ {0xc3,0x17},
++ {0xc5,0x26},
++ {0xc7,0x5e},
++ {0xce,0x04},
++ {0xd2,0x04},
++ {0xec,0x00},
++ {0xc0,0x05},
++ {0xc1,0x40},
++ {0xfc,0x07},
++ {0x05,0x00},
++ {0x06,0x00},
++ {0x07,0x8b},
++ {0x08,0xf5},
++ {0x09,0x00},
++ {0x0a,0x89},
++ {0x0b,0x00},
++ {0x0c,0xb0},
++ {0x0d,0x00},
++ {0x0e,0x40},
++ {0xfc,0x00},
++ {0x70,0x02},
++ {0xfc,0x03},
++ {0x2e,0x00},
++ {0x5e,0x00},
++ {0x8e,0x00},
++ {0xbe,0x00},
++ {0xee,0x00},
++ {0xfc,0x04},
++ {0x2e,0x00},
++ {0x5e,0x00},
++ {0x8e,0x00},
++ {0xbe,0x00},
++ {0xee,0x00},
++ {0xfc,0x00},
++ {0x73,0x11},
++ {0x02,0x09},
++ {0x20,0x02},
++ {0xfc,0x00},
++ {0x02,0x09}, // 800 x 600
++
++ //==========================================================
++ // ISP Setting
++ //==========================================================
++ {0xfc,0x00},
++ {0x6c,0xb0},
++ {0x6d,0x00},
++ {0xfc,0x20},
++ {0x16,0x5a},
++ {0xfc,0x00},
++ {0x78,0x63},
++ {0xfc,0x20},
++ {0x16,0x60},
++ {0xfc,0x20},
++ {0x57,0x18},
++ {0x2c,0x30},
++ {0x2e,0x00},
++ {0x14,0x70},
++ {0x01,0x02},
++ {0xfc,0x07},
++ {0x11,0x01},
++ {0xfc,0x07},
++ {0x3e,0x0a},
++ {0xfc,0x01},
++ {0xc8,0xa0},
++ {0xfc,0x00},
++ {0x3e,0x10},
++ {0x3d,0x04},
++ {0xfc,0x22},
++ {0x8c,0x04},
++ {0x8d,0x06},
++ {0xfc,0x00},
++ {0x32,0x02},
++ {0x81,0x10},
++ {0xbc,0xf0},
++ {0x29,0x03}, //Brightness Offset High
++ {0x2a,0xc0}, //Brightness Offset Low
++ {0x2b,0x03}, //Color Saturation High
++ {0x2c,0x80}, //Color Saturation Low
++ {0xfc,0x07},
++ {0x37,0x00},
++ {0x64,0x6f},
++ {0xfc,0x00},
++ {0x72,0xa0},//a3},
++ {0x74,0x18}, // 0x18 : 60hz auto 0x14 : 50hz auto 0x08 : 60hz fixed 0x04 : 50hz fixed flicker
++ {0xfc,0x20},
++ {0x02,0x02},
++ {0xfc,0x00},
++ {0x62,0x02},
++ {0xfc,0x02},
++ {0x4e,0x00},
++ {0x4e,0x00},
++ {0x4e,0x00},
++ {0x4e,0x00},
++ {0x4f,0x0a},
++ {0x4f,0x0a},
++ {0x4f,0x0a},
++ {0x4f,0x0a},
++ {0xfc,0x01},
++ {0x0c,0x03},
++ {0x0c,0x03},
++ {0x01,0x00},
++ {0xfc,0x00},
++ {0x7e,0xf4},
++ {0xfc,0x01},
++ {0x3d,0x10},
++ {0xfc,0x02},
++ {0x03,0x20},
++ {0xfc,0x01},
++ {0x00,0x90},
++ {0xfc,0x07},
++ {0x3a,0xaa},
++ {0xfc,0x02},
++ {0x4e,0x1b},
++ {0x4f,0xda},
++ {0xfc,0x07},
++ {0x97,0x00},
++
++ //==========================================================
++ // COLOR MATRIX
++ //==========================================================
++ {0xfc,0x01},
++ {0x51,0x08},
++ {0x52,0x9b},
++ {0x53,0xfc},
++ {0x54,0x07},
++ {0x55,0xff},
++ {0x56,0x5e},
++ {0x57,0xfd},
++ {0x58,0x0e},
++ {0x59,0x07},
++ {0x5a,0xee},
++ {0x5b,0xff},
++ {0x5c,0x05},
++ {0x5d,0xff},
++ {0x5e,0x7a},
++ {0x5f,0xfc},
++ {0x60,0x23},
++ {0x61,0x08},
++ {0x62,0x64},
++ //==========================================================
++ // EDGE SUPPRESSION
++ //==========================================================
++ {0xfc,0x00},
++ {0x89,0x03},
++ {0xfc,0x0b},
++ {0x42,0x50},
++ {0x43,0x60},
++ {0x45,0x30},
++ {0x49,0x10},
++ {0x4d,0x30},
++ {0x51,0x10},
++ //==========================================================
++ // EDGE ENHANCEMENT
++ //==========================================================
++ {0xfc,0x05},
++ {0x34,0x34},
++ {0x35,0x08},
++ {0x36,0x0b},
++ {0x3f,0x00},
++ {0x42,0x10},
++ {0x43,0x00},
++ {0x45,0xa0},
++ {0x46,0x7a},
++ {0x47,0x40},
++ {0x48,0x0c},
++ {0x49,0x31},
++ {0x40,0x41},
++ //==========================================================
++ // GAMMA
++ //==========================================================
++ {0xfc,0x1d},
++ {0x00,0x0a},
++ {0x01,0x1e},
++ {0x02,0x42},
++ {0x03,0x07},
++ {0x04,0x01},
++ {0x05,0x9e},
++ {0x06,0xfa},
++ {0x07,0x42},
++ {0x08,0x75},
++ {0x09,0x5a},
++ {0x0a,0xa5},
++ {0x0b,0xc9},
++ {0x0c,0xec},
++ {0x0d,0x0d},
++ {0x0e,0xab},
++ {0x0f,0x2b},
++ {0x10,0x48},
++ {0x11,0x64},
++ {0x12,0x7c},
++ {0x13,0xff},
++ {0x14,0x91},
++ {0x15,0xa2},
++ {0x16,0xb0},
++ {0x17,0xbd},
++ {0x18,0xff},
++ {0x19,0xc8},
++ {0x1a,0xd2},
++ {0x1b,0xda},
++ {0x1c,0xe0},
++ {0x1d,0xff},
++ {0x1e,0xe5},
++ {0x1f,0xea},
++ {0x20,0xed},
++ {0x21,0xef},
++ {0x22,0xff},
++ {0x23,0xf0},
++ {0x24,0xf3},
++ {0x25,0xf5},
++ {0x26,0xf8},
++ {0x27,0xff},
++ {0x28,0xfb},
++ {0x29,0xff},
++ {0x2a,0xf0},
++ {0x2b,0x0a},
++ {0x2c,0x1e},
++ {0x2d,0x42},
++ {0x2e,0x07},
++ {0x2f,0x01},
++ {0x30,0x9e},
++ {0x31,0xfa},
++ {0x32,0x42},
++ {0x33,0x75},
++ {0x34,0x5a},
++ {0x35,0xa5},
++ {0x36,0xc9},
++ {0x37,0xec},
++ {0x38,0x0d},
++ {0x39,0xab},
++ {0x3a,0x2b},
++ {0x3b,0x48},
++ {0x3c,0x64},
++ {0x3d,0x7c},
++ {0x3e,0xff},
++ {0x3f,0x91},
++ {0x40,0xa2},
++ {0x41,0xb0},
++ {0x42,0xbd},
++ {0x43,0xff},
++ {0x44,0xc8},
++ {0x45,0xd2},
++ {0x46,0xda},
++ {0x47,0xe0},
++ {0x48,0xff},
++ {0x49,0xe5},
++ {0x4a,0xea},
++ {0x4b,0xed},
++ {0x4c,0xef},
++ {0x4d,0xff},
++ {0x4e,0xf0},
++ {0x4f,0xf3},
++ {0x50,0xf5},
++ {0x51,0xf8},
++ {0x52,0xff},
++ {0x53,0xfb},
++ {0x54,0xff},
++ {0x55,0xf0},
++ {0x56,0x0a},
++ {0x57,0x1e},
++ {0x58,0x42},
++ {0x59,0x07},
++ {0x5a,0x01},
++ {0x5b,0x9e},
++ {0x5c,0xfa},
++ {0x5d,0x42},
++ {0x5e,0x75},
++ {0x5f,0x5a},
++ {0x60,0xa5},
++ {0x61,0xc9},
++ {0x62,0xec},
++ {0x63,0x0d},
++ {0x64,0xab},
++ {0x65,0x2b},
++ {0x66,0x48},
++ {0x67,0x64},
++ {0x68,0x7c},
++ {0x69,0xff},
++ {0x6a,0x91},
++ {0x6b,0xa2},
++ {0x6c,0xb0},
++ {0x6d,0xbd},
++ {0x6e,0xff},
++ {0x6f,0xc8},
++ {0x70,0xd2},
++ {0x71,0xda},
++ {0x72,0xe0},
++ {0x73,0xff},
++ {0x74,0xe5},
++ {0x75,0xea},
++ {0x76,0xed},
++ {0x77,0xef},
++ {0x78,0xff},
++ {0x79,0xf0},
++ {0x7a,0xf3},
++ {0x7b,0xf5},
++ {0x7c,0xf8},
++ {0x7d,0xff},
++ {0x7e,0xfb},
++ {0x7f,0xff},
++ {0x80,0xf0},
++ //==========================================================
++ // HUE CONTROL
++ //==========================================================
++ {0xfc,0x00},
++ {0x62,0x03},
++ {0x48,0x42}, //2000K
++ {0x49,0x40},
++ {0x4a,0xf0},
++ {0x4b,0xf4},
++ {0x4c,0x40},
++ {0x4d,0x6a},
++ {0x4e,0x08},
++ {0x4f,0x03},
++ {0x50,0x46}, //3000K
++ {0x51,0x48},
++ {0x52,0xf8},
++ {0x53,0xf4},
++ {0x54,0x40},
++ {0x55,0x6a},
++ {0x56,0x08},
++ {0x57,0xfd},
++ {0x58,0x30}, //5000K
++ {0x59,0x38},
++ {0x5a,0x02},
++ {0x5b,0xf0},
++ {0x5c,0x30},
++ {0x5d,0x4a},
++ {0x5e,0x0c},
++ {0x5f,0xfd},
++
++ //==========================================================
++ // Bad Pixel Replacement
++ //==========================================================
++ {0xfc,0x0b},
++ {0x0b,0x00},
++ {0x0c,0x40},
++ {0x0d,0x5a},
++ {0x0e,0x00},
++ {0x0f,0x20},
++ {0x10,0x00},
++ {0x11,0x10},
++ {0x12,0x00},
++ {0x13,0x00},
++ {0x14,0xff},
++ {0x15,0xff},
++ {0x16,0x48},
++ {0x17,0x60},
++ {0x18,0x00},
++ {0x19,0x00},
++ {0x1a,0x00},
++ {0x1b,0x20},
++ {0x1c,0x00},
++ {0x1d,0x00},
++ {0x1e,0x00},
++ {0x1f,0x20},
++ //==========================================================
++ // GR/GB CORRECTION
++ //==========================================================
++ {0xfc,0x01},
++ {0x45,0x0c},
++ {0xfc,0x0b},
++ {0x21,0x00},
++ {0x22,0x58},
++ {0x23,0x68},
++ {0x24,0x1a},
++ {0x25,0x28},//0x16
++ {0x26,0x1a},
++ {0x27,0x28},//0x20
++ //==========================================================
++ // Noise Reduction
++ //==========================================================
++ {0xfc,0x01},
++ {0x4c,0x01},
++ {0x49,0x15},
++ {0x4b,0x0a},
++ {0xfc,0x0b},
++ {0x28,0x00},
++ {0x29,0x00},
++ {0x2a,0x14},
++ {0x2b,0x00},
++ {0x2c,0x14},
++ {0x2d,0x00},
++ {0x2e,0x90},
++ {0x2f,0x00},
++ {0x30,0xc0},
++ {0x31,0x00},
++ {0x32,0xa0},
++ {0x33,0x00},
++ {0x34,0xd0},
++ //==========================================================
++ // 1D-Y/C-SIGMA-LPF
++ //==========================================================
++ {0xfc,0x01},
++ {0x05,0xc0},
++ {0xfc,0x0b},
++ {0x35,0x00},
++ {0x36,0x60},
++ {0x37,0x68},
++ {0x38,0x00},
++ {0x39,0x08},
++ {0x3a,0x00},
++ {0x3b,0x30},
++ {0x3c,0x60},
++ {0x3d,0x68},
++ {0x3e,0x00},
++ {0x3f,0x30},
++ {0x40,0x00},
++ {0x41,0x38},
++ {0xd4,0x60},
++ {0xd5,0x68},
++ {0xd6,0xb0},
++ {0xd7,0xb8},
++ {0xd8,0xb0},
++ {0xd9,0xb8},
++ //==========================================================
++ // COLOR SUPPRESS
++ //==========================================================
++ {0xfc,0x0b},
++ {0x08,0x73},
++ {0x09,0x03},
++ {0x0a,0x40},
++ //==========================================================
++ // SHADING
++ //==========================================================
++ {0xfc,0x09},
++ {0x01,0x06},
++ {0x02,0x40},
++ {0x03,0x04},
++ {0x04,0xb0},
++ {0x05,0x03}, //0x02
++ {0x06,0x1a}, //0x10 0x08 0xf8
++ {0x07,0x02},
++ {0x08,0x2b}, //0x4b 0x5b 0x70 0x8a
++ {0x09,0x03},
++ {0x0a,0x02},
++ {0x0b,0x02},
++ {0x0c,0x58},
++ {0x0d,0x03}, //0x02
++ {0x0e,0x22}, //0x18 0x10 0xf0 0xd0
++ {0x0f,0x02},
++ {0x10,0x5d}, //0x51 0x39
++ {0x1d,0x80},
++ {0x1e,0x00},
++ {0x1f,0x80},
++ {0x20,0x00},
++ {0x21,0x80},
++ {0x22,0x00},
++ {0x23,0x80},
++ {0x24,0x00},
++ {0x25,0x80},
++ {0x26,0x00},
++ {0x27,0x80},
++ {0x28,0x00},
++ {0x29,0x80},
++ {0x2a,0x00},
++ {0x2b,0x80},
++ {0x2c,0x00},
++ {0x2d,0x80},
++ {0x2e,0x00},
++ {0x2f,0x80},
++ {0x30,0x00},
++ {0x31,0x80},
++ {0x32,0x00},
++ {0x33,0x7d},
++ {0x34,0x7c},
++ {0x35,0x01},
++ {0x36,0x0a},
++ {0x37,0x01},
++ {0x38,0x1e},
++ {0x39,0x01},
++ {0x3a,0x41},
++ {0x3b,0x01},
++ {0x3c,0x72},
++ {0x3d,0x01},
++ {0x3e,0x8c},
++ {0x3f,0x01},
++ {0x40,0xa7},
++ {0x41,0x01},
++ {0x42,0xc5},
++ {0x43,0x01},
++ {0x44,0xec},
++ {0x45,0x01},
++ {0x46,0x00},
++ {0x47,0x01},
++ {0x48,0x0c},
++ {0x49,0x01},
++ {0x4a,0x29},
++ {0x4b,0x01},
++ {0x4c,0x4d},
++ {0x4d,0x01},
++ {0x4e,0x5f},
++ {0x4f,0x01},
++ {0x50,0x78},
++ {0x51,0x01},
++ {0x52,0x92},
++ {0x53,0x01},
++ {0x54,0xb1},
++ {0x55,0x01},
++ {0x56,0x00},
++ {0x57,0x01},
++ {0x58,0x0a},
++ {0x59,0x01},
++ {0x5a,0x23},
++ {0x5b,0x01},
++ {0x5c,0x3d},
++ {0x5d,0x01},
++ {0x5e,0x4f},
++ {0x5f,0x01},
++ {0x60,0x62},
++ {0x61,0x01},
++ {0x62,0x76},
++ {0x63,0x01},
++ {0x64,0x8e},
++ {0x65,0x00},
++ {0x66,0xa4},
++ {0x67,0xdf},
++ {0x68,0x02},
++ {0x69,0x93},
++ {0x6a,0x7e},
++ {0x6b,0x05},
++ {0x6c,0xcb},
++ {0x6d,0xdb},
++ {0x6e,0x07},
++ {0x6f,0xe3},
++ {0x70,0xb2},
++ {0x71,0x0a},
++ {0x72,0x4d},
++ {0x73,0xf8},
++ {0x74,0x0d},
++ {0x75,0x0a},
++ {0x76,0xad},
++ {0x77,0x10},
++ {0x78,0x19},
++ {0x79,0xd3},
++ {0x7a,0x00},
++ {0x7b,0x93},
++ {0x7c,0xdd},
++ {0x7d,0x02},
++ {0x7e,0x4f},
++ {0x7f,0x75},
++ {0x80,0x05},
++ {0x81,0x32},
++ {0x82,0xc7},
++ {0x83,0x07},
++ {0x84,0x13},
++ {0x85,0x56},
++ {0x86,0x09},
++ {0x87,0x3d},
++ {0x88,0xd3},
++ {0x89,0x0b},
++ {0x8a,0xb2},
++ {0x8b,0x3f},
++ {0x8c,0x0e},
++ {0x8d,0x70},
++ {0x8e,0x9a},
++ {0x8f,0x00},
++ {0x90,0x9c},
++ {0x91,0xf4},
++ {0x92,0x02},
++ {0x93,0x73},
++ {0x94,0xcf},
++ {0x95,0x05},
++ {0x96,0x84},
++ {0x97,0x92},
++ {0x98,0x07},
++ {0x99,0x82},
++ {0x9a,0xaa},
++ {0x9b,0x09},
++ {0x9c,0xcf},
++ {0x9d,0x3c},
++ {0x9e,0x0c},
++ {0x9f,0x6a},
++ {0xa0,0x48},
++ {0xa1,0x0f},
++ {0xa2,0x53},
++ {0xa3,0xcd},
++ {0xa4,0x63},
++ {0xa5,0x5f},
++ {0xa6,0x21},
++ {0xa7,0x1f},
++ {0xa8,0x13},
++ {0xa9,0xdf},
++ {0xaa,0x1e},
++ {0xab,0x93},
++ {0xac,0x1a},
++ {0xad,0x7f},
++ {0xae,0x17},
++ {0xaf,0x61},
++ {0xb0,0x14},
++ {0xb1,0xeb},
++ {0xb2,0x6e},
++ {0xb3,0xcd},
++ {0xb4,0x24},
++ {0xb5,0xef},
++ {0xb6,0x16},
++ {0xb7,0x29},
++ {0xb8,0x22},
++ {0xb9,0x17},
++ {0xba,0x1d},
++ {0xbb,0x8c},
++ {0xbc,0x1a},
++ {0xbd,0x12},
++ {0xbe,0x17},
++ {0xbf,0x53},
++ {0xc0,0x68},
++ {0xc1,0x63},
++ {0xc2,0x22},
++ {0xc3,0xcb},
++ {0xc4,0x14},
++ {0xc5,0xe0},
++ {0xc6,0x20},
++ {0xc7,0x1e},
++ {0xc8,0x1b},
++ {0xc9,0xd6},
++ {0xca,0x18},
++ {0xcb,0x8f},
++ {0xcc,0x15},
++ {0xcd,0xf9},
++ {0x00,0x02},
++ //==========================================================
++ // X-Shading
++ //==========================================================
++ {0xfc,0x1b},
++ {0x80,0x00},
++ {0x81,0x00},
++ {0x82,0x4c},
++ {0x83,0x00},
++ {0x84,0x86},
++ {0x85,0x03},
++ {0x86,0x5e},
++ {0x87,0x00},
++ {0x88,0x07},
++ {0x89,0xa4},
++ {0x90,0x00},
++ {0x91,0xd3},
++ {0x92,0x01},
++ {0x93,0x09},
++ {0x94,0x01},
++ {0x95,0x3a},
++ {0x96,0x01},
++ {0x97,0x5c},
++ {0x98,0x01},
++ {0x99,0x70},
++ {0x9a,0x01},
++ {0x9b,0x5f},
++ {0x9c,0x01},
++ {0x9d,0x2d},
++ {0x9e,0x00},
++ {0x9f,0x9b},
++ {0xa0,0x00},
++ {0xa1,0xbd},
++ {0xa2,0x00},
++ {0xa3,0xd9},
++ {0xa4,0x00},
++ {0xa5,0xf8},
++ {0xa6,0x01},
++ {0xa7,0x05},
++ {0xa8,0x00},
++ {0xa9,0xfd},
++ {0xaa,0x00},
++ {0xab,0xdf},
++ {0xac,0x00},
++ {0xad,0x35},
++ {0xae,0x00},
++ {0xaf,0x33},
++ {0xb0,0x00},
++ {0xb1,0x29},
++ {0xb2,0x00},
++ {0xb3,0x20},
++ {0xb4,0x00},
++ {0xb5,0x2a},
++ {0xb6,0x00},
++ {0xb7,0x38},
++ {0xb8,0x00},
++ {0xb9,0x3d},
++ {0xba,0x07},
++ {0xbb,0xb2},
++ {0xbc,0x07},
++ {0xbd,0x86},
++ {0xbe,0x07},
++ {0xbf,0x54},
++ {0xc0,0x07},
++ {0xc1,0x2b},
++ {0xc2,0x07},
++ {0xc3,0x27},
++ {0xc4,0x07},
++ {0xc5,0x41},
++ {0xc6,0x07},
++ {0xc7,0x6e},
++ {0xc8,0x07},
++ {0xc9,0x4a},
++ {0xca,0x06},
++ {0xcb,0xfe},
++ {0xcc,0x06},
++ {0xcd,0xb5},
++ {0xce,0x06},
++ {0xcf,0x86},
++ {0xd0,0x06},
++ {0xd1,0x73},
++ {0xd2,0x06},
++ {0xd3,0x92},
++ {0xd4,0x06},
++ {0xd5,0xe0},
++
++ {0xfc,0x0b},
++ {0xda,0x00},
++ {0xdb,0x9c},
++ {0xdc,0x00},
++ {0xdd,0xd1},
++ {0xfc,0x00},
++ {0x81,0x10},
++ {0xfc,0x1b},
++ {0x80,0x01},
++
++ //
++ {0xfc,0x00},
++ {0x03,0x4b},
++ {0xfc,0x06},
++ {0x01,0x35},
++ {0x03,0xc2},
++ {0x05,0x48},
++ {0x07,0xb8},
++ {0x31,0x2a},
++ {0x33,0x61},
++ {0x35,0x28},
++ {0x37,0x5c},
++ //==========================================================
++ // AE Window
++ //==========================================================
++ //ave
++ {0xfc,0x20},
++ {0x60,0x11},
++ {0x61,0x11},
++ {0x62,0x11},
++ {0x63,0x11},
++ {0x64,0x11},
++ {0x65,0x11},
++ {0x66,0x11},
++ {0x67,0x11},
++ {0x68,0x11},
++ {0x69,0x11},
++ {0x6a,0x11},
++ {0x6b,0x11},
++ {0x6c,0x11},
++ {0x6d,0x11},
++ {0x6e,0x11},
++ {0x6f,0x11},
++ {0x70,0x11},
++ {0x71,0x11},
++ {0x72,0x11},
++ {0x73,0x11},
++ {0x74,0x11},
++ {0x75,0x11},
++ {0x76,0x11},
++ {0x77,0x11},
++
++ //==========================================================
++ // SAIT AWB
++ //==========================================================
++ // White Point For Hue Control MWB
++ {0xfc,0x22},
++ {0x01,0xcf},
++ {0x03,0x86},
++ {0x05,0xbc},
++ {0x07,0xb2},
++ {0x09,0xae},
++ {0x0b,0xd5},
++ {0x0d,0x95},
++ {0x0f,0xf4},
++ {0x10,0x00},
++ {0x11,0x79},
++ {0x12,0x00},
++ {0x13,0xfd},
++ {0x15,0x7f},
++ {0x16,0x00},
++ {0x17,0xff},
++
++
++ // Basic Setting
++ {0xfc,0x22}, //AWB Basic
++ {0xA0,0x01},
++ {0xA1,0x3F},
++ {0xA2,0x0E},
++ {0xA3,0x8A},
++ {0xA4,0x07},
++ {0xA5,0xF6},
++ {0xA6,0x11},
++ {0xA7,0x9A},
++ {0xA9,0x02},
++ {0xAA,0xA8},
++ {0xAB,0x7F},
++ {0xAC,0xE8},
++ {0xAD,0x02},
++ {0xAE,0xA1},
++ {0xAF,0x4F},
++ {0xB0,0xCF},
++ {0xBD,0x80},
++ {0x94,0x37},
++ {0x95,0xCC},
++ {0x96,0x62},
++ {0x97,0x3A},
++ {0xD0,0xA0},
++ {0xD1,0x25},
++ {0xD2,0x42},
++ {0xD3,0x20},
++ {0xD4,0xa0}, //Low Temp ÀÎ½Ä ±âÁØ
++ {0xDB,0x25},
++ {0xDC,0x78},
++ {0xDD,0x20},
++ {0xe7,0x00}, //Low Temp AWB
++ {0xe8,0xbb},
++ {0xe9,0x00},
++ {0xea,0x72},
++ {0xeb,0x03},
++ {0xec,0x84},
++ {0xEE,0x98},
++
++ {0xfc,0x00},
++ {0x8a,0x08},
++ {0x8b,0x03},
++
++
++ // Pixel Filter Setting
++ {0xfc,0x07},
++ {0x95,0xcf},
++ {0xfc,0x01},
++ {0xd3,0x4e},
++ {0xd4,0x80},
++ {0xd5,0x3e},
++ {0xd6,0x00},
++ {0xd7,0x5d},
++ {0xd8,0x80},
++ {0xd9,0x4d},
++ {0xda,0x00},
++ {0xdb,0x1d},
++ {0xdc,0xa8},
++ {0xdd,0x26},
++ {0xde,0x95},
++ {0xdf,0x21},
++ {0xe0,0xb1},
++ {0xe1,0x1c},
++ {0xe2,0x1a},
++ {0xe3,0x40},
++ {0xe4,0x40},
++ {0xe5,0x40},
++ {0xe6,0x40},
++ {0xe7,0x1f},
++ {0xe8,0x39},
++ {0xe9,0x36},
++ {0xea,0x23},
++ {0xeb,0x00},
++
++ // Polygon AWB Region Tune
++ {0xfc,0x22},
++ {0x18,0x00},
++ {0x19,0x59},
++ {0x1a,0xe9},
++ {0x1b,0x00},
++ {0x1c,0x5b},
++ {0x1d,0xcb},
++ {0x1e,0x00},
++ {0x1f,0x7e},
++ {0x20,0xa0},
++ {0x21,0x00},
++ {0x22,0x91},
++ {0x23,0x88},
++ {0x24,0x00},
++ {0x25,0xa3},
++ {0x26,0x74},
++ {0x27,0x00},
++ {0x28,0xb9},
++ {0x29,0x60},
++ {0x2a,0x00},
++ {0x2b,0xd3},
++ {0x2c,0x5a},
++ {0x2d,0x00},
++ {0x2e,0xd5},
++ {0x2f,0x74},
++ {0x30,0x00},
++ {0x31,0xbc},
++ {0x32,0x7d},
++ {0x33,0x00},
++ {0x34,0xad},
++ {0x35,0x89},
++ {0x36,0x00},
++ {0x37,0x9a},
++ {0x38,0xa6},
++ {0x39,0x00},
++ {0x3a,0x75},
++ {0x3b,0xde},
++ {0x3c,0x00},
++ {0x3d,0x00},
++ {0x3e,0x00},
++ {0x3f,0x00},
++ {0x40,0x00},
++ {0x41,0x00},
++ {0x42,0x00},
++ {0x43,0x00},
++ {0x44,0x00},
++ {0x45,0x00},
++ {0x46,0x00},
++ {0x47,0x00},
++ {0x48,0x00},
++ {0x49,0x00},
++ {0x4a,0x00},
++ {0x4b,0x00},
++ {0x4c,0x00},
++ {0x4d,0x00},
++ {0x4e,0x00},
++ {0x4f,0x00},
++ {0x50,0x00},
++ {0x51,0x00},
++ {0x52,0x00},
++ {0x53,0x00},
++ {0x54,0x00},
++ {0x55,0x00},
++ {0x56,0x00},
++
++ // Moving Equation Weight
++ {0xfc,0x22},
++ {0x98,0x07},
++
++ //EIT Threshold
++ {0xfc,0x22},
++ {0xb1,0x00},
++ {0xb2,0x02},
++ {0xb3,0x00},
++ {0xb4,0xc1},
++ {0xb5,0x00},
++ {0xb6,0x02},
++ {0xb7,0x00},
++ {0xb9,0xc2},
++ {0xd7,0x00},
++ {0xd8,0x35},
++ {0xd9,0x20},
++ {0xda,0x81},
++
++ //==========================================================
++ // R, B Offset
++ //==========================================================
++ {0xfc,0x00},
++ {0x79,0xf2}, //0xf1//0xf5//0xf6 Global R Offset
++ {0x7a,0x1c}, //0x09//0x05//0x08 Global B Offset
++ {0xde,0x00},
++ {0xf0,0x6a},
++ {0xfc,0x22}, // Offset
++ {0x58,0xf9},
++ {0x59,0xf7},
++ {0x5a,0x05},
++ {0x5b,0xf5},
++ {0x5c,0x0a},//0c
++ {0x5d,0xfb},
++ {0x5e,0x0a},//0c
++ {0x5f,0xfe},
++ {0x60,0x0a},
++ {0x61,0x06},
++ {0x62,0x0a},
++ {0x63,0x06},
++
++ // Green Stablity Enhance
++ {0xfc,0x22},
++ {0xb9,0x00},
++ {0xba,0x00},
++ {0xbb,0x00},
++ {0xbc,0x00},
++ {0xe5,0x01},
++ {0xe6,0xff},
++ // AWB2_OPTION : BD_OUTDOORCLASY
++ {0xbd,0x80}, //0x8c
++ {0x70,0xf0},
++
++ //==========================================================
++ // Special function sephia B/W etc
++ //==========================================================
++ {0xfc,0x07},
++ {0x30,0xc0},
++ {0x31,0x20},
++ {0x32,0x40},
++ {0x33,0xc0},
++ {0x34,0x00},
++ {0x35,0xb0},
++
++
++ //==========================================================
++ // EE Wide LUMA
++ //==========================================================
++ {0xfc,0x1d},
++ {0x86,0x02},
++ {0x87,0xc0},
++ {0x88,0x03},
++ {0x89,0xc0},
++ {0x8a,0x02},
++ {0x8b,0x00},
++ {0x8c,0x00},
++ {0x8d,0x00},
++ {0x8e,0x00},
++ {0x8f,0xd0},
++ {0x90,0x00},
++ {0x91,0x00},
++ {0x92,0x02},
++ {0x93,0x00},
++ {0x94,0x00},
++ {0x95,0x00},
++ {0x96,0x00},
++ {0x97,0xd0},
++ {0x98,0x00},
++ {0x99,0x00},
++ {0x9a,0x02},
++ {0x9b,0x60},
++ {0x9c,0x00},
++ {0x9d,0x00},
++ {0x9e,0x02},
++ {0x9f,0x60},
++ {0xa0,0x00},
++ {0xa1,0x00},
++ {0xa2,0x09},
++ {0x85,0x01},
++
++ //==========================================================
++ // Color Correction Coefficient
++ //==========================================================
++ {0xfc,0x0b},
++ {0x60,0x08},
++ {0x61,0x9b},
++ {0x62,0xfc},
++ {0x63,0x07},
++ {0x64,0xff},
++ {0x65,0x5e},
++ {0x66,0xfd},
++ {0x67,0x0e},
++ {0x68,0x07},
++ {0x69,0xee},
++ {0x6a,0xff},
++ {0x6b,0x05},
++ {0x6c,0xff},
++ {0x6d,0x7a},
++ {0x6e,0xfc},
++ {0x6f,0x23},
++ {0x70,0x08},
++ {0x71,0x64},
++ {0x72,0x04},
++ {0x73,0xfd},
++ {0x74,0xfd},
++ {0x75,0xea},
++ {0x76,0x01},
++ {0x77,0x19},
++ {0x78,0xfd},
++ {0x79,0xbf},
++ {0x7a,0x05},
++ {0x7b,0x16},
++ {0x7c,0x01},
++ {0x7d,0x2b},
++ {0x7e,0xff},
++ {0x7f,0xbf},
++ {0x80,0xf8},
++ {0x81,0x8e},
++ {0x82,0x0b},
++ {0x83,0xb3},
++ {0x84,0x04},
++ {0x85,0xfd},
++ {0x86,0xfd},
++ {0x87,0xea},
++ {0x88,0x01},
++ {0x89,0x19},
++ {0x8a,0xfd},
++ {0x8b,0xbf},
++ {0x8c,0x05},
++ {0x8d,0x16},
++ {0x8e,0x01},
++ {0x8f,0x2b},
++ {0x90,0xff},
++ {0x91,0xbf},
++ {0x92,0xf8},
++ {0x93,0x8e},
++ {0x94,0x0b},
++ {0x95,0xb3},
++
++
++ ///////////////////////////////////////////////////
++ // Stable Range For Cintr
++ ///////////////////////////////////////////////////
++ {0xfc,0x20},
++ {0x52,0x10},
++ {0x53,0x10},
++
++ ///////////////////////////////////////////////////
++ // Mirror Option
++ ///////////////////////////////////////////////////
++ {0xfc,0x20},
++ {0x0f,0x01}, // Weight Mirrored 63 to 0
++ {0xfc,0x00},
++ {0x75,0x05},
++#endif
++ {REG_TERM, VAL_TERM}
++};
++
++
++static struct sensor_reg sensor_preview[] = {
++ //===================================
++ // CAMERA PREVIEW(800*600)
++ //===================================
++ {0xfc,0x02},
++ {0x2d,0x48}, //double shutter width control.double shutter enable
++ {0x44,0x63}, //Reserved
++ {0xfc,0x03},
++ {0x02,0x04}, //CIS_FRAME_V_DEPTH_H
++ {0xfc,0x20},
++ {0x14,0x70}, //80 //BRIGHT_OFFSET,
++ {0xfc,0x00},
++ {0x03,0x4b}, // AE/AWB On
++ {0x7e,0x74}, // Suppress On
++ {0x89,0x03}, // Edge Suppress On
++ {0xfc,0x20},
++ {0x16,0x5a}, //50 // Frame AE Start
++ {0xfc,0x02},
++ {0x30,0x82}, // Analog offset
++ {0x37,0x11}, //0d // Global Gain
++ {0x60,0x00}, // Blank_Adrs
++ {0x45,0x0e}, // CDS Timing for Average Sub_Sampling
++ {0x47,0x2f}, // Reserved
++ {0xfc,0x00},
++ {0x02,0x09}, // 800 x 600 Recovery
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_capture[] = {
++ //===================================
++ // 1600*1200 SNAPSHOT
++ //===================================
++ {0xfc, 0x00},
++ {0x03, 0x48},
++ {0xfc, 0x02},
++ {0x30, 0x90},
++ {0x37, 0x20},
++ {0x60, 0x01},
++ {0x45, 0xff},
++ {0x47, 0x0f},
++ {0xfc, 0x00},
++ {0x02, 0x00},
++// {0xfc, 0x00},
++// {0x75, 0x05}, //H.V mirror
++ {REG_TERM, VAL_TERM}
++};
++
++ struct sensor_reg* sensor_reg_common[3] =
++{
++ sensor_common,
++ sensor_preview,
++ sensor_capture
++};
++
++static struct sensor_reg sensor_brightness_0[] = {
++ {0xfc,0x00},
++ {0x29,0x02},
++ {0x2a,0xa0},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_1[] = {
++ {0xfc,0x00},
++ {0x29,0x03},
++ {0x2a,0xa0},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_2[] = {
++ {0xfc,0x00},
++ {0x29,0x04},
++ {0x2a,0xa0},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_3[] = {
++ {0xfc,0x00},
++ {0x29,0x05},
++ {0x2a,0xa0},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_brightness_4[] = {
++ {0xfc,0x00},
++ {0x29,0x03},
++ {0x2a,0xa0},
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_brightness[5] =
++{
++ sensor_brightness_0,
++ sensor_brightness_1,
++ sensor_brightness_2,
++ sensor_brightness_3,
++ sensor_brightness_4
++};
++
++
++static struct sensor_reg sensor_awb_auto[] = {
++ //===================================
++ // CameraWB_Auto
++ //===================================
++ {0xfc,0x00},
++ {0x04,0x00},
++ {0x05,0x00},
++
++ {0xfc,0x22},
++ {0x05,0xca}, // CRWB
++ {0x07,0xc8}, // CBWB
++
++ {0xfc,0x00},
++ {0x30,0x00},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_daylight[] = {
++ //===================================
++ // CameraWB_Daylight
++ //===================================
++
++ {0xfc,0x00},
++ {0x04,0x00},
++ {0x05,0x00},
++
++ {0xfc,0x22},
++ {0x05,0xd0}, // CRWB
++ {0x07,0x98}, // CBWB
++
++ {0xfc,0x00},
++ {0x30,0x02},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_incandescent[] = {
++//==========================================================
++// CAMERA_WB_Tungsten
++//==========================================================
++
++ {0xfc,0x00},
++ {0x04,0x00},
++ {0x05,0x00},
++ {0xfc,0x22},
++ {0x05,0xa0}, //9d // CRWB
++ {0x07,0xdc}, //e0//f5// CBWB
++ {0xfc,0x00},
++ {0x30,0x02},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_fluorescent[] = {
++ //===================================
++ // CameraWB_fluorescent
++ //===================================
++
++ {0xfc,0x00},
++ {0x04,0x00},
++ {0x05,0x00},
++
++ {0xfc,0x22},
++ {0x05,0xb0}, // CRWB
++ {0x07,0xbf}, // CBWB
++
++ {0xfc,0x00},
++ {0x30,0x02},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_cloudy[] = {
++ //===================================
++ // CameraWB_Cloudy
++ //===================================
++ {0xfc,0x00},
++ {0x04,0x00},
++ {0x05,0x00},
++
++ {0xfc,0x22},
++ {0x05,0xe8}, // CRWB
++ {0x07,0x90}, // CBWB
++
++ {0xfc,0x00},
++ {0x30,0x05},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_awb_sunset[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_awb[6] =
++{
++ sensor_awb_auto,
++ sensor_awb_daylight,
++ sensor_awb_incandescent,
++ sensor_awb_fluorescent,
++ sensor_awb_cloudy,
++ sensor_awb_sunset
++
++};
++
++
++static struct sensor_reg sensor_iso_auto[] = {
++ //===================================
++ // CameraIso_Auto
++ //===================================
++
++ {0xfc,0x00},
++ {0x6c,0xa0},
++ {0x6d,0x00},
++ {0x78,0x6a},
++
++ {0xfc,0x01},
++ {0x2b,0x02}, // Gr_H
++ {0x2c,0x90}, // Gr_L
++ {0x2d,0x02}, // Gb_H
++ {0x2e,0x90}, // Gb_L
++ {0x2f,0x02}, // R_H
++ {0x30,0x90}, // R_L
++ {0x31,0x02}, // B_H
++ {0x32,0x90}, // B_L
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_100[] = {
++ //===================================
++ // CameraIso_100
++ //===================================
++
++ {0xfc,0x00},
++ {0x6c,0x98},
++ {0x6d,0x00},
++ {0x78,0x6b},
++
++ {0xfc,0x01},
++ {0x2b,0x02}, // Gr_H
++ {0x2c,0xc0}, // Gr_L
++ {0x2d,0x02}, // Gb_H
++ {0x2e,0xc0}, // Gb_L
++ {0x2f,0x02}, // R_H
++ {0x30,0xc0}, // R_L
++ {0x31,0x02}, // B_H
++ {0x32,0xc0}, // B_L
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_200[] = {
++ //===================================
++ // CameraIso_200
++ //===================================
++ {0xfc,0x00},
++ {0x6c,0xd0},
++ {0x6d,0x00},
++ {0x78,0x70},
++
++ {0xfc,0x01},
++ {0x2b,0x03}, // Gr_H
++ {0x2c,0x80}, // Gr_L
++ {0x2d,0x03}, // Gb_H
++ {0x2e,0x80}, // Gb_L
++ {0x2f,0x03}, // R_H
++ {0x30,0x80}, // R_L
++ {0x31,0x03}, // B_H
++ {0x32,0x80}, // B_L
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_iso_400[] = {
++ //===================================
++ // CameraIso_400
++ //===================================
++
++ {0xfc,0x00},
++ {0x6c,0x40},
++ {0x6d,0x01},
++ {0x78,0x6d},
++
++ {0xfc,0x01},
++ {0x2b,0x04}, // Gr_H
++ {0x2c,0x00}, // Gr_L
++ {0x2d,0x04}, // Gb_H
++ {0x2e,0x00}, // Gb_L
++ {0x2f,0x04}, // R_H
++ {0x30,0x00}, // R_L
++ {0x31,0x04}, // B_H
++ {0x32,0x00}, // B_L
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_iso[4] =
++{
++ sensor_iso_auto,
++ sensor_iso_100,
++ sensor_iso_200,
++ sensor_iso_400
++};
++
++
++static struct sensor_reg sensor_effect_normal[] = {
++
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_gray[] = {
++
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_negative[] = {
++
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sepia[] = {
++
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sharpness[] = {
++
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_effect_sketch[] = {
++
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_effect[6] =
++{
++ sensor_effect_normal,
++ sensor_effect_gray,
++ sensor_effect_negative,
++ sensor_effect_sepia,
++ sensor_effect_sharpness,
++ sensor_effect_sketch,
++};
++
++static struct sensor_reg sensor_reg_flipnone[] = {
++ //===================================
++ // CAMERA_FLIP_NONE (1/4)
++ //===================================
++ {0xfc,0x20},
++ {0x0f,0x00}, // Weight Mirrored (0 - 63)
++ {0xfc,0x00},
++ {0x75,0x04},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_hflip[] = {
++ //===================================
++ // CAMERA_FLIP_MIRROR_ONLY (2/4)
++ //===================================
++ {0xfc,0x20},
++ {0x0f,0x00}, // Weight Mirrored (0 - 63)
++ {0xfc,0x00},
++ {0x75,0x06},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_vflip[] = {
++ //===================================
++ // CAMERA_FLIP_WATER_ONLY (3/4)
++ //===================================
++ {0xfc,0x20},
++ {0x0f,0x01}, // Weight Mirrored (63 - 0)
++ {0xfc,0x00},
++ {0x75,0x07},
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_reg_hvflip[] = {
++ //===================================
++ // CAMERA_FLIP_WATER_MIRROR (4/4)
++ //===================================
++ {0xfc,0x20},
++ {0x0f,0x01}, // Weight Mirrored (63 - 0)
++ {0xfc,0x00},
++ {0x75,0x05},
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_flip[4] =
++{
++ sensor_reg_flipnone,
++ sensor_reg_hflip,
++ sensor_reg_vflip,
++ sensor_reg_hvflip,
++};
++
++
++static struct sensor_reg sensor_secne_auto[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_night[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_landscape[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_portrait[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_secne_sport[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_scene[5] =
++{
++ sensor_secne_auto,
++ sensor_secne_night,
++ sensor_secne_landscape,
++ sensor_secne_portrait,
++ sensor_secne_sport
++};
++
++static struct sensor_reg sensor_me_mtrix[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_me_center_weighted[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_me_spot[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_metering_exposure[3] =
++{
++ sensor_me_mtrix,
++ sensor_me_center_weighted,
++ sensor_me_spot,
++};
++
++static struct sensor_reg sensor_af_single[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++static struct sensor_reg sensor_af_manual[] = {
++ {REG_TERM, VAL_TERM}
++};
++
++struct sensor_reg* sensor_reg_af[2] =
++{
++ sensor_af_single,
++ sensor_af_manual,
++};
++
++#endif
++
+diff --git a/drivers/media/video/tcccam/s5k4bafb_2mp.h b/drivers/media/video/tcccam/s5k4bafb_2mp.h
+new file mode 100644
+index 0000000..a979aa8
+--- /dev/null
++++ b/drivers/media/video/tcccam/s5k4bafb_2mp.h
+@@ -0,0 +1,63 @@
++/*
++ * drivers/media/video/tcccam/s5k4bafb_2mp.h
++ *
++ * Register definitions for the s5k4bafb CameraChip.
++ *
++ * Author: zzau (zzau@telechips.com)
++ *
++ * Copyright (C) 2008 Telechips, 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.
++ */
++
++#ifndef S5K4BAFB_H
++#define S5K4BAFB_H
++
++/* The S5K4BAFB I2C sensor chip has a fixed slave address of 0x5D. */
++#define SENSOR_I2C_ADDR 0x52
++
++#define REG_TERM 0xFF /* terminating list entry for reg */
++#define VAL_TERM 0xFF /* terminating list entry for val */
++
++
++// ZOOM Setting!!
++#define PRV_W 800
++#define PRV_H 600
++#define PRV_ZOFFX 8
++#define PRV_ZOFFY 6
++
++#define CAP_W 1600
++#define CAP_H 1200
++#define CAP_ZOFFX 16
++#define CAP_ZOFFY 12
++
++#define CAM_2XMAX_ZOOM_STEP 25
++#define CAM_CAPCHG_WIDTH 800
++
++
++struct sensor_reg {
++ unsigned char reg;
++ unsigned char val[1];
++};
++
++struct capture_size {
++ unsigned long width;
++ unsigned long height;
++};
++
++extern struct capture_size sensor_sizes[];
++
++extern struct sensor_reg* sensor_reg_common[];
++extern struct sensor_reg* sensor_reg_brightness[];
++extern struct sensor_reg* sensor_reg_awb[];
++extern struct sensor_reg* sensor_reg_iso[];
++extern struct sensor_reg* sensor_reg_effect[];
++extern struct sensor_reg* sensor_reg_flip[];
++extern struct sensor_reg* sensor_reg_scene[];
++extern struct sensor_reg* sensor_reg_metering_exposure[];
++extern struct sensor_reg* sensor_reg_af[];
++
++#endif /* S5K4BAFB_H */
++
+diff --git a/drivers/media/video/tcccam/sensor_if.c b/drivers/media/video/tcccam/sensor_if.c
+new file mode 100644
+index 0000000..d235ef0
+--- /dev/null
++++ b/drivers/media/video/tcccam/sensor_if.c
+@@ -0,0 +1,831 @@
++
++/*
++ * drivers/media/video/tcccam/sensor_if.c
++ *
++ * COMMON Sensor driver for camera sensor interface
++ *
++ *
++ *
++ * 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 <linux/errno.h>
++#include <linux/i2c.h>
++#include <linux/videodev.h>
++#include <linux/videodev2.h>
++//#include <media/video-buf.h>
++#include <linux/delay.h>
++#include <asm/mach-types.h>
++
++#include <asm/io.h>
++
++#include <bsp.h>
++#include "tcc_cam_i2c.h"
++
++#include "sensor_if.h"
++#include "tdd_cif.h"
++#include "cam.h"
++
++#ifdef USING_HW_I2C
++#include <linux/i2c.h>
++#endif
++
++#ifdef USING_HW_I2C
++static int enabled = 0;
++#define SENSOR_DEVICE_I2C (SENSOR_I2C_ADDR>>1)
++static unsigned short probe[] = { 0, SENSOR_DEVICE_I2C, I2C_CLIENT_END };
++static unsigned short dummy[] = {I2C_CLIENT_END};
++
++static struct i2c_client_address_data addr_data = {
++ .normal_i2c = dummy,
++ .probe = probe,
++ .ignore = dummy,
++};
++
++static struct i2c_driver cam_i2c_driver;
++static struct i2c_client *cam_i2c_client = NULL;
++
++#if 0
++static void TOUCH_SEND_CMD(unsigned char reg, unsigned char val)
++{
++ unsigned char cmd[1];
++ cmd[0] = val;
++ i2c_master_send(cam_i2c_client, cmd, 1);
++}
++
++static void TOUCH_READ_DAT(unsigned char reg, unsigned int val)
++{
++ unsigned char *buf;
++ buf = (unsigned char *)val;
++ i2c_master_recv(cam_i2c_client, buf, 2);
++}
++#endif
++
++static int cam_i2c_probe(struct i2c_adapter *adap, int addr, int kind)
++{
++ struct i2c_client *i2c;
++ int ret;
++
++ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
++ if (!i2c)
++ return -ENOMEM;
++
++ strcpy(i2c->name, "CAM_SENSOR");
++ i2c->flags = 0;
++ i2c->addr = addr;
++ i2c->adapter = adap;
++ i2c->driver = &cam_i2c_driver;
++
++ cam_i2c_client = i2c;
++
++ /* attach i2c client device */
++ ret = i2c_attach_client(i2c);
++ if (ret < 0) {
++ printk("%s: failed to attach codec at addr %x\n", __func__, addr);
++ goto err;
++ }
++
++ return ret;
++err:
++ kfree(i2c);
++ return ret;
++}
++
++static int cam_i2c_detach(struct i2c_client *client)
++{
++ i2c_detach_client(client);
++
++ if(cam_i2c_client)
++ {
++ kfree(cam_i2c_client);
++ cam_i2c_client = NULL;
++ }
++ return 0;
++}
++
++static int cam_i2c_attach(struct i2c_adapter *adap)
++{
++ return i2c_probe(adap, &addr_data, cam_i2c_probe);
++}
++
++/* tsc2003 i2c codec control layer */
++static struct i2c_driver cam_i2c_driver = {
++ .driver = {
++ .name = "tcc-cam-sensor",
++ .owner = THIS_MODULE,
++ },
++ .id = I2C_DRIVERID_SENSOR,
++ .attach_adapter = cam_i2c_attach,
++ .detach_client = cam_i2c_detach,
++ .command = NULL,
++};
++#endif
++
++/* list of image formats supported by sensor sensor */
++const static struct v4l2_fmtdesc sensor_formats[] = {
++ {
++ /* Note: V4L2 defines RGB565 as:
++ *
++ * Byte 0 Byte 1
++ * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
++ *
++ * We interpret RGB565 as:
++ *
++ * Byte 0 Byte 1
++ * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
++ */
++ .description = "RGB565, le",
++ .pixelformat = V4L2_PIX_FMT_RGB565,
++ },{
++ /* Note: V4L2 defines RGB565X as:
++ *
++ * Byte 0 Byte 1
++ * b4 b3 b2 b1 b0 g5 g4 g3 g2 g1 g0 r4 r3 r2 r1 r0
++ *
++ * We interpret RGB565X as:
++ *
++ * Byte 0 Byte 1
++ * r4 r3 r2 r1 r0 g5 g4 g3 g2 g1 g0 b4 b3 b2 b1 b0
++ */
++ .description = "RGB565, be",
++ .pixelformat = V4L2_PIX_FMT_RGB565X,
++ },
++ {
++ .description = "YUYV (YUV 4:2:2), packed",
++ .pixelformat = V4L2_PIX_FMT_YUYV,
++ },{
++ .description = "UYVY, packed",
++ .pixelformat = V4L2_PIX_FMT_UYVY,
++ },
++ {
++ /* Note: V4L2 defines RGB555 as:
++ *
++ * Byte 0 Byte 1
++ * g2 g1 g0 r4 r3 r2 r1 r0 x b4 b3 b2 b1 b0 g4 g3
++ *
++ * We interpret RGB555 as:
++ *
++ * Byte 0 Byte 1
++ * g2 g1 g0 b4 b3 b2 b1 b0 x r4 r3 r2 r1 r0 g4 g3
++ */
++ .description = "RGB555, le",
++ .pixelformat = V4L2_PIX_FMT_RGB555,
++ },{
++ /* Note: V4L2 defines RGB555X as:
++ *
++ * Byte 0 Byte 1
++ * x b4 b3 b2 b1 b0 g4 g3 g2 g1 g0 r4 r3 r2 r1 r0
++ *
++ * We interpret RGB555X as:
++ *
++ * Byte 0 Byte 1
++ * x r4 r3 r2 r1 r0 g4 g3 g2 g1 g0 b4 b3 b2 b1 b0
++ */
++ .description = "RGB555, be",
++ .pixelformat = V4L2_PIX_FMT_RGB555X,
++ }
++};
++
++#define NUM_CAPTURE_FORMATS ARRAY_SIZE(sensor_formats)
++
++#if defined(SENSOR_2M)
++enum image_size { UXGA, SXGA, XGA, SVGA, VGA, QVGA, QCIF};
++#define NUM_IMAGE_SIZES 7
++#elif defined(SENSOR_3M)
++enum image_size { QXGA, UXGA, SXGA, XGA, SVGA, VGA, QVGA, QCIF};
++#define NUM_IMAGE_SIZES 8
++#elif defined(SENSOR_5M)
++enum image_size { QQXGA, QXGA, UXGA, SXGA, XGA, SVGA, VGA, QVGA, QCIF};
++#define NUM_IMAGE_SIZES 9
++#endif
++
++enum pixel_format { YUV, RGB565, RGB555 };
++#define NUM_PIXEL_FORMATS 3
++
++
++//need to revised MCC
++#ifdef CONFIG_ARCH_OMAP24XX
++#define NUM_OVERLAY_FORMATS 4
++#else
++#define NUM_OVERLAY_FORMATS 2
++#endif
++
++
++#define DEF_BRIGHTNESS 3
++#define DEF_ISO 0
++#define DEF_AWB 0
++#define DEF_EFFECT 0
++#define DEF_ZOOM 0
++#define DEF_FLIP 0
++#define DEF_SCENE 0
++#define DEF_METERING_EXPOSURE 0
++#define DEF_FLASH 0
++
++
++/* Our own specific controls */
++#define V4L2_CID_ISO V4L2_CID_PRIVATE_BASE+0
++#define V4L2_CID_EFFECT V4L2_CID_PRIVATE_BASE+1
++#define V4L2_CID_ZOOM V4L2_CID_PRIVATE_BASE+2
++#define V4L2_CID_FLIP V4L2_CID_PRIVATE_BASE+3
++#define V4L2_CID_SCENE V4L2_CID_PRIVATE_BASE+4
++#define V4L2_CID_METERING_EXPOSURE V4L2_CID_PRIVATE_BASE+5
++#define V4L2_CID_FLASH V4L2_CID_PRIVATE_BASE+6
++
++#define V4L2_CID_LAST_PRIV V4L2_CID_FLASH
++
++
++/* Video controls */
++static struct vcontrol {
++ struct v4l2_queryctrl qc;
++ int current_value;
++} control[] = {
++ { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, "Brightness", 0, 4, 1,
++ DEF_BRIGHTNESS },
++ 0},
++
++ { { V4L2_CID_AUTO_WHITE_BALANCE, V4L2_CTRL_TYPE_INTEGER, "Auto White Balance", 0,5,1,
++ DEF_AWB },
++ 0},
++
++ { { V4L2_CID_ISO, V4L2_CTRL_TYPE_INTEGER, "Iso", 0, 3, 1,
++ DEF_ISO },
++ 0},
++
++ { { V4L2_CID_EFFECT, V4L2_CTRL_TYPE_INTEGER, "Special Effect", 0, 6, 1,
++ DEF_EFFECT },
++ 0},
++
++ { { V4L2_CID_ZOOM, V4L2_CTRL_TYPE_INTEGER, "Zoom", 0, 25, 1,
++ DEF_ZOOM },
++ 0},
++
++ { { V4L2_CID_FLIP, V4L2_CTRL_TYPE_INTEGER, "Flip", 0, 3, 1,
++ DEF_FLIP },
++ 0},
++
++ { { V4L2_CID_SCENE, V4L2_CTRL_TYPE_INTEGER, "Scene", 0, 5, 1,
++ DEF_SCENE},
++ 0},
++
++ { { V4L2_CID_METERING_EXPOSURE, V4L2_CTRL_TYPE_INTEGER, "Metering Exposure", 0, 3, 1,
++ DEF_METERING_EXPOSURE},
++ 0},
++
++ { { V4L2_CID_FLASH, V4L2_CTRL_TYPE_INTEGER, "Flash", 0, 4, 1,
++ DEF_FLASH},
++ 0},
++};
++
++
++unsigned int sensor_control[] =
++{
++ V4L2_CID_BRIGHTNESS,
++ V4L2_CID_AUTO_WHITE_BALANCE,
++ V4L2_CID_ISO,
++ //V4L2_CID_EFFECT,
++ //V4L2_CID_ZOOM,
++ V4L2_CID_FLIP,
++ V4L2_CID_SCENE,
++ V4L2_CID_METERING_EXPOSURE,
++ //V4L2_CID_FLASH
++};
++
++
++extern u8 current_effect_mode;
++extern int tccxxx_cif_set_effect (u8 nCameraEffect);
++extern int tccxxx_cif_set_zoom(unsigned char arg);
++extern int CAMERA_SEND_CMD(unsigned char hb, unsigned short lb);
++
++#ifdef USING_HW_I2C
++int sensor_write(ushort reg, ushort *val)
++{
++ unsigned char data[25];
++ unsigned char bytes;
++
++#if defined(CONFIG_VIDEO_CAMERA_SENSOR_MT9P111)
++ unsigned int cnt;
++
++ if(reg == REG_TERM && val[1] == VAL_END)
++ {
++ mdelay(val[0]);
++ printk("Sensor init Delay[%d]!!!! \n", val[0]);
++ return 0;
++ }
++
++ data[0]= reg>>8;
++ data[1]= (u8)reg&0xff;
++
++ for( cnt = 0; cnt<25 ; cnt++)
++ {
++ if(val[cnt] == VAL_END)
++ break;
++
++ data[(cnt+1)*2] = val[cnt] >> 8;
++ data[(cnt+1)*2+1] = (char)val[cnt] & 0xff;
++ }
++
++ bytes = cnt*2 + 2;
++ //printk("write[0x%x, 0x%x (cnt:%d)]!!!! \n", reg, val[0], bytes);
++
++#elif defined(CONFIG_VIDEO_CAMERA_SENSOR_MT9D112)
++
++ if (reg == CAMDLY)
++ {
++ mdelay(val[0]);
++ return 0;
++ }
++
++ data[0]= reg>>8;
++ data[1]= (u8)reg&0xff;
++ data[2]= val[0]>>8;
++ data[3]=(u8)val[0]&0xff;
++ bytes = 4;
++#elif defined(CONFIG_VIDEO_CAMERA_SENSOR_MT9D111)
++ data[0]= (u8)reg&0xff;
++ data[1]= val[0]>>8;
++ data[2]=(u8)val[0]&0xff;
++ bytes = 3;
++#else
++ data[0]= (u8)reg&0xff;
++ data[1]=(u8)val[0]&0xff;
++ bytes = 2;
++#endif
++
++ if (i2c_master_send(cam_i2c_client, data, bytes) == bytes)
++ {
++ mdelay(1);
++ return 0;
++ }
++ else
++ {
++ printk("write error!!!! \n");
++ return -EIO;
++ }
++}
++
++inline int sensor_read(u8 reg)
++{
++ int val;
++
++
++ return val;
++}
++#endif
++
++int sensor_write_regs(const struct sensor_reg reglist[])
++{
++ int err;
++ int err_cnt = 0;
++ int total_cnt = 0;
++ const struct sensor_reg *next = reglist;
++
++ while (!((next->reg == REG_TERM) && (next->val[0] == VAL_TERM)))
++ {
++#ifdef USING_HW_I2C
++ err = sensor_write(next->reg, next->val);
++ //udelay(100);
++ if (err)
++ {
++ printk("try write!!!! \n");
++ err_cnt++;
++ if(err_cnt >= 3)
++ {
++ printk("ERROR: Sensor I2C !!!! \n");
++ return err;
++ }
++ }
++ else
++ {
++ total_cnt++;
++ next++;
++ }
++#else
++ err= CAMERA_SEND_CMD(next->reg, next->val);
++ if(err)
++ {
++ total_cnt++;
++ err_cnt = 0;
++ next++;
++ }
++ else
++ {
++ printk("try write!!!! \n");
++ err_cnt++;
++ if(err_cnt >= 3)
++ {
++ printk("ERROR: Sensor I2C !!!! \n");
++ return err;
++ }
++ }
++#endif
++ }
++
++ printk("I2C %d write Success!!!! \n", total_cnt);
++
++ return 0;
++}
++
++int sensor_change_mode(unsigned char capture_mode)
++{
++ int ret=0;
++
++ if(capture_mode)
++ ret = sensor_write_regs(sensor_reg_common[2]);
++ else
++ {
++#if defined(CONFIG_VIDEO_CAMERA_SENSOR_MT9D112)
++ ret = sensor_write_regs(sensor_reg_common[0]);
++ mdelay(10);
++#endif
++ ret = sensor_write_regs(sensor_reg_common[1]);
++// mdelay(10);
++ }
++
++ return ret;
++}
++
++int sensor_adjust_autofocus(void)
++{
++ sensor_write_regs(sensor_reg_af[0]);
++}
++
++/* Returns the index of the requested ID from the control structure array */
++static int find_vctrl(int id)
++{
++ int i;
++ int ctrl_cnt = ARRAY_SIZE(control);
++
++ if (id < V4L2_CID_BASE)
++ return -EDOM;
++
++ for (i = ctrl_cnt - 1; i >= 0; i--)
++ {
++ if (control[i].qc.id == id)
++ break;
++ }
++
++ if (i < 0)
++ i = -EINVAL;
++
++ return i;
++}
++
++
++/* initialize Sensor after module was reset. */
++int sensor_init_module(enum image_size isize, enum pixel_format pfmt,unsigned long xclk)
++{
++ int err;
++
++ /* common register initialization */
++#if defined(CONFIG_VIDEO_CAMERA_SENSOR_MT9D112)
++#else
++ err = sensor_write_regs(sensor_reg_common[0]);
++ if (err)
++ return err;
++#endif
++
++ return 0;
++}
++
++
++/* Find the best match for a requested image capture size. The best match
++ * is chosen as the nearest match that has the same number or fewer pixels
++ * as the requested size, or the smallest image size if the requested size
++ * has fewer pixels than the smallest image.
++ */
++static enum image_size sensor_find_size(unsigned int width, unsigned int height)
++{
++ enum image_size isize;
++ unsigned long pixels = width*height;
++
++ for (isize = 0; isize < (NUM_IMAGE_SIZES-1); isize++) {
++ if (sensor_sizes[isize + 1].height*
++ sensor_sizes[isize + 1].width > pixels)
++ {
++ return isize;
++ }
++ }
++ return UXGA;
++}
++
++/* following are sensor interface functions implemented by
++ * sensor driver.
++ */
++int sensor_query_control(struct v4l2_queryctrl *qc)
++{
++ int i;
++
++ i = find_vctrl (qc->id);
++ if (i == -EINVAL)
++ {
++ qc->flags = V4L2_CTRL_FLAG_DISABLED;
++ return 0;
++ }
++
++ if (i < 0)
++ return -EINVAL;
++
++ *qc = control[i].qc;
++
++ return 0;
++}
++
++int sensor_get_control(struct v4l2_control *vc)
++{
++ int i;
++ struct vcontrol * lvc;
++
++ if((i = find_vctrl(vc->id)) < 0)
++ return -EINVAL;
++
++ lvc = &control[i];
++ vc->value = lvc->current_value;
++
++ return 0;
++}
++
++int sensor_set_control(struct v4l2_control *vc)
++{
++ struct vcontrol *lvc;
++ int val = vc->value;
++ int i;
++ int err;
++
++ if((i = find_vctrl(vc->id)) < 0)
++ return -EINVAL;
++
++ lvc = &control[i];
++
++ if(lvc->qc.maximum < val)
++ return val;
++
++ switch(vc->id)
++ {
++ case V4L2_CID_BRIGHTNESS:
++ err = sensor_write_regs(sensor_reg_brightness[val]);
++ break;
++
++ case V4L2_CID_AUTO_WHITE_BALANCE:
++ err = sensor_write_regs(sensor_reg_awb[val]);
++ break;
++
++ case V4L2_CID_ISO:
++ err = sensor_write_regs(sensor_reg_iso[val]);
++ break;
++
++ case V4L2_CID_EFFECT:
++ err = tccxxx_cif_set_effect(val);
++ //err = sensor_write_regs(sensor_reg_effect[val]);
++ break;
++
++ case V4L2_CID_ZOOM:
++ err = tccxxx_cif_set_zoom(val);
++ break;
++
++ case V4L2_CID_FLIP:
++ err = sensor_write_regs(sensor_reg_flip[val]);
++ break;
++
++ case V4L2_CID_SCENE:
++ err = sensor_write_regs(sensor_reg_scene[val]);
++ break;
++
++ case V4L2_CID_METERING_EXPOSURE:
++ err = sensor_write_regs(sensor_reg_metering_exposure[val]);
++ break;
++
++ case V4L2_CID_FLASH:
++ //err = ;
++ break;
++
++
++ default:
++ break;
++
++ }
++
++ lvc->current_value = val;
++
++ return 0;
++}
++
++
++/* In case of ESD-detection, to set current value in sensor after module was resetted. */
++int sensor_set_current_control(void)
++{
++ struct v4l2_control vc;
++ int i;
++ int ctrl_cnt = ARRAY_SIZE(sensor_control);
++
++ printk("Setting Sensor-ctrl!! %d /n", ctrl_cnt);
++
++ for (i = ctrl_cnt - 1; i >= 0; i--)
++ {
++ vc.id = sensor_control[i];
++ sensor_get_control(&vc);
++ sensor_set_control(&vc);
++ }
++
++ return 0;
++}
++
++/* Implement the VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
++ */
++int sensor_enum_pixformat(struct v4l2_fmtdesc *fmt)
++{
++ int index = fmt->index;
++ enum v4l2_buf_type type = fmt->type;
++
++ memset(fmt, 0, sizeof(*fmt));
++ fmt->index = index;
++ fmt->type = type;
++
++ switch (fmt->type) {
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++ if (index >= NUM_CAPTURE_FORMATS)
++ return -EINVAL;
++ break;
++
++ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
++ if (index >= NUM_OVERLAY_FORMATS)
++ return -EINVAL;
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ fmt->flags = sensor_formats[index].flags;
++ strlcpy(fmt->description, sensor_formats[index].description, sizeof(fmt->description));
++ fmt->pixelformat = sensor_formats[index].pixelformat;
++
++ return 0;
++}
++
++/* Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This
++ * ioctl is used to negotiate the image capture size and pixel format
++ * without actually making it take effect.
++ */
++static int sensor_try_format(struct v4l2_pix_format *pix)
++{
++ enum image_size isize;
++ int ifmt;
++
++ isize = sensor_find_size(pix->width, pix->height);
++ pix->width = sensor_sizes[isize].width;
++ pix->height = sensor_sizes[isize].height;
++
++ for (ifmt = 0; ifmt < NUM_CAPTURE_FORMATS; ifmt++)
++ {
++ if (pix->pixelformat == sensor_formats[ifmt].pixelformat)
++ break;
++ }
++
++ if (ifmt == NUM_CAPTURE_FORMATS)
++ ifmt = 0;
++
++ pix->pixelformat = sensor_formats[ifmt].pixelformat;
++ pix->field = V4L2_FIELD_NONE;
++ pix->bytesperline = pix->width*2;
++ pix->sizeimage = pix->bytesperline*pix->height;
++ pix->priv = 0;
++
++ switch (pix->pixelformat)
++ {
++ case V4L2_PIX_FMT_YUYV:
++ case V4L2_PIX_FMT_UYVY:
++ default:
++ pix->colorspace = V4L2_COLORSPACE_JPEG;
++ break;
++
++ case V4L2_PIX_FMT_RGB565:
++ case V4L2_PIX_FMT_RGB565X:
++ case V4L2_PIX_FMT_RGB555:
++ case V4L2_PIX_FMT_RGB555X:
++ pix->colorspace = V4L2_COLORSPACE_SRGB;
++ break;
++ }
++
++ return 0;
++}
++
++
++
++/* Given a capture format in pix, the frame period in timeperframe, and
++ * the xclk frequency, set the capture format of the sensor.
++ * The actual frame period will be returned in timeperframe.
++ */
++int sensor_configure(struct v4l2_pix_format *pix, unsigned long xclk)
++{
++ enum pixel_format pfmt = YUV;
++
++ switch (pix->pixelformat) {
++ case V4L2_PIX_FMT_RGB565:
++ case V4L2_PIX_FMT_RGB565X:
++ pfmt = RGB565;
++ break;
++ case V4L2_PIX_FMT_RGB555:
++ case V4L2_PIX_FMT_RGB555X:
++ pfmt = RGB555;
++ break;
++ case V4L2_PIX_FMT_YUYV:
++ case V4L2_PIX_FMT_UYVY:
++ default:
++ pfmt = YUV;
++ }
++
++ return sensor_init_module(sensor_find_size(pix->width, pix->height), pfmt, xclk);
++}
++
++
++/* Initialize the sensor.
++ * This routine allocates and initializes the data structure for the sensor,
++ * powers up the sensor, registers the I2C driver, and sets a default image
++ * capture format in pix. The capture format is not actually programmed
++ * into the sensor by this routine.
++ * This function must return a non-NULL value to indicate that
++ * initialization is successful.
++ */
++int sensor_init(struct v4l2_pix_format *pix)
++{
++ int ret;
++
++ //memset(&cam_sensor, 0x00, sizeof(struct dev_sensor));
++ TDD_CIF_Initialize();
++ //msleep(5);
++
++
++#ifdef USING_HW_I2C
++ if(!enabled)
++ {
++ ret = i2c_add_driver(&cam_i2c_driver);
++ if (ret != 0)
++ {
++ printk(KERN_ERR "Failed to register Sensor I2C client.\n");
++ return ENODEV;
++ }
++ enabled = 1;
++ }
++#else
++ DDI_I2C_Initialize();
++ i2c_init();
++#endif
++
++ /* Make the default capture format QVGA YUV422 */
++ pix->width = sensor_sizes[VGA].width;
++ pix->height = sensor_sizes[VGA].height;
++ pix->pixelformat = V4L2_PIX_FMT_YUYV;
++ sensor_try_format(pix);
++
++ return 0;
++}
++
++/* Prepare for the driver to exit.
++ * Balances sensor_init().
++ * This function must de-initialize the sensor and its associated data
++ * structures.
++ */
++int sensor_cleanup(void)
++{
++#ifdef USING_HW_I2C
++ if(enabled)
++ {
++ i2c_del_driver(&cam_i2c_driver);
++
++ if(cam_i2c_client)
++ {
++ kfree(cam_i2c_client);
++ cam_i2c_client = NULL;
++ }
++ enabled = 0;
++ }
++#endif
++
++ return 0;
++}
++
++/* ----------------------------------------------------------------------- */
++
++
++
++#if 0
++static int __init sensor_init_module(void)
++{
++ return i2c_add_driver(&i2c_driver_sensor);
++}
++
++static int __exit sensor_exit(void)
++{
++ i2c_del_driver();
++}
++
++module_init(sensor_init_module);
++module_exit(sensor_exit);
++#endif
++
++MODULE_DESCRIPTION("Camera SENSOR driver");
++MODULE_AUTHOR("Telechips");
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/media/video/tcccam/sensor_if.h b/drivers/media/video/tcccam/sensor_if.h
+new file mode 100644
+index 0000000..45d2e30
+--- /dev/null
++++ b/drivers/media/video/tcccam/sensor_if.h
+@@ -0,0 +1,61 @@
++/*
++ * drivers/media/video/tcccam/sensor_if.h
++ *
++ * Copyright (C) 2008 Telechips, Inc.
++ *
++ * Sensor interface to TCC camera capture drivers
++ * Sensor driver should implement this interface
++ *
++ * This package is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#include <linux/videodev2.h>
++
++#ifndef TCC_SENSOR_IF_H
++#define TCC_SENSOR_IF_H
++
++#define USING_HW_I2C
++
++#if defined(CONFIG_VIDEO_CAMERA_SENSOR_MT9P111)
++#define SENSOR_5M
++#define I2C_DRIVERID_SENSOR I2C_DRIVERID_MT9P111
++#include "mt9p111_5mp.h"
++#elif defined(CONFIG_VIDEO_CAMERA_SENSOR_MV9317)
++#define SENSOR_3M
++#define I2C_DRIVERID_SENSOR I2C_DRIVERID_MV9317
++#include "mv9317_3mp.h"
++#elif defined(CONFIG_VIDEO_CAMERA_SENSOR_MT9D111)
++#define SENSOR_2M
++#define I2C_DRIVERID_SENSOR I2C_DRIVERID_MT9D111
++#include "mt9d111_2mp.h"
++#elif defined(CONFIG_VIDEO_CAMERA_SENSOR_MT9D112)
++#define SENSOR_2M
++#define I2C_DRIVERID_SENSOR I2C_DRIVERID_MT9D112
++#include "mt9d112_2mp.h"
++#elif defined(CONFIG_VIDEO_CAMERA_SENSOR_S5K4BAFB)
++#define SENSOR_2M
++#define I2C_DRIVERID_SENSOR I2C_DRIVERID_S5K4BAFB
++#define TCC_VCORE_30FPS_CAMERASENSOR
++#include "s5k4bafb_2mp.h"
++#endif
++
++#define TCC_SENSOR_NAME_LEN 31
++
++extern int sensor_change_mode(unsigned char capture_mode);
++extern int sensor_adjust_autofocus(void);
++extern int sensor_query_control(struct v4l2_queryctrl *qc);
++extern int sensor_get_control(struct v4l2_control *vc);
++extern int sensor_set_control(struct v4l2_control *vc);
++extern int sensor_set_current_control(void);
++extern int sensor_enum_pixformat(struct v4l2_fmtdesc *fmt);
++extern int sensor_configure(struct v4l2_pix_format *pix, unsigned long xclk);
++extern int sensor_init(struct v4l2_pix_format *pix);
++extern int sensor_cleanup(void);
++
++#endif
+diff --git a/drivers/media/video/tcccam/tcc_cam.c b/drivers/media/video/tcccam/tcc_cam.c
+new file mode 100644
+index 0000000..25e5ee9
+--- /dev/null
++++ b/drivers/media/video/tcccam/tcc_cam.c
+@@ -0,0 +1,1397 @@
++
++/*
++ * drivers/media/video/tcccam/tcc83x_cif.c
++ *
++ * Copyright (C) 2008 Telechips, Inc.
++ *
++ * Video-for-Linux (Version 2) camera capture driver for
++ * the TCC78xx camera controller.
++ *
++ * leverage some code from CEE distribution
++ * Copyright (C) 2003-2004 MontaVista Software, Inc.
++ *
++ * This package is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#include <linux/autoconf.h>
++#include <linux/vmalloc.h>
++#include <linux/slab.h>
++#include <linux/proc_fs.h>
++#include <linux/ctype.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/clk.h>
++
++#include <mach/irqs.h>
++//#include <asm/arch/dma.h>
++#include <mach/hardware.h>
++#include <asm/io.h>
++
++#include <bsp.h>
++
++#include <mach/memory.h>
++#include <asm/scatterlist.h>
++#include <asm/mach-types.h>
++
++#include "sensor_if.h"
++#include "tcc_cam.h"
++#include "camera_hw_if.h"
++#include "camera_core.h"
++#include "tdd_cif.h"
++#include "cam.h"
++#include "cam_reg.h"
++#include "tcc_cam_inc.h"
++
++#if 0
++static int debug = 1;
++#else
++static int debug = 0;
++#endif
++
++#define dprintk(msg...) if (debug) { printk( "Tcc_cam: " msg); }
++
++
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++#include "tcc83xx/tcc83xx_jpeg.h"
++#include "tcc83xx/jpeg_param.h"
++
++JPEG_ENC_INFO gJPEG_ENC_Info;
++JPEG_DEC_INFO gJPEG_DEC_Info;
++JPEG_BUFFER_CTRL gJPEG_Buffer_Info;
++JPEG_DISPLAY_INFO JPEG_Info;
++jpeg_parser_rsp gJpegInfo;
++extern volatile char gJpegDecodeDone;
++extern volatile char gJpegEncodeDone;
++unsigned char gJpegCodecMode = JPEG_UNKNOWN_MODE;
++extern uint8 gIsExifThumbnailProcess;
++extern jpeg_encode_option_type gEncodeOption;
++
++unsigned char gIsRolling;
++
++void *jpeg_header_remapped_address; // Header Buffer
++void *jpeg_remapped_base_address;
++
++//#define JPEG_STREAM 0x180000 //1600*1024
++//#define JPEG_HEADER 0x020000 //96*1024
++#define JPEG_STREAM 0x1D0000 //1856*1024
++#define JPEG_HEADER 0x030000 //192*1024
++
++#define CAPTURE_PHY_ADDRESS PA_VIDEO_BASE
++#define JPEG_PHY_ADDRESS PA_VIDEO_BASE + CAPTURE_MEM
++#endif
++
++u8 current_effect_mode = 0;
++struct TCCxxxCIF hardware_data;
++
++void cif_timer_register(void* priv, unsigned long timeover);
++void cif_dma_hw_reg(unsigned char frame_num);
++
++static unsigned char cam_irq = 0;
++static unsigned char skip_frm = 8, skipped_frm = 0;
++
++/* Clears the camera data FIFO by setting RAZ_FIFO bit in MODE configuration
++ register. */
++static void cif_clear_fifo(struct TCCxxxCIF *data)
++{
++ #if 0
++ data->camera_regs->mode |= RAZ_FIFO;
++ udelay(10);
++ data->camera_regs->mode &= ~RAZ_FIFO;
++#endif
++}
++
++static void cif_reset(struct TCCxxxCIF *data, int yes)
++{
++#if 0
++ if (machine_is_omap_h3())
++ data->camera_regs->gpio = yes ? 0 : 1;
++ else
++ data->camera_regs->gpio = yes ? 1 : 0;
++#endif
++}
++
++static void cif_data_init(void *priv)
++{
++//Ä«¸Þ¶ó ÃʱâÈ­
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) priv;
++
++ //Default Setting
++ data->cif_cfg.order422 = CIF_YCBYCR;
++
++#if defined(CONFIG_VIDEO_CAMERA_SENSOR_MT9P111)
++ data->cif_cfg.polarity_pclk = POSITIVE_EDGE;
++#else
++ data->cif_cfg.polarity_pclk = NEGATIVE_EDGE;
++#endif
++
++#if defined(CONFIG_VIDEO_CAMERA_SENSOR_MV9317)
++ data->cif_cfg.polarity_vsync = ACT_LOW;
++#else
++ data->cif_cfg.polarity_vsync = ACT_HIGH;
++#endif
++ data->cif_cfg.polarity_href = ACT_HIGH;
++
++ data->cif_cfg.oper_mode = OPER_PREVIEW;
++ data->cif_cfg.zoom_step = 0;
++
++ data->cif_cfg.base_buf = hardware_data.cif_buf.addr;
++ data->cif_cfg.pp_num = 0;//TCC_CAMERA_MAX_BUFNBRS;
++ data->cif_cfg.fmt = M420_ZERO;
++
++ data->cif_cfg.main_set.target_x = 0;
++ data->cif_cfg.main_set.target_y = 0;
++
++ data->cif_cfg.esd_restart = OFF;
++
++ data->cif_cfg.cap_status = CAPTURE_NONE;
++ data->cif_cfg.retry_cnt = 0;
++
++ current_effect_mode = 0;
++
++}
++
++
++static irqreturn_t cif_cam_isr(int irq, void *client_data/*, struct pt_regs *regs*/)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *)&hardware_data;
++ struct tccxxx_cif_buffer *cif_buf;
++ unsigned int current_frame_num;
++
++ struct tccxxx_cif_buffer *next_1st_buf;
++ unsigned int next_1st_num;
++
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++ unsigned int uCLineCnt, uTempVCNT;
++#endif
++
++ client_data = client_data;
++
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++ if (data->cif_cfg.oper_mode == OPER_CAPTURE)
++ {
++ if(TDD_CIF_GetIntStatus(GET_CIF_INT_VCNT_GEN))
++ {
++ if (gIsRolling)
++ {
++ uCLineCnt = HwCIF->HwCCLC;
++
++ BITSET(HwCIF->HwCIRQ, HwCIRQ_VIT);
++
++ uTempVCNT = HwCIF->HwCCLC;
++ while(uTempVCNT%FRAME_LINE_CNT == 0 && uTempVCNT != data->cif_cfg.main_set.target_y)
++ uTempVCNT = HwCIF->HwCCLC;
++
++ BITSET(HwCIF->HwCIRQ, HwCIRQ_VIT);
++
++ if(gJpegCodecMode != JPEG_ENCODE_MODE)
++ {
++ gJpegCodecMode = JPEG_ENCODE_MODE;
++ BITCSET(HwJPEGENC->JP_START, 0x0000000F, HwJP_START_RUN);
++ BITCSET(HwJPEGENC->HwJP_SBUF_WCNT, 0x0000FFFF, uCLineCnt);
++ }
++ else if(((uCLineCnt%FRAME_LINE_CNT==0)||(uCLineCnt >= data->cif_cfg.main_set.target_y - FRAME_LINE_CNT)))
++ {
++ if(uCLineCnt >= (data->cif_cfg.main_set.target_y - FRAME_LINE_CNT))
++ {
++ BITCSET(HwJPEGENC->HwJP_SBUF_WCNT, 0x0000FFFF, data->cif_cfg.main_set.target_y);
++ }
++ else
++ BITCSET(HwJPEGENC->HwJP_SBUF_WCNT, 0x0000FFFF, uCLineCnt);
++ }
++ }
++
++ return IRQ_HANDLED;
++ }
++
++ if(TDD_CIF_GetIntStatus(GET_CIF_INT_ENC_STRT))
++ {
++ BITSET(HwCIF->HwCIRQ, HwCIRQ_ENS);
++
++ gJpegCodecMode = JPEG_ENCODE_MODE;
++ BITCSET(HwJPEGENC->JP_START, 0x0000000F, HwJP_START_RUN);
++ return IRQ_HANDLED;
++ }
++ }
++#else
++ if(TDD_CIF_GetIntStatus(GET_CIF_INT_ENC_STRT))
++ {
++ data->cif_cfg.now_frame_num = 0;
++ cif_buf = data->buf + data->cif_cfg.now_frame_num;
++
++ cif_buf->v4lbuf.bytesused = data->cif_cfg.main_set.target_x*data->cif_cfg.main_set.target_y*2;
++ cif_buf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
++ cif_buf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
++
++ list_move_tail(&cif_buf->buf_list, &data->done_list);
++
++ data->cif_cfg.cap_status = CAPTURE_DONE;
++
++ wake_up_interruptible(&data->frame_wait); //POLL
++ //if (!list_empty(&data->done_list))
++ // wake_up(&data->frame_wait);
++
++ //(CONFIG_ARCH_TCC8900)
++ BITSET(HwCIF->CIRQ, HwCIRQ_ENS);
++ BITSET(HwCIF->CIRQ, HwCIRQ_ENS);
++
++ return IRQ_HANDLED;
++ }
++#endif
++
++ //preview : Stored-One-Frame in DMA
++ if(TDD_CIF_GetIntStatus(GET_CIF_INT_ONEFRAME_STORE))
++ {
++ if(data->stream_state == STREAM_ON)
++ {
++ TDD_CIF_SetInterrupt(SET_CIF_UPDATE_WITHOUT_VSYNC);
++
++ if(skip_frm == 0)
++ {
++ current_frame_num = data->cif_cfg.now_frame_num;
++ cif_buf = data->buf + data->cif_cfg.now_frame_num;
++
++ next_1st_num = (current_frame_num+1) % (data->cif_cfg.pp_num);
++ next_1st_buf = data->buf + next_1st_num;
++
++ if(cif_buf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED
++ && next_1st_buf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED
++ )
++ {
++ dprintk("[Isr=%d/%d]\n", current_frame_num, data->cif_cfg.pp_num);
++ cif_dma_hw_reg((data->cif_cfg.now_frame_num+1) % (data->cif_cfg.pp_num));
++
++ // spin_unlock_irqrestore(&data->dev_lock, flags);
++ cif_buf->v4lbuf.bytesused = data->cif_cfg.main_set.target_x*data->cif_cfg.main_set.target_y*2;
++ // cif_buf->v4lbuf.sequence = cam->buf_seq[bufno];
++ cif_buf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
++ cif_buf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
++ // spin_lock_irqsave(&data->dev_lock, flags);
++ // cif_buf->v4lbuf.timestamp = gettimeofday(.., ..);
++
++ list_move_tail(&cif_buf->buf_list, &data->done_list);
++
++ if (!list_empty(&data->done_list))
++ wake_up(&data->frame_wait);
++
++ }
++ else
++ {
++ skipped_frm++;
++ }
++ }
++ else
++ {
++ skip_frm--;
++ }
++
++ //(CONFIG_ARCH_TCC8900)
++ BITSET(HwCIF->CIRQ, HwCIRQ_SOF);
++ BITSET(HwCIF->CIRQ, HwCIRQ_MSOF);
++ BITCLR(HwCIF->CIRQ, HwCIRQ_MSOF);
++
++ TDD_CIF_SetInterrupt(SET_CIF_UPDATE_IN_VSYNC);
++ }
++
++ }
++
++ return IRQ_HANDLED;
++}
++
++/* ------------- below are interface functions ----------------- */
++/* ------------- these functions are named tccxxxcif_<name> -- */
++
++/* Enables the camera. Takes camera out of reset. Enables the clocks. */
++static int cif_enable(void *priv)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) priv;
++
++ cif_reset(data, 1);
++#if 0
++ /* give clock to camera_module */
++ data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT);
++ data->camera_regs->ctrlclock = MCLK_EN | CAMEXCLK_EN;
++
++ omap16xx_cam_clear_fifo(data);
++#endif
++ /* wait for camera to settle down */
++ mdelay(5);
++
++ return 0;
++}
++
++/* Disables all the camera clocks. Put the camera interface in reset. */
++static int cif_disable(void)
++{
++// struct TCCxxxCIF *data = (struct TCCxxxCIF *) priv;
++
++ TDD_CIF_Termination();
++
++// cif_clear_fifo(data);
++// cif_reset(data, 0);
++
++ return 0;
++}
++
++static int cif_cleanup(void)
++{
++ cif_disable();
++ return 0;
++}
++
++
++/* Abort the data transfer */
++static int cif_abort(void *priv)
++{
++#if 0
++
++ return cif_disable();
++#endif
++}
++
++static int cif_set_xclk(int xclk)
++{
++
++
++#if 0
++ int xclk_val;
++ int divisor = 1;
++ divisor = data->ocp_clk/xclk;
++
++ if ( divisor * xclk < data->ocp_clk)
++ ++divisor;
++
++ switch (divisor) {
++ case 1:
++ case 2:
++ xclk_val = FOSCMOD_TC2_CK2;
++ break;
++ case 3:
++ xclk_val = FOSCMOD_TC2_CK3;
++ break;
++ case 4:
++ case 5:
++ case 6:
++ case 7:
++ xclk_val = FOSCMOD_TC2_CK4;
++ break;
++ case 8:
++ case 9:
++ xclk_val = FOSCMOD_TC2_CK8;
++ break;
++ case 10:
++ case 11:
++ xclk_val = FOSCMOD_TC2_CK10;
++ break;
++ case 12:
++ case 13:
++ case 14:
++ case 15:
++ xclk_val = FOSCMOD_TC2_CK12;
++ break;
++ case 16:
++ xclk_val = FOSCMOD_TC2_CK16;
++ break;
++ default:
++ xclk_val = FOSCMOD_TC2_CK16;
++ }
++
++ /* follow the protocol to change the XCLK clock */
++ data->camera_regs->ctrlclock &= ~CAMEXCLK_EN;
++ data->camera_regs->ctrlclock |= xclk_val;
++ data->camera_regs->ctrlclock |= CAMEXCLK_EN;
++
++ return (data->ocp_clk/divisor);
++#endif
++ return 0;
++}
++
++
++static void cif_check_handler(unsigned long arg)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) arg;
++ unsigned long timeover = 0;
++
++ if(data->cif_cfg.oper_mode == OPER_PREVIEW)
++ {
++ if(0) // Check Sensor-ESD register!!
++ {
++ data->cif_cfg.esd_restart = ON;
++ timeover = 0;
++ }
++ else
++ timeover = HZ;
++
++ cif_timer_register(data, timeover);
++ }
++}
++
++void cif_timer_register(void* priv, unsigned long timeover)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) priv;
++
++ init_timer(&data->cam_timer);
++ data->cam_timer.function = cif_check_handler;
++ data->cam_timer.data = (unsigned long)data;
++ data->cam_timer.expires = get_jiffies_64()+ timeover;
++
++ add_timer(&data->cam_timer);
++}
++
++void cif_timer_deregister(void)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++
++ del_timer(&data->cam_timer);
++ data->cam_timer.expires = 0;
++}
++
++
++void cif_scaler_set(void *priv)
++{
++ cif_main_set *data = (cif_main_set *) priv;
++ unsigned int sc_hfactor, sc_vfactor;
++ unsigned int crop_hor_ofst, crop_ver_ofst;
++
++ if(((data->target_x /4)*3) == data->target_y ||
++ ((data->target_x /11)*9) == data->target_y) // if 4:3 ratio ?
++ {
++ data->scaler_x = data->target_x;
++ data->scaler_y = data->target_y;
++ }
++ else
++ {
++ if(data->target_y%3)
++ data->scaler_y = (data->target_y + (3 - data->target_y%3));
++ else
++ data->scaler_y = data->target_y;
++
++ data->scaler_x = data->scaler_y/3 * 4;
++
++ if(data->scaler_x < data->target_x)
++ {
++ if(data->target_x%4)
++ data->scaler_x = (data->target_x + (4 - data->target_x%4));
++ else
++ data->scaler_x = data->target_x;
++ data->scaler_y = data->scaler_x/4 * 3;
++ }
++ }
++
++ sc_hfactor = (data->source_x*256/data->scaler_x);
++ sc_vfactor = (data->source_y*256/data->scaler_y);
++
++ TDD_CIF_SetFreeScale(SET_CIF_SCALER_SRC_SIZE|SET_CIF_SCALER_DST_SIZE,
++ data->source_x, data->source_y, 0, 0, data->scaler_x, data->scaler_y, 0,0);
++ TDD_CIF_SetFreeScale(SET_CIF_SCALER_SRC_OFFSET,
++ 0, 0, data->win_hor_ofst, data->win_ver_ofst, 0, 0, 0,0);
++ TDD_CIF_SetFreeScale(SET_CIF_SCALER_FACTOR, 0, 0, 0, 0, 0, 0,
++ sc_hfactor, sc_vfactor);
++
++ //Crop
++ crop_hor_ofst = (data->scaler_x - data->target_x)/2;
++ crop_ver_ofst = (data->scaler_y - data->target_y)/2;
++ TDD_CIF_SetImage(INPUT_IMG, data->scaler_x, data->scaler_y,
++ crop_hor_ofst, (data->scaler_x - data->target_x - crop_hor_ofst),
++ crop_ver_ofst, (data->scaler_y - data->target_y - crop_ver_ofst));
++
++ TDD_CIF_SetScalerCtrl(SET_CIF_SCALER_ENABLE);
++}
++
++void cif_scaler_calc(void)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++ enum cifoper_mode mode = data->cif_cfg.oper_mode;
++ unsigned int off_x, off_y, width, height;
++
++ if(mode == OPER_PREVIEW
++ || (mode == OPER_CAPTURE && data->cif_cfg.main_set.target_x < CAM_CAPCHG_WIDTH) )
++ {
++ off_x = PRV_ZOFFX;
++ off_y = PRV_ZOFFY;
++ width = PRV_W;
++ height = PRV_H;
++ }
++ else
++ {
++ off_x = CAP_ZOFFX;
++ off_y = CAP_ZOFFY;
++ width = CAP_W;
++ height = CAP_H;
++ }
++
++ data->cif_cfg.main_set.win_hor_ofst = off_x * data->cif_cfg.zoom_step;
++ data->cif_cfg.main_set.win_ver_ofst = off_y * data->cif_cfg.zoom_step;
++ data->cif_cfg.main_set.source_x = width - (off_x * data->cif_cfg.zoom_step)*2;
++ data->cif_cfg.main_set.source_y = height - (off_y * data->cif_cfg.zoom_step)*2;
++
++ TDD_CIF_SetSensorOutImgSize(width, height);
++
++ cif_scaler_set(&data->cif_cfg.main_set);
++}
++
++void cif_dma_hw_reg(unsigned char frame_num)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++
++ data->cif_cfg.now_frame_num = frame_num;
++
++ TDD_CIF_SetBaseAddr(INPUT_IMG, (unsigned int)data->cif_cfg.preview_buf[frame_num].p_Y,
++ (unsigned int)data->cif_cfg.preview_buf[frame_num].p_Cb,
++ (unsigned int)data->cif_cfg.preview_buf[frame_num].p_Cr);
++
++ TDD_CIF_SetBaseAddr_offset(INPUT_IMG, data->cif_cfg.main_set.target_x, data->cif_cfg.main_set.target_x/2);
++}
++
++void cif_preview_dma_set(void)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++ unsigned char i;
++ dma_addr_t base_addr = data->cif_cfg.base_buf;
++ unsigned int y_offset;
++ unsigned int uv_offset = 0;
++ unsigned int total_off = 0;
++
++ data->cif_cfg.now_frame_num = 0;
++ y_offset = data->cif_cfg.main_set.target_x*data->cif_cfg.main_set.target_y;
++
++ if(data->cif_cfg.fmt == M420_ZERO)
++ uv_offset = (data->cif_cfg.main_set.target_x*data->cif_cfg.main_set.target_y)/2;
++ else
++ uv_offset = (data->cif_cfg.main_set.target_x*data->cif_cfg.main_set.target_y)/4;
++
++ total_off = y_offset + uv_offset*2;
++ total_off = PAGE_ALIGN(total_off);
++ for(i = 0; i<data->cif_cfg.pp_num; i++)
++ {
++ data->cif_cfg.preview_buf[i].p_Y = (unsigned int)PAGE_ALIGN( base_addr + total_off*i);
++ data->cif_cfg.preview_buf[i].p_Cb = (unsigned int)data->cif_cfg.preview_buf[i].p_Y + y_offset;
++ data->cif_cfg.preview_buf[i].p_Cr = (unsigned int)data->cif_cfg.preview_buf[i].p_Cb + uv_offset;
++ }
++
++}
++
++void cif_capture_dma_set(void *priv)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++ //unsigned char i;
++ dma_addr_t base_addr = data->cif_cfg.base_buf;
++ unsigned int y_offset;
++ unsigned int uv_offset = 0;
++
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++ if(gIsRolling)
++ {
++ y_offset = JPEG_Info.JpegCaptureBuffSize/2;
++
++ if(data->cif_cfg.fmt == M420_ZERO)
++ uv_offset = JPEG_Info.JpegCaptureBuffSize/4;
++ else
++ uv_offset = JPEG_Info.JpegCaptureBuffSize/4/2;
++ }
++ else
++#endif
++ {
++ y_offset = data->cif_cfg.main_set.target_x*data->cif_cfg.main_set.target_y;
++
++ if(data->cif_cfg.fmt == M420_ZERO)
++ uv_offset = (data->cif_cfg.main_set.target_x*data->cif_cfg.main_set.target_y)/2;
++ else
++ uv_offset = (data->cif_cfg.main_set.target_x*data->cif_cfg.main_set.target_y)/4;
++ }
++
++ data->cif_cfg.capture_buf.p_Y = (unsigned int)base_addr;
++ data->cif_cfg.capture_buf.p_Cb = (unsigned int)data->cif_cfg.capture_buf.p_Y + y_offset;
++ data->cif_cfg.capture_buf.p_Cr = (unsigned int)data->cif_cfg.capture_buf.p_Cb + uv_offset;
++
++ TDD_CIF_SetBaseAddr(INPUT_IMG, (unsigned int)data->cif_cfg.capture_buf.p_Y,
++ (unsigned int)data->cif_cfg.capture_buf.p_Cb,
++ (unsigned int)data->cif_cfg.capture_buf.p_Cr);
++
++ TDD_CIF_SetBaseAddr_offset(INPUT_IMG, data->cif_cfg.main_set.target_x, data->cif_cfg.main_set.target_x/2);
++
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++ if(gIsRolling)
++ {
++ if(data->cif_cfg.fmt == M420_ZERO)
++ {
++ TDD_CIF_SetBaseAddr(IN_IMG_ROLLING,
++ ((unsigned int)data->cif_cfg.capture_buf.p_Y+(JPEG_Info.JpegCaptureBuffSize/2)-4),
++ ((unsigned int)data->cif_cfg.capture_buf.p_Cb+(JPEG_Info.JpegCaptureBuffSize/2/2)-4),
++ ((unsigned int)data->cif_cfg.capture_buf.p_Cr+(JPEG_Info.JpegCaptureBuffSize/2/2)-4));
++ }
++ else
++ {
++ TDD_CIF_SetBaseAddr(IN_IMG_ROLLING,
++ ((unsigned int)data->cif_cfg.capture_buf.p_Y+(JPEG_Info.JpegCaptureBuffSize/2)-4),
++ ((unsigned int)data->cif_cfg.capture_buf.p_Cb+(JPEG_Info.JpegCaptureBuffSize/2/4)-4),
++ ((unsigned int)data->cif_cfg.capture_buf.p_Cr+(JPEG_Info.JpegCaptureBuffSize/2/4)-4));
++ }
++ }
++#endif
++
++}
++
++
++
++void cif_interrupt_enable(enum cifoper_mode mode)
++{
++ TDD_CIF_SetMaskIntStatus(SET_CIF_INT_ALL_MASK);
++
++ if(mode == OPER_PREVIEW)
++ {
++ TDD_CIF_SetMaskIntStatus(SET_CIF_INT_STORE_1FRM_NOT_MASK);
++ }
++ else
++ {
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++ if(gIsRolling)
++ {
++ TDD_CIF_SetMaskIntStatus(SET_CIF_INT_VCNT_NOT_MASK);
++ }
++ else
++#endif
++ {
++ TDD_CIF_SetMaskIntStatus(SET_CIF_INT_ENC_STRT_NOT_MASK);
++ TDD_CIF_SetInterrupt(SET_CIF_UPDATE_WITHOUT_VSYNC);
++ }
++ }
++
++ TDD_CIF_SetInterrupt(SET_CIF_INT_ENABLE);
++}
++
++void cif_interrupt_disable(void)
++{
++ TDD_CIF_SetInterrupt(SET_CIF_INT_DISABLE);
++}
++
++void cif_global_reset(void)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++
++ TDD_CIF_SetInterrupt(SET_CIF_INT_TYPE_HOLDUP); //should be '1'
++ TDD_CIF_SetInterrupt(SET_CIF_UPDATE_IN_VSYNC);
++ TDD_CIF_SetInfo(SET_CIF_ALL, SEPARATE, MSB_FIRST, MODE_YUV, FMT422, BAYER_RGB, MODE16, data->cif_cfg.order422, SWICH_BUS);
++
++ //DMA configure
++ TDD_CIF_SetTransfer(SET_CIF_TRANSFER_ALL, BURST8, LOCK_TR, BURST_TRANS);
++ TDD_CIF_SetSyncPol(data->cif_cfg.polarity_href, data->cif_cfg.polarity_vsync);
++
++ //Effect all clear
++ TDD_CIF_SetEffectMode(SET_CIF_CEM_NOR);
++
++ TDD_CIF_SetCtrl(SET_CIF_II_ALL, CIF_PWDN_DISABLE, CIF_BYPASS_SCALER_DISABLE,
++ data->cif_cfg.polarity_pclk, FRAME_0, data->cif_cfg.fmt, CIF_656CONVERT_DISABLE);
++}
++
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++static irqreturn_t tccxxx_jpeg_handler(int irq, void *dev_id/*, struct pt_regs *reg*/)
++{
++ unsigned long lFlag, TempFlag;
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++ struct tccxxx_cif_buffer *cif_buf;
++
++ lFlag = HwJP_INT_FLAG;
++
++ if (lFlag & HwJP_INT_FLAG_CODED_BUF_STAT)
++ {
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++ data->cif_cfg.cap_status = CAPTURE_OVERFLOW;
++ #ifdef JPEG_TESTCODE
++ JPEG_BUS_Disable(JPEG_ENCODE_MODE); // temp!! NO-thumbnail!!
++ JPEG_INTERRUPT_Disable(JPEG_ENCODE_MODE);
++ #endif
++ wake_up_interruptible(&data->frame_wait);
++#endif // JPEG_ENCODE_WITH_CAPTURE
++ dprintk(KERN_ALERT "JPEG ENCODING BUFFER-ERROR! \r\n");
++
++ }
++ else if (lFlag & HwJP_INT_FLAG_DECODING_ERR)
++ {
++
++ }
++ else if (lFlag & HwJP_INT_FLAG_JOB_FINISHED)
++ {
++ //Save to memory
++ if (gJpegCodecMode == JPEG_ENCODE_MODE)
++ {
++ gJpegEncodeDone = 1;
++ data->cif_cfg.cap_status = CAPTURE_DONE;
++
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++ #ifdef JPEG_TESTCODE
++ tccxxx_jpeg_make_header(&(data->cif_cfg.jpg_info.jpg_len), &(data->cif_cfg.jpg_info.jpg_hdr_len));
++ JPEG_BUS_Disable(JPEG_ENCODE_MODE); // temp!! NO-thumbnail!!
++ JPEG_INTERRUPT_Disable(JPEG_ENCODE_MODE);
++ #endif
++ wake_up_interruptible(&data->frame_wait);
++#endif // JPEG_ENCODE_WITH_CAPTURE
++
++ dprintk(KERN_ALERT "JPEG ENCODING DONE! \r\n");
++ }
++ else if (gJpegCodecMode == JPEG_DECODE_MODE)
++ {
++ gJpegDecodeDone = 1;
++ dprintk(KERN_ALERT "JPEG DECODING DONE \r\n");
++ }
++ }
++#ifdef TCC83XX
++ else if (lFlag & HwJP_INT_FLAG_YBUF_ROLLING)
++ {
++ BITSET(HwJP_INT_MASK, HwJP_INT_MASK_YBUF_ROLLING);
++ }
++#endif
++
++ TempFlag = HwJP_INT_ACK;
++
++ return IRQ_HANDLED;
++}
++
++static int
++tccxxx_jpeg_encode_method(void)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++ unsigned int ucReturnVal = FALSE;
++ unsigned int temp_1, temp_2;
++
++ JPEG_Info.JpegCaptureBuffSize = CAPTURE_MEM;
++
++ if (JPEG_Info.JpegCaptureBuffSize < data->cif_cfg.main_set.target_x*data->cif_cfg.main_set.target_y*2)
++ ucReturnVal = TRUE;
++
++ if(ucReturnVal)
++ {
++ temp_1 = (JPEG_Info.JpegCaptureBuffSize/2)/data->cif_cfg.main_set.target_x;
++
++ if (temp_1%FRAME_LINE_CNT != 0)
++ {
++ temp_2 = temp_1/FRAME_LINE_CNT;
++ JPEG_Info.JpegCaptureBuffSize = (temp_2*FRAME_LINE_CNT)*data->cif_cfg.main_set.target_x*2;
++ }
++ }
++
++ return ucReturnVal;
++}
++
++static int
++tccxxx_jpeg_encode_init(enum jpeg_quantisation_val val)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++
++ unsigned int uiOutputBufferSize, uiInputBufferSize;
++ void *BufferY, *BufferU, *BufferV;
++
++ gJpegCodecMode = JPEG_UNKNOWN_MODE;
++ JPEG_Exif_Header_Info_Init();
++
++ BufferY = (void*)data->cif_cfg.capture_buf.p_Y ;
++ BufferU = (void*)data->cif_cfg.capture_buf.p_Cb;
++ BufferV = (void*)data->cif_cfg.capture_buf.p_Cr;
++
++ JPEG_BUS_EnableJPEG_ENCODE_MODE();
++ JPEG_SW_Reset(JPEG_ENCODE_MODE);
++ gJpegEncodeDone = 0;
++
++ uiInputBufferSize = (JPEG_Info.JpegCaptureBuffSize/2)/data->cif_cfg.main_set.target_x;
++ uiOutputBufferSize = gJPEG_Buffer_Info.pBaseBitstreamDataSize/1024;
++
++ gJPEG_ENC_Info.is_rolling = gIsRolling;
++ gJPEG_ENC_Info.y_addr = (unsigned int)BufferY;
++ gJPEG_ENC_Info.u_addr = (unsigned int)BufferU;
++ gJPEG_ENC_Info.v_addr = (unsigned int)BufferV;
++ gJPEG_ENC_Info.ifrm_hsize = data->cif_cfg.main_set.target_x;
++ gJPEG_ENC_Info.ibuf_vsize = uiInputBufferSize;
++ gJPEG_ENC_Info.q_value = val;
++ gJPEG_ENC_Info.img_hsize = data->cif_cfg.main_set.target_x;
++ gJPEG_ENC_Info.img_vsize = data->cif_cfg.main_set.target_y;
++ gJPEG_ENC_Info.cbuf_addr = (unsigned int)gJPEG_Buffer_Info.pBaseBitstreamDataAddr;
++ gJPEG_ENC_Info.cbuf_size = uiOutputBufferSize;
++ gJPEG_ENC_Info.frame_cnt = FRAME_LINE_CNT;
++ gJPEG_ENC_Info.chroma = HwJP_CHROMA_422;
++
++#ifdef JPEG_TESTCODE
++ data->cif_cfg.jpg_info.jpg_buf_addr = jpeg_remapped_base_address;
++ data->cif_cfg.jpg_info.jpg_hdr_addr = jpeg_header_remapped_address;
++#endif
++
++ JPEG_SET_Encode_Config(&gJPEG_ENC_Info);
++
++ JPEG_INTERRUPT_Enable(JPEG_ENCODE_MODE);
++
++ return 0;
++}
++
++int tccxxx_jpeg_make_header(unsigned int *uiBitStreamSize, unsigned int *uiHeaderSize)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++ void *HeaderBuffer;
++
++ //while (!gJpegEncodeDone)
++
++ if (gIsExifThumbnailProcess)
++ {
++ gEncodeOption.ThumbnailInfo.pThumbnail_Buff = (void *)((uint32)jpeg_header_remapped_address + 2048);
++ gEncodeOption.ThumbnailInfo.thumbnail_image_size = JPEG_Encoded_Data_Size();
++ }
++ else
++ {
++ *uiBitStreamSize = JPEG_Encoded_Data_Size();
++
++ gEncodeOption.BitStreamSize = *uiBitStreamSize;
++ gEncodeOption.ThumbnailInfo.thumbnail_image_size = 0;
++ gEncodeOption.ImageWidth = data->cif_cfg.main_set.target_x;
++ gEncodeOption.ImageHeight = data->cif_cfg.main_set.target_y;
++ gEncodeOption.Q_FactorValue = JPEG_DEFAULT;
++ }
++
++ HeaderBuffer = jpeg_header_remapped_address;
++
++ *uiHeaderSize = TCCXXX_JPEG_Make_Header((uint32)HeaderBuffer, &gEncodeOption, &gJpegHeaderExifRsp);
++ *uiBitStreamSize = gEncodeOption.BitStreamSize;
++
++ gJpegEncodeDone = 0;
++ gIsExifThumbnailProcess = FALSE;
++
++ return 0;
++}
++#endif
++
++
++int tccxxx_cif_buffer_set(struct v4l2_requestbuffers *req)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++ dma_addr_t base_addr = data->cif_cfg.base_buf;
++ unsigned int y_offset = data->cif_cfg.main_set.target_x*data->cif_cfg.main_set.target_y;
++ unsigned int uv_offset = 0;
++ unsigned int total_off = 0;
++ unsigned char i;
++ unsigned long total_req_buf_size=0;
++ unsigned char req_buf = req->count;
++ unsigned int buff_size;
++
++ data->cif_cfg.now_frame_num = 0;
++
++ if (req->count > TCC_CAMERA_MAX_BUFNBRS)
++ req->count = TCC_CAMERA_MAX_BUFNBRS;
++
++ if (req->count < 0)
++ req->count = 2;
++
++ if(data->cif_cfg.fmt == M420_ZERO)
++ buff_size = PAGE_ALIGN(y_offset*2);
++ else
++ buff_size = PAGE_ALIGN(y_offset + y_offset/2);
++
++
++ data->buf->v4lbuf.length = buff_size;
++
++retry:
++ if(req_buf == 1)
++ {
++#if 0 // ZzaU :: Don't check Buffer in Rolling-Capture.
++ if (data->buf->v4lbuf.length > CAPTURE_MEM)
++ {
++ printk("reqbufs: count invalid\n");
++ return -1;
++ }
++#endif
++ }
++ else
++ {
++ if (data->buf->v4lbuf.length*req->count > PREVIEW_MEM)
++ {
++ req->count--;
++ if (req->count <= 0)
++ {
++ printk("reqbufs: count invalid\n");
++ return -1;
++ }
++ goto retry;
++ }
++ }
++
++ memset(data->static_buf,0x00,req->count * sizeof(struct tccxxx_cif_buffer));
++
++ data->done_list.prev = data->done_list.next = &data->done_list;
++ data->list.prev = data->list.next = &data->list;
++
++ for (data->n_sbufs = 0; data->n_sbufs < req->count; (data->n_sbufs++))
++ {
++ struct tccxxx_cif_buffer *buf = &(data->static_buf[data->n_sbufs]);
++
++ INIT_LIST_HEAD(&buf->buf_list);
++
++ //buf->v4lbuf.length = PAGE_ALIGN(cam->pix_format.sizeimage);
++ buf->v4lbuf.length = buff_size;
++
++ total_req_buf_size += buf->v4lbuf.length;
++ //dprintk(KERN_WARNING "<total size is 0x%x / 0x%x>\n", (unsigned int)(buf->v4lbuf.length), (unsigned int)(total_req_buf_size));
++
++ buf->mapcount = 0;
++ buf->cam = data;
++ buf->v4lbuf.index = data->n_sbufs;
++ buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ buf->v4lbuf.field = V4L2_FIELD_NONE;
++ buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
++
++ /*
++ * Offset: must be 32-bit even on a 64-bit system. videobuf-dma-sg
++ * just uses the length times the index, but the spec warns
++ * against doing just that - vma merging problems. So we
++ * leave a gap between each pair of buffers.
++ */
++ //buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;
++
++ }
++
++ //data->cif_cfg.pp_num = req->count;
++ data->cif_cfg.pp_num = data->n_sbufs;
++ req->count = data->cif_cfg.pp_num;
++
++
++ if(data->cif_cfg.fmt == M420_ZERO)
++ uv_offset = (data->cif_cfg.main_set.target_x*data->cif_cfg.main_set.target_y)/2;
++ else
++ uv_offset = (data->cif_cfg.main_set.target_x*data->cif_cfg.main_set.target_y)/4;
++
++ total_off = y_offset + uv_offset*2;
++ total_off = PAGE_ALIGN(total_off);
++ for(i = 0; i<data->cif_cfg.pp_num; i++)
++ {
++ data->cif_cfg.preview_buf[i].p_Y = (unsigned int)PAGE_ALIGN( base_addr + total_off*i);
++ data->cif_cfg.preview_buf[i].p_Cb = (unsigned int)data->cif_cfg.preview_buf[i].p_Y + y_offset;
++ data->cif_cfg.preview_buf[i].p_Cr = (unsigned int)data->cif_cfg.preview_buf[i].p_Cb + uv_offset;
++ }
++
++ printk("\n reqbufs: success :: buffer count = %d \n",data->cif_cfg.pp_num);
++ return 0;
++}
++
++int tccxxx_cif_cam_restart(struct v4l2_pix_format *pix, unsigned long xclk)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++ struct tccxxx_cif_buffer *cif_buf;
++
++ tccxxx_cif_stop_stream();
++
++ TDD_CIF_Reset();
++ sensor_configure(pix,xclk);
++ sensor_change_mode(OPER_PREVIEW);
++
++ while(!list_empty(&data->done_list))
++ {
++ cif_buf = list_entry(data->done_list.next, struct tccxxx_cif_buffer, buf_list);
++ list_del(&cif_buf->buf_list);
++
++ cif_buf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
++ cif_buf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
++
++ list_add_tail(&cif_buf->buf_list, &data->list);
++ }
++
++ // Sensor setting Again!!
++ sensor_set_current_control();
++
++ cif_dma_hw_reg(0);
++ data->stream_state = STREAM_ON;
++ cif_interrupt_enable(data->cif_cfg.oper_mode);
++
++ data->cif_cfg.esd_restart = OFF;
++ cif_timer_register(data, HZ);
++
++ return 0;
++}
++
++int tccxxx_cif_start_stream(void)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++
++ data->cif_cfg.oper_mode = OPER_PREVIEW;
++
++ skip_frm = 1;
++ skipped_frm = 0;
++
++ CIF_OpStop();
++ sensor_change_mode(OPER_PREVIEW);
++
++ TDD_CIF_SetInterrupt(SET_CIF_UPDATE_IN_VSYNC);
++ cif_global_reset();
++
++ tccxxx_cif_set_effect(current_effect_mode);
++
++ cif_scaler_calc();
++ cif_preview_dma_set();
++ cif_dma_hw_reg(0);
++
++ CIF_ONOFF(ON);
++
++ data->stream_state = STREAM_ON;
++
++ cif_interrupt_enable(data->cif_cfg.oper_mode);
++
++ cif_timer_register(data, HZ);
++
++ while(skip_frm)
++ {
++ msleep(1);
++ }
++ sensor_adjust_autofocus();
++
++ dprintk("@---- %s (%d)\n", __FUNCTION__, __LINE__);
++
++ return 0;
++}
++
++int tccxxx_cif_stop_stream(void)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++ //int i;
++
++ cif_timer_deregister();
++
++ cif_interrupt_disable();
++ //udelay(100);
++
++ data->stream_state= STREAM_OFF;
++
++ printk("\n\n SKIPPED FRAME = %d \n\n", skipped_frm);
++//wkjung
++/*
++ mutex_lock(&data->lock);
++
++ INIT_LIST_HEAD(&data->done_list);
++ INIT_LIST_HEAD(&data->list);
++
++ for(i=0; i<data->cif_cfg.pp_num;i++)
++ {
++ INIT_LIST_HEAD(&data->buf[i].buf_list);
++ data->buf[i].v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
++ data->buf[i].v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
++ }
++ mutex_unlock(&data->lock);
++*/
++
++ return 0;
++}
++
++void tccxxx_cif_set_overlay(void)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++ cif_SuperImpose *SiData = (cif_SuperImpose *)&(data->cif_cfg.si_overlay);
++
++ unsigned int frame_width = data->cif_cfg.main_set.scaler_x; // Scaler_out width
++ unsigned int frame_height = data->cif_cfg.main_set.scaler_y; // Scaler_out width
++ unsigned int siFrame_hoffset_s = 0;
++ unsigned int siFrame_hoffset_e = 0;
++ unsigned int siFrame_voffset_s = 0;
++ unsigned int siFrame_voffset_e = 0;
++ unsigned int si_buffer_addr = data->cif_buf.addr + SiData->buff_offset;
++
++ siFrame_hoffset_s = siFrame_hoffset_e = (frame_width - SiData->width)/2;
++ siFrame_voffset_s = siFrame_voffset_e = (frame_height - SiData->height)/2;
++
++ TDD_CIF_OverlayCtrl(SET_CIF_OVERLAY_DISABLE, OL_RGB_565);
++
++ if(SiData->buff_offset != 0)
++ {
++ TDD_CIF_SetImage(OVERLAY_IMG, frame_width, frame_height,
++ siFrame_hoffset_s, siFrame_hoffset_e, siFrame_voffset_s, siFrame_voffset_e);
++ TDD_CIF_SetOverlay (SET_CIF_OVERLAY_ALL, 49, FULL_OVERLAY, OP_ALPHA, OP_ALPHA, ALPHA100, ALPHA100);
++ TDD_CIF_SetOverlayKey(SET_CIF_OVERLAYKEY_ALL, SiData->chromakey_info.key_y,
++ SiData->chromakey_info.key_u,
++ SiData->chromakey_info.key_v,
++ SiData->chromakey_info.mask_r,
++ SiData->chromakey_info.mask_g,
++ SiData->chromakey_info.mask_b);
++
++ TDD_CIF_OverlayCtrl(SET_CIF_CHROMA_ENABLE|SET_CIF_OVERLAY_ENABLE|SET_CIF_COLOR_CONV_ENABLE|
++ SET_CIF_COLOR_MODE_RGB, OL_RGB_565);
++ TDD_CIF_SetBaseAddr(OVERLAY_IMG, (unsigned int)si_buffer_addr, 0, 0);
++ }
++}
++
++int tccxxx_cif_set_effect (u8 nCameraEffect)
++{
++ unsigned int uiSepiaU = 0x64;
++ unsigned int uiSepiaV = 0x8C;
++ unsigned int uiSKCoeff0 = 0x02;
++ unsigned int uiSKCoeff1 = 0x0;
++ unsigned int uiSKCoeff2 = 0xff;
++ unsigned int uiSkecthThreshold = 0x80;
++
++ if (nCameraEffect == TCC_EFFECT_NORMAL)
++ TDD_CIF_SetEffectMode(SET_CIF_CEM_NOR);
++ else if(nCameraEffect == TCC_EFFECT_GRAY)
++ TDD_CIF_SetEffectMode(SET_CIF_CEM_GRAY);
++ else if(nCameraEffect == TCC_EFFECT_NEGATIVE)
++ TDD_CIF_SetEffectMode(SET_CIF_CEM_NEGA);
++ else if(nCameraEffect == TCC_EFFECT_SKETCH)
++ {
++ uiSkecthThreshold = 0x89;
++ TDD_CIF_SetEffectMode(SET_CIF_CEM_SKT);
++ TDD_CIF_SetEffectHFilterCoeff(uiSKCoeff0, uiSKCoeff1, uiSKCoeff2);
++ TDD_CIF_SetEffectSketchTh(uiSkecthThreshold);
++ }
++ else if(nCameraEffect == TCC_EFFECT_SEPHIA)
++ {
++ uiSepiaU = 0x64;
++ uiSepiaV = 0x8C;
++ TDD_CIF_SetEffectMode(SET_CIF_CEM_SEPI);
++ TDD_CIF_SetEffectSepiaUV(uiSepiaU, uiSepiaV);
++ }
++ else if(nCameraEffect == TCC_EFFECT_GREEN)
++ {
++ uiSepiaU = 100;
++ uiSepiaV = 80;
++ TDD_CIF_SetEffectMode(SET_CIF_CEM_SEPI);
++ TDD_CIF_SetEffectSepiaUV(uiSepiaU, uiSepiaV);
++
++ }
++ else if(nCameraEffect == TCC_EFFECT_AQUA)
++ {
++ uiSepiaU = 192;
++ uiSepiaV = 80;
++ TDD_CIF_SetEffectMode(SET_CIF_CEM_SEPI);
++ TDD_CIF_SetEffectSepiaUV(uiSepiaU, uiSepiaV);
++
++ }
++ current_effect_mode = (u8) nCameraEffect;
++
++ return 0;
++}
++
++int tccxxx_cif_capture(int quality)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++ unsigned int ens_addr;
++ int skip_frame = 0;
++// int ret = 0;
++
++
++ data->cif_cfg.oper_mode = OPER_CAPTURE;
++
++ cif_interrupt_disable();
++
++ CIF_OpStop();
++ cif_global_reset();
++ tccxxx_cif_set_effect(current_effect_mode);
++
++ if(data->cif_cfg.main_set.target_x >= CAM_CAPCHG_WIDTH && !(data->cif_cfg.retry_cnt))
++ sensor_change_mode(OPER_CAPTURE);
++
++ cif_scaler_calc();
++
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++ gIsRolling = tccxxx_jpeg_encode_method();
++#endif
++ cif_capture_dma_set(data);
++
++ //capture config
++ if(data->cif_cfg.retry_cnt)
++ skip_frame = 0;
++ else
++ {
++ skip_frame = 1;
++ }
++
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++ if(gIsRolling)
++ {
++ TDD_CIF_SetInterrupt(SET_CIF_UPDATE_WITHOUT_VSYNC);
++ TDD_CIF_SetCaptureCtrl(SET_CIF_SKIP_NUM|SET_CIF_VCNT_NUM, skip_frame, FRAME_LINE_CNT/16,
++ SET_CIF_EIT_ENC_INT|SET_CIF_RLV_ENABLE|SET_CIF_RLU_ENABLE|SET_CIF_RLY_ENABLE|
++ SET_CIF_CAP_ENABLE|SET_CIF_VEN_ENABLE);
++ }
++ else
++#endif
++ {
++ ens_addr = (unsigned int)data->cif_cfg.capture_buf.p_Y +
++ (data->cif_cfg.main_set.target_x * (data->cif_cfg.main_set.target_y - 2));
++
++ if(data->cif_cfg.main_set.target_x < CAM_CAPCHG_WIDTH)
++ TDD_CIF_SetCaptureCtrl(SET_CIF_SKIP_NUM, skip_frame, 0,SET_CIF_EIT_ENC_INT|SET_CIF_CAP_ENABLE|SET_CIF_UES_ENABLE);
++ else
++ TDD_CIF_SetCaptureCtrl(SET_CIF_SKIP_NUM, skip_frame, 0,SET_CIF_EIT_ENC_INT|SET_CIF_CAP_ENABLE|SET_CIF_UES_ENABLE);
++
++ TDD_CIF_SetBaseAddr(IN_ENC_START_ADDR, ens_addr, 0, 0);
++ }
++
++ cif_interrupt_enable(data->cif_cfg.oper_mode);
++
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++ tccxxx_jpeg_encode_init(quality);
++#endif
++
++ if(data->cif_cfg.si_overlay.buff_offset != 0)
++ tccxxx_cif_set_overlay();
++
++ data->cif_cfg.cap_status = CAPTURE_NONE;
++ TDD_CIF_ONOFF(ON);
++
++ return 0;
++}
++
++
++int tccxxx_cif_set_zoom(unsigned char arg)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++
++ data->cif_cfg.zoom_step = arg;
++
++ if(data->stream_state != STREAM_OFF)
++ cif_scaler_calc();
++
++ return 0;
++}
++
++int tccxxx_cif_set_resolution(unsigned int pixel_fmt, unsigned short width, unsigned short height)
++{
++ struct TCCxxxCIF *data = &hardware_data;
++
++ //if(data->cif_cfg.main_set.target_x == width
++ // && data->cif_cfg.fmt == pixel_fmt)
++ // return 0;
++
++ if(pixel_fmt == V4L2_PIX_FMT_YUYV)//YUV 422
++ data->cif_cfg.fmt = M420_ZERO;
++ else
++ data->cif_cfg.fmt = M420_ODD;
++
++ data->cif_cfg.main_set.target_x = width;
++ data->cif_cfg.main_set.target_y = height;
++
++ if(data->stream_state != STREAM_OFF)
++ {
++ tccxxx_cif_stop_stream();
++ tccxxx_cif_start_stream();
++ }
++
++ return 0;
++}
++
++int tccxxx_cif_open(void)
++{
++ int ret;
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++
++ data->done_list.next = &data->done_list;
++ data->list.next = &data->list;
++
++ if(!cam_irq)
++ {
++ if ((ret = request_irq(IRQ_CAM, cif_cam_isr, IRQF_DISABLED, "camera", NULL)) < 0)
++ {
++ printk("FAILED to aquire irq\n");
++ return ret;
++ }
++ cam_irq = 1;
++ }
++
++#if defined(JPEG_ENCODE_WITH_CAPTURE) && !defined(NLY_ENCODE_JPEG_IN_ROLLING_CAPTURE)
++ free_irq(IRQ_JPGE, NULL);
++ if ((ret = request_irq(IRQ_JPE, tccxxx_jpeg_handler, IRQF_DISABLED, "jpeg", NULL)) < 0)
++ {
++ printk("FAILED to aquire irq\n");
++ return ret;
++ }
++#endif
++
++ return 0;
++}
++
++int tccxxx_cif_close(void)
++{
++ struct TCCxxxCIF *data = (struct TCCxxxCIF *) &hardware_data;
++ int i;
++
++/*
++ mutex_lock(&data->lock);
++
++ INIT_LIST_HEAD(&data->done_list);
++ INIT_LIST_HEAD(&data->list);
++
++ for(i=0; i<data->cif_cfg.pp_num;i++)
++ {
++ INIT_LIST_HEAD(&data->buf[i].buf_list);
++ data->buf[i].v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
++ data->buf[i].v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
++ }
++
++ mutex_unlock(&data->lock);
++*/
++ cif_interrupt_disable();
++ cif_cleanup();
++
++ dprintk("reamp : [0x%x - 0x%x] -> [0x%x] \n",data->cif_buf.addr, data->cif_buf.bytes, data->cif_buf.area);
++ iounmap(data->cif_buf.area);
++
++ free_irq(IRQ_CAM, NULL);
++ cam_irq = 0;
++
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++ free_irq(IRQ_JPGE, NULL);
++#endif
++
++ cif_timer_deregister();
++
++ return 0;
++}
++
++
++/* Initialise the OMAP camera interface */
++int tccxxx_cif_init(void)
++{
++ struct cif_dma_buffer *buf = &hardware_data.cif_buf;
++
++ memset(&hardware_data,0x00,sizeof(struct TCCxxxCIF));
++ hardware_data.buf = hardware_data.static_buf;
++
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++ buf->bytes = PAGE_ALIGN(CAPTURE_MEM+JPEG_MEM);
++ buf->addr = PA_VIDEO_BASE;
++ buf->area = ioremap_nocache(buf->addr,buf->bytes);
++
++ jpeg_remapped_base_address = (void *)ioremap_nocache(JPEG_PHY_ADDRESS, PAGE_ALIGN(JPEG_MEM-PAGE_SIZE)); //JPEG Buffer
++ jpeg_header_remapped_address = jpeg_remapped_base_address + JPEG_STREAM;
++
++ gJPEG_Buffer_Info.pBaseRawDataAddr = (void*)CAPTURE_PHY_ADDRESS;
++ gJPEG_Buffer_Info.pBaseRawDataSize = CAPTURE_MEM;
++ gJPEG_Buffer_Info.pBaseBitstreamDataAddr = (void*)JPEG_PHY_ADDRESS;
++ gJPEG_Buffer_Info.pBaseBitstreamDataSize = JPEG_STREAM;
++ gJPEG_Buffer_Info.pBaseHeaderDataAddr = (void*)(JPEG_PHY_ADDRESS + JPEG_STREAM);
++ gJPEG_Buffer_Info.pBaseHeaderDataSize = JPEG_HEADER;
++#else
++ buf->bytes = PAGE_ALIGN(PREVIEW_MEM);
++ buf->addr = PA_VIDEO_BASE;
++ buf->area = ioremap_nocache(buf->addr,buf->bytes);
++ dprintk("reamp : [0x%x - 0x%x] -> [0x%x] \n",buf->addr, buf->bytes, buf->area);
++#endif
++
++ if (buf->area == NULL)
++ {
++ printk(KERN_ERR CAM_NAME ": cannot remap buffer\n");
++ return ENODEV;
++ }
++
++ /* Init the camera IF */
++ cif_data_init((void*)&hardware_data);
++ /* enable it. This is needed for sensor detection */
++ cif_enable((void*)&hardware_data);
++
++ init_waitqueue_head(&hardware_data.frame_wait);
++ spin_lock_init(&hardware_data.dev_lock);
++
++ INIT_LIST_HEAD(&hardware_data.list);
++ INIT_LIST_HEAD(&hardware_data.done_list);
++ mutex_init(&hardware_data.lock);
++
++ return 0;
++}
++
+diff --git a/drivers/media/video/tcccam/tcc_cam.h b/drivers/media/video/tcccam/tcc_cam.h
+new file mode 100644
+index 0000000..01fceca
+--- /dev/null
++++ b/drivers/media/video/tcccam/tcc_cam.h
+@@ -0,0 +1,367 @@
++/*
++ * drivers/media/video/tcccam/tcc_cam.h
++ *
++ * Copyright (C) 2008 Telechips, Inc.
++ *
++ * This package is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
++ */
++
++#include <media/v4l2-common.h>
++
++
++#ifndef TCCXX_CIF_H
++#define TCCXX_CIF_H
++
++//#define JPEG_ENCODE_WITH_CAPTURE
++#ifdef JPEG_ENCODE_WITH_CAPTURE
++#define JPEG_TESTCODE
++#else
++typedef struct {
++ unsigned int src;
++ int width;
++ int height;
++ unsigned int bitstream_size;
++ unsigned int thumb_size;
++ unsigned int header_size;
++}TCCXXX_JPEG_ENC_DATA;
++#endif
++
++#define DMA_ELEM_SIZE 4
++#define FIFO_TRIGGER_LVL (32)
++
++/* Maximum number of buffers */
++#define TCC_CAMERA_MAX_BUFNBRS 8
++
++/*
++ * ---------------------------------------------------------------------------
++ * tccxxx Camera Interface
++ * ---------------------------------------------------------------------------
++ */
++#ifndef _LCDC_H_
++#define PAGE0 0
++#define PAGE1 1
++
++#define SET_LCD_ENABLE 0x00000001
++#define SET_LCD_DISABLE 0x00000002
++#define SET_CH0_ENABLE 0x00000004
++#define SET_CH0_DISABLE 0x00000008
++#define SET_CH1_ENABLE 0x00000010
++#define SET_CH1_DISABLE 0x00000020
++#define SET_CH2_ENABLE 0x00000040
++#define SET_CH2_DISABLE 0x00000080
++#define SET_TFT_ENABLE 0x00000100
++#define SET_TFT_DISABLE 0x00000200
++#define SET_TVOUT_ENABLE 0x00000400
++#define SET_TVOUT_DISABLE 0x00000800
++#define SET_STN_ENABLE 0x00001000
++#define SET_STN_DISABLE 0x00002000
++#define SET_NOTINTERLACE_ENABLE 0x00004000
++#define SET_NOTINTERLACE_DISABLE 0x00008000
++#define SET_DP2_ENABLE 0x00010000
++#define SET_DP2_DISABLE 0x00020000
++#define SET_RGB2YUV_ENABLE 0x00040000
++#define SET_RGB2YUV_DISABLE 0x00080000
++#define SET_CCIR656_ENABLE 0x00100000
++#define SET_CCIR656_DISABLE 0x00200000
++#define SET_CH0YUV2RGB_ENABLE 0x00400000
++#define SET_CH0YUV2RGB_DISABLE 0x00800000
++#define SET_CH1CHROMA_ENABLE 0x01000000
++#define SET_CH1CHROMA_DISABLE 0x02000000
++#define SET_CH2CHROMA_ENABLE 0x04000000
++#define SET_CH2CHROMA_DISABLE 0x08000000
++#define SET_CH1ALPHA_ENABLE 0x10000000
++#define SET_CH1ALPHA_DISABLE 0x20000000
++#define SET_CH2ALPHA_ENABLE 0x40000000
++#define SET_CH2ALPHA_DISABLE 0x80000000
++
++#define LCD_CH 1
++#define IMG_CH0 2
++#define IMG_CH1 4
++#define IMG_CH2 8
++
++
++#define SET_IMAGE_SIZE 0x00000001
++#define SET_IMAGE_POSITION 0x00000002
++#define SET_IMAGE_OFFSET 0x00000004
++#define SET_IMAGE_SCALE 0x00000008
++#define SET_IMAGE_FORMAT 0x00000010
++#define READ_IMAGE_POSITION 0x00000020
++#define SET_IMAGE_ALL 0x0000003F
++#define SET_LCD_POLARITY 0x00000040
++#define SET_LCD_MASK 0x00000080
++#define SET_LCD_ALL 0x000000C0
++
++#define IMG_LIT_ENDIAN ((0x0)<<7)
++#define IMG_BIG_ENDIAN ((0x1)<<7)
++#define IMG_RGB ((0x0)<<4)
++#define IMG_YUV420 ((0x1)<<4)
++#define IMG_YUV422 ((0x3)<<4)
++#define IMG_YUV422_DISP ((0x7)<<4)
++#define IMG_BPP_1 ((0x0)<<0)
++#define IMG_BPP_2 ((0x1)<<0)
++#define IMG_BPP_4 ((0x2)<<0)
++#define IMG_BPP_332 ((0x3)<<0)
++#define IMG_BPP_444 ((0x4)<<0)
++#define IMG_BPP_565 ((0x5)<<0)
++#define IMG_BPP_555 ((0x6)<<0)
++#define IMG_BPP_888 ((0x7)<<0)
++#endif
++
++
++enum cif_order422 {
++ CIF_YCBYCR = 0,
++ CIF_YCRYCB,
++ CIF_CBYCRY,
++ CIF_CRYCBY,
++};
++
++enum cifout_fmt {
++ CIF_YUV422 = 0,
++ CIF_YUV420_ODD,
++ CIF_YUV420_EVEN,
++};
++
++enum cifoper_mode {
++ OPER_PREVIEW = 0,
++ OPER_CAPTURE,
++};
++
++enum jpeg_resolution{
++ CAM_UXGA = 0, // 1600 X 1200,
++ CAM_SXGA, // 1280 X 1024, //1280 X 960
++ CAM_XGA, // 1024 X 768,
++ CAM_SVGA, // 800 X 600,
++ CAM_VGA, // 640 X 480,
++ CAM_QVGA, // 320 X 240,
++ CAM_QCIF, // 176 X 144,
++ CAM_MAX
++};
++
++enum tcc_effect_type{
++ TCC_EFFECT_NORMAL,
++ TCC_EFFECT_GRAY,
++ TCC_EFFECT_NEGATIVE,
++ TCC_EFFECT_SEPHIA,
++ TCC_EFFECT_AQUA,
++ TCC_EFFECT_GREEN,
++ TCC_EFFECT_SKETCH,
++ TCC_EFFECT_UNDEFINED
++};
++
++typedef struct _ZOOM_DATA
++{
++ unsigned short XOffset;
++ unsigned short YOffset;
++ unsigned short Src_HSize;
++ unsigned short Src_VSize;
++} ZOOM_DATA;
++
++typedef struct _FRAME_DATA
++{
++ unsigned short framex;
++ unsigned short framey;
++ unsigned short cap_x;
++ unsigned short cap_y;
++} FRAME_DATA;
++
++typedef struct {
++ unsigned int p_Y;
++ unsigned int p_Cb;
++ unsigned int p_Cr;
++}img_buf_t;
++
++typedef struct {
++ unsigned short source_x; /* CIF Input-Selection width/height */
++ unsigned short source_y;
++ unsigned short win_hor_ofst; /* CIF Input-Selection Hori/Vert Offset (ex. For Zoom)*/
++ unsigned short win_ver_ofst;
++
++ unsigned short scaler_x; /* CIF Scaler out */
++ unsigned short scaler_y;
++ unsigned short target_x; /* CIF Crop out :: real out */
++ unsigned short target_y;
++}cif_main_set;
++
++typedef struct
++{
++ unsigned short chromakey;
++
++ unsigned char mask_r;
++ unsigned char mask_g;
++ unsigned char mask_b;
++
++ unsigned char key_y;
++ unsigned char key_u;
++ unsigned char key_v;
++
++}si_chromakey_info;
++
++typedef struct
++{
++ unsigned short start_x;
++ unsigned short start_y;
++ unsigned short width;
++ unsigned short height;
++
++ unsigned int buff_offset;
++
++ si_chromakey_info chromakey_info;
++}cif_SuperImpose;
++
++enum capture_status{
++ CAPTURE_DONE = 0,
++ CAPTURE_NO_INT,
++ CAPTURE_OVERFLOW,
++ CAPTURE_NONE
++};
++
++typedef struct
++{
++ unsigned int *jpg_hdr_addr;
++ unsigned int jpg_hdr_len;
++ unsigned int *jpg_buf_addr;
++ unsigned int jpg_len;
++}jpeg_info;
++
++typedef struct cif_c_t {
++ enum cif_order422 order422;
++
++ unsigned char polarity_pclk;
++ unsigned char polarity_vsync;
++ unsigned char polarity_href;
++
++ enum cifoper_mode oper_mode;
++ unsigned char zoom_step; // for capture!!
++ cif_main_set main_set;
++
++
++ /* 2 pingpong Frame memory */
++ dma_addr_t base_buf;
++ unsigned int pp_totalsize;
++ unsigned char pp_num; /* used pingpong memory number */
++ img_buf_t preview_buf[TCC_CAMERA_MAX_BUFNBRS];
++ //img_buf_t rotate_buf[2];
++ img_buf_t capture_buf;
++
++ cif_SuperImpose si_overlay;
++
++ jpeg_info jpg_info;
++ enum cifout_fmt fmt;
++
++ volatile unsigned char now_frame_num; // current buffer_index
++
++ volatile unsigned char esd_restart;
++
++ //Retry Capture
++ volatile enum capture_status cap_status;
++ volatile unsigned char retry_cnt;
++} cif_cfg_t;
++
++/* NUM_CAMDMA_CHANNELS is the number of logical channels used for
++ * DMA data transfer.
++ */
++#define NUM_CAMDMA_CHANNELS 2
++/*
++ * info for buffer allocation
++ */
++struct cif_dma_buffer {
++ unsigned char *area; /* virtual pointer */
++ dma_addr_t addr; /* physical address */
++ size_t bytes; /* buffer size in bytes */
++ void *private_data; /* private for allocator; don't touch */
++};
++
++#if 0
++/* buffer info */
++
++struct cif_buffer_info {
++ int state; /* state of buffer */
++ unsigned long size; /* size of jpg frame */
++ struct timeval timestamp; /* timestamp */
++ unsigned long sequence; /* sequence number */
++};
++
++#endif
++
++enum tcc_cif_buffer_state {
++ TCC_CIF_BUF_UNUSED, /* not used */
++ TCC_CIF_BUF_QUEUED,
++ TCC_CIF_BUF_USING, /* currently grabbing / playing */
++ TCC_CIF_BUF_GRABBING,
++ TCC_CIF_BUF_DONE, /* done */
++ TCC_CIF_BUF_ERROR,
++};
++
++
++enum tcc_stream_state {
++ STREAM_OFF,
++ STREAM_INTERRUPT,
++ STREAM_ON,
++};
++
++
++/*
++ * Tracking of streaming I/O buffers.
++ */
++struct tccxxx_cif_buffer {
++ struct list_head buf_list;
++ struct v4l2_buffer v4lbuf;
++ enum tcc_cif_buffer_state state;
++// char *buffer; /* Where it lives in kernel space */
++ int mapcount;
++ unsigned long vma_use_count;
++ struct TCCxxxCIF *cam;
++};
++
++struct TCCxxxCIF{
++
++ cif_cfg_t cif_cfg;
++ /* frequncy (in Hz) of camera interface functional clock (ocp_clk) */
++ //unsigned long ocp_clk;
++
++ struct timer_list cam_timer;
++
++ struct list_head list;
++ struct list_head done_list;
++
++// struct cif_buffer buf[TCC_CAMERA_MAX_BUFNBRS];
++ //wkjung 0412
++ struct tccxxx_cif_buffer static_buf[TCC_CAMERA_MAX_BUFNBRS];
++ struct tccxxx_cif_buffer *buf;
++ struct cif_dma_buffer cif_buf;
++ unsigned int n_sbufs; /* How many we have */
++
++ wait_queue_head_t frame_wait; /* Waiting on frame data */
++ spinlock_t dev_lock; /* Access to device */
++ struct mutex lock;
++
++ enum tcc_stream_state stream_state;
++
++ int new;
++};
++
++
++#define VIDIOC_USER_CIF_OVERLAY _IOWR ('V', BASE_VIDIOC_PRIVATE, cif_SuperImpose)
++#define VIDIOC_USER_JPEG_CAPTURE _IOWR ('V', BASE_VIDIOC_PRIVATE+1, int)
++#define VIDIOC_USER_GET_CAPTURE_INFO _IOWR ('V', BASE_VIDIOC_PRIVATE+2, TCCXXX_JPEG_ENC_DATA)
++
++extern int tccxxx_cif_buffer_set(struct v4l2_requestbuffers *req);
++extern int tccxxx_cif_cam_restart(struct v4l2_pix_format *pix, unsigned long xclk);
++extern int tccxxx_cif_start_stream(void);
++extern int tccxxx_cif_stop_stream(void);
++extern void tccxxx_cif_set_overlay(void);
++extern int tccxxx_cif_set_effect (u8 nCameraEffect);
++extern int tccxxx_cif_capture(int quality);
++extern int tccxxx_cif_set_zoom(unsigned char arg);
++extern int tccxxx_cif_set_resolution(unsigned int pixel_fmt, unsigned short width, unsigned short height);
++extern int tccxxx_cif_open(void);
++extern int tccxxx_cif_close(void);
++extern int tccxxx_cif_init(void);
++
++#endif /* TCCXX_CIF_H */
+diff --git a/drivers/media/video/tcccam/tcc_cam_i2c.c b/drivers/media/video/tcccam/tcc_cam_i2c.c
+new file mode 100644
+index 0000000..ac36d30
+--- /dev/null
++++ b/drivers/media/video/tcccam/tcc_cam_i2c.c
+@@ -0,0 +1,478 @@
++/****************************************************************************
++ *
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++****************************************************************************/
++
++#include <bsp.h>
++#include "tcc_cam_i2c.h"
++#include <asm/delay.h>
++
++
++#include "sensor_if.h"
++
++#define I2C_WR 0
++#define I2C_RD 1
++
++static char I2C_use_flag;
++
++//Functions
++static unsigned char i2c_read(unsigned int i2ctgt, unsigned char SlaveAddr, char addr, unsigned char *ptr, unsigned char bytes);
++static unsigned char i2c_write(unsigned int i2ctgt, unsigned char SlaveAddr, char addr, unsigned char *ptr, unsigned char bytes);
++void i2c_init(void);
++static int i2c_register(unsigned int i2ctgt);
++int DDI_I2C_Initialize(void);
++
++
++typedef struct stI2C_Vector
++{
++ unsigned long int tgtaddr;
++ unsigned long int port;
++}tI2C_Vector;
++
++static unsigned int guiI2CTgt;
++
++static const tI2C_Vector I2C_VectorTable[I2C_MAX_VECTOR + 1][I2C_SIGNAL_BUS] =
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ {{0xF0102000, Hw0}, {0xF0102000, Hw1}}, //CODEC
++ {{0xF0102000, Hw0}, {0xF0102000, Hw1}}, //TVOUT
++ {{0xF0102000, Hw8}, {0xF0102000, Hw9}}, //TOUCH
++ {{0xF0102000, Hw8}, {0xF0102000, Hw9}}, //CAMERA
++ {{0xF0102000, Hw0}, {0xF0102000, Hw1}}, //I2C_MAX_VECTOR
++#else
++ {{HwGPADAT_Addr, Hw0}, {HwGPADAT_Addr, Hw1}}, //CODEC
++ {{HwGPADAT_Addr, Hw0}, {HwGPADAT_Addr, Hw1}}, //TVOUT
++ {{HwGPADAT_Addr, Hw8}, {HwGPADAT_Addr, Hw9}}, //TOUCH
++ {{HwGPADAT_Addr, Hw0}, {HwGPADAT_Addr, Hw1}}, //CAMERA
++ {{HwGPADAT_Addr, Hw0}, {HwGPADAT_Addr, Hw1}}, //I2C_MAX_VECTOR
++#endif
++};
++static tI2C_Vector I2C_Vector[I2C_SIGNAL_BUS];
++
++static void delay760(unsigned int count)
++{
++ #define DELAYCNT 1
++ for(count=DELAYCNT;count>0;count--) {
++ udelay(4);
++ }
++ #undef DELAYCNT
++}
++
++// start bit
++static void i2c_comm_s(void)
++{
++ i2c_wr;
++ i2c_clk_hi;
++ i2c_data_hi;
++ delay760(i2c_Tbuf);
++
++ i2c_wr;
++ i2c_data_lo;
++ delay760(i2c_Thold);
++ i2c_clk_lo;
++ delay760(i2c_Thold);
++}
++
++// data out
++static void i2c_out_byte(unsigned char *ptr)
++{
++ unsigned char i, temp;
++
++ i2c_wr;
++ for(i=0;i<8;i++)
++ {
++ temp = *ptr << i;
++ temp &= 0x80;
++ if(temp){
++ i2c_data_hi;
++ }else{
++ i2c_data_lo;
++ }
++ delay760(i2c_Tsetup);
++
++ i2c_clk_hi;
++ delay760(i2c_Thold);
++
++ i2c_clk_lo;
++ delay760(i2c_Thold);
++ }
++}
++
++// get acknowledge
++static unsigned char i2c_get_ack(void)
++{
++ unsigned char i=0;
++
++ i2c_rd;
++
++ i2c_clk_hi;
++ delay760(i2c_Tcatch);
++
++ i = (unsigned char)((*(volatile unsigned long int *)I2C_Vector[I2C_DATA].tgtaddr) & (I2C_Vector[I2C_DATA].port));
++ delay760(i2c_Tcatch);
++
++ i2c_clk_lo;
++ delay760(i2c_Thold);
++
++ return i;
++}
++
++
++// Input Byte
++static void i2c_in_byte(unsigned char *ptr)
++{
++ unsigned int i, temp=0;
++
++ i2c_rd;
++
++ for(i=0;i<8;i++)
++ {
++ i2c_clk_hi;
++ delay760(i2c_Tcatch);
++
++ temp = (unsigned int)( ( (*(volatile unsigned long int *)(I2C_Vector[I2C_DATA].tgtaddr)) & (I2C_Vector[I2C_DATA].port))) ? 1 : 0;
++
++ if(i == 0) *ptr = temp;
++ else *ptr = (*ptr << 1) | temp;
++ delay760(i2c_Tcatch);
++
++ i2c_clk_lo;
++ delay760(i2c_Thold);
++ }
++}
++
++// put acknowledge
++static void i2c_do_ack(unsigned char bit)
++{
++
++ i2c_wr;
++
++ if(bit){
++ i2c_data_hi;
++ }else{
++ i2c_data_lo;
++ }
++ delay760(i2c_Tsetup);
++
++ i2c_clk_hi;
++ delay760(i2c_Thold);
++
++ i2c_clk_lo;
++ delay760(i2c_Thold);
++}
++
++// stop bit HwGDATA_A |= CODEC_SDIN_SET;
++static void i2c_comm_p(void)
++{
++ i2c_wr;
++ i2c_data_lo;
++ delay760(i2c_Tsetup);
++
++ i2c_clk_hi;
++ delay760(i2c_Thold);
++
++ i2c_data_hi;
++ delay760(i2c_Tbuf);
++}
++
++
++void i2c_init(void)
++{
++ // transfer rate setting... 8bit
++ I2C_use_flag = I2C_FREE;
++}
++
++static void TC_TimeDly(int ticks){
++ int ms;
++ while(ticks --){
++ ms = 100;
++ while(ms --);
++ }
++}
++
++static unsigned char i2c_write(unsigned int i2ctgt, unsigned char SlaveAddr, char subaddr, unsigned char *ptr, unsigned char bytes )
++{
++ unsigned char SA = SlaveAddr | I2C_WR ;
++ unsigned char i;
++
++ //RETAILMSG(TRUE, (TEXT("Wavedev:::i2c_write\r\n")));
++
++ /* for prevent from access on same time */
++ while( I2C_use_flag == I2C_USED ) {
++ TC_TimeDly(1);
++ }
++ I2C_use_flag = I2C_USED;
++
++ i2c_register(i2ctgt);
++
++ i2c_wr;
++ i2c_clk_hi;
++ i2c_data_hi;
++ delay760(i2c_Tbuf);
++
++ i2c_comm_s();
++ i2c_out_byte(&SA); // slave address | write
++
++ if(i2c_get_ack() != i2c_ack)
++ {
++ i2c_comm_p();
++ I2C_use_flag = I2C_FREE;
++ return i2c_err;
++ }
++
++ if( subaddr != (char)I2C_SUBADDR_NOUSE )
++ {
++ i2c_out_byte((unsigned char*)&subaddr); // address
++
++ if(i2c_get_ack() != i2c_ack)
++ {
++ i2c_comm_p();
++ I2C_use_flag = I2C_FREE;
++ return i2c_err;
++ }
++ }
++
++ for(i=0; i<bytes ; i++)
++ {
++ i2c_out_byte(ptr);
++
++ if(i2c_get_ack()) ;
++ else ;
++
++ ptr++;
++ }
++
++ i2c_comm_p();
++
++ I2C_use_flag = I2C_FREE;
++ return i2c_ok;
++}
++
++static unsigned char i2c_read(unsigned int i2ctgt, unsigned char SlaveAddr, char subaddr, unsigned char *ptr, unsigned char bytes)
++{
++ unsigned char i;
++ unsigned char SA = SlaveAddr | I2C_WR ;
++
++ /* for prevent from access on same time */
++ while( I2C_use_flag == I2C_USED ) {
++ TC_TimeDly(1);
++ }
++ I2C_use_flag = I2C_USED;
++
++ i2c_register(i2ctgt);
++
++ if( subaddr != (char)I2C_SUBADDR_NOUSE )
++ {
++ i2c_wr;
++ i2c_clk_hi;
++ i2c_data_hi;
++ delay760(i2c_Tbuf);
++
++ i2c_comm_s();
++ i2c_out_byte(&SA); // address | write
++
++ if(i2c_get_ack() != i2c_ack)
++ {
++ i2c_comm_p();
++ I2C_use_flag = I2C_FREE;
++ return i2c_err;
++ }
++
++ i2c_out_byte((unsigned char*)&subaddr);
++
++ if(i2c_get_ack() != i2c_ack)
++ {
++ i2c_comm_p();
++ I2C_use_flag = I2C_FREE;
++ return i2c_err;
++ }
++ }
++
++ i2c_wr;
++ i2c_data_hi;
++ i2c_clk_hi;
++ delay760(i2c_Tbuf);
++
++ SA = SlaveAddr | I2C_RD ;
++ i2c_comm_s();
++ i2c_out_byte(&SA); // Addr | Read
++
++ if(i2c_get_ack() != i2c_ack)
++ {
++ i2c_comm_p();
++ I2C_use_flag = I2C_FREE;
++ return i2c_err;
++ }
++
++ for(i=0;i<bytes;i++)
++ {
++ i2c_in_byte(ptr);
++
++ if(i < (bytes-1)) i2c_do_ack(i2c_ack);
++ else i2c_do_ack(i2c_noack);
++
++ ptr++;
++ }
++
++ i2c_comm_p();
++
++ I2C_use_flag = I2C_FREE;
++ return i2c_ok;
++}
++
++static int i2c_register(unsigned int i2ctgt)
++{
++ guiI2CTgt = i2ctgt;
++
++ I2C_Vector[I2C_CLK] = I2C_VectorTable[i2ctgt][I2C_CLK];
++ I2C_Vector[I2C_DATA] = I2C_VectorTable[i2ctgt][I2C_DATA];
++
++ return 1;
++}
++
++
++
++#ifdef USING_HW_I2C
++static void OpenI2C(unsigned int i2c_clock)
++{
++ int iCnt;
++
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ unsigned int i2c_clk_input_freq, prescale;
++
++ //tca_ckc_setswreset(RB_I2CCONTROLLER, OFF);
++ //tca_ckc_setswreset(RB_I2CCONTROLLER, ON);
++
++ tca_ckc_setiobus(RB_I2CCONTROLLER, ENABLE);
++
++ BITCSET(HwGPIOA->GPFN1, HwPORTCFG_GPFN0_MASK, HwPORTCFG_GPFN0(1)); // A[8] SCL1
++ BITCSET(HwGPIOA->GPFN1, HwPORTCFG_GPFN1_MASK, HwPORTCFG_GPFN1(1)); // A[9] SDA1
++
++
++ /* I2C IO-bus enable */
++ tca_ckc_setiobus(RB_I2CCONTROLLER, ENABLE);
++
++ /* get I2C bus clock
++ * bootloader set I2C bus clock
++ */
++ i2c_clk_input_freq = tca_ckc_getperi(PERI_I2C);
++
++ prescale = ((i2c_clk_input_freq / 10) / (i2c_clock * 5)) - 1;
++ HwI2CMASTER1->PRES = prescale;
++ HwI2CMASTER1->CTRL = Hw7 | Hw6 | HwZERO; // start enable, stop enable, 8bit mode
++ BITSET(HwI2CMASTER1->CMD, Hw0); // clear pending interrupt
++
++ printk("i2c-1 SCK(%d) <-- input clk(%dKhz), prescale(%d)\n", i2c_clock, i2c_clk_input_freq, prescale);
++
++#else
++
++ IO_CKC_EnableBUS_I2C();
++ BITCLR(HwPCK_I2C, Hw28); // enable
++ IO_CKC_SetI2CClock(41000); // 196.8Mhz / 48 = 4.1Mhz
++
++ BITSET(HwSWRESET, HwSWRESET_I2C_ON);
++ BITCLR(HwSWRESET, HwSWRESET_I2C_ON);
++
++ BITCSET(HwI2CMCH0_PRES, 0xFFFFFFFF, 0x0000003C); // 4.1Mhz / 61 = 68.33Khz
++ BITSET(HwI2CMCH0_CTRL, HwI2CMCH0_CTRL_EN_ON);
++
++ for (iCnt=0;iCnt<10;iCnt++);
++
++ BITCLR(HwI2CMCH0_CTRL, HwI2CMCH0_CTRL_EN_ON);
++ BITCLR(HwPCK_I2C, Hw28); // enable
++ IO_CKC_DisableBUS_I2C();
++#endif
++}
++
++
++static void CloseI2C(void)
++{
++/*
++ IIC_STOP();
++
++ BITCLR(HwI2CMCH0_CTRL, HwI2CMCH0_CTRL_IEN_ON);
++ BITCLR(HwI2CMCH0_CTRL, HwI2CMCH0_CTRL_EN_ON);
++ BITCLR(HwPCK_I2C, HwPCK_I2C_EN_EN);
++ IO_CKC_DisableBUS_I2C();
++ */
++}
++#endif
++
++int DDI_I2C_Initialize(void)
++{
++#ifdef USING_HW_I2C
++ OpenI2C(200); //200Khz
++#endif
++
++ return 0;
++}
++
++
++int DDI_I2C_Terminate(void)
++{
++ //CloseI2C();
++
++ return 0;
++}
++
++
++
++static int DDI_I2C_Write(unsigned int uiFlag, unsigned int uiHbyte, unsigned int uiLbyte)
++{
++// I2C_SW_WRITE_t *I2C_SwWrite;
++ int iReturn = 0;
++ unsigned char ucSzDataBuff[2];//, ucSize;
++ char cSubAddr;
++ char bytes;
++
++ if(uiFlag == I2C_CAMERA)
++ {
++ cSubAddr = (char)uiHbyte;
++
++ #if defined(CONFIG_VIDEO_CAMERA_SENSOR_MT9D111)
++ ucSzDataBuff[0] =(unsigned char *)( (uiLbyte&0xff00)>>8);
++ ucSzDataBuff[1]= (unsigned char *)(uiLbyte&0x00ff);
++ bytes = 2;
++ #else
++ ucSzDataBuff[0] = (unsigned char)uiLbyte;
++ bytes = 1;
++ #endif
++
++ iReturn = i2c_write(uiFlag, (unsigned char)SENSOR_I2C_ADDR, cSubAddr, ucSzDataBuff, bytes);
++ }
++
++ return iReturn;
++}
++
++static int DDI_I2C_Read(unsigned int uiFlag, unsigned int uiHbyte, unsigned int uiLbyte)
++{
++
++ return 0;
++}
++
++//***********************************************************
++int CAMERA_SEND_CMD(unsigned char hb, unsigned short lb)
++{
++ int err=0;
++
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ BITCSET(HwGPIOA->GPFN1, HwPORTCFG_GPFN0_MASK, HwPORTCFG_GPFN0(0)); // A[8] SCL1
++ BITCSET(HwGPIOA->GPFN1, HwPORTCFG_GPFN1_MASK, HwPORTCFG_GPFN1(0)); // A[9] SDA1
++ err= DDI_I2C_Write(I2C_CAMERA, hb, lb);
++ BITCSET(HwGPIOA->GPFN1, HwPORTCFG_GPFN0_MASK, HwPORTCFG_GPFN0(1)); // A[8] SCL1
++ BITCSET(HwGPIOA->GPFN1, HwPORTCFG_GPFN1_MASK, HwPORTCFG_GPFN1(1)); // A[9] SDA1
++#else
++ BITCSET(HwPORTCFG11, (0x0f<<4),HwZERO);
++ err= DDI_I2C_Write(I2C_CAMERA, hb, lb);
++ BITCSET(HwPORTCFG11, (0x0f<<4),Hw0<<4);
++#endif
++
++ udelay(500);
++
++ return err;
++}
++
++/* end of file */
++
+diff --git a/drivers/media/video/tcccam/tcc_cam_i2c.h b/drivers/media/video/tcccam/tcc_cam_i2c.h
+new file mode 100644
+index 0000000..54511fa
+--- /dev/null
++++ b/drivers/media/video/tcccam/tcc_cam_i2c.h
+@@ -0,0 +1,104 @@
++/****************************************************************************
++ * TCC Version 0.6
++ * Copyright (c) telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++****************************************************************************/
++
++#ifndef __TCC7901_I2C_H_char__
++#define __TCC7901_I2C_H_char__
++
++#if defined(CONFIG_ARCH_TCC92X)
++#include <mach/bsp.h>
++#elif defined(CONFIG_ARCH_TCC79X)
++#include <mach/tcc79x.h>
++#endif
++#include "sensor_if.h"
++
++#define IO_CKC_EnableBUS_I2C() (BITSET(HwBCLKCTR, HwBCLKCTR_I2C_ON))
++#define IO_CKC_DisableBUS_I2C() (BITCLR(HwBCLKCTR, HwBCLKCTR_I2C_ON))
++
++#define IO_CKC_Fxin 120000
++
++/************************************************************************
++ * I2C define
++ ***********************************************************************/
++#define i2c_ack 0 // i2c acknowledgement
++#define i2c_noack 1 // i2c no acknowledgement
++#define i2c_err 0 // i2c error occurs
++#define i2c_ok 1 // i2c error does not occurs
++
++
++// I2C-bus standard mode timing setting
++#define i2c_Tbuf 400 //200
++#define i2c_Tsetup 8 //4//8 // above min 250ns
++#define i2c_Thold 200 //100 // the fm_Thold is a basic time as above min 5us
++#define i2c_Tcatch 100 //50 // the half of the i2c_Thold
++
++#define I2C_SUBADDR_NOUSE -1
++
++// Message
++#define I2C_FREE 0
++#define I2C_USED 1
++
++
++
++enum
++{
++ I2C_CODEC,
++ I2C_TVOUT,
++ I2C_TOUCH,
++ I2C_CAMERA,
++ I2C_MAX_VECTOR
++} ;
++
++enum
++{
++ I2C_CLK,
++ I2C_DATA,
++ I2C_SIGNAL_BUS
++};
++
++#define i2c_wr (*(volatile unsigned long int *)(I2C_Vector[I2C_DATA].tgtaddr+0x04) |= (I2C_Vector[I2C_DATA].port));
++#define i2c_rd (*(volatile unsigned long int *)(I2C_Vector[I2C_DATA].tgtaddr+0x04) &= ~(I2C_Vector[I2C_DATA].port));
++#define i2c_clk_hi (*(volatile unsigned long int *)(I2C_Vector[I2C_CLK].tgtaddr) |= (I2C_Vector[I2C_CLK].port));
++#define i2c_clk_lo (*(volatile unsigned long int *)(I2C_Vector[I2C_CLK].tgtaddr) &= ~(I2C_Vector[I2C_CLK].port));
++#define i2c_data_hi (*(volatile unsigned long int *)(I2C_Vector[I2C_DATA].tgtaddr) |= (I2C_Vector[I2C_DATA].port));
++#define i2c_data_lo (*(volatile unsigned long int *)(I2C_Vector[I2C_DATA].tgtaddr) &= ~(I2C_Vector[I2C_DATA].port));
++
++
++//**********************************************************************
++#define codec_slaveaddr 0x34 //WM8731 / TLV320 CODEC slave addr
++#define touch_slaveaddr 0x90 //TSC2003 A/D conveter slave addr
++
++
++typedef struct I2C_SW_READ_s
++{
++ unsigned int i2ctgt;
++ unsigned char SlaveAddr;
++ char subaddr;
++ unsigned char *ptr;
++ unsigned char bytes;
++ unsigned char i2c_return;
++} I2C_SW_READ_t;
++
++typedef struct I2C_SW_WRITE_s
++{
++ unsigned int i2ctgt;
++ unsigned char SlaveAddr;
++ char subaddr;
++ unsigned char *ptr;
++ unsigned char bytes;
++ unsigned char i2c_return;
++} I2C_SW_WRITE_t;
++
++
++//***********************************************************************
++extern void i2c_init(void);
++extern int DDI_I2C_Initialize(void);
++extern int DDI_I2C_Terminate(void);
++
++
++
++#endif /*__TCC7901_I2C_H_char__*/
++
+diff --git a/drivers/media/video/tcccam/tcc_cam_inc.h b/drivers/media/video/tcccam/tcc_cam_inc.h
+new file mode 100644
+index 0000000..44b895d
+--- /dev/null
++++ b/drivers/media/video/tcccam/tcc_cam_inc.h
+@@ -0,0 +1,17 @@
++/****************************************************************************
++ * TCC Version 0.6
++ * Copyright (c) telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++****************************************************************************/
++#include <mach/memory.h>
++
++
++/* memory allocation */
++#define PMEM_ADSP_BASE TCC_VPU_OFFSET
++
++#define PREVIEW_MEM 0x800000 // 8MB
++#define CAPTURE_MEM 0x600000 //0x600000 //6144*1024
++#define JPEG_MEM 0x200000 //0x200000 //2048*1024
++#define PA_VIDEO_BASE PMEM_ADSP_BASE
++
+diff --git a/drivers/media/video/tcccam/tdd_cif.c b/drivers/media/video/tcccam/tdd_cif.c
+new file mode 100644
+index 0000000..d70bf47
+--- /dev/null
++++ b/drivers/media/video/tcccam/tdd_cif.c
+@@ -0,0 +1,2881 @@
++/************************************************************************
++* Telechips Multi Media Player
++* ------------------------------------------------
++*
++* FUNCTION : CAMERA INTERFACE API
++* MODEL : DMP
++* CPU NAME : TCCXXX
++* SOURCE : tdd_cif.c
++*
++* START DATE : 2008. 4. 17.
++* MODIFY DATE :
++* DEVISION : DEPT. SYSTEM 3-2 TEAM
++* : TELECHIPS, INC.
++************************************************************************/
++#include <linux/delay.h>
++#include <asm/system.h>
++#include <mach/hardware.h>
++#include <asm/io.h>
++
++#include <bsp.h>
++
++#include "sensor_if.h"
++#include "cam.h"
++#include "cam_reg.h"
++#include "tdd_cif.h"
++
++#if defined(CONFIG_ARCH_TCC8900)
++#include <mach/tcc_pca953x.h>
++#endif
++
++
++#if defined(CONFIG_ARCH_TCC92X)
++#define CAM_PWR_ENABLE() (HwGPIOD->GPEN |= Hw10); (HwGPIOD->GPDAT |= Hw10);
++#define CAM_PWR_DISABLE() (HwGPIOD->GPEN |= Hw10); (HwGPIOD->GPDAT &= ~Hw10);
++#define CAM_PWRDN_ENABLE() (HwGPIOF->GPEN |= Hw21); (HwGPIOF->GPDAT |= Hw21);
++#define CAM_PWRDN_DISABLE() (HwGPIOF->GPEN |= Hw21); (HwGPIOF->GPDAT &= ~Hw21);
++#define CAM_RESET_HIGH() (HwGPIOE->GPEN |= Hw2); (HwGPIOE->GPDAT |= Hw2);
++#define CAM_RESET_LOW() (HwGPIOE->GPEN |= Hw2); (HwGPIOE->GPDAT &= ~Hw2);
++//#define CAM_MCLK_ENABLE() BITSET(HwCIF->HwPCK_CAM, HwPCK_EN_EN);
++//#define CAM_MCLK_DISABLE() BITCLR(HwCIF->HwPCK_CAM, HwPCK_EN_EN);
++#elif defined(CONFIG_ARCH_TCC8900)
++#define CAM_PWR_ENABLE() TDD_CIF_PWRCtrl(1);
++#define CAM_PWR_DISABLE() TDD_CIF_PWRCtrl(0);
++#define CAM_PWRDN_ENABLE()
++#define CAM_PWRDN_DISABLE()
++#define CAM_RESET_HIGH() (HwGPIOE->GPEN |= Hw26); (HwGPIOE->GPDAT |= Hw26);
++#define CAM_RESET_LOW() (HwGPIOE->GPEN |= Hw26); (HwGPIOE->GPDAT &= ~Hw26);
++//#define CAM_MCLK_ENABLE() BITSET(HwCIF->HwPCK_CAM, HwPCK_EN_EN);
++//#define CAM_MCLK_DISABLE() BITCLR(HwCIF->HwPCK_CAM, HwPCK_EN_EN);
++#elif defined(CONFIG_ARCH_TCC79X)
++#define CAM_PWR_ENABLE()
++#define CAM_PWR_DISABLE()
++ #define CAM_PWRDN_ENABLE() (HwGPFEN |= Hw1); (HwGPFDAT |= Hw1);
++#define CAM_PWRDN_DISABLE() (HwGPFEN |= Hw1); (HwGPFDAT &= ~Hw1);
++#define CAM_RESET_HIGH() (HwGPEEN |= Hw9); (HwGPEDAT |= Hw9);
++#define CAM_RESET_LOW() (HwGPEEN |= Hw9); (HwGPEDAT &= ~Hw9);
++//#define CAM_MCLK_ENABLE() BITSET(HwPCK_CAM, HwPCK_EN_EN);
++//#define CAM_MCLK_DISABLE() BITCLR(HwPCK_CAM, HwPCK_EN_EN);
++#endif
++
++#if defined(CONFIG_ARCH_TCC8900)
++void TDD_CIF_PWRCtrl(int pwrctrl_onoff)
++{
++ int state;
++ if (pwrctrl_onoff)
++ state = ON;
++ else
++ state = OFF;
++
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, Hw3, OUTPUT, state, SET_DIRECTION|SET_VALUE);
++}
++#endif
++
++void cif_delay(int ms)
++{
++#if 1 //ZzaU
++ unsigned int msec;
++
++ msec = ms / 10; //10msec unit
++
++ if(!msec)
++ msleep(1);
++ else
++ msleep(msec);
++#else
++ int totCnt, iCnt, temp = 0;
++
++ totCnt = ms*20000;
++ for(iCnt = 0; iCnt < totCnt; iCnt++)
++ {
++ temp++;
++ }
++#endif
++}
++
++void TDD_CIF_Reset(void)
++{
++ CAM_RESET_HIGH();
++ cif_delay(15);//msleep(1);
++ //CAM_RESET_LOW();
++ //cif_delay(15);//msleep(15);
++ //CAM_RESET_HIGH();
++ //cif_delay(15);//msleep(15);
++ //CAM_RESET_LOW();
++ //cif_delay(15);//msleep(15);
++ //CAM_RESET_HIGH();
++ //cif_delay(15);//msleep(15);
++
++}
++
++void TDD_CIF_Initialize()
++{
++#if 0
++ //(CONFIG_ARCH_TCC92X)
++ //DMA transfer Á¾·áÀÌÈÄ ready¸¦ ±â´Ù¸®Áö ¾Ê°í writeµÈ°ÍÀ¸·Î ÆÇ´ÜÇÏ¿© ¹Ù·Î ´ÙÀ½ transferÁøÇà..
++ BITCSET(HwDDI_CACHE->DDIC_CTRL, HwDDIC_CTRL_BW, 0x80000000);
++
++ //GPIO Functional setting!!
++ BITCSET(HwGPIOE->GPFN1, 0xFFFF0000, 0x11110000);
++ HwGPIOE->GPFN2 = 0x11111111;
++
++ //PWDN/Reset/Power Normal GPIO setting!!
++ HwGPIOF->GPFN2 &= ~0x00F00000; // PWDN
++ HwGPIOE->GPFN0 &= ~0x00000F00; // Reset
++ HwGPIOD->GPFN1 &= ~0x00000F00; // Power Ctrl
++
++ // Set Pull-Up/Down Control
++ BITSET( HwGPIOE->GPPD0, 0xAA000000 ); // D0~D3
++ BITSET( HwGPIOE->GPPD1, 0x000028AA ); // D4~D7, VS, HS
++#endif
++
++ //(CONFIG_ARCH_TCC8900)
++
++ //DMA transfer Á¾·áÀÌÈÄ ready¸¦ ±â´Ù¸®Áö ¾Ê°í writeµÈ°ÍÀ¸·Î ÆÇ´ÜÇÏ¿© ¹Ù·Î ´ÙÀ½ transferÁøÇà..
++ BITCSET(HwDDI_CACHE->DDIC_CTRL, HwDDIC_CTRL_BW, 0x80000000);
++
++#if 0
++ //This register doesn't exist.
++ //BITSET(HwBCLKCTR, HwBCLKCTR_CIC_ON|Hw30); //CAM and MailBox
++ BITSET(HwCKC->PCLK_CIFMC, Hw28);
++#endif
++
++ //CPD[0] - CPD[3]
++ BITCSET(HwGPIO->GPEFN1, 0xFFFF0000, Hw28|Hw24|Hw20|Hw16);
++ //CCKI, CVS, CHS, CCKO, CPD[7] - CPD[4]
++ BITCSET(HwGPIO->GPEFN2, 0xFFFFFFFF, Hw28|Hw24|Hw20|Hw16|Hw12|Hw8|Hw4|Hw0);
++ BITCLR(HwGPIO->GPEEN, 0x7FF000); // CPD Data bus as Input mode
++ BITSET(HwGPIO->GPEEN, 0x800000); // CCKO output mode
++
++ //PWDN/Reset/Power Normal GPIO setting!!
++ //Reset CAM_RST
++ BITCSET(HwGPIO->GPEFN3, (Hw12-Hw8), 0);
++ BITSET(HwGPIO->GPEEN, Hw26);
++
++ // Set Pull-Up/Down Control
++ BITCSET(HwGPIO->GPEPD0, 0xFF000000, 0xAA000000); // Camera Port D0~D3 Pull down
++ BITCSET(HwGPIO->GPEPD1, 0x00003FFF, 0x00002AAA); // Camera Port D4~D7, cvs,chs,cki Pull down
++
++#if 0
++ //Enable Scaler Clock divider enable register
++ BITSET(HwCKC->PCLK_CIFSC, Hw28);
++
++ //SWReset for DDIBUS(Camera interface)
++ BITSET(HwDDI_CONFIG->SWRESET, Hw0);
++ BITCLR(HwDDI_CONFIG->SWRESET, Hw0);
++#endif
++
++ CAM_PWR_ENABLE();
++ CAM_PWRDN_DISABLE();
++ cif_delay(10);
++ CAM_RESET_LOW();
++ cif_delay(10);
++
++#if defined(CONFIG_VIDEO_CAMERA_SENSOR_MT9P111)
++ cif_delay(20);
++ CIF_Open();
++ cif_delay(20);
++
++//start standby!!
++ CAM_PWRDN_ENABLE();
++ cif_delay(20);
++
++ CIF_Close();
++ cif_delay(20);
++ CAM_PWRDN_DISABLE();
++ cif_delay(20);
++//end standby!!
++#else
++#if !defined(CONFIG_VIDEO_CAMERA_SENSOR_MT9D111) //Not apply for mt9d111!!
++ CAM_PWRDN_ENABLE();
++ cif_delay(5);
++#endif
++#endif
++
++ CIF_Open();
++ cif_delay(40);
++
++ TDD_CIF_Reset();
++}
++
++void TDD_CIF_Termination(void)
++{
++ CIF_ONOFF(OFF);
++
++ CAM_RESET_LOW()
++ CAM_PWR_DISABLE();
++ CAM_PWRDN_DISABLE();
++
++ CIF_Close();
++
++ msleep(5);
++}
++
++void TDD_CIF_ONOFF(unsigned int uiOnOff)
++{
++ CIF_ONOFF(uiOnOff);
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setInfo
++//
++// DESCRIPTION
++// set CIF register : HwICPCR1
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetInfo(unsigned int uiFlag, unsigned int uiBypass, unsigned int uiBypassBusSel,
++ unsigned int uiColorPattern, unsigned int uiPatternFormat, unsigned int uiRGBMode,
++ unsigned int uiRGBBitMode, unsigned int uiColorSequence, unsigned int uiBusOrder)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ // 1. HwICPCR1_BP Hw15 // Bypass
++ if(uiFlag & SET_CIF_BYPASS_MODE)
++ {
++ BITCSET(HwCIF->ICPCR1, HwICPCR1_BP, (uiBypass << 15));
++ }
++
++ // 2. HwICPCR1_BBS_LSB8 Hw14 // When bypass 16bits mode, LSB 8bits are stored in first
++ if(uiFlag & SET_CIF_BYPASS_BUS)
++ {
++ BITCSET(HwCIF->ICPCR1, HwICPCR1_BBS_LSB8, (uiBypassBusSel << 14));
++ }
++
++ // 3. HwICPCR1_CP_RGB Hw12 // RGB(555,565,bayer) color pattern
++ if(uiFlag & SET_CIF_COLOR_PATTERN)
++ {
++ BITCSET(HwCIF->ICPCR1, HwICPCR1_CP_RGB, (uiColorPattern << 12));
++ }
++
++ // 4.
++ // HwICPCR1_PF_444 HwZERO // 4:4:4 format
++ // HwICPCR1_PF_422 Hw10 // 4:2:2 format
++ // HwICPCR1_PF_420 Hw11 // 4:2:0 format or RGB(555,565,bayer) mode
++ if(uiFlag & SET_CIF_PATTERN_FORMAT)
++ {
++ BITCSET(HwCIF->ICPCR1, (HwICPCR1_PF_420|HwICPCR1_PF_422), (uiPatternFormat << 10));
++ }
++
++ // 5.
++ // HwICPCR1_RGBM_BAYER HwZERO // Bayer RGB Mode
++ // HwICPCR1_RGBM_RGB555 Hw8 // RGB555 Mode
++ // HwICPCR1_RGBM_RGB565 Hw9 // RGB565 Mode
++ if(uiFlag & SET_CIF_RGB_MODE)
++ {
++ BITCSET(HwCIF->ICPCR1, (HwICPCR1_RGBM_RGB555|HwICPCR1_RGBM_RGB565), (uiRGBMode << 8));
++ }
++
++ // 6.
++ // HwICPCR1_RGBBM_16 HwZERO // 16bit mode
++ // HwICPCR1_RGBBM_8DISYNC Hw6 // 8bit disable sync
++ // HwICPCR1_RGBBM_8 Hw7 // 8bit mode
++ if(uiFlag & SET_CIF_RGBBIT_MODE)
++ {
++ BITCSET(HwCIF->ICPCR1, (HwICPCR1_RGBBM_8DISYNC|HwICPCR1_RGBBM_8), (uiRGBBitMode << 6));
++ }
++
++ // 7. CS
++ // HwICPCR1_CS_RGBMG HwZERO // 555RGB:RGB(MG), 565RGB:RGB, 444/422/420:R/Cb/U first, Bayer RGB:BG->GR, CCIR656:YCbYCr
++ // HwICPCR1_CS_RGBLG Hw4 // 555RGB:RGB(LG), 565RGB:RGB, 444/422/420:R/Cb/U first, Bayer RGB:GR->BG, CCIR656:YCrYCb
++ // HwICPCR1_CS_BGRMG Hw5 // 555RGB:BGR(MG), 565RGB:BGR, 444/422/420:B/Cr/V first, Bayer RGB:RG->GB, CCIR656:CbYCrY
++ // HwICPCR1_CS_BGRLG (Hw5|Hw4) // 555RGB:BGR(LG), 565RGB:BGR, 444/422/420:B/Cr/V first, Bayer RGB:GB->RG, CCIR656:CrYCbY
++ if(uiFlag & SET_CIF_COLOR_SEQUENCE)
++ {
++ BITCSET(HwCIF->ICPCR1, HwICPCR1_CS_BGRLG, (uiColorSequence << 4));
++ }
++
++ // 8. HwICPCR1_BO_SW Hw2 // Switch the MSB/LSB 8bit Bus
++ if(uiFlag & SET_CIF_BUS_ORDER)
++ {
++ BITCSET(HwCIF->ICPCR1, HwICPCR1_BO_SW, (uiBusOrder << 2));
++ }
++#else // (CONFIG_ARCH_TCC79X)
++ // 1. HwICPCR1_BP Hw15 // Bypass
++ if(uiFlag & SET_CIF_BYPASS_MODE)
++ {
++ BITCSET(HwICPCR1, HwICPCR1_BP, (uiBypass << 15));
++ }
++
++ // 2. HwICPCR1_BBS_LSB8 Hw14 // When bypass 16bits mode, LSB 8bits are stored in first
++ if(uiFlag & SET_CIF_BYPASS_BUS)
++ {
++ BITCSET(HwICPCR1, HwICPCR1_BBS_LSB8, (uiBypassBusSel << 14));
++ }
++
++ // 3. HwICPCR1_CP_RGB Hw12 // RGB(555,565,bayer) color pattern
++ if(uiFlag & SET_CIF_COLOR_PATTERN)
++ {
++ BITCSET(HwICPCR1, HwICPCR1_CP_RGB, (uiColorPattern << 12));
++ }
++
++ // 4.
++ // HwICPCR1_PF_444 HwZERO // 4:4:4 format
++ // HwICPCR1_PF_422 Hw10 // 4:2:2 format
++ // HwICPCR1_PF_420 Hw11 // 4:2:0 format or RGB(555,565,bayer) mode
++ if(uiFlag & SET_CIF_PATTERN_FORMAT)
++ {
++ BITCSET(HwICPCR1, (HwICPCR1_PF_420|HwICPCR1_PF_422), (uiPatternFormat << 10));
++ }
++
++ // 5.
++ // HwICPCR1_RGBM_BAYER HwZERO // Bayer RGB Mode
++ // HwICPCR1_RGBM_RGB555 Hw8 // RGB555 Mode
++ // HwICPCR1_RGBM_RGB565 Hw9 // RGB565 Mode
++ if(uiFlag & SET_CIF_RGB_MODE)
++ {
++ BITCSET(HwICPCR1, (HwICPCR1_RGBM_RGB555|HwICPCR1_RGBM_RGB565), (uiRGBMode << 8));
++ }
++
++ // 6.
++ // HwICPCR1_RGBBM_16 HwZERO // 16bit mode
++ // HwICPCR1_RGBBM_8DISYNC Hw6 // 8bit disable sync
++ // HwICPCR1_RGBBM_8 Hw7 // 8bit mode
++ if(uiFlag & SET_CIF_RGBBIT_MODE)
++ {
++ BITCSET(HwICPCR1, (HwICPCR1_RGBBM_8DISYNC|HwICPCR1_RGBBM_8), (uiRGBBitMode << 6));
++ }
++
++ // 7. CS
++ // HwICPCR1_CS_RGBMG HwZERO // 555RGB:RGB(MG), 565RGB:RGB, 444/422/420:R/Cb/U first, Bayer RGB:BG->GR, CCIR656:YCbYCr
++ // HwICPCR1_CS_RGBLG Hw4 // 555RGB:RGB(LG), 565RGB:RGB, 444/422/420:R/Cb/U first, Bayer RGB:GR->BG, CCIR656:YCrYCb
++ // HwICPCR1_CS_BGRMG Hw5 // 555RGB:BGR(MG), 565RGB:BGR, 444/422/420:B/Cr/V first, Bayer RGB:RG->GB, CCIR656:CbYCrY
++ // HwICPCR1_CS_BGRLG (Hw5|Hw4) // 555RGB:BGR(LG), 565RGB:BGR, 444/422/420:B/Cr/V first, Bayer RGB:GB->RG, CCIR656:CrYCbY
++ if(uiFlag & SET_CIF_COLOR_SEQUENCE)
++ {
++ BITCSET(HwICPCR1, HwICPCR1_CS_BGRLG, (uiColorSequence << 4));
++ }
++
++ // 8. HwICPCR1_BO_SW Hw2 // Switch the MSB/LSB 8bit Bus
++ if(uiFlag & SET_CIF_BUS_ORDER)
++ {
++ BITCSET(HwICPCR1, HwICPCR1_BO_SW, (uiBusOrder << 2));
++ }
++
++#endif
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setCtrl
++//
++// DESCRIPTION
++// set CIF register : HwICPCR1
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetCtrl(unsigned int uiFlag, unsigned int uiPWDN, unsigned int uiBypass_Scaler,
++ unsigned int uiPXCLK_POL, unsigned int uiSKPF, unsigned int uiM420_FC, unsigned int uiC656)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ // 1. HwICPCR1_PWD Power down mode in camera >> 0:Disable, 1:Power down mode , This power down mode is connected the PWDN of camera sensor
++ if(uiFlag & SET_CIF_PWDN)
++ {
++ BITCSET(HwCIF->ICPCR1, HwICPCR1_PWD, (uiPWDN << 30));
++ }
++
++ // 2. HwICPCR1_BPS Hw23 // Bypass Scaler >> 0:Non, 1:Bypass //BP_SCA
++ if(uiFlag & SET_CIF_BYPASS_SCALER)
++ {
++ BITCSET(HwCIF->ICPCR1, HwICPCR1_BPS, (uiBypass_Scaler << 23));
++ }
++
++ // 3. HwICPCR1_POL Hw21 // PXCLK Polarity >> 0:Positive edge, 1:Negative edge
++ if(uiFlag & SET_CIF_PXCLK_POL)
++ {
++ BITCSET(HwCIF->ICPCR1, HwICPCR1_POL, (uiPXCLK_POL << 21));
++ }
++
++ // 4. HwICPCR1_SKPF // Skip Frame >> 0~7 #Frames skips [20:18]
++ if(uiFlag & SET_CIF_SKPF)
++ {
++ BITCSET(HwCIF->ICPCR1, HwICPCR1_SKPF, (uiSKPF << 18));
++ }
++
++ // 5.
++ // HwICPCR1_M420_ZERO HwZERO // Format Convert (YUV422->YUV420) , Not-Convert
++ // HwICPCR1_M420_ODD Hw17 // converted in odd line skip // 10
++ // HwICPCR1_M420_EVEN (Hw17|Hw16) // converted in even line skip //11
++ if(uiFlag & SET_CIF_M42_FC)
++ {
++ BITCSET(HwCIF->ICPCR1, HwICPCR1_M420_EVEN, (uiM420_FC << 16));
++ }
++
++ // 7. #define HwICPCR1_C656 Hw13 // Convert 656 format 0:Disable, 1:Enable
++ if(uiFlag & SET_CIF_C656)
++ {
++ BITCSET(HwCIF->ICPCR1, HwICPCR1_C656, (uiC656 << 13)); // PCIF->ICPCR1
++ }
++#else //(CONFIG_ARCH_TCC79X)
++ // 1. HwICPCR1_PWD Power down mode in camera >> 0:Disable, 1:Power down mode , This power down mode is connected the PWDN of camera sensor
++ if(uiFlag & SET_CIF_PWDN)
++ {
++ BITCSET(HwICPCR1, HwICPCR1_PWD, (uiPWDN << 30));
++ }
++
++ // 2. HwICPCR1_BPS Hw23 // Bypass Scaler >> 0:Non, 1:Bypass //BP_SCA
++ if(uiFlag & SET_CIF_BYPASS_SCALER)
++ {
++ BITCSET(HwICPCR1, HwICPCR1_BPS, (uiBypass_Scaler << 23));
++ }
++
++ // 3. HwICPCR1_POL Hw21 // PXCLK Polarity >> 0:Positive edge, 1:Negative edge
++ if(uiFlag & SET_CIF_PXCLK_POL)
++ {
++ BITCSET(HwICPCR1, HwICPCR1_POL, (uiPXCLK_POL << 21));
++ }
++
++ // 4. HwICPCR1_SKPF // Skip Frame >> 0~7 #Frames skips [20:18]
++ if(uiFlag & SET_CIF_SKPF)
++ {
++ BITCSET(HwICPCR1, HwICPCR1_SKPF, (uiSKPF << 18));
++ }
++
++ // 5.
++ // HwICPCR1_M420_ZERO HwZERO // Format Convert (YUV422->YUV420) , Not-Convert
++ // HwICPCR1_M420_ODD Hw17 // converted in odd line skip // 10
++ // HwICPCR1_M420_EVEN (Hw17|Hw16) // converted in even line skip //11
++ if(uiFlag & SET_CIF_M42_FC)
++ {
++ BITCSET(HwICPCR1, HwICPCR1_M420_EVEN_SKIP, (uiM420_FC << 16));
++ }
++
++ // 7. #define HwICPCR1_C656 Hw13 // Convert 656 format 0:Disable, 1:Enable
++ if(uiFlag & SET_CIF_C656)
++ {
++ BITCSET(HwICPCR1, HwICPCR1_C656, (uiC656 << 13)); // PCIF->ICPCR1
++ }
++#endif
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setTransfer
++//
++// DESCRIPTION
++// CIF transef mode setting
++// set CIF register : HwCDCR1
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetTransfer(unsigned int uiFlag, unsigned int uiBurst, unsigned int uiLock, unsigned int uiTransMode)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ //HwCDCR1_TM_INC Hw3 // INC Transfer
++ if(uiFlag & SET_CIF_TRANSFER_MODE)
++ {
++ BITCSET(HwCIF->CDCR1, HwCDCR1_TM_INC, (uiTransMode << 3));
++ }
++
++ // HwCDCR1_LOCK_ON Hw2 // Lock Transfer
++ if(uiFlag & SET_CIF_TRANSFER_LOCK)
++ {
++ BITCSET(HwCIF->CDCR1, HwCDCR1_LOCK_ON, (uiLock << 2));
++ }
++
++ // HwCDCR1_BS_1 HwZERO // The DMA transfers the image data as 1 word to memory
++ // HwCDCR1_BS_2 Hw0 // The DMA transfers the image data as 2 word to memory
++ // HwCDCR1_BS_4 Hw1 // The DMA transfers the image data as 4 word to memory
++ // HwCDCR1_BS_8 (Hw1|Hw0) // The DMA transfers the image data as 8 word to memory (default)
++ if(uiFlag & SET_CIF_TRANSFER_BURST)
++ {
++ BITCSET(HwCIF->CDCR1, HwCDCR1_BS_8, uiBurst); // PCIF->CDCR1
++ }
++
++#else // (CONFIG_ARCH_TCC79X)
++ //HwCDCR1_TM_INC Hw3 // INC Transfer
++ if(uiFlag & SET_CIF_TRANSFER_MODE)
++ {
++ BITCSET(HwCDCR1, HwCDCR1_TM_INC, (uiTransMode << 3));
++ }
++
++ // HwCDCR1_LOCK_ON Hw2 // Lock Transfer
++ if(uiFlag & SET_CIF_TRANSFER_LOCK)
++ {
++ BITCSET(HwCDCR1, HwCDCR1_LOCK_ON, (uiLock << 2));
++ }
++
++ // HwCDCR1_BS_1 HwZERO // The DMA transfers the image data as 1 word to memory
++ // HwCDCR1_BS_2 Hw0 // The DMA transfers the image data as 2 word to memory
++ // HwCDCR1_BS_4 Hw1 // The DMA transfers the image data as 4 word to memory
++ // HwCDCR1_BS_8 (Hw1|Hw0) // The DMA transfers the image data as 8 word to memory (default)
++ if(uiFlag & SET_CIF_TRANSFER_BURST)
++ {
++ BITCSET(HwCDCR1, HwCDCR1_BS_8, uiBurst); // HwCIF->CDCR1
++ }
++#endif
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_convertR2Y
++//
++// DESCRIPTION
++// set CIF register : HwCR2Y
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_R2Y_Convert(unsigned int uiFlag, unsigned int uiFMT, unsigned int uiEN)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ //HwCR2Y_FMT (Hw4|Hw3|Hw2|Hw1) // FMT[4:1] 0000 -> Input format 16bit 565RGB(RGB sequence) ÀÚ¼¼ÇÑ »çÇ× 750A CIF SPEC. 1-22
++ if(uiFlag & SET_CIF_CR2Y_FMT)
++ {
++ BITCSET(HwCIF->CR2Y, HwCR2Y_FMT, (uiFMT<<1));
++ }
++
++ //HwCR2Y_EN Hw0 // R2Y Enable, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CR2Y_EN)
++ {
++ BITCSET(HwCIF->CR2Y, HwCR2Y_EN, (uiEN)); // PCIF->CR2Y
++ }
++#else //(CONFIG_ARCH_TCC79X)
++ //HwCR2Y_FMT (Hw4|Hw3|Hw2|Hw1) // FMT[4:1] 0000 -> Input format 16bit 565RGB(RGB sequence) ÀÚ¼¼ÇÑ »çÇ× 750A CIF SPEC. 1-22
++ if(uiFlag & SET_CIF_CR2Y_FMT)
++ {
++ BITCSET(HwCR2Y, HwCR2Y_555GAR_BGR8, (uiFMT<<1));
++ }
++
++ //HwCR2Y_EN Hw0 // R2Y Enable, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CR2Y_EN)
++ {
++ BITCSET(HwCR2Y, HwCR2Y_EN, (uiEN)); // HwCIF->CR2Y
++ }
++
++#endif
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_overlayCtrl
++//
++// DESCRIPTION
++// set CIF register : HwOCTRL1, HwOCTRL2
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_OverlayCtrl(unsigned int uiFlag, unsigned int uiRgb)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ if(uiFlag & SET_CIF_ALPHA_ENABLE)
++ {
++ BITSET(HwCIF->OCTRL1, HwOCTRL1_AEN_EN);
++ }
++
++ if(uiFlag & SET_CIF_ALPHA_DISABLE)
++ {
++ BITCLR(HwCIF->OCTRL1, HwOCTRL1_AEN_EN);
++ }
++ if(uiFlag & SET_CIF_CHROMA_ENABLE)
++ {
++ BITSET(HwCIF->OCTRL1, HwOCTRL1_CEN_EN);
++ }
++
++ if(uiFlag & SET_CIF_CHROMA_DISABLE)
++ {
++ BITCLR(HwCIF->OCTRL1, HwOCTRL1_CEN_EN);
++ }
++
++ if(uiFlag & SET_CIF_OVERLAY_ENABLE)
++ {
++ BITSET(HwCIF->OCTRL1, HwOCTRL1_OE_EN);
++ }
++
++ if(uiFlag & SET_CIF_OVERLAY_DISABLE)
++ {
++ BITCLR(HwCIF->OCTRL1, HwOCTRL1_OE_EN);
++ }
++
++ if(uiFlag & SET_CIF_COLOR_CONV_ENABLE)
++ {
++ BITSET(HwCIF->OCTRL2, HwOCTRL2_CONV);
++ }
++
++ if(uiFlag & SET_CIF_COLOR_CONV_DISABLE)
++ {
++ BITCLR(HwCIF->OCTRL2, HwOCTRL2_CONV);
++ }
++
++ if(uiFlag & SET_CIF_COLOR_MODE_RGB)
++ {
++ BITSET(HwCIF->OCTRL2, HwOCTRL2_MD);
++ BITCSET(HwCIF->OCTRL2, 0x00000006, (uiRgb << 1));
++ }
++
++ if(uiFlag & SET_CIF_COLOR_MODE_YUV)
++ {
++ BITCLR(HwCIF->OCTRL2, HwOCTRL2_MD);
++ }
++#else //(CONFIG_ARCH_TCC79X)
++ if(uiFlag & SET_CIF_ALPHA_ENABLE)
++ {
++ BITSET(HwOCTRL1, HwOCTRL1_AEN_EN);
++ }
++
++ if(uiFlag & SET_CIF_ALPHA_DISABLE)
++ {
++ BITCLR(HwOCTRL1, HwOCTRL1_AEN_EN);
++ }
++ if(uiFlag & SET_CIF_CHROMA_ENABLE)
++ {
++ BITSET(HwOCTRL1, HwOCTRL1_CEN_EN);
++ }
++
++ if(uiFlag & SET_CIF_CHROMA_DISABLE)
++ {
++ BITCLR(HwOCTRL1, HwOCTRL1_CEN_EN);
++ }
++
++ if(uiFlag & SET_CIF_OVERLAY_ENABLE)
++ {
++ BITSET(HwOCTRL1, HwOCTRL1_OE_EN);
++ }
++
++ if(uiFlag & SET_CIF_OVERLAY_DISABLE)
++ {
++ BITCLR(HwOCTRL1, HwOCTRL1_OE_EN);
++ }
++
++ if(uiFlag & SET_CIF_COLOR_CONV_ENABLE)
++ {
++ BITSET(HwOCTRL2, HwOCTRL2_CONV);
++ }
++
++ if(uiFlag & SET_CIF_COLOR_CONV_DISABLE)
++ {
++ BITCLR(HwOCTRL2, HwOCTRL2_CONV);
++ }
++
++ if(uiFlag & SET_CIF_COLOR_MODE_RGB)
++ {
++ BITSET(HwOCTRL2, HwOCTRL2_MD);
++ BITCSET(HwOCTRL2, 0x00000006, (uiRgb << 1));
++ }
++
++ if(uiFlag & SET_CIF_COLOR_MODE_YUV)
++ {
++ BITCLR(HwOCTRL2, HwOCTRL2_MD);
++ }
++
++#endif
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_overlaySet
++//
++// DESCRIPTION
++// set CIF register : HwOCTRL1
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetOverlay(unsigned int uiFlag, unsigned int uiOverlayCNT, unsigned int uiOverlayMethod,
++ unsigned int uiXOR1, unsigned int uiXOR0, unsigned int uiAlpha1, unsigned int uiAlpha0)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ if(uiFlag & SET_CIF_OVERLAY_COUNT)
++ {
++ BITCSET(HwCIF->OCTRL1, HwOCTRL1_OCNT_MAX, (uiOverlayCNT << 24));
++ }
++
++ if(uiFlag & SET_CIF_OVERLAY_METHOD)
++ {
++ BITCSET(HwCIF->OCTRL1, HwOCTRL1_OM_BLOCK, (uiOverlayMethod << 16));
++ }
++
++ if(uiFlag & SET_CIF_OVERLAY_XOR0)
++ {
++ BITCSET(HwCIF->OCTRL1, HwOCTRL1_XR0_100, (uiXOR0 << 9));
++ }
++
++ if(uiFlag & SET_CIF_OVERLAY_XOR1)
++ {
++ BITCSET(HwCIF->OCTRL1, HwOCTRL1_XR1_100, (uiXOR1 << 10));
++ }
++
++ if(uiFlag & SET_CIF_OVERLAY_ALPHA0)
++ {
++ BITCSET(HwCIF->OCTRL1, HwOCTRL1_AP0_100, (uiAlpha0 << 4));
++ }
++
++ if(uiFlag & SET_CIF_OVERLAY_ALPHA1)
++ {
++ BITCSET(HwCIF->OCTRL1, HwOCTRL1_AP1_100, (uiAlpha1 << 6));
++ }
++#else //(CONFIG_ARCH_TCC79X)
++ if(uiFlag & SET_CIF_OVERLAY_COUNT)
++ {
++ BITCSET(HwOCTRL1, HwOCTRL1_OCNT_MAX, (uiOverlayCNT << 24));
++ }
++
++ if(uiFlag & SET_CIF_OVERLAY_METHOD)
++ {
++ BITCSET(HwOCTRL1, HwOCTRL1_OM_BLOCK, (uiOverlayMethod << 16));
++ }
++
++ if(uiFlag & SET_CIF_OVERLAY_XOR0)
++ {
++ BITCSET(HwOCTRL1, HwOCTRL1_XR0_100, (uiXOR0 << 9));
++ }
++
++ if(uiFlag & SET_CIF_OVERLAY_XOR1)
++ {
++ BITCSET(HwOCTRL1, HwOCTRL1_XR1_100, (uiXOR1 << 10));
++ }
++
++ if(uiFlag & SET_CIF_OVERLAY_ALPHA0)
++ {
++ BITCSET(HwOCTRL1, HwOCTRL1_AP0_100, (uiAlpha0 << 4));
++ }
++
++ if(uiFlag & SET_CIF_OVERLAY_ALPHA1)
++ {
++ BITCSET(HwOCTRL1, HwOCTRL1_AP1_100, (uiAlpha1 << 6));
++ }
++
++#endif
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_overlaySetKey
++//
++// DESCRIPTION
++// set CIF register : HwOCTRL3, HwOCTRL4
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetOverlayKey(unsigned int uiFlag, unsigned int uiKEYR, unsigned int uiKEYG, unsigned int uiKEYB,
++ unsigned int uiMKEYR, unsigned int uiMKEYG, unsigned int uiMKEYB)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ if(uiFlag & SET_CIF_OVERLAY_KEY)
++ {
++ BITCSET(HwCIF->OCTRL3, (HwOCTRL3_KEYR_MAX|HwOCTRL3_KEYG_MAX|HwOCTRL3_KEYB_MAX), ((uiKEYR << 16)|(uiKEYG << 8)|uiKEYB));
++ } // HwCIF->OCTRL3
++
++ if(uiFlag & SET_CIF_OVERLAY_MASKKEY)
++ {
++ BITCSET(HwCIF->OCTRL4, (HwOCTRL4_MKEYR_MAX|HwOCTRL4_MKEYG_MAX|HwOCTRL4_MKEYB_MAX), ((uiMKEYR << 16)|(uiMKEYG << 8)|uiMKEYB));
++ } // HwCIF->OCTRL4
++#else //(CONFIG_ARCH_TCC79X)
++ if(uiFlag & SET_CIF_OVERLAY_KEY)
++ {
++ BITCSET(HwOCTRL3, (HwOCTRL3_KEYR_MAX|HwOCTRL3_KEYG_MAX|HwOCTRL3_KEYB_MAX), ((uiKEYR << 16)|(uiKEYG << 8)|uiKEYB));
++ } // HwCIF->OCTRL3
++
++ if(uiFlag & SET_CIF_OVERLAY_MASKKEY)
++ {
++ BITCSET(HwOCTRL4, (HwOCTRL4_MKEYR_MAX|HwOCTRL4_MKEYG_MAX|HwOCTRL4_MKEYB_MAX), ((uiMKEYR << 16)|(uiMKEYG << 8)|uiMKEYB));
++ } // HwCIF->OCTRL4
++#endif
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setSyncPol
++//
++// DESCRIPTION
++// set CIF register : H and V sync polarity
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetSyncPol(unsigned int uiHPolarity, unsigned int uiVpolarity)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ BITCSET(HwCIF->ICPCR1, HwICPCR1_HSP_HIGH, (uiHPolarity << 1));
++ BITCSET(HwCIF->ICPCR1, HwICPCR1_VSP_HIGH, uiVpolarity); // HwCIF->ICPCR1
++#else
++ BITCSET(HwICPCR1, HwICPCR1_HSP_HIGH, (uiHPolarity << 1));
++ BITCSET(HwICPCR1, HwICPCR1_VSP_HIGH, uiVpolarity); // HwCIF->ICPCR1
++
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setSyncPol
++//
++// DESCRIPTION
++// set CIF register : HwIIS, HwIIW1, HwIIW2,
++// HwOIS, HwOIW1, HwOIW2
++//
++// Parameters
++// CIF_SETIMG (Camera I/F setting image)
++// uiType : Input imge(INPUT_IMG), overlay image (OVER_IMG)
++// uiHsize : Horizontal size
++// uiVSize : vertical size
++// uiHorWindowingStart : start X position of windowing image
++// uiHorWindowingEnd : end X position of windowing image
++// uiVerWindowingStart : start Y position of windowing image
++// uiVerWindowingEnd : end Y position of windowing image
++// BaseAddress0 : Y channel base address In Overlay, overlay image adress
++// BaseAddress1 : U channel base address (don't use overlay image)
++// BaseAddress2 : V channel base address (don't use overlay image)
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetImage(unsigned int uiType, unsigned int uiHsize, unsigned int uiVsize,
++ unsigned int uiHorWindowingStart, unsigned int uiHorWindowingEnd,
++ unsigned int uiVerWindowingStart, unsigned int uiVerWindowingEnd)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ if (uiType & INPUT_IMG)
++ {
++ BITCSET(HwCIF->IIS, 0xFFFFFFFF, ((uiHsize << 16) | uiVsize));
++ BITCSET(HwCIF->IIW1, 0xFFFFFFFF, ((uiHorWindowingStart<< 16) | uiHorWindowingEnd));
++ BITCSET(HwCIF->IIW2, 0xFFFFFFFF, ((uiVerWindowingStart<< 16) | uiVerWindowingEnd));
++ }
++
++ if(uiType & OVERLAY_IMG)
++ {
++ BITCSET(HwCIF->OIS, 0xFFFFFFFF, ((uiHsize << 16) | uiVsize));
++ BITCSET(HwCIF->OIW1, 0xFFFFFFFF, ((uiHorWindowingStart<< 16) | uiHorWindowingEnd));
++ BITCSET(HwCIF->OIW2, 0xFFFFFFFF, ((uiVerWindowingStart<< 16) | uiVerWindowingEnd));
++ }
++#else //(CONFIG_ARCH_TCC79X)
++ if (uiType & INPUT_IMG)
++ {
++ BITCSET(HwIIS, 0xFFFFFFFF, ((uiHsize << 16) | uiVsize));
++ BITCSET(HwIIW1, 0xFFFFFFFF, ((uiHorWindowingStart<< 16) | uiHorWindowingEnd));
++ BITCSET(HwIIW2, 0xFFFFFFFF, ((uiVerWindowingStart<< 16) | uiVerWindowingEnd));
++ }
++
++ if(uiType & OVERLAY_IMG)
++ {
++ BITCSET(HwOIS, 0xFFFFFFFF, ((uiHsize << 16) | uiVsize));
++ BITCSET(HwOIW1, 0xFFFFFFFF, ((uiHorWindowingStart<< 16) | uiHorWindowingEnd));
++ BITCSET(HwOIW2, 0xFFFFFFFF, ((uiVerWindowingStart<< 16) | uiVerWindowingEnd));
++ }
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setSensorOutImgSize
++//
++// DESCRIPTION
++// set CIF register : HwCEIS
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetSensorOutImgSize(unsigned int uiHsize, unsigned int uiVsize)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ BITCSET(HwCEM->CEIS, HwCEIS_HSIZE, (uiHsize<<16));
++ BITCSET(HwCEM->CEIS, HwCEIS_VSIZE, (uiVsize)); // HwCEM->CEIS
++#else //(CONFIG_ARCH_TCC79X)
++ BITCSET(HwCEIS, HwCEIS_HSIZE, (uiHsize<<16));
++ BITCSET(HwCEIS, HwCEIS_VSIZE, (uiVsize)); // HwCEM->CEIS
++
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setBaseAddr
++//
++// DESCRIPTION
++// set CIF register : HwCDCR2, HwCDCR3, HwCDCR4
++// HwCOBA
++// HwCDCR5,
++// HwCDCR6, HwCDCR7, HwCDCR8
++// HwCESA
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetBaseAddr (unsigned int uiType, unsigned int uiBaseAddr0,
++ unsigned int uiBaseAddr1, unsigned int uiBaseAddr2)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++
++ if (uiType & INPUT_IMG)
++ {
++ BITCSET(HwCIF->CDCR2, 0xFFFFFFFF, uiBaseAddr0);
++ BITCSET(HwCIF->CDCR3, 0xFFFFFFFF, uiBaseAddr1);
++ BITCSET(HwCIF->CDCR4, 0xFFFFFFFF, uiBaseAddr2);
++ }
++
++ if(uiType & OVERLAY_IMG)
++ {
++ BITCSET(HwCIF->COBA, 0xFFFFFFFF, uiBaseAddr0);
++ }
++
++ if (uiType & IN_IMG_ROLLING)
++ {
++ BITCSET(HwCIF->CDCR6, 0xFFFFFFFF, uiBaseAddr0);
++ BITCSET(HwCIF->CDCR7, 0xFFFFFFFF, uiBaseAddr1);
++ BITCSET(HwCIF->CDCR8, 0xFFFFFFFF, uiBaseAddr2);
++ }
++
++ if(uiType & IN_ENC_START_ADDR)
++ {
++ BITCSET(HwCIF->CESA, 0xFFFFFFFF, uiBaseAddr0);
++ }
++#else //(CONFIG_ARCH_TCC79X)
++
++ if (uiType & INPUT_IMG)
++ {
++ BITCSET(HwCDCR2, 0xFFFFFFFF, uiBaseAddr0);
++ BITCSET(HwCDCR3, 0xFFFFFFFF, uiBaseAddr1);
++ BITCSET(HwCDCR4, 0xFFFFFFFF, uiBaseAddr2);
++ }
++
++ if(uiType & OVERLAY_IMG)
++ {
++ BITCSET(HwCOBA, 0xFFFFFFFF, uiBaseAddr0);
++ }
++
++ if (uiType & IN_IMG_ROLLING)
++ {
++ BITCSET(HwCDCR5, 0xFFFFFFFF, uiBaseAddr0);
++ BITCSET(HwCDCR6, 0xFFFFFFFF, uiBaseAddr1);
++ BITCSET(HwCDCR7, 0xFFFFFFFF, uiBaseAddr2);
++ }
++
++ if(uiType & IN_ENC_START_ADDR)
++ {
++ BITCSET(HwCESA, 0xFFFFFFFF, uiBaseAddr0);
++ }
++#endif
++}
++
++
++void TDD_CIF_SetBaseAddr_offset(unsigned int uiType, unsigned int uiOFFSET_Y, unsigned int uiOFFSET_C)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ if (uiType & INPUT_IMG)
++ {
++ BITCSET(HwCIF->CDCR5, 0xFFFFFFFF, ((uiOFFSET_C << 16) | uiOFFSET_Y));
++ }
++
++ if(uiType & OVERLAY_IMG)
++ {
++ BITCSET(HwCIF->COBO, 0xFFFFFFFF, (uiOFFSET_Y));
++ }
++#endif
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setInterrupt
++//
++// DESCRIPTION
++// set CIF register : HwIEN, HwSEL, HwCIRQ
++// HwIEN, HwIRQSEL, HwCIRQ
++// HwCESA
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetInterrupt(unsigned int uiFlag)
++{
++ // Interrupt Enable 0:interrupt disable, 1:interrupt enable //Hw31
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ if(uiFlag & SET_CIF_INT_ENABLE)
++ {
++ BITSET(HwPIC->IEN0, HwINT0_CAM);
++ BITSET(HwPIC->SEL0, HwINT0_CAM);
++ BITSET(HwCIF->CIRQ, HwCIRQ_IEN); // Camera Interrupt enable
++ }
++ if(uiFlag & SET_CIF_INT_DISABLE)
++ {
++ BITCLR(HwPIC->IEN0, HwINT0_CAM);
++ BITCLR(HwPIC->SEL0, HwINT0_CAM);
++ BITCLR(HwCIF->CIRQ, HwCIRQ_IEN); // Camera Interrupt enable
++ }
++#else //(CONFIG_ARCH_TCC79X)
++ if(uiFlag & SET_CIF_INT_ENABLE)
++ {
++ BITSET(HwIEN, HwINT_CAM);
++ BITSET(HwSEL, HwINT_CAM);
++ BITSET(HwCIRQ, HwCIRQ_IEN_EN); // Camera Interrupt enable
++ }
++ if(uiFlag & SET_CIF_INT_DISABLE)
++ {
++ BITCLR(HwIEN, HwINT_CAM);
++ BITCLR(HwSEL, HwINT_CAM);
++ BITCLR(HwCIRQ, HwCIRQ_IEN_EN); // Camera Interrupt enable
++ }
++#endif
++
++
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ // Update Register in VSYNC 0:Register is update without VSYNC , 1:When VSYNC is posedge, register is updated. //Hw30
++ if(uiFlag & SET_CIF_UPDATE_IN_VSYNC)
++ {
++ BITSET(HwCIF->CIRQ, HwCIRQ_URV);
++ }
++
++ if(uiFlag & SET_CIF_UPDATE_WITHOUT_VSYNC)
++ {
++ BITCLR(HwCIF->CIRQ, HwCIRQ_URV);
++ }
++
++ // Interrupt Type 0:Pulse type, 1:Hold-up type when respond signal(ICR) is high //Hw29
++ if(uiFlag & SET_CIF_INT_TYPE_HOLDUP)
++ {
++ BITSET(HwCIF->CIRQ, HwCIRQ_ITY);
++ }
++
++ if(uiFlag & SET_CIF_INT_TYPE_PULSE)
++ {
++ BITCLR(HwCIF->CIRQ, HwCIRQ_ITY);
++ }
++
++ // Interrupt Clear 0:.... , 1:Interrupt Clear (using ITY is Hold-up type) //Hw28
++ if(uiFlag & SET_CIF_INT_HOLD_CLEAR)
++ {
++ BITSET(HwCIF->CIRQ, HwCIRQ_ICR);
++ }
++#else //(CONFIG_ARCH_TCC79X)
++ // Update Register in VSYNC 0:Register is update without VSYNC , 1:When VSYNC is posedge, register is updated. //Hw30
++ if(uiFlag & SET_CIF_UPDATE_IN_VSYNC)
++ {
++ BITSET(HwCIRQ, HwCIRQ_URV);
++ }
++
++ if(uiFlag & SET_CIF_UPDATE_WITHOUT_VSYNC)
++ {
++ BITCLR(HwCIRQ, HwCIRQ_URV);
++ }
++
++ // Interrupt Type 0:Pulse type, 1:Hold-up type when respond signal(ICR) is high //Hw29
++ if(uiFlag & SET_CIF_INT_TYPE_HOLDUP)
++ {
++ BITSET(HwCIRQ, HwCIRQ_ITY);
++ }
++
++ if(uiFlag & SET_CIF_INT_TYPE_PULSE)
++ {
++ BITCLR(HwCIRQ, HwCIRQ_ITY);
++ }
++
++ // Interrupt Clear 0:.... , 1:Interrupt Clear (using ITY is Hold-up type) //Hw28
++ if(uiFlag & SET_CIF_INT_HOLD_CLEAR)
++ {
++ BITSET(HwCIRQ, HwCIRQ_ICR);
++ }
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setMaskIntStatus
++//
++// DESCRIPTION
++// CIF interrupt status masking
++// set CIF register : HwCIRQ
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetMaskIntStatus(unsigned int uiFlag)
++{
++
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ // Hw29 should be written "1"!!
++ BITSET(HwCIF->CIRQ, HwCIRQ_ITY);
++
++ // Hw26 // Mask interrupt of VS negative edge, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_VS_NEGA_MASK)
++ {
++ BITSET(HwCIF->CIRQ, HwCIRQ_MVN);
++ }
++
++ if(uiFlag & SET_CIF_INT_VS_NEGA_NOT_MASK)
++ {
++ BITCLR(HwCIF->CIRQ, HwCIRQ_MVN);
++ }
++
++ // Hw25 // Mask interrupt of VS negative edge, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_VS_POSI_MASK)
++ {
++ BITSET(HwCIF->CIRQ, HwCIRQ_MVP);
++ }
++
++ if(uiFlag & SET_CIF_INT_VS_POSI_NOT_MASK)
++ {
++ BITCLR(HwCIF->CIRQ, HwCIRQ_MVP);
++ }
++
++ // Hw24 // Mask interrupt of VCNT Interrupt, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_VCNT_MASK)
++ {
++ BITSET(HwCIF->CIRQ, HwCIRQ_MVIT);
++ }
++
++ if(uiFlag & SET_CIF_INT_VCNT_NOT_MASK)
++ {
++ BITCLR(HwCIF->CIRQ, HwCIRQ_MVIT);
++ }
++
++ // Hw23 // Mask interrupt of Scaler Error, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_SCALER_ERR_MASK)
++ {
++ BITSET(HwCIF->CIRQ, HwCIRQ_MSE);
++ }
++
++ if(uiFlag & SET_CIF_INT_SCALER_ERR_NOT_MASK)
++ {
++ BITCLR(HwCIF->CIRQ, HwCIRQ_MSE);
++ }
++
++ // Hw22 // Mask interrupt of Scaler finish, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_SCALER_FINISH_MASK)
++ {
++ BITSET(HwCIF->CIRQ, HwCIRQ_MSF);
++ }
++
++ if(uiFlag & SET_CIF_INT_SCALER_FINISH_NOT_MASK)
++ {
++ BITCLR(HwCIF->CIRQ, HwCIRQ_MSF);
++ }
++
++ // Hw21 // Mask interrupt of Encoding start, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_ENC_STRT_MASK)
++ {
++ BITSET(HwCIF->CIRQ, HwCIRQ_MENS);
++ }
++
++ if(uiFlag & SET_CIF_INT_ENC_STRT_NOT_MASK)
++ {
++ BITCLR(HwCIF->CIRQ, HwCIRQ_MENS);
++ }
++
++ // Hw20 // Mask interrupt of Rolling V address, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_ROLL_VADDR_MASK)
++ {
++ BITSET(HwCIF->CIRQ, HwCIRQ_MRLV);
++ }
++
++ if(uiFlag & SET_CIF_INT_ROLL_VADDR_NOT_MASK)
++ {
++ BITCLR(HwCIF->CIRQ, HwCIRQ_MRLV);
++ }
++
++ // Hw19 // Mask interrupt of Rolling U address, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_ROLL_UADDR_MASK)
++ {
++ BITSET(HwCIF->CIRQ, HwCIRQ_MRLU);
++ }
++
++ if(uiFlag & SET_CIF_INT_ROLL_UADDR_NOT_MASK)
++ {
++ BITCLR(HwCIF->CIRQ, HwCIRQ_MRLU);
++ }
++
++ // Hw18 // Mask interrupt of Rolling Y address, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_ROLL_YADDR_MASK)
++ {
++ BITSET(HwCIF->CIRQ, HwCIRQ_MRLY);
++ }
++
++ if(uiFlag & SET_CIF_INT_ROLL_YADDR_NOT_MASK)
++ {
++ BITCLR(HwCIF->CIRQ, HwCIRQ_MRLY);
++ }
++
++ // Hw17 // Mask interrupt of Capture frame, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_CAPTURE_FRM_MASK)
++ {
++ BITSET(HwCIF->CIRQ, HwCIRQ_MSCF);
++ }
++
++ if(uiFlag & SET_CIF_INT_CAPTURE_FRM_NOT_MASK)
++ {
++ BITCLR(HwCIF->CIRQ, HwCIRQ_MSCF);
++ }
++
++ // Hw16 // Mask interrupt of Stored one frame, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_STORE_1FRM_MASK)
++ {
++ BITSET(HwCIF->CIRQ, HwCIRQ_MSOF);
++ }
++
++ if(uiFlag & SET_CIF_INT_STORE_1FRM_NOT_MASK)
++ {
++ BITCLR(HwCIF->CIRQ, HwCIRQ_MSOF);
++ }
++
++ if(uiFlag & SET_CIF_INT_ALL_MASK)
++ {
++ //BITCSET(HwCIRQ, 0x07FF0000, 0x7FF<<16);
++ BITSET(HwCIF->CIRQ, 0x7FF<<16);
++ }
++
++ if(uiFlag & SET_CIF_INT_ALL_CLEAR_MASK)
++ {
++ BITCLR(HwCIF->CIRQ, 0x5FF<<16);// Hw29 should be written "1"!!
++ } // HwCIF->CIRQ
++#else //(CONFIG_ARCH_TCC79X)
++ // Hw26 // Mask interrupt of VS negative edge, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_VS_NEGA_MASK)
++ {
++ BITSET(HwCIRQ, HwCIRQ_MVN);
++ }
++
++ if(uiFlag & SET_CIF_INT_VS_NEGA_NOT_MASK)
++ {
++ BITCLR(HwCIRQ, HwCIRQ_MVN);
++ }
++
++ // Hw25 // Mask interrupt of VS negative edge, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_VS_POSI_MASK)
++ {
++ BITSET(HwCIRQ, HwCIRQ_MVP);
++ }
++
++ if(uiFlag & SET_CIF_INT_VS_POSI_NOT_MASK)
++ {
++ BITCLR(HwCIRQ, HwCIRQ_MVP);
++ }
++
++ // Hw24 // Mask interrupt of VCNT Interrupt, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_VCNT_MASK)
++ {
++ BITSET(HwCIRQ, HwCIRQ_MVIT);
++ }
++
++ if(uiFlag & SET_CIF_INT_VCNT_NOT_MASK)
++ {
++ BITCLR(HwCIRQ, HwCIRQ_MVIT);
++ }
++
++ // Hw23 // Mask interrupt of Scaler Error, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_SCALER_ERR_MASK)
++ {
++ BITSET(HwCIRQ, HwCIRQ_MSE);
++ }
++
++ if(uiFlag & SET_CIF_INT_SCALER_ERR_NOT_MASK)
++ {
++ BITCLR(HwCIRQ, HwCIRQ_MSE);
++ }
++
++ // Hw22 // Mask interrupt of Scaler finish, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_SCALER_FINISH_MASK)
++ {
++ BITSET(HwCIRQ, HwCIRQ_MSF);
++ }
++
++ if(uiFlag & SET_CIF_INT_SCALER_FINISH_NOT_MASK)
++ {
++ BITCLR(HwCIRQ, HwCIRQ_MSF);
++ }
++
++ // Hw21 // Mask interrupt of Encoding start, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_ENC_STRT_MASK)
++ {
++ BITSET(HwCIRQ, HwCIRQ_MENS);
++ }
++
++ if(uiFlag & SET_CIF_INT_ENC_STRT_NOT_MASK)
++ {
++ BITCLR(HwCIRQ, HwCIRQ_MENS);
++ }
++
++ // Hw20 // Mask interrupt of Rolling V address, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_ROLL_VADDR_MASK)
++ {
++ BITSET(HwCIRQ, HwCIRQ_MRLV);
++ }
++
++ if(uiFlag & SET_CIF_INT_ROLL_VADDR_NOT_MASK)
++ {
++ BITCLR(HwCIRQ, HwCIRQ_MRLV);
++ }
++
++ // Hw19 // Mask interrupt of Rolling U address, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_ROLL_UADDR_MASK)
++ {
++ BITSET(HwCIRQ, HwCIRQ_MRLU);
++ }
++
++ if(uiFlag & SET_CIF_INT_ROLL_UADDR_NOT_MASK)
++ {
++ BITCLR(HwCIRQ, HwCIRQ_MRLU);
++ }
++
++ // Hw18 // Mask interrupt of Rolling Y address, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_ROLL_YADDR_MASK)
++ {
++ BITSET(HwCIRQ, HwCIRQ_MRLY);
++ }
++
++ if(uiFlag & SET_CIF_INT_ROLL_YADDR_NOT_MASK)
++ {
++ BITCLR(HwCIRQ, HwCIRQ_MRLY);
++ }
++
++ // Hw17 // Mask interrupt of Capture frame, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_CAPTURE_FRM_MASK)
++ {
++ BITSET(HwCIRQ, HwCIRQ_MSCF);
++ }
++
++ if(uiFlag & SET_CIF_INT_CAPTURE_FRM_NOT_MASK)
++ {
++ BITCLR(HwCIRQ, HwCIRQ_MSCF);
++ }
++
++ // Hw16 // Mask interrupt of Stored one frame, 0:Don't mask, 1:Mask
++ if(uiFlag & SET_CIF_INT_STORE_1FRM_MASK)
++ {
++ BITSET(HwCIRQ, HwCIRQ_MSOF);
++ }
++
++ if(uiFlag & SET_CIF_INT_STORE_1FRM_NOT_MASK)
++ {
++ BITCLR(HwCIRQ, HwCIRQ_MSOF);
++ }
++
++ if(uiFlag & SET_CIF_INT_ALL_MASK)
++ {
++ //BITCSET(HwCIRQ, 0x07FF0000, 0x7FF<<16);
++ BITSET(HwCIRQ, 0x7FF<<16);
++ }
++
++ if(uiFlag & SET_CIF_INT_ALL_CLEAR_MASK)
++ {
++ BITCLR(HwCIRQ, 0x7FF<<16);
++ } // HwCIF->CIRQ
++
++#endif
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_getIntStatus
++//
++// DESCRIPTION
++// get CIF status
++// get CIF register : HwCIRQ
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++unsigned int TDD_CIF_GetIntStatus(unsigned int uiFlag)
++{
++ unsigned long uiRegStatus = 0;
++
++#if defined(CONFIG_ARCH_TCC79X)
++ // ÀÎÅÍ·´Æ® ¹ß»ý °ú µ¿½Ã¿¡ status settingÀÌ changeµÈ status value¸¦ READ(GET)
++ if(uiFlag & GET_CIF_INT_VS_STATUS)
++ {
++ uiRegStatus = HwCIRQ & HwCIRQ_VSS;
++ }
++
++ //#define HwCIRQ_VN Hw10 // VS positive, 0:-, 1:When VS is generated if Negative edge
++ if(uiFlag & GET_CIF_INT_NEGA_VS_GEN)
++ {
++ uiRegStatus = HwCIRQ & HwCIRQ_VN;
++ //BITSET(HwCIRQ, HwCIRQ_VN);
++ }
++
++ //#define HwCIRQ_VP Hw9 // VS positive, 0:-, 1:When VS is generated if positive edge
++ if(uiFlag & GET_CIF_INT_POSI_VS_GEN)
++ {
++ uiRegStatus = HwCIRQ & HwCIRQ_VP;
++ //BITSET(HwCIRQ, HwCIRQ_VP);
++ }
++
++ //#define HwCIRQ_VIT Hw8 // VCNT Interrupt, 0:-, 1:When VCNT is generated....
++ if(uiFlag & GET_CIF_INT_VCNT_GEN)
++ {
++ uiRegStatus = HwCIRQ & HwCIRQ_VIT;
++ //BITSET(HwCIRQ, HwCIRQ_VIT);
++ }
++
++ //#define HwCIRQ_SE Hw7 // Scaler Error, 0:-, 1:When Scale operation is not correct.
++ if(uiFlag & GET_CIF_INT_SCALER_ERR)
++ {
++ uiRegStatus = HwCIRQ & HwCIRQ_SE;
++ //BITSET(HwCIRQ, HwCIRQ_SE);
++ }
++
++ //#define HwCIRQ_SF Hw6 // Scaler Finish, 0:-, 1:When Scale operation is finished
++ if(uiFlag & GET_CIF_INT_SCALER_FINISH)
++ {
++ uiRegStatus = HwCIRQ & HwCIRQ_SF;
++ //BITSET(HwCIRQ, HwCIRQ_SF);
++ }
++
++ //#define HwCIRQ_ENS Hw5 // Encoding start status, 0:-, 1:When Y address is bigger than encoding start address, this bit is high
++ if(uiFlag & GET_CIF_INT_ENC_STRT)
++ {
++ uiRegStatus = HwCIRQ & HwCIRQ_ENS;
++ //BITSET(HwCIRQ, HwCIRQ_ENS);
++ }
++
++ //#define HwCIRQ_ROLV Hw4 // Rolling V address status, 0:-, 1:If V address is move to start address, this bit is high
++ if(uiFlag & GET_CIF_INT_ROLL_VADDR_STRT)
++ {
++ uiRegStatus = HwCIRQ & HwCIRQ_ROLV;
++ //BITSET(HwCIRQ, HwCIRQ_ROLV);
++ }
++
++ //#define HwCIRQ_ROLU Hw3 // Rolling U address starus, 0:-, 1:If U address is move to start address, this bit is high
++ if(uiFlag & GET_CIF_INT_ROLL_UADDR_STRT)
++ {
++ uiRegStatus = HwCIRQ & HwCIRQ_ROLU;
++ // BITSET(HwCIRQ, HwCIRQ_ROLU);
++ }
++
++ //#define HwCIRQ_ROLY Hw2 // Rolling Y address starus, 0:-, 1:If Y address is move to start address, this bit is high
++ if(uiFlag & GET_CIF_INT_ROLL_YADDR_STRT)
++ {
++ uiRegStatus = HwCIRQ & HwCIRQ_ROLY;
++ //BITSET(HwCIRQ, HwCIRQ_ROLY);
++ }
++
++ //#define HwCIRQ_SCF Hw1 // Stored captured frame, 0:-, 1:If Captured frame is stored, this bit is high
++ if(uiFlag & GET_CIF_INT_CAPTURE_FRM_STORE)
++ {
++ uiRegStatus = HwCIRQ & HwCIRQ_SCF;
++ //BITSET(HwCIRQ, HwCIRQ_SCF);
++ }
++
++ //#define HwCIRQ_SOF Hw0 // Stored One frame, 0-, 1:If one frame if stored, this bit is high.
++ if(uiFlag & GET_CIF_INT_ONEFRAME_STORE)
++ {
++ uiRegStatus = HwCIRQ & HwCIRQ_SOF; // HwCIF->CIRQ
++ //BITSET(HwCIRQ, HwCIRQ_SOF);
++ }
++#else //(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ // ÀÎÅÍ·´Æ® ¹ß»ý °ú µ¿½Ã¿¡ status settingÀÌ changeµÈ status value¸¦ READ(GET)
++ if(uiFlag & GET_CIF_INT_VS_STATUS)
++ {
++ uiRegStatus = HwCIF->CIRQ & HwCIRQ_VSS;
++ }
++
++ //#define HwCIRQ_VN Hw10 // VS positive, 0:-, 1:When VS is generated if Negative edge
++ if(uiFlag & GET_CIF_INT_NEGA_VS_GEN)
++ {
++ uiRegStatus = HwCIF->CIRQ & HwCIRQ_VN;
++ //BITSET(HwCIRQ, HwCIRQ_VN);
++ }
++
++ //#define HwCIRQ_VP Hw9 // VS positive, 0:-, 1:When VS is generated if positive edge
++ if(uiFlag & GET_CIF_INT_POSI_VS_GEN)
++ {
++ uiRegStatus = HwCIF->CIRQ & HwCIRQ_VP;
++ //BITSET(HwCIRQ, HwCIRQ_VP);
++ }
++
++ //#define HwCIRQ_VIT Hw8 // VCNT Interrupt, 0:-, 1:When VCNT is generated....
++ if(uiFlag & GET_CIF_INT_VCNT_GEN)
++ {
++ uiRegStatus = HwCIF->CIRQ & HwCIRQ_VIT;
++ //BITSET(HwCIRQ, HwCIRQ_VIT);
++ }
++
++ //#define HwCIRQ_SE Hw7 // Scaler Error, 0:-, 1:When Scale operation is not correct.
++ if(uiFlag & GET_CIF_INT_SCALER_ERR)
++ {
++ uiRegStatus = HwCIF->CIRQ & HwCIRQ_SE;
++ //BITSET(HwCIRQ, HwCIRQ_SE);
++ }
++
++ //#define HwCIRQ_SF Hw6 // Scaler Finish, 0:-, 1:When Scale operation is finished
++ if(uiFlag & GET_CIF_INT_SCALER_FINISH)
++ {
++ uiRegStatus = HwCIF->CIRQ & HwCIRQ_SF;
++ //BITSET(HwCIRQ, HwCIRQ_SF);
++ }
++
++ //#define HwCIRQ_ENS Hw5 // Encoding start status, 0:-, 1:When Y address is bigger than encoding start address, this bit is high
++ if(uiFlag & GET_CIF_INT_ENC_STRT)
++ {
++ uiRegStatus = HwCIF->CIRQ & HwCIRQ_ENS;
++ //BITSET(HwCIRQ, HwCIRQ_ENS);
++ }
++
++ //#define HwCIRQ_ROLV Hw4 // Rolling V address status, 0:-, 1:If V address is move to start address, this bit is high
++ if(uiFlag & GET_CIF_INT_ROLL_VADDR_STRT)
++ {
++ uiRegStatus = HwCIF->CIRQ & HwCIRQ_ROLV;
++ //BITSET(HwCIRQ, HwCIRQ_ROLV);
++ }
++
++ //#define HwCIRQ_ROLU Hw3 // Rolling U address starus, 0:-, 1:If U address is move to start address, this bit is high
++ if(uiFlag & GET_CIF_INT_ROLL_UADDR_STRT)
++ {
++ uiRegStatus = HwCIF->CIRQ & HwCIRQ_ROLU;
++ // BITSET(HwCIRQ, HwCIRQ_ROLU);
++ }
++
++ //#define HwCIRQ_ROLY Hw2 // Rolling Y address starus, 0:-, 1:If Y address is move to start address, this bit is high
++ if(uiFlag & GET_CIF_INT_ROLL_YADDR_STRT)
++ {
++ uiRegStatus = HwCIF->CIRQ & HwCIRQ_ROLY;
++ //BITSET(HwCIRQ, HwCIRQ_ROLY);
++ }
++
++ //#define HwCIRQ_SCF Hw1 // Stored captured frame, 0:-, 1:If Captured frame is stored, this bit is high
++ if(uiFlag & GET_CIF_INT_CAPTURE_FRM_STORE)
++ {
++ uiRegStatus = HwCIF->CIRQ & HwCIRQ_SCF;
++ //BITSET(HwCIRQ, HwCIRQ_SCF);
++ }
++
++ //#define HwCIRQ_SOF Hw0 // Stored One frame, 0-, 1:If one frame if stored, this bit is high.
++ if(uiFlag & GET_CIF_INT_ONEFRAME_STORE)
++ {
++ uiRegStatus = HwCIF->CIRQ & HwCIRQ_SOF; // PCIF->CIRQ
++ //BITSET(HwCIRQ, HwCIRQ_SOF);
++ }
++#endif
++
++ return (unsigned int)uiRegStatus;
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_set656FormatConfig
++//
++// DESCRIPTION
++// set CIF register : Hw656FCR1, Hw656FCR2
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_Set656FormatConfig(unsigned int uiType, unsigned int uiPsl, unsigned int uiFpv,
++ unsigned int uiSpv, unsigned int uiTpv, unsigned int uiHb, unsigned int uiVb)
++{
++#if defined(CONFIG_ARCH_TCC79X)
++ if(uiType & SET_CIF_656_PSL)
++ {
++ BITCSET(Hw656FCR1, 0x06000000, (uiPsl << 25));
++ }
++
++ if(uiType & SET_CIF_656_FPV)
++ {
++ BITCSET(Hw656FCR1, 0x00FF0000, (uiFpv << 16));
++ }
++
++ if(uiType & SET_CIF_656_SPV)
++ {
++ BITCSET(Hw656FCR1, 0x0000FF00, (uiSpv << 8));
++ }
++
++ if(uiType & SET_CIF_656_TPV)
++ {
++ BITCSET(Hw656FCR1, 0x000000FF, uiTpv);
++ }
++
++ if(uiType & SET_CIF_656_H_BLANK)
++ {
++ BITCSET(Hw656FCR2, 0x000001E0, (uiHb << 5));
++ }
++
++ if(uiType & SET_CIF_656_V_BLANK)
++ {
++ BITCSET(Hw656FCR2, 0x0000000F, uiVb); // HwCIF->CCIR656FCR2
++ }
++#else //(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ if(uiType & SET_CIF_656_PSL)
++ {
++ BITCSET(HwCIF->CCIR656FCR1, 0x06000000, (uiPsl << 25));
++ }
++
++ if(uiType & SET_CIF_656_FPV)
++ {
++ BITCSET(HwCIF->CCIR656FCR1, 0x00FF0000, (uiFpv << 16));
++ }
++
++ if(uiType & SET_CIF_656_SPV)
++ {
++ BITCSET(HwCIF->CCIR656FCR1, 0x0000FF00, (uiSpv << 8));
++ }
++
++ if(uiType & SET_CIF_656_TPV)
++ {
++ BITCSET(HwCIF->CCIR656FCR1, 0x000000FF, uiTpv);
++ }
++
++ if(uiType & SET_CIF_656_H_BLANK)
++ {
++ BITCSET(HwCIF->CCIR656FCR2, 0x000001E0, (uiHb << 5));
++ }
++
++ if(uiType & SET_CIF_656_V_BLANK)
++ {
++ BITCSET(HwCIF->CCIR656FCR2, 0x0000000F, uiVb); // PCIF->CCIR656FCR2
++ }
++#endif
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setFIFOStatusClear
++//
++// DESCRIPTION
++// clear FIFO Status
++// set CIF register : HwFIFOSTATE
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetFIFOStatusClear(void)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ BITSET(HwCIF->FIFOSTATE, HwFIFOSTATE_CLR); // HwCIF->FIFOSTATE
++#else //(CONFIG_ARCH_TCC92X)
++ BITSET(HwFIFOSTATE, HwFIFOSTATE_CLR); // HwCIF->FIFOSTATE
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setFIFOStatusClear
++//
++// DESCRIPTION
++// get CIF register : HwFIFOSTATE
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++unsigned int TDD_CIF_GetFIFOStatus(unsigned int uiType)
++{
++ unsigned long uiRet = 0;
++
++#if defined(CONFIG_ARCH_TCC79X)
++ if(uiType & GET_CIF_OVERLAY_READ_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_REO);
++ }
++
++ if(uiType & GET_CIF_VCH_READ_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_REV);
++ }
++
++ if(uiType & GET_CIF_UCH_READ_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_REU);
++ }
++
++ if(uiType & GET_CIF_YCH_READ_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_REY);
++ }
++
++ if(uiType & GET_CIF_OVERLAY_WRITE_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_WEO);
++ }
++
++ if(uiType & GET_CIF_VCH_WRITE_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_WEV);
++ }
++
++ if(uiType & GET_CIF_UCH_WRITE_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_WEU);
++ }
++
++ if(uiType & GET_CIF_YCH_WRITE_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_WEY);
++ }
++
++ if(uiType & GET_CIF_OVERLAY_EMPTY_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_EO);
++ }
++
++ if(uiType & GET_CIF_VCH_EMPTY_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_EV);
++ }
++
++ if(uiType & GET_CIF_UCH_EMPTY_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_EU);
++ }
++
++ if(uiType & GET_CIF_YCH_EMPTY_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_EY);
++ }
++
++ if(uiType & GET_CIF_OVERLAY_FULL_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_FO);
++ }
++
++ if(uiType & GET_CIF_VCH_FULL_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_FV);
++ }
++
++ if(uiType & GET_CIF_UCH_FULL_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_FU);
++ }
++
++ if(uiType & GET_CIF_YCH_FULL_ERR)
++ {
++ uiRet |= (HwFIFOSTATE & HwFIFOSTATE_FY); // HwCIF->FIFOSTATE
++ }
++#else //(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ if(uiType & GET_CIF_OVERLAY_READ_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_REO);
++ }
++
++ if(uiType & GET_CIF_VCH_READ_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_REV);
++ }
++
++ if(uiType & GET_CIF_UCH_READ_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_REU);
++ }
++
++ if(uiType & GET_CIF_YCH_READ_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_REY);
++ }
++
++ if(uiType & GET_CIF_OVERLAY_WRITE_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_WEO);
++ }
++
++ if(uiType & GET_CIF_VCH_WRITE_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_WEV);
++ }
++
++ if(uiType & GET_CIF_UCH_WRITE_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_WEU);
++ }
++
++ if(uiType & GET_CIF_YCH_WRITE_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_WEY);
++ }
++
++ if(uiType & GET_CIF_OVERLAY_EMPTY_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_EO);
++ }
++
++ if(uiType & GET_CIF_VCH_EMPTY_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_EV);
++ }
++
++ if(uiType & GET_CIF_UCH_EMPTY_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_EU);
++ }
++
++ if(uiType & GET_CIF_YCH_EMPTY_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_EY);
++ }
++
++ if(uiType & GET_CIF_OVERLAY_FULL_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_FO);
++ }
++
++ if(uiType & GET_CIF_VCH_FULL_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_FV);
++ }
++
++ if(uiType & GET_CIF_UCH_FULL_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_FU);
++ }
++
++ if(uiType & GET_CIF_YCH_FULL_ERR)
++ {
++ uiRet |= (HwCIF->FIFOSTATE & HwFIFOSTATE_FY); // PCIF->FIFOSTATE
++ }
++#endif
++ return (unsigned int)uiRet;
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setCaptureCtrl
++//
++// DESCRIPTION
++// CIF Capture Control
++// set CIF register : HwCCM1, HwCCM2
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetCaptureCtrl(unsigned int uiType, unsigned int uiSkipNum, unsigned int uiVCnt, unsigned int uiFlag)
++{
++#if defined(CONFIG_ARCH_TCC79X)
++ if(uiType & SET_CIF_SKIP_NUM)
++ {
++ BITCSET(HwCCM1, HwCCM1_SKIPNUM, (uiSkipNum << 4));
++ }
++
++ if(uiType & SET_CIF_VCNT_NUM)
++ {
++ BITCSET(HwCCM2, HwCCM2_VCNT, (uiVCnt << 4));
++ }
++
++ if(uiFlag & SET_CIF_EIT_ENC_INT)
++ {
++ BITSET(HwCCM1, HwCCM1_EIT);
++ }
++
++ if(uiFlag & SET_CIF_EIT_ALWAYS_1_PULSE)
++ {
++ BITCLR(HwCCM1, HwCCM1_EIT);
++ }
++
++ if(uiFlag & SET_CIF_UES_ENABLE)
++ {
++ BITSET(HwCCM1, HwCCM1_UES);
++ }
++
++ if(uiFlag & SET_CIF_UES_DISABLE)
++ {
++ BITCLR(HwCCM1, HwCCM1_UES);
++ }
++
++ if(uiFlag & SET_CIF_RLV_ENABLE)
++ {
++ BITSET(HwCCM1, HwCCM1_RLV);
++ }
++
++ if(uiFlag & SET_CIF_RLV_DISABLE)
++ {
++ BITCLR(HwCCM1, HwCCM1_RLV);
++ }
++
++ if(uiFlag & SET_CIF_RLU_ENABLE)
++ {
++ BITSET(HwCCM1, HwCCM1_RLU);
++ }
++
++ if(uiFlag & SET_CIF_RLU_DISABLE)
++ {
++ BITCLR(HwCCM1, HwCCM1_RLU);
++ }
++
++ if(uiFlag & SET_CIF_RLY_ENABLE)
++ {
++ BITSET(HwCCM1, HwCCM1_RLY);
++ }
++
++ if(uiFlag & SET_CIF_RLY_DISABLE)
++ {
++ BITCLR(HwCCM1, HwCCM1_RLY);
++ }
++
++ if(uiFlag & SET_CIF_CAP_ENABLE)
++ {
++ BITSET(HwCCM1, HwCCM1_CAP);
++ }
++
++ if(uiFlag & SET_CIF_CAP_DISABLE)
++ {
++ BITCLR(HwCCM1, HwCCM1_CAP);
++ }
++
++ if(uiFlag & SET_CIF_VEN_ENABLE)
++ {
++ BITSET(HwCCM2, HwCCM2_VEN);
++ }
++
++ if(uiFlag & SET_CIF_VEN_DISABLE)
++ {
++ BITCLR(HwCCM2, HwCCM2_VEN);
++ }
++#else //(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ if(uiType & SET_CIF_SKIP_NUM)
++ {
++ BITCSET(HwCIF->CCM1, HwCCM1_SKIPNUM, (uiSkipNum << 4));
++ }
++
++ if(uiType & SET_CIF_VCNT_NUM)
++ {
++ BITCSET(HwCIF->CCM2, HwCCM2_VCNT, (uiVCnt << 4));
++ }
++
++ if(uiFlag & SET_CIF_EIT_ENC_INT)
++ {
++ BITSET(HwCIF->CCM1, HwCCM1_EIT);
++ }
++
++ if(uiFlag & SET_CIF_EIT_ALWAYS_1_PULSE)
++ {
++ BITCLR(HwCIF->CCM1, HwCCM1_EIT);
++ }
++
++ if(uiFlag & SET_CIF_UES_ENABLE)
++ {
++ BITSET(HwCIF->CCM1, HwCCM1_UES);
++ }
++
++ if(uiFlag & SET_CIF_UES_DISABLE)
++ {
++ BITCLR(HwCIF->CCM1, HwCCM1_UES);
++ }
++
++ if(uiFlag & SET_CIF_RLV_ENABLE)
++ {
++ BITSET(HwCIF->CCM1, HwCCM1_RLV);
++ }
++
++ if(uiFlag & SET_CIF_RLV_DISABLE)
++ {
++ BITCLR(HwCIF->CCM1, HwCCM1_RLV);
++ }
++
++ if(uiFlag & SET_CIF_RLU_ENABLE)
++ {
++ BITSET(HwCIF->CCM1, HwCCM1_RLU);
++ }
++
++ if(uiFlag & SET_CIF_RLU_DISABLE)
++ {
++ BITCLR(HwCIF->CCM1, HwCCM1_RLU);
++ }
++
++ if(uiFlag & SET_CIF_RLY_ENABLE)
++ {
++ BITSET(HwCIF->CCM1, HwCCM1_RLY);
++ }
++
++ if(uiFlag & SET_CIF_RLY_DISABLE)
++ {
++ BITCLR(HwCIF->CCM1, HwCCM1_RLY);
++ }
++
++ if(uiFlag & SET_CIF_CAP_ENABLE)
++ {
++ BITSET(HwCIF->CCM1, HwCCM1_CAP);
++ }
++
++ if(uiFlag & SET_CIF_CAP_DISABLE)
++ {
++ BITCLR(HwCIF->CCM1, HwCCM1_CAP); // PCIF->CCM1
++ }
++
++ if(uiFlag & SET_CIF_VEN_ENABLE)
++ {
++ BITSET(HwCIF->CCM2, HwCCM2_VEN);
++ }
++
++ if(uiFlag & SET_CIF_VEN_DISABLE)
++ {
++ BITCLR(HwCIF->CCM2, HwCCM2_VEN); // PCIF->CCM2
++ }
++#endif
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_getCaptureStatus
++//
++// DESCRIPTION
++// get CIF register : HwCCM1
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++unsigned int TDD_CIF_GetCaptureStatus(unsigned int uiType)
++{
++ unsigned long uiCaptureStatus = 0;
++
++#if defined(CONFIG_ARCH_TCC79X)
++ //HwCCM1_ENCNUM 0xF0000000 // Encode INT number (using CAP mode) [31:28], value area (0~15), Encode interrupt number
++ if(uiType & SET_CIF_CCM1_ENCNUM)
++ {
++ uiCaptureStatus = HwCCM1 & HwCCM1_ENCNUM;
++ }
++
++ //HwCCM1_ROLNUMV 0x0F000000 // Rolling number in V (using CAP mode) [27:24], value area (0~15), Rolling number
++ if(uiType & SET_CIF_CCM1_ROLNUMV)
++ {
++ uiCaptureStatus = HwCCM1 & HwCCM1_ROLNUMV;
++ }
++
++ //HwCCM1_ROLNUMU 0x00F00000 // Rolling number in U (using CAP mode) [23:20], value area (0~15), Rolling number
++ if(uiType & SET_CIF_CCM1_ROLNUMU)
++ {
++ uiCaptureStatus = HwCCM1 & HwCCM1_ROLNUMU;
++ }
++
++ //HwCCM1_ROLNUMY 0x000F0000 // Rolling number in Y (using CAP mode) [19:16], value area (0~15), Rolling number
++ if(uiType & SET_CIF_CCM1_ROLNUMY)
++ {
++ uiCaptureStatus = HwCCM1 & HwCCM1_ROLNUMY;
++ }
++
++ //HwCCM1_CB Hw10 // Capture Busy, 0:-, 1:Capture busy
++ if(uiType & SET_CIF_CCM1_CB)
++ {
++ uiCaptureStatus = (HwCCM1 & HwCCM1_CB);
++ } // HwCIF->CCM1
++#else //(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ //HwCCM1_ENCNUM 0xF0000000 // Encode INT number (using CAP mode) [31:28], value area (0~15), Encode interrupt number
++ if(uiType & SET_CIF_CCM1_ENCNUM)
++ {
++ uiCaptureStatus = HwCIF->CCM1 & HwCCM1_ENCNUM;
++ }
++
++ //HwCCM1_ROLNUMV 0x0F000000 // Rolling number in V (using CAP mode) [27:24], value area (0~15), Rolling number
++ if(uiType & SET_CIF_CCM1_ROLNUMV)
++ {
++ uiCaptureStatus = HwCIF->CCM1 & HwCCM1_ROLNUMV;
++ }
++
++ //HwCCM1_ROLNUMU 0x00F00000 // Rolling number in U (using CAP mode) [23:20], value area (0~15), Rolling number
++ if(uiType & SET_CIF_CCM1_ROLNUMU)
++ {
++ uiCaptureStatus = HwCIF->CCM1 & HwCCM1_ROLNUMU;
++ }
++
++ //HwCCM1_ROLNUMY 0x000F0000 // Rolling number in Y (using CAP mode) [19:16], value area (0~15), Rolling number
++ if(uiType & SET_CIF_CCM1_ROLNUMY)
++ {
++ uiCaptureStatus = HwCIF->CCM1 & HwCCM1_ROLNUMY;
++ }
++
++ //HwCCM1_CB Hw10 // Capture Busy, 0:-, 1:Capture busy
++ if(uiType & SET_CIF_CCM1_CB)
++ {
++ uiCaptureStatus = (HwCIF->CCM1 & HwCCM1_CB);
++ } // HwCIF->CCM1
++#endif
++ return (unsigned int)uiCaptureStatus;
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_getCurAddr
++//
++// DESCRIPTION
++// get CIF register : HwCCYA, HwCCUA, HwCCVA
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_GetCurAddr(volatile unsigned long *uiCurYAddr, volatile unsigned long *uiCurUAddr,
++ volatile unsigned long *uiCurVAddr)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ uiCurYAddr = (HwCIF->CCYA);
++ uiCurUAddr = (HwCIF->CCUA);
++ uiCurVAddr = (HwCIF->CCVA);
++#else //(CONFIG_ARCH_TCC92X)
++ uiCurYAddr = (&HwCCYA);
++ uiCurUAddr = (&HwCCUA);
++ uiCurVAddr = (&HwCCVA);
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_getCurLineCnt
++//
++// DESCRIPTION
++// get CIF register : HwCCLC
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_GetCurLineCnt(volatile unsigned long *uiCurLineCount)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ uiCurLineCount = HwCIF->CCVA;
++#else //(CONFIG_ARCH_TCC92X)
++ uiCurLineCount = &HwCCLC;
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setEffectMode
++//
++// DESCRIPTION
++// CIF effect setting
++// set CIF register : HwCEM
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetEffectMode(unsigned int uiFlag)
++{
++ unsigned int uiValue = 1;
++
++#if defined(CONFIG_ARCH_TCC79X)
++ BITCSET(HwCEM, 0xFFFFFFFF, 0x00000000); // ¸ðµÎ 0 ½ÃÅ´
++
++ // HwCEM_UVS Hw15 // UV Swap 0:u-v-u-v sequence, 1:v-u-v-u sequence
++ if(uiFlag & SET_CIF_CEM_UVS)
++ {
++ BITCSET(HwCEM, HwCEM_UVS, (uiValue<<15)); // (uiValue<<15)); only u-v-u-v sequence
++ }
++
++ // HwCEM_VB Hw14 // V Bias (V channel value offset), 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_VB)
++ {
++ BITCSET(HwCEM, HwCEM_VB, (uiValue<<14));
++ }
++
++ // HwCEM_UB Hw13 // U Bias (U channel value offset), 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_UB)
++ {
++ BITCSET(HwCEM, HwCEM_UB, (uiValue<<13));
++ }
++
++ // HwCEM_YB Hw12 // Y Bias (Y channel value offset), 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_YB)
++ {
++ BITCSET(HwCEM, HwCEM_YB, (uiValue<<12));
++ }
++
++ // HwCEM_YCS Hw11 // YC Swap 0:u-y-v-y sequence, 1:y-u-y-v sequence
++ if(uiFlag & SET_CIF_CEM_YCS)
++ {
++ BITCSET(HwCEM, HwCEM_YCS, (uiValue<<11)); // (uiValue<<11)); only y-u-y-v sequence
++ }
++
++ // HwCEM_IVY Hw10 // Invert Y, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_IVY)
++ {
++ BITCSET(HwCEM, HwCEM_IVY, (uiValue<<10));
++ }
++
++ // HwCEM_STC Hw9 // Strong C, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_STC)
++ {
++ BITCSET(HwCEM, HwCEM_STC, (uiValue<<9));
++ }
++
++ // HwCEM_YCL Hw8 // Y Clamp (Y value clipping), 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_YCL)
++ {
++ BITCSET(HwCEM, HwCEM_YCL, (uiValue<<8));
++ }
++
++ // HwCEM_CS Hw7 // C Select (Color filter), 0:disable, 1:Enable(Color filter)
++ if(uiFlag & SET_CIF_CEM_CS )
++ {
++ BITCSET(HwCEM, HwCEM_CS , (uiValue<<7));
++ }
++
++ // HwCEM_SKT Hw6 // Sketch Enable, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_SKT)
++ {
++ BITCSET(HwCEM, HwCEM_SKT, (uiValue<<6));
++ }
++
++ // HwCEM_EMM Hw5 // Emboss mode, 0:Positive emboss, 1:Negative emboss
++ if(uiFlag & SET_CIF_CEM_EMM)
++ {
++ BITCSET(HwCEM, HwCEM_EMM, (uiValue<<5));
++ }
++
++ // HwCEM_EMB Hw4 // Emboss, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_EMB)
++ {
++ BITCSET(HwCEM, HwCEM_EMB, (uiValue<<4));
++ }
++
++ // HwCEM_NEGA Hw3 // Negative mode, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_NEGA)
++ {
++ BITCSET(HwCEM, HwCEM_NEGA, (uiValue<<3));
++ }
++
++ // HwCEM_GRAY Hw2 // Gray mode, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_GRAY)
++ {
++ BITCSET(HwCEM, HwCEM_GRAY, (uiValue<<2));
++ }
++
++ // HwCEM_SEPI Hw1 // Sepia mode, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_SEPI)
++ {
++ BITCSET(HwCEM, HwCEM_SEPI, (uiValue<<1));
++ }
++
++ // HwCEM_NOR Hw0 // Normal mode, 0:Effect mode, 1:Normal mode
++ if(uiFlag & SET_CIF_CEM_NOR)
++ {
++ BITCSET(HwCEM, HwCEM_NOR, (uiValue)); // ¸ðµÎ 0 ½ÃÅ°°í normal ¸¸ 1
++ }
++
++ // ALL_CLEAR
++ if(uiFlag & SET_CIF_CEM_ALL_CLEAR)
++ {
++ BITCSET(HwCEM, 0xFFFFFFFF, 0x00000000); // ¸ðµÎ 0 ½ÃÅ´
++ } // HwCEM->CEM
++#else //(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ BITCSET(HwCEM->CEM, 0xFFFFFFFF, 0x00000000); // ¸ðµÎ 0 ½ÃÅ´
++
++ // HwCEM_UVS Hw15 // UV Swap 0:u-v-u-v sequence, 1:v-u-v-u sequence
++ if(uiFlag & SET_CIF_CEM_UVS)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_UVS, (uiValue<<15)); // (uiValue<<15)); only u-v-u-v sequence
++ }
++
++ // HwCEM_VB Hw14 // V Bias (V channel value offset), 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_VB)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_VB, (uiValue<<14));
++ }
++
++ // HwCEM_UB Hw13 // U Bias (U channel value offset), 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_UB)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_UB, (uiValue<<13));
++ }
++
++ // HwCEM_YB Hw12 // Y Bias (Y channel value offset), 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_YB)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_YB, (uiValue<<12));
++ }
++
++ // HwCEM_YCS Hw11 // YC Swap 0:u-y-v-y sequence, 1:y-u-y-v sequence
++ if(uiFlag & SET_CIF_CEM_YCS)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_YCS, (uiValue<<11)); // (uiValue<<11)); only y-u-y-v sequence
++ }
++
++ // HwCEM_IVY Hw10 // Invert Y, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_IVY)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_IVY, (uiValue<<10));
++ }
++
++ // HwCEM_STC Hw9 // Strong C, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_STC)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_STC, (uiValue<<9));
++ }
++
++ // HwCEM_YCL Hw8 // Y Clamp (Y value clipping), 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_YCL)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_YCL, (uiValue<<8));
++ }
++
++ // HwCEM_CS Hw7 // C Select (Color filter), 0:disable, 1:Enable(Color filter)
++ if(uiFlag & SET_CIF_CEM_CS )
++ {
++ BITCSET(HwCEM->CEM, HwCEM_CS , (uiValue<<7));
++ }
++
++ // HwCEM_SKT Hw6 // Sketch Enable, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_SKT)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_SKT, (uiValue<<6));
++ }
++
++ // HwCEM_EMM Hw5 // Emboss mode, 0:Positive emboss, 1:Negative emboss
++ if(uiFlag & SET_CIF_CEM_EMM)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_EMM, (uiValue<<5));
++ }
++
++ // HwCEM_EMB Hw4 // Emboss, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_EMB)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_EMB, (uiValue<<4));
++ }
++
++ // HwCEM_NEGA Hw3 // Negative mode, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_NEGA)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_NEGA, (uiValue<<3));
++ }
++
++ // HwCEM_GRAY Hw2 // Gray mode, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_GRAY)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_GRAY, (uiValue<<2));
++ }
++
++ // HwCEM_SEPI Hw1 // Sepia mode, 0:disable, 1:Enable
++ if(uiFlag & SET_CIF_CEM_SEPI)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_SEPI, (uiValue<<1));
++ }
++
++ // HwCEM_NOR Hw0 // Normal mode, 0:Effect mode, 1:Normal mode
++ if(uiFlag & SET_CIF_CEM_NOR)
++ {
++ BITCSET(HwCEM->CEM, HwCEM_NOR, (uiValue)); // ¸ðµÎ 0 ½ÃÅ°°í normal ¸¸ 1
++ }
++
++ // ALL_CLEAR
++ if(uiFlag & SET_CIF_CEM_ALL_CLEAR)
++ {
++ BITCSET(HwCEM->CEM, 0xFFFFFFFF, 0x00000000); // ¸ðµÎ 0 ½ÃÅ´
++ } // HwCEM->CEM
++#endif
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setEffectSepiaUV
++//
++// DESCRIPTION
++// CIF effect setting
++// set CIF register : HwCSUV
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetEffectSepiaUV(unsigned int uiSepiaU, unsigned int uiSepiaV)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ BITCSET(HwCEM->CSUV, HwHwCSUV_SEPIA_U, (uiSepiaU<<8));
++ BITCSET(HwCEM->CSUV, HwHwCSUV_SEPIA_V, (uiSepiaV)); // HwCEM->CSUV
++#else //(CONFIG_ARCH_TCC92X)
++ BITCSET(HwCSUV, HwHwCSUV_SEPIA_U, (uiSepiaU<<8));
++ BITCSET(HwCSUV, HwHwCSUV_SEPIA_V, (uiSepiaV)); // HwCEM->CSUV
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setEffectColorSelect
++//
++// DESCRIPTION
++// CIF effect setting
++// set CIF register : HwCCS
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetEffectColorSelect(unsigned int uiUStart, unsigned int uiUEnd,
++ unsigned int uiVStart, unsigned int uiVEnd)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ BITCSET(HwCEM->CCS, HwCCS_USTART, (uiUStart<<24));
++ BITCSET(HwCEM->CCS, HwCCS_UEND, (uiUEnd<<16));
++ BITCSET(HwCEM->CCS, HwCCS_VSTART, (uiVStart<<8));
++ BITCSET(HwCEM->CCS, HwCCS_VEND, (uiVEnd)); // HwCEM->CCS
++#else //(CONFIG_ARCH_TCC92X)
++ BITCSET(HwCCS, HwCCS_USTART, (uiUStart<<24));
++ BITCSET(HwCCS, HwCCS_UEND, (uiUEnd<<16));
++ BITCSET(HwCCS, HwCCS_VSTART, (uiVStart<<8));
++ BITCSET(HwCCS, HwCCS_VEND, (uiVEnd)); // HwCEM->CCS
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setEffectHFilterCoeff
++//
++// DESCRIPTION
++// CIF effect setting
++// set CIF register : HwCHFC_COEF
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetEffectHFilterCoeff(unsigned int uiCoeff0, unsigned int uiCoeff1, unsigned int uiCoeff2)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ BITCSET(HwCEM->CHFC, HwCHFC_COEF0, (uiCoeff0<<16));
++ BITCSET(HwCEM->CHFC, HwCHFC_COEF1, (uiCoeff1<<8));
++ BITCSET(HwCEM->CHFC, HwCHFC_COEF2, (uiCoeff2)); // HwCEM->CHFC
++#else //(CONFIG_ARCH_TCC92X)
++ BITCSET(HwCHFC, HwCHFC_COEF0, (uiCoeff0<<16));
++ BITCSET(HwCHFC, HwCHFC_COEF1, (uiCoeff1<<8));
++ BITCSET(HwCHFC, HwCHFC_COEF2, (uiCoeff2));
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setEffectSketchTh
++//
++// DESCRIPTION
++// CIF effect setting
++// set CIF register : HwCST
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetEffectSketchTh(unsigned int uithreshold)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ BITCSET(HwCEM->CST, HwCST_THRESHOLD, (uithreshold)); // HwCEM->CST
++#else //(CONFIG_ARCH_TCC92X)
++ BITCSET(HwCST, HwCST_THRESHOLD, (uithreshold)); // HwCEM->CST
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setEffectClampTh
++//
++// DESCRIPTION
++// CIF effect setting
++// set CIF register : HwCCT
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetEffectClampTh(unsigned int uithreshold)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ BITCSET(HwCEM->CCT, HwCCT_THRESHOLD, (uithreshold)); //HwCEM->CCT
++#else //(CONFIG_ARCH_TCC92X)
++ BITCSET(HwCCT, HwCCT_THRESHOLD, (uithreshold)); //HwCEM->CCT
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setEffectBias
++//
++// DESCRIPTION
++// CIF effect setting
++// set CIF register : HwCBR
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetEffectBias(unsigned int uiYBias, unsigned int uiUBias, unsigned int uiVBias)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ BITCSET(HwCEM->CBR, HwCBR_YBIAS, (uiYBias<<16));
++ BITCSET(HwCEM->CBR, HwCBR_UBIAS, (uiUBias<<8));
++ BITCSET(HwCEM->CBR, HwCBR_VBIAS, (uiVBias)); //PEFFECT->CBR
++#else //(CONFIG_ARCH_TCC92X)
++ BITCSET(HwCBR, HwCBR_YBIAS, (uiYBias<<16));
++ BITCSET(HwCBR, HwCBR_UBIAS, (uiUBias<<8));
++ BITCSET(HwCBR, HwCBR_VBIAS, (uiVBias)); //PEFFECT->CBR
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setInpathCtrl
++//
++// DESCRIPTION
++// get CIF register : HwCIC
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetInpathCtrl(unsigned int uiType, unsigned int uiHWait,
++ unsigned int uiStrobeCycle, unsigned int uiInpathWait)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ if(uiType & SET_CIF_INPATH_H_WAIT)
++ {
++ BITCSET(HwCEM->INPATH_CTRL, HwCIC_H2H_WAIT, (uiHWait << 16));
++ }
++
++ if(uiType & SET_CIF_INPATH_S_CYCLE)
++ {
++ BITCSET(HwCEM->INPATH_CTRL, HwCIC_STB_CYCLE, (uiStrobeCycle << 8));
++ }
++
++ if(uiType & SET_CIF_INPATH_I_WAIT)
++ {
++ BITCSET(HwCEM->INPATH_CTRL, HwCIC_INP_WAIT, (uiInpathWait << 4));
++ }
++
++ if(uiType & SET_CIF_INPATH_R_ENABLE)
++ {
++ BITSET(HwCEM->INPATH_CTRL, HwCIC_INPR);
++ }
++
++ if(uiType & SET_CIF_INPATH_R_DISABLE)
++ {
++ BITCLR(HwCEM->INPATH_CTRL, HwCIC_INPR);
++ }
++
++ if(uiType & SET_CIF_INPATH_FLUSH_ENABLE)
++ {
++ BITSET(HwCEM->INPATH_CTRL, HwCIC_FA);
++ }
++
++ if(uiType & SET_CIF_INPATH_FLUSH_DISABLE)
++ {
++ BITCLR(HwCEM->INPATH_CTRL, HwCIC_FA);
++ }
++
++ if(uiType & SET_CIF_INPATH_ENABLE)
++ {
++ BITSET(HwCEM->INPATH_CTRL, HwCIC_INE);
++ }
++
++ if(uiType & SET_CIF_INPATH_DISABLE)
++ {
++ BITCLR(HwCEM->INPATH_CTRL, HwCIC_INE);
++ }
++
++ if(uiType & SET_CIF_INPATH_MEM)
++ {
++ BITSET(HwCEM->INPATH_CTRL, HwCIC_INP);
++ }
++
++ if(uiType & SET_CIF_INPATH_CAM)
++ {
++ BITCLR(HwCEM->INPATH_CTRL, HwCIC_INP);
++ }
++#else //(CONFIG_ARCH_TCC92X)
++ if(uiType & SET_CIF_INPATH_H_WAIT)
++ {
++ BITCSET(HwCIC, HwCIC_H2H_WAIT, (uiHWait << 16));
++ }
++
++ if(uiType & SET_CIF_INPATH_S_CYCLE)
++ {
++ BITCSET(HwCIC, HwCIC_STB_CYCLE, (uiStrobeCycle << 8));
++ }
++
++ if(uiType & SET_CIF_INPATH_I_WAIT)
++ {
++ BITCSET(HwCIC, HwCIC_INP_WAIT, (uiInpathWait << 4));
++ }
++
++ if(uiType & SET_CIF_INPATH_R_ENABLE)
++ {
++ BITSET(HwCIC, HwCIC_INPR);
++ }
++
++ if(uiType & SET_CIF_INPATH_R_DISABLE)
++ {
++ BITCLR(HwCIC, HwCIC_INPR);
++ }
++
++ if(uiType & SET_CIF_INPATH_FLUSH_ENABLE)
++ {
++ BITSET(HwCIC, HwCIC_FA);
++ }
++
++ if(uiType & SET_CIF_INPATH_FLUSH_DISABLE)
++ {
++ BITCLR(HwCIC, HwCIC_FA);
++ }
++
++ if(uiType & SET_CIF_INPATH_ENABLE)
++ {
++ BITSET(HwCIC, HwCIC_INE);
++ }
++
++ if(uiType & SET_CIF_INPATH_DISABLE)
++ {
++ BITCLR(HwCIC, HwCIC_INE);
++ }
++
++ if(uiType & SET_CIF_INPATH_MEM)
++ {
++ BITSET(HwCIC, HwCIC_INP);
++ }
++
++ if(uiType & SET_CIF_INPATH_CAM)
++ {
++ BITCLR(HwCIC, HwCIC_INP);
++ }
++
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setInpathAddr
++//
++// DESCRIPTION
++// set CIF register : HwCISA1,HwCISA2, HwCISA3
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetInpathAddr(unsigned int uiSrcType, unsigned int uiSrcBase, unsigned int uiSrcBaseY,
++ unsigned int uiSrcBaseU, unsigned int uiSrcBaseV)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ BITCSET(HwCEM->CISA2, HwCISA2_SRC_TYPE_420SEPA, (uiSrcType<<28)); // HwCEM->CISA2
++ BITCSET(HwCEM->CISA1, HwCISA1_SRC_BASE, (uiSrcBase << 28)); // HwCEM->CISA1
++ //HwCISA1_SRC_BASE_Y 0x0FFFFFFF // SRC_BASE_Y [27:0] Source base address in Y channel (27 down to 0 bit assign in bass address)
++ BITCSET(HwCEM->CISA1, HwCISA1_SRC_BASE_Y, (uiSrcBaseY)); // HwCEM->CISA1
++ //HwCISA2_SRC_BASE_U 0x0FFFFFFF // SRC_BASE_U [27:0] Source base address in U channal (27 down to 0 bit assign in base address)
++ BITCSET(HwCEM->CISA2, HwCISA2_SRC_BASE_U, (uiSrcBaseU)); // HwCEM->CISA2
++ //HwCISA3_SRC_BASE_V 0x0FFFFFFF // SRC_BASE_V [27:0] Source base address in V channal (27 down to 0 bit assign in base address)
++ BITCSET(HwCEM->CISA3, HwCISA3_SRC_BASE_V, (uiSrcBaseV)); // HwCEM->CISA3
++#else //(CONFIG_ARCH_TCC92X)
++ BITCSET(HwCISA2, HwCISA2_SRCTYPE_420SEP, (uiSrcType<<28));
++ BITCSET(HwCISA1, HwCISA1_SRC_BASE, (uiSrcBase << 28)); // HwCEM->CISA1
++ //HwCISA1_SRC_BASE_Y 0x0FFFFFFF // SRC_BASE_Y [27:0] Source base address in Y channel (27 down to 0 bit assign in bass address)
++ BITCSET(HwCISA1, HwCISA1_SRC_BASE_Y, (uiSrcBaseY)); // HwCEM->CISA1
++ //HwCISA2_SRC_BASE_U 0x0FFFFFFF // SRC_BASE_U [27:0] Source base address in U channal (27 down to 0 bit assign in base address)
++ BITCSET(HwCISA2, HwCISA2_SRC_BASE_U, (uiSrcBaseU)); // HwCEM->CISA2
++ //HwCISA3_SRC_BASE_V 0x0FFFFFFF // SRC_BASE_V [27:0] Source base address in V channal (27 down to 0 bit assign in base address)
++ BITCSET(HwCISA3, HwCISA3_SRC_BASE_V, (uiSrcBaseV)); // HwCEM->CISA3
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setInpathScale
++//
++// DESCRIPTION
++// set CIF register : HwCISS, HwCISO, HwCIDS, HwCIS
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetInpathScale(unsigned int uiType, unsigned int uiSrcHSize, unsigned int uiSrcVSize,
++ unsigned int uiOffY, unsigned int uiOffC, unsigned int uiDstHSize,
++ unsigned int uiDstVSize, unsigned int uiHScale, unsigned int uiVScale)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ if(uiType & SET_CIF_INPATH_SRC_SIZE)
++ {
++ BITCSET(HwCEM->CISS, HwCISS_SRC_HSIZE, (uiSrcHSize<<16)); // PEFFECT->CISS
++ BITCSET(HwCEM->CISS, HwCISS_SRC_VSIZE, (uiSrcVSize));
++ }
++
++ if(uiType & SET_CIF_INPATH_SRC_OFFSET)
++ {
++ BITCSET(HwCEM->CISO, HwCISO_SRC_OFFSET_Y, (uiOffY<<16)); //HwCEM->CISO
++ BITCSET(HwCEM->CISO, HwCISO_SRC_OFFSET_C, (uiOffC));
++ }
++
++ if(uiType & SET_CIF_INPATH_DST_SIZE)
++ {
++ BITCSET(HwCEM->CIDS, HwCIDS_DST_HSIZE, (uiDstHSize<<16)); // HwCEM->CIDS
++ BITCSET(HwCEM->CIDS, HwCIDS_DST_VSIZE, (uiDstVSize));
++ }
++
++ if(uiType & SET_CIF_INPATH_SCALE)
++ {
++ BITCSET(HwCEM->CIS, HwCIS_HSCALE, (uiHScale<<16)); // HwCEM->CIS
++ BITCSET(HwCEM->CIS, HwCIS_VSCALE, (uiVScale));
++ }
++#else //(CONFIG_ARCH_TCC92X)
++ if(uiType & SET_CIF_INPATH_SRC_SIZE)
++ {
++ BITCSET(HwCISS, HwCISS_SRC_HSIZE, (uiSrcHSize<<16)); // HwCEM->CISS
++ BITCSET(HwCISS, HwCISS_SRC_VSIZE, (uiSrcVSize));
++ }
++
++ if(uiType & SET_CIF_INPATH_SRC_OFFSET)
++ {
++ BITCSET(HwCISO, HwCISO_SRC_OFFSET_Y, (uiOffY<<16)); //HwCEM->CISO
++ BITCSET(HwCISO, HwCISO_SRC_OFFSET_C, (uiOffC));
++ }
++
++ if(uiType & SET_CIF_INPATH_DST_SIZE)
++ {
++ BITCSET(HwCIDS, HwCIDS_DST_HSIZE, (uiDstHSize<<16)); // HwCEM->CIDS
++ BITCSET(HwCIDS, HwCIDS_DST_VSIZE, (uiDstVSize));
++ }
++
++ if(uiType & SET_CIF_INPATH_SCALE)
++ {
++ BITCSET(HwCIS, HwCIS_HSCALE, (uiHScale<<16)); // HwCEM->CIS
++ BITCSET(HwCIS, HwCIS_VSCALE, (uiVScale));
++ }
++#endif
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setDownScale
++//
++// DESCRIPTION
++// set CIF register : HwCDS
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetDownScale(unsigned int uiScaleEnable, unsigned int uiXScale, unsigned int uiYScale)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ BITCSET(HwCIF->CDS, HwCDS_SEN_EN, uiScaleEnable); // HwCIF->CDS
++ BITCSET(HwCIF->CDS, HwCDS_SFH_8, (uiXScale << 4));
++ BITCSET(HwCIF->CDS, HwCDS_SFV_8, (uiYScale << 2));
++#else //(CONFIG_ARCH_TCC92X)
++ BITCSET(HwCDS, HwCDS_SEN_EN, uiScaleEnable); // HwCIF->CDS
++ BITCSET(HwCDS, HwCDS_SFH_8, (uiXScale << 4));
++ BITCSET(HwCDS, HwCDS_SFV_8, (uiYScale << 2));
++#endif
++}
++
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setScalerCtrl
++//
++// DESCRIPTION
++// CIF Scaler control
++// set CIF register : HwSCC
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetScalerCtrl(unsigned int uiEN)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ if(uiEN & SET_CIF_SCALER_ENABLE) // HwCSC->CSC
++ {
++ BITSET(HwCSC->CSC, HwSCC_EN); // PCIFSACLER ¹Ù·Î ¿¬°áÇصµ µÉ°Í °°À½.
++ }
++
++ if(uiEN & SET_CIF_SCALER_DISABLE)
++ {
++ BITCLR(HwCSC->CSC, HwSCC_EN);
++ }
++#else //(CONFIG_ARCH_TCC92X)
++ if(uiEN & SET_CIF_SCALER_ENABLE) // HwCSC->CSC
++ {
++ BITSET(HwCSC, HwCSC_EN);
++ }
++
++ if(uiEN & SET_CIF_SCALER_DISABLE)
++ {
++ BITCLR(HwCSC, HwCSC_EN);
++ }
++#endif
++}
++
++/*------------------------------------------------------------------------*/
++// NAME : DEV_CIF_setFreeScale
++//
++// DESCRIPTION
++// CIF scaler setting
++// set CIF register : HwSCSS, HwSCSO, HwSCDS, HwSCSF
++//
++// Parameters
++//
++// Returns
++//
++/* -----------------------------------------------------------------------*/
++void TDD_CIF_SetFreeScale(unsigned int uiType, unsigned int uiSrcHSize, unsigned int uiSrcVSize,
++ unsigned int uiOffH, unsigned int uiOffV, unsigned int uiDstHSize,
++ unsigned int uiDstVSize, unsigned int uiHFactor, unsigned int uiVFactor)
++{
++#if defined(CONFIG_ARCH_TCC92X) || defined(CONFIG_ARCH_TCC8900)
++ if(uiType & SET_CIF_SCALER_SRC_SIZE)
++ {
++ BITCSET(HwCSC->CSSS, HwSCSS_HSIZE, (uiSrcHSize<<16)); // HwCSC->CSSS
++ BITCSET(HwCSC->CSSS, HwSCSS_VSIZE, (uiSrcVSize));
++ }
++
++ if(uiType & SET_CIF_SCALER_SRC_OFFSET)
++ {
++ BITCSET(HwCSC->CSSO, HwSCSO_OFFSET_H, (uiOffH<<16)); // HwCSC->CSSO
++ BITCSET(HwCSC->CSSO, HwSCSO_OFFSET_V, (uiOffV));
++ }
++
++ if(uiType & SET_CIF_SCALER_DST_SIZE)
++ {
++ BITCSET(HwCSC->CSDS, HwSCDS_HSIZE, (uiDstHSize<<16)); // HwCSC->CSDS
++ BITCSET(HwCSC->CSDS, HwSCDS_VSIZE, (uiDstVSize));
++ }
++
++ if(uiType & SET_CIF_SCALER_FACTOR)
++ {
++ BITCSET(HwCSC->CSSF, HwSCSF_HSCALE, (uiHFactor<<16)); // HwCSC->CSSF
++ BITCSET(HwCSC->CSSF, HwSCSF_VSCALE, (uiVFactor));
++ }
++#else //(CONFIG_ARCH_TCC92X)
++ if(uiType & SET_CIF_SCALER_SRC_SIZE)
++ {
++ BITCSET(HwCSSS, HwCSSS_HSIZE, (uiSrcHSize<<16));
++ BITCSET(HwCSSS, HwCSSS_VSIZE, (uiSrcVSize));
++ }
++
++ if(uiType & SET_CIF_SCALER_SRC_OFFSET)
++ {
++ BITCSET(HwCSSO, HwCSSO_OFFSET_H, (uiOffH<<16));
++ BITCSET(HwCSSO, HwCSSO_OFFSET_V, (uiOffV));
++ }
++
++ if(uiType & SET_CIF_SCALER_DST_SIZE)
++ {
++ BITCSET(HwCSDS, HwCSDS_HSIZE, (uiDstHSize<<16));
++ BITCSET(HwCSDS, HwCSDS_VSIZE, (uiDstVSize));
++ }
++
++ if(uiType & SET_CIF_SCALER_FACTOR)
++ {
++ BITCSET(HwCSSF, HwCSSF_HSCALE, (uiHFactor<<16));
++ BITCSET(HwCSSF, HwCSSF_VSCALE, (uiVFactor));
++ }
++#endif
++
++}
++
++/* end of file */
++
+diff --git a/drivers/media/video/tcccam/tdd_cif.h b/drivers/media/video/tcccam/tdd_cif.h
+new file mode 100644
+index 0000000..f146c76
+--- /dev/null
++++ b/drivers/media/video/tcccam/tdd_cif.h
+@@ -0,0 +1 @@
++/************************************************************************ * Telechips Multi Media Player * ------------------------------------------------ * * FUNCTION : CAMERA INTERFACE API * MODEL : DMP * CPU NAME : TCCXXX * SOURCE : tdd_cif.h * * START DATE : 2008. 4. 17. * MODIFY DATE : * DEVISION : DEPT. SYSTEM 3-2 TEAM * : TELECHIPS, INC. ************************************************************************/ #ifndef _TDD_CIF_H_ #define _TDD_CIF_H_ extern void TDD_CIF_Initialize(void); extern void TDD_CIF_Reset(void); extern void TDD_CIF_ONOFF(unsigned int uiOnOff); extern void TDD_CIF_Termination(void); extern void TDD_CIF_Reset(void); /**************************************************************************** * * Function of * * DDI_CIF_SetInfo * * Input : uiFlag * uiBypass : SEPARATE / NON_SEPARATE * uiBypassBusSel : FIRST_MSB / FIRST LSB (by 16bit mode) * uiColorPattern : YUV / RGB * uiPatternFormat : YUV444 / YUV422 / YUV420 or RGB mode * uiRGBMode : In RGB mode BAYER RGB, RGB565, RGB555 mode * uiRGBBitMode : Data bus bit 16bit mode, 8bit (enable sync), 8bit (disable sync) * uiColorSequence : Color sequence.. * uiBusOrder : Swap the MSB/LSB data bus * uiOverlayCNT : Overlay Count * Output : * Return : none * * Description : Input Image Color/Pattern Configuration (ICPCR1) *****************************************************************************/ extern void TDD_CIF_SetInfo(unsigned int uiFlag, unsigned int uiBypass, unsigned int uiBypassBusSel, unsigned int uiColorPattern, unsigned int uiPatternFormat, unsigned int uiRGBMode, unsigned int uiRGBBitMode, unsigned int uiColorSequence, unsigned int uiBusOrder); /**************************************************************************** * * Function of * * DDI_CIF_SetTransfer * * Input : uiFlag * uiTransMode : BURST / INC * uiBurst : BurstSize * uiLock : Lock transfer * Output : * Return : none * * Description : Camera I/F DMA transfer mode (CDCR1) *****************************************************************************/ extern void TDD_CIF_SetTransfer(unsigned int uiFlag, unsigned int uiBurst, unsigned int uiLock, unsigned int uiTransMode); /**************************************************************************** * * Function of * * DDI_CIF_SetOverlay * * Input : uiFlag * uiOverlayCNT : Overlay Count * uiOverlayMethod : Full / Block image * uiXOR1 : XOR operation 1 * uiXOR0 : XOR operation 0 * uiAlpha1 : Alpha value in alpha 1 (0-25%, 1-50%, 2-75%, 3-100%) * uiAlpha0 : Alpha value in alpha 0 (0-25%, 1-50%, 2-75%, 3-100%) * * Output : * Return : none * * Description : Camera I/F Overlay control (OCTRL1) *****************************************************************************/ extern void TDD_CIF_SetOverlay(unsigned int uiFlag, unsigned int uiOverlayCNT, unsigned int uiOverlayMethod, unsigned int uiXOR1, unsigned int uiXOR0, unsigned int uiAlpha1, unsigned int uiAlpha0); /**************************************************************************** * * Function of * * DDI_CIF_SetOverlayKey * * Input : uiFlag * uiKEYR : Chroma-key value R(U) * uiKEYG : Chroma-key value G(Y) * uiKEYB : Chroma-key value B(V) * uiMKEYR : Mask Chroma-key value R(U) * uiMKEYG : Mask Chroma-key value G(Y) * uiMKEYB : Mask Chroma-key value B(V) * Output : * Return : none * * Description : Camera I/F Overlay key value control 2/3 (OCTRL2/OCTRL3) *****************************************************************************/ extern void TDD_CIF_SetOverlayKey(unsigned int uiFlag, unsigned int uiKEYR, unsigned int uiKEYG, unsigned int uiKEYB, unsigned int uiMKEYR, unsigned int uiMKEYG, unsigned int uiMKEYB); /**************************************************************************** * * Function of * * DDI_CIF_SetSyncPol * * Input : uiHPolarity : Horizontal polarity (active high/low) * uiVPolarity : Vertical polarity (active high/low) * Output : * Return : none * * Description : CIF_SYNC_POL (Camera I/F sync polarity) * *****************************************************************************/ extern void TDD_CIF_SetSyncPol(unsigned int uiHPolarity, unsigned int uiVpolarity); /**************************************************************************** * * Function of * * DDI_CIF_SetImage * * Input : uiType : Input imge(INPUT_IMG), overlay image (OVERLAY_IMG) * uiHsize : Horizontal size * uiVSize : vertical size * uiHorWindowingStart : start X position of windowing image * uiHorWindowingEnd : end X position of windowing image * uiVerWindowingStart : start Y position of windowing image * uiVerWindowingEnd : end Y position of windowing image * BaseAddress0 : Y channel base address In Overlay, overlay image adress * BaseAddress1 : U channel base address (don't use overlay image) * BaseAddress2 : V channel base address (don't use overlay image) * Output : * Return : none * * Description : CIF_SETIMG (Camera I/F setting image) * *****************************************************************************/ extern void TDD_CIF_SetImage(unsigned int uiType, unsigned int uiHsize, unsigned int uiVsize, unsigned int uiHorWindowingStart, unsigned int uiHorWindowingEnd, unsigned int uiVerWindowingStart, unsigned int uiVerWindowingEnd); /**************************************************************************** * * Function of * * DDI_CIF_SetScale * * Input : uiScaleEnable : Scale enable * uiXScale : Horizontal scale factor * uiYScale : Vertical scale factor * Output : * Return : none * * Description : Camera I/F Down scaler (CDS) *****************************************************************************/ extern void TDD_CIF_SetDownScale(unsigned int uiScaleEnable, unsigned int uiXScale, unsigned int uiYScale); /**************************************************************************** * * Function of * * DDI_CIF_SetBaseAddr * * Input : uiType : IN IMAGE / OVERLAY IMAGE * uiBaseAddr0 : Input image Y(G) / Overlay image base address * uiBaseAddr1 : Input image U(R) / none * uiBaseAddr2 : Input image V(B) / none * Output : * Return : none * * Description : IN IMAGE - Camera I/F DMA Configuration (CDCR2/CDCR3/CDCR4) * OVERLAY IMAGE - Camera I/F Overlay base address set (COBA) *****************************************************************************/ extern void TDD_CIF_SetBaseAddr(unsigned int uiType, unsigned int uiBaseAddr0, unsigned int uiBaseAddr1, unsigned int uiBaseAddr2); extern void TDD_CIF_SetBaseAddr_offset(unsigned int uiType, unsigned int uiOFFSET_Y, unsigned int uiOFFSET_C); /**************************************************************************** * * Function of * * DDI_CIF_OverlayCtrl * * Input : uiFlag (Alpha/Chromakey/Overlay) * uiAlphaEnable (Enable/Disable) * uiChromakeyEnable (Enable/Disable) * uiOverlayEnable (Enable/Disable) * Output : * Return : none * * Description : Camera I/F Alpha/Chromakey/Overlay enable/disable *****************************************************************************/ extern void TDD_CIF_OverlayCtrl(unsigned int uiFlag, unsigned int uiRgb); extern void TDD_CIF_SetInterrupt(unsigned int uiFlag); extern unsigned int TDD_CIF_GetIntStatus(unsigned int uiFlag); extern void TDD_CIF_SetCaptureCtrl(unsigned int uiType, unsigned int uiSkipNum, unsigned int uiVCnt, unsigned int uiFlag); extern void TDD_CIF_SetCtrl(unsigned int uiFlag, unsigned int uiPWDN, unsigned int uiBypass_Scaler, unsigned int uiPXCLK_POL, unsigned int uiSKPF, unsigned int uiM420_FC, unsigned int uiC656); extern void TDD_CIF_SetMaskIntStatus(unsigned int uiFlag); extern void TDD_CIF_SetSensorOutImgSize(unsigned int uiHsize, unsigned int uiVsize); extern void TDD_CIF_SetScalerCtrl(unsigned int uiEN); extern void TDD_CIF_SetFreeScale(unsigned int uiType, unsigned int uiSrcHSize, unsigned int uiSrcVSize, unsigned int uiOffH, unsigned int uiOffV, unsigned int uiDstHSize, unsigned int uiDstVSize, unsigned int uiHFactor, unsigned int uiVFactor); extern void TDD_CIF_SetEffectMode(unsigned int uiFlag); extern void TDD_CIF_SetEffectSepiaUV(unsigned int uiSepiaU, unsigned int uiSepiaV); extern void TDD_CIF_SetEffectColorSelect(unsigned int uiUStart, unsigned int uiUEnd, unsigned int uiVStart, unsigned int uiVEnd); extern void TDD_CIF_SetEffectHFilterCoeff(unsigned int uiCoeff0, unsigned int uiCoeff1, unsigned int uiCoeff2); extern void TDD_CIF_SetEffectSketchTh(unsigned int uithreshold); extern void TDD_CIF_SetEffectClampTh(unsigned int uithreshold); extern void TDD_CIF_SetEffectBias(unsigned int uiYBias, unsigned int uiUBias, unsigned int uiVBias); #endif // _TDD_CIF_H_
+\ No newline at end of file
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index fee7304..9f478c3 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -13,6 +13,11 @@ menuconfig MISC_DEVICES
+
+ if MISC_DEVICES
+
++config SMARTQV_ENCRYPT
++ tristate "AT88SC5211C CryptoMemory Device driver for SmartQV5 and SmartQV7"
++ depends on MACH_TCC8900
++ ---help---
++
+ config ATMEL_PWM
+ tristate "Atmel AT32/AT91 PWM support"
+ depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index 817f7f5..6830ef1 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -3,6 +3,7 @@
+ #
+ obj- := misc.o # Dummy rule to force built-in.o to be made
+
++obj-$(CONFIG_SMARTQV_ENCRYPT) += smartqv_encrypt/
+ obj-$(CONFIG_IBM_ASM) += ibmasm/
+ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
+ obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
+diff --git a/drivers/misc/smartqv_encrypt/Makefile b/drivers/misc/smartqv_encrypt/Makefile
+new file mode 100644
+index 0000000..3f258c3
+--- /dev/null
++++ b/drivers/misc/smartqv_encrypt/Makefile
+@@ -0,0 +1,3 @@
++
++obj-$(CONFIG_SMARTQV_ENCRYPT) := smartqv_encrypt.o
++
+diff --git a/drivers/misc/smartqv_encrypt/lib_Crypto.h b/drivers/misc/smartqv_encrypt/lib_Crypto.h
+new file mode 100644
+index 0000000..9e6b634
+--- /dev/null
++++ b/drivers/misc/smartqv_encrypt/lib_Crypto.h
+@@ -0,0 +1,1426 @@
++/** \file
++ * \brief Definitions and declarations for external reference into CrytoMemory
++ * and Companion CryptoMemory Library.
++ */
++/*
++*******************************************************************************
++* |
++* File Name | lib_Crypto.h
++*------------------------------------------------------------------------------
++* Project | CryptoMemory and Companion CryptoMemory
++*------------------------------------------------------------------------------
++* Created | October 02, 2006
++*-----------------|-----------------------------------------------------------
++* Description | This file contains all the definitions and function which
++* | are used to reference to/from CryptoMemory and its
++* | Companion library.
++*-----------------|------------------------------------------------------------
++* | Copyright (c) 2006 Atmel Corp.
++* | All Rights Reserved.
++* |
++******************************************************************************
++*/
++#ifndef LIB_CRYPTO_H
++#define LIB_CRYPTO_H
++
++typedef unsigned char uchar;
++
++/** \mainpage Crypto-Memory Library Documentation
++ *
++ * \section intro_sec Introduction
++ *
++ * The CryptoMemory family is a high performance secure memory devices
++ * providing 1K to 256K bits of user memory with advanced security and
++ * cryptographic features built in. The memory is divided into 4, 8 or 16
++ * user zones each of which may be individually set with different security
++ * access rights or used together to provide space for one or multiple data
++ * files. A configuration zone contains registers to define the security
++ * rights for each user zone and space for passwords and secret keys used by
++ * the security logic of CryptoMemory.
++ *
++ * The CryptoRF family integrates a 13.56 MHz RFinterface into a CryptoMemory,
++ * resulting in a Contactless Smart Card with advanced security and
++ * cryptographic features. This device is optimized as a contactless secure
++ * memory, for multi-application RF smart card, and secure identification for
++ * electronic data transfer, without the requirement of an interal
++ * microprocessor. The CryptoRF devices provide 1K to 64K bits of user memory.
++ *
++ * The CryptoCompanion Chip is designed as the mate to Atmel`s CryptoRF and
++ * CryptoMemory chips.
++ *
++ * This Library supports the synchronous interface most useful in embedded
++ * systems. While similar to the Two Wire Interface, it is not 100% compatable.
++ *
++ * \section embedded_app Embedded Applications
++ *
++ * Through dynamic, symmetric-mutual authentication, data encryption, and
++ * the use of encrypted checksums, CryptoMemory provides a secure place for
++ * storage of sensitive information within an embedded system.
++ *
++ * A 2-wire serial interface running at 1.0 MHz is used for fast and efficient
++ * communications with up to 15 devices that may be individually addressed.
++ *
++ * \section rf_app RF Applications
++ *
++ * For communications, the RF interface utilizes the ISO 14443-2 and -3 Type B
++ * bit timing and signal modulation schemes, and the ISO 14443-3 Slot-MARKER
++ * Anticollision Protocol. Data is exchanged half duplex at a 106-kbit/s rate,
++ * with a two-byte CRC_B providing error detection capability. The maximum
++ * communication range between the reader antenna and contactless card is
++ * approximately 10 cm when used with an RFID reader that transmits the maximum
++ * ISO 14443-2 RF power level.
++ *
++ * \section detail_sec Details
++ *
++ * To enable the security features of CryptoMemory, the device must first be
++ * personalized to set up registers and load in the appropriate passwords
++ * and keys. This is accomplished though programming the configuration zone
++ * of CryptoMemory using simple write and read commands. To gain access to
++ * the configuration zone, the secure code (write 7 password) must
++ * be successfully presented. After writing and verifying data in the
++ * configuration zone, the security fuses must be blown to lock this
++ * information in the device.
++ *
++ * \subsection subsection1 Configuration Memory
++ *
++ * The configuration memory consists of 2048 bits of EEPROM memory used for
++ * storing passwords, keys, codes and defining security levels to be used for
++ * each User Zone. Access rights to the configuration memory are defined in
++ * the control logic and may not be altered by the user. These access rights
++ * include the ability to program certain portions of the Configuration Zone
++ * and then lock the data written through use of the Security Fuses. The
++ * configuration memory for each CryptoMemory device is identical with the
++ * exception of the number of Access Registers and Password/Key Registers used.
++ *
++ * Unused registers become reserved space to ensure the other components of
++ * the configuration memory remain at the same address location regardless of
++ * the number of User Zones in a device.
++ *
++ * \subsection subsection2 Communication Security Modes
++ *
++ * Communication between the device and host operates in three basic modes.
++ * Standard mode is the default mode for the device after power-up.
++ * Authentication mode is activated by a successful authentication sequence.
++ * Encryption mode is activated by a successful encryption activation following
++ * a successful authentication.
++ *
++ * \subsection subsection3 Security Operations
++ *
++ * \subsubsection subsubsection1 Password Verification
++ *
++ * Passwords may be used to protect read and write access to the user zones.
++ * Any one of 8 password sets may be assigned to any user zone through the
++ * access registers. Separate 24 bit read and write passwords are provided.
++ * A read password will only allow data to be read from the protected zone,
++ * a write password allows both read and write access. When a password is
++ * successfully presented using the verify password command it remains active
++ * until another verify password command is issued or the device is reset.
++ * Only one password may be active at a time. When an incorrect password is
++ * presented the password attempts counter (PAC) will decrement. When the
++ * PAC reaches a value of 0x00 the associated password is permanently disabled
++ * and the protected user zone(s) cannot be accessed.
++ *
++ * \subsubsection subsubsection2 Authentication Protocol
++ *
++ * An authentication protocol may be used to protect access to the user zones.
++ * Any one of 4 key sets may be assigned to any user zone through the access
++ * registers. Each key set consists of a secret seed, cryptogram and session
++ * key. When the authentication communication mode is successfully entered
++ * with the verify authentication command the specific key set remains active
++ * until another verify authentication command is issued or the device is
++ * reset. An unsuccessful verify authentication command will deactivate the
++ * key set. Only one key set may be active at a time. When an incorrect
++ * authentication attempt is made the authentication attempts counter (AAC)
++ * will decrement. When the AAC reaches a value of 0x00 the associated key set
++ * is permanently disabled and the protected user zone(s) cannot be accessed.
++ *
++ * \subsubsection subsubsection3 Data Encryption
++ *
++ * The data exchanged between the CryptoMemory device and the host logic
++ * during read, write and verify password commands may be encrypted to ensure
++ * data confidentiality. This may be accomplished at the option of the host
++ * logic by executing the verify encryption command after a successful
++ * authentication using the same key set. Encryption may be required for any
++ * data exchange to a specific user zone by the proper setting of the access
++ * registers. In this case the successful completion of verify authentication
++ * and verify encryption commands is required before any data may be read
++ * from or written to the protected user zone. Data read from the
++ * configuration zone is never encrypted.
++ *
++ * When the encryption communication mode is successfully entered with the
++ * verify encryption command the specific key set remains active until another
++ * verify authentication command is issued or the device is reset. An
++ * unsuccessful verify encryption command will deactivate the key set and
++ * reset device security. Only one key set may be active at a time. When an
++ * incorrect encryption attempt is made the authentication attempts counter
++ * (AAC) will decrement. When the AAC reaches a value of 0x00 the associated
++ * key set is permanently disabled and the protected user zone(s) cannot be
++ * accessed. The process to activate encryption is very similar to that used
++ * to verify authentication, a calculated session key replaces the secret
++ * seed in the sequence.
++ *
++ * \subsubsection subsubsection4 Encrypted Checksum
++ *
++ * CryptoMemory implements a data validity check function in the form of an
++ * encrypted checksum. This checksum provides a bi-directional data integrity
++ * check and data origin authentication capability in the form of a Message
++ * Authentication Code (MAC): only the host/device that carried out a valid
++ * authentication is capable of computing a valid MAC. When writing data to
++ * the CryptoMemory device in authentication or encryption communication modes
++ * a valid checksum must be sent to the device immediately following the write
++ * command for data to actually be written. If the checksum sent is not
++ * correct, data will not be written to the device and security will be reset
++ * requiring a new verify authentication command to be issued to continue.
++ * When reading data the use of a checksum is optional. The read checksum
++ * command will reset device security so it is recommended to only be used
++ * after all data has been read from the device.
++ *
++ * \subsection subsection_default CryptoMemory Default Values
++ *
++ * \htmlonly
++ <TABLE CELLSPACING=10 > <TBODY> <TR>
++ <TD><B>Device</B></TD> <TD><B>ATR</B></TD>
++ <TD><B>Fab Code</B></TD> <TD><B>Lot History Code</B></TD>
++ <TD><B>Write 7 Password (Secure Code)</B></TD> </TR>
++ <TR> <TD ALIGN=CENTER>AT88SC0104C</TD>
++ <TD ALIGN=CENTER>3B B2 11 00 10 80 00 01</TD>
++ <TD ALIGN=CENTER>10 10</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>DD 42 97</TD> </TR>
++ <TR> <TD ALIGN=CENTER>AT88SC0204C</TD>
++ <TD ALIGN=CENTER>3B B2 11 00 10 80 00 02</TD>
++ <TD ALIGN=CENTER>20 20</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>E5 47 47</TD> </TR>
++ <TR> <TD ALIGN=CENTER>AT88SC0404C</TD>
++ <TD ALIGN=CENTER>3B B2 11 00 10 80 00 04</TD>
++ <TD ALIGN=CENTER>40 40</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>60 57 34</TD> </TR>
++ <TR><TD ALIGN=CENTER>AT88SC0808C</TD>
++ <TD ALIGN=CENTER>3B B2 11 00 10 80 00 08</TD>
++ <TD ALIGN=CENTER>80 60</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>22 E8 3F</TD> </TR>
++ <TR><TD ALIGN=CENTER>AT88SC1616C</TD>
++ <TD ALIGN=CENTER>3B B2 11 00 10 80 00 16</TD>
++ <TD ALIGN=CENTER>16 80</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>20 0C E0</TD> </TR>
++ <TR><TD ALIGN=CENTER>AT88SC3216C</TD>
++ <TD ALIGN=CENTER>3B B3 11 00 00 00 00 32</TD>
++ <TD ALIGN=CENTER>32 10</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>CB 28 50</TD> </TR>
++ <TR><TD ALIGN=CENTER>AT88SC6416C</TD>
++ <TD ALIGN=CENTER>3B B3 11 00 00 00 00 64</TD>
++ <TD ALIGN=CENTER>64 40</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>F7 62 0B</TD> </TR>
++ <TR><TD ALIGN=CENTER>AT88SC12816C</TD>
++ <TD ALIGN=CENTER>3B B3 11 00 00 00 01 28</TD>
++ <TD ALIGN=CENTER>28 60</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>22 EF 67</TD> </TR>
++ <TR><TD ALIGN=CENTER>AT88SC25616C</TD>
++ <TD ALIGN=CENTER>3B B3 11 00 00 00 02 56</TD>
++ <TD ALIGN=CENTER>58 60</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>17 C3 3A</TD> </TR>
++ <TR></TR> </TBODY> </TABLE> \endhtmlonly
++ *
++ * \subsection subsection_default1 CryptoRF Default Values
++ *
++ * \htmlonly
++ <TABLE CELLSPACING=10 > <TBODY> <TR>
++ <TD><B>Device</B></TD> <TD><B>Density Code</B></TD>
++ <TD><B>RBmax Code</B></TD> <TD><B>Lot History Code</B></TD>
++ <TD><B>Write 7 Password (Secure Code)</B></TD> </TR>
++ <TR> <TD ALIGN=CENTER>AT88SC0104CRF</TD>
++ <TD ALIGN=CENTER>02</TD>
++ <TD ALIGN=CENTER>10</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>10 14 7C</TD> </TR>
++ <TR> <TD ALIGN=CENTER>AT88SC0204CRF</TD>
++ <TD ALIGN=CENTER>12</TD>
++ <TD ALIGN=CENTER>10</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>20 C2 8B</TD> </TR>
++ <TR> <TD ALIGN=CENTER>AT88SC0404CRF</TD>
++ <TD ALIGN=CENTER>22</TD>
++ <TD ALIGN=CENTER>10</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>30 1D D2</TD> </TR>
++ <TR><TD ALIGN=CENTER>AT88SC0808CRF</TD>
++ <TD ALIGN=CENTER>33</TD>
++ <TD ALIGN=CENTER>10</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>40 7F AB</TD> </TR>
++ <TR><TD ALIGN=CENTER>AT88SC1616CRF</TD>
++ <TD ALIGN=CENTER>44</TD>
++ <TD ALIGN=CENTER>10</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>50 44 72</TD> </TR>
++ <TR><TD ALIGN=CENTER>AT88SC3216CRF</TD>
++ <TD ALIGN=CENTER>54</TD>
++ <TD ALIGN=CENTER>30</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>60 78 AF</TD> </TR>
++ <TR><TD ALIGN=CENTER>AT88SC6416CRF</TD>
++ <TD ALIGN=CENTER>64</TD>
++ <TD ALIGN=CENTER>30</TD> <TD ALIGN=CENTER>Variable, locked</TD>
++ <TD ALIGN=CENTER>70 BA 2E</TD> </TR>
++ <TR></TR> </TBODY> </TABLE> \endhtmlonly
++ *
++ * \section integrate-sec Integration Guide
++ * The supplied CryptoMemory Library supports the APIs list
++ * below. The following describes how to build a simple
++ * application using this library.
++ *
++ * \subsection subsection5 Files To Include.
++ * Below are files must add to system software.\n
++ *
++ * lib_Crypto.h:
++ *
++ * In your top level source file (probably the one that
++ * interface to lib_CMC.a or lib_CM.a), you will need to include lib_Crypto.h.
++ * This header file contained all external refernce APIs,
++ * defines and enumerations which are used by library or
++ * application. This file must be retained as is and no
++ * modification should be made.\n
++ *
++ * lib_CMC.a or lib_CM.a:
++ *
++ * In your IDE or makefile, you need to add lib_CMC.a or lib_CM.a for
++ * linker to link this library into your system software. This
++ * library archived from all object files generated by GNU
++ * compiler for AVR processor. If you use different
++ * processor other than AVR, you need request Atmel to
++ * generate a library to fit your environment and processor.
++ *
++ * lib_Support.c
++ *
++ * This file contains all APIs which library refers at compiler
++ * time and calls at run-time. Since this file is used as a
++ * reference file, you might change logic within these API but
++ * must retain all API names, input and output parameters as
++ * defined. Below are definitions, tables and routines which
++ * defined and implemented by Atmel. You can use them as
++ * implemented or modify to fit your system. Below are
++ * sections in the lib_Support.c file which needed to examine
++ * to fit your system software environment.
++ *
++ * \subsection subsection6 Definitions (lib_Support.c)
++ * Below are defintions must define to fit system enviroment.
++ *
++ * CM_NUM_DEVICE\n
++ * This definition is defined how many CM devices are in system
++ * \if CMC_DOXY
++ * CMC_NUM_DEVICE\n
++ * This definition is defined how many CMC devices are in
++ * system
++ * \endif
++ * \subsection subsection7 Tables (lib_Support.c)
++ * Below are tables must define to fit system enviroment.\n
++ *
++ * cm_device_addresses[]\n
++ * This table defined all CM device addresses in system with
++ * last entry must be "0". For CM, default address is 0x0B.
++ * Each device on the bus has a unique address programmed into
++ * its DCR register. CryptoMemory device always response to
++ * address "0x0B" no matter what address is programmed into the
++ * DCR. The CM device address is defined to program from bit
++ * 0-3 only.
++ * \if CMC_DOXY
++ * cmc_device_addresses[]\n
++ * This table defined all CMC device addresses in system with
++ * last entry must be "0". The CMC device address is defined to
++ * program from bit 1-7.
++ * \endif
++ * sDeviceTypeInfoTBL[]\n
++ * This table defined all possible CM device types which are
++ * supported by Atmel.
++ *
++ * \subsection subsection8 Routines (lib_Support.c)
++ * Below are routines that can be used as implemented or
++ * modified to meet system software needed. These routines
++ * will call by library at run-time.\n
++ *
++ * cm_FindDeviceIndex(uchar ucCmDevAddr)\n
++ * This routine returns a CM index from CM device address table
++ * that based from CM device address.
++ *
++ * getCMDevAddr(uchar ucIndex)\n
++ * This rotuine returns a CM device address from CM device
++ * address table that based from CM device index.
++ *
++ * getCMDevType(uchar ucIndex)\n
++ * This routine returns a CM device type from CM device type
++ * table that based from CM device index.
++ *
++ * cmc_FindDeviceIndex(uchar ucDevAddr)\n
++ * This routine returns a CMC index from CMC device address
++ * table that based from CMC device address.
++ *
++ * getCMCDevAddr(uchar ucIndex)\n
++ * This rotuine returns a CMC device address from CMC device
++ * address table that based from CMC device index.
++ *
++ * WaitForNotBusy(uchar ucDevAddr)\n
++ * This routine waits for the CMC "BUSY" bit to CLEAR.
++ *
++ * WaitForData(uchar ucDevAddr)\n
++ * This routine waits for the CMC "DATA AVAILABLE" bit to SET.
++ *
++ * WaitForStartupDone(uchar ucDevAddr)\n
++ * This routine waits for the CMC "STARTUPDONE" bit to SET.
++ *
++ * lib_memcpy(puchar pucDesMem, puchar pucSrcMem, uint uiCnt)\n
++ * This routine calls standard C library to copy number of
++ * bytes from source to destination memory.
++ *
++ * lib_memcmp(puchar pucMem1, puchar pucMem2, uint ucCnt)\n
++ * This routine calls standard C library to compare two
++ * strings.
++ *
++ * lib_malloc(uchar ucBytes)\n
++ * This rouitne calls standard C library to allocate a buffer
++ * from memeory pool.
++ *
++ * lib_free(puchar pucBuff)\n
++ * This rouitne calls standard C library to deallocate a buffer
++ * back to memeory pool.
++ *
++ * lib_rand(void)\n
++ * This rouitne calls standard C library to get a random
++ * byte.\n
++ *
++ * \subsection subsection9 APIs in library (lib_CMC.a or lib_CM.a)
++ * Below are APIs in library which avialable for other layers
++ * to call.\n
++ *
++ * getLibVersNum(void)\n
++ * Get library version
++ *
++ * cm_Init(void)\n
++ * Initializes Crypto devices.
++ *
++ * cm_WriteUserZone(uchar ucDevAddr, uint uiCryptoAddr, puchar pucBuffer, uchar ucCount)\n
++ * Writes data into the (previously set) CM user zone
++ *
++ * cm_ReadUserZone(uchar ucDevAddr, uint uiCryptoAddr, puchar pucBuffer, uchar ucCount)\n
++ * Reads data from the (previously set) CM user
++ * zone
++ *
++ * cm_WriteConfigZone(uchar ucDevAddr, uchar ucCryptoAddr, puchar pucBuffer, uchar ucCount, uchar ucAntiTearing)\n
++ * Write data into the CM Configuration Memory
++ *
++ * cm_WriteFuse(uchar ucDevAddr, uchar ucFuze)\n
++ * Writes Fuse Byte to the specified CM device address
++ *
++ * cm_SetUserZone(uchar ucDevAddr, uchar ucZoneNumber, uchar ucAntiTearing)\n
++ * Sets CM user zone
++ *
++ * cm_ReadConfigZone(uchar ucDevAddr, uchar ucCryptoAddr, puchar pucBuffer, uchar ucCount)\n
++ * Reads data from the CM Configuration Zone
++ *
++ * cm_ReadFuse(uchar ucDevAddr, puchar pucFuze)\n
++ * Reads Fuse Byte from CM device
++ *
++ * cm_ReadChecksum(uchar ucDevAddr, puchar pucChkSum)\n
++ * Reads Checksum
++ *
++ * cm_SendChecksum(uchar ucDevAddr, puchar pucChkSum)\n
++ * Sends checksum
++ *
++ * cm_VerifyCrypto(uchar ucDevAddr, uchar ucKeySet, puchar pucBuff, puchar pucBuff2, uchar ucEncrypt)\n
++ * Activates Authentication and (optionally) Encryption mode
++ *
++ * cm_ResetCrypto(uchar ucDevAddr)\n
++ * Reset authentication and encryption and resets the
++ * cryptoengine
++ *
++ * cm_VerifyPassword(uchar ucDevAddr, puchar pucPassword, uchar ucSet, uchar ucRW)\n
++ * Verifies Password.
++ * \if CMC_DOXY
++ * cmc_VerifyFlash(uchar ucCmcDevAddr, puchar pucExtDigest, puchar pucIntDigest)\n
++ * Verifies System Digest
++ *
++ * cmc_StartChallenge(uchar ucCmcDevAddr, puchar pucCmcChallenge, puchar pucCmcSeed, puchar pucSystemSeed)\n
++ * Verify Start Challenge
++ *
++ * cmc_GetRandom(uchar ucCmcDevAddr, puchar pucData)\n
++ * Gets a 20 byte random number from the Companion Chip
++ *
++ * cmc_IncrementCounter(uchar ucCmcDevAddr, uchar ucSelector)\n
++ * Increments the value of the specified counter by 1
++ *
++ * cmc_ReadCounter(uchar ucCmcDevAddr, uchar ucSelector, puchar pucData)\n
++ * Reads 32 bits of the specified counter
++ *
++ * cmc_WriteMemory(uchar ucCmcDevAddr, uint uiAddress, uchar ucCount, puchar pucData)\n
++ * Writes the contents of the specified address
++ *
++ * cmc_WriteMemoryAuthorized(uchar ucCmcDevAddr, uint uiAddress, uchar ucData, puchar pucF0)\n
++ * Authorizes to writes a single byte in the first 16 bytes of
++ * the ReadOnly section at the specified address
++ *
++ * cmc_WriteMemoryEncrypted(uchar ucCmcDevAddr, uint uiAddress,puchar pucData, puchar pucNonce)\n
++ * Writes 16 byte page of EEPROM with encryption.
++ *
++ * cmc_ReadMemory(uchar ucCmcDevAddr, uint uiAddress, uchar ucCount, puchar pucData)\n
++ * Reads the contents of the specified address.
++ *
++ * cmc_ReadMemoryDigest(uchar ucCmcDevAddr, uint uiAddress, puchar pucData)\n
++ * Reads the specified 32 byte block and computes the SHA-1
++ * digest.
++ *
++ * cmc_ReadManufID(uchar ucCmcDevAddr, puchar pucData)\n
++ * Reads the contents of the Manufacturing ID and Lock Byte
++ *
++ * cmc_Lock(uchar ucCmcDevAddr)\n
++ * Locks the current memory values into the Companion Chip.
++ *
++ * cmc_Status(uchar ucCmcDevAddr)\n
++ * Reads Status byte from CMC
++ *
++ * cmc_SHA1(puchar pucInData, uchar ucLen, puchar pucOutData)\n
++ * Calculates digest with SHA-1 algorithm\n
++ * \endif
++ */
++
++
++/*
++****************************************************
++* Defintions for CryptoMemory and Companion
++****************************************************
++*/
++// Basic Datatypes
++typedef unsigned char *puchar;
++typedef signed char schar;
++typedef signed char *pschar;
++typedef unsigned short *pushort;
++typedef signed short sushort;
++typedef signed short *pshort;
++typedef unsigned int *puint;
++typedef signed int sint;
++typedef signed int *psint;
++
++#ifdef __AVR__
++ #ifdef __GNUC__
++ #include <avr/io.h>
++ #include <avr/pgmspace.h>
++ #define ROM_READ(addr) pgm_read_word(addr)
++///< Read of program space (flash) in AVR is different from RAM read
++ #define ROM_READ_BYTE(addr) pgm_read_byte(addr)
++///< Read of program space (flash) in AVR is different from RAM read
++ #define ROM_READ_DWORD(addr) pgm_read_dword(addr)
++///< Read of program space (flash) in AVR is different from RAM read
++ #else
++ #define ROM_READ(addr) *addr
++///< Read of program space (flash) in AVR is different from RAM read
++ #define ROM_READ_BYTE(addr) *addr
++///< Read of program space (flash) in AVR is different from RAM read
++ #define ROM_READ_DWORD(addr) *addr
++///< Read of program space (flash) in AVR is different from RAM read
++ #define PROGMEM ///< Needed in GCC to differentiate ROM from RAM
++ #endif
++#else
++ #define ROM_READ(addr) *addr
++///< Read of program space (flash) in AVR is different from RAM read
++ #define ROM_READ_BYTE(addr) *addr
++///< Read of program space (flash) in AVR is different from RAM read
++ #define ROM_READ_DWORD(addr) *addr
++///< Read of program space (flash) in AVR is different from RAM read
++ #define PROGMEM ///< Needed in GCC to differentiate ROM from RAM
++#endif
++
++
++
++// Basic Definations (if not available elsewhere)
++#ifndef FALSE
++#define FALSE (0)
++#define TRUE (!FALSE)
++#endif
++#ifndef NULL
++#define NULL ((void *)0)
++#endif
++
++/** \brief Status Return Codes */
++typedef enum {
++ SUCCESS = 0x00, ///< General OK, no error
++#ifdef CMC
++ CMC_RST_LOCKED = 0x01, ///< CMC Reset Locked, disabled until power or reset cycle
++ CMC_BAD_CMD = 0x02, ///< CMC Command format or operand bad
++ CMC_TIME_DELAY = 0x03, ///< CMC Disabled for a time delay (Power or Security)
++ CMC_AUTH_FAIL = 0x04, ///< CMC Authentication required or failed
++ CMC_PERM_LOCKED = 0x07, ///< CMC Permanently locked
++ CMC_RESPONSE_FAILED = 0x0A, ///< CMC and System fail StartUp State
++ CMC_BUSY = 0x0B, ///< CMC Busy
++ CMC_DATA_NOT_AVAIL = 0x0C, ///< CMC Data Not Available
++ CMC_STARTUP_NOT_DONE =0x0D, ///< CMC and Ssytem fail Challengence State
++#endif
++ FAILED = 0x14, ///< General failure
++ FAIL_CMDSTART = 0x15, ///< Command start failed
++ FAIL_CMDSEND = 0x16, ///< Failed to send a command
++ FAIL_WRDATA = 0x17, ///< Failed to write data
++ FAIL_RDDATA = 0x18, ///< Failed to read data
++ UNKNOWN_DEVICE = 0x19, ///< Invalid device number
++ WRITE_CMD_ERROR = 0x1A, ///< Write Command Error
++ READ_CMD_ERROR = 0x1B, ///< Read Command Error
++ PASSWORD_NOT_ACCEPTED = 0x1C, ///< Write password not accepted
++ INVALID_USER_ZONE = 0x1D, ///< Wrong user zone
++ INVALID_NUM_BYTES_2WRITE = 0x1E,///< Number of bytes to write too large
++ INVALID_NUM_BYTES_2READ = 0x1F, ///< Number of bytes to read too large
++ ERROR_MAX = 255 ///< Maximum error
++
++} RETURN_CODE;
++
++
++/** \brief Below are defined of Crypto Memory device type */
++
++typedef enum {
++ UNKNOWN_DEVICE_TYPE,
++ AT88SC0104C, /// < 1 KBits User Zone
++ AT88SC0204C, /// < 2 KBits User Zone
++ AT88SC0404C, /// < 4 KBits User Zone
++ AT88SC0808C, /// < 8 KBits User Zone
++ AT88SC1616C, /// < 16 KBits User Zone
++ AT88SC3216C, /// < 32 KBits User Zone
++ AT88SC6416C, /// < 64 KBits User Zone
++ AT88SC12816C, /// < 128 KBits User Zone
++ AT88SC25616C, /// < 256 KBits User Zone
++ AT88SCRF, /// < CM for RF
++ MAX_CM_DEVICE_TYPE /// < Maximum device type
++} CM_DEVICE_TYPE;
++
++/** \brief Maximum of CM device addresses
++*/
++#define CM_MAX_DEV_ADDR 0x0F
++
++#ifdef CMC
++/** \if CMC_DOXY
++ * \brief Maximum of CMC device addresses
++ * \endif
++*/
++#define CMC_MAX_DEV_ADDR 0xFE
++#endif
++
++/*
++****************************************************
++* CryptoMemory Function Prototypes
++****************************************************
++*/
++/** \brief Initializes the CrytpoMemory
++ *
++ * Resets the crypto engines and parameters associated with them
++ * for each device in the cm_device_addresses table.
++ * This function should be called immediately after calling the low level
++ * function ll_PowerOn(). If the return value is not SUCCESS, use of
++ * the CryptoMemory device(s) may not continue.
++ * If system runs with CryptoMemory Companion chip then this cm_Init will
++ * initialize them in this init state.
++ *
++ * \return Returns SUCCESS if device_address is in cm_device_addresses,
++ * UNKNOWN_DEVICE otherwise.
++ *
++ * \remarks Example: if (cm_Init() != SUCCESS) return 0; \n
++ * Initializes all devices in the cm_device_addresses table.
++ */
++extern RETURN_CODE cm_Init (void);
++
++/** \brief Writes data into the (previously set) user zone
++ *
++ * This function is the main memory write function, and will automatically
++ * include encryption or anti-tearing (if enabled).
++ *
++ * \param ucDevAddr - Device address (a nibble) corresponding to the default
++ * value (0xb) or the device configuration register lower nibble.
++ * \param uiCryptoAddr - 2 byte address within the zone to write
++ * \param pucBuffer - pointer to the buffer with the write data
++ * \param ucCount - how many bytes to write
++ *
++ * \return Returns the results of ll_SendCommand() and ll_SendData().
++ *
++ * \remarks Example: ucReturn = cm_WriteUserZone(DEFAULT_ADDRESS, 0, ucData,
++ * 16);\n
++ * Writes 16 bytes from ucData at address 0 to device at DEFAULT_ADDRESS.\n
++ * Return SUCCESS or the result of ll_SendCommand() or
++ * ll_SendData().
++ */
++extern RETURN_CODE cm_WriteUserZone(uchar ucDevAddr, uint uiCryptoAddr, \
++ puchar pucBuffer, uchar ucCount);
++
++/** \brief Reads data from the (previously set) user zone
++ *
++ * This function is the main memory read function, and will automatically
++ * include encryption (if enabled).
++ *
++ * \param ucDevAddr - Device address (a nibble) corresponding to the default
++ * value (0xb) or the device configuration register lower nibble.
++ * \param uiCryptoAddr - 2 byte address within the zone to read
++ * \param pucBuffer - pointer to a buffer to receive data
++ * \param ucCount - the number of bytes to read
++ *
++ * \return Returns the results of ll_SendCommand() and ll_ReceiveData().
++ *
++ * \remarks Example: ucReturn = cm_ReadUserZone(DEFAULT_ADDRESS, 0, ucData, 16);\n
++ * Reads 16 bytes into ucData from address 0 in device at DEFAULT_ADDRESS.\n
++ * Return SUCCESS or the result of ll_SendCommand() or
++ * ll_ReceiveData().
++ */
++extern RETURN_CODE cm_ReadUserZone(uchar ucDevAddr, uint uiCryptoAddr, \
++ puchar pucBuffer, uchar ucCount);
++
++/** \brief Write data into the Configuration Memory
++ *
++ * The input parameters determine which device address to write, which
++ * starting address in the configuration memory to write to, how many
++ * bytes to write, where the data to write is, and whether to use
++ * the anti-tearing option.
++ *
++ * \param ucDevAddr- Device Address (a nibble) corresponding to the
++ * default value (0xb) or the device configuration register lower
++ * nibble.
++ * \param ucCryptoAddr - Configuration Memory address - see the Configuration
++ * Memory map for the specific CryptoMemory Device to determine the address
++ * of the appropriate parameter.
++ * \param pucBuffer - Pointer to buffer containing write data.
++ * \param ucCount - the number of bytes to write
++ * \param ucAntiTearing - antitearing flag. If TRUE, anti-tearing is
++ * enabled. Anti-tearing should not be used unless required, as it
++ * causes more write cycles than necessary.
++ *
++ * \return Return value of ll_SendCommand() or ll_SendData().
++ *
++ * \remarks
++ * Example: \n
++ * ucReturn = cm_WriteConfigZone(DEFAULT_ADDRESS, 0x0A, ucData, 2, FALSE);\n
++ * Writes 2 bytes from ucData at CryptoMemory address 0x0A to the CryptoMemory
++ * device at DEFAULT_ADDRESS (0xb).
++ * Anti-tearing is not enabled. \n
++ * Return SUCCESS or the result of ll_SendCommand() or
++ * ll_SendData().
++ *
++ */
++extern RETURN_CODE cm_WriteConfigZone(uchar ucDevAddr, uchar ucCryptoAddr, \
++ puchar pucBuffer, uchar ucCount, \
++ uchar ucAntiTearing);
++
++/** \brief Writes Fuse Byte to the specified device address
++ *
++ * Fuse values are (in bit order from 3 to 0):
++ * - SEC (blown by Atmel before shipment, locks Lot History Code)
++ * - FAB (locks Answer to Reset and Fab Code)
++ * - CMA (locks Card Manufacturer Code)
++ * - PER (locks the remaining portions of the System Zone)
++ *
++ * \param ucDevAddr - Device Address (a nibble) corresponding to the
++ * default value (0xb) or the device configuration register lower
++ * nibble.
++ * \param ucFuze - A byte holding the fuse data
++ * \return SUCCESS or ll_SendCommand() result.
++ *
++ * \remarks Example: ucReturn = WriteFuse(DEFAULT_ADDRESS, ucData);\n
++ * Writes fuse data in ucData to device at DEFAULT_ADDRESS.
++ * Return SUCCESS or the result of ll_SendCommand()
++ */
++extern RETURN_CODE cm_WriteFuse(uchar ucDevAddr, uchar ucFuze);
++
++/** \brief System Write to set the user zone for following commands
++ *
++ * When reading or writing the main EEPROM memory of the CryptoMemory device,
++ * the supplied address refers to an offset within a user zone (refer to
++ * the User Zone map for the specific CryptoMemory Device to determine the
++ * number of zones and zone size.) This function sets the user zone.
++ *
++ * \param ucDevAddr - Device address (a nibble) corresponding to the default
++ * value (0xb) or the device configuration register lower nibble.
++ * \param ucZoneNumber - user zone number to set
++ * \param ucAntiTearing - antitearing flag. If TRUE, anti-tearing is enabled.
++ * Anti-tearing should not be used unless required, as it causes more write
++ * cycles than necessary.
++ *
++ * \return Result of ll_SendCommand().
++ *
++ * \remarks Example: ucReturn = cm_SetUserZone(DEFAULT_ADDRESS, 3, FALSE);\n
++ * Sets the device at the default address (0xb) to user zone 3; anti-tearing
++ * is not enabled.
++ * Return SUCCESS or the result of ll_SendCommand()
++ */
++extern RETURN_CODE cm_SetUserZone(uchar ucDevAddr, uchar ucZoneNumber, \
++ uchar ucAntiTearing);
++
++/** \brief Read data from the Configuration Zone
++ *
++ * The input parameters determine which device address to read, which
++ * starting address in the configuration zone to read from, how many
++ * bytes to read, and where to place the returned data.
++ *
++ * \param ucDevAddr - Device Address (a nibble) corresponding to the
++ * default value (0xb) or the device configuration register lower
++ * nibble.
++ * \param ucCryptoAddr - Configuration Zone address - see the Configuration
++ * Zone map for the specific CryptoMemory Device to determine the address
++ * of the appropriate parameter.
++ * \param pucBuffer - Pointer to buffer to contain returned data,
++ * which must be large enough to hold ucCount bytes.
++ * \param ucCount - the number of bytes to read
++ * \return SUCCESS or the result of ll_SendCommand() or ll_ReceiveData()
++ *
++ * \remarks
++ * Example: ucReturn = cm_ReadConfigZone(DEFAULT_ADDRESS, 0x0A, ucData, 2);\n
++ * Reads 2 bytes at address 0x0A from the DEFAULT_ADDRESS (0xb) into ucData.\n
++ * Return SUCCESS or the result of ll_SendCommand() or
++ * ll_ReceiveData().
++ */
++extern RETURN_CODE cm_ReadConfigZone(uchar ucDevAddr, uchar ucCryptoAddr, \
++ puchar pucBuffer, uchar ucCount);
++
++/** \brief Read Fuse Byte from the device specified by ucDevAddr
++ *
++ * Fuse values are (in bit order from 3 to 0):
++ * - SEC (blown by Atmel before shipment, locks Lot History Code)
++ * - FAB (locks Answer to Reset and Fab Code)
++ * - CMA (locks Card Manufacturer Code)
++ * - PER (locks the remaining portions of the Configuration Zone)
++ *
++ * \param ucDevAddr - Device Address (a nibble) corresponding to the
++ * default value (0xb) or the device configuration register lower
++ * nibble.
++ * \param pucFuze - A pointer to a byte to hold the fuse data
++ * \return SUCCESS or ll_SendCommand() or ll_ReceiveData() result.
++ *
++ * \remarks Example: ucReturn = ReadFuse(DEFAULT_ADDRESS, ucData);\n
++ * Reads fuse data from device at DEFAULT_ADDRESS into
++ * ucData.
++ * Return SUCCESS or the result of ll_SendCommand() or
++ * ll_ReceiveData().
++ */
++extern RETURN_CODE cm_ReadFuse(uchar ucDevAddr, puchar pucFuze);
++
++/** \brief Read Checksum
++ *
++ * If the UCR bit in the Device Configuration Register is 1, the cryptographic
++ * engine will be reset. If UCR = 0, it will not be reset.\n
++ * This function provides a method to check on the synchronicity of the host
++ * and device cryptoengines without affecting the attempts counters.
++ *
++ * \param ucDevAddr - Device Address (a nibble) corresponding to the
++ * default value (0xb) or the device configuration register lower
++ * nibble.
++ * \param pucChkSum - pointer to 2 bytes to store calculated CheckSum
++ * \return SUCCESS or the results of ll_SendCommand() or ll_ReceiveData().
++ *
++ * \remarks Example: ucReturn = cm_ReadChecksum(DEFAULT_ADDRESS, ucData);\n
++ * Reads the checksum value into ucData for the device at
++ * DEFAULT_ADDRESS.
++ * Return SUCCESS or the result of ll_SendCommand() or or
++ * ll_ReceiveData().
++ */
++extern RETURN_CODE cm_ReadChecksum(uchar ucDevAddr, puchar pucChkSum);
++
++/** \brief Send checksum.
++ *
++ * If device is in authentication mode, any user zone write must be followed
++ * with a cm_SendChecksum command with the proper checksum. Otherwise the
++ * device will not complete the write. An invalid checksum will also clear
++ * authentication.
++ *
++ * \param ucDevAddr - Device Address (a nibble) corresponding to the
++ * default value (0xb) or the device configuration register lower
++ * nibble.
++ * \param pucChkSum - pointer to 2 byte array holding checksum.
++ * Always pass NULL so that function will calculate the appropriate checksum.
++ *
++ * \return Results of ll_SendCommand() or ll_SendData()
++ *
++ * \remarks Example: ucReturn = cm_SendChecksum(DEFAULT_ADDRESS, NULL);\n
++ * Sends the correct checksum to the device at the DEFAULT_ADDRESS.
++ * Return SUCCESS or the result of ll_SendCommand() or or
++ * ll_SendData().
++ */
++extern RETURN_CODE cm_SendChecksum(uchar ucDevAddr, puchar pucChkSum);
++
++/** \brief This routine activates Authentication and (optionally)
++ * Encryption modes.
++ *
++ * When called the function:
++ * - reads the current cryptogram (C<SUB>i</SUB>) of the specified key set,
++ * \if CMC_DOXY
++ * - computes the next cryptogram (C<SUP>A</SUP>) based on the secret
++ * KID pucKey (KID) and the random number (Q).
++ * \else
++ * - computes the next cryptogram (C<SUP>A</SUP>) based on the secret
++ * seed pucKey (G) and the random number (Q).
++ * \endif
++ * - sends the (CH<SUP>A</SUP>) (crypto challenge) and the random number to the
++ * CryptoMemory device,
++ * - Reads the chip's newly calculated cryptogram (C<SUB>i</SUB><SUP>A</SUP>)
++ * and compares it with C<SUP>A</SUP>.
++ *
++ * If C<SUP>A</SUP> matches C<SUB>i</SUB><SUP>A</SUP> then
++ * authentication is successful AND:
++ * - both host (function) and device save the new Cryptogram and
++ * calculate new Session Keys.
++ *
++ * In addition, if ucEncrypt is TRUE the function, using the new Session Key
++ * and a new random number
++ * - computes a new challenge (CH<SUP>E</SUP>), a new cryptogram
++ * (C<SUP>E</SUP>) and a new Session Key (S<SUP>E</SUP>),
++ * - sends the challenge (CH<SUP>E</SUP>) and random number (Q) to the
++ * CryptoMemory device,
++ * - reads the device's newly calculated cryptogram (C<SUB>i</SUB><SUP>E</SUP>)
++ * and compares it with C<SUP>E</SUP>.
++ *
++ * If the two match then encryption is activated.
++ *
++ * \param ucDevAddr - Device Address (a nibble) corresponding to the
++ * default value (0xb) or the device configuration register lower
++ * nibble.
++ * \if CMC_DOXY
++ * \param ucKeySet - index number of the current key set to be used for
++ * authentication / encryption. Upper nible is contained F index and lower
++ * is contained G index.
++ * \param pucBuff1 - pointer to 16 bytes Secret KID.
++ * \param pucBuff2 - pointer to 8 bytes uniqui serial or
++ * identification number of CM.
++ * \else
++ * \param ucKeySet - index number of the current key set to be used for
++ * authentication / encryption. Upper nible is ignored and
++ * lower is contained G index.
++ * \param pucBuff1 - pointer to the Secret Seed (G) associated
++ * with this key set.
++ * \param pucBuff2 - random number. If NULL, the function will
++ * calculate new random numbers for both actions.)
++ * \endif
++ * \param ucEncrypt - if TRUE command the device to enter encryption mode also
++ * (with the same key set).
++ *
++ * \return SUCCESS or the results of ll_SendCommand(), ll_ReceiveData()
++ * or ll_SendData() result.
++ *
++ * \remarks Example: \n
++ * ucReturn = cm_VerifyCrypto(DEFAULT_ADDRESS, 1, ucData, NULL, TRUE);\n
++ * Enter authentication mode with key set 1, secret seed in ucData,
++ * calculate a random number for the user, and enter the encryption mode.\n
++ * Return SUCCESS or the result of ll_SendCommand() or
++ * ll_SendData() or ll_ReceiveData().
++ */
++extern RETURN_CODE cm_VerifyCrypto(uchar ucDevAddr, uchar ucKeySet, \
++ puchar pucBuff1, puchar pucBuff2, \
++ uchar ucEncrypt);
++
++/** \brief This routine reset active password
++ *
++ * When called the function:
++ * - sends the Verify Password Command with the second byte set to 0xFF.
++ *
++ * \param ucDevAddr - Device Address (a nibble) corresponding to the
++ * default value (0xb) or the device configuration register lower
++ * nibble.
++ *
++ * \return SUCCESS or the results of ll_SendCommand() or ll_SendData().
++ *
++ * \remarks Example: \n
++ * ucReturn = cm_ResetPassword(DEFAULT_ADDRESS);\n
++ * Reset active password for device at address
++ * DEFAULT_ADDRESS.
++ * Return SUCCESS or the result of ll_SendCommand() or or
++ * ll_SendData().
++ */
++extern RETURN_CODE cm_ResetPassword(uchar ucDevAddr);
++
++/** \brief This routine reset authentication and encryption
++ * and resets the cryptoengine.
++ *
++ * When called the function:
++ * - sends the Verify Crypto Command with no arguments and
++ * - Resets the CryptoEngine in firmware.
++ *
++ * \param ucDevAddr - Device Address (a nibble) corresponding to the
++ * default value (0xb) or the device configuration register lower
++ * nibble.
++ *
++ * \return SUCCESS or the results of ll_SendCommand() or ll_SendData().
++ *
++ * \remarks Example: \n
++ * ucReturn = cm_ResetCrypto(DEFAULT_ADDRESS);\n
++ * Leave authentication and encryption mode for device at address
++ * DEFAULT_ADDRESS.
++ * Return SUCCESS or the result of ll_SendCommand() or or
++ * ll_SendData().
++ */
++extern RETURN_CODE cm_ResetCrypto(uchar ucDevAddr);
++
++/** \brief Verifies Password.
++ *
++ * Using the verify password command, send either the "write" or "read"
++ * password to the appropriate address. Then read the password location
++ * in the config zone and see if the password attempts counter = 0xff
++ * (passed).\n
++ * If Authentication mode is active, then this function encrypts passwords
++ * automatically.
++ *
++ * \param ucDevAddr - Device Address (a nibble) corresponding to the
++ * default value (0xb) or the device configuration register lower
++ * nibble.
++ * \if CMC_DOXY
++ * \param pucPassword - pointer to password to verify and only valid if authentication
++ * is not required.
++ * \param ucSet - index number of the password set
++ * system with Companion devie: bit 0-3: CM password index
++ * bit 4-7: companion pwd index.
++ * \else
++ * \param pucPassword - pointer to password to verify.
++ * \param ucSet - index number of the password set
++ * system without Companion device, bit 0-3: CM password index
++ * bit 4-7 are ignore.
++ * system with Companion devie: bit 0-3: CM password index
++ * bit 4-7: companion pwd index.
++ * \endif
++ * \param ucRW - whether it's the read or write password. Read = 1, Write = 0.
++ *
++ * \return SUCCESS or the results of ll_SendCommand() or ll_SendData() or
++ * ll_ReceiveData()
++ *
++ * \remarks
++ * Example: ucReturn = cm_VerifyPassword(DEFAULT_ADDRESS, ucData, 7, 0);\n
++ * Verify the write password number 7 at the DEFAULT_ADDRESS.\n
++ * Return SUCCESS or the result of ll_SendCommand() or
++ * ll_SendData() or ll_ReceiveData().
++ */
++extern RETURN_CODE cm_VerifyPassword(uchar ucDevAddr, puchar pucPassword, \
++ uchar ucSet, uchar ucRW);
++
++#ifdef CMC
++/*
++****************************************************
++* CryptoMemory Companion (CMC) Function Prototypes
++****************************************************
++*/
++
++/**\if CMC_DOXY
++ * \brief Verifies System Digest
++ *
++ * If Mode bit 0 = 0, simply verifies that *pucDigest matches FlashDigest.
++ * If Mode bit 0 = 1, verifies that SHA-1(Digest, FlashDigest) = *pucSignature.
++ *
++ * \param ucCmcDevAddr - CMC device address
++ * \param pucExtDigest - pointer to 20 bytes of external Digest
++ * \param pucIntDigest - pointer to 20 bytes of internal EEPROM Flash Digest.
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++extern RETURN_CODE cmc_VerifyFlash(uchar ucCmcDevAddr, puchar pucExtDigest, \
++ puchar pucIntDigest);
++
++/** \if CMC_DOXY
++ * \brief Start Challenge
++ *
++ * This API will use to verify the mutually authenticate between system processor and
++ * compnaion device. If either CMC or System secret seeds is not the same as in EEPROM,
++ * then CMC will return FAIL. If both secret seeds are the same as in EEPROM, CMC will
++ * return SUCCESS.
++ *
++ * \param ucCmcDevAddr - CMC device address
++ * \param pucCmcChallenge - pointer to 20 bytes of CMC Challenge
++ * \param pucCmcSeed - pointer to 16 bytes of CMC secret seed. This CMC secret seed bytes
++ * must be the same as CMCSeed in EEPROM
++ * \param pucSystemSeed - pointer to 16 bytes of System secret seed. This System secret
++ * seed bytes must be the same as SystemSeed in EEPROM.
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++extern RETURN_CODE cmc_StartChallenge(uchar ucCmcDevAddr, puchar pucCmcChallenge, \
++ puchar pucCmcSeed, puchar pucSystemSeed);
++
++/** \if CMC_DOXY
++ * \brief Gets a 20 byte random number from the Companion Chip
++ *
++ * \param ucCmcDevAddr - CMC device address
++ * \param pucData - pointer to returned 20 byte random number.
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++extern RETURN_CODE cmc_GetRandom(uchar ucCmcDevAddr, puchar pucData) ;
++
++/** \if CMC_DOXY
++ * \brief Increments the value of the specified counter by 1
++ *
++ * \param ucCmcDevAddr - CMC device address
++ * \param ucSelector - Counter to increment (0 - 3).
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++extern RETURN_CODE cmc_IncrementCounter(uchar ucCmcDevAddr, uchar ucSelector) ;
++
++/** \if CMC_DOXY
++ * \brief Returns the least 32 bits of the specified counter.
++ *
++ * \param ucCmcDevAddr - CMC device address
++ * \param ucSelector - Counter to read (0 - 3).
++ * \param pucData - pointer to least significant 4 bytes of counter data.
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++extern RETURN_CODE cmc_ReadCounter(uchar ucCmcDevAddr, uchar ucSelector, \
++ puchar pucData) ;
++
++/** \if CMC_DOXY
++ * \brief Writes the contents of the specified address.
++ *
++ * Writes up to the end of the read/write memory space.
++ * After locking, only the read/write space can be written.
++ * Up to 16 bytes may be written with a single operation
++ *
++ * \param ucCmcDevAddr - CMC device address
++ * \param uiAddress - Address of first byte to write. 7 most sig. bits ignored.
++ * \param ucCount - Write ucCount bytes to EEPROM (data
++ * follows).
++ * \param pucData - pointer to clear text data to write.
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++extern RETURN_CODE cmc_WriteMemory(uchar ucCmcDevAddr, uint uiAddress, \
++ uchar ucCount, puchar pucData) ;
++
++/** \if CMC_DOXY
++ * \brief Authorize to writes a single byte in the first 16
++ * bytes of the ReadOnly section at the specified address.
++ *
++ * Address must point to one of the first 16 bytes within the ReadOnly
++ * section of memory. This command only works if Mode:Bit2 = 1.
++ * Only one byte may be written with a each operation
++ *
++ * \param ucCmcDevAddr - CMC ddevice address
++ * \param uiAddress - Address of byte to write. 7 most sig. bits ignored.
++ * \param ucData - clear text data to write.
++ * \param pucF0 - pointer to buffer that contained 8 bytes
++ * of F0
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++extern RETURN_CODE cmc_WriteMemoryAuthorized(uchar ucCmcDevAddr, uint uiAddress, \
++ uchar ucData, puchar pucF0) ;
++
++/** \if CMC_DOXY
++ * \brief Writes 16 byte page of EEPROM with encryption.
++ *
++ * Writes 16 byte pages up to the end of the read/write memory space.
++ * Uses the SHA-1 of (Address || EncKey || Nonce).
++ * Smaller blocks than 16 bytes cannot be written with this command.
++ * Cannot be executed after Companion Chip is locked.
++ *
++ * \param ucCmcDevAddr - CMC ddevice address
++ * \param uiAddress - Address of the 16 byte page to write. 7 most significant
++ * and 4 least significant bits ignored.
++ * \param pucData - pointer to 16 bytes of clear data to write.
++ * \param pucNonce - Random value encryption seed.
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++extern RETURN_CODE cmc_WriteMemoryEncrypted(uchar ucCmcDevAddr, uint uiAddress, \
++ puchar pucData, puchar pucNonce) ;
++
++/** \if CMC_DOXY
++ * \brief Read the contents of the specified address.
++ *
++ * Reads up to the end of the read/write memory space.
++ * After locking, only the read only and the read/write space can be read.
++ * Up to 16 bytes may be read with a single operation
++ *
++ * \param ucCmcDevAddr - CMC ddevice address
++ * \param uiAddress - Address of first byte to read. 7 most sig. bits ignored.
++ * \param ucCount - Read ucCount+1 bytes from EEPROM.
++ * \param pucData - pointer to clear text data read from Companion Chip.
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++extern RETURN_CODE cmc_ReadMemory(uchar ucCmcDevAddr, uint uiAddress, \
++ uchar ucCount, puchar pucData) ;
++
++/** \if CMC_DOXY
++ * \brief Read the specified 32 byte block and computes the
++ * SHA-1 digest.
++ *
++ * Provides a mechanism of verifying that the personalization of the chip
++ * completed correctly before locked.
++ * Note that verifying the digest of 0 requires knowing EncKey.
++ * Cannot be executed after Companion Chip is locked.
++ *
++ * \param ucCmcDevAddr - CMC ddevice address
++ * \param uiAddress - Address of the 32 byte page to read. 7 most significant
++ * and 5 least significant bits ignored.
++ * \param pucData - pointer to 20 byte digest
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++extern RETURN_CODE cmc_ReadMemoryDigest(uchar ucCmcDevAddr, uint uiAddress, \
++ puchar pucData) ;
++
++/** \if CMC_DOXY
++ * \brief Read the contents of the Manufacturing ID and Lock
++ * Byte.
++ *
++ * \param ucCmcDevAddr - CMC ddevice address
++ *
++ * \param pucData - pointer to 16 byte Manufacturing ID and Lock Byte.
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++extern RETURN_CODE cmc_ReadManufID(uchar ucCmcDevAddr, puchar pucData) ;
++
++/** \if CMC_DOXY
++ * \brief Lock the current memory values.
++ *
++ * \param ucCmcDevAddr - CMC ddevice address.
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++extern RETURN_CODE cmc_Lock(uchar ucCmcDevAddr) ;
++
++/** \if CMC_DOXY
++ * \brief Returns the status byte from a CMC device.
++ *
++ * \param ucCmcDevAddr - CMC ddevice address
++ *
++ * \return uchar - status from a CMC device
++ * \endif
++*/
++extern uchar cmc_Status(uchar ucCmcDevAddr) ;
++
++#endif /* CMC */
++
++/**
++ * \brief Send command bytes to a device.
++ *
++ * This routine is external reference by library
++ *
++ * \param pucInsBuf - pointer to buffer of command bytes to
++ * send.
++ * \param ucLen - number of command bytes to send.
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ */
++extern RETURN_CODE ll_SendCommand(puchar pucInsBuf, uchar ucLen);
++
++/** \if CMC_DOXY
++ * \brief Receive data bytes from a CMC device.
++ *
++ * This routine is external reference by library.
++ *
++ * \param pucRecBuf - pointer to buffer of receving data bytes
++ * \param ucLen - number of data bytes to receive
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++#ifdef CMC
++extern RETURN_CODE ll_CmcReceiveData(puchar pucRecBuf, uchar ucLen);
++#endif
++
++/** \brief Receive data bytes from a CM device.
++ *
++ * This routine is external reference by library.
++ *
++ * \param pucRecBuf - pointer to buffer of receving data bytes
++ * \param ucLen - number of data bytes to receive
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ */
++extern RETURN_CODE ll_ReceiveData(puchar pucRecBuf, uchar ucLen);
++
++/** \brief Send data bytes to a device.
++ *
++ * This routine is external reference by library.
++ *
++ * \param pucSendBuf - pointer to buffer of data bytes to send
++ * \param ucLen - number of data bytes to send
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ */
++extern RETURN_CODE ll_SendData(puchar pucSendBuf, uchar ucLen);
++
++/**
++ * \brief Wait for number of clock ticks
++ * This routine is external reference by library.
++ *
++ * \param ucLoop - number of (Start + 15 clocks + Stop) to loop
++ */
++extern void ll_WaitClock(uchar ucLoop);
++
++/**
++ * \brief Copy number of bytes from source to destination
++ * locations.
++ *
++ * This routine is external reference by library.
++ *
++ * \param pucDestMem - destination buffer
++ * \param pucSrcMem - source buffer
++ * \param uiCnt - number of bytes to copy
++ */
++extern void lib_memcpy(puchar pucDestMem, puchar pucSrcMem, uint uiCnt);
++
++/**
++ * \brief Compare two strings.
++ *
++ * This routine is external reference by library.
++ *
++ * \param pucMem1 - string 1 buffer
++ * \param pucMem2 - string 2 buffer
++ * \param uiCnt - number of bytes to compare
++ */
++extern uchar lib_memcmp(puchar pucMem1, puchar pucMem2, uint uiCnt);
++
++/**
++ * \brief Allocate memory from memory pool.
++ *
++ * This routine is external reference by library.
++ *
++ * \param ucBytes - number of bytes to allocate
++ *
++ * \return puchar - pointer to allocated buffer
++ *
++ */
++extern puchar lib_malloc(uchar ucBytes);
++
++/** \brief Deallocate memory back to memory pool.
++ *
++ * This routine is external reference by library.
++ *
++ * \param pucBuff - pointer to deallocated buffer
++ */
++extern void lib_free(puchar pucBuff);
++
++/** \brief Get random byte.
++ *
++ * This routine is external reference by library.
++ *
++ * \return uchar - random byte
++ */
++extern uchar lib_rand(void);
++
++/** \brief Get CM device address based from device index.
++ *
++ * This routine is external reference by library.
++ *
++ * \param ucIndex - CM device index
++ *
++ * \return uchar - CM device address
++ */
++extern uchar getCMDevAddr(uchar ucIndex);
++
++/** \brief Get CM device index based from device address.
++ *
++ * This routine is external reference by library.
++ *
++ * \param ucCmDevAddr - CM device address
++ *
++ * \return uchar - CM device index
++ */
++extern uchar cm_FindDeviceIndex(uchar ucCmDevAddr);
++
++/** \brief Get CM device type based from device index.
++ *
++ * This routine is external reference by library.
++ *
++ * \param ucIndex - CM device index
++ *
++ * \return CM_DEVICE_TYPE - CM device type
++ */
++extern CM_DEVICE_TYPE getCMDevType(uchar ucIndex);
++
++/** \brief Get number CM device.
++ *
++ * This routine is external reference by library.
++ *
++ * \return uchar - number of CM devices
++ */
++extern uchar getNumCmDev(void);
++
++
++/** \brief Get library version number.
++ *
++ * \return puchar - pointer to string of characters
++ */
++extern puchar getLibVersNum(void);
++
++#ifdef CMC
++
++/** \if CMC_DOXY
++ * \brief Wait for BUSY bit from CMC status to CLEAR.
++ *
++ * This routine is external reference by library.
++ *
++ * \param ucCmcDevAddr - CMC device address
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++extern uchar WaitForNotBusy(uchar ucCmcDevAddr);
++
++/** \if CMC_DOXY
++ * \brief Wait for DATA bit from CMC status to SET.
++ *
++ * This routine is external reference by library.
++ *
++ * \param ucCmcDevAddr - CMC device address
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ * \endif
++ */
++extern uchar WaitForData(uchar ucCmcDevAddr);
++
++/** \brief Wait for STARTUPDONE bit from CMC status to SET.
++ *
++ * This routine is external reference by library.
++ *
++ * \param ucCmcDevAddr - CMC device address
++ *
++ * \return SUCCESS or the result of cmc_Status()
++ */
++extern uchar WaitForStartupDone(uchar ucCmcDevAddr);
++
++/** \if CMC_DOXY
++ * \brief Get CMC device index based from device address.
++ *
++ * This routine is external reference by library.
++ *
++ * \param ucCmcDevAddr - CMC device address
++ *
++ * \return uchar - CMC device index
++ * \endif
++ */
++extern uchar cmc_FindDeviceIndex(uchar ucCmcDevAddr);
++
++/** \if CMC_DOXY
++ * \brief Get CMC device address based from device index.
++ *
++ * This routine is external reference by library.
++ *
++ * \param ucIndex - CMC device index
++ *
++ * \return uchar - CMC Cdevice address
++ * \endif
++ */
++extern uchar getCMCDevAddr(uchar ucIndex);
++
++
++/** \if CMC_DOXY
++ * \brief Reset CMC device.
++ *
++ * This routine is external reference by library.
++ * \endif
++ */
++extern void cmc_Reset(void);
++
++/** \if CMC_DOXY
++ * \brief SHA-1 processing
++ *
++ * \param pucChallenge - First input to SHA-1 algorithm
++ * \param ucLen - Length of pucChallenge
++ * \param pucResponse - Output from SHA-1 algorithm
++ * \endif
++ */
++extern void cmc_SHA1(puchar pucInData, uchar ucLen, puchar pucOutData);
++#endif
++
++#endif
++
+diff --git a/drivers/misc/smartqv_encrypt/smartqv_encrypt.c b/drivers/misc/smartqv_encrypt/smartqv_encrypt.c
+new file mode 100644
+index 0000000..7e2a582
+--- /dev/null
++++ b/drivers/misc/smartqv_encrypt/smartqv_encrypt.c
+@@ -0,0 +1,116 @@
++/****************************************************************
++ * $ID: smartqv_encrypt.c Sun, 22 Mar 2009 15:48:25 +0800 root $ *
++ * *
++ * Description: *
++ * *
++ * Maintainer: (Meihui Fan) <mhfan@hhcn.com> *
++ * *
++ * Copyright (C) 2009 HHTech *
++ * www.hhcn.com, www.hhcn.org *
++ * All rights reserved. *
++ * *
++ * This file is free software; *
++ * you are free to modify and/or redistribute it *
++ * under the terms of the GNU General Public Licence (GPL). *
++ * *
++ * Last modified: 二, 29 9月 2009 16:34:00 +0800 by root #
++ ****************************************************************/
++#include <linux/module.h>
++#include <linux/miscdevice.h>
++#include <linux/slab.h>
++#include <linux/smp_lock.h>
++#include <linux/ioport.h>
++#include <linux/capability.h>
++#include <linux/fcntl.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/device.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <hhtech_gpio.h>
++#include <mach/gpio.h>
++
++typedef enum {
++ SCL_HIGH,
++ SCL_LOW,
++ SDA_HIGH,
++ SDA_LOW,
++ SDA_DATA
++} I2C_CMD;
++
++#define GPIO_SCL TCC_GPD11
++#define GPIO_SDA TCC_GPD12
++
++/*
++ * The smartqv_encrypt device is one of the misc char devices.
++ * This is its minor number.
++ */
++#define SMARTQV_ENCRYPT_DEV_MINOR 234
++
++static int smartqv_encrypt_open(struct inode * inode, struct file * filp)
++{
++ return 0;
++}
++
++static int smartqv_encrypt_release(struct inode *inode, struct file *file)
++{
++ return 0;
++}
++
++static int smartqv_encrypt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ int ret = 0;
++ switch (cmd) {
++ case SCL_HIGH:
++ gpio_direction_output(GPIO_SCL, 1);
++ break;
++ case SCL_LOW:
++ gpio_direction_output(GPIO_SCL, 0);
++ break;
++ case SDA_HIGH:
++ gpio_direction_input(GPIO_SDA); // important!
++ break;
++ case SDA_LOW:
++ gpio_direction_output(GPIO_SDA, 0);
++ break;
++ case SDA_DATA:
++ gpio_direction_input(GPIO_SDA);
++ ret = gpio_get_value(GPIO_SDA);
++ break;
++ }
++ return ret;
++}
++
++static const struct file_operations smartqv_encrypt_fops = {
++ .ioctl = smartqv_encrypt_ioctl,
++ .open = smartqv_encrypt_open,
++ .release = smartqv_encrypt_release,
++};
++
++static struct miscdevice smartqv_encrypt_device = {
++ .minor = SMARTQV_ENCRYPT_DEV_MINOR,
++ .name = "smartqv_encrypt",
++ .fops = &smartqv_encrypt_fops
++};
++
++static int __init smartqv_encrypt_init(void)
++{
++ return misc_register(&smartqv_encrypt_device);
++}
++
++static void __exit smartqv_encrypt_exit(void)
++{
++ misc_deregister(&smartqv_encrypt_device);
++}
++
++module_init(smartqv_encrypt_init);
++module_exit(smartqv_encrypt_exit);
++
++MODULE_AUTHOR("Guoqiang Wang");
++MODULE_DESCRIPTION("Encypt module for SmartQV");
++MODULE_LICENSE("GPL");
++
++
++/**************** End Of File: smartqv_encrypt.c ****************/
++// vim:sts=4:ts=8:
+diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
+index 956bd76..4bcaf5c 100644
+--- a/drivers/mmc/core/sdio_cis.c
++++ b/drivers/mmc/core/sdio_cis.c
+@@ -220,7 +220,9 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
+ break;
+
+ /* 0xff means we're done */
+- if (tpl_code == 0xff)
++ //if (tpl_code == 0xff)
++ /* Realtek 8123 */
++ if (tpl_code == 0xff || tpl_code==0x00)
+ break;
+
+ ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link);
+diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
+index dfa585f..b10bc07 100644
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -192,3 +192,23 @@ config MMC_TMIO
+ help
+ This provides support for the SD/MMC cell found in TC6393XB,
+ T7L66XB and also ipaq ASIC3
++
++config MMC_TCC_SDHC
++ bool "Telechips SD/MMC Host Controller Driver"
++ help
++ This selects the Telechips Multimedia card Interface.
++ If you have an TCC board with a Multimedia Card slot,
++ say Y here.
++
++config MMC_TCC_SDHC_CORE0
++ bool "Enabling a TCC SDHC Core 0"
++ depends on MMC_TCC_SDHC
++ help
++ This selects the TCC SDHC Core 0.
++
++config MMC_TCC_SDHC_CORE1
++ bool "Enabling a TCC SDHC Core 1"
++ depends on MMC_TCC_SDHC
++ help
++ This selects the TCC SDHC Core 1.
++
+diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
+index c794cc5..d0ea63e 100644
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -22,4 +22,5 @@ obj-$(CONFIG_MMC_SPI) += mmc_spi.o
+ obj-$(CONFIG_MMC_S3C) += s3cmci.o
+ obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
+ obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
++obj-$(CONFIG_MMC_TCC_SDHC) += tcc_sdhc.o
+
+diff --git a/drivers/mmc/host/tcc_sdhc.c b/drivers/mmc/host/tcc_sdhc.c
+new file mode 100644
+index 0000000..8485eb4
+--- /dev/null
++++ b/drivers/mmc/host/tcc_sdhc.c
+@@ -0,0 +1,1298 @@
++/*
++ * linux/drivers/mmc/host/tcc_sdhc.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: June 10, 2008
++ * Description: SD/MMC Host Driver for Telechips Boards.
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/dma-mapping.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/timer.h>
++#include <linux/mmc/host.h>
++#include <linux/mmc/mmc.h>
++#include <linux/mmc/sdio.h>
++#include <linux/mmc/card.h>
++#include <linux/clk.h>
++
++#include <linux/pci.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/scatterlist.h>
++#include <asm/mach-types.h>
++
++#include <linux/tcc_ll.h>
++#include <linux/tcc_pwm.h>
++
++#include <bsp.h>
++#include <mach/hardware.h>
++#include <mach/irqs.h>
++#include <mach/tca_ckc.h>
++#include <mach/tcc_pca953x.h>
++
++#include <mach/gpio.h>
++#include <hhtech_gpio.h>
++
++#include "tcc_sdhc.h"
++
++/*
++ * Controller registers
++ */
++#define TCCSDHC_DMA_ADDRESS 0x00
++#define TCCSDHC_BLOCK_SIZE 0x04
++
++#define TCCSDHC_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
++
++#define TCCSDHC_BLOCK_COUNT 0x06
++#define TCCSDHC_ARGUMENT 0x08
++//#define TCCSDHC_TRANSFER_MODE 0x0C
++//#define TCCSDHC_COMMAND 0x0E
++#define TCCSDHC_TMODE_COM 0x0C
++
++#define TCCSDHC_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff))
++
++#define TCCSDHC_RESPONSE10 0x10
++#define TCCSDHC_RESPONSE32 0x14
++#define TCCSDHC_RESPONSE54 0x18
++#define TCCSDHC_RESPONSE76 0x1c
++#define TCCSDHC_BUFFER 0x20
++#define TCCSDHC_PRESENT_STATE 0x24
++#define TCCSDHC_HOST_CONTROL 0x28
++//#define TCCSDHC_POWER_CONTROL 0x29
++//#define TCCSDHC_BLOCK_GAP_CONTROL 0x2A
++//#define TCCSDHC_WAKE_UP_CONTROL 0x2B
++#define TCCSDHC_CLOCK_CONTROL 0x2C
++#define TCCSDHC_TIMEOUT_CONTROL 0x2E
++//#define TCCSDHC_SOFTWARE_RESET 0x2F
++#define TCCSDHC_INT_STATUS 0x30
++#define TCCSDHC_INT_ENABLE 0x34
++#define TCCSDHC_SIGNAL_ENABLE 0x38
++#define TCCSDHC_ACMD12_ERR 0x3C
++
++#undef DEBUG
++//#define DEBUG
++#ifdef DEBUG
++#define SD_DEBUG(x...) printk(x)
++#define SD_ERROR(x...) printk(x)
++#else
++#define SD_DEBUG(x...)
++#define SD_ERROR(x...)
++#endif
++
++#define DRIVER_NAME "tcc-sdhc"
++#define DRIVER_NAME_CORE0 "tcc-sdhc0"
++#define DRIVER_NAME_CORE1 "tcc-sdhc1"
++#define DETECT_TIMEOUT (HZ/2)
++#define SDMMC_FIFO_CNT 1024
++#define SDMMC_TIMEOUT_TICKS (1000*HZ/1000) /* 1000ms */
++
++volatile PSDCHCTRL_T pSDCHCTRL = (volatile PSDCHCTRL_T)SDCHCTRL_BASE;
++volatile PSDHOST_T pSDMMC_SLOT0 = (volatile PSDHOST_T)SDCORE0SLOT0_BASE;
++volatile PSDHOST_T pSDMMC_SLOT1 = (volatile PSDHOST_T)SDCORE1SLOT2_BASE;
++
++
++struct tcc_mmc_host {
++ int initialized;
++ int suspended;
++ struct mmc_request *mrq;
++ struct mmc_command *cmd;
++ struct mmc_data *data;
++ int data_early:1; /* Data finished before cmd */
++
++ struct mmc_host *mmc;
++ struct device *dev;
++ unsigned char id; /* 16xx chips have 2 MMC blocks */
++ unsigned long peri_clk;
++ struct clk *iclk;
++ struct clk *fclk;
++ struct resource *res;
++ void __iomem *base;
++ u32 iobase;
++ int irq;
++ unsigned char bus_mode;
++ unsigned char hw_bus_mode;
++
++ char slot_desc[16]; /* Name for reservations */
++
++ unsigned int sg_len;
++ int sg_idx;
++ u16 *buffer;
++ u32 buffer_bytes_left;
++ u32 total_bytes_left;
++
++ struct scatterlist *cur_sg; /* We're working on this */
++ int num_sg; /* Entries left */
++ int offset; /* Offset into current sg */
++ int remain; /* Bytes left in current */
++
++ short wp_pin;
++
++ short card_inserted; /* to mark the card is inserted or not */
++
++ struct tasklet_struct finish_tasklet;
++
++ spinlock_t lock; /* Mutex */
++
++ int flags; /* Host attributes */
++#define TCC_MMC_USE_DMA (1<<0) /* Host is DMA capable */
++#define TCC_MMC_REQ_USE_DMA (1<<1) /* Use DMA for this req. */
++
++ struct timer_list detect_timer;
++ struct timer_list timer;
++};
++
++static bool bChanged = 0;
++static stpwrinfo pwrinfo = {PWR_STATUS_ON};
++
++static void tcc_mmc_start_command(struct tcc_mmc_host *host, struct mmc_command *cmd);
++static void tcc_mmc_tasklet_finish(unsigned long param);
++static void init_mmc_host(struct tcc_mmc_host *host);
++static void deinit_mmc_host(struct tcc_mmc_host *host);
++
++static int tcc_sw_reset(struct tcc_mmc_host *host, uint8_t rst_bits)
++{
++ int timeout = 100;
++
++ tcc_writew(rst_bits<<8 | tcc_readw(host->iobase+TCCSDHC_TIMEOUT_CONTROL), host->iobase+TCCSDHC_TIMEOUT_CONTROL);
++
++ while (--timeout) {
++ if (!(tcc_readw(host->iobase+TCCSDHC_TIMEOUT_CONTROL)& rst_bits<<8)){
++ break;
++ }
++ /* Must be mdelay not msleep, as called from interrupt context */
++ mdelay(1);
++ }
++ if (!timeout) {
++ SD_DEBUG("timed out waiting for reset\n");
++ return -ETIMEDOUT;
++ }
++
++ return 0;
++}
++
++int tcc_mmc_card_inserted(struct tcc_mmc_host *host)
++{
++ int ret = -1;
++ if(host->id == 0) {
++ ret = gpio_get_value(GPIO_SD_DETE) ? 0 : 1;
++ } else if(host->id == 1) {
++ ret = 1; /* Wifi always on */
++ }
++ return ret;
++}
++
++/*
++ * Card insert/remove timer handler
++ */
++static void tcc_mmc_poll_event(unsigned long data)
++{
++ struct tcc_mmc_host *host = (struct tcc_mmc_host *) data;
++
++ if (!tcc_mmc_card_inserted(host)) {
++ /* card removed */
++ if (host->card_inserted == 1) {
++ host->card_inserted = 0;
++ bChanged = 1;
++ SD_DEBUG("SD card removed\n");
++ }
++ } else if (host->card_inserted == 0) {
++ host->card_inserted = 1;
++ bChanged = 1;
++ SD_DEBUG("SD card inserted");
++ }
++
++ if (host && bChanged) {
++ mmc_detect_change(host->mmc, msecs_to_jiffies(500));
++ bChanged = 0;
++ }
++
++ mod_timer(&host->detect_timer, jiffies + DETECT_TIMEOUT);
++}
++
++static void tcc_mmc_clock_onoff(struct tcc_mmc_host *host, unsigned char onoff)
++{
++ u16 temp_val;
++
++ if (onoff == 1) {
++ BITSET(HwIOBUSCFG->HCLKEN0, HwIOBUSCFG_SD);
++
++ temp_val = tcc_readw(host->iobase+TCCSDHC_CLOCK_CONTROL);
++ tcc_writew(temp_val|HwSDCLKSEL_SCK_EN, host->iobase+TCCSDHC_CLOCK_CONTROL);
++ } else if (onoff == 0) {
++ temp_val = tcc_readw(host->iobase+TCCSDHC_CLOCK_CONTROL);
++ tcc_writew(temp_val&~HwSDCLKSEL_SCK_EN, host->iobase+TCCSDHC_CLOCK_CONTROL);
++
++ //FIXME: need to be revised for power saving. currently bus clock is always running.
++ if ((pSDMMC_SLOT0->CLK & HwSDCLKSEL_SCK_EN) == 0 &&(pSDMMC_SLOT1->CLK & HwSDCLKSEL_SCK_EN) == 0) {
++ //HwBCLKCTR &= ~HwBCLKCTR_SD_ON;
++ }
++ }
++}
++
++static void tcc_mmc_finish_data(struct tcc_mmc_host *host)
++{
++ struct mmc_data *data;
++ u16 blocks;
++
++ BUG_ON(!host->data);
++
++ data = host->data;
++ host->data = NULL;
++
++ if (host->flags & TCC_MMC_REQ_USE_DMA) {
++ pci_unmap_sg(NULL, data->sg, data->sg_len,
++ (data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
++ }
++
++ /*
++ * Controller doesn't count down when in single block mode.
++ */
++ if (data->blocks == 1) {
++ blocks = (data->error == 0) ? 0 : 1;
++ } else {
++ blocks = tcc_readw(host->iobase+TCCSDHC_BLOCK_COUNT);
++ }
++ data->bytes_xfered = data->blksz * (data->blocks - blocks);
++
++ if (!data->error && blocks) {
++ printk(KERN_ERR "%s: Controller signalled completion even "
++ "though there were blocks left.\n",
++ mmc_hostname(host->mmc));
++ data->error = -EIO;
++ }
++#if 0 //It must be enabled. When It doesn't sends STOP command
++ if (data->stop) {
++ /*
++ * The controller needs a reset of internal state machines
++ * upon error conditions.
++ */
++ if (data->error) {
++ tcc_sw_reset(host, HwSD_SRESET_RSTCMD);
++ tcc_sw_reset(host, HwSD_SRESET_RSTDAT);
++ }
++ tcc_mmc_start_command(host, data->stop);
++ } else {
++ tasklet_schedule(&host->finish_tasklet);
++ }
++#endif
++ tasklet_schedule(&host->finish_tasklet);
++}
++
++//FIXME: Not yet implemented...
++static void tcc_transfer_pio(struct tcc_mmc_host *host)
++{
++ BUG_ON(!host->data);
++ printk("\nenter %s ", __func__);
++}
++
++static void tcc_mmc_start_command(struct tcc_mmc_host *host, struct mmc_command *cmd)
++{
++ u32 resptype;
++ u32 cmdtype;
++ u32 mask;
++ unsigned long timeout;
++ int cmd_reg = 0x00000000;
++ unsigned int uiIntStatusEn;
++
++ /* Wait max 10 ms */
++ timeout = 10;
++
++ cmdtype = 0;
++
++ mask = HwSD_STATE_NOCMD;
++ if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY)) {
++ mask |= HwSD_STATE_NODAT;
++ }
++
++ /* We shouldn't wait for data inihibit for stop commands, even
++ though they might use busy signaling */
++ if (host->mrq->data && (cmd == host->mrq->data->stop)) {
++ mask &= ~HwSD_STATE_NODAT;
++ }
++
++ while (tcc_readl(host->iobase+TCCSDHC_PRESENT_STATE) & mask) {
++ if (timeout == 0) {
++ printk(KERN_ERR "%s: Controller never released "
++ "inhibit bit(s).\n", mmc_hostname(host->mmc));
++ cmd->error = -EIO;
++ tasklet_schedule(&host->finish_tasklet);
++ return;
++ }
++ timeout--;
++ mdelay(1);
++ }
++
++ mod_timer(&host->timer, jiffies + 2 * HZ);
++
++ host->cmd = cmd;
++
++ switch (mmc_resp_type(cmd)) {
++ case MMC_RSP_NONE:
++ resptype = 0;
++ break;
++ case MMC_RSP_R1:
++ resptype = 2;
++ break;
++ case MMC_RSP_R1B:
++ resptype = 3;
++ break;
++ case MMC_RSP_R2:
++ resptype = 1;
++ break;
++ default:
++ resptype = 2;
++ break;
++ }
++
++ uiIntStatusEn = tcc_readl(host->iobase+TCCSDHC_INT_ENABLE);
++
++ uiIntStatusEn |= HwSDINT_EN_TDONE | HwSDINT_EN_CDONE;
++
++ if (cmd->data) {
++ host->data = cmd->data;
++ host->data_early = 0;
++
++ cmd_reg |= HwSD_COM_TRANS_DATSEL | HwSD_COM_TRANS_DIR;
++
++ if (cmd->data->blocks > 1) {
++ cmd_reg |= HwSD_COM_TRANS_MS | HwSD_COM_TRANS_BCNTEN;
++ if(cmd->opcode !=SD_IO_RW_EXTENDED) {
++ cmd_reg |= HwSD_COM_TRANS_ACMD12; // It is related STOP command
++ }
++ }
++
++ if (cmd->data->flags & MMC_DATA_WRITE)
++ cmd_reg &= ~HwSD_COM_TRANS_DIR;
++
++ if (host->flags & TCC_MMC_USE_DMA)
++ host->flags |= TCC_MMC_REQ_USE_DMA;
++
++ if (host->flags & TCC_MMC_REQ_USE_DMA)
++ cmd_reg |= HwSD_COM_TRANS_DMAEN;
++
++ if (host->flags & TCC_MMC_REQ_USE_DMA) {
++ int count;
++ count = pci_map_sg(NULL, cmd->data->sg, cmd->data->sg_len,
++ (cmd->data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
++ BUG_ON(count != 1);
++
++ tcc_writel(sg_dma_address(cmd->data->sg), host->iobase+TCCSDHC_DMA_ADDRESS);
++
++ } else {
++ host->cur_sg = cmd->data->sg;
++ host->num_sg = cmd->data->sg_len;
++ host->offset = 0;
++ host->remain = host->cur_sg->length;
++ }
++ }
++
++ if (((cmd->opcode==SD_IO_RW_DIRECT)&& ((cmd->arg & (0x03<<28)) ==0)
++ && ((cmd->arg&(0x1ff<<9)) ==(SDIO_CCCR_ABORT<<9)) &&(cmd->arg&0x07))
++ || (cmd->opcode==MMC_STOP_TRANSMISSION)) {
++ /* Use R5b For CMD52, Function 0, I/O Abort
++ * Need to be revised for handling CMD12
++ */
++ cmdtype = HwSD_COM_TRANS_ABORT;
++ }
++
++ if (cmd->flags & MMC_RSP_CRC)
++ cmd_reg |= HwSD_COM_TRANS_CRCHK;
++
++ if (cmd->flags & MMC_RSP_OPCODE)
++ cmd_reg |= HwSD_COM_TRANS_CICHK;
++
++ cmd_reg |= (cmd->opcode << 24) |cmdtype| (resptype << 16);
++
++ tcc_mmc_clock_onoff(host, 1);
++
++ if (tcc_readl(host->iobase+TCCSDHC_INT_STATUS) & HwSDINT_STATUS_ERR) {
++ tcc_writew(tcc_readw(host->iobase+TCCSDHC_TIMEOUT_CONTROL)|(HwSD_SRESET_RSTCMD<<8), host->iobase+TCCSDHC_TIMEOUT_CONTROL);
++ while (tcc_readw(host->iobase+TCCSDHC_TIMEOUT_CONTROL) & HwSD_SRESET_RSTCMD<<8);
++ msleep(1);
++ }
++
++ tcc_writel(tcc_readl(host->iobase+TCCSDHC_INT_STATUS),host->iobase+TCCSDHC_INT_STATUS);
++
++ if (cmd->data) {
++ tcc_writew((0x07<<12) | cmd->data->blksz, host->iobase+TCCSDHC_BLOCK_SIZE);
++ tcc_writew(cmd->data->blocks , host->iobase+TCCSDHC_BLOCK_COUNT);
++ } else {
++ tcc_writel(0, host->iobase+TCCSDHC_DMA_ADDRESS);
++ tcc_writew(0, host->iobase+TCCSDHC_BLOCK_SIZE);
++ tcc_writew(0, host->iobase+TCCSDHC_BLOCK_COUNT);
++ }
++
++ tcc_writel(cmd->arg, host->iobase+TCCSDHC_ARGUMENT);
++
++ /* Enable transfer interrupt sources */
++ tcc_writel(uiIntStatusEn, host->iobase+TCCSDHC_INT_ENABLE);
++ tcc_writel(cmd_reg, host->iobase +TCCSDHC_TMODE_COM);
++
++ SD_DEBUG("%s: opcode=%d, arg=%x\n", __func__, cmd->opcode, cmd->arg);
++ //SD_DEBUG("data:%x,blksz:%d,blk:%d,flags:%x\n\n", data, data->blksz, data->blocks, data->flags);
++}
++
++static void tcc_mmc_finish_command(struct tcc_mmc_host *host)
++{
++ BUG_ON(host->cmd == NULL);
++
++ if (host->cmd->flags & MMC_RSP_PRESENT) {
++ if (host->cmd->flags & MMC_RSP_136) {
++ host->cmd->resp[0] = tcc_readl(host->iobase+TCCSDHC_RESPONSE76);
++ host->cmd->resp[1] = tcc_readl(host->iobase+TCCSDHC_RESPONSE54);
++ host->cmd->resp[2] = tcc_readl(host->iobase+TCCSDHC_RESPONSE32);
++ host->cmd->resp[3] = tcc_readl(host->iobase+TCCSDHC_RESPONSE10);
++
++ SD_DEBUG("%s: R2: resp[0]=0x%08x, resp[1]=0x%08x, resp[2]=0x%08x, resp[3]=0x%08x\n",
++ __func__, host->cmd->resp[0], host->cmd->resp[1], host->cmd->resp[2], host->cmd->resp[3]);
++
++ host->cmd->resp[0] = (host->cmd->resp[0] << 8) | ((host->cmd->resp[1] & 0xFF000000) >> 24);
++ host->cmd->resp[1] = (host->cmd->resp[1] << 8) | ((host->cmd->resp[2] & 0xFF000000) >> 24);
++ host->cmd->resp[2] = (host->cmd->resp[2] << 8) | ((host->cmd->resp[3] & 0xFF000000) >> 24);
++ host->cmd->resp[3] <<= 8;
++
++ } else {
++ host->cmd->resp[0] = tcc_readl(host->iobase+TCCSDHC_RESPONSE10);
++
++ SD_DEBUG("%s: R1: resp[0]=0x%08x\n", __func__, host->cmd->resp[0]);
++ }
++ }
++
++ host->cmd->error = 0;
++
++ if (host->data && host->data_early)
++ tcc_mmc_finish_data(host);
++
++ if (!host->cmd->data)
++ tasklet_schedule(&host->finish_tasklet);
++
++ host->cmd = NULL;
++}
++
++static void tcc_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
++{
++ struct tcc_mmc_host *host = mmc_priv(mmc);
++ unsigned long flags;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ BUG_ON(host->mrq != NULL);
++
++ host->mrq = mrq;
++
++ if(!host->card_inserted) {
++ host->mrq->cmd->error = -ENOMEDIUM;
++ tasklet_schedule(&host->finish_tasklet);
++ } else {
++ tcc_mmc_start_command(host, mrq->cmd);
++ }
++
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++/* High speed mode threshold (Hz).
++ *
++ * Although high speed mode should be suitable for all speeds not all
++ * controller/card combinations are capable of meeting the higher
++ * tolerances for (e.g.) clock rise/fall times. Therefore, default
++ * mode is used where possible for improved compatibility. */
++
++#define SDIO_CLOCK_FREQ_HIGH_SPD 25000000
++
++static void tcc_hw_set_high_speed(struct mmc_host *mmc, int hs)
++{
++ struct tcc_mmc_host *host = mmc_priv(mmc);
++ u8 host_ctrl = 0;
++
++ host_ctrl= tcc_readw(host->iobase+TCCSDHC_HOST_CONTROL);
++ host_ctrl &= ~HwSD_POWER_HS;
++
++ if (hs) {
++ host_ctrl |= HwSD_POWER_HS;
++ }
++
++ tcc_writew(host_ctrl, host->iobase+TCCSDHC_HOST_CONTROL);
++}
++
++static void tcc_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++ unsigned long flags;
++ unsigned uBCLKCTR;
++ struct tcc_mmc_host *host = mmc_priv(mmc);
++ uint32_t temp_reg;
++
++ long dwMaxClockRate = host->peri_clk;
++ int i = 0; /* 2^i is the divisor value */
++ u32 clk_div=0;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ uBCLKCTR = HwIOBUSCFG->HCLKEN0;
++ HwIOBUSCFG->HCLKEN0 |= HwIOBUSCFG_SD;
++
++ if (ios->clock != 0) {
++ tcc_hw_set_high_speed(mmc, ios->clock >SDIO_CLOCK_FREQ_HIGH_SPD);
++ /* shift MaxClockRate until we find the closest frequency <= target */
++ while ((ios->clock < dwMaxClockRate) && (i < 8)) {
++ dwMaxClockRate = dwMaxClockRate >> 1;
++ i++;
++ }
++
++ if (i != 0) {
++ //printk("\nclock value = %d\n", i);
++ clk_div = 1<<(i-1);
++ temp_reg = tcc_readl(host->iobase+TCCSDHC_CLOCK_CONTROL);
++ tcc_writew(temp_reg & ~HwSDCLKSEL_SCK_EN, host->iobase+TCCSDHC_CLOCK_CONTROL);
++
++ udelay(10);
++
++ tcc_writew((clk_div << 8)|HwSDCLKSEL_INCLK_EN, host->iobase+TCCSDHC_CLOCK_CONTROL);
++
++ while ((tcc_readl(host->iobase+TCCSDHC_CLOCK_CONTROL) & HwSDCLKSEL_INCLK_STABLE) == 0);
++ temp_reg = tcc_readl(host->iobase+TCCSDHC_CLOCK_CONTROL);
++ tcc_writew(temp_reg|(HwSDCLKSEL_SCK_EN|HwSDCLKSEL_INCLK_EN), host->iobase+TCCSDHC_CLOCK_CONTROL);
++ }
++ }
++
++ switch (ios->power_mode) {
++ case MMC_POWER_OFF:
++ //printk("-----------------------MMC_POWER_OFF\n");
++ deinit_mmc_host(host);
++ break;
++ case MMC_POWER_UP:
++ //printk("-----------------------MMC_POWER_UP\n");
++ init_mmc_host(host);
++ break;
++ case MMC_POWER_ON:
++ //printk("-----------------------MMC_POWER_ON\n");
++ break;
++ }
++
++ switch (ios->bus_width) {
++ case MMC_BUS_WIDTH_1:
++ //printk("\n/***********1 bit mode***************/ \n");
++ if (host->id == 0) {
++ pSDMMC_SLOT0->CONTL &= ~(HwSD_POWER_SD4 | HwSD_POWER_SD8);
++ pSDMMC_SLOT0->CONTL |= HwSD_POWER_VOL33;
++
++ pSDMMC_SLOT0->CONTH &=~Hw19;
++ } else if (host->id == 1) {
++ pSDMMC_SLOT1->CONTL &= ~(HwSD_POWER_SD4 | HwSD_POWER_SD8);
++ pSDMMC_SLOT1->CONTL |= HwSD_POWER_VOL33;
++
++ pSDMMC_SLOT1->CONTH &=~Hw19;
++ }
++ break;
++ case MMC_BUS_WIDTH_4:
++ //printk("\n/***********4 bit mode***************/\n ");
++ if (host->id == 0) {
++ pSDMMC_SLOT0->CONTL &= ~HwSD_POWER_SD8;
++ pSDMMC_SLOT0->CONTL |= ((HwSD_POWER_VOL33) | HwSD_POWER_SD4);
++ pSDMMC_SLOT0->CONTH |=Hw19;
++ } else if (host->id == 1) {
++ pSDMMC_SLOT1->CONTL &= ~HwSD_POWER_SD8;
++ pSDMMC_SLOT1->CONTL |= ((HwSD_POWER_VOL33) | HwSD_POWER_SD4);
++ pSDMMC_SLOT1->CONTH |=Hw19;
++ }
++ break;
++ }
++
++ host->bus_mode = ios->bus_mode;
++
++ //need to add resetting a controller?
++
++ HwIOBUSCFG->HCLKEN0 = uBCLKCTR;
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static int tcc_mmc_get_ro(struct mmc_host *mmc)
++{
++ struct tcc_mmc_host *host = mmc_priv(mmc);
++ unsigned long flags;
++ uint32_t reg=0;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ reg = tcc_readl(host->iobase + TCCSDHC_PRESENT_STATE);
++
++ spin_unlock_irqrestore(&host->lock, flags);
++
++ return !(reg & HwSD_STATE_SDWP);
++}
++
++static void tcc_sdio_hw_enable_int(struct mmc_host *mmc, uint32_t sigs)
++{
++ struct tcc_mmc_host *host = mmc_priv(mmc);
++ unsigned long flags;
++ uint32_t stat_en;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ stat_en=tcc_readl(host->iobase+TCCSDHC_INT_ENABLE);
++ tcc_writel( stat_en | sigs, host->iobase+TCCSDHC_INT_ENABLE);
++
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static void tcc_sdio_hw_disable_int(struct mmc_host *mmc, uint32_t sigs)
++{
++ struct tcc_mmc_host *host = mmc_priv(mmc);
++ unsigned long flags;
++ uint32_t stat_en;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ stat_en=tcc_readl(host->iobase+TCCSDHC_INT_ENABLE);
++ tcc_writel(stat_en & ~sigs, host->iobase+TCCSDHC_INT_ENABLE);
++
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static void tcc_sdio_enable_card_int(struct mmc_host *mmc)
++{
++ tcc_sdio_hw_enable_int(mmc, HwSDINT_EN_CDINT);
++}
++
++static void tcc_sdio_disable_card_int(struct mmc_host *mmc)
++{
++ tcc_sdio_hw_disable_int(mmc, HwSDINT_EN_CDINT);
++}
++
++/*
++ * Interrupt handling
++ */
++static void tcc_mmc_cmd_irq(struct tcc_mmc_host *host, u32 intmask)
++{
++ BUG_ON(intmask == 0);
++
++ if (!host->cmd) {
++ printk(KERN_ERR "%s: Got command interrupt 0x%08x even "
++ "though no command operation was in progress.\n",
++ mmc_hostname(host->mmc), (unsigned)intmask);
++ return;
++ }
++
++ if (intmask & HwSDINT_STATUS_CMDTIME) {
++ host->cmd->error = -ETIMEDOUT;
++ } else if (intmask & (HwSDINT_STATUS_CMDCRC | HwSDINT_STATUS_CMDEND | HwSDINT_STATUS_CINDEX)) {
++ host->cmd->error = -EILSEQ;
++ }
++
++ if (host->cmd->error) {
++ tasklet_schedule(&host->finish_tasklet);
++ } else if (intmask & HwSDINT_STATUS_CDONE) {
++ tcc_mmc_finish_command(host);
++ }
++}
++
++static void tcc_mmc_data_irq(struct tcc_mmc_host *host, u32 intmask)
++{
++ BUG_ON(intmask == 0);
++
++ if (!host->data) {
++ /*
++ * A data end interrupt is sent together with the response
++ * for the stop command.
++ */
++ if (intmask & HwSDINT_STATUS_TDONE)
++ return;
++
++ printk(KERN_ERR "%s: Got data interrupt 0x%08x even "
++ "though no data operation was in progress.\n",
++ mmc_hostname(host->mmc), (unsigned)intmask);
++ return;
++ }
++
++ if (intmask & HwSDINT_STATUS_DATTIME) {
++ host->data->error = -ETIMEDOUT;
++ } else if (intmask & (HwSDINT_STATUS_DATCRC | HwSDINT_STATUS_DATEND)) {
++ host->data->error = -EILSEQ;
++ }
++
++ if (host->data->error) {
++ tcc_mmc_finish_data(host);
++ } else {
++ if (intmask & (HwSDINT_STATUS_RDRDY | HwSDINT_STATUS_WRRDY)) {
++ printk(" \n %x \n ", intmask);
++ tcc_transfer_pio(host);
++ }
++
++ /*
++ * We currently don't do anything fancy with DMA
++ * boundaries, but as we can't disable the feature
++ * we need to at least restart the transfer.
++ */
++ if (intmask & HwSDINT_STATUS_DMA){
++ tcc_writel(tcc_readl(host->iobase+TCCSDHC_DMA_ADDRESS), host->iobase+TCCSDHC_DMA_ADDRESS);
++ }
++
++ if (intmask & HwSDINT_STATUS_TDONE) {
++ if (host->cmd) {
++ /*
++ * Data managed to finish before the
++ * command completed. Make sure we do
++ * things in the proper order.
++ */
++ host->data_early = 1;
++ } else {
++ tcc_mmc_finish_data(host);
++ }
++ }
++ }
++}
++
++static irqreturn_t tcc_mmc_interrupt_handler(int irq, void *dev_id)
++{
++ unsigned int IntStatus;
++ irqreturn_t result;
++ int cardint = 0;
++ struct tcc_mmc_host *host = (struct tcc_mmc_host *) dev_id;
++
++ spin_lock(&host->lock);
++
++ IntStatus = tcc_readl(host->iobase+TCCSDHC_INT_STATUS);
++
++ if (IntStatus == 0) {
++ result=IRQ_NONE;
++ }
++
++ if (IntStatus & HwSDINT_CMD_MASK) {
++ tcc_writel(IntStatus & HwSDINT_CMD_MASK,host->iobase+TCCSDHC_INT_STATUS);
++ tcc_mmc_cmd_irq(host, IntStatus & HwSDINT_CMD_MASK);
++ }
++
++ if (IntStatus & HwSDINT_DATA_MASK) {
++ tcc_writel(IntStatus & HwSDINT_DATA_MASK,host->iobase+TCCSDHC_INT_STATUS);
++ tcc_mmc_data_irq(host, IntStatus & HwSDINT_DATA_MASK);
++ }
++
++ IntStatus &= ~(HwSDINT_CMD_MASK |HwSDINT_DATA_MASK);
++ IntStatus &= ~HwSDINT_STATUS_ERR;
++
++ if(IntStatus & HwSDINT_STATUS_CDINT) {
++ cardint =1;
++ }
++
++ IntStatus &= ~ HwSDINT_STATUS_CDINT;
++
++ if (IntStatus) {
++ SD_DEBUG(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n", mmc_hostname(host->mmc), IntStatus);
++ tcc_writel(IntStatus, host->iobase+TCCSDHC_INT_STATUS);
++ }
++
++ result=IRQ_HANDLED;
++
++ mmiowb();
++
++//out:
++ spin_unlock(&host->lock);
++
++ if (host->id == 1) {
++ unsigned int tcc_stat = tcc_readl(host->iobase+TCCSDHC_INT_ENABLE);
++ udelay(30); //XXX: SDIO lost response when WIFI in deepsleep
++ }
++
++
++ if (cardint) {
++ mmc_signal_sdio_irq(host->mmc);
++ }
++
++ return result;
++}
++
++static void tcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
++{
++ if (enable) {
++ tcc_sdio_enable_card_int(mmc);
++ } else {
++ tcc_sdio_disable_card_int(mmc);
++ }
++}
++
++static struct mmc_host_ops tcc_mmc_ops = {
++ .request = tcc_mmc_request,
++ .set_ios = tcc_mmc_set_ios,
++ .get_ro = tcc_mmc_get_ro,
++ .enable_sdio_irq = tcc_enable_sdio_irq,
++};
++
++/*
++ * Tasklets
++ */
++static void tcc_mmc_tasklet_finish(unsigned long param)
++{
++ struct tcc_mmc_host *host;
++ unsigned long flags;
++ struct mmc_request *mrq;
++
++ host = (struct tcc_mmc_host *)param;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ del_timer(&host->timer);
++
++ mrq = host->mrq;
++
++ /*
++ * The controller needs a reset of internal state machines
++ * upon error conditions.
++ */
++ if (mrq->cmd->error ||
++ (mrq->data && (mrq->data->error ||
++ (mrq->data->stop && mrq->data->stop->error)))) {
++
++ /* Spec says we should do both at the same time, but Ricoh
++ controllers do not like that. */
++ tcc_sw_reset(host, HwSD_SRESET_RSTCMD);
++ tcc_sw_reset(host, HwSD_SRESET_RSTDAT);
++ }
++
++ host->mrq = NULL;
++ host->cmd = NULL;
++ host->data = NULL;
++
++ mmiowb();
++
++ spin_unlock_irqrestore(&host->lock, flags);
++ mmc_request_done(host->mmc, mrq);
++}
++
++static void tcc_mmc_timeout_timer(unsigned long data)
++{
++ struct tcc_mmc_host *host;
++ unsigned long flags;
++
++ host = (struct tcc_mmc_host*)data;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ if (host->mrq) {
++ printk(KERN_ERR "%s: Timeout waiting for hardware "
++ "interrupt.\n", mmc_hostname(host->mmc));
++
++ if (host->data) {
++ host->data->error = -ETIMEDOUT;
++ tcc_mmc_finish_data(host);
++ } else {
++ if (host->cmd)
++ host->cmd->error = -ETIMEDOUT;
++ else
++ host->mrq->cmd->error = -ETIMEDOUT;
++
++ tasklet_schedule(&host->finish_tasklet);
++ }
++ }
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static void init_mmc_host(struct tcc_mmc_host *host)
++{
++ if (host->id == 0) {
++ /* power */
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, SD0_ON, OUTPUT, ON, SET_DIRECTION|SET_VALUE);
++
++ /* iobus */
++ tca_ckc_set_iobus_swreset(RB_SDMMCCONTROLLER, ON);
++ tca_ckc_setiobus(RB_SDMMCCONTROLLER, ENABLE);
++
++ /* clock */
++ tca_ckc_setperi(PERI_SDMMC0, ENABLE, 480000, PCDIRECTPLL3);
++ host->peri_clk = tca_ckc_getperi(PERI_SDMMC0) * 100;
++ SD_DEBUG("tcc-sdhc%d: clock %lu\n", host->id, host->peri_clk);
++
++ /* slot0 port2 */
++ BITCSET(pSDCHCTRL->SDPORTCTRL, HwSD_PORTCTRL_SLOT0_MASK, HwSD_PORTCTRL_SLOT0(2));
++ pSDMMC_SLOT0->STSEN = 0x03ff00ff;
++ pSDMMC_SLOT0->INTEN = 0x03ff01ff;
++
++ BITCSET(pSDMMC_SLOT0->TIME, 0x00FF, 0x0E);
++
++ BITCSET(HwGPIOE->GPFN1, Hw32-Hw16, Hw29|Hw25|Hw21|Hw17); /* GPIOE[15:12] - SD0_D[0:3] */
++ BITCSET(HwGPIOE->GPFN2, Hw24-Hw16, Hw21|Hw17); /* GPIOE[21:20] - SD0_CMD, SD0_CLK */
++ BITCSET(HwGPIOE->GPCD0, 0xFF000000, 0x55000000); /* driver strength */
++ BITCSET(HwGPIOE->GPCD1, 0x00000F00, 0x00000500);
++
++ /* GPIOF[13] - SD CD */
++ gpio_direction_input(GPIO_SD_DETE);
++
++ pSDMMC_SLOT0->CONTL &= ~(HwSD_POWER_SD4 | HwSD_POWER_SD8);
++ pSDMMC_SLOT0->CONTL |= HwSD_POWER_POW;
++
++ } else if (host->id == 1) {
++ /* power */
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, SD1_ON, OUTPUT, ON, SET_DIRECTION|SET_VALUE);
++
++ /* iobus */
++ tca_ckc_set_iobus_swreset(RB_SDMMCCONTROLLER, ON);
++ tca_ckc_setiobus(RB_SDMMCCONTROLLER, ENABLE);
++
++ /* clock */
++ tca_ckc_setperi(PERI_SDMMC1, ENABLE, 480000, PCDIRECTPLL3);
++ host->peri_clk = tca_ckc_getperi(PERI_SDMMC1) * 100;
++ SD_DEBUG("tcc-sdhc%d: clock %lu\n", host->id, host->peri_clk);
++
++ /* slot2 port5 */
++ BITCSET(pSDCHCTRL->SDPORTCTRL, HwSD_PORTCTRL_SLOT2_MASK, HwSD_PORTCTRL_SLOT2(5));
++ pSDMMC_SLOT1->STSEN = 0x03ff00ff;
++ pSDMMC_SLOT1->INTEN = 0x03ff01ff;
++
++ BITCSET(pSDMMC_SLOT1->TIME, 0x00FF, 0x0E);
++
++ BITCSET(HwGPIOB->GPFN0, Hw16-Hw0, HwPORTCFG_GPFN3(2)|HwPORTCFG_GPFN2(2)
++ | HwPORTCFG_GPFN1(2)|HwPORTCFG_GPFN0(2)); /* GPIOB[3:0] - SD1_D[0:3] */
++ BITCSET(HwGPIOB->GPFN1, Hw24-Hw16, HwPORTCFG_GPFN5(2)|HwPORTCFG_GPFN4(2)); /* GPIOB[13:12] - SD1_CMD, SD1_CLK*/
++ BITCSET(HwGPIOB->GPCD0, 0x0F0000FF, 0x3F0000FF); /* driver strength */
++
++ pSDMMC_SLOT1->CONTL &= ~(HwSD_POWER_SD4 | HwSD_POWER_SD8);
++ pSDMMC_SLOT1->CONTL |= HwSD_POWER_POW;
++ }
++}
++
++static void deinit_mmc_host(struct tcc_mmc_host *host)
++{
++ if (host->id == 0) {
++ /* clock */
++ tca_ckc_setperi(PERI_SDMMC0, DISABLE, 480000, PCDIRECTPLL3);
++
++ /* power */
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, SD0_ON, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++
++ /* slot0 port2 - GPIO mode */
++ BITCLR(HwGPIOE->GPFN1, Hw32-Hw16); /* GPIOE[15:12] */
++ BITCLR(HwGPIOE->GPFN2, Hw24-Hw16); /* GPIOE[21:20] */
++ /* output mode */
++ BITSET(HwGPIOE->GPEN, Hw21|Hw20|Hw15|Hw14|Hw13|Hw12);
++
++ /* SD Bus Power */
++ BITCLR(pSDMMC_SLOT0->CONTL, HwSD_POWER_POW);
++ } else if (host->id == 1) {
++ /* clock */
++ tca_ckc_setperi(PERI_SDMMC1, DISABLE, 480000, PCDIRECTPLL3);
++
++ /* power */
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, SD1_ON, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++
++ /* slot2 port5 - GPIO mode */
++ BITCLR(HwGPIOB->GPFN0, Hw16-Hw0);
++ BITCLR(HwGPIOB->GPFN1, Hw24-Hw16);
++ BITSET(HwGPIOB->GPEN, Hw13|Hw12|Hw3|Hw2|Hw1|Hw0);
++
++ /* SD Bus Power */
++ BITCLR(pSDMMC_SLOT1->CONTL, HwSD_POWER_POW);
++ }
++}
++
++/*
++ * SDHC Power on/off control
++ */
++static int sdhc_pwr_ctl(void *h_private, int cmd, void *p_out)
++{
++ struct platform_device *pdev = (struct platform_device *)h_private;
++ struct tcc_mmc_host *host = platform_get_drvdata(pdev);
++
++ switch (cmd) {
++ case PWR_CMD_OFF:
++ //printk("PWR_CMD_OFF command ==> [%d]\n", cmd);
++ if (pwrinfo.status == PWR_STATUS_OFF) {
++ return 0;
++ }
++ pwrinfo.status = PWR_STATUS_OFF;
++ if (host) {
++ if (mmc_suspend_host(host->mmc, PMSG_SUSPEND) == 0) {
++ host->suspended = 1;
++ } else {
++ return -EIO;
++ }
++ }
++ break;
++ case PWR_CMD_ON:
++ //printk("PWR_CMD_ON command ==> [%d]\n", cmd);
++ if (pwrinfo.status == PWR_STATUS_ON) {
++ return 0;
++ }
++ pwrinfo.status = PWR_STATUS_ON;
++ if (host) {
++ if (mmc_resume_host(host->mmc) == 0) {
++ host->suspended = 0;
++ } else {
++ return -EIO;
++ }
++ }
++ break;
++ case PWR_CMD_GETSTATUS:
++ //printk("PWR_CMD_GETSTATUS command ==> [%d], status:[%d]\n", cmd, pwrinfo.status);
++ memcpy(p_out, &pwrinfo, sizeof(stpwrinfo));
++ break;
++ default:
++ //printk("unknown pwr command !!! ==> [%d]\n", cmd);
++ return -EINVAL;
++ break;
++ }
++
++ return 0;
++}
++
++static int __init tcc_mmc_probe(struct platform_device *pdev)
++{
++ struct mmc_host *mmc;
++ struct tcc_mmc_host *host = NULL;
++ volatile PPIC pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++ int ret = 0;
++
++ mmc = mmc_alloc_host(sizeof(struct tcc_mmc_host), &pdev->dev);
++ if (!mmc)
++ return -ENOMEM;
++
++ host = mmc_priv(mmc);
++ host->mmc = mmc;
++ host->id = pdev->id;
++
++ init_mmc_host(host);
++
++ host->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ host->irq = platform_get_irq(pdev, 0);
++ host->iobase = host->res->start;
++ host->flags = TCC_MMC_USE_DMA;
++
++ mmc->caps |= MMC_CAP_SDIO_IRQ|MMC_CAP_4_BIT_DATA;
++ mmc->ops = &tcc_mmc_ops;
++ mmc->f_min = 100000;
++ mmc->f_max = 48000000;
++ mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
++
++ /*
++ * Maximum number of segments. Hardware cannot do scatter lists.
++ */
++ if (host->flags & TCC_MMC_USE_DMA) {
++ mmc->max_hw_segs = 1;
++ } else {
++ mmc->max_hw_segs = 16;
++ }
++ mmc->max_phys_segs = 16;
++
++ /*
++ * Maximum number of sectors in one transfer. Limited by DMA boundary
++ * size (512KiB).
++ */
++ mmc->max_req_size = 524288;
++
++ /*
++ * Maximum segment size. Could be one segment with the maximum number
++ * of bytes.
++ */
++ mmc->max_seg_size = mmc->max_req_size;
++
++ /*
++ * Maximum block size. This varies from controller to controller and
++ * is specified in the capabilities register.
++ */
++ // mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
++ // if (mmc->max_blk_size >= 3) {
++ // printk(KERN_WARNING "%s: Invalid maximum block size, assuming 512\n",
++ // host->slot_descr);
++ mmc->max_blk_size = 512;
++ // } else
++ // mmc->max_blk_size = 512 << mmc->max_blk_size;
++
++ /*
++ * Maximum block count.
++ */
++ mmc->max_blk_count = 65535;
++
++ host->dev = &pdev->dev;
++ platform_set_drvdata(pdev, host);
++
++ /* configuration the SD card insertion detection */
++ init_timer(&host->detect_timer);
++ host->detect_timer.function = tcc_mmc_poll_event;
++ host->detect_timer.data = (unsigned long) host;
++ host->detect_timer.expires = jiffies + DETECT_TIMEOUT;
++
++ mmc_add_host(mmc);
++
++ spin_lock_init(&host->lock);
++
++ add_timer(&host->detect_timer);
++
++ /*
++ * Init tasklets.
++ */
++ tasklet_init(&host->finish_tasklet,tcc_mmc_tasklet_finish, (unsigned long)host);
++
++ setup_timer(&host->timer, tcc_mmc_timeout_timer, (unsigned long)host);
++
++ pPIC->SEL1 |= HwINT1_SD0 << host->id;
++ pPIC->INTMSK1 |= HwINT1_SD0 << host->id;
++ pPIC->MODE1 |= HwINT1_SD0 << host->id; // Level trigger
++
++ snprintf(host->slot_desc, 16, "tcc-sdhc%d", host->id);
++ ret = request_irq(host->irq, tcc_mmc_interrupt_handler, IRQF_SHARED, host->slot_desc, host);
++ if (ret)
++ goto error;
++
++ /* initialize the card-insert status */
++ if (tcc_mmc_card_inserted(host)) {
++ host->card_inserted = 1;
++ } else {
++ host->card_inserted = 0;
++ }
++
++ /* add power control functions */
++ insert_pwm_node(DEVICE_SDHC, sdhc_pwr_ctl, pdev);
++
++ printk("%s%d: init\n", DRIVER_NAME, host->id);
++ return ret;
++
++error:
++ printk("%s%d: failed\n", DRIVER_NAME, host->id);
++ return ret;
++}
++
++static int tcc_mmc_remove(struct platform_device *pdev)
++{
++ struct mmc_host *mmc = platform_get_drvdata(pdev);
++
++ platform_set_drvdata(pdev, NULL);
++
++ if (mmc) {
++ struct tcc_mmc_host *host = mmc_priv(mmc);
++
++ mmc_remove_host(mmc);
++ tcc_sw_reset(host, HwSD_SRESET_RSTALL);
++ free_irq(host->irq, host);
++ del_timer_sync(&host->detect_timer);
++ del_timer_sync(&host->timer);
++ tasklet_kill(&host->finish_tasklet);
++ mmc_free_host(mmc);
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int tcc_mmc_suspend(struct platform_device *pdev, pm_message_t mesg)
++{
++ int ret = 0;
++
++ struct tcc_mmc_host *host = platform_get_drvdata(pdev);
++
++ if (host && host->suspended)
++ return 0;
++
++ if (host) {
++ ret = mmc_suspend_host(host->mmc, mesg);
++ if (ret == 0)
++ host->suspended = 1;
++ }
++
++ return ret;
++}
++
++static int tcc_mmc_resume(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ struct tcc_mmc_host *host = platform_get_drvdata(pdev);
++
++ if (host && !host->suspended)
++ return 0;
++
++ if (host) {
++ ret = mmc_resume_host(host->mmc);
++ if (ret == 0)
++ host->suspended = 0;
++ }
++
++ return ret;
++}
++#else
++#define tcc_mmc_suspend NULL
++#define tcc_mmc_resume NULL
++#endif
++
++
++#if defined(CONFIG_MMC_TCC_SDHC_CORE0)
++static struct platform_driver tcc_mmc_core0_driver = {
++ .probe = tcc_mmc_probe,
++ .remove = tcc_mmc_remove,
++ .suspend = tcc_mmc_suspend,
++ .resume = tcc_mmc_resume,
++ .driver = {
++ .name = DRIVER_NAME_CORE0,
++ },
++};
++#endif
++#if defined(CONFIG_MMC_TCC_SDHC_CORE1)
++static struct platform_driver tcc_mmc_core1_driver = {
++ .probe = tcc_mmc_probe,
++ .remove = tcc_mmc_remove,
++ .suspend = tcc_mmc_suspend,
++ .resume = tcc_mmc_resume,
++ .driver = {
++ .name = DRIVER_NAME_CORE1,
++ },
++};
++#endif
++
++static int __init tcc_mmc_init(void)
++{
++ int ret = -1;
++#if defined(CONFIG_MMC_TCC_SDHC_CORE0)
++ ret = platform_driver_register(&tcc_mmc_core0_driver);
++#endif
++#if defined(CONFIG_MMC_TCC_SDHC_CORE1)
++ ret = platform_driver_register(&tcc_mmc_core1_driver);
++#endif
++ return ret;
++}
++
++static void __exit tcc_mmc_exit(void)
++{
++#if defined(CONFIG_MMC_TCC_SDHC_CORE0)
++ platform_driver_unregister(&tcc_mmc_core0_driver);
++#endif
++#if defined(CONFIG_MMC_TCC_SDHC_CORE1)
++ platform_driver_unregister(&tcc_mmc_core1_driver);
++#endif
++
++ /* remove power control functions */
++ remove_pwm_node(DEVICE_SDHC);
++}
++
++module_init(tcc_mmc_init);
++module_exit(tcc_mmc_exit);
++
++MODULE_DESCRIPTION("Telechips SD/MMC Card driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS(DRIVER_NAME);
++MODULE_AUTHOR("Telechips Inc. linux@telechips.com");
+diff --git a/drivers/mmc/host/tcc_sdhc.h b/drivers/mmc/host/tcc_sdhc.h
+new file mode 100644
+index 0000000..5b11c2c
+--- /dev/null
++++ b/drivers/mmc/host/tcc_sdhc.h
+@@ -0,0 +1,224 @@
++#ifndef __TCC_SDHC_H__
++#define __TCC_SDHC_H__
++
++
++/*******************************************************************************
++* 5. SD/SDIO/MMC/CE-ATA Host Controller Register Define (Base Addr = 0xF0590000)
++********************************************************************************/
++//Core 0 Slot 0
++#define SDCORE0SLOT0_BASE 0xF05A0000
++//Core 0 Slot 1
++#define SDCORE0SLOT1_BASE 0xF05A0100
++//Core 1 Slot 2
++#define SDCORE1SLOT2_BASE 0xF05A0200
++//Core 1 Slot 3
++#define SDCORE1SLOT3_BASE 0xF05A0300
++// Channel Control Register
++#define SDCHCTRL_BASE 0xF05A0800 // R/W 0x0000 SD/MMC port control register
++
++#define HwSD_COM_TRANS_ABORT Hw23+Hw22
++#define HwSD_COM_TRANS_DATSEL Hw21 // data present select
++#define HwSD_COM_TRANS_CICHK Hw20 // command index check enable
++#define HwSD_COM_TRANS_CRCHK Hw19 // command CRC check enable
++#define HwSD_COM_TRANS_SPI Hw7 // SPI mode
++#define HwSD_COM_TRANS_ATACMD Hw6 // cmd completion enable for CE-ATA
++#define HwSD_COM_TRANS_MS Hw5 // multi/single block select
++#define HwSD_COM_TRANS_DIR Hw4 // data transfer direction select
++#define HwSD_COM_TRANS_ACMD12 Hw2 // auto CMD12 enable
++#define HwSD_COM_TRANS_BCNTEN Hw1 // block count enable
++#define HwSD_COM_TRANS_DMAEN Hw0 // DMA Enable
++
++
++#define HwSDCLKSEL_DIV_256 0x80
++#define HwSDCLKSEL_DIV_128 0x40
++#define HwSDCLKSEL_DIV_64 0x20
++#define HwSDCLKSEL_DIV_32 0x10
++#define HwSDCLKSEL_DIV_16 0x08
++#define HwSDCLKSEL_DIV_8 0x04
++#define HwSDCLKSEL_DIV_4 0x02
++#define HwSDCLKSEL_DIV_2 0x01
++#define HwSDCLKSEL_DIV_0 0x00
++#define HwSDCLKSEL_SCK_EN Hw2
++#define HwSDCLKSEL_INCLK_STABLE Hw1
++#define HwSDCLKSEL_INCLK_EN Hw0
++
++#define HwSD_POWER_POW Hw8 // SD bus power
++#define HwSD_POWER_SD8 Hw5 // SD 8-bit mode
++#define HwSD_POWER_HS Hw2 // high speed enable
++#define HwSD_POWER_SD4 Hw1 // data transfer width
++#define HwSD_POWER_VOL33 Hw11+Hw10+Hw9
++
++
++#define HwSD_SRESET_RSTALL Hw0 // software reset for All
++#define HwSD_SRESET_RSTCMD Hw1 // software reset for CMD line
++#define HwSD_SRESET_RSTDAT Hw2 // software reset for DAT line
++
++
++// Port Control
++#define HwSD_PORTCTRL_CD(X) (Hw30 << (X)) // Card Detection for SLOT X. (X = 0 or 1)
++#define HwSD_PORTCTRL_WP(X) (Hw27 << (X)) // Write Protect for SLOT X. (X = 0 or 1)
++#define HwSD_PORTCTRL_SLOT3(X) ((X) * Hw12) // Port Select for SLOT 3 (X = 0 ~ 7)
++#define HwSD_PORTCTRL_SLOT3_MASK HwSD_PORTCTRL_SLOT3(15)
++#define HwSD_PORTCTRL_SLOT2(X) ((X) * Hw8) // Port Select for SLOT 2 (X = 0 ~ 7)
++#define HwSD_PORTCTRL_SLOT2_MASK HwSD_PORTCTRL_SLOT2(15)
++#define HwSD_PORTCTRL_SLOT1(X) ((X) * Hw4) // Port Select for SLOT 1 (X = 0 ~ 7)
++#define HwSD_PORTCTRL_SLOT1_MASK HwSD_PORTCTRL_SLOT1(15)
++#define HwSD_PORTCTRL_SLOT0(X) ((X) * Hw0) // Port Select for SLOT 0 (X = 0 ~ 7)
++#define HwSD_PORTCTRL_SLOT0_MASK HwSD_PORTCTRL_SLOT0(15)
++
++#define HwSD_STATE_SDWP Hw19
++#define HwSD_STATE_NODAT Hw1 // data inhibit
++#define HwSD_STATE_NOCMD Hw0 // command inhibit
++
++#define HwSDINT_STATUS_DATEND Hw22 // data end bit error
++#define HwSDINT_STATUS_DATCRC Hw21 // data crc error
++#define HwSDINT_STATUS_DATTIME Hw20 // data timeout error
++#define HwSDINT_STATUS_CINDEX Hw19 // command index error
++#define HwSDINT_STATUS_CMDEND Hw18 // command command end bit error
++#define HwSDINT_STATUS_CMDCRC Hw17 // command crc error
++#define HwSDINT_STATUS_CMDTIME Hw16 // command timeout error
++#define HwSDINT_STATUS_ERR Hw15 // error interrupt
++#define HwSDINT_STATUS_CDINT Hw8 // card interrupt
++#define HwSDINT_STATUS_CDOUT Hw7 // card removal
++#define HwSDINT_STATUS_CDIN Hw6 // card insertion
++#define HwSDINT_STATUS_RDRDY Hw5 // buffer read ready
++#define HwSDINT_STATUS_WRRDY Hw4 // buffer write ready
++#define HwSDINT_STATUS_DMA Hw3 // DMA interrupt
++#define HwSDINT_STATUS_BLKGAP Hw2 // block gap event
++#define HwSDINT_STATUS_TDONE Hw1 // transfer complete
++#define HwSDINT_STATUS_CDONE Hw0 // command complete
++
++#define HwSDINT_EN_ADMA Hw25 // ADMA error signal enable
++#define HwSDINT_EN_ACMD12 Hw24 // auto CMD12 error signal enable
++#define HwSDINT_EN_CLIMIT Hw23 // current limit error signal enable
++#define HwSDINT_EN_DATEND Hw22 // data end bit error signal enable
++#define HwSDINT_EN_DATCRC Hw21 // data crc error signal enable
++#define HwSDINT_EN_DATTIME Hw20 // data timeout error signal enable
++#define HwSDINT_EN_CINDEX Hw19 // command index error signal enable
++#define HwSDINT_EN_CMDEND Hw18 // command end bit error signal enable
++#define HwSDINT_EN_CMDCRC Hw17 // command crc error signal enable
++#define HwSDINT_EN_CMDTIME Hw16 // command timeout error signal enable
++#define HwSDINT_EN_CDINT Hw8 // card interrupt signal enable
++#define HwSDINT_EN_CDOUT Hw7 // card removal signal enable
++#define HwSDINT_EN_CDIN Hw6 // card insertion signal enable
++#define HwSDINT_EN_RDRDY Hw5 // buffer read ready signal enable
++#define HwSDINT_EN_WRRDY Hw4 // buffer write ready signal enable
++#define HwSDINT_EN_DMA Hw3 // DMA interrupt signal enable
++#define HwSDINT_EN_BLKGAP Hw2 // block gap event signal enable
++#define HwSDINT_EN_TDONE Hw1 // transfer complete signal enable
++#define HwSDINT_EN_CDONE Hw0 // command complete signal enable
++
++
++#define HwSDINT_NORMAL_MASK 0x00007FFF
++#define HwSDINT_ERROR_MASK 0xFFFF8000
++
++#define HwSDINT_CMD_MASK (HwSDINT_EN_CDONE | HwSDINT_EN_CMDTIME | \
++ HwSDINT_EN_CMDCRC | HwSDINT_EN_CMDEND | HwSDINT_EN_CINDEX)
++
++#define HwSDINT_DATA_MASK (HwSDINT_EN_TDONE | HwSDINT_EN_DMA | \
++ HwSDINT_EN_RDRDY | HwSDINT_EN_WRRDY | \
++ HwSDINT_EN_DATTIME | HwSDINT_EN_DATCRC | \
++ HwSDINT_EN_DATEND)
++
++
++typedef struct _SDHOST_T{
++ volatile unsigned int SDMA; // 0x000 R/W 0x0000 SDMA System Address
++// volatile unsigned short NOTDEFINE0; // 0x002
++ volatile unsigned short BSIZE; // 0x004 R/W 0x0000 Block Size
++ volatile unsigned short BCNT; // 0x006 R/W 0x0000 Block Count
++ volatile unsigned int ARG; // 0x008 R/W 0x0000 Argument
++// volatile unsigned short NOTDEFINE1; // 0x00A
++
++/////
++// volatile unsigned short TMODE; // 0x00C R/W 0x0000 Transfer Mode
++// volatile unsigned short CMD; // 0x00E R/W 0x0000 Command
++ volatile unsigned int CTMODE; // 0x00C R/W Command and Transfer Mode
++/////
++
++////
++// volatile unsigned short RESP0; // 0x010 R 0x0000 Response0
++// volatile unsigned short RESP1; // 0x012 R 0x0000 Response1
++ volatile unsigned int RESP1_0; // 0x010 R Response0,1
++///
++
++/////
++// volatile unsigned short RESP2; // 0x014 R 0x0000 Response2
++// volatile unsigned short RESP3; // 0x016 R 0x0000 Response3
++ volatile unsigned int RESP3_2; // 0x014 R Response2,3
++/////
++
++//////
++// volatile unsigned short RESP4; // 0x018 R 0x0000 Response4
++// volatile unsigned short RESP5; // 0x01A R 0x0000 Response5
++ volatile unsigned int RESP5_4; // 0x018 R Response4,5
++/////
++
++//////
++// volatile unsigned short RESP6; // 0x01C R 0x0000 Response6
++// volatile unsigned short RESP7; // 0x01E R 0x0000 Response7
++ volatile unsigned int RESP7_6; // 0x01C R Response6,7
++//////
++
++ volatile unsigned short DATAL; // 0x020 R/W - Buffer Data Port(Low)
++ volatile unsigned short DATAH; // 0x022 R/W - Buffer Data Port(High)
++////
++// volatile unsigned short STATEL; // 0x024 R 0x0000 Present State(Low)
++// volatile unsigned short STATEH; // 0x026 R 0x0000 Present State(High)
++ volatile unsigned int STATE; // 0x024 R Present State
++////
++
++ volatile unsigned short CONTL; // 0x028 R/W 0x0000 Power Control / Host Control
++ volatile unsigned short CONTH; // 0x02A R/W 0x0000 Wakeup Control / Block Gap Control
++ volatile unsigned short CLK; // 0x02C R/W 0x0000 Clock Control
++//////
++ volatile unsigned short TIME; // 0x02E R/W 0x0000 Software Reset / Timeout Control
++// volatile unsigned char TIME; // 0x02E R/W Software Reset / Timeout Control
++// volatile unsigned char RESET; // 0x02F R/W Software Reset / Timeout Control
++//////
++
++/////////////
++/// volatile unsigned short STSL; // 0x030 R 0x0000 Normal Interrupt Status(Low)
++/// volatile unsigned short STSH; // 0x032 R 0x0000 Normal Interrupt Status(High)
++ volatile unsigned int STS; // 0x030 R Normal Interrupt Status
++/////////////
++
++//////
++// volatile unsigned short STSENL; // 0x034 R/W 0x0000 Normal Interrupt Status Enable(Low)
++// volatile unsigned short STSENH; // 0x036 R/W 0x0000 Normal Interrupt Status Enable(High)
++ volatile unsigned int STSEN; // 0x034 R/W Normal Interrupt Status Enable
++/////
++/////
++// volatile unsigned short INTENL; // 0x038 R/W 0x0000 Normal Interrupt Signal Enable(Low)
++// volatile unsigned short INTENH; // 0x03A R/W 0x0000 Normal Interrupt Signal Enable(High)
++ volatile unsigned int INTEN; // 0x038 R/W Normal Interrupt Signal Enable
++/////
++ volatile unsigned short CMD12ERR; // 0x03C R 0x0000 Auto CMD12 Error Status
++ volatile unsigned short NOTDEFINE2; // 0x03E
++ volatile unsigned short CAPL; // 0x040 R 0x30B0 Capabilities(Low)
++ volatile unsigned short CAPH; // 0x042 R 0x69EF Capabilities(High)
++ volatile unsigned short NOTDEFINE3[2]; // 0x044, 0x046
++ volatile unsigned short CURL; // 0x048 R 0x0001 Maximum Current Capabilities(Low)
++ volatile unsigned short CURH; // 0x04A R 0x0000 Maximum Current Capabilities(High)
++ volatile unsigned short NOTDEFINE4[2]; // 0x04C, 0x04E
++ volatile unsigned short FORCEL; // 0x050 W 0x0000 Force event for AutoCmd12 Error
++ volatile unsigned short FORCEH; // 0x052 W 0x0000 Force event for Error Interrupt Status
++ volatile unsigned short AUDIO_DMAERR; // 0x054 R/W 0x0000 AUDIO DMA Error Status
++ volatile unsigned short NOTDEFINE5; // 0x056
++ volatile unsigned short ADDR0; // 0x058 R/W 0x0000 AUDIO DMA Address[15:0]
++ volatile unsigned short ADDR1; // 0x05A R/W 0x0000 AUDIO DMA Address[31:16]
++ volatile unsigned short ADDR2; // 0x05C R/W 0x0000 AUDIO DMA Address[47:32]
++ volatile unsigned short ADDR3; // 0x05E R/W 0x0000 AUDIO DMA Address[63:48]
++ volatile unsigned short NOTDEFINE6[78]; // 0x060~0x0FA
++ volatile unsigned short SLOT; // 0x0FC R 0x0000 Slot Interrupt Status
++ volatile unsigned short VERSION; // 0x0FE R 0x0002 Host Controller Version
++}SDHOST_T, *PSDHOST_T;
++
++typedef struct _SDCHCTRL_T{
++ volatile unsigned int SDPORTCTRL; // 0x00 R/W 0x0000 SD/MMC port control register
++ volatile unsigned int SDPORTDLY0; // 0x04 R/W 0x0000 SD/MMC output delay control register
++ volatile unsigned int SDPORTDLY1; // 0x08 R/W 0x0000 SD/MMC output delay control register
++ volatile unsigned int SDPORTDLY2; // 0x0C R/W 0x0000 SD/MMC output delay control register
++ volatile unsigned int SDPORTDLY3; // 0x10 R/W 0x0000 SD/MMC output delay control register
++}SDCHCTRL_T, *PSDCHCTRL_T;
++
++#endif /*__TCC_SDHC_H__*/
+diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
+index db3377d..98ff482 100644
+--- a/drivers/net/usb/dm9601.c
++++ b/drivers/net/usb/dm9601.c
+@@ -518,7 +518,10 @@ static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+ return NULL;
+ }
+
+- __skb_push(skb, DM_TX_OVERHEAD);
++ /* because TCC8902's USB OTG Controller request that the
++ * transfer buffer of urb must be DWORD aligned, so make
++ * skb->data DWORD aligned */
++ __skb_push(skb, ((unsigned int)skb->data) % 4);
+
+ /* usbnet adds padding if length is a multiple of packet size
+ if so, adjust length value in header */
+diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
+index fdbf3be..8325b87 100644
+--- a/drivers/net/usb/kaweth.c
++++ b/drivers/net/usb/kaweth.c
+@@ -645,7 +645,10 @@ static void kaweth_usb_receive(struct urb *urb)
+ return;
+ }
+
+- skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
++ /* because TCC8902's USB OTG Controller request that the
++ * transfer buffer of urb must be DWORD aligned, so make
++ * skb->data DWORD aligned */
++ skb_reserve(skb, ((unsigned int)skb->data) % 4);
+
+ skb_copy_to_linear_data(skb, kaweth->rx_buf + 2, pkt_len);
+
+diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
+index 7914867..7110a07 100644
+--- a/drivers/net/usb/pegasus.c
++++ b/drivers/net/usb/pegasus.c
+@@ -575,7 +575,10 @@ static void fill_skb_pool(pegasus_t * pegasus)
+ */
+ if (pegasus->rx_pool[i] == NULL)
+ return;
+- skb_reserve(pegasus->rx_pool[i], 2);
++ /* because TCC8902's USB OTG Controller request that the
++ * transfer buffer of urb must be DWORD aligned, so make
++ * skb->data DWORD aligned */
++ skb_reserve(pegasus->rx_pool[i], ((unsigned int)pegasus->rx_pool[i]->data) % 4);
+ }
+ }
+
+diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
+index 6133401..c6de3eb 100644
+--- a/drivers/net/usb/rtl8150.c
++++ b/drivers/net/usb/rtl8150.c
+@@ -648,7 +648,10 @@ static void fill_skb_pool(rtl8150_t *dev)
+ if (!skb) {
+ return;
+ }
+- skb_reserve(skb, 2);
++ /* because TCC8902's USB OTG Controller request that the
++ * transfer buffer of urb must be DWORD aligned, so make
++ * skb->data DWORD aligned */
++ skb_reserve(skb, ((unsigned int)skb->data) % 4);
+ dev->rx_skb_pool[i] = skb;
+ }
+ }
+diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
+index 02d25c7..c198b06 100644
+--- a/drivers/net/usb/usbnet.c
++++ b/drivers/net/usb/usbnet.c
+@@ -309,7 +309,6 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
+ usb_free_urb (urb);
+ return;
+ }
+- skb_reserve (skb, NET_IP_ALIGN);
+
+ entry = (struct skb_data *) skb->cb;
+ entry->urb = urb;
+diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
+index 45bdf0b..5796516 100644
+--- a/drivers/net/wireless/Kconfig
++++ b/drivers/net/wireless/Kconfig
+@@ -313,6 +313,27 @@ config LIBERTAS_THINFIRM_USB
+ ---help---
+ A driver for Marvell Libertas 8388 USB devices using thinfirm.
+
++config MARVELL_8686_SDIO
++ tristate "Official driver for Marvell SDIO 8686"
++ depends on WLAN_80211 && MMC
++ select WIRELESS_EXT
++ select IEEE80211
++ select FW_LOADER
++ ---help---
++ Official driver for Marvell 8686 devices.
++
++config MARVELL_8686_PROC_FS
++ bool "Enable proc-fs support for official marvell 8686 module."
++ depends on MARVELL_8686_SDIO
++ ---help---
++ Proc-fs support.
++
++config MARVELL_8686_DEBUG
++ bool "Enable full debugging output in the official marvell 8686 module."
++ depends on MARVELL_8686_SDIO
++ ---help---
++ Debugging support.
++
+ config AIRO
+ tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
+ depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN)
+diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
+index 59d2d80..847a10f 100644
+--- a/drivers/net/wireless/Makefile
++++ b/drivers/net/wireless/Makefile
+@@ -50,6 +50,8 @@ obj-$(CONFIG_LIBERTAS) += libertas/
+
+ obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf/
+
++obj-$(CONFIG_MARVELL_8686_SDIO) += marvell8686/
++
+ rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o
+ rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o
+
+diff --git a/drivers/net/wireless/marvell8686/Makefile b/drivers/net/wireless/marvell8686/Makefile
+new file mode 100644
+index 0000000..e443661
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/Makefile
+@@ -0,0 +1,15 @@
++ifeq ($(CONFIG_MARVELL_8686_PROC_FS),y)
++ sd8686-objs += wlan_proc.o
++endif
++
++ifeq ($(CONFIG_MARVELL_8686_DEBUG),y)
++ sd8686-objs += wlan_debug.o
++endif
++
++sd8686-objs += wlan_main.o wlan_fw.o \
++ wlan_wext.o wlan_rx.o wlan_tx.o \
++ wlan_cmd.o wlan_cmdresp.o wlan_scan.o \
++ wlan_join.o wlan_wmm.o wlan_11d.o wlan_fops.o \
++ if_sdio.o
++obj-$(CONFIG_MARVELL_8686_SDIO) += sd8686.o
++
+diff --git a/drivers/net/wireless/marvell8686/README b/drivers/net/wireless/marvell8686/README
+new file mode 100644
+index 0000000..5dca07e
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/README
+@@ -0,0 +1,1587 @@
++===============================================================================
++ U S E R M A N U A L
++
++1) FOR DRIVER BUILD
++
++ Goto source code directory src_xxxx.
++ make [clean] build
++ The driver and utility binaries can be found in ../bin_xxxx directory.
++
++2) FOR DRIVER INSTALL
++
++ a) Copy helper_sd.bin and sd8xxx.bin to /lib/firmware/mrvl/ directory,
++ create the directory if it doesn't exist.
++ b) insmod sdio.o (or sdio.ko) [clkrate=5|10|20] [intmode=0|1] [gpiopin=n]
++ The default SDIO clock frequency is 20 MHz. It can be changed to 10 MHz or 5 MHz.
++ intmode -- 0 for SDIO (default)
++ intmode -- 1 for GPIO, gpiopin for GPIO pin# has to be specified in this mode.
++ c) insmod sd8xxx.o (or sd8xxx.ko) helper_name=/lib/firmware/mrvl/helper_sd.bin \
++ fw_name=/lib/firmware/mrvl/sd8xxx.bin
++
++ To install SD8xxx Driver with user-specified helper file /lib/firmware/mrvl/helper_sd.bin and
++ MFG firmware file /lib/firmware/mrvl/sd8xxxmfg.bin, using the following command:
++ insmod sdio.o (or sdio.ko)
++ insmod sd8xxx.o (or sd8xxx.ko) mfgmode=1 helper_name=/lib/firmware/mrvl/helper_sd.bin \
++ fw_name=/lib/firmware/mrvl/sd8xxxmfg.bin
++
++3) FOR DRIVER PROC & DEBUG
++
++ The following info are provided in /proc/net/wlan/info,
++
++ driver_name = "wlan"
++ driver_version = <chip id, firmware version and driver version>
++ InterfaceName = "ethX"
++ Mode = "Ad-hoc" | "Managed" | "Auto" | "Unknown"
++ State = "Disconnected" | "Connected"
++ MACAddress = <6-byte adapter MAC address>
++ MCCount = <multicast address count>
++ ESSID = <current SSID>
++ Channel = <current channel>
++ region_code = <current region code>
++ MCAddr[n] = <multicast address>
++ num_tx_bytes = <number of bytes sent to device>
++ num_rx_bytes = <number of bytes received from device and sent to kernel>
++ num_tx_pkts = <number of packets sent to device>
++ num_rx_pkts = <number of packets received from device and sent to kernel>
++ num_tx_pkts_dropped = <number of tx packets dropped by driver>
++ num_rx_pkts_dropped = <number of rx packets dropped by driver>
++ num_tx_pkts_err = <number of tx packets failed to send to device>
++ num_rx_pkts_err = <number of rx packets failed to receive from device>
++ carrier "on" | "off"
++ tx queue "stopped" | "started"
++ CurCmd "NULL" | <current command id and action>
++
++ The following debug info are provided in /proc/net/wlan/debug,
++
++ IntCounter = <interrupt count, cleared when interrupt handled>
++ ConnectStatus = <0/1, disconnected/connected>
++ wmmQStp = <0/1, WMM queue started/stopped>
++ wmmPkts = <number of tx packets in WMM queues>
++ wmmAcVo = <number of packets sent to device from WMM AcVo queue>
++ wmmAcVi = <number of packets sent to device from WMM AcVi queue>
++ wmmAcBE = <number of packets sent to device from WMM AcBE queue>
++ wmmAcBK = <number of packets sent to device from WMM AcBK queue>
++ PSMode = <0/1, CAM mode/PS mode>
++ PSState = <0/1/2/3, full power state/awake state/pre-sleep state/sleep state>
++ IsDeepSleep = <0/1, not deep sleep state/deep sleep state>
++ IsAutoDeepSleepEnabled = <0/1, not auto deep sleep mode/auto deep sleep mode>
++ WakeupDevReq = <0/1, wakeup device not required/required>
++ WakeupTries = <wakeup device count, cleared when device awake>
++ HS_Configured = <0/1, host sleep not configured/configured>
++ HS_Activated = <0/1, extended host sleep not activated/activated>
++ num_tx_timeout = <number of tx timeout>
++ num_cmd_timeout = <number of timeout commands>
++ TimeoutCmdId = <command id of the last timeout command>
++ TimeoutCmdAct = <command action of the last timeout command>
++ LastCmdId = <command id of the last several commands sent to device>
++ LastCmdAct = <command action of the last several commands sent to device>
++ LastCmdIndex = <0 based last command index>
++ LastCmdRespId = <command id of the last several command responses received from device>
++ LastCmdRespIndex = <0 based last command response index>
++ LastEvent = <event id of the last several events received from device>
++ LastEventIndex = <0 based last event index>
++ num_cmd_h2c_fail = <number of commands failed to send to device>
++ num_cmd_sleep_cfm_fail = <number of sleep confirm failed to send to device>
++ num_tx_h2c_fail = <number of data packets failed to send to device>
++ num_evt_deauth = <number of deauthenticated events received from device>
++ num_evt_disassoc = <number of disassociated events received from device>
++ num_evt_link_lost = <number of link lost events received from device>
++ num_cmd_deauth = <number of deauthenticate commands sent to device>
++ num_cmd_assoc_ok = <number of associate commands with success return>
++ num_cmd_assoc_fail = <number of associate commands with failure return>
++ dnld_sent = <0/1/2, send resources available/sending data to device/sending command to device>
++
++ Use dmesg or cat /var/log/debug to check driver debug messages.
++
++ Update /proc/sys/kernel/printk to change message log levels.
++ For example,
++ echo 6 > /proc/sys/kernel/printk (messages with a higher priority than 6
++ will be printed to the console)
++ echo 15 > /proc/sys/kernel/printk (all messages will be printed to console)
++
++4) FOR IWPRIV COMMAND
++
++NAME
++ This manual describes the usage of private commands used in Marvell WLAN
++ Linux Driver. All the commands available in Wlanconfig will not be available
++ in the iwpriv.
++
++ To use parameters as hex format, a'0x' must precede it for the parameters to
++ be parsed properly.
++
++SYNOPSIS
++ iwpriv <ethX> <command> [sub-command] ...
++
++ iwpriv ethX version
++ iwpriv ethX verext
++ iwpriv ethX scantype [sub-command]
++ iwpriv ethX getSNR <n>
++ iwpriv ethX getNF <n>
++ iwpriv ethX getRSSI <n>
++ iwpriv ethX setrxant <n>
++ iwpriv ethX getrxant
++ iwpriv ethX settxant <n>
++ iwpriv ethX gettxant
++ iwpriv ethX authalgs <n>
++ iwpriv ethX encryptionmode <n>
++ iwpriv ethX setregioncode <n>
++ iwpriv ethX getregioncode
++ iwpriv ethX setbcnavg <n>
++ iwpriv ethX getbcnavg
++ iwpriv ethX setdataavg <n>
++ iwpriv ethX getdataavg
++ iwpriv ethX setlisteninter <n>
++ iwpriv ethX getlisteninter
++ iwpriv ethX setmultipledtim <n>
++ iwpriv ethX getmultipledtim
++ iwpriv ethX atimwindow <n>
++ iwpriv ethX deepsleep <n>
++ iwpriv ethX autodeepsleep <n>
++ iwpriv ethX hscfg <n>
++ iwpriv ethX hssetpara <n>
++ iwpriv ethX deauth
++ iwpriv ethX adhocstop
++ iwpriv ethX radioon
++ iwpriv ethX radiooff
++ iwpriv ethX reasso-on
++ iwpriv ethX reasso-off
++ iwpriv ethX scanmode [sub-command]
++ iwpriv ethX setwpaie <n>
++ iwpriv ethX setaeskey <n>
++ iwpriv ethX getaeskey
++ iwpriv ethX rmaeskey
++ iwpriv ethX getcis
++ iwpriv ethX getlog
++ iwpriv ethX getadhocstatus
++ iwpriv ethX adhocgrate <n>
++
++Version 4 Command:
++ iwpriv ethX inactivityto <n>
++ iwpriv ethX sleeppd <n>
++ iwpriv ethX enable11d <n>
++ iwpriv ethX bgscan <n>
++ iwpriv ethX wmm <n>
++ iwpriv ethX tpccfg <n>
++ iwpriv ethX sdioclock <n>
++
++Version 5 Command:
++ iwpriv ethX ledgpio <n>
++ iwpriv ethX wmm_qosinfo <n>
++ iwpriv ethX scanprobes <n>
++ iwpriv ethX lolisteninter <n>
++ iwpriv ethX rateadapt <n> <m> <l> <k>
++ iwpriv ethX fwwakeupmethod <n>
++ iwpriv ethX txcontrol <n>
++ iwpriv ethX uapsdnullgen <n>
++ iwpriv ethX psnullinterval <n>
++ iwpriv ethX getrxinfo
++ iwpriv ethX gettxrate
++ iwpriv ethX bcninterval [n]
++ iwpriv ethX setcoalescing <n>
++ iwpriv ethX bcnmisto <n>
++ iwpriv ethX adhocawakepd <n>
++ iwpriv ethX sdiopullctrl <m> <n>
++ iwpriv ethX scantime [s] [a] [p]
++ iwpriv ethX ldocfg [n]
++ iwpriv ethX dataevtcfg [a] [b] [c] [d] [e] [f] [g] [h] [i]
++ iwpriv ethX sdiomode [n]
++ iwpriv ethX rtsctsctrl [n]
++ iwpriv ethX drvdbg [n] [m]
++ iwpriv ethX adhocgprot [n]
++ iwpriv ethX getrate
++ iwpriv ethX associate <n>
++ iwpriv ethX getdtim
++
++DESCRIPTION
++ Those commands are used to send additional commands to the Marvell WLAN
++ card via the Linux device driver.
++
++ The ethX parameter specifies the network device that is to be used to
++ perform this command on. it could be eth0, eth1 etc.
++
++version
++ This is used to get the current version of the driver and the firmware.
++
++verext
++ Retrieve and display an extended version string from the firmware
++
++ Usage:
++ iwpriv ethX verext [#]
++
++ where [#] is an optional argument to retrieve a specific version string,
++ omission of the argument retrieves the 0 indexed string
++
++scantype
++ This command is used to set the scan type to be used by the driver in
++ the scan command. This setting will not be used while performing a scan
++ for a specific SSID, as it is always done with scan type being active.
++
++ where the sub-commands are: -
++ active -- to set the scan type to active
++ passive -- to set the scan type to passive
++ get -- to get the scan type set in the driver
++
++getSNR
++ This command gets the average and non average value of Signal to Noise
++ Ratio of Beacon and Data.
++
++ where value is:
++ 0 -- Beacon non-average.
++ 1 -- Beacon average.
++ 2 -- Data non-average.
++ 3 -- Data average.
++
++ If no value is given, all four values are returned in the order mentioned
++ above.
++
++ Note: This command is available only when STA is connected.
++
++getRSSI
++ This command gets the average and non average value os Receive Signal
++ Strength of Beacon and Data.
++
++ where value is:
++ 0 -- Beacon non-average.
++ 1 -- Beacon average.
++ 2 -- Data non-average.
++ 3 -- Data average.
++
++ Note: This command is available only when STA is connected.
++
++getNF
++ This command gets the average and non average value of Noise Floor of
++ Beacon and Data.
++
++ where value is:
++ 0 -- Beacon non-average.
++ 1 -- Beacon average.
++ 2 -- Data non-average.
++ 3 -- Data average.
++
++ Note: This command is available only when STA is connected.
++
++setrxant
++ This command is used to set the mode for Rx antenna.
++
++ The options that can be sent are:-
++ 1 -- Antenna 1.
++ 2 -- Antenna 2.
++ 0xFFFF -- Diversity.
++
++ Usage:
++ iwpriv ethX setrxant 0x01: select Antenna 1.
++
++getrxant
++ This command is used to get the mode for Rx antenna.
++
++settxant
++ This command is used to set the mode for Tx antenna.
++ The options that can be sent are:-
++ 1 -- Antenna 1.
++ 2 -- Antenna 2.
++ 0xFFFF -- Diversity.
++ Usage:
++ iwpriv ethX settxant 0x01: select Antenna 1.
++
++gettxant
++ This command is used to get the mode for Tx antenna.
++
++authalgs
++ This command is used by the WPA supplicant to set the authentication
++ algorithms in the station.
++
++encryptionmode
++ This command is used by the WPA supplicant to set the encryption algorithm.
++
++ where values can be:-
++ 0 -- NONE
++ 1 -- WEP40
++ 2 -- TKIP
++ 3 -- CCMP
++ 4 -- WEP104
++
++setregioncode
++ This command is used to set the region code in the station.
++ where value is 'region code' for various regions like
++ USA FCC, Canada IC, France, Europe ETSI, Japan ...
++
++ Usage:
++ iwpriv ethX setregioncode 0x10: set region code to USA (0x10).
++
++getregioncode
++ This command is used to get the region code information set in the
++ station.
++
++setbcnavg
++ Set the weighting factor for calculating beacon average RSSI and SNR.
++ where value can be:
++ 0 -- default beacon averaging factor (8)
++ 1-8 -- beacon averaging factor
++ Usage:
++ iwpriv ethX setbcnavg 0
++ iwpriv ethX setbcnavg 8
++
++getbcnavg
++ Get the weighting factor for calculating beacon average RSSI and SNR.
++ Usage:
++ iwpriv ethX getbcnavg
++
++setdataavg
++ Set the weighting factor for calculating data average RSSI and SNR.
++ where value can be:
++ 0 -- default data averaging factor (8)
++ 1-8 -- data averaging factor
++ Usage:
++ iwpriv ethX setdataavg 0
++ iwpriv ethX setdataavg 8
++
++getdataavg
++ Get the weighting factor for calculating data average RSSI and SNR.
++ Usage:
++ iwpriv ethX getdataavg
++
++setlisteninter
++ This command is used to set the listen interval in the
++ station.
++
++ where the value ranges between 1 - 255
++
++getlisteninter
++ This command is used to get the listen interval value set in the
++ station.
++
++setmultipledtim
++ This command is used to set the multiple dtim value in the
++ station.
++ where the value is 1,2,3,4,5,0xfffe
++ 65534 (0xfffe) means that the dtim will be ignored in firmware,
++ listen interval or local listen interval will be used.
++
++getmultipledtim
++ This command is used to get the multiple dtim value set in the station.
++
++atimwindow
++ This command is used to set atim value in the station when an argument is given,
++ return the atim value set by the user and the current atim value if adapter is in connected state.
++ The valid atimwindow is between 0 - 50.
++
++ Usage:
++ iwpriv ethX atimwindow 0 (set atimwindow to 0)
++
++ not connected:
++ iwpriv ethX atimwindow (get atimwindow value set by user)
++
++ connected:
++ iwpriv ethX atimwindow (get atimwindow set by user previously
++ and current atimwindow)
++
++deauth
++ This command is used to send the de-authentication to the AP with which
++ the station is associated. This command is valid only when
++ station is in Infrastructure mode.
++
++ Note: This command is available only when STA is connected.
++
++reasso-on
++ This command is used to enable re-association function in dirver.
++
++reasso-off
++ This command is used to disable re-association function in driver
++
++adhocstop
++ This command is used to stop beacon transmission from the station and
++ go into idle state in ad-hoc mode.
++
++ Note: This command is available only when STA is connected.
++
++radioon
++ This command is used to turn on the RF antenna.
++
++radiooff
++ This command is sued to turn off the RF antenna.
++
++scanmode
++ This command is used to set the station to scan for either IBSS
++ networks or BSS networks or both BSS and IBSS networks. This
++ command can be used with sub commands,
++
++ where the value for
++ bss -- Scan All the BSS networks.
++ ibss -- Scan All the IBSS networks.
++ any -- Scan both BSS and IBSS networks.
++
++deepsleep
++ This command is used to configure the station in deepsleep mode.
++
++ where the option is:
++ 1 -- Enable deepsleep mode
++ 0 -- Disable deepsleep mode
++ 2 -- Display deepsleep setting
++ Usage:
++ iwpriv ethX deepsleep 1
++ Enable deepsleep mode
++ iwpriv ethX deepsleep 0
++ Disable deepsleep mode
++ iwpriv ethX deepsleep 2
++ Display deepsleep setting
++
++autodeepsleep
++ This command is used to configure the station in auto deepsleep mode.
++
++ where the option is:
++ 1 -- Enable auto deepsleep mode
++ 0 -- Disable auto deepsleep mode
++ Usage:
++ iwpriv ethX autodeepsleep
++ Read the current auto deepsleep setting
++ iwpriv ethX autodeepsleep 1
++ Enable auto deepsleep mode
++ iwpriv ethX autodeepsleep 0
++ Disable auto deepsleep mode
++
++hscfg
++ This command is used to configure the host sleep parameters.
++
++ iwpriv ethX hscfg Condition [GPIO# [Gap]]
++
++ Note:
++
++ 1) This command takes one (Condition) or two (Condition and GPIO#) or three (Condition, GPIO# and gap)
++ parameters.
++
++ where Condition is:
++ bit 0 = 1 -- broadcast data
++ bit 1 = 1 -- unicast data
++ bit 2 = 1 -- mac event
++ bit 3 = 1 -- multicast packet
++
++ where GPIO is the pin number of GPIO used to wakeup the host. It could be any valid
++ GPIO pin# (e.g. 0-7) or 0xff (Interface, e.g. SDIO will be used instead).
++
++ where Gap is the gap in milli seconds between wakeup signal and wakeup event
++ or 0xff for special setting.
++
++ 2) the Host Sleep mode will be cancelled if condition is set to -1.
++
++ 3) Usage:
++ iwpriv eth1 hscfg -1 # cancel host sleep mode
++
++ iwpriv eth1 hscfg 3 # broadcast and unicast data
++ # use GPIO and GAP set previously
++
++ iwpriv eth1 hscfg 2 0x3 # unicast data
++ # use GPIO 3
++ # use GAP set previously
++
++ iwpriv eth1 hscfg 2 1 0xa0 # unicast data
++ # use GPIO 1
++ # gap: 160 ms
++
++ iwpriv eth1 hscfg 2 0xff # unicast data
++ # use Interface (e.g. SDIO)
++ # use GAP set previously
++
++ iwpriv eth1 hscfg 0x2 0x3 0xff # unicast data
++ # use GPIO 3
++ # special host sleep mode
++
++ iwpriv eth1 hscfg 0x2 0xff 0xff # unicast data
++ # use Interface (e.g. SDIO)
++ # special host sleep mode
++
++hssetpara
++ This command is used to set host sleep parameters.
++
++ iwpriv ethX hssetpara Condition [GPIO# [Gap]]
++
++ Note:
++ 1) The usages of parameters are the same as "hscfg" command.
++ 2) The parameters will be saved in the driver and be usded when host suspends.
++
++setwpaie
++ This command is used by WPA supplicant to send the WPA-IE to the driver.
++
++setaeskey
++ This command is used to set the AES key, when the station is in Ad-hoc
++ mode.
++
++ where value can be any 16 byte value.
++
++ Usage:
++ iwpriv ethX setaeskey 12345678901234567890123456789012
++
++getaeskey
++ This command is used to get the AES key, when the station is in Ad-hoc
++ mode.
++
++rmaeskey
++ This command is used to remove the Ad-Hoc AES key that is previously set.
++ It will disable ad-hoc AES as well.
++
++getcis
++ This command is used to read the Card Info Structure Table.
++
++getlog
++ This command is used to get the 802.11 statistics available in the
++ station.
++
++ Note: This command is available only when STA is connected.
++
++getadhocstatus
++ This command is used to get the ad-hoc Network Status.
++
++ The various status codes are:
++ AdhocStarted
++ AdhocJoined
++ AdhocIdle
++ InfraMode
++ AutoUnknownMode
++
++ Note: This command is available only when STA is connected.
++
++adhocgrate
++ This command is used to enable(1) g_rate, Disable(0) g_rate
++ and request(2) the status which g_rate is disabled/enabled,
++ for Ad-hoc creator.
++
++ where value is:
++ 0 -- Disable
++ 1 -- Enable
++ 2 -- Get
++
++ledgpio
++ This command is used to set/get LED settings.
++
++ iwpriv ethX ledgpio <LEDs>
++ will set the corresponding LED for the GPIO Line.
++
++ iwpriv ethX ledgpio
++ will get the current LEDs settings.
++
++ Usage:
++ iwpriv eth1 ledgpio 1 0 2 1 3 16
++ LED 1 -> GPIO 0
++ LED 2 -> GPIO 1
++ LED 3 -> disable
++
++ iwpriv eth1 ledgpio
++ shows LED information in the format as mentioned above.
++
++ Note: LED 0 is invalid
++ Maximum Number of LEDs are 3.
++
++inactivityto
++ This command is used by the host to set/get the inactivity timeout value,
++ which specifies when WLAN device is put to sleep.
++
++ Usage:
++ iwpriv ethX inactivityto [<timeout>]
++
++ where the parameter are:
++ timeout: timeout value in milliseconds.
++
++ Example:
++ iwpriv eth1 inactivityto
++ "get the timeout value"
++
++ iwpriv eth1 inactivityto X
++ "set timeout value to X ms"
++
++sleeppd
++ This command is used to configure the sleep period of the WLAN device.
++
++ Usage:
++ iwpriv ethX sleeppd [<sleep period>]
++
++ where the parameter are:
++ Period: sleep period in milliseconds. Range 10~60.
++
++ Example:
++ iwpriv eth1 sleeppd 10
++ "set period as 10 ms"
++ iwpriv eth1 sleeppd
++ "get the sleep period configuration"
++
++enable11d
++ This command is used to control 11d
++ where value is:
++ 1 -- Enable
++ 0 -- Disable
++ 2 -- Get
++
++wmm
++ This command is used to control WMM
++
++ where value is:
++ 0 -- Disable
++ 1 -- Enable
++ 2 -- Get
++
++
++bgscan
++ Enables or disables the Background scan.
++
++ The configuration for bg scan must be set using wlanconfig
++
++ Usage:
++ wlanconfig ethX bgscanconfig bg_scan_config.conf
++ iwpriv ethX bgscan 0 (disable)
++ iwpriv ethX bgscan 1 (enable)
++ iwpriv ethX bgscan 2 (display enable or disable)
++
++tpccfg
++ Enables or disables automatic transmit power control.
++
++ The first parameter turns this feature on (1) or off (0). When turning
++ on, the user must also supply four more parameters in the following
++ order:
++ -UseSNR (Use SNR (in addition to PER) for TPC algorithm),
++ -P0 (P0 power level for TPC),
++ -P1 (P1 power level for TPC),
++ -P2 (P2 power level for TPC).
++
++ Usage:
++ iwpriv ethX tpccfg: Get current configuration
++ iwpriv ethX tpccfg 0: disable auto TPC
++ iwpriv ethX tpccfg 0x01 0x00 0x05 0x0a 0x0d: enable auto TPC; do not use SNR;
++ P0=0x05; P1=0x0a; P2=0x0d;
++ iwpriv ethX tpccfg 0x01 0x01 0x05 0x0a 0x0d: enable auto TPC; use SNR;
++ P0=0x05; P1=0x0a; P2=0x0d.
++
++sdioclock
++ Turn On(1) or Off(0) the SDIO clock.
++
++ Usage:
++ iwpriv ethX sdioclock 1 (on)
++ iwpriv ethX sdioclock 0 (off)
++
++wmm_qosinfo
++ This command sets WMM IE QOS info when an argument is given, and gets current WMM
++ IE QOS info when no argument is given.
++
++ Usage:
++ iwpriv ethX wmm_qosinfo 0x0f (set WMM IE QOS info to 0x0f)
++ iwpriv ethX wmm_qosinfo (get WMM IE QOS info)
++
++scanprobes
++ This command sets number of probe requests per channel.
++
++ Usage:
++ iwpriv ethX scanprobes 3 (set scan probes to 3)
++ iwpriv ethX scanprobes (get scan probes)
++
++lolisteninter
++ This command sets the value of listen interval.
++
++ Usage:
++ iwpriv ethX lolisteninter 234 (set the lolisteninter to 234)
++ iwpriv ethX lolisteninter (get the lolisteninter value)
++
++rateadapt
++ This command sets the data rates bitmap.
++ Where <n>
++ 0: no HW rate drop
++ 1: HW table rate drop
++ 2: HW single rate drop
++ <m>
++ data rate bitmap
++ Bit Data rate
++ 0 1 Mbps
++ 1 2 Mbps
++ 2 5.5 Mbps
++ 3 11 Mbps
++ 4 Reserved
++ 5 6 Mbps
++ 6 9 Mbps
++ 7 12 Mbps
++ 8 18 Mbps
++ 9 24 Mbps
++ 10 36 Mbps
++ 11 48 Mbps
++ 12 54 Mbps
++ 12-15 Reserved
++ <l> Threshold, Number of same rate retries before switch to Final rate.
++ Used only if HW single rate drop is selected. Typical values are from 3 to 6.
++
++ <k> Final Rate, This value is used only if HW single rate drop is selected.
++ value Data rate
++ 0 1 Mbps
++ 1 2 Mbps
++ 2 5.5 Mbps
++ 3 11 Mbps
++ 4 Reserved
++ 5 6 Mbps
++ 6 9 Mbps
++ 7 12 Mbps
++ 8 18 Mbps
++ 9 24 Mbps
++ 10 36 Mbps
++ 11 48 Mbps
++ 12 54 Mbps
++ 13-15 Reserved
++ Usage:
++ iwpriv ethX rateadapt
++ read the currect data rate setting
++ iwpriv ethX rateadapt 1 0x07
++ enable hardware auto data rate adapt and
++ data rates are 1Mbps, 2Mbsp and 5.5Mbps
++ iwpriv ethX rateadapt 2 0x0f 6 2
++ use HW single rate drop, data rates are 1Mbps, 2Mbsp and 5.5Mbps, 11Mbps
++ Threshold is 6, Final Rate is 5.5 Mbps
++
++fwwakeupmethod
++ This command is used to set the firmware wakeup method.
++
++ where value <n> is:
++ 0 -- Leave the current method to wakeup firmware unchanged
++ 1 -- Firmware wakeup through the interface command interrupt
++ -- (default setting for SDIO/GSPI)
++ 2 -- Firmware wakeup through the GPIO pin
++ -- (default setting for CF)
++
++ Usage:
++ iwpriv ethX fwwakeupmethod
++ Read the current firmware wakeup method setting
++ iwpriv ethX fwwakeupmethod 0
++ Leave the current method to wakeup firmware unchanged
++ iwpriv ethX fwwakeupmethod 1
++ Firmware wakeup through the interface command interrupt
++ iwpriv ethX fwwakeupmethod 2
++ Firmware wakeup through the GPIO pin
++
++txcontrol [DefaultFlags (if no UP setting)] [UserPriority] [UserPriorityFlags]
++ This command is used to set/get the TX rate, WMM ack policy, and
++ retry limit for all packets, or selectively the packets with a specific
++ user priority.
++
++ The DefaultFlags setting is ignored for any command with 2 or more
++ arguments.
++
++ The value of the u32 txcontrol flags returned and input for
++ DefaultFlags or UserPriorityFlags specific settings is given by the
++ following bitmap:
++
++ bit[4:0], if bit[4] == 1:
++ bit[3:0] -- 0 1 2 3 4 5 6 7 8 9 10 11 12 13-16
++ Data Rate(Mbps) -- 1 2 5.5 11 Rsv 6 9 12 18 24 36 48 54 Rsv
++
++ bit[12:8]
++ if bit[12] == 1, bit[11:8] specifies the Tx retry limit.
++
++ bit[14:13] specifies per packet ack policy:
++ if bit[14] == 1, bit[13] == 1 specifies No Ack Policy
++
++ All unused and reserved bits should be set to zero for the entire
++ u32 field.
++
++ Usage:
++ Number of arguments given:
++
++ 0: Return the default setting for the txcontrol flags
++ > iwpriv eth1 txcontrol
++
++ 1: Set the default value for the txcontrol flags
++ > iwpriv eth1 txcontrol 0x6013 - No ACK, 11Mbps
++ > iwpriv eth1 txcontrol 0x151A - 5 retries, 36Mbps
++
++ 2: Return a specific User Priority setting. If the UP setting is zero,
++ the default value will be used and returned:
++ > iwpriv eth1 txcontrol 0 7 - Return UP 7 txcontrol value (UP7 = VO)
++
++ 3: Set a User Priority specific value for the txcontrol flags. A value
++ of zero will revert to the default setting:
++ > iwpriv eth1 txcontrol 0 5 0x6013 - (UP5 = VI), No ACK 11Mbps.
++
++uapsdnullgen
++ This command is used to enable(1) UAPSD null package generation,
++ Disable(0) UAPSD null package generation, and request(2) the status
++ which null package generation is disabled/enabled,
++ for Ad-hoc creator.
++
++ where value is:
++ 0 -- Disable
++ 1 -- Enable
++ 2 -- Get
++
++psnullinterval
++ This command is used to set/request NULL package interval for Power Save
++ under infrastructure mode.
++
++ where value is:
++ -1 -- Disable
++ n>0 -- Set interval as n (seconds)
++
++getrxinfo
++ This command gets non average value of Signal to Noise Ratio of Data and rate index.
++
++ The following table shows RateIndex and Rate
++
++ RateIndex Data rate
++ 0 1 Mbps
++ 1 2 Mbps
++ 2 5.5 Mbps
++ 3 11 Mbps
++ 4 Reserved
++ 5 6 Mbps
++ 6 9 Mbps
++ 7 12 Mbps
++ 8 18 Mbps
++ 9 24 Mbps
++ 10 36 Mbps
++ 11 48 Mbps
++ 12 54 Mbps
++ 13-15 Reserved
++
++gettxrate
++ This command gets current Tx rate index of the first packet associated with Rate Adaptation.
++
++ The following table shows RateIndex and Rate
++
++ RateIndex Data rate
++ 0 1 Mbps
++ 1 2 Mbps
++ 2 5.5 Mbps
++ 3 11 Mbps
++ 4 Reserved
++ 5 6 Mbps
++ 6 9 Mbps
++ 7 12 Mbps
++ 8 18 Mbps
++ 9 24 Mbps
++ 10 36 Mbps
++ 11 48 Mbps
++ 12 54 Mbps
++ 13-15 Reserved
++
++bcninterval
++ This command is used to set beacon interval in adhoc mode when an argument is given,
++ return the value set by the user and the current adhoc beacon interval if adapter is in connected state.
++ The valid beacon interval is between 20 - 1000, default beacon interval is 100.
++
++ Usage:
++ iwpriv ethX bcninterval 100 (set adhoc beacon interval to 100)
++
++ not connected:
++ iwpriv ethX bcninterval (get adhoc beacon interval set by user)
++
++ connected:
++ iwpriv ethX bcninterval (get adhoc beacon interval set by user previously
++ and current beacon interval)
++
++setcoalescing
++ This command is used to disable/enable IBSS coalescing function, and get IBSS coalescing status.
++
++ where value is:
++ 0 -- Disable IBSS coalescing function
++ 1 -- Enable IBSS coalescing function
++ 2 -- Get current IBSS coalescing status
++
++bcnmisto
++ This command is used to set/get beacon miss timeout for Power Save
++ under infrastructure mode.
++
++ where value is:
++ 0xffff -- Disabled
++ 0 -- no change
++ 1--50 (miliseconds)
++
++adhocawakepd
++ This command is used to set/get adhoc awake period for Power Save Mode.
++
++ where value is:
++ 0xff -- firmware will go to sleep after send out beacon
++ 0--no change
++ 1--31 (beacon interval)
++
++sdiopullctrl
++ This command is used to set/get seting of pulling up and pulling down of SDIO lines,
++ The PullUp is the delay before pulling SDIO lines up. The PullDown is the
++ delay before pull SDIO lines down. the unit is us for both PullUp and PullDown.
++
++ where <m> PullUp
++ 0--no delay is needed
++ 0xffff--no pulling up is needed
++
++ <n> PullDown
++ 0--no delay is needed
++ 0xffff--no pulling up is needed
++
++ Usage:
++ iwpriv ethX sdiopullctrl
++ Read the currect firmware SDIO PullUp and PullDown settings
++ iwpriv ethX sdiopullctrl 5 5
++ Set SDIO PullUp/PullDown to 5 us
++ iwpriv ethX sdiopullctrl 0xffff 0xffff
++ Disable SDIO PullUp and PullDown
++
++scantime
++ This command is used to set/get scan time per channel in milliseconds.
++ The current setting will be returned every time.
++
++ Usage:
++ iwpriv ethX scantime [s] [a] [p]
++
++ where the parameters are,
++ [s]: specific SSID/BSSID scan time, default 100 ms, max 500 ms
++ [a]: active scan time, default 100 ms, max 500 ms
++ [p]: passive scan time, default 100 ms, max 2000 ms
++ No change if the parameter is 0 or the parameter is not provided.
++
++ For example:
++ iwpriv ethX scantime 30 (set specific scan time to 30 ms)
++ iwpriv ethX scantime 0 100 (set active scan time to 100 ms)
++ iwpriv ethX scantime 30 80 200 (set specific scan time to 30 ms,
++ set active scan time to 80 ms,
++ set passive scan time to 200 ms)
++
++ldocfg
++ This command is used to set/get internal/external core power voltage source.
++ By default firmware uses internal LDO for 1.2V core power supply.
++ The current setting will be returned if no parameter provided.
++
++ Usage:
++ iwpriv ethX ldocfg [n]
++
++ where the parameter is,
++ 0 -- internal
++ 1 -- external
++
++dataevtcfg
++ This command is used to set/get the subscription of low RSSI, low SNR, high RSSI and
++ high SNR events in data packet.
++
++ Where value <a> is:
++ Events bitmap
++ Bit
++ 0 RSSI_LOW RSSI_LOW event is generated when avg data RSSI is below threshold
++ 1 SNR_LOW SNR_LOW event is generated when avg data SNR is below threshold
++ 2 RSSI_HIGH RSSI_HIGH event is generated when avg data RSSI go above threshold
++ 3 SNR_HIGH SNR_HIGH event is generated when avg data SNR go above threshold
++
++ Where value <b> is:
++ RSSI_LOW threshold (Absolute value, the actual value should be negative)
++ Where value <c> is:
++ RSSI_LOW reporting frequency. if set to 0, event will only report once.
++ if set to 1, event will be reported every time it occur.
++ if set to N, event will be reported only when the condition happens N consecutive times.
++
++ Where value <d> is:
++ SNR_LOW threshold
++ Where value <e> is:
++ SNR_LOW reporting frequency. if set to 0, event will only report once.
++ if set to 1, event will be reported every time it occur.
++ if set to N, event will be reported only when the condition happens N consecutive times.
++
++ Where value <f> is:
++ RSSI_HIGH threshold (Absolute value, the actual value should be negative)
++ Where value <g> is:
++ RSSI_HIGH reporting frequency. if set to 0, event will only report once.
++ if set to 1, event will be reported every time it occur.
++ if set to N, event will be reported only when the condition happens N consecutive times.
++
++ Where value <h> is:
++ SNR_HIGH threshold
++ Where value <i> is:
++ SNR_HIGH reporting frequency. if set to 0, event will only report once.
++ if set to 1, event will be reported every time it occur.
++ if set to N, event will be reported only when the condition happens N consecutive times.
++
++ Usage:
++ iwpriv ethX dataevtcfg (get current data subscribe event settings)
++ iwpriv ethX dataevtcfg 15 70 1 56 0 40 5 86 0
++ (set current data subscribe event,
++ when avg data RSSI below -70, such as -80,
++ RSSI_LOW event will be generated every time;
++ when avg data RSSI above -40 happens 5 consecutive times,
++ such as -30,-32,-34,-29,-33, RSSI_HIGH event will be generated 1 times;
++ when avg data SNR below 56 or above 86,
++ SNR_LOW or SNR_HIGHT event will be generated once)
++
++sdiomode
++ This command is used to set/get sdio mode.
++ The setting will take effect when next command 53 is issued.
++
++ where the parameter <n> is,
++ 1 -- set sdio to 1 bit mode
++ 4 -- set sdio to 4 bit mode
++
++ Usage:
++ iwpriv ethX sdiomode (get current sdio mode)
++ iwpriv ethX sdiomode 1 (set to 1 bit mode)
++ iwpriv ethX sdiomode 4 (set to 4 bit mode)
++
++rtsctsctrl
++ This command is used to set/get the RTS/CTS or CTS To SELF for g rate protection to the firmware.
++ where the parameter <n> is,
++ 1 -- set RTS/CTS for g rate protection to the firmware.
++ 0 -- set CTS To SELF for g rate protection to the firmware.
++
++ Usage:
++ iwpriv ethX rtsctsctrl (gets the RTS/CTS or CTS To SELF)
++ iwpriv ethX rtsctsctrl 1 (set RTS/CTS for g rate protection to the firmware.)
++ iwpriv ethX rtsctsctrl 0 (set CTS To SELF for g rate protection to the firmware.)
++
++drvdbg
++ This command is used to set/get the bit masks of driver debug message control.
++
++ Usage:
++ iwpriv ethX drvdbg [n] [m]
++
++ Where the parameter <n> is the generic debug message control bit mask.
++ The following types of driver debug messages can be dynamically enabled or
++ disabled by setting or clearing the corresponding bits,
++ bit 0: MSG PRINTM(MSG,...)
++ bit 1: FATAL PRINTM(FATAL,...)
++ bit 2: ERROR PRINTM(ERROR,...)
++ bit 3: DATA PRINTM(DATA,...)
++ bit 4: CMND PRINTM(CMND,...)
++ bit 5: EVENT PRINTM(EVENT,...)
++ bit 6: INTR PRINTM(INTR,...)
++ ...
++ bit 16: DAT_D PRINTM(DAT_D,...), DBG_HEXDUMP(DAT_D,...)
++ bit 17: CMD_D PRINTM(CMD_D,...), DBG_HEXDUMP(CMD_D,...)
++ bit 18: FW_D PRINTM(FW_D,...)
++ ...
++ bit 28: ENTRY PRINTM(ENTRY,...), ENTER(), LEAVE()
++ bit 29: WARN PRINTM(WARN,...)
++ bit 30: INFO PRINTM(INFO,...)
++
++ Where the parameter <m> is the extended interface module debug message control
++ bit mask. The following types of debug messages can be controlled.
++
++ bit 0: IF_D PRINTM(IF_D,...), DBG_HEXDUMP(IF_D,...)
++
++ If CONFIG_DEBUG=2, all kinds of debug messages can be configured.
++ By default all debug messages are enabled except for EVENT and IF_D.
++
++ If CONFIG_DEBUG=1, all kinds of debug messages can be configured except
++ for ENTRY, WARN and INFO. By default MSG and FATAL are enabled.
++
++ Some special debug messages,
++ '*' // WLAN driver ISR is called (bit 6 INTR enabled)
++ '|' // PS awake event is received (bit 5 EVENT enabled)
++ '_' // PS sleep event is received (bit 5 EVENT enabled)
++ '+' // PS sleep confirm is sent (bit 5 EVENT enabled)
++
++ For example:
++ iwpriv ethX drvdbg (get the current driver debug masks)
++ iwpriv ethX drvdbg 0 0 (disable all the debug messages)
++ iwpriv ethX drvdbg 7 (enable MSG, FATAL and ERROR messages,
++ no change for if debug control)
++ iwpriv ethX drvdbg 3 1 (enable MSG and FATAL messages,
++ enable IF_D message)
++ iwpriv ethX drvdbg -1 -1 (enable all the debug messages)
++
++adhocgprot
++ This command is used to set/get 802.11g ad-hoc protection state.
++
++ where value is:
++ 0 -- Disable
++ 1 -- Enable
++ 2 -- Get
++ Usage:
++ iwpriv ethX adhocgprot 0 (disable 802.11g ad-hoc g protection)
++ iwpriv ethX adhocgprot 1 (enable 802.11g ad-hoc g protection)
++ iwpriv ethX adhocgprot 2 (get 802.11g ad-hoc g protection state)
++
++getrate
++ This command is used to get the supported rates. Returned rates are in 0.5M unit.
++
++associate <scan table index>
++ Associate to a specific BSS entry in the scan table. The enumeration
++ of the entries in the scan table is determined by the
++ getscantable API or from the iwlist scan results. A re-scan is not
++ performed before the association attempt is made.
++
++getdtim
++ This command is used to get the current DTIM value.
++ Note: This command is available only when STA is connected.
++
++
++===============================================================================
++
++ U S E R M A N U A L F O R W L A N _ C O N F I G
++
++NAME
++wlanconfig - configure the additional parameters available for the Marvell
++ WLAN Linux Driver.
++
++SYNOPSIS
++wlanconfig -v
++wlanconfig <ethX> <command> [parameters] ...
++
++wlanconfig ethX version
++wlanconfig ethX <rdmac|rdbbp|rdrf> <offset>
++wlanconfig ethX <wrmac|wrbbp|wrrf> <offset> <n>
++wlanconfig ethX sdcmd52r <FN no.> <address>
++wlanconfig ethX sdcmd52w <FN no.> <address> <data>
++wlanconfig ethX caldataext <filename>
++wlanconfig ethX rdeeprom <offset> <length>
++wlanconfig ethX sleepparams <config values>
++wlanconfig ethX bca-ts <config values>
++wlanconfig ethX extscan <ssid>
++wlanconfig ethX getscanlist
++
++Version 4 Command:
++wlanconfig ethX bgscanconfig <filename>
++
++Version 5 Command:
++wlanconfig ethX hostcmd <hostcmd.conf> <subevent_get>
++wlanconfig ethX hostcmd <hostcmd.conf> <subevent_set>
++
++Version 6 Command:
++wlanconfig ethX setuserscan [ARGS]
++wlanconfig ethX getscantable
++wlanconfig ethX getassocrsp
++
++Version 8
++wlanconfig ethX addts <filename.conf> <section# of tspec> <timeout in ms>
++wlanconfig ethX delts <filename.conf> <section# of tspec>
++wlanconfig ethX qconfig set msdu <lifetime in TUs> [Queue Id: 0-3]
++wlanconfig ethX qconfig get [Queue Id: 0-3]
++wlanconfig ethX qconfig def [Queue Id: 0-3]
++wlanconfig ethX qstats on [Queue Id: 0-3]
++wlanconfig ethX qstats off [Queue Id: 0-3]
++wlanconfig ethX qstats get [Queue Id: 0-3]
++wlanconfig ethX hostcmd <hostcmd.conf> <pa_cfg_ext_get>
++wlanconfig ethX hostcmd <hostcmd.conf> <pa_cfg_ext_set>
++wlanconfig ethX hostcmd <hostcmd.conf> <arp_filter>
++wlanconfig ethX hostcmd <hostcmd.conf> <auto_tx_get>
++wlanconfig ethX hostcmd <hostcmd.conf> <NatKeepAlive>
++wlanconfig ethX hostcmd <hostcmd.conf> <auto_tx_unreg>
++wlanconfig ethX hostcmd <hostcmd.conf> <ledctrl_get>
++wlanconfig ethX hstest
++wlanconfig ethX getcfptable [region]
++
++Version 9
++wlanconfig ethX gettsf
++wlanconfig ethX arpfilter <arpfilter.conf>
++wlanconfig ethX txpktstats
++
++DESCRIPTION
++
++those commands are used in Marvell specic applicaion called wlanconfig.
++
++===========
++-v
++ This command is used to display the version of wlanconfig utility.
++ Usage:
++ wlanconfig -v
++
++rdmac
++rdbbp
++rdrf
++ These commands are used to read the MAC, BBP and RF registers from the
++ card. These commands take one parameter that specifies the offset
++ location that is to be read. This parameter can be specified either in
++ decimal or in hexadecimal (by preceding the number with a "0x").
++
++ Usage:
++ wlanconfig ethX rdmac 0xa123
++ wlanconfig ethX rdbbp 0x0123
++ wlanconfig ethX rdrf 0x0123
++
++wrmac
++wrbbp
++wrrf
++ These commands are used to write the MAC, BBP and RF registers in the
++ card. These commands take two parameters that specify the offset
++ location and the value that is to be written. This parameters can be
++ specified either in decimal or in hexadecimal (by preceding the number
++ with a "0x").
++
++ Usage:
++ wlanconfig ethX wrmac 0xa123 0xaa
++ wlanconfig ethX wrbbp 0x0123 0xaa
++ wlanconfig ethX wrrf 0x0123 0xaa
++
++sdcmd52r
++ This command is used to read a controller register in
++ Secure Digital I/O Interfaces.
++
++ wlanconfig eth1 sdcmd52r <function number> <register address>
++
++ Usage:
++ wlanconfig eth1 sdcmd52r 0x00 0x07
++
++sdcmd52w
++ This command is used to write to a controller register in
++ Secure Digital I/O Interfaces.
++
++ wlanconfig eth1 sdcmd52w <function number> <register address> <value>
++
++ Usage:
++ wlanconfig eth1 sdcmd52w 0x00 0x02 0x0a
++
++caldataext
++ In order to overcome the situation without EEPROM in the WLAN module,
++ we send the extension calibration command to modify the existing
++ hardware-spec command. This command takes one parameter that specifies
++ the file name of the configuration file.
++
++ Usage:
++ wlanconfig eth1 caldataext <cal_data_ext_set_<version>.conf>
++ cal_data_ext_set_<version>.conf is a configuration file to the
++ wlanconfig to set the calibration values. The 3 existing
++ versions are v5, vA and v7.
++ Example:
++ wlanconfig eth1 caldataext cal_data_ext_set_v5.conf
++ Edit this file for changing calibration values.
++
++rdeeprom
++ To read the EEPROM contents of the card.
++
++ Usage:
++ wlanconfig ethX rdeeprom 0x00 0x10
++
++sleepparams
++ This command is used to set the sleepclock configurations
++
++ Usage:
++ wlanconfig ethX sleepparams get: reads the current sleepclock configuration
++
++ wlanconfig ethX sleepparams set p1 p2 p3 p4 p5 p6: writes the sleepclock configuration.
++
++ where:
++ p1 is Sleep clock error in ppm (0-65535)
++ p2 is Wakeup offset in usec (0-65535)
++ p3 is Clock stabilization time in usec (0-65535)
++ p4 is Control periodic calibration (0-2)
++ p5 is Control the use of external sleep clock (0-2)
++ p6 is reserved for debug (0-65535)
++
++bca-ts
++ This command is used to set/get the BCA timeshare parameters.
++
++ This command only works after BCA been enabled.
++
++ Usage:
++ wlanconfig ethX bca-ts <Traffic Type> <TimeShareInterval> <BTTime>
++
++ where:
++ Traffic Type 0 - Wlan and bluetooth are low priority.
++ 1 - Wlan and bluetooth are high priority.
++
++ TimeShareInterval value is not multiple of 10 then floor value
++ is taken and the valid range is < 20 ... 60,000 > in milliseconds.
++
++ BTTime value is not multiple of 10 then floor value is
++ taken and the valid range is < 0 ... TimeShareInterval value >
++ in milliseconds.
++
++ Example:
++ wlanconfig ethX bca-ts get 1
++ get the BCA timeshare settings when wlan and bluetooth are set to high priority.
++
++ wlanconfig ethX bca-ts set 1 30 20
++ set wlan and bluetooth to high priority, wlan TimeShareInterval to 30ms, BTTime to 20ms.
++
++
++bgscanconfig
++ This will configure the various parameters for background scan.
++
++ wlanconfig ethX bgscanconfig bg_scan_config.conf
++
++ bg_scan_config.conf is the configuration file to wlanconfig
++
++ Edit this file for changing bg scan values.
++
++hostcmd <hostcmd.conf> <subevent_get>
++hostcmd <hostcmd.conf> <subevent_set>
++ This command is used to set the configurations for
++ event descriptor interface command.
++ hostcmd.conf is a generic configuration file containing multiple configuration enties
++ for subscrive event API
++ subsvent_get: get subscribed event parameters
++ subsvent_set: set subscribed event parameters
++
++ Usage:
++ wlanconfig ethX hostcmd hostcmd.conf subevent_get
++ wlanconfig ethX hostcmd hostcmd.conf subevent_set
++
++extscan
++ This command is used to do a specific scan.
++
++ Usage: wlanconfig ethX extscan <SSID>
++
++ Example:
++ wlanconfig ethX extscan LINKSYS-AP
++
++ To see the results of use getscanlist command.
++
++getscanlist
++ This command is used to get the scan results.
++
++ Usage: wlanconfig ethX getscanlist
++
++ Example:
++ wlanconfig ethX getscanlist
++
++setuserscan
++ Initiate a customized scan and retrieve the results
++
++ Usage:
++ wlanconfig ethX setuserscan [ARGS]
++
++ where [ARGS]:
++
++ chan=[chan#][band][mode] where band is [a,b,g] and mode is
++ blank for active or 'p' for passive
++ bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan
++ ssid="[SSID]" specify a SSID filter for the scan
++ wc="[WILDCARD SSID]" specify a UNIX pattern matching filter (using *
++ and ?) for SSIDs found in a broadcast probe
++ keep=[0 or 1] keep the previous scan results (1), discard (0)
++ dur=[scan time] time to scan for each channel in milliseconds
++ probes=[#] number of probe requests to send on each chan
++ for each broadcast probe required and each SSID
++ specific probe required
++ type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any)
++
++ Any combination of the above arguments can be supplied on the command line.
++ If the chan token is absent, a full channel scan will be completed by
++ the driver. If the dur or probes tokens are absent, the driver default
++ setting will be used. The bssid and ssid fields, if blank,
++ will produce an unfiltered scan. The type field will default to 3 (Any)
++ and the keep field will default to 0 (Discard).
++
++ Examples:
++ 1) Perform an active scan on channels 1, 6, and 11 in the 'g' band:
++ setuserscan chan=1g,6g,11g
++
++ 2) Perform a passive scan on channel 11 for 20 ms:
++ setuserscan chan=11gp dur=20
++
++ 3) Perform an active scan on channels 1, 6, and 11; and a passive scan on
++ channel 36 in the 'a' band:
++ setuserscan chan=1g,6g,11g,36ap
++
++ 4) Perform an active scan on channel 6 and 36 for a specific SSID:
++ setuserscan chan=6g,36a ssid="TestAP"
++
++ 5) Scan all available channels (B/G, A bands) for a specific BSSID, keep
++ the current scan table intact, update existing or append new scan data:
++ setuserscan bssid=00:50:43:20:12:82 keep=1
++
++ 6) Scan channel 6, for all infrastructure networks, sending two probe
++ requests. Keep the previous scan table intact. Update any duplicate
++ BSSID/SSID matches with the new scan data:
++ setuserscan chan=6g type=1 probes=2 keep=1
++
++ 7) Scan channel 1 and 6, for all networks matching the Mrvl*AP
++ or AP*Mrvl? patterns and for MrvlTst SSID. Generate 3 broadcast
++ probes for the patterns and 3 SSID specific probes for MrvlTst on
++ both channel 1 and channel 6.
++ chan=1g,6g probes=3 wc="Mrvl*AP" wc="AP*Mrvl?" ssid="MrvlTst"
++
++ All entries in the scan table (not just the new scan data when keep=1)
++ will be displayed upon completion by use of the getscantable ioctl.
++
++getscantable
++ Display the current contents of the driver scan table
++
++ Usage:
++ wlanconfig ethX getscantable
++ wlanconfig ethX getscantable [#]
++ wlanconfig ethX getscantable tsf
++ wlanconfig ethX getscantable help
++
++ 1) Without argument, the entire scantable is displayed.
++ 2) Specifying a # will display detailed information about a specific scan
++ table entry. '0' displays driver cached information regarding the
++ current association (if any).
++ 3) The tsf argument will display the entire scan table with the recorded
++ TSF timestamp for the entry.
++ 4) The help argument will display the legend for the capability field
++
++getassocrsp
++ Display the contents of the driver association response buffer. The
++ driver buffer is cleared after the response is returned to prevent
++ state response buffer returns.
++
++ Usage:
++ wlanconfig ethX getassocrsp
++
++setmrvltlv
++ Setup a test Marvell TLV for the driver to insert in the next
++ association command to the firmware.
++
++ wlanconfig will provision a test TLV that can be verified in the assoc.
++ response to the AP. Used to test the IOCTL functionality.
++
++ Usage:
++ wlanconfig ethX setmrvltlv
++
++addts
++ Send an ADDTS command to the associated AP.
++
++ Process a given conf file for a specific TSPEC data block. Send the
++ TSPEC along with any other IEs to the driver/firmware for transmission
++ in an ADDTS request to the associated AP.
++
++ Return the execution status of the command as well as the ADDTS response
++ from the AP if any.
++
++ Usage:
++ wlanconfig ethX addts <filename.conf> <section# of tspec> <timeout(ms)>
++
++delts
++ Send a DELTS command to the associated AP.
++
++ Process a given conf file for a specific TSPEC data block. Send the
++ TSPEC along with any other IEs to the driver/firmware for transmission
++ in a DELTS request to the associated AP.
++
++ Return the execution status of the command. There is no response to a
++ DELTS from the AP.
++
++ Usage:
++ wlanconfig ethX delts <filename.conf> <section# of tspec>
++
++qconfig
++ Send a WMM AC Queue configuration command to get/set/default params
++
++ Configure or get the parameters of a WMM AC queue. The command takes
++ an optional Queue Id as a last parameter. Without the queue id, all
++ queues will be acted upon.
++
++ Usage:
++ wlanconfig ethX qconfig set msdu <lifetime in TUs> [Queue Id: 0-3]
++ wlanconfig ethX qconfig get [Queue Id: 0-3]
++ wlanconfig ethX qconfig def [Queue Id: 0-3]
++
++qstats
++ Turn on/off or retrieve and clear the queue statistics for an AC
++
++ Turn the queue statistics collection on/off for a given AC or retrieve the
++ current accumulated stats and clear them from the firmware. The command
++ takes an optional Queue Id as a last parameter. Without the queue id,
++ all queues will be acted upon.
++
++ Usage:
++ wlanconfig ethX qstats on [Queue Id: 0-3]
++ wlanconfig ethX qstats off [Queue Id: 0-3]
++ wlanconfig ethX qstats get [Queue Id: 0-3]
++
++hostcmd <hostcmd.conf> <pa_cfg_ext_get>
++hostcmd <hostcmd.conf> <pa_cfg_ext_set>
++ This configures the power adaptation paramemters
++
++ Usage:
++ wlanconfig ethX hostcmd hostcmd.conf pa_cfg_ext_get
++ wlanconfig ethX hostcmd hostcmd.conf pa_cfg_ext_set
++
++ hostcmd.conf is a generic configuration file containing multiple configuration enties
++ for power adapation
++ pa_cfg_ext_get: get pa_cfg_ext parameters
++ pa_cfg_ext_set: set pa_cfg_ext parameters
++
++ The following table shows the bitmap of the rates (bit 0 is the least significant bit):
++
++ Bit Data rate
++ 0 1 Mbps
++ 1 2 Mbps
++ 2 5.5 Mbps
++ 3 11 Mbps
++ 4 Reserved
++ 5 6 Mbps
++ 6 9 Mbps
++ 7 12 Mbps
++ 8 18 Mbps
++ 9 24 Mbps
++ 10 36 Mbps
++ 11 48 Mbps
++ 12 54 Mbps
++ 13-15 Reserved
++
++ Up to 5 power level groups are supported.
++
++ The default power adaptation groups:
++
++ Power Level Rate Bitmap (Mbps)
++ 13 dbm 0x1800 (54, 48)
++ 15 dbm 0x07e0 (36, 24, 18, 12, 9, 6)
++ 18 dbm 0x000f (11, 5.5, 2, 1)
++
++ Edit the hostcmd.conf file to change the settings
++
++hostcmd <hostcmd.conf> <arp_filter>
++ This is an extended host_sleep_cfg command to configure the ARP filtering parameters.
++
++ Usage:
++ wlanconfig ethX hostcmd hostcmd.conf arp_filter
++
++ Edit the arp_filter section in hostcmd.conf file to change the settings
++
++hostcmd <hostcmd.conf> <auto_tx_get>
++hostcmd <hostcmd.conf> <NatKeepAlive>
++hostcmd <hostcmd.conf> <auto_tx_unreg>
++ This configures the Frame Auto Transmission paramemters
++
++ Usage:
++ wlanconfig ethX hostcmd hostcmd.conf auto_tx_get
++ wlanconfig ethX hostcmd hostcmd.conf NatKeepAlive
++ wlanconfig ethX hostcmd hostcmd.conf auto_tx_unreg
++
++ hostcmd.conf is a generic configuration file containing multiple configuration enties
++ for Frame Auto Transmission
++ auto_tx_get: get auto_tx parameters
++ NatKeepAlive: register to firmware for sending NAT Keep Alive packet
++ auto_tx_unreg: unregister to firmware auto_tx
++
++ Edit the auto_tx section in hostcmd.conf file to change the settings
++
++hostcmd <hostcmd.conf> <ledctrl_get>
++ This command is used to set/get LED control.
++
++ Usage:
++ wlanconfig ethX hostcmd hostcmd.conf ledctrl_get
++ wlanconfig ethX hostcmd hostcmd.conf ledctrl_set
++
++ hostcmd.conf is a generic configuration file containing multiple configuration enties
++ for LED Ctrl
++ led_ctrl_get: get auto_tx parameters
++ led_ctrl_set: set auto_tx parameters
++
++ Edit the ledctrl section in hostcmd.conf file to change the settings
++
++hstest
++ This command runs in the background to handle GPIO/SDIO interrupt events
++ in HOST SLEEP mode.
++
++ Usage:
++ wlanconfig ethX hstest &
++
++getcfptable
++ This command is used to get Channel-Freq-MaxTxPower table based on the region code.
++ If no parameter provided, the CFP table for current region code will be returned.
++
++ Usage:
++ wlanconfig ethX getcfptable [region]
++
++gettsf
++ Display the current MAC TSF value.
++
++arpfilter <arpfilter.conf>
++ This command is used to configure the ARP filtering parameters.
++
++ Usage:
++ wlanconfig ethX arpfilter arpfilter.conf
++
++ Edit arpfilter.conf file to change the settings
++
++txpktstats
++ Retrieve and clear transmit packet statistics collected by the firmware:
++
++ The API displays the following statistics for each rate:
++ - Number of packets initially queued using the rate
++ - Number of total attempts for the packets queued using this initial
++ rate. This includes attempts at other rates in case of hardware or
++ single rate drop modes.
++ - Number of retry exhaustion failures for packets queued using this
++ initial rate.
++ - Number of MSDU lifetime expiry failures for packets queued using
++ this initial rate.
++ - Number of packets successfully completed at this rate
++
++==============================================================================
+diff --git a/drivers/net/wireless/marvell8686/host.h b/drivers/net/wireless/marvell8686/host.h
+new file mode 100644
+index 0000000..cf4562a
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/host.h
+@@ -0,0 +1,349 @@
++/** @file host.h
++ *
++ * @brief This file contains definitions of WLAN commands.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ */
++/********************************************************
++Change log:
++ 10/11/05: Add Doxygen format comments
++ 01/11/06: Remove assoc response codes; full IEEE assoc resp now returned
++ 04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
++ 04/10/06: Add power_adapt_cfg_ext command
++ 04/18/06: Remove old Subscrive Event and add new Subscribe Event
++ implementation through generic hostcmd API
++ 05/03/06: Add auto_tx hostcmd
++ 05/04/06: Add IBSS coalescing related new hostcmd and event
++ 08/28/06: Add LED_CTRL hostcmd
++********************************************************/
++
++#ifndef _HOST_H_
++#define _HOST_H_
++
++/** PUBLIC DEFINITIONS */
++#define DEFAULT_AD_HOC_CHANNEL 6
++#define DEFAULT_AD_HOC_CHANNEL_A 36
++/** The first valid channel for use */
++#define FIRST_VALID_CHANNEL 0xff
++
++/** IEEE 802.11 OIDs */
++#define OID_802_11_INFRASTRUCTURE_MODE 0x00008001
++#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008002
++#define OID_802_11_RTS_THRESHOLD 0x00008003
++#define OID_802_11_ADD_WEP 0x00008004
++#define OID_802_11_REMOVE_WEP 0x00008005
++#define OID_802_11_TX_RETRYCOUNT 0x00008006
++#define OID_802_11D_ENABLE 0x00008007
++#define OID_802_11_DTIM 0x00008009
++
++#define HostCmd_OPTION_WAITFORRSP 0x0002
++
++/** Host Command ID */
++#define HostCmd_CMD_GET_HW_SPEC 0x0003
++#define HostCmd_CMD_802_11_RESET 0x0005
++#define HostCmd_CMD_802_11_SCAN 0x0006
++#define HostCmd_CMD_802_11_GET_LOG 0x000b
++#define HostCmd_CMD_MAC_MULTICAST_ADR 0x0010
++#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059
++#define HostCmd_CMD_802_11_ASSOCIATE 0x0012
++#define HostCmd_CMD_802_11_SET_WEP 0x0013
++#define HostCmd_CMD_802_11_SNMP_MIB 0x0016
++#define HostCmd_CMD_MAC_REG_ACCESS 0x0019
++#define HostCmd_CMD_BBP_REG_ACCESS 0x001a
++#define HostCmd_CMD_RF_REG_ACCESS 0x001b
++#define HostCmd_CMD_802_11_RADIO_CONTROL 0x001c
++#define HostCmd_CMD_802_11_RF_CHANNEL 0x001d
++#define HostCmd_CMD_802_11_RF_TX_POWER 0x001e
++#define HostCmd_CMD_802_11_RSSI 0x001f
++#define HostCmd_CMD_802_11_RF_ANTENNA 0x0020
++
++#define HostCmd_CMD_802_11_PS_MODE 0x0021
++
++#define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024
++#define HostCmd_CMD_MAC_CONTROL 0x0028
++#define HostCmd_CMD_802_11_AD_HOC_START 0x002b
++#define HostCmd_CMD_802_11_AD_HOC_JOIN 0x002c
++
++#define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e
++
++#define HostCmd_CMD_802_11_DEEP_SLEEP 0x003e
++
++#define HostCmd_CMD_802_11_AD_HOC_STOP 0x0040
++
++#define HostCmd_CMD_802_11_HOST_SLEEP_CFG 0x0043
++#define HostCmd_CMD_802_11_WAKEUP_CONFIRM 0x0044
++#define HostCmd_CMD_802_11_HOST_SLEEP_ACTIVATE 0x0045
++
++#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D
++#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059
++
++#define HostCmd_CMD_802_11_BAND_CONFIG 0x0058
++
++#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b
++
++#define HostCmd_CMD_802_11_SLEEP_PARAMS 0x0066
++
++#define HostCmd_CMD_802_11_INACTIVITY_TIMEOUT 0x0067
++
++#define HostCmd_CMD_802_11_SLEEP_PERIOD 0x0068
++#define HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE 0x0069
++
++#define HostCmd_CMD_802_11_BG_SCAN_CONFIG 0x006b
++#define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c
++
++#define HostCmd_CMD_802_11_CAL_DATA_EXT 0x006d
++
++#define HostCmd_CMD_WMM_ADDTS_REQ 0x006E
++#define HostCmd_CMD_WMM_DELTS_REQ 0x006F
++#define HostCmd_CMD_WMM_QUEUE_CONFIG 0x0070
++#define HostCmd_CMD_WMM_GET_STATUS 0x0071
++
++#define HostCmd_CMD_802_11_TPC_CFG 0x0072
++
++#define HostCmd_CMD_802_11_FW_WAKE_METHOD 0x0074
++
++#define HostCmd_CMD_802_11_LED_CONTROL 0x004e
++
++#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075
++
++#define HostCmd_CMD_802_11_RATE_ADAPT_RATESET 0x0076
++
++#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f
++
++#define HostCmd_CMD_802_11_POWER_ADAPT_CFG_EXT 0x007e
++
++#define HostCmd_CMD_GET_TSF 0x0080
++
++#define HostCmd_CMD_WMM_QUEUE_STATS 0x0081
++
++#define HostCmd_CMD_802_11_AUTO_TX 0x0082
++#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
++
++#define HostCmd_CMD_MEM_ACCESS 0x0086
++
++#define HostCmd_CMD_SDIO_GPIO_INT_CONFIG (0x0088)
++
++#ifdef MFG_CMD_SUPPORT
++#define HostCmd_CMD_MFG_COMMAND 0x0089
++#define HostCmd_RET_MFG_COMMAND 0x8089
++#endif
++
++#define HostCmd_CMD_TX_PKT_STATS 0x008d
++
++#define HostCmd_CMD_SDIO_PULL_CTRL 0x0093
++
++#define HostCmd_CMD_802_11_LDO_CONFIG 0x0096
++
++#define HostCmd_CMD_VERSION_EXT 0x0097
++
++/* For the IEEE Power Save */
++#define HostCmd_SubCmd_Enter_PS 0x0030
++#define HostCmd_SubCmd_Exit_PS 0x0031
++#define HostCmd_SubCmd_Sleep_Confirmed 0x0034
++#define HostCmd_SubCmd_Full_PowerDown 0x0035
++#define HostCmd_SubCmd_Full_PowerUp 0x0036
++
++/* Command RET code, MSB is set to 1 */
++#define HostCmd_RET_HW_SPEC_INFO 0x8003
++#define HostCmd_RET_802_11_RESET 0x8005
++#define HostCmd_RET_802_11_SCAN 0x8006
++#define HostCmd_RET_802_11_GET_LOG 0x800b
++#define HostCmd_RET_MAC_CONTROL 0x8028
++#define HostCmd_RET_MAC_MULTICAST_ADR 0x8010
++#define HostCmd_RET_802_11_DEAUTHENTICATE 0x8024
++#define HostCmd_RET_802_11_ASSOCIATE 0x8012
++#define HostCmd_RET_802_11_SET_WEP 0x8013
++#define HostCmd_RET_802_3_STAT 0x8015
++#define HostCmd_RET_802_11_SNMP_MIB 0x8016
++#define HostCmd_RET_MAC_REG_ACCESS 0x8019
++#define HostCmd_RET_BBP_REG_ACCESS 0x801a
++#define HostCmd_RET_RF_REG_ACCESS 0x801b
++#define HostCmd_RET_802_11_RADIO_CONTROL 0x801c
++#define HostCmd_RET_802_11_RF_CHANNEL 0x801d
++#define HostCmd_RET_802_11_RSSI 0x801f
++#define HostCmd_RET_802_11_RF_TX_POWER 0x801e
++#define HostCmd_RET_802_11_RF_ANTENNA 0x8020
++#define HostCmd_RET_802_11_PS_MODE 0x8021
++
++#define HostCmd_RET_802_11_AD_HOC_START 0x802B
++#define HostCmd_RET_802_11_AD_HOC_JOIN 0x802C
++
++#define HostCmd_RET_802_11_KEY_MATERIAL 0x805e
++
++#define HostCmd_ACT_SET 0x0001
++#define HostCmd_ACT_GET 0x0000
++
++#define HostCmd_RET_802_11_AD_HOC_STOP 0x8040
++
++#define HostCmd_RET_802_11_HOST_SLEEP_CFG 0x8043
++#define HostCmd_RET_802_11_WAKEUP_CONFIRM 0x8044
++#define HostCmd_RET_802_11_HOST_SLEEP_ACTIVATE 0x8045
++
++#define HostCmd_RET_802_11_MAC_ADDRESS 0x804D
++#define HostCmd_RET_802_11_EEPROM_ACCESS 0x8059
++
++#define HostCmd_RET_802_11_BAND_CONFIG 0x8058
++
++#define HostCmd_RET_802_11_SLEEP_PARAMS 0x8066
++
++#define HostCmd_RET_802_11_INACTIVITY_TIMEOUT 0x8067
++
++#define HostCmd_RET_802_11_SLEEP_PERIOD 0x8068
++#define HostCmd_RET_802_11_BCA_CONFIG_TIMESHARE 0x8069
++
++#define HostCmd_RET_802_11D_DOMAIN_INFO 0x805B
++
++#define HostCmd_RET_802_11_BG_SCAN_CONFIG 0x806b
++#define HostCmd_RET_802_11_BG_SCAN_QUERY 0x806c
++
++#define HostCmd_RET_802_11_CAL_DATA_EXT 0x806d
++
++#define HostCmd_RET_WMM_ADDTS_REQ 0x806E
++#define HostCmd_RET_WMM_DELTS_REQ 0x806F
++#define HostCmd_RET_WMM_QUEUE_CONFIG 0x8070
++#define HostCmd_RET_WMM_GET_STATUS 0x8071
++
++#define HostCmd_RET_802_11_TPC_CFG 0x8072
++
++#define HostCmd_RET_802_11_LED_CONTROL 0x804e
++
++#define HostCmd_RET_802_11_FW_WAKE_METHOD 0x8074
++
++#define HostCmd_RET_802_11_SUBSCRIBE_EVENT 0x8075
++
++#define HostCmd_RET_802_11_RATE_ADAPT_RATESET 0x8076
++
++#define HostCmd_RTE_802_11_TX_RATE_QUERY 0x807f
++
++#define HostCmd_RET_GET_TSF 0x8080
++
++#define HostCmd_RET_WMM_QUEUE_STATS 0x8081
++
++#define HostCmd_RET_802_11_POWER_ADAPT_CFG_EXT 0x807e
++
++#define HostCmd_RET_802_11_AUTO_TX 0x8082
++
++#define HostCmd_RET_802_11_IBSS_COALESCING_STATUS 0x8083
++
++#define HostCmd_RET_MEM_ACCESS 0x8086
++
++#define HostCmd_RET_SDIO_GPIO_INT_CONFIG (0x8088)
++
++#define HostCmd_RET_TX_PKT_STATS 0x808d
++
++#define HostCmd_RET_SDIO_PULL_CTRL 0x8093
++
++#define HostCmd_RET_802_11_LDO_CONFIG 0x8096
++
++#define HostCmd_RET_VERSION_EXT 0x8097
++
++/** General Result Code*/
++/* OK */
++#define HostCmd_RESULT_OK 0x0000
++/* Genenral error */
++#define HostCmd_RESULT_ERROR 0x0001
++/* Command is not valid */
++#define HostCmd_RESULT_NOT_SUPPORT 0x0002
++/* Command is pending */
++#define HostCmd_RESULT_PENDING 0x0003
++/* System is busy (command ignored) */
++#define HostCmd_RESULT_BUSY 0x0004
++/* Data buffer is not big enough */
++#define HostCmd_RESULT_PARTIAL_DATA 0x0005
++
++/* Definition of action or option for each command */
++
++/* Define general purpose action */
++#define HostCmd_ACT_GEN_READ 0x0000
++#define HostCmd_ACT_GEN_WRITE 0x0001
++#define HostCmd_ACT_GEN_GET 0x0000
++#define HostCmd_ACT_GEN_SET 0x0001
++#define HostCmd_ACT_GEN_REMOVE 0x0002
++#define HostCmd_ACT_GEN_OFF 0x0000
++#define HostCmd_ACT_GEN_ON 0x0001
++
++/* Define action or option for HostCmd_CMD_802_11_SET_WEP */
++#define HostCmd_ACT_ADD 0x0002
++#define HostCmd_ACT_REMOVE 0x0004
++
++#define HostCmd_TYPE_WEP_40_BIT 0x0001
++#define HostCmd_TYPE_WEP_104_BIT 0x0002
++
++#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff
++
++/* Define action or option for HostCmd_CMD_802_11_SCAN */
++#define HostCmd_BSS_TYPE_BSS 0x0001
++#define HostCmd_BSS_TYPE_IBSS 0x0002
++#define HostCmd_BSS_TYPE_ANY 0x0003
++
++/* Define action or option for HostCmd_CMD_802_11_SCAN */
++#define HostCmd_SCAN_TYPE_ACTIVE 0x0000
++#define HostCmd_SCAN_TYPE_PASSIVE 0x0001
++
++/* Radio type definitions for the channel TLV */
++#define HostCmd_SCAN_RADIO_TYPE_BG 0
++#define HostCmd_SCAN_RADIO_TYPE_A 1
++
++/* Define action or option for HostCmd_CMD_MAC_CONTROL */
++#define HostCmd_ACT_MAC_RX_ON 0x0001
++#define HostCmd_ACT_MAC_TX_ON 0x0002
++#define HostCmd_ACT_MAC_LOOPBACK_ON 0x0004
++#define HostCmd_ACT_MAC_WEP_ENABLE 0x0008
++#define HostCmd_ACT_MAC_ETHERNETII_ENABLE 0x0010
++#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
++#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
++#define HostCmd_ACT_MAC_RTS_CTS_ENABLE 0x0200
++#define HostCmd_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
++#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON 0x2000
++
++/* Define action or option or constant for HostCmd_CMD_MAC_MULTICAST_ADR */
++#define HostCmd_SIZE_MAC_ADR 6
++#define HostCmd_MAX_MCAST_ADRS 32
++
++#define RADIO_ON 0x01
++#define RADIO_OFF 0x00
++
++/* Define action or option for CMD_802_11_RF_CHANNEL */
++#define HostCmd_OPT_802_11_RF_CHANNEL_GET 0x00
++#define HostCmd_OPT_802_11_RF_CHANNEL_SET 0x01
++
++#define HostCmd_ACT_SET_RX 0x0001
++#define HostCmd_ACT_SET_TX 0x0002
++#define HostCmd_ACT_SET_BOTH 0x0003
++#define HostCmd_ACT_GET_RX 0x0004
++#define HostCmd_ACT_GET_TX 0x0008
++#define HostCmd_ACT_GET_BOTH 0x000c
++
++/** Card Event definition */
++#define MACREG_INT_CODE_DUMMY_HOST_WAKEUP_SIGNAL 0x00000001
++#define MACREG_INT_CODE_LINK_LOST_WITH_SCAN 0x00000002
++#define MACREG_INT_CODE_LINK_LOST 0x00000003
++#define MACREG_INT_CODE_LINK_SENSED 0x00000004
++#define MACREG_INT_CODE_MIB_CHANGED 0x00000006
++#define MACREG_INT_CODE_INIT_DONE 0x00000007
++#define MACREG_INT_CODE_DEAUTHENTICATED 0x00000008
++#define MACREG_INT_CODE_DISASSOCIATED 0x00000009
++#define MACREG_INT_CODE_PS_AWAKE 0x0000000a
++#define MACREG_INT_CODE_PS_SLEEP 0x0000000b
++#define MACREG_INT_CODE_MIC_ERR_MULTICAST 0x0000000d
++#define MACREG_INT_CODE_MIC_ERR_UNICAST 0x0000000e
++#define MACREG_INT_CODE_WM_AWAKE 0x0000000f
++#define MACREG_INT_CODE_DEEP_SLEEP_AWAKE 0x00000010
++#define MACREG_INT_CODE_ADHOC_BCN_LOST 0x00000011
++#define MACREG_INT_CODE_HOST_SLEEP_AWAKE 0x00000012
++#define MACREG_INT_CODE_WMM_STATUS_CHANGE 0x00000017
++#define MACREG_INT_CODE_BG_SCAN_REPORT 0x00000018
++#define MACREG_INT_CODE_RSSI_LOW 0x00000019
++#define MACREG_INT_CODE_SNR_LOW 0x0000001a
++#define MACREG_INT_CODE_MAX_FAIL 0x0000001b
++#define MACREG_INT_CODE_RSSI_HIGH 0x0000001c
++#define MACREG_INT_CODE_SNR_HIGH 0x0000001d
++#define MACREG_INT_CODE_IBSS_COALESCED 0x0000001e
++#define MACREG_INT_CODE_PRE_BEACON_LOST 0x00000031
++
++/* Define bitmap conditions for HOST_SLEEP_CFG */
++#define HOST_SLEEP_CFG_CANCEL 0xffffffff
++#define HOST_SLEEP_CFG_WAKEUP_THRU_INTERFACE 0xff
++#define HOST_SLEEP_CFG_GAP_FF 0xff
++
++#endif /* _HOST_H_ */
+diff --git a/drivers/net/wireless/marvell8686/hostcmd.h b/drivers/net/wireless/marvell8686/hostcmd.h
+new file mode 100644
+index 0000000..9f189bb
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/hostcmd.h
+@@ -0,0 +1,1052 @@
++/** @file hostcmd.h
++ *
++ * @brief This file contains the function prototypes, data structure
++ * and defines for all the host/station commands
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ */
++/********************************************************
++Change log:
++ 10/11/05: Add Doxygen format comments
++ 01/11/06: Update association struct to reflect IEEE passthrough response
++ Conditionalize new scan/join structures
++ 04/10/06: Add hostcmd generic API and power_adapt_cfg_ext command
++ 04/18/06: Remove old Subscrive Event and add new Subscribe Event
++ implementation through generic hostcmd API
++ 05/03/06: Add auto_tx hostcmd
++ 05/04/06: Add IBSS coalescing related new hostcmd
++ 08/28/06: Add LED_CTRL hostcmd
++ 08/29/06: Add ledgpio private command
++********************************************************/
++
++#ifndef __HOSTCMD__H
++#define __HOSTCMD__H
++
++/* 802.11-related definitions */
++
++/** TxPD descriptor */
++typedef struct _TxPD
++{
++ /** Current Tx packet status */
++ u32 TxStatus;
++ /** Tx Control */
++ u32 TxControl;
++ u32 TxPacketLocation;
++ /** Tx packet length */
++ u16 TxPacketLength;
++ /**Destination MAC address */
++ u8 TxDestAddr[MRVDRV_ETH_ADDR_LEN];
++ /** Pkt Priority */
++ u8 Priority;
++ /** Trasnit Pkt Flags*/
++ u8 Flags;
++ /** Amount of time the packet has been queued in the driver (units = 2ms)*/
++ u8 PktDelay_2ms;
++ /** Reserved */
++ u8 Reserved1;
++
++} __ATTRIB_PACK__ TxPD, *PTxPD;
++
++/** RxPD Descriptor */
++typedef struct _RxPD
++{
++ /** Current Rx packet status */
++ u16 RxStatus;
++
++ /** SNR */
++ u8 SNR;
++
++ /** Tx Control */
++ u8 RxControl;
++
++ /** Pkt Length */
++ u16 PktLen;
++
++ /** Noise Floor */
++ u8 NF;
++
++ /** Rx Packet Rate */
++ u8 RxRate;
++
++ /** Pkt offset */
++ u32 PktOffset;
++ u8 RxPacketType;
++ u8 Reserved_1[3];
++ /** Pkt Priority */
++ u8 Priority;
++ u8 Reserved[3];
++
++} __ATTRIB_PACK__ RxPD, *PRxPD;
++
++#if defined(__KERNEL__)
++
++/** CmdCtrlNode */
++typedef struct _CmdCtrlNode
++{
++ /* CMD link list */
++ struct list_head list;
++
++ u32 Status;
++
++ /* CMD ID */
++ WLAN_OID cmd_oid;
++
++ /*CMD wait option: wait for finish or no wait */
++ u16 wait_option;
++
++ /* command parameter */
++ void *pdata_buf;
++
++ /*command data */
++ u8 *BufVirtualAddr;
++
++ u16 CmdFlags;
++
++ /* wait queue */
++ u16 CmdWaitQWoken;
++ wait_queue_head_t cmdwait_q __ATTRIB_ALIGN__;
++} __ATTRIB_PACK__ CmdCtrlNode, *PCmdCtrlNode;
++
++#endif
++
++/** MRVL_WEP_KEY */
++typedef struct _MRVL_WEP_KEY
++{
++ u32 Length;
++ u32 KeyIndex;
++ u32 KeyLength;
++ u8 KeyMaterial[MRVL_KEY_BUFFER_SIZE_IN_BYTE];
++} __ATTRIB_PACK__ MRVL_WEP_KEY, *PMRVL_WEP_KEY;
++
++typedef ULONGLONG WLAN_802_11_KEY_RSC;
++
++/** WLAN_802_11_KEY */
++typedef struct _WLAN_802_11_KEY
++{
++ u32 Length;
++ u32 KeyIndex;
++ u32 KeyLength;
++ WLAN_802_11_MAC_ADDRESS BSSID;
++ WLAN_802_11_KEY_RSC KeyRSC;
++ u8 KeyMaterial[MRVL_MAX_KEY_WPA_KEY_LENGTH];
++} __ATTRIB_PACK__ WLAN_802_11_KEY;
++
++/** MRVL_WPA_KEY */
++typedef struct _MRVL_WPA_KEY
++{
++ u32 KeyIndex;
++ u32 KeyLength;
++ u32 KeyRSC;
++ u8 KeyMaterial[MRVL_MAX_KEY_WPA_KEY_LENGTH];
++} MRVL_WPA_KEY, *PMRVL_WPA_KEY;
++
++/** MRVL_WLAN_WPA_KEY */
++typedef struct _MRVL_WLAN_WPA_KEY
++{
++ u8 EncryptionKey[16];
++ u8 MICKey1[8];
++ u8 MICKey2[8];
++} MRVL_WLAN_WPA_KEY, *PMRVL_WLAN_WPA_KEY;
++
++/* Received Signal Strength Indication in dBm*/
++typedef LONG WLAN_802_11_RSSI;
++
++/** WLAN_802_11_WEP */
++typedef struct _WLAN_802_11_WEP
++{
++ /* Length of this structure */
++ u32 Length;
++
++ /* 0 is the per-client key, 1-N are the global keys */
++ u32 KeyIndex;
++
++ /* length of key in bytes */
++ u32 KeyLength;
++
++ /* variable length depending on above field */
++ u8 KeyMaterial[1];
++} __ATTRIB_PACK__ WLAN_802_11_WEP;
++
++/** WLAN_802_11_SSID */
++typedef struct _WLAN_802_11_SSID
++{
++ /* SSID Length */
++ u32 SsidLength;
++
++ /* SSID information field */
++ u8 Ssid[WLAN_MAX_SSID_LENGTH];
++} __ATTRIB_PACK__ WLAN_802_11_SSID;
++
++typedef u32 WLAN_802_11_FRAGMENTATION_THRESHOLD;
++typedef u32 WLAN_802_11_RTS_THRESHOLD;
++typedef u32 WLAN_802_11_ANTENNA;
++
++/** wlan_offset_value */
++typedef struct _wlan_offset_value
++{
++ u32 offset;
++ u32 value;
++} wlan_offset_value;
++
++/** WLAN_802_11_FIXED_IEs */
++typedef struct _WLAN_802_11_FIXED_IEs
++{
++ u8 Timestamp[8];
++ u16 BeaconInterval;
++ u16 Capabilities;
++} WLAN_802_11_FIXED_IEs;
++
++/** WLAN_802_11_VARIABLE_IEs */
++typedef struct _WLAN_802_11_VARIABLE_IEs
++{
++ u8 ElementID;
++ u8 Length;
++ u8 data[1];
++} WLAN_802_11_VARIABLE_IEs;
++
++/** WLAN_802_11_AI_RESFI */
++typedef struct _WLAN_802_11_AI_RESFI
++{
++ u16 Capabilities;
++ u16 StatusCode;
++ u16 AssociationId;
++} WLAN_802_11_AI_RESFI;
++
++/** WLAN_802_11_AI_REQFI */
++typedef struct _WLAN_802_11_AI_REQFI
++{
++ u16 Capabilities;
++ u16 ListenInterval;
++ WLAN_802_11_MAC_ADDRESS CurrentAPAddress;
++} WLAN_802_11_AI_REQFI;
++
++/* Define general data structure */
++/** HostCmd_DS_GEN */
++typedef struct _HostCmd_DS_GEN
++{
++ u16 Command;
++ u16 Size;
++ u16 SeqNum;
++ u16 Result;
++} __ATTRIB_PACK__ HostCmd_DS_GEN, HostCmd_DS_802_11_DEEP_SLEEP;
++
++#define S_DS_GEN sizeof(HostCmd_DS_GEN)
++/*
++ * Define data structure for HostCmd_CMD_GET_HW_SPEC
++ * This structure defines the response for the GET_HW_SPEC command
++ */
++/** HostCmd_DS_GET_HW_SPEC */
++typedef struct _HostCmd_DS_GET_HW_SPEC
++{
++ /* HW Interface version number */
++ u16 HWIfVersion;
++
++ /* HW version number */
++ u16 Version;
++
++ /* Max number of TxPD FW can handle */
++ u16 NumOfTxPD;
++
++ /* Max no of Multicast address */
++ u16 NumOfMCastAdr;
++
++ /* MAC address */
++ u8 PermanentAddr[6];
++
++ /* Region Code */
++ u16 RegionCode;
++
++ /* Number of antenna used */
++ u16 NumberOfAntenna;
++
++ /* FW release number, example 0x1234=1.2.3.4 */
++ u32 FWReleaseNumber;
++
++ u32 Reserved_1;
++
++ u32 Reserved_2;
++
++ u32 Reserved_3;
++
++ /*FW/HW Capability */
++ u32 fwCapInfo;
++} __ATTRIB_PACK__ HostCmd_DS_GET_HW_SPEC;
++
++typedef struct _HostCmd_DS_802_11_SUBSCRIBE_EVENT
++{
++ u16 Action;
++ u16 Events;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_SUBSCRIBE_EVENT;
++
++/*
++ * This scan handle Country Information IE(802.11d compliant)
++ * Define data structure for HostCmd_CMD_802_11_SCAN
++ */
++/** HostCmd_DS_802_11_SCAN */
++typedef struct _HostCmd_DS_802_11_SCAN
++{
++ u8 BSSType;
++ u8 BSSID[ETH_ALEN];
++ u8 TlvBuffer[1];
++ /* MrvlIEtypes_SsIdParamSet_t SsIdParamSet;
++ * MrvlIEtypes_ChanListParamSet_t ChanListParamSet;
++ * MrvlIEtypes_RatesParamSet_t OpRateSet;
++ * */
++} __ATTRIB_PACK__ HostCmd_DS_802_11_SCAN;
++
++typedef struct _HostCmd_DS_802_11_SCAN_RSP
++{
++ u16 BSSDescriptSize;
++ u8 NumberOfSets;
++ u8 BssDescAndTlvBuffer[1];
++
++} __ATTRIB_PACK__ HostCmd_DS_802_11_SCAN_RSP;
++
++/** HostCmd_CMD_802_11_GET_LOG */
++typedef struct _HostCmd_DS_802_11_GET_LOG
++{
++ u32 mcasttxframe;
++ u32 failed;
++ u32 retry;
++ u32 multiretry;
++ u32 framedup;
++ u32 rtssuccess;
++ u32 rtsfailure;
++ u32 ackfailure;
++ u32 rxfrag;
++ u32 mcastrxframe;
++ u32 fcserror;
++ u32 txframe;
++ u32 reserved;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_GET_LOG;
++
++/** HostCmd_CMD_MAC_CONTROL */
++typedef struct _HostCmd_DS_MAC_CONTROL
++{
++ u16 Action;
++ u16 Reserved;
++} __ATTRIB_PACK__ HostCmd_DS_MAC_CONTROL;
++
++/** HostCmd_CMD_MAC_MULTICAST_ADR */
++typedef struct _HostCmd_DS_MAC_MULTICAST_ADR
++{
++ u16 Action;
++ u16 NumOfAdrs;
++ u8 MACList[MRVDRV_ETH_ADDR_LEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
++} __ATTRIB_PACK__ HostCmd_DS_MAC_MULTICAST_ADR;
++
++/** HostCmd_CMD_802_11_DEAUTHENTICATE */
++typedef struct _HostCmd_DS_802_11_DEAUTHENTICATE
++{
++ u8 MacAddr[6];
++ u16 ReasonCode;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_DEAUTHENTICATE;
++
++/** HostCmd_DS_802_11_ASSOCIATE */
++typedef struct _HostCmd_DS_802_11_ASSOCIATE
++{
++ u8 PeerStaAddr[6];
++ IEEEtypes_CapInfo_t CapInfo;
++ u16 ListenInterval;
++ u8 Reserved1[3];
++
++ /*
++ * MrvlIEtypes_SsIdParamSet_t SsIdParamSet;
++ * MrvlIEtypes_PhyParamSet_t PhyParamSet;
++ * MrvlIEtypes_SsParamSet_t SsParamSet;
++ * MrvlIEtypes_RatesParamSet_t RatesParamSet;
++ */
++} __ATTRIB_PACK__ HostCmd_DS_802_11_ASSOCIATE;
++
++/** HostCmd_RET_802_11_ASSOCIATE */
++typedef struct
++{
++ IEEEtypes_AssocRsp_t assocRsp;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_ASSOCIATE_RSP;
++
++/** HostCmd_RET_802_11_AD_HOC_JOIN */
++typedef struct _HostCmd_DS_802_11_AD_HOC_RESULT
++{
++ u8 PAD[3];
++ u8 BSSID[MRVDRV_ETH_ADDR_LEN];
++} __ATTRIB_PACK__ HostCmd_DS_802_11_AD_HOC_RESULT;
++
++/** HostCmd_CMD_802_11_SET_WEP */
++typedef struct _HostCmd_DS_802_11_SET_WEP
++{
++ /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
++ u16 Action;
++
++ /* Key Index selected for Tx */
++ u16 KeyIndex;
++
++ /* 40, 128bit or TXWEP */
++ u8 WEPTypeForKey1;
++
++ u8 WEPTypeForKey2;
++ u8 WEPTypeForKey3;
++ u8 WEPTypeForKey4;
++ u8 WEP1[16];
++ u8 WEP2[16];
++ u8 WEP3[16];
++ u8 WEP4[16];
++} __ATTRIB_PACK__ HostCmd_DS_802_11_SET_WEP;
++
++/** HostCmd_DS_802_11_AD_HOC_STOP */
++typedef struct _HostCmd_DS_802_11_AD_HOC_STOP
++{
++
++} __ATTRIB_PACK__ HostCmd_DS_802_11_AD_HOC_STOP;
++
++/** HostCmd_CMD_802_11_SNMP_MIB */
++typedef struct _HostCmd_DS_802_11_SNMP_MIB
++{
++ u16 QueryType;
++ u16 OID;
++ u16 BufSize;
++ u8 Value[128];
++} __ATTRIB_PACK__ HostCmd_DS_802_11_SNMP_MIB;
++
++/** HostCmd_CMD_MAC_REG_ACCESS */
++typedef struct _HostCmd_DS_MAC_REG_ACCESS
++{
++ u16 Action;
++ u16 Offset;
++ u32 Value;
++} __ATTRIB_PACK__ HostCmd_DS_MAC_REG_ACCESS;
++
++/** HostCmd_CMD_BBP_REG_ACCESS */
++typedef struct _HostCmd_DS_BBP_REG_ACCESS
++{
++ u16 Action;
++ u16 Offset;
++ u8 Value;
++ u8 Reserved[3];
++} __ATTRIB_PACK__ HostCmd_DS_BBP_REG_ACCESS;
++
++/** HostCmd_CMD_RF_REG_ACCESS */
++typedef struct _HostCmd_DS_RF_REG_ACCESS
++{
++ u16 Action;
++ u16 Offset;
++ u8 Value;
++ u8 Reserved[3];
++} __ATTRIB_PACK__ HostCmd_DS_RF_REG_ACCESS;
++
++/** HostCmd_CMD_802_11_RADIO_CONTROL */
++typedef struct _HostCmd_DS_802_11_RADIO_CONTROL
++{
++ u16 Action;
++ u16 Control;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_RADIO_CONTROL;
++
++/* HostCmd_DS_802_11_SLEEP_PARAMS */
++typedef struct _HostCmd_DS_802_11_SLEEP_PARAMS
++{
++ /* ACT_GET/ACT_SET */
++ u16 Action;
++
++ /* Sleep clock error in ppm */
++ u16 Error;
++
++ /* Wakeup offset in usec */
++ u16 Offset;
++
++ /* Clock stabilization time in usec */
++ u16 StableTime;
++
++ /* Control periodic calibration */
++ u8 CalControl;
++
++ /* Control the use of external sleep clock */
++ u8 ExternalSleepClk;
++
++ /* Reserved field, should be set to zero */
++ u16 Reserved;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_SLEEP_PARAMS;
++
++/* HostCmd_DS_802_11_SLEEP_PERIOD */
++typedef struct _HostCmd_DS_802_11_SLEEP_PERIOD
++{
++ /* ACT_GET/ACT_SET */
++ u16 Action;
++
++ /* Sleep Period in msec */
++ u16 Period;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_SLEEP_PERIOD;
++
++/* HostCmd_DS_802_11_BCA_TIMESHARE */
++typedef struct _HostCmd_DS_802_11_BCA_TIMESHARE
++{
++ /* ACT_GET/ACT_SET */
++ u16 Action;
++
++ /* Type: WLAN, BT */
++ u16 TrafficType;
++
++ /* 20msec - 60000msec */
++ u32 TimeShareInterval;
++
++ /* PTA arbiter time in msec */
++ u32 BTTime;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_BCA_TIMESHARE;
++
++/* HostCmd_DS_802_11_INACTIVITY_TIMEOUT */
++typedef struct _HostCmd_DS_802_11_INACTIVITY_TIMEOUT
++{
++ /* ACT_GET/ACT_SET */
++ u16 Action;
++
++ /* Inactivity timeout in msec */
++ u16 Timeout;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_INACTIVITY_TIMEOUT;
++
++/** HostCmd_CMD_802_11_RF_CHANNEL */
++typedef struct _HostCmd_DS_802_11_RF_CHANNEL
++{
++ u16 Action;
++ u16 CurrentChannel;
++ u16 RFType;
++ u16 Reserved;
++ u8 ChannelList[32];
++} __ATTRIB_PACK__ HostCmd_DS_802_11_RF_CHANNEL;
++
++/** HostCmd_CMD_802_11_RSSI */
++typedef struct _HostCmd_DS_802_11_RSSI
++{
++ /* weighting factor */
++ u16 N;
++
++ u16 Reserved_0;
++ u16 Reserved_1;
++ u16 Reserved_2;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_RSSI;
++
++/** HostCmd_DS_802_11_RSSI_RSP */
++typedef struct _HostCmd_DS_802_11_RSSI_RSP
++{
++ u16 SNR;
++ u16 NoiseFloor;
++ u16 AvgSNR;
++ u16 AvgNoiseFloor;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_RSSI_RSP;
++
++/** HostCmd_DS_802_11_MAC_ADDRESS */
++typedef struct _HostCmd_DS_802_11_MAC_ADDRESS
++{
++ u16 Action;
++ u8 MacAdd[ETH_ALEN];
++} __ATTRIB_PACK__ HostCmd_DS_802_11_MAC_ADDRESS;
++
++/** HostCmd_CMD_802_11_RF_TX_POWER */
++typedef struct _HostCmd_DS_802_11_RF_TX_POWER
++{
++ u16 Action;
++ u16 CurrentLevel;
++ u8 MaxPower;
++ u8 MinPower;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_RF_TX_POWER;
++
++/** HostCmd_CMD_802_11_RF_ANTENNA */
++typedef struct _HostCmd_DS_802_11_RF_ANTENNA
++{
++ u16 Action;
++
++ /* Number of antennas or 0xffff(diversity) */
++ u16 AntennaMode;
++
++} __ATTRIB_PACK__ HostCmd_DS_802_11_RF_ANTENNA;
++
++/** HostCmd_CMD_802_11_PS_MODE */
++typedef struct _HostCmd_DS_802_11_PS_MODE
++{
++ u16 Action;
++ u16 NullPktInterval;
++ u16 MultipleDtim;
++ u16 BCNMissTimeOut;
++ u16 LocalListenInterval;
++ u16 AdhocAwakePeriod;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_PS_MODE;
++
++/** PS_CMD_ConfirmSleep */
++typedef struct _PS_CMD_ConfirmSleep
++{
++ u16 Command;
++ u16 Size;
++ u16 SeqNum;
++ u16 Result;
++
++ u16 Action;
++ u16 Reserved1;
++ u16 MultipleDtim;
++ u16 Reserved;
++ u16 LocalListenInterval;
++} __ATTRIB_PACK__ PS_CMD_ConfirmSleep, *PPS_CMD_ConfirmSleep;
++
++/** HostCmd_CMD_802_11_FW_WAKE_METHOD */
++typedef struct _HostCmd_DS_802_11_FW_WAKEUP_METHOD
++{
++ u16 Action;
++ u16 Method;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_FW_WAKEUP_METHOD;
++
++/** HostCmd_DS_802_11_RATE_ADAPT_RATESET */
++typedef struct _HostCmd_DS_802_11_RATE_ADAPT_RATESET
++{
++ u16 Action;
++ u16 HWRateDropMode;
++ u16 Bitmap;
++ u16 Threshold;
++ u16 FinalRate;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_RATE_ADAPT_RATESET;
++
++/** HostCmd_DS_802_11_AD_HOC_START*/
++typedef struct _HostCmd_DS_802_11_AD_HOC_START
++{
++ u8 SSID[MRVDRV_MAX_SSID_LENGTH];
++ u8 BSSType;
++ u16 BeaconPeriod;
++ u8 DTIMPeriod;
++ IEEEtypes_SsParamSet_t SsParamSet;
++ IEEEtypes_PhyParamSet_t PhyParamSet;
++ u16 Reserved1;
++ IEEEtypes_CapInfo_t Cap;
++ u8 DataRate[HOSTCMD_SUPPORTED_RATES];
++} __ATTRIB_PACK__ HostCmd_DS_802_11_AD_HOC_START;
++
++/** AdHoc_BssDesc_t */
++typedef struct _AdHoc_BssDesc_t
++{
++ u8 BSSID[6];
++ u8 SSID[32];
++ u8 BSSType;
++ u16 BeaconPeriod;
++ u8 DTIMPeriod;
++ u8 TimeStamp[8];
++ u8 LocalTime[8];
++ IEEEtypes_PhyParamSet_t PhyParamSet;
++ IEEEtypes_SsParamSet_t SsParamSet;
++ IEEEtypes_CapInfo_t Cap;
++ u8 DataRates[HOSTCMD_SUPPORTED_RATES];
++
++ /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
++ * Adhoc join command and will cause a binary layout mismatch with
++ * the firmware
++ */
++} __ATTRIB_PACK__ AdHoc_BssDesc_t;
++
++/** HostCmd_DS_802_11_AD_HOC_JOIN */
++typedef struct _HostCmd_DS_802_11_AD_HOC_JOIN
++{
++ AdHoc_BssDesc_t BssDescriptor;
++ u16 Reserved1;
++ u16 Reserved2;
++
++} __ATTRIB_PACK__ HostCmd_DS_802_11_AD_HOC_JOIN;
++
++typedef union _KeyInfo_WEP_t
++{
++ u8 Reserved;
++
++ /* bits 1-4: Specifies the index of key */
++ u8 WepKeyIndex;
++
++ /* bit 0: Specifies that this key is
++ * to be used as the default for TX data packets
++ * */
++ u8 isWepDefaultKey;
++} __ATTRIB_PACK__ KeyInfo_WEP_t;
++
++typedef union _KeyInfo_TKIP_t
++{
++ u8 Reserved;
++
++ /* bit 2: Specifies that this key is
++ * enabled and valid to use */
++ u8 isKeyEnabled;
++
++ /* bit 1: Specifies that this key is
++ * to be used as the unicast key */
++ u8 isUnicastKey;
++
++ /* bit 0: Specifies that this key is
++ * to be used as the multicast key */
++ u8 isMulticastKey;
++} __ATTRIB_PACK__ KeyInfo_TKIP_t;
++
++typedef union _KeyInfo_AES_t
++{
++ u8 Reserved;
++
++ /* bit 2: Specifies that this key is
++ * enabled and valid to use */
++ u8 isKeyEnabled;
++
++ /* bit 1: Specifies that this key is
++ * to be used as the unicast key */
++ u8 isUnicastKey;
++
++ /* bit 0: Specifies that this key is
++ * to be used as the multicast key */
++ u8 isMulticastKey;
++} __ATTRIB_PACK__ KeyInfo_AES_t;
++
++/** KeyMaterial_TKIP_t */
++typedef struct _KeyMaterial_TKIP_t
++{
++ /* TKIP encryption/decryption key */
++ u8 TkipKey[16];
++
++ /* TKIP TX MIC Key */
++ u8 TkipTxMicKey[16];
++
++ /* TKIP RX MIC Key */
++ u8 TkipRxMicKey[16];
++} __ATTRIB_PACK__ KeyMaterial_TKIP_t, *PKeyMaterial_TKIP_t;
++
++/** KeyMaterial_AES_t */
++typedef struct _KeyMaterial_AES_t
++{
++ /* AES encryption/decryption key */
++ u8 AesKey[16];
++} __ATTRIB_PACK__ KeyMaterial_AES_t, *PKeyMaterial_AES_t;
++
++/** MrvlIEtype_KeyParamSet_t */
++typedef struct _MrvlIEtype_KeyParamSet_t
++{
++ /* Type ID */
++ u16 Type;
++
++ /* Length of Payload */
++ u16 Length;
++
++ /* Type of Key: WEP=0, TKIP=1, AES=2 */
++ u16 KeyTypeId;
++
++ /* Key Control Info specific to a KeyTypeId */
++ u16 KeyInfo;
++
++ /* Length of key */
++ u16 KeyLen;
++
++ /* Key material of size KeyLen */
++ u8 Key[32];
++} __ATTRIB_PACK__ MrvlIEtype_KeyParamSet_t, *PMrvlIEtype_KeyParamSet_t;
++
++/** HostCmd_DS_802_11_KEY_MATERIAL */
++typedef struct _HostCmd_DS_802_11_KEY_MATERIAL
++{
++ u16 Action;
++
++ MrvlIEtype_KeyParamSet_t KeyParamSet;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_KEY_MATERIAL;
++
++/** HostCmd_DS_802_11_HOST_SLEEP_CFG */
++typedef struct _HostCmd_DS_HOST_802_11_HOST_SLEEP_CFG
++{
++ /* bit0=1: non-unicast data
++ * bit1=1: unicast data
++ * bit2=1: mac events
++ * bit3=1: magic packet
++ */
++ u32 conditions;
++
++ u8 gpio;
++
++ /* in milliseconds */
++ u8 gap;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_HOST_SLEEP_CFG;
++
++#define CAL_DATA_HEADER_LEN 6 /* sizeof(HostCmd_DS_802_11_CAL_DATA_EXT)-sizeof(CalData) */
++
++/** HostCmd_DS_802_11_CAL_DATA_EXT */
++typedef struct _HostCmd_DS_802_11_CAL_DATA_EXT
++{
++ u16 Action;
++ u16 Revision;
++ u16 CalDataLen;
++ u8 CalData[1];
++} __ATTRIB_PACK__ HostCmd_DS_802_11_CAL_DATA_EXT;
++
++/** HostCmd_DS_802_11_EEPROM_ACCESS */
++typedef struct _HostCmd_DS_802_11_EEPROM_ACCESS
++{
++ u16 Action;
++
++ /* multiple 4 */
++ u16 Offset;
++ u16 ByteCount;
++ u8 Value;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_EEPROM_ACCESS;
++
++/** HostCmd_DS_802_11_BG_SCAN_CONFIG */
++typedef struct _HostCmd_DS_802_11_BG_SCAN_CONFIG
++{
++ /** Action */
++ u16 Action;
++
++ /**
++ * Enable/Disable
++ * 0 - Disable
++ * 1 - Enable
++ */
++ u8 Enable;
++
++ /**
++ * bssType
++ * 1 - Infrastructure
++ * 2 - IBSS
++ * 3 - any
++ */
++ u8 BssType;
++
++ /**
++ * ChannelsPerScan
++ * Number of channels to scan during a single scanning opportunity
++ */
++ u8 ChannelsPerScan;
++
++ u8 Reserved1[3];
++
++ /** ScanInterval */
++ u32 ScanInterval;
++
++ /**
++ * StoreCondition
++ * - SSID Match
++ * - SSID Match & Exceed SNR Threshold
++ */
++ u32 StoreCondition;
++
++ /**
++ * ReportConditions
++ * - SSID Match
++ * - SSID Match & Exceed SNR Threshold
++ */
++ u32 ReportConditions;
++
++ u16 Reserved2;
++
++ /* Attach TLV based parameters as needed:
++ *
++ * MrvlIEtypes_SsIdParamSet_t Set specific SSID filter
++ * MrvlIEtypes_ChanListParamSet_t Set the channels & channel params
++ * MrvlIEtypes_NumProbes_t Number of probes per SSID/broadcast
++ * MrvlIEtypes_WildCardSsIdParamSet_t Wildcard SSID matching patterns
++ * MrvlIEtypes_SnrThreshold_t SNR Threshold for match/report
++ */
++
++} __ATTRIB_PACK__ HostCmd_DS_802_11_BG_SCAN_CONFIG;
++
++/** HostCmd_DS_802_11_BG_SCAN_QUERY */
++typedef struct _HostCmd_DS_802_11_BG_SCAN_QUERY
++{
++ u8 Flush;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_BG_SCAN_QUERY;
++
++/** HostCmd_DS_802_11_BG_SCAN_QUERY_RSP */
++typedef struct _HostCmd_DS_802_11_BG_SCAN_QUERY_RSP
++{
++ u32 ReportCondition;
++ HostCmd_DS_802_11_SCAN_RSP scanresp;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_BG_SCAN_QUERY_RSP;
++
++/** HostCmd_DS_802_11_TPC_CFG */
++typedef struct _HostCmd_DS_802_11_TPC_CFG
++{
++ u16 Action;
++ u8 Enable;
++ s8 P0;
++ s8 P1;
++ s8 P2;
++ u8 UseSNR;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_TPC_CFG;
++
++/** HostCmd_DS_802_11_LED_CTRL */
++typedef struct _HostCmd_DS_802_11_LED_CTRL
++{
++ u16 Action; /* 0 = ACT_GET; 1 = ACT_SET; */
++ u16 LedNums; /* Numbers of LEDs supported */
++ MrvlIEtypes_LedGpio_t LedGpio;
++ MrvlIEtypes_LedBehavior_t LedBehavior[1];
++} __ATTRIB_PACK__ HostCmd_DS_802_11_LED_CTRL;
++
++/** HostCmd_DS_802_11_POWER_ADAPT_CFG_EXT */
++typedef struct _HostCmd_DS_802_11_POWER_ADAPT_CFG_EXT
++{
++ /** Action */
++ u16 Action; /* 0 = ACT_GET; 1 = ACT_SET; */
++ u16 EnablePA; /* 0 = disable; 1 = enable; */
++ MrvlIEtypes_PowerAdapt_Group_t PowerAdaptGroup;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_POWER_ADAPT_CFG_EXT;
++
++typedef struct _HostCmd_DS_SDIO_INT_CONFIG
++{
++ u16 Action; /* 0: get; 1: set */
++ u16 Gpio_pin;
++ u16 Gpio_int_edge; /*1: failing edge; 0: rasing edge */
++ u16 Gpio_pulse_width; /* in usec units */
++} __ATTRIB_PACK__ HostCmd_DS_SDIO_INT_CONFIG;
++
++typedef struct _HostCmd_DS_SDIO_PULL_CTRL
++{
++ u16 Action; /* 0: get; 1: set */
++ u16 PullUp; /* the delay of pulling up in us */
++ u16 PullDown; /* the delay of pulling down in us */
++} __ATTRIB_PACK__ HostCmd_DS_SDIO_PULL_CTRL;
++typedef struct _HostCmd_DS_802_11_IBSS_Status
++{
++ u16 Action;
++ u16 Enable;
++ u8 BSSID[ETH_ALEN];
++ u16 BeaconInterval;
++ u16 ATIMWindow;
++ u16 UseGRateProtection;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_IBSS_Status;
++
++typedef struct _HostCmd_TX_RATE_QUERY
++{
++ u16 TxRate;
++} __ATTRIB_PACK__ HostCmd_TX_RATE_QUERY;
++
++/** HostCmd_DS_802_11_AUTO_TX */
++typedef struct _HostCmd_DS_802_11_AUTO_TX
++{
++ /** Action */
++ u16 Action; /* 0 = ACT_GET; 1 = ACT_SET; */
++ MrvlIEtypes_AutoTx_t AutoTx;
++} __ATTRIB_PACK__ HostCmd_DS_802_11_AUTO_TX;
++
++/** HostCmd_MEM_ACCESS */
++typedef struct _HostCmd_DS_MEM_ACCESS
++{
++ /** Action */
++ u16 Action; /* 0 = ACT_GET; 1 = ACT_SET; */
++ u16 Reserved;
++ u32 Addr;
++ u32 Value;
++} __ATTRIB_PACK__ HostCmd_DS_MEM_ACCESS;
++
++typedef struct
++{
++ u64 TsfValue;
++} __ATTRIB_PACK__ HostCmd_DS_GET_TSF;
++
++#define LDO_INTERNAL 0
++#define LDO_EXTERNAL 1
++
++typedef struct _HostCmd_DS_802_11_LDO_CONFIG
++{
++ u16 Action; /* 0 = ACT_GET; 1 = ACT_SET; */
++ u16 PMSource; /* 0 = LDO_INTERNAL; 1 = LDO_EXTERNAL */
++} __ATTRIB_PACK__ HostCmd_DS_802_11_LDO_CONFIG;
++
++typedef struct _HostCmd_DS_VERSION_EXT
++{
++ u8 versionStrSel;
++ char versionStr[128];
++} __ATTRIB_PACK__ HostCmd_DS_VERSION_EXT;
++
++/** Define data structure for HostCmd_CMD_802_11D_DOMAIN_INFO */
++typedef struct _HostCmd_DS_802_11D_DOMAIN_INFO
++{
++ u16 Action;
++ MrvlIEtypes_DomainParamSet_t Domain;
++} __ATTRIB_PACK__ HostCmd_DS_802_11D_DOMAIN_INFO;
++
++/** Define data structure for HostCmd_RET_802_11D_DOMAIN_INFO */
++typedef struct _HostCmd_DS_802_11D_DOMAIN_INFO_RSP
++{
++ u16 Action;
++ MrvlIEtypes_DomainParamSet_t Domain;
++} __ATTRIB_PACK__ HostCmd_DS_802_11D_DOMAIN_INFO_RSP;
++
++typedef struct
++{
++ u32 PktInitCnt;
++ u32 PktSuccessCnt;
++ u32 TxAttempts;
++ u32 RetryFailure;
++ u32 ExpiryFailure;
++} __ATTRIB_PACK__ HostCmd_DS_TX_PKT_STAT_Entry;
++
++typedef struct
++{
++ HostCmd_DS_TX_PKT_STAT_Entry StatEntry[HOSTCMD_SUPPORTED_RATES];
++} __ATTRIB_PACK__ HostCmd_DS_TX_PKT_STATS;
++
++/** _HostCmd_DS_COMMAND*/
++struct _HostCmd_DS_COMMAND
++{
++
++ /** Command Header */
++ u16 Command;
++ u16 Size;
++ u16 SeqNum;
++ u16 Result;
++
++ /** Command Body */
++ union
++ {
++ HostCmd_DS_GET_HW_SPEC hwspec;
++ HostCmd_DS_802_11_PS_MODE psmode;
++ HostCmd_DS_802_11_SCAN scan;
++ HostCmd_DS_802_11_SCAN_RSP scanresp;
++ HostCmd_DS_MAC_CONTROL macctrl;
++ HostCmd_DS_802_11_ASSOCIATE associate;
++ HostCmd_DS_802_11_ASSOCIATE_RSP associatersp;
++ HostCmd_DS_802_11_DEAUTHENTICATE deauth;
++ HostCmd_DS_802_11_SET_WEP wep;
++ HostCmd_DS_802_11_AD_HOC_START ads;
++ HostCmd_DS_802_11_AD_HOC_RESULT result;
++ HostCmd_DS_802_11_GET_LOG glog;
++ HostCmd_DS_802_11_SNMP_MIB smib;
++ HostCmd_DS_802_11_RF_TX_POWER txp;
++ HostCmd_DS_802_11_RF_ANTENNA rant;
++ HostCmd_DS_802_11_RATE_ADAPT_RATESET rateset;
++ HostCmd_DS_MAC_MULTICAST_ADR madr;
++ HostCmd_DS_802_11_AD_HOC_JOIN adj;
++ HostCmd_DS_802_11_RADIO_CONTROL radio;
++ HostCmd_DS_802_11_RF_CHANNEL rfchannel;
++ HostCmd_DS_802_11_RSSI rssi;
++ HostCmd_DS_802_11_RSSI_RSP rssirsp;
++ HostCmd_DS_802_11_AD_HOC_STOP adhoc_stop;
++ HostCmd_DS_802_11_MAC_ADDRESS macadd;
++ HostCmd_DS_802_11_KEY_MATERIAL keymaterial;
++ HostCmd_DS_MAC_REG_ACCESS macreg;
++ HostCmd_DS_BBP_REG_ACCESS bbpreg;
++ HostCmd_DS_RF_REG_ACCESS rfreg;
++ HostCmd_DS_802_11_CAL_DATA_EXT caldataext;
++ HostCmd_DS_802_11_HOST_SLEEP_CFG hostsleepcfg;
++ HostCmd_DS_802_11_EEPROM_ACCESS rdeeprom;
++
++ HostCmd_DS_802_11D_DOMAIN_INFO domaininfo;
++ HostCmd_DS_802_11D_DOMAIN_INFO_RSP domaininforesp;
++ HostCmd_DS_802_11_BG_SCAN_CONFIG bgscancfg;
++ HostCmd_DS_802_11_BG_SCAN_QUERY bgscanquery;
++ HostCmd_DS_802_11_BG_SCAN_QUERY_RSP bgscanqueryresp;
++ HostCmd_DS_WMM_GET_STATUS getWmmStatus;
++ HostCmd_DS_WMM_ADDTS_REQ addTsReq;
++ HostCmd_DS_WMM_DELTS_REQ delTsReq;
++ HostCmd_DS_WMM_QUEUE_CONFIG queueConfig;
++ HostCmd_DS_WMM_QUEUE_STATS queueStats;
++ HostCmd_DS_TX_PKT_STATS txPktStats;
++ HostCmd_DS_802_11_SLEEP_PARAMS sleep_params;
++ HostCmd_DS_802_11_BCA_TIMESHARE bca_timeshare;
++ HostCmd_DS_802_11_INACTIVITY_TIMEOUT inactivity_timeout;
++ HostCmd_DS_802_11_SLEEP_PERIOD ps_sleeppd;
++ HostCmd_DS_802_11_TPC_CFG tpccfg;
++ HostCmd_DS_802_11_LED_CTRL ledgpio;
++ HostCmd_DS_802_11_FW_WAKEUP_METHOD fwwakeupmethod;
++
++ HostCmd_TX_RATE_QUERY txrate;
++ HostCmd_DS_GET_TSF gettsf;
++ HostCmd_DS_802_11_IBSS_Status ibssCoalescing;
++ HostCmd_DS_SDIO_INT_CONFIG sdio_int;
++ HostCmd_DS_SDIO_PULL_CTRL sdiopullctl;
++ HostCmd_DS_802_11_LDO_CONFIG ldocfg;
++ HostCmd_DS_VERSION_EXT verext;
++ } params;
++} __ATTRIB_PACK__;
++
++#endif
+diff --git a/drivers/net/wireless/marvell8686/if_sdio.c b/drivers/net/wireless/marvell8686/if_sdio.c
+new file mode 100644
+index 0000000..36f2c26
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/if_sdio.c
+@@ -0,0 +1,1379 @@
++/** @file if_sdio.c
++ * @brief This file contains SDIO IF (interface) module
++ * related functions.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ */
++/****************************************************
++Change log:
++ 10/14/05: add Doxygen format comments
++ 01/05/06: add kernel 2.6.x support
++ 01/23/06: add fw downlaod
++ 06/06/06: add macro SD_BLOCK_SIZE_FW_DL for firmware download
++ add macro ALLOC_BUF_SIZE for cmd resp/Rx data skb buffer allocation
++****************************************************/
++#include <linux/mmc/card.h>
++#include <linux/mmc/sdio_func.h>
++#include <linux/mmc/sdio_ids.h>
++
++#include "if_sdio.h"
++
++//#undef PRINTM
++//#define PRINTM(INFO, msg...) printk(msg)
++
++/* define SD block size for firmware download */
++#define SD_BLOCK_SIZE_FW_DL 32
++
++/* define SD block size for data Tx/Rx */
++#define SD_BLOCK_SIZE 128 /* To minimize the overhead of ethernet frame
++ with 1514 bytes, 320 bytes block size is used */
++
++#define ALLOC_BUF_SIZE (((MAX(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, \
++ MRVDRV_SIZE_OF_CMD_BUFFER) + SDIO_HEADER_LEN \
++ + SD_BLOCK_SIZE - 1) / SD_BLOCK_SIZE) * SD_BLOCK_SIZE)
++
++/* Max retry number of CMD53 write */
++#define MAX_WRITE_IOMEM_RETRY 2
++
++/********************************************************
++ Local Variables
++********************************************************/
++
++/********************************************************
++ Global Variables
++********************************************************/
++
++struct if_sdio_card {
++ struct sdio_func *func;
++ wlan_private *priv;
++ int model;
++
++ u8 int_cause;
++
++ u8 chiprev;
++ u8 async_int_mode;
++ u8 block_size_512;
++ card_capability info;
++};
++
++extern wlan_private *wlanpriv;
++const char *helper_name;
++const char *fw_name;
++/********************************************************
++ Local Functions
++********************************************************/
++
++/**
++ * @brief This function adds the card
++ *
++ * @param card A pointer to the card
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++sbi_add_card(void *card, struct device *dmdev)
++{
++ struct if_sdio_card *sdio_card = (struct if_sdio_card*)card;
++ sdio_card->priv = wlan_add_card(card, dmdev);
++ if (sdio_card->priv)
++ return WLAN_STATUS_SUCCESS;
++ else
++ return WLAN_STATUS_FAILURE;
++}
++
++/**
++ * @brief This function removes the card
++ *
++ * @param card A pointer to the card
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++sbi_remove_card(void *card)
++{
++ return wlan_remove_card(card);
++}
++
++/**
++ * @brief This function reads scratch registers
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param dat A pointer to keep returned data
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++mv_sdio_read_scratch(wlan_private * priv, u16 * dat)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ u8 scr0;
++ u8 scr1;
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++
++ scr0 = sdio_readb(card->func, CARD_OCR_0_REG, &ret);
++ if (ret)
++ return WLAN_STATUS_FAILURE;
++
++ scr1 = sdio_readb(card->func, CARD_OCR_1_REG, &ret);
++ PRINTM(INFO, "CARD_OCR_0_REG = 0x%x, CARD_OCR_1_REG = 0x%x\n", scr0,
++ scr1);
++ if (ret)
++ return WLAN_STATUS_FAILURE;
++
++ *dat = (((u16) scr1) << 8) | scr0;
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function polls the card status register.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param bits the bit mask
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++mv_sdio_poll_card_status(wlan_private * priv, u8 bits)
++{
++ int tries;
++ int rval;
++ u8 cs;
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++
++ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
++ cs = sdio_readb(card->func, CARD_STATUS_REG, &rval);
++ if (rval == 0 && (cs & bits) == bits) {
++ return WLAN_STATUS_SUCCESS;
++ }
++
++ mdelay(1);
++ }
++
++ PRINTM(WARN, "mv_sdio_poll_card_status: FAILED!:%d\n", rval);
++ return WLAN_STATUS_FAILURE;
++}
++
++/**
++ * @brief This function programs the firmware image.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param firmware A pointer to the buffer of firmware image
++ * @param firmwarelen the length of firmware image
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++sbi_prog_firmware_image(wlan_private * priv,
++ const u8 * firmware, int firmwarelen)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ u16 firmwarestat;
++ u8 *fwbuf = priv->adapter->TmpTxBuf;
++ int fwblknow;
++ u32 tx_len;
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++#ifdef FW_DOWNLOAD_SPEED
++ u32 tv1, tv2;
++#endif
++
++ ENTER();
++
++ sdio_claim_host(card->func);
++ ret = sdio_set_block_size(card->func, SD_BLOCK_SIZE_FW_DL);
++ if (ret) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ if ((ret = mv_sdio_read_scratch(priv, &firmwarestat)) < 0) {
++ PRINTM(INFO, "read scratch returned <0\n");
++ goto done;
++ }
++
++ if (firmwarestat == FIRMWARE_READY) {
++ PRINTM(INFO, "FW already downloaded!\n");
++ ret = WLAN_STATUS_SUCCESS;
++ goto done;
++ }
++
++ PRINTM(INFO, "Downloading helper image (%d bytes), block size %d bytes\n",
++ firmwarelen, SD_BLOCK_SIZE_FW_DL);
++
++#ifdef FW_DOWNLOAD_SPEED
++ tv1 = get_utimeofday();
++#endif
++ /* Perform firmware data transfer */
++ tx_len =
++ (FIRMWARE_TRANSFER_NBLOCK * SD_BLOCK_SIZE_FW_DL) - SDIO_HEADER_LEN;
++ for (fwblknow = 0; fwblknow < firmwarelen; fwblknow += tx_len) {
++
++ /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
++ ret = mv_sdio_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
++ if (ret < 0) {
++ PRINTM(FATAL, "FW download died @ %d\n", fwblknow);
++ goto done;
++ }
++
++ /* Set blocksize to transfer - checking for last block */
++ if (firmwarelen - fwblknow < tx_len)
++ tx_len = firmwarelen - fwblknow;
++
++ fwbuf[0] = ((tx_len & 0x000000ff) >> 0); /* Little-endian */
++ fwbuf[1] = ((tx_len & 0x0000ff00) >> 8);
++ fwbuf[2] = ((tx_len & 0x00ff0000) >> 16);
++ fwbuf[3] = ((tx_len & 0xff000000) >> 24);
++
++ /* Copy payload to buffer */
++ memcpy(&fwbuf[SDIO_HEADER_LEN], &firmware[fwblknow], tx_len);
++
++ PRINTM(INFO, ".");
++
++ /* Send data */
++ ret = sdio_writesb(card->func, priv->wlan_dev.ioport,
++ fwbuf, FIRMWARE_TRANSFER_NBLOCK * SD_BLOCK_SIZE_FW_DL);
++
++ if (ret) {
++ PRINTM(FATAL, "IO error: transferring block @ %d\n", fwblknow);
++ goto done;
++ }
++ }
++
++#ifdef FW_DOWNLOAD_SPEED
++ tv2 = get_utimeofday();
++ PRINTM(INFO, "helper: %ld.%03ld.%03ld ", tv1 / 1000000,
++ (tv1 % 1000000) / 1000, tv1 % 1000);
++ PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000,
++ (tv2 % 1000000) / 1000, tv2 % 1000);
++ tv2 -= tv1;
++ PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000,
++ (tv2 % 1000000) / 1000, tv2 % 1000);
++#endif
++
++ /* Write last EOF data */
++ PRINTM(INFO, "\nTransferring EOF block\n");
++ memset(fwbuf, 0x0, SD_BLOCK_SIZE_FW_DL);
++ ret = sdio_writesb(card->func, priv->wlan_dev.ioport, fwbuf, SD_BLOCK_SIZE_FW_DL);
++
++ if (ret) {
++ PRINTM(FATAL, "IO error in writing EOF FW block\n");
++ goto done;
++ }
++
++ ret = WLAN_STATUS_SUCCESS;
++
++done:
++ sdio_set_block_size(card->func, 0);
++ sdio_release_host(card->func);
++ return ret;
++}
++
++/**
++ * @brief This function downloads firmware image to the card.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param firmware A pointer to firmware image buffer
++ * @param firmwarelen the length of firmware image
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++sbi_download_wlan_fw_image(wlan_private * priv,
++ const u8 * firmware, int firmwarelen)
++{
++ u8 base0;
++ u8 base1;
++ int ret = WLAN_STATUS_SUCCESS;
++ int offset;
++ u8 *fwbuf = priv->adapter->TmpTxBuf;
++ int timeout = 5000;
++ u16 len;
++ int txlen = 0;
++ int tx_blocks = 0;
++ int i = 0;
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++#ifdef FW_DOWNLOAD_SPEED
++ u32 tv1, tv2;
++#endif
++
++ ENTER();
++
++ PRINTM(INFO, "Downloading FW image (%d bytes)\n", firmwarelen);
++
++#ifdef FW_DOWNLOAD_SPEED
++ tv1 = get_utimeofday();
++#endif
++ sdio_claim_host(card->func);
++
++ ret = sdio_set_block_size(card->func, SD_BLOCK_SIZE_FW_DL);
++ if (ret) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ /* Wait initially for the first non-zero value */
++ do {
++ base0 = sdio_readb(card->func, HOST_F1_RD_BASE_0, &ret);
++ if (ret) {
++ PRINTM(WARN, "Dev BASE0 register read failed:"
++ " base0=0x%04X(%d)\n", base0, base0);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ base1 = sdio_readb(card->func, HOST_F1_RD_BASE_1, &ret);
++ if (ret) {
++ PRINTM(WARN, "Dev BASE1 register read failed:"
++ " base1=0x%04X(%d)\n", base1, base1);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ len = (((u16) base1) << 8) | base0;
++ mdelay(1);
++ } while (!len && --timeout);
++
++ if (!timeout) {
++ PRINTM(MSG, "Helper downloading finished.\n");
++ PRINTM(MSG, "Timeout for FW downloading!\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
++ ret = mv_sdio_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
++ if (ret < 0) {
++ PRINTM(FATAL, "FW download died, helper not ready\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ len &= ~B_BIT_0;
++
++ /* Perform firmware data transfer */
++ for (offset = 0; offset < firmwarelen; offset += txlen) {
++ txlen = len;
++
++ /* Set blocksize to transfer - checking for last block */
++ if (firmwarelen - offset < txlen) {
++ txlen = firmwarelen - offset;
++ }
++ /* PRINTM(INFO, "fw: offset=%d, txlen = 0x%04X(%d)\n",
++ offset,txlen,txlen); */
++ PRINTM(INFO, ".");
++
++ tx_blocks = (txlen + SD_BLOCK_SIZE_FW_DL - 1) / SD_BLOCK_SIZE_FW_DL;
++
++ /* Copy payload to buffer */
++ memcpy(fwbuf, &firmware[offset], txlen);
++
++ /* Send data */
++ ret = sdio_writesb(card->func, priv->wlan_dev.ioport,
++ fwbuf, tx_blocks * SD_BLOCK_SIZE_FW_DL);
++
++ if (ret) {
++ PRINTM(ERROR, "FW download, write iomem (%d) failed: %d\n", i,
++ ret);
++ sdio_writeb(card->func, 0x04, CONFIGURATION_REG, &ret);
++ if (ret) {
++ PRINTM(ERROR, "write ioreg failed (FN1 CFG)\n");
++ }
++ }
++
++ /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
++ ret = mv_sdio_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
++ if (ret < 0) {
++ PRINTM(FATAL, "FW download with helper died @ %d\n", offset);
++ goto done;
++ }
++
++ base0 = sdio_readb(card->func, HOST_F1_RD_BASE_0, &ret);
++ if (ret) {
++ PRINTM(WARN, "Dev BASE0 register read failed:"
++ " base0=0x%04X(%d)\n", base0, base0);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ base1 = sdio_readb(card->func, HOST_F1_RD_BASE_1, &ret);
++ if (ret) {
++ PRINTM(WARN, "Dev BASE1 register read failed:"
++ " base1=0x%04X(%d)\n", base1, base1);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ len = (((u16) base1) << 8) | base0;
++
++ if (!len) {
++ break;
++ }
++
++ if (len & B_BIT_0) {
++ i++;
++ if (i > MAX_WRITE_IOMEM_RETRY) {
++ PRINTM(FATAL, "FW download failure, over max retry count\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ PRINTM(ERROR, "CRC error indicated by the helper:"
++ " len = 0x%04X, txlen = %d\n", len, txlen);
++ len &= ~B_BIT_0;
++ /* Setting this to 0 to resend from same offset */
++ txlen = 0;
++ }
++ else
++ i = 0;
++ }
++ PRINTM(INFO, "\nFW download over, size %d bytes\n", firmwarelen);
++
++ ret = WLAN_STATUS_SUCCESS;
++done:
++ sdio_set_block_size(card->func, 0);
++ sdio_release_host(card->func);
++#ifdef FW_DOWNLOAD_SPEED
++ tv2 = get_utimeofday();
++ PRINTM(INFO, "FW: %ld.%03ld.%03ld ", tv1 / 1000000,
++ (tv1 % 1000000) / 1000, tv1 % 1000);
++ PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000,
++ (tv2 % 1000000) / 1000, tv2 % 1000);
++ tv2 -= tv1;
++ PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000,
++ (tv2 % 1000000) / 1000, tv2 % 1000);
++#endif
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function reads data from the card.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param type A pointer to keep type as data or command
++ * @param nb A pointer to keep the data/cmd length retured in buffer
++ * @param payload A pointer to the data/cmd buffer
++ * @param nb the length of data/cmd buffer
++ * @param npayload the length of data/cmd buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++mv_sdio_card_to_host(wlan_private * priv,
++ u32 * type, int *nb, u8 * payload, int npayload)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ u16 buf_len = 0;
++ int buf_block_len;
++ int blksz;
++ u32 *pevent;
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++
++ ENTER();
++
++ if (!payload) {
++ PRINTM(WARN, "payload NULL pointer received!\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto exit;
++ }
++
++ /* Read the length of data to be transferred */
++ ret = mv_sdio_read_scratch(priv, &buf_len);
++ if (ret < 0) {
++ PRINTM(ERROR, "card_to_host, read RX length failed\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto exit;
++ }
++
++ if (buf_len <= SDIO_HEADER_LEN || buf_len > npayload) {
++ PRINTM(ERROR, "card_to_host, invalid packet length: %d\n", buf_len);
++ ret = WLAN_STATUS_FAILURE;
++ goto exit;
++ }
++
++ ret = mv_sdio_poll_card_status(priv, CARD_IO_READY);
++ if (ret < 0) {
++ PRINTM(FATAL, "MV card status fail\n");
++ goto exit;
++ }
++
++ /* Allocate buffer */
++ blksz = SD_BLOCK_SIZE;
++ buf_block_len = (buf_len + blksz - 1) / blksz;
++
++ ret = sdio_set_block_size(card->func, blksz);
++ if (ret) {
++ ret = WLAN_STATUS_FAILURE;
++ goto exit;
++ }
++
++ ret = sdio_readsb(card->func, payload, priv->wlan_dev.ioport, buf_block_len * blksz);
++
++ if (ret) {
++ PRINTM(ERROR, "card_to_host, read iomem failed: %d\n", ret);
++ ret = WLAN_STATUS_FAILURE;
++ goto exit;
++ }
++ *nb = buf_len;
++
++ DBG_HEXDUMP(IF_D, "SDIO Blk Rd", payload, blksz * buf_block_len);
++
++ *type = (payload[2] | (payload[3] << 8));
++ if (*type == MVSD_EVENT) {
++ pevent = (u32 *) & payload[4];
++ priv->adapter->EventCause = MVSD_EVENT | (((u16) (*pevent)) << 3);
++ }
++
++exit:
++ sdio_set_block_size(card->func, 0);
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function enables the host interrupts mask
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param mask the interrupt mask
++ * @return WLAN_STATUS_SUCCESS
++ */
++static int
++enable_host_int_mask(wlan_private * priv, u8 mask)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++
++ sdio_claim_host(card->func);
++ /* Simply write the mask to the register */
++ sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret);
++ sdio_release_host(card->func);
++
++ if (ret) {
++ PRINTM(WARN, "ret = %d\n", ret);
++ ret = WLAN_STATUS_FAILURE;
++ }
++
++ priv->adapter->HisRegCpy = 1;
++
++ return ret;
++}
++
++/** @brief This function disables the host interrupts mask.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param mask the interrupt mask
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++disable_host_int_mask(wlan_private * priv, u8 mask)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ u8 host_int_mask;
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++
++ sdio_claim_host(card->func);
++ /* Read back the host_int_mask register */
++ host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret);
++ if (ret) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ /* Update with the mask and write back to the register */
++ host_int_mask &= ~mask;
++ sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret);
++ if (ret) {
++ PRINTM(WARN, "Unable to diable the host interrupt!\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++done:
++ sdio_release_host(card->func);
++ return ret;
++}
++
++/********************************************************
++ Global Functions
++********************************************************/
++
++/**
++ * @brief This function handles the interrupt.
++ *
++ * @param irq The irq of device.
++ * @param dev_id A pointer to net_device structure
++ * @param fp A pointer to pt_regs structure
++ * @return n/a
++ */
++static void sbi_interrupt(struct sdio_func *func)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ u8 sdio_ireg = 0;
++ u8 *cmdBuf;
++ wlan_private *priv;
++ wlan_dev_t *wlan_dev;
++ struct sk_buff *skb;
++ struct if_sdio_card* card = NULL;
++ ENTER();
++
++ priv = wlanpriv;
++ wlan_dev = &priv->wlan_dev;
++ card = (struct if_sdio_card*)wlan_dev->card;
++
++ sdio_ireg = sdio_readb(func, HOST_INTSTATUS_REG, &ret);
++ if (ret) {
++ PRINTM(WARN, "sdio_read_ioreg: read int status register failed\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ sdio_writeb(func, (~sdio_ireg) & (DN_LD_HOST_INT_STATUS | UP_LD_HOST_INT_STATUS),
++ HOST_INTSTATUS_REG, &ret);
++ if (ret) {
++ PRINTM(WARN, "sdio_write_ioreg: clear int status register failed\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ if (sdio_ireg & DN_LD_HOST_INT_STATUS) { /* tx_done INT */
++ if (!priv->wlan_dev.dnld_sent) { /* tx_done already received */
++ PRINTM(INFO, "warning: tx_done already received:"
++ " dnld_sent=0x%x int status=0x%x\n",
++ priv->wlan_dev.dnld_sent, sdio_ireg);
++ }
++ else {
++ wmm_process_fw_iface_tx_xfer_end(priv);
++ priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
++ }
++ OS_INT_DISABLE;
++ card->int_cause |= HIS_TxDnLdRdy;
++ wlan_interrupt(wlan_dev->netdev);
++ OS_INT_RESTORE;
++ }
++
++ if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
++
++ /*
++ * DMA read data is by block alignment,so we need alloc extra block
++ * to avoid wrong memory access.
++ */
++ if (!(skb = dev_alloc_skb(ALLOC_BUF_SIZE))) {
++ PRINTM(WARN, "No free skb\n");
++ priv->stats.rx_dropped++;
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ /*
++ * Transfer data from card
++ * skb->tail is passed as we are calling skb_put after we
++ * are reading the data
++ */
++ if (mv_sdio_card_to_host(priv, &wlan_dev->upld_typ,
++ (int *) &wlan_dev->upld_len, skb->tail,
++ ALLOC_BUF_SIZE) < 0) {
++ u8 cr = 0;
++
++ PRINTM(ERROR, "Card to host failed: int status=0x%x\n",
++ sdio_ireg);
++ cr = sdio_readb(func, CONFIGURATION_REG, &ret);
++ if (ret)
++ PRINTM(ERROR, "read ioreg failed (FN1 CFG)\n");
++
++ PRINTM(INFO, "Config Reg val = %d\n", cr);
++ sdio_writeb(func, cr | 0x04, CONFIGURATION_REG, &ret);
++ if (ret)
++ PRINTM(ERROR, "write ioreg failed (FN1 CFG)\n");
++
++ PRINTM(INFO, "write success\n");
++ cr = sdio_readb(func, CONFIGURATION_REG, &ret);
++ if (ret)
++ PRINTM(ERROR, "read ioreg failed (FN1 CFG)\n");
++
++ PRINTM(INFO, "Config reg val =%x\n", cr);
++ ret = WLAN_STATUS_FAILURE;
++ kfree_skb(skb);
++ goto done;
++ }
++
++ OS_INT_DISABLE;
++ switch (wlan_dev->upld_typ) {
++ case MVSD_DAT:
++ PRINTM(DATA, "Data <= FW\n");
++ card->int_cause |= HIS_RxUpLdRdy;
++ skb_put(skb, priv->wlan_dev.upld_len);
++ skb_pull(skb, SDIO_HEADER_LEN);
++ list_add_tail((struct list_head *) skb,
++ (struct list_head *) &priv->adapter->RxSkbQ);
++ /* skb will be freed by kernel later */
++ break;
++
++ case MVSD_CMD:
++ PRINTM(DATA, "CMD\n");
++
++ /* take care of CurCmd = NULL case */
++ if (!priv->adapter->CurCmd) {
++ cmdBuf = priv->wlan_dev.upld_buf;
++ }
++ else {
++ cmdBuf = priv->adapter->CurCmd->BufVirtualAddr;
++ }
++
++ priv->wlan_dev.upld_len -= SDIO_HEADER_LEN;
++ memcpy(cmdBuf, skb->data + SDIO_HEADER_LEN,
++ MIN(MRVDRV_SIZE_OF_CMD_BUFFER, priv->wlan_dev.upld_len));
++ kfree_skb(skb);
++ card->int_cause |= HIS_CmdUpLdRdy;
++ break;
++
++ case MVSD_EVENT:
++ /* event cause has been saved to priv->adapter->EventCause */
++ kfree_skb(skb);
++ card->int_cause |= HIS_CardEvent;
++ break;
++
++ default:
++ PRINTM(ERROR, "SDIO unknown upld type = 0x%x\n",
++ wlan_dev->upld_typ);
++ kfree_skb(skb);
++ break;
++ }
++ wlan_interrupt(wlan_dev->netdev);
++ OS_INT_RESTORE;
++ }
++
++ ret = WLAN_STATUS_SUCCESS;
++done:
++ LEAVE();
++ return;
++}
++
++/**
++ * @brief This function reads the IO register.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param func funcion number
++ * @param reg register to be read
++ * @param dat A pointer to variable that keeps returned value
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++sbi_read_ioreg(wlan_private * priv, u8 func, u32 reg, u8 * dat)
++{
++ int ret;
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++ sdio_claim_host(card->func);
++ if (func == 0)
++ *dat = sdio_f0_readb(card->func, reg, &ret);
++ else
++ *dat = sdio_readb(card->func, reg, &ret);
++ sdio_release_host(card->func);
++ return ret;
++}
++
++/**
++ * @brief This function writes the IO register.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param func funcion number
++ * @param reg register to be written
++ * @param dat the value to be written
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++sbi_write_ioreg(wlan_private * priv, u8 func, u32 reg, u8 dat)
++{
++ int ret;
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++ sdio_claim_host(card->func);
++ if (func == 0)
++ sdio_f0_writeb(card->func, dat, reg, &ret);
++ else
++ sdio_writeb(card->func, dat, reg, &ret);
++ sdio_release_host(card->func);
++ return ret;
++}
++
++/**
++ * @brief This function checks the interrupt status and handle it accordingly.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param ireg A pointer to variable that keeps returned value
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++sbi_get_int_status(wlan_private * priv, u8 * ireg)
++{
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++ OS_INT_DISABLE;
++ *ireg = card->int_cause;
++ card->int_cause = 0;
++ OS_INT_RESTORE;
++ return WLAN_STATUS_SUCCESS;
++
++}
++
++/**
++ * @brief This function is a dummy function.
++ *
++ * @return WLAN_STATUS_SUCCESS
++ */
++int
++sbi_card_to_host(wlan_private * priv, u32 type,
++ u32 * nb, u8 * payload, u16 npayload)
++{
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @return WLAN_STATUS_SUCCESS
++ */
++int
++sbi_read_event_cause(wlan_private * priv)
++{
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function disables the host interrupts.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++sbi_disable_host_int(wlan_private * priv)
++{
++ return disable_host_int_mask(priv, HIM_DISABLE);
++}
++
++/**
++ * @brief This function enables the host interrupts.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS
++ */
++int
++sbi_enable_host_int(wlan_private * priv)
++{
++ return enable_host_int_mask(priv, HIM_ENABLE);
++}
++
++/**
++ * @brief This function de-registers the device.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS
++ */
++int
++sbi_unregister_dev(wlan_private * priv)
++{
++ ENTER();
++
++ if (priv->wlan_dev.card != NULL) {
++ /* Release the SDIO IRQ */
++ PRINTM(WARN, "Making the sdio dev card as NULL\n");
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function registers the device.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++sbi_register_dev(wlan_private * priv)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ u8 reg;
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++
++ ENTER();
++
++ /* Initialize the private structure */
++ strncpy(priv->wlan_dev.name, "sdio0", sizeof(priv->wlan_dev.name));
++ priv->wlan_dev.ioport = 0;
++ priv->wlan_dev.upld_rcv = 0;
++ priv->wlan_dev.upld_typ = 0;
++ priv->wlan_dev.upld_len = 0;
++
++ sdio_claim_host(card->func);
++ /* Read the IO port */
++ reg = sdio_readb(card->func, IO_PORT_0_REG, &ret);
++ if (ret)
++ goto failed;
++ else
++ priv->wlan_dev.ioport |= reg;
++
++ reg = sdio_readb(card->func, IO_PORT_1_REG, &ret);
++ if (ret)
++ goto failed;
++ else
++ priv->wlan_dev.ioport |= (reg << 8);
++
++ reg = sdio_readb(card->func, IO_PORT_2_REG, &ret);
++ if (ret)
++ goto failed;
++ else
++ priv->wlan_dev.ioport |= (reg << 16);
++ sdio_release_host(card->func);
++
++ PRINTM(INFO, "SDIO FUNC1 IO port: 0x%x\n", priv->wlan_dev.ioport);
++
++ /* Disable host interrupt first. */
++ if ((ret = disable_host_int_mask(priv, 0xff)) < 0) {
++ PRINTM(WARN, "Warning: unable to disable host interrupt!\n");
++ }
++
++ priv->adapter->chip_rev = card->chiprev;
++ priv->adapter->sdiomode = 4;
++
++ return WLAN_STATUS_SUCCESS;
++
++failed:
++ sdio_release_host(card->func);
++ priv->wlan_dev.card = NULL;
++
++ return WLAN_STATUS_FAILURE;
++}
++
++/**
++ * @brief This function sends data to the card.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param type data or command
++ * @param payload A pointer to the data/cmd buffer
++ * @param nb the length of data/cmd
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ int buf_block_len;
++ int blksz;
++ int i = 0;
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++
++ ENTER();
++
++ sdio_claim_host(card->func);
++ priv->adapter->HisRegCpy = 0;
++
++ /* Allocate buffer and copy payload */
++ blksz = SD_BLOCK_SIZE;
++ buf_block_len = (nb + SDIO_HEADER_LEN + blksz - 1) / blksz;
++
++ /* This is SDIO specific header
++ * length: byte[1][0],
++ * type: byte[3][2] (MVSD_DAT = 0, MVSD_CMD = 1, MVSD_EVENT = 3)
++ */
++ priv->adapter->TmpTxBuf[0] = (nb + SDIO_HEADER_LEN) & 0xff;
++ priv->adapter->TmpTxBuf[1] = ((nb + SDIO_HEADER_LEN) >> 8) & 0xff;
++ priv->adapter->TmpTxBuf[2] = type;
++ priv->adapter->TmpTxBuf[3] = 0x0;
++
++ if (payload != NULL &&
++ (nb > 0 &&
++ nb <= (sizeof(priv->adapter->TmpTxBuf) - SDIO_HEADER_LEN))) {
++ if (type == MVMS_CMD)
++ memcpy(&priv->adapter->TmpTxBuf[SDIO_HEADER_LEN], payload, nb);
++ }
++ else {
++ PRINTM(WARN, "sbi_host_to_card(): Error: payload=%p, nb=%d\n",
++ payload, nb);
++ }
++
++ if (type == MVSD_DAT)
++ priv->wlan_dev.dnld_sent = DNLD_DATA_SENT;
++ else
++ priv->wlan_dev.dnld_sent = DNLD_CMD_SENT;
++
++ ret = sdio_set_block_size(card->func, blksz);
++ if (ret) {
++ ret = WLAN_STATUS_FAILURE;
++ goto exit;
++ }
++
++ do {
++ /* Transfer data to card */
++ ret = sdio_writesb(card->func, priv->wlan_dev.ioport,
++ priv->adapter->TmpTxBuf, blksz * buf_block_len);
++ if (ret) {
++ i++;
++
++ PRINTM(ERROR, "host_to_card, write iomem (%d) failed: %d\n", i,
++ ret);
++ sdio_writeb(card->func, 0x04, CONFIGURATION_REG, &ret);
++ if (ret) {
++ PRINTM(ERROR, "write ioreg failed (FN1 CFG)\n");
++ }
++ ret = WLAN_STATUS_FAILURE;
++ if (i > MAX_WRITE_IOMEM_RETRY) {
++ priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
++ goto exit;
++ }
++ }
++ else {
++ DBG_HEXDUMP(IF_D, "SDIO Blk Wr", priv->adapter->TmpTxBuf,
++ blksz * buf_block_len);
++ }
++ } while (ret == WLAN_STATUS_FAILURE);
++
++exit:
++ sdio_set_block_size(card->func, 0);
++ sdio_release_host(card->func);
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function reads CIS informaion.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++sbi_get_cis_info(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ u8 tupledata[255];
++ ENTER();
++
++ /* TODO using sdio tuple data */
++
++ /* Copy the CIS Table to Adapter */
++ memset(Adapter->CisInfoBuf, 0x0, sizeof(Adapter->CisInfoBuf));
++ memcpy(Adapter->CisInfoBuf, tupledata, sizeof(tupledata));
++ Adapter->CisInfoLen = sizeof(tupledata);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function probes the card.
++ *
++ * @param card_p A pointer to the card
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++sbi_probe_card(void *card_p)
++{
++ struct if_sdio_card* card = (struct if_sdio_card*)card_p;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ if (!card) {
++ ret = -ENODEV; //WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ /* Check for MANFID */
++ PRINTM(INFO, "Marvell SDIO card detected!\n");
++
++ sdio_claim_host(card->func);
++ /* read Revision Register to get the hw revision number */
++ card->chiprev = sdio_readb(card->func, CARD_REVISION_REG, &ret);
++ if (ret) {
++ PRINTM(FATAL, "cannot read CARD_REVISION_REG\n");
++ }
++ else {
++ PRINTM(INFO, "revision=0x%x\n", card->chiprev);
++ switch (card->chiprev) {
++ default:
++ card->block_size_512 = TRUE;
++ card->async_int_mode = TRUE;
++ break;
++ }
++ }
++
++ ret = WLAN_STATUS_SUCCESS;
++done:
++ sdio_release_host(card->func);
++ return ret;
++}
++
++/**
++ * @brief This function calls sbi_download_wlan_fw_image to download
++ * firmware image to the card.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++sbi_prog_firmware_w_helper(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ if (Adapter->fmimage != NULL) {
++ return sbi_download_wlan_fw_image(priv,
++ Adapter->fmimage,
++ Adapter->fmimage_len);
++ }
++ else {
++ PRINTM(MSG, "No external FW image\n");
++ return WLAN_STATUS_FAILURE;
++ }
++}
++
++/**
++ * @brief This function programs helper image.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++sbi_prog_helper(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ if (Adapter->helper != NULL) {
++ return sbi_prog_firmware_image(priv,
++ Adapter->helper, Adapter->helper_len);
++ }
++ else {
++ PRINTM(MSG, "No external helper image\n");
++ return WLAN_STATUS_FAILURE;
++ }
++}
++
++/**
++ * @brief This function checks if the firmware is ready to accept
++ * command or not.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++sbi_verify_fw_download(wlan_private * priv)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ u16 firmwarestat;
++ int tries;
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++
++ sdio_claim_host(card->func);
++ /* Wait for firmware initialization event */
++ for (tries = 0; tries < MAX_FIRMWARE_POLL_TRIES; tries++) {
++ if ((ret = mv_sdio_read_scratch(priv, &firmwarestat)) < 0)
++ continue;
++
++ if (firmwarestat == FIRMWARE_READY) {
++ ret = WLAN_STATUS_SUCCESS;
++ break;
++ }
++ else {
++ mdelay(10);
++ ret = WLAN_STATUS_FAILURE;
++ }
++ }
++
++ if (ret < 0) {
++ PRINTM(MSG, "Timeout waiting for FW to become active\n");
++ goto done;
++ }
++
++ ret = WLAN_STATUS_SUCCESS;
++done:
++ sdio_release_host(card->func);
++ return ret;
++}
++
++/**
++ * @brief This function set bus clock on/off
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param option TRUE--on , FALSE--off
++ * @return WLAN_STATUS_SUCCESS
++ */
++int
++sbi_set_bus_clock(wlan_private * priv, u8 option)
++{
++/* if (option == TRUE)
++ start_bus_clock(((mmc_card_t) ((priv->wlan_dev).card))->ctrlr);
++ else
++ stop_bus_clock_2(((mmc_card_t) ((priv->wlan_dev).card))->ctrlr); */
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function makes firmware exiting from deep sleep.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++sbi_exit_deep_sleep(wlan_private * priv)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++
++ sbi_set_bus_clock(priv, TRUE);
++
++ sdio_claim_host(card->func);
++ sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
++ sdio_release_host(card->func);
++
++ return ret;
++}
++
++/**
++ * @brief This function resets the setting of deep sleep.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++sbi_reset_deepsleep_wakeup(wlan_private * priv)
++{
++
++ int ret = WLAN_STATUS_SUCCESS;
++ struct if_sdio_card* card = (struct if_sdio_card*)priv->wlan_dev.card;
++
++ ENTER();
++
++ sdio_claim_host(card->func);
++ sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
++ sdio_release_host(card->func);
++
++ LEAVE();
++
++ return ret;
++}
++
++static const struct sdio_device_id if_sdio_ids[] = {
++ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_LIBERTAS)},
++ { /* end: all zeroes */},
++};
++
++MODULE_DEVICE_TABLE(sdio, if_sdio_ids);
++struct if_sdio_model
++{
++ int model;
++ const char *helper;
++ const char *firmware;
++};
++
++static struct if_sdio_model if_sdio_models[] = {
++ {
++ /* 8686 */
++ .model = 0x0B,
++ .helper = "/lib/firmware/sd8686_helper.bin",
++ .firmware = "/lib/firmware/sd8686.bin",
++ },
++};
++
++static int if_sdio_probe(struct sdio_func *func,
++ const struct sdio_device_id *id)
++{
++ struct if_sdio_card *card;
++ int ret, i;
++ unsigned int model;
++
++ card = kzalloc(sizeof(struct if_sdio_card), GFP_KERNEL);
++
++ for (i = 0;i < func->card->num_info;i++) {
++ if (sscanf(func->card->info[i],
++ "802.11 SDIO ID: %x", &model) == 1)
++ break;
++ if (sscanf(func->card->info[i],
++ "ID: %x", &model) == 1)
++ break;
++ if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
++ model = 4;
++ break;
++ }
++ }
++
++ if (i == func->card->num_info) {
++ printk("unable to identify card model\n");
++ return -ENODEV;
++ }
++
++ card->func = func;
++ card->model = model;
++
++ for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) {
++ if (card->model == if_sdio_models[i].model)
++ break;
++ }
++
++ if (i == ARRAY_SIZE(if_sdio_models)) {
++ printk("unknown card model 0x%x\n", card->model);
++ ret = -ENODEV;
++ goto free;
++ }
++
++ helper_name = if_sdio_models[i].helper;
++ fw_name = if_sdio_models[i].firmware;
++
++ sdio_claim_host(func);
++
++ ret = sdio_enable_func(func);
++ if (ret)
++ goto release;
++
++ sdio_writeb(func, 0x00, HOST_INT_MASK_REG, &ret);
++ if (ret) {
++ PRINTM(WARN, "Unable to diable the host interrupt!\n");
++ goto reclaim;
++ }
++
++ ret = sdio_claim_irq(func, sbi_interrupt);
++ if (ret)
++ goto disable;
++
++ sdio_release_host(func);
++
++ sdio_set_drvdata(func, card);
++
++ ret = sbi_add_card(card, &func->dev);
++ if (ret)
++ goto reclaim;
++
++out:
++ return ret;
++
++reclaim:
++ sdio_claim_host(func);
++ sdio_release_irq(func);
++disable:
++ sdio_disable_func(func);
++release:
++ sdio_release_host(func);
++free:
++ kfree(card);
++ goto out;
++}
++
++static void if_sdio_remove(struct sdio_func *func)
++{
++ struct if_sdio_card *card = sdio_get_drvdata(func);
++ sbi_remove_card(card);
++ sdio_claim_host(func);
++ sdio_release_irq(func);
++ sdio_disable_func(func);
++ sdio_release_host(func);
++ kfree(card);
++ return;
++}
++
++static struct sdio_driver if_sdio_driver = {
++ .name = "sd8686_sdio",
++ .id_table = if_sdio_ids,
++ .probe = if_sdio_probe,
++ .remove = if_sdio_remove,
++};
++
++static int if_sdio_init_module(void)
++{
++ int ret = 0;
++
++ printk(KERN_INFO "8686 sdio: sd 8686 driver\n");
++ printk(KERN_INFO "8686 sdio: Copyright HHCN 2009\n");
++
++ ret = sdio_register_driver(&if_sdio_driver);
++
++ return ret;
++}
++
++static void if_sdio_exit_module(void)
++{
++ sdio_unregister_driver(&if_sdio_driver);
++}
++
++module_init(if_sdio_init_module);
++module_exit(if_sdio_exit_module);
++
++MODULE_DESCRIPTION("Marvell SD8686 SDIO WLAN Driver");
++MODULE_AUTHOR("You Sheng");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/net/wireless/marvell8686/if_sdio.h b/drivers/net/wireless/marvell8686/if_sdio.h
+new file mode 100644
+index 0000000..d059ccf
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/if_sdio.h
+@@ -0,0 +1,97 @@
++/** @file if_sdio.h
++ * @brief This file contains SDIO IF (interface) module
++ * related macros, enum, and structure.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++/****************************************************
++Change log:
++ 10/12/05: add Doxygen format comments
++****************************************************/
++
++#ifndef _IF_SDIO_H_
++#define _IF_SDIO_H_
++
++#include "include.h"
++#include "sdio.h"
++
++#define SD_BUS_WIDTH_1 0x00
++#define SD_BUS_WIDTH_4 0x02
++#define SD_BUS_WIDTH_MASK 0x03
++#define ASYNC_INT_MODE 0x20
++
++/* Host Control Registers */
++#define IO_PORT_0_REG 0x00
++#define IO_PORT_1_REG 0x01
++#define IO_PORT_2_REG 0x02
++#define CONFIGURATION_REG 0x03
++#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2)
++#define HOST_POWER_UP (0x1U << 1)
++#define HOST_POWER_DOWN (0x1U << 0)
++#define HOST_INT_MASK_REG 0x04
++#define UP_LD_HOST_INT_MASK (0x1U)
++#define DN_LD_HOST_INT_MASK (0x2U)
++#define HOST_INTSTATUS_REG 0x05
++#define UP_LD_HOST_INT_STATUS (0x1U)
++#define DN_LD_HOST_INT_STATUS (0x2U)
++#define HOST_INT_RSR_REG 0x06
++#define UP_LD_HOST_INT_RSR (0x1U)
++#define HOST_INT_STATUS_REG 0x07
++#define UP_LD_CRC_ERR (0x1U << 2)
++#define UP_LD_RESTART (0x1U << 1)
++#define DN_LD_RESTART (0x1U << 0)
++
++/* Card Control Registers */
++#define SQ_READ_BASE_ADDRESS_A0_REG 0x10
++#define SQ_READ_BASE_ADDRESS_A1_REG 0x11
++#define SQ_READ_BASE_ADDRESS_A2_REG 0x12
++#define SQ_READ_BASE_ADDRESS_A3_REG 0x13
++#define SQ_READ_BASE_ADDRESS_B0_REG 0x14
++#define SQ_READ_BASE_ADDRESS_B1_REG 0x15
++#define SQ_READ_BASE_ADDRESS_B2_REG 0x16
++#define SQ_READ_BASE_ADDRESS_B3_REG 0x17
++#define CARD_STATUS_REG 0x20
++#define CARD_IO_READY (0x1U << 3)
++#define CIS_CARD_RDY (0x1U << 2)
++#define UP_LD_CARD_RDY (0x1U << 1)
++#define DN_LD_CARD_RDY (0x1U << 0)
++#define HOST_INTERRUPT_MASK_REG 0x24
++#define HOST_POWER_INT_MASK (0x1U << 3)
++#define ABORT_CARD_INT_MASK (0x1U << 2)
++#define UP_LD_CARD_INT_MASK (0x1U << 1)
++#define DN_LD_CARD_INT_MASK (0x1U << 0)
++#define CARD_INTERRUPT_STATUS_REG 0x28
++#define POWER_UP_INT (0x1U << 4)
++#define POWER_DOWN_INT (0x1U << 3)
++#define CARD_INTERRUPT_RSR_REG 0x2c
++#define POWER_UP_RSR (0x1U << 4)
++#define POWER_DOWN_RSR (0x1U << 3)
++#define DEBUG_0_REG 0x30
++#define SD_TESTBUS0 (0x1U)
++#define DEBUG_1_REG 0x31
++#define SD_TESTBUS1 (0x1U)
++#define DEBUG_2_REG 0x32
++#define SD_TESTBUS2 (0x1U)
++#define DEBUG_3_REG 0x33
++#define SD_TESTBUS3 (0x1U)
++#define CARD_OCR_0_REG 0x34
++#define CARD_OCR_1_REG 0x35
++#define CARD_OCR_3_REG 0x36
++#define CARD_CONFIG_REG 0x38
++#define CARD_REVISION_REG 0x3c
++#define CMD53_FINISH_GBUS (0x1U << 1)
++#define SD_NEG_EDGE (0x1U << 0)
++
++/* Special registers in function 0 of the SDxx card */
++#define SCRATCH_0_REG 0x80fe
++#define SCRATCH_1_REG 0x80ff
++
++#define HOST_F1_RD_BASE_0 0x0010
++#define HOST_F1_RD_BASE_1 0x0011
++#define HOST_F1_CARD_RDY 0x0020
++
++/********************************************************
++ Global Functions
++********************************************************/
++
++#endif /* _IF_SDIO_H */
+diff --git a/drivers/net/wireless/marvell8686/include.h b/drivers/net/wireless/marvell8686/include.h
+new file mode 100644
+index 0000000..6bf9abe
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/include.h
+@@ -0,0 +1,42 @@
++/** @file include.h
++ *
++ * @brief This file contains all the necessary include file.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ */
++/********************************************************
++Change log:
++ 10/11/05: Add Doxygen format comments
++ 01/11/06: Conditional include file removal/addition
++ 01/30/06: Add kernel 2.6 support
++
++********************************************************/
++
++#ifndef _INCLUDE_H_
++#define _INCLUDE_H_
++
++#include "os_headers.h"
++#include "wlan_types.h"
++#include "wlan_defs.h"
++#include "wlan_thread.h"
++
++#include "wlan_wmm.h"
++#include "wlan_11d.h"
++
++#include "os_timers.h"
++
++#include "host.h"
++#include "hostcmd.h"
++
++#include "wlan_scan.h"
++#include "wlan_join.h"
++
++#include "wlan_dev.h"
++#include "os_macros.h"
++#include "sbi.h"
++
++#include "sdio.h"
++
++#include "wlan_wext.h"
++#include "wlan_decl.h"
++#endif /* _INCLUDE_H_ */
+diff --git a/drivers/net/wireless/marvell8686/os_defs.h b/drivers/net/wireless/marvell8686/os_defs.h
+new file mode 100644
+index 0000000..0529bdd
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/os_defs.h
+@@ -0,0 +1,42 @@
++/*
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++
++#ifndef _OS_HEADER1_
++#define _OS_HEADER1_
++
++typedef char CHAR;
++typedef char *PCHAR;
++typedef u8 *PUCHAR;
++typedef u16 *PUSHORT;
++typedef long *PLONG;
++typedef PLONG LONG_PTR;
++typedef u32 *ULONG_PTR;
++typedef u32 *Pu32;
++typedef unsigned int UINT;
++typedef UINT *PUINT;
++typedef void VOID;
++typedef VOID *PVOID;
++typedef int WLAN_STATUS;
++typedef u8 BOOLEAN;
++typedef BOOLEAN *PBOOLEAN;
++typedef PVOID PDRIVER_OBJECT;
++typedef PUCHAR PUNICODE_STRING;
++typedef long long LONGLONG;
++typedef LONGLONG *PLONGLONG;
++typedef unsigned long long *PULONGLONG;
++typedef PUCHAR ANSI_STRING;
++typedef ANSI_STRING *PANSI_STRING;
++typedef unsigned short WCHAR;
++typedef WCHAR *PWCHAR;
++typedef WCHAR *LPWCH, *PWCH;
++typedef WCHAR *NWPSTR;
++typedef WCHAR *LPWSTR, *PWSTR;
++typedef struct semaphore SEMAPHORE;
++
++#ifdef __KERNEL__
++typedef irqreturn_t IRQ_RET_TYPE;
++#define IRQ_RET return IRQ_HANDLED
++#endif /* __KERNEL__ */
++
++#endif /* _OS_HEADER1 */
+diff --git a/drivers/net/wireless/marvell8686/os_headers.h b/drivers/net/wireless/marvell8686/os_headers.h
+new file mode 100644
+index 0000000..872d394
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/os_headers.h
+@@ -0,0 +1,69 @@
++/*
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++
++#ifndef _OS_HEADERS_H
++#define _OS_HEADERS_H
++
++#ifndef __ATTRIB_ALIGN__
++#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
++#endif
++
++#ifndef __ATTRIB_PACK__
++#define __ATTRIB_PACK__ __attribute__ ((packed))
++#endif
++
++/* Linux header files */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/version.h>
++#include <linux/param.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/mm.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/types.h>
++#include <linux/ioport.h>
++#include <linux/pci.h>
++#include <linux/ctype.h>
++#include <linux/proc_fs.h>
++#include <linux/ptrace.h>
++#include <linux/string.h>
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
++#include <linux/config.h>
++#endif
++
++#include <linux/ioport.h>
++
++/* New Code to synchronize between IEEE Power save and PM*/
++#ifdef ENABLE_PM
++#include <linux/pm.h>
++#endif
++
++/* ASM files */
++#include <linux/semaphore.h>
++#include <asm/byteorder.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/system.h>
++
++/* Net header files */
++#include <linux/wireless.h>
++#include <linux/netdevice.h>
++#include <linux/net.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/if_arp.h>
++#include <linux/if_ether.h>
++#include <linux/etherdevice.h>
++#include <net/arp.h>
++#include <linux/rtnetlink.h>
++
++/* Wireless header */
++#include <net/iw_handler.h>
++#endif
+diff --git a/drivers/net/wireless/marvell8686/os_macros.h b/drivers/net/wireless/marvell8686/os_macros.h
+new file mode 100644
+index 0000000..945c609
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/os_macros.h
+@@ -0,0 +1,165 @@
++/*
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++#ifndef _OS_MACROS_H
++#define _OS_MACROS_H
++
++#define os_time_get() jiffies
++
++extern spinlock_t driver_lock;
++extern unsigned long driver_flags;
++#define OS_INT_DISABLE spin_lock_irqsave(&driver_lock, driver_flags)
++#define OS_INT_RESTORE spin_unlock_irqrestore(&driver_lock, driver_flags); \
++ driver_lock = SPIN_LOCK_UNLOCKED
++
++#define UpdateTransStart(dev) { \
++ dev->trans_start = jiffies; \
++}
++
++#define OS_SET_THREAD_STATE(x) set_current_state(x)
++
++#define MODULE_GET if(try_module_get(THIS_MODULE)==0) return WLAN_STATUS_FAILURE;
++#define MODULE_PUT module_put(THIS_MODULE)
++
++#define OS_INIT_SEMAPHORE(x) init_MUTEX(x)
++#define OS_ACQ_SEMAPHORE_BLOCK(x) down_interruptible(x)
++#define OS_ACQ_SEMAPHORE_NOBLOCK(x) down_trylock(x)
++#define OS_REL_SEMAPHORE(x) up(x)
++
++/* Definitions below are needed for other OS like threadx */
++#define TX_DISABLE
++#define TX_RESTORE
++#define ConfigureThreadPriority()
++#define OS_INTERRUPT_SAVE_AREA
++#define OS_FREE_LOCK(x)
++#define TX_EVENT_FLAGS_SET(x, y, z)
++
++#define os_wait_interruptible_timeout(waitq, cond, timeout) \
++ wait_event_interruptible_timeout(waitq, cond, timeout)
++
++static inline void
++os_sched_timeout(u32 millisec)
++{
++ set_current_state(TASK_INTERRUPTIBLE);
++
++ schedule_timeout((millisec * HZ) / 1000);
++}
++
++static inline void
++os_schedule(u32 millisec)
++{
++ schedule_timeout((millisec * HZ) / 1000);
++}
++
++static inline int
++CopyMulticastAddrs(wlan_adapter * Adapter, struct net_device *dev)
++{
++ int i = 0;
++ struct dev_mc_list *mcptr = dev->mc_list;
++
++ for (i = 0; i < dev->mc_count; i++) {
++ memcpy(&Adapter->MulticastList[i], mcptr->dmi_addr, ETH_ALEN);
++ mcptr = mcptr->next;
++ }
++
++ return i;
++}
++
++static inline u32
++get_utimeofday(void)
++{
++ struct timeval t;
++ u32 ut;
++
++ do_gettimeofday(&t);
++ ut = (u32) t.tv_sec * 1000000 + ((u32) t.tv_usec);
++ return ut;
++}
++
++static inline int
++os_upload_rx_packet(wlan_private * priv, struct sk_buff *skb)
++{
++
++#define IPFIELD_ALIGN_OFFSET 2
++
++ skb->dev = priv->wlan_dev.netdev;
++ skb->protocol = eth_type_trans(skb, priv->wlan_dev.netdev);
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
++
++ netif_rx(skb);
++
++ return 0;
++}
++
++static inline void
++os_free_tx_packet(wlan_private * priv)
++{
++ ulong flags;
++
++ if (priv->adapter->CurrentTxSkb) {
++ kfree_skb(priv->adapter->CurrentTxSkb);
++ spin_lock_irqsave(&priv->adapter->CurrentTxLock, flags);
++ priv->adapter->CurrentTxSkb = NULL;
++ spin_unlock_irqrestore(&priv->adapter->CurrentTxLock, flags);
++ }
++}
++
++/*
++ * netif carrier_on/off and start(wake)/stop_queue handling
++ *
++ * carrier_on carrier_off start_queue stop_queue
++ * open x(connect) x(disconnect) x
++ * close x x
++ * assoc x x
++ * deauth x x
++ * adhoc-start
++ * adhoc-join
++ * adhoc-link x x
++ * adhoc-bcnlost x x
++ * scan-begin x x
++ * scan-end x x
++ * ds-enter x x
++ * ds-exit x x
++ * xmit x
++ * xmit-done x
++ * tx-timeout
++ */
++static inline void
++os_carrier_on(wlan_private * priv)
++{
++ if (!netif_carrier_ok(priv->wlan_dev.netdev) &&
++ (priv->adapter->MediaConnectStatus == WlanMediaStateConnected) &&
++ ((priv->adapter->InfrastructureMode != Wlan802_11IBSS) ||
++ (priv->adapter->AdhocLinkSensed))) {
++ netif_carrier_on(priv->wlan_dev.netdev);
++ }
++}
++
++static inline void
++os_carrier_off(wlan_private * priv)
++{
++ if (netif_carrier_ok(priv->wlan_dev.netdev)) {
++ netif_carrier_off(priv->wlan_dev.netdev);
++ }
++}
++
++static inline void
++os_start_queue(wlan_private * priv)
++{
++ if (netif_queue_stopped(priv->wlan_dev.netdev) &&
++ (priv->adapter->MediaConnectStatus == WlanMediaStateConnected) &&
++ ((priv->adapter->InfrastructureMode != Wlan802_11IBSS) ||
++ (priv->adapter->AdhocLinkSensed))) {
++ netif_wake_queue(priv->wlan_dev.netdev);
++ }
++}
++
++static inline void
++os_stop_queue(wlan_private * priv)
++{
++ if (!netif_queue_stopped(priv->wlan_dev.netdev)) {
++ netif_stop_queue(priv->wlan_dev.netdev);
++ }
++}
++
++#endif /* _OS_MACROS_H */
+diff --git a/drivers/net/wireless/marvell8686/os_timers.h b/drivers/net/wireless/marvell8686/os_timers.h
+new file mode 100644
+index 0000000..b31387f
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/os_timers.h
+@@ -0,0 +1,83 @@
++/*
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++
++#ifndef _OS_TIMERS_H
++#define _OS_TIMERS_H
++
++typedef struct __WLAN_DRV_TIMER
++{
++ struct timer_list tl;
++ void (*timer_function) (void *context);
++ void *function_context;
++ UINT time_period;
++ BOOLEAN timer_is_periodic;
++ BOOLEAN timer_is_canceled;
++} __ATTRIB_PACK__ WLAN_DRV_TIMER, *PWLAN_DRV_TIMER;
++
++static inline void
++TimerHandler(unsigned long fcontext)
++{
++ PWLAN_DRV_TIMER timer = (PWLAN_DRV_TIMER) fcontext;
++
++ timer->timer_function(timer->function_context);
++
++ if (timer->timer_is_periodic == TRUE) {
++ mod_timer(&timer->tl, jiffies + ((timer->time_period * HZ) / 1000));
++ }
++}
++
++static inline void
++InitializeTimer(PWLAN_DRV_TIMER timer,
++ void (*TimerFunction) (void *context), void *FunctionContext)
++{
++ // first, setup the timer to trigger the WlanTimerHandler proxy
++ init_timer(&timer->tl);
++ timer->tl.function = TimerHandler;
++ timer->tl.data = (u32) timer;
++
++ // then tell the proxy which function to call and what to pass it
++ timer->timer_function = TimerFunction;
++ timer->function_context = FunctionContext;
++ timer->timer_is_canceled = FALSE;
++}
++
++static inline void
++SetTimer(PWLAN_DRV_TIMER timer, UINT MillisecondPeriod)
++{
++ timer->time_period = MillisecondPeriod;
++ timer->timer_is_periodic = FALSE;
++ timer->tl.expires = jiffies + (MillisecondPeriod * HZ) / 1000;
++ add_timer(&timer->tl);
++ timer->timer_is_canceled = FALSE;
++}
++
++static inline void
++ModTimer(PWLAN_DRV_TIMER timer, UINT MillisecondPeriod)
++{
++ timer->time_period = MillisecondPeriod;
++ timer->timer_is_periodic = FALSE;
++ mod_timer(&timer->tl, jiffies + (MillisecondPeriod * HZ) / 1000);
++ timer->timer_is_canceled = FALSE;
++}
++
++static inline void
++SetPeriodicTimer(PWLAN_DRV_TIMER timer, UINT MillisecondPeriod)
++{
++ timer->time_period = MillisecondPeriod;
++ timer->timer_is_periodic = TRUE;
++ timer->tl.expires = jiffies + (MillisecondPeriod * HZ) / 1000;
++ add_timer(&timer->tl);
++ timer->timer_is_canceled = FALSE;
++}
++
++#define FreeTimer(x) do {} while (0)
++
++static inline void
++CancelTimer(WLAN_DRV_TIMER * timer)
++{
++ del_timer(&timer->tl);
++ timer->timer_is_canceled = TRUE;
++}
++
++#endif /* _OS_TIMERS_H */
+diff --git a/drivers/net/wireless/marvell8686/release_version.h b/drivers/net/wireless/marvell8686/release_version.h
+new file mode 100644
+index 0000000..161da80
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/release_version.h
+@@ -0,0 +1,5 @@
++/**
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++
++#define DRIVER_RELEASE_VERSION "26409.p60"
+diff --git a/drivers/net/wireless/marvell8686/sbi.h b/drivers/net/wireless/marvell8686/sbi.h
+new file mode 100644
+index 0000000..29a21b0
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/sbi.h
+@@ -0,0 +1,111 @@
++/** @file sbi.h
++ *
++ * @brief This file contains IF layer definitions.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++/********************************************************
++Change log:
++ 10/11/05: Add Doxygen format comments
++ 01/05/06: Add kernel 2.6.x support
++
++********************************************************/
++
++#ifndef _SBI_H_
++#define _SBI_H_
++
++/**Bit Definition*/
++#define B_BIT_0 0x01
++#define B_BIT_1 0x02
++#define B_BIT_2 0x04
++#define B_BIT_3 0x08
++#define B_BIT_4 0x10
++#define B_BIT_5 0x20
++#define B_BIT_6 0x40
++#define B_BIT_7 0x80
++#define B_BIT_8 0x100
++#define B_BIT_9 0X200
++#define B_BIT_10 0x400
++
++/** INT Status Bit Definition*/
++#define HIS_RxUpLdRdy B_BIT_0
++#define HIS_TxDnLdRdy B_BIT_1
++#define HIS_CmdDnLdRdy B_BIT_2
++#define HIS_CardEvent B_BIT_3
++#define HIS_CmdUpLdRdy B_BIT_4
++#define HIS_WrFifoOvrflow B_BIT_5
++#define HIS_RdFifoUndrflow B_BIT_6
++#define HIS_WlanReady B_BIT_7
++
++#define HIM_DISABLE 0xff
++#define HIM_ENABLE 0x03
++
++#define FIRMWARE_READY 0xfedc
++#ifndef DEV_NAME_LEN
++#define DEV_NAME_LEN 32
++#endif
++#define MAXKEYLEN 13
++
++/* The number of times to try when polling for status bits */
++#define MAX_POLL_TRIES 1000
++
++/* The number of times to try when waiting for downloaded firmware to
++ become active. (polling the scratch register). */
++
++#define MAX_FIRMWARE_POLL_TRIES 1000
++
++#define FIRMWARE_TRANSFER_NBLOCK 1
++#define SBI_EVENT_CAUSE_SHIFT 3
++
++typedef enum _mv_sd_type
++{
++ MVSD_DAT = 0,
++ MVSD_CMD = 1,
++ MVSD_EVENT = 3
++} mv_sd_type;
++
++/** Function Prototype Declaration */
++typedef wlan_private *(*wlan_notifier_fn_add) (void *dev_id);
++typedef int (*wlan_notifier_fn_remove) (void *dev_id);
++
++typedef IRQ_RET_TYPE(*isr_notifier_fn_t) (s32 irq, void *dev_id,
++ struct pt_regs * reg);
++typedef IRQ_RET_TYPE(*handler_fn_t) (s32 irq, void *dev_id, struct pt_regs *);
++
++/* Probe and Check if the card is present*/
++int sbi_probe_card(void *card);
++int *sbi_register(wlan_notifier_fn_add, wlan_notifier_fn_remove, void *);
++int sbi_register_dev(wlan_private * priv);
++int sbi_unregister_dev(wlan_private *);
++int sbi_disable_host_int(wlan_private * priv);
++int sbi_get_int_status(wlan_private * priv, u8 *);
++void sbi_unregister(void);
++int sbi_prog_firmware(wlan_private *);
++int sbi_verify_fw_download(wlan_private *);
++
++int sbi_prog_helper(wlan_private *);
++int sbi_prog_firmware_w_helper(wlan_private *);
++
++int sbi_read_event_cause(wlan_private *);
++int sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
++int sbi_card_to_host(wlan_private * priv, u32 type, u32 * nb, u8 * payload,
++ u16 npayload);
++int sbi_enable_host_int(wlan_private *);
++
++int sbi_exit_deep_sleep(wlan_private *);
++int sbi_reset_deepsleep_wakeup(wlan_private *);
++#ifdef ENABLE_PM
++int sbi_suspend(wlan_private *);
++int sbi_resume(wlan_private *);
++#endif
++
++int sbi_read_ioreg(wlan_private * priv, u8 func, u32 reg, u8 * dat);
++int sbi_write_ioreg(wlan_private * priv, u8 func, u32 reg, u8 dat);
++int sbi_set_bus_clock(wlan_private * priv, u8 option);
++
++int sbi_get_cis_info(wlan_private * priv);
++
++int wlan_remove_card(void *card);
++wlan_private* wlan_add_card(void *card, struct device *dmdev);
++
++#endif /* _SBI_H */
+diff --git a/drivers/net/wireless/marvell8686/sdio.h b/drivers/net/wireless/marvell8686/sdio.h
+new file mode 100644
+index 0000000..e181742
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/sdio.h
+@@ -0,0 +1,112 @@
++/*File sdio.h
++ * This file contains the structure definations for the low level driver
++ * And the error response related code
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++
++#ifndef __SDIO_H__
++#define __SDIO_H__
++
++#include <linux/spinlock.h> /* For read write semaphores */
++#include <linux/semaphore.h>
++#include <linux/completion.h>
++#include <asm/dma.h>
++#ifdef CONFIG_MARVELL_8686_PROC_FS
++ #include <linux/proc_fs.h>
++#endif
++
++#include "os_defs.h"
++
++#ifdef DEBUG_SDIO_LEVEL2
++#ifndef DEBUG_LEVEL1
++#define DEBUG_LEVEL1
++#endif
++#define _ENTER() printk(KERN_DEBUG "Enter: %s, %s linux %i\n", __FUNCTION__, \
++ __FILE__, __LINE__)
++#define _LEAVE() printk(KERN_DEBUG "Leave: %s, %s linux %i\n", __FUNCTION__, \
++ __FILE__, __LINE__)
++#else
++#define _ENTER()
++#define _LEAVE()
++#endif
++
++#ifdef DEBUG_SDIO_LEVEL1
++#define _DBGMSG(x...) printk(KERN_DEBUG x)
++#define _WARNING(x...) printk(KERN_DEBUG x)
++#else
++#define _DBGMSG(x...)
++#define _WARNING(x...)
++#endif
++
++#ifdef DEBUG_SDIO_LEVEL0
++#define _PRINTK(x...) printk(x)
++#define _ERROR(x...) printk(KERN_ERR x)
++#else
++#define _PRINTK(x...)
++#define _ERROR(x...)
++#endif
++
++typedef struct _card_capability
++{
++ u8 num_of_io_funcs; /* Number of i/o functions */
++ u8 memory_yes; /* Memory present ? */
++ u16 rca; /* Relative Card Address */
++ u32 ocr; /* Operation Condition register */
++ u16 fnblksz[8];
++ u32 cisptr[8];
++} card_capability;
++
++typedef struct _dummy_tmpl
++{
++ int irq_line;
++} dummy_tmpl;
++
++typedef struct _sdio_host *mmc_controller_t;
++
++typedef enum _sdio_fsm
++{
++ SDIO_FSM_IDLE = 1,
++ SDIO_FSM_CLK_OFF,
++ SDIO_FSM_END_CMD,
++ SDIO_FSM_BUFFER_IN_TRANSIT,
++ SDIO_FSM_END_BUFFER,
++ SDIO_FSM_END_IO,
++ SDIO_FSM_END_PRG,
++ SDIO_FSM_ERROR
++} sdio_fsm_state;
++
++typedef struct _sdio_host
++{
++ char name[16];
++ int bus_width;
++} __attribute__ ((aligned)) sdio_ctrller;
++
++typedef struct _sdio_operations
++{
++ char name[16];
++} sdio_operations;
++
++typedef struct _iorw_extended_t
++{
++ u8 rw_flag; /** If 0 command is READ; else if 1 command is WRITE */
++ u8 func_num;
++ u8 blkmode;
++ u8 op_code;
++ u32 reg_addr;
++ u32 byte_cnt;
++ u32 blk_size;
++ u8 *buf;
++} iorw_extended_t;
++
++#define BUS_INTERFACE_CONTROL_REG 0x07
++#define CARD_CAPABILITY_REG 0x08
++#define COMMON_CIS_POINTER_0_REG 0x09
++#define COMMON_CIS_POINTER_1_REG 0x0a
++#define COMMON_CIS_POINTER_2_REG 0x0b
++#define BUS_SUSPEND_REG 0x0c
++#define FUNCTION_SELECT_REG 0x0d
++#define EXEC_FLAGS_REG 0x0e
++#define READY_FLAGS_REG 0x0f
++
++#endif /* __SDIO__H */
+diff --git a/drivers/net/wireless/marvell8686/wlan_11d.c b/drivers/net/wireless/marvell8686/wlan_11d.c
+new file mode 100644
+index 0000000..0dbcf49
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_11d.c
+@@ -0,0 +1,893 @@
++/** @file wlan_11d.c
++ * @brief This file contains functions for 802.11D.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++/********************************************************
++Change log:
++ 10/04/05: Add Doxygen format comments
++
++********************************************************/
++#include "include.h"
++
++/********************************************************
++ Local Variables
++********************************************************/
++#define TX_PWR_DEFAULT 10
++
++static region_code_mapping_t region_code_mapping[] = {
++ {"US ", 0x10}, /* US FCC */
++ {"CA ", 0x20}, /* IC Canada */
++ {"SG ", 0x10}, /* Singapore */
++ {"EU ", 0x30}, /* ETSI */
++ {"AU ", 0x30}, /* Australia */
++ {"KR ", 0x30}, /* Republic Of Korea */
++ {"FR ", 0x32}, /* France */
++ {"JP ", 0x40}, /* Japan */
++ {"JP ", 0x41}, /* Japan */
++};
++
++/********************************************************
++ Global Variables
++********************************************************/
++/* Following 2 structure defines the supported channels */
++CHANNEL_FREQ_POWER channel_freq_power_UN_BG[] = {
++ {1, 2412, TX_PWR_DEFAULT},
++ {2, 2417, TX_PWR_DEFAULT},
++ {3, 2422, TX_PWR_DEFAULT},
++ {4, 2427, TX_PWR_DEFAULT},
++ {5, 2432, TX_PWR_DEFAULT},
++ {6, 2437, TX_PWR_DEFAULT},
++ {7, 2442, TX_PWR_DEFAULT},
++ {8, 2447, TX_PWR_DEFAULT},
++ {9, 2452, TX_PWR_DEFAULT},
++ {10, 2457, TX_PWR_DEFAULT},
++ {11, 2462, TX_PWR_DEFAULT},
++ {12, 2467, TX_PWR_DEFAULT},
++ {13, 2472, TX_PWR_DEFAULT},
++ {14, 2484, TX_PWR_DEFAULT}
++};
++
++CHANNEL_FREQ_POWER channel_freq_power_UN_AJ[] = {
++ {8, 5040, TX_PWR_DEFAULT},
++ {12, 5060, TX_PWR_DEFAULT},
++ {16, 5080, TX_PWR_DEFAULT},
++ {34, 5170, TX_PWR_DEFAULT},
++ {38, 5190, TX_PWR_DEFAULT},
++ {42, 5210, TX_PWR_DEFAULT},
++ {46, 5230, TX_PWR_DEFAULT},
++ {36, 5180, TX_PWR_DEFAULT},
++ {40, 5200, TX_PWR_DEFAULT},
++ {44, 5220, TX_PWR_DEFAULT},
++ {48, 5240, TX_PWR_DEFAULT},
++ {52, 5260, TX_PWR_DEFAULT},
++ {56, 5280, TX_PWR_DEFAULT},
++ {60, 5300, TX_PWR_DEFAULT},
++ {64, 5320, TX_PWR_DEFAULT},
++ {100, 5500, TX_PWR_DEFAULT},
++ {104, 5520, TX_PWR_DEFAULT},
++ {108, 5540, TX_PWR_DEFAULT},
++ {112, 5560, TX_PWR_DEFAULT},
++ {116, 5580, TX_PWR_DEFAULT},
++ {120, 5600, TX_PWR_DEFAULT},
++ {124, 5620, TX_PWR_DEFAULT},
++ {128, 5640, TX_PWR_DEFAULT},
++ {132, 5660, TX_PWR_DEFAULT},
++ {136, 5680, TX_PWR_DEFAULT},
++ {140, 5700, TX_PWR_DEFAULT},
++ {149, 5745, TX_PWR_DEFAULT},
++ {153, 5765, TX_PWR_DEFAULT},
++ {157, 5785, TX_PWR_DEFAULT},
++ {161, 5805, TX_PWR_DEFAULT},
++ {165, 5825, TX_PWR_DEFAULT},
++/* {240, 4920, TX_PWR_DEFAULT},
++ {244, 4940, TX_PWR_DEFAULT},
++ {248, 4960, TX_PWR_DEFAULT},
++ {252, 4980, TX_PWR_DEFAULT},
++channels for 11J JP 10M channel gap */
++};
++
++extern CHANNEL_FREQ_POWER *wlan_get_region_cfp_table(u8 region,
++ u8 band, int *cfp_no);
++
++/********************************************************
++ Local Functions
++********************************************************/
++/**
++ * @brief This function convert Region string to code integer
++ * @param region region string
++ * @return region id
++*/
++static u8
++wlan_region_2_code(s8 * region)
++{
++ u8 i;
++ u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
++
++ for (i = 0; i < COUNTRY_CODE_LEN && region[i]; i++)
++ region[i] = toupper(region[i]);
++
++ for (i = 0; i < size; i++) {
++ if (!memcmp(region, region_code_mapping[i].region, COUNTRY_CODE_LEN))
++ return (region_code_mapping[i].code);
++ }
++
++ /* default is US */
++ return (region_code_mapping[0].code);
++}
++
++/**
++ * @brief This function converts interger code to region string
++ * @param code region code
++ * @return region string
++*/
++static u8 *
++wlan_code_2_region(u8 code)
++{
++ u8 i;
++ u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
++ for (i = 0; i < size; i++) {
++ if (region_code_mapping[i].code == code)
++ return (region_code_mapping[i].region);
++ }
++ /* default is US */
++ return (region_code_mapping[0].region);
++}
++
++/**
++ * @brief This function finds the NoOfChan-th chan after the firstChan
++ * @param band band
++ * @param firstChan first channel number
++ * @param NoOfChan number of channels
++ * @return the NoOfChan-th chan number
++*/
++static BOOLEAN
++wlan_get_chan_11d(u8 band, u8 firstChan, u8 NoOfChan, u8 * chan)
++/*find the NoOfChan-th chan after the firstChan*/
++{
++ u8 i;
++ CHANNEL_FREQ_POWER *cfp;
++ u8 cfp_no;
++
++ ENTER();
++
++ {
++ cfp = channel_freq_power_UN_BG;
++ cfp_no = sizeof(channel_freq_power_UN_BG) /
++ sizeof(CHANNEL_FREQ_POWER);
++ }
++
++ for (i = 0; i < cfp_no; i++) {
++ if ((cfp + i)->Channel == firstChan) {
++ PRINTM(INFO, "firstChan found\n");
++ break;
++ }
++ }
++
++ if (i < cfp_no) {
++ /*if beyond the boundary */
++ if (i + NoOfChan < cfp_no) {
++ *chan = (cfp + i + NoOfChan)->Channel;
++ return TRUE;
++ }
++ }
++
++ LEAVE();
++ return FALSE;
++}
++
++/**
++ * @brief This function Checks if chan txpwr is learned from AP/IBSS
++ * @param chan chan number
++ * @param parsed_region_chan pointer to parsed_region_chan_11d_t
++ * @return TRUE; FALSE
++*/
++BOOLEAN
++wlan_channel_known_11d(u8 chan, parsed_region_chan_11d_t * parsed_region_chan)
++{
++ chan_power_11d_t *chanPwr = parsed_region_chan->chanPwr;
++ u8 NoOfChan = parsed_region_chan->NoOfChan;
++ u8 i = 0;
++
++ ENTER();
++ HEXDUMP("11D:parsed_region_chan:", (char *) chanPwr,
++ sizeof(chan_power_11d_t) * NoOfChan);
++
++ for (i = 0; i < NoOfChan; i++) {
++ if (chan == chanPwr[i].chan) {
++ PRINTM(INFO, "11D: Found Chan:%d\n", chan);
++ LEAVE();
++ return TRUE;
++ }
++ }
++
++ PRINTM(INFO, "11D: Not Find Chan:%d\n", chan);
++ LEAVE();
++ return FALSE;
++}
++
++/********************************************************
++ Global Functions
++********************************************************/
++
++/**
++ * @brief This function Converts chan to frequency
++ * @param chan channel number
++ * @param band band
++ * @return channel frequency
++*/
++u32
++chan_2_freq(u8 chan, u8 band)
++{
++ CHANNEL_FREQ_POWER *cf;
++ u16 cnt;
++ u16 i;
++ u32 freq = 0;
++
++ ENTER();
++
++ {
++ cf = channel_freq_power_UN_BG;
++ cnt = sizeof(channel_freq_power_UN_BG) / sizeof(CHANNEL_FREQ_POWER);
++ }
++
++ for (i = 0; i < cnt; i++) {
++ if (chan == cf[i].Channel)
++ freq = cf[i].Freq;
++ }
++
++ LEAVE();
++ return freq;
++}
++
++/**
++ * @brief This function generates domaininfo from parsed_region_chan
++ * @param parsed_region_chan pointer to parsed_region_chan_11d_t
++ * @param domaininfo pointer to wlan_802_11d_domain_reg_t
++ * @return WLAN_STATUS_SUCCESS
++*/
++int
++wlan_generate_domain_info_11d(parsed_region_chan_11d_t * parsed_region_chan,
++ wlan_802_11d_domain_reg_t * domaininfo)
++{
++ u8 NoOfSubband = 0;
++
++ u8 NoOfChan = parsed_region_chan->NoOfChan;
++ u8 NoOfParsedChan = 0;
++
++ u8 firstChan = 0, nextChan = 0, maxPwr = 0;
++
++ u8 i, flag = 0;
++
++ ENTER();
++
++ memcpy(domaininfo->CountryCode, parsed_region_chan->CountryCode,
++ COUNTRY_CODE_LEN);
++
++ PRINTM(INFO, "11D:NoOfChan=%d\n", NoOfChan);
++ HEXDUMP("11D:parsed_region_chan:", (char *) parsed_region_chan,
++ sizeof(parsed_region_chan_11d_t));
++
++ for (i = 0; i < NoOfChan; i++) {
++ if (!flag) {
++ flag = 1;
++ nextChan = firstChan = parsed_region_chan->chanPwr[i].chan;
++ maxPwr = parsed_region_chan->chanPwr[i].pwr;
++ NoOfParsedChan = 1;
++ continue;
++ }
++
++ if (parsed_region_chan->chanPwr[i].chan == nextChan + 1 &&
++ parsed_region_chan->chanPwr[i].pwr == maxPwr) {
++ nextChan++;
++ NoOfParsedChan++;
++ } else {
++ domaininfo->Subband[NoOfSubband].FirstChan = firstChan;
++ domaininfo->Subband[NoOfSubband].NoOfChan = NoOfParsedChan;
++ domaininfo->Subband[NoOfSubband].MaxTxPwr = maxPwr;
++ NoOfSubband++;
++ NoOfParsedChan = 1;
++ nextChan = firstChan = parsed_region_chan->chanPwr[i].chan;
++ maxPwr = parsed_region_chan->chanPwr[i].pwr;
++ }
++ }
++
++ if (flag) {
++ domaininfo->Subband[NoOfSubband].FirstChan = firstChan;
++ domaininfo->Subband[NoOfSubband].NoOfChan = NoOfParsedChan;
++ domaininfo->Subband[NoOfSubband].MaxTxPwr = maxPwr;
++ NoOfSubband++;
++ }
++ domaininfo->NoOfSubband = NoOfSubband;
++
++ PRINTM(INFO, "NoOfSubband=%x\n", domaininfo->NoOfSubband);
++ HEXDUMP("11D:domaininfo:", (char *) domaininfo,
++ COUNTRY_CODE_LEN + 1 +
++ sizeof(IEEEtypes_SubbandSet_t) * NoOfSubband);
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
++ * @param region_chan pointer to REGION_CHANNEL
++ * @param *parsed_region_chan pointer to parsed_region_chan_11d_t
++ * @return N/A
++*/
++void
++wlan_generate_parsed_region_chan_11d(REGION_CHANNEL * region_chan,
++ parsed_region_chan_11d_t *
++ parsed_region_chan)
++{
++ u8 i;
++ CHANNEL_FREQ_POWER *cfp;
++
++ ENTER();
++
++ if (region_chan == NULL) {
++ PRINTM(INFO, "11D: region_chan is NULL\n");
++ return;
++ }
++
++ cfp = region_chan->CFP;
++ if (cfp == NULL) {
++ PRINTM(INFO, "11D: cfp equal NULL \n");
++ return;
++ }
++
++ parsed_region_chan->band = region_chan->Band;
++ parsed_region_chan->region = region_chan->Region;
++ memcpy(parsed_region_chan->CountryCode,
++ wlan_code_2_region(region_chan->Region), COUNTRY_CODE_LEN);
++
++ PRINTM(INFO, "11D: region[0x%x] band[%d]\n", parsed_region_chan->region,
++ parsed_region_chan->band);
++
++ for (i = 0; i < region_chan->NrCFP; i++, cfp++) {
++ parsed_region_chan->chanPwr[i].chan = cfp->Channel;
++ parsed_region_chan->chanPwr[i].pwr = cfp->MaxTxPower;
++ PRINTM(INFO, "11D: Chan[%d] Pwr[%d]\n",
++ parsed_region_chan->chanPwr[i].chan,
++ parsed_region_chan->chanPwr[i].pwr);
++ }
++ parsed_region_chan->NoOfChan = region_chan->NrCFP;
++
++ PRINTM(INFO, "11D: NoOfChan[%d]\n", parsed_region_chan->NoOfChan);
++
++ LEAVE();
++ return;
++}
++
++/**
++ * @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
++ * @param region region ID
++ * @param band band
++ * @param chan chan
++ * @return TRUE;FALSE
++*/
++BOOLEAN
++wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan)
++{
++ CHANNEL_FREQ_POWER *cfp;
++ int cfp_no;
++ u8 idx;
++
++ ENTER();
++
++ if ((cfp = wlan_get_region_cfp_table(region, band, &cfp_no)) == NULL) {
++ return FALSE;
++ }
++
++ for (idx = 0; idx < cfp_no; idx++) {
++ if (chan == (cfp + idx)->Channel) {
++ /* If Mrvl Chip Supported? */
++ if ((cfp + idx)->Unsupported) {
++ return FALSE;
++ } else {
++ return TRUE;
++ }
++ }
++ }
++
++ /*chan is not in the region table */
++ LEAVE();
++ return FALSE;
++}
++
++/**
++ * @brief This function checks if chan txpwr is learned from AP/IBSS
++ * @param chan chan number
++ * @param parsed_region_chan pointer to parsed_region_chan_11d_t
++ * @return WLAN_STATUS_SUCCESS
++*/
++int
++wlan_parse_domain_info_11d(IEEEtypes_CountryInfoFullSet_t * CountryInfo,
++ u8 band,
++ parsed_region_chan_11d_t * parsed_region_chan)
++{
++ u8 NoOfSubband, NoOfChan;
++ u8 lastChan, firstChan, curChan;
++ u8 region;
++
++ u8 idx = 0; /*chan index in parsed_region_chan */
++
++ u8 j, i;
++
++ ENTER();
++
++ /*Validation Rules:
++ 1. Valid Region Code
++ 2. First Chan increment
++ 3. Channel range no overlap
++ 4. Channel is valid?
++ 5. Channel is supported by Region?
++ 6. Others
++ */
++
++ HEXDUMP("CountryInfo:", (s8 *) CountryInfo, 30);
++
++ if ((*(CountryInfo->CountryCode)) == 0 ||
++ (CountryInfo->Len <= COUNTRY_CODE_LEN)) {
++ /* No region Info or Wrong region info: treat as No 11D info */
++ LEAVE();
++ return WLAN_STATUS_FAILURE;
++ }
++
++ /*Step1: check region_code */
++ parsed_region_chan->region = region =
++ wlan_region_2_code((s8 *) CountryInfo->CountryCode);
++
++ PRINTM(INFO, "regioncode=%x\n", (u8) parsed_region_chan->region);
++ HEXDUMP("CountryCode:", (char *) CountryInfo->CountryCode,
++ COUNTRY_CODE_LEN);
++
++ parsed_region_chan->band = band;
++
++ memcpy(parsed_region_chan->CountryCode, CountryInfo->CountryCode,
++ COUNTRY_CODE_LEN);
++
++ NoOfSubband = (CountryInfo->Len - COUNTRY_CODE_LEN) /
++ sizeof(IEEEtypes_SubbandSet_t);
++
++ for (j = 0, lastChan = 0; j < NoOfSubband; j++) {
++
++ if (CountryInfo->Subband[j].FirstChan <= lastChan) {
++ /*Step2&3. Check First Chan Num increment and no overlap */
++ PRINTM(INFO, "11D: Chan[%d>%d] Overlap\n",
++ CountryInfo->Subband[j].FirstChan, lastChan);
++ continue;
++ }
++
++ firstChan = CountryInfo->Subband[j].FirstChan;
++ NoOfChan = CountryInfo->Subband[j].NoOfChan;
++
++ for (i = 0; idx < MAX_NO_OF_CHAN && i < NoOfChan; i++) {
++ /*step4: channel is supported? */
++
++ if (wlan_get_chan_11d(band, firstChan, i, &curChan)
++ == FALSE) {
++ /* Chan is not found in UN table */
++ PRINTM(INFO, "chan is not supported: %d \n", i);
++ break;
++ }
++
++ lastChan = curChan;
++
++ /*step5: We don't need to Check if curChan is supported by mrvl in region */
++ parsed_region_chan->chanPwr[idx].chan = curChan;
++ parsed_region_chan->chanPwr[idx].pwr =
++ CountryInfo->Subband[j].MaxTxPwr;
++ idx++;
++ }
++
++ /*Step6: Add other checking if any */
++
++ }
++
++ parsed_region_chan->NoOfChan = idx;
++
++ PRINTM(INFO, "NoOfChan=%x\n", parsed_region_chan->NoOfChan);
++ HEXDUMP("11D:parsed_region_chan:", (s8 *) parsed_region_chan,
++ 2 + COUNTRY_CODE_LEN + sizeof(parsed_region_chan_11d_t) * idx);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function calculates the scan type for channels
++ * @param chan chan number
++ * @param parsed_region_chan pointer to parsed_region_chan_11d_t
++ * @return PASSIVE if chan is unknown; ACTIVE if chan is known
++*/
++u8
++wlan_get_scan_type_11d(u8 chan, parsed_region_chan_11d_t * parsed_region_chan)
++{
++ u8 scan_type = HostCmd_SCAN_TYPE_PASSIVE;
++
++ ENTER();
++
++ if (wlan_channel_known_11d(chan, parsed_region_chan)) {
++ PRINTM(INFO, "11D: Found and do Active Scan\n");
++ scan_type = HostCmd_SCAN_TYPE_ACTIVE;
++ } else {
++ PRINTM(INFO, "11D: Not Find and do Passive Scan\n");
++ }
++
++ LEAVE();
++ return scan_type;
++
++}
++
++/**
++ * @brief This function gets if 11D is enabled
++ * @param priv pointer to wlan_private
++ * @return ENABLE_11D;DISABLE_11D
++*/
++state_11d_t
++wlan_get_state_11d(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ wlan_802_11d_state_t *state = &Adapter->State11D;
++ return (state->Enable11D);
++}
++
++/**
++ * @brief initialize internal variable for 11D
++ * @param priv pointer to wlan_private
++ * @return N/A
++*/
++void
++wlan_init_11d(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ wlan_802_11d_state_t *state = &Adapter->State11D;
++
++ state->Enable11D = DISABLE_11D;
++
++ memset(&(priv->adapter->parsed_region_chan), 0,
++ sizeof(parsed_region_chan_11d_t));
++
++ return;
++}
++
++/**
++ * @brief This function enable/disable 11D
++ * @param priv pointer to wlan_private
++ * @param flag enable/disable flag
++ * @return WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
++*/
++int
++wlan_enable_11d(wlan_private * priv, state_11d_t flag)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ wlan_802_11d_state_t *state = &Adapter->State11D;
++ int ret;
++ state_11d_t enable = flag;
++
++ ENTER();
++
++ state->Enable11D = flag;
++
++ /* send cmd to FW to enable/disable 11D fucntion in FW */
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_SNMP_MIB,
++ HostCmd_ACT_SET,
++ HostCmd_OPTION_WAITFORRSP,
++ OID_802_11D_ENABLE, &enable);
++ if (ret) {
++ PRINTM(INFO, "11D: Fail to enable 11D \n");
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function sets DOMAIN INFO to FW
++ * @param priv pointer to wlan_private
++ * @return WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
++*/
++int
++wlan_set_domain_info_11d(wlan_private * priv)
++{
++ int ret;
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
++ HostCmd_ACT_GEN_SET,
++ HostCmd_OPTION_WAITFORRSP, 0, NULL);
++ if (ret) {
++ PRINTM(INFO, "11D: Fail to dnld domain Info\n");
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function setups scan channels
++ * @param priv pointer to wlan_private
++ * @param band band
++ * @return WLAN_STATUS_SUCCESS
++*/
++int
++wlan_set_universaltable(wlan_private * priv, u8 band)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ u16 size = sizeof(CHANNEL_FREQ_POWER);
++ u16 i = 0;
++
++ ENTER();
++
++ memset(Adapter->universal_channel, 0, sizeof(Adapter->universal_channel));
++
++ {
++ Adapter->universal_channel[i].NrCFP =
++ sizeof(channel_freq_power_UN_BG) / size;
++ PRINTM(INFO, "11D: BG-band NrCFP=%d\n",
++ Adapter->universal_channel[i].NrCFP);
++
++ Adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
++ Adapter->universal_channel[i].Valid = TRUE;
++ Adapter->universal_channel[i].Region = UNIVERSAL_REGION_CODE;
++ Adapter->universal_channel[i].Band = band;
++ i++;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function implements command CMD_802_11D_DOMAIN_INFO
++ * @param priv pointer to wlan_private
++ * @param cmd pointer to cmd buffer
++ * @param cmdno cmd ID
++ * @param CmdOption cmd action
++ * @return WLAN_STATUS_SUCCESS
++*/
++int
++wlan_cmd_802_11d_domain_info(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, u16 cmdno,
++ u16 CmdOption)
++{
++ HostCmd_DS_802_11D_DOMAIN_INFO *pDomainInfo = &cmd->params.domaininfo;
++ MrvlIEtypes_DomainParamSet_t *domain = &pDomainInfo->Domain;
++ wlan_adapter *Adapter = priv->adapter;
++ u8 NoOfSubband = Adapter->DomainReg.NoOfSubband;
++
++ ENTER();
++
++ PRINTM(INFO, "NoOfSubband=%x\n", NoOfSubband);
++
++ cmd->Command = wlan_cpu_to_le16(cmdno);
++ pDomainInfo->Action = wlan_cpu_to_le16(CmdOption);
++ if (CmdOption == HostCmd_ACT_GET) {
++ cmd->Size = wlan_cpu_to_le16(sizeof(pDomainInfo->Action) + S_DS_GEN);
++ HEXDUMP("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd, (int) (cmd->Size));
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++ }
++
++ domain->Header.Type = wlan_cpu_to_le16(TLV_TYPE_DOMAIN);
++ memcpy(domain->CountryCode, Adapter->DomainReg.CountryCode,
++ sizeof(domain->CountryCode));
++
++ domain->Header.Len =
++ wlan_cpu_to_le16(NoOfSubband * sizeof(IEEEtypes_SubbandSet_t) +
++ sizeof(domain->CountryCode));
++
++ if (NoOfSubband) {
++ memcpy(domain->Subband, Adapter->DomainReg.Subband,
++ NoOfSubband * sizeof(IEEEtypes_SubbandSet_t));
++
++ cmd->Size = wlan_cpu_to_le16(sizeof(pDomainInfo->Action) +
++ domain->Header.Len +
++ sizeof(MrvlIEtypesHeader_t) + S_DS_GEN);
++ } else {
++ cmd->Size = wlan_cpu_to_le16(sizeof(pDomainInfo->Action) + S_DS_GEN);
++ }
++
++ HEXDUMP("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, (int) (cmd->Size));
++
++ LEAVE();
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function implements private cmd: enable/disable 11D
++ * @param priv pointer to wlan_private
++ * @param wrq pointer to user data
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq)
++{
++ int data = 0;
++ int *val;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
++
++ PRINTM(INFO, "Enable 11D: %s\n",
++ (data == CMD_ENABLED) ? "Enable" : "Disable");
++ switch (data) {
++ case CMD_ENABLED:
++ wlan_enable_11d(priv, ENABLE_11D);
++ break;
++ case CMD_DISABLED:
++ wlan_enable_11d(priv, DISABLE_11D);
++ break;
++ default:
++ break;
++ }
++
++ data =
++ (Adapter->State11D.Enable11D ==
++ ENABLE_11D) ? CMD_ENABLED : CMD_DISABLED;
++ val = (int *) wrq->u.name;
++ *val = data;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function parses countryinfo from AP and download country info to FW
++ * @param priv pointer to wlan_private
++ * @param resp pointer to command response buffer
++ * @return WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
++ */
++int
++wlan_ret_802_11d_domain_info(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_802_11D_DOMAIN_INFO_RSP
++ * domaininfo = &resp->params.domaininforesp;
++ MrvlIEtypes_DomainParamSet_t * domain = &domaininfo->Domain;
++ u16 Action = wlan_le16_to_cpu(domaininfo->Action);
++ s16 ret = WLAN_STATUS_SUCCESS;
++ u8 NoOfSubband = 0;
++
++ ENTER();
++
++ HEXDUMP("11D DOMAIN Info Rsp Data:", (u8 *) resp, resp->Size);
++
++ NoOfSubband =
++ (wlan_le16_to_cpu(domain->Header.Len) -
++ 3) / sizeof(IEEEtypes_SubbandSet_t);
++ /* countrycode 3 bytes */
++
++ PRINTM(INFO, "11D Domain Info Resp: NoOfSubband=%d\n", NoOfSubband);
++
++ if (NoOfSubband > MRVDRV_MAX_SUBBAND_802_11D) {
++ PRINTM(INFO, "Invalid Numrer of Subband returned!!\n");
++ return WLAN_STATUS_FAILURE;
++ }
++
++ switch (Action) {
++ case HostCmd_ACT_SET: /*Proc Set Action */
++ break;
++
++ case HostCmd_ACT_GET:
++ break;
++ default:
++ PRINTM(INFO, "Invalid Action:%d\n", domaininfo->Action);
++ ret = WLAN_STATUS_FAILURE;
++ break;
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function parses countryinfo from AP and download country info to FW
++ * @param priv pointer to wlan_private
++ * @return WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
++ */
++int
++wlan_parse_dnld_countryinfo_11d(wlan_private * priv)
++{
++ int ret;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ /* Skip new 11d download when roaming */
++ return WLAN_STATUS_SUCCESS;
++ }
++
++ if (wlan_get_state_11d(priv) == ENABLE_11D) {
++
++ memset(&Adapter->parsed_region_chan, 0,
++ sizeof(parsed_region_chan_11d_t));
++
++ ret =
++ wlan_parse_domain_info_11d(&Adapter->pAttemptedBSSDesc->
++ CountryInfo, 0,
++ &Adapter->parsed_region_chan);
++
++ if (ret == WLAN_STATUS_FAILURE) {
++ PRINTM(INFO, "11D: No region info in the AP BssDesc..\n");
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++ }
++
++ memset(&Adapter->DomainReg, 0, sizeof(wlan_802_11d_domain_reg_t));
++ wlan_generate_domain_info_11d(&Adapter->parsed_region_chan,
++ &Adapter->DomainReg);
++
++ ret = wlan_set_domain_info_11d(priv);
++
++ if (ret) {
++ PRINTM(INFO, "11D: Err set domainInfo to FW\n");
++ LEAVE();
++ return ret;
++ }
++ }
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function generates 11D info from user specified regioncode and download to FW
++ * @param priv pointer to wlan_private
++ * @return WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
++ */
++int
++wlan_create_dnld_countryinfo_11d(wlan_private * priv, u8 band)
++{
++ int ret;
++ wlan_adapter *Adapter = priv->adapter;
++ REGION_CHANNEL *region_chan;
++ u8 j;
++
++ ENTER();
++ PRINTM(INFO, "11D:Band[%d]\n", band);
++
++ /* update parsed_region_chan_11; dnld domaininf to FW */
++
++ for (j = 0; j < sizeof(Adapter->region_channel) /
++ sizeof(Adapter->region_channel[0]); j++) {
++ region_chan = &Adapter->region_channel[j];
++
++ PRINTM(INFO, "11D:[%d] region_chan->Band[%d]\n", j,
++ region_chan->Band);
++
++ if (!region_chan || !region_chan->Valid || !region_chan->CFP)
++ continue;
++ if (region_chan->Band != band)
++ continue;
++ break;
++ }
++
++ if (j >= sizeof(Adapter->region_channel) /
++ sizeof(Adapter->region_channel[0])) {
++ PRINTM(INFO, "11D:region_chan not found. Band[%d]\n", band);
++ LEAVE();
++ return WLAN_STATUS_FAILURE;
++ }
++
++ memset(&Adapter->parsed_region_chan, 0, sizeof(parsed_region_chan_11d_t));
++ wlan_generate_parsed_region_chan_11d(region_chan,
++ &Adapter->parsed_region_chan);
++
++ memset(&Adapter->DomainReg, 0, sizeof(wlan_802_11d_domain_reg_t));
++ wlan_generate_domain_info_11d(&Adapter->parsed_region_chan,
++ &Adapter->DomainReg);
++
++ ret = wlan_set_domain_info_11d(priv);
++
++ if (ret) {
++ PRINTM(INFO, "11D: Err set domainInfo to FW\n");
++ LEAVE();
++ return ret;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
+diff --git a/drivers/net/wireless/marvell8686/wlan_11d.h b/drivers/net/wireless/marvell8686/wlan_11d.h
+new file mode 100644
+index 0000000..208f64b
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_11d.h
+@@ -0,0 +1,110 @@
++/** @file wlan_11d.h
++ * @brief This header file contains data structures and
++ * function declarations of 802.11d
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++/*************************************************************
++Change log:
++ 09/26/05: add Doxygen format comments
++ ************************************************************/
++
++#ifndef _WLAN_11D_
++#define _WLAN_11D_
++
++#define MAX_CHAN_NUM 255
++
++#define UNIVERSAL_REGION_CODE 0xff
++
++/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr)
++ */
++#define MAX_NO_OF_CHAN 40
++
++typedef struct _REGION_CHANNEL *PREGION_CHANNEL;
++
++typedef enum
++{
++ DISABLE_11D = 0,
++ ENABLE_11D = 1,
++} state_11d_t;
++
++/** domain regulatory information */
++typedef struct _wlan_802_11d_domain_reg
++{
++ /** country Code*/
++ u8 CountryCode[COUNTRY_CODE_LEN];
++ /** No. of subband*/
++ u8 NoOfSubband;
++ IEEEtypes_SubbandSet_t Subband[MRVDRV_MAX_SUBBAND_802_11D];
++} wlan_802_11d_domain_reg_t;
++
++typedef struct _chan_power_11d
++{
++ u8 chan;
++ u8 pwr;
++} __ATTRIB_PACK__ chan_power_11d_t;
++
++typedef struct _parsed_region_chan_11d
++{
++ u8 band;
++ u8 region;
++ s8 CountryCode[COUNTRY_CODE_LEN];
++ chan_power_11d_t chanPwr[MAX_NO_OF_CHAN];
++ u8 NoOfChan;
++} __ATTRIB_PACK__ parsed_region_chan_11d_t;
++
++/** Data for state machine */
++typedef struct _wlan_802_11d_state
++{
++ /** True for Enabling 11D*/
++ BOOLEAN Enable11D;
++} wlan_802_11d_state_t;
++
++typedef struct _region_code_mapping
++{
++ s8 region[COUNTRY_CODE_LEN];
++ u8 code;
++} region_code_mapping_t;
++
++/* function prototypes*/
++int wlan_generate_domain_info_11d(parsed_region_chan_11d_t *
++ parsed_region_chan,
++ wlan_802_11d_domain_reg_t * domaininfo);
++
++int wlan_parse_domain_info_11d(IEEEtypes_CountryInfoFullSet_t * CountryInfo,
++ u8 band,
++ parsed_region_chan_11d_t * parsed_region_chan);
++
++u8 wlan_get_scan_type_11d(u8 chan,
++ parsed_region_chan_11d_t * parsed_region_chan);
++
++u32 chan_2_freq(u8 chan, u8 band);
++
++int wlan_set_domain_info_11d(wlan_private * priv);
++
++state_11d_t wlan_get_state_11d(wlan_private * priv);
++
++void wlan_init_11d(wlan_private * priv);
++
++int wlan_enable_11d(wlan_private * priv, state_11d_t flag);
++
++int wlan_set_universaltable(wlan_private * priv, u8 band);
++
++void wlan_generate_parsed_region_chan_11d(PREGION_CHANNEL region_chan,
++ parsed_region_chan_11d_t *
++ parsed_region_chan);
++
++int wlan_cmd_802_11d_domain_info(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, u16 cmdno,
++ u16 CmdOption);
++
++int wlan_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq);
++
++int wlan_ret_802_11d_domain_info(wlan_private * priv,
++ HostCmd_DS_COMMAND * resp);
++
++int wlan_parse_dnld_countryinfo_11d(wlan_private * priv);
++
++int wlan_create_dnld_countryinfo_11d(wlan_private * priv, u8 band);
++
++#endif /* _WLAN_11D_ */
+diff --git a/drivers/net/wireless/marvell8686/wlan_cmd.c b/drivers/net/wireless/marvell8686/wlan_cmd.c
+new file mode 100644
+index 0000000..2d5bf55
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_cmd.c
+@@ -0,0 +1,2501 @@
++/** @file wlan_cmd.c
++ *
++ * @brief This file contains the handling of command.
++ * it prepares command and sends it to firmware when
++ * it is ready.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ *
++ */
++/********************************************************
++Change log:
++ 10/04/05: Add Doxygen format comments
++ 01/05/06: Add kernel 2.6.x support
++ 01/11/06: Conditionalize new scan/join structures
++ 01/31/06: Add support to selectively enabe the FW Scan channel filter
++ 02/16/06: Clear scan in progress flag when scan command failed and dropped
++ 04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
++ 04/18/06: Remove old Subscrive Event and add new Subscribe Event
++ implementation through generic hostcmd API
++ 05/04/06: Add IBSS coalescing related new hostcmd handling
++ 08/29/06: Add ledgpio private command
++********************************************************/
++
++#include "include.h"
++
++/********************************************************
++ Local Variables
++********************************************************/
++
++static u16 Commands_Allowed_In_PS[] = {
++ HostCmd_CMD_802_11_RSSI,
++ HostCmd_CMD_802_11_HOST_SLEEP_CFG,
++ HostCmd_CMD_802_11_WAKEUP_CONFIRM,
++};
++
++/********************************************************
++ Global Variables
++********************************************************/
++
++/********************************************************
++ Local Functions
++********************************************************/
++
++/**
++ * @brief This function checks if the commans is allowed
++ * in PS mode not.
++ *
++ * @param Command the command ID
++ * @return TRUE or FALSE
++ */
++static BOOLEAN
++Is_Command_Allowed_In_PS(u16 Command)
++{
++ int count = sizeof(Commands_Allowed_In_PS)
++ / sizeof(Commands_Allowed_In_PS[0]);
++ int i;
++
++ for (i = 0; i < count; i++) {
++ if (Command == wlan_cpu_to_le16(Commands_Allowed_In_PS[i]))
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++/**
++ * @brief This function prepares command of get_hw_spec.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_hw_spec(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
++{
++ HostCmd_DS_GET_HW_SPEC *hwspec = &cmd->params.hwspec;
++
++ ENTER();
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_GET_HW_SPEC);
++ cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_GET_HW_SPEC) + S_DS_GEN);
++ memcpy(hwspec->PermanentAddr, priv->adapter->CurrentAddr, ETH_ALEN);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of ps_mode.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_ps_mode(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, u16 cmd_action)
++{
++ HostCmd_DS_802_11_PS_MODE *psm = &cmd->params.psmode;
++ u16 Action = cmd_action;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE);
++ cmd->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_PS_MODE) + S_DS_GEN);
++ psm->Action = wlan_cpu_to_le16(cmd_action);
++ psm->MultipleDtim = 0;
++ switch (Action) {
++ case HostCmd_SubCmd_Enter_PS:
++ PRINTM(INFO, "PS Command:" "SubCode- Enter PS\n");
++ PRINTM(INFO, "LocalListenInterval = %d\n",
++ Adapter->LocalListenInterval);
++
++ psm->LocalListenInterval =
++ wlan_cpu_to_le16(Adapter->LocalListenInterval);
++ psm->NullPktInterval = wlan_cpu_to_le16(Adapter->NullPktInterval);
++ psm->MultipleDtim = wlan_cpu_to_le16(priv->adapter->MultipleDtim);
++ psm->BCNMissTimeOut = wlan_cpu_to_le16(priv->adapter->BCNMissTimeOut);
++ if (priv->adapter->InfrastructureMode == Wlan802_11IBSS)
++ psm->AdhocAwakePeriod =
++ wlan_cpu_to_le16(priv->adapter->AdhocAwakePeriod);
++ break;
++
++ case HostCmd_SubCmd_Exit_PS:
++ PRINTM(INFO, "PS Command:" "SubCode- Exit PS\n");
++ break;
++
++ case HostCmd_SubCmd_Sleep_Confirmed:
++ PRINTM(INFO, "PS Command: SubCode- sleep confirm\n");
++ break;
++
++ default:
++ break;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of fw_wakeup_method.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @param pdata_buf A pointer to data buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_fw_wakeup_method(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ int cmd_action, void *pdata_buf)
++{
++ HostCmd_DS_802_11_FW_WAKEUP_METHOD *fwwm = &cmd->params.fwwakeupmethod;
++ u16 action = (u16) cmd_action;
++ u16 method = *((u16 *) pdata_buf);
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_FW_WAKE_METHOD);
++ cmd->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_FW_WAKEUP_METHOD) +
++ S_DS_GEN);
++ fwwm->Action = wlan_cpu_to_le16(action);
++ switch (action) {
++ case HostCmd_ACT_SET:
++ fwwm->Method = wlan_cpu_to_le16(method);
++ break;
++ case HostCmd_ACT_GET:
++ default:
++ fwwm->Method = 0;
++ break;
++ }
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function sends the HS_Activated event to the application
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_host_sleep_activated_event(wlan_private * priv)
++{
++ ENTER();
++
++ priv->adapter->HS_Activated = TRUE;
++ os_carrier_off(priv);
++ os_stop_queue(priv);
++ wmm_stop_queue(priv);
++
++#if WIRELESS_EXT > 14
++ send_iwevcustom_event(priv, CUS_EVT_HS_ACTIVATED);
++#endif /* WIRELESS_EXT */
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function sends the HS_DeActivated event to the application
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_host_sleep_deactivated_event(wlan_private * priv)
++{
++ ENTER();
++
++ priv->adapter->HS_Activated = FALSE;
++
++#if WIRELESS_EXT > 14
++ send_iwevcustom_event(priv, CUS_EVT_HS_DEACTIVATED);
++#endif /* WIRELESS_EXT */
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function sends the HS_GPIO_INT event to the application
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_host_sleep_gpio_int_event(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (Adapter->bHostSleepConfigured) {
++#if WIRELESS_EXT > 14
++ send_iwevcustom_event(priv, CUS_EVT_HS_GPIO_INT);
++#endif /* WIRELESS_EXT */
++ } else {
++ PRINTM(INFO, "hs_gpio_int: HS not configured !!!\n");
++ }
++
++ LEAVE();
++
++ return ret;
++}
++
++/**
++ * @brief This function prepares command of host_sleep_cfg.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param pdata_buf A pointer to HostCmd_DS_802_11_HOST_SLEEP_CFG structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_host_sleep_cfg(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ HostCmd_DS_802_11_HOST_SLEEP_CFG * pdata_buf)
++{
++ HostCmd_DS_802_11_HOST_SLEEP_CFG *phwuc = &cmd->params.hostsleepcfg;
++
++ ENTER();
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_HOST_SLEEP_CFG);
++ if ((pdata_buf->conditions != HOST_SLEEP_CFG_CANCEL)
++ && ((priv->adapter->ArpFilterSize > 0)
++ && (priv->adapter->ArpFilterSize <= ARP_FILTER_MAX_BUF_SIZE))) {
++ PRINTM(INFO, "Attach %d bytes ArpFilter to HSCfg cmd\n",
++ priv->adapter->ArpFilterSize);
++ memcpy(((u8 *) phwuc) + sizeof(HostCmd_DS_802_11_HOST_SLEEP_CFG),
++ priv->adapter->ArpFilter, priv->adapter->ArpFilterSize);
++ cmd->Size =
++ wlan_cpu_to_le16(priv->adapter->ArpFilterSize +
++ sizeof(HostCmd_DS_802_11_HOST_SLEEP_CFG) +
++ S_DS_GEN);
++ } else
++ cmd->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_HOST_SLEEP_CFG) +
++ S_DS_GEN);
++ phwuc->conditions = wlan_cpu_to_le32(pdata_buf->conditions);
++ phwuc->gpio = pdata_buf->gpio;
++ phwuc->gap = pdata_buf->gap;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of inactivity_timeout.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action Action: GET SET
++ * @param pdata_buf A pointer to data buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ u16 cmd_action, void *pdata_buf)
++{
++ u16 *timeout = (u16 *) pdata_buf;
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_INACTIVITY_TIMEOUT);
++ cmd->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_INACTIVITY_TIMEOUT) +
++ S_DS_GEN);
++
++ cmd->params.inactivity_timeout.Action = wlan_cpu_to_le16(cmd_action);
++
++ if (cmd_action)
++ cmd->params.inactivity_timeout.Timeout = wlan_cpu_to_le16(*timeout);
++ else
++ cmd->params.inactivity_timeout.Timeout = 0;
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of sleep_period.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @param pdata_buf A pointer to data buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_sleep_period(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ u16 cmd_action, void *pdata_buf)
++{
++ HostCmd_DS_802_11_SLEEP_PERIOD *pSleepPeriod = &cmd->params.ps_sleeppd;
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PERIOD);
++ cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SLEEP_PERIOD) +
++ S_DS_GEN);
++ memmove(pSleepPeriod, pdata_buf, sizeof(HostCmd_DS_802_11_SLEEP_PERIOD));
++ pSleepPeriod->Action = wlan_cpu_to_le16(pSleepPeriod->Action);
++ pSleepPeriod->Period = wlan_cpu_to_le16(pSleepPeriod->Period);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of sleep_params.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_sleep_params(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, u16 cmd_action)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ HostCmd_DS_802_11_SLEEP_PARAMS *sp = &cmd->params.sleep_params;
++
++ ENTER();
++
++ cmd->Size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_SLEEP_PARAMS)) +
++ S_DS_GEN);
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PARAMS);
++
++ if (cmd_action == HostCmd_ACT_GEN_GET) {
++ memset(&Adapter->sp, 0, sizeof(SleepParams));
++ memset(sp, 0, sizeof(HostCmd_DS_802_11_SLEEP_PARAMS));
++ sp->Action = wlan_cpu_to_le16(cmd_action);
++ } else if (cmd_action == HostCmd_ACT_GEN_SET) {
++ sp->Action = wlan_cpu_to_le16(cmd_action);
++ sp->Error = wlan_cpu_to_le16(Adapter->sp.sp_error);
++ sp->Offset = wlan_cpu_to_le16(Adapter->sp.sp_offset);
++ sp->StableTime = wlan_cpu_to_le16(Adapter->sp.sp_stabletime);
++ sp->CalControl = (u8) Adapter->sp.sp_calcontrol;
++ sp->ExternalSleepClk = (u8) Adapter->sp.sp_extsleepclk;
++ sp->Reserved = wlan_cpu_to_le16(Adapter->sp.sp_reserved);
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++#define WEP_40_BIT_LEN 5
++#define WEP_104_BIT_LEN 13
++
++/**
++ * @brief This function prepares command of set_wep.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_oid OID: ADD_WEP KEY or REMOVE_WEP KEY
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_set_wep(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, u32 cmd_oid)
++{
++ HostCmd_DS_802_11_SET_WEP *wep = &cmd->params.wep;
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (cmd_oid == OID_802_11_ADD_WEP) {
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SET_WEP);
++ cmd->Size =
++ wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_SET_WEP)) + S_DS_GEN);
++ wep->Action = wlan_cpu_to_le16(HostCmd_ACT_ADD);
++
++ /* default tx key index */
++ wep->KeyIndex = wlan_cpu_to_le16(Adapter->CurrentWepKeyIndex &
++ HostCmd_WEP_KEY_INDEX_MASK);
++
++ PRINTM(INFO, "Tx Key Index: %u\n", wep->KeyIndex);
++
++ switch (Adapter->WepKey[0].KeyLength) {
++ case WEP_40_BIT_LEN:
++ wep->WEPTypeForKey1 = HostCmd_TYPE_WEP_40_BIT;
++ memmove(wep->WEP1, Adapter->WepKey[0].KeyMaterial,
++ Adapter->WepKey[0].KeyLength);
++ break;
++ case WEP_104_BIT_LEN:
++ wep->WEPTypeForKey1 = HostCmd_TYPE_WEP_104_BIT;
++ memmove(wep->WEP1, Adapter->WepKey[0].KeyMaterial,
++ Adapter->WepKey[0].KeyLength);
++ break;
++ case 0:
++ break;
++ default:
++ PRINTM(INFO, "Key1 Length = %d is incorrect\n",
++ Adapter->WepKey[0].KeyLength);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ switch (Adapter->WepKey[1].KeyLength) {
++ case WEP_40_BIT_LEN:
++ wep->WEPTypeForKey2 = HostCmd_TYPE_WEP_40_BIT;
++ memmove(wep->WEP2, Adapter->WepKey[1].KeyMaterial,
++ Adapter->WepKey[1].KeyLength);
++ break;
++ case WEP_104_BIT_LEN:
++ wep->WEPTypeForKey2 = HostCmd_TYPE_WEP_104_BIT;
++ memmove(wep->WEP2, Adapter->WepKey[1].KeyMaterial,
++ Adapter->WepKey[1].KeyLength);
++ break;
++ case 0:
++ break;
++ default:
++ PRINTM(INFO, "Key2 Length = %d is incorrect\n",
++ Adapter->WepKey[1].KeyLength);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ switch (Adapter->WepKey[2].KeyLength) {
++ case WEP_40_BIT_LEN:
++ wep->WEPTypeForKey3 = HostCmd_TYPE_WEP_40_BIT;
++ memmove(wep->WEP3, Adapter->WepKey[2].KeyMaterial,
++ Adapter->WepKey[2].KeyLength);
++ break;
++ case WEP_104_BIT_LEN:
++ wep->WEPTypeForKey3 = HostCmd_TYPE_WEP_104_BIT;
++ memmove(wep->WEP3, Adapter->WepKey[2].KeyMaterial,
++ Adapter->WepKey[2].KeyLength);
++ break;
++ case 0:
++ break;
++ default:
++ PRINTM(INFO, "Key3 Length = %d is incorrect\n",
++ Adapter->WepKey[2].KeyLength);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ switch (Adapter->WepKey[3].KeyLength) {
++ case WEP_40_BIT_LEN:
++ wep->WEPTypeForKey4 = HostCmd_TYPE_WEP_40_BIT;
++ memmove(wep->WEP4, Adapter->WepKey[3].KeyMaterial,
++ Adapter->WepKey[3].KeyLength);
++ break;
++ case WEP_104_BIT_LEN:
++ wep->WEPTypeForKey4 = HostCmd_TYPE_WEP_104_BIT;
++ memmove(wep->WEP4, Adapter->WepKey[3].KeyMaterial,
++ Adapter->WepKey[3].KeyLength);
++ break;
++ case 0:
++ break;
++ default:
++ PRINTM(INFO, "Key4 Length = %d is incorrect\n",
++ Adapter->WepKey[3].KeyLength);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ } else if (cmd_oid == OID_802_11_REMOVE_WEP) {
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SET_WEP);
++ cmd->Size =
++ wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_SET_WEP)) + S_DS_GEN);
++ wep->Action = wlan_cpu_to_le16(HostCmd_ACT_REMOVE);
++
++ /* default tx key index */
++ wep->KeyIndex = wlan_cpu_to_le16((u16) (Adapter->CurrentWepKeyIndex &
++ (u32)
++ HostCmd_WEP_KEY_INDEX_MASK));
++ }
++
++ ret = WLAN_STATUS_SUCCESS;
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function prepares command of key_material.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @param cmd_oid OID: ENABLE or DISABLE
++ * @param pdata_buf A pointer to data buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_key_material(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ u16 cmd_action,
++ WLAN_OID cmd_oid, void *pdata_buf)
++{
++ HostCmd_DS_802_11_KEY_MATERIAL *pKeyMaterial = &cmd->params.keymaterial;
++ WLAN_802_11_KEY *pKey = (WLAN_802_11_KEY *) pdata_buf;
++ u16 KeyParamSet_len;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
++ pKeyMaterial->Action = wlan_cpu_to_le16(cmd_action);
++
++ if (cmd_action == HostCmd_ACT_GET) {
++ cmd->Size = wlan_cpu_to_le16(2 + S_DS_GEN);
++ ret = WLAN_STATUS_SUCCESS;
++ goto done;
++ }
++
++ memset(&pKeyMaterial->KeyParamSet, 0, sizeof(MrvlIEtype_KeyParamSet_t));
++
++ if (pKey->KeyLength == WPA_AES_KEY_LEN) {
++ PRINTM(INFO, "WPA_AES\n");
++ pKeyMaterial->KeyParamSet.KeyTypeId =
++ wlan_cpu_to_le16(KEY_TYPE_ID_AES);
++
++ if (cmd_oid == (WLAN_OID) KEY_INFO_ENABLED)
++ pKeyMaterial->KeyParamSet.KeyInfo =
++ wlan_cpu_to_le16(KEY_INFO_AES_ENABLED);
++ else
++ pKeyMaterial->KeyParamSet.KeyInfo =
++ !(wlan_cpu_to_le16(KEY_INFO_AES_ENABLED));
++
++ if (pKey->KeyIndex & 0x40000000) //AES pairwise key: unicast
++ pKeyMaterial->KeyParamSet.KeyInfo |=
++ wlan_cpu_to_le16(KEY_INFO_AES_UNICAST);
++ else //AES group key: multicast
++ pKeyMaterial->KeyParamSet.KeyInfo |=
++ wlan_cpu_to_le16(KEY_INFO_AES_MCAST);
++ } else if (pKey->KeyLength == WPA_TKIP_KEY_LEN) {
++ PRINTM(INFO, "WPA_TKIP\n");
++ pKeyMaterial->KeyParamSet.KeyTypeId =
++ wlan_cpu_to_le16(KEY_TYPE_ID_TKIP);
++ pKeyMaterial->KeyParamSet.KeyInfo =
++ wlan_cpu_to_le16(KEY_INFO_TKIP_ENABLED);
++
++ if (pKey->KeyIndex & 0x40000000) //TKIP pairwise key: unicast
++ pKeyMaterial->KeyParamSet.KeyInfo |=
++ wlan_cpu_to_le16(KEY_INFO_TKIP_UNICAST);
++ else //TKIP group key: multicast
++ pKeyMaterial->KeyParamSet.KeyInfo |=
++ wlan_cpu_to_le16(KEY_INFO_TKIP_MCAST);
++ }
++
++ if (pKeyMaterial->KeyParamSet.KeyTypeId) {
++ pKeyMaterial->KeyParamSet.Type =
++ wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
++ pKeyMaterial->KeyParamSet.KeyLen = wlan_cpu_to_le16(pKey->KeyLength);
++ memcpy(pKeyMaterial->KeyParamSet.Key,
++ pKey->KeyMaterial, pKey->KeyLength);
++ pKeyMaterial->KeyParamSet.Length =
++ wlan_cpu_to_le16(pKey->KeyLength + 6);
++
++#define TYPE_LEN_FIELDS_LEN 4
++ KeyParamSet_len = (pKey->KeyLength + 6) + TYPE_LEN_FIELDS_LEN;
++#define ACTION_FIELD_LEN 2
++ cmd->Size =
++ wlan_cpu_to_le16(KeyParamSet_len + ACTION_FIELD_LEN + S_DS_GEN);
++ }
++
++ ret = WLAN_STATUS_SUCCESS;
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function prepares command of get_log.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_get_log(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
++{
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
++ cmd->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_GET_LOG) + S_DS_GEN);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of snmp_mib.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @param cmd_oid the OID of SNMP MIB
++ * @param pdata_buf the pointer to data buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_snmp_mib(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ int cmd_action, int cmd_oid, void *pdata_buf)
++{
++ HostCmd_DS_802_11_SNMP_MIB *pSNMPMIB = &cmd->params.smib;
++ wlan_adapter *Adapter = priv->adapter;
++ u8 ucTemp;
++
++ ENTER();
++
++ PRINTM(INFO, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
++ cmd->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SNMP_MIB) + S_DS_GEN);
++
++ switch (cmd_oid) {
++ case OID_802_11_INFRASTRUCTURE_MODE:
++ pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
++ pSNMPMIB->OID = wlan_cpu_to_le16((u16) DesiredBssType_i);
++ pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u8));
++ if (Adapter->InfrastructureMode == Wlan802_11Infrastructure)
++ ucTemp = SNMP_MIB_VALUE_INFRA;
++ else
++ ucTemp = SNMP_MIB_VALUE_ADHOC;
++
++ memmove(pSNMPMIB->Value, &ucTemp, sizeof(u8));
++
++ break;
++
++ case OID_802_11D_ENABLE:
++ {
++ u32 ulTemp;
++
++ pSNMPMIB->OID = wlan_cpu_to_le16((u16) Dot11D_i);
++
++ if (cmd_action == HostCmd_ACT_SET) {
++ pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
++ pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u16));
++ ulTemp = *(u32 *) pdata_buf;
++ *((PUSHORT) (pSNMPMIB->Value)) =
++ wlan_cpu_to_le16((u16) ulTemp);
++ }
++ break;
++ }
++
++ case OID_802_11_FRAGMENTATION_THRESHOLD:
++ {
++ WLAN_802_11_FRAGMENTATION_THRESHOLD ulTemp;
++
++ pSNMPMIB->OID = wlan_cpu_to_le16((u16) FragThresh_i);
++
++ if (cmd_action == HostCmd_ACT_GET) {
++ pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
++ } else if (cmd_action == HostCmd_ACT_SET) {
++ pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
++ pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u16));
++ ulTemp = *((WLAN_802_11_FRAGMENTATION_THRESHOLD *)
++ pdata_buf);
++ *((PUSHORT) (pSNMPMIB->Value)) =
++ wlan_cpu_to_le16((u16) ulTemp);
++
++ }
++
++ break;
++ }
++
++ case OID_802_11_RTS_THRESHOLD:
++ {
++
++ WLAN_802_11_RTS_THRESHOLD ulTemp;
++ pSNMPMIB->OID = wlan_cpu_to_le16((u16) RtsThresh_i);
++
++ if (cmd_action == HostCmd_ACT_GET) {
++ pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
++ } else if (cmd_action == HostCmd_ACT_SET) {
++ pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
++ pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u16));
++ ulTemp = *((WLAN_802_11_RTS_THRESHOLD *)
++ pdata_buf);
++ *(PUSHORT) (pSNMPMIB->Value) = wlan_cpu_to_le16((u16) ulTemp);
++ }
++ break;
++ }
++ case OID_802_11_TX_RETRYCOUNT:
++ pSNMPMIB->OID = wlan_cpu_to_le16((u16) ShortRetryLim_i);
++
++ if (cmd_action == HostCmd_ACT_GET) {
++ pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
++ } else if (cmd_action == HostCmd_ACT_SET) {
++ pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
++ pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u16));
++ *((PUSHORT) (pSNMPMIB->Value)) =
++ wlan_cpu_to_le16((u16) Adapter->TxRetryCount);
++ }
++ break;
++
++ case OID_802_11_DTIM:
++ pSNMPMIB->OID = wlan_cpu_to_le16((u16) DtimPeriod_i);
++
++ if (cmd_action == HostCmd_ACT_GET) {
++ pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
++ }
++ break;
++
++ default:
++ break;
++ }
++
++ PRINTM(INFO,
++ "SNMP_CMD: Command=0x%x, Size=0x%x, SeqNum=0x%x, Result=0x%x\n",
++ cmd->Command, cmd->Size, cmd->SeqNum, cmd->Result);
++
++ PRINTM(INFO,
++ "SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x, Value=0x%x\n",
++ pSNMPMIB->QueryType, pSNMPMIB->OID, pSNMPMIB->BufSize,
++ *(u16 *) pSNMPMIB->Value);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of radio_control.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_radio_control(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, int cmd_action)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ HostCmd_DS_802_11_RADIO_CONTROL *pRadioControl = &cmd->params.radio;
++
++ ENTER();
++
++ cmd->Size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_RADIO_CONTROL))
++ + S_DS_GEN);
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RADIO_CONTROL);
++
++ pRadioControl->Action = wlan_cpu_to_le16(cmd_action);
++ pRadioControl->Control = wlan_cpu_to_le16(Adapter->RadioOn);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of bca_timeshare.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @param user_bca_ts A pointer to HostCmd_DS_802_11_BCA_TIMESHARE structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_bca_timeshare(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ u16 cmd_action,
++ HostCmd_DS_802_11_BCA_TIMESHARE * user_bca_ts)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ HostCmd_DS_802_11_BCA_TIMESHARE *bca_ts = &cmd->params.bca_timeshare;
++
++ ENTER();
++
++ cmd->Size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_BCA_TIMESHARE)) +
++ S_DS_GEN);
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE);
++
++ if (cmd_action == HostCmd_ACT_GEN_GET) {
++ memset(&Adapter->bca_ts, 0, sizeof(bca_ts));
++ memset(bca_ts, 0, sizeof(HostCmd_DS_802_11_BCA_TIMESHARE));
++ bca_ts->Action = wlan_cpu_to_le16(cmd_action);
++ bca_ts->TrafficType = wlan_cpu_to_le16(user_bca_ts->TrafficType);
++ } else if (cmd_action == HostCmd_ACT_GEN_SET) {
++ bca_ts->Action = wlan_cpu_to_le16(cmd_action);
++ bca_ts->TrafficType = wlan_cpu_to_le16(user_bca_ts->TrafficType);
++ bca_ts->TimeShareInterval =
++ wlan_cpu_to_le32(user_bca_ts->TimeShareInterval);
++ bca_ts->BTTime = wlan_cpu_to_le32(user_bca_ts->BTTime);
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of rf_tx_power.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @param pdata_buf A pointer to data buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ u16 cmd_action, void *pdata_buf)
++{
++
++ HostCmd_DS_802_11_RF_TX_POWER *pRTP = &cmd->params.txp;
++
++ ENTER();
++
++ cmd->Size =
++ wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_RF_TX_POWER)) + S_DS_GEN);
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_TX_POWER);
++ pRTP->Action = cmd_action;
++
++ PRINTM(INFO, "RF_TX_POWER_CMD: Size:%d Cmd:0x%x Act:%d\n", cmd->Size,
++ cmd->Command, pRTP->Action);
++
++ switch (cmd_action) {
++ case HostCmd_ACT_GEN_GET:
++ pRTP->Action = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
++ pRTP->CurrentLevel = 0;
++ break;
++
++ case HostCmd_ACT_GEN_SET:
++ pRTP->Action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
++ pRTP->CurrentLevel = wlan_cpu_to_le16(*((u16 *) pdata_buf));
++ break;
++ }
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of rf_antenna.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @param pdata_buf A pointer to data buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_rf_antenna(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ u16 cmd_action, void *pdata_buf)
++{
++ HostCmd_DS_802_11_RF_ANTENNA *rant = &cmd->params.rant;
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_ANTENNA);
++ cmd->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RF_ANTENNA) + S_DS_GEN);
++
++ rant->Action = wlan_cpu_to_le16(cmd_action);
++ if ((cmd_action == HostCmd_ACT_SET_RX) ||
++ (cmd_action == HostCmd_ACT_SET_TX)) {
++ rant->AntennaMode =
++ wlan_cpu_to_le16((u16) (*(WLAN_802_11_ANTENNA *) pdata_buf));
++ }
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of rate_adapt_rateset.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, u16 cmd_action)
++{
++ HostCmd_DS_802_11_RATE_ADAPT_RATESET * rateadapt = &cmd->params.rateset;
++ wlan_adapter *Adapter = priv->adapter;
++
++ cmd->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RATE_ADAPT_RATESET) +
++ S_DS_GEN);
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RATE_ADAPT_RATESET);
++
++ ENTER();
++
++ rateadapt->Action = wlan_cpu_to_le16(cmd_action);
++ rateadapt->HWRateDropMode = wlan_cpu_to_le16(Adapter->HWRateDropMode);
++ rateadapt->Threshold = wlan_cpu_to_le16(Adapter->Threshold);
++ rateadapt->FinalRate = wlan_cpu_to_le16(Adapter->FinalRate);
++ rateadapt->Bitmap = wlan_cpu_to_le16(Adapter->RateBitmap);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of mac_multicast_adr.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_mac_multicast_adr(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, u16 cmd_action)
++{
++ HostCmd_DS_MAC_MULTICAST_ADR *pMCastAdr = &cmd->params.madr;
++ wlan_adapter *Adapter = priv->adapter;
++
++ cmd->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_MULTICAST_ADR) + S_DS_GEN);
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR);
++
++ pMCastAdr->Action = wlan_cpu_to_le16(cmd_action);
++ pMCastAdr->NumOfAdrs =
++ wlan_cpu_to_le16((u16) Adapter->NumOfMulticastMACAddr);
++ memcpy(pMCastAdr->MACList, Adapter->MulticastList,
++ Adapter->NumOfMulticastMACAddr * ETH_ALEN);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of rf_channel.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @param pdata_buf A pointer to data buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_rf_channel(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ int option, void *pdata_buf)
++{
++ HostCmd_DS_802_11_RF_CHANNEL *rfchan = &cmd->params.rfchannel;
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL);
++ cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RF_CHANNEL)
++ + S_DS_GEN);
++
++ if (option == HostCmd_OPT_802_11_RF_CHANNEL_SET) {
++ rfchan->CurrentChannel = wlan_cpu_to_le16(*((u16 *) pdata_buf));
++ }
++
++ rfchan->Action = wlan_cpu_to_le16(option);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of rssi.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_rssi(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RSSI);
++ cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RSSI) + S_DS_GEN);
++ cmd->params.rssi.N = wlan_cpu_to_le16(Adapter->bcn_avg_factor);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of reg_access.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @param pdata_buf A pointer to data buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_reg_access(wlan_private * priv,
++ HostCmd_DS_COMMAND * CmdPtr,
++ u8 cmd_action, void *pdata_buf)
++{
++ wlan_offset_value *offval;
++
++ ENTER();
++
++ offval = (wlan_offset_value *) pdata_buf;
++
++ switch (CmdPtr->Command) {
++ case HostCmd_CMD_MAC_REG_ACCESS:
++ {
++ HostCmd_DS_MAC_REG_ACCESS *macreg;
++
++ CmdPtr->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_REG_ACCESS) +
++ S_DS_GEN);
++ macreg = (HostCmd_DS_MAC_REG_ACCESS *) & CmdPtr->params.macreg;
++
++ macreg->Action = wlan_cpu_to_le16(cmd_action);
++ macreg->Offset = wlan_cpu_to_le16((u16) offval->offset);
++ macreg->Value = wlan_cpu_to_le32(offval->value);
++
++ break;
++ }
++
++ case HostCmd_CMD_BBP_REG_ACCESS:
++ {
++ HostCmd_DS_BBP_REG_ACCESS *bbpreg;
++
++ CmdPtr->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_BBP_REG_ACCESS) +
++ S_DS_GEN);
++ bbpreg = (HostCmd_DS_BBP_REG_ACCESS *) & CmdPtr->params.bbpreg;
++
++ bbpreg->Action = wlan_cpu_to_le16(cmd_action);
++ bbpreg->Offset = wlan_cpu_to_le16((u16) offval->offset);
++ bbpreg->Value = (u8) offval->value;
++
++ break;
++ }
++
++ case HostCmd_CMD_RF_REG_ACCESS:
++ {
++ HostCmd_DS_RF_REG_ACCESS *rfreg;
++
++ CmdPtr->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_RF_REG_ACCESS) + S_DS_GEN);
++ rfreg = (HostCmd_DS_RF_REG_ACCESS *) & CmdPtr->params.rfreg;
++
++ rfreg->Action = wlan_cpu_to_le16(cmd_action);
++ rfreg->Offset = wlan_cpu_to_le16((u16) offval->offset);
++ rfreg->Value = (u8) offval->value;
++
++ break;
++ }
++
++ default:
++ break;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of mac_address.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_mac_address(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, u16 cmd_action)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS);
++ cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_MAC_ADDRESS) +
++ S_DS_GEN);
++ cmd->Result = 0;
++
++ cmd->params.macadd.Action = wlan_cpu_to_le16(cmd_action);
++
++ if (cmd_action == HostCmd_ACT_SET) {
++ memcpy(cmd->params.macadd.MacAdd, Adapter->CurrentAddr, ETH_ALEN);
++ HEXDUMP("SET_CMD: MAC ADDRESS-", Adapter->CurrentAddr, 6);
++ }
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of cal_data_ext.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param pdata_buf A pointer to data buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_cal_data_ext(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *pdata_buf)
++{
++ HostCmd_DS_802_11_CAL_DATA_EXT *PCalDataext = pdata_buf;
++
++ HostCmd_DS_802_11_CAL_DATA_EXT *pCmdCalData =
++ (HostCmd_DS_802_11_CAL_DATA_EXT *) & cmd->params.caldataext;
++
++ ENTER();
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_CAL_DATA_EXT);
++
++ PRINTM(INFO, "CalDataLen = %d(d)\n", PCalDataext->CalDataLen);
++
++ if (PCalDataext->CalDataLen >
++ MAX_SETGET_CONF_CMD_LEN - CAL_DATA_HEADER_LEN) {
++ PRINTM(MSG, "CAL_DATA_EXT: Cal data lenght too large!\n");
++ return WLAN_STATUS_FAILURE;
++ }
++
++ memcpy(pCmdCalData, PCalDataext,
++ PCalDataext->CalDataLen + CAL_DATA_HEADER_LEN);
++
++ pCmdCalData->Action = wlan_cpu_to_le16(pCmdCalData->Action);
++ pCmdCalData->Revision = wlan_cpu_to_le16(pCmdCalData->Revision);
++ pCmdCalData->CalDataLen = wlan_cpu_to_le16(pCmdCalData->CalDataLen);
++
++ cmd->Size = wlan_cpu_to_le16(PCalDataext->CalDataLen +
++ CAL_DATA_HEADER_LEN + S_DS_GEN);
++
++ PRINTM(INFO, "CAL_DATA_EXT: cmd->Size = %d(d)\n", cmd->Size);
++
++ cmd->Result = 0;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of eeprom_access.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @param pdata_buf A pointer to data buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_802_11_eeprom_access(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ int cmd_action, void *pdata_buf)
++{
++ wlan_ioctl_regrdwr *ea = pdata_buf;
++
++ ENTER();
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_EEPROM_ACCESS);
++ cmd->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_EEPROM_ACCESS) + S_DS_GEN);
++ cmd->Result = 0;
++
++ cmd->params.rdeeprom.Action = wlan_cpu_to_le16(ea->Action);
++ cmd->params.rdeeprom.Offset = wlan_cpu_to_le16(ea->Offset);
++ cmd->params.rdeeprom.ByteCount = wlan_cpu_to_le16(ea->NOB);
++ cmd->params.rdeeprom.Value = 0;
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++static int
++wlan_cmd_802_11_IBSS_Coalesced_Status(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ int cmd_action, void *pdata_buf)
++{
++ HostCmd_DS_802_11_IBSS_Status *pIBSSReq = &(cmd->params.ibssCoalescing);
++ u16 *enable = pdata_buf;
++
++ PRINTM(INFO, "HostCmd_CMD_802_11_BSSID_QUERY request");
++
++ cmd->Command =
++ wlan_cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS);
++ cmd->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_IBSS_Status) + S_DS_GEN);
++ cmd->Result = 0;
++ pIBSSReq->Action = wlan_cpu_to_le16(cmd_action);
++
++ switch (cmd_action) {
++ case HostCmd_ACT_SET:
++ pIBSSReq->Enable = wlan_cpu_to_le16(*enable);
++ break;
++
++ /* In other case.. Noting to do */
++ case HostCmd_ACT_GET:
++ default:
++ break;
++ }
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function queues the command to cmd list.
++ *
++ * @param Adapter A pointer to wlan_adapter structure
++ * @param CmdNode A pointer to CmdCtrlNode structure
++ * @param addtail specify if the cmd needs to be queued in the header or tail
++ * @return n/a
++ */
++void
++QueueCmd(wlan_adapter * Adapter, CmdCtrlNode * CmdNode, BOOLEAN addtail)
++{
++ ulong flags;
++ HostCmd_DS_COMMAND *CmdPtr;
++ u16 command;
++
++ ENTER();
++
++ if (!CmdNode) {
++ PRINTM(WARN, "QUEUE_CMD: CmdNode is NULL\n");
++ goto done;
++ }
++
++ CmdPtr = (HostCmd_DS_COMMAND *) CmdNode->BufVirtualAddr;
++ if (!CmdPtr) {
++ PRINTM(WARN, "QUEUE_CMD: CmdPtr is NULL\n");
++ goto done;
++ }
++
++ command = wlan_le16_to_cpu(CmdPtr->Command);
++
++ /* Exit_PS command needs to be queued in the header always. */
++ if (command == HostCmd_CMD_802_11_PS_MODE) {
++ HostCmd_DS_802_11_PS_MODE *psm = &CmdPtr->params.psmode;
++ if (wlan_le16_to_cpu(psm->Action) == HostCmd_SubCmd_Exit_PS) {
++ if (Adapter->PSState != PS_STATE_FULL_POWER)
++ addtail = FALSE;
++ }
++ }
++
++ if ((command == HostCmd_CMD_802_11_WAKEUP_CONFIRM)
++ || (command == HostCmd_CMD_802_11_HOST_SLEEP_ACTIVATE)
++ || (command == HostCmd_CMD_802_11_HOST_SLEEP_CFG)
++ ) {
++ addtail = FALSE;
++ }
++
++ spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
++
++ if (addtail)
++ list_add_tail((struct list_head *) CmdNode, &Adapter->CmdPendingQ);
++ else
++ list_add((struct list_head *) CmdNode, &Adapter->CmdPendingQ);
++
++ spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
++
++ PRINTM(INFO, "QUEUE_CMD: cmd=0x%x is queued\n", command);
++
++ done:
++ LEAVE();
++ return;
++}
++
++#ifdef MFG_CMD_SUPPORT
++/**
++ * @brief This function sends general command to firmware.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param pdata_buf A pointer to data buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_mfg_cmd(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *pdata_buf)
++{
++ HostCmd_DS_GEN *pCmdPtr;
++
++ ENTER();
++
++ pCmdPtr = (HostCmd_DS_GEN *) pdata_buf;
++
++ /* copy the MFG command to command buffer */
++ memcpy((void *) cmd, pdata_buf, pCmdPtr->Size);
++
++ PRINTM(INFO, "MFG command size = %d\n", pCmdPtr->Size);
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_MFG_COMMAND);
++ cmd->Size = wlan_cpu_to_le16(cmd->Size);
++ cmd->Result = 0;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++#endif
++
++/**
++ * @brief This function downloads the command to firmware.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param CmdNode A pointer to CmdCtrlNode structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++DownloadCommandToStation(wlan_private * priv, CmdCtrlNode * CmdNode)
++{
++ ulong flags;
++ HostCmd_DS_COMMAND *CmdPtr;
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++ u16 CmdSize;
++ u16 Command;
++
++ OS_INTERRUPT_SAVE_AREA;
++
++ ENTER();
++
++ if (!Adapter || !CmdNode) {
++ PRINTM(ERROR, "DNLD_CMD: Adapter = %#x, CmdNode = %#x\n",
++ (int) Adapter, (int) CmdNode);
++ if (CmdNode)
++ CleanupAndInsertCmd(priv, CmdNode);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ CmdPtr = (HostCmd_DS_COMMAND *) CmdNode->BufVirtualAddr;
++
++ if (!CmdPtr || !CmdPtr->Size) {
++ PRINTM(ERROR, "DNLD_CMD: CmdPtr is Null or Cmd Size is Zero, "
++ "Not sending\n");
++ CleanupAndInsertCmd(priv, CmdNode);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ /* Set command sequence number */
++ Adapter->SeqNum++;
++ CmdPtr->SeqNum = wlan_cpu_to_le16(Adapter->SeqNum);
++
++ spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
++ Adapter->CurCmd = CmdNode;
++ spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
++
++ Command = wlan_le16_to_cpu(CmdPtr->Command);
++ CmdSize = wlan_le16_to_cpu(CmdPtr->Size);
++
++ CmdNode->CmdWaitQWoken = FALSE;
++
++ ret = sbi_host_to_card(priv, MVMS_CMD, (u8 *) CmdPtr, CmdSize);
++
++ /* clear TxDone interrupt bit */
++ OS_INT_DISABLE;
++ Adapter->HisRegCpy &= ~HIS_TxDnLdRdy;
++ OS_INT_RESTORE;
++
++ if (ret != 0) {
++ PRINTM(ERROR, "DNLD_CMD: Host to Card Failed\n");
++ /* set error code that will be transferred back to PrepareAndSendCommand() */
++ Adapter->CurCmdRetCode = WLAN_STATUS_FAILURE;
++ CleanupAndInsertCmd(priv, Adapter->CurCmd);
++ spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
++ Adapter->CurCmd = NULL;
++ spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
++ Adapter->dbg.num_cmd_host_to_card_failure++;
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ /* Save the last command id and action to debug log */
++ Adapter->dbg.LastCmdIndex = (Adapter->dbg.LastCmdIndex + 1) % DBG_CMD_NUM;
++ Adapter->dbg.LastCmdId[Adapter->dbg.LastCmdIndex] = Command;
++ Adapter->dbg.LastCmdAct[Adapter->dbg.LastCmdIndex] =
++ wlan_le16_to_cpu(*(u16 *) ((u8 *) CmdPtr + S_DS_GEN));
++
++ PRINTM(CMND, "DNLD_CMD: 0x%x, act 0x%x, len %d, seqno %d @ %lu\n",
++ Command, wlan_le16_to_cpu(*(u16 *) ((u8 *) CmdPtr + S_DS_GEN)),
++ CmdSize, wlan_le16_to_cpu(CmdPtr->SeqNum), os_time_get());
++ DBG_HEXDUMP(CMD_D, "DNLD_CMD", CmdNode->BufVirtualAddr, CmdSize);
++
++ /* Setup the timer after transmit command */
++ if (Command == HostCmd_CMD_802_11_SCAN
++ || Command == HostCmd_CMD_802_11_DEAUTHENTICATE
++ || Command == HostCmd_CMD_802_11_ASSOCIATE
++ || Command == HostCmd_CMD_WMM_ADDTS_REQ) {
++ ModTimer(&Adapter->MrvDrvCommandTimer, MRVDRV_TIMER_10S);
++ } else {
++ ModTimer(&Adapter->MrvDrvCommandTimer, MRVDRV_TIMER_5S);
++ }
++
++ Adapter->CommandTimerIsSet = TRUE;
++
++ if (Command == HostCmd_CMD_802_11_DEEP_SLEEP) {
++ if (Adapter->IntCounter || Adapter->CurrentTxSkb)
++ PRINTM(INFO, "DNLD_CMD: DS- IntCnt=%d CurTxSkb=%s\n",
++ Adapter->IntCounter, (Adapter->CurrentTxSkb) ? "Y" : "N");
++
++ if (Adapter->IntCounter) {
++ OS_INT_DISABLE;
++ Adapter->IntCounterSaved = Adapter->IntCounter;
++ Adapter->IntCounter = 0;
++ OS_INT_RESTORE;
++ }
++ if (Adapter->CurrentTxSkb) {
++ kfree_skb(Adapter->CurrentTxSkb);
++ OS_INT_DISABLE;
++ Adapter->CurrentTxSkb = NULL;
++ OS_INT_RESTORE;
++ priv->stats.tx_dropped++;
++ }
++ /* 1. change the PS state to DEEP_SLEEP
++ * 2. since there is no response for this command, so
++ * delete the command timer and free the Node. */
++
++ Adapter->IsDeepSleep = TRUE;
++
++ CleanupAndInsertCmd(priv, CmdNode);
++ spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
++ Adapter->CurCmd = NULL;
++ spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
++
++ if (Adapter->CommandTimerIsSet) {
++ CancelTimer(&Adapter->MrvDrvCommandTimer);
++ Adapter->CommandTimerIsSet = FALSE;
++ }
++
++ if (!Adapter->IsAutoDeepSleepEnabled
++ || (Adapter->bHostSleepConfigured &&
++ (Adapter->HSCfg.gpio != HOST_SLEEP_CFG_WAKEUP_THRU_INTERFACE))
++ )
++ /* stop clock to save more power */
++ sbi_set_bus_clock(priv, FALSE);
++
++ if (Adapter->IsAutoDeepSleepEnabled) {
++ Adapter->bWakeupDevRequired = TRUE;
++ /* For auto deep sleep mode, after entering deep sleep state,
++ * dnld_sent flag should be cleared so that the commands in
++ * pending queue can be handled by main thread. */
++ priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
++ }
++
++ if (Adapter->bHostSleepConfigured) {
++ Adapter->bWakeupDevRequired = TRUE;
++ wlan_host_sleep_activated_event(priv);
++ }
++
++ }
++
++ ret = WLAN_STATUS_SUCCESS;
++
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function prepares command of mac_control.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_cmd_mac_control(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *InfoBuf)
++{
++ HostCmd_DS_MAC_CONTROL *mac = &cmd->params.macctrl;
++ u16 Action = *((u16 *) InfoBuf);
++
++ ENTER();
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_MAC_CONTROL);
++ cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_CONTROL) + S_DS_GEN);
++ mac->Action = wlan_cpu_to_le16(Action);
++
++ PRINTM(INFO, "wlan_cmd_mac_control(): Action=0x%X Size=%d\n",
++ mac->Action, cmd->Size);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/********************************************************
++ Global Functions
++********************************************************/
++
++/**
++ * @brief This function inserts command node to CmdFreeQ
++ * after cleans it.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param pTempCmd A pointer to CmdCtrlNode structure
++ * @return n/a
++ */
++void
++CleanupAndInsertCmd(wlan_private * priv, CmdCtrlNode * pTempCmd)
++{
++ ulong flags;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (!pTempCmd)
++ goto done;
++
++ spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
++ CleanUpCmdCtrlNode(pTempCmd);
++ list_add_tail((struct list_head *) pTempCmd, &Adapter->CmdFreeQ);
++ spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
++
++ done:
++ LEAVE();
++}
++
++/**
++ * @brief This function prepare the command before send to firmware.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd_no command number
++ * @param cmd_action command action: GET or SET
++ * @param wait_option wait option: wait response or not
++ * @param cmd_oid cmd oid: treated as sub command
++ * @param pdata_buf A pointer to informaion buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++PrepareAndSendCommand(wlan_private * priv,
++ u16 cmd_no,
++ u16 cmd_action,
++ u16 wait_option, WLAN_OID cmd_oid, void *pdata_buf)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_adapter *Adapter = priv->adapter;
++ CmdCtrlNode *CmdNode;
++ HostCmd_DS_COMMAND *CmdPtr;
++
++ ENTER();
++
++ if (!Adapter) {
++ PRINTM(ERROR, "PREP_CMD: Adapter is Null\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ if (Adapter->SurpriseRemoved) {
++ PRINTM(ERROR, "PREP_CMD: Card is Removed\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ CmdNode = GetFreeCmdCtrlNode(priv);
++
++ if (CmdNode == NULL) {
++ PRINTM(MSG, "PREP_CMD: No free CmdNode\n");
++
++ /* Wake up main thread to execute next command */
++ wake_up_interruptible(&priv->MainThread.waitQ);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ SetCmdCtrlNode(priv, CmdNode, cmd_oid, wait_option, pdata_buf);
++
++ CmdPtr = (HostCmd_DS_COMMAND *) CmdNode->BufVirtualAddr;
++
++ if (!CmdPtr) {
++ PRINTM(MSG, "PREP_CMD: BufVirtualAddr of CmdNode is NULL\n");
++ CleanupAndInsertCmd(priv, CmdNode);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ CmdPtr->Command = cmd_no;
++ CmdPtr->Result = 0;
++
++ TX_EVENT_FLAGS_SET(&CmdNode->cmdwait_q, 0, TX_AND);
++ switch (cmd_no) {
++ case HostCmd_CMD_GET_HW_SPEC:
++ ret = wlan_cmd_hw_spec(priv, CmdPtr);
++ break;
++ case HostCmd_CMD_802_11_PS_MODE:
++ ret = wlan_cmd_802_11_ps_mode(priv, CmdPtr, cmd_action);
++ break;
++
++ case HostCmd_CMD_802_11_SCAN:
++ ret = wlan_cmd_802_11_scan(priv, CmdPtr, pdata_buf);
++ break;
++
++ case HostCmd_CMD_MAC_CONTROL:
++ ret = wlan_cmd_mac_control(priv, CmdPtr, pdata_buf);
++ break;
++
++ case HostCmd_CMD_802_11_ASSOCIATE:
++ ret = wlan_cmd_802_11_associate(priv, CmdPtr, pdata_buf);
++ break;
++
++ case HostCmd_CMD_802_11_DEAUTHENTICATE:
++ ret = wlan_cmd_802_11_deauthenticate(priv, CmdPtr);
++ break;
++
++ case HostCmd_CMD_802_11_SET_WEP:
++ ret = wlan_cmd_802_11_set_wep(priv, CmdPtr, cmd_oid);
++ break;
++
++ case HostCmd_CMD_802_11_AD_HOC_START:
++ ret = wlan_cmd_802_11_ad_hoc_start(priv, CmdPtr, pdata_buf);
++ break;
++ case HostCmd_CMD_802_11_RESET:
++ CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
++ CmdPtr->Size = wlan_cpu_to_le16(S_DS_GEN);
++ break;
++
++ case HostCmd_CMD_802_11_GET_LOG:
++ ret = wlan_cmd_802_11_get_log(priv, CmdPtr);
++ break;
++
++ case HostCmd_CMD_802_11_SNMP_MIB:
++ ret = wlan_cmd_802_11_snmp_mib(priv, CmdPtr,
++ cmd_action, cmd_oid, pdata_buf);
++ break;
++
++ case HostCmd_CMD_MAC_REG_ACCESS:
++ case HostCmd_CMD_BBP_REG_ACCESS:
++ case HostCmd_CMD_RF_REG_ACCESS:
++ ret = wlan_cmd_reg_access(priv, CmdPtr, cmd_action, pdata_buf);
++ break;
++
++ case HostCmd_CMD_802_11_RF_CHANNEL:
++ ret = wlan_cmd_802_11_rf_channel(priv, CmdPtr, cmd_action, pdata_buf);
++ break;
++
++ case HostCmd_CMD_802_11_RF_TX_POWER:
++ ret = wlan_cmd_802_11_rf_tx_power(priv, CmdPtr,
++ cmd_action, pdata_buf);
++ break;
++
++ case HostCmd_CMD_802_11_RADIO_CONTROL:
++ ret = wlan_cmd_802_11_radio_control(priv, CmdPtr, cmd_action);
++ break;
++
++ case HostCmd_CMD_802_11_RF_ANTENNA:
++ ret = wlan_cmd_802_11_rf_antenna(priv, CmdPtr, cmd_action, pdata_buf);
++ break;
++
++ case HostCmd_CMD_802_11_RATE_ADAPT_RATESET:
++ ret = wlan_cmd_802_11_rate_adapt_rateset(priv, CmdPtr, cmd_action);
++ break;
++
++ case HostCmd_CMD_MAC_MULTICAST_ADR:
++ ret = wlan_cmd_mac_multicast_adr(priv, CmdPtr, cmd_action);
++ break;
++
++ case HostCmd_CMD_802_11_AD_HOC_JOIN:
++ ret = wlan_cmd_802_11_ad_hoc_join(priv, CmdPtr, pdata_buf);
++ break;
++
++ case HostCmd_CMD_802_11_RSSI:
++ ret = wlan_cmd_802_11_rssi(priv, CmdPtr);
++ break;
++
++ case HostCmd_CMD_802_11_AD_HOC_STOP:
++ ret = wlan_cmd_802_11_ad_hoc_stop(priv, CmdPtr);
++ break;
++ case HostCmd_CMD_802_11_KEY_MATERIAL:
++ ret = wlan_cmd_802_11_key_material(priv, CmdPtr,
++ cmd_action, cmd_oid, pdata_buf);
++ break;
++
++ case HostCmd_CMD_802_11_MAC_ADDRESS:
++ ret = wlan_cmd_802_11_mac_address(priv, CmdPtr, cmd_action);
++ break;
++ case HostCmd_CMD_802_11_CAL_DATA_EXT:
++ ret = wlan_cmd_802_11_cal_data_ext(priv, CmdPtr, pdata_buf);
++ break;
++
++ case HostCmd_CMD_802_11_DEEP_SLEEP:
++ CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
++ CmdPtr->Size = wlan_cpu_to_le16((u16)
++ (sizeof
++ (HostCmd_DS_802_11_DEEP_SLEEP)));
++ break;
++
++ case HostCmd_CMD_802_11_HOST_SLEEP_CFG:
++ ret = wlan_cmd_802_11_host_sleep_cfg(priv, CmdPtr, pdata_buf);
++ break;
++ case HostCmd_CMD_802_11_WAKEUP_CONFIRM:
++ case HostCmd_CMD_802_11_HOST_SLEEP_ACTIVATE:
++ CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
++ CmdPtr->Size = wlan_cpu_to_le16(S_DS_GEN);
++ break;
++
++ case HostCmd_CMD_802_11_EEPROM_ACCESS:
++ ret = wlan_cmd_802_11_eeprom_access(priv, CmdPtr,
++ cmd_action, pdata_buf);
++ break;
++
++#ifdef MFG_CMD_SUPPORT
++ case HostCmd_CMD_MFG_COMMAND:
++ ret = wlan_cmd_mfg_cmd(priv, CmdPtr, pdata_buf);
++ break;
++#endif
++
++ case HostCmd_CMD_802_11D_DOMAIN_INFO:
++ ret = wlan_cmd_802_11d_domain_info(priv, CmdPtr, cmd_no, cmd_action);
++ break;
++
++ case HostCmd_CMD_802_11_SLEEP_PARAMS:
++ ret = wlan_cmd_802_11_sleep_params(priv, CmdPtr, cmd_action);
++ break;
++ case HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE:
++ ret = wlan_cmd_802_11_bca_timeshare(priv, CmdPtr,
++ cmd_action, pdata_buf);
++ break;
++ case HostCmd_CMD_802_11_INACTIVITY_TIMEOUT:
++ ret = wlan_cmd_802_11_inactivity_timeout(priv, CmdPtr,
++ cmd_action, pdata_buf);
++ break;
++ case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
++ ret = wlan_cmd_802_11_bg_scan_config(priv, CmdPtr,
++ cmd_action, pdata_buf);
++ break;
++
++ case HostCmd_CMD_802_11_BG_SCAN_QUERY:
++ ret = wlan_cmd_802_11_bg_scan_query(priv, CmdPtr);
++ break;
++
++ case HostCmd_CMD_802_11_FW_WAKE_METHOD:
++ ret = wlan_cmd_802_11_fw_wakeup_method(priv, CmdPtr,
++ cmd_action, pdata_buf);
++ break;
++
++ case HostCmd_CMD_WMM_GET_STATUS:
++ ret = wlan_cmd_wmm_get_status(priv, CmdPtr, pdata_buf);
++ break;
++
++ case HostCmd_CMD_WMM_ADDTS_REQ:
++ ret = wlan_cmd_wmm_addts_req(priv, CmdPtr, pdata_buf);
++ break;
++ case HostCmd_CMD_WMM_DELTS_REQ:
++ ret = wlan_cmd_wmm_delts_req(priv, CmdPtr, pdata_buf);
++ break;
++ case HostCmd_CMD_WMM_QUEUE_CONFIG:
++ ret = wlan_cmd_wmm_queue_config(priv, CmdPtr, pdata_buf);
++ break;
++ case HostCmd_CMD_WMM_QUEUE_STATS:
++ ret = wlan_cmd_wmm_queue_stats(priv, CmdPtr, pdata_buf);
++ break;
++ case HostCmd_CMD_TX_PKT_STATS:
++ CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_TX_PKT_STATS);
++ CmdPtr->Size = wlan_cpu_to_le16(S_DS_GEN);
++ ret = WLAN_STATUS_SUCCESS;
++ break;
++ case HostCmd_CMD_802_11_TPC_CFG:
++ CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_TPC_CFG);
++ CmdPtr->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_TPC_CFG) + S_DS_GEN);
++
++ memmove(&CmdPtr->params.tpccfg,
++ pdata_buf, sizeof(HostCmd_DS_802_11_TPC_CFG));
++ CmdPtr->params.tpccfg.Action =
++ wlan_cpu_to_le16(CmdPtr->params.tpccfg.Action);
++
++ ret = WLAN_STATUS_SUCCESS;
++ break;
++ case HostCmd_CMD_802_11_LED_CONTROL:
++ {
++ HostCmd_DS_802_11_LED_CTRL *pLedCtrl = &CmdPtr->params.ledgpio;
++ MrvlIEtypes_LedGpio_t *gpio = &pLedCtrl->LedGpio;
++ MrvlIEtypes_LedBehavior_t *pLedBehavior = pLedCtrl->LedBehavior;
++
++ memmove(&CmdPtr->params.ledgpio,
++ pdata_buf, sizeof(HostCmd_DS_802_11_LED_CTRL));
++
++ CmdPtr->Command =
++ wlan_cpu_to_le16(HostCmd_CMD_802_11_LED_CONTROL);
++
++#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
++ CmdPtr->Size = wlan_cpu_to_le16(gpio->Header.Len + S_DS_GEN
++ +
++ ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
++
++ pLedCtrl->Action = wlan_cpu_to_le16(pLedCtrl->Action);
++ pLedCtrl->LedNums = wlan_cpu_to_le16(pLedCtrl->LedNums);
++
++ gpio->Header.Type = wlan_cpu_to_le16(gpio->Header.Type);
++ gpio->Header.Len = wlan_cpu_to_le16(gpio->Header.Len);
++
++ pLedBehavior->Header.Type =
++ wlan_cpu_to_le16(pLedBehavior->Header.Type);
++ pLedBehavior->Header.Len =
++ wlan_cpu_to_le16(pLedBehavior->Header.Len);
++
++ ret = WLAN_STATUS_SUCCESS;
++ break;
++ }
++ case HostCmd_CMD_802_11_SLEEP_PERIOD:
++ ret = wlan_cmd_802_11_sleep_period(priv, CmdPtr,
++ cmd_action, pdata_buf);
++ break;
++ case HostCmd_CMD_GET_TSF:
++ CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_GET_TSF);
++ CmdPtr->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_GET_TSF)
++ + S_DS_GEN);
++ ret = WLAN_STATUS_SUCCESS;
++ break;
++ case HostCmd_CMD_802_11_TX_RATE_QUERY:
++ CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
++ CmdPtr->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_TX_RATE_QUERY) + S_DS_GEN);
++ Adapter->TxRate = 0;
++ ret = WLAN_STATUS_SUCCESS;
++ break;
++ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
++ ret =
++ wlan_cmd_802_11_IBSS_Coalesced_Status(priv, CmdPtr, cmd_action,
++ pdata_buf);
++ break;
++
++ case HostCmd_CMD_SDIO_GPIO_INT_CONFIG:
++ {
++ HostCmd_DS_SDIO_INT_CONFIG *pSdioIntConf =
++ &CmdPtr->params.sdio_int;
++
++ CmdPtr->Command =
++ wlan_cpu_to_le16(HostCmd_CMD_SDIO_GPIO_INT_CONFIG);
++ CmdPtr->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_SDIO_INT_CONFIG) +
++ S_DS_GEN);
++
++ memcpy(pSdioIntConf, pdata_buf,
++ sizeof(HostCmd_DS_SDIO_INT_CONFIG));
++ pSdioIntConf->Action = wlan_cpu_to_le16(pSdioIntConf->Action);
++ pSdioIntConf->Gpio_pin = wlan_cpu_to_le16(pSdioIntConf->Gpio_pin);
++ pSdioIntConf->Gpio_int_edge =
++ wlan_cpu_to_le16(pSdioIntConf->Gpio_int_edge);
++ pSdioIntConf->Gpio_pulse_width =
++ wlan_cpu_to_le16(pSdioIntConf->Gpio_pulse_width);
++
++ ret = WLAN_STATUS_SUCCESS;
++ break;
++ }
++
++ case HostCmd_CMD_SDIO_PULL_CTRL:
++ {
++ HostCmd_DS_SDIO_PULL_CTRL *pSdiopullctl =
++ &CmdPtr->params.sdiopullctl;
++
++ CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_SDIO_PULL_CTRL);
++ CmdPtr->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_SDIO_PULL_CTRL) +
++ S_DS_GEN);
++
++ memcpy(pSdiopullctl, pdata_buf,
++ sizeof(HostCmd_DS_SDIO_PULL_CTRL));
++ pSdiopullctl->Action = wlan_cpu_to_le16(pSdiopullctl->Action);
++ pSdiopullctl->PullUp = wlan_cpu_to_le16(pSdiopullctl->PullUp);
++ pSdiopullctl->PullDown = wlan_cpu_to_le16(pSdiopullctl->PullDown);
++
++ ret = WLAN_STATUS_SUCCESS;
++ break;
++ }
++
++ case HostCmd_CMD_802_11_LDO_CONFIG:
++ CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
++ CmdPtr->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_LDO_CONFIG) + S_DS_GEN);
++ memcpy(&CmdPtr->params.ldocfg, pdata_buf,
++ sizeof(HostCmd_DS_802_11_LDO_CONFIG));
++ CmdPtr->params.ldocfg.Action =
++ wlan_cpu_to_le16(CmdPtr->params.ldocfg.Action);
++ CmdPtr->params.ldocfg.PMSource =
++ wlan_cpu_to_le16(CmdPtr->params.ldocfg.PMSource);
++ break;
++
++ case HostCmd_CMD_VERSION_EXT:
++ CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
++ memcpy(&CmdPtr->params, pdata_buf, sizeof(HostCmd_DS_VERSION_EXT));
++ CmdPtr->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_VERSION_EXT)
++ + S_DS_GEN);
++ break;
++
++ default:
++ PRINTM(INFO, "PREP_CMD: unknown command- %#x\n", cmd_no);
++ ret = WLAN_STATUS_FAILURE;
++ break;
++ }
++
++ /* return error, since the command preparation failed */
++ if (ret != WLAN_STATUS_SUCCESS) {
++ PRINTM(ERROR, "PREP_CMD: Command 0x%x preparation failed\n", cmd_no);
++ CleanupAndInsertCmd(priv, CmdNode);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ PRINTM(CMND, "PREP_CMD: 0x%x\n", cmd_no);
++
++ CmdNode->CmdWaitQWoken = FALSE;
++ QueueCmd(Adapter, CmdNode, TRUE);
++ wake_up_interruptible(&priv->MainThread.waitQ);
++
++ if (wait_option & HostCmd_OPTION_WAITFORRSP) {
++ PRINTM(INFO, "PREP_CMD: Wait for CMD response...\n");
++ wait_event_interruptible(CmdNode->cmdwait_q, CmdNode->CmdWaitQWoken);
++ if (Adapter->CurCmdRetCode) {
++ PRINTM(INFO, "PREP_CMD: Command failed with return code=%d\n",
++ Adapter->CurCmdRetCode);
++ Adapter->CurCmdRetCode = 0;
++ ret = WLAN_STATUS_FAILURE;
++ }
++ }
++
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function allocates the command buffer and link
++ * it to command free queue.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++AllocateCmdBuffer(wlan_private * priv)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ u32 ulBufSize;
++ u32 i;
++ CmdCtrlNode *TempCmdArray;
++ u8 *pTempVirtualAddr;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ /* Allocate and initialize CmdCtrlNode */
++ ulBufSize = sizeof(CmdCtrlNode) * MRVDRV_NUM_OF_CMD_BUFFER;
++
++ if (!(TempCmdArray = kmalloc(ulBufSize, GFP_KERNEL))) {
++ PRINTM(INFO, "ALLOC_CMD_BUF: Failed to allocate TempCmdArray\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ Adapter->CmdArray = TempCmdArray;
++ memset(Adapter->CmdArray, 0, ulBufSize);
++
++ /* Allocate and initialize command buffers */
++ ulBufSize = MRVDRV_SIZE_OF_CMD_BUFFER;
++ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
++ if (!(pTempVirtualAddr = kmalloc(ulBufSize, GFP_KERNEL))) {
++ PRINTM(INFO, "ALLOC_CMD_BUF: pTempVirtualAddr: out of memory\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ memset(pTempVirtualAddr, 0, ulBufSize);
++
++ /* Update command buffer virtual */
++ TempCmdArray[i].BufVirtualAddr = pTempVirtualAddr;
++ }
++
++ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
++ init_waitqueue_head(&TempCmdArray[i].cmdwait_q);
++ CleanupAndInsertCmd(priv, &TempCmdArray[i]);
++ }
++
++ ret = WLAN_STATUS_SUCCESS;
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function frees the command buffer.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++FreeCmdBuffer(wlan_private * priv)
++{
++ u32 ulBufSize;
++ UINT i;
++ CmdCtrlNode *TempCmdArray;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ /* need to check if cmd array is allocated or not */
++ if (Adapter->CmdArray == NULL) {
++ PRINTM(INFO, "FREE_CMD_BUF: CmdArray is Null\n");
++ goto done;
++ }
++
++ TempCmdArray = Adapter->CmdArray;
++
++ /* Release shared memory buffers */
++ ulBufSize = MRVDRV_SIZE_OF_CMD_BUFFER;
++ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
++ if (TempCmdArray[i].BufVirtualAddr) {
++ PRINTM(INFO, "Free all the array\n");
++ kfree(TempCmdArray[i].BufVirtualAddr);
++ TempCmdArray[i].BufVirtualAddr = NULL;
++ }
++ }
++
++ /* Release CmdCtrlNode */
++ if (Adapter->CmdArray) {
++ PRINTM(INFO, "Free CmdArray\n");
++ kfree(Adapter->CmdArray);
++ Adapter->CmdArray = NULL;
++ }
++
++ done:
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function gets a free command node if available in
++ * command free queue.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return CmdCtrlNode A pointer to CmdCtrlNode structure or NULL
++ */
++CmdCtrlNode *
++GetFreeCmdCtrlNode(wlan_private * priv)
++{
++ CmdCtrlNode *TempNode;
++ wlan_adapter *Adapter = priv->adapter;
++ ulong flags;
++
++ ENTER();
++
++ if (!Adapter)
++ return NULL;
++
++ spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
++
++ if (!list_empty(&Adapter->CmdFreeQ)) {
++ TempNode = (CmdCtrlNode *) Adapter->CmdFreeQ.next;
++ list_del((struct list_head *) TempNode);
++ } else {
++ PRINTM(WARN, "GET_CMD_NODE: CmdCtrlNode is not available\n");
++ TempNode = NULL;
++ }
++
++ spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
++
++ if (TempNode) {
++ CleanUpCmdCtrlNode(TempNode);
++ }
++
++ LEAVE();
++ return TempNode;
++}
++
++/**
++ * @brief This function cleans command node.
++ *
++ * @param pTempNode A pointer to CmdCtrlNode structure
++ * @return n/a
++ */
++void
++CleanUpCmdCtrlNode(CmdCtrlNode * pTempNode)
++{
++ ENTER();
++
++ if (!pTempNode)
++ return;
++ pTempNode->CmdWaitQWoken = TRUE;
++
++ if (pTempNode->wait_option & HostCmd_OPTION_WAITFORRSP) {
++ wake_up_interruptible(&pTempNode->cmdwait_q);
++ }
++ pTempNode->Status = 0;
++ pTempNode->cmd_oid = (WLAN_OID) 0;
++ pTempNode->wait_option = 0;
++ pTempNode->CmdFlags = 0;
++ pTempNode->pdata_buf = NULL;
++
++ if (pTempNode->BufVirtualAddr != NULL)
++ memset(pTempNode->BufVirtualAddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
++
++ LEAVE();
++ return;
++}
++
++/**
++ * @brief This function initializes the command node.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param pTempNode A pointer to CmdCtrlNode structure
++ * @param cmd_oid cmd oid: treated as sub command
++ * @param wait_option wait option: wait response or not
++ * @param pdata_buf A pointer to informaion buffer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++void
++SetCmdCtrlNode(wlan_private * priv,
++ CmdCtrlNode * pTempNode,
++ WLAN_OID cmd_oid, u16 wait_option, void *pdata_buf)
++{
++ ENTER();
++
++ if (!pTempNode)
++ return;
++
++ pTempNode->cmd_oid = cmd_oid;
++ pTempNode->wait_option = wait_option;
++ pTempNode->pdata_buf = pdata_buf;
++
++ LEAVE();
++}
++
++/**
++ * @brief This function executes next command in command
++ * pending queue. It will put fimware back to PS mode
++ * if applicable.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++ExecuteNextCommand(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ CmdCtrlNode *CmdNode = NULL;
++ HostCmd_DS_COMMAND *CmdPtr;
++ ulong flags;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (!Adapter) {
++ PRINTM(MSG, "EXEC_NEXT_CMD: Adapter is NULL\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
++
++ if (Adapter->CurCmd) {
++ PRINTM(MSG, "EXEC_NEXT_CMD: there is command in processing!\n");
++ spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ if (!list_empty(&Adapter->CmdPendingQ)) {
++ CmdNode = (CmdCtrlNode *)
++ Adapter->CmdPendingQ.next;
++ }
++
++ spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
++
++ if (CmdNode) {
++ CmdPtr = (HostCmd_DS_COMMAND *) CmdNode->BufVirtualAddr;
++
++ if (Is_Command_Allowed_In_PS(CmdPtr->Command)) {
++ if ((Adapter->PSState == PS_STATE_SLEEP)
++ || (Adapter->PSState == PS_STATE_PRE_SLEEP)
++ ) {
++ PRINTM(INFO,
++ "EXEC_NEXT_CMD: Cannot send cmd 0x%x in PSState %d\n",
++ CmdPtr->Command, Adapter->PSState);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ PRINTM(INFO, "EXEC_NEXT_CMD: OK to send command "
++ "0x%x in PSState %d\n", CmdPtr->Command, Adapter->PSState);
++ } else if (Adapter->PSState != PS_STATE_FULL_POWER) {
++ /*
++ * 1. Non-PS command:
++ * Queue it. set NeedToWakeup to TRUE if current state
++ * is SLEEP, otherwise call PSWakeup to send Exit_PS.
++ * 2. PS command but not Exit_PS:
++ * Ignore it.
++ * 3. PS command Exit_PS:
++ * Set NeedToWakeup to TRUE if current state is SLEEP,
++ * otherwise send this command down to firmware
++ * immediately.
++ */
++ if (CmdPtr->Command !=
++ wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE)) {
++ /* Prepare to send Exit PS,
++ * this non PS command will be sent later */
++ if ((Adapter->PSState == PS_STATE_SLEEP)
++ || (Adapter->PSState == PS_STATE_PRE_SLEEP)
++ ) {
++ /* w/ new scheme, it will not reach here.
++ since it is blocked in main_thread. */
++ Adapter->NeedToWakeup = TRUE;
++ } else
++ PSWakeup(priv, 0);
++
++ ret = WLAN_STATUS_SUCCESS;
++ goto done;
++ } else {
++ /*
++ * PS command. Ignore it if it is not Exit_PS.
++ * otherwise send it down immediately.
++ */
++ HostCmd_DS_802_11_PS_MODE *psm = &CmdPtr->params.psmode;
++
++ PRINTM(INFO, "EXEC_NEXT_CMD: PS cmd- Action=0x%x\n",
++ psm->Action);
++ if (psm->Action != wlan_cpu_to_le16(HostCmd_SubCmd_Exit_PS)) {
++ PRINTM(INFO, "EXEC_NEXT_CMD: Ignore Enter PS cmd\n");
++ list_del((struct list_head *) CmdNode);
++ CleanupAndInsertCmd(priv, CmdNode);
++
++ ret = WLAN_STATUS_SUCCESS;
++ goto done;
++ }
++
++ if ((Adapter->PSState == PS_STATE_SLEEP)
++ || (Adapter->PSState == PS_STATE_PRE_SLEEP)
++ ) {
++ PRINTM(INFO,
++ "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n");
++ list_del((struct list_head *) CmdNode);
++ CleanupAndInsertCmd(priv, CmdNode);
++ Adapter->NeedToWakeup = TRUE;
++
++ ret = WLAN_STATUS_SUCCESS;
++ goto done;
++ }
++
++ PRINTM(INFO, "EXEC_NEXT_CMD: Sending Exit_PS down...\n");
++ }
++ }
++ list_del((struct list_head *) CmdNode);
++ DownloadCommandToStation(priv, CmdNode);
++ } else {
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ /*
++ * check if in power save mode, if yes, put the device back
++ * to PS mode
++ */
++ if ((Adapter->PSMode != Wlan802_11PowerModeCAM) &&
++ (Adapter->PSState == PS_STATE_FULL_POWER)) {
++ if (Adapter->SecInfo.WPAEnabled
++ || Adapter->SecInfo.WPA2Enabled) {
++ if (Adapter->IsGTK_SET) {
++ PRINTM(INFO, "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
++ " go back to PS_SLEEP");
++ PSSleep(priv, 0);
++ }
++ } else {
++ if ((Adapter->InfrastructureMode != Wlan802_11IBSS)
++ || Adapter->CurBssParams.BSSDescriptor.ATIMWindow) {
++ PRINTM(INFO, "EXEC_NEXT_CMD: Command PendQ is empty,"
++ " go back to PS_SLEEP");
++ PSSleep(priv, 0);
++ }
++ }
++ }
++ } else {
++ /*
++ * check if in auto deep sleep mode, if yes, put the device back
++ * to DS mode
++ */
++ if (Adapter->IsAutoDeepSleepEnabled && !Adapter->IntCounter) {
++ PRINTM(INFO, "Entering Auto Deep Sleep mode...\n");
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_DEEP_SLEEP, 0,
++ 0, 0, NULL);
++ }
++ }
++ /* The hs_activate command is sent when Host Sleep is configured
++ and de-activated in full power mode. */
++ if (Adapter->bHostSleepConfigured && !Adapter->HS_Activated
++ && ((Adapter->MediaConnectStatus == WlanMediaStateConnected)
++ || (!Adapter->IsAutoDeepSleepEnabled))
++ && (((Adapter->PSMode == Wlan802_11PowerModeCAM)
++ && (Adapter->PSState == PS_STATE_FULL_POWER))
++ || ((Adapter->InfrastructureMode == Wlan802_11IBSS)
++ && !Adapter->CurBssParams.BSSDescriptor.ATIMWindow)
++ )) {
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_HOST_SLEEP_ACTIVATE,
++ 0, 0, 0, NULL);
++ }
++ }
++
++ ret = WLAN_STATUS_SUCCESS;
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function handles the timeout of command sending.
++ * It will re-send the same command again.
++ *
++ * @param FunctionContext A pointer to FunctionContext
++ * @return n/a
++ */
++void
++MrvDrvCommandTimerFunction(void *FunctionContext)
++{
++ wlan_private *priv = (wlan_private *) FunctionContext;
++ wlan_adapter *Adapter = priv->adapter;
++ CmdCtrlNode *pTempNode;
++ HostCmd_DS_COMMAND *CmdPtr;
++
++ ENTER();
++
++ PRINTM(CMND, "Command timeout.\n");
++
++ Adapter->CommandTimerIsSet = FALSE;
++
++ if (!Adapter->num_cmd_timeout)
++ Adapter->dbg.num_cmd_timeout++;
++
++ pTempNode = Adapter->CurCmd;
++
++ if (pTempNode == NULL) {
++ PRINTM(INFO, "CurCmd Empty\n");
++ goto exit;
++ }
++
++ CmdPtr = (HostCmd_DS_COMMAND *) pTempNode->BufVirtualAddr;
++ if (CmdPtr == NULL) {
++ goto exit;
++ }
++
++ if (CmdPtr->Size) {
++ Adapter->dbg.TimeoutCmdId = wlan_cpu_to_le16(CmdPtr->Command);
++ Adapter->dbg.TimeoutCmdAct =
++ wlan_cpu_to_le16(*(u16 *) ((u8 *) CmdPtr + S_DS_GEN));
++ PRINTM(CMND, "Timeout cmd = 0x%x, act = 0x%x\n",
++ Adapter->dbg.TimeoutCmdId, Adapter->dbg.TimeoutCmdAct);
++ }
++#define MAX_CMD_TIMEOUT_COUNT 3
++ Adapter->num_cmd_timeout++;
++ if (Adapter->num_cmd_timeout > MAX_CMD_TIMEOUT_COUNT) {
++ PRINTM(FATAL, "num_cmd_timeout=%d\n", Adapter->num_cmd_timeout);
++ goto exit;
++ }
++
++ /* Restart the timer to trace command response again */
++ ModTimer(&Adapter->MrvDrvCommandTimer, MRVDRV_TIMER_1S);
++ Adapter->CommandTimerIsSet = TRUE;
++
++ /* Wake up main thread to read int status register */
++ Adapter->IntCounter++;
++ wake_up_interruptible(&priv->MainThread.waitQ);
++
++ exit:
++ LEAVE();
++ return;
++}
++
++/**
++ * @brief This function sends sleep confirm command to firmware.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmdptr A pointer to the command
++ * @param size the size of command
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++SendConfirmSleep(wlan_private * priv, u8 * CmdPtr, u16 size)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++ static u32 i = 0;
++
++ ENTER();
++
++ HEXDUMP("SLEEP_CFM", CmdPtr, size);
++
++ ret = sbi_host_to_card(priv, MVMS_CMD, CmdPtr, size);
++ priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
++
++ if (ret) {
++ PRINTM(MSG, "SLEEP_CFM: sbi_host_to_card() failed\n");
++ Adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
++ } else {
++ Adapter->PSState = PS_STATE_SLEEP;
++
++ if (Adapter->bHostSleepConfigured &&
++ (Adapter->sleep_period.period == 0)) {
++ Adapter->bWakeupDevRequired = TRUE;
++
++ wlan_host_sleep_activated_event(priv);
++ }
++#define NUM_SC_PER_LINE 16
++ if (++i % NUM_SC_PER_LINE == 0) {
++ PRINTM(EVENT, "+\n");
++ } else {
++ PRINTM(EVENT, "+");
++ }
++
++ /* check if interrupt is received after sleep confirm */
++ if (Adapter->IntCounter) {
++ PRINTM(INFO, "SLEEP_CFM: After sent, IntCnt=%d\n",
++ Adapter->IntCounter);
++ Adapter->PSState = PS_STATE_AWAKE;
++
++ }
++
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function sends Enter_PS command to firmware.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wait_option wait response or not
++ * @return n/a
++ */
++void
++PSSleep(wlan_private * priv, int wait_option)
++{
++
++ ENTER();
++
++ PrepareAndSendCommand(priv, HostCmd_CMD_802_11_PS_MODE,
++ HostCmd_SubCmd_Enter_PS, wait_option, 0, NULL);
++
++ LEAVE();
++ return;
++}
++
++/**
++ * @brief This function sends Eixt_PS command to firmware.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wait_option wait response or not
++ * @return n/a
++ */
++void
++PSWakeup(wlan_private * priv, int wait_option)
++{
++ WLAN_802_11_POWER_MODE LocalPSMode;
++
++ ENTER();
++
++ LocalPSMode = Wlan802_11PowerModeCAM;
++
++ PrepareAndSendCommand(priv, HostCmd_CMD_802_11_PS_MODE,
++ HostCmd_SubCmd_Exit_PS,
++ wait_option, 0, &LocalPSMode);
++
++ LEAVE();
++ return;
++}
++
++/**
++ * @brief This function checks condition and prepares to
++ * send sleep confirm command to firmware if ok.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param PSMode Power Saving mode
++ * @return n/a
++ */
++void
++PSConfirmSleep(wlan_private * priv, u16 PSMode)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (!priv->wlan_dev.dnld_sent && !Adapter->CurCmd && !Adapter->IntCounter) {
++ SendConfirmSleep(priv, (u8 *) & Adapter->PSConfirmSleep,
++ sizeof(PS_CMD_ConfirmSleep));
++
++ os_start_queue(priv);
++ } else {
++ PRINTM(INFO, "Delay Sleep Confirm (%s%s%s)\n",
++ (priv->wlan_dev.dnld_sent) ? "D" : "",
++ (Adapter->CurCmd) ? "C" : "",
++ (Adapter->IntCounter) ? "I" : "");
++ }
++
++ LEAVE();
++}
+diff --git a/drivers/net/wireless/marvell8686/wlan_cmdresp.c b/drivers/net/wireless/marvell8686/wlan_cmdresp.c
+new file mode 100644
+index 0000000..780c997
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_cmdresp.c
+@@ -0,0 +1,1595 @@
++/** @file wlan_cmdresp.c
++ * @brief This file contains the handling of command
++ * responses as well as events generated by firmware.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ */
++/********************************************************
++Change log:
++ 10/10/05: Add Doxygen format comments
++ 11/11/05: Add support for WMM Status change event
++ 12/13/05: Add Proprietary periodic sleep support
++ 12/23/05: Fix bug in adhoc start where the current index was
++ not properly being assigned before it was used.
++ 01/05/06: Add kernel 2.6.x support
++ 01/11/06: Conditionalize new scan/join structures.
++ Update assoc response handling; entire IEEE response returned
++ 04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
++ 04/10/06: Add hostcmd generic API
++ 04/18/06: Remove old Subscrive Event and add new Subscribe Event
++ implementation through generic hostcmd API
++ 05/04/06: Add IBSS coalescing related new hostcmd response handling
++ 05/08/06: Remove PermanentAddr from Adapter
++ 06/08/06: Remove function HandleMICFailureEvent()
++ 08/29/06: Add ledgpio private command
++********************************************************/
++
++#include "include.h"
++
++/********************************************************
++ Local Variables
++********************************************************/
++
++/********************************************************
++ Global Variables
++********************************************************/
++
++/********************************************************
++ Local Functions
++********************************************************/
++
++/**
++ * @brief This function handles disconnect event. it
++ * reports disconnect to upper layer, clean tx/rx packets,
++ * reset link state etc.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return n/a
++ */
++void
++MacEventDisconnected(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ union iwreq_data wrqu;
++
++ ENTER();
++
++ if (Adapter->MediaConnectStatus != WlanMediaStateConnected)
++ return;
++
++ PRINTM(INFO, "Handles disconnect event.\n");
++
++ /* Free Tx and Rx packets, report disconnect to upper layer */
++ wlan_clean_txrx(priv);
++
++ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
++ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
++
++ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
++
++ /* reset SNR/NF/RSSI values */
++ memset(Adapter->SNR, 0x00, sizeof(Adapter->SNR));
++ memset(Adapter->NF, 0x00, sizeof(Adapter->NF));
++ memset(Adapter->RSSI, 0x00, sizeof(Adapter->RSSI));
++ memset(Adapter->rawSNR, 0x00, sizeof(Adapter->rawSNR));
++ memset(Adapter->rawNF, 0x00, sizeof(Adapter->rawNF));
++ Adapter->nextSNRNF = 0;
++ Adapter->numSNRNF = 0;
++ Adapter->RxPDRate = 0;
++ PRINTM(INFO, "Current SSID=%s, Ssid Length=%u\n",
++ Adapter->CurBssParams.BSSDescriptor.Ssid.Ssid,
++ Adapter->CurBssParams.BSSDescriptor.Ssid.SsidLength);
++ PRINTM(INFO, "Previous SSID=%s, Ssid Length=%u\n",
++ Adapter->PreviousSSID.Ssid, Adapter->PreviousSSID.SsidLength);
++
++ Adapter->SecInfo.WPAEnabled = FALSE;
++ Adapter->SecInfo.WPA2Enabled = FALSE;
++ Adapter->Wpa_ie_len = 0;
++ Adapter->SecInfo.EncryptionMode = CIPHER_NONE;
++
++ Adapter->MediaConnectStatus = WlanMediaStateDisconnected;
++
++ Adapter->AdhocLinkSensed = FALSE;
++
++ /*
++ * memorize the previous SSID and BSSID
++ * it could be used for re-assoc
++ */
++ memcpy(&Adapter->PreviousSSID,
++ &Adapter->CurBssParams.BSSDescriptor.Ssid,
++ sizeof(WLAN_802_11_SSID));
++ memcpy(Adapter->PreviousBSSID,
++ Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
++
++ /* need to erase the current SSID and BSSID info */
++ memset(&Adapter->CurBssParams, 0x00, sizeof(Adapter->CurBssParams));
++
++ if (Adapter->PSState != PS_STATE_FULL_POWER) {
++ /* make firmware to exit PS mode */
++ PRINTM(INFO, "Disconnected, so exit PS mode.\n");
++ PSWakeup(priv, 0);
++ }
++
++ LEAVE();
++}
++
++/**
++ * @brief This function handles link lost, deauth and
++ * disassoc events.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return n/a
++ */
++static void
++HandleDisconnectEvent(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ MacEventDisconnected(priv);
++#ifdef REASSOCIATION
++ if (Adapter->Reassoc_on == TRUE) {
++ PRINTM(INFO, "RE-ASSOC: trigger the timer\n");
++ Adapter->ReassocTimerIsSet = TRUE;
++ ModTimer(&Adapter->MrvDrvTimer, 0);
++ }
++#endif /* REASSOCIATION */
++ }
++}
++
++/**
++ * @brief This function handles the command response of reg_access
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param type the type of reg access (MAC, BBP or RF)
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_reg_access(wlan_private * priv, u16 type, HostCmd_DS_COMMAND * resp)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ wlan_offset_value *pOffsetValue =
++ (wlan_offset_value *) Adapter->CurCmd->pdata_buf;
++
++ ENTER();
++
++ switch (type) {
++ case HostCmd_RET_MAC_REG_ACCESS:
++ {
++ HostCmd_DS_MAC_REG_ACCESS *reg;
++
++ reg = (HostCmd_DS_MAC_REG_ACCESS *) & resp->params.macreg;
++
++ pOffsetValue->offset = wlan_le16_to_cpu(reg->Offset);
++ pOffsetValue->value = wlan_le32_to_cpu(reg->Value);
++ break;
++ }
++
++ case HostCmd_RET_BBP_REG_ACCESS:
++ {
++ HostCmd_DS_BBP_REG_ACCESS *reg;
++ reg = (HostCmd_DS_BBP_REG_ACCESS *) & resp->params.bbpreg;
++
++ pOffsetValue->offset = wlan_le16_to_cpu(reg->Offset);
++ pOffsetValue->value = (u8) reg->Value;
++ break;
++ }
++
++ case HostCmd_RET_RF_REG_ACCESS:
++ {
++ HostCmd_DS_RF_REG_ACCESS *reg;
++ reg = (HostCmd_DS_RF_REG_ACCESS *) & resp->params.rfreg;
++
++ pOffsetValue->offset = wlan_le16_to_cpu(reg->Offset);
++ pOffsetValue->value = (u8) reg->Value;
++ break;
++ }
++
++ default:
++ LEAVE();
++ return WLAN_STATUS_FAILURE;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of get_hw_spec
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_get_hw_spec(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ u32 i;
++ HostCmd_DS_GET_HW_SPEC *hwspec = &resp->params.hwspec;
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ Adapter->fwCapInfo = wlan_le32_to_cpu(hwspec->fwCapInfo);
++
++ Adapter->FWReleaseNumber = wlan_le32_to_cpu(hwspec->FWReleaseNumber);
++
++ PRINTM(INFO, "GET_HW_SPEC: FWReleaseVersion- 0x%X\n",
++ Adapter->FWReleaseNumber);
++ PRINTM(INFO, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
++ hwspec->PermanentAddr[0], hwspec->PermanentAddr[1],
++ hwspec->PermanentAddr[2], hwspec->PermanentAddr[3],
++ hwspec->PermanentAddr[4], hwspec->PermanentAddr[5]);
++ PRINTM(INFO, "GET_HW_SPEC: HWIfVersion=0x%X Version=0x%X\n",
++ wlan_le16_to_cpu(hwspec->HWIfVersion),
++ wlan_le16_to_cpu(hwspec->Version));
++
++ Adapter->RegionCode = wlan_le16_to_cpu(hwspec->RegionCode);
++
++ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
++ /* use the region code to search for the index */
++ if (Adapter->RegionCode == RegionCodeToIndex[i]) {
++ break;
++ }
++ }
++
++ /* if it's unidentified region code, use the default (USA) */
++ if (i >= MRVDRV_MAX_REGION_CODE) {
++ Adapter->RegionCode = 0x10;
++ PRINTM(WARN, "unidentified region code, use the default (USA)\n");
++ }
++
++ /* HACK IT MAKE RegionCode always equals 0x30 */
++ Adapter->RegionCode = 0x30;
++
++ if (Adapter->CurrentAddr[0] == 0xff) {
++ memmove(Adapter->CurrentAddr, hwspec->PermanentAddr, ETH_ALEN);
++ }
++ /* HACK PermanentAddr[0] Equals 0xFF */
++ if (Adapter->CurrentAddr[0] == 0xff) {
++ Adapter->CurrentAddr[0] = 0x00;
++ Adapter->CurrentAddr[1] = 0x1a;
++ Adapter->CurrentAddr[2] = 0x6b;
++ }
++ memcpy(priv->wlan_dev.netdev->dev_addr, Adapter->CurrentAddr, ETH_ALEN);
++
++ if (wlan_set_regiontable(priv, Adapter->RegionCode, 0)) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ if (wlan_set_universaltable(priv, 0)) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function handles the command response of host_sleep_cfg
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_host_sleep_cfg(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ HostCmd_DS_802_11_HOST_SLEEP_CFG *hscfg = &resp->params.hostsleepcfg;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (hscfg->conditions != HOST_SLEEP_CFG_CANCEL) {
++ Adapter->bHostSleepConfigured = TRUE;
++ } else {
++ Adapter->bHostSleepConfigured = FALSE;
++ if (Adapter->PSState == PS_STATE_FULL_POWER && Adapter->HS_Activated) {
++ wlan_host_sleep_deactivated_event(priv);
++ }
++ os_start_queue(priv);
++ os_carrier_on(priv);
++ wmm_start_queue(priv);
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function handles the command response of fw_wakeup_method
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_fw_wakeup_method(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ HostCmd_DS_802_11_FW_WAKEUP_METHOD *fwwm = &resp->params.fwwakeupmethod;
++ u16 action;
++
++ ENTER();
++
++ action = wlan_le16_to_cpu(fwwm->Action);
++
++ switch (action) {
++ case HostCmd_ACT_GET:
++ case HostCmd_ACT_SET:
++ Adapter->fwWakeupMethod = wlan_le16_to_cpu(fwwm->Method);
++ break;
++ default:
++ break;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of sleep_params
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_sleep_params(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_802_11_SLEEP_PARAMS *sp = &resp->params.sleep_params;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ PRINTM(INFO, "error=%x offset=%x stabletime=%x calcontrol=%x\n"
++ " extsleepclk=%x\n", sp->Error, sp->Offset,
++ sp->StableTime, sp->CalControl, sp->ExternalSleepClk);
++ Adapter->sp.sp_error = wlan_le16_to_cpu(sp->Error);
++ Adapter->sp.sp_offset = wlan_le16_to_cpu(sp->Offset);
++ Adapter->sp.sp_stabletime = wlan_le16_to_cpu(sp->StableTime);
++ Adapter->sp.sp_calcontrol = wlan_le16_to_cpu(sp->CalControl);
++ Adapter->sp.sp_extsleepclk = wlan_le16_to_cpu(sp->ExternalSleepClk);
++ Adapter->sp.sp_reserved = wlan_le16_to_cpu(sp->Reserved);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of sleep_params
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_sleep_period(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_802_11_SLEEP_PERIOD *sp_period = &resp->params.ps_sleeppd;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ Adapter->sleep_period.period = wlan_le16_to_cpu(sp_period->Period);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of bca_timeshare
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_bca_timeshare(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_802_11_BCA_TIMESHARE *bca_ts = &resp->params.bca_timeshare;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ PRINTM(MSG, "TrafficType=%x TimeShareInterva=%x BTTime=%x\n",
++ bca_ts->TrafficType, bca_ts->TimeShareInterval, bca_ts->BTTime);
++
++ Adapter->bca_ts.TrafficType = wlan_le16_to_cpu(bca_ts->TrafficType);
++ Adapter->bca_ts.TimeShareInterval =
++ wlan_le32_to_cpu(bca_ts->TimeShareInterval);
++ Adapter->bca_ts.BTTime = wlan_le32_to_cpu(bca_ts->BTTime);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of mac_control
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_mac_control(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of set_wep
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_set_wep(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of reset
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_reset(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ ENTER();
++ PRINTM(INFO, "HWAC - Reset command successful\n");
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of snmp_mib
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_snmp_mib(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_802_11_SNMP_MIB *smib = &resp->params.smib;
++ u16 OID = wlan_le16_to_cpu(smib->OID);
++ u16 QueryType = wlan_le16_to_cpu(smib->QueryType);
++
++ ENTER();
++
++ PRINTM(INFO, "SNMP_RESP: value of the OID = %x, QueryType=%x\n", OID,
++ QueryType);
++ PRINTM(INFO, "SNMP_RESP: Buf size = %x\n",
++ wlan_le16_to_cpu(smib->BufSize));
++
++ if (QueryType == HostCmd_ACT_GEN_GET) {
++ switch (OID) {
++ case FragThresh_i:
++ priv->adapter->FragThsd =
++ wlan_le16_to_cpu(*((PUSHORT) (smib->Value)));
++ PRINTM(INFO, "SNMP_RESP: FragThsd =%u\n",
++ priv->adapter->FragThsd);
++ break;
++ case RtsThresh_i:
++ priv->adapter->RTSThsd =
++ wlan_le16_to_cpu(*((PUSHORT) (smib->Value)));
++ PRINTM(INFO, "SNMP_RESP: RTSThsd =%u\n", priv->adapter->RTSThsd);
++ break;
++ case ShortRetryLim_i:
++ priv->adapter->TxRetryCount =
++ wlan_le16_to_cpu(*((PUSHORT) (smib->Value)));
++ PRINTM(INFO, "SNMP_RESP: TxRetryCount =%u\n",
++ priv->adapter->RTSThsd);
++ break;
++ case DtimPeriod_i:
++ priv->adapter->Dtim =
++ wlan_le16_to_cpu(*((PUSHORT) (smib->Value)));
++ PRINTM(INFO, "SNMP_RESP: DtimPeriod =%u\n", priv->adapter->Dtim);
++ break;
++ default:
++ break;
++ }
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of radio_control
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_radio_control(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ ENTER();
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of key_material
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_key_material(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_802_11_KEY_MATERIAL *pKey = &resp->params.keymaterial;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (wlan_le16_to_cpu(pKey->Action) == HostCmd_ACT_SET) {
++ if ((wlan_le16_to_cpu(pKey->KeyParamSet.KeyInfo) &
++ KEY_INFO_TKIP_MCAST)
++ || (wlan_le16_to_cpu(pKey->KeyParamSet.KeyInfo) &
++ KEY_INFO_AES_MCAST)) {
++ PRINTM(INFO, "Key: GTK is set\n");
++ Adapter->IsGTK_SET = TRUE;
++ }
++ }
++
++ memcpy(Adapter->aeskey.KeyParamSet.Key, pKey->KeyParamSet.Key,
++ sizeof(pKey->KeyParamSet.Key));
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of mac_address
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_mac_address(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_802_11_MAC_ADDRESS *MacAdd = &resp->params.macadd;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ memcpy(Adapter->CurrentAddr, MacAdd->MacAdd, ETH_ALEN);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of rf_tx_power
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_rf_tx_power(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_802_11_RF_TX_POWER *rtp = &resp->params.txp;
++ wlan_adapter *Adapter = priv->adapter;
++ u16 Action = wlan_le16_to_cpu(rtp->Action);
++
++ ENTER();
++
++ Adapter->TxPowerLevel = wlan_le16_to_cpu(rtp->CurrentLevel);
++
++ if (Action == HostCmd_ACT_GET) {
++ Adapter->MaxTxPowerLevel = rtp->MaxPower;
++ Adapter->MinTxPowerLevel = rtp->MinPower;
++ }
++
++ PRINTM(INFO, "Current TxPower Level = %d,Max Power=%d, Min Power=%d\n",
++ Adapter->TxPowerLevel, Adapter->MaxTxPowerLevel,
++ Adapter->MinTxPowerLevel);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of rf_antenna
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_rf_antenna(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_802_11_RF_ANTENNA *pAntenna = &resp->params.rant;
++ wlan_adapter *Adapter = priv->adapter;
++ u16 Action = wlan_le16_to_cpu(pAntenna->Action);
++
++ if (Action == HostCmd_ACT_GET_RX)
++ Adapter->RxAntennaMode = wlan_le16_to_cpu(pAntenna->AntennaMode);
++
++ if (Action == HostCmd_ACT_GET_TX)
++ Adapter->TxAntennaMode = wlan_le16_to_cpu(pAntenna->AntennaMode);
++
++ PRINTM(INFO, "RF_ANT_RESP: Action = 0x%x, Mode = 0x%04x\n",
++ Action, wlan_le16_to_cpu(pAntenna->AntennaMode));
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of multicast_address
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_mac_multicast_adr(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of rate_adapt_rateset
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv,
++ HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_802_11_RATE_ADAPT_RATESET *rates = &resp->params.rateset;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (wlan_le16_to_cpu(rates->Action) == HostCmd_ACT_GET) {
++ Adapter->HWRateDropMode = wlan_le16_to_cpu(rates->HWRateDropMode);
++ Adapter->Threshold = wlan_le16_to_cpu(rates->Threshold);
++ Adapter->FinalRate = wlan_le16_to_cpu(rates->FinalRate);
++ Adapter->RateBitmap = wlan_le16_to_cpu(rates->Bitmap);
++ }
++
++ LEAVE();
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of rf_channel
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_rf_channel(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_802_11_RF_CHANNEL *rfchannel = &resp->params.rfchannel;
++ wlan_adapter *Adapter = priv->adapter;
++ u16 Action = wlan_le16_to_cpu(rfchannel->Action);
++ u16 newChannel = wlan_le16_to_cpu(rfchannel->CurrentChannel);
++
++ ENTER();
++
++ if (Action == HostCmd_OPT_802_11_RF_CHANNEL_GET
++ && Adapter->CurBssParams.BSSDescriptor.Channel != newChannel) {
++ PRINTM(INFO, "Channel Switch: %d to %d\n",
++ Adapter->CurBssParams.BSSDescriptor.Channel, newChannel);
++
++ /* Update the channel again */
++ Adapter->CurBssParams.BSSDescriptor.Channel = newChannel;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of rssi
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_rssi(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_802_11_RSSI_RSP *rssirsp = &resp->params.rssirsp;
++ wlan_adapter *Adapter = priv->adapter;
++
++ /* store the non average value */
++ Adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = wlan_le16_to_cpu(rssirsp->SNR);
++ Adapter->NF[TYPE_BEACON][TYPE_NOAVG] =
++ wlan_le16_to_cpu(rssirsp->NoiseFloor);
++
++ Adapter->SNR[TYPE_BEACON][TYPE_AVG] = wlan_le16_to_cpu(rssirsp->AvgSNR);
++ Adapter->NF[TYPE_BEACON][TYPE_AVG] =
++ wlan_le16_to_cpu(rssirsp->AvgNoiseFloor);
++
++ Adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] =
++ CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
++ Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
++
++ Adapter->RSSI[TYPE_BEACON][TYPE_AVG] =
++ CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
++ Adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
++
++ PRINTM(INFO, "Beacon RSSI value = 0x%x\n",
++ Adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++#ifdef MFG_CMD_SUPPORT
++/**
++ * @brief This function handles the command response of mfg_cmd
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_mfg_cmd(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ PRINTM(INFO, "MFG command response size = %d\n", resp->Size);
++
++ resp->Size = MIN(resp->Size, MRVDRV_SIZE_OF_CMD_BUFFER);
++ memcpy(Adapter->CurCmd->pdata_buf, (void *) resp, resp->Size);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++#endif /* MFG_CMD_SUPPORT */
++
++/**
++ * @brief This function handles the command response of cal_data_ext.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_802_11_cal_data_ext(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ HostCmd_DS_802_11_CAL_DATA_EXT *pCalDataExt = &resp->params.caldataext;
++
++ ENTER();
++
++ if (wlan_le16_to_cpu(pCalDataExt->Action) == HostCmd_ACT_GEN_GET) {
++ pCalDataExt->Action = wlan_le16_to_cpu(pCalDataExt->Action);
++ pCalDataExt->Revision = wlan_le16_to_cpu(pCalDataExt->Revision);
++ pCalDataExt->CalDataLen = wlan_le16_to_cpu(pCalDataExt->CalDataLen);
++
++ memmove(Adapter->CurCmd->pdata_buf,
++ pCalDataExt, pCalDataExt->CalDataLen + CAL_DATA_HEADER_LEN);
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of eeprom_access
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_ret_802_11_eeprom_access(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ wlan_ioctl_regrdwr *pBuf =
++ (wlan_ioctl_regrdwr *) Adapter->CurCmd->pdata_buf;
++
++ PRINTM(INFO, "eeprom read len=%x\n",
++ wlan_le16_to_cpu(resp->params.rdeeprom.ByteCount));
++ if (pBuf->NOB < wlan_le16_to_cpu(resp->params.rdeeprom.ByteCount)) {
++ pBuf->NOB = 0;
++ PRINTM(INFO, "eeprom read return length is too big\n");
++ return WLAN_STATUS_FAILURE;
++ }
++ pBuf->NOB = wlan_le16_to_cpu(resp->params.rdeeprom.ByteCount);
++ if (pBuf->NOB > 0) {
++ memcpy(&pBuf->Value, (u8 *) & resp->params.rdeeprom.Value, pBuf->NOB);
++ HEXDUMP("EEPROM", (char *) &pBuf->Value, pBuf->NOB);
++ }
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of get_log
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_ret_get_log(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_802_11_GET_LOG *LogMessage =
++ (HostCmd_DS_802_11_GET_LOG *) & resp->params.glog;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ /* TODO Convert it to Big Endian before copy */
++ memcpy(&Adapter->LogMsg, LogMessage, sizeof(HostCmd_DS_802_11_GET_LOG));
++ endian_convert_GET_LOG(Adapter->LogMsg);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++static void
++wlan_ret_802_11_IBSS_Coalesced_Status(wlan_private * priv,
++ HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_802_11_IBSS_Status *IBSSStatusRsp;
++ wlan_adapter *Adapter;
++ union iwreq_data wrqu;
++ u8 nullMac[6] = { 0, 0, 0, 0, 0, 0 };
++
++ Adapter = priv->adapter;
++ IBSSStatusRsp = &(resp->params.ibssCoalescing);
++
++ if (Adapter->CurCmd->pdata_buf)
++ *(int *) Adapter->CurCmd->pdata_buf = IBSSStatusRsp->Enable;
++
++ if (wlan_le16_to_cpu(IBSSStatusRsp->Action) == HostCmd_ACT_SET) {
++ return;
++ }
++
++ PRINTM(INFO, "New BSSID %x:%x:%x:%x:%x:%x\n",
++ IBSSStatusRsp->BSSID[0],
++ IBSSStatusRsp->BSSID[1],
++ IBSSStatusRsp->BSSID[2],
++ IBSSStatusRsp->BSSID[3],
++ IBSSStatusRsp->BSSID[4], IBSSStatusRsp->BSSID[5]);
++
++ /* if rsp has NULL BSSID, Just return.. No Action */
++ if (!memcmp(IBSSStatusRsp->BSSID, nullMac, MRVDRV_ETH_ADDR_LEN)) {
++ PRINTM(MSG, "New BSSID is NULL\n");
++ return;
++ }
++
++ /* if BSSID is diff, Send evnet to Linux */
++ if (memcmp(Adapter->CurBssParams.BSSDescriptor.MacAddress,
++ IBSSStatusRsp->BSSID, ETH_ALEN)) {
++ memcpy((void *) Adapter->CurBssParams.BSSDescriptor.MacAddress,
++ (void *) IBSSStatusRsp->BSSID, MRVDRV_ETH_ADDR_LEN);
++
++ /* Beacon Interval and ATIM window */
++ Adapter->CurBssParams.BSSDescriptor.BeaconPeriod
++ = IBSSStatusRsp->BeaconInterval;
++ Adapter->CurBssParams.BSSDescriptor.ATIMWindow
++ = IBSSStatusRsp->ATIMWindow;
++ //ERP Information
++ Adapter->CurBssParams.BSSDescriptor.ERPFlags =
++ (u8) IBSSStatusRsp->UseGRateProtection;
++
++ memset(&wrqu, 0, sizeof(wrqu));
++ memcpy(wrqu.ap_addr.sa_data,
++ Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
++ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
++
++ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
++
++ }
++}
++
++/********************************************************
++ Global Functions
++********************************************************/
++
++/**
++ * @brief This function stop tx/rx queue and free skb
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++void
++wlan_clean_txrx(wlan_private * priv)
++{
++ os_stop_queue(priv);
++ os_carrier_off(priv);
++
++ wmm_stop_queue(priv);
++ wmm_cleanup_queues(priv);
++
++ /* Free Tx and Rx packets */
++ os_free_tx_packet(priv);
++ wlan_send_rxskbQ(priv);
++}
++
++/**
++ * @brief This function handles the command response
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_process_rx_command(wlan_private * priv)
++{
++ u16 RespCmd;
++ HostCmd_DS_COMMAND *resp;
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++ ulong flags;
++ u16 Result;
++
++ ENTER();
++
++ /* Now we got response from FW, cancel the command timer */
++ if (Adapter->CommandTimerIsSet) {
++ CancelTimer(&Adapter->MrvDrvCommandTimer);
++ Adapter->CommandTimerIsSet = FALSE;
++ }
++
++ if (!Adapter->CurCmd) {
++ resp = (HostCmd_DS_COMMAND *) priv->wlan_dev.upld_buf;
++ resp->Command = wlan_le16_to_cpu(resp->Command);
++ PRINTM(ERROR, "CMD_RESP: NULL CurCmd, 0x%x\n", resp->Command);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ Adapter->num_cmd_timeout = 0;
++
++ DBG_HEXDUMP(CMD_D, "CMD_RESP", Adapter->CurCmd->BufVirtualAddr,
++ priv->wlan_dev.upld_len);
++
++ resp = (HostCmd_DS_COMMAND *) (Adapter->CurCmd->BufVirtualAddr);
++
++ resp->Command = wlan_le16_to_cpu(resp->Command);
++ resp->Size = wlan_le16_to_cpu(resp->Size);
++ resp->SeqNum = wlan_le16_to_cpu(resp->SeqNum);
++ resp->Result = wlan_le16_to_cpu(resp->Result);
++
++ RespCmd = resp->Command;
++ Result = resp->Result;
++
++ /* Save the last command response to debug log */
++ Adapter->dbg.LastCmdRespIndex =
++ (Adapter->dbg.LastCmdRespIndex + 1) % DBG_CMD_NUM;
++ Adapter->dbg.LastCmdRespId[Adapter->dbg.LastCmdRespIndex] = RespCmd;
++
++ PRINTM(CMND, "CMD_RESP: 0x%x, result %d, len %d, seqno %d @ %lu\n",
++ RespCmd, Result, resp->Size, resp->SeqNum, os_time_get());
++
++ if (!(RespCmd & 0x8000)) {
++ PRINTM(ERROR, "CMD_RESP: Invalid response to command!");
++ Adapter->CurCmdRetCode = WLAN_STATUS_FAILURE;
++ CleanupAndInsertCmd(priv, Adapter->CurCmd);
++ spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
++ Adapter->CurCmd = NULL;
++ spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
++
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ /* Store the response code to CurCmdRetCode. */
++ Adapter->CurCmdRetCode = resp->Result;
++
++ if (RespCmd == HostCmd_RET_802_11_PS_MODE) {
++ HostCmd_DS_802_11_PS_MODE *psmode;
++
++ psmode = &resp->params.psmode;
++ PRINTM(INFO, "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
++ resp->Result, psmode->Action);
++ psmode->Action = wlan_cpu_to_le16(psmode->Action);
++
++ if (Result) {
++ PRINTM(ERROR, "CMD_RESP: PS command failed- %#x \n",
++ resp->Result);
++ if (Adapter->InfrastructureMode == Wlan802_11IBSS) {
++ /*
++ * We should not re-try enter-ps command in
++ * ad-hoc mode. It takes place in
++ * ExecuteNextCommand().
++ */
++ if (psmode->Action == HostCmd_SubCmd_Enter_PS)
++ Adapter->PSMode = Wlan802_11PowerModeCAM;
++ }
++ } else if (psmode->Action == HostCmd_SubCmd_Enter_PS) {
++ Adapter->NeedToWakeup = FALSE;
++ Adapter->PSState = PS_STATE_AWAKE;
++
++ if (Adapter->MediaConnectStatus != WlanMediaStateConnected) {
++ /*
++ * When Deauth Event received before Enter_PS command
++ * response, We need to wake up the firmware.
++ */
++ PRINTM(INFO,
++ "CMD_RESP: Disconnected, Going to invoke PSWakeup\n");
++ PSWakeup(priv, 0);
++ }
++ } else if (psmode->Action == HostCmd_SubCmd_Exit_PS) {
++ Adapter->NeedToWakeup = FALSE;
++ Adapter->PSState = PS_STATE_FULL_POWER;
++
++ } else {
++ PRINTM(INFO, "CMD_RESP: PS- Action=0x%X\n", psmode->Action);
++ }
++
++ CleanupAndInsertCmd(priv, Adapter->CurCmd);
++ spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
++ Adapter->CurCmd = NULL;
++ spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
++
++ ret = WLAN_STATUS_SUCCESS;
++ goto done;
++ }
++
++ if (Adapter->CurCmd->CmdFlags & CMD_F_HOSTCMD) {
++ /* Copy the response back to response buffer */
++ memcpy(Adapter->CurCmd->pdata_buf, resp, resp->Size);
++
++ Adapter->CurCmd->CmdFlags &= ~CMD_F_HOSTCMD;
++
++ if ((Result == HostCmd_RESULT_OK)
++ && (RespCmd == HostCmd_RET_802_11_HOST_SLEEP_CFG)) {
++ ret = wlan_ret_host_sleep_cfg(priv, resp);
++ }
++ } else {
++ /* If the command is not successful, cleanup and return failure */
++ if ((Result != HostCmd_RESULT_OK || !(RespCmd & 0x8000))) {
++ PRINTM(ERROR, "CMD_RESP: cmd %#x error, result=%#x\n",
++ resp->Command, resp->Result);
++ /*
++ * Handling errors here
++ */
++ switch (RespCmd) {
++ case HostCmd_RET_HW_SPEC_INFO:
++ PRINTM(INFO, "CMD_RESP: HW spec command Failed\n");
++ break;
++
++ }
++
++ CleanupAndInsertCmd(priv, Adapter->CurCmd);
++ spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
++ Adapter->CurCmd = NULL;
++ spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
++
++ return WLAN_STATUS_FAILURE;
++ }
++
++ switch (RespCmd) {
++ case HostCmd_RET_MAC_REG_ACCESS:
++ case HostCmd_RET_BBP_REG_ACCESS:
++ case HostCmd_RET_RF_REG_ACCESS:
++ ret = wlan_ret_reg_access(priv, RespCmd, resp);
++
++ break;
++
++ case HostCmd_RET_HW_SPEC_INFO:
++ ret = wlan_ret_get_hw_spec(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_BG_SCAN_QUERY:
++ {
++ union iwreq_data wrqu;
++
++ ret = wlan_ret_802_11_scan(priv, resp);
++ memset(&wrqu, 0, sizeof(union iwreq_data));
++ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
++ NULL);
++ PRINTM(INFO, "CMD_RESP: BG_SCAN result is ready!\n");
++ break;
++ }
++ case HostCmd_RET_802_11_SCAN:
++ ret = wlan_ret_802_11_scan(priv, resp);
++ break;
++
++ case HostCmd_RET_MAC_CONTROL:
++ ret = wlan_ret_mac_control(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_GET_LOG:
++ ret = wlan_ret_get_log(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_ASSOCIATE:
++ ret = wlan_ret_802_11_associate(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_DEAUTHENTICATE:
++ ret = wlan_ret_802_11_disassociate(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_SET_WEP:
++ ret = wlan_ret_802_11_set_wep(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_AD_HOC_START:
++ case HostCmd_RET_802_11_AD_HOC_JOIN:
++ ret = wlan_ret_802_11_ad_hoc(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_RESET:
++ ret = wlan_ret_802_11_reset(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_SNMP_MIB:
++ ret = wlan_ret_802_11_snmp_mib(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_RF_TX_POWER:
++ ret = wlan_ret_802_11_rf_tx_power(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_RADIO_CONTROL:
++ ret = wlan_ret_802_11_radio_control(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_HOST_SLEEP_CFG:
++ ret = wlan_ret_host_sleep_cfg(priv, resp);
++ break;
++ case HostCmd_RET_802_11_WAKEUP_CONFIRM:
++ wlan_host_sleep_deactivated_event(priv);
++ break;
++ case HostCmd_RET_802_11_HOST_SLEEP_ACTIVATE:
++ if (Adapter->bHostSleepConfigured
++ && Adapter->HSCfg.gap == HOST_SLEEP_CFG_GAP_FF)
++ Adapter->bWakeupDevRequired = TRUE;
++ wlan_host_sleep_activated_event(priv);
++ break;
++
++ case HostCmd_RET_802_11_RF_ANTENNA:
++ ret = wlan_ret_802_11_rf_antenna(priv, resp);
++ break;
++
++ case HostCmd_RET_MAC_MULTICAST_ADR:
++ ret = wlan_ret_mac_multicast_adr(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_RATE_ADAPT_RATESET:
++ ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
++ break;
++ case HostCmd_RET_802_11_RF_CHANNEL:
++ ret = wlan_ret_802_11_rf_channel(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_RSSI:
++ ret = wlan_ret_802_11_rssi(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_MAC_ADDRESS:
++ ret = wlan_ret_802_11_mac_address(priv, resp);
++ break;
++
++#ifdef MFG_CMD_SUPPORT
++ case HostCmd_RET_MFG_COMMAND:
++ ret = wlan_ret_mfg_cmd(priv, resp);
++ break;
++#endif
++ case HostCmd_RET_802_11_AD_HOC_STOP:
++ ret = wlan_ret_802_11_ad_hoc_stop(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_CAL_DATA_EXT:
++ ret = wlan_ret_802_11_cal_data_ext(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_KEY_MATERIAL:
++ ret = wlan_ret_802_11_key_material(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_EEPROM_ACCESS:
++ ret = wlan_ret_802_11_eeprom_access(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11D_DOMAIN_INFO:
++ ret = wlan_ret_802_11d_domain_info(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_SLEEP_PARAMS:
++ ret = wlan_ret_802_11_sleep_params(priv, resp);
++ break;
++ case HostCmd_RET_802_11_BCA_CONFIG_TIMESHARE:
++ ret = wlan_ret_802_11_bca_timeshare(priv, resp);
++ break;
++ case HostCmd_RET_802_11_INACTIVITY_TIMEOUT:
++ *((u16 *) Adapter->CurCmd->pdata_buf) =
++ wlan_le16_to_cpu(resp->params.inactivity_timeout.Timeout);
++ break;
++ case HostCmd_RET_802_11_BG_SCAN_CONFIG:
++ break;
++
++ case HostCmd_RET_802_11_FW_WAKE_METHOD:
++ ret = wlan_ret_fw_wakeup_method(priv, resp);
++ break;
++
++ case HostCmd_RET_802_11_SLEEP_PERIOD:
++ ret = wlan_ret_802_11_sleep_period(priv, resp);
++ break;
++ case HostCmd_RET_WMM_GET_STATUS:
++ ret = wlan_cmdresp_wmm_get_status(priv, resp);
++ break;
++ case HostCmd_RET_WMM_ADDTS_REQ:
++ ret = wlan_cmdresp_wmm_addts_req(priv, resp);
++ break;
++ case HostCmd_RET_WMM_DELTS_REQ:
++ ret = wlan_cmdresp_wmm_delts_req(priv, resp);
++ break;
++ case HostCmd_RET_WMM_QUEUE_CONFIG:
++ ret = wlan_cmdresp_wmm_queue_config(priv, resp);
++ break;
++ case HostCmd_RET_WMM_QUEUE_STATS:
++ ret = wlan_cmdresp_wmm_queue_stats(priv, resp);
++ break;
++ case HostCmd_RET_TX_PKT_STATS:
++ memcpy(Adapter->CurCmd->pdata_buf,
++ &resp->params.txPktStats, sizeof(HostCmd_DS_TX_PKT_STATS));
++ ret = WLAN_STATUS_SUCCESS;
++ break;
++ case HostCmd_RET_802_11_TPC_CFG:
++ memmove(Adapter->CurCmd->pdata_buf,
++ &resp->params.tpccfg, sizeof(HostCmd_DS_802_11_TPC_CFG));
++ break;
++ case HostCmd_RET_802_11_LED_CONTROL:
++ {
++ HostCmd_DS_802_11_LED_CTRL *pLedCtrl = &resp->params.ledgpio;
++ MrvlIEtypes_LedGpio_t *pGpio = &pLedCtrl->LedGpio;
++ MrvlIEtypes_LedBehavior_t *pBehavior = pLedCtrl->LedBehavior;
++
++ pLedCtrl->Action = wlan_le16_to_cpu(pLedCtrl->Action);
++ pLedCtrl->LedNums = wlan_le16_to_cpu(pLedCtrl->LedNums);
++ pGpio->Header.Type = wlan_le16_to_cpu(pGpio->Header.Type);
++ pGpio->Header.Len = wlan_le16_to_cpu(pGpio->Header.Len);
++ pBehavior->Header.Type =
++ wlan_le16_to_cpu(pBehavior->Header.Type);
++ pBehavior->Header.Len =
++ wlan_le16_to_cpu(pBehavior->Header.Len);
++ memmove(Adapter->CurCmd->pdata_buf, &resp->params.ledgpio,
++ sizeof(HostCmd_DS_802_11_LED_CTRL));
++ break;
++ }
++
++ case HostCmd_RET_GET_TSF:
++ resp->params.gettsf.TsfValue =
++ wlan_le64_to_cpu(resp->params.gettsf.TsfValue);
++ memcpy(priv->adapter->CurCmd->pdata_buf,
++ &resp->params.gettsf.TsfValue, sizeof(u64));
++ break;
++ case HostCmd_RTE_802_11_TX_RATE_QUERY:
++ priv->adapter->TxRate =
++ wlan_le16_to_cpu(resp->params.txrate.TxRate);
++ break;
++ case HostCmd_RET_802_11_IBSS_COALESCING_STATUS:
++ wlan_ret_802_11_IBSS_Coalesced_Status(priv, resp);
++ break;
++
++ case HostCmd_RET_SDIO_GPIO_INT_CONFIG:
++ memmove(Adapter->CurCmd->pdata_buf,
++ &resp->params.sdio_int,
++ sizeof(HostCmd_DS_SDIO_INT_CONFIG));
++ break;
++
++ case HostCmd_RET_SDIO_PULL_CTRL:
++ memmove(Adapter->CurCmd->pdata_buf,
++ &resp->params.sdiopullctl,
++ sizeof(HostCmd_DS_SDIO_PULL_CTRL));
++ break;
++
++ case HostCmd_RET_802_11_LDO_CONFIG:
++ resp->params.ldocfg.Action =
++ wlan_le16_to_cpu(resp->params.ldocfg.Action);
++ resp->params.ldocfg.PMSource =
++ wlan_le16_to_cpu(resp->params.ldocfg.PMSource);
++ memmove(Adapter->CurCmd->pdata_buf, &resp->params.ldocfg,
++ sizeof(HostCmd_DS_802_11_LDO_CONFIG));
++ break;
++
++ case HostCmd_RET_VERSION_EXT:
++ memcpy(Adapter->CurCmd->pdata_buf,
++ &resp->params.verext, sizeof(HostCmd_DS_VERSION_EXT));
++ break;
++
++ default:
++ PRINTM(INFO, "CMD_RESP: Unknown command response %#x\n",
++ resp->Command);
++ break;
++ }
++ }
++
++ if (Adapter->CurCmd) {
++ /* Clean up and Put current command back to CmdFreeQ */
++ CleanupAndInsertCmd(priv, Adapter->CurCmd);
++ spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
++ Adapter->CurCmd = NULL;
++ spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
++ }
++
++ done:
++ LEAVE();
++ return ret;
++}
++
++#if WIRELESS_EXT >= 18
++/**
++ * @brief This function sends mic error event to application.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @para event MIC ERROR EVENT.
++ * @return n/a
++ */
++void
++send_mic_error_event(wlan_private * priv, u32 event)
++{
++ union iwreq_data iwrq;
++ struct iw_michaelmicfailure mic;
++
++ ENTER();
++
++ memset(&iwrq, 0, sizeof(iwrq));
++ memset(&mic, 0, sizeof(mic));
++ if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
++ mic.flags = IW_MICFAILURE_PAIRWISE;
++ } else {
++ mic.flags = IW_MICFAILURE_GROUP;
++ }
++
++ iwrq.data.pointer = &mic;
++ iwrq.data.length = sizeof(mic);
++
++ wireless_send_event(priv->wlan_dev.netdev, IWEVMICHAELMICFAILURE, &iwrq,
++ (u8 *) & mic);
++
++ LEAVE();
++ return;
++}
++#endif
++
++/**
++ * @brief This function handles events generated by firmware
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_process_event(wlan_private * priv)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_adapter *Adapter = priv->adapter;
++ u32 eventcause = Adapter->EventCause >> SBI_EVENT_CAUSE_SHIFT;
++
++ ENTER();
++
++ /* Save the last event to debug log */
++ Adapter->dbg.LastEventIndex =
++ (Adapter->dbg.LastEventIndex + 1) % DBG_CMD_NUM;
++ Adapter->dbg.LastEvent[Adapter->dbg.LastEventIndex] = eventcause;
++
++ if (eventcause != MACREG_INT_CODE_PS_SLEEP &&
++ eventcause != MACREG_INT_CODE_PS_AWAKE)
++ PRINTM(EVENT, "EVENT: 0x%x @ %lu\n", eventcause, os_time_get());
++
++ switch (eventcause) {
++ case MACREG_INT_CODE_DUMMY_HOST_WAKEUP_SIGNAL:
++ PRINTM(INFO, "EVENT: DUMMY_HOST_WAKEUP_SIGNAL\n");
++ if (!priv->adapter->HS_Activated) {
++ PRINTM(WARN, "DUMMY_HOST_WAKEUP_SIGNAL (HS_Deactivated)\n");
++ } else {
++ wlan_host_sleep_gpio_int_event(priv);
++ }
++ break;
++ case MACREG_INT_CODE_LINK_SENSED:
++ PRINTM(INFO, "EVENT: LINK_SENSED\n");
++ Adapter->AdhocLinkSensed = TRUE;
++ os_carrier_on(priv);
++ os_start_queue(priv);
++ wmm_start_queue(priv);
++ send_iwevcustom_event(priv, CUS_EVT_ADHOC_LINK_SENSED);
++ break;
++
++ case MACREG_INT_CODE_DEAUTHENTICATED:
++ PRINTM(INFO, "EVENT: Deauthenticated\n");
++ Adapter->dbg.num_event_deauth++;
++ HandleDisconnectEvent(priv);
++ break;
++
++ case MACREG_INT_CODE_DISASSOCIATED:
++ PRINTM(INFO, "EVENT: Disassociated\n");
++ Adapter->dbg.num_event_disassoc++;
++ HandleDisconnectEvent(priv);
++ break;
++
++ case MACREG_INT_CODE_LINK_LOST:
++ PRINTM(INFO, "EVENT: Link lost\n");
++ Adapter->dbg.num_event_link_lost++;
++ HandleDisconnectEvent(priv);
++ break;
++
++ case MACREG_INT_CODE_PS_SLEEP:
++ PRINTM(INFO, "EVENT: SLEEP\n");
++ PRINTM(EVENT, "_");
++
++ /* handle unexpected PS SLEEP event */
++ if (Adapter->PSState == PS_STATE_FULL_POWER) {
++ PRINTM(INFO, "EVENT: In FULL POWER mode - ignore PS SLEEP\n");
++ break;
++ }
++ Adapter->PSState = PS_STATE_PRE_SLEEP;
++ PSConfirmSleep(priv, (u16) Adapter->PSMode);
++ break;
++
++ case MACREG_INT_CODE_PS_AWAKE:
++ PRINTM(INFO, "EVENT: AWAKE \n");
++ PRINTM(EVENT, "|");
++
++ /* handle unexpected PS AWAKE event */
++ if (Adapter->PSState == PS_STATE_FULL_POWER) {
++ PRINTM(INFO, "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
++ break;
++ }
++
++ Adapter->TxLockFlag = FALSE;
++ if (TRUE == CheckLastPacketIndication(priv)) {
++ if (!priv->wlan_dev.dnld_sent && Adapter->gen_null_pkg) {
++ SendNullPacket(priv, MRVDRV_TxPD_POWER_MGMT_NULL_PACKET |
++ MRVDRV_TxPD_POWER_MGMT_LAST_PACKET);
++ Adapter->TxLockFlag = TRUE;
++ }
++ }
++
++ Adapter->PSState = PS_STATE_AWAKE;
++
++ if (Adapter->NeedToWakeup == TRUE) {
++ /*
++ * wait for the command processing to finish
++ * before resuming sending
++ * Adapter->NeedToWakeup will be set to FALSE
++ * in PSWakup()
++ */
++ PRINTM(INFO, "Waking up...\n");
++ PSWakeup(priv, 0);
++ }
++ break;
++
++ case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
++ sbi_reset_deepsleep_wakeup(priv);
++ PRINTM(INFO, "EVENT: DS_AWAKE\n");
++ if (priv->adapter->IsDeepSleep == TRUE) {
++ Adapter->IsDeepSleep = FALSE;
++ Adapter->bWakeupDevRequired = FALSE;
++ Adapter->WakeupTries = 0;
++
++ /*
++ * For auto DS + BGS case, some delay is needed to
++ * avoid going back to DS before getting BGS result
++ */
++ if (Adapter->IsAutoDeepSleepEnabled &&
++ Adapter->bgScanConfig->Enable)
++ os_sched_timeout(10);
++ priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
++ priv->adapter->HisRegCpy |= HIS_TxDnLdRdy;
++ }
++ send_iwevcustom_event(priv, CUS_EVT_DEEP_SLEEP_AWAKE);
++ wake_up_interruptible(&Adapter->ds_awake_q);
++ break;
++
++ case MACREG_INT_CODE_HOST_SLEEP_AWAKE:
++ PRINTM(INFO, "EVENT: HS_AWAKE\n");
++ Adapter->bWakeupDevRequired = FALSE;
++
++ Adapter->WakeupTries = 0;
++
++ sbi_reset_deepsleep_wakeup(priv);
++
++ /*
++ * in BG SCAN mode w/ deep sleep, WAKE UP event
++ * will be sent first, Deep Sleep Awake will
++ * be sent later.
++ */
++ if (priv->adapter->IsDeepSleep == TRUE) {
++ priv->adapter->IsDeepSleep = FALSE;
++ priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
++ priv->adapter->HisRegCpy |= HIS_TxDnLdRdy;
++ }
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_WAKEUP_CONFIRM,
++ 0, 0, 0, NULL);
++ break;
++
++ case MACREG_INT_CODE_MIC_ERR_UNICAST:
++ PRINTM(INFO, "EVENT: UNICAST MIC ERROR\n");
++#if WIRELESS_EXT >= 18
++ send_mic_error_event(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
++#else
++ send_iwevcustom_event(priv, CUS_EVT_MLME_MIC_ERR_UNI);
++#endif
++ break;
++
++ case MACREG_INT_CODE_MIC_ERR_MULTICAST:
++ PRINTM(INFO, "EVENT: MULTICAST MIC ERROR\n");
++#if WIRELESS_EXT >= 18
++ send_mic_error_event(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
++#else
++ send_iwevcustom_event(priv, CUS_EVT_MLME_MIC_ERR_MUL);
++#endif
++ break;
++ case MACREG_INT_CODE_MIB_CHANGED:
++ case MACREG_INT_CODE_INIT_DONE:
++ break;
++
++ case MACREG_INT_CODE_ADHOC_BCN_LOST:
++ PRINTM(INFO, "EVENT: ADHOC_BCN_LOST\n");
++ Adapter->AdhocLinkSensed = FALSE;
++ wlan_clean_txrx(priv);
++ send_iwevcustom_event(priv, CUS_EVT_ADHOC_BCN_LOST);
++ break;
++
++ case MACREG_INT_CODE_BG_SCAN_REPORT:
++ PRINTM(INFO, "EVENT: BGS_REPORT\n");
++ Adapter->bgScanConfig->Enable = FALSE;
++ ret = sendBgScanQueryCmd(priv);
++ break;
++ case MACREG_INT_CODE_WMM_STATUS_CHANGE:
++ PRINTM(INFO, "EVENT: WMM status changed\n");
++ ret = sendWMMStatusChangeCmd(priv);
++ break;
++
++ case MACREG_INT_CODE_RSSI_LOW:
++ PRINTM(INFO, "EVENT: RSSI_LOW\n");
++ send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_LOW);
++ break;
++ case MACREG_INT_CODE_SNR_LOW:
++ PRINTM(INFO, "EVENT: SNR_LOW\n");
++ send_iwevcustom_event(priv, CUS_EVT_BEACON_SNR_LOW);
++ break;
++ case MACREG_INT_CODE_MAX_FAIL:
++ PRINTM(INFO, "EVENT: MAX_FAIL\n");
++ send_iwevcustom_event(priv, CUS_EVT_MAX_FAIL);
++ break;
++ case MACREG_INT_CODE_RSSI_HIGH:
++ PRINTM(INFO, "EVENT: RSSI_HIGH\n");
++ send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_HIGH);
++ break;
++ case MACREG_INT_CODE_SNR_HIGH:
++ PRINTM(INFO, "EVENT: SNR_HIGH\n");
++ send_iwevcustom_event(priv, CUS_EVT_BEACON_SNR_HIGH);
++ break;
++ case MACREG_INT_CODE_PRE_BEACON_LOST:
++ PRINTM(INFO, "EVENT: Pre-Beacon Lost\n");
++ send_iwevcustom_event(priv, CUS_EVT_PRE_BEACON_LOST);
++ break;
++ case MACREG_INT_CODE_IBSS_COALESCED:
++ PRINTM(INFO, "EVENT: IBSS_COALESCED\n");
++ ret = sendADHOCBSSIDQuery(priv);
++ break;
++ default:
++ PRINTM(INFO, "EVENT: unknown event id: %#x\n", eventcause);
++ break;
++ }
++
++ Adapter->EventCause = 0;
++ LEAVE();
++ return ret;
++}
+diff --git a/drivers/net/wireless/marvell8686/wlan_debug.c b/drivers/net/wireless/marvell8686/wlan_debug.c
+new file mode 100644
+index 0000000..8a980aa
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_debug.c
+@@ -0,0 +1,281 @@
++/** @file wlan_debug.c
++ * @brief This file contains functions for debug proc file.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ */
++/********************************************************
++Change log:
++ 10/04/05: Add Doxygen format comments
++ 01/05/06: Add kernel 2.6.x support
++
++********************************************************/
++
++#include "include.h"
++
++#ifdef CONFIG_MARVELL_8686_PROC_FS
++/********************************************************
++ Local Variables
++********************************************************/
++
++#define item_size(n) (sizeof ((wlan_adapter *)0)->n)
++#define item_addr(n) ((u32) &((wlan_adapter *)0)->n)
++
++#define item_dbg_size(n) (sizeof (((wlan_adapter *)0)->dbg.n))
++#define item_dbg_addr(n) ((u32) &(((wlan_adapter *)0)->dbg.n))
++
++#define item1_size(n) (sizeof ((wlan_dev_t *)0)->n)
++#define item1_addr(n) ((u32) &((wlan_dev_t *)0)->n)
++
++struct debug_data
++{
++ char name[32];
++ u32 size;
++ u32 addr;
++ u32 offset;
++};
++
++/* To debug any member of wlan_adapter or wlan_dev_t, simply add one line here.
++ */
++#define ITEMS_FROM_WLAN_DEV 1
++
++static struct debug_data items[] = {
++ {"IntCounter", item_size(IntCounter), 0, item_addr(IntCounter)},
++ {"ConnectStatus", item_size(MediaConnectStatus), 0,
++ item_addr(MediaConnectStatus)},
++ {"wmmQStp", item_size(wmm.queueStopped), 0, item_addr(wmm.queueStopped)},
++ {"wmmPkts", item_size(wmm.packetsQueued), 0,
++ item_addr(wmm.packetsQueued)},
++ {"wmmAcVo", item_size(wmm.packetsOut[WMM_AC_VO]), 0,
++ item_addr(wmm.packetsOut[WMM_AC_VO])},
++ {"wmmAcVi", item_size(wmm.packetsOut[WMM_AC_VI]), 0,
++ item_addr(wmm.packetsOut[WMM_AC_VI])},
++ {"wmmAcBE", item_size(wmm.packetsOut[WMM_AC_BE]), 0,
++ item_addr(wmm.packetsOut[WMM_AC_BE])},
++ {"wmmAcBK", item_size(wmm.packetsOut[WMM_AC_BK]), 0,
++ item_addr(wmm.packetsOut[WMM_AC_BK])},
++ {"PSMode", item_size(PSMode), 0, item_addr(PSMode)},
++ {"PSState", item_size(PSState), 0, item_addr(PSState)},
++ {"IsDeepSleep", item_size(IsDeepSleep), 0, item_addr(IsDeepSleep)},
++ {"IsAutoDeepSleepEnabled", item_size(IsAutoDeepSleepEnabled), 0,
++ item_addr(IsAutoDeepSleepEnabled)},
++ {"WakeupDevReq", item_size(bWakeupDevRequired), 0,
++ item_addr(bWakeupDevRequired)},
++ {"WakeupTries", item_size(WakeupTries), 0, item_addr(WakeupTries)},
++ {"HS_Configured", item_size(bHostSleepConfigured), 0,
++ item_addr(bHostSleepConfigured)},
++ {"HS_Activated", item_size(HS_Activated), 0, item_addr(HS_Activated)},
++ {"num_tx_timeout", item_dbg_size(num_tx_timeout), 0,
++ item_dbg_addr(num_tx_timeout)},
++ {"num_cmd_timeout", item_dbg_size(num_cmd_timeout), 0,
++ item_dbg_addr(num_cmd_timeout)},
++ {"TimeoutCmdId", item_dbg_size(TimeoutCmdId), 0,
++ item_dbg_addr(TimeoutCmdId)},
++ {"TimeoutCmdAct", item_dbg_size(TimeoutCmdAct), 0,
++ item_dbg_addr(TimeoutCmdAct)},
++ {"LastCmdId", item_dbg_size(LastCmdId), 0, item_dbg_addr(LastCmdId)},
++ {"LastCmdAct", item_dbg_size(LastCmdAct), 0, item_dbg_addr(LastCmdAct)},
++ {"LastCmdIndex", item_dbg_size(LastCmdIndex), 0,
++ item_dbg_addr(LastCmdIndex)},
++ {"LastCmdRespId", item_dbg_size(LastCmdRespId), 0,
++ item_dbg_addr(LastCmdRespId)},
++ {"LastCmdRespIndex", item_dbg_size(LastCmdRespIndex), 0,
++ item_dbg_addr(LastCmdRespIndex)},
++ {"LastEvent", item_dbg_size(LastEvent), 0, item_dbg_addr(LastEvent)},
++ {"LastEventIndex", item_dbg_size(LastEventIndex), 0,
++ item_dbg_addr(LastEventIndex)},
++ {"num_cmd_h2c_fail", item_dbg_size(num_cmd_host_to_card_failure), 0,
++ item_dbg_addr(num_cmd_host_to_card_failure)},
++ {"num_cmd_sleep_cfm_fail",
++ item_dbg_size(num_cmd_sleep_cfm_host_to_card_failure), 0,
++ item_dbg_addr(num_cmd_sleep_cfm_host_to_card_failure)},
++ {"num_tx_h2c_fail", item_dbg_size(num_tx_host_to_card_failure), 0,
++ item_dbg_addr(num_tx_host_to_card_failure)},
++ {"num_evt_deauth", item_dbg_size(num_event_deauth), 0,
++ item_dbg_addr(num_event_deauth)},
++ {"num_evt_disassoc", item_dbg_size(num_event_disassoc), 0,
++ item_dbg_addr(num_event_disassoc)},
++ {"num_evt_link_lost", item_dbg_size(num_event_link_lost), 0,
++ item_dbg_addr(num_event_link_lost)},
++ {"num_cmd_deauth", item_dbg_size(num_cmd_deauth), 0,
++ item_dbg_addr(num_cmd_deauth)},
++ {"num_cmd_assoc_ok", item_dbg_size(num_cmd_assoc_success), 0,
++ item_dbg_addr(num_cmd_assoc_success)},
++ {"num_cmd_assoc_fail", item_dbg_size(num_cmd_assoc_failure), 0,
++ item_dbg_addr(num_cmd_assoc_failure)},
++
++ {"dnld_sent", item1_size(dnld_sent), 0, item1_addr(dnld_sent)},
++};
++
++static int num_of_items = sizeof(items) / sizeof(items[0]);
++
++/********************************************************
++ Global Variables
++********************************************************/
++
++/********************************************************
++ Local Functions
++********************************************************/
++/**
++ * @brief proc read function
++ *
++ * @param page pointer to buffer
++ * @param s read data starting position
++ * @param off offset
++ * @param cnt counter
++ * @param eof end of file flag
++ * @param data data to output
++ * @return number of output data
++ */
++static int
++wlan_debug_read(char *page, char **s, off_t off, int cnt, int *eof,
++ void *data)
++{
++ int val = 0;
++ char *p = page;
++ int i;
++
++ struct debug_data *d = (struct debug_data *) data;
++
++ MODULE_GET;
++
++ for (i = 0; i < num_of_items; i++) {
++ if (d[i].size == 1)
++ val = *((u8 *) d[i].addr);
++ else if (d[i].size == 2)
++ val = *((u16 *) d[i].addr);
++ else if (d[i].size == 4)
++ val = *((u32 *) d[i].addr);
++ else {
++ int j;
++ p += sprintf(p, "%s=", d[i].name);
++ for (j = 0; j < d[i].size; j += 2) {
++ val = *(u16 *) (d[i].addr + j);
++ p += sprintf(p, "0x%x ", val);
++ }
++ p += sprintf(p, "\n");
++ continue;
++ }
++
++ if (strstr(d[i].name, "Id"))
++ p += sprintf(p, "%s=0x%x\n", d[i].name, val);
++ else
++ p += sprintf(p, "%s=%d\n", d[i].name, val);
++ }
++ MODULE_PUT;
++ return p - page;
++}
++
++/**
++ * @brief proc write function
++ *
++ * @param f file pointer
++ * @param buf pointer to data buffer
++ * @param cnt data number to write
++ * @param data data to write
++ * @return number of data
++ */
++static int
++wlan_debug_write(struct file *f, const char *buf, unsigned long cnt,
++ void *data)
++{
++ int r, i;
++ char *pdata;
++ char *p;
++ char *p0;
++ char *p1;
++ char *p2;
++ struct debug_data *d = (struct debug_data *) data;
++
++ MODULE_GET;
++
++ pdata = (char *) kmalloc(cnt, GFP_KERNEL);
++ if (pdata == NULL) {
++ MODULE_PUT;
++ return 0;
++ }
++
++ if (copy_from_user(pdata, buf, cnt)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ kfree(pdata);
++ MODULE_PUT;
++ return 0;
++ }
++
++ p0 = pdata;
++ for (i = 0; i < num_of_items; i++) {
++ do {
++ p = strstr(p0, d[i].name);
++ if (p == NULL)
++ break;
++ p1 = strchr(p, '\n');
++ if (p1 == NULL)
++ break;
++ p0 = p1++;
++ p2 = strchr(p, '=');
++ if (!p2)
++ break;
++ p2++;
++ r = string_to_number(p2);
++ if (d[i].size == 1)
++ *((u8 *) d[i].addr) = (u8) r;
++ else if (d[i].size == 2)
++ *((u16 *) d[i].addr) = (u16) r;
++ else if (d[i].size == 4)
++ *((u32 *) d[i].addr) = (u32) r;
++ break;
++ } while (TRUE);
++ }
++ kfree(pdata);
++ MODULE_PUT;
++ return cnt;
++}
++
++/********************************************************
++ Global Functions
++********************************************************/
++/**
++ * @brief create debug proc file
++ *
++ * @param priv pointer wlan_private
++ * @param dev pointer net_device
++ * @return N/A
++ */
++void
++wlan_debug_entry(wlan_private * priv, struct net_device *dev)
++{
++ int i;
++ struct proc_dir_entry *r;
++
++ if (priv->proc_entry == NULL)
++ return;
++
++ for (i = 0; i < (num_of_items - ITEMS_FROM_WLAN_DEV); i++) {
++ items[i].addr = items[i].offset + (u32) priv->adapter;
++ }
++ for (i = num_of_items - ITEMS_FROM_WLAN_DEV; i < num_of_items; i++) {
++ items[i].addr = items[i].offset + (u32) & priv->wlan_dev;
++ }
++ r = create_proc_entry("debug", 0644, priv->proc_entry);
++ if (r == NULL)
++ return;
++
++ r->data = &items[0];
++ r->read_proc = wlan_debug_read;
++ r->write_proc = wlan_debug_write;
++ r->owner = THIS_MODULE;
++
++}
++
++/**
++ * @brief remove proc file
++ *
++ * @param priv pointer wlan_private
++ * @return N/A
++ */
++void
++wlan_debug_remove(wlan_private * priv)
++{
++ remove_proc_entry("debug", priv->proc_entry);
++}
++
++#endif
+diff --git a/drivers/net/wireless/marvell8686/wlan_decl.h b/drivers/net/wireless/marvell8686/wlan_decl.h
+new file mode 100644
+index 0000000..73aaad4
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_decl.h
+@@ -0,0 +1,109 @@
++/** @file wlan_decl.h
++ * @brief This file contains declaration referring to
++ * functions defined in other source files
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ */
++/******************************************************
++Change log:
++ 09/29/05: add Doxygen format comments
++ 01/05/06: Add kernel 2.6.x support
++ 01/11/06: Conditionalize new scan/join structures.
++ Move wlan_wext statics to their source file.
++******************************************************/
++
++#ifndef _WLAN_DECL_H_
++#define _WLAN_DECL_H_
++
++/** Function Prototype Declaration */
++int wlan_init_fw(wlan_private * priv);
++int wlan_tx_packet(wlan_private * priv, struct sk_buff *skb);
++void wlan_free_adapter(wlan_private * priv);
++
++int SendNullPacket(wlan_private * priv, u8 flags);
++BOOLEAN CheckLastPacketIndication(wlan_private * priv);
++
++void Wep_encrypt(wlan_private * priv, u8 * Buf, u32 Len);
++int FreeCmdBuffer(wlan_private * priv);
++void CleanUpCmdCtrlNode(CmdCtrlNode * pTempNode);
++CmdCtrlNode *GetFreeCmdCtrlNode(wlan_private * priv);
++
++void SetCmdCtrlNode(wlan_private * priv,
++ CmdCtrlNode * pTempNode,
++ WLAN_OID cmd_oid, u16 wait_option, void *pdata_buf);
++
++BOOLEAN Is_Command_Allowed(wlan_private * priv);
++
++int PrepareAndSendCommand(wlan_private * priv,
++ u16 cmd_no,
++ u16 cmd_action,
++ u16 wait_option, WLAN_OID cmd_oid, void *pdata_buf);
++
++void QueueCmd(wlan_adapter * Adapter, CmdCtrlNode * CmdNode, BOOLEAN addtail);
++
++int SetDeepSleep(wlan_private * priv, BOOLEAN bDeepSleep);
++int AllocateCmdBuffer(wlan_private * priv);
++int ExecuteNextCommand(wlan_private * priv);
++int wlan_process_event(wlan_private * priv);
++void wlan_interrupt(struct net_device *);
++u32 index_to_data_rate(u8 index);
++u8 data_rate_to_index(u32 rate);
++void HexDump(char *prompt, u8 * data, int len);
++void get_version(wlan_adapter * adapter, char *version, int maxlen);
++void wlan_read_write_rfreg(wlan_private * priv);
++
++#ifdef CONFIG_MARVELL_8686_PROC_FS
++/** The proc fs interface */
++void wlan_proc_entry(wlan_private * priv, struct net_device *dev);
++void wlan_proc_remove(wlan_private * priv);
++int string_to_number(char *s);
++#ifdef CONFIG_MARVELL_8686_DEBUG
++void wlan_debug_entry(wlan_private * priv, struct net_device *dev);
++void wlan_debug_remove(wlan_private * priv);
++#endif
++#endif
++int wlan_process_rx_command(wlan_private * priv);
++void wlan_process_tx(wlan_private * priv);
++void CleanupAndInsertCmd(wlan_private * priv, CmdCtrlNode * pTempCmd);
++void MrvDrvCommandTimerFunction(void *FunctionContext);
++
++#ifdef REASSOCIATION
++void MrvDrvReassocTimerFunction(void *FunctionContext);
++#endif /* REASSOCIATION */
++
++int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra);
++int wlan_set_regiontable(wlan_private * priv, u8 region, u8 band);
++
++void wlan_clean_txrx(wlan_private * priv);
++
++int wlan_host_sleep_activated_event(wlan_private * priv);
++int wlan_host_sleep_deactivated_event(wlan_private * priv);
++int wlan_host_sleep_gpio_int_event(wlan_private * priv);
++int wlan_deep_sleep_ioctl(wlan_private * priv, struct ifreq *rq);
++
++int ProcessRxedPacket(wlan_private * priv, struct sk_buff *);
++
++void PSSleep(wlan_private * priv, int wait_option);
++void PSConfirmSleep(wlan_private * priv, u16 PSMode);
++void PSWakeup(wlan_private * priv, int wait_option);
++
++void wlan_send_rxskbQ(wlan_private * priv);
++
++extern CHANNEL_FREQ_POWER *find_cfp_by_band_and_channel(wlan_adapter *
++ adapter, u8 band,
++ u16 channel);
++extern CHANNEL_FREQ_POWER *get_cfp_by_band_and_channel(u8 band, u16 channel,
++ REGION_CHANNEL *
++ region_channnel);
++
++extern void MacEventDisconnected(wlan_private * priv);
++
++#if WIRELESS_EXT > 14
++void send_iwevcustom_event(wlan_private * priv, s8 * str);
++#endif
++
++int fw_read(const char *name, u8 ** addr, u32 * len);
++void fw_buffer_free(u8 * addr);
++
++#endif /* _WLAN_DECL_H_ */
+diff --git a/drivers/net/wireless/marvell8686/wlan_defs.h b/drivers/net/wireless/marvell8686/wlan_defs.h
+new file mode 100644
+index 0000000..0f6202b
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_defs.h
+@@ -0,0 +1,623 @@
++/** @file wlan_defs.h
++ * @brief This header file contains global constant/enum definitions,
++ * global variable declaration.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ */
++/*************************************************************
++Change log:
++ 10/11/05: add Doxygen format comments
++ 01/11/06: Add NELEMENTS, BAND_XX defines
++ 04/10/06: Add hostcmd generic API and power_adapt_cfg_ext command
++************************************************************/
++
++#ifndef _WLAN_DEFS_H_
++#define _WLAN_DEFS_H_
++
++#include "os_defs.h"
++
++/** Double-Word(32Bit) Bit definition */
++#define DW_BIT_0 0x00000001
++#define DW_BIT_1 0x00000002
++#define DW_BIT_2 0x00000004
++#define DW_BIT_3 0x00000008
++#define DW_BIT_4 0x00000010
++#define DW_BIT_5 0x00000020
++#define DW_BIT_6 0x00000040
++#define DW_BIT_7 0x00000080
++#define DW_BIT_8 0x00000100
++#define DW_BIT_9 0x00000200
++#define DW_BIT_10 0x00000400
++#define DW_BIT_11 0x00000800
++#define DW_BIT_12 0x00001000
++#define DW_BIT_13 0x00002000
++#define DW_BIT_14 0x00004000
++#define DW_BIT_15 0x00008000
++#define DW_BIT_16 0x00010000
++#define DW_BIT_17 0x00020000
++#define DW_BIT_18 0x00040000
++#define DW_BIT_19 0x00080000
++#define DW_BIT_20 0x00100000
++#define DW_BIT_21 0x00200000
++#define DW_BIT_22 0x00400000
++#define DW_BIT_23 0x00800000
++#define DW_BIT_24 0x01000000
++#define DW_BIT_25 0x02000000
++#define DW_BIT_26 0x04000000
++#define DW_BIT_27 0x08000000
++#define DW_BIT_28 0x10000000
++#define DW_BIT_29 0x20000000
++#define DW_BIT_30 0x40000000
++#define DW_BIT_31 0x80000000
++
++/** Word (16bit) Bit Definition*/
++#define W_BIT_0 0x0001
++#define W_BIT_1 0x0002
++#define W_BIT_2 0x0004
++#define W_BIT_3 0x0008
++#define W_BIT_4 0x0010
++#define W_BIT_5 0x0020
++#define W_BIT_6 0x0040
++#define W_BIT_7 0x0080
++#define W_BIT_8 0x0100
++#define W_BIT_9 0x0200
++#define W_BIT_10 0x0400
++#define W_BIT_11 0x0800
++#define W_BIT_12 0x1000
++#define W_BIT_13 0x2000
++#define W_BIT_14 0x4000
++#define W_BIT_15 0x8000
++
++/** Byte (8Bit) Bit definition*/
++#define B_BIT_0 0x01
++#define B_BIT_1 0x02
++#define B_BIT_2 0x04
++#define B_BIT_3 0x08
++#define B_BIT_4 0x10
++#define B_BIT_5 0x20
++#define B_BIT_6 0x40
++#define B_BIT_7 0x80
++
++/** Debug Macro definition*/
++#ifdef DEBUG_LEVEL1
++
++extern u32 drvdbg;
++extern u32 ifdbg;
++
++/* Debug message control bit definition for drvdbg */
++#define DBG_MSG DW_BIT_0
++#define DBG_FATAL DW_BIT_1
++#define DBG_ERROR DW_BIT_2
++#define DBG_DATA DW_BIT_3
++#define DBG_CMND DW_BIT_4
++#define DBG_EVENT DW_BIT_5
++#define DBG_INTR DW_BIT_6
++
++#define DBG_DAT_D DW_BIT_16
++#define DBG_CMD_D DW_BIT_17
++#define DBG_FW_D DW_BIT_18
++
++#define DBG_ENTRY DW_BIT_28
++#define DBG_WARN DW_BIT_29
++#define DBG_INFO DW_BIT_30
++
++/* Debug message control bit definition for ifdbg */
++#define DBG_IF_D DW_BIT_0
++
++#ifdef DEBUG_LEVEL2
++#define PRINTM_INFO(msg...) {if (drvdbg & DBG_INFO) printk(KERN_DEBUG msg);}
++#define PRINTM_WARN(msg...) {if (drvdbg & DBG_WARN) printk(KERN_DEBUG msg);}
++#define PRINTM_ENTRY(msg...) {if (drvdbg & DBG_ENTRY) printk(KERN_DEBUG msg);}
++#else
++#define PRINTM_INFO(msg...) do {} while (0)
++#define PRINTM_WARN(msg...) do {} while (0)
++#define PRINTM_ENTRY(msg...) do {} while (0)
++#endif /* DEBUG_LEVEL2 */
++
++#define PRINTM_FW_D(msg...) {if (drvdbg & DBG_FW_D) printk(KERN_DEBUG msg);}
++#define PRINTM_CMD_D(msg...) {if (drvdbg & DBG_CMD_D) printk(KERN_DEBUG msg);}
++#define PRINTM_DAT_D(msg...) {if (drvdbg & DBG_DAT_D) printk(KERN_DEBUG msg);}
++
++#define PRINTM_INTR(msg...) {if (drvdbg & DBG_INTR) printk(KERN_DEBUG msg);}
++#define PRINTM_EVENT(msg...) {if (drvdbg & DBG_EVENT) printk(msg);}
++#define PRINTM_CMND(msg...) {if (drvdbg & DBG_CMND) printk(KERN_DEBUG msg);}
++#define PRINTM_DATA(msg...) {if (drvdbg & DBG_DATA) printk(KERN_DEBUG msg);}
++#define PRINTM_ERROR(msg...) {if (drvdbg & DBG_ERROR) printk(KERN_DEBUG msg);}
++#define PRINTM_FATAL(msg...) {if (drvdbg & DBG_FATAL) printk(KERN_DEBUG msg);}
++#define PRINTM_MSG(msg...) {if (drvdbg & DBG_MSG) printk(KERN_ALERT msg);}
++
++#define PRINTM_IF_D(msg...) {if (ifdbg & DBG_IF_D) printk(KERN_DEBUG msg);}
++
++#define PRINTM(level,msg...) PRINTM_##level(msg)
++
++#else
++
++#define PRINTM(level,msg...) do {} while (0)
++
++#endif /* DEBUG_LEVEL1 */
++
++#define ASSERT(cond) \
++do { \
++ if (!(cond)) \
++ PRINTM(INFO, "ASSERT: %s, %s:%i\n", \
++ __FUNCTION__, __FILE__, __LINE__); \
++} while(0)
++
++#define ENTER() PRINTM(ENTRY, "Enter: %s, %s:%i\n", __FUNCTION__, \
++ __FILE__, __LINE__)
++#define LEAVE() PRINTM(ENTRY, "Leave: %s, %s:%i\n", __FUNCTION__, \
++ __FILE__, __LINE__)
++
++#if defined(DEBUG_LEVEL1) && defined(__KERNEL__)
++#define DBG_DUMP_BUF_LEN 64
++#define MAX_DUMP_PER_LINE 16
++#define MAX_DATA_DUMP_LEN 48
++
++static inline void
++hexdump(char *prompt, u8 * buf, int len)
++{
++ int i;
++ char dbgdumpbuf[DBG_DUMP_BUF_LEN];
++ char *ptr = dbgdumpbuf;
++
++ printk(KERN_DEBUG "%s:\n", prompt);
++ for (i = 1; i <= len; i++) {
++ ptr += sprintf(ptr, "%02x ", *buf);
++ buf++;
++ if (i % MAX_DUMP_PER_LINE == 0) {
++ *ptr = 0;
++ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
++ ptr = dbgdumpbuf;
++ }
++ }
++ if (len % MAX_DUMP_PER_LINE) {
++ *ptr = 0;
++ printk(KERN_DEBUG "%s\n", dbgdumpbuf);
++ }
++}
++
++#define DBG_HEXDUMP_CMD_D(x,y,z) {if (drvdbg & DBG_CMD_D) hexdump(x,y,z);}
++#define DBG_HEXDUMP_DAT_D(x,y,z) {if (drvdbg & DBG_DAT_D) hexdump(x,y,z);}
++#define DBG_HEXDUMP_IF_D(x,y,z) {if (ifdbg & DBG_IF_D) hexdump(x,y,z);}
++#define DBG_HEXDUMP_FW_D(x,y,z) {if (drvdbg & DBG_FW_D) hexdump(x,y,z);}
++
++#define DBG_HEXDUMP(level,x,y,z) DBG_HEXDUMP_##level(x,y,z)
++
++#else
++#define DBG_HEXDUMP(level,x,y,z) do {} while (0)
++#endif
++
++#if defined(DEBUG_LEVEL2) && defined(__KERNEL__)
++#define HEXDUMP(x,y,z) {if (drvdbg & DBG_INFO) hexdump(x,y,z);}
++#else
++#define HEXDUMP(x,y,z) do {} while (0)
++#endif
++
++#ifndef TRUE
++#define TRUE 1
++#endif
++#ifndef FALSE
++#define FALSE 0
++#endif
++
++#ifndef MIN
++#define MIN(a,b) ((a) < (b) ? (a) : (b))
++#endif
++
++#ifndef MAX
++#define MAX(a,b) ((a) > (b) ? (a) : (b))
++#endif
++
++#ifndef NELEMENTS
++#define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
++#endif
++
++/** Buffer Constants */
++
++/* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
++* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
++* driver has more local TxPDs. Each TxPD on the host memory is associated
++* with a Tx control node. The driver maintains 8 RxPD descriptors for
++* station firmware to store Rx packet information.
++*
++* Current version of MAC has a 32x6 multicast address buffer.
++*
++* 802.11b can have up to 14 channels, the driver keeps the
++* BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
++*/
++
++#define MRVDRV_SIZE_OF_PPA 0x00000008
++#define MRVDRV_SIZE_OF_DPA 0x00000008
++#define MRVDRV_NUM_OF_TxPD 0x00000020
++#define MRVDRV_NUM_OF_CMD_BUFFER 10
++#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
++#define MRVDRV_MAX_BSSID_LIST 64
++#define MRVDRV_TIMER_10S 10000
++#define MRVDRV_TIMER_5S 5000
++#define MRVDRV_TIMER_1S 1000
++#define MRVDRV_SNAP_HEADER_LEN 8
++#define MRVDRV_ETH_HEADER_SIZE 14
++
++#define ARP_FILTER_MAX_BUF_SIZE 68
++
++#define WLAN_UPLD_SIZE 2312
++#define DEV_NAME_LEN 32
++
++#ifndef ETH_ALEN
++#define ETH_ALEN 6
++#endif
++
++/** Misc constants */
++/* This section defines 802.11 specific contants */
++#define SDIO_HEADER_LEN 4
++
++#define MRVDRV_MAX_REGION_CODE 6
++#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe
++#define MRVDRV_MIN_MULTIPLE_DTIM 1
++#define MRVDRV_MAX_MULTIPLE_DTIM 5
++#define MRVDRV_DEFAULT_MULTIPLE_DTIM 1
++
++#define MRVDRV_DEFAULT_LISTEN_INTERVAL 10
++#define MRVDRV_DEFAULT_LOCAL_LISTEN_INTERVAL 0
++
++#define MRVDRV_CHANNELS_PER_ACTIVE_SCAN 14
++#define MRVDRV_MIN_BEACON_INTERVAL 20
++#define MRVDRV_MAX_BEACON_INTERVAL 1000
++#define MRVDRV_BEACON_INTERVAL 100
++
++#define MRVDRV_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ)
++#define MRVDRV_SCAN_WATCHDOG_TIMEOUT (10 * HZ)
++#define MRVDRV_DEEP_SLEEP_EXIT_TIMEOUT (10 * HZ)
++
++/** TxPD Status */
++
++/* Station firmware use TxPD status field to report final Tx transmit
++* result, Bit masks are used to present combined situations.
++*/
++
++#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
++#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
++
++/** Tx control node status */
++
++#define MRVDRV_TX_CTRL_NODE_STATUS_IDLE 0x0000
++
++/* Link spped */
++#define MRVDRV_LINK_SPEED_1mbps 10000 /* in unit of 100bps */
++#define MRVDRV_LINK_SPEED_11mbps 110000
++
++/** RSSI-related defines */
++/* RSSI constants are used to implement 802.11 RSSI threshold
++* indication. if the Rx packet signal got too weak for 5 consecutive
++* times, miniport driver (driver) will report this event to wrapper
++*/
++
++#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96)
++
++/** RTS/FRAG related defines */
++#define MRVDRV_RTS_MIN_VALUE 0
++#define MRVDRV_RTS_MAX_VALUE 2347
++#define MRVDRV_FRAG_MIN_VALUE 256
++#define MRVDRV_FRAG_MAX_VALUE 2346
++
++/* Fixed IE size is 8 bytes time stamp + 2 bytes beacon interval +
++ * 2 bytes cap */
++#define MRVL_FIXED_IE_SIZE 12
++
++/* This is for firmware specific length */
++#define EXTRA_LEN 36
++#define MRVDRV_MAXIMUM_ETH_PACKET_SIZE 1514
++
++#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
++ (MRVDRV_MAXIMUM_ETH_PACKET_SIZE + sizeof(TxPD) + EXTRA_LEN)
++
++#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
++ (MRVDRV_MAXIMUM_ETH_PACKET_SIZE + sizeof(RxPD) \
++ + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
++
++#define CMD_F_HOSTCMD (1 << 0)
++
++/* to resolve CISCO AP extension */
++#define MRVDRV_SCAN_LIST_VAR_IE_SPACE 256
++#define FW_IS_WPA_ENABLED(_adapter) \
++ (_adapter->fwCapInfo & FW_CAPINFO_WPA)
++
++#define FW_CAPINFO_WPA (1 << 0)
++#define WLAN_802_11_AI_REQFI_CAPABILITIES 1
++#define WLAN_802_11_AI_REQFI_LISTENINTERVAL 2
++#define WLAN_802_11_AI_REQFI_CURRENTAPADDRESS 4
++
++#define WLAN_802_11_AI_RESFI_CAPABILITIES 1
++#define WLAN_802_11_AI_RESFI_STATUSCODE 2
++#define WLAN_802_11_AI_RESFI_ASSOCIATIONID 4
++
++#define MRVL_NUM_WEP_KEY 4
++
++/** WPA Key LENGTH*/
++/* Support 4 keys per key set */
++#define MRVL_NUM_WPA_KEY_PER_SET 4
++#define MRVL_MAX_WPA_KEY_LENGTH 32
++
++#define WPA_AES_KEY_LEN 16
++#define WPA_TKIP_KEY_LEN 32
++
++/* A few details needed for WEP (Wireless Equivalent Privacy) */
++/* 104 bits */
++#define MAX_WEP_KEY_SIZE 13
++/*40 bits RC4 - WEP*/
++#define MIN_WEP_KEY_SIZE 5
++
++#define RF_ANTENNA_1 0x1
++#define RF_ANTENNA_2 0x2
++#define RF_ANTENNA_AUTO 0xFFFF
++
++#define KEY_INFO_ENABLED 0x01
++
++#define SNR_BEACON 0
++#define SNR_RXPD 1
++#define NF_BEACON 2
++#define NF_RXPD 3
++
++/** MACRO DEFINITIONS */
++#define CAL_NF(NF) ((s32)(-(s32)(NF)))
++#define CAL_RSSI(SNR, NF) ((s32)((s32)(SNR) + CAL_NF(NF)))
++#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI)))
++
++#define DEFAULT_BCN_AVG_FACTOR 8
++#define DEFAULT_DATA_AVG_FACTOR 8
++#define MIN_BCN_AVG_FACTOR 1
++#define MAX_BCN_AVG_FACTOR 8
++#define MIN_DATA_AVG_FACTOR 1
++#define MAX_DATA_AVG_FACTOR 8
++#define AVG_SCALE 100
++#define CAL_AVG_SNR_NF(AVG, SNRNF, N) \
++ (((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \
++ ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
++ AVG_SCALE)) / N))
++
++#define WLAN_STATUS_SUCCESS (0)
++#define WLAN_STATUS_FAILURE (-1)
++#define WLAN_STATUS_NOT_ACCEPTED (-2)
++
++#define MAX_LEDS 3
++#define LED_DISABLED 16
++#define LED_BLINKING 2
++
++/* S_SWAP : To swap 2 u8 */
++#define S_SWAP(a,b) do { \
++ u8 t = SArr[a]; \
++ SArr[a] = SArr[b]; SArr[b] = t; \
++ } while(0)
++
++/* SWAP: swap u8 */
++#define SWAP_U8(a,b) {u8 t; t=a; a=b; b=t;}
++
++/* SWAP: swap u8 */
++#define SWAP_U16(a,b) {u16 t; t=a; a=b; b=t;}
++
++#define wlan_le16_to_cpu(x) x
++#define wlan_le32_to_cpu(x) x
++#define wlan_le64_to_cpu(x) x
++#define wlan_cpu_to_le16(x) x
++#define wlan_cpu_to_le32(x) x
++#define wlan_cpu_to_le64(x) x
++
++#define endian_convert_TxPD(x)
++#define endian_convert_RxPD(x)
++#define endian_convert_GET_LOG(x)
++
++/** Global Varibale Declaration */
++typedef struct _wlan_private wlan_private;
++typedef struct _wlan_adapter wlan_adapter;
++typedef struct _HostCmd_DS_COMMAND HostCmd_DS_COMMAND;
++
++extern u32 DSFreqList[15];
++extern const char driver_version[];
++extern u32 DSFreqList[];
++extern u16 RegionCodeToIndex[MRVDRV_MAX_REGION_CODE];
++
++extern u8 WlanDataRates[WLAN_SUPPORTED_RATES];
++
++extern u8 SupportedRates[G_SUPPORTED_RATES];
++
++extern u8 AdhocRates_G[G_SUPPORTED_RATES];
++
++extern u8 AdhocRates_B[4];
++extern wlan_private *wlanpriv;
++
++#ifdef MFG_CMD_SUPPORT
++#define SIOCCFMFG SIOCDEVPRIVATE
++#endif /* MFG_CMD_SUPPORT */
++
++#define INTMODE_SDIO 0
++#define INTMODE_GPIO 1
++extern int intmode;
++extern int gpiopin;
++
++/** ENUM definition*/
++/** SNRNF_TYPE */
++typedef enum _SNRNF_TYPE
++{
++ TYPE_BEACON = 0,
++ TYPE_RXPD,
++ MAX_TYPE_B
++} SNRNF_TYPE;
++
++/** SNRNF_DATA*/
++typedef enum _SNRNF_DATA
++{
++ TYPE_NOAVG = 0,
++ TYPE_AVG,
++ MAX_TYPE_AVG
++} SNRNF_DATA;
++
++/** WLAN_802_11_AUTH_ALG*/
++typedef enum _WLAN_802_11_AUTH_ALG
++{
++ AUTH_ALG_OPEN_SYSTEM = 1,
++ AUTH_ALG_SHARED_KEY = 2,
++ AUTH_ALG_NETWORK_EAP = 8,
++} WLAN_802_11_AUTH_ALG;
++
++/** WLAN_802_11_ENCRYPTION_MODE */
++typedef enum _WLAN_802_11_ENCRYPTION_MODE
++{
++ CIPHER_NONE,
++ CIPHER_WEP40,
++ CIPHER_TKIP,
++ CIPHER_CCMP,
++ CIPHER_WEP104,
++} WLAN_802_11_ENCRYPTION_MODE;
++
++/** WLAN_802_11_POWER_MODE */
++typedef enum _WLAN_802_11_POWER_MODE
++{
++ Wlan802_11PowerModeCAM,
++ Wlan802_11PowerModeMAX_PSP,
++ Wlan802_11PowerModeFast_PSP,
++
++ /*not a real mode, defined as an upper bound */
++ Wlan802_11PowerModeMax
++} WLAN_802_11_POWER_MODE;
++
++/** PS_STATE */
++typedef enum _PS_STATE
++{
++ PS_STATE_FULL_POWER,
++ PS_STATE_AWAKE,
++ PS_STATE_PRE_SLEEP,
++ PS_STATE_SLEEP
++} PS_STATE;
++
++/** DNLD_STATE */
++typedef enum _DNLD_STATE
++{
++ DNLD_RES_RECEIVED,
++ DNLD_DATA_SENT,
++ DNLD_CMD_SENT
++} DNLD_STATE;
++
++/** WLAN_MEDIA_STATE */
++typedef enum _WLAN_MEDIA_STATE
++{
++ WlanMediaStateDisconnected,
++ WlanMediaStateConnected
++} WLAN_MEDIA_STATE;
++
++/** WLAN_802_11_PRIVACY_FILTER */
++typedef enum _WLAN_802_11_PRIVACY_FILTER
++{
++ Wlan802_11PrivFilterAcceptAll,
++ Wlan802_11PrivFilter8021xWEP
++} WLAN_802_11_PRIVACY_FILTER;
++
++/** mv_ms_type */
++typedef enum _mv_ms_type
++{
++ MVMS_DAT = 0,
++ MVMS_CMD = 1,
++ /* 2: reserved */
++ MVMS_EVENT = 3
++} mv_ms_type;
++
++/* Hardware status codes */
++typedef enum _WLAN_HARDWARE_STATUS
++{
++ WlanHardwareStatusReady,
++ WlanHardwareStatusInitializing,
++ WlanHardwareStatusReset,
++ WlanHardwareStatusClosing,
++ WlanHardwareStatusNotReady
++} WLAN_HARDWARE_STATUS;
++
++/** WLAN_802_11_AUTHENTICATION_MODE */
++typedef enum _WLAN_802_11_AUTHENTICATION_MODE
++{
++ Wlan802_11AuthModeOpen = 0x00,
++ Wlan802_11AuthModeShared = 0x01,
++ Wlan802_11AuthModeNetworkEAP = 0x80,
++} WLAN_802_11_AUTHENTICATION_MODE;
++
++/** WLAN_802_11_WEP_STATUS */
++typedef enum _WLAN_802_11_WEP_STATUS
++{
++ Wlan802_11WEPEnabled,
++ Wlan802_11WEPDisabled,
++ Wlan802_11WEPKeyAbsent,
++ Wlan802_11WEPNotSupported
++} WLAN_802_11_WEP_STATUS;
++
++/** SNMP_MIB_INDEX_e */
++typedef enum _SNMP_MIB_INDEX_e
++{
++ DesiredBssType_i = 0,
++ OpRateSet_i,
++ BcnPeriod_i,
++ DtimPeriod_i,
++ AssocRspTimeOut_i,
++ RtsThresh_i,
++ ShortRetryLim_i,
++ LongRetryLim_i,
++ FragThresh_i,
++ Dot11D_i,
++ Dot11H_i,
++ ManufId_i,
++ ProdId_i,
++ ManufOui_i,
++ ManufName_i,
++ ManufProdName_i,
++ ManufProdVer_i
++} SNMP_MIB_INDEX_e;
++
++/** KEY_TYPE_ID */
++typedef enum _KEY_TYPE_ID
++{
++ KEY_TYPE_ID_WEP = 0,
++ KEY_TYPE_ID_TKIP,
++ KEY_TYPE_ID_AES
++} KEY_TYPE_ID;
++
++/** KEY_INFO_WEP*/
++typedef enum _KEY_INFO_WEP
++{
++ KEY_INFO_WEP_DEFAULT_KEY = 0x01
++} KEY_INFO_WEP;
++
++/** KEY_INFO_TKIP */
++typedef enum _KEY_INFO_TKIP
++{
++ KEY_INFO_TKIP_MCAST = 0x01,
++ KEY_INFO_TKIP_UNICAST = 0x02,
++ KEY_INFO_TKIP_ENABLED = 0x04
++} KEY_INFO_TKIP;
++
++/** KEY_INFO_AES*/
++typedef enum _KEY_INFO_AES
++{
++ KEY_INFO_AES_MCAST = 0x01,
++ KEY_INFO_AES_UNICAST = 0x02,
++ KEY_INFO_AES_ENABLED = 0x04
++} KEY_INFO_AES;
++
++/** SNMP_MIB_VALUE_e */
++typedef enum _SNMP_MIB_VALUE_e
++{
++ SNMP_MIB_VALUE_INFRA = 1,
++ SNMP_MIB_VALUE_ADHOC
++} SNMP_MIB_VALUE_e;
++
++/** HWRateDropMode */
++typedef enum _HWRateDropMode
++{
++ NO_HW_RATE_DROP,
++ HW_TABLE_RATE_DROP,
++ HW_SINGLE_RATE_DROP
++} HWRateDropMode;
++
++#ifdef __KERNEL__
++extern struct iw_handler_def wlan_handler_def;
++struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev);
++int wlan_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
++#endif
++
++#endif /* _WLAN_DEFS_H_ */
+diff --git a/drivers/net/wireless/marvell8686/wlan_dev.h b/drivers/net/wireless/marvell8686/wlan_dev.h
+new file mode 100644
+index 0000000..33ede64
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_dev.h
+@@ -0,0 +1,470 @@
++/** @file wlan_dev.h
++ * @brief This file contains definitions and data structures specific
++ * to Marvell 802.11 NIC. It contains the Device Information
++ * structure wlan_adapter.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ */
++/*************************************************************
++Change log:
++ 09/26/05: add Doxygen format comments
++ 01/11/06: Conditionalize new scan/join structures.
++ 04/18/06: Remove old Subscrive Event and add new Subscribe Event
++ implementation through generic hostcmd API
++ 05/08/06: Remove PermanentAddr from Adapter
++
++ ************************************************************/
++
++#ifndef _WLAN_DEV_H_
++#define _WLAN_DEV_H_
++
++#define MAX_BSSID_PER_CHANNEL 16
++
++/* For the extended Scan */
++#define MAX_EXTENDED_SCAN_BSSID_LIST MAX_BSSID_PER_CHANNEL * \
++ MRVDRV_MAX_CHANNEL_SIZE + 1
++
++typedef struct _PER_CHANNEL_BSSID_LIST_DATA
++{
++ u8 ucStart;
++ u8 ucNumEntry;
++} PER_CHANNEL_BSSID_LIST_DATA, *PPER_CHANNEL_BSSID_LIST_DATA;
++
++typedef struct _MRV_BSSID_IE_LIST
++{
++ WLAN_802_11_FIXED_IEs FixedIE;
++ u8 VariableIE[MRVDRV_SCAN_LIST_VAR_IE_SPACE];
++} MRV_BSSID_IE_LIST, *PMRV_BSSID_IE_LIST;
++
++#define MAX_REGION_CHANNEL_NUM 2
++
++/** Chan-Freq-TxPower mapping table*/
++typedef struct _CHANNEL_FREQ_POWER
++{
++ /** Channel Number */
++ u16 Channel;
++ /** Frequency of this Channel */
++ u32 Freq;
++ /** Max allowed Tx power level */
++ u16 MaxTxPower;
++ /** TRUE:channel unsupported; FLASE:supported*/
++ BOOLEAN Unsupported;
++} CHANNEL_FREQ_POWER;
++
++/** region-band mapping table*/
++typedef struct _REGION_CHANNEL
++{
++ /** TRUE if this entry is valid */
++ BOOLEAN Valid;
++ /** Region code for US, Japan ... */
++ u8 Region;
++ /** Band B/G/A, used for BAND_CONFIG cmd */
++ u8 Band;
++ /** Actual No. of elements in the array below */
++ u8 NrCFP;
++ /** chan-freq-txpower mapping table*/
++ CHANNEL_FREQ_POWER *CFP;
++} REGION_CHANNEL;
++
++typedef struct _wlan_802_11_security_t
++{
++ BOOLEAN WPAEnabled;
++ BOOLEAN WPA2Enabled;
++ WLAN_802_11_WEP_STATUS WEPStatus;
++ WLAN_802_11_AUTHENTICATION_MODE AuthenticationMode;
++ WLAN_802_11_ENCRYPTION_MODE EncryptionMode;
++} wlan_802_11_security_t;
++
++/** Current Basic Service Set State Structure */
++typedef struct
++{
++ BSSDescriptor_t BSSDescriptor;
++
++ /** band */
++ u8 band;
++
++ /** number of rates supported */
++ int NumOfRates;
++
++ /** supported rates*/
++ u8 DataRates[WLAN_SUPPORTED_RATES];
++
++ /** wmm enable? */
++ u8 wmm_enabled;
++
++ /** uapsd enable?*/
++ u8 wmm_uapsd_enabled;
++} CurrentBSSParams_t;
++
++/** sleep_params */
++typedef struct SleepParams
++{
++ u16 sp_error;
++ u16 sp_offset;
++ u16 sp_stabletime;
++ u8 sp_calcontrol;
++ u8 sp_extsleepclk;
++ u16 sp_reserved;
++} SleepParams;
++
++/** sleep_period */
++typedef struct SleepPeriod
++{
++ u16 period;
++ u16 reserved;
++} SleepPeriod;
++
++#define DBG_CMD_NUM 5
++
++/** info for debug purpose */
++typedef struct _wlan_dbg
++{
++ u32 num_cmd_host_to_card_failure;
++ u32 num_cmd_sleep_cfm_host_to_card_failure;
++ u32 num_tx_host_to_card_failure;
++ u32 num_event_deauth;
++ u32 num_event_disassoc;
++ u32 num_event_link_lost;
++ u32 num_cmd_deauth;
++ u32 num_cmd_assoc_success;
++ u32 num_cmd_assoc_failure;
++ u32 num_tx_timeout;
++ u32 num_cmd_timeout;
++ u16 TimeoutCmdId;
++ u16 TimeoutCmdAct;
++ u16 LastCmdId[DBG_CMD_NUM];
++ u16 LastCmdAct[DBG_CMD_NUM];
++ u16 LastCmdIndex;
++ u16 LastCmdRespId[DBG_CMD_NUM];
++ u16 LastCmdRespIndex;
++ u16 LastEvent[DBG_CMD_NUM];
++ u16 LastEventIndex;
++} wlan_dbg;
++
++/** Data structure for the Marvell WLAN device */
++typedef struct _wlan_dev
++{
++ /** device name */
++ char name[DEV_NAME_LEN];
++ /** card pointer */
++ void *card;
++ /** IO port */
++ u32 ioport;
++ /** Upload received */
++ u32 upld_rcv;
++ /** Upload type */
++ u32 upld_typ;
++ /** Upload length */
++ u32 upld_len;
++ /** netdev pointer */
++ struct net_device *netdev;
++ struct device *hotplug_device;
++
++ /* Upload buffer */
++ u8 upld_buf[WLAN_UPLD_SIZE];
++ /* Download sent:
++ bit0 1/0=data_sent/data_tx_done,
++ bit1 1/0=cmd_sent/cmd_tx_done,
++ all other bits reserved 0 */
++ u8 dnld_sent;
++} wlan_dev_t, *pwlan_dev_t;
++
++/* Data structure for WPS information */
++typedef struct
++{
++ IEEEtypes_VendorSpecific_t wpsIe;
++ BOOLEAN SessionEnable;
++} wps_t;
++
++/** Private structure for the MV device */
++struct _wlan_private
++{
++ int open;
++
++ wlan_adapter *adapter;
++ wlan_dev_t wlan_dev;
++
++ struct net_device_stats stats;
++
++ struct iw_statistics wstats;
++#ifdef CONFIG_MARVELL_8686_PROC_FS
++ struct proc_dir_entry *proc_entry;
++ struct proc_dir_entry *proc_dev;
++#endif
++
++ /** thread to service interrupts */
++ wlan_thread MainThread;
++
++#ifdef REASSOCIATION
++ /** thread to service mac events */
++ wlan_thread ReassocThread;
++#endif /* REASSOCIATION */
++};
++
++/** Wlan Adapter data structure*/
++struct _wlan_adapter
++{
++ u8 TmpTxBuf[WLAN_UPLD_SIZE] __ATTRIB_ALIGN__;
++ /** STATUS variables */
++ WLAN_HARDWARE_STATUS HardwareStatus;
++ u32 FWReleaseNumber;
++ u32 fwCapInfo;
++ u8 chip_rev;
++
++ /** Command-related variables */
++ u16 SeqNum;
++ CmdCtrlNode *CmdArray;
++ /** Current Command */
++ CmdCtrlNode *CurCmd;
++ int CurCmdRetCode;
++
++ /** Command Queues */
++ /** Free command buffers */
++ struct list_head CmdFreeQ;
++ /** Pending command buffers */
++ struct list_head CmdPendingQ;
++
++ /** Variables brought in from private structure */
++ int irq;
++
++ /** Async and Sync Event variables */
++ u32 IntCounter;
++ u32 IntCounterSaved; /* save int for DS/PS */
++ u32 EventCause;
++ u8 nodeName[16]; /* nickname */
++
++ /** spin locks */
++ spinlock_t QueueSpinLock __ATTRIB_ALIGN__;
++
++ /** Timers */
++ WLAN_DRV_TIMER MrvDrvCommandTimer __ATTRIB_ALIGN__;
++ BOOLEAN CommandTimerIsSet;
++
++#ifdef REASSOCIATION
++ /**Reassociation timer*/
++ BOOLEAN ReassocTimerIsSet;
++ WLAN_DRV_TIMER MrvDrvTimer __ATTRIB_ALIGN__;
++#endif /* REASSOCIATION */
++
++ /** Event Queues */
++ wait_queue_head_t ds_awake_q __ATTRIB_ALIGN__;
++
++ u8 HisRegCpy;
++
++ /** bg scan related variable */
++ HostCmd_DS_802_11_BG_SCAN_CONFIG *bgScanConfig;
++ u32 bgScanConfigSize;
++
++ /** WMM related variable*/
++ WMM_DESC wmm;
++
++ /** current ssid/bssid related parameters*/
++ CurrentBSSParams_t CurBssParams;
++
++ WLAN_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
++
++ BSSDescriptor_t *pAttemptedBSSDesc;
++
++ WLAN_802_11_SSID AttemptedSSIDBeforeScan;
++ WLAN_802_11_SSID PreviousSSID;
++ u8 PreviousBSSID[MRVDRV_ETH_ADDR_LEN];
++
++ BSSDescriptor_t *ScanTable;
++ u32 NumInScanTable;
++
++ u8 ScanType;
++ u32 ScanMode;
++ u16 SpecificScanTime;
++ u16 ActiveScanTime;
++ u16 PassiveScanTime;
++
++ u16 BeaconPeriod;
++ u8 AdhocCreate;
++ BOOLEAN AdhocLinkSensed;
++
++#ifdef REASSOCIATION
++ /** Reassociation on and off */
++ BOOLEAN Reassoc_on;
++ SEMAPHORE ReassocSem;
++#endif /* REASSOCIATION */
++
++ BOOLEAN ATIMEnabled;
++
++ /** MAC address information */
++ u8 CurrentAddr[MRVDRV_ETH_ADDR_LEN];
++ u8 MulticastList[MRVDRV_MAX_MULTICAST_LIST_SIZE]
++ [MRVDRV_ETH_ADDR_LEN];
++ u32 NumOfMulticastMACAddr;
++
++ u16 HWRateDropMode;
++ u16 RateBitmap;
++ u16 Threshold;
++ u16 FinalRate;
++ /** control G Rates */
++ BOOLEAN adhoc_grate_enabled;
++
++ WLAN_802_11_ANTENNA TxAntenna;
++ WLAN_802_11_ANTENNA RxAntenna;
++
++ u8 AdhocChannel;
++ WLAN_802_11_FRAGMENTATION_THRESHOLD FragThsd;
++ WLAN_802_11_RTS_THRESHOLD RTSThsd;
++
++ u32 DataRate;
++ BOOLEAN Is_DataRate_Auto;
++
++ /** number of association attempts for the current SSID cmd */
++ u16 ListenInterval;
++ u16 TxRetryCount;
++
++ u16 Dtim;
++
++ /** Tx-related variables (for single packet tx) */
++ struct sk_buff *CurrentTxSkb;
++ struct sk_buff RxSkbQ;
++ BOOLEAN TxLockFlag;
++ u16 gen_null_pkg;
++ spinlock_t CurrentTxLock __ATTRIB_ALIGN__;
++
++ /** NIC Operation characteristics */
++ u16 CurrentPacketFilter;
++ u32 MediaConnectStatus;
++ u16 RegionCode;
++ u16 TxPowerLevel;
++ u8 MaxTxPowerLevel;
++ u8 MinTxPowerLevel;
++
++ /** POWER MANAGEMENT AND PnP SUPPORT */
++ BOOLEAN SurpriseRemoved;
++ u16 AtimWindow;
++
++ u16 PSMode; /* Wlan802_11PowerModeCAM=disable
++ Wlan802_11PowerModeMAX_PSP=enable */
++ u16 MultipleDtim;
++ u16 BCNMissTimeOut;
++ u32 PSState;
++ BOOLEAN NeedToWakeup;
++
++ PS_CMD_ConfirmSleep PSConfirmSleep;
++ u16 LocalListenInterval;
++ u16 NullPktInterval;
++ u16 AdhocAwakePeriod;
++ u16 fwWakeupMethod;
++ BOOLEAN IsDeepSleep;
++ BOOLEAN IsAutoDeepSleepEnabled;
++ BOOLEAN bWakeupDevRequired;
++ u32 WakeupTries;
++ BOOLEAN bHostSleepConfigured;
++ HostCmd_DS_802_11_HOST_SLEEP_CFG HSCfg;
++ /** ARP filter related variable */
++ u8 ArpFilter[ARP_FILTER_MAX_BUF_SIZE];
++ u32 ArpFilterSize;
++ BOOLEAN HS_Activated;
++
++ /** Encryption parameter */
++ wlan_802_11_security_t SecInfo;
++
++ MRVL_WEP_KEY WepKey[MRVL_NUM_WEP_KEY];
++ u16 CurrentWepKeyIndex;
++
++ /** Buffer for TLVs passed from the application to be inserted into the
++ * association request to firmware
++ */
++ u8 mrvlAssocTlvBuffer[MRVDRV_ASSOC_TLV_BUF_SIZE];
++
++ /** Length of the data stored in mrvlAssocTlvBuffer*/
++ u8 mrvlAssocTlvBufferLen;
++
++ /** Buffer to store the association response for application retrieval */
++ u8 assocRspBuffer[MRVDRV_ASSOC_RSP_BUF_SIZE];
++
++ /** Length of the data stored in assocRspBuffer */
++ int assocRspSize;
++
++ /** Generice IEEE IEs passed from the application to be inserted into the
++ * association request to firmware
++ */
++ u8 genIeBuffer[MRVDRV_GENIE_BUF_SIZE];
++
++ /** Length of the data stored in genIeBuffer */
++ u8 genIeBufferLen;
++
++ BOOLEAN IsGTK_SET;
++
++ /** Encryption Key*/
++ u8 Wpa_ie[256];
++ u8 Wpa_ie_len;
++
++ HostCmd_DS_802_11_KEY_MATERIAL aeskey;
++
++ /* Advanced Encryption Standard */
++ BOOLEAN AdhocAESEnabled;
++ wait_queue_head_t cmd_EncKey __ATTRIB_ALIGN__;
++
++ u16 RxAntennaMode;
++ u16 TxAntennaMode;
++
++ /** Requested Signal Strength*/
++ u16 bcn_avg_factor;
++ u16 data_avg_factor;
++ u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
++ u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
++ u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
++ u8 rawSNR[DEFAULT_DATA_AVG_FACTOR];
++ u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
++ u16 nextSNRNF;
++ u16 numSNRNF;
++ u32 RxPDAge;
++ u16 RxPDRate;
++
++ BOOLEAN RadioOn;
++
++ /** Blue Tooth Co-existence Arbitration */
++ HostCmd_DS_802_11_BCA_TIMESHARE bca_ts;
++
++ /** sleep_params */
++ SleepParams sp;
++
++ /** sleep_period (Enhanced Power Save) */
++ SleepPeriod sleep_period;
++
++#define MAX_REGION_CHANNEL_NUM 2
++ /** Region Channel data */
++ REGION_CHANNEL region_channel[MAX_REGION_CHANNEL_NUM];
++
++ REGION_CHANNEL universal_channel[MAX_REGION_CHANNEL_NUM];
++
++ /** 11D and Domain Regulatory Data */
++ wlan_802_11d_domain_reg_t DomainReg;
++ parsed_region_chan_11d_t parsed_region_chan;
++
++ /** FSM variable for 11d support */
++ wlan_802_11d_state_t State11D;
++ u8 beaconBuffer[MAX_SCAN_BEACON_BUFFER];
++ u8 *pBeaconBufEnd;
++
++ /** MISCELLANEOUS */
++ /* Card Information Structure */
++ u8 CisInfoBuf[512];
++ u16 CisInfoLen;
++
++ HostCmd_DS_802_11_GET_LOG LogMsg;
++ u16 ScanProbes;
++
++ u32 PktTxCtrl;
++
++ u8 *helper;
++ u32 helper_len;
++ u8 *fmimage;
++ u32 fmimage_len;
++ u16 TxRate;
++
++ wps_t wps;
++
++ wlan_dbg dbg;
++ wlan_subscribe_event subevent;
++ u8 sdiomode;
++ u32 num_cmd_timeout;
++};
++
++#endif /* _WLAN_DEV_H_ */
+diff --git a/drivers/net/wireless/marvell8686/wlan_fops.c b/drivers/net/wireless/marvell8686/wlan_fops.c
+new file mode 100644
+index 0000000..1e27d6f
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_fops.c
+@@ -0,0 +1,217 @@
++/** @file wlan_fops.c
++ * @brief This file contains the file read functions
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++/********************************************************
++Change log:
++ 01/06/06: Add Doxygen format comments
++
++********************************************************/
++
++#include "include.h"
++
++#include <linux/fs.h>
++#include <asm/uaccess.h>
++#include <asm/fcntl.h>
++#include <linux/vmalloc.h>
++
++/********************************************************
++ Local Variables
++********************************************************/
++
++/********************************************************
++ Global Variables
++********************************************************/
++
++/********************************************************
++ Local Functions
++********************************************************/
++
++/**
++ * @brief This function opens/create a file in kernel mode.
++ *
++ * @param filename Name of the file to be opened
++ * @param flags File flags
++ * @param mode File permissions
++ * @return file pointer if successful or NULL if failed.
++ */
++static struct file *
++wlan_fopen(const char *filename, unsigned int flags, int mode)
++{
++ int orgfsuid, orgfsgid;
++ struct file *file_ret;
++
++ /* Save uid and gid used for filesystem access. */
++
++ orgfsuid = current->fsuid;
++ orgfsgid = current->fsgid;
++
++ /* Set user and group to 0 (root) */
++ current->fsuid = 0;
++ current->fsgid = 0;
++
++ /* Open the file in kernel mode */
++ file_ret = filp_open(filename, flags, mode);
++
++ /* Restore the uid and gid */
++ current->fsuid = orgfsuid;
++ current->fsgid = orgfsgid;
++
++ /* Check if the file was opened successfully
++ and return the file pointer of it was. */
++ return ((IS_ERR(file_ret)) ? NULL : file_ret);
++}
++
++/**
++ * @brief This function closes a file in kernel mode.
++ *
++ * @param file_ptr File pointer
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_fclose(struct file *file_ptr)
++{
++ int orgfsuid, orgfsgid;
++ int file_ret;
++
++ if ((NULL == file_ptr) || (IS_ERR(file_ptr)))
++ return -ENOENT;
++
++ /* Save uid and gid used for filesystem access. */
++ orgfsuid = current->fsuid;
++ orgfsgid = current->fsgid;
++
++ /* Set user and group to 0 (root) */
++ current->fsuid = 0;
++ current->fsgid = 0;
++
++ /* Close the file in kernel mode (user_id = 0) */
++ file_ret = filp_close(file_ptr, 0);
++
++ /* Restore the uid and gid */
++ current->fsuid = orgfsuid;
++ current->fsgid = orgfsgid;
++
++ return (file_ret);
++}
++
++/**
++ * @brief This function reads data from files in kernel mode.
++ *
++ * @param file_ptr File pointer
++ * @param buf Buffers to read data into
++ * @param len Length of buffer
++ * @return number of characters read
++ */
++static int
++wlan_fread(struct file *file_ptr, char *buf, int len)
++{
++ int orgfsuid, orgfsgid;
++ int file_ret;
++ mm_segment_t orgfs;
++
++ /* Check if the file pointer is valid */
++ if ((NULL == file_ptr) || (IS_ERR(file_ptr)))
++ return -ENOENT;
++
++ /* Check for a valid file read function */
++ if (file_ptr->f_op->read == NULL)
++ return -ENOSYS;
++
++ /* Check for access permissions */
++ if (((file_ptr->f_flags & O_ACCMODE) & (O_RDONLY | O_RDWR)) == 0)
++ return -EACCES;
++
++ /* Check if there is a valid length */
++ if (0 >= len)
++ return -EINVAL;
++
++ /* Save uid and gid used for filesystem access. */
++ orgfsuid = current->fsuid;
++ orgfsgid = current->fsgid;
++
++ /* Set user and group to 0 (root) */
++ current->fsuid = 0;
++ current->fsgid = 0;
++
++ /* Save FS register and set FS register to kernel
++ space, needed for read and write to accept
++ buffer in kernel space. */
++ orgfs = get_fs();
++
++ /* Set the FS register to KERNEL mode. */
++ set_fs(KERNEL_DS);
++
++ /* Read the actual data from the file */
++ file_ret = file_ptr->f_op->read(file_ptr, buf, len, &file_ptr->f_pos);
++
++ /* Restore the FS register */
++ set_fs(orgfs);
++
++ /* Restore the uid and gid */
++ current->fsuid = orgfsuid;
++ current->fsgid = orgfsgid;
++
++ return (file_ret);
++}
++
++/********************************************************
++ Global Functions
++********************************************************/
++
++/**
++ * @brief This function free FW/Helper buffer.
++ *
++ * @param addr Pointer to buffer storing FW/Helper
++ * @return None
++ */
++void
++fw_buffer_free(u8 * addr)
++{
++ vfree(addr);
++}
++
++/**
++ * @brief This function reads FW/Helper.
++ *
++ * @param name File name
++ * @param addr Pointer to buffer storing FW/Helper
++ * @param len Pointer to length of FW/Helper
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++fw_read(const char *name, u8 ** addr, u32 * len)
++{
++ struct file *fp;
++ int ret;
++ u8 *ptr;
++
++ fp = wlan_fopen(name, O_RDWR, 0);
++
++ if (fp == NULL) {
++ PRINTM(MSG, "Could not open file:%s\n", name);
++ return WLAN_STATUS_FAILURE;
++ }
++
++ /*calculate file length */
++ *len = fp->f_dentry->d_inode->i_size - fp->f_pos;
++
++ ptr = (u8 *) vmalloc(*len + 1023);
++ if (ptr == NULL) {
++ PRINTM(MSG, "vmalloc failure\n");
++ return WLAN_STATUS_FAILURE;
++ }
++ if (wlan_fread(fp, ptr, *len) > 0) {
++ *addr = ptr;
++ ret = WLAN_STATUS_SUCCESS;
++ } else {
++ fw_buffer_free(ptr);
++ *addr = NULL;
++ PRINTM(MSG, "fail to read the file %s \n", name);
++ ret = WLAN_STATUS_FAILURE;
++ }
++
++ wlan_fclose(fp);
++ return ret;
++}
+diff --git a/drivers/net/wireless/marvell8686/wlan_fw.c b/drivers/net/wireless/marvell8686/wlan_fw.c
+new file mode 100644
+index 0000000..0fc258d
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_fw.c
+@@ -0,0 +1,532 @@
++/** @file wlan_fw.c
++ * @brief This file contains the initialization for FW
++ * and HW
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ */
++/********************************************************
++Change log:
++ 09/28/05: Add Doxygen format comments
++ 01/05/06: Add kernel 2.6.x support
++ 01/11/06: Conditionalize new scan/join functions.
++ Cleanup association response handler initialization.
++ 01/06/05: Add FW file read
++ 05/08/06: Remove the 2nd GET_HW_SPEC command and TempAddr/PermanentAddr
++ 06/30/06: replaced MODULE_PARM(name, type) with module_param(name, type, perm)
++
++********************************************************/
++
++#include "include.h"
++#include <linux/vmalloc.h>
++
++/********************************************************
++ Local Variables
++********************************************************/
++
++extern const char *helper_name;
++extern const char *fw_name;
++
++#if 0
++module_param(helper_name, charp, 0);
++module_param(fw_name, charp, 0);
++#endif
++
++#ifdef MFG_CMD_SUPPORT
++int mfgmode = 0;
++module_param(mfgmode, int, 0);
++#endif
++
++/********************************************************
++ Global Variables
++********************************************************/
++
++/********************************************************
++ Local Functions
++********************************************************/
++
++/**
++ * @brief This function downloads firmware image, gets
++ * HW spec from firmware and set basic parameters to
++ * firmware.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_setup_station_hw(wlan_private * priv)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_adapter *adapter = priv->adapter;
++ u8 *ptr = NULL;
++ u32 len = 0;
++
++ //HostCmd_DS_SDIO_INT_CONFIG sdio_int_cfg;
++
++ ENTER();
++
++ sbi_disable_host_int(priv);
++
++#if 0
++ if ((intmode == INTMODE_GPIO) && (gpiopin == 0)) {
++ PRINTM(MSG, "Invalid gpio pin#\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++#endif
++
++ adapter->fmimage = NULL;
++ adapter->fmimage_len = 0;
++ adapter->helper = NULL;
++ adapter->helper_len = 0;
++
++ if (helper_name != NULL) {
++ if (fw_read(helper_name, &ptr, &len) != WLAN_STATUS_FAILURE) {
++ adapter->helper = ptr;
++ adapter->helper_len = len;
++ PRINTM(INFO, "helper read success, len=%x\n", len);
++ } else {
++ PRINTM(MSG, "helper %s read fail.\n", helper_name);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ }
++
++ if (fw_name != NULL) {
++ if (fw_read(fw_name, &ptr, &len) != WLAN_STATUS_FAILURE) {
++ adapter->fmimage = ptr;
++ adapter->fmimage_len = len;
++ PRINTM(INFO, "fw read success, len=%x\n", len);
++ } else {
++ PRINTM(MSG, "fw %s read fail.\n", fw_name);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ }
++
++ /* Download the helper */
++ ret = sbi_prog_helper(priv);
++
++ if (ret) {
++ PRINTM(INFO, "Bootloader in invalid state!\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ /* Download the main firmware via the helper firmware */
++ if (sbi_prog_firmware_w_helper(priv)) {
++ PRINTM(INFO, "Wlan FW download failed!\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ /* check if the fimware is downloaded successfully or not */
++ if (sbi_verify_fw_download(priv)) {
++ PRINTM(INFO, "FW failed to be active in time!\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++#define RF_REG_OFFSET 0x07
++#define RF_REG_VALUE 0xc8
++
++ sbi_enable_host_int(priv);
++
++#define INT_RASING_EDGE 0
++#define INT_FALLING_EDGE 1
++
++#define DELAY_1_US 1
++#if 0
++ if (intmode == INTMODE_GPIO) {
++ /* This command should be issued first */
++ sdio_int_cfg.Action = HostCmd_ACT_GEN_SET;
++ sdio_int_cfg.Gpio_pin = gpiopin;
++ sdio_int_cfg.Gpio_int_edge = INT_FALLING_EDGE;
++ sdio_int_cfg.Gpio_pulse_width = DELAY_1_US;
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_SDIO_GPIO_INT_CONFIG,
++ 0, HostCmd_OPTION_WAITFORRSP,
++ 0, &sdio_int_cfg);
++ }
++#endif
++#ifdef MFG_CMD_SUPPORT
++ if (mfgmode == 0) {
++#endif
++
++ /*
++ * Read MAC address from HW
++ */
++ memset(adapter->CurrentAddr, 0xff, MRVDRV_ETH_ADDR_LEN);
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_GET_HW_SPEC,
++ 0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
++
++ if (ret) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_MAC_CONTROL,
++ 0, HostCmd_OPTION_WAITFORRSP, 0,
++ &adapter->CurrentPacketFilter);
++
++ if (ret) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_FW_WAKE_METHOD,
++ HostCmd_ACT_GET,
++ HostCmd_OPTION_WAITFORRSP, 0,
++ &priv->adapter->fwWakeupMethod);
++
++ if (ret) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++#ifdef MFG_CMD_SUPPORT
++ }
++#endif
++
++#ifdef MFG_CMD_SUPPORT
++ if (mfgmode == 0) {
++#endif
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_RATE_ADAPT_RATESET,
++ HostCmd_ACT_GEN_GET,
++ HostCmd_OPTION_WAITFORRSP, 0, NULL);
++ if (ret) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ priv->adapter->DataRate = 0;
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_RF_TX_POWER,
++ HostCmd_ACT_GEN_GET,
++ HostCmd_OPTION_WAITFORRSP, 0, NULL);
++
++ if (ret) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++#ifdef MFG_CMD_SUPPORT
++ }
++#endif
++
++ ret = WLAN_STATUS_SUCCESS;
++ done:
++ if (adapter->helper != NULL) {
++ fw_buffer_free(adapter->helper);
++ }
++ if (adapter->fmimage != NULL) {
++ fw_buffer_free(adapter->fmimage);
++ }
++
++ LEAVE();
++
++ return (ret);
++}
++
++/**
++ * @brief This function initializes timers.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return n/a
++ */
++static void
++init_sync_objects(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ InitializeTimer(&Adapter->MrvDrvCommandTimer,
++ MrvDrvCommandTimerFunction, priv);
++ Adapter->CommandTimerIsSet = FALSE;
++
++#ifdef REASSOCIATION
++ /* Initialize the timer for the reassociation */
++ InitializeTimer(&Adapter->MrvDrvTimer, MrvDrvReassocTimerFunction, priv);
++ Adapter->ReassocTimerIsSet = FALSE;
++#endif /* REASSOCIATION */
++
++ return;
++}
++
++/**
++ * @brief This function allocates buffer for the member of adapter
++ * structure like command buffer and BSSID list.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_allocate_adapter(wlan_private * priv)
++{
++ u32 ulBufSize;
++ wlan_adapter *Adapter = priv->adapter;
++
++ BSSDescriptor_t *pTempScanTable;
++
++ /* Allocate buffer to store the BSSID list */
++ ulBufSize = sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST;
++ if (!(pTempScanTable = kmalloc(ulBufSize, GFP_KERNEL))) {
++ return WLAN_STATUS_FAILURE;
++ }
++
++ Adapter->ScanTable = pTempScanTable;
++ memset(Adapter->ScanTable, 0, ulBufSize);
++
++ if (!(Adapter->bgScanConfig =
++ kmalloc(sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG), GFP_KERNEL))) {
++ return WLAN_STATUS_FAILURE;
++ }
++ Adapter->bgScanConfigSize = sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG);
++ memset(Adapter->bgScanConfig, 0, Adapter->bgScanConfigSize);
++
++ spin_lock_init(&Adapter->QueueSpinLock);
++
++ /* Allocate the command buffers */
++ if (AllocateCmdBuffer(priv) != WLAN_STATUS_SUCCESS) {
++ return WLAN_STATUS_FAILURE;
++ }
++
++ memset(&Adapter->PSConfirmSleep, 0, sizeof(PS_CMD_ConfirmSleep));
++ Adapter->PSConfirmSleep.SeqNum = wlan_cpu_to_le16(++Adapter->SeqNum);
++ Adapter->PSConfirmSleep.Command =
++ wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE);
++ Adapter->PSConfirmSleep.Size =
++ wlan_cpu_to_le16(sizeof(PS_CMD_ConfirmSleep));
++ Adapter->PSConfirmSleep.Result = 0;
++ Adapter->PSConfirmSleep.Action =
++ wlan_cpu_to_le16(HostCmd_SubCmd_Sleep_Confirmed);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function initializes the adapter structure
++ * and set default value to the member of adapter.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return n/a
++ */
++static void
++wlan_init_adapter(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int i;
++
++ Adapter->ScanProbes = 0;
++
++ Adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
++ Adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
++
++ /* ATIM params */
++ Adapter->AtimWindow = 0;
++ Adapter->ATIMEnabled = FALSE;
++
++ Adapter->MediaConnectStatus = WlanMediaStateDisconnected;
++
++ memset(Adapter->CurrentAddr, 0xff, MRVDRV_ETH_ADDR_LEN);
++
++ /* Status variables */
++ Adapter->HardwareStatus = WlanHardwareStatusInitializing;
++
++ /* scan type */
++ Adapter->ScanType = HostCmd_SCAN_TYPE_ACTIVE;
++
++ /* scan mode */
++ Adapter->ScanMode = HostCmd_BSS_TYPE_ANY;
++
++ /* scan time */
++ Adapter->SpecificScanTime = MRVDRV_SPECIFIC_SCAN_CHAN_TIME;
++ Adapter->ActiveScanTime = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
++ Adapter->PassiveScanTime = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
++
++ /* 802.11 specific */
++ Adapter->SecInfo.WEPStatus = Wlan802_11WEPDisabled;
++ for (i = 0; i < sizeof(Adapter->WepKey) / sizeof(Adapter->WepKey[0]); i++)
++ memset(&Adapter->WepKey[i], 0, sizeof(MRVL_WEP_KEY));
++ Adapter->CurrentWepKeyIndex = 0;
++ Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
++ Adapter->SecInfo.EncryptionMode = CIPHER_NONE;
++ Adapter->AdhocAESEnabled = FALSE;
++ Adapter->InfrastructureMode = Wlan802_11Infrastructure;
++
++ Adapter->NumInScanTable = 0;
++ Adapter->pAttemptedBSSDesc = NULL;
++#ifdef REASSOCIATION
++ OS_INIT_SEMAPHORE(&Adapter->ReassocSem);
++#endif
++ Adapter->pBeaconBufEnd = Adapter->beaconBuffer;
++
++ Adapter->HisRegCpy |= HIS_TxDnLdRdy;
++
++ memset(&Adapter->CurBssParams, 0, sizeof(Adapter->CurBssParams));
++
++ /* PnP and power profile */
++ Adapter->SurpriseRemoved = FALSE;
++
++ Adapter->CurrentPacketFilter =
++ HostCmd_ACT_MAC_RTS_CTS_ENABLE |
++ HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON;
++
++ Adapter->RadioOn = RADIO_ON;
++#ifdef REASSOCIATION
++#if (WIRELESS_EXT >= 18)
++ Adapter->Reassoc_on = FALSE;
++#else
++ Adapter->Reassoc_on = TRUE;
++#endif
++#endif /* REASSOCIATION */
++ Adapter->TxAntenna = RF_ANTENNA_2;
++ Adapter->RxAntenna = RF_ANTENNA_AUTO;
++
++ Adapter->HWRateDropMode = HW_TABLE_RATE_DROP;
++ Adapter->Is_DataRate_Auto = TRUE;
++ Adapter->BeaconPeriod = MRVDRV_BEACON_INTERVAL;
++
++ Adapter->AdhocChannel = DEFAULT_AD_HOC_CHANNEL;
++
++ Adapter->PSMode = Wlan802_11PowerModeCAM;
++ Adapter->MultipleDtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
++
++ Adapter->ListenInterval = MRVDRV_DEFAULT_LISTEN_INTERVAL;
++
++ Adapter->PSState = PS_STATE_FULL_POWER;
++
++ Adapter->NeedToWakeup = FALSE;
++ Adapter->LocalListenInterval = 0; /* default value in firmware will be used */
++ Adapter->fwWakeupMethod = WAKEUP_FW_UNCHANGED;
++
++ Adapter->IsDeepSleep = FALSE;
++ Adapter->IsAutoDeepSleepEnabled = FALSE;
++
++ Adapter->bWakeupDevRequired = FALSE;
++
++ Adapter->WakeupTries = 0;
++ Adapter->bHostSleepConfigured = FALSE;
++
++ Adapter->HSCfg.conditions = HOST_SLEEP_CFG_CANCEL;
++ Adapter->HSCfg.gpio = 0;
++ Adapter->HSCfg.gap = 0;
++
++ Adapter->DataRate = 0; // Initially indicate the rate as auto
++
++ Adapter->adhoc_grate_enabled = FALSE;
++
++ Adapter->IntCounter = Adapter->IntCounterSaved = 0;
++
++ INIT_LIST_HEAD((struct list_head *) &Adapter->RxSkbQ);
++
++ Adapter->gen_null_pkg = TRUE; /*Enable NULL Pkg generation */
++
++ init_waitqueue_head(&Adapter->cmd_EncKey);
++
++ spin_lock_init(&Adapter->CurrentTxLock);
++
++ Adapter->CurrentTxSkb = NULL;
++ Adapter->PktTxCtrl = 0;
++
++ return;
++}
++
++/********************************************************
++ Global Functions
++********************************************************/
++
++/**
++ * @brief This function initializes firmware
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_init_fw(wlan_private * priv)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ /* Allocate adapter structure */
++ if ((ret = wlan_allocate_adapter(priv)) != WLAN_STATUS_SUCCESS) {
++ goto done;
++ }
++
++ /* init adapter structure */
++ wlan_init_adapter(priv);
++
++ /* init timer etc. */
++ init_sync_objects(priv);
++
++ /* download fimrware etc. */
++ if ((ret = wlan_setup_station_hw(priv)) != WLAN_STATUS_SUCCESS) {
++ Adapter->HardwareStatus = WlanHardwareStatusNotReady;
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ /* init 802.11d */
++ wlan_init_11d(priv);
++
++ Adapter->HardwareStatus = WlanHardwareStatusReady;
++ ret = WLAN_STATUS_SUCCESS;
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function frees the structure of adapter
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return n/a
++ */
++void
++wlan_free_adapter(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (!Adapter) {
++ PRINTM(INFO, "Why double free adapter?:)\n");
++ return;
++ }
++
++ PRINTM(INFO, "Free Command buffer\n");
++ FreeCmdBuffer(priv);
++
++ PRINTM(INFO, "Free CommandTimer\n");
++ if (Adapter->CommandTimerIsSet) {
++ CancelTimer(&Adapter->MrvDrvCommandTimer);
++ Adapter->CommandTimerIsSet = FALSE;
++ }
++ FreeTimer(&Adapter->MrvDrvCommandTimer);
++#ifdef REASSOCIATION
++ PRINTM(INFO, "Free MrvDrvTimer\n");
++ if (Adapter->ReassocTimerIsSet) {
++ CancelTimer(&Adapter->MrvDrvTimer);
++ Adapter->ReassocTimerIsSet = FALSE;
++ }
++ FreeTimer(&Adapter->MrvDrvTimer);
++#endif /* REASSOCIATION */
++
++ if (Adapter->bgScanConfig) {
++ kfree(Adapter->bgScanConfig);
++ Adapter->bgScanConfig = NULL;
++ }
++
++ OS_FREE_LOCK(&Adapter->CurrentTxLock);
++ OS_FREE_LOCK(&Adapter->QueueSpinLock);
++
++ PRINTM(INFO, "Free ScanTable\n");
++ if (Adapter->ScanTable) {
++ kfree(Adapter->ScanTable);
++ Adapter->ScanTable = NULL;
++ }
++
++ PRINTM(INFO, "Free Adapter\n");
++
++ /* Free the adapter object itself */
++ kfree(Adapter);
++ priv->adapter = NULL;
++ LEAVE();
++}
+diff --git a/drivers/net/wireless/marvell8686/wlan_join.c b/drivers/net/wireless/marvell8686/wlan_join.c
+new file mode 100644
+index 0000000..46d5961
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_join.c
+@@ -0,0 +1,2031 @@
++/** @file wlan_join.c
++ *
++ * @brief Functions implementing wlan infrastructure and adhoc join routines
++ *
++ * IOCTL handlers as well as command preperation and response routines
++ * for sending adhoc start, adhoc join, and association commands
++ * to the firmware.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ *
++ * @sa wlan_join.h
++ */
++/*************************************************************
++Change Log:
++ 01/11/06: Initial revision. Match new scan code, relocate related functions
++ 01/19/06: Fix failure to save adhoc ssid as current after adhoc start
++ 03/16/06: Add a semaphore to protect reassociation thread
++
++************************************************************/
++
++#include "include.h"
++
++/**
++ * @brief This function finds out the common rates between rate1 and rate2.
++ *
++ * It will fill common rates in rate1 as output if found.
++ *
++ * NOTE: Setting the MSB of the basic rates need to be taken
++ * care, either before or after calling this function
++ *
++ * @param Adapter A pointer to wlan_adapter structure
++ * @param rate1 the buffer which keeps input and output
++ * @param rate1_size the size of rate1 buffer
++ * @param rate2 the buffer which keeps rate2
++ * @param rate2_size the size of rate2 buffer.
++ *
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++get_common_rates(wlan_adapter * Adapter, u8 * rate1,
++ int rate1_size, u8 * rate2, int rate2_size)
++{
++ u8 *ptr = rate1;
++ int ret = WLAN_STATUS_SUCCESS;
++ u8 *tmp = NULL;
++ int i, j;
++
++ if (!(tmp = kmalloc(rate1_size, GFP_KERNEL))) {
++ PRINTM(WARN, "Allocate buffer for common rates failed\n");
++ return -ENOMEM;
++ }
++
++ memcpy(tmp, rate1, rate1_size);
++ memset(rate1, 0, rate1_size);
++
++ for (i = 0; rate2[i] && i < rate2_size; i++) {
++ for (j = 0; tmp[j] && j < rate1_size; j++) {
++ /* Check common rate, excluding the bit for basic rate */
++ if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
++ *rate1++ = tmp[j];
++ break;
++ }
++ }
++ }
++
++ HEXDUMP("rate1 (AP) Rates", tmp, rate1_size);
++ HEXDUMP("rate2 (Card) Rates", rate2, rate2_size);
++ HEXDUMP("Common Rates", ptr, rate1 - ptr);
++ PRINTM(INFO, "Tx DataRate is set to 0x%X\n", Adapter->DataRate);
++
++ if (!Adapter->Is_DataRate_Auto) {
++ while (*ptr) {
++ if ((*ptr & 0x7f) == Adapter->DataRate) {
++ ret = WLAN_STATUS_SUCCESS;
++ goto done;
++ }
++ ptr++;
++ }
++ PRINTM(MSG, "Previously set fixed data rate %#x isn't "
++ "compatible with the network.\n", Adapter->DataRate);
++
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ ret = WLAN_STATUS_SUCCESS;
++ done:
++ kfree(tmp);
++ return ret;
++}
++
++/**
++ * @brief Create the intersection of the rates supported by a target BSS and
++ * our Adapter settings for use in an assoc/join command.
++ *
++ * @param Adapter A pointer to wlan_adapter structure
++ * @param pBSSDesc BSS Descriptor whose rates are used in the setup
++ * @param pOutRates Output: Octet array of rates common between the BSS
++ * and the Adapter supported rates settings
++ * @param pOutRatesSize Output: Number of rates/octets set in pOutRates
++ *
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ *
++ */
++static int
++setup_rates_from_bssdesc(wlan_adapter * Adapter,
++ BSSDescriptor_t * pBSSDesc,
++ u8 * pOutRates, int *pOutRatesSize)
++{
++ u8 *card_rates;
++ int card_rates_size;
++
++ ENTER();
++
++ memcpy(pOutRates, pBSSDesc->SupportedRates, WLAN_SUPPORTED_RATES);
++
++ card_rates = SupportedRates;
++ card_rates_size = sizeof(SupportedRates);
++
++ if (get_common_rates(Adapter, pOutRates, WLAN_SUPPORTED_RATES,
++ card_rates, card_rates_size)) {
++ *pOutRatesSize = 0;
++ PRINTM(INFO, "get_common_rates failed\n");
++ LEAVE();
++ return WLAN_STATUS_FAILURE;
++ }
++
++ *pOutRatesSize = MIN(strlen(pOutRates), WLAN_SUPPORTED_RATES);
++
++ LEAVE();
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Retrieve the association response
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_get_assoc_rsp_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int copySize;
++
++ /*
++ * Set the amount to copy back to the application as the minimum of the
++ * available assoc resp data or the buffer provided by the application
++ */
++ copySize = MIN(Adapter->assocRspSize, wrq->u.data.length);
++
++ /* Copy the (re)association response back to the application */
++ if (copy_to_user(wrq->u.data.pointer, Adapter->assocRspBuffer, copySize)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++
++ /* Returned copy length */
++ wrq->u.data.length = copySize;
++
++ /* Reset assoc buffer */
++ Adapter->assocRspSize = 0;
++
++ /* No error on return */
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Set an opaque block of Marvell TLVs for insertion into the
++ * association command
++ *
++ * Pass an opaque block of data, expected to be Marvell TLVs, to the driver
++ * for eventual passthrough to the firmware in an associate/join
++ * (and potentially start) command.
++ *
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_set_mrvl_tlv_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ /* If the passed length is zero, reset the buffer */
++ if (wrq->u.data.length == 0) {
++ Adapter->mrvlAssocTlvBufferLen = 0;
++ } else {
++ /*
++ * Verify that the passed length is not larger than the available
++ * space remaining in the buffer
++ */
++ if (wrq->u.data.length < (sizeof(Adapter->mrvlAssocTlvBuffer)
++ - Adapter->mrvlAssocTlvBufferLen)) {
++ /* Append the passed data to the end of the mrvlAssocTlvBuffer */
++ if (copy_from_user(Adapter->mrvlAssocTlvBuffer
++ + Adapter->mrvlAssocTlvBufferLen,
++ wrq->u.data.pointer, wrq->u.data.length)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ /* Increment the stored buffer length by the size passed */
++ Adapter->mrvlAssocTlvBufferLen += wrq->u.data.length;
++ } else {
++ /* Passed data does not fit in the remaining buffer space */
++ ret = WLAN_STATUS_FAILURE;
++ }
++ }
++
++ /* Return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE */
++ return ret;
++}
++
++/**
++ * @brief Stop Adhoc Network
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_do_adhocstop_ioctl(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (Adapter->InfrastructureMode == Wlan802_11IBSS &&
++ Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++
++ ret = StopAdhocNetwork(priv);
++
++ } else {
++ LEAVE();
++ return -ENOTSUPP;
++ }
++
++ LEAVE();
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Set essid
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param dwrq A pointer to iw_point structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS--success, otherwise--fail
++ */
++int
++wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++ WLAN_802_11_SSID reqSSID;
++ int i;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ /* Clear any past association response stored for application retrieval */
++ Adapter->assocRspSize = 0;
++
++#ifdef REASSOCIATION
++ // cancel re-association timer if there's one
++ if (Adapter->ReassocTimerIsSet == TRUE) {
++ CancelTimer(&Adapter->MrvDrvTimer);
++ Adapter->ReassocTimerIsSet = FALSE;
++ }
++
++ if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
++ PRINTM(ERROR, "Acquire semaphore error, wlan_set_essid\n");
++ return -EBUSY;
++ }
++#endif /* REASSOCIATION */
++
++ /* Check the size of the string */
++ if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
++ ret = -E2BIG;
++ goto setessid_ret;
++ }
++
++ memset(&reqSSID, 0, sizeof(WLAN_802_11_SSID));
++
++ /*
++ * Check if we asked for `any' or 'particular'
++ */
++ if (!dwrq->flags) {
++ if (FindBestNetworkSsid(priv, &reqSSID)) {
++ PRINTM(INFO, "Could not find best network\n");
++ ret = WLAN_STATUS_SUCCESS;
++ goto setessid_ret;
++ }
++ } else {
++ /* Set the SSID */
++#if WIRELESS_EXT > 20
++ reqSSID.SsidLength = dwrq->length;
++#else
++ reqSSID.SsidLength = dwrq->length - 1;
++#endif
++ memcpy(reqSSID.Ssid, extra,
++ MIN(reqSSID.SsidLength, reqSSID.SsidLength));
++
++ }
++
++ PRINTM(INFO, "Requested new SSID = %s\n",
++ (reqSSID.SsidLength > 0) ? (char *) reqSSID.Ssid : "NULL");
++ if (!reqSSID.SsidLength || reqSSID.Ssid[0] < 0x20) {
++ PRINTM(INFO, "Invalid SSID - aborting set_essid\n");
++ ret = -EINVAL;
++ goto setessid_ret;
++ }
++
++ if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
++ /* infrastructure mode */
++ PRINTM(INFO, "SSID requested = %s\n", reqSSID.Ssid);
++
++ if ((dwrq->flags & IW_ENCODE_INDEX) > 1) {
++ i = (dwrq->flags & IW_ENCODE_INDEX) - 1; /* convert to 0 based */
++
++ PRINTM(INFO, "Request SSID by index = %d\n", i);
++
++ if (i > Adapter->NumInScanTable) {
++ /* Failed to find in table since index is > current max. */
++ i = -EINVAL;
++ }
++ } else {
++ SendSpecificSSIDScan(priv, &reqSSID);
++ i = FindSSIDInList(Adapter,
++ &reqSSID, NULL, Wlan802_11Infrastructure);
++ }
++
++ if (i >= 0) {
++ PRINTM(INFO, "SSID found in scan list ... associating...\n");
++
++ ret = wlan_associate(priv, &Adapter->ScanTable[i]);
++
++ if (ret) {
++ goto setessid_ret;
++ }
++ } else { /* i >= 0 */
++ ret = i; /* return -ENETUNREACH, passed from FindSSIDInList */
++ goto setessid_ret;
++ }
++ } else {
++ /* ad hoc mode */
++ /* If the requested SSID matches current SSID return */
++ if (!SSIDcmp(&Adapter->CurBssParams.BSSDescriptor.Ssid, &reqSSID)) {
++ ret = WLAN_STATUS_SUCCESS;
++ goto setessid_ret;
++ }
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ /*
++ * Exit Adhoc mode
++ */
++ PRINTM(INFO, "Sending Adhoc Stop\n");
++ ret = StopAdhocNetwork(priv);
++
++ if (ret) {
++ goto setessid_ret;
++ }
++ }
++ Adapter->AdhocLinkSensed = FALSE;
++
++ if ((dwrq->flags & IW_ENCODE_INDEX) > 1) {
++ i = (dwrq->flags & IW_ENCODE_INDEX) - 1; /* 0 based */
++ if (i > Adapter->NumInScanTable) {
++ /* Failed to find in table since index is > current max. */
++ i = -EINVAL;
++ }
++ } else {
++ /* Scan for the network */
++ SendSpecificSSIDScan(priv, &reqSSID);
++
++ /* Search for the requested SSID in the scan table */
++ i = FindSSIDInList(Adapter, &reqSSID, NULL, Wlan802_11IBSS);
++ }
++
++ if (i >= 0) {
++ PRINTM(INFO, "SSID found at %d in List, so join\n", i);
++ JoinAdhocNetwork(priv, &Adapter->ScanTable[i]);
++ } else {
++ /* else send START command */
++ PRINTM(INFO, "SSID not found in list, "
++ "so creating adhoc with ssid = %s\n", reqSSID.Ssid);
++
++ StartAdhocNetwork(priv, &reqSSID);
++ } /* end of else (START command) */
++ } /* end of else (Ad hoc mode) */
++
++ /*
++ * The MediaConnectStatus change can be removed later when
++ * the ret code is being properly returned.
++ */
++ /* Check to see if we successfully connected */
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ ret = WLAN_STATUS_SUCCESS;
++ } else {
++ ret = -ENETDOWN;
++ }
++
++ setessid_ret:
++#ifdef REASSOCIATION
++ OS_REL_SEMAPHORE(&Adapter->ReassocSem);
++#endif
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Connect to the AP or Ad-hoc Network with specific bssid
++ *
++ * NOTE: Scan should be issued by application before this function is called
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param awrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
++ struct sockaddr *awrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++ const u8 bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 };
++ u8 reqBSSID[ETH_ALEN];
++ int i;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ /* Clear any past association response stored for application retrieval */
++ Adapter->assocRspSize = 0;
++
++ if (awrq->sa_family != ARPHRD_ETHER)
++ return -EINVAL;
++
++ PRINTM(INFO, "ASSOC: WAP: sa_data: %02x:%02x:%02x:%02x:%02x:%02x\n",
++ (u8) awrq->sa_data[0], (u8) awrq->sa_data[1],
++ (u8) awrq->sa_data[2], (u8) awrq->sa_data[3],
++ (u8) awrq->sa_data[4], (u8) awrq->sa_data[5]);
++#ifdef REASSOCIATION
++ // cancel re-association timer if there's one
++ if (Adapter->ReassocTimerIsSet == TRUE) {
++ CancelTimer(&Adapter->MrvDrvTimer);
++ Adapter->ReassocTimerIsSet = FALSE;
++ }
++#endif /* REASSOCIATION */
++
++ if (!memcmp(bcast, awrq->sa_data, ETH_ALEN)) {
++ i = FindBestSSIDInList(Adapter);
++ } else {
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ if (memcmp
++ (awrq->sa_data,
++ Adapter->CurBssParams.BSSDescriptor.MacAddress,
++ ETH_ALEN) == 0)
++ return WLAN_STATUS_SUCCESS;
++ }
++ memcpy(reqBSSID, awrq->sa_data, ETH_ALEN);
++
++ PRINTM(INFO, "ASSOC: WAP: Bssid = %02x:%02x:%02x:%02x:%02x:%02x\n",
++ reqBSSID[0], reqBSSID[1], reqBSSID[2],
++ reqBSSID[3], reqBSSID[4], reqBSSID[5]);
++
++ /* Search for index position in list for requested MAC */
++ i = FindBSSIDInList(Adapter, reqBSSID, Adapter->InfrastructureMode);
++ }
++
++ if (i < 0) {
++ PRINTM(INFO, "ASSOC: WAP: MAC address not found in BSSID List\n");
++ return -ENETUNREACH;
++ }
++
++ if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
++
++ ret = wlan_associate(priv, &Adapter->ScanTable[i]);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ } else {
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ /* Exit Adhoc mode */
++ ret = StopAdhocNetwork(priv);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ }
++ Adapter->AdhocLinkSensed = FALSE;
++
++ JoinAdhocNetwork(priv, &Adapter->ScanTable[i]);
++ }
++
++ /* Check to see if we successfully connected */
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ ret = WLAN_STATUS_SUCCESS;
++ } else {
++ ret = -ENETDOWN;
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Associated to a specific BSS discovered in a scan
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param pBSSDesc Pointer to the BSS descriptor to associate with.
++ *
++ * @return WLAN_STATUS_SUCCESS-success, otherwise fail
++ */
++int
++wlan_associate(wlan_private * priv, BSSDescriptor_t * pBSSDesc)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int enableData = TRUE;
++ union iwreq_data wrqu;
++ int ret;
++ IEEEtypes_AssocRsp_t *pAssocRsp;
++ u8 currentBSSID[MRVDRV_ETH_ADDR_LEN];
++ int reassocAttempt = FALSE;
++
++ ENTER();
++
++ /* Return error if the Adapter or table entry is not marked as infra */
++ if ((Adapter->InfrastructureMode != Wlan802_11Infrastructure)
++ || (pBSSDesc->InfrastructureMode != Wlan802_11Infrastructure)) {
++ LEAVE();
++ return -EINVAL;
++ }
++
++ memcpy(&currentBSSID,
++ &Adapter->CurBssParams.BSSDescriptor.MacAddress,
++ sizeof(currentBSSID));
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ reassocAttempt = TRUE;
++ PRINTM(INFO, "Attempting reassociation, stopping wmm queues\n");
++ wmm_stop_queue(priv);
++ }
++
++ /* Clear any past association response stored for application retrieval */
++ Adapter->assocRspSize = 0;
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_ASSOCIATE,
++ 0, HostCmd_OPTION_WAITFORRSP, 0, pBSSDesc);
++
++ if (Adapter->wmm.enabled) {
++ /* Don't re-enable carrier until we get the WMM_GET_STATUS event */
++ enableData = FALSE;
++ } else {
++ /* Since WMM is not enabled, setup the queues with the defaults */
++ wmm_setup_queues(priv);
++ }
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++
++ if (reassocAttempt
++ && (memcmp(&currentBSSID,
++ &Adapter->CurBssParams.BSSDescriptor.MacAddress,
++ sizeof(currentBSSID)) == 0)) {
++
++ /* Reassociation attempt failed, still associated to old AP,
++ ** no need to wait for WMM notification to restart data
++ */
++ enableData = TRUE;
++ }
++ if (enableData) {
++ PRINTM(INFO, "Post association, re-enabling data flow\n");
++ wmm_start_queue(priv);
++ os_carrier_on(priv);
++ os_start_queue(priv);
++ }
++ } else {
++ PRINTM(INFO, "Post association, stopping data flow\n");
++ os_carrier_off(priv);
++ os_stop_queue(priv);
++ }
++
++ memcpy(wrqu.ap_addr.sa_data,
++ &Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
++ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
++ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
++
++ pAssocRsp = (IEEEtypes_AssocRsp_t *) Adapter->assocRspBuffer;
++
++ if (ret || pAssocRsp->StatusCode) {
++ ret = -ENETUNREACH;
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Associated to a specific indexed entry in the ScanTable
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param tableIdx Index into the ScanTable to associate to, index parameter
++ * base value is 1. No scanning is done before the
++ * association attempt.
++ *
++ * @return WLAN_STATUS_SUCCESS-success, otherwise fail
++ */
++int
++wlan_associate_to_table_idx(wlan_private * priv, int tableIdx)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret;
++
++ ENTER();
++
++#ifdef REASSOCIATION
++ if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
++ PRINTM(ERROR, "Acquire semaphore error\n");
++ return -EBUSY;
++ }
++#endif
++
++ PRINTM(INFO, "ASSOC: iwpriv: Index = %d, NumInScanTable = %d\n",
++ tableIdx, Adapter->NumInScanTable);
++
++ /* Check index in table, subtract 1 if within range and call association
++ * sub-function. ScanTable[] is 0 based, parameter is 1 based to
++ * conform with IW_ENCODE_INDEX flag parameter passing in iwconfig/iwlist
++ */
++ if (tableIdx && (tableIdx <= Adapter->NumInScanTable)) {
++ ret = wlan_associate(priv, &Adapter->ScanTable[tableIdx - 1]);
++ } else {
++ ret = -EINVAL;
++ }
++
++#ifdef REASSOCIATION
++ OS_REL_SEMAPHORE(&Adapter->ReassocSem);
++#endif
++ LEAVE();
++
++ return ret;
++}
++
++/**
++ * @brief Start an Adhoc Network
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param AdhocSSID The ssid of the Adhoc Network
++ * @return WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
++ */
++int
++StartAdhocNetwork(wlan_private * priv, WLAN_802_11_SSID * AdhocSSID)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ Adapter->AdhocCreate = TRUE;
++
++ PRINTM(INFO, "Adhoc Channel = %d\n", Adapter->AdhocChannel);
++ PRINTM(INFO, "CurBssParams.channel = %d\n",
++ Adapter->CurBssParams.BSSDescriptor.Channel);
++ PRINTM(INFO, "CurBssParams.band = %d\n", Adapter->CurBssParams.band);
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_AD_HOC_START,
++ 0, HostCmd_OPTION_WAITFORRSP, 0, AdhocSSID);
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Join an adhoc network found in a previous scan
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param pBSSDesc Pointer to a BSS descriptor found in a previous scan
++ * to attempt to join
++ *
++ * @return WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
++ */
++int
++JoinAdhocNetwork(wlan_private * priv, BSSDescriptor_t * pBSSDesc)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ PRINTM(INFO, "JoinAdhocNetwork: CurBss.ssid =%s\n",
++ Adapter->CurBssParams.BSSDescriptor.Ssid.Ssid);
++ PRINTM(INFO, "JoinAdhocNetwork: CurBss.ssid_len =%u\n",
++ Adapter->CurBssParams.BSSDescriptor.Ssid.SsidLength);
++ PRINTM(INFO, "JoinAdhocNetwork: ssid =%s\n", pBSSDesc->Ssid.Ssid);
++ PRINTM(INFO, "JoinAdhocNetwork: ssid len =%u\n",
++ pBSSDesc->Ssid.SsidLength);
++
++ /* check if the requested SSID is already joined */
++ if (Adapter->CurBssParams.BSSDescriptor.Ssid.SsidLength
++ && !SSIDcmp(&pBSSDesc->Ssid,
++ &Adapter->CurBssParams.BSSDescriptor.Ssid)
++ && (Adapter->CurBssParams.BSSDescriptor.InfrastructureMode ==
++ Wlan802_11IBSS)) {
++
++ PRINTM(INFO,
++ "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
++ "not attempting to re-join");
++
++ return WLAN_STATUS_FAILURE;
++ }
++
++ PRINTM(INFO, "CurBssParams.channel = %d\n",
++ Adapter->CurBssParams.BSSDescriptor.Channel);
++ PRINTM(INFO, "CurBssParams.band = %c\n", Adapter->CurBssParams.band);
++
++ Adapter->AdhocCreate = FALSE;
++
++ // store the SSID info temporarily
++ memset(&Adapter->AttemptedSSIDBeforeScan, 0, sizeof(WLAN_802_11_SSID));
++ memcpy(&Adapter->AttemptedSSIDBeforeScan,
++ &pBSSDesc->Ssid, sizeof(WLAN_802_11_SSID));
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
++ 0, HostCmd_OPTION_WAITFORRSP, 0, pBSSDesc);
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Stop the Adhoc Network
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
++ */
++int
++StopAdhocNetwork(wlan_private * priv)
++{
++ return PrepareAndSendCommand(priv, HostCmd_CMD_802_11_AD_HOC_STOP,
++ 0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
++}
++
++/**
++ * @brief Send Deauthentication Request
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
++ */
++int
++SendDeauthentication(wlan_private * priv)
++{
++ return PrepareAndSendCommand(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
++ 0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
++}
++
++/**
++ * @brief Set Idle Off
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlanidle_off(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++ const u8 zeroMac[] = { 0, 0, 0, 0, 0, 0 };
++ int i;
++
++ ENTER();
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
++ if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
++ if (memcmp(Adapter->PreviousBSSID, zeroMac, sizeof(zeroMac)) != 0) {
++
++ PRINTM(INFO, "Previous SSID = %s\n",
++ Adapter->PreviousSSID.Ssid);
++ PRINTM(INFO, "Previous BSSID = "
++ "%02x:%02x:%02x:%02x:%02x:%02x:\n",
++ Adapter->PreviousBSSID[0], Adapter->PreviousBSSID[1],
++ Adapter->PreviousBSSID[2], Adapter->PreviousBSSID[3],
++ Adapter->PreviousBSSID[4], Adapter->PreviousBSSID[5]);
++
++ i = FindSSIDInList(Adapter,
++ &Adapter->PreviousSSID,
++ Adapter->PreviousBSSID,
++ Adapter->InfrastructureMode);
++
++ if (i < 0) {
++ SendSpecificBSSIDScan(priv, Adapter->PreviousBSSID);
++ i = FindSSIDInList(Adapter,
++ &Adapter->PreviousSSID,
++ Adapter->PreviousBSSID,
++ Adapter->InfrastructureMode);
++ }
++
++ if (i < 0) {
++ /* If the BSSID could not be found, try just the SSID */
++ i = FindSSIDInList(Adapter,
++ &Adapter->PreviousSSID,
++ NULL, Adapter->InfrastructureMode);
++ }
++
++ if (i < 0) {
++ SendSpecificSSIDScan(priv, &Adapter->PreviousSSID);
++ i = FindSSIDInList(Adapter,
++ &Adapter->PreviousSSID,
++ NULL, Adapter->InfrastructureMode);
++ }
++
++ if (i >= 0) {
++ ret = wlan_associate(priv, &Adapter->ScanTable[i]);
++ }
++ }
++ } else if (Adapter->InfrastructureMode == Wlan802_11IBSS) {
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_AD_HOC_START,
++ 0, HostCmd_OPTION_WAITFORRSP,
++ 0, &Adapter->PreviousSSID);
++ }
++ }
++ /* else it is connected */
++
++ PRINTM(INFO, "\nwlanidle is off");
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Set Idle On
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlanidle_on(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
++ PRINTM(INFO, "Previous SSID = %s\n", Adapter->PreviousSSID.Ssid);
++ memcpy(&Adapter->PreviousSSID,
++ &Adapter->CurBssParams.BSSDescriptor.Ssid,
++ sizeof(WLAN_802_11_SSID));
++ SendDeauthentication(priv);
++
++ } else if (Adapter->InfrastructureMode == Wlan802_11IBSS) {
++ ret = StopAdhocNetwork(priv);
++ }
++
++ }
++#ifdef REASSOCIATION
++ if (Adapter->ReassocTimerIsSet == TRUE) {
++ CancelTimer(&Adapter->MrvDrvTimer);
++ Adapter->ReassocTimerIsSet = FALSE;
++ }
++#endif /* REASSOCIATION */
++
++ PRINTM(INFO, "\nwlanidle is on");
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Append a generic IE as a passthrough TLV to a TLV buffer.
++ *
++ * This function is called from the network join command prep. routine.
++ * If the IE buffer has been setup by the application, this routine appends
++ * the buffer as a passthrough TLV type to the request.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param ppBuffer pointer to command buffer pointer
++ *
++ * @return bytes added to the buffer
++ */
++static int
++wlan_cmd_append_generic_ie(wlan_private * priv, u8 ** ppBuffer)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int retLen = 0;
++ MrvlIEtypesHeader_t ieHeader;
++
++ /* Null Checks */
++ if (ppBuffer == 0)
++ return 0;
++ if (*ppBuffer == 0)
++ return 0;
++
++ /*
++ * If there is a generic ie buffer setup, append it to the return
++ * parameter buffer pointer.
++ */
++ if (Adapter->genIeBufferLen) {
++ PRINTM(INFO, "append generic %d to %p\n", Adapter->genIeBufferLen,
++ *ppBuffer);
++
++ /* Wrap the generic IE buffer with a passthrough TLV type */
++ ieHeader.Type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
++ ieHeader.Len = wlan_cpu_to_le16(Adapter->genIeBufferLen);
++ memcpy(*ppBuffer, &ieHeader, sizeof(ieHeader));
++
++ /* Increment the return size and the return buffer pointer param */
++ *ppBuffer += sizeof(ieHeader);
++ retLen += sizeof(ieHeader);
++
++ /* Copy the generic IE buffer to the output buffer, advance pointer */
++ memcpy(*ppBuffer, Adapter->genIeBuffer, Adapter->genIeBufferLen);
++
++ /* Increment the return size and the return buffer pointer param */
++ *ppBuffer += Adapter->genIeBufferLen;
++ retLen += Adapter->genIeBufferLen;
++
++ /* Reset the generic IE buffer */
++ Adapter->genIeBufferLen = 0;
++ }
++
++ /* return the length appended to the buffer */
++ return retLen;
++}
++
++/**
++ * @brief Append any application provided Marvell TLVs to a TLV buffer.
++ *
++ * This function is called from the network join command prep. routine.
++ * If the Marvell TLV buffer has been setup by the application, this routine
++ * appends the buffer to the request.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param ppBuffer pointer to command buffer pointer
++ *
++ * @return bytes added to the buffer
++ */
++static int
++wlan_cmd_append_marvell_tlv(wlan_private * priv, u8 ** ppBuffer)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int retLen = 0;
++
++ /* Null Checks */
++ if (ppBuffer == 0)
++ return 0;
++ if (*ppBuffer == 0)
++ return 0;
++
++ /*
++ * If there is a Marvell TLV buffer setup, append it to the return
++ * parameter buffer pointer.
++ */
++ if (Adapter->mrvlAssocTlvBufferLen) {
++ PRINTM(INFO, "append tlv %d to %p\n",
++ Adapter->mrvlAssocTlvBufferLen, *ppBuffer);
++
++ /* Copy the TLV buffer to the output buffer, advance pointer */
++ memcpy(*ppBuffer,
++ Adapter->mrvlAssocTlvBuffer, Adapter->mrvlAssocTlvBufferLen);
++
++ /* Increment the return size and the return buffer pointer param */
++ *ppBuffer += Adapter->mrvlAssocTlvBufferLen;
++ retLen += Adapter->mrvlAssocTlvBufferLen;
++
++ /* Reset the Marvell TLV buffer */
++ Adapter->mrvlAssocTlvBufferLen = 0;
++ }
++
++ /* return the length appended to the buffer */
++ return retLen;
++}
++
++/**
++ * @brief Append TSF tracking info from the scan table for the target AP
++ *
++ * This function is called from the network join command prep. routine.
++ * The TSF table TSF sent to the firmware contians two TSF values:
++ * - the TSF of the target AP from its previous beacon/probe response
++ * - the TSF timestamp of our local MAC at the time we observed the
++ * beacon/probe response.
++ *
++ * The firmware uses the timestamp values to set an initial TSF value
++ * in the MAC for the new association after a reassociation attempt.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param ppBuffer A pointer to command buffer pointer
++ * @param pBSSDesc A pointer to the BSS Descriptor from the scan table of
++ * the AP we are trying to join
++ *
++ * @return bytes added to the buffer
++ */
++static int
++wlan_cmd_append_tsf_tlv(wlan_private * priv, u8 ** ppBuffer,
++ BSSDescriptor_t * pBSSDesc)
++{
++ MrvlIEtypes_TsfTimestamp_t tsfTlv;
++ u64 tsfVal;
++
++ /* Null Checks */
++ if (ppBuffer == 0)
++ return 0;
++ if (*ppBuffer == 0)
++ return 0;
++
++ memset(&tsfTlv, 0x00, sizeof(MrvlIEtypes_TsfTimestamp_t));
++
++ tsfTlv.Header.Type = wlan_cpu_to_le16(TLV_TYPE_TSFTIMESTAMP);
++ tsfTlv.Header.Len = wlan_cpu_to_le16(2 * sizeof(tsfVal));
++
++ memcpy(*ppBuffer, &tsfTlv, sizeof(tsfTlv.Header));
++ *ppBuffer += sizeof(tsfTlv.Header);
++
++ /* TSF timestamp from the firmware TSF when the bcn/prb rsp was received */
++ tsfVal = wlan_cpu_to_le64(pBSSDesc->networkTSF);
++ memcpy(*ppBuffer, &tsfVal, sizeof(tsfVal));
++ *ppBuffer += sizeof(tsfVal);
++
++ memcpy(&tsfVal, pBSSDesc->TimeStamp, sizeof(tsfVal));
++
++ PRINTM(INFO, "ASSOC: TSF offset calc: %016llx - %016llx\n",
++ tsfVal, pBSSDesc->networkTSF);
++
++ tsfVal = wlan_cpu_to_le64(tsfVal);
++ memcpy(*ppBuffer, &tsfVal, sizeof(tsfVal));
++ *ppBuffer += sizeof(tsfVal);
++
++ return (sizeof(tsfTlv.Header) + (2 * sizeof(tsfVal)));
++}
++
++/**
++ * @brief This function prepares command of deauthenticate.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_cmd_802_11_deauthenticate(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ HostCmd_DS_802_11_DEAUTHENTICATE *dauth = &cmd->params.deauth;
++
++ ENTER();
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE);
++ cmd->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_DEAUTHENTICATE) + S_DS_GEN);
++
++ /* set AP MAC address */
++ memcpy(dauth->MacAddr,
++ &Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
++
++ /* Reason code 3 = Station is leaving */
++#define REASON_CODE_STA_LEAVING 3
++ dauth->ReasonCode = wlan_cpu_to_le16(REASON_CODE_STA_LEAVING);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of association.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param pdata_buf Void cast of BSSDescriptor_t from the scan table to assoc
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_cmd_802_11_associate(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *pdata_buf)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ HostCmd_DS_802_11_ASSOCIATE *pAsso = &cmd->params.associate;
++ int ret = WLAN_STATUS_SUCCESS;
++ BSSDescriptor_t *pBSSDesc;
++ WLAN_802_11_RATES rates;
++ int ratesSize;
++ u8 *pos;
++ u16 TmpCap;
++ MrvlIEtypes_SsIdParamSet_t *pSsidTlv;
++ MrvlIEtypes_PhyParamSet_t *pPhyTlv;
++ MrvlIEtypes_SsParamSet_t *pSsTlv;
++ MrvlIEtypes_RatesParamSet_t *pRatesTlv;
++ MrvlIEtypes_AuthType_t *pAuthTlv;
++ MrvlIEtypes_RsnParamSet_t *pRsnTlv;
++
++ ENTER();
++
++ pBSSDesc = (BSSDescriptor_t *) pdata_buf;
++ pos = (u8 *) pAsso;
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
++
++ /* Save so we know which BSS Desc to use in the response handler */
++ Adapter->pAttemptedBSSDesc = pBSSDesc;
++
++ memcpy(pAsso->PeerStaAddr,
++ pBSSDesc->MacAddress, sizeof(pAsso->PeerStaAddr));
++ pos += sizeof(pAsso->PeerStaAddr);
++
++ /* set the listen interval */
++ pAsso->ListenInterval = wlan_cpu_to_le16(Adapter->ListenInterval);
++
++ pos += sizeof(pAsso->CapInfo);
++ pos += sizeof(pAsso->ListenInterval);
++ pos += sizeof(pAsso->Reserved1);
++
++ pSsidTlv = (MrvlIEtypes_SsIdParamSet_t *) pos;
++ pSsidTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_SSID);
++ pSsidTlv->Header.Len = pBSSDesc->Ssid.SsidLength;
++ memcpy(pSsidTlv->SsId, pBSSDesc->Ssid.Ssid, pSsidTlv->Header.Len);
++ pos += sizeof(pSsidTlv->Header) + pSsidTlv->Header.Len;
++ pSsidTlv->Header.Len = wlan_cpu_to_le16(pSsidTlv->Header.Len);
++
++ pPhyTlv = (MrvlIEtypes_PhyParamSet_t *) pos;
++ pPhyTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_PHY_DS);
++ pPhyTlv->Header.Len = sizeof(pPhyTlv->fh_ds.DsParamSet);
++ memcpy(&pPhyTlv->fh_ds.DsParamSet,
++ &pBSSDesc->PhyParamSet.DsParamSet.CurrentChan,
++ sizeof(pPhyTlv->fh_ds.DsParamSet));
++ pos += sizeof(pPhyTlv->Header) + pPhyTlv->Header.Len;
++ pPhyTlv->Header.Len = wlan_cpu_to_le16(pPhyTlv->Header.Len);
++
++ pSsTlv = (MrvlIEtypes_SsParamSet_t *) pos;
++ pSsTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_CF);
++ pSsTlv->Header.Len = sizeof(pSsTlv->cf_ibss.CfParamSet);
++ pos += sizeof(pSsTlv->Header) + pSsTlv->Header.Len;
++ pSsTlv->Header.Len = wlan_cpu_to_le16(pSsTlv->Header.Len);
++
++ /* Get the common rates supported between the driver and the BSS Desc */
++ if (setup_rates_from_bssdesc(Adapter, pBSSDesc, rates, &ratesSize)) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ /* Setup the Rates TLV in the association command */
++ pRatesTlv = (MrvlIEtypes_RatesParamSet_t *) pos;
++ pRatesTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_RATES);
++ pRatesTlv->Header.Len = wlan_cpu_to_le16(ratesSize);
++ memcpy(pRatesTlv->Rates, rates, ratesSize);
++ pos += sizeof(pRatesTlv->Header) + ratesSize;
++ PRINTM(INFO, "ASSOC_CMD: Rates size = %d\n", ratesSize);
++
++ /* Add the Authentication type to be used for Auth frames if needed */
++ pAuthTlv = (MrvlIEtypes_AuthType_t *) pos;
++ pAuthTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_AUTH_TYPE);
++ pAuthTlv->Header.Len = sizeof(pAuthTlv->AuthType);
++ pAuthTlv->AuthType = Adapter->SecInfo.AuthenticationMode;
++ pos += sizeof(pAuthTlv->Header) + pAuthTlv->Header.Len;
++ pAuthTlv->Header.Len = wlan_cpu_to_le16(pAuthTlv->Header.Len);
++
++ if (!Adapter->wps.SessionEnable) {
++ if (Adapter->SecInfo.WPAEnabled || Adapter->SecInfo.WPA2Enabled) {
++ pRsnTlv = (MrvlIEtypes_RsnParamSet_t *) pos;
++ pRsnTlv->Header.Type = (u16) Adapter->Wpa_ie[0]; /* WPA_IE or WPA2_IE */
++ pRsnTlv->Header.Type = pRsnTlv->Header.Type & 0x00FF;
++ pRsnTlv->Header.Type = wlan_cpu_to_le16(pRsnTlv->Header.Type);
++ pRsnTlv->Header.Len = (u16) Adapter->Wpa_ie[1];
++ pRsnTlv->Header.Len = pRsnTlv->Header.Len & 0x00FF;
++ if (pRsnTlv->Header.Len <= (sizeof(Adapter->Wpa_ie) - 2)) {
++ memcpy(pRsnTlv->RsnIE, &Adapter->Wpa_ie[2],
++ pRsnTlv->Header.Len);
++ } else {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ HEXDUMP("ASSOC_CMD: RSN IE", (u8 *) pRsnTlv,
++ sizeof(pRsnTlv->Header) + pRsnTlv->Header.Len);
++ pos += sizeof(pRsnTlv->Header) + pRsnTlv->Header.Len;
++ pRsnTlv->Header.Len = wlan_cpu_to_le16(pRsnTlv->Header.Len);
++ }
++ }
++
++ wlan_wmm_process_association_req(priv, &pos, &pBSSDesc->wmmIE);
++
++ wlan_cmd_append_generic_ie(priv, &pos);
++
++ wlan_cmd_append_marvell_tlv(priv, &pos);
++
++ wlan_cmd_append_tsf_tlv(priv, &pos, pBSSDesc);
++
++ if (wlan_create_dnld_countryinfo_11d(priv, 0)) {
++ PRINTM(INFO, "Dnld_countryinfo_11d failed\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ if (wlan_parse_dnld_countryinfo_11d(priv)) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ cmd->Size = wlan_cpu_to_le16((u16) (pos - (u8 *) pAsso) + S_DS_GEN);
++
++ /* set the Capability info at last */
++ memcpy(&TmpCap, &pBSSDesc->Cap, sizeof(pAsso->CapInfo));
++ TmpCap &= CAPINFO_MASK;
++ PRINTM(INFO, "ASSOC_CMD: TmpCap=%4X CAPINFO_MASK=%4X\n",
++ TmpCap, CAPINFO_MASK);
++ TmpCap = wlan_cpu_to_le16(TmpCap);
++ memcpy(&pAsso->CapInfo, &TmpCap, sizeof(pAsso->CapInfo));
++
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function prepares command of ad_hoc_start.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param pssid A pointer to WLAN_802_11_SSID structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_cmd_802_11_ad_hoc_start(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *pssid)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ HostCmd_DS_802_11_AD_HOC_START *adhs = &cmd->params.ads;
++ int ret = WLAN_STATUS_SUCCESS;
++ int cmdAppendSize = 0;
++ int i;
++ u16 TmpCap;
++ BSSDescriptor_t *pBSSDesc;
++
++ ENTER();
++
++ if (!Adapter) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START);
++
++ pBSSDesc = &Adapter->CurBssParams.BSSDescriptor;
++ Adapter->pAttemptedBSSDesc = pBSSDesc;
++
++ /*
++ * Fill in the parameters for 2 data structures:
++ * 1. HostCmd_DS_802_11_AD_HOC_START Command
++ * 2. pBSSDesc
++ *
++ * Driver will fill up SSID, BSSType,IBSS param, Physical Param,
++ * probe delay, and Cap info.
++ *
++ * Firmware will fill up beacon period, Basic rates
++ * and operational rates.
++ */
++
++ memset(adhs->SSID, 0, MRVDRV_MAX_SSID_LENGTH);
++
++ memcpy(adhs->SSID, ((WLAN_802_11_SSID *) pssid)->Ssid,
++ ((WLAN_802_11_SSID *) pssid)->SsidLength);
++
++ PRINTM(INFO, "ADHOC_S_CMD: SSID = %s\n", adhs->SSID);
++
++ memset(pBSSDesc->Ssid.Ssid, 0, MRVDRV_MAX_SSID_LENGTH);
++ memcpy(pBSSDesc->Ssid.Ssid,
++ ((WLAN_802_11_SSID *) pssid)->Ssid,
++ ((WLAN_802_11_SSID *) pssid)->SsidLength);
++
++ pBSSDesc->Ssid.SsidLength = ((WLAN_802_11_SSID *) pssid)->SsidLength;
++
++ /* set the BSS type */
++ adhs->BSSType = HostCmd_BSS_TYPE_IBSS;
++ pBSSDesc->InfrastructureMode = Wlan802_11IBSS;
++ adhs->BeaconPeriod = wlan_cpu_to_le16(Adapter->BeaconPeriod);
++ pBSSDesc->BeaconPeriod = Adapter->BeaconPeriod;
++
++ /* set Physical param set */
++#define DS_PARA_IE_ID 3
++#define DS_PARA_IE_LEN 1
++
++ adhs->PhyParamSet.DsParamSet.ElementId = DS_PARA_IE_ID;
++ adhs->PhyParamSet.DsParamSet.Len = DS_PARA_IE_LEN;
++
++ if (!get_cfp_by_band_and_channel
++ (0, (u16) Adapter->AdhocChannel, Adapter->region_channel)) {
++ CHANNEL_FREQ_POWER *cfp;
++ cfp =
++ get_cfp_by_band_and_channel(0, FIRST_VALID_CHANNEL,
++ Adapter->region_channel);
++ if (cfp)
++ Adapter->AdhocChannel = cfp->Channel;
++ }
++
++ ASSERT(Adapter->AdhocChannel);
++
++ PRINTM(INFO, "ADHOC_S_CMD: Creating ADHOC on Channel %d\n",
++ Adapter->AdhocChannel);
++
++ Adapter->CurBssParams.BSSDescriptor.Channel = Adapter->AdhocChannel;
++
++ pBSSDesc->Channel = Adapter->AdhocChannel;
++ adhs->PhyParamSet.DsParamSet.CurrentChan = Adapter->AdhocChannel;
++
++ memcpy(&pBSSDesc->PhyParamSet,
++ &adhs->PhyParamSet, sizeof(IEEEtypes_PhyParamSet_t));
++
++ pBSSDesc->NetworkTypeInUse = Wlan802_11DS;
++
++ /* set IBSS param set */
++#define IBSS_PARA_IE_ID 6
++#define IBSS_PARA_IE_LEN 2
++
++ adhs->SsParamSet.IbssParamSet.ElementId = IBSS_PARA_IE_ID;
++ adhs->SsParamSet.IbssParamSet.Len = IBSS_PARA_IE_LEN;
++ adhs->SsParamSet.IbssParamSet.AtimWindow
++ = wlan_cpu_to_le16(Adapter->AtimWindow);
++ pBSSDesc->ATIMWindow = Adapter->AtimWindow;
++ memcpy(&pBSSDesc->SsParamSet,
++ &adhs->SsParamSet, sizeof(IEEEtypes_SsParamSet_t));
++
++ /* set Capability info */
++ adhs->Cap.Ess = 0;
++ adhs->Cap.Ibss = 1;
++ pBSSDesc->Cap.Ibss = 1;
++
++ /* set up privacy in pBSSDesc */
++ if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled
++ || Adapter->AdhocAESEnabled) {
++
++#define AD_HOC_CAP_PRIVACY_ON 1
++ PRINTM(INFO, "ADHOC_S_CMD: WEPStatus set, Privacy to WEP\n");
++ pBSSDesc->Privacy = Wlan802_11PrivFilter8021xWEP;
++ adhs->Cap.Privacy = AD_HOC_CAP_PRIVACY_ON;
++ } else {
++ PRINTM(INFO, "ADHOC_S_CMD: WEPStatus NOT set, Setting "
++ "Privacy to ACCEPT ALL\n");
++ pBSSDesc->Privacy = Wlan802_11PrivFilterAcceptAll;
++ }
++
++ memset(adhs->DataRate, 0, sizeof(adhs->DataRate));
++
++ if (Adapter->adhoc_grate_enabled == TRUE) {
++ memcpy(adhs->DataRate, AdhocRates_G,
++ MIN(sizeof(adhs->DataRate), sizeof(AdhocRates_G)));
++ if (Adapter->
++ CurrentPacketFilter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON) {
++ ret =
++ PrepareAndSendCommand(priv, HostCmd_CMD_MAC_CONTROL, 0,
++ HostCmd_OPTION_WAITFORRSP, 0,
++ &Adapter->CurrentPacketFilter);
++ if (ret) {
++ PRINTM(INFO, "ADHOC_S_CMD: G Protection config failed\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ }
++ } else {
++ memcpy(adhs->DataRate, AdhocRates_B,
++ MIN(sizeof(adhs->DataRate), sizeof(AdhocRates_B)));
++ }
++
++ /* Find the last non zero */
++ for (i = 0; i < sizeof(adhs->DataRate) && adhs->DataRate[i]; i++);
++
++ Adapter->CurBssParams.NumOfRates = i;
++
++ /* Copy the ad-hoc creating rates into Current BSS state structure */
++ memcpy(&Adapter->CurBssParams.DataRates,
++ &adhs->DataRate, Adapter->CurBssParams.NumOfRates);
++
++ PRINTM(INFO, "ADHOC_S_CMD: Rates=%02x %02x %02x %02x \n",
++ adhs->DataRate[0], adhs->DataRate[1],
++ adhs->DataRate[2], adhs->DataRate[3]);
++
++ PRINTM(INFO, "ADHOC_S_CMD: AD HOC Start command is ready\n");
++
++ if (wlan_create_dnld_countryinfo_11d(priv, Adapter->CurBssParams.band)) {
++ PRINTM(INFO, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_AD_HOC_START)
++ + S_DS_GEN + cmdAppendSize);
++
++ memcpy(&TmpCap, &adhs->Cap, sizeof(u16));
++ TmpCap = wlan_cpu_to_le16(TmpCap);
++ memcpy(&adhs->Cap, &TmpCap, sizeof(u16));
++
++ ret = WLAN_STATUS_SUCCESS;
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function prepares command of ad_hoc_stop.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_cmd_802_11_ad_hoc_stop(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
++{
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
++ cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_AD_HOC_STOP)
++ + S_DS_GEN);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of ad_hoc_join.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param pdata_buf Void cast of BSSDescriptor_t from the scan table to join
++ *
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_cmd_802_11_ad_hoc_join(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *pdata_buf)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ HostCmd_DS_802_11_AD_HOC_JOIN *pAdHocJoin = &cmd->params.adj;
++ BSSDescriptor_t *pBSSDesc = (BSSDescriptor_t *) pdata_buf;
++ int cmdAppendSize = 0;
++ int ret = WLAN_STATUS_SUCCESS;
++ WLAN_802_11_RATES rates;
++ int ratesSize;
++ u16 TmpCap;
++ u16 CurrentPacketFilter;
++
++ ENTER();
++
++#define USE_G_PROTECTION 0x02
++ if (pBSSDesc->ERPFlags & USE_G_PROTECTION) {
++ CurrentPacketFilter =
++ Adapter->
++ CurrentPacketFilter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
++ ret =
++ PrepareAndSendCommand(priv, HostCmd_CMD_MAC_CONTROL, 0,
++ HostCmd_OPTION_WAITFORRSP, 0,
++ &CurrentPacketFilter);
++ if (ret) {
++ PRINTM(INFO, "ADHOC_S_CMD: G Protection config failed\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ }
++ Adapter->pAttemptedBSSDesc = pBSSDesc;
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN);
++
++ pAdHocJoin->BssDescriptor.BSSType = HostCmd_BSS_TYPE_IBSS;
++
++ pAdHocJoin->BssDescriptor.BeaconPeriod
++ = wlan_cpu_to_le16(pBSSDesc->BeaconPeriod);
++
++ memcpy(&pAdHocJoin->BssDescriptor.BSSID,
++ &pBSSDesc->MacAddress, MRVDRV_ETH_ADDR_LEN);
++
++ memcpy(&pAdHocJoin->BssDescriptor.SSID,
++ &pBSSDesc->Ssid.Ssid, pBSSDesc->Ssid.SsidLength);
++
++ memcpy(&pAdHocJoin->BssDescriptor.PhyParamSet,
++ &pBSSDesc->PhyParamSet, sizeof(IEEEtypes_PhyParamSet_t));
++
++ memcpy(&pAdHocJoin->BssDescriptor.SsParamSet,
++ &pBSSDesc->SsParamSet, sizeof(IEEEtypes_SsParamSet_t));
++
++ memcpy(&TmpCap, &pBSSDesc->Cap, sizeof(IEEEtypes_CapInfo_t));
++
++ TmpCap &= CAPINFO_MASK;
++
++ PRINTM(INFO, "ADHOC_J_CMD: TmpCap=%4X CAPINFO_MASK=%4X\n",
++ TmpCap, CAPINFO_MASK);
++ memcpy(&pAdHocJoin->BssDescriptor.Cap, &TmpCap,
++ sizeof(IEEEtypes_CapInfo_t));
++
++ /* information on BSSID descriptor passed to FW */
++ PRINTM(INFO,
++ "ADHOC_J_CMD: BSSID = %02x-%02x-%02x-%02x-%02x-%02x, SSID = %s\n",
++ pAdHocJoin->BssDescriptor.BSSID[0],
++ pAdHocJoin->BssDescriptor.BSSID[1],
++ pAdHocJoin->BssDescriptor.BSSID[2],
++ pAdHocJoin->BssDescriptor.BSSID[3],
++ pAdHocJoin->BssDescriptor.BSSID[4],
++ pAdHocJoin->BssDescriptor.BSSID[5],
++ pAdHocJoin->BssDescriptor.SSID);
++
++ /* Get the common rates supported between the driver and the BSS Desc */
++ if (setup_rates_from_bssdesc(Adapter, pBSSDesc, rates, &ratesSize)) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ /* Copy Data Rates from the Rates recorded in scan response */
++ memset(pAdHocJoin->BssDescriptor.DataRates, 0,
++ sizeof(pAdHocJoin->BssDescriptor.DataRates));
++ memcpy(pAdHocJoin->BssDescriptor.DataRates, rates, ratesSize);
++
++ /* Copy the adhoc join rates into Current BSS state structure */
++ Adapter->CurBssParams.NumOfRates = ratesSize;
++ memcpy(&Adapter->CurBssParams.DataRates, rates, ratesSize);
++
++ /* Copy the channel information */
++ Adapter->CurBssParams.BSSDescriptor.Channel = pBSSDesc->Channel;
++
++ if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled
++ || Adapter->AdhocAESEnabled) {
++ pAdHocJoin->BssDescriptor.Cap.Privacy = AD_HOC_CAP_PRIVACY_ON;
++ }
++
++ if (Adapter->PSMode == Wlan802_11PowerModeMAX_PSP) {
++ /* wake up first */
++ WLAN_802_11_POWER_MODE LocalPSMode;
++
++ LocalPSMode = Wlan802_11PowerModeCAM;
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_PS_MODE,
++ HostCmd_ACT_GEN_SET, 0, 0, &LocalPSMode);
++
++ if (ret) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ }
++
++ if (wlan_create_dnld_countryinfo_11d(priv, 0)) {
++ PRINTM(INFO, "Dnld_countryinfo_11d failed\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ if (wlan_parse_dnld_countryinfo_11d(priv)) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_AD_HOC_JOIN)
++ + S_DS_GEN + cmdAppendSize);
++
++ memcpy(&TmpCap, &pAdHocJoin->BssDescriptor.Cap,
++ sizeof(IEEEtypes_CapInfo_t));
++ TmpCap = wlan_cpu_to_le16(TmpCap);
++
++ memcpy(&pAdHocJoin->BssDescriptor.Cap,
++ &TmpCap, sizeof(IEEEtypes_CapInfo_t));
++
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Association firmware command response handler
++ *
++ * The response buffer for the association command has the following
++ * memory layout.
++ *
++ * For cases where an association response was not received (indicated
++ * by the CapInfo and AId field):
++ *
++ * .------------------------------------------------------------.
++ * | Header(4 * sizeof(u16)): Standard command response hdr |
++ * .------------------------------------------------------------.
++ * | CapInfo/Error Return(u16): |
++ * | 0xFFFF(-1): Internal error |
++ * | 0xFFFE(-2): Authentication unhandled message |
++ * | 0xFFFD(-3): Authentication refused |
++ * | 0xFFFC(-4): Timeout waiting for AP response |
++ * .------------------------------------------------------------.
++ * | StatusCode(u16): |
++ * | If CapInfo is -1: |
++ * | An internal firmware failure prevented the |
++ * | command from being processed. The StatusCode |
++ * | will be set to 1. |
++ * | |
++ * | If CapInfo is -2: |
++ * | An authentication frame was received but was |
++ * | not handled by the firmware. IEEE Status |
++ * | code for the failure is returned. |
++ * | |
++ * | If CapInfo is -3: |
++ * | An authentication frame was received and the |
++ * | StatusCode is the IEEE Status reported in the |
++ * | response. |
++ * | |
++ * | If CapInfo is -4: |
++ * | (1) Association response timeout |
++ * | (2) Authentication response timeout |
++ * .------------------------------------------------------------.
++ * | AId(u16): 0xFFFF |
++ * .------------------------------------------------------------.
++ *
++ *
++ * For cases where an association response was received, the IEEE
++ * standard association response frame is returned:
++ *
++ * .------------------------------------------------------------.
++ * | Header(4 * sizeof(u16)): Standard command response hdr |
++ * .------------------------------------------------------------.
++ * | CapInfo(u16): IEEE Capability |
++ * .------------------------------------------------------------.
++ * | StatusCode(u16): IEEE Status Code |
++ * .------------------------------------------------------------.
++ * | AId(u16): IEEE Association ID |
++ * .------------------------------------------------------------.
++ * | IEEE IEs(variable): Any received IEs comprising the |
++ * | remaining portion of a received |
++ * | association response frame. |
++ * .------------------------------------------------------------.
++ *
++ * For simplistic handling, the StatusCode field can be used to determine
++ * an association success (0) or failure (non-zero).
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_ret_802_11_associate(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++ IEEEtypes_AssocRsp_t *pAssocRsp;
++ BSSDescriptor_t *pBSSDesc;
++ WLAN_802_11_RATES rates;
++ int ratesSize;
++
++ ENTER();
++
++ pAssocRsp = (IEEEtypes_AssocRsp_t *) & resp->params;
++
++ HEXDUMP("ASSOC_RESP:", (void *) &resp->params,
++ wlan_le16_to_cpu(resp->Size) - S_DS_GEN);
++
++ Adapter->assocRspSize = MIN(wlan_le16_to_cpu(resp->Size) - S_DS_GEN,
++ sizeof(Adapter->assocRspBuffer));
++
++ memcpy(Adapter->assocRspBuffer, &resp->params, Adapter->assocRspSize);
++
++ if (pAssocRsp->StatusCode) {
++ priv->adapter->dbg.num_cmd_assoc_failure++;
++
++ PRINTM(CMND, "ASSOC_RESP: Association Failed, "
++ "status code = %d, error = %d\n",
++ pAssocRsp->StatusCode, *(short *) &pAssocRsp->Capability);
++ ret = WLAN_STATUS_FAILURE;
++
++ goto done;
++ }
++
++ /* Send a Media Connected event, according to the Spec */
++ Adapter->MediaConnectStatus = WlanMediaStateConnected;
++
++ /* Set the attempted BSSID Index to current */
++ pBSSDesc = Adapter->pAttemptedBSSDesc;
++
++ PRINTM(INFO, "ASSOC_RESP: %s\n", pBSSDesc->Ssid.Ssid);
++
++ /* Make a copy of current BSSID descriptor */
++ memcpy(&Adapter->CurBssParams.BSSDescriptor,
++ pBSSDesc, sizeof(BSSDescriptor_t));
++
++ /* update CurBssParams */
++ Adapter->CurBssParams.BSSDescriptor.Channel
++ = pBSSDesc->PhyParamSet.DsParamSet.CurrentChan;
++
++ if (setup_rates_from_bssdesc(Adapter, pBSSDesc, rates, &ratesSize)) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ /* Copy the infra. association rates into Current BSS state structure */
++ Adapter->CurBssParams.NumOfRates = ratesSize;
++ memcpy(&Adapter->CurBssParams.DataRates, rates, ratesSize);
++
++ /* Adjust the timestamps in the scan table to be relative to the newly
++ * associated AP's TSF
++ */
++ wlan_scan_update_tsf_timestamps(priv, pBSSDesc);
++
++ if (pBSSDesc->wmmIE.VendHdr.ElementId == WMM_IE) {
++ Adapter->CurBssParams.wmm_enabled = TRUE;
++ } else {
++ Adapter->CurBssParams.wmm_enabled = FALSE;
++ }
++
++ if (Adapter->wmm.required && Adapter->CurBssParams.wmm_enabled) {
++ Adapter->wmm.enabled = TRUE;
++ } else {
++ Adapter->wmm.enabled = FALSE;
++ }
++
++ Adapter->CurBssParams.wmm_uapsd_enabled = FALSE;
++
++ if (Adapter->wmm.enabled == TRUE) {
++ Adapter->CurBssParams.wmm_uapsd_enabled
++ = pBSSDesc->wmmIE.QoSInfo.QosUAPSD;
++ }
++
++ PRINTM(INFO, "ASSOC_RESP: CurrentPacketFilter is %x\n",
++ Adapter->CurrentPacketFilter);
++
++ if (Adapter->SecInfo.WPAEnabled || Adapter->SecInfo.WPA2Enabled)
++ Adapter->IsGTK_SET = FALSE;
++
++ Adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0;
++ Adapter->NF[TYPE_RXPD][TYPE_AVG] = 0;
++
++ memset(Adapter->rawSNR, 0x00, sizeof(Adapter->rawSNR));
++ memset(Adapter->rawNF, 0x00, sizeof(Adapter->rawNF));
++ Adapter->nextSNRNF = 0;
++ Adapter->numSNRNF = 0;
++
++ priv->adapter->dbg.num_cmd_assoc_success++;
++
++ PRINTM(INFO, "ASSOC_RESP: Associated \n");
++
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function handles the command response of disassociate
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_ret_802_11_disassociate(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ ENTER();
++
++ priv->adapter->dbg.num_cmd_deauth++;
++ MacEventDisconnected(priv);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the command response of ad_hoc_start and
++ * ad_hoc_join
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_ret_802_11_ad_hoc(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++ u16 Command = resp->Command;
++ u16 Result = resp->Result;
++ HostCmd_DS_802_11_AD_HOC_RESULT *pAdHocResult;
++ union iwreq_data wrqu;
++ BSSDescriptor_t *pBSSDesc;
++
++ ENTER();
++
++ pAdHocResult = &resp->params.result;
++
++ pBSSDesc = Adapter->pAttemptedBSSDesc;
++
++ /*
++ * Join result code 0 --> SUCCESS
++ */
++ if (Result) {
++ PRINTM(INFO, "ADHOC_RESP Failed\n");
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ MacEventDisconnected(priv);
++ }
++
++ memset(&Adapter->CurBssParams.BSSDescriptor,
++ 0x00, sizeof(Adapter->CurBssParams.BSSDescriptor));
++
++ LEAVE();
++ return WLAN_STATUS_FAILURE;
++ }
++
++ /* Send a Media Connected event, according to the Spec */
++ Adapter->MediaConnectStatus = WlanMediaStateConnected;
++
++ if (Command == HostCmd_RET_802_11_AD_HOC_START) {
++ PRINTM(INFO, "ADHOC_S_RESP %s\n", pBSSDesc->Ssid.Ssid);
++
++ /* Update the created network descriptor with the new BSSID */
++ memcpy(pBSSDesc->MacAddress,
++ pAdHocResult->BSSID, MRVDRV_ETH_ADDR_LEN);
++ } else {
++ /*
++ * Now the join cmd should be successful
++ * If BSSID has changed use SSID to compare instead of BSSID
++ */
++ PRINTM(INFO, "ADHOC_J_RESP %s\n", pBSSDesc->Ssid.Ssid);
++
++ /* Make a copy of current BSSID descriptor, only needed for join since
++ * the current descriptor is already being used for adhoc start
++ */
++ memcpy(&Adapter->CurBssParams.BSSDescriptor,
++ pBSSDesc, sizeof(BSSDescriptor_t));
++ }
++
++ memset(&wrqu, 0, sizeof(wrqu));
++ memcpy(wrqu.ap_addr.sa_data,
++ &Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
++ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
++ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
++
++ PRINTM(INFO, "ADHOC_RESP: Channel = %d\n", Adapter->AdhocChannel);
++ PRINTM(INFO, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
++ Adapter->CurBssParams.BSSDescriptor.MacAddress[0],
++ Adapter->CurBssParams.BSSDescriptor.MacAddress[1],
++ Adapter->CurBssParams.BSSDescriptor.MacAddress[2],
++ Adapter->CurBssParams.BSSDescriptor.MacAddress[3],
++ Adapter->CurBssParams.BSSDescriptor.MacAddress[4],
++ Adapter->CurBssParams.BSSDescriptor.MacAddress[5]);
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function handles the command response of ad_hoc_stop
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_ret_802_11_ad_hoc_stop(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ ENTER();
++
++ MacEventDisconnected(priv);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++#ifdef REASSOCIATION
++/**
++ * @brief This function handles re-association. it is triggered
++ * by re-assoc timer.
++ *
++ * @param data A pointer to wlan_thread structure
++ * @return WLAN_STATUS_SUCCESS
++ */
++int
++wlan_reassociation_thread(void *data)
++{
++ wlan_thread *thread = data;
++ wlan_private *priv = thread->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ wait_queue_t wait;
++ int i;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ OS_INTERRUPT_SAVE_AREA;
++
++ ENTER();
++
++ wlan_activate_thread(thread);
++ init_waitqueue_entry(&wait, current);
++
++ current->flags |= PF_NOFREEZE;
++
++ for (;;) {
++ add_wait_queue(&thread->waitQ, &wait);
++ OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE);
++
++ PRINTM(INFO, "Reassoc: Thread sleeping...\n");
++
++ schedule();
++
++ OS_SET_THREAD_STATE(TASK_RUNNING);
++ remove_wait_queue(&thread->waitQ, &wait);
++
++ if (Adapter->SurpriseRemoved) {
++ break;
++ }
++
++ if (kthread_should_stop()) {
++ break;
++ }
++
++ PRINTM(INFO, "Reassoc: Thread waking up...\n");
++
++ if (Adapter->InfrastructureMode != Wlan802_11Infrastructure ||
++ Adapter->HardwareStatus != WlanHardwareStatusReady) {
++ PRINTM(MSG, "Reassoc: mode or hardware status is not correct\n");
++ continue;
++ }
++
++ /* The semaphore is used to avoid reassociation thread and
++ wlan_set_scan/wlan_set_essid interrupting each other.
++ Reassociation should be disabled completely by application if
++ wlan_set_user_scan_ioctl/wlan_set_wap is used.
++ */
++ if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
++ PRINTM(ERROR, "Acquire semaphore error, reassociation thread\n");
++ goto settimer;
++ }
++
++ if (Adapter->MediaConnectStatus != WlanMediaStateDisconnected) {
++ OS_REL_SEMAPHORE(&Adapter->ReassocSem);
++ PRINTM(MSG, "Reassoc: Adapter->MediaConnectStatus is wrong\n");
++ continue;
++ }
++
++ PRINTM(INFO, "Reassoc: Required ESSID: %s\n",
++ Adapter->PreviousSSID.Ssid);
++
++ PRINTM(INFO, "Reassoc: Performing Active Scan @ %lu\n",
++ os_time_get());
++ SendSpecificSSIDScan(priv, &Adapter->PreviousSSID);
++
++ i = FindSSIDInList(Adapter,
++ &Adapter->PreviousSSID,
++ Adapter->PreviousBSSID,
++ Adapter->InfrastructureMode);
++
++ if (i < 0) {
++ /* If the SSID could not be found, try just the SSID */
++ i = FindSSIDInList(Adapter,
++ &Adapter->PreviousSSID,
++ NULL, Adapter->InfrastructureMode);
++ }
++
++ if (i >= 0) {
++ if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled) {
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_SET_WEP,
++ 0, HostCmd_OPTION_WAITFORRSP,
++ OID_802_11_ADD_WEP, NULL);
++ if (ret)
++ PRINTM(INFO, "Ressoc: Fail to set WEP KEY\n");
++ }
++ wlan_associate(priv, &Adapter->ScanTable[i]);
++ }
++
++ OS_REL_SEMAPHORE(&Adapter->ReassocSem);
++
++ settimer:
++ if (Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
++ PRINTM(INFO, "Reassoc: No AP found or assoc failed."
++ "Restarting re-assoc Timer @ %lu\n", os_time_get());
++
++ Adapter->ReassocTimerIsSet = TRUE;
++ ModTimer(&Adapter->MrvDrvTimer, MRVDRV_TIMER_10S);
++ }
++ }
++
++ wlan_deactivate_thread(thread);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function triggers re-association by waking up
++ * re-assoc thread.
++ *
++ * @param FunctionContext A pointer to FunctionContext
++ * @return n/a
++ */
++void
++MrvDrvReassocTimerFunction(void *FunctionContext)
++{
++ wlan_private *priv = (wlan_private *) FunctionContext;
++ wlan_adapter *Adapter = priv->adapter;
++ OS_INTERRUPT_SAVE_AREA;
++
++ ENTER();
++
++ PRINTM(INFO, "MrvDrvReassocTimer fired.\n");
++ Adapter->ReassocTimerIsSet = FALSE;
++ if (Adapter->PSState != PS_STATE_FULL_POWER) {
++ /* wait until Exit_PS command returns */
++ Adapter->ReassocTimerIsSet = TRUE;
++ ModTimer(&Adapter->MrvDrvTimer, MRVDRV_TIMER_1S);
++ PRINTM(INFO, "MrvDrvTimerFunction(PSState=%d) waiting"
++ "for Exit_PS done\n", Adapter->PSState);
++ LEAVE();
++ return;
++ }
++
++ PRINTM(INFO, "Waking Up the Reassoc Thread\n");
++
++ wake_up_interruptible(&priv->ReassocThread.waitQ);
++
++ LEAVE();
++ return;
++}
++#endif /* REASSOCIATION */
++
++int
++sendADHOCBSSIDQuery(wlan_private * priv)
++{
++ return PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
++ HostCmd_ACT_GET, 0, 0, NULL);
++}
+diff --git a/drivers/net/wireless/marvell8686/wlan_join.h b/drivers/net/wireless/marvell8686/wlan_join.h
+new file mode 100644
+index 0000000..ffb944e
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_join.h
+@@ -0,0 +1,84 @@
++/** @file wlan_join.h
++ *
++ * @brief Interface for the wlan infrastructure and adhoc join routines
++ *
++ * Driver interface functions and type declarations for the join module
++ * implemented in wlan_join.c. Process all start/join requests for
++ * both adhoc and infrastructure networks
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ *
++ * @sa wlan_join.c
++ */
++/*************************************************************
++Change Log:
++ 01/11/06: Initial revision. Match new scan code, relocate related functions
++
++************************************************************/
++
++#ifndef _WLAN_JOIN_H
++#define _WLAN_JOIN_H
++
++//! Size of buffer allocated to store the association response from firmware
++#define MRVDRV_ASSOC_RSP_BUF_SIZE 500
++
++//! Size of buffer allocated to store IEs passed to firmware in the assoc req
++#define MRVDRV_GENIE_BUF_SIZE 256
++
++//! Size of buffer allocated to store TLVs passed to firmware in the assoc req
++#define MRVDRV_ASSOC_TLV_BUF_SIZE 256
++
++extern int wlan_cmd_802_11_authenticate(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ void *pdata_buf);
++extern int wlan_cmd_802_11_ad_hoc_join(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ void *pdata_buf);
++extern int wlan_cmd_802_11_ad_hoc_stop(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd);
++extern int wlan_cmd_802_11_ad_hoc_start(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ void *pssid);
++extern int wlan_cmd_802_11_deauthenticate(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd);
++extern int wlan_cmd_802_11_associate(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ void *pdata_buf);
++extern int wlan_ret_802_11_authenticate(wlan_private * priv,
++ HostCmd_DS_COMMAND * resp);
++extern int wlan_ret_802_11_ad_hoc(wlan_private * priv,
++ HostCmd_DS_COMMAND * resp);
++extern int wlan_ret_802_11_ad_hoc_stop(wlan_private * priv,
++ HostCmd_DS_COMMAND * resp);
++extern int wlan_ret_802_11_disassociate(wlan_private * priv,
++ HostCmd_DS_COMMAND * resp);
++extern int wlan_ret_802_11_associate(wlan_private * priv,
++ HostCmd_DS_COMMAND * resp);
++
++extern int wlan_associate(wlan_private * priv, BSSDescriptor_t * pBSSDesc);
++extern int wlan_associate_to_table_idx(wlan_private * priv, int tableIdx);
++
++extern int wlanidle_on(wlan_private * priv);
++extern int wlanidle_off(wlan_private * priv);
++
++extern int wlan_do_adhocstop_ioctl(wlan_private * priv);
++extern int wlan_reassociation_thread(void *data);
++
++extern int StartAdhocNetwork(wlan_private * priv,
++ WLAN_802_11_SSID * AdhocSSID);
++extern int JoinAdhocNetwork(wlan_private * priv, BSSDescriptor_t * pBSSDesc);
++extern int StopAdhocNetwork(wlan_private * priv);
++extern int SendDeauthentication(wlan_private * priv);
++
++extern int wlan_do_adhocstop_ioctl(wlan_private * priv);
++extern int wlan_get_assoc_rsp_ioctl(wlan_private * priv, struct iwreq *wrq);
++extern int wlan_set_mrvl_tlv_ioctl(wlan_private * priv, struct iwreq *wrq);
++
++#ifdef __KERNEL__
++extern int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
++ struct sockaddr *awrq, char *extra);
++#endif
++
++extern int sendADHOCBSSIDQuery(wlan_private * priv);
++
++#endif
+diff --git a/drivers/net/wireless/marvell8686/wlan_main.c b/drivers/net/wireless/marvell8686/wlan_main.c
+new file mode 100644
+index 0000000..653c9f5
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_main.c
+@@ -0,0 +1,1362 @@
++/** @file wlan_main.c
++ *
++ * @brief This file contains the major functions in WLAN
++ * driver. It includes init, exit, open, close and main
++ * thread etc..
++ *
++ */
++/**
++ * @mainpage M-WLAN Linux Driver
++ *
++ * @section overview_sec Overview
++ *
++ * The M-WLAN is a Linux reference driver for Marvell
++ * 802.11 (a/b/g) WLAN chipset.
++ *
++ * @section copyright_sec Copyright
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ *
++ */
++/********************************************************
++Change log:
++ 09/30/05: Add Doxygen format comments
++ 12/09/05: Add TX_QUEUE support
++ 01/05/06: Add kernel 2.6.x support
++ 01/11/06: Conditionalize new scan/join functions.
++ 01/12/06: Add TxLockFlag for UAPSD power save mode
++ and Proprietary Periodic sleep support
++********************************************************/
++
++#include "include.h"
++
++/********************************************************
++ Local Variables
++********************************************************/
++
++#ifdef ENABLE_PM
++#define WLAN_PM_DRV_NAME "wlan_pm_drv"
++
++static int wlan_pm_suspend(struct device *pmdev, u32 state, u32 level);
++static int wlan_pm_resume(struct device *pmdev, u32 level);
++static void wlan_pm_release(struct device *pmdev);
++
++/*!
++ * This structure contains pointers to the power management callback functions.
++ */
++static struct device_driver wlan_pm_driver = {
++ .name = WLAN_PM_DRV_NAME,
++ .bus = &platform_bus_type,
++ .suspend = wlan_pm_suspend,
++ .resume = wlan_pm_resume,
++};
++
++/*! Device Definition for WLAN */
++static struct platform_device wlan_pm_platform_device = {
++ .name = WLAN_PM_DRV_NAME,
++ .id = 0,
++ .dev.release = wlan_pm_release,
++};
++#endif
++
++spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;
++ulong driver_flags;
++
++#define WLAN_TX_PWR_DEFAULT 20 /*100mW */
++#define WLAN_TX_PWR_US_DEFAULT 20 /*100mW */
++#define WLAN_TX_PWR_JP_DEFAULT 16 /*50mW */
++#define WLAN_TX_PWR_FR_100MW 20 /*100mW */
++#define WLAN_TX_PWR_FR_10MW 10 /*10mW */
++#define WLAN_TX_PWR_EMEA_DEFAULT 20 /*100mW */
++
++/* Format { Channel, Frequency (MHz), MaxTxPower } */
++/* Band: 'B/G', Region: USA FCC/Canada IC */
++static CHANNEL_FREQ_POWER channel_freq_power_US_BG[] = {
++ {1, 2412, WLAN_TX_PWR_US_DEFAULT},
++ {2, 2417, WLAN_TX_PWR_US_DEFAULT},
++ {3, 2422, WLAN_TX_PWR_US_DEFAULT},
++ {4, 2427, WLAN_TX_PWR_US_DEFAULT},
++ {5, 2432, WLAN_TX_PWR_US_DEFAULT},
++ {6, 2437, WLAN_TX_PWR_US_DEFAULT},
++ {7, 2442, WLAN_TX_PWR_US_DEFAULT},
++ {8, 2447, WLAN_TX_PWR_US_DEFAULT},
++ {9, 2452, WLAN_TX_PWR_US_DEFAULT},
++ {10, 2457, WLAN_TX_PWR_US_DEFAULT},
++ {11, 2462, WLAN_TX_PWR_US_DEFAULT}
++};
++
++/* Band: 'B/G', Region: Europe ETSI */
++static CHANNEL_FREQ_POWER channel_freq_power_EU_BG[] = {
++ {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT},
++ {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT},
++ {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT},
++ {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT},
++ {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT},
++ {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT},
++ {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT},
++ {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT},
++ {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT},
++ {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT},
++ {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT},
++ {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT},
++ {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT}
++};
++
++/* Band: 'B/G', Region: France */
++static CHANNEL_FREQ_POWER channel_freq_power_FR_BG[] = {
++ {1, 2412, WLAN_TX_PWR_FR_100MW},
++ {2, 2417, WLAN_TX_PWR_FR_100MW},
++ {3, 2422, WLAN_TX_PWR_FR_100MW},
++ {4, 2427, WLAN_TX_PWR_FR_100MW},
++ {5, 2432, WLAN_TX_PWR_FR_100MW},
++ {6, 2437, WLAN_TX_PWR_FR_100MW},
++ {7, 2442, WLAN_TX_PWR_FR_100MW},
++ {8, 2447, WLAN_TX_PWR_FR_100MW},
++ {9, 2452, WLAN_TX_PWR_FR_100MW},
++ {10, 2457, WLAN_TX_PWR_FR_10MW},
++ {11, 2462, WLAN_TX_PWR_FR_10MW},
++ {12, 2467, WLAN_TX_PWR_FR_10MW},
++ {13, 2472, WLAN_TX_PWR_FR_10MW}
++};
++
++/* Band: 'B/G', Region: Japan */
++static CHANNEL_FREQ_POWER channel_freq_power_JPN41_BG[] = {
++ {1, 2412, WLAN_TX_PWR_JP_DEFAULT},
++ {2, 2417, WLAN_TX_PWR_JP_DEFAULT},
++ {3, 2422, WLAN_TX_PWR_JP_DEFAULT},
++ {4, 2427, WLAN_TX_PWR_JP_DEFAULT},
++ {5, 2432, WLAN_TX_PWR_JP_DEFAULT},
++ {6, 2437, WLAN_TX_PWR_JP_DEFAULT},
++ {7, 2442, WLAN_TX_PWR_JP_DEFAULT},
++ {8, 2447, WLAN_TX_PWR_JP_DEFAULT},
++ {9, 2452, WLAN_TX_PWR_JP_DEFAULT},
++ {10, 2457, WLAN_TX_PWR_JP_DEFAULT},
++ {11, 2462, WLAN_TX_PWR_JP_DEFAULT},
++ {12, 2467, WLAN_TX_PWR_JP_DEFAULT},
++ {13, 2472, WLAN_TX_PWR_JP_DEFAULT}
++};
++
++/* Band: 'B/G', Region: Japan */
++static CHANNEL_FREQ_POWER channel_freq_power_JPN40_BG[] = {
++ {14, 2484, WLAN_TX_PWR_JP_DEFAULT}
++};
++
++/********************************************************
++ Global Variables
++********************************************************/
++
++/**
++ * the structure for channel, frequency and power
++ */
++typedef struct _region_cfp_table
++{
++ u8 region;
++ CHANNEL_FREQ_POWER *cfp_BG;
++ int cfp_no_BG;
++} region_cfp_table_t;
++
++/**
++ * the structure for the mapping between region and CFP
++ */
++region_cfp_table_t region_cfp_table[] = {
++ {0x10, /*US FCC */
++ channel_freq_power_US_BG,
++ sizeof(channel_freq_power_US_BG) / sizeof(CHANNEL_FREQ_POWER),
++ }
++ ,
++ {0x20, /*CANADA IC */
++ channel_freq_power_US_BG,
++ sizeof(channel_freq_power_US_BG) / sizeof(CHANNEL_FREQ_POWER),
++ }
++ ,
++ {0x30, /*EU*/ channel_freq_power_EU_BG,
++ sizeof(channel_freq_power_EU_BG) / sizeof(CHANNEL_FREQ_POWER),
++ }
++ ,
++ {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
++ sizeof(channel_freq_power_FR_BG) / sizeof(CHANNEL_FREQ_POWER),
++ }
++ ,
++ {0x40, /*JAPAN*/ channel_freq_power_JPN40_BG,
++ sizeof(channel_freq_power_JPN40_BG) / sizeof(CHANNEL_FREQ_POWER),
++ }
++ ,
++ {0x41, /*JAPAN*/ channel_freq_power_JPN41_BG,
++ sizeof(channel_freq_power_JPN41_BG) / sizeof(CHANNEL_FREQ_POWER),
++ }
++ ,
++/*Add new region here */
++};
++
++/**
++ * the rates supported by the card
++ */
++u8 WlanDataRates[WLAN_SUPPORTED_RATES] =
++ { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
++ 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
++};
++
++/**
++ * the rates supported
++ */
++u8 SupportedRates[G_SUPPORTED_RATES] =
++ { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48,
++ 0x60, 0x6c, 0
++};
++
++/**
++ * the rates supported for ad-hoc G mode
++ */
++u8 AdhocRates_G[G_SUPPORTED_RATES] =
++ { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
++0 };
++
++/**
++ * the rates supported for ad-hoc B mode
++ */
++u8 AdhocRates_B[4] = { 0x82, 0x84, 0x8b, 0x96 };
++
++/**
++ * the global variable of a pointer to wlan_private
++ * structure variable
++ */
++wlan_private *wlanpriv = NULL;
++
++u32 DSFreqList[15] = {
++ 0, 2412000, 2417000, 2422000, 2427000, 2432000, 2437000, 2442000,
++ 2447000, 2452000, 2457000, 2462000, 2467000, 2472000, 2484000
++};
++
++/**
++ * the table to keep region code
++ */
++u16 RegionCodeToIndex[MRVDRV_MAX_REGION_CODE] =
++ { 0x10, 0x20, 0x30, 0x32, 0x40, 0x41 };
++
++/********************************************************
++ Local Functions
++********************************************************/
++
++/**
++ * @brief This function opens the network device
++ *
++ * @param dev A pointer to net_device structure
++ * @return WLAN_STATUS_SUCCESS
++ */
++static int
++wlan_open(struct net_device *dev)
++{
++ wlan_private *priv = (wlan_private *) dev->priv;
++ wlan_adapter *adapter = priv->adapter;
++
++ ENTER();
++
++ MODULE_GET;
++
++ priv->open = TRUE;
++
++ if ((adapter->MediaConnectStatus == WlanMediaStateConnected)
++ && (adapter->InfrastructureMode != Wlan802_11IBSS
++ || adapter->AdhocLinkSensed == TRUE))
++ os_carrier_on(priv);
++ else
++ os_carrier_off(priv);
++
++ os_start_queue(priv);
++ wmm_start_queue(priv);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function closes the network device
++ *
++ * @param dev A pointer to net_device structure
++ * @return WLAN_STATUS_SUCCESS
++ */
++static int
++wlan_close(struct net_device *dev)
++{
++ wlan_private *priv = dev->priv;
++
++ ENTER();
++
++ if (priv->adapter)
++ wlan_clean_txrx(priv);
++
++ MODULE_PUT;
++
++ priv->open = FALSE;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++#ifdef ENABLE_PM
++/**
++ * @brief
++ * This function is called to put the SDHC in a low power state. Refer to the
++ * document driver-model/driver.txt in the kernel source tree for more
++ * information.
++ *
++ * @param dev the device structure used to give information on which SDHC
++ * to suspend
++ * @param state the power state the device is entering
++ * @param level the stage in device suspension process that we want the
++ * device to be put in
++ *
++ * @return 0 : go to sleep mode
++ * -1 : do not accept to go to sleep mode.
++ */
++static int
++wlan_pm_suspend(struct device *pmdev, u32 state, u32 level)
++{
++ wlan_private *priv = wlanpriv;
++ wlan_adapter *Adapter = priv->adapter;
++ struct net_device *dev = priv->wlan_dev.netdev;
++
++ switch (level) {
++
++ case SUSPEND_DISABLE:
++ PRINTM(INFO, "WIFI_PM_SUSPEND_CALLBACK: enter SUSPEND_DISABLE.\n");
++
++ /* in associated mode : check that chipset is in IEEE PS and well configured to wake up the host if needed */
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ if ((Adapter->PSState != PS_STATE_SLEEP)
++ || (!Adapter->bWakeupDevRequired)
++ || (Adapter->WakeupTries != 0)) {
++ PRINTM(INFO, "WIFI_PM_SUSPEND_CALLBACK: can't enter sleep mode because \
++ PSstate=%d, bWakeupDevRequired=%d, wakeupTries=%d\n",
++ Adapter->PSState, Adapter->bWakeupDevRequired, Adapter->WakeupTries);
++ return WLAN_STATUS_FAILURE;
++ }
++
++ else {
++
++ /*
++ * Detach the network interface
++ * if the network is running
++ */
++ if (netif_running(dev)) {
++ netif_device_detach(dev);
++ PRINTM(INFO, "netif_device_detach().\n");
++ }
++ /* Stop bus clock */
++ sbi_set_bus_clock(priv, FALSE);
++ }
++ }
++
++ /* in non associated mode : check that chipset is in Deepsleep mode */
++ else {
++ if (Adapter->IsDeepSleep == FALSE) {
++ PRINTM(INFO,
++ "WIFI_PM_SUSPEND_CALLBACK: No allowed to enter sleep while in FW in full power.\n");
++ return WLAN_STATUS_FAILURE;
++ }
++ /*
++ * Detach the network interface
++ * if the network is running
++ */
++ if (netif_running(dev)) {
++ netif_device_detach(dev);
++ }
++ }
++ break;
++
++ case SUSPEND_SAVE_STATE:
++
++ PRINTM(INFO, "WIFI_PM_SUSPEND_CALLBACK: enter SUSPEND_SAVE_STATE.\n");
++ /* Save bus state to restore it when waking up */
++ sbi_suspend(priv);
++
++ break;
++
++ case SUSPEND_POWER_DOWN:
++
++ PRINTM(INFO, "WIFI_PM_SUSPEND_CALLBACK: enter SUSPEND_POWER_DOWN.\n");
++ /* nothing to do */
++ break;
++
++ default:
++
++ break;
++
++ }
++
++ return WLAN_STATUS_SUCCESS;
++
++}
++
++/**
++ * @brief
++ * This function is called to bring the SDHC back from a low power state. Refer
++ * to the document driver-model/driver.txt in the kernel source tree for more
++ * information.
++ *
++ * @param dev the device structure used to give information on which SDHC
++ * to resume
++ * @param level the stage in device resumption process that we want the
++ * device to be put in
++ *
++ * @return The function always returns 0.
++ */
++static int
++wlan_pm_resume(struct device *pmdev, u32 level)
++{
++ wlan_private *priv = wlanpriv;
++ wlan_adapter *Adapter = priv->adapter;
++ struct net_device *dev = priv->wlan_dev.netdev;
++
++ switch (level) {
++
++ case RESUME_POWER_ON:
++
++ PRINTM(INFO, "WIFI_PM_RESUME_CALLBACK: enter RESUME_POWER_ON.\n");
++ /* nothing to do */
++ break;
++
++ case RESUME_RESTORE_STATE:
++
++ PRINTM(INFO,
++ "WIFI_PM_RESUME_CALLBACK: enter RESUME_RESTORE_STATE.\n");
++ /* Restore bus state */
++ sbi_resume(priv);
++ break;
++
++ case RESUME_ENABLE:
++
++ PRINTM(INFO, "WIFI_PM_RESUME_CALLBACK: enter RESUME_ENABLE.\n");
++
++ /* in associated mode */
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++
++ if (Adapter->bWakeupDevRequired == FALSE) {
++ /* could never happen */
++ PRINTM(MSG, "WIFI_PM_RESUME_CALLBACK: serious error.\n");
++ } else {
++ /*
++ * Start bus clock
++ */
++ sbi_set_bus_clock(priv, TRUE);
++ /*
++ * Attach the network interface
++ * if the network is running
++ */
++ if (netif_running(dev)) {
++ netif_device_attach(dev);
++ PRINTM(INFO, "WIFI_PM : after netif_device_attach().\n");
++ }
++ PRINTM(INFO,
++ "WIFI_PM : After netif attach, in associated mode.\n");
++ }
++ }
++
++ /* in non associated mode */
++ else {
++ if (netif_running(dev)) {
++ netif_device_attach(dev);
++ }
++
++ PRINTM(INFO,
++ "WIFI_PM : after netif attach, in NON associated mode.\n");
++ }
++ break;
++
++ default:
++ break;
++
++ }
++ return WLAN_STATUS_SUCCESS;
++
++}
++
++/**
++ * @brief
++ * Dummy function to be compliant with Linux Power Management framework.
++ *
++ * @param pmdev the device structure used to give information on which SDHC
++ * to use
++ *
++ * @return None.
++ */
++static void
++wlan_pm_release(struct device *pmdev)
++{
++ PRINTM(INFO, "WIFI_PM_DRIVER : Into pm_device release function\n");
++ return;
++}
++
++#endif /* ENABLE_PM */
++
++/**
++ * @brief This function handles packet transmission
++ *
++ * @param skb A pointer to sk_buff structure
++ * @param dev A pointer to net_device structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ int ret;
++ wlan_private *priv = dev->priv;
++
++ ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ PRINTM(DATA, "Data <= kernel\n");
++
++ if (wlan_tx_packet(priv, skb)) {
++ /* Transmit failed */
++ ret = WLAN_STATUS_FAILURE;
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function handles the timeout of packet
++ * transmission
++ *
++ * @param dev A pointer to net_device structure
++ * @return n/a
++ */
++static void
++wlan_tx_timeout(struct net_device *dev)
++{
++ wlan_private *priv = (wlan_private *) dev->priv;
++
++ ENTER();
++
++ PRINTM(DATA, "Tx timeout\n");
++ UpdateTransStart(dev);
++
++ priv->adapter->dbg.num_tx_timeout++;
++
++ priv->adapter->IntCounter++;
++ wake_up_interruptible(&priv->MainThread.waitQ);
++
++ LEAVE();
++}
++
++/**
++ * @brief This function returns the network statistics
++ *
++ * @param dev A pointer to wlan_private structure
++ * @return A pointer to net_device_stats structure
++ */
++static struct net_device_stats *
++wlan_get_stats(struct net_device *dev)
++{
++ wlan_private *priv = (wlan_private *) dev->priv;
++
++ return &priv->stats;
++}
++
++/**
++ * @brief This function sets the MAC address to firmware.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param pRxPD A pointer to RxPD structure of received packet
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++wlan_set_mac_address(struct net_device *dev, void *addr)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_private *priv = (wlan_private *) dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ struct sockaddr *pHwAddr = (struct sockaddr *) addr;
++
++ ENTER();
++
++ memset(Adapter->CurrentAddr, 0, MRVDRV_ETH_ADDR_LEN);
++
++ /* dev->dev_addr is 8 bytes */
++ HEXDUMP("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
++
++ HEXDUMP("addr:", pHwAddr->sa_data, ETH_ALEN);
++ memcpy(Adapter->CurrentAddr, pHwAddr->sa_data, ETH_ALEN);
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_MAC_ADDRESS,
++ HostCmd_ACT_SET,
++ HostCmd_OPTION_WAITFORRSP, 0, NULL);
++
++ if (ret) {
++ PRINTM(INFO, "set mac address failed.\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ HEXDUMP("Adapter->MacAddr:", Adapter->CurrentAddr, ETH_ALEN);
++ memcpy(dev->dev_addr, Adapter->CurrentAddr, ETH_ALEN);
++
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function sets multicast addresses to firmware
++ *
++ * @param dev A pointer to net_device structure
++ * @return n/a
++ */
++static void
++wlan_set_multicast_list(struct net_device *dev)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ int OldPacketFilter;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ OldPacketFilter = Adapter->CurrentPacketFilter;
++
++ if (dev->flags & IFF_PROMISC) {
++ PRINTM(INFO, "Enable Promiscuous mode\n");
++ Adapter->CurrentPacketFilter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
++ Adapter->CurrentPacketFilter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
++ } else {
++ /* Multicast */
++ Adapter->CurrentPacketFilter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
++
++ if (dev->flags & IFF_ALLMULTI || dev->mc_count >
++ MRVDRV_MAX_MULTICAST_LIST_SIZE) {
++ PRINTM(INFO, "Enabling All Multicast!\n");
++ Adapter->CurrentPacketFilter |=
++ HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
++ } else {
++ Adapter->CurrentPacketFilter &=
++ ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
++
++ if (!dev->mc_count) {
++ PRINTM(INFO, "No multicast addresses - "
++ "disabling multicast!\n");
++
++ } else {
++ int i;
++
++ Adapter->NumOfMulticastMACAddr =
++ CopyMulticastAddrs(Adapter, dev);
++
++ PRINTM(INFO, "Multicast addresses: %d\n", dev->mc_count);
++
++ for (i = 0; i < dev->mc_count; i++) {
++ PRINTM(INFO, "Multicast address %d:"
++ "%x %x %x %x %x %x\n", i,
++ Adapter->MulticastList[i][0],
++ Adapter->MulticastList[i][1],
++ Adapter->MulticastList[i][2],
++ Adapter->MulticastList[i][3],
++ Adapter->MulticastList[i][4],
++ Adapter->MulticastList[i][5]);
++ }
++ /* set multicast addresses to firmware */
++ ret =
++ PrepareAndSendCommand(priv, HostCmd_CMD_MAC_MULTICAST_ADR,
++ HostCmd_ACT_GEN_SET, 0, 0, NULL);
++ }
++ }
++ }
++
++ if (Adapter->CurrentPacketFilter != OldPacketFilter) {
++ if (ret == WLAN_STATUS_SUCCESS)
++ PrepareAndSendCommand(priv,
++ HostCmd_CMD_MAC_CONTROL,
++ 0, 0, 0, &Adapter->CurrentPacketFilter);
++ }
++
++ LEAVE();
++}
++
++/**
++ * @brief This function pops rx_skb from the rx queue.
++ *
++ * @param RxSkbQ A pointer to rx_skb queue
++ * @return A pointer to skb
++ */
++static struct sk_buff *
++wlan_pop_rx_skb(struct sk_buff *RxSkbQ)
++{
++ struct sk_buff *skb_data = NULL;
++
++ if (!list_empty((struct list_head *) RxSkbQ)) {
++ skb_data = RxSkbQ->next;
++ list_del((struct list_head *) RxSkbQ->next);
++ }
++
++ return skb_data;
++}
++
++/**
++ * @brief This function hanldes the major job in WLAN driver.
++ * it handles the event generated by firmware, rx data received
++ * from firmware and tx data sent from kernel.
++ *
++ * @param data A pointer to wlan_thread structure
++ * @return WLAN_STATUS_SUCCESS
++ */
++static int
++wlan_service_main_thread(void *data)
++{
++ wlan_thread *thread = data;
++ wlan_private *priv = thread->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ wait_queue_t wait;
++ u8 ireg = 0;
++ u8 runCmd = 1;
++
++ OS_INTERRUPT_SAVE_AREA;
++
++ ENTER();
++
++ wlan_activate_thread(thread);
++
++ init_waitqueue_entry(&wait, current);
++
++ current->flags |= PF_NOFREEZE;
++
++ wmm_init(priv);
++
++ for (;;) {
++ add_wait_queue(&thread->waitQ, &wait);
++ OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE);
++
++ runCmd = 1;
++ TX_DISABLE;
++
++ if ((Adapter->WakeupTries) ||
++ (Adapter->PSState == PS_STATE_SLEEP
++ && !Adapter->bWakeupDevRequired) ||
++ (!Adapter->IntCounter &&
++ Adapter->PSState == PS_STATE_PRE_SLEEP) ||
++ (!Adapter->IntCounter
++ && (priv->wlan_dev.dnld_sent || Adapter->TxLockFlag
++ || wmm_lists_empty(priv) || wmm_is_queue_stopped(priv))
++ && (priv->wlan_dev.dnld_sent || !Adapter->CurrentTxSkb)
++ && (priv->wlan_dev.dnld_sent || Adapter->CurCmd ||
++ list_empty(&Adapter->CmdPendingQ))
++ )
++ ) {
++ PRINTM(INFO, "main-thread sleeping... "
++ "HS_Act=%s WakeupReq=%s Conn=%s PS_Mode=%d PS_State=%d\n",
++ (Adapter->HS_Activated) ? "Y" : "N",
++ (Adapter->bWakeupDevRequired) ? "Y" : "N",
++ (Adapter->MediaConnectStatus) ? "Y" : "N",
++ Adapter->PSMode, Adapter->PSState);
++
++#ifdef _MAINSTONE
++ MST_LEDDAT1 = get_utimeofday();
++#endif
++ TX_RESTORE;
++ schedule();
++ PRINTM(INFO, "main-thread waking up: IntCnt=%d "
++ "CurCmd=%s CmdPending=%s\n"
++ " Connect=%s "
++ "CurTxSkb=%s dnld_sent=%d\n",
++ Adapter->IntCounter,
++ (Adapter->CurCmd) ? "Y" : "N",
++ list_empty(&Adapter->CmdPendingQ) ? "N" : "Y",
++ (Adapter->MediaConnectStatus) ? "Y" : "N",
++ (Adapter->CurrentTxSkb) ? "Y" : "N",
++ priv->wlan_dev.dnld_sent);
++ } else {
++ TX_RESTORE;
++ }
++
++ OS_SET_THREAD_STATE(TASK_RUNNING);
++ remove_wait_queue(&thread->waitQ, &wait);
++
++ if (kthread_should_stop() || Adapter->SurpriseRemoved) {
++ PRINTM(INFO, "main-thread: break from main thread: "
++ "SurpriseRemoved=0x%x\n", Adapter->SurpriseRemoved);
++ break;
++ }
++
++ if (Adapter->IntCounter) {
++ OS_INT_DISABLE;
++ Adapter->IntCounter = 0;
++ OS_INT_RESTORE;
++
++ if (sbi_get_int_status(priv, &ireg)) {
++ PRINTM(ERROR,
++ "main-thread: reading HOST_INT_STATUS_REG failed\n");
++ continue;
++ }
++ OS_INT_DISABLE;
++ Adapter->HisRegCpy |= ireg;
++ OS_INT_RESTORE;
++ PRINTM(INTR, "INT: status = 0x%x\n", Adapter->HisRegCpy);
++ } else if (Adapter->bWakeupDevRequired
++ && (Adapter->HS_Activated || (Adapter->IsDeepSleep)
++ )
++ ) {
++ Adapter->WakeupTries++;
++ PRINTM(CMND,
++ "Wakeup device... WakeupReq=%s Conn=%s PS_Mode=%d PS_State=%d\n",
++ (Adapter->bWakeupDevRequired) ? "Y" : "N",
++ (priv->adapter->MediaConnectStatus) ? "Y" : "N",
++ priv->adapter->PSMode, priv->adapter->PSState);
++
++ /* Wake up device */
++ if (sbi_exit_deep_sleep(priv))
++ PRINTM(MSG, "main-thread: wakeup dev failed\n");
++ continue;
++ }
++
++ /* Command response? */
++ if (Adapter->HisRegCpy & HIS_CmdUpLdRdy) {
++ OS_INT_DISABLE;
++ Adapter->HisRegCpy &= ~HIS_CmdUpLdRdy;
++ OS_INT_RESTORE;
++
++ wlan_process_rx_command(priv);
++ }
++
++ /* Any received data? */
++ if (Adapter->HisRegCpy & HIS_RxUpLdRdy) {
++ OS_INT_DISABLE;
++ Adapter->HisRegCpy &= ~HIS_RxUpLdRdy;
++ OS_INT_RESTORE;
++
++ wlan_send_rxskbQ(priv);
++ runCmd = 0;
++ }
++
++ /* Any Card Event */
++ if (Adapter->HisRegCpy & HIS_CardEvent) {
++ OS_INT_DISABLE;
++ Adapter->HisRegCpy &= ~HIS_CardEvent;
++ OS_INT_RESTORE;
++
++ if (sbi_read_event_cause(priv)) {
++ PRINTM(ERROR, "main-thread: sbi_read_event_cause failed.\n");
++ continue;
++ }
++ wlan_process_event(priv);
++ }
++
++ /* Check if we need to confirm Sleep Request received previously */
++ if (Adapter->PSState == PS_STATE_PRE_SLEEP) {
++ if (!priv->wlan_dev.dnld_sent && !Adapter->CurCmd) {
++ ASSERT(Adapter->MediaConnectStatus ==
++ WlanMediaStateConnected);
++ PSConfirmSleep(priv, (u16) Adapter->PSMode);
++ }
++ }
++
++ /* The PS state is changed during processing of
++ * Sleep Request event above
++ */
++ if ((Adapter->PSState == PS_STATE_SLEEP)
++ || (Adapter->PSState == PS_STATE_PRE_SLEEP)) {
++ continue;
++ }
++
++ if (Adapter->IsDeepSleep)
++ continue;
++
++ /* The HS_Activated flag is changed during processing of
++ HS_Activate command resp */
++ /* We cannot send command or data if HS_Activated and
++ WakeupDevRequired are TRUE */
++ if (Adapter->HS_Activated && Adapter->bWakeupDevRequired) {
++ PRINTM(INFO, "main-thread: cannot send command or data, "
++ "HS_Activated=%d\n", Adapter->HS_Activated);
++ continue;
++ }
++
++ /* Execute the next command */
++ if (!priv->wlan_dev.dnld_sent && !Adapter->CurCmd && runCmd == 1) {
++ ExecuteNextCommand(priv);
++ }
++
++ if (!priv->wlan_dev.dnld_sent
++ && !wmm_lists_empty(priv) && !wmm_is_queue_stopped(priv)) {
++ if ((Adapter->PSState == PS_STATE_FULL_POWER)
++ || (Adapter->sleep_period.period == 0)
++ || (Adapter->TxLockFlag == FALSE)) {
++ wmm_process_tx(priv);
++ }
++ }
++
++ }
++
++ wlan_deactivate_thread(thread);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function adds the card. it will probe the
++ * card, allocate the wlan_priv and initialize the device.
++ *
++ * @param card A pointer to card
++ * @return A pointer to wlan_private structure
++ */
++wlan_private *
++wlan_add_card(void *card, struct device *dmdev)
++{
++ struct net_device *dev = NULL;
++ wlan_private *priv = NULL;
++
++ ENTER();
++
++ /* probe the card */
++ if (sbi_probe_card(card) < 0) {
++ PRINTM(MSG, "NO card found!\n");
++ return NULL;
++ }
++
++ /* Allocate an Ethernet device and register it */
++ if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
++ PRINTM(MSG, "Init ethernet device failed!\n");
++ return NULL;
++ }
++
++ priv = dev->priv;
++
++ /* allocate buffer for wlan_adapter */
++ if (!(priv->adapter = kmalloc(sizeof(wlan_adapter), GFP_KERNEL))) {
++ PRINTM(MSG, "Allocate buffer for wlan_adapter failed!\n");
++ goto err_kmalloc;
++ }
++
++ /* init wlan_adapter */
++ memset(priv->adapter, 0, sizeof(wlan_adapter));
++
++ priv->wlan_dev.netdev = dev;
++ priv->wlan_dev.card = card;
++ priv->wlan_dev.hotplug_device = dmdev;
++ wlanpriv = priv;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
++ SET_MODULE_OWNER(dev);
++#endif
++
++ /* Setup the OS Interface to our functions */
++ dev->open = wlan_open;
++ dev->hard_start_xmit = wlan_hard_start_xmit;
++ dev->stop = wlan_close;
++ dev->do_ioctl = wlan_do_ioctl;
++ dev->set_mac_address = wlan_set_mac_address;
++
++ dev->tx_timeout = wlan_tx_timeout;
++ dev->get_stats = wlan_get_stats;
++ dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
++
++#ifdef WIRELESS_EXT
++#if WIRELESS_EXT > 17
++ wlan_handler_def.get_wireless_stats = wlan_get_wireless_stats;
++#else
++ dev->get_wireless_stats = wlan_get_wireless_stats;
++#endif
++ dev->wireless_handlers = (struct iw_handler_def *) &wlan_handler_def;
++#endif
++#define NETIF_F_DYNALLOC 16
++ dev->features |= NETIF_F_DYNALLOC;
++ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
++ dev->set_multicast_list = wlan_set_multicast_list;
++
++ SET_NETDEV_DEV(dev, dmdev);
++
++ init_waitqueue_head(&priv->adapter->ds_awake_q);
++
++#ifdef ENABLE_PM
++ /* register Driver to Linux Power Management system. */
++ if (!driver_register(&wlan_pm_driver)) {
++ /* Register one device to Linux Power Management system. */
++ if (platform_device_register(&wlan_pm_platform_device)) {
++ PRINTM(MSG,
++ "WiFi driver, wlan_main : error when registering device to Linux Power Managment.\n");
++ driver_unregister(&wlan_pm_driver);
++ } else {
++ PRINTM(INFO,
++ "WiFi device and driver registered to Linux Power Managment.\n");
++ }
++ } else {
++ PRINTM(MSG,
++ "WiFi driver, wlan_main : error when registering driver to Linux Power Managment.\n");
++ }
++
++#endif
++
++ INIT_LIST_HEAD(&priv->adapter->CmdFreeQ);
++ INIT_LIST_HEAD(&priv->adapter->CmdPendingQ);
++
++ PRINTM(INFO, "Starting kthread...\n");
++ priv->MainThread.priv = priv;
++ wlan_create_thread(wlan_service_main_thread,
++ &priv->MainThread, "wlan_main_service");
++
++ ConfigureThreadPriority();
++
++#ifdef REASSOCIATION
++ priv->ReassocThread.priv = priv;
++ wlan_create_thread(wlan_reassociation_thread,
++ &priv->ReassocThread, "wlan_reassoc_service");
++#endif /* REASSOCIATION */
++
++ /*
++ * Register the device. Fillup the private data structure with
++ * relevant information from the card and request for the required
++ * IRQ.
++ */
++
++ if (sbi_register_dev(priv) < 0) {
++ PRINTM(FATAL, "Failed to register wlan device!\n");
++ goto err_registerdev;
++ }
++
++ PRINTM(WARN, "%s: Marvell Wlan 802.11 Adapter "
++ "revision 0x%02X at IRQ %i\n", dev->name,
++ priv->adapter->chip_rev, dev->irq);
++
++#ifdef CONFIG_MARVELL_8686_PROC_FS
++ wlan_proc_entry(priv, dev);
++#ifdef CONFIG_MARVELL_8686_DEBUG
++ wlan_debug_entry(priv, dev);
++#endif
++#endif
++
++ /* Get the CIS Table */
++ sbi_get_cis_info(priv);
++
++ /* init FW and HW */
++ if (wlan_init_fw(priv)) {
++ PRINTM(FATAL, "Firmware Init Failed\n");
++ goto err_init_fw;
++ }
++
++ if (register_netdev(dev)) {
++ printk(KERN_ERR "Cannot register network device!\n");
++ goto err_netdev;
++ }
++
++ LEAVE();
++ return priv;
++
++err_netdev:
++ unregister_netdev(dev);
++
++err_init_fw:
++ sbi_unregister_dev(priv);
++
++#ifdef CONFIG_MARVELL_8686_PROC_FS
++#ifdef CONFIG_MARVELL_8686_DEBUG
++ wlan_debug_remove(priv);
++#endif
++ wlan_proc_remove(priv);
++#endif
++
++err_registerdev:
++ /* Stop the thread servicing the interrupts */
++ wake_up_interruptible(&priv->MainThread.waitQ);
++ wlan_terminate_thread(&priv->MainThread);
++
++#ifdef REASSOCIATION
++ wake_up_interruptible(&priv->ReassocThread.waitQ);
++ wlan_terminate_thread(&priv->ReassocThread);
++#endif /* REASSOCIATION */
++
++err_kmalloc:
++ free_netdev(dev);
++ wlan_free_adapter(priv);
++ wlanpriv = NULL;
++
++ LEAVE();
++ return NULL;
++}
++
++/**
++ * @brief This function removes the card.
++ *
++ * @param priv A pointer to card
++ * @return WLAN_STATUS_SUCCESS
++ */
++int
++wlan_remove_card(void *card)
++{
++ wlan_private *priv = wlanpriv;
++ wlan_adapter *Adapter;
++ struct net_device *dev;
++ union iwreq_data wrqu;
++
++ ENTER();
++
++ if (!priv) {
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++ }
++
++ Adapter = priv->adapter;
++
++ if (!Adapter) {
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++ }
++
++ dev = priv->wlan_dev.netdev;
++
++ wake_up_interruptible(&Adapter->ds_awake_q);
++
++ if (Adapter->CurCmd) {
++ PRINTM(INFO, "Wake up current cmdwait_q\n");
++ wake_up_interruptible(&Adapter->CurCmd->cmdwait_q);
++ }
++
++ Adapter->CurCmd = NULL;
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ wlan_clean_txrx(priv);
++ Adapter->MediaConnectStatus = WlanMediaStateDisconnected;
++ }
++ Adapter->IsAutoDeepSleepEnabled = FALSE;
++ if (Adapter->IsDeepSleep == TRUE) {
++ sbi_exit_deep_sleep(priv);
++ if (Adapter->IsDeepSleep == TRUE) {
++ if (os_wait_interruptible_timeout(Adapter->ds_awake_q,
++ !Adapter->IsDeepSleep,
++ MRVDRV_DEEP_SLEEP_EXIT_TIMEOUT)
++ == 0) {
++ PRINTM(MSG, "ds_awake_q: timer expired\n");
++ }
++ }
++ }
++
++ if (Adapter->PSMode == Wlan802_11PowerModeMAX_PSP) {
++ Adapter->PSMode = Wlan802_11PowerModeCAM;
++ PSWakeup(priv, HostCmd_OPTION_WAITFORRSP);
++ }
++
++ memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
++ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
++ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
++
++ /* Disable interrupts on the card as we cannot handle them after RESET */
++ sbi_disable_host_int(priv);
++
++ PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RESET, 0, 0, 0, NULL);
++
++ os_sched_timeout(500);
++
++#ifdef ENABLE_PM
++ /* unregister driver and device from Linux Power Management system. */
++ platform_device_unregister(&wlan_pm_platform_device);
++ driver_unregister(&wlan_pm_driver);
++#endif
++
++ Adapter->SurpriseRemoved = TRUE;
++
++ /* Stop the thread servicing the interrupts */
++ wake_up_interruptible(&priv->MainThread.waitQ);
++
++#ifdef REASSOCIATION
++ wake_up_interruptible(&priv->ReassocThread.waitQ);
++#endif /* REASSOCIATION */
++
++#ifdef CONFIG_MARVELL_8686_PROC_FS
++#ifdef CONFIG_MARVELL_8686_DEBUG
++ wlan_debug_remove(priv);
++#endif
++ wlan_proc_remove(priv);
++#endif
++
++ PRINTM(INFO, "unregester dev\n");
++ sbi_unregister_dev(priv);
++
++ /* Last reference is our one */
++ PRINTM(INFO, "refcnt = %d\n", atomic_read(&dev->refcnt));
++
++ PRINTM(INFO, "netdev_finish_unregister: %s%s.\n", dev->name,
++ (dev->features & NETIF_F_DYNALLOC) ? "" : ", old style");
++
++ unregister_netdev(dev);
++
++ PRINTM(INFO, "Unregister finish\n");
++
++ priv->wlan_dev.netdev = NULL;
++ PRINTM(INFO, "Free Adapter\n");
++ wlan_free_adapter(priv);
++ free_netdev(dev);
++ wlanpriv = NULL;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/********************************************************
++ Global Functions
++********************************************************/
++
++/**
++ * @brief This function sends the rx packets to the os from the skb queue
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return n/a
++ */
++void
++wlan_send_rxskbQ(wlan_private * priv)
++{
++ struct sk_buff *skb;
++
++ ENTER();
++ if (priv->adapter) {
++ while ((skb = wlan_pop_rx_skb(&priv->adapter->RxSkbQ))) {
++ if (ProcessRxedPacket(priv, skb) == -ENOMEM)
++ break;
++ }
++ }
++ LEAVE();
++}
++
++/**
++ * @brief This function finds the CFP in
++ * region_cfp_table based on region and band parameter.
++ *
++ * @param region The region code
++ * @param band The band
++ * @param cfp_no A pointer to CFP number
++ * @return A pointer to CFP
++ */
++CHANNEL_FREQ_POWER *
++wlan_get_region_cfp_table(u8 region, u8 band, int *cfp_no)
++{
++ int i;
++
++ ENTER();
++
++ for (i = 0; i < sizeof(region_cfp_table) / sizeof(region_cfp_table_t);
++ i++) {
++ PRINTM(INFO, "region_cfp_table[i].region=%d\n",
++ region_cfp_table[i].region);
++ if (region_cfp_table[i].region == region) {
++ {
++ *cfp_no = region_cfp_table[i].cfp_no_BG;
++ LEAVE();
++ return region_cfp_table[i].cfp_BG;
++ }
++ }
++ }
++
++ LEAVE();
++ return NULL;
++}
++
++/**
++ * @brief This function sets region table.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param region The region code
++ * @param band The band
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_set_regiontable(wlan_private * priv, u8 region, u8 band)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int i = 0;
++
++ CHANNEL_FREQ_POWER *cfp;
++ int cfp_no;
++
++ ENTER();
++
++ memset(Adapter->region_channel, 0, sizeof(Adapter->region_channel));
++
++ {
++ cfp = wlan_get_region_cfp_table(region, band, &cfp_no);
++ if (cfp != NULL) {
++ Adapter->region_channel[i].NrCFP = cfp_no;
++ Adapter->region_channel[i].CFP = cfp;
++ } else {
++ PRINTM(INFO, "wrong region code %#x in Band B-G\n", region);
++ return WLAN_STATUS_FAILURE;
++ }
++ Adapter->region_channel[i].Valid = TRUE;
++ Adapter->region_channel[i].Region = region;
++ Adapter->region_channel[i].Band = band;
++ i++;
++ }
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function handles the interrupt. it will change PS
++ * state if applicable. it will wake up main_thread to handle
++ * the interrupt event as well.
++ *
++ * @param dev A pointer to net_device structure
++ * @return n/a
++ */
++void
++wlan_interrupt(struct net_device *dev)
++{
++ wlan_private *priv = dev->priv;
++
++ priv->adapter->IntCounter++;
++
++ PRINTM(INTR, "*\n");
++
++ priv->adapter->WakeupTries = 0;
++
++ if (priv->adapter->PSState == PS_STATE_SLEEP) {
++ priv->adapter->PSState = PS_STATE_AWAKE;
++ }
++
++ wake_up_interruptible(&priv->MainThread.waitQ);
++}
++
++#if 0
++/**
++ * @brief This function initializes module.
++ *
++ * @param n/a A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_init_module(void)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (sbi_register(wlan_add_card, wlan_remove_card, NULL) == NULL) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function cleans module
++ *
++ * @param priv n/a
++ * @return n/a
++ */
++void
++wlan_cleanup_module(void)
++{
++ ENTER();
++
++ sbi_unregister();
++
++ LEAVE();
++}
++
++module_init(wlan_init_module);
++module_exit(wlan_cleanup_module);
++#endif
++
++MODULE_DESCRIPTION("M-WLAN Driver");
++MODULE_AUTHOR("Marvell International Ltd.");
+diff --git a/drivers/net/wireless/marvell8686/wlan_proc.c b/drivers/net/wireless/marvell8686/wlan_proc.c
+new file mode 100644
+index 0000000..99604dd
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_proc.c
+@@ -0,0 +1,213 @@
++/** @file wlan_proc.c
++ * @brief This file contains functions for proc fin proc file.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++/********************************************************
++Change log:
++ 10/04/05: Add Doxygen format comments
++ 01/05/06: Add kernel 2.6.x support
++
++********************************************************/
++#include "include.h"
++
++#ifdef CONFIG_MARVELL_8686_PROC_FS
++/********************************************************
++ Local Variables
++********************************************************/
++
++static char *szModes[] = {
++ "Ad-hoc",
++ "Managed",
++ "Auto",
++ "Unknown"
++};
++
++/********************************************************
++ Global Variables
++********************************************************/
++
++/********************************************************
++ Local Functions
++********************************************************/
++
++/**
++ * @brief proc read function
++ *
++ * @param page pointer to buffer
++ * @param start read data starting position
++ * @param offset offset
++ * @param count counter
++ * @param eof end of file flag
++ * @param data data to output
++ * @return number of output data
++ */
++static int
++wlan_proc_read(char *page, char **start, off_t offset,
++ int count, int *eof, void *data)
++{
++ int i;
++ char *p = page;
++ struct net_device *netdev = data;
++ struct dev_mc_list *mcptr = netdev->mc_list;
++ char fmt[64];
++ wlan_private *priv = netdev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ ulong flags;
++
++ if (offset != 0) {
++ *eof = 1;
++ goto exit;
++ }
++
++ get_version(Adapter, fmt, sizeof(fmt) - 1);
++
++ p += sprintf(p, "driver_name = " "\"wlan\"\n");
++ p += sprintf(p, "driver_version = %s", fmt);
++ p += sprintf(p, "\nInterfaceName=\"%s\"\n", netdev->name);
++ p += sprintf(p, "Mode=\"%s\"\n", szModes[Adapter->InfrastructureMode]);
++ p += sprintf(p, "State=\"%s\"\n",
++ ((Adapter->MediaConnectStatus ==
++ WlanMediaStateDisconnected) ? "Disconnected" :
++ "Connected"));
++ p += sprintf(p, "MACAddress=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
++ netdev->dev_addr[0], netdev->dev_addr[1],
++ netdev->dev_addr[2], netdev->dev_addr[3],
++ netdev->dev_addr[4], netdev->dev_addr[5]);
++
++ p += sprintf(p, "MCCount=\"%d\"\n", netdev->mc_count);
++ p += sprintf(p, "ESSID=\"%s\"\n",
++ (u8 *) Adapter->CurBssParams.BSSDescriptor.Ssid.Ssid);
++ p += sprintf(p, "Channel=\"%d\"\n",
++ Adapter->CurBssParams.BSSDescriptor.Channel);
++ p += sprintf(p, "region_code = \"%02x\"\n", (u32) Adapter->RegionCode);
++
++ /*
++ * Put out the multicast list
++ */
++ for (i = 0; i < netdev->mc_count; i++) {
++ p += sprintf(p,
++ "MCAddr[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
++ i,
++ mcptr->dmi_addr[0], mcptr->dmi_addr[1],
++ mcptr->dmi_addr[2], mcptr->dmi_addr[3],
++ mcptr->dmi_addr[4], mcptr->dmi_addr[5]);
++
++ mcptr = mcptr->next;
++ }
++ p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
++ p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
++ p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
++ p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
++ p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
++ p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
++ p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
++ p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
++ p += sprintf(p, "carrier %s\n",
++ ((netif_carrier_ok(priv->wlan_dev.netdev)) ? "on" : "off"));
++ p += sprintf(p, "tx queue %s\n",
++ ((netif_queue_stopped(priv->wlan_dev.netdev)) ? "stopped" :
++ "started"));
++
++ spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
++ if (Adapter->CurCmd) {
++ HostCmd_DS_COMMAND *CmdPtr =
++ (HostCmd_DS_COMMAND *) Adapter->CurCmd->BufVirtualAddr;
++ p += sprintf(p, "CurCmd ID = 0x%x, 0x%x\n",
++ wlan_cpu_to_le16(CmdPtr->Command),
++ wlan_cpu_to_le16(*(u16 *) ((u8 *) CmdPtr + S_DS_GEN)));
++ } else {
++ p += sprintf(p, "CurCmd NULL\n");
++ }
++ spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
++
++ exit:
++ return (p - page);
++}
++
++/********************************************************
++ Global Functions
++********************************************************/
++
++/**
++ * @brief create wlan proc file
++ *
++ * @param priv pointer wlan_private
++ * @param dev pointer net_device
++ * @return N/A
++ */
++void
++wlan_proc_entry(wlan_private * priv, struct net_device *dev)
++{
++
++ PRINTM(INFO, "Creating Proc Interface\n");
++
++ if (!priv->proc_entry) {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++ priv->proc_entry = proc_mkdir("wlan", init_net.proc_net);
++#else
++ priv->proc_entry = proc_mkdir("wlan", proc_net);
++#endif
++
++
++ if (priv->proc_entry) {
++ priv->proc_dev = create_proc_read_entry
++ ("info", 0, priv->proc_entry, wlan_proc_read, dev);
++ }
++ }
++}
++
++/**
++ * @brief remove proc file
++ *
++ * @param priv pointer wlan_private
++ * @return N/A
++ */
++void
++wlan_proc_remove(wlan_private * priv)
++{
++
++ if (priv->proc_entry) {
++ remove_proc_entry("info", priv->proc_entry);
++ }
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++ remove_proc_entry("wlan", init_net.proc_net);
++#else
++ remove_proc_entry("wlan", proc_net);
++#endif
++
++}
++
++/**
++ * @brief convert string to number
++ *
++ * @param s pointer to numbered string
++ * @return converted number from string s
++ */
++int
++string_to_number(char *s)
++{
++ int r = 0;
++ int base = 0;
++
++ if ((strncmp(s, "0x", 2) == 0) || (strncmp(s, "0X", 2) == 0))
++ base = 16;
++ else
++ base = 10;
++ if (base == 16)
++ s += 2;
++ for (s = s; *s != 0; s++) {
++ if ((*s >= 48) && (*s <= 57))
++ r = (r * base) + (*s - 48);
++ else if ((*s >= 65) && (*s <= 70))
++ r = (r * base) + (*s - 55);
++ else if ((*s >= 97) && (*s <= 102))
++ r = (r * base) + (*s - 87);
++ else
++ break;
++ }
++
++ return r;
++}
++
++#endif
+diff --git a/drivers/net/wireless/marvell8686/wlan_rx.c b/drivers/net/wireless/marvell8686/wlan_rx.c
+new file mode 100644
+index 0000000..9a55ca1
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_rx.c
+@@ -0,0 +1,367 @@
++/** @file wlan_rx.c
++ * @brief This file contains the handling of RX in wlan
++ * driver.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++/********************************************************
++Change log:
++ 09/28/05: Add Doxygen format comments
++ 12/09/05: ADD Sliding window SNR/NF Average Calculation support
++
++********************************************************/
++
++#include "include.h"
++
++/********************************************************
++ Local Variables
++********************************************************/
++
++typedef struct
++{
++ u8 dest_addr[6];
++ u8 src_addr[6];
++ u16 h803_len;
++
++} __ATTRIB_PACK__ Eth803Hdr_t;
++
++typedef struct
++{
++ u8 llc_dsap;
++ u8 llc_ssap;
++ u8 llc_ctrl;
++ u8 snap_oui[3];
++ u16 snap_type;
++
++} __ATTRIB_PACK__ Rfc1042Hdr_t;
++
++typedef struct
++{
++ Eth803Hdr_t eth803_hdr;
++ Rfc1042Hdr_t rfc1042_hdr;
++
++} __ATTRIB_PACK__ RxPacketHdr_t;
++
++typedef struct
++{
++ u8 dest_addr[6];
++ u8 src_addr[6];
++ u16 ethertype;
++
++} __ATTRIB_PACK__ EthII_Hdr_t;
++
++/********************************************************
++ Global Variables
++********************************************************/
++
++/********************************************************
++ Local Functions
++********************************************************/
++
++/**
++ * @brief This function computes the AvgSNR .
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return AvgSNR
++ */
++static u8
++wlan_getAvgSNR(wlan_private * priv)
++{
++ u8 i;
++ u16 temp = 0;
++ wlan_adapter *Adapter = priv->adapter;
++ if (Adapter->numSNRNF == 0)
++ return 0;
++ for (i = 0; i < Adapter->numSNRNF; i++)
++ temp += Adapter->rawSNR[i];
++ return (u8) (temp / Adapter->numSNRNF);
++
++}
++
++/**
++ * @brief This function computes the AvgNF
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return AvgNF
++ */
++static u8
++wlan_getAvgNF(wlan_private * priv)
++{
++ u8 i;
++ u16 temp = 0;
++ wlan_adapter *Adapter = priv->adapter;
++ if (Adapter->numSNRNF == 0)
++ return 0;
++ for (i = 0; i < Adapter->numSNRNF; i++)
++ temp += Adapter->rawNF[i];
++ return (u8) (temp / Adapter->numSNRNF);
++
++}
++
++/**
++ * @brief This function save the raw SNR/NF to our internel buffer
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param pRxPD A pointer to RxPD structure of received packet
++ * @return n/a
++ */
++static void
++wlan_save_rawSNRNF(wlan_private * priv, RxPD * pRxPD)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ if (Adapter->numSNRNF < Adapter->data_avg_factor)
++ Adapter->numSNRNF++;
++ Adapter->rawSNR[Adapter->nextSNRNF] = pRxPD->SNR;
++ Adapter->rawNF[Adapter->nextSNRNF] = pRxPD->NF;
++ Adapter->nextSNRNF++;
++ if (Adapter->nextSNRNF >= Adapter->data_avg_factor)
++ Adapter->nextSNRNF = 0;
++ return;
++}
++
++#define DATA_RSSI_LOW_BIT 0x01
++#define DATA_SNR_LOW_BIT 0x02
++#define DATA_RSSI_HIGH_BIT 0x04
++#define DATA_SNR_HIGH_BIT 0x08
++/**
++ * @brief This function computes the RSSI in received packet.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return n/a
++ */
++static void
++wlan_check_subscribe_event(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int temp;
++ if (Adapter->subevent.EventsBitmap == 0)
++ return;
++ if ((Adapter->subevent.EventsBitmap & DATA_RSSI_LOW_BIT) ||
++ (Adapter->subevent.EventsBitmap & DATA_RSSI_HIGH_BIT)) {
++ temp =
++ -CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
++ Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
++ if (Adapter->subevent.EventsBitmap & DATA_RSSI_LOW_BIT) {
++ if (temp > Adapter->subevent.Rssi_low.value) {
++ if (!Adapter->subevent.Rssi_low.Freq) {
++ Adapter->subevent.EventsBitmap &= ~DATA_RSSI_LOW_BIT;
++ send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_LOW);
++ } else {
++ Adapter->subevent.Rssi_low_count++;
++ if (Adapter->subevent.Rssi_low_count >=
++ Adapter->subevent.Rssi_low.Freq) {
++ Adapter->subevent.Rssi_low_count = 0;
++ send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_LOW);
++ }
++ }
++ } else
++ Adapter->subevent.Rssi_low_count = 0;
++ }
++ if (Adapter->subevent.EventsBitmap & DATA_RSSI_HIGH_BIT) {
++ if (temp < Adapter->subevent.Rssi_high.value) {
++ if (!Adapter->subevent.Rssi_high.Freq) {
++ Adapter->subevent.EventsBitmap &= ~DATA_RSSI_HIGH_BIT;
++ send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_HIGH);
++ } else {
++ Adapter->subevent.Rssi_high_count++;
++ if (Adapter->subevent.Rssi_high_count >=
++ Adapter->subevent.Rssi_high.Freq) {
++ Adapter->subevent.Rssi_high_count = 0;
++ send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_HIGH);
++ }
++ }
++ } else
++ Adapter->subevent.Rssi_high_count = 0;
++ }
++ }
++ if ((Adapter->subevent.EventsBitmap & DATA_SNR_LOW_BIT) ||
++ (Adapter->subevent.EventsBitmap & DATA_SNR_HIGH_BIT)) {
++ temp = Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
++ if (Adapter->subevent.EventsBitmap & DATA_SNR_LOW_BIT) {
++ if (temp < Adapter->subevent.Snr_low.value) {
++ if (!Adapter->subevent.Snr_low.Freq) {
++ send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_LOW);
++ Adapter->subevent.EventsBitmap &= ~DATA_SNR_LOW_BIT;
++ } else {
++ Adapter->subevent.Snr_low_count++;
++ if (Adapter->subevent.Snr_low_count >=
++ Adapter->subevent.Snr_low.Freq) {
++ Adapter->subevent.Snr_low_count = 0;
++ send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_LOW);
++ }
++ }
++ } else
++ Adapter->subevent.Snr_low_count = 0;
++ }
++ if (Adapter->subevent.EventsBitmap & DATA_SNR_HIGH_BIT) {
++ if (temp > Adapter->subevent.Snr_high.value) {
++ if (!Adapter->subevent.Snr_high.Freq) {
++ Adapter->subevent.EventsBitmap &= ~DATA_SNR_HIGH_BIT;
++ send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_HIGH);
++ } else {
++ Adapter->subevent.Snr_high_count++;
++ if (Adapter->subevent.Snr_high_count >=
++ Adapter->subevent.Snr_high.Freq) {
++ Adapter->subevent.Snr_high_count = 0;
++ send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_HIGH);
++ }
++ }
++
++ } else
++ Adapter->subevent.Snr_high_count = 0;
++ }
++ }
++ return;
++}
++
++/**
++ * @brief This function computes the RSSI in received packet.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param pRxPD A pointer to RxPD structure of received packet
++ * @return n/a
++ */
++static void
++wlan_compute_rssi(wlan_private * priv, RxPD * pRxPD)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ PRINTM(INFO, "RxPD: SNR = %d, NF = %d\n", pRxPD->SNR, pRxPD->NF);
++
++ Adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = pRxPD->SNR;
++ Adapter->NF[TYPE_RXPD][TYPE_NOAVG] = pRxPD->NF;
++ wlan_save_rawSNRNF(priv, pRxPD);
++
++ Adapter->RxPDAge = os_time_get();
++ Adapter->RxPDRate = pRxPD->RxRate;
++
++ Adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getAvgSNR(priv) * AVG_SCALE;
++ Adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getAvgNF(priv) * AVG_SCALE;
++ PRINTM(INFO, "SNR-avg = %d, NF-avg = %d\n",
++ Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
++ Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
++
++ Adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] =
++ CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
++ Adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
++
++ Adapter->RSSI[TYPE_RXPD][TYPE_AVG] =
++ CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
++ Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
++ wlan_check_subscribe_event(priv);
++ LEAVE();
++}
++
++/********************************************************
++ Global functions
++********************************************************/
++
++/**
++ * @brief This function processes received packet and forwards it
++ * to kernel/upper layer
++ *
++ * @param priv A pointer to wlan_private
++ * @param skb A pointer to skb which includes the received packet
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++ProcessRxedPacket(wlan_private * priv, struct sk_buff *skb)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++
++ RxPacketHdr_t *pRxPkt;
++ RxPD *pRxPD;
++
++ int hdrChop;
++ EthII_Hdr_t *pEthHdr;
++ u32 u32SkbLen = skb->len;
++
++ const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
++
++ ENTER();
++
++ pRxPD = (RxPD *) skb->data;
++ pRxPkt = (RxPacketHdr_t *) ((u8 *) pRxPD + pRxPD->PktOffset);
++
++ DBG_HEXDUMP(DAT_D, "Rx", skb->data, MIN(skb->len, MAX_DATA_DUMP_LEN));
++
++ endian_convert_RxPD(pRxPD);
++
++ if (skb->len < (ETH_HLEN + 8 + pRxPD->PktOffset)) {
++ PRINTM(ERROR, "RX Error: FRAME RECEIVED WITH BAD LENGTH\n");
++ priv->stats.rx_length_errors++;
++ ret = WLAN_STATUS_SUCCESS;
++ kfree_skb(skb);
++ goto done;
++ }
++
++ PRINTM(INFO, "RX Data: skb->len - pRxPD->PktOffset = %d - %d = %d\n",
++ skb->len, pRxPD->PktOffset, skb->len - pRxPD->PktOffset);
++
++ HEXDUMP("RX Data: Dest", pRxPkt->eth803_hdr.dest_addr,
++ sizeof(pRxPkt->eth803_hdr.dest_addr));
++ HEXDUMP("RX Data: Src", pRxPkt->eth803_hdr.src_addr,
++ sizeof(pRxPkt->eth803_hdr.src_addr));
++
++ if (memcmp(&pRxPkt->rfc1042_hdr,
++ rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
++ /*
++ * Replace the 803 header and rfc1042 header (llc/snap) with an
++ * EthernetII header, keep the src/dst and snap_type (ethertype)
++ *
++ * The firmware only passes up SNAP frames converting
++ * all RX Data from 802.11 to 802.2/LLC/SNAP frames.
++ *
++ * To create the Ethernet II, just move the src, dst address right
++ * before the snap_type.
++ */
++ pEthHdr = (EthII_Hdr_t *)
++ ((u8 *) & pRxPkt->eth803_hdr
++ + sizeof(pRxPkt->eth803_hdr) + sizeof(pRxPkt->rfc1042_hdr)
++ - sizeof(pRxPkt->eth803_hdr.dest_addr)
++ - sizeof(pRxPkt->eth803_hdr.src_addr)
++ - sizeof(pRxPkt->rfc1042_hdr.snap_type));
++
++ memcpy(pEthHdr->src_addr, pRxPkt->eth803_hdr.src_addr,
++ sizeof(pEthHdr->src_addr));
++ memcpy(pEthHdr->dest_addr, pRxPkt->eth803_hdr.dest_addr,
++ sizeof(pEthHdr->dest_addr));
++
++ /* Chop off the RxPD + the excess memory from the 802.2/llc/snap header
++ * that was removed
++ */
++ hdrChop = (u8 *) pEthHdr - (u8 *) pRxPD;
++ } else {
++ HEXDUMP("RX Data: LLC/SNAP",
++ (u8 *) & pRxPkt->rfc1042_hdr, sizeof(pRxPkt->rfc1042_hdr));
++
++ /* Chop off the RxPD */
++ hdrChop = (u8 *) & pRxPkt->eth803_hdr - (u8 *) pRxPD;
++ }
++
++ /* Chop off the leading header bytes so the skb points to the start of
++ * either the reconstructed EthII frame or the 802.2/llc/snap frame
++ */
++ skb_pull(skb, hdrChop);
++
++ u32SkbLen = skb->len;
++ wlan_compute_rssi(priv, pRxPD);
++
++ if (os_upload_rx_packet(priv, skb)) {
++ PRINTM(ERROR, "RX Error: os_upload_rx_packet" " returns failure\n");
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++ priv->stats.rx_bytes += u32SkbLen;
++ priv->stats.rx_packets++;
++
++ PRINTM(DATA, "Data => kernel\n");
++
++ ret = WLAN_STATUS_SUCCESS;
++ done:
++ LEAVE();
++
++ return (ret);
++}
+diff --git a/drivers/net/wireless/marvell8686/wlan_scan.c b/drivers/net/wireless/marvell8686/wlan_scan.c
+new file mode 100644
+index 0000000..a6c4060
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_scan.c
+@@ -0,0 +1,3226 @@
++/** @file wlan_scan.c
++ *
++ * @brief Functions implementing wlan scan IOCTL and firmware command APIs
++ *
++ * IOCTL handlers as well as command preperation and response routines
++ * for sending scan commands to the firmware.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ *
++ * @sa wlan_scan.h
++ */
++/********************************************************
++Change Log:
++ 01/11/06: Initial revision. New scan code, relocate related functions
++ 01/19/06: Update specific scan routines to discard old results for adhoc
++ 01/31/06: Add support for selectively enabling the FW Scan channel filter
++
++************************************************************/
++
++#include "include.h"
++
++/********************************************************
++ Local Constants
++********************************************************/
++
++//! Approximate amount of data needed to pass a scan result back to iwlist
++#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
++ + MRVDRV_MAX_SSID_LENGTH \
++ + IW_EV_UINT_LEN \
++ + IW_EV_FREQ_LEN \
++ + IW_EV_QUAL_LEN \
++ + MRVDRV_MAX_SSID_LENGTH \
++ + IW_EV_PARAM_LEN \
++ + 40) /* 40 for WPAIE */
++
++//! Memory needed to store a max sized Channel List TLV for a firmware scan
++#define CHAN_TLV_MAX_SIZE (sizeof(MrvlIEtypesHeader_t) \
++ + (MRVDRV_MAX_CHANNELS_PER_SCAN \
++ * sizeof(ChanScanParamSet_t)))
++
++//! Memory needed to store a max number/size SSID TLV for a firmware scan
++#define SSID_TLV_MAX_SIZE (1 * sizeof(MrvlIEtypes_SsIdParamSet_t))
++
++//! WPS TLV MAX size is MAX IE size plus 2 bytes for u16 MRVL TLV extension
++#define WPS_TLV_MAX_SIZE (sizeof(IEEEtypes_VendorSpecific_t) + 2)
++
++//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max
++#define MAX_SCAN_CFG_ALLOC (sizeof(wlan_scan_cmd_config) \
++ + sizeof(MrvlIEtypes_NumProbes_t) \
++ + CHAN_TLV_MAX_SIZE \
++ + SSID_TLV_MAX_SIZE \
++ + WPS_TLV_MAX_SIZE)
++
++//! The maximum number of channels the firmware can scan per command
++#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
++
++/**
++ * @brief Number of channels to scan per firmware scan command issuance.
++ *
++ * Number restricted to prevent hitting the limit on the amount of scan data
++ * returned in a single firmware scan command.
++ */
++#define MRVDRV_CHANNELS_PER_SCAN_CMD 4
++
++//! Macro to enable/disable SSID checking before storing a scan table
++#ifdef DISCARD_BAD_SSID
++#define CHECK_SSID_IS_VALID(x) ssid_valid(&bssidEntry.Ssid)
++#else
++#define CHECK_SSID_IS_VALID(x) TRUE
++#endif
++
++/********************************************************
++ Local Variables and Types
++********************************************************/
++
++/**
++ * @brief Interally used to send a configured scan cmd between driver routines
++ */
++typedef union
++{
++ wlan_scan_cmd_config config; //!< Scan configuration (variable length)
++ u8 configAllocBuf[MAX_SCAN_CFG_ALLOC]; //!< Max allocated block
++} wlan_scan_cmd_config_tlv;
++
++/**
++ * @brief Check if a scanned network compatible with the driver settings
++ *
++ * WEP WPA WPA2 ad-hoc encrypt Network
++ * enabled enabled enabled AES mode Privacy WPA WPA2 Compatible
++ * 0 0 0 0 NONE 0 0 0 yes No security
++ * 0 1 0 0 x 1x 1 x yes WPA
++ * 0 0 1 0 x 1x x 1 yes WPA2
++ * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES
++ *
++ * 1 0 0 0 NONE 1 0 0 yes Static WEP
++ * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP
++ *
++ *
++ * @param Adapter A pointer to wlan_adapter
++ * @param index Index in ScanTable to check against current driver settings
++ * @param mode Network mode: Infrastructure or IBSS
++ *
++ * @return Index in ScanTable, or error code if negative
++ */
++static int
++IsNetworkCompatible(wlan_adapter * Adapter, int index, int mode)
++{
++ BSSDescriptor_t *pBSSDesc;
++
++ ENTER();
++
++ pBSSDesc = &Adapter->ScanTable[index];
++
++ /* Don't check for compatibility if roaming */
++ if ((Adapter->MediaConnectStatus == WlanMediaStateConnected)
++ && (Adapter->InfrastructureMode == Wlan802_11Infrastructure)
++ && (pBSSDesc->InfrastructureMode == Wlan802_11Infrastructure)) {
++ LEAVE();
++ return index;
++ }
++
++ if (Adapter->wps.SessionEnable == TRUE) {
++ PRINTM(INFO, "Return success directly in WPS period\n");
++ LEAVE();
++ return index;
++ }
++
++ if (pBSSDesc->InfrastructureMode == mode) {
++ if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
++ && !Adapter->SecInfo.WPAEnabled
++ && !Adapter->SecInfo.WPA2Enabled
++ && pBSSDesc->wpaIE.VendHdr.ElementId != WPA_IE
++ && pBSSDesc->rsnIE.IeeeHdr.ElementId != RSN_IE
++ && !Adapter->AdhocAESEnabled
++ && Adapter->SecInfo.EncryptionMode == CIPHER_NONE
++ && !pBSSDesc->Privacy) {
++ /* no security */
++ LEAVE();
++ return index;
++ } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled
++ && !Adapter->SecInfo.WPAEnabled
++ && !Adapter->SecInfo.WPA2Enabled
++ && !Adapter->AdhocAESEnabled && pBSSDesc->Privacy) {
++ /* static WEP enabled */
++ LEAVE();
++ return index;
++ } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
++ && Adapter->SecInfo.WPAEnabled
++ && !Adapter->SecInfo.WPA2Enabled
++ && (pBSSDesc->wpaIE.VendHdr.ElementId == WPA_IE)
++ && !Adapter->AdhocAESEnabled
++ /* Privacy bit may NOT be set in some APs like LinkSys WRT54G
++ && pBSSDesc->Privacy */
++ ) {
++ /* WPA enabled */
++ PRINTM(INFO, "IsNetworkCompatible() WPA: index=%d wpa_ie=%#x "
++ "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
++ "privacy=%#x\n",
++ index,
++ pBSSDesc->wpaIE.VendHdr.ElementId,
++ pBSSDesc->rsnIE.IeeeHdr.ElementId,
++ (Adapter->SecInfo.WEPStatus ==
++ Wlan802_11WEPEnabled) ? "e" : "d",
++ (Adapter->SecInfo.WPAEnabled) ? "e" : "d",
++ (Adapter->SecInfo.WPA2Enabled) ? "e" : "d",
++ Adapter->SecInfo.EncryptionMode, pBSSDesc->Privacy);
++ LEAVE();
++ return index;
++ } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
++ && !Adapter->SecInfo.WPAEnabled
++ && Adapter->SecInfo.WPA2Enabled
++ && (pBSSDesc->rsnIE.IeeeHdr.ElementId == RSN_IE)
++ && !Adapter->AdhocAESEnabled
++ /* Privacy bit may NOT be set in some APs like LinkSys WRT54G
++ && pBSSDesc->Privacy */
++ ) {
++ /* WPA2 enabled */
++ PRINTM(INFO, "IsNetworkCompatible() WPA2: index=%d wpa_ie=%#x "
++ "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
++ "privacy=%#x\n",
++ index,
++ pBSSDesc->wpaIE.VendHdr.ElementId,
++ pBSSDesc->rsnIE.IeeeHdr.ElementId,
++ (Adapter->SecInfo.WEPStatus ==
++ Wlan802_11WEPEnabled) ? "e" : "d",
++ (Adapter->SecInfo.WPAEnabled) ? "e" : "d",
++ (Adapter->SecInfo.WPA2Enabled) ? "e" : "d",
++ Adapter->SecInfo.EncryptionMode, pBSSDesc->Privacy);
++ LEAVE();
++ return index;
++ } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
++ && !Adapter->SecInfo.WPAEnabled
++ && !Adapter->SecInfo.WPA2Enabled
++ && (pBSSDesc->wpaIE.VendHdr.ElementId != WPA_IE)
++ && (pBSSDesc->rsnIE.IeeeHdr.ElementId != RSN_IE)
++ && Adapter->AdhocAESEnabled
++ && Adapter->SecInfo.EncryptionMode == CIPHER_NONE
++ && pBSSDesc->Privacy) {
++ /* Ad-hoc AES enabled */
++ LEAVE();
++ return index;
++ } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
++ && !Adapter->SecInfo.WPAEnabled
++ && !Adapter->SecInfo.WPA2Enabled
++ && (pBSSDesc->wpaIE.VendHdr.ElementId != WPA_IE)
++ && (pBSSDesc->rsnIE.IeeeHdr.ElementId != RSN_IE)
++ && !Adapter->AdhocAESEnabled
++ && Adapter->SecInfo.EncryptionMode != CIPHER_NONE
++ && pBSSDesc->Privacy) {
++ /* dynamic WEP enabled */
++ PRINTM(INFO, "IsNetworkCompatible() dynamic WEP: index=%d "
++ "wpa_ie=%#x wpa2_ie=%#x EncMode=%#x privacy=%#x\n",
++ index,
++ pBSSDesc->wpaIE.VendHdr.ElementId,
++ pBSSDesc->rsnIE.IeeeHdr.ElementId,
++ Adapter->SecInfo.EncryptionMode, pBSSDesc->Privacy);
++ LEAVE();
++ return index;
++ }
++
++ /* security doesn't match */
++ PRINTM(INFO, "IsNetworkCompatible() FAILED: index=%d wpa_ie=%#x "
++ "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n",
++ index,
++ pBSSDesc->wpaIE.VendHdr.ElementId,
++ pBSSDesc->rsnIE.IeeeHdr.ElementId,
++ (Adapter->SecInfo.WEPStatus ==
++ Wlan802_11WEPEnabled) ? "e" : "d",
++ (Adapter->SecInfo.WPAEnabled) ? "e" : "d",
++ (Adapter->SecInfo.WPA2Enabled) ? "e" : "d",
++ Adapter->SecInfo.EncryptionMode, pBSSDesc->Privacy);
++ LEAVE();
++ return -ECONNREFUSED;
++ }
++
++ /* mode doesn't match */
++ LEAVE();
++ return -ENETUNREACH;
++}
++
++/**
++ * @brief This function validates a SSID as being able to be printed
++ *
++ * @param pSsid SSID structure to validate
++ *
++ * @return TRUE or FALSE
++ */
++static BOOLEAN
++ssid_valid(WLAN_802_11_SSID * pSsid)
++{
++ int ssidIdx;
++
++ for (ssidIdx = 0; ssidIdx < pSsid->SsidLength; ssidIdx++) {
++ if (!isprint(pSsid->Ssid[ssidIdx])) {
++ return FALSE;
++ }
++ }
++
++ return TRUE;
++}
++
++/**
++ * @brief Post process the scan table after a new scan command has completed
++ *
++ * Inspect each entry of the scan table and try to find an entry that
++ * matches our current associated/joined network from the scan. If
++ * one is found, update the stored copy of the BSSDescriptor for our
++ * current network.
++ *
++ * Debug dump the current scan table contents if compiled accordingly.
++ *
++ * @param priv A pointer to wlan_private structure
++ *
++ * @return void
++ */
++static void
++wlan_scan_process_results(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int i;
++ int foundCurrent;
++
++ foundCurrent = FALSE;
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ Adapter->CurBssParams.BSSDescriptor.pBeaconBuf = NULL;
++ Adapter->CurBssParams.BSSDescriptor.beaconBufSize = 0;
++ Adapter->CurBssParams.BSSDescriptor.beaconBufSizeMax = 0;
++ i = FindSSIDInList(Adapter,
++ &Adapter->CurBssParams.BSSDescriptor.Ssid,
++ Adapter->CurBssParams.BSSDescriptor.MacAddress,
++ Adapter->InfrastructureMode);
++
++ if (i >= 0) {
++ PRINTM(INFO, "Found current ssid/bssid in list @ index #%d\n", i);
++ /* Make a copy of current BSSID descriptor */
++ memcpy(&Adapter->CurBssParams.BSSDescriptor,
++ &Adapter->ScanTable[i],
++ sizeof(Adapter->CurBssParams.BSSDescriptor));
++ }
++ }
++
++ for (i = 0; i < Adapter->NumInScanTable; i++) {
++ PRINTM(INFO, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, "
++ "RSSI[%03d], SSID[%s]\n",
++ i,
++ Adapter->ScanTable[i].MacAddress[0],
++ Adapter->ScanTable[i].MacAddress[1],
++ Adapter->ScanTable[i].MacAddress[2],
++ Adapter->ScanTable[i].MacAddress[3],
++ Adapter->ScanTable[i].MacAddress[4],
++ Adapter->ScanTable[i].MacAddress[5],
++ (s32) Adapter->ScanTable[i].Rssi,
++ Adapter->ScanTable[i].Ssid.Ssid);
++
++ }
++}
++
++/**
++ * @brief Create a channel list for the driver to scan based on region info
++ *
++ * Use the driver region/band information to construct a comprehensive list
++ * of channels to scan. This routine is used for any scan that is not
++ * provided a specific channel list to scan.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param scanChanList Output parameter: Resulting channel list to scan
++ * @param filteredScan Flag indicating whether or not a BSSID or SSID filter
++ * is being sent in the command to firmware. Used to
++ * increase the number of channels sent in a scan
++ * command and to disable the firmware channel scan
++ * filter.
++ *
++ * @return void
++ */
++static void
++wlan_scan_create_channel_list(wlan_private * priv,
++ ChanScanParamSet_t * scanChanList,
++ BOOLEAN filteredScan)
++{
++
++ wlan_adapter *Adapter = priv->adapter;
++ REGION_CHANNEL *scanRegion;
++ CHANNEL_FREQ_POWER *cfp;
++ int rgnIdx;
++ int chanIdx;
++ int nextChan;
++ u8 scanType;
++
++ chanIdx = 0;
++
++ /* Set the default scan type to the user specified type, will later
++ * be changed to passive on a per channel basis if restricted by
++ * regulatory requirements (11d or 11h)
++ */
++ scanType = Adapter->ScanType;
++
++ for (rgnIdx = 0; rgnIdx < NELEMENTS(Adapter->region_channel); rgnIdx++) {
++ if (wlan_get_state_11d(priv) == ENABLE_11D &&
++ Adapter->MediaConnectStatus != WlanMediaStateConnected) {
++ /* Scan all the supported chan for the first scan */
++ if (!Adapter->universal_channel[rgnIdx].Valid)
++ continue;
++ scanRegion = &Adapter->universal_channel[rgnIdx];
++
++ /* clear the parsed_region_chan for the first scan */
++ memset(&Adapter->parsed_region_chan, 0x00,
++ sizeof(Adapter->parsed_region_chan));
++ } else {
++ if (!Adapter->region_channel[rgnIdx].Valid)
++ continue;
++ scanRegion = &Adapter->region_channel[rgnIdx];
++ }
++
++ for (nextChan = 0;
++ nextChan < scanRegion->NrCFP; nextChan++, chanIdx++) {
++
++ cfp = scanRegion->CFP + nextChan;
++
++ if (wlan_get_state_11d(priv) == ENABLE_11D) {
++ scanType =
++ wlan_get_scan_type_11d(cfp->Channel,
++ &Adapter->parsed_region_chan);
++ }
++
++ switch (scanRegion->Band) {
++ case BAND_B:
++ case BAND_G:
++ default:
++ scanChanList[chanIdx].RadioType = HostCmd_SCAN_RADIO_TYPE_BG;
++ break;
++ }
++
++ if (scanType == HostCmd_SCAN_TYPE_PASSIVE) {
++ scanChanList[chanIdx].MaxScanTime =
++ wlan_cpu_to_le16(Adapter->PassiveScanTime);
++ scanChanList[chanIdx].ChanScanMode.PassiveScan = TRUE;
++ } else {
++ scanChanList[chanIdx].MaxScanTime =
++ wlan_cpu_to_le16(Adapter->ActiveScanTime);
++ scanChanList[chanIdx].ChanScanMode.PassiveScan = FALSE;
++ }
++
++ scanChanList[chanIdx].ChanNumber = cfp->Channel;
++
++ if (filteredScan) {
++ scanChanList[chanIdx].MaxScanTime =
++ wlan_cpu_to_le16(Adapter->SpecificScanTime);
++ scanChanList[chanIdx].ChanScanMode.DisableChanFilt = TRUE;
++ }
++ }
++ }
++}
++
++static void
++wlan_add_wps_probe_request_ie(wlan_private * priv, u8 ** ppTlvOut)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ MrvlIEtypesHeader_t *tlv;
++
++ if (Adapter->wps.wpsIe.VendHdr.Len) {
++ tlv = (MrvlIEtypesHeader_t *) * ppTlvOut;
++ tlv->Type = wlan_cpu_to_le16(TLV_TYPE_WPS_ENROLLEE_PROBE_REQ_TLV);
++ tlv->Len = wlan_cpu_to_le16(Adapter->wps.wpsIe.VendHdr.Len);
++ *ppTlvOut += sizeof(MrvlIEtypesHeader_t);
++ memcpy(*ppTlvOut,
++ Adapter->wps.wpsIe.VendHdr.Oui,
++ Adapter->wps.wpsIe.VendHdr.Len);
++ *ppTlvOut += (Adapter->wps.wpsIe.VendHdr.Len
++ + sizeof(MrvlIEtypesHeader_t));
++ }
++}
++
++/**
++ * @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
++ *
++ * Application layer or other functions can invoke wlan_scan_networks
++ * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
++ * This structure is used as the basis of one or many wlan_scan_cmd_config
++ * commands that are sent to the command processing module and sent to
++ * firmware.
++ *
++ * Create a wlan_scan_cmd_config based on the following user supplied
++ * parameters (if present):
++ * - SSID filter
++ * - BSSID filter
++ * - Number of Probes to be sent
++ * - Channel list
++ *
++ * If the SSID or BSSID filter is not present, disable/clear the filter.
++ * If the number of probes is not set, use the adapter default setting
++ * Qualify the channel
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param pUserScanIn NULL or pointer to scan configuration parameters
++ * @param pScanCfgOut Output parameter: Resulting scan configuration
++ * @param ppChanTlvOut Output parameter: Pointer to the start of the
++ * channel TLV portion of the output scan config
++ * @param pScanChanList Output parameter: Pointer to the resulting channel
++ * list to scan
++ * @param pMaxChanPerScan Output parameter: Number of channels to scan for
++ * each issuance of the firmware scan command
++ * @param pFilteredScan Output parameter: Flag indicating whether or not
++ * a BSSID or SSID filter is being sent in the
++ * command to firmware. Used to increase the number
++ * of channels sent in a scan command and to
++ * disable the firmware channel scan filter.
++ * @param pScanCurrentOnly Output parameter: Flag indicating whether or not
++ * we are only scanning our current active channel
++ *
++ * @return void
++ */
++static void
++wlan_scan_setup_scan_config(wlan_private * priv,
++ const wlan_ioctl_user_scan_cfg * pUserScanIn,
++ wlan_scan_cmd_config * pScanCfgOut,
++ MrvlIEtypes_ChanListParamSet_t ** ppChanTlvOut,
++ ChanScanParamSet_t * pScanChanList,
++ int *pMaxChanPerScan,
++ BOOLEAN * pFilteredScan,
++ BOOLEAN * pScanCurrentOnly)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ const u8 zeroMac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
++ MrvlIEtypes_NumProbes_t *pNumProbesTlv;
++ u8 *pTlvPos;
++ u16 numProbes;
++ u16 ssidLen;
++ int chanIdx;
++ int scanType;
++ int scanDur;
++ int channel;
++ int radioType;
++ int ssidIdx;
++ BOOLEAN ssidFilter;
++
++ MrvlIEtypes_WildCardSsIdParamSet_t *pWildCardSsidTlv;
++
++ /* The tlvBufferLen is calculated for each scan command. The TLVs added
++ * in this routine will be preserved since the routine that sends
++ * the command will append channelTLVs at *ppChanTlvOut. The difference
++ * between the *ppChanTlvOut and the tlvBuffer start will be used
++ * to calculate the size of anything we add in this routine.
++ */
++ pScanCfgOut->tlvBufferLen = 0;
++
++ /* Running tlv pointer. Assigned to ppChanTlvOut at end of function
++ * so later routines know where channels can be added to the command buf
++ */
++ pTlvPos = pScanCfgOut->tlvBuffer;
++
++ /*
++ * Set the initial scan paramters for progressive scanning. If a specific
++ * BSSID or SSID is used, the number of channels in the scan command
++ * will be increased to the absolute maximum
++ */
++ *pMaxChanPerScan = MRVDRV_MAX_CHANNELS_PER_SCAN;
++
++ /* Initialize the scan as un-filtered; the flag is later set to
++ * TRUE below if a SSID or BSSID filter is sent in the command
++ */
++ *pFilteredScan = FALSE;
++
++ /* Initialize the scan as not being only on the current channel. If
++ * the channel list is customized, only contains one channel, and
++ * is the active channel, this is set true and data flow is not halted.
++ */
++ *pScanCurrentOnly = FALSE;
++
++ if (pUserScanIn) {
++
++ /* Default the ssidFilter flag to TRUE, set false under certain
++ * wildcard conditions and qualified by the existence of an SSID
++ * list before marking the scan as filtered
++ */
++ ssidFilter = TRUE;
++
++ /* Set the bss type scan filter, use Adapter setting if unset */
++ pScanCfgOut->bssType = (pUserScanIn->bssType ? pUserScanIn->bssType :
++ Adapter->ScanMode);
++
++ /* Set the number of probes to send, use Adapter setting if unset */
++ numProbes = (pUserScanIn->numProbes ? pUserScanIn->numProbes :
++ Adapter->ScanProbes);
++
++ /*
++ * Set the BSSID filter to the incoming configuration,
++ * if non-zero. If not set, it will remain disabled (all zeros).
++ */
++ memcpy(pScanCfgOut->specificBSSID,
++ pUserScanIn->specificBSSID,
++ sizeof(pScanCfgOut->specificBSSID));
++
++ for (ssidIdx = 0; ((ssidIdx < NELEMENTS(pUserScanIn->ssidList))
++ && (*pUserScanIn->ssidList[ssidIdx].ssid
++ || pUserScanIn->ssidList[ssidIdx].maxLen));
++ ssidIdx++) {
++
++ ssidLen = strlen(pUserScanIn->ssidList[ssidIdx].ssid) + 1;
++
++ pWildCardSsidTlv = (MrvlIEtypes_WildCardSsIdParamSet_t *) pTlvPos;
++ pWildCardSsidTlv->Header.Type
++ = wlan_cpu_to_le16(TLV_TYPE_WILDCARDSSID);
++ pWildCardSsidTlv->Header.Len
++ = ssidLen + sizeof(pWildCardSsidTlv->MaxSsidLength);
++ pWildCardSsidTlv->MaxSsidLength
++ = pUserScanIn->ssidList[ssidIdx].maxLen;
++
++ memcpy(pWildCardSsidTlv->SsId,
++ pUserScanIn->ssidList[ssidIdx].ssid, ssidLen);
++
++ pTlvPos += (sizeof(pWildCardSsidTlv->Header)
++ + pWildCardSsidTlv->Header.Len);
++
++ pWildCardSsidTlv->Header.Len
++ = wlan_cpu_to_le16(pWildCardSsidTlv->Header.Len);
++
++ PRINTM(INFO, "Scan: ssidList[%d]: %s, %d\n",
++ ssidIdx,
++ pWildCardSsidTlv->SsId, pWildCardSsidTlv->MaxSsidLength);
++
++ /* Empty wildcard ssid with a maxlen will match many or potentially
++ * all SSIDs (maxlen == 32), therefore do not treat the scan
++ * as filtered.
++ */
++ if ((ssidLen == 0) && pWildCardSsidTlv->MaxSsidLength) {
++ ssidFilter = FALSE;
++ }
++ }
++
++ /*
++ * The default number of channels sent in the command is low to
++ * ensure the response buffer from the firmware does not truncate
++ * scan results. That is not an issue with an SSID or BSSID
++ * filter applied to the scan results in the firmware.
++ */
++ if ((ssidIdx && ssidFilter)
++ || memcmp(pScanCfgOut->specificBSSID, &zeroMac, sizeof(zeroMac))) {
++ *pFilteredScan = TRUE;
++ }
++
++ } else {
++ pScanCfgOut->bssType = Adapter->ScanMode;
++ numProbes = Adapter->ScanProbes;
++ }
++
++ /* If the input config or adapter has the number of Probes set, add tlv */
++ if (numProbes) {
++
++ PRINTM(INFO, "Scan: numProbes = %d\n", numProbes);
++
++ pNumProbesTlv = (MrvlIEtypes_NumProbes_t *) pTlvPos;
++ pNumProbesTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
++ pNumProbesTlv->Header.Len = sizeof(pNumProbesTlv->NumProbes);
++ pNumProbesTlv->NumProbes = wlan_cpu_to_le16(numProbes);
++
++ pTlvPos += sizeof(pNumProbesTlv->Header) + pNumProbesTlv->Header.Len;
++
++ pNumProbesTlv->Header.Len =
++ wlan_cpu_to_le16(pNumProbesTlv->Header.Len);
++ }
++
++ wlan_add_wps_probe_request_ie(priv, &pTlvPos);
++
++ /*
++ * Set the output for the channel TLV to the address in the tlv buffer
++ * past any TLVs that were added in this fuction (SSID, numProbes).
++ * Channel TLVs will be added past this for each scan command, preserving
++ * the TLVs that were previously added.
++ */
++ *ppChanTlvOut = (MrvlIEtypes_ChanListParamSet_t *) pTlvPos;
++
++ if (pUserScanIn && pUserScanIn->chanList[0].chanNumber) {
++
++ PRINTM(INFO, "Scan: Using supplied channel list\n");
++
++ for (chanIdx = 0;
++ chanIdx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
++ && pUserScanIn->chanList[chanIdx].chanNumber; chanIdx++) {
++
++ channel = pUserScanIn->chanList[chanIdx].chanNumber;
++ (pScanChanList + chanIdx)->ChanNumber = channel;
++
++ radioType = pUserScanIn->chanList[chanIdx].radioType;
++ (pScanChanList + chanIdx)->RadioType = radioType;
++
++ scanType = pUserScanIn->chanList[chanIdx].scanType;
++
++ if (scanType == HostCmd_SCAN_TYPE_PASSIVE) {
++ (pScanChanList + chanIdx)->ChanScanMode.PassiveScan = TRUE;
++ } else {
++ (pScanChanList + chanIdx)->ChanScanMode.PassiveScan = FALSE;
++ }
++
++ if (pUserScanIn->chanList[chanIdx].scanTime) {
++ scanDur = pUserScanIn->chanList[chanIdx].scanTime;
++ } else {
++ if (scanType == HostCmd_SCAN_TYPE_PASSIVE) {
++ scanDur = Adapter->PassiveScanTime;
++ } else if (*pFilteredScan) {
++ scanDur = Adapter->SpecificScanTime;
++ } else {
++ scanDur = Adapter->ActiveScanTime;
++ }
++ }
++
++ (pScanChanList + chanIdx)->MinScanTime =
++ wlan_cpu_to_le16(scanDur);
++ (pScanChanList + chanIdx)->MaxScanTime =
++ wlan_cpu_to_le16(scanDur);
++ }
++
++ /* Check if we are only scanning the current channel */
++ if ((chanIdx == 1)
++ && (pUserScanIn->chanList[0].chanNumber
++ == priv->adapter->CurBssParams.BSSDescriptor.Channel)) {
++ *pScanCurrentOnly = TRUE;
++ PRINTM(INFO, "Scan: Scanning current channel only");
++ }
++
++ } else {
++ PRINTM(INFO, "Scan: Creating full region channel list\n");
++ wlan_scan_create_channel_list(priv, pScanChanList, *pFilteredScan);
++ }
++}
++
++/**
++ * @brief Construct and send multiple scan config commands to the firmware
++ *
++ * Previous routines have created a wlan_scan_cmd_config with any requested
++ * TLVs. This function splits the channel TLV into maxChanPerScan lists
++ * and sends the portion of the channel TLV along with the other TLVs
++ * to the wlan_cmd routines for execution in the firmware.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param maxChanPerScan Maximum number channels to be included in each
++ * scan command sent to firmware
++ * @param filteredScan Flag indicating whether or not a BSSID or SSID
++ * filter is being used for the firmware command
++ * scan command sent to firmware
++ * @param pScanCfgOut Scan configuration used for this scan.
++ * @param pChanTlvOut Pointer in the pScanCfgOut where the channel TLV
++ * should start. This is past any other TLVs that
++ * must be sent down in each firmware command.
++ * @param pScanChanList List of channels to scan in maxChanPerScan segments
++ *
++ * @return WLAN_STATUS_SUCCESS or error return otherwise
++ */
++static int
++wlan_scan_channel_list(wlan_private * priv,
++ int maxChanPerScan,
++ BOOLEAN filteredScan,
++ wlan_scan_cmd_config * pScanCfgOut,
++ MrvlIEtypes_ChanListParamSet_t * pChanTlvOut,
++ ChanScanParamSet_t * pScanChanList)
++{
++ ChanScanParamSet_t *pTmpChan;
++ ChanScanParamSet_t *pStartChan;
++ u8 scanBand;
++ int doneEarly;
++ int tlvIdx;
++ int totalscantime;
++ int ret;
++
++ ENTER();
++
++ if (pScanCfgOut == 0 || pChanTlvOut == 0 || pScanChanList == 0) {
++ PRINTM(INFO, "Scan: Null detect: %p, %p, %p\n",
++ pScanCfgOut, pChanTlvOut, pScanChanList);
++ return WLAN_STATUS_FAILURE;
++ }
++
++ ret = WLAN_STATUS_SUCCESS;
++
++ pChanTlvOut->Header.Type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
++
++ /* Set the temp channel struct pointer to the start of the desired list */
++ pTmpChan = pScanChanList;
++
++ /* Loop through the desired channel list, sending a new firmware scan
++ * commands for each maxChanPerScan channels (or for 1,6,11 individually
++ * if configured accordingly)
++ */
++ while (pTmpChan->ChanNumber) {
++
++ tlvIdx = 0;
++ totalscantime = 0;
++ pChanTlvOut->Header.Len = 0;
++ scanBand = pTmpChan->RadioType;
++ pStartChan = pTmpChan;
++ doneEarly = FALSE;
++
++ /* Construct the Channel TLV for the scan command. Continue to
++ * insert channel TLVs until:
++ * - the tlvIdx hits the maximum configured per scan command
++ * - the next channel to insert is 0 (end of desired channel list)
++ * - doneEarly is set (controlling individual scanning of 1,6,11)
++ */
++ while (tlvIdx < maxChanPerScan && pTmpChan->ChanNumber && !doneEarly) {
++
++ PRINTM(INFO, "Scan: Chan(%3d), Radio(%d), Mode(%d,%d), Dur(%d)\n",
++ pTmpChan->ChanNumber,
++ pTmpChan->RadioType,
++ pTmpChan->ChanScanMode.PassiveScan,
++ pTmpChan->ChanScanMode.DisableChanFilt,
++ pTmpChan->MaxScanTime);
++
++ /* Copy the current channel TLV to the command being prepared */
++ memcpy(pChanTlvOut->ChanScanParam + tlvIdx,
++ pTmpChan, sizeof(pChanTlvOut->ChanScanParam));
++
++ /* Increment the TLV header length by the size appended */
++ pChanTlvOut->Header.Len += sizeof(pChanTlvOut->ChanScanParam);
++
++ /*
++ * The tlv buffer length is set to the number of bytes of the
++ * between the channel tlv pointer and the start of the
++ * tlv buffer. This compensates for any TLVs that were appended
++ * before the channel list.
++ */
++ pScanCfgOut->tlvBufferLen = ((u8 *) pChanTlvOut
++ - pScanCfgOut->tlvBuffer);
++
++ /* Add the size of the channel tlv header and the data length */
++ pScanCfgOut->tlvBufferLen += (sizeof(pChanTlvOut->Header)
++ + pChanTlvOut->Header.Len);
++
++ /* Increment the index to the channel tlv we are constructing */
++ tlvIdx++;
++
++ /* Count the total scan time per command */
++ totalscantime += pTmpChan->MaxScanTime;
++
++ doneEarly = FALSE;
++
++ /* Stop the loop if the *current* channel is in the 1,6,11 set
++ * and we are not filtering on a BSSID or SSID.
++ */
++ if (!filteredScan && (pTmpChan->ChanNumber == 1
++ || pTmpChan->ChanNumber == 6
++ || pTmpChan->ChanNumber == 11)) {
++ doneEarly = TRUE;
++ }
++
++ /* Increment the tmp pointer to the next channel to be scanned */
++ pTmpChan++;
++
++ /* Stop the loop if the *next* channel is in the 1,6,11 set.
++ * This will cause it to be the only channel scanned on the next
++ * interation
++ */
++ if (!filteredScan && (pTmpChan->ChanNumber == 1
++ || pTmpChan->ChanNumber == 6
++ || pTmpChan->ChanNumber == 11)) {
++ doneEarly = TRUE;
++ }
++ }
++
++ /* The total scan time should be less than scan command timeout value */
++ if (totalscantime > MRVDRV_MAX_TOTAL_SCAN_TIME) {
++ PRINTM(MSG,
++ "Total scan time %d ms is over limit (%d ms), scan skipped\n",
++ totalscantime, MRVDRV_MAX_TOTAL_SCAN_TIME);
++ ret = WLAN_STATUS_FAILURE;
++ break;
++ }
++
++ pChanTlvOut->Header.Len = wlan_cpu_to_le16(pChanTlvOut->Header.Len);
++
++ /* Send the scan command to the firmware with the specified cfg */
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SCAN, 0,
++ HostCmd_OPTION_WAITFORRSP, 0,
++ pScanCfgOut);
++ }
++
++ LEAVE();
++
++ if (ret) {
++ return WLAN_STATUS_FAILURE;
++ }
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Internal function used to start a scan based on an input config
++ *
++ * Use the input user scan configuration information when provided in
++ * order to send the appropriate scan commands to firmware to populate or
++ * update the internal driver scan table
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param pUserScanIn Pointer to the input configuration for the requested
++ * scan.
++ *
++ * @return WLAN_STATUS_SUCCESS or < 0 if error
++ */
++static int
++wlan_scan_networks(wlan_private * priv,
++ const wlan_ioctl_user_scan_cfg * pUserScanIn)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ MrvlIEtypes_ChanListParamSet_t *pChanTlvOut;
++
++ ChanScanParamSet_t scanChanList[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
++ wlan_scan_cmd_config_tlv scanCfgOut;
++ BOOLEAN keepPreviousScan;
++ BOOLEAN filteredScan;
++ BOOLEAN scanCurrentChanOnly;
++ int maxChanPerScan;
++ int ret;
++ BOOLEAN bBgScan;
++
++ ENTER();
++
++ memset(scanChanList, 0x00, sizeof(scanChanList));
++ memset(&scanCfgOut, 0x00, sizeof(scanCfgOut));
++
++ keepPreviousScan = FALSE;
++
++ wlan_scan_setup_scan_config(priv,
++ pUserScanIn,
++ &scanCfgOut.config,
++ &pChanTlvOut,
++ scanChanList,
++ &maxChanPerScan,
++ &filteredScan, &scanCurrentChanOnly);
++
++ if (pUserScanIn) {
++ keepPreviousScan = pUserScanIn->keepPreviousScan;
++ }
++
++ if (keepPreviousScan == FALSE) {
++ memset(Adapter->ScanTable, 0x00,
++ sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
++ Adapter->NumInScanTable = 0;
++ Adapter->pBeaconBufEnd = Adapter->beaconBuffer;
++ }
++
++ /* Keep the data path active if we are only scanning our current channel */
++ if (!scanCurrentChanOnly) {
++ PRINTM(INFO, "Scan: WMM Queue stop\n");
++ priv->wlan_dev.netdev->watchdog_timeo = MRVDRV_SCAN_WATCHDOG_TIMEOUT;
++ /* If WMM queues are in use, only stop the internal data queues */
++ wmm_stop_queue(priv);
++ }
++
++ bBgScan = priv->adapter->bgScanConfig->Enable;
++ if (priv->adapter->bgScanConfig->Enable == TRUE) {
++ wlan_bg_scan_enable(priv, FALSE);
++ }
++
++ ret = wlan_scan_channel_list(priv,
++ maxChanPerScan,
++ filteredScan,
++ &scanCfgOut.config,
++ pChanTlvOut, scanChanList);
++
++ /* Process the resulting scan table:
++ * - Remove any bad ssids
++ * - Update our current BSS information from scan data
++ */
++ wlan_scan_process_results(priv);
++
++ if (bBgScan == TRUE) {
++ wlan_bg_scan_enable(priv, TRUE);
++ }
++
++ PRINTM(INFO, "Scan: WMM Queue start\n");
++
++ priv->wlan_dev.netdev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ wmm_start_queue(priv);
++ }
++ os_carrier_on(priv);
++ os_start_queue(priv);
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Create a brief scan resp to relay basic BSS info to the app layer
++ *
++ * When the beacon/probe response has not been buffered, use the saved BSS
++ * information available to provide a minimum response for the application
++ * ioctl retrieval routines. Include:
++ * - Timestamp
++ * - Beacon Period
++ * - Capabilities (including WMM Element if available)
++ * - SSID
++ *
++ * @param ppBuffer Output parameter: Buffer used to create basic scan rsp
++ * @param pBSSDesc Pointer to a BSS entry in the scan table to create
++ * scan response from for delivery to the application layer
++ *
++ * @return void
++ */
++static void
++wlan_scan_create_brief_table_entry(u8 ** ppBuffer, BSSDescriptor_t * pBSSDesc)
++{
++ u8 *pTmpBuf = *ppBuffer;
++ u8 tmpSSIDHdr[2];
++ u8 ieLen;
++
++ if (copy_to_user(pTmpBuf, pBSSDesc->TimeStamp,
++ sizeof(pBSSDesc->TimeStamp))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return;
++ }
++ pTmpBuf += sizeof(pBSSDesc->TimeStamp);
++
++ if (copy_to_user(pTmpBuf, &pBSSDesc->BeaconPeriod,
++ sizeof(pBSSDesc->BeaconPeriod))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return;
++ }
++ pTmpBuf += sizeof(pBSSDesc->BeaconPeriod);
++
++ if (copy_to_user(pTmpBuf, &pBSSDesc->Cap, sizeof(pBSSDesc->Cap))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return;
++ }
++ pTmpBuf += sizeof(pBSSDesc->Cap);
++
++ tmpSSIDHdr[0] = 0; /* Element ID for SSID is zero */
++ tmpSSIDHdr[1] = pBSSDesc->Ssid.SsidLength;
++ if (copy_to_user(pTmpBuf, tmpSSIDHdr, sizeof(tmpSSIDHdr))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return;
++ }
++ pTmpBuf += sizeof(tmpSSIDHdr);
++
++ if (copy_to_user(pTmpBuf, pBSSDesc->Ssid.Ssid, pBSSDesc->Ssid.SsidLength)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return;
++ }
++ pTmpBuf += pBSSDesc->Ssid.SsidLength;
++
++ if (pBSSDesc->wmmIE.VendHdr.ElementId == WMM_IE) {
++ ieLen = sizeof(IEEEtypes_Header_t) + pBSSDesc->wmmIE.VendHdr.Len;
++ if (copy_to_user(pTmpBuf, &pBSSDesc->wmmIE, ieLen)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return;
++ }
++
++ pTmpBuf += ieLen;
++ }
++
++ if (pBSSDesc->wpaIE.VendHdr.ElementId == WPA_IE) {
++ ieLen = sizeof(IEEEtypes_Header_t) + pBSSDesc->wpaIE.VendHdr.Len;
++ if (copy_to_user(pTmpBuf, &pBSSDesc->wpaIE, ieLen)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return;
++ }
++
++ pTmpBuf += ieLen;
++ }
++
++ if (pBSSDesc->rsnIE.IeeeHdr.ElementId == RSN_IE) {
++ ieLen = sizeof(IEEEtypes_Header_t) + pBSSDesc->rsnIE.IeeeHdr.Len;
++ if (copy_to_user(pTmpBuf, &pBSSDesc->rsnIE, ieLen)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return;
++ }
++
++ pTmpBuf += ieLen;
++ }
++
++ *ppBuffer = pTmpBuf;
++}
++
++/**
++ * @brief Inspect the scan response buffer for pointers to expected TLVs
++ *
++ * TLVs can be included at the end of the scan response BSS information.
++ * Parse the data in the buffer for pointers to TLVs that can potentially
++ * be passed back in the response
++ *
++ * @param pTlv Pointer to the start of the TLV buffer to parse
++ * @param tlvBufSize Size of the TLV buffer
++ * @param ppTsfTlv Output parameter: Pointer to the TSF TLV if found
++ *
++ * @return void
++ */
++static void
++wlan_ret_802_11_scan_get_tlv_ptrs(MrvlIEtypes_Data_t * pTlv,
++ int tlvBufSize,
++ MrvlIEtypes_TsfTimestamp_t ** ppTsfTlv)
++{
++ MrvlIEtypes_Data_t *pCurrentTlv;
++ int tlvBufLeft;
++ u16 tlvType;
++ u16 tlvLen;
++
++ pCurrentTlv = pTlv;
++ tlvBufLeft = tlvBufSize;
++ *ppTsfTlv = NULL;
++
++ PRINTM(INFO, "SCAN_RESP: tlvBufSize = %d\n", tlvBufSize);
++ HEXDUMP("SCAN_RESP: TLV Buf", (u8 *) pTlv, tlvBufSize);
++
++ while (tlvBufLeft >= sizeof(MrvlIEtypesHeader_t)) {
++ tlvType = wlan_le16_to_cpu(pCurrentTlv->Header.Type);
++ tlvLen = wlan_le16_to_cpu(pCurrentTlv->Header.Len);
++
++ switch (tlvType) {
++ case TLV_TYPE_TSFTIMESTAMP:
++ PRINTM(INFO, "SCAN_RESP: TSF Timestamp TLV, len = %d\n", tlvLen);
++ *ppTsfTlv = (MrvlIEtypes_TsfTimestamp_t *) pCurrentTlv;
++ break;
++
++ default:
++ PRINTM(INFO, "SCAN_RESP: Unhandled TLV = %d\n", tlvType);
++ /* Give up, this seems corrupted */
++ return;
++ } /* switch */
++
++ tlvBufLeft -= (sizeof(pTlv->Header) + tlvLen);
++ pCurrentTlv = (MrvlIEtypes_Data_t *) (pCurrentTlv->Data + tlvLen);
++ } /* while */
++}
++
++/**
++ * @brief Interpret a BSS scan response returned from the firmware
++ *
++ * Parse the various fixed fields and IEs passed back for a a BSS probe
++ * response or beacon from the scan command. Record information as needed
++ * in the scan table BSSDescriptor_t for that entry.
++ *
++ * @param pBSSIDEntry Output parameter: Pointer to the BSS Entry
++ *
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++InterpretBSSDescriptionWithIE(BSSDescriptor_t * pBSSEntry,
++ u8 ** pBeaconInfo, int *bytesLeft)
++{
++ IEEEtypes_ElementId_e elemID;
++ IEEEtypes_FhParamSet_t *pFH;
++ IEEEtypes_DsParamSet_t *pDS;
++ IEEEtypes_CfParamSet_t *pCF;
++ IEEEtypes_IbssParamSet_t *pIbss;
++ IEEEtypes_CapInfo_t *pCap;
++ WLAN_802_11_FIXED_IEs fixedIE;
++ u8 *pCurrentPtr;
++ u8 *pRate;
++ u8 elemLen;
++ u16 totalIeLen;
++ u8 bytesToCopy;
++ u8 rateSize;
++ u16 beaconSize;
++ BOOLEAN foundDataRateIE;
++ int bytesLeftForCurrentBeacon;
++ IEEEtypes_ERPInfo_t *pERPInfo;
++
++ IEEEtypes_VendorSpecific_t *pVendorIe;
++ const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
++ const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
++ const u8 wps_oui[4] = { 0x00, 0x50, 0xf2, 0x04 };
++
++ IEEEtypes_CountryInfoSet_t *pcountryinfo;
++
++ ENTER();
++
++ foundDataRateIE = FALSE;
++ rateSize = 0;
++ beaconSize = 0;
++
++ if (*bytesLeft >= sizeof(beaconSize)) {
++ /* Extract & convert beacon size from the command buffer */
++ memcpy(&beaconSize, *pBeaconInfo, sizeof(beaconSize));
++ beaconSize = wlan_le16_to_cpu(beaconSize);
++ *bytesLeft -= sizeof(beaconSize);
++ *pBeaconInfo += sizeof(beaconSize);
++ }
++
++ if (beaconSize == 0 || beaconSize > *bytesLeft) {
++
++ *pBeaconInfo += *bytesLeft;
++ *bytesLeft = 0;
++
++ return WLAN_STATUS_FAILURE;
++ }
++
++ /* Initialize the current working beacon pointer for this BSS iteration */
++ pCurrentPtr = *pBeaconInfo;
++
++ /* Advance the return beacon pointer past the current beacon */
++ *pBeaconInfo += beaconSize;
++ *bytesLeft -= beaconSize;
++
++ bytesLeftForCurrentBeacon = beaconSize;
++
++ memcpy(pBSSEntry->MacAddress, pCurrentPtr, MRVDRV_ETH_ADDR_LEN);
++ PRINTM(INFO, "InterpretIE: AP MAC Addr-%02x:%02x:%02x:%02x:%02x:%02x\n",
++ pBSSEntry->MacAddress[0], pBSSEntry->MacAddress[1],
++ pBSSEntry->MacAddress[2], pBSSEntry->MacAddress[3],
++ pBSSEntry->MacAddress[4], pBSSEntry->MacAddress[5]);
++
++ pCurrentPtr += MRVDRV_ETH_ADDR_LEN;
++ bytesLeftForCurrentBeacon -= MRVDRV_ETH_ADDR_LEN;
++
++ if (bytesLeftForCurrentBeacon < 12) {
++ PRINTM(INFO, "InterpretIE: Not enough bytes left\n");
++ return WLAN_STATUS_FAILURE;
++ }
++
++ /*
++ * next 4 fields are RSSI, time stamp, beacon interval,
++ * and capability information
++ */
++
++ /* RSSI is 1 byte long */
++ pBSSEntry->Rssi = wlan_le32_to_cpu((LONG) (*pCurrentPtr));
++ PRINTM(INFO, "InterpretIE: RSSI=%02X\n", *pCurrentPtr);
++ pCurrentPtr += 1;
++ bytesLeftForCurrentBeacon -= 1;
++
++ /*
++ * The RSSI is not part of the beacon/probe response. After we have
++ * advanced pCurrentPtr past the RSSI field, save the remaining
++ * data for use at the application layer
++ */
++ pBSSEntry->pBeaconBuf = pCurrentPtr;
++ pBSSEntry->beaconBufSize = bytesLeftForCurrentBeacon;
++
++ /* time stamp is 8 bytes long */
++ memcpy(fixedIE.Timestamp, pCurrentPtr, 8);
++ memcpy(pBSSEntry->TimeStamp, pCurrentPtr, 8);
++ pCurrentPtr += 8;
++ bytesLeftForCurrentBeacon -= 8;
++
++ /* beacon interval is 2 bytes long */
++ memcpy(&fixedIE.BeaconInterval, pCurrentPtr, 2);
++ pBSSEntry->BeaconPeriod = wlan_le16_to_cpu(fixedIE.BeaconInterval);
++ pCurrentPtr += 2;
++ bytesLeftForCurrentBeacon -= 2;
++
++ /* capability information is 2 bytes long */
++ memcpy(&fixedIE.Capabilities, pCurrentPtr, 2);
++ PRINTM(INFO, "InterpretIE: fixedIE.Capabilities=0x%X\n",
++ fixedIE.Capabilities);
++ fixedIE.Capabilities = wlan_le16_to_cpu(fixedIE.Capabilities);
++ pCap = (IEEEtypes_CapInfo_t *) & fixedIE.Capabilities;
++ memcpy(&pBSSEntry->Cap, pCap, sizeof(IEEEtypes_CapInfo_t));
++ pCurrentPtr += 2;
++ bytesLeftForCurrentBeacon -= 2;
++
++ /* rest of the current buffer are IE's */
++ PRINTM(INFO, "InterpretIE: IELength for this AP = %d\n",
++ bytesLeftForCurrentBeacon);
++
++ HEXDUMP("InterpretIE: IE info", (u8 *) pCurrentPtr,
++ bytesLeftForCurrentBeacon);
++
++ if (pCap->Privacy) {
++ PRINTM(INFO, "InterpretIE: AP WEP enabled\n");
++ pBSSEntry->Privacy = Wlan802_11PrivFilter8021xWEP;
++ } else {
++ pBSSEntry->Privacy = Wlan802_11PrivFilterAcceptAll;
++ }
++
++ if (pCap->Ibss == 1) {
++ pBSSEntry->InfrastructureMode = Wlan802_11IBSS;
++ } else {
++ pBSSEntry->InfrastructureMode = Wlan802_11Infrastructure;
++ }
++
++ /* process variable IE */
++ while (bytesLeftForCurrentBeacon >= 2) {
++ elemID = (IEEEtypes_ElementId_e) (*((u8 *) pCurrentPtr));
++ elemLen = *((u8 *) pCurrentPtr + 1);
++ totalIeLen = elemLen + sizeof(IEEEtypes_Header_t);
++
++ if (bytesLeftForCurrentBeacon < elemLen) {
++ PRINTM(INFO, "InterpretIE: Error in processing IE, "
++ "bytes left < IE length\n");
++ bytesLeftForCurrentBeacon = 0;
++ continue;
++ }
++
++ switch (elemID) {
++
++ case SSID:
++ pBSSEntry->Ssid.SsidLength = elemLen;
++ memcpy(pBSSEntry->Ssid.Ssid, (pCurrentPtr + 2), elemLen);
++ PRINTM(INFO, "InterpretIE: Ssid: %-32s\n", pBSSEntry->Ssid.Ssid);
++ break;
++
++ case SUPPORTED_RATES:
++ memcpy(pBSSEntry->DataRates, pCurrentPtr + 2, elemLen);
++ memcpy(pBSSEntry->SupportedRates, pCurrentPtr + 2, elemLen);
++ HEXDUMP("InterpretIE: SupportedRates:",
++ pBSSEntry->SupportedRates, elemLen);
++ rateSize = elemLen;
++ foundDataRateIE = TRUE;
++ break;
++
++ case EXTRA_IE:
++ PRINTM(INFO, "InterpretIE: EXTRA_IE Found!\n");
++ pBSSEntry->extra_ie = 1;
++ break;
++
++ case FH_PARAM_SET:
++ pFH = (IEEEtypes_FhParamSet_t *) pCurrentPtr;
++ pBSSEntry->NetworkTypeInUse = Wlan802_11FH;
++ memcpy(&pBSSEntry->PhyParamSet.FhParamSet, pFH,
++ sizeof(IEEEtypes_FhParamSet_t));
++ pBSSEntry->PhyParamSet.FhParamSet.DwellTime
++ =
++ wlan_le16_to_cpu(pBSSEntry->PhyParamSet.FhParamSet.DwellTime);
++ break;
++
++ case DS_PARAM_SET:
++ pDS = (IEEEtypes_DsParamSet_t *) pCurrentPtr;
++
++ pBSSEntry->NetworkTypeInUse = Wlan802_11DS;
++ pBSSEntry->Channel = pDS->CurrentChan;
++
++ memcpy(&pBSSEntry->PhyParamSet.DsParamSet, pDS,
++ sizeof(IEEEtypes_DsParamSet_t));
++ break;
++
++ case CF_PARAM_SET:
++ pCF = (IEEEtypes_CfParamSet_t *) pCurrentPtr;
++ memcpy(&pBSSEntry->SsParamSet.CfParamSet, pCF,
++ sizeof(IEEEtypes_CfParamSet_t));
++ break;
++
++ case IBSS_PARAM_SET:
++ pIbss = (IEEEtypes_IbssParamSet_t *) pCurrentPtr;
++ pBSSEntry->ATIMWindow = wlan_le32_to_cpu(pIbss->AtimWindow);
++ memcpy(&pBSSEntry->SsParamSet.IbssParamSet, pIbss,
++ sizeof(IEEEtypes_IbssParamSet_t));
++ break;
++
++ /* Handle Country Info IE */
++ case COUNTRY_INFO:
++ pcountryinfo = (IEEEtypes_CountryInfoSet_t *) pCurrentPtr;
++
++ if (pcountryinfo->Len < sizeof(pcountryinfo->CountryCode) ||
++ pcountryinfo->Len + 2 >
++ sizeof(IEEEtypes_CountryInfoFullSet_t)) {
++ PRINTM(INFO,
++ "InterpretIE: 11D- Err "
++ "CountryInfo len =%d min=%d max=%d\n",
++ pcountryinfo->Len, sizeof(pcountryinfo->CountryCode),
++ sizeof(IEEEtypes_CountryInfoFullSet_t));
++ LEAVE();
++ return WLAN_STATUS_FAILURE;
++ }
++
++ memcpy(&pBSSEntry->CountryInfo,
++ pcountryinfo, pcountryinfo->Len + 2);
++ HEXDUMP("InterpretIE: 11D- CountryInfo:",
++ (u8 *) pcountryinfo, (u32) (pcountryinfo->Len + 2));
++ break;
++ case ERP_INFO:
++ pERPInfo = (IEEEtypes_ERPInfo_t *) pCurrentPtr;
++ pBSSEntry->ERPFlags = pERPInfo->ERPFlags;
++ break;
++ case EXTENDED_SUPPORTED_RATES:
++ /*
++ * only process extended supported rate
++ * if data rate is already found.
++ * data rate IE should come before
++ * extended supported rate IE
++ */
++ if (foundDataRateIE) {
++ if ((elemLen + rateSize) > WLAN_SUPPORTED_RATES) {
++ bytesToCopy = (WLAN_SUPPORTED_RATES - rateSize);
++ } else {
++ bytesToCopy = elemLen;
++ }
++
++ pRate = (u8 *) pBSSEntry->DataRates;
++ pRate += rateSize;
++ memcpy(pRate, pCurrentPtr + 2, bytesToCopy);
++
++ pRate = (u8 *) pBSSEntry->SupportedRates;
++ pRate += rateSize;
++ memcpy(pRate, pCurrentPtr + 2, bytesToCopy);
++ }
++ HEXDUMP("InterpretIE: ExtSupportedRates:",
++ pBSSEntry->SupportedRates, elemLen + rateSize);
++ break;
++
++ case VENDOR_SPECIFIC_221:
++ pVendorIe = (IEEEtypes_VendorSpecific_t *) pCurrentPtr;
++
++ if ((!memcmp
++ (pVendorIe->VendHdr.Oui, wpa_oui,
++ sizeof(pVendorIe->VendHdr.Oui)))
++ && (pVendorIe->VendHdr.OuiType == wpa_oui[3])) {
++ pBSSEntry->wpaIE.VendHdr.Len
++ = (MIN(totalIeLen, sizeof(pBSSEntry->wpaIE))
++ - sizeof(IEEEtypes_Header_t));
++
++ memcpy(&pBSSEntry->wpaIE,
++ pCurrentPtr,
++ (pBSSEntry->wpaIE.VendHdr.Len
++ + sizeof(IEEEtypes_Header_t)));
++
++ HEXDUMP("InterpretIE: Resp WPA_IE",
++ (u8 *) & pBSSEntry->wpaIE,
++ (pBSSEntry->wpaIE.VendHdr.Len
++ + sizeof(IEEEtypes_Header_t)));
++ } else
++ if ((!memcmp
++ (pVendorIe->VendHdr.Oui, wmm_oui,
++ sizeof(pVendorIe->VendHdr.Oui)))
++ && (pVendorIe->VendHdr.OuiType == wmm_oui[3])) {
++ if (totalIeLen == sizeof(IEEEtypes_WmmParameter_t)
++ || totalIeLen == sizeof(IEEEtypes_WmmInfo_t)) {
++
++ /* Only accept and copy the WMM IE if it matches
++ * the size expected for the WMM Info IE or the
++ * WMM Parameter IE.
++ */
++ memcpy((u8 *) & pBSSEntry->wmmIE, pCurrentPtr,
++ totalIeLen);
++ HEXDUMP("InterpretIE: Resp WMM_IE",
++ (u8 *) & pBSSEntry->wmmIE, totalIeLen);
++ }
++ } else
++ if ((!memcmp
++ (pVendorIe->VendHdr.Oui, wps_oui,
++ sizeof(pVendorIe->VendHdr.Oui)))
++ && (pVendorIe->VendHdr.OuiType == wps_oui[3])) {
++ memcpy((u8 *) & pBSSEntry->wpsIE, pCurrentPtr, totalIeLen);
++ HEXDUMP("InterpretIE: Resp WPS_IE",
++ (u8 *) & pBSSEntry->wpsIE, totalIeLen);
++ }
++ break;
++ case RSN_IE:
++ pBSSEntry->rsnIE.IeeeHdr.Len
++ = (MIN(totalIeLen, sizeof(pBSSEntry->rsnIE))
++ - sizeof(IEEEtypes_Header_t));
++
++ memcpy(&pBSSEntry->rsnIE,
++ pCurrentPtr,
++ pBSSEntry->rsnIE.IeeeHdr.Len + sizeof(IEEEtypes_Header_t));
++
++ HEXDUMP("InterpretIE: Resp RSN_IE",
++ (u8 *) & pBSSEntry->rsnIE,
++ pBSSEntry->rsnIE.IeeeHdr.Len +
++ sizeof(IEEEtypes_Header_t));
++ break;
++ }
++
++ pCurrentPtr += elemLen + 2;
++
++ /* need to account for IE ID and IE Len */
++ bytesLeftForCurrentBeacon -= (elemLen + 2);
++
++ } /* while (bytesLeftForCurrentBeacon > 2) */
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Compare two SSIDs
++ *
++ * @param ssid1 A pointer to ssid to compare
++ * @param ssid2 A pointer to ssid to compare
++ *
++ * @return 0--ssid is same, otherwise is different
++ */
++int
++SSIDcmp(WLAN_802_11_SSID * ssid1, WLAN_802_11_SSID * ssid2)
++{
++ if (!ssid1 || !ssid2)
++ return -1;
++
++ if (ssid1->SsidLength != ssid2->SsidLength)
++ return -1;
++
++ return memcmp(ssid1->Ssid, ssid2->Ssid, ssid1->SsidLength);
++}
++
++/**
++ * @brief This function finds a specific compatible BSSID in the scan list
++ *
++ * @param Adapter A pointer to wlan_adapter
++ * @param bssid BSSID to find in the scan list
++ * @param mode Network mode: Infrastructure or IBSS
++ *
++ * @return index in BSSID list, or error return code (< 0)
++ */
++int
++FindBSSIDInList(wlan_adapter * Adapter, u8 * bssid, int mode)
++{
++ int ret = -ENETUNREACH;
++ int i;
++
++ if (!bssid)
++ return -EFAULT;
++
++ PRINTM(INFO, "FindBSSID: Num of BSSIDs = %d\n", Adapter->NumInScanTable);
++
++ /* Look through the scan table for a compatible match. The ret return
++ * variable will be equal to the index in the scan table (greater
++ * than zero) if the network is compatible. The loop will continue
++ * past a matched bssid that is not compatible in case there is an
++ * AP with multiple SSIDs assigned to the same BSSID
++ */
++ for (i = 0; ret < 0 && i < Adapter->NumInScanTable; i++) {
++ if (!memcmp(Adapter->ScanTable[i].MacAddress, bssid, ETH_ALEN)) {
++ switch (mode) {
++ case Wlan802_11Infrastructure:
++ case Wlan802_11IBSS:
++ ret = IsNetworkCompatible(Adapter, i, mode);
++ break;
++ default:
++ ret = i;
++ break;
++ }
++ }
++ }
++
++ if (ret >= 0) {
++ if (find_cfp_by_band_and_channel
++ (Adapter, 0, Adapter->ScanTable[ret].Channel) == NULL) {
++ ret = -ENETUNREACH;
++ }
++ }
++ return ret;
++}
++
++/**
++ * @brief This function finds ssid in ssid list.
++ *
++ * @param Adapter A pointer to wlan_adapter
++ * @param ssid SSID to find in the list
++ * @param bssid BSSID to qualify the SSID selection (if provided)
++ * @param mode Network mode: Infrastructure or IBSS
++ *
++ * @return index in BSSID list
++ */
++int
++FindSSIDInList(wlan_adapter * Adapter, WLAN_802_11_SSID * ssid,
++ u8 * bssid, int mode)
++{
++ int net = -ENETUNREACH;
++ u8 bestrssi = 0;
++ int i, j;
++
++ PRINTM(INFO, "Num of Entries in Table = %d\n", Adapter->NumInScanTable);
++
++ /* Loop through the table until the maximum is reached or until a match
++ * is found based on the bssid field comparison
++ */
++ for (i = 0;
++ i < Adapter->NumInScanTable && (bssid == NULL || (bssid && net < 0));
++ i++) {
++
++ if (!SSIDcmp(&Adapter->ScanTable[i].Ssid, ssid) && ((bssid == NULL)
++ ||
++ !memcmp(Adapter->
++ ScanTable
++ [i].
++ MacAddress,
++ bssid,
++ ETH_ALEN)))
++ {
++ switch (mode) {
++ case Wlan802_11Infrastructure:
++ case Wlan802_11IBSS:
++ j = IsNetworkCompatible(Adapter, i, mode);
++
++ if (j >= 0) {
++ if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) > bestrssi) {
++ bestrssi = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
++ net = i;
++ }
++ } else {
++ if (net == -ENETUNREACH) {
++ net = j;
++ }
++ }
++ break;
++ case Wlan802_11AutoUnknown:
++ default:
++ /* Do not check compatibility if the mode requested is
++ * AutoUnknown. Allows generic find to work without
++ * verifying against the Adapter security settings
++ */
++ if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) > bestrssi) {
++ bestrssi = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
++ net = i;
++ }
++ break;
++ }
++ }
++ }
++ if (net >= 0) {
++ if (find_cfp_by_band_and_channel
++ (Adapter, 0, Adapter->ScanTable[net].Channel) == NULL) {
++ net = -ENETUNREACH;
++ }
++ }
++ return net;
++}
++
++/**
++ * @brief This function finds the best SSID in the Scan List
++ *
++ * Search the scan table for the best SSID that also matches the current
++ * adapter network preference (infrastructure or adhoc)
++ *
++ * @param Adapter A pointer to wlan_adapter
++ *
++ * @return index in BSSID list
++ */
++int
++FindBestSSIDInList(wlan_adapter * Adapter)
++{
++ int mode = Adapter->InfrastructureMode;
++ int bestnet = -ENETUNREACH;
++ u8 bestrssi = 0;
++ int i;
++
++ ENTER();
++
++ PRINTM(INFO, "Num of BSSIDs = %d\n", Adapter->NumInScanTable);
++
++ for (i = 0; i < Adapter->NumInScanTable; i++) {
++ switch (mode) {
++ case Wlan802_11Infrastructure:
++ case Wlan802_11IBSS:
++ if (IsNetworkCompatible(Adapter, i, mode) >= 0) {
++ if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) > bestrssi) {
++ bestrssi = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
++ bestnet = i;
++ }
++ }
++ break;
++ case Wlan802_11AutoUnknown:
++ default:
++ if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) > bestrssi) {
++ bestrssi = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
++ bestnet = i;
++ }
++ break;
++ }
++ }
++
++ LEAVE();
++ return bestnet;
++}
++
++/**
++ * @brief Find the AP with specific ssid in the scan list
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param pSSID A pointer to AP's ssid
++ *
++ * @return WLAN_STATUS_SUCCESS--success, otherwise--fail
++ */
++int
++FindBestNetworkSsid(wlan_private * priv, WLAN_802_11_SSID * pSSID)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++ BSSDescriptor_t *pReqBSSID;
++ int i;
++
++ ENTER();
++
++ memset(pSSID, 0, sizeof(WLAN_802_11_SSID));
++
++ wlan_scan_networks(priv, NULL);
++
++ i = FindBestSSIDInList(Adapter);
++
++ if (i >= 0) {
++
++ pReqBSSID = &Adapter->ScanTable[i];
++ memcpy(pSSID, &pReqBSSID->Ssid, sizeof(WLAN_802_11_SSID));
++
++ /* Make sure we are in the right mode */
++ if (Adapter->InfrastructureMode == Wlan802_11AutoUnknown) {
++ Adapter->InfrastructureMode = pReqBSSID->InfrastructureMode;
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_SNMP_MIB,
++ HostCmd_ACT_SET,
++ HostCmd_OPTION_WAITFORRSP,
++ OID_802_11_INFRASTRUCTURE_MODE, NULL);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ }
++ }
++
++ if (!pSSID->SsidLength) {
++ ret = WLAN_STATUS_FAILURE;
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Delete a specific indexed entry from the scan table.
++ *
++ * Delete the scan table entry indexed by tableIdx. Compact the remaining
++ * entries and adjust any buffering of beacon/probe response data
++ * if needed.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param tableIdx Scan table entry index to delete from the table
++ *
++ * @return void
++ *
++ * @pre tableIdx must be an index to a valid entry
++ */
++static void
++wlan_scan_delete_table_entry(wlan_private * priv, int tableIdx)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int delIdx;
++ uint beaconBufAdj;
++ u8 *pBeaconBuf;
++
++ /* Shift the saved beacon buffer data for the scan table back over the
++ * entry being removed. Update the end of buffer pointer. Save the
++ * deleted buffer allocation size for pointer adjustments for entries
++ * compacted after the deleted index.
++ */
++ beaconBufAdj = Adapter->ScanTable[tableIdx].beaconBufSizeMax;
++
++ PRINTM(INFO, "Scan: Delete Entry %d, beacon buffer removal = %d bytes\n",
++ tableIdx, beaconBufAdj);
++
++ /* Check if the table entry had storage allocated for its beacon */
++ if (beaconBufAdj) {
++ pBeaconBuf = Adapter->ScanTable[tableIdx].pBeaconBuf;
++
++ /* Remove the entry's buffer space, decrement the table end pointer
++ * by the amount we are removing
++ */
++ Adapter->pBeaconBufEnd -= beaconBufAdj;
++
++ PRINTM(INFO,
++ "Scan: Delete Entry %d, compact data: %p <- %p (sz = %d)\n",
++ tableIdx,
++ pBeaconBuf,
++ pBeaconBuf + beaconBufAdj,
++ Adapter->pBeaconBufEnd - pBeaconBuf);
++
++ /* Compact data storage. Copy all data after the deleted entry's
++ * end address (pBeaconBuf + beaconBufAdj) back to the original
++ * start address (pBeaconBuf).
++ *
++ * Scan table entries affected by the move will have their entry
++ * pointer adjusted below.
++ *
++ * Use memmove since the dest/src memory regions overlap.
++ */
++ memmove(pBeaconBuf,
++ pBeaconBuf + beaconBufAdj,
++ Adapter->pBeaconBufEnd - pBeaconBuf);
++ }
++
++ PRINTM(INFO, "Scan: Delete Entry %d, NumInScanTable = %d\n",
++ tableIdx, Adapter->NumInScanTable);
++
++ /* Shift all of the entries after the tableIdx back by one, compacting
++ * the table and removing the requested entry
++ */
++ for (delIdx = tableIdx; (delIdx + 1) < Adapter->NumInScanTable; delIdx++) {
++ /* Copy the next entry over this one */
++ memcpy(Adapter->ScanTable + delIdx,
++ Adapter->ScanTable + delIdx + 1, sizeof(BSSDescriptor_t));
++
++ /* Adjust this entry's pointer to its beacon buffer based on the
++ * removed/compacted entry from the deleted index. Don't decrement
++ * if the buffer pointer is NULL (no data stored for this entry).
++ */
++ if (Adapter->ScanTable[delIdx].pBeaconBuf) {
++ Adapter->ScanTable[delIdx].pBeaconBuf -= beaconBufAdj;
++ }
++ }
++
++ /* The last entry is invalid now that it has been deleted or moved back */
++ memset(Adapter->ScanTable + Adapter->NumInScanTable - 1,
++ 0x00, sizeof(BSSDescriptor_t));
++
++ Adapter->NumInScanTable--;
++}
++
++/**
++ * @brief Delete all occurrences of a given SSID from the scan table
++ *
++ * Iterate through the scan table and delete all entries that match a given
++ * SSID. Compact the remaining scan table entries.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param pDelSSID Pointer to an SSID struct to use in deleting all
++ * matching SSIDs from the scan table
++ *
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ *
++ */
++static int
++wlan_scan_delete_ssid_table_entry(wlan_private * priv,
++ WLAN_802_11_SSID * pDelSSID)
++{
++ int tableIdx;
++ int retval = WLAN_STATUS_FAILURE;
++
++ ENTER();
++
++ PRINTM(INFO, "Scan: Delete Ssid Entry: %-32s\n", pDelSSID->Ssid);
++
++ /* If the requested SSID is found in the table, delete it. Then keep
++ * searching the table for multiple entires for the SSID until no
++ * more are found
++ */
++ while ((tableIdx = FindSSIDInList(priv->adapter,
++ pDelSSID,
++ NULL, Wlan802_11AutoUnknown)) >= 0) {
++ PRINTM(INFO, "Scan: Delete Ssid Entry: Found Idx = %d\n", tableIdx);
++ retval = WLAN_STATUS_SUCCESS;
++ wlan_scan_delete_table_entry(priv, tableIdx);
++ }
++
++ LEAVE();
++
++ return retval;
++}
++
++/**
++ * @brief Scan Network
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ *
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_set_scan(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ union iwreq_data wrqu;
++#if WIRELESS_EXT >= 18
++ struct iw_scan_req *req;
++ struct iw_point *dwrq = (struct iw_point *) vwrq;
++ wlan_ioctl_user_scan_cfg scanCfg;
++#endif
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++#ifdef REASSOCIATION
++ if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
++ PRINTM(ERROR, "Acquire semaphore error, wlan_set_scan\n");
++ return -EBUSY;
++ }
++#endif
++#if WIRELESS_EXT >= 18
++ if ((dwrq->flags & IW_SCAN_THIS_ESSID) &&
++ (dwrq->length == sizeof(struct iw_scan_req))) {
++ req = (struct iw_scan_req *) extra;
++ if (req->essid_len <= WLAN_MAX_SSID_LENGTH) {
++ memset(&scanCfg, 0x00, sizeof(scanCfg));
++ memcpy(scanCfg.ssidList[0].ssid, (u8 *) req->essid,
++ req->essid_len);
++ if (!wlan_scan_networks(priv, &scanCfg)) {
++ memset(&wrqu, 0, sizeof(union iwreq_data));
++ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
++ NULL);
++
++ }
++ }
++ } else {
++#endif
++
++ if (!wlan_scan_networks(priv, NULL)) {
++ memset(&wrqu, 0, sizeof(union iwreq_data));
++ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
++ NULL);
++
++ }
++#if WIRELESS_EXT >= 18
++ }
++#endif
++
++#ifdef REASSOCIATION
++ OS_REL_SEMAPHORE(&Adapter->ReassocSem);
++#endif
++
++ if (Adapter->SurpriseRemoved)
++ return WLAN_STATUS_FAILURE;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Send a scan command for all available channels filtered on a spec
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param pRequestedSSID A pointer to AP's ssid
++ *
++ * @return WLAN_STATUS_SUCCESS-success, otherwise fail
++ */
++int
++SendSpecificSSIDScan(wlan_private * priv, WLAN_802_11_SSID * pRequestedSSID)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ wlan_ioctl_user_scan_cfg scanCfg;
++
++ ENTER();
++
++ if (pRequestedSSID == NULL) {
++ return WLAN_STATUS_FAILURE;
++ }
++
++ wlan_scan_delete_ssid_table_entry(priv, pRequestedSSID);
++
++ memset(&scanCfg, 0x00, sizeof(scanCfg));
++
++ memcpy(scanCfg.ssidList[0].ssid,
++ pRequestedSSID->Ssid, pRequestedSSID->SsidLength);
++ scanCfg.keepPreviousScan = TRUE;
++
++ wlan_scan_networks(priv, &scanCfg);
++
++ if (Adapter->SurpriseRemoved)
++ return WLAN_STATUS_FAILURE;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief scan an AP with specific BSSID
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param bssid A pointer to AP's bssid
++ *
++ * @return WLAN_STATUS_SUCCESS-success, otherwise fail
++ */
++int
++SendSpecificBSSIDScan(wlan_private * priv, u8 * bssid)
++{
++ wlan_ioctl_user_scan_cfg scanCfg;
++
++ ENTER();
++
++ if (bssid == NULL) {
++ return WLAN_STATUS_FAILURE;
++ }
++
++ memset(&scanCfg, 0x00, sizeof(scanCfg));
++ memcpy(scanCfg.specificBSSID, bssid, sizeof(scanCfg.specificBSSID));
++ scanCfg.keepPreviousScan = TRUE;
++
++ wlan_scan_networks(priv, &scanCfg);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Retrieve the scan table entries via wireless tools IOCTL call
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param dwrq A pointer to iw_point structure
++ * @param extra A pointer to extra data buf
++ *
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_get_scan(struct net_device *dev, struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++ char *current_ev = extra;
++ char *end_buf = extra + IW_SCAN_MAX_DATA;
++ CHANNEL_FREQ_POWER *cfp;
++ BSSDescriptor_t *pScanTable;
++ char *current_val; /* For rates */
++ struct iw_event iwe; /* Temporary buffer */
++ int i;
++ int j;
++ int rate;
++
++ u8 buf[16 + 256 * 2];
++ u8 *ptr;
++ u8 *pRawData;
++#define PERFECT_RSSI ((u8)50)
++#define WORST_RSSI ((u8)0)
++#define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI))
++ u8 rssi;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ PRINTM(INFO, "Current Ssid: %-32s\n",
++ Adapter->CurBssParams.BSSDescriptor.Ssid.Ssid);
++ }
++
++ PRINTM(INFO, "Scan: Get: NumInScanTable = %d\n", Adapter->NumInScanTable);
++
++#if WIRELESS_EXT > 13
++ /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP.
++ * The new API using SIOCGIWSCAN is only limited by buffer size
++ * WE-14 -> WE-16 the buffer is limited to IW_SCAN_MAX_DATA bytes
++ * which is 4096.
++ */
++ for (i = 0; i < Adapter->NumInScanTable; i++) {
++ if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
++ PRINTM(INFO, "i=%d break out: current_ev=%p end_buf=%p "
++ "MAX_SCAN_CELL_SIZE=%d\n",
++ i, current_ev, end_buf, MAX_SCAN_CELL_SIZE);
++ break;
++ }
++
++ pScanTable = &Adapter->ScanTable[i];
++
++ PRINTM(INFO, "i=%d Ssid: %-32s\n", i, pScanTable->Ssid.Ssid);
++
++ cfp =
++ find_cfp_by_band_and_channel(Adapter, 0,
++ (u16) pScanTable->Channel);
++ if (!cfp) {
++ PRINTM(INFO, "Invalid channel number %d\n", pScanTable->Channel);
++ continue;
++ }
++
++ if (ssid_valid(&Adapter->ScanTable[i].Ssid) == FALSE) {
++ continue;
++ }
++
++ /* First entry *MUST* be the AP MAC address */
++ iwe.cmd = SIOCGIWAP;
++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
++ memcpy(iwe.u.ap_addr.sa_data,
++ &Adapter->ScanTable[i].MacAddress, ETH_ALEN);
++
++ iwe.len = IW_EV_ADDR_LEN;
++ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, iwe.len);
++
++ //Add the ESSID
++ iwe.u.data.length = Adapter->ScanTable[i].Ssid.SsidLength;
++
++ if (iwe.u.data.length > 32) {
++ iwe.u.data.length = 32;
++ }
++
++ iwe.cmd = SIOCGIWESSID;
++ iwe.u.essid.flags = (i + 1) & IW_ENCODE_INDEX;
++ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
++ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe,
++ (s8 *) Adapter->ScanTable[i].Ssid.
++ Ssid);
++
++ //Add mode
++ iwe.cmd = SIOCGIWMODE;
++ iwe.u.mode = Adapter->ScanTable[i].InfrastructureMode + 1;
++ iwe.len = IW_EV_UINT_LEN;
++ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, iwe.len);
++
++ //frequency
++ iwe.cmd = SIOCGIWFREQ;
++ iwe.u.freq.m = (long) cfp->Freq * 100000;
++ iwe.u.freq.e = 1;
++ iwe.len = IW_EV_FREQ_LEN;
++ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, iwe.len);
++
++ /* Add quality statistics */
++ iwe.cmd = IWEVQUAL;
++ iwe.u.qual.updated = IW_QUAL_ALL_UPDATED;
++ iwe.u.qual.level = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
++
++ rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE;
++ iwe.u.qual.qual =
++ (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *
++ (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /
++ (RSSI_DIFF * RSSI_DIFF);
++ if (iwe.u.qual.qual > 100)
++ iwe.u.qual.qual = 100;
++
++ if (Adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
++ iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
++ } else {
++ iwe.u.qual.noise = CAL_NF(Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
++ }
++ if ((Adapter->InfrastructureMode == Wlan802_11IBSS) &&
++ !SSIDcmp(&Adapter->CurBssParams.BSSDescriptor.Ssid,
++ &Adapter->ScanTable[i].Ssid)
++ && Adapter->AdhocCreate) {
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_RSSI,
++ 0, HostCmd_OPTION_WAITFORRSP, 0,
++ NULL);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ iwe.u.qual.level =
++ CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
++ Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
++ }
++
++ iwe.len = IW_EV_QUAL_LEN;
++ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, iwe.len);
++
++ /* Add encryption capability */
++ iwe.cmd = SIOCGIWENCODE;
++ if (Adapter->ScanTable[i].Privacy) {
++ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
++ } else {
++ iwe.u.data.flags = IW_ENCODE_DISABLED;
++ }
++ iwe.u.data.length = 0;
++ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
++ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, NULL);
++
++ current_val = current_ev + IW_EV_LCP_LEN;
++
++ iwe.cmd = SIOCGIWRATE;
++
++ iwe.u.bitrate.fixed = 0;
++ iwe.u.bitrate.disabled = 0;
++ iwe.u.bitrate.value = 0;
++
++ /* Bit rate given in 500 kb/s units (+ 0x80) */
++ for (j = 0; j < sizeof(Adapter->ScanTable[i].SupportedRates); j++) {
++ if (Adapter->ScanTable[i].SupportedRates[j] == 0) {
++ break;
++ }
++ rate = (Adapter->ScanTable[i].SupportedRates[j] & 0x7F) * 500000;
++ if (rate > iwe.u.bitrate.value) {
++ iwe.u.bitrate.value = rate;
++ }
++
++ iwe.u.bitrate.value = (Adapter->ScanTable[i].SupportedRates[j]
++ & 0x7f) * 500000;
++ iwe.len = IW_EV_PARAM_LEN;
++ current_ev =
++ iwe_stream_add_value(info, current_ev, current_val, end_buf, &iwe,
++ iwe.len);
++
++ }
++ if ((Adapter->ScanTable[i].InfrastructureMode == Wlan802_11IBSS) &&
++ !SSIDcmp(&Adapter->CurBssParams.BSSDescriptor.Ssid,
++ &Adapter->ScanTable[i].Ssid)
++ && Adapter->AdhocCreate) {
++ iwe.u.bitrate.value = 22 * 500000;
++ }
++ iwe.len = IW_EV_PARAM_LEN;
++ current_ev = iwe_stream_add_value(info, current_ev, current_val, end_buf,
++ &iwe, iwe.len);
++
++ /* Add new value to event */
++ current_val = current_ev + IW_EV_LCP_LEN;
++
++ if (Adapter->ScanTable[i].rsnIE.IeeeHdr.ElementId == RSN_IE) {
++ pRawData = (u8 *) & Adapter->ScanTable[i].rsnIE;
++ memset(&iwe, 0, sizeof(iwe));
++ memset(buf, 0, sizeof(buf));
++ ptr = buf;
++#if WIRELESS_EXT >= 18
++ memcpy(buf, pRawData,
++ Adapter->ScanTable[i].rsnIE.IeeeHdr.Len + 2);
++ iwe.cmd = IWEVGENIE;
++ iwe.u.data.length = Adapter->ScanTable[i].rsnIE.IeeeHdr.Len + 2;
++#else
++ ptr += sprintf(ptr, "rsn_ie=");
++
++ for (j = 0;
++ j < (Adapter->ScanTable[i].rsnIE.IeeeHdr.Len
++ + sizeof(IEEEtypes_Header_t)); j++) {
++ ptr += sprintf(ptr, "%02x", *(pRawData + j));
++ }
++ iwe.u.data.length = strlen(buf);
++
++ PRINTM(INFO, "iwe.u.data.length %d\n", iwe.u.data.length);
++ PRINTM(INFO, "WPA2 BUF: %s \n", buf);
++
++ iwe.cmd = IWEVCUSTOM;
++#endif
++ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
++ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf);
++ }
++ if (Adapter->ScanTable[i].wpaIE.VendHdr.ElementId == WPA_IE) {
++ pRawData = (u8 *) & Adapter->ScanTable[i].wpaIE;
++ memset(&iwe, 0, sizeof(iwe));
++ memset(buf, 0, sizeof(buf));
++ ptr = buf;
++#if WIRELESS_EXT >= 18
++ memcpy(buf, pRawData,
++ Adapter->ScanTable[i].wpaIE.VendHdr.Len + 2);
++ iwe.cmd = IWEVGENIE;
++ iwe.u.data.length = Adapter->ScanTable[i].wpaIE.VendHdr.Len + 2;
++#else
++ ptr += sprintf(ptr, "wpa_ie=");
++
++ for (j = 0;
++ j < (Adapter->ScanTable[i].wpaIE.VendHdr.Len
++ + sizeof(IEEEtypes_Header_t)); j++) {
++ ptr += sprintf(ptr, "%02x", *(pRawData + j));
++ }
++ iwe.u.data.length = strlen(buf);
++
++ PRINTM(INFO, "iwe.u.data.length %d\n", iwe.u.data.length);
++ PRINTM(INFO, "WPA BUF: %s \n", buf);
++
++ iwe.cmd = IWEVCUSTOM;
++#endif
++ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
++ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf);
++ }
++ if (Adapter->ScanTable[i].wpsIE.VendHdr.ElementId == WPS_IE) {
++ pRawData = (u8 *) & Adapter->ScanTable[i].wpsIE;
++ memset(&iwe, 0, sizeof(iwe));
++ memset(buf, 0, sizeof(buf));
++ ptr = buf;
++ ptr += sprintf(ptr, "wps_ie=");
++
++ for (j = 0;
++ j < (Adapter->ScanTable[i].wpsIE.VendHdr.Len
++ + sizeof(IEEEtypes_Header_t)); j++) {
++ ptr += sprintf(ptr, "%02x", *(pRawData + j));
++ }
++ iwe.u.data.length = strlen(buf);
++
++ PRINTM(INFO, "iwe.u.data.length %d\n", iwe.u.data.length);
++ PRINTM(INFO, "WPS BUF: %s \n", buf);
++
++ iwe.cmd = IWEVCUSTOM;
++ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
++ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf);
++ }
++
++#if WIRELESS_EXT > 14
++
++ if (Adapter->ScanTable[i].extra_ie != 0) {
++ memset(&iwe, 0, sizeof(iwe));
++ memset(buf, 0, sizeof(buf));
++ ptr = buf;
++ ptr += sprintf(ptr, "extra_ie");
++ iwe.u.data.length = strlen(buf);
++
++ PRINTM(INFO, "iwe.u.data.length %d\n", iwe.u.data.length);
++ PRINTM(INFO, "BUF: %s \n", buf);
++
++ iwe.cmd = IWEVCUSTOM;
++ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
++ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf);
++ }
++#endif
++
++ current_val = current_ev + IW_EV_LCP_LEN;
++
++ /*
++ * Check if we added any event
++ */
++ if ((current_val - current_ev) > IW_EV_LCP_LEN)
++ current_ev = current_val;
++ }
++
++ dwrq->length = (current_ev - extra);
++ dwrq->flags = 0;
++
++ LEAVE();
++#endif
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Create a wlan_ioctl_get_scan_table_entry for a given BSS
++ * Descriptor for inclusion in the ioctl response to the user space
++ * application.
++ *
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param pBSSDesc Pointer to a BSS entry in the scan table to form
++ * scan response from for delivery to the application layer
++ * @param ppBuffer Output parameter: Buffer used to output scan return struct
++ * @param pSpaceLeft Output parameter: Number of bytes available in the
++ * response buffer.
++ *
++ * @return WLAN_STATUS_SUCCESS, or < 0 with IOCTL error code
++ */
++static int
++wlan_get_scan_table_ret_entry(wlan_private * priv,
++ BSSDescriptor_t * pBSSDesc,
++ u8 ** ppBuffer, int *pSpaceLeft)
++{
++ wlan_adapter *Adapter;
++ wlan_ioctl_get_scan_table_entry *pRspEntry;
++ wlan_ioctl_get_scan_table_entry tmpRspEntry;
++ int spaceNeeded;
++ u8 *pCurrent;
++ int variableSize;
++
++ const int fixedSize = (sizeof(tmpRspEntry.fixedFieldLength)
++ + sizeof(tmpRspEntry.fixedFields)
++ + sizeof(tmpRspEntry.bssInfoLength));
++
++ ENTER();
++
++ Adapter = priv->adapter;
++ pCurrent = *ppBuffer;
++
++ /* The variable size returned is the stored beacon size */
++ variableSize = pBSSDesc->beaconBufSize;
++
++ /* If we stored a beacon and its size was zero, set the variable
++ * size return value to the size of the brief scan response
++ * wlan_scan_create_brief_table_entry creates. Also used if
++ * we are not configured to store beacons in the first place
++ */
++ if (variableSize == 0) {
++ variableSize = pBSSDesc->Ssid.SsidLength + 2;
++ variableSize += (sizeof(pBSSDesc->BeaconPeriod)
++ + sizeof(pBSSDesc->TimeStamp)
++ + sizeof(pBSSDesc->Cap));
++ if (pBSSDesc->wmmIE.VendHdr.ElementId == WMM_IE) {
++ variableSize += (sizeof(IEEEtypes_Header_t)
++ + pBSSDesc->wmmIE.VendHdr.Len);
++ }
++
++ if (pBSSDesc->wpaIE.VendHdr.ElementId == WPA_IE) {
++ variableSize += (sizeof(IEEEtypes_Header_t)
++ + pBSSDesc->wpaIE.VendHdr.Len);
++ }
++
++ if (pBSSDesc->rsnIE.IeeeHdr.ElementId == RSN_IE) {
++ variableSize += (sizeof(IEEEtypes_Header_t)
++ + pBSSDesc->rsnIE.IeeeHdr.Len);
++ }
++ }
++
++ spaceNeeded = fixedSize + variableSize;
++
++ PRINTM(INFO, "GetScanTable: need(%d), left(%d)\n",
++ spaceNeeded, *pSpaceLeft);
++
++ if (spaceNeeded >= *pSpaceLeft) {
++ *pSpaceLeft = 0;
++ LEAVE();
++ return -E2BIG;
++ }
++
++ *pSpaceLeft -= spaceNeeded;
++
++ tmpRspEntry.fixedFieldLength = sizeof(pRspEntry->fixedFields);
++
++ memcpy(tmpRspEntry.fixedFields.bssid,
++ pBSSDesc->MacAddress, sizeof(pRspEntry->fixedFields.bssid));
++
++ tmpRspEntry.fixedFields.rssi = pBSSDesc->Rssi;
++ tmpRspEntry.fixedFields.channel = pBSSDesc->Channel;
++ tmpRspEntry.fixedFields.networkTSF = pBSSDesc->networkTSF;
++ tmpRspEntry.bssInfoLength = variableSize;
++
++ /*
++ * Copy fixed fields to user space
++ */
++ if (copy_to_user(pCurrent, &tmpRspEntry, fixedSize)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ LEAVE();
++ return -EFAULT;
++ }
++
++ pCurrent += fixedSize;
++
++ if (pBSSDesc->pBeaconBuf) {
++ /*
++ * Copy variable length elements to user space
++ */
++ if (copy_to_user(pCurrent, pBSSDesc->pBeaconBuf,
++ pBSSDesc->beaconBufSize)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ LEAVE();
++ return -EFAULT;
++ }
++
++ pCurrent += pBSSDesc->beaconBufSize;
++ } else {
++ wlan_scan_create_brief_table_entry(&pCurrent, pBSSDesc);
++ }
++
++ *ppBuffer = pCurrent;
++
++ LEAVE();
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Retrieve the scan response/beacon table
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ *
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_get_scan_table_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter;
++ BSSDescriptor_t *pBSSDesc;
++ wlan_ioctl_get_scan_table_info *pRspInfo;
++ int retcode;
++ int retlen;
++ int spaceLeft;
++ u8 *pCurrent;
++ u8 *pBufferEnd;
++ u32 scanStart;
++ u32 numScansDone;
++
++ numScansDone = 0;
++ retcode = WLAN_STATUS_SUCCESS;
++ Adapter = priv->adapter;
++
++ if (copy_from_user(&scanStart,
++ wrq->u.data.pointer, sizeof(scanStart)) != 0) {
++ /* copy_from_user failed */
++ PRINTM(INFO, "GetScanTable: copy from user failed\n");
++ return -EFAULT;
++ }
++
++ pRspInfo = (wlan_ioctl_get_scan_table_info *) wrq->u.data.pointer;
++ pCurrent = pRspInfo->scan_table_entry_buffer;
++ pBufferEnd = wrq->u.data.pointer + wrq->u.data.length - 1;
++ spaceLeft = pBufferEnd - pCurrent;
++ PRINTM(INFO, "GetScanTable: scanStart req = %d\n", scanStart);
++ PRINTM(INFO, "GetScanTable: length avail = %d\n", wrq->u.data.length);
++
++ if (scanStart == 0) {
++ PRINTM(INFO, "GetScanTable: get current BSS Descriptor\n");
++
++ /* Use to get current association saved descriptor */
++ pBSSDesc = &Adapter->CurBssParams.BSSDescriptor;
++
++ retcode = wlan_get_scan_table_ret_entry(priv,
++ pBSSDesc,
++ &pCurrent, &spaceLeft);
++
++ if (retcode == WLAN_STATUS_SUCCESS) {
++ numScansDone = 1;
++ }
++
++ } else {
++ scanStart--;
++
++ while (spaceLeft
++ && (scanStart + numScansDone < Adapter->NumInScanTable)
++ && (retcode == WLAN_STATUS_SUCCESS)) {
++
++ pBSSDesc = &Adapter->ScanTable[scanStart + numScansDone];
++
++ PRINTM(INFO, "GetScanTable: get current BSS Descriptor [%d]\n",
++ scanStart + numScansDone);
++
++ retcode = wlan_get_scan_table_ret_entry(priv,
++ pBSSDesc,
++ &pCurrent, &spaceLeft);
++
++ if (retcode == WLAN_STATUS_SUCCESS) {
++ numScansDone++;
++ }
++ }
++ }
++
++ pRspInfo->scanNumber = numScansDone;
++ retlen = pCurrent - (u8 *) wrq->u.data.pointer;
++
++ wrq->u.data.length = retlen;
++
++ /* Return retcode (EFAULT or E2BIG) in the case where no scan results were
++ * successfully encoded.
++ */
++
++ return (numScansDone ? WLAN_STATUS_SUCCESS : retcode);
++}
++
++/**
++ * @brief Update the scan entry TSF timestamps to reflect a new association
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param pNewBssDesc A pointer to the newly associated AP's scan table entry
++ *
++ * @return void
++ */
++void
++wlan_scan_update_tsf_timestamps(wlan_private * priv,
++ BSSDescriptor_t * pNewBssDesc)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int tableIdx;
++ u64 newTsfBase;
++ s64 tsfDelta;
++
++ memcpy(&newTsfBase, pNewBssDesc->TimeStamp, sizeof(newTsfBase));
++
++ tsfDelta = newTsfBase - pNewBssDesc->networkTSF;
++
++ PRINTM(INFO, "TSF: Update TSF timestamps, 0x%016llx -> 0x%016llx\n",
++ pNewBssDesc->networkTSF, newTsfBase);
++
++ for (tableIdx = 0; tableIdx < Adapter->NumInScanTable; tableIdx++) {
++ Adapter->ScanTable[tableIdx].networkTSF += tsfDelta;
++ }
++}
++
++/**
++ * @brief Private IOCTL entry to perform an app configured immediate scan
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure containing the
++ * wlan_ioctl_user_scan_cfg requesting this scan
++ *
++ * @return 0 if successful; IOCTL error code otherwise
++ */
++int
++wlan_set_user_scan_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_ioctl_user_scan_cfg scanReq;
++ int retcode;
++ union iwreq_data wrqu;
++
++#ifdef REASSOCIATION
++ if (OS_ACQ_SEMAPHORE_BLOCK(&priv->adapter->ReassocSem)) {
++ PRINTM(ERROR, "Acquire semaphore error, wlan_extscan_ioctl\n");
++ return -EBUSY;
++ }
++#endif
++
++ memset(&scanReq, 0x00, sizeof(scanReq));
++
++ if (copy_from_user(&scanReq,
++ wrq->u.data.pointer,
++ MIN(wrq->u.data.length, sizeof(scanReq))) != 0) {
++ /* copy_from_user failed */
++ PRINTM(INFO, "SetUserScan: copy from user failed\n");
++ retcode = -EFAULT;
++
++ } else {
++
++ retcode = wlan_scan_networks(priv, &scanReq);
++
++ memset(&wrqu, 0x00, sizeof(union iwreq_data));
++ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
++
++ }
++
++#ifdef REASSOCIATION
++ OS_REL_SEMAPHORE(&priv->adapter->ReassocSem);
++#endif
++
++ return retcode;
++}
++
++/**
++ * @brief Prepare a scan command to be sent to the firmware
++ *
++ * Use the wlan_scan_cmd_config sent to the command processing module in
++ * the PrepareAndSendCommand to configure a HostCmd_DS_802_11_SCAN command
++ * struct to send to firmware.
++ *
++ * The fixed fields specifying the BSS type and BSSID filters as well as a
++ * variable number/length of TLVs are sent in the command to firmware.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure to be sent to
++ * firmware with the HostCmd_DS_801_11_SCAN structure
++ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
++ * to set the fields/TLVs for the command sent to firmware
++ *
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ *
++ * @sa wlan_scan_create_channel_list
++ */
++int
++wlan_cmd_802_11_scan(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *pdata_buf)
++{
++ HostCmd_DS_802_11_SCAN *pScan = &cmd->params.scan;
++ wlan_scan_cmd_config *pScanCfg;
++
++ ENTER();
++
++ pScanCfg = (wlan_scan_cmd_config *) pdata_buf;
++
++ /* Set fixed field variables in scan command */
++ pScan->BSSType = pScanCfg->bssType;
++ memcpy(pScan->BSSID, pScanCfg->specificBSSID, sizeof(pScan->BSSID));
++ memcpy(pScan->TlvBuffer, pScanCfg->tlvBuffer, pScanCfg->tlvBufferLen);
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN);
++
++ /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
++ cmd->Size = wlan_cpu_to_le16(sizeof(pScan->BSSType)
++ + sizeof(pScan->BSSID)
++ + pScanCfg->tlvBufferLen + S_DS_GEN);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Store a beacon or probe response for a BSS returned in the scan
++ *
++ * Store a new scan response or an update for a previous scan response. New
++ * entries need to verify that they do not exceed the total amount of
++ * memory allocated for the table.
++
++ * Replacement entries need to take into consideration the amount of space
++ * currently allocated for the beacon/probe response and adjust the entry
++ * as needed.
++ *
++ * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
++ * for an entry in case it is a beacon since a probe response for the
++ * network will by larger per the standard. This helps to reduce the
++ * amount of memory copying to fit a new probe response into an entry
++ * already occupied by a network's previously stored beacon.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param beaconIdx Index in the scan table to store this entry; may be
++ * replacing an older duplicate entry for this BSS
++ * @param numInTable Number of entries currently in the table
++ * @param pNewBeacon Pointer to the new beacon/probe response to save
++ *
++ * @return void
++ */
++void
++wlan_ret_802_11_scan_store_beacon(wlan_private * priv,
++ int beaconIdx,
++ int numInTable,
++ BSSDescriptor_t * pNewBeacon)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ u8 *pBcnStore;
++ int newBcnSize;
++ int oldBcnSize;
++ int bcnSpace;
++ int adjIdx;
++
++ if (Adapter->ScanTable[beaconIdx].pBeaconBuf != NULL) {
++
++ newBcnSize = pNewBeacon->beaconBufSize;
++ oldBcnSize = Adapter->ScanTable[beaconIdx].beaconBufSize;
++ bcnSpace = Adapter->ScanTable[beaconIdx].beaconBufSizeMax;
++ pBcnStore = Adapter->ScanTable[beaconIdx].pBeaconBuf;
++
++ /* Set the max to be the same as current entry unless changed below */
++ pNewBeacon->beaconBufSizeMax = bcnSpace;
++
++ if (newBcnSize == oldBcnSize) {
++ /*
++ * Beacon is the same size as the previous entry.
++ * Replace the previous contents with the scan result
++ */
++ memcpy(pBcnStore,
++ pNewBeacon->pBeaconBuf, pNewBeacon->beaconBufSize);
++
++ } else if (newBcnSize <= bcnSpace) {
++ /*
++ * New beacon size will fit in the amount of space
++ * we have previously allocated for it
++ */
++
++ /* Copy the new beacon buffer entry over the old one */
++ memcpy(pBcnStore, pNewBeacon->pBeaconBuf, newBcnSize);
++
++ /* If the old beacon size was less than the maximum
++ * we had alloted for the entry, and the new entry
++ * is even smaller, reset the max size to the old beacon
++ * entry and compress the storage space (leaving a new
++ * pad space of (oldBcnSize - newBcnSize).
++ */
++ if (oldBcnSize < bcnSpace && newBcnSize != bcnSpace) {
++ /*
++ * Old Beacon size is smaller than the alloted storage size.
++ * Shrink the alloted storage space.
++ */
++ PRINTM(INFO, "AppControl: Smaller Duplicate Beacon (%d), "
++ "old = %d, new = %d, space = %d, left = %d\n",
++ beaconIdx, oldBcnSize, newBcnSize, bcnSpace,
++ (sizeof(Adapter->beaconBuffer) -
++ (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
++
++ /* memmove (since the memory overlaps) the data
++ * after the beacon we just stored to the end of
++ * the current beacon. This cleans up any unused
++ * space the old larger beacon was using in the buffer
++ */
++ memmove(pBcnStore + oldBcnSize,
++ pBcnStore + bcnSpace,
++ Adapter->pBeaconBufEnd - (pBcnStore + bcnSpace));
++
++ /* Decrement the end pointer by the difference between
++ * the old larger size and the new smaller size since
++ * we are using less space due to the new beacon being
++ * smaller
++ */
++ Adapter->pBeaconBufEnd -= (bcnSpace - oldBcnSize);
++
++ /* Set the maximum storage size to the old beacon size */
++ pNewBeacon->beaconBufSizeMax = oldBcnSize;
++
++ /* Adjust beacon buffer pointers that are past the current */
++ for (adjIdx = 0; adjIdx < numInTable; adjIdx++) {
++ if (Adapter->ScanTable[adjIdx].pBeaconBuf > pBcnStore) {
++ Adapter->ScanTable[adjIdx].pBeaconBuf
++ -= (bcnSpace - oldBcnSize);
++ }
++ }
++ }
++ } else if (Adapter->pBeaconBufEnd + (newBcnSize - bcnSpace)
++ < (Adapter->beaconBuffer + sizeof(Adapter->beaconBuffer))) {
++ /*
++ * Beacon is larger than space previously allocated (bcnSpace)
++ * and there is enough space left in the beaconBuffer to store
++ * the additional data
++ */
++ PRINTM(INFO, "AppControl: Larger Duplicate Beacon (%d), "
++ "old = %d, new = %d, space = %d, left = %d\n",
++ beaconIdx, oldBcnSize, newBcnSize, bcnSpace,
++ (sizeof(Adapter->beaconBuffer) -
++ (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
++
++ /* memmove (since the memory overlaps) the data
++ * after the beacon we just stored to the end of
++ * the current beacon. This moves the data for
++ * the beacons after this further in memory to
++ * make space for the new larger beacon we are
++ * about to copy in.
++ */
++ memmove(pBcnStore + newBcnSize,
++ pBcnStore + bcnSpace,
++ Adapter->pBeaconBufEnd - (pBcnStore + bcnSpace));
++
++ /* Copy the new beacon buffer entry over the old one */
++ memcpy(pBcnStore, pNewBeacon->pBeaconBuf, newBcnSize);
++
++ /* Move the beacon end pointer by the amount of new
++ * beacon data we are adding
++ */
++ Adapter->pBeaconBufEnd += (newBcnSize - bcnSpace);
++
++ /* This entry is bigger than the alloted max space
++ * previously reserved. Increase the max space to
++ * be equal to the new beacon size
++ */
++ pNewBeacon->beaconBufSizeMax = newBcnSize;
++
++ /* Adjust beacon buffer pointers that are past the current */
++ for (adjIdx = 0; adjIdx < numInTable; adjIdx++) {
++ if (Adapter->ScanTable[adjIdx].pBeaconBuf > pBcnStore) {
++ Adapter->ScanTable[adjIdx].pBeaconBuf
++ += (newBcnSize - bcnSpace);
++ }
++ }
++ } else {
++ /*
++ * Beacon is larger than the previously allocated space, but
++ * there is not enough free space to store the additional data
++ */
++ PRINTM(INFO,
++ "AppControl: Failed: Larger Duplicate Beacon (%d),"
++ " old = %d, new = %d, space = %d, left = %d\n",
++ beaconIdx, oldBcnSize, newBcnSize, bcnSpace,
++ (sizeof(Adapter->beaconBuffer) -
++ (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
++
++ /* Storage failure, keep old beacon intact */
++ pNewBeacon->beaconBufSize = oldBcnSize;
++ }
++
++ /* Point the new entry to its permanent storage space */
++ pNewBeacon->pBeaconBuf = pBcnStore;
++
++ } else {
++ /* No existing beacon data exists for this entry, check to see
++ * if we can fit it in the remaining space
++ */
++ if (Adapter->pBeaconBufEnd + pNewBeacon->beaconBufSize +
++ SCAN_BEACON_ENTRY_PAD < (Adapter->beaconBuffer +
++ sizeof(Adapter->beaconBuffer))) {
++
++ /* Copy the beacon buffer data from the local entry to the
++ * adapter dev struct buffer space used to store the raw
++ * beacon data for each entry in the scan table
++ */
++ memcpy(Adapter->pBeaconBufEnd, pNewBeacon->pBeaconBuf,
++ pNewBeacon->beaconBufSize);
++
++ /* Update the beacon ptr to point to the table save area */
++ pNewBeacon->pBeaconBuf = Adapter->pBeaconBufEnd;
++ pNewBeacon->beaconBufSizeMax = (pNewBeacon->beaconBufSize
++ + SCAN_BEACON_ENTRY_PAD);
++
++ /* Increment the end pointer by the size reserved */
++ Adapter->pBeaconBufEnd += pNewBeacon->beaconBufSizeMax;
++
++ PRINTM(INFO, "AppControl: Beacon[%02d] sz=%03d,"
++ " used = %04d, left = %04d\n",
++ beaconIdx,
++ pNewBeacon->beaconBufSize,
++ (Adapter->pBeaconBufEnd - Adapter->beaconBuffer),
++ (sizeof(Adapter->beaconBuffer) -
++ (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
++ } else {
++ /*
++ * No space for new beacon
++ */
++ PRINTM(INFO, "AppControl: No space beacon (%d): "
++ "%02x:%02x:%02x:%02x:%02x:%02x; sz=%03d, left=%03d\n",
++ beaconIdx,
++ pNewBeacon->MacAddress[0], pNewBeacon->MacAddress[1],
++ pNewBeacon->MacAddress[2], pNewBeacon->MacAddress[3],
++ pNewBeacon->MacAddress[4], pNewBeacon->MacAddress[5],
++ pNewBeacon->beaconBufSize,
++ (sizeof(Adapter->beaconBuffer) -
++ (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
++
++ /* Storage failure; clear storage records for this bcn */
++ pNewBeacon->pBeaconBuf = NULL;
++ pNewBeacon->beaconBufSize = 0;
++ pNewBeacon->beaconBufSizeMax = 0;
++ }
++ }
++}
++
++/**
++ * @brief This function handles the command response of scan
++ *
++ * The response buffer for the scan command has the following
++ * memory layout:
++ *
++ * .-----------------------------------------------------------.
++ * | Header (4 * sizeof(u16)): Standard command response hdr |
++ * .-----------------------------------------------------------.
++ * | BufSize (u16) : sizeof the BSS Description data |
++ * .-----------------------------------------------------------.
++ * | NumOfSet (u8) : Number of BSS Descs returned |
++ * .-----------------------------------------------------------.
++ * | BSSDescription data (variable, size given in BufSize) |
++ * .-----------------------------------------------------------.
++ * | TLV data (variable, size calculated using Header->Size, |
++ * | BufSize and sizeof the fixed fields above) |
++ * .-----------------------------------------------------------.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param resp A pointer to HostCmd_DS_COMMAND
++ *
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_ret_802_11_scan(wlan_private * priv, HostCmd_DS_COMMAND * resp)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ HostCmd_DS_802_11_SCAN_RSP *pScan;
++ BSSDescriptor_t newBssEntry;
++ MrvlIEtypes_Data_t *pTlv;
++ MrvlIEtypes_TsfTimestamp_t *pTsfTlv;
++ u8 *pBssInfo;
++ u16 scanRespSize;
++ int bytesLeft;
++ int numInTable;
++ int bssIdx;
++ int idx;
++ int tlvBufSize;
++ u64 tsfVal;
++ BOOLEAN bgScanResp;
++
++ ENTER();
++
++ bgScanResp = (resp->Command == HostCmd_RET_802_11_BG_SCAN_QUERY);
++ if (bgScanResp) {
++ pScan = &resp->params.bgscanqueryresp.scanresp;
++ } else {
++ pScan = &resp->params.scanresp;
++ }
++
++ if (pScan->NumberOfSets > MRVDRV_MAX_BSSID_LIST) {
++ PRINTM(INFO, "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
++ pScan->NumberOfSets);
++ LEAVE();
++ return WLAN_STATUS_FAILURE;
++ }
++
++ bytesLeft = wlan_le16_to_cpu(pScan->BSSDescriptSize);
++ PRINTM(INFO, "SCAN_RESP: BSSDescriptSize %d\n", bytesLeft);
++
++ scanRespSize = resp->Size;
++
++ PRINTM(CMND, "SCAN_RESP: returned %d APs before parsing\n",
++ pScan->NumberOfSets);
++
++ numInTable = Adapter->NumInScanTable;
++ pBssInfo = pScan->BssDescAndTlvBuffer;
++
++ /* The size of the TLV buffer is equal to the entire command response
++ * size (scanRespSize) minus the fixed fields (sizeof()'s), the
++ * BSS Descriptions (BSSDescriptSize as bytesLef) and the command
++ * response header (S_DS_GEN)
++ */
++ tlvBufSize = scanRespSize - (bytesLeft + sizeof(pScan->BSSDescriptSize)
++ + sizeof(pScan->NumberOfSets)
++ + S_DS_GEN);
++
++ pTlv = (MrvlIEtypes_Data_t *) (pScan->BssDescAndTlvBuffer + bytesLeft);
++
++ /* Search the TLV buffer space in the scan response for any valid TLVs */
++ wlan_ret_802_11_scan_get_tlv_ptrs(pTlv, tlvBufSize, &pTsfTlv);
++
++ /*
++ * Process each scan response returned (pScan->NumberOfSets). Save
++ * the information in the newBssEntry and then insert into the
++ * driver scan table either as an update to an existing entry
++ * or as an addition at the end of the table
++ */
++ for (idx = 0; idx < pScan->NumberOfSets && bytesLeft; idx++) {
++ /* Zero out the newBssEntry we are about to store info in */
++ memset(&newBssEntry, 0x00, sizeof(newBssEntry));
++
++ /* Process the data fields and IEs returned for this BSS */
++ if ((InterpretBSSDescriptionWithIE(&newBssEntry,
++ &pBssInfo,
++ &bytesLeft) == WLAN_STATUS_SUCCESS)
++ && CHECK_SSID_IS_VALID(&newBssEntry.Ssid)) {
++
++ PRINTM(INFO, "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
++ newBssEntry.MacAddress[0], newBssEntry.MacAddress[1],
++ newBssEntry.MacAddress[2], newBssEntry.MacAddress[3],
++ newBssEntry.MacAddress[4], newBssEntry.MacAddress[5]);
++
++ /*
++ * Search the scan table for the same bssid
++ */
++ for (bssIdx = 0; bssIdx < numInTable; bssIdx++) {
++ if (memcmp(newBssEntry.MacAddress,
++ Adapter->ScanTable[bssIdx].MacAddress,
++ sizeof(newBssEntry.MacAddress)) == 0) {
++ /*
++ * If the SSID matches as well, it is a duplicate of
++ * this entry. Keep the bssIdx set to this
++ * entry so we replace the old contents in the table
++ */
++ if ((newBssEntry.Ssid.SsidLength ==
++ Adapter->ScanTable[bssIdx].Ssid.SsidLength)
++ && (memcmp(newBssEntry.Ssid.Ssid,
++ Adapter->ScanTable[bssIdx].Ssid.Ssid,
++ newBssEntry.Ssid.SsidLength) == 0)) {
++ PRINTM(INFO, "SCAN_RESP: Duplicate of index: %d\n",
++ bssIdx);
++ break;
++ }
++ }
++ }
++ /*
++ * If the bssIdx is equal to the number of entries in the table,
++ * the new entry was not a duplicate; append it to the scan
++ * table
++ */
++ if (bssIdx == numInTable) {
++ /* Range check the bssIdx, keep it limited to the last entry */
++ if (bssIdx == MRVDRV_MAX_BSSID_LIST) {
++ bssIdx--;
++ } else {
++ numInTable++;
++ }
++ }
++
++ /*
++ * Save the beacon/probe response returned for later application
++ * retrieval. Duplicate beacon/probe responses are updated if
++ * possible
++ */
++ wlan_ret_802_11_scan_store_beacon(priv,
++ bssIdx,
++ numInTable, &newBssEntry);
++ /*
++ * If the TSF TLV was appended to the scan results, save
++ * this entry's TSF value in the networkTSF field. The
++ * networkTSF is the firmware's TSF value at the time the
++ * beacon or probe response was received.
++ */
++ if (pTsfTlv) {
++ memcpy(&tsfVal, &pTsfTlv->tsfTable[idx], sizeof(tsfVal));
++ tsfVal = wlan_le64_to_cpu(tsfVal);
++
++ memcpy(&newBssEntry.networkTSF,
++ &tsfVal, sizeof(newBssEntry.networkTSF));
++ }
++
++ /* Copy the locally created newBssEntry to the scan table */
++ memcpy(&Adapter->ScanTable[bssIdx],
++ &newBssEntry, sizeof(Adapter->ScanTable[bssIdx]));
++
++ } else {
++
++ /* Error parsing/interpreting the scan response, skipped */
++ PRINTM(INFO, "SCAN_RESP: "
++ "InterpretBSSDescriptionWithIE returned ERROR\n");
++ }
++ }
++
++ PRINTM(CMND, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
++ pScan->NumberOfSets, numInTable - Adapter->NumInScanTable,
++ numInTable);
++
++ /* Update the total number of BSSIDs in the scan table */
++ Adapter->NumInScanTable = numInTable;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief scan network with specific ssid
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ *
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_extscan_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ WLAN_802_11_SSID Ext_Scan_SSID;
++ wlan_ioctl_user_scan_cfg scanCfg;
++ union iwreq_data wrqu;
++
++ ENTER();
++
++ if (copy_from_user(&Ext_Scan_SSID, req->ifr_data, sizeof(Ext_Scan_SSID))) {
++ PRINTM(INFO, "copy of SSID for ext scan from user failed \n");
++ LEAVE();
++ return -EFAULT;
++ }
++#ifdef REASSOCIATION
++ if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
++ PRINTM(ERROR, "Acquire semaphore error, wlan_extscan_ioctl\n");
++ return -EBUSY;
++ }
++#endif
++
++ memset(&scanCfg, 0x00, sizeof(scanCfg));
++
++ memcpy(scanCfg.ssidList[0].ssid, Ext_Scan_SSID.Ssid,
++ Ext_Scan_SSID.SsidLength);
++
++ wlan_scan_networks(priv, &scanCfg);
++
++ memset(&wrqu, 0, sizeof(union iwreq_data));
++ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
++
++#ifdef REASSOCIATION
++ OS_REL_SEMAPHORE(&Adapter->ReassocSem);
++#endif
++
++ if (Adapter->SurpriseRemoved)
++ return WLAN_STATUS_FAILURE;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function sends BG_SCAN query command to firmware.
++ *
++ * @param priv A pointer to wlan_private structure
++ *
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++sendBgScanQueryCmd(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ /* Clear the previous scan result */
++ memset(Adapter->ScanTable, 0x00,
++ sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
++ Adapter->NumInScanTable = 0;
++ Adapter->pBeaconBufEnd = Adapter->beaconBuffer;
++
++ return PrepareAndSendCommand(priv, HostCmd_CMD_802_11_BG_SCAN_QUERY,
++ 0, 0, 0, NULL);
++}
++
++/**
++ * @brief Enable/Disable BG Scan
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param enable TRUE-enable, FALSE-disable
++ *
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_bg_scan_enable(wlan_private * priv, BOOLEAN enable)
++{
++ int ret;
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_BG_SCAN_CONFIG,
++ 0, HostCmd_OPTION_WAITFORRSP, 0, &enable);
++ return ret;
++}
++
++/**
++ * @brief config BGSCAN parameter
++
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ *
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_do_bg_scan_config_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++ u8 action;
++ u8 *buf = NULL;
++ HostCmd_DS_802_11_BG_SCAN_CONFIG *tmp;
++
++ ENTER();
++
++ action = *((u8 *) req->ifr_data + SKIP_CMDNUM + SKIP_SIZE);
++ PRINTM(INFO, "Action = %d\n", action);
++
++ switch (action) {
++ case HostCmd_ACT_GEN_GET:
++ buf = kmalloc(Adapter->bgScanConfigSize + SKIP_TYPE_SIZE, GFP_KERNEL);
++ if (!buf) {
++ PRINTM(MSG, "kmalloc no memory !!\n");
++ return -ENOMEM;
++ }
++ memcpy(buf, &Adapter->bgScanConfigSize, SKIP_SIZE);
++ memcpy(buf + SKIP_TYPE_SIZE, Adapter->bgScanConfig,
++ Adapter->bgScanConfigSize);
++
++ if (copy_to_user(req->ifr_data, buf,
++ Adapter->bgScanConfigSize + SKIP_TYPE_SIZE)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ kfree(buf);
++ return -EFAULT;
++ }
++
++ kfree(buf);
++
++ break;
++
++ case HostCmd_ACT_GEN_SET:
++ Adapter->bgScanConfigSize = *(u16 *) (req->ifr_data + SKIP_CMDNUM);
++ PRINTM(INFO, "bgscanConfigSize = %d\n", Adapter->bgScanConfigSize);
++
++ if (!(tmp = kmalloc(Adapter->bgScanConfigSize, GFP_KERNEL))) {
++ PRINTM(MSG, "kmalloc no memory !!\n");
++ Adapter->bgScanConfigSize = 0;
++ return -ENOMEM;
++ }
++
++ HEXDUMP("treq", req->ifr_data + SKIP_CMDNUM + SKIP_SIZE,
++ Adapter->bgScanConfigSize);
++
++ if (copy_from_user(tmp, req->ifr_data + SKIP_CMDNUM + SKIP_SIZE,
++ Adapter->bgScanConfigSize)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ kfree(tmp);
++ return -EFAULT;
++ }
++
++ if (Adapter->bgScanConfig) {
++ tmp->Enable = Adapter->bgScanConfig->Enable;
++ buf = (u8 *) Adapter->bgScanConfig;
++ }
++ Adapter->bgScanConfig = tmp;
++ if (buf)
++ kfree(buf);
++
++ break;
++ }
++
++ LEAVE();
++
++ return ret;
++}
++
++/**
++ * @brief This function prepares command of bg_scan_config.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ * @param cmd_action the action: GET or SET
++ * @param pdata_buf A pointer to data buffer
++ *
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_cmd_802_11_bg_scan_config(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ int cmd_action, void *pdata_buf)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ HostCmd_DS_802_11_BG_SCAN_CONFIG *bgcfg = &cmd->params.bgscancfg;
++ BOOLEAN enable = *((BOOLEAN *) pdata_buf);
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG);
++ cmd->Size =
++ wlan_cpu_to_le16((priv->adapter->bgScanConfigSize) + S_DS_GEN);
++
++ Adapter->bgScanConfig->Enable = enable;
++
++ memcpy(bgcfg, Adapter->bgScanConfig, Adapter->bgScanConfigSize);
++
++ bgcfg->Action = wlan_cpu_to_le16(bgcfg->Action);
++ bgcfg->ScanInterval = wlan_cpu_to_le32(bgcfg->ScanInterval);
++ bgcfg->StoreCondition = wlan_cpu_to_le32(bgcfg->StoreCondition);
++ bgcfg->ReportConditions = wlan_cpu_to_le32(bgcfg->ReportConditions);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief This function prepares command of bg_scan_query.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param cmd A pointer to HostCmd_DS_COMMAND structure
++ *
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_cmd_802_11_bg_scan_query(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
++{
++ HostCmd_DS_802_11_BG_SCAN_QUERY *bgquery = &cmd->params.bgscanquery;
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
++ cmd->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_BG_SCAN_QUERY) + S_DS_GEN);
++
++ bgquery->Flush = 1;
++
++ return WLAN_STATUS_SUCCESS;
++}
+diff --git a/drivers/net/wireless/marvell8686/wlan_scan.h b/drivers/net/wireless/marvell8686/wlan_scan.h
+new file mode 100644
+index 0000000..2274cd3
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_scan.h
+@@ -0,0 +1,284 @@
++/** @file wlan_scan.h
++ *
++ * @brief Interface for the wlan network scan routines
++ *
++ * Driver interface functions and type declarations for the scan module
++ * implemented in wlan_scan.c.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ *
++ * @sa wlan_scan.c
++ */
++/*************************************************************
++Change Log:
++ 01/11/06: Initial revision. New scan code, relocate related functions
++
++************************************************************/
++
++#ifndef _WLAN_SCAN_H
++#define _WLAN_SCAN_H
++
++//! Infrastructure BSS scan type in wlan_scan_cmd_config
++#define WLAN_SCAN_BSS_TYPE_BSS 1
++
++//! Adhoc BSS scan type in wlan_scan_cmd_config
++#define WLAN_SCAN_BSS_TYPE_IBSS 2
++
++//! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter
++#define WLAN_SCAN_BSS_TYPE_ANY 3
++
++/** @brief Maximum buffer space for beacons retrieved from scan responses
++ * 4000 has successfully stored up to 40 beacons
++ * 6000 has successfully stored the max scan results (max 64)
++ */
++#define MAX_SCAN_BEACON_BUFFER 6000
++
++/**
++ * @brief Buffer pad space for newly allocated beacons/probe responses
++ *
++ * Beacons are typically 6 bytes longer than an equivalent probe response.
++ * For each scan response stored, allocate an extra byte pad at the end to
++ * allow easy expansion to store a beacon in the same memory a probe reponse
++ * previously contained
++ */
++#define SCAN_BEACON_ENTRY_PAD 6
++
++//! Scan time specified in the channel TLV for each channel for passive scans
++#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 100
++
++//! Scan time specified in the channel TLV for each channel for active scans
++#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100
++
++//! Scan time specified in the channel TLV for each channel for specific scans
++#define MRVDRV_SPECIFIC_SCAN_CHAN_TIME 100
++
++//! Max passive scan time for each channel in milliseconds
++#define MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME 2000
++
++//! Max active scan time for each channel in milliseconds
++#define MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME 500
++
++/**
++ * Max total scan time in milliseconds
++ * The total scan time should be less than scan command timeout value (10s)
++ */
++#define MRVDRV_MAX_TOTAL_SCAN_TIME (MRVDRV_TIMER_10S - MRVDRV_TIMER_1S)
++
++/**
++ * @brief Structure used internally in the wlan driver to configure a scan.
++ *
++ * Sent to the command processing module to configure the firmware
++ * scan command prepared by wlan_cmd_802_11_scan.
++ *
++ * @sa wlan_scan_networks
++ *
++ */
++typedef struct
++{
++ /**
++ * @brief BSS Type to be sent in the firmware command
++ *
++ * Field can be used to restrict the types of networks returned in the
++ * scan. Valid settings are:
++ *
++ * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure)
++ * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
++ * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
++ */
++ u8 bssType;
++
++ /**
++ * @brief Specific BSSID used to filter scan results in the firmware
++ */
++ u8 specificBSSID[MRVDRV_ETH_ADDR_LEN];
++
++ /**
++ * @brief Length of TLVs sent in command starting at tlvBuffer
++ */
++ int tlvBufferLen;
++
++ /**
++ * @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command
++ *
++ * @sa TLV_TYPE_CHANLIST, MrvlIEtypes_ChanListParamSet_t
++ * @sa TLV_TYPE_SSID, MrvlIEtypes_SsIdParamSet_t
++ */
++ u8 tlvBuffer[1]; //!< SSID TLV(s) and ChanList TLVs are stored here
++} wlan_scan_cmd_config;
++
++/**
++ * @brief Sub-structure passed in wlan_ioctl_get_scan_table_entry for each BSS
++ *
++ * Fixed field information returned for the scan response in the IOCTL
++ * response.
++ */
++typedef struct
++{
++ u8 bssid[6]; //!< BSSID of this network
++ u8 channel; //!< Channel this beacon/probe response was detected
++ u8 rssi; //!< RSSI for the received packet
++ u64 networkTSF; //!< TSF value from the firmware at packet reception
++} __ATTRIB_PACK__ wlan_ioctl_get_scan_table_fixed;
++
++/**
++ * @brief Structure passed in the wlan_ioctl_get_scan_table_info for each
++ * BSS returned in the WLAN_GET_SCAN_RESP IOCTL
++ *
++ * @sa wlan_get_scan_table_ioctl
++ */
++typedef struct
++{
++
++ /**
++ * @brief Fixed field length included in the response.
++ *
++ * Length value is included so future fixed fields can be added to the
++ * response without breaking backwards compatibility. Use the length
++ * to find the offset for the bssInfoLength field, not a sizeof() calc.
++ */
++ u32 fixedFieldLength;
++
++ /**
++ * @brief Always present, fixed length data fields for the BSS
++ */
++ wlan_ioctl_get_scan_table_fixed fixedFields;
++
++ /**
++ * @brief Length of the BSS Information (probe resp or beacon) that
++ * follows starting at bssInfoBuffer
++ */
++ u32 bssInfoLength;
++
++ /**
++ * @brief Probe response or beacon scanned for the BSS.
++ *
++ * Field layout:
++ * - TSF 8 octets
++ * - Beacon Interval 2 octets
++ * - Capability Info 2 octets
++ *
++ * - IEEE Infomation Elements; variable number & length per 802.11 spec
++ */
++ u8 bssInfoBuffer[1];
++} __ATTRIB_PACK__ wlan_ioctl_get_scan_table_entry;
++
++/**
++ * @brief WLAN_GET_SCAN_RESP private IOCTL struct to retrieve the scan table
++ *
++ * @sa wlan_get_scan_table_ioctl
++ */
++typedef struct
++{
++
++ /**
++ * - Zero based scan entry to start retrieval in command request
++ * - Number of scans entires returned in command response
++ */
++ u32 scanNumber;
++
++ /**
++ * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures.
++ * Each struct is padded to the nearest 32 bit boundary.
++ */
++ u8 scan_table_entry_buffer[1];
++
++} __ATTRIB_PACK__ wlan_ioctl_get_scan_table_info;
++
++/**
++ * @brief Structure used to store information for each beacon/probe response
++ */
++typedef struct
++{
++ WLAN_802_11_MAC_ADDRESS MacAddress;
++
++ WLAN_802_11_SSID Ssid;
++
++ /* WEP encryption requirement */
++ u32 Privacy;
++
++ /* receive signal strength in dBm */
++ WLAN_802_11_RSSI Rssi;
++
++ u32 Channel;
++
++ u16 BeaconPeriod;
++
++ u32 ATIMWindow;
++ u8 ERPFlags;
++
++ WLAN_802_11_NETWORK_TYPE NetworkTypeInUse;
++ WLAN_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
++ WLAN_802_11_RATES SupportedRates;
++ IEEEtypes_WmmParameter_t wmmIE;
++
++ int extra_ie;
++
++ u8 TimeStamp[8]; //!< TSF value included in the beacon/probe response
++
++ IEEEtypes_PhyParamSet_t PhyParamSet;
++ IEEEtypes_SsParamSet_t SsParamSet;
++ IEEEtypes_CapInfo_t Cap;
++
++ u8 DataRates[WLAN_SUPPORTED_RATES];
++
++ u64 networkTSF; //!< TSF timestamp from the current firmware TSF
++
++ IEEEtypes_CountryInfoFullSet_t CountryInfo;
++
++ IEEEtypes_VendorSpecific_t wpaIE;
++ IEEEtypes_Generic_t rsnIE;
++
++ IEEEtypes_VendorSpecific_t wpsIE;
++
++ u8 *pBeaconBuf; //!< Pointer to the returned scan response
++ uint beaconBufSize; //!< Length of the stored scan response
++ uint beaconBufSizeMax; //!< Max allocated size for updated scan response
++
++} BSSDescriptor_t;
++
++extern int SSIDcmp(WLAN_802_11_SSID * ssid1, WLAN_802_11_SSID * ssid2);
++extern int FindSSIDInList(wlan_adapter * Adapter, WLAN_802_11_SSID * ssid,
++ u8 * bssid, int mode);
++extern int FindBestSSIDInList(wlan_adapter * Adapter);
++extern int FindBSSIDInList(wlan_adapter * Adapter, u8 * bssid, int mode);
++
++extern int FindBestNetworkSsid(wlan_private * priv, WLAN_802_11_SSID * pSSID);
++
++extern int SendSpecificSSIDScan(wlan_private * priv,
++ WLAN_802_11_SSID * pRequestedSSID);
++extern int SendSpecificBSSIDScan(wlan_private * priv, u8 * bssid);
++
++extern int wlan_get_scan_table_ioctl(wlan_private * priv, struct iwreq *wrq);
++extern int wlan_set_user_scan_ioctl(wlan_private * priv, struct iwreq *wrq);
++
++extern int wlan_associate(wlan_private * priv, BSSDescriptor_t * pBSSDesc);
++
++extern int wlan_cmd_802_11_scan(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *pdata_buf);
++
++extern void wlan_scan_update_tsf_timestamps(wlan_private * priv,
++ BSSDescriptor_t * pNewBssDesc);
++
++extern int wlan_ret_802_11_scan(wlan_private * priv,
++ HostCmd_DS_COMMAND * resp);
++
++extern int wlan_extscan_ioctl(wlan_private * priv, struct ifreq *req);
++
++extern int sendBgScanQueryCmd(wlan_private * priv);
++extern int wlan_bg_scan_enable(wlan_private * priv, BOOLEAN enable);
++extern int wlan_do_bg_scan_config_ioctl(wlan_private * priv,
++ struct ifreq *req);
++extern int wlan_cmd_802_11_bg_scan_config(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd,
++ int cmd_action, void *pdata_buf);
++extern int wlan_cmd_802_11_bg_scan_query(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd);
++
++#ifdef __KERNEL__
++extern int wlan_get_scan(struct net_device *dev, struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra);
++extern int wlan_set_scan(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra);
++#endif
++
++#endif /* _WLAN_SCAN_H */
+diff --git a/drivers/net/wireless/marvell8686/wlan_thread.h b/drivers/net/wireless/marvell8686/wlan_thread.h
+new file mode 100644
+index 0000000..3d9c01c
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_thread.h
+@@ -0,0 +1,58 @@
++/*
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++
++#ifndef __WLAN_THREAD_H_
++#define __WLAN_THREAD_H_
++
++#include <linux/kthread.h>
++
++typedef struct
++{
++ struct task_struct *task;
++ wait_queue_head_t waitQ;
++ pid_t pid;
++ void *priv;
++} wlan_thread;
++
++static inline void
++wlan_activate_thread(wlan_thread * thr)
++{
++ /** Record the thread pid */
++ thr->pid = current->pid;
++
++ /** Initialize the wait queue */
++ init_waitqueue_head(&thr->waitQ);
++}
++
++static inline void
++wlan_deactivate_thread(wlan_thread * thr)
++{
++ ENTER();
++
++ LEAVE();
++}
++
++static inline void
++wlan_create_thread(int (*wlanfunc) (void *), wlan_thread * thr, char *name)
++{
++ thr->task = kthread_run(wlanfunc, thr, "%s", name);
++}
++
++static inline int
++wlan_terminate_thread(wlan_thread * thr)
++{
++ ENTER();
++
++ /* Check if the thread is active or not */
++ if (!thr->pid) {
++ PRINTM(INFO, "Thread does not exist\n");
++ return -1;
++ }
++ kthread_stop(thr->task);
++
++ LEAVE();
++ return 0;
++}
++
++#endif
+diff --git a/drivers/net/wireless/marvell8686/wlan_tx.c b/drivers/net/wireless/marvell8686/wlan_tx.c
+new file mode 100644
+index 0000000..f04f6e1
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_tx.c
+@@ -0,0 +1,286 @@
++/** @file wlan_tx.c
++ * @brief This file contains the handling of TX in wlan
++ * driver.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++/********************************************************
++Change log:
++ 09/28/05: Add Doxygen format comments
++ 12/13/05: Add Proprietary periodic sleep support
++ 01/05/06: Add kernel 2.6.x support
++ 04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
++********************************************************/
++
++#include "include.h"
++
++/********************************************************
++ Local Variables
++********************************************************/
++
++/********************************************************
++ Global Variables
++********************************************************/
++
++/********************************************************
++ Local Functions
++********************************************************/
++
++/**
++ * @brief This function processes a single packet and sends
++ * to IF layer
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param skb A pointer to skb which includes TX packet
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++static int
++SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++ TxPD LocalTxPD;
++ TxPD *pLocalTxPD = &LocalTxPD;
++ u8 *ptr = Adapter->TmpTxBuf;
++
++ ENTER();
++
++ if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
++ PRINTM(ERROR, "Tx Error: Bad skb length %d : %d\n",
++ skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ memset(pLocalTxPD, 0, sizeof(TxPD));
++
++ pLocalTxPD->TxPacketLength = skb->len;
++
++ if (Adapter->wmm.enabled) {
++ /*
++ * original skb->priority has been overwritten
++ * by wmm_map_and_add_skb()
++ */
++ pLocalTxPD->Priority = (u8) skb->priority;
++
++ pLocalTxPD->PktDelay_2ms = wmm_compute_driver_packet_delay(skb);
++ }
++
++ if (pLocalTxPD->Priority < NELEMENTS(Adapter->wmm.userPriPktTxCtrl)) {
++ /*
++ * Set the priority specific TxControl field, setting of 0 will
++ * cause the default value to be used later in this function
++ */
++ pLocalTxPD->TxControl
++ = Adapter->wmm.userPriPktTxCtrl[pLocalTxPD->Priority];
++ }
++
++ if (Adapter->PSState != PS_STATE_FULL_POWER) {
++ if (TRUE == CheckLastPacketIndication(priv)) {
++ Adapter->TxLockFlag = TRUE;
++ pLocalTxPD->Flags = MRVDRV_TxPD_POWER_MGMT_LAST_PACKET;
++ }
++ }
++
++ /* offset of actual data */
++ pLocalTxPD->TxPacketLocation = sizeof(TxPD);
++
++ if (pLocalTxPD->TxControl == 0) {
++ /* TxCtrl set by user or default */
++ pLocalTxPD->TxControl = Adapter->PktTxCtrl;
++ }
++
++ endian_convert_TxPD(pLocalTxPD);
++
++ memcpy((u8 *) pLocalTxPD->TxDestAddr, skb->data, MRVDRV_ETH_ADDR_LEN);
++
++ ptr += SDIO_HEADER_LEN;
++ memcpy(ptr, pLocalTxPD, sizeof(TxPD));
++
++ ptr += sizeof(TxPD);
++
++ memcpy(ptr, skb->data, skb->len);
++
++ ret = sbi_host_to_card(priv, MVMS_DAT, Adapter->TmpTxBuf,
++ skb->len + sizeof(TxPD));
++ if (ret) {
++ PRINTM(ERROR,
++ "SendSinglePacket Error: sbi_host_to_card failed: 0x%X\n",
++ ret);
++ Adapter->dbg.num_tx_host_to_card_failure++;
++ goto done;
++ }
++
++ PRINTM(DATA, "Data => FW\n");
++ DBG_HEXDUMP(DAT_D, "Tx", ptr - sizeof(TxPD),
++ MIN(skb->len + sizeof(TxPD), MAX_DATA_DUMP_LEN));
++
++ wmm_process_fw_iface_tx_xfer_start(priv);
++
++ done:
++ if (!ret) {
++ priv->stats.tx_packets++;
++ priv->stats.tx_bytes += skb->len;
++ } else {
++ priv->stats.tx_dropped++;
++ priv->stats.tx_errors++;
++ }
++
++ /* need to be freed in all cases */
++ os_free_tx_packet(priv);
++
++ LEAVE();
++ return ret;
++}
++
++/********************************************************
++ Global functions
++********************************************************/
++
++/**
++ * @brief This function checks the conditions and sends packet to IF
++ * layer if everything is ok.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return n/a
++ */
++void
++wlan_process_tx(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ OS_INTERRUPT_SAVE_AREA;
++
++ if (priv->wlan_dev.dnld_sent) {
++ PRINTM(MSG, "TX Error: dnld_sent = %d, not sending\n",
++ priv->wlan_dev.dnld_sent);
++ goto done;
++ }
++
++ SendSinglePacket(priv, Adapter->CurrentTxSkb);
++ OS_INT_DISABLE;
++ priv->adapter->HisRegCpy &= ~HIS_TxDnLdRdy;
++ OS_INT_RESTORE;
++
++ done:
++ LEAVE();
++}
++
++/**
++ * @brief This function queues the packet received from
++ * kernel/upper layer and wake up the main thread to handle it.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param skb A pointer to skb which includes TX packet
++ * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
++ */
++int
++wlan_tx_packet(wlan_private * priv, struct sk_buff *skb)
++{
++ ulong flags;
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ HEXDUMP("TX Data", skb->data, MIN(skb->len, 100));
++
++ spin_lock_irqsave(&Adapter->CurrentTxLock, flags);
++
++ wmm_map_and_add_skb(priv, skb);
++ wake_up_interruptible(&priv->MainThread.waitQ);
++ spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
++
++ LEAVE();
++
++ return ret;
++}
++
++/**
++ * @brief This function tells firmware to send a NULL data packet.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param flags Trasnit Pkt Flags
++ * @return n/a
++ */
++int
++SendNullPacket(wlan_private * priv, u8 flags)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ TxPD txpd = { 0 };
++ int ret = WLAN_STATUS_SUCCESS;
++ u8 *ptr = Adapter->TmpTxBuf;
++
++ ENTER();
++
++ if (Adapter->SurpriseRemoved == TRUE) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
++ ret = WLAN_STATUS_FAILURE;
++ goto done;
++ }
++
++ memset(&txpd, 0, sizeof(TxPD));
++
++ txpd.TxControl = Adapter->PktTxCtrl;
++ txpd.Flags = flags;
++ txpd.Priority = WMM_HIGHEST_PRIORITY;
++ txpd.TxPacketLocation = sizeof(TxPD);
++
++ endian_convert_TxPD(&txpd);
++
++ ptr += SDIO_HEADER_LEN;
++ memcpy(ptr, &txpd, sizeof(TxPD));
++
++ ret = sbi_host_to_card(priv, MVMS_DAT, Adapter->TmpTxBuf, sizeof(TxPD));
++
++ if (ret != 0) {
++ PRINTM(ERROR, "TX Error: SendNullPacket failed!\n");
++ Adapter->dbg.num_tx_host_to_card_failure++;
++ goto done;
++ }
++ PRINTM(DATA, "Null data => FW\n");
++ DBG_HEXDUMP(DAT_D, "Tx", ptr, sizeof(TxPD));
++
++ done:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief This function check if we need send last packet indication.
++ *
++ * @param priv A pointer to wlan_private structure
++ *
++ * @return TRUE or FALSE
++ */
++BOOLEAN
++CheckLastPacketIndication(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ BOOLEAN ret = FALSE;
++ BOOLEAN prop_ps = TRUE;
++
++ ENTER();
++
++ if (Adapter->sleep_period.period == 0 || Adapter->gen_null_pkg == FALSE /* for UPSD certification tests */
++ ) {
++ LEAVE();
++ return ret;
++ }
++
++ if (wmm_lists_empty(priv)) {
++ if (((Adapter->CurBssParams.wmm_uapsd_enabled == TRUE)
++ && (Adapter->wmm.qosinfo != 0)) || prop_ps) {
++ ret = TRUE;
++ }
++ }
++
++ LEAVE();
++ return ret;
++}
+diff --git a/drivers/net/wireless/marvell8686/wlan_types.h b/drivers/net/wireless/marvell8686/wlan_types.h
+new file mode 100644
+index 0000000..76e4f25
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_types.h
+@@ -0,0 +1,1050 @@
++/** @file wlan_types.h
++ * @brief This header file contains definition for global types
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ */
++/*************************************************************
++Change log:
++ 10/11/05: add Doxygen format comments
++ 01/11/06: Add IEEE Association response type. Add TSF TLV information.
++ 01/31/06: Add support to selectively enabe the FW Scan channel filter
++ 04/10/06: Add power_adapt_cfg_ext command
++ 04/18/06: Remove old Subscrive Event and add new Subscribe Event
++ implementation through generic hostcmd API
++ 05/03/06: Add auto_tx hostcmd
++ 08/28/06: Add LED_CTRL hostcmd
++************************************************************/
++
++#ifndef _WLAN_TYPES_
++#define _WLAN_TYPES_
++
++#ifndef __KERNEL__
++typedef char s8;
++typedef unsigned char u8;
++
++typedef signed short s16;
++typedef unsigned short u16;
++
++typedef signed long s32;
++typedef unsigned long u32;
++
++typedef signed long long s64;
++typedef unsigned long long u64;
++
++typedef u32 dma_addr_t;
++typedef u32 dma64_addr_t;
++/* Dma addresses are 32-bits wide. */
++#ifndef __ATTRIB_ALIGN__
++#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
++#endif
++
++#ifndef __ATTRIB_PACK__
++#define __ATTRIB_PACK__ __attribute__ ((packed))
++#endif
++#endif
++
++typedef long LONG;
++typedef unsigned long long ULONGLONG;
++typedef u32 WLAN_OID;
++
++#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
++#define MRVDRV_MAX_CHANNEL_SIZE 14
++#define MRVDRV_ETH_ADDR_LEN 6
++#define MRVDRV_MAX_SSID_LENGTH 32
++#define MRVDRV_MAX_BSS_DESCRIPTS 16
++/** WEP list macros & data structures */
++#define MRVL_KEY_BUFFER_SIZE_IN_BYTE 16
++#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32
++
++#define HOSTCMD_SUPPORTED_RATES G_SUPPORTED_RATES
++
++#define BAND_B (0x01)
++#define BAND_G (0x02)
++#define ALL_802_11_BANDS (BAND_B | BAND_G)
++
++#define B_SUPPORTED_RATES 8
++#define G_SUPPORTED_RATES 14
++
++#define WLAN_SUPPORTED_RATES 14
++#define WLAN_MAX_SSID_LENGTH 32
++
++#define MAX_POWER_ADAPT_GROUP 5
++
++#define MRVDRV_MAX_SSID_LIST_LENGTH 10
++
++typedef u8 WLAN_802_11_RATES[WLAN_SUPPORTED_RATES];
++typedef u8 WLAN_802_11_MAC_ADDRESS[ETH_ALEN];
++
++/** WLAN_802_11_NETWORK_TYPE */
++typedef enum _WLAN_802_11_NETWORK_TYPE
++{
++ Wlan802_11FH,
++ Wlan802_11DS,
++ /*defined as upper bound */
++ Wlan802_11NetworkTypeMax
++} WLAN_802_11_NETWORK_TYPE, *PWLAN_802_11_NETWORK_TYPE;
++
++/** WLAN_802_11_NETWORK_INFRASTRUCTURE */
++typedef enum _WLAN_802_11_NETWORK_INFRASTRUCTURE
++{
++ Wlan802_11IBSS,
++ Wlan802_11Infrastructure,
++ Wlan802_11AutoUnknown,
++ /*defined as upper bound */
++ Wlan802_11InfrastructureMax
++} WLAN_802_11_NETWORK_INFRASTRUCTURE, *PWLAN_802_11_NETWORK_INFRASTRUCTURE;
++
++#define IEEE_MAX_IE_SIZE 256
++
++/** IEEE Type definitions */
++typedef enum _IEEEtypes_ElementId_e
++{
++ SSID = 0,
++ SUPPORTED_RATES = 1,
++ FH_PARAM_SET = 2,
++ DS_PARAM_SET = 3,
++ CF_PARAM_SET = 4,
++
++ IBSS_PARAM_SET = 6,
++
++ COUNTRY_INFO = 7,
++
++ ERP_INFO = 42,
++ EXTENDED_SUPPORTED_RATES = 50,
++
++ VENDOR_SPECIFIC_221 = 221,
++ WMM_IE = VENDOR_SPECIFIC_221,
++
++ WPS_IE = VENDOR_SPECIFIC_221,
++
++ WPA_IE = VENDOR_SPECIFIC_221,
++ RSN_IE = 48,
++
++ EXTRA_IE = 133,
++} __ATTRIB_PACK__ IEEEtypes_ElementId_e;
++
++#define CAPINFO_MASK (~( W_BIT_15 | W_BIT_14 | \
++ W_BIT_12 | W_BIT_11 | W_BIT_9) )
++
++typedef struct _IEEEtypes_CapInfo_t
++{
++ u8 Ess:1;
++ u8 Ibss:1;
++ u8 CfPollable:1;
++ u8 CfPollRqst:1;
++ u8 Privacy:1;
++ u8 ShortPreamble:1;
++ u8 Pbcc:1;
++ u8 ChanAgility:1;
++ u8 SpectrumMgmt:1;
++ u8 Rsrvd3:1;
++ u8 ShortSlotTime:1;
++ u8 Apsd:1;
++ u8 Rsvrd2:1;
++ u8 DSSSOFDM:1;
++ u8 Rsrvd1:2;
++} __ATTRIB_PACK__ IEEEtypes_CapInfo_t;
++
++typedef struct
++{
++ u8 ElementId;
++ u8 Len;
++} __ATTRIB_PACK__ IEEEtypes_Header_t;
++
++/** IEEEtypes_CfParamSet_t */
++typedef struct _IEEEtypes_CfParamSet_t
++{
++ u8 ElementId;
++ u8 Len;
++ u8 CfpCnt;
++ u8 CfpPeriod;
++ u16 CfpMaxDuration;
++ u16 CfpDurationRemaining;
++} __ATTRIB_PACK__ IEEEtypes_CfParamSet_t;
++
++typedef struct IEEEtypes_IbssParamSet_t
++{
++ u8 ElementId;
++ u8 Len;
++ u16 AtimWindow;
++} __ATTRIB_PACK__ IEEEtypes_IbssParamSet_t;
++
++/** IEEEtypes_SsParamSet_t */
++typedef union _IEEEtypes_SsParamSet_t
++{
++ IEEEtypes_CfParamSet_t CfParamSet;
++ IEEEtypes_IbssParamSet_t IbssParamSet;
++} __ATTRIB_PACK__ IEEEtypes_SsParamSet_t;
++
++/** IEEEtypes_FhParamSet_t */
++typedef struct _IEEEtypes_FhParamSet_t
++{
++ u8 ElementId;
++ u8 Len;
++ u16 DwellTime;
++ u8 HopSet;
++ u8 HopPattern;
++ u8 HopIndex;
++} __ATTRIB_PACK__ IEEEtypes_FhParamSet_t;
++
++typedef struct _IEEEtypes_DsParamSet_t
++{
++ u8 ElementId;
++ u8 Len;
++ u8 CurrentChan;
++} __ATTRIB_PACK__ IEEEtypes_DsParamSet_t;
++
++/** IEEEtypes_DsParamSet_t */
++typedef union IEEEtypes_PhyParamSet_t
++{
++ IEEEtypes_FhParamSet_t FhParamSet;
++ IEEEtypes_DsParamSet_t DsParamSet;
++} __ATTRIB_PACK__ IEEEtypes_PhyParamSet_t;
++
++typedef struct _IEEEtypes_ERPInfo_t
++{
++ u8 ElementId;
++ u8 Len;
++ u8 ERPFlags;
++} __ATTRIB_PACK__ IEEEtypes_ERPInfo_t;
++
++typedef u16 IEEEtypes_AId_t;
++typedef u16 IEEEtypes_StatusCode_t;
++
++typedef struct
++{
++ IEEEtypes_CapInfo_t Capability;
++ IEEEtypes_StatusCode_t StatusCode;
++ IEEEtypes_AId_t AId;
++ u8 IEBuffer[1];
++} __ATTRIB_PACK__ IEEEtypes_AssocRsp_t;
++
++typedef struct
++{
++ u8 ElementId;
++ u8 Len;
++ u8 Oui[3];
++ u8 OuiType;
++ u8 OuiSubtype;
++ u8 Version;
++} __ATTRIB_PACK__ IEEEtypes_VendorHeader_t;
++
++typedef struct
++{
++ IEEEtypes_VendorHeader_t VendHdr;
++
++ /* IE Max - size of previous fields */
++ u8 Data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_VendorHeader_t)];
++
++}
++__ATTRIB_PACK__ IEEEtypes_VendorSpecific_t;
++
++typedef struct
++{
++ IEEEtypes_Header_t IeeeHdr;
++
++ /* IE Max - size of previous fields */
++ u8 Data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_Header_t)];
++
++}
++__ATTRIB_PACK__ IEEEtypes_Generic_t;
++
++/** TLV type ID definition */
++#define PROPRIETARY_TLV_BASE_ID 0x0100
++
++/* Terminating TLV Type */
++#define MRVL_TERMINATE_TLV_ID 0xffff
++
++#define TLV_TYPE_SSID 0x0000
++#define TLV_TYPE_RATES 0x0001
++#define TLV_TYPE_PHY_FH 0x0002
++#define TLV_TYPE_PHY_DS 0x0003
++#define TLV_TYPE_CF 0x0004
++#define TLV_TYPE_IBSS 0x0006
++
++#define TLV_TYPE_DOMAIN 0x0007
++
++#define TLV_TYPE_POWER_CAPABILITY 0x0021
++
++#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
++#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1)
++#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2)
++#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4)
++#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5)
++#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6)
++#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7)
++#define TLV_TYPE_LED_GPIO (PROPRIETARY_TLV_BASE_ID + 8)
++#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 9)
++#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10)
++#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 12)
++#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 13)
++#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16)
++#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18)
++#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
++#define TLV_TYPE_POWERADAPTCFGEXT (PROPRIETARY_TLV_BASE_ID + 20)
++#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
++#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23)
++#define TLV_TYPE_AUTO_TX (PROPRIETARY_TLV_BASE_ID + 24)
++#define TLV_TYPE_WPS_ENROLLEE_PROBE_REQ_TLV (PROPRIETARY_TLV_BASE_ID + 27)
++#define TLV_TYPE_STARTBGSCANLATER (PROPRIETARY_TLV_BASE_ID + 30)
++#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31)
++#define TLV_TYPE_PRE_BEACON_LOST (PROPRIETARY_TLV_BASE_ID + 73)
++
++/** TLV related data structures*/
++/** MrvlIEtypesHeader_t */
++typedef struct _MrvlIEtypesHeader
++{
++ u16 Type;
++ u16 Len;
++} __ATTRIB_PACK__ MrvlIEtypesHeader_t;
++
++/** MrvlIEtypes_Data_t */
++typedef struct _MrvlIEtypes_Data_t
++{
++ MrvlIEtypesHeader_t Header;
++ u8 Data[1];
++} __ATTRIB_PACK__ MrvlIEtypes_Data_t;
++
++/** MrvlIEtypes_RatesParamSet_t */
++typedef struct _MrvlIEtypes_RatesParamSet_t
++{
++ MrvlIEtypesHeader_t Header;
++ u8 Rates[1];
++} __ATTRIB_PACK__ MrvlIEtypes_RatesParamSet_t;
++
++/** MrvlIEtypes_SsIdParamSet_t */
++typedef struct _MrvlIEtypes_SsIdParamSet_t
++{
++ MrvlIEtypesHeader_t Header;
++ u8 SsId[1];
++} __ATTRIB_PACK__ MrvlIEtypes_SsIdParamSet_t;
++
++/** MrvlIEtypes_WildCardSsIdParamSet_t */
++typedef struct _MrvlIEtypes_WildCardSsIdParamSet_t
++{
++ MrvlIEtypesHeader_t Header;
++ u8 MaxSsidLength;
++ u8 SsId[1];
++} __ATTRIB_PACK__ MrvlIEtypes_WildCardSsIdParamSet_t;
++
++/** ChanScanMode_t */
++typedef struct
++{
++ u8 PassiveScan:1;
++ u8 DisableChanFilt:1;
++ u8 Reserved_2_7:6;
++} __ATTRIB_PACK__ ChanScanMode_t;
++
++/** ChanScanParamSet_t */
++typedef struct _ChanScanParamSet_t
++{
++ u8 RadioType;
++ u8 ChanNumber;
++ ChanScanMode_t ChanScanMode;
++ u16 MinScanTime;
++ u16 MaxScanTime;
++} __ATTRIB_PACK__ ChanScanParamSet_t;
++
++/** MrvlIEtypes_ChanListParamSet_t */
++typedef struct _MrvlIEtypes_ChanListParamSet_t
++{
++ MrvlIEtypesHeader_t Header;
++ ChanScanParamSet_t ChanScanParam[1];
++} __ATTRIB_PACK__ MrvlIEtypes_ChanListParamSet_t;
++
++/** CfParamSet_t */
++typedef struct _CfParamSet_t
++{
++ u8 CfpCnt;
++ u8 CfpPeriod;
++ u16 CfpMaxDuration;
++ u16 CfpDurationRemaining;
++} __ATTRIB_PACK__ CfParamSet_t;
++
++/** IbssParamSet_t */
++typedef struct _IbssParamSet_t
++{
++ u16 AtimWindow;
++} __ATTRIB_PACK__ IbssParamSet_t;
++
++/** MrvlIEtypes_SsParamSet_t */
++typedef struct _MrvlIEtypes_SsParamSet_t
++{
++ MrvlIEtypesHeader_t Header;
++ union
++ {
++ CfParamSet_t CfParamSet[1];
++ IbssParamSet_t IbssParamSet[1];
++ } cf_ibss;
++} __ATTRIB_PACK__ MrvlIEtypes_SsParamSet_t;
++
++/** FhParamSet_t */
++typedef struct _FhParamSet_t
++{
++ u16 DwellTime;
++ u8 HopSet;
++ u8 HopPattern;
++ u8 HopIndex;
++} __ATTRIB_PACK__ FhParamSet_t;
++
++/** DsParamSet_t */
++typedef struct _DsParamSet_t
++{
++ u8 CurrentChan;
++} __ATTRIB_PACK__ DsParamSet_t;
++
++/** MrvlIEtypes_PhyParamSet_t */
++typedef struct _MrvlIEtypes_PhyParamSet_t
++{
++ MrvlIEtypesHeader_t Header;
++ union
++ {
++ FhParamSet_t FhParamSet[1];
++ DsParamSet_t DsParamSet[1];
++ } fh_ds;
++} __ATTRIB_PACK__ MrvlIEtypes_PhyParamSet_t;
++
++/** MrvlIEtypes_RsnParamSet_t */
++typedef struct _MrvlIEtypes_RsnParamSet_t
++{
++ MrvlIEtypesHeader_t Header;
++ u8 RsnIE[1];
++} __ATTRIB_PACK__ MrvlIEtypes_RsnParamSet_t;
++
++/** MrvlIEtypes_WmmParamSet_t */
++typedef struct _MrvlIEtypes_WmmParamSet_t
++{
++ MrvlIEtypesHeader_t Header;
++ u8 WmmIE[1];
++} __ATTRIB_PACK__ MrvlIEtypes_WmmParamSet_t;
++
++typedef struct
++{
++ MrvlIEtypesHeader_t Header;
++ u8 QueueIndex;
++ u8 Disabled;
++ u8 Reserved1;
++ u8 Reserved2;
++ u8 FlowRequired;
++ u8 FlowCreated;
++ u32 Reserved3;
++} __ATTRIB_PACK__ MrvlIEtypes_WmmQueueStatus_t;
++
++/** Table of TSF values returned in the scan result */
++typedef struct
++{
++ MrvlIEtypesHeader_t Header;
++ u64 tsfTable[1];
++} __ATTRIB_PACK__ MrvlIEtypes_TsfTimestamp_t;
++
++/** Local Power Capability */
++typedef struct _MrvlIEtypes_PowerCapability_t
++{
++ MrvlIEtypesHeader_t Header;
++ s8 MinPower;
++ s8 MaxPower;
++} __ATTRIB_PACK__ MrvlIEtypes_PowerCapability_t;
++
++/** MrvlIEtypes_RssiParamSet_t */
++typedef struct _MrvlIEtypes_RssiThreshold_t
++{
++ MrvlIEtypesHeader_t Header;
++ u8 RSSIValue;
++ u8 RSSIFreq;
++} __ATTRIB_PACK__ MrvlIEtypes_RssiThreshold_t;
++
++/** MrvlIEtypes_SnrThreshold_t */
++typedef struct _MrvlIEtypes_SnrThreshold_t
++{
++ MrvlIEtypesHeader_t Header;
++ u8 SNRValue;
++ u8 SNRFreq;
++} __ATTRIB_PACK__ MrvlIEtypes_SnrThreshold_t;
++
++/** MrvlIEtypes_PreBeaconLost_t */
++typedef struct _MrvlIEtypes_PreBeaconLost_t
++{
++ MrvlIEtypesHeader_t Header;
++ u8 PreBeaconLost;
++ u8 Reserved;
++} __ATTRIB_PACK__ MrvlIEtypes_PreBeaconLost_t;
++
++/** MrvlIEtypes_FailureCount_t */
++typedef struct _MrvlIEtypes_FailureCount_t
++{
++ MrvlIEtypesHeader_t Header;
++ u8 FailValue;
++ u8 FailFreq;
++} __ATTRIB_PACK__ MrvlIEtypes_FailureCount_t;
++
++/** MrvlIEtypes_BeaconsMissed_t */
++typedef struct _MrvlIEtypes_BeaconsMissed_t
++{
++ MrvlIEtypesHeader_t Header;
++ u8 BeaconMissed;
++ u8 Reserved;
++} __ATTRIB_PACK__ MrvlIEtypes_BeaconsMissed_t;
++
++/** MrvlIEtypes_NumProbes_t */
++typedef struct _MrvlIEtypes_NumProbes_t
++{
++ MrvlIEtypesHeader_t Header;
++ u16 NumProbes;
++} __ATTRIB_PACK__ MrvlIEtypes_NumProbes_t;
++
++/** MrvlIEtypes_StartBGScanLater_t */
++typedef struct _MrvlIEtypes_StartBGScanLater_t
++{
++ MrvlIEtypesHeader_t Header;
++ u16 StartLater;
++} __ATTRIB_PACK__ MrvlIEtypes_StartBGScanLater_t;
++
++typedef struct _LedGpio_t
++{
++ u8 LedNum; /* LED # mapped to GPIO pin # below */
++ u8 GpioNum; /* GPIO pin # used to control LED # above */
++} __ATTRIB_PACK__ LedGpio_t;
++
++/** MrvlIEtypes_LedGpio_t */
++typedef struct _MrvlIEtypes_LedGpio_t
++{
++ MrvlIEtypesHeader_t Header;
++ LedGpio_t LedGpio[1];
++} __ATTRIB_PACK__ MrvlIEtypes_LedGpio_t;
++
++/** MrvlIEtypes_LedBehavior_t */
++typedef struct _MrvlIEtypes_LedBehavior_t
++{
++ MrvlIEtypesHeader_t Header;
++ u8 FirmwareState; /* Firmware State */
++ u8 LedNum; /* LED # */
++ u8 LedState; /* LED State corresponding to Firmware State */
++ u8 LedArgs; /* Arguments for LED State */
++} __ATTRIB_PACK__ MrvlIEtypes_LedBehavior_t;
++
++typedef struct _PA_Group_t
++{
++ u16 PowerAdaptLevel;
++ u16 RateBitmap;
++ u32 Reserved;
++} __ATTRIB_PACK__ PA_Group_t;
++
++/** MrvlIEtypes_PA_Group_t */
++typedef struct _MrvlIEtypes_PowerAdapt_Group_t
++{
++ MrvlIEtypesHeader_t Header;
++ PA_Group_t PA_Group[MAX_POWER_ADAPT_GROUP];
++} __ATTRIB_PACK__ MrvlIEtypes_PowerAdapt_Group_t;
++
++typedef struct _AutoTx_MacFrame_t
++{
++ u16 Interval; /* in seconds */
++ u8 Priority; /* User Priority: 0~7, ignored if non-WMM */
++ u8 Reserved; /* set to 0 */
++ u16 FrameLen; /* Length of MAC frame payload */
++ u8 DestMacAddr[ETH_ALEN];
++ u8 SrcMacAddr[ETH_ALEN];
++ u8 Payload[];
++} __ATTRIB_PACK__ AutoTx_MacFrame_t;
++
++/** MrvlIEtypes_AutoTx_t */
++typedef struct _MrvlIEtypes_AutoTx_t
++{
++ MrvlIEtypesHeader_t Header;
++ AutoTx_MacFrame_t AutoTx_MacFrame;
++} __ATTRIB_PACK__ MrvlIEtypes_AutoTx_t;
++
++typedef struct
++{
++ u8 value;
++ u8 Freq;
++} Threshold;
++
++typedef struct
++{
++ u16 EventsBitmap; /* bit 0: RSSI low, bit 1: SNR low,
++ * bit 2: RSSI high, bit 3: SNR high
++ */
++ Threshold Rssi_low;
++ Threshold Snr_low;
++ Threshold Rssi_high;
++ Threshold Snr_high;
++ u8 Rssi_low_count;
++ u8 Snr_low_count;
++ u8 Rssi_high_count;
++ u8 Snr_high_count;
++} wlan_subscribe_event;
++
++/** Auth type to be used in the Authentication portion of an Assoc seq */
++typedef struct
++{
++ MrvlIEtypesHeader_t Header;
++ u16 AuthType;
++} __ATTRIB_PACK__ MrvlIEtypes_AuthType_t;
++
++#define MRVDRV_MAX_SUBBAND_802_11D 83
++#define COUNTRY_CODE_LEN 3
++
++/** Data structure for Country IE*/
++typedef struct _IEEEtypes_SubbandSet
++{
++ u8 FirstChan;
++ u8 NoOfChan;
++ u8 MaxTxPwr;
++} __ATTRIB_PACK__ IEEEtypes_SubbandSet_t;
++
++typedef struct _IEEEtypes_CountryInfoSet
++{
++ u8 ElementId;
++ u8 Len;
++ u8 CountryCode[COUNTRY_CODE_LEN];
++ IEEEtypes_SubbandSet_t Subband[1];
++} __ATTRIB_PACK__ IEEEtypes_CountryInfoSet_t;
++
++typedef struct _IEEEtypes_CountryInfoFullSet
++{
++ u8 ElementId;
++ u8 Len;
++ u8 CountryCode[COUNTRY_CODE_LEN];
++ IEEEtypes_SubbandSet_t Subband[MRVDRV_MAX_SUBBAND_802_11D];
++} __ATTRIB_PACK__ IEEEtypes_CountryInfoFullSet_t;
++
++typedef struct _MrvlIEtypes_DomainParamSet
++{
++ MrvlIEtypesHeader_t Header;
++ u8 CountryCode[COUNTRY_CODE_LEN];
++ IEEEtypes_SubbandSet_t Subband[1];
++} __ATTRIB_PACK__ MrvlIEtypes_DomainParamSet_t;
++
++/** Size of a TSPEC. Used to allocate necessary buffer space in commands */
++#define WMM_TSPEC_SIZE 63
++
++/** Extra IE bytes allocated in messages for appended IEs after a TSPEC */
++#define WMM_ADDTS_EXTRA_IE_BYTES 256
++
++/** Extra TLV bytes allocated in messages for configuring WMM Queues */
++#define WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES 64
++/** Maximum number of AC QOS queues available in the driver/firmware */
++#define MAX_AC_QUEUES 4
++
++/** enum of WMM AC_QUEUES */
++typedef enum
++{
++ WMM_AC_BK,
++ WMM_AC_BE,
++ WMM_AC_VI,
++ WMM_AC_VO,
++} __ATTRIB_PACK__ wlan_wmm_ac_e;
++
++/** data structure of WMM QoS information */
++typedef struct
++{
++ u8 ParaSetCount:4;
++ u8 Reserved:3;
++ u8 QosUAPSD:1;
++} __ATTRIB_PACK__ IEEEtypes_WmmQosInfo_t;
++
++typedef struct
++{
++ u8 Aifsn:4;
++ u8 Acm:1;
++ u8 Aci:2;
++ u8 Reserved:1;
++} __ATTRIB_PACK__ IEEEtypes_WmmAciAifsn_t;
++
++/** data structure of WMM ECW */
++typedef struct
++{
++ u8 EcwMin:4;
++ u8 EcwMax:4;
++} __ATTRIB_PACK__ IEEEtypes_WmmEcw_t;
++
++/** data structure of WMM AC parameters */
++typedef struct
++{
++ IEEEtypes_WmmAciAifsn_t AciAifsn;
++ IEEEtypes_WmmEcw_t Ecw;
++ u16 TxopLimit;
++} __ATTRIB_PACK__ IEEEtypes_WmmAcParameters_t;
++
++/** data structure of WMM Info IE */
++typedef struct
++{
++
++ /**
++ * WMM Info IE - Vendor Specific Header:
++ * ElementId [221/0xdd]
++ * Len [7]
++ * Oui [00:50:f2]
++ * OuiType [2]
++ * OuiSubType [0]
++ * Version [1]
++ */
++ IEEEtypes_VendorHeader_t VendHdr;
++
++ IEEEtypes_WmmQosInfo_t QoSInfo;
++
++} __ATTRIB_PACK__ IEEEtypes_WmmInfo_t;
++
++/** data structure of WMM parameter IE */
++typedef struct
++{
++ /**
++ * WMM Parameter IE - Vendor Specific Header:
++ * ElementId [221/0xdd]
++ * Len [24]
++ * Oui [00:50:f2]
++ * OuiType [2]
++ * OuiSubType [1]
++ * Version [1]
++ */
++ IEEEtypes_VendorHeader_t VendHdr;
++
++ IEEEtypes_WmmQosInfo_t QoSInfo;
++ u8 Reserved;
++
++ /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
++ IEEEtypes_WmmAcParameters_t AcParams[MAX_AC_QUEUES];
++
++} __ATTRIB_PACK__ IEEEtypes_WmmParameter_t;
++
++/**
++ * @brief Firmware command structure to retrieve the firmware WMM status.
++ *
++ * Used to retrieve the status of each WMM AC Queue in TLV
++ * format (MrvlIEtypes_WmmQueueStatus_t) as well as the current WMM
++ * parameter IE advertised by the AP.
++ *
++ * Used in response to a MACREG_INT_CODE_WMM_STATUS_CHANGE event signalling
++ * a QOS change on one of the ACs or a change in the WMM Parameter in
++ * the Beacon.
++ *
++ * TLV based command, byte arrays used for max sizing purpose. There are no
++ * arguments sent in the command, the TLVs are returned by the firmware.
++ */
++typedef struct
++{
++ u8 queueStatusTlv[sizeof(MrvlIEtypes_WmmQueueStatus_t) * MAX_AC_QUEUES];
++ u8 wmmParamTlv[sizeof(IEEEtypes_WmmParameter_t) + 2];
++
++}
++__ATTRIB_PACK__ HostCmd_DS_WMM_GET_STATUS;
++
++/**
++ * @brief Enumeration for the command result from an ADDTS or DELTS command
++ */
++typedef enum
++{
++ TSPEC_RESULT_SUCCESS = 0,
++ TSPEC_RESULT_EXEC_FAILURE = 1,
++ TSPEC_RESULT_TIMEOUT = 2,
++ TSPEC_RESULT_DATA_INVALID = 3,
++
++} __ATTRIB_PACK__ wlan_wmm_tspec_result_e;
++
++/**
++ * @brief IOCTL structure to send an ADDTS request and retrieve the response.
++ *
++ * IOCTL structure from the application layer relayed to firmware to
++ * instigate an ADDTS management frame with an appropriate TSPEC IE as well
++ * as any additional IEs appended in the ADDTS Action frame.
++ *
++ * @sa wlan_wmm_addts_req_ioctl
++ */
++typedef struct
++{
++ wlan_wmm_tspec_result_e commandResult;
++ u32 timeout_ms;
++
++ u8 ieeeStatusCode;
++
++ u8 tspecData[WMM_TSPEC_SIZE];
++
++ u8 addtsExtraIEBuf[WMM_ADDTS_EXTRA_IE_BYTES];
++
++} __ATTRIB_PACK__ wlan_ioctl_wmm_addts_req_t;
++
++/**
++ * @brief IOCTL structure to send a DELTS request.
++ *
++ * IOCTL structure from the application layer relayed to firmware to
++ * instigate an DELTS management frame with an appropriate TSPEC IE.
++ *
++ * @sa wlan_wmm_delts_req_ioctl
++ */
++typedef struct
++{
++ wlan_wmm_tspec_result_e commandResult; //!< Firmware execution result
++
++ u8 ieeeReasonCode; //!< IEEE reason code sent, unused for WMM
++
++ u8 tspecData[WMM_TSPEC_SIZE]; //!< TSPEC to send in the DELTS
++
++} __ATTRIB_PACK__ wlan_ioctl_wmm_delts_req_t;
++
++/**
++ * @brief Internal command structure used in executing an ADDTS command.
++ *
++ * Relay information between the IOCTL layer and the firmware command and
++ * command response procedures.
++ *
++ * @sa wlan_wmm_addts_req_ioctl
++ * @sa wlan_cmd_wmm_addts_req
++ * @sa wlan_cmdresp_wmm_addts_req
++ */
++typedef struct
++{
++ wlan_wmm_tspec_result_e commandResult;
++ u32 timeout_ms;
++
++ u8 dialogToken;
++ u8 ieeeStatusCode;
++
++ int tspecDataLen;
++ u8 tspecData[WMM_TSPEC_SIZE];
++ u8 addtsExtraIEBuf[WMM_ADDTS_EXTRA_IE_BYTES];
++
++} wlan_cmd_wmm_addts_req_t;
++
++/**
++ * @brief Internal command structure used in executing an DELTS command.
++ *
++ * Relay information between the IOCTL layer and the firmware command and
++ * command response procedures.
++ *
++ * @sa wlan_wmm_delts_req_ioctl
++ * @sa wlan_cmd_wmm_delts_req
++ * @sa wlan_cmdresp_wmm_delts_req
++ */
++typedef struct
++{
++ wlan_wmm_tspec_result_e commandResult;
++
++ u8 dialogToken;
++
++ u8 ieeeReasonCode;
++
++ int tspecDataLen;
++ u8 tspecData[WMM_TSPEC_SIZE];
++
++} wlan_cmd_wmm_delts_req_t;
++
++/**
++ * @brief Command structure for the HostCmd_CMD_WMM_ADDTS_REQ firmware command
++ *
++ */
++typedef struct
++{
++ wlan_wmm_tspec_result_e commandResult;
++ u32 timeout_ms;
++
++ u8 dialogToken;
++ u8 ieeeStatusCode;
++ u8 tspecData[WMM_TSPEC_SIZE];
++ u8 addtsExtraIEBuf[WMM_ADDTS_EXTRA_IE_BYTES];
++
++} __ATTRIB_PACK__ HostCmd_DS_WMM_ADDTS_REQ;
++
++/**
++ * @brief Command structure for the HostCmd_CMD_WMM_DELTS_REQ firmware command
++ */
++typedef struct
++{
++ wlan_wmm_tspec_result_e commandResult;
++ u8 dialogToken;
++ u8 ieeeReasonCode;
++ u8 tspecData[WMM_TSPEC_SIZE];
++
++} __ATTRIB_PACK__ HostCmd_DS_WMM_DELTS_REQ;
++
++/**
++ * @brief Enumeration for the action field in the Queue configure command
++ */
++typedef enum
++{
++ WMM_QUEUE_CONFIG_ACTION_GET = 0,
++ WMM_QUEUE_CONFIG_ACTION_SET = 1,
++ WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2,
++
++ WMM_QUEUE_CONFIG_ACTION_MAX
++} __ATTRIB_PACK__ wlan_wmm_queue_config_action_e;
++
++/**
++ * @brief Command structure for the HostCmd_CMD_WMM_QUEUE_CONFIG firmware cmd
++ *
++ * Set/Get/Default the Queue parameters for a specific AC in the firmware.
++ *
++ */
++typedef struct
++{
++ wlan_wmm_queue_config_action_e action; //!< Set, Get, or Default
++ wlan_wmm_ac_e accessCategory; //!< WMM_AC_BK(0) to WMM_AC_VO(3)
++
++ /** @brief MSDU lifetime expiry per 802.11e
++ *
++ * - Ignored if 0 on a set command
++ * - Set to the 802.11e specified 500 TUs when defaulted
++ */
++ u16 msduLifetimeExpiry;
++
++ u8 tlvBuffer[WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES]; //!< Not supported yet
++
++} __ATTRIB_PACK__ HostCmd_DS_WMM_QUEUE_CONFIG;
++
++/**
++ * @brief Internal command structure used in executing a queue config command.
++ *
++ * Relay information between the IOCTL layer and the firmware command and
++ * command response procedures.
++ *
++ * @sa wlan_wmm_queue_config_ioctl
++ * @sa wlan_cmd_wmm_queue_config
++ * @sa wlan_cmdresp_wmm_queue_config
++ */
++typedef struct
++{
++ wlan_wmm_queue_config_action_e action; //!< Set, Get, or Default
++ wlan_wmm_ac_e accessCategory; //!< WMM_AC_BK(0) to WMM_AC_VO(3)
++ u16 msduLifetimeExpiry; //!< lifetime expiry in TUs
++
++ int tlvBufLen; //!< Not supported yet
++ u8 tlvBuffer[WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES]; //!< Not supported yet
++
++} wlan_cmd_wmm_queue_config_t;
++
++/**
++ * @brief IOCTL structure to configure a specific AC Queue's parameters
++ *
++ * IOCTL structure from the application layer relayed to firmware to
++ * get, set, or default the WMM AC queue parameters.
++ *
++ * - msduLifetimeExpiry is ignored if set to 0 on a set command
++ *
++ * @sa wlan_wmm_queue_config_ioctl
++ */
++typedef struct
++{
++ wlan_wmm_queue_config_action_e action; //!< Set, Get, or Default
++ wlan_wmm_ac_e accessCategory; //!< WMM_AC_BK(0) to WMM_AC_VO(3)
++ u16 msduLifetimeExpiry; //!< lifetime expiry in TUs
++
++ u8 supportedRates[10]; //!< Not supported yet
++
++} __ATTRIB_PACK__ wlan_ioctl_wmm_queue_config_t;
++
++/**
++ * @brief Enumeration for the action field in the queue stats command
++ */
++typedef enum
++{
++ WMM_STATS_ACTION_START = 0,
++ WMM_STATS_ACTION_STOP = 1,
++ WMM_STATS_ACTION_GET_CLR = 2,
++ WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */
++ WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */
++
++ WMM_STATS_ACTION_MAX
++} __ATTRIB_PACK__ wlan_wmm_stats_action_e;
++
++/** Number of bins in the histogram for the HostCmd_DS_WMM_QUEUE_STATS */
++#define WMM_STATS_PKTS_HIST_BINS 7
++
++/**
++ * @brief Command structure for the HostCmd_CMD_WMM_QUEUE_STATS firmware cmd
++ *
++ * Turn statistical collection on/off for a given AC or retrieve the
++ * accumulated stats for an AC and clear them in the firmware.
++ */
++typedef struct
++{
++ wlan_wmm_stats_action_e action; //!< Start, Stop, or Get
++ wlan_wmm_ac_e accessCategory; //!< WMM_AC_BK(0) to WMM_AC_VO(3)
++
++ u16 pktCount; //!< Number of successful packets transmitted
++ u16 pktLoss; //!< Packets lost; not included in pktCount
++ u32 avgQueueDelay; //!< Average Queue delay in microseconds
++ u32 avgTxDelay; //!< Average Transmission delay in microseconds
++ u32 usedTime; //!< Calculated medium time - Not currently used
++
++ /** @brief Queue Delay Histogram; number of packets per queue delay range
++ *
++ * [0] - 0ms <= delay < 5ms
++ * [1] - 5ms <= delay < 10ms
++ * [2] - 10ms <= delay < 20ms
++ * [3] - 20ms <= delay < 30ms
++ * [4] - 30ms <= delay < 40ms
++ * [5] - 40ms <= delay < 50ms
++ * [6] - 50ms <= delay < msduLifetime (TUs)
++ */
++ u16 delayHistogram[WMM_STATS_PKTS_HIST_BINS];
++
++ u16 reserved_u16_1;
++
++} __ATTRIB_PACK__ HostCmd_DS_WMM_QUEUE_STATS;
++
++/**
++ * @brief IOCTL structure to start, stop, and get statistics for a WMM AC
++ *
++ * IOCTL structure from the application layer relayed to firmware to
++ * start or stop statistical collection for a given AC. Also used to
++ * retrieve and clear the collected stats on a given AC.
++ *
++ * @sa wlan_wmm_queue_stats_ioctl
++ */
++typedef struct
++{
++ wlan_wmm_stats_action_e action; //!< Start, Stop, or Get
++ wlan_wmm_ac_e accessCategory; //!< WMM_AC_BK(0) to WMM_AC_VO(3)
++ u16 pktCount; //!< Number of successful packets transmitted
++ u16 pktLoss; //!< Packets lost; not included in pktCount
++ u32 avgQueueDelay; //!< Average Queue delay in microseconds
++ u32 avgTxDelay; //!< Average Transmission delay in microseconds
++ u32 usedTime; //!< Calculated medium time
++
++ /** @brief Queue Delay Histogram; number of packets per queue delay range
++ *
++ * [0] - 0ms <= delay < 5ms
++ * [1] - 5ms <= delay < 10ms
++ * [2] - 10ms <= delay < 20ms
++ * [3] - 20ms <= delay < 30ms
++ * [4] - 30ms <= delay < 40ms
++ * [5] - 40ms <= delay < 50ms
++ * [6] - 50ms <= delay < msduLifetime (TUs)
++ */
++ u16 delayHistogram[WMM_STATS_PKTS_HIST_BINS];
++} __ATTRIB_PACK__ wlan_ioctl_wmm_queue_stats_t;
++
++/**
++ * @brief IOCTL sub structure for a specific WMM AC Status
++ */
++typedef struct
++{
++ u8 wmmAcm;
++ u8 flowRequired;
++ u8 flowCreated;
++ u8 disabled;
++} __ATTRIB_PACK__ wlan_ioctl_wmm_queue_status_ac_t;
++
++/**
++ * @brief IOCTL structure to retrieve the WMM AC Queue status
++ *
++ * IOCTL structure from the application layer to retrieve:
++ * - ACM bit setting for the AC
++ * - Firmware status (flow required, flow created, flow disabled)
++ *
++ * @sa wlan_wmm_queue_status_ioctl
++ */
++typedef struct
++{
++ wlan_ioctl_wmm_queue_status_ac_t acStatus[MAX_AC_QUEUES];
++} __ATTRIB_PACK__ wlan_ioctl_wmm_queue_status_t;
++
++/** Firmware status for a specific AC */
++typedef struct
++{
++ u8 Disabled;
++ u8 FlowRequired;
++ u8 FlowCreated;
++} WmmAcStatus_t;
++
++#endif /* _WLAN_TYPES_ */
+diff --git a/drivers/net/wireless/marvell8686/wlan_version.h b/drivers/net/wireless/marvell8686/wlan_version.h
+new file mode 100644
+index 0000000..bacedd5
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_version.h
+@@ -0,0 +1,18 @@
++/** @file wlan_version.h
++ * @brief This file contains wlan driver version number.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++/********************************************************
++Change log:
++ 10/04/05: Add Doxygen format comments
++
++********************************************************/
++#include "release_version.h"
++
++const char driver_version[] =
++ "sd8686-%s-" DRIVER_RELEASE_VERSION "-(" "FP" "4" ")"
++#ifdef DEBUG_LEVEL2
++ "-dbg"
++#endif
++ " ";
+diff --git a/drivers/net/wireless/marvell8686/wlan_wext.c b/drivers/net/wireless/marvell8686/wlan_wext.c
+new file mode 100644
+index 0000000..adef3ab
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_wext.c
+@@ -0,0 +1,8047 @@
++/** @file wlan_wext.c
++ * @brief This file contains ioctl functions
++ *
++ * Copyright ?Marvell International Ltd. and/or its affiliates, 2003-2007
++ */
++/********************************************************
++Change log:
++ 10/10/05: Add Doxygen format comments
++ 12/23/05: Modify FindBSSIDInList to search entire table for
++ duplicate BSSIDs when earlier matches are not compatible
++ 12/26/05: Remove errant memcpy in wlanidle_off; overwriting stack space
++ 01/05/06: Add kernel 2.6.x support
++ 01/11/06: Conditionalize new scan/join functions.
++ Update statics/externs. Move forward decl. from wlan_decl.h
++ 04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
++ 04/10/06: Add hostcmd generic API
++ 04/18/06: Remove old Subscrive Event and add new Subscribe Event
++ implementation through generic hostcmd API
++ 05/04/06: Add IBSS coalescing related new iwpriv command
++ 08/29/06: Add ledgpio private command
++ 10/23/06: Validate setbcnavg/setdataavg command parameters and
++ return error if out of range
++********************************************************/
++
++#include "include.h"
++
++#include "wlan_version.h"
++
++#define GETLOG_BUFSIZE 512
++
++#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \
++ MRVDRV_MAX_SSID_LENGTH + \
++ IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \
++ IW_EV_QUAL_LEN + MRVDRV_MAX_SSID_LENGTH + \
++ IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */
++
++typedef struct _ioctl_cmd
++{
++ int cmd;
++ int subcmd;
++ BOOLEAN fixsize;
++} ioctl_cmd;
++
++static ioctl_cmd Commands_Allowed_In_DeepSleep[] = {
++ {.cmd = WLANDEEPSLEEP,.subcmd = 0,.fixsize = FALSE},
++ {.cmd = WLAN_SETONEINT_GETWORDCHAR,.subcmd = WLANVERSION,.fixsize =
++ FALSE},
++ {.cmd = WLAN_SETINT_GETINT,.subcmd = WLANSDIOCLOCK,.fixsize = TRUE},
++ {.cmd = WLAN_SET_GET_2K,.subcmd = WLAN_GET_CFP_TABLE,.fixsize = FALSE},
++#ifdef DEBUG_LEVEL1
++ {.cmd = WLAN_SET_GET_SIXTEEN_INT,.subcmd = WLAN_DRV_DBG,.fixsize = FALSE},
++#endif
++};
++
++static ioctl_cmd Commands_Allowed_In_HostSleep[] = {
++ {.cmd = WLAN_SETONEINT_GETWORDCHAR,.subcmd = WLANVERSION,.fixsize =
++ FALSE},
++ {.cmd = WLANDEEPSLEEP,.subcmd = 1,.fixsize = FALSE},
++ {.cmd = WLANDEEPSLEEP,.subcmd = 0,.fixsize = FALSE},
++ {.cmd = WLAN_SETINT_GETINT,.subcmd = WLANSDIOCLOCK,.fixsize = TRUE},
++ {.cmd = WLAN_SET_GET_2K,.subcmd = WLAN_GET_CFP_TABLE,.fixsize = FALSE},
++#ifdef DEBUG_LEVEL1
++ {.cmd = WLAN_SET_GET_SIXTEEN_INT,.subcmd = WLAN_DRV_DBG,.fixsize = FALSE},
++#endif
++};
++
++/********************************************************
++ Local Variables
++********************************************************/
++
++/********************************************************
++ Global Variables
++********************************************************/
++#ifdef DEBUG_LEVEL1
++#ifdef DEBUG_LEVEL2
++#define DEFAULT_DEBUG_MASK (0xffffffff & ~DBG_EVENT)
++#else
++#define DEFAULT_DEBUG_MASK (DBG_MSG | DBG_FATAL | DBG_ERROR)
++#endif
++u32 drvdbg = DEFAULT_DEBUG_MASK;
++u32 ifdbg = 0;
++#endif
++
++/********************************************************
++ Local Functions
++********************************************************/
++static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra);
++static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra);
++
++static int wlan_get_essid(struct net_device *dev,
++ struct iw_request_info *info, struct iw_point *dwrq,
++ char *extra);
++
++static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
++ struct iw_freq *fwrq, char *extra);
++static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
++ struct iw_freq *fwrq, char *extra);
++
++static int wlan_set_mode(struct net_device *dev, struct iw_request_info *info,
++ u32 * uwrq, char *extra);
++static int wlan_get_mode(struct net_device *dev, struct iw_request_info *info,
++ u32 * uwrq, char *extra);
++
++static int wlan_set_encode(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra);
++static int wlan_get_encode(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq, u8 * extra);
++
++static int wlan_set_txpow(struct net_device *dev,
++ struct iw_request_info *info, struct iw_param *vwrq,
++ char *extra);
++static int wlan_get_txpow(struct net_device *dev,
++ struct iw_request_info *info, struct iw_param *vwrq,
++ char *extra);
++
++static int wlan_set_coalescing_ioctl(wlan_private * priv, struct iwreq *wrq);
++
++extern CHANNEL_FREQ_POWER *wlan_get_region_cfp_table(u8 region, u8 band,
++ int *cfp_no);
++
++/**
++ * @brief This function checks if the commans is allowed
++ * in deepsleep/hostsleep mode or not.
++ *
++ * @param req A pointer to ifreq structure
++ * @param cmd the command ID
++ * @return TRUE or FALSE
++ */
++static BOOLEAN
++Is_Command_Allowed_In_Sleep(struct ifreq *req, int cmd,
++ ioctl_cmd * allowed_cmds, int count)
++{
++ int subcmd = 0;
++ struct iwreq *wrq = (struct iwreq *) req;
++ int i;
++
++ for (i = 0; i < count; i++) {
++ if (cmd == allowed_cmds[i].cmd) {
++ if (allowed_cmds[i].subcmd == 0)
++ return TRUE;
++ if (allowed_cmds[i].fixsize == TRUE)
++ subcmd = (int) req->ifr_data;
++ else
++ subcmd = wrq->u.data.flags;
++ if (allowed_cmds[i].subcmd == subcmd)
++ return TRUE;
++ }
++ }
++ return FALSE;
++}
++
++/**
++ * @brief This function checks if the command is allowed.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return TRUE or FALSE
++ */
++BOOLEAN
++Is_Command_Allowed(wlan_private * priv)
++{
++ BOOLEAN ret = TRUE;
++
++ if (priv->adapter->bHostSleepConfigured) {
++ PRINTM(INFO, "IOCTLS called when WLAN access is blocked\n");
++ ret = FALSE;
++ }
++ if (!priv->adapter->IsAutoDeepSleepEnabled) {
++ if ((priv->adapter->IsDeepSleep == TRUE)) {
++ PRINTM(INFO, "IOCTLS called when station is in DeepSleep\n");
++ ret = FALSE;
++ }
++ }
++
++ return ret;
++}
++
++/**
++ * @brief Find a character in a string.
++ *
++ * @param s A pointer to string
++ * @param c Character to be located
++ * @param dlen the length of string
++ * @return A pointer to the first occurrence of c in string, or NULL if c is not found.
++ */
++static void *
++wlan_memchr(void *s, int c, int n)
++{
++ const u8 *p = s;
++
++ while (n-- != 0) {
++ if ((u8) c == *p++) {
++ return (void *) (p - 1);
++ }
++ }
++ return NULL;
++}
++
++#if WIRELESS_EXT > 14
++/**
++ * @brief Convert mw value to dbm value
++ *
++ * @param mw the value of mw
++ * @return the value of dbm
++ */
++static int
++mw_to_dbm(int mw)
++{
++ if (mw < 2)
++ return 0;
++ else if (mw < 3)
++ return 3;
++ else if (mw < 4)
++ return 5;
++ else if (mw < 6)
++ return 7;
++ else if (mw < 7)
++ return 8;
++ else if (mw < 8)
++ return 9;
++ else if (mw < 10)
++ return 10;
++ else if (mw < 13)
++ return 11;
++ else if (mw < 16)
++ return 12;
++ else if (mw < 20)
++ return 13;
++ else if (mw < 25)
++ return 14;
++ else if (mw < 32)
++ return 15;
++ else if (mw < 40)
++ return 16;
++ else if (mw < 50)
++ return 17;
++ else if (mw < 63)
++ return 18;
++ else if (mw < 79)
++ return 19;
++ else if (mw < 100)
++ return 20;
++ else
++ return 21;
++}
++
++/**
++ * @brief This function sends customized event to application.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @para str A pointer to event string
++ * @return n/a
++ */
++void
++send_iwevcustom_event(wlan_private * priv, s8 * str)
++{
++ union iwreq_data iwrq;
++ u8 buf[50];
++
++ ENTER();
++
++ memset(&iwrq, 0, sizeof(union iwreq_data));
++ memset(buf, 0, sizeof(buf));
++
++ snprintf(buf, sizeof(buf) - 1, "%s", str);
++
++ iwrq.data.pointer = buf;
++ iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
++
++ /* Send Event to upper layer */
++ wireless_send_event(priv->wlan_dev.netdev, IWEVCUSTOM, &iwrq, buf);
++ PRINTM(INFO, "Wireless event %s is sent to app\n", str);
++
++ LEAVE();
++ return;
++}
++#endif
++
++/**
++ * @brief Find the channel frequency power info with specific channel
++ *
++ * @param adapter A pointer to wlan_adapter structure
++ * @param band it can be BAND_A, BAND_G or BAND_B
++ * @param channel the channel for looking
++ * @return A pointer to CHANNEL_FREQ_POWER structure or NULL if not find.
++ */
++CHANNEL_FREQ_POWER *
++find_cfp_by_band_and_channel(wlan_adapter * adapter, u8 band, u16 channel)
++{
++ CHANNEL_FREQ_POWER *cfp = NULL;
++
++ ENTER();
++
++ if (adapter->State11D.Enable11D == ENABLE_11D)
++ cfp =
++ get_cfp_by_band_and_channel(band, channel,
++ adapter->universal_channel);
++ else
++ cfp =
++ get_cfp_by_band_and_channel(band, channel,
++ adapter->region_channel);
++
++ return cfp;
++}
++
++/**
++ * @brief Find the channel frequency power info with specific frequency
++ *
++ * @param adapter A pointer to wlan_adapter structure
++ * @param band it can be BAND_A, BAND_G or BAND_B
++ * @param freq the frequency for looking
++ * @return Pointer to CHANNEL_FREQ_POWER structure; NULL if not found
++ */
++static CHANNEL_FREQ_POWER *
++find_cfp_by_band_and_freq(wlan_adapter * adapter, u8 band, u32 freq)
++{
++ CHANNEL_FREQ_POWER *cfp = NULL;
++ REGION_CHANNEL *rc;
++ int count = sizeof(adapter->region_channel) /
++ sizeof(adapter->region_channel[0]);
++ int i, j;
++
++ for (j = 0; !cfp && (j < count); j++) {
++ rc = &adapter->region_channel[j];
++
++ if (adapter->State11D.Enable11D == ENABLE_11D) {
++ rc = &adapter->universal_channel[j];
++ }
++
++ if (!rc->Valid || !rc->CFP)
++ continue;
++ if (rc->Band != band)
++ continue;
++ for (i = 0; i < rc->NrCFP; i++) {
++ if (rc->CFP[i].Freq == freq) {
++ cfp = &rc->CFP[i];
++ break;
++ }
++ }
++ }
++
++ if (!cfp && freq)
++ PRINTM(INFO, "find_cfp_by_band_and_freql(): cannot find cfp by "
++ "band %d & freq %d\n", band, freq);
++
++ return cfp;
++}
++
++#ifdef MFG_CMD_SUPPORT
++/**
++ * @brief Manufacturing command ioctl function
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS--success, otherwise--fail
++ */
++static int
++wlan_mfg_command(wlan_private * priv, struct iwreq *wrq)
++{
++ HostCmd_DS_GEN *pCmdPtr;
++ u8 *mfg_cmd;
++ u16 mfg_cmd_len;
++ int ret;
++
++ ENTER();
++
++ /* allocate MFG command buffer */
++ if (!(mfg_cmd = kmalloc(MRVDRV_SIZE_OF_CMD_BUFFER, GFP_KERNEL))) {
++ PRINTM(INFO, "allocate MFG command buffer failed!\n");
++ return -ENOMEM;
++ }
++
++ /* get MFG command header */
++ if (copy_from_user(mfg_cmd, wrq->u.data.pointer, sizeof(HostCmd_DS_GEN))) {
++ PRINTM(INFO, "copy from user failed: MFG command header\n");
++ ret = -EFAULT;
++ goto mfg_exit;
++ }
++
++ /* get the command size */
++ pCmdPtr = (HostCmd_DS_GEN *) mfg_cmd;
++ mfg_cmd_len = pCmdPtr->Size;
++ PRINTM(INFO, "MFG command len = %d\n", mfg_cmd_len);
++
++ if (mfg_cmd_len > MRVDRV_SIZE_OF_CMD_BUFFER) {
++ ret = -EINVAL;
++ goto mfg_exit;
++ }
++
++ /* get the whole command from user */
++ if (copy_from_user(mfg_cmd, wrq->u.data.pointer, mfg_cmd_len)) {
++ PRINTM(INFO, "copy from user failed: MFG command\n");
++ ret = -EFAULT;
++ goto mfg_exit;
++ }
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_MFG_COMMAND,
++ 0, HostCmd_OPTION_WAITFORRSP, 0, mfg_cmd);
++
++ /* copy the response back to user */
++ if (!ret && pCmdPtr->Size) {
++ mfg_cmd_len = MIN(pCmdPtr->Size, mfg_cmd_len);
++ if (copy_to_user(wrq->u.data.pointer, mfg_cmd, mfg_cmd_len)) {
++ PRINTM(INFO, "copy to user failed: MFG command\n");
++ ret = -EFAULT;
++ }
++ wrq->u.data.length = mfg_cmd_len;
++ }
++
++ mfg_exit:
++ kfree(mfg_cmd);
++ LEAVE();
++ return ret;
++}
++#endif
++
++/**
++ * @brief Check if Rate Auto
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return TRUE/FALSE
++ */
++BOOLEAN
++Is_Rate_Auto(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int i;
++ int ratenum = 0;
++ int bitsize = 0;
++ bitsize = sizeof(Adapter->RateBitmap) * 8;
++ for (i = 0; i < bitsize; i++) {
++ if (Adapter->RateBitmap & (1 << i))
++ ratenum++;
++ if (ratenum > 1)
++ break;
++ }
++ if (ratenum > 1)
++ return TRUE;
++ else
++ return FALSE;
++}
++
++/**
++ * @brief Covert Rate Bitmap to Rate index
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return TRUE/FALSE
++ */
++int
++GetRateIndex(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int bitsize = sizeof(Adapter->RateBitmap) * 8;
++ int i;
++ for (i = 0; i < bitsize; i++) {
++ if (Adapter->RateBitmap & (1 << i))
++ return i;
++ }
++ return 0;
++}
++
++/**
++ * @brief Update Current Channel
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
++ */
++static int
++UpdateCurrentChannel(wlan_private * priv)
++{
++ int ret;
++
++ /*
++ ** the channel in f/w could be out of sync, get the current channel
++ */
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RF_CHANNEL,
++ HostCmd_OPT_802_11_RF_CHANNEL_GET,
++ HostCmd_OPTION_WAITFORRSP, 0, NULL);
++
++ PRINTM(INFO, "Current Channel = %d\n",
++ priv->adapter->CurBssParams.BSSDescriptor.Channel);
++
++ return ret;
++}
++
++/**
++ * @brief Set Current Channel
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param channel The channel to be set.
++ * @return WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
++ */
++static int
++SetCurrentChannel(wlan_private * priv, int channel)
++{
++ PRINTM(INFO, "Set Channel = %d\n", channel);
++
++ /*
++ ** Current channel is not set to AdhocChannel requested, set channel
++ */
++ return (PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RF_CHANNEL,
++ HostCmd_OPT_802_11_RF_CHANNEL_SET,
++ HostCmd_OPTION_WAITFORRSP, 0, &channel));
++}
++
++/**
++ * @brief Change Adhoc Channel
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param channel The channel to be set.
++ * @return WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
++ */
++static int
++ChangeAdhocChannel(wlan_private * priv, int channel)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_adapter *Adapter = priv->adapter;
++
++ Adapter->AdhocChannel = channel;
++
++ UpdateCurrentChannel(priv);
++
++ if (Adapter->CurBssParams.BSSDescriptor.Channel == Adapter->AdhocChannel) {
++ /* AdhocChannel is set to the current Channel already */
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++ }
++
++ PRINTM(INFO, "Updating Channel from %d to %d\n",
++ Adapter->CurBssParams.BSSDescriptor.Channel,
++ Adapter->AdhocChannel);
++
++ SetCurrentChannel(priv, Adapter->AdhocChannel);
++
++ UpdateCurrentChannel(priv);
++
++ if (Adapter->CurBssParams.BSSDescriptor.Channel != Adapter->AdhocChannel) {
++ PRINTM(INFO, "Failed to updated Channel to %d, channel = %d\n",
++ Adapter->AdhocChannel,
++ Adapter->CurBssParams.BSSDescriptor.Channel);
++ LEAVE();
++ return WLAN_STATUS_FAILURE;
++ }
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ int i;
++ WLAN_802_11_SSID curAdhocSsid;
++
++ PRINTM(INFO, "Channel Changed while in an IBSS\n");
++
++ /* Copy the current ssid */
++ memcpy(&curAdhocSsid,
++ &Adapter->CurBssParams.BSSDescriptor.Ssid,
++ sizeof(WLAN_802_11_SSID));
++
++ /* Exit Adhoc mode */
++ PRINTM(INFO, "In ChangeAdhocChannel(): Sending Adhoc Stop\n");
++ ret = StopAdhocNetwork(priv);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++
++ /* Scan for the network */
++ SendSpecificSSIDScan(priv, &curAdhocSsid);
++
++ // find out the BSSID that matches the current SSID
++ i = FindSSIDInList(Adapter, &curAdhocSsid, NULL, Wlan802_11IBSS);
++
++ if (i >= 0) {
++ PRINTM(INFO, "SSID found at %d in List," "so join\n", i);
++ JoinAdhocNetwork(priv, &Adapter->ScanTable[i]);
++ } else {
++ // else send START command
++ PRINTM(INFO, "SSID not found in list, "
++ "so creating adhoc with ssid = %s\n", curAdhocSsid.Ssid);
++ StartAdhocNetwork(priv, &curAdhocSsid);
++ } // end of else (START command)
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Set/Get WPA IE
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param ie_data_ptr A pointer to IE
++ * @param ie_len Length of the IE
++ *
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_wpa_ie_helper(wlan_private * priv, u8 * ie_data_ptr, u16 ie_len)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (ie_len) {
++ if (ie_len > sizeof(Adapter->Wpa_ie)) {
++ PRINTM(INFO, "failed to copy WPA IE, too big \n");
++ return -EFAULT;
++ }
++ if (copy_from_user(Adapter->Wpa_ie, ie_data_ptr, ie_len)) {
++ PRINTM(INFO, "failed to copy WPA IE \n");
++ return -EFAULT;
++ }
++ Adapter->Wpa_ie_len = ie_len;
++ PRINTM(INFO, "Set Wpa_ie_len=%d IE=%#x\n",
++ Adapter->Wpa_ie_len, Adapter->Wpa_ie[0]);
++ HEXDUMP("Wpa_ie", Adapter->Wpa_ie, Adapter->Wpa_ie_len);
++
++ if (Adapter->Wpa_ie[0] == WPA_IE) {
++ Adapter->SecInfo.WPAEnabled = TRUE;
++ } else if (Adapter->Wpa_ie[0] == RSN_IE) {
++ Adapter->SecInfo.WPA2Enabled = TRUE;
++ } else {
++ Adapter->SecInfo.WPAEnabled = FALSE;
++ Adapter->SecInfo.WPA2Enabled = FALSE;
++ }
++ } else {
++ memset(Adapter->Wpa_ie, 0, sizeof(Adapter->Wpa_ie));
++ Adapter->Wpa_ie_len = ie_len;
++ PRINTM(INFO, "Reset Wpa_ie_len=%d IE=%#x\n",
++ Adapter->Wpa_ie_len, Adapter->Wpa_ie[0]);
++ Adapter->SecInfo.WPAEnabled = FALSE;
++ Adapter->SecInfo.WPA2Enabled = FALSE;
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Set/Get WPA IE
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ *
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_wpa_ie_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *) req;
++
++ return wlan_set_wpa_ie_helper(priv,
++ wrq->u.data.pointer, wrq->u.data.length);
++}
++
++/**
++ * @brief Set WPA key
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_encode_wpa(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_private *priv = dev->priv;
++ WLAN_802_11_KEY *pKey;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ pKey = (WLAN_802_11_KEY *) extra;
++
++ HEXDUMP("Key buffer: ", extra, dwrq->length);
++
++ // current driver only supports key length of up to 32 bytes
++ if (pKey->KeyLength > MRVL_MAX_WPA_KEY_LENGTH) {
++ PRINTM(INFO, " Error in key length \n");
++ return WLAN_STATUS_FAILURE;
++ }
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_KEY_MATERIAL,
++ HostCmd_ACT_SET,
++ HostCmd_OPTION_WAITFORRSP,
++ KEY_INFO_ENABLED, pKey);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/*
++ * iwconfig ethX key on: WEPEnabled;
++ * iwconfig ethX key off: WEPDisabled;
++ * iwconfig ethX key [x]: CurrentWepKeyIndex = x; WEPEnabled;
++ * iwconfig ethX key [x] kstr: WepKey[x] = kstr;
++ * iwconfig ethX key kstr: WepKey[CurrentWepKeyIndex] = kstr;
++ *
++ * all: Send command SET_WEP;
++ SetMacPacketFilter;
++ */
++
++/**
++ * @brief Set WEP key
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_encode_nonwpa(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ MRVL_WEP_KEY *pWep;
++ int index, PrevAuthMode;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ if (Adapter->CurrentWepKeyIndex >= MRVL_NUM_WEP_KEY)
++ Adapter->CurrentWepKeyIndex = 0;
++ pWep = &Adapter->WepKey[Adapter->CurrentWepKeyIndex];
++ PrevAuthMode = Adapter->SecInfo.AuthenticationMode;
++
++ index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
++
++ if (index >= 4) {
++ PRINTM(INFO, "Key index #%d out of range.\n", index + 1);
++ return -EINVAL;
++ }
++
++ PRINTM(INFO, "Flags=0x%x, Length=%d Index=%d CurrentWepKeyIndex=%d\n",
++ dwrq->flags, dwrq->length, index, Adapter->CurrentWepKeyIndex);
++
++ if (dwrq->length > 0) {
++ /* iwconfig ethX key [n] xxxxxxxxxxx
++ * Key has been provided by the user
++ */
++
++ /*
++ * Check the size of the key
++ */
++
++ if (dwrq->length > MAX_WEP_KEY_SIZE) {
++ return -EINVAL;
++ }
++
++ /*
++ * Check the index (none -> use current)
++ */
++
++ if (index < 0 || index > 3) //invalid index or no index
++ index = Adapter->CurrentWepKeyIndex;
++ else //index is given & valid
++ pWep = &Adapter->WepKey[index];
++
++ /*
++ * Check if the key is not marked as invalid
++ */
++ if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
++ /* Cleanup */
++ memset(pWep, 0, sizeof(MRVL_WEP_KEY));
++
++ /* Copy the key in the driver */
++ memcpy(pWep->KeyMaterial, extra, dwrq->length);
++
++ /* Set the length */
++ if (dwrq->length > MIN_WEP_KEY_SIZE) {
++ pWep->KeyLength = MAX_WEP_KEY_SIZE;
++ } else {
++ if (dwrq->length > 0) {
++ pWep->KeyLength = MIN_WEP_KEY_SIZE;
++ } else {
++ /* Disable the key */
++ pWep->KeyLength = 0;
++ }
++ }
++ pWep->KeyIndex = index;
++
++ if (Adapter->SecInfo.WEPStatus != Wlan802_11WEPEnabled) {
++ /*
++ * The status is set as Key Absent
++ * so as to make sure we display the
++ * keys when iwlist ethX key is used
++ */
++ Adapter->SecInfo.WEPStatus = Wlan802_11WEPKeyAbsent;
++ }
++
++ PRINTM(INFO, "KeyIndex=%u KeyLength=%u\n",
++ pWep->KeyIndex, pWep->KeyLength);
++ HEXDUMP("WepKey", (u8 *) pWep->KeyMaterial, pWep->KeyLength);
++ }
++ } else {
++ /*
++ * No key provided so it is either enable key,
++ * on or off */
++ if (dwrq->flags & IW_ENCODE_DISABLED) {
++ PRINTM(INFO, "*** iwconfig ethX key off ***\n");
++
++ Adapter->SecInfo.WEPStatus = Wlan802_11WEPDisabled;
++ if (Adapter->SecInfo.AuthenticationMode ==
++ Wlan802_11AuthModeShared)
++ Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
++ } else {
++ /* iwconfig ethX key [n]
++ * iwconfig ethX key on
++ * Do we want to just set the transmit key index ?
++ */
++
++ if (index < 0 || index > 3) {
++ PRINTM(INFO, "*** iwconfig ethX key on ***\n");
++ index = Adapter->CurrentWepKeyIndex;
++ } else {
++ PRINTM(INFO, "*** iwconfig ethX key [x=%d] ***\n", index);
++ Adapter->CurrentWepKeyIndex = index;
++ }
++
++ /* Copy the required key as the current key */
++ pWep = &Adapter->WepKey[index];
++
++ if (!pWep->KeyLength) {
++ PRINTM(INFO, "Key not set,so cannot enable it\n");
++ return -EPERM;
++ }
++
++ Adapter->SecInfo.WEPStatus = Wlan802_11WEPEnabled;
++
++ HEXDUMP("KeyMaterial", (u8 *) pWep->KeyMaterial, pWep->KeyLength);
++ }
++ }
++
++ if (pWep->KeyLength) {
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_SET_WEP,
++ 0, HostCmd_OPTION_WAITFORRSP,
++ OID_802_11_ADD_WEP, NULL);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ }
++
++ if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled) {
++ Adapter->CurrentPacketFilter |= HostCmd_ACT_MAC_WEP_ENABLE;
++ } else {
++ Adapter->CurrentPacketFilter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
++ }
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_MAC_CONTROL,
++ 0, HostCmd_OPTION_WAITFORRSP,
++ 0, &Adapter->CurrentPacketFilter);
++
++ if (dwrq->flags & IW_ENCODE_RESTRICTED) {
++ /* iwconfig ethX restricted key [1] */
++ Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeShared;
++ PRINTM(INFO, "Auth mode restricted!\n");
++ } else if (dwrq->flags & IW_ENCODE_OPEN) {
++ /* iwconfig ethX key [2] open */
++ Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
++ PRINTM(INFO, "Auth mode open!\n");
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Set RX Antenna
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param Mode RF antenna mode
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++SetRxAntenna(wlan_private * priv, int Mode)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_adapter *Adapter = priv->adapter;
++
++ if (Mode != RF_ANTENNA_1 && Mode != RF_ANTENNA_2
++ && Mode != RF_ANTENNA_AUTO) {
++ return -EINVAL;
++ }
++
++ Adapter->RxAntennaMode = Mode;
++
++ PRINTM(INFO, "SET RX Antenna Mode to 0x%04x\n", Adapter->RxAntennaMode);
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RF_ANTENNA,
++ HostCmd_ACT_SET_RX, HostCmd_OPTION_WAITFORRSP,
++ 0, &Adapter->RxAntennaMode);
++ return ret;
++}
++
++/**
++ * @brief Set TX Antenna
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param Mode RF antenna mode
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++SetTxAntenna(wlan_private * priv, int Mode)
++{
++ int ret = 0;
++ wlan_adapter *Adapter = priv->adapter;
++
++ if ((Mode != RF_ANTENNA_1) && (Mode != RF_ANTENNA_2)
++ && (Mode != RF_ANTENNA_AUTO)) {
++ return -EINVAL;
++ }
++
++ Adapter->TxAntennaMode = Mode;
++
++ PRINTM(INFO, "SET TX Antenna Mode to 0x%04x\n", Adapter->TxAntennaMode);
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RF_ANTENNA,
++ HostCmd_ACT_SET_TX, HostCmd_OPTION_WAITFORRSP,
++ 0, &Adapter->TxAntennaMode);
++
++ return ret;
++}
++
++/**
++ * @brief Get RX Antenna
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param buf A pointer to recieve antenna mode
++ * @return length of buf
++ */
++static int
++GetRxAntenna(wlan_private * priv, char *buf)
++{
++ int ret = 0;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ // clear it, so we will know if the value
++ // returned below is correct or not.
++ Adapter->RxAntennaMode = 0;
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RF_ANTENNA,
++ HostCmd_ACT_GET_RX, HostCmd_OPTION_WAITFORRSP,
++ 0, NULL);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++
++ PRINTM(INFO, "Get Rx Antenna Mode:0x%04x\n", Adapter->RxAntennaMode);
++
++ LEAVE();
++
++ return sprintf(buf, "0x%04x", Adapter->RxAntennaMode) + 1;
++}
++
++/**
++ * @brief Get TX Antenna
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param buf A pointer to recieve antenna mode
++ * @return length of buf
++ */
++static int
++GetTxAntenna(wlan_private * priv, char *buf)
++{
++ int ret = 0;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ // clear it, so we will know if the value
++ // returned below is correct or not.
++ Adapter->TxAntennaMode = 0;
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RF_ANTENNA,
++ HostCmd_ACT_GET_TX, HostCmd_OPTION_WAITFORRSP,
++ 0, NULL);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++
++ PRINTM(INFO, "Get Tx Antenna Mode:0x%04x\n", Adapter->TxAntennaMode);
++
++ LEAVE();
++
++ return sprintf(buf, "0x%04x", Adapter->TxAntennaMode) + 1;
++}
++
++/**
++ * @brief Set Radio On/OFF
++ *
++ * @param priv A pointer to wlan_private structure
++ * @option Radio Option
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_radio_ioctl(wlan_private * priv, u8 option)
++{
++ int ret = 0;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (Adapter->RadioOn != option) {
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ PRINTM(MSG, "Cannot turn radio off in connected state.\n");
++ LEAVE();
++ return -EINVAL;
++ }
++
++ PRINTM(INFO, "Switching %s the Radio\n", option ? "On" : "Off");
++ Adapter->RadioOn = option;
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_RADIO_CONTROL,
++ HostCmd_ACT_GEN_SET,
++ HostCmd_OPTION_WAITFORRSP, 0, NULL);
++ }
++
++ LEAVE();
++ return ret;
++}
++
++#ifdef REASSOCIATION
++/**
++ * @brief Set Auto Reassociation On
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++reassociation_on(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ Adapter->Reassoc_on = TRUE;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Set Auto Reassociation Off
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++reassociation_off(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (Adapter->ReassocTimerIsSet == TRUE) {
++ CancelTimer(&Adapter->MrvDrvTimer);
++ Adapter->ReassocTimerIsSet = FALSE;
++ }
++
++ Adapter->Reassoc_on = FALSE;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++#endif /* REASSOCIATION */
++
++/**
++ * @brief Set Region
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param region_code region code
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_region(wlan_private * priv, u16 region_code)
++{
++ int i;
++
++ ENTER();
++
++ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
++ // use the region code to search for the index
++ if (region_code == RegionCodeToIndex[i]) {
++ priv->adapter->RegionCode = region_code;
++ break;
++ }
++ }
++
++ // if it's unidentified region code
++ if (i >= MRVDRV_MAX_REGION_CODE) {
++ PRINTM(INFO, "Region Code not identified\n");
++ LEAVE();
++ return WLAN_STATUS_FAILURE;
++ }
++
++ if (wlan_set_regiontable(priv, priv->adapter->RegionCode, 0)) {
++ LEAVE();
++ return -EINVAL;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Copy Rates
++ *
++ * @param dest A pointer to Dest Buf
++ * @param src A pointer to Src Buf
++ * @param len The len of Src Buf
++ * @return Number of Rates copyed
++ */
++static inline int
++CopyRates(u8 * dest, int pos, u8 * src, int len)
++{
++ int i;
++
++ for (i = 0; i < len && src[i]; i++, pos++) {
++ if (pos >= sizeof(WLAN_802_11_RATES))
++ break;
++ dest[pos] = src[i];
++ }
++
++ return pos;
++}
++
++/**
++ * @brief Get active data rates
++ *
++ * @param Adapter A pointer to wlan_adapter structure
++ * @param rate The buf to return the active rates
++ * @return The number of Rates
++ */
++static int
++get_active_data_rates(wlan_adapter * Adapter, WLAN_802_11_RATES rates)
++{
++ int k = 0;
++
++ ENTER();
++
++ if (Adapter->MediaConnectStatus != WlanMediaStateConnected) {
++ if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
++ //Infra. mode
++ PRINTM(INFO, "Infra\n");
++ k = CopyRates(rates, k, SupportedRates, sizeof(SupportedRates));
++ } else {
++ //ad-hoc mode
++ PRINTM(INFO, "Adhoc G\n");
++ k = CopyRates(rates, k, AdhocRates_G, sizeof(AdhocRates_G));
++ }
++ } else {
++ k = CopyRates(rates, 0, Adapter->CurBssParams.DataRates,
++ Adapter->CurBssParams.NumOfRates);
++ }
++
++ LEAVE();
++
++ return k;
++}
++
++/**
++ * @brief Get/Set Per packet TX Control flags
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to user data
++ * @return WLAN_STATUS_SUCCESS--success, otherwise fail
++ */
++static int
++wlan_txcontrol(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int data[3];
++ int ret;
++
++ ENTER();
++
++ ret = WLAN_STATUS_SUCCESS;
++
++ switch (wrq->u.data.length) {
++ case 0:
++ /*
++ * Get the Global setting for TxCtrl
++ */
++ if (copy_to_user(wrq->u.data.pointer,
++ &Adapter->PktTxCtrl, sizeof(u32))) {
++ PRINTM(INFO, "copy_to_user failed!\n");
++ ret = -EFAULT;
++ } else {
++ wrq->u.data.length = 1;
++ }
++ break;
++
++ case 1:
++ /*
++ * Set the Global setting for TxCtrl
++ */
++ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ ret = -EFAULT;
++ } else {
++ Adapter->PktTxCtrl = data[0];
++ PRINTM(INFO, "PktTxCtrl set: 0x%08x\n", Adapter->PktTxCtrl);
++ }
++ break;
++
++ case 2:
++ /*
++ * Get the per User Priority setting for TxCtrl for the given UP
++ */
++ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * 2)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ ret = -EFAULT;
++
++ } else if (data[1] >= NELEMENTS(Adapter->wmm.userPriPktTxCtrl)) {
++ /* Range check the UP input from user space */
++ PRINTM(INFO, "User priority out of range\n");
++ ret = -EINVAL;
++
++ } else if (Adapter->wmm.userPriPktTxCtrl[data[1]]) {
++ data[2] = Adapter->wmm.userPriPktTxCtrl[data[1]];
++
++ /* User priority setting is valid, return it */
++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 3)) {
++ PRINTM(INFO, "copy_to_user failed!\n");
++ ret = -EFAULT;
++ } else {
++ wrq->u.data.length = 3;
++ }
++
++ } else {
++ /* Return the global setting since the UP set is zero */
++ data[2] = Adapter->PktTxCtrl;
++
++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 3)) {
++ PRINTM(INFO, "copy_to_user failed!\n");
++ ret = -EFAULT;
++ } else {
++ wrq->u.data.length = 3;
++ }
++ }
++ break;
++
++ case 3:
++ /*
++ * Set the per User Priority setting for TxCtrl for the given UP
++ */
++
++ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * 3)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ ret = -EFAULT;
++ } else if (data[1] >= NELEMENTS(Adapter->wmm.userPriPktTxCtrl)) {
++ PRINTM(INFO, "User priority out of range\n");
++ ret = -EINVAL;
++ } else {
++ Adapter->wmm.userPriPktTxCtrl[data[1]] = data[2];
++
++ if (Adapter->wmm.userPriPktTxCtrl[data[1]] == 0) {
++ /* Return the global setting since the UP set is zero */
++ data[2] = Adapter->PktTxCtrl;
++ }
++
++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 3)) {
++ PRINTM(INFO, "copy_to_user failed!\n");
++ ret = -EFAULT;
++ } else {
++ wrq->u.data.length = 3;
++ }
++ }
++ break;
++
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Enable/Disable atim uapsd null package generation
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to user data
++ * @return WLAN_STATUS_SUCCESS--success, otherwise fail
++ */
++static int
++wlan_null_pkg_gen(wlan_private * priv, struct iwreq *wrq)
++{
++ int data;
++ wlan_adapter *Adapter = priv->adapter;
++ int *val;
++
++ ENTER();
++
++ data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
++ PRINTM(INFO, "Enable UAPSD NULL PKG: %s\n",
++ (data == CMD_ENABLED) ? "Enable" : "Disable");
++ switch (data) {
++ case CMD_ENABLED:
++ Adapter->gen_null_pkg = TRUE;
++ break;
++ case CMD_DISABLED:
++ Adapter->gen_null_pkg = FALSE;
++ break;
++ default:
++ break;
++ }
++
++ data = (Adapter->gen_null_pkg == TRUE) ? CMD_ENABLED : CMD_DISABLED;
++ val = (int *) wrq->u.name;
++ *val = data;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get/Set NULL Package generation interval
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to user data
++ * @return WLAN_STATUS_SUCCESS--success, otherwise fail
++ */
++static int
++wlan_null_pkt_interval(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int data;
++ ENTER();
++
++ if ((int) wrq->u.data.length == 0) {
++ data = Adapter->NullPktInterval;
++
++ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
++ PRINTM(MSG, "copy_to_user failed!\n");
++ return -EFAULT;
++ }
++ } else {
++ if ((int) wrq->u.data.length > 1) {
++ PRINTM(MSG, "ioctl too many args!\n");
++ return -EFAULT;
++ }
++ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ Adapter->NullPktInterval = data;
++ }
++
++ wrq->u.data.length = 1;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get/Set Adhoc awake period
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_adhoc_awake_period(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int data;
++ ENTER();
++
++ if ((int) wrq->u.data.length == 0) {
++ data = Adapter->AdhocAwakePeriod;
++ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
++ PRINTM(MSG, "copy_to_user failed!\n");
++ return -EFAULT;
++ }
++ } else {
++ if ((int) wrq->u.data.length > 1) {
++ PRINTM(MSG, "ioctl too many args!\n");
++ return -EFAULT;
++ }
++ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++#define AWAKE_PERIOD_MIN 1
++#define AWAKE_PERIOD_MAX 31
++#define DISABLE_AWAKE_PERIOD 0xff
++ if ((((data & 0xff) >= AWAKE_PERIOD_MIN) &&
++ ((data & 0xff) <= AWAKE_PERIOD_MAX)) ||
++ ((data & 0xff) == DISABLE_AWAKE_PERIOD))
++ Adapter->AdhocAwakePeriod = (u16) data;
++ else {
++ PRINTM(INFO,
++ "Invalid parameter, AdhocAwakePeriod not changed.\n");
++ return -EINVAL;
++
++ }
++ }
++ wrq->u.data.length = 1;
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get/Set bcn missing timeout
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_bcn_miss_timeout(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int data;
++ ENTER();
++
++ if ((int) wrq->u.data.length == 0) {
++ data = Adapter->BCNMissTimeOut;
++ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
++ PRINTM(MSG, "copy_to_user failed!\n");
++ return -EFAULT;
++ }
++ } else {
++ if ((int) wrq->u.data.length > 1) {
++ PRINTM(MSG, "ioctl too many args!\n");
++ return -EFAULT;
++ }
++ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++ if (((data >= 0) && (data <= 50)) || (data == 0xffff))
++ Adapter->BCNMissTimeOut = (u16) data;
++ else {
++ PRINTM(INFO,
++ "Invalid parameter, BCN Missing timeout not changed.\n");
++ return -EINVAL;
++
++ }
++ }
++
++ wrq->u.data.length = 1;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get/Set adhoc g proctection
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_adhoc_g_protection(wlan_private * priv, struct iwreq *wrq)
++{
++ int data;
++ int *val;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++#define ADHOC_G_PROTECTION_ON 1
++#define ADHOC_G_PROTECTION_OFF 0
++ data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
++
++ switch (data) {
++ case CMD_DISABLED:
++ Adapter->CurrentPacketFilter &=
++ ~HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
++ break;
++ case CMD_ENABLED:
++ Adapter->CurrentPacketFilter |= HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
++ break;
++
++ case CMD_GET:
++ if (Adapter->
++ CurrentPacketFilter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)
++ data = ADHOC_G_PROTECTION_ON;
++ else
++ data = ADHOC_G_PROTECTION_OFF;
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ val = (int *) wrq->u.name;
++ *val = data;
++
++ LEAVE();
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++#define USE_RTS_CTS 1
++#define USE_CTS_TO_SELF 0
++/**
++ * @brief GetSet RTS/CTS or CTS to self.
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_rts_cts_ctrl(wlan_private * priv, struct iwreq *wrq)
++{
++ int data;
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = 0;
++ ENTER();
++
++ if ((int) wrq->u.data.length == 0) {
++ if (Adapter->CurrentPacketFilter & HostCmd_ACT_MAC_RTS_CTS_ENABLE)
++ data = USE_RTS_CTS;
++ else
++ data = USE_CTS_TO_SELF;
++ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
++ PRINTM(MSG, "copy_to_user failed!\n");
++ return -EFAULT;
++ }
++ } else {
++ if ((int) wrq->u.data.length > 1) {
++ PRINTM(MSG, "ioctl too many args!\n");
++ return -EFAULT;
++ }
++ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++ if (data == USE_RTS_CTS) {
++ Adapter->CurrentPacketFilter |= HostCmd_ACT_MAC_RTS_CTS_ENABLE;
++ } else {
++ Adapter->CurrentPacketFilter &= ~HostCmd_ACT_MAC_RTS_CTS_ENABLE;
++ }
++ PRINTM(INFO, "Adapter->CurrentPacketFilter=0x%x\n",
++ Adapter->CurrentPacketFilter);
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_MAC_CONTROL,
++ 0, HostCmd_OPTION_WAITFORRSP,
++ 0, &Adapter->CurrentPacketFilter);
++ }
++ wrq->u.data.length = 1;
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get/Set sdio mode
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_sdio_mode(wlan_private * priv, struct iwreq *wrq)
++{
++ int data;
++ int bus_width;
++ wlan_adapter *Adapter = priv->adapter;
++ ENTER();
++
++ if ((int) wrq->u.data.length == 0) {
++ data = 4;
++ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
++ PRINTM(MSG, "copy_to_user failed!\n");
++ return -EFAULT;
++ }
++ } else {
++ if ((int) wrq->u.data.length > 1) {
++ PRINTM(MSG, "ioctl too many args!\n");
++ return -EFAULT;
++ }
++ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++ if ((data != 1) && (data != 4))
++ return -EFAULT;
++ bus_width = 4;
++ if (bus_width != data)
++ Adapter->sdiomode = (u8) data;
++ }
++ wrq->u.data.length = 1;
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get/Set LDO config
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to wrq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_ldo_config(wlan_private * priv, struct iwreq *wrq)
++{
++ HostCmd_DS_802_11_LDO_CONFIG ldocfg;
++ int data = 0;
++ u16 action;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (wrq->u.data.length == 0) {
++ action = HostCmd_ACT_GEN_GET;
++ } else if (wrq->u.data.length > 1) {
++ PRINTM(MSG, "ioctl too many args!\n");
++ ret = -EFAULT;
++ goto ldoexit;
++ } else {
++ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ ret = -EFAULT;
++ goto ldoexit;
++ }
++ if (data != LDO_INTERNAL && data != LDO_EXTERNAL) {
++ PRINTM(MSG, "Invalid parameter, LDO config not changed.\n");
++ ret = -EFAULT;
++ goto ldoexit;
++ }
++ action = HostCmd_ACT_GEN_SET;
++ }
++ ldocfg.Action = action;
++ ldocfg.PMSource = (u16) data;
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_LDO_CONFIG,
++ action, HostCmd_OPTION_WAITFORRSP,
++ 0, (void *) &ldocfg);
++
++ if (!ret && action == HostCmd_ACT_GEN_GET) {
++ data = (int) ldocfg.PMSource;
++ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ ret = -EFAULT;
++ goto ldoexit;
++ }
++ wrq->u.data.length = 1;
++ }
++
++ ldoexit:
++ LEAVE();
++ return ret;
++}
++
++#ifdef DEBUG_LEVEL1
++/**
++ * @brief Get/Set the bit mask of driver debug message control
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to wrq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_drv_dbg(wlan_private * priv, struct iwreq *wrq)
++{
++ int data[4];
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (wrq->u.data.length == 0) {
++ data[0] = drvdbg;
++ data[1] = ifdbg;
++ /* Return the current driver debug bit masks */
++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ ret = -EFAULT;
++ goto drvdbgexit;
++ }
++ wrq->u.data.length = 2;
++ } else if (wrq->u.data.length < 3) {
++ /* Get the driver debug bit masks */
++ if (copy_from_user
++ (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ ret = -EFAULT;
++ goto drvdbgexit;
++ }
++ drvdbg = data[0];
++ if (wrq->u.data.length == 2)
++ ifdbg = data[1];
++ } else {
++ PRINTM(INFO, "Invalid parameter number\n");
++ goto drvdbgexit;
++ }
++
++ printk(KERN_ALERT "drvdbg = 0x%x\n", drvdbg);
++#ifdef DEBUG_LEVEL2
++ printk(KERN_ALERT "INFO (%08x) %s\n", DBG_INFO,
++ (drvdbg & DBG_INFO) ? "X" : "");
++ printk(KERN_ALERT "WARN (%08x) %s\n", DBG_WARN,
++ (drvdbg & DBG_WARN) ? "X" : "");
++ printk(KERN_ALERT "ENTRY (%08x) %s\n", DBG_ENTRY,
++ (drvdbg & DBG_ENTRY) ? "X" : "");
++#endif
++ printk(KERN_ALERT "FW_D (%08x) %s\n", DBG_FW_D,
++ (drvdbg & DBG_FW_D) ? "X" : "");
++ printk(KERN_ALERT "CMD_D (%08x) %s\n", DBG_CMD_D,
++ (drvdbg & DBG_CMD_D) ? "X" : "");
++ printk(KERN_ALERT "DAT_D (%08x) %s\n", DBG_DAT_D,
++ (drvdbg & DBG_DAT_D) ? "X" : "");
++
++ printk(KERN_ALERT "INTR (%08x) %s\n", DBG_INTR,
++ (drvdbg & DBG_INTR) ? "X" : "");
++ printk(KERN_ALERT "EVENT (%08x) %s\n", DBG_EVENT,
++ (drvdbg & DBG_EVENT) ? "X" : "");
++ printk(KERN_ALERT "CMND (%08x) %s\n", DBG_CMND,
++ (drvdbg & DBG_CMND) ? "X" : "");
++ printk(KERN_ALERT "DATA (%08x) %s\n", DBG_DATA,
++ (drvdbg & DBG_DATA) ? "X" : "");
++ printk(KERN_ALERT "ERROR (%08x) %s\n", DBG_ERROR,
++ (drvdbg & DBG_ERROR) ? "X" : "");
++ printk(KERN_ALERT "FATAL (%08x) %s\n", DBG_FATAL,
++ (drvdbg & DBG_FATAL) ? "X" : "");
++ printk(KERN_ALERT "MSG (%08x) %s\n", DBG_MSG,
++ (drvdbg & DBG_MSG) ? "X" : "");
++ printk(KERN_ALERT "ifdbg = 0x%x\n", ifdbg);
++ printk(KERN_ALERT "IF_D (%08x) %s\n", DBG_IF_D,
++ (ifdbg & DBG_IF_D) ? "X" : "");
++
++ drvdbgexit:
++ LEAVE();
++ return ret;
++}
++#endif
++
++/**
++ * @brief Commit handler: called after a bunch of SET operations
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_config_commit(struct net_device *dev,
++ struct iw_request_info *info, char *cwrq, char *extra)
++{
++ ENTER();
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get protocol name
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_name(struct net_device *dev, struct iw_request_info *info,
++ char *cwrq, char *extra)
++{
++ const char *cp;
++ char comm[6] = { "COMM-" };
++ char mrvl[6] = { "MRVL-" };
++ int cnt;
++
++ ENTER();
++
++ strcpy(cwrq, mrvl);
++
++ cp = strstr(driver_version, comm);
++ if (cp == driver_version) //skip leading "COMM-"
++ cp = driver_version + strlen(comm);
++ else
++ cp = driver_version;
++
++ cnt = strlen(mrvl);
++ cwrq += cnt;
++ while (cnt < 16 && (*cp != '-')) {
++ *cwrq++ = toupper(*cp++);
++ cnt++;
++ }
++ *cwrq = '\0';
++
++ LEAVE();
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get frequency
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param fwrq A pointer to iw_freq structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
++ struct iw_freq *fwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ CHANNEL_FREQ_POWER *cfp;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ cfp = find_cfp_by_band_and_channel(Adapter, 0,
++ (u16) Adapter->CurBssParams.
++ BSSDescriptor.Channel);
++
++ if (!cfp) {
++ if (Adapter->CurBssParams.BSSDescriptor.Channel) {
++ PRINTM(INFO, "Invalid channel=%d\n",
++ Adapter->CurBssParams.BSSDescriptor.Channel);
++ }
++ return -EINVAL;
++ }
++
++ fwrq->m = (long) cfp->Freq * 100000;
++ fwrq->e = 1;
++
++ PRINTM(INFO, "freq=%u\n", fwrq->m);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get current BSSID
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param awrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
++ struct sockaddr *awrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ memcpy(awrq->sa_data,
++ Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
++ } else {
++ memset(awrq->sa_data, 0, ETH_ALEN);
++ }
++ awrq->sa_family = ARPHRD_ETHER;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Set Adapter Node Name
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ /*
++ * Check the size of the string
++ */
++
++ if (dwrq->length > 16) {
++ return -E2BIG;
++ }
++
++ memset(Adapter->nodeName, 0, sizeof(Adapter->nodeName));
++ memcpy(Adapter->nodeName, extra, dwrq->length);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get Adapter Node Name
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ /*
++ * Get the Nick Name saved
++ */
++
++ strncpy(extra, Adapter->nodeName, 16);
++
++ extra[16] = '\0';
++
++ /*
++ * If none, we may want to get the one that was set
++ */
++
++ /*
++ * Push it out !
++ */
++#if WIRELESS_EXT > 20
++ dwrq->length = strlen(extra);
++#else
++ dwrq->length = strlen(extra) + 1;
++#endif
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Set RTS threshold
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ int rthr = vwrq->value;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ if (vwrq->disabled) {
++ Adapter->RTSThsd = rthr = MRVDRV_RTS_MAX_VALUE;
++ } else {
++ if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
++ return -EINVAL;
++ Adapter->RTSThsd = rthr;
++ }
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SNMP_MIB,
++ HostCmd_ACT_SET, HostCmd_OPTION_WAITFORRSP,
++ OID_802_11_RTS_THRESHOLD, &rthr);
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get RTS threshold
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ Adapter->RTSThsd = 0;
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SNMP_MIB,
++ HostCmd_ACT_GET, HostCmd_OPTION_WAITFORRSP,
++ OID_802_11_RTS_THRESHOLD, NULL);
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++
++ vwrq->value = Adapter->RTSThsd;
++ vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
++ || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
++ vwrq->fixed = 1;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Set Fragment threshold
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ int fthr = vwrq->value;
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ if (vwrq->disabled) {
++ Adapter->FragThsd = fthr = MRVDRV_FRAG_MAX_VALUE;
++ } else {
++ if (fthr < MRVDRV_FRAG_MIN_VALUE || fthr > MRVDRV_FRAG_MAX_VALUE)
++ return -EINVAL;
++ Adapter->FragThsd = fthr;
++ }
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SNMP_MIB,
++ HostCmd_ACT_SET, HostCmd_OPTION_WAITFORRSP,
++ OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get Fragment threshold
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ Adapter->FragThsd = 0;
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GET,
++ HostCmd_OPTION_WAITFORRSP,
++ OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++
++ vwrq->value = Adapter->FragThsd;
++ vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
++ || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
++ vwrq->fixed = 1;
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get Wlan Mode
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_mode(struct net_device *dev,
++ struct iw_request_info *info, u32 * uwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *adapter = priv->adapter;
++
++ ENTER();
++
++ switch (adapter->InfrastructureMode) {
++ case Wlan802_11IBSS:
++ *uwrq = IW_MODE_ADHOC;
++ break;
++
++ case Wlan802_11Infrastructure:
++ *uwrq = IW_MODE_INFRA;
++ break;
++
++ default:
++ case Wlan802_11AutoUnknown:
++ *uwrq = IW_MODE_AUTO;
++ break;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get Encryption key
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_encode(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq, u8 * extra)
++{
++
++ wlan_private *priv = dev->priv;
++ wlan_adapter *adapter = priv->adapter;
++ int index = (dwrq->flags & IW_ENCODE_INDEX);
++
++ ENTER();
++
++ PRINTM(INFO, "flags=0x%x index=%d length=%d CurrentWepKeyIndex=%d\n",
++ dwrq->flags, index, dwrq->length, adapter->CurrentWepKeyIndex);
++ if (index < 0 || index > 4) {
++ PRINTM(INFO, "Key index #%d out of range.\n", index);
++ LEAVE();
++ return -EINVAL;
++ }
++ if (adapter->CurrentWepKeyIndex >= MRVL_NUM_WEP_KEY)
++ adapter->CurrentWepKeyIndex = 0;
++ dwrq->flags = 0;
++
++ /*
++ * Check encryption mode
++ */
++
++ switch (adapter->SecInfo.AuthenticationMode) {
++ case Wlan802_11AuthModeOpen:
++ dwrq->flags = IW_ENCODE_OPEN;
++ break;
++
++ case Wlan802_11AuthModeShared:
++ case Wlan802_11AuthModeNetworkEAP:
++ dwrq->flags = IW_ENCODE_RESTRICTED;
++ break;
++ default:
++ dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
++ break;
++ }
++
++ if ((adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled)
++ || (adapter->SecInfo.WEPStatus == Wlan802_11WEPKeyAbsent)
++ || adapter->SecInfo.WPAEnabled || adapter->SecInfo.WPA2Enabled) {
++ dwrq->flags &= ~IW_ENCODE_DISABLED;
++ } else {
++ dwrq->flags |= IW_ENCODE_DISABLED;
++ }
++
++ memset(extra, 0, 16);
++
++ if (!index) {
++ /* Handle current key request */
++ if ((adapter->WepKey[adapter->CurrentWepKeyIndex].KeyLength) &&
++ (adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled)) {
++ index = adapter->WepKey[adapter->CurrentWepKeyIndex].KeyIndex;
++ memcpy(extra, adapter->WepKey[index].KeyMaterial,
++ adapter->WepKey[index].KeyLength);
++ dwrq->length = adapter->WepKey[index].KeyLength;
++ /* return current key */
++ dwrq->flags |= (index + 1);
++ /* return WEP enabled */
++ dwrq->flags &= ~IW_ENCODE_DISABLED;
++ } else if ((adapter->SecInfo.WPAEnabled)
++ || (adapter->SecInfo.WPA2Enabled)
++ ) {
++ /* return WPA enabled */
++ dwrq->flags &= ~IW_ENCODE_DISABLED;
++ } else {
++ dwrq->flags |= IW_ENCODE_DISABLED;
++ }
++ } else {
++ /* Handle specific key requests */
++ index--;
++ if (adapter->WepKey[index].KeyLength) {
++ memcpy(extra, adapter->WepKey[index].KeyMaterial,
++ adapter->WepKey[index].KeyLength);
++ dwrq->length = adapter->WepKey[index].KeyLength;
++ /* return current key */
++ dwrq->flags |= (index + 1);
++ /* return WEP enabled */
++ dwrq->flags &= ~IW_ENCODE_DISABLED;
++ } else if ((adapter->SecInfo.WPAEnabled)
++ || (adapter->SecInfo.WPA2Enabled)
++ ) {
++ /* return WPA enabled */
++ dwrq->flags &= ~IW_ENCODE_DISABLED;
++ } else {
++ dwrq->flags |= IW_ENCODE_DISABLED;
++ }
++ }
++
++ dwrq->flags |= IW_ENCODE_NOKEY;
++
++ PRINTM(INFO, "Key:%02x:%02x:%02x:%02x:%02x:%02x KeyLen=%d\n",
++ extra[0], extra[1], extra[2],
++ extra[3], extra[4], extra[5], dwrq->length);
++
++ PRINTM(INFO, "Return flags=0x%x\n", dwrq->flags);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get TX Power
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_txpow(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_RF_TX_POWER,
++ HostCmd_ACT_GEN_GET,
++ HostCmd_OPTION_WAITFORRSP, 0, NULL);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++
++ PRINTM(INFO, "TXPOWER GET %d dbm.\n", Adapter->TxPowerLevel);
++ vwrq->value = Adapter->TxPowerLevel;
++ vwrq->fixed = 1;
++ if (Adapter->RadioOn) {
++ vwrq->disabled = 0;
++ vwrq->flags = IW_TXPOW_DBM;
++ } else {
++ vwrq->disabled = 1;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Set TX Retry Count
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_private *priv = dev->priv;
++ wlan_adapter *adapter = priv->adapter;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ if (vwrq->flags == IW_RETRY_LIMIT) {
++ /* The MAC has a 4-bit Total_Tx_Count register
++ Total_Tx_Count = 1 + Tx_Retry_Count */
++#define TX_RETRY_MIN 0
++#define TX_RETRY_MAX 14
++ if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
++ return -EINVAL;
++
++ /* Set Tx retry count */
++ adapter->TxRetryCount = vwrq->value + 1;
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SNMP_MIB,
++ HostCmd_ACT_SET,
++ HostCmd_OPTION_WAITFORRSP,
++ OID_802_11_TX_RETRYCOUNT, NULL);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ } else {
++ return -EOPNOTSUPP;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get TX Retry Count
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ Adapter->TxRetryCount = 0;
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GET,
++ HostCmd_OPTION_WAITFORRSP,
++ OID_802_11_TX_RETRYCOUNT, NULL);
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ vwrq->disabled = 0;
++ if (!vwrq->flags) {
++ vwrq->flags = IW_RETRY_LIMIT;
++ /* Get Tx retry count */
++ vwrq->value = Adapter->TxRetryCount - 1;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Sort Channels
++ *
++ * @param freq A pointer to iw_freq structure
++ * @param num number of Channels
++ * @return NA
++ */
++static inline void
++sort_channels(struct iw_freq *freq, int num)
++{
++ int i, j;
++ struct iw_freq temp;
++
++ for (i = 0; i < num; i++)
++ for (j = i + 1; j < num; j++)
++ if (freq[i].i > freq[j].i) {
++ temp.i = freq[i].i;
++ temp.m = freq[i].m;
++
++ freq[i].i = freq[j].i;
++ freq[i].m = freq[j].m;
++
++ freq[j].i = temp.i;
++ freq[j].m = temp.m;
++ }
++}
++
++/* data rate listing
++ MULTI_BANDS:
++ abg a b b/g
++ Infra G(12) A(8) B(4) G(12)
++ Adhoc A+B(12) A(8) B(4) B(4)
++
++ non-MULTI_BANDS:
++ b b/g
++ Infra B(4) G(12)
++ Adhoc B(4) B(4)
++ */
++/**
++ * @brief Get Range Info
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_range(struct net_device *dev, struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ int i, j;
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ struct iw_range *range = (struct iw_range *) extra;
++ CHANNEL_FREQ_POWER *cfp;
++ WLAN_802_11_RATES rates;
++
++ ENTER();
++
++ dwrq->length = sizeof(struct iw_range);
++ memset(range, 0, sizeof(struct iw_range));
++
++ range->min_nwid = 0;
++ range->max_nwid = 0;
++
++ memset(rates, 0, sizeof(rates));
++ range->num_bitrates = get_active_data_rates(Adapter, rates);
++ if (range->num_bitrates > sizeof(rates))
++ range->num_bitrates = sizeof(rates);
++
++ for (i = 0; i < MIN(range->num_bitrates, IW_MAX_BITRATES) && rates[i];
++ i++) {
++ range->bitrate[i] = (rates[i] & 0x7f) * 500000;
++ }
++ range->num_bitrates = i;
++ PRINTM(INFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
++ range->num_bitrates);
++
++ range->num_frequency = 0;
++ if (wlan_get_state_11d(priv) == ENABLE_11D &&
++ Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ u8 chan_no;
++ u8 band;
++
++ parsed_region_chan_11d_t *parsed_region_chan =
++ &Adapter->parsed_region_chan;
++
++ band = parsed_region_chan->band;
++ PRINTM(INFO, "band=%d NoOfChan=%d\n", band,
++ parsed_region_chan->NoOfChan);
++
++ for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
++ && (i < parsed_region_chan->NoOfChan); i++) {
++ chan_no = parsed_region_chan->chanPwr[i].chan;
++ PRINTM(INFO, "chan_no=%d\n", chan_no);
++ range->freq[range->num_frequency].i = (long) chan_no;
++ range->freq[range->num_frequency].m =
++ (long) chan_2_freq(chan_no, band) * 100000;
++ range->freq[range->num_frequency].e = 1;
++ range->num_frequency++;
++ }
++ } else {
++ for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
++ && (j < sizeof(Adapter->region_channel)
++ / sizeof(Adapter->region_channel[0])); j++) {
++ cfp = Adapter->region_channel[j].CFP;
++ for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
++ && Adapter->region_channel[j].Valid
++ && cfp && (i < Adapter->region_channel[j].NrCFP); i++) {
++ range->freq[range->num_frequency].i = (long) cfp->Channel;
++ range->freq[range->num_frequency].m =
++ (long) cfp->Freq * 100000;
++ range->freq[range->num_frequency].e = 1;
++ cfp++;
++ range->num_frequency++;
++ }
++ }
++ }
++
++ PRINTM(INFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
++ IW_MAX_FREQUENCIES, range->num_frequency);
++
++ range->num_channels = range->num_frequency;
++
++ sort_channels(&range->freq[0], range->num_frequency);
++
++ /*
++ * Set an indication of the max TCP throughput in bit/s that we can
++ * expect using this interface
++ */
++ if (i > 2)
++ range->throughput = 5000 * 1000;
++ else
++ range->throughput = 1500 * 1000;
++ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
++ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
++
++ range->min_rts = MRVDRV_RTS_MIN_VALUE;
++ range->max_rts = MRVDRV_RTS_MAX_VALUE;
++ range->min_frag = MRVDRV_FRAG_MIN_VALUE;
++ range->max_frag = MRVDRV_FRAG_MAX_VALUE;
++
++ range->encoding_size[0] = 5;
++ range->encoding_size[1] = 13;
++ range->num_encoding_sizes = 2;
++ range->max_encoding_tokens = 4;
++
++#define IW_POWER_PERIOD_MIN 1000000 /* 1 sec */
++#define IW_POWER_PERIOD_MAX 120000000 /* 2 min */
++#define IW_POWER_TIMEOUT_MIN 1000 /* 1 ms */
++#define IW_POWER_TIMEOUT_MAX 1000000 /* 1 sec */
++
++ /* Power Management duration & timeout */
++ range->min_pmp = IW_POWER_PERIOD_MIN;
++ range->max_pmp = IW_POWER_PERIOD_MAX;
++ range->min_pmt = IW_POWER_TIMEOUT_MIN;
++ range->max_pmt = IW_POWER_TIMEOUT_MAX;
++ range->pmp_flags = IW_POWER_PERIOD;
++ range->pmt_flags = IW_POWER_TIMEOUT;
++ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
++
++ /*
++ * Minimum version we recommend
++ */
++ range->we_version_source = 15;
++
++ /*
++ * Version we are compiled with
++ */
++ range->we_version_compiled = WIRELESS_EXT;
++
++ range->retry_capa = IW_RETRY_LIMIT;
++ range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
++
++ range->min_retry = TX_RETRY_MIN;
++ range->max_retry = TX_RETRY_MAX;
++
++ /*
++ * Set the qual, level and noise range values
++ */
++ /*
++ * need to put the right values here
++ */
++#define IW_MAX_QUAL_PERCENT 100
++#define IW_AVG_QUAL_PERCENT 70
++ range->max_qual.qual = IW_MAX_QUAL_PERCENT;
++ range->max_qual.level = 0;
++ range->max_qual.noise = 0;
++
++ range->avg_qual.qual = IW_AVG_QUAL_PERCENT;
++ range->avg_qual.level = 0;
++ range->avg_qual.noise = 0;
++
++ range->sensitivity = 0;
++ /*
++ * Setup the supported power level ranges
++ */
++ memset(range->txpower, 0, sizeof(range->txpower));
++ range->txpower[0] = Adapter->MinTxPowerLevel;
++ range->txpower[1] = Adapter->MaxTxPowerLevel;
++ range->num_txpower = 2;
++ range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Set power management
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_set_power(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ /* PS is currently supported only in Infrastructure Mode
++ * Remove this check if it is to be supported in IBSS mode also
++ */
++
++ if (vwrq->disabled) {
++ Adapter->PSMode = Wlan802_11PowerModeCAM;
++ if (Adapter->PSState != PS_STATE_FULL_POWER) {
++ PSWakeup(priv, HostCmd_OPTION_WAITFORRSP);
++ }
++
++ return 0;
++ }
++
++ if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
++ PRINTM(INFO, "Setting power timeout command is not supported\n");
++ return -EINVAL;
++ } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
++ PRINTM(INFO, "Setting power period command is not supported\n");
++ return -EINVAL;
++ }
++
++ if (Adapter->PSMode != Wlan802_11PowerModeCAM) {
++ return WLAN_STATUS_SUCCESS;
++ }
++
++ Adapter->PSMode = Wlan802_11PowerModeMAX_PSP;
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ PSSleep(priv, HostCmd_OPTION_WAITFORRSP);
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get power management
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_power(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ int mode;
++
++ ENTER();
++
++ mode = Adapter->PSMode;
++
++ if ((vwrq->disabled = (mode == Wlan802_11PowerModeCAM))
++ || Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++ }
++
++ vwrq->value = 0;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Set sensitivity threshold
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_sens(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ ENTER();
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get sensitivity threshold
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_FAILURE
++ */
++static int
++wlan_get_sens(struct net_device *dev,
++ struct iw_request_info *info, struct iw_param *vwrq,
++ char *extra)
++{
++ ENTER();
++ LEAVE();
++ return WLAN_STATUS_FAILURE;
++}
++
++/**
++ * @brief Append/Reset IE buffer.
++ *
++ * Pass an opaque block of data, expected to be IEEE IEs, to the driver
++ * for eventual passthrough to the firmware in an associate/join
++ * (and potentially start) command. This function is the main body
++ * for both wlan_set_gen_ie_ioctl and wlan_set_gen_ie
++ *
++ * Data is appended to an existing buffer and then wrapped in a passthrough
++ * TLV in the command API to the firmware. The firmware treats the data
++ * as a transparent passthrough to the transmitted management frame.
++ *
++ * @param Adapter A pointer to wlan_private structure
++ * @param ie_data_ptr A pointer to iwreq structure
++ * @param ie_len Length of the IE or IE block passed in ie_data_ptr
++ *
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_gen_ie_helper(wlan_private * priv, u8 * ie_data_ptr, u16 ie_len)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_adapter *Adapter = priv->adapter;
++ IEEEtypes_VendorHeader_t *pVendorIe;
++ const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
++ const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
++ /* If the passed length is zero, reset the buffer */
++ if (ie_len == 0) {
++ Adapter->genIeBufferLen = 0;
++
++ } else if (ie_data_ptr == NULL) {
++ /* NULL check */
++ ret = -EINVAL;
++ } else {
++
++ pVendorIe = (IEEEtypes_VendorHeader_t *) ie_data_ptr;
++
++ /* Test to see if it is a WPA IE, if not, then it is a gen IE */
++ if ((pVendorIe->ElementId == RSN_IE)
++ || ((pVendorIe->ElementId == WPA_IE)
++ && (pVendorIe->OuiType == wpa_oui[3])
++ && (memcmp(pVendorIe->Oui, wpa_oui, sizeof(pVendorIe->Oui)) ==
++ 0))) {
++
++ /* IE is a WPA/WPA2 IE so call set_wpa function */
++ ret = wlan_set_wpa_ie_helper(priv, ie_data_ptr, ie_len);
++ } else if ((pVendorIe->ElementId == WPS_IE)
++ && (memcmp(pVendorIe->Oui, wps_oui, sizeof(pVendorIe->Oui))
++ == 0)
++ && (pVendorIe->OuiType == wps_oui[3])) {
++ /*
++ * Discard first two byte (Element ID and Length)
++ * because they are not needed in the case of setting WPS_IE
++ */
++ if (pVendorIe->Len > 4) {
++ memcpy((u8 *) & Adapter->wps.wpsIe, ie_data_ptr, ie_len);
++ HEXDUMP("wpsIe",
++ (u8 *) & Adapter->wps.wpsIe,
++ Adapter->wps.wpsIe.VendHdr.Len + 2);
++
++ } else {
++ /* Only wps oui exist, reset driver wps buffer */
++ memset((u8 *) & Adapter->wps.wpsIe,
++ 0x00, sizeof(Adapter->wps.wpsIe));
++ PRINTM(INFO, "wpsIe cleared\n");
++ }
++ } else {
++ /*
++ * Verify that the passed length is not larger than the available
++ * space remaining in the buffer
++ */
++ if (ie_len < (sizeof(Adapter->genIeBuffer)
++ - Adapter->genIeBufferLen)) {
++
++ /* Append the passed data to the end of the genIeBuffer */
++ if (copy_from_user((Adapter->genIeBuffer
++ + Adapter->genIeBufferLen),
++ ie_data_ptr, ie_len)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ ret = -EFAULT;
++
++ } else {
++ /* Increment the stored buffer length by the size passed */
++ Adapter->genIeBufferLen += ie_len;
++ }
++
++ } else {
++ /* Passed data does not fit in the remaining buffer space */
++ ret = WLAN_STATUS_FAILURE;
++ }
++ }
++ }
++
++ /* Return WLAN_STATUS_SUCCESS, or < 0 for error case */
++ return ret;
++}
++
++/**
++ * @brief Get IE buffer from driver
++ *
++ * Used to pass an opaque block of data, expected to be IEEE IEs,
++ * back to the application. Currently the data block passed
++ * back to the application is the saved association response retrieved
++ * from the firmware.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param ie_data_ptr A pointer to the IE or IE block
++ * @param ie_len_ptr In/Out parameter pointer for the buffer length passed
++ * in ie_data_ptr and the resulting data length copied
++ *
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_gen_ie_helper(wlan_private * priv,
++ u8 * ie_data_ptr, u16 * ie_len_ptr)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ IEEEtypes_AssocRsp_t *pAssocRsp;
++ int copySize;
++
++ pAssocRsp = (IEEEtypes_AssocRsp_t *) Adapter->assocRspBuffer;
++
++ /*
++ * Set the amount to copy back to the application as the minimum of the
++ * available IE data or the buffer provided by the application
++ */
++ copySize = (Adapter->assocRspSize - sizeof(pAssocRsp->Capability) -
++ -sizeof(pAssocRsp->StatusCode) - sizeof(pAssocRsp->AId));
++ copySize = MIN(copySize, *ie_len_ptr);
++
++ /* Copy the IEEE TLVs in the assoc response back to the application */
++ if (copy_to_user(ie_data_ptr, (u8 *) pAssocRsp->IEBuffer, copySize)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++
++ /* Returned copy length */
++ *ie_len_ptr = copySize;
++
++ /* No error on return */
++ return WLAN_STATUS_SUCCESS;
++}
++
++#if (WIRELESS_EXT >= 18)
++/**
++ * @brief Set IE
++ *
++ * Calls main function set_gen_ie_fuct that adds the inputted IE
++ * to the genie buffer
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param dwrq A pointer to iw_point structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_gen_ie(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ return wlan_set_gen_ie_helper(dev->priv, dwrq->pointer, dwrq->length);
++}
++
++/**
++ * @brief Get IE
++ *
++ * Calls main function get_gen_ie_fuct that retrieves expected IEEE IEs
++ * and places then in the iw_point structure
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param dwrq A pointer to iw_point structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_gen_ie(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ return wlan_get_gen_ie_helper(dev->priv, dwrq->pointer, &dwrq->length);
++}
++
++/**
++ * @brief Set authentication mode
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_setauthalg(wlan_private * priv, int alg)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ PRINTM(INFO, "auth alg is %#x\n", alg);
++
++ switch (alg) {
++ case IW_AUTH_ALG_SHARED_KEY:
++ Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeShared;
++ break;
++ case IW_AUTH_ALG_LEAP:
++ //clear WPA IE
++ wlan_set_wpa_ie_helper(priv, NULL, 0);
++ Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeNetworkEAP;
++ break;
++ case IW_AUTH_ALG_OPEN_SYSTEM:
++ default:
++ Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
++ break;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief set authentication mode params
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_auth(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++ switch (vwrq->flags & IW_AUTH_INDEX) {
++ case IW_AUTH_CIPHER_PAIRWISE:
++ case IW_AUTH_CIPHER_GROUP:
++ if (vwrq->value & IW_AUTH_CIPHER_NONE)
++ priv->adapter->SecInfo.EncryptionMode = CIPHER_NONE;
++ else if (vwrq->value & IW_AUTH_CIPHER_WEP40)
++ priv->adapter->SecInfo.EncryptionMode = CIPHER_WEP40;
++ else if (vwrq->value & IW_AUTH_CIPHER_TKIP)
++ priv->adapter->SecInfo.EncryptionMode = CIPHER_TKIP;
++ else if (vwrq->value & IW_AUTH_CIPHER_CCMP)
++ priv->adapter->SecInfo.EncryptionMode = CIPHER_CCMP;
++ else if (vwrq->value & IW_AUTH_CIPHER_WEP104)
++ priv->adapter->SecInfo.EncryptionMode = CIPHER_WEP104;
++ break;
++ case IW_AUTH_80211_AUTH_ALG:
++ wlan_setauthalg(priv, vwrq->value);
++ break;
++ case IW_AUTH_WPA_ENABLED:
++ if (vwrq->value == FALSE)
++ wlan_set_wpa_ie_helper(priv, NULL, 0);
++ break;
++ case IW_AUTH_WPA_VERSION:
++ case IW_AUTH_KEY_MGMT:
++ case IW_AUTH_TKIP_COUNTERMEASURES:
++ case IW_AUTH_DROP_UNENCRYPTED:
++ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
++ case IW_AUTH_ROAMING_CONTROL:
++ case IW_AUTH_PRIVACY_INVOKED:
++ default:
++ break;
++ }
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief get authentication mode params
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_auth(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++ ENTER();
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++ switch (vwrq->flags & IW_AUTH_INDEX) {
++ case IW_AUTH_CIPHER_PAIRWISE:
++ case IW_AUTH_CIPHER_GROUP:
++ if (priv->adapter->SecInfo.EncryptionMode == CIPHER_NONE)
++ vwrq->value = IW_AUTH_CIPHER_NONE;
++ else if (priv->adapter->SecInfo.EncryptionMode == CIPHER_WEP40)
++ vwrq->value = IW_AUTH_CIPHER_WEP40;
++ else if (priv->adapter->SecInfo.EncryptionMode == CIPHER_TKIP)
++ vwrq->value = IW_AUTH_CIPHER_TKIP;
++ else if (priv->adapter->SecInfo.EncryptionMode == CIPHER_CCMP)
++ vwrq->value = IW_AUTH_CIPHER_CCMP;
++ else if (priv->adapter->SecInfo.EncryptionMode == CIPHER_WEP104)
++ vwrq->value = IW_AUTH_CIPHER_WEP104;
++ break;
++ case IW_AUTH_80211_AUTH_ALG:
++ if (Adapter->SecInfo.AuthenticationMode == Wlan802_11AuthModeShared)
++ vwrq->value = IW_AUTH_ALG_SHARED_KEY;
++ else if (Adapter->SecInfo.AuthenticationMode ==
++ Wlan802_11AuthModeNetworkEAP)
++ vwrq->value = IW_AUTH_ALG_LEAP;
++ else
++ vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
++ break;
++ case IW_AUTH_WPA_ENABLED:
++ if (Adapter->Wpa_ie_len > 0)
++ vwrq->value = TRUE;
++ else
++ vwrq->value = FALSE;
++ break;
++ case IW_AUTH_WPA_VERSION:
++ case IW_AUTH_KEY_MGMT:
++ case IW_AUTH_TKIP_COUNTERMEASURES:
++ case IW_AUTH_DROP_UNENCRYPTED:
++ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
++ case IW_AUTH_ROAMING_CONTROL:
++ case IW_AUTH_PRIVACY_INVOKED:
++ default:
++ ret = -EOPNOTSUPP;
++ break;
++ }
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Request MLME operation
++ *
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param dwrq A pointer to iw_point structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_mlme(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ struct iw_mlme *mlme = (struct iw_mlme *) extra;
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++ if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) {
++ if (Adapter->InfrastructureMode == Wlan802_11Infrastructure &&
++ Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ SendDeauthentication(priv);
++ } else if (Adapter->InfrastructureMode == Wlan802_11IBSS &&
++ Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ StopAdhocNetwork(priv);
++ }
++ }
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Extended version of encoding configuration
++ *
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param dwrq A pointer to iw_point structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_encode_ext(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
++ wlan_private *priv = dev->priv;
++ WLAN_802_11_KEY *pkey;
++ int keyindex;
++ u8 *pKeyMaterial = NULL;
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++ keyindex = dwrq->flags & IW_ENCODE_INDEX;
++ if (keyindex > 4)
++ return -EINVAL;
++ if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext)))
++ return -EINVAL;
++ pKeyMaterial = (u8 *) (ext + 1);
++ //Disable Key
++ if ((dwrq->flags & IW_ENCODE_DISABLED) && (ext->key_len == 0)) {
++ dwrq->length = 0;
++ wlan_set_encode_nonwpa(dev, info, dwrq, extra);
++ return WLAN_STATUS_SUCCESS;
++ }
++ //Set WEP key
++ if (ext->key_len <= MAX_WEP_KEY_SIZE) {
++ dwrq->length = ext->key_len;
++ wlan_set_encode_nonwpa(dev, info, dwrq, pKeyMaterial);
++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
++ dwrq->length = 0;
++ wlan_set_encode_nonwpa(dev, info, dwrq, extra);
++ }
++ } else {
++ pkey = kmalloc(sizeof(WLAN_802_11_KEY) + ext->key_len, GFP_KERNEL);
++ if (!pkey) {
++ PRINTM(INFO, "allocate key buffer failed!\n");
++ return -ENOMEM;
++ }
++ memset(pkey, 0, sizeof(WLAN_802_11_KEY) + ext->key_len);
++ memcpy((u8 *) pkey->BSSID, (u8 *) ext->addr.sa_data, ETH_ALEN);
++ pkey->KeyLength = ext->key_len;
++ memcpy(pkey->KeyMaterial, pKeyMaterial, ext->key_len);
++ pkey->KeyIndex = keyindex - 1;
++ if (pkey->KeyIndex == 0)
++ pkey->KeyIndex = 0x40000000;
++ if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
++ memcpy((u8 *) & pkey->KeyRSC, ext->rx_seq,
++ IW_ENCODE_SEQ_MAX_SIZE);
++ pkey->Length = sizeof(WLAN_802_11_KEY) + ext->key_len;
++ wlan_set_encode_wpa(dev, info, dwrq, (u8 *) pkey);
++ kfree(pkey);
++ }
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Extended version of encoding configuration
++ *
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param dwrq A pointer to iw_point structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_encode_ext(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ return -EOPNOTSUPP;
++}
++#endif /* #if (WIRELESS_EXT >= 18) */
++
++/**
++ * @brief Append/Reset IE buffer.
++ *
++ * Pass an opaque block of data, expected to be IEEE IEs, to the driver
++ * for eventual passthrough to the firmware in an associate/join
++ * (and potentially start) command.
++ *
++ * Data is appended to an existing buffer and then wrapped in a passthrough
++ * TLV in the command API to the firmware. The firmware treats the data
++ * as a transparent passthrough to the transmitted management frame.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_gen_ie_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ return wlan_set_gen_ie_helper(priv,
++ wrq->u.data.pointer, wrq->u.data.length);
++}
++
++/**
++ * @brief Get IE buffer from driver
++ *
++ * Used to pass an opaque block of data, expected to be IEEE IEs,
++ * back to the application. Currently the data block passed
++ * back to the application is the saved association response retrieved
++ * from the firmware.
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ *
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_gen_ie_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ return wlan_get_gen_ie_helper(priv,
++ wrq->u.data.pointer, &wrq->u.data.length);
++}
++
++/*
++ * iwconfig settable callbacks
++ */
++static const iw_handler wlan_handler[] = {
++ (iw_handler) wlan_config_commit, /* SIOCSIWCOMMIT */
++ (iw_handler) wlan_get_name, /* SIOCGIWNAME */
++ (iw_handler) NULL, /* SIOCSIWNWID */
++ (iw_handler) NULL, /* SIOCGIWNWID */
++ (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */
++ (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */
++ (iw_handler) wlan_set_mode, /* SIOCSIWMODE */
++ (iw_handler) wlan_get_mode, /* SIOCGIWMODE */
++ (iw_handler) wlan_set_sens, /* SIOCSIWSENS */
++ (iw_handler) wlan_get_sens, /* SIOCGIWSENS */
++ (iw_handler) NULL, /* SIOCSIWRANGE */
++ (iw_handler) wlan_get_range, /* SIOCGIWRANGE */
++ (iw_handler) NULL, /* SIOCSIWPRIV */
++ (iw_handler) NULL, /* SIOCGIWPRIV */
++ (iw_handler) NULL, /* SIOCSIWSTATS */
++ (iw_handler) NULL, /* SIOCGIWSTATS */
++#if WIRELESS_EXT > 15
++ iw_handler_set_spy, /* SIOCSIWSPY */
++ iw_handler_get_spy, /* SIOCGIWSPY */
++ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
++ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
++#else /* WIRELESS_EXT > 15 */
++#ifdef WIRELESS_SPY
++ (iw_handler) wlan_set_spy, /* SIOCSIWSPY */
++ (iw_handler) wlan_get_spy, /* SIOCGIWSPY */
++#else /* WIRELESS_SPY */
++ (iw_handler) NULL, /* SIOCSIWSPY */
++ (iw_handler) NULL, /* SIOCGIWSPY */
++#endif /* WIRELESS_SPY */
++ (iw_handler) NULL, /* -- hole -- */
++ (iw_handler) NULL, /* -- hole -- */
++#endif /* WIRELESS_EXT > 15 */
++ (iw_handler) wlan_set_wap, /* SIOCSIWAP */
++ (iw_handler) wlan_get_wap, /* SIOCGIWAP */
++#if WIRELESS_EXT >= 18
++ (iw_handler) wlan_set_mlme, /* SIOCSIWMLME */
++#else
++ (iw_handler) NULL, /* -- hole -- */
++#endif
++ //(iw_handler) wlan_get_aplist, /* SIOCGIWAPLIST */
++ NULL, /* SIOCGIWAPLIST */
++#if WIRELESS_EXT > 13
++ (iw_handler) wlan_set_scan, /* SIOCSIWSCAN */
++ (iw_handler) wlan_get_scan, /* SIOCGIWSCAN */
++#else /* WIRELESS_EXT > 13 */
++ (iw_handler) NULL, /* SIOCSIWSCAN */
++ (iw_handler) NULL, /* SIOCGIWSCAN */
++#endif /* WIRELESS_EXT > 13 */
++ (iw_handler) wlan_set_essid, /* SIOCSIWESSID */
++ (iw_handler) wlan_get_essid, /* SIOCGIWESSID */
++ (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */
++ (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */
++ (iw_handler) NULL, /* -- hole -- */
++ (iw_handler) NULL, /* -- hole -- */
++ (iw_handler) wlan_set_rate, /* SIOCSIWRATE */
++ (iw_handler) wlan_get_rate, /* SIOCGIWRATE */
++ (iw_handler) wlan_set_rts, /* SIOCSIWRTS */
++ (iw_handler) wlan_get_rts, /* SIOCGIWRTS */
++ (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */
++ (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */
++ (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */
++ (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */
++ (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */
++ (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */
++ (iw_handler) NULL, /* -- hole -- */
++ (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */
++ (iw_handler) wlan_set_power, /* SIOCSIWPOWER */
++ (iw_handler) wlan_get_power, /* SIOCGIWPOWER */
++#if (WIRELESS_EXT >= 18)
++ (iw_handler) NULL, /* -- hole -- */
++ (iw_handler) NULL, /* -- hole -- */
++ (iw_handler) wlan_set_gen_ie, /* SIOCSIWGENIE */
++ (iw_handler) wlan_get_gen_ie, /* SIOCGIWGENIE */
++ (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */
++ (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */
++ (iw_handler) wlan_set_encode_ext, /* SIOCSIWENCODEEXT */
++ (iw_handler) wlan_get_encode_ext, /* SIOCGIWENCODEEXT */
++#endif /* WIRELESSS_EXT >= 18 */
++};
++
++/*
++ * iwpriv settable callbacks
++ */
++
++static const iw_handler wlan_private_handler[] = {
++ NULL, /* SIOCIWFIRSTPRIV */
++};
++
++static const struct iw_priv_args wlan_private_args[] = {
++ /*
++ * { cmd, set_args, get_args, name }
++ */
++ {
++ WLANEXTSCAN,
++ IW_PRIV_TYPE_INT,
++ IW_PRIV_TYPE_CHAR | 2,
++ "extscan"},
++ {
++ WLANHOSTCMD,
++ IW_PRIV_TYPE_BYTE | 2047,
++ IW_PRIV_TYPE_BYTE | 2047,
++ "hostcmd"},
++ {
++ WLANARPFILTER,
++ IW_PRIV_TYPE_BYTE | 2047,
++ IW_PRIV_TYPE_BYTE | 2047,
++ "arpfilter"},
++ {
++ WLANREGRDWR,
++ IW_PRIV_TYPE_CHAR | 256,
++ IW_PRIV_TYPE_CHAR | 256,
++ "regrdwr"},
++ {
++ WLANCMD52RDWR,
++ IW_PRIV_TYPE_BYTE | 7,
++ IW_PRIV_TYPE_BYTE | 7,
++ "sdcmd52rw"},
++ {
++ WLANCMD53RDWR,
++ IW_PRIV_TYPE_CHAR | 32,
++ IW_PRIV_TYPE_CHAR | 32,
++ "sdcmd53rw"},
++ {
++ WLAN_SETCONF_GETCONF,
++ IW_PRIV_TYPE_BYTE | MAX_SETGET_CONF_SIZE,
++ IW_PRIV_TYPE_BYTE | MAX_SETGET_CONF_SIZE,
++ "setgetconf"},
++ {
++ WLANCISDUMP,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_BYTE | 512,
++ "getcis"},
++ {
++ WLANSCAN_TYPE,
++ IW_PRIV_TYPE_CHAR | 8,
++ IW_PRIV_TYPE_CHAR | 8,
++ "scantype"},
++ {
++ WLAN_SETINT_GETINT,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ ""},
++ {
++ WLANNF,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "getNF"},
++ {
++ WLANRSSI,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "getRSSI"},
++ {
++ WLANBGSCAN,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "bgscan"},
++ {
++ WLANENABLE11D,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "enable11d"},
++ {
++ WLANADHOCGRATE,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "adhocgrate"},
++ {
++ WLANSDIOCLOCK,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "sdioclock"},
++ {
++ WLANWMM_ENABLE,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "wmm"},
++ {
++ WLANNULLGEN,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "uapsdnullgen"},
++ {
++ WLANADHOCCSET,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "setcoalescing"},
++ {
++ WLAN_ADHOC_G_PROT,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "adhocgprot"},
++
++ {
++ WLAN_SETONEINT_GETONEINT,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_INT | 1,
++ ""},
++ {
++ WLAN_WMM_QOSINFO,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_INT | 1,
++ "wmm_qosinfo"},
++ {
++ WLAN_LISTENINTRVL,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_INT | 1,
++ "lolisteninter"},
++ {
++ WLAN_FW_WAKEUP_METHOD,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_INT | 1,
++ "fwwakeupmethod"},
++ {
++ WLAN_NULLPKTINTERVAL,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_INT | 1,
++ "psnullinterval"},
++ {
++ WLAN_BCN_MISS_TIMEOUT,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_INT | 1,
++ "bcnmisto"},
++ {
++ WLAN_ADHOC_AWAKE_PERIOD,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_INT | 1,
++ "adhocawakepd"},
++ {
++ WLAN_LDO,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_INT | 1,
++ "ldocfg"},
++ {
++ WLAN_SDIO_MODE,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_INT | 1,
++ "sdiomode"},
++ {
++ WLAN_RTS_CTS_CTRL,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_INT | 1,
++ "rtsctsctrl"},
++ {
++ WLAN_AUTODEEPSLEEP,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_INT | 1,
++ "autodeepsleep"},
++ {
++ WLAN_WAKEUP_MT,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_INT | 1,
++ "wakeupmt"},
++ /* Using iwpriv sub-command feature */
++ {
++ WLAN_SETONEINT_GETNONE,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_NONE,
++ ""},
++ {
++ WLAN_SUBCMD_SETRXANTENNA,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_NONE,
++ "setrxant"},
++ {
++ WLAN_SUBCMD_SETTXANTENNA,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_NONE,
++ "settxant"},
++ {
++ WLANSETAUTHALG,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_NONE,
++ "authalgs",
++ },
++ {
++ WLANSETENCRYPTIONMODE,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_NONE,
++ "encryptionmode",
++ },
++ {
++ WLANSETREGION,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_NONE,
++ "setregioncode"},
++ {
++ WLAN_SET_LISTEN_INTERVAL,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_NONE,
++ "setlisteninter"},
++ {
++ WLAN_SET_MULTIPLE_DTIM,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_NONE,
++ "setmultipledtim"},
++ {
++ WLANSETBCNAVG,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_NONE,
++ "setbcnavg"},
++ {
++ WLANSETDATAAVG,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_NONE,
++ "setdataavg"},
++ {
++ WLANASSOCIATE,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ IW_PRIV_TYPE_NONE,
++ "associate"},
++ {
++ WLAN_SETNONE_GETONEINT,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ ""},
++ {
++ WLANGETREGION,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "getregioncode"},
++ {
++ WLAN_GET_LISTEN_INTERVAL,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "getlisteninter"},
++ {
++ WLAN_GET_MULTIPLE_DTIM,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "getmultipledtim"},
++ {
++ WLAN_GET_TX_RATE,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "gettxrate"},
++ {
++ WLANGETBCNAVG,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "getbcnavg"},
++ {
++ WLANGETDATAAVG,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "getdataavg"},
++ {
++ WLANGETDTIM,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
++ "getdtim"},
++ {
++ WLAN_SETNONE_GETTWELVE_CHAR,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_CHAR | 12,
++ ""},
++ {
++ WLAN_SUBCMD_GETRXANTENNA,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_CHAR | 12,
++ "getrxant"},
++ {
++ WLAN_SUBCMD_GETTXANTENNA,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_CHAR | 12,
++ "gettxant"},
++ {
++ WLAN_GET_TSF,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_CHAR | 12,
++ "gettsf"},
++ {
++ WLAN_WPS_SESSION,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_CHAR | 12,
++ "wpssession"},
++ {
++ WLANDEEPSLEEP,
++ IW_PRIV_TYPE_CHAR | 1,
++ IW_PRIV_TYPE_CHAR | 6,
++ "deepsleep"},
++ {
++ WLANHOSTSLEEPCFG,
++ IW_PRIV_TYPE_CHAR | 31,
++ IW_PRIV_TYPE_NONE,
++ "hostsleepcfg"},
++ {
++ WLAN_SETNONE_GETNONE,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_NONE,
++ ""},
++ {
++ WLANDEAUTH,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_NONE,
++ "deauth"},
++ {
++ WLANADHOCSTOP,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_NONE,
++ "adhocstop"},
++ {
++ WLANRADIOON,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_NONE,
++ "radioon"},
++ {
++ WLANRADIOOFF,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_NONE,
++ "radiooff"},
++ {
++ WLANREMOVEADHOCAES,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_NONE,
++ "rmaeskey"},
++#ifdef REASSOCIATION
++ {
++ WLANREASSOCIATIONAUTO,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_NONE,
++ "reasso-on"},
++ {
++ WLANREASSOCIATIONUSER,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_NONE,
++ "reasso-off"},
++#endif /* REASSOCIATION */
++ {
++ WLANWLANIDLEON,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_NONE,
++ "wlanidle-on"},
++ {
++ WLANWLANIDLEOFF,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_NONE,
++ "wlanidle-off"},
++ {
++ WLAN_SET64CHAR_GET64CHAR,
++ IW_PRIV_TYPE_CHAR | 64,
++ IW_PRIV_TYPE_CHAR | 64,
++ ""},
++ {
++ WLANSLEEPPARAMS,
++ IW_PRIV_TYPE_CHAR | 64,
++ IW_PRIV_TYPE_CHAR | 64,
++ "sleepparams"},
++
++ {
++ WLAN_BCA_TIMESHARE,
++ IW_PRIV_TYPE_CHAR | 64,
++ IW_PRIV_TYPE_CHAR | 64,
++ "bca-ts"},
++ {
++ WLANSCAN_MODE,
++ IW_PRIV_TYPE_CHAR | 64,
++ IW_PRIV_TYPE_CHAR | 64,
++ "scanmode"},
++ {
++ WLAN_GET_ADHOC_STATUS,
++ IW_PRIV_TYPE_CHAR | 64,
++ IW_PRIV_TYPE_CHAR | 64,
++ "getadhocstatus"},
++ {
++ WLAN_SET_GEN_IE,
++ IW_PRIV_TYPE_CHAR | 64,
++ IW_PRIV_TYPE_CHAR | 64,
++ "setgenie"},
++ {
++ WLAN_GET_GEN_IE,
++ IW_PRIV_TYPE_CHAR | 64,
++ IW_PRIV_TYPE_CHAR | 64,
++ "getgenie"},
++ {
++ WLAN_WMM_QUEUE_STATUS,
++ IW_PRIV_TYPE_CHAR | 64,
++ IW_PRIV_TYPE_CHAR | 64,
++ "qstatus"},
++ {
++ WLAN_SETWORDCHAR_GETNONE,
++ IW_PRIV_TYPE_CHAR | 32,
++ IW_PRIV_TYPE_NONE,
++ ""},
++ {
++ WLANSETADHOCAES,
++ IW_PRIV_TYPE_CHAR | 32,
++ IW_PRIV_TYPE_NONE,
++ "setaeskey"},
++ {
++ WLAN_SETONEINT_GETWORDCHAR,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_CHAR | 128,
++ ""},
++ {
++ WLANGETADHOCAES,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_CHAR | 128,
++ "getaeskey"},
++ {
++ WLANVERSION,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_CHAR | 128,
++ "version"},
++ {
++ WLANVEREXT,
++ IW_PRIV_TYPE_INT | 1,
++ IW_PRIV_TYPE_CHAR | 128,
++ "verext"},
++ {
++ WLANSETWPAIE,
++ IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 24,
++ IW_PRIV_TYPE_NONE,
++ "setwpaie"},
++ {
++ WLANGETLOG,
++ IW_PRIV_TYPE_NONE,
++ IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE,
++ "getlog"},
++ {
++ WLAN_SET_GET_SIXTEEN_INT,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ ""},
++ {
++ WLAN_TPCCFG,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "tpccfg"},
++ {
++ WLAN_SCANPROBES,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "scanprobes"},
++ {
++ WLAN_LED_GPIO_CTRL,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "ledgpio"},
++ {
++ WLAN_SLEEP_PERIOD,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "sleeppd"},
++ {
++ WLAN_ADAPT_RATESET,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "rateadapt"},
++
++ {
++ WLAN_INACTIVITY_TIMEOUT,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "inactivityto"},
++ {
++ WLANSNR,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "getSNR"},
++ {
++ WLAN_GET_RATE,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "getrate"},
++ {
++ WLAN_GET_RXINFO,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "getrxinfo"},
++ {
++ WLAN_SET_ATIM_WINDOW,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "atimwindow"},
++ {
++ WLAN_BEACON_INTERVAL,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "bcninterval"},
++ {
++ WLAN_SDIO_PULL_CTRL,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "sdiopullctrl"},
++ {
++ WLAN_SCAN_TIME,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "scantime"},
++ {
++ WLAN_DATA_SUBSCRIBE_EVENT,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "dataevtcfg"},
++ {
++ WLAN_TXCONTROL,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "txcontrol"},
++ {
++ WLANHSCFG,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "hscfg"},
++ {
++ WLANHSSETPARA,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "hssetpara"},
++#ifdef DEBUG_LEVEL1
++ {
++ WLAN_DRV_DBG,
++ IW_PRIV_TYPE_INT | 16,
++ IW_PRIV_TYPE_INT | 16,
++ "drvdbg"},
++#endif
++ {
++ WLAN_SET_GET_2K,
++ IW_PRIV_TYPE_BYTE | 2000,
++ IW_PRIV_TYPE_BYTE | 2000,
++ ""},
++ {
++ WLAN_SET_USER_SCAN,
++ IW_PRIV_TYPE_BYTE | 2000,
++ IW_PRIV_TYPE_BYTE | 2000,
++ "setuserscan"},
++ {
++ WLAN_GET_SCAN_TABLE,
++ IW_PRIV_TYPE_BYTE | 2000,
++ IW_PRIV_TYPE_BYTE | 2000,
++ "getscantable"},
++ {
++ WLAN_SET_MRVL_TLV,
++ IW_PRIV_TYPE_BYTE | 2000,
++ IW_PRIV_TYPE_BYTE | 2000,
++ "setmrvltlv"},
++ {
++ WLAN_GET_ASSOC_RSP,
++ IW_PRIV_TYPE_BYTE | 2000,
++ IW_PRIV_TYPE_BYTE | 2000,
++ "getassocrsp"},
++ {
++ WLAN_ADDTS_REQ,
++ IW_PRIV_TYPE_BYTE | 2000,
++ IW_PRIV_TYPE_BYTE | 2000,
++ "addts"},
++ {
++ WLAN_DELTS_REQ,
++ IW_PRIV_TYPE_BYTE | 2000,
++ IW_PRIV_TYPE_BYTE | 2000,
++ "delts"},
++ {
++ WLAN_QUEUE_CONFIG,
++ IW_PRIV_TYPE_BYTE | 2000,
++ IW_PRIV_TYPE_BYTE | 2000,
++ "qconfig"},
++ {
++ WLAN_QUEUE_STATS,
++ IW_PRIV_TYPE_BYTE | 2000,
++ IW_PRIV_TYPE_BYTE | 2000,
++ "qstats"},
++ {
++ WLAN_TX_PKT_STATS,
++ IW_PRIV_TYPE_BYTE | 2000,
++ IW_PRIV_TYPE_BYTE | 2000,
++ "txpktstats"},
++ {
++ WLAN_GET_CFP_TABLE,
++ IW_PRIV_TYPE_BYTE | 2000,
++ IW_PRIV_TYPE_BYTE | 2000,
++ "getcfptable"},
++};
++
++struct iw_handler_def wlan_handler_def = {
++ num_standard:sizeof(wlan_handler) / sizeof(iw_handler),
++ num_private:sizeof(wlan_private_handler) / sizeof(iw_handler),
++ num_private_args:sizeof(wlan_private_args) /
++ sizeof(struct iw_priv_args),
++ standard:(iw_handler *) wlan_handler,
++ private:(iw_handler *) wlan_private_handler,
++ private_args:(struct iw_priv_args *) wlan_private_args,
++};
++
++/**
++ * @brief get the channel frequency power info with specific channel
++ *
++ * @param band it can be BAND_A, BAND_G or BAND_B
++ * @param channel the channel for looking
++ * @param region_channel A pointer to REGION_CHANNEL structure
++ * @return A pointer to CHANNEL_FREQ_POWER structure or NULL if not find.
++ */
++
++CHANNEL_FREQ_POWER *
++get_cfp_by_band_and_channel(u8 band, u16 channel,
++ REGION_CHANNEL * region_channnel)
++{
++ REGION_CHANNEL *rc;
++ CHANNEL_FREQ_POWER *cfp = NULL;
++ int i, j;
++
++ for (j = 0; !cfp && (j < MAX_REGION_CHANNEL_NUM); j++) {
++ rc = &region_channnel[j];
++
++ if (!rc->Valid || !rc->CFP)
++ continue;
++ if (rc->Band != band)
++ continue;
++ if (channel == FIRST_VALID_CHANNEL)
++ cfp = &rc->CFP[0];
++ else {
++ for (i = 0; i < rc->NrCFP; i++) {
++ if (rc->CFP[i].Channel == channel) {
++ cfp = &rc->CFP[i];
++ break;
++ }
++ }
++ }
++ }
++
++ if (!cfp && channel)
++ PRINTM(INFO, "get_cfp_by_band_and_channel(): cannot find "
++ "cfp by band %d & channel %d\n", band, channel);
++
++ LEAVE();
++ return cfp;
++}
++
++/**
++ * @brief wlan hostcmd ioctl handler
++ *
++ * @param dev A pointer to net_device structure
++ * @param req A pointer to ifreq structure
++ * @param cmd command
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_hostcmd_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
++{
++ u8 *tempResponseBuffer;
++ CmdCtrlNode *pCmdNode;
++ HostCmd_DS_GEN *pCmdPtr;
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ u16 wait_option = 0;
++ struct iwreq *wrq = (struct iwreq *) req;
++
++ ENTER();
++
++ if ((wrq->u.data.pointer == NULL) || (wrq->u.data.length < S_DS_GEN)) {
++ PRINTM(INFO,
++ "wlan_hostcmd_ioctl() corrupt data: pointer=%p, length=%d\n",
++ wrq->u.data.pointer, wrq->u.data.length);
++ return -EFAULT;
++ }
++
++ /*
++ * Get a free command control node
++ */
++ if (!(pCmdNode = GetFreeCmdCtrlNode(priv))) {
++ PRINTM(INFO, "Failed GetFreeCmdCtrlNode\n");
++ return -ENOMEM;
++ }
++
++ if (!
++ (tempResponseBuffer =
++ kmalloc(MRVDRV_SIZE_OF_CMD_BUFFER, GFP_KERNEL))) {
++ PRINTM(INFO, "ERROR: Failed to allocate response buffer!\n");
++ CleanupAndInsertCmd(priv, pCmdNode);
++ return -ENOMEM;
++ }
++
++ wait_option |= HostCmd_OPTION_WAITFORRSP;
++
++ SetCmdCtrlNode(priv, pCmdNode, 0, wait_option, NULL);
++ init_waitqueue_head(&pCmdNode->cmdwait_q);
++
++ pCmdPtr = (HostCmd_DS_GEN *) pCmdNode->BufVirtualAddr;
++
++ /*
++ * Copy the whole command into the command buffer
++ */
++ if (copy_from_user(pCmdPtr, wrq->u.data.pointer, wrq->u.data.length)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ kfree(tempResponseBuffer);
++ CleanupAndInsertCmd(priv, pCmdNode);
++ return -EFAULT;
++ }
++
++ if (pCmdPtr->Size < S_DS_GEN) {
++ PRINTM(INFO, "wlan_hostcmd_ioctl() invalid cmd size: Size=%d\n",
++ pCmdPtr->Size);
++ kfree(tempResponseBuffer);
++ CleanupAndInsertCmd(priv, pCmdNode);
++ return -EFAULT;
++ }
++
++ pCmdNode->pdata_buf = tempResponseBuffer;
++ pCmdNode->CmdFlags |= CMD_F_HOSTCMD;
++
++ pCmdPtr->Result = 0;
++
++ PRINTM(INFO, "HOSTCMD Command: 0x%04x Size: %d\n",
++ pCmdPtr->Command, pCmdPtr->Size);
++ HEXDUMP("Command Data", (u8 *) (pCmdPtr), MIN(32, pCmdPtr->Size));
++ PRINTM(INFO, "Copying data from : (user)0x%p -> 0x%p(driver)\n",
++ req->ifr_data, pCmdPtr);
++
++ pCmdNode->CmdWaitQWoken = FALSE;
++ pCmdPtr->Command = wlan_cpu_to_le16(pCmdPtr->Command);
++ pCmdPtr->Size = wlan_cpu_to_le16(pCmdPtr->Size);
++ QueueCmd(Adapter, pCmdNode, TRUE);
++ wake_up_interruptible(&priv->MainThread.waitQ);
++
++ if (wait_option & HostCmd_OPTION_WAITFORRSP) {
++ /* Sleep until response is generated by FW */
++ wait_event_interruptible(pCmdNode->cmdwait_q,
++ pCmdNode->CmdWaitQWoken);
++ }
++
++ /* Copy the response back to user space */
++ pCmdPtr = (HostCmd_DS_GEN *) tempResponseBuffer;
++
++ if (copy_to_user(wrq->u.data.pointer, tempResponseBuffer, pCmdPtr->Size))
++ PRINTM(INFO, "ERROR: copy_to_user failed!\n");
++ wrq->u.data.length = pCmdPtr->Size;
++ kfree(tempResponseBuffer);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief wlan arpfilter ioctl handler
++ *
++ * @param dev A pointer to net_device structure
++ * @param req A pointer to ifreq structure
++ * @param cmd command
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_arpfilter_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
++{
++ wlan_private *priv = dev->priv;
++ struct iwreq *wrq = (struct iwreq *) req;
++ wlan_adapter *Adapter = priv->adapter;
++ MrvlIEtypesHeader_t hdr;
++
++ ENTER();
++
++ if ((wrq->u.data.pointer == NULL)
++ || (wrq->u.data.length < sizeof(MrvlIEtypesHeader_t))
++ || (wrq->u.data.length > sizeof(Adapter->ArpFilter))) {
++ PRINTM(INFO,
++ "wlan_arpfilter_ioctl() corrupt data: pointer=%p, length=%d\n",
++ wrq->u.data.pointer, wrq->u.data.length);
++ return -EFAULT;
++ }
++
++ if (copy_from_user(&hdr, wrq->u.data.pointer, sizeof(hdr))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ if (hdr.Len == 0) {
++ Adapter->ArpFilterSize = 0;
++ memset(Adapter->ArpFilter, 0, sizeof(Adapter->ArpFilter));
++ } else {
++ Adapter->ArpFilterSize = wrq->u.data.length;
++
++ PRINTM(INFO, "Copying data from : (user)0x%p -> 0x%p(driver)\n",
++ wrq->u.data.pointer, Adapter->ArpFilter);
++ if (copy_from_user(Adapter->ArpFilter, wrq->u.data.pointer,
++ Adapter->ArpFilterSize)) {
++ Adapter->ArpFilterSize = 0;
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ HEXDUMP("ArpFilter", Adapter->ArpFilter, Adapter->ArpFilterSize);
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get Rx Info
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wreq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success
++ */
++static int
++wlan_get_rxinfo(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int data[2];
++ ENTER();
++ data[0] = Adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
++ data[1] = Adapter->RxPDRate;
++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = 2;
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get SNR
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wreq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_snr(wlan_private * priv, struct iwreq *wrq)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_adapter *Adapter = priv->adapter;
++ int data[4];
++
++ ENTER();
++
++ memset(data, 0, sizeof(data));
++ if (wrq->u.data.length) {
++ if (copy_from_user
++ (data, wrq->u.data.pointer,
++ MIN(wrq->u.data.length, 4) * sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++ }
++ if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) {
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_RSSI,
++ 0, HostCmd_OPTION_WAITFORRSP,
++ 0, NULL);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ }
++ }
++
++ if (wrq->u.data.length == 0) {
++ data[0] = Adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
++ data[1] = Adapter->SNR[TYPE_BEACON][TYPE_AVG];
++ if ((jiffies - Adapter->RxPDAge) > HZ) //data expired after 1 second
++ data[2] = 0;
++ else
++ data[2] = Adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
++ data[3] = Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 4)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = 4;
++ } else if (data[0] == 0) {
++ data[0] = Adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = 1;
++ } else if (data[0] == 1) {
++ data[0] = Adapter->SNR[TYPE_BEACON][TYPE_AVG];
++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = 1;
++ } else if (data[0] == 2) {
++ if ((jiffies - Adapter->RxPDAge) > HZ) //data expired after 1 second
++ data[0] = 0;
++ else
++ data[0] = Adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = 1;
++ } else if (data[0] == 3) {
++ data[0] = Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = 1;
++ } else {
++ return -ENOTSUPP;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get/Set SDIO PULL CTRL
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wreq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_sdio_pull_ctrl(wlan_private * priv, struct iwreq *wrq)
++{
++ int data[2];
++ HostCmd_DS_SDIO_PULL_CTRL sdio_pull_ctrl;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++ memset(&sdio_pull_ctrl, 0, sizeof(sdio_pull_ctrl));
++ if (wrq->u.data.length > 0) {
++ if (copy_from_user(data, wrq->u.data.pointer, sizeof(data))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++ PRINTM(INFO, "WLAN SET SDIO PULL CTRL: %d %d\n", data[0], data[1]);
++ sdio_pull_ctrl.Action = HostCmd_ACT_GEN_SET;
++ sdio_pull_ctrl.PullUp = data[0];
++ sdio_pull_ctrl.PullDown = data[1];
++ } else {
++ sdio_pull_ctrl.Action = HostCmd_ACT_GEN_GET;
++ }
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_SDIO_PULL_CTRL,
++ 0, HostCmd_OPTION_WAITFORRSP,
++ 0, (void *) &sdio_pull_ctrl);
++ data[0] = sdio_pull_ctrl.PullUp;
++ data[1] = sdio_pull_ctrl.PullDown;
++ wrq->u.data.length = 2;
++ if (copy_to_user
++ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get/Set scan time
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wreq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_scan_time(wlan_private * priv, struct iwreq *wrq)
++{
++ int data[3] = { 0, 0, 0 };
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (wrq->u.data.length > 0 && wrq->u.data.length <= 3) {
++ if (copy_from_user
++ (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ PRINTM(INFO,
++ "WLAN SET Scan Time: Specific %d, Active %d, Passive %d\n",
++ data[0], data[1], data[2]);
++ if (data[0]) {
++ if (data[0] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME) {
++ PRINTM(MSG,
++ "Invalid parameter, max specific scan time is %d ms\n",
++ MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME);
++ return -EINVAL;
++ }
++ Adapter->SpecificScanTime = data[0];
++ }
++ if (data[1]) {
++ if (data[1] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME) {
++ PRINTM(MSG,
++ "Invalid parameter, max active scan time is %d ms\n",
++ MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME);
++ return -EINVAL;
++ }
++ Adapter->ActiveScanTime = data[1];
++ }
++ if (data[2]) {
++ if (data[2] > MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME) {
++ PRINTM(MSG,
++ "Invalid parameter, max passive scan time is %d ms\n",
++ MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME);
++ return -EINVAL;
++ }
++ Adapter->PassiveScanTime = data[2];
++ }
++ }
++
++ data[0] = Adapter->SpecificScanTime;
++ data[1] = Adapter->ActiveScanTime;
++ data[2] = Adapter->PassiveScanTime;
++ wrq->u.data.length = 3;
++ if (copy_to_user
++ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get/Set Adhoc beacon Interval
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wreq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq)
++{
++ int data[2];
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (wrq->u.data.length > 0) {
++ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ PRINTM(INFO, "WLAN SET BEACON INTERVAL: %d\n", data[0]);
++ if ((data[0] > MRVDRV_MAX_BEACON_INTERVAL) ||
++ (data[0] < MRVDRV_MIN_BEACON_INTERVAL))
++ return -ENOTSUPP;
++ Adapter->BeaconPeriod = data[0];
++ }
++ data[0] = Adapter->BeaconPeriod;
++ wrq->u.data.length = 1;
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ data[1] = Adapter->CurBssParams.BSSDescriptor.BeaconPeriod;
++ wrq->u.data.length = 2;
++ }
++ if (copy_to_user
++ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get/Set Adhoc ATIM Window
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wreq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_ATIM_Window(wlan_private * priv, struct iwreq *wrq)
++{
++ int data[2];
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (wrq->u.data.length > 0) {
++ if (copy_from_user(data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ PRINTM(INFO, "WLAN SET ATIM WINDOW: %d\n", data[0]);
++ Adapter->AtimWindow = data[0];
++ Adapter->AtimWindow = MIN(Adapter->AtimWindow, 50);
++ }
++ data[0] = Adapter->AtimWindow;
++ wrq->u.data.length = 1;
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ data[1] = Adapter->CurBssParams.BSSDescriptor.ATIMWindow;
++ wrq->u.data.length = 2;
++ }
++ if (copy_to_user
++ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get/Set data subscribe event
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wreq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_data_subscribe_event(wlan_private * priv, struct iwreq *wrq)
++{
++ int data[9];
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ memset(data, 0, sizeof(data));
++ if (wrq->u.data.length > 9)
++ return -EFAULT;
++ if (wrq->u.data.length > 0) {
++ if (copy_from_user
++ (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++ memset(&Adapter->subevent, 0, sizeof(Adapter->subevent));
++ Adapter->subevent.EventsBitmap = (u16) data[0];
++ Adapter->subevent.Rssi_low.value = (u8) data[1];
++ Adapter->subevent.Rssi_low.Freq = (u8) data[2];
++ Adapter->subevent.Snr_low.value = (u8) data[3];
++ Adapter->subevent.Snr_low.Freq = (u8) data[4];
++ Adapter->subevent.Rssi_high.value = (u8) data[5];
++ Adapter->subevent.Rssi_high.Freq = (u8) data[6];
++ Adapter->subevent.Snr_high.value = (u8) data[7];
++ Adapter->subevent.Snr_high.Freq = (u8) data[8];
++ } else {
++ data[0] = (int) Adapter->subevent.EventsBitmap;
++ data[1] = (int) Adapter->subevent.Rssi_low.value;
++ data[2] = (int) Adapter->subevent.Rssi_low.Freq;
++ data[3] = (int) Adapter->subevent.Snr_low.value;
++ data[4] = (int) Adapter->subevent.Snr_low.Freq;
++ data[5] = (int) Adapter->subevent.Rssi_high.value;
++ data[6] = (int) Adapter->subevent.Rssi_high.Freq;
++ data[7] = (int) Adapter->subevent.Snr_high.value;
++ data[8] = (int) Adapter->subevent.Snr_high.Freq;
++ }
++ wrq->u.data.length = 9;
++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get RSSI
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wreq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_rssi(wlan_private * priv, struct iwreq *wrq)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_adapter *Adapter = priv->adapter;
++ int temp;
++ int data = 0;
++ int *val;
++
++ ENTER();
++ data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
++ if ((data == 0) || (data == 1)) {
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_RSSI,
++ 0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ }
++
++ switch (data) {
++ case 0:
++
++ temp = CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
++ Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
++ break;
++ case 1:
++ temp = CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_AVG],
++ Adapter->NF[TYPE_BEACON][TYPE_AVG]);
++ break;
++ case 2:
++ if ((jiffies - Adapter->RxPDAge) > HZ) //data expired after 1 second
++ temp = 0;
++ else
++ temp = CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
++ Adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
++ break;
++ case 3:
++ temp = CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
++ Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
++ break;
++ default:
++ return -ENOTSUPP;
++ }
++ val = (int *) wrq->u.name;
++ *val = temp;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get NF
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wreq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_nf(wlan_private * priv, struct iwreq *wrq)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_adapter *Adapter = priv->adapter;
++ int temp;
++ int data = 0;
++ int *val;
++
++ ENTER();
++ data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
++ if ((data == 0) || (data == 1)) {
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_RSSI,
++ 0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ }
++
++ switch (data) {
++ case 0:
++ temp = Adapter->NF[TYPE_BEACON][TYPE_NOAVG];
++ break;
++ case 1:
++ temp = Adapter->NF[TYPE_BEACON][TYPE_AVG];
++ break;
++ case 2:
++ if ((jiffies - Adapter->RxPDAge) > HZ) //data expired after 1 second
++ temp = 0;
++ else
++ temp = Adapter->NF[TYPE_RXPD][TYPE_NOAVG];
++ break;
++ case 3:
++ temp = Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
++ break;
++ default:
++ return -ENOTSUPP;
++ }
++
++ temp = CAL_NF(temp);
++
++ PRINTM(INFO, "***temp = %d\n", temp);
++ val = (int *) wrq->u.name;
++ *val = temp;
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Remove AES key
++ *
++ * @param priv A pointer to wlan_private structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_remove_aes(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ WLAN_802_11_KEY key;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (Adapter->InfrastructureMode != Wlan802_11IBSS ||
++ Adapter->MediaConnectStatus == WlanMediaStateConnected)
++ return -EOPNOTSUPP;
++
++ Adapter->AdhocAESEnabled = FALSE;
++
++ memset(&key, 0, sizeof(WLAN_802_11_KEY));
++ PRINTM(INFO, "WPA2: DISABLE AES_KEY\n");
++ key.KeyLength = WPA_AES_KEY_LEN;
++ key.KeyIndex = 0x40000000;
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_KEY_MATERIAL,
++ HostCmd_ACT_SET,
++ HostCmd_OPTION_WAITFORRSP,
++ !(KEY_INFO_ENABLED), &key);
++
++ LEAVE();
++
++ return ret;
++}
++
++/**
++ * @brief Get Support Rates
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_getrate_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ WLAN_802_11_RATES rates;
++ int rate[sizeof(rates)];
++ int i;
++
++ ENTER();
++
++ memset(rates, 0, sizeof(rates));
++ memset(rate, 0, sizeof(rate));
++ wrq->u.data.length = get_active_data_rates(Adapter, rates);
++ if (wrq->u.data.length > sizeof(rates))
++ wrq->u.data.length = sizeof(rates);
++
++ for (i = 0; i < wrq->u.data.length; i++) {
++ rates[i] &= ~0x80;
++ rate[i] = rates[i];
++ }
++
++ if (copy_to_user
++ (wrq->u.data.pointer, rate, wrq->u.data.length * sizeof(int))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get TxRate
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_txrate_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int *pdata;
++ struct iwreq *wrq = (struct iwreq *) req;
++ int ret = WLAN_STATUS_SUCCESS;
++ ENTER();
++ Adapter->TxRate = 0;
++ PRINTM(INFO, "wlan_get_txrate_ioctl\n");
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
++ HostCmd_ACT_GET, HostCmd_OPTION_WAITFORRSP,
++ 0, NULL);
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ pdata = (int *) wrq->u.name;
++ *pdata = (int) Adapter->TxRate;
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get DTIM
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_dtim_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ struct iwreq *wrq = (struct iwreq *) req;
++ int *pdata;
++ int ret = WLAN_STATUS_FAILURE;
++
++ ENTER();
++
++ /* The DTIM value is valid only in connected state */
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ Adapter->Dtim = 0;
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SNMP_MIB,
++ HostCmd_ACT_GET,
++ HostCmd_OPTION_WAITFORRSP,
++ OID_802_11_DTIM, NULL);
++ if (!ret) {
++ pdata = (int *) wrq->u.name;
++ *pdata = (int) Adapter->Dtim;
++ }
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get Adhoc Status
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_get_adhoc_status_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ char status[64];
++ wlan_adapter *Adapter = priv->adapter;
++
++ memset(status, 0, sizeof(status));
++
++ switch (Adapter->InfrastructureMode) {
++ case Wlan802_11IBSS:
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ if (Adapter->AdhocCreate == TRUE)
++ strcpy(status, "AdhocStarted");
++ else
++ strcpy(status, "AdhocJoined");
++ } else {
++ strcpy(status, "AdhocIdle");
++ }
++ break;
++ case Wlan802_11Infrastructure:
++ strcpy(status, "InfraMode");
++ break;
++ default:
++ strcpy(status, "AutoUnknownMode");
++ break;
++ }
++
++ PRINTM(INFO, "Status = %s\n", status);
++ wrq->u.data.length = strlen(status) + 1;
++
++ if (wrq->u.data.pointer) {
++ if (copy_to_user(wrq->u.data.pointer, &status, wrq->u.data.length))
++ return -EFAULT;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get Driver Version
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_version_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ int len;
++ char buf[128];
++ struct iwreq *wrq = (struct iwreq *) req;
++
++ ENTER();
++
++ get_version(priv->adapter, buf, sizeof(buf) - 1);
++
++ len = strlen(buf);
++ if (wrq->u.data.pointer) {
++ if (copy_to_user(wrq->u.data.pointer, buf, len)) {
++ PRINTM(INFO, "CopyToUser failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = len;
++ }
++
++ PRINTM(INFO, "wlan version: %s\n", buf);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get Driver and FW version
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_verext_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ HostCmd_DS_VERSION_EXT versionExtCmd;
++ int len;
++
++ ENTER();
++
++ memset(&versionExtCmd, 0x00, sizeof(versionExtCmd));
++
++ if (wrq->u.data.flags == 0) {
++ //from iwpriv subcmd
++ versionExtCmd.versionStrSel =
++ *((int *) (wrq->u.name + SUBCMD_OFFSET));
++ } else {
++ if (copy_from_user(&versionExtCmd.versionStrSel,
++ wrq->u.data.pointer,
++ sizeof(versionExtCmd.versionStrSel))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++ }
++
++ PrepareAndSendCommand(priv,
++ HostCmd_CMD_VERSION_EXT, 0,
++ HostCmd_OPTION_WAITFORRSP, 0, &versionExtCmd);
++
++ len = strlen(versionExtCmd.versionStr) + 1;
++ if (wrq->u.data.pointer) {
++ if (copy_to_user(wrq->u.data.pointer, versionExtCmd.versionStr, len)) {
++ PRINTM(INFO, "CopyToUser failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = len;
++ }
++
++ PRINTM(INFO, "Version: %s\n", versionExtCmd.versionStr);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Read/Write adapter registers
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_regrdwr_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ wlan_ioctl_regrdwr regrdwr;
++ wlan_offset_value offval;
++ u8 *pRdeeprom;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (copy_from_user(&regrdwr, req->ifr_data, sizeof(regrdwr))) {
++ PRINTM(INFO,
++ "copy of regrdwr for wlan_regrdwr_ioctl from user failed \n");
++ LEAVE();
++ return -EFAULT;
++ }
++
++ if (regrdwr.WhichReg == REG_EEPROM) {
++ PRINTM(INFO, "Inside RDEEPROM\n");
++ pRdeeprom =
++ (char *) kmalloc((regrdwr.NOB + sizeof(regrdwr)), GFP_KERNEL);
++ if (!pRdeeprom) {
++ PRINTM(INFO, "allocate memory for EEPROM read failed\n");
++ return -ENOMEM;
++ }
++ memcpy(pRdeeprom, &regrdwr, sizeof(regrdwr));
++ PRINTM(INFO, "Action: %d, Offset: %x, NOB: %02x\n",
++ regrdwr.Action, regrdwr.Offset, regrdwr.NOB);
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_EEPROM_ACCESS,
++ regrdwr.Action, HostCmd_OPTION_WAITFORRSP,
++ 0, pRdeeprom);
++
++ /*
++ * Return the result back to the user
++ */
++ if (!ret && regrdwr.Action == HostCmd_ACT_GEN_READ) {
++ if (copy_to_user
++ (req->ifr_data, pRdeeprom, sizeof(regrdwr) + regrdwr.NOB)) {
++ PRINTM(INFO,
++ "copy of regrdwr for wlan_regrdwr_ioctl to user failed \n");
++ ret = -EFAULT;
++ }
++ }
++
++ kfree(pRdeeprom);
++
++ LEAVE();
++ return ret;
++ }
++
++ offval.offset = regrdwr.Offset;
++ offval.value = (regrdwr.Action) ? regrdwr.Value : 0x00;
++
++ PRINTM(INFO, "RegAccess: %02x Action:%d "
++ "Offset: %04x Value: %04x\n",
++ regrdwr.WhichReg, regrdwr.Action, offval.offset, offval.value);
++
++ /*
++ * regrdwr.WhichReg should contain the command that
++ * corresponds to which register access is to be
++ * performed HostCmd_CMD_MAC_REG_ACCESS 0x0019
++ * HostCmd_CMD_BBP_REG_ACCESS 0x001a
++ * HostCmd_CMD_RF_REG_ACCESS 0x001b
++ */
++ if (regrdwr.WhichReg == REG_MAC ||
++ regrdwr.WhichReg == REG_BBP || regrdwr.WhichReg == REG_RF) {
++ ret = PrepareAndSendCommand(priv, regrdwr.WhichReg,
++ regrdwr.Action, HostCmd_OPTION_WAITFORRSP,
++ 0, &offval);
++ } else
++ ret = -EINVAL;
++
++ /*
++ * Return the result back to the user
++ */
++ if (!ret && regrdwr.Action == HostCmd_ACT_GEN_READ) {
++ regrdwr.Value = offval.value;
++ if (copy_to_user(req->ifr_data, &regrdwr, sizeof(regrdwr))) {
++ PRINTM(INFO,
++ "copy of regrdwr for wlan_regrdwr_ioctl to user failed \n");
++ ret = -EFAULT;
++ }
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Cmd52 read/write register
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_cmd52rdwr_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ u8 buf[7];
++ u8 rw, func, dat = 0xff;
++ u32 reg;
++
++ ENTER();
++
++ if (copy_from_user(buf, req->ifr_data, sizeof(buf))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ rw = buf[0];
++ func = buf[1];
++ reg = buf[5];
++ reg = (reg << 8) + buf[4];
++ reg = (reg << 8) + buf[3];
++ reg = (reg << 8) + buf[2];
++
++ if (rw != 0)
++ dat = buf[6];
++
++ PRINTM(INFO, "rw=%d func=%d reg=0x%08X dat=0x%02X\n", rw, func, reg, dat);
++
++ if (rw == 0) {
++ if (sbi_read_ioreg(priv, func, reg, &dat) < 0) {
++ PRINTM(INFO, "sdio_read_ioreg: reading register 0x%X failed\n",
++ reg);
++ dat = 0xff;
++ }
++ } else {
++ if (sbi_write_ioreg(priv, func, reg, dat) < 0) {
++ PRINTM(INFO, "sdio_read_ioreg: writing register 0x%X failed\n",
++ reg);
++ dat = 0xff;
++ }
++ }
++ if (copy_to_user(req->ifr_data, &dat, sizeof(dat))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Cmd53 read/write register
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_cmd53rdwr_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ return -EINVAL;
++}
++
++/**
++ * @brief Convert ascii string to Hex integer
++ *
++ * @param d A pointer to integer buf
++ * @param s A pointer to ascii string
++ * @param dlen the length o fascii string
++ * @return number of integer
++ */
++static int
++ascii2hex(u8 * d, char *s, u32 dlen)
++{
++ int i;
++ u8 n;
++
++ memset(d, 0x00, dlen);
++
++ for (i = 0; i < dlen * 2; i++) {
++ if ((s[i] >= 48) && (s[i] <= 57))
++ n = s[i] - 48;
++ else if ((s[i] >= 65) && (s[i] <= 70))
++ n = s[i] - 55;
++ else if ((s[i] >= 97) && (s[i] <= 102))
++ n = s[i] - 87;
++ else
++ break;
++ if ((i % 2) == 0)
++ n = n * 16;
++ d[i / 2] += n;
++ }
++
++ return i;
++}
++
++/**
++ * @brief Set adhoc aes key
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_setadhocaes_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ u8 key_ascii[32];
++ u8 key_hex[16];
++ int ret = 0;
++ struct iwreq *wrq = (struct iwreq *) req;
++ wlan_adapter *Adapter = priv->adapter;
++
++ WLAN_802_11_KEY key;
++
++ ENTER();
++
++ if (Adapter->InfrastructureMode != Wlan802_11IBSS)
++ return -EOPNOTSUPP;
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected)
++ return -EOPNOTSUPP;
++
++ if (copy_from_user(key_ascii, wrq->u.data.pointer, sizeof(key_ascii))) {
++ PRINTM(INFO, "wlan_setadhocaes_ioctl copy from user failed \n");
++ LEAVE();
++ return -EFAULT;
++ }
++
++ Adapter->AdhocAESEnabled = TRUE;
++ ascii2hex(key_hex, key_ascii, sizeof(key_hex));
++
++ HEXDUMP("wlan_setadhocaes_ioctl", key_hex, sizeof(key_hex));
++
++ PRINTM(INFO, "WPA2: ENABLE AES_KEY\n");
++ key.KeyLength = WPA_AES_KEY_LEN;
++ key.KeyIndex = 0x40000000;
++ memcpy(key.KeyMaterial, key_hex, key.KeyLength);
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_KEY_MATERIAL,
++ HostCmd_ACT_SET,
++ HostCmd_OPTION_WAITFORRSP,
++ KEY_INFO_ENABLED, &key);
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get adhoc aes key
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_getadhocaes_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ u8 *tmp;
++ u8 key_ascii[33];
++ u8 key_hex[16];
++ int i, ret = 0;
++ struct iwreq *wrq = (struct iwreq *) req;
++ wlan_adapter *Adapter = priv->adapter;
++ WLAN_802_11_KEY key;
++
++ ENTER();
++
++ memset(key_hex, 0x00, sizeof(key_hex));
++
++ PRINTM(INFO, "WPA2: ENABLE AES_KEY\n");
++ key.KeyLength = WPA_AES_KEY_LEN;
++ key.KeyIndex = 0x40000000;
++ memcpy(key.KeyMaterial, key_hex, key.KeyLength);
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_KEY_MATERIAL,
++ HostCmd_ACT_GET,
++ HostCmd_OPTION_WAITFORRSP,
++ KEY_INFO_ENABLED, &key);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++
++ memcpy(key_hex, Adapter->aeskey.KeyParamSet.Key, sizeof(key_hex));
++
++ HEXDUMP("wlan_getadhocaes_ioctl", key_hex, sizeof(key_hex));
++
++ wrq->u.data.length = sizeof(key_ascii) + 1;
++
++ memset(key_ascii, 0x00, sizeof(key_ascii));
++ tmp = key_ascii;
++
++ for (i = 0; i < sizeof(key_hex); i++)
++ tmp += sprintf(tmp, "%02x", key_hex[i]);
++
++ if (wrq->u.data.pointer) {
++ if (copy_to_user(wrq->u.data.pointer, &key_ascii, sizeof(key_ascii))) {
++ PRINTM(INFO, "copy_to_user failed\n");
++ return -EFAULT;
++ }
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Set multiple dtim
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_multiple_dtim_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ struct iwreq *wrq = (struct iwreq *) req;
++ u32 mdtim;
++ int idata;
++ int ret = -EINVAL;
++
++ ENTER();
++
++ idata = *((int *) (wrq->u.name + SUBCMD_OFFSET));
++ mdtim = (u32) idata;
++ if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM) &&
++ (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM))
++ || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) {
++ priv->adapter->MultipleDtim = mdtim;
++ ret = WLAN_STATUS_SUCCESS;
++ }
++ if (ret)
++ PRINTM(INFO, "Invalid parameter, MultipleDtim not changed.\n");
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Set authentication mode
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_setauthalg_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ int alg;
++ struct iwreq *wrq = (struct iwreq *) req;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (wrq->u.data.flags == 0) {
++ //from iwpriv subcmd
++ alg = *((int *) (wrq->u.name + SUBCMD_OFFSET));
++ } else {
++ //from wpa_supplicant subcmd
++ if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++ }
++
++ PRINTM(INFO, "auth alg is %#x\n", alg);
++
++ switch (alg) {
++ case AUTH_ALG_SHARED_KEY:
++ Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeShared;
++ break;
++ case AUTH_ALG_NETWORK_EAP:
++ Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeNetworkEAP;
++ break;
++ case AUTH_ALG_OPEN_SYSTEM:
++ default:
++ Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
++ break;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Set Encryption mode
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_setencryptionmode_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ int mode;
++ struct iwreq *wrq = (struct iwreq *) req;
++
++ ENTER();
++
++ if (wrq->u.data.flags == 0) {
++ //from iwpriv subcmd
++ mode = *((int *) (wrq->u.name + SUBCMD_OFFSET));
++ } else {
++ //from wpa_supplicant subcmd
++ if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++ }
++ PRINTM(INFO, "encryption mode is %#x\n", mode);
++ priv->adapter->SecInfo.EncryptionMode = mode;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get Rx antenna
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_subcmd_getrxantenna_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ int len;
++ char buf[8];
++ struct iwreq *wrq = (struct iwreq *) req;
++
++ ENTER();
++
++ PRINTM(INFO, "WLAN_SUBCMD_GETRXANTENNA\n");
++ len = GetRxAntenna(priv, buf);
++
++ wrq->u.data.length = len;
++ if (wrq->u.data.pointer) {
++ if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
++ PRINTM(INFO, "CopyToUser failed\n");
++ return -EFAULT;
++ }
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get Tx antenna
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_subcmd_gettxantenna_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ int len;
++ char buf[8];
++ struct iwreq *wrq = (struct iwreq *) req;
++
++ ENTER();
++
++ PRINTM(INFO, "WLAN_SUBCMD_GETTXANTENNA\n");
++ len = GetTxAntenna(priv, buf);
++
++ wrq->u.data.length = len;
++ if (wrq->u.data.pointer) {
++ if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
++ PRINTM(INFO, "CopyToUser failed\n");
++ return -EFAULT;
++ }
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get the MAC TSF value from the firmware
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure containing buffer
++ * space to store a TSF value retrieved from the firmware
++ *
++ * @return 0 if successful; IOCTL error code otherwise
++ */
++static int
++wlan_get_tsf_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ u64 tsfVal = 0;
++ int ret;
++
++ ENTER();
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_GET_TSF,
++ 0, HostCmd_OPTION_WAITFORRSP, 0, &tsfVal);
++
++ PRINTM(INFO, "IOCTL: Get TSF = 0x%016llx\n", tsfVal);
++
++ if (ret != WLAN_STATUS_SUCCESS) {
++ PRINTM(INFO, "IOCTL: Get TSF; Command exec failed\n");
++ ret = -EFAULT;
++ } else {
++ if (copy_to_user(wrq->u.data.pointer,
++ &tsfVal,
++ MIN(wrq->u.data.length, sizeof(tsfVal))) != 0) {
++
++ PRINTM(INFO, "IOCTL: Get TSF; Copy to user failed\n");
++ ret = -EFAULT;
++ } else {
++ ret = 0;
++ }
++ }
++
++ LEAVE();
++
++ return ret;
++}
++
++/**
++ * @brief Control WPS Session Enable/Disable
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_do_wps_session_ioctl(wlan_private * priv, struct iwreq *req)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ char buf[8];
++ struct iwreq *wrq = (struct iwreq *) req;
++
++ ENTER();
++
++ PRINTM(INFO, "WLAN_WPS_SESSION\n");
++
++ memset(buf, 0, sizeof(buf));
++ if (copy_from_user(buf, wrq->u.data.pointer,
++ MIN(sizeof(buf) - 1, wrq->u.data.length))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ if (buf[0] == 1)
++ Adapter->wps.SessionEnable = TRUE;
++ else
++ Adapter->wps.SessionEnable = FALSE;
++
++ PRINTM(INFO, "Adapter->wps.SessionEnable = %d\n",
++ Adapter->wps.SessionEnable);
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get/Set DeepSleep mode
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_deepsleep_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ char status[128];
++ struct iwreq *wrq = (struct iwreq *) req;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ PRINTM(MSG, "Cannot enter Deep Sleep mode in connected state.\n");
++ return -EINVAL;
++ }
++
++ if (*(char *) req->ifr_data == '0') {
++ PRINTM(INFO, "Exit Deep Sleep Mode.\n");
++ sprintf(status, "setting to off ");
++ SetDeepSleep(priv, FALSE);
++ } else if (*(char *) req->ifr_data == '1') {
++ PRINTM(INFO, "Enter Deep Sleep Mode.\n");
++ sprintf(status, "setting to on ");
++ SetDeepSleep(priv, TRUE);
++ } else if (*(char *) req->ifr_data == '2') {
++ PRINTM(INFO, "Get Deep Sleep Mode.\n");
++ if (Adapter->IsDeepSleep == TRUE) {
++ sprintf(status, "on ");
++ } else {
++ sprintf(status, "off ");
++ }
++ } else {
++ PRINTM(INFO, "unknown option = %d\n", *(u8 *) req->ifr_data);
++ return -EINVAL;
++ }
++
++ if (wrq->u.data.pointer) {
++ if (copy_to_user(wrq->u.data.pointer, &status, strlen(status)))
++ return -EFAULT;
++ wrq->u.data.length = strlen(status);
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Config hostsleep parameter
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_do_hostsleepcfg_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ char buf[32];
++ int ret = WLAN_STATUS_SUCCESS;
++ int gpio, gap;
++
++ memset(buf, 0, sizeof(buf));
++ if (copy_from_user(buf, wrq->u.data.pointer,
++ MIN(sizeof(buf) - 1, wrq->u.data.length))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++ buf[sizeof(buf) - 1] = 0;
++
++ if (sscanf(buf, "%x %x %x", &Adapter->HSCfg.conditions, &gpio, &gap) != 3) {
++ PRINTM(MSG, "Invalid parameters\n");
++ return -EINVAL;
++ }
++
++ if (Adapter->HSCfg.conditions != HOST_SLEEP_CFG_CANCEL) {
++ Adapter->HSCfg.gpio = (u8) gpio;
++ Adapter->HSCfg.gap = (u8) gap;
++ }
++
++ PRINTM(INFO,
++ "hostsleepcfg: cond=%#x gpio=%#x gap=%#x PSState=%d HS_Activated=%d\n",
++ Adapter->HSCfg.conditions, Adapter->HSCfg.gpio, Adapter->HSCfg.gap,
++ Adapter->PSState, Adapter->HS_Activated);
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_HOST_SLEEP_CFG,
++ 0, HostCmd_OPTION_WAITFORRSP, 0,
++ &Adapter->HSCfg);
++
++ return ret;
++}
++
++/**
++ * @brief Config Host Sleep parameters
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wreq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_hscfg_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int data[3] = { -1, 0xff, 0xff };
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (wrq->u.data.length >= 1 && wrq->u.data.length <= 3) {
++ if (copy_from_user
++ (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++ PRINTM(INFO,
++ "wlan_hscfg_ioctl: data[0]=%#08x, data[1]=%#02x, data[2]=%#02x\n",
++ data[0], data[1], data[2]);
++ } else {
++ PRINTM(MSG, "Invalid Argument\n");
++ return -EINVAL;
++ }
++
++ Adapter->HSCfg.conditions = data[0];
++ if (Adapter->HSCfg.conditions != HOST_SLEEP_CFG_CANCEL) {
++ if (wrq->u.data.length == 2) {
++ Adapter->HSCfg.gpio = (u8) data[1];
++ } else if (wrq->u.data.length == 3) {
++ Adapter->HSCfg.gpio = (u8) data[1];
++ Adapter->HSCfg.gap = (u8) data[2];
++ }
++ }
++
++ PRINTM(INFO,
++ "hscfg: cond=%#x gpio=%#x gap=%#x PSState=%d HS_Activated=%d\n",
++ Adapter->HSCfg.conditions, Adapter->HSCfg.gpio, Adapter->HSCfg.gap,
++ Adapter->PSState, Adapter->HS_Activated);
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_HOST_SLEEP_CFG,
++ 0, HostCmd_OPTION_WAITFORRSP, 0,
++ &Adapter->HSCfg);
++
++ data[0] = Adapter->HSCfg.conditions;
++ data[1] = Adapter->HSCfg.gpio;
++ data[2] = Adapter->HSCfg.gap;
++ wrq->u.data.length = 3;
++ if (copy_to_user
++ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Set Host Sleep parameters
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wreq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_hssetpara_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int data[3] = { -1, 0xff, 0xff };
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (wrq->u.data.length >= 1 && wrq->u.data.length <= 3) {
++ if (copy_from_user
++ (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++ PRINTM(INFO,
++ "wlan_hssetpara_ioctl: data[0]=%#08x, data[1]=%#02x, data[2]=%#02x\n",
++ data[0], data[1], data[2]);
++ }
++
++ Adapter->HSCfg.conditions = data[0];
++ if (Adapter->HSCfg.conditions != HOST_SLEEP_CFG_CANCEL) {
++ if (wrq->u.data.length == 2) {
++ Adapter->HSCfg.gpio = (u8) data[1];
++ } else if (wrq->u.data.length == 3) {
++ Adapter->HSCfg.gpio = (u8) data[1];
++ Adapter->HSCfg.gap = (u8) data[2];
++ }
++ }
++
++ PRINTM(INFO,
++ "hssetpara: cond=%#x gpio=%#x gap=%#x PSState=%d HS_Activated=%d\n",
++ Adapter->HSCfg.conditions, Adapter->HSCfg.gpio, Adapter->HSCfg.gap,
++ Adapter->PSState, Adapter->HS_Activated);
++
++ data[0] = Adapter->HSCfg.conditions;
++ data[1] = Adapter->HSCfg.gpio;
++ data[2] = Adapter->HSCfg.gap;
++ wrq->u.data.length = 3;
++ if (copy_to_user
++ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get/Set Cal data ext
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_do_caldata_ext_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ HostCmd_DS_802_11_CAL_DATA_EXT *pCalData = NULL;
++ int ret = WLAN_STATUS_SUCCESS;
++ u16 action;
++
++ ENTER();
++
++ if (!(pCalData = kmalloc(MAX_SETGET_CONF_CMD_LEN, GFP_KERNEL))) {
++ PRINTM(INFO, "Allocate memory failed\n");
++ ret = -ENOMEM;
++ goto calexit;
++ }
++ memset(pCalData, 0, MAX_SETGET_CONF_CMD_LEN);
++
++ if (copy_from_user(pCalData, req->ifr_data + SKIP_CMDNUM,
++ MAX_SETGET_CONF_CMD_LEN)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ kfree(pCalData);
++ ret = -EFAULT;
++ goto calexit;
++ }
++
++ action = (pCalData->Action == HostCmd_ACT_GEN_SET) ?
++ HostCmd_ACT_GEN_SET : HostCmd_ACT_GEN_GET;
++
++ HEXDUMP("Cal data ext", (u8 *) pCalData, MAX_SETGET_CONF_CMD_LEN);
++
++ PRINTM(INFO, "CalData Action = 0x%0X\n", action);
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_CAL_DATA_EXT,
++ action,
++ HostCmd_OPTION_WAITFORRSP, 0, pCalData);
++
++ if (!ret && action == HostCmd_ACT_GEN_GET) {
++ if (copy_to_user(req->ifr_data + SKIP_CMDNUM, pCalData,
++ MAX_SETGET_CONF_CMD_LEN)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ ret = -EFAULT;
++ }
++ }
++
++ kfree(pCalData);
++ calexit:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get/Set sleep period
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_sleep_period(wlan_private * priv, struct iwreq *wrq)
++{
++ int ret;
++ int data;
++ wlan_adapter *Adapter = priv->adapter;
++ HostCmd_DS_802_11_SLEEP_PERIOD sleeppd;
++
++ ENTER();
++
++ if (wrq->u.data.length > 1)
++ return -ENOTSUPP;
++
++ memset(&sleeppd, 0, sizeof(sleeppd));
++ memset(&Adapter->sleep_period, 0, sizeof(SleepPeriod));
++
++ if (wrq->u.data.length == 0) {
++ sleeppd.Action = HostCmd_ACT_GEN_GET;
++ } else {
++ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ /* sleep period is 0 or 10~60 in milliseconds */
++#define MIN_SLEEP_PERIOD 10
++#define MAX_SLEEP_PERIOD 60
++#define SLEEP_PERIOD_RESERVED_FF 0xFF
++ if ((data <= MAX_SLEEP_PERIOD && data >= MIN_SLEEP_PERIOD) ||
++ (data == 0)
++ || (data == SLEEP_PERIOD_RESERVED_FF) /* for UPSD certification tests */
++ ) {
++ sleeppd.Action = HostCmd_ACT_GEN_SET;
++ sleeppd.Period = data;
++ } else
++ return -EINVAL;
++ }
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SLEEP_PERIOD,
++ 0, HostCmd_OPTION_WAITFORRSP,
++ 0, (void *) &sleeppd);
++
++ data = (int) Adapter->sleep_period.period;
++ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = 1;
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get/Set adapt rate
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq)
++{
++ int ret;
++ wlan_adapter *Adapter = priv->adapter;
++ int data[4];
++ int rateindex;
++
++ ENTER();
++ memset(data, 0, sizeof(data));
++ if (!wrq->u.data.length) {
++ PRINTM(INFO, "Get ADAPT RATE SET\n");
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_RATE_ADAPT_RATESET,
++ HostCmd_ACT_GEN_GET,
++ HostCmd_OPTION_WAITFORRSP, 0, NULL);
++ data[0] = Adapter->HWRateDropMode;
++ data[2] = Adapter->Threshold;
++ data[3] = Adapter->FinalRate;
++ wrq->u.data.length = 4;
++ data[1] = Adapter->RateBitmap;
++ if (copy_to_user
++ (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++
++ } else {
++ PRINTM(INFO, "Set ADAPT RATE SET\n");
++ if (wrq->u.data.length > 4)
++ return -EINVAL;
++ if (copy_from_user
++ (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ if (data[0] > HW_SINGLE_RATE_DROP)
++ return -EINVAL;
++ Adapter->HWRateDropMode = data[0];
++ Adapter->Threshold = data[2];
++ Adapter->FinalRate = data[3];
++ Adapter->RateBitmap = data[1];
++ Adapter->Is_DataRate_Auto = Is_Rate_Auto(priv);
++ if (Adapter->Is_DataRate_Auto)
++ Adapter->DataRate = 0;
++ else {
++ rateindex = GetRateIndex(priv);
++ Adapter->DataRate = index_to_data_rate(rateindex);
++ }
++ PRINTM(INFO, "RateBitmap=%x,IsRateAuto=%d,DataRate=%d\n",
++ Adapter->RateBitmap, Adapter->Is_DataRate_Auto,
++ Adapter->DataRate);
++ ret =
++ PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RATE_ADAPT_RATESET,
++ HostCmd_ACT_GEN_SET,
++ HostCmd_OPTION_WAITFORRSP, 0, NULL);
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get/Set inactivity timeout
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_inactivity_timeout(wlan_private * priv, struct iwreq *wrq)
++{
++ int ret;
++ int data = 0;
++ u16 timeout = 0;
++
++ ENTER();
++ if (wrq->u.data.length > 1)
++ return -ENOTSUPP;
++
++ if (wrq->u.data.length == 0) {
++ /* Get */
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_INACTIVITY_TIMEOUT,
++ HostCmd_ACT_GET,
++ HostCmd_OPTION_WAITFORRSP, 0, &timeout);
++ data = timeout;
++ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ } else {
++ /* Set */
++ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ timeout = data;
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_INACTIVITY_TIMEOUT,
++ HostCmd_ACT_SET,
++ HostCmd_OPTION_WAITFORRSP, 0, &timeout);
++ }
++
++ wrq->u.data.length = 1;
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get LOG
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ int ret;
++ char *buf = NULL;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ PRINTM(INFO, " GET STATS\n");
++
++ if (!(buf = kmalloc(GETLOG_BUFSIZE, GFP_KERNEL))) {
++ PRINTM(INFO, "kmalloc failed!\n");
++ return -ENOMEM;
++ }
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_GET_LOG,
++ 0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
++
++ if (!ret && wrq->u.data.pointer) {
++ sprintf(buf, "\n"
++ "mcasttxframe %u\n"
++ "failed %u\n"
++ "retry %u\n"
++ "multiretry %u\n"
++ "framedup %u\n"
++ "rtssuccess %u\n"
++ "rtsfailure %u\n"
++ "ackfailure %u\n"
++ "rxfrag %u\n"
++ "mcastrxframe %u\n"
++ "fcserror %u\n"
++ "txframe %u\n",
++ Adapter->LogMsg.mcasttxframe,
++ Adapter->LogMsg.failed,
++ Adapter->LogMsg.retry,
++ Adapter->LogMsg.multiretry,
++ Adapter->LogMsg.framedup,
++ Adapter->LogMsg.rtssuccess,
++ Adapter->LogMsg.rtsfailure,
++ Adapter->LogMsg.ackfailure,
++ Adapter->LogMsg.rxfrag,
++ Adapter->LogMsg.mcastrxframe,
++ Adapter->LogMsg.fcserror, Adapter->LogMsg.txframe);
++
++ wrq->u.data.length = strlen(buf) + 1;
++ if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ ret = -EFAULT;
++ }
++ }
++
++ kfree(buf);
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief config sleep parameters
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_sleep_params_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ int ret;
++ wlan_adapter *Adapter = priv->adapter;
++ wlan_ioctl_sleep_params_config sp;
++
++ ENTER();
++
++ memset(&sp, 0, sizeof(sp));
++
++ if (!wrq->u.data.pointer)
++ return -EFAULT;
++ if (copy_from_user(&sp, wrq->u.data.pointer,
++ MIN(sizeof(sp), wrq->u.data.length))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ memcpy(&Adapter->sp, &sp.Error, sizeof(SleepParams));
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SLEEP_PARAMS,
++ sp.Action, HostCmd_OPTION_WAITFORRSP,
++ 0, NULL);
++
++ if (!ret && !sp.Action) {
++ memcpy(&sp.Error, &Adapter->sp, sizeof(SleepParams));
++ if (copy_to_user(wrq->u.data.pointer, &sp, sizeof(sp))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = sizeof(sp);
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Read the CIS Table
++ * @param priv A pointer to wlan_private structure
++ * @param req A pointer to ifreq structure
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_do_getcis_ioctl(wlan_private * priv, struct ifreq *req)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ struct iwreq *wrq = (struct iwreq *) req;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (wrq->u.data.pointer) {
++ if (copy_to_user(wrq->u.data.pointer, Adapter->CisInfoBuf,
++ Adapter->CisInfoLen)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = Adapter->CisInfoLen;
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Set BCA timeshare
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to user data
++ * @return WLAN_STATUS_SUCCESS--success, otherwise fail
++ */
++static int
++wlan_bca_timeshare_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ int ret;
++ wlan_adapter *Adapter = priv->adapter;
++ wlan_ioctl_bca_timeshare_config bca_ts;
++
++ ENTER();
++
++ memset(&bca_ts, 0, sizeof(HostCmd_DS_802_11_BCA_TIMESHARE));
++
++ if (!wrq->u.data.pointer)
++ return -EFAULT;
++ if (copy_from_user(&bca_ts, wrq->u.data.pointer,
++ MIN(sizeof(bca_ts), wrq->u.data.length))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ PRINTM(INFO, "TrafficType=%x TimeShareInterva=%x BTTime=%x\n",
++ bca_ts.TrafficType, bca_ts.TimeShareInterval, bca_ts.BTTime);
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE,
++ bca_ts.Action, HostCmd_OPTION_WAITFORRSP,
++ 0, &bca_ts);
++
++ if (!ret && !bca_ts.Action) {
++ if (copy_to_user(wrq->u.data.pointer, &Adapter->bca_ts,
++ sizeof(bca_ts))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = sizeof(HostCmd_DS_802_11_BCA_TIMESHARE);
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Set scan type
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to user data
++ * @return WLAN_STATUS_SUCCESS--success, otherwise fail
++ */
++static int
++wlan_scan_type_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ u8 buf[12];
++ u8 *option[] = { "active", "passive", "get", };
++ int i, max_options = (sizeof(option) / sizeof(option[0]));
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (wlan_get_state_11d(priv) == ENABLE_11D) {
++ PRINTM(INFO, "11D: Cannot set scantype when 11D enabled\n");
++ return -EFAULT;
++ }
++
++ memset(buf, 0, sizeof(buf));
++
++ if (copy_from_user(buf, wrq->u.data.pointer, MIN(sizeof(buf),
++ wrq->u.data.length))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ PRINTM(INFO, "Scan Type Option = %s\n", buf);
++
++ buf[sizeof(buf) - 1] = '\0';
++
++ for (i = 0; i < max_options; i++) {
++ if (!strcmp(buf, option[i]))
++ break;
++ }
++
++ switch (i) {
++ case 0:
++ Adapter->ScanType = HostCmd_SCAN_TYPE_ACTIVE;
++
++ break;
++ case 1:
++ Adapter->ScanType = HostCmd_SCAN_TYPE_PASSIVE;
++ break;
++ case 2:
++ wrq->u.data.length = strlen(option[Adapter->ScanType]) + 1;
++
++ if (copy_to_user(wrq->u.data.pointer,
++ option[Adapter->ScanType], wrq->u.data.length)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ ret = -EFAULT;
++ }
++
++ break;
++ default:
++ PRINTM(INFO, "Invalid Scan Type Ioctl Option\n");
++ ret = -EINVAL;
++ break;
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Set scan mode
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to user data
++ * @return WLAN_STATUS_SUCCESS--success, otherwise fail
++ */
++static int
++wlan_scan_mode_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ u8 buf[12];
++ u8 *option[] = { "bss", "ibss", "any", "get" };
++ int i, max_options = (sizeof(option) / sizeof(option[0]));
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ memset(buf, 0, sizeof(buf));
++
++ if (copy_from_user(buf, wrq->u.data.pointer, MIN(sizeof(buf),
++ wrq->u.data.length))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ PRINTM(INFO, "Scan Mode Option = %s\n", buf);
++
++ buf[sizeof(buf) - 1] = '\0';
++
++ for (i = 0; i < max_options; i++) {
++ if (!strcmp(buf, option[i]))
++ break;
++ }
++
++ switch (i) {
++
++ case 0:
++ Adapter->ScanMode = HostCmd_BSS_TYPE_BSS;
++ break;
++ case 1:
++ Adapter->ScanMode = HostCmd_BSS_TYPE_IBSS;
++ break;
++ case 2:
++ Adapter->ScanMode = HostCmd_BSS_TYPE_ANY;
++ break;
++ case 3:
++
++ wrq->u.data.length = strlen(option[Adapter->ScanMode - 1]) + 1;
++
++ PRINTM(INFO, "Get Scan Mode Option = %s\n",
++ option[Adapter->ScanMode - 1]);
++
++ PRINTM(INFO, "Scan Mode Length %d\n", wrq->u.data.length);
++
++ if (copy_to_user(wrq->u.data.pointer,
++ option[Adapter->ScanMode - 1], wrq->u.data.length)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ ret = -EFAULT;
++ }
++ PRINTM(INFO, "GET Scan Type Option after copy = %s\n",
++ (char *) wrq->u.data.pointer);
++
++ break;
++
++ default:
++ PRINTM(INFO, "Invalid Scan Mode Ioctl Option\n");
++ ret = -EINVAL;
++ break;
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get/Set Adhoc G Rate
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to user data
++ * @return WLAN_STATUS_SUCCESS--success, otherwise fail
++ */
++static int
++wlan_do_set_grate_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int data, data1;
++ int *val;
++
++ ENTER();
++
++ data1 = *((int *) (wrq->u.name + SUBCMD_OFFSET));
++ switch (data1) {
++ case 0:
++ Adapter->adhoc_grate_enabled = FALSE;
++ break;
++ case 1:
++ Adapter->adhoc_grate_enabled = TRUE;
++ break;
++ case 2:
++ break;
++ default:
++ return -EINVAL;
++ }
++ data = Adapter->adhoc_grate_enabled;
++ val = (int *) wrq->u.name;
++ *val = data;
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get/Set Firmware wakeup method
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to user data
++ * @return WLAN_STATUS_SUCCESS--success, otherwise fail
++ */
++static int
++wlan_cmd_fw_wakeup_method(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ u16 action;
++ u16 method;
++ int ret;
++ int data;
++
++ ENTER();
++
++ if (wrq->u.data.length == 0 || !wrq->u.data.pointer) {
++ action = HostCmd_ACT_GET;
++ method = Adapter->fwWakeupMethod;
++ } else {
++ action = HostCmd_ACT_SET;
++ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ switch (data) {
++ case 0:
++ method = WAKEUP_FW_UNCHANGED;
++ break;
++ case 1:
++ method = WAKEUP_FW_THRU_INTERFACE;
++ break;
++ case 2:
++ method = WAKEUP_FW_THRU_GPIO;
++ break;
++ default:
++ return -EINVAL;
++ }
++ }
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_FW_WAKE_METHOD, action,
++ HostCmd_OPTION_WAITFORRSP, 0, &method);
++
++ if (action == HostCmd_ACT_GET) {
++ method = Adapter->fwWakeupMethod;
++ if (copy_to_user(wrq->u.data.pointer, &method, sizeof(method))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = 1;
++ }
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get/Set Auto Deep Sleep mode
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to user data
++ * @return WLAN_STATUS_SUCCESS--success, otherwise fail
++ */
++static int
++wlan_auto_deep_sleep(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int data;
++
++ ENTER();
++
++ if (wrq->u.data.length > 0 && wrq->u.data.pointer) {
++ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ switch (data) {
++ case 0:
++ if (Adapter->IsAutoDeepSleepEnabled) {
++ Adapter->IsAutoDeepSleepEnabled = FALSE;
++ /* Try to exit DS if auto DS disabled */
++ SetDeepSleep(priv, FALSE);
++ }
++ break;
++ case 1:
++ if (!Adapter->IsAutoDeepSleepEnabled) {
++ Adapter->IsAutoDeepSleepEnabled = TRUE;
++ /* Wakeup main thread to enter DS if auto DS enabled */
++ wake_up_interruptible(&priv->MainThread.waitQ);
++ }
++ break;
++ default:
++ return -EINVAL;
++ }
++ }
++
++ data = Adapter->IsAutoDeepSleepEnabled;
++ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(data))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = 1;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get the CFP table based on the region code
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ *
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_get_cfp_table_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ pwlan_ioctl_cfp_table ioctl_cfp;
++ CHANNEL_FREQ_POWER *cfp;
++ int cfp_no;
++ int regioncode;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (wrq->u.data.length == 0 || !wrq->u.data.pointer) {
++ ret = -EINVAL;
++ goto cfpexit;
++ }
++
++ ioctl_cfp = (pwlan_ioctl_cfp_table) wrq->u.data.pointer;
++
++ if (copy_from_user(&regioncode, &ioctl_cfp->region, sizeof(int))) {
++ PRINTM(INFO, "Get CFP table: copy from user failed\n");
++ ret = -EFAULT;
++ goto cfpexit;
++ }
++
++ if (!regioncode)
++ regioncode = Adapter->RegionCode;
++
++ cfp =
++ wlan_get_region_cfp_table((u8) regioncode, BAND_G | BAND_B, &cfp_no);
++
++ if (cfp == NULL) {
++ PRINTM(MSG, "No related CFP table found, region code = 0x%x\n",
++ regioncode);
++ ret = -EFAULT;
++ goto cfpexit;
++ }
++
++ if (copy_to_user(&ioctl_cfp->cfp_no, &cfp_no, sizeof(int))) {
++ PRINTM(INFO, "Get CFP table: copy to user failed\n");
++ ret = -EFAULT;
++ goto cfpexit;
++ }
++
++ if (copy_to_user
++ (ioctl_cfp->cfp, cfp, sizeof(CHANNEL_FREQ_POWER) * cfp_no)) {
++ PRINTM(INFO, "Get CFP table: copy to user failed\n");
++ ret = -EFAULT;
++ goto cfpexit;
++ }
++
++ wrq->u.data.length =
++ sizeof(int) * 2 + sizeof(CHANNEL_FREQ_POWER) * cfp_no;
++
++ cfpexit:
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Retrieve transmit packet statistics from the firmware
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param wrq A pointer to iwreq structure
++ *
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_tx_pkt_stats_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ HostCmd_DS_TX_PKT_STATS txPktStats;
++ int ret;
++
++ ENTER();
++
++ if (wrq->u.data.length == 0 || !wrq->u.data.pointer) {
++ LEAVE();
++ return -EINVAL;
++ }
++
++ if (wrq->u.data.length < sizeof(txPktStats)) {
++ LEAVE();
++ return -E2BIG;
++ }
++
++ memset(&txPktStats, 0x00, sizeof(txPktStats));
++
++ if ((ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_TX_PKT_STATS, 0,
++ HostCmd_OPTION_WAITFORRSP,
++ 0, &txPktStats))) {
++ LEAVE();
++ return ret;
++ }
++
++ if (copy_to_user(wrq->u.data.pointer,
++ (u8 *) & txPktStats, sizeof(txPktStats))) {
++ PRINTM(INFO, "TxPktStats: copy to user failed\n");
++ return -EFAULT;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/********************************************************
++ Global Functions
++********************************************************/
++/**
++ * @brief ioctl function - entry point
++ *
++ * @param dev A pointer to net_device structure
++ * @param req A pointer to ifreq structure
++ * @param cmd command
++ * @return WLAN_STATUS_SUCCESS--success, otherwise fail
++ */
++int
++wlan_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
++{
++ int subcmd = 0;
++ int idata = 0;
++ int *pdata;
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ struct iwreq *wrq = (struct iwreq *) req;
++
++ ENTER();
++
++ if (Adapter->bHostSleepConfigured) {
++ BOOLEAN cmd_allowed = FALSE;
++ int count = sizeof(Commands_Allowed_In_HostSleep)
++ / sizeof(Commands_Allowed_In_HostSleep[0]);
++
++ if (cmd == WLANHOSTSLEEPCFG) {
++ char buf[32];
++ u32 cond;
++
++ memset(buf, 0, sizeof(buf));
++ if (copy_from_user(buf, wrq->u.data.pointer,
++ MIN(sizeof(buf) - 1, wrq->u.data.length))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++ buf[sizeof(buf) - 1] = 0;
++ sscanf(buf, "%x ", &cond);
++ if (cond == HOST_SLEEP_CFG_CANCEL) {
++ cmd_allowed = TRUE;
++ if (Adapter->IsDeepSleep) {
++ SetDeepSleep(priv, FALSE);
++ }
++ }
++ } else if (cmd == WLAN_SET_GET_SIXTEEN_INT &&
++ ((int) wrq->u.data.flags == WLANHSCFG)) {
++ u32 cond;
++ if (copy_from_user(&cond, wrq->u.data.pointer, sizeof(cond))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ if (cond == HOST_SLEEP_CFG_CANCEL) {
++ cmd_allowed = TRUE;
++ if (Adapter->IsDeepSleep) {
++ SetDeepSleep(priv, FALSE);
++ }
++ }
++ } else
++ if (Is_Command_Allowed_In_Sleep
++ (req, cmd, Commands_Allowed_In_HostSleep, count)) {
++ cmd_allowed = TRUE;
++ }
++ if (!cmd_allowed) {
++ PRINTM(MSG, "%s IOCTLS called when WLAN access is blocked\n",
++ __FUNCTION__);
++ return -EBUSY;
++ }
++ }
++
++ if (!Adapter->IsAutoDeepSleepEnabled) {
++ if (Adapter->IsDeepSleep) {
++ int count = sizeof(Commands_Allowed_In_DeepSleep)
++ / sizeof(Commands_Allowed_In_DeepSleep[0]);
++
++ if (!Is_Command_Allowed_In_Sleep
++ (req, cmd, Commands_Allowed_In_DeepSleep, count)) {
++ PRINTM(MSG,
++ "():%s IOCTLS called when station is"
++ " in DeepSleep\n", __FUNCTION__);
++ return -EBUSY;
++ }
++ }
++ } else if (cmd == WLANDEEPSLEEP) {
++ PRINTM(MSG,
++ "DeepSleep command is not allowed in AutoDeepSleep mode\n");
++ return -EBUSY;
++ }
++
++ PRINTM(INFO, "wlan_do_ioctl: ioctl cmd = 0x%x\n", cmd);
++ switch (cmd) {
++ case WLANEXTSCAN:
++ ret = wlan_extscan_ioctl(priv, req);
++ break;
++ case WLANHOSTCMD:
++ ret = wlan_hostcmd_ioctl(dev, req, cmd);
++ break;
++ case WLANARPFILTER:
++ ret = wlan_arpfilter_ioctl(dev, req, cmd);
++ break;
++
++ case WLANCISDUMP: /* Read CIS Table */
++ ret = wlan_do_getcis_ioctl(priv, req);
++ break;
++
++ case WLANSCAN_TYPE:
++ PRINTM(INFO, "Scan Type Ioctl\n");
++ ret = wlan_scan_type_ioctl(priv, wrq);
++ break;
++
++#ifdef MFG_CMD_SUPPORT
++ case WLANMANFCMD:
++ PRINTM(INFO, "Entering the Manufacturing ioctl SIOCCFMFG\n");
++ ret = wlan_mfg_command(priv, wrq);
++
++ PRINTM(INFO, "Manufacturing Ioctl %s\n",
++ (ret) ? "failed" : "success");
++ break;
++#endif
++
++ case WLANREGRDWR: /* Register read write command */
++ ret = wlan_regrdwr_ioctl(priv, req);
++ break;
++
++ case WLANCMD52RDWR: /* CMD52 read/write command */
++ ret = wlan_cmd52rdwr_ioctl(priv, req);
++ break;
++
++ case WLANCMD53RDWR: /* CMD53 read/write command */
++ ret = wlan_cmd53rdwr_ioctl(priv, req);
++ break;
++
++ case SIOCSIWENCODE: /* set encoding token & mode for WPA */
++ ret = wlan_set_encode(dev, NULL, &(wrq->u.data), wrq->u.data.pointer);
++ break;
++ case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */
++ switch (wrq->u.data.flags) {
++ case WLANDEAUTH:
++ PRINTM(INFO, "Deauth\n");
++ if (Adapter->InfrastructureMode == Wlan802_11Infrastructure &&
++ Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ SendDeauthentication(priv);
++ } else if (Adapter->InfrastructureMode == Wlan802_11IBSS &&
++ Adapter->MediaConnectStatus ==
++ WlanMediaStateConnected) {
++ StopAdhocNetwork(priv);
++ }
++ break;
++
++ case WLANADHOCSTOP:
++ PRINTM(INFO, "Adhoc stop\n");
++ ret = wlan_do_adhocstop_ioctl(priv);
++ break;
++
++ case WLANRADIOON:
++ wlan_radio_ioctl(priv, RADIO_ON);
++ break;
++
++ case WLANRADIOOFF:
++ ret = wlan_radio_ioctl(priv, RADIO_OFF);
++ break;
++ case WLANREMOVEADHOCAES:
++ ret = wlan_remove_aes(priv);
++ break;
++#ifdef REASSOCIATION
++ case WLANREASSOCIATIONAUTO:
++ reassociation_on(priv);
++ break;
++ case WLANREASSOCIATIONUSER:
++ reassociation_off(priv);
++ break;
++#endif /* REASSOCIATION */
++ case WLANWLANIDLEON:
++ wlanidle_on(priv);
++ break;
++ case WLANWLANIDLEOFF:
++ wlanidle_off(priv);
++ break;
++ } /* End of switch */
++ break;
++
++ case WLAN_SETWORDCHAR_GETNONE:
++ switch (wrq->u.data.flags) {
++ case WLANSETADHOCAES:
++ ret = wlan_setadhocaes_ioctl(priv, req);
++ break;
++ }
++ break;
++
++ case WLAN_SETONEINT_GETWORDCHAR:
++ switch (wrq->u.data.flags) {
++ case WLANGETADHOCAES:
++ ret = wlan_getadhocaes_ioctl(priv, req);
++ break;
++ case WLANVERSION: /* Get driver version */
++ ret = wlan_version_ioctl(priv, req);
++ break;
++ case WLANVEREXT:
++ ret = wlan_verext_ioctl(priv, wrq);
++ break;
++ }
++ break;
++
++ case WLANSETWPAIE:
++ ret = wlan_set_wpa_ie_ioctl(priv, req);
++ break;
++ case WLAN_SETINT_GETINT:
++ /* The first 4 bytes of req->ifr_data is sub-ioctl number
++ * after 4 bytes sits the payload.
++ */
++ subcmd = (int) req->ifr_data; //from iwpriv subcmd
++ switch (subcmd) {
++ case WLANNF:
++ ret = wlan_get_nf(priv, wrq);
++ break;
++ case WLANRSSI:
++ ret = wlan_get_rssi(priv, wrq);
++ break;
++ case WLANBGSCAN:
++ {
++ int data, data1;
++ int *val;
++ data1 = *((int *) (wrq->u.name + SUBCMD_OFFSET));
++ switch (data1) {
++ case CMD_DISABLED:
++ PRINTM(INFO, "Background scan is set to disable\n");
++ ret = wlan_bg_scan_enable(priv, FALSE);
++ val = (int *) wrq->u.name;
++ *val = data1;
++ break;
++ case CMD_ENABLED:
++ PRINTM(INFO, "Background scan is set to enable\n");
++ ret = wlan_bg_scan_enable(priv, TRUE);
++ val = (int *) wrq->u.name;
++ *val = data1;
++ break;
++ case CMD_GET:
++ data = (Adapter->bgScanConfig->Enable == TRUE) ?
++ CMD_ENABLED : CMD_DISABLED;
++ val = (int *) wrq->u.name;
++ *val = data;
++ break;
++ default:
++ ret = -EINVAL;
++ PRINTM(INFO, "Background scan: wrong parameter\n");
++ break;
++ }
++ }
++ break;
++ case WLANENABLE11D:
++ ret = wlan_cmd_enable_11d(priv, wrq);
++ break;
++ case WLANADHOCGRATE:
++ ret = wlan_do_set_grate_ioctl(priv, wrq);
++ break;
++ case WLANSDIOCLOCK:
++ {
++ int data;
++ int *val;
++ data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
++ switch (data) {
++ case CMD_DISABLED:
++ PRINTM(INFO, "SDIO clock is turned off\n");
++ ret = sbi_set_bus_clock(priv, FALSE);
++ break;
++ case CMD_ENABLED:
++ PRINTM(INFO, "SDIO clock is turned on\n");
++ ret = sbi_set_bus_clock(priv, TRUE);
++ break;
++ case CMD_GET: /* need an API in sdio.c to get STRPCL */
++ default:
++ ret = -EINVAL;
++ PRINTM(INFO, "sdioclock: wrong parameter\n");
++ break;
++ }
++ val = (int *) wrq->u.name;
++ *val = data;
++ }
++ break;
++ case WLANWMM_ENABLE:
++ ret = wlan_wmm_enable_ioctl(priv, wrq);
++ break;
++ case WLANNULLGEN:
++ ret = wlan_null_pkg_gen(priv, wrq);
++ /* enable/disable null pkg generation */
++ break;
++ case WLANADHOCCSET:
++ ret = wlan_set_coalescing_ioctl(priv, wrq);
++ break;
++ case WLAN_ADHOC_G_PROT:
++ ret = wlan_adhoc_g_protection(priv, wrq);
++ break;
++
++ }
++ break;
++
++ case WLAN_SETONEINT_GETONEINT:
++ switch (wrq->u.data.flags) {
++
++ case WLAN_WMM_QOSINFO:
++ {
++ int data;
++ if (wrq->u.data.length == 1) {
++ if (copy_from_user
++ (&data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++ Adapter->wmm.qosinfo = (u8) data;
++ } else {
++ data = (int) Adapter->wmm.qosinfo;
++ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ wrq->u.data.length = 1;
++ }
++ }
++ break;
++ case WLAN_LISTENINTRVL:
++ if (!wrq->u.data.length) {
++ int data;
++ PRINTM(INFO, "Get LocalListenInterval Value\n");
++#define GET_ONE_INT 1
++ data = Adapter->LocalListenInterval;
++ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++
++ wrq->u.data.length = GET_ONE_INT;
++ } else {
++ int data;
++ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ PRINTM(INFO, "Set LocalListenInterval = %d\n", data);
++#define MAX_U16_VAL 65535
++ if (data > MAX_U16_VAL) {
++ PRINTM(INFO, "Exceeds U16 value\n");
++ return -EINVAL;
++ }
++ Adapter->LocalListenInterval = data;
++ }
++ break;
++ case WLAN_FW_WAKEUP_METHOD:
++ ret = wlan_cmd_fw_wakeup_method(priv, wrq);
++ break;
++ case WLAN_NULLPKTINTERVAL:
++ ret = wlan_null_pkt_interval(priv, wrq);
++ break;
++ case WLAN_BCN_MISS_TIMEOUT:
++ ret = wlan_bcn_miss_timeout(priv, wrq);
++ break;
++ case WLAN_ADHOC_AWAKE_PERIOD:
++ ret = wlan_adhoc_awake_period(priv, wrq);
++ break;
++ case WLAN_LDO:
++ ret = wlan_ldo_config(priv, wrq);
++ break;
++ case WLAN_SDIO_MODE:
++ ret = wlan_sdio_mode(priv, wrq);
++ break;
++ case WLAN_RTS_CTS_CTRL:
++ ret = wlan_rts_cts_ctrl(priv, wrq);
++ break;
++ case WLAN_AUTODEEPSLEEP:
++ ret = wlan_auto_deep_sleep(priv, wrq);
++ break;
++ case WLAN_WAKEUP_MT:
++ if (wrq->u.data.length > 0)
++ Adapter->IntCounter++;
++ wake_up_interruptible(&priv->MainThread.waitQ);
++ break;
++ default:
++ ret = -EOPNOTSUPP;
++ break;
++ }
++ break;
++
++ case WLAN_SETONEINT_GETNONE:
++ /* The first 4 bytes of req->ifr_data is sub-ioctl number
++ * after 4 bytes sits the payload.
++ */
++ subcmd = wrq->u.data.flags; //from wpa_supplicant subcmd
++
++ if (!subcmd)
++ subcmd = (int) req->ifr_data; //from iwpriv subcmd
++
++ idata = *((int *) (wrq->u.name + SUBCMD_OFFSET));
++
++ switch (subcmd) {
++ case WLAN_SUBCMD_SETRXANTENNA: /* SETRXANTENNA */
++ ret = SetRxAntenna(priv, idata);
++ break;
++ case WLAN_SUBCMD_SETTXANTENNA: /* SETTXANTENNA */
++ ret = SetTxAntenna(priv, idata);
++ break;
++
++ case WLANSETBCNAVG:
++ if (idata == 0)
++ Adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
++ else if (idata > MAX_BCN_AVG_FACTOR || idata < MIN_BCN_AVG_FACTOR) {
++ PRINTM(MSG, "The value '%u' is out of the range (0-%u).\n",
++ idata, MAX_BCN_AVG_FACTOR);
++ return -EINVAL;
++ } else
++ Adapter->bcn_avg_factor = idata;
++ break;
++ case WLANSETDATAAVG:
++ if (idata == 0)
++ Adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
++ else if (idata > MAX_DATA_AVG_FACTOR
++ || idata < MIN_DATA_AVG_FACTOR) {
++ PRINTM(MSG, "The value '%u' is out of the range (0-%u).\n",
++ idata, MAX_DATA_AVG_FACTOR);
++ return -EINVAL;
++ } else
++ Adapter->data_avg_factor = idata;
++ memset(Adapter->rawSNR, 0x00, sizeof(Adapter->rawSNR));
++ memset(Adapter->rawNF, 0x00, sizeof(Adapter->rawNF));
++ Adapter->nextSNRNF = 0;
++ Adapter->numSNRNF = 0;
++ break;
++ case WLANASSOCIATE:
++ ret = wlan_associate_to_table_idx(priv, idata);
++ break;
++
++ case WLANSETREGION:
++ ret = wlan_set_region(priv, (u16) idata);
++ break;
++
++ case WLAN_SET_LISTEN_INTERVAL:
++ Adapter->ListenInterval = (u16) idata;
++ break;
++
++ case WLAN_SET_MULTIPLE_DTIM:
++ ret = wlan_set_multiple_dtim_ioctl(priv, req);
++ break;
++
++ case WLANSETAUTHALG:
++ ret = wlan_setauthalg_ioctl(priv, req);
++ break;
++
++ case WLANSETENCRYPTIONMODE:
++ ret = wlan_setencryptionmode_ioctl(priv, req);
++ break;
++
++ default:
++ ret = -EOPNOTSUPP;
++ break;
++ }
++
++ break;
++
++ case WLAN_SETNONE_GETTWELVE_CHAR: /* Get Antenna settings */
++ /*
++ * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is
++ * in flags of iwreq structure, otherwise it will be in
++ * mode member of iwreq structure.
++ */
++ switch ((int) wrq->u.data.flags) {
++ case WLAN_SUBCMD_GETRXANTENNA: /* Get Rx Antenna */
++ ret = wlan_subcmd_getrxantenna_ioctl(priv, req);
++ break;
++
++ case WLAN_SUBCMD_GETTXANTENNA: /* Get Tx Antenna */
++ ret = wlan_subcmd_gettxantenna_ioctl(priv, req);
++ break;
++
++ case WLAN_GET_TSF:
++ ret = wlan_get_tsf_ioctl(priv, wrq);
++ break;
++
++ case WLAN_WPS_SESSION:
++ ret = wlan_do_wps_session_ioctl(priv, wrq);
++ break;
++ }
++ break;
++
++ case WLANDEEPSLEEP:
++ ret = wlan_deepsleep_ioctl(priv, req);
++ break;
++
++ case WLANHOSTSLEEPCFG:
++ ret = wlan_do_hostsleepcfg_ioctl(priv, wrq);
++ break;
++
++ case WLAN_SET64CHAR_GET64CHAR:
++ switch ((int) wrq->u.data.flags) {
++
++ case WLANSLEEPPARAMS:
++ ret = wlan_sleep_params_ioctl(priv, wrq);
++ break;
++
++ case WLAN_BCA_TIMESHARE:
++ ret = wlan_bca_timeshare_ioctl(priv, wrq);
++ break;
++ case WLANSCAN_MODE:
++ PRINTM(INFO, "Scan Mode Ioctl\n");
++ ret = wlan_scan_mode_ioctl(priv, wrq);
++ break;
++
++ case WLAN_GET_ADHOC_STATUS:
++ ret = wlan_get_adhoc_status_ioctl(priv, wrq);
++ break;
++ case WLAN_SET_GEN_IE:
++ ret = wlan_set_gen_ie_ioctl(priv, wrq);
++ break;
++ case WLAN_GET_GEN_IE:
++ ret = wlan_get_gen_ie_ioctl(priv, wrq);
++ break;
++ case WLAN_WMM_QUEUE_STATUS:
++ ret = wlan_wmm_queue_status_ioctl(priv, wrq);
++ break;
++ }
++ break;
++
++ case WLAN_SETCONF_GETCONF:
++ PRINTM(INFO, "The WLAN_SETCONF_GETCONF=0x%x is %d\n",
++ WLAN_SETCONF_GETCONF, *(u8 *) req->ifr_data);
++ switch (*(u8 *) req->ifr_data) {
++ case CAL_DATA_EXT_CONFIG:
++ ret = wlan_do_caldata_ext_ioctl(priv, req);
++ break;
++ case BG_SCAN_CONFIG:
++ ret = wlan_do_bg_scan_config_ioctl(priv, req);
++ break;
++ }
++ break;
++
++ case WLAN_SETNONE_GETONEINT:
++ switch ((int) req->ifr_data) {
++ case WLANGETBCNAVG:
++ pdata = (int *) wrq->u.name;
++ *pdata = (int) Adapter->bcn_avg_factor;
++ break;
++
++ case WLANGETDATAAVG:
++ pdata = (int *) wrq->u.name;
++ *pdata = (int) Adapter->data_avg_factor;
++ break;
++
++ case WLANGETREGION:
++ pdata = (int *) wrq->u.name;
++ *pdata = (int) Adapter->RegionCode;
++ break;
++
++ case WLAN_GET_LISTEN_INTERVAL:
++ pdata = (int *) wrq->u.name;
++ *pdata = (int) Adapter->ListenInterval;
++ break;
++
++ case WLAN_GET_MULTIPLE_DTIM:
++ pdata = (int *) wrq->u.name;
++ *pdata = (int) Adapter->MultipleDtim;
++ break;
++ case WLAN_GET_TX_RATE:
++ ret = wlan_get_txrate_ioctl(priv, req);
++ break;
++ case WLANGETDTIM:
++ ret = wlan_get_dtim_ioctl(priv, req);
++ break;
++ default:
++ ret = -EOPNOTSUPP;
++
++ }
++
++ break;
++
++ case WLANGETLOG:
++ ret = wlan_do_getlog_ioctl(priv, wrq);
++ break;
++
++ case WLAN_SET_GET_SIXTEEN_INT:
++ switch ((int) wrq->u.data.flags) {
++ case WLAN_TPCCFG:
++ {
++ int data[5];
++ HostCmd_DS_802_11_TPC_CFG cfg;
++ memset(&cfg, 0, sizeof(cfg));
++ if ((wrq->u.data.length > 1) && (wrq->u.data.length != 5))
++ return WLAN_STATUS_FAILURE;
++
++ if (wrq->u.data.length == 0) {
++ cfg.Action = HostCmd_ACT_GEN_GET;
++ } else {
++ if (copy_from_user(data,
++ wrq->u.data.pointer,
++ sizeof(int) * 5)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ cfg.Action = HostCmd_ACT_GEN_SET;
++ cfg.Enable = data[0];
++ cfg.UseSNR = data[1];
++#define TPC_DATA_NO_CHANG 0x7f
++ if (wrq->u.data.length == 1) {
++ cfg.P0 = TPC_DATA_NO_CHANG;
++ cfg.P1 = TPC_DATA_NO_CHANG;
++ cfg.P2 = TPC_DATA_NO_CHANG;
++ } else {
++ cfg.P0 = data[2];
++ cfg.P1 = data[3];
++ cfg.P2 = data[4];
++ }
++ }
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_TPC_CFG, 0,
++ HostCmd_OPTION_WAITFORRSP, 0,
++ (void *) &cfg);
++
++ data[0] = cfg.Enable;
++ data[1] = cfg.UseSNR;
++ data[2] = cfg.P0;
++ data[3] = cfg.P1;
++ data[4] = cfg.P2;
++ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 5)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++
++ wrq->u.data.length = 5;
++ }
++ break;
++
++ case WLAN_SCANPROBES:
++ {
++ int data;
++ if (wrq->u.data.length > 0) {
++ if (copy_from_user
++ (&data, wrq->u.data.pointer, sizeof(int))) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ Adapter->ScanProbes = data;
++ } else {
++ data = Adapter->ScanProbes;
++ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++ }
++ wrq->u.data.length = 1;
++ }
++ break;
++ case WLAN_LED_GPIO_CTRL:
++ {
++ int i;
++ int data[MAX_LEDS * 2];
++ HostCmd_DS_802_11_LED_CTRL ctrl;
++ MrvlIEtypes_LedGpio_t *gpio;
++
++ gpio = (MrvlIEtypes_LedGpio_t *) & ctrl.LedGpio;
++
++ if ((wrq->u.data.length > MAX_LEDS * 2) ||
++ (wrq->u.data.length % 2) != 0) {
++ PRINTM(MSG, "invalid ledgpio parameters\n");
++ return -EINVAL;
++ }
++
++ memset(&ctrl, 0, sizeof(ctrl));
++ if (wrq->u.data.length == 0) {
++ ctrl.Action = HostCmd_ACT_GEN_GET;
++ } else {
++ if (copy_from_user(data, wrq->u.data.pointer,
++ sizeof(int) * wrq->u.data.length)) {
++ PRINTM(INFO, "Copy from user failed\n");
++ return -EFAULT;
++ }
++
++ ctrl.Action = HostCmd_ACT_GEN_SET;
++ ctrl.LedNums = 0;
++ gpio->Header.Type = TLV_TYPE_LED_GPIO;
++ gpio->Header.Len = wrq->u.data.length;
++ for (i = 0; i < wrq->u.data.length; i += 2) {
++ gpio->LedGpio[i / 2].LedNum = data[i];
++ gpio->LedGpio[i / 2].GpioNum = data[i + 1];
++ }
++ }
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_LED_CONTROL, 0,
++ HostCmd_OPTION_WAITFORRSP,
++ 0, (void *) &ctrl);
++
++ for (i = 0; i < gpio->Header.Len; i += 2) {
++ data[i] = gpio->LedGpio[i / 2].LedNum;
++ data[i + 1] = gpio->LedGpio[i / 2].GpioNum;
++ }
++ if (copy_to_user(wrq->u.data.pointer, data,
++ sizeof(int) * gpio->Header.Len)) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++
++ wrq->u.data.length = gpio->Header.Len;
++ }
++ break;
++ case WLAN_SLEEP_PERIOD:
++ ret = wlan_sleep_period(priv, wrq);
++ break;
++ case WLAN_ADAPT_RATESET:
++ ret = wlan_adapt_rateset(priv, wrq);
++ break;
++ case WLAN_INACTIVITY_TIMEOUT:
++ ret = wlan_inactivity_timeout(priv, wrq);
++ break;
++ case WLANSNR:
++ ret = wlan_get_snr(priv, wrq);
++ break;
++ case WLAN_GET_RATE:
++ ret = wlan_getrate_ioctl(priv, wrq);
++ break;
++ case WLAN_GET_RXINFO:
++ ret = wlan_get_rxinfo(priv, wrq);
++ break;
++ case WLAN_SET_ATIM_WINDOW:
++ ret = wlan_ATIM_Window(priv, wrq);
++ break;
++ case WLAN_BEACON_INTERVAL:
++ ret = wlan_beacon_interval(priv, wrq);
++ break;
++ case WLAN_SDIO_PULL_CTRL:
++ ret = wlan_sdio_pull_ctrl(priv, wrq);
++ break;
++ case WLAN_SCAN_TIME:
++ ret = wlan_scan_time(priv, wrq);
++ break;
++ case WLAN_DATA_SUBSCRIBE_EVENT:
++ ret = wlan_data_subscribe_event(priv, wrq);
++ break;
++ case WLAN_TXCONTROL:
++ ret = wlan_txcontrol(priv, wrq);
++ break;
++ case WLANHSCFG:
++ ret = wlan_hscfg_ioctl(priv, wrq);
++ break;
++ case WLANHSSETPARA:
++ ret = wlan_hssetpara_ioctl(priv, wrq);
++ break;
++#ifdef DEBUG_LEVEL1
++ case WLAN_DRV_DBG:
++ ret = wlan_drv_dbg(priv, wrq);
++ break;
++#endif
++ }
++ break;
++
++ case WLAN_SET_GET_2K:
++ switch ((int) wrq->u.data.flags) {
++ case WLAN_SET_USER_SCAN:
++ ret = wlan_set_user_scan_ioctl(priv, wrq);
++ break;
++ case WLAN_GET_SCAN_TABLE:
++ ret = wlan_get_scan_table_ioctl(priv, wrq);
++ break;
++ case WLAN_SET_MRVL_TLV:
++ ret = wlan_set_mrvl_tlv_ioctl(priv, wrq);
++ break;
++ case WLAN_GET_ASSOC_RSP:
++ ret = wlan_get_assoc_rsp_ioctl(priv, wrq);
++ break;
++ case WLAN_ADDTS_REQ:
++ ret = wlan_wmm_addts_req_ioctl(priv, wrq);
++ break;
++ case WLAN_DELTS_REQ:
++ ret = wlan_wmm_delts_req_ioctl(priv, wrq);
++ break;
++ case WLAN_QUEUE_CONFIG:
++ ret = wlan_wmm_queue_config_ioctl(priv, wrq);
++ break;
++ case WLAN_QUEUE_STATS:
++ ret = wlan_wmm_queue_stats_ioctl(priv, wrq);
++ break;
++ case WLAN_TX_PKT_STATS:
++ ret = wlan_tx_pkt_stats_ioctl(priv, wrq);
++ break;
++ case WLAN_GET_CFP_TABLE:
++ ret = wlan_get_cfp_table_ioctl(priv, wrq);
++ break;
++ default:
++ ret = -EOPNOTSUPP;
++ }
++ break;
++
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get wireless statistics
++ *
++ * NOTE: If PrepareAndSendCommand() with wait option is issued
++ * in this function, a kernel dump (scheduling while atomic)
++ * issue may happen on some versions of kernels.
++ *
++ * @param dev A pointer to net_device structure
++ * @return A pointer to iw_statistics buf
++ */
++struct iw_statistics *
++wlan_get_wireless_stats(struct net_device *dev)
++{
++ enum {
++ POOR = 30,
++ FAIR = 60,
++ GOOD = 80,
++ VERY_GOOD = 90,
++ EXCELLENT = 95,
++ PERFECT = 100
++ };
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++ u8 rssi;
++ u32 rssi_qual;
++ u32 tx_qual;
++ u32 quality = 0;
++ u32 tx_retries;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return NULL;
++ }
++
++ priv->wstats.status = Adapter->InfrastructureMode;
++ priv->wstats.discard.retries = priv->stats.tx_errors;
++
++ priv->wstats.qual.level =
++ CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
++ Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
++ priv->wstats.qual.noise = CAL_NF(Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
++ if (Adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0
++ && Adapter->MediaConnectStatus == WlanMediaStateConnected)
++ priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
++ else
++ priv->wstats.qual.noise =
++ CAL_NF(Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
++
++ rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
++ if (rssi < 15)
++ rssi_qual = rssi * POOR / 10;
++ else if (rssi < 20)
++ rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
++ else if (rssi < 30)
++ rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
++ else if (rssi < 40)
++ rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) / 10 + GOOD;
++ else
++ rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) / 10 + VERY_GOOD;
++ quality = rssi_qual;
++
++ tx_retries = Adapter->LogMsg.retry;
++
++ if (tx_retries > 75)
++ tx_qual = (90 - tx_retries) * POOR / 15;
++ else if (tx_retries > 70)
++ tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
++ else if (tx_retries > 65)
++ tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
++ else if (tx_retries > 50)
++ tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) / 15 + GOOD;
++ else
++ tx_qual = (50 - tx_retries) * (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
++ quality = min(quality, tx_qual);
++
++ priv->wstats.qual.qual = min_t(u8, quality, 100);
++ priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
++
++ PRINTM(INFO, "Signal Level = %#x\n", priv->wstats.qual.level);
++ PRINTM(INFO, "Noise = %#x\n", priv->wstats.qual.noise);
++
++ /* send RSSI command to get beacon RSSI/NF, valid only if associated */
++ PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RSSI, 0, 0, 0, NULL);
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_GET_LOG, 0,
++ 0, 0, NULL);
++
++ if (!ret) {
++ priv->wstats.discard.code = 0;
++ priv->wstats.discard.fragment = Adapter->LogMsg.fcserror;
++ priv->wstats.discard.retries = Adapter->LogMsg.retry;
++ priv->wstats.discard.misc = Adapter->LogMsg.ackfailure;
++ }
++
++ return &priv->wstats;
++}
++
++static int
++wlan_set_coalescing_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ int data;
++ int *val;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
++
++ switch (data) {
++ case CMD_DISABLED:
++ case CMD_ENABLED:
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
++ HostCmd_ACT_SET,
++ HostCmd_OPTION_WAITFORRSP, 0, &data);
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ break;
++
++ case CMD_GET:
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
++ HostCmd_ACT_GET,
++ HostCmd_OPTION_WAITFORRSP, 0, &data);
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ val = (int *) wrq->u.name;
++ *val = data;
++
++ LEAVE();
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Set frequency
++ *
++ * @param priv A pointer to wlan_private structure
++ * @param info A pointer to iw_request_info structure
++ * @param fwrq A pointer to iw_freq structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS--success, otherwise--fail
++ */
++int
++wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
++ struct iw_freq *fwrq, char *extra)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ int rc = -EINPROGRESS; /* Call commit handler */
++ CHANNEL_FREQ_POWER *cfp;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++ if (Adapter->InfrastructureMode != Wlan802_11IBSS)
++ return -EOPNOTSUPP;
++
++ /*
++ * If setting by frequency, convert to a channel
++ */
++ if (fwrq->e == 1) {
++
++ long f = fwrq->m / 100000;
++ int c = 0;
++
++ cfp = find_cfp_by_band_and_freq(Adapter, 0, f);
++ if (!cfp) {
++ PRINTM(INFO, "Invalid freq=%ld\n", f);
++ return -EINVAL;
++ }
++
++ c = (int) cfp->Channel;
++
++ if (c < 0)
++ return -EINVAL;
++
++ fwrq->e = 0;
++ fwrq->m = c;
++ }
++
++ /*
++ * Setting by channel number
++ */
++ if (fwrq->m > 1000 || fwrq->e > 0) {
++ rc = -EOPNOTSUPP;
++ } else {
++ int channel = fwrq->m;
++
++ cfp = find_cfp_by_band_and_channel(Adapter, 0, (u16) channel);
++ if (!cfp) {
++ rc = -EINVAL;
++ } else {
++ rc = ChangeAdhocChannel(priv, channel);
++ /* If station is WEP enabled, send the
++ * command to set WEP in firmware
++ */
++ if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled) {
++ PRINTM(INFO, "set_freq: WEP Enabled\n");
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_SET_WEP,
++ 0, HostCmd_OPTION_WAITFORRSP,
++ OID_802_11_ADD_WEP, NULL);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ Adapter->CurrentPacketFilter |= HostCmd_ACT_MAC_WEP_ENABLE;
++
++ PrepareAndSendCommand(priv,
++ HostCmd_CMD_MAC_CONTROL,
++ 0, HostCmd_OPTION_WAITFORRSP,
++ 0, &Adapter->CurrentPacketFilter);
++ }
++ }
++ }
++
++ LEAVE();
++ return rc;
++}
++
++/**
++ * @brief Set Deep Sleep
++ *
++ * @param adapter A pointer to wlan_private structure
++ * @param bDeepSleep TRUE--enalbe deepsleep, FALSE--disable deepsleep
++ * @return WLAN_STATUS_SUCCESS-success, otherwise fail
++ */
++
++int
++SetDeepSleep(wlan_private * priv, BOOLEAN bDeepSleep)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_adapter *Adapter = priv->adapter;
++
++ ENTER();
++
++ if (bDeepSleep == TRUE) {
++ if (Adapter->IsDeepSleep != TRUE) {
++ PRINTM(INFO, "Deep Sleep: sleep\n");
++
++ // note: the command could be queued and executed later
++ // if there is command in prigressing.
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_DEEP_SLEEP, 0,
++ HostCmd_OPTION_WAITFORRSP, 0, NULL);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ wmm_stop_queue(priv);
++ os_stop_queue(priv);
++ os_carrier_off(priv);
++ }
++ } else {
++ if (Adapter->IsDeepSleep == TRUE) {
++ PRINTM(CMND, "Deep Sleep: wakeup\n");
++
++ if (Adapter->IntCounterSaved) {
++ Adapter->IntCounter = Adapter->IntCounterSaved;
++ Adapter->IntCounterSaved = 0;
++ }
++
++ if (sbi_exit_deep_sleep(priv))
++ PRINTM(ERROR, "Deep Sleep : wakeup failed\n");
++
++ if (Adapter->IsDeepSleep == TRUE) {
++
++ if (os_wait_interruptible_timeout(Adapter->ds_awake_q,
++ !Adapter->IsDeepSleep,
++ MRVDRV_DEEP_SLEEP_EXIT_TIMEOUT)
++ == 0) {
++ PRINTM(MSG, "ds_awake_q: timer expired\n");
++ }
++ }
++
++ if (Adapter->IntCounter)
++ wake_up_interruptible(&priv->MainThread.waitQ);
++ }
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief use index to get the data rate
++ *
++ * @param index The index of data rate
++ * @return data rate or 0
++ */
++u32
++index_to_data_rate(u8 index)
++{
++ if (index >= sizeof(WlanDataRates))
++ index = 0;
++
++ return WlanDataRates[index];
++}
++
++/**
++ * @brief use rate to get the index
++ *
++ * @param rate data rate
++ * @return index or 0
++ */
++u8
++data_rate_to_index(u32 rate)
++{
++ u8 *ptr;
++
++ if (rate)
++ if ((ptr = wlan_memchr(WlanDataRates, (u8) rate,
++ sizeof(WlanDataRates))))
++ return (ptr - WlanDataRates);
++
++ return 0;
++}
++
++/**
++ * @brief set data rate
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++
++int
++wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ u32 data_rate;
++ int ret = WLAN_STATUS_SUCCESS;
++ WLAN_802_11_RATES rates;
++ u8 *rate;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ PRINTM(INFO, "Vwrq->value = %d\n", vwrq->value);
++
++ if (vwrq->value == -1) {
++ Adapter->DataRate = 0;
++ Adapter->RateBitmap = 0;
++ memset(rates, 0, sizeof(rates));
++ get_active_data_rates(Adapter, rates);
++ rate = rates;
++ while (*rate) {
++ Adapter->RateBitmap |= 1 << (data_rate_to_index(*rate & 0x7f));
++ rate++;
++ }
++ Adapter->Is_DataRate_Auto = TRUE;
++ } else {
++ if ((vwrq->value % 500000)) {
++ return -EINVAL;
++ }
++
++ data_rate = vwrq->value / 500000;
++
++ memset(rates, 0, sizeof(rates));
++ get_active_data_rates(Adapter, rates);
++ rate = rates;
++ while (*rate) {
++ PRINTM(INFO, "Rate=0x%X Wanted=0x%X\n", *rate, data_rate);
++ if ((*rate & 0x7f) == (data_rate & 0x7f))
++ break;
++ rate++;
++ }
++ if (!*rate) {
++ PRINTM(MSG, "The fixed data rate 0x%X is out "
++ "of range.\n", data_rate);
++ return -EINVAL;
++ }
++
++ Adapter->DataRate = data_rate;
++ Adapter->RateBitmap = 1 << (data_rate_to_index(Adapter->DataRate));
++ Adapter->Is_DataRate_Auto = FALSE;
++ }
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_RATE_ADAPT_RATESET,
++ HostCmd_ACT_GEN_SET,
++ HostCmd_OPTION_WAITFORRSP, 0, NULL);
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief get data rate
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ if (Adapter->Is_DataRate_Auto)
++ vwrq->fixed = 0;
++ else
++ vwrq->fixed = 1;
++
++ Adapter->TxRate = 0;
++
++ ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
++ HostCmd_ACT_GET, HostCmd_OPTION_WAITFORRSP,
++ 0, NULL);
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ vwrq->value = index_to_data_rate(Adapter->TxRate) * 500000;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief set wireless mode
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_set_mode(struct net_device *dev,
++ struct iw_request_info *info, u32 * uwrq, char *extra)
++{
++ int ret = WLAN_STATUS_SUCCESS;
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++
++ WLAN_802_11_NETWORK_INFRASTRUCTURE WantedMode;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ switch (*uwrq) {
++ case IW_MODE_ADHOC:
++ PRINTM(INFO, "Wanted Mode is ad-hoc: current DataRate=%#x\n",
++ Adapter->DataRate);
++ WantedMode = Wlan802_11IBSS;
++ break;
++
++ case IW_MODE_INFRA:
++ PRINTM(INFO, "Wanted Mode is Infrastructure\n");
++ WantedMode = Wlan802_11Infrastructure;
++ break;
++
++ case IW_MODE_AUTO:
++ PRINTM(INFO, "Wanted Mode is Auto\n");
++ WantedMode = Wlan802_11AutoUnknown;
++ break;
++
++ default:
++ PRINTM(INFO, "Wanted Mode is Unknown: 0x%x\n", *uwrq);
++ return -EINVAL;
++ }
++
++ if (Adapter->InfrastructureMode == WantedMode ||
++ WantedMode == Wlan802_11AutoUnknown) {
++ PRINTM(INFO, "Already set to required mode! No change!\n");
++
++ Adapter->InfrastructureMode = WantedMode;
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++ }
++
++ if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
++ if (Adapter->PSState != PS_STATE_FULL_POWER) {
++ PSWakeup(priv, HostCmd_OPTION_WAITFORRSP);
++ }
++ Adapter->PSMode = Wlan802_11PowerModeCAM;
++ }
++
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
++ ret = SendDeauthentication(priv);
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ } else if (Adapter->InfrastructureMode == Wlan802_11IBSS) {
++ /* If current mode is Adhoc, clean stale information */
++ ret = StopAdhocNetwork(priv);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++ }
++ }
++
++ Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
++
++ Adapter->InfrastructureMode = WantedMode;
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_SNMP_MIB,
++ 0, HostCmd_OPTION_WAITFORRSP,
++ OID_802_11_INFRASTRUCTURE_MODE, NULL);
++
++ if (ret) {
++ LEAVE();
++ return ret;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Set Encryption key
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++static int
++wlan_set_encode(struct net_device *dev,
++ struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++
++ WLAN_802_11_KEY *pKey = NULL;
++ int retval = -EINVAL;
++
++ ENTER();
++
++ if (dwrq->length > MAX_WEP_KEY_SIZE) {
++ pKey = (WLAN_802_11_KEY *) extra;
++ if (pKey->KeyLength <= MAX_WEP_KEY_SIZE) {
++ //dynamic WEP
++ dwrq->length = pKey->KeyLength;
++ dwrq->flags = pKey->KeyIndex + 1;
++ retval = wlan_set_encode_nonwpa(dev, info, dwrq,
++ pKey->KeyMaterial);
++ } else {
++ //WPA
++ retval = wlan_set_encode_wpa(dev, info, dwrq, extra);
++ }
++ } else {
++ //static WEP
++ PRINTM(INFO, "Setting WEP\n");
++ retval = wlan_set_encode_nonwpa(dev, info, dwrq, extra);
++ }
++
++ return retval;
++}
++
++/**
++ * @brief set tx power
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
++ struct iw_param *vwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ int ret = WLAN_STATUS_SUCCESS;
++
++ u16 dbm;
++
++ ENTER();
++
++ if (!Is_Command_Allowed(priv)) {
++ PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
++ return -EBUSY;
++ }
++
++ if (vwrq->disabled) {
++ wlan_radio_ioctl(priv, RADIO_OFF);
++ return WLAN_STATUS_SUCCESS;
++ }
++
++ wlan_radio_ioctl(priv, RADIO_ON);
++
++#if WIRELESS_EXT > 14
++ if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
++ dbm = (u16) mw_to_dbm(vwrq->value);
++ } else
++#endif
++ dbm = (u16) vwrq->value;
++
++ if ((dbm < Adapter->MinTxPowerLevel) || (dbm > Adapter->MaxTxPowerLevel)) {
++ PRINTM(MSG,
++ "The set txpower value %d dBm is out of range (%d dBm-%d dBm)!\n",
++ dbm, Adapter->MinTxPowerLevel, Adapter->MaxTxPowerLevel);
++ LEAVE();
++ return -EINVAL;
++ }
++
++ /* auto tx power control */
++
++ if (vwrq->fixed == 0)
++ dbm = 0xffff;
++
++ PRINTM(INFO, "<1>TXPOWER SET %d dbm.\n", dbm);
++
++ ret = PrepareAndSendCommand(priv,
++ HostCmd_CMD_802_11_RF_TX_POWER,
++ HostCmd_ACT_GEN_SET,
++ HostCmd_OPTION_WAITFORRSP, 0, (void *) &dbm);
++
++ LEAVE();
++ return ret;
++}
++
++/**
++ * @brief Get current essid
++ *
++ * @param dev A pointer to net_device structure
++ * @param info A pointer to iw_request_info structure
++ * @param vwrq A pointer to iw_param structure
++ * @param extra A pointer to extra data buf
++ * @return WLAN_STATUS_SUCCESS --success, otherwise fail
++ */
++int
++wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
++ struct iw_point *dwrq, char *extra)
++{
++ wlan_private *priv = dev->priv;
++ wlan_adapter *Adapter = priv->adapter;
++ int tblIdx = -1;
++ BSSDescriptor_t *pBSSDesc;
++
++ ENTER();
++
++ pBSSDesc = &Adapter->CurBssParams.BSSDescriptor;
++
++ /*
++ * Get the current SSID
++ */
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++
++ tblIdx = FindSSIDInList(Adapter,
++ &pBSSDesc->Ssid,
++ pBSSDesc->MacAddress,
++ Adapter->InfrastructureMode);
++
++ memcpy(extra, &pBSSDesc->Ssid.Ssid, pBSSDesc->Ssid.SsidLength);
++ extra[pBSSDesc->Ssid.SsidLength] = '\0';
++
++ } else {
++ memset(extra, 0, 32);
++ extra[pBSSDesc->Ssid.SsidLength] = '\0';
++ }
++
++ /* To make the driver backward compatible with WPA supplicant v0.2.4 */
++ if (dwrq->length == 32) {
++ dwrq->length = MIN(pBSSDesc->Ssid.SsidLength, IW_ESSID_MAX_SIZE);
++ } else {
++#if WIRELESS_EXT > 20
++ dwrq->length = pBSSDesc->Ssid.SsidLength;
++#else
++ dwrq->length = pBSSDesc->Ssid.SsidLength + 1;
++#endif
++ }
++
++ /* If the current network is in the table, return the table index */
++ if (tblIdx >= 0) {
++ dwrq->flags = (tblIdx + 1) & IW_ENCODE_INDEX;
++ } else {
++ dwrq->flags = 1;
++ }
++
++ LEAVE();
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Get version
++ *
++ * @param adapter A pointer to wlan_adapter structure
++ * @param version A pointer to version buffer
++ * @param maxlen max length of version buffer
++ * @return NA
++ */
++void
++get_version(wlan_adapter * adapter, char *version, int maxlen)
++{
++ union
++ {
++ u32 l;
++ u8 c[4];
++ } ver;
++ char fwver[32];
++
++ ver.l = adapter->FWReleaseNumber;
++ if (ver.c[3] == 0)
++ sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]);
++ else
++ sprintf(fwver, "%u.%u.%u.p%u",
++ ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
++
++ snprintf(version, maxlen, driver_version, fwver);
++}
+diff --git a/drivers/net/wireless/marvell8686/wlan_wext.h b/drivers/net/wireless/marvell8686/wlan_wext.h
+new file mode 100644
+index 0000000..d1d40d1
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_wext.h
+@@ -0,0 +1,406 @@
++/** @file wlan_wext.h
++ * @brief This file contains definition for IOCTL call.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
++ */
++/********************************************************
++Change log:
++ 10/11/05: Add Doxygen format comments
++ 12/19/05: Correct a typo in structure _wlan_ioctl_wmm_tspec
++ 01/11/06: Conditionalize new scan/join ioctls
++ 04/10/06: Add hostcmd generic API
++ 04/18/06: Remove old Subscrive Event and add new Subscribe Event
++ implementation through generic hostcmd API
++ 06/08/06: Add definitions of custom events
++ 08/29/06: Add ledgpio private command
++********************************************************/
++
++#ifndef _WLAN_WEXT_H_
++#define _WLAN_WEXT_H_
++
++#include "wlan_types.h"
++
++#define SUBCMD_OFFSET 4
++/** PRIVATE CMD ID */
++#define WLANIOCTL 0x8BE0
++
++#define WLANSETWPAIE (WLANIOCTL + 0)
++#define WLANCISDUMP (WLANIOCTL + 1)
++#ifdef MFG_CMD_SUPPORT
++#define WLANMANFCMD (WLANIOCTL + 2)
++#endif
++#define WLANREGRDWR (WLANIOCTL + 3)
++#define MAX_EEPROM_DATA 256
++#define WLANHOSTCMD (WLANIOCTL + 4)
++
++#define WLANHOSTSLEEPCFG (WLANIOCTL + 5)
++#define WLANARPFILTER (WLANIOCTL + 6)
++
++#define WLAN_SETINT_GETINT (WLANIOCTL + 7)
++#define WLANNF 1
++#define WLANRSSI 2
++#define WLANBGSCAN 4
++#define WLANENABLE11D 5
++#define WLANADHOCGRATE 6
++#define WLANSDIOCLOCK 7
++#define WLANWMM_ENABLE 8
++#define WLANNULLGEN 10
++#define WLANADHOCCSET 11
++#define WLAN_ADHOC_G_PROT 12
++
++#define WLAN_SETNONE_GETNONE (WLANIOCTL + 8)
++#define WLANDEAUTH 1
++#define WLANRADIOON 2
++#define WLANRADIOOFF 3
++#define WLANREMOVEADHOCAES 4
++#define WLANADHOCSTOP 5
++#ifdef REASSOCIATION
++#define WLANREASSOCIATIONAUTO 8
++#define WLANREASSOCIATIONUSER 9
++#endif /* REASSOCIATION */
++#define WLANWLANIDLEON 10
++#define WLANWLANIDLEOFF 11
++
++#define WLANGETLOG (WLANIOCTL + 9)
++#define WLAN_SETCONF_GETCONF (WLANIOCTL + 10)
++
++#define BG_SCAN_CONFIG 1
++#define CAL_DATA_EXT_CONFIG 2
++
++#define WLANSCAN_TYPE (WLANIOCTL + 11)
++
++#define WLAN_SET_GET_2K (WLANIOCTL + 13)
++#define WLAN_SET_USER_SCAN 1
++#define WLAN_GET_SCAN_TABLE 2
++#define WLAN_SET_MRVL_TLV 3
++#define WLAN_GET_ASSOC_RSP 4
++#define WLAN_ADDTS_REQ 5
++#define WLAN_DELTS_REQ 6
++#define WLAN_QUEUE_CONFIG 7
++#define WLAN_QUEUE_STATS 8
++#define WLAN_GET_CFP_TABLE 9
++#define WLAN_TX_PKT_STATS 12
++
++#define WLAN_SETNONE_GETONEINT (WLANIOCTL + 15)
++#define WLANGETREGION 1
++#define WLAN_GET_LISTEN_INTERVAL 2
++#define WLAN_GET_MULTIPLE_DTIM 3
++#define WLAN_GET_TX_RATE 4
++#define WLANGETBCNAVG 5
++#define WLANGETDATAAVG 6
++#define WLANGETDTIM 7
++
++#define WLAN_SETNONE_GETTWELVE_CHAR (WLANIOCTL + 19)
++#define WLAN_SUBCMD_GETRXANTENNA 1
++#define WLAN_SUBCMD_GETTXANTENNA 2
++#define WLAN_GET_TSF 3
++#define WLAN_WPS_SESSION 4
++
++#define WLAN_SETWORDCHAR_GETNONE (WLANIOCTL + 20)
++#define WLANSETADHOCAES 1
++
++#define WLAN_SETONEINT_GETWORDCHAR (WLANIOCTL + 21)
++#define WLANGETADHOCAES 1
++#define WLANVERSION 2
++#define WLANVEREXT 3
++
++#define WLAN_SETONEINT_GETONEINT (WLANIOCTL + 23)
++#define WLAN_WMM_QOSINFO 2
++#define WLAN_LISTENINTRVL 3
++#define WLAN_FW_WAKEUP_METHOD 4
++#define WAKEUP_FW_UNCHANGED 0
++#define WAKEUP_FW_THRU_INTERFACE 1
++#define WAKEUP_FW_THRU_GPIO 2
++
++#define WLAN_NULLPKTINTERVAL 5
++#define WLAN_BCN_MISS_TIMEOUT 6
++#define WLAN_ADHOC_AWAKE_PERIOD 7
++#define WLAN_LDO 8
++#define WLAN_SDIO_MODE 9
++#define WLAN_AUTODEEPSLEEP 12
++#define WLAN_WAKEUP_MT 13
++
++#define WLAN_RTS_CTS_CTRL 14
++
++#define WLAN_SETONEINT_GETNONE (WLANIOCTL + 24)
++#define WLAN_SUBCMD_SETRXANTENNA 1
++#define WLAN_SUBCMD_SETTXANTENNA 2
++#define WLANSETAUTHALG 4
++#define WLANSETENCRYPTIONMODE 5
++#define WLANSETREGION 6
++#define WLAN_SET_LISTEN_INTERVAL 7
++
++#define WLAN_SET_MULTIPLE_DTIM 8
++
++#define WLANSETBCNAVG 9
++#define WLANSETDATAAVG 10
++#define WLANASSOCIATE 11
++
++#define WLAN_SET64CHAR_GET64CHAR (WLANIOCTL + 25)
++#define WLANSLEEPPARAMS 2
++#define WLAN_BCA_TIMESHARE 3
++#define WLANSCAN_MODE 6
++
++#define WLAN_GET_ADHOC_STATUS 9
++
++#define WLAN_SET_GEN_IE 10
++#define WLAN_GET_GEN_IE 11
++
++#define WLAN_WMM_QUEUE_STATUS 13
++
++#define WLANEXTSCAN (WLANIOCTL + 26)
++#define WLANDEEPSLEEP (WLANIOCTL + 27)
++#define DEEP_SLEEP_ENABLE 1
++#define DEEP_SLEEP_DISABLE 0
++
++#define WLAN_SET_GET_SIXTEEN_INT (WLANIOCTL + 29)
++#define WLAN_TPCCFG 1
++#define WLAN_LED_GPIO_CTRL 5
++#define WLAN_SCANPROBES 6
++#define WLAN_SLEEP_PERIOD 7
++#define WLAN_ADAPT_RATESET 8
++#define WLAN_INACTIVITY_TIMEOUT 9
++#define WLANSNR 10
++#define WLAN_GET_RATE 11
++#define WLAN_GET_RXINFO 12
++#define WLAN_SET_ATIM_WINDOW 13
++#define WLAN_BEACON_INTERVAL 14
++#define WLAN_SDIO_PULL_CTRL 15
++#define WLAN_SCAN_TIME 16
++#define WLAN_DATA_SUBSCRIBE_EVENT 18
++#define WLAN_TXCONTROL 19
++#define WLANHSCFG 21
++#define WLANHSSETPARA 22
++#ifdef DEBUG_LEVEL1
++#define WLAN_DRV_DBG 25
++#endif
++
++#define WLANCMD52RDWR (WLANIOCTL + 30)
++#define WLANCMD53RDWR (WLANIOCTL + 31)
++#define CMD53BUFLEN 32
++
++#define REG_MAC 0x19
++#define REG_BBP 0x1a
++#define REG_RF 0x1b
++#define REG_EEPROM 0x59
++
++#define CMD_DISABLED 0
++#define CMD_ENABLED 1
++#define CMD_GET 2
++#define SKIP_CMDNUM 4
++#define SKIP_TYPE 1
++#define SKIP_SIZE 2
++#define SKIP_ACTION 2
++#define SKIP_TYPE_SIZE (SKIP_TYPE + SKIP_SIZE)
++#define SKIP_TYPE_ACTION (SKIP_TYPE + SKIP_ACTION)
++
++#define MAX_SETGET_CONF_SIZE 2000 /* less than MRVDRV_SIZE_OF_CMD_BUFFER */
++#define MAX_SETGET_CONF_CMD_LEN (MAX_SETGET_CONF_SIZE - SKIP_CMDNUM)
++
++/* define custom events */
++#define CUS_EVT_HS_ACTIVATED "HS_ACTIVATED "
++#define CUS_EVT_HS_DEACTIVATED "HS_DEACTIVATED "
++#define CUS_EVT_HS_GPIO_INT "HS_GPIO_INT "
++#define CUS_EVT_BEACON_RSSI_LOW "EVENT=BEACON_RSSI_LOW"
++#define CUS_EVT_BEACON_SNR_LOW "EVENT=BEACON_SNR_LOW"
++#define CUS_EVT_BEACON_RSSI_HIGH "EVENT=BEACON_RSSI_HIGH"
++#define CUS_EVT_BEACON_SNR_HIGH "EVENT=BEACON_SNR_HIGH"
++#define CUS_EVT_MAX_FAIL "EVENT=MAX_FAIL"
++#define CUS_EVT_MLME_MIC_ERR_UNI "MLME-MICHAELMICFAILURE.indication unicast "
++#define CUS_EVT_MLME_MIC_ERR_MUL "MLME-MICHAELMICFAILURE.indication multicast "
++
++#define CUS_EVT_DATA_RSSI_LOW "EVENT=DATA_RSSI_LOW"
++#define CUS_EVT_DATA_SNR_LOW "EVENT=DATA_SNR_LOW"
++#define CUS_EVT_DATA_RSSI_HIGH "EVENT=DATA_RSSI_HIGH"
++#define CUS_EVT_DATA_SNR_HIGH "EVENT=DATA_SNR_HIGH"
++#define CUS_EVT_PRE_BEACON_LOST "EVENT=PRE_BEACON_LOST"
++
++#define CUS_EVT_DEEP_SLEEP_AWAKE "EVENT=DS_AWAKE"
++
++#define CUS_EVT_ADHOC_LINK_SENSED "EVENT=ADHOC_LINK_SENSED"
++#define CUS_EVT_ADHOC_BCN_LOST "EVENT=ADHOC_BCN_LOST"
++
++/**
++ * @brief Maximum number of channels that can be sent in a setuserscan ioctl
++ *
++ * @sa wlan_ioctl_user_scan_cfg
++ */
++#define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50
++
++/** wlan_ioctl */
++typedef struct _wlan_ioctl
++{
++ /** Command ID */
++ u16 command;
++ /** data length */
++ u16 len;
++ /** data pointer */
++ u8 *data;
++} wlan_ioctl;
++
++/** wlan_ioctl_rfantenna */
++typedef struct _wlan_ioctl_rfantenna
++{
++ u16 Action;
++ u16 AntennaMode;
++} wlan_ioctl_rfantenna;
++
++/** wlan_ioctl_regrdwr */
++typedef struct _wlan_ioctl_regrdwr
++{
++ /** Which register to access */
++ u16 WhichReg;
++ /** Read or Write */
++ u16 Action;
++ u32 Offset;
++ u16 NOB;
++ u32 Value;
++} wlan_ioctl_regrdwr;
++
++/** wlan_ioctl_cfregrdwr */
++typedef struct _wlan_ioctl_cfregrdwr
++{
++ /** Read or Write */
++ u8 Action;
++ /** register address */
++ u16 Offset;
++ /** register value */
++ u16 Value;
++} wlan_ioctl_cfregrdwr;
++
++/** wlan_ioctl_adhoc_key_info */
++typedef struct _wlan_ioctl_adhoc_key_info
++{
++ u16 action;
++ u8 key[16];
++ u8 tkiptxmickey[16];
++ u8 tkiprxmickey[16];
++} wlan_ioctl_adhoc_key_info;
++
++/** sleep_params */
++typedef struct _wlan_ioctl_sleep_params_config
++{
++ u16 Action;
++ u16 Error;
++ u16 Offset;
++ u16 StableTime;
++ u8 CalControl;
++ u8 ExtSleepClk;
++ u16 Reserved;
++} __ATTRIB_PACK__ wlan_ioctl_sleep_params_config,
++ *pwlan_ioctl_sleep_params_config;
++
++/** BCA TIME SHARE */
++typedef struct _wlan_ioctl_bca_timeshare_config
++{
++ /** ACT_GET/ACT_SET */
++ u16 Action;
++ /** Type: WLAN, BT */
++ u16 TrafficType;
++ /** Interval: 20msec - 60000msec */
++ u32 TimeShareInterval;
++ /** PTA arbiter time in msec */
++ u32 BTTime;
++} __ATTRIB_PACK__ wlan_ioctl_bca_timeshare_config,
++ *pwlan_ioctl_bca_timeshare_config;
++
++#define MAX_CFP_LIST_NUM 64
++
++/** wlan_ioctl_cfp_table */
++typedef struct _wlan_ioctl_cfp_table
++{
++ u32 region;
++ u32 cfp_no;
++ struct
++ {
++ u16 Channel;
++ u32 Freq;
++ u16 MaxTxPower;
++ u8 Unsupported;
++ } cfp[MAX_CFP_LIST_NUM];
++} __ATTRIB_PACK__ wlan_ioctl_cfp_table, *pwlan_ioctl_cfp_table;
++
++/**
++ * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
++ *
++ * Multiple instances of this structure are included in the IOCTL command
++ * to configure a instance of a scan on the specific channel.
++ */
++typedef struct
++{
++ u8 chanNumber; //!< Channel Number to scan
++ u8 radioType; //!< Radio type: 'B/G' Band = 0, 'A' Band = 1
++ u8 scanType; //!< Scan type: Active = 0, Passive = 1
++ u8 reserved;
++ u16 scanTime; //!< Scan duration in milliseconds; if 0 default used
++} __ATTRIB_PACK__ wlan_ioctl_user_scan_chan;
++/**
++ * @brief IOCTL SSID List sub-structure sent in wlan_ioctl_user_scan_cfg
++ *
++ * Used to specify SSID specific filters as well as SSID pattern matching
++ * filters for scan result processing in firmware.
++ */
++typedef struct
++{
++ char ssid[MRVDRV_MAX_SSID_LENGTH + 1];
++ u8 maxLen;
++} __ATTRIB_PACK__ wlan_ioctl_user_scan_ssid;
++
++/**
++ * @brief IOCTL input structure to configure an immediate scan cmd to firmware
++ *
++ * Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl. Specifies
++ * a number of parameters to be used in general for the scan as well
++ * as a channel list (wlan_ioctl_user_scan_chan) for each scan period
++ * desired.
++ *
++ * @sa wlan_set_user_scan_ioctl
++ */
++typedef struct
++{
++
++ /**
++ * @brief Flag set to keep the previous scan table intact
++ *
++ * If set, the scan results will accumulate, replacing any previous
++ * matched entries for a BSS with the new scan data
++ */
++ u8 keepPreviousScan; //!< Do not erase the existing scan results
++
++ /**
++ * @brief BSS Type to be sent in the firmware command
++ *
++ * Field can be used to restrict the types of networks returned in the
++ * scan. Valid settings are:
++ *
++ * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure)
++ * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
++ * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
++ */
++ u8 bssType;
++
++ /**
++ * @brief Configure the number of probe requests for active chan scans
++ */
++ u8 numProbes;
++
++ u8 reserved;
++
++ /**
++ * @brief BSSID filter sent in the firmware command to limit the results
++ */
++ u8 specificBSSID[MRVDRV_ETH_ADDR_LEN];
++
++ /**
++ * @brief SSID filter list used in the to limit the scan results
++ */
++ wlan_ioctl_user_scan_ssid ssidList[MRVDRV_MAX_SSID_LIST_LENGTH];
++
++ /**
++ * @brief Variable number (fixed maximum) of channels to scan up
++ */
++ wlan_ioctl_user_scan_chan chanList[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
++
++} __ATTRIB_PACK__ wlan_ioctl_user_scan_cfg;
++
++#endif /* _WLAN_WEXT_H_ */
+diff --git a/drivers/net/wireless/marvell8686/wlan_wmm.c b/drivers/net/wireless/marvell8686/wlan_wmm.c
+new file mode 100644
+index 0000000..789ad2e
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_wmm.c
+@@ -0,0 +1,1666 @@
++/** @file wlan_wmm.c
++ * @brief This file contains functions for WMM.
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++/********************************************************
++Change log:
++ 10/04/05: Add Doxygen format comments
++ 11/11/05: Add support for WMM Status change event
++ 01/05/06: Add kernel 2.6.x support
++ 01/11/06: Conditionalize new scan/join code modifications.
++ 04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
++********************************************************/
++#include "include.h"
++
++/********************************************************
++ Local Variables
++********************************************************/
++
++/** Maximum value FW can accept for driver delay in packet transmission */
++#define DRV_PKT_DELAY_TO_FW_MAX 512
++
++/** Set limit of driver packet delay for use in MSDU lifetime expiry and
++ * traffic stream metrics.
++ *
++ * - Set to 0 to disable driver delay in firmware
++ * - Set to DRV_PKT_DELAY_TO_FW_MAX to enable all possible values
++ */
++#define DRV_PKT_DELAY_TO_FW_LIMIT 0
++
++/** Upper and Lower threshold for packet queuing in the driver
++ *
++ * - When the number of packets queued reaches the upper limit,
++ * the driver will stop the net queue in the app/kernel space.
++ *
++ * - When the number of packets drops beneath the lower limit after
++ * having reached the upper limit, the driver will restart the net
++ * queue.
++ */
++#define WMM_QUEUED_PACKET_LOWER_LIMIT 40
++#define WMM_QUEUED_PACKET_UPPER_LIMIT 50
++
++#define IPTOS_OFFSET 5
++
++static const u8 wmm_info_ie[] = { WMM_IE, 0x07,
++ 0x00, 0x50, 0xf2, 0x02,
++ 0x00, 0x01, 0x00
++};
++
++/********************************************************
++ Local Functions
++********************************************************/
++#ifdef DEBUG_LEVEL2
++/**
++ * @brief Debug print function to display the priority parameters for a WMM AC
++ *
++ * @param acStr String pointer giving the AC enumeration (BK, BE, VI, VO)
++ * @param pACParam Pointer to the AC paramters to display
++ *
++ * @return void
++ */
++static void
++wmm_debugPrintAC(wlan_wmm_ac_e acVal,
++ const IEEEtypes_WmmAcParameters_t * pACParam)
++{
++ const char *acStr[] = { "BK", "BE", "VI", "VO" };
++
++ PRINTM(INFO, "WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, "
++ "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n",
++ acStr[acVal], pACParam->AciAifsn.Aci, pACParam->AciAifsn.Acm,
++ pACParam->AciAifsn.Aifsn, pACParam->Ecw.EcwMin,
++ pACParam->Ecw.EcwMax, wlan_le16_to_cpu(pACParam->TxopLimit));
++}
++
++#define PRINTM_AC(acStr, pACParam) wmm_debugPrintAC(acStr, pACParam)
++#else
++#define PRINTM_AC(acStr, pACParam)
++#endif
++
++/**
++ * @brief Compute the difference between two timestamps.
++ *
++ * @param pTv1 Pointer to timestamp1
++ * @param pTv2 Pointer to timestamp2
++ *
++ * @return Time difference in ms between pTv1 and pTv2 (pTv1 - pTv2)
++ */
++static int
++timeval_diff_in_ms(const struct timeval *pTv1, const struct timeval *pTv2)
++{
++ int diff_ms;
++
++ diff_ms = (pTv1->tv_sec - pTv2->tv_sec) * 1000;
++ diff_ms += (pTv1->tv_usec - pTv2->tv_usec) / 1000;
++
++ return diff_ms;
++}
++
++/**
++ * @brief Set the WMM queue priorities to their default values
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return void
++ */
++static void
++wmm_default_queue_priorities(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ /* default queue priorities: VO->VI->BE->BK */
++ Adapter->wmm.queuePriority[0] = WMM_AC_VO;
++ Adapter->wmm.queuePriority[1] = WMM_AC_VI;
++ Adapter->wmm.queuePriority[2] = WMM_AC_BE;
++ Adapter->wmm.queuePriority[3] = WMM_AC_BK;
++}
++
++/**
++ * @brief Initialize WMM priority queues
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return void
++ */
++static void
++wmm_setup_queue_priorities(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ IEEEtypes_WmmParameter_t *pWmmIe;
++ wlan_wmm_ac_e acOrder[4] = { WMM_AC_BE, WMM_AC_BK,
++ WMM_AC_VI, WMM_AC_VO
++ };
++
++ u16 cwmax, cwmin, avg_back_off, tmp[4];
++ int i, j, numAc;
++
++ if (Adapter->wmm.enabled == FALSE) {
++ /* WMM is not enabled, just set the defaults and return */
++ wmm_default_queue_priorities(priv);
++ return;
++ }
++
++ pWmmIe = &Adapter->CurBssParams.BSSDescriptor.wmmIE;
++
++ HEXDUMP("WMM: setup_queue_priorities: param IE",
++ (u8 *) pWmmIe, sizeof(IEEEtypes_WmmParameter_t));
++
++ PRINTM(INFO, "WMM Parameter IE: version=%d, "
++ "QoSInfo Parameter Set Count=%d, Reserved=%#x\n",
++ pWmmIe->VendHdr.Version, pWmmIe->QoSInfo.ParaSetCount,
++ pWmmIe->Reserved);
++
++ for (numAc = 0; numAc < NELEMENTS(acOrder); numAc++) {
++ cwmax = (1 << pWmmIe->AcParams[numAc].Ecw.EcwMax) - 1;
++ cwmin = (1 << pWmmIe->AcParams[numAc].Ecw.EcwMin) - 1;
++ avg_back_off = (cwmin >> 1) + pWmmIe->AcParams[numAc].AciAifsn.Aifsn;
++ Adapter->wmm.queuePriority[numAc] = acOrder[numAc];
++ tmp[numAc] = avg_back_off;
++
++ PRINTM(INFO, "WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
++ cwmax, cwmin, avg_back_off);
++ PRINTM_AC(acOrder[numAc], &pWmmIe->AcParams[numAc]);
++ }
++
++ HEXDUMP("WMM: avg_back_off", (u8 *) tmp, sizeof(tmp));
++ HEXDUMP("WMM: queuePriority", Adapter->wmm.queuePriority,
++ sizeof(Adapter->wmm.queuePriority));
++
++ /* bubble sort */
++ for (i = 0; i < numAc; i++) {
++ for (j = 1; j < numAc - i; j++) {
++ if (tmp[j - 1] > tmp[j]) {
++ SWAP_U16(tmp[j - 1], tmp[j]);
++ SWAP_U8(Adapter->wmm.queuePriority[j - 1],
++ Adapter->wmm.queuePriority[j]);
++ } else if (tmp[j - 1] == tmp[j]) {
++ if (Adapter->wmm.queuePriority[j - 1]
++ < Adapter->wmm.queuePriority[j]) {
++ SWAP_U8(Adapter->wmm.queuePriority[j - 1],
++ Adapter->wmm.queuePriority[j]);
++ }
++ }
++ }
++ }
++
++ HEXDUMP("WMM: avg_back_off, sort", (u8 *) tmp, sizeof(tmp));
++ HEXDUMP("WMM: queuePriority, sort", Adapter->wmm.queuePriority,
++ sizeof(Adapter->wmm.queuePriority));
++}
++
++/**
++ * @brief pop up the highest skb from wmm queue
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return void
++ */
++static void
++wmm_pop_highest_prio_skb(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int i;
++ u8 ac;
++
++ ENTER();
++
++ for (i = 0; i < MAX_AC_QUEUES; i++) {
++ ac = Adapter->wmm.queuePriority[i];
++ if (!list_empty((struct list_head *) &Adapter->wmm.txSkbQ[ac])) {
++ PRINTM(DATA, "WMM: Highest prio pkt in AC Queue %d\n", i);
++ Adapter->CurrentTxSkb = Adapter->wmm.txSkbQ[ac].next;
++ Adapter->wmm.packetsOut[ac]++;
++ list_del((struct list_head *) Adapter->wmm.txSkbQ[ac].next);
++ break;
++ }
++ }
++
++ LEAVE();
++}
++
++/**
++ * @brief Evaluate whether or not an AC is to be downgraded
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param evalAC AC to evaluate for downgrading
++ *
++ * @return WMM AC the evalAC traffic is to be sent on.
++ */
++static wlan_wmm_ac_e
++wmm_eval_downgrade_ac(wlan_private * priv, wlan_wmm_ac_e evalAC)
++{
++ wlan_wmm_ac_e downAC;
++ wlan_wmm_ac_e retAC;
++ WmmAcStatus_t *pACStatus;
++
++ pACStatus = &priv->adapter->wmm.acStatus[evalAC];
++
++ if (pACStatus->Disabled == FALSE) {
++ /* Okay to use this AC, its enabled */
++ return evalAC;
++ }
++
++ /* Setup a default return value of the lowest priority */
++ retAC = WMM_AC_BK;
++
++ /*
++ * Find the highest AC that is enabled and does not require admission
++ * control. The spec disallows downgarding to an AC which is enabled
++ * due to a completed admission control. Unadmitted traffic is not
++ * to be sent on an AC with admitted traffic.
++ */
++ for (downAC = WMM_AC_BK; downAC < evalAC; downAC++) {
++ pACStatus = &priv->adapter->wmm.acStatus[downAC];
++
++ if ((pACStatus->Disabled == FALSE)
++ && (pACStatus->FlowRequired == FALSE)) {
++ /* AC is enabled and does not require admission control */
++ retAC = downAC;
++ }
++ }
++
++ return retAC;
++}
++
++/**
++ * @brief Downgrade WMM priority queue
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return void
++ */
++static void
++wmm_setup_ac_downgrade(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ wlan_wmm_ac_e acVal;
++
++ PRINTM(INFO, "WMM: AC Priorities: BK(0), BE(1), VI(2), VO(3)\n");
++
++ if (Adapter->wmm.enabled == FALSE) {
++ /* WMM is not enabled, default priorities */
++ for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) {
++ for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) {
++ Adapter->wmm.acDowngradedVals[acVal] = acVal;
++ }
++ }
++ } else {
++ for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) {
++ Adapter->wmm.acDowngradedVals[acVal]
++ = wmm_eval_downgrade_ac(priv, acVal);
++ PRINTM(INFO, "WMM: AC PRIO %d maps to %d\n",
++ acVal, Adapter->wmm.acDowngradedVals[acVal]);
++ }
++ }
++}
++
++/**
++ * @brief Convert the IP TOS field to an WMM AC Queue assignment
++ *
++ * @param tos IP TOS field
++ *
++ * @return WMM AC Queue mapping of the IP TOS field
++ */
++wlan_wmm_ac_e
++wmm_convert_tos_to_ac(int tos)
++{
++ u8 tosIdx;
++
++ /* Map of TOS UP values to WMM AC */
++ const wlan_wmm_ac_e tos_to_ac[] = { WMM_AC_BE,
++ WMM_AC_BK,
++ WMM_AC_BK,
++ WMM_AC_BE,
++ WMM_AC_VI,
++ WMM_AC_VI,
++ WMM_AC_VO,
++ WMM_AC_VO
++ };
++
++ tosIdx = tos >> IPTOS_OFFSET;
++
++ if (tosIdx >= NELEMENTS(tos_to_ac)) {
++ return WMM_AC_BE;
++ }
++
++ return tos_to_ac[tosIdx];
++}
++
++/**
++ * @brief Evaluate a given AC and downgrade it to a lower AC if the
++ * WMM Parameter IE received from the AP indicates that the AP
++ * is disabled (due to call admission control (ACM bit)
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param acVal AC to evaulate for downgrading
++ *
++ * @return Same AC as input if downgrading not required or
++ * the AC the traffic for the given AC should be downgraded to
++ */
++wlan_wmm_ac_e
++wmm_downgrade_ac(wlan_private * priv, wlan_wmm_ac_e acVal)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ return (Adapter->wmm.acDowngradedVals[acVal]);
++}
++
++/**
++ * @brief Map the IP TOS field to a user priority value
++ *
++ * @param tos IP TOS field
++ *
++ * @return User priority tos input parameter maps to
++ */
++static u8
++wmm_tos_to_priority(u8 tos)
++{
++ u8 tosIdx;
++ const u8 tos_to_priority[] = {
++ /* Priority DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */
++ 0x00, /* 0 0 0 AC_BE */
++ 0x01, /* 0 0 1 AC_BK */
++ 0x02, /* 0 1 0 AC_BK */
++ 0x03, /* 0 1 1 AC_BE */
++ 0x04, /* 1 0 0 AC_VI */
++ 0x05, /* 1 0 1 AC_VI */
++ 0x06, /* 1 1 0 AC_VO */
++ 0x07 /* 1 1 1 AC_VO */
++ };
++
++ tosIdx = tos >> IPTOS_OFFSET;
++
++ if (tosIdx >= NELEMENTS(tos_to_priority)) {
++ return WMM_AC_BE;
++ }
++
++ return tos_to_priority[tosIdx];
++}
++
++/**
++ * @brief Process a transfer of a data packet to the firmware from the
++ * driver queue in order to manipulate flow control in the driver.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return void
++ */
++void
++wmm_process_fw_iface_tx_xfer_start(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ if (--Adapter->wmm.packetsQueued < WMM_QUEUED_PACKET_LOWER_LIMIT) {
++ PRINTM(DATA, "WMM: FW OS+: %d\n", Adapter->wmm.packetsQueued);
++ os_start_queue(priv);
++ }
++}
++
++/**
++ * @brief Process the completion of a data packet transfer to the firmware
++ * from the driver queue in order to manipulate flow control in the
++ * driver.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return void
++ *
++ */
++void
++wmm_process_fw_iface_tx_xfer_end(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ if (Adapter->wmm.packetsQueued) {
++ PRINTM(DATA, "WMM: FW OS-: %d\n", Adapter->wmm.packetsQueued);
++ os_stop_queue(priv);
++ }
++}
++
++/**
++ * @brief Process a transfer of a data packet from the OS to the driver
++ * queue in order to manipulate flow control in the driver.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return void
++ */
++void
++wmm_process_app_iface_tx(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ Adapter->wmm.packetsQueued++;
++
++ if ((!priv->wlan_dev.dnld_sent && (Adapter->PSState != PS_STATE_SLEEP))
++ || (Adapter->wmm.packetsQueued >= WMM_QUEUED_PACKET_UPPER_LIMIT)) {
++ PRINTM(DATA, "WMM: APP OS-: %d\n", Adapter->wmm.packetsQueued);
++ os_stop_queue(priv);
++ }
++}
++
++/**
++ * @brief Stop the WMM data queues. Traffic is still accepted from the
++ * OS until the buffer limits are reached.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return void
++ */
++void
++wmm_stop_queue(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ PRINTM(DATA, "WMM: Q-: %d\n", Adapter->wmm.packetsQueued);
++ Adapter->wmm.queueStopped = TRUE;
++}
++
++/**
++ * @brief Start/re-start the WMM data queues and indicate to the OS layer
++ * that data is being accepted again.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return void
++ */
++void
++wmm_start_queue(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++
++ PRINTM(DATA, "WMM: Q+: %d\n", Adapter->wmm.packetsQueued);
++ Adapter->wmm.queueStopped = FALSE;
++ if (Adapter->wmm.packetsQueued) {
++ wake_up_interruptible(&priv->MainThread.waitQ);
++ }
++ os_carrier_on(priv);
++ os_start_queue(priv);
++}
++
++/**
++ * @brief Query the status of the WMM queues. Determine if the driver data
++ * path is active or not.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return TRUE if WMM queues have been stopped, FALSE if still active
++ */
++int
++wmm_is_queue_stopped(wlan_private * priv)
++{
++ return (priv->adapter->wmm.queueStopped == TRUE);
++}
++
++/**
++ * @brief Initialize the WMM state information and the WMM data path queues.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return void
++ */
++void
++wmm_init(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ int i;
++ memset(&Adapter->wmm, 0x00, sizeof(Adapter->wmm));
++
++ for (i = 0; i < MAX_AC_QUEUES; i++) {
++ INIT_LIST_HEAD((struct list_head *) &Adapter->wmm.txSkbQ[i]);
++ }
++
++ Adapter->wmm.required = FALSE;
++
++ Adapter->gen_null_pkg = TRUE; /*Enable NULL Pkg generation */
++}
++
++/**
++ * @brief Setup the queue priorities and downgrade any queues as required
++ * by the WMM info. Setups default values if WMM is not active
++ * for this association.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return void
++ */
++void
++wmm_setup_queues(wlan_private * priv)
++{
++ wmm_setup_queue_priorities(priv);
++ wmm_setup_ac_downgrade(priv);
++}
++
++/**
++ * @brief implement WMM enable command
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param wrq Pointer to user data
++ *
++ * @return WLAN_STATUS_SUCCESS if success; otherwise <0
++ */
++int
++wlan_wmm_enable_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ ulong flags;
++ int data, data1;
++ int *val;
++
++ ENTER();
++
++ data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
++ switch (data) {
++ case CMD_DISABLED: /* disable */
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ return -EPERM;
++ }
++
++ spin_lock_irqsave(&Adapter->CurrentTxLock, flags);
++ Adapter->wmm.required = FALSE;
++ if (!Adapter->wmm.enabled) {
++ spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
++ data1 = Adapter->wmm.required;
++ val = (int *) wrq->u.name;
++ *val = data;
++ return WLAN_STATUS_SUCCESS;
++ } else {
++ Adapter->wmm.enabled = 0;
++ }
++
++ if (Adapter->CurrentTxSkb) {
++ kfree_skb(Adapter->CurrentTxSkb);
++ OS_INT_DISABLE;
++ Adapter->CurrentTxSkb = NULL;
++ OS_INT_RESTORE;
++ priv->stats.tx_dropped++;
++ }
++
++ spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
++ break;
++
++ case CMD_ENABLED: /* enable */
++ if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
++ return -EPERM;
++ }
++ spin_lock_irqsave(&Adapter->CurrentTxLock, flags);
++ Adapter->wmm.required = TRUE;
++ spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
++ break;
++
++ case CMD_GET:
++ break;
++ default:
++ PRINTM(INFO, "Invalid option\n");
++ return -EINVAL;
++ }
++
++ data = Adapter->wmm.required;
++ val = (int *) wrq->u.name;
++ *val = data;
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Implement cmd HostCmd_CMD_WMM_GET_STATUS
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param cmd Pointer to CMD buffer
++ * @param InfoBuf Pointer to cmd data
++ *
++ * @return WLAN_STATUS_SUCCESS
++ */
++int
++wlan_cmd_wmm_get_status(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *InfoBuf)
++{
++ PRINTM(INFO, "WMM: WMM_GET_STATUS cmd sent\n");
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
++ cmd->Size =
++ wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_GET_STATUS) + S_DS_GEN);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Send a command to firmware to retrieve the current WMM status
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
++ */
++int
++sendWMMStatusChangeCmd(wlan_private * priv)
++{
++ return PrepareAndSendCommand(priv, HostCmd_CMD_WMM_GET_STATUS,
++ 0, 0, 0, NULL);
++}
++
++/**
++ * @brief Check if wmm TX queue is empty
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return FALSE if not empty; TRUE if empty
++ */
++int
++wmm_lists_empty(wlan_private * priv)
++{
++ int i;
++
++ for (i = 0; i < MAX_AC_QUEUES; i++) {
++ if (!list_empty((struct list_head *) &priv->adapter->wmm.txSkbQ[i])) {
++ return FALSE;
++ }
++ }
++ return TRUE;
++}
++
++/**
++ * @brief Cleanup wmm TX queue
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return void
++ */
++void
++wmm_cleanup_queues(wlan_private * priv)
++{
++ int i;
++ struct sk_buff *delNode, *Q;
++
++ ENTER();
++
++ for (i = 0; i < MAX_AC_QUEUES; i++) {
++ Q = &priv->adapter->wmm.txSkbQ[i];
++
++ while (!list_empty((struct list_head *) Q)) {
++ delNode = Q->next;
++ list_del((struct list_head *) delNode);
++ kfree_skb(delNode);
++ }
++ }
++
++ priv->adapter->wmm.packetsQueued = 0;
++
++ LEAVE();
++}
++
++/**
++ * @brief Add skb to WMM queue
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param skb Pointer to sk_buff
++ *
++ * @return void
++ */
++void
++wmm_map_and_add_skb(wlan_private * priv, struct sk_buff *skb)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ struct ethhdr *eth;
++ struct timeval tstamp;
++ u8 tos;
++ wlan_wmm_ac_e ac;
++ wlan_wmm_ac_e ac_down;
++
++ eth = (struct ethhdr *) skb->data;
++
++ switch (eth->h_proto) {
++ case __constant_htons(ETH_P_IP):
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
++ PRINTM(INFO, "packet type ETH_P_IP: %04x, tos=%#x prio=%#x\n",
++ eth->h_proto, ip_hdr(skb)->tos, skb->priority);
++ tos = IPTOS_PREC(ip_hdr(skb)->tos) >> IPTOS_OFFSET;
++#else
++ PRINTM(DATA, "packet type ETH_P_IP: %04x, tos=%#x prio=%#x\n",
++ eth->h_proto, skb->nh.iph->tos, skb->priority);
++ tos = IPTOS_PREC(skb->nh.iph->tos);
++#endif
++ break;
++ case __constant_htons(ETH_P_ARP):
++ PRINTM(DATA, "ARP packet %04x\n", eth->h_proto);
++ default:
++ tos = 0;
++ break;
++ }
++
++ ac = wmm_convert_tos_to_ac(tos);
++ ac_down = wmm_downgrade_ac(priv, ac);
++
++ skb->priority = wmm_tos_to_priority(tos);
++ PRINTM(DATA, "wmm_map: tos=%#x, ac=%#x ac_down=%#x, priority=%#x\n",
++ tos, ac, ac_down, skb->priority);
++
++ list_add_tail((struct list_head *) skb,
++ (struct list_head *) &Adapter->wmm.txSkbQ[ac_down]);
++
++ wmm_process_app_iface_tx(priv);
++
++ /* Record the current time the packet was queued; used to determine
++ * the amount of time the packet was queued in the driver before it
++ * was sent to the firmware. The delay is then sent along with the
++ * packet to the firmware for aggregate delay calculation for stats
++ * and MSDU lifetime expiry.
++ */
++ do_gettimeofday(&tstamp);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
++ skb->tstamp = timeval_to_ktime(tstamp);
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
++ skb_set_timestamp(skb, &tstamp);
++#else
++ memcpy(&skb->stamp, &tstamp, sizeof(skb->stamp));
++#endif
++}
++
++/**
++ * @brief Process the GET_WMM_STATUS command response from firmware
++ *
++ * The GET_WMM_STATUS command returns multiple TLVs for:
++ * - Each AC Queue status
++ * - Current WMM Parameter IE
++ *
++ * This function parses the TLVs and then calls further functions
++ * to process any changes in the queue prioritization or state.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param resp Pointer to the command response buffer including TLVs
++ * TLVs for each queue and the WMM Parameter IE.
++ *
++ * @return WLAN_STATUS_SUCCESS
++ */
++int
++wlan_cmdresp_wmm_get_status(wlan_private * priv,
++ const HostCmd_DS_COMMAND * resp)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ u8 *pCurrent = (u8 *) & resp->params.getWmmStatus;
++ u32 respLen = resp->Size;
++ int valid = TRUE;
++ int enableData = TRUE;
++
++ MrvlIEtypes_Data_t *pTlvHdr;
++ MrvlIEtypes_WmmQueueStatus_t *pTlvWmmQStatus;
++ IEEEtypes_WmmParameter_t *pWmmParamIe;
++ WmmAcStatus_t *pACStatus;
++
++ PRINTM(INFO, "WMM: WMM_GET_STATUS cmdresp received: %d\n", respLen);
++ HEXDUMP("CMD_RESP: WMM_GET_STATUS", pCurrent, respLen);
++
++ while ((respLen >= sizeof(pTlvHdr->Header)) && valid) {
++ pTlvHdr = (MrvlIEtypes_Data_t *) pCurrent;
++ pTlvHdr->Header.Len = wlan_le16_to_cpu(pTlvHdr->Header.Len);
++
++ switch (wlan_le16_to_cpu(pTlvHdr->Header.Type)) {
++ case TLV_TYPE_WMMQSTATUS:
++ pTlvWmmQStatus = (MrvlIEtypes_WmmQueueStatus_t *) pTlvHdr;
++ PRINTM(INFO,
++ "CMD_RESP: WMM_GET_STATUS: QSTATUS TLV: %d, %d, %d\n",
++ pTlvWmmQStatus->QueueIndex, pTlvWmmQStatus->FlowRequired,
++ pTlvWmmQStatus->Disabled);
++
++ pACStatus = &Adapter->wmm.acStatus[pTlvWmmQStatus->QueueIndex];
++ pACStatus->Disabled = pTlvWmmQStatus->Disabled;
++ pACStatus->FlowRequired = pTlvWmmQStatus->FlowRequired;
++ pACStatus->FlowCreated = pTlvWmmQStatus->FlowCreated;
++ break;
++
++ case WMM_IE:
++ /*
++ * Point the regular IEEE IE 2 bytes into the Marvell IE
++ * and setup the IEEE IE type and length byte fields
++ */
++
++ HEXDUMP("WMM: WMM TLV:", (u8 *) pTlvHdr, pTlvHdr->Header.Len + 4);
++
++ pWmmParamIe = (IEEEtypes_WmmParameter_t *) (pCurrent + 2);
++ pWmmParamIe->VendHdr.Len = pTlvHdr->Header.Len;
++ pWmmParamIe->VendHdr.ElementId = WMM_IE;
++
++ PRINTM(INFO, "CMD_RESP: WMM_GET_STATUS: WMM Parameter Set: %d\n",
++ pWmmParamIe->QoSInfo.ParaSetCount);
++
++ memcpy((u8 *) & Adapter->CurBssParams.BSSDescriptor.wmmIE,
++ pWmmParamIe, pWmmParamIe->VendHdr.Len + 2);
++
++ break;
++
++ default:
++ valid = FALSE;
++ break;
++ }
++
++ pCurrent += (pTlvHdr->Header.Len + sizeof(pTlvHdr->Header));
++ respLen -= (pTlvHdr->Header.Len + sizeof(pTlvHdr->Header));
++ }
++
++ wmm_setup_queue_priorities(priv);
++ wmm_setup_ac_downgrade(priv);
++
++ if (enableData) {
++ wmm_start_queue(priv);
++ os_carrier_on(priv);
++ os_start_queue(priv);
++ }
++
++ send_iwevcustom_event(priv, WMM_CONFIG_CHANGE_INDICATION);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Call back from the command module to allow insertion of a WMM TLV
++ *
++ * If the BSS we are associating to supports WMM, add the required WMM
++ * Information IE to the association request command buffer in the form
++ * of a Marvell extended IEEE IE.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param ppAssocBuf Output parameter: Pointer to the TLV output buffer,
++ * modified on return to point after the appended WMM TLV
++ * @param pWmmIE Pointer to the WMM IE for the BSS we are joining
++ *
++ * @return Length of data appended to the association tlv buffer
++ */
++u32
++wlan_wmm_process_association_req(wlan_private * priv,
++ u8 ** ppAssocBuf,
++ IEEEtypes_WmmParameter_t * pWmmIE)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ MrvlIEtypes_WmmParamSet_t *pWmmTlv;
++ u32 retLen = 0;
++
++ /* Null checks */
++ if (ppAssocBuf == 0)
++ return 0;
++ if (*ppAssocBuf == 0)
++ return 0;
++ if (pWmmIE == 0)
++ return 0;
++
++ PRINTM(INFO, "WMM: process assoc req: bss->wmmIe=%x\n",
++ pWmmIE->VendHdr.ElementId);
++
++ if (Adapter->wmm.required && pWmmIE->VendHdr.ElementId == WMM_IE) {
++ pWmmTlv = (MrvlIEtypes_WmmParamSet_t *) * ppAssocBuf;
++ pWmmTlv->Header.Type = (u16) wmm_info_ie[0];
++ pWmmTlv->Header.Type = wlan_cpu_to_le16(pWmmTlv->Header.Type);
++ pWmmTlv->Header.Len = (u16) wmm_info_ie[1];
++ pWmmTlv->Header.Len = wlan_cpu_to_le16(pWmmTlv->Header.Len);
++
++ memcpy(pWmmTlv->WmmIE, &wmm_info_ie[2], pWmmTlv->Header.Len);
++#define QOS_INFO_PARA_MASK 0x0f
++ if (pWmmIE->QoSInfo.QosUAPSD
++ && ((Adapter->wmm.qosinfo & QOS_INFO_PARA_MASK) != 0)) {
++ memcpy((u8 *) (pWmmTlv->WmmIE + pWmmTlv->Header.Len
++ - sizeof(Adapter->wmm.qosinfo)),
++ &Adapter->wmm.qosinfo, sizeof(Adapter->wmm.qosinfo));
++ }
++ retLen = sizeof(pWmmTlv->Header) + pWmmTlv->Header.Len;
++
++ HEXDUMP("ASSOC_CMD: WMM IE", (u8 *) pWmmTlv, retLen);
++ *ppAssocBuf += retLen;
++ }
++
++ return retLen;
++}
++
++/**
++ * @brief Compute the time delay in the driver queues for a given skb.
++ *
++ * When the skb is received at the OS/Driver interface, the current
++ * time is set in the skb structure. The difference between the present
++ * time and that received time is computed in this function and limited
++ * based on pre-compiled limits in the driver.
++ *
++ * @param skb Pointer to a sk_buff which has been previously timestamped
++ *
++ * @return Time delay of the packet in 2ms units after having limit applied
++ */
++u8
++wmm_compute_driver_packet_delay(const struct sk_buff * skb)
++{
++ u8 retVal;
++ struct timeval in_tv;
++ struct timeval out_tv;
++ int queue_delay;
++
++ retVal = 0;
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
++ skb_get_timestamp(skb, &in_tv);
++#else
++ memcpy(&in_tv, &skb->stamp, sizeof(in_tv));
++#endif
++ do_gettimeofday(&out_tv);
++
++ queue_delay = timeval_diff_in_ms(&out_tv, &in_tv);
++
++ /* Queue delay is passed as a uint8 in units of 2ms (ms shifted
++ * by 1). Min value (other than 0) is therefore 2ms, max is 510ms.
++ *
++ * Pass max value if queue_delay is beyond the uint8 range
++ */
++ retVal = MIN(queue_delay, DRV_PKT_DELAY_TO_FW_LIMIT) >> 1;
++
++ PRINTM(DATA, "WMM: Pkt Delay: %d ms, %d ms sent to FW\n",
++ queue_delay, retVal);
++
++ return retVal;
++}
++
++/**
++ * @brief Transmit the highest priority packet awaiting in the WMM Queues
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ *
++ * @return void
++ */
++void
++wmm_process_tx(wlan_private * priv)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ ulong flags;
++
++ OS_INTERRUPT_SAVE_AREA;
++
++ ENTER();
++
++ if ((Adapter->PSState == PS_STATE_SLEEP)
++ || (Adapter->PSState == PS_STATE_PRE_SLEEP)) {
++ PRINTM(INFO, "In PS State %d"
++ " - Not sending the packet\n", Adapter->PSState);
++ LEAVE();
++
++ return;
++ }
++
++ spin_lock_irqsave(&Adapter->CurrentTxLock, flags);
++
++ if (priv->wlan_dev.dnld_sent) {
++ spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
++
++ LEAVE();
++
++ return;
++ }
++
++ UpdateTransStart(priv->wlan_dev.netdev);
++ wmm_pop_highest_prio_skb(priv);
++
++ spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
++
++ if (Adapter->CurrentTxSkb) {
++ wlan_process_tx(priv);
++ }
++
++ LEAVE();
++}
++
++/**
++ * @brief Private IOCTL entry to get the status of the WMM queues
++ *
++ * Return the following information for each WMM AC:
++ * - WMM IE Acm Required
++ * - Firmware Flow Required
++ * - Firmware Flow Established
++ * - Firmware Queue Enabled
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param wrq A pointer to iwreq structure containing the
++ * wlan_ioctl_wmm_queue_status_t struct for request
++ *
++ * @return 0 if successful; IOCTL error code otherwise
++ */
++int
++wlan_wmm_queue_status_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_adapter *Adapter = priv->adapter;
++ wlan_ioctl_wmm_queue_status_t qstatus;
++ wlan_wmm_ac_e acVal;
++ WmmAcStatus_t *pACStatus;
++ IEEEtypes_WmmAcParameters_t *pWmmIeAC;
++
++ for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) {
++ pACStatus = &Adapter->wmm.acStatus[acVal];
++ pWmmIeAC = &Adapter->CurBssParams.BSSDescriptor.wmmIE.AcParams[acVal];
++
++ /* Acm bit */
++ qstatus.acStatus[acVal].wmmAcm = pWmmIeAC->AciAifsn.Acm;
++
++ /* Firmware status */
++ qstatus.acStatus[acVal].flowRequired = pACStatus->FlowRequired;
++ qstatus.acStatus[acVal].flowCreated = pACStatus->FlowCreated;
++ qstatus.acStatus[acVal].disabled = pACStatus->Disabled;
++ }
++
++ if (copy_to_user(wrq->u.data.pointer, &qstatus, sizeof(qstatus))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Private IOCTL entry to send an ADDTS TSPEC
++ *
++ * Receive a ADDTS command from the application. The command structure
++ * contains a TSPEC and timeout in milliseconds. The timeout is performed
++ * in the firmware after the ADDTS command frame is sent.
++ *
++ * The TSPEC is received in the API as an opaque block whose length is
++ * calculated from the IOCTL data length. The firmware will send the
++ * entire data block, including the bytes after the TSPEC. This is done
++ * to allow extra IEs to be packaged with the TSPEC in the ADDTS action
++ * frame.
++ *
++ * The IOCTL structure contains two return fields:
++ * - The firmware command result which indicates failure and timeouts
++ * - The IEEE Status code which contains the corresponding value from
++ * any ADDTS response frame received.
++ *
++ * In addition, the opaque TSPEC data block passed in is replaced with the
++ * TSPEC recieved in the ADDTS response frame. In case of failure, the
++ * AP may modify the TSPEC on return and in the case of success, the
++ * medium time is returned as calculated by the AP. Along with the TSPEC,
++ * any IEs that are sent in the ADDTS response are also returned and can be
++ * parsed using the IOCTL length as an indicator of extra elements.
++ *
++ * The return value to the application layer indicates a driver execution
++ * success or failure. A successful return could still indicate a firmware
++ * failure or AP negotiation failure via the commandResult field copied
++ * back to the application.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param wrq A pointer to iwreq structure containing the
++ * wlan_ioctl_wmm_addts_req_t struct for this ADDTS request
++ *
++ * @return 0 if successful; IOCTL error code otherwise
++ */
++int
++wlan_wmm_addts_req_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ static u8 dialogTok = 0;
++ wlan_ioctl_wmm_addts_req_t addtsIoctl;
++ wlan_cmd_wmm_addts_req_t addtsCmd;
++ int retcode;
++
++ if (copy_from_user(&addtsIoctl,
++ wrq->u.data.pointer,
++ MIN(wrq->u.data.length, sizeof(addtsIoctl))) != 0) {
++ /* copy_from_user failed */
++ PRINTM(INFO, "TSPEC: ADDTS copy from user failed\n");
++ retcode = -EFAULT;
++
++ } else {
++ memset(&addtsCmd, 0x00, sizeof(addtsCmd));
++ if ((++dialogTok) == 0)
++ dialogTok = 1;
++
++ addtsCmd.dialogToken = dialogTok;
++ addtsCmd.timeout_ms = addtsIoctl.timeout_ms;
++ addtsCmd.tspecDataLen = (wrq->u.data.length
++ - sizeof(addtsCmd.timeout_ms)
++ - sizeof(addtsCmd.commandResult)
++ - sizeof(addtsCmd.ieeeStatusCode));
++ memcpy(addtsCmd.tspecData,
++ addtsIoctl.tspecData, addtsCmd.tspecDataLen);
++
++ retcode = PrepareAndSendCommand(priv,
++ HostCmd_CMD_WMM_ADDTS_REQ, 0,
++ HostCmd_OPTION_WAITFORRSP, 0,
++ &addtsCmd);
++
++ wrq->u.data.length = (sizeof(addtsIoctl.timeout_ms)
++ + sizeof(addtsIoctl.commandResult)
++ + sizeof(addtsIoctl.ieeeStatusCode)
++ + addtsCmd.tspecDataLen);
++
++ addtsIoctl.commandResult = addtsCmd.commandResult;
++ addtsIoctl.ieeeStatusCode = addtsCmd.ieeeStatusCode;
++ memcpy(addtsIoctl.tspecData,
++ addtsCmd.tspecData, addtsCmd.tspecDataLen);
++
++ if (copy_to_user(wrq->u.data.pointer,
++ &addtsIoctl, sizeof(addtsIoctl))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++
++ if (retcode) {
++ return -EFAULT;
++ }
++ }
++
++ return retcode;
++}
++
++/**
++ * @brief Private IOCTL entry to send a DELTS TSPEC
++ *
++ * Receive a DELTS command from the application. The command structure
++ * contains a TSPEC and reason code along with space for a command result
++ * to be returned. The information is packaged is sent to the wlan_cmd.c
++ * firmware command prep and send routines for execution in the firmware.
++ *
++ * The reason code is not used for WMM implementations but is indicated in
++ * the 802.11e specification.
++ *
++ * The return value to the application layer indicates a driver execution
++ * success or failure. A successful return could still indicate a firmware
++ * failure via the commandResult field copied back to the application.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param wrq A pointer to iwreq structure containing the
++ * wlan_ioctl_wmm_delts_req_t struct for this DELTS request
++ *
++ * @return 0 if successful; IOCTL error code otherwise
++ */
++int
++wlan_wmm_delts_req_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_ioctl_wmm_delts_req_t deltsIoctl;
++ wlan_cmd_wmm_delts_req_t deltsCmd;
++ int retcode;
++
++ if (copy_from_user(&deltsIoctl,
++ wrq->u.data.pointer,
++ MIN(wrq->u.data.length, sizeof(deltsIoctl))) != 0) {
++ /* copy_from_user failed */
++ PRINTM(INFO, "TSPEC: DELTS copy from user failed\n");
++ retcode = -EFAULT;
++
++ } else {
++ memset(&deltsCmd, 0x00, sizeof(deltsCmd));
++
++ /* Dialog token unused for WMM implementations */
++ deltsCmd.dialogToken = 0;
++
++ deltsCmd.ieeeReasonCode = deltsIoctl.ieeeReasonCode;
++
++ /* Calculate the length of the TSPEC and any other IEs */
++ deltsCmd.tspecDataLen = (wrq->u.data.length
++ - sizeof(deltsCmd.commandResult)
++ - sizeof(deltsCmd.ieeeReasonCode));
++ memcpy(deltsCmd.tspecData,
++ deltsIoctl.tspecData, deltsCmd.tspecDataLen);
++
++ /* Send the DELTS request to firmware, wait for a response */
++ retcode = PrepareAndSendCommand(priv,
++ HostCmd_CMD_WMM_DELTS_REQ, 0,
++ HostCmd_OPTION_WAITFORRSP, 0,
++ &deltsCmd);
++
++ /* Return the firmware command result back to the application layer */
++ deltsIoctl.commandResult = deltsCmd.commandResult;
++
++ if (copy_to_user(wrq->u.data.pointer,
++ &deltsCmd,
++ MIN(wrq->u.data.length, sizeof(deltsIoctl)))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ return -EFAULT;
++ }
++
++ if (retcode) {
++ retcode = -EFAULT;
++ }
++ }
++
++ return retcode;
++}
++
++/**
++ * @brief Process the ADDTS_REQ command response from firmware
++ *
++ * Return the ADDTS firmware response to the calling thread that sent
++ * the command. The result is then relayed back the app layer.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param resp Pointer to the command response buffer including the
++ * command result and any returned ADDTS response TSPEC
++ * elements
++ *
++ * @return WLAN_STATUS_SUCCESS
++ *
++ * @sa wlan_wmm_addts_req_ioctl
++ */
++int
++wlan_cmdresp_wmm_addts_req(wlan_private * priv,
++ const HostCmd_DS_COMMAND * resp)
++{
++ wlan_cmd_wmm_addts_req_t *pAddTsCmd;
++ const HostCmd_DS_WMM_ADDTS_REQ *pCmdResp;
++
++ /* Cast the NULL pointer of the buffer the IOCTL sent in the command req */
++ pAddTsCmd = (wlan_cmd_wmm_addts_req_t *) priv->adapter->CurCmd->pdata_buf;
++
++ /* Convenience variable for the ADDTS response from the firmware */
++ pCmdResp = &resp->params.addTsReq;
++
++ /* Assign return data */
++ pAddTsCmd->commandResult = pCmdResp->commandResult;
++
++ if (pCmdResp->commandResult == TSPEC_RESULT_SUCCESS) {
++ pAddTsCmd->dialogToken = pCmdResp->dialogToken;
++ pAddTsCmd->ieeeStatusCode = pCmdResp->ieeeStatusCode;
++
++ /* The tspecData field is potentially variable in size due to extra IEs
++ * that may have been in the ADDTS response action frame. Calculate
++ * the data length from the firmware command response.
++ */
++ pAddTsCmd->tspecDataLen = (resp->Size
++ - sizeof(pCmdResp->commandResult)
++ - sizeof(pCmdResp->timeout_ms)
++ - sizeof(pCmdResp->dialogToken)
++ - sizeof(pCmdResp->ieeeStatusCode)
++ - S_DS_GEN);
++
++ /* Copy the TSPEC data include any extra IEs after the TSPEC */
++ memcpy(pAddTsCmd->tspecData,
++ pCmdResp->tspecData,
++ MIN(pAddTsCmd->tspecDataLen, sizeof(pAddTsCmd->tspecData)
++ + sizeof(pAddTsCmd->addtsExtraIEBuf)));
++ } else {
++ pAddTsCmd->dialogToken = 0;
++ pAddTsCmd->ieeeStatusCode = 0;
++ pAddTsCmd->tspecDataLen = 0;
++ }
++
++ PRINTM(INFO, "TSPEC: ADDTS ret = %d,%d sz=%d\n",
++ pAddTsCmd->commandResult, pAddTsCmd->ieeeStatusCode,
++ pAddTsCmd->tspecDataLen);
++
++ HEXDUMP("TSPEC: ADDTS data",
++ pAddTsCmd->tspecData, pAddTsCmd->tspecDataLen);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Process the DELTS_REQ command response from firmware
++ *
++ * Return the DELTS firmware response to the calling thread that sent
++ * the command. The result is then relayed back the app layer.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param resp Pointer to the command response buffer with the command
++ * result. No other response information is passed back
++ * to the driver.
++ *
++ * @return WLAN_STATUS_SUCCESS
++ *
++ * @sa wlan_wmm_delts_req_ioctl
++ */
++int
++wlan_cmdresp_wmm_delts_req(wlan_private * priv,
++ const HostCmd_DS_COMMAND * resp)
++{
++ wlan_cmd_wmm_delts_req_t *pDelTsCmd;
++
++ /* Cast the NULL pointer of the buffer the IOCTL sent in the command req */
++ pDelTsCmd = (wlan_cmd_wmm_delts_req_t *) priv->adapter->CurCmd->pdata_buf;
++
++ pDelTsCmd->commandResult =
++ wlan_le16_to_cpu(resp->params.delTsReq.commandResult);
++
++ PRINTM(INFO, "TSPEC: DELTS result = %d\n", pDelTsCmd->commandResult);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Implement cmd HostCmd_DS_WMM_ADDTS_REQ
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param cmd Pointer to CMD buffer
++ * @param InfoBuf Pointer to cmd data
++ *
++ * @return WLAN_STATUS_SUCCESS
++ *
++ * @sa wlan_wmm_addts_req_ioctl
++ */
++int
++wlan_cmd_wmm_addts_req(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *InfoBuf)
++{
++ wlan_cmd_wmm_addts_req_t *pAddTsCmd;
++ int tspecCopySize;
++
++ pAddTsCmd = (wlan_cmd_wmm_addts_req_t *) InfoBuf;
++
++ cmd->params.addTsReq.timeout_ms = pAddTsCmd->timeout_ms;
++ cmd->params.addTsReq.dialogToken = pAddTsCmd->dialogToken;
++
++ tspecCopySize = MIN(pAddTsCmd->tspecDataLen,
++ sizeof(cmd->params.addTsReq.tspecData));
++ memcpy(&cmd->params.addTsReq.tspecData,
++ pAddTsCmd->tspecData, tspecCopySize);
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_ADDTS_REQ);
++ cmd->Size = wlan_cpu_to_le16(sizeof(cmd->params.addTsReq.dialogToken)
++ + sizeof(cmd->params.addTsReq.timeout_ms)
++ + sizeof(cmd->params.addTsReq.commandResult)
++ + sizeof(cmd->params.addTsReq.ieeeStatusCode)
++ + tspecCopySize + S_DS_GEN);
++
++ cmd->params.addTsReq.timeout_ms
++ = wlan_cpu_to_le32(cmd->params.addTsReq.timeout_ms);
++
++ PRINTM(INFO, "WMM: ADDTS Cmd: Data Len = %d\n", pAddTsCmd->tspecDataLen);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Implement cmd HostCmd_DS_WMM_DELTS_REQ
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param cmd Pointer to CMD buffer
++ * @param InfoBuf Void pointer cast of a wlan_cmd_wmm_delts_req_t struct
++ *
++ * @return WLAN_STATUS_SUCCESS
++ *
++ * @sa wlan_wmm_delts_req_ioctl
++ */
++int
++wlan_cmd_wmm_delts_req(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *InfoBuf)
++{
++ wlan_cmd_wmm_delts_req_t *pDelTsCmd;
++ int tspecCopySize;
++
++ pDelTsCmd = (wlan_cmd_wmm_delts_req_t *) InfoBuf;
++
++ cmd->params.delTsReq.dialogToken = pDelTsCmd->dialogToken;
++ cmd->params.delTsReq.ieeeReasonCode = pDelTsCmd->ieeeReasonCode;
++
++ tspecCopySize = MIN(pDelTsCmd->tspecDataLen,
++ sizeof(cmd->params.delTsReq.tspecData));
++ memcpy(&cmd->params.delTsReq.tspecData,
++ pDelTsCmd->tspecData, tspecCopySize);
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_DELTS_REQ);
++ cmd->Size = wlan_cpu_to_le16(sizeof(cmd->params.delTsReq.dialogToken)
++ + sizeof(cmd->params.delTsReq.commandResult)
++ + sizeof(cmd->params.delTsReq.ieeeReasonCode)
++ + tspecCopySize + S_DS_GEN);
++
++ PRINTM(INFO, "WMM: DELTS Cmd prepared\n");
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Prepare the firmware command buffer for the WMM_QUEUE_CONFIG command
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param cmd Pointer to CMD buffer
++ * @param InfoBuf Void pointer cast of a wlan_cmd_wmm_queue_config_t struct
++ *
++ * @return WLAN_STATUS_SUCCESS
++ */
++int
++wlan_cmd_wmm_queue_config(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *InfoBuf)
++{
++ wlan_cmd_wmm_queue_config_t *pQConfigCmd;
++ int tlvCopySize;
++
++ pQConfigCmd = (wlan_cmd_wmm_queue_config_t *) InfoBuf;
++
++ cmd->params.queueConfig.action = pQConfigCmd->action;
++ cmd->params.queueConfig.accessCategory = pQConfigCmd->accessCategory;
++ cmd->params.queueConfig.msduLifetimeExpiry
++ = wlan_cpu_to_le16(pQConfigCmd->msduLifetimeExpiry);
++
++ tlvCopySize = MIN(pQConfigCmd->tlvBufLen,
++ sizeof(cmd->params.queueConfig.tlvBuffer));
++ memcpy(&cmd->params.queueConfig.tlvBuffer,
++ pQConfigCmd->tlvBuffer, tlvCopySize);
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_CONFIG);
++ cmd->Size = wlan_cpu_to_le16(sizeof(cmd->params.queueConfig.action)
++ +
++ sizeof(cmd->params.queueConfig.
++ accessCategory)
++ +
++ sizeof(cmd->params.queueConfig.
++ msduLifetimeExpiry)
++ + tlvCopySize + S_DS_GEN);
++
++ PRINTM(INFO, "WMM: QUEUE CONFIG Cmd prepared\n");
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Process the WMM_QUEUE_CONFIG command response from firmware
++ *
++ * Return the firmware command response to the blocked IOCTL caller function.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param resp Pointer to the command response buffer with:
++ * - action code
++ * - access category
++ * - collected statistics if requested
++ *
++ * @return WLAN_STATUS_SUCCESS
++ *
++ * @sa wlan_wmm_queue_config_ioctl
++ */
++int
++wlan_cmdresp_wmm_queue_config(wlan_private * priv,
++ const HostCmd_DS_COMMAND * resp)
++{
++ wlan_cmd_wmm_queue_config_t *pQConfigCmd;
++ const HostCmd_DS_WMM_QUEUE_CONFIG *pCmdResp;
++
++ pQConfigCmd =
++ (wlan_cmd_wmm_queue_config_t *) (priv->adapter->CurCmd->pdata_buf);
++ pCmdResp = &resp->params.queueConfig;
++
++ pQConfigCmd->action = pCmdResp->action;
++ pQConfigCmd->accessCategory = pCmdResp->accessCategory;
++ pQConfigCmd->msduLifetimeExpiry
++ = wlan_le16_to_cpu(pCmdResp->msduLifetimeExpiry);
++
++ pQConfigCmd->tlvBufLen = (resp->Size - sizeof(pCmdResp->action)
++ - sizeof(pCmdResp->accessCategory)
++ - sizeof(pCmdResp->msduLifetimeExpiry)
++ - S_DS_GEN);
++
++ memcpy(pQConfigCmd->tlvBuffer,
++ pCmdResp->tlvBuffer, pQConfigCmd->tlvBufLen);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Private IOCTL entry to get/set a specified AC Queue's parameters
++ *
++ * Receive a AC Queue configuration command which is used to get, set, or
++ * default the parameters associated with a specific WMM AC Queue.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param wrq A pointer to iwreq structure containing the
++ * wlan_ioctl_wmm_queue_config_t struct
++ *
++ * @return 0 if successful; IOCTL error code otherwise
++ */
++int
++wlan_wmm_queue_config_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_ioctl_wmm_queue_config_t queueConfigIoctl;
++ wlan_cmd_wmm_queue_config_t queueConfigCmd;
++ int retcode;
++
++ PRINTM(INFO, "WMM: Queue Config IOCTL Enter\n");
++
++ if (copy_from_user(&queueConfigIoctl,
++ wrq->u.data.pointer,
++ MIN(wrq->u.data.length,
++ sizeof(queueConfigIoctl))) != 0) {
++ /* copy_from_user failed */
++ PRINTM(INFO, "WMM: Queue Config: copy from user failed\n");
++ retcode = -EFAULT;
++
++ } else {
++ memset(&queueConfigCmd, 0x00, sizeof(queueConfigCmd));
++
++ queueConfigCmd.action = queueConfigIoctl.action;
++ queueConfigCmd.accessCategory = queueConfigIoctl.accessCategory;
++ queueConfigCmd.msduLifetimeExpiry
++ = queueConfigIoctl.msduLifetimeExpiry;
++
++ /* Create a rates TLV from the supportedRates[] ioctl field */
++ queueConfigCmd.tlvBufLen = 0;
++
++ retcode = PrepareAndSendCommand(priv,
++ HostCmd_CMD_WMM_QUEUE_CONFIG, 0,
++ HostCmd_OPTION_WAITFORRSP, 0,
++ &queueConfigCmd);
++ if (retcode) {
++ retcode = -EFAULT;
++ } else {
++ memset(&queueConfigIoctl, 0x00, sizeof(queueConfigIoctl));
++
++ queueConfigIoctl.action = queueConfigCmd.action;
++ queueConfigIoctl.accessCategory = queueConfigCmd.accessCategory;
++ queueConfigIoctl.msduLifetimeExpiry
++ = queueConfigCmd.msduLifetimeExpiry;
++
++ wrq->u.data.length = sizeof(queueConfigIoctl);
++
++ if (copy_to_user(wrq->u.data.pointer,
++ &queueConfigIoctl, sizeof(queueConfigIoctl))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ retcode = -EFAULT;
++ }
++ }
++ }
++
++ return retcode;
++}
++
++/**
++ * @brief Prepare the firmware command buffer for the WMM_QUEUE_STATS command
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param cmd pointer to CMD buffer
++ * @param InfoBuf void pointer cast of a HostCmd_CMD_WMM_QUEUE_STATS struct
++ *
++ * @return WLAN_STATUS_SUCCESS
++ */
++int
++wlan_cmd_wmm_queue_stats(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *InfoBuf)
++{
++ memcpy(&cmd->params.queueStats, InfoBuf, sizeof(cmd->params.queueStats));
++
++ cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_STATS);
++ cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_QUEUE_STATS)
++ + S_DS_GEN);
++
++ PRINTM(INFO, "WMM: QUEUE STATS Cmd prepared\n");
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Process the WMM_QUEUE_STATS command response from firmware
++ *
++ * Return the firmware command response to the blocked IOCTL caller function.
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param resp Pointer to the command response buffer with:
++ * - action code
++ * - access category
++ * - collected statistics if requested
++ *
++ * @return WLAN_STATUS_SUCCESS
++ *
++ * @sa wlan_wmm_queue_stats_ioctl
++ */
++int
++wlan_cmdresp_wmm_queue_stats(wlan_private * priv,
++ const HostCmd_DS_COMMAND * resp)
++{
++ HostCmd_DS_WMM_QUEUE_STATS *pQueueStats =
++ (HostCmd_DS_WMM_QUEUE_STATS *) priv->adapter->CurCmd->pdata_buf;
++
++ memcpy(pQueueStats, &resp->params.queueStats, (resp->Size - S_DS_GEN));
++
++ pQueueStats->pktCount = wlan_le16_to_cpu(pQueueStats->pktCount);
++ pQueueStats->pktLoss = wlan_le16_to_cpu(pQueueStats->pktLoss);
++ pQueueStats->avgQueueDelay = wlan_le32_to_cpu(pQueueStats->avgQueueDelay);
++ pQueueStats->avgTxDelay = wlan_le32_to_cpu(pQueueStats->avgTxDelay);
++ pQueueStats->usedTime = wlan_le32_to_cpu(pQueueStats->usedTime);
++
++ PRINTM(INFO, "WMM: Queue Stats response: %d\n", resp->Size - S_DS_GEN);
++
++ return WLAN_STATUS_SUCCESS;
++}
++
++/**
++ * @brief Private IOCTL entry to get and start/stop queue stats on a WMM AC
++ *
++ * Receive a AC Queue statistics command from the application for a specific
++ * WMM AC. The command can:
++ * - Turn stats on
++ * - Turn stats off
++ * - Collect and clear the stats
++ *
++ * @param priv Pointer to the wlan_private driver data struct
++ * @param wrq A pointer to iwreq structure containing the
++ * wlan_ioctl_wmm_queue_stats_t struct
++ *
++ * @return 0 if successful; IOCTL error code otherwise
++ */
++int
++wlan_wmm_queue_stats_ioctl(wlan_private * priv, struct iwreq *wrq)
++{
++ wlan_ioctl_wmm_queue_stats_t queueStatsIoctl;
++ HostCmd_DS_WMM_QUEUE_STATS queueStatsCmd;
++ int retcode;
++
++ if (copy_from_user(&queueStatsIoctl,
++ wrq->u.data.pointer,
++ MIN(wrq->u.data.length,
++ sizeof(queueStatsIoctl))) != 0) {
++ /* copy_from_user failed */
++ PRINTM(INFO, "WMM: Queue Stats: copy from user failed\n");
++ retcode = -EFAULT;
++
++ } else {
++ memcpy(&queueStatsCmd, &queueStatsIoctl, sizeof(queueStatsIoctl));
++
++ PRINTM(INFO, "WMM: QUEUE STATS Ioctl: %d, %d\n",
++ queueStatsCmd.action, queueStatsCmd.accessCategory);
++
++ retcode = PrepareAndSendCommand(priv,
++ HostCmd_CMD_WMM_QUEUE_STATS, 0,
++ HostCmd_OPTION_WAITFORRSP, 0,
++ &queueStatsCmd);
++ if (retcode) {
++ retcode = -EFAULT;
++ } else {
++ if (copy_to_user(wrq->u.data.pointer,
++ &queueStatsCmd,
++ MIN(wrq->u.data.length,
++ sizeof(queueStatsCmd)))) {
++ PRINTM(INFO, "Copy to user failed\n");
++ retcode = -EFAULT;
++ }
++ }
++ }
++
++ if (retcode != WLAN_STATUS_SUCCESS) {
++ PRINTM(INFO, "WMM: QUEUE STATS Ioctl FAILED: %d, %d\n",
++ queueStatsIoctl.action, queueStatsIoctl.accessCategory);
++ }
++
++ return retcode;
++}
+diff --git a/drivers/net/wireless/marvell8686/wlan_wmm.h b/drivers/net/wireless/marvell8686/wlan_wmm.h
+new file mode 100644
+index 0000000..97c24db
+--- /dev/null
++++ b/drivers/net/wireless/marvell8686/wlan_wmm.h
+@@ -0,0 +1,111 @@
++/** @file wlan_wmm.h
++ * @brief This file contains related macros, enum, and struct
++ * of wmm functionalities
++ *
++ * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2006
++ */
++/****************************************************
++Change log:
++ 09/26/05: add Doxygen format comments
++ 04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
++****************************************************/
++
++#ifndef __WLAN_WMM_H
++#define __WLAN_WMM_H
++
++/** Custom indiciation message sent to the application layer for WMM changes */
++#define WMM_CONFIG_CHANGE_INDICATION "WMM_CONFIG_CHANGE.indication"
++
++/** Highest priority setting for a packet (uses voice AC) */
++#define WMM_HIGHEST_PRIORITY 7
++
++#ifdef __KERNEL__
++
++/** struct of WMM DESC */
++typedef struct
++{
++ u8 required;
++ u8 enabled;
++ u8 packetsQueued;
++ u8 queueStopped;
++ u32 packetsOut[MAX_AC_QUEUES];
++ u32 userPriPktTxCtrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */
++
++ struct sk_buff txSkbQ[MAX_AC_QUEUES];
++ WmmAcStatus_t acStatus[MAX_AC_QUEUES];
++ wlan_wmm_ac_e acDowngradedVals[MAX_AC_QUEUES];
++
++ /** wmm queue priority table*/
++ u8 queuePriority[MAX_AC_QUEUES];
++
++ u8 qosinfo;
++} __ATTRIB_PACK__ WMM_DESC;
++
++extern void wmm_map_and_add_skb(wlan_private * priv, struct sk_buff *);
++extern u8 wmm_compute_driver_packet_delay(const struct sk_buff *skb);
++#endif
++
++extern int sendWMMStatusChangeCmd(wlan_private * priv);
++extern int wmm_lists_empty(wlan_private * priv);
++extern void wmm_cleanup_queues(wlan_private * priv);
++extern void wmm_process_tx(wlan_private * priv);
++
++extern void wmm_init(wlan_private * priv);
++extern void wmm_setup_queues(wlan_private * priv);
++extern void wmm_start_queue(wlan_private * priv);
++extern void wmm_stop_queue(wlan_private * priv);
++extern int wmm_is_queue_stopped(wlan_private * priv);
++
++extern void wmm_process_fw_iface_tx_xfer_start(wlan_private * priv);
++extern void wmm_process_fw_iface_tx_xfer_end(wlan_private * priv);
++extern void wmm_process_app_iface_tx(wlan_private * priv);
++extern wlan_wmm_ac_e wmm_convert_tos_to_ac(int tos);
++extern wlan_wmm_ac_e wmm_downgrade_ac(wlan_private * priv,
++ wlan_wmm_ac_e acVal);
++
++extern u32 wlan_wmm_process_association_req(wlan_private * priv,
++ u8 ** ppAssocBuf,
++ IEEEtypes_WmmParameter_t *
++ pWmmIE);
++
++/*
++ * Functions used in the cmd handling routine
++ */
++extern int wlan_cmd_wmm_get_status(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *InfoBuf);
++extern int wlan_cmd_wmm_addts_req(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *InfoBuf);
++extern int wlan_cmd_wmm_delts_req(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *InfoBuf);
++extern int wlan_cmd_wmm_queue_config(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *InfoBuf);
++extern int wlan_cmd_wmm_queue_stats(wlan_private * priv,
++ HostCmd_DS_COMMAND * cmd, void *InfoBuf);
++
++/*
++ * Functions used in the cmdresp handling routine
++ */
++extern int wlan_cmdresp_wmm_get_status(wlan_private * priv,
++ const HostCmd_DS_COMMAND * resp);
++extern int wlan_cmdresp_wmm_addts_req(wlan_private * priv,
++ const HostCmd_DS_COMMAND * resp);
++extern int wlan_cmdresp_wmm_delts_req(wlan_private * priv,
++ const HostCmd_DS_COMMAND * resp);
++extern int wlan_cmdresp_wmm_queue_config(wlan_private * priv,
++ const HostCmd_DS_COMMAND * resp);
++extern int wlan_cmdresp_wmm_queue_stats(wlan_private * priv,
++ const HostCmd_DS_COMMAND * resp);
++
++/*
++ * IOCTLs
++ */
++extern int wlan_wmm_enable_ioctl(wlan_private * priv, struct iwreq *wrq);
++extern int wlan_wmm_queue_status_ioctl(wlan_private * priv,
++ struct iwreq *wrq);
++
++extern int wlan_wmm_addts_req_ioctl(wlan_private * priv, struct iwreq *wrq);
++extern int wlan_wmm_delts_req_ioctl(wlan_private * priv, struct iwreq *wrq);
++extern int wlan_wmm_queue_config_ioctl(wlan_private * priv,
++ struct iwreq *wrq);
++extern int wlan_wmm_queue_stats_ioctl(wlan_private * priv, struct iwreq *wrq);
++#endif /* __WLAN_WMM_H */
+diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
+index 123092d..4178c2b 100644
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -499,6 +499,15 @@ config RTC_DRV_WM8350
+
+ comment "on-CPU RTC drivers"
+
++config RTC_DRV_TCC
++ tristate "Telechips RTC"
++ depends on ARCH_TCC
++ help
++ RTC (Realtime Clock) driver for the clock inbuilt into the
++ Telechips TCC SoCs.
++ This driver can also be build as a module. If so, the module
++ will be called rtc-tcc.
++
+ config RTC_DRV_OMAP
+ tristate "TI OMAP1"
+ depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730
+diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
+index 6e79c91..51bcb00 100644
+--- a/drivers/rtc/Makefile
++++ b/drivers/rtc/Makefile
+@@ -17,6 +17,11 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
+
+ # Keep the list ordered.
+
++ifeq ($(CONFIG_ARCH_TCC),y)
++$(shell ln -fsn $(CONFIG_TCC_STRING) $(srctree)/drivers/rtc/tcc)
++endif
++obj-$(CONFIG_RTC_DRV_TCC)+= rtc-tcc.o tcc/tca_rtc.o tcc/tca_alarm.o
++
+ obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
+ obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
+ obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
+diff --git a/drivers/rtc/rtc-tcc.c b/drivers/rtc/rtc-tcc.c
+new file mode 100644
+index 0000000..ef2bcf6
+--- /dev/null
++++ b/drivers/rtc/rtc-tcc.c
+@@ -0,0 +1,494 @@
++/*
++ * linux/drivers/serial/tcc-rtc.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: Feb 10, 2009
++ * Description: RTC driver for Telechips TCC Series
++ *
++ * Copyright (C) 2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/string.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/rtc.h>
++#include <linux/bcd.h>
++#include <linux/clk.h>
++#include <linux/log2.h>
++
++#include <mach/hardware.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/delay.h>
++#include <asm/mach/time.h>
++#include <mach/TCC89x_Physical.h>
++#include <bsp.h>
++#include "tcc/tca_alarm.h"
++
++
++//#define pr_debug printk
++#define DRV_NAME "tcc-rtc"
++
++#define RTCCON 0x00
++#define INTCON 0x04
++#define RTCALM 0x08
++#define ALMSEC 0x0C
++#define ALMMIN 0x10
++#define ALMHOUR 0x14
++#define ALMDATE 0x18
++#define ALMDAY 0x1C
++#define ALMMON 0x20
++#define ALMYEAR 0x24
++#define BCDSEC 0x28
++#define BCDMIN 0x2C
++#define BCDHOUR 0x30
++#define BCDDATE 0x34
++#define BCDDAY 0x38
++#define BCDMON 0x3C
++#define BCDYEAR 0x40
++#define RTCIM 0x44
++#define RTCPEND 0x48
++#define RTCSTR 0x4c
++
++#if 0
++#pragma pack(push, 4)
++struct tcc_rtc_regs {
++ volatile unsigned long RTCCON, INTCON, RTCALM,
++ ALMSEC, ALMMIN, ALMHOUR, ALMDATE, ALMDAY, ALMMON, ALMYEAR,
++ BCDSEC, BCDMIN, BCDHOUR, BCDDATE, BCDDAY, BCDMON, BCDYEAR,
++ RTCIM, RTCPEND;
++};
++#pragma pack(pop)
++
++volatile struct tcc_rtc_regs *rtc_regs;
++#endif
++
++static void __iomem *rtc_base;
++static int tcc_rtc_alarmno = NO_IRQ;
++
++
++/* IRQ Handlers */
++
++static irqreturn_t tcc_rtc_alarmirq(int irq, void *id)
++{
++ //printk("[IRQ OK]\n");
++
++ tca_alarm_setint((unsigned int)rtc_base);
++
++ rtc_update_irq(id, 1, RTC_AF | RTC_IRQF);
++
++ return IRQ_HANDLED;
++}
++
++/* Update control registers */
++static void tcc_rtc_setaie(int to)
++{
++ unsigned int tmp;
++
++ pr_debug("%s: aie=%d\n", __func__, to);
++
++ tcc_writel( tcc_readl(rtc_base + RTCCON) | Hw1, rtc_base + RTCCON);
++ tcc_writel( tcc_readl(rtc_base + INTCON) | Hw0, rtc_base + INTCON);
++
++ tmp = tcc_readl(rtc_base + RTCALM) & ~Hw7;
++
++ if (to)
++ tmp |= Hw7;
++
++ tcc_writel(tmp, rtc_base + RTCALM);
++
++ //tcc_writel( tcc_readl(rtc_base + INTCON) & ~Hw0, rtc_base + INTCON);
++ tcc_writel( tcc_readl(rtc_base + RTCCON) & ~Hw1, rtc_base + RTCCON);
++}
++
++
++/* Time read/write */
++static int tcc_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
++{
++ rtctime pTime;
++
++
++ local_irq_disable();
++ tca_rtc_gettime((unsigned int)rtc_base, &pTime);
++
++ rtc_tm->tm_sec = pTime.wSecond;
++ rtc_tm->tm_min = pTime.wMinute;
++ rtc_tm->tm_hour = pTime.wHour;
++ rtc_tm->tm_mday = pTime.wDay;
++ rtc_tm->tm_mon = pTime.wMonth - 1;
++ rtc_tm->tm_year = pTime.wYear - 1900;
++
++ if (rtc_tm->tm_year < 70 || rtc_tm->tm_year > 194
++ || ((unsigned)rtc_tm->tm_mon) >= 12
++ || rtc_tm->tm_mday < 1
++ || rtc_tm->tm_mday > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year + 1900)
++ || ((unsigned)rtc_tm->tm_hour) >= 24
++ || ((unsigned)rtc_tm->tm_min) >= 60
++ || ((unsigned)rtc_tm->tm_sec) >= 60)
++ {
++ printk("KERN_ERR %s: something wrong, force system time to 2009.1.1, 0:0:0\n", __func__);
++ rtc_tm->tm_year = 109;
++ rtc_tm->tm_mon = 0;
++ rtc_tm->tm_mday = 1;
++ rtc_tm->tm_hour = 0;
++ rtc_tm->tm_min = 0;
++ rtc_tm->tm_sec = 0;
++ }
++
++ pr_debug("read time %02d.%02d.%02d %02d/%02d/%02d\n",
++ rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
++ rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
++
++ local_irq_enable();
++
++ return 0;
++}
++
++static int tcc_rtc_settime(struct device *dev, struct rtc_time *tm)
++{
++ rtctime pTime;
++
++ pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n",
++ tm->tm_year, tm->tm_mon, tm->tm_mday,
++ tm->tm_hour, tm->tm_min, tm->tm_sec);
++
++ local_irq_disable();
++
++ pTime.wSecond = tm->tm_sec;
++ pTime.wMinute = tm->tm_min;
++ pTime.wHour = tm->tm_hour;
++ pTime.wDay = tm->tm_mday;
++ pTime.wMonth = tm->tm_mon + 1;
++ pTime.wYear = tm->tm_year + 1900;
++
++ tca_rtc_settime((unsigned int)rtc_base, &pTime);
++
++ local_irq_enable();
++
++ return 0;
++}
++
++static int tcc_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
++{
++ struct rtc_time *alm_tm = &alrm->time;
++ unsigned int alm_en, alm_pnd;
++
++ rtctime pTime;
++
++ pr_debug("%s\n", __func__);
++
++ local_irq_disable();
++
++ tcc_writel( tcc_readl(rtc_base + RTCCON) | Hw1, rtc_base + RTCCON);
++ tcc_writel( tcc_readl(rtc_base + INTCON) | Hw0, rtc_base + INTCON);
++
++ alm_en = tcc_readl(rtc_base + RTCALM);
++ alm_pnd = tcc_readl(rtc_base + RTCPEND);
++
++ alrm->enabled = (alm_en & Hw7) ? 1 : 0;
++ alrm->pending = (alm_pnd & Hw0) ? 1 : 0;
++
++ pr_debug(" alrm->enabled = %d, alm_en = %d\n", alrm->enabled, alm_en);
++
++ tcc_writel( tcc_readl(rtc_base + INTCON) & ~Hw0, rtc_base + INTCON);
++ tcc_writel( tcc_readl(rtc_base + RTCCON) & ~Hw1, rtc_base + RTCCON);
++
++ tca_alarm_gettime((unsigned int)rtc_base, &pTime);
++
++ alm_tm->tm_sec = pTime.wSecond;
++ alm_tm->tm_min = pTime.wMinute;
++ alm_tm->tm_hour = pTime.wHour;
++ alm_tm->tm_mday = pTime.wDay ;
++ alm_tm->tm_mon = pTime.wMonth - 1;
++ alm_tm->tm_year = pTime.wYear - 1900;
++
++ pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",
++ alm_en,
++ alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
++ alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
++
++ local_irq_enable();
++
++ return 0;
++}
++
++static int tcc_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
++{
++ rtctime pTime;
++ struct rtc_time *tm = &alrm->time;
++ pr_debug("%s\n", __func__);
++
++ local_irq_disable();
++
++ alrm->enabled = 1;
++
++ pTime.wSecond = tm->tm_sec;
++ pTime.wMinute = tm->tm_min;
++ pTime.wHour = tm->tm_hour;
++ pTime.wDay = tm->tm_mday;
++ pTime.wMonth = tm->tm_mon + 1;
++ pTime.wYear = tm->tm_year + 1900;
++
++ pr_debug("set alarm %02d.%02d.%02d %02d/%02d/%02d\n",
++ pTime.wSecond, pTime.wMinute, pTime.wHour,
++ pTime.wDay, pTime.wMonth, pTime.wYear);
++
++ tca_alarm_settime((unsigned int)rtc_base, &pTime);
++
++ //tcc_writel( tcc_readl(rtc_base + RTCCON) & ~Hw0, rtc_base + RTCCON);
++ tcc_writel( tcc_readl(rtc_base + RTCCON) | Hw1, rtc_base + RTCCON);
++ tcc_writel( tcc_readl(rtc_base + INTCON) | Hw0, rtc_base + INTCON);
++ //tcc_writel( tcc_readl(rtc_base + INTCON) & ~Hw15, rtc_base + INTCON);
++
++ if (alrm->enabled) {
++ tcc_writel(tcc_readl(rtc_base + RTCALM)| Hw7, rtc_base + RTCALM);
++ enable_irq_wake(tcc_rtc_alarmno);
++ } else {
++ tcc_writel(tcc_readl(rtc_base + RTCALM)& ~Hw7, rtc_base + RTCALM);
++ disable_irq_wake(tcc_rtc_alarmno);
++ }
++
++ tcc_writel( tcc_readl(rtc_base + INTCON) & ~Hw0, rtc_base + INTCON);
++ tcc_writel( tcc_readl(rtc_base + RTCCON) & ~Hw1, rtc_base + RTCCON);
++
++ local_irq_enable();
++
++ return 0;
++}
++
++static int tcc_rtc_proc(struct device *dev, struct seq_file *seq)
++{
++ return 0;
++}
++
++
++static int tcc_rtc_ioctl(struct device *dev,
++ unsigned int cmd, unsigned long arg)
++{
++ unsigned int ret = -ENOIOCTLCMD;
++
++ switch (cmd) {
++ case RTC_AIE_OFF:
++ tcc_rtc_setaie(0);
++ ret = 0;
++ break;
++ case RTC_AIE_ON:
++ tcc_rtc_setaie(1);
++ ret = 0;
++ break;
++ case RTC_PIE_OFF:
++ break;
++ case RTC_PIE_ON:
++ break;
++ case RTC_IRQP_READ:
++ break;
++ case RTC_IRQP_SET:
++ break;
++ case RTC_UIE_ON:
++ break;
++ case RTC_UIE_OFF:
++ break;
++ ret = -EINVAL;
++ }
++
++ return ret;
++}
++
++
++static const struct rtc_class_ops tcc_rtcops = {
++ .read_time = tcc_rtc_gettime,
++ .set_time = tcc_rtc_settime,
++ .read_alarm = tcc_rtc_getalarm,
++ .set_alarm = tcc_rtc_setalarm,
++ .proc = tcc_rtc_proc,
++ .ioctl = tcc_rtc_ioctl,
++};
++
++#if 0
++static void tcc_rtc_enable(struct platform_device *pdev, int en)
++{
++ if (rtc_base == NULL)
++ return;
++
++
++ tca_alarm_setint((unsigned int)rtc_base);
++}
++#endif
++
++static int tcc_rtc_remove(struct platform_device *dev)
++{
++ struct rtc_device *rtc = platform_get_drvdata(dev);
++
++ platform_set_drvdata(dev, NULL);
++ rtc_device_unregister(rtc);
++
++ tcc_rtc_setaie(0);
++
++ free_irq(tcc_rtc_alarmno, rtc);
++
++ return 0;
++}
++
++
++static int tcc_rtc_probe(struct platform_device *pdev)
++{
++ struct rtc_device *rtc;
++ int ret;
++ volatile PIOBUSCFG pIOBUSCFG = (volatile PIOBUSCFG)tcc_p2v(HwIOBUSCFG_BASE);
++ int valid_time = 1;
++
++ // BUS Enable
++ pIOBUSCFG->HCLKEN0 |= Hw26;
++
++ rtc_base = (void __iomem *)tcc_p2v(HwRTC_BASE);
++
++ if (rtc_base == NULL) {
++ printk("failed ioremap()\n");
++ return -ENOMEM;
++ }
++
++
++ // SW Reset
++ if(valid_time)
++ {
++ pIOBUSCFG->HRSTEN0 &= ~Hw26;
++ pIOBUSCFG->HRSTEN0 |= Hw26;
++ // tcc_rtc_init((unsigned int)rtc_base);
++ // RTC Initialization
++ tcc_writel( Hw1, rtc_base + RTCCON);
++ tcc_writel( Hw0, rtc_base + INTCON);
++ tcc_writel( tcc_readl(rtc_base + RTCCON) | Hw0, rtc_base + RTCCON);
++ tcc_writel( tcc_readl(rtc_base + RTCCON) & ~Hw15, rtc_base + RTCCON);
++ tcc_writel( tcc_readl(rtc_base + RTCCON) & ~(Hw13 | Hw12 | Hw10 | Hw9 | Hw8), rtc_base + INTCON);
++ tcc_writel( tcc_readl(rtc_base + INTCON) | Hw12, rtc_base + INTCON);
++ tcc_writel( tcc_readl(rtc_base + RTCCON) | Hw15, rtc_base + RTCCON);
++
++ tcc_writel( tcc_readl(rtc_base + RTCCON) & ~Hw0, rtc_base + RTCCON);
++ tcc_writel( tcc_readl(rtc_base + RTCIM) & ~(Hw3 | Hw0), rtc_base + RTCIM);
++// tcc_writel( tcc_readl(rtc_base + RTCIM) | Hw2, rtc_base + RTCIM);
++ tcc_writel( tcc_readl(rtc_base + RTCIM) & ~Hw2, rtc_base + RTCIM);
++
++ tcc_writel( tcc_readl(rtc_base + RTCALM) & ~(Hw7 - Hw0), rtc_base + RTCALM);
++ tcc_writel( tcc_readl(rtc_base + INTCON) & ~Hw0, rtc_base + INTCON);
++ tcc_writel( tcc_readl(rtc_base + RTCCON) & ~Hw1, rtc_base + RTCCON);
++
++ }else {
++ // ADD PMWKUP RTC Normal mode}
++ }
++
++ //tcc_rtc_enable(pdev, 1);
++ //tca_alarm_setint((unsigned int)rtc_base);
++
++ /* find the IRQs */
++ tcc_rtc_alarmno = platform_get_irq(pdev, 0);
++ pr_debug("tcc_rtc: alarm irq %d\n", tcc_rtc_alarmno);
++
++ if (tcc_rtc_alarmno < 0) {
++ dev_err(&pdev->dev, "no irq for alarm\n");
++ return -ENOENT;
++ }
++
++ /* register RTC and exit */
++ rtc = rtc_device_register(pdev->name, &pdev->dev, &tcc_rtcops, THIS_MODULE);
++
++ if (IS_ERR(rtc)) {
++ dev_err(&pdev->dev, "cannot attach rtc\n");
++ ret = PTR_ERR(rtc);
++ goto err_nortc;
++ }
++
++ platform_set_drvdata(pdev, rtc);
++
++
++ if(request_irq(tcc_rtc_alarmno, tcc_rtc_alarmirq,
++ IRQF_DISABLED, DRV_NAME, rtc))
++ {
++ printk("%s: RTC timer interrupt IRQ%d already claimed\n",
++ pdev->name, tcc_rtc_alarmno);
++ return 0;
++ }
++
++ //tca_alarm_setpmwkup((unsigned int)rtc_base, (unsigned int)pPIC);
++ //device_init_wakeup(&pdev->dev, 1);
++
++ return 0;
++
++ err_nortc:
++ //tcc_rtc_enable(pdev, 0);
++ rtc_device_unregister(rtc);
++ return ret;
++
++}
++
++#ifdef CONFIG_PM
++
++/* RTC Power management control */
++
++static int tcc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ if (device_may_wakeup(&pdev->dev))
++ enable_irq_wake(tcc_rtc_alarmno);
++ return 0;
++}
++
++static int tcc_rtc_resume(struct platform_device *pdev)
++{
++ if (device_may_wakeup(&pdev->dev))
++ disable_irq_wake(tcc_rtc_alarmno);
++ return 0;
++}
++#else
++#define tcc_rtc_suspend NULL
++#define tcc_rtc_resume NULL
++#endif
++
++static struct platform_driver tcc_rtc_driver = {
++ .probe = tcc_rtc_probe,
++ .remove = tcc_rtc_remove,
++ .suspend = tcc_rtc_suspend,
++ .resume = tcc_rtc_resume,
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static char __initdata banner[] = "TCC RTC, (c) 2009, Telechips \n";
++
++static int __init tcc_rtc_init(void)
++{
++ printk(banner);
++ return platform_driver_register(&tcc_rtc_driver);
++}
++
++static void __exit tcc_rtc_exit(void)
++{
++ platform_driver_unregister(&tcc_rtc_driver);
++}
++
++module_init(tcc_rtc_init);
++module_exit(tcc_rtc_exit);
++
++MODULE_AUTHOR("linux <linux@telechips.com>");
++MODULE_DESCRIPTION("Telechips RTC Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/rtc/tcc b/drivers/rtc/tcc
+new file mode 120000
+index 0000000..c3a8743
+--- /dev/null
++++ b/drivers/rtc/tcc
+@@ -0,0 +1 @@
++tcc8900
+\ No newline at end of file
+diff --git a/drivers/rtc/tcc8900/tca_alarm.c b/drivers/rtc/tcc8900/tca_alarm.c
+new file mode 100644
+index 0000000..6a5a6f2
+--- /dev/null
++++ b/drivers/rtc/tcc8900/tca_alarm.c
+@@ -0,0 +1,319 @@
++
++/****************************************************************************
++ * FileName : tca_alarm.C
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++/*****************************************************************************
++*
++* Header Files Include
++*
++******************************************************************************/
++#include "tca_alarm.h"
++
++/*****************************************************************************
++*
++* Defines
++*
++******************************************************************************/
++#define WINCE_ONLY
++
++
++/*****************************************************************************
++*
++* structures
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* Variables
++*
++******************************************************************************/
++
++
++
++/*****************************************************************************
++*
++* Functions
++*
++******************************************************************************/
++
++/*****************************************************************************
++* Function Name : tca_rtcgettime()
++******************************************************************************/
++VOLATILE void tca_alarm_gettime(unsigned int devbaseaddresss, rtctime *pTime)
++{
++ unsigned uCON;
++
++ PRTC pRTC = (PRTC)devbaseaddresss;
++
++ BITSET(pRTC->RTCCON, Hw1); // RTC Register write enabled
++ BITSET(pRTC->INTCON, Hw0); // Interrupt Block Write Enable
++
++ pTime->wSecond = pRTC->ALMSEC;
++ pTime->wMinute = pRTC->ALMMIN;
++ pTime->wHour = pRTC->ALMHOUR;
++ pTime->wDayOfWeek = pRTC->ALMDAY;
++ pTime->wDay = pRTC->ALMDATE;
++ pTime->wMonth = pRTC->ALMMON;
++ pTime->wYear = pRTC->ALMYEAR;
++ uCON = pRTC->RTCALM;
++
++ BITCLR(pRTC->INTCON, Hw0); // Interrupt Block Write Disable
++ BITCLR(pRTC->RTCCON, Hw1); // RTC Register write Disable
++
++ /* Second */
++ if (ISZERO(uCON, Hw0))
++ pTime->wSecond = (unsigned char) 0;
++ else
++ pTime->wSecond = FROM_BCD( pTime->wSecond );
++
++ /* Minute */
++ if (ISZERO(uCON, Hw1))
++ pTime->wMinute = (unsigned char) 0;
++ else
++ pTime->wMinute = FROM_BCD( pTime->wMinute );
++
++ /* Hour */
++ if (ISZERO(uCON, Hw2))
++ pTime->wHour = (unsigned char) 0;
++ else
++ pTime->wHour = FROM_BCD( pTime->wHour );
++
++ /* date */
++ if (ISZERO(uCON, Hw3))
++ pTime->wDay = (unsigned char) 0;
++ else
++ pTime->wDay = FROM_BCD( pTime->wDay );
++
++ /* month */
++ if (ISZERO(uCON, Hw5))
++ pTime->wMonth = (unsigned char) 0;
++ else
++ pTime->wMonth = FROM_BCD( pTime->wMonth );
++
++ /* year */
++ if (ISZERO(uCON, Hw6))
++ pTime->wYear = (unsigned short) 0;
++ else
++ pTime->wYear = FROM_BCD( pTime->wYear );
++
++ /* weekdays */
++ if (ISZERO(uCON, Hw4))
++ pTime->wDayOfWeek = 1;
++ else
++ pTime->wDayOfWeek = FROM_BCD( pTime->wDayOfWeek );
++
++ pRTC->RTCALM = uCON;
++
++}
++
++/*****************************************************************************
++* Function Name : tca_rtcsettime()
++******************************************************************************/
++VOLATILE void tca_alarm_settime(unsigned int devbaseaddresss, rtctime *pTime)
++{
++ unsigned uCON;
++ PRTC pRTC = (PRTC)devbaseaddresss;
++
++ BITSET(pRTC->RTCCON, Hw1); // RTC Register write enabled
++ BITSET(pRTC->INTCON, Hw0); // Interrupt Block Write Enable
++
++ uCON = 0xEF; // Not wDayOfWeek
++ /* Second */
++ if ( pTime->wSecond > 59 )
++ BITCLR(uCON, Hw0);//HwRTCALM_SECEN_EN
++ else
++ pRTC->ALMSEC = TO_BCD( pTime->wSecond );
++
++ /* Minute */
++ if ( pTime->wMinute > 59 )
++ BITCLR(uCON, Hw1);//HwRTCALM_MINEN_EN
++ else
++ pRTC->ALMMIN = TO_BCD( pTime->wMinute );
++
++ /* Hour */
++ if ( pTime->wHour > 23 )
++ BITCLR(uCON, Hw2);//HwRTCALM_HOUREN_EN
++ else
++ pRTC->ALMHOUR = TO_BCD( pTime->wHour );
++
++ /* Date */
++ if ( pTime->wDay > 31 || pTime->wDay < 1 )
++ BITCLR(uCON, Hw3);//HwRTCALM_DATEEN_EN
++ else
++ pRTC->ALMDATE = TO_BCD( pTime->wDay );
++
++ /* month */
++ if (pTime->wMonth > 12 || pTime->wMonth < 1)
++ BITCLR(uCON, Hw5);//HwRTCALM_MONEN_EN
++ else
++ pRTC->ALMMON = TO_BCD( pTime->wMonth );
++
++ /* year */
++ if (pTime->wYear > 2099 || pTime->wYear < 1900)
++ BITCLR(uCON, Hw6);//HwRTCALM_YEAREN_EN
++ else
++ pRTC->ALMYEAR = TO_BCD( pTime->wYear );
++
++ /* Day */
++ if ( pTime->wDayOfWeek > 6)
++ BITCLR(uCON, Hw4);//HwRTCALM_DAYEN_EN
++ else
++ pRTC->ALMDAY = pTime->wDayOfWeek+1;
++
++ // Enable ALARM
++ pRTC->RTCALM = uCON;
++
++ BITCLR(pRTC->RTCIM,Hw3|Hw1|Hw0); // Normal Mode,PMWKUP Active low, Disable alarm interrupt mode
++ BITSET(pRTC->RTCIM,Hw1|Hw0); ////Suports on the edge alarm interrupt
++
++ BITSET(pRTC->RTCSTR,Hw6);
++ pRTC->RTCPEND = 0;
++ //BITSET(pRTC->RTCSTR,Hw5|Hw4);
++
++ //BITCLR(pRTC->INTCON,Hw0); // Normal Mode,PMWKUP Active low, Disable alarm interrupt mode
++ BITCSET(pRTC->RTCCON, Hw1, Hw6); // Enable Alarm Interrupt
++}
++
++/************************************************************************************************
++* FUNCTION : tca_alarm_setint
++*
++* DESCRIPTION :
++*
++************************************************************************************************/
++VOLATILE void tca_alarm_setint(unsigned int devbaseaddresss)
++{
++ volatile rtctime lpTime;
++
++
++ //Set Alarm
++ tca_rtc_gettime(devbaseaddresss, (rtctime *)&lpTime);
++
++#if defined(WINCE_ONLY)
++ if(lpTime.wSecond < 57){
++ lpTime.wSecond += 3;
++ }
++ else{
++ if(lpTime.wMinute < 59){
++ lpTime.wMinute += 1;
++ lpTime.wSecond = 0;
++ }
++ else{
++ if(lpTime.wHour < 23){
++ lpTime.wHour += 1;
++ lpTime.wMinute = 0;
++ lpTime.wSecond = 0;
++ }
++ else{
++ lpTime.wHour = 0;
++ lpTime.wMinute = 0;
++ lpTime.wSecond = 0;
++ }
++ }
++ }
++
++#else
++ if(lpTime.wSecond < 55)
++ lpTime.wSecond += 5;
++#endif
++
++ tca_alarm_settime(devbaseaddresss, (rtctime *)&lpTime);
++
++
++
++}
++
++/************************************************************************************************
++* FUNCTION : tca_alarm_setpmwkup
++*
++* DESCRIPTION :
++*
++************************************************************************************************/
++extern char wakeup_time[50];
++VOLATILE void tca_alarm_setpmwkup(unsigned int rtcbaseaddresss,unsigned int vicbaseaddresss)
++{
++ volatile rtctime lpTime;
++
++ PRTC pRTC = (PRTC)rtcbaseaddresss;
++ PPIC pPIC = (PPIC)vicbaseaddresss;
++
++ int year,month,day,hour,minute,second;
++
++ sscanf(wakeup_time,"%d-%d-%d %d:%d:%d",&year,&month,&day,&hour,&minute,&second);
++// printk(KERN_EMERG"%d,%d,%d,%d,%d,%d\n",year,month,day,hour,minute,second);
++ //Set Alarm
++ tca_rtc_gettime(rtcbaseaddresss, (rtctime *)&lpTime);
++// printk(KERN_EMERG"!!!dcs: %d-%d-%d-%d-%d-%d-%d\n",lpTime.wYear,lpTime.wMonth,lpTime.wDayOfWeek,lpTime.wDay,lpTime.wHour,lpTime.wMinute,lpTime.wSecond);
++
++ if(((year == 60)||(month == 60)||(day == 60)||(hour == 60)||(minute == 60)||(second == 60)))
++ {
++
++#if defined(WINCE_ONLY)
++
++ if(lpTime.wSecond < 50){
++ lpTime.wSecond += 10;
++ }
++ else{
++ if(lpTime.wMinute < 59){
++ lpTime.wMinute += 1;
++ lpTime.wSecond = 10;
++ }
++ else{
++ if(lpTime.wHour < 23){
++ lpTime.wHour += 1;
++ lpTime.wMinute = 0;
++ lpTime.wSecond = 10;
++ }
++ else{
++ lpTime.wHour = 0;
++ lpTime.wMinute = 0;
++ lpTime.wSecond = 0;
++ }
++ }
++ }
++#else
++ if(lpTime.wSecond < 55)
++ lpTime.wSecond += 5;
++#endif
++ }else
++ {
++ lpTime.wYear = year;
++ lpTime.wMonth = month;
++ lpTime.wDay = day;
++ lpTime.wHour = hour;
++ lpTime.wMinute = minute;
++ lpTime.wSecond = second;
++ }
++
++ tca_alarm_settime(rtcbaseaddresss, (rtctime *)&lpTime);
++
++ pPIC->CLR1 = Hw11;
++ pPIC->MSTS1 |= Hw11;
++ pPIC->SEL1 |= Hw11;
++
++ BITSET(pRTC->RTCCON, Hw1);// Enable RTCEN
++ BITSET(pRTC->INTCON, Hw0);// Enable INTWREN
++ BITCLR(pRTC->RTCIM, 0xf);
++ BITSET(pRTC->RTCIM, Hw0|Hw3); // Enable ALMINT_EDGE_EN, Enable PMWKUP_ACTIVE_HIGH, Enable PWDN_POWERDOWN_MODE
++ BITSET(pRTC->RTCCON, Hw1 | Hw7);
++
++ //PMWKUP Disable Start
++ //pRTC->RTCCON = 0;
++ //BITSET(pRTC->RTCCON, Hw1);
++ //BITSET(pRTC->INTCON, Hw0);
++ //pRTC->RTCIM = 0;
++ //BITSET(pRTC->RTCIM, Hw0);
++ //PMWKUP Disable End
++}
++
++
++
+diff --git a/drivers/rtc/tcc8900/tca_alarm.h b/drivers/rtc/tcc8900/tca_alarm.h
+new file mode 100644
+index 0000000..d3eb22d
+--- /dev/null
++++ b/drivers/rtc/tcc8900/tca_alarm.h
+@@ -0,0 +1,71 @@
++
++/****************************************************************************
++ * FileName : tca_alarm.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++/*****************************************************************************
++*
++* Defines
++*
++******************************************************************************/
++#ifndef __TCA_ALARAM_H__
++#define __TCA_ALARAM_H__
++
++#include <bsp.h>
++#include "tca_rtc.h"
++
++/*****************************************************************************
++*
++* Enum
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* Type Defines
++*
++******************************************************************************/
++
++/*****************************************************************************
++*
++* Structures
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* External Variables
++*
++******************************************************************************/
++
++/*****************************************************************************
++*
++* External Functions
++*
++******************************************************************************/
++#ifdef __cplusplus
++extern
++"C" {
++#endif
++#include <bsp.h>
++
++VOLATILE void tca_alarm_gettime(unsigned int devbaseaddresss, rtctime *pTime);
++VOLATILE void tca_alarm_settime(unsigned int devbaseaddresss,rtctime *pTime);
++VOLATILE void tca_alarm_setint(unsigned int devbaseaddresss);
++VOLATILE void tca_alarm_setpmwkup(unsigned int rtcbaseaddresss,unsigned int vicbaseaddresss);
++
++#ifdef __cplusplus
++ }
++#endif
++
++#endif //__TCA_ALARAM_H__
++
+diff --git a/drivers/rtc/tcc8900/tca_rtc.c b/drivers/rtc/tcc8900/tca_rtc.c
+new file mode 100644
+index 0000000..1ff43a4
+--- /dev/null
++++ b/drivers/rtc/tcc8900/tca_rtc.c
+@@ -0,0 +1,187 @@
++
++/****************************************************************************
++ * FileName : tca_rtc.C
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++
++/*****************************************************************************
++*
++* Header Files Include
++*
++******************************************************************************/
++#include "tca_rtc.h"
++
++/*****************************************************************************
++*
++* Defines
++*
++******************************************************************************/
++
++/*****************************************************************************
++*
++* structures
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* Variables
++*
++******************************************************************************/
++
++
++
++/*****************************************************************************
++*
++* Functions
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++* Function Name : tca_rtcgettime()
++******************************************************************************/
++VOLATILE void tca_rtc_gettime(unsigned int devbaseaddresss,rtctime *pTime)
++{
++
++ unsigned int data;
++ unsigned short seconds;
++
++ PRTC pRTC = (PRTC)devbaseaddresss;
++
++ // Enable RTC control.
++ BITCLR(pRTC->RTCCON, Hw4); // RTC Register write enabled
++ BITSET(pRTC->RTCCON, Hw1); // RTC Register write enabled
++ BITSET(pRTC->INTCON, Hw0); // Interrupt Block Write Enable
++
++ do {
++ data = (pRTC->BCDSEC & 0x7f);
++ seconds = FROM_BCD(data);
++
++ data = (pRTC->BCDYEAR & 0xFFFF);
++ pTime->wYear = FROM_BCD(data); // Start from 1980
++
++ data = (pRTC->BCDMON & 0x1f);
++ pTime->wMonth = FROM_BCD(data);
++
++ data = (pRTC->BCDDATE & 0x3f);
++ pTime->wDay = FROM_BCD(data);
++
++ data = (pRTC->BCDDAY & 0x07);
++ pTime->wDayOfWeek = FROM_BCD(data);
++
++ data = (pRTC->BCDHOUR & 0x3f);
++ pTime->wHour = FROM_BCD(data);
++
++ data = (pRTC->BCDMIN & 0x7f);
++ pTime->wMinute = FROM_BCD(data);
++
++ data = (pRTC->BCDSEC & 0x7f);
++ pTime->wSecond = FROM_BCD(data);
++
++ pTime->wMilliseconds = 0;
++ } while (pTime->wSecond != seconds);
++
++ //BITCLR(pRTC->INTCON, Hw0);
++ BITCLR(pRTC->RTCCON, Hw1);
++}
++
++/*****************************************************************************
++* Function Name : tca_rtcsettime()
++******************************************************************************/
++VOLATILE void tca_rtc_settime(unsigned int devbaseaddresss, rtctime *pTime)
++{
++ PRTC pRTC = (PRTC)devbaseaddresss;
++ // Enable RTC control.
++ BITSET(pRTC->RTCCON, Hw0); //RTC Start Halt
++ BITSET(pRTC->RTCCON, Hw4); //RTC Clock Count Reset
++ BITCLR(pRTC->RTCCON, Hw4); //RTC Clock Count No Reset
++ BITSET(pRTC->RTCCON, Hw4); //RTC Clock Count Reset
++ BITSET(pRTC->RTCCON, Hw1); //RTC Write Enable
++ BITSET(pRTC->INTCON, Hw0);
++ BITCLR(pRTC->INTCON, Hw15); //RTC Clock Count No Reset
++
++ pRTC->BCDSEC = TO_BCD(pTime->wSecond);
++ pRTC->BCDMIN = TO_BCD(pTime->wMinute);
++ pRTC->BCDHOUR = TO_BCD(pTime->wHour);
++ pRTC->BCDDAY = TO_BCD(pTime->wDayOfWeek);
++ pRTC->BCDDATE = TO_BCD(pTime->wDay);
++ pRTC->BCDMON = TO_BCD(pTime->wMonth);
++ pRTC->BCDYEAR = TO_BCD(pTime->wYear);
++
++ // Disable RTC control.
++ BITSET(pRTC->INTCON, Hw0); //RTC Protection Enable
++ BITCLR(pRTC->RTCCON, Hw1); //RTC Write Disable
++ BITCLR(pRTC->RTCCON, Hw0); //RTC Start Run
++}
++
++/*****************************************************************************
++* Function Name : tca_rtcsettime()
++******************************************************************************/
++volatile unsigned int tca_rtc_checkvalidtime(unsigned int devbaseaddresss)
++{
++
++ unsigned IsNeedMending;
++ rtctime pTimeTest;
++
++ tca_rtc_gettime(devbaseaddresss, &pTimeTest);
++
++ //-------------------------------------------
++ // Conversion to Dec and Check validity
++ //-------------------------------------------
++ IsNeedMending = 0;
++
++ /* Second */
++ if (pTimeTest.wSecond > 59)
++ {
++ IsNeedMending = 1;
++ }
++
++ /* Minute */
++ if ( pTimeTest.wMinute > 59 )
++ {
++ IsNeedMending = 1;
++ }
++
++ /* Hour */
++ if ( pTimeTest.wHour > 23 )
++ {
++ IsNeedMending = 1;
++ }
++
++ /* Date */ // 1~31
++ if ( ( pTimeTest.wDay < 1 ) || ( pTimeTest.wDay > 31 ) )
++ {
++ IsNeedMending = 1;
++ }
++
++ /* Day */ // Sunday ~ Saturday
++ if ( pTimeTest.wDayOfWeek > 6 )
++ {
++ IsNeedMending = 1;
++ }
++
++ /* Month */
++ if ( ( pTimeTest.wMonth < 1 ) || ( pTimeTest.wMonth > 12 ) )
++ {
++ IsNeedMending = 1;
++ }
++
++ /* Year */
++ if ( pTimeTest.wYear < 1980 || pTimeTest.wYear > 2100)
++ {
++ IsNeedMending = 1;
++ }
++
++ return IsNeedMending;
++
++}
++
+diff --git a/drivers/rtc/tcc8900/tca_rtc.h b/drivers/rtc/tcc8900/tca_rtc.h
+new file mode 100644
+index 0000000..abf1a5f
+--- /dev/null
++++ b/drivers/rtc/tcc8900/tca_rtc.h
+@@ -0,0 +1,76 @@
++
++/****************************************************************************
++ * FileName : tca_rtc.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++/*****************************************************************************
++*
++* Defines
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* Enum
++*
++******************************************************************************/
++#ifndef __TCA_RTC_H__
++#define __TCA_RTC_H__
++
++#include "bsp.h"
++
++
++/*****************************************************************************
++*
++* Type Defines
++*
++******************************************************************************/
++#define FROM_BCD(n) ((((n) >> 4) * 10) + ((n) & 0xf))
++#define TO_BCD(n) ((((n) / 10) << 4) | ((n) % 10))
++#define RTC_YEAR_DATUM 1980
++
++
++/*****************************************************************************
++*
++* Structures
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* External Variables
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* External Functions
++*
++******************************************************************************/
++#ifdef __cplusplus
++extern
++"C" {
++#endif
++
++#include <bsp.h>
++
++VOLATILE void tca_rtc_gettime(unsigned int devbaseaddresss,rtctime *pTime);
++VOLATILE void tca_rtc_settime(unsigned int devbaseaddresss,rtctime *pTime);
++volatile unsigned int tca_rtc_checkvalidtime(unsigned int devbaseaddresss);
++
++#ifdef __cplusplus
++ }
++#endif
++
++
++#endif //__TCA_RTC_H__
++
+diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
+index 579d63a..bd551ff 100644
+--- a/drivers/serial/Kconfig
++++ b/drivers/serial/Kconfig
+@@ -486,6 +486,40 @@ config SERIAL_S3C2400
+ help
+ Serial port support for the Samsung S3C2400 SoC
+
++config SERIAL_TCC
++ tristate "Telechips TCC Serial port support"
++ depends on ARM && ARCH_TCC
++ select SERIAL_CORE
++ help
++ Support for the on-chip UARTs on the Telechips TCC series CPUs,
++ providing /dev/ttySAC0, 1.
++
++config SERIAL_TCC_CONSOLE
++ bool "Support for console on TCC serial port"
++ depends on ARM && ARCH_TCC
++ depends on SERIAL_TCC
++ select SERIAL_CORE_CONSOLE
++ help
++ Allow selection of the TCC on-board serial ports for use as
++ an virtual console.
++
++ Even if you say Y here, the currently visible virtual console
++ (/dev/ttyx) will still be used as the system console by default, but
++ you can alter that using a kernel command line option such as
++ "console=ttySACx". (Try "man bootparam" or see the documentation of
++ your boot loader about how to pass options to the kernel at
++ boot time.)
++
++config SERIAL_TCC_DMA
++ bool "Support for DMA mode"
++ depends on ARM && ARCH_TCC
++ depends on SERIAL_TCC
++ help
++ This driver works under DMA mode. If this option is selected, the
++ TCC simple dma driver is also enabled.
++
++
++
+ config SERIAL_S3C2410
+ tristate "Samsung S3C2410 Serial port support"
+ depends on SERIAL_SAMSUNG && CPU_S3C2410
+diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
+index 0c17c8d..636fe66 100644
+--- a/drivers/serial/Makefile
++++ b/drivers/serial/Makefile
+@@ -14,6 +14,13 @@ obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
+ obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
+ obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
+
++
++ifeq ($(CONFIG_ARCH_TCC),y)
++$(shell ln -fsn $(CONFIG_TCC_STRING) $(srctree)/drivers/serial/tcc)
++endif
++obj-$(CONFIG_SERIAL_TCC) += tcc_serial.o tcc/tca_serial.o
++#obj-$(CONFIG_SERIAL_TCC) += tcc_serial.o
++
+ obj-$(CONFIG_SERIAL_8250) += 8250.o
+ obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
+ obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
+diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
+index 874786a..fb6e4f6 100644
+--- a/drivers/serial/serial_core.c
++++ b/drivers/serial/serial_core.c
+@@ -1085,6 +1085,8 @@ static int uart_get_count(struct uart_state *state,
+ /*
+ * Called via sys_ioctl. We can use spin_lock_irq() here.
+ */
++int rfcomm_tty_ioctl_called = 0;
++EXPORT_SYMBOL(rfcomm_tty_ioctl_called);
+ static int
+ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+@@ -1160,6 +1162,8 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
+ struct uart_port *port = state->port;
+ if (port->ops->ioctl)
+ ret = port->ops->ioctl(port, cmd, arg);
++ else if(cmd == TCSETS && rfcomm_tty_ioctl_called == 1)
++ ret = 0;
+ break;
+ }
+ }
+diff --git a/drivers/serial/tcc b/drivers/serial/tcc
+new file mode 120000
+index 0000000..c3a8743
+--- /dev/null
++++ b/drivers/serial/tcc
+@@ -0,0 +1 @@
++tcc8900
+\ No newline at end of file
+diff --git a/drivers/serial/tcc8900/tca_serial.c b/drivers/serial/tcc8900/tca_serial.c
+new file mode 100644
+index 0000000..d7d9bf3
+--- /dev/null
++++ b/drivers/serial/tcc8900/tca_serial.c
+@@ -0,0 +1,450 @@
++
++/****************************************************************************
++ * FileName : tca_tccserial.c
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++/*****************************************************************************
++*
++* Include
++*
++******************************************************************************/
++
++#include <bsp.h>
++#include "../tcc_serial.h"
++
++
++/*****************************************************************************
++*
++* Defines
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++* Function Name : tca_serial_portinit(int nCh, int nPort, unsigned long* pvGpioAddr, unsigned long* pvPortMuxAddr)
++******************************************************************************
++* Desription : tca_serial_portinit
++* Parameter : int nCh, int nPort, unsigned long* pvGpioAddr, unsigned long* pvPortMuxAddr
++* Return : None
++******************************************************************************/
++void tca_serial_portinit(int nCh, int nPort, unsigned long* pvGpioAddr, unsigned long* pvPortMuxAddr)
++{
++
++ PGPIO pGpio = (PGPIO)pvGpioAddr;
++ PUARTPORTMUX pPortmux = (PUARTPORTMUX)pvPortMuxAddr;
++
++
++ // ch5 cannot use DMA (spec.)
++ // each value of CHSEL shuld be different
++ /*
++ if(nPort == 5){ //change ch
++ BITCSET(pPortmux->CHSEL, 0x7 <<(4*nCh), nPort << (4*nCh));
++ BITCSET(pPortmux->CHSEL, 0x7 <<(4*5), nCh << (4*5));
++ }
++ */
++
++
++ BITCSET(pPortmux->CHSEL, 0x7 <<(4*0), 0 << (4*0)); //portmuxinit
++ BITCSET(pPortmux->CHSEL, 0x7 <<(4*1), 1 << (4*1)); //portmuxinit
++ BITCSET(pPortmux->CHSEL, 0x7 <<(4*2), 2 << (4*2)); //portmuxinit
++ BITCSET(pPortmux->CHSEL, 0x7 <<(4*3), 5 << (4*3)); //portmuxinit
++ BITCSET(pPortmux->CHSEL, 0x7 <<(4*4), 4 << (4*4)); //portmuxinit
++ BITCSET(pPortmux->CHSEL, 0x7 <<(4*5), 3 << (4*5)); //portmuxinit
++
++ switch(nPort){//do port set
++ case 0:
++ BITCSET(pGpio->GPEFN0, Hw4-Hw0, Hw0);
++ BITCSET(pGpio->GPEFN0, Hw8-Hw4, Hw4);
++ break;
++ case 1:
++ BITCSET(pGpio->GPEFN0, Hw24-Hw20, Hw20);
++ BITCSET(pGpio->GPEFN0, Hw20-Hw16, Hw16);
++ break;
++ case 2:
++ BITCSET(pGpio->GPEFN1, Hw4-Hw0, Hw0);
++ BITCSET(pGpio->GPEFN1, Hw8-Hw4, Hw4);
++ break;
++ case 3:
++ BITCSET(pGpio->GPDFN1, Hw28-Hw24, Hw24);
++ BITCSET(pGpio->GPDFN1, Hw24-Hw20, Hw20);
++ break;
++ case 4:
++ BITCSET(pGpio->GPDFN2, Hw8-Hw4, Hw4);
++ BITCSET(pGpio->GPDFN2, Hw12-Hw8, Hw8);
++ break;
++ case 5:
++ BITCSET(pGpio->GPDFN2, Hw8-Hw4, Hw4);
++ BITCSET(pGpio->GPDFN2, Hw12-Hw8, Hw8);
++ break;
++ }
++
++}
++
++
++void tca_serial_gpio_setting(int nCh, int nPort, unsigned long* pvGpioAddr, unsigned long* pvPortMuxAddr)
++{
++
++ PGPIO pGpio = (PGPIO)pvGpioAddr;
++ PUARTPORTMUX pPortmux = (PUARTPORTMUX)pvPortMuxAddr;
++
++ switch(nPort){//do port set
++ case 0:
++ BITCSET(pGpio->GPEFN0, Hw4-Hw0, Hw0);
++ BITCSET(pGpio->GPEFN0, Hw8-Hw4, Hw4);
++ break;
++ case 1:
++ BITCSET(pGpio->GPEFN0, Hw24-Hw20, Hw20);
++ BITCSET(pGpio->GPEFN0, Hw20-Hw16, Hw16);
++ break;
++ case 2:
++ BITCSET(pGpio->GPEFN1, Hw4-Hw0, Hw0);
++ BITCSET(pGpio->GPEFN1, Hw8-Hw4, Hw4);
++ break;
++ case 3:
++ BITCSET(pGpio->GPDFN1, Hw28-Hw24, Hw24);
++ BITCSET(pGpio->GPDFN1, Hw24-Hw20, Hw20);
++ break;
++ case 4:
++ BITCSET(pGpio->GPDFN2, Hw8-Hw4, Hw4);
++ BITCSET(pGpio->GPDFN2, Hw12-Hw8, Hw8);
++ break;
++ case 5:
++ BITCSET(pGpio->GPDFN2, Hw8-Hw4, Hw4);
++ BITCSET(pGpio->GPDFN2, Hw12-Hw8, Hw8);
++ break;
++ }
++}
++
++
++void tca_serial_gpio_default(int nCh, int nPort, unsigned long* pvGpioAddr, unsigned long* pvPortMuxAddr)
++{
++
++ PGPIO pGpio = (PGPIO)pvGpioAddr;
++ PUARTPORTMUX pPortmux = (PUARTPORTMUX)pvPortMuxAddr;
++
++ switch(nPort){//do port set
++ case 0:
++ BITCLR(pGpio->GPEFN0, Hw4-Hw0);
++ BITCLR(pGpio->GPEFN0, Hw8-Hw4);
++
++ BITCLR(pGpio->GPEEN, Hw4-Hw0);
++ BITCLR(pGpio->GPEDAT, Hw4-Hw0);
++
++ break;
++ case 1:
++ BITCLR(pGpio->GPEFN0, Hw24-Hw20);
++ BITCLR(pGpio->GPEFN0, Hw20-Hw16);
++
++ BITCLR(pGpio->GPEEN, Hw8-Hw4);
++ BITCLR(pGpio->GPEDAT, Hw8-Hw4);
++ break;
++ case 2:
++ BITCLR(pGpio->GPEFN1, Hw4-Hw0);
++ BITCLR(pGpio->GPEFN1, Hw8-Hw4);
++
++ BITCLR(pGpio->GPEEN, Hw12-Hw7);
++ BITCLR(pGpio->GPEDAT, Hw12-Hw7);
++ break;
++ case 3:
++ BITCLR(pGpio->GPDFN1, Hw28-Hw24);
++ BITCLR(pGpio->GPDFN1, Hw24-Hw20);
++
++ BITCLR(pGpio->GPDEN, Hw17-Hw13);
++ BITCLR(pGpio->GPDDAT, Hw17-Hw13);
++ break;
++ case 4:
++ BITCLR(pGpio->GPDFN2, Hw8-Hw4);
++ BITCLR(pGpio->GPDFN2, Hw12-Hw8);
++
++ BITCLR(pGpio->GPDEN, Hw17-Hw13);
++ BITCLR(pGpio->GPDDAT, Hw17-Hw13);
++
++ break;
++ case 5:
++ BITCLR(pGpio->GPDFN2, Hw8-Hw4);
++ BITCLR(pGpio->GPDFN2, Hw12-Hw8);
++
++ BITCLR(pGpio->GPDEN, Hw21-Hw17);
++ BITCLR(pGpio->GPDDAT, Hw21-Hw1);
++ break;
++ }
++
++}
++
++
++
++/*****************************************************************************
++* Function Name : tca_serial_dmaclrinterrupt(unsigned nDmanum, unsigned long* pVirtualDmaAddr)
++******************************************************************************
++* Desription : tca_serial_dmaclrinterrupt
++* Parameter : unsigned nDmanum, unsigned long* pVirtualDmaAddr
++* Return : success(SUCCESS)
++******************************************************************************/
++unsigned int tca_serial_dmaclrinterrupt(unsigned nDmanum, unsigned long* pVirtualDmaAddr)
++{
++ PGDMACTRL pDMA = (PGDMACTRL)pVirtualDmaAddr;
++ switch( nDmanum ){
++ case 0:
++ pDMA->CHCTRL0 |= Hw3;
++ break;
++ case 1:
++ pDMA->CHCTRL1 |= Hw3;
++ break;
++ case 2:
++ pDMA->CHCTRL2 |= Hw3;
++ break;
++ default:
++ return 0;
++ }
++ return 1;
++}
++
++/*****************************************************************************
++* Function Name : tca_dma_dmacurrentaddress(int m_DmaNumber, unsigned long* pVirtualDmaAddr)
++******************************************************************************
++* Desription : tca_dma_dmacurrentaddress
++* Parameter : int m_DmaNumber, unsigned long* pVirtualDmaAddr
++* Return :
++******************************************************************************/
++int tca_dma_dmacurrentaddress(int m_DmaNumber, unsigned long* pVirtualDmaAddr)
++{
++ PGDMACTRL pDMA = (PGDMACTRL)pVirtualDmaAddr;
++ switch(m_DmaNumber)
++ {
++ case 0:
++ return (pDMA->C_DADR0);
++ case 1:
++ return (pDMA->C_DADR1);
++ case 2:
++ return (pDMA->C_DADR2);
++ default:
++ return 0;
++ }
++}
++/*****************************************************************************
++* Function Name : tca_dma_dmadeststartaddress(int m_DmaNumber, unsigned long* pVirtualDmaAddr)
++******************************************************************************
++* Desription : tca_dma_dmadeststartaddress
++* Parameter : int m_DmaNumber, unsigned long* pVirtualDmaAddr
++* Return :
++******************************************************************************/
++int tca_dma_dmadeststartaddress(int m_DmaNumber, unsigned long* pVirtualDmaAddr)
++{
++ PGDMACTRL pDMA = (PGDMACTRL)pVirtualDmaAddr;
++ switch(m_DmaNumber){
++ case 0:
++ return (pDMA->ST_DADR0);
++ case 1:
++ return (pDMA->ST_DADR1);
++ case 2:
++ return (pDMA->ST_DADR2);
++ default:
++ return 0;
++ }
++ return 0;
++}
++/*****************************************************************************
++* Function Name : tca_dma_clrien(int m_DmaNumber, unsigned long* pVirtualDmaAddr)
++******************************************************************************
++* Desription : tca_dma_clrien
++* Parameter : int m_DmaNumber, unsigned long* pVirtualDmaAddr
++* Return :
++******************************************************************************/
++int tca_dma_clrien(int m_DmaNumber, unsigned long* pVirtualDmaAddr)
++{
++ PGDMACTRL pDMA = (PGDMACTRL)pVirtualDmaAddr;
++ switch(m_DmaNumber){
++ case 0:
++ pDMA->CHCTRL0 &= Hw2;
++ break;
++ case 1:
++ pDMA->CHCTRL1 &= Hw2;
++ break;
++ case 2:
++ pDMA->CHCTRL2 &= Hw2;
++ break;
++ default:
++ return 0;
++ }
++ return 0;
++}
++/*****************************************************************************
++* Function Name : tca_dma_setien(int m_DmaNumber, unsigned long* pVirtualDmaAddr)
++******************************************************************************
++* Desription : tca_dma_setien
++* Parameter : int m_DmaNumber, unsigned long* pVirtualDmaAddr
++* Return :
++******************************************************************************/
++int tca_dma_setien(int m_DmaNumber, unsigned long* pVirtualDmaAddr)
++{
++ PGDMACTRL pDMA = (PGDMACTRL)pVirtualDmaAddr;
++ switch(m_DmaNumber){
++ case 0:
++ pDMA->CHCTRL0 |= Hw2;
++ break;
++ case 1:
++ pDMA->CHCTRL1 |= Hw2;
++ break;
++ case 2:
++ pDMA->CHCTRL2 |= Hw2;
++ break;
++ default:
++ return 0;
++ }
++ return 0;
++}
++/*****************************************************************************
++* Function Name : tca_dma_ctrl(int m_DmaNumber, unsigned long* pVirtualDmaAddr)
++******************************************************************************
++* Desription : tca_dma_ctrl
++* Parameter : int m_DmaNumber, unsigned long* pVirtualDmaAddr
++* Return :
++******************************************************************************/
++int tca_dma_ctrl(int m_DmaNumber, unsigned long* pVirtualDmaAddr)
++{
++ PGDMACTRL pDMA = (PGDMACTRL)pVirtualDmaAddr;
++
++ switch(m_DmaNumber){
++ case 0:
++ return (pDMA->CHCTRL0);
++ case 1:
++ return (pDMA->CHCTRL1);
++ case 2:
++ return (pDMA->CHCTRL2);
++ default:
++ return 0;
++ }
++
++}
++
++
++/*****************************************************************************
++* Function Name : tca_dma_setconfig(
++ iunsigned uCH,
++ void *pSRT,
++ unsigned uSPARAM,
++ void *pDST,
++ unsigned uDPARAM,
++ unsigned uCHCTRL,
++ unsigned uSize,
++ unsigned channel,
++ unsigned mode,
++ unsigned long* pVirtualDmaAddr
++)
++******************************************************************************
++* Desription : tca_dma_setconfig
++* Parameter :
++* Return :
++******************************************************************************/
++void tca_dma_setconfig(
++ unsigned uCH,
++ void* pSRT,
++ unsigned uSPARAM,
++ void* pDST,
++ unsigned uDPARAM,
++ unsigned uCHCTRL,
++ unsigned uSize,
++ unsigned channel,
++ unsigned mode,
++ unsigned long* pVirtualDmaAddr
++)
++{
++ PGDMACTRL pDMA = (PGDMACTRL)pVirtualDmaAddr;
++
++
++ switch( uCH ) {
++ case 0:
++ if (uSize){
++ // Set Source Address & Source Parameter (mask + increment)
++ pDMA->ST_SADR0 = (int)pSRT;
++ pDMA->SPARAM0 = uSPARAM;
++
++ // Set Dest Address & Dest Parameter (mask + increment)
++ pDMA->ST_DADR0 = (int)pDST;
++ pDMA->DPARAM0 = uDPARAM;
++ pDMA->RPTCTRL0 &= ~Hw31;
++
++
++ pDMA->EXTREQ0 = tca_uart_channelselect(channel, mode);
++ pDMA->HCOUNT0 = uSize;
++ }
++
++ pDMA->CHCTRL0 = uCHCTRL;
++ pDMA->CHCTRL0 |= Hw0;
++ break;
++ case 1:
++ if (uSize){
++ // Set Source Address & Source Parameter (mask + increment)
++ pDMA->ST_SADR1 = (int)pSRT;
++ pDMA->SPARAM1 = uSPARAM;
++
++ // Set Dest Address & Dest Parameter (mask + increment)
++ pDMA->ST_DADR1 = (int)pDST;
++ pDMA->DPARAM1 = uDPARAM;
++ pDMA->RPTCTRL1 &= ~Hw31;
++
++ pDMA->EXTREQ1 = tca_uart_channelselect(channel, mode);
++ // now one HOP is 1*8/8 bytes, HwHCOUNT determine how many HOPS will fire a interrupt
++ pDMA->HCOUNT1 = uSize;//((uSize)>>0x01)>>0x03;
++ }
++
++ pDMA->CHCTRL1 = uCHCTRL;
++ pDMA->CHCTRL1 |= Hw0;
++ break;
++ case 2:
++ if (uSize){
++ // Set Source Address & Source Parameter (mask + increment)
++ pDMA->ST_SADR2 = (int)pSRT;
++ pDMA->SPARAM2 = uSPARAM;
++
++ // Set Dest Address & Dest Parameter (mask + increment)
++ pDMA->ST_DADR2 = (int)pDST;
++ pDMA->DPARAM2 = uDPARAM;
++ pDMA->RPTCTRL2 &= ~Hw31;
++
++ pDMA->EXTREQ2 = tca_uart_channelselect(channel, mode);
++ // now one HOP is 1*8/8 bytes, HwHCOUNT determine how many HOPS will fire a interrupt
++ pDMA->HCOUNT2 = uSize;//((uSize)>>0x01)>>0x03;
++ }
++
++ pDMA->CHCTRL2 = uCHCTRL;
++ pDMA->CHCTRL2 |= Hw0;
++ break;
++ }
++}
++
++/*****************************************************************************
++* Function Name : tca_uart_channelselectint channel, int mode)
++******************************************************************************
++* Desription : tca_serial_portinit
++* Parameter : int channel, int mode
++* Return :
++******************************************************************************/
++int tca_uart_channelselect(int channel, int mode)
++{
++
++ switch(channel){
++ case 0:
++ return (mode?HwEXTREQ_UART0_RX:HwEXTREQ_UART0_TX);
++ break;
++ case 1:
++ return (mode?HwEXTREQ_UART1_RX:HwEXTREQ_UART1_TX);
++ break;
++ case 2:
++ return (mode?HwEXTREQ_UART2_RX:HwEXTREQ_UART2_TX);
++ break;
++ case 3:
++ return (mode?HwEXTREQ_UART3_RX:HwEXTREQ_UART3_TX);
++ default :
++ break;
++
++ }
++ return 0;
++}
+\ No newline at end of file
+diff --git a/drivers/serial/tcc8900/tca_serial.h b/drivers/serial/tcc8900/tca_serial.h
+new file mode 100644
+index 0000000..586a69b
+--- /dev/null
++++ b/drivers/serial/tcc8900/tca_serial.h
+@@ -0,0 +1,52 @@
++
++/****************************************************************************
++ * FileName : tca_tccserial.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++
++/*****************************************************************************
++*
++* Defines
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* APIs
++*
++******************************************************************************/
++
++
++int tca_uart_channelselect(int channel, int mode);
++void tca_serial_gpio_setting(int nCh, int nPort, unsigned long* pvGpioAddr, unsigned long* pvPortMuxAddr);
++void tca_serial_gpio_default(int nCh, int nPort, unsigned long* pvGpioAddr, unsigned long* pvPortMuxAddr);
++void tca_serial_portinit(int nCh, int nPort, unsigned long* pvGpioAddr, unsigned long* pvPortMuxAddr);
++
++int tca_dma_ctrl(int m_DmaNumber, unsigned long* pVirtualDmaAddr);
++int tca_dma_dmacurrentaddress(int m_DmaNumber, unsigned long* pVirtualDmaAddr);
++int tca_dma_dmadeststartaddress(int m_DmaNumber,unsigned long* pVirtualDmaAddr);
++int tca_dma_clrien(int m_DmaNumber, unsigned long* pVirtualDmaAddr);
++int tca_dma_setien(int m_DmaNumber, unsigned long* pVirtualDmaAddr);
++unsigned int tca_serial_dmaclrinterrupt(unsigned nDmanum, unsigned long* pVirtualDmaAddr);
++void tca_dma_setconfig( unsigned uCH, void* pSRT,
++ unsigned uSPARAM, void* pDST,
++ unsigned uDPARAM, unsigned uCHCTRL,
++ unsigned uSize, unsigned channel,
++ unsigned mode, unsigned long* pVirtualDmaAddr);
++
++
++#ifdef __cplusplus
++}
++#endif
+diff --git a/drivers/serial/tcc_serial.c b/drivers/serial/tcc_serial.c
+new file mode 100644
+index 0000000..821985b
+--- /dev/null
++++ b/drivers/serial/tcc_serial.c
+@@ -0,0 +1,1698 @@
++/*
++ * linux/drivers/serial/tcc_serial.c
++ *
++ * Based on: drivers/serial/s3c2410.c and driver/serial/bfin_5xx.c
++ * Author: <linux@telechips.com>
++ * Created: June 10, 2008
++ * Description: Driver for onboard UARTs on the Telechips TCC Series
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <linux/module.h>
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++#include <linux/init.h>
++#include <linux/sysrq.h>
++#include <linux/console.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/serial_core.h>
++#include <linux/serial.h>
++#include <linux/delay.h>
++#include <linux/clk.h>
++#include <linux/serial_reg.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include <mach/hardware.h>
++#include <mach/irqs.h>
++
++#if CONFIG_MACH_TCC8900
++#include <bsp.h>
++#include <mach/tcc_pca953x.h>
++#include "tcc/tca_serial.h"
++#include "tcc_serial.h"
++#define DRV_NAME "tcc8900-uart"
++#define CONSOLE_PORT 0
++#define UART1 1
++#define CONSOLE_BASE *(volatile unsigned long *)0xF0532000
++#endif
++
++#define BAUDRATE 115200
++
++#if defined(CONFIG_SERIAL_TCC_DMA)
++#define CONFIG_SERIAL_TCC_DMA_TX
++#define CONFIG_SERIAL_TCC_DMA_RX
++#endif
++
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++#include <linux/dma-mapping.h>
++
++#define DMA_PORT UART1 // UART1
++#define DMA_TX_CH_NUM 0 // GDMA1-0
++#define DMA_TX_INT INT_DMA1_CH0
++#define DMA_BUF_SIZE FIFOSIZE
++#define DMA_TX_MODE 0
++//#define HwGDMA_BASE HwGDMA0_BASE // GDMA1
++#define HwGDMA_BASE HwGDMA1_BASE // GDMA1
++//#define HwGDMA_BASE HwGDMA2_BASE // GDMA1
++//#define HwGDMA_BASE HwGDMA3_BASE // GDMA1
++#endif
++
++#ifdef CONFIG_SERIAL_TCC_DMA_RX
++#define DMA_CH_NUM_RX 1 // GDMA1-1
++#define DMA_RX_MODE 1
++#define TIME_STEP 1//(1*HZ)
++#define DMA_RX_BUF_SIZE 0x1000
++#include <linux/time.h>
++#include <linux/timer.h>
++#include <linux/delay.h>
++
++void *dma_rx_buffer, *dma_rx_buffer_physical;
++struct timer_list *timer;
++static int rx_dma_tail=0;
++void *kerneltimer_timeover(void *arg );
++static int timer_state=0;
++static DECLARE_WORK(work_queue, kerneltimer_timeover);
++static unsigned long start_value;
++#endif
++
++#define TIMEOUT jiffies_to_msecs(1000)
++
++#define UART_IER_ELSI UART_IER_RLSI
++
++/* UARTx_LCR Masks */
++#define WLS(x) (((x)-5) & 0x03) /* Word Length Select */
++#define STB 0x04 /* Stop Bits */
++#define PEN 0x08 /* Parity Enable */
++#define EPS 0x10 /* Even Parity Select */
++#define SP 0x20 /* Stick Parity */
++#define SB 0x40 /* Set Break */
++#define DLAB 0x80 /* Divisor Latch Access */
++
++/* UARTx_MCR Mask */
++#define AFE 0x20 /* Auto Flow Control Enable */
++#define LOOP 0x10 /* Loopback Mode Enable */
++#define RTS 0x02 /* Request To Sent */
++
++/* UARTx_LSR Masks */
++#define DR 0x01 /* Data Ready */
++#define OE 0x02 /* Overrun Error */
++#define PE 0x04 /* Parity Error */
++#define FE 0x08 /* Framing Error */
++#define BI 0x10 /* Break Interrupt */
++#define THRE 0x20 /* THR Empty */
++#define TEMT 0x40 /* TSR and UART_THR Empty */
++
++/* UARTx_IER Masks */
++#define ERXI 0x01
++#define ETXI 0x02
++#define ELSI 0x04
++
++#define OFFSET_THR 0x00 /* Transmit Holding register */
++#define OFFSET_RBR 0x00 /* Receive Buffer register */
++#define OFFSET_DLL 0x00 /* Divisor Latch (Low-Byte) */
++#define OFFSET_IER 0x04 /* Interrupt Enable Register */
++#define OFFSET_DLM 0x04 /* Divisor Latch (High-Byte) */
++#define OFFSET_IIR 0x08 /* Interrupt Identification Register */
++#define OFFSET_FCR 0x08 /* FIFO Control Register */
++#define OFFSET_LCR 0x0C /* Line Control Register */
++#define OFFSET_MCR 0x10 /* Modem Control Register */
++#define OFFSET_LSR 0x14 /* Line Status Register */
++#define OFFSET_MSR 0x18 /* Modem Status Register */
++#define OFFSET_SCR 0x1C /* SCR Scratch Register */
++#define OFFSET_AFT 0x20 /* AFC Trigger Level Register */
++#define OFFSET_UCR 0x24 /* UART Control Register */
++
++#define portaddr(port, reg) ((port)->membase + (reg))
++
++#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
++#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
++
++#define wr_regl(port, reg, val) \
++ do { __raw_writel(val, portaddr(port, reg)); } while(0)
++#define wr_regb(port, reg, val) \
++ do { __raw_writeb(val, portaddr(port, reg)); } while(0)
++
++
++
++/* structures */
++
++struct tcc_uart_clksrc {
++ const char *name;
++ unsigned int divisor;
++ unsigned int min_baud;
++ unsigned int max_baud;
++};
++
++struct tcc_uart_info {
++ char *name;
++ unsigned int type;
++ unsigned int fifosize;
++};
++
++struct tcc_reg_info {
++ unsigned long bDLL;
++ unsigned long bIER;
++ unsigned long bDLM;
++ unsigned long bLCR;
++ unsigned long bMCR;
++ unsigned long bSCR;
++ unsigned long bFCR;
++ unsigned long bMSR;
++ unsigned long bAFT;
++ unsigned long bUCR;
++};
++
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++typedef struct _tcc_dma_buf_t {
++ char *addr;
++ dma_addr_t dma_addr;
++ int buf_size; // total size of DMA
++} tcc_dma_buf_t;
++#endif
++
++struct tcc_uart_port {
++ unsigned char rx_claimed;
++ unsigned char tx_claimed;
++
++ struct tcc_uart_info *info;
++ struct tcc_uart_clksrc *clksrc;
++ struct clk *clk;
++ struct clk *baudclk;
++ struct uart_port port;
++ wait_queue_head_t wait_q;
++ int fifosize;
++ char *name;
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ wait_queue_head_t wait_dma_q;
++ tcc_dma_buf_t dma_tx_buffer;
++#endif
++ struct tcc_reg_info reg; // for suspend/resume
++};
++
++/* configuration defines */
++
++#if 0
++//#define dbg(x...) printk(KERN_DEBUG "tcc uart: ");
++#define dbg printk
++#else /* no debug */
++#define dbg(x...) do {} while(0)
++#endif
++
++/* UART name and device definitions */
++
++#define TCC_SERIAL_NAME "ttySAC"
++#define TCC_SERIAL_MAJOR 204
++#define TCC_SERIAL_MINOR 64
++
++/* conversion functions */
++
++#define tcc_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)
++
++/* Number of serial ports */
++#define NR_PORTS (6)
++
++#define FIFOSIZE (16) /* defend on FCR */
++
++#define tx_enabled(port) ((port)->unused[0])
++#define rx_enabled(port) ((port)->unused[1])
++#define port_used(port) ((port)->unused1)
++
++static void tcc_serial_console_putchar(struct uart_port *port, int ch);
++extern void tcc_serial_uart_putchar(struct uart_port *port, int ch);
++
++int tcc_serial_init_ports(struct tcc_uart_port *ourport, struct tcc_uart_info *info, struct platform_device *pdev);
++
++static struct uart_ops tcc_serial_ops;
++
++static struct tcc_uart_port tcc_serial_ports[NR_PORTS] = {
++ [0] = {
++ .port = {
++ .lock = __SPIN_LOCK_UNLOCKED(tcc_uart_port[0].port.lock),
++ .iotype = UPIO_MEM,
++ .irq = INT_UART0,
++ .uartclk = 0,
++ .fifosize = FIFOSIZE,
++ .ops = &tcc_serial_ops,
++ .flags = UPF_BOOT_AUTOCONF,
++ .line = 0,
++ },
++ .name = "uart0"
++ },
++ [1] = {
++ .port = {
++ .lock = __SPIN_LOCK_UNLOCKED(tcc_uart_port[1].port.lock),
++ .iotype = UPIO_MEM,
++ .uartclk = 0,
++ .irq = INT_UART1,
++ .fifosize = FIFOSIZE,
++ .ops = &tcc_serial_ops,
++ .flags = UPF_BOOT_AUTOCONF,
++ .line = 1,
++ },
++ .name = "uart1"
++ },
++#if defined(_EXTRAUART_)
++ [2] = {
++ .port = {
++ .lock = __SPIN_LOCK_UNLOCKED(tcc_uart_port[2].port.lock),
++ .iotype = UPIO_MEM,
++ .irq = INT_UART2,
++ .uartclk = 0,
++ .fifosize = FIFOSIZE,
++ .ops = &tcc_serial_ops,
++ .flags = UPF_BOOT_AUTOCONF,
++ .line = 2,
++ },
++ .name = "uart2"
++ },
++ [3] = {
++ .port = {
++ .lock = __SPIN_LOCK_UNLOCKED(tcc_uart_port[3].port.lock),
++ .iotype = UPIO_MEM,
++ .irq = INT_UART3,
++ .uartclk = 0,
++ .fifosize = FIFOSIZE,
++ .ops = &tcc_serial_ops,
++ .flags = UPF_BOOT_AUTOCONF,
++ .line = 3,
++ },
++ .name = "uart3"
++ },
++ [4] = {
++ .port = {
++ .lock = __SPIN_LOCK_UNLOCKED(tcc_uart_port[4].port.lock),
++ .iotype = UPIO_MEM,
++ .irq = INT_UART4,
++ .uartclk = 0,
++ .fifosize = FIFOSIZE,
++ .ops = &tcc_serial_ops,
++ .flags = UPF_BOOT_AUTOCONF,
++ .line = 4,
++ },
++ .name = "uart4"
++ },
++ [5] = {
++ .port = {
++ .lock = __SPIN_LOCK_UNLOCKED(tcc_uart_port[5].port.lock),
++ .iotype = UPIO_MEM,
++ .irq = INT_UART5,
++ .uartclk = 0,
++ .fifosize = FIFOSIZE,
++ .ops = &tcc_serial_ops,
++ .flags = UPF_BOOT_AUTOCONF,
++ .line = 5,
++ },
++ .name = "uart5"
++ },
++#endif
++
++};
++
++#ifdef CONFIG_SERIAL_TCC_DMA_RX
++
++void kerneltimer_registertimer(struct timer_list* ptimer, unsigned long timeover,struct uart_port *port )
++{
++ init_timer( ptimer );
++ ptimer->expires = get_jiffies_64() + timeover;
++ ptimer->data = (unsigned long)port;
++ ptimer->function = (void *)kerneltimer_timeover;
++ add_timer( ptimer);
++}
++
++void my_uart_rx_process(unsigned long arg)
++{
++ volatile int current_tail,current_head, i, rts_state;
++ struct uart_port *port;
++ unsigned int ch = 0;
++ unsigned uerstat = 0, flag;
++ struct tty_struct *tty;
++ unsigned char *buffer;
++
++ volatile PGDMACTRL pDMA = (volatile PGDMACTRL)tcc_p2v(HwGDMA_BASE);
++ int cur_addr = tca_dma_dmacurrentaddress(DMA_CH_NUM_RX, (unsigned long *)pDMA);
++
++ port = (struct uart_port *)arg;
++ buffer = (unsigned char *)dma_rx_buffer;
++ current_tail = rx_dma_tail & (DMA_RX_BUF_SIZE-1);
++ current_head = cur_addr & (DMA_RX_BUF_SIZE-1);
++
++ if (current_head != current_tail) {
++ if (current_head > current_tail) rts_state = current_head - current_tail;
++ else rts_state = DMA_RX_BUF_SIZE - current_tail - current_head;
++ if (rts_state > 2048) {
++ printk("RTS ON[0x%x : 0x%x]\n", cur_addr, current_tail);
++ wr_regl(port, OFFSET_MCR, rd_regl(port, OFFSET_MCR) & ~Hw1);
++ }
++
++ spin_lock(&port->lock);
++ tty = port->info->port.tty;
++
++ flag = TTY_NORMAL;
++ port->icount.rx++;
++
++ if (uerstat & UART_LSR_BI) {
++ port->icount.brk++;
++ goto out;
++ }
++
++ if (uerstat & UART_LSR_FE)
++ port->icount.frame++;
++ if (uerstat & UART_LSR_OE)
++ port->icount.overrun++;
++
++ uerstat &= port->read_status_mask;
++
++ if (uerstat & UART_LSR_BI)
++ flag = TTY_BREAK;
++ else if (uerstat & UART_LSR_PE)
++ flag = TTY_PARITY;
++ else if (uerstat & ( UART_LSR_FE | UART_LSR_OE))
++ flag = TTY_FRAME;
++
++ if (current_head < current_tail) current_head += (DMA_RX_BUF_SIZE);
++ for(i=current_tail;i<current_head;i++) {
++ if (timer_state == 0) break;
++ if (i >= DMA_RX_BUF_SIZE)
++ ch = buffer[i-DMA_RX_BUF_SIZE];
++ else
++ ch = buffer[i];
++
++ if (uart_handle_sysrq_char(port, ch))
++ goto out;
++ /* put the received char into UART buffer */
++ uart_insert_char(port, uerstat, UART_LSR_OE, ch, flag);
++ tty_flip_buffer_push(tty);
++ rx_dma_tail++;
++ }
++
++ if (rts_state > 2048) {
++ printk("RTS OFF\n");
++ wr_regl(port, OFFSET_MCR, rd_regl(port, OFFSET_MCR) | Hw1);
++ }
++out:
++ spin_unlock(&port->lock);
++ }
++}
++
++void *kerneltimer_timeover(void *arg )
++{
++ volatile PGDMACTRL pDMA = (volatile PGDMACTRL)tcc_p2v(HwGDMA_BASE);
++ int cur_addr = tca_dma_dmacurrentaddress(DMA_CH_NUM_RX, (unsigned long *)pDMA);
++
++ if (start_value == cur_addr) {
++ if (start_value == 0x20000000) my_uart_rx_process((unsigned long)arg);
++ } else {
++ if (start_value != 0x20000000) {
++ rx_dma_tail = (int) dma_rx_buffer_physical;
++ start_value = 0x20000000;
++ }
++
++ my_uart_rx_process((unsigned long)arg);
++ }
++
++ if (timer_state == 1)
++ kerneltimer_registertimer( timer, TIME_STEP,arg );
++
++ return 0;
++}
++
++int kerneltimer_init(struct uart_port *port)
++{
++ timer= kmalloc( sizeof( struct timer_list ), GFP_KERNEL );
++ if( timer== NULL ) return -ENOMEM;
++ memset( timer, 0, sizeof( struct timer_list) );
++ kerneltimer_registertimer( timer,TIME_STEP,port );
++
++ return 0;
++}
++#endif
++
++static inline struct tcc_uart_port *to_ourport(struct uart_port *port)
++{
++ return container_of(port, struct tcc_uart_port, port);
++}
++
++/* translate a port to the device name */
++
++static inline const char *tcc_serial_portname(struct uart_port *port)
++{
++ return to_platform_device(port->dev)->name;
++}
++
++
++static void tcc_serial_stop_tx(struct uart_port *port)
++{
++ while(!(rd_regl(port, OFFSET_LSR)) & TEMT)
++ continue;
++
++ if(tx_enabled(port)){
++ disable_irq(port->irq);
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ // disable_irq(DMA_TX_INT);
++#endif
++ tx_enabled(port) = 0;
++ }
++}
++
++static int get_writable_fifo_size(struct uart_port *port)
++{
++ unsigned int ier;
++
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ struct circ_buf *xmit = &port->info->xmit;
++ int tmp;
++#endif
++ ier = rd_regl(port, OFFSET_IER);
++
++ wr_regl(port, OFFSET_IER, ier | Hw1);
++
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ if (interruptible_sleep_on_timeout(&(tcc_serial_ports[port->line].wait_q), TIMEOUT) != 0) {
++ if(port->line== DMA_PORT) {
++ int f_size = 0;
++ tmp = xmit->head - xmit->tail;
++ f_size = ((tmp > 0) ? tmp : UART_XMIT_SIZE + tmp);
++ if (f_size > FIFOSIZE) {
++ f_size = FIFOSIZE;
++ }
++ return f_size;
++ } else {
++ return FIFOSIZE;
++ }
++ }
++
++ if(port->line== DMA_PORT) {
++ tmp = xmit->head - xmit->tail;
++ return ((tmp > 0) ? tmp : UART_XMIT_SIZE + tmp);
++ } else if (interruptible_sleep_on_timeout(&(tcc_serial_ports[port->line].wait_q), TIMEOUT) != 0) {
++ return FIFOSIZE;
++ }
++#else
++
++
++ if (interruptible_sleep_on_timeout(&(tcc_serial_ports[port->line].wait_q), TIMEOUT) != 0) {
++ return FIFOSIZE;
++ }
++#endif
++ return 0;
++}
++
++static void update_fifo_size(struct uart_port *port)
++{
++ /*FIXME: */
++ tcc_serial_ports[port->line].fifosize = FIFOSIZE;
++ return;
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ if(port->line == DMA_PORT)
++ tcc_serial_ports[port->line].fifosize = get_writable_fifo_size(port);
++ else if (tcc_serial_ports[port->line].fifosize <= 0)
++ tcc_serial_ports[port->line].fifosize = get_writable_fifo_size(port);
++#else
++
++ if (tcc_serial_ports[port->line].fifosize <= 0) {
++ tcc_serial_ports[port->line].fifosize = get_writable_fifo_size(port);
++ }
++#endif
++}
++
++static void tcc_serial_start_tx(struct uart_port *port)
++{
++ struct circ_buf *xmit = &port->info->xmit;
++ unsigned long flags;
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ struct tcc_uart_port *ourport;
++ volatile PGDMACTRL pDMA = (volatile PGDMACTRL)tcc_p2v(HwGDMA_BASE);
++#endif
++
++ if(!tx_enabled(port)) {
++ enable_irq(port->irq);
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ // enable_irq(DMA_TX_INT);
++#endif
++ tx_enabled(port) = 1;
++ }
++
++ local_irq_save(flags);
++ if (port->x_char) {
++ update_fifo_size(port);
++ if (tcc_serial_ports[port->line].fifosize > 0) {
++
++ tcc_serial_uart_putchar(port, port->x_char);
++ port->icount.tx++;
++ port->x_char = 0;
++ tcc_serial_ports[port->line].fifosize--;
++ }
++ }
++
++ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
++ tcc_serial_stop_tx(port);
++ goto out;
++ }
++
++ while(!(uart_circ_empty(xmit))) {
++ update_fifo_size(port);
++
++ if (tcc_serial_ports[port->line].fifosize > 0) {
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ if(port->line==DMA_PORT)
++ {
++ ourport = &tcc_serial_ports[port->line];
++
++ if(tcc_serial_ports[DMA_PORT].fifosize > 0)
++ {
++ wr_regl(port, OFFSET_UCR, rd_regl(port, OFFSET_UCR) & ~Hw0);
++ memcpy(tcc_serial_ports[DMA_PORT].dma_tx_buffer.addr, (xmit->buf+xmit->tail),tcc_serial_ports[DMA_PORT].fifosize );
++
++ //DMA Setting
++ tca_dma_setconfig(DMA_TX_CH_NUM,
++ (void *)tcc_serial_ports[DMA_PORT].dma_tx_buffer.dma_addr,
++ 0x1, /* src Param */
++ portaddr(port, 0x0),
++ 0x0, /* dest Param */
++ HwCHCTRL_SYNC_EN |
++ HwCHCTRL_TYPE_SL |
++ HwCHCTRL_BSIZE_1 |
++ HwCHCTRL_WSIZE_8 |
++ HwCHCTRL_IEN_ON |
++ HwCHCTRL_FLAG ,
++ tcc_serial_ports[DMA_PORT].fifosize ,
++ DMA_PORT,
++ DMA_TX_MODE, /* mode */
++ (unsigned long *)pDMA);
++
++ wr_regl(port, OFFSET_UCR, rd_regl(port, OFFSET_UCR) |Hw0);
++ interruptible_sleep_on_timeout(&(tcc_serial_ports[port->line].wait_dma_q), TIMEOUT);
++
++ xmit->tail = (xmit->tail + tcc_serial_ports[DMA_PORT].fifosize) & (UART_XMIT_SIZE - 1);
++
++ port->icount.tx+= tcc_serial_ports[port->line].fifosize;
++ //tcc_serial_ports[port->line].fifosize-=tcc_serial_ports[DMA_PORT].fifosize;
++ tcc_serial_ports[port->line].fifosize = 0;
++ }
++
++ } else {
++ tcc_serial_uart_putchar(port, xmit->buf[xmit->tail]);
++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++ port->icount.tx++;
++ tcc_serial_ports[port->line].fifosize--;
++ }
++#else
++ tcc_serial_uart_putchar(port, xmit->buf[xmit->tail]);
++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++ port->icount.tx++;
++ tcc_serial_ports[port->line].fifosize--;
++
++#endif
++ }// if (tcc_serial_ports[port->line].fifosize > 0)
++ }// while(!(uart_circ_empty(xmit)))
++
++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++ uart_write_wakeup(port);
++
++out:
++ local_irq_restore(flags);
++}
++
++
++static void tcc_serial_stop_rx(struct uart_port *port)
++{
++ dbg("%s\n", __func__);
++ if (rx_enabled(port)) {
++ disable_irq(port->irq);
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ // disable_irq(DMA_TX_INT);
++#endif
++ rx_enabled(port) = 0;
++ }
++
++}
++
++static void tcc_serial_enable_ms(struct uart_port *port)
++{
++ dbg("%s\n", __func__);
++}
++
++static inline struct tcc_uart_info *tcc_port_to_info(struct uart_port *port)
++{
++ return to_ourport(port)->info;
++}
++
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++static irqreturn_t tcc_serial_interrupt_dma(int irq, void *id)
++{
++ struct uart_port *port = id;
++ volatile PGDMACTRL pDMA = (volatile PGDMACTRL)tcc_p2v(HwGDMA_BASE);
++
++ spin_lock(&port->lock);
++ if (port->line == DMA_PORT) {
++ /* XXX */
++ //tca_dma_clrien(DMA_TX_CH_NUM, (unsigned long *)pDMA);
++ //tca_serial_dmaclrinterrupt(DMA_TX_CH_NUM, (unsigned long *)pDMA);
++ wake_up(&(tcc_serial_ports[port->line].wait_dma_q));
++ tca_dma_clrien(DMA_TX_CH_NUM, (unsigned long *)pDMA);
++ tca_serial_dmaclrinterrupt(DMA_TX_CH_NUM, (unsigned long *)pDMA);
++ }
++ spin_unlock(&port->lock);
++ return IRQ_HANDLED;
++}
++#endif
++
++
++static irqreturn_t tcc_serial_interrupt(int irq, void *id)
++{
++ unsigned int ch = 0;
++ struct uart_port *port = id;
++ unsigned uerstat, flag;
++ struct tty_struct *tty = port->info->port.tty;
++ int rx_flag = 0;
++ unsigned int iir_data = 0;
++ unsigned int t_ier;
++
++ uerstat = 0;
++
++ spin_lock(&port->lock);
++
++ iir_data = rd_regl(port, OFFSET_IIR);
++ iir_data = (iir_data & 0x0E) >> 1;
++ if (iir_data & 0x02 || iir_data & 0x06) {
++ ch = rd_regb(port, OFFSET_RBR);
++ rx_flag = 1;
++ } else if (iir_data & 0x01) {
++ t_ier = rd_regl(port, OFFSET_IER);
++ wr_regl(port, OFFSET_IER, (t_ier & ~Hw1));
++
++ wake_up(&(tcc_serial_ports[port->line].wait_q));
++ }
++
++
++#ifdef CONFIG_SERIAL_TCC_DMA_RX
++ if(port->line != DMA_PORT) {
++ #endif
++
++ if (rx_flag) {
++ flag = TTY_NORMAL;
++ port->icount.rx++;
++
++ if (uerstat & UART_LSR_BI) {
++ dbg("break!\n");
++ port->icount.brk++;
++ goto out;
++ }
++
++ if (uerstat & UART_LSR_FE)
++ port->icount.frame++;
++ if (uerstat & UART_LSR_OE)
++ port->icount.overrun++;
++
++ uerstat &= port->read_status_mask;
++
++ if (uerstat & UART_LSR_BI)
++ flag = TTY_BREAK;
++ else if (uerstat & UART_LSR_PE)
++ flag = TTY_PARITY;
++ else if (uerstat & ( UART_LSR_FE | UART_LSR_OE))
++ flag = TTY_FRAME;
++
++ if (uart_handle_sysrq_char(port, ch))
++ goto out;
++ /* put the received char into UART buffer */
++ uart_insert_char(port, uerstat, UART_LSR_OE, ch, flag);
++
++ tty_flip_buffer_push(tty);
++ }
++
++#ifdef CONFIG_SERIAL_TCC_DMA_RX
++ }
++#endif
++
++
++out:
++ spin_unlock(&port->lock);
++ return IRQ_HANDLED;
++}
++
++static unsigned int tcc_serial_tx_empty(struct uart_port *port)
++{
++ unsigned short lsr;
++
++ lsr = rd_regl(port, OFFSET_LSR);
++ if (lsr & TEMT)
++ return TIOCSER_TEMT;
++ else
++ return 0;
++
++}
++
++static unsigned int tcc_serial_get_mctrl(struct uart_port *port)
++{
++ dbg("%s\n", __func__);
++ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
++}
++
++static void tcc_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
++{
++ dbg("%s\n", __func__);
++ /* todo - possibly remove AFC and do manual CTS */
++}
++
++static void tcc_serial_break_ctl(struct uart_port *port, int break_state)
++{
++ dbg("%s\n", __func__);
++}
++
++static void tcc_serial_shutdown(struct uart_port *port)
++{
++
++#ifdef CONFIG_SERIAL_TCC_DMA_RX
++ if(port->line == DMA_PORT)
++ {
++ timer_state=0;
++ mdelay(1);
++ kfree(timer);
++ }
++#endif
++
++ wr_regl(port, OFFSET_IER, 0x0);
++ free_irq(port->irq, port);
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ if(port->line == DMA_PORT)
++ free_irq(DMA_TX_INT, port);
++#endif
++ port_used(port) = 0; // for suspend/resume
++}
++
++int pwr_ioctl_uart(int onoff, struct uart_port *port )
++{
++ static int flag=1;
++
++ volatile PGPIO pGPIO = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
++ volatile PPIC tPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++
++ if (onoff) // ON
++ {
++ tx_enabled(port) = 1;
++ rx_enabled(port) = 1;
++ port_used(port) = 1; // for suspend/resume
++
++ if(port->line == UART1){
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, BT_ON, OUTPUT, HIGH, SET_DIRECTION|SET_VALUE);
++ dbg("tcc_uart: BT power %s\n", (tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, 0, OUTPUT, 0, GET_VALUE)&BT_ON)?"ON":"OFF");
++ }
++
++ tca_ckc_setiobus(port->line + RB_UARTCONTROLLER0 , 1);
++ tca_ckc_setperi(port->line + PERI_UART0,ENABLE,520000,PCDIRECTPLL2);
++
++ if(port->line == 0) {
++ pGPIO->GPEEN |= (Hw1|Hw0);
++ pGPIO->GPEFN0 |= (Hw4|Hw0); // UTXD0, URXD0
++
++ } else if(port->line == 1) {
++ pGPIO->GPEEN |= (Hw4|Hw5|Hw6|Hw7);
++ BITCLR(pGPIO->GPEFN0, Hw31-Hw16);
++ pGPIO->GPEFN0 |= (Hw28|Hw24|Hw20|Hw16); // UTXD1, URXD1,
++ }
++
++ tPIC->INTMSK1 |= Hw15;
++
++ flag = 1;
++ }
++ else // OFF
++ {
++ if (!flag)
++ return 0;
++
++ tx_enabled(port) = 0;
++ rx_enabled(port) = 0;
++ port_used(port) = 0; // for suspend/resume
++
++ if(port->line == UART1){
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, BT_ON, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++ dbg("tcc_uart: BT power %s\n", (tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, 0, OUTPUT, 0, GET_VALUE)&BT_ON)?"ON":"OFF");
++ }
++
++ if(port->line == 0) {
++ pGPIO->GPEEN &= ~(Hw1|Hw0);
++ BITCLR(pGPIO->GPEFN0, Hw8-Hw0);
++ BITCLR(pGPIO->GPEDAT, Hw4-Hw0);
++ } else if(port->line == 1) {
++ pGPIO->GPEEN &= ~(Hw4|Hw5|Hw6|Hw7);
++ BITCLR(pGPIO->GPEFN0, Hw31-Hw16);
++ BITCLR(pGPIO->GPEDAT, Hw8-Hw4);
++ }
++
++ tPIC->INTMSK1 &= ~Hw15;
++
++ flag = 0;
++ }
++
++ return 0;
++}
++
++static stpwrinfo pwrinfo = {PWR_STATUS_ON};
++
++static int uart_pwr_ctl(void *h_private, int cmd, void *p_out)
++{
++ switch (cmd) {
++ case PWR_CMD_OFF:
++ dbg("PWR_CMD_OFF command ==> [%d]\n", cmd);
++ pwr_ioctl_uart(0, h_private);
++ pwrinfo.status = PWR_STATUS_OFF;
++ break;
++ case PWR_CMD_ON:
++ dbg("PWR_CMD_ON command ==> [%d]\n", cmd);
++ pwr_ioctl_uart(1, h_private);
++ pwrinfo.status = PWR_STATUS_ON;
++ break;
++ case PWR_CMD_GETSTATUS:
++ dbg("PWR_CMD_GETSTATUS command ==> [%d], status:[%d]\n", cmd, pwrinfo.status);
++ memcpy(p_out, &pwrinfo, sizeof(stpwrinfo));
++ break;
++// case PWR_CMD_MAX:
++// dbg ("PWR_CMD_MAX command ==> [%d]\n", cmd);
++// break;
++ default:
++ printk("unknown pwr command !!! ==> [%d]\n", cmd);
++ break;
++ }
++ return 0;
++}
++
++
++/* while application opening the console device, this function will invoked
++ * This function will initialize the interrupt handling
++ */
++static int tcc_serial_startup(struct uart_port *port)
++{
++ int retval=0;
++ unsigned int lcr;
++
++ volatile PPIC tPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++ volatile PGPIO pGPIO = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
++#ifdef CONFIG_SERIAL_TCC_DMA_RX
++ volatile PGDMACTRL pDMA = (volatile PGDMACTRL)tcc_p2v(HwGDMA_BASE);
++#endif
++
++ if(port->line == UART1){
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, BT_ON, OUTPUT, HIGH, SET_DIRECTION|SET_VALUE);
++ dbg("tcc_uart: BT power %s\n", (tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, 0, OUTPUT, 0, GET_VALUE)&BT_ON)?"ON":"OFF");
++ }
++
++
++ tx_enabled(port) = 1;
++ rx_enabled(port) = 1;
++ port_used(port) = 1; // for suspend/resume
++
++ tca_ckc_setiobus(port->line + RB_UARTCONTROLLER0 , 1);
++ tca_ckc_setperi(port->line + PERI_UART0,ENABLE,520000,PCDIRECTPLL2);
++
++#if 0
++ tca_serial_portinit(0, port->line, &pGPIO, &pPORTMUX);
++#else
++ if(port->line == 0) {
++ pGPIO->GPEEN |= (Hw1|Hw0);
++ pGPIO->GPEFN0 |= (Hw4|Hw0); // UTXD0, URXD0
++
++ } else if(port->line == 1) {
++ pGPIO->GPEEN |= (Hw4|Hw5|Hw6|Hw7);
++ BITCLR(pGPIO->GPEFN0, Hw31-Hw16);
++ pGPIO->GPEFN0 |= (Hw28|Hw24|Hw20|Hw16); // UTXD1, URXD1,
++ }
++#endif
++
++
++ wr_regl(port, OFFSET_IER, 0x0);
++
++ lcr = rd_regl(port, OFFSET_LCR);
++ wr_regl(port, OFFSET_LCR, (lcr | Hw7));
++
++ wr_regl(port, OFFSET_FCR, 0x07);
++ tcc_serial_ports[port->line].fifosize = FIFOSIZE;
++ tcc_serial_ports[port->line].reg.bFCR = 0x07; // for resume restore
++
++ wr_regl(port, OFFSET_LCR, (lcr & (~Hw7)));
++
++ rd_regl(port, OFFSET_IIR);
++
++ retval = request_irq(port->irq, tcc_serial_interrupt, IRQF_SHARED, tcc_serial_ports[port->line].name , port);
++ dbg("request serial irq:%d,retval:%d\n", port->irq, retval);
++
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ if(port->line == DMA_PORT)
++ retval = request_irq(DMA_TX_INT, tcc_serial_interrupt_dma, IRQF_SHARED, "uart1_dma" , port);
++ dbg("request serial dma irq:%d,retval:%d\n", DMA_TX_INT, retval);
++ //pDMA->CHCTRL0 |= Hw2;
++#endif
++
++#ifdef CONFIG_SERIAL_TCC_DMA_RX
++{
++ int cur_addr = tca_dma_dmacurrentaddress(DMA_CH_NUM_RX, (unsigned long *)pDMA);
++
++ if(port->line == DMA_PORT) {
++
++ printk("rx_dma_tail : %x\n",rx_dma_tail);
++
++ wr_regl(port, OFFSET_MCR, rd_regl(port, OFFSET_MCR) | Hw5);
++ wr_regl(port, OFFSET_MCR, rd_regl(port, OFFSET_MCR) | Hw1);
++ wr_regl(port, OFFSET_AFT, 0x00000021);
++ // Set Source Address & Source Parameter (mask + increment)
++
++ wr_regl(port, OFFSET_UCR, rd_regl(port, OFFSET_UCR) & ~Hw1);
++
++ tca_dma_setconfig(DMA_CH_NUM_RX,
++ portaddr(port, 0x0),
++ 0x0, /* src Param */
++ dma_rx_buffer_physical,
++ 0x1, /* dest Param */
++ //HwCHCTRL_CONT_C |
++ HwCHCTRL_SYNC_EN |
++ HwCHCTRL_TYPE_SL |
++ HwCHCTRL_BSIZE_1 |
++ HwCHCTRL_WSIZE_8 |
++ // HwCHCTRL_IEN_ON |
++ HwCHCTRL_REP_EN |
++ HwCHCTRL_FLAG ,
++ DMA_RX_BUF_SIZE ,
++ DMA_PORT,
++ DMA_RX_MODE, /* mode */
++ (unsigned long *)pDMA);
++
++ wr_regl(port, OFFSET_UCR, rd_regl(port, OFFSET_UCR) |Hw1);
++
++ start_value = cur_addr;
++ if (cur_addr != 0x20000000)
++ rx_dma_tail = cur_addr;
++ else
++ rx_dma_tail = (int) dma_rx_buffer_physical;
++ timer_state=1;
++ kerneltimer_init(port);
++ }
++}
++#endif
++
++
++ //wr_regl(port, OFFSET_IER, ERXI);
++ wr_regl(port, OFFSET_IER, ERXI | ETXI);
++#ifdef CONFIG_SERIAL_TCC_DMA_RX
++ if(port->line == DMA_PORT) {
++ printk("line %d IER tx Only\n", port->line);
++ wr_regl(port, OFFSET_IER, ETXI);
++ }
++#endif
++
++ //tca_serial_intrdone();
++ tPIC->INTMSK1 |= Hw15;
++
++ return retval;
++}
++
++/* power power management control */
++
++static void tcc_serial_pm(struct uart_port *port, unsigned int level, unsigned int old)
++{
++}
++
++
++static inline int tcc_serial_setsource(struct uart_port *port, struct tcc_uart_clksrc *c)
++{
++ return 0;
++}
++
++static void tcc_serial_set_termios(struct uart_port *port,
++ struct ktermios *termios,
++ struct ktermios *old)
++{
++ unsigned long flags;
++ unsigned int baud, quot;
++ unsigned int ulcon;
++ //unsigned int umcon;
++ unsigned int umcon, lsr;
++ int uart_clk = 0;
++
++ /*
++ * We don't support modem control lines.
++ */
++ termios->c_cflag &= ~(HUPCL | CMSPAR);
++ termios->c_cflag |= CLOCAL;
++
++ /*
++ * Ask the core to calculate the divisor for us.
++ */
++
++ baud = uart_get_baud_rate(port, termios, old, 0, 3500000);
++ uart_clk = (unsigned int)tca_ckc_getperi(port->line + PERI_UART0);
++ quot = (uart_clk*100)/(16*baud);
++
++ /*
++ * set byte size
++ */
++ switch (termios->c_cflag & CSIZE) {
++ case CS5:
++ dbg("config: 5bits/char\n");
++ ulcon = 0;
++ break;
++ case CS6:
++ dbg("config: 6bits/char\n");
++ ulcon = 1;
++ break;
++ case CS7:
++ dbg("config: 7bits/char\n");
++ ulcon = 2;
++ break;
++ case CS8:
++ default:
++ dbg("config: 8bits/char\n");
++ ulcon = 3;
++ break;
++ }
++
++ /* preserve original lcon IR settings */
++
++ if (termios->c_cflag & CSTOPB)
++ ulcon |= (1<<2); /* HwUART_LCR_STB_ONE */
++
++ umcon = (termios->c_cflag & CRTSCTS) ? (Hw5|Hw1) : 0; /* HwUART_MCR_RTS_ON */
++
++ if (termios->c_cflag & PARENB) {
++ if (termios->c_cflag & PARODD)
++ ulcon |= ((0<<4)|(1<<3));
++ else
++ ulcon |= ((1<<4)|(1<<3));
++ } else {
++ ulcon |= (0<<3);
++ }
++
++ spin_lock_irqsave(&port->lock, flags);
++
++ do {
++ lsr = rd_regl(port, OFFSET_LSR);
++ } while (!(lsr & TEMT));
++
++ dbg("setting ulcon to %08x, brddiv to %d\n", ulcon, quot);
++
++ wr_regl(port, OFFSET_MCR, umcon);
++ wr_regl(port, OFFSET_LCR, (ulcon | (1<<7)));
++ if(quot > 0xFF) {
++ wr_regl(port, OFFSET_DLL, 0x00FF);
++ wr_regl(port, OFFSET_DLM, quot >> 8);
++ }else if (quot > 0) {
++ wr_regl(port, OFFSET_DLL, quot);
++ wr_regl(port, OFFSET_DLM, 0x0);
++ }
++ wr_regl(port, OFFSET_LCR, (ulcon & (~(1<<7))));
++
++ /*
++ * Update the per-port timeout.
++ */
++ uart_update_timeout(port, termios->c_cflag, baud);
++
++ /*
++ * Which character status flags are we interested in?
++ */
++ port->read_status_mask = 0;
++ if (termios->c_iflag & INPCK)
++ port->read_status_mask |= 0;
++
++ /*
++ * Which character status flags should we ignore?
++ */
++ port->ignore_status_mask = 0;
++ if (termios->c_iflag & IGNPAR)
++ port->ignore_status_mask |= 0;
++ if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
++ port->ignore_status_mask |= 0;
++
++ /*
++ * Ignore all characters if CREAD is not set.
++ */
++ if ((termios->c_cflag & CREAD) == 0)
++ port->ignore_status_mask |= 0;
++
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static const char *tcc_serial_type(struct uart_port *port)
++{
++ return tcc_serial_ports[port->line].name;
++}
++
++#define MAP_SIZE (0x100)
++
++static void tcc_serial_release_port(struct uart_port *port)
++{
++ /* TODO */
++ //release_mem_region(port->mapbase, MAP_SIZE);
++}
++
++static int tcc_serial_request_port(struct uart_port *port)
++{
++ return 0;
++ /*
++ return request_mem_region(port->mapbase, MAP_SIZE, "tcc7901") ? 0 : -EBUSY;
++ */
++}
++
++static void tcc_serial_config_port(struct uart_port *port, int flags)
++{
++ if (flags & UART_CONFIG_TYPE && tcc_serial_request_port(port) == 0)
++ port->type = PORT_TCC;
++}
++
++/*
++ * verify the new serial_struct (for TIOCSSERIAL).
++ */
++static int
++tcc_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
++{
++ struct tcc_uart_info *info = tcc_port_to_info(port);
++
++ if (ser->type != PORT_UNKNOWN && ser->type != info->type)
++ return -EINVAL;
++ return 0;
++}
++
++
++#ifdef CONFIG_SERIAL_TCC_CONSOLE
++
++static struct console tcc_serial_console;
++
++#define TCC_SERIAL_CONSOLE &tcc_serial_console
++#else
++#define TCC_SERIAL_CONSOLE NULL
++#endif
++
++static struct uart_ops tcc_serial_ops = {
++ .pm = tcc_serial_pm,
++ .tx_empty = tcc_serial_tx_empty,
++ .get_mctrl = tcc_serial_get_mctrl,
++ .set_mctrl = tcc_serial_set_mctrl,
++ .stop_tx = tcc_serial_stop_tx,
++ .start_tx = tcc_serial_start_tx,
++ .stop_rx = tcc_serial_stop_rx,
++ .enable_ms = tcc_serial_enable_ms,
++ .break_ctl = tcc_serial_break_ctl,
++ .startup = tcc_serial_startup,
++ .shutdown = tcc_serial_shutdown,
++ .set_termios = tcc_serial_set_termios,
++ .type = tcc_serial_type,
++ .release_port = tcc_serial_release_port,
++ .request_port = tcc_serial_request_port,
++ .config_port = tcc_serial_config_port,
++ .verify_port = tcc_serial_verify_port,
++};
++
++
++static struct uart_driver tcc_uart_drv = {
++ .owner = THIS_MODULE,
++ .dev_name = "tcc-uart",
++ .nr = NR_PORTS,
++ .cons = TCC_SERIAL_CONSOLE,
++ .driver_name = TCC_SERIAL_NAME,
++ .major = TCC_SERIAL_MAJOR,
++ .minor = TCC_SERIAL_MINOR,
++};
++
++
++/* initialise serial port information */
++/* cpu specific variations on the serial port support */
++
++#if 0
++static int tcc_serial_getsource(struct uart_port *port,
++ struct tcc_uart_clksrc *clk)
++{
++ return 0;
++}
++#endif
++
++static struct tcc_uart_info tcc_uart_inf = {
++ .name = "Telechips UART",
++ .type = PORT_TCC,
++ .fifosize = FIFOSIZE,
++};
++
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++static void *tcc_free_dma_buf(tcc_dma_buf_t *dma_buf)
++{
++ dbg("%s\n", __func__);
++ if (dma_buf) {
++ if (dma_buf->dma_addr != 0) {
++ dma_free_writecombine(0, dma_buf->buf_size, dma_buf->addr, dma_buf->dma_addr);
++ }
++ memset(dma_buf, 0, sizeof(tcc_dma_buf_t));
++ }
++ return NULL;
++}
++
++static void *tcc_malloc_dma_buf(tcc_dma_buf_t *dma_buf, int buf_size)
++{
++
++
++ dbg("%s\n", __func__);
++ if (dma_buf) {
++ tcc_free_dma_buf(dma_buf);
++ dma_buf->buf_size = buf_size;
++ dma_buf->addr = dma_alloc_writecombine(0, dma_buf->buf_size, &dma_buf->dma_addr, GFP_KERNEL);
++ dbg("Malloc DMA buffer @0x%X(Phy=0x%X), size:%d\n",
++ (unsigned int)dma_buf->addr,
++ (unsigned int)dma_buf->dma_addr,
++ dma_buf->buf_size);
++ return dma_buf->addr;
++ }
++ return NULL;
++}
++#endif
++
++
++static int probe_index = 0;
++
++static int tcc_uart_probe(struct platform_device *dev, struct tcc_uart_info *info)
++{
++ int ret;
++ struct tcc_uart_port *ourport;
++
++ volatile PPIC pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ volatile PGDMACTRL pDMA = (volatile PGDMACTRL)tcc_p2v(HwGDMA_BASE);
++#endif
++
++ dbg("%s\n", __func__);
++
++ //tca_serial_intrinit();
++ pPIC->SEL1 |= Hw15;
++ pPIC->INTMSK1 |= Hw15;
++ pPIC->MODE1 |= Hw15; // Level trigger
++
++ ourport = &tcc_serial_ports[probe_index];
++
++ probe_index++;
++
++ //insert_pwm_node(DEVICE_UART, uart_pwr_ctl, &ourport->port);
++
++ ret = tcc_serial_init_ports(ourport, info, dev);
++ init_waitqueue_head(&(ourport->wait_q));
++
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ init_waitqueue_head(&(ourport->wait_dma_q));
++#endif
++
++ if (ret < 0){
++ dbg("tcc_serial_init_ports failure\n");
++ goto probe_err;
++ }
++
++ ret = uart_add_one_port(&tcc_uart_drv, &ourport->port);
++
++ if (ret){
++ dbg("uart_add_one_port failure\n");
++ return ret;
++ }
++
++ platform_set_drvdata(dev, &ourport->port);
++
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ if((&ourport->port)->line == DMA_PORT) {
++ if (!tcc_malloc_dma_buf(&(tcc_serial_ports[DMA_PORT].dma_tx_buffer), DMA_BUF_SIZE)) {
++ dbg("Unable to attach UART TX DMA 1 channel\n");
++ ret = -ENOMEM;
++ goto probe_err;
++ }
++ }
++ tca_dma_setien(DMA_TX_CH_NUM, (unsigned long *)pDMA);
++#endif
++
++#ifdef CONFIG_SERIAL_TCC_DMA_RX
++ if((&ourport->port)->line == DMA_PORT)
++ {
++ dma_rx_buffer = dma_alloc_writecombine(0, DMA_RX_BUF_SIZE, &dma_rx_buffer_physical, GFP_KERNEL);
++ if (dma_rx_buffer == 0) {
++ dbg("Unable to attach UART RX DMA 5 channel\n");
++ return -ENOMEM;
++ }
++ rx_dma_tail = (int) dma_rx_buffer_physical;
++ }
++#endif
++
++ return ret;
++
++probe_err:
++ dbg("probe_err\n");
++ return ret;
++}
++
++
++static int tcc_serial_remove(struct platform_device *dev)
++{
++ struct uart_port *port = tcc_dev_to_port(&dev->dev);
++#ifdef CONFIG_SERIAL_TCC_DMA_RX
++ volatile PGDMACTRL pDMA = (volatile PGDMACTRL)tcc_p2v(HwGDMA_BASE);
++#endif
++
++ if(port->line == UART1){
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, BT_ON, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++ dbg("tcc_uart: BT power %s\n", (tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, 0, OUTPUT, 0, GET_VALUE)&BT_ON)?"ON":"OFF");
++ }
++
++
++ if (port)
++ uart_remove_one_port(&tcc_uart_drv, port);
++
++#ifdef CONFIG_SERIAL_TCC_DMA_TX
++ if(port->line == DMA_PORT)
++ tcc_free_dma_buf(&(tcc_serial_ports[DMA_PORT].dma_tx_buffer));
++#endif
++
++#ifdef CONFIG_SERIAL_TCC_DMA_RX
++ if(port->line == DMA_PORT)
++ {
++ dma_free_writecombine(0,DMA_RX_BUF_SIZE,dma_rx_buffer,dma_rx_buffer_physical);
++ wr_regl(port, OFFSET_UCR, rd_regl(port, OFFSET_UCR) & ~Hw1);
++ pDMA->CHCTRL1 &= Hw0;
++ }
++#endif
++
++
++ return 0;
++}
++
++/* UART power management code */
++
++#ifdef CONFIG_PM
++/*-------------------------------------------------
++ * TODO: handling DMA_PORT suspend/resume (TCC79X)
++ * DMA stop and start ...
++ *-------------------------------------------------*/
++static int tcc_serial_suspend(struct platform_device *dev, pm_message_t state)
++{
++ struct uart_port *port = tcc_dev_to_port(&dev->dev);
++ struct tcc_reg_info *reg = &tcc_serial_ports[port->line].reg;
++
++ if (port && port_used(port)) {
++ port->suspended = 1;
++
++ // disable interrupt
++ wr_regl(port, OFFSET_IER, (rd_regl(port, OFFSET_IER) & (~UART_IER_ELSI)));
++
++ reg->bLCR = rd_regl(port, OFFSET_LCR);
++
++ // DLAB = 0
++ wr_regl(port, OFFSET_LCR, (reg->bLCR & (~Hw7)));
++ reg->bIER = rd_regl(port, OFFSET_IER);
++
++ // DLAB = 1
++ wr_regl(port, OFFSET_LCR, (reg->bLCR | Hw7));
++// reg->bFCR = 0x07; // set in tcc_serial_startup()
++ reg->bDLL = rd_regl(port, OFFSET_DLL);
++ reg->bDLM = rd_regl(port, OFFSET_DLM);
++
++ reg->bMCR = rd_regl(port, OFFSET_MCR);
++ reg->bAFT = rd_regl(port, OFFSET_AFT);
++ reg->bUCR = rd_regl(port, OFFSET_UCR);
++ }
++
++ return 0;
++}
++
++static int tcc_serial_resume(struct platform_device *dev)
++{
++ struct uart_port *port = tcc_dev_to_port(&dev->dev);
++ struct tcc_reg_info *reg = &tcc_serial_ports[port->line].reg;
++
++ if (port && port_used(port)) {
++ if (port->suspended) {
++ // DLAB = 0
++ wr_regl(port, OFFSET_LCR, (reg->bLCR & (~Hw7)));
++ wr_regl(port, OFFSET_IER, reg->bIER);
++
++ // DLAB = 1
++ wr_regl(port, OFFSET_LCR, (reg->bLCR | Hw7));
++ wr_regl(port, OFFSET_FCR, reg->bFCR);
++ wr_regl(port, OFFSET_DLL, reg->bDLL);
++ wr_regl(port, OFFSET_DLM, reg->bDLM);
++
++ wr_regl(port, OFFSET_MCR, reg->bMCR);
++ wr_regl(port, OFFSET_AFT, reg->bAFT);
++ wr_regl(port, OFFSET_UCR, reg->bUCR);
++
++ port->suspended = 0;
++ // DLAB = 0
++ wr_regl(port, OFFSET_LCR, (reg->bLCR & (~Hw7)));
++ wr_regl(port, OFFSET_IER, (rd_regl(port, OFFSET_IER) | UART_IER_ELSI));
++
++ wr_regl(port, OFFSET_LCR, reg->bLCR);
++ }
++ }
++
++ return 0;
++}
++
++#else
++#define tcc_serial_suspend NULL
++#define tcc_serial_resume NULL
++#endif
++
++static int tcc_serial_probe(struct platform_device *dev)
++{
++ return tcc_uart_probe(dev, &tcc_uart_inf);
++}
++
++static struct platform_driver tcc_serial_drv = {
++ .probe = tcc_serial_probe,
++ .remove = tcc_serial_remove,
++ .suspend = tcc_serial_suspend,
++ .resume = tcc_serial_resume,
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int tcc_serial_init(struct platform_driver *drv,
++ struct tcc_uart_info *info)
++{
++ dbg("%s(%p,%p)\n", __func__, drv, info);
++
++ return platform_driver_register(drv);
++}
++
++static inline void tcc_serial_exit(void)
++{
++ //remove_pwm_node(DEVICE_UART);
++ platform_driver_unregister(&tcc_serial_drv);
++}
++
++
++/* module initialisation code */
++
++static int __init tcc_serial_modinit(void)
++{
++ int ret;
++
++ ret = uart_register_driver(&tcc_uart_drv);
++ if (ret < 0) {
++ dbg(KERN_ERR "failed to register UART driver\n");
++ return -1;
++ }
++ //printk("Serial driver %s registered.\n", tcc_uart_drv.driver_name);
++
++ tcc_serial_init(&tcc_serial_drv, &tcc_uart_inf);
++
++ return 0;
++}
++
++static void __exit tcc_serial_modexit(void)
++{
++ tcc_serial_exit();
++
++ uart_unregister_driver(&tcc_uart_drv);
++}
++
++
++module_init(tcc_serial_modinit);
++module_exit(tcc_serial_modexit);
++
++/************************************************************
++ *
++ * The following is Console driver
++ *
++ ************************************************************/
++
++#ifdef CONFIG_SERIAL_TCC_CONSOLE
++
++static struct uart_port *cons_uart;
++
++static void tcc_serial_console_putchar(struct uart_port *port, int ch)
++{
++ while (!(rd_regl(port, OFFSET_LSR) & THRE))
++ barrier();
++
++ wr_regb(port, OFFSET_THR, ch);
++
++}
++
++void tcc_serial_uart_putchar(struct uart_port *port, int ch)
++{
++ while (!(rd_regl(port, OFFSET_LSR) & THRE))
++ barrier();
++
++ wr_regb(port, OFFSET_THR, ch);
++}
++
++
++static void tcc_console_write(struct console *co, const char *s,
++ unsigned int count)
++{
++ struct uart_port *port;
++ unsigned int t_ier, b_ier;
++
++ port = &tcc_serial_ports[co->index].port;
++
++ t_ier = rd_regl(port, OFFSET_IER);
++ b_ier = t_ier;
++
++ wr_regl(port, OFFSET_IER, t_ier & ~ETXI);
++ uart_console_write(cons_uart, s, count, tcc_serial_console_putchar);
++ wr_regl(port, OFFSET_IER, b_ier);
++}
++
++static void __init
++tcc_serial_get_options(struct uart_port *port, int *baud,
++ int *parity, int *bits)
++{
++}
++
++
++/* tcc_serial_init_ports
++ * initialise the serial ports from the machine provided initialisation data.
++ */
++int tcc_serial_init_ports(struct tcc_uart_port *ourport,
++ struct tcc_uart_info *info,
++ struct platform_device *pdev)
++{
++ struct uart_port *port = &ourport->port;
++ struct resource *res;
++ int ret;
++
++ dbg("tcc_serial_init_ports: initialising ports...\n");
++
++ port->iotype = UPIO_MEM;
++ port->flags = UPF_BOOT_AUTOCONF;
++ port->ops = &tcc_serial_ops;
++ port->fifosize = FIFOSIZE;
++ port->line = pdev->id;
++ port->dev = &pdev->dev;
++ port->type = PORT_TCC;
++ ourport->info = info;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (res == NULL) {
++ printk(KERN_ERR "failed to find memory resource for uart\n");
++ return -EINVAL;
++ }
++
++ //port->mapbase = pdev->resource[0].start;
++ port->mapbase = res->start;
++ //port->membase = ioremap_nocache(port->mapbase, MAP_SIZE);
++ port->membase = (unsigned char __iomem *)port->mapbase;
++ port->irq = platform_get_irq(pdev, 0);
++
++ ret = (int)port->line;
++
++ return ret;
++}
++
++static int __init
++tcc_console_setup(struct console *co, char *options)
++{
++ struct uart_port *port;
++ int baud = BAUDRATE;
++ int bits = 8;
++ int parity = 'n';
++ int flow = 'n';
++
++ dbg("tcc_serial_console_setup: co=%p (%d), %s\n", co, co->index, options);
++
++ /* is this a valid port */
++
++ if (co->index == -1 || co->index >= NR_PORTS)
++ co->index = CONSOLE_PORT;
++
++ port = &tcc_serial_ports[co->index].port;
++
++ /* is the port configured? */
++
++ if (port->mapbase == 0x0) {
++ port->mapbase = (resource_size_t)&(CONSOLE_BASE);
++ port->membase = (unsigned char __iomem *)port->mapbase;
++ co->index = CONSOLE_PORT;
++ port = &tcc_serial_ports[co->index].port;
++ }
++
++ cons_uart = port;
++
++ if (options) {
++ dbg("uart_parse_options\n");
++ uart_parse_options(options, &baud, &parity, &bits, &flow);
++ } else {
++ dbg("tcc_serial_get_options\n");
++ tcc_serial_get_options(port, &baud, &parity, &bits);
++ }
++
++ dbg("tcc_serial_console_setup: port=%p (%d)\n", port, co->index);
++ return uart_set_options(port, co, baud, parity, bits, flow);
++}
++
++/* tcc_console_init
++ *
++ * initialise the console from one of the uart drivers
++*/
++
++static struct console tcc_serial_console =
++{
++ .name = TCC_SERIAL_NAME,
++ .device = uart_console_device,
++ .flags = CON_PRINTBUFFER | CON_ENABLED,
++ .index = -1,
++ .write = tcc_console_write,
++ .setup = tcc_console_setup,
++};
++
++static int tcc_console_init(void)
++{
++ struct tcc_uart_info *info;
++
++ dbg("%s\n", __func__);
++
++ info = &tcc_uart_inf;
++
++ tcc_serial_console.data = &tcc_uart_drv;
++ register_console(&tcc_serial_console);
++
++ return 0;
++}
++
++console_initcall(tcc_console_init);
++
++#endif /* CONFIG_SERIAL_TCC_CONSOLE */
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("linux <linux@telechips.com>");
++MODULE_DESCRIPTION("Telechips TCC Serial port driver");
++
+diff --git a/drivers/serial/tcc_serial.h b/drivers/serial/tcc_serial.h
+new file mode 100644
+index 0000000..dc5c3c7
+--- /dev/null
++++ b/drivers/serial/tcc_serial.h
+@@ -0,0 +1,75 @@
++/*
++tcc for UART
++*/
++#ifndef __DEFINES_H__
++#define __DEFINES_H__
++
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/*****************************************************************************
++*
++* Defines
++*
++******************************************************************************/
++
++
++//UART
++#define HwUART_IER_EMSI_EN Hw3 // Enable Modem status interrupt
++#define HwUART_IER_EMSI_DIS ~Hw3 // Disable Modem status interrupt
++#define HwUART_IER_ELSI_EN Hw2 // Enable receiver line status interrupt
++#define HwUART_IER_ELSI_DIS ~Hw2 // Disable receiver line status interrupt
++#define HwUART_IER_ETXI_EN Hw1 // Enable transmitter holding register empty interrupt
++#define HwUART_IER_ETXI_DIS ~Hw1 // Disable transmitter holding register empty interrupt
++#define HwUART_IER_ERXI_EN Hw0 // Enable received data available interrupt
++#define HwUART_IER_ERXI_DIS ~Hw0 // Disable received data available interrupt
++#define HwUART_IIR_STF Hw27 // 1:TX is done (SmartCard TX done flag)
++#define HwUART_IIR_IPF Hw0 // 1:Interrupt has not generated, 0:Interrupt pending
++
++#define HwEXTREQ_UART1_RX Hw30 // Connected Hardware = UART Channel 1 Receiver
++#define HwEXTREQ_UART1_TX Hw29 // Connected Hardware = UART Channel 1 Tranceiver
++#define HwEXTREQ_UART0_RX Hw27 // Connected Hardware = UART Channel 0 Receiver
++#define HwEXTREQ_UART0_TX Hw26 // Connected Hardware = UART Channel 0 Tranceiver
++#define HwEXTREQ_UART3_RX Hw11 // Connected Hardware = UART Channel 3 Receiver
++#define HwEXTREQ_UART3_TX Hw10 // Connected Hardware = UART Channel 3 Tranceiver
++#define HwEXTREQ_UART2_RX Hw9 // Connected Hardware = UART Channel 2 Receiver
++#define HwEXTREQ_UART2_TX Hw8 // Connected Hardware = UART Channel 2 Tranceiver
++
++//DMA
++#define HwCHCTRL_SYNC_EN Hw13 // Synchronize Hardware Request
++#define HwCHCTRL_TYPE_SL (Hw9+Hw8) // SINGLE transfer with level-triggered detection
++#define HwCHCTRL_BSIZE_1 HwZERO // 1 Burst transfer consists of 1 read or write cycle
++#define HwCHCTRL_WSIZE_8 HwZERO // Each cycle read or write 8bit data
++#define HwCHCTRL_IEN_ON Hw2 // At the same time the FLAG goes to 1, DMA interrupt request is generated
++#define HwCHCTRL_FLAG Hw3 // W : Clears FLAG to 0, R : Represents that all hop of transfer are fulfilled
++#define HwCHCTRL_CONT_C Hw15 // DMA transfer begins from C_SADR / C_DADR address. It must be used after the former transfer has been executed, so that C_SADR and C_DADR contain a meaningful vlaue
++#define HwCHCTRL_REP_EN Hw1 // The DMA channel remains enabled. When another DMA request has occurred, the DMA channel start transfer data again with the same manner(type,address,increment,mask) as the latest transfer of that channel
++
++/*****************************************************************************
++*
++* APIs
++*
++******************************************************************************/
++
++void tcc_serial_iobusonoff(int nCh, int nPort, int bOn);
++void tcc_serial_portinit(int nCh, int nPort, unsigned long* pvGpioAddr, unsigned long* pvPortMuxAddr);
++void tcc_serial_portdeinit(int nCh);
++int tcc_dma_ctrl(int m_DmaNumber, unsigned long* pVirtualDmaAddr);
++int tcc_dma_dmacurrentaddress(int m_DmaNumber, unsigned long* pVirtualDmaAddr);
++int tcc_dma_dmadeststartaddress(int m_DmaNumber,unsigned long* pVirtualDmaAddr);
++int tcc_dma_clrien(int m_DmaNumber, unsigned long* pVirtualDmaAddr);
++int tcc_dma_setien(int m_DmaNumber, unsigned long* pVirtualDmaAddr);
++unsigned int tcc_serial_dmaclrinterrupt(unsigned nDmanum, unsigned long* pVirtualDmaAddr);
++void tcc_dma_setconfig( unsigned uCH, void* pSRT,
++ unsigned uSPARAM, void* pDST,
++ unsigned uDPARAM, unsigned uCHCTRL,
++ unsigned uSize, unsigned channel,
++ unsigned mode, unsigned long* pVirtualDmaAddr);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index b9d0efb..3c96d62 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -204,6 +204,20 @@ config SPI_XILINX
+ See the "OPB Serial Peripheral Interface (SPI) (v1.00e)"
+ Product Specification document (DS464) for hardware details.
+
++comment "Telechips GPSB (General Purpose Serial Bus) Controller Drivers"
++
++config SPI_TCC_MASTER
++ tristate "Telechips SPI Master controller"
++ depends on SPI_MASTER && ARCH_TCC
++ help
++ This is SPI master mode driver.
++
++config TSIF_TCC_SLAVE
++ tristate "Telechips SPI Slave (TSIF) controller"
++ depends on ARCH_TCC
++ help
++ This is SPI slave mode driver for TSIF (Transport Stream Interface) modules.
++
+ #
+ # Add new SPI master controllers in alphabetical order above this line
+ #
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index ccf18de..ae896ee 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -31,6 +31,15 @@ obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
+ obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o
+ # ... add above this line ...
+
++# Telechips SPI controller
++ifeq ($(CONFIG_ARCH_TCC),y)
++$(shell ln -fsn $(CONFIG_TCC_STRING)/ $(srctree)/drivers/spi/tcc)
++endif
++
++obj-y += tcc/tca_spi_hwset.o
++obj-$(CONFIG_SPI_TCC_MASTER) += tcc_spi.o
++obj-$(CONFIG_TSIF_TCC_SLAVE) += tcc_tsif.o
++
+ # SPI protocol drivers (device/link on bus)
+ obj-$(CONFIG_SPI_AT25) += at25.o
+ obj-$(CONFIG_SPI_SPIDEV) += spidev.o
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index 3734dc9..3ed9a61 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -262,6 +262,8 @@ int spi_add_device(struct spi_device *spi)
+ goto done;
+ }
+
++/* spidev_open() called setup() */
++#if 0
+ /* Drivers may modify this initial i/o setup, but will
+ * normally rely on the device being setup. Devices
+ * using SPI_CS_HIGH can't coexist well otherwise...
+@@ -272,6 +274,7 @@ int spi_add_device(struct spi_device *spi)
+ "setup", spi->dev.bus_id, status);
+ goto done;
+ }
++#endif
+
+ /* Device may be bound to an active driver when this returns */
+ status = device_add(&spi->dev);
+diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
+index 5d869c4..1f47513 100644
+--- a/drivers/spi/spidev.c
++++ b/drivers/spi/spidev.c
+@@ -482,6 +482,22 @@ static int spidev_open(struct inode *inode, struct file *filp)
+ }
+ }
+ if (status == 0) {
++ /* Telechips spi hw open/close */
++ if (spidev->users == 0) {
++ if (spi_tcc_open(spi_dev_get(spidev->spi))) {
++ status = -EIO;
++ dev_dbg(&spidev->spi->dev, "open(spi_tcc_open)/EIO\n");
++ goto exit;
++ }
++
++ /* This code was moved from spi_add_device() */
++ status = spi_setup(spidev->spi);
++ if (status < 0) {
++ dev_dbg(&spidev->spi->dev, "open(spi_setup)/EIO\n");
++ goto exit;
++ }
++ }
++
+ if (!spidev->buffer) {
+ spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);
+ if (!spidev->buffer) {
+@@ -497,6 +513,7 @@ static int spidev_open(struct inode *inode, struct file *filp)
+ } else
+ pr_debug("spidev: nothing for minor %d\n", iminor(inode));
+
++exit:
+ mutex_unlock(&device_list_lock);
+ unlock_kernel();
+ return status;
+@@ -516,6 +533,9 @@ static int spidev_release(struct inode *inode, struct file *filp)
+ if (!spidev->users) {
+ int dofree;
+
++ /* Telechips spi hw open/close */
++ spi_tcc_close(spi_dev_get(spidev->spi));
++
+ kfree(spidev->buffer);
+ spidev->buffer = NULL;
+
+diff --git a/drivers/spi/tcc8900/tca_spi_hwset.c b/drivers/spi/tcc8900/tca_spi_hwset.c
+new file mode 100644
+index 0000000..96287d9
+--- /dev/null
++++ b/drivers/spi/tcc8900/tca_spi_hwset.c
+@@ -0,0 +1,328 @@
++
++/****************************************************************************
++ * FileName : tca_spi_hwset.c
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++#if defined(_LINUX_)
++#include <linux/module.h>
++#include <mach/io.h>
++#else
++#include <stdlib.h>
++#include "tcc_gpio.h"
++#endif
++
++#include <bsp.h>
++#include "tca_spi_hwset.h"
++
++
++static int tca_spi_isenabledma(struct tca_spi_handle *h)
++{
++ return (h->regs->DMACTR & Hw0) ? 1 : 0;
++}
++
++static int tca_spi_dmastop(struct tca_spi_handle *h)
++{
++ BITCLR(h->regs->DMACTR, Hw31 | Hw30); /* disable DMA Transmit & Receive */
++ BITSET(h->regs->DMAICR, Hw29| Hw28);
++ BITCLR(h->regs->DMACTR, Hw0); /* DMA disable */
++ return 0;
++}
++
++static int tca_spi_dmastart(struct tca_spi_handle *h)
++{
++ BITSET(h->regs->DMACTR, Hw31 | Hw30); /* enable DMA Transmit & Receive */
++ BITCLR(h->regs->DMACTR, Hw17 | Hw16 | Hw15 | Hw14); /* set Multiple address mode */
++
++ BITCLR(h->regs->DMAICR, Hw16); /* disable DMA Packet Interrupt */
++ BITSET(h->regs->DMAICR, Hw17); /* enable DMA Done Interrupt */
++ BITCLR(h->regs->DMAICR, Hw20); /* set rx interrupt */
++
++ BITSET(h->regs->DMACTR, Hw0); /* DMA enable */
++ return 0;
++}
++
++static int tca_spi_dmastart_slave(struct tca_spi_handle *h)
++{
++ //BITSET(h->regs->DMACTR, Hw31 | Hw30); /* enable DMA Transmit & Receive */
++ BITSET(h->regs->DMACTR, Hw30); /* enable DMA Transmit */
++ BITCLR(h->regs->DMACTR, Hw17 | Hw16 | Hw15 | Hw14); /* set Multiple address mode */
++
++ BITSET(h->regs->DMAICR, Hw16); /* enable DMA Packet Interrupt */
++ //BITSET(h->regs->DMAICR, Hw17); /* enable DMA Done Interrupt */
++ BITCLR(h->regs->DMAICR, Hw20); /* set rx interrupt */
++
++ //h->regs->DMAICR = h->regs->DMAICR | (256 & 0x1FFF);
++ BITSET(h->regs->DMAICR, Hw16); /* enable DMA Packet Interrupt */
++
++ if (h->dma_mode == 0) {
++ BITCSET(h->regs->DMACTR, Hw5|Hw4, Hw29); /* Normal mode & Continuous mode*/
++ } else {
++ BITSET(h->regs->DMACTR, Hw4); /* MPEG2-TS mode */
++ }
++
++ BITSET(h->regs->DMACTR, Hw0); /* DMA enable */
++ return 0;
++}
++
++static void tca_spi_clearfifopacket(struct tca_spi_handle *h)
++{
++ /* clear tx/rx FIFO & Packet counter */
++ BITSET(h->regs->MODE, Hw15 | Hw14);
++ BITSET(h->regs->DMACTR, Hw2);
++ BITCLR(h->regs->DMACTR, Hw2);
++ BITCLR(h->regs->MODE, Hw15 | Hw14);
++}
++
++static void tca_spi_setpacketcnt(struct tca_spi_handle *h, int size)
++{
++ /* set packet count & size */
++ h->regs->PACKET = (size & 0x1FFF);
++}
++
++static void tca_spi_setpacketcnt_slave(struct tca_spi_handle *h, int size)
++{
++ unsigned int packet_cnt = (h->dma_total_packet_cnt & 0x1FFF) - 1;
++ unsigned int packet_size = (MPEG_PACKET_SIZE & 0x1FFF);
++ unsigned int intr_packet_cnt = (h->dma_intr_packet_cnt & 0x1FFF) - 1;
++
++ if (packet_size != size) {
++ size = packet_size;
++ }
++
++ h->regs->PACKET = (packet_cnt << 16) | packet_size;
++ BITCSET(h->regs->DMAICR, 0x1FFF, intr_packet_cnt);
++}
++
++static void tca_spi_setbitwidth(struct tca_spi_handle *h, int width)
++{
++ int width_value = (width - 1) & 0x1F;
++
++ /* set bit width */
++ BITCLR(h->regs->MODE, Hw12 | Hw11 | Hw10 | Hw9 | Hw8);
++ h->regs->MODE |= (width_value << 8);
++ if (width_value & Hw4) {
++ BITCLR(h->regs->DMACTR, Hw28);
++ } else {
++ BITSET(h->regs->DMACTR, Hw28);
++ }
++}
++
++static void tca_spi_setdmaaddr(struct tca_spi_handle *h)
++{
++ /* set dma txbase/rxbase & request DMA tx/rx */
++ h->regs->TXBASE = h->tx_dma.dma_addr;
++ h->regs->RXBASE = h->rx_dma.dma_addr;
++
++ h->regs->INTEN = h->tx_dma.dma_addr ? (h->regs->INTEN | Hw31) : (h->regs->INTEN & ~Hw31);
++ h->regs->INTEN = h->rx_dma.dma_addr ? (h->regs->INTEN | Hw30) : (h->regs->INTEN & ~Hw30);
++}
++
++static void tca_spi_setdmaaddr_slave(struct tca_spi_handle *h)
++{
++ /* set dma txbase/rxbase & request DMA tx/rx */
++ h->regs->RXBASE = h->rx_dma.dma_addr;
++ h->regs->INTEN = h->rx_dma.dma_addr ? (h->regs->INTEN | Hw30) : (h->regs->INTEN & ~Hw30);
++}
++
++static void tca_spi_hwinit(struct tca_spi_handle *h)
++{
++ /* init => set SPI mode, set Master mode ... */
++ memset((void *)(h->regs), 0, sizeof(struct tca_spi_regs));
++
++ h->set_bit_width(h, 32);
++
++ /* [SCK] Tx: risiing edge, Rx: falling edge & enable Operation */
++ BITSET((h->regs)->MODE, Hw17 | Hw18 | Hw3);
++
++ h->set_dma_addr(h);
++ h->clear_fifo_packet(h);
++}
++
++static void tca_spi_hwinit_slave(struct tca_spi_handle *h)
++{
++ /* init => set SPI mode, set Master mode ... */
++ memset((void *)(h->regs), 0, sizeof(struct tca_spi_regs));
++
++ h->set_bit_width(h, 32);
++
++ /* [SCK] Tx: risiing edge, Rx: falling edge & enable Operation */
++ BITSET((h->regs)->MODE, Hw17 | Hw18 | Hw3);
++ BITSET((h->regs)->MODE, Hw2 | Hw5);
++
++ h->set_dma_addr(h);
++ h->clear_fifo_packet(h);
++}
++
++static void tca_spi_set_mpegtspidmode(struct tca_spi_handle *h, int is_set)
++{
++ if (is_set) {
++ BITSET(h->regs->DMACTR, Hw19 | Hw18);
++ } else {
++ BITCLR(h->regs->DMACTR, Hw19 | Hw18);
++ }
++}
++
++
++/******************************
++ * return value
++ *
++ * ret == 0: success
++ * ret > 0 or ret < 0: fail
++ ******************************/
++int tca_spi_init(tca_spi_handle_t *h,
++ volatile struct tca_spi_regs *regs,
++ int irq,
++ dma_alloc_f tea_dma_alloc,
++ dma_free_f tea_dma_free,
++ int dma_size,
++ int id,
++ int is_slave)
++{
++ int ret = -1;
++
++#if defined(_LINUX_)
++ volatile PPIC pic_regs = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++ volatile PGPIO gpio_regs = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
++ volatile PGPSBPORTCFG gpsb_pcf_regs = (volatile PGPSBPORTCFG)tcc_p2v(HwGPSBPORTCFG_BASE);
++#else
++ PPIC pic_regs = (PPIC)tcc_allocbaseaddress((unsigned int)&HwPIC_BASE);
++ PGPIO gpio_regs = (PGPIO)tcc_allocbaseaddress((unsigned int)&HwGPIO_BASE);
++ PGPSBPORTCFG gpsb_pcf_regs = (PGPSBPORTCFG)tcc_allocbaseaddress((unsigned int)&HwGPSBPORTCFG_BASE);
++#endif
++
++ if (h) { memset(h, 0, sizeof(tca_spi_handle_t)); }
++ if (regs) {
++ h->regs = regs;
++ h->irq = irq;
++ h->id = id;
++ h->is_slave = is_slave;
++ h->gpio_set = 0x1234;
++
++ h->dma_stop = tca_spi_dmastop;
++ h->dma_start = is_slave ? tca_spi_dmastart_slave : tca_spi_dmastart;
++ h->clear_fifo_packet = tca_spi_clearfifopacket;
++ h->set_packet_cnt = is_slave ? tca_spi_setpacketcnt_slave : tca_spi_setpacketcnt;
++ h->set_bit_width = tca_spi_setbitwidth;
++ h->set_dma_addr = is_slave ? tca_spi_setdmaaddr_slave : tca_spi_setdmaaddr;
++ h->hw_init = is_slave ? tca_spi_hwinit_slave : tca_spi_hwinit;
++ h->is_enable_dma = tca_spi_isenabledma;
++ h->set_mpegts_pidmode = tca_spi_set_mpegtspidmode;
++
++ h->tea_dma_alloc = tea_dma_alloc;
++ h->tea_dma_free = tea_dma_free;
++
++ h->dma_total_size = dma_size;
++ h->dma_mode = 1; /* default MPEG2-TS DMA mode */
++
++ /* interrupt init */
++ BITSET(pic_regs->MODE1, HwINT1_GPSB); // level-trigger
++ BITCLR(pic_regs->POL1, HwINT1_GPSB); // active-high
++
++ /* clear gpsb port config except used port (ch0, ch1) */
++ //BITSET(gpsb_pcf_regs->PCFG0, Hw32-Hw16); // GPS use ch2
++ BITSET(gpsb_pcf_regs->PCFG1, Hw16-Hw0);
++
++ if (h->id == 0) {
++#if 1
++ /* GPIO_C[31:29] - port 10(0xA) - TSIF only */
++ BITCSET(gpio_regs->GPCFN3, Hw32-Hw20, Hw29|Hw25|Hw21);
++ BITCSET(gpsb_pcf_regs->PCFG0, Hw8-Hw0, 0xA);
++#else
++ /* port config (SPI0 == DXB0, GPIO_D[8:5]) --- TODO:GPIO_C[31:29]*/
++ BITCSET(gpio_regs->GPDFN0, Hw32-Hw20, Hw29|Hw25|Hw21); // GPIOD[7:5]
++ if (is_slave) {
++ BITCLR(gpio_regs->GPDFN1, Hw4-Hw0); // for TSIF (GPIOD[8] is reset pin)
++ } else {
++ BITCSET(gpio_regs->GPDFN1, Hw4-Hw0, Hw1); // for Master (GPIOD[8] is SDO1)
++ }
++ /* GPSB port config (channel 0 port mapping == 11) */
++ BITCSET(gpsb_pcf_regs->PCFG0, Hw8-Hw0, 0xB);
++#endif
++ } else {
++ /* port config (SPI1 == DXB1) */
++ if (is_slave) {
++ BITCSET(gpio_regs->GPEFN1, Hw12-Hw0, Hw9|Hw5|Hw1); // for TSIF (GPIOE[10:8])
++ } else {
++ BITCSET(gpio_regs->GPEFN1, Hw16-Hw0, Hw13|Hw9|Hw5|Hw1); // for Master (GPIOE[11:8])
++ }
++ /* GPSB port config (channel 1 port mapping == 4) */
++ BITCSET(gpsb_pcf_regs->PCFG0, Hw16-Hw8, 0x400);
++ }
++
++ if (h->tea_dma_alloc) {
++ if (h->tea_dma_alloc(&(h->rx_dma), dma_size) == 0) {
++ if (is_slave) {
++ ret = 0;
++ } else if (h->tea_dma_alloc(&(h->tx_dma), dma_size) == 0 && h->tea_dma_alloc(&(h->tx_dma_1), dma_size) == 0) {
++ ret = 0;
++ }
++ }
++ } else {
++ /* Already, tsif has rx_dma buf */
++ ret = 0;
++ }
++
++ if (ret) { tca_spi_clean(h); }
++ }
++
++ return ret;
++}
++
++void tca_spi_clean(tca_spi_handle_t *h)
++{
++ if (h) {
++ if (h->tea_dma_free) {
++ h->tea_dma_free(&(h->tx_dma));
++ h->tea_dma_free(&(h->rx_dma));
++ h->tea_dma_free(&(h->tx_dma_1));
++ }
++ memset(h, 0, sizeof(tca_spi_handle_t));
++
++ /* release GPIO */
++ if (h->gpio_set == 0x1234) {
++ #if defined(_LINUX_)
++ volatile PGPIO gpio_regs = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
++ #else
++ PGPIO gpio_regs = (PGPIO)tcc_allocbaseaddress((unsigned int)&HwGPIO_BASE);
++ #endif
++
++ if (h->id == 0) {
++#if 1
++ /* GPIO_C[31:29] set "GPIO output low" */
++ BITCLR(gpio_regs->GPCFN3, Hw32-Hw20);
++ BITSET(gpio_regs->GPCEN, Hw31|Hw30|Hw29);
++ BITCLR(gpio_regs->GPCDAT, Hw31|Hw30|Hw29);
++#else
++ /* port config (SPI0 == DXB0, GPIO_D[8:5]) */
++ BITCLR(gpio_regs->GPDFN0, Hw32-Hw20); // GPIOD[7:5]
++ BITCLR(gpio_regs->GPDFN1, Hw4-Hw0); // GPIOD[8]
++ BITSET(gpio_regs->GPDEN, Hw8|Hw7|Hw6|Hw5);
++ BITCLR(gpio_regs->GPDDAT, Hw8|Hw7|Hw6|Hw5);
++#endif
++ } else {
++ /* port config (SPI1 == DXB1) */
++ if (h->is_slave) {
++ BITCLR(gpio_regs->GPEFN1, Hw12-Hw0); // for TSIF (GPIOE[10:8])
++ BITSET(gpio_regs->GPEEN, Hw10|Hw9|Hw8);
++ BITCLR(gpio_regs->GPEDAT, Hw10|Hw9|Hw8);
++ } else {
++ BITCLR(gpio_regs->GPEFN1, Hw16-Hw0); // for Master (GPIOE[11:8])
++ BITSET(gpio_regs->GPEEN, Hw11|Hw10|Hw9|Hw8);
++ BITCLR(gpio_regs->GPEDAT, Hw11|Hw10|Hw9|Hw8);
++ }
++ }
++ }
++ }
++}
++
++#if defined(_LINUX_)
++EXPORT_SYMBOL(tca_spi_init);
++EXPORT_SYMBOL(tca_spi_clean);
++#endif
+diff --git a/drivers/spi/tcc8900/tca_spi_hwset.h b/drivers/spi/tcc8900/tca_spi_hwset.h
+new file mode 100644
+index 0000000..21c479a
+--- /dev/null
++++ b/drivers/spi/tcc8900/tca_spi_hwset.h
+@@ -0,0 +1,116 @@
++/****************************************************************************
++ * FileName : tca_spi_hwset.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#ifndef __TCA_SPI_HWSET_H__
++#define __TCA_SPI_HWSET_H__
++
++#if !defined(_LINUX_)
++#define TSIF_DTCM_DMA_MEM_SIZE 0x1600
++#define TSIF_RX_BUFFER_BASE_VA (0x8A000000 + 0x200)
++#define TSIF_RX_BUFFER_BASE_PA (0xA0000000 + 0x200)
++#endif
++
++#define MPEG_PACKET_SIZE 188
++#define WAIT_TIME_FOR_DMA_DONE (1000 * 8)
++
++#pragma pack(push, 4)
++struct tca_spi_regs {
++ volatile unsigned long PORT, STAT, INTEN, MODE, CTRL, EVTCTRL, CCV,
++ DUMMY,
++ TXBASE, RXBASE, PACKET, DMACTR, DMASTR, DMAICR;
++};
++#pragma pack(pop)
++
++struct tea_dma_buf {
++ void *v_addr;
++ unsigned int dma_addr;
++ int buf_size; // total size of DMA
++};
++
++typedef struct tca_spi_handle tca_spi_handle_t;
++typedef int (*dma_alloc_f)(struct tea_dma_buf *tdma, unsigned int size);
++typedef void (*dma_free_f)(struct tea_dma_buf *tdma);
++
++struct tca_spi_handle {
++ volatile struct tca_spi_regs *regs;
++ struct tea_dma_buf tx_dma, rx_dma;
++ struct tea_dma_buf tx_dma_1;
++ int flag;
++ int irq;
++ void *private_data;
++ int id;
++ int is_slave;
++ int gpio_set;
++
++ int (*is_enable_dma)(tca_spi_handle_t *h);
++ int (*dma_stop)(tca_spi_handle_t *h);
++ int (*dma_start)(tca_spi_handle_t *h);
++ void (*clear_fifo_packet)(tca_spi_handle_t *h);
++ void (*set_packet_cnt)(tca_spi_handle_t *h, int cnt);
++ void (*set_bit_width)(tca_spi_handle_t *h, int width);
++ void (*set_dma_addr)(tca_spi_handle_t *h);
++ void (*hw_init)(tca_spi_handle_t *h);
++ void (*set_mpegts_pidmode)(tca_spi_handle_t *h, int is_set);
++
++ dma_alloc_f tea_dma_alloc; // tea function.
++ dma_free_f tea_dma_free; // tea function.
++
++ int clk; // Mhz
++
++ /* add for slave */
++ unsigned int dma_total_packet_cnt, dma_intr_packet_cnt;
++ int q_pos, cur_q_pos;
++ int dma_total_size;
++ int dma_mode;
++};
++
++
++#define tca_spi_setCPOL(R, S) \
++ do {\
++ if (S) BITSET((R)->MODE, Hw16);\
++ else BITCLR((R)->MODE, Hw16);\
++ } while (0)
++
++#define tca_spi_setCPHA(R, S) \
++ do {\
++ if (S) BITSET((R)->MODE, Hw18 | Hw17);\
++ else BITCLR((R)->MODE, Hw18 | Hw17);\
++ } while (0)
++
++#define tca_spi_setCS_HIGH(R, S) \
++ do {\
++ if (S) BITSET((R)->MODE, Hw20 | Hw19);\
++ else BITCLR((R)->MODE, Hw20 | Hw19);\
++ } while (0)
++#define tca_spi_setLSB_FIRST(R, S) \
++ do {\
++ if (S) BITSET((R)->MODE, Hw7);\
++ else BITCLR((R)->MODE, Hw7);\
++ } while (0)
++
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++extern int tca_spi_init(tca_spi_handle_t *h,
++ volatile struct tca_spi_regs *regs,
++ int irq,
++ dma_alloc_f tea_dma_alloc,
++ dma_free_f tea_dma_free,
++ int dma_size,
++ int id,
++ int is_slave);
++
++extern void tca_spi_clean(tca_spi_handle_t *h);
++#ifdef __cplusplus
++}
++#endif
++
++#endif /*__TCA_SPI_HWSET_H__*/
+diff --git a/drivers/spi/tcc_spi.c b/drivers/spi/tcc_spi.c
+new file mode 100644
+index 0000000..d04fe86
+--- /dev/null
++++ b/drivers/spi/tcc_spi.c
+@@ -0,0 +1,590 @@
++/*
++ * linux/drivers/spi/tcc_spi.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 1st April, 2009
++ * Description: Driver for Telechips SPI Controllers
++ * SPI master mode
++ *
++ * Copyright (c) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++#include <linux/init.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/compile.h>
++
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++
++#include <asm/io.h>
++#include <asm/dma.h>
++
++#include <bsp.h>
++#include "tcc/tca_spi_hwset.h"
++
++
++#define SPI_DMA_SIZE 2048
++
++struct tcc_peri_id_table {
++ unsigned int bus_id;
++ unsigned int clk_id;
++};
++
++struct tcc_peri_id_table sa_peri_id_table[] = {
++ { RB_GPSBCONTROLLER0, PERI_GPSB0 },
++ { RB_GPSBCONTROLLER1, PERI_GPSB1 },
++// { RB_GPSBCONTROLLER2, PERI_GPSB2 },
++// { RB_GPSBCONTROLLER3, PERI_GPSB3 },
++// { RB_GPSBCONTROLLER4, PERI_GPSB4 },
++// { RB_GPSBCONTROLLER5, PERI_GPSB5 },
++};
++
++struct tca_spi_pri_handle {
++ struct platform_device *pdev;
++ int rx_len, rx_cnt;
++ int tx_len, tx_cnt;
++ struct {
++ int xfer_pos;
++ int value;
++ } done;
++
++ unsigned char stopping;
++ wait_queue_head_t wait_q;
++ struct list_head queue;
++ struct spi_message *current_message;
++ spinlock_t lock;
++};
++
++static void tea_free_dma_linux(struct tea_dma_buf *tdma)
++{
++ if (tdma) {
++ if (tdma->v_addr != 0) {
++ dma_free_writecombine(0, tdma->buf_size, tdma->v_addr, tdma->dma_addr);
++ }
++ memset(tdma, 0, sizeof(struct tea_dma_buf));
++ }
++}
++
++static int tea_alloc_dma_linux(struct tea_dma_buf *tdma, unsigned int size)
++{
++ int ret = -1;
++ if (tdma) {
++ tea_free_dma_linux(tdma);
++ tdma->buf_size = size;
++ tdma->v_addr = dma_alloc_writecombine(0, tdma->buf_size, &tdma->dma_addr, GFP_KERNEL);
++ //printk("tcc_spi: alloc DMA buffer @0x%X(Phy=0x%X), size:%d\n",
++ // (unsigned int)tdma->v_addr,
++ // (unsigned int)tdma->dma_addr,
++ // tdma->buf_size);
++ ret = tdma->v_addr ? 0 : 1;
++ }
++ return ret;
++}
++
++static int tcc_spi_start_rxtx(struct spi_master *master, unsigned int flen)
++{
++ struct tca_spi_handle *tspi = spi_master_get_devdata(master);
++ struct tca_spi_pri_handle *tpri = (struct tca_spi_pri_handle *)tspi->private_data;
++
++ tpri->done.value = -EIO;
++ //mutex_lock(&(tpri->pm_mutex));
++
++ if ((flen > 0) && (flen <= tspi->rx_dma.buf_size)) {
++ tpri->rx_len = flen;
++ tpri->tx_len = flen;
++ tpri->rx_cnt = 0;
++ tpri->tx_cnt = 0;
++
++ tspi->clear_fifo_packet(tspi);
++ tspi->set_packet_cnt(tspi, flen);
++ tspi->dma_start(tspi);
++
++ if (wait_event_interruptible_timeout((tpri->wait_q),
++ (tpri->rx_cnt == tpri->rx_len),
++ msecs_to_jiffies(WAIT_TIME_FOR_DMA_DONE)) == 0) {
++ printk("[%s] wait_event timeout (%dms) !!!\n",
++ __func__, WAIT_TIME_FOR_DMA_DONE);
++ } else {
++ if (tpri->rx_cnt == tpri->rx_len) {
++ tpri->done.value = 0;
++ }
++ }
++ }
++
++ tpri->current_message = NULL;
++ //mutex_unlock(&(tpri->pm_mutex));
++
++ return tpri->done.value;
++}
++
++static void tcc_spi_next_message(struct spi_master *master)
++{
++ struct tca_spi_handle *tspi = NULL;
++ struct spi_message *msg = NULL;
++ struct spi_device *spi = NULL;
++ struct spi_transfer *xfer = NULL;
++ unsigned int flen = 0;
++ unsigned int copy_len = 0, total_len = 0;
++ struct tca_spi_pri_handle *tpri = NULL;
++ unsigned int bit_width = 0;
++
++ tspi = spi_master_get_devdata(master);
++ tpri = (struct tca_spi_pri_handle *)tspi->private_data;
++
++ BUG_ON(tpri->current_message);
++
++ msg = list_entry(tpri->queue.next, struct spi_message, queue);
++ list_del_init(&(msg->queue));
++ tpri->current_message = msg;
++
++ spi = msg->spi;
++
++ list_for_each_entry(xfer, &(msg->transfers), transfer_list) {
++ tpri->done.xfer_pos = 0;
++ tpri->done.value = 0;
++ total_len = xfer->len;
++ do {
++ copy_len = (total_len > tspi->rx_dma.buf_size) ? tspi->rx_dma.buf_size : total_len;
++
++ if (copy_len & 0x3) {
++ copy_len %= 4;
++ bit_width = tspi->regs->MODE;
++ bit_width = ((bit_width >> 8) & 0x1F) + 1;
++ tspi->set_bit_width(tspi, 8);
++ }
++
++ if (xfer->tx_buf) {
++ if (tspi->flag) {
++ tspi->regs->TXBASE = tspi->tx_dma.dma_addr;
++ memcpy(tspi->tx_dma.v_addr, xfer->tx_buf + tpri->done.xfer_pos, copy_len);
++ tspi->flag = 0;
++ } else {
++ tspi->regs->TXBASE = tspi->tx_dma_1.dma_addr;
++ memcpy(tspi->tx_dma_1.v_addr, xfer->tx_buf + tpri->done.xfer_pos, copy_len);
++ tspi->flag = 1;
++ }
++ }
++
++ if (tcc_spi_start_rxtx(master, copy_len)) {
++ tspi->clear_fifo_packet(tspi);
++ goto lb_return;
++ }
++
++ if (xfer->rx_buf) {
++ memcpy(xfer->rx_buf + tpri->done.xfer_pos, tspi->rx_dma.v_addr, copy_len);
++ }
++
++ if (bit_width) {
++ tspi->set_bit_width(tspi, bit_width);
++ bit_width = 0;
++ }
++
++ total_len -= copy_len;
++ tpri->done.xfer_pos += copy_len;
++ } while (total_len);
++ flen += xfer->len;
++ }
++
++lb_return:
++ msg->status = tpri->done.value;
++ if (msg->status == 0) {
++ msg->actual_length = flen;
++ }
++ msg->complete(msg->context);
++
++ if (list_empty(&(tpri->queue)) || tpri->stopping) {
++ ;
++ } else {
++ tcc_spi_next_message(master);
++ }
++}
++
++static irqreturn_t tcc_spi_isr(int irq, void *dev_id)
++{
++ struct spi_master *master = dev_id;
++ struct tca_spi_handle *tspi = spi_master_get_devdata(master);
++ //unsigned long flags = 0;
++ unsigned long dma_done_reg = 0;
++ struct tca_spi_pri_handle *tpri = (struct tca_spi_pri_handle *)tspi->private_data;
++
++ //local_save_flags(flags);
++ //local_irq_disable();
++
++ dma_done_reg = tspi->regs->DMAICR;
++
++ if (dma_done_reg & Hw29) {
++ tspi->dma_stop(tspi);
++ tpri->tx_cnt = tpri->tx_len;
++ tpri->rx_cnt = tpri->rx_len;
++ wake_up(&(tpri->wait_q));
++ }
++
++ //local_irq_restore(flags);
++ return IRQ_HANDLED;
++}
++
++#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST)
++static int tcc_spi_setup(struct spi_device *spi)
++{
++ struct tca_spi_handle *tspi = NULL;
++ unsigned int bits = spi->bits_per_word;
++ struct tca_spi_pri_handle *tpri = NULL;
++ //unsigned int mode = 0;
++
++ tspi = spi_master_get_devdata(spi->master);
++ tpri = (struct tca_spi_pri_handle *)tspi->private_data;
++
++ if (tpri->stopping)
++ return -ESHUTDOWN;
++ if (spi->chip_select > spi->master->num_chipselect) {
++ dev_dbg(&spi->dev,
++ "setup: invalid chipselect %u (%u defined)\n",
++ spi->chip_select, spi->master->num_chipselect);
++ return -EINVAL;
++ }
++
++ if (bits == 0)
++ bits = 8;
++ if (bits != 8 && bits != 16 && bits != 32) {
++ dev_dbg(&spi->dev, "setup: invalid bits_per_word %u\n", bits);
++ return -EINVAL;
++ }
++ tspi->set_bit_width(tspi, bits);
++
++ if (spi->mode & ~MODEBITS) {
++ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
++ spi->mode & ~MODEBITS);
++ return -EINVAL;
++ }
++
++ //mode = tspi->regs->MODE;
++ tca_spi_setCPOL(tspi->regs, (spi->mode & SPI_CPOL));
++ tca_spi_setCPHA(tspi->regs, (spi->mode & SPI_CPHA));
++ tca_spi_setCS_HIGH(tspi->regs, (spi->mode & SPI_CS_HIGH));
++ tca_spi_setLSB_FIRST(tspi->regs, (spi->mode & SPI_LSB_FIRST));
++ //tspi->regs->MODE = mode;
++
++ return 0;
++}
++
++static int tcc_spi_transfer(struct spi_device *spi, struct spi_message *msg)
++{
++ struct tca_spi_handle *tspi = NULL;
++ //unsigned long flags = 0;
++ struct tca_spi_pri_handle *tpri = NULL;
++
++ tspi = (struct tca_spi_handle *)spi_master_get_devdata(spi->master);
++ tpri = (struct tca_spi_pri_handle *)tspi->private_data;
++
++ if (unlikely(list_empty(&(msg->transfers)))) {
++ return -EINVAL;
++ }
++
++ if (tpri->stopping) {
++ return -ESHUTDOWN;
++ }
++
++ msg->status = -EINPROGRESS;
++ msg->actual_length = 0;
++
++ //spin_lock_irqsave(&(tpri->lock), flags);
++ list_add_tail(&(msg->queue), &(tpri->queue));
++ if (!tpri->current_message) {
++ tcc_spi_next_message(spi->master);
++ }
++ //spin_unlock_irqrestore(&(tpri->lock), flags);
++ return 0;
++}
++
++static void tcc_spi_cleanup(struct spi_device *spi)
++{
++ if (!spi->controller_state)
++ return;
++ dev_dbg(&spi->dev, "tcc_spi_cleanup\n");
++}
++
++static void tcc_spi_close(struct spi_device *spi)
++{
++ struct tca_spi_handle *tspi = NULL;
++ struct tca_spi_pri_handle *tpri = NULL;
++ struct spi_message *msg = NULL;
++
++ tspi = spi_master_get_devdata(spi->master);
++
++ tpri = (struct tca_spi_pri_handle *)tspi->private_data;
++ spin_lock_irq(&(tpri->lock));
++ tpri->stopping = 1;
++ spin_unlock_irq(&tpri->lock);
++ list_for_each_entry(msg, &(tpri->queue), queue) {
++ msg->status = -ESHUTDOWN;
++ msg->complete(msg->context);
++ }
++ if (tpri) { kfree(tpri); }
++
++ free_irq(tspi->irq, spi->master);
++
++ tca_spi_clean(tspi);
++ tca_ckc_setiobus(sa_peri_id_table[tspi->id].bus_id, DISABLE);
++ tca_ckc_setperi(sa_peri_id_table[tspi->id].clk_id, DISABLE, 40000, PCDIRECTPLL2);
++}
++
++static int tcc_spi_open(struct spi_device *spi)
++{
++ int ret = 0;
++ struct spi_master *master = NULL;
++ struct platform_device *pdev = NULL;
++ struct tca_spi_handle *tspi = NULL;
++ struct tca_spi_pri_handle *tpri = NULL;
++
++ master = spi->master;
++ tspi = spi_master_get_devdata(spi->master);
++
++ tpri = (struct tca_spi_pri_handle *)kmalloc(sizeof(struct tca_spi_pri_handle), GFP_KERNEL);
++ if (tpri == NULL) {
++ return -ENOMEM;
++ }
++ memset(tpri, 0, sizeof(struct tca_spi_pri_handle));
++
++ /* iobus reset */
++ tca_ckc_set_iobus_swreset(sa_peri_id_table[master->bus_num].bus_id, OFF);
++ tca_ckc_set_iobus_swreset(sa_peri_id_table[master->bus_num].bus_id, ON);
++
++ tca_ckc_setiobus(sa_peri_id_table[master->bus_num].bus_id, ENABLE);
++ tca_ckc_setperi(sa_peri_id_table[master->bus_num].clk_id, ENABLE, 40000, PCDIRECTPLL2);
++
++ if (tca_spi_init(tspi,
++ (volatile struct tca_spi_regs *)master->tcc_reg_base,
++ master->tcc_irq_no,
++ tea_alloc_dma_linux,
++ tea_free_dma_linux,
++ SPI_DMA_SIZE,
++ master->bus_num,
++ 0)) {
++ goto err;
++ }
++
++ tspi->private_data = (void *)tpri;
++ tpri->pdev = pdev;
++
++ spin_lock_init(&(tpri->lock));
++ INIT_LIST_HEAD(&(tpri->queue));
++
++ tspi->clear_fifo_packet(tspi);
++ tspi->dma_stop(tspi);
++ init_waitqueue_head(&(tpri->wait_q));
++
++ tspi->hw_init(tspi);
++
++ ret = request_irq(tspi->irq, tcc_spi_isr, IRQF_SHARED, master->dev.parent->bus_id, master);
++ if (ret) { goto err; }
++
++ return 0;
++
++err:
++ printk("%s: error!!!\n", __func__);
++ tca_spi_clean(tspi);
++ tca_ckc_setiobus(sa_peri_id_table[pdev->id].bus_id, DISABLE);
++ tca_ckc_setperi(sa_peri_id_table[pdev->id].bus_id, DISABLE, 40000, PCDIRECTPLL2);
++ if (tpri) { kfree(tpri); }
++ return ret;
++}
++
++static int __init tcc_spi_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++ int irq = -1;
++ struct resource *regs = NULL;
++ struct spi_master *master = NULL;
++ //struct tca_spi_handle *tspi = NULL;
++ //struct tca_spi_pri_handle *tpri = NULL;
++
++ printk("tcc-spi: spi%d probe\n", pdev->id);
++
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!regs) {
++ return -ENXIO;
++ }
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ return -ENXIO;
++ }
++
++ master = spi_alloc_master(&(pdev->dev), sizeof(struct tca_spi_handle));
++ if (!master) {
++ ret = -ENOMEM;
++ goto LB_ret_put;
++ }
++
++ //tpri = (struct tca_spi_pri_handle *)kmalloc(sizeof(struct tca_spi_pri_handle), GFP_KERNEL);
++ //if (tpri == NULL) {
++ // ret = -ENOMEM;
++ // goto LB_ret_put;
++ //}
++ //memset(tpri, 0, sizeof(struct tca_spi_pri_handle));
++
++ /* iobus reset */
++ //tca_ckc_set_iobus_swreset(sa_peri_id_table[pdev->id].bus_id, OFF);
++ //tca_ckc_set_iobus_swreset(sa_peri_id_table[pdev->id].bus_id, ON);
++ //
++ //tca_ckc_setiobus(sa_peri_id_table[pdev->id].bus_id, ENABLE);
++ //tca_ckc_setperi(sa_peri_id_table[pdev->id].clk_id, ENABLE, 40000, PCDIRECTPLL2);
++
++ master->bus_num = pdev->id;
++ master->num_chipselect = 1;
++ master->setup = tcc_spi_setup;
++ master->transfer = tcc_spi_transfer;
++ master->cleanup = tcc_spi_cleanup;
++ master->tcc_open = tcc_spi_open;
++ master->tcc_close = tcc_spi_close;
++ master->tcc_irq_no = irq;
++ master->tcc_reg_base = regs->start;
++ platform_set_drvdata(pdev, master);
++
++ //tspi = spi_master_get_devdata(master);
++ //if (tca_spi_init(tspi,
++ // (volatile struct tca_spi_regs *)regs->start,
++ // irq,
++ // tea_alloc_dma_linux,
++ // tea_free_dma_linux,
++ // SPI_DMA_SIZE,
++ // pdev->id,
++ // 0)) {
++ // goto LB_ret_put;
++ //}
++
++ //tspi->private_data = (void *)tpri;
++ //tpri->pdev = pdev;
++
++ //spin_lock_init(&(tpri->lock));
++ //INIT_LIST_HEAD(&(tpri->queue));
++
++ //tspi->clear_fifo_packet(tspi);
++ //tspi->dma_stop(tspi);
++ //init_waitqueue_head(&(tpri->wait_q));
++
++ ret = spi_register_master(master);
++ if (ret) { goto LB_ret_free; }
++
++ //tspi->hw_init(tspi);
++
++ //ret = request_irq(tspi->irq, tcc_spi_isr, IRQF_SHARED, pdev->dev.bus_id, master);
++ //if (ret) { goto LB_ret_free; }
++
++ return 0;
++
++LB_ret_free:
++ //tca_spi_clean(tspi);
++
++LB_ret_put:
++ spi_master_put(master);
++ //if (tpri) { kfree(tpri); }
++
++ return ret;
++}
++
++static int tcc_spi_remove(struct platform_device *pdev)
++{
++ struct spi_master *master = platform_get_drvdata(pdev);
++ //struct tca_spi_handle *tspi = NULL;
++ //struct spi_message *msg = NULL;
++ //struct tca_spi_pri_handle *tpri = NULL;
++
++ //tspi = spi_master_get_devdata(master);
++
++ //tpri = (struct tca_spi_pri_handle *)tspi->private_data;
++ //spin_lock_irq(&(tpri->lock));
++ //tpri->stopping = 1;
++ //spin_unlock_irq(&tpri->lock);
++ //list_for_each_entry(msg, &(tpri->queue), queue) {
++ // msg->status = -ESHUTDOWN;
++ // msg->complete(msg->context);
++ //}
++
++ //free_irq(tspi->irq, master);
++ //if (tspi->private_data) { kfree(tspi->private_data); }
++ //tca_spi_clean(tspi);
++
++ spi_unregister_master(master);
++
++ //tca_ckc_setiobus(sa_peri_id_table[pdev->id].bus_id, DISABLE);
++ //tca_ckc_setperi(sa_peri_id_table[pdev->id].clk_id, DISABLE, 40000, PCDIRECTPLL2);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int tcc_spi_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ struct spi_master *master = platform_get_drvdata(pdev);
++ struct tca_spi_handle *tspi = spi_master_get_devdata(master);
++
++ if (tspi) {
++ (void)(state);
++ }
++ return 0;
++}
++
++static int tcc_spi_resume(struct platform_device *pdev)
++{
++ struct spi_master *master = platform_get_drvdata(pdev);
++ struct tca_spi_handle *tspi = spi_master_get_devdata(master);
++ volatile PGPSBPORTCFG gpsb_pcf_regs = (volatile PGPSBPORTCFG)tcc_p2v(HwGPSBPORTCFG_BASE);
++
++ if (tspi) {
++ tspi->clear_fifo_packet(tspi);
++
++ //if (tspi->is_enable_dma(tspi)) {
++ // tspi->dma_stop(tspi);
++ // tspi->dma_start(tspi);
++ //}
++ if (tspi->id == 0) {
++ BITCSET(gpsb_pcf_regs->PCFG0, Hw8-Hw0, 0xB);
++ } else {
++ BITCSET(gpsb_pcf_regs->PCFG0, Hw16-Hw8, 0x400);
++ }
++ }
++
++ return 0;
++}
++#else
++#define tcc_spi_suspend NULL
++#define tcc_spi_resume NULL
++#endif
++
++static struct platform_driver tcc_spidrv = {
++ .remove = tcc_spi_remove,
++ .suspend = tcc_spi_suspend,
++ .resume = tcc_spi_resume,
++ .driver = {
++ .name = "tcc-spi",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init tcc_spi_init(void)
++{
++ return platform_driver_probe(&tcc_spidrv, tcc_spi_probe);
++}
++
++static void __exit tcc_spi_exit(void)
++{
++ platform_driver_unregister(&tcc_spidrv);
++}
++module_init(tcc_spi_init);
++module_exit(tcc_spi_exit);
++
++MODULE_AUTHOR("Telechips Inc. SYS4-3 linux@telechips.com");
++MODULE_DESCRIPTION("Telechips SPI Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/spi/tcc_tsif.c b/drivers/spi/tcc_tsif.c
+new file mode 100644
+index 0000000..a6bc718
+--- /dev/null
++++ b/drivers/spi/tcc_tsif.c
+@@ -0,0 +1,535 @@
++/*
++ * linux/drivers/spi/tcc_tsif.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 1st April, 2009
++ * Description: Driver for Telechips SPI (GPSB) Controllers
++ * SPI slave mode for DXB TSIF (Transport Stream Interface) modules
++ *
++ * Copyright (c) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/dma-mapping.h>
++#include <linux/poll.h>
++#include <linux/spi/spi.h>
++
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/dma.h>
++
++#include <bsp.h>
++#include <mach/tcc_pca953x.h>
++#include <linux/spi/tcc_tsif.h>
++#include "tcc/tca_spi_hwset.h"
++
++
++#define SPI_DMA_SIZE 0x100000
++
++struct tca_spi_pri_handle {
++ wait_queue_head_t wait_q;
++ struct mutex mutex;
++ int open_cnt;
++};
++
++static tca_spi_handle_t tsif_handle;
++static struct tca_spi_pri_handle tsif_pri;
++
++
++static int __init tsif_drv_probe(struct platform_device *dev)
++{
++ platform_set_drvdata(dev, &tsif_handle);
++ return 0;
++}
++
++static int tsif_drv_suspend(struct platform_device *dev, pm_message_t state)
++{
++ return 0;
++}
++
++static int tsif_drv_resume(struct platform_device *dev)
++{
++ tca_spi_handle_t *p_tsif = platform_get_drvdata(dev);
++ volatile PGPSBPORTCFG gpsb_pcf_regs = (volatile PGPSBPORTCFG)tcc_p2v(HwGPSBPORTCFG_BASE);
++
++ if (p_tsif) {
++ if (p_tsif->id == 0) {
++ BITCSET(gpsb_pcf_regs->PCFG0, Hw8-Hw0, 0xB);
++ } else {
++ BITCSET(gpsb_pcf_regs->PCFG0, Hw16-Hw8, 0x400);
++ }
++ if (p_tsif->is_enable_dma(p_tsif)) {
++ p_tsif->dma_stop(p_tsif);
++ p_tsif->dma_start(p_tsif);
++ }
++ }
++ return 0;
++}
++
++static struct platform_driver tsif_platform_driver = {
++ .driver = {
++ .name = "tcc-tsif",
++ .owner = THIS_MODULE,
++ },
++ .suspend = tsif_drv_suspend,
++ .resume = tsif_drv_resume,
++};
++
++
++static int tcc_dxb_power(unsigned long flag)
++{
++ if (flag == 1) {
++ /* GPIO_EXPAND DXB_ON Power-on */
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, DXB_ON, OUTPUT, HIGH, SET_DIRECTION|SET_VALUE);
++ } else if (flag == 0) {
++ /* GPIO_EXPAND DXB_ON Power-off */
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, DXB_ON, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++ } else {
++ return -EINVAL;
++ }
++ printk("tcc_tsif: DXB power %s\n", (tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, 0, OUTPUT, 0, GET_VALUE)&DXB_ON)?"ON":"OFF");
++ return 0;
++}
++
++static void tea_free_dma_linux(struct tea_dma_buf *tdma)
++{
++ if (tdma) {
++ if (tdma->v_addr != 0) {
++ dma_free_writecombine(0, tdma->buf_size, tdma->v_addr, tdma->dma_addr);
++ }
++ memset(tdma, 0, sizeof(struct tea_dma_buf));
++ }
++}
++
++static int tea_alloc_dma_linux(struct tea_dma_buf *tdma, unsigned int size)
++{
++ int ret = -1;
++ if (tdma) {
++ tea_free_dma_linux(tdma);
++ tdma->buf_size = size;
++ tdma->v_addr = dma_alloc_writecombine(0, tdma->buf_size, &tdma->dma_addr, GFP_KERNEL);
++ printk("tcc_tsif: alloc DMA buffer @0x%X(Phy=0x%X), size:%d\n",
++ (unsigned int)tdma->v_addr,
++ (unsigned int)tdma->dma_addr,
++ tdma->buf_size);
++ ret = tdma->v_addr ? 0 : 1;
++ }
++ return ret;
++}
++
++static irqreturn_t tcc_tsif_dma_handler(int irq, void *dev_id)
++{
++ struct tca_spi_handle *tspi = (struct tca_spi_handle *)dev_id;
++ struct tca_spi_pri_handle *tpri = (struct tca_spi_pri_handle *)tspi->private_data;
++ unsigned long dma_done_reg = 0;
++
++ dma_done_reg = tspi->regs->DMAICR;
++ if (dma_done_reg & (Hw28 | Hw29)) {
++ BITSET(tspi->regs->DMAICR, Hw29 | Hw28);
++ if (tpri->open_cnt > 0) {
++ tspi->cur_q_pos = (int)(tspi->regs->DMASTR >> 17);
++ wake_up(&(tpri->wait_q));
++ }
++ }
++ return IRQ_HANDLED;
++}
++
++static int tsif_get_readable_cnt(tca_spi_handle_t *H)
++{
++ if (H) {
++ int dma_pos = H->cur_q_pos;
++ int q_pos = H->q_pos;
++ int readable_cnt = 0;
++
++ if (dma_pos > q_pos) {
++ readable_cnt = dma_pos - q_pos;
++ } else if (dma_pos < q_pos) {
++ readable_cnt = H->dma_total_packet_cnt - q_pos;
++ readable_cnt += dma_pos;
++ }
++ return readable_cnt;
++ }
++ return 0;
++}
++
++static ssize_t tcc_tsif_read(struct file *filp, char *buf, size_t len, loff_t *ppos)
++{
++ int readable_cnt = 0, copy_cnt = 0;
++ int copy_byte = 0;
++
++ readable_cnt = tsif_get_readable_cnt(&tsif_handle);
++ if (readable_cnt > 0) {
++ copy_byte = readable_cnt * TSIF_PACKET_SIZE;
++ if (copy_byte > len) {
++ copy_byte = len;
++ }
++
++ copy_byte -= copy_byte % TSIF_PACKET_SIZE;
++ copy_cnt = copy_byte / TSIF_PACKET_SIZE;
++ copy_cnt -= copy_cnt % tsif_handle.dma_intr_packet_cnt;
++ copy_byte = copy_cnt * TSIF_PACKET_SIZE;
++
++ if (copy_cnt >= tsif_handle.dma_intr_packet_cnt) {
++ int offset = tsif_handle.q_pos * TSIF_PACKET_SIZE;
++ if (copy_cnt > tsif_handle.dma_total_packet_cnt - tsif_handle.q_pos) {
++ int first_copy_byte = (tsif_handle.dma_total_packet_cnt - tsif_handle.q_pos) * TSIF_PACKET_SIZE;
++ int first_copy_cnt = first_copy_byte / TSIF_PACKET_SIZE;
++ int second_copy_byte = (copy_cnt - first_copy_cnt) * TSIF_PACKET_SIZE;
++
++ if (copy_to_user(buf, tsif_handle.rx_dma.v_addr + offset, first_copy_byte)) {
++ return -EFAULT;
++ }
++ if (copy_to_user(buf + first_copy_byte, tsif_handle.rx_dma.v_addr, second_copy_byte)) {
++ return -EFAULT;
++ }
++
++ tsif_handle.q_pos = copy_cnt - first_copy_cnt;
++ } else {
++ if (copy_to_user(buf, tsif_handle.rx_dma.v_addr + offset, copy_byte)) {
++ return -EFAULT;
++ }
++
++ tsif_handle.q_pos += copy_cnt;
++ if (tsif_handle.q_pos >= tsif_handle.dma_total_packet_cnt) {
++ tsif_handle.q_pos = 0;
++ }
++ }
++ return copy_byte;
++ }
++ }
++ return 0;
++}
++
++static ssize_t tcc_tsif_write(struct file *filp, const char *buf, size_t len, loff_t *ppos)
++{
++ return 0;
++}
++
++static unsigned int tcc_tsif_poll(struct file *filp, struct poll_table_struct *wait)
++{
++ if (tsif_get_readable_cnt(&tsif_handle) >= tsif_handle.dma_intr_packet_cnt) {
++ return (POLLIN | POLLRDNORM);
++ }
++
++ poll_wait(filp, &(tsif_pri.wait_q), wait);
++ if (tsif_get_readable_cnt(&tsif_handle) >= tsif_handle.dma_intr_packet_cnt) {
++ return (POLLIN | POLLRDNORM);
++ }
++ return 0;
++}
++
++static int tcc_tsif_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
++{
++ int ret = 0;
++ switch (cmd) {
++ case IOCTL_TSIF_DMA_START:
++ {
++ struct tcc_tsif_param param;
++ if (copy_from_user(&param, (void *)arg, sizeof(struct tcc_tsif_param))) {
++ printk("cannot copy from user tcc_tsif_param in IOCTL_TSIF_DMA_START !!! \n");
++ return -EFAULT;
++ }
++
++ if (((TSIF_PACKET_SIZE * param.ts_total_packet_cnt) > tsif_handle.dma_total_size)
++ || (param.ts_total_packet_cnt <= 0)) {
++ printk("so big ts_total_packet_cnt !!! \n");
++ return -EFAULT;
++ }
++
++ tsif_handle.dma_stop(&tsif_handle);
++
++ tca_spi_setCPHA(tsif_handle.regs, param.mode & SPI_CPHA);
++ tca_spi_setCPOL(tsif_handle.regs, param.mode & SPI_CPOL);
++ tca_spi_setCS_HIGH(tsif_handle.regs, param.mode & SPI_CS_HIGH);
++ tca_spi_setLSB_FIRST(tsif_handle.regs, param.mode & SPI_LSB_FIRST);
++
++ tsif_handle.dma_mode = param.dma_mode;
++ if (tsif_handle.dma_mode == 0) {
++ tsif_handle.set_mpegts_pidmode(&tsif_handle, 0);
++ }
++
++ tsif_handle.dma_total_packet_cnt = param.ts_total_packet_cnt;
++ tsif_handle.dma_intr_packet_cnt = param.ts_intr_packet_cnt;
++
++ tsif_handle.clear_fifo_packet(&tsif_handle);
++ tsif_handle.q_pos = tsif_handle.cur_q_pos = 0;
++
++ tsif_handle.set_packet_cnt(&tsif_handle, MPEG_PACKET_SIZE);
++ printk("interrupt packet count [%u]\n", tsif_handle.dma_intr_packet_cnt);
++ tsif_handle.dma_start(&tsif_handle);
++ }
++ break;
++
++ case IOCTL_TSIF_DMA_STOP:
++ tsif_handle.dma_stop(&tsif_handle);
++ break;
++
++ case IOCTL_TSIF_GET_MAX_DMA_SIZE:
++ {
++ struct tcc_tsif_param param;
++
++ param.ts_total_packet_cnt = tsif_handle.dma_total_size / TSIF_PACKET_SIZE;
++ param.ts_intr_packet_cnt = 1;
++
++ if (copy_to_user((void *)arg, (void *)&param, sizeof(struct tcc_tsif_param))) {
++ printk("cannot copy to user tcc_tsif_param in IOCTL_TSIF_GET_MAX_DMA_SIZE !!! \n");
++ return -EFAULT;
++ }
++ }
++ break;
++
++ case IOCTL_TSIF_SET_PID:
++ {
++ struct tcc_tsif_pid_param param;
++ if (copy_from_user(&param, (void *)arg, sizeof(struct tcc_tsif_pid_param))) {
++ printk("cannot copy from user tcc_tsif_pid_param in IOCTL_TSIF_SET_PID !!! \n");
++ return -EFAULT;
++ }
++
++ if (param.valid_data_cnt <= PID_MATCH_TABLE_MAX_CNT) {
++ int i = 0;
++ for (i = 0; i < PID_MATCH_TABLE_MAX_CNT; i++) {
++ HwGPSB_PIDT(i) = 0;
++ }
++ if (param.valid_data_cnt > 0) {
++ for (i = 0; i < param.valid_data_cnt; i++) {
++ HwGPSB_PIDT(i) = (param.pid_data)[i] & 0x1FFFFFFF;
++ BITSET(HwGPSB_PIDT(i), (TSIF_SPI_NUM == 0) ? HwGPSB_PIDT_CH0 : HwGPSB_PIDT_CH1);
++ }
++ tsif_handle.set_mpegts_pidmode(&tsif_handle, 1);
++ } else {
++ tsif_handle.set_mpegts_pidmode(&tsif_handle, 0);
++ }
++ } else {
++ printk("tsif: PID TABLE is so big !!! (0x%X)\n", cmd);
++ ret = -EINVAL;
++ }
++ }
++ break;
++
++ case IOCTL_TSIF_DXB_POWER:
++ {
++ unsigned long flag;
++ if (copy_from_user((void *)&flag, (const void *)arg, sizeof(flag))) {
++ return -EFAULT;
++ }
++ if (tcc_dxb_power(flag)) {
++ return -EINVAL;
++ }
++ }
++ break;
++
++ default:
++ printk("tsif: unrecognized ioctl (0x%X)\n", cmd);
++ ret = -EINVAL;
++ break;
++ }
++ return ret;
++}
++
++static int tcc_tsif_init(int tsif_num)
++{
++ int ret = 0;
++ volatile struct tca_spi_regs *reg_addr = NULL;
++
++ //printk("%s: spi%d open\n", __func__, tsif_num);
++ reg_addr = (volatile struct tca_spi_regs *)((TSIF_SPI_NUM == 0)
++ ? &(HwGPSBCH0_BASE) : &(HwGPSBCH1_BASE));
++
++ memset(&tsif_handle, 0, sizeof(tca_spi_handle_t));
++ //memset(&tsif_pri, 0, sizeof(struct tca_spi_pri_handle));
++
++ /* GPIO_EXPAND DXB Power-on */
++ //tcc_dxb_power(1);
++
++ // reset
++ tca_ckc_set_iobus_swreset(tsif_num == 0 ? RB_GPSBCONTROLLER0 : RB_GPSBCONTROLLER1, OFF);
++ tca_ckc_set_iobus_swreset(tsif_num == 0 ? RB_GPSBCONTROLLER0 : RB_GPSBCONTROLLER1, ON);
++
++ tca_ckc_setiobus(tsif_num == 0 ? RB_GPSBCONTROLLER0 : RB_GPSBCONTROLLER1, ENABLE);
++
++ if (tca_spi_init(&tsif_handle,
++ reg_addr,
++ (TSIF_SPI_NUM == 0) ? INT_GPSB0_DMA : INT_GPSB1_DMA,
++ tea_alloc_dma_linux,
++ tea_free_dma_linux,
++ SPI_DMA_SIZE,
++ TSIF_SPI_NUM,
++ 1)) {
++ printk("%s: tca_spi_init error !!!!!\n", __func__);
++ ret = -EBUSY;
++ goto err_spi;
++ }
++
++ tsif_handle.private_data = (void *)&tsif_pri;
++ tsif_handle.clear_fifo_packet(&tsif_handle);
++ tsif_handle.dma_stop(&tsif_handle);
++
++ //init_waitqueue_head(&(tsif_pri.wait_q));
++ //mutex_init(&(tsif_pri.mutex));
++
++ tsif_handle.dma_total_packet_cnt = tsif_handle.dma_total_size / TSIF_PACKET_SIZE;
++ tsif_handle.dma_intr_packet_cnt = 1;
++
++ tsif_handle.hw_init(&tsif_handle);
++
++ ret = request_irq(tsif_handle.irq, tcc_tsif_dma_handler, IRQF_SHARED, TSIF_DEV_NAME, &tsif_handle);
++ if (ret) {
++ goto err_irq;
++ }
++
++ tsif_handle.set_packet_cnt(&tsif_handle, MPEG_PACKET_SIZE);
++
++ return 0;
++
++err_irq:
++ free_irq(tsif_handle.irq, &tsif_handle);
++
++err_spi:
++ tca_spi_clean(&tsif_handle);
++ tca_ckc_setiobus(tsif_num == 0 ? RB_GPSBCONTROLLER0 : RB_GPSBCONTROLLER1, DISABLE);
++ /* GPIO_EXPAND DXB Power-off */
++ //tcc_dxb_power(0);
++
++ return ret;
++}
++
++static void tcc_tsif_deinit(int tsif_num)
++{
++ free_irq(tsif_handle.irq, &tsif_handle);
++ tca_spi_clean(&tsif_handle);
++ tca_ckc_setiobus(tsif_num == 0 ? RB_GPSBCONTROLLER0 : RB_GPSBCONTROLLER1, DISABLE);
++ /* GPIO_EXPAND DXB Power-off */
++ //tcc_dxb_power(0);
++}
++
++static int tcc_tsif_open(struct inode *inode, struct file *filp)
++{
++ int ret = 0;
++ mutex_lock(&(tsif_pri.mutex));
++ if (tsif_pri.open_cnt == 0) {
++ tsif_pri.open_cnt++;
++ ret = tcc_tsif_init(TSIF_SPI_NUM);
++ if (ret == 0) {
++ tsif_handle.set_mpegts_pidmode(&tsif_handle, 0);
++ }
++ } else {
++ ret = -EBUSY;
++ }
++ mutex_unlock(&(tsif_pri.mutex));
++ return ret;
++}
++
++static int tcc_tsif_release(struct inode *inode, struct file *filp)
++{
++ mutex_lock(&(tsif_pri.mutex));
++ tsif_handle.dma_stop(&tsif_handle);
++ if (tsif_pri.open_cnt > 0) {
++ tsif_pri.open_cnt--;
++ tcc_tsif_deinit(TSIF_SPI_NUM);
++ }
++ mutex_unlock(&(tsif_pri.mutex));
++ return 0;
++}
++
++struct file_operations tcc_tsif_fops =
++{
++ .owner = THIS_MODULE,
++ .read = tcc_tsif_read,
++ .write = tcc_tsif_write,
++ .ioctl = tcc_tsif_ioctl,
++ .open = tcc_tsif_open,
++ .release = tcc_tsif_release,
++ .poll = tcc_tsif_poll,
++};
++
++static int __init tsif_init(void)
++{
++ int ret;
++ //volatile struct tca_spi_regs *reg_addr = NULL;
++
++ printk("%s: spi%d init\n", TSIF_DEV_NAME, TSIF_SPI_NUM);
++ //reg_addr = (volatile struct tca_spi_regs *)((TSIF_SPI_NUM == 0)
++ // ? &(HwGPSBCH0_BASE) : &(HwGPSBCH1_BASE));
++
++ //memset(&tsif_handle, 0, sizeof(tca_spi_handle_t));
++ memset(&tsif_pri, 0, sizeof(struct tca_spi_pri_handle));
++ ret = register_chrdev(TSIF_DEV_MAJOR, TSIF_DEV_NAME, &tcc_tsif_fops);
++ if (ret < 0) {
++ printk("[%s:%d] register_chrdev error !!!!!\n", __func__, __LINE__);
++ return ret;
++ }
++
++ ///* GPIO_EXPAND DXB Power-on */
++ ////tcc_dxb_power(1);
++
++ // reset
++ //tca_ckc_set_iobus_swreset(TSIF_SPI_NUM == 0 ? RB_GPSBCONTROLLER0 : RB_GPSBCONTROLLER1, OFF);
++ //tca_ckc_set_iobus_swreset(TSIF_SPI_NUM == 0 ? RB_GPSBCONTROLLER0 : RB_GPSBCONTROLLER1, ON);
++
++ //tca_ckc_setiobus(TSIF_SPI_NUM == 0 ? RB_GPSBCONTROLLER0 : RB_GPSBCONTROLLER1, ENABLE);
++
++ //if (tca_spi_init(&tsif_handle,
++ // reg_addr,
++ // (TSIF_SPI_NUM == 0) ? INT_GPSB0_DMA : INT_GPSB1_DMA,
++ // tea_alloc_dma_linux,
++ // tea_free_dma_linux,
++ // SPI_DMA_SIZE,
++ // TSIF_SPI_NUM,
++ // 1)) {
++ // printk("[%s:%d] tca_spi_init error !!!!!\n", __func__, __LINE__);
++ // return -EINVAL;
++ //}
++
++ //tsif_handle.private_data = (void *)&tsif_pri;
++ //tsif_handle.clear_fifo_packet(&tsif_handle);
++ //tsif_handle.dma_stop(&tsif_handle);
++
++ init_waitqueue_head(&(tsif_pri.wait_q));
++ mutex_init(&(tsif_pri.mutex));
++
++ //tsif_handle.dma_total_packet_cnt = tsif_handle.dma_total_size / TSIF_PACKET_SIZE;
++ //tsif_handle.dma_intr_packet_cnt = 1;
++
++ //tsif_handle.hw_init(&tsif_handle);
++ //ret = request_irq(tsif_handle.irq, tcc_tsif_dma_handler, IRQF_SHARED, "tsif", &tsif_handle);
++
++ //tsif_handle.set_packet_cnt(&tsif_handle, MPEG_PACKET_SIZE);
++
++ ret = platform_driver_probe(&tsif_platform_driver, tsif_drv_probe);
++ return ret;
++}
++
++static void __exit tsif_exit(void)
++{
++ //printk("tcc-tsif: exit.\n");
++
++ //free_irq(tsif_handle.irq, &tsif_handle);
++ //tca_spi_clean(&tsif_handle);
++ //tca_ckc_setiobus(TSIF_SPI_NUM == 0 ? RB_GPSBCONTROLLER0 : RB_GPSBCONTROLLER1, DISABLE);
++ ///* GPIO_EXPAND DXB Power-off */
++ ////tcc_dxb_power(0);
++
++ unregister_chrdev(TSIF_DEV_MAJOR, TSIF_DEV_NAME);
++ platform_driver_unregister(&tsif_platform_driver);
++}
++module_init(tsif_init);
++module_exit(tsif_exit);
++
++MODULE_AUTHOR("Telechips Inc. SYS4-3 linux@telechips.com");
++MODULE_DESCRIPTION("Telechips TSIF driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
+index 289d81a..5556064 100644
+--- a/drivers/usb/Kconfig
++++ b/drivers/usb/Kconfig
+@@ -28,6 +28,7 @@ config USB_ARCH_HAS_HCD
+ config USB_ARCH_HAS_OHCI
+ boolean
+ # ARM:
++ default y if ARCH_TCC # Telechips OHCI
+ default y if SA1111
+ default y if ARCH_OMAP
+ default y if ARCH_LH7A404
+@@ -100,6 +101,8 @@ source "drivers/usb/mon/Kconfig"
+
+ source "drivers/usb/wusbcore/Kconfig"
+
++source "drivers/usb/dwc_otg/Kconfig"
++
+ source "drivers/usb/host/Kconfig"
+
+ source "drivers/usb/musb/Kconfig"
+diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
+index 8b7c419..a127e09 100644
+--- a/drivers/usb/Makefile
++++ b/drivers/usb/Makefile
+@@ -37,3 +37,5 @@ obj-$(CONFIG_USB) += misc/
+
+ obj-$(CONFIG_USB_ATM) += atm/
+ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
++
++obj-$(CONFIG_TCC_DWC_OTG) += dwc_otg/ # Telechips USB OTG
+diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
+index b19cbfc..b9bb936 100644
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -37,6 +37,9 @@
+ #endif
+ #endif
+
++#if defined(CONFIG_ARCH_TCC8900) && defined(CONFIG_LCD_7)
++extern int choosedevice;
++#endif
+ struct usb_hub {
+ struct device *intfdev; /* the "interface" device */
+ struct usb_device *hdev;
+@@ -3120,6 +3123,13 @@ static void hub_events(void)
+ clear_port_feature(hdev, i,
+ USB_PORT_FEAT_C_OVER_CURRENT);
+ hub_power_on(hub, true);
++#if defined(CONFIG_ARCH_TCC8900) && defined(CONFIG_LCD_7)
++ printk("choosedevice = 1\n");
++ choosedevice = 1;
++ mdelay(500);
++ printk("choosedevice = 0\n");
++ choosedevice = 0;
++#endif
+ }
+
+ if (portchange & USB_PORT_STAT_C_RESET) {
+diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
+index e8cdce5..55d18d8 100644
+--- a/drivers/usb/core/otg_whitelist.h
++++ b/drivers/usb/core/otg_whitelist.h
+@@ -21,6 +21,7 @@ static struct usb_device_id whitelist_table [] = {
+ /* hubs are optional in OTG, but very handy ... */
+ { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
+ { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
++{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 2), },
+
+ #ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */
+ /* FIXME actually, printers are NOT supposed to use device classes;
+diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
+index c070b34..dc5d636 100644
+--- a/drivers/usb/core/quirks.c
++++ b/drivers/usb/core/quirks.c
+@@ -101,7 +101,7 @@ void usb_detect_quirks(struct usb_device *udev)
+
+ /* By default, disable autosuspend for all non-hubs */
+ #ifdef CONFIG_USB_SUSPEND
+- if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
++ //if (udev->descriptor.bDeviceClass != USB_CLASS_HUB) //AlenOh
+ udev->autosuspend_disabled = 1;
+ #endif
+
+diff --git a/drivers/usb/dwc_otg/Kconfig b/drivers/usb/dwc_otg/Kconfig
+new file mode 100644
+index 0000000..db70c31
+--- /dev/null
++++ b/drivers/usb/dwc_otg/Kconfig
+@@ -0,0 +1,49 @@
++#
++# Synopsys DWC OTG Controller Drivers
++# for Telechips System-on-Chips
++#
++
++comment "Telechips DWC OTG Controller Drivers"
++ depends on ARCH_TCC
++
++config TCC_DWC_OTG
++ tristate "Telechips DWC OTG support"
++ help
++ Telechips USB OTG Controller driver.
++ Synopsys DesignWare Hi-Speed USB On-The-Go (OTG) Core used on the Telechips SoC.
++ select USB_OTG
++
++choice
++ prompt "Telechips DWC OTG mode"
++ depends on TCC_DWC_OTG
++ default TCC_DWC_OTG_DUAL_ROLE
++ help
++ Select Telechips DWC OTG mode,
++ OTG Dual-role or OTG Host only or OTG Device only mode.
++
++config TCC_DWC_OTG_DUAL_ROLE
++ bool "OTG Dual-role mode"
++ select USB_GADGET
++ help
++ Telechips DWC OTG Dual-role mode driver.
++
++config TCC_DWC_OTG_DEVICE_ONLY
++ bool "OTG Device only mode"
++ select USB_GADGET
++ help
++ Telechips DWC OTG Device _only_ mode driver.
++
++config TCC_DWC_OTG_HOST_ONLY
++ bool "OTG Host only mode"
++ help
++ Telechips DWC OTG Host _only_ mode driver.
++
++endchoice
++
++config TCC_DWC_OTG_DEBUG
++ depends on TCC_DWC_OTG
++ bool "Enable debugging messages"
++ default n
++ help
++ This enables Telechips DWC OTG debugging.
++
+diff --git a/drivers/usb/dwc_otg/Makefile b/drivers/usb/dwc_otg/Makefile
+new file mode 100644
+index 0000000..969aa86
+--- /dev/null
++++ b/drivers/usb/dwc_otg/Makefile
+@@ -0,0 +1,37 @@
++#
++# Synopsys DWC OTG Controller Drivers
++# for Telechips System-on-Chips
++#
++
++obj-$(CONFIG_TCC_DWC_OTG) += tcc_dwc_otg.o
++
++tcc_dwc_otg-objs := dwc_otg_driver.o
++tcc_dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o
++tcc_dwc_otg-objs += dwc_otg_pcd.o dwc_otg_pcd_intr.o
++tcc_dwc_otg-objs += dwc_otg_hcd.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o
++tcc_dwc_otg-objs += tcc_usb_phy.o
++
++#dwc_otg-objs += dwc_otg_attr.o
++#EXTRA_CFLAGS += -D_USE_ATTR_
++
++#
++# OTG Mode
++#
++ifeq ($(CONFIG_TCC_DWC_OTG_DUAL_ROLE),y)
++ EXTRA_CFLAGS += -DDWC_DUAL_ROLE
++endif
++ifeq ($(CONFIG_TCC_DWC_OTG_DEVICE_ONLY),y)
++ EXTRA_CFLAGS += -DDWC_DEVICE_ONLY
++endif
++ifeq ($(CONFIG_TCC_DWC_OTG_HOST_ONLY),y)
++ EXTRA_CFLAGS += -DDWC_HOST_ONLY
++endif
++
++#
++# Debugging
++#
++ifeq ($(CONFIG_TCC_DWC_OTG_DEBUG),y)
++ EXTRA_CFLAGS += -DDEBUG -DLINUX
++ EXTRA_CFLAGS += -DDWC_HS_ELECT_TST
++endif
++
+diff --git a/drivers/usb/dwc_otg/dwc_otg_attr.c b/drivers/usb/dwc_otg/dwc_otg_attr.c
+new file mode 100644
+index 0000000..c15b8a0
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_attr.c
+@@ -0,0 +1,792 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_attr.c $
++ * $Revision: #5 $
++ * $Date: 2005/09/15 $
++ * $Change: 537387 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++/** @file
++ *
++ * The diagnostic interface will provide access to the controller for
++ * bringing up the hardware and testing. The Linux driver attributes
++ * feature will be used to provide the Linux Diagnostic
++ * Interface. These attributes are accessed through sysfs.
++ */
++
++/** @page "Linux Module Attributes"
++ *
++ * The Linux module attributes feature is used to provide the Linux
++ * Diagnostic Interface. These attributes are accessed through sysfs.
++ * The diagnostic interface will provide access to the controller for
++ * bringing up the hardware and testing.
++
++
++ The following table shows the attributes.
++ <table>
++ <tr>
++ <td><b> Name</b></td>
++ <td><b> Description</b></td>
++ <td><b> Access</b></td>
++ </tr>
++
++ <tr>
++ <td> mode </td>
++ <td> Returns the current mode: 0 for device mode, 1 for host mode</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hnpcapable </td>
++ <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register.
++ Read returns the current value.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> srpcapable </td>
++ <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register.
++ Read returns the current value.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> hnp </td>
++ <td> Initiates the Host Negotiation Protocol. Read returns the status.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> srp </td>
++ <td> Initiates the Session Request Protocol. Read returns the status.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> buspower </td>
++ <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> bussuspend </td>
++ <td> Suspends the USB bus.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> busconnected </td>
++ <td> Gets the connection status of the bus</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> gotgctl </td>
++ <td> Gets or sets the Core Control Status Register.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> gusbcfg </td>
++ <td> Gets or sets the Core USB Configuration Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> grxfsiz </td>
++ <td> Gets or sets the Receive FIFO Size Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> gnptxfsiz </td>
++ <td> Gets or sets the non-periodic Transmit Size Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> gpvndctl </td>
++ <td> Gets or sets the PHY Vendor Control Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> ggpio </td>
++ <td> Gets the value in the lower 16-bits of the General Purpose IO Register
++ or sets the upper 16 bits.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> guid </td>
++ <td> Gets or sets the value of the User ID Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> gsnpsid </td>
++ <td> Gets the value of the Synopsys ID Regester</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> devspeed </td>
++ <td> Gets or sets the device speed setting in the DCFG register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> enumspeed </td>
++ <td> Gets the device enumeration Speed.</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hptxfsiz </td>
++ <td> Gets the value of the Host Periodic Transmit FIFO</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hprt0 </td>
++ <td> Gets or sets the value in the Host Port Control and Status Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> regoffset </td>
++ <td> Sets the register offset for the next Register Access</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> regvalue </td>
++ <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> remote_wakeup </td>
++ <td> On read, shows the status of Remote Wakeup. On write, initiates a remote
++ wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote
++ Wakeup signalling bit in the Device Control Register is set for 1
++ milli-second.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> regdump </td>
++ <td> Dumps the contents of core registers.</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hcddump </td>
++ <td> Dumps the current HCD state.</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hcd_frrem </td>
++ <td> Shows the average value of the Frame Remaining
++ field in the Host Frame Number/Frame Remaining register when an SOF interrupt
++ occurs. This can be used to determine the average interrupt latency. Also
++ shows the average Frame Remaining value for start_transfer and the "a" and
++ "b" sample points. The "a" and "b" sample points may be used during debugging
++ bto determine how long it takes to execute a section of the HCD code.</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> rd_reg_test </td>
++ <td> Displays the time required to read the GNPTXFSIZ register many times
++ (the output shows the number of times the register is read).
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> wr_reg_test </td>
++ <td> Displays the time required to write the GNPTXFSIZ register many times
++ (the output shows the number of times the register is written).
++ <td> Read</td>
++ </tr>
++
++ </table>
++
++ Example usage:
++ To get the current mode:
++ cat /sys/devices/lm0/mode
++
++ To power down the USB:
++ echo 0 > /sys/devices/lm0/buspower
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/stat.h> /* permission constants */
++
++#include <asm/sizes.h>
++#include <asm/io.h>
++#include <asm/arch/lm.h>
++#include <asm/sizes.h>
++
++#include "dwc_otg_plat.h"
++#include "dwc_otg_attr.h"
++#include "dwc_otg_driver.h"
++#include "dwc_otg_pcd.h"
++#include "dwc_otg_hcd.h"
++
++/*
++ * MACROs for defining sysfs attribute
++ */
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \
++static ssize_t _otg_attr_name_##_show (struct device *_dev, char *buf) \
++{ \
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);\
++ uint32_t val; \
++ val = dwc_read_reg32 (_addr_); \
++ val = (val & (_mask_)) >> _shift_; \
++ return sprintf (buf, "%s = 0x%x\n", _string_, val); \
++}
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \
++static ssize_t _otg_attr_name_##_store (struct device *_dev, const char *buf, size_t count) \
++{ \
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);\
++ uint32_t set = simple_strtoul(buf, NULL, 16); \
++ uint32_t clear = set; \
++ clear = ((~clear) << _shift_) & _mask_; \
++ set = (set << _shift_) & _mask_; \
++ dev_dbg(_dev, "Storing Address=0x%08x Set=0x%08x Clear=0x%08x\n", (uint32_t)_addr_, set, clear); \
++ dwc_modify_reg32(_addr_, clear, set); \
++ return count; \
++}
++
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \
++DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \
++DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \
++DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
++
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \
++DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \
++DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
++
++/*
++ * MACROs for defining sysfs attribute for 32-bit registers
++ */
++#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_addr_,_string_) \
++static ssize_t _otg_attr_name_##_show (struct device *_dev, char *buf) \
++{ \
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);\
++ uint32_t val; \
++ val = dwc_read_reg32 (_addr_); \
++ return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
++}
++#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_addr_,_string_) \
++static ssize_t _otg_attr_name_##_store (struct device *_dev, const char *buf, size_t count) \
++{ \
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);\
++ uint32_t val = simple_strtoul(buf, NULL, 16); \
++ dev_dbg(_dev, "Storing Address=0x%08x Val=0x%08x\n", (uint32_t)_addr_, val); \
++ dwc_write_reg32(_addr_, val); \
++ return count; \
++}
++
++#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \
++DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_addr_,_string_) \
++DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_addr_,_string_) \
++DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
++
++#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \
++DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_addr_,_string_) \
++DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
++
++
++/** @name Functions for Show/Store of Attributes */
++/**@{*/
++
++/**
++ * Show the register offset of the Register Access.
++ */
++static ssize_t regoffset_show( struct device *_dev, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ return snprintf(buf, sizeof("0xFFFFFFFF\n")+1,"0x%08x\n", otg_dev->reg_offset);
++}
++
++/**
++ * Set the register offset for the next Register Access Read/Write
++ */
++static ssize_t regoffset_store( struct device *_dev, const char *buf,
++ size_t count )
++{
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ uint32_t offset = simple_strtoul(buf, NULL, 16);
++ //dev_dbg(_dev, "Offset=0x%08x\n", offset);
++ if (offset < SZ_256K ) {
++ otg_dev->reg_offset = offset;
++ }
++ else {
++ dev_err( _dev, "invalid offset\n" );
++ }
++
++ return count;
++}
++DEVICE_ATTR(regoffset, S_IRUGO|S_IWUSR, regoffset_show, regoffset_store);
++
++
++/**
++ * Show the value of the register at the offset in the reg_offset
++ * attribute.
++ */
++static ssize_t regvalue_show( struct device *_dev, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ uint32_t val;
++ volatile uint32_t *addr;
++
++ if (otg_dev->reg_offset != 0xFFFFFFFF &&
++ 0 != otg_dev->base) {
++ /* Calculate the address */
++ addr = (uint32_t*)(otg_dev->reg_offset +
++ (uint8_t*)otg_dev->base);
++ //dev_dbg(_dev, "@0x%08x\n", (unsigned)addr);
++ val = dwc_read_reg32( addr );
++ return snprintf(buf, sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n")+1,
++ "Reg@0x%06x = 0x%08x\n",
++ otg_dev->reg_offset, val);
++ }
++ else {
++ dev_err(_dev, "Invalid offset (0x%0x)\n",
++ otg_dev->reg_offset);
++ return sprintf(buf, "invalid offset\n" );
++ }
++}
++
++/**
++ * Store the value in the register at the offset in the reg_offset
++ * attribute.
++ *
++ */
++static ssize_t regvalue_store( struct device *_dev, const char *buf,
++ size_t count )
++{
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ volatile uint32_t * addr;
++ uint32_t val = simple_strtoul(buf, NULL, 16);
++ //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val);
++ if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) {
++ /* Calculate the address */
++ addr = (uint32_t*)(otg_dev->reg_offset +
++ (uint8_t*)otg_dev->base);
++ //dev_dbg(_dev, "@0x%08x\n", (unsigned)addr);
++ dwc_write_reg32( addr, val );
++ }
++ else {
++ dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
++ otg_dev->reg_offset);
++ }
++ return count;
++}
++DEVICE_ATTR(regvalue, S_IRUGO|S_IWUSR, regvalue_show, regvalue_store);
++
++/*
++ * Attributes
++ */
++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<20),20,"Mode");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable,&(otg_dev->core_if->core_global_regs->gusbcfg),(1<<9),9,"Mode");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable,&(otg_dev->core_if->core_global_regs->gusbcfg),(1<<8),8,"Mode");
++
++//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
++//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected,otg_dev->core_if->host_if->hprt0,0x01,0,"Bus Connected");
++
++DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl,&(otg_dev->core_if->core_global_regs->gotgctl),"GOTGCTL");
++DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,&(otg_dev->core_if->core_global_regs->gusbcfg),"GUSBCFG");
++DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,&(otg_dev->core_if->core_global_regs->grxfsiz),"GRXFSIZ");
++DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,&(otg_dev->core_if->core_global_regs->gnptxfsiz),"GNPTXFSIZ");
++DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,&(otg_dev->core_if->core_global_regs->gpvndctl),"GPVNDCTL");
++DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,&(otg_dev->core_if->core_global_regs->ggpio),"GGPIO");
++DWC_OTG_DEVICE_ATTR_REG32_RW(guid,&(otg_dev->core_if->core_global_regs->guid),"GUID");
++DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,&(otg_dev->core_if->core_global_regs->gsnpsid),"GSNPSID");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed,&(otg_dev->core_if->dev_if->dev_global_regs->dcfg),0x3,0,"Device Speed");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed,&(otg_dev->core_if->dev_if->dev_global_regs->dsts),0x6,1,"Device Enumeration Speed");
++
++DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,&(otg_dev->core_if->core_global_regs->hptxfsiz),"HPTXFSIZ");
++DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0,otg_dev->core_if->host_if->hprt0,"HPRT0");
++
++
++/**
++ * @todo Add code to initiate the HNP.
++ */
++/**
++ * Show the HNP status bit
++ */
++static ssize_t hnp_show( struct device *_dev, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ gotgctl_data_t val;
++ val.d32 = dwc_read_reg32 (&(otg_dev->core_if->core_global_regs->gotgctl));
++ return sprintf (buf, "HstNegScs = 0x%x\n", val.b.hstnegscs);
++}
++
++/**
++ * Set the HNP Request bit
++ */
++static ssize_t hnp_store( struct device *_dev, const char *buf,
++ size_t count )
++{
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ uint32_t in = simple_strtoul(buf, NULL, 16);
++ uint32_t *addr = (uint32_t *)&(otg_dev->core_if->core_global_regs->gotgctl);
++ gotgctl_data_t mem;
++ mem.d32 = dwc_read_reg32(addr);
++ mem.b.hnpreq = in;
++ dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32);
++ dwc_write_reg32(addr, mem.d32);
++ return count;
++}
++DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);
++
++/**
++ * @todo Add code to initiate the SRP.
++ */
++/**
++ * Show the SRP status bit
++ */
++static ssize_t srp_show( struct device *_dev, char *buf)
++{
++#ifndef DWC_HOST_ONLY
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ gotgctl_data_t val;
++ val.d32 = dwc_read_reg32 (&(otg_dev->core_if->core_global_regs->gotgctl));
++ return sprintf (buf, "SesReqScs = 0x%x\n", val.b.sesreqscs);
++#else
++ return sprintf(buf, "Host Only Mode!\n");
++#endif
++}
++
++
++
++/**
++ * Set the SRP Request bit
++ */
++static ssize_t srp_store( struct device *_dev, const char *buf,
++ size_t count )
++{
++#ifndef DWC_HOST_ONLY
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ dwc_otg_pcd_initiate_srp(otg_dev->pcd);
++#endif
++ return count;
++}
++DEVICE_ATTR(srp, 0644, srp_show, srp_store);
++
++/**
++ * @todo Need to do more for power on/off?
++ */
++/**
++ * Show the Bus Power status
++ */
++static ssize_t buspower_show( struct device *_dev, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ hprt0_data_t val;
++ val.d32 = dwc_read_reg32 (otg_dev->core_if->host_if->hprt0);
++ return sprintf (buf, "Bus Power = 0x%x\n", val.b.prtpwr);
++}
++
++
++/**
++ * Set the Bus Power status
++ */
++static ssize_t buspower_store( struct device *_dev, const char *buf,
++ size_t count )
++{
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ uint32_t on = simple_strtoul(buf, NULL, 16);
++ uint32_t *addr = (uint32_t *)otg_dev->core_if->host_if->hprt0;
++ hprt0_data_t mem;
++
++ mem.d32 = dwc_read_reg32(addr);
++ mem.b.prtpwr = on;
++
++ //dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32);
++ dwc_write_reg32(addr, mem.d32);
++
++ return count;
++}
++DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);
++
++/**
++ * @todo Need to do more for suspend?
++ */
++/**
++ * Show the Bus Suspend status
++ */
++static ssize_t bussuspend_show( struct device *_dev, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ hprt0_data_t val;
++ val.d32 = dwc_read_reg32 (otg_dev->core_if->host_if->hprt0);
++ return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp);
++}
++
++/**
++ * Set the Bus Suspend status
++ */
++static ssize_t bussuspend_store( struct device *_dev, const char *buf,
++ size_t count )
++{
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ uint32_t in = simple_strtoul(buf, NULL, 16);
++ uint32_t *addr = (uint32_t *)otg_dev->core_if->host_if->hprt0;
++ hprt0_data_t mem;
++ mem.d32 = dwc_read_reg32(addr);
++ mem.b.prtsusp = in;
++ dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32);
++ dwc_write_reg32(addr, mem.d32);
++ return count;
++}
++DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);
++
++/**
++ * Show the status of Remote Wakeup.
++ */
++static ssize_t remote_wakeup_show( struct device *_dev, char *buf)
++{
++#ifndef DWC_HOST_ONLY
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ dctl_data_t val;
++ val.d32 =
++ dwc_read_reg32( &otg_dev->core_if->dev_if->dev_global_regs->dctl);
++ return sprintf( buf, "Remote Wakeup = %d Enabled = %d\n",
++ val.b.rmtwkupsig, otg_dev->pcd->remote_wakeup_enable);
++#else
++ return sprintf(buf, "Host Only Mode!\n");
++#endif
++}
++/**
++ * Initiate a remote wakeup of the host. The Device control register
++ * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable
++ * flag is set.
++ *
++ */
++static ssize_t remote_wakeup_store( struct device *_dev, const char *buf,
++ size_t count )
++{
++#ifndef DWC_HOST_ONLY
++ uint32_t val = simple_strtoul(buf, NULL, 16);
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ if (val&1) {
++ dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
++ }
++ else {
++ dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
++ }
++#endif
++ return count;
++}
++DEVICE_ATTR(remote_wakeup, S_IRUGO|S_IWUSR, remote_wakeup_show,
++ remote_wakeup_store);
++
++/**
++ * Dump global registers and either host or device registers (depending on the
++ * current mode of the core).
++ */
++static ssize_t regdump_show( struct device *_dev, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++
++ dwc_otg_dump_global_registers( otg_dev->core_if);
++ if (dwc_otg_is_host_mode(otg_dev->core_if)) {
++ dwc_otg_dump_host_registers( otg_dev->core_if);
++ } else {
++ dwc_otg_dump_dev_registers( otg_dev->core_if);
++ }
++ return sprintf( buf, "Register Dump\n" );
++}
++
++DEVICE_ATTR(regdump, S_IRUGO|S_IWUSR, regdump_show, 0);
++
++/**
++ * Dump the current hcd state.
++ */
++static ssize_t hcddump_show( struct device *_dev, char *buf)
++{
++#ifndef DWC_DEVICE_ONLY
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ dwc_otg_hcd_dump_state(otg_dev->hcd);
++#endif
++ return sprintf( buf, "HCD Dump\n" );
++}
++
++DEVICE_ATTR(hcddump, S_IRUGO|S_IWUSR, hcddump_show, 0);
++
++/**
++ * Dump the average frame remaining at SOF. This can be used to
++ * determine average interrupt latency. Frame remaining is also shown for
++ * start transfer and two additional sample points.
++ */
++static ssize_t hcd_frrem_show( struct device *_dev, char *buf)
++{
++#ifndef DWC_DEVICE_ONLY
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ dwc_otg_hcd_dump_frrem(otg_dev->hcd);
++#endif
++ return sprintf( buf, "HCD Dump Frame Remaining\n" );
++}
++
++DEVICE_ATTR(hcd_frrem, S_IRUGO|S_IWUSR, hcd_frrem_show, 0);
++
++/**
++ * Displays the time required to read the GNPTXFSIZ register many times (the
++ * output shows the number of times the register is read).
++ */
++#define RW_REG_COUNT 10000000
++#define MSEC_PER_JIFFIE 1000/HZ
++static ssize_t rd_reg_test_show( struct device *_dev, char *buf)
++{
++ int i;
++ int time;
++ int start_jiffies;
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++
++ printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
++ HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
++ start_jiffies = jiffies;
++ for (i = 0; i < RW_REG_COUNT; i++) {
++ dwc_read_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz);
++ }
++ time = jiffies - start_jiffies;
++ return sprintf( buf, "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
++ RW_REG_COUNT, time * MSEC_PER_JIFFIE, time );
++}
++
++DEVICE_ATTR(rd_reg_test, S_IRUGO|S_IWUSR, rd_reg_test_show, 0);
++
++/**
++ * Displays the time required to write the GNPTXFSIZ register many times (the
++ * output shows the number of times the register is written).
++ */
++static ssize_t wr_reg_test_show( struct device *_dev, char *buf)
++{
++ int i;
++ int time;
++ int start_jiffies;
++ dwc_otg_device_t *otg_dev = dev_get_otgdata(_dev);
++ uint32_t reg_val;
++
++ printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
++ HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
++ reg_val = dwc_read_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz);
++ start_jiffies = jiffies;
++ for (i = 0; i < RW_REG_COUNT; i++) {
++ dwc_write_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz, reg_val);
++ }
++ time = jiffies - start_jiffies;
++ return sprintf( buf, "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
++ RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
++}
++
++DEVICE_ATTR(wr_reg_test, S_IRUGO|S_IWUSR, wr_reg_test_show, 0);
++/**@}*/
++
++/**
++ * Create the device files
++ */
++void dwc_otg_attr_create (struct lm_device *lmdev)
++{
++ device_create_file(&lmdev->dev, &dev_attr_regoffset);
++ device_create_file(&lmdev->dev, &dev_attr_regvalue);
++ device_create_file(&lmdev->dev, &dev_attr_mode);
++ device_create_file(&lmdev->dev, &dev_attr_hnpcapable);
++ device_create_file(&lmdev->dev, &dev_attr_srpcapable);
++ device_create_file(&lmdev->dev, &dev_attr_hnp);
++ device_create_file(&lmdev->dev, &dev_attr_srp);
++ device_create_file(&lmdev->dev, &dev_attr_buspower);
++ device_create_file(&lmdev->dev, &dev_attr_bussuspend);
++ device_create_file(&lmdev->dev, &dev_attr_busconnected);
++ device_create_file(&lmdev->dev, &dev_attr_gotgctl);
++ device_create_file(&lmdev->dev, &dev_attr_gusbcfg);
++ device_create_file(&lmdev->dev, &dev_attr_grxfsiz);
++ device_create_file(&lmdev->dev, &dev_attr_gnptxfsiz);
++ device_create_file(&lmdev->dev, &dev_attr_gpvndctl);
++ device_create_file(&lmdev->dev, &dev_attr_ggpio);
++ device_create_file(&lmdev->dev, &dev_attr_guid);
++ device_create_file(&lmdev->dev, &dev_attr_gsnpsid);
++ device_create_file(&lmdev->dev, &dev_attr_devspeed);
++ device_create_file(&lmdev->dev, &dev_attr_enumspeed);
++ device_create_file(&lmdev->dev, &dev_attr_hptxfsiz);
++ device_create_file(&lmdev->dev, &dev_attr_hprt0);
++ device_create_file(&lmdev->dev, &dev_attr_remote_wakeup);
++ device_create_file(&lmdev->dev, &dev_attr_regdump);
++ device_create_file(&lmdev->dev, &dev_attr_hcddump);
++ device_create_file(&lmdev->dev, &dev_attr_hcd_frrem);
++ device_create_file(&lmdev->dev, &dev_attr_rd_reg_test);
++ device_create_file(&lmdev->dev, &dev_attr_wr_reg_test);
++}
++
++/**
++ * Remove the device files
++ */
++void dwc_otg_attr_remove (struct lm_device *lmdev)
++{
++ device_remove_file(&lmdev->dev, &dev_attr_regoffset);
++ device_remove_file(&lmdev->dev, &dev_attr_regvalue);
++ device_remove_file(&lmdev->dev, &dev_attr_mode);
++ device_remove_file(&lmdev->dev, &dev_attr_hnpcapable);
++ device_remove_file(&lmdev->dev, &dev_attr_srpcapable);
++ device_remove_file(&lmdev->dev, &dev_attr_hnp);
++ device_remove_file(&lmdev->dev, &dev_attr_srp);
++ device_remove_file(&lmdev->dev, &dev_attr_buspower);
++ device_remove_file(&lmdev->dev, &dev_attr_bussuspend);
++ device_remove_file(&lmdev->dev, &dev_attr_busconnected);
++ device_remove_file(&lmdev->dev, &dev_attr_gotgctl);
++ device_remove_file(&lmdev->dev, &dev_attr_gusbcfg);
++ device_remove_file(&lmdev->dev, &dev_attr_grxfsiz);
++ device_remove_file(&lmdev->dev, &dev_attr_gnptxfsiz);
++ device_remove_file(&lmdev->dev, &dev_attr_gpvndctl);
++ device_remove_file(&lmdev->dev, &dev_attr_ggpio);
++ device_remove_file(&lmdev->dev, &dev_attr_guid);
++ device_remove_file(&lmdev->dev, &dev_attr_gsnpsid);
++ device_remove_file(&lmdev->dev, &dev_attr_devspeed);
++ device_remove_file(&lmdev->dev, &dev_attr_enumspeed);
++ device_remove_file(&lmdev->dev, &dev_attr_hptxfsiz);
++ device_remove_file(&lmdev->dev, &dev_attr_hprt0);
++ device_remove_file(&lmdev->dev, &dev_attr_remote_wakeup);
++ device_remove_file(&lmdev->dev, &dev_attr_regdump);
++ device_remove_file(&lmdev->dev, &dev_attr_hcddump);
++ device_remove_file(&lmdev->dev, &dev_attr_hcd_frrem);
++ device_remove_file(&lmdev->dev, &dev_attr_rd_reg_test);
++ device_remove_file(&lmdev->dev, &dev_attr_wr_reg_test);
++}
+diff --git a/drivers/usb/dwc_otg/dwc_otg_attr.h b/drivers/usb/dwc_otg/dwc_otg_attr.h
+new file mode 100644
+index 0000000..bacb088
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_attr.h
+@@ -0,0 +1,67 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_attr.h $
++ * $Revision: #1 $
++ * $Date: 2005/07/07 $
++ * $Change: 510275 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++#if !defined(__DWC_OTG_ATTR_H__)
++#define __DWC_OTG_ATTR_H__
++
++/** @file
++ * This file contains the interface to the Linux device attributes.
++ */
++extern struct device_attribute dev_attr_regoffset;
++extern struct device_attribute dev_attr_regvalue;
++
++extern struct device_attribute dev_attr_mode;
++extern struct device_attribute dev_attr_hnpcapable;
++extern struct device_attribute dev_attr_srpcapable;
++extern struct device_attribute dev_attr_hnp;
++extern struct device_attribute dev_attr_srp;
++extern struct device_attribute dev_attr_buspower;
++extern struct device_attribute dev_attr_bussuspend;
++extern struct device_attribute dev_attr_busconnected;
++extern struct device_attribute dev_attr_gotgctl;
++extern struct device_attribute dev_attr_gusbcfg;
++extern struct device_attribute dev_attr_grxfsiz;
++extern struct device_attribute dev_attr_gnptxfsiz;
++extern struct device_attribute dev_attr_gpvndctl;
++extern struct device_attribute dev_attr_ggpio;
++extern struct device_attribute dev_attr_guid;
++extern struct device_attribute dev_attr_gsnpsid;
++extern struct device_attribute dev_attr_devspeed;
++extern struct device_attribute dev_attr_enumspeed;
++extern struct device_attribute dev_attr_hptxfsiz;
++extern struct device_attribute dev_attr_hprt0;
++
++void dwc_otg_attr_create (struct lm_device *lmdev);
++void dwc_otg_attr_remove (struct lm_device *lmdev);
++
++#endif
+diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.c b/drivers/usb/dwc_otg/dwc_otg_cil.c
+new file mode 100644
+index 0000000..79c8467
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_cil.c
+@@ -0,0 +1,3384 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_cil.c $
++ * $Revision: #24 $
++ * $Date: 2007/02/07 $
++ * $Change: 791271 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++/** @file
++ *
++ * The Core Interface Layer provides basic services for accessing and
++ * managing the DWC_otg hardware. These services are used by both the
++ * Host Controller Driver and the Peripheral Controller Driver.
++ *
++ * The CIL manages the memory map for the core so that the HCD and PCD
++ * don't have to do this separately. It also handles basic tasks like
++ * reading/writing the registers and data FIFOs in the controller.
++ * Some of the data access functions provide encapsulation of several
++ * operations required to perform a task, such as writing multiple
++ * registers to start a transfer. Finally, the CIL performs basic
++ * services that are not specific to either the host or device modes
++ * of operation. These services include management of the OTG Host
++ * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A
++ * Diagnostic API is also provided to allow testing of the controller
++ * hardware.
++ *
++ * The Core Interface Layer has the following requirements:
++ * - Provides basic controller operations.
++ * - Minimal use of OS services.
++ * - The OS services used will be abstracted by using inline functions
++ * or macros.
++ *
++ */
++#include <asm/unaligned.h>
++#ifdef DEBUG
++#include <linux/jiffies.h>
++#endif
++
++#include "dwc_otg_plat.h"
++#include "dwc_otg_regs.h"
++#include "dwc_otg_cil.h"
++
++#include "tcc_usb_phy.h"
++#include "tcc_usb_def.h"
++
++/* For Signature */
++#define DWC_OTG_CIL_SIGNATURE 'D','W','C','_','O','T','G','_','C','I','L','_'
++#define DWC_OTG_CIL_VERSION 'V','2','.','0','0','3'
++static const unsigned char DWC_OTG_CIL_C_Version[] =
++ {SIGBYAHONG, DWC_OTG_CIL_SIGNATURE, SIGN_OS ,SIGN_CHIPSET, DWC_OTG_CIL_VERSION, 0};
++
++
++const unsigned char* dwc_otg_cil_get_version(void)
++{
++ return DWC_OTG_CIL_C_Version;
++}
++
++#define USE_PERIODIC_EP 1
++
++/**
++ * This function is called to initialize the DWC_otg CSR data
++ * structures. The register addresses in the device and host
++ * structures are initialized from the base address supplied by the
++ * caller. The calling function must make the OS calls to get the
++ * base address of the DWC_otg controller registers. The core_params
++ * argument holds the parameters that specify how the core should be
++ * configured.
++ *
++ * @param[in] _reg_base_addr Base address of DWC_otg core registers
++ * @param[in] _core_params Pointer to the core configuration parameters
++ *
++ */
++dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t *_reg_base_addr,
++ dwc_otg_core_params_t *_core_params)
++{
++ dwc_otg_core_if_t *core_if = 0;
++ dwc_otg_dev_if_t *dev_if = 0;
++ dwc_otg_host_if_t *host_if = 0;
++ uint8_t *reg_base = (uint8_t *)_reg_base_addr;
++ int i = 0;
++
++ DWC_DEBUGPL(DBG_CILV, "%s(%p,%p)\n", __func__, _reg_base_addr, _core_params);
++
++ core_if = kmalloc( sizeof(dwc_otg_core_if_t), GFP_KERNEL);
++
++ if (core_if == 0) \
++ {
++ DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_core_if_t failed\n");
++ return 0;
++ }
++
++ memset(core_if, 0, sizeof(dwc_otg_core_if_t));
++
++ core_if->core_params = _core_params;
++ core_if->core_global_regs = (dwc_otg_core_global_regs_t *)reg_base;
++
++ /*
++ * Allocate the Device Mode structures.
++ */
++ dev_if = kmalloc( sizeof(dwc_otg_dev_if_t), GFP_KERNEL);
++
++ if (dev_if == 0)
++ {
++ DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n");
++ kfree( core_if );
++ return 0;
++ }
++
++ dev_if->dev_global_regs =
++ (dwc_otg_device_global_regs_t *)(reg_base + DWC_DEV_GLOBAL_REG_OFFSET);
++
++ for (i=0; i<MAX_EPS_CHANNELS; i++)
++ {
++ dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *)
++ (reg_base + DWC_DEV_IN_EP_REG_OFFSET +
++ (i * DWC_EP_REG_OFFSET));
++
++ dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *)
++ (reg_base + DWC_DEV_OUT_EP_REG_OFFSET +
++ (i * DWC_EP_REG_OFFSET));
++ DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n",
++ i, &dev_if->in_ep_regs[i]->diepctl);
++ DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n",
++ i, &dev_if->out_ep_regs[i]->doepctl);
++ }
++
++ dev_if->speed = 0; // unknown
++
++ core_if->dev_if = dev_if;
++
++ /*
++ * Allocate the Host Mode structures.
++ */
++ host_if = kmalloc( sizeof(dwc_otg_host_if_t), GFP_KERNEL);
++
++ if (host_if == 0)
++ {
++ DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_host_if_t failed\n");
++ kfree( dev_if );
++ kfree( core_if );
++ return 0;
++ }
++
++ host_if->host_global_regs = (dwc_otg_host_global_regs_t *)
++ (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET);
++
++ host_if->hprt0 = (uint32_t*)(reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);
++
++ for (i=0; i<MAX_EPS_CHANNELS; i++)
++ {
++ host_if->hc_regs[i] = (dwc_otg_hc_regs_t *)
++ (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET +
++ (i * DWC_OTG_CHAN_REGS_OFFSET));
++ DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n",
++ i, &host_if->hc_regs[i]->hcchar);
++ }
++
++ host_if->num_host_channels = MAX_EPS_CHANNELS;
++ core_if->host_if = host_if;
++
++ for (i=0; i<MAX_EPS_CHANNELS; i++)
++ {
++ core_if->data_fifo[i] =
++ (uint32_t *)(reg_base + DWC_OTG_DATA_FIFO_OFFSET +
++ (i * DWC_OTG_DATA_FIFO_SIZE));
++ DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08x\n",
++ i, (unsigned)core_if->data_fifo[i]);
++ }
++
++ core_if->pcgcctl = (uint32_t*)(reg_base + DWC_OTG_PCGCCTL_OFFSET);
++
++ /*
++ * Store the contents of the hardware configuration registers here for
++ * easy access later.
++ */
++ core_if->hwcfg1.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg1);
++ core_if->hwcfg2.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg2);
++ core_if->hwcfg3.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg3);
++ core_if->hwcfg4.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg4);
++
++ DWC_DEBUGPL(DBG_CILV,"hwcfg1=%08x\n",core_if->hwcfg1.d32);
++ DWC_DEBUGPL(DBG_CILV,"hwcfg2=%08x\n",core_if->hwcfg2.d32);
++ DWC_DEBUGPL(DBG_CILV,"hwcfg3=%08x\n",core_if->hwcfg3.d32);
++ DWC_DEBUGPL(DBG_CILV,"hwcfg4=%08x\n",core_if->hwcfg4.d32);
++
++ DWC_DEBUGPL(DBG_CILV,"op_mode=%0x\n",core_if->hwcfg2.b.op_mode);
++ DWC_DEBUGPL(DBG_CILV,"arch=%0x\n",core_if->hwcfg2.b.architecture);
++ DWC_DEBUGPL(DBG_CILV,"num_dev_ep=%d\n",core_if->hwcfg2.b.num_dev_ep);
++ DWC_DEBUGPL(DBG_CILV,"num_host_chan=%d\n",core_if->hwcfg2.b.num_host_chan);
++ DWC_DEBUGPL(DBG_CILV,"nonperio_tx_q_depth=0x%0x\n",core_if->hwcfg2.b.nonperio_tx_q_depth);
++ DWC_DEBUGPL(DBG_CILV,"host_perio_tx_q_depth=0x%0x\n",core_if->hwcfg2.b.host_perio_tx_q_depth);
++ DWC_DEBUGPL(DBG_CILV,"dev_token_q_depth=0x%0x\n",core_if->hwcfg2.b.dev_token_q_depth);
++
++ DWC_DEBUGPL(DBG_CILV,"Total FIFO SZ=4160\n");//, core_if->hwcfg3.b.dfifo_depth);
++ DWC_DEBUGPL(DBG_CILV,"xfer_size_cntr_width=%0x\n", core_if->hwcfg3.b.xfer_size_cntr_width);
++
++ /*
++ * Set the SRP sucess bit for FS-I2c
++ */
++ core_if->srp_success = 0;
++ core_if->srp_timer_started = 0;
++
++ return core_if;
++}
++
++/**
++ * This function frees the structures allocated by dwc_otg_cil_init().
++ *
++ * @param[in] _core_if The core interface pointer returned from
++ * dwc_otg_cil_init().
++ *
++ */
++void dwc_otg_cil_remove( dwc_otg_core_if_t *_core_if )
++{
++ /* Disable all interrupts */
++ dwc_modify_reg32( &_core_if->core_global_regs->gahbcfg, 1, 0);
++ dwc_write_reg32( &_core_if->core_global_regs->gintmsk, 0);
++
++ if ( _core_if->dev_if ) {
++ kfree( _core_if->dev_if );
++ }
++ if ( _core_if->host_if ) {
++ kfree( _core_if->host_if );
++ }
++ kfree( _core_if );
++}
++
++/**
++ * This function enables the controller's Global Interrupt in the AHB Config
++ * register.
++ *
++ * @param[in] _core_if Programming view of DWC_otg controller.
++ */
++extern void dwc_otg_enable_global_interrupts( dwc_otg_core_if_t *_core_if )
++{
++ gahbcfg_data_t ahbcfg = { .d32 = 0};
++ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */
++ dwc_modify_reg32(&_core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32);
++}
++
++/**
++ * This function disables the controller's Global Interrupt in the AHB Config
++ * register.
++ *
++ * @param[in] _core_if Programming view of DWC_otg controller.
++ */
++extern void dwc_otg_disable_global_interrupts( dwc_otg_core_if_t *_core_if )
++{
++ gahbcfg_data_t ahbcfg = { .d32 = 0};
++ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */
++ dwc_modify_reg32(&_core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
++}
++
++/**
++ * This function initializes the commmon interrupts, used in both
++ * device and host modes.
++ *
++ * @param[in] _core_if Programming view of the DWC_otg controller
++ *
++ */
++static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t *_core_if)
++{
++ dwc_otg_core_global_regs_t *global_regs =
++ _core_if->core_global_regs;
++ gintmsk_data_t intr_mask = { .d32 = 0};
++
++ /* Clear any pending OTG Interrupts */
++ dwc_write_reg32( &global_regs->gotgint, 0xFFFFFFFF);
++
++ /* Clear any pending interrupts */
++ dwc_write_reg32( &global_regs->gintsts, 0xFFFFFFFF);
++
++ /*
++ * Enable the interrupts in the GINTMSK.
++ */
++ intr_mask.b.modemismatch = 1;
++ intr_mask.b.otgintr = 1;
++
++ if (!_core_if->dma_enable)
++ {
++ intr_mask.b.rxstsqlvl = 1;
++ }
++
++ intr_mask.b.conidstschng = 1;
++ intr_mask.b.wkupintr = 1;
++ intr_mask.b.disconnect = 1;
++ intr_mask.b.usbsuspend = 1;
++ intr_mask.b.sessreqintr = 1;
++ dwc_write_reg32( &global_regs->gintmsk, intr_mask.d32);
++}
++
++/**
++ * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY
++ * type.
++ */
++static void init_fslspclksel(dwc_otg_core_if_t *_core_if)
++{
++ uint32_t val;
++ hcfg_data_t hcfg;
++
++ if (((_core_if->hwcfg2.b.hs_phy_type == 2) &&
++ (_core_if->hwcfg2.b.fs_phy_type == 1) &&
++ (_core_if->core_params->ulpi_fs_ls)) ||
++ (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS))
++ {
++ /* Full speed PHY */
++ val = DWC_HCFG_48_MHZ;
++ }
++ else
++ {
++ /* High speed PHY running at full speed or high speed */
++ val = DWC_HCFG_30_60_MHZ;
++ }
++
++ DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val);
++ hcfg.d32 = dwc_read_reg32(&_core_if->host_if->host_global_regs->hcfg);
++ hcfg.b.fslspclksel = val;
++ dwc_write_reg32(&_core_if->host_if->host_global_regs->hcfg, hcfg.d32);
++}
++
++/**
++ * Initializes the DevSpd field of the DCFG register depending on the PHY type
++ * and the enumeration speed of the device.
++ */
++static void init_devspd(dwc_otg_core_if_t *_core_if)
++{
++ uint32_t val;
++ dcfg_data_t dcfg;
++
++ if (((_core_if->hwcfg2.b.hs_phy_type == 2) &&
++ (_core_if->hwcfg2.b.fs_phy_type == 1) &&
++ (_core_if->core_params->ulpi_fs_ls)) ||
++ (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS))
++ {
++ /* Full speed PHY */
++ val = 0x3;
++ }
++ else if (_core_if->core_params->speed == DWC_SPEED_PARAM_FULL)
++ {
++ /* High speed PHY running at full speed */
++ val = 0x1;
++ }
++ else
++ {
++ /* High speed PHY running at high speed */
++ val = 0x0;
++ }
++
++ DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val);
++
++ dcfg.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dcfg);
++ dcfg.b.devspd = val;
++ dwc_write_reg32(&_core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
++}
++
++/**
++ * This function calculates the number of IN EPS
++ * using GHWCFG1 and GHWCFG2 registers values
++ *
++ * @param _pcd the pcd structure.
++ */
++static uint32_t calc_num_in_eps(dwc_otg_core_if_t *_core_if)
++{
++ uint32_t num_in_eps = 0;
++ uint32_t num_eps = _core_if->hwcfg2.b.num_dev_ep;
++ uint32_t hwcfg1 = _core_if->hwcfg1.d32 >> 3;
++ uint32_t num_tx_fifos = _core_if->hwcfg4.b.num_in_eps;
++ int i;
++
++
++ for (i = 0; i < num_eps; ++i)
++ {
++ if (!(hwcfg1 & 0x1))
++ num_in_eps++;
++
++ hwcfg1 >>= 2;
++ }
++
++ if (_core_if->hwcfg4.b.ded_fifo_en)
++ {
++ num_in_eps = (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps;
++ }
++
++ return num_in_eps;
++}
++
++
++/**
++ * This function calculates the number of OUT EPS
++ * using GHWCFG1 and GHWCFG2 registers values
++ *
++ * @param _pcd the pcd structure.
++ */
++static uint32_t calc_num_out_eps(dwc_otg_core_if_t *_core_if)
++{
++ uint32_t num_out_eps = 0;
++ uint32_t num_eps = _core_if->hwcfg2.b.num_dev_ep;
++ uint32_t hwcfg1 = _core_if->hwcfg1.d32 >> 2;
++ int i;
++
++ for (i = 0; i < num_eps; ++i)
++ {
++ if (!(hwcfg1 & 0x2))
++ num_out_eps++;
++
++ hwcfg1 >>= 2;
++ }
++ return num_out_eps;
++}
++/**
++ * This function initializes the DWC_otg controller registers and
++ * prepares the core for device mode or host mode operation.
++ *
++ * @param _core_if Programming view of the DWC_otg controller
++ *
++ */
++void dwc_otg_core_init(dwc_otg_core_if_t *_core_if)
++{
++ int i = 0;
++ dwc_otg_core_global_regs_t *global_regs =
++ _core_if->core_global_regs;
++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
++ gahbcfg_data_t ahbcfg = { .d32 = 0};
++ gusbcfg_data_t usbcfg = { .d32 = 0 };
++ gi2cctl_data_t i2cctl = {.d32 = 0};
++
++ //AlenOh for core reset halt test DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p)\n",_core_if);
++
++ /* Common Initialization */
++
++ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
++
++ /* Program the ULPI External VBUS bit if needed */
++ usbcfg.b.ulpi_ext_vbus_drv = 0;
++ //(_core_if->core_params->phy_ulpi_ext_vbus == DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0;
++
++ /* Set external TS Dline pulsing */
++ usbcfg.b.term_sel_dl_pulse = (_core_if->core_params->ts_dline == 1) ? 1 : 0;
++ //AlenOh for core reset halt test DWC_DEBUGPL(DBG_CILV, "term_sel_dl_pulse=%d\n",usbcfg.b.term_sel_dl_pulse);
++ dwc_write_reg32 (&global_regs->gusbcfg, usbcfg.d32);
++
++ /* Reset the Controller */
++ dwc_otg_core_reset( _core_if );
++
++ //AlenOh
++ _core_if->vbus_state = 0;
++ schedule_work(&_core_if->vbus_work);
++
++ /* Initialize parameters from Hardware configuration registers. */
++ dev_if->num_in_eps = calc_num_in_eps(_core_if);
++ dev_if->num_out_eps = calc_num_out_eps(_core_if);
++
++
++ DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",_core_if->hwcfg4.b.num_dev_perio_in_ep);
++
++ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++)
++ {
++ dev_if->perio_tx_fifo_size[i] =
++ dwc_read_reg32( &global_regs->dptxfsiz_dieptxf[i]) >> 16;
++ DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n",
++ i, dev_if->perio_tx_fifo_size[i]);
++ }
++
++ for (i=0; i < _core_if->hwcfg4.b.num_in_eps; i++)
++ {
++ dev_if->tx_fifo_size[i] =
++ dwc_read_reg32( &global_regs->dptxfsiz_dieptxf[i]) >> 16;
++ DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n",
++ i, dev_if->tx_fifo_size[i]);
++ }
++
++ _core_if->total_fifo_size = 4160;//_core_if->hwcfg3.b.dfifo_depth;
++ _core_if->rx_fifo_size =
++ dwc_read_reg32( &global_regs->grxfsiz);
++ _core_if->nperio_tx_fifo_size =
++ dwc_read_reg32( &global_regs->gnptxfsiz) >> 16;
++
++ DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", _core_if->total_fifo_size);
++ DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", _core_if->rx_fifo_size);
++ DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n", _core_if->nperio_tx_fifo_size);
++
++ /* This programming sequence needs to happen in FS mode before any other
++ * programming occurs */
++ if ((_core_if->core_params->speed == DWC_SPEED_PARAM_FULL) &&
++ (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS))
++ {
++ /* If FS mode with FS PHY */
++ DWC_DEBUGPL(DBG_CIL, "FS mode with FS PHY\n");
++
++ /* core_init() is now called on every switch so only call the
++ * following for the first time through. */
++ if (!_core_if->phy_init_done)
++ {
++ _core_if->phy_init_done = 1;
++ DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n");
++ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
++ usbcfg.b.physel = 1;
++ dwc_write_reg32 (&global_regs->gusbcfg, usbcfg.d32);
++
++ /* Reset after a PHY select */
++ dwc_otg_core_reset( _core_if );
++ }
++
++ /* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also
++ * do this on HNP Dev/Host mode switches (done in dev_init and
++ * host_init). */
++ if (dwc_otg_is_host_mode(_core_if))
++ {
++ init_fslspclksel(_core_if);
++ }
++ else
++ {
++ init_devspd(_core_if);
++ }
++
++ if (_core_if->core_params->i2c_enable)
++ {
++ DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n");
++ /* Program GUSBCFG.OtgUtmifsSel to I2C */
++ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
++ usbcfg.b.otgutmifssel = 1;
++ dwc_write_reg32 (&global_regs->gusbcfg, usbcfg.d32);
++
++ /* Program GI2CCTL.I2CEn */
++ i2cctl.d32 = dwc_read_reg32(&global_regs->gi2cctl);
++ i2cctl.b.i2cdevaddr = 1;
++ i2cctl.b.i2cen = 0;
++ dwc_write_reg32 (&global_regs->gi2cctl, i2cctl.d32);
++ i2cctl.b.i2cen = 1;
++ dwc_write_reg32 (&global_regs->gi2cctl, i2cctl.d32);
++ }
++
++ } /* endif speed == DWC_SPEED_PARAM_FULL */
++
++ else
++ {
++ /* High speed PHY. */
++ DWC_DEBUGPL(DBG_CIL, "High speed PHY\n");
++ if (!_core_if->phy_init_done)
++ {
++ _core_if->phy_init_done = 1;
++ /* HS PHY parameters. These parameters are preserved
++ * during soft reset so only program the first time. Do
++ * a soft reset immediately after setting phyif. */
++ if (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_ULPI)
++ {
++ /* ULPI interface */
++ DWC_DEBUGPL(DBG_CIL, "ULPI interface\n");
++ usbcfg.b.ulpi_utmi_sel = 1;
++ usbcfg.b.phyif = 0;
++ usbcfg.b.ddrsel = _core_if->core_params->phy_ulpi_ddr;
++ }
++ else
++ {
++ /* UTMI+ interface */
++ DWC_DEBUGPL(DBG_CIL, "UTMI+ interface\n");
++ usbcfg.b.ulpi_utmi_sel = 0;
++ if (_core_if->core_params->phy_utmi_width == 16) {
++ usbcfg.b.phyif = 1;
++ }
++ else
++ {
++ usbcfg.b.phyif = 0;
++ }
++ }
++
++ dwc_write_reg32( &global_regs->gusbcfg, usbcfg.d32);
++
++ /* Reset after setting the PHY parameters */
++ dwc_otg_core_reset( _core_if );
++ }
++ }
++
++ //if ((_core_if->hwcfg2.b.hs_phy_type == 2) &&
++ // (_core_if->hwcfg2.b.fs_phy_type == 1) &&
++ // (_core_if->core_params->ulpi_fs_ls))
++ //{
++ // DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n");
++ // usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
++ // usbcfg.b.ulpi_fsls = 1;
++ // usbcfg.b.ulpi_clk_sus_m = 1;
++ // dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
++ //}
++ //else
++ {
++ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
++ usbcfg.b.ulpi_fsls = 0;
++ usbcfg.b.ulpi_clk_sus_m = 0;
++ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
++ }
++
++ /* Program the GAHBCFG Register.*/
++ //switch (_core_if->hwcfg2.b.architecture)
++ //{
++ //
++ //case DWC_SLAVE_ONLY_ARCH:
++ // DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n");
++ // ahbcfg.b.nptxfemplvl_txfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
++ // ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
++ //_core_if->dma_enable = 0;
++ // break;
++ //
++ //case DWC_EXT_DMA_ARCH:
++ // DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n");
++ // ahbcfg.b.hburstlen = _core_if->core_params->dma_burst_size;
++ //_core_if->dma_enable = (_core_if->core_params->dma_enable != 0);
++ // break;
++ //
++ //case DWC_INT_DMA_ARCH:
++ DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n");
++// ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR;
++// _core_if->dma_enable = (_core_if->core_params->dma_enable != 0);
++
++ if (_core_if->core_params->dma_enable)
++ {
++ ahbcfg.b.dmaenable = 1;
++ ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR16;//0; //It increases EP IN transaction speed - AlenOh
++ _core_if->dma_enable = 1;
++ DWC_PRINT("Internal DMA Mode...\n");
++ }
++ else
++ {
++ ahbcfg.b.dmaenable = 0;
++ ahbcfg.b.hburstlen = 0;
++
++ //AlenOh
++ ahbcfg.b.nptxfemplvl_txfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_EMPTY;
++ ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_EMPTY;
++
++ _core_if->dma_enable = 0;
++ DWC_PRINT("Slave Mode...\n");
++ }
++ // break;
++ //
++ //}
++
++ ahbcfg.b.dmaenable = _core_if->dma_enable;
++ dwc_write_reg32(&global_regs->gahbcfg, ahbcfg.d32);
++
++ _core_if->en_multiple_tx_fifo = _core_if->hwcfg4.b.ded_fifo_en;
++
++
++ /*
++ * Program the GUSBCFG register.
++ */
++ usbcfg.d32 = dwc_read_reg32( &global_regs->gusbcfg );
++
++ //switch (_core_if->hwcfg2.b.op_mode)
++ //{
++ //case DWC_MODE_HNP_SRP_CAPABLE:
++ usbcfg.b.hnpcap = (_core_if->core_params->otg_cap ==
++ DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
++ usbcfg.b.srpcap = (_core_if->core_params->otg_cap !=
++ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
++ // break;
++ //
++ //case DWC_MODE_SRP_ONLY_CAPABLE:
++ // usbcfg.b.hnpcap = 0;
++ // usbcfg.b.srpcap = (_core_if->core_params->otg_cap !=
++ // DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
++ // break;
++ //
++ //case DWC_MODE_NO_HNP_SRP_CAPABLE:
++ // usbcfg.b.hnpcap = 0;
++ // usbcfg.b.srpcap = 0;
++ // break;
++ //
++ //case DWC_MODE_SRP_CAPABLE_DEVICE:
++ // usbcfg.b.hnpcap = 0;
++ // usbcfg.b.srpcap = (_core_if->core_params->otg_cap !=
++ // DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
++ // break;
++ //
++ //case DWC_MODE_NO_SRP_CAPABLE_DEVICE:
++ // usbcfg.b.hnpcap = 0;
++ // usbcfg.b.srpcap = 0;
++ // break;
++ //
++ //case DWC_MODE_SRP_CAPABLE_HOST:
++ // usbcfg.b.hnpcap = 0;
++ // usbcfg.b.srpcap = (_core_if->core_params->otg_cap !=
++ // DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
++ // break;
++ //
++ //case DWC_MODE_NO_SRP_CAPABLE_HOST:
++ // usbcfg.b.hnpcap = 0;
++ // usbcfg.b.srpcap = 0;
++ // break;
++ //}
++
++ dwc_write_reg32( &global_regs->gusbcfg, usbcfg.d32);
++
++ /* Enable common interrupts */
++ dwc_otg_enable_common_interrupts( _core_if );
++
++ /* Do device or host intialization based on mode during PCD
++ * and HCD initialization */
++ if (dwc_otg_is_host_mode( _core_if ))
++ {
++ DWC_DEBUGPL(DBG_ANY, "Host Mode\n" );
++ _core_if->op_state = A_HOST;
++ }
++ else
++ {
++ DWC_DEBUGPL(DBG_ANY, "Device Mode\n" );
++ _core_if->op_state = B_PERIPHERAL;
++#ifdef DWC_DEVICE_ONLY
++ dwc_otg_core_dev_init( _core_if );
++#endif
++ }
++}
++
++
++/**
++ * This function enables the Device mode interrupts.
++ *
++ * @param _core_if Programming view of DWC_otg controller
++ */
++void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t *_core_if)
++{
++ gintmsk_data_t intr_mask = { .d32 = 0};
++ dwc_otg_core_global_regs_t *global_regs =
++ _core_if->core_global_regs;
++
++ DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
++
++ /* Disable all interrupts. */
++ dwc_write_reg32( &global_regs->gintmsk, 0);
++
++ /* Clear any pending interrupts */
++ dwc_write_reg32( &global_regs->gintsts, 0xFFFFFFFF);
++
++ /* Enable the common interrupts */
++ dwc_otg_enable_common_interrupts( _core_if );
++
++ /* Enable interrupts */
++ intr_mask.b.usbreset = 1;
++ intr_mask.b.enumdone = 1;
++ intr_mask.b.inepintr = 1;
++ intr_mask.b.outepintr = 1;
++ intr_mask.b.erlysuspend = 1;
++
++ //if(_core_if->en_multiple_tx_fifo == 0)
++ //{
++ // intr_mask.b.epmismatch = 1;
++ //}
++
++ /** @todo NGS: Should this be a module parameter? */
++#ifdef USE_PERIODIC_EP
++ intr_mask.b.isooutdrop = 1;
++ intr_mask.b.eopframe = 1;
++ intr_mask.b.incomplisoin = 1;
++ intr_mask.b.incomplisoout = 1;
++#endif
++
++ dwc_modify_reg32( &global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
++
++ DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__,
++ dwc_read_reg32( &global_regs->gintmsk));
++}
++
++/**
++ * This function initializes the DWC_otg controller registers for
++ * device mode.
++ *
++ * @param _core_if Programming view of DWC_otg controller
++ *
++ */
++void dwc_otg_core_dev_init(dwc_otg_core_if_t *_core_if)
++{
++ int i;
++ dwc_otg_core_global_regs_t *global_regs =
++ _core_if->core_global_regs;
++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
++ dwc_otg_core_params_t *params = _core_if->core_params;
++ dcfg_data_t dcfg = {.d32 = 0};
++ grstctl_t resetctl = { .d32=0 };
++ uint32_t rx_fifo_size;
++ fifosize_data_t nptxfifosize;
++ fifosize_data_t txfifosize;
++ dthrctl_data_t dthrctl;
++
++ /* Restart the Phy Clock */
++ dwc_write_reg32(_core_if->pcgcctl, 0);
++
++ /* Device configuration register */
++ init_devspd(_core_if);
++ dcfg.d32 = dwc_read_reg32( &dev_if->dev_global_regs->dcfg);
++ dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80;
++ dwc_write_reg32( &dev_if->dev_global_regs->dcfg, dcfg.d32 );
++
++ /* Configure data FIFO sizes */
++ if ( _core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo )
++ {
++ DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n", _core_if->total_fifo_size);
++ DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n", params->dev_rx_fifo_size);
++ DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n", params->dev_nperio_tx_fifo_size);
++
++ /* Rx FIFO */
++ DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
++ dwc_read_reg32(&global_regs->grxfsiz));
++
++ rx_fifo_size = params->dev_rx_fifo_size;
++ dwc_write_reg32( &global_regs->grxfsiz, rx_fifo_size );
++
++ DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
++ dwc_read_reg32(&global_regs->grxfsiz));
++
++ /** Set Periodic Tx FIFO Mask all bits 0 */
++ _core_if->p_tx_msk = 0;
++
++ /** Set Tx FIFO Mask all bits 0 */
++ _core_if->tx_msk = 0;
++
++ //if(_core_if->en_multiple_tx_fifo == 0)
++ //{
++ // fifosize_data_t ptxfifosize;
++ // /* Non-periodic Tx FIFO */
++ // DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
++ // dwc_read_reg32(&global_regs->gnptxfsiz));
++ //
++ // nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
++ // nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
++ //
++ // dwc_write_reg32( &global_regs->gnptxfsiz, nptxfifosize.d32 );
++ //
++ // DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
++ // dwc_read_reg32(&global_regs->gnptxfsiz));
++ //
++ // /**@todo NGS: Fix Periodic FIFO Sizing! */
++ // /*
++ // * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15.
++ // * Indexes of the FIFO size module parameters in the
++ // * dev_perio_tx_fifo_size array and the FIFO size registers in
++ // * the dptxfsiz array run from 0 to 14.
++ // */
++ // /** @todo Finish debug of this */
++ // ptxfifosize.b.startaddr = nptxfifosize.b.startaddr + nptxfifosize.b.depth;
++ // for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++)
++ // {
++ // ptxfifosize.b.depth = params->dev_perio_tx_fifo_size[i];
++ // DWC_DEBUGPL(DBG_CIL, "initial dptxfsiz_dieptxf[%d]=%08x\n", i,
++ // dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]));
++ // dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[i],
++ // ptxfifosize.d32 );
++ // DWC_DEBUGPL(DBG_CIL, "new dptxfsiz_dieptxf[%d]=%08x\n", i,
++ // dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]));
++ // ptxfifosize.b.startaddr += ptxfifosize.b.depth;
++ // }
++ //}
++ //else
++ {
++ DWC_DEBUGPL(DBG_CIL, "multiple tx fifo\n");
++ /*
++ * Tx FIFOs These FIFOs are numbered from 1 to 15.
++ * Indexes of the FIFO size module parameters in the
++ * dev_tx_fifo_size array and the FIFO size registers in
++ * the dptxfsiz_dieptxf array run from 0 to 14.
++ */
++
++
++ /* Non-periodic Tx FIFO */
++ DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
++ dwc_read_reg32(&global_regs->gnptxfsiz));
++
++ nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
++ nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
++
++ dwc_write_reg32( &global_regs->gnptxfsiz, nptxfifosize.d32 );
++
++ DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
++ dwc_read_reg32(&global_regs->gnptxfsiz));
++
++ txfifosize.b.startaddr = nptxfifosize.b.startaddr + nptxfifosize.b.depth;
++
++ for (i=1; i < 9/*AlenOh _core_if->hwcfg4.b.num_dev_perio_in_ep*/; i++)
++ {
++ txfifosize.b.depth = params->dev_tx_fifo_size[i];
++
++ DWC_DEBUGPL(DBG_CIL, "initial dptxfsiz_dieptxf[%d]=%08x\n", i,
++ dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i-1]));
++
++ dwc_write_reg32( &global_regs->dptxfsiz_dieptxf[i-1],
++ txfifosize.d32 );
++
++ DWC_DEBUGPL(DBG_CIL, "new dptxfsiz_dieptxf[%d]=%08x\n", i,
++ dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i-1]));
++
++ txfifosize.b.startaddr += txfifosize.b.depth;
++ }
++
++ if (txfifosize.b.startaddr>params->data_fifo_size)
++ {
++ printk("usb:serious error:fifo overflow error! (fifo size %d/%d)\n",txfifosize.b.startaddr,params->data_fifo_size);
++ while (1);
++ }
++ }
++ }
++ /* Flush the FIFOs */
++ dwc_otg_flush_tx_fifo(_core_if, 0x10); /* all Tx FIFOs */
++ dwc_otg_flush_rx_fifo(_core_if);
++
++ /* Flush the Learning Queue. */
++ resetctl.b.intknqflsh = 1;
++ dwc_write_reg32( &_core_if->core_global_regs->grstctl, resetctl.d32);
++
++ /* Clear all pending Device Interrupts */
++ dwc_write_reg32( &dev_if->dev_global_regs->diepmsk, 0 );
++ dwc_write_reg32( &dev_if->dev_global_regs->doepmsk, 0 );
++ dwc_write_reg32( &dev_if->dev_global_regs->daint, 0xFFFFFFFF );
++ dwc_write_reg32( &dev_if->dev_global_regs->daintmsk, 0 );
++
++ for (i=0; i <= dev_if->num_in_eps; i++)
++ {
++ depctl_data_t depctl;
++ depctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl);
++ if (depctl.b.epena)
++ {
++ depctl.d32 = 0;
++ depctl.b.epdis = 1;
++ depctl.b.snak = 1;
++ }
++ else
++ {
++ depctl.d32 = 0;
++ }
++
++ dwc_write_reg32( &dev_if->in_ep_regs[i]->diepctl, depctl.d32);
++
++
++ dwc_write_reg32( &dev_if->in_ep_regs[i]->dieptsiz, 0);
++ dwc_write_reg32( &dev_if->in_ep_regs[i]->diepdma, 0);
++ dwc_write_reg32( &dev_if->in_ep_regs[i]->diepint, 0xFF);
++ }
++
++ for (i=0; i <= dev_if->num_out_eps; i++)
++ {
++ depctl_data_t depctl;
++ depctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[i]->doepctl);
++ if (depctl.b.epena)
++ {
++ depctl.d32 = 0;
++ depctl.b.epdis = 1;
++ depctl.b.snak = 1;
++ }
++ else
++ {
++ depctl.d32 = 0;
++ }
++
++ dwc_write_reg32( &dev_if->out_ep_regs[i]->doepctl, depctl.d32);
++
++ dwc_write_reg32( &dev_if->out_ep_regs[i]->doeptsiz, 0);
++ dwc_write_reg32( &dev_if->out_ep_regs[i]->doepdma, 0);
++ dwc_write_reg32( &dev_if->out_ep_regs[i]->doepint, 0xFF);
++ }
++
++ if (_core_if->en_multiple_tx_fifo && _core_if->dma_enable)
++ {
++ dev_if->non_iso_tx_thr_en = _core_if->core_params->thr_ctl & 0x1;
++ dev_if->iso_tx_thr_en = (_core_if->core_params->thr_ctl >> 1) & 0x1;
++ dev_if->rx_thr_en = (_core_if->core_params->thr_ctl >> 2) & 0x1;
++
++ dev_if->rx_thr_length = _core_if->core_params->rx_thr_length;
++ dev_if->tx_thr_length = _core_if->core_params->tx_thr_length;
++
++
++ dthrctl.d32 = 0;
++ dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en;
++ dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en;
++ dthrctl.b.tx_thr_len = dev_if->tx_thr_length;
++ dthrctl.b.rx_thr_en = dev_if->rx_thr_en;
++ dthrctl.b.rx_thr_len = dev_if->rx_thr_length;
++
++ dwc_write_reg32( &dev_if->dev_global_regs->dtknqr3_dthrctl, dthrctl.d32);
++
++ DWC_DEBUGPL(DBG_CIL, "Non ISO Tx Thr - %d\nISO Tx Thr - %d\nRx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n",
++ dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en, dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len, dthrctl.b.rx_thr_len);
++
++ }
++
++ dwc_otg_enable_device_interrupts( _core_if );
++
++ //AlenOh
++ //{
++ // diepmsk_data_t msk = {.d32 = 0};
++ // msk.b.txfifoundrn = 1;
++ // dwc_modify_reg32(&dev_if->dev_global_regs->diepmsk, msk.d32, msk.d32);
++ //}
++
++
++}
++
++/**
++ * This function enables the Host mode interrupts.
++ *
++ * @param _core_if Programming view of DWC_otg controller
++ */
++void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t *_core_if)
++{
++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs;
++ gintmsk_data_t intr_mask = {.d32 = 0};
++
++ DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
++
++ /* Disable all interrupts. */
++ dwc_write_reg32(&global_regs->gintmsk, 0);
++
++ /* Clear any pending interrupts. */
++ dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF);
++
++ /* Enable the common interrupts */
++ dwc_otg_enable_common_interrupts(_core_if);
++
++ /*
++ * Enable host mode interrupts without disturbing common
++ * interrupts.
++ */
++ intr_mask.b.sofintr = 1;
++ intr_mask.b.portintr = 1;
++ intr_mask.b.hcintr = 1;
++
++ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
++}
++
++/**
++ * This function disables the Host Mode interrupts.
++ *
++ * @param _core_if Programming view of DWC_otg controller
++ */
++void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t *_core_if)
++{
++ dwc_otg_core_global_regs_t *global_regs =
++ _core_if->core_global_regs;
++ gintmsk_data_t intr_mask = {.d32 = 0};
++
++ DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__);
++
++ /*
++ * Disable host mode interrupts without disturbing common
++ * interrupts.
++ */
++ intr_mask.b.sofintr = 1;
++ intr_mask.b.portintr = 1;
++ intr_mask.b.hcintr = 1;
++ intr_mask.b.ptxfempty = 1;
++ intr_mask.b.nptxfempty = 1;
++
++ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0);
++}
++
++/**
++ * This function initializes the DWC_otg controller registers for
++ * host mode.
++ *
++ * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
++ * request queues. Host channels are reset to ensure that they are ready for
++ * performing transfers.
++ *
++ * @param _core_if Programming view of DWC_otg controller
++ *
++ */
++void dwc_otg_core_host_init(dwc_otg_core_if_t *_core_if)
++{
++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs;
++ dwc_otg_host_if_t *host_if = _core_if->host_if;
++ dwc_otg_core_params_t *params = _core_if->core_params;
++ hprt0_data_t hprt0 = {.d32 = 0};
++ fifosize_data_t nptxfifosize;
++ fifosize_data_t ptxfifosize;
++ int i;
++ hcchar_data_t hcchar;
++ hcfg_data_t hcfg;
++ dwc_otg_hc_regs_t *hc_regs;
++ int num_channels;
++ gotgctl_data_t gotgctl = {.d32 = 0};
++
++ DWC_DEBUGPL(DBG_CILV,"%s(%p)\n", __func__, _core_if);
++
++ /* Restart the Phy Clock */
++ dwc_write_reg32(_core_if->pcgcctl, 0);
++
++ /* Initialize Host Configuration Register */
++ init_fslspclksel(_core_if);
++ if (_core_if->core_params->speed == DWC_SPEED_PARAM_FULL)
++ {
++ hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg);
++ hcfg.b.fslssupp = 1;
++ dwc_write_reg32(&host_if->host_global_regs->hcfg, hcfg.d32);
++ }
++
++ /* Configure data FIFO sizes */
++ if (_core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo)
++ {
++ DWC_DEBUGPL(DBG_CIL,"Total FIFO Size=%d\n", _core_if->total_fifo_size);
++ DWC_DEBUGPL(DBG_CIL,"Rx FIFO Size=%d\n", params->host_rx_fifo_size);
++ DWC_DEBUGPL(DBG_CIL,"NP Tx FIFO Size=%d\n", params->host_nperio_tx_fifo_size);
++ DWC_DEBUGPL(DBG_CIL,"P Tx FIFO Size=%d\n", params->host_perio_tx_fifo_size);
++
++ /* Rx FIFO */
++ DWC_DEBUGPL(DBG_CIL,"initial grxfsiz=%08x\n", dwc_read_reg32(&global_regs->grxfsiz));
++ dwc_write_reg32(&global_regs->grxfsiz, params->host_rx_fifo_size);
++ DWC_DEBUGPL(DBG_CIL,"new grxfsiz=%08x\n", dwc_read_reg32(&global_regs->grxfsiz));
++
++ /* Non-periodic Tx FIFO */
++ DWC_DEBUGPL(DBG_CIL,"initial gnptxfsiz=%08x\n", dwc_read_reg32(&global_regs->gnptxfsiz));
++ nptxfifosize.b.depth = params->host_nperio_tx_fifo_size;
++ nptxfifosize.b.startaddr = params->host_rx_fifo_size;
++ dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32);
++ DWC_DEBUGPL(DBG_CIL,"new gnptxfsiz=%08x\n", dwc_read_reg32(&global_regs->gnptxfsiz));
++
++ /* Periodic Tx FIFO */
++ DWC_DEBUGPL(DBG_CIL,"initial hptxfsiz=%08x\n", dwc_read_reg32(&global_regs->hptxfsiz));
++ ptxfifosize.b.depth = params->host_perio_tx_fifo_size;
++ ptxfifosize.b.startaddr = nptxfifosize.b.startaddr + nptxfifosize.b.depth;
++ dwc_write_reg32(&global_regs->hptxfsiz, ptxfifosize.d32);
++ DWC_DEBUGPL(DBG_CIL,"new hptxfsiz=%08x\n", dwc_read_reg32(&global_regs->hptxfsiz));
++ }
++
++ /* Clear Host Set HNP Enable in the OTG Control Register */
++ gotgctl.b.hstsethnpen = 1;
++ dwc_modify_reg32( &global_regs->gotgctl, gotgctl.d32, 0);
++
++ /* Make sure the FIFOs are flushed. */
++ dwc_otg_flush_tx_fifo(_core_if, 0x10 /* all Tx FIFOs */);
++ dwc_otg_flush_rx_fifo(_core_if);
++
++ /* Flush out any leftover queued requests. */
++ num_channels = _core_if->core_params->host_channels;
++ for (i = 0; i < num_channels; i++)
++ {
++ hc_regs = _core_if->host_if->hc_regs[i];
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ hcchar.b.chen = 0;
++ hcchar.b.chdis = 1;
++ hcchar.b.epdir = 0;
++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
++ }
++
++ /* Halt all channels to put them into a known state. */
++ for (i = 0; i < num_channels; i++)
++ {
++ int count = 0;
++ hc_regs = _core_if->host_if->hc_regs[i];
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ hcchar.b.chen = 1;
++ hcchar.b.chdis = 1;
++ hcchar.b.epdir = 0;
++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
++ DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d\n", __func__, i);
++ do
++ {
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ if (++count > 1000)
++ {
++ DWC_ERROR("%s: Unable to clear halt on channel %d\n",
++ __func__, i);
++ break;
++ }
++ }
++ while (hcchar.b.chen);
++ }
++
++ /* Turn on the vbus power. */
++ DWC_PRINT("Init: Port Power? op_state=%d\n", _core_if->op_state);
++ if (_core_if->op_state == A_HOST)
++ {
++ hprt0.d32 = dwc_otg_read_hprt0(_core_if);
++ DWC_PRINT("Init: Power Port (%d)\n", hprt0.b.prtpwr);
++ if (hprt0.b.prtpwr == 0 )
++ {
++ _core_if->vbus_state = 1;
++ schedule_work(&_core_if->vbus_work);
++ }
++ }
++
++ dwc_otg_enable_host_interrupts( _core_if );
++}
++
++/**
++ * Prepares a host channel for transferring packets to/from a specific
++ * endpoint. The HCCHARn register is set up with the characteristics specified
++ * in _hc. Host channel interrupts that may need to be serviced while this
++ * transfer is in progress are enabled.
++ *
++ * @param _core_if Programming view of DWC_otg controller
++ * @param _hc Information needed to initialize the host channel
++ */
++void dwc_otg_hc_init(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc)
++{
++ uint32_t intr_enable;
++ hcintmsk_data_t hc_intr_mask;
++ gintmsk_data_t gintmsk = {.d32 = 0};
++ hcchar_data_t hcchar;
++ hcsplt_data_t hcsplt;
++
++ uint8_t hc_num = _hc->hc_num;
++ dwc_otg_host_if_t *host_if = _core_if->host_if;
++ dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num];
++
++ /* Clear old interrupt conditions for this host channel. */
++ hc_intr_mask.d32 = 0xFFFFFFFF;
++ hc_intr_mask.b.reserved = 0;
++ dwc_write_reg32(&hc_regs->hcint, hc_intr_mask.d32);
++
++ /* Enable channel interrupts required for this transfer. */
++ hc_intr_mask.d32 = 0;
++ hc_intr_mask.b.chhltd = 1;
++ if (_core_if->dma_enable)
++ {
++ hc_intr_mask.b.ahberr = 1;
++ if (_hc->error_state && !_hc->do_split &&
++ _hc->ep_type != DWC_OTG_EP_TYPE_ISOC)
++ {
++ hc_intr_mask.b.ack = 1;
++ if (_hc->ep_is_in)
++ {
++ hc_intr_mask.b.datatglerr = 1;
++ if (_hc->ep_type != DWC_OTG_EP_TYPE_INTR)
++ {
++ hc_intr_mask.b.nak = 1;
++ }
++ }
++ }
++ }
++ else
++ {
++ switch (_hc->ep_type)
++ {
++ case DWC_OTG_EP_TYPE_CONTROL:
++ case DWC_OTG_EP_TYPE_BULK:
++ hc_intr_mask.b.xfercompl = 1;
++ hc_intr_mask.b.stall = 1;
++ hc_intr_mask.b.xacterr = 1;
++ hc_intr_mask.b.datatglerr = 1;
++ if (_hc->ep_is_in)
++ {
++ hc_intr_mask.b.bblerr = 1;
++ }
++ else
++ {
++ hc_intr_mask.b.nak = 1;
++ hc_intr_mask.b.nyet = 1;
++ if (_hc->do_ping)
++ {
++ hc_intr_mask.b.ack = 1;
++ }
++ }
++
++ if (_hc->do_split)
++ {
++ hc_intr_mask.b.nak = 1;
++ if (_hc->complete_split)
++ {
++ hc_intr_mask.b.nyet = 1;
++ }
++ else
++ {
++ hc_intr_mask.b.ack = 1;
++ }
++ }
++
++ if (_hc->error_state)
++ {
++ hc_intr_mask.b.ack = 1;
++ }
++ break;
++ case DWC_OTG_EP_TYPE_INTR:
++ hc_intr_mask.b.xfercompl = 1;
++ hc_intr_mask.b.nak = 1;
++ hc_intr_mask.b.stall = 1;
++ hc_intr_mask.b.xacterr = 1;
++ hc_intr_mask.b.datatglerr = 1;
++ hc_intr_mask.b.frmovrun = 1;
++
++ if (_hc->ep_is_in)
++ {
++ hc_intr_mask.b.bblerr = 1;
++ }
++ if (_hc->error_state)
++ {
++ hc_intr_mask.b.ack = 1;
++ }
++ if (_hc->do_split)
++ {
++ if (_hc->complete_split)
++ {
++ hc_intr_mask.b.nyet = 1;
++ }
++ else
++ {
++ hc_intr_mask.b.ack = 1;
++ }
++ }
++ break;
++ case DWC_OTG_EP_TYPE_ISOC:
++ hc_intr_mask.b.xfercompl = 1;
++ hc_intr_mask.b.frmovrun = 1;
++ hc_intr_mask.b.ack = 1;
++
++ if (_hc->ep_is_in)
++ {
++ hc_intr_mask.b.xacterr = 1;
++ hc_intr_mask.b.bblerr = 1;
++ }
++ break;
++ }
++ }
++ dwc_write_reg32(&hc_regs->hcintmsk, hc_intr_mask.d32);
++
++ /* Enable the top level host channel interrupt. */
++ intr_enable = (1 << hc_num);
++ dwc_modify_reg32(&host_if->host_global_regs->haintmsk, 0, intr_enable);
++
++ /* Make sure host channel interrupts are enabled. */
++ gintmsk.b.hcintr = 1;
++ dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
++
++ /*
++ * Program the HCCHARn register with the endpoint characteristics for
++ * the current transfer.
++ */
++ hcchar.d32 = 0;
++ hcchar.b.devaddr = _hc->dev_addr;
++ hcchar.b.epnum = _hc->ep_num;
++ hcchar.b.epdir = _hc->ep_is_in;
++ hcchar.b.lspddev = (_hc->speed == DWC_OTG_EP_SPEED_LOW);
++ hcchar.b.eptype = _hc->ep_type;
++ hcchar.b.mps = _hc->max_packet;
++
++ dwc_write_reg32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32);
++
++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num);
++ DWC_DEBUGPL(DBG_HCDV, " Dev Addr: %d\n", hcchar.b.devaddr);
++ DWC_DEBUGPL(DBG_HCDV, " Ep Num: %d\n", hcchar.b.epnum);
++ DWC_DEBUGPL(DBG_HCDV, " Is In: %d\n", hcchar.b.epdir);
++ DWC_DEBUGPL(DBG_HCDV, " Is Low Speed: %d\n", hcchar.b.lspddev);
++ DWC_DEBUGPL(DBG_HCDV, " Ep Type: %d\n", hcchar.b.eptype);
++ DWC_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n", hcchar.b.mps);
++ DWC_DEBUGPL(DBG_HCDV, " Multi Cnt: %d\n", hcchar.b.multicnt);
++
++ /*
++ * Program the HCSPLIT register for SPLITs
++ */
++ hcsplt.d32 = 0;
++ if (_hc->do_split)
++ {
++ DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n", _hc->hc_num,
++ _hc->complete_split ? "CSPLIT" : "SSPLIT");
++ hcsplt.b.compsplt = _hc->complete_split;
++ hcsplt.b.xactpos = _hc->xact_pos;
++ hcsplt.b.hubaddr = _hc->hub_addr;
++ hcsplt.b.prtaddr = _hc->port_addr;
++ DWC_DEBUGPL(DBG_HCDV, " comp split %d\n", _hc->complete_split);
++ DWC_DEBUGPL(DBG_HCDV, " xact pos %d\n", _hc->xact_pos);
++ DWC_DEBUGPL(DBG_HCDV, " hub addr %d\n", _hc->hub_addr);
++ DWC_DEBUGPL(DBG_HCDV, " port addr %d\n", _hc->port_addr);
++ DWC_DEBUGPL(DBG_HCDV, " is_in %d\n", _hc->ep_is_in);
++ DWC_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n", hcchar.b.mps);
++ DWC_DEBUGPL(DBG_HCDV, " xferlen: %d\n", _hc->xfer_len);
++ }
++ dwc_write_reg32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32);
++
++}
++
++/**
++ * Attempts to halt a host channel. This function should only be called in
++ * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under
++ * normal circumstances in DMA mode, the controller halts the channel when the
++ * transfer is complete or a condition occurs that requires application
++ * intervention.
++ *
++ * In slave mode, checks for a free request queue entry, then sets the Channel
++ * Enable and Channel Disable bits of the Host Channel Characteristics
++ * register of the specified channel to intiate the halt. If there is no free
++ * request queue entry, sets only the Channel Disable bit of the HCCHARn
++ * register to flush requests for this channel. In the latter case, sets a
++ * flag to indicate that the host channel needs to be halted when a request
++ * queue slot is open.
++ *
++ * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
++ * HCCHARn register. The controller ensures there is space in the request
++ * queue before submitting the halt request.
++ *
++ * Some time may elapse before the core flushes any posted requests for this
++ * host channel and halts. The Channel Halted interrupt handler completes the
++ * deactivation of the host channel.
++ *
++ * @param _core_if Controller register interface.
++ * @param _hc Host channel to halt.
++ * @param _halt_status Reason for halting the channel.
++ */
++void dwc_otg_hc_halt(dwc_otg_core_if_t *_core_if,
++ dwc_hc_t *_hc,
++ dwc_otg_halt_status_e _halt_status)
++{
++ gnptxsts_data_t nptxsts;
++ hptxsts_data_t hptxsts;
++ hcchar_data_t hcchar;
++ dwc_otg_hc_regs_t *hc_regs;
++ dwc_otg_core_global_regs_t *global_regs;
++ dwc_otg_host_global_regs_t *host_global_regs;
++
++ hc_regs = _core_if->host_if->hc_regs[_hc->hc_num];
++ global_regs = _core_if->core_global_regs;
++ host_global_regs = _core_if->host_if->host_global_regs;
++
++ WARN_ON(_halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS);
++
++ if (_halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
++ _halt_status == DWC_OTG_HC_XFER_AHB_ERR)
++ {
++ /*
++ * Disable all channel interrupts except Ch Halted. The QTD
++ * and QH state associated with this transfer has been cleared
++ * (in the case of URB_DEQUEUE), so the channel needs to be
++ * shut down carefully to prevent crashes.
++ */
++ hcintmsk_data_t hcintmsk;
++ hcintmsk.d32 = 0;
++ hcintmsk.b.chhltd = 1;
++ dwc_write_reg32(&hc_regs->hcintmsk, hcintmsk.d32);
++
++ /*
++ * Make sure no other interrupts besides halt are currently
++ * pending. Handling another interrupt could cause a crash due
++ * to the QTD and QH state.
++ */
++ dwc_write_reg32(&hc_regs->hcint, ~hcintmsk.d32);
++
++ /*
++ * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
++ * even if the channel was already halted for some other
++ * reason.
++ */
++ _hc->halt_status = _halt_status;
++
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ if (hcchar.b.chen == 0)
++ {
++ /*
++ * The channel is either already halted or it hasn't
++ * started yet. In DMA mode, the transfer may halt if
++ * it finishes normally or a condition occurs that
++ * requires driver intervention. Don't want to halt
++ * the channel again. In either Slave or DMA mode,
++ * it's possible that the transfer has been assigned
++ * to a channel, but not started yet when an URB is
++ * dequeued. Don't want to halt a channel that hasn't
++ * started yet.
++ */
++ return;
++ }
++ }
++
++ if (_hc->halt_pending)
++ {
++ /*
++ * A halt has already been issued for this channel. This might
++ * happen when a transfer is aborted by a higher level in
++ * the stack.
++ */
++#ifdef DEBUG
++ DWC_PRINT("*** %s: Channel %d, _hc->halt_pending already set ***\n",
++ __func__, _hc->hc_num);
++
++ /* dwc_otg_dump_global_registers(_core_if); */
++ /* dwc_otg_dump_host_registers(_core_if); */
++#endif
++ return;
++ }
++
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ hcchar.b.chen = 1;
++ hcchar.b.chdis = 1;
++
++ if (!_core_if->dma_enable)
++ {
++ /* Check for space in the request queue to issue the halt. */
++ if (_hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
++ _hc->ep_type == DWC_OTG_EP_TYPE_BULK)
++ {
++ nptxsts.d32 = dwc_read_reg32(&global_regs->gnptxsts);
++ if (nptxsts.b.nptxqspcavail == 0)
++ {
++ hcchar.b.chen = 0;
++ }
++ }
++ else
++ {
++ hptxsts.d32 = dwc_read_reg32(&host_global_regs->hptxsts);
++ if ((hptxsts.b.ptxqspcavail == 0) || (_core_if->queuing_high_bandwidth))
++ {
++ hcchar.b.chen = 0;
++ }
++ }
++ }
++
++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
++
++ _hc->halt_status = _halt_status;
++
++ if (hcchar.b.chen)
++ {
++ _hc->halt_pending = 1;
++ _hc->halt_on_queue = 0;
++ }
++ else
++ {
++ _hc->halt_on_queue = 1;
++ }
++
++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num);
++ DWC_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n", hcchar.d32);
++ DWC_DEBUGPL(DBG_HCDV, " halt_pending: %d\n", _hc->halt_pending);
++ DWC_DEBUGPL(DBG_HCDV, " halt_on_queue: %d\n", _hc->halt_on_queue);
++ DWC_DEBUGPL(DBG_HCDV, " halt_status: %d\n", _hc->halt_status);
++
++ return;
++}
++
++/**
++ * Clears the transfer state for a host channel. This function is normally
++ * called after a transfer is done and the host channel is being released.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _hc Identifies the host channel to clean up.
++ */
++void dwc_otg_hc_cleanup(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc)
++{
++ dwc_otg_hc_regs_t *hc_regs;
++
++ _hc->xfer_started = 0;
++
++ /*
++ * Clear channel interrupt enables and any unhandled channel interrupt
++ * conditions.
++ */
++ hc_regs = _core_if->host_if->hc_regs[_hc->hc_num];
++ dwc_write_reg32(&hc_regs->hcintmsk, 0);
++ dwc_write_reg32(&hc_regs->hcint, 0xFFFFFFFF);
++
++#ifdef DEBUG
++ del_timer(&_core_if->hc_xfer_timer[_hc->hc_num]);
++ {
++ hcchar_data_t hcchar;
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ if (hcchar.b.chdis)
++ {
++ DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
++ __func__, _hc->hc_num, hcchar.d32);
++ }
++ }
++#endif
++}
++
++/**
++ * Sets the channel property that indicates in which frame a periodic transfer
++ * should occur. This is always set to the _next_ frame. This function has no
++ * effect on non-periodic transfers.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _hc Identifies the host channel to set up and its properties.
++ * @param _hcchar Current value of the HCCHAR register for the specified host
++ * channel.
++ */
++static inline void hc_set_even_odd_frame(dwc_otg_core_if_t *_core_if,
++ dwc_hc_t *_hc,
++ hcchar_data_t *_hcchar)
++{
++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
++ {
++ hfnum_data_t hfnum;
++ hfnum.d32 = dwc_read_reg32(&_core_if->host_if->host_global_regs->hfnum);
++
++ /* 1 if _next_ frame is odd, 0 if it's even */
++ _hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;
++#ifdef DEBUG
++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR && _hc->do_split && !_hc->complete_split)
++ {
++ switch (hfnum.b.frnum & 0x7)
++ {
++ case 7:
++ _core_if->hfnum_7_samples++;
++ _core_if->hfnum_7_frrem_accum += hfnum.b.frrem;
++ break;
++ case 0:
++ _core_if->hfnum_0_samples++;
++ _core_if->hfnum_0_frrem_accum += hfnum.b.frrem;
++ break;
++ default:
++ _core_if->hfnum_other_samples++;
++ _core_if->hfnum_other_frrem_accum += hfnum.b.frrem;
++ break;
++ }
++ }
++#endif
++ }
++}
++
++#ifdef DEBUG
++static void hc_xfer_timeout(unsigned long _ptr)
++{
++ hc_xfer_info_t *xfer_info = (hc_xfer_info_t *)_ptr;
++ int hc_num = xfer_info->hc->hc_num;
++ DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num);
++ DWC_WARN(" start_hcchar_val 0x%08x\n", xfer_info->core_if->start_hcchar_val[hc_num]);
++}
++#endif
++
++/*
++ * This function does the setup for a data transfer for a host channel and
++ * starts the transfer. May be called in either Slave mode or DMA mode. In
++ * Slave mode, the caller must ensure that there is sufficient space in the
++ * request queue and Tx Data FIFO.
++ *
++ * For an OUT transfer in Slave mode, it loads a data packet into the
++ * appropriate FIFO. If necessary, additional data packets will be loaded in
++ * the Host ISR.
++ *
++ * For an IN transfer in Slave mode, a data packet is requested. The data
++ * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
++ * additional data packets are requested in the Host ISR.
++ *
++ * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
++ * register along with a packet count of 1 and the channel is enabled. This
++ * causes a single PING transaction to occur. Other fields in HCTSIZ are
++ * simply set to 0 since no data transfer occurs in this case.
++ *
++ * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
++ * all the information required to perform the subsequent data transfer. In
++ * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
++ * controller performs the entire PING protocol, then starts the data
++ * transfer.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _hc Information needed to initialize the host channel. The xfer_len
++ * value may be reduced to accommodate the max widths of the XferSize and
++ * PktCnt fields in the HCTSIZn register. The multi_count value may be changed
++ * to reflect the final xfer_len value.
++ */
++void dwc_otg_hc_start_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc)
++{
++ hcchar_data_t hcchar;
++ hctsiz_data_t hctsiz;
++ uint16_t num_packets;
++ uint32_t max_hc_xfer_size = _core_if->core_params->max_transfer_size;
++ uint16_t max_hc_pkt_count = _core_if->core_params->max_packet_count;
++ dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num];
++
++ hctsiz.d32 = 0;
++
++ if (_hc->do_ping)
++ {
++ if (!_core_if->dma_enable)
++ {
++ dwc_otg_hc_do_ping(_core_if, _hc);
++ _hc->xfer_started = 1;
++ return;
++ }
++ else
++ {
++ hctsiz.b.dopng = 1;
++ }
++ }
++
++ if (_hc->do_split)
++ {
++ num_packets = 1;
++
++ if (_hc->complete_split && !_hc->ep_is_in)
++ {
++ /* For CSPLIT OUT Transfer, set the size to 0 so the
++ * core doesn't expect any data written to the FIFO */
++ _hc->xfer_len = 0;
++ }
++ else if (_hc->ep_is_in || (_hc->xfer_len > _hc->max_packet))
++ {
++ _hc->xfer_len = _hc->max_packet;
++ }
++ else if (!_hc->ep_is_in && (_hc->xfer_len > 188))
++ {
++ _hc->xfer_len = 188;
++ }
++
++ hctsiz.b.xfersize = _hc->xfer_len;
++ }
++ else
++ {
++ /*
++ * Ensure that the transfer length and packet count will fit
++ * in the widths allocated for them in the HCTSIZn register.
++ */
++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
++ {
++ /*
++ * Make sure the transfer size is no larger than one
++ * (micro)frame's worth of data. (A check was done
++ * when the periodic transfer was accepted to ensure
++ * that a (micro)frame's worth of data can be
++ * programmed into a channel.)
++ */
++ uint32_t max_periodic_len = _hc->multi_count * _hc->max_packet;
++ if (_hc->xfer_len > max_periodic_len)
++ {
++ _hc->xfer_len = max_periodic_len;
++ }
++ else
++ {
++ }
++ }
++ else if (_hc->xfer_len > max_hc_xfer_size)
++ {
++ /* Make sure that xfer_len is a multiple of max packet size. */
++ _hc->xfer_len = max_hc_xfer_size - _hc->max_packet + 1;
++ }
++
++ if (_hc->xfer_len > 0)
++ {
++// if ((_hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) && _hc->xfer_len == _hc->max_packet)
++
++ num_packets = (_hc->xfer_len + _hc->max_packet - 1) / _hc->max_packet;
++
++ if (num_packets > max_hc_pkt_count)
++ {
++ num_packets = max_hc_pkt_count;
++ _hc->xfer_len = num_packets * _hc->max_packet;
++ }
++ }
++ else
++ {
++ /* Need 1 packet for transfer length of 0. */
++ num_packets = 1;
++ }
++
++ if (_hc->ep_is_in)
++ {
++ /* Always program an integral # of max packets for IN transfers. */
++ _hc->xfer_len = num_packets * _hc->max_packet;
++ }
++
++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
++ {
++ /*
++ * Make sure that the multi_count field matches the
++ * actual transfer length.
++ */
++ _hc->multi_count = num_packets;
++ }
++
++ if (_hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
++ {
++ /* Set up the initial PID for the transfer. */
++ if (_hc->speed == DWC_OTG_EP_SPEED_HIGH)
++ {
++ if (_hc->ep_is_in)
++ {
++ if (_hc->multi_count == 1)
++ {
++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
++ }
++ else if (_hc->multi_count == 2)
++ {
++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
++ }
++ else
++ {
++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA2;
++ }
++ }
++ else
++ {
++ if (_hc->multi_count == 1)
++ {
++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
++ }
++ else
++ {
++ _hc->data_pid_start = DWC_OTG_HC_PID_MDATA;
++ }
++ }
++ }
++ else
++ {
++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
++ }
++ }
++
++ hctsiz.b.xfersize = _hc->xfer_len;
++ }
++
++ _hc->start_pkt_count = num_packets;
++ hctsiz.b.pktcnt = num_packets;
++ hctsiz.b.pid = _hc->data_pid_start;
++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
++
++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num);
++ DWC_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize);
++ DWC_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n", hctsiz.b.pktcnt);
++ DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid);
++
++ if (_core_if->dma_enable)
++ {
++ dwc_write_reg32(&hc_regs->hcdma, (uint32_t)_hc->xfer_buff);
++ }
++
++ /* Start the split */
++ if (_hc->do_split)
++ {
++ hcsplt_data_t hcsplt;
++ hcsplt.d32 = dwc_read_reg32 (&hc_regs->hcsplt);
++ hcsplt.b.spltena = 1;
++ dwc_write_reg32(&hc_regs->hcsplt, hcsplt.d32);
++ }
++
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ hcchar.b.multicnt = _hc->multi_count;
++ hc_set_even_odd_frame(_core_if, _hc, &hcchar);
++#ifdef DEBUG
++ _core_if->start_hcchar_val[_hc->hc_num] = hcchar.d32;
++ if (hcchar.b.chdis)
++ {
++ DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
++ __func__, _hc->hc_num, hcchar.d32);
++ }
++#endif
++
++ /* Set host channel enable after all other setup is complete. */
++ hcchar.b.chen = 1;
++ hcchar.b.chdis = 0;
++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
++
++ _hc->xfer_started = 1;
++ _hc->requests++;
++
++ if (!_core_if->dma_enable &&
++ !_hc->ep_is_in && _hc->xfer_len > 0)
++ {
++ /* Load OUT packet into the appropriate Tx FIFO. */
++ dwc_otg_hc_write_packet(_core_if, _hc);
++ }
++
++#ifdef DEBUG
++ /* Start a timer for this transfer. */
++ _core_if->hc_xfer_timer[_hc->hc_num].function = hc_xfer_timeout;
++ _core_if->hc_xfer_info[_hc->hc_num].core_if = _core_if;
++ _core_if->hc_xfer_info[_hc->hc_num].hc = _hc;
++ _core_if->hc_xfer_timer[_hc->hc_num].data = (unsigned long)(&_core_if->hc_xfer_info[_hc->hc_num]);
++ _core_if->hc_xfer_timer[_hc->hc_num].expires = jiffies + (HZ*10);
++ add_timer(&_core_if->hc_xfer_timer[_hc->hc_num]);
++#endif
++}
++
++/**
++ * This function continues a data transfer that was started by previous call
++ * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is
++ * sufficient space in the request queue and Tx Data FIFO. This function
++ * should only be called in Slave mode. In DMA mode, the controller acts
++ * autonomously to complete transfers programmed to a host channel.
++ *
++ * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
++ * if there is any data remaining to be queued. For an IN transfer, another
++ * data packet is always requested. For the SETUP phase of a control transfer,
++ * this function does nothing.
++ *
++ * @return 1 if a new request is queued, 0 if no more requests are required
++ * for this transfer.
++ */
++int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc)
++{
++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num);
++
++ if (_hc->do_split) {
++ /* SPLITs always queue just once per channel */
++ return 0;
++ }
++ else if (_hc->data_pid_start == DWC_OTG_HC_PID_SETUP)
++ {
++ /* SETUPs are queued only once since they can't be NAKed. */
++ return 0;
++ }
++ else if (_hc->ep_is_in)
++ {
++ /*
++ * Always queue another request for other IN transfers. If
++ * back-to-back INs are issued and NAKs are received for both,
++ * the driver may still be processing the first NAK when the
++ * second NAK is received. When the interrupt handler clears
++ * the NAK interrupt for the first NAK, the second NAK will
++ * not be seen. So we can't depend on the NAK interrupt
++ * handler to requeue a NAKed request. Instead, IN requests
++ * are issued each time this function is called. When the
++ * transfer completes, the extra requests for the channel will
++ * be flushed.
++ */
++ hcchar_data_t hcchar;
++ dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num];
++
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ hc_set_even_odd_frame(_core_if, _hc, &hcchar);
++ hcchar.b.chen = 1;
++ hcchar.b.chdis = 0;
++ DWC_DEBUGPL(DBG_HCDV, " IN xfer: hcchar = 0x%08x\n", hcchar.d32);
++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
++ _hc->requests++;
++ return 1;
++ }
++ else
++ {
++ /* OUT transfers. */
++ if (_hc->xfer_count < _hc->xfer_len)
++ {
++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
++ {
++ hcchar_data_t hcchar;
++ dwc_otg_hc_regs_t *hc_regs;
++ hc_regs = _core_if->host_if->hc_regs[_hc->hc_num];
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ hc_set_even_odd_frame(_core_if, _hc, &hcchar);
++ }
++
++ /* Load OUT packet into the appropriate Tx FIFO. */
++ dwc_otg_hc_write_packet(_core_if, _hc);
++ _hc->requests++;
++ return 1;
++ }
++ else
++ {
++ return 0;
++ }
++ }
++}
++
++/**
++ * Starts a PING transfer. This function should only be called in Slave mode.
++ * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled.
++ */
++void dwc_otg_hc_do_ping(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc)
++{
++ hcchar_data_t hcchar;
++ hctsiz_data_t hctsiz;
++ dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num];
++
++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num);
++
++ hctsiz.d32 = 0;
++ hctsiz.b.dopng = 1;
++ hctsiz.b.pktcnt = 1;
++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
++
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ hcchar.b.chen = 1;
++ hcchar.b.chdis = 0;
++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
++}
++
++/*
++ * This function writes a packet into the Tx FIFO associated with the Host
++ * Channel. For a channel associated with a non-periodic EP, the non-periodic
++ * Tx FIFO is written. For a channel associated with a periodic EP, the
++ * periodic Tx FIFO is written. This function should only be called in Slave
++ * mode.
++ *
++ * Upon return the xfer_buff and xfer_count fields in _hc are incremented by
++ * then number of bytes written to the Tx FIFO.
++ */
++void dwc_otg_hc_write_packet(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc)
++{
++ uint32_t i;
++ uint32_t remaining_count;
++ uint32_t byte_count;
++ uint32_t dword_count;
++
++ uint32_t *data_buff = (uint32_t *)(_hc->xfer_buff);
++ uint32_t *data_fifo = _core_if->data_fifo[_hc->hc_num];
++
++ remaining_count = _hc->xfer_len - _hc->xfer_count;
++ if (remaining_count > _hc->max_packet)
++ {
++ byte_count = _hc->max_packet;
++ }
++ else
++ {
++ byte_count = remaining_count;
++ }
++
++ dword_count = (byte_count + 3) / 4;
++
++ if ((((unsigned long)data_buff) & 0x3) == 0)
++ {
++ /* xfer_buff is DWORD aligned. */
++ for (i = 0; i < dword_count; i++, data_buff++)
++ {
++ dwc_write_reg32(data_fifo, *data_buff);
++ }
++ }
++ else
++ {
++ /* xfer_buff is not DWORD aligned. */
++ for (i = 0; i < dword_count; i++, data_buff++)
++ {
++ dwc_write_reg32(data_fifo, get_unaligned(data_buff));
++ }
++ }
++
++ _hc->xfer_count += byte_count;
++ _hc->xfer_buff += byte_count;
++}
++
++/**
++ * Gets the current USB frame number. This is the frame number from the last
++ * SOF packet.
++ */
++uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t *_core_if)
++{
++ dsts_data_t dsts;
++ dsts.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dsts);
++
++ /* read current frame/microfreme number from DSTS register */
++ return dsts.b.soffn;
++}
++
++/**
++ * This function reads a setup packet from the Rx FIFO into the destination
++ * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl)
++ * Interrupt routine when a SETUP packet has been received in Slave mode.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _dest Destination buffer for packet data.
++ */
++void dwc_otg_read_setup_packet(dwc_otg_core_if_t *_core_if, uint32_t *_dest)
++{
++ /* Get the 8 bytes of a setup transaction data */
++
++ /* Pop 2 DWORDS off the receive data FIFO into memory */
++ _dest[0] = dwc_read_reg32(_core_if->data_fifo[0]);
++ _dest[1] = dwc_read_reg32(_core_if->data_fifo[0]);
++}
++
++
++/**
++ * This function enables EP0 OUT to receive SETUP packets and configures EP0
++ * IN for transmitting packets. It is normally called when the
++ * "Enumeration Done" interrupt occurs.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _ep The EP0 data.
++ */
++void dwc_otg_ep0_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
++{
++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
++ dsts_data_t dsts;
++ depctl_data_t diepctl;
++ depctl_data_t doepctl;
++ dctl_data_t dctl ={.d32=0};
++
++ /* Read the Device Status and Endpoint 0 Control registers */
++ dsts.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dsts);
++ diepctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl);
++ doepctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl);
++
++ /* Set the MPS of the IN EP based on the enumeration speed */
++ switch (dsts.b.enumspd)
++ {
++ case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
++ case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
++ case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
++ diepctl.b.mps = DWC_DEP0CTL_MPS_64;
++ break;
++ case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
++ diepctl.b.mps = DWC_DEP0CTL_MPS_8;
++ break;
++ }
++
++ dwc_write_reg32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
++
++ /* Enable OUT EP for receive */
++ doepctl.b.epena = 1;
++ dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
++
++#ifdef VERBOSE
++ DWC_DEBUGPL(DBG_PCDV,"doepctl0=%0x\n",
++ dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl));
++ DWC_DEBUGPL(DBG_PCDV,"diepctl0=%0x\n",
++ dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl));
++#endif
++ dctl.b.cgnpinnak = 1;
++ dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
++ DWC_DEBUGPL(DBG_PCDV,"dctl=%0x\n",
++ dwc_read_reg32(&dev_if->dev_global_regs->dctl));
++}
++
++/**
++ * This function activates an EP. The Device EP control register for
++ * the EP is configured as defined in the ep structure. Note: This
++ * function is not used for EP0.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _ep The EP to activate.
++ */
++void dwc_otg_ep_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
++{
++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
++ depctl_data_t depctl;
++ volatile uint32_t *addr;
++ daint_data_t daintmsk = {.d32=0};
++
++ DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, _ep->num,
++ (_ep->is_in?"IN":"OUT"));
++
++ /* Read DEPCTLn register */
++ if (_ep->is_in == 1)
++ {
++ addr = &dev_if->in_ep_regs[_ep->num]->diepctl;
++ daintmsk.ep.in = 1<<_ep->num;
++ }
++ else
++ {
++ addr = &dev_if->out_ep_regs[_ep->num]->doepctl;
++ daintmsk.ep.out = 1<<_ep->num;
++ }
++
++ /* If the EP is already active don't change the EP Control
++ * register. */
++ depctl.d32 = dwc_read_reg32(addr);
++ if (!depctl.b.usbactep)
++ {
++ depctl.b.mps = _ep->maxpacket;
++ depctl.b.eptype = _ep->type;
++ depctl.b.txfnum = _ep->tx_fifo_num;
++
++ if (_ep->type == DWC_OTG_EP_TYPE_ISOC)
++ {
++ depctl.b.setd0pid = 1; // ???
++ }
++ else
++ {
++ depctl.b.setd0pid = 1;
++ }
++ depctl.b.usbactep = 1;
++
++ dwc_write_reg32(addr, depctl.d32);
++ DWC_DEBUGPL(DBG_PCDV,"DEPCTL=%08x\n", dwc_read_reg32(addr));
++ }
++
++
++ /* Enable the Interrupt for this EP */
++ dwc_modify_reg32(&dev_if->dev_global_regs->daintmsk,
++ 0, daintmsk.d32);
++
++ DWC_DEBUGPL(DBG_PCDV,"DAINTMSK=%0x\n",
++ dwc_read_reg32(&dev_if->dev_global_regs->daintmsk));
++
++ _ep->stall_clear_flag = 0;
++ return;
++}
++
++/**
++ * This function deactivates an EP. This is done by clearing the USB Active
++ * EP bit in the Device EP control register. Note: This function is not used
++ * for EP0. EP0 cannot be deactivated.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _ep The EP to deactivate.
++ */
++void dwc_otg_ep_deactivate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
++{
++ depctl_data_t depctl ={.d32 = 0};
++ volatile uint32_t *addr;
++ daint_data_t daintmsk = {.d32=0};
++
++ /* Read DEPCTLn register */
++ if (_ep->is_in == 1)
++ {
++ addr = &_core_if->dev_if->in_ep_regs[_ep->num]->diepctl;
++ daintmsk.ep.in = 1<<_ep->num;
++ }
++ else
++ {
++ addr = &_core_if->dev_if->out_ep_regs[_ep->num]->doepctl;
++ daintmsk.ep.out = 1<<_ep->num;
++ }
++
++ depctl.b.usbactep = 0;
++ dwc_write_reg32(addr, depctl.d32);
++
++ /* Disable the Interrupt for this EP */
++ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs->daintmsk,
++ daintmsk.d32, 0);
++
++ return;
++}
++
++/**
++ * This function does the setup for a data transfer for an EP and
++ * starts the transfer. For an IN transfer, the packets will be
++ * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
++ * the packets are unloaded from the Rx FIFO in the ISR. the ISR.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _ep The EP to start the transfer on.
++ */
++
++void dwc_otg_ep_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
++{
++ /** @todo Refactor this funciton to check the transfer size
++ * count value does not execed the number bits in the Transfer
++ * count register. */
++ depctl_data_t depctl;
++ deptsiz_data_t deptsiz;
++
++#ifdef CHECK_PACKET_COUNTER_WIDTH
++ const uint32_t MAX_XFER_SIZE =
++ _core_if->core_params->max_transfer_size;
++ const uint32_t MAX_PKT_COUNT =
++ _core_if->core_params->max_packet_count;
++ uint32_t num_packets;
++ uint32_t transfer_len;
++ dwc_otg_dev_out_ep_regs_t *out_regs =
++ _core_if->dev_if->out_ep_regs[_ep->num];
++ dwc_otg_dev_in_ep_regs_t *in_regs =
++ _core_if->dev_if->in_ep_regs[_ep->num];
++ gnptxsts_data_t txstatus;
++
++ int lvl = SET_DEBUG_LEVEL(DBG_PCD);
++
++ DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
++ "xfer_buff=%p start_xfer_buff=%p\n",
++ _ep->num, (_ep->is_in?"IN":"OUT"), _ep->xfer_len,
++ _ep->xfer_count, _ep->xfer_buff, _ep->start_xfer_buff);
++
++ transfer_len = _ep->xfer_len - _ep->xfer_count;
++ if (transfer_len > MAX_XFER_SIZE)
++ {
++ transfer_len = MAX_XFER_SIZE;
++ }
++ if (transfer_len == 0)
++ {
++ num_packets = 1;
++ /* OUT EP to recieve Zero-length packet set transfer
++ * size to maxpacket size. */
++ if (!_ep->is_in)
++ {
++ transfer_len = _ep->maxpacket;
++ }
++ }
++ else
++ {
++ num_packets =
++ (transfer_len + _ep->maxpacket - 1) / _ep->maxpacket;
++ if (num_packets > MAX_PKT_COUNT)
++ {
++ num_packets = MAX_PKT_COUNT;
++ }
++ }
++ DWC_DEBUGPL(DBG_PCD, "transfer_len=%d #pckt=%d\n", transfer_len,
++ num_packets);
++
++ deptsiz.b.xfersize = transfer_len;
++ deptsiz.b.pktcnt = num_packets;
++
++ /* IN endpoint */
++ if (_ep->is_in == 1)
++ {
++ depctl.d32 = dwc_read_reg32(&in_regs->diepctl);
++ }
++ /* OUT endpoint */
++ else
++ {
++ depctl.d32 = dwc_read_reg32(&out_regs->doepctl);
++ }
++
++ /* EP enable, IN data in FIFO */
++ depctl.b.cnak = 1;
++ depctl.b.epena = 1;
++ /* IN endpoint */
++ if (_ep->is_in == 1)
++ {
++ //txstatus.d32 = dwc_read_reg32(&_core_if->core_global_regs->gnptxsts);
++
++ //if (txstatus.b.nptxqspcavail == 0)
++ //{
++ // DWC_DEBUGPL(DBG_ANY, "TX Queue Full (0x%0x)\n",
++ // txstatus.d32);
++ // return;
++ //}
++
++ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
++ dwc_write_reg32(&in_regs->diepctl, depctl.d32);
++
++ /**
++ * Enable the Non-Periodic Tx FIFO empty interrupt, the
++ * data will be written into the fifo by the ISR.
++ */
++ if (_core_if->dma_enable)
++ {
++ dwc_write_reg32 (&in_regs->diepdma, (uint32_t)_ep->xfer_buff);
++ }
++ else
++ {
++ //if(_core_if->en_multiple_tx_fifo == 0)
++ //{
++ // gintmsk_data_t intr_mask = { .d32 = 0};
++ // intr_mask.b.nptxfempty = 1;
++ //
++ // dwc_modify_reg32( &_core_if->core_global_regs->gintsts,
++ // intr_mask.d32, 0);
++ //
++ // dwc_modify_reg32( &_core_if->core_global_regs->gintmsk,
++ // intr_mask.d32, intr_mask.d32);
++ //}
++ //else
++ {
++ /* Enable the Tx FIFO Empty Interrupt for this EP */
++ if (_ep->xfer_len > 0 && _ep->type != DWC_OTG_EP_TYPE_ISOC)
++ {
++ uint32_t fifoemptymsk = 0;
++ fifoemptymsk = (0x1 << _ep->num);
++ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
++ 0, fifoemptymsk);
++ }
++ }
++ }
++ }
++ else
++ {
++ /* OUT endpoint */
++ dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32);
++ dwc_write_reg32(&out_regs->doepctl, depctl.d32);
++ if (_core_if->dma_enable)
++ {
++ dwc_write_reg32 (&out_regs->doepdma,
++ (uint32_t)_ep->xfer_buff);
++ }
++ }
++ DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
++ dwc_read_reg32(&out_regs->doepctl),
++ dwc_read_reg32(&out_regs->doeptsiz));
++ DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
++ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk),
++ dwc_read_reg32(&_core_if->core_global_regs->gintmsk));
++
++ SET_DEBUG_LEVEL(lvl);
++#endif
++
++ DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
++
++ DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
++ "xfer_buff=%p start_xfer_buff=%p\n",
++ _ep->num, (_ep->is_in?"IN":"OUT"), _ep->xfer_len,
++ _ep->xfer_count, _ep->xfer_buff, _ep->start_xfer_buff);
++
++ /* IN endpoint */
++ if (_ep->is_in == 1)
++ {
++ dwc_otg_dev_in_ep_regs_t *in_regs =
++ _core_if->dev_if->in_ep_regs[_ep->num];
++
++ //gnptxsts_data_t gtxstatus;
++
++ if ( !_core_if->dma_enable && (_ep->type != DWC_OTG_EP_TYPE_ISOC)) {
++ //gtxstatus.d32 =
++ // dwc_read_reg32(&_core_if->core_global_regs->gnptxsts);
++
++ //if(_core_if->en_multiple_tx_fifo == 0 && gtxstatus.b.nptxqspcavail == 0)
++ //{
++//#ifdef DEBUG
++ // DWC_PRINT("TX Queue Full (0x%0x)\n", gtxstatus.d32);
++//#endif
++ // return;
++ //}
++ }
++ depctl.d32 = dwc_read_reg32(&(in_regs->diepctl));
++ deptsiz.d32 = dwc_read_reg32(&(in_regs->dieptsiz));
++
++ /* Zero Length Packet? */
++ if (_ep->xfer_len == 0)
++ {
++ deptsiz.b.xfersize = 0;
++ deptsiz.b.pktcnt = 1;
++ }
++ else
++ {
++ /* Program the transfer size and packet count
++ * as follows: xfersize = N * maxpacket +
++ * short_packet pktcnt = N + (short_packet
++ * exist ? 1 : 0)
++ */
++ deptsiz.b.xfersize = _ep->xfer_len;
++ deptsiz.b.pktcnt =
++ (_ep->xfer_len - 1 + _ep->maxpacket) /
++ _ep->maxpacket;
++ }
++ if (_ep->type == DWC_OTG_EP_TYPE_ISOC) {
++ deptsiz.b.mc = deptsiz.b.pktcnt;
++ }
++
++ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
++
++ /* Write the DMA register */
++ if (_core_if->dma_enable)
++ {
++ dwc_write_reg32 (&(in_regs->diepdma),
++ (uint32_t)_ep->dma_addr);
++ }
++ else
++ {
++ if (_ep->type != DWC_OTG_EP_TYPE_ISOC)
++ {
++ /**
++ * Enable the Non-Periodic Tx FIFO empty interrupt,
++ * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
++ * the data will be written into the fifo by the ISR.
++ */
++ //if(_core_if->en_multiple_tx_fifo == 0)
++ //{
++ // intr_mask.b.nptxfempty = 1;
++ // dwc_modify_reg32( &_core_if->core_global_regs->gintsts,
++ // intr_mask.d32, 0);
++ // dwc_modify_reg32( &_core_if->core_global_regs->gintmsk,
++ // intr_mask.d32, intr_mask.d32);
++ //}
++ //else
++ {
++ /* Enable the Tx FIFO Empty Interrupt for this EP */
++ if (_ep->xfer_len > 0)
++ {
++ uint32_t fifoemptymsk = 0;
++ fifoemptymsk = 1 << _ep->num;
++ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
++ 0, fifoemptymsk);
++ }
++ }
++ }
++ }
++ if (_ep->type == DWC_OTG_EP_TYPE_ISOC) {
++ depctl.b.setd1pid = 1;
++ }
++
++ /* EP enable, IN data in FIFO */
++ depctl.b.cnak = 1;
++ depctl.b.epena = 1;
++// dwc_write_reg32(&in_regs->diepctl, depctl.d32);
++ dwc_modify_reg32(&in_regs->diepctl,depctl.d32,depctl.d32);
++ depctl.d32 = dwc_read_reg32 (&_core_if->dev_if->in_ep_regs[0]->diepctl);
++ //depctl.b.nextep = _ep->num;
++ //dwc_write_reg32 (&_core_if->dev_if->in_ep_regs[0]->diepctl, depctl.d32);
++
++ // Added by Sheeja S on 10th Sep 07 for ISO IN Slave mode.
++ if (!_core_if->dma_enable && (_ep->type == DWC_OTG_EP_TYPE_ISOC) ) {
++ while (_ep->xfer_count != _ep->xfer_len) {
++ dwc_otg_ep_write_packet (_core_if, _ep, 0);
++ }
++ }
++#if 1
++ DWC_DEBUGPL(DBG_PCD, "DIEPCTL=%08x DIEPTSIZ=%08x\n",
++ dwc_read_reg32(&in_regs->diepctl),
++ dwc_read_reg32(&in_regs->dieptsiz));
++ DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
++ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk),
++ dwc_read_reg32(&_core_if->core_global_regs->gintmsk));
++#endif
++ }
++ else
++ {
++ /* OUT endpoint */
++ dwc_otg_dev_out_ep_regs_t *out_regs =
++ _core_if->dev_if->out_ep_regs[_ep->num];
++
++ depctl.d32 = dwc_read_reg32(&(out_regs->doepctl));
++ deptsiz.d32 = dwc_read_reg32(&(out_regs->doeptsiz));
++
++ /* Program the transfer size and packet count as follows:
++ *
++ * pktcnt = N
++ * xfersize = N * maxpacket
++ */
++ if (_ep->xfer_len == 0)
++ {
++ /* Zero Length Packet */
++ deptsiz.b.xfersize = _ep->maxpacket;
++ deptsiz.b.pktcnt = 1;
++ }
++ else
++ {
++ deptsiz.b.pktcnt =
++ (_ep->xfer_len + (_ep->maxpacket - 1)) /
++ _ep->maxpacket;
++ deptsiz.b.xfersize = deptsiz.b.pktcnt * _ep->maxpacket;
++ }
++
++ if (_ep->type == DWC_OTG_EP_TYPE_ISOC) {
++ deptsiz.b.mc = deptsiz.b.pktcnt;
++ }
++
++ dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32);
++
++ DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n",
++ _ep->num,
++ deptsiz.b.xfersize, deptsiz.b.pktcnt);
++
++ if (_core_if->dma_enable)
++ {
++ dwc_write_reg32 (&(out_regs->doepdma),
++ (uint32_t)_ep->dma_addr);
++ }
++
++ if (_ep->type == DWC_OTG_EP_TYPE_ISOC)
++ {
++ /** @todo NGS: dpid is read-only. Use setd0pid
++ * or setd1pid. */
++ if (_ep->even_odd_frame)
++ {
++ depctl.b.setd1pid = 1;
++ }
++ else
++ {
++ depctl.b.setd0pid = 1;
++ }
++ depctl.b.setd1pid = 1;
++ }
++
++ /* EP enable */
++ depctl.b.cnak = 1;
++ depctl.b.epena = 1;
++
++ dwc_write_reg32(&out_regs->doepctl, depctl.d32);
++
++ DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
++ dwc_read_reg32(&out_regs->doepctl),
++ dwc_read_reg32(&out_regs->doeptsiz));
++ DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
++ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk),
++ dwc_read_reg32(&_core_if->core_global_regs->gintmsk));
++ }
++}
++
++
++/**
++ * This function does the setup for a data transfer for EP0 and starts
++ * the transfer. For an IN transfer, the packets will be loaded into
++ * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are
++ * unloaded from the Rx FIFO in the ISR.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _ep The EP0 data.
++ */
++void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
++{
++ depctl_data_t depctl;
++ deptsiz0_data_t deptsiz;
++
++ DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
++ "xfer_buff=%p start_xfer_buff=%p total_len=%d\n",
++ _ep->num, (_ep->is_in?"IN":"OUT"), _ep->xfer_len,
++ _ep->xfer_count, _ep->xfer_buff, _ep->start_xfer_buff,
++ _ep->total_len);
++ _ep->total_len = _ep->xfer_len;
++
++ /* IN endpoint */
++ if (_ep->is_in == 1)
++ {
++ dwc_otg_dev_in_ep_regs_t *in_regs =
++ _core_if->dev_if->in_ep_regs[0];
++
++ //gnptxsts_data_t gtxstatus;
++
++ //gtxstatus.d32 =
++ // dwc_read_reg32(&_core_if->core_global_regs->gnptxsts);
++
++ //if( !_core_if->dma_enable && _core_if->en_multiple_tx_fifo == 0 && gtxstatus.b.nptxqspcavail == 0)
++ //{
++//#ifdef DEBUG
++ // deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz);
++ // DWC_DEBUGPL(DBG_PCD,"DIEPCTL0=%0x\n",
++ // dwc_read_reg32(&in_regs->diepctl));
++ // DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n",
++ // deptsiz.d32,
++ // deptsiz.b.xfersize, deptsiz.b.pktcnt);
++ // DWC_PRINT("TX Queue or FIFO Full (0x%0x)\n",
++ // gtxstatus.d32);
++//#endif
++ // return;
++ //}
++
++
++ depctl.d32 = dwc_read_reg32(&in_regs->diepctl);
++ deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz);
++
++ /* Zero Length Packet? */
++ if (_ep->xfer_len == 0)
++ {
++ deptsiz.b.xfersize = 0;
++ deptsiz.b.pktcnt = 1;
++ }
++ else
++ {
++ /* Program the transfer size and packet count
++ * as follows: xfersize = N * maxpacket +
++ * short_packet pktcnt = N + (short_packet
++ * exist ? 1 : 0)
++ */
++ if (_ep->xfer_len > _ep->maxpacket)
++ {
++ _ep->xfer_len = _ep->maxpacket;
++ deptsiz.b.xfersize = _ep->maxpacket;
++ }
++ else
++ {
++ deptsiz.b.xfersize = _ep->xfer_len;
++ }
++ deptsiz.b.pktcnt = 1;
++ }
++ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
++ DWC_DEBUGPL(DBG_PCDV, "IN len=%d xfersize=%d pktcnt=%d [%08x]\n",
++ _ep->xfer_len,
++ deptsiz.b.xfersize, deptsiz.b.pktcnt, deptsiz.d32);
++
++ /* Write the DMA register */
++ if (_core_if->dma_enable)
++ {
++ dwc_write_reg32 (&(in_regs->diepdma),
++ (uint32_t)_ep->dma_addr);
++ }
++
++ /* EP enable, IN data in FIFO */
++ depctl.b.cnak = 1;
++ depctl.b.epena = 1;
++ dwc_write_reg32(&in_regs->diepctl, depctl.d32);
++
++ /**
++ * Enable the Non-Periodic Tx FIFO empty interrupt, the
++ * data will be written into the fifo by the ISR.
++ */
++ if (!_core_if->dma_enable)
++ {
++ //if(_core_if->en_multiple_tx_fifo == 0)
++ //{
++ // gintmsk_data_t intr_mask = { .d32 = 0};
++ // intr_mask.b.nptxfempty = 1;
++ // dwc_modify_reg32( &_core_if->core_global_regs->gintsts,
++ // intr_mask.d32, 0);
++ // dwc_modify_reg32( &_core_if->core_global_regs->gintmsk,
++ // intr_mask.d32, intr_mask.d32);
++ //}
++ //else
++ {
++ /* Enable the Tx FIFO Empty Interrupt for this EP */
++ if (_ep->xfer_len > 0)
++ {
++ uint32_t fifoemptymsk = 0;
++ fifoemptymsk |= 1 << _ep->num;
++ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
++ 0, fifoemptymsk);
++ }
++ }
++ }
++ }
++ else
++ {
++ /* OUT endpoint */
++ dwc_otg_dev_out_ep_regs_t *out_regs =
++ _core_if->dev_if->out_ep_regs[_ep->num];
++
++ depctl.d32 = dwc_read_reg32(&out_regs->doepctl);
++ deptsiz.d32 = dwc_read_reg32(&out_regs->doeptsiz);
++
++ /* Program the transfer size and packet count as follows:
++ * xfersize = N * (maxpacket + 4 - (maxpacket % 4))
++ * pktcnt = N */
++ if (_ep->xfer_len == 0)
++ {
++ /* Zero Length Packet */
++ deptsiz.b.xfersize = _ep->maxpacket;
++ deptsiz.b.pktcnt = 1;
++ }
++ else
++ {
++ deptsiz.b.pktcnt =
++ (_ep->xfer_len + (_ep->maxpacket - 1)) /
++ _ep->maxpacket;
++ deptsiz.b.xfersize = deptsiz.b.pktcnt * _ep->maxpacket;
++ }
++
++ dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32);
++ DWC_DEBUGPL(DBG_PCDV, "len=%d xfersize=%d pktcnt=%d\n",
++ _ep->xfer_len,
++ deptsiz.b.xfersize, deptsiz.b.pktcnt);
++
++ if (_core_if->dma_enable)
++ {
++ dwc_write_reg32 (&(out_regs->doepdma),
++ (uint32_t)_ep->dma_addr);
++ }
++
++ /* EP enable */
++ depctl.b.cnak = 1;
++ depctl.b.epena = 1;
++ dwc_write_reg32 (&(out_regs->doepctl), depctl.d32);
++ }
++}
++
++/**
++ * This function continues control IN transfers started by
++ * dwc_otg_ep0_start_transfer, when the transfer does not fit in a
++ * single packet. NOTE: The DIEPCTL0/DOEPCTL0 registers only have one
++ * bit for the packet count.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _ep The EP0 data.
++ */
++void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
++{
++ depctl_data_t depctl;
++ deptsiz0_data_t deptsiz;
++ //gintmsk_data_t intr_mask = { .d32 = 0};
++ if (_ep->is_in == 1)
++ {
++ dwc_otg_dev_in_ep_regs_t *in_regs =
++ _core_if->dev_if->in_ep_regs[0];
++ //gnptxsts_data_t tx_status = {.d32 = 0};
++
++ //tx_status.d32 = dwc_read_reg32( &_core_if->core_global_regs->gnptxsts );
++ /** @todo Should there be check for room in the Tx
++ * Status Queue. If not remove the code above this comment. */
++
++ depctl.d32 = dwc_read_reg32(&in_regs->diepctl);
++ deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz);
++
++ /* Program the transfer size and packet count
++ * as follows: xfersize = N * maxpacket +
++ * short_packet pktcnt = N + (short_packet
++ * exist ? 1 : 0)
++ */
++ deptsiz.b.xfersize = (_ep->total_len - _ep->xfer_count) > _ep->maxpacket ? _ep->maxpacket :
++ (_ep->total_len - _ep->xfer_count);
++ deptsiz.b.pktcnt = 1;
++ _ep->xfer_len += deptsiz.b.xfersize;
++
++ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
++ DWC_DEBUGPL(DBG_PCDV, "IN len=%d xfersize=%d pktcnt=%d [%08x] xfer_count %d\n",
++ _ep->xfer_len,
++ deptsiz.b.xfersize, deptsiz.b.pktcnt, deptsiz.d32,_ep->xfer_count);
++
++ /* Write the DMA register */
++ if (_core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH)
++ {
++ _ep->dma_addr += _ep->maxpacket;
++ dwc_write_reg32 (&(in_regs->diepdma),
++ (uint32_t)_ep->dma_addr);
++ }
++
++ /* EP enable, IN data in FIFO */
++ depctl.b.cnak = 1;
++ depctl.b.epena = 1;
++ dwc_write_reg32(&in_regs->diepctl, depctl.d32);
++
++ /**
++ * Enable the Non-Periodic Tx FIFO empty interrupt, the
++ * data will be written into the fifo by the ISR.
++ */
++ //if (!_core_if->dma_enable && _core_if->en_multiple_tx_fifo==0)
++ //{
++ // /* First clear it from GINTSTS */
++ // intr_mask.b.nptxfempty = 1;
++ // dwc_write_reg32( &_core_if->core_global_regs->gintsts,
++ // intr_mask.d32 );
++ //
++ // dwc_modify_reg32( &_core_if->core_global_regs->gintmsk,
++ // intr_mask.d32, intr_mask.d32);
++ //}
++ }
++}
++
++#ifdef DEBUG
++void dump_msg(const u8 *buf, unsigned int length)
++{
++ unsigned int start, num, i;
++ char line[52], *p;
++
++ if (length >= 512)
++ return;
++ start = 0;
++ while (length > 0)
++ {
++ num = min(length, 16u);
++ p = line;
++ for (i = 0; i < num; ++i)
++ {
++ if (i == 8)
++ *p++ = ' ';
++ sprintf(p, " %02x", buf[i]);
++ p += 3;
++ }
++ *p = 0;
++ DWC_PRINT( "%6x: %s\n", start, line);
++ buf += num;
++ start += num;
++ length -= num;
++ }
++}
++#else
++static inline void dump_msg(const u8 *buf, unsigned int length)
++{
++}
++#endif
++
++/**
++ * This function writes a packet into the Tx FIFO associated with the
++ * EP. For non-periodic EPs the non-periodic Tx FIFO is written. For
++ * periodic EPs the periodic Tx FIFO associated with the EP is written
++ * with all packets for the next micro-frame.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _ep The EP to write packet for.
++ * @param _dma Indicates if DMA is being used.
++ */
++void dwc_otg_ep_write_packet(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep, int _dma)
++{
++ /**
++ * The buffer is padded to DWORD on a per packet basis in
++ * slave/dma mode if the MPS is not DWORD aligned. The last
++ * packet, if short, is also padded to a multiple of DWORD.
++ *
++ * ep->xfer_buff always starts DWORD aligned in memory and is a
++ * multiple of DWORD in length
++ *
++ * ep->xfer_len can be any number of bytes
++ *
++ * ep->xfer_count is a multiple of ep->maxpacket until the last
++ * packet
++ *
++ * FIFO access is DWORD */
++
++ uint32_t i;
++ uint32_t byte_count;
++ uint32_t dword_count;
++ uint32_t *fifo;
++ uint32_t *data_buff = (uint32_t *)_ep->xfer_buff;
++
++ //DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, _core_if, _ep);
++ if (_ep->xfer_count >= _ep->xfer_len) {
++ DWC_WARN("%s() No data for EP%d!!!\n", __func__, _ep->num);
++ return;
++ }
++
++ /* Find the byte length of the packet either short packet or MPS */
++ if ((_ep->xfer_len - _ep->xfer_count) < _ep->maxpacket)
++ {
++ byte_count = _ep->xfer_len - _ep->xfer_count;
++ }
++ else
++ {
++ byte_count = _ep->maxpacket;
++ }
++
++ /* Find the DWORD length, padded by extra bytes as neccessary if MPS
++ * is not a multiple of DWORD */
++ dword_count = (byte_count + 3) / 4;
++
++#ifdef VERBOSE
++ dump_msg(_ep->xfer_buff, byte_count);
++#endif
++
++ /**@todo NGS Where are the Periodic Tx FIFO addresses
++ * intialized? What should this be? */
++
++ fifo = _core_if->data_fifo[_ep->num];
++
++
++ DWC_DEBUGPL((DBG_PCDV|DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n",
++ fifo, data_buff, *data_buff, byte_count);
++
++ if (!_dma)
++ {
++ for (i=0; i<dword_count; i++, data_buff++)
++ {
++ dwc_write_reg32( fifo, *data_buff );
++ }
++ }
++
++ _ep->xfer_count += byte_count;
++ _ep->xfer_buff += byte_count;
++}
++
++/**
++ * Set the EP STALL.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _ep The EP to set the stall on.
++ */
++void dwc_otg_ep_set_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
++{
++ depctl_data_t depctl;
++ volatile uint32_t *depctl_addr;
++
++ DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _ep->num,
++ (_ep->is_in?"IN":"OUT"));
++
++ if (_ep->is_in == 1)
++ {
++ depctl_addr = &(_core_if->dev_if->in_ep_regs[_ep->num]->diepctl);
++ depctl.d32 = dwc_read_reg32(depctl_addr);
++
++ /* set the disable and stall bits */
++ if (depctl.b.epena)
++ {
++ depctl.b.epdis = 1;
++ }
++ depctl.b.stall = 1;
++ dwc_write_reg32(depctl_addr, depctl.d32);
++ }
++ else
++ {
++ depctl_addr = &(_core_if->dev_if->out_ep_regs[_ep->num]->doepctl);
++ depctl.d32 = dwc_read_reg32(depctl_addr);
++
++ /* set the stall bit */
++ depctl.b.stall = 1;
++ dwc_write_reg32(depctl_addr, depctl.d32);
++ }
++
++ DWC_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",dwc_read_reg32(depctl_addr));
++
++ return;
++}
++
++/**
++ * Clear the EP STALL.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _ep The EP to clear stall from.
++ */
++void dwc_otg_ep_clear_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
++{
++ depctl_data_t depctl;
++ volatile uint32_t *depctl_addr;
++
++ DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _ep->num,
++ (_ep->is_in?"IN":"OUT"));
++
++ if (_ep->is_in == 1)
++ {
++ depctl_addr = &(_core_if->dev_if->in_ep_regs[_ep->num]->diepctl);
++ }
++ else
++ {
++ depctl_addr = &(_core_if->dev_if->out_ep_regs[_ep->num]->doepctl);
++ }
++
++ depctl.d32 = dwc_read_reg32(depctl_addr);
++
++ /* clear the stall bits */
++ depctl.b.stall = 0;
++
++ /*
++ * USB Spec 9.4.5: For endpoints using data toggle, regardless
++ * of whether an endpoint has the Halt feature set, a
++ * ClearFeature(ENDPOINT_HALT) request always results in the
++ * data toggle being reinitialized to DATA0.
++ */
++ if (_ep->type == DWC_OTG_EP_TYPE_INTR ||
++ _ep->type == DWC_OTG_EP_TYPE_BULK)
++ {
++ depctl.b.setd0pid = 1; /* DATA0 */
++ }
++
++ dwc_write_reg32(depctl_addr, depctl.d32);
++ DWC_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",dwc_read_reg32(depctl_addr));
++ return;
++}
++
++/**
++ * This function reads a packet from the Rx FIFO into the destination
++ * buffer. To read SETUP data use dwc_otg_read_setup_packet.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _dest Destination buffer for the packet.
++ * @param _bytes Number of bytes to copy to the destination.
++ */
++void dwc_otg_read_packet(dwc_otg_core_if_t *_core_if,
++ uint8_t *_dest,
++ uint16_t _bytes)
++{
++ int i;
++ int word_count = (_bytes + 3) / 4;
++
++ volatile uint32_t *fifo = _core_if->data_fifo[0];
++ uint32_t *data_buff = (uint32_t *)_dest;
++
++ /**
++ * @todo Account for the case where _dest is not dword aligned. This
++ * requires reading data from the FIFO into a uint32_t temp buffer,
++ * then moving it into the data buffer.
++ */
++
++ DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__,
++ _core_if, _dest, _bytes);
++
++ for (i=0; i<word_count; i++, data_buff++) \
++ {
++ *data_buff = dwc_read_reg32(fifo);
++ }
++
++ return;
++}
++
++
++
++/**
++ * This functions reads the device registers and prints them
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++void dwc_otg_dump_dev_registers(dwc_otg_core_if_t *_core_if)
++{
++ int i;
++ volatile uint32_t *addr;
++
++ DWC_PRINT("Device Global Registers\n");
++ addr=&_core_if->dev_if->dev_global_regs->dcfg;
++ DWC_PRINT("DCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->dev_if->dev_global_regs->dctl;
++ DWC_PRINT("DCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->dev_if->dev_global_regs->dsts;
++ DWC_PRINT("DSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->dev_if->dev_global_regs->diepmsk;
++ DWC_PRINT("DIEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->dev_if->dev_global_regs->doepmsk;
++ DWC_PRINT("DOEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->dev_if->dev_global_regs->daint;
++ DWC_PRINT("DAINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->dev_if->dev_global_regs->dtknqr1;
++ DWC_PRINT("DTKNQR1 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ if (_core_if->hwcfg2.b.dev_token_q_depth > 6)
++ {
++ addr=&_core_if->dev_if->dev_global_regs->dtknqr2;
++ DWC_PRINT("DTKNQR2 @0x%08X : 0x%08X\n",
++ (uint32_t)addr,dwc_read_reg32(addr));
++ }
++
++ addr=&_core_if->dev_if->dev_global_regs->dvbusdis;
++ DWC_PRINT("DVBUSID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++
++ addr=&_core_if->dev_if->dev_global_regs->dvbuspulse;
++ DWC_PRINT("DVBUSPULSE @0x%08X : 0x%08X\n",
++ (uint32_t)addr,dwc_read_reg32(addr));
++
++ if (_core_if->hwcfg2.b.dev_token_q_depth > 14)
++ {
++ addr=&_core_if->dev_if->dev_global_regs->dtknqr3_dthrctl;
++ DWC_PRINT("DTKNQR3 @0x%08X : 0x%08X\n",
++ (uint32_t)addr, dwc_read_reg32(addr));
++ }
++
++ if (_core_if->hwcfg2.b.dev_token_q_depth > 22)
++ {
++ addr=&_core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
++ DWC_PRINT("DTKNQR4 @0x%08X : 0x%08X\n",
++ (uint32_t)addr, dwc_read_reg32(addr));
++ }
++
++ for (i=0; i<= _core_if->dev_if->num_in_eps; i++)
++ {
++ DWC_PRINT("Device IN EP %d Registers\n", i);
++ addr=&_core_if->dev_if->in_ep_regs[i]->diepctl;
++ DWC_PRINT("DIEPCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->dev_if->in_ep_regs[i]->diepint;
++ DWC_PRINT("DIEPINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->dev_if->in_ep_regs[i]->dieptsiz;
++ DWC_PRINT("DIETSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->dev_if->in_ep_regs[i]->diepdma;
++ DWC_PRINT("DIEPDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->dev_if->in_ep_regs[i]->dtxfsts;
++ DWC_PRINT("DTXFSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ }
++
++
++ for (i=0; i<= _core_if->dev_if->num_out_eps; i++)
++ {
++ DWC_PRINT("Device OUT EP %d Registers\n", i);
++ addr=&_core_if->dev_if->out_ep_regs[i]->doepctl;
++ DWC_PRINT("DOEPCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->dev_if->out_ep_regs[i]->doepfn;
++ DWC_PRINT("DOEPFN @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->dev_if->out_ep_regs[i]->doepint;
++ DWC_PRINT("DOEPINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->dev_if->out_ep_regs[i]->doeptsiz;
++ DWC_PRINT("DOETSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->dev_if->out_ep_regs[i]->doepdma;
++ DWC_PRINT("DOEPDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++
++ }
++ return;
++}
++
++/**
++ * This function reads the host registers and prints them
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++void dwc_otg_dump_host_registers(dwc_otg_core_if_t *_core_if)
++{
++ int i;
++ volatile uint32_t *addr;
++
++ DWC_PRINT("Host Global Registers\n");
++ addr=&_core_if->host_if->host_global_regs->hcfg;
++ DWC_PRINT("HCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->host_if->host_global_regs->hfir;
++ DWC_PRINT("HFIR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->host_if->host_global_regs->hfnum;
++ DWC_PRINT("HFNUM @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->host_if->host_global_regs->hptxsts;
++ DWC_PRINT("HPTXSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->host_if->host_global_regs->haint;
++ DWC_PRINT("HAINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->host_if->host_global_regs->haintmsk;
++ DWC_PRINT("HAINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=_core_if->host_if->hprt0;
++ DWC_PRINT("HPRT0 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++
++ for (i=0; i<_core_if->core_params->host_channels; i++)
++ {
++ DWC_PRINT("Host Channel %d Specific Registers\n", i);
++ addr=&_core_if->host_if->hc_regs[i]->hcchar;
++ DWC_PRINT("HCCHAR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->host_if->hc_regs[i]->hcsplt;
++ DWC_PRINT("HCSPLT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->host_if->hc_regs[i]->hcint;
++ DWC_PRINT("HCINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->host_if->hc_regs[i]->hcintmsk;
++ DWC_PRINT("HCINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->host_if->hc_regs[i]->hctsiz;
++ DWC_PRINT("HCTSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->host_if->hc_regs[i]->hcdma;
++ DWC_PRINT("HCDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++
++ }
++ return;
++}
++
++/**
++ * This function reads the core global registers and prints them
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++void dwc_otg_dump_global_registers(dwc_otg_core_if_t *_core_if)
++{
++ int i;
++ volatile uint32_t *addr;
++
++ DWC_PRINT("Core Global Registers\n");
++ addr=&_core_if->core_global_regs->gotgctl;
++ DWC_PRINT("GOTGCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->gotgint;
++ DWC_PRINT("GOTGINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->gahbcfg;
++ DWC_PRINT("GAHBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->gusbcfg;
++ DWC_PRINT("GUSBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->grstctl;
++ DWC_PRINT("GRSTCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->gintsts;
++ DWC_PRINT("GINTSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->gintmsk;
++ DWC_PRINT("GINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->grxstsr;
++ DWC_PRINT("GRXSTSR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ //addr=&_core_if->core_global_regs->grxstsp;
++ //DWC_PRINT("GRXSTSP @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->grxfsiz;
++ DWC_PRINT("GRXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->gnptxfsiz;
++ DWC_PRINT("GNPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->gnptxsts;
++ DWC_PRINT("GNPTXSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->gi2cctl;
++ DWC_PRINT("GI2CCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->gpvndctl;
++ DWC_PRINT("GPVNDCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->ggpio;
++ DWC_PRINT("GGPIO @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->guid;
++ DWC_PRINT("GUID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->gsnpsid;
++ DWC_PRINT("GSNPSID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->ghwcfg1;
++ DWC_PRINT("GHWCFG1 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->ghwcfg2;
++ DWC_PRINT("GHWCFG2 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->ghwcfg3;
++ DWC_PRINT("GHWCFG3 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->ghwcfg4;
++ DWC_PRINT("GHWCFG4 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++ addr=&_core_if->core_global_regs->hptxfsiz;
++ DWC_PRINT("HPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr));
++
++ for (i=0; i<_core_if->hwcfg4.b.num_dev_perio_in_ep; i++)
++ {
++ addr=&_core_if->core_global_regs->dptxfsiz_dieptxf[i];
++ DWC_PRINT("DPTXFSIZ[%d] @0x%08X : 0x%08X\n",i,(uint32_t)addr,dwc_read_reg32(addr));
++ }
++}
++
++/**
++ * Flush a Tx FIFO.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _num Tx FIFO to flush.
++ */
++extern void dwc_otg_flush_tx_fifo( dwc_otg_core_if_t *_core_if,
++ const int _num )
++{
++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs;
++ volatile grstctl_t greset = { .d32 = 0};
++ int count = 0;
++
++ DWC_DEBUGPL((DBG_CIL|DBG_PCDV), "Flush Tx FIFO %d\n", _num);
++
++ greset.b.txfflsh = 1;
++ greset.b.txfnum = _num;
++ dwc_write_reg32( &global_regs->grstctl, greset.d32 );
++
++ do
++ {
++ greset.d32 = dwc_read_reg32( &global_regs->grstctl);
++ if (++count > 10000)
++ {
++ DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
++ __func__, greset.d32,
++ dwc_read_reg32( &global_regs->gnptxsts));
++ break;
++ }
++ }
++ while (greset.b.txfflsh == 1);
++
++ /* Wait for 3 PHY Clocks*/
++ UDELAY(1);
++}
++
++/**
++ * Flush Rx FIFO.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++extern void dwc_otg_flush_rx_fifo( dwc_otg_core_if_t *_core_if )
++{
++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs;
++ volatile grstctl_t greset = { .d32 = 0};
++ int count = 0;
++
++ DWC_DEBUGPL((DBG_CIL|DBG_PCDV), "%s\n", __func__);
++ /*
++ *
++ */
++ greset.b.rxfflsh = 1;
++ dwc_write_reg32( &global_regs->grstctl, greset.d32 );
++
++ do
++ {
++ greset.d32 = dwc_read_reg32( &global_regs->grstctl);
++ if (++count > 10000)
++ {
++ DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__,
++ greset.d32);
++ break;
++ }
++ }
++ while (greset.b.rxfflsh == 1);
++
++ /* Wait for 3 PHY Clocks*/
++ UDELAY(1);
++}
++
++/**
++ * Do core a soft reset of the core. Be careful with this because it
++ * resets all the internal state machines of the core.
++ */
++void dwc_otg_core_reset(dwc_otg_core_if_t *_core_if)
++{
++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs;
++ volatile grstctl_t greset = { .d32 = 0};
++ int count = 0;
++
++ DWC_DEBUGPL(DBG_CILV, "%s\n", __func__);
++ /* Wait for AHB master IDLE state. */
++ do
++ {
++ UDELAY(10);
++ greset.d32 = dwc_read_reg32( &global_regs->grstctl);
++ if (++count > 100000)
++ {
++ DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x\n", __func__,
++ greset.d32);
++ return;
++ }
++ }
++ while (greset.b.ahbidle == 0);
++
++ /* Core Soft Reset */
++ count = 0;
++ greset.b.csftrst = 1;
++ dwc_write_reg32( &global_regs->grstctl, greset.d32 );
++ do
++ {
++ greset.d32 = dwc_read_reg32( &global_regs->grstctl);
++ if (++count > 10000)
++ {
++ DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n", __func__,
++ greset.d32);
++ break;
++ }
++ }
++ while (greset.b.csftrst == 1);
++
++ /* Wait for 3 PHY Clocks*/
++ //DWC_PRINT("100ms\n");
++ MDELAY(100);
++}
++
++
++
++/**
++ * Register HCD callbacks. The callbacks are used to start and stop
++ * the HCD for interrupt processing.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _cb the HCD callback structure.
++ * @param _p pointer to be passed to callback function (usb_hcd*).
++ */
++extern void dwc_otg_cil_register_hcd_callbacks( dwc_otg_core_if_t *_core_if,
++ dwc_otg_cil_callbacks_t *_cb,
++ void *_p)
++{
++ _core_if->hcd_cb = _cb;
++ _cb->p = _p;
++}
++
++/**
++ * Register PCD callbacks. The callbacks are used to start and stop
++ * the PCD for interrupt processing.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _cb the PCD callback structure.
++ * @param _p pointer to be passed to callback function (pcd*).
++ */
++extern void dwc_otg_cil_register_pcd_callbacks( dwc_otg_core_if_t *_core_if,
++ dwc_otg_cil_callbacks_t *_cb,
++ void *_p)
++{
++ _core_if->pcd_cb = _cb;
++ _cb->p = _p;
++}
++
+diff --git a/drivers/usb/dwc_otg/dwc_otg_cil.h b/drivers/usb/dwc_otg/dwc_otg_cil.h
+new file mode 100644
+index 0000000..aa810ae
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_cil.h
+@@ -0,0 +1,901 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_cil.h $
++ * $Revision: #12 $
++ * $Date: 2007/02/08 $
++ * $Change: 792294 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++#if !defined(__DWC_CIL_H__)
++#define __DWC_CIL_H__
++
++#include "dwc_otg_plat.h"
++#include "dwc_otg_regs.h"
++#include <linux/workqueue.h>
++#ifdef DEBUG
++#include "linux/timer.h"
++#endif
++
++/**
++ * @file
++ * This file contains the interface to the Core Interface Layer.
++ */
++
++/**
++ * The <code>dwc_ep</code> structure represents the state of a single
++ * endpoint when acting in device mode. It contains the data items
++ * needed for an endpoint to be activated and transfer packets.
++ */
++typedef struct dwc_ep
++{
++ /** EP number used for register address lookup */
++ uint8_t num;
++ /** EP direction 0 = OUT */
++ unsigned is_in : 1;
++ /** EP active. */
++ unsigned active : 1;
++
++ /** Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic Tx FIFO
++ If dedicated Tx FIFOs are enabled for all IN Eps - Tx FIFO # FOR IN EPs*/
++ unsigned tx_fifo_num : 4;
++ /** EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR */
++ unsigned type : 2;
++#define DWC_OTG_EP_TYPE_CONTROL 0
++#define DWC_OTG_EP_TYPE_ISOC 1
++#define DWC_OTG_EP_TYPE_BULK 2
++#define DWC_OTG_EP_TYPE_INTR 3
++
++ /** DATA start PID for INTR and BULK EP */
++ unsigned data_pid_start : 1;
++ /** Frame (even/odd) for ISOC EP */
++ unsigned even_odd_frame : 1;
++ /** Max Packet bytes */
++ unsigned maxpacket : 11;
++
++ /** @name Transfer state */
++ /** @{ */
++
++ /**
++ * Pointer to the beginning of the transfer buffer -- do not modify
++ * during transfer.
++ */
++
++ uint32_t dma_addr;
++
++ uint8_t *start_xfer_buff;
++ /** pointer to the transfer buffer */
++ uint8_t *xfer_buff;
++ /** Number of bytes to transfer */
++ unsigned xfer_len : 19;
++ /** Number of bytes transferred. */
++ unsigned xfer_count : 19;
++ /** Sent ZLP */
++ unsigned sent_zlp : 1;
++ /** Total len for control transfer */
++ unsigned total_len : 19;
++
++ /** stall clear flag */
++ unsigned stall_clear_flag : 1;
++ /** @} */
++} dwc_ep_t;
++
++/*
++ * Reasons for halting a host channel.
++ */
++typedef enum dwc_otg_halt_status
++{
++ DWC_OTG_HC_XFER_NO_HALT_STATUS,
++ DWC_OTG_HC_XFER_COMPLETE,
++ DWC_OTG_HC_XFER_URB_COMPLETE,
++ DWC_OTG_HC_XFER_ACK,
++ DWC_OTG_HC_XFER_NAK,
++ DWC_OTG_HC_XFER_NYET,
++ DWC_OTG_HC_XFER_STALL,
++ DWC_OTG_HC_XFER_XACT_ERR,
++ DWC_OTG_HC_XFER_FRAME_OVERRUN,
++ DWC_OTG_HC_XFER_BABBLE_ERR,
++ DWC_OTG_HC_XFER_DATA_TOGGLE_ERR,
++ DWC_OTG_HC_XFER_AHB_ERR,
++ DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE,
++ DWC_OTG_HC_XFER_URB_DEQUEUE
++} dwc_otg_halt_status_e;
++
++/**
++ * Host channel descriptor. This structure represents the state of a single
++ * host channel when acting in host mode. It contains the data items needed to
++ * transfer packets to an endpoint via a host channel.
++ */
++typedef struct dwc_hc
++{
++ /** Host channel number used for register address lookup */
++ uint8_t hc_num;
++
++ /** Device to access */
++ unsigned dev_addr : 7;
++
++ /** EP to access */
++ unsigned ep_num : 4;
++
++ /** EP direction. 0: OUT, 1: IN */
++ unsigned ep_is_in : 1;
++
++ /**
++ * EP speed.
++ * One of the following values:
++ * - DWC_OTG_EP_SPEED_LOW
++ * - DWC_OTG_EP_SPEED_FULL
++ * - DWC_OTG_EP_SPEED_HIGH
++ */
++ unsigned speed : 2;
++#define DWC_OTG_EP_SPEED_LOW 0
++#define DWC_OTG_EP_SPEED_FULL 1
++#define DWC_OTG_EP_SPEED_HIGH 2
++
++ /**
++ * Endpoint type.
++ * One of the following values:
++ * - DWC_OTG_EP_TYPE_CONTROL: 0
++ * - DWC_OTG_EP_TYPE_ISOC: 1
++ * - DWC_OTG_EP_TYPE_BULK: 2
++ * - DWC_OTG_EP_TYPE_INTR: 3
++ */
++ unsigned ep_type : 2;
++
++ /** Max packet size in bytes */
++ unsigned max_packet : 11;
++
++ /**
++ * PID for initial transaction.
++ * 0: DATA0,<br>
++ * 1: DATA2,<br>
++ * 2: DATA1,<br>
++ * 3: MDATA (non-Control EP),
++ * SETUP (Control EP)
++ */
++ unsigned data_pid_start : 2;
++#define DWC_OTG_HC_PID_DATA0 0
++#define DWC_OTG_HC_PID_DATA2 1
++#define DWC_OTG_HC_PID_DATA1 2
++#define DWC_OTG_HC_PID_MDATA 3
++#define DWC_OTG_HC_PID_SETUP 3
++
++ /** Number of periodic transactions per (micro)frame */
++ unsigned multi_count: 2;
++
++ /** @name Transfer State */
++ /** @{ */
++
++ /** Pointer to the current transfer buffer position. */
++ uint8_t *xfer_buff;
++ /** Total number of bytes to transfer. */
++ uint32_t xfer_len;
++ /** Number of bytes transferred so far. */
++ uint32_t xfer_count;
++ /** Packet count at start of transfer.*/
++ uint16_t start_pkt_count;
++
++ /**
++ * Flag to indicate whether the transfer has been started. Set to 1 if
++ * it has been started, 0 otherwise.
++ */
++ uint8_t xfer_started;
++
++ /**
++ * Set to 1 to indicate that a PING request should be issued on this
++ * channel. If 0, process normally.
++ */
++ uint8_t do_ping;
++
++ /**
++ * Set to 1 to indicate that the error count for this transaction is
++ * non-zero. Set to 0 if the error count is 0.
++ */
++ uint8_t error_state;
++
++ /**
++ * Set to 1 to indicate that this channel should be halted the next
++ * time a request is queued for the channel. This is necessary in
++ * slave mode if no request queue space is available when an attempt
++ * is made to halt the channel.
++ */
++ uint8_t halt_on_queue;
++
++ /**
++ * Set to 1 if the host channel has been halted, but the core is not
++ * finished flushing queued requests. Otherwise 0.
++ */
++ uint8_t halt_pending;
++
++ /**
++ * Reason for halting the host channel.
++ */
++ dwc_otg_halt_status_e halt_status;
++
++ /*
++ * Split settings for the host channel
++ */
++ uint8_t do_split; /**< Enable split for the channel */
++ uint8_t complete_split; /**< Enable complete split */
++ uint8_t hub_addr; /**< Address of high speed hub */
++
++ uint8_t port_addr; /**< Port of the low/full speed device */
++ /** Split transaction position
++ * One of the following values:
++ * - DWC_HCSPLIT_XACTPOS_MID
++ * - DWC_HCSPLIT_XACTPOS_BEGIN
++ * - DWC_HCSPLIT_XACTPOS_END
++ * - DWC_HCSPLIT_XACTPOS_ALL */
++ uint8_t xact_pos;
++
++ /** Set when the host channel does a short read. */
++ uint8_t short_read;
++
++ /**
++ * Number of requests issued for this channel since it was assigned to
++ * the current transfer (not counting PINGs).
++ */
++ uint8_t requests;
++
++ /**
++ * Queue Head for the transfer being processed by this channel.
++ */
++ struct dwc_otg_qh *qh;
++
++ /** @} */
++
++ /** Entry in list of host channels. */
++ struct list_head hc_list_entry;
++} dwc_hc_t;
++
++/**
++ * The following parameters may be specified when starting the module. These
++ * parameters define how the DWC_otg controller should be configured.
++ * Parameter values are passed to the CIL initialization function
++ * dwc_otg_cil_init.
++ */
++typedef struct dwc_otg_core_params
++{
++ int32_t opt;
++#define dwc_param_opt_default 1
++
++ /**
++ * Specifies the OTG capabilities. The driver will automatically
++ * detect the value for this parameter if none is specified.
++ * 0 - HNP and SRP capable (default)
++ * 1 - SRP Only capable
++ * 2 - No HNP/SRP capable
++ */
++ int32_t otg_cap;
++#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0
++#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1
++#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
++#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
++
++ /**
++ * Specifies whether to use slave or DMA mode for accessing the data
++ * FIFOs. The driver will automatically detect the value for this
++ * parameter if none is specified.
++ * 0 - Slave
++ * 1 - DMA (default, if available)
++ */
++ int32_t dma_enable;
++#define dwc_param_dma_enable_default 1
++
++ /** The DMA Burst size (applicable only for External DMA
++ * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
++ */
++ int32_t dma_burst_size; /* Translate this to GAHBCFG values */
++#define dwc_param_dma_burst_size_default 32
++
++ /**
++ * Specifies the maximum speed of operation in host and device mode.
++ * The actual speed depends on the speed of the attached device and
++ * the value of phy_type. The actual speed depends on the speed of the
++ * attached device.
++ * 0 - High Speed (default)
++ * 1 - Full Speed
++ */
++ int32_t speed;
++#define dwc_param_speed_default 0
++#define DWC_SPEED_PARAM_HIGH 0
++#define DWC_SPEED_PARAM_FULL 1
++
++ /** Specifies whether low power mode is supported when attached
++ * to a Full Speed or Low Speed device in host mode.
++ * 0 - Don't support low power mode (default)
++ * 1 - Support low power mode
++ */
++ int32_t host_support_fs_ls_low_power;
++#define dwc_param_host_support_fs_ls_low_power_default 0
++
++ /** Specifies the PHY clock rate in low power mode when connected to a
++ * Low Speed device in host mode. This parameter is applicable only if
++ * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
++ * then defaults to 6 MHZ otherwise 48 MHZ.
++ *
++ * 0 - 48 MHz
++ * 1 - 6 MHz
++ */
++ int32_t host_ls_low_power_phy_clk;
++#define dwc_param_host_ls_low_power_phy_clk_default 0
++#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
++#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
++
++ /**
++ * 0 - Use cC FIFO size parameters
++ * 1 - Allow dynamic FIFO sizing (default)
++ */
++ int32_t enable_dynamic_fifo;
++#define dwc_param_enable_dynamic_fifo_default 1
++
++ /** Total number of 4-byte words in the data FIFO memory. This
++ * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
++ * Tx FIFOs.
++ * 32 to 32768
++ * AlenOh:Note: The total FIFO memory depth in the TCC configuration is 4160.
++ */
++ int32_t data_fifo_size;
++#define dwc_param_data_fifo_size_default 4160
++
++ /** Number of 4-byte words in the Rx FIFO in device mode when dynamic
++ * FIFO sizing is enabled.
++ * 16 to 32768 (default 1064)
++ */
++ int32_t dev_rx_fifo_size;
++#define dwc_param_dev_rx_fifo_size_default 1064
++
++ /** Number of 4-byte words in the non-periodic Tx FIFO in device mode
++ * when dynamic FIFO sizing is enabled.
++ * 16 to 32768 (default 1024)
++ */
++ int32_t dev_nperio_tx_fifo_size;
++#define dwc_param_dev_nperio_tx_fifo_size_default (64/4) //1024 //AlenOh
++
++ /** Number of 4-byte words in each of the periodic Tx FIFOs in device
++ * mode when dynamic FIFO sizing is enabled.
++ * 4 to 768 (default 256)
++ */
++ uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
++#define dwc_param_dev_perio_tx_fifo_size_default 256
++
++ /** Number of 4-byte words in the Rx FIFO in host mode when dynamic
++ * FIFO sizing is enabled.
++ * 16 to 32768 (default 1024)
++ */
++ int32_t host_rx_fifo_size;
++#define dwc_param_host_rx_fifo_size_default 1024
++
++ /** Number of 4-byte words in the non-periodic Tx FIFO in host mode
++ * when Dynamic FIFO sizing is enabled in the core.
++ * 16 to 32768 (default 1024)
++ */
++ int32_t host_nperio_tx_fifo_size;
++#define dwc_param_host_nperio_tx_fifo_size_default 1024
++
++ /** Number of 4-byte words in the host periodic Tx FIFO when dynamic
++ * FIFO sizing is enabled.
++ * 16 to 32768 (default 1024)
++ */
++ int32_t host_perio_tx_fifo_size;
++#define dwc_param_host_perio_tx_fifo_size_default 1024
++
++ /** The maximum transfer size supported in bytes.
++ * 2047 to 65,535 (default 65,535)
++ */
++ int32_t max_transfer_size;
++#define dwc_param_max_transfer_size_default 65535
++
++ /** The maximum number of packets in a transfer.
++ * 15 to 511 (default 511)
++ */
++ int32_t max_packet_count;
++#define dwc_param_max_packet_count_default 511
++
++ /** The number of host channel registers to use.
++ * 1 to 16 (default 12)
++ * Note: The FPGA configuration supports a maximum of 12 host channels.
++ */
++ int32_t host_channels;
++#define dwc_param_host_channels_default 12
++
++ /** The number of endpoints in addition to EP0 available for device
++ * mode operations.
++ * 1 to 15 (default 6 IN and OUT)
++ * Note: The FPGA configuration supports a maximum of 6 IN and OUT
++ * endpoints in addition to EP0.
++ */
++ int32_t dev_endpoints;
++#define dwc_param_dev_endpoints_default 6
++
++ /**
++ * Specifies the type of PHY interface to use. By default, the driver
++ * will automatically detect the phy_type.
++ *
++ * 0 - Full Speed PHY
++ * 1 - UTMI+ (default)
++ * 2 - ULPI
++ */
++ int32_t phy_type;
++#define DWC_PHY_TYPE_PARAM_FS 0
++#define DWC_PHY_TYPE_PARAM_UTMI 1
++#define DWC_PHY_TYPE_PARAM_ULPI 2
++#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI
++
++ /**
++ * Specifies the UTMI+ Data Width. This parameter is
++ * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
++ * PHY_TYPE, this parameter indicates the data width between
++ * the MAC and the ULPI Wrapper.) Also, this parameter is
++ * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
++ * to "8 and 16 bits", meaning that the core has been
++ * configured to work at either data path width.
++ *
++ * 8 or 16 bits (default 16)
++ */
++ int32_t phy_utmi_width;
++#define dwc_param_phy_utmi_width_default 16
++
++ /**
++ * Specifies whether the ULPI operates at double or single
++ * data rate. This parameter is only applicable if PHY_TYPE is
++ * ULPI.
++ *
++ * 0 - single data rate ULPI interface with 8 bit wide data
++ * bus (default)
++ * 1 - double data rate ULPI interface with 4 bit wide data
++ * bus
++ */
++ int32_t phy_ulpi_ddr;
++#define dwc_param_phy_ulpi_ddr_default 0
++
++ /**
++ * Specifies whether to use the internal or external supply to
++ * drive the vbus with a ULPI phy.
++ */
++ int32_t phy_ulpi_ext_vbus;
++#define DWC_PHY_ULPI_INTERNAL_VBUS 0
++#define DWC_PHY_ULPI_EXTERNAL_VBUS 1
++#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS
++
++ /**
++ * Specifies whether to use the I2Cinterface for full speed PHY. This
++ * parameter is only applicable if PHY_TYPE is FS.
++ * 0 - No (default)
++ * 1 - Yes
++ */
++ int32_t i2c_enable;
++#define dwc_param_i2c_enable_default 0
++
++ int32_t ulpi_fs_ls;
++#define dwc_param_ulpi_fs_ls_default 0
++
++ int32_t ts_dline;
++#define dwc_param_ts_dline_default 0
++
++ /**
++ * Specifies whether dedicated transmit FIFOs are
++ * enabled for non periodic IN endpoints in device mode
++ * 0 - No
++ * 1 - Yes
++ */
++ int32_t en_multiple_tx_fifo;
++#define dwc_param_en_multiple_tx_fifo_default 1
++
++ /** Number of 4-byte words in each of the Tx FIFOs in device
++ * mode when dynamic FIFO sizing is enabled.
++ * 4 to 768 (default 256)
++ */
++ uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
++#define dwc_param_dev_tx_fifo_size_default 256
++
++ /** Thresholding enable flag-
++ * bit 0 - enable non-ISO Tx thresholding
++ * bit 1 - enable ISO Tx thresholding
++ * bit 2 - enable Rx thresholding
++ */
++ uint32_t thr_ctl;
++#define dwc_param_thr_ctl_default 0
++
++ /** Thresholding length for Tx
++ * FIFOs in 32 bit DWORDs
++ */
++ uint32_t tx_thr_length;
++#define dwc_param_tx_thr_length_default 64
++
++ /** Thresholding length for Rx
++ * FIFOs in 32 bit DWORDs
++ */
++ uint32_t rx_thr_length;
++#define dwc_param_rx_thr_length_default 64
++
++} dwc_otg_core_params_t;
++
++#ifdef DEBUG
++struct dwc_otg_core_if;
++typedef struct hc_xfer_info
++{
++ struct dwc_otg_core_if *core_if;
++ dwc_hc_t *hc;
++} hc_xfer_info_t;
++#endif
++
++/**
++ * The <code>dwc_otg_core_if</code> structure contains information needed to manage
++ * the DWC_otg controller acting in either host or device mode. It
++ * represents the programming view of the controller as a whole.
++ */
++typedef struct dwc_otg_core_if
++{
++ /** Parameters that define how the core should be configured.*/
++ dwc_otg_core_params_t *core_params;
++
++ /** Core Global registers starting at offset 000h. */
++ dwc_otg_core_global_regs_t *core_global_regs;
++
++ /** Device-specific information */
++ dwc_otg_dev_if_t *dev_if;
++ /** Host-specific information */
++ dwc_otg_host_if_t *host_if;
++
++ /*
++ * Set to 1 if the core PHY interface bits in USBCFG have been
++ * initialized.
++ */
++ uint8_t phy_init_done;
++
++ /*
++ * SRP Success flag, set by srp success interrupt in FS I2C mode
++ */
++ uint8_t srp_success;
++ uint8_t srp_timer_started;
++
++ /* Common configuration information */
++ /** Power and Clock Gating Control Register */
++ volatile uint32_t *pcgcctl;
++#define DWC_OTG_PCGCCTL_OFFSET 0xE00
++
++ /** Push/pop addresses for endpoints or host channels.*/
++ uint32_t *data_fifo[MAX_EPS_CHANNELS];
++#define DWC_OTG_DATA_FIFO_OFFSET 0x1000
++#define DWC_OTG_DATA_FIFO_SIZE 0x1000
++
++ /** Total RAM for FIFOs (Bytes) */
++ uint16_t total_fifo_size;
++ /** Size of Rx FIFO (Bytes) */
++ uint16_t rx_fifo_size;
++ /** Size of Non-periodic Tx FIFO (Bytes) */
++ uint16_t nperio_tx_fifo_size;
++
++
++ /** 1 if DMA is enabled, 0 otherwise. */
++ uint8_t dma_enable;
++
++ /** 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */
++ uint8_t en_multiple_tx_fifo;
++
++ /** Set to 1 if multiple packets of a high-bandwidth transfer is in
++ * process of being queued */
++ uint8_t queuing_high_bandwidth;
++
++ /** Hardware Configuration -- stored here for convenience.*/
++ hwcfg1_data_t hwcfg1;
++ hwcfg2_data_t hwcfg2;
++ hwcfg3_data_t hwcfg3;
++ hwcfg4_data_t hwcfg4;
++
++ /** The operational State, during transations
++ * (a_host>>a_peripherial and b_device=>b_host) this may not
++ * match the core but allows the software to determine
++ * transitions.
++ */
++ uint8_t op_state;
++
++ /**
++ * Set to 1 if the HCD needs to be restarted on a session request
++ * interrupt. This is required if no connector ID status change has
++ * occurred since the HCD was last disconnected.
++ */
++ uint8_t restart_hcd_on_session_req;
++
++ /** HCD callbacks */
++ /** A-Device is a_host */
++#define A_HOST (1)
++ /** A-Device is a_suspend */
++#define A_SUSPEND (2)
++ /** A-Device is a_peripherial */
++#define A_PERIPHERAL (3)
++ /** B-Device is operating as a Peripheral. */
++#define B_PERIPHERAL (4)
++ /** B-Device is operating as a Host. */
++#define B_HOST (5)
++
++ /** HCD callbacks */
++ struct dwc_otg_cil_callbacks *hcd_cb;
++ /** PCD callbacks */
++ struct dwc_otg_cil_callbacks *pcd_cb;
++
++ /** Device mode Periodic Tx FIFO Mask */
++ uint32_t p_tx_msk;
++ /** Device mode Periodic Tx FIFO Mask */
++ uint32_t tx_msk;
++
++#ifdef DEBUG
++ uint32_t start_hcchar_val[MAX_EPS_CHANNELS];
++
++ hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS];
++ struct timer_list hc_xfer_timer[MAX_EPS_CHANNELS];
++
++ uint32_t hfnum_7_samples;
++ uint64_t hfnum_7_frrem_accum;
++ uint32_t hfnum_0_samples;
++ uint64_t hfnum_0_frrem_accum;
++ uint32_t hfnum_other_samples;
++ uint64_t hfnum_other_frrem_accum;
++#endif
++
++ struct work_struct vbus_work;
++ int8_t vbus_state;
++} dwc_otg_core_if_t;
++
++/*
++ * The following functions support initialization of the CIL driver component
++ * and the DWC_otg controller.
++ */
++extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t *_reg_base_addr,
++ dwc_otg_core_params_t *_core_params);
++extern void dwc_otg_cil_remove(dwc_otg_core_if_t *_core_if);
++extern void dwc_otg_core_init(dwc_otg_core_if_t *_core_if);
++extern void dwc_otg_core_host_init(dwc_otg_core_if_t *_core_if);
++extern void dwc_otg_core_dev_init(dwc_otg_core_if_t *_core_if);
++extern void dwc_otg_enable_global_interrupts( dwc_otg_core_if_t *_core_if );
++extern void dwc_otg_disable_global_interrupts( dwc_otg_core_if_t *_core_if );
++
++/** @name Device CIL Functions
++ * The following functions support managing the DWC_otg controller in device
++ * mode.
++ */
++/**@{*/
++extern void dwc_otg_wakeup(dwc_otg_core_if_t *_core_if);
++extern void dwc_otg_read_setup_packet (dwc_otg_core_if_t *_core_if, uint32_t *_dest);
++extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t *_core_if);
++extern void dwc_otg_ep0_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep);
++extern void dwc_otg_ep_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep);
++extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep);
++extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep);
++extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep);
++extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep);
++extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep, int _dma);
++extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep);
++extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep);
++extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t *_core_if);
++extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t *_core_if);
++/**@}*/
++
++/** @name Host CIL Functions
++ * The following functions support managing the DWC_otg controller in host
++ * mode.
++ */
++/**@{*/
++extern void dwc_otg_hc_init(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc);
++extern void dwc_otg_hc_halt(dwc_otg_core_if_t *_core_if,
++ dwc_hc_t *_hc,
++ dwc_otg_halt_status_e _halt_status);
++extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc);
++extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc);
++extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc);
++extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc);
++extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc);
++extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t *_core_if);
++extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t *_core_if);
++
++/**
++ * This function Reads HPRT0 in preparation to modify. It keeps the
++ * WC bits 0 so that if they are read as 1, they won't clear when you
++ * write it back
++ */
++static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t *_core_if)
++{
++ hprt0_data_t hprt0;
++ hprt0.d32 = dwc_read_reg32(_core_if->host_if->hprt0);
++ hprt0.b.prtena = 0;
++ hprt0.b.prtconndet = 0;
++ hprt0.b.prtenchng = 0;
++ hprt0.b.prtovrcurrchng = 0;
++ return hprt0.d32;
++}
++
++extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t *_core_if);
++/**@}*/
++
++/** @name Common CIL Functions
++ * The following functions support managing the DWC_otg controller in either
++ * device or host mode.
++ */
++/**@{*/
++
++extern void dwc_otg_read_packet(dwc_otg_core_if_t *core_if,
++ uint8_t *dest,
++ uint16_t bytes);
++
++extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t *_core_if);
++
++extern void dwc_otg_flush_tx_fifo( dwc_otg_core_if_t *_core_if,
++ const int _num );
++extern void dwc_otg_flush_rx_fifo( dwc_otg_core_if_t *_core_if );
++extern void dwc_otg_core_reset( dwc_otg_core_if_t *_core_if );
++
++/**
++ * This function returns the Core Interrupt register.
++ */
++static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t *_core_if)
++{
++ return (dwc_read_reg32(&_core_if->core_global_regs->gintsts) &
++ dwc_read_reg32(&_core_if->core_global_regs->gintmsk));
++}
++
++/**
++ * This function returns the OTG Interrupt register.
++ */
++static inline uint32_t dwc_otg_read_otg_intr (dwc_otg_core_if_t *_core_if)
++{
++ return (dwc_read_reg32 (&_core_if->core_global_regs->gotgint));
++}
++
++/**
++ * This function reads the Device All Endpoints Interrupt register and
++ * returns the IN endpoint interrupt bits.
++ */
++static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t *_core_if)
++{
++ uint32_t v;
++ v = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daint) &
++ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk);
++ return (v & 0xffff);
++
++}
++
++/**
++ * This function reads the Device All Endpoints Interrupt register and
++ * returns the OUT endpoint interrupt bits.
++ */
++static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t *_core_if)
++{
++ uint32_t v;
++ v = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daint) &
++ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk);
++ return ((v & 0xffff0000) >> 16);
++}
++
++/**
++ * This function returns the Device IN EP Interrupt register
++ */
++static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t *_core_if,
++ dwc_ep_t *_ep)
++{
++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
++ uint32_t v, msk, emp;
++ msk = dwc_read_reg32(&dev_if->dev_global_regs->diepmsk);
++ emp = dwc_read_reg32(&dev_if->dev_global_regs->dtknqr4_fifoemptymsk);
++ msk |= ((emp >> _ep->num) & 0x1) << 7;
++ v = dwc_read_reg32(&dev_if->in_ep_regs[_ep->num]->diepint) & msk;
++ /*
++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
++ uint32_t v;
++ v = dwc_read_reg32(&dev_if->in_ep_regs[_ep->num]->diepint) &
++ dwc_read_reg32(&dev_if->dev_global_regs->diepmsk);
++ */
++ return v;
++}
++/**
++ * This function returns the Device OUT EP Interrupt register
++ */
++static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t *_core_if,
++ dwc_ep_t *_ep)
++{
++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
++ uint32_t v;
++ v = dwc_read_reg32( &dev_if->out_ep_regs[_ep->num]->doepint) &
++ dwc_read_reg32(&dev_if->dev_global_regs->doepmsk);
++ return v;
++}
++
++/**
++ * This function returns the Host All Channel Interrupt register
++ */
++static inline uint32_t dwc_otg_read_host_all_channels_intr (dwc_otg_core_if_t *_core_if)
++{
++ return (dwc_read_reg32 (&_core_if->host_if->host_global_regs->haint));
++}
++
++static inline uint32_t dwc_otg_read_host_channel_intr (dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc)
++{
++ return (dwc_read_reg32 (&_core_if->host_if->hc_regs[_hc->hc_num]->hcint));
++}
++
++
++/**
++ * This function returns the mode of the operation, host or device.
++ *
++ * @return 0 - Device Mode, 1 - Host Mode
++ */
++static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t *_core_if)
++{
++ return (dwc_read_reg32( &_core_if->core_global_regs->gintsts ) & 0x1);
++}
++
++extern int choosedevice;
++static inline uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t *_core_if)
++{
++ if(!choosedevice)
++ return 0;
++ else
++ return (dwc_otg_mode(_core_if) != DWC_HOST_MODE);
++}
++static inline uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t *_core_if)
++{
++ if(!choosedevice)
++ return 1;
++ else
++ return (dwc_otg_mode(_core_if) == DWC_HOST_MODE);
++}
++
++extern int32_t dwc_otg_handle_common_intr( dwc_otg_core_if_t *_core_if );
++
++
++/**@}*/
++
++/**
++ * DWC_otg CIL callback structure. This structure allows the HCD and
++ * PCD to register functions used for starting and stopping the PCD
++ * and HCD for role change on for a DRD.
++ */
++typedef struct dwc_otg_cil_callbacks
++{
++ /** Start function for role change */
++ int (*start) (void *_p);
++ /** Stop Function for role change */
++ int (*stop) (void *_p);
++ /** Disconnect Function for role change */
++ int (*disconnect) (void *_p);
++ /** Resume/Remote wakeup Function */
++ int (*resume_wakeup) (void *_p);
++ /** Suspend function */
++ int (*suspend) (void *_p);
++ /** Session Start (SRP) */
++ int (*session_start) (void *_p);
++ /** Pointer passed to start() and stop() */
++ void *p;
++} dwc_otg_cil_callbacks_t;
++
++extern void dwc_otg_cil_register_pcd_callbacks( dwc_otg_core_if_t *_core_if,
++ dwc_otg_cil_callbacks_t *_cb,
++ void *_p);
++extern void dwc_otg_cil_register_hcd_callbacks( dwc_otg_core_if_t *_core_if,
++ dwc_otg_cil_callbacks_t *_cb,
++ void *_p);
++#endif
+diff --git a/drivers/usb/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/dwc_otg/dwc_otg_cil_intr.c
+new file mode 100644
+index 0000000..3b96620
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_cil_intr.c
+@@ -0,0 +1,738 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_cil_intr.c $
++ * $Revision: #7 $
++ * $Date: 2005/11/02 $
++ * $Change: 553126 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++/** @file
++ *
++ * The Core Interface Layer provides basic services for accessing and
++ * managing the DWC_otg hardware. These services are used by both the
++ * Host Controller Driver and the Peripheral Controller Driver.
++ *
++ * This file contains the Common Interrupt handlers.
++ */
++#include <mach/gpio.h>
++#include <hhtech_gpio.h>
++#include "dwc_otg_driver.h"
++#include "dwc_otg_plat.h"
++#include "dwc_otg_regs.h"
++#include "dwc_otg_cil.h"
++#include "tcc_usb_def.h"
++#include "tcc_usb_phy.h"
++
++/* For Signature */
++#define DWC_OTG_CIL_INTR_SIGNATURE 'D','W','C','_','O','T','G','_','C','I','L','_','I','N','T','R','_'
++#define DWC_OTG_CIL_INTR_VERSION 'V','2','.','0','0','2'
++static const unsigned char DWC_OTG_CIL_INTR_C_Version[] =
++ {SIGBYAHONG, DWC_OTG_CIL_INTR_SIGNATURE, SIGN_OS ,SIGN_CHIPSET, DWC_OTG_CIL_INTR_VERSION, 0};
++extern int choosedevice;
++const unsigned char* dwc_otg_cil_intr_get_version(void)
++{
++ return DWC_OTG_CIL_INTR_C_Version;
++}
++
++#ifdef DEBUG
++inline const char *op_state_str( dwc_otg_core_if_t *_core_if )
++{
++ return (_core_if->op_state==A_HOST?"a_host":
++ (_core_if->op_state==A_SUSPEND?"a_suspend":
++ (_core_if->op_state==A_PERIPHERAL?"a_peripheral":
++ (_core_if->op_state==B_PERIPHERAL?"b_peripheral":
++ (_core_if->op_state==B_HOST?"b_host":
++ "unknown")))));
++}
++#endif
++
++/** This function will log a debug message
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++int32_t dwc_otg_handle_mode_mismatch_intr (dwc_otg_core_if_t *_core_if)
++{
++ gintsts_data_t gintsts;
++ DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
++ dwc_otg_mode(_core_if) ? "Host" : "Device");
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.modemismatch = 1;
++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32);
++ return 1;
++}
++
++/** Start the HCD. Helper function for using the HCD callbacks.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++static inline void hcd_start( dwc_otg_core_if_t *_core_if )
++{
++ if (_core_if->hcd_cb && _core_if->hcd_cb->start) {
++ _core_if->hcd_cb->start( _core_if->hcd_cb->p );
++ }
++}
++/** Stop the HCD. Helper function for using the HCD callbacks.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++static inline void hcd_stop( dwc_otg_core_if_t *_core_if )
++{
++ if (_core_if->hcd_cb && _core_if->hcd_cb->stop) {
++ _core_if->hcd_cb->stop( _core_if->hcd_cb->p );
++ }
++}
++/** Disconnect the HCD. Helper function for using the HCD callbacks.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++static inline void hcd_disconnect( dwc_otg_core_if_t *_core_if )
++{
++ if (_core_if->hcd_cb && _core_if->hcd_cb->disconnect) {
++ _core_if->hcd_cb->disconnect( _core_if->hcd_cb->p );
++ }
++}
++/** Inform the HCD the a New Session has begun. Helper function for
++ * using the HCD callbacks.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++static inline void hcd_session_start( dwc_otg_core_if_t *_core_if )
++{
++ if (_core_if->hcd_cb && _core_if->hcd_cb->session_start) {
++ _core_if->hcd_cb->session_start( _core_if->hcd_cb->p );
++ }
++}
++
++/** Start the PCD. Helper function for using the PCD callbacks.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++static inline void pcd_start( dwc_otg_core_if_t *_core_if )
++{
++ if (_core_if->pcd_cb && _core_if->pcd_cb->start ) {
++ _core_if->pcd_cb->start( _core_if->pcd_cb->p );
++ }
++}
++/** Stop the PCD. Helper function for using the PCD callbacks.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++static inline void pcd_stop( dwc_otg_core_if_t *_core_if )
++{
++ if (_core_if->pcd_cb && _core_if->pcd_cb->stop ) {
++ _core_if->pcd_cb->stop( _core_if->pcd_cb->p );
++ }
++}
++/** Suspend the PCD. Helper function for using the PCD callbacks.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++static inline void pcd_suspend( dwc_otg_core_if_t *_core_if )
++{
++ if (_core_if->pcd_cb && _core_if->pcd_cb->suspend ) {
++ _core_if->pcd_cb->suspend( _core_if->pcd_cb->p );
++ }
++}
++/** Resume the PCD. Helper function for using the PCD callbacks.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++static inline void pcd_resume( dwc_otg_core_if_t *_core_if )
++{
++ if (_core_if->pcd_cb && _core_if->pcd_cb->resume_wakeup ) {
++ _core_if->pcd_cb->resume_wakeup( _core_if->pcd_cb->p );
++ }
++}
++
++/**
++ * This function handles the OTG Interrupts. It reads the OTG
++ * Interrupt Register (GOTGINT) to determine what interrupt has
++ * occurred.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t *_core_if)
++{
++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs;
++ gotgint_data_t gotgint;
++ gotgctl_data_t gotgctl;
++ gintmsk_data_t gintmsk;
++
++ gotgint.d32 = dwc_read_reg32( &global_regs->gotgint);
++ gotgctl.d32 = dwc_read_reg32( &global_regs->gotgctl);
++ DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
++ op_state_str(_core_if));
++ //DWC_DEBUGPL(DBG_CIL, "gotgctl=%08x\n", gotgctl.d32 );
++
++ if (gotgint.b.sesenddet) {
++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
++ "Session End Detected++ (%s)\n",
++ op_state_str(_core_if));
++ gotgctl.d32 = dwc_read_reg32( &global_regs->gotgctl);
++
++ if (_core_if->op_state == B_HOST) {
++ pcd_start( _core_if );
++ _core_if->op_state = B_PERIPHERAL;
++ } else {
++ /* If not B_HOST and Device HNP still set. HNP
++ * Did not succeed!*/
++ if (gotgctl.b.devhnpen) {
++ DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
++ DWC_ERROR( "Device Not Connected/Responding!\n" );
++ }
++
++ /* If Session End Detected the B-Cable has
++ * been disconnected. */
++ /* Reset PCD and Gadget driver to a
++ * clean state. */
++ pcd_stop(_core_if);
++
++ ////////////////////////////////////////////////////////////////////
++ //AlenOh's comment
++ // pcd_stop() can't perpectly adjusts OTG LINK.
++ // It causes next USB connection failure.
++ // OTG LINK RESET can perpectly adjusts itself.
++ // For SRP, USBPHY should stay in reset state during OTG LINK RESET
++ USBPHY_SetMode(USBPHY_MODE_RESET);
++ dwc_otg_core_init(_core_if);
++ dwc_otg_enable_global_interrupts(_core_if);
++ pcd_start( _core_if );
++ USBPHY_SetMode(USBPHY_MODE_DEVICE);
++ ////////////////////////////////////////////////////////////////////
++ }
++ gotgctl.d32 = 0;
++ gotgctl.b.devhnpen = 1;
++ dwc_modify_reg32( &global_regs->gotgctl, gotgctl.d32, 0);
++ // printk("Session End Detected\n");
++ }
++ if (gotgint.b.sesreqsucstschng) {
++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
++ "Session Reqeust Success Status Change++\n");
++ gotgctl.d32 = dwc_read_reg32( &global_regs->gotgctl);
++ if (gotgctl.b.sesreqscs) {
++ if ((_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) &&
++ (_core_if->core_params->i2c_enable)) {
++ _core_if->srp_success = 1;
++ }
++ else {
++ pcd_resume( _core_if );
++ /* Clear Session Request */
++ gotgctl.d32 = 0;
++ gotgctl.b.sesreq = 1;
++ dwc_modify_reg32( &global_regs->gotgctl,
++ gotgctl.d32, 0);
++ }
++ }
++ }
++ if (gotgint.b.hstnegsucstschng) {
++ /* Print statements during the HNP interrupt handling
++ * can cause it to fail.*/
++ gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
++ if (gotgctl.b.hstnegscs) {
++ if (dwc_otg_is_host_mode(_core_if) ) {
++ _core_if->op_state = B_HOST;
++ /*
++ * Need to disable SOF interrupt immediately.
++ * When switching from device to host, the PCD
++ * interrupt handler won't handle the
++ * interrupt if host mode is already set. The
++ * HCD interrupt handler won't get called if
++ * the HCD state is HALT. This means that the
++ * interrupt does not get handled and Linux
++ * complains loudly.
++ */
++ gintmsk.d32 = 0;
++ gintmsk.b.sofintr = 1;
++ dwc_modify_reg32(&global_regs->gintmsk,
++ gintmsk.d32, 0);
++ pcd_stop(_core_if);
++ /*
++ * Initialize the Core for Host mode.
++ */
++ hcd_start( _core_if );
++ _core_if->op_state = B_HOST;
++ }
++ } else {
++ gotgctl.d32 = 0;
++ gotgctl.b.hnpreq = 1;
++ gotgctl.b.devhnpen = 1;
++ dwc_modify_reg32( &global_regs->gotgctl,
++ gotgctl.d32, 0);
++ DWC_DEBUGPL( DBG_ANY, "HNP Failed\n");
++ DWC_ERROR( "Device Not Connected/Responding\n" );
++ }
++ }
++ if (gotgint.b.hstnegdet) {
++ /* The disconnect interrupt is set at the same time as
++ * Host Negotiation Detected. During the mode
++ * switch all interrupts are cleared so the disconnect
++ * interrupt handler will not get executed.
++ */
++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
++ "Host Negotiation Detected++ (%s)\n",
++ (dwc_otg_is_host_mode(_core_if)?"Host":"Device"));
++ if (dwc_otg_is_device_mode(_core_if)) {
++ DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",_core_if->op_state);
++ hcd_disconnect( _core_if );
++ pcd_start( _core_if );
++ _core_if->op_state = A_PERIPHERAL;
++ } else {
++ /*
++ * Need to disable SOF interrupt immediately. When
++ * switching from device to host, the PCD interrupt
++ * handler won't handle the interrupt if host mode is
++ * already set. The HCD interrupt handler won't get
++ * called if the HCD state is HALT. This means that
++ * the interrupt does not get handled and Linux
++ * complains loudly.
++ */
++ gintmsk.d32 = 0;
++ gintmsk.b.sofintr = 1;
++ dwc_modify_reg32(&global_regs->gintmsk,
++ gintmsk.d32, 0);
++ pcd_stop( _core_if );
++ hcd_start( _core_if );
++ _core_if->op_state = A_HOST;
++ }
++ }
++ if (gotgint.b.adevtoutchng) {
++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
++ "A-Device Timeout Change++\n");
++ }
++ if (gotgint.b.debdone) {
++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
++ "Debounce Done++\n");
++ }
++
++ /* Clear GOTGINT */
++ dwc_write_reg32 (&_core_if->core_global_regs->gotgint, gotgint.d32);
++
++ return 1;
++}
++
++/**
++ * This function handles the Connector ID Status Change Interrupt. It
++ * reads the OTG Interrupt Register (GOTCTL) to determine whether this
++ * is a Device to Host Mode transition or a Host Mode to Device
++ * Transition.
++ *
++ * This only occurs when the cable is connected/removed from the PHY
++ * connector.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++extern void set_usb_syspwr_en(int sw);
++extern void set_usb_otgdrv_en(int sw);
++int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *_core_if)
++{
++ uint32_t count = 0;
++
++ gintsts_data_t gintsts = { .d32 = 0 };
++ gintmsk_data_t gintmsk = { .d32 = 0 };
++ gotgctl_data_t gotgctl = { .d32 = 0 };
++
++ /*
++ * Need to disable SOF interrupt immediately. If switching from device
++ * to host, the PCD interrupt handler won't handle the interrupt if
++ * host mode is already set. The HCD interrupt handler won't get
++ * called if the HCD state is HALT. This means that the interrupt does
++ * not get handled and Linux complains loudly.
++ */
++ gintmsk.b.sofintr = 1;
++ dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
++
++ DWC_DEBUGPL(DBG_CIL, " ++Connector ID Status Change Interrupt++ (%s)\n",
++ (dwc_otg_is_host_mode(_core_if)?"Host":"Device"));
++ gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl);
++ DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
++ DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
++
++ /* B-Device connector (Device Mode) */
++ if (gotgctl.b.conidsts && choosedevice) {
++ /* Wait for switch to device mode. */
++ while (!dwc_otg_is_device_mode(_core_if) ) {
++ DWC_PRINT("Waiting for Peripheral Mode, Mode=%s\n",
++ (dwc_otg_is_host_mode(_core_if)?"Host":"Peripheral"));
++ MDELAY(100);
++ if (++count > 10000) *(uint32_t*)NULL=0;
++ }
++ printk("ID change ISR : Device\n");
++
++ set_usb_otgdrv_en(0);
++ if(!(gpio_get_value(GPIO_USB_HOSTPWR_EN) | gpio_get_value(GPIO_HDMI_EN)))
++ set_usb_syspwr_en(0);
++
++ _core_if->op_state = B_PERIPHERAL;
++ dwc_otg_core_init(_core_if);
++ dwc_otg_enable_global_interrupts(_core_if);
++ pcd_start( _core_if );
++ } else {
++ /* A-Device connector (Host Mode) */
++ while (!dwc_otg_is_host_mode(_core_if) ) {
++ DWC_PRINT("Waiting for Host Mode, Mode=%s\n",
++ (dwc_otg_is_host_mode(_core_if)?"Host":"Peripheral"));
++ MDELAY(100);
++ if (++count > 10000) *(uint32_t*)NULL=0;
++ }
++ printk("ID change ISR : Host\n");
++
++ set_usb_syspwr_en(1);
++ set_usb_otgdrv_en(1);
++
++ _core_if->op_state = A_HOST;
++ /*
++ * Initialize the Core for Host mode.
++ */
++ dwc_otg_core_init(_core_if);
++ dwc_otg_enable_global_interrupts(_core_if);
++ hcd_start( _core_if );
++ }
++
++ /* Set flag and clear interrupt */
++ gintsts.b.conidstschng = 1;
++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32);
++
++ return 1;
++}
++/**
++ * This interrupt indicates that a device is initiating the Session
++ * Request Protocol to request the host to turn on bus power so a new
++ * session can begin. The handler responds by turning on bus power. If
++ * the DWC_otg controller is in low power mode, the handler brings the
++ * controller out of low power mode before turning on bus power.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++int32_t dwc_otg_handle_session_req_intr( dwc_otg_core_if_t *_core_if )
++{
++ gintsts_data_t gintsts;
++#ifndef DWC_HOST_ONLY
++
++ DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
++
++ if (dwc_otg_is_device_mode(_core_if) ) {
++ DWC_PRINT("SRP: Device mode\n");
++ } else {
++ /* Turn on the port power bit. */
++ _core_if->vbus_state = 1;
++ schedule_work(&_core_if->vbus_work);
++ DWC_PRINT("SRP: Host mode\n");
++
++ /* Start the Connection timer. So a message can be displayed
++ * if connect does not occur within 10 seconds. */
++ hcd_session_start( _core_if );
++ }
++#endif
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.sessreqintr = 1;
++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32);
++
++ return 1;
++}
++
++/**
++ * This interrupt indicates that the DWC_otg controller has detected a
++ * resume or remote wakeup sequence. If the DWC_otg controller is in
++ * low power mode, the handler must brings the controller out of low
++ * power mode. The controller automatically begins resume
++ * signaling. The handler schedules a time to stop resume signaling.
++ */
++int32_t dwc_otg_handle_wakeup_detected_intr( dwc_otg_core_if_t *_core_if )
++{
++ gintsts_data_t gintsts;
++
++ DWC_DEBUGPL(DBG_ANY, "++Resume and Remote Wakeup Detected Interrupt++\n");
++
++ if (dwc_otg_is_device_mode(_core_if) ) {
++ dctl_data_t dctl = {.d32=0};
++ DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
++ dwc_read_reg32( &_core_if->dev_if->dev_global_regs->dsts));
++#ifdef PARTIAL_POWER_DOWN
++ if (_core_if->hwcfg4.b.power_optimiz) {
++ pcgcctl_data_t power = {.d32=0};
++
++ power.d32 = dwc_read_reg32( _core_if->pcgcctl );
++ DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n", power.d32);
++
++ power.b.stoppclk = 0;
++ dwc_write_reg32( _core_if->pcgcctl, power.d32);
++
++ power.b.pwrclmp = 0;
++ dwc_write_reg32( _core_if->pcgcctl, power.d32);
++
++ power.b.rstpdwnmodule = 0;
++ dwc_write_reg32( _core_if->pcgcctl, power.d32);
++ }
++#endif
++ /* Clear the Remote Wakeup Signalling */
++ dctl.b.rmtwkupsig = 1;
++ dwc_modify_reg32( &_core_if->dev_if->dev_global_regs->dctl,
++ dctl.d32, 0 );
++
++ if (_core_if->pcd_cb && _core_if->pcd_cb->resume_wakeup) {
++ _core_if->pcd_cb->resume_wakeup( _core_if->pcd_cb->p );
++ }
++
++ } else {
++ /*
++ * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
++ * so that OPT tests pass with all PHYs).
++ */
++ hprt0_data_t hprt0 = {.d32=0};
++ pcgcctl_data_t pcgcctl = {.d32=0};
++ /* Restart the Phy Clock */
++ pcgcctl.b.stoppclk = 1;
++ dwc_modify_reg32(_core_if->pcgcctl, pcgcctl.d32, 0);
++ UDELAY(10);
++
++ /* Now wait for 70 ms. */
++ hprt0.d32 = dwc_otg_read_hprt0( _core_if );
++ DWC_DEBUGPL(DBG_ANY,"Resume: HPRT0=%0x\n", hprt0.d32);
++ MDELAY(70);
++ hprt0.b.prtres = 0; /* Resume */
++ dwc_write_reg32(_core_if->host_if->hprt0, hprt0.d32);
++ DWC_DEBUGPL(DBG_ANY,"Clear Resume: HPRT0=%0x\n", dwc_read_reg32(_core_if->host_if->hprt0));
++ }
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.wkupintr = 1;
++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32);
++
++ return 1;
++}
++
++/**
++ * This interrupt indicates that a device has been disconnected from
++ * the root port.
++ */
++int32_t dwc_otg_handle_disconnect_intr( dwc_otg_core_if_t *_core_if)
++{
++ gintsts_data_t gintsts;
++
++ DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
++ (dwc_otg_is_host_mode(_core_if)?"Host":"Device"),
++ op_state_str(_core_if));
++
++ /** @todo Consolidate this if statement. */
++#ifndef DWC_HOST_ONLY
++ if (_core_if->op_state == B_HOST) {
++ /* If in device mode Disconnect and stop the HCD, then
++ * start the PCD. */
++ hcd_disconnect( _core_if );
++ pcd_start( _core_if );
++ _core_if->op_state = B_PERIPHERAL;
++ } else if (dwc_otg_is_device_mode(_core_if)) {
++ gotgctl_data_t gotgctl = { .d32 = 0 };
++ gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl);
++ if (gotgctl.b.hstsethnpen==1) {
++ /* Do nothing, if HNP in process the OTG
++ * interrupt "Host Negotiation Detected"
++ * interrupt will do the mode switch.
++ */
++ } else if (gotgctl.b.devhnpen == 0) {
++ /* If in device mode Disconnect and stop the HCD, then
++ * start the PCD. */
++ hcd_disconnect( _core_if );
++ pcd_start( _core_if );
++ _core_if->op_state = B_PERIPHERAL;
++ } else {
++ DWC_DEBUGPL(DBG_ANY,"!a_peripheral && !devhnpen\n");
++ }
++ } else {
++ if (_core_if->op_state == A_HOST) {
++ /* A-Cable still connected but device disconnected. */
++ hcd_disconnect( _core_if );
++ }
++ }
++#endif
++
++ gintsts.d32 = 0;
++ gintsts.b.disconnect = 1;
++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32);
++ return 1;
++}
++/**
++ * This interrupt indicates that SUSPEND state has been detected on
++ * the USB.
++ *
++ * For HNP the USB Suspend interrupt signals the change from
++ * "a_peripheral" to "a_host".
++ *
++ * When power management is enabled the core will be put in low power
++ * mode.
++ */
++int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t *_core_if )
++{
++ dsts_data_t dsts;
++ gintsts_data_t gintsts;
++
++ DWC_DEBUGPL(DBG_ANY,"USB SUSPEND\n");
++
++ if (dwc_otg_is_device_mode( _core_if ) ) {
++ /* Check the Device status register to determine if the Suspend
++ * state is active. */
++ dsts.d32 = dwc_read_reg32( &_core_if->dev_if->dev_global_regs->dsts);
++ DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
++ DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
++ "HWCFG4.power Optimize=%d\n",
++ dsts.b.suspsts, _core_if->hwcfg4.b.power_optimiz);
++
++#ifdef PARTIAL_POWER_DOWN
++ /** @todo Add a module parameter for power management. */
++
++ if (dsts.b.suspsts && _core_if->hwcfg4.b.power_optimiz) {
++ pcgcctl_data_t power = {.d32=0};
++ DWC_DEBUGPL(DBG_CIL, "suspend\n");
++
++ power.b.pwrclmp = 1;
++ dwc_write_reg32( _core_if->pcgcctl, power.d32);
++
++ power.b.rstpdwnmodule = 1;
++ dwc_modify_reg32( _core_if->pcgcctl, 0, power.d32);
++
++ power.b.stoppclk = 1;
++ dwc_modify_reg32( _core_if->pcgcctl, 0, power.d32);
++
++ } else {
++ DWC_DEBUGPL(DBG_ANY,"disconnect?\n");
++ }
++#endif
++ /* PCD callback for suspend. */
++ pcd_suspend(_core_if);
++ } else {
++ if (_core_if->op_state == A_PERIPHERAL) {
++ DWC_DEBUGPL(DBG_ANY,"a_peripheral->a_host\n");
++ /* Clear the a_peripheral flag, back to a_host. */
++ pcd_stop( _core_if );
++ hcd_start( _core_if );
++ _core_if->op_state = A_HOST;
++ }
++ }
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.usbsuspend = 1;
++ dwc_write_reg32( &_core_if->core_global_regs->gintsts, gintsts.d32);
++
++ return 1;
++}
++
++
++/**
++ * This function returns the Core Interrupt register.
++ */
++static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t *_core_if)
++{
++ gintsts_data_t gintsts;
++ gintmsk_data_t gintmsk;
++ gintmsk_data_t gintmsk_common = {.d32=0};
++ gintmsk_common.b.wkupintr = 1;
++ gintmsk_common.b.sessreqintr = 1;
++ gintmsk_common.b.conidstschng = 1;
++ gintmsk_common.b.otgintr = 1;
++ gintmsk_common.b.modemismatch = 1;
++ gintmsk_common.b.disconnect = 1;
++ gintmsk_common.b.usbsuspend = 1;
++ /** @todo: The port interrupt occurs while in device
++ * mode. Added code to CIL to clear the interrupt for now!
++ */
++ gintmsk_common.b.portintr = 1;
++
++ gintsts.d32 = dwc_read_reg32(&_core_if->core_global_regs->gintsts);
++ gintmsk.d32 = dwc_read_reg32(&_core_if->core_global_regs->gintmsk);
++#ifdef DEBUG
++ /* if any common interrupts set */
++ if (gintsts.d32 & gintmsk_common.d32) {
++ DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n",
++ gintsts.d32, gintmsk.d32);
++ }
++#endif
++
++ return ((gintsts.d32 & gintmsk.d32 ) & gintmsk_common.d32);
++
++}
++
++/**
++ * Common interrupt handler.
++ *
++ * The common interrupts are those that occur in both Host and Device mode.
++ * This handler handles the following interrupts:
++ * - Mode Mismatch Interrupt
++ * - Disconnect Interrupt
++ * - OTG Interrupt
++ * - Connector ID Status Change Interrupt
++ * - Session Request Interrupt.
++ * - Resume / Remote Wakeup Detected Interrupt.
++ *
++ */
++extern int32_t dwc_otg_handle_common_intr( dwc_otg_core_if_t *_core_if )
++{
++ int retval = 0;
++ gintsts_data_t gintsts;
++
++ gintsts.d32 = dwc_otg_read_common_intr(_core_if);
++
++ if (gintsts.b.modemismatch) {
++ retval |= dwc_otg_handle_mode_mismatch_intr( _core_if );
++ }
++ if (gintsts.b.otgintr) {
++ retval |= dwc_otg_handle_otg_intr( _core_if );
++ }
++ if (gintsts.b.conidstschng) {
++ retval |= dwc_otg_handle_conn_id_status_change_intr( _core_if );
++ }
++ if (gintsts.b.disconnect) {
++ retval |= dwc_otg_handle_disconnect_intr( _core_if );
++ }
++ if (gintsts.b.sessreqintr) {
++ retval |= dwc_otg_handle_session_req_intr( _core_if );
++ }
++ if (gintsts.b.wkupintr) {
++ retval |= dwc_otg_handle_wakeup_detected_intr( _core_if );
++ }
++ if (gintsts.b.usbsuspend) {
++ retval |= dwc_otg_handle_usb_suspend_intr( _core_if );
++ }
++ if (gintsts.b.portintr && dwc_otg_is_device_mode(_core_if)) {
++ /* The port interrupt occurs while in device mode with HPRT0
++ * Port Enable/Disable.
++ */
++ gintsts.d32 = 0;
++ gintsts.b.portintr = 1;
++ dwc_write_reg32(&_core_if->core_global_regs->gintsts,
++ gintsts.d32);
++ retval |= 1;
++
++ }
++ return retval;
++}
+diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.c b/drivers/usb/dwc_otg/dwc_otg_driver.c
+new file mode 100644
+index 0000000..cbadc83
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_driver.c
+@@ -0,0 +1,1688 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_driver.c $
++ * $Revision: #12 $
++ * $Date: 2007/02/07 $
++ * $Change: 791271 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++/** @file
++ * The dwc_otg_driver module provides the initialization and cleanup entry
++ * points for the DWC_otg driver. This module will be dynamically installed
++ * after Linux is booted using the insmod command. When the module is
++ * installed, the dwc_otg_driver_init function is called. When the module is
++ * removed (using rmmod), the dwc_otg_driver_cleanup function is called.
++ *
++ * This module also defines a data structure for the dwc_otg_driver, which is
++ * used in conjunction with the standard ARM lm_device structure. These
++ * structures allow the OTG driver to comply with the standard Linux driver
++ * model in which devices and drivers are registered with a bus driver. This
++ * has the benefit that Linux can expose attributes of the driver and device
++ * in its special sysfs file system. Users can then read or write files in
++ * this file system to perform diagnostics on the driver components or the
++ * device.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/stat.h> /* permission constants */
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/kthread.h>
++
++#include <asm/io.h>
++#include <asm/sizes.h>
++
++//#include <mach/bsp.h>
++
++#ifdef _USE_ATTR_
++#include <asm/arch/lm.h>
++#include "dwc_otg_attr.h"
++#endif
++
++#include "dwc_otg_plat.h"
++#include "dwc_otg_driver.h"
++#include "dwc_otg_cil.h"
++#include "dwc_otg_pcd.h"
++#include "dwc_otg_hcd.h"
++
++#include "tcc_usb_phy.h"
++#include "tcc_usb_def.h"
++
++#include <mach/tcc_pca953x.h>
++#include <linux/tcc_pwm.h>
++#include <linux/tcc_ll.h>
++
++#define DWC_DRIVER_VERSION "2.60a 22-NOV-2006"
++#define DWC_DRIVER_DESC "HS OTG USB Controller driver"
++
++extern int choosedevice;
++static int bak_choosedevice = 0;
++
++static const char dwc_driver_name[] = "dwc_otg";
++/* For Signature */
++#define DWC_OTG_DRIVER_SIGNATURE 'D','W','C','_','O','T','G','_','D','R','I','V','E','R','_'
++#define DWC_OTG_DRIVER_VERSION 'V','2','.','0','0','2'
++static const unsigned char DWC_OTG_DRIVER_C_Version[] =
++ {SIGBYAHONG, DWC_OTG_DRIVER_SIGNATURE, SIGN_OS ,SIGN_CHIPSET, DWC_OTG_DRIVER_VERSION, 0};
++
++extern void set_usb_syspwr_en(int sw);
++extern void set_usb_otgdrv_en(int sw);
++
++/*-------------------------------------------------------------------------*/
++/* Encapsulate the module parameter settings */
++
++static dwc_otg_core_params_t dwc_otg_module_params = {
++ .opt = -1,
++ .otg_cap = -1,
++ .dma_enable = -1,
++ .dma_burst_size = -1,
++ .speed = -1,
++ .host_support_fs_ls_low_power = -1,
++ .host_ls_low_power_phy_clk = -1,
++ .enable_dynamic_fifo = -1,
++ .data_fifo_size = -1,
++ .dev_rx_fifo_size = -1,
++ .dev_nperio_tx_fifo_size = -1,
++ .dev_perio_tx_fifo_size =
++ { /* dev_perio_tx_fifo_size_1 */
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1
++ }, /* 15 */
++ .host_rx_fifo_size = -1,
++ .host_nperio_tx_fifo_size = -1,
++ .host_perio_tx_fifo_size = -1,
++ .max_transfer_size = -1,
++ .max_packet_count = -1,
++ .host_channels = -1,
++ .dev_endpoints = -1,
++ .phy_type = -1,
++ .phy_utmi_width = -1,
++ .phy_ulpi_ddr = -1,
++ .phy_ulpi_ext_vbus = -1,
++ .i2c_enable = -1,
++ .ulpi_fs_ls = -1,
++ .ts_dline = -1,
++ .en_multiple_tx_fifo = -1,
++ .dev_tx_fifo_size =
++ { /* dev_tx_fifo_size */
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1,
++ -1
++ }, /* 15 */
++ .thr_ctl = -1,
++ .tx_thr_length = -1,
++ .rx_thr_length = -1,
++};
++
++#ifndef DWC_HOST_ONLY
++extern const unsigned char* dwc_otg_cil_get_version(void);
++extern const unsigned char* dwc_otg_cil_intr_get_version(void);
++extern const unsigned char* dwc_otg_pcd_get_version(void);
++extern const unsigned char* dwc_otg_pcd_intr_get_version(void);
++#endif
++static const char off_string[] = "off";
++static const char on_string[] = "on";
++static ssize_t show_hvbus(struct device_driver *_drv, char *_buf)
++{
++ return sprintf(_buf, "%s\n", "on");
++}
++static ssize_t set_hvbus(struct device_driver *_drv, const char *_buf,
++ size_t _count)
++{
++ int rc = 0;
++ int len = _count;
++ char *cp = memchr(_buf, '\n', _count);
++ if (cp)
++ len = cp - _buf;
++
++ if (len == sizeof off_string - 1 && strncmp(_buf, off_string, len) == 0)
++ {
++ //gotgctl_data_t gotgctl;
++ //gotgctl.d32 = dwc_read_reg32( &g_dwc_otg_device->core_if->core_global_regs->gotgctl);
++ //printk("hstsethnpen=%d\n",gotgctl.b.hstsethnpen);
++ TCC_DVBUS_Control(0);
++ }
++ else if (len == sizeof on_string - 1 && strncmp(_buf, on_string, len) == 0)
++ TCC_DVBUS_Control(1);
++ else
++ rc = -EINVAL;
++
++ return (rc < 0 ? rc : _count);
++}
++static DRIVER_ATTR(hvbus, S_IRUGO|S_IWUSR, show_hvbus, set_hvbus);
++
++/**
++ * This function shows the Driver Version.
++ */
++static ssize_t version_show(struct device_driver *_drv, char *buf)
++{
++#ifdef DWC_HOST_ONLY
++ return snprintf(buf, sizeof(DWC_DRIVER_VERSION)+2,"%s\n",
++ DWC_DRIVER_VERSION);
++#else
++ return snprintf(buf, PAGE_SIZE,"%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n"
++ ,DWC_DRIVER_VERSION
++ ,DWC_OTG_DRIVER_C_Version
++ ,dwc_otg_cil_get_version()
++ ,dwc_otg_cil_intr_get_version()
++ ,dwc_otg_pcd_get_version()
++ ,dwc_otg_pcd_intr_get_version()
++ ,USBPHY_GetVersion());
++#endif
++}
++static DRIVER_ATTR(version, S_IRUGO, version_show, NULL);
++
++/**
++ * Global Debug Level Mask.
++ */
++uint32_t g_dbg_lvl = DBG_HCD | DBG_HCDV | DBG_CILV | DBG_CIL;
++
++/**
++ * This function shows the driver Debug Level.
++ */
++static ssize_t dbg_level_show(struct device_driver *_drv, char *_buf)
++{
++ return sprintf(_buf, "0x%0x\n", g_dbg_lvl);
++}
++/**
++ * This function stores the driver Debug Level.
++ */
++static ssize_t dbg_level_store(struct device_driver *_drv, const char *_buf,
++ size_t _count)
++{
++ g_dbg_lvl = simple_strtoul(_buf, NULL, 16);
++ return _count;
++}
++static DRIVER_ATTR(debuglevel, S_IRUGO|S_IWUSR, dbg_level_show, dbg_level_store);
++
++
++static void tcc_usb_link_reset(void)
++{
++ BITCLR(HwIOBUSCFG->HRSTEN0, HwIOBUSCFG_USB);
++ {
++ volatile unsigned int t=1000;
++ while (t-->0);
++ }
++ BITSET(HwIOBUSCFG->HRSTEN0, HwIOBUSCFG_USB);
++}
++
++//static void show_system_info(void)
++//{
++// unsigned int cpu;
++// unsigned int bus;
++// unsigned int io_bus;
++// cpu = tca_ckc_getcpu() / 10000;
++// bus = tca_ckc_getbus() / 10000;
++// io_bus = tca_ckc_getfbusctrl(CLKCTRL4) / 10000;
++// printk("CPU:%d, BUS:%d, IOBUS:%d\n", cpu, bus, io_bus);
++//}
++
++static void tcc_set_vbus(dwc_otg_core_if_t *_core_if)
++{
++ hprt0_data_t hprt0;
++
++ TCC_DVBUS_Control((int)_core_if->vbus_state);
++ // wait the voltage to be stable
++
++ msleep_interruptible(100);
++
++ /* Control the port power bit. */
++ hprt0.d32 = dwc_otg_read_hprt0( _core_if );
++ hprt0.b.prtpwr = (unsigned)_core_if->vbus_state;
++ dwc_write_reg32(_core_if->host_if->hprt0, hprt0.d32);
++}
++
++static void tcc_vbus_work(struct work_struct *work)
++{
++ dwc_otg_core_if_t *core_if = container_of(work, dwc_otg_core_if_t, vbus_work);
++ tcc_set_vbus(core_if);
++}
++
++/**
++ * This function shows the file_storage gadget attach/detach status
++ */
++static ssize_t fsg_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ dwc_otg_device_t *dwc_otg_device = platform_get_otgdata(pdev);
++ return sprintf(buf, "%d\n", dwc_otg_device->flagDeviceAttach);
++}
++static DEVICE_ATTR(fsg, S_IRUGO, fsg_show, NULL);
++
++#define DWC_SET_MODE
++#ifdef DWC_SET_MODE
++static ssize_t read_mode(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ dwc_otg_device_t *dwc_otg_device = platform_get_otgdata(pdev);
++ return sprintf(buf, "%d\n", dwc_otg_device->flagMode);
++}
++static ssize_t set_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ dwc_otg_device_t *dwc_otg_device = platform_get_otgdata(pdev);
++ unsigned long mode;
++ mode = simple_strtoul(buf, (char **)NULL, 10);
++ dwc_otg_device->flagMode = (uint8_t)mode;
++ return count;
++}
++static DEVICE_ATTR(setmode, S_IRUSR|S_IWUSR, read_mode, set_mode);
++
++static int is_ID(uint8_t mode)
++{
++ int ret;
++ if (mode == 0) {
++ ret = 0;
++ } else if (mode == 1) {
++ ret = 1;
++ } else {
++ ret = (HwGPIO->GPADAT & Hw13);
++ }
++ return ret;
++}
++#endif
++
++/*
++ * OTG Power on/off control
++ * TODO: Handling DWC_HOST_ONLY/DWC_DEVICE_ONLY,
++ * this code only control DWC_DUAL_ROLE.
++ */
++static stpwrinfo pwrinfo = {PWR_STATUS_ON};
++static int otg_pwr_ctl(void *h_private, int cmd, void *p_out)
++{
++ dwc_otg_device_t *dwc_otg_device = (dwc_otg_device_t *)h_private;
++
++ switch (cmd) {
++ case PWR_CMD_OFF:
++ //printk("PWR_CMD_OFF command ==> [%d]\n", cmd);
++ if (pwrinfo.status == PWR_STATUS_OFF) {
++ return 0;
++ }
++ pwrinfo.status = PWR_STATUS_OFF;
++
++ dwc_otg_device->flagMode_backup = dwc_otg_device->flagMode;
++
++ dwc_otg_device->flagMode = 1;
++ /* wait for change mode */
++#ifdef CONFIG_LCD_7
++ bak_choosedevice = choosedevice;
++ choosedevice = 1;
++#endif
++ while (dwc_otg_device->flagID == 0) {
++ msleep_interruptible(200);
++ }
++ msleep_interruptible(200);
++
++ USBPHY_Off();
++
++ /* PWR_GP1 off.
++ * Warning: OHCI can not work
++ */
++ //tcc_pca953x_setup(PCA9538_U4_SLAVE_ADDR, PWR_GP1, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++
++ break;
++ case PWR_CMD_ON:
++ //printk("PWR_CMD_ON command ==> [%d]\n", cmd);
++ if (pwrinfo.status == PWR_STATUS_ON) {
++ return 0;
++ }
++ pwrinfo.status = PWR_STATUS_ON;
++
++ USBPHY_On();
++
++ dwc_otg_device->flagMode = 1;
++ /* wait for change mode */
++#ifdef CONFIG_LCD_7
++ choosedevice = 1;
++#endif
++ while (dwc_otg_device->flagID == 0) {
++ msleep_interruptible(200);
++ }
++ msleep_interruptible(200);
++
++ dwc_otg_device->flagMode = dwc_otg_device->flagMode_backup;
++
++#ifdef CONFIG_LCD_7
++ choosedevice = bak_choosedevice;
++#endif
++
++ break;
++ case PWR_CMD_GETSTATUS:
++ //printk("PWR_CMD_GETSTATUS command ==> [%d], status:[%d]\n", cmd, pwrinfo.status);
++ memcpy(p_out, &pwrinfo, sizeof(stpwrinfo));
++ break;
++ default:
++ //printk("unknown pwr command !!! ==> [%d]\n", cmd);
++ return -EINVAL;
++ break;
++ }
++
++ return 0;
++}
++
++static int tcc_usb_thread(void* _dwc_otg_device)
++{
++ dwc_otg_device_t *dwc_otg_device = _dwc_otg_device;
++
++ DWC_DEBUGPL(DBG_ANY, "%s starts...\n", __func__);
++
++#if defined(DWC_HOST_ONLY)
++#define IsID() ( 0 )
++#elif defined(DWC_DEVICE_ONLY)
++#define IsID() ( 1 )
++#else
++ //*********************************
++ // GPIO_A13 for ID pin
++ //*********************************
++ // Port Configuration : GPIO_A13 -> GPIO
++ BITCSET(HwGPIO->GPAFN1, (0xF/*mask*/)<<20, (0/*GPIO*/)<<20);
++ // Direction : input mode
++ BITCLR(HwGPIO->GPAEN ,Hw13);
++ // Pull UP/DOWN : pull-up only
++ BITCSET(HwGPIO->GPAPD0, 0x3/*mask*/<<26, 0x1/*pull-up only*/<<26);
++
++#if defined(DWC_SET_MODE)
++#define IsID() is_ID(dwc_otg_device->flagMode)
++#else
++#define IsID() ( HwGPIO->GPADAT & Hw13 )
++#endif
++
++#endif
++
++ //**********************************
++ // EINT0 -> USB_VBON
++ //**********************************
++ BITCSET(HwGPIO->EINTSEL0, (Hw6-Hw0), 62);
++ dwc_otg_device->flagDeviceVBUS = 0;
++#define IsUSBDET() ( HwPIC->STS0 & (1<<INT_EI0) )
++
++ dwc_otg_device->flagID = -1;
++ dwc_otg_device->flagDeviceAttach = 0;
++ while (!kthread_should_stop())
++ {
++ msleep_interruptible(200);
++
++ if ( IsID() == 0 || choosedevice == 0)
++ {
++ // ID = host mode
++ if ( dwc_otg_device->flagID != 0 )
++ {
++ dwc_otg_device->flagID = 0;
++ printk("Set ID to host mode\n");
++ DWC_DEBUGPL(DBG_ANY, "%s - ID : host mode\n", __func__);
++ USBPHY_SetID(0);
++ USBPHY_SetMode(USBPHY_MODE_HOST);
++ }
++ dwc_otg_device->flagDeviceVBUS = 0;
++ }
++ else
++ {
++ // ID = device mode
++ if ( dwc_otg_device->flagID != 1 )
++ {
++ dwc_otg_device->flagID = 1;
++ printk("Set ID to device mode\n");
++ DWC_DEBUGPL(DBG_ANY, "%s - ID : device mode\n", __func__);
++#ifndef DWC_HOST_ONLY
++ USBPHY_SetID(1);
++ msleep_interruptible(100);
++#endif
++ }
++#ifndef DWC_HOST_ONLY
++ if ( (dwc_otg_device->pcd) ? dwc_otg_device->pcd->driver : 0 )
++ {
++ if(dwc_otg_device->flagDeviceVBUS==0)
++ {
++ dwc_otg_device->flagDeviceVBUS = 1;
++ USBPHY_SetMode(USBPHY_MODE_DEVICE);
++ }
++
++ /* Send KOBJ_ONLINE/KOBJ_OFFLINE uevent */
++ if (IsUSBDET()) {
++ if (dwc_otg_device->flagDeviceAttach != 1) {
++ /* online@/devices/platform/dwc_otg.0 */
++ kobject_uevent(&dwc_otg_device->pcd->gadget.dev.parent->kobj, KOBJ_ONLINE);
++ dwc_otg_device->flagDeviceAttach = 1;
++ }
++ } else {
++ if (dwc_otg_device->flagDeviceAttach == 1) {
++ /* offline@/devices/platform/dwc_otg.0 */
++ kobject_uevent(&dwc_otg_device->pcd->gadget.dev.parent->kobj, KOBJ_OFFLINE);
++ dwc_otg_device->flagDeviceAttach = 0;
++ }
++ }
++ }
++ else
++ {
++ dwc_otg_device->flagDeviceVBUS = 0;
++ USBPHY_SetMode(USBPHY_MODE_RESET);
++ }
++#endif
++ }
++ }
++
++ DWC_DEBUGPL(DBG_ANY, "%s stopped!!!\n", __func__);
++
++ return 0;
++}
++
++/**
++ * This function is called during module intialization to verify that
++ * the module parameters are in a valid state.
++ */
++static int check_parameters(dwc_otg_core_if_t *core_if)
++{
++ int i;
++ int retval = 0;
++
++ /* Checks if the parameter is outside of its valid range of values */
++#define DWC_OTG_PARAM_TEST(_param_,_low_,_high_) \
++ ((dwc_otg_module_params._param_ < (_low_)) || \
++ (dwc_otg_module_params._param_ > (_high_)))
++
++ /* If the parameter has been set by the user, check that the parameter value is
++ * within the value range of values. If not, report a module error. */
++#define DWC_OTG_PARAM_ERR(_param_,_low_,_high_,_string_) \
++ do { \
++ if (dwc_otg_module_params._param_ != -1) { \
++ if (DWC_OTG_PARAM_TEST(_param_,(_low_),(_high_))) { \
++ DWC_ERROR("`%d' invalid for parameter `%s'\n", \
++ dwc_otg_module_params._param_, _string_); \
++ dwc_otg_module_params._param_ = dwc_param_##_param_##_default; \
++ retval ++; \
++ } \
++ } \
++ } while (0)
++
++ DWC_OTG_PARAM_ERR(opt,0,1,"opt");
++ DWC_OTG_PARAM_ERR(otg_cap,0,2,"otg_cap");
++ DWC_OTG_PARAM_ERR(dma_enable,0,1,"dma_enable");
++ DWC_OTG_PARAM_ERR(speed,0,1,"speed");
++ DWC_OTG_PARAM_ERR(host_support_fs_ls_low_power,0,1,"host_support_fs_ls_low_power");
++ DWC_OTG_PARAM_ERR(host_ls_low_power_phy_clk,0,1,"host_ls_low_power_phy_clk");
++ DWC_OTG_PARAM_ERR(enable_dynamic_fifo,0,1,"enable_dynamic_fifo");
++ DWC_OTG_PARAM_ERR(data_fifo_size,32,32768,"data_fifo_size");
++ DWC_OTG_PARAM_ERR(dev_rx_fifo_size,16,32768,"dev_rx_fifo_size");
++ DWC_OTG_PARAM_ERR(dev_nperio_tx_fifo_size,16,32768,"dev_nperio_tx_fifo_size");
++ DWC_OTG_PARAM_ERR(host_rx_fifo_size,16,32768,"host_rx_fifo_size");
++ DWC_OTG_PARAM_ERR(host_nperio_tx_fifo_size,16,32768,"host_nperio_tx_fifo_size");
++ DWC_OTG_PARAM_ERR(host_perio_tx_fifo_size,16,32768,"host_perio_tx_fifo_size");
++ DWC_OTG_PARAM_ERR(max_transfer_size,2047,524288,"max_transfer_size");
++ DWC_OTG_PARAM_ERR(max_packet_count,15,511,"max_packet_count");
++ DWC_OTG_PARAM_ERR(host_channels,1,16,"host_channels");
++ DWC_OTG_PARAM_ERR(dev_endpoints,1,15,"dev_endpoints");
++ DWC_OTG_PARAM_ERR(phy_type,0,2,"phy_type");
++ DWC_OTG_PARAM_ERR(phy_ulpi_ddr,0,1,"phy_ulpi_ddr");
++ DWC_OTG_PARAM_ERR(phy_ulpi_ext_vbus,0,1,"phy_ulpi_ext_vbus");
++ DWC_OTG_PARAM_ERR(i2c_enable,0,1,"i2c_enable");
++ DWC_OTG_PARAM_ERR(ulpi_fs_ls,0,1,"ulpi_fs_ls");
++ DWC_OTG_PARAM_ERR(ts_dline,0,1,"ts_dline");
++
++ if (dwc_otg_module_params.dma_burst_size != -1)
++ {
++ if (DWC_OTG_PARAM_TEST(dma_burst_size,1,1) &&
++ DWC_OTG_PARAM_TEST(dma_burst_size,4,4) &&
++ DWC_OTG_PARAM_TEST(dma_burst_size,8,8) &&
++ DWC_OTG_PARAM_TEST(dma_burst_size,16,16) &&
++ DWC_OTG_PARAM_TEST(dma_burst_size,32,32) &&
++ DWC_OTG_PARAM_TEST(dma_burst_size,64,64) &&
++ DWC_OTG_PARAM_TEST(dma_burst_size,128,128) &&
++ DWC_OTG_PARAM_TEST(dma_burst_size,256,256))
++ {
++ DWC_ERROR("`%d' invalid for parameter `dma_burst_size'\n",
++ dwc_otg_module_params.dma_burst_size);
++ dwc_otg_module_params.dma_burst_size = 32;
++ retval ++;
++ }
++ }
++
++ if (dwc_otg_module_params.phy_utmi_width != -1)
++ {
++ if (DWC_OTG_PARAM_TEST(phy_utmi_width,8,8) &&
++ DWC_OTG_PARAM_TEST(phy_utmi_width,16,16))
++ {
++ DWC_ERROR("`%d' invalid for parameter `phy_utmi_width'\n",
++ dwc_otg_module_params.phy_utmi_width);
++ dwc_otg_module_params.phy_utmi_width = 16;
++ retval ++;
++ }
++ }
++
++ for (i=0; i<15; i++)
++ {
++ /** @todo should be like above */
++ //DWC_OTG_PARAM_ERR(dev_perio_tx_fifo_size[i],4,768,"dev_perio_tx_fifo_size");
++ if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1)
++ {
++ if (DWC_OTG_PARAM_TEST(dev_perio_tx_fifo_size[i],4,768))
++ {
++ DWC_ERROR("`%d' invalid for parameter `%s_%d'\n",
++ dwc_otg_module_params.dev_perio_tx_fifo_size[i], "dev_perio_tx_fifo_size", i);
++ dwc_otg_module_params.dev_perio_tx_fifo_size[i] = dwc_param_dev_perio_tx_fifo_size_default;
++ retval ++;
++ }
++ }
++ }
++
++ DWC_OTG_PARAM_ERR(en_multiple_tx_fifo,0,1,"en_multiple_tx_fifo");
++
++ for (i=0; i<15; i++)
++ {
++ /** @todo should be like above */
++ //DWC_OTG_PARAM_ERR(dev_tx_fifo_size[i],4,768,"dev_tx_fifo_size");
++ if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1)
++ {
++ if (DWC_OTG_PARAM_TEST(dev_tx_fifo_size[i],4,768))
++ {
++ DWC_ERROR("`%d' invalid for parameter `%s_%d'\n",
++ dwc_otg_module_params.dev_tx_fifo_size[i], "dev_tx_fifo_size", i);
++ dwc_otg_module_params.dev_tx_fifo_size[i] = dwc_param_dev_tx_fifo_size_default;
++ retval ++;
++ }
++ }
++ }
++
++ DWC_OTG_PARAM_ERR(thr_ctl, 0, 7, "thr_ctl");
++ DWC_OTG_PARAM_ERR(tx_thr_length, 8, 128, "tx_thr_length");
++ DWC_OTG_PARAM_ERR(rx_thr_length, 8, 128, "rx_thr_length");
++
++
++ /* At this point, all module parameters that have been set by the user
++ * are valid, and those that have not are left unset. Now set their
++ * default values and/or check the parameters against the hardware
++ * configurations of the OTG core. */
++
++
++
++ /* This sets the parameter to the default value if it has not been set by the
++ * user */
++#define DWC_OTG_PARAM_SET_DEFAULT(_param_) \
++ ({ \
++ int changed = 1; \
++ if (dwc_otg_module_params._param_ == -1) { \
++ changed = 0; \
++ dwc_otg_module_params._param_ = dwc_param_##_param_##_default; \
++ } \
++ changed; \
++ })
++
++ /* This checks the macro agains the hardware configuration to see if it is
++ * valid. It is possible that the default value could be invalid. In this
++ * case, it will report a module error if the user touched the parameter.
++ * Otherwise it will adjust the value without any error. */
++#define DWC_OTG_PARAM_CHECK_VALID(_param_,_str_,_is_valid_,_set_valid_) \
++ ({ \
++ int changed = DWC_OTG_PARAM_SET_DEFAULT(_param_); \
++ int error = 0; \
++ if (!(_is_valid_)) { \
++ if (changed) { \
++ DWC_ERROR("`%d' invalid for parameter `%s'. Check HW configuration.\n", dwc_otg_module_params._param_,_str_); \
++ error = 1; \
++ } \
++ dwc_otg_module_params._param_ = (_set_valid_); \
++ } \
++ error; \
++ })
++
++ /* OTG Cap */
++ retval += DWC_OTG_PARAM_CHECK_VALID(otg_cap,"otg_cap",
++ ( {
++ int valid;
++ valid = 1;
++ switch (dwc_otg_module_params.otg_cap) {
++ case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE:
++ if (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) valid = 0;
++ break;
++ case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE:
++ if ((core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) &&
++ (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) &&
++ (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) &&
++ (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST))
++ {
++ valid = 0;
++ }
++ break;
++ case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE:
++ /* always valid */
++ break;
++ }
++ valid;
++ }),
++ (((core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) ||
++ (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) ||
++ (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) ||
++ (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ?
++ DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE :
++ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE));
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(dma_enable,"dma_enable",
++ ((dwc_otg_module_params.dma_enable == 1) && (core_if->hwcfg2.b.architecture == 0)) ? 0 : 1,
++ 0);
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(opt,"opt",
++ 1,
++ 0);
++
++ DWC_OTG_PARAM_SET_DEFAULT(dma_burst_size);
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(host_support_fs_ls_low_power,
++ "host_support_fs_ls_low_power",
++ 1, 0);
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(enable_dynamic_fifo,
++ "enable_dynamic_fifo",
++ ((dwc_otg_module_params.enable_dynamic_fifo == 0) ||
++ (core_if->hwcfg2.b.dynamic_fifo == 1)), 0);
++
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(data_fifo_size,
++ "data_fifo_size",
++ (dwc_otg_module_params.data_fifo_size <= 4160/*core_if->hwcfg3.b.dfifo_depth*/),
++ 4160/*core_if->hwcfg3.b.dfifo_depth*/);
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(dev_rx_fifo_size,
++ "dev_rx_fifo_size",
++ (dwc_otg_module_params.dev_rx_fifo_size <= dwc_read_reg32(&core_if->core_global_regs->grxfsiz)),
++ dwc_read_reg32(&core_if->core_global_regs->grxfsiz));
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(dev_nperio_tx_fifo_size,
++ "dev_nperio_tx_fifo_size",
++ (dwc_otg_module_params.dev_nperio_tx_fifo_size <= (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)),
++ (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16));
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(host_rx_fifo_size,
++ "host_rx_fifo_size",
++ (dwc_otg_module_params.host_rx_fifo_size <= dwc_read_reg32(&core_if->core_global_regs->grxfsiz)),
++ dwc_read_reg32(&core_if->core_global_regs->grxfsiz));
++
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(host_nperio_tx_fifo_size,
++ "host_nperio_tx_fifo_size",
++ (dwc_otg_module_params.host_nperio_tx_fifo_size <= (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)),
++ (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16));
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(host_perio_tx_fifo_size,
++ "host_perio_tx_fifo_size",
++ (dwc_otg_module_params.host_perio_tx_fifo_size <= ((dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16))),
++ ((dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16)));
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(max_transfer_size,
++ "max_transfer_size",
++ (dwc_otg_module_params.max_transfer_size < (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))),
++ ((1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1));
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(max_packet_count,
++ "max_packet_count",
++ (dwc_otg_module_params.max_packet_count < (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))),
++ ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1));
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(host_channels,
++ "host_channels",
++ (dwc_otg_module_params.host_channels <= (core_if->hwcfg2.b.num_host_chan + 1)),
++ (core_if->hwcfg2.b.num_host_chan + 1));
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(dev_endpoints,
++ "dev_endpoints",
++ (dwc_otg_module_params.dev_endpoints <= (core_if->hwcfg2.b.num_dev_ep)),
++ core_if->hwcfg2.b.num_dev_ep);
++
++ /*
++ * Define the following to disable the FS PHY Hardware checking. This is for
++ * internal testing only.
++ *
++ * #define NO_FS_PHY_HW_CHECKS
++ */
++
++#ifdef NO_FS_PHY_HW_CHECKS
++ retval += DWC_OTG_PARAM_CHECK_VALID(phy_type,
++ "phy_type", 1, 0);
++#else
++ retval += DWC_OTG_PARAM_CHECK_VALID(phy_type,
++ "phy_type",
++ ( {
++ int valid = 0;
++ if ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_UTMI) &&
++ ((core_if->hwcfg2.b.hs_phy_type == 1) ||
++ (core_if->hwcfg2.b.hs_phy_type == 3)))
++ {
++ valid = 1;
++ }
++ else if ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_ULPI) &&
++ ((core_if->hwcfg2.b.hs_phy_type == 2) ||
++ (core_if->hwcfg2.b.hs_phy_type == 3)))
++ {
++ valid = 1;
++ }
++ else if ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) &&
++ (core_if->hwcfg2.b.fs_phy_type == 1))
++ {
++ valid = 1;
++ }
++ valid;
++ }),
++ ( {
++ int set = DWC_PHY_TYPE_PARAM_FS;
++ if (core_if->hwcfg2.b.hs_phy_type) {
++ if ((core_if->hwcfg2.b.hs_phy_type == 3) ||
++ (core_if->hwcfg2.b.hs_phy_type == 1)) {
++ set = DWC_PHY_TYPE_PARAM_UTMI;
++ }
++ else {
++ set = DWC_PHY_TYPE_PARAM_ULPI;
++ }
++ }
++ set;
++ }));
++#endif
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(speed,"speed",
++ (dwc_otg_module_params.speed == 0) && (dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) ? 0 : 1,
++ dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS ? 1 : 0);
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(host_ls_low_power_phy_clk,
++ "host_ls_low_power_phy_clk",
++ ((dwc_otg_module_params.host_ls_low_power_phy_clk == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ) && (dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) ? 0 : 1),
++ ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) ? DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ : DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ));
++
++ DWC_OTG_PARAM_SET_DEFAULT(phy_ulpi_ddr);
++ DWC_OTG_PARAM_SET_DEFAULT(phy_ulpi_ext_vbus);
++ DWC_OTG_PARAM_SET_DEFAULT(phy_utmi_width);
++ DWC_OTG_PARAM_SET_DEFAULT(ulpi_fs_ls);
++ DWC_OTG_PARAM_SET_DEFAULT(ts_dline);
++
++#ifdef NO_FS_PHY_HW_CHECKS
++ retval += DWC_OTG_PARAM_CHECK_VALID(i2c_enable,
++ "i2c_enable", 1, 0);
++#else
++ retval += DWC_OTG_PARAM_CHECK_VALID(i2c_enable,
++ "i2c_enable",
++ (dwc_otg_module_params.i2c_enable == 1) && (core_if->hwcfg3.b.i2c == 0) ? 0 : 1,
++ 0);
++#endif
++
++ for (i=0; i<15; i++)
++ {
++ //int changed = 1;
++ //int error = 0;
++
++ if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] == -1)
++ {
++ //changed = 0;
++ dwc_otg_module_params.dev_perio_tx_fifo_size[i] = dwc_param_dev_perio_tx_fifo_size_default;
++ }
++ //AlenOh
++ //if (!(dwc_otg_module_params.dev_perio_tx_fifo_size[i] <= (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i]))))
++ //{
++ // if (changed)
++ // {
++ // DWC_ERROR("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n", dwc_otg_module_params.dev_perio_tx_fifo_size[i],i);
++ // error = 1;
++ // }
++ // dwc_otg_module_params.dev_perio_tx_fifo_size[i] = dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i]);
++ //}
++ //retval += error;
++ }
++
++ retval += DWC_OTG_PARAM_CHECK_VALID(en_multiple_tx_fifo,"en_multiple_tx_fifo",
++ ((dwc_otg_module_params.en_multiple_tx_fifo == 1) && (core_if->hwcfg4.b.ded_fifo_en == 0)) ? 0 : 1,
++ 0);
++
++ for (i=0; i<15; i++)
++ {
++ //int changed = 1;
++ //int error = 0;
++
++ if (dwc_otg_module_params.dev_tx_fifo_size[i] == -1)
++ {
++ //changed = 0;
++ dwc_otg_module_params.dev_tx_fifo_size[i] = dwc_param_dev_tx_fifo_size_default;
++ }
++ //AlenOh
++ //if (!(dwc_otg_module_params.dev_tx_fifo_size[i] <= (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i]))))
++ //{
++ // if (changed)
++ // {
++ // DWC_ERROR("%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n", dwc_otg_module_params.dev_tx_fifo_size[i],i);
++ // error = 1;
++ // }
++ // dwc_otg_module_params.dev_tx_fifo_size[i] = dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i]);
++ //}
++ //retval += error;
++ }
++
++ DWC_OTG_PARAM_SET_DEFAULT(thr_ctl);
++ DWC_OTG_PARAM_SET_DEFAULT(tx_thr_length);
++ DWC_OTG_PARAM_SET_DEFAULT(rx_thr_length);
++
++ return retval;
++}
++
++/**
++ * This function is the top level interrupt handler for the Common
++ * (Device and host modes) interrupts.
++ */
++static irqreturn_t dwc_otg_common_irq(int _irq, void *_dev)
++{
++ dwc_otg_device_t *otg_dev = _dev;
++ int32_t retval = IRQ_NONE;
++
++ retval = dwc_otg_handle_common_intr( otg_dev->core_if );
++ return IRQ_RETVAL(retval);
++}
++
++/**
++ * This function is called when a lm_device is unregistered with the
++ * dwc_otg_driver. This happens, for example, when the rmmod command is
++ * executed. The device may or may not be electrically present. If it is
++ * present, the driver stops device processing. Any resources used on behalf
++ * of this device are freed.
++ *
++ * @param[in] _lmdev
++ */
++static int dwc_otg_driver_remove(struct platform_device *pdev)
++{
++ dwc_otg_device_t *otg_dev = platform_get_otgdata(pdev);
++ DWC_DEBUGPL(DBG_ANY, "%s(%p)\n", __func__, pdev);
++
++ if (otg_dev == NULL)
++ {
++ /* Memory allocation for the dwc_otg_device failed. */
++ return 0;
++ }
++
++ /* remove power control functions */
++ remove_pwm_node(DEVICE_OTG);
++
++ if (!IS_ERR(otg_dev->vbus_usb_task)) {
++ printk("vbus_usb_task stops...\n");
++ kthread_stop(otg_dev->vbus_usb_task);
++ }
++
++ /* flush work_queue */
++ flush_scheduled_work();
++ cancel_work_sync(&otg_dev->core_if->vbus_work);
++ otg_dev->core_if->vbus_state = -1;
++
++ /*
++ * Free the IRQ
++ */
++ if (otg_dev->common_irq_installed)
++ {
++ free_irq(ARM_VP_OTG_INTR, otg_dev);
++ }
++
++#ifndef DWC_DEVICE_ONLY
++ if (otg_dev->hcd != NULL)
++ {
++ dwc_otg_hcd_remove(pdev);
++ }
++#endif
++
++#ifndef DWC_HOST_ONLY
++ if (otg_dev->pcd != NULL)
++ {
++ dwc_otg_pcd_remove(pdev);
++ }
++#endif
++ if (otg_dev->core_if != NULL)
++ {
++ dwc_otg_cil_remove(otg_dev->core_if);
++ }
++
++ /*
++ * Remove the device attributes
++ */
++#ifdef _USE_ATTR_
++ dwc_otg_attr_remove(pdev);
++#endif
++#ifdef DWC_SET_MODE
++ device_remove_file(&pdev->dev, &dev_attr_setmode);
++ device_remove_file(&pdev->dev, &dev_attr_fsg);
++#endif
++
++ /*
++ * Return the memory.
++ */
++ if (otg_dev->base != NULL)
++ {
++ //iounmap(otg_dev->base);
++ }
++ kfree(otg_dev);
++
++ /*
++ * Clear the drvdata pointer.
++ */
++ platform_set_otgdata(pdev, NULL);
++
++ return 0;
++}
++
++/**
++ * This function is called when an lm_device is bound to a
++ * dwc_otg_driver. It creates the driver components required to
++ * control the device (CIL, HCD, and PCD) and it initializes the
++ * device. The driver components are stored in a dwc_otg_device
++ * structure. A reference to the dwc_otg_device is saved in the
++ * lm_device. This allows the driver to access the dwc_otg_device
++ * structure on subsequent calls to driver methods for this device.
++ *
++ * @param[in] _lmdev lm_device definition
++ */
++static int dwc_otg_driver_probe(struct platform_device *pdev)
++{
++ int retval = 0;
++ dwc_otg_device_t *dwc_otg_device;
++ int32_t snpsid;
++
++ printk(KERN_DEBUG "dwc_otg_driver_probe(%p)\n", pdev);
++
++ dwc_otg_device = kmalloc(sizeof(dwc_otg_device_t), GFP_KERNEL);
++
++ if (dwc_otg_device == 0)
++ {
++ printk(KERN_ERR "kmalloc of dwc_otg_device failed\n");
++ retval = -ENOMEM;
++ goto fail;
++ }
++
++ memset(dwc_otg_device, 0, sizeof(*dwc_otg_device));
++ dwc_otg_device->reg_offset = 0xFFFFFFFF;
++ dwc_otg_device->vbus_usb_task = (struct task_struct *)(-EINVAL);
++
++ /*
++ * Map the DWC_otg Core memory into virtual address space.
++ */
++ //dwc_otg_device->base = ioremap(VERSATILE_LT_BASE, SZ_256K);
++ //dwc_otg_device->base = (void *)tcc_p2v(HwUSB20OTG_BASE);
++ dwc_otg_device->base = (void *)0xF0550000;
++
++ if (dwc_otg_device->base == NULL)
++ {
++ printk(KERN_ERR "ioremap() failed\n");
++ retval = -ENOMEM;
++ goto fail;
++ }
++ printk(KERN_DEBUG "base=0x%08x\n", (unsigned)dwc_otg_device->base);
++
++ /*
++ * Attempt to ensure this device is really a DWC_otg Controller.
++ * Read and verify the SNPSID register contents. The value should be
++ * 0x45F42XXX, which corresponds to "OT2", as in "OTG version 2.XX".
++ */
++ snpsid = dwc_read_reg32((uint32_t *)((uint8_t *)dwc_otg_device->base + 0x40));
++
++ if ((snpsid & 0xFFFFF000) != 0x4F542000)
++ {
++ printk(KERN_ERR "Bad value for SNPSID: 0x%08x\n", snpsid);
++ retval = -EINVAL;
++ goto fail;
++ }
++
++ /*
++ * Initialize driver data to point to the global DWC_otg
++ * Device structure.
++ */
++ platform_set_otgdata(pdev, dwc_otg_device);
++ printk(KERN_DEBUG "dwc_otg_device=0x%p\n", dwc_otg_device);
++
++ dwc_otg_device->core_if = dwc_otg_cil_init( dwc_otg_device->base,
++ &dwc_otg_module_params);
++ if (dwc_otg_device->core_if == 0)
++ {
++ printk(KERN_ERR "CIL initialization failed!\n");
++ retval = -ENOMEM;
++ goto fail;
++ }
++
++ /*
++ * Validate parameter values.
++ */
++ if (check_parameters(dwc_otg_device->core_if) != 0)
++ {
++ retval = -EINVAL;
++ goto fail;
++ }
++
++ /*
++ * Create Device Attributes in sysfs
++ */
++#ifdef _USE_ATTR_
++ dwc_otg_attr_create (pdev);
++#endif
++#ifdef DWC_SET_MODE
++ device_create_file(&pdev->dev, &dev_attr_setmode);
++ dwc_otg_device->flagMode = 2;
++ device_create_file(&pdev->dev, &dev_attr_fsg);
++ dwc_otg_device->flagDeviceAttach = 0;
++#endif
++
++ INIT_WORK(&dwc_otg_device->core_if->vbus_work, tcc_vbus_work);
++
++ /*
++ * Disable the global interrupt until all the interrupt
++ * handlers are installed.
++ */
++ dwc_otg_disable_global_interrupts( dwc_otg_device->core_if );
++ /*
++ * Install the interrupt handler for the common interrupts before
++ * enabling common interrupts in core_init below.
++ */
++ DWC_DEBUGPL( DBG_CIL, "registering (common) handler for irq%d\n",
++ ARM_VP_OTG_INTR);
++ retval = request_irq(ARM_VP_OTG_INTR, dwc_otg_common_irq,
++ IRQF_SHARED, "dwc_otg", dwc_otg_device );
++ if (retval != 0)
++ {
++ DWC_ERROR("request of irq%d failed\n",ARM_VP_OTG_INTR);
++ retval = -EBUSY;
++ goto fail;
++ }
++ else
++ {
++ dwc_otg_device->common_irq_installed = 1;
++ }
++
++ /*
++ * Initialize the DWC_otg core.
++ */
++ tca_ckc_setiobus(RB_USB20OTG, ENABLE); // Turn on the USB clock from IO BUS
++ TCC_DVBUS_Control(0);
++ USBPHY_SetMode(USBPHY_MODE_RESET);
++#ifdef DWC_DEVICE_ONLY
++ USBPHY_SetID(1); // device
++#else
++ USBPHY_SetID(0); // host for dwc_otg_hcd_init
++#endif
++ tcc_usb_link_reset(); //Reset OTG LINK - AlenOh
++ dwc_otg_core_init(dwc_otg_device->core_if);
++
++ mdelay(5); //TODO: remove delay...
++
++#ifndef DWC_HOST_ONLY
++ /*
++ * Initialize the PCD
++ */
++ retval = dwc_otg_pcd_init(pdev);
++ if (retval != 0)
++ {
++ DWC_ERROR("dwc_otg_pcd_init failed\n");
++ dwc_otg_device->pcd = NULL;
++ goto fail;
++ }
++#endif
++#ifndef DWC_DEVICE_ONLY
++ /*
++ * Initialize the HCD
++ */
++ //TCC_DVBUS_Control(1);
++ //USBPHY_SetID(0);
++ //USBPHY_SetMode(USBPHY_MODE_HOST);
++ retval = dwc_otg_hcd_init(pdev);
++ if (retval != 0)
++ {
++ DWC_ERROR("dwc_otg_hcd_init failed\n");
++ dwc_otg_device->hcd = NULL;
++ goto fail;
++ }
++#endif
++
++ dwc_otg_device->vbus_usb_task = kthread_create(tcc_usb_thread, dwc_otg_device,"tcc-usb-thread");
++ if (IS_ERR(dwc_otg_device->vbus_usb_task)) {
++ printk("\nPTR ERR %p", dwc_otg_device->vbus_usb_task);
++ return -EINVAL;
++ }
++
++ /* Tell the thread to start working */
++ wake_up_process(dwc_otg_device->vbus_usb_task);
++
++ /*
++ * Enable the global interrupt after all the interrupt
++ * handlers are installed.
++ */
++ dwc_otg_enable_global_interrupts( dwc_otg_device->core_if );
++
++ /* add power control functions */
++ insert_pwm_node(DEVICE_OTG, otg_pwr_ctl, dwc_otg_device);
++
++#if defined (CONFIG_LCD_7)
++ /* OTG power on */
++ set_usb_syspwr_en(1);
++ set_usb_otgdrv_en(1);
++#endif
++ return 0;
++
++fail:
++ dwc_otg_driver_remove(pdev);
++ return retval;
++}
++
++#ifdef CONFIG_PM
++static int dwc_otg_driver_suspend(struct platform_device *pdev, pm_message_t state)
++{
++#if 0
++ //dwc_otg_device_t *dwc_otg_device = platform_get_otgdata(pdev);
++
++ ///* mode change & wait */
++ //dwc_otg_device->flagMode_backup = dwc_otg_device->flagMode;
++ //dwc_otg_device->flagMode = 1;
++ //while (dwc_otg_device->flagID == 0) {
++ // msleep_interruptible(200);
++ //}
++ //msleep_interruptible(200);
++ //
++ //USBPHY_Off();
++
++ dwc_otg_driver_remove(pdev);
++#else
++ dwc_otg_device_t *dwc_otg_device = platform_get_otgdata(pdev);
++
++ /* device mode change & wait */
++ dwc_otg_device->flagMode_backup = dwc_otg_device->flagMode;
++ dwc_otg_device->flagMode = 1;
++#ifdef CONFIG_LCD_7
++ bak_choosedevice = choosedevice;
++ choosedevice = 1;
++#endif
++ while (dwc_otg_device->flagID == 0) {
++ msleep_interruptible(200);
++ }
++ msleep_interruptible(200);
++
++ USBPHY_Off();
++#endif
++
++ return 0;
++}
++
++static int dwc_otg_driver_resume(struct platform_device *pdev)
++{
++#if 0
++ dwc_otg_driver_probe(pdev);
++#else
++ dwc_otg_device_t *dwc_otg_device = platform_get_otgdata(pdev);
++
++ USBPHY_On();
++
++ /* device mode change & wait */
++ dwc_otg_device->flagMode = 1;
++#ifdef CONFIG_LCD_7
++ choosedevice = 1;
++#endif
++ while (dwc_otg_device->flagID == 0) {
++ msleep_interruptible(200);
++ }
++ msleep_interruptible(200);
++
++ /* resotre mode */
++ dwc_otg_device->flagMode = dwc_otg_device->flagMode_backup;
++#endif
++
++#ifdef CONFIG_LCD_7
++ choosedevice = bak_choosedevice;
++#endif
++
++ return 0;
++}
++#else
++#define dwc_otg_driver_suspend NULL
++#define dwc_otg_driver_resume NULL
++#endif
++
++/**
++ * This structure defines the methods to be called by a bus driver
++ * during the lifecycle of a device on that bus. Both drivers and
++ * devices are registered with a bus driver. The bus driver matches
++ * devices to drivers based on information in the device and driver
++ * structures.
++ *
++ * The probe function is called when the bus driver matches a device
++ * to this driver. The remove function is called when a device is
++ * unregistered with the bus driver.
++ */
++static struct platform_driver dwc_otg_driver = {
++ .probe = dwc_otg_driver_probe,
++ .remove = dwc_otg_driver_remove,
++ .suspend = dwc_otg_driver_suspend,
++ .resume = dwc_otg_driver_resume,
++ .driver = {
++ .name = dwc_driver_name,
++ .owner = THIS_MODULE,
++ },
++};
++
++
++/**
++ * This function is called when the dwc_otg_driver is installed with the
++ * insmod command. It registers the dwc_otg_driver structure with the
++ * appropriate bus driver. This will cause the dwc_otg_driver_probe function
++ * to be called. In addition, the bus driver will automatically expose
++ * attributes defined for the device and driver in the special sysfs file
++ * system.
++ *
++ * @return
++ */
++static int __init dwc_otg_driver_init(void)
++{
++ int retval = 0;
++
++ printk(KERN_INFO "%s: version %s\n", dwc_driver_name, DWC_DRIVER_VERSION);
++ retval = platform_driver_register(&dwc_otg_driver);
++ if (retval < 0) {
++ printk(KERN_ERR "%s retval=%d\n", __func__, retval);
++ return retval;
++ }
++ driver_create_file(&dwc_otg_driver.driver, &driver_attr_version);
++ driver_create_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
++ driver_create_file(&dwc_otg_driver.driver, &driver_attr_hvbus);
++
++ return retval;
++}
++module_init(dwc_otg_driver_init);
++
++/**
++ * This function is called when the driver is removed from the kernel
++ * with the rmmod command. The driver unregisters itself with its bus
++ * driver.
++ *
++ */
++static void __exit dwc_otg_driver_cleanup(void)
++{
++ printk(KERN_DEBUG "dwc_otg_driver_cleanup()\n");
++
++ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
++ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
++ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_hvbus);
++
++ /* remove power control functions */
++ remove_pwm_node(DEVICE_OTG);
++
++ platform_driver_unregister(&dwc_otg_driver);
++
++ printk(KERN_INFO "%s module removed\n", dwc_driver_name);
++}
++module_exit(dwc_otg_driver_cleanup);
++
++MODULE_DESCRIPTION(DWC_DRIVER_DESC);
++MODULE_AUTHOR("Synopsys Inc.");
++MODULE_LICENSE("GPL");
++
++module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444);
++MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None");
++module_param_named(opt, dwc_otg_module_params.opt, int, 0444);
++MODULE_PARM_DESC(opt, "OPT Mode");
++module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444);
++MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled");
++module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int, 0444);
++MODULE_PARM_DESC(dma_burst_size, "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256");
++module_param_named(speed, dwc_otg_module_params.speed, int, 0444);
++MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed");
++module_param_named(host_support_fs_ls_low_power, dwc_otg_module_params.host_support_fs_ls_low_power, int, 0444);
++MODULE_PARM_DESC(host_support_fs_ls_low_power, "Support Low Power w/FS or LS 0=Support 1=Don't Support");
++module_param_named(host_ls_low_power_phy_clk, dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444);
++MODULE_PARM_DESC(host_ls_low_power_phy_clk, "Low Speed Low Power Clock 0=48Mhz 1=6Mhz");
++module_param_named(enable_dynamic_fifo, dwc_otg_module_params.enable_dynamic_fifo, int, 0444);
++MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing");
++module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int, 0444);
++MODULE_PARM_DESC(data_fifo_size, "Total number of words in the data FIFO memory 32-32768");
++module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size, int, 0444);
++MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
++module_param_named(dev_nperio_tx_fifo_size, dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444);
++MODULE_PARM_DESC(dev_nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768");
++module_param_named(dev_perio_tx_fifo_size_1, dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_1, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(dev_perio_tx_fifo_size_2, dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_2, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(dev_perio_tx_fifo_size_3, dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_3, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(dev_perio_tx_fifo_size_4, dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_4, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(dev_perio_tx_fifo_size_5, dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_5, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(dev_perio_tx_fifo_size_6, dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_6, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(dev_perio_tx_fifo_size_7, dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_7, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(dev_perio_tx_fifo_size_8, dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_8, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(dev_perio_tx_fifo_size_9, dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_9, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(dev_perio_tx_fifo_size_10, dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_10, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(dev_perio_tx_fifo_size_11, dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_11, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(dev_perio_tx_fifo_size_12, dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_12, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(dev_perio_tx_fifo_size_13, dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_13, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(dev_perio_tx_fifo_size_14, dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_14, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(dev_perio_tx_fifo_size_15, dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444);
++MODULE_PARM_DESC(dev_perio_tx_fifo_size_15, "Number of words in the periodic Tx FIFO 4-768");
++module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size, int, 0444);
++MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
++module_param_named(host_nperio_tx_fifo_size, dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444);
++MODULE_PARM_DESC(host_nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768");
++module_param_named(host_perio_tx_fifo_size, dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444);
++MODULE_PARM_DESC(host_perio_tx_fifo_size, "Number of words in the host periodic Tx FIFO 16-32768");
++module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size, int, 0444);
++/** @todo Set the max to 512K, modify checks */
++MODULE_PARM_DESC(max_transfer_size, "The maximum transfer size supported in bytes 2047-65535");
++module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count, int, 0444);
++MODULE_PARM_DESC(max_packet_count, "The maximum number of packets in a transfer 15-511");
++module_param_named(host_channels, dwc_otg_module_params.host_channels, int, 0444);
++MODULE_PARM_DESC(host_channels, "The number of host channel registers to use 1-16");
++module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int, 0444);
++MODULE_PARM_DESC(dev_endpoints, "The number of endpoints in addition to EP0 available for device mode 1-15");
++module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444);
++MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI");
++module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int, 0444);
++MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits");
++module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444);
++MODULE_PARM_DESC(phy_ulpi_ddr, "ULPI at double or single data rate 0=Single 1=Double");
++module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus, int, 0444);
++MODULE_PARM_DESC(phy_ulpi_ext_vbus, "ULPI PHY using internal or external vbus 0=Internal");
++module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444);
++MODULE_PARM_DESC(i2c_enable, "FS PHY Interface");
++module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444);
++MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only");
++module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444);
++MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs");
++module_param_named(debug, g_dbg_lvl, int, 0444);
++MODULE_PARM_DESC(debug, "");
++
++module_param_named(en_multiple_tx_fifo, dwc_otg_module_params.en_multiple_tx_fifo, int, 0444);
++MODULE_PARM_DESC(en_multiple_tx_fifo, "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled");
++module_param_named(dev_tx_fifo_size_1, dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768");
++module_param_named(dev_tx_fifo_size_2, dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768");
++module_param_named(dev_tx_fifo_size_3, dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768");
++module_param_named(dev_tx_fifo_size_4, dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768");
++module_param_named(dev_tx_fifo_size_5, dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768");
++module_param_named(dev_tx_fifo_size_6, dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768");
++module_param_named(dev_tx_fifo_size_7, dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768");
++module_param_named(dev_tx_fifo_size_8, dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768");
++module_param_named(dev_tx_fifo_size_9, dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768");
++module_param_named(dev_tx_fifo_size_10, dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768");
++module_param_named(dev_tx_fifo_size_11, dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768");
++module_param_named(dev_tx_fifo_size_12, dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768");
++module_param_named(dev_tx_fifo_size_13, dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768");
++module_param_named(dev_tx_fifo_size_14, dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768");
++module_param_named(dev_tx_fifo_size_15, dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444);
++MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768");
++
++module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444);
++MODULE_PARM_DESC(thr_ctl, "Thresholding enable flag bit 0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled");
++module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int, 0444);
++MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs");
++module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int, 0444);
++MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs");
++/** @page "Module Parameters"
++ *
++ * The following parameters may be specified when starting the module.
++ * These parameters define how the DWC_otg controller should be
++ * configured. Parameter values are passed to the CIL initialization
++ * function dwc_otg_cil_init
++ *
++ * Example: <code>modprobe dwc_otg speed=1 otg_cap=1</code>
++ *
++
++ <table>
++ <tr><td>Parameter Name</td><td>Meaning</td></tr>
++
++ <tr>
++ <td>otg_cap</td>
++ <td>Specifies the OTG capabilities. The driver will automatically detect the
++ value for this parameter if none is specified.
++ - 0: HNP and SRP capable (default, if available)
++ - 1: SRP Only capable
++ - 2: No HNP/SRP capable
++ </td></tr>
++
++ <tr>
++ <td>dma_enable</td>
++ <td>Specifies whether to use slave or DMA mode for accessing the data FIFOs.
++ The driver will automatically detect the value for this parameter if none is
++ specified.
++ - 0: Slave
++ - 1: DMA (default, if available)
++ </td></tr>
++
++ <tr>
++ <td>dma_burst_size</td>
++ <td>The DMA Burst size (applicable only for External DMA Mode).
++ - Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32)
++ </td></tr>
++
++ <tr>
++ <td>speed</td>
++ <td>Specifies the maximum speed of operation in host and device mode. The
++ actual speed depends on the speed of the attached device and the value of
++ phy_type.
++ - 0: High Speed (default)
++ - 1: Full Speed
++ </td></tr>
++
++ <tr>
++ <td>host_support_fs_ls_low_power</td>
++ <td>Specifies whether low power mode is supported when attached to a Full
++ Speed or Low Speed device in host mode.
++ - 0: Don't support low power mode (default)
++ - 1: Support low power mode
++ </td></tr>
++
++ <tr>
++ <td>host_ls_low_power_phy_clk</td>
++ <td>Specifies the PHY clock rate in low power mode when connected to a Low
++ Speed device in host mode. This parameter is applicable only if
++ HOST_SUPPORT_FS_LS_LOW_POWER is enabled.
++ - 0: 48 MHz (default)
++ - 1: 6 MHz
++ </td></tr>
++
++ <tr>
++ <td>enable_dynamic_fifo</td>
++ <td> Specifies whether FIFOs may be resized by the driver software.
++ - 0: Use cC FIFO size parameters
++ - 1: Allow dynamic FIFO sizing (default)
++ </td></tr>
++
++ <tr>
++ <td>data_fifo_size</td>
++ <td>Total number of 4-byte words in the data FIFO memory. This memory
++ includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs.
++ - Values: 32 to 32768 (default 8192)
++
++ Note: The total FIFO memory depth in the FPGA configuration is 8192.
++ </td></tr>
++
++ <tr>
++ <td>dev_rx_fifo_size</td>
++ <td>Number of 4-byte words in the Rx FIFO in device mode when dynamic
++ FIFO sizing is enabled.
++ - Values: 16 to 32768 (default 1064)
++ </td></tr>
++
++ <tr>
++ <td>dev_nperio_tx_fifo_size</td>
++ <td>Number of 4-byte words in the non-periodic Tx FIFO in device mode when
++ dynamic FIFO sizing is enabled.
++ - Values: 16 to 32768 (default 1024)
++ </td></tr>
++
++ <tr>
++ <td>dev_perio_tx_fifo_size_n (n = 1 to 15)</td>
++ <td>Number of 4-byte words in each of the periodic Tx FIFOs in device mode
++ when dynamic FIFO sizing is enabled.
++ - Values: 4 to 768 (default 256)
++ </td></tr>
++
++ <tr>
++ <td>host_rx_fifo_size</td>
++ <td>Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO
++ sizing is enabled.
++ - Values: 16 to 32768 (default 1024)
++ </td></tr>
++
++ <tr>
++ <td>host_nperio_tx_fifo_size</td>
++ <td>Number of 4-byte words in the non-periodic Tx FIFO in host mode when
++ dynamic FIFO sizing is enabled in the core.
++ - Values: 16 to 32768 (default 1024)
++ </td></tr>
++
++ <tr>
++ <td>host_perio_tx_fifo_size</td>
++ <td>Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO
++ sizing is enabled.
++ - Values: 16 to 32768 (default 1024)
++ </td></tr>
++
++ <tr>
++ <td>max_transfer_size</td>
++ <td>The maximum transfer size supported in bytes.
++ - Values: 2047 to 65,535 (default 65,535)
++ </td></tr>
++
++ <tr>
++ <td>max_packet_count</td>
++ <td>The maximum number of packets in a transfer.
++ - Values: 15 to 511 (default 511)
++ </td></tr>
++
++ <tr>
++ <td>host_channels</td>
++ <td>The number of host channel registers to use.
++ - Values: 1 to 16 (default 12)
++
++ Note: The FPGA configuration supports a maximum of 12 host channels.
++ </td></tr>
++
++ <tr>
++ <td>dev_endpoints</td>
++ <td>The number of endpoints in addition to EP0 available for device mode
++ operations.
++ - Values: 1 to 15 (default 6 IN and OUT)
++
++ Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in
++ addition to EP0.
++ </td></tr>
++
++ <tr>
++ <td>phy_type</td>
++ <td>Specifies the type of PHY interface to use. By default, the driver will
++ automatically detect the phy_type.
++ - 0: Full Speed
++ - 1: UTMI+ (default, if available)
++ - 2: ULPI
++ </td></tr>
++
++ <tr>
++ <td>phy_utmi_width</td>
++ <td>Specifies the UTMI+ Data Width. This parameter is applicable for a
++ phy_type of UTMI+. Also, this parameter is applicable only if the
++ OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the
++ core has been configured to work at either data path width.
++ - Values: 8 or 16 bits (default 16)
++ </td></tr>
++
++ <tr>
++ <td>phy_ulpi_ddr</td>
++ <td>Specifies whether the ULPI operates at double or single data rate. This
++ parameter is only applicable if phy_type is ULPI.
++ - 0: single data rate ULPI interface with 8 bit wide data bus (default)
++ - 1: double data rate ULPI interface with 4 bit wide data bus
++ </td></tr>
++
++ <tr>
++ <td>i2c_enable</td>
++ <td>Specifies whether to use the I2C interface for full speed PHY. This
++ parameter is only applicable if PHY_TYPE is FS.
++ - 0: Disabled (default)
++ - 1: Enabled
++ </td></tr>
++
++ <tr>
++ <td>otg_en_multiple_tx_fifo</td>
++ <td>Specifies whether dedicatedto tx fifos are enabled for non periodic IN EPs.
++ The driver will automatically detect the value for this parameter if none is
++ specified.
++ - 0: Disabled
++ - 1: Enabled (default, if available)
++ </td></tr>
++
++ <tr>
++ <td>dev_tx_fifo_size_n (n = 1 to 15)</td>
++ <td>Number of 4-byte words in each of the Tx FIFOs in device mode
++ when dynamic FIFO sizing is enabled.
++ - Values: 4 to 768 (default 256)
++ </td></tr>
++
++*/
+diff --git a/drivers/usb/dwc_otg/dwc_otg_driver.h b/drivers/usb/dwc_otg/dwc_otg_driver.h
+new file mode 100644
+index 0000000..ed4016a
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_driver.h
+@@ -0,0 +1,80 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_driver.h $
++ * $Revision: #2 $
++ * $Date: 2007/02/07 $
++ * $Change: 791271 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++#if !defined(__DWC_OTG_DRIVER_H__)
++#define __DWC_OTG_DRIVER_H__
++
++/** @file
++ * This file contains the interface to the Linux driver.
++ */
++#include "dwc_otg_cil.h"
++
++#define ARM_VP_OTG_INTR INT_UOTG
++/* Type declarations */
++struct dwc_otg_pcd;
++struct dwc_otg_hcd;
++
++/**
++ * This structure is a wrapper that encapsulates the driver components used to
++ * manage a single DWC_otg controller.
++ */
++typedef struct dwc_otg_device
++{
++ /** Base address returned from ioremap() */
++ void *base;
++
++ struct lm_device *lmdev;
++
++ /** Pointer to the core interface structure. */
++ dwc_otg_core_if_t *core_if;
++
++ /** Register offset for Diagnostic API.*/
++ uint32_t reg_offset;
++
++ /** Pointer to the PCD structure. */
++ struct dwc_otg_pcd *pcd;
++
++ /** Pointer to the HCD structure. */
++ struct dwc_otg_hcd *hcd;
++
++ /** Flag to indicate whether the common IRQ handler is installed. */
++ uint8_t common_irq_installed;
++
++ uint8_t flagID;
++ uint8_t flagDeviceVBUS;
++ uint8_t flagDeviceAttach;
++ uint8_t flagMode, flagMode_backup;
++ struct task_struct *vbus_usb_task;
++} dwc_otg_device_t;
++
++#endif
+diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.c b/drivers/usb/dwc_otg/dwc_otg_hcd.c
+new file mode 100644
+index 0000000..a08fa9a
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_hcd.c
+@@ -0,0 +1,2817 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd.c $
++ * $Revision: #16 $
++ * $Date: 2006/12/05 $
++ * $Change: 762293 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++#ifndef DWC_DEVICE_ONLY
++
++/**
++ * @file
++ *
++ * This file contains the implementation of the HCD. In Linux, the HCD
++ * implements the hc_driver API.
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/errno.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/string.h>
++#include <linux/dma-mapping.h>
++
++#ifdef _USE_ATTR_
++#include <asm/arch/lm.h>
++#endif
++
++#include "dwc_otg_driver.h"
++#include "dwc_otg_hcd.h"
++#include "dwc_otg_regs.h"
++#include "tcc_usb_phy.h"
++
++static const char dwc_otg_hcd_name [] = "dwc_otg_hcd";
++
++static int dwc_otg_hcd_hub_suspend(struct usb_hcd *_hcd)
++{
++ return 0;
++}
++
++static int dwc_otg_hcd_hub_resume(struct usb_hcd *_hcd)
++{
++ return 0;
++}
++
++static const struct hc_driver dwc_otg_hc_driver = {
++
++ .description = dwc_otg_hcd_name,
++ .product_desc = "DWC OTG Controller",
++ .hcd_priv_size = sizeof(dwc_otg_hcd_t),
++
++ .irq = dwc_otg_hcd_irq,
++
++ .flags = HCD_MEMORY | HCD_USB2,
++
++ //.reset =
++ .start = dwc_otg_hcd_start,
++ //.suspend =
++ //.resume =
++ .stop = dwc_otg_hcd_stop,
++
++ .urb_enqueue = dwc_otg_hcd_urb_enqueue,
++ .urb_dequeue = dwc_otg_hcd_urb_dequeue,
++ .endpoint_disable = dwc_otg_hcd_endpoint_disable,
++
++ .get_frame_number = dwc_otg_hcd_get_frame_number,
++
++ .hub_status_data = dwc_otg_hcd_hub_status_data,
++ .hub_control = dwc_otg_hcd_hub_control,
++ .bus_suspend = dwc_otg_hcd_hub_suspend,
++ .bus_resume = dwc_otg_hcd_hub_resume,
++};
++
++
++
++/**
++ * Work queue function for starting the HCD when A-Cable is connected.
++ * The dwc_otg_hcd_start() must be called in a process context.
++ */
++static void hcd_start_func(struct work_struct *work)
++{
++ dwc_otg_hcd_t *dwc_otg_hcd = container_of(work, struct dwc_otg_hcd, start_work);
++ struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
++
++ DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, usb_hcd);
++ if (usb_hcd) {
++ dwc_otg_hcd_start(usb_hcd);
++ }
++}
++
++/**
++ * HCD Callback function for starting the HCD when A-Cable is
++ * connected.
++ *
++ * @param _p void pointer to the <code>struct usb_hcd</code>
++ */
++static int32_t dwc_otg_hcd_start_cb(void *_p)
++{
++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_p);
++ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
++ hprt0_data_t hprt0;
++
++ if (core_if->op_state == B_HOST) {
++ /*
++ * Reset the port. During a HNP mode switch the reset
++ * needs to occur within 1ms and have a duration of at
++ * least 50ms.
++ */
++ hprt0.d32 = dwc_otg_read_hprt0 (core_if);
++ hprt0.b.prtrst = 1;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++ ((struct usb_hcd *)_p)->self.is_b_host = 1;
++ } else {
++ ((struct usb_hcd *)_p)->self.is_b_host = 0;
++ }
++
++ /* Need to start the HCD in a non-interrupt context. */
++ INIT_WORK(&dwc_otg_hcd->start_work, hcd_start_func);
++ schedule_work(&dwc_otg_hcd->start_work);
++
++ return 1;
++}
++
++
++/**
++ * HCD Callback function for stopping the HCD.
++ *
++ * @param _p void pointer to the <code>struct usb_hcd</code>
++ */
++static int32_t dwc_otg_hcd_stop_cb( void *_p )
++{
++ struct usb_hcd *usb_hcd = (struct usb_hcd *)_p;
++ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p);
++ dwc_otg_hcd_stop( usb_hcd );
++ return 1;
++}
++
++static void del_xfer_timers(dwc_otg_hcd_t *_hcd)
++{
++#ifdef DEBUG
++ int i;
++ int num_channels = _hcd->core_if->core_params->host_channels;
++ for (i = 0; i < num_channels; i++) {
++ del_timer(&_hcd->core_if->hc_xfer_timer[i]);
++ }
++#endif
++}
++
++static void del_timers(dwc_otg_hcd_t *_hcd)
++{
++ del_xfer_timers(_hcd);
++ del_timer(&_hcd->conn_timer);
++}
++
++/**
++ * Processes all the URBs in a single list of QHs. Completes them with
++ * -ETIMEDOUT and frees the QTD.
++ */
++static void kill_urbs_in_qh_list(dwc_otg_hcd_t *_hcd, struct list_head *_qh_list)
++{
++ struct list_head *qh_item;
++ dwc_otg_qh_t *qh;
++ struct list_head *qtd_item;
++ dwc_otg_qtd_t *qtd;
++
++ list_for_each(qh_item, _qh_list) {
++ qh = list_entry(qh_item, dwc_otg_qh_t, qh_list_entry);
++ for (qtd_item = qh->qtd_list.next;
++ qtd_item != &qh->qtd_list;
++ qtd_item = qh->qtd_list.next) {
++ qtd = list_entry(qtd_item, dwc_otg_qtd_t, qtd_list_entry);
++ if (qtd->urb != NULL) {
++ dwc_otg_hcd_complete_urb(_hcd, qtd->urb,
++ -ETIMEDOUT);
++ }
++ dwc_otg_hcd_qtd_remove_and_free(qtd);
++ }
++ }
++}
++
++/**
++ * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic
++ * and periodic schedules. The QTD associated with each URB is removed from
++ * the schedule and freed. This function may be called when a disconnect is
++ * detected or when the HCD is being stopped.
++ */
++static void kill_all_urbs(dwc_otg_hcd_t *_hcd)
++{
++ kill_urbs_in_qh_list(_hcd, &_hcd->non_periodic_sched_inactive);
++ kill_urbs_in_qh_list(_hcd, &_hcd->non_periodic_sched_active);
++ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_inactive);
++ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_ready);
++ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_assigned);
++ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_queued);
++}
++
++/**
++ * HCD Callback function for disconnect of the HCD.
++ *
++ * @param _p void pointer to the <code>struct usb_hcd</code>
++ */
++static int32_t dwc_otg_hcd_disconnect_cb( void *_p )
++{
++ gintsts_data_t intr;
++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_p);
++
++ //DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p);
++
++ /*
++ * Set status flags for the hub driver.
++ */
++ dwc_otg_hcd->flags.b.port_connect_status_change = 1;
++ dwc_otg_hcd->flags.b.port_connect_status = 0;
++
++ /*
++ * Shutdown any transfers in process by clearing the Tx FIFO Empty
++ * interrupt mask and status bits and disabling subsequent host
++ * channel interrupts.
++ */
++ intr.d32 = 0;
++ intr.b.nptxfempty = 1;
++ intr.b.ptxfempty = 1;
++ intr.b.hcintr = 1;
++ dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintmsk, intr.d32, 0);
++ dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintsts, intr.d32, 0);
++
++ del_timers(dwc_otg_hcd);
++
++ /*
++ * Turn off the vbus power only if the core has transitioned to device
++ * mode. If still in host mode, need to keep power on to detect a
++ * reconnection.
++ */
++ if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
++ if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
++ dwc_otg_hcd->core_if->vbus_state = 0;
++ schedule_work(&dwc_otg_hcd->core_if->vbus_work);
++ DWC_PRINT("Disconnect: PortPower off\n");
++ }
++
++ dwc_otg_disable_host_interrupts( dwc_otg_hcd->core_if );
++ }
++
++ /* Respond with an error status to all URBs in the schedule. */
++ kill_all_urbs(dwc_otg_hcd);
++
++ if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
++ /* Clean up any host channels that were in use. */
++ int num_channels;
++ int i;
++ dwc_hc_t *channel;
++ dwc_otg_hc_regs_t *hc_regs;
++ hcchar_data_t hcchar;
++
++ num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
++
++ if (!dwc_otg_hcd->core_if->dma_enable) {
++ /* Flush out any channel requests in slave mode. */
++ for (i = 0; i < num_channels; i++) {
++ channel = dwc_otg_hcd->hc_ptr_array[i];
++ if (list_empty(&channel->hc_list_entry)) {
++ hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[i];
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ if (hcchar.b.chen) {
++ hcchar.b.chen = 0;
++ hcchar.b.chdis = 1;
++ hcchar.b.epdir = 0;
++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
++ }
++ }
++ }
++ }
++
++ for (i = 0; i < num_channels; i++) {
++ channel = dwc_otg_hcd->hc_ptr_array[i];
++ if (list_empty(&channel->hc_list_entry)) {
++ hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[i];
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ if (hcchar.b.chen) {
++ /* Halt the channel. */
++ hcchar.b.chdis = 1;
++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
++ }
++
++ dwc_otg_hc_cleanup(dwc_otg_hcd->core_if, channel);
++ list_add_tail(&channel->hc_list_entry,
++ &dwc_otg_hcd->free_hc_list);
++ }
++ }
++ }
++
++ /* A disconnect will end the session so the B-Device is no
++ * longer a B-host. */
++ ((struct usb_hcd *)_p)->self.is_b_host = 0;
++ return 1;
++}
++
++/**
++ * Connection timeout function. An OTG host is required to display a
++ * message if the device does not connect within 10 seconds.
++ */
++void dwc_otg_hcd_connect_timeout( unsigned long _ptr )
++{
++ DWC_DEBUGPL(DBG_HCDV, "%s(%x)\n", __func__, (int)_ptr);
++ DWC_PRINT( "Connect Timeout\n");
++ DWC_ERROR( "Device Not Connected/Responding\n" );
++}
++
++/**
++ * Start the connection timer. An OTG host is required to display a
++ * message if the device does not connect within 10 seconds. The
++ * timer is deleted if a port connect interrupt occurs before the
++ * timer expires.
++ */
++static void dwc_otg_hcd_start_connect_timer( dwc_otg_hcd_t *_hcd)
++{
++ init_timer( &_hcd->conn_timer );
++ _hcd->conn_timer.function = dwc_otg_hcd_connect_timeout;
++ _hcd->conn_timer.data = (unsigned long)0;
++ _hcd->conn_timer.expires = jiffies + (HZ*10);
++ add_timer( &_hcd->conn_timer );
++}
++
++/**
++ * HCD Callback function for disconnect of the HCD.
++ *
++ * @param _p void pointer to the <code>struct usb_hcd</code>
++ */
++static int32_t dwc_otg_hcd_session_start_cb( void *_p )
++{
++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_p);
++ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p);
++ dwc_otg_hcd_start_connect_timer( dwc_otg_hcd );
++ return 1;
++}
++
++/**
++ * HCD Callback structure for handling mode switching.
++ */
++static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
++ .start = dwc_otg_hcd_start_cb,
++ .stop = dwc_otg_hcd_stop_cb,
++ .disconnect = dwc_otg_hcd_disconnect_cb,
++ .session_start = dwc_otg_hcd_session_start_cb,
++ .p = 0,
++};
++
++
++/**
++ * Reset tasklet function
++ */
++static void reset_tasklet_func (unsigned long data)
++{
++ dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t*)data;
++ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
++ hprt0_data_t hprt0;
++
++ DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
++
++ hprt0.d32 = dwc_otg_read_hprt0 (core_if);
++ hprt0.b.prtrst = 1;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++ mdelay (60);
++
++ hprt0.b.prtrst = 0;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++ dwc_otg_hcd->flags.b.port_reset_change = 1;
++
++ return;
++}
++
++static struct tasklet_struct reset_tasklet = {
++ .next = NULL,
++ .state = 0,
++ .count = ATOMIC_INIT(0),
++ .func = reset_tasklet_func,
++ .data = 0,
++};
++
++/**
++ * Initializes the HCD. This function allocates memory for and initializes the
++ * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the
++ * USB bus with the core and calls the hc_driver->start() function. It returns
++ * a negative error on failure.
++ */
++static u64 dwc_otg_dmamask = 0xffffffffUL;
++int __init dwc_otg_hcd_init(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd = NULL;
++ dwc_otg_hcd_t *dwc_otg_hcd = NULL;
++ dwc_otg_device_t *otg_dev = platform_get_otgdata(pdev);
++
++ int num_channels;
++ int i;
++ dwc_hc_t *channel;
++
++ int retval = 0;
++
++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n");
++ DWC_DEBUGPL(DBG_CILV, "%s: dwc_otg_device(%p)\n", __func__, otg_dev);
++
++ /*
++ * Allocate memory for the base HCD plus the DWC OTG HCD.
++ * Initialize the base HCD.
++ */
++ hcd = usb_create_hcd(&dwc_otg_hc_driver, &pdev->dev, "DWC OTG Controller");
++ if (hcd == NULL) {
++ retval = -ENOMEM;
++ goto error1;
++ }
++ hcd->regs = otg_dev->base;
++ hcd->self.otg_port = 1;
++
++ /* Initialize the DWC OTG HCD. */
++ dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
++ dwc_otg_hcd->core_if = otg_dev->core_if;
++ otg_dev->hcd = dwc_otg_hcd;
++
++ /* Register the HCD CIL Callbacks */
++ dwc_otg_cil_register_hcd_callbacks(otg_dev->core_if,
++ &hcd_cil_callbacks, hcd);
++
++ /* Initialize the non-periodic schedule. */
++ INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_inactive);
++ INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_active);
++
++ /* Initialize the periodic schedule. */
++ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_inactive);
++ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_ready);
++ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_assigned);
++ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_queued);
++
++ /*
++ * Create a host channel descriptor for each host channel implemented
++ * in the controller. Initialize the channel descriptor array.
++ */
++ INIT_LIST_HEAD(&dwc_otg_hcd->free_hc_list);
++ num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
++ for (i = 0; i < num_channels; i++) {
++ channel = kmalloc(sizeof(dwc_hc_t), GFP_KERNEL);
++ if (channel == NULL) {
++ retval = -ENOMEM;
++ DWC_ERROR("%s: host channel allocation failed\n", __func__);
++ goto error2;
++ }
++ memset(channel, 0, sizeof(dwc_hc_t));
++ channel->hc_num = i;
++ dwc_otg_hcd->hc_ptr_array[i] = channel;
++#ifdef DEBUG
++ init_timer(&dwc_otg_hcd->core_if->hc_xfer_timer[i]);
++#endif
++
++ DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i, channel);
++ }
++
++ /* Initialize the Connection timeout timer. */
++ init_timer( &dwc_otg_hcd->conn_timer );
++
++ /* Initialize reset tasklet. */
++ reset_tasklet.data = (unsigned long) dwc_otg_hcd;
++ dwc_otg_hcd->reset_tasklet = &reset_tasklet;
++
++ /* Set device flags indicating whether the HCD supports DMA. */
++ if (otg_dev->core_if->dma_enable) {
++ DWC_PRINT("Using DMA mode\n");
++ //dev->dma_mask = (void *)~0;
++ //dev->coherent_dma_mask = ~0;
++ pdev->dev.dma_mask = &dwc_otg_dmamask;
++ pdev->dev.coherent_dma_mask = ~0;
++ } else {
++ DWC_PRINT("Using Slave mode\n");
++ pdev->dev.dma_mask = (void *)0;
++ pdev->dev.coherent_dma_mask = 0;
++ }
++
++ /*
++ * Finish generic HCD initialization and start the HCD. This function
++ * allocates the DMA buffer pool, registers the USB bus, requests the
++ * IRQ line, and calls dwc_otg_hcd_start method.
++ */
++ retval = usb_add_hcd(hcd, ARM_VP_OTG_INTR, IRQF_SHARED);
++ if (retval < 0) {
++ goto error2;
++ }
++
++ /*
++ * Allocate space for storing data on status transactions. Normally no
++ * data is sent, but this space acts as a bit bucket. This must be
++ * done after usb_add_hcd since that function allocates the DMA buffer
++ * pool.
++ */
++ if (otg_dev->core_if->dma_enable) {
++ dwc_otg_hcd->status_buf =
++ dma_alloc_coherent(&pdev->dev,
++ DWC_OTG_HCD_STATUS_BUF_SIZE,
++ &dwc_otg_hcd->status_buf_dma,
++ GFP_KERNEL | GFP_DMA);
++ dwc_otg_hcd->tmp_rcv_buf =
++ dma_alloc_coherent(&pdev->dev,
++ DWC_OTG_HCD_TMP_BUF_SIZE,
++ &dwc_otg_hcd->tmp_rcv_buf_dma,
++ GFP_KERNEL | GFP_DMA);
++ dwc_otg_hcd->tmp_snd_buf =
++ dma_alloc_coherent(&pdev->dev,
++ DWC_OTG_HCD_TMP_BUF_SIZE,
++ &dwc_otg_hcd->tmp_snd_buf_dma,
++ GFP_KERNEL | GFP_DMA);
++ dwc_otg_hcd->old_tmp_buf = dwc_otg_hcd->tmp_rcv_buf;
++ dwc_otg_hcd->rcv_buf_align_flag = 0;
++ } else {
++ dwc_otg_hcd->status_buf = kmalloc(DWC_OTG_HCD_STATUS_BUF_SIZE,
++ GFP_KERNEL);
++ }
++ if (dwc_otg_hcd->status_buf == NULL) {
++ retval = -ENOMEM;
++ DWC_ERROR("%s: status_buf allocation failed\n", __func__);
++ goto error3;
++ }
++
++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Initialized HCD, bus=%s, usbbus=%d\n",
++ "DWC OTG Controller", hcd->self.busnum);
++
++ return 0;
++
++ /* Error conditions */
++error3:
++ usb_remove_hcd(hcd);
++error2:
++ dwc_otg_hcd_free(hcd);
++ usb_put_hcd(hcd);
++error1:
++ return retval;
++}
++
++/**
++ * Removes the HCD.
++ * Frees memory and resources associated with the HCD and deregisters the bus.
++ */
++void dwc_otg_hcd_remove(struct platform_device *pdev)
++{
++ dwc_otg_device_t *otg_dev = platform_get_otgdata(pdev);
++ dwc_otg_hcd_t *dwc_otg_hcd;
++ struct usb_hcd *hcd;
++
++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE\n");
++
++ /* Turn off all interrupts */
++ dwc_otg_hcd = otg_dev->hcd;
++ dwc_write_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintmsk, 0);
++ dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gahbcfg, 1, 0);
++
++ /* Release hcd driver */
++ hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
++ usb_remove_hcd(hcd);
++ dwc_otg_hcd_free(hcd);
++ usb_put_hcd(hcd);
++
++ return;
++}
++
++
++/* =========================================================================
++ * Linux HC Driver Functions
++ * ========================================================================= */
++
++/**
++ * Initializes dynamic portions of the DWC_otg HCD state.
++ */
++static void hcd_reinit(dwc_otg_hcd_t *_hcd)
++{
++ struct list_head *item;
++ int num_channels;
++ int i;
++ dwc_hc_t *channel;
++
++ _hcd->flags.d32 = 0;
++
++ _hcd->non_periodic_qh_ptr = &_hcd->non_periodic_sched_active;
++ _hcd->non_periodic_channels = 0;
++ _hcd->periodic_channels = 0;
++
++ /*
++ * Put all channels in the free channel list and clean up channel
++ * states.
++ */
++ item = _hcd->free_hc_list.next;
++ while (item != &_hcd->free_hc_list) {
++ list_del(item);
++ item = _hcd->free_hc_list.next;
++ }
++ num_channels = _hcd->core_if->core_params->host_channels;
++ for (i = 0; i < num_channels; i++) {
++ channel = _hcd->hc_ptr_array[i];
++ list_add_tail(&channel->hc_list_entry, &_hcd->free_hc_list);
++ dwc_otg_hc_cleanup(_hcd->core_if, channel);
++ }
++
++ /* Initialize the DWC core for host mode operation. */
++ dwc_otg_core_host_init(_hcd->core_if);
++}
++
++/** Initializes the DWC_otg controller and its root hub and prepares it for host
++ * mode operation. Activates the root port. Returns 0 on success and a negative
++ * error code on failure. */
++int dwc_otg_hcd_start(struct usb_hcd *_hcd)
++{
++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd);
++ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
++ struct usb_bus *bus;
++
++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
++
++ bus = hcd_to_bus(_hcd);
++
++ /* Initialize the bus state. If the core is in Device Mode
++ * HALT the USB bus and return. */
++ if (dwc_otg_is_device_mode (core_if)) {
++ _hcd->state = HC_STATE_HALT;
++ return 0;
++ }
++ _hcd->state = HC_STATE_RUNNING;
++
++ /* Initialize and connect root hub if one is not already attached */
++ if (bus->root_hub) {
++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
++ /* Inform the HUB driver to resume. */
++ usb_hcd_resume_root_hub(_hcd);
++ } else {
++ DWC_DEBUGPL(DBG_HCD, "\n!!!!! DWC OTG HCD Has Not Root Hub !!!!!\n");
++ return -ENODEV;
++ }
++
++ hcd_reinit(dwc_otg_hcd);
++
++ return 0;
++}
++
++static void qh_list_free(dwc_otg_hcd_t *_hcd, struct list_head *_qh_list)
++{
++ struct list_head *item;
++ dwc_otg_qh_t *qh;
++
++ if (_qh_list->next == NULL) {
++ /* The list hasn't been initialized yet. */
++ return;
++ }
++
++ /* Ensure there are no QTDs or URBs left. */
++ kill_urbs_in_qh_list(_hcd, _qh_list);
++
++ for (item = _qh_list->next; item != _qh_list; item = _qh_list->next) {
++ qh = list_entry(item, dwc_otg_qh_t, qh_list_entry);
++ dwc_otg_hcd_qh_remove_and_free(_hcd, qh);
++ }
++}
++
++/**
++ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
++ * stopped.
++ */
++void dwc_otg_hcd_stop(struct usb_hcd *_hcd)
++{
++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd);
++
++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
++
++ /* Turn off all host-specific interrupts. */
++ dwc_otg_disable_host_interrupts( dwc_otg_hcd->core_if );
++
++ /*
++ * The root hub should be disconnected before this function is called.
++ * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
++ * and the QH lists (via ..._hcd_endpoint_disable).
++ */
++
++ /* Turn off the vbus power */
++ DWC_PRINT("PortPower off\n");
++ if (dwc_otg_hcd->core_if->vbus_state == -1) {
++ /* if driver rmmod */
++ TCC_DVBUS_Control(0);
++ } else {
++ dwc_otg_hcd->core_if->vbus_state = 0;
++ schedule_work(&dwc_otg_hcd->core_if->vbus_work);
++ }
++
++ return;
++}
++
++
++/** Returns the current frame number. */
++int dwc_otg_hcd_get_frame_number(struct usb_hcd *_hcd)
++{
++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd);
++ hfnum_data_t hfnum;
++
++ hfnum.d32 = dwc_read_reg32(&dwc_otg_hcd->core_if->
++ host_if->host_global_regs->hfnum);
++
++#ifdef DEBUG_SOF
++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n", hfnum.b.frnum);
++#endif
++ return hfnum.b.frnum;
++}
++
++/**
++ * Frees secondary storage associated with the dwc_otg_hcd structure contained
++ * in the struct usb_hcd field.
++ */
++void dwc_otg_hcd_free(struct usb_hcd *_hcd)
++{
++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd);
++ int i;
++
++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
++
++ del_timers(dwc_otg_hcd);
++
++ /* Free memory for QH/QTD lists */
++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
++
++ /* Free memory for the host channels. */
++ for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++ dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];
++ if (hc != NULL) {
++ DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n", i, hc);
++ kfree(hc);
++ }
++ }
++
++ if (dwc_otg_hcd->core_if->dma_enable) {
++ if (dwc_otg_hcd->status_buf_dma) {
++ dma_free_coherent(_hcd->self.controller,
++ DWC_OTG_HCD_STATUS_BUF_SIZE,
++ dwc_otg_hcd->status_buf,
++ dwc_otg_hcd->status_buf_dma);
++ }
++ if (dwc_otg_hcd->tmp_rcv_buf_dma) {
++ dma_free_coherent(_hcd->self.controller,
++ DWC_OTG_HCD_TMP_BUF_SIZE,
++ dwc_otg_hcd->tmp_rcv_buf,
++ dwc_otg_hcd->tmp_rcv_buf_dma);
++ }
++ if (dwc_otg_hcd->tmp_snd_buf_dma) {
++ dma_free_coherent(_hcd->self.controller,
++ DWC_OTG_HCD_TMP_BUF_SIZE,
++ dwc_otg_hcd->tmp_snd_buf,
++ dwc_otg_hcd->tmp_snd_buf_dma);
++ }
++ } else if (dwc_otg_hcd->status_buf != NULL) {
++ kfree(dwc_otg_hcd->status_buf);
++ }
++
++ return;
++}
++
++
++#ifdef DEBUG
++static void dump_urb_info(struct urb *_urb, char* _fn_name)
++{
++ DWC_PRINT("%s, urb %p\n", _fn_name, _urb);
++ DWC_PRINT(" Device address: %d\n", usb_pipedevice(_urb->pipe));
++ DWC_PRINT(" Endpoint: %d, %s\n", usb_pipeendpoint(_urb->pipe),
++ (usb_pipein(_urb->pipe) ? "IN" : "OUT"));
++ DWC_PRINT(" Endpoint type: %s\n",
++ ({char *pipetype;
++ switch (usb_pipetype(_urb->pipe)) {
++ case PIPE_CONTROL: pipetype = "CONTROL"; break;
++ case PIPE_BULK: pipetype = "BULK"; break;
++ case PIPE_INTERRUPT: pipetype = "INTERRUPT"; break;
++ case PIPE_ISOCHRONOUS: pipetype = "ISOCHRONOUS"; break;
++ default: pipetype = "UNKNOWN"; break;
++ }; pipetype;}));
++ DWC_PRINT(" Speed: %s\n",
++ ({char *speed;
++ switch (_urb->dev->speed) {
++ case USB_SPEED_HIGH: speed = "HIGH"; break;
++ case USB_SPEED_FULL: speed = "FULL"; break;
++ case USB_SPEED_LOW: speed = "LOW"; break;
++ default: speed = "UNKNOWN"; break;
++ }; speed;}));
++ DWC_PRINT(" Max packet size: %d\n",
++ usb_maxpacket(_urb->dev, _urb->pipe, usb_pipeout(_urb->pipe)));
++ DWC_PRINT(" Data buffer length: %d\n", _urb->transfer_buffer_length);
++ DWC_PRINT(" Transfer buffer: %p, Transfer DMA: %p\n",
++ _urb->transfer_buffer, (void *)_urb->transfer_dma);
++ DWC_PRINT(" Setup buffer: %p, Setup DMA: %p\n",
++ _urb->setup_packet, (void *)_urb->setup_dma);
++ DWC_PRINT(" Interval: %d\n", _urb->interval);
++ if (usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) {
++ int i;
++ for (i = 0; i < _urb->number_of_packets; i++) {
++ DWC_PRINT(" ISO Desc %d:\n", i);
++ DWC_PRINT(" offset: %d, length %d\n",
++ _urb->iso_frame_desc[i].offset,
++ _urb->iso_frame_desc[i].length);
++ }
++ }
++}
++
++static void dump_channel_info(dwc_otg_hcd_t *_hcd,
++ dwc_otg_qh_t *qh)
++{
++ if (qh->channel != NULL) {
++ dwc_hc_t *hc = qh->channel;
++ struct list_head *item;
++ dwc_otg_qh_t *qh_item;
++ int num_channels = _hcd->core_if->core_params->host_channels;
++ int i;
++
++ dwc_otg_hc_regs_t *hc_regs;
++ hcchar_data_t hcchar;
++ hcsplt_data_t hcsplt;
++ hctsiz_data_t hctsiz;
++ uint32_t hcdma;
++
++ hc_regs = _hcd->core_if->host_if->hc_regs[hc->hc_num];
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);
++ hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
++ hcdma = dwc_read_reg32(&hc_regs->hcdma);
++
++ DWC_PRINT(" Assigned to channel %p:\n", hc);
++ DWC_PRINT(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
++ DWC_PRINT(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);
++ DWC_PRINT(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
++ hc->dev_addr, hc->ep_num, hc->ep_is_in);
++ DWC_PRINT(" ep_type: %d\n", hc->ep_type);
++ DWC_PRINT(" max_packet: %d\n", hc->max_packet);
++ DWC_PRINT(" data_pid_start: %d\n", hc->data_pid_start);
++ DWC_PRINT(" xfer_started: %d\n", hc->xfer_started);
++ DWC_PRINT(" halt_status: %d\n", hc->halt_status);
++ DWC_PRINT(" xfer_buff: %p\n", hc->xfer_buff);
++ DWC_PRINT(" xfer_len: %d\n", hc->xfer_len);
++ DWC_PRINT(" qh: %p\n", hc->qh);
++ DWC_PRINT(" NP inactive sched:\n");
++ list_for_each(item, &_hcd->non_periodic_sched_inactive) {
++ qh_item = list_entry(item, dwc_otg_qh_t, qh_list_entry);
++ DWC_PRINT(" %p\n", qh_item);
++ }
++ DWC_PRINT(" NP active sched:\n");
++ list_for_each(item, &_hcd->non_periodic_sched_active) {
++ qh_item = list_entry(item, dwc_otg_qh_t, qh_list_entry);
++ DWC_PRINT(" %p\n", qh_item);
++ }
++ DWC_PRINT(" Channels: \n");
++ for (i = 0; i < num_channels; i++) {
++ dwc_hc_t *hc = _hcd->hc_ptr_array[i];
++ DWC_PRINT(" %2d: %p\n", i, hc);
++ }
++ }
++}
++#endif
++
++/** Starts processing a USB transfer request specified by a USB Request Block
++ * (URB). mem_flags indicates the type of memory allocation to use while
++ * processing this URB. */
++int dwc_otg_hcd_urb_enqueue(struct usb_hcd *_hcd,
++ struct urb *_urb,
++ gfp_t _mem_flags)
++{
++ int retval = 0;
++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd);
++ dwc_otg_qtd_t *qtd;
++
++#ifdef DEBUG
++ if (CHK_DEBUG_LEVEL(DBG_HCD_URB)) {
++ dump_urb_info(_urb, "dwc_otg_hcd_urb_enqueue");
++ }
++#endif
++ if (!dwc_otg_hcd->flags.b.port_connect_status) {
++ /* No longer connected. */
++ return -ENODEV;
++ }
++
++ /* because TCC8902's USB OTG Controller request that the transfer buffer must be DWORD aligned when using DMA mode.
++ so when transfer_buffer of urb is not DWORD aligned, we use another DWORD aligned temp buffer instead, and do
++ according data copying work before urb transferring (when send data to device) or after urb transferring
++ (when receive data from device). */
++ if((unsigned int)_urb->transfer_buffer % 4) { // when transfer_buffer of urb is not DWORD aligned
++ if(usb_pipein(_urb->pipe) != 0) { // when receive data from device
++ dwc_otg_hcd->rcv_buf_align_flag = 1;
++ dwc_otg_hcd->old_tmp_buf = _urb->transfer_buffer;
++ dwc_otg_hcd->old_tmp_buf_size = _urb->transfer_buffer_length;
++ _urb->transfer_buffer = dwc_otg_hcd->tmp_rcv_buf;
++ _urb->transfer_dma = dwc_otg_hcd->tmp_rcv_buf_dma;
++ } else { // when send data to device
++ memcpy(dwc_otg_hcd->tmp_snd_buf, _urb->transfer_buffer, _urb->transfer_buffer_length);
++ _urb->transfer_buffer = dwc_otg_hcd->tmp_snd_buf;
++ _urb->transfer_dma = dwc_otg_hcd->tmp_snd_buf_dma;
++ }
++ }
++ qtd = dwc_otg_hcd_qtd_create (_urb);
++ if (qtd == NULL) {
++ DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
++ return -ENOMEM;
++ }
++
++ retval = dwc_otg_hcd_qtd_add (qtd, dwc_otg_hcd);
++ if (retval < 0) {
++ DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
++ "Error status %d\n", retval);
++ dwc_otg_hcd_qtd_free(qtd);
++ }
++
++ return retval;
++}
++
++/** Aborts/cancels a USB transfer request. Always returns 0 to indicate
++ * success. */
++int dwc_otg_hcd_urb_dequeue(struct usb_hcd *_hcd,
++ struct urb *_urb,
++ int status)
++{
++ unsigned long flags;
++ dwc_otg_hcd_t *dwc_otg_hcd;
++ dwc_otg_qtd_t *urb_qtd;
++ dwc_otg_qh_t *qh;
++ struct usb_host_endpoint *_ep = dwc_urb_to_endpoint(_urb);
++
++
++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
++
++ local_irq_save(flags);
++
++ dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd);
++ urb_qtd = (dwc_otg_qtd_t *)_urb->hcpriv;
++ qh = (dwc_otg_qh_t *)_ep->hcpriv;
++
++#ifdef DEBUG
++ if (CHK_DEBUG_LEVEL(DBG_HCD_URB)) {
++ dump_urb_info(_urb, "dwc_otg_hcd_urb_dequeue");
++ if (urb_qtd == qh->qtd_in_process) {
++ dump_channel_info(dwc_otg_hcd, qh);
++ }
++ }
++#endif
++
++ if (urb_qtd == qh->qtd_in_process) {
++ /* The QTD is in process (it has been assigned to a channel). */
++
++ if (dwc_otg_hcd->flags.b.port_connect_status) {
++ /*
++ * If still connected (i.e. in host mode), halt the
++ * channel so it can be used for other transfers. If
++ * no longer connected, the host registers can't be
++ * written to halt the channel since the core is in
++ * device mode.
++ */
++ dwc_otg_hc_halt(dwc_otg_hcd->core_if, qh->channel,
++ DWC_OTG_HC_XFER_URB_DEQUEUE);
++ }
++ }
++
++ /*
++ * Free the QTD and clean up the associated QH. Leave the QH in the
++ * schedule if it has any remaining QTDs.
++ */
++ dwc_otg_hcd_qtd_remove_and_free(urb_qtd);
++ if (urb_qtd == qh->qtd_in_process) {
++ dwc_otg_hcd_qh_deactivate(dwc_otg_hcd, qh, 0);
++ qh->channel = NULL;
++ qh->qtd_in_process = NULL;
++ } else if (list_empty(&qh->qtd_list)) {
++ dwc_otg_hcd_qh_remove(dwc_otg_hcd, qh);
++ }
++
++ local_irq_restore(flags);
++
++ _urb->hcpriv = NULL;
++
++ /* Higher layer software sets URB status. */
++ usb_hcd_giveback_urb(_hcd, _urb, status);
++#ifdef DEBUG
++ if (CHK_DEBUG_LEVEL(DBG_HCD_URB)) {
++ DWC_PRINT("Called usb_hcd_giveback_urb()\n");
++ DWC_PRINT(" urb->status = %d\n", _urb->status);
++ }
++#endif
++
++ return 0;
++}
++
++
++/** Frees resources in the DWC_otg controller related to a given endpoint. Also
++ * clears state in the HCD related to the endpoint. Any URBs for the endpoint
++ * must already be dequeued. */
++void dwc_otg_hcd_endpoint_disable(struct usb_hcd *_hcd,
++ struct usb_host_endpoint *_ep)
++
++{
++ dwc_otg_qh_t *qh;
++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd);
++
++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
++ "endpoint=%d\n", _ep->desc.bEndpointAddress,
++ dwc_ep_addr_to_endpoint(_ep->desc.bEndpointAddress));
++
++ qh = (dwc_otg_qh_t *)(_ep->hcpriv);
++ if (qh != NULL) {
++#ifdef DEBUG
++ /** Check that the QTD list is really empty */
++ if (!list_empty(&qh->qtd_list)) {
++ DWC_WARN("DWC OTG HCD EP DISABLE:"
++ " QTD List for this endpoint is not empty\n");
++ }
++#endif
++
++ dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd, qh);
++ _ep->hcpriv = NULL;
++ }
++
++ return;
++}
++
++/** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
++ * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
++ * interrupt.
++ *
++ * This function is called by the USB core when an interrupt occurs */
++irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *_hcd)
++{
++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd);
++ return IRQ_RETVAL(dwc_otg_hcd_handle_intr(dwc_otg_hcd));
++}
++
++/** Creates Status Change bitmap for the root hub and root port. The bitmap is
++ * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
++ * is the status change indicator for the single root port. Returns 1 if either
++ * change indicator is 1, otherwise returns 0. */
++int dwc_otg_hcd_hub_status_data(struct usb_hcd *_hcd,
++ char *_buf)
++{
++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd);
++
++ _buf[0] = 0;
++ _buf[0] |= (dwc_otg_hcd->flags.b.port_connect_status_change ||
++ dwc_otg_hcd->flags.b.port_reset_change ||
++ dwc_otg_hcd->flags.b.port_enable_change ||
++ dwc_otg_hcd->flags.b.port_suspend_change ||
++ dwc_otg_hcd->flags.b.port_over_current_change) << 1;
++
++#ifdef DEBUG
++ if (_buf[0]) {
++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
++ " Root port status changed\n");
++ DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n",
++ dwc_otg_hcd->flags.b.port_connect_status_change);
++ DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n",
++ dwc_otg_hcd->flags.b.port_reset_change);
++ DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n",
++ dwc_otg_hcd->flags.b.port_enable_change);
++ DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n",
++ dwc_otg_hcd->flags.b.port_suspend_change);
++ DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n",
++ dwc_otg_hcd->flags.b.port_over_current_change);
++ }
++#endif
++ return (_buf[0] != 0);
++}
++
++#ifdef DWC_HS_ELECT_TST
++/*
++ * Quick and dirty hack to implement the HS Electrical Test
++ * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
++ *
++ * This code was copied from our userspace app "hset". It sends a
++ * Get Device Descriptor control sequence in two parts, first the
++ * Setup packet by itself, followed some time later by the In and
++ * Ack packets. Rather than trying to figure out how to add this
++ * functionality to the normal driver code, we just hijack the
++ * hardware, using these two function to drive the hardware
++ * directly.
++ */
++
++dwc_otg_core_global_regs_t *global_regs;
++dwc_otg_host_global_regs_t *hc_global_regs;
++dwc_otg_hc_regs_t *hc_regs;
++uint32_t *data_fifo;
++
++static void do_setup(void)
++{
++ gintsts_data_t gintsts;
++ hctsiz_data_t hctsiz;
++ hcchar_data_t hcchar;
++ haint_data_t haint;
++ hcint_data_t hcint;
++
++ /* Enable HAINTs */
++ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001);
++
++ /* Enable HCINTs */
++ dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3);
++
++ /* Read GINTSTS */
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
++
++ /* Read HAINT */
++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
++ //fprintf(stderr, "HAINT: %08x\n", haint.d32);
++
++ /* Read HCINT */
++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
++
++ /* Read HCCHAR */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
++
++ /* Clear HCINT */
++ dwc_write_reg32(&hc_regs->hcint, hcint.d32);
++
++ /* Clear HAINT */
++ dwc_write_reg32(&hc_global_regs->haint, haint.d32);
++
++ /* Clear GINTSTS */
++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
++
++ /* Read GINTSTS */
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
++
++ /*
++ * Send Setup packet (Get Device Descriptor)
++ */
++
++ /* Make sure channel is disabled */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ if (hcchar.b.chen) {
++ //fprintf(stderr, "Channel already enabled 1, HCCHAR = %08x\n", hcchar.d32);
++ hcchar.b.chdis = 1;
++// hcchar.b.chen = 1;
++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
++ //sleep(1);
++ mdelay(1000);
++
++ /* Read GINTSTS */
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
++
++ /* Read HAINT */
++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
++ //fprintf(stderr, "HAINT: %08x\n", haint.d32);
++
++ /* Read HCINT */
++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
++
++ /* Read HCCHAR */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
++
++ /* Clear HCINT */
++ dwc_write_reg32(&hc_regs->hcint, hcint.d32);
++
++ /* Clear HAINT */
++ dwc_write_reg32(&hc_global_regs->haint, haint.d32);
++
++ /* Clear GINTSTS */
++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
++
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ //if (hcchar.b.chen) {
++ // fprintf(stderr, "** Channel _still_ enabled 1, HCCHAR = %08x **\n", hcchar.d32);
++ //}
++ }
++
++ /* Set HCTSIZ */
++ hctsiz.d32 = 0;
++ hctsiz.b.xfersize = 8;
++ hctsiz.b.pktcnt = 1;
++ hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
++
++ /* Set HCCHAR */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
++ hcchar.b.epdir = 0;
++ hcchar.b.epnum = 0;
++ hcchar.b.mps = 8;
++ hcchar.b.chen = 1;
++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
++
++ /* Fill FIFO with Setup data for Get Device Descriptor */
++ data_fifo = (uint32_t *)((char *)global_regs + 0x1000);
++ dwc_write_reg32(data_fifo++, 0x01000680);
++ dwc_write_reg32(data_fifo++, 0x00080000);
++
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "Waiting for HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32);
++
++ /* Wait for host channel interrupt */
++ do {
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ } while (gintsts.b.hcintr == 0);
++
++ //fprintf(stderr, "Got HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32);
++
++ /* Disable HCINTs */
++ dwc_write_reg32(&hc_regs->hcintmsk, 0x0000);
++
++ /* Disable HAINTs */
++ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000);
++
++ /* Read HAINT */
++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
++ //fprintf(stderr, "HAINT: %08x\n", haint.d32);
++
++ /* Read HCINT */
++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
++
++ /* Read HCCHAR */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
++
++ /* Clear HCINT */
++ dwc_write_reg32(&hc_regs->hcint, hcint.d32);
++
++ /* Clear HAINT */
++ dwc_write_reg32(&hc_global_regs->haint, haint.d32);
++
++ /* Clear GINTSTS */
++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
++
++ /* Read GINTSTS */
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
++}
++
++static void do_in_ack(void)
++{
++ gintsts_data_t gintsts;
++ hctsiz_data_t hctsiz;
++ hcchar_data_t hcchar;
++ haint_data_t haint;
++ hcint_data_t hcint;
++ host_grxsts_data_t grxsts;
++
++ /* Enable HAINTs */
++ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001);
++
++ /* Enable HCINTs */
++ dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3);
++
++ /* Read GINTSTS */
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
++
++ /* Read HAINT */
++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
++ //fprintf(stderr, "HAINT: %08x\n", haint.d32);
++
++ /* Read HCINT */
++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
++
++ /* Read HCCHAR */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
++
++ /* Clear HCINT */
++ dwc_write_reg32(&hc_regs->hcint, hcint.d32);
++
++ /* Clear HAINT */
++ dwc_write_reg32(&hc_global_regs->haint, haint.d32);
++
++ /* Clear GINTSTS */
++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
++
++ /* Read GINTSTS */
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
++
++ /*
++ * Receive Control In packet
++ */
++
++ /* Make sure channel is disabled */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ if (hcchar.b.chen) {
++ //fprintf(stderr, "Channel already enabled 2, HCCHAR = %08x\n", hcchar.d32);
++ hcchar.b.chdis = 1;
++ hcchar.b.chen = 1;
++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
++ //sleep(1);
++ mdelay(1000);
++
++ /* Read GINTSTS */
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
++
++ /* Read HAINT */
++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
++ //fprintf(stderr, "HAINT: %08x\n", haint.d32);
++
++ /* Read HCINT */
++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
++
++ /* Read HCCHAR */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
++
++ /* Clear HCINT */
++ dwc_write_reg32(&hc_regs->hcint, hcint.d32);
++
++ /* Clear HAINT */
++ dwc_write_reg32(&hc_global_regs->haint, haint.d32);
++
++ /* Clear GINTSTS */
++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
++
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ //if (hcchar.b.chen) {
++ // fprintf(stderr, "** Channel _still_ enabled 2, HCCHAR = %08x **\n", hcchar.d32);
++ //}
++ }
++
++ /* Set HCTSIZ */
++ hctsiz.d32 = 0;
++ hctsiz.b.xfersize = 8;
++ hctsiz.b.pktcnt = 1;
++ hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
++
++ /* Set HCCHAR */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
++ hcchar.b.epdir = 1;
++ hcchar.b.epnum = 0;
++ hcchar.b.mps = 8;
++ hcchar.b.chen = 1;
++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
++
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "Waiting for RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32);
++
++ /* Wait for receive status queue interrupt */
++ do {
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ } while (gintsts.b.rxstsqlvl == 0);
++
++ //fprintf(stderr, "Got RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32);
++
++ /* Read RXSTS */
++ grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp);
++ //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32);
++
++ /* Clear RXSTSQLVL in GINTSTS */
++ gintsts.d32 = 0;
++ gintsts.b.rxstsqlvl = 1;
++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
++
++ switch (grxsts.b.pktsts) {
++ case DWC_GRXSTS_PKTSTS_IN:
++ /* Read the data into the host buffer */
++ if (grxsts.b.bcnt > 0) {
++ int i;
++ int word_count = (grxsts.b.bcnt + 3) / 4;
++
++ data_fifo = (uint32_t *)((char *)global_regs + 0x1000);
++
++ for (i = 0; i < word_count; i++) {
++ (void)dwc_read_reg32(data_fifo++);
++ }
++ }
++
++ //fprintf(stderr, "Received %u bytes\n", (unsigned)grxsts.b.bcnt);
++ break;
++
++ default:
++ //fprintf(stderr, "** Unexpected GRXSTS packet status 1 **\n");
++ break;
++ }
++
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "Waiting for RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32);
++
++ /* Wait for receive status queue interrupt */
++ do {
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ } while (gintsts.b.rxstsqlvl == 0);
++
++ //fprintf(stderr, "Got RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32);
++
++ /* Read RXSTS */
++ grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp);
++ //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32);
++
++ /* Clear RXSTSQLVL in GINTSTS */
++ gintsts.d32 = 0;
++ gintsts.b.rxstsqlvl = 1;
++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
++
++ switch (grxsts.b.pktsts) {
++ case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
++ break;
++
++ default:
++ //fprintf(stderr, "** Unexpected GRXSTS packet status 2 **\n");
++ break;
++ }
++
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "Waiting for HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32);
++
++ /* Wait for host channel interrupt */
++ do {
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ } while (gintsts.b.hcintr == 0);
++
++ //fprintf(stderr, "Got HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32);
++
++ /* Read HAINT */
++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
++ //fprintf(stderr, "HAINT: %08x\n", haint.d32);
++
++ /* Read HCINT */
++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
++
++ /* Read HCCHAR */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
++
++ /* Clear HCINT */
++ dwc_write_reg32(&hc_regs->hcint, hcint.d32);
++
++ /* Clear HAINT */
++ dwc_write_reg32(&hc_global_regs->haint, haint.d32);
++
++ /* Clear GINTSTS */
++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
++
++ /* Read GINTSTS */
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
++
++// usleep(100000);
++// mdelay(100);
++ mdelay(1);
++
++ /*
++ * Send handshake packet
++ */
++
++ /* Read HAINT */
++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
++ //fprintf(stderr, "HAINT: %08x\n", haint.d32);
++
++ /* Read HCINT */
++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
++
++ /* Read HCCHAR */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
++
++ /* Clear HCINT */
++ dwc_write_reg32(&hc_regs->hcint, hcint.d32);
++
++ /* Clear HAINT */
++ dwc_write_reg32(&hc_global_regs->haint, haint.d32);
++
++ /* Clear GINTSTS */
++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
++
++ /* Read GINTSTS */
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
++
++ /* Make sure channel is disabled */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ if (hcchar.b.chen) {
++ //fprintf(stderr, "Channel already enabled 3, HCCHAR = %08x\n", hcchar.d32);
++ hcchar.b.chdis = 1;
++ hcchar.b.chen = 1;
++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
++ //sleep(1);
++ mdelay(1000);
++
++ /* Read GINTSTS */
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
++
++ /* Read HAINT */
++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
++ //fprintf(stderr, "HAINT: %08x\n", haint.d32);
++
++ /* Read HCINT */
++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
++
++ /* Read HCCHAR */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
++
++ /* Clear HCINT */
++ dwc_write_reg32(&hc_regs->hcint, hcint.d32);
++
++ /* Clear HAINT */
++ dwc_write_reg32(&hc_global_regs->haint, haint.d32);
++
++ /* Clear GINTSTS */
++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
++
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ //if (hcchar.b.chen) {
++ // fprintf(stderr, "** Channel _still_ enabled 3, HCCHAR = %08x **\n", hcchar.d32);
++ //}
++ }
++
++ /* Set HCTSIZ */
++ hctsiz.d32 = 0;
++ hctsiz.b.xfersize = 0;
++ hctsiz.b.pktcnt = 1;
++ hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
++
++ /* Set HCCHAR */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
++ hcchar.b.epdir = 0;
++ hcchar.b.epnum = 0;
++ hcchar.b.mps = 8;
++ hcchar.b.chen = 1;
++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
++
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "Waiting for HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32);
++
++ /* Wait for host channel interrupt */
++ do {
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ } while (gintsts.b.hcintr == 0);
++
++ //fprintf(stderr, "Got HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32);
++
++ /* Disable HCINTs */
++ dwc_write_reg32(&hc_regs->hcintmsk, 0x0000);
++
++ /* Disable HAINTs */
++ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000);
++
++ /* Read HAINT */
++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
++ //fprintf(stderr, "HAINT: %08x\n", haint.d32);
++
++ /* Read HCINT */
++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32);
++
++ /* Read HCCHAR */
++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32);
++
++ /* Clear HCINT */
++ dwc_write_reg32(&hc_regs->hcint, hcint.d32);
++
++ /* Clear HAINT */
++ dwc_write_reg32(&hc_global_regs->haint, haint.d32);
++
++ /* Clear GINTSTS */
++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
++
++ /* Read GINTSTS */
++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32);
++}
++#endif /* DWC_HS_ELECT_TST */
++
++/** Handles hub class-specific requests.*/
++int dwc_otg_hcd_hub_control(struct usb_hcd *_hcd,
++ u16 _typeReq,
++ u16 _wValue,
++ u16 _wIndex,
++ char *_buf,
++ u16 _wLength)
++{
++ int retval = 0;
++
++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd);
++ dwc_otg_core_if_t *core_if = hcd_to_dwc_otg_hcd (_hcd)->core_if;
++ struct usb_hub_descriptor *desc;
++ hprt0_data_t hprt0 = {.d32 = 0};
++
++ uint32_t port_status;
++
++ switch (_typeReq) {
++ case ClearHubFeature:
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "ClearHubFeature 0x%x\n", _wValue);
++ switch (_wValue) {
++ case C_HUB_LOCAL_POWER:
++ case C_HUB_OVER_CURRENT:
++ /* Nothing required here */
++ break;
++ default:
++ retval = -EINVAL;
++ DWC_ERROR ("DWC OTG HCD - "
++ "ClearHubFeature request %xh unknown\n", _wValue);
++ }
++ break;
++ case ClearPortFeature:
++ if (!_wIndex || _wIndex > 1)
++ goto error;
++
++ switch (_wValue) {
++ case USB_PORT_FEAT_ENABLE:
++ DWC_DEBUGPL (DBG_ANY, "DWC OTG HCD HUB CONTROL - "
++ "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
++ hprt0.d32 = dwc_otg_read_hprt0 (core_if);
++ hprt0.b.prtena = 1;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++ break;
++ case USB_PORT_FEAT_SUSPEND:
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
++ hprt0.d32 = dwc_otg_read_hprt0 (core_if);
++ hprt0.b.prtres = 1;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++ /* Clear Resume bit */
++ mdelay (100);
++ hprt0.b.prtres = 0;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++ break;
++ case USB_PORT_FEAT_POWER:
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "ClearPortFeature USB_PORT_FEAT_POWER\n");
++ hprt0.d32 = dwc_otg_read_hprt0 (core_if);
++ hprt0.b.prtpwr = 0;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++ break;
++ case USB_PORT_FEAT_INDICATOR:
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
++ /* Port inidicator not supported */
++ break;
++ case USB_PORT_FEAT_C_CONNECTION:
++ /* Clears drivers internal connect status change
++ * flag */
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
++ dwc_otg_hcd->flags.b.port_connect_status_change = 0;
++ break;
++ case USB_PORT_FEAT_C_RESET:
++ /* Clears the driver's internal Port Reset Change
++ * flag */
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
++ dwc_otg_hcd->flags.b.port_reset_change = 0;
++ break;
++ case USB_PORT_FEAT_C_ENABLE:
++ /* Clears the driver's internal Port
++ * Enable/Disable Change flag */
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
++ dwc_otg_hcd->flags.b.port_enable_change = 0;
++ break;
++ case USB_PORT_FEAT_C_SUSPEND:
++ /* Clears the driver's internal Port Suspend
++ * Change flag, which is set when resume signaling on
++ * the host port is complete */
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
++ dwc_otg_hcd->flags.b.port_suspend_change = 0;
++ break;
++ case USB_PORT_FEAT_C_OVER_CURRENT:
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
++ dwc_otg_hcd->flags.b.port_over_current_change = 0;
++ break;
++ default:
++ retval = -EINVAL;
++ DWC_ERROR ("DWC OTG HCD - "
++ "ClearPortFeature request %xh "
++ "unknown or unsupported\n", _wValue);
++ }
++ break;
++ case GetHubDescriptor:
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "GetHubDescriptor\n");
++ desc = (struct usb_hub_descriptor *)_buf;
++ desc->bDescLength = 9;
++ desc->bDescriptorType = 0x29;
++ desc->bNbrPorts = 1;
++ desc->wHubCharacteristics = 0x08;
++ desc->bPwrOn2PwrGood = 1;
++ desc->bHubContrCurrent = 0;
++ desc->bitmap[0] = 0;
++ desc->bitmap[1] = 0xff;
++ break;
++ case GetHubStatus:
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "GetHubStatus\n");
++ memset (_buf, 0, 4);
++ break;
++ case GetPortStatus:
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "GetPortStatus\n");
++
++ if (!_wIndex || _wIndex > 1)
++ goto error;
++
++ port_status = 0;
++
++ if (dwc_otg_hcd->flags.b.port_connect_status_change)
++ port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
++
++ if (dwc_otg_hcd->flags.b.port_enable_change)
++ port_status |= (1 << USB_PORT_FEAT_C_ENABLE);
++
++ if (dwc_otg_hcd->flags.b.port_suspend_change)
++ port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
++
++ if (dwc_otg_hcd->flags.b.port_reset_change)
++ port_status |= (1 << USB_PORT_FEAT_C_RESET);
++
++ if (dwc_otg_hcd->flags.b.port_over_current_change) {
++ DWC_ERROR("Device Not Supported\n");
++ port_status |= (1 << USB_PORT_FEAT_C_OVER_CURRENT);
++ }
++
++ if (!dwc_otg_hcd->flags.b.port_connect_status) {
++ /*
++ * The port is disconnected, which means the core is
++ * either in device mode or it soon will be. Just
++ * return 0's for the remainder of the port status
++ * since the port register can't be read if the core
++ * is in device mode.
++ */
++ *((__le32 *) _buf) = cpu_to_le32(port_status);
++ break;
++ }
++
++ hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
++ DWC_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32);
++
++ if (hprt0.b.prtconnsts)
++ port_status |= (1 << USB_PORT_FEAT_CONNECTION);
++
++ if (hprt0.b.prtena)
++ port_status |= (1 << USB_PORT_FEAT_ENABLE);
++
++ if (hprt0.b.prtsusp)
++ port_status |= (1 << USB_PORT_FEAT_SUSPEND);
++
++ if (hprt0.b.prtovrcurract)
++ port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT);
++
++ if (hprt0.b.prtrst)
++ port_status |= (1 << USB_PORT_FEAT_RESET);
++
++ if (hprt0.b.prtpwr)
++ port_status |= (1 << USB_PORT_FEAT_POWER);
++
++ if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
++ port_status |= (1 << USB_PORT_FEAT_HIGHSPEED);
++ else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
++ port_status |= (1 << USB_PORT_FEAT_LOWSPEED);
++
++ if (hprt0.b.prttstctl)
++ port_status |= (1 << USB_PORT_FEAT_TEST);
++
++ /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
++
++ *((__le32 *) _buf) = cpu_to_le32(port_status);
++
++ break;
++ case SetHubFeature:
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "SetHubFeature\n");
++ /* No HUB features supported */
++ break;
++ case SetPortFeature:
++ if (_wValue != USB_PORT_FEAT_TEST && (!_wIndex || _wIndex > 1))
++ goto error;
++
++ if (!dwc_otg_hcd->flags.b.port_connect_status) {
++ /*
++ * The port is disconnected, which means the core is
++ * either in device mode or it soon will be. Just
++ * return without doing anything since the port
++ * register can't be written if the core is in device
++ * mode.
++ */
++ break;
++ }
++
++ switch (_wValue) {
++ case USB_PORT_FEAT_SUSPEND:
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
++ if (_hcd->self.otg_port == _wIndex &&
++ _hcd->self.b_hnp_enable) {
++ gotgctl_data_t gotgctl = {.d32=0};
++ gotgctl.b.hstsethnpen = 1;
++ dwc_modify_reg32( &core_if->core_global_regs->gotgctl,
++ 0, gotgctl.d32);
++ core_if->op_state = A_SUSPEND;
++ }
++ hprt0.d32 = dwc_otg_read_hprt0 (core_if);
++ hprt0.b.prtsusp = 1;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++ //DWC_PRINT( "SUSPEND: HPRT0=%0x\n", hprt0.d32);
++ /* Suspend the Phy Clock */
++ {
++ pcgcctl_data_t pcgcctl = {.d32=0};
++ pcgcctl.b.stoppclk = 1;
++ dwc_write_reg32(core_if->pcgcctl, pcgcctl.d32);
++ }
++
++ /* For HNP the bus must be suspended for at least 200ms.*/
++ if (_hcd->self.b_hnp_enable) {
++ mdelay(200);
++ //DWC_PRINT( "SUSPEND: wait complete! (%d)\n", _hcd->state);
++ }
++ break;
++ case USB_PORT_FEAT_POWER:
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "SetPortFeature - USB_PORT_FEAT_POWER\n");
++ hprt0.d32 = dwc_otg_read_hprt0 (core_if);
++ hprt0.b.prtpwr = 1;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++ break;
++ case USB_PORT_FEAT_RESET:
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "SetPortFeature - USB_PORT_FEAT_RESET\n");
++ hprt0.d32 = dwc_otg_read_hprt0 (core_if);
++ /* When B-Host the Port reset bit is set in
++ * the Start HCD Callback function, so that
++ * the reset is started within 1ms of the HNP
++ * success interrupt. */
++ if (!_hcd->self.is_b_host) {
++ hprt0.b.prtrst = 1;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++ }
++ /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
++ MDELAY (60);
++ hprt0.b.prtrst = 0;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++ break;
++
++#ifdef DWC_HS_ELECT_TST
++ case USB_PORT_FEAT_TEST:
++ {
++ uint32_t t;
++ gintmsk_data_t gintmsk;
++
++ t = (_wIndex >> 8); /* MSB wIndex USB */
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "SetPortFeature - USB_PORT_FEAT_TEST %d\n", t);
++ warn("USB_PORT_FEAT_TEST %d\n", t);
++ if (t < 6) {
++ hprt0.d32 = dwc_otg_read_hprt0 (core_if);
++ hprt0.b.prttstctl = t;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++ } else {
++ /* Setup global vars with reg addresses (quick and
++ * dirty hack, should be cleaned up)
++ */
++ global_regs = core_if->core_global_regs;
++ hc_global_regs = core_if->host_if->host_global_regs;
++ hc_regs = (dwc_otg_hc_regs_t *)((char *)global_regs + 0x500);
++ data_fifo = (uint32_t *)((char *)global_regs + 0x1000);
++
++ if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */
++ /* Save current interrupt mask */
++ gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk);
++
++ /* Disable all interrupts while we muck with
++ * the hardware directly
++ */
++ dwc_write_reg32(&global_regs->gintmsk, 0);
++
++ /* 15 second delay per the test spec */
++ mdelay(15000);
++
++ /* Drive suspend on the root port */
++ hprt0.d32 = dwc_otg_read_hprt0 (core_if);
++ hprt0.b.prtsusp = 1;
++ hprt0.b.prtres = 0;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++
++ /* 15 second delay per the test spec */
++ mdelay(15000);
++
++ /* Drive resume on the root port */
++ hprt0.d32 = dwc_otg_read_hprt0 (core_if);
++ hprt0.b.prtsusp = 0;
++ hprt0.b.prtres = 1;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++ mdelay(100);
++
++ /* Clear the resume bit */
++ hprt0.b.prtres = 0;
++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
++
++ /* Restore interrupts */
++ dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32);
++ } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
++ /* Save current interrupt mask */
++ gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk);
++
++ /* Disable all interrupts while we muck with
++ * the hardware directly
++ */
++ dwc_write_reg32(&global_regs->gintmsk, 0);
++
++ /* 15 second delay per the test spec */
++ mdelay(15000);
++
++ /* Send the Setup packet */
++ do_setup();
++
++ /* 15 second delay so nothing else happens for awhile */
++ mdelay(15000);
++
++ /* Restore interrupts */
++ dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32);
++ } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
++ /* Save current interrupt mask */
++ gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk);
++
++ /* Disable all interrupts while we muck with
++ * the hardware directly
++ */
++ dwc_write_reg32(&global_regs->gintmsk, 0);
++
++ /* Send the Setup packet */
++ do_setup();
++
++ /* 15 second delay so nothing else happens for awhile */
++ mdelay(15000);
++
++ /* Send the In and Ack packets */
++ do_in_ack();
++
++ /* 15 second delay so nothing else happens for awhile */
++ mdelay(15000);
++
++ /* Restore interrupts */
++ dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32);
++ }
++ }
++ break;
++ }
++#endif /* DWC_HS_ELECT_TST */
++
++ case USB_PORT_FEAT_INDICATOR:
++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - "
++ "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
++ /* Not supported */
++ break;
++ default:
++ retval = -EINVAL;
++ DWC_ERROR ("DWC OTG HCD - "
++ "SetPortFeature request %xh "
++ "unknown or unsupported\n", _wValue);
++ break;
++ }
++ break;
++ default:
++error:
++ retval = -EINVAL;
++ DWC_WARN ("DWC OTG HCD - "
++ "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
++ _typeReq, _wIndex, _wValue);
++ break;
++ }
++
++ return retval;
++}
++
++
++/**
++ * Assigns transactions from a QTD to a free host channel and initializes the
++ * host channel to perform the transactions. The host channel is removed from
++ * the free list.
++ *
++ * @param _hcd The HCD state structure.
++ * @param _qh Transactions from the first QTD for this QH are selected and
++ * assigned to a free host channel.
++ */
++static void assign_and_init_hc(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh)
++{
++ dwc_hc_t *hc;
++ dwc_otg_qtd_t *qtd;
++ struct urb *urb;
++
++ DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, _hcd, _qh);
++
++ hc = list_entry(_hcd->free_hc_list.next, dwc_hc_t, hc_list_entry);
++
++ /* Remove the host channel from the free list. */
++ list_del_init(&hc->hc_list_entry);
++
++ qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry);
++ urb = qtd->urb;
++ _qh->channel = hc;
++ _qh->qtd_in_process = qtd;
++
++ /*
++ * Use usb_pipedevice to determine device address. This address is
++ * 0 before the SET_ADDRESS command and the correct address afterward.
++ */
++ hc->dev_addr = usb_pipedevice(urb->pipe);
++ hc->ep_num = usb_pipeendpoint(urb->pipe);
++
++ if (urb->dev->speed == USB_SPEED_LOW) {
++ hc->speed = DWC_OTG_EP_SPEED_LOW;
++ } else if (urb->dev->speed == USB_SPEED_FULL) {
++ hc->speed = DWC_OTG_EP_SPEED_FULL;
++ } else {
++ hc->speed = DWC_OTG_EP_SPEED_HIGH;
++ }
++
++ hc->max_packet = dwc_max_packet(_qh->maxp);
++
++ hc->xfer_started = 0;
++ hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
++ hc->error_state = (qtd->error_count > 0);
++ hc->halt_on_queue = 0;
++ hc->halt_pending = 0;
++ hc->requests = 0;
++
++ /*
++ * The following values may be modified in the transfer type section
++ * below. The xfer_len value may be reduced when the transfer is
++ * started to accommodate the max widths of the XferSize and PktCnt
++ * fields in the HCTSIZn register.
++ */
++ hc->do_ping = _qh->ping_state;
++ hc->ep_is_in = (usb_pipein(urb->pipe) != 0);
++ hc->data_pid_start = _qh->data_toggle;
++ hc->multi_count = 1;
++
++ if (_hcd->core_if->dma_enable) {
++ hc->xfer_buff = (uint8_t *)urb->transfer_dma + urb->actual_length;
++ } else {
++ hc->xfer_buff = (uint8_t *)urb->transfer_buffer + urb->actual_length;
++ }
++ hc->xfer_len = urb->transfer_buffer_length - urb->actual_length;
++ hc->xfer_count = 0;
++
++ /*
++ * Set the split attributes
++ */
++ hc->do_split = 0;
++ if (_qh->do_split) {
++ hc->do_split = 1;
++ hc->xact_pos = qtd->isoc_split_pos;
++ hc->complete_split = qtd->complete_split;
++ hc->hub_addr = urb->dev->tt->hub->devnum;
++ hc->port_addr = urb->dev->ttport;
++ }
++
++ switch (usb_pipetype(urb->pipe)) {
++ case PIPE_CONTROL:
++ hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
++ switch (qtd->control_phase) {
++ case DWC_OTG_CONTROL_SETUP:
++ DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n");
++ hc->do_ping = 0;
++ hc->ep_is_in = 0;
++ hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
++ if (_hcd->core_if->dma_enable) {
++ hc->xfer_buff = (uint8_t *)urb->setup_dma;
++ } else {
++ hc->xfer_buff = (uint8_t *)urb->setup_packet;
++ }
++ hc->xfer_len = 8;
++ break;
++ case DWC_OTG_CONTROL_DATA:
++ DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n");
++ hc->data_pid_start = qtd->data_toggle;
++ break;
++ case DWC_OTG_CONTROL_STATUS:
++ /*
++ * Direction is opposite of data direction or IN if no
++ * data.
++ */
++ DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n");
++ if (urb->transfer_buffer_length == 0) {
++ hc->ep_is_in = 1;
++ } else {
++ hc->ep_is_in = (usb_pipein(urb->pipe) != USB_DIR_IN);
++ }
++ if (hc->ep_is_in) {
++ hc->do_ping = 0;
++ }
++ hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
++ hc->xfer_len = 0;
++ if (_hcd->core_if->dma_enable) {
++ hc->xfer_buff = (uint8_t *)_hcd->status_buf_dma;
++ } else {
++ hc->xfer_buff = (uint8_t *)_hcd->status_buf;
++ }
++ break;
++ }
++ break;
++ case PIPE_BULK:
++ hc->ep_type = DWC_OTG_EP_TYPE_BULK;
++ break;
++ case PIPE_INTERRUPT:
++ hc->ep_type = DWC_OTG_EP_TYPE_INTR;
++ break;
++ case PIPE_ISOCHRONOUS:
++ {
++ struct usb_iso_packet_descriptor *frame_desc;
++ frame_desc = &urb->iso_frame_desc[qtd->isoc_frame_index];
++ hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
++ if (_hcd->core_if->dma_enable) {
++ hc->xfer_buff = (uint8_t *)urb->transfer_dma;
++ } else {
++ hc->xfer_buff = (uint8_t *)urb->transfer_buffer;
++ }
++ hc->xfer_buff += frame_desc->offset + qtd->isoc_split_offset;
++ hc->xfer_len = frame_desc->length - qtd->isoc_split_offset;
++
++ if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
++ if (hc->xfer_len <= 188) {
++ hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
++ }
++ else {
++ hc->xact_pos = DWC_HCSPLIT_XACTPOS_BEGIN;
++ }
++ }
++ }
++ break;
++ }
++
++ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++ hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
++ /*
++ * This value may be modified when the transfer is started to
++ * reflect the actual transfer length.
++ */
++ hc->multi_count = dwc_hb_mult(_qh->maxp);
++ }
++
++ dwc_otg_hc_init(_hcd->core_if, hc);
++ hc->qh = _qh;
++}
++
++/**
++ * This function selects transactions from the HCD transfer schedule and
++ * assigns them to available host channels. It is called from HCD interrupt
++ * handler functions.
++ *
++ * @param _hcd The HCD state structure.
++ *
++ * @return The types of new transactions that were assigned to host channels.
++ */
++dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd)
++{
++ struct list_head *qh_ptr;
++ dwc_otg_qh_t *qh;
++ int num_channels;
++ dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
++
++#ifdef DEBUG_SOF
++ DWC_DEBUGPL(DBG_HCD, " Select Transactions\n");
++#endif
++
++ /* Process entries in the periodic ready list. */
++ qh_ptr = _hcd->periodic_sched_ready.next;
++ while (qh_ptr != &_hcd->periodic_sched_ready &&
++ !list_empty(&_hcd->free_hc_list)) {
++
++ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry);
++ assign_and_init_hc(_hcd, qh);
++
++ /*
++ * Move the QH from the periodic ready schedule to the
++ * periodic assigned schedule.
++ */
++ qh_ptr = qh_ptr->next;
++ list_move(&qh->qh_list_entry, &_hcd->periodic_sched_assigned);
++
++ ret_val = DWC_OTG_TRANSACTION_PERIODIC;
++ }
++
++ /*
++ * Process entries in the inactive portion of the non-periodic
++ * schedule. Some free host channels may not be used if they are
++ * reserved for periodic transfers.
++ */
++ qh_ptr = _hcd->non_periodic_sched_inactive.next;
++ num_channels = _hcd->core_if->core_params->host_channels;
++ while (qh_ptr != &_hcd->non_periodic_sched_inactive &&
++ (_hcd->non_periodic_channels <
++ num_channels - _hcd->periodic_channels) &&
++ !list_empty(&_hcd->free_hc_list)) {
++
++ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry);
++ assign_and_init_hc(_hcd, qh);
++
++ /*
++ * Move the QH from the non-periodic inactive schedule to the
++ * non-periodic active schedule.
++ */
++ qh_ptr = qh_ptr->next;
++ list_move(&qh->qh_list_entry, &_hcd->non_periodic_sched_active);
++
++ if (ret_val == DWC_OTG_TRANSACTION_NONE) {
++ ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
++ } else {
++ ret_val = DWC_OTG_TRANSACTION_ALL;
++ }
++
++ _hcd->non_periodic_channels++;
++ }
++
++ return ret_val;
++}
++
++/**
++ * Attempts to queue a single transaction request for a host channel
++ * associated with either a periodic or non-periodic transfer. This function
++ * assumes that there is space available in the appropriate request queue. For
++ * an OUT transfer or SETUP transaction in Slave mode, it checks whether space
++ * is available in the appropriate Tx FIFO.
++ *
++ * @param _hcd The HCD state structure.
++ * @param _hc Host channel descriptor associated with either a periodic or
++ * non-periodic transfer.
++ * @param _fifo_dwords_avail Number of DWORDs available in the periodic Tx
++ * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic
++ * transfers.
++ *
++ * @return 1 if a request is queued and more requests may be needed to
++ * complete the transfer, 0 if no more requests are required for this
++ * transfer, -1 if there is insufficient space in the Tx FIFO.
++ */
++static int queue_transaction(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ uint16_t _fifo_dwords_avail)
++{
++ int retval;
++
++ if (_hcd->core_if->dma_enable) {
++ if (!_hc->xfer_started) {
++ dwc_otg_hc_start_transfer(_hcd->core_if, _hc);
++ _hc->qh->ping_state = 0;
++ }
++ retval = 0;
++ } else if (_hc->halt_pending) {
++ /* Don't queue a request if the channel has been halted. */
++ retval = 0;
++ } else if (_hc->halt_on_queue) {
++ dwc_otg_hc_halt(_hcd->core_if, _hc, _hc->halt_status);
++ retval = 0;
++ } else if (_hc->do_ping) {
++ if (!_hc->xfer_started) {
++ dwc_otg_hc_start_transfer(_hcd->core_if, _hc);
++ }
++ retval = 0;
++ } else if (!_hc->ep_is_in ||
++ _hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
++ if ((_fifo_dwords_avail * 4) >= _hc->max_packet) {
++ if (!_hc->xfer_started) {
++ dwc_otg_hc_start_transfer(_hcd->core_if, _hc);
++ retval = 1;
++ } else {
++ retval = dwc_otg_hc_continue_transfer(_hcd->core_if, _hc);
++ }
++ } else {
++ retval = -1;
++ }
++ } else {
++ if (!_hc->xfer_started) {
++ dwc_otg_hc_start_transfer(_hcd->core_if, _hc);
++ retval = 1;
++ } else {
++ retval = dwc_otg_hc_continue_transfer(_hcd->core_if, _hc);
++ }
++ }
++
++ return retval;
++}
++
++/**
++ * Processes active non-periodic channels and queues transactions for these
++ * channels to the DWC_otg controller. After queueing transactions, the NP Tx
++ * FIFO Empty interrupt is enabled if there are more transactions to queue as
++ * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
++ * FIFO Empty interrupt is disabled.
++ */
++static void process_non_periodic_channels(dwc_otg_hcd_t *_hcd)
++{
++ gnptxsts_data_t tx_status;
++ struct list_head *orig_qh_ptr;
++ dwc_otg_qh_t *qh;
++ int status;
++ int no_queue_space = 0;
++ int no_fifo_space = 0;
++ int more_to_do = 0;
++
++ dwc_otg_core_global_regs_t *global_regs = _hcd->core_if->core_global_regs;
++
++ DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
++#ifdef DEBUG
++ tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts);
++ DWC_DEBUGPL(DBG_HCDV, " NP Tx Req Queue Space Avail (before queue): %d\n",
++ tx_status.b.nptxqspcavail);
++ DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n",
++ tx_status.b.nptxfspcavail);
++#endif
++ /*
++ * Keep track of the starting point. Skip over the start-of-list
++ * entry.
++ */
++ if (_hcd->non_periodic_qh_ptr == &_hcd->non_periodic_sched_active) {
++ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next;
++ }
++ orig_qh_ptr = _hcd->non_periodic_qh_ptr;
++
++ /*
++ * Process once through the active list or until no more space is
++ * available in the request queue or the Tx FIFO.
++ */
++ do {
++ tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts);
++ if (!_hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) {
++ no_queue_space = 1;
++ break;
++ }
++
++ qh = list_entry(_hcd->non_periodic_qh_ptr, dwc_otg_qh_t, qh_list_entry);
++ status = queue_transaction(_hcd, qh->channel, tx_status.b.nptxfspcavail);
++
++ if (status > 0) {
++ more_to_do = 1;
++ } else if (status < 0) {
++ no_fifo_space = 1;
++ break;
++ }
++
++ /* Advance to next QH, skipping start-of-list entry. */
++ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next;
++ if (_hcd->non_periodic_qh_ptr == &_hcd->non_periodic_sched_active) {
++ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next;
++ }
++
++ } while (_hcd->non_periodic_qh_ptr != orig_qh_ptr);
++
++ if (!_hcd->core_if->dma_enable) {
++ gintmsk_data_t intr_mask = {.d32 = 0};
++ intr_mask.b.nptxfempty = 1;
++
++#ifdef DEBUG
++ tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts);
++ DWC_DEBUGPL(DBG_HCDV, " NP Tx Req Queue Space Avail (after queue): %d\n",
++ tx_status.b.nptxqspcavail);
++ DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (after queue): %d\n",
++ tx_status.b.nptxfspcavail);
++#endif
++ if (more_to_do || no_queue_space || no_fifo_space) {
++ /*
++ * May need to queue more transactions as the request
++ * queue or Tx FIFO empties. Enable the non-periodic
++ * Tx FIFO empty interrupt. (Always use the half-empty
++ * level to ensure that new requests are loaded as
++ * soon as possible.)
++ */
++ dwc_modify_reg32(&global_regs->gintmsk, 0, intr_mask.d32);
++ } else {
++ /*
++ * Disable the Tx FIFO empty interrupt since there are
++ * no more transactions that need to be queued right
++ * now. This function is called from interrupt
++ * handlers to queue more transactions as transfer
++ * states change.
++ */
++ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0);
++ }
++ }
++}
++
++/**
++ * Processes periodic channels for the next frame and queues transactions for
++ * these channels to the DWC_otg controller. After queueing transactions, the
++ * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
++ * to queue as Periodic Tx FIFO or request queue space becomes available.
++ * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
++ */
++static void process_periodic_channels(dwc_otg_hcd_t *_hcd)
++{
++ hptxsts_data_t tx_status;
++ struct list_head *qh_ptr;
++ dwc_otg_qh_t *qh;
++ int status;
++ int no_queue_space = 0;
++ int no_fifo_space = 0;
++
++ dwc_otg_host_global_regs_t *host_regs;
++ host_regs = _hcd->core_if->host_if->host_global_regs;
++
++ DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
++#ifdef DEBUG
++ tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts);
++ DWC_DEBUGPL(DBG_HCDV, " P Tx Req Queue Space Avail (before queue): %d\n",
++ tx_status.b.ptxqspcavail);
++ DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n",
++ tx_status.b.ptxfspcavail);
++#endif
++
++ qh_ptr = _hcd->periodic_sched_assigned.next;
++ while (qh_ptr != &_hcd->periodic_sched_assigned) {
++ tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts);
++ if (tx_status.b.ptxqspcavail == 0) {
++ no_queue_space = 1;
++ break;
++ }
++
++ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry);
++
++ /*
++ * Set a flag if we're queuing high-bandwidth in slave mode.
++ * The flag prevents any halts to get into the request queue in
++ * the middle of multiple high-bandwidth packets getting queued.
++ */
++ if ((!_hcd->core_if->dma_enable) &&
++ (qh->channel->multi_count > 1))
++ {
++ _hcd->core_if->queuing_high_bandwidth = 1;
++ }
++
++ status = queue_transaction(_hcd, qh->channel, tx_status.b.ptxfspcavail);
++ if (status < 0) {
++ no_fifo_space = 1;
++ break;
++ }
++
++ /*
++ * In Slave mode, stay on the current transfer until there is
++ * nothing more to do or the high-bandwidth request count is
++ * reached. In DMA mode, only need to queue one request. The
++ * controller automatically handles multiple packets for
++ * high-bandwidth transfers.
++ */
++ if (_hcd->core_if->dma_enable ||
++ (status == 0 ||
++ qh->channel->requests == qh->channel->multi_count)) {
++ qh_ptr = qh_ptr->next;
++ /*
++ * Move the QH from the periodic assigned schedule to
++ * the periodic queued schedule.
++ */
++ list_move(&qh->qh_list_entry, &_hcd->periodic_sched_queued);
++
++ /* done queuing high bandwidth */
++ _hcd->core_if->queuing_high_bandwidth = 0;
++ }
++ }
++
++ if (!_hcd->core_if->dma_enable) {
++ dwc_otg_core_global_regs_t *global_regs;
++ gintmsk_data_t intr_mask = {.d32 = 0};
++
++ global_regs = _hcd->core_if->core_global_regs;
++ intr_mask.b.ptxfempty = 1;
++#ifdef DEBUG
++ tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts);
++ DWC_DEBUGPL(DBG_HCDV, " P Tx Req Queue Space Avail (after queue): %d\n",
++ tx_status.b.ptxqspcavail);
++ DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (after queue): %d\n",
++ tx_status.b.ptxfspcavail);
++#endif
++ if (!(list_empty(&_hcd->periodic_sched_assigned)) ||
++ no_queue_space || no_fifo_space) {
++ /*
++ * May need to queue more transactions as the request
++ * queue or Tx FIFO empties. Enable the periodic Tx
++ * FIFO empty interrupt. (Always use the half-empty
++ * level to ensure that new requests are loaded as
++ * soon as possible.)
++ */
++ dwc_modify_reg32(&global_regs->gintmsk, 0, intr_mask.d32);
++ } else {
++ /*
++ * Disable the Tx FIFO empty interrupt since there are
++ * no more transactions that need to be queued right
++ * now. This function is called from interrupt
++ * handlers to queue more transactions as transfer
++ * states change.
++ */
++ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0);
++ }
++ }
++}
++
++/**
++ * This function processes the currently active host channels and queues
++ * transactions for these channels to the DWC_otg controller. It is called
++ * from HCD interrupt handler functions.
++ *
++ * @param _hcd The HCD state structure.
++ * @param _tr_type The type(s) of transactions to queue (non-periodic,
++ * periodic, or both).
++ */
++void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t *_hcd,
++ dwc_otg_transaction_type_e _tr_type)
++{
++#ifdef DEBUG_SOF
++ DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
++#endif
++ /* Process host channels associated with periodic transfers. */
++ if ((_tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
++ _tr_type == DWC_OTG_TRANSACTION_ALL) &&
++ !list_empty(&_hcd->periodic_sched_assigned)) {
++
++ process_periodic_channels(_hcd);
++ }
++
++ /* Process host channels associated with non-periodic transfers. */
++ if ((_tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
++ _tr_type == DWC_OTG_TRANSACTION_ALL)) {
++ if (!list_empty(&_hcd->non_periodic_sched_active)) {
++ process_non_periodic_channels(_hcd);
++ } else {
++ /*
++ * Ensure NP Tx FIFO empty interrupt is disabled when
++ * there are no non-periodic transfers to process.
++ */
++ gintmsk_data_t gintmsk = {.d32 = 0};
++ gintmsk.b.nptxfempty = 1;
++ dwc_modify_reg32(&_hcd->core_if->core_global_regs->gintmsk,
++ gintmsk.d32, 0);
++ }
++ }
++}
++
++/**
++ * Sets the final status of an URB and returns it to the device driver. Any
++ * required cleanup of the URB is performed.
++ */
++void dwc_otg_hcd_complete_urb(dwc_otg_hcd_t *_hcd, struct urb *_urb, int _status)
++{
++
++#ifdef DEBUG
++ if (CHK_DEBUG_LEVEL(DBG_HCD_URB))
++ DWC_PRINT("%s: urb %p, device %d, ep %d %s, status=%d\n",
++ __func__, _urb, usb_pipedevice(_urb->pipe),
++ usb_pipeendpoint(_urb->pipe),
++ usb_pipein(_urb->pipe) ? "IN" : "OUT", _status);
++ if (usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) {
++ int i;
++ for (i = 0; i < _urb->number_of_packets; i++) {
++ DWC_PRINT(" ISO Desc %d status: %d\n",
++ i, _urb->iso_frame_desc[i].status);
++ }
++ }
++#endif
++
++ _urb->status = _status;
++ _urb->hcpriv = NULL;
++ usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(_hcd), _urb, _status);
++}
++
++/*
++ * Returns the Queue Head for an URB.
++ */
++dwc_otg_qh_t *dwc_urb_to_qh(struct urb *_urb)
++{
++ struct usb_host_endpoint *ep = dwc_urb_to_endpoint(_urb);
++ return (dwc_otg_qh_t *)ep->hcpriv;
++}
++
++#ifdef DEBUG
++void dwc_print_setup_data (uint8_t *setup)
++{
++ int i;
++ if (CHK_DEBUG_LEVEL(DBG_HCD)){
++ DWC_PRINT("Setup Data = MSB ");
++ for (i=7; i>=0; i--) DWC_PRINT ("%02x ", setup[i]);
++ DWC_PRINT("\n");
++ DWC_PRINT(" bmRequestType Tranfer = %s\n", (setup[0]&0x80) ? "Device-to-Host" : "Host-to-Device");
++ DWC_PRINT(" bmRequestType Type = ");
++ switch ((setup[0]&0x60) >> 5) {
++ case 0: DWC_PRINT("Standard\n"); break;
++ case 1: DWC_PRINT("Class\n"); break;
++ case 2: DWC_PRINT("Vendor\n"); break;
++ case 3: DWC_PRINT("Reserved\n"); break;
++ }
++ DWC_PRINT(" bmRequestType Recipient = ");
++ switch (setup[0]&0x1f) {
++ case 0: DWC_PRINT("Device\n"); break;
++ case 1: DWC_PRINT("Interface\n"); break;
++ case 2: DWC_PRINT("Endpoint\n"); break;
++ case 3: DWC_PRINT("Other\n"); break;
++ default: DWC_PRINT("Reserved\n"); break;
++ }
++ DWC_PRINT(" bRequest = 0x%0x\n", setup[1]);
++ DWC_PRINT(" wValue = 0x%0x\n", *((uint16_t *)&setup[2]));
++ DWC_PRINT(" wIndex = 0x%0x\n", *((uint16_t *)&setup[4]));
++ DWC_PRINT(" wLength = 0x%0x\n\n", *((uint16_t *)&setup[6]));
++ }
++}
++#endif
++
++void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t *_hcd) {
++#ifdef DEBUG
++ DWC_PRINT("Frame remaining at SOF:\n");
++ DWC_PRINT(" samples %u, accum %llu, avg %llu/%u\n",
++ _hcd->frrem_samples, _hcd->frrem_accum,
++ _hcd->frrem_accum, _hcd->frrem_samples);
++ //DWC_PRINT(" samples %u, accum %llu, avg %llu\n", //[TCC] FIXME: NOT SUPPORT 64Bit division!!!
++ // _hcd->frrem_samples, _hcd->frrem_accum,
++ // (_hcd->frrem_samples > 0) ?
++ // _hcd->frrem_accum/_hcd->frrem_samples : 0);
++
++ DWC_PRINT("\n");
++ DWC_PRINT("Frame remaining at start_transfer (uframe 7):\n");
++ DWC_PRINT(" samples %u, accum %llu, avg %llu/%u\n",
++ _hcd->core_if->hfnum_7_samples, _hcd->core_if->hfnum_7_frrem_accum,
++ _hcd->core_if->hfnum_7_frrem_accum, _hcd->core_if->hfnum_7_samples);
++ //DWC_PRINT(" samples %u, accum %llu, avg %llu\n",
++ // _hcd->core_if->hfnum_7_samples, _hcd->core_if->hfnum_7_frrem_accum,
++ // (_hcd->core_if->hfnum_7_samples > 0) ?
++ // _hcd->core_if->hfnum_7_frrem_accum/_hcd->core_if->hfnum_7_samples : 0);
++ DWC_PRINT("Frame remaining at start_transfer (uframe 0):\n");
++ DWC_PRINT(" samples %u, accum %llu, avg %llu/%u\n",
++ _hcd->core_if->hfnum_0_samples, _hcd->core_if->hfnum_0_frrem_accum,
++ _hcd->core_if->hfnum_0_frrem_accum, _hcd->core_if->hfnum_0_samples);
++ //DWC_PRINT(" samples %u, accum %llu, avg %llu\n",
++ // _hcd->core_if->hfnum_0_samples, _hcd->core_if->hfnum_0_frrem_accum,
++ // (_hcd->core_if->hfnum_0_samples > 0) ?
++ // _hcd->core_if->hfnum_0_frrem_accum/_hcd->core_if->hfnum_0_samples : 0);
++ DWC_PRINT("Frame remaining at start_transfer (uframe 1-6):\n");
++ DWC_PRINT(" samples %u, accum %llu, avg %llu/%u\n",
++ _hcd->core_if->hfnum_other_samples, _hcd->core_if->hfnum_other_frrem_accum,
++ _hcd->core_if->hfnum_other_frrem_accum, _hcd->core_if->hfnum_other_samples);
++ //DWC_PRINT(" samples %u, accum %llu, avg %llu\n",
++ // _hcd->core_if->hfnum_other_samples, _hcd->core_if->hfnum_other_frrem_accum,
++ // (_hcd->core_if->hfnum_other_samples > 0) ?
++ // _hcd->core_if->hfnum_other_frrem_accum/_hcd->core_if->hfnum_other_samples : 0);
++
++ DWC_PRINT("\n");
++ DWC_PRINT("Frame remaining at sample point A (uframe 7):\n");
++ DWC_PRINT(" samples %u, accum %llu, avg %llu/%u\n",
++ _hcd->hfnum_7_samples_a, _hcd->hfnum_7_frrem_accum_a,
++ _hcd->hfnum_7_frrem_accum_a, _hcd->hfnum_7_samples_a);
++ //DWC_PRINT(" samples %u, accum %llu, avg %llu\n",
++ // _hcd->hfnum_7_samples_a, _hcd->hfnum_7_frrem_accum_a,
++ // (_hcd->hfnum_7_samples_a > 0) ?
++ // _hcd->hfnum_7_frrem_accum_a/_hcd->hfnum_7_samples_a : 0);
++ DWC_PRINT("Frame remaining at sample point A (uframe 0):\n");
++ DWC_PRINT(" samples %u, accum %llu, avg %llu/%u\n",
++ _hcd->hfnum_0_samples_a, _hcd->hfnum_0_frrem_accum_a,
++ _hcd->hfnum_0_frrem_accum_a, _hcd->hfnum_0_samples_a);
++ //DWC_PRINT(" samples %u, accum %llu, avg %llu\n",
++ // _hcd->hfnum_0_samples_a, _hcd->hfnum_0_frrem_accum_a,
++ // (_hcd->hfnum_0_samples_a > 0) ?
++ // _hcd->hfnum_0_frrem_accum_a/_hcd->hfnum_0_samples_a : 0);
++ DWC_PRINT("Frame remaining at sample point A (uframe 1-6):\n");
++ DWC_PRINT(" samples %u, accum %llu, avg %llu/%u\n",
++ _hcd->hfnum_other_samples_a, _hcd->hfnum_other_frrem_accum_a,
++ _hcd->hfnum_other_frrem_accum_a, _hcd->hfnum_other_samples_a);
++ //DWC_PRINT(" samples %u, accum %llu, avg %llu\n",
++ // _hcd->hfnum_other_samples_a, _hcd->hfnum_other_frrem_accum_a,
++ // (_hcd->hfnum_other_samples_a > 0) ?
++ // _hcd->hfnum_other_frrem_accum_a/_hcd->hfnum_other_samples_a : 0);
++
++ DWC_PRINT("\n");
++ DWC_PRINT("Frame remaining at sample point B (uframe 7):\n");
++ DWC_PRINT(" samples %u, accum %llu, avg %llu/%u\n",
++ _hcd->hfnum_7_samples_b, _hcd->hfnum_7_frrem_accum_b,
++ _hcd->hfnum_7_frrem_accum_b, _hcd->hfnum_7_samples_b);
++ //DWC_PRINT(" samples %u, accum %llu, avg %llu\n",
++ // _hcd->hfnum_7_samples_b, _hcd->hfnum_7_frrem_accum_b,
++ // (_hcd->hfnum_7_samples_b > 0) ?
++ // _hcd->hfnum_7_frrem_accum_b/_hcd->hfnum_7_samples_b : 0);
++ DWC_PRINT("Frame remaining at sample point B (uframe 0):\n");
++ DWC_PRINT(" samples %u, accum %llu, avg %llu/%u\n",
++ _hcd->hfnum_0_samples_b, _hcd->hfnum_0_frrem_accum_b,
++ _hcd->hfnum_0_frrem_accum_b, _hcd->hfnum_0_samples_b);
++ //DWC_PRINT(" samples %u, accum %llu, avg %llu\n",
++ // _hcd->hfnum_0_samples_b, _hcd->hfnum_0_frrem_accum_b,
++ // (_hcd->hfnum_0_samples_b > 0) ?
++ // _hcd->hfnum_0_frrem_accum_b/_hcd->hfnum_0_samples_b : 0);
++ DWC_PRINT("Frame remaining at sample point B (uframe 1-6):\n");
++ DWC_PRINT(" samples %u, accum %llu, avg %llu/%u\n",
++ _hcd->hfnum_other_samples_b, _hcd->hfnum_other_frrem_accum_b,
++ _hcd->hfnum_other_frrem_accum_b, _hcd->hfnum_other_samples_b);
++ //DWC_PRINT(" samples %u, accum %llu, avg %llu\n",
++ // _hcd->hfnum_other_samples_b, _hcd->hfnum_other_frrem_accum_b,
++ // (_hcd->hfnum_other_samples_b > 0) ?
++ // _hcd->hfnum_other_frrem_accum_b/_hcd->hfnum_other_samples_b : 0);
++#endif
++}
++
++void dwc_otg_hcd_dump_state(dwc_otg_hcd_t *_hcd)
++{
++#ifdef DEBUG
++ int num_channels;
++ int i;
++ gnptxsts_data_t np_tx_status;
++ hptxsts_data_t p_tx_status;
++
++ num_channels = _hcd->core_if->core_params->host_channels;
++ DWC_PRINT("\n");
++ DWC_PRINT("************************************************************\n");
++ DWC_PRINT("HCD State:\n");
++ DWC_PRINT(" Num channels: %d\n", num_channels);
++ for (i = 0; i < num_channels; i++) {
++ dwc_hc_t *hc = _hcd->hc_ptr_array[i];
++ DWC_PRINT(" Channel %d:\n", i);
++ DWC_PRINT(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
++ hc->dev_addr, hc->ep_num, hc->ep_is_in);
++ DWC_PRINT(" speed: %d\n", hc->speed);
++ DWC_PRINT(" ep_type: %d\n", hc->ep_type);
++ DWC_PRINT(" max_packet: %d\n", hc->max_packet);
++ DWC_PRINT(" data_pid_start: %d\n", hc->data_pid_start);
++ DWC_PRINT(" multi_count: %d\n", hc->multi_count);
++ DWC_PRINT(" xfer_started: %d\n", hc->xfer_started);
++ DWC_PRINT(" xfer_buff: %p\n", hc->xfer_buff);
++ DWC_PRINT(" xfer_len: %d\n", hc->xfer_len);
++ DWC_PRINT(" xfer_count: %d\n", hc->xfer_count);
++ DWC_PRINT(" halt_on_queue: %d\n", hc->halt_on_queue);
++ DWC_PRINT(" halt_pending: %d\n", hc->halt_pending);
++ DWC_PRINT(" halt_status: %d\n", hc->halt_status);
++ DWC_PRINT(" do_split: %d\n", hc->do_split);
++ DWC_PRINT(" complete_split: %d\n", hc->complete_split);
++ DWC_PRINT(" hub_addr: %d\n", hc->hub_addr);
++ DWC_PRINT(" port_addr: %d\n", hc->port_addr);
++ DWC_PRINT(" xact_pos: %d\n", hc->xact_pos);
++ DWC_PRINT(" requests: %d\n", hc->requests);
++ DWC_PRINT(" qh: %p\n", hc->qh);
++ if (hc->xfer_started) {
++ hfnum_data_t hfnum;
++ hcchar_data_t hcchar;
++ hctsiz_data_t hctsiz;
++ hcint_data_t hcint;
++ hcintmsk_data_t hcintmsk;
++ hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum);
++ hcchar.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hcchar);
++ hctsiz.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hctsiz);
++ hcint.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hcint);
++ hcintmsk.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hcintmsk);
++ DWC_PRINT(" hfnum: 0x%08x\n", hfnum.d32);
++ DWC_PRINT(" hcchar: 0x%08x\n", hcchar.d32);
++ DWC_PRINT(" hctsiz: 0x%08x\n", hctsiz.d32);
++ DWC_PRINT(" hcint: 0x%08x\n", hcint.d32);
++ DWC_PRINT(" hcintmsk: 0x%08x\n", hcintmsk.d32);
++ }
++ if (hc->xfer_started && (hc->qh != NULL) && (hc->qh->qtd_in_process != NULL)) {
++ dwc_otg_qtd_t *qtd;
++ struct urb *urb;
++ qtd = hc->qh->qtd_in_process;
++ urb = qtd->urb;
++ DWC_PRINT(" URB Info:\n");
++ DWC_PRINT(" qtd: %p, urb: %p\n", qtd, urb);
++ if (urb != NULL) {
++ DWC_PRINT(" Dev: %d, EP: %d %s\n",
++ usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe),
++ usb_pipein(urb->pipe) ? "IN" : "OUT");
++ DWC_PRINT(" Max packet size: %d\n",
++ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
++ DWC_PRINT(" transfer_buffer: %p\n", urb->transfer_buffer);
++ DWC_PRINT(" transfer_dma: %p\n", (void *)urb->transfer_dma);
++ DWC_PRINT(" transfer_buffer_length: %d\n", urb->transfer_buffer_length);
++ DWC_PRINT(" actual_length: %d\n", urb->actual_length);
++ }
++ }
++ }
++ DWC_PRINT(" non_periodic_channels: %d\n", _hcd->non_periodic_channels);
++ DWC_PRINT(" periodic_channels: %d\n", _hcd->periodic_channels);
++ DWC_PRINT(" periodic_usecs: %d\n", _hcd->periodic_usecs);
++ np_tx_status.d32 = dwc_read_reg32(&_hcd->core_if->core_global_regs->gnptxsts);
++ DWC_PRINT(" NP Tx Req Queue Space Avail: %d\n", np_tx_status.b.nptxqspcavail);
++ DWC_PRINT(" NP Tx FIFO Space Avail: %d\n", np_tx_status.b.nptxfspcavail);
++ p_tx_status.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hptxsts);
++ DWC_PRINT(" P Tx Req Queue Space Avail: %d\n", p_tx_status.b.ptxqspcavail);
++ DWC_PRINT(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
++ dwc_otg_hcd_dump_frrem(_hcd);
++ dwc_otg_dump_global_registers(_hcd->core_if);
++ dwc_otg_dump_host_registers(_hcd->core_if);
++ DWC_PRINT("************************************************************\n");
++ DWC_PRINT("\n");
++#endif
++}
++#endif /* DWC_DEVICE_ONLY */
+diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd.h b/drivers/usb/dwc_otg/dwc_otg_hcd.h
+new file mode 100644
+index 0000000..adc9b7f
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_hcd.h
+@@ -0,0 +1,668 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd.h $
++ * $Revision: #6 $
++ * $Date: 2006/12/05 $
++ * $Change: 762293 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++#ifndef DWC_DEVICE_ONLY
++#ifndef __DWC_HCD_H__
++#define __DWC_HCD_H__
++
++#include <linux/list.h>
++#include <linux/usb.h>
++#include "../core/hcd.h"
++
++#ifdef _USE_ATTR_
++struct lm_device;
++#endif
++struct dwc_otg_device;
++
++#include "dwc_otg_cil.h"
++
++/**
++ * @file
++ *
++ * This file contains the structures, constants, and interfaces for
++ * the Host Contoller Driver (HCD).
++ *
++ * The Host Controller Driver (HCD) is responsible for translating requests
++ * from the USB Driver into the appropriate actions on the DWC_otg controller.
++ * It isolates the USBD from the specifics of the controller by providing an
++ * API to the USBD.
++ */
++
++/**
++ * Phases for control transfers.
++ */
++typedef enum dwc_otg_control_phase {
++ DWC_OTG_CONTROL_SETUP,
++ DWC_OTG_CONTROL_DATA,
++ DWC_OTG_CONTROL_STATUS
++} dwc_otg_control_phase_e;
++
++/** Transaction types. */
++typedef enum dwc_otg_transaction_type {
++ DWC_OTG_TRANSACTION_NONE,
++ DWC_OTG_TRANSACTION_PERIODIC,
++ DWC_OTG_TRANSACTION_NON_PERIODIC,
++ DWC_OTG_TRANSACTION_ALL
++} dwc_otg_transaction_type_e;
++
++/**
++ * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
++ * interrupt, or isochronous transfer. A single QTD is created for each URB
++ * (of one of these types) submitted to the HCD. The transfer associated with
++ * a QTD may require one or multiple transactions.
++ *
++ * A QTD is linked to a Queue Head, which is entered in either the
++ * non-periodic or periodic schedule for execution. When a QTD is chosen for
++ * execution, some or all of its transactions may be executed. After
++ * execution, the state of the QTD is updated. The QTD may be retired if all
++ * its transactions are complete or if an error occurred. Otherwise, it
++ * remains in the schedule so more transactions can be executed later.
++ */
++typedef struct dwc_otg_qtd {
++ /**
++ * Determines the PID of the next data packet for the data phase of
++ * control transfers. Ignored for other transfer types.<br>
++ * One of the following values:
++ * - DWC_OTG_HC_PID_DATA0
++ * - DWC_OTG_HC_PID_DATA1
++ */
++ uint8_t data_toggle;
++
++ /** Current phase for control transfers (Setup, Data, or Status). */
++ dwc_otg_control_phase_e control_phase;
++
++ /** Keep track of the current split type
++ * for FS/LS endpoints on a HS Hub */
++ uint8_t complete_split;
++
++ /** How many bytes transferred during SSPLIT OUT */
++ uint32_t ssplit_out_xfer_count;
++
++ /**
++ * Holds the number of bus errors that have occurred for a transaction
++ * within this transfer.
++ */
++ uint8_t error_count;
++
++ /**
++ * Index of the next frame descriptor for an isochronous transfer. A
++ * frame descriptor describes the buffer position and length of the
++ * data to be transferred in the next scheduled (micro)frame of an
++ * isochronous transfer. It also holds status for that transaction.
++ * The frame index starts at 0.
++ */
++ int isoc_frame_index;
++
++ /** Position of the ISOC split on full/low speed */
++ uint8_t isoc_split_pos;
++
++ /** Position of the ISOC split in the buffer for the current frame */
++ uint16_t isoc_split_offset;
++
++ /** URB for this transfer */
++ struct urb *urb;
++
++ /** This list of QTDs */
++ struct list_head qtd_list_entry;
++
++} dwc_otg_qtd_t;
++
++/**
++ * A Queue Head (QH) holds the static characteristics of an endpoint and
++ * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
++ * be entered in either the non-periodic or periodic schedule.
++ */
++typedef struct dwc_otg_qh {
++ /**
++ * Endpoint type.
++ * One of the following values:
++ * - USB_ENDPOINT_XFER_CONTROL
++ * - USB_ENDPOINT_XFER_ISOC
++ * - USB_ENDPOINT_XFER_BULK
++ * - USB_ENDPOINT_XFER_INT
++ */
++ uint8_t ep_type;
++ uint8_t ep_is_in;
++
++ /** wMaxPacketSize Field of Endpoint Descriptor. */
++ uint16_t maxp;
++
++ /**
++ * Determines the PID of the next data packet for non-control
++ * transfers. Ignored for control transfers.<br>
++ * One of the following values:
++ * - DWC_OTG_HC_PID_DATA0
++ * - DWC_OTG_HC_PID_DATA1
++ */
++ uint8_t data_toggle;
++
++ /** Ping state if 1. */
++ uint8_t ping_state;
++
++ /**
++ * List of QTDs for this QH.
++ */
++ struct list_head qtd_list;
++
++ /** Host channel currently processing transfers for this QH. */
++ dwc_hc_t *channel;
++
++ /** QTD currently assigned to a host channel for this QH. */
++ dwc_otg_qtd_t *qtd_in_process;
++
++ /** Full/low speed endpoint on high-speed hub requires split. */
++ uint8_t do_split;
++
++ /** @name Periodic schedule information */
++ /** @{ */
++
++ /** Bandwidth in microseconds per (micro)frame. */
++ uint8_t usecs;
++
++ /** Interval between transfers in (micro)frames. */
++ uint16_t interval;
++
++ /**
++ * (micro)frame to initialize a periodic transfer. The transfer
++ * executes in the following (micro)frame.
++ */
++ uint16_t sched_frame;
++
++ /** (micro)frame at which last start split was initialized. */
++ uint16_t start_split_frame;
++
++ /** @} */
++
++ /** Entry for QH in either the periodic or non-periodic schedule. */
++ struct list_head qh_list_entry;
++} dwc_otg_qh_t;
++
++/**
++ * This structure holds the state of the HCD, including the non-periodic and
++ * periodic schedules.
++ */
++typedef struct dwc_otg_hcd {
++
++ /** DWC OTG Core Interface Layer */
++ dwc_otg_core_if_t *core_if;
++
++ /** Internal DWC HCD Flags */
++ volatile union dwc_otg_hcd_internal_flags {
++ uint32_t d32;
++ struct {
++ unsigned port_connect_status_change : 1;
++ unsigned port_connect_status : 1;
++ unsigned port_reset_change : 1;
++ unsigned port_enable_change : 1;
++ unsigned port_suspend_change : 1;
++ unsigned port_over_current_change : 1;
++ unsigned reserved : 27;
++ } b;
++ } flags;
++
++ /**
++ * Inactive items in the non-periodic schedule. This is a list of
++ * Queue Heads. Transfers associated with these Queue Heads are not
++ * currently assigned to a host channel.
++ */
++ struct list_head non_periodic_sched_inactive;
++
++ /**
++ * Active items in the non-periodic schedule. This is a list of
++ * Queue Heads. Transfers associated with these Queue Heads are
++ * currently assigned to a host channel.
++ */
++ struct list_head non_periodic_sched_active;
++
++ /**
++ * Pointer to the next Queue Head to process in the active
++ * non-periodic schedule.
++ */
++ struct list_head *non_periodic_qh_ptr;
++
++ /**
++ * Inactive items in the periodic schedule. This is a list of QHs for
++ * periodic transfers that are _not_ scheduled for the next frame.
++ * Each QH in the list has an interval counter that determines when it
++ * needs to be scheduled for execution. This scheduling mechanism
++ * allows only a simple calculation for periodic bandwidth used (i.e.
++ * must assume that all periodic transfers may need to execute in the
++ * same frame). However, it greatly simplifies scheduling and should
++ * be sufficient for the vast majority of OTG hosts, which need to
++ * connect to a small number of peripherals at one time.
++ *
++ * Items move from this list to periodic_sched_ready when the QH
++ * interval counter is 0 at SOF.
++ */
++ struct list_head periodic_sched_inactive;
++
++ /**
++ * List of periodic QHs that are ready for execution in the next
++ * frame, but have not yet been assigned to host channels.
++ *
++ * Items move from this list to periodic_sched_assigned as host
++ * channels become available during the current frame.
++ */
++ struct list_head periodic_sched_ready;
++
++ /**
++ * List of periodic QHs to be executed in the next frame that are
++ * assigned to host channels.
++ *
++ * Items move from this list to periodic_sched_queued as the
++ * transactions for the QH are queued to the DWC_otg controller.
++ */
++ struct list_head periodic_sched_assigned;
++
++ /**
++ * List of periodic QHs that have been queued for execution.
++ *
++ * Items move from this list to either periodic_sched_inactive or
++ * periodic_sched_ready when the channel associated with the transfer
++ * is released. If the interval for the QH is 1, the item moves to
++ * periodic_sched_ready because it must be rescheduled for the next
++ * frame. Otherwise, the item moves to periodic_sched_inactive.
++ */
++ struct list_head periodic_sched_queued;
++
++ /**
++ * Total bandwidth claimed so far for periodic transfers. This value
++ * is in microseconds per (micro)frame. The assumption is that all
++ * periodic transfers may occur in the same (micro)frame.
++ */
++ uint16_t periodic_usecs;
++
++ /**
++ * Frame number read from the core at SOF. The value ranges from 0 to
++ * DWC_HFNUM_MAX_FRNUM.
++ */
++ uint16_t frame_number;
++
++ /**
++ * Free host channels in the controller. This is a list of
++ * dwc_hc_t items.
++ */
++ struct list_head free_hc_list;
++
++ /**
++ * Number of host channels assigned to periodic transfers. Currently
++ * assuming that there is a dedicated host channel for each periodic
++ * transaction and at least one host channel available for
++ * non-periodic transactions.
++ */
++ int periodic_channels;
++
++ /**
++ * Number of host channels assigned to non-periodic transfers.
++ */
++ int non_periodic_channels;
++
++ /**
++ * Array of pointers to the host channel descriptors. Allows accessing
++ * a host channel descriptor given the host channel number. This is
++ * useful in interrupt handlers.
++ */
++ dwc_hc_t *hc_ptr_array[MAX_EPS_CHANNELS];
++
++ /**
++ * Buffer to use for any data received during the status phase of a
++ * control transfer. Normally no data is transferred during the status
++ * phase. This buffer is used as a bit bucket.
++ */
++ uint8_t *status_buf;
++
++ /**
++ * DMA address for status_buf.
++ */
++ dma_addr_t status_buf_dma;
++
++ /**
++ * Temp buffer to use for replacing the real transfer buffer of urb
++ * when original transfer buffer is not DWORD aligned.
++ */
++ uint8_t *tmp_rcv_buf, *tmp_snd_buf;
++ /* DMA address for temp buffer */
++ dma_addr_t tmp_rcv_buf_dma, tmp_snd_buf_dma;
++ /* Save the address of original transfer buffer when it is not DWORD aligned */
++ uint8_t *old_tmp_buf;
++ /* Save original transfer size when original transfer buffer is not
++ * DWORD aligned */
++ uint32_t old_tmp_buf_size;
++ /* 1 indicate: need to copy data back to the original transfer buffer after
++ * urb transferring */
++ uint8_t rcv_buf_align_flag;
++
++#define DWC_OTG_HCD_STATUS_BUF_SIZE 64
++#define DWC_OTG_HCD_TMP_BUF_SIZE 1544
++
++ /**
++ * Structure to allow starting the HCD in a non-interrupt context
++ * during an OTG role change.
++ */
++ struct work_struct start_work;
++
++ /**
++ * Connection timer. An OTG host must display a message if the device
++ * does not connect. Started when the VBus power is turned on via
++ * sysfs attribute "buspower".
++ */
++ struct timer_list conn_timer;
++
++ /* Tasket to do a reset */
++ struct tasklet_struct *reset_tasklet;
++
++#ifdef DEBUG
++ uint32_t frrem_samples;
++ uint64_t frrem_accum;
++
++ uint32_t hfnum_7_samples_a;
++ uint64_t hfnum_7_frrem_accum_a;
++ uint32_t hfnum_0_samples_a;
++ uint64_t hfnum_0_frrem_accum_a;
++ uint32_t hfnum_other_samples_a;
++ uint64_t hfnum_other_frrem_accum_a;
++
++ uint32_t hfnum_7_samples_b;
++ uint64_t hfnum_7_frrem_accum_b;
++ uint32_t hfnum_0_samples_b;
++ uint64_t hfnum_0_frrem_accum_b;
++ uint32_t hfnum_other_samples_b;
++ uint64_t hfnum_other_frrem_accum_b;
++#endif
++
++ /**
++ * AlenOh
++ * It stores urb->dev->speed
++ */
++ uint32_t speed;
++} dwc_otg_hcd_t;
++
++/** Gets the dwc_otg_hcd from a struct usb_hcd */
++static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
++{
++ return (dwc_otg_hcd_t *)(hcd->hcd_priv);
++}
++
++/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */
++static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t *dwc_otg_hcd)
++{
++ return container_of((void *)dwc_otg_hcd, struct usb_hcd, hcd_priv);
++}
++
++/** @name HCD Create/Destroy Functions */
++/** @{ */
++extern int __init dwc_otg_hcd_init(struct platform_device *pdev);
++extern void dwc_otg_hcd_remove(struct platform_device *pdev);
++/** @} */
++
++/** @name Linux HC Driver API Functions */
++/** @{ */
++
++extern int dwc_otg_hcd_start(struct usb_hcd *hcd);
++extern void dwc_otg_hcd_stop(struct usb_hcd *hcd);
++extern int dwc_otg_hcd_get_frame_number(struct usb_hcd *hcd);
++extern void dwc_otg_hcd_free(struct usb_hcd *hcd);
++extern int dwc_otg_hcd_urb_enqueue(struct usb_hcd *hcd,
++ struct urb *urb,
++ gfp_t mem_flags);
++extern int dwc_otg_hcd_urb_dequeue(struct usb_hcd *hcd,
++ /* struct usb_host_endpoint *ep,*/
++ struct urb *urb,
++ int status);
++extern void dwc_otg_hcd_endpoint_disable(struct usb_hcd *hcd,
++ struct usb_host_endpoint *ep);
++extern irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
++extern int dwc_otg_hcd_hub_status_data(struct usb_hcd *hcd,
++ char *buf);
++extern int dwc_otg_hcd_hub_control(struct usb_hcd *hcd,
++ u16 typeReq,
++ u16 wValue,
++ u16 wIndex,
++ char *buf,
++ u16 wLength);
++
++/** @} */
++
++/** @name Transaction Execution Functions */
++/** @{ */
++extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd);
++extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t *_hcd,
++ dwc_otg_transaction_type_e _tr_type);
++extern void dwc_otg_hcd_complete_urb(dwc_otg_hcd_t *_hcd, struct urb *_urb,
++ int _status);
++/** @} */
++
++/** @name Interrupt Handler Functions */
++/** @{ */
++extern int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t *_dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t *_dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr (dwc_otg_hcd_t *_dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *_dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t *_dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr (dwc_otg_hcd_t *_dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_disconnect_intr (dwc_otg_hcd_t *_dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *_dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_hc_n_intr (dwc_otg_hcd_t *_dwc_otg_hcd, uint32_t _num);
++extern int32_t dwc_otg_hcd_handle_session_req_intr (dwc_otg_hcd_t *_dwc_otg_hcd);
++extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr (dwc_otg_hcd_t *_dwc_otg_hcd);
++/** @} */
++
++
++/** @name Schedule Queue Functions */
++/** @{ */
++
++/* Implemented in dwc_otg_hcd_queue.c */
++extern dwc_otg_qh_t *dwc_otg_hcd_qh_create (dwc_otg_hcd_t *_hcd, struct urb *_urb);
++extern void dwc_otg_hcd_qh_init (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, struct urb *_urb);
++extern void dwc_otg_hcd_qh_free (dwc_otg_qh_t *_qh);
++extern int dwc_otg_hcd_qh_add (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh);
++extern void dwc_otg_hcd_qh_remove (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh);
++extern void dwc_otg_hcd_qh_deactivate (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, int sched_csplit);
++
++/** Remove and free a QH */
++static inline void dwc_otg_hcd_qh_remove_and_free (dwc_otg_hcd_t *_hcd,
++ dwc_otg_qh_t *_qh)
++{
++ dwc_otg_hcd_qh_remove (_hcd, _qh);
++ dwc_otg_hcd_qh_free (_qh);
++}
++
++/** Allocates memory for a QH structure.
++ * @return Returns the memory allocate or NULL on error. */
++static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc (void)
++{
++ return (dwc_otg_qh_t *) kmalloc (sizeof(dwc_otg_qh_t), GFP_KERNEL);
++}
++
++extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create (struct urb *urb);
++extern void dwc_otg_hcd_qtd_init (dwc_otg_qtd_t *qtd, struct urb *urb);
++extern int dwc_otg_hcd_qtd_add (dwc_otg_qtd_t *qtd, dwc_otg_hcd_t *dwc_otg_hcd);
++
++/** Allocates memory for a QTD structure.
++ * @return Returns the memory allocate or NULL on error. */
++static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc (void)
++{
++ return (dwc_otg_qtd_t *) kmalloc (sizeof(dwc_otg_qtd_t), GFP_KERNEL);
++}
++
++/** Frees the memory for a QTD structure. QTD should already be removed from
++ * list.
++ * @param[in] _qtd QTD to free.*/
++static inline void dwc_otg_hcd_qtd_free (dwc_otg_qtd_t *_qtd)
++{
++ kfree (_qtd);
++}
++
++/** Removes a QTD from list.
++ * @param[in] _qtd QTD to remove from list. */
++static inline void dwc_otg_hcd_qtd_remove (dwc_otg_qtd_t *_qtd)
++{
++ unsigned long flags;
++ local_irq_save (flags);
++ list_del (&_qtd->qtd_list_entry);
++ local_irq_restore (flags);
++}
++
++/** Remove and free a QTD */
++static inline void dwc_otg_hcd_qtd_remove_and_free (dwc_otg_qtd_t *_qtd)
++{
++ dwc_otg_hcd_qtd_remove (_qtd);
++ dwc_otg_hcd_qtd_free (_qtd);
++}
++
++/** @} */
++
++
++/** @name Internal Functions */
++/** @{ */
++dwc_otg_qh_t *dwc_urb_to_qh(struct urb *_urb);
++void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t *_hcd);
++void dwc_otg_hcd_dump_state(dwc_otg_hcd_t *_hcd);
++/** @} */
++
++/** Gets the usb_host_endpoint associated with an URB. */
++static inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *_urb)
++{
++ struct usb_device *dev = _urb->dev;
++ int ep_num = usb_pipeendpoint(_urb->pipe);
++
++ if (usb_pipein(_urb->pipe))
++ return dev->ep_in[ep_num];
++ else
++ return dev->ep_out[ep_num];
++}
++
++/**
++ * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
++ * qualified with its direction (possible 32 endpoints per device).
++ */
++#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
++ ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
++
++/** Gets the QH that contains the list_head */
++#define dwc_list_to_qh(_list_head_ptr_) (container_of(_list_head_ptr_,dwc_otg_qh_t,qh_list_entry))
++
++/** Gets the QTD that contains the list_head */
++#define dwc_list_to_qtd(_list_head_ptr_) (container_of(_list_head_ptr_,dwc_otg_qtd_t,qtd_list_entry))
++
++/** Check if QH is non-periodic */
++#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == USB_ENDPOINT_XFER_BULK) || \
++ (_qh_ptr_->ep_type == USB_ENDPOINT_XFER_CONTROL))
++
++/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */
++#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
++
++/** Packet size for any kind of endpoint descriptor */
++#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
++
++/**
++ * Returns true if _frame1 is less than or equal to _frame2. The comparison is
++ * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the
++ * frame number when the max frame number is reached.
++ */
++static inline int dwc_frame_num_le(uint16_t _frame1, uint16_t _frame2)
++{
++ return ((_frame2 - _frame1) & DWC_HFNUM_MAX_FRNUM) <=
++ (DWC_HFNUM_MAX_FRNUM >> 1);
++}
++
++/**
++ * Returns true if _frame1 is greater than _frame2. The comparison is done
++ * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
++ * number when the max frame number is reached.
++ */
++static inline int dwc_frame_num_gt(uint16_t _frame1, uint16_t _frame2)
++{
++ return (_frame1 != _frame2) &&
++ (((_frame1 - _frame2) & DWC_HFNUM_MAX_FRNUM) <
++ (DWC_HFNUM_MAX_FRNUM >> 1));
++}
++
++/**
++ * Increments _frame by the amount specified by _inc. The addition is done
++ * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value.
++ */
++static inline uint16_t dwc_frame_num_inc(uint16_t _frame, uint16_t _inc)
++{
++ return (_frame + _inc) & DWC_HFNUM_MAX_FRNUM;
++}
++
++static inline uint16_t dwc_full_frame_num (uint16_t _frame)
++{
++ return ((_frame) & DWC_HFNUM_MAX_FRNUM) >> 3;
++}
++
++static inline uint16_t dwc_micro_frame_num (uint16_t _frame)
++{
++ return (_frame) & 0x7;
++}
++
++#ifdef DEBUG
++/**
++ * Macro to sample the remaining PHY clocks left in the current frame. This
++ * may be used during debugging to determine the average time it takes to
++ * execute sections of code. There are two possible sample points, "a" and
++ * "b", so the _letter argument must be one of these values.
++ *
++ * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
++ * example, "cat /sys/devices/lm0/hcd_frrem".
++ */
++#define dwc_sample_frrem(_hcd, _qh, _letter) \
++{ \
++ hfnum_data_t hfnum; \
++ dwc_otg_qtd_t *qtd; \
++ qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \
++ if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \
++ hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum); \
++ switch (hfnum.b.frnum & 0x7) { \
++ case 7: \
++ _hcd->hfnum_7_samples_##_letter++; \
++ _hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \
++ break; \
++ case 0: \
++ _hcd->hfnum_0_samples_##_letter++; \
++ _hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \
++ break; \
++ default: \
++ _hcd->hfnum_other_samples_##_letter++; \
++ _hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \
++ break; \
++ } \
++ } \
++}
++#else
++#define dwc_sample_frrem(_hcd, _qh, _letter)
++#endif
++#endif
++#endif /* DWC_DEVICE_ONLY */
+diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c
+new file mode 100644
+index 0000000..dad5050
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c
+@@ -0,0 +1,1831 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd_intr.c $
++ * $Revision: #7 $
++ * $Date: 2005/11/02 $
++ * $Change: 553126 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++#ifndef DWC_DEVICE_ONLY
++
++#include "dwc_otg_driver.h"
++#include "dwc_otg_hcd.h"
++#include "dwc_otg_regs.h"
++/** @file
++ * This file contains the implementation of the HCD Interrupt handlers.
++ */
++
++/* Display the contents of the buffer */
++extern void dump_msg(const u8 *buf, unsigned int length);
++
++
++/** This function handles interrupts for the HCD. */
++int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
++{
++ int retval = 0;
++
++ dwc_otg_core_if_t *core_if = _dwc_otg_hcd->core_if;
++ gintsts_data_t gintsts;
++#ifdef DEBUG
++ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++#endif
++
++ /* Check if HOST Mode */
++ if (dwc_otg_is_host_mode(core_if)) {
++ gintsts.d32 = dwc_otg_read_core_intr(core_if);
++ if (!gintsts.d32) {
++ return 0;
++ }
++
++#ifdef DEBUG
++ /* Don't print debug message in the interrupt handler on SOF */
++# ifndef DEBUG_SOF
++ if (gintsts.d32 != DWC_SOF_INTR_MASK)
++# endif
++ DWC_DEBUGPL (DBG_HCD, "\n");
++#endif
++
++#ifdef DEBUG
++# ifndef DEBUG_SOF
++ if (gintsts.d32 != DWC_SOF_INTR_MASK)
++# endif
++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x\n", gintsts.d32);
++#endif
++
++ if (gintsts.b.sofintr) {
++ retval |= dwc_otg_hcd_handle_sof_intr (_dwc_otg_hcd);
++ }
++ if (gintsts.b.rxstsqlvl) {
++ retval |= dwc_otg_hcd_handle_rx_status_q_level_intr (_dwc_otg_hcd);
++ }
++ if (gintsts.b.nptxfempty) {
++ retval |= dwc_otg_hcd_handle_np_tx_fifo_empty_intr (_dwc_otg_hcd);
++ }
++ if (gintsts.b.i2cintr) {
++ /** @todo Implement i2cintr handler. */
++ }
++ if (gintsts.b.portintr) {
++ retval |= dwc_otg_hcd_handle_port_intr (_dwc_otg_hcd);
++ }
++ if (gintsts.b.hcintr) {
++ retval |= dwc_otg_hcd_handle_hc_intr (_dwc_otg_hcd);
++ }
++ if (gintsts.b.ptxfempty) {
++ retval |= dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (_dwc_otg_hcd);
++ }
++#ifdef DEBUG
++# ifndef DEBUG_SOF
++ if (gintsts.d32 != DWC_SOF_INTR_MASK)
++# endif
++ {
++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Finished Servicing Interrupts\n");
++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n",
++ dwc_read_reg32(&global_regs->gintsts));
++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n",
++ dwc_read_reg32(&global_regs->gintmsk));
++ }
++#endif
++
++#ifdef DEBUG
++# ifndef DEBUG_SOF
++ if (gintsts.d32 != DWC_SOF_INTR_MASK)
++# endif
++ DWC_DEBUGPL (DBG_HCD, "\n");
++#endif
++
++ }
++
++ return retval;
++}
++
++#ifdef DWC_TRACK_MISSED_SOFS
++#warning Compiling code to track missed SOFs
++#define FRAME_NUM_ARRAY_SIZE 1000
++/**
++ * This function is for debug only.
++ */
++static inline void track_missed_sofs(uint16_t _curr_frame_number) {
++ static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE];
++ static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE];
++ static int frame_num_idx = 0;
++ static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM;
++ static int dumped_frame_num_array = 0;
++
++ if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
++ if ((((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) != _curr_frame_number)) {
++ frame_num_array[frame_num_idx] = _curr_frame_number;
++ last_frame_num_array[frame_num_idx++] = last_frame_num;
++ }
++ } else if (!dumped_frame_num_array) {
++ int i;
++ printk(KERN_EMERG USB_DWC "Frame Last Frame\n");
++ printk(KERN_EMERG USB_DWC "----- ----------\n");
++ for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
++ printk(KERN_EMERG USB_DWC "0x%04x 0x%04x\n",
++ frame_num_array[i], last_frame_num_array[i]);
++ }
++ dumped_frame_num_array = 1;
++ }
++ last_frame_num = _curr_frame_number;
++}
++#endif
++
++/**
++ * Handles the start-of-frame interrupt in host mode. Non-periodic
++ * transactions may be queued to the DWC_otg controller for the current
++ * (micro)frame. Periodic transactions may be queued to the controller for the
++ * next (micro)frame.
++ */
++int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t *_hcd)
++{
++ hfnum_data_t hfnum;
++ struct list_head *qh_entry;
++ dwc_otg_qh_t *qh;
++ dwc_otg_transaction_type_e tr_type;
++ gintsts_data_t gintsts = {.d32 = 0};
++
++ hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum);
++
++#ifdef DEBUG_SOF
++ DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n");
++#endif
++
++ _hcd->frame_number = hfnum.b.frnum;
++
++#ifdef DEBUG
++ _hcd->frrem_accum += hfnum.b.frrem;
++ _hcd->frrem_samples++;
++#endif
++
++#ifdef DWC_TRACK_MISSED_SOFS
++ track_missed_sofs(_hcd->frame_number);
++#endif
++
++ /* Determine whether any periodic QHs should be executed. */
++ qh_entry = _hcd->periodic_sched_inactive.next;
++ while (qh_entry != &_hcd->periodic_sched_inactive) {
++ qh = list_entry(qh_entry, dwc_otg_qh_t, qh_list_entry);
++ qh_entry = qh_entry->next;
++ if (dwc_frame_num_le(qh->sched_frame, _hcd->frame_number)) {
++ /*
++ * Move QH to the ready list to be executed next
++ * (micro)frame.
++ */
++ list_move(&qh->qh_list_entry, &_hcd->periodic_sched_ready);
++ }
++ }
++
++ tr_type = dwc_otg_hcd_select_transactions(_hcd);
++ if (tr_type != DWC_OTG_TRANSACTION_NONE) {
++ dwc_otg_hcd_queue_transactions(_hcd, tr_type);
++ }
++
++ /* Clear interrupt */
++ gintsts.b.sofintr = 1;
++ dwc_write_reg32(&_hcd->core_if->core_global_regs->gintsts, gintsts.d32);
++
++ return 1;
++}
++
++/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at
++ * least one packet in the Rx FIFO. The packets are moved from the FIFO to
++ * memory if the DWC_otg controller is operating in Slave mode. */
++int32_t dwc_otg_hcd_handle_rx_status_q_level_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
++{
++ host_grxsts_data_t grxsts;
++ dwc_hc_t *hc = NULL;
++
++ DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n");
++
++ grxsts.d32 = dwc_read_reg32(&_dwc_otg_hcd->core_if->core_global_regs->grxstsp);
++
++ hc = _dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum];
++
++ /* Packet Status */
++ DWC_DEBUGPL(DBG_HCDV, " Ch num = %d\n", grxsts.b.chnum);
++ DWC_DEBUGPL(DBG_HCDV, " Count = %d\n", grxsts.b.bcnt);
++ DWC_DEBUGPL(DBG_HCDV, " DPID = %d, hc.dpid = %d\n", grxsts.b.dpid, hc->data_pid_start);
++ DWC_DEBUGPL(DBG_HCDV, " PStatus = %d\n", grxsts.b.pktsts);
++
++ switch (grxsts.b.pktsts) {
++ case DWC_GRXSTS_PKTSTS_IN:
++ /* Read the data into the host buffer. */
++ if (grxsts.b.bcnt > 0) {
++ dwc_otg_read_packet(_dwc_otg_hcd->core_if,
++ hc->xfer_buff,
++ grxsts.b.bcnt);
++
++ /* Update the HC fields for the next packet received. */
++ hc->xfer_count += grxsts.b.bcnt;
++ hc->xfer_buff += grxsts.b.bcnt;
++ }
++
++ case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
++ case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
++ case DWC_GRXSTS_PKTSTS_CH_HALTED:
++ /* Handled in interrupt, just ignore data */
++ break;
++ default:
++ DWC_ERROR ("RX_STS_Q Interrupt: Unknown status %d\n", grxsts.b.pktsts);
++ break;
++ }
++
++ return 1;
++}
++
++/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More
++ * data packets may be written to the FIFO for OUT transfers. More requests
++ * may be written to the non-periodic request queue for IN transfers. This
++ * interrupt is enabled only in Slave mode. */
++int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
++{
++ DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n");
++ dwc_otg_hcd_queue_transactions(_dwc_otg_hcd,
++ DWC_OTG_TRANSACTION_NON_PERIODIC);
++ return 1;
++}
++
++/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data
++ * packets may be written to the FIFO for OUT transfers. More requests may be
++ * written to the periodic request queue for IN transfers. This interrupt is
++ * enabled only in Slave mode. */
++int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
++{
++ DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n");
++ dwc_otg_hcd_queue_transactions(_dwc_otg_hcd,
++ DWC_OTG_TRANSACTION_PERIODIC);
++ return 1;
++}
++
++/** There are multiple conditions that can cause a port interrupt. This function
++ * determines which interrupt conditions have occurred and handles them
++ * appropriately. */
++int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
++{
++ int retval = 0;
++ hprt0_data_t hprt0;
++ hprt0_data_t hprt0_modify;
++
++ hprt0.d32 = dwc_read_reg32(_dwc_otg_hcd->core_if->host_if->hprt0);
++ hprt0_modify.d32 = dwc_read_reg32(_dwc_otg_hcd->core_if->host_if->hprt0);
++
++ /* Clear appropriate bits in HPRT0 to clear the interrupt bit in
++ * GINTSTS */
++
++ hprt0_modify.b.prtena = 0;
++ hprt0_modify.b.prtconndet = 0;
++ hprt0_modify.b.prtenchng = 0;
++ hprt0_modify.b.prtovrcurrchng = 0;
++
++ /* Port Connect Detected
++ * Set flag and clear if detected */
++ if (hprt0.b.prtconndet) {
++ DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x "
++ "Port Connect Detected--\n", hprt0.d32);
++ _dwc_otg_hcd->flags.b.port_connect_status_change = 1;
++ _dwc_otg_hcd->flags.b.port_connect_status = 1;
++ hprt0_modify.b.prtconndet = 1;
++
++ /* B-Device has connected, Delete the connection timer. */
++ del_timer( &_dwc_otg_hcd->conn_timer );
++
++ /* The Hub driver asserts a reset when it sees port connect
++ * status change flag */
++ retval |= 1;
++ }
++
++ /* Port Enable Changed
++ * Clear if detected - Set internal flag if disabled */
++ if (hprt0.b.prtenchng) {
++ DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
++ "Port Enable Changed--\n", hprt0.d32);
++ hprt0_modify.b.prtenchng = 1;
++ if (hprt0.b.prtena == 1) {
++ int do_reset = 0;
++ dwc_otg_core_params_t *params = _dwc_otg_hcd->core_if->core_params;
++ dwc_otg_core_global_regs_t *global_regs = _dwc_otg_hcd->core_if->core_global_regs;
++ dwc_otg_host_if_t *host_if = _dwc_otg_hcd->core_if->host_if;
++
++ /* Check if we need to adjust the PHY clock speed for
++ * low power and adjust it */
++ if (params->host_support_fs_ls_low_power)
++ {
++ gusbcfg_data_t usbcfg;
++
++ usbcfg.d32 = dwc_read_reg32 (&global_regs->gusbcfg);
++
++ if ((hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED) ||
++ (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_FULL_SPEED))
++ {
++ /*
++ * Low power
++ */
++ hcfg_data_t hcfg;
++ if (usbcfg.b.phylpwrclksel == 0) {
++ /* Set PHY low power clock select for FS/LS devices */
++ usbcfg.b.phylpwrclksel = 1;
++ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
++ do_reset = 1;
++ }
++
++ hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg);
++
++ if ((hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED) &&
++ (params->host_ls_low_power_phy_clk ==
++ DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ))
++ {
++ /* 6 MHZ */
++ DWC_DEBUGPL(DBG_CIL, "FS_PHY programming HCFG to 6 MHz (Low Power)\n");
++ if (hcfg.b.fslspclksel != DWC_HCFG_6_MHZ) {
++ hcfg.b.fslspclksel = DWC_HCFG_6_MHZ;
++ dwc_write_reg32(&host_if->host_global_regs->hcfg,
++ hcfg.d32);
++ do_reset = 1;
++ }
++ }
++ else {
++ /* 48 MHZ */
++ DWC_DEBUGPL(DBG_CIL, "FS_PHY programming HCFG to 48 MHz ()\n");
++ if (hcfg.b.fslspclksel != DWC_HCFG_48_MHZ) {
++ hcfg.b.fslspclksel = DWC_HCFG_48_MHZ;
++ dwc_write_reg32(&host_if->host_global_regs->hcfg,
++ hcfg.d32);
++ do_reset = 1;
++ }
++ }
++ }
++ else {
++ /*
++ * Not low power
++ */
++ if (usbcfg.b.phylpwrclksel == 1) {
++ usbcfg.b.phylpwrclksel = 0;
++ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
++ do_reset = 1;
++ }
++ }
++
++ if (do_reset) {
++ tasklet_schedule(_dwc_otg_hcd->reset_tasklet);
++ }
++ }
++
++ if (!do_reset) {
++ /* Port has been enabled set the reset change flag */
++ _dwc_otg_hcd->flags.b.port_reset_change = 1;
++ }
++
++ } else {
++ _dwc_otg_hcd->flags.b.port_enable_change = 1;
++ }
++ retval |= 1;
++ }
++
++ /** Overcurrent Change Interrupt */
++ if (hprt0.b.prtovrcurrchng) {
++ DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x "
++ "Port Overcurrent Changed--\n", hprt0.d32);
++ _dwc_otg_hcd->flags.b.port_over_current_change = 1;
++ hprt0_modify.b.prtovrcurrchng = 1;
++ retval |= 1;
++ }
++
++ /* Clear Port Interrupts */
++ dwc_write_reg32(_dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
++
++ return retval;
++}
++
++
++/** This interrupt indicates that one or more host channels has a pending
++ * interrupt. There are multiple conditions that can cause each host channel
++ * interrupt. This function determines which conditions have occurred for each
++ * host channel interrupt and handles them appropriately. */
++int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *_dwc_otg_hcd)
++{
++ int i;
++ int retval = 0;
++ haint_data_t haint;
++
++ /* Clear appropriate bits in HCINTn to clear the interrupt bit in
++ * GINTSTS */
++
++ haint.d32 = dwc_otg_read_host_all_channels_intr(_dwc_otg_hcd->core_if);
++
++ for (i=0; i<_dwc_otg_hcd->core_if->core_params->host_channels; i++) {
++ if (haint.b2.chint & (1 << i)) {
++ retval |= dwc_otg_hcd_handle_hc_n_intr (_dwc_otg_hcd, i);
++ }
++ }
++
++ return retval;
++}
++
++/* Macro used to clear one channel interrupt */
++#define clear_hc_int(_hc_regs_,_intr_) \
++do { \
++ hcint_data_t hcint_clear = {.d32 = 0}; \
++ hcint_clear.b._intr_ = 1; \
++ dwc_write_reg32(&((_hc_regs_)->hcint), hcint_clear.d32); \
++} while (0)
++
++/*
++ * Macro used to disable one channel interrupt. Channel interrupts are
++ * disabled when the channel is halted or released by the interrupt handler.
++ * There is no need to handle further interrupts of that type until the
++ * channel is re-assigned. In fact, subsequent handling may cause crashes
++ * because the channel structures are cleaned up when the channel is released.
++ */
++#define disable_hc_int(_hc_regs_,_intr_) \
++do { \
++ hcintmsk_data_t hcintmsk = {.d32 = 0}; \
++ hcintmsk.b._intr_ = 1; \
++ dwc_modify_reg32(&((_hc_regs_)->hcintmsk), hcintmsk.d32, 0); \
++} while (0)
++
++/**
++ * Gets the actual length of a transfer after the transfer halts. _halt_status
++ * holds the reason for the halt.
++ *
++ * For IN transfers where _halt_status is DWC_OTG_HC_XFER_COMPLETE,
++ * *_short_read is set to 1 upon return if less than the requested
++ * number of bytes were transferred. Otherwise, *_short_read is set to 0 upon
++ * return. _short_read may also be NULL on entry, in which case it remains
++ * unchanged.
++ */
++static uint32_t get_actual_xfer_length(dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd,
++ dwc_otg_halt_status_e _halt_status,
++ int *_short_read)
++{
++ hctsiz_data_t hctsiz;
++ uint32_t length;
++
++ if (_short_read != NULL) {
++ *_short_read = 0;
++ }
++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz);
++
++ if (_halt_status == DWC_OTG_HC_XFER_COMPLETE) {
++ if (_hc->ep_is_in) {
++ length = _hc->xfer_len - hctsiz.b.xfersize;
++ if (_short_read != NULL) {
++ *_short_read = (hctsiz.b.xfersize != 0);
++ }
++ } else if (_hc->qh->do_split) {
++ length = _qtd->ssplit_out_xfer_count;
++ } else {
++ length = _hc->xfer_len;
++ }
++ } else {
++ /*
++ * Must use the hctsiz.pktcnt field to determine how much data
++ * has been transferred. This field reflects the number of
++ * packets that have been transferred via the USB. This is
++ * always an integral number of packets if the transfer was
++ * halted before its normal completion. (Can't use the
++ * hctsiz.xfersize field because that reflects the number of
++ * bytes transferred via the AHB, not the USB).
++ */
++ length = (_hc->start_pkt_count - hctsiz.b.pktcnt) * _hc->max_packet;
++ }
++
++ return length;
++}
++
++/**
++ * Updates the state of the URB after a Transfer Complete interrupt on the
++ * host channel. Updates the actual_length field of the URB based on the
++ * number of bytes transferred via the host channel. Sets the URB status
++ * if the data transfer is finished.
++ *
++ * @return 1 if the data transfer specified by the URB is completely finished,
++ * 0 otherwise.
++ */
++static int update_urb_state_xfer_comp(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ struct urb *_urb,
++ dwc_otg_qtd_t *_qtd)
++{
++ int xfer_done = 0;
++ int short_read = 0;
++
++ _urb->actual_length += get_actual_xfer_length(_hc, _hc_regs, _qtd,
++ DWC_OTG_HC_XFER_COMPLETE,
++ &short_read);
++
++ if (short_read || (_urb->actual_length == _urb->transfer_buffer_length)) {
++ xfer_done = 1;
++ if (short_read && (_urb->transfer_flags & URB_SHORT_NOT_OK)) {
++ _urb->status = -EREMOTEIO;
++ }
++ else {
++ _urb->status = 0;
++ /* After urb transferring, if original transfer
++ * buffer is not DWORD aligned and data direction is
++ * from device to USB OTG Controller, copy data back
++ * to from the temp buffer */
++ if(_hcd->rcv_buf_align_flag == 1) {
++ if(usb_pipein(_urb->pipe) != 0 && (unsigned int)_hcd->old_tmp_buf % 4) {
++ _hcd->rcv_buf_align_flag = 0;
++ memcpy(_hcd->old_tmp_buf, _hcd->tmp_rcv_buf, _hcd->old_tmp_buf_size);
++ }
++ }
++ }
++ }
++
++#ifdef DEBUG
++ {
++ hctsiz_data_t hctsiz;
++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz);
++ DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
++ __func__, (_hc->ep_is_in ? "IN" : "OUT"), _hc->hc_num);
++ DWC_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", _hc->xfer_len);
++ DWC_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n", hctsiz.b.xfersize);
++ DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n",
++ _urb->transfer_buffer_length);
++ DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n", _urb->actual_length);
++ DWC_DEBUGPL(DBG_HCDV, " short_read %d, xfer_done %d\n",
++ short_read, xfer_done);
++ }
++#endif
++
++ return xfer_done;
++}
++
++/*
++ * Save the starting data toggle for the next transfer. The data toggle is
++ * saved in the QH for non-control transfers and it's saved in the QTD for
++ * control transfers.
++ */
++static void save_data_toggle(dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd)
++{
++ hctsiz_data_t hctsiz;
++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz);
++
++ if (_hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) {
++ dwc_otg_qh_t *qh = _hc->qh;
++ if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
++ qh->data_toggle = DWC_OTG_HC_PID_DATA0;
++ } else {
++ qh->data_toggle = DWC_OTG_HC_PID_DATA1;
++ }
++ } else {
++ if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
++ _qtd->data_toggle = DWC_OTG_HC_PID_DATA0;
++ } else {
++ _qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
++ }
++ }
++}
++
++/**
++ * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic
++ * QHs, removes the QH from the active non-periodic schedule. If any QTDs are
++ * still linked to the QH, the QH is added to the end of the inactive
++ * non-periodic schedule. For periodic QHs, removes the QH from the periodic
++ * schedule if no more QTDs are linked to the QH.
++ */
++static void deactivate_qh(dwc_otg_hcd_t *_hcd,
++ dwc_otg_qh_t *_qh,
++ int free_qtd)
++{
++ int continue_split = 0;
++ dwc_otg_qtd_t *qtd;
++
++ DWC_DEBUGPL(DBG_HCDV, " %s(%p,%p,%d)\n", __func__, _hcd, _qh, free_qtd);
++
++ qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry);
++
++ if (qtd->complete_split) {
++ continue_split = 1;
++ }
++ else if ((qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID) ||
++ (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END))
++ {
++ continue_split = 1;
++ }
++
++ if (free_qtd) {
++ dwc_otg_hcd_qtd_remove_and_free(qtd);
++ continue_split = 0;
++ }
++
++ _qh->channel = NULL;
++ _qh->qtd_in_process = NULL;
++ dwc_otg_hcd_qh_deactivate(_hcd, _qh, continue_split);
++}
++
++/**
++ * Updates the state of an Isochronous URB when the transfer is stopped for
++ * any reason. The fields of the current entry in the frame descriptor array
++ * are set based on the transfer state and the input _halt_status. Completes
++ * the Isochronous URB if all the URB frames have been completed.
++ *
++ * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be
++ * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE.
++ */
++static dwc_otg_halt_status_e
++update_isoc_urb_state(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd,
++ dwc_otg_halt_status_e _halt_status)
++{
++ struct urb *urb = _qtd->urb;
++ dwc_otg_halt_status_e ret_val = _halt_status;
++ struct usb_iso_packet_descriptor *frame_desc;
++
++ frame_desc = &urb->iso_frame_desc[_qtd->isoc_frame_index];
++ switch (_halt_status) {
++ case DWC_OTG_HC_XFER_COMPLETE:
++ frame_desc->status = 0;
++ frame_desc->actual_length =
++ get_actual_xfer_length(_hc, _hc_regs, _qtd,
++ _halt_status, NULL);
++ break;
++ case DWC_OTG_HC_XFER_FRAME_OVERRUN:
++ urb->error_count++;
++ if (_hc->ep_is_in) {
++ frame_desc->status = -ENOSR;
++ } else {
++ frame_desc->status = -ECOMM;
++ }
++ frame_desc->actual_length = 0;
++ break;
++ case DWC_OTG_HC_XFER_BABBLE_ERR:
++ urb->error_count++;
++ frame_desc->status = -EOVERFLOW;
++ /* Don't need to update actual_length in this case. */
++ break;
++ case DWC_OTG_HC_XFER_XACT_ERR:
++ urb->error_count++;
++ frame_desc->status = -EPROTO;
++ frame_desc->actual_length =
++ get_actual_xfer_length(_hc, _hc_regs, _qtd,
++ _halt_status, NULL);
++ default:
++ DWC_ERROR("%s: Unhandled _halt_status (%d)\n", __func__,
++ _halt_status);
++ BUG();
++ break;
++ }
++
++ if (++_qtd->isoc_frame_index == urb->number_of_packets) {
++ /*
++ * urb->status is not used for isoc transfers.
++ * The individual frame_desc statuses are used instead.
++ */
++ dwc_otg_hcd_complete_urb(_hcd, urb, 0);
++ ret_val = DWC_OTG_HC_XFER_URB_COMPLETE;
++ } else {
++ ret_val = DWC_OTG_HC_XFER_COMPLETE;
++ }
++
++ return ret_val;
++}
++
++/**
++ * Releases a host channel for use by other transfers. Attempts to select and
++ * queue more transactions since at least one host channel is available.
++ *
++ * @param _hcd The HCD state structure.
++ * @param _hc The host channel to release.
++ * @param _qtd The QTD associated with the host channel. This QTD may be freed
++ * if the transfer is complete or an error has occurred.
++ * @param _halt_status Reason the channel is being released. This status
++ * determines the actions taken by this function.
++ */
++static void release_channel(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_qtd_t *_qtd,
++ dwc_otg_halt_status_e _halt_status)
++{
++ dwc_otg_transaction_type_e tr_type;
++ int free_qtd;
++
++ DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d\n",
++ __func__, _hc->hc_num, _halt_status);
++
++ switch (_halt_status) {
++ case DWC_OTG_HC_XFER_URB_COMPLETE:
++ free_qtd = 1;
++ break;
++ case DWC_OTG_HC_XFER_AHB_ERR:
++ case DWC_OTG_HC_XFER_STALL:
++ case DWC_OTG_HC_XFER_BABBLE_ERR:
++ free_qtd = 1;
++ break;
++ case DWC_OTG_HC_XFER_XACT_ERR:
++ if (_qtd->error_count >= 3) {
++ DWC_DEBUGPL(DBG_HCDV, " Complete URB with transaction error\n");
++ free_qtd = 1;
++ _qtd->urb->status = -EPROTO;
++ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPROTO);
++ } else {
++ free_qtd = 0;
++ }
++ break;
++ case DWC_OTG_HC_XFER_URB_DEQUEUE:
++ /*
++ * The QTD has already been removed and the QH has been
++ * deactivated. Don't want to do anything except release the
++ * host channel and try to queue more transfers.
++ */
++ goto cleanup;
++ case DWC_OTG_HC_XFER_NO_HALT_STATUS:
++ DWC_ERROR("%s: No halt_status, channel %d\n", __func__, _hc->hc_num);
++ free_qtd = 0;
++ break;
++ default:
++ free_qtd = 0;
++ break;
++ }
++
++
++ deactivate_qh(_hcd, _hc->qh, free_qtd);
++
++cleanup:
++ /*
++ * Release the host channel for use by other transfers. The cleanup
++ * function clears the channel interrupt enables and conditions, so
++ * there's no need to clear the Channel Halted interrupt separately.
++ */
++ dwc_otg_hc_cleanup(_hcd->core_if, _hc);
++ list_add_tail(&_hc->hc_list_entry, &_hcd->free_hc_list);
++
++ switch (_hc->ep_type) {
++ case DWC_OTG_EP_TYPE_CONTROL:
++ case DWC_OTG_EP_TYPE_BULK:
++ _hcd->non_periodic_channels--;
++ break;
++
++ default:
++ /*
++ * Don't release reservations for periodic channels here.
++ * That's done when a periodic transfer is descheduled (i.e.
++ * when the QH is removed from the periodic schedule).
++ */
++ break;
++ }
++
++ /* Try to queue more transfers now that there's a free channel. */
++ tr_type = dwc_otg_hcd_select_transactions(_hcd);
++ if (tr_type != DWC_OTG_TRANSACTION_NONE) {
++ dwc_otg_hcd_queue_transactions(_hcd, tr_type);
++ }
++}
++
++/**
++ * Halts a host channel. If the channel cannot be halted immediately because
++ * the request queue is full, this function ensures that the FIFO empty
++ * interrupt for the appropriate queue is enabled so that the halt request can
++ * be queued when there is space in the request queue.
++ *
++ * This function may also be called in DMA mode. In that case, the channel is
++ * simply released since the core always halts the channel automatically in
++ * DMA mode.
++ */
++static void halt_channel(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_qtd_t *_qtd,
++ dwc_otg_halt_status_e _halt_status)
++{
++ if (_hcd->core_if->dma_enable) {
++ release_channel(_hcd, _hc, _qtd, _halt_status);
++ return;
++ }
++
++ /* Slave mode processing... */
++ dwc_otg_hc_halt(_hcd->core_if, _hc, _halt_status);
++
++ if (_hc->halt_on_queue) {
++ gintmsk_data_t gintmsk = {.d32 = 0};
++ dwc_otg_core_global_regs_t *global_regs;
++ global_regs = _hcd->core_if->core_global_regs;
++
++ if (_hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
++ _hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
++ /*
++ * Make sure the Non-periodic Tx FIFO empty interrupt
++ * is enabled so that the non-periodic schedule will
++ * be processed.
++ */
++ gintmsk.b.nptxfempty = 1;
++ dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32);
++ } else {
++ /*
++ * Move the QH from the periodic queued schedule to
++ * the periodic assigned schedule. This allows the
++ * halt to be queued when the periodic schedule is
++ * processed.
++ */
++ list_move(&_hc->qh->qh_list_entry,
++ &_hcd->periodic_sched_assigned);
++
++ /*
++ * Make sure the Periodic Tx FIFO Empty interrupt is
++ * enabled so that the periodic schedule will be
++ * processed.
++ */
++ gintmsk.b.ptxfempty = 1;
++ dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32);
++ }
++ }
++}
++
++/**
++ * Performs common cleanup for non-periodic transfers after a Transfer
++ * Complete interrupt. This function should be called after any endpoint type
++ * specific handling is finished to release the host channel.
++ */
++static void complete_non_periodic_xfer(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd,
++ dwc_otg_halt_status_e _halt_status)
++{
++ hcint_data_t hcint;
++
++ _qtd->error_count = 0;
++
++ hcint.d32 = dwc_read_reg32(&_hc_regs->hcint);
++ if (hcint.b.nyet) {
++ /*
++ * Got a NYET on the last transaction of the transfer. This
++ * means that the endpoint should be in the PING state at the
++ * beginning of the next transfer.
++ */
++ _hc->qh->ping_state = 1;
++ clear_hc_int(_hc_regs,nyet);
++ }
++
++ /*
++ * Always halt and release the host channel to make it available for
++ * more transfers. There may still be more phases for a control
++ * transfer or more data packets for a bulk transfer at this point,
++ * but the host channel is still halted. A channel will be reassigned
++ * to the transfer when the non-periodic schedule is processed after
++ * the channel is released. This allows transactions to be queued
++ * properly via dwc_otg_hcd_queue_transactions, which also enables the
++ * Tx FIFO Empty interrupt if necessary.
++ */
++ if (_hc->ep_is_in) {
++ /*
++ * IN transfers in Slave mode require an explicit disable to
++ * halt the channel. (In DMA mode, this call simply releases
++ * the channel.)
++ */
++ halt_channel(_hcd, _hc, _qtd, _halt_status);
++ } else {
++ /*
++ * The channel is automatically disabled by the core for OUT
++ * transfers in Slave mode.
++ */
++ release_channel(_hcd, _hc, _qtd, _halt_status);
++ }
++}
++
++/**
++ * Performs common cleanup for periodic transfers after a Transfer Complete
++ * interrupt. This function should be called after any endpoint type specific
++ * handling is finished to release the host channel.
++ */
++static void complete_periodic_xfer(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd,
++ dwc_otg_halt_status_e _halt_status)
++{
++ hctsiz_data_t hctsiz;
++ _qtd->error_count = 0;
++
++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz);
++ if (!_hc->ep_is_in || hctsiz.b.pktcnt == 0) {
++ /* Core halts channel in these cases. */
++ release_channel(_hcd, _hc, _qtd, _halt_status);
++ } else {
++ /* Flush any outstanding requests from the Tx queue. */
++ halt_channel(_hcd, _hc, _qtd, _halt_status);
++ }
++}
++
++/**
++ * Handles a host channel Transfer Complete interrupt. This handler may be
++ * called in either DMA mode or Slave mode.
++ */
++static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd)
++{
++ int urb_xfer_done;
++ dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE;
++ struct urb *urb = _qtd->urb;
++ int pipe_type = usb_pipetype(urb->pipe);
++ hcint_data_t hcint;
++ hcintmsk_data_t hcintmsk;
++
++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++ "Transfer Complete--\n", _hc->hc_num);
++
++ hcint.d32 = dwc_read_reg32(&_hc_regs->hcint);
++ hcintmsk.d32 = dwc_read_reg32(&_hc_regs->hcintmsk);
++ DWC_DEBUGPL(DBG_HCDV, " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
++ /*
++ * Handle xfer complete on CSPLIT.
++ */
++ if (_hc->qh->do_split) {
++ _qtd->complete_split = 0;
++ }
++
++ /* Update the QTD and URB states. */
++ switch (pipe_type) {
++ case PIPE_CONTROL:
++ switch (_qtd->control_phase) {
++ case DWC_OTG_CONTROL_SETUP:
++ if (urb->transfer_buffer_length > 0) {
++ _qtd->control_phase = DWC_OTG_CONTROL_DATA;
++ } else {
++ _qtd->control_phase = DWC_OTG_CONTROL_STATUS;
++ }
++ DWC_DEBUGPL(DBG_HCDV, " Control setup transaction done\n");
++ halt_status = DWC_OTG_HC_XFER_COMPLETE;
++ break;
++ case DWC_OTG_CONTROL_DATA: {
++ urb_xfer_done = update_urb_state_xfer_comp(_hcd, _hc, _hc_regs, urb, _qtd);
++ if (urb_xfer_done) {
++ _qtd->control_phase = DWC_OTG_CONTROL_STATUS;
++ DWC_DEBUGPL(DBG_HCDV, " Control data transfer done\n");
++ } else {
++ save_data_toggle(_hc, _hc_regs, _qtd);
++ }
++
++ // Added by Sheeja S on 14th Sep 07 for debuging
++// dump_msg(urb->transfer_buffer, urb->transfer_buffer_length);
++
++ halt_status = DWC_OTG_HC_XFER_COMPLETE;
++ break;
++ }
++ case DWC_OTG_CONTROL_STATUS:
++ DWC_DEBUGPL(DBG_HCDV, " Control transfer complete\n");
++ if (urb->status == -EINPROGRESS) {
++ urb->status = 0;
++ }
++ dwc_otg_hcd_complete_urb(_hcd, urb, urb->status);
++ halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
++ break;
++ }
++
++ complete_non_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, halt_status);
++ break;
++ case PIPE_BULK:
++ DWC_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n");
++ urb_xfer_done = update_urb_state_xfer_comp(_hcd, _hc, _hc_regs, urb, _qtd);
++ if (urb_xfer_done) {
++ dwc_otg_hcd_complete_urb(_hcd, urb, urb->status);
++ halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
++ } else {
++ halt_status = DWC_OTG_HC_XFER_COMPLETE;
++ }
++
++ save_data_toggle(_hc, _hc_regs, _qtd);
++ complete_non_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, halt_status);
++ break;
++ case PIPE_INTERRUPT:
++ DWC_DEBUGPL(DBG_HCDV, " Interrupt transfer complete\n");
++ update_urb_state_xfer_comp(_hcd, _hc, _hc_regs, urb, _qtd);
++
++ /*
++ * Interrupt URB is done on the first transfer complete
++ * interrupt.
++ */
++ dwc_otg_hcd_complete_urb(_hcd, urb, urb->status);
++ save_data_toggle(_hc, _hc_regs, _qtd);
++ complete_periodic_xfer(_hcd, _hc, _hc_regs, _qtd,
++ DWC_OTG_HC_XFER_URB_COMPLETE);
++ break;
++ case PIPE_ISOCHRONOUS:
++ DWC_DEBUGPL(DBG_HCDV, " Isochronous transfer complete\n");
++ if (_qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL)
++ {
++ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd,
++ DWC_OTG_HC_XFER_COMPLETE);
++ }
++ complete_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, halt_status);
++ break;
++ }
++
++ disable_hc_int(_hc_regs,xfercompl);
++ hcint.d32 = dwc_read_reg32(&_hc_regs->hcint);
++ hcintmsk.d32 = dwc_read_reg32(&_hc_regs->hcintmsk);
++ DWC_DEBUGPL(DBG_HCDV, " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
++ return 1;
++}
++
++/**
++ * Handles a host channel STALL interrupt. This handler may be called in
++ * either DMA mode or Slave mode.
++ */
++static int32_t handle_hc_stall_intr(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd)
++{
++ struct urb *urb = _qtd->urb;
++ int pipe_type = usb_pipetype(urb->pipe);
++
++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++ "STALL Received--\n", _hc->hc_num);
++
++ if (pipe_type == PIPE_CONTROL) {
++ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPIPE);
++ }
++
++ if (pipe_type == PIPE_BULK || pipe_type == PIPE_INTERRUPT) {
++ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPIPE);
++ /*
++ * USB protocol requires resetting the data toggle for bulk
++ * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
++ * setup command is issued to the endpoint. Anticipate the
++ * CLEAR_FEATURE command since a STALL has occurred and reset
++ * the data toggle now.
++ */
++ _hc->qh->data_toggle = 0;
++ }
++
++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_STALL);
++
++ disable_hc_int(_hc_regs,stall);
++
++ return 1;
++}
++
++/*
++ * Updates the state of the URB when a transfer has been stopped due to an
++ * abnormal condition before the transfer completes. Modifies the
++ * actual_length field of the URB to reflect the number of bytes that have
++ * actually been transferred via the host channel.
++ */
++static void update_urb_state_xfer_intr(dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ struct urb *_urb,
++ dwc_otg_qtd_t *_qtd,
++ dwc_otg_halt_status_e _halt_status)
++{
++ uint32_t bytes_transferred = get_actual_xfer_length(_hc, _hc_regs, _qtd,
++ _halt_status, NULL);
++ _urb->actual_length += bytes_transferred;
++
++#ifdef DEBUG
++ {
++ hctsiz_data_t hctsiz;
++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz);
++ DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
++ __func__, (_hc->ep_is_in ? "IN" : "OUT"), _hc->hc_num);
++ DWC_DEBUGPL(DBG_HCDV, " _hc->start_pkt_count %d\n", _hc->start_pkt_count);
++ DWC_DEBUGPL(DBG_HCDV, " hctsiz.pktcnt %d\n", hctsiz.b.pktcnt);
++ DWC_DEBUGPL(DBG_HCDV, " _hc->max_packet %d\n", _hc->max_packet);
++ DWC_DEBUGPL(DBG_HCDV, " bytes_transferred %d\n", bytes_transferred);
++ DWC_DEBUGPL(DBG_HCDV, " _urb->actual_length %d\n", _urb->actual_length);
++ DWC_DEBUGPL(DBG_HCDV, " _urb->transfer_buffer_length %d\n",
++ _urb->transfer_buffer_length);
++ }
++#endif
++}
++
++/**
++ * Handles a host channel NAK interrupt. This handler may be called in either
++ * DMA mode or Slave mode.
++ */
++static int32_t handle_hc_nak_intr(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd)
++{
++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++ "NAK Received--\n", _hc->hc_num);
++
++ /*
++ * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
++ * interrupt. Re-start the SSPLIT transfer.
++ */
++ if (_hc->do_split) {
++ if (_hc->complete_split) {
++ _qtd->error_count = 0;
++ }
++ _qtd->complete_split = 0;
++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK);
++ goto handle_nak_done;
++ }
++
++ switch (usb_pipetype(_qtd->urb->pipe)) {
++ case PIPE_CONTROL:
++ case PIPE_BULK:
++ if (_hcd->core_if->dma_enable && _hc->ep_is_in) {
++ /*
++ * NAK interrupts are enabled on bulk/control IN
++ * transfers in DMA mode for the sole purpose of
++ * resetting the error count after a transaction error
++ * occurs. The core will continue transferring data.
++ */
++ _qtd->error_count = 0;
++ goto handle_nak_done;
++ }
++
++ /*
++ * NAK interrupts normally occur during OUT transfers in DMA
++ * or Slave mode. For IN transfers, more requests will be
++ * queued as request queue space is available.
++ */
++ _qtd->error_count = 0;
++
++ if (!_hc->qh->ping_state) {
++ update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb,
++ _qtd, DWC_OTG_HC_XFER_NAK);
++ save_data_toggle(_hc, _hc_regs, _qtd);
++ if (_qtd->urb->dev->speed == USB_SPEED_HIGH) {
++ _hc->qh->ping_state = 1;
++ }
++ }
++
++ /*
++ * Halt the channel so the transfer can be re-started from
++ * the appropriate point or the PING protocol will
++ * start/continue.
++ */
++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK);
++ break;
++ case PIPE_INTERRUPT:
++ _qtd->error_count = 0;
++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK);
++ break;
++ case PIPE_ISOCHRONOUS:
++ /* Should never get called for isochronous transfers. */
++ BUG();
++ break;
++ }
++
++handle_nak_done:
++ disable_hc_int(_hc_regs,nak);
++
++ return 1;
++}
++
++/**
++ * Handles a host channel ACK interrupt. This interrupt is enabled when
++ * performing the PING protocol in Slave mode, when errors occur during
++ * either Slave mode or DMA mode, and during Start Split transactions.
++ */
++static int32_t handle_hc_ack_intr(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd)
++{
++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++ "ACK Received--\n", _hc->hc_num);
++
++ if (_hc->do_split) {
++ /*
++ * Handle ACK on SSPLIT.
++ * ACK should not occur in CSPLIT.
++ */
++ if ((!_hc->ep_is_in) && (_hc->data_pid_start != DWC_OTG_HC_PID_SETUP)) {
++ _qtd->ssplit_out_xfer_count = _hc->xfer_len;
++ }
++ if (!(_hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !_hc->ep_is_in)) {
++ /* Don't need complete for isochronous out transfers. */
++ _qtd->complete_split = 1;
++ }
++
++ /* ISOC OUT */
++ if ((_hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && !_hc->ep_is_in) {
++ switch (_hc->xact_pos) {
++ case DWC_HCSPLIT_XACTPOS_ALL:
++ break;
++ case DWC_HCSPLIT_XACTPOS_END:
++ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
++ _qtd->isoc_split_offset = 0;
++ break;
++ case DWC_HCSPLIT_XACTPOS_BEGIN:
++ case DWC_HCSPLIT_XACTPOS_MID:
++ /*
++ * For BEGIN or MID, calculate the length for
++ * the next microframe to determine the correct
++ * SSPLIT token, either MID or END.
++ */
++ do {
++ struct usb_iso_packet_descriptor *frame_desc;
++
++ frame_desc = &_qtd->urb->iso_frame_desc[_qtd->isoc_frame_index];
++ _qtd->isoc_split_offset += 188;
++
++ if ((frame_desc->length - _qtd->isoc_split_offset) <= 188) {
++ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_END;
++ }
++ else {
++ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_MID;
++ }
++
++ } while (0);
++ break;
++ }
++ }
++ else {
++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_ACK);
++ }
++ } else {
++ _qtd->error_count = 0;
++
++ if (_hc->qh->ping_state) {
++ _hc->qh->ping_state = 0;
++ /*
++ * Halt the channel so the transfer can be re-started
++ * from the appropriate point. This only happens in
++ * Slave mode. In DMA mode, the ping_state is cleared
++ * when the transfer is started because the core
++ * automatically executes the PING, then the transfer.
++ */
++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_ACK);
++ }
++ }
++
++ /*
++ * If the ACK occurred when _not_ in the PING state, let the channel
++ * continue transferring data after clearing the error count.
++ */
++
++ disable_hc_int(_hc_regs,ack);
++
++ return 1;
++}
++
++/**
++ * Handles a host channel NYET interrupt. This interrupt should only occur on
++ * Bulk and Control OUT endpoints and for complete split transactions. If a
++ * NYET occurs at the same time as a Transfer Complete interrupt, it is
++ * handled in the xfercomp interrupt handler, not here. This handler may be
++ * called in either DMA mode or Slave mode.
++ */
++static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd)
++{
++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++ "NYET Received--\n", _hc->hc_num);
++
++ /*
++ * NYET on CSPLIT
++ * re-do the CSPLIT immediately on non-periodic
++ */
++ if ((_hc->do_split) && (_hc->complete_split)) {
++ if ((_hc->ep_type == DWC_OTG_EP_TYPE_INTR) ||
++ (_hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {
++ int frnum = dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(_hcd));
++
++ if (dwc_full_frame_num(frnum) !=
++ dwc_full_frame_num(_hc->qh->sched_frame)) {
++ /*
++ * No longer in the same full speed frame.
++ * Treat this as a transaction error.
++ */
++#if 0
++ /** @todo Fix system performance so this can
++ * be treated as an error. Right now complete
++ * splits cannot be scheduled precisely enough
++ * due to other system activity, so this error
++ * occurs regularly in Slave mode.
++ */
++ _qtd->error_count++;
++#endif
++ _qtd->complete_split = 0;
++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR);
++ /** @todo add support for isoc release */
++ goto handle_nyet_done;
++ }
++ }
++
++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NYET);
++ goto handle_nyet_done;
++ }
++
++ _hc->qh->ping_state = 1;
++ _qtd->error_count = 0;
++
++ update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb, _qtd,
++ DWC_OTG_HC_XFER_NYET);
++ save_data_toggle(_hc, _hc_regs, _qtd);
++
++ /*
++ * Halt the channel and re-start the transfer so the PING
++ * protocol will start.
++ */
++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NYET);
++
++handle_nyet_done:
++ disable_hc_int(_hc_regs,nyet);
++ return 1;
++}
++
++/**
++ * Handles a host channel babble interrupt. This handler may be called in
++ * either DMA mode or Slave mode.
++ */
++static int32_t handle_hc_babble_intr(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd)
++{
++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++ "Babble Error--\n", _hc->hc_num);
++ if (_hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
++ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EOVERFLOW);
++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_BABBLE_ERR);
++ } else {
++ dwc_otg_halt_status_e halt_status;
++ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd,
++ DWC_OTG_HC_XFER_BABBLE_ERR);
++ halt_channel(_hcd, _hc, _qtd, halt_status);
++ }
++ disable_hc_int(_hc_regs,bblerr);
++ return 1;
++}
++
++/**
++ * Handles a host channel AHB error interrupt. This handler is only called in
++ * DMA mode.
++ */
++static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd)
++{
++ hcchar_data_t hcchar;
++ hcsplt_data_t hcsplt;
++ hctsiz_data_t hctsiz;
++ uint32_t hcdma;
++ struct urb *urb = _qtd->urb;
++
++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++ "AHB Error--\n", _hc->hc_num);
++
++ hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar);
++ hcsplt.d32 = dwc_read_reg32(&_hc_regs->hcsplt);
++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz);
++ hcdma = dwc_read_reg32(&_hc_regs->hcdma);
++
++ DWC_ERROR("AHB ERROR, Channel %d\n", _hc->hc_num);
++ DWC_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
++ DWC_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);
++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n");
++ DWC_ERROR(" Device address: %d\n", usb_pipedevice(urb->pipe));
++ DWC_ERROR(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
++ (usb_pipein(urb->pipe) ? "IN" : "OUT"));
++ DWC_ERROR(" Endpoint type: %s\n",
++ ({char *pipetype;
++ switch (usb_pipetype(urb->pipe)) {
++ case PIPE_CONTROL: pipetype = "CONTROL"; break;
++ case PIPE_BULK: pipetype = "BULK"; break;
++ case PIPE_INTERRUPT: pipetype = "INTERRUPT"; break;
++ case PIPE_ISOCHRONOUS: pipetype = "ISOCHRONOUS"; break;
++ default: pipetype = "UNKNOWN"; break;
++ }; pipetype;}));
++ DWC_ERROR(" Speed: %s\n",
++ ({char *speed;
++ switch (urb->dev->speed) {
++ case USB_SPEED_HIGH: speed = "HIGH"; break;
++ case USB_SPEED_FULL: speed = "FULL"; break;
++ case USB_SPEED_LOW: speed = "LOW"; break;
++ default: speed = "UNKNOWN"; break;
++ }; speed;}));
++ DWC_ERROR(" Max packet size: %d\n",
++ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
++ DWC_ERROR(" Data buffer length: %d\n", urb->transfer_buffer_length);
++ DWC_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n",
++ urb->transfer_buffer, (void *)urb->transfer_dma);
++ DWC_ERROR(" Setup buffer: %p, Setup DMA: %p\n",
++ urb->setup_packet, (void *)urb->setup_dma);
++ DWC_ERROR(" Interval: %d\n", urb->interval);
++
++ dwc_otg_hcd_complete_urb(_hcd, urb, -EIO);
++
++ /*
++ * Force a channel halt. Don't call halt_channel because that won't
++ * write to the HCCHARn register in DMA mode to force the halt.
++ */
++ dwc_otg_hc_halt(_hcd->core_if, _hc, DWC_OTG_HC_XFER_AHB_ERR);
++
++ disable_hc_int(_hc_regs,ahberr);
++ return 1;
++}
++
++/**
++ * Handles a host channel transaction error interrupt. This handler may be
++ * called in either DMA mode or Slave mode.
++ */
++static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd)
++{
++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++ "Transaction Error--\n", _hc->hc_num);
++
++ switch (usb_pipetype(_qtd->urb->pipe)) {
++ case PIPE_CONTROL:
++ case PIPE_BULK:
++ _qtd->error_count++;
++ if (!_hc->qh->ping_state) {
++ update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb,
++ _qtd, DWC_OTG_HC_XFER_XACT_ERR);
++ save_data_toggle(_hc, _hc_regs, _qtd);
++ if (!_hc->ep_is_in && _qtd->urb->dev->speed == USB_SPEED_HIGH) {
++ _hc->qh->ping_state = 1;
++ }
++ }
++
++ /*
++ * Halt the channel so the transfer can be re-started from
++ * the appropriate point or the PING protocol will start.
++ */
++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR);
++ break;
++ case PIPE_INTERRUPT:
++ _qtd->error_count++;
++ if ((_hc->do_split) && (_hc->complete_split)) {
++ _qtd->complete_split = 0;
++ }
++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR);
++ break;
++ case PIPE_ISOCHRONOUS:
++ {
++ dwc_otg_halt_status_e halt_status;
++ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd,
++ DWC_OTG_HC_XFER_XACT_ERR);
++
++ halt_channel(_hcd, _hc, _qtd, halt_status);
++ }
++ break;
++ }
++
++
++ disable_hc_int(_hc_regs,xacterr);
++
++ return 1;
++}
++
++/**
++ * Handles a host channel frame overrun interrupt. This handler may be called
++ * in either DMA mode or Slave mode.
++ */
++static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd)
++{
++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++ "Frame Overrun--\n", _hc->hc_num);
++
++ switch (usb_pipetype(_qtd->urb->pipe)) {
++ case PIPE_CONTROL:
++ case PIPE_BULK:
++ break;
++ case PIPE_INTERRUPT:
++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN);
++ break;
++ case PIPE_ISOCHRONOUS:
++ {
++ dwc_otg_halt_status_e halt_status;
++ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd,
++ DWC_OTG_HC_XFER_FRAME_OVERRUN);
++
++ halt_channel(_hcd, _hc, _qtd, halt_status);
++ }
++ break;
++ }
++
++ disable_hc_int(_hc_regs,frmovrun);
++
++ return 1;
++}
++
++/**
++ * Handles a host channel data toggle error interrupt. This handler may be
++ * called in either DMA mode or Slave mode.
++ */
++static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd)
++{
++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++ "Data Toggle Error--\n", _hc->hc_num);
++
++ if (_hc->ep_is_in) {
++ _qtd->error_count = 0;
++ } else {
++ DWC_ERROR("Data Toggle Error on OUT transfer,"
++ "channel %d\n", _hc->hc_num);
++ }
++
++ disable_hc_int(_hc_regs,datatglerr);
++
++ return 1;
++}
++
++#ifdef DEBUG
++/**
++ * This function is for debug only. It checks that a valid halt status is set
++ * and that HCCHARn.chdis is clear. If there's a problem, corrective action is
++ * taken and a warning is issued.
++ * @return 1 if halt status is ok, 0 otherwise.
++ */
++static inline int halt_status_ok(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd)
++{
++ hcchar_data_t hcchar;
++ hctsiz_data_t hctsiz;
++ hcint_data_t hcint;
++ hcintmsk_data_t hcintmsk;
++ hcsplt_data_t hcsplt;
++
++ if (_hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) {
++ /*
++ * This code is here only as a check. This condition should
++ * never happen. Ignore the halt if it does occur.
++ */
++ hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar);
++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz);
++ hcint.d32 = dwc_read_reg32(&_hc_regs->hcint);
++ hcintmsk.d32 = dwc_read_reg32(&_hc_regs->hcintmsk);
++ hcsplt.d32 = dwc_read_reg32(&_hc_regs->hcsplt);
++ DWC_WARN("%s: _hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, "
++ "channel %d, hcchar 0x%08x, hctsiz 0x%08x, "
++ "hcint 0x%08x, hcintmsk 0x%08x, "
++ "hcsplt 0x%08x, qtd->complete_split %d\n",
++ __func__, _hc->hc_num, hcchar.d32, hctsiz.d32,
++ hcint.d32, hcintmsk.d32,
++ hcsplt.d32, _qtd->complete_split);
++
++ DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n",
++ __func__, _hc->hc_num);
++ DWC_WARN("\n");
++ clear_hc_int(_hc_regs,chhltd);
++ return 0;
++ }
++
++ /*
++ * This code is here only as a check. hcchar.chdis should
++ * never be set when the halt interrupt occurs. Halt the
++ * channel again if it does occur.
++ */
++ hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar);
++ if (hcchar.b.chdis) {
++ DWC_WARN("%s: hcchar.chdis set unexpectedly, "
++ "hcchar 0x%08x, trying to halt again\n",
++ __func__, hcchar.d32);
++ clear_hc_int(_hc_regs,chhltd);
++ _hc->halt_pending = 0;
++ halt_channel(_hcd, _hc, _qtd, _hc->halt_status);
++ return 0;
++ }
++
++ return 1;
++}
++#endif
++
++/**
++ * Handles a host Channel Halted interrupt in DMA mode. This handler
++ * determines the reason the channel halted and proceeds accordingly.
++ */
++static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd)
++{
++ hcint_data_t hcint;
++ hcintmsk_data_t hcintmsk;
++
++ if (_hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
++ _hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
++ /*
++ * Just release the channel. A dequeue can happen on a
++ * transfer timeout. In the case of an AHB Error, the channel
++ * was forced to halt because there's no way to gracefully
++ * recover.
++ */
++ release_channel(_hcd, _hc, _qtd, _hc->halt_status);
++ return;
++ }
++
++ /* Read the HCINTn register to determine the cause for the halt. */
++ hcint.d32 = dwc_read_reg32(&_hc_regs->hcint);
++ hcintmsk.d32 = dwc_read_reg32(&_hc_regs->hcintmsk);
++
++ if (hcint.b.xfercomp) {
++ /** @todo This is here because of a possible hardware bug. Spec
++ * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT
++ * interrupt w/ACK bit set should occur, but I only see the
++ * XFERCOMP bit, even with it masked out. This is a workaround
++ * for that behavior. Should fix this when hardware is fixed.
++ */
++ if ((_hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && (!_hc->ep_is_in)) {
++ handle_hc_ack_intr(_hcd, _hc, _hc_regs, _qtd);
++ }
++ handle_hc_xfercomp_intr(_hcd, _hc, _hc_regs, _qtd);
++ } else if (hcint.b.stall) {
++ handle_hc_stall_intr(_hcd, _hc, _hc_regs, _qtd);
++ } else if (hcint.b.xacterr) {
++ /*
++ * Must handle xacterr before nak or ack. Could get a xacterr
++ * at the same time as either of these on a BULK/CONTROL OUT
++ * that started with a PING. The xacterr takes precedence.
++ */
++ handle_hc_xacterr_intr(_hcd, _hc, _hc_regs, _qtd);
++ } else if (hcint.b.nyet) {
++ /*
++ * Must handle nyet before nak or ack. Could get a nyet at the
++ * same time as either of those on a BULK/CONTROL OUT that
++ * started with a PING. The nyet takes precedence.
++ */
++ handle_hc_nyet_intr(_hcd, _hc, _hc_regs, _qtd);
++ } else if (hcint.b.bblerr) {
++ handle_hc_babble_intr(_hcd, _hc, _hc_regs, _qtd);
++ } else if (hcint.b.frmovrun) {
++ handle_hc_frmovrun_intr(_hcd, _hc, _hc_regs, _qtd);
++ } else if (hcint.b.nak && !hcintmsk.b.nak) {
++ /*
++ * If nak is not masked, it's because a non-split IN transfer
++ * is in an error state. In that case, the nak is handled by
++ * the nak interrupt handler, not here. Handle nak here for
++ * BULK/CONTROL OUT transfers, which halt on a NAK to allow
++ * rewinding the buffer pointer.
++ */
++ handle_hc_nak_intr(_hcd, _hc, _hc_regs, _qtd);
++ } else if (hcint.b.ack && !hcintmsk.b.ack) {
++ /*
++ * If ack is not masked, it's because a non-split IN transfer
++ * is in an error state. In that case, the ack is handled by
++ * the ack interrupt handler, not here. Handle ack here for
++ * split transfers. Start splits halt on ACK.
++ */
++ handle_hc_ack_intr(_hcd, _hc, _hc_regs, _qtd);
++ } else {
++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
++ /*
++ * A periodic transfer halted with no other channel
++ * interrupts set. Assume it was halted by the core
++ * because it could not be completed in its scheduled
++ * (micro)frame.
++ */
++#ifdef DEBUG
++ DWC_PRINT("%s: Halt channel %d (assume incomplete periodic transfer)\n",
++ __func__, _hc->hc_num);
++#endif
++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);
++ } else {
++ DWC_ERROR("%s: Channel %d, DMA Mode -- ChHltd set, but reason "
++ "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n",
++ __func__, _hc->hc_num, hcint.d32,
++ dwc_read_reg32(&_hcd->core_if->core_global_regs->gintsts));
++ }
++ }
++}
++
++/**
++ * Handles a host channel Channel Halted interrupt.
++ *
++ * In slave mode, this handler is called only when the driver specifically
++ * requests a halt. This occurs during handling other host channel interrupts
++ * (e.g. nak, xacterr, stall, nyet, etc.).
++ *
++ * In DMA mode, this is the interrupt that occurs when the core has finished
++ * processing a transfer on a channel. Other host channel interrupts (except
++ * ahberr) are disabled in DMA mode.
++ */
++static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t *_hcd,
++ dwc_hc_t *_hc,
++ dwc_otg_hc_regs_t *_hc_regs,
++ dwc_otg_qtd_t *_qtd)
++{
++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
++ "Channel Halted--\n", _hc->hc_num);
++
++ if (_hcd->core_if->dma_enable) {
++ handle_hc_chhltd_intr_dma(_hcd, _hc, _hc_regs, _qtd);
++ } else {
++#ifdef DEBUG
++ if (!halt_status_ok(_hcd, _hc, _hc_regs, _qtd)) {
++ return 1;
++ }
++#endif
++ release_channel(_hcd, _hc, _qtd, _hc->halt_status);
++ }
++
++ return 1;
++}
++
++/** Handles interrupt for a specific Host Channel */
++int32_t dwc_otg_hcd_handle_hc_n_intr (dwc_otg_hcd_t *_dwc_otg_hcd, uint32_t _num)
++{
++ int retval = 0;
++ hcint_data_t hcint;
++ hcintmsk_data_t hcintmsk;
++ dwc_hc_t *hc;
++ dwc_otg_hc_regs_t *hc_regs;
++ dwc_otg_qtd_t *qtd;
++
++ DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", _num);
++
++ hc = _dwc_otg_hcd->hc_ptr_array[_num];
++ hc_regs = _dwc_otg_hcd->core_if->host_if->hc_regs[_num];
++ qtd = list_entry(hc->qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry);
++
++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
++ hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk);
++ DWC_DEBUGPL(DBG_HCDV, " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
++ hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
++ hcint.d32 = hcint.d32 & hcintmsk.d32;
++
++ if (!_dwc_otg_hcd->core_if->dma_enable) {
++ if ((hcint.b.chhltd) && (hcint.d32 != 0x2)) {
++ hcint.b.chhltd = 0;
++ }
++ }
++
++ if (hcint.b.xfercomp) {
++ retval |= handle_hc_xfercomp_intr(_dwc_otg_hcd, hc, hc_regs, qtd);
++ /*
++ * If NYET occurred at same time as Xfer Complete, the NYET is
++ * handled by the Xfer Complete interrupt handler. Don't want
++ * to call the NYET interrupt handler in this case.
++ */
++ hcint.b.nyet = 0;
++ }
++ if (hcint.b.chhltd) {
++ retval |= handle_hc_chhltd_intr(_dwc_otg_hcd, hc, hc_regs, qtd);
++ }
++ if (hcint.b.ahberr) {
++ retval |= handle_hc_ahberr_intr(_dwc_otg_hcd, hc, hc_regs, qtd);
++ }
++ if (hcint.b.stall) {
++ retval |= handle_hc_stall_intr(_dwc_otg_hcd, hc, hc_regs, qtd);
++ }
++ if (hcint.b.nak) {
++ retval |= handle_hc_nak_intr(_dwc_otg_hcd, hc, hc_regs, qtd);
++ }
++ if (hcint.b.ack) {
++ retval |= handle_hc_ack_intr(_dwc_otg_hcd, hc, hc_regs, qtd);
++ }
++ if (hcint.b.nyet) {
++ retval |= handle_hc_nyet_intr(_dwc_otg_hcd, hc, hc_regs, qtd);
++ }
++ if (hcint.b.xacterr) {
++ retval |= handle_hc_xacterr_intr(_dwc_otg_hcd, hc, hc_regs, qtd);
++ }
++ if (hcint.b.bblerr) {
++ retval |= handle_hc_babble_intr(_dwc_otg_hcd, hc, hc_regs, qtd);
++ }
++ if (hcint.b.frmovrun) {
++ retval |= handle_hc_frmovrun_intr(_dwc_otg_hcd, hc, hc_regs, qtd);
++ }
++ if (hcint.b.datatglerr) {
++ retval |= handle_hc_datatglerr_intr(_dwc_otg_hcd, hc, hc_regs, qtd);
++ }
++
++ return retval;
++}
++
++#endif /* DWC_DEVICE_ONLY */
+diff --git a/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c
+new file mode 100644
+index 0000000..450d6c9
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c
+@@ -0,0 +1,660 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd_queue.c $
++ * $Revision: #4 $
++ * $Date: 2005/09/15 $
++ * $Change: 537387 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++#ifndef DWC_DEVICE_ONLY
++
++/**
++ * @file
++ *
++ * This file contains the functions to manage Queue Heads and Queue
++ * Transfer Descriptors.
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/errno.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/string.h>
++
++#ifdef _USE_ATTR_
++#include <asm/arch/lm.h>
++#endif
++
++#include "dwc_otg_driver.h"
++#include "dwc_otg_hcd.h"
++#include "dwc_otg_regs.h"
++
++/**
++ * This function allocates and initializes a QH.
++ *
++ * @param _hcd The HCD state structure for the DWC OTG controller.
++ * @param[in] _urb Holds the information about the device/endpoint that we need
++ * to initialize the QH.
++ *
++ * @return Returns pointer to the newly allocated QH, or NULL on error. */
++dwc_otg_qh_t *dwc_otg_hcd_qh_create (dwc_otg_hcd_t *_hcd, struct urb *_urb)
++{
++ dwc_otg_qh_t *qh;
++
++ /* Allocate memory */
++ /** @todo add memflags argument */
++ qh = dwc_otg_hcd_qh_alloc ();
++ if (qh == NULL) {
++ return NULL;
++ }
++
++ dwc_otg_hcd_qh_init (_hcd, qh, _urb);
++ return qh;
++}
++
++/** Free each QTD in the QH's QTD-list then free the QH. QH should already be
++ * removed from a list. QTD list should already be empty if called from URB
++ * Dequeue.
++ *
++ * @param[in] _qh The QH to free.
++ */
++void dwc_otg_hcd_qh_free (dwc_otg_qh_t *_qh)
++{
++ dwc_otg_qtd_t *qtd;
++ struct list_head *pos;
++ unsigned long flags;
++
++ /* Free each QTD in the QTD list */
++ local_irq_save (flags);
++ for (pos = _qh->qtd_list.next;
++ pos != &_qh->qtd_list;
++ pos = _qh->qtd_list.next)
++ {
++ list_del (pos);
++ qtd = dwc_list_to_qtd (pos);
++ dwc_otg_hcd_qtd_free (qtd);
++ }
++ local_irq_restore (flags);
++
++ kfree (_qh);
++ return;
++}
++
++/** Initializes a QH structure.
++ *
++ * @param[in] _hcd The HCD state structure for the DWC OTG controller.
++ * @param[in] _qh The QH to init.
++ * @param[in] _urb Holds the information about the device/endpoint that we need
++ * to initialize the QH. */
++#define SCHEDULE_SLOP 10
++void dwc_otg_hcd_qh_init(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, struct urb *_urb)
++{
++ memset (_qh, 0, sizeof (dwc_otg_qh_t));
++
++ /* Initialize QH */
++ switch (usb_pipetype(_urb->pipe)) {
++ case PIPE_CONTROL:
++ _qh->ep_type = USB_ENDPOINT_XFER_CONTROL;
++ break;
++ case PIPE_BULK:
++ _qh->ep_type = USB_ENDPOINT_XFER_BULK;
++ break;
++ case PIPE_ISOCHRONOUS:
++ _qh->ep_type = USB_ENDPOINT_XFER_ISOC;
++ break;
++ case PIPE_INTERRUPT:
++ _qh->ep_type = USB_ENDPOINT_XFER_INT;
++ break;
++ }
++
++ _qh->ep_is_in = usb_pipein(_urb->pipe) ? 1 : 0;
++
++ _qh->data_toggle = DWC_OTG_HC_PID_DATA0;
++ _qh->maxp = usb_maxpacket(_urb->dev, _urb->pipe, !(usb_pipein(_urb->pipe)));
++ INIT_LIST_HEAD(&_qh->qtd_list);
++ INIT_LIST_HEAD(&_qh->qh_list_entry);
++ _qh->channel = NULL;
++
++ /* FS/LS Enpoint on HS Hub
++ * NOT virtual root hub */
++ _qh->do_split = 0;
++ if (((_urb->dev->speed == USB_SPEED_LOW) ||
++ (_urb->dev->speed == USB_SPEED_FULL)) &&
++ (_urb->dev->tt) && (_urb->dev->tt->hub/*AlenOh*/) && (_urb->dev->tt->hub->devnum != 1))
++ {
++ DWC_DEBUGPL(DBG_HCD, "QH init: EP %d: TT found at hub addr %d, for port %d\n",
++ usb_pipeendpoint(_urb->pipe), _urb->dev->tt->hub->devnum,
++ _urb->dev->ttport);
++ _qh->do_split = 1;
++ }
++
++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT ||
++ _qh->ep_type == USB_ENDPOINT_XFER_ISOC) {
++ /* Compute scheduling parameters once and save them. */
++ hprt0_data_t hprt;
++
++ /** @todo Account for split transfers in the bus time. */
++ int bytecount = dwc_hb_mult(_qh->maxp) * dwc_max_packet(_qh->maxp);
++ _qh->usecs = usb_calc_bus_time(_urb->dev->speed,
++ usb_pipein(_urb->pipe),
++ (_qh->ep_type == USB_ENDPOINT_XFER_ISOC),
++ bytecount);
++
++ /* Start in a slightly future (micro)frame. */
++ _qh->sched_frame = dwc_frame_num_inc(_hcd->frame_number,
++ SCHEDULE_SLOP);
++
++ _qh->interval = _urb->interval;
++#if 0
++ /* Increase interrupt polling rate for debugging. */
++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) {
++ _qh->interval = 8;
++ }
++#endif
++ hprt.d32 = dwc_read_reg32(_hcd->core_if->host_if->hprt0);
++ if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
++ ((_urb->dev->speed == USB_SPEED_LOW) ||
++ (_urb->dev->speed == USB_SPEED_FULL)))
++ {
++ _qh->interval *= 8;
++ _qh->sched_frame |= 0x7;
++ _qh->start_split_frame = _qh->sched_frame;
++ }
++
++ }
++
++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", _qh);
++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n",
++ _urb->dev->devnum);
++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n",
++ usb_pipeendpoint(_urb->pipe),
++ usb_pipein(_urb->pipe) == USB_DIR_IN ? "IN" : "OUT");
++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Speed = %s\n",
++ ({ char *speed; switch (_urb->dev->speed) {
++ case USB_SPEED_LOW: speed = "low"; break;
++ case USB_SPEED_FULL: speed = "full"; break;
++ case USB_SPEED_HIGH: speed = "high"; break;
++ default: speed = "?"; break;
++ }; speed;}));
++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n",
++ ({ char *type; switch (_qh->ep_type) {
++ case USB_ENDPOINT_XFER_ISOC: type = "isochronous"; break;
++ case USB_ENDPOINT_XFER_INT: type = "interrupt"; break;
++ case USB_ENDPOINT_XFER_CONTROL: type = "control"; break;
++ case USB_ENDPOINT_XFER_BULK: type = "bulk"; break;
++ default: type = "?"; break;
++ }; type;}));
++#ifdef DEBUG
++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) {
++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
++ _qh->usecs);
++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
++ _qh->interval);
++ }
++#endif
++
++ return;
++}
++
++/**
++ * Checks that a channel is available for a periodic transfer.
++ *
++ * @return 0 if successful, negative error code otherise.
++ */
++static int periodic_channel_available(dwc_otg_hcd_t *_hcd)
++{
++ /*
++ * Currently assuming that there is a dedicated host channnel for each
++ * periodic transaction plus at least one host channel for
++ * non-periodic transactions.
++ */
++ int status;
++ int num_channels;
++
++ num_channels = _hcd->core_if->core_params->host_channels;
++ if ((_hcd->periodic_channels + _hcd->non_periodic_channels < num_channels) &&
++ (_hcd->periodic_channels < num_channels - 1)) {
++ status = 0;
++ }
++ else {
++ DWC_NOTICE("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
++ __func__, num_channels, _hcd->periodic_channels,
++ _hcd->non_periodic_channels);
++ status = -ENOSPC;
++ }
++
++ return status;
++}
++
++/**
++ * Checks that there is sufficient bandwidth for the specified QH in the
++ * periodic schedule. For simplicity, this calculation assumes that all the
++ * transfers in the periodic schedule may occur in the same (micro)frame.
++ *
++ * @param _hcd The HCD state structure for the DWC OTG controller.
++ * @param _qh QH containing periodic bandwidth required.
++ *
++ * @return 0 if successful, negative error code otherwise.
++ */
++static int check_periodic_bandwidth(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh)
++{
++ int status;
++ uint16_t max_claimed_usecs;
++
++ status = 0;
++
++ //AlenOh, It prevent unwanted change of OTG speed
++ //if (_hcd->core_if->core_params->speed == DWC_SPEED_PARAM_HIGH) {
++ if (_hcd->speed == DWC_SPEED_PARAM_HIGH) {
++ /*
++ * High speed mode.
++ * Max periodic usecs is 80% x 125 usec = 100 usec.
++ */
++ max_claimed_usecs = 100 - _qh->usecs;
++ } else {
++ /*
++ * Full speed mode.
++ * Max periodic usecs is 90% x 1000 usec = 900 usec.
++ */
++ max_claimed_usecs = 900 - _qh->usecs;
++ }
++
++ if (_hcd->periodic_usecs > max_claimed_usecs) {
++ DWC_NOTICE("%s: already claimed usecs %d, required usecs %d\n",
++ __func__, _hcd->periodic_usecs, _qh->usecs);
++ status = -ENOSPC;
++ }
++
++ return status;
++}
++
++/**
++ * Checks that the max transfer size allowed in a host channel is large enough
++ * to handle the maximum data transfer in a single (micro)frame for a periodic
++ * transfer.
++ *
++ * @param _hcd The HCD state structure for the DWC OTG controller.
++ * @param _qh QH for a periodic endpoint.
++ *
++ * @return 0 if successful, negative error code otherwise.
++ */
++static int check_max_xfer_size(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh)
++{
++ int status;
++ uint32_t max_xfer_size;
++ uint32_t max_channel_xfer_size;
++
++ status = 0;
++
++ max_xfer_size = dwc_max_packet(_qh->maxp) * dwc_hb_mult(_qh->maxp);
++ max_channel_xfer_size = _hcd->core_if->core_params->max_transfer_size;
++
++ if (max_xfer_size > max_channel_xfer_size) {
++ DWC_NOTICE("%s: Periodic xfer length %d > "
++ "max xfer length for channel %d\n",
++ __func__, max_xfer_size, max_channel_xfer_size);
++ status = -ENOSPC;
++ }
++
++ return status;
++}
++
++/**
++ * Schedules an interrupt or isochronous transfer in the periodic schedule.
++ *
++ * @param _hcd The HCD state structure for the DWC OTG controller.
++ * @param _qh QH for the periodic transfer. The QH should already contain the
++ * scheduling information.
++ *
++ * @return 0 if successful, negative error code otherwise.
++ */
++static int schedule_periodic(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh)
++{
++ int status = 0;
++
++ status = periodic_channel_available(_hcd);
++ if (status) {
++ DWC_NOTICE("%s: No host channel available for periodic "
++ "transfer.\n", __func__);
++ return status;
++ }
++
++ status = check_periodic_bandwidth(_hcd, _qh);
++ if (status) {
++ DWC_NOTICE("%s: Insufficient periodic bandwidth for "
++ "periodic transfer.\n", __func__);
++ return status;
++ }
++
++ status = check_max_xfer_size(_hcd, _qh);
++ if (status) {
++ DWC_NOTICE("%s: Channel max transfer size too small "
++ "for periodic transfer.\n", __func__);
++ return status;
++ }
++
++ /* Always start in the inactive schedule. */
++ list_add_tail(&_qh->qh_list_entry, &_hcd->periodic_sched_inactive);
++
++ /* Reserve the periodic channel. */
++ _hcd->periodic_channels++;
++
++ /* Update claimed usecs per (micro)frame. */
++ _hcd->periodic_usecs += _qh->usecs;
++
++ /* Update average periodic bandwidth claimed and # periodic reqs for usbfs. */
++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_allocated += _qh->usecs / _qh->interval;
++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) {
++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_int_reqs++;
++ DWC_DEBUGPL(DBG_HCD, "Scheduled intr: qh %p, usecs %d, period %d\n",
++ _qh, _qh->usecs, _qh->interval);
++ } else {
++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_isoc_reqs++;
++ DWC_DEBUGPL(DBG_HCD, "Scheduled isoc: qh %p, usecs %d, period %d\n",
++ _qh, _qh->usecs, _qh->interval);
++ }
++
++ return status;
++}
++
++/**
++ * This function adds a QH to either the non periodic or periodic schedule if
++ * it is not already in the schedule. If the QH is already in the schedule, no
++ * action is taken.
++ *
++ * @return 0 if successful, negative error code otherwise.
++ */
++int dwc_otg_hcd_qh_add (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh)
++{
++ unsigned long flags;
++ int status = 0;
++
++ local_irq_save(flags);
++
++ if (!list_empty(&_qh->qh_list_entry)) {
++ /* QH already in a schedule. */
++ goto done;
++ }
++
++ /* Add the new QH to the appropriate schedule */
++ if (dwc_qh_is_non_per(_qh)) {
++ /* Always start in the inactive schedule. */
++ list_add_tail(&_qh->qh_list_entry, &_hcd->non_periodic_sched_inactive);
++ } else {
++ status = schedule_periodic(_hcd, _qh);
++ }
++
++done:
++ local_irq_restore(flags);
++
++ return status;
++}
++
++/**
++ * Removes an interrupt or isochronous transfer from the periodic schedule.
++ *
++ * @param _hcd The HCD state structure for the DWC OTG controller.
++ * @param _qh QH for the periodic transfer.
++ */
++static void deschedule_periodic(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh)
++{
++ list_del_init(&_qh->qh_list_entry);
++
++ /* Release the periodic channel reservation. */
++ _hcd->periodic_channels--;
++
++ /* Update claimed usecs per (micro)frame. */
++ _hcd->periodic_usecs -= _qh->usecs;
++
++ /* Update average periodic bandwidth claimed and # periodic reqs for usbfs. */
++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_allocated -= _qh->usecs / _qh->interval;
++
++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) {
++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_int_reqs--;
++ DWC_DEBUGPL(DBG_HCD, "Descheduled intr: qh %p, usecs %d, period %d\n",
++ _qh, _qh->usecs, _qh->interval);
++ } else {
++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_isoc_reqs--;
++ DWC_DEBUGPL(DBG_HCD, "Descheduled isoc: qh %p, usecs %d, period %d\n",
++ _qh, _qh->usecs, _qh->interval);
++ }
++}
++
++/**
++ * Removes a QH from either the non-periodic or periodic schedule. Memory is
++ * not freed.
++ *
++ * @param[in] _hcd The HCD state structure.
++ * @param[in] _qh QH to remove from schedule. */
++void dwc_otg_hcd_qh_remove (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ if (list_empty(&_qh->qh_list_entry)) {
++ /* QH is not in a schedule. */
++ goto done;
++ }
++
++ if (dwc_qh_is_non_per(_qh)) {
++ if (_hcd->non_periodic_qh_ptr == &_qh->qh_list_entry) {
++ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next;
++ }
++ list_del_init(&_qh->qh_list_entry);
++ } else {
++ deschedule_periodic(_hcd, _qh);
++ }
++
++done:
++ local_irq_restore(flags);
++}
++
++/**
++ * Deactivates a QH. For non-periodic QHs, removes the QH from the active
++ * non-periodic schedule. The QH is added to the inactive non-periodic
++ * schedule if any QTDs are still attached to the QH.
++ *
++ * For periodic QHs, the QH is removed from the periodic queued schedule. If
++ * there are any QTDs still attached to the QH, the QH is added to either the
++ * periodic inactive schedule or the periodic ready schedule and its next
++ * scheduled frame is calculated. The QH is placed in the ready schedule if
++ * the scheduled frame has been reached already. Otherwise it's placed in the
++ * inactive schedule. If there are no QTDs attached to the QH, the QH is
++ * completely removed from the periodic schedule.
++ */
++void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, int sched_next_periodic_split)
++{
++ unsigned long flags;
++ local_irq_save(flags);
++
++ if (dwc_qh_is_non_per(_qh)) {
++ dwc_otg_hcd_qh_remove(_hcd, _qh);
++ if (!list_empty(&_qh->qtd_list)) {
++ /* Add back to inactive non-periodic schedule. */
++ dwc_otg_hcd_qh_add(_hcd, _qh);
++ }
++ } else {
++ uint16_t frame_number = dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(_hcd));
++
++ if (_qh->do_split) {
++ /* Schedule the next continuing periodic split transfer */
++ if (sched_next_periodic_split) {
++
++ _qh->sched_frame = frame_number;
++ if (dwc_frame_num_le(frame_number,
++ dwc_frame_num_inc(_qh->start_split_frame, 1))) {
++ /*
++ * Allow one frame to elapse after start
++ * split microframe before scheduling
++ * complete split, but DONT if we are
++ * doing the next start split in the
++ * same frame for an ISOC out.
++ */
++ if ((_qh->ep_type != USB_ENDPOINT_XFER_ISOC) || (_qh->ep_is_in != 0)) {
++ _qh->sched_frame = dwc_frame_num_inc(_qh->sched_frame, 1);
++ }
++ }
++ } else {
++ _qh->sched_frame = dwc_frame_num_inc(_qh->start_split_frame,
++ _qh->interval);
++ if (dwc_frame_num_le(_qh->sched_frame, frame_number)) {
++ _qh->sched_frame = frame_number;
++ }
++ _qh->sched_frame |= 0x7;
++ _qh->start_split_frame = _qh->sched_frame;
++ }
++ } else {
++ _qh->sched_frame = dwc_frame_num_inc(_qh->sched_frame, _qh->interval);
++ if (dwc_frame_num_le(_qh->sched_frame, frame_number)) {
++ _qh->sched_frame = frame_number;
++ }
++ }
++
++ if (list_empty(&_qh->qtd_list)) {
++ dwc_otg_hcd_qh_remove(_hcd, _qh);
++ } else {
++ /*
++ * Remove from periodic_sched_queued and move to
++ * appropriate queue.
++ */
++ if (_qh->sched_frame == frame_number) {
++ list_move(&_qh->qh_list_entry,
++ &_hcd->periodic_sched_ready);
++ } else {
++ list_move(&_qh->qh_list_entry,
++ &_hcd->periodic_sched_inactive);
++ }
++ }
++ }
++
++ local_irq_restore(flags);
++}
++
++/**
++ * This function allocates and initializes a QTD.
++ *
++ * @param[in] _urb The URB to create a QTD from. Each URB-QTD pair will end up
++ * pointing to each other so each pair should have a unique correlation.
++ *
++ * @return Returns pointer to the newly allocated QTD, or NULL on error. */
++dwc_otg_qtd_t *dwc_otg_hcd_qtd_create (struct urb *_urb)
++{
++ dwc_otg_qtd_t *qtd;
++
++ qtd = dwc_otg_hcd_qtd_alloc ();
++ if (qtd == NULL) {
++ return NULL;
++ }
++
++ dwc_otg_hcd_qtd_init (qtd, _urb);
++ return qtd;
++}
++
++/**
++ * Initializes a QTD structure.
++ *
++ * @param[in] _qtd The QTD to initialize.
++ * @param[in] _urb The URB to use for initialization. */
++void dwc_otg_hcd_qtd_init (dwc_otg_qtd_t *_qtd, struct urb *_urb)
++{
++ memset (_qtd, 0, sizeof (dwc_otg_qtd_t));
++ _qtd->urb = _urb;
++ if (usb_pipecontrol(_urb->pipe)) {
++ /*
++ * The only time the QTD data toggle is used is on the data
++ * phase of control transfers. This phase always starts with
++ * DATA1.
++ */
++ _qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
++ _qtd->control_phase = DWC_OTG_CONTROL_SETUP;
++ }
++
++ /* start split */
++ _qtd->complete_split = 0;
++ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
++ _qtd->isoc_split_offset = 0;
++
++ /* Store the qtd ptr in the urb to reference what QTD. */
++ _urb->hcpriv = _qtd;
++ return;
++}
++
++/**
++ * This function adds a QTD to the QTD-list of a QH. It will find the correct
++ * QH to place the QTD into. If it does not find a QH, then it will create a
++ * new QH. If the QH to which the QTD is added is not currently scheduled, it
++ * is placed into the proper schedule based on its EP type.
++ *
++ * @param[in] _qtd The QTD to add
++ * @param[in] _dwc_otg_hcd The DWC HCD structure
++ *
++ * @return 0 if successful, negative error code otherwise.
++ */
++int dwc_otg_hcd_qtd_add (dwc_otg_qtd_t *_qtd,
++ dwc_otg_hcd_t *_dwc_otg_hcd)
++{
++ struct usb_host_endpoint *ep;
++ dwc_otg_qh_t *qh;
++ unsigned long flags;
++ int retval = 0;
++
++ struct urb *urb = _qtd->urb;
++
++ local_irq_save(flags);
++
++ /*
++ * Get the QH which holds the QTD-list to insert to. Create QH if it
++ * doesn't exist.
++ */
++ ep = dwc_urb_to_endpoint(urb);
++ qh = (dwc_otg_qh_t *)ep->hcpriv;
++ if (qh == NULL) {
++ qh = dwc_otg_hcd_qh_create (_dwc_otg_hcd, urb);
++ if (qh == NULL) {
++ goto done;
++ }
++ ep->hcpriv = qh;
++ }
++ //AlenOh, It prevent unwanted change of OTG speed
++ //_dwc_otg_hcd->core_if->core_params->speed = urb->dev->speed;
++ _dwc_otg_hcd->speed = urb->dev->speed;
++ retval = dwc_otg_hcd_qh_add(_dwc_otg_hcd, qh);
++ if (retval == 0) {
++ list_add_tail(&_qtd->qtd_list_entry, &qh->qtd_list);
++ }
++
++done:
++ local_irq_restore(flags);
++ return retval;
++}
++
++#endif /* DWC_DEVICE_ONLY */
+diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.c b/drivers/usb/dwc_otg/dwc_otg_pcd.c
+new file mode 100644
+index 0000000..0e8fbc3
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_pcd.c
+@@ -0,0 +1,1666 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_pcd.c $
++ * $Revision: #18 $
++ * $Date: 2007/02/07 $
++ * $Change: 791271 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++#ifndef DWC_HOST_ONLY
++
++/** @file
++ * This file implements the Peripheral Controller Driver.
++ *
++ * The Peripheral Controller Driver (PCD) is responsible for
++ * translating requests from the Function Driver into the appropriate
++ * actions on the DWC_otg controller. It isolates the Function Driver
++ * from the specifics of the controller by providing an API to the
++ * Function Driver.
++ *
++ * The Peripheral Controller Driver for Linux will implement the
++ * Gadget API, so that the existing Gadget drivers can be used.
++ * (Gadget Driver is the Linux terminology for a Function Driver.)
++ *
++ * The Linux Gadget API is defined in the header file
++ * <code><linux/usb_gadget.h></code>. The USB EP operations API is
++ * defined in the structure <code>usb_ep_ops</code> and the USB
++ * Controller API is defined in the structure
++ * <code>usb_gadget_ops</code>.
++ *
++ * An important function of the PCD is managing interrupts generated
++ * by the DWC_otg controller. The implementation of the DWC_otg device
++ * mode interrupt service routines is in dwc_otg_pcd_intr.c.
++ *
++ * @todo Add Device Mode test modes (Test J mode, Test K mode, etc).
++ * @todo Does it work when the request size is greater than DEPTSIZ
++ * transfer size
++ *
++ */
++
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/errno.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/string.h>
++#include <linux/dma-mapping.h>
++
++#ifdef _USE_ATTR_
++#include <asm/arch/lm.h>
++#endif
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++
++#include "dwc_otg_driver.h"
++#include "dwc_otg_pcd.h"
++#include "tcc_usb_def.h"
++
++/* For Signature */
++#define DWC_OTG_PCD_SIGNATURE 'D','W','C','_','O','T','G','_','P','C','D','_'
++#define DWC_OTG_PCD_VERSION 'V','2','.','0','0','2'
++static const unsigned char DWC_OTG_PCD_C_Version[] =
++ {SIGBYAHONG, DWC_OTG_PCD_SIGNATURE, SIGN_OS ,SIGN_CHIPSET, DWC_OTG_PCD_VERSION, 0};
++
++
++const unsigned char* dwc_otg_pcd_get_version(void)
++{
++ return DWC_OTG_PCD_C_Version;
++}
++
++
++/**
++ * Static PCD pointer for use in usb_gadget_register_driver and
++ * usb_gadget_unregister_driver. Initialized in dwc_otg_pcd_init.
++ */
++static dwc_otg_pcd_t *s_pcd = 0;
++
++
++/* Display the contents of the buffer */
++extern void dump_msg(const u8 *buf, unsigned int length);
++
++
++/**
++ * This function completes a request. It call's the request call back.
++ */
++void request_done(dwc_otg_pcd_ep_t *_ep, dwc_otg_pcd_request_t *_req,
++ int _status)
++{
++ unsigned stopped = _ep->stopped;
++
++ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _ep);
++ list_del_init(&_req->queue);
++
++ if (_req->req.status == -EINPROGRESS)
++ {
++ _req->req.status = _status;
++ }
++ else
++ {
++ _status = _req->req.status;
++ }
++
++ /* don't modify queue heads during completion callback */
++ _ep->stopped = 1;
++ SPIN_LOCK(&_ep->pcd->lock);
++ _req->req.complete(&_ep->ep, &_req->req);
++ SPIN_UNLOCK(&_ep->pcd->lock);
++
++ if (_ep->pcd->request_pending > 0)
++ {
++ --_ep->pcd->request_pending;
++ }
++
++ _ep->stopped = stopped;
++}
++
++/**
++ * This function terminates all the requsts in the EP request queue.
++ */
++void request_nuke( dwc_otg_pcd_ep_t *_ep )
++{
++ dwc_otg_pcd_request_t *req;
++
++ _ep->stopped = 1;
++
++ /* called with irqs blocked?? */
++ while (!list_empty(&_ep->queue))
++ {
++ req = list_entry(_ep->queue.next, dwc_otg_pcd_request_t,
++ queue);
++ request_done(_ep, req, -ESHUTDOWN );
++ }
++}
++
++/* USB Endpoint Operations */
++/*
++ * The following sections briefly describe the behavior of the Gadget
++ * API endpoint operations implemented in the DWC_otg driver
++ * software. Detailed descriptions of the generic behavior of each of
++ * these functions can be found in the Linux header file
++ * include/linux/usb_gadget.h.
++ *
++ * The Gadget API provides wrapper functions for each of the function
++ * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper
++ * function, which then calls the underlying PCD function. The
++ * following sections are named according to the wrapper
++ * functions. Within each section, the corresponding DWC_otg PCD
++ * function name is specified.
++ *
++ */
++
++/**
++ * This function assigns periodic Tx FIFO to an periodic EP
++ * in shared Tx FIFO mode
++ */
++//static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t *core_if)
++//{
++// uint32_t PerTxMsk = 1;
++// int i;
++// for(i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; ++i)
++// {
++// if((PerTxMsk & core_if->p_tx_msk) == 0)
++// {
++// core_if->p_tx_msk |= PerTxMsk;
++// return i + 1;
++// }
++// PerTxMsk <<= 1;
++// }
++// return 0;
++//}
++/**
++ * This function releases periodic Tx FIFO
++ * in shared Tx FIFO mode
++ */
++static void release_perio_tx_fifo(dwc_otg_core_if_t *core_if, uint32_t fifo_num)
++{
++ core_if->p_tx_msk = (core_if->p_tx_msk & (1 << (fifo_num - 1))) ^ core_if->p_tx_msk;
++}
++/**
++ * This function assigns periodic Tx FIFO to an periodic EP
++ * in shared Tx FIFO mode
++ */
++//static uint32_t assign_tx_fifo(dwc_otg_core_if_t *core_if)
++//{
++// uint32_t TxMsk = 1;
++// int i;
++//
++// for (i = 0; i < core_if->hwcfg4.b.num_in_eps; ++i)
++// {
++// if ((TxMsk & core_if->tx_msk) == 0)
++// {
++// core_if->tx_msk |= TxMsk;
++// return i + 1;
++// }
++// TxMsk <<= 1;
++// }
++// return 0;
++//}
++/**
++ * This function releases periodic Tx FIFO
++ * in shared Tx FIFO mode
++ */
++static void release_tx_fifo(dwc_otg_core_if_t *core_if, uint32_t fifo_num)
++{
++ core_if->tx_msk = (core_if->tx_msk & (1 << (fifo_num - 1))) ^ core_if->tx_msk;
++}
++/**
++ * This function is called by the Gadget Driver for each EP to be
++ * configured for the current configuration (SET_CONFIGURATION).
++ *
++ * This function initializes the dwc_otg_ep_t data structure, and then
++ * calls dwc_otg_ep_activate.
++ */
++static int dwc_otg_pcd_ep_enable(struct usb_ep *_ep,
++ const struct usb_endpoint_descriptor *_desc)
++{
++ dwc_otg_pcd_ep_t *ep = 0;
++ dwc_otg_pcd_t *pcd = 0;
++ unsigned long flags;
++
++ DWC_DEBUGPL(DBG_PCDV,"%s(%p,%p)\n", __func__, _ep, _desc );
++ ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);
++ if (!_ep || !_desc || ep->desc ||
++ _desc->bDescriptorType != USB_DT_ENDPOINT)
++ {
++ DWC_WARN( "%s, bad ep or descriptor\n", __func__);
++ return -EINVAL;
++ }
++ if (ep == &ep->pcd->ep0)
++ {
++ DWC_WARN("%s, bad ep(0)\n", __func__);
++ return -EINVAL;
++ }
++
++ /* Check FIFO size? */
++ if (!_desc->wMaxPacketSize)
++ {
++ DWC_WARN("%s, bad %s maxpacket\n", __func__, _ep->name);
++ return -ERANGE;
++ }
++
++ pcd = ep->pcd;
++ if (!pcd->driver || pcd->gadget.speed == USB_SPEED_UNKNOWN)
++ {
++ DWC_WARN("%s, bogus device state\n", __func__);
++ return -ESHUTDOWN;
++ }
++
++ SPIN_LOCK_IRQSAVE(&pcd->lock, flags);
++
++ ep->desc = _desc;
++ ep->ep.maxpacket = le16_to_cpu (_desc->wMaxPacketSize);
++
++ /*
++ * Activate the EP
++ */
++ ep->stopped = 0;
++
++ ep->dwc_ep.is_in = (USB_DIR_IN & _desc->bEndpointAddress) != 0;
++ ep->dwc_ep.maxpacket = ep->ep.maxpacket;
++
++ ep->dwc_ep.type = _desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
++
++ if (ep->dwc_ep.is_in)
++ {
++ //if(!pcd->otg_dev->core_if->en_multiple_tx_fifo)
++ //{
++ // ep->dwc_ep.tx_fifo_num = 0;
++ //
++ // if ((_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
++ // USB_ENDPOINT_XFER_ISOC )
++ // {
++ // /*
++ // * if ISOC EP then assign a Periodic Tx FIFO.
++ // */
++ // ep->dwc_ep.tx_fifo_num = assign_perio_tx_fifo(pcd->otg_dev->core_if);
++ // }
++ //}
++ //else
++ {
++ /*
++ * if Dedicated FIFOs mode is on then assign a Tx FIFO.
++ */
++ ep->dwc_ep.tx_fifo_num = ep->dwc_ep.num;//assign_tx_fifo(pcd->otg_dev->core_if);
++ }
++ }
++ /* Set initial data PID. */
++ if ((_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
++ USB_ENDPOINT_XFER_BULK )
++ {
++ ep->dwc_ep.data_pid_start = 0;
++ }
++
++ DWC_DEBUGPL(DBG_PCD, " Activate %s-%s: type=%d, mps=%d desc=%p\n",
++ ep->ep.name, (ep->dwc_ep.is_in ?"IN":"OUT"),
++ ep->dwc_ep.type, ep->dwc_ep.maxpacket, ep->desc );
++
++
++ dwc_otg_ep_activate( GET_CORE_IF(pcd), &ep->dwc_ep );
++ SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);
++ return 0;
++}
++
++/**
++ * This function is called when an EP is disabled due to disconnect or
++ * change in configuration. Any pending requests will terminate with a
++ * status of -ESHUTDOWN.
++ *
++ * This function modifies the dwc_otg_ep_t data structure for this EP,
++ * and then calls dwc_otg_ep_deactivate.
++ */
++int dwc_otg_pcd_ep_disable(struct usb_ep *_ep)
++{
++ dwc_otg_pcd_ep_t *ep;
++ unsigned long flags;
++
++ DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _ep);
++ ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);
++ if (!_ep || !ep->desc)
++ {
++ DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
++ _ep ? ep->ep.name : NULL);
++ return -EINVAL;
++ }
++
++ SPIN_LOCK_IRQSAVE(&ep->pcd->lock, flags);
++
++ request_nuke( ep );
++
++ dwc_otg_ep_deactivate( GET_CORE_IF(ep->pcd), &ep->dwc_ep );
++ ep->desc = 0;
++ ep->stopped = 1;
++
++ if (ep->dwc_ep.is_in)
++ {
++ release_perio_tx_fifo(GET_CORE_IF(ep->pcd), ep->dwc_ep.tx_fifo_num);
++ release_tx_fifo(GET_CORE_IF(ep->pcd), ep->dwc_ep.tx_fifo_num);
++ }
++
++ SPIN_UNLOCK_IRQRESTORE(&ep->pcd->lock, flags);
++
++ DWC_DEBUGPL(DBG_PCD, "%s disabled\n", _ep->name);
++ return 0;
++}
++
++
++/**
++ * This function allocates a request object to use with the specified
++ * endpoint.
++ *
++ * @param _ep The endpoint to be used with with the request
++ * @param _gfp_flags the GFP_* flags to use.
++ */
++static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *_ep,
++ gfp_t _gfp_flags)
++{
++ dwc_otg_pcd_request_t *req;
++
++ DWC_DEBUGPL(DBG_PCDV,"%s(%p,%d)\n", __func__, _ep, _gfp_flags);
++ if (0 == _ep )
++ {
++ DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
++ return 0;
++ }
++ req = kmalloc( sizeof(dwc_otg_pcd_request_t), _gfp_flags);
++ if (0 == req)
++ {
++ DWC_WARN("%s() %s\n", __func__,
++ "request allocation failed!\n");
++ return 0;
++ }
++ memset(req, 0, sizeof(dwc_otg_pcd_request_t));
++ req->req.dma = DMA_ADDR_INVALID;
++ INIT_LIST_HEAD(&req->queue);
++ return &req->req;
++}
++
++/**
++ * This function frees a request object.
++ *
++ * @param _ep The endpoint associated with the request
++ * @param _req The request being freed
++ */
++static void dwc_otg_pcd_free_request(struct usb_ep *_ep,
++ struct usb_request *_req)
++{
++ dwc_otg_pcd_request_t *req;
++ DWC_DEBUGPL(DBG_PCDV,"%s(%p,%p)\n", __func__, _ep, _req);
++
++ if (0 == _ep || 0 == _req)
++ {
++ DWC_WARN("%s() %s\n", __func__,
++ "Invalid ep or req argument!\n");
++ return;
++ }
++
++ req = container_of(_req, dwc_otg_pcd_request_t, req);
++ kfree(req);
++}
++
++/**
++ * This function is used to submit an I/O Request to an EP.
++ *
++ * - When the request completes the request's completion callback
++ * is called to return the request to the driver.
++ * - An EP, except control EPs, may have multiple requests
++ * pending.
++ * - Once submitted the request cannot be examined or modified.
++ * - Each request is turned into one or more packets.
++ * - A BULK EP can queue any amount of data; the transfer is
++ * packetized.
++ * - Zero length Packets are specified with the request 'zero'
++ * flag.
++ */
++static int dwc_otg_pcd_ep_queue(struct usb_ep *_ep,
++ struct usb_request *_req, gfp_t _gfp_flags)
++{
++ int prevented = 0;
++ dwc_otg_pcd_request_t *req;
++ dwc_otg_pcd_ep_t *ep;
++ dwc_otg_pcd_t *pcd;
++ unsigned long flags = 0;
++
++ DWC_DEBUGPL(DBG_PCDV,"%s(%p,%p,%d)\n",
++ __func__, _ep, _req, _gfp_flags);
++
++ req = container_of(_req, dwc_otg_pcd_request_t, req);
++ if (!_req || !_req->complete || !_req->buf ||
++ !list_empty(&req->queue))
++ {
++ DWC_WARN("%s, bad params\n", __func__);
++ return -EINVAL;
++ }
++
++ ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);
++ if (!_ep || (!ep->desc && ep->dwc_ep.num != 0))
++ {
++ DWC_WARN("%s, bad ep\n", __func__);
++ return -EINVAL;
++ }
++ pcd = ep->pcd;
++ if (!pcd->driver || pcd->gadget.speed == USB_SPEED_UNKNOWN)
++ {
++ DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n", pcd->gadget.speed);
++ DWC_WARN("%s, bogus device state\n", __func__);
++ return -ESHUTDOWN;
++ }
++
++
++ DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
++ _ep->name, _req, _req->length, _req->buf);
++
++ if (!GET_CORE_IF(pcd)->core_params->opt)
++ {
++ if (ep->dwc_ep.num != 0)
++ {
++ DWC_ERROR("%s queue req %p, len %d buf %p\n",
++ _ep->name, _req, _req->length, _req->buf);
++ }
++ }
++
++ SPIN_LOCK_IRQSAVE(&ep->pcd->lock, flags);
++
++#if defined(DEBUG) & defined(VERBOSE)
++ dump_msg(_req->buf, _req->length);
++#endif
++ //MDELAY(5);
++ _req->status = -EINPROGRESS;
++ _req->actual = 0;
++
++ /*
++ * For EP0 IN without premature status, zlp is required?
++ */
++ if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in)
++ {
++ DWC_DEBUGPL(DBG_PCDV, "%s-OUT ZLP\n", _ep->name);
++ //_req->zero = 1;
++ }
++
++ /* Start the transfer */
++ if (list_empty(&ep->queue) && !ep->stopped)
++ {
++ /* EP0 Transfer? */
++ if (ep->dwc_ep.num == 0)
++ {
++ switch (pcd->ep0state)
++ {
++ case EP0_IN_DATA_PHASE:
++ DWC_DEBUGPL(DBG_PCD,
++ "%s ep0: EP0_IN_DATA_PHASE\n",
++ __func__);
++ break;
++
++ case EP0_OUT_DATA_PHASE:
++ DWC_DEBUGPL(DBG_PCD,
++ "%s ep0: EP0_OUT_DATA_PHASE\n",
++ __func__);
++ //if (pcd->request_config)
++ //{
++ // /* Complete STATUS PHASE */
++ // ep->dwc_ep.is_in = 1;
++ // pcd->ep0state = EP0_STATUS;
++ //}
++ break;
++
++ case EP0_STATUS:
++ DWC_DEBUGPL(DBG_PCD,
++ "%s ep0: EP0_STATUS\n",
++ __func__);
++ break;
++
++ default:
++ DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n",
++ pcd->ep0state);
++ SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);
++ return -EL2HLT;
++ }
++
++ ep->dwc_ep.dma_addr = _req->dma;
++ ep->dwc_ep.start_xfer_buff = _req->buf;
++ ep->dwc_ep.xfer_buff = _req->buf;
++ ep->dwc_ep.xfer_len = _req->length;
++ ep->dwc_ep.xfer_count = 0;
++ ep->dwc_ep.sent_zlp = 0;
++ ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
++ dwc_otg_ep0_start_transfer( GET_CORE_IF(pcd),
++ &ep->dwc_ep );
++ }
++ else
++ {
++ /* Setup and start the Transfer */
++ ep->dwc_ep.dma_addr = _req->dma;
++ ep->dwc_ep.start_xfer_buff = _req->buf;
++ ep->dwc_ep.xfer_buff = _req->buf;
++ ep->dwc_ep.xfer_len = _req->length;
++ ep->dwc_ep.xfer_count = 0;
++ ep->dwc_ep.sent_zlp = 0;
++ ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
++ dwc_otg_ep_start_transfer( GET_CORE_IF(pcd),
++ &ep->dwc_ep );
++ }
++ }
++
++ if ((req != 0) || prevented)
++ {
++ ++pcd->request_pending;
++ list_add_tail(&req->queue, &ep->queue);
++ if (ep->dwc_ep.is_in && ep->stopped && !(GET_CORE_IF(pcd)->dma_enable))
++ {
++ /** @todo NGS Create a function for this. */
++ diepmsk_data_t diepmsk = { .d32 = 0};
++ diepmsk.b.intktxfemp = 1;
++ dwc_modify_reg32( &GET_CORE_IF(pcd)->dev_if->dev_global_regs->diepmsk, 0, diepmsk.d32 );
++ }
++ }
++
++ SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);
++ return 0;
++}
++
++/**
++ * This function cancels an I/O request from an EP.
++ */
++static int dwc_otg_pcd_ep_dequeue(struct usb_ep *_ep,
++ struct usb_request *_req)
++{
++ dwc_otg_pcd_request_t *req;
++ dwc_otg_pcd_ep_t *ep;
++ dwc_otg_pcd_t *pcd;
++ unsigned long flags;
++
++ DWC_DEBUGPL(DBG_PCDV,"%s(%p,%p)\n", __func__, _ep, _req);
++
++ ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);
++ if (!_ep || !_req || (!ep->desc && ep->dwc_ep.num != 0))
++ {
++ DWC_WARN("%s, bad argument\n", __func__);
++ return -EINVAL;
++ }
++ pcd = ep->pcd;
++ if (!pcd->driver || pcd->gadget.speed == USB_SPEED_UNKNOWN)
++ {
++ DWC_WARN("%s, bogus device state\n", __func__);
++ return -ESHUTDOWN;
++ }
++
++ SPIN_LOCK_IRQSAVE(&pcd->lock, flags);
++ DWC_DEBUGPL(DBG_PCDV, "%s %s %s %p\n", __func__, _ep->name,
++ ep->dwc_ep.is_in ? "IN" : "OUT",
++ _req);
++
++ /* make sure it's actually queued on this endpoint */
++ list_for_each_entry( req, &ep->queue, queue)
++ {
++ if (&req->req == _req)
++ {
++ break;
++ }
++ }
++
++ if (&req->req != _req)
++ {
++ SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);
++ return -EINVAL;
++ }
++
++ if (!list_empty(&req->queue))
++ {
++ request_done(ep, req, -ECONNRESET);
++ }
++ else
++ {
++ req = 0;
++ }
++
++ SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);
++
++ return req ? 0 : -EOPNOTSUPP;
++}
++
++/**
++ * usb_ep_set_halt stalls an endpoint.
++ *
++ * usb_ep_clear_halt clears an endpoint halt and resets its data
++ * toggle.
++ *
++ * Both of these functions are implemented with the same underlying
++ * function. The behavior depends on the value argument.
++ *
++ * @param[in] _ep the Endpoint to halt or clear halt.
++ * @param[in] _value
++ * - 0 means clear_halt.
++ * - 1 means set_halt,
++ * - 2 means clear stall lock flag.
++ * - 3 means set stall lock flag.
++ */
++static int dwc_otg_pcd_ep_set_halt(struct usb_ep *_ep, int _value)
++{
++ int retval = 0;
++ unsigned long flags;
++ dwc_otg_pcd_ep_t *ep = 0;
++
++
++ DWC_DEBUGPL(DBG_PCD,"HALT %s %d\n", _ep->name, _value);
++
++ ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);
++
++ if (!_ep || (!ep->desc && ep != &ep->pcd->ep0) ||
++ ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC)
++ {
++ DWC_WARN("%s, bad ep\n", __func__);
++ return -EINVAL;
++ }
++
++ SPIN_LOCK_IRQSAVE(&ep->pcd->lock, flags);
++ if (!list_empty(&ep->queue))
++ {
++ DWC_WARN("%s() %s XFer In process\n", __func__, _ep->name);
++ retval = -EAGAIN;
++ }
++ else if (_value == 0)
++ {
++ dwc_otg_ep_clear_stall( ep->pcd->otg_dev->core_if,
++ &ep->dwc_ep );
++ }
++ else if (_value == 1)
++ {
++ if (ep->dwc_ep.num == 0)
++ {
++ ep->pcd->ep0state = EP0_STALL;
++ }
++
++ ep->stopped = 1;
++ dwc_otg_ep_set_stall( ep->pcd->otg_dev->core_if,
++ &ep->dwc_ep );
++ }
++ else if (_value == 2)
++ {
++ ep->dwc_ep.stall_clear_flag = 0;
++ }
++ else if (_value == 3)
++ {
++ ep->dwc_ep.stall_clear_flag = 1;
++ }
++
++ SPIN_UNLOCK_IRQRESTORE(&ep->pcd->lock, flags);
++ return retval;
++}
++
++
++static struct usb_ep_ops dwc_otg_pcd_ep_ops =
++{
++ .enable = dwc_otg_pcd_ep_enable,
++ .disable = dwc_otg_pcd_ep_disable,
++
++ .alloc_request = dwc_otg_pcd_alloc_request,
++ .free_request = dwc_otg_pcd_free_request,
++
++ .queue = dwc_otg_pcd_ep_queue,
++ .dequeue = dwc_otg_pcd_ep_dequeue,
++
++ .set_halt = dwc_otg_pcd_ep_set_halt,
++ .fifo_status = 0,
++ .fifo_flush = 0,
++};
++
++/* Gadget Operations */
++/**
++ * The following gadget operations will be implemented in the DWC_otg
++ * PCD. Functions in the API that are not described below are not
++ * implemented.
++ *
++ * The Gadget API provides wrapper functions for each of the function
++ * pointers defined in usb_gadget_ops. The Gadget Driver calls the
++ * wrapper function, which then calls the underlying PCD function. The
++ * following sections are named according to the wrapper functions
++ * (except for ioctl, which doesn't have a wrapper function). Within
++ * each section, the corresponding DWC_otg PCD function name is
++ * specified.
++ *
++ */
++
++/**
++ *Gets the USB Frame number of the last SOF.
++ */
++static int dwc_otg_pcd_get_frame(struct usb_gadget *_gadget)
++{
++ dwc_otg_pcd_t *pcd;
++
++ DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _gadget);
++
++ if (_gadget == 0)
++ {
++ return -ENODEV;
++ }
++ else
++ {
++ pcd = container_of(_gadget, dwc_otg_pcd_t, gadget);
++ dwc_otg_get_frame_number( GET_CORE_IF(pcd) );
++ }
++
++ return 0;
++}
++
++void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t *_pcd)
++{
++ uint32_t *addr = (uint32_t *)&(GET_CORE_IF(_pcd)->core_global_regs->gotgctl);
++ gotgctl_data_t mem;
++ gotgctl_data_t val;
++
++ val.d32 = dwc_read_reg32( addr );
++ if (val.b.sesreq)
++ {
++ DWC_ERROR("Session Request Already active!\n");
++ return;
++ }
++
++ DWC_NOTICE("Session Request Initated\n");
++ mem.d32 = dwc_read_reg32(addr);
++ mem.b.sesreq = 1;
++ dwc_write_reg32(addr, mem.d32);
++
++ /* Start the SRP timer */
++ dwc_otg_pcd_start_srp_timer( _pcd );
++ return;
++}
++
++void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t *_pcd, int set)
++{
++ dctl_data_t dctl = {.d32=0};
++ volatile uint32_t *addr =
++ &(GET_CORE_IF(_pcd)->dev_if->dev_global_regs->dctl);
++
++ if (dwc_otg_is_device_mode(GET_CORE_IF(_pcd)))
++ {
++ if (_pcd->remote_wakeup_enable)
++ {
++ if (set)
++ {
++ dctl.b.rmtwkupsig = 1;
++ dwc_modify_reg32( addr, 0, dctl.d32 );
++ DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
++ mdelay(1);
++ dwc_modify_reg32( addr, dctl.d32, 0 );
++ DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n");
++ }
++ else
++ {
++ }
++ }
++ else
++ {
++ DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n");
++ }
++ }
++
++ return;
++}
++
++/**
++ * Initiates Session Request Protocol (SRP) to wakeup the host if no
++ * session is in progress. If a session is already in progress, but
++ * the device is suspended, remote wakeup signaling is started.
++ *
++ */
++static int dwc_otg_pcd_wakeup(struct usb_gadget *_gadget)
++{
++ unsigned long flags;
++ dwc_otg_pcd_t *pcd;
++ dsts_data_t dsts;
++ gotgctl_data_t gotgctl;
++
++ DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _gadget);
++
++ if (_gadget == 0)
++ {
++ return -ENODEV;
++ }
++ else
++ {
++ pcd = container_of(_gadget, dwc_otg_pcd_t, gadget);
++ }
++ SPIN_LOCK_IRQSAVE(&pcd->lock, flags);
++
++ /*
++ * This function starts the Protocol if no session is in progress. If
++ * a session is already in progress, but the device is suspended,
++ * remote wakeup signaling is started.
++ */
++
++ /* Check if valid session */
++ gotgctl.d32 = dwc_read_reg32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl));
++ if (gotgctl.b.bsesvld)
++ {
++ /* Check if suspend state */
++ dsts.d32 = dwc_read_reg32(&(GET_CORE_IF(pcd)->dev_if->dev_global_regs->dsts));
++ if (dsts.b.suspsts)
++ {
++ dwc_otg_pcd_remote_wakeup(pcd, 1);
++ }
++ }
++ else
++ {
++ dwc_otg_pcd_initiate_srp(pcd);
++ }
++
++ SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);
++ return 0;
++}
++
++static const struct usb_gadget_ops dwc_otg_pcd_ops =
++{
++ .get_frame = dwc_otg_pcd_get_frame,
++ .wakeup = dwc_otg_pcd_wakeup,
++ // current versions must always be self-powered
++};
++
++/**
++ * This function updates the otg values in the gadget structure.
++ */
++void dwc_otg_pcd_update_otg( dwc_otg_pcd_t *_pcd, const unsigned _reset )
++{
++
++ if (!_pcd->gadget.is_otg)
++ return;
++
++ if (_reset)
++ {
++ _pcd->b_hnp_enable = 0;
++ _pcd->a_hnp_support = 0;
++ _pcd->a_alt_hnp_support = 0;
++ }
++
++ _pcd->gadget.b_hnp_enable = _pcd->b_hnp_enable;
++ _pcd->gadget.a_hnp_support = _pcd->a_hnp_support;
++ _pcd->gadget.a_alt_hnp_support = _pcd->a_alt_hnp_support;
++}
++
++/**
++ * This function is the top level PCD interrupt handler.
++ */
++static irqreturn_t
++dwc_otg_pcd_irq(int _irq, void *_dev)
++{
++ dwc_otg_pcd_t *pcd = _dev;
++ int32_t retval = IRQ_NONE;
++ retval = dwc_otg_pcd_handle_intr( pcd );
++ return IRQ_RETVAL(retval);
++}
++
++/**
++ * PCD Callback function for initializing the PCD when switching to
++ * device mode.
++ *
++ * @param _p void pointer to the <code>dwc_otg_pcd_t</code>
++ */
++static int32_t dwc_otg_pcd_start_cb( void *_p )
++{
++ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *)_p;
++
++ /*
++ * Initialized the Core for Device mode.
++ */
++ if (dwc_otg_is_device_mode( GET_CORE_IF(pcd) ))
++ {
++ dwc_otg_core_dev_init(GET_CORE_IF(pcd));
++ }
++
++ return 1;
++}
++
++/**
++ * PCD Callback function for stopping the PCD when switching to Host
++ * mode.
++ *
++ * @param _p void pointer to the <code>dwc_otg_pcd_t</code>
++ */
++static int32_t dwc_otg_pcd_stop_cb( void *_p )
++{
++ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *)_p;
++ extern void dwc_otg_pcd_stop(dwc_otg_pcd_t *_pcd);
++
++ dwc_otg_pcd_stop( pcd );
++ return 1;
++}
++
++
++/**
++ * PCD Callback function for notifying the PCD when resuming from
++ * suspend.
++ *
++ * @param _p void pointer to the <code>dwc_otg_pcd_t</code>
++ */
++static int32_t dwc_otg_pcd_suspend_cb( void *_p )
++{
++ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *)_p;
++
++ if (pcd->driver && pcd->driver->suspend)
++ {
++ SPIN_LOCK(&pcd->lock);
++ pcd->driver->suspend(&pcd->gadget);
++ SPIN_UNLOCK(&pcd->lock);
++ }
++
++ return 1;
++}
++
++
++/**
++ * PCD Callback function for notifying the PCD when resuming from
++ * suspend.
++ *
++ * @param _p void pointer to the <code>dwc_otg_pcd_t</code>
++ */
++static int32_t dwc_otg_pcd_resume_cb( void *_p )
++{
++ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *)_p;
++
++ if (pcd->driver && pcd->driver->resume)
++ {
++ SPIN_LOCK(&pcd->lock);
++ pcd->driver->resume(&pcd->gadget);
++ SPIN_UNLOCK(&pcd->lock);
++ }
++
++ /* Stop the SRP timeout timer. */
++ if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS) ||
++ (!GET_CORE_IF(pcd)->core_params->i2c_enable))
++ {
++ if (GET_CORE_IF(pcd)->srp_timer_started)
++ {
++ GET_CORE_IF(pcd)->srp_timer_started = 0;
++ del_timer( &pcd->srp_timer );
++ }
++ }
++ return 1;
++}
++
++
++/**
++ * PCD Callback structure for handling mode switching.
++ */
++static dwc_otg_cil_callbacks_t pcd_callbacks =
++{
++ .start = dwc_otg_pcd_start_cb,
++ .stop = dwc_otg_pcd_stop_cb,
++ .suspend = dwc_otg_pcd_suspend_cb,
++ .resume_wakeup = dwc_otg_pcd_resume_cb,
++ .p = 0, /* Set at registration */
++};
++
++/**
++ * This function is called when the SRP timer expires. The SRP should
++ * complete within 6 seconds.
++ */
++static void srp_timeout( unsigned long _ptr )
++{
++ gotgctl_data_t gotgctl;
++ dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *)_ptr;
++ volatile uint32_t *addr = &core_if->core_global_regs->gotgctl;
++
++ gotgctl.d32 = dwc_read_reg32(addr);
++
++ core_if->srp_timer_started = 0;
++
++ if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) &&
++ (core_if->core_params->i2c_enable))
++ {
++ DWC_PRINT( "SRP Timeout\n");
++
++ if ((core_if->srp_success) &&
++ (gotgctl.b.bsesvld))
++ {
++ if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup )
++ {
++ core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
++ }
++
++ /* Clear Session Request */
++ gotgctl.d32 = 0;
++ gotgctl.b.sesreq = 1;
++ dwc_modify_reg32( &core_if->core_global_regs->gotgctl,
++ gotgctl.d32, 0);
++
++ core_if->srp_success = 0;
++ }
++ else
++ {
++ DWC_ERROR( "Device not connected/responding\n");
++ gotgctl.b.sesreq = 0;
++ dwc_write_reg32(addr, gotgctl.d32);
++ }
++ }
++ else if (gotgctl.b.sesreq)
++ {
++ DWC_PRINT( "SRP Timeout\n");
++
++ DWC_ERROR( "Device not connected/responding\n");
++ gotgctl.b.sesreq = 0;
++ dwc_write_reg32(addr, gotgctl.d32);
++ }
++ else
++ {
++ DWC_PRINT( " SRP GOTGCTL=%0x\n", gotgctl.d32);
++ }
++}
++
++/**
++ * Start the SRP timer to detect when the SRP does not complete within
++ * 6 seconds.
++ *
++ * @param _pcd the pcd structure.
++ */
++void dwc_otg_pcd_start_srp_timer(dwc_otg_pcd_t *_pcd )
++{
++ struct timer_list *srp_timer = &_pcd->srp_timer;
++ GET_CORE_IF(_pcd)->srp_timer_started = 1;
++ init_timer( srp_timer );
++ srp_timer->function = srp_timeout;
++ srp_timer->data = (unsigned long)GET_CORE_IF(_pcd);
++ srp_timer->expires = jiffies + (HZ*6);
++ add_timer( srp_timer );
++}
++
++/**
++ * Tasklet
++ *
++ */
++extern void start_next_request( dwc_otg_pcd_ep_t *_ep );
++
++static void start_xfer_tasklet_func (unsigned long data)
++{
++ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t*)data;
++ dwc_otg_core_if_t *core_if = pcd->otg_dev->core_if;
++
++ int i;
++ depctl_data_t diepctl;
++
++ DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n");
++
++ diepctl.d32 = dwc_read_reg32( &core_if->dev_if->in_ep_regs[0]->diepctl);
++
++ if (pcd->ep0.queue_sof)
++ {
++ pcd->ep0.queue_sof = 0;
++ start_next_request (&pcd->ep0);
++ // break;
++ }
++
++ for (i=0; i<core_if->dev_if->num_in_eps; i++)
++ {
++ depctl_data_t diepctl;
++ diepctl.d32 = dwc_read_reg32( &core_if->dev_if->in_ep_regs[i]->diepctl);
++
++ if (pcd->in_ep[i].queue_sof)
++ {
++ pcd->in_ep[i].queue_sof = 0;
++ start_next_request (&pcd->in_ep[i]);
++ // break;
++ }
++ }
++
++ return;
++}
++
++
++
++
++
++
++
++static struct tasklet_struct start_xfer_tasklet = {
++ .next = NULL,
++ .state = 0,
++ .count = ATOMIC_INIT(0),
++ .func = start_xfer_tasklet_func,
++ .data = 0,
++};
++/**
++ * This function initialized the pcd Dp structures to there default
++ * state.
++ *
++ * @param _pcd the pcd structure.
++ */
++void dwc_otg_pcd_reinit(dwc_otg_pcd_t *_pcd)
++{
++ static const char * names[] =
++ {
++
++ "ep0",
++ "ep1in",
++ "ep2in",
++ "ep3in",
++ "ep4in",
++ "ep5in",
++ "ep6in",
++ "ep7in",
++ "ep8in",
++ "ep9in",
++ "ep10in",
++ "ep11in",
++ "ep12in",
++ "ep13in",
++ "ep14in",
++ "ep15in",
++ "ep1out",
++ "ep2out",
++ "ep3out",
++ "ep4out",
++ "ep5out",
++ "ep6out",
++ "ep7out",
++ "ep8out",
++ "ep9out",
++ "ep10out",
++ "ep11out",
++ "ep12out",
++ "ep13out",
++ "ep14out",
++ "ep15out"
++
++ };
++
++ int i;
++ int in_ep_cntr, out_ep_cntr;
++ uint32_t hwcfg1;
++ uint32_t num_in_eps = (GET_CORE_IF(_pcd))->dev_if->num_in_eps;
++ uint32_t num_out_eps = (GET_CORE_IF(_pcd))->dev_if->num_out_eps;
++ dwc_otg_pcd_ep_t *ep;
++
++ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
++
++ INIT_LIST_HEAD (&_pcd->gadget.ep_list);
++ _pcd->gadget.ep0 = &_pcd->ep0.ep;
++ _pcd->gadget.speed = USB_SPEED_UNKNOWN;
++
++ INIT_LIST_HEAD (&_pcd->gadget.ep0->ep_list);
++
++ /**
++ * Initialize the EP0 structure.
++ */
++ ep = &_pcd->ep0;
++
++ /* Init EP structure */
++ ep->desc = 0;
++ ep->pcd = _pcd;
++ ep->stopped = 1;
++
++ /* Init DWC ep structure */
++ ep->dwc_ep.num = 0;
++ ep->dwc_ep.active = 0;
++ ep->dwc_ep.tx_fifo_num = 0;
++ /* Control until ep is actvated */
++ ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
++ ep->dwc_ep.maxpacket = MAX_PACKET_SIZE;
++ ep->dwc_ep.dma_addr = 0;
++ ep->dwc_ep.start_xfer_buff = 0;
++ ep->dwc_ep.xfer_buff = 0;
++ ep->dwc_ep.xfer_len = 0;
++ ep->dwc_ep.xfer_count = 0;
++ ep->dwc_ep.sent_zlp = 0;
++ ep->dwc_ep.total_len = 0;
++ ep->queue_sof = 0;
++
++ /* Init the usb_ep structure. */
++ ep->ep.name = names[0];
++ ep->ep.ops = &dwc_otg_pcd_ep_ops;
++
++ /**
++ * @todo NGS: What should the max packet size be set to
++ * here? Before EP type is set?
++ */
++ ep->ep.maxpacket = MAX_PACKET_SIZE;
++
++ list_add_tail (&ep->ep.ep_list, &_pcd->gadget.ep_list);
++
++ INIT_LIST_HEAD (&ep->queue);
++ /**
++ * Initialize the EP structures.
++ */
++ in_ep_cntr = 0;
++ hwcfg1 = (GET_CORE_IF(_pcd))->hwcfg1.d32 >> 3;
++
++ for (i = 1; in_ep_cntr < num_in_eps; i++)
++ {
++ if ((hwcfg1 & 0x1) == 0)
++ {
++ dwc_otg_pcd_ep_t *ep = &_pcd->in_ep[in_ep_cntr];
++ in_ep_cntr ++;
++
++ /* Init EP structure */
++ ep->desc = 0;
++ ep->pcd = _pcd;
++ ep->stopped = 1;
++
++ /* Init DWC ep structure */
++ ep->dwc_ep.is_in = 1;
++ ep->dwc_ep.num = i;
++ ep->dwc_ep.active = 0;
++ ep->dwc_ep.tx_fifo_num = 0;
++
++ /* Control until ep is actvated */
++ ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
++ ep->dwc_ep.maxpacket = MAX_PACKET_SIZE;
++ ep->dwc_ep.dma_addr = 0;
++ ep->dwc_ep.start_xfer_buff = 0;
++ ep->dwc_ep.xfer_buff = 0;
++ ep->dwc_ep.xfer_len = 0;
++ ep->dwc_ep.xfer_count = 0;
++ ep->dwc_ep.sent_zlp = 0;
++ ep->dwc_ep.total_len = 0;
++ ep->queue_sof = 0;
++
++ /* Init the usb_ep structure. */
++ /**
++ * @todo NGS: Add direction to EP, based on contents
++ * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
++ * sprintf( ";r
++ */
++ ep->ep.name = names[i];
++ ep->ep.ops = &dwc_otg_pcd_ep_ops;
++
++ /**
++ * @todo NGS: What should the max packet size be set to
++ * here? Before EP type is set?
++ */
++ ep->ep.maxpacket = MAX_PACKET_SIZE;
++
++ list_add_tail (&ep->ep.ep_list, &_pcd->gadget.ep_list);
++
++ INIT_LIST_HEAD (&ep->queue);
++ }
++ hwcfg1 >>= 2;
++ }
++
++ out_ep_cntr = 0;
++ hwcfg1 = (GET_CORE_IF(_pcd))->hwcfg1.d32 >> 2;
++
++ for (i = 1; out_ep_cntr < num_out_eps; i++)
++ {
++ if ((hwcfg1 & 0x1) == 0)
++ {
++ dwc_otg_pcd_ep_t *ep = &_pcd->out_ep[out_ep_cntr];
++ out_ep_cntr++;
++
++ /* Init EP structure */
++ ep->desc = 0;
++ ep->pcd = _pcd;
++ ep->stopped = 1;
++
++ /* Init DWC ep structure */
++ ep->dwc_ep.is_in = 0;
++ ep->dwc_ep.num = i;
++ ep->dwc_ep.active = 0;
++ ep->dwc_ep.tx_fifo_num = 0;
++ /* Control until ep is actvated */
++ ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
++ ep->dwc_ep.maxpacket = MAX_PACKET_SIZE;
++ ep->dwc_ep.dma_addr = 0;
++ ep->dwc_ep.start_xfer_buff = 0;
++ ep->dwc_ep.xfer_buff = 0;
++ ep->dwc_ep.xfer_len = 0;
++ ep->dwc_ep.xfer_count = 0;
++ ep->dwc_ep.sent_zlp = 0;
++ ep->dwc_ep.total_len = 0;
++ ep->queue_sof = 0;
++
++ /* Init the usb_ep structure. */
++ /**
++ * @todo NGS: Add direction to EP, based on contents
++ * of HWCFG1. Need a copy of HWCFG1 in pcd structure?
++ * sprintf( ";r
++ */
++ ep->ep.name = names[15 + i];
++ ep->ep.ops = &dwc_otg_pcd_ep_ops;
++ /**
++ * @todo NGS: What should the max packet size be set to
++ * here? Before EP type is set?
++ */
++ ep->ep.maxpacket = MAX_PACKET_SIZE;
++
++ list_add_tail (&ep->ep.ep_list, &_pcd->gadget.ep_list);
++
++ INIT_LIST_HEAD (&ep->queue);
++ }
++ hwcfg1 >>= 2;
++ }
++
++ /* remove ep0 from the list. There is a ep0 pointer.*/
++ list_del_init (&_pcd->ep0.ep.ep_list);
++
++ _pcd->ep0state = EP0_DISCONNECT;
++ _pcd->ep0.ep.maxpacket = MAX_EP0_SIZE;
++ _pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE;
++ _pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
++}
++
++/**
++ * This function releases the Gadget device.
++ * required by device_unregister().
++ *
++ * @todo Should this do something? Should it free the PCD?
++ */
++static void dwc_otg_pcd_gadget_release(struct device *_dev)
++{
++ DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _dev);
++}
++
++
++static const char on_string[] = "on";
++static ssize_t set_srp(struct device *dev, struct device_attribute *attr,
++ const char *_buf, size_t _count)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ dwc_otg_device_t *otg_dev = platform_get_otgdata(pdev);
++ int rc = 0;
++ int len = _count;
++ char *cp = memchr(_buf, '\n', _count);
++ if (cp)
++ len = cp - _buf;
++
++ if (len == sizeof on_string - 1 && strncmp(_buf, on_string, len) == 0)
++ dwc_otg_pcd_initiate_srp(otg_dev->pcd);
++ else
++ rc = -EINVAL;
++
++ return (rc < 0 ? rc : _count);
++}
++static DEVICE_ATTR(srpinit, S_IWUSR, NULL, set_srp);
++
++/**
++ * This function initialized the PCD portion of the driver.
++ *
++ */
++
++int __init dwc_otg_pcd_init(struct platform_device *pdev)
++{
++ static char pcd_name[] = "dwc_otg_pcd";
++ dwc_otg_pcd_t *pcd;
++ dwc_otg_device_t *otg_dev = platform_get_otgdata(pdev);
++ int retval = 0;
++
++ device_create_file(&pdev->dev,&dev_attr_srpinit);
++
++ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n",__func__, pdev);
++ /*
++ * Allocate PCD structure
++ */
++ pcd = kmalloc( sizeof(dwc_otg_pcd_t), GFP_KERNEL);
++
++ if (pcd == 0)
++ {
++ return -ENOMEM;
++ }
++
++ memset(pcd, 0, sizeof(dwc_otg_pcd_t));
++ spin_lock_init( &pcd->lock );
++
++ otg_dev->pcd = pcd;
++ s_pcd = pcd;
++ pcd->gadget.name = pcd_name;
++ strcpy(pcd->gadget.dev.bus_id, "gadget");
++
++ pcd->otg_dev = platform_get_otgdata(pdev);
++
++ pcd->gadget.dev.parent = &pdev->dev;
++ pcd->gadget.dev.release = dwc_otg_pcd_gadget_release;
++ pcd->gadget.ops = &dwc_otg_pcd_ops;
++
++ if (GET_CORE_IF(pcd)->hwcfg4.b.ded_fifo_en)
++ {
++ DWC_PRINT("Dedicated Tx FIFOs mode\n");
++ }
++ else
++ {
++ DWC_PRINT("Shared Tx FIFO mode\n");
++ }
++
++ /* If the module is set to FS or if the PHY_TYPE is FS then the gadget
++ * should not report as dual-speed capable. replace the following line
++ * with the block of code below it once the software is debugged for
++ * this. If is_dualspeed = 0 then the gadget driver should not report
++ * a device qualifier descriptor when queried. */
++ if ((GET_CORE_IF(pcd)->core_params->speed == DWC_SPEED_PARAM_FULL) ||
++ ((GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type == 2) &&
++ (GET_CORE_IF(pcd)->hwcfg2.b.fs_phy_type == 1) &&
++ (GET_CORE_IF(pcd)->core_params->ulpi_fs_ls)))
++ {
++ pcd->gadget.is_dualspeed = 0;
++ }
++ else
++ {
++ pcd->gadget.is_dualspeed = 1;
++ }
++
++ //if ((otg_dev->core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE) ||
++ //(otg_dev->core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST) ||
++ //(otg_dev->core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) ||
++ //(otg_dev->core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST))
++ //{
++ // pcd->gadget.is_otg = 0;
++ //}
++ //else
++ {
++ pcd->gadget.is_otg = 1;
++ }
++
++ pcd->driver = 0;
++ /* Register the gadget device */
++ device_register( &pcd->gadget.dev );
++
++ /*
++ * Initialized the Core for Device mode.
++ */
++ if (dwc_otg_is_device_mode( GET_CORE_IF(pcd) ))
++ {
++ dwc_otg_core_dev_init( GET_CORE_IF(pcd) );
++ }
++ /*
++ * Initialize EP structures
++ */
++ dwc_otg_pcd_reinit( pcd );
++
++ /*
++ * Register the PCD Callbacks.
++ */
++ dwc_otg_cil_register_pcd_callbacks( otg_dev->core_if, &pcd_callbacks,pcd );
++ /*
++ * Setup interupt handler
++ */
++ DWC_DEBUGPL( DBG_ANY, "registering handler for irq%d\n",ARM_VP_OTG_INTR );
++ retval = request_irq(ARM_VP_OTG_INTR, dwc_otg_pcd_irq,
++ IRQF_SHARED, pcd->gadget.name, pcd);
++ if (retval != 0)
++ {
++ DWC_ERROR("request of irq%d failed\n", ARM_VP_OTG_INTR);
++ kfree (pcd);
++ return -EBUSY;
++ }
++
++ /*
++ * Initialize the DMA buffer for SETUP packets
++ */
++ if (GET_CORE_IF(pcd)->dma_enable)
++ {
++ pcd->setup_pkt = dma_alloc_coherent (NULL, sizeof (*pcd->setup_pkt) * 5, &pcd->setup_pkt_dma_handle, 0);
++ pcd->status_buf = dma_alloc_coherent (NULL, sizeof (uint16_t), &pcd->status_buf_dma_handle, 0);
++ }
++ else
++ {
++ pcd->setup_pkt = kmalloc (sizeof (*pcd->setup_pkt) * 5, GFP_KERNEL);
++ pcd->status_buf = kmalloc (sizeof (uint16_t), GFP_KERNEL);
++ }
++
++ if (pcd->setup_pkt == 0)
++ {
++ kfree (pcd);
++ return -ENOMEM;
++ }
++
++ /* Initialize tasklet */
++ start_xfer_tasklet.data = (unsigned long)pcd;
++ pcd->start_xfer_tasklet = &start_xfer_tasklet;
++
++ return 0;
++}
++
++/**
++ * Cleanup the PCD.
++ */
++void dwc_otg_pcd_remove(struct platform_device *pdev)
++{
++ dwc_otg_device_t *otg_dev = platform_get_otgdata(pdev);
++ dwc_otg_pcd_t *pcd = otg_dev->pcd;
++
++ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, pdev);
++
++ device_remove_file(&pdev->dev, &dev_attr_srpinit);
++
++ /*
++ * Free the IRQ
++ */
++ free_irq(ARM_VP_OTG_INTR, pcd);
++
++ /* start with the driver above us */
++ if (pcd->driver)
++ {
++ /* should have been done already by driver model core */
++ DWC_WARN("driver '%s' is still registered\n",
++ pcd->driver->driver.name);
++ usb_gadget_unregister_driver( pcd->driver);
++ }
++ device_unregister(&pcd->gadget.dev);
++
++ if (GET_CORE_IF(pcd)->dma_enable)
++ {
++ dma_free_coherent (NULL, sizeof (*pcd->setup_pkt) * 5, pcd->setup_pkt, pcd->setup_pkt_dma_handle);
++ dma_free_coherent (NULL, sizeof (uint16_t), pcd->status_buf, pcd->status_buf_dma_handle);
++ }
++ else
++ {
++ kfree (pcd->setup_pkt);
++ kfree (pcd->status_buf);
++ }
++
++ kfree(pcd);
++ otg_dev->pcd = 0;
++}
++
++/**
++ * This function registers a gadget driver with the PCD.
++ *
++ * When a driver is successfully registered, it will receive control
++ * requests including set_configuration(), which enables non-control
++ * requests. then usb traffic follows until a disconnect is reported.
++ * then a host may connect again, or the driver might get unbound.
++ *
++ * @param _driver The driver being registered
++ */
++int usb_gadget_register_driver(struct usb_gadget_driver *_driver)
++{
++ int retval;
++
++ DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n", _driver->driver.name);
++
++ if (!_driver || _driver->speed == USB_SPEED_UNKNOWN ||
++ !_driver->bind ||
++ !_driver->unbind ||
++ !_driver->disconnect ||
++ !_driver->setup)
++ {
++ DWC_DEBUGPL(DBG_PCDV,"EINVAL\n");
++ return -EINVAL;
++ }
++ if (s_pcd == 0)
++ {
++ DWC_DEBUGPL(DBG_PCDV,"ENODEV\n");
++ return -ENODEV;
++ }
++ if (s_pcd->driver != 0)
++ {
++ DWC_DEBUGPL(DBG_PCDV,"EBUSY (%p)\n", s_pcd->driver);
++ return -EBUSY;
++ }
++
++ /* hook up the driver */
++ s_pcd->driver = _driver;
++ s_pcd->gadget.dev.driver = &_driver->driver;
++
++ DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", _driver->driver.name);
++ retval = _driver->bind(&s_pcd->gadget);
++ if (retval)
++ {
++ DWC_ERROR("bind to driver %s --> error %d\n",
++ _driver->driver.name, retval);
++ s_pcd->driver = 0;
++ s_pcd->gadget.dev.driver = 0;
++ return retval;
++ }
++ DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n",
++ _driver->driver.name);
++ return 0;
++}
++
++EXPORT_SYMBOL(usb_gadget_register_driver);
++
++/**
++ * This function unregisters a gadget driver
++ *
++ * @param _driver The driver being unregistered
++ */
++int usb_gadget_unregister_driver(struct usb_gadget_driver *_driver)
++{
++ //DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);
++
++ if (s_pcd == 0)
++ {
++ DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
++ -ENODEV);
++ return -ENODEV;
++ }
++ if (_driver == 0 || _driver != s_pcd->driver)
++ {
++ DWC_DEBUGPL( DBG_ANY, "%s Return(%d): driver?\n", __func__,
++ -EINVAL);
++ return -EINVAL;
++ }
++
++ _driver->unbind(&s_pcd->gadget);
++ s_pcd->driver = 0;
++
++ DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n",
++ _driver->driver.name);
++ return 0;
++}
++EXPORT_SYMBOL(usb_gadget_unregister_driver);
++
++#endif /* DWC_HOST_ONLY */
+diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd.h b/drivers/usb/dwc_otg/dwc_otg_pcd.h
+new file mode 100644
+index 0000000..041a8af
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_pcd.h
+@@ -0,0 +1,213 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_pcd.h $
++ * $Revision: #6 $
++ * $Date: 2007/02/07 $
++ * $Change: 791271 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++#ifndef DWC_HOST_ONLY
++#if !defined(__DWC_PCD_H__)
++#define __DWC_PCD_H__
++
++#include <linux/types.h>
++#include <linux/list.h>
++#include <linux/errno.h>
++#include <linux/platform_device.h>
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++#include <linux/interrupt.h>
++#include <linux/dma-mapping.h>
++
++struct lm_device;
++struct dwc_otg_device;
++
++#include "dwc_otg_cil.h"
++
++/**
++ * @file
++ *
++ * This file contains the structures, constants, and interfaces for
++ * the Perpherial Contoller Driver (PCD).
++ *
++ * The Peripheral Controller Driver (PCD) for Linux will implement the
++ * Gadget API, so that the existing Gadget drivers can be used. For
++ * the Mass Storage Function driver the File-backed USB Storage Gadget
++ * (FBS) driver will be used. The FBS driver supports the
++ * Control-Bulk (CB), Control-Bulk-Interrupt (CBI), and Bulk-Only
++ * transports.
++ *
++ */
++
++/** Invalid DMA Address */
++#define DMA_ADDR_INVALID (~(dma_addr_t)0)
++/** Maxpacket size for EP0 */
++#define MAX_EP0_SIZE 64
++/** Maxpacket size for any EP */
++#define MAX_PACKET_SIZE 1024
++
++/**
++ * Get the pointer to the core_if from the pcd pointer.
++ */
++#define GET_CORE_IF( _pcd ) (_pcd->otg_dev->core_if)
++
++/**
++ * States of EP0.
++ */
++typedef enum ep0_state
++{
++ EP0_DISCONNECT, /* no host */
++ EP0_IDLE,
++ EP0_IN_DATA_PHASE,
++ EP0_OUT_DATA_PHASE,
++ EP0_STATUS,
++ EP0_STALL,
++} ep0state_e;
++
++/** Fordward declaration.*/
++struct dwc_otg_pcd;
++
++/** PCD EP structure.
++ * This structure describes an EP, there is an array of EPs in the PCD
++ * structure.
++ */
++typedef struct dwc_otg_pcd_ep
++{
++ /** USB EP data */
++ struct usb_ep ep;
++ /** USB EP Descriptor */
++ const struct usb_endpoint_descriptor *desc;
++
++ /** queue of dwc_otg_pcd_requests. */
++ struct list_head queue;
++ unsigned stopped : 1;
++ unsigned disabling : 1;
++ unsigned dma : 1;
++ unsigned queue_sof : 1;
++
++ /** DWC_otg ep data. */
++ dwc_ep_t dwc_ep;
++
++ /** Pointer to PCD */
++ struct dwc_otg_pcd *pcd;
++} dwc_otg_pcd_ep_t;
++
++
++
++/** DWC_otg PCD Structure.
++ * This structure encapsulates the data for the dwc_otg PCD.
++ */
++typedef struct dwc_otg_pcd
++{
++ /** USB gadget */
++ struct usb_gadget gadget;
++ /** USB gadget driver pointer*/
++ struct usb_gadget_driver *driver;
++ /** The DWC otg device pointer. */
++ struct dwc_otg_device *otg_dev;
++
++ /** State of EP0 */
++ ep0state_e ep0state;
++ /** EP0 Request is pending */
++ unsigned ep0_pending : 1;
++ /** Indicates when SET CONFIGURATION Request is in process */
++ //unsigned request_config : 1;
++ /** The state of the Remote Wakeup Enable. */
++ unsigned remote_wakeup_enable : 1;
++ /** The state of the B-Device HNP Enable. */
++ unsigned b_hnp_enable : 1;
++ /** The state of A-Device HNP Support. */
++ unsigned a_hnp_support : 1;
++ /** The state of the A-Device Alt HNP support. */
++ unsigned a_alt_hnp_support : 1;
++ /** Count of pending Requests */
++ unsigned request_pending;
++
++ /** SETUP packet for EP0
++ * This structure is allocated as a DMA buffer on PCD initialization
++ * with enough space for up to 3 setup packets.
++ */
++ union
++ {
++ struct usb_ctrlrequest req;
++ uint32_t d32[2];
++ } *setup_pkt;
++
++ dma_addr_t setup_pkt_dma_handle;
++
++ /** 2-byte dma buffer used to return status from GET_STATUS */
++ uint16_t *status_buf;
++ dma_addr_t status_buf_dma_handle;
++
++ /** Array of EPs. */
++ dwc_otg_pcd_ep_t ep0;
++ /** Array of IN EPs. */
++ dwc_otg_pcd_ep_t in_ep[ MAX_EPS_CHANNELS - 1];
++ /** Array of OUT EPs. */
++ dwc_otg_pcd_ep_t out_ep[ MAX_EPS_CHANNELS - 1];
++ /** number of valid EPs in the above array. */
++// unsigned num_eps : 4;
++ spinlock_t lock;
++ /** Timer for SRP. If it expires before SRP is successful
++ * clear the SRP. */
++ struct timer_list srp_timer;
++
++ /** Tasklet to defer starting of TEST mode transmissions until
++ * Status Phase has been completed.
++ */
++ struct tasklet_struct test_mode_tasklet;
++
++ /** Tasklet to delay starting of xfer in DMA mode */
++ struct tasklet_struct *start_xfer_tasklet;
++
++ /** The test mode to enter when the tasklet is executed. */
++ unsigned test_mode;
++
++} dwc_otg_pcd_t;
++
++
++/** DWC_otg request structure.
++ * This structure is a list of requests.
++ */
++typedef struct dwc_otg_pcd_request
++{
++ struct usb_request req; /**< USB Request. */
++ struct list_head queue; /**< queue of these requests. */
++} dwc_otg_pcd_request_t;
++
++
++extern int __init dwc_otg_pcd_init(struct platform_device *pdev);
++extern void dwc_otg_pcd_remove(struct platform_device *pdev);
++
++extern int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t *_pcd);
++extern void dwc_otg_pcd_start_srp_timer(dwc_otg_pcd_t *_pcd);
++
++extern void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t *_pcd);
++extern void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t *_pcd, int set);
++
++#endif
++#endif /* DWC_HOST_ONLY */
+diff --git a/drivers/usb/dwc_otg/dwc_otg_pcd_intr.c b/drivers/usb/dwc_otg/dwc_otg_pcd_intr.c
+new file mode 100644
+index 0000000..37e8916
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_pcd_intr.c
+@@ -0,0 +1,2714 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_pcd_intr.c $
++ * $Revision: #18 $
++ * $Date: 2007/02/07 $
++ * $Change: 791271 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++#ifndef DWC_HOST_ONLY
++#include <linux/interrupt.h>
++#include <linux/dma-mapping.h>
++#include "dwc_otg_driver.h"
++#include "dwc_otg_pcd.h"
++#include "tcc_usb_def.h"
++
++/* For Signature */
++#define DWC_OTG_PCD_INTR_SIGNATURE 'D','W','C','_','O','T','G','_','P','C','D','_','I','N','T','R','_'
++#define DWC_OTG_PCD_INTR_VERSION 'V','2','.','0','0','1'
++static const unsigned char DWC_OTG_PCD_INTR_C_Version[] =
++ {SIGBYAHONG, DWC_OTG_PCD_INTR_SIGNATURE, SIGN_OS ,SIGN_CHIPSET, DWC_OTG_PCD_INTR_VERSION, 0};
++
++
++const unsigned char* dwc_otg_pcd_intr_get_version(void)
++{
++ return DWC_OTG_PCD_INTR_C_Version;
++}
++
++
++#define DEBUG_EP0
++
++/* request functions defined in "dwc_otg_pcd.c" */
++extern void request_done( dwc_otg_pcd_ep_t *_ep, dwc_otg_pcd_request_t *_req,
++ int _status);
++extern void request_nuke( dwc_otg_pcd_ep_t *_ep );
++extern void dwc_otg_pcd_update_otg( dwc_otg_pcd_t *_pcd,
++ const unsigned _reset );
++
++/** @file
++ * This file contains the implementation of the PCD Interrupt handlers.
++ *
++ * The PCD handles the device interrupts. Many conditions can cause a
++ * device interrupt. When an interrupt occurs, the device interrupt
++ * service routine determines the cause of the interrupt and
++ * dispatches handling to the appropriate function. These interrupt
++ * handling functions are described below.
++ * All interrupt registers are processed from LSB to MSB.
++ */
++
++
++/**
++ * This function prints the ep0 state for debug purposes.
++ */
++static inline void print_ep0_state( dwc_otg_pcd_t *_pcd )
++{
++#ifdef DEBUG
++ char str[40];
++
++ switch (_pcd->ep0state)
++ {
++ case EP0_DISCONNECT:
++ strcpy(str, "EP0_DISCONNECT");
++ break;
++ case EP0_IDLE:
++ strcpy(str, "EP0_IDLE");
++ break;
++ case EP0_IN_DATA_PHASE:
++ strcpy(str, "EP0_IN_DATA_PHASE");
++ break;
++ case EP0_OUT_DATA_PHASE:
++ strcpy(str, "EP0_OUT_DATA_PHASE");
++ break;
++ case EP0_STATUS:
++ strcpy(str,"EP0_STATUS");
++ break;
++ case EP0_STALL:
++ strcpy(str,"EP0_STALL");
++ break;
++ default:
++ strcpy(str,"EP0_INVALID");
++ }
++
++ DWC_DEBUGPL(DBG_ANY, "%s(%d)\n", str, _pcd->ep0state);
++#endif
++}
++
++/**
++ * This function returns pointer to in ep struct with number ep_num
++ */
++static inline dwc_otg_pcd_ep_t* get_in_ep( dwc_otg_pcd_t *_pcd, uint32_t ep_num)
++{
++ int i;
++ int num_in_eps = GET_CORE_IF(_pcd)->dev_if->num_in_eps;
++ if (ep_num == 0)
++ {
++ return &_pcd->ep0;
++ }
++ else
++ {
++ for (i = 0; i < num_in_eps; ++i)
++ {
++ if (_pcd->in_ep[i].dwc_ep.num == ep_num)
++ return &_pcd->in_ep[i];
++ }
++ return 0;
++ }
++}
++/**
++ * This function returns pointer to out ep struct with number ep_num
++ */
++static inline dwc_otg_pcd_ep_t* get_out_ep( dwc_otg_pcd_t *_pcd, uint32_t ep_num)
++{
++ int i;
++ int num_out_eps = GET_CORE_IF(_pcd)->dev_if->num_out_eps;
++ if (ep_num == 0)
++ {
++ return &_pcd->ep0;
++ }
++ else
++ {
++ for (i = 0; i < num_out_eps; ++i)
++ {
++ if (_pcd->out_ep[i].dwc_ep.num == ep_num)
++ return &_pcd->out_ep[i];
++ }
++ return 0;
++ }
++}
++/**
++ * This functions gets a pointer to an EP from the wIndex address
++ * value of the control request.
++ */
++static dwc_otg_pcd_ep_t *get_ep_by_addr (dwc_otg_pcd_t *_pcd, u16 _wIndex)
++{
++ dwc_otg_pcd_ep_t *ep;
++
++ if ((_wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
++ return &_pcd->ep0;
++ list_for_each_entry( ep, &_pcd->gadget.ep_list, ep.ep_list)
++ {
++ u8 bEndpointAddress;
++
++ if (!ep->desc)
++ continue;
++ bEndpointAddress = ep->desc->bEndpointAddress;
++ if ((_wIndex ^ bEndpointAddress) & USB_DIR_IN)
++ continue;
++ if ((_wIndex & 0x0f) == (bEndpointAddress & 0x0f))
++ return ep;
++ }
++ return NULL;
++}
++
++/**
++ * This function checks the EP request queue, if the queue is not
++ * empty the next request is started.
++ */
++void start_next_request( dwc_otg_pcd_ep_t *_ep )
++{
++ dwc_otg_pcd_request_t *req = 0;
++
++ if (!list_empty(&_ep->queue))
++ {
++ req = list_entry(_ep->queue.next,
++ dwc_otg_pcd_request_t, queue);
++
++ /* Setup and start the Transfer */
++ _ep->dwc_ep.start_xfer_buff = req->req.buf;
++ _ep->dwc_ep.xfer_buff = req->req.buf;
++ _ep->dwc_ep.xfer_len = req->req.length;
++ _ep->dwc_ep.xfer_count = 0;
++ _ep->dwc_ep.dma_addr = req->req.dma;
++ _ep->dwc_ep.sent_zlp = 0;
++ _ep->dwc_ep.total_len = _ep->dwc_ep.xfer_len;
++
++ //DWC_ERROR(" -> starting transfer (start_next_req) %s %s\n",
++ //_ep->ep.name, _ep->dwc_ep.is_in?"IN":"OUT");
++
++ dwc_otg_ep_start_transfer( GET_CORE_IF(_ep->pcd), &_ep->dwc_ep );
++ }
++}
++
++/**
++ * This function handles the SOF Interrupts. At this time the SOF
++ * Interrupt is disabled.
++ */
++int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t *_pcd)
++{
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
++
++ gintsts_data_t gintsts;
++
++ //DWC_DEBUGPL(DBG_PCD, "SOF\n");
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.sofintr = 1;
++ dwc_write_reg32 (&core_if->core_global_regs->gintsts, gintsts.d32);
++
++ return 1;
++}
++
++
++/**
++ * This function handles the Rx Status Queue Level Interrupt, which
++ * indicates that there is a least one packet in the Rx FIFO. The
++ * packets are moved from the FIFO to memory, where they will be
++ * processed when the Endpoint Interrupt Register indicates Transfer
++ * Complete or SETUP Phase Done.
++ *
++ * Repeat the following until the Rx Status Queue is empty:
++ * -# Read the Receive Status Pop Register (GRXSTSP) to get Packet
++ * info
++ * -# If Receive FIFO is empty then skip to step Clear the interrupt
++ * and exit
++ * -# If SETUP Packet call dwc_otg_read_setup_packet to copy the
++ * SETUP data to the buffer
++ * -# If OUT Data Packet call dwc_otg_read_packet to copy the data
++ * to the destination buffer
++ */
++int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(dwc_otg_pcd_t *_pcd)
++{
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
++ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++ gintmsk_data_t gintmask = {.d32=0};
++ device_grxsts_data_t status;
++ dwc_otg_pcd_ep_t *ep;
++ gintsts_data_t gintsts;
++#ifdef DEBUG
++ static char *dpid_str[] ={ "D0", "D2", "D1", "MDATA" };
++#endif
++
++ //DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
++ /* Disable the Rx Status Queue Level interrupt */
++ gintmask.b.rxstsqlvl= 1;
++ dwc_modify_reg32( &global_regs->gintmsk, gintmask.d32, 0);
++
++ /* Get the Status from the top of the FIFO */
++ status.d32 = dwc_read_reg32( &global_regs->grxstsp );
++
++ DWC_DEBUGPL(DBG_PCD, "EP:%d BCnt:%d DPID:%s "
++ "pktsts:%x Frame:%d(0x%0x)\n",
++ status.b.epnum, status.b.bcnt,
++ dpid_str[status.b.dpid],
++ status.b.pktsts, status.b.fn, status.b.fn);
++ /* Get pointer to EP structure */
++ ep = get_out_ep(_pcd, status.b.epnum);
++// ep = &_pcd->out_ep[ status.b.epnum - 1];
++
++ switch (status.b.pktsts)
++ {
++ case DWC_DSTS_GOUT_NAK:
++ DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n");
++ break;
++ case DWC_STS_DATA_UPDT:
++ DWC_DEBUGPL(DBG_PCDV, "OUT Data Packet\n");
++ if (status.b.bcnt && ep->dwc_ep.xfer_buff)
++ {
++ /** @todo NGS Check for buffer overflow? */
++ dwc_otg_read_packet( core_if,
++ ep->dwc_ep.xfer_buff,
++ status.b.bcnt);
++ ep->dwc_ep.xfer_count += status.b.bcnt;
++ ep->dwc_ep.xfer_buff += status.b.bcnt;
++ }
++ break;
++ case DWC_STS_XFER_COMP:
++ DWC_DEBUGPL(DBG_PCDV, "OUT Complete\n");
++ break;
++ case DWC_DSTS_SETUP_COMP:
++#ifdef DEBUG_EP0
++ DWC_DEBUGPL(DBG_PCDV, "Setup Complete\n");
++#endif
++ break;
++ case DWC_DSTS_SETUP_UPDT:
++ dwc_otg_read_setup_packet( core_if, _pcd->setup_pkt->d32);
++#ifdef DEBUG_EP0
++ DWC_DEBUGPL(DBG_PCD,
++ "SETUP PKT: %02x.%02x v%04x i%04x l%04x\n",
++ _pcd->setup_pkt->req.bRequestType,
++ _pcd->setup_pkt->req.bRequest,
++ _pcd->setup_pkt->req.wValue,
++ _pcd->setup_pkt->req.wIndex,
++ _pcd->setup_pkt->req.wLength);
++#endif
++ ep->dwc_ep.xfer_count += status.b.bcnt;
++ break;
++ default:
++ DWC_DEBUGPL(DBG_PCDV, "Invalid Packet Status (0x%0x)\n",
++ status.b.pktsts);
++ break;
++ }
++
++ /* Enable the Rx Status Queue Level interrupt */
++ dwc_modify_reg32( &global_regs->gintmsk, 0, gintmask.d32);
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.rxstsqlvl = 1;
++ dwc_write_reg32 (&global_regs->gintsts, gintsts.d32);
++
++ //DWC_DEBUGPL(DBG_PCDV, "EXIT: %s\n", __func__);
++ return 1;
++}
++/**
++ * This function examines the Device IN Token Learning Queue to
++ * determine the EP number of the last IN token received. This
++ * implementation is for the Mass Storage device where there are only
++ * 2 IN EPs (Control-IN and BULK-IN).
++ *
++ * The EP numbers for the first six IN Tokens are in DTKNQR1 and there
++ * are 8 EP Numbers in each of the other possible DTKNQ Registers.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ *
++ */
++static inline int get_ep_of_last_in_token(dwc_otg_core_if_t *_core_if)
++{
++ dwc_otg_device_global_regs_t *dev_global_regs =
++ _core_if->dev_if->dev_global_regs;
++ const uint32_t TOKEN_Q_DEPTH = _core_if->hwcfg2.b.dev_token_q_depth;
++ /* Number of Token Queue Registers */
++ const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
++ dtknq1_data_t dtknqr1;
++ uint32_t in_tkn_epnums[4];
++ int ndx = 0;
++ int i = 0;
++ volatile uint32_t *addr = &dev_global_regs->dtknqr1;
++ int epnum = 0;
++
++ //DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
++
++
++ /* Read the DTKNQ Registers */
++ for (i = 0; i < DTKNQ_REG_CNT; i++)
++ {
++ in_tkn_epnums[ i ] = dwc_read_reg32(addr);
++ DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i+1,
++ in_tkn_epnums[i]);
++ if (addr == &dev_global_regs->dvbusdis)
++ {
++ addr = &dev_global_regs->dtknqr3_dthrctl;
++ }
++ else
++ {
++ ++addr;
++ }
++
++ }
++
++ /* Copy the DTKNQR1 data to the bit field. */
++ dtknqr1.d32 = in_tkn_epnums[0];
++ /* Get the EP numbers */
++ in_tkn_epnums[0] = dtknqr1.b.epnums0_5;
++ ndx = dtknqr1.b.intknwptr - 1;
++
++ //DWC_DEBUGPL(DBG_PCDV,"ndx=%d\n",ndx);
++ if (ndx == -1)
++ {
++ /** @todo Find a simpler way to calculate the max
++ * queue position.*/
++ int cnt = TOKEN_Q_DEPTH;
++ if (TOKEN_Q_DEPTH <= 6)
++ {
++ cnt = TOKEN_Q_DEPTH - 1;
++ }
++ else if (TOKEN_Q_DEPTH <= 14)
++ {
++ cnt = TOKEN_Q_DEPTH - 7;
++ }
++ else if (TOKEN_Q_DEPTH <= 22)
++ {
++ cnt = TOKEN_Q_DEPTH - 15;
++ }
++ else
++ {
++ cnt = TOKEN_Q_DEPTH - 23;
++ }
++ epnum = (in_tkn_epnums[ DTKNQ_REG_CNT - 1 ] >> (cnt * 4)) & 0xF;
++ }
++ else
++ {
++ if (ndx <= 5)
++ {
++ epnum = (in_tkn_epnums[0] >> (ndx * 4)) & 0xF;
++ }
++ else if (ndx <= 13 )
++ {
++ ndx -= 6;
++ epnum = (in_tkn_epnums[1] >> (ndx * 4)) & 0xF;
++ }
++ else if (ndx <= 21 )
++ {
++ ndx -= 14;
++ epnum = (in_tkn_epnums[2] >> (ndx * 4)) & 0xF;
++ }
++ else if (ndx <= 29 )
++ {
++ ndx -= 22;
++ epnum = (in_tkn_epnums[3] >> (ndx * 4)) & 0xF;
++ }
++ }
++ //DWC_DEBUGPL(DBG_PCD,"epnum=%d\n",epnum);
++ return epnum;
++}
++
++/**
++ * This interrupt occurs when the non-periodic Tx FIFO is half-empty.
++ * The active request is checked for the next packet to be loaded into
++ * the non-periodic Tx FIFO.
++ */
++//int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(dwc_otg_pcd_t *_pcd)
++//{
++// dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
++// dwc_otg_core_global_regs_t *global_regs =
++// core_if->core_global_regs;
++// dwc_otg_dev_in_ep_regs_t *ep_regs;
++// gnptxsts_data_t txstatus = {.d32 = 0};
++// gintsts_data_t gintsts;
++//
++// int epnum = 0;
++// dwc_otg_pcd_ep_t *ep = 0;
++// uint32_t len = 0;
++// int dwords;
++//
++// /* Get the epnum from the IN Token Learning Queue. */
++// epnum = get_ep_of_last_in_token(core_if);
++// ep = get_in_ep(_pcd, epnum);
++///*
++// if(epnum != 0)
++// ep = &_pcd->in_ep[epnum-1];
++// else
++// ep = &_pcd->ep0;
++//*/
++// DWC_DEBUGPL(DBG_PCD, "NP TxFifo Empty: %s(%d) \n", ep->ep.name, epnum );
++//
++// ep_regs = core_if->dev_if->in_ep_regs[epnum];
++//
++// len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
++// if (len > ep->dwc_ep.maxpacket)
++// {
++// len = ep->dwc_ep.maxpacket;
++// }
++// dwords = (len + 3)/4;
++//
++//
++// /* While there is space in the queue and space in the FIFO and
++// * More data to tranfer, Write packets to the Tx FIFO */
++// txstatus.d32 = dwc_read_reg32( &global_regs->gnptxsts );
++// DWC_DEBUGPL(DBG_PCDV, "b4 GNPTXSTS=0x%08x\n",txstatus.d32);
++//
++// while (txstatus.b.nptxqspcavail > 0 &&
++// txstatus.b.nptxfspcavail >= dwords &&
++// ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len)
++// {
++// /* Write the FIFO */
++// dwc_otg_ep_write_packet( core_if, &ep->dwc_ep, 0 );
++// len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
++//
++// if (len > ep->dwc_ep.maxpacket)
++// {
++// len = ep->dwc_ep.maxpacket;
++// }
++//
++// dwords = (len + 3)/4;
++// txstatus.d32 = dwc_read_reg32(&global_regs->gnptxsts);
++// DWC_DEBUGPL(DBG_PCDV,"GNPTXSTS=0x%08x\n",txstatus.d32);
++// }
++//
++// DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n",
++// dwc_read_reg32( &global_regs->gnptxsts));
++//
++// /* Clear interrupt */
++// gintsts.d32 = 0;
++// gintsts.b.nptxfempty = 1;
++// dwc_write_reg32 (&global_regs->gintsts, gintsts.d32);
++//
++// return 1;
++//}
++
++/**
++ * This function is called when dedicated Tx FIFO Empty interrupt occurs.
++ * The active request is checked for the next packet to be loaded into
++ * apropriate Tx FIFO.
++ */
++static int32_t write_empty_tx_fifo(dwc_otg_pcd_t *_pcd, uint32_t epnum)
++{
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
++ dwc_otg_dev_if_t* dev_if = core_if->dev_if;
++ //dwc_otg_dev_in_ep_regs_t *ep_regs;
++ dtxfsts_data_t txstatus = {.d32 = 0};
++ dwc_otg_pcd_ep_t *ep = 0;
++ uint32_t len = 0;
++ int dwords;
++
++ ep = get_in_ep(_pcd, epnum);
++ /*
++ if(epnum != 0)
++ ep = &_pcd->in_ep[epnum-1];
++ else
++ ep = &_pcd->ep0;
++ */
++ DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %s(%d) \n", ep->ep.name, epnum );
++
++ if ( ep->dwc_ep.xfer_count >= ep->dwc_ep.xfer_len ) //AlenOh
++ {
++ DWC_DEBUGPL(DBG_PCD, "There are no data for write to TxFifo\n");
++ return 0;
++ }
++
++ //ep_regs = core_if->dev_if->in_ep_regs[epnum];
++
++ len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
++
++ if (len > ep->dwc_ep.maxpacket)
++ {
++ len = ep->dwc_ep.maxpacket;
++ }
++
++ dwords = (len + 3)/4;
++
++ /* While there is space in the queue and space in the FIFO and
++ * More data to tranfer, Write packets to the Tx FIFO */
++ txstatus.d32 = dwc_read_reg32( &dev_if->in_ep_regs[epnum]->dtxfsts);
++ DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n",epnum,txstatus.d32);
++
++ while (txstatus.b.txfspcavail >= dwords &&
++ ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len &&
++ ep->dwc_ep.xfer_len != 0)
++ {
++ /* Write the FIFO */
++ dwc_otg_ep_write_packet( core_if, &ep->dwc_ep, 0);
++
++ len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
++ if (len > ep->dwc_ep.maxpacket)
++ {
++ len = ep->dwc_ep.maxpacket;
++ }
++
++ dwords = (len + 3)/4;
++ txstatus.d32 = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts);
++ DWC_DEBUGPL(DBG_PCDV,"dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
++ }
++
++ DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n",epnum,dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts));
++
++ return 1;
++}
++
++
++/**
++ * This function is called when the Device is disconnected. It stops
++ * any active requests and informs the Gadget driver of the
++ * disconnect.
++ */
++void dwc_otg_pcd_stop(dwc_otg_pcd_t *_pcd)
++{
++ int i, num_in_eps, num_out_eps;
++ dwc_otg_pcd_ep_t *ep;
++
++ //gintmsk_data_t intr_mask = {.d32 = 0};
++
++ num_in_eps = GET_CORE_IF(_pcd)->dev_if->num_in_eps;
++ num_out_eps = GET_CORE_IF(_pcd)->dev_if->num_out_eps;
++
++ DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__ );
++ /* don't disconnect drivers more than once */
++ if (_pcd->ep0state == EP0_DISCONNECT)
++ {
++ DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__ );
++ return;
++ }
++ _pcd->ep0state = EP0_DISCONNECT;
++
++ /* Reset the OTG state. */
++ dwc_otg_pcd_update_otg( _pcd, 1);
++
++ /* Disable the NP Tx Fifo Empty Interrupt. */
++ //intr_mask.b.nptxfempty = 1;
++ //dwc_modify_reg32(&GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
++ // intr_mask.d32, 0);
++
++ /* Flush the FIFOs */
++ /**@todo NGS Flush Periodic FIFOs */
++ dwc_otg_flush_tx_fifo( GET_CORE_IF(_pcd), 0x10); //AlenOh all Tx FIFOs
++ dwc_otg_flush_rx_fifo( GET_CORE_IF(_pcd) );
++
++ /* prevent new request submissions, kill any outstanding requests */
++ ep = &_pcd->ep0;
++ request_nuke(ep);
++ /* prevent new request submissions, kill any outstanding requests */
++ for (i = 0; i < num_in_eps; i++)
++ {
++ dwc_otg_pcd_ep_t *ep = &_pcd->in_ep[i];
++ request_nuke(ep);
++ }
++ /* prevent new request submissions, kill any outstanding requests */
++ for (i = 0; i < num_out_eps; i++)
++ {
++ dwc_otg_pcd_ep_t *ep = &_pcd->out_ep[i];
++ request_nuke(ep);
++ }
++
++ /* report disconnect; the driver is already quiesced */
++ if (_pcd->driver && _pcd->driver->disconnect)
++ {
++ SPIN_LOCK(&_pcd->lock);
++ _pcd->driver->disconnect(&_pcd->gadget);
++ SPIN_UNLOCK(&_pcd->lock);
++ }
++}
++
++/**
++ * This interrupt indicates that ...
++ */
++int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t *_pcd)
++{
++ gintmsk_data_t intr_mask = { .d32 = 0};
++ gintsts_data_t gintsts;
++
++ DWC_PRINT("INTERRUPT Handler not implemented for %s\n", "i2cintr");
++ intr_mask.b.i2cintr = 1;
++ dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
++ intr_mask.d32, 0 );
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.i2cintr = 1;
++ dwc_write_reg32 (&GET_CORE_IF(_pcd)->core_global_regs->gintsts,
++ gintsts.d32);
++ return 1;
++}
++
++
++/**
++ * This interrupt indicates that ...
++ */
++int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t *_pcd)
++{
++ gintsts_data_t gintsts;
++#if defined(VERBOSE)
++ DWC_PRINT("Early Suspend Detected\n");
++#endif
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.erlysuspend = 1;
++ dwc_write_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintsts,
++ gintsts.d32);
++ return 1;
++}
++
++/**
++ * This function configures EPO to receive SETUP packets.
++ *
++ * @todo NGS: Update the comments from the HW FS.
++ *
++ * -# Program the following fields in the endpoint specific registers
++ * for Control OUT EP 0, in order to receive a setup packet
++ * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
++ * setup packets)
++ * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
++ * to back setup packets)
++ * - In DMA mode, DOEPDMA0 Register with a memory address to
++ * store any setup packets received
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ * @param _pcd Programming view of the PCD.
++ */
++static inline void ep0_out_start( dwc_otg_core_if_t *_core_if, dwc_otg_pcd_t *_pcd )
++{
++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
++ deptsiz0_data_t doeptsize0 = { .d32 = 0};
++
++#ifdef VERBOSE
++ DWC_DEBUGPL(DBG_PCDV,"%s() doepctl0=%0x\n", __func__,
++ dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl));
++#endif
++
++ doeptsize0.b.supcnt = 3;
++ doeptsize0.b.pktcnt = 1;
++ doeptsize0.b.xfersize = 8*3;
++
++ dwc_write_reg32( &dev_if->out_ep_regs[0]->doeptsiz,
++ doeptsize0.d32 );
++
++ if (_core_if->dma_enable)
++ {
++ depctl_data_t doepctl = { .d32 = 0 };
++ /** @todo dma needs to handle multiple setup packets (up to 3) */
++ dwc_write_reg32(&dev_if->out_ep_regs[0]->doepdma,
++ _pcd->setup_pkt_dma_handle);
++ // EP enable
++ doepctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl);
++ doepctl.b.epena = 1;
++
++ doepctl.d32 = 0x80008000;
++ dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl,
++ doepctl.d32);
++ }
++#ifdef VERBOSE
++ DWC_DEBUGPL(DBG_PCDV,"doepctl0=%0x\n",
++ dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl));
++ DWC_DEBUGPL(DBG_PCDV,"diepctl0=%0x\n",
++ dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl));
++#endif
++
++}
++
++
++/**
++ * This interrupt occurs when a USB Reset is detected. When the USB
++ * Reset Interrupt occurs the device state is set to DEFAULT and the
++ * EP0 state is set to IDLE.
++ * -# Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1)
++ * -# Unmask the following interrupt bits
++ * - DAINTMSK.INEP0 = 1 (Control 0 IN endpoint)
++ * - DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint)
++ * - DOEPMSK.SETUP = 1
++ * - DOEPMSK.XferCompl = 1
++ * - DIEPMSK.XferCompl = 1
++ * - DIEPMSK.TimeOut = 1
++ * -# Program the following fields in the endpoint specific registers
++ * for Control OUT EP 0, in order to receive a setup packet
++ * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
++ * setup packets)
++ * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
++ * to back setup packets)
++ * - In DMA mode, DOEPDMA0 Register with a memory address to
++ * store any setup packets received
++ * At this point, all the required initialization, except for enabling
++ * the control 0 OUT endpoint is done, for receiving SETUP packets.
++ */
++int32_t dwc_otg_pcd_handle_usb_reset_intr( dwc_otg_pcd_t * _pcd)
++{
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
++ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++ depctl_data_t doepctl = { .d32 = 0};
++ daint_data_t daintmsk = { .d32 = 0};
++ doepmsk_data_t doepmsk = { .d32 = 0};
++ diepmsk_data_t diepmsk = { .d32 = 0};
++ dcfg_data_t dcfg = { .d32=0 };
++ grstctl_t resetctl = { .d32=0 };
++ dctl_data_t dctl = {.d32=0};
++ int i = 0;
++ gintsts_data_t gintsts;
++
++ DWC_PRINT("USB RESET\n");
++
++ /* reset the HNP settings */
++ dwc_otg_pcd_update_otg( _pcd, 1);
++
++ /* Clear the Remote Wakeup Signalling */
++ dctl.b.rmtwkupsig = 1;
++ dwc_modify_reg32( &core_if->dev_if->dev_global_regs->dctl,
++ dctl.d32, 0 );
++
++ /* Set NAK for all OUT EPs */
++ doepctl.b.snak = 1;
++ for (i=0; i <= dev_if->num_out_eps; i++)
++ {
++ dwc_write_reg32( &dev_if->out_ep_regs[i]->doepctl,
++ doepctl.d32 );
++ //AlenOh
++ dwc_write_reg32( &dev_if->in_ep_regs[i]->diepctl,
++ doepctl.d32 );
++ }
++
++ //AlenOh
++ /* Flush the FIFOs */
++ dwc_otg_flush_tx_fifo( core_if, 0x10 ); /* all Tx FIFOs */
++ dwc_otg_flush_rx_fifo( core_if );
++
++ /* Flush the Learning Queue */
++ resetctl.b.intknqflsh = 1;
++ dwc_write_reg32( &core_if->core_global_regs->grstctl, resetctl.d32);
++
++ daintmsk.b.inep0 = 1;
++ daintmsk.b.outep0 = 1;
++ dwc_write_reg32( &dev_if->dev_global_regs->daintmsk, daintmsk.d32 );
++
++ doepmsk.b.setup = 1;
++ doepmsk.b.xfercompl = 1;
++ doepmsk.b.ahberr = 1;
++ doepmsk.b.epdisabled = 1;
++ dwc_write_reg32( &dev_if->dev_global_regs->doepmsk, doepmsk.d32 );
++
++ diepmsk.b.xfercompl = 1;
++ diepmsk.b.timeout = 1;
++ diepmsk.b.epdisabled = 1;
++ diepmsk.b.ahberr = 1;
++// diepmsk.b.intknepmis = 1;
++ dwc_write_reg32( &dev_if->dev_global_regs->diepmsk, diepmsk.d32 );
++ /* Reset Device Address */
++ dcfg.d32 = dwc_read_reg32( &dev_if->dev_global_regs->dcfg);
++ dcfg.b.devaddr = 0;
++ dwc_write_reg32( &dev_if->dev_global_regs->dcfg, dcfg.d32);
++
++ /* setup EP0 to receive SETUP packets */
++ ep0_out_start( core_if, _pcd );
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.usbreset = 1;
++ dwc_write_reg32 (&core_if->core_global_regs->gintsts, gintsts.d32);
++
++ return 1;
++}
++
++/**
++ * Get the device speed from the device status register and convert it
++ * to USB speed constant.
++ *
++ * @param _core_if Programming view of DWC_otg controller.
++ */
++static int get_device_speed( dwc_otg_core_if_t *_core_if )
++{
++ dsts_data_t dsts;
++ enum usb_device_speed speed = USB_SPEED_UNKNOWN;
++ dsts.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dsts);
++
++ switch (dsts.b.enumspd)
++ {
++ case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
++ speed = USB_SPEED_HIGH;
++ break;
++ case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
++ case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
++ speed = USB_SPEED_FULL;
++ break;
++
++ case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
++ speed = USB_SPEED_LOW;
++ break;
++ }
++
++ return speed;
++}
++
++/**
++ * Read the device status register and set the device speed in the
++ * data structure.
++ * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
++ */
++int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t *_pcd)
++{
++ dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;
++ gintsts_data_t gintsts;
++ gusbcfg_data_t gusbcfg;
++ dwc_otg_core_global_regs_t *global_regs =
++ GET_CORE_IF(_pcd)->core_global_regs;
++ uint32_t gsnpsid = global_regs->gsnpsid;
++ uint8_t utmi16b, utmi8b;
++ DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n");
++
++ if (gsnpsid >= (uint32_t)0x4f54260a)
++ {
++ utmi16b = 5;
++ utmi8b = 9;
++ }
++ else
++ {
++ utmi16b = 4;
++ utmi8b = 8;
++ }
++ dwc_otg_ep0_activate( GET_CORE_IF(_pcd), &ep0->dwc_ep );
++
++#ifdef DEBUG_EP0
++ print_ep0_state(_pcd);
++#endif
++
++ if (_pcd->ep0state == EP0_DISCONNECT)
++ {
++ _pcd->ep0state = EP0_IDLE;
++ }
++ else if (_pcd->ep0state == EP0_STALL)
++ {
++ _pcd->ep0state = EP0_IDLE;
++ }
++
++ _pcd->ep0state = EP0_IDLE;
++
++ ep0->stopped = 0;
++
++ _pcd->gadget.speed = get_device_speed(GET_CORE_IF(_pcd));
++
++ /* Set USB turnaround time based on device speed and PHY interface. */
++ gusbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
++ if (_pcd->gadget.speed == USB_SPEED_HIGH)
++ {
++ if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_ULPI)
++ {
++ /* ULPI interface */
++ gusbcfg.b.usbtrdtim = 9;
++ }
++ if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_UTMI)
++ {
++/////
++ /* UTMI+ interface */
++ if (GET_CORE_IF(_pcd)->hwcfg4.b.utmi_phy_data_width == 0)
++ {
++ gusbcfg.b.usbtrdtim = utmi8b;
++ }
++ else if (GET_CORE_IF(_pcd)->hwcfg4.b.utmi_phy_data_width == 1)
++ {
++ gusbcfg.b.usbtrdtim = utmi16b;
++ }
++ else if (GET_CORE_IF(_pcd)->core_params->phy_utmi_width == 8)
++ {
++ gusbcfg.b.usbtrdtim = utmi8b;
++ }
++ else
++ {
++ gusbcfg.b.usbtrdtim = utmi16b;
++ }
++ }
++ if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI)
++ {
++ /* UTMI+ OR ULPI interface */
++ if (gusbcfg.b.ulpi_utmi_sel == 1)
++ {
++ /* ULPI interface */
++ gusbcfg.b.usbtrdtim = 9;
++ }
++ else
++ {
++ /* UTMI+ interface */
++ if (GET_CORE_IF(_pcd)->core_params->phy_utmi_width == 16)
++ {
++ gusbcfg.b.usbtrdtim = utmi16b;
++ }
++ else
++ {
++ gusbcfg.b.usbtrdtim = utmi8b;
++ }
++ }
++ }
++ }
++ else
++ {
++ /* Full or low speed */
++ gusbcfg.b.usbtrdtim = 9;
++ }
++ dwc_write_reg32(&global_regs->gusbcfg, gusbcfg.d32);
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.enumdone = 1;
++ dwc_write_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintsts,
++ gintsts.d32 );
++ return 1;
++}
++
++/**
++ * This interrupt indicates that the ISO OUT Packet was dropped due to
++ * Rx FIFO full or Rx Status Queue Full. If this interrupt occurs
++ * read all the data from the Rx FIFO.
++ */
++int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t *_pcd )
++{
++ gintmsk_data_t intr_mask = { .d32 = 0};
++ gintsts_data_t gintsts;
++
++ DWC_PRINT("INTERRUPT Handler not implemented for %s\n",
++ "ISOC Out Dropped");
++
++ intr_mask.b.isooutdrop = 1;
++ dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
++ intr_mask.d32, 0 );
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.isooutdrop = 1;
++ dwc_write_reg32 (&GET_CORE_IF(_pcd)->core_global_regs->gintsts,
++ gintsts.d32);
++
++ return 1;
++}
++
++/**
++ * This interrupt indicates the end of the portion of the micro-frame
++ * for periodic transactions. If there is a periodic transaction for
++ * the next frame, load the packets into the EP periodic Tx FIFO.
++ */
++int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t *_pcd )
++{
++ gintmsk_data_t intr_mask = { .d32 = 0};
++ gintsts_data_t gintsts;
++ DWC_PRINT("INTERRUPT Handler not implemented for %s\n",
++ "EOP");
++
++ intr_mask.b.eopframe = 1;
++ dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
++ intr_mask.d32, 0 );
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.eopframe = 1;
++ dwc_write_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintsts,
++ gintsts.d32);
++
++ return 1;
++}
++
++/**
++ * This interrupt indicates that EP of the packet on the top of the
++ * non-periodic Tx FIFO does not match EP of the IN Token received.
++ *
++ * The "Device IN Token Queue" Registers are read to determine the
++ * order the IN Tokens have been received. The non-periodic Tx FIFO
++ * is flushed, so it can be reloaded in the order seen in the IN Token
++ * Queue.
++ */
++int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_core_if_t *_core_if)
++{
++ gintsts_data_t gintsts;
++ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _core_if);
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.epmismatch = 1;
++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32);
++
++ return 1;
++}
++
++/**
++ * This funcion stalls EP0.
++ */
++static inline void ep0_do_stall( dwc_otg_pcd_t *_pcd, const int err_val )
++{
++ dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;
++ //struct usb_ctrlrequest *ctrl = &_pcd->setup_pkt->req;
++ //DWC_WARN("req %02x.%02x protocol STALL; err %d\n",
++ // ctrl->bRequestType, ctrl->bRequest, err_val);
++
++ ep0->dwc_ep.is_in = 1;
++ dwc_otg_ep_set_stall( _pcd->otg_dev->core_if, &ep0->dwc_ep );
++ _pcd->ep0.stopped = 1;
++ _pcd->ep0state = EP0_IDLE;
++ ep0_out_start( GET_CORE_IF(_pcd), _pcd );
++}
++
++/**
++ * This functions delegates the setup command to the gadget driver.
++ */
++static inline void do_gadget_setup( dwc_otg_pcd_t *_pcd,
++ struct usb_ctrlrequest * _ctrl)
++{
++ int ret = 0;
++ if (_pcd->driver && _pcd->driver->setup)
++ {
++ SPIN_LOCK(&_pcd->lock);
++ ret = _pcd->driver->setup(&_pcd->gadget, _ctrl);
++ SPIN_UNLOCK(&_pcd->lock);
++ if (ret < 0)
++ {
++ ep0_do_stall( _pcd, ret );
++ }
++
++ /** @todo This is a g_file_storage gadget driver specific
++ * workaround: a DELAYED_STATUS result from the fsg_setup
++ * routine will result in the gadget queueing a EP0 IN status
++ * phase for a two-stage control transfer. Exactly the same as
++ * a SET_CONFIGURATION/SET_INTERFACE except that this is a class
++ * specific request. Need a generic way to know when the gadget
++ * driver will queue the status phase. Can we assume when we
++ * call the gadget driver setup() function that it will always
++ * queue and require the following flag? Need to look into
++ * this.
++ */
++ /* if (ret == 256 + 999)
++ {
++ _pcd->request_config = 1;
++ }*/
++ }
++}
++
++/**
++ * This function starts the Zero-Length Packet for the IN status phase
++ * of a 2 stage control transfer.
++ */
++static inline void do_setup_in_status_phase( dwc_otg_pcd_t *_pcd)
++{
++ dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;
++ if (_pcd->ep0state == EP0_STALL)
++ {
++ return;
++ }
++
++ _pcd->ep0state = EP0_STATUS;
++
++ /* Prepare for more SETUP Packets */
++ DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n");
++ ep0->dwc_ep.xfer_len = 0;
++ ep0->dwc_ep.xfer_count = 0;
++ ep0->dwc_ep.is_in = 1;
++ ep0->dwc_ep.dma_addr = _pcd->setup_pkt_dma_handle;
++
++ dwc_otg_ep0_start_transfer( GET_CORE_IF(_pcd), &ep0->dwc_ep );
++
++ /* Prepare for more SETUP Packets */
++ ep0_out_start( GET_CORE_IF(_pcd), _pcd );
++
++}
++
++/**
++ * This function starts the Zero-Length Packet for the OUT status phase
++ * of a 2 stage control transfer.
++ */
++static inline void do_setup_out_status_phase( dwc_otg_pcd_t *_pcd)
++{
++ dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;
++ if (_pcd->ep0state == EP0_STALL)
++ {
++ DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n");
++ return;
++ }
++ _pcd->ep0state = EP0_STATUS;
++
++ /* Prepare for more SETUP Packets */
++ //ep0_out_start( GET_CORE_IF(_pcd), _pcd );
++
++ DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n");
++ ep0->dwc_ep.xfer_len = 0;
++ ep0->dwc_ep.xfer_count = 0;
++ ep0->dwc_ep.is_in = 0;
++ //ep0->dwc_ep.dma_addr = 0xffffffff;
++ ep0->dwc_ep.dma_addr = _pcd->setup_pkt_dma_handle;
++ dwc_otg_ep0_start_transfer( GET_CORE_IF(_pcd), &ep0->dwc_ep );
++
++ /* Prepare for more SETUP Packets */
++ ep0_out_start( GET_CORE_IF(_pcd), _pcd );
++
++}
++
++/**
++ * Clear the EP halt (STALL) and if pending requests start the
++ * transfer.
++ */
++static inline void pcd_clear_halt( dwc_otg_pcd_t *_pcd, dwc_otg_pcd_ep_t *_ep )
++{
++ if (_ep->dwc_ep.stall_clear_flag == 0)
++ dwc_otg_ep_clear_stall( GET_CORE_IF(_pcd), &_ep->dwc_ep );
++
++ /* Reactive the EP */
++ dwc_otg_ep_activate( GET_CORE_IF(_pcd), &_ep->dwc_ep );
++ if (_ep->stopped)
++ {
++ _ep->stopped = 0;
++ /* If there is a request in the EP queue start it */
++
++ /** @todo FIXME: this causes an EP mismatch in DMA mode.
++ * epmismatch not yet implemented. */
++
++ /*
++ * Above fixme is solved by implmenting a tasklet to call the
++ * start_next_request(), outside of interrupt context at some
++ * time after the current time, after a clear-halt setup packet.
++ * Still need to implement ep mismatch in the future if a gadget
++ * ever uses more than one endpoint at once
++ */
++ if (GET_CORE_IF(_pcd)->dma_enable)
++ {
++ _ep->queue_sof = 1;
++ tasklet_schedule (_pcd->start_xfer_tasklet);
++ }
++ else
++ {
++#if 0
++ _ep->queue_sof = 1;
++ DWC_ERROR("tasklet schedule\n");
++ tasklet_schedule (_pcd->start_xfer_tasklet);
++ if (GET_CORE_IF(_pcd)->core_params->opt)
++ {
++ start_next_request( _ep );
++ }
++#endif
++ }
++ }
++ /* Start Control Status Phase */
++ do_setup_in_status_phase( _pcd );
++}
++
++/**
++ * This function is called when the SET_FEATURE TEST_MODE Setup packet
++ * is sent from the host. The Device Control register is written with
++ * the Test Mode bits set to the specified Test Mode. This is done as
++ * a tasklet so that the "Status" phase of the control transfer
++ * completes before transmitting the TEST packets.
++ *
++ * @todo This has not been tested since the tasklet struct was put
++ * into the PCD struct!
++ *
++ */
++static void do_test_mode( unsigned long _data )
++{
++ dctl_data_t dctl;
++ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *)_data;
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++ int test_mode = pcd->test_mode;
++
++
++// DWC_WARN("%s() has not been tested since being rewritten!\n", __func__);
++
++ dctl.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dctl);
++ switch (test_mode)
++ {
++ case 1: // TEST_J
++ dctl.b.tstctl = 1;
++ break;
++
++ case 2: // TEST_K
++ dctl.b.tstctl = 2;
++ break;
++
++ case 3: // TEST_SE0_NAK
++ dctl.b.tstctl = 3;
++ break;
++
++ case 4: // TEST_PACKET
++ dctl.b.tstctl = 4;
++ break;
++
++ case 5: // TEST_FORCE_ENABLE
++ dctl.b.tstctl = 5;
++ break;
++ }
++ dwc_write_reg32(&core_if->dev_if->dev_global_regs->dctl,
++ dctl.d32);
++}
++
++
++/**
++ * This function process the SET_FEATURE Setup Commands.
++ */
++static inline void do_set_feature( dwc_otg_pcd_t *_pcd )
++{
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
++ dwc_otg_core_global_regs_t *global_regs =
++ core_if->core_global_regs;
++ struct usb_ctrlrequest ctrl = _pcd->setup_pkt->req;
++ dwc_otg_pcd_ep_t *ep = 0;
++ int32_t otg_cap_param = core_if->core_params->otg_cap;
++ gotgctl_data_t gotgctl = { .d32 = 0 };
++
++ DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
++ ctrl.bRequestType, ctrl.bRequest,
++ ctrl.wValue, ctrl.wIndex, ctrl.wLength);
++ DWC_DEBUGPL(DBG_PCD,"otg_cap=%d\n", otg_cap_param);
++
++
++ switch (ctrl.bRequestType & USB_RECIP_MASK)
++ {
++ case USB_RECIP_DEVICE:
++ switch (ctrl.wValue)
++ {
++ case USB_DEVICE_REMOTE_WAKEUP:
++ _pcd->remote_wakeup_enable = 1;
++ break;
++
++ case USB_DEVICE_TEST_MODE:
++ /* Setup the Test Mode tasklet to do the Test
++ * Packet generation after the SETUP Status
++ * phase has completed. */
++
++ /** @todo This has not been tested since the
++ * tasklet struct was put into the PCD
++ * struct! */
++ _pcd->test_mode_tasklet.next = 0;
++ _pcd->test_mode_tasklet.state = 0;
++ atomic_set( &_pcd->test_mode_tasklet.count, 0);
++ _pcd->test_mode_tasklet.func = do_test_mode;
++ _pcd->test_mode_tasklet.data = (unsigned long)_pcd;
++ _pcd->test_mode = ctrl.wIndex >> 8;
++ tasklet_schedule(&_pcd->test_mode_tasklet);
++ break;
++
++ case USB_DEVICE_B_HNP_ENABLE:
++ DWC_DEBUGPL(DBG_PCDV, "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
++
++ /* dev may initiate HNP */
++ if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
++ {
++ _pcd->b_hnp_enable = 1;
++ dwc_otg_pcd_update_otg( _pcd, 0 );
++ DWC_DEBUGPL(DBG_PCD, "Request B HNP\n");
++ /**@todo Is the gotgctl.devhnpen cleared
++ * by a USB Reset? */
++ gotgctl.b.devhnpen = 1;
++ gotgctl.b.hnpreq = 1;
++ dwc_write_reg32( &global_regs->gotgctl, gotgctl.d32 );
++ }
++ else
++ {
++ ep0_do_stall( _pcd, -EOPNOTSUPP);
++ }
++ break;
++
++ case USB_DEVICE_A_HNP_SUPPORT:
++ /* RH port supports HNP */
++ DWC_DEBUGPL(DBG_PCDV, "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");
++ if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
++ {
++ _pcd->a_hnp_support = 1;
++ dwc_otg_pcd_update_otg( _pcd, 0 );
++ }
++ else
++ {
++ ep0_do_stall( _pcd, -EOPNOTSUPP);
++ }
++ break;
++
++ case USB_DEVICE_A_ALT_HNP_SUPPORT:
++ /* other RH port does */
++ DWC_DEBUGPL(DBG_PCDV, "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
++ if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)
++ {
++ _pcd->a_alt_hnp_support = 1;
++ dwc_otg_pcd_update_otg( _pcd, 0 );
++ }
++ else
++ {
++ ep0_do_stall( _pcd, -EOPNOTSUPP);
++ }
++ break;
++
++ default:
++ ep0_do_stall(_pcd, -EOPNOTSUPP);
++ return;
++ }
++ do_setup_in_status_phase( _pcd );
++ break;
++
++ case USB_RECIP_INTERFACE:
++ do_gadget_setup(_pcd, &ctrl );
++ break;
++
++ case USB_RECIP_ENDPOINT:
++ if (ctrl.wValue == USB_ENDPOINT_HALT)
++ {
++ ep = get_ep_by_addr(_pcd, ctrl.wIndex);
++ if (ep == 0)
++ {
++ ep0_do_stall(_pcd, -EOPNOTSUPP);
++ return;
++ }
++ ep->stopped = 1;
++ dwc_otg_ep_set_stall( core_if, &ep->dwc_ep );
++ }
++ do_setup_in_status_phase( _pcd );
++ break;
++ }
++}
++
++/**
++ * This function process the CLEAR_FEATURE Setup Commands.
++ */
++static inline void do_clear_feature( dwc_otg_pcd_t *_pcd )
++{
++ struct usb_ctrlrequest ctrl = _pcd->setup_pkt->req;
++ dwc_otg_pcd_ep_t *ep = 0;
++
++
++ DWC_DEBUGPL(DBG_PCD,
++ "CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
++ ctrl.bRequestType, ctrl.bRequest,
++ ctrl.wValue, ctrl.wIndex, ctrl.wLength);
++
++ switch (ctrl.bRequestType & USB_RECIP_MASK)
++ {
++ case USB_RECIP_DEVICE:
++ switch (ctrl.wValue)
++ {
++ case USB_DEVICE_REMOTE_WAKEUP:
++ _pcd->remote_wakeup_enable = 0;
++ break;
++
++ case USB_DEVICE_TEST_MODE:
++ /** @todo Add CLEAR_FEATURE for TEST modes. */
++ break;
++ }
++ do_setup_in_status_phase( _pcd );
++ break;
++
++ case USB_RECIP_ENDPOINT:
++ ep = get_ep_by_addr(_pcd, ctrl.wIndex);
++ if (ep == 0)
++ {
++ ep0_do_stall(_pcd, -EOPNOTSUPP);
++ return;
++ }
++
++ pcd_clear_halt(_pcd, ep );
++
++ break;
++ }
++}
++
++/**
++ * This function processes SETUP commands. In Linux, the USB Command
++ * processing is done in two places - the first being the PCD and the
++ * second in the Gadget Driver (for example, the File-Backed Storage
++ * Gadget Driver).
++ *
++ * <table>
++ * <tr><td>Command </td><td>Driver </td><td>Description</td></tr>
++ *
++ * <tr><td>GET_STATUS </td><td>PCD </td><td>Command is processed as
++ * defined in chapter 9 of the USB 2.0 Specification chapter 9
++ * </td></tr>
++ *
++ * <tr><td>CLEAR_FEATURE </td><td>PCD </td><td>The Device and Endpoint
++ * requests are the ENDPOINT_HALT feature is procesed, all others the
++ * interface requests are ignored.</td></tr>
++ *
++ * <tr><td>SET_FEATURE </td><td>PCD </td><td>The Device and Endpoint
++ * requests are processed by the PCD. Interface requests are passed
++ * to the Gadget Driver.</td></tr>
++ *
++ * <tr><td>SET_ADDRESS </td><td>PCD </td><td>Program the DCFG reg,
++ * with device address received </td></tr>
++ *
++ * <tr><td>GET_DESCRIPTOR </td><td>Gadget Driver </td><td>Return the
++ * requested descriptor</td></tr>
++ *
++ * <tr><td>SET_DESCRIPTOR </td><td>Gadget Driver </td><td>Optional -
++ * not implemented by any of the existing Gadget Drivers.</td></tr>
++ *
++ * <tr><td>SET_CONFIGURATION </td><td>Gadget Driver </td><td>Disable
++ * all EPs and enable EPs for new configuration.</td></tr>
++ *
++ * <tr><td>GET_CONFIGURATION </td><td>Gadget Driver </td><td>Return
++ * the current configuration</td></tr>
++ *
++ * <tr><td>SET_INTERFACE </td><td>Gadget Driver </td><td>Disable all
++ * EPs and enable EPs for new configuration.</td></tr>
++ *
++ * <tr><td>GET_INTERFACE </td><td>Gadget Driver </td><td>Return the
++ * current interface.</td></tr>
++ *
++ * <tr><td>SYNC_FRAME </td><td>PCD </td><td>Display debug
++ * message.</td></tr>
++ * </table>
++ *
++ * When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are
++ * processed by pcd_setup. Calling the Function Driver's setup function from
++ * pcd_setup processes the gadget SETUP commands.
++ */
++static inline void pcd_setup( dwc_otg_pcd_t *_pcd )
++{
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
++ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++ struct usb_ctrlrequest ctrl = _pcd->setup_pkt->req;
++ dwc_otg_pcd_ep_t *ep;
++ dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;
++ uint16_t *status = _pcd->status_buf;
++
++ deptsiz0_data_t doeptsize0 = { .d32 = 0};
++
++#ifdef DEBUG_EP0
++ DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n",
++ ctrl.bRequestType, ctrl.bRequest,
++ ctrl.wValue, ctrl.wIndex, ctrl.wLength);
++#endif
++
++ doeptsize0.d32 = dwc_read_reg32( &dev_if->out_ep_regs[0]->doeptsiz );
++
++ /** @todo handle > 1 setup packet , assert error for now */
++ if (core_if->dma_enable && (doeptsize0.b.supcnt < 2))
++ {
++ DWC_ERROR ("\n\n----------- CANNOT handle > 1 setup packet in DMA mode\n\n");
++ }
++
++ /* Clean up the request queue */
++ request_nuke( ep0 );
++ ep0->stopped = 0;
++
++ if (ctrl.bRequestType & USB_DIR_IN)
++ {
++ ep0->dwc_ep.is_in = 1;
++ _pcd->ep0state = EP0_IN_DATA_PHASE;
++ }
++ else
++ {
++ ep0->dwc_ep.is_in = 0;
++ _pcd->ep0state = EP0_OUT_DATA_PHASE;
++ }
++
++ if ( ctrl.wLength == 0 ) //AlenOh
++ {
++ ep0->dwc_ep.is_in = 1;
++ _pcd->ep0state = EP0_STATUS;
++ }
++
++ if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
++ {
++ /* handle non-standard (class/vendor) requests in the gadget driver */
++ do_gadget_setup(_pcd, &ctrl );
++ return;
++ }
++
++ /** @todo NGS: Handle bad setup packet? */
++
++ switch (ctrl.bRequest)
++ {
++ case USB_REQ_GET_STATUS:
++#ifdef DEBUG_EP0
++ DWC_DEBUGPL(DBG_PCD,
++ "GET_STATUS %02x.%02x v%04x i%04x l%04x\n",
++ ctrl.bRequestType, ctrl.bRequest,
++ ctrl.wValue, ctrl.wIndex, ctrl.wLength);
++#endif
++
++ switch (ctrl.bRequestType & USB_RECIP_MASK)
++ {
++ case USB_RECIP_DEVICE:
++ *status = 0x1; /* Self powered */
++ *status |= _pcd->remote_wakeup_enable << 1;
++ break;
++
++ case USB_RECIP_INTERFACE:
++ *status = 0;
++ break;
++
++ case USB_RECIP_ENDPOINT:
++ ep = get_ep_by_addr(_pcd, ctrl.wIndex);
++ if ( ep == 0 || ctrl.wLength > 2)
++ {
++ ep0_do_stall(_pcd, -EOPNOTSUPP);
++ return;
++ }
++ /** @todo check for EP stall */
++ *status = ep->stopped;
++ break;
++ }
++ _pcd->ep0_pending = 1;
++
++ ep0->dwc_ep.start_xfer_buff = (uint8_t *)status;
++ ep0->dwc_ep.xfer_buff = (uint8_t *)status;
++ ep0->dwc_ep.dma_addr = _pcd->status_buf_dma_handle;
++ ep0->dwc_ep.xfer_len = 2;
++ ep0->dwc_ep.xfer_count = 0;
++ ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
++ dwc_otg_ep0_start_transfer( GET_CORE_IF(_pcd), &ep0->dwc_ep );
++ break;
++
++ case USB_REQ_CLEAR_FEATURE:
++ do_clear_feature( _pcd );
++ break;
++
++ case USB_REQ_SET_FEATURE:
++ do_set_feature( _pcd );
++ break;
++
++ case USB_REQ_SET_ADDRESS:
++ if (ctrl.bRequestType == USB_RECIP_DEVICE)
++ {
++ dcfg_data_t dcfg = {.d32=0};
++
++#ifdef DEBUG_EP0
++ DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue);
++#endif
++ dcfg.b.devaddr = ctrl.wValue;
++ dwc_modify_reg32( &dev_if->dev_global_regs->dcfg,
++ 0, dcfg.d32);
++ do_setup_in_status_phase( _pcd );
++ return;
++ }
++ break;
++
++ case USB_REQ_SET_INTERFACE:
++ case USB_REQ_SET_CONFIGURATION:
++ //_pcd->request_config = 1; /* Configuration changed */
++ do_gadget_setup(_pcd, &ctrl );
++ break;
++
++ case USB_REQ_SYNCH_FRAME:
++ do_gadget_setup(_pcd, &ctrl );
++ break;
++
++ default:
++ /* Call the Gadget Driver's setup functions */
++ do_gadget_setup(_pcd, &ctrl );
++ break;
++ }
++}
++
++/**
++ * This function completes the ep0 control transfer.
++ */
++static int32_t ep0_complete_request( dwc_otg_pcd_ep_t *_ep )
++{
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_ep->pcd);
++ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++ dwc_otg_dev_in_ep_regs_t *in_ep_regs =
++ dev_if->in_ep_regs[_ep->dwc_ep.num];
++#ifdef DEBUG_EP0
++ dwc_otg_dev_out_ep_regs_t *out_ep_regs =
++ dev_if->out_ep_regs[_ep->dwc_ep.num];
++#endif
++ deptsiz0_data_t deptsiz;
++ dwc_otg_pcd_request_t *req;
++ int is_last = 0;
++ dwc_otg_pcd_t *pcd = _ep->pcd;
++
++ //DWC_DEBUGPL(DBG_PCDV, "%s() %s\n", __func__, _ep->ep.name);
++
++ if (pcd->ep0_pending && list_empty(&_ep->queue))
++ {
++ if (_ep->dwc_ep.is_in)
++ {
++#ifdef DEBUG_EP0
++ DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n");
++#endif
++ do_setup_out_status_phase(pcd);
++ }
++ else
++ {
++#ifdef DEBUG_EP0
++ DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n");
++#endif
++ do_setup_in_status_phase(pcd);
++ }
++ pcd->ep0_pending = 0;
++ pcd->ep0state = EP0_STATUS;
++ return 1;
++ }
++
++ if (list_empty(&_ep->queue))
++ {
++ return 0;
++ }
++ req = list_entry(_ep->queue.next, dwc_otg_pcd_request_t, queue);
++
++
++ if (pcd->ep0state == EP0_STATUS)
++ {
++ is_last = 1;
++ }
++ else if ( req->req.zero && (_ep->dwc_ep.xfer_count%_ep->dwc_ep.maxpacket)==0 )
++ {
++ req->req.actual = _ep->dwc_ep.xfer_count;
++ //do_setup_in_status_phase (pcd);
++ req->req.zero = 0;
++ _ep->dwc_ep.xfer_len = 0;
++ _ep->dwc_ep.xfer_count = 0;
++ _ep->dwc_ep.sent_zlp = 1;
++ dwc_otg_ep0_start_transfer( GET_CORE_IF(pcd), &_ep->dwc_ep );
++ return 1;
++ }
++ else if (_ep->dwc_ep.is_in)
++ {
++ deptsiz.d32 = dwc_read_reg32( &in_ep_regs->dieptsiz);
++#ifdef DEBUG_EP0
++ DWC_DEBUGPL(DBG_PCDV, "%s len=%d xfersize=%d pktcnt=%d\n",
++ _ep->ep.name, _ep->dwc_ep.xfer_len,
++ deptsiz.b.xfersize, deptsiz.b.pktcnt);
++#endif
++ if (deptsiz.b.xfersize == 0)
++ {
++ req->req.actual = _ep->dwc_ep.xfer_count;
++ /* Is a Zero Len Packet needed? */
++ //if (req->req.zero) {
++#ifdef DEBUG_EP0
++ DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n");
++#endif
++ do_setup_out_status_phase(pcd);
++ }
++ }
++ else
++ {
++ /* ep0-OUT */
++#ifdef DEBUG_EP0
++ deptsiz.d32 = dwc_read_reg32( &out_ep_regs->doeptsiz);
++ DWC_DEBUGPL(DBG_PCDV, "%s len=%d xsize=%d pktcnt=%d\n",
++ _ep->ep.name, _ep->dwc_ep.xfer_len,
++ deptsiz.b.xfersize,
++ deptsiz.b.pktcnt);
++#endif
++ req->req.actual = _ep->dwc_ep.xfer_count;
++
++ /* Is a Zero Len Packet needed? */
++ //if (req->req.zero) {
++#ifdef DEBUG_EP0
++ DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n");
++#endif
++ do_setup_in_status_phase(pcd);
++ }
++
++ /* Complete the request */
++ if (is_last)
++ {
++ request_done(_ep, req, 0);
++ _ep->dwc_ep.start_xfer_buff = 0;
++ _ep->dwc_ep.xfer_buff = 0;
++ _ep->dwc_ep.xfer_len = 0;
++ return 1;
++ }
++ return 0;
++}
++
++/**
++ * This function completes the request for the EP. If there are
++ * additional requests for the EP in the queue they will be started.
++ */
++static void complete_ep( dwc_otg_pcd_ep_t *_ep )
++{
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_ep->pcd);
++ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++ dwc_otg_dev_in_ep_regs_t *in_ep_regs =
++ dev_if->in_ep_regs[_ep->dwc_ep.num];
++ deptsiz_data_t deptsiz;
++ dwc_otg_pcd_request_t *req = 0;
++ int is_last = 0;
++
++ DWC_DEBUGPL(DBG_PCDV,"%s() %s-%s \n", __func__, _ep->ep.name,
++ (_ep->dwc_ep.is_in?"IN":"OUT"));
++
++ /* Get any pending requests */
++ if (!list_empty(&_ep->queue))
++ {
++ req = list_entry(_ep->queue.next, dwc_otg_pcd_request_t, queue);
++ }
++ else // AlenOh
++ {
++ printk("no pending request\n");
++ return;
++ }
++ DWC_DEBUGPL(DBG_PCD, "Requests %d\n",_ep->pcd->request_pending);
++
++ if (_ep->dwc_ep.is_in)
++ {
++ deptsiz.d32 = dwc_read_reg32( &in_ep_regs->dieptsiz);
++ if (core_if->dma_enable)
++ {
++ if (deptsiz.b.xfersize == 0)
++ _ep->dwc_ep.xfer_count = _ep->dwc_ep.xfer_len;
++ }
++
++ DWC_DEBUGPL(DBG_PCDV, "%s len=%d xfersize=%d pktcnt=%d\n",
++ _ep->ep.name, _ep->dwc_ep.xfer_len,
++ deptsiz.b.xfersize, deptsiz.b.pktcnt);
++
++ if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0 &&
++ _ep->dwc_ep.xfer_count == _ep->dwc_ep.xfer_len)
++ {
++ is_last = 1;
++ }
++ else
++ {
++ DWC_WARN("Incomplete transfer (%s-%s [siz=%d pkt=%d])\n",
++ _ep->ep.name, (_ep->dwc_ep.is_in?"IN":"OUT"),
++ deptsiz.b.xfersize, deptsiz.b.pktcnt);
++ }
++ }
++ else
++ {
++ dwc_otg_dev_out_ep_regs_t *out_ep_regs =
++ dev_if->out_ep_regs[_ep->dwc_ep.num];
++ deptsiz.d32 = 0;
++ deptsiz.d32 = dwc_read_reg32( &out_ep_regs->doeptsiz);
++
++#ifdef DEBUG
++
++ DWC_DEBUGPL(DBG_PCDV, "addr %p, %s len=%d cnt=%d xsize=%d pktcnt=%d\n",
++ &out_ep_regs->doeptsiz, _ep->ep.name, _ep->dwc_ep.xfer_len,
++ _ep->dwc_ep.xfer_count,
++ deptsiz.b.xfersize,
++ deptsiz.b.pktcnt);
++#endif
++ is_last = 1;
++ }
++
++ /* Complete the request */
++ if (is_last)
++ {
++
++ if (core_if->dma_enable)
++ {
++ req->req.actual = _ep->dwc_ep.xfer_len - deptsiz.b.xfersize;
++ }
++ else
++ {
++ req->req.actual = _ep->dwc_ep.xfer_count;
++ }
++
++ request_done(_ep, req, 0);
++
++ _ep->dwc_ep.start_xfer_buff = 0;
++ _ep->dwc_ep.xfer_buff = 0;
++ _ep->dwc_ep.xfer_len = 0;
++
++ /* If there is a request in the queue start it.*/
++ start_next_request( _ep );
++ }
++}
++
++/**
++ * This function handles EP0 Control transfers.
++ *
++ * The state of the control tranfers are tracked in
++ * <code>ep0state</code>.
++ */
++static void handle_ep0( dwc_otg_pcd_t *_pcd )
++{
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
++ dwc_otg_pcd_ep_t *ep0 = &_pcd->ep0;
++
++#ifdef DEBUG_EP0
++ DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
++ print_ep0_state(_pcd);
++#endif
++
++ switch (_pcd->ep0state)
++ {
++ case EP0_DISCONNECT:
++ break;
++
++ case EP0_IDLE:
++ //_pcd->request_config = 0;
++
++ pcd_setup( _pcd );
++ break;
++
++ case EP0_IN_DATA_PHASE:
++#ifdef DEBUG_EP0
++ DWC_DEBUGPL(DBG_PCD, "DATA_IN EP%d-%s: type=%d, mps=%d\n",
++ ep0->dwc_ep.num, (ep0->dwc_ep.is_in ?"IN":"OUT"),
++ ep0->dwc_ep.type, ep0->dwc_ep.maxpacket );
++#endif
++ if (core_if->dma_enable)
++ {
++ /*
++ * For EP0 we can only program 1 packet at a time so we
++ * need to do the make calculations after each complete.
++ * Call write_packet to make the calculations, as in
++ * slave mode, and use those values to determine if we
++ * can complete.
++ */
++ dwc_otg_ep_write_packet (core_if, &ep0->dwc_ep, 1);
++ }
++ if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len)
++ {
++ dwc_otg_ep0_continue_transfer ( GET_CORE_IF(_pcd), &ep0->dwc_ep );
++ DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
++ }
++ else
++ {
++ ep0_complete_request( ep0 );
++ DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
++ }
++ break;
++ case EP0_OUT_DATA_PHASE:
++ //#ifdef DEBUG_EP0
++ DWC_DEBUGPL(DBG_PCD, "DATA_OUT EP%d-%s: type=%d, mps=%d\n",
++ ep0->dwc_ep.num, (ep0->dwc_ep.is_in ?"IN":"OUT"),
++ ep0->dwc_ep.type, ep0->dwc_ep.maxpacket );
++ //#endif
++ ep0_complete_request( ep0 );
++ break;
++
++
++ case EP0_STATUS:
++ DWC_DEBUGPL(DBG_PCD, "CASE: EP0_STATUS\n");
++ ep0_complete_request( ep0 );
++ _pcd->ep0state = EP0_IDLE;
++ ep0->stopped = 1;
++ ep0->dwc_ep.is_in = 0; /* OUT for next SETUP */
++
++ /* Prepare for more SETUP Packets */
++ if (core_if->dma_enable)
++ {
++ ep0_out_start( core_if, _pcd );
++ }
++
++ if (!GET_CORE_IF(_pcd)->dma_enable)
++ {
++ int i;
++
++ depctl_data_t diepctl;
++ diepctl.d32 = dwc_read_reg32( &core_if->dev_if->in_ep_regs[0]->diepctl);
++
++ if (_pcd->ep0.queue_sof)
++ {
++ _pcd->ep0.queue_sof = 0;
++ start_next_request (&_pcd->ep0);
++ }
++
++ diepctl.d32 = dwc_read_reg32( &core_if->dev_if->in_ep_regs[0]->diepctl);
++
++ if (_pcd->ep0.queue_sof)
++ {
++ _pcd->ep0.queue_sof = 0;
++ start_next_request (&_pcd->ep0);
++ }
++ for (i=0; i < core_if->dev_if->num_in_eps; i++)
++ {
++ diepctl.d32 = dwc_read_reg32( &core_if->dev_if->in_ep_regs[i+1]->diepctl);
++
++ if (_pcd->in_ep[i].queue_sof)
++ {
++ _pcd->in_ep[i].queue_sof = 0;
++ start_next_request (&_pcd->in_ep[i]);
++ }
++ }
++ }
++ break;
++
++ case EP0_STALL:
++ DWC_ERROR("EP0 STALLed, should not get here pcd_setup()\n");
++ break;
++ }
++#ifdef DEBUG_EP0
++ print_ep0_state(_pcd);
++#endif
++}
++
++/**
++ * Restart transfer
++ */
++static void restart_transfer( dwc_otg_pcd_t *_pcd, const uint32_t _epnum)
++{
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
++ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++ deptsiz_data_t dieptsiz = {.d32=0};
++ //depctl_data_t diepctl = {.d32=0};
++ dwc_otg_pcd_ep_t *ep;
++
++ dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[_epnum]->dieptsiz);
++
++ ep = get_in_ep(_pcd, _epnum);
++ /*
++ if(_epnum != 0)
++ ep = &_pcd->in_ep[ _epnum - 1];
++ else
++ ep = &_pcd->ep0;
++ */
++ DWC_DEBUGPL(DBG_PCD,"xfer_buff=%p xfer_count=%0x xfer_len=%0x"
++ " stopped=%d\n", ep->dwc_ep.xfer_buff,
++ ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len ,
++ ep->stopped);
++ /*
++ * If xfersize is 0 and pktcnt in not 0, resend the last packet.
++ */
++ if ( dieptsiz.b.pktcnt && dieptsiz.b.xfersize == 0 &&
++ ep->dwc_ep.start_xfer_buff != 0)
++ {
++ if ( ep->dwc_ep.xfer_len <= ep->dwc_ep.maxpacket )
++ {
++ ep->dwc_ep.xfer_count = 0;
++ ep->dwc_ep.xfer_buff = ep->dwc_ep.start_xfer_buff;
++ }
++ else
++ {
++ ep->dwc_ep.xfer_count -= ep->dwc_ep.maxpacket;
++ /* convert packet size to dwords. */
++ ep->dwc_ep.xfer_buff -= ep->dwc_ep.maxpacket;
++ }
++ ep->stopped = 0;
++ DWC_DEBUGPL(DBG_PCD,"xfer_buff=%p xfer_count=%0x "
++ "xfer_len=%0x stopped=%d\n",
++ ep->dwc_ep.xfer_buff,
++ ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len ,
++ ep->stopped
++ );
++ if (_epnum == 0)
++ {
++ dwc_otg_ep0_start_transfer(core_if, &ep->dwc_ep);
++ }
++ else
++ {
++ dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
++ }
++ }
++}
++
++
++/**
++ * handle the IN EP disable interrupt.
++ */
++static inline void handle_in_ep_disable_intr(dwc_otg_pcd_t *_pcd,
++ const uint32_t _epnum)
++{
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
++ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++ deptsiz_data_t dieptsiz = {.d32=0};
++ dctl_data_t dctl = {.d32=0};
++ dwc_otg_pcd_ep_t *ep;
++ dwc_ep_t *dwc_ep;
++
++ ep = get_in_ep(_pcd, _epnum);
++ dwc_ep = &ep->dwc_ep;
++ /*
++ if(_epnum != 0)
++ {
++ ep = &_pcd->in_ep[ _epnum - 1];
++ dwc_ep = &_pcd->in_ep[ _epnum - 1].dwc_ep;
++ }
++ else
++ {
++ ep = &_pcd->ep0;
++ dwc_ep = &_pcd->ep0.dwc_ep;
++ }
++ */
++ DWC_DEBUGPL(DBG_PCD,"diepctl%d=%0x\n", _epnum,
++ dwc_read_reg32(&dev_if->in_ep_regs[_epnum]->diepctl));
++ dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[_epnum]->dieptsiz);
++
++ DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
++ dieptsiz.b.pktcnt,
++ dieptsiz.b.xfersize );
++
++ if (ep->stopped)
++ {
++ /* Flush the Tx FIFO */
++ /** @todo NGS: This is not the correct FIFO */
++ if (dwc_ep->type == USB_ENDPOINT_XFER_ISOC) {
++ dwc_otg_flush_tx_fifo( core_if, _epnum );
++ }
++ else
++ dwc_otg_flush_tx_fifo( core_if, _epnum );
++ /* Clear the Global IN NP NAK */
++ dctl.d32 = 0;
++ dctl.b.cgnpinnak = 1;
++ dwc_modify_reg32(&dev_if->dev_global_regs->dctl,
++ dctl.d32, 0);
++ /* Restart the transaction */
++ if (dieptsiz.b.pktcnt != 0 ||
++ dieptsiz.b.xfersize != 0)
++ {
++ restart_transfer( _pcd, _epnum );
++ }
++ }
++ else
++ {
++ /* Restart the transaction */
++ if (dieptsiz.b.pktcnt != 0 ||
++ dieptsiz.b.xfersize != 0)
++ {
++ restart_transfer( _pcd, _epnum );
++ }
++ DWC_DEBUGPL(DBG_ANY, "STOPPED!!!\n");
++ }
++}
++
++/**
++ * Handler for the IN EP timeout handshake interrupt.
++ */
++static inline void handle_in_ep_timeout_intr(dwc_otg_pcd_t *_pcd,
++ const uint32_t _epnum)
++{
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
++ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++
++#ifdef DEBUG
++ deptsiz_data_t dieptsiz = {.d32=0};
++ uint32_t epnum = 0;
++#endif
++ dctl_data_t dctl = {.d32=0};
++ dwc_otg_pcd_ep_t *ep;
++
++ gintmsk_data_t intr_mask = {.d32 = 0};
++
++ ep = get_in_ep(_pcd, _epnum);
++ /*
++ if(_epnum != 0)
++ ep = &_pcd->in_ep[ _epnum - 1];
++ else
++ ep = &_pcd->ep0;
++ */
++
++ /* Disable the NP Tx Fifo Empty Interrrupt */
++ //if (!core_if->dma_enable)
++ //{
++ // intr_mask.b.nptxfempty = 1;
++ // dwc_modify_reg32( &core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
++ //}
++ /** @todo NGS Check EP type.
++ * Implement for Periodic EPs */
++ /*
++ * Non-periodic EP
++ */
++ /* Enable the Global IN NAK Effective Interrupt */
++ intr_mask.b.ginnakeff = 1;
++ dwc_modify_reg32( &core_if->core_global_regs->gintmsk,
++ 0, intr_mask.d32);
++
++ /* Set Global IN NAK */
++ dctl.b.sgnpinnak = 1;
++ dwc_modify_reg32(&dev_if->dev_global_regs->dctl,
++ dctl.d32, dctl.d32);
++
++ ep->stopped = 1;
++
++#ifdef DEBUG
++ dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dieptsiz);
++ DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
++ dieptsiz.b.pktcnt,
++ dieptsiz.b.xfersize );
++#endif
++
++#ifdef DISABLE_PERIODIC_EP
++ /*
++ * Set the NAK bit for this EP to
++ * start the disable process.
++ */
++ diepctl.d32 = 0;
++ diepctl.b.snak = 1;
++ dwc_modify_reg32(&dev_if->in_ep_regs[epnum]->diepctl, diepctl.d32, diepctl.d32);
++ ep->disabling = 1;
++ ep->stopped = 1;
++#endif
++}
++
++
++/**
++ * This interrupt indicates that an IN EP has a pending Interrupt.
++ * The sequence for handling the IN EP interrupt is shown below:
++ * -# Read the Device All Endpoint Interrupt register
++ * -# Repeat the following for each IN EP interrupt bit set (from
++ * LSB to MSB).
++ * -# Read the Device Endpoint Interrupt (DIEPINTn) register
++ * -# If "Transfer Complete" call the request complete function
++ * -# If "Endpoint Disabled" complete the EP disable procedure.
++ * -# If "AHB Error Interrupt" log error
++ * -# If "Time-out Handshake" log error
++ * -# If "IN Token Received when TxFIFO Empty" write packet to Tx
++ * FIFO.
++ * -# If "IN Token EP Mismatch" (disable, this is handled by EP
++ * Mismatch Interrupt)
++ */
++static int32_t dwc_otg_pcd_handle_in_ep_intr(dwc_otg_pcd_t *_pcd)
++{
++#define CLEAR_IN_EP_INTR(__core_if,__epnum,__intr) \
++do { \
++ diepint_data_t diepint = {.d32=0}; \
++ diepint.b.__intr = 1; \
++ dwc_write_reg32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \
++ diepint.d32); \
++} while (0)
++
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
++ dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++ diepint_data_t diepint = {.d32=0};
++ depctl_data_t diepctl = {.d32=0};
++ uint32_t ep_intr;
++ uint32_t epnum = 0;
++ dwc_otg_pcd_ep_t *ep;
++ dwc_ep_t *dwc_ep;
++ uint32_t _empty_msk, _diepctl;
++ //gintmsk_data_t intr_mask = {.d32 = 0};
++
++
++ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
++
++ /* Read in the device interrupt bits */
++ ep_intr = dwc_otg_read_dev_all_in_ep_intr( core_if );
++
++ /* Service the Device IN interrupts for each endpoint */
++ while ( ep_intr )
++ {
++ if (ep_intr&0x1)
++ {
++ /* Get EP pointer */
++ ep = get_in_ep(_pcd, epnum);
++ dwc_ep = &ep->dwc_ep;
++
++ _diepctl = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->diepctl);
++ _empty_msk = dwc_read_reg32(&dev_if->dev_global_regs->dtknqr4_fifoemptymsk);
++
++// DWC_DEBUGPL(DBG_PCDV, "IN EP INTERRUPT - %d\nepmty_msk - %8x diepctl - %8x\n",epnum, _empty_msk, _diepctl);
++
++ DWC_DEBUGPL(DBG_PCD,
++ "EP%d-%s: type=%d, mps=%d\n",
++ dwc_ep->num, (dwc_ep->is_in ?"IN":"OUT"),
++ dwc_ep->type, dwc_ep->maxpacket );
++
++ diepint.d32 = dwc_otg_read_dev_in_ep_intr( core_if, dwc_ep );
++
++ DWC_DEBUGPL(DBG_PCDV, "EP %d Interrupt Register - 0x%x\n", epnum, diepint.d32);
++ /* Transfer complete */
++ if ( diepint.b.xfercompl )
++ {
++ DWC_DEBUGPL(DBG_PCD,"EP%d IN Xfer Complete\n", epnum);
++
++ /* Disable the NP Tx FIFO Empty
++ * Interrrupt */
++ //if(core_if->en_multiple_tx_fifo == 0)
++ //{
++ // intr_mask.b.nptxfempty = 1;
++ // dwc_modify_reg32( &core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
++ //}
++ //else
++ {
++ /* Disable the Tx FIFO Empty Interrupt for this EP */
++ uint32_t fifoemptymsk = 0x1 << dwc_ep->num;
++ dwc_modify_reg32(&core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk, fifoemptymsk, 0);
++ //intr_mask.b.nptxfempty = 1;
++ //dwc_modify_reg32( &core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
++ }
++ /* Clear the bit in DIEPINTn for this interrupt */
++ CLEAR_IN_EP_INTR(core_if,epnum,xfercompl);
++
++ /* Complete the transfer */
++ if (epnum == 0)
++ {
++ handle_ep0( _pcd );
++ }
++ else
++ {
++ complete_ep( ep );
++ }
++ }
++ /* Endpoint disable */
++ if ( diepint.b.epdisabled )
++ {
++ DWC_DEBUGPL(DBG_ANY,"EP%d IN disabled\n", epnum);
++ handle_in_ep_disable_intr( _pcd, epnum );
++
++ /* Clear the bit in DIEPINTn for this interrupt */
++ CLEAR_IN_EP_INTR(core_if,epnum,epdisabled);
++ }
++ /* AHB Error */
++ if ( diepint.b.ahberr )
++ {
++ DWC_DEBUGPL(DBG_ANY,"EP%d IN AHB Error\n", epnum);
++ /* Clear the bit in DIEPINTn for this interrupt */
++ CLEAR_IN_EP_INTR(core_if,epnum,ahberr);
++ }
++ /* TimeOUT Handshake (non-ISOC IN EPs) */
++ if ( diepint.b.timeout )
++ {
++ DWC_DEBUGPL(DBG_ANY,"EP%d IN Time-out\n", epnum);
++ handle_in_ep_timeout_intr( _pcd, epnum );
++
++ CLEAR_IN_EP_INTR(core_if,epnum,timeout);
++ }
++ /** IN Token received with TxF Empty */
++ if (diepint.b.intktxfemp)
++ {
++ DWC_DEBUGPL(DBG_ANY,"EP%d IN TKN TxFifo Empty\n",
++ epnum);
++ if (!ep->stopped && epnum != 0)
++ {
++ diepmsk_data_t diepmsk = { .d32 = 0};
++ diepmsk.b.intktxfemp = 1;
++ dwc_modify_reg32( &dev_if->dev_global_regs->diepmsk, diepmsk.d32, 0 );
++ start_next_request(ep);
++ }
++ CLEAR_IN_EP_INTR(core_if,epnum,intktxfemp);
++ }
++ /** IN Token Received with EP mismatch */
++ if (diepint.b.intknepmis)
++ {
++ DWC_DEBUGPL(DBG_ANY,"EP%d IN TKN EP Mismatch\n", epnum);
++ CLEAR_IN_EP_INTR(core_if,epnum,intknepmis);
++ }
++ /** IN Endpoint NAK Effective */
++ if (diepint.b.inepnakeff)
++ {
++ DWC_DEBUGPL(DBG_ANY,"EP%d IN EP NAK Effective\n", epnum);
++ /* Periodic EP */
++ if (ep->disabling)
++ {
++ diepctl.d32 = 0;
++ diepctl.b.snak = 1;
++ diepctl.b.epdis = 1;
++ dwc_modify_reg32(&dev_if->in_ep_regs[epnum]->diepctl, diepctl.d32, diepctl.d32);
++ }
++ CLEAR_IN_EP_INTR(core_if,epnum,inepnakeff);
++
++ }
++
++ /** IN EP Tx FIFO Empty Intr */
++ if (diepint.b.emptyintr)
++ {
++ DWC_DEBUGPL(DBG_ANY,"EP%d Tx FIFO Empty Intr \n", epnum);
++ if (write_empty_tx_fifo(_pcd, epnum)==0)
++ {
++ //AlenOh
++ /* Disable the NP Tx FIFO Empty
++ * Interrrupt */
++ //if(core_if->en_multiple_tx_fifo == 0)
++ //{
++ // intr_mask.b.nptxfempty = 1;
++ // dwc_modify_reg32( &core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
++ //}
++ //else
++ {
++ /* Disable the Tx FIFO Empty Interrupt for this EP */
++ uint32_t fifoemptymsk = 0x1 << dwc_ep->num;
++ dwc_modify_reg32(&core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk, fifoemptymsk, 0);
++ //intr_mask.b.nptxfempty = 1;
++ //dwc_modify_reg32( &core_if->core_global_regs->gintmsk, intr_mask.d32, 0);
++ }
++ }
++
++ CLEAR_IN_EP_INTR(core_if,epnum,emptyintr);
++
++ }
++ }
++ epnum++;
++ ep_intr >>=1;
++ }
++
++ return 1;
++#undef CLEAR_IN_EP_INTR
++}
++
++/**
++ * This interrupt indicates that an OUT EP has a pending Interrupt.
++ * The sequence for handling the OUT EP interrupt is shown below:
++ * -# Read the Device All Endpoint Interrupt register
++ * -# Repeat the following for each OUT EP interrupt bit set (from
++ * LSB to MSB).
++ * -# Read the Device Endpoint Interrupt (DOEPINTn) register
++ * -# If "Transfer Complete" call the request complete function
++ * -# If "Endpoint Disabled" complete the EP disable procedure.
++ * -# If "AHB Error Interrupt" log error
++ * -# If "Setup Phase Done" process Setup Packet (See Standard USB
++ * Command Processing)
++ */
++static int32_t dwc_otg_pcd_handle_out_ep_intr(dwc_otg_pcd_t *_pcd)
++{
++#define CLEAR_OUT_EP_INTR(__core_if,__epnum,__intr) \
++do { \
++ doepint_data_t doepint = {.d32=0}; \
++ doepint.b.__intr = 1; \
++ dwc_write_reg32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \
++ doepint.d32); \
++} while (0)
++
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
++ uint32_t ep_intr;
++ doepint_data_t doepint = {.d32=0};
++ uint32_t epnum = 0;
++ dwc_ep_t *dwc_ep;
++
++ DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
++
++ /* Read in the device interrupt bits */
++ ep_intr = dwc_otg_read_dev_all_out_ep_intr( core_if );
++
++ while ( ep_intr )
++ {
++ if (ep_intr&0x1)
++ {
++ /* Get EP pointer */
++ dwc_ep = &((get_out_ep(_pcd, epnum))->dwc_ep);
++// dwc_ep = &_pcd->out_ep[ epnum - 1].dwc_ep;
++#ifdef VERBOSE
++ DWC_DEBUGPL(DBG_PCDV,
++ "EP%d-%s: type=%d, mps=%d\n",
++ dwc_ep->num, (dwc_ep->is_in ?"IN":"OUT"),
++ dwc_ep->type, dwc_ep->maxpacket );
++#endif
++ doepint.d32 = dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep);
++ /* Transfer complete */
++ if ( doepint.b.xfercompl )
++ {
++ DWC_DEBUGPL(DBG_PCD,"EP%d OUT Xfer Complete\n",
++ epnum);
++ /* Clear the bit in DOEPINTn for this interrupt */
++ CLEAR_OUT_EP_INTR(core_if,epnum,xfercompl);
++
++ if (epnum == 0)
++ {
++ handle_ep0( _pcd );
++ }
++ else
++ {
++ complete_ep( get_out_ep(_pcd, epnum) );
++// complete_ep( &_pcd->out_ep[ epnum - 1] );
++ }
++ }
++ /* Endpoint disable */
++ if ( doepint.b.epdisabled )
++ {
++ DWC_DEBUGPL(DBG_PCD,"EP%d OUT disabled\n", epnum);
++ /* Clear the bit in DOEPINTn for this interrupt */
++ CLEAR_OUT_EP_INTR(core_if,epnum,epdisabled);
++ }
++ /* AHB Error */
++ if ( doepint.b.ahberr )
++ {
++ DWC_DEBUGPL(DBG_PCD,"EP%d OUT AHB Error\n", epnum);
++ DWC_DEBUGPL(DBG_PCD,"EP DMA REG %d \n", core_if->dev_if->out_ep_regs[epnum]->doepdma);
++ CLEAR_OUT_EP_INTR(core_if,epnum,ahberr);
++ }
++ /* Setup Phase Done (contorl EPs) */
++ if ( doepint.b.setup )
++ {
++#ifdef DEBUG_EP0
++ DWC_DEBUGPL(DBG_PCD,"EP%d SETUP Done\n",
++ epnum);
++#endif
++ handle_ep0( _pcd );
++ CLEAR_OUT_EP_INTR(core_if,epnum,setup);
++ }
++ }
++ epnum++;
++ ep_intr >>=1;
++ }
++
++ return 1;
++
++#undef CLEAR_OUT_EP_INTR
++}
++
++/**
++ * Incomplete ISO IN Transfer Interrupt.
++ * This interrupt indicates one of the following conditions occurred
++ * while transmitting an ISOC transaction.
++ * - Corrupted IN Token for ISOC EP.
++ * - Packet not complete in FIFO.
++ * The follow actions will be taken:
++ * -# Determine the EP
++ * -# Set incomplete flag in dwc_ep structure
++ * -# Disable EP; when "Endpoint Disabled" interrupt is received
++ * Flush FIFO
++ */
++int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr(dwc_otg_pcd_t *_pcd)
++{
++ gintmsk_data_t intr_mask = { .d32 = 0};
++ gintsts_data_t gintsts;
++#if 0
++ depctl_data_t diepctl ;
++ diepint_data_t diepint;
++ int epnum =0, i =0;
++#endif
++ DWC_PRINT("INTERRUPT Handler not implemented for %s\n",
++ "IN ISOC Incomplete");
++
++ /* The application must read the EP Control register for all isochronous IN endpoints to detect EPs with
++ incomplete IN data transfers.
++ */
++#if 0
++ for (i=1; i<=15; i++) {
++ diepctl.d32 = dwc_read_reg32(&GET_CORE_IF(_pcd)->dev_if->in_ep_regs[i]->diepctl);
++ if ((diepctl.b.epena) && (diepctl.b.eptype == 0x01)) {
++ epnum = i;
++ break;
++ }
++ }
++ /* Disable the Periodic IN Endpoint*/
++
++ diepctl.b.snak = 1;
++
++ diepctl.b.epdis = 1;
++ dwc_write_reg32(&GET_CORE_IF(_pcd)->dev_if->in_ep_regs[epnum]->diepctl,diepctl.d32);
++
++ /* End */
++#endif
++ intr_mask.b.incomplisoin = 1;
++ dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
++ intr_mask.d32, 0 );
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.incomplisoin = 1;
++ dwc_write_reg32 (&GET_CORE_IF(_pcd)->core_global_regs->gintsts,
++ gintsts.d32);
++
++ return 1;
++}
++
++/**
++ * Incomplete ISO OUT Transfer Interrupt.
++ *
++ * This interrupt indicates that the core has dropped an ISO OUT
++ * packet. The following conditions can be the cause:
++ * - FIFO Full, the entire packet would not fit in the FIFO.
++ * - CRC Error
++ * - Corrupted Token
++ * The follow actions will be taken:
++ * -# Determine the EP
++ * -# Set incomplete flag in dwc_ep structure
++ * -# Read any data from the FIFO
++ * -# Disable EP. when "Endpoint Disabled" interrupt is received
++ * re-enable EP.
++ */
++int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr(dwc_otg_pcd_t *_pcd)
++{
++ /** @todo implement ISR */
++ gintmsk_data_t intr_mask = { .d32 = 0};
++ gintsts_data_t gintsts;
++ DWC_PRINT("INTERRUPT Handler not implemented for %s\n",
++ "OUT ISOC Incomplete");
++
++ intr_mask.b.incomplisoout = 1;
++ dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
++ intr_mask.d32, 0 );
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.incomplisoout = 1;
++ dwc_write_reg32 (&GET_CORE_IF(_pcd)->core_global_regs->gintsts,
++ gintsts.d32);
++
++ return 1;
++}
++
++/**
++ * This function handles the Global IN NAK Effective interrupt.
++ *
++ */
++int32_t dwc_otg_pcd_handle_in_nak_effective( dwc_otg_pcd_t *_pcd )
++{
++ dwc_otg_dev_if_t *dev_if = GET_CORE_IF(_pcd)->dev_if;
++ depctl_data_t diepctl = { .d32 = 0};
++ depctl_data_t diepctl_rd = { .d32 = 0};
++ gintmsk_data_t intr_mask = { .d32 = 0};
++ gintsts_data_t gintsts;
++ int i;
++
++ DWC_DEBUGPL(DBG_PCD, "Global IN NAK Effective\n");
++
++ /* Disable all active IN EPs */
++ diepctl.b.epdis = 1;
++ diepctl.b.snak = 1;
++
++ for (i=0; i <= dev_if->num_in_eps; i++)
++ {
++ diepctl_rd.d32 = dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl);
++ if (diepctl_rd.b.epena)
++ {
++ dwc_write_reg32( &dev_if->in_ep_regs[i]->diepctl,
++ diepctl.d32 );
++ }
++ }
++ /* Disable the Global IN NAK Effective Interrupt */
++ intr_mask.b.ginnakeff = 1;
++ dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
++ intr_mask.d32, 0);
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.ginnakeff = 1;
++ dwc_write_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintsts,
++ gintsts.d32);
++
++ return 1;
++}
++
++/**
++ * OUT NAK Effective.
++ *
++ */
++int32_t dwc_otg_pcd_handle_out_nak_effective( dwc_otg_pcd_t *_pcd )
++{
++ gintmsk_data_t intr_mask = { .d32 = 0};
++ gintsts_data_t gintsts;
++
++ DWC_PRINT("INTERRUPT Handler not implemented for %s\n",
++ "Global IN NAK Effective\n");
++ /* Disable the Global IN NAK Effective Interrupt */
++ intr_mask.b.goutnakeff = 1;
++ dwc_modify_reg32( &GET_CORE_IF(_pcd)->core_global_regs->gintmsk,
++ intr_mask.d32, 0);
++
++ /* Clear interrupt */
++ gintsts.d32 = 0;
++ gintsts.b.goutnakeff = 1;
++ dwc_write_reg32 (&GET_CORE_IF(_pcd)->core_global_regs->gintsts,
++ gintsts.d32);
++
++ return 1;
++}
++
++
++/**
++ * PCD interrupt handler.
++ *
++ * The PCD handles the device interrupts. Many conditions can cause a
++ * device interrupt. When an interrupt occurs, the device interrupt
++ * service routine determines the cause of the interrupt and
++ * dispatches handling to the appropriate function. These interrupt
++ * handling functions are described below.
++ *
++ * All interrupt registers are processed from LSB to MSB.
++ *
++ */
++int32_t dwc_otg_pcd_handle_intr( dwc_otg_pcd_t *_pcd )
++{
++ dwc_otg_core_if_t *core_if = GET_CORE_IF(_pcd);
++#ifdef VERBOSE
++ dwc_otg_core_global_regs_t *global_regs =
++ core_if->core_global_regs;
++#endif
++ gintsts_data_t gintr_status;
++ int32_t retval = 0;
++
++#ifdef VERBOSE
++ DWC_DEBUGPL(DBG_ANY, "%s() gintsts=%08x gintmsk=%08x\n",
++ __func__,
++ dwc_read_reg32( &global_regs->gintsts),
++ dwc_read_reg32( &global_regs->gintmsk));
++#endif
++
++ if (dwc_otg_is_device_mode(core_if))
++ {
++ SPIN_LOCK(&_pcd->lock);
++#ifdef VERBOSE
++ DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%08x gintmsk=%08x\n",
++ __func__,
++ dwc_read_reg32( &global_regs->gintsts),
++ dwc_read_reg32( &global_regs->gintmsk));
++#endif
++
++ gintr_status.d32 = dwc_otg_read_core_intr(core_if);
++ if (!gintr_status.d32)
++ {
++ SPIN_UNLOCK(&_pcd->lock);
++ return 0;
++ }
++ DWC_DEBUGPL(DBG_PCDV, "%s: gintsts&gintmsk=%08x\n",
++ __func__, gintr_status.d32 );
++
++ if (gintr_status.b.sofintr)
++ {
++ retval |= dwc_otg_pcd_handle_sof_intr( _pcd );
++ }
++ if (gintr_status.b.rxstsqlvl)
++ {
++ retval |= dwc_otg_pcd_handle_rx_status_q_level_intr( _pcd );
++ }
++ //if (gintr_status.b.nptxfempty)
++ //{
++ // retval |= dwc_otg_pcd_handle_np_tx_fifo_empty_intr( _pcd );
++ //}
++ if (gintr_status.b.ginnakeff)
++ {
++ retval |= dwc_otg_pcd_handle_in_nak_effective( _pcd );
++ }
++ if (gintr_status.b.goutnakeff)
++ {
++ retval |= dwc_otg_pcd_handle_out_nak_effective( _pcd );
++ }
++ if (gintr_status.b.i2cintr)
++ {
++ retval |= dwc_otg_pcd_handle_i2c_intr( _pcd );
++ }
++ if (gintr_status.b.erlysuspend)
++ {
++ retval |= dwc_otg_pcd_handle_early_suspend_intr( _pcd );
++ }
++ if (gintr_status.b.usbreset)
++ {
++ retval |= dwc_otg_pcd_handle_usb_reset_intr( _pcd );
++ }
++ if (gintr_status.b.enumdone)
++ {
++ retval |= dwc_otg_pcd_handle_enum_done_intr( _pcd );
++ }
++ if (gintr_status.b.isooutdrop)
++ {
++ retval |= dwc_otg_pcd_handle_isoc_out_packet_dropped_intr( _pcd );
++ }
++ if (gintr_status.b.eopframe)
++ {
++ retval |= dwc_otg_pcd_handle_end_periodic_frame_intr( _pcd );
++ }
++ if (gintr_status.b.epmismatch)
++ {
++ retval |= dwc_otg_pcd_handle_ep_mismatch_intr( core_if );
++ }
++ if (gintr_status.b.inepint)
++ {
++ retval |= dwc_otg_pcd_handle_in_ep_intr( _pcd );
++ }
++ if (gintr_status.b.outepintr)
++ {
++ retval |= dwc_otg_pcd_handle_out_ep_intr( _pcd );
++ }
++ if (gintr_status.b.incomplisoin)
++ {
++ retval |= dwc_otg_pcd_handle_incomplete_isoc_in_intr( _pcd );
++ }
++ if (gintr_status.b.incomplisoout)
++ {
++ retval |= dwc_otg_pcd_handle_incomplete_isoc_out_intr( _pcd );
++ }
++#ifdef VERBOSE
++ DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%0x\n", __func__,
++ dwc_read_reg32( &global_regs->gintsts));
++#endif
++ SPIN_UNLOCK(&_pcd->lock);
++ }
++ return retval;
++}
++
++#endif /* DWC_HOST_ONLY */
+diff --git a/drivers/usb/dwc_otg/dwc_otg_plat.h b/drivers/usb/dwc_otg/dwc_otg_plat.h
+new file mode 100644
+index 0000000..5092a56
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_plat.h
+@@ -0,0 +1,297 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/platform/dwc_otg_plat.h $
++ * $Revision: #1 $
++ * $Date: 2005/07/07 $
++ * $Change: 510301 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++#if !defined(__DWC_OTG_PLAT_H__)
++#define __DWC_OTG_PLAT_H__
++
++#include <linux/types.h>
++#include <linux/slab.h>
++#include <linux/list.h>
++#include <linux/delay.h>
++#include <asm/io.h>
++#include <linux/platform_device.h>
++
++/**
++ * @file
++ *
++ * This file contains the Platform Specific constants, interfaces
++ * (functions and macros) for Linux.
++ *
++ */
++#if !defined(__LINUX_ARM_ARCH__)
++#error "The contents of this file is Linux specific!!!"
++#endif
++
++/**
++ * Reads the content of a register.
++ *
++ * @param _reg address of register to read.
++ * @return contents of the register.
++ *
++
++ * Usage:<br>
++ * <code>uint32_t dev_ctl = dwc_read_reg32(&dev_regs->dctl);</code>
++ */
++static __inline__ uint32_t dwc_read_reg32( volatile uint32_t *_reg)
++{
++ return readl(_reg);
++};
++
++/**
++ * Writes a register with a 32 bit value.
++ *
++ * @param _reg address of register to read.
++ * @param _value to write to _reg.
++ *
++ * Usage:<br>
++ * <code>dwc_write_reg32(&dev_regs->dctl, 0); </code>
++ */
++static __inline__ void dwc_write_reg32( volatile uint32_t *_reg, const uint32_t _value)
++{
++ writel( _value, _reg );
++};
++
++/**
++ * This function modifies bit values in a register. Using the
++ * algorithm: (reg_contents & ~clear_mask) | set_mask.
++ *
++ * @param _reg address of register to read.
++ * @param _clear_mask bit mask to be cleared.
++ * @param _set_mask bit mask to be set.
++ *
++ * Usage:<br>
++ * <code> // Clear the SOF Interrupt Mask bit and <br>
++ * // set the OTG Interrupt mask bit, leaving all others as they were.
++ * dwc_modify_reg32(&dev_regs->gintmsk, DWC_SOF_INT, DWC_OTG_INT);</code>
++ */
++static __inline__
++void dwc_modify_reg32( volatile uint32_t *_reg, const uint32_t _clear_mask, const uint32_t _set_mask)
++{
++ writel( (readl(_reg) & ~_clear_mask) | _set_mask, _reg );
++};
++
++/**
++ *
++ */
++static __inline__
++void *dev_get_otgdata(const struct device *dev)
++{
++ return dev->platform_data;
++}
++
++static __inline__
++void dev_set_otgdata(struct device *dev, void *data)
++{
++ dev->platform_data = data;
++}
++
++#define platform_get_otgdata(_dev) dev_get_otgdata(&(_dev)->dev)
++#define platform_set_otgdata(_dev,data) dev_set_otgdata(&(_dev)->dev, (data))
++
++/**
++ * Wrapper for the OS micro-second delay function.
++ * @param[in] _usecs Microseconds of delay
++ */
++static __inline__ void UDELAY( const uint32_t _usecs )
++{
++ udelay( _usecs );
++}
++
++/**
++ * Wrapper for the OS milli-second delay function.
++ * @param[in] _msecs milliseconds of delay
++ */
++static __inline__ void MDELAY( const uint32_t _msecs )
++{
++ mdelay( _msecs );
++}
++
++/**
++ * Wrapper for the Linux spin_lock. On the ARM (Integrator)
++ * spin_lock() is a nop.
++ *
++ * @param _lock Pointer to the spinlock.
++ */
++static __inline__ void SPIN_LOCK( spinlock_t *_lock )
++{
++ spin_lock(_lock);
++}
++
++/**
++ * Wrapper for the Linux spin_unlock. On the ARM (Integrator)
++ * spin_lock() is a nop.
++ *
++ * @param _lock Pointer to the spinlock.
++ */
++static __inline__ void SPIN_UNLOCK( spinlock_t *_lock )
++{
++ spin_unlock(_lock);
++}
++
++/**
++ * Wrapper (macro) for the Linux spin_lock_irqsave. On the ARM
++ * (Integrator) spin_lock() is a nop.
++ *
++ * @param _l Pointer to the spinlock.
++ * @param _f unsigned long for irq flags storage.
++ */
++#define SPIN_LOCK_IRQSAVE( _l, _f ) { \
++ spin_lock_irqsave(_l,_f); \
++ }
++
++/**
++ * Wrapper (macro) for the Linux spin_unlock_irqrestore. On the ARM
++ * (Integrator) spin_lock() is a nop.
++ *
++ * @param _l Pointer to the spinlock.
++ * @param _f unsigned long for irq flags storage.
++ */
++#define SPIN_UNLOCK_IRQRESTORE( _l,_f ) {\
++ spin_unlock_irqrestore(_l,_f); \
++ }
++
++
++/*
++ * Debugging support vanishes in non-debug builds.
++ */
++
++
++/**
++ * The Debug Level bit-mask variable.
++ */
++extern uint32_t g_dbg_lvl;
++/**
++ * Set the Debug Level variable.
++ */
++static inline uint32_t SET_DEBUG_LEVEL( const uint32_t _new )
++{
++ uint32_t old = g_dbg_lvl;
++ g_dbg_lvl = _new;
++ return old;
++}
++
++/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */
++#define DBG_CIL (0x2)
++/** When debug level has the DBG_CILV bit set, display CIL Verbose debug
++ * messages */
++#define DBG_CILV (0x20)
++/** When debug level has the DBG_PCD bit set, display PCD (Device) debug
++ * messages */
++#define DBG_PCD (0x4)
++/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug
++ * messages */
++#define DBG_PCDV (0x40)
++/** When debug level has the DBG_HCD bit set, display Host debug messages */
++#define DBG_HCD (0x8)
++/** When debug level has the DBG_HCDV bit set, display Verbose Host debug
++ * messages */
++#define DBG_HCDV (0x80)
++/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host
++ * mode. */
++#define DBG_HCD_URB (0x800)
++
++/** When debug level has any bit set, display debug messages */
++#define DBG_ANY (0xFF)
++
++/** All debug messages off */
++#define DBG_OFF 0
++
++/** Prefix string for DWC_DEBUG print macros. */
++#define USB_DWC "DWC_otg: "
++
++/**
++ * Print a debug message when the Global debug level variable contains
++ * the bit defined in <code>lvl</code>.
++ *
++ * @param[in] lvl - Debug level, use one of the DBG_ constants above.
++ * @param[in] x - like printf
++ *
++ * Example:<p>
++ * <code>
++ * DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr);
++ * </code>
++ * <br>
++ * results in:<br>
++ * <code>
++ * usb-DWC_otg: dwc_otg_cil_init(ca867000)
++ * </code>
++ */
++#if 1
++#ifdef DEBUG
++
++# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)printk( KERN_DEBUG USB_DWC x ); }while(0)
++# define DWC_DEBUGP(x...) DWC_DEBUGPL(DBG_ANY, x )
++
++# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl)
++
++#else
++
++# define DWC_DEBUGPL(lvl, x...) do{}while(0)
++# define DWC_DEBUGP(x...)
++
++# define CHK_DEBUG_LEVEL(level) (0)
++
++#endif /*DEBUG*/
++#else
++#ifdef DEBUG
++# define DWC_DEBUGPL(lvl, x...) printk(KERN_INFO USB_DWC x )
++# define DWC_DEBUGP(x...) printk(KERN_INFO USB_DWC X )
++#endif
++#endif
++
++#ifdef DEBUG
++/**
++ * Print an Error message.
++ */
++#define DWC_ERROR(x...) printk( KERN_ERR USB_DWC x )
++/**
++ * Print a Warning message.
++ */
++#define DWC_WARN(x...) printk( KERN_WARNING USB_DWC x )
++/**
++ * Print a notice (normal but significant message).
++ */
++#define DWC_NOTICE(x...) printk( KERN_NOTICE USB_DWC x )
++/**
++ * Basic message printing.
++ */
++#define DWC_PRINT(x...) printk( KERN_INFO USB_DWC x )
++#else
++#define DWC_ERROR(x...)
++#define DWC_WARN(x...)
++#define DWC_NOTICE(x...)
++#define DWC_PRINT(x...)
++#endif
++
++#endif
++
+diff --git a/drivers/usb/dwc_otg/dwc_otg_regs.h b/drivers/usb/dwc_otg/dwc_otg_regs.h
+new file mode 100644
+index 0000000..a3de849
+--- /dev/null
++++ b/drivers/usb/dwc_otg/dwc_otg_regs.h
+@@ -0,0 +1,1884 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_regs.h $
++ * $Revision: #8 $
++ * $Date: 2007/02/07 $
++ * $Change: 791271 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++#ifndef __DWC_OTG_REGS_H__
++#define __DWC_OTG_REGS_H__
++
++/**
++ * @file
++ *
++ * This file contains the data structures for accessing the DWC_otg core registers.
++ *
++ * The application interfaces with the HS OTG core by reading from and
++ * writing to the Control and Status Register (CSR) space through the
++ * AHB Slave interface. These registers are 32 bits wide, and the
++ * addresses are 32-bit-block aligned.
++ * CSRs are classified as follows:
++ * - Core Global Registers
++ * - Device Mode Registers
++ * - Device Global Registers
++ * - Device Endpoint Specific Registers
++ * - Host Mode Registers
++ * - Host Global Registers
++ * - Host Port CSRs
++ * - Host Channel Specific Registers
++ *
++ * Only the Core Global registers can be accessed in both Device and
++ * Host modes. When the HS OTG core is operating in one mode, either
++ * Device or Host, the application must not access registers from the
++ * other mode. When the core switches from one mode to another, the
++ * registers in the new mode of operation must be reprogrammed as they
++ * would be after a power-on reset.
++ */
++
++/****************************************************************************/
++/** DWC_otg Core registers .
++ * The dwc_otg_core_global_regs structure defines the size
++ * and relative field offsets for the Core Global registers.
++ */
++typedef struct dwc_otg_core_global_regs
++{
++ /** OTG Control and Status Register. <i>Offset: 000h</i> */
++ volatile uint32_t gotgctl;
++ /** OTG Interrupt Register. <i>Offset: 004h</i> */
++ volatile uint32_t gotgint;
++ /**Core AHB Configuration Register. <i>Offset: 008h</i> */
++ volatile uint32_t gahbcfg;
++
++#define DWC_GLBINTRMASK 0x0001
++#define DWC_DMAENABLE 0x0020
++#define DWC_NPTXEMPTYLVL_EMPTY 0x0080
++#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000
++#define DWC_PTXEMPTYLVL_EMPTY 0x0100
++#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000
++
++ /**Core USB Configuration Register. <i>Offset: 00Ch</i> */
++ volatile uint32_t gusbcfg;
++ /**Core Reset Register. <i>Offset: 010h</i> */
++ volatile uint32_t grstctl;
++ /**Core Interrupt Register. <i>Offset: 014h</i> */
++ volatile uint32_t gintsts;
++ /**Core Interrupt Mask Register. <i>Offset: 018h</i> */
++ volatile uint32_t gintmsk;
++ /**Receive Status Queue Read Register (Read Only). <i>Offset: 01Ch</i> */
++ volatile uint32_t grxstsr;
++ /**Receive Status Queue Read & POP Register (Read Only). <i>Offset: 020h</i>*/
++ volatile uint32_t grxstsp;
++ /**Receive FIFO Size Register. <i>Offset: 024h</i> */
++ volatile uint32_t grxfsiz;
++ /**Non Periodic Transmit FIFO Size Register. <i>Offset: 028h</i> */
++ volatile uint32_t gnptxfsiz;
++ /**Non Periodic Transmit FIFO/Queue Status Register (Read
++ * Only). <i>Offset: 02Ch</i> */
++ volatile uint32_t gnptxsts;
++ /**I2C Access Register. <i>Offset: 030h</i> */
++ volatile uint32_t gi2cctl;
++ /**PHY Vendor Control Register. <i>Offset: 034h</i> */
++ volatile uint32_t gpvndctl;
++ /**General Purpose Input/Output Register. <i>Offset: 038h</i> */
++ volatile uint32_t ggpio;
++ /**User ID Register. <i>Offset: 03Ch</i> */
++ volatile uint32_t guid;
++ /**Synopsys ID Register (Read Only). <i>Offset: 040h</i> */
++ volatile uint32_t gsnpsid;
++ /**User HW Config1 Register (Read Only). <i>Offset: 044h</i> */
++ volatile uint32_t ghwcfg1;
++ /**User HW Config2 Register (Read Only). <i>Offset: 048h</i> */
++ volatile uint32_t ghwcfg2;
++#define DWC_SLAVE_ONLY_ARCH 0
++#define DWC_EXT_DMA_ARCH 1
++#define DWC_INT_DMA_ARCH 2
++
++#define DWC_MODE_HNP_SRP_CAPABLE 0
++#define DWC_MODE_SRP_ONLY_CAPABLE 1
++#define DWC_MODE_NO_HNP_SRP_CAPABLE 2
++#define DWC_MODE_SRP_CAPABLE_DEVICE 3
++#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4
++#define DWC_MODE_SRP_CAPABLE_HOST 5
++#define DWC_MODE_NO_SRP_CAPABLE_HOST 6
++
++ /**User HW Config3 Register (Read Only). <i>Offset: 04Ch</i> */
++ volatile uint32_t ghwcfg3;
++ /**User HW Config4 Register (Read Only). <i>Offset: 050h</i>*/
++ volatile uint32_t ghwcfg4;
++ /** Reserved <i>Offset: 054h-0FFh</i> */
++ uint32_t reserved[43];
++ /** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */
++ volatile uint32_t hptxfsiz;
++ /** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled,
++ otherwise Device Transmit FIFO#n Register.
++ * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */
++ volatile uint32_t dptxfsiz_dieptxf[15];
++} dwc_otg_core_global_regs_t;
++
++/**
++ * This union represents the bit fields of the Core OTG Control
++ * and Status Register (GOTGCTL). Set the bits using the bit
++ * fields then write the <i>d32</i> value to the register.
++ */
++typedef union gotgctl_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned sesreqscs : 1;
++ unsigned sesreq : 1;
++ unsigned reserved2_7 : 6;
++ unsigned hstnegscs : 1;
++ unsigned hnpreq : 1;
++ unsigned hstsethnpen : 1;
++ unsigned devhnpen : 1;
++ unsigned reserved12_15 : 4;
++ unsigned conidsts : 1;
++ unsigned reserved17 : 1;
++ unsigned asesvld : 1;
++ unsigned bsesvld : 1;
++ unsigned currmod : 1;
++ unsigned reserved21_31 : 11;
++ } b;
++} gotgctl_data_t;
++
++/**
++ * This union represents the bit fields of the Core OTG Interrupt Register
++ * (GOTGINT). Set/clear the bits using the bit fields then write the <i>d32</i>
++ * value to the register.
++ */
++typedef union gotgint_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ /** Current Mode */
++ unsigned reserved0_1 : 2;
++
++ /** Session End Detected */
++ unsigned sesenddet : 1;
++
++ unsigned reserved3_7 : 5;
++
++ /** Session Request Success Status Change */
++ unsigned sesreqsucstschng : 1;
++ /** Host Negotiation Success Status Change */
++ unsigned hstnegsucstschng : 1;
++
++ unsigned reserver10_16 : 7;
++
++ /** Host Negotiation Detected */
++ unsigned hstnegdet : 1;
++ /** A-Device Timeout Change */
++ unsigned adevtoutchng : 1;
++ /** Debounce Done */
++ unsigned debdone : 1;
++
++ unsigned reserved31_20 : 12;
++
++ } b;
++} gotgint_data_t;
++
++
++/**
++ * This union represents the bit fields of the Core AHB Configuration
++ * Register (GAHBCFG). Set/clear the bits using the bit fields then
++ * write the <i>d32</i> value to the register.
++ */
++typedef union gahbcfg_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned glblintrmsk : 1;
++#define DWC_GAHBCFG_GLBINT_ENABLE 1
++
++ unsigned hburstlen : 4;
++#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0
++#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1
++#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3
++#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5
++#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7
++
++ unsigned dmaenable : 1;
++#define DWC_GAHBCFG_DMAENABLE 1
++ unsigned reserved : 1;
++ unsigned nptxfemplvl_txfemplvl : 1;
++ unsigned ptxfemplvl : 1;
++#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1
++#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0
++ unsigned reserved9_31 : 23;
++ } b;
++} gahbcfg_data_t;
++
++/**
++ * This union represents the bit fields of the Core USB Configuration
++ * Register (GUSBCFG). Set the bits using the bit fields then write
++ * the <i>d32</i> value to the register.
++ */
++typedef union gusbcfg_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned toutcal : 3;
++ unsigned phyif : 1;
++ unsigned ulpi_utmi_sel : 1;
++ unsigned fsintf : 1;
++ unsigned physel : 1;
++ unsigned ddrsel : 1;
++ unsigned srpcap : 1;
++ unsigned hnpcap : 1;
++ unsigned usbtrdtim : 4;
++ unsigned nptxfrwnden : 1;
++ unsigned phylpwrclksel : 1;
++ unsigned otgutmifssel : 1;
++ unsigned ulpi_fsls : 1;
++ unsigned ulpi_auto_res : 1;
++ unsigned ulpi_clk_sus_m : 1;
++ unsigned ulpi_ext_vbus_drv : 1;
++ unsigned ulpi_int_vbus_indicator : 1;
++ unsigned term_sel_dl_pulse : 1;
++ unsigned reserved : 9;
++ } b;
++} gusbcfg_data_t;
++
++/**
++ * This union represents the bit fields of the Core Reset Register
++ * (GRSTCTL). Set/clear the bits using the bit fields then write the
++ * <i>d32</i> value to the register.
++ */
++typedef union grstctl_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ /** Core Soft Reset (CSftRst) (Device and Host)
++ *
++ * The application can flush the control logic in the
++ * entire core using this bit. This bit resets the
++ * pipelines in the AHB Clock domain as well as the
++ * PHY Clock domain.
++ *
++ * The state machines are reset to an IDLE state, the
++ * control bits in the CSRs are cleared, all the
++ * transmit FIFOs and the receive FIFO are flushed.
++ *
++ * The status mask bits that control the generation of
++ * the interrupt, are cleared, to clear the
++ * interrupt. The interrupt status bits are not
++ * cleared, so the application can get the status of
++ * any events that occurred in the core after it has
++ * set this bit.
++ *
++ * Any transactions on the AHB are terminated as soon
++ * as possible following the protocol. Any
++ * transactions on the USB are terminated immediately.
++ *
++ * The configuration settings in the CSRs are
++ * unchanged, so the software doesn't have to
++ * reprogram these registers (Device
++ * Configuration/Host Configuration/Core System
++ * Configuration/Core PHY Configuration).
++ *
++ * The application can write to this bit, any time it
++ * wants to reset the core. This is a self clearing
++ * bit and the core clears this bit after all the
++ * necessary logic is reset in the core, which may
++ * take several clocks, depending on the current state
++ * of the core.
++ */
++ unsigned csftrst : 1;
++ /** Hclk Soft Reset
++ *
++ * The application uses this bit to reset the control logic in
++ * the AHB clock domain. Only AHB clock domain pipelines are
++ * reset.
++ */
++ unsigned hsftrst : 1;
++ /** Host Frame Counter Reset (Host Only)<br>
++ *
++ * The application can reset the (micro)frame number
++ * counter inside the core, using this bit. When the
++ * (micro)frame counter is reset, the subsequent SOF
++ * sent out by the core, will have a (micro)frame
++ * number of 0.
++ */
++ unsigned hstfrm : 1;
++ /** In Token Sequence Learning Queue Flush
++ * (INTknQFlsh) (Device Only)
++ */
++ unsigned intknqflsh : 1;
++ /** RxFIFO Flush (RxFFlsh) (Device and Host)
++ *
++ * The application can flush the entire Receive FIFO
++ * using this bit. <p>The application must first
++ * ensure that the core is not in the middle of a
++ * transaction. <p>The application should write into
++ * this bit, only after making sure that neither the
++ * DMA engine is reading from the RxFIFO nor the MAC
++ * is writing the data in to the FIFO. <p>The
++ * application should wait until the bit is cleared
++ * before performing any other operations. This bit
++ * will takes 8 clocks (slowest of PHY or AHB clock)
++ * to clear.
++ */
++ unsigned rxfflsh : 1;
++ /** TxFIFO Flush (TxFFlsh) (Device and Host).
++ *
++ * This bit is used to selectively flush a single or
++ * all transmit FIFOs. The application must first
++ * ensure that the core is not in the middle of a
++ * transaction. <p>The application should write into
++ * this bit, only after making sure that neither the
++ * DMA engine is writing into the TxFIFO nor the MAC
++ * is reading the data out of the FIFO. <p>The
++ * application should wait until the core clears this
++ * bit, before performing any operations. This bit
++ * will takes 8 clocks (slowest of PHY or AHB clock)
++ * to clear.
++ */
++ unsigned txfflsh : 1;
++
++ /** TxFIFO Number (TxFNum) (Device and Host).
++ *
++ * This is the FIFO number which needs to be flushed,
++ * using the TxFIFO Flush bit. This field should not
++ * be changed until the TxFIFO Flush bit is cleared by
++ * the core.
++ * - 0x0 : Non Periodic TxFIFO Flush
++ * - 0x1 : Periodic TxFIFO #1 Flush in device mode
++ * or Periodic TxFIFO in host mode
++ * - 0x2 : Periodic TxFIFO #2 Flush in device mode.
++ * - ...
++ * - 0xF : Periodic TxFIFO #15 Flush in device mode
++ * - 0x10: Flush all the Transmit NonPeriodic and
++ * Transmit Periodic FIFOs in the core
++ */
++ unsigned txfnum : 5;
++ /** Reserved */
++ unsigned reserved11_29 : 19;
++ /** DMA Request Signal. Indicated DMA request is in
++ * probress. Used for debug purpose. */
++ unsigned dmareq : 1;
++ /** AHB Master Idle. Indicates the AHB Master State
++ * Machine is in IDLE condition. */
++ unsigned ahbidle : 1;
++ } b;
++} grstctl_t;
++
++
++/**
++ * This union represents the bit fields of the Core Interrupt Mask
++ * Register (GINTMSK). Set/clear the bits using the bit fields then
++ * write the <i>d32</i> value to the register.
++ */
++typedef union gintmsk_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned reserved0 : 1;
++ unsigned modemismatch : 1;
++ unsigned otgintr : 1;
++ unsigned sofintr : 1;
++ unsigned rxstsqlvl : 1;
++ unsigned nptxfempty : 1;
++ unsigned ginnakeff : 1;
++ unsigned goutnakeff : 1;
++ unsigned reserved8 : 1;
++ unsigned i2cintr : 1;
++ unsigned erlysuspend : 1;
++ unsigned usbsuspend : 1;
++ unsigned usbreset : 1;
++ unsigned enumdone : 1;
++ unsigned isooutdrop : 1;
++ unsigned eopframe : 1;
++ unsigned reserved16 : 1;
++ unsigned epmismatch : 1;
++ unsigned inepintr : 1;
++ unsigned outepintr : 1;
++ unsigned incomplisoin : 1;
++ unsigned incomplisoout : 1;
++ unsigned reserved22_23 : 2;
++ unsigned portintr : 1;
++ unsigned hcintr : 1;
++ unsigned ptxfempty : 1;
++ unsigned reserved27 : 1;
++ unsigned conidstschng : 1;
++ unsigned disconnect : 1;
++ unsigned sessreqintr : 1;
++ unsigned wkupintr : 1;
++ } b;
++} gintmsk_data_t;
++/**
++ * This union represents the bit fields of the Core Interrupt Register
++ * (GINTSTS). Set/clear the bits using the bit fields then write the
++ * <i>d32</i> value to the register.
++ */
++typedef union gintsts_data
++{
++ /** raw register data */
++ uint32_t d32;
++#define DWC_SOF_INTR_MASK 0x0008
++ /** register bits */
++ struct
++ {
++#define DWC_HOST_MODE 1
++ unsigned curmode : 1;
++ unsigned modemismatch : 1;
++ unsigned otgintr : 1;
++ unsigned sofintr : 1;
++ unsigned rxstsqlvl : 1;
++ unsigned nptxfempty : 1;
++ unsigned ginnakeff : 1;
++ unsigned goutnakeff : 1;
++ unsigned reserved8 : 1;
++ unsigned i2cintr : 1;
++ unsigned erlysuspend : 1;
++ unsigned usbsuspend : 1;
++ unsigned usbreset : 1;
++ unsigned enumdone : 1;
++ unsigned isooutdrop : 1;
++ unsigned eopframe : 1;
++ unsigned intokenrx : 1;
++ unsigned epmismatch : 1;
++ unsigned inepint: 1;
++ unsigned outepintr : 1;
++ unsigned incomplisoin : 1;
++ unsigned incomplisoout : 1;
++ unsigned reserved22_23 : 2;
++ unsigned portintr : 1;
++ unsigned hcintr : 1;
++ unsigned ptxfempty : 1;
++ unsigned reserved27 : 1;
++ unsigned conidstschng : 1;
++ unsigned disconnect : 1;
++ unsigned sessreqintr : 1;
++ unsigned wkupintr : 1;
++ } b;
++} gintsts_data_t;
++
++
++/**
++ * This union represents the bit fields in the Device Receive Status Read and
++ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
++ * element then read out the bits using the <i>b</i>it elements.
++ */
++typedef union device_grxsts_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned epnum : 4;
++ unsigned bcnt : 11;
++ unsigned dpid : 2;
++
++#define DWC_STS_DATA_UPDT 0x2 // OUT Data Packet
++#define DWC_STS_XFER_COMP 0x3 // OUT Data Transfer Complete
++
++#define DWC_DSTS_GOUT_NAK 0x1 // Global OUT NAK
++#define DWC_DSTS_SETUP_COMP 0x4 // Setup Phase Complete
++#define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet
++ unsigned pktsts : 4;
++ unsigned fn : 4;
++ unsigned reserved : 7;
++ } b;
++} device_grxsts_data_t;
++
++/**
++ * This union represents the bit fields in the Host Receive Status Read and
++ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i>
++ * element then read out the bits using the <i>b</i>it elements.
++ */
++typedef union host_grxsts_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned chnum : 4;
++ unsigned bcnt : 11;
++ unsigned dpid : 2;
++
++ unsigned pktsts : 4;
++#define DWC_GRXSTS_PKTSTS_IN 0x2
++#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3
++#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5
++#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7
++
++ unsigned reserved : 11;
++ } b;
++} host_grxsts_data_t;
++
++/**
++ * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ,
++ * GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). Read the register into the <i>d32</i> element then
++ * read out the bits using the <i>b</i>it elements.
++ */
++typedef union fifosize_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned startaddr : 16;
++ unsigned depth : 16;
++ } b;
++} fifosize_data_t;
++
++/**
++ * This union represents the bit fields in the Non-Periodic Transmit
++ * FIFO/Queue Status Register (GNPTXSTS). Read the register into the
++ * <i>d32</i> element then read out the bits using the <i>b</i>it
++ * elements.
++ */
++typedef union gnptxsts_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned nptxfspcavail : 16;
++ unsigned nptxqspcavail : 8;
++ /** Top of the Non-Periodic Transmit Request Queue
++ * - bit 24 - Terminate (Last entry for the selected
++ * channel/EP)
++ * - bits 26:25 - Token Type
++ * - 2'b00 - IN/OUT
++ * - 2'b01 - Zero Length OUT
++ * - 2'b10 - PING/Complete Split
++ * - 2'b11 - Channel Halt
++ * - bits 30:27 - Channel/EP Number
++ */
++ unsigned nptxqtop_terminate : 1;
++ unsigned nptxqtop_token : 2;
++ unsigned nptxqtop_chnep : 4;
++ unsigned reserved : 1;
++ } b;
++} gnptxsts_data_t;
++
++/**
++ * This union represents the bit fields in the Transmit
++ * FIFO Status Register (DTXFSTS). Read the register into the
++ * <i>d32</i> element then read out the bits using the <i>b</i>it
++ * elements.
++ */
++typedef union dtxfsts_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned txfspcavail : 16;
++ unsigned reserved : 16;
++ } b;
++} dtxfsts_data_t;
++
++/**
++ * This union represents the bit fields in the I2C Control Register
++ * (I2CCTL). Read the register into the <i>d32</i> element then read out the
++ * bits using the <i>b</i>it elements.
++ */
++typedef union gi2cctl_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned rwdata : 8;
++ unsigned regaddr : 8;
++ unsigned addr : 7;
++ unsigned i2cen : 1;
++ unsigned ack : 1;
++ unsigned i2csuspctl : 1;
++ unsigned i2cdevaddr : 2;
++ unsigned reserved : 2;
++ unsigned rw : 1;
++ unsigned bsydne : 1;
++ } b;
++} gi2cctl_data_t;
++
++/**
++ * This union represents the bit fields in the User HW Config1
++ * Register. Read the register into the <i>d32</i> element then read
++ * out the bits using the <i>b</i>it elements.
++ */
++typedef union hwcfg1_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned ep_dir0 : 2;
++ unsigned ep_dir1 : 2;
++ unsigned ep_dir2 : 2;
++ unsigned ep_dir3 : 2;
++ unsigned ep_dir4 : 2;
++ unsigned ep_dir5 : 2;
++ unsigned ep_dir6 : 2;
++ unsigned ep_dir7 : 2;
++ unsigned ep_dir8 : 2;
++ unsigned ep_dir9 : 2;
++ unsigned ep_dir10 : 2;
++ unsigned ep_dir11 : 2;
++ unsigned ep_dir12 : 2;
++ unsigned ep_dir13 : 2;
++ unsigned ep_dir14 : 2;
++ unsigned ep_dir15 : 2;
++ } b;
++} hwcfg1_data_t;
++
++/**
++ * This union represents the bit fields in the User HW Config2
++ * Register. Read the register into the <i>d32</i> element then read
++ * out the bits using the <i>b</i>it elements.
++ */
++typedef union hwcfg2_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ /* GHWCFG2 */
++ unsigned op_mode : 3;
++#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0
++#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1
++#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2
++#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
++#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
++#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
++#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
++
++ unsigned architecture : 2;
++ unsigned point2point : 1;
++ unsigned hs_phy_type : 2;
++#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
++#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1
++#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2
++#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
++
++ unsigned fs_phy_type : 2;
++ unsigned num_dev_ep : 4;
++ unsigned num_host_chan : 4;
++ unsigned perio_ep_supported : 1;
++ unsigned dynamic_fifo : 1;
++ unsigned rx_status_q_depth : 2;
++ unsigned nonperio_tx_q_depth : 2;
++ unsigned host_perio_tx_q_depth : 2;
++ unsigned dev_token_q_depth : 5;
++ unsigned reserved31 : 1;
++ } b;
++} hwcfg2_data_t;
++
++/**
++ * This union represents the bit fields in the User HW Config3
++ * Register. Read the register into the <i>d32</i> element then read
++ * out the bits using the <i>b</i>it elements.
++ */
++typedef union hwcfg3_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ /* GHWCFG3 */
++ unsigned xfer_size_cntr_width : 4;
++ unsigned packet_size_cntr_width : 3;
++ unsigned otg_func : 1;
++ unsigned i2c : 1;
++ unsigned vendor_ctrl_if : 1;
++ unsigned optional_features : 1;
++ unsigned synch_reset_type : 1;
++ unsigned ahb_phy_clock_synch : 1;
++ unsigned reserved15_13 : 3;
++ unsigned dfifo_depth : 16;
++ } b;
++} hwcfg3_data_t;
++
++/**
++ * This union represents the bit fields in the User HW Config4
++ * Register. Read the register into the <i>d32</i> element then read
++ * out the bits using the <i>b</i>it elements.
++ */
++typedef union hwcfg4_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned num_dev_perio_in_ep : 4;
++ unsigned power_optimiz : 1;
++ unsigned min_ahb_freq : 9;
++ unsigned utmi_phy_data_width : 2;
++ unsigned num_dev_mode_ctrl_ep : 4;
++ unsigned iddig_filt_en : 1;
++ unsigned vbus_valid_filt_en : 1;
++ unsigned a_valid_filt_en : 1;
++ unsigned b_valid_filt_en : 1;
++ unsigned session_end_filt_en : 1;
++ unsigned ded_fifo_en : 1;
++ unsigned num_in_eps : 4;
++ unsigned reserved31_30 : 2;
++ } b;
++} hwcfg4_data_t;
++
++////////////////////////////////////////////
++// Device Registers
++/**
++ * Device Global Registers. <i>Offsets 800h-BFFh</i>
++ *
++ * The following structures define the size and relative field offsets
++ * for the Device Mode Registers.
++ *
++ * <i>These registers are visible only in Device mode and must not be
++ * accessed in Host mode, as the results are unknown.</i>
++ */
++typedef struct dwc_otg_dev_global_regs
++{
++ /** Device Configuration Register. <i>Offset 800h</i> */
++ volatile uint32_t dcfg;
++ /** Device Control Register. <i>Offset: 804h</i> */
++ volatile uint32_t dctl;
++ /** Device Status Register (Read Only). <i>Offset: 808h</i> */
++ volatile uint32_t dsts;
++ /** Reserved. <i>Offset: 80Ch</i> */
++ uint32_t unused;
++ /** Device IN Endpoint Common Interrupt Mask
++ * Register. <i>Offset: 810h</i> */
++ volatile uint32_t diepmsk;
++ /** Device OUT Endpoint Common Interrupt Mask
++ * Register. <i>Offset: 814h</i> */
++ volatile uint32_t doepmsk;
++ /** Device All Endpoints Interrupt Register. <i>Offset: 818h</i> */
++ volatile uint32_t daint;
++ /** Device All Endpoints Interrupt Mask Register. <i>Offset:
++ * 81Ch</i> */
++ volatile uint32_t daintmsk;
++ /** Device IN Token Queue Read Register-1 (Read Only).
++ * <i>Offset: 820h</i> */
++ volatile uint32_t dtknqr1;
++ /** Device IN Token Queue Read Register-2 (Read Only).
++ * <i>Offset: 824h</i> */
++ volatile uint32_t dtknqr2;
++ /** Device VBUS discharge Register. <i>Offset: 828h</i> */
++ volatile uint32_t dvbusdis;
++ /** Device VBUS Pulse Register. <i>Offset: 82Ch</i> */
++ volatile uint32_t dvbuspulse;
++ /** Device IN Token Queue Read Register-3 (Read Only). /
++ * Device Thresholding control register (Read/Write)
++ * <i>Offset: 830h</i> */
++ volatile uint32_t dtknqr3_dthrctl;
++ /** Device IN Token Queue Read Register-4 (Read Only). /
++ * Device IN EPs empty Inr. Mask Register (Read/Write)
++ * <i>Offset: 834h</i> */
++ volatile uint32_t dtknqr4_fifoemptymsk;
++} dwc_otg_device_global_regs_t;
++
++/**
++ * This union represents the bit fields in the Device Configuration
++ * Register. Read the register into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it elements. Write the
++ * <i>d32</i> member to the dcfg register.
++ */
++typedef union dcfg_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ /** Device Speed */
++ unsigned devspd : 2;
++ /** Non Zero Length Status OUT Handshake */
++ unsigned nzstsouthshk : 1;
++#define DWC_DCFG_SEND_STALL 1
++
++ unsigned reserved3 : 1;
++ /** Device Addresses */
++ unsigned devaddr : 7;
++ /** Periodic Frame Interval */
++ unsigned perfrint : 2;
++#define DWC_DCFG_FRAME_INTERVAL_80 0
++#define DWC_DCFG_FRAME_INTERVAL_85 1
++#define DWC_DCFG_FRAME_INTERVAL_90 2
++#define DWC_DCFG_FRAME_INTERVAL_95 3
++
++ unsigned reserved13_17 : 5;
++ /** In Endpoint Mis-match count */
++ unsigned epmscnt : 4;
++ } b;
++} dcfg_data_t;
++
++/**
++ * This union represents the bit fields in the Device Control
++ * Register. Read the register into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it elements.
++ */
++typedef union dctl_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ /** Remote Wakeup */
++ unsigned rmtwkupsig : 1;
++ /** Soft Disconnect */
++ unsigned sftdiscon : 1;
++ /** Global Non-Periodic IN NAK Status */
++ unsigned gnpinnaksts : 1;
++ /** Global OUT NAK Status */
++ unsigned goutnaksts : 1;
++ /** Test Control */
++ unsigned tstctl : 3;
++ /** Set Global Non-Periodic IN NAK */
++ unsigned sgnpinnak : 1;
++ /** Clear Global Non-Periodic IN NAK */
++ unsigned cgnpinnak : 1;
++ /** Set Global OUT NAK */
++ unsigned sgoutnak : 1;
++ /** Clear Global OUT NAK */
++ unsigned cgoutnak : 1;
++
++ unsigned reserved : 21;
++ } b;
++} dctl_data_t;
++
++/**
++ * This union represents the bit fields in the Device Status
++ * Register. Read the register into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it elements.
++ */
++typedef union dsts_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ /** Suspend Status */
++ unsigned suspsts : 1;
++ /** Enumerated Speed */
++ unsigned enumspd : 2;
++#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0
++#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1
++#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2
++#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3
++ /** Erratic Error */
++ unsigned errticerr : 1;
++ unsigned reserved4_7: 4;
++ /** Frame or Microframe Number of the received SOF */
++ unsigned soffn : 14;
++ unsigned reserved22_31 : 10;
++ } b;
++} dsts_data_t;
++
++
++/**
++ * This union represents the bit fields in the Device IN EP Interrupt
++ * Register and the Device IN EP Common Mask Register.
++ *
++ * - Read the register into the <i>d32</i> member then set/clear the
++ * bits using the <i>b</i>it elements.
++ */
++typedef union diepint_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ /** Transfer complete mask */
++ unsigned xfercompl : 1;
++ /** Endpoint disable mask */
++ unsigned epdisabled : 1;
++ /** AHB Error mask */
++ unsigned ahberr : 1;
++ /** TimeOUT Handshake mask (non-ISOC EPs) */
++ unsigned timeout : 1;
++ /** IN Token received with TxF Empty mask */
++ unsigned intktxfemp : 1;
++ /** IN Token Received with EP mismatch mask */
++ unsigned intknepmis : 1;
++ /** IN Endpoint HAK Effective mask */
++ unsigned inepnakeff : 1;
++ /** IN Endpoint HAK Effective mask */
++ unsigned emptyintr : 1;
++
++ unsigned txfifoundrn : 1;
++
++ unsigned reserved08_31 : 23;
++ } b;
++} diepint_data_t;
++/**
++ * This union represents the bit fields in the Device IN EP Common
++ * Interrupt Mask Register.
++ */
++typedef union diepint_data diepmsk_data_t;
++
++/**
++ * This union represents the bit fields in the Device OUT EP Interrupt
++ * Registerand Device OUT EP Common Interrupt Mask Register.
++ *
++ * - Read the register into the <i>d32</i> member then set/clear the
++ * bits using the <i>b</i>it elements.
++ */
++typedef union doepint_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ /** Transfer complete */
++ unsigned xfercompl : 1;
++ /** Endpoint disable */
++ unsigned epdisabled : 1;
++ /** AHB Error */
++ unsigned ahberr : 1;
++ /** Setup Phase Done (contorl EPs) */
++ unsigned setup : 1;
++ unsigned reserved04_31 : 28;
++ } b;
++} doepint_data_t;
++/**
++ * This union represents the bit fields in the Device OUT EP Common
++ * Interrupt Mask Register.
++ */
++typedef union doepint_data doepmsk_data_t;
++
++
++/**
++ * This union represents the bit fields in the Device All EP Interrupt
++ * and Mask Registers.
++ * - Read the register into the <i>d32</i> member then set/clear the
++ * bits using the <i>b</i>it elements.
++ */
++typedef union daint_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ /** IN Endpoint bits */
++ unsigned in : 16;
++ /** OUT Endpoint bits */
++ unsigned out : 16;
++ } ep;
++ struct
++ {
++ /** IN Endpoint bits */
++ unsigned inep0 : 1;
++ unsigned inep1 : 1;
++ unsigned inep2 : 1;
++ unsigned inep3 : 1;
++ unsigned inep4 : 1;
++ unsigned inep5 : 1;
++ unsigned inep6 : 1;
++ unsigned inep7 : 1;
++ unsigned inep8 : 1;
++ unsigned inep9 : 1;
++ unsigned inep10 : 1;
++ unsigned inep11 : 1;
++ unsigned inep12 : 1;
++ unsigned inep13 : 1;
++ unsigned inep14 : 1;
++ unsigned inep15 : 1;
++ /** OUT Endpoint bits */
++ unsigned outep0 : 1;
++ unsigned outep1 : 1;
++ unsigned outep2 : 1;
++ unsigned outep3 : 1;
++ unsigned outep4 : 1;
++ unsigned outep5 : 1;
++ unsigned outep6 : 1;
++ unsigned outep7 : 1;
++ unsigned outep8 : 1;
++ unsigned outep9 : 1;
++ unsigned outep10 : 1;
++ unsigned outep11 : 1;
++ unsigned outep12 : 1;
++ unsigned outep13 : 1;
++ unsigned outep14 : 1;
++ unsigned outep15 : 1;
++ } b;
++} daint_data_t;
++
++/**
++ * This union represents the bit fields in the Device IN Token Queue
++ * Read Registers.
++ * - Read the register into the <i>d32</i> member.
++ * - READ-ONLY Register
++ */
++typedef union dtknq1_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ /** In Token Queue Write Pointer */
++ unsigned intknwptr : 5;
++ /** Reserved */
++ unsigned reserved05_06 : 2;
++ /** write pointer has wrapped. */
++ unsigned wrap_bit : 1;
++ /** EP Numbers of IN Tokens 0 ... 4 */
++ unsigned epnums0_5 : 24;
++ } b;
++} dtknq1_data_t;
++
++/**
++ * This union represents Threshold control Register
++ * - Read and write the register into the <i>d32</i> member.
++ * - READ-WRITABLE Register
++ */
++typedef union dthrctl_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ /** non ISO Tx Thr. Enable */
++ unsigned non_iso_thr_en : 1;
++ /** ISO Tx Thr. Enable */
++ unsigned iso_thr_en : 1;
++ /** Tx Thr. Length */
++ unsigned tx_thr_len : 9;
++ /** Reserved */
++ unsigned reserved11_15 : 5;
++ /** Rx Thr. Enable */
++ unsigned rx_thr_en : 1;
++ /** Rx Thr. Length */
++ unsigned rx_thr_len : 9;
++ /** Reserved */
++ unsigned reserved26 : 1;
++ /** Arbiter Parking Enable */ //AlenOh
++ unsigned arb_prk_en : 1;
++ /** Reserved */ //AlenOh
++ unsigned reservied28_31 : 4;
++ } b;
++} dthrctl_data_t;
++
++
++/**
++ * Device Logical IN Endpoint-Specific Registers. <i>Offsets
++ * 900h-AFCh</i>
++ *
++ * There will be one set of endpoint registers per logical endpoint
++ * implemented.
++ *
++ * <i>These registers are visible only in Device mode and must not be
++ * accessed in Host mode, as the results are unknown.</i>
++ */
++typedef struct dwc_otg_dev_in_ep_regs
++{
++ /** Device IN Endpoint Control Register. <i>Offset:900h +
++ * (ep_num * 20h) + 00h</i> */
++ volatile uint32_t diepctl;
++ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 04h</i> */
++ uint32_t reserved04;
++ /** Device IN Endpoint Interrupt Register. <i>Offset:900h +
++ * (ep_num * 20h) + 08h</i> */
++ volatile uint32_t diepint;
++ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 0Ch</i> */
++ uint32_t reserved0C;
++ /** Device IN Endpoint Transfer Size
++ * Register. <i>Offset:900h + (ep_num * 20h) + 10h</i> */
++ volatile uint32_t dieptsiz;
++ /** Device IN Endpoint DMA Address Register. <i>Offset:900h +
++ * (ep_num * 20h) + 14h</i> */
++ volatile uint32_t diepdma;
++ /** Device IN Endpoint Transmit FIFO Status Register. <i>Offset:900h +
++ * (ep_num * 20h) + 18h</i> */
++ volatile uint32_t dtxfsts;
++ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 1Ch - 900h +
++ * (ep_num * 20h) + 1Ch</i>*/
++ uint32_t reserved18;
++} dwc_otg_dev_in_ep_regs_t;
++
++/**
++ * Device Logical OUT Endpoint-Specific Registers. <i>Offsets:
++ * B00h-CFCh</i>
++ *
++ * There will be one set of endpoint registers per logical endpoint
++ * implemented.
++ *
++ * <i>These registers are visible only in Device mode and must not be
++ * accessed in Host mode, as the results are unknown.</i>
++ */
++typedef struct dwc_otg_dev_out_ep_regs
++{
++ /** Device OUT Endpoint Control Register. <i>Offset:B00h +
++ * (ep_num * 20h) + 00h</i> */
++ volatile uint32_t doepctl;
++ /** Device OUT Endpoint Frame number Register. <i>Offset:
++ * B00h + (ep_num * 20h) + 04h</i> */
++ volatile uint32_t doepfn;
++ /** Device OUT Endpoint Interrupt Register. <i>Offset:B00h +
++ * (ep_num * 20h) + 08h</i> */
++ volatile uint32_t doepint;
++ /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 0Ch</i> */
++ uint32_t reserved0C;
++ /** Device OUT Endpoint Transfer Size Register. <i>Offset:
++ * B00h + (ep_num * 20h) + 10h</i> */
++ volatile uint32_t doeptsiz;
++ /** Device OUT Endpoint DMA Address Register. <i>Offset:B00h
++ * + (ep_num * 20h) + 14h</i> */
++ volatile uint32_t doepdma;
++ /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 18h - B00h +
++ * (ep_num * 20h) + 1Ch</i> */
++ uint32_t unused[2];
++} dwc_otg_dev_out_ep_regs_t;
++
++/**
++ * This union represents the bit fields in the Device EP Control
++ * Register. Read the register into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it elements.
++ */
++typedef union depctl_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ /** Maximum Packet Size
++ * IN/OUT EPn
++ * IN/OUT EP0 - 2 bits
++ * 2'b00: 64 Bytes
++ * 2'b01: 32
++ * 2'b10: 16
++ * 2'b11: 8 */
++ unsigned mps : 11;
++#define DWC_DEP0CTL_MPS_64 0
++#define DWC_DEP0CTL_MPS_32 1
++#define DWC_DEP0CTL_MPS_16 2
++#define DWC_DEP0CTL_MPS_8 3
++
++ /** Next Endpoint
++ * IN EPn/IN EP0
++ * OUT EPn/OUT EP0 - reserved */
++ unsigned nextep : 4;
++
++ /** USB Active Endpoint */
++ unsigned usbactep : 1;
++
++ /** Endpoint DPID (INTR/Bulk IN and OUT endpoints)
++ * This field contains the PID of the packet going to
++ * be received or transmitted on this endpoint. The
++ * application should program the PID of the first
++ * packet going to be received or transmitted on this
++ * endpoint , after the endpoint is
++ * activated. Application use the SetD1PID and
++ * SetD0PID fields of this register to program either
++ * D0 or D1 PID.
++ *
++ * The encoding for this field is
++ * - 0: D0
++ * - 1: D1
++ */
++ unsigned dpid : 1;
++
++ /** NAK Status */
++ unsigned naksts : 1;
++
++ /** Endpoint Type
++ * 2'b00: Control
++ * 2'b01: Isochronous
++ * 2'b10: Bulk
++ * 2'b11: Interrupt */
++ unsigned eptype : 2;
++
++ /** Snoop Mode
++ * OUT EPn/OUT EP0
++ * IN EPn/IN EP0 - reserved */
++ unsigned snp : 1;
++
++ /** Stall Handshake */
++ unsigned stall : 1;
++
++ /** Tx Fifo Number
++ * IN EPn/IN EP0
++ * OUT EPn/OUT EP0 - reserved */
++ unsigned txfnum : 4;
++
++ /** Clear NAK */
++ unsigned cnak : 1;
++ /** Set NAK */
++ unsigned snak : 1;
++ /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints)
++ * Writing to this field sets the Endpoint DPID (DPID)
++ * field in this register to DATA0. Set Even
++ * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints)
++ * Writing to this field sets the Even/Odd
++ * (micro)frame (EO_FrNum) field to even (micro)
++ * frame.
++ */
++ unsigned setd0pid : 1;
++ /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints)
++ * Writing to this field sets the Endpoint DPID (DPID)
++ * field in this register to DATA1 Set Odd
++ * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints)
++ * Writing to this field sets the Even/Odd
++ * (micro)frame (EO_FrNum) field to odd (micro) frame.
++ */
++ unsigned setd1pid : 1;
++
++ /** Endpoint Disable */
++ unsigned epdis : 1;
++ /** Endpoint Enable */
++ unsigned epena : 1;
++ } b;
++} depctl_data_t;
++
++/**
++ * This union represents the bit fields in the Device EP Transfer
++ * Size Register. Read the register into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it elements.
++ */
++typedef union deptsiz_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct {
++ /** Transfer size */
++ unsigned xfersize : 19;
++ /** Packet Count */
++ unsigned pktcnt : 10;
++ /** Multi Count - Periodic IN endpoints */
++ unsigned mc : 2;
++ unsigned reserved : 1;
++ } b;
++} deptsiz_data_t;
++
++/**
++ * This union represents the bit fields in the Device EP 0 Transfer
++ * Size Register. Read the register into the <i>d32</i> member then
++ * set/clear the bits using the <i>b</i>it elements.
++ */
++typedef union deptsiz0_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct {
++ /** Transfer size */
++ unsigned xfersize : 7;
++ /** Reserved */
++ unsigned reserved7_18 : 12;
++ /** Packet Count */
++ unsigned pktcnt : 1;
++ /** Reserved */
++ unsigned reserved20_28 : 9;
++ /**Setup Packet Count (DOEPTSIZ0 Only) */
++ unsigned supcnt : 2;
++ unsigned reserved31;
++ } b;
++} deptsiz0_data_t;
++
++
++/** Maximum number of Periodic FIFOs */
++#define MAX_PERIO_FIFOS 15
++/** Maximum number of Periodic FIFOs */
++#define MAX_TX_FIFOS 15
++
++/** Maximum number of Endpoints/HostChannels */
++#define MAX_EPS_CHANNELS 16
++
++/**
++ * The dwc_otg_dev_if structure contains information needed to manage
++ * the DWC_otg controller acting in device mode. It represents the
++ * programming view of the device-specific aspects of the controller.
++ */
++typedef struct dwc_otg_dev_if
++{
++ /** Pointer to device Global registers.
++ * Device Global Registers starting at offset 800h
++ */
++ dwc_otg_device_global_regs_t *dev_global_regs;
++#define DWC_DEV_GLOBAL_REG_OFFSET 0x800
++
++ /**
++ * Device Logical IN Endpoint-Specific Registers 900h-AFCh
++ */
++ dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS];
++#define DWC_DEV_IN_EP_REG_OFFSET 0x900
++#define DWC_EP_REG_OFFSET 0x20
++
++ /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */
++ dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];
++#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00
++
++ /* Device configuration information*/
++ uint8_t speed; /**< Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS */
++ uint8_t num_in_eps; /**< Number # of Tx EP range: 0-15 exept ep0 */
++ uint8_t num_out_eps; /**< Number # of Rx EP range: 0-15 exept ep 0*/
++
++ /** Size of periodic FIFOs (Bytes) */
++ uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS];
++
++ /** Size of Tx FIFOs (Bytes) */
++ uint16_t tx_fifo_size[MAX_TX_FIFOS];
++
++ /** Thresholding enable flags and length varaiables **/
++ uint16_t rx_thr_en;
++ uint16_t iso_tx_thr_en;
++ uint16_t non_iso_tx_thr_en;
++
++ uint16_t rx_thr_length;
++ uint16_t tx_thr_length;
++
++} dwc_otg_dev_if_t;
++
++
++
++
++/////////////////////////////////////////////////
++// Host Mode Register Structures
++//
++/**
++ * The Host Global Registers structure defines the size and relative
++ * field offsets for the Host Mode Global Registers. Host Global
++ * Registers offsets 400h-7FFh.
++*/
++typedef struct dwc_otg_host_global_regs
++{
++ /** Host Configuration Register. <i>Offset: 400h</i> */
++ volatile uint32_t hcfg;
++ /** Host Frame Interval Register. <i>Offset: 404h</i> */
++ volatile uint32_t hfir;
++ /** Host Frame Number / Frame Remaining Register. <i>Offset: 408h</i> */
++ volatile uint32_t hfnum;
++ /** Reserved. <i>Offset: 40Ch</i> */
++ uint32_t reserved40C;
++ /** Host Periodic Transmit FIFO/ Queue Status Register. <i>Offset: 410h</i> */
++ volatile uint32_t hptxsts;
++ /** Host All Channels Interrupt Register. <i>Offset: 414h</i> */
++ volatile uint32_t haint;
++ /** Host All Channels Interrupt Mask Register. <i>Offset: 418h</i> */
++ volatile uint32_t haintmsk;
++} dwc_otg_host_global_regs_t;
++
++/**
++ * This union represents the bit fields in the Host Configuration Register.
++ * Read the register into the <i>d32</i> member then set/clear the bits using
++ * the <i>b</i>it elements. Write the <i>d32</i> member to the hcfg register.
++ */
++typedef union hcfg_data
++{
++ /** raw register data */
++ uint32_t d32;
++
++ /** register bits */
++ struct
++ {
++ /** FS/LS Phy Clock Select */
++ unsigned fslspclksel : 2;
++#define DWC_HCFG_30_60_MHZ 0
++#define DWC_HCFG_48_MHZ 1
++#define DWC_HCFG_6_MHZ 2
++
++ /** FS/LS Only Support */
++ unsigned fslssupp : 1;
++ } b;
++} hcfg_data_t;
++
++/**
++ * This union represents the bit fields in the Host Frame Remaing/Number
++ * Register.
++ */
++typedef union hfir_data
++{
++ /** raw register data */
++ uint32_t d32;
++
++ /** register bits */
++ struct
++ {
++ unsigned frint : 16;
++ unsigned reserved : 16;
++ } b;
++} hfir_data_t;
++
++/**
++ * This union represents the bit fields in the Host Frame Remaing/Number
++ * Register.
++ */
++typedef union hfnum_data
++{
++ /** raw register data */
++ uint32_t d32;
++
++ /** register bits */
++ struct
++ {
++ unsigned frnum : 16;
++#define DWC_HFNUM_MAX_FRNUM 0x3FFF
++ unsigned frrem : 16;
++ } b;
++} hfnum_data_t;
++
++typedef union hptxsts_data
++{
++ /** raw register data */
++ uint32_t d32;
++
++ /** register bits */
++ struct
++ {
++ unsigned ptxfspcavail : 16;
++ unsigned ptxqspcavail : 8;
++ /** Top of the Periodic Transmit Request Queue
++ * - bit 24 - Terminate (last entry for the selected channel)
++ * - bits 26:25 - Token Type
++ * - 2'b00 - Zero length
++ * - 2'b01 - Ping
++ * - 2'b10 - Disable
++ * - bits 30:27 - Channel Number
++ * - bit 31 - Odd/even microframe
++ */
++ unsigned ptxqtop_terminate : 1;
++ unsigned ptxqtop_token : 2;
++ unsigned ptxqtop_chnum : 4;
++ unsigned ptxqtop_odd : 1;
++ } b;
++} hptxsts_data_t;
++
++/**
++ * This union represents the bit fields in the Host Port Control and Status
++ * Register. Read the register into the <i>d32</i> member then set/clear the
++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
++ * hprt0 register.
++ */
++typedef union hprt0_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned prtconnsts : 1;
++ unsigned prtconndet : 1;
++ unsigned prtena : 1;
++ unsigned prtenchng : 1;
++ unsigned prtovrcurract : 1;
++ unsigned prtovrcurrchng : 1;
++ unsigned prtres : 1;
++ unsigned prtsusp : 1;
++ unsigned prtrst : 1;
++ unsigned reserved9 : 1;
++ unsigned prtlnsts : 2;
++ unsigned prtpwr : 1;
++ unsigned prttstctl : 4;
++ unsigned prtspd : 2;
++#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0
++#define DWC_HPRT0_PRTSPD_FULL_SPEED 1
++#define DWC_HPRT0_PRTSPD_LOW_SPEED 2
++ unsigned reserved19_31 : 13;
++ } b;
++} hprt0_data_t;
++
++/**
++ * This union represents the bit fields in the Host All Interrupt
++ * Register.
++ */
++typedef union haint_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned ch0 : 1;
++ unsigned ch1 : 1;
++ unsigned ch2 : 1;
++ unsigned ch3 : 1;
++ unsigned ch4 : 1;
++ unsigned ch5 : 1;
++ unsigned ch6 : 1;
++ unsigned ch7 : 1;
++ unsigned ch8 : 1;
++ unsigned ch9 : 1;
++ unsigned ch10 : 1;
++ unsigned ch11 : 1;
++ unsigned ch12 : 1;
++ unsigned ch13 : 1;
++ unsigned ch14 : 1;
++ unsigned ch15 : 1;
++ unsigned reserved : 16;
++ } b;
++
++ struct
++ {
++ unsigned chint : 16;
++ unsigned reserved : 16;
++ } b2;
++} haint_data_t;
++
++/**
++ * This union represents the bit fields in the Host All Interrupt
++ * Register.
++ */
++typedef union haintmsk_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ unsigned ch0 : 1;
++ unsigned ch1 : 1;
++ unsigned ch2 : 1;
++ unsigned ch3 : 1;
++ unsigned ch4 : 1;
++ unsigned ch5 : 1;
++ unsigned ch6 : 1;
++ unsigned ch7 : 1;
++ unsigned ch8 : 1;
++ unsigned ch9 : 1;
++ unsigned ch10 : 1;
++ unsigned ch11 : 1;
++ unsigned ch12 : 1;
++ unsigned ch13 : 1;
++ unsigned ch14 : 1;
++ unsigned ch15 : 1;
++ unsigned reserved : 16;
++ } b;
++
++ struct
++ {
++ unsigned chint : 16;
++ unsigned reserved : 16;
++ } b2;
++} haintmsk_data_t;
++
++/**
++ * Host Channel Specific Registers. <i>500h-5FCh</i>
++ */
++typedef struct dwc_otg_hc_regs
++{
++ /** Host Channel 0 Characteristic Register. <i>Offset: 500h + (chan_num * 20h) + 00h</i> */
++ volatile uint32_t hcchar;
++ /** Host Channel 0 Split Control Register. <i>Offset: 500h + (chan_num * 20h) + 04h</i> */
++ volatile uint32_t hcsplt;
++ /** Host Channel 0 Interrupt Register. <i>Offset: 500h + (chan_num * 20h) + 08h</i> */
++ volatile uint32_t hcint;
++ /** Host Channel 0 Interrupt Mask Register. <i>Offset: 500h + (chan_num * 20h) + 0Ch</i> */
++ volatile uint32_t hcintmsk;
++ /** Host Channel 0 Transfer Size Register. <i>Offset: 500h + (chan_num * 20h) + 10h</i> */
++ volatile uint32_t hctsiz;
++ /** Host Channel 0 DMA Address Register. <i>Offset: 500h + (chan_num * 20h) + 14h</i> */
++ volatile uint32_t hcdma;
++ /** Reserved. <i>Offset: 500h + (chan_num * 20h) + 18h - 500h + (chan_num * 20h) + 1Ch</i> */
++ uint32_t reserved[2];
++} dwc_otg_hc_regs_t;
++
++/**
++ * This union represents the bit fields in the Host Channel Characteristics
++ * Register. Read the register into the <i>d32</i> member then set/clear the
++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
++ * hcchar register.
++ */
++typedef union hcchar_data
++{
++ /** raw register data */
++ uint32_t d32;
++
++ /** register bits */
++ struct
++ {
++ /** Maximum packet size in bytes */
++ unsigned mps : 11;
++
++ /** Endpoint number */
++ unsigned epnum : 4;
++
++ /** 0: OUT, 1: IN */
++ unsigned epdir : 1;
++
++ unsigned reserved : 1;
++
++ /** 0: Full/high speed device, 1: Low speed device */
++ unsigned lspddev : 1;
++
++ /** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */
++ unsigned eptype : 2;
++
++ /** Packets per frame for periodic transfers. 0 is reserved. */
++ unsigned multicnt : 2;
++
++ /** Device address */
++ unsigned devaddr : 7;
++
++ /**
++ * Frame to transmit periodic transaction.
++ * 0: even, 1: odd
++ */
++ unsigned oddfrm : 1;
++
++ /** Channel disable */
++ unsigned chdis : 1;
++
++ /** Channel enable */
++ unsigned chen : 1;
++ } b;
++} hcchar_data_t;
++
++typedef union hcsplt_data
++{
++ /** raw register data */
++ uint32_t d32;
++
++ /** register bits */
++ struct
++ {
++ /** Port Address */
++ unsigned prtaddr : 7;
++
++ /** Hub Address */
++ unsigned hubaddr : 7;
++
++ /** Transaction Position */
++ unsigned xactpos : 2;
++#define DWC_HCSPLIT_XACTPOS_MID 0
++#define DWC_HCSPLIT_XACTPOS_END 1
++#define DWC_HCSPLIT_XACTPOS_BEGIN 2
++#define DWC_HCSPLIT_XACTPOS_ALL 3
++
++ /** Do Complete Split */
++ unsigned compsplt : 1;
++
++ /** Reserved */
++ unsigned reserved : 14;
++
++ /** Split Enble */
++ unsigned spltena : 1;
++ } b;
++} hcsplt_data_t;
++
++
++/**
++ * This union represents the bit fields in the Host All Interrupt
++ * Register.
++ */
++typedef union hcint_data
++{
++ /** raw register data */
++ uint32_t d32;
++ /** register bits */
++ struct
++ {
++ /** Transfer Complete */
++ unsigned xfercomp : 1;
++ /** Channel Halted */
++ unsigned chhltd : 1;
++ /** AHB Error */
++ unsigned ahberr : 1;
++ /** STALL Response Received */
++ unsigned stall : 1;
++ /** NAK Response Received */
++ unsigned nak : 1;
++ /** ACK Response Received */
++ unsigned ack : 1;
++ /** NYET Response Received */
++ unsigned nyet : 1;
++ /** Transaction Err */
++ unsigned xacterr : 1;
++ /** Babble Error */
++ unsigned bblerr : 1;
++ /** Frame Overrun */
++ unsigned frmovrun : 1;
++ /** Data Toggle Error */
++ unsigned datatglerr : 1;
++ /** Reserved */
++ unsigned reserved : 21;
++ } b;
++} hcint_data_t;
++
++/**
++ * This union represents the bit fields in the Host Channel Transfer Size
++ * Register. Read the register into the <i>d32</i> member then set/clear the
++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
++ * hcchar register.
++ */
++typedef union hctsiz_data
++{
++ /** raw register data */
++ uint32_t d32;
++
++ /** register bits */
++ struct
++ {
++ /** Total transfer size in bytes */
++ unsigned xfersize : 19;
++
++ /** Data packets to transfer */
++ unsigned pktcnt : 10;
++
++ /**
++ * Packet ID for next data packet
++ * 0: DATA0
++ * 1: DATA2
++ * 2: DATA1
++ * 3: MDATA (non-Control), SETUP (Control)
++ */
++ unsigned pid : 2;
++#define DWC_HCTSIZ_DATA0 0
++#define DWC_HCTSIZ_DATA1 2
++#define DWC_HCTSIZ_DATA2 1
++#define DWC_HCTSIZ_MDATA 3
++#define DWC_HCTSIZ_SETUP 3
++
++ /** Do PING protocol when 1 */
++ unsigned dopng : 1;
++ } b;
++} hctsiz_data_t;
++
++/**
++ * This union represents the bit fields in the Host Channel Interrupt Mask
++ * Register. Read the register into the <i>d32</i> member then set/clear the
++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the
++ * hcintmsk register.
++ */
++typedef union hcintmsk_data
++{
++ /** raw register data */
++ uint32_t d32;
++
++ /** register bits */
++ struct
++ {
++ unsigned xfercompl : 1;
++ unsigned chhltd : 1;
++ unsigned ahberr : 1;
++ unsigned stall : 1;
++ unsigned nak : 1;
++ unsigned ack : 1;
++ unsigned nyet : 1;
++ unsigned xacterr : 1;
++ unsigned bblerr : 1;
++ unsigned frmovrun : 1;
++ unsigned datatglerr : 1;
++ unsigned reserved : 21;
++ } b;
++} hcintmsk_data_t;
++
++/** OTG Host Interface Structure.
++ *
++ * The OTG Host Interface Structure structure contains information
++ * needed to manage the DWC_otg controller acting in host mode. It
++ * represents the programming view of the host-specific aspects of the
++ * controller.
++ */
++typedef struct dwc_otg_host_if
++{
++ /** Host Global Registers starting at offset 400h.*/
++ dwc_otg_host_global_regs_t *host_global_regs;
++#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400
++
++ /** Host Port 0 Control and Status Register */
++ volatile uint32_t *hprt0;
++#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440
++
++
++ /** Host Channel Specific Registers at offsets 500h-5FCh. */
++ dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS];
++#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500
++#define DWC_OTG_CHAN_REGS_OFFSET 0x20
++
++
++ /* Host configuration information */
++ /** Number of Host Channels (range: 1-16) */
++ uint8_t num_host_channels;
++ /** Periodic EPs supported (0: no, 1: yes) */
++ uint8_t perio_eps_supported;
++ /** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */
++ uint16_t perio_tx_fifo_size;
++
++} dwc_otg_host_if_t;
++
++
++/**
++ * This union represents the bit fields in the Power and Clock Gating Control
++ * Register. Read the register into the <i>d32</i> member then set/clear the
++ * bits using the <i>b</i>it elements.
++ */
++typedef union pcgcctl_data
++{
++ /** raw register data */
++ uint32_t d32;
++
++ /** register bits */
++ struct
++ {
++ /** Stop Pclk */
++ unsigned stoppclk : 1;
++ /** Gate Hclk */
++ unsigned gatehclk : 1;
++ /** Power Clamp */
++ unsigned pwrclmp : 1;
++ /** Reset Power Down Modules */
++ unsigned rstpdwnmodule : 1;
++ /** PHY Suspended */
++ unsigned physuspended : 1;
++
++ unsigned reserved : 27;
++ } b;
++} pcgcctl_data_t;
++
++
++#endif
+diff --git a/drivers/usb/dwc_otg/tcc_usb_def.h b/drivers/usb/dwc_otg/tcc_usb_def.h
+new file mode 100644
+index 0000000..5d7fb71
+--- /dev/null
++++ b/drivers/usb/dwc_otg/tcc_usb_def.h
+@@ -0,0 +1,59 @@
++/*
++ *
++ */
++#ifndef __TCC_USB_DEF_H__
++#define __TCC_USB_DEF_H__
++
++#include <bsp.h>
++
++//===================================================================
++//
++// DRIVER SIGNATURE
++//
++//===================================================================
++#define SIGBYAHONG 'S','I','G','B','Y','A','H','O','N','G','_'
++
++#if defined(_WINCE_)
++#define SIGN_OS 'W','I','N','C','E','_'
++#elif defined(_LINUX_)
++#define SIGN_OS 'L','I','N','U','X','_'
++#else
++#define SIGN_OS 'N','U','_'
++#endif
++
++#if defined(TCC77X)
++#define SIGN_CHIPSET 'T','C','C','7','7','X','X','_'
++#elif defined(TCC78X)
++#define SIGN_CHIPSET 'T','C','C','7','8','X','X','_'
++#elif defined(TCC79X)
++#define SIGN_CHIPSET 'T','C','C','7','9','X','X','_'
++#elif defined(TCC81XX)
++#define SIGN_CHIPSET 'T','C','C','8','1','X','X','_'
++#elif defined(TCC82XX)
++#define SIGN_CHIPSET 'T','C','C','8','2','X','X','_'
++#elif defined(TCC83XX)
++#define SIGN_CHIPSET 'T','C','C','8','3','X','X','_'
++#elif defined(TCC87XX)
++#define SIGN_CHIPSET 'T','C','C','8','7','X','X','_'
++#elif defined(CONFIG_MACH_TCC8900)
++#define SIGN_CHIPSET 'T','C','C','8','9','X','X','_'
++#elif defined(TCC91XX)
++#define SIGN_CHIPSET 'T','C','C','9','1','X','X','_'
++#elif defined(TCC92XX)
++#define SIGN_CHIPSET 'T','C','C','9','2','X','X','_'
++#else
++#error
++#endif
++
++
++typedef enum {
++ USB_MODE_NONE,
++ USB_MODE_HOST,
++ USB_MODE_DEVICE
++} USB_MODE_T;
++
++
++#define pUSBPHYCFG ((PUSBPHYCFG)&HwUSBPHYCFG_BASE)
++#define pUSBOTGCFG ((PUSBOTGCFG)&HwUSBOTGCFG_BASE)
++
++#endif /*__TCC_USB_DEF_H__*/
+diff --git a/drivers/usb/dwc_otg/tcc_usb_phy.c b/drivers/usb/dwc_otg/tcc_usb_phy.c
+new file mode 100644
+index 0000000..a1041c3
+--- /dev/null
++++ b/drivers/usb/dwc_otg/tcc_usb_phy.c
+@@ -0,0 +1,181 @@
++/*
++ *
++ */
++#include <linux/kernel.h>
++#include <bsp.h>
++#include <mach/tcc_pca953x.h>
++#include "tcc_usb_def.h"
++#include "tcc_usb_phy.h"
++
++/* For Signature */
++#define TCC_USB_PHY_SIGNATURE 'T','C','C','_','U','S','B','_','P','H','Y','_'
++#define TCC_USB_PHY_VERSION 'V','2','.','0','0','0'
++static const unsigned char TCC_USB_PHY_C_Version[] =
++ {SIGBYAHONG, TCC_USB_PHY_SIGNATURE, SIGN_OS ,SIGN_CHIPSET, TCC_USB_PHY_VERSION, 0};
++
++#define UPCR0_PR Hw14 // (1:enable)/(0:disable) Port Reset
++#define UPCR0_CM_EN Hw13 // Common Block Power Down Enable
++#define UPCR0_CM_DIS ~Hw13 // Common Block Power Down Disable
++#define UPCR0_RCS_11 (Hw12+Hw11) // Reference Clock Select for PLL Block ; The PLL uses CLKCORE as reference
++#define UPCR0_RCS_10 Hw12 // Reference Clock Select for PLL Block ; The PLL uses CLKCORE as reference
++#define UPCR0_RCS_01 Hw11 // Reference Clock Select for PLL Block ; The XO block uses an external clock supplied on the XO pin
++#define UPCR0_RCS_00 ((~Hw12)&(~Hw11)) // Reference Clock Select for PLL Block ; The XO block uses the clock from a crystal
++#define UPCR0_RCD_48 Hw10 // Reference Clock Frequency Select ; 48MHz
++#define UPCR0_RCD_24 Hw9 // Reference Clock Frequency Select ; 24MHz
++#define UPCR0_RCD_12 ((~Hw10)&(~Hw9)) // Reference Clock Frequency Select ; 12MHz
++#define UPCR0_SDI_EN Hw8 // IDDQ Test Enable ; The analog blocks are powered down
++#define UPCR0_SDI_DIS ~Hw8 // IDDQ Test Disable ; The analog blocks are not powered down
++#define UPCR0_FO_SI Hw7 // UTMI/Serial Interface Select ; Serial Interface
++#define UPCR0_FO_UTMI ~Hw7 // UTMI/Serial Interface Select ; UTMI
++#define UPCR0_VBDS Hw6
++#define UPCR0_DMPD Hw5 // 1:enable / 0:disable the pull-down resistance on D-
++#define UPCR0_DPPD Hw4 // 1: enable, 0:disable the pull-down resistance on D+
++#define UPCR0_VBD Hw1 // The VBUS signal is (1:valid)/(0:invalid), and the pull-up resistor on D+ is (1:enabled)/(0:disabled)
++
++#define UPCR1_TXFSLST(x) ((x&0xF)<<12)
++#define UPCR1_SQRXT(x) ((x&0x7)<<8)
++#define UPCR1_OTGT(x) ((x&0x7)<<4)
++#define UPCR1_CDT(x) (x&0x7)
++
++#define UPCR2_TM_FS Hw14
++#define UPCR2_TM_HS 0
++#define UPCR2_XCVRSEL_LS_ON_FS (Hw13|Hw12)
++#define UPCR2_XCVRSEL_LS Hw13
++#define UPCR2_XCVRSEL_FS Hw12
++#define UPCR2_XCVRSEL_HS 0
++#define UPCR2_OPMODE_MASK (Hw10|Hw9)
++#define UPCR2_OPMODE_SYNC_EOP (Hw10|Hw9)
++#define UPCR2_OPMODE_DIS_BITS_NRZI Hw10
++#define UPCR2_OPMODE_NON_DRVING Hw9
++#define UPCR2_OPMODE_NORMAL 0
++#define UPCR2_TXVRT(x) ((x&0xF)<<5)
++#define UPCR2_TXRT(x) ((x&0x3)<<2)
++#define UPCR2_TP_EN Hw0
++#define UPCR2_TP_DIS 0
++
++
++const unsigned char * USBPHY_GetVersion(void)
++{
++ return TCC_USB_PHY_C_Version;
++}
++
++void USBPHY_EnableClock(void)
++{
++ /* MODE=0 for USBOTG, SDI=0 for turn on all analog blocks */
++ BITCLR(pUSBPHYCFG->UPCR0, Hw15|Hw8);
++}
++
++void USBPHY_SetMode(USBPHY_MODE_T mode)
++{
++ /*if ( mode == USB_MODE_NONE )
++ {
++ pUSBPHYCFG->UPCR0 = 0x2940; // float DP,PM pins
++ }
++ else*/ if ( mode == USBPHY_MODE_RESET )
++ {
++ pUSBPHYCFG->UPCR0 = 0x4870;
++ }
++ else if ( mode == USBPHY_MODE_HOST )
++ {
++ pUSBPHYCFG->UPCR0 = 0x2800;
++ pUSBPHYCFG->UPCR1 =
++ UPCR1_TXFSLST(7) // FS/LS Pull-Up Resistance Adjustment = Design default
++ | UPCR1_SQRXT(3) // Squelch Threshold Tune = -5%
++ | UPCR1_OTGT(4) // VBUS Valid Threshold Adjustment = Design default
++ | UPCR1_CDT(3); // Disconnect Threshold Adjustment = Design default
++ pUSBPHYCFG->UPCR2 =
++ UPCR2_TM_HS
++ | UPCR2_XCVRSEL_HS
++ | UPCR2_OPMODE_NORMAL
++ | UPCR2_TXVRT(10) // HS DC voltage level adjustment = Design default
++ | UPCR2_TXRT(0) // HS Transmitter Rise/Fall Time Adjustment = Design default
++ | UPCR2_TP_EN;
++ //pUSBPHYCFG->UPCR3 = 0x9000; // OTG disable
++ }
++ else if ( mode == USBPHY_MODE_DEVICE )
++ {
++ pUSBPHYCFG->UPCR0 = 0x2800;
++ pUSBPHYCFG->UPCR1 =
++ UPCR1_TXFSLST(7) // FS/LS Pull-Up Resistance Adjustment = Design default
++ | UPCR1_SQRXT(3) // Squelch Threshold Tune = -5%
++ | UPCR1_OTGT(4) // VBUS Valid Threshold Adjustment = Design default
++ | UPCR1_CDT(3); // Disconnect Threshold Adjustment = Design default
++ pUSBPHYCFG->UPCR2 =
++ UPCR2_TM_HS
++ | UPCR2_XCVRSEL_HS
++ | UPCR2_OPMODE_NORMAL
++ | UPCR2_TXVRT(10) // HS DC voltage level adjustment = Design default
++ | UPCR2_TXRT(0) // HS Transmitter Rise/Fall Time Adjustment = Design default
++ | UPCR2_TP_EN;
++ //pUSBPHYCFG->UPCR3 = 0x9000; // OTG disable
++ }
++}
++
++#ifndef OTGID_ID_HOST
++#define OTGID_ID_HOST (~Hw9)
++#endif
++#ifndef OTGID_ID_DEVICE
++#define OTGID_ID_DEVICE Hw9
++#endif
++void USBPHY_SetID(unsigned int ID)
++{
++ if ( ID ) {
++ pUSBOTGCFG->OTGID |= OTGID_ID_DEVICE;
++ } else {
++ pUSBOTGCFG->OTGID &= OTGID_ID_HOST;
++ }
++}
++
++/*
++ * OTG VBUS Power Control. It is controlled GPIO_EXPAND DVBUS_ON.
++ * - Host mode: DVBUS_ON is HIGH
++ * - Device mode: DVBUS_ON is LOW
++ */
++void TCC_DVBUS_Control(int on)
++{
++ if (on) {
++ tcc_pca953x_setup(PCA9538_U4_SLAVE_ADDR, PWR_GP1, OUTPUT, HIGH, SET_DIRECTION|SET_VALUE);
++ tcc_pca953x_setup(PCA9538_U4_SLAVE_ADDR, DVBUS_ON, OUTPUT, HIGH, SET_DIRECTION|SET_VALUE);
++ } else {
++ tcc_pca953x_setup(PCA9538_U4_SLAVE_ADDR, DVBUS_ON, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++#if !defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OHCI_HCD_MODULE)
++ tcc_pca953x_setup(PCA9538_U4_SLAVE_ADDR, PWR_GP1, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++#endif
++ }
++ printk(KERN_DEBUG "DVBUS_ON power %s\n", (tcc_pca953x_setup(PCA9538_U4_SLAVE_ADDR, 0, OUTPUT, 0, GET_VALUE)&DVBUS_ON)?"ON":"OFF");
++ printk(KERN_DEBUG "PWR_GP1 power %s\n", (tcc_pca953x_setup(PCA9538_U4_SLAVE_ADDR, 0, OUTPUT, 0, GET_VALUE)&PWR_GP1)?"ON":"OFF");
++}
++
++/*
++ * USBPHY Power on/off
++ */
++void USBPHY_Off(void)
++{
++#if 1
++ BITCSET(pUSBPHYCFG->UPCR2, Hw10|Hw9/*UPCR2_OPMODE_MASK*/, Hw9/*UPCR2_OPMODE_NON_DRVING*/);
++ pUSBPHYCFG->UPCR0 = 0x4840;
++ pUSBPHYCFG->UPCR0 = 0x6940;
++#else
++ BITSET(pUSBPHYCFG->UPCR0, Hw8);
++#endif
++}
++
++void USBPHY_On(void)
++{
++#if 1
++ BITCSET(pUSBPHYCFG->UPCR2, Hw10|Hw9/*UPCR2_OPMODE_MASK*/, 0/*UPCR2_OPMODE_NORMAL*/);
++ pUSBPHYCFG->UPCR0 = 0x2842;
++#else
++ BITCLR(pUSBPHYCFG->UPCR0, Hw8);
++#endif
++
++}
++
++//void TCC_SetIntr(void)
++//{
++// BITCLR(HwPIC->POL1, HwINT1_UOTG); // 0:active-high / 1:active-low
++// BITSET(HwPIC->MODE1, HwINT1_UOTG); // 1:Level / 0:edge trigger
++// //BITCLR(HwPIC->MODEA1, HwINT1_UOTG); // 0:single edge / 1:both edge
++//}
++
++/* end of file */
+diff --git a/drivers/usb/dwc_otg/tcc_usb_phy.h b/drivers/usb/dwc_otg/tcc_usb_phy.h
+new file mode 100644
+index 0000000..d2b0d60
+--- /dev/null
++++ b/drivers/usb/dwc_otg/tcc_usb_phy.h
+@@ -0,0 +1,24 @@
++/*
++ *
++ */
++#ifndef __TCC_USB_PHY_H__
++#define __TCC_USB_PHY_H__
++
++#include "tcc_usb_def.h"
++
++typedef enum {
++ USBPHY_MODE_RESET,
++ USBPHY_MODE_HOST,
++ USBPHY_MODE_DEVICE
++} USBPHY_MODE_T;
++
++extern const unsigned char * USBPHY_GetVersion(void);
++extern void USBPHY_EnableClock(void);
++extern void USBPHY_SetMode(USBPHY_MODE_T mode);
++void USBPHY_DEVICE_VBUS(unsigned int valid);
++extern void USBPHY_SetID(unsigned int ID);
++extern void TCC_DVBUS_Control(int on);
++extern void USBPHY_On(void);
++extern void USBPHY_Off(void);
++
++#endif /*__TCC_USB_PHY_H__*/
+\ No newline at end of file
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index dd4cd5a..17f2b94 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -15,6 +15,7 @@
+
+ menuconfig USB_GADGET
+ tristate "USB Gadget Support"
++ depends on TCC_DWC_OTG_DUAL_ROLE && TCC_DWC_OTG_DEVICE_ONLY
+ help
+ USB is a master/slave protocol, organized with one master
+ host (such as a PC) controlling up to 127 peripheral devices.
+@@ -119,6 +120,23 @@ choice
+ often need board-specific hooks.
+
+ #
++# Telechips USB DWC OTG Controller
++#
++config USB_GADGET_TCC_OTG
++ boolean "Telechips USB DWC OTG Device Controller"
++ depends on ARCH_TCC && TCC_DWC_OTG
++ select USB_GADGET_SELECTED
++ select USB_GADGET_DUALSPEED
++ help
++ Telechips USB OTG Device Controller Driver
++ Synopsys DesignWare Hi-Speed USB On-The-Go (OTG) Core used on the Telechips SoC.
++
++config USB_TCC_OTG
++ tristate
++ depends on USB_GADGET_TCC_OTG
++ default USB_GADGET
++
++#
+ # Integrated controllers
+ #
+
+diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
+index bd4041b..fe8c700 100644
+--- a/drivers/usb/gadget/Makefile
++++ b/drivers/usb/gadget/Makefile
+@@ -3,6 +3,7 @@
+ #
+ ifeq ($(CONFIG_USB_GADGET_DEBUG),y)
+ EXTRA_CFLAGS += -DDEBUG
++ EXTRA_CFLAGS += -O0
+ endif
+
+ obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
+diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
+index c4e62a6..d1a761a 100644
+--- a/drivers/usb/gadget/file_storage.c
++++ b/drivers/usb/gadget/file_storage.c
+@@ -238,13 +238,15 @@
+ #include <linux/string.h>
+ #include <linux/freezer.h>
+ #include <linux/utsname.h>
++#include <linux/dma-mapping.h>
+
+ #include <linux/usb/ch9.h>
+ #include <linux/usb/gadget.h>
+
+ #include "gadget_chips.h"
+
+-
++#include <bsp.h>
++#include <linux/tcc_ioctl.h>
+
+ /*
+ * Kbuild is not very cooperative with respect to linking separately
+@@ -274,9 +276,15 @@ MODULE_LICENSE("Dual BSD/GPL");
+ *
+ * DO NOT REUSE THESE IDs with any other driver!! Ever!!
+ * Instead: allocate your own, using normal USB-IF procedures. */
++#ifdef CONFIG_ARCH_TCC
++#define DRIVER_VENDOR_ID 0x140e // Telechips
++#define DRIVER_PRODUCT_ID 0xb058 // TCC79x MSC
++#else
+ #define DRIVER_VENDOR_ID 0x0525 // NetChip
+ #define DRIVER_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget
++#endif
+
++#define DMA_MODE
+
+ /*
+ * This driver assumes self-powered hardware and has no way for users to
+@@ -332,14 +340,18 @@ MODULE_LICENSE("Dual BSD/GPL");
+
+ #define MAX_LUNS 8
+
++/* Number of buffers we will use. 2 is enough for double-buffering */
++#define NUM_BUFFERS 2
++
+ static struct {
+- char *file[MAX_LUNS];
+- int ro[MAX_LUNS];
++ char *file[MAX_LUNS];
++ int ro[MAX_LUNS];
++ int can_ioctl[MAX_LUNS];
++ int removable[MAX_LUNS];
+ unsigned int num_filenames;
+ unsigned int num_ros;
+ unsigned int nluns;
+
+- int removable;
+ int can_stall;
+
+ char *transport_parm;
+@@ -357,7 +369,6 @@ static struct {
+ } mod_data = { // Default values
+ .transport_parm = "BBB",
+ .protocol_parm = "SCSI",
+- .removable = 0,
+ .can_stall = 1,
+ .vendor = DRIVER_VENDOR_ID,
+ .product = DRIVER_PRODUCT_ID,
+@@ -550,6 +561,8 @@ struct lun {
+ loff_t num_sectors;
+
+ unsigned int ro : 1;
++ unsigned int can_ioctl : 1;
++ unsigned int removable : 1;
+ unsigned int prevent_medium_removal : 1;
+ unsigned int registered : 1;
+ unsigned int info_valid : 1;
+@@ -573,9 +586,6 @@ static struct lun *dev_to_lun(struct device *dev)
+ #define EP0_BUFSIZE 256
+ #define DELAYED_STATUS (EP0_BUFSIZE + 999) // An impossibly large value
+
+-/* Number of buffers we will use. 2 is enough for double-buffering */
+-#define NUM_BUFFERS 2
+-
+ enum fsg_buffer_state {
+ BUF_STATE_EMPTY = 0,
+ BUF_STATE_FULL,
+@@ -584,6 +594,9 @@ enum fsg_buffer_state {
+
+ struct fsg_buffhd {
+ void *buf;
++ #ifdef DMA_MODE
++ dma_addr_t dma; //for dma (AlenOh)
++ #endif
+ enum fsg_buffer_state state;
+ struct fsg_buffhd *next;
+
+@@ -996,7 +1009,11 @@ ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+ /* The CBI specification limits the serial string to 12 uppercase hexadecimal
+ * characters. */
+ static char manufacturer[64];
++#ifdef CONFIG_ARCH_TCC
++static char serial[]="0123456789ABCDEF0123456789ABCDEF";
++#else
+ static char serial[13];
++#endif
+
+ /* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
+ static struct usb_string strings[] = {
+@@ -1467,7 +1484,9 @@ static int fsg_setup(struct usb_gadget *gadget,
+ dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
+
+ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
++ {
+ rc = class_setup_req(fsg, ctrl);
++ }
+ else
+ rc = standard_setup_req(fsg, ctrl);
+
+@@ -1599,10 +1618,13 @@ static int do_read(struct fsg_dev *fsg)
+ amount = min((unsigned int) amount_left, mod_data.buflen);
+ amount = min((loff_t) amount,
+ curlun->file_length - file_offset);
+- partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
+- if (partial_page > 0)
+- amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
+- partial_page);
++
++ if (curlun->can_ioctl==0)
++ {
++ partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
++ if (partial_page > 0)
++ amount = min(amount, (unsigned int) PAGE_CACHE_SIZE - partial_page);
++ }
+
+ /* Wait for the next buffer to become available */
+ bh = fsg->next_buffhd_to_fill;
+@@ -1626,9 +1648,25 @@ static int do_read(struct fsg_dev *fsg)
+
+ /* Perform the read */
+ file_offset_tmp = file_offset;
+- nread = vfs_read(curlun->filp,
+- (char __user *) bh->buf,
+- amount, &file_offset_tmp);
++ if(curlun->can_ioctl)
++ {
++ struct storage_direct sdArg;
++ sdArg.buf = bh->buf;
++ sdArg.count = (size_t)amount;
++ sdArg.pos = file_offset_tmp;
++ sdArg.actual = 0;
++ sdArg.user_space = 0;
++ if(curlun->filp->f_op->unlocked_ioctl)
++ curlun->filp->f_op->unlocked_ioctl(curlun->filp, IOCTL_STORAGE_DIRECT_READ, (unsigned long)&sdArg);
++ file_offset_tmp = sdArg.pos;
++ nread = sdArg.actual;
++ }
++ else
++ {
++ nread = vfs_read(curlun->filp,
++ (char __user *) bh->buf,
++ amount, &file_offset_tmp);
++ }
+ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
+ (unsigned long long) file_offset,
+ (int) nread);
+@@ -1671,7 +1709,7 @@ static int do_read(struct fsg_dev *fsg)
+ return -EIO; // No default reply
+ }
+
+-
++static unsigned long xp_send_sum = 0;
+ /*-------------------------------------------------------------------------*/
+
+ static int do_write(struct fsg_dev *fsg)
+@@ -1708,8 +1746,10 @@ static int do_write(struct fsg_dev *fsg)
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
++#if 0 /* comment by csduan */
+ if (fsg->cmnd[1] & 0x08) // FUA
+ curlun->filp->f_flags |= O_SYNC;
++#endif /* comment by csduan */
+ }
+ if (lba >= curlun->num_sectors) {
+ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+@@ -1721,6 +1761,16 @@ static int do_write(struct fsg_dev *fsg)
+ file_offset = usb_offset = ((loff_t) lba) << 9;
+ amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
+
++ if(fsg->cmnd[0] != SC_WRITE_6) {
++ if (fsg->cmnd[1] & 0x08) {
++ xp_send_sum += amount_left_to_write;
++ if(xp_send_sum > 50*1024*1024) {
++ xp_send_sum = 0;
++ curlun->filp->f_flags |= O_SYNC;
++ }
++ }
++ }
++
+ while (amount_left_to_write > 0) {
+
+ /* Queue a request for more data from the host */
+@@ -1739,10 +1789,13 @@ static int do_write(struct fsg_dev *fsg)
+ amount = min(amount_left_to_req, mod_data.buflen);
+ amount = min((loff_t) amount, curlun->file_length -
+ usb_offset);
+- partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
+- if (partial_page > 0)
+- amount = min(amount,
+- (unsigned int) PAGE_CACHE_SIZE - partial_page);
++
++ if (curlun->can_ioctl==0)
++ {
++ partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
++ if (partial_page > 0)
++ amount = min(amount, (unsigned int) PAGE_CACHE_SIZE - partial_page);
++ }
+
+ if (amount == 0) {
+ get_some_more = 0;
+@@ -1799,17 +1852,35 @@ static int do_write(struct fsg_dev *fsg)
+ amount = bh->outreq->actual;
+ if (curlun->file_length - file_offset < amount) {
+ LERROR(curlun,
+- "write %u @ %llu beyond end %llu\n",
+- amount, (unsigned long long) file_offset,
+- (unsigned long long) curlun->file_length);
+- amount = curlun->file_length - file_offset;
++ "write %u @ %llu beyond end %llu\n",
++ amount, (unsigned long long) file_offset,
++ (unsigned long long) curlun->file_length);
++ amount = curlun->file_length - file_offset;
+ }
+
+ /* Perform the write */
+ file_offset_tmp = file_offset;
+- nwritten = vfs_write(curlun->filp,
+- (char __user *) bh->buf,
+- amount, &file_offset_tmp);
++
++ if(curlun->can_ioctl)
++ {
++ struct storage_direct sdArg;
++ sdArg.buf = bh->buf;
++ sdArg.count = (size_t)amount;
++ sdArg.pos = file_offset_tmp;
++ sdArg.actual = 0;
++ sdArg.user_space = 0;
++ if(curlun->filp->f_op->unlocked_ioctl)
++ curlun->filp->f_op->unlocked_ioctl(curlun->filp, IOCTL_STORAGE_DIRECT_WRITE, (unsigned long)&sdArg);
++ file_offset_tmp = sdArg.pos;
++ nwritten = sdArg.actual;
++ }
++ else
++ {
++ nwritten = vfs_write(curlun->filp,
++ (char __user *) bh->buf,
++ amount, &file_offset_tmp);
++ }
++
+ VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
+ (unsigned long long) file_offset,
+ (int) nwritten);
+@@ -1984,9 +2055,25 @@ static int do_verify(struct fsg_dev *fsg)
+
+ /* Perform the read */
+ file_offset_tmp = file_offset;
+- nread = vfs_read(curlun->filp,
+- (char __user *) bh->buf,
+- amount, &file_offset_tmp);
++ if(curlun->can_ioctl)
++ {
++ struct storage_direct sdArg;
++ sdArg.buf = bh->buf;
++ sdArg.count = (size_t)amount;
++ sdArg.pos = file_offset_tmp;
++ sdArg.actual = 0;
++ sdArg.user_space = 0;
++ if(curlun->filp->f_op->unlocked_ioctl)
++ curlun->filp->f_op->unlocked_ioctl(curlun->filp, IOCTL_STORAGE_DIRECT_READ, (unsigned long)&sdArg);
++ file_offset_tmp = sdArg.pos;
++ nread = sdArg.actual;
++ }
++ else
++ {
++ nread = vfs_read(curlun->filp,
++ (char __user *) bh->buf,
++ amount, &file_offset_tmp);
++ }
+ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
+ (unsigned long long) file_offset,
+ (int) nread);
+@@ -2021,8 +2108,14 @@ static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+ {
+ u8 *buf = (u8 *) bh->buf;
+
++#ifdef CONFIG_ARCH_TCC
++ static char vendor_id[] = "TELECHIP";
++ static char product_id[] = "MASS STORAGE ";
++ printk("do_inquiry\n");
++#else
+ static char vendor_id[] = "Linux ";
+ static char product_id[] = "File-Stor Gadget";
++#endif
+
+ if (!fsg->curlun) { // Unsupported LUNs are okay
+ fsg->bad_lun_okay = 1;
+@@ -2032,10 +2125,16 @@ static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+ }
+
+ memset(buf, 0, 8); // Non-removable, direct-access device
+- if (mod_data.removable)
++ //if (mod_data.removable)
++ if(fsg->curlun->removable)
+ buf[1] = 0x80;
++#ifdef CONFIG_ARCH_TCC
++ buf[2] = 0; // 0 for UFI device
++ buf[3] = 1; // 1 for UFI device
++#else
+ buf[2] = 2; // ANSI SCSI level 2
+ buf[3] = 2; // SCSI-2 INQUIRY data format
++#endif
+ buf[4] = 31; // Additional length
+ // No special options
+ sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, product_id,
+@@ -2200,7 +2299,8 @@ static int do_start_stop(struct fsg_dev *fsg)
+ struct lun *curlun = fsg->curlun;
+ int loej, start;
+
+- if (!mod_data.removable) {
++ //if (!mod_data.removable) {
++ if (!curlun->removable) {
+ curlun->sense_data = SS_INVALID_COMMAND;
+ return -EINVAL;
+ }
+@@ -2209,7 +2309,8 @@ static int do_start_stop(struct fsg_dev *fsg)
+ loej = fsg->cmnd[4] & 0x02;
+ start = fsg->cmnd[4] & 0x01;
+
+-#ifdef CONFIG_USB_FILE_STORAGE_TEST
++//#ifdef CONFIG_USB_FILE_STORAGE_TEST
++#if 1
+ if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed
+ (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+@@ -2250,7 +2351,8 @@ static int do_prevent_allow(struct fsg_dev *fsg)
+ struct lun *curlun = fsg->curlun;
+ int prevent;
+
+- if (!mod_data.removable) {
++ //if (!mod_data.removable) {
++ if (!curlun->removable) {
+ curlun->sense_data = SS_INVALID_COMMAND;
+ return -EINVAL;
+ }
+@@ -2600,6 +2702,9 @@ static int send_status(struct fsg_dev *fsg)
+
+ fsg->intr_buffhd = bh; // Point to the right buffhd
+ fsg->intreq->buf = bh->inreq->buf;
++ #ifdef DMA_MODE
++ fsg->intreq->dma = bh->inreq->dma; //for dma (AlenOh)
++ #endif
+ fsg->intreq->context = bh;
+ start_transfer(fsg, fsg->intr_in, fsg->intreq,
+ &fsg->intreq_busy, &bh->state);
+@@ -3210,6 +3315,9 @@ reset:
+ if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0)
+ goto reset;
+ bh->inreq->buf = bh->outreq->buf = bh->buf;
++ #ifdef DMA_MODE
++ bh->inreq->dma = bh->outreq->dma = bh->dma; //for dma (AlenOh)
++ #endif
+ bh->inreq->context = bh->outreq->context = bh;
+ bh->inreq->complete = bulk_in_complete;
+ bh->outreq->complete = bulk_out_complete;
+@@ -3529,6 +3637,14 @@ static int open_backing_file(struct lun *curlun, const char *filename)
+ return PTR_ERR(filp);
+ }
+
++ if(curlun->can_ioctl && filp->f_op->unlocked_ioctl)
++ {
++ if(filp->f_op->unlocked_ioctl(filp, IOCTL_STORAGE_PING, 0) != 0 )
++ {
++ curlun->can_ioctl = 0;
++ }
++ }
++
+ if (!(filp->f_mode & FMODE_WRITE))
+ ro = 1;
+
+@@ -3663,6 +3779,12 @@ static ssize_t store_file(struct device *dev, struct device_attribute *attr,
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
+ int rc = 0;
+
++ if( !curlun->removable )
++ {
++ LDBG(curlun, "It's not removable\n");
++ return -EBUSY;
++ }
++
+ if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) {
+ LDBG(curlun, "eject attempt prevented\n");
+ return -EBUSY; // "Door is locked"
+@@ -3745,11 +3867,21 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
+
+ /* Free the data buffers */
+ for (i = 0; i < NUM_BUFFERS; ++i)
++ {
++ #ifdef DMA_MODE
++ dma_free_coherent (NULL, mod_data.buflen, fsg->buffhds[i].buf, fsg->buffhds[i].dma); //for dma (AlenOh)
++ #else
+ kfree(fsg->buffhds[i].buf);
++ #endif
++ }
+
+ /* Free the request and buffer for endpoint 0 */
+ if (req) {
++ #ifdef DMA_MODE
++ dma_free_coherent (NULL, EP0_BUFSIZE, req->buf, req->dma); //for dma (AlenOh)
++ #else
+ kfree(req->buf);
++ #endif
+ usb_ep_free_request(fsg->ep0, req);
+ }
+
+@@ -3762,7 +3894,7 @@ static int __init check_parameters(struct fsg_dev *fsg)
+ int prot;
+ int gcnum;
+
+- /* Store the default values */
++ /* Store the default values */
+ mod_data.transport_type = USB_PR_BULK;
+ mod_data.transport_name = "Bulk-only";
+ mod_data.protocol_type = USB_SC_SCSI;
+@@ -3841,6 +3973,17 @@ static int __init check_parameters(struct fsg_dev *fsg)
+ return 0;
+ }
+
++static int fsg_removable(void)
++{
++ unsigned int i;
++ for(i=0;i<mod_data.nluns;i++)
++ {
++ if(mod_data.removable[i])
++ return 1;
++ }
++
++ return 0;
++}
+
+ static int __init fsg_bind(struct usb_gadget *gadget)
+ {
+@@ -3852,19 +3995,26 @@ static int __init fsg_bind(struct usb_gadget *gadget)
+ struct usb_request *req;
+ char *pathbuf, *p;
+
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]fsg_bind start\n");
++#endif
+ fsg->gadget = gadget;
+ set_gadget_data(gadget, fsg);
+ fsg->ep0 = gadget->ep0;
+ fsg->ep0->driver_data = fsg;
+
+- if ((rc = check_parameters(fsg)) != 0)
++ if ((rc = check_parameters(fsg)) != 0) {
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]check_parameters fail\n");
++#endif
+ goto out;
++ }
+
+- if (mod_data.removable) { // Enable the store_xxx attributes
++ //if (mod_data.removable) { // Enable the store_xxx attributes
+ dev_attr_ro.attr.mode = dev_attr_file.attr.mode = 0644;
+ dev_attr_ro.store = store_ro;
+ dev_attr_file.store = store_file;
+- }
++ //}
+
+ /* Find out how many LUNs there should be */
+ i = mod_data.nluns;
+@@ -3880,6 +4030,9 @@ static int __init fsg_bind(struct usb_gadget *gadget)
+ * LUN devices in sysfs. */
+ fsg->luns = kzalloc(i * sizeof(struct lun), GFP_KERNEL);
+ if (!fsg->luns) {
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]kzalloc fail\n");
++#endif
+ rc = -ENOMEM;
+ goto out;
+ }
+@@ -3888,6 +4041,8 @@ static int __init fsg_bind(struct usb_gadget *gadget)
+ for (i = 0; i < fsg->nluns; ++i) {
+ curlun = &fsg->luns[i];
+ curlun->ro = mod_data.ro[i];
++ curlun->can_ioctl = mod_data.can_ioctl[i];
++ curlun->removable = mod_data.removable[i];
+ curlun->dev.release = lun_release;
+ curlun->dev.parent = &gadget->dev;
+ curlun->dev.driver = &fsg_driver.driver;
+@@ -3897,6 +4052,9 @@ static int __init fsg_bind(struct usb_gadget *gadget)
+
+ if ((rc = device_register(&curlun->dev)) != 0) {
+ INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]register LUN%d: %d fail\n", i, rc);
++#endif
+ goto out;
+ }
+ if ((rc = device_create_file(&curlun->dev,
+@@ -3904,6 +4062,9 @@ static int __init fsg_bind(struct usb_gadget *gadget)
+ (rc = device_create_file(&curlun->dev,
+ &dev_attr_file)) != 0) {
+ device_unregister(&curlun->dev);
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]device create file fail\n");
++#endif
+ goto out;
+ }
+ curlun->registered = 1;
+@@ -3911,10 +4072,18 @@ static int __init fsg_bind(struct usb_gadget *gadget)
+
+ if (mod_data.file[i] && *mod_data.file[i]) {
+ if ((rc = open_backing_file(curlun,
+- mod_data.file[i])) != 0)
++ mod_data.file[i])) != 0) {
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]open backing file fail\n");
++#endif
+ goto out;
+- } else if (!mod_data.removable) {
++ }
++ //} else if (!mod_data.removable) {
++ } else if (!fsg_removable()) {
+ ERROR(fsg, "no file given for LUN%d\n", i);
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]no file given\n");
++#endif
+ rc = -EINVAL;
+ goto out;
+ }
+@@ -3922,22 +4091,35 @@ static int __init fsg_bind(struct usb_gadget *gadget)
+
+ /* Find all the endpoints we will use */
+ usb_ep_autoconfig_reset(gadget);
+- ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc);
+- if (!ep)
+- goto autoconf_fail;
+- ep->driver_data = fsg; // claim the endpoint
+- fsg->bulk_in = ep;
+
+ ep = usb_ep_autoconfig(gadget, &fs_bulk_out_desc);
+- if (!ep)
++ if (!ep) {
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]bulk out autoconf_fail\n");
++#endif
+ goto autoconf_fail;
++ }
+ ep->driver_data = fsg; // claim the endpoint
+ fsg->bulk_out = ep;
+
++ ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc);
++ if (!ep) {
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]bulk in autoconf_fail\n");
++#endif
++ goto autoconf_fail;
++ }
++ ep->driver_data = fsg; // claim the endpoint
++ fsg->bulk_in = ep;
++
+ if (transport_is_cbi()) {
+ ep = usb_ep_autoconfig(gadget, &fs_intr_in_desc);
+- if (!ep)
++ if (!ep) {
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]int in autoconf_fail\n");
++#endif
+ goto autoconf_fail;
++ }
+ ep->driver_data = fsg; // claim the endpoint
+ fsg->intr_in = ep;
+ }
+@@ -3969,18 +4151,33 @@ static int __init fsg_bind(struct usb_gadget *gadget)
+ fs_intr_in_desc.bEndpointAddress;
+ }
+
+- if (gadget_is_otg(gadget))
++ if (gadget_is_otg(gadget)) {
+ otg_desc.bmAttributes |= USB_OTG_HNP;
++ /* Commented by Sheeja S on 6th Feb 2006 to disable Remote Wakeup. */ //from dwc_otg, AlenOh
++ //AlenOh config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++ }
+
+ rc = -ENOMEM;
+
+ /* Allocate the request and buffer for endpoint 0 */
+ fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
+- if (!req)
++ if (!req) {
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]ep alloc request fail\n");
++#endif
+ goto out;
++ }
++ #ifdef DMA_MODE
++ req->buf = dma_alloc_coherent(NULL,EP0_BUFSIZE,&req->dma,GFP_KERNEL | GFP_DMA); //for dma (AlenOh)
++ #else
+ req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
+- if (!req->buf)
++ #endif
++ if (!req->buf) {
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]kmalloc EP0_BUFSIZE fail\n");
++#endif
+ goto out;
++ }
+ req->complete = ep0_complete;
+
+ /* Allocate the data buffers */
+@@ -3990,9 +4187,17 @@ static int __init fsg_bind(struct usb_gadget *gadget)
+ /* Allocate for the bulk-in endpoint. We assume that
+ * the buffer will also work with the bulk-out (and
+ * interrupt-in) endpoint. */
++ #ifdef DMA_MODE
++ bh->buf = dma_alloc_coherent(NULL,mod_data.buflen,&bh->dma,GFP_KERNEL | GFP_DMA); //for dma (AlenOh)
++ #else
+ bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL);
+- if (!bh->buf)
++ #endif
++ if (!bh->buf) {
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]kmalloc mod_data.buflen fail\n");
++#endif
+ goto out;
++ }
+ bh->next = bh + 1;
+ }
+ fsg->buffhds[NUM_BUFFERS - 1].next = &fsg->buffhds[0];
+@@ -4000,12 +4205,17 @@ static int __init fsg_bind(struct usb_gadget *gadget)
+ /* This should reflect the actual gadget power source */
+ usb_gadget_set_selfpowered(gadget);
+
++#ifdef CONFIG_ARCH_TCC
++ snprintf(manufacturer, sizeof manufacturer, "TELECHIPS");
++#else
+ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
++#endif
+
+ /* On a real device, serial[] would be loaded from permanent
+ * storage. We just encode it from the driver version string. */
++#ifndef CONFIG_ARCH_TCC
+ for (i = 0; i < sizeof(serial) - 2; i += 2) {
+ unsigned char c = DRIVER_VERSION[i / 2];
+
+@@ -4013,11 +4223,15 @@ static int __init fsg_bind(struct usb_gadget *gadget)
+ break;
+ sprintf(&serial[i], "%02X", c);
+ }
++#endif
+
+ fsg->thread_task = kthread_create(fsg_main_thread, fsg,
+ "file-storage-gadget");
+ if (IS_ERR(fsg->thread_task)) {
+ rc = PTR_ERR(fsg->thread_task);
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]PTR ERR\n");
++#endif
+ goto out;
+ }
+
+@@ -4048,7 +4262,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
+ DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",
+ mod_data.vendor, mod_data.product, mod_data.release);
+ DBG(fsg, "removable=%d, stall=%d, buflen=%u\n",
+- mod_data.removable, mod_data.can_stall,
++ /*mod_data.removable*/fsg_removable(), mod_data.can_stall,
+ mod_data.buflen);
+ DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
+
+@@ -4137,11 +4351,21 @@ static int __init fsg_init(void)
+ int rc;
+ struct fsg_dev *fsg;
+
+- if ((rc = fsg_alloc()) != 0)
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]fsg_init start\n");
++#endif
++ if ((rc = fsg_alloc()) != 0) {
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]fsg_alloc fail\n");
++#endif
+ return rc;
++ }
+ fsg = the_fsg;
+ if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0)
+ kref_put(&fsg->ref, fsg_release);
++#ifdef CONFIG_ARCH_TCC
++ printk("[tcc-gadget]fsg init end\n");
++#endif
+ return rc;
+ }
+ module_init(fsg_init);
+diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
+index 4e3107d..ddf3bc8 100644
+--- a/drivers/usb/gadget/gadget_chips.h
++++ b/drivers/usb/gadget/gadget_chips.h
+@@ -158,6 +158,14 @@
+ #define gadget_is_fsl_qe(g) 0
+ #endif
+
++#if defined(CONFIG_USB_GADGET_TCC_OTG_STANDALONE)
++#define gadget_is_tcc(g) !strcmp("tcc-udc", (g)->name)
++#elif defined(CONFIG_TCC_DWC_OTG_DEVICE_ONLY) || \
++ defined(CONFIG_TCC_DWC_OTG_DUAL_ROLE)
++#define gadget_is_tcc(g) !strcmp("dwc_otg_pcd", (g)->name)
++#else
++#define gadget_is_tcc(g) 0
++#endif
+
+ // CONFIG_USB_GADGET_SX2
+ // CONFIG_USB_GADGET_AU1X00
+@@ -225,6 +233,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
+ return 0x21;
+ else if (gadget_is_fsl_qe(gadget))
+ return 0x22;
++ else if (gadget_is_tcc(gadget))
++ return 0xff;
+ return -ENOENT;
+ }
+
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index f3a75a9..e11af8e 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -124,7 +124,7 @@ config USB_ISP1760_HCD
+ module will be called isp1760.
+
+ config USB_OHCI_HCD
+- tristate "OHCI HCD support"
++ tristate "OHCI HCD support (TCC8900 only)"
+ depends on USB && USB_ARCH_HAS_OHCI
+ select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
+ ---help---
+diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
+index 8aa3f45..13c2bca 100644
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -992,6 +992,11 @@ MODULE_LICENSE ("GPL");
+ #define PCI_DRIVER ohci_pci_driver
+ #endif
+
++#ifdef CONFIG_ARCH_TCC
++#include "ohci-tcc.c"
++#define PLATFORM_DRIVER ohci_hcd_tcc_driver
++#endif
++
+ #if defined(CONFIG_ARCH_SA1100) && defined(CONFIG_SA1111)
+ #include "ohci-sa1111.c"
+ #define SA1111_DRIVER ohci_hcd_sa1111_driver
+diff --git a/drivers/usb/host/ohci-tcc.c b/drivers/usb/host/ohci-tcc.c
+new file mode 100644
+index 0000000..994c440
+--- /dev/null
++++ b/drivers/usb/host/ohci-tcc.c
+@@ -0,0 +1,529 @@
++/*
++ * linux/drivers/usb/host/ohci-tcc.c
++ *
++ * Description: OHCI HCD (Host Controller Driver) for USB.
++ * Bus Glue for Telechips TCCXXX
++ *
++ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
++ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
++ * (C) Copyright 2002 Hewlett-Packard Company
++ * (C) Copyright 2008-2009 Telechips <linux@telechips.com>
++ * (C) Copyright 2008-2009 Telechips
++ *
++ * Rewritten by <linux@telechips.com>
++ * Written by Christopher Hoover <ch@hpl.hp.com>
++ * Based on fragments of previous driver by Russell King et al.
++ *
++ * Modified for LH7A404 from ohci-sa1111.c
++ * by Durgesh Pattamatta <pattamattad@sharpsec.com>
++ *
++ * Modified for pxa27x from ohci-lh7a404.c
++ * by Nick Bane <nick@cecomputing.co.uk> 26-8-2004
++ *
++ * Modified for TCCXXX from ohci-pxa27x.c
++ * by Telechips Linux Team <linux@telechips.com> 03-9-2008
++ *
++ * This file is licenced under the GPL.
++ */
++
++#include <linux/device.h>
++#include <linux/signal.h>
++#include <linux/platform_device.h>
++#include <asm/mach-types.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include <linux/tcc_pwm.h>
++#include <linux/tcc_ll.h>
++
++#include <bsp.h>
++#include <mach/ohci.h>
++#include <mach/tcc_pca953x.h>
++
++static int tcc_ohci_select_pmm(unsigned long reg_base, int mode, int num_port, int *port_mode)
++{
++ volatile struct _USBHOST11 *ohci_reg;
++ ohci_reg = (volatile struct _USBHOST11 *)reg_base;
++
++ switch (mode) {
++ case USBOHCI_PPM_NPS:
++ /* set NO Power Switching mode */
++ ohci_reg->HcRhDescriptorA |= USBOHCI_UHCRHDA_NPS;
++ break;
++ case USBOHCI_PPM_GLOBAL:
++ /* make sure the NO Power Switching mode bit is OFF so Power Switching can occur
++ * make sure the PSM bit is CLEAR, which allows all ports to be controlled with
++ * the GLOBAL set and clear power commands
++ */
++ ohci_reg->HcRhDescriptorA &= ~(USBOHCI_UHCRHDA_NPS|USBOHCI_UHCRHDA_PSM_PERPORT);
++ break;
++ case USBOHCI_PPM_PERPORT:
++ /* make sure the NO Power Switching mode bit is OFF so Power Switching can occur
++ * make sure the PSM bit is SET, which allows all ports to be controlled with
++ * the PER PORT set and clear power commands
++ */
++ ohci_reg->HcRhDescriptorA &= ~USBOHCI_UHCRHDA_NPS;
++ ohci_reg->HcRhDescriptorA |= USBOHCI_UHCRHDA_PSM_PERPORT;
++
++ /* set the power management mode for each individual port to Per Port. */
++ {
++ int p;
++ for (p = 0; p < num_port; p++) {
++ ohci_reg->HcRhDescriptorB |= (unsigned int)( 1u << (p+17) ); // port 1 begins at bit 17
++ }
++ }
++ break;
++ case USBOHCI_PPM_MIXED:
++ /* make sure the NO Power Switching mode bit is OFF so Power Switching can occur
++ * make sure the PSM bit is SET, which allows all ports to be controlled with
++ * the PER PORT set and clear power commands
++ */
++ ohci_reg->HcRhDescriptorA &= ~USBOHCI_UHCRHDA_NPS;
++ ohci_reg->HcRhDescriptorA |= USBOHCI_UHCRHDA_PSM_PERPORT;
++
++ /* set the power management mode for each individual port to Per Port.
++ * if the value in the PortMode array is non-zero, set Per Port mode for the port.
++ * if the value in the PortMode array is zero, set Global mode for the port
++ */
++ {
++ int p;
++ for (p = 0; p < num_port; p++) {
++ if (port_mode[p]) {
++ ohci_reg->HcRhDescriptorB |= (unsigned int)( 1u << (p+17) ); // port 1 begins at bit 17
++ } else {
++ ohci_reg->HcRhDescriptorB &= ~(unsigned int)( 1u << (p+17) ); // port 1 begins at bit 17
++ }
++ }
++ }
++ break;
++ default:
++ printk(KERN_ERR "Invalid mode %d, set to non-power switch mode.\n", mode);
++ ohci_reg->HcRhDescriptorA |= USBOHCI_UHCRHDA_NPS;
++ }
++ return 0;
++}
++
++extern int usb_disabled(void);
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * TCC89/91/92 has two down stream ports.
++ * Down stream port1 interfaces with USB1.1 transceiver.
++ * Down stream port2 interfaces with USB2.0 OTG PHY.
++ * port1 should be power off, because OTG use USB2.0 OTG PHY.
++ */
++void ohci_port_power_control(void)
++{
++ PUSBHOST11 ohci = (PUSBHOST11)tcc_p2v(HwUSBHOST_BASE);
++
++ /* Port power switch mode & each port is powered individually
++ */
++ BITCSET(ohci->HcRhDescriptorA, Hw9|Hw8, Hw8); // NPS 0, PSM 1
++
++ /* port2 power state is only affected by per-port power control (Set/ClearPortPower)
++ * port1 is controlled by the global power switch (Set/ClearGlobalPower)
++ */
++ BITSET(ohci->HcRhDescriptorB, Hw18); // PPCM bit2 1
++
++ /* Clear the PortPowerStatus (port2 power off)
++ */
++ ohci->HcRhPortStatus2 = Hw9; // port2 LSDA 1
++}
++
++static void USBHostVBUSControl(int on)
++{
++ /* GPIO_EXPAND HVBUS & PWR_GP1 control */
++ if (on) {
++ tcc_pca953x_setup(PCA9538_U4_SLAVE_ADDR, PWR_GP1, OUTPUT, HIGH, SET_DIRECTION|SET_VALUE);
++ tcc_pca953x_setup(PCA9538_U4_SLAVE_ADDR, HVBUS_ON, OUTPUT, HIGH, SET_DIRECTION|SET_VALUE);
++ } else {
++#if !defined(CONFIG_TCC_DWC_OTG) && !defined(CONFIG_TCC_DWC_OTG_MODULE)
++ tcc_pca953x_setup(PCA9538_U4_SLAVE_ADDR, PWR_GP1, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++#endif
++ tcc_pca953x_setup(PCA9538_U4_SLAVE_ADDR, HVBUS_ON, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++ }
++}
++
++static void TurnOnUSBHostClocks(void)
++{
++ PIOBUSCFG pIOBUSCfg;
++ pIOBUSCfg = (PIOBUSCFG)tcc_p2v(HwIOBUSCFG_BASE);
++ tca_ckc_setperi(PERI_USB11H, ENABLE, 480000, PCDIRECTPLL3);
++ BITSET(pIOBUSCfg->HCLKEN0, Hw0); // Bit0 is USB1.1 Host IOBUS AHB clock
++ BITSET(pIOBUSCfg->HRSTEN0, Hw0); // Bit0 is USB1.1 Host IOBUS AHB Hreset
++}
++
++static void TurnOffUSBHostClocks(void)
++{
++ PIOBUSCFG pIOBUSCfg;
++ pIOBUSCfg = (PIOBUSCFG)tcc_p2v(HwIOBUSCFG_BASE);
++ tca_ckc_setperi(PERI_USB11H, DISABLE, 480000, PCDIRECTPLL3);
++ BITCLR(pIOBUSCfg->HCLKEN0, Hw0);
++ BITCLR(pIOBUSCfg->HRSTEN0, Hw0);
++}
++
++static void USBHostReset(void)
++{
++ PIOBUSCFG pIOBUSCfg;
++ pIOBUSCfg = (PIOBUSCFG)tcc_p2v(HwIOBUSCFG_BASE);
++ BITCLR(pIOBUSCfg->HRSTEN0, Hw0);
++ BITSET(pIOBUSCfg->HRSTEN0, Hw0);
++}
++
++static int tcc_set_cken(int sw)
++{
++ if (sw){
++ TurnOnUSBHostClocks();
++ USBHostReset();
++ } else {
++ TurnOffUSBHostClocks();
++ }
++ return 0;
++}
++
++static int tcc_start_hc(struct device *dev)
++{
++ int retval = 0;
++ struct tccohci_platform_data *inf;
++ PIOBUSCFG pIOBUSCfg;
++ inf = dev->platform_data;
++
++ /* USB 1.1 Host Configuration Register
++ * DP, DN pull-down enable
++ */
++ pIOBUSCfg = (PIOBUSCFG)tcc_p2v(HwIOBUSCFG_BASE);
++ BITSET(pIOBUSCfg->USB11H, Hw4|Hw3);
++
++ tcc_set_cken(1);
++
++ if (inf->init)
++ retval = inf->init(dev);
++ if (retval < 0)
++ return retval;
++
++ return 0;
++}
++
++static void tcc_stop_hc(struct device *dev)
++{
++ struct tccohci_platform_data *inf;
++ inf = dev->platform_data;
++ if (inf->exit)
++ inf->exit(dev);
++
++ tcc_set_cken(0);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* configure so an HC device and id are always provided */
++/* always called with process context; sleeping is OK */
++
++
++/**
++ * usb_hcd_tcc_probe - initialize tcc-based HCDs
++ * Context: !in_interrupt()
++ *
++ * Allocates basic resources for this USB host controller, and
++ * then invokes the start() method for the HCD associated with it
++ * through the hotplug entry's driver_data.
++ *
++ */
++static int usb_hcd_tcc_probe (const struct hc_driver *driver, struct platform_device *pdev)
++{
++ int retval = 0;
++ struct usb_hcd *hcd;
++ struct tccohci_platform_data *inf;
++
++ inf = pdev->dev.platform_data;
++ if (!inf) {
++ return -ENODEV;
++ }
++
++ if (pdev->resource[1].flags != IORESOURCE_IRQ) {
++ printk(KERN_ERR "resource[1] is not IORESOURCE_IRQ");
++ return -ENOMEM;
++ }
++
++ hcd = usb_create_hcd (driver, &pdev->dev, "tcc");
++ if (!hcd)
++ return -ENOMEM;
++ hcd->rsrc_start = io_p2v(pdev->resource[0].start);
++ hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
++
++ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
++ printk(KERN_ERR "request_mem_region failed");
++ retval = -EBUSY;
++ goto err1;
++ }
++ hcd->regs = (void __iomem *)(int)(hcd->rsrc_start);
++
++ /* GPIO_EXPAND HVBUS & PWR_GP1 Power-on */
++ USBHostVBUSControl(1);
++ retval = tcc_pca953x_setup(PCA9538_U4_SLAVE_ADDR, 0, OUTPUT, 0, GET_VALUE);
++#if 0 /* comment by csduan */
++ if (!(retval & PWR_GP1) || !(retval & HVBUS_ON)) {
++ printk(KERN_ERR "ohci-tcc: GPIO_EXPAND power failed\n");
++ retval = -EIO;
++ goto err2;
++ }
++#endif /* comment by csduan */
++
++ if ((retval = tcc_start_hc(&pdev->dev)) < 0) {
++ printk(KERN_ERR "tcc_start_hc failed");
++ goto err2;
++ }
++
++ /* Select Power Management Mode */
++ tcc_ohci_select_pmm(hcd->rsrc_start, inf->port_mode, 0, 0);
++
++ if (inf->power_budget)
++ hcd->power_budget = inf->power_budget;
++
++ ohci_hcd_init(hcd_to_ohci(hcd));
++
++ retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED);
++ if (retval == 0) {
++ return retval;
++ }
++
++ tcc_stop_hc(&pdev->dev);
++err2:
++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++err1:
++ usb_put_hcd(hcd);
++ return retval;
++}
++
++
++/* may be called without controller electrically present */
++/* may be called with controller, bus, and devices active */
++
++/**
++ * usb_hcd_tcc_remove - shutdown processing for tcc-based HCDs
++ * @dev: USB Host Controller being removed
++ * Context: !in_interrupt()
++ *
++ * Reverses the effect of usb_hcd_tcc_probe(), first invoking
++ * the HCD's stop() method. It is always called from a thread
++ * context, normally "rmmod", "apmd", or something similar.
++ *
++ */
++static void usb_hcd_tcc_remove (struct usb_hcd *hcd, struct platform_device *pdev)
++{
++ usb_remove_hcd(hcd);
++
++ tcc_stop_hc(&pdev->dev);
++
++ /* GPIO_EXPAND HVBUS & PWR_GP1 Power-off */
++ USBHostVBUSControl(0);
++
++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++ usb_put_hcd(hcd);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int __devinit ohci_tcc_start (struct usb_hcd *hcd)
++{
++ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
++ int ret;
++
++ tcc_set_cken(1);
++
++ /* The value of NDP in roothub_a is incorrect on this hardware */
++ ohci->num_ports = 1;
++
++ if ((ret = ohci_init(ohci)) < 0) {
++ return ret;
++ }
++ if ((ret = ohci_run (ohci)) < 0) {
++ err ("can't start %s", hcd->self.bus_name);
++ ohci_stop (hcd);
++ return ret;
++ }
++
++ ohci_port_power_control();
++
++ return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static const struct hc_driver ohci_tcc_hc_driver = {
++ .description = hcd_name,
++ .product_desc = "TCC OHCI",
++ .hcd_priv_size = sizeof(struct ohci_hcd),
++
++ /*
++ * generic hardware linkage
++ */
++ .irq = ohci_irq,
++ .flags = HCD_USB11 | HCD_MEMORY,
++
++ /*
++ * basic lifecycle operations
++ */
++ .start = ohci_tcc_start,
++ .stop = ohci_stop,
++#ifndef __OLD__
++ .shutdown = ohci_shutdown,
++#endif
++
++ /*
++ * managing i/o requests and associated device resources
++ */
++ .urb_enqueue = ohci_urb_enqueue,
++ .urb_dequeue = ohci_urb_dequeue,
++ .endpoint_disable = ohci_endpoint_disable,
++
++ /*
++ * scheduling support
++ */
++ .get_frame_number = ohci_get_frame,
++
++ /*
++ * root hub support
++ */
++ .hub_status_data = ohci_hub_status_data,
++ .hub_control = ohci_hub_control,
++#ifdef CONFIG_PM
++ .bus_suspend = ohci_bus_suspend,
++ .bus_resume = ohci_bus_resume,
++#endif
++ .start_port_reset = ohci_start_port_reset,
++};
++
++
++/*-------------------------------------------------------------------------*/
++
++#ifdef CONFIG_PM
++int ohci_hcd_tcc_drv_suspend(struct platform_device *pdev, pm_message_t state)
++{
++#if 0 /* comment by csduan */
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
++
++ if (time_before(jiffies, ohci->next_statechange))
++ msleep(5);
++ ohci->next_statechange = jiffies;
++
++ tcc_stop_hc(&pdev->dev);
++ hcd->state = HC_STATE_SUSPENDED;
++
++ USBHostVBUSControl(0);
++#endif /* comment by csduan */
++
++ return 0;
++}
++
++static int ohci_hcd_tcc_drv_resume(struct platform_device *pdev)
++{
++#if 0 /* comment by csduan */
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
++ int status;
++
++ USBHostVBUSControl(1);
++
++ if (time_before(jiffies, ohci->next_statechange))
++ msleep(5);
++ ohci->next_statechange = jiffies;
++
++ if ((status = tcc_start_hc(&pdev->dev)) < 0)
++ return status;
++ ohci_finish_controller_resume(hcd);
++
++ ohci_port_power_control();
++#endif /* comment by csduan */
++
++ return 0;
++}
++#else
++#define ohci_hcd_tcc_drv_suspend NULL
++#define ohci_hcd_tcc_drv_resume NULL
++#endif
++
++/*-----------------------------------------------------------------
++ * OHCI Power on/off control
++ */
++static stpwrinfo pwrinfo = {PWR_STATUS_ON};
++static int ohci_pwr_ctl(void *h_private, int cmd, void *p_out)
++{
++ struct platform_device *pdev = (struct platform_device *)h_private;
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ switch (cmd) {
++ case PWR_CMD_OFF:
++ //printk("PWR_CMD_OFF command ==> [%d]\n", cmd);
++ if (pwrinfo.status == PWR_STATUS_OFF) {
++ return 0;
++ }
++ pwrinfo.status = PWR_STATUS_OFF;
++ /* refer to ohci_hcd_tcc_drv_remove */
++ usb_hcd_tcc_remove(hcd, pdev);
++ platform_set_drvdata(pdev, NULL);
++ break;
++ case PWR_CMD_ON:
++ //printk("PWR_CMD_ON command ==> [%d]\n", cmd);
++ if (pwrinfo.status == PWR_STATUS_ON) {
++ return 0;
++ }
++ pwrinfo.status = PWR_STATUS_ON;
++ /* refer to ohci_hcd_tcc_drv_probe */
++ if (usb_disabled()) { return -EIO; }
++ usb_hcd_tcc_probe(&ohci_tcc_hc_driver, pdev);
++ break;
++ case PWR_CMD_GETSTATUS:
++ //printk("PWR_CMD_GETSTATUS command ==> [%d], status:[%d]\n", cmd, pwrinfo.status);
++ memcpy(p_out, &pwrinfo, sizeof(stpwrinfo));
++ break;
++ default:
++ //printk("unknown pwr command !!! ==> [%d]\n", cmd);
++ return -EINVAL;
++ break;
++ }
++
++ return 0;
++}
++
++static int ohci_hcd_tcc_drv_probe(struct platform_device *pdev)
++{
++ if (usb_disabled()) {
++ return -ENODEV;
++ }
++
++ /* add power control functions */
++ insert_pwm_node(DEVICE_OHCI, ohci_pwr_ctl, pdev);
++
++ return usb_hcd_tcc_probe(&ohci_tcc_hc_driver, pdev);
++}
++
++static int ohci_hcd_tcc_drv_remove(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ /* remove power control functions */
++ remove_pwm_node(DEVICE_OHCI);
++
++ usb_hcd_tcc_remove(hcd, pdev);
++ platform_set_drvdata(pdev, NULL);
++ return 0;
++}
++
++
++static struct platform_driver ohci_hcd_tcc_driver = {
++ .probe = ohci_hcd_tcc_drv_probe,
++ .remove = ohci_hcd_tcc_drv_remove,
++ .suspend = ohci_hcd_tcc_drv_suspend,
++ .resume = ohci_hcd_tcc_drv_resume,
++ .driver = {
++ .name = "tcc-ohci",
++ .owner = THIS_MODULE,
++ },
++};
++
++
++/* work with hotplug and coldplug */
++MODULE_ALIAS("platform:tcc-ohci");
+diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
+index 809697b..d695456 100644
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -259,10 +259,17 @@ static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *po
+
+ /* ZTE PRODUCTS */
+ #define ZTE_VENDOR_ID 0x19d2
++#define ZTE_PRODUCT_MF622 0x0001
++#define ZTE_PRODUCT_MU350 0x0003
+ #define ZTE_PRODUCT_MF628 0x0015
+ #define ZTE_PRODUCT_MF626 0x0031
++#define ZTE_PRODUCT_AC560 0x0073
+ #define ZTE_PRODUCT_CDMA_TECH 0xfffe
+
++/* DTT PRODUCTS */
++#define DTT_VENDOR_ID 0x1ab7
++#define DTT_PRODUCT_AIRCARD_901 0x2000
++
+ /* Ericsson products */
+ #define ERICSSON_VENDOR_ID 0x0bdb
+ #define ERICSSON_PRODUCT_F3507G 0x1900
+@@ -412,7 +419,7 @@ static struct usb_device_id option_ids[] = {
+ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
+ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },
+ { USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) },
+- { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MSA501HS) },
++ /*{ USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MSA501HS) },
+ { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_ET502HS) },
+ { USB_DEVICE(ONDA_VENDOR_ID, 0x0003) },
+ { USB_DEVICE(ONDA_VENDOR_ID, 0x0004) },
+@@ -447,7 +454,7 @@ static struct usb_device_id option_ids[] = {
+ { USB_DEVICE(ONDA_VENDOR_ID, 0x0027) },
+ { USB_DEVICE(ONDA_VENDOR_ID, 0x0028) },
+ { USB_DEVICE(ONDA_VENDOR_ID, 0x0029) },
+- { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MT503HS) },
++ { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MT503HS) },*/
+ { USB_DEVICE(YISO_VENDOR_ID, YISO_PRODUCT_U893) },
+ { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
+ { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
+@@ -472,9 +479,13 @@ static struct usb_device_id option_ids[] = {
+ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
+ { USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
++ { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622) },
++ { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MU350) },
+ { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626) },
++ { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_AC560) },
+ { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) },
+ { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) },
++ { USB_DEVICE(DTT_VENDOR_ID, DTT_PRODUCT_AIRCARD_901) },
+ { USB_DEVICE(ERICSSON_VENDOR_ID, ERICSSON_PRODUCT_F3507G) },
+ { USB_DEVICE(PANTECH_VENDOR_ID, PANTECH_PRODUCT_PC5740) },
+ { USB_DEVICE(PANTECH_VENDOR_ID, PANTECH_PRODUCT_PC5750) },
+diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
+index 3f3ce13..51d9526 100644
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -1886,6 +1886,59 @@ config FB_W100
+
+ If unsure, say N.
+
++config FB_TCC8900
++ tristate "Telechips TCC8900 DEMO board framebuffer support"
++ depends on FB && MACH_TCC8900
++ default n
++ select FB_CFB_FILLRECT
++ select FB_CFB_COPYAREA
++ select FB_CFB_IMAGEBLIT
++ select TCC_BL
++ ---help---
++ Frame buffer driver for the built-in LCD controller in the Telechips
++ TCC8900 processor.
++
++ If unsure, say N.
++
++choice
++ prompt "Select LCD Type"
++ depends on FB_TCC8900
++ default FB_TCC_TD043MTEX
++
++config FB_TCC_A070VW04
++ bool "A070VW04"
++ ---help---
++ TBA
++
++config FB_TCC_TD043MTEX
++ bool "TD043MTEX"
++ ---help---
++ TBA
++
++endchoice
++
++config FB_TCC_BPP
++ tristate "Advanced options for TCC8900 Framebuffer"
++ depends on FB_TCC8900
++ default n
++ ---help---
++ TBA
++
++choice
++depends on FB_TCC_BPP
++prompt "Select BPP(Bits Per Pixel)"
++default FB_TCC_BPP_16
++config FB_TCC_BPP_16
++ bool "16 BPP"
++ ---help---
++ TBA
++
++config FB_TCC_BPP_32
++ bool "32 BPP"
++ ---help---
++ TBA
++endchoice
++
+ config FB_SH_MOBILE_LCDC
+ tristate "SuperH Mobile LCDC framebuffer support"
+ depends on FB && SUPERH
+diff --git a/drivers/video/Makefile b/drivers/video/Makefile
+index e39e33e..90e1097 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -123,6 +123,9 @@ obj-$(CONFIG_FB_OMAP) += omap/
+ obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
+ obj-$(CONFIG_FB_CARMINE) += carminefb.o
+ obj-$(CONFIG_FB_MB862XX) += mb862xx/
++obj-$(CONFIG_FB_TCC8900) += tccfb.o tca_lcdc.o tca_tvout.o
++obj-$(CONFIG_FB_TCC_A070VW04) += tccfb_a070vw04.o
++obj-$(CONFIG_FB_TCC_TD043MTEX) += tccfb_td043mtex.o
+
+ # Platform or fallback drivers go here
+ obj-$(CONFIG_FB_UVESA) += uvesafb.o
+diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
+index 3c65b0d..d0d1ee3 100644
+--- a/drivers/video/fbmem.c
++++ b/drivers/video/fbmem.c
+@@ -458,8 +458,13 @@ static int fb_show_logo_line(struct fb_info *info, int rotate,
+ fb_set_logo(info, logo, logo_new, fb_logo.depth);
+ }
+
++#ifdef CONFIG_LOGO_CENTER
++ image.dx = (info->var.xres - logo->width) / 2;
++ image.dy = y + (info->var.yres - logo->height) / 2;
++#else
+ image.dx = 0;
+ image.dy = y;
++#endif
+ image.width = logo->width;
+ image.height = logo->height;
+
+diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
+index d4a2c11..d400a12 100644
+--- a/drivers/video/fbsysfs.c
++++ b/drivers/video/fbsysfs.c
+@@ -379,6 +379,13 @@ static ssize_t show_pan(struct device *device,
+ fb_info->var.yoffset);
+ }
+
++extern unsigned int tvo_status(void);
++static ssize_t show_tvostatus(struct device *device,
++ struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", tvo_status());
++}
++
+ static ssize_t show_name(struct device *device,
+ struct device_attribute *attr, char *buf)
+ {
+@@ -496,6 +503,7 @@ static struct device_attribute device_attrs[] = {
+ __ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),
+ __ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),
+ __ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
++ __ATTR(tvo_status, S_IRUGO, show_tvostatus, NULL),
+ __ATTR(name, S_IRUGO, show_name, NULL),
+ __ATTR(stride, S_IRUGO, show_stride, NULL),
+ __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
+diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
+index 39ac49e..208d56a 100644
+--- a/drivers/video/logo/Kconfig
++++ b/drivers/video/logo/Kconfig
+@@ -15,6 +15,10 @@ config FB_LOGO_EXTRA
+ depends on FB=y
+ default y if SPU_BASE
+
++config LOGO_CENTER
++ bool "Put logo on the center of screen"
++ default n
++
+ config LOGO_LINUX_MONO
+ bool "Standard black and white Linux logo"
+ default y
+diff --git a/drivers/video/logo/logo_linux_clut224.ppm b/drivers/video/logo/logo_linux_clut224.ppm
+index 3c14e43..64e0601 100644
+--- a/drivers/video/logo/logo_linux_clut224.ppm
++++ b/drivers/video/logo/logo_linux_clut224.ppm
+@@ -1,1604 +1,2150 @@
+ P3
+-# Standard 224-color Linux logo
+-80 80
++110 113
+ 255
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 6 6 6 10 10 10 10 10 10
+- 10 10 10 6 6 6 6 6 6 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 10 10 10 14 14 14
+- 22 22 22 26 26 26 30 30 30 34 34 34
+- 30 30 30 30 30 30 26 26 26 18 18 18
+- 14 14 14 10 10 10 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 14 14 14 26 26 26 42 42 42
+- 54 54 54 66 66 66 78 78 78 78 78 78
+- 78 78 78 74 74 74 66 66 66 54 54 54
+- 42 42 42 26 26 26 18 18 18 10 10 10
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 22 22 22 42 42 42 66 66 66 86 86 86
+- 66 66 66 38 38 38 38 38 38 22 22 22
+- 26 26 26 34 34 34 54 54 54 66 66 66
+- 86 86 86 70 70 70 46 46 46 26 26 26
+- 14 14 14 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 10 10 10 26 26 26
+- 50 50 50 82 82 82 58 58 58 6 6 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 6 6 6 54 54 54 86 86 86 66 66 66
+- 38 38 38 18 18 18 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 22 22 22 50 50 50
+- 78 78 78 34 34 34 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 6 6 6 70 70 70
+- 78 78 78 46 46 46 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 18 18 18 42 42 42 82 82 82
+- 26 26 26 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 14 14 14
+- 46 46 46 34 34 34 6 6 6 2 2 6
+- 42 42 42 78 78 78 42 42 42 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 0 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 10 10 10 30 30 30 66 66 66 58 58 58
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 26 26 26
+- 86 86 86 101 101 101 46 46 46 10 10 10
+- 2 2 6 58 58 58 70 70 70 34 34 34
+- 10 10 10 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 14 14 14 42 42 42 86 86 86 10 10 10
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 30 30 30
+- 94 94 94 94 94 94 58 58 58 26 26 26
+- 2 2 6 6 6 6 78 78 78 54 54 54
+- 22 22 22 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 22 22 22 62 62 62 62 62 62 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 26 26 26
+- 54 54 54 38 38 38 18 18 18 10 10 10
+- 2 2 6 2 2 6 34 34 34 82 82 82
+- 38 38 38 14 14 14 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 30 30 30 78 78 78 30 30 30 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 10 10 10
+- 10 10 10 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 78 78 78
+- 50 50 50 18 18 18 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 38 38 38 86 86 86 14 14 14 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 54 54 54
+- 66 66 66 26 26 26 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 42 42 42 82 82 82 2 2 6 2 2 6
+- 2 2 6 6 6 6 10 10 10 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 6 6 6
+- 14 14 14 10 10 10 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 18 18 18
+- 82 82 82 34 34 34 10 10 10 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 46 46 46 86 86 86 2 2 6 2 2 6
+- 6 6 6 6 6 6 22 22 22 34 34 34
+- 6 6 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 18 18 18 34 34 34
+- 10 10 10 50 50 50 22 22 22 2 2 6
+- 2 2 6 2 2 6 2 2 6 10 10 10
+- 86 86 86 42 42 42 14 14 14 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 1 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 46 46 46 86 86 86 2 2 6 2 2 6
+- 38 38 38 116 116 116 94 94 94 22 22 22
+- 22 22 22 2 2 6 2 2 6 2 2 6
+- 14 14 14 86 86 86 138 138 138 162 162 162
+-154 154 154 38 38 38 26 26 26 6 6 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 86 86 86 46 46 46 14 14 14 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 46 46 46 86 86 86 2 2 6 14 14 14
+-134 134 134 198 198 198 195 195 195 116 116 116
+- 10 10 10 2 2 6 2 2 6 6 6 6
+-101 98 89 187 187 187 210 210 210 218 218 218
+-214 214 214 134 134 134 14 14 14 6 6 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 86 86 86 50 50 50 18 18 18 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 1 0 0 0
+- 0 0 1 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 46 46 46 86 86 86 2 2 6 54 54 54
+-218 218 218 195 195 195 226 226 226 246 246 246
+- 58 58 58 2 2 6 2 2 6 30 30 30
+-210 210 210 253 253 253 174 174 174 123 123 123
+-221 221 221 234 234 234 74 74 74 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 70 70 70 58 58 58 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 46 46 46 82 82 82 2 2 6 106 106 106
+-170 170 170 26 26 26 86 86 86 226 226 226
+-123 123 123 10 10 10 14 14 14 46 46 46
+-231 231 231 190 190 190 6 6 6 70 70 70
+- 90 90 90 238 238 238 158 158 158 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 70 70 70 58 58 58 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 1 0 0 0
+- 0 0 1 0 0 1 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 42 42 42 86 86 86 6 6 6 116 116 116
+-106 106 106 6 6 6 70 70 70 149 149 149
+-128 128 128 18 18 18 38 38 38 54 54 54
+-221 221 221 106 106 106 2 2 6 14 14 14
+- 46 46 46 190 190 190 198 198 198 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 74 74 74 62 62 62 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 1 0 0 0
+- 0 0 1 0 0 0 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 42 42 42 94 94 94 14 14 14 101 101 101
+-128 128 128 2 2 6 18 18 18 116 116 116
+-118 98 46 121 92 8 121 92 8 98 78 10
+-162 162 162 106 106 106 2 2 6 2 2 6
+- 2 2 6 195 195 195 195 195 195 6 6 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 74 74 74 62 62 62 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 1 0 0 1
+- 0 0 1 0 0 0 0 0 1 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 38 38 38 90 90 90 14 14 14 58 58 58
+-210 210 210 26 26 26 54 38 6 154 114 10
+-226 170 11 236 186 11 225 175 15 184 144 12
+-215 174 15 175 146 61 37 26 9 2 2 6
+- 70 70 70 246 246 246 138 138 138 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 70 70 70 66 66 66 26 26 26 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 38 38 38 86 86 86 14 14 14 10 10 10
+-195 195 195 188 164 115 192 133 9 225 175 15
+-239 182 13 234 190 10 232 195 16 232 200 30
+-245 207 45 241 208 19 232 195 16 184 144 12
+-218 194 134 211 206 186 42 42 42 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 50 50 50 74 74 74 30 30 30 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 34 34 34 86 86 86 14 14 14 2 2 6
+-121 87 25 192 133 9 219 162 10 239 182 13
+-236 186 11 232 195 16 241 208 19 244 214 54
+-246 218 60 246 218 38 246 215 20 241 208 19
+-241 208 19 226 184 13 121 87 25 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 50 50 50 82 82 82 34 34 34 10 10 10
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 34 34 34 82 82 82 30 30 30 61 42 6
+-180 123 7 206 145 10 230 174 11 239 182 13
+-234 190 10 238 202 15 241 208 19 246 218 74
+-246 218 38 246 215 20 246 215 20 246 215 20
+-226 184 13 215 174 15 184 144 12 6 6 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 26 26 26 94 94 94 42 42 42 14 14 14
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 30 30 30 78 78 78 50 50 50 104 69 6
+-192 133 9 216 158 10 236 178 12 236 186 11
+-232 195 16 241 208 19 244 214 54 245 215 43
+-246 215 20 246 215 20 241 208 19 198 155 10
+-200 144 11 216 158 10 156 118 10 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 6 6 6 90 90 90 54 54 54 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 30 30 30 78 78 78 46 46 46 22 22 22
+-137 92 6 210 162 10 239 182 13 238 190 10
+-238 202 15 241 208 19 246 215 20 246 215 20
+-241 208 19 203 166 17 185 133 11 210 150 10
+-216 158 10 210 150 10 102 78 10 2 2 6
+- 6 6 6 54 54 54 14 14 14 2 2 6
+- 2 2 6 62 62 62 74 74 74 30 30 30
+- 10 10 10 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 34 34 34 78 78 78 50 50 50 6 6 6
+- 94 70 30 139 102 15 190 146 13 226 184 13
+-232 200 30 232 195 16 215 174 15 190 146 13
+-168 122 10 192 133 9 210 150 10 213 154 11
+-202 150 34 182 157 106 101 98 89 2 2 6
+- 2 2 6 78 78 78 116 116 116 58 58 58
+- 2 2 6 22 22 22 90 90 90 46 46 46
+- 18 18 18 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 38 38 38 86 86 86 50 50 50 6 6 6
+-128 128 128 174 154 114 156 107 11 168 122 10
+-198 155 10 184 144 12 197 138 11 200 144 11
+-206 145 10 206 145 10 197 138 11 188 164 115
+-195 195 195 198 198 198 174 174 174 14 14 14
+- 2 2 6 22 22 22 116 116 116 116 116 116
+- 22 22 22 2 2 6 74 74 74 70 70 70
+- 30 30 30 10 10 10 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 18 18 18
+- 50 50 50 101 101 101 26 26 26 10 10 10
+-138 138 138 190 190 190 174 154 114 156 107 11
+-197 138 11 200 144 11 197 138 11 192 133 9
+-180 123 7 190 142 34 190 178 144 187 187 187
+-202 202 202 221 221 221 214 214 214 66 66 66
+- 2 2 6 2 2 6 50 50 50 62 62 62
+- 6 6 6 2 2 6 10 10 10 90 90 90
+- 50 50 50 18 18 18 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 10 10 10 34 34 34
+- 74 74 74 74 74 74 2 2 6 6 6 6
+-144 144 144 198 198 198 190 190 190 178 166 146
+-154 121 60 156 107 11 156 107 11 168 124 44
+-174 154 114 187 187 187 190 190 190 210 210 210
+-246 246 246 253 253 253 253 253 253 182 182 182
+- 6 6 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 62 62 62
+- 74 74 74 34 34 34 14 14 14 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 10 10 10 22 22 22 54 54 54
+- 94 94 94 18 18 18 2 2 6 46 46 46
+-234 234 234 221 221 221 190 190 190 190 190 190
+-190 190 190 187 187 187 187 187 187 190 190 190
+-190 190 190 195 195 195 214 214 214 242 242 242
+-253 253 253 253 253 253 253 253 253 253 253 253
+- 82 82 82 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 14 14 14
+- 86 86 86 54 54 54 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 18 18 18 46 46 46 90 90 90
+- 46 46 46 18 18 18 6 6 6 182 182 182
+-253 253 253 246 246 246 206 206 206 190 190 190
+-190 190 190 190 190 190 190 190 190 190 190 190
+-206 206 206 231 231 231 250 250 250 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-202 202 202 14 14 14 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 42 42 42 86 86 86 42 42 42 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 14 14 14 38 38 38 74 74 74 66 66 66
+- 2 2 6 6 6 6 90 90 90 250 250 250
+-253 253 253 253 253 253 238 238 238 198 198 198
+-190 190 190 190 190 190 195 195 195 221 221 221
+-246 246 246 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 82 82 82 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 78 78 78 70 70 70 34 34 34
+- 14 14 14 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 34 34 34 66 66 66 78 78 78 6 6 6
+- 2 2 6 18 18 18 218 218 218 253 253 253
+-253 253 253 253 253 253 253 253 253 246 246 246
+-226 226 226 231 231 231 246 246 246 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 178 178 178 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 18 18 18 90 90 90 62 62 62
+- 30 30 30 10 10 10 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 10 10 10 26 26 26
+- 58 58 58 90 90 90 18 18 18 2 2 6
+- 2 2 6 110 110 110 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-250 250 250 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 231 231 231 18 18 18 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 18 18 18 94 94 94
+- 54 54 54 26 26 26 10 10 10 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 22 22 22 50 50 50
+- 90 90 90 26 26 26 2 2 6 2 2 6
+- 14 14 14 195 195 195 250 250 250 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-250 250 250 242 242 242 54 54 54 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 38 38 38
+- 86 86 86 50 50 50 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 14 14 14 38 38 38 82 82 82
+- 34 34 34 2 2 6 2 2 6 2 2 6
+- 42 42 42 195 195 195 246 246 246 253 253 253
+-253 253 253 253 253 253 253 253 253 250 250 250
+-242 242 242 242 242 242 250 250 250 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 250 250 250 246 246 246 238 238 238
+-226 226 226 231 231 231 101 101 101 6 6 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 38 38 38 82 82 82 42 42 42 14 14 14
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 10 10 10 26 26 26 62 62 62 66 66 66
+- 2 2 6 2 2 6 2 2 6 6 6 6
+- 70 70 70 170 170 170 206 206 206 234 234 234
+-246 246 246 250 250 250 250 250 250 238 238 238
+-226 226 226 231 231 231 238 238 238 250 250 250
+-250 250 250 250 250 250 246 246 246 231 231 231
+-214 214 214 206 206 206 202 202 202 202 202 202
+-198 198 198 202 202 202 182 182 182 18 18 18
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 62 62 62 66 66 66 30 30 30
+- 10 10 10 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 14 14 14 42 42 42 82 82 82 18 18 18
+- 2 2 6 2 2 6 2 2 6 10 10 10
+- 94 94 94 182 182 182 218 218 218 242 242 242
+-250 250 250 253 253 253 253 253 253 250 250 250
+-234 234 234 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 246 246 246
+-238 238 238 226 226 226 210 210 210 202 202 202
+-195 195 195 195 195 195 210 210 210 158 158 158
+- 6 6 6 14 14 14 50 50 50 14 14 14
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 6 6 6 86 86 86 46 46 46
+- 18 18 18 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 22 22 22 54 54 54 70 70 70 2 2 6
+- 2 2 6 10 10 10 2 2 6 22 22 22
+-166 166 166 231 231 231 250 250 250 253 253 253
+-253 253 253 253 253 253 253 253 253 250 250 250
+-242 242 242 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 246 246 246
+-231 231 231 206 206 206 198 198 198 226 226 226
+- 94 94 94 2 2 6 6 6 6 38 38 38
+- 30 30 30 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 62 62 62 66 66 66
+- 26 26 26 10 10 10 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 30 30 30 74 74 74 50 50 50 2 2 6
+- 26 26 26 26 26 26 2 2 6 106 106 106
+-238 238 238 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 246 246 246 218 218 218 202 202 202
+-210 210 210 14 14 14 2 2 6 2 2 6
+- 30 30 30 22 22 22 2 2 6 2 2 6
+- 2 2 6 2 2 6 18 18 18 86 86 86
+- 42 42 42 14 14 14 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 42 42 42 90 90 90 22 22 22 2 2 6
+- 42 42 42 2 2 6 18 18 18 218 218 218
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 250 250 250 221 221 221
+-218 218 218 101 101 101 2 2 6 14 14 14
+- 18 18 18 38 38 38 10 10 10 2 2 6
+- 2 2 6 2 2 6 2 2 6 78 78 78
+- 58 58 58 22 22 22 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 18 18 18
+- 54 54 54 82 82 82 2 2 6 26 26 26
+- 22 22 22 2 2 6 123 123 123 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 250 250 250
+-238 238 238 198 198 198 6 6 6 38 38 38
+- 58 58 58 26 26 26 38 38 38 2 2 6
+- 2 2 6 2 2 6 2 2 6 46 46 46
+- 78 78 78 30 30 30 10 10 10 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 10 10 10 30 30 30
+- 74 74 74 58 58 58 2 2 6 42 42 42
+- 2 2 6 22 22 22 231 231 231 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 250 250 250
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 246 246 246 46 46 46 38 38 38
+- 42 42 42 14 14 14 38 38 38 14 14 14
+- 2 2 6 2 2 6 2 2 6 6 6 6
+- 86 86 86 46 46 46 14 14 14 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 14 14 14 42 42 42
+- 90 90 90 18 18 18 18 18 18 26 26 26
+- 2 2 6 116 116 116 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 250 250 250 238 238 238
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 94 94 94 6 6 6
+- 2 2 6 2 2 6 10 10 10 34 34 34
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 74 74 74 58 58 58 22 22 22 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 10 10 10 26 26 26 66 66 66
+- 82 82 82 2 2 6 38 38 38 6 6 6
+- 14 14 14 210 210 210 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 246 246 246 242 242 242
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 144 144 144 2 2 6
+- 2 2 6 2 2 6 2 2 6 46 46 46
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 42 42 42 74 74 74 30 30 30 10 10 10
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 14 14 14 42 42 42 90 90 90
+- 26 26 26 6 6 6 42 42 42 2 2 6
+- 74 74 74 250 250 250 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 242 242 242 242 242 242
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 182 182 182 2 2 6
+- 2 2 6 2 2 6 2 2 6 46 46 46
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 10 10 10 86 86 86 38 38 38 10 10 10
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 10 10 10 26 26 26 66 66 66 82 82 82
+- 2 2 6 22 22 22 18 18 18 2 2 6
+-149 149 149 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 234 234 234 242 242 242
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 206 206 206 2 2 6
+- 2 2 6 2 2 6 2 2 6 38 38 38
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 6 6 6 86 86 86 46 46 46 14 14 14
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 18 18 18 46 46 46 86 86 86 18 18 18
+- 2 2 6 34 34 34 10 10 10 6 6 6
+-210 210 210 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 234 234 234 242 242 242
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 221 221 221 6 6 6
+- 2 2 6 2 2 6 6 6 6 30 30 30
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 82 82 82 54 54 54 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 26 26 26 66 66 66 62 62 62 2 2 6
+- 2 2 6 38 38 38 10 10 10 26 26 26
+-238 238 238 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 238 238 238
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 6 6 6
+- 2 2 6 2 2 6 10 10 10 30 30 30
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 66 66 66 58 58 58 22 22 22
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 38 38 38 78 78 78 6 6 6 2 2 6
+- 2 2 6 46 46 46 14 14 14 42 42 42
+-246 246 246 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 242 242 242
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 234 234 234 10 10 10
+- 2 2 6 2 2 6 22 22 22 14 14 14
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 66 66 66 62 62 62 22 22 22
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 18 18 18
+- 50 50 50 74 74 74 2 2 6 2 2 6
+- 14 14 14 70 70 70 34 34 34 62 62 62
+-250 250 250 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 246 246 246
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 234 234 234 14 14 14
+- 2 2 6 2 2 6 30 30 30 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 66 66 66 62 62 62 22 22 22
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 18 18 18
+- 54 54 54 62 62 62 2 2 6 2 2 6
+- 2 2 6 30 30 30 46 46 46 70 70 70
+-250 250 250 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 246 246 246
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 226 226 226 10 10 10
+- 2 2 6 6 6 6 30 30 30 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 66 66 66 58 58 58 22 22 22
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 22 22 22
+- 58 58 58 62 62 62 2 2 6 2 2 6
+- 2 2 6 2 2 6 30 30 30 78 78 78
+-250 250 250 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 246 246 246
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 206 206 206 2 2 6
+- 22 22 22 34 34 34 18 14 6 22 22 22
+- 26 26 26 18 18 18 6 6 6 2 2 6
+- 2 2 6 82 82 82 54 54 54 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 26 26 26
+- 62 62 62 106 106 106 74 54 14 185 133 11
+-210 162 10 121 92 8 6 6 6 62 62 62
+-238 238 238 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 246 246 246
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 158 158 158 18 18 18
+- 14 14 14 2 2 6 2 2 6 2 2 6
+- 6 6 6 18 18 18 66 66 66 38 38 38
+- 6 6 6 94 94 94 50 50 50 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 10 10 10 10 10 10 18 18 18 38 38 38
+- 78 78 78 142 134 106 216 158 10 242 186 14
+-246 190 14 246 190 14 156 118 10 10 10 10
+- 90 90 90 238 238 238 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 250 250 250
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 246 230 190
+-238 204 91 238 204 91 181 142 44 37 26 9
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 38 38 38 46 46 46
+- 26 26 26 106 106 106 54 54 54 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 14 14 14 22 22 22
+- 30 30 30 38 38 38 50 50 50 70 70 70
+-106 106 106 190 142 34 226 170 11 242 186 14
+-246 190 14 246 190 14 246 190 14 154 114 10
+- 6 6 6 74 74 74 226 226 226 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 231 231 231 250 250 250
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 228 184 62
+-241 196 14 241 208 19 232 195 16 38 30 10
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 6 6 6 30 30 30 26 26 26
+-203 166 17 154 142 90 66 66 66 26 26 26
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 18 18 18 38 38 38 58 58 58
+- 78 78 78 86 86 86 101 101 101 123 123 123
+-175 146 61 210 150 10 234 174 13 246 186 14
+-246 190 14 246 190 14 246 190 14 238 190 10
+-102 78 10 2 2 6 46 46 46 198 198 198
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 234 234 234 242 242 242
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 224 178 62
+-242 186 14 241 196 14 210 166 10 22 18 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 6 6 6 121 92 8
+-238 202 15 232 195 16 82 82 82 34 34 34
+- 10 10 10 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 14 14 14 38 38 38 70 70 70 154 122 46
+-190 142 34 200 144 11 197 138 11 197 138 11
+-213 154 11 226 170 11 242 186 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-225 175 15 46 32 6 2 2 6 22 22 22
+-158 158 158 250 250 250 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 250 250 250 242 242 242 224 178 62
+-239 182 13 236 186 11 213 154 11 46 32 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 61 42 6 225 175 15
+-238 190 10 236 186 11 112 100 78 42 42 42
+- 14 14 14 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 22 22 22 54 54 54 154 122 46 213 154 11
+-226 170 11 230 174 11 226 170 11 226 170 11
+-236 178 12 242 186 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-241 196 14 184 144 12 10 10 10 2 2 6
+- 6 6 6 116 116 116 242 242 242 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 231 231 231 198 198 198 214 170 54
+-236 178 12 236 178 12 210 150 10 137 92 6
+- 18 14 6 2 2 6 2 2 6 2 2 6
+- 6 6 6 70 47 6 200 144 11 236 178 12
+-239 182 13 239 182 13 124 112 88 58 58 58
+- 22 22 22 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 30 30 30 70 70 70 180 133 36 226 170 11
+-239 182 13 242 186 14 242 186 14 246 186 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 232 195 16 98 70 6 2 2 6
+- 2 2 6 2 2 6 66 66 66 221 221 221
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 206 206 206 198 198 198 214 166 58
+-230 174 11 230 174 11 216 158 10 192 133 9
+-163 110 8 116 81 8 102 78 10 116 81 8
+-167 114 7 197 138 11 226 170 11 239 182 13
+-242 186 14 242 186 14 162 146 94 78 78 78
+- 34 34 34 14 14 14 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 30 30 30 78 78 78 190 142 34 226 170 11
+-239 182 13 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 241 196 14 203 166 17 22 18 6
+- 2 2 6 2 2 6 2 2 6 38 38 38
+-218 218 218 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-250 250 250 206 206 206 198 198 198 202 162 69
+-226 170 11 236 178 12 224 166 10 210 150 10
+-200 144 11 197 138 11 192 133 9 197 138 11
+-210 150 10 226 170 11 242 186 14 246 190 14
+-246 190 14 246 186 14 225 175 15 124 112 88
+- 62 62 62 30 30 30 14 14 14 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 30 30 30 78 78 78 174 135 50 224 166 10
+-239 182 13 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 241 196 14 139 102 15
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 78 78 78 250 250 250 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-250 250 250 214 214 214 198 198 198 190 150 46
+-219 162 10 236 178 12 234 174 13 224 166 10
+-216 158 10 213 154 11 213 154 11 216 158 10
+-226 170 11 239 182 13 246 190 14 246 190 14
+-246 190 14 246 190 14 242 186 14 206 162 42
+-101 101 101 58 58 58 30 30 30 14 14 14
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 30 30 30 74 74 74 174 135 50 216 158 10
+-236 178 12 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 241 196 14 226 184 13
+- 61 42 6 2 2 6 2 2 6 2 2 6
+- 22 22 22 238 238 238 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 226 226 226 187 187 187 180 133 36
+-216 158 10 236 178 12 239 182 13 236 178 12
+-230 174 11 226 170 11 226 170 11 230 174 11
+-236 178 12 242 186 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 186 14 239 182 13
+-206 162 42 106 106 106 66 66 66 34 34 34
+- 14 14 14 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 26 26 26 70 70 70 163 133 67 213 154 11
+-236 178 12 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 241 196 14
+-190 146 13 18 14 6 2 2 6 2 2 6
+- 46 46 46 246 246 246 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 221 221 221 86 86 86 156 107 11
+-216 158 10 236 178 12 242 186 14 246 186 14
+-242 186 14 239 182 13 239 182 13 242 186 14
+-242 186 14 246 186 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-242 186 14 225 175 15 142 122 72 66 66 66
+- 30 30 30 10 10 10 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 26 26 26 70 70 70 163 133 67 210 150 10
+-236 178 12 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-232 195 16 121 92 8 34 34 34 106 106 106
+-221 221 221 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-242 242 242 82 82 82 18 14 6 163 110 8
+-216 158 10 236 178 12 242 186 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 242 186 14 163 133 67
+- 46 46 46 18 18 18 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 10 10 10
+- 30 30 30 78 78 78 163 133 67 210 150 10
+-236 178 12 246 186 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-241 196 14 215 174 15 190 178 144 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 218 218 218
+- 58 58 58 2 2 6 22 18 6 167 114 7
+-216 158 10 236 178 12 246 186 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 186 14 242 186 14 190 150 46
+- 54 54 54 22 22 22 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 38 38 38 86 86 86 180 133 36 213 154 11
+-236 178 12 246 186 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 232 195 16 190 146 13 214 214 214
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 250 250 250 170 170 170 26 26 26
+- 2 2 6 2 2 6 37 26 9 163 110 8
+-219 162 10 239 182 13 246 186 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 186 14 236 178 12 224 166 10 142 122 72
+- 46 46 46 18 18 18 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 18 18 18
+- 50 50 50 109 106 95 192 133 9 224 166 10
+-242 186 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-242 186 14 226 184 13 210 162 10 142 110 46
+-226 226 226 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-253 253 253 253 253 253 253 253 253 253 253 253
+-198 198 198 66 66 66 2 2 6 2 2 6
+- 2 2 6 2 2 6 50 34 6 156 107 11
+-219 162 10 239 182 13 246 186 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 242 186 14
+-234 174 13 213 154 11 154 122 46 66 66 66
+- 30 30 30 10 10 10 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 22 22 22
+- 58 58 58 154 121 60 206 145 10 234 174 13
+-242 186 14 246 186 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 186 14 236 178 12 210 162 10 163 110 8
+- 61 42 6 138 138 138 218 218 218 250 250 250
+-253 253 253 253 253 253 253 253 253 250 250 250
+-242 242 242 210 210 210 144 144 144 66 66 66
+- 6 6 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 61 42 6 163 110 8
+-216 158 10 236 178 12 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 239 182 13 230 174 11 216 158 10
+-190 142 34 124 112 88 70 70 70 38 38 38
+- 18 18 18 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 22 22 22
+- 62 62 62 168 124 44 206 145 10 224 166 10
+-236 178 12 239 182 13 242 186 14 242 186 14
+-246 186 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 236 178 12 216 158 10 175 118 6
+- 80 54 7 2 2 6 6 6 6 30 30 30
+- 54 54 54 62 62 62 50 50 50 38 38 38
+- 14 14 14 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 6 6 6 80 54 7 167 114 7
+-213 154 11 236 178 12 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 190 14 242 186 14 239 182 13 239 182 13
+-230 174 11 210 150 10 174 135 50 124 112 88
+- 82 82 82 54 54 54 34 34 34 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 18 18 18
+- 50 50 50 158 118 36 192 133 9 200 144 11
+-216 158 10 219 162 10 224 166 10 226 170 11
+-230 174 11 236 178 12 239 182 13 239 182 13
+-242 186 14 246 186 14 246 190 14 246 190 14
+-246 190 14 246 190 14 246 190 14 246 190 14
+-246 186 14 230 174 11 210 150 10 163 110 8
+-104 69 6 10 10 10 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 6 6 6 91 60 6 167 114 7
+-206 145 10 230 174 11 242 186 14 246 190 14
+-246 190 14 246 190 14 246 186 14 242 186 14
+-239 182 13 230 174 11 224 166 10 213 154 11
+-180 133 36 124 112 88 86 86 86 58 58 58
+- 38 38 38 22 22 22 10 10 10 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 14 14 14
+- 34 34 34 70 70 70 138 110 50 158 118 36
+-167 114 7 180 123 7 192 133 9 197 138 11
+-200 144 11 206 145 10 213 154 11 219 162 10
+-224 166 10 230 174 11 239 182 13 242 186 14
+-246 186 14 246 186 14 246 186 14 246 186 14
+-239 182 13 216 158 10 185 133 11 152 99 6
+-104 69 6 18 14 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 2 2 6 2 2 6 2 2 6
+- 2 2 6 6 6 6 80 54 7 152 99 6
+-192 133 9 219 162 10 236 178 12 239 182 13
+-246 186 14 242 186 14 239 182 13 236 178 12
+-224 166 10 206 145 10 192 133 9 154 121 60
+- 94 94 94 62 62 62 42 42 42 22 22 22
+- 14 14 14 6 6 6 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 18 18 18 34 34 34 58 58 58 78 78 78
+-101 98 89 124 112 88 142 110 46 156 107 11
+-163 110 8 167 114 7 175 118 6 180 123 7
+-185 133 11 197 138 11 210 150 10 219 162 10
+-226 170 11 236 178 12 236 178 12 234 174 13
+-219 162 10 197 138 11 163 110 8 130 83 6
+- 91 60 6 10 10 10 2 2 6 2 2 6
+- 18 18 18 38 38 38 38 38 38 38 38 38
+- 38 38 38 38 38 38 38 38 38 38 38 38
+- 38 38 38 38 38 38 26 26 26 2 2 6
+- 2 2 6 6 6 6 70 47 6 137 92 6
+-175 118 6 200 144 11 219 162 10 230 174 11
+-234 174 13 230 174 11 219 162 10 210 150 10
+-192 133 9 163 110 8 124 112 88 82 82 82
+- 50 50 50 30 30 30 14 14 14 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 14 14 14 22 22 22 34 34 34
+- 42 42 42 58 58 58 74 74 74 86 86 86
+-101 98 89 122 102 70 130 98 46 121 87 25
+-137 92 6 152 99 6 163 110 8 180 123 7
+-185 133 11 197 138 11 206 145 10 200 144 11
+-180 123 7 156 107 11 130 83 6 104 69 6
+- 50 34 6 54 54 54 110 110 110 101 98 89
+- 86 86 86 82 82 82 78 78 78 78 78 78
+- 78 78 78 78 78 78 78 78 78 78 78 78
+- 78 78 78 82 82 82 86 86 86 94 94 94
+-106 106 106 101 101 101 86 66 34 124 80 6
+-156 107 11 180 123 7 192 133 9 200 144 11
+-206 145 10 200 144 11 192 133 9 175 118 6
+-139 102 15 109 106 95 70 70 70 42 42 42
+- 22 22 22 10 10 10 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 6 6 6 10 10 10
+- 14 14 14 22 22 22 30 30 30 38 38 38
+- 50 50 50 62 62 62 74 74 74 90 90 90
+-101 98 89 112 100 78 121 87 25 124 80 6
+-137 92 6 152 99 6 152 99 6 152 99 6
+-138 86 6 124 80 6 98 70 6 86 66 30
+-101 98 89 82 82 82 58 58 58 46 46 46
+- 38 38 38 34 34 34 34 34 34 34 34 34
+- 34 34 34 34 34 34 34 34 34 34 34 34
+- 34 34 34 34 34 34 38 38 38 42 42 42
+- 54 54 54 82 82 82 94 86 76 91 60 6
+-134 86 6 156 107 11 167 114 7 175 118 6
+-175 118 6 167 114 7 152 99 6 121 87 25
+-101 98 89 62 62 62 34 34 34 18 18 18
+- 6 6 6 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 6 6 6 10 10 10
+- 18 18 18 22 22 22 30 30 30 42 42 42
+- 50 50 50 66 66 66 86 86 86 101 98 89
+-106 86 58 98 70 6 104 69 6 104 69 6
+-104 69 6 91 60 6 82 62 34 90 90 90
+- 62 62 62 38 38 38 22 22 22 14 14 14
+- 10 10 10 10 10 10 10 10 10 10 10 10
+- 10 10 10 10 10 10 6 6 6 10 10 10
+- 10 10 10 10 10 10 10 10 10 14 14 14
+- 22 22 22 42 42 42 70 70 70 89 81 66
+- 80 54 7 104 69 6 124 80 6 137 92 6
+-134 86 6 116 81 8 100 82 52 86 86 86
+- 58 58 58 30 30 30 14 14 14 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 10 10 10 14 14 14
+- 18 18 18 26 26 26 38 38 38 54 54 54
+- 70 70 70 86 86 86 94 86 76 89 81 66
+- 89 81 66 86 86 86 74 74 74 50 50 50
+- 30 30 30 14 14 14 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 18 18 18 34 34 34 58 58 58
+- 82 82 82 89 81 66 89 81 66 89 81 66
+- 94 86 66 94 86 76 74 74 74 50 50 50
+- 26 26 26 14 14 14 6 6 6 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 6 6 6 6 6 6 14 14 14 18 18 18
+- 30 30 30 38 38 38 46 46 46 54 54 54
+- 50 50 50 42 42 42 30 30 30 18 18 18
+- 10 10 10 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 6 6 6 14 14 14 26 26 26
+- 38 38 38 50 50 50 58 58 58 58 58 58
+- 54 54 54 42 42 42 30 30 30 18 18 18
+- 10 10 10 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 6 6 6 10 10 10 14 14 14 18 18 18
+- 18 18 18 14 14 14 10 10 10 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 6 6 6
+- 14 14 14 18 18 18 22 22 22 22 22 22
+- 18 18 18 14 14 14 10 10 10 6 6 6
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
+- 0 0 0 0 0 0 0 0 0 0 0 0
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 253 243 247
++250 231 237 248 216 227 242 190 209 242 190 209 242 190 209 242 190 209
++248 216 227 250 231 237 254 253 253 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 252 251 239 250 247 226 245 244 203 228 234 180 228 234 180
++228 234 180 245 244 203 250 247 226 252 251 239 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 248 216 227 239 172 194 231 129 171 224 95 140
++218 61 124 215 47 116 214 40 114 212 36 111 213 38 112 214 40 114
++215 47 116 220 74 128 224 95 140 236 151 178 242 190 209 253 243 247
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 254 253 253 245 244 203 226 232 147
++211 222 128 196 211 92 193 208 58 180 198 43 180 198 43 179 197 38
++180 198 43 180 198 43 193 208 58 196 211 92 211 222 128 226 232 147
++245 244 203 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 253 243 247
++239 172 194 224 95 140 215 47 116 211 23 102 211 23 102 211 23 102
++212 31 106 213 35 108 212 36 111 212 36 111 212 36 111 212 36 111
++213 35 108 212 31 106 211 23 102 211 23 102 212 36 111 220 62 124
++231 129 171 248 216 227 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 250 247 226 226 232 147 196 211 92 184 202 41 175 195 20
++175 195 20 175 195 31 176 195 35 179 197 38 179 197 38 179 197 38
++177 196 38 176 195 35 175 195 31 175 195 31 166 188 23 166 188 23
++180 198 43 196 211 92 226 232 147 250 250 231 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 254 253 253 239 172 194 220 74 128
++211 23 102 211 23 102 212 31 106 213 35 108 212 36 111 212 36 111
++212 36 111 212 36 111 212 36 111 212 36 111 212 36 111 212 36 111
++212 36 111 212 36 111 212 36 111 212 36 111 213 35 108 212 31 106
++211 23 102 213 37 112 229 120 149 248 216 227 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 250 247 226
++211 222 128 189 205 44 182 200 31 182 200 31 182 200 31 182 200 39
++182 200 39 181 200 38 179 197 38 179 197 38 179 197 38 179 197 38
++179 197 38 177 196 38 175 195 37 176 195 35 175 195 37 174 194 36
++175 195 31 166 188 23 166 188 23 176 196 49 211 222 128 250 250 231
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 248 216 227 224 95 140 211 23 102 211 23 102
++212 36 111 212 36 111 212 36 111 212 36 111 212 36 111 212 36 111
++212 36 111 212 36 111 212 36 111 212 36 111 212 36 111 213 37 112
++213 37 112 213 37 112 213 37 112 213 37 112 213 38 112 213 38 112
++214 38 113 212 36 111 211 23 102 214 40 114 231 129 171 253 243 247
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 226 232 147 193 208 58
++182 200 31 181 200 38 186 202 40 184 202 41 182 200 39 182 200 39
++182 200 39 182 200 39 181 200 38 179 197 38 179 197 38 179 197 38
++179 197 38 177 196 38 175 195 37 176 195 35 176 195 35 175 195 37
++174 194 36 174 194 36 173 192 36 169 190 33 166 188 23 193 208 58
++228 234 180 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 236 151 178 213 38 112 211 23 102 213 35 108 212 36 111
++212 36 111 212 36 111 212 36 111 212 36 111 212 36 111 212 36 111
++212 36 111 212 36 111 212 36 111 213 37 112 213 37 112 213 37 112
++213 37 112 213 37 112 213 38 112 213 38 112 214 38 113 214 38 113
++214 38 113 214 38 113 214 38 113 213 35 108 211 23 102 223 80 132
++248 216 227 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 250 250 231 196 211 92 182 200 31 182 200 31
++186 202 40 186 202 40 186 202 40 184 202 41 184 202 41 182 200 39
++182 200 39 182 200 39 182 200 39 181 200 38 179 197 38 179 197 38
++179 197 38 177 196 38 177 196 38 175 195 37 176 195 35 175 195 37
++175 195 37 174 194 36 173 192 36 173 192 36 173 192 36 166 188 23
++166 188 23 211 222 128 252 251 239 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 251 247
++229 120 149 211 23 102 212 31 106 212 36 111 212 36 111 212 36 111
++212 36 111 212 36 111 212 36 111 213 37 112 213 37 112 213 37 112
++213 37 112 213 37 112 213 37 112 213 37 112 213 38 112 214 38 113
++214 38 113 214 38 113 214 38 113 214 38 113 214 38 113 214 38 113
++215 39 113 215 39 113 215 39 113 215 39 113 215 39 113 212 31 106
++216 43 114 239 172 194 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 245 244 203 193 208 58 182 200 31 187 203 40 187 203 40
++186 202 40 186 202 40 186 202 40 186 202 40 184 202 41 182 200 39
++182 200 39 182 200 39 182 200 39 181 200 38 179 197 38 179 197 38
++179 197 38 179 197 38 177 196 38 177 196 38 175 195 37 175 195 37
++175 195 37 174 194 36 174 194 36 173 192 36 173 192 36 173 192 36
++171 191 36 166 188 23 196 211 92 250 247 226 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 253 243 247 224 95 140
++211 23 102 213 35 108 212 36 111 212 36 111 212 36 111 212 36 111
++212 36 111 213 37 112 213 37 112 213 37 112 213 37 112 213 37 112
++213 38 112 213 38 112 214 38 113 214 38 113 214 38 113 214 38 113
++214 38 113 214 38 113 214 38 113 215 39 113 215 39 113 215 39 113
++215 39 113 215 39 113 215 39 113 216 41 113 216 41 113 216 41 113
++213 35 108 212 31 106 236 151 178 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++245 244 203 193 208 58 182 200 31 189 204 42 189 204 42 187 203 40
++187 203 40 186 202 40 186 202 40 186 202 40 184 202 41 184 202 41
++182 200 39 182 200 39 182 200 39 181 200 38 181 200 38 179 197 38
++179 197 38 179 197 38 177 196 38 177 196 38 177 196 38 176 195 35
++175 195 37 175 195 37 174 194 36 173 192 37 173 192 36 173 192 36
++173 192 36 169 190 33 166 188 23 176 196 49 247 246 214 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 253 243 247 224 95 140 211 23 102
++212 36 111 212 36 111 213 37 112 213 37 112 213 37 112 213 37 112
++213 37 112 213 38 112 213 38 112 214 38 113 214 38 113 214 38 113
++214 38 113 214 38 113 214 38 113 214 38 113 215 39 113 215 39 113
++215 39 113 215 39 113 215 39 113 215 39 113 216 41 113 216 41 113
++216 41 113 216 41 113 216 41 113 216 41 113 216 41 113 216 43 114
++216 43 114 213 37 112 212 31 106 239 172 194 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 245 244 203
++195 209 44 188 204 31 189 204 42 189 204 42 189 204 42 187 203 42
++187 203 40 187 203 40 186 202 40 186 202 40 186 202 40 184 202 41
++184 202 41 182 200 39 182 200 39 182 200 39 182 200 39 181 200 38
++179 197 38 179 197 38 179 197 38 177 196 38 177 196 38 175 195 37
++176 195 35 175 195 37 175 194 36 174 194 36 173 192 37 173 192 36
++173 192 36 173 192 36 171 191 36 166 188 23 176 196 49 250 247 226
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 231 129 171 211 23 102 212 36 111
++213 37 112 213 37 112 213 37 112 213 37 112 213 37 112 213 38 112
++213 38 112 214 38 113 214 38 113 214 38 113 214 38 113 214 38 113
++214 38 113 214 38 113 215 39 113 215 39 113 215 39 113 215 39 113
++215 39 113 215 39 113 216 41 113 216 41 113 216 41 113 216 41 113
++216 41 113 216 41 113 216 41 113 216 43 114 216 43 114 216 43 114
++216 43 114 216 43 114 214 39 110 214 39 110 242 190 209 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 247 246 214 193 208 58
++188 204 31 190 206 42 190 206 42 189 205 40 189 204 42 189 204 42
++187 203 42 186 203 40 186 202 40 186 202 40 186 202 40 186 202 40
++184 202 41 182 200 39 182 200 39 182 200 39 182 200 39 181 200 38
++179 197 38 179 197 38 179 197 38 179 197 38 177 196 38 175 195 37
++176 195 35 175 195 37 175 195 37 174 194 36 174 194 36 173 192 36
++173 192 36 173 192 36 171 191 36 171 191 36 166 188 23 196 211 92
++250 252 247 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 239 172 194 211 23 102 213 35 108 213 38 112
++213 38 112 214 38 113 214 38 113 214 38 113 214 38 113 214 38 113
++214 38 113 214 38 113 215 39 113 215 39 113 215 39 113 215 39 113
++215 39 113 215 39 113 215 39 113 216 41 113 216 41 113 216 41 113
++216 41 113 216 41 113 216 41 113 216 41 113 216 41 113 216 41 113
++216 43 114 216 43 114 216 43 114 216 43 114 216 43 114 216 43 114
++216 43 114 217 45 113 217 45 113 213 35 108 218 61 124 248 216 227
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 250 252 247 196 211 92 188 204 31
++190 206 42 190 206 42 190 206 42 189 204 42 189 204 42 189 204 42
++189 204 42 187 203 40 187 203 40 186 202 40 186 202 40 186 202 40
++184 202 41 182 200 39 182 200 39 182 200 39 182 200 39 181 200 38
++181 200 38 179 197 38 179 197 38 179 197 38 179 197 38 177 196 38
++177 196 38 176 195 35 175 195 37 175 194 36 174 194 36 173 192 37
++173 192 36 173 192 36 173 192 36 171 191 36 171 191 36 166 188 23
++211 222 128 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 248 216 227 215 47 116 212 31 106 214 38 113 214 38 113
++214 38 113 214 38 113 214 38 113 214 38 113 214 38 113 214 38 113
++215 39 113 215 39 113 215 39 113 215 39 113 215 39 113 215 39 113
++215 39 113 213 35 108 212 31 106 212 31 106 212 31 106 212 31 106
++213 37 112 216 43 114 216 43 114 216 43 114 216 43 114 216 43 114
++216 43 114 216 43 114 216 43 114 216 43 114 217 45 113 217 45 113
++217 45 113 217 45 113 217 45 113 217 45 113 212 31 106 224 95 140
++254 253 253 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 226 232 147 188 204 31 193 208 43
++192 206 41 190 206 42 190 206 42 189 205 40 189 204 42 189 204 42
++189 204 42 187 203 42 187 203 40 186 202 40 186 202 40 186 202 40
++184 202 41 184 202 41 181 200 38 182 200 31 175 195 20 175 195 20
++175 195 31 175 195 31 178 196 36 179 197 38 179 197 38 177 196 38
++177 196 38 176 195 35 175 195 37 175 195 37 174 194 36 173 192 36
++173 192 36 173 192 36 173 192 36 171 191 36 171 191 36 169 190 33
++166 188 23 228 234 180 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 224 95 140 211 23 102 214 38 113 214 38 113 214 38 113
++214 38 113 215 39 113 215 39 113 215 39 113 215 39 113 215 39 113
++215 39 113 216 41 113 216 41 113 216 41 113 213 35 108 212 31 106
++213 37 109 221 69 124 224 95 140 229 120 149 229 120 149 224 95 140
++218 61 124 213 35 108 213 35 108 215 39 113 216 43 114 216 43 114
++217 45 113 216 43 114 217 45 113 217 45 113 217 45 113 217 45 113
++217 45 113 217 45 113 217 45 113 215 47 116 218 48 113 213 35 108
++239 172 194 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 245 244 203 195 209 44 192 207 33 193 208 43
++193 208 43 190 206 42 190 206 42 190 206 42 190 206 42 189 204 42
++189 204 42 189 204 42 187 203 40 187 203 40 186 202 40 187 203 38
++182 200 31 182 200 31 187 203 42 196 211 92 196 211 92 196 211 92
++196 211 92 193 208 58 179 197 38 175 195 31 175 195 31 176 195 35
++177 196 38 175 195 37 176 195 35 175 195 37 175 195 37 174 194 36
++174 194 36 173 192 36 173 192 36 173 192 36 171 191 36 171 191 36
++166 188 23 176 196 49 252 251 239 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++242 190 209 212 31 106 213 37 112 214 38 113 215 39 113 215 39 113
++215 39 113 215 39 113 215 39 113 215 39 113 215 39 113 216 41 113
++216 41 113 216 41 113 213 37 109 212 31 106 220 62 124 231 129 171
++248 216 227 250 231 237 254 251 247 255 255 255 255 255 255 253 243 247
++250 231 237 242 190 209 229 120 149 215 47 116 212 31 106 216 43 114
++217 45 113 217 45 113 217 45 113 217 45 113 217 45 113 217 45 113
++218 48 113 218 48 113 218 48 113 218 48 113 218 48 113 217 40 109
++221 69 124 253 243 247 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 229 218 98 188 204 31 193 208 43 193 208 43
++193 208 43 192 206 41 190 206 42 190 206 42 190 206 42 189 204 42
++189 205 40 189 204 42 187 203 42 187 203 40 182 200 31 182 200 31
++196 211 92 228 234 180 250 247 226 252 251 239 254 253 253 255 255 255
++254 253 253 252 251 239 247 246 214 226 232 147 196 211 92 175 195 31
++175 195 31 177 196 38 176 195 35 175 195 37 175 195 37 174 194 36
++174 194 36 173 192 36 173 192 36 173 192 36 171 191 36 171 191 36
++171 191 36 166 188 23 211 222 128 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 251 247
++224 95 140 211 23 102 215 39 113 215 39 113 215 39 113 215 39 113
++215 39 113 215 39 113 215 39 113 216 41 113 216 41 113 216 41 113
++216 41 113 213 35 108 216 41 113 236 151 178 250 231 237 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 248 216 227 224 95 140 212 31 106
++216 43 114 215 47 116 218 48 113 218 48 113 215 47 116 218 48 113
++218 48 113 218 48 113 218 50 114 218 50 114 218 50 114 218 50 114
++213 35 108 236 151 178 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 245 244 203 192 207 33 193 208 43 195 209 44 193 208 43
++193 208 43 193 208 43 190 206 42 190 206 42 190 206 42 189 204 42
++189 205 40 189 204 42 189 204 42 182 200 31 193 208 58 228 234 180
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 254 253 253 228 234 180
++176 196 49 175 195 20 177 196 38 176 195 35 175 195 37 174 194 36
++174 194 36 174 194 36 173 192 36 173 192 36 173 192 36 171 191 36
++171 191 36 169 190 33 176 196 49 250 250 231 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 190 209
++213 35 108 213 37 112 215 39 113 216 41 113 216 41 113 216 41 113
++216 41 113 216 41 113 216 41 113 216 43 114 216 43 114 216 43 114
++213 35 108 218 61 124 242 190 209 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 254 253 253 236 151 178
++217 40 109 216 43 114 218 50 114 218 48 113 218 50 114 218 50 114
++218 50 114 218 50 114 218 50 114 218 50 114 218 50 114 219 52 114
++217 44 109 223 80 132 253 243 247 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 211 222 128 192 207 33 195 209 44 195 209 44 193 208 43
++193 208 43 193 208 43 192 206 41 190 206 42 190 206 42 190 206 42
++189 204 42 187 203 40 182 200 31 196 211 92 252 251 239 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++247 246 214 196 211 92 175 195 20 175 195 37 176 195 35 175 195 37
++174 194 36 174 194 36 173 192 36 173 192 36 173 192 36 171 191 36
++171 191 36 169 190 33 166 188 23 211 222 128 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 231 129 171
++211 23 102 216 41 113 216 41 113 216 41 113 216 41 113 216 41 113
++216 41 113 216 43 114 216 43 114 216 43 114 216 43 114 213 35 108
++218 61 124 248 216 227 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++236 151 178 217 40 109 217 45 113 218 50 114 218 50 114 218 50 114
++218 50 114 218 50 114 219 52 114 219 52 114 219 52 114 219 52 114
++219 52 114 217 40 109 242 190 209 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++250 247 226 193 208 58 194 208 41 195 209 44 195 209 44 193 208 43
++193 208 43 193 208 43 193 208 43 190 206 42 190 206 42 190 206 42
++190 206 42 188 204 31 211 222 128 254 253 253 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 250 250 231 196 211 92 175 195 20 175 195 37 175 195 37
++175 195 37 174 194 36 174 194 36 173 192 36 173 192 36 173 192 36
++171 191 36 171 191 36 166 188 23 193 208 58 250 252 247 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 253 243 247 220 62 124
++213 37 112 216 41 113 216 43 114 216 43 114 216 43 114 216 43 114
++216 43 114 216 43 114 216 43 114 216 43 114 216 41 113 214 39 110
++242 190 209 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 231 129 171 213 35 108 219 52 114 219 52 114 219 52 114
++219 52 114 219 52 114 219 52 114 219 52 114 219 52 114 219 52 114
++219 52 114 217 44 109 231 129 171 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++242 234 164 192 207 33 195 209 42 195 209 44 195 209 44 195 209 44
++193 208 43 193 208 43 193 208 43 192 206 41 190 206 42 190 206 42
++188 204 31 196 211 92 250 252 247 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 250 247 226 176 196 49 175 195 31 175 195 37
++175 195 37 175 195 37 174 194 36 174 194 36 173 192 36 173 192 36
++171 191 36 171 191 36 169 190 33 169 190 33 245 244 203 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 242 190 209 213 37 109
++216 41 113 216 43 114 216 43 114 216 43 114 216 43 114 216 43 114
++216 43 114 216 43 114 216 43 114 217 45 113 212 31 106 231 129 171
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 253 243 247 223 80 132 217 44 109 219 52 114 219 52 114
++219 52 114 219 52 114 219 52 114 219 52 114 219 52 114 219 55 114
++219 55 114 218 48 113 223 80 132 253 243 247 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++211 222 128 192 207 33 197 211 44 195 209 44 195 209 44 195 209 44
++195 209 44 193 208 43 193 208 43 193 208 43 190 206 42 189 205 40
++193 208 43 247 246 214 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 228 234 180 175 195 31 176 195 35
++175 195 37 175 195 37 174 194 36 174 194 36 173 192 36 173 192 36
++173 192 36 171 191 36 171 191 36 166 188 23 211 222 128 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 236 151 178 213 35 108
++216 43 114 216 43 114 216 43 114 216 43 114 217 45 113 217 45 113
++217 45 113 217 45 113 217 45 113 217 40 109 218 61 124 250 231 237
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 239 172 194 217 40 109 218 50 114 219 52 114
++219 52 114 219 55 114 219 55 114 219 55 114 219 55 114 219 55 114
++220 58 116 219 52 114 220 59 117 248 216 227 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 252 251 239
++193 208 58 194 208 41 198 211 44 197 211 44 195 209 44 195 209 44
++195 209 44 193 208 43 193 208 43 193 208 43 193 208 43 188 204 31
++211 222 128 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 254 253 253 196 211 92 175 195 31
++176 195 35 175 195 37 175 195 37 174 194 36 173 192 37 173 192 36
++173 192 36 173 192 36 171 191 36 166 188 23 196 211 92 254 253 253
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 224 95 140 212 31 106
++216 43 114 217 45 113 217 45 113 217 45 113 217 45 113 217 45 113
++217 45 113 217 45 113 217 45 113 212 31 106 231 129 171 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 253 243 247 223 80 132 217 44 109 219 55 114
++219 55 114 219 55 114 219 55 114 220 58 116 220 58 116 220 58 116
++220 58 116 219 55 114 218 51 110 239 172 194 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 247 246 214
++198 211 44 197 211 44 197 211 44 197 211 44 197 211 44 195 209 44
++195 209 44 195 209 44 193 208 43 193 208 43 193 208 43 192 206 41
++247 246 214 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 228 234 180 175 195 20
++176 195 35 176 195 35 175 195 37 174 194 36 174 194 36 173 192 36
++173 192 36 173 192 36 171 191 36 169 190 33 176 196 49 252 251 239
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 254 251 247 223 80 132 213 35 108
++217 45 113 217 45 113 217 45 113 217 45 113 217 45 113 218 48 113
++215 47 116 218 48 113 217 45 113 217 45 113 242 190 209 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 231 129 171 217 44 109 220 58 116
++220 58 116 220 58 116 220 58 116 220 58 116 220 58 116 220 58 116
++220 58 116 220 58 116 217 44 109 236 151 178 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 237 181
++192 207 33 199 212 45 198 211 44 197 211 44 197 211 44 195 209 44
++195 209 44 195 209 44 195 209 44 193 208 43 192 207 33 196 211 92
++254 251 247 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 250 247 226 180 198 43
++175 195 31 175 195 37 175 195 37 175 195 37 174 194 36 174 194 36
++173 192 36 173 192 36 173 192 36 169 190 33 171 191 36 247 246 214
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 250 231 237 220 74 128 213 37 109
++217 45 113 218 48 113 218 48 113 215 47 116 218 48 113 218 48 113
++218 48 113 218 48 113 217 45 113 220 62 124 250 231 237 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 239 172 194 218 51 110 220 58 116
++220 58 116 220 58 116 220 58 116 220 58 116 220 59 117 220 59 117
++220 59 117 220 59 117 217 44 109 231 129 171 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 234 164
++192 207 33 199 212 45 199 212 45 198 211 44 197 211 44 197 211 44
++195 209 44 195 209 44 195 209 44 193 208 43 188 204 31 211 222 128
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 254 251 247 196 211 92
++175 195 20 176 195 35 176 195 35 175 195 37 174 194 36 174 194 36
++173 192 36 173 192 36 173 192 36 171 191 36 169 190 33 245 244 203
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 248 216 227 220 62 124 217 40 109
++218 48 113 218 48 113 218 48 113 218 48 113 218 50 114 218 50 114
++218 50 114 218 50 114 217 45 113 223 80 132 254 251 247 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 242 190 209 219 52 114 220 58 116
++220 59 117 220 59 117 220 59 117 220 59 117 220 61 116 220 61 116
++220 61 116 220 61 116 217 44 109 229 120 149 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 226 232 147
++192 207 33 199 212 45 199 212 45 198 211 44 198 211 44 197 211 44
++195 209 44 195 209 44 195 209 44 193 208 43 188 204 31 226 232 147
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 196 211 92
++175 195 20 177 196 38 176 195 35 176 195 35 175 195 37 174 194 36
++174 194 36 173 192 36 173 192 36 173 192 36 166 188 23 228 234 180
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 248 216 227 220 62 124 216 41 113
++218 48 113 218 50 114 218 50 114 218 50 114 218 50 114 218 50 114
++218 50 114 218 50 114 217 44 109 224 95 140 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 248 216 227 219 55 114 220 59 117
++220 59 117 220 61 116 220 61 116 220 61 116 220 61 116 220 61 116
++220 61 116 220 61 116 218 51 110 229 120 149 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 226 232 147
++192 207 33 201 213 45 199 212 45 199 212 45 198 211 44 197 211 44
++197 211 44 195 209 44 195 209 44 195 209 42 188 204 31 226 232 147
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 211 222 128
++175 195 20 177 196 38 176 195 35 176 195 35 175 195 37 175 194 36
++174 194 36 173 192 36 173 192 36 173 192 36 169 190 33 228 234 180
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 248 216 227 220 62 124 217 44 109
++218 50 114 218 50 114 218 50 114 219 52 114 218 50 114 219 52 114
++219 52 114 219 52 114 217 45 113 223 80 132 254 253 253 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 248 216 227 219 55 114 220 61 116
++220 61 116 220 61 116 220 61 116 220 61 116 220 61 116 220 61 116
++221 65 117 221 65 117 218 51 110 229 120 149 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 226 232 147
++192 207 33 201 213 45 201 213 45 199 212 45 198 211 44 197 211 44
++197 211 44 195 209 44 195 209 44 195 209 44 188 204 31 226 232 147
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 211 222 128
++175 195 20 177 196 38 175 195 37 176 195 35 175 195 37 175 195 37
++174 194 36 174 194 36 173 192 36 173 192 36 169 190 33 228 234 180
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 250 231 237 222 71 124 217 44 109
++219 52 114 219 52 114 219 52 114 219 52 114 219 52 114 219 52 114
++219 52 114 219 52 114 218 48 113 222 71 124 253 243 247 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 242 190 209 219 55 114 220 61 116
++220 61 116 221 65 117 221 65 117 221 65 117 221 65 117 221 65 117
++221 65 117 221 65 117 218 51 110 231 129 171 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 234 164
++192 207 33 201 213 45 199 212 45 199 212 45 199 212 45 198 211 44
++197 211 44 197 211 44 195 209 44 195 209 44 188 204 31 226 232 147
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 254 253 253 196 211 92
++175 195 20 179 197 38 177 196 38 177 196 38 176 195 35 175 195 37
++175 194 36 174 194 36 173 192 36 173 192 36 169 190 33 228 234 180
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 253 243 247 223 80 132 217 44 109
++219 52 114 219 52 114 219 52 114 219 52 114 219 52 114 219 52 114
++219 52 114 219 52 114 218 50 114 220 59 117 248 216 227 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 236 151 178 218 51 110 221 65 117
++221 65 117 221 65 117 221 65 117 221 65 117 221 65 117 221 66 117
++221 66 117 221 66 117 218 51 110 236 151 178 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 237 181
++192 207 33 201 213 45 201 213 45 199 212 45 199 212 45 198 211 44
++198 211 44 197 211 44 195 209 44 195 209 44 192 207 33 229 218 98
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 252 251 239 193 208 58
++175 195 31 177 196 38 177 196 38 177 196 38 176 195 35 175 195 37
++175 195 37 174 194 36 173 192 36 173 192 36 169 190 33 245 244 203
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 224 95 140 217 40 109
++219 52 114 219 52 114 219 52 114 219 52 114 219 55 114 219 55 114
++219 55 114 219 55 114 219 55 114 217 44 109 236 151 178 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 254 253 253 224 95 140 218 51 110 221 65 117
++221 65 117 221 66 117 221 66 117 221 66 117 221 66 117 221 66 117
++221 66 117 221 66 117 219 55 114 239 172 194 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 245 244 203
++198 211 44 201 213 45 201 213 45 201 213 45 199 212 45 199 212 45
++198 211 44 197 211 44 197 211 44 195 209 44 194 208 41 193 208 58
++250 250 231 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 245 244 203 175 195 31
++178 196 36 179 197 38 179 197 38 177 196 38 175 195 37 176 195 35
++175 195 37 175 195 37 174 194 36 173 192 36 176 196 49 250 250 231
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 231 129 171 217 44 109
++219 55 114 219 55 114 219 55 114 219 55 114 219 55 114 220 58 116
++220 58 116 220 58 116 220 58 116 217 44 109 224 95 140 254 251 247
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 248 216 227 221 66 117 220 63 115 221 66 117
++221 66 117 221 66 117 221 66 117 221 66 117 221 66 117 221 66 117
++221 66 117 221 66 117 221 66 117 242 190 209 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 250 250 231
++193 208 58 201 213 45 201 213 45 201 213 45 199 212 45 199 212 45
++198 211 44 197 211 44 197 211 44 195 209 44 195 209 44 192 207 33
++226 232 147 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 211 222 128 175 195 31
++179 197 38 179 197 38 179 197 38 177 196 38 175 195 37 176 195 35
++175 195 37 175 195 37 174 194 36 169 190 33 196 211 92 250 252 247
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 239 172 194 218 48 113
++219 55 114 220 58 116 220 58 116 220 58 116 220 58 116 220 58 116
++220 58 116 220 58 116 220 58 116 220 58 116 218 51 110 242 190 209
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 231 129 171 218 51 110 221 66 117 221 66 117
++221 66 117 221 66 117 221 66 117 221 66 117 222 73 119 222 73 119
++222 73 119 221 65 117 223 80 132 250 231 237 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 253 253
++229 218 98 192 207 33 201 213 45 201 213 45 201 213 45 199 212 45
++199 212 45 198 211 44 198 211 44 197 211 44 195 209 44 192 207 33
++193 208 58 252 251 239 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 247 246 214 184 202 41 178 196 36
++179 197 38 179 197 38 179 197 38 179 197 38 177 196 38 177 196 38
++176 195 35 175 195 37 175 194 36 166 188 23 211 222 128 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 248 216 227 220 59 117
++219 55 114 220 58 116 220 58 116 220 58 116 220 58 116 220 58 116
++220 58 116 220 59 117 220 59 117 220 59 117 219 52 114 223 80 132
++250 231 237 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 242 190 209 220 58 116 221 66 117 221 66 117 221 66 117
++221 66 117 222 73 119 222 73 119 222 73 119 222 73 119 222 73 119
++222 73 119 220 63 115 229 120 149 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++226 232 147 192 207 33 201 213 45 201 213 45 201 213 45 199 212 45
++199 212 45 198 211 44 198 211 44 197 211 44 197 211 44 195 209 42
++188 204 31 211 222 128 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 254 253 253 196 211 92 175 195 20 181 200 38
++181 200 38 179 197 38 179 197 38 179 197 38 177 196 38 177 196 38
++176 195 35 176 195 35 174 194 36 166 188 23 228 234 180 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 254 253 253 224 95 140
++218 51 110 220 58 116 220 59 117 220 59 117 220 59 117 220 59 117
++220 59 117 220 61 116 220 61 116 220 61 116 220 61 116 218 51 110
++229 120 149 254 251 247 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++248 216 227 222 82 121 220 63 115 222 73 119 222 73 119 222 73 119
++222 73 119 222 73 119 222 73 119 222 73 119 222 73 119 222 73 119
++222 73 119 220 64 111 239 172 194 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++245 244 203 201 213 45 201 213 45 201 213 45 201 213 45 201 213 45
++199 212 45 199 212 45 198 211 44 197 211 44 197 211 44 195 209 44
++194 208 41 194 208 41 228 234 180 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 226 232 147 182 200 31 181 200 38 182 200 39
++181 200 38 179 197 38 179 197 38 179 197 38 179 197 38 177 196 38
++175 195 37 176 195 35 175 195 31 176 196 49 250 247 226 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 239 172 194
++217 44 109 220 59 117 220 59 117 220 59 117 220 61 116 220 61 116
++220 61 116 220 61 116 220 61 116 220 61 116 220 61 116 220 61 116
++218 51 110 229 120 149 253 243 247 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 248 216 227
++224 95 140 220 64 111 222 73 119 222 73 119 222 73 119 222 73 119
++222 73 119 222 73 119 222 73 119 222 73 119 222 73 119 222 75 119
++221 72 115 223 85 123 250 231 237 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 229 218 98 198 211 44 201 213 45 201 213 45 201 213 45
++201 213 45 199 212 45 199 212 45 198 211 44 197 211 44 195 209 44
++195 209 44 192 207 33 195 209 44 228 234 180 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 226 232 147 182 200 31 181 200 38 182 200 39 182 200 39
++181 200 38 179 197 38 179 197 38 179 197 38 179 197 38 177 196 38
++177 196 38 175 195 37 166 188 23 196 211 92 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 250 231 237
++223 80 132 218 51 110 220 61 116 220 61 116 220 61 116 220 61 116
++220 61 116 221 65 117 221 65 117 221 65 117 221 65 117 221 65 117
++221 65 117 218 51 110 224 95 140 248 216 227 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 242 190 209 222 82 121
++220 64 111 222 73 119 222 73 119 222 73 119 222 73 119 222 73 119
++222 75 119 222 75 119 222 75 119 222 75 119 222 75 119 222 75 119
++220 64 111 236 151 178 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 242 234 164 192 207 33 201 213 45 201 213 45 201 213 45
++201 213 45 199 212 45 199 212 45 198 211 44 198 211 44 197 211 44
++197 211 44 195 209 44 192 207 33 194 208 41 226 232 147 252 251 239
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 250 247 226
++211 222 128 182 200 31 181 200 38 182 200 39 182 200 39 182 200 39
++182 200 39 181 200 38 181 200 38 179 197 38 179 197 38 179 197 38
++177 196 38 175 195 37 175 195 31 228 234 180 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++236 151 178 217 44 109 220 61 116 220 61 116 221 65 117 221 65 117
++221 65 117 221 65 117 221 65 117 221 65 117 221 65 117 221 66 117
++221 66 117 221 66 117 219 55 114 221 69 124 236 151 178 248 216 227
++254 251 247 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 253 243 247 242 190 209 229 120 149 220 63 115 221 65 117
++222 73 119 222 73 119 222 73 119 222 75 119 222 75 119 222 75 119
++222 75 119 222 75 119 222 75 119 222 75 119 222 75 119 221 72 115
++222 82 121 248 216 227 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 252 251 239 228 210 65 198 211 44 201 213 45 201 213 45
++201 213 45 201 213 45 199 212 45 199 212 45 198 211 44 197 211 44
++197 211 44 195 209 44 195 209 44 194 208 41 188 204 31 196 211 92
++228 234 180 250 250 231 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 250 247 226 226 232 147 193 208 58
++182 200 31 182 200 39 184 202 41 182 200 39 182 200 39 182 200 39
++182 200 39 181 200 38 181 200 38 179 197 38 179 197 38 179 197 38
++177 196 38 175 195 31 196 211 92 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++253 243 247 223 80 132 219 55 114 221 65 117 221 65 117 221 65 117
++221 66 117 221 66 117 221 66 117 221 66 117 221 66 117 221 66 117
++221 66 117 221 66 117 221 66 117 221 65 117 219 55 114 221 66 117
++229 120 149 236 151 178 239 172 194 242 190 209 242 190 209 239 172 194
++231 129 171 224 95 140 221 65 117 220 63 115 222 73 119 222 75 119
++222 75 119 222 75 119 222 75 119 222 75 119 222 75 119 222 75 119
++222 75 119 222 75 119 222 75 119 222 78 120 222 78 120 220 64 111
++236 151 178 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 228 234 180 192 207 33 201 213 45 201 213 45
++201 213 45 201 213 45 201 213 45 199 212 45 199 212 45 198 211 44
++197 211 44 197 211 44 195 209 44 195 209 44 195 209 42 192 207 33
++188 204 31 193 208 58 211 222 128 226 232 147 228 234 180 228 234 180
++228 234 180 226 232 147 196 211 92 189 205 44 182 200 31 182 200 31
++186 202 40 186 202 40 186 202 40 184 202 41 182 200 39 182 200 39
++182 200 39 182 200 39 181 200 38 179 197 38 179 197 38 179 197 38
++176 195 35 175 195 31 245 244 203 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 239 172 194 218 51 110 221 65 117 221 66 117 221 66 117
++221 66 117 221 66 117 221 66 117 221 66 117 221 66 117 221 66 117
++221 66 117 222 73 119 222 73 119 222 73 119 222 73 119 221 66 117
++220 64 111 219 55 114 220 64 111 221 66 117 221 65 117 220 64 111
++220 64 111 220 63 115 222 73 119 222 75 119 222 75 119 222 75 119
++222 75 119 222 75 119 222 75 119 222 78 120 222 78 120 222 78 120
++222 78 120 222 78 120 222 79 120 222 79 120 221 72 115 224 95 140
++250 231 237 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 254 253 253 229 218 98 192 207 33 201 213 45
++201 213 45 201 213 45 201 213 45 199 212 45 199 212 45 198 211 44
++197 211 44 197 211 44 195 209 44 195 209 44 195 209 44 195 209 44
++193 208 43 189 205 40 188 204 31 188 204 31 188 204 31 187 203 38
++188 204 31 182 200 31 182 200 31 187 203 38 187 203 40 186 203 40
++186 202 40 186 202 40 186 202 40 184 202 41 184 202 41 182 200 39
++182 200 39 182 200 39 181 200 38 181 200 38 179 197 38 179 197 38
++175 195 20 211 222 128 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 254 253 253 229 120 149 218 51 110 221 66 117 221 66 117
++221 66 117 221 66 117 221 66 117 222 73 119 222 73 119 222 73 119
++222 73 119 222 73 119 222 73 119 222 73 119 222 73 119 222 73 119
++222 73 119 222 73 119 222 73 119 222 73 119 222 73 119 222 73 119
++222 75 119 222 75 119 222 75 119 222 75 119 222 75 119 222 75 119
++222 75 119 222 78 120 222 78 120 222 78 120 222 78 120 222 79 120
++222 79 120 222 79 120 222 79 120 222 75 119 221 72 115 242 190 209
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 247 246 214 201 213 45 201 213 45
++201 213 45 201 213 45 201 213 45 199 212 45 199 212 45 198 211 44
++198 211 44 197 211 44 195 209 44 195 209 44 195 209 44 195 209 44
++193 208 43 193 208 43 193 208 43 192 206 41 189 205 40 189 205 40
++189 205 40 189 205 40 189 205 40 189 204 42 187 203 42 187 203 40
++186 202 40 186 202 40 186 202 40 184 202 41 184 202 41 182 200 39
++182 200 39 182 200 39 182 200 39 181 200 38 181 200 38 175 195 31
++193 208 58 250 250 231 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 250 231 237 224 95 140 219 55 114 222 73 119
++222 73 119 222 73 119 222 73 119 222 73 119 222 73 119 222 73 119
++222 73 119 222 73 119 222 73 119 222 73 119 222 73 119 222 73 119
++222 75 119 222 75 119 222 75 119 222 75 119 222 75 119 222 75 119
++222 75 119 222 75 119 222 78 120 222 78 120 222 78 120 222 78 120
++222 78 120 222 79 120 222 79 120 222 79 120 222 79 120 222 79 120
++222 79 120 222 79 120 222 79 120 220 64 111 236 151 178 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 242 237 181 198 211 44
++201 213 45 201 213 45 201 213 45 201 213 45 199 212 45 199 212 45
++198 211 44 198 211 44 197 211 44 195 209 44 195 209 44 195 209 44
++193 208 43 193 208 43 193 208 43 193 208 43 190 206 42 190 206 42
++190 206 42 189 205 40 189 204 42 189 204 42 189 204 42 187 203 40
++187 203 40 186 202 40 186 202 40 186 202 40 184 202 41 184 202 41
++182 200 39 182 200 39 182 200 39 181 200 38 175 195 31 179 197 38
++245 244 203 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 248 216 227 222 78 120 220 64 111
++222 73 119 222 73 119 222 73 119 222 73 119 222 73 119 222 73 119
++222 73 119 222 73 119 222 73 119 222 75 119 222 75 119 222 75 119
++222 75 119 222 75 119 222 75 119 222 75 119 222 75 119 222 78 120
++222 78 120 222 78 120 222 78 120 222 79 120 222 79 120 222 79 120
++222 79 120 222 79 120 222 79 120 222 79 120 222 79 120 222 82 121
++222 82 121 222 82 121 221 72 115 231 129 171 254 253 253 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 226 232 147
++192 207 33 201 213 45 201 213 45 201 213 45 199 212 45 199 212 45
++199 212 45 197 211 44 197 211 44 197 211 44 195 209 44 195 209 44
++195 209 44 193 208 43 193 208 43 193 208 43 192 206 41 190 206 42
++190 206 42 190 206 42 189 204 42 189 204 42 189 204 42 187 203 42
++187 203 40 186 202 40 186 202 40 186 202 40 186 202 40 184 202 41
++182 200 39 182 200 39 182 200 39 178 196 36 175 195 31 228 234 180
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 242 190 209 222 78 120
++220 64 111 222 73 119 222 73 119 222 73 119 222 75 119 222 75 119
++222 75 119 222 75 119 222 75 119 222 75 119 222 75 119 222 75 119
++222 78 120 222 78 120 222 78 120 222 78 120 222 78 120 222 79 120
++222 79 120 222 79 120 222 79 120 222 79 120 222 79 120 222 79 120
++222 79 120 222 82 121 222 82 121 222 82 121 223 84 121 223 84 121
++222 82 121 221 72 115 229 120 149 253 243 247 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 253 253
++211 222 128 192 207 33 201 213 45 201 213 45 201 213 45 201 213 45
++199 212 45 199 212 45 198 211 44 197 211 44 195 209 44 195 209 44
++195 209 44 195 209 44 193 208 43 193 208 43 193 208 43 192 206 41
++190 206 42 190 206 42 190 206 42 189 205 40 189 205 40 189 204 42
++187 203 42 187 203 40 186 202 40 186 202 40 186 202 40 184 202 41
++184 202 41 184 202 41 182 200 31 175 195 31 226 232 147 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 248 216 227
++223 85 123 220 64 111 222 75 119 222 75 119 222 75 119 222 75 119
++222 75 119 222 75 119 222 75 119 222 78 120 222 78 120 222 78 120
++222 78 120 222 79 120 222 79 120 222 79 120 222 79 120 222 79 120
++222 79 120 222 79 120 222 79 120 222 82 121 222 82 121 222 82 121
++222 82 121 222 82 121 223 84 121 223 84 121 223 85 123 222 82 120
++221 72 115 231 129 171 253 243 247 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 226 232 147 195 209 42 198 211 44 201 213 45 199 212 45
++199 212 45 199 212 45 198 211 44 197 211 44 197 211 44 195 209 44
++195 209 44 195 209 44 193 208 43 193 208 43 193 208 43 192 206 41
++190 206 42 190 206 42 190 206 42 189 204 42 189 205 40 189 204 42
++189 204 42 187 203 40 186 203 40 186 202 40 186 202 40 184 202 41
++184 202 41 182 200 31 182 200 39 228 234 180 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++250 231 237 229 120 149 220 64 111 221 72 115 222 75 119 222 78 120
++222 78 120 222 78 120 222 78 120 222 79 120 222 79 120 222 79 120
++222 79 120 222 79 120 222 79 120 222 79 120 222 79 120 222 82 121
++222 82 121 222 82 121 222 82 121 223 84 121 223 84 121 223 84 121
++223 84 121 223 84 121 223 85 123 223 85 123 222 79 117 222 79 117
++236 151 178 254 251 247 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 242 234 164 201 213 45 192 207 33 201 213 45
++199 212 45 199 212 45 198 211 44 197 211 44 197 211 44 197 211 44
++195 209 44 195 209 44 195 209 44 193 208 43 193 208 43 193 208 43
++192 206 41 190 206 42 190 206 42 190 206 42 189 204 42 187 203 40
++189 204 42 187 203 42 187 203 40 186 202 40 186 202 40 181 200 38
++175 195 20 193 208 58 242 237 181 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 254 253 253 236 151 178 223 85 123 222 75 119 222 78 120
++222 79 120 222 79 120 222 79 120 222 79 120 222 79 120 222 79 120
++222 79 120 222 79 120 222 79 120 222 82 121 222 82 121 222 82 121
++223 84 121 223 84 121 223 84 121 223 84 121 223 85 123 223 85 123
++223 85 123 223 85 123 223 84 121 221 72 115 224 95 140 242 190 209
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 245 244 203 196 211 92 192 207 33
++198 211 44 199 212 45 199 212 45 198 211 44 197 211 44 197 211 44
++195 209 44 195 209 44 195 209 44 193 208 43 193 208 43 193 208 43
++192 206 41 190 206 42 190 206 42 190 206 42 189 204 42 189 205 40
++189 204 42 187 203 42 187 203 40 186 203 40 186 202 40 186 202 40
++196 211 92 250 247 226 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 242 190 209 221 72 115 222 79 120
++222 79 120 222 79 120 222 79 120 222 82 121 222 82 121 222 82 121
++222 82 121 223 84 121 223 84 121 223 84 121 223 84 121 223 84 121
++223 85 123 223 85 123 223 85 123 223 85 123 223 85 123 223 84 121
++222 79 117 221 72 115 223 85 123 236 151 178 250 231 237 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 254 251 247 242 234 164
++193 208 58 192 207 33 192 207 33 198 211 44 198 211 44 197 211 44
++195 209 44 195 209 44 195 209 44 195 209 44 193 208 43 193 208 43
++193 208 43 192 206 41 190 206 42 190 206 42 190 206 42 189 204 42
++189 205 40 189 204 42 187 203 42 187 203 40 182 200 31 211 222 128
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 231 129 171 221 72 115 222 79 120
++222 79 120 222 82 121 222 82 121 222 82 121 222 82 121 223 84 121
++223 84 121 223 84 121 223 84 121 223 85 123 223 85 123 223 85 123
++223 85 123 223 85 123 223 85 123 222 82 120 221 72 115 222 79 117
++224 95 140 236 151 178 250 231 237 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++252 251 239 226 232 147 196 211 92 195 209 42 192 207 33 192 207 33
++197 211 44 195 209 44 195 209 44 195 209 44 193 208 43 193 208 43
++193 208 43 193 208 43 190 206 42 190 206 42 190 206 42 189 204 42
++189 205 40 187 203 40 189 204 42 187 203 40 182 200 31 193 208 58
++252 251 239 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 242 190 209 221 72 115 222 79 120 222 82 121
++223 84 121 223 84 121 223 84 121 223 84 121 223 84 121 223 85 123
++223 85 123 223 85 123 223 85 123 223 85 123 223 84 121 222 82 120
++222 79 117 222 79 117 222 82 120 224 95 140 236 151 178 242 190 209
++250 231 237 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 254 251 247 242 237 181 211 222 128 196 211 92
++195 209 42 192 207 33 192 207 33 192 207 33 194 208 41 195 209 42
++193 208 43 193 208 43 192 206 41 190 206 42 190 206 42 190 206 42
++189 204 42 187 203 40 189 204 42 187 203 42 187 203 40 182 200 31
++211 222 128 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 253 243 247 224 95 140 222 75 119 223 84 121 223 84 121
++223 84 121 223 85 123 223 85 123 223 85 123 223 85 123 223 85 123
++223 85 123 223 84 121 222 79 117 221 72 115 223 84 121 224 95 140
++229 120 149 239 172 194 248 216 227 253 243 247 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 252 251 239
++247 246 214 226 232 147 229 218 98 193 208 58 195 209 44 188 204 31
++188 204 31 192 206 41 193 208 43 192 206 41 190 206 42 190 206 42
++190 206 42 189 204 42 187 203 40 189 204 42 187 203 40 187 203 38
++187 203 42 247 246 214 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 239 172 194 221 72 115 223 85 123 223 85 123 223 85 123
++223 85 123 223 85 123 223 85 123 222 82 120 222 82 120 222 79 117
++222 79 117 223 85 123 229 120 149 236 151 178 242 190 209 250 231 237
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 252 251 239 242 237 181 226 232 147
++196 211 92 193 208 58 188 204 31 188 204 31 192 207 33 189 205 40
++189 205 40 189 204 42 189 204 42 189 204 42 187 203 42 187 203 40
++175 195 20 196 211 92 254 253 253 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++250 231 237 224 95 140 222 79 117 223 85 123 223 85 123 223 85 123
++222 79 117 221 72 115 222 79 117 223 85 123 229 120 149 236 151 178
++242 190 209 250 231 237 253 243 247 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++254 253 253 250 247 226 242 237 181 211 222 128 196 211 92 193 208 58
++188 204 31 182 200 31 188 204 31 187 203 38 189 204 42 187 203 40
++187 203 38 182 200 31 228 234 180 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++236 151 178 221 72 115 222 82 120 222 79 117 222 79 117 222 79 117
++224 95 140 231 129 171 239 172 194 248 216 227 254 251 247 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 247 246 214
++228 234 180 211 222 128 193 208 58 187 203 40 182 200 31 188 204 31
++187 203 38 182 200 31 196 211 92 250 252 247 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 190 209
++221 72 115 222 82 120 224 95 140 229 120 149 239 172 194 248 216 227
++250 231 237 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 252 251 239 245 244 203 226 232 147 196 211 92
++193 208 58 187 203 38 175 195 20 226 232 147 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 254 253 253 236 151 178
++236 151 178 242 190 209 250 231 237 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++252 251 239 242 237 181 211 222 128 196 211 92 250 247 226 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 254 253 253 253 243 247
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 250 252 247 250 252 247 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++239 248 249 201 231 236 221 240 243 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++247 246 214 242 234 164 250 247 226 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 254 253 253 221 240 243 187 224 231 151 211 222
++128 197 208 109 190 204 221 240 243 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++250 250 231 244 209 33 244 209 33 229 218 98 248 229 146 245 244 203
++252 251 239 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 248 252 253 221 240 243
++201 231 236 151 211 222 128 197 208 109 190 204 102 188 202 99 187 201
++96 185 201 171 218 226 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 242 237 181 242 206 16 242 206 16 243 207 19 244 209 33
++244 209 33 229 218 98 242 234 164 247 246 214 252 251 239 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 239 248 249 201 231 236 171 218 226 134 201 213 107 189 203
++92 185 200 96 185 201 102 188 202 105 189 203 109 190 204 102 188 202
++128 197 208 248 252 253 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 229 218 98 243 207 19 244 209 33 243 207 28
++243 207 26 243 205 21 242 205 14 243 207 28 228 210 65 247 227 124
++242 234 164 247 246 214 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 239 248 249 221 240 243 171 218 226
++134 201 213 105 189 203 96 185 201 83 182 199 89 184 201 97 187 203
++105 189 203 105 189 203 105 189 203 109 190 204 109 190 204 105 188 202
++201 231 236 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 247 246 214 244 209 33 243 207 26 243 207 28
++244 209 33 244 209 33 243 207 28 243 206 25 242 206 16 241 201 6
++243 204 20 244 209 33 228 210 65 247 227 124 242 237 181 250 247 226
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 253 253
++221 240 243 187 224 231 149 206 215 109 192 207 83 182 199 81 181 199
++83 182 199 92 185 200 96 185 201 97 187 203 102 188 202 102 188 202
++105 189 203 105 189 203 107 189 203 109 190 204 105 188 202 137 202 213
++254 253 253 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 247 227 124 242 205 14 243 207 28
++244 209 33 244 209 33 243 207 28 243 207 28 243 207 28 243 207 26
++243 206 23 243 204 20 242 202 16 241 201 6 242 202 13 244 209 33
++229 218 98 248 229 146 245 244 203 252 251 239 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 239 248 249 187 224 231 151 211 222 109 192 207
++89 184 201 72 178 197 72 178 197 81 181 199 89 184 201 92 185 200
++92 185 200 96 185 201 97 187 203 99 187 201 102 188 202 102 188 202
++105 189 203 105 189 203 107 189 203 105 189 203 105 189 203 221 240 243
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 250 250 231 244 209 33 243 206 25
++244 209 33 243 207 28 243 207 28 243 207 28 243 207 26 243 206 25
++243 206 25 243 206 25 243 204 22 243 205 21 243 205 21 242 202 13
++241 197 1 241 197 1 243 204 22 244 209 33 229 218 98 248 229 146
++247 246 214 254 253 253 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 253 253
++201 231 236 134 201 213 84 184 202 66 177 197 70 178 196 72 178 197
++77 180 198 83 182 199 84 184 202 89 184 201 89 184 201 92 185 200
++96 185 201 96 185 201 97 187 203 99 187 201 102 188 202 102 188 202
++105 189 203 105 189 203 107 189 203 99 187 201 151 211 222 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 242 234 164 243 207 19
++243 207 28 243 207 28 243 207 28 243 207 28 243 206 25 243 206 25
++243 206 25 243 206 23 243 205 21 243 205 21 243 204 22 243 203 18
++243 203 18 243 203 18 242 202 13 241 201 6 240 197 5 240 197 5
++243 203 18 228 210 65 242 234 164 252 251 239 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 187 224 231 109 192 207
++65 176 196 63 175 195 72 178 197 79 181 198 79 181 198 81 181 199
++83 182 199 83 182 199 89 184 201 89 184 201 92 185 200 92 185 200
++96 185 201 96 185 201 97 187 203 100 188 204 102 188 202 105 189 203
++105 189 203 107 189 203 105 189 203 119 193 206 239 248 249 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 228 210 65
++242 206 16 243 207 28 243 207 28 243 207 26 243 206 25 243 206 25
++243 206 25 243 205 21 243 205 21 243 204 22 243 204 20 243 203 18
++243 203 18 243 204 20 242 202 16 242 202 16 242 202 16 242 202 16
++241 198 11 241 197 1 241 197 1 244 209 33 248 229 146 252 251 239
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 221 240 243 121 197 211 58 174 194 63 175 195
++69 178 196 73 180 199 75 181 199 79 181 198 79 181 198 81 181 199
++83 182 199 83 182 199 89 184 201 89 184 201 92 185 200 92 185 200
++96 185 201 96 185 201 97 187 203 102 188 202 102 188 202 105 189 203
++105 189 203 107 189 203 107 189 203 116 192 205 187 224 231 248 252 253
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 242 234 164 228 210 65
++243 205 21 243 207 28 243 207 28 243 206 25 243 206 25 243 206 25
++243 206 23 243 205 21 243 205 21 243 204 22 243 203 18 243 203 18
++243 203 18 243 203 18 242 202 16 242 202 16 242 202 16 242 202 13
++242 202 13 241 201 15 241 198 11 241 197 1 240 194 0 244 209 33
++242 237 181 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 171 218 226 71 179 199 58 174 194 68 178 198 71 179 199
++73 180 199 75 181 199 75 181 199 79 181 198 81 181 199 83 182 199
++83 182 199 84 184 202 89 184 201 89 184 201 92 185 200 92 185 200
++96 185 201 97 187 203 100 188 204 102 188 202 102 188 202 105 189 203
++105 189 203 109 190 204 109 190 204 109 190 204 102 188 202 137 202 213
++221 240 243 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 250 250 231 229 218 98 242 206 16 243 206 23
++243 207 28 243 207 28 243 207 26 243 206 25 243 206 25 243 206 25
++243 205 21 243 205 21 243 204 22 243 204 20 243 203 18 243 203 18
++243 203 18 242 202 16 242 202 16 242 202 16 241 201 15 241 198 11
++241 201 15 241 201 15 241 198 9 241 198 9 241 198 11 240 194 0
++239 195 1 247 227 124 254 251 247 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 248 252 253
++149 206 215 58 174 194 58 174 194 68 178 198 68 178 198 71 179 199
++73 180 199 75 181 199 77 180 198 79 181 198 81 181 199 83 182 199
++83 182 199 89 184 201 89 184 201 89 184 201 92 185 200 92 185 200
++96 185 201 97 187 203 100 188 204 102 188 202 102 188 202 105 189 203
++105 189 203 109 190 204 109 190 204 113 192 205 113 192 205 105 189 203
++122 194 206 201 231 236 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 247 246 214 228 210 65 242 205 14 243 207 26 243 207 28
++243 207 28 243 205 27 243 206 25 243 206 25 243 206 25 243 204 22
++243 205 21 243 205 21 243 204 22 243 203 18 243 203 18 243 203 18
++243 203 18 242 202 16 242 202 16 242 202 16 242 202 13 241 201 15
++241 201 15 241 198 11 241 198 9 241 198 11 241 198 11 240 197 6
++241 197 1 239 192 0 228 210 65 250 250 231 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 248 252 253 128 201 213
++49 171 193 64 176 196 68 178 198 68 178 198 70 178 196 72 178 197
++73 180 199 75 181 199 79 181 198 79 181 198 83 182 199 83 182 199
++83 182 199 89 184 201 89 184 201 89 184 201 92 185 200 96 185 201
++96 185 201 97 187 203 100 188 204 102 188 202 105 189 203 105 189 203
++105 189 203 109 190 204 109 190 204 113 192 205 113 192 205 116 192 205
++113 192 205 116 192 205 201 231 236 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++245 244 203 244 209 33 243 204 20 243 207 28 243 207 28 243 207 28
++243 207 28 243 207 26 243 206 25 243 206 25 243 206 25 243 205 21
++243 205 21 243 205 21 243 203 18 243 203 18 243 203 18 243 203 18
++242 202 16 242 202 16 242 202 16 241 201 15 242 202 13 241 201 15
++241 201 15 241 198 9 241 198 9 241 198 11 240 197 6 240 197 5
++240 197 6 240 197 5 239 192 0 244 209 33 247 246 214 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 248 252 253 128 201 213 49 171 193
++63 175 195 66 177 197 66 177 197 68 178 198 70 178 196 72 178 197
++73 180 199 75 181 199 79 181 198 81 181 199 81 181 199 83 182 199
++83 182 199 89 184 201 89 184 201 92 185 200 92 185 200 96 185 201
++97 187 203 99 187 201 102 188 202 102 188 202 105 189 203 105 189 203
++107 189 203 109 190 204 109 190 204 113 192 205 113 192 205 116 192 205
++116 192 205 113 192 205 116 192 205 201 231 236 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 245 244 203
++244 209 33 243 205 21 244 209 33 243 207 28 243 207 28 243 207 28
++243 207 26 243 206 25 243 206 25 243 206 25 243 204 22 243 205 21
++243 205 21 243 204 20 243 203 18 243 203 18 243 203 18 242 202 16
++242 202 16 242 202 16 242 202 16 242 202 13 241 201 15 241 201 15
++241 198 11 241 198 9 241 198 11 241 198 11 240 197 5 240 197 5
++240 197 6 240 197 4 240 194 0 238 191 0 244 209 33 250 247 226
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 151 211 222 49 171 193 63 175 195
++65 176 196 66 177 197 68 178 198 70 178 196 72 178 197 73 180 199
++75 181 199 77 180 198 79 181 198 81 181 199 83 182 199 83 182 199
++84 184 202 89 184 201 89 184 201 92 185 200 96 185 201 96 185 201
++97 187 203 99 187 201 102 188 202 102 188 202 105 189 203 105 189 203
++109 190 204 109 190 204 113 192 205 113 192 205 116 192 205 116 192 205
++119 193 206 119 193 206 119 193 206 122 194 206 221 240 243 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 250 247 226 244 209 33
++243 207 19 244 209 33 243 207 28 243 207 28 243 207 28 243 207 28
++243 206 25 243 206 25 243 206 25 243 206 23 243 205 21 243 205 21
++243 204 22 243 203 18 243 203 18 243 203 18 243 203 18 242 202 16
++242 202 16 242 202 16 241 201 15 241 198 11 241 201 15 241 198 11
++241 198 9 241 198 11 241 198 11 240 197 6 240 197 4 240 197 6
++240 197 5 241 197 1 239 195 1 239 195 1 238 190 0 228 210 65
++252 251 239 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 187 224 231 49 171 193 58 174 194 64 176 196
++66 177 197 66 177 197 68 178 198 70 178 196 72 178 197 73 180 199
++75 181 199 77 180 198 79 181 198 81 181 199 83 182 199 83 182 199
++89 184 201 89 184 201 92 185 200 92 185 200 96 185 201 96 185 201
++97 187 203 99 187 201 102 188 202 102 188 202 105 189 203 105 189 203
++109 190 204 109 190 204 113 192 205 113 192 205 116 192 205 116 192 205
++119 193 206 119 193 206 122 194 206 119 193 206 134 199 210 239 248 249
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 254 251 247 229 218 98 242 206 16
++244 209 33 244 209 33 243 207 28 243 207 28 243 207 28 243 207 26
++243 206 25 243 206 25 243 206 25 243 205 21 243 205 21 243 204 22
++243 204 20 243 203 18 243 203 18 243 203 18 242 202 16 242 202 16
++242 202 16 241 201 15 242 202 13 241 201 15 241 201 15 241 198 9
++241 198 9 241 198 11 241 198 11 240 197 5 240 197 5 240 197 6
++241 197 1 240 194 0 239 195 1 239 195 1 240 194 0 238 188 0
++229 218 98 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 221 240 243 68 178 198 49 171 193 64 176 196 64 176 196
++66 177 197 68 178 198 68 178 198 70 178 196 72 178 197 73 180 199
++75 181 199 79 181 198 79 181 198 81 181 199 83 182 199 83 182 199
++83 182 199 83 182 199 83 182 199 83 182 199 89 184 201 89 184 201
++92 185 200 97 187 203 102 188 202 105 189 203 105 189 203 107 189 203
++109 190 204 109 190 204 113 192 205 113 192 205 116 192 205 116 192 205
++119 193 206 122 194 206 122 194 206 124 196 207 116 192 205 151 211 222
++254 253 253 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 248 229 146 242 205 14 244 209 33
++244 209 33 243 207 28 243 207 28 243 207 28 243 207 28 243 206 25
++243 206 25 243 206 25 243 204 22 243 205 21 243 205 21 243 204 22
++243 203 18 242 202 16 242 202 13 241 198 9 241 201 6 240 197 5
++240 197 6 240 197 4 241 198 9 241 201 15 241 198 11 241 198 9
++241 198 11 241 198 11 240 197 6 240 197 5 240 197 6 240 197 4
++240 194 0 239 195 1 240 194 1 240 194 0 240 194 0 240 192 0
++238 191 0 242 234 164 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 121 197 211 49 171 193 63 175 195 64 176 196 65 176 196
++66 177 197 68 178 198 68 178 198 72 178 197 72 178 197 73 180 199
++75 181 199 79 181 198 81 181 199 83 182 199 79 181 198 72 178 197
++89 184 201 103 191 206 121 197 211 134 201 213 134 201 213 121 197 211
++109 192 207 96 185 201 92 185 200 102 188 202 105 189 203 107 189 203
++109 190 204 109 190 204 113 192 205 116 192 205 116 192 205 116 192 205
++119 193 206 122 194 206 124 196 207 124 196 207 128 197 208 119 193 206
++201 231 236 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 245 244 203 244 209 33 243 207 26 244 209 33
++243 207 28 243 207 28 243 207 28 243 207 28 243 206 25 243 206 25
++243 206 25 243 206 25 243 205 21 243 205 21 243 204 22 243 203 18
++241 201 6 241 201 6 243 205 27 244 209 33 228 210 65 228 210 65
++228 210 65 244 209 33 243 204 22 240 194 0 241 197 1 241 198 9
++241 198 11 241 198 9 240 197 4 240 197 6 240 197 6 240 194 0
++239 195 1 239 195 1 240 194 1 240 194 0 240 194 0 240 194 0
++238 189 0 241 203 27 252 251 239 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++201 231 236 49 171 193 58 174 194 63 175 195 64 176 196 65 176 196
++66 177 197 68 178 198 68 178 198 72 178 197 73 180 199 75 181 199
++77 180 198 79 181 198 77 180 198 70 178 196 97 187 203 151 211 222
++201 231 236 239 248 249 255 255 255 255 255 255 255 255 255 254 253 253
++239 248 249 201 231 236 149 206 215 102 188 202 99 187 201 107 189 203
++109 190 204 113 192 205 113 192 205 116 192 205 116 192 205 119 193 206
++119 193 206 122 194 206 124 196 207 126 196 207 128 197 208 122 194 206
++149 206 215 248 252 253 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 229 218 98 242 205 14 244 209 33 244 209 33
++243 207 28 243 207 28 243 207 28 243 205 27 243 206 25 243 206 25
++243 206 25 243 205 21 243 205 21 243 205 21 242 202 13 241 201 6
++228 210 65 248 229 146 245 244 203 254 251 247 255 255 255 255 255 255
++255 255 255 252 251 239 245 244 203 247 227 124 244 209 33 240 194 0
++240 197 4 240 197 5 240 197 5 240 197 6 241 197 1 240 194 0
++239 195 1 239 195 1 240 194 0 240 194 0 240 194 0 240 194 0
++238 192 0 237 187 0 247 227 124 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++109 192 207 49 171 193 58 174 194 64 176 196 64 176 196 66 177 197
++66 177 197 68 178 198 70 178 196 72 178 197 73 180 199 75 181 199
++79 181 198 72 178 197 79 181 198 151 211 222 239 248 249 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 221 240 243 137 202 213 99 187 201
++107 189 203 113 192 205 113 192 205 116 192 205 116 192 205 119 193 206
++119 193 206 122 194 206 124 196 207 126 196 207 128 197 208 128 197 208
++122 194 206 201 231 236 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 245 244 203 243 206 25 243 207 28 244 209 33 243 207 28
++243 207 28 243 207 28 243 207 28 243 206 25 243 206 25 243 206 25
++243 206 23 243 205 21 243 205 21 241 201 6 244 209 33 242 234 164
++254 251 247 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 252 251 239 248 229 146
++242 202 16 239 194 0 240 197 6 240 197 5 241 197 1 239 195 1
++239 195 1 240 194 1 240 194 0 240 194 0 240 194 0 238 192 0
++238 192 0 238 190 0 240 197 25 250 250 231 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 201 231 236
++58 174 194 58 174 194 63 175 195 64 176 196 65 176 196 66 177 197
++68 178 198 68 178 198 70 178 196 72 178 197 73 180 199 75 181 199
++72 178 197 89 184 201 201 231 236 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 248 252 253 171 218 226
++105 188 202 109 190 204 113 192 205 116 192 205 116 192 205 119 193 206
++122 194 206 124 196 207 124 196 207 126 196 207 128 197 208 131 197 208
++124 196 207 149 206 215 248 252 253 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 229 218 98 243 203 18 244 209 33 244 209 33 243 207 28
++243 207 28 243 207 28 243 207 26 243 206 25 243 206 25 243 206 25
++243 205 21 243 205 21 241 201 6 229 218 98 250 247 226 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++245 244 203 244 209 33 239 194 0 241 197 1 240 194 0 239 195 1
++240 194 1 240 194 0 240 194 0 240 194 0 239 192 0 238 192 0
++238 191 0 238 191 0 237 187 0 247 227 124 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 137 202 213
++49 171 193 58 174 194 63 175 195 64 176 196 66 177 197 66 177 197
++68 178 198 69 178 196 70 178 196 73 180 199 73 180 199 70 178 196
++84 184 202 201 231 236 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++187 224 231 105 189 203 113 192 205 116 192 205 116 192 205 119 193 206
++122 194 206 124 196 207 124 196 207 128 197 208 128 197 208 131 197 208
++134 199 210 126 196 207 221 240 243 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++250 247 226 244 209 33 243 206 25 244 209 33 243 207 28 243 207 28
++243 207 28 243 205 27 243 206 25 243 206 25 243 206 25 243 204 22
++243 205 21 241 201 6 229 218 98 254 251 247 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 250 250 231 244 209 33 239 192 0 239 195 1 240 194 1
++240 194 0 240 194 0 240 194 0 240 194 0 238 192 0 238 192 0
++238 191 0 238 191 0 237 187 0 244 209 33 254 251 247 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 239 248 249 75 181 199
++58 174 194 58 174 194 63 175 195 64 176 196 66 177 197 66 177 197
++68 178 198 70 178 196 72 178 197 73 180 199 73 180 199 72 178 197
++201 231 236 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 171 218 226 105 188 202 116 192 205 119 193 206 119 193 206
++122 194 206 124 196 207 126 196 207 128 197 208 128 197 208 131 197 208
++134 199 210 128 197 208 171 218 226 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++242 234 164 243 203 18 243 207 28 243 207 28 243 207 28 243 207 28
++243 207 28 243 207 26 243 206 25 243 206 25 243 206 25 243 205 21
++241 201 6 228 210 65 252 251 239 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 247 246 214 241 201 15 240 194 0 240 194 1
++240 194 0 240 194 0 240 194 0 239 194 0 238 192 0 238 192 0
++238 191 0 238 191 0 238 189 0 238 191 0 245 244 203 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 201 231 236 49 171 193
++58 174 194 63 175 195 64 176 196 64 176 196 66 177 197 66 177 197
++68 178 198 70 178 196 72 178 197 73 180 199 63 175 195 149 206 215
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 239 248 249 134 201 213 109 190 204 119 193 206 119 193 206
++122 194 206 124 196 207 126 196 207 128 197 208 128 197 208 131 197 208
++134 199 210 131 197 208 149 206 215 248 252 253 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++229 218 98 242 205 14 244 209 33 243 207 28 243 207 28 243 207 28
++243 207 26 243 206 25 243 206 25 243 206 25 243 205 21 242 205 14
++243 204 22 245 244 203 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 248 229 146 238 191 0 240 194 0
++240 194 0 240 194 0 239 194 0 238 192 0 238 191 0 238 191 0
++238 191 0 238 191 0 238 191 0 237 187 0 247 227 124 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 151 211 222 49 171 193
++58 174 194 63 175 195 64 176 196 64 176 196 66 177 197 68 178 198
++68 178 198 72 178 197 72 178 197 69 178 196 84 184 202 221 240 243
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 201 231 236 109 190 204 119 193 206 122 194 206
++124 196 207 124 196 207 126 196 207 128 197 208 128 197 208 134 199 210
++134 199 210 134 199 210 137 202 213 221 240 243 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 252 251 239
++228 210 65 243 206 23 243 207 28 243 207 28 243 207 28 243 207 26
++243 206 25 243 206 25 243 206 25 243 206 23 243 205 21 241 201 6
++229 218 98 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 254 253 253 244 209 33 240 192 0
++240 194 0 240 194 0 238 192 0 238 192 0 238 191 0 238 191 0
++238 191 0 238 191 0 238 190 0 237 187 0 228 210 65 254 253 253
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 116 195 209 49 171 193
++58 174 194 63 175 195 64 176 196 65 176 196 66 177 197 68 178 198
++70 178 196 72 178 197 72 178 197 63 175 195 137 202 213 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 248 252 253 134 201 213 113 192 205 122 194 206
++124 196 207 124 196 207 128 197 208 128 197 208 131 197 208 134 199 210
++134 199 210 134 199 210 134 199 210 201 231 236 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 247 246 214
++243 207 28 243 207 28 243 207 28 243 207 28 243 207 28 243 207 26
++243 206 25 243 206 25 243 206 25 243 205 21 243 205 21 243 203 18
++245 244 203 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 248 229 146 238 189 0
++240 194 0 239 194 0 238 192 0 238 192 0 238 191 0 238 191 0
++238 191 0 238 191 0 238 190 0 238 188 0 240 197 25 252 251 239
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 248 252 253 92 186 203 49 171 193
++58 174 194 63 175 195 64 176 196 66 177 197 66 177 197 68 178 198
++69 178 196 71 179 199 72 178 197 72 178 197 201 231 236 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 171 218 226 113 192 205 122 194 206
++124 196 207 126 196 207 128 197 208 128 197 208 131 197 208 134 199 210
++134 199 210 134 199 210 128 197 208 187 224 231 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 237 181
++243 207 19 243 207 28 243 207 28 243 207 28 243 207 26 243 206 25
++243 206 25 243 206 25 243 204 22 243 205 21 242 202 13 228 210 65
++254 251 247 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 250 247 226 241 198 11
++238 191 0 238 192 0 238 192 0 238 191 0 238 191 0 238 191 0
++238 191 0 238 190 0 238 190 0 238 188 0 238 190 0 247 246 214
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 239 248 249 84 184 202 49 171 193
++63 175 195 64 176 196 65 176 196 66 177 197 68 178 198 68 178 198
++70 178 196 72 178 197 70 178 196 84 184 202 239 248 249 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 201 231 236 116 192 205 122 194 206
++124 196 207 126 196 207 128 197 208 128 197 208 131 197 208 134 199 210
++134 199 210 134 199 210 128 196 207 171 218 226 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 234 164
++243 203 18 243 207 28 243 207 28 243 207 28 243 207 26 243 206 25
++243 206 25 243 206 23 243 205 21 243 205 21 241 201 6 247 227 124
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 254 251 247 228 210 65
++237 187 0 238 192 0 238 191 0 238 191 0 238 191 0 238 191 0
++238 190 0 238 190 0 238 189 0 238 189 0 237 187 0 242 237 181
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 221 240 243 73 180 199 49 171 193
++63 175 195 64 176 196 65 176 196 66 177 197 68 178 198 68 178 198
++72 178 197 72 178 197 69 178 196 100 188 204 248 252 253 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 221 240 243 116 192 205 124 196 207
++124 196 207 126 196 207 128 197 208 131 197 208 131 197 208 134 199 210
++134 199 210 134 199 210 131 197 208 171 218 226 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 248 229 146
++242 206 16 243 207 28 243 207 28 243 205 27 243 206 25 243 206 25
++243 206 25 243 205 21 243 205 21 243 205 21 241 197 1 247 227 124
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 229 218 98
++237 187 0 238 192 0 238 191 0 238 191 0 238 191 0 238 191 0
++238 190 0 238 190 0 238 189 0 238 189 0 237 187 0 242 234 164
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 221 240 243 71 179 199 58 174 194
++63 175 195 64 176 196 66 177 197 66 177 197 68 178 198 70 178 196
++72 178 197 73 180 199 69 178 196 109 192 207 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 221 240 243 119 193 206 124 196 207
++126 196 207 128 197 208 128 197 208 131 197 208 134 199 210 134 199 210
++134 199 210 137 202 213 131 197 208 171 218 226 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 248 229 146
++242 206 16 243 207 28 243 207 28 243 206 25 243 206 25 243 206 25
++243 206 23 243 205 21 243 205 21 243 204 22 241 197 1 248 229 146
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 229 218 98
++237 187 0 238 191 0 238 191 0 238 191 0 238 191 0 238 190 0
++238 190 0 238 189 0 238 189 0 238 189 0 237 187 0 242 234 164
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 221 240 243 71 179 199 58 174 194
++63 175 195 64 176 196 66 177 197 66 177 197 68 178 198 70 178 196
++72 178 197 73 180 199 69 178 196 103 191 206 254 253 253 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 221 240 243 119 193 206 124 196 207
++126 196 207 128 197 208 128 197 208 131 197 208 134 199 210 134 199 210
++134 199 210 137 202 213 131 197 208 171 218 226 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 248 229 146
++242 206 16 243 207 28 243 207 26 243 206 25 243 206 25 243 206 25
++243 205 21 243 205 21 243 204 22 243 204 20 241 197 1 248 229 146
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 229 218 98
++237 187 0 238 191 0 238 191 0 238 191 0 238 191 0 238 190 0
++238 190 0 238 189 0 238 189 0 238 188 0 237 187 0 242 234 164
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 221 240 243 75 181 199 58 174 194
++64 176 196 64 176 196 66 177 197 66 177 197 68 178 198 70 178 196
++72 178 197 73 180 199 72 178 197 92 186 203 239 248 249 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 201 231 236 119 193 206 124 196 207
++126 196 207 128 197 208 128 197 208 131 197 208 134 199 210 134 199 210
++134 199 210 137 202 213 131 197 208 171 218 226 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 248 229 146
++242 206 16 243 207 28 243 206 25 243 206 25 243 206 25 243 206 23
++243 205 21 243 205 21 243 205 21 243 203 18 241 197 1 247 227 124
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 228 210 65
++237 187 0 238 191 0 238 191 0 238 191 0 238 190 0 238 190 0
++238 189 0 238 189 0 238 188 0 238 188 0 237 187 0 242 237 181
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 239 248 249 84 184 202 49 171 193
++64 176 196 65 176 196 66 177 197 68 178 198 70 178 196 72 178 197
++72 178 197 73 180 199 73 180 199 83 182 199 221 240 243 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 187 224 231 116 192 205 124 196 207
++128 197 208 128 197 208 131 197 208 134 199 210 134 199 210 134 199 210
++137 202 213 137 202 213 131 197 208 187 224 231 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 242 234 164
++242 205 14 243 207 26 243 206 25 243 206 25 243 206 25 243 205 21
++243 205 21 243 204 22 243 204 20 243 203 18 241 201 6 229 218 98
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 252 251 239 241 203 27
++237 187 0 238 191 0 238 191 0 238 191 0 238 190 0 238 190 0
++238 189 0 238 189 0 238 188 0 238 188 0 237 187 0 245 244 203
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 103 191 206 49 171 193
++64 176 196 65 176 196 66 177 197 68 178 198 70 178 196 72 178 197
++73 180 199 75 181 199 75 181 199 70 178 196 171 218 226 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 151 211 222 116 192 205 124 196 207
++128 197 208 128 197 208 131 197 208 134 199 210 134 199 210 134 199 210
++137 202 213 137 202 213 134 199 210 201 231 236 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 245 244 203
++243 203 18 243 206 25 243 206 25 243 206 25 243 204 22 243 205 21
++243 205 21 243 204 20 243 203 18 243 203 18 242 202 16 243 207 28
++250 247 226 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 245 244 203 238 189 0
++238 190 0 238 191 0 238 191 0 238 190 0 238 190 0 238 189 0
++238 189 0 238 188 0 238 188 0 237 187 0 239 189 11 250 247 226
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 128 201 213 49 171 193
++64 176 196 66 177 197 68 178 198 68 178 198 72 178 197 72 178 197
++73 180 199 75 181 199 77 180 198 69 178 196 116 195 209 248 252 253
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 221 240 243 124 196 207 122 194 206 126 196 207
++128 197 208 128 197 208 131 197 208 134 199 210 134 199 210 137 202 213
++137 202 213 137 202 213 137 202 213 221 240 243 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 250 247 226
++244 209 33 243 204 20 243 206 25 243 206 23 243 205 21 243 205 21
++243 204 22 243 203 18 243 203 18 243 203 18 243 203 18 240 197 4
++248 229 146 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 229 218 98 237 187 0
++238 191 0 238 191 0 238 190 0 238 190 0 238 189 0 238 189 0
++238 188 0 238 188 0 237 187 0 237 187 0 244 209 33 254 251 247
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 171 218 226 58 174 194
++64 176 196 66 177 197 68 178 198 68 178 198 72 178 197 72 178 197
++73 180 199 75 181 199 79 181 198 79 181 198 72 178 197 201 231 236
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 171 218 226 113 192 205 124 196 207 126 196 207
++128 197 208 131 197 208 131 197 208 134 199 210 134 199 210 137 202 213
++137 202 213 134 199 210 149 206 215 239 248 249 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 254 251 247
++228 210 65 242 202 13 243 206 25 243 204 22 243 205 21 243 205 21
++243 204 20 243 203 18 243 203 18 243 203 18 242 202 16 241 201 6
++244 209 33 254 251 247 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 247 246 214 239 189 11 238 189 0
++238 191 0 238 191 0 238 190 0 238 190 0 238 189 0 238 189 0
++238 188 0 238 188 0 237 187 0 237 187 0 229 218 98 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 221 240 243 65 176 196
++64 176 196 66 177 197 68 178 198 68 178 198 72 178 197 73 180 199
++73 180 199 77 180 198 79 181 198 81 181 199 77 180 198 103 191 206
++239 248 249 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 201 231 236 116 192 205 124 196 207 124 196 207 128 197 208
++128 197 208 131 197 208 134 199 210 134 199 210 134 199 210 137 202 213
++137 202 213 134 199 210 171 218 226 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++247 227 124 241 201 6 243 204 22 243 205 21 243 205 21 243 204 22
++243 203 18 243 203 18 243 203 18 243 203 18 242 202 16 241 201 15
++240 197 4 247 227 124 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 228 210 65 237 187 0 238 191 0
++238 191 0 238 190 0 238 190 0 238 190 0 238 189 0 238 189 0
++238 188 0 238 188 0 237 187 0 237 187 0 242 234 164 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 254 253 253 103 191 206
++58 174 194 66 177 197 68 178 198 70 178 196 72 178 197 73 180 199
++73 180 199 77 180 198 79 181 198 81 181 199 83 182 199 72 178 197
++137 202 213 254 253 253 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++239 248 249 128 197 208 116 192 205 124 196 207 124 196 207 128 197 208
++128 197 208 131 197 208 134 199 210 134 199 210 134 199 210 137 202 213
++137 202 213 134 199 210 201 231 236 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++245 244 203 243 206 25 243 203 18 243 205 21 243 204 22 243 204 20
++243 203 18 243 203 18 243 203 18 242 202 16 242 202 16 243 203 18
++241 198 11 240 197 6 242 237 181 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 247 227 124 237 187 0 238 191 0 238 191 0
++238 191 0 238 190 0 238 190 0 238 189 0 238 189 0 238 188 0
++238 188 0 237 187 0 237 187 0 240 197 25 250 247 226 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 171 218 226
++49 171 193 66 177 197 68 178 198 70 178 196 72 178 197 73 180 199
++75 181 199 79 181 198 79 181 198 81 181 199 83 182 199 83 182 199
++79 181 198 151 211 222 248 252 253 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 221 240 243
++137 202 213 113 192 205 122 194 206 124 196 207 126 196 207 128 197 208
++128 197 208 131 197 208 134 199 210 134 199 210 134 199 210 137 202 213
++134 199 210 149 206 215 239 248 249 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++254 253 253 228 210 65 242 202 13 243 205 21 243 204 22 243 203 18
++243 203 18 243 203 18 242 202 16 242 202 16 242 202 16 242 202 16
++242 202 13 240 197 6 243 203 18 242 237 181 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 248 229 146 238 189 0 238 190 0 238 191 0 238 190 0
++238 190 0 238 190 0 238 189 0 238 189 0 238 188 0 238 188 0
++237 187 0 237 187 0 237 187 0 228 210 65 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 239 248 249
++84 184 202 58 174 194 68 178 198 70 178 196 73 180 199 73 180 199
++75 181 199 79 181 198 79 181 198 83 182 199 83 182 199 84 184 202
++84 184 202 79 181 198 128 201 213 221 240 243 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 201 231 236 128 197 208
++113 192 205 122 194 206 124 196 207 124 196 207 126 196 207 128 197 208
++128 197 208 131 197 208 134 199 210 134 199 210 134 199 210 137 202 213
++131 197 208 187 224 231 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 248 229 146 241 201 6 243 204 22 243 203 18 243 203 18
++243 203 18 243 203 18 242 202 16 242 202 16 242 202 16 241 201 15
++242 202 13 241 201 15 240 197 5 240 197 6 247 227 124 254 251 247
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 250 250 231
++229 218 98 237 187 0 238 190 0 238 191 0 238 191 0 238 190 0
++238 190 0 238 190 0 238 189 0 238 189 0 238 188 0 238 188 0
++237 187 0 237 187 0 237 187 0 242 237 181 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++151 211 222 58 174 194 69 178 196 72 178 197 73 180 199 75 181 199
++77 180 198 79 181 198 81 181 199 83 182 199 83 182 199 84 184 202
++89 184 201 89 184 201 81 181 199 100 188 204 171 218 226 221 240 243
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 254 253 253 221 240 243 151 211 222 109 190 204 113 192 205
++119 193 206 122 194 206 124 196 207 124 196 207 128 197 208 128 197 208
++131 197 208 134 199 210 134 199 210 134 199 210 137 202 213 134 199 210
++137 202 213 221 240 243 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 252 251 239 244 209 33 242 202 13 243 203 18 243 203 18
++243 203 18 242 202 16 242 202 16 242 202 16 241 201 15 242 202 13
++241 201 15 241 201 15 241 198 11 240 197 4 240 194 0 228 210 65
++242 234 164 252 251 239 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 250 247 226 248 229 146 241 203 27
++237 187 0 238 191 0 238 191 0 238 191 0 238 191 0 238 190 0
++238 190 0 238 189 0 238 189 0 238 188 0 238 188 0 237 187 0
++237 187 0 237 187 0 228 210 65 254 253 253 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++239 248 249 84 184 202 64 176 196 72 178 197 73 180 199 75 181 199
++77 180 198 79 181 198 81 181 199 83 182 199 83 182 199 84 184 202
++89 184 201 89 184 201 92 185 200 89 184 201 83 182 199 105 189 203
++137 202 213 171 218 226 201 231 236 201 231 236 201 231 236 201 231 236
++171 218 226 137 202 213 113 192 205 105 189 203 116 192 205 119 193 206
++119 193 206 122 194 206 124 196 207 126 196 207 128 197 208 128 197 208
++131 197 208 134 199 210 134 199 210 134 199 210 137 202 213 131 197 208
++187 224 231 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 242 234 164 241 201 6 242 202 16 243 203 18
++243 203 18 242 202 16 242 202 16 242 202 16 242 202 13 242 202 13
++241 201 15 241 198 11 241 198 9 241 198 11 241 198 11 239 194 0
++240 194 0 244 209 33 229 218 98 248 229 146 242 234 164 242 237 181
++242 234 164 248 229 146 228 210 65 240 197 25 238 189 0 238 189 0
++238 191 0 238 191 0 238 191 0 238 191 0 238 190 0 238 190 0
++238 189 0 238 189 0 238 189 0 238 188 0 238 188 0 237 187 0
++237 187 0 237 187 0 242 237 181 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 187 224 231 58 174 194 71 179 199 73 180 199 75 181 199
++79 181 198 81 181 199 81 181 199 83 182 199 83 182 199 89 184 201
++89 184 201 92 185 200 92 185 200 96 185 201 96 185 201 96 185 201
++96 185 201 92 185 200 96 185 201 96 185 201 99 187 201 102 188 202
++102 188 202 105 189 203 113 192 205 116 192 205 116 192 205 119 193 206
++122 194 206 122 194 206 124 196 207 128 197 208 128 197 208 131 197 208
++131 197 208 134 199 210 134 199 210 137 202 213 134 199 210 149 206 215
++239 248 249 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 254 251 247 228 210 65 241 201 6 243 203 18
++242 202 16 242 202 16 242 202 16 241 201 15 241 198 11 241 201 15
++241 201 15 241 198 9 241 198 9 241 198 11 241 198 9 240 197 5
++241 197 1 239 194 0 239 194 0 239 192 0 239 192 0 238 191 0
++238 190 0 238 190 0 238 190 0 238 190 0 238 191 0 238 191 0
++238 191 0 238 191 0 238 191 0 238 190 0 238 190 0 238 189 0
++238 189 0 238 189 0 238 188 0 238 188 0 237 187 0 237 187 0
++237 187 0 229 218 98 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 121 197 211 58 174 194 73 180 199 75 181 199
++79 181 198 81 181 199 83 182 199 83 182 199 83 182 199 89 184 201
++89 184 201 92 185 200 92 185 200 96 185 201 97 187 203 99 187 201
++102 188 202 102 188 202 105 189 203 105 189 203 109 190 204 109 190 204
++113 192 205 113 192 205 113 192 205 116 192 205 119 193 206 119 193 206
++122 194 206 124 196 207 124 196 207 128 197 208 128 197 208 131 197 208
++131 197 208 134 199 210 134 199 210 134 199 210 131 197 208 201 231 236
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 245 244 203 243 204 23 241 198 11
++242 202 16 242 202 16 242 202 16 241 198 11 241 201 15 241 201 15
++241 198 11 241 198 9 241 198 11 241 198 11 240 197 6 240 197 5
++240 197 6 240 197 4 240 194 0 239 195 1 240 194 1 240 194 0
++240 194 0 240 194 0 240 194 0 238 192 0 238 192 0 238 191 0
++238 191 0 238 191 0 238 191 0 238 190 0 238 190 0 238 189 0
++238 189 0 238 189 0 238 188 0 238 188 0 237 187 0 237 187 0
++240 197 25 250 247 226 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 239 248 249 92 186 203 66 177 197 79 181 198
++79 181 198 81 181 199 83 182 199 83 182 199 84 184 202 89 184 201
++89 184 201 92 185 200 96 185 201 96 185 201 97 187 203 100 188 204
++102 188 202 102 188 202 105 189 203 105 189 203 109 190 204 109 190 204
++113 192 205 113 192 205 116 192 205 116 192 205 119 193 206 119 193 206
++122 194 206 124 196 207 124 196 207 128 197 208 128 197 208 131 197 208
++134 199 210 134 199 210 134 199 210 128 196 207 187 224 231 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 248 229 146 240 197 4
++242 202 13 243 203 18 241 201 15 242 202 13 241 201 15 241 201 15
++241 198 9 241 198 11 241 198 11 241 198 9 240 197 4 240 197 6
++240 197 6 241 197 1 240 194 0 239 195 1 240 194 1 240 194 0
++240 194 0 240 194 0 239 194 0 238 192 0 238 191 0 238 191 0
++238 191 0 238 191 0 238 191 0 238 190 0 238 190 0 238 189 0
++238 189 0 238 188 0 238 188 0 237 187 0 237 187 0 237 187 0
++242 237 181 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 221 240 243 81 181 199 69 178 196
++79 181 198 81 181 199 83 182 199 83 182 199 89 184 201 89 184 201
++89 184 201 92 185 200 96 185 201 96 185 201 97 187 203 100 188 204
++102 188 202 105 189 203 105 189 203 105 189 203 109 190 204 109 190 204
++113 192 205 113 192 205 116 192 205 116 192 205 119 193 206 119 193 206
++122 194 206 124 196 207 126 196 207 128 197 208 128 197 208 131 197 208
++134 199 210 134 199 210 127 196 207 171 218 226 248 252 253 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 247 227 124
++241 197 1 241 201 15 242 202 13 241 201 15 241 201 15 241 198 11
++241 198 9 241 198 11 241 198 11 240 197 5 240 197 5 240 197 6
++241 197 1 240 194 0 239 195 1 240 194 1 240 194 0 240 194 0
++240 194 0 239 192 0 238 192 0 238 191 0 238 191 0 238 191 0
++238 191 0 238 190 0 238 190 0 238 190 0 238 189 0 238 189 0
++238 188 0 238 188 0 238 188 0 237 187 0 237 187 0 248 229 146
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 201 231 236 83 182 199
++72 178 197 83 182 199 83 182 199 83 182 199 89 184 201 89 184 201
++92 185 200 92 185 200 96 185 201 96 185 201 97 187 203 100 188 204
++102 188 202 105 189 203 105 189 203 107 189 203 109 190 204 109 190 204
++113 192 205 113 192 205 116 192 205 116 192 205 119 193 206 119 193 206
++122 194 206 124 196 207 127 196 207 128 197 208 128 197 208 131 197 208
++134 199 210 126 196 207 151 211 222 248 252 253 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++247 227 124 241 197 1 241 198 11 241 201 15 241 198 11 241 198 9
++241 198 11 241 198 11 240 197 6 240 197 5 240 197 6 240 197 4
++240 194 0 239 195 1 240 194 1 240 194 1 240 194 0 240 194 0
++240 194 0 238 192 0 238 192 0 238 191 0 238 191 0 238 191 0
++238 191 0 238 190 0 238 190 0 238 189 0 238 189 0 238 188 0
++238 188 0 238 188 0 237 187 0 237 187 0 247 227 124 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 201 231 236
++92 186 203 70 178 196 83 182 199 84 184 202 89 184 201 89 184 201
++92 185 200 92 185 200 96 185 201 97 187 203 99 187 201 102 188 202
++102 188 202 105 189 203 105 189 203 107 189 203 109 190 204 113 192 205
++113 192 205 113 192 205 116 192 205 116 192 205 119 193 206 122 194 206
++124 196 207 124 196 207 126 196 207 128 197 208 131 197 208 131 197 208
++124 196 207 171 218 226 248 252 253 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++254 253 253 247 227 124 241 197 1 240 197 6 241 198 11 241 198 9
++241 198 11 241 198 9 240 197 5 240 197 6 240 197 6 241 197 1
++240 194 0 239 195 1 240 194 1 240 194 0 240 194 0 240 194 0
++239 192 0 238 192 0 238 192 0 238 191 0 238 191 0 238 191 0
++238 191 0 238 190 0 238 190 0 238 189 0 238 189 0 238 188 0
++238 188 0 237 187 0 237 187 0 248 229 146 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++221 240 243 116 195 209 70 178 196 83 182 199 89 184 201 89 184 201
++92 185 200 96 185 201 96 185 201 97 187 203 99 187 201 102 188 202
++102 188 202 105 189 203 105 189 203 109 190 204 109 190 204 113 192 205
++113 192 205 116 192 205 116 192 205 119 193 206 119 193 206 122 194 206
++124 196 207 124 196 207 128 197 208 128 197 208 128 197 208 124 196 207
++171 218 226 248 252 253 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 248 229 146 241 198 11 241 197 1 241 198 11
++241 198 11 240 197 6 240 197 5 240 197 6 240 197 4 241 197 1
++239 195 1 239 195 1 240 194 1 240 194 0 240 194 0 240 194 0
++238 192 0 238 192 0 238 191 0 238 191 0 238 191 0 238 191 0
++238 190 0 238 190 0 238 189 0 238 189 0 238 189 0 238 188 0
++237 187 0 240 197 25 242 234 164 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 239 248 249 151 211 222 83 182 199 77 180 198 89 184 201
++92 185 200 96 185 201 96 185 201 97 187 203 100 188 204 102 188 202
++105 189 203 105 189 203 107 189 203 109 190 204 109 190 204 113 192 205
++113 192 205 116 192 205 116 192 205 119 193 206 122 194 206 122 194 206
++124 196 207 126 196 207 124 196 207 119 193 206 137 202 213 201 231 236
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 242 237 181 244 209 33 240 194 0
++240 194 0 240 197 4 240 197 6 240 197 6 241 197 1 239 195 1
++239 195 1 240 194 1 240 194 0 240 194 0 240 194 0 238 192 0
++238 192 0 238 191 0 238 191 0 238 191 0 238 191 0 238 190 0
++238 190 0 238 189 0 238 189 0 238 188 0 237 187 0 237 187 0
++228 210 65 247 246 214 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 201 231 236 128 201 213 83 182 199
++83 182 199 96 185 201 96 185 201 97 187 203 102 188 202 102 188 202
++105 189 203 105 189 203 107 189 203 109 190 204 109 190 204 113 192 205
++113 192 205 116 192 205 116 192 205 119 193 206 122 194 206 122 194 206
++124 196 207 116 192 205 128 197 208 171 218 226 239 248 249 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 254 251 247 247 227 124
++241 203 27 239 194 0 240 194 0 241 197 1 240 194 0 239 195 1
++240 194 1 240 194 0 240 194 0 240 194 0 239 192 0 238 192 0
++238 191 0 238 191 0 238 191 0 238 191 0 238 191 0 238 190 0
++238 190 0 238 189 0 237 187 0 237 187 0 244 209 33 248 229 146
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 201 231 236
++137 202 213 96 185 201 89 184 201 92 185 200 96 185 201 102 188 202
++105 189 203 105 189 203 109 190 204 109 190 204 113 192 205 113 192 205
++116 192 205 116 192 205 116 192 205 116 192 205 113 192 205 116 192 205
++131 197 208 171 218 226 221 240 243 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++250 247 226 247 227 124 241 203 27 240 194 0 239 192 0 239 192 0
++240 194 0 240 194 0 240 194 0 239 194 0 238 192 0 238 192 0
++238 191 0 238 191 0 238 191 0 238 190 0 238 188 0 237 187 0
++237 187 0 237 187 0 244 209 33 248 229 146 252 251 239 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 221 240 243 171 218 226 134 201 213 113 192 205 102 188 202
++96 185 201 92 185 200 96 185 201 99 187 201 102 188 202 102 188 202
++105 188 202 107 189 203 119 193 206 134 201 213 151 211 222 201 231 236
++239 248 249 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 252 251 239 242 234 164 229 218 98 241 203 27
++241 198 9 238 190 0 238 188 0 237 187 0 237 187 0 237 187 0
++237 187 0 237 187 0 237 187 0 238 189 0 239 189 11 244 209 33
++229 218 98 242 237 181 254 251 247 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 239 248 249 201 231 236
++187 224 231 171 218 226 171 218 226 171 218 226 171 218 226 171 218 226
++187 224 231 201 231 236 221 240 243 239 248 249 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 252 251 239
++245 244 203 242 234 164 247 227 124 247 227 124 229 218 98 229 218 98
++229 218 98 247 227 124 248 229 146 242 234 164 245 244 203 254 253 253
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255
++255 255 255 255 255 255
+diff --git a/drivers/video/tca_backlight.h b/drivers/video/tca_backlight.h
+new file mode 120000
+index 0000000..2893a4f
+--- /dev/null
++++ b/drivers/video/tca_backlight.h
+@@ -0,0 +1 @@
++../char/tca_backlight.h
+\ No newline at end of file
+diff --git a/drivers/video/tca_lcdc.c b/drivers/video/tca_lcdc.c
+new file mode 100644
+index 0000000..23f75b0
+--- /dev/null
++++ b/drivers/video/tca_lcdc.c
+@@ -0,0 +1,781 @@
++
++
++/****************************************************************************
++ * FileName : tca_lcdc.c
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++
++#include <asm/io.h>
++#include <bsp.h>
++
++enum {
++ IMGFMT_1BPP = 0, // 1bpp indexed color
++ IMGFMT_2BPP = 1, // 2bpp indexed color
++ IMGFMT_4BPP = 2, // 4bpp indexed color
++ IMGFMT_8BPP = 3, // 8bpp indexed color
++ //...
++ IMGFMT_RGB332 = 8, // RGB332 - 1bytes aligned - R[7:5],G[4:2],B[1:0]
++ IMGFMT_RGB444 = 9, // RGB444 - 2bytes aligned - A[15:12],R[11:8],G[7:3],B[3:0]
++ IMGFMT_RGB565 = 10, // RGB565 - 2bytes aligned - R[15:11],G[10:5],B[4:0]
++ IMGFMT_RGB555 = 11, // RGB555 - 2bytes aligned - A[15],R[14:10],G[9:5],B[4:0]
++ IMGFMT_RGB888 = 12, // RGB888 - 4bytes aligned - A[31:24],R[23:16],G[15:8],B[7:0]
++ IMGFMT_RGB666 = 13, // RGB666 - 4bytes aligned - A[23:18],R[17:12],G[11:6],B[5:0]
++ //...
++ IMGFMT_YUV420 = 24, // YCbCr 4:2:0 Separated format - Not Supported for Image 1 and 2
++ IMGFMT_YUV422 = 25, // YCbCr 4:2:2 Separated format - Not Supported for Image 1 and 2
++ IMGFMT_YUV422P = 26, // YCbCr 4:2:2 Sequential format
++ //...
++ IMGFMT_YUV420I0 = 28, // YCbCr 4:2:0 interleved type 0 format - Not Supported for Image 1 and 2
++ IMGFMT_YUV420I1 = 29, // YCbCr 4:2:0 interleved type 1 format - Not Supported for Image 1 and 2
++ IMGFMT_YUV422I0 = 30, // YCbCr 4:2:2 interleved type 0 format - Not Supported for Image 1 and 2
++ IMGFMT_YUV422I1 = 31, // YCbCr 4:2:2 interleved type 1 format - Not Supported for Image 1 and 2
++
++};// IMGCH_FMT_t;
++
++/*
++ * Channel(IMGx) Enable/Disable
++ *
++ * ch : 0 - IMG0
++ * 1 - IMG1
++ * 2 - IMG2
++ *
++ * flag : 0 - disable
++ * 1 - enable
++ *
++ */
++void tca_lcdc_setimgchenable(int id, unsigned int ch, unsigned int flag)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ switch(ch)
++ {
++ case 0:
++ BITCSET (pLCDC->LI0C, Hw28, (flag) << 28);
++ break;
++ case 1:
++ BITCSET (pLCDC->LI1C, Hw28, (flag) << 28);
++ break;
++ case 2:
++ BITCSET (pLCDC->LI2C, Hw28, (flag) << 28);
++ break;
++ default:
++ break;
++ }
++}
++EXPORT_SYMBOL(tca_lcdc_setimgchenable);
++
++
++/*
++ * Alpha Blending Enable for Image 0/1/2
++ *
++ * imgch: 0 - Image Ch0
++ * 1 - Image Ch1
++ * 2 - Layer Ch2
++ *
++ * flag : 0 - disable
++ * 1 - enable
++ *
++ */
++void tca_lcdc_setlayeralphablendingenable(int id, unsigned int imgch, unsigned int flag)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ switch(imgch)
++ {
++ case 0:
++ BITCSET (pLCDC->LI0C, Hw30, (flag) << 30);
++ break;
++ case 1:
++ BITCSET (pLCDC->LI1C, Hw30, (flag) << 30);
++ break;
++ case 2:
++ BITCSET (pLCDC->LI2C, Hw30, (flag) << 30);
++ break;
++ default:
++ break;
++ }
++}
++
++
++/*
++ * Alpha Selection for Image 0/1/2
++ *
++ * imgch: 0 - Image Ch0
++ * 1 - Image Ch1
++ * 2 - Layer Ch2
++ *
++ * asel : 0 - A10 bits and A11 are used as alpha value
++ * (Ref->tca_lcdc_setlayeralphavalue())
++ * 1 - Alpha bits in the pixel are used as alpha value.
++ *
++ */
++void tca_lcdc_setalphaselection(int id, unsigned int imgch, unsigned int asel)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ switch(imgch)
++ {
++ case 0:
++ BITCSET (pLCDC->LI0C, Hw24, (asel) << 24);
++ break;
++ case 1:
++ BITCSET (pLCDC->LI1C, Hw24, (asel) << 24);
++ break;
++ case 2:
++ BITCSET (pLCDC->LI2C, Hw24, (asel) << 24);
++ break;
++ default:
++ break;
++ }
++}
++
++
++/*
++ * Setting alpha-value for Image 0/1/2
++ *
++ * imgch: Image 0/1/2
++ *
++ * alpha: Output Pixel = Main Pixel * (1-alpha/256) + Overlay Pixel*(alpha)
++ *
++ */
++void tca_lcdc_setlayeralphavalue(int id, unsigned int imgch, unsigned char alpha)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ switch(imgch)
++ {
++ case 0:
++ BITCSET(pLCDC->LI0A, (Hw24-Hw16) | (Hw8-Hw0), ((alpha&0x000000ff)<<16) | ((alpha&0x000000ff)));
++ break;
++ case 1:
++ BITCSET(pLCDC->LI1A, (Hw24-Hw16) | (Hw8-Hw0), ((alpha&0x000000ff)<<16) | ((alpha&0x000000ff)));
++ break;
++ case 2:
++ BITCSET(pLCDC->LI2A, (Hw24-Hw16) | (Hw8-Hw0), ((alpha&0x000000ff)<<16) | ((alpha&0x000000ff)));
++ break;
++ }
++}
++
++
++
++/*
++ * Chroma Key Enable for Image 0/1/2
++ *
++ * imgch: Image 0/1/2
++ *
++ * flag : 0 - disable
++ * 1 - enable
++ *
++ */
++void tca_lcdc_setlayerchromakeyenable(int id, unsigned int imgch, unsigned int flag)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ switch(imgch)
++ {
++ case 0:
++ BITCSET (pLCDC->LI0C, Hw29, (flag) << 29);
++ break;
++ case 1:
++ BITCSET (pLCDC->LI1C, Hw29, (flag) << 29);
++ break;
++ case 2:
++ BITCSET (pLCDC->LI2C, Hw29, (flag) << 29);
++ break;
++ default:
++ break;
++ }
++}
++
++
++
++/*
++ * Setting croma-key value for Image 0/1/2
++ *
++ * imgch: Image 0/1/2
++ *
++ * ry : chroma-key value in R(Y) channel for Layer
++ * gu : chroma-key value in G(U) channel for Layer
++ * bv : chroma-key value in V(V) channel for Layer
++ *
++ */
++void tca_lcdc_setlayerchromakeyvalue(int id, unsigned int imgch, unsigned int ry, unsigned int gu, unsigned int bv)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ switch(imgch)
++ {
++ case 0:
++ BITCSET (pLCDC->LI0KR, Hw8-Hw0, (ry&0x000000ff));
++ BITCSET (pLCDC->LI0KG, Hw8-Hw0, (gu&0x000000ff));
++ BITCSET (pLCDC->LI0KB, Hw8-Hw0, (bv&0x000000ff));
++ break;
++ case 1:
++ BITCSET (pLCDC->LI1KR, Hw8-Hw0, (ry&0x000000ff));
++ BITCSET (pLCDC->LI1KG, Hw8-Hw0, (gu&0x000000ff));
++ BITCSET (pLCDC->LI1KB, Hw8-Hw0, (bv&0x000000ff));
++ break;
++ case 2:
++ BITCSET (pLCDC->LI2KR, Hw8-Hw0, (ry&0x000000ff));
++ BITCSET (pLCDC->LI2KG, Hw8-Hw0, (gu&0x000000ff));
++ BITCSET (pLCDC->LI2KB, Hw8-Hw0, (bv&0x000000ff));
++ break;
++ default:
++ break;
++ }
++}
++
++
++/*
++ * Setting masking croma-key value for layer1/layer2
++ *
++ * imgch: Image 0/1/2
++ *
++ * mry : masking chroma-key value in R(Y) channel for Layer
++ * mgu : masking chroma-key value in G(U) channel for Layer
++ * mbv : masking chroma-key value in V(V) channel for Layer
++ *
++ */
++void tca_lcdc_setlayerchromakeymask(int id, unsigned int imgch, unsigned int mry, unsigned int mgu, unsigned int mbv)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ switch(imgch)
++ {
++ case 0:
++ BITCSET (pLCDC->LI0KR, Hw24-Hw16, (mry&0x000000ff)<<16);
++ BITCSET (pLCDC->LI0KG, Hw24-Hw16, (mgu&0x000000ff)<<16);
++ BITCSET (pLCDC->LI0KB, Hw24-Hw16, (mbv&0x000000ff)<<16);
++ break;
++ case 1:
++ BITCSET (pLCDC->LI1KR, Hw24-Hw16, (mry&0x000000ff)<<16);
++ BITCSET (pLCDC->LI1KG, Hw24-Hw16, (mgu&0x000000ff)<<16);
++ BITCSET (pLCDC->LI1KB, Hw24-Hw16, (mbv&0x000000ff)<<16);
++ break;
++ case 2:
++ BITCSET (pLCDC->LI2KR, Hw24-Hw16, (mry&0x000000ff)<<16);
++ BITCSET (pLCDC->LI2KG, Hw24-Hw16, (mgu&0x000000ff)<<16);
++ BITCSET (pLCDC->LI2KB, Hw24-Hw16, (mbv&0x000000ff)<<16);
++ break;
++ default:
++ break;
++ }
++}
++
++
++/*
++ * Setting IMGx Format.
++ *
++ * ch : 0 - IMG0
++ * 1 - IMG1
++ * 2 - IMG2
++ *
++ * fmt : Ref to IMGCH_FMT_t type
++ *
++ */
++// default ZERO-FILL
++void tca_lcdc_setimgchfmt(int id, unsigned int imgch, unsigned int fmt/*, unsigned int pd*/)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ switch(imgch)
++ {
++ case 0:
++ BITCSET (pLCDC->LI0C, Hw5-Hw0, fmt);
++ if(fmt >=24)
++ BITSET (pLCDC->LI0C, Hw8);
++ else
++ BITCLR (pLCDC->LI0C, Hw8);
++ break;
++ case 1:
++ BITCSET (pLCDC->LI1C, Hw5-Hw0, fmt);
++ if(fmt >=24)
++ BITSET (pLCDC->LI1C, Hw8);
++ else
++ BITCLR (pLCDC->LI1C, Hw8);
++ break;
++ case 2:
++ BITCSET (pLCDC->LI2C, Hw5-Hw0, fmt);
++ if(fmt >=24)
++ BITSET (pLCDC->LI2C, Hw8);
++ else
++ BITCLR (pLCDC->LI2C, Hw8);
++ break;
++ default:
++ break;
++ }
++
++
++}
++
++
++void tca_lcdc_getimgchfmt(int id, unsigned int imgch, unsigned int *out_fmt/*, unsigned int *out_pd*/)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ switch(imgch)
++ {
++ case 0:
++ *out_fmt= (pLCDC->LI0C & 0x0000001F);
++ break;
++ case 1:
++ *out_fmt= (pLCDC->LI1C & 0x0000001F);
++ break;
++ case 2:
++ *out_fmt= (pLCDC->LI2C & 0x0000001F);
++ break;
++ }
++}
++
++
++
++/*
++ * Setting LCD IMGx base address
++ *
++ * ch : IMG channel.
++ * 0 - IMG0
++ * 1 - IMG1
++ * 2 - IMG2
++ * base0 : IMGx base address. IMG0 Y base address.
++ * base1 : IMG0 U base address.
++ * base2 : IMG0 V base address.
++ *
++ */
++void tca_lcdc_setimgchbase(int id, unsigned int imgch, unsigned int base0, unsigned int base1, unsigned int base2)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ switch (imgch)
++ {
++ case 0: //IMG_CH0 :
++ BITCSET(pLCDC->LI0BA0, 0xFFFFFFFF, base0);
++ BITCSET(pLCDC->LI0BA1, 0xFFFFFFFF, base1);
++ BITCSET(pLCDC->LI0BA2, 0xFFFFFFFF, base2);
++ break;
++ case 1: //IMG_CH1 :
++ BITCSET(pLCDC->LI1BA0, 0xFFFFFFFF, base0);
++ break;
++ case 2: //IMG_CH2 :
++ BITCSET(pLCDC->LI2BA0, 0xFFFFFFFF, base0);
++ break;
++ }
++}
++
++void tca_lcdc_getimgchbase(int id, unsigned int imgch, unsigned int *out_base0, unsigned int *out_base1, unsigned int *out_base2)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ switch (imgch)
++ {
++ case 0: //IMG_CH0 :
++ *out_base0 = (pLCDC->LI0BA0);
++ *out_base1 = (pLCDC->LI0BA1);
++ *out_base2 = (pLCDC->LI0BA2);
++ break;
++ case 1: //IMG_CH1 :
++ *out_base0 = (pLCDC->LI1BA0);
++ *out_base1 = 0;
++ *out_base2 = 0;
++ break;
++ case 2: //IMG_CH2 :
++ *out_base0 = (pLCDC->LI2BA0);
++ *out_base1 = 0;
++ *out_base2 = 0;
++ break;
++ }
++}
++
++
++void tca_lcdc_setimgchOffsetInfo(int id, unsigned int imgch, unsigned int offset0, unsigned int offset1)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ switch (imgch)
++ {
++ case 0: //IMG_CH0 :
++ BITCSET(pLCDC->LI0O, 0xFFFFFFFF, (offset0&0x0000ffff) | (offset1&0x0000ffff)<<16);
++ break;
++ case 1: //IMG_CH1 :
++ BITCSET(pLCDC->LI1O, 0xFFFFFFFF, (offset0&0x0000ffff));
++ break;
++ case 2: //IMG_CH2 :
++ BITCSET(pLCDC->LI2O, 0xFFFFFFFF, (offset0&0x0000ffff));
++ break;
++ }
++}
++
++void tca_lcdc_setaddroffset(int id, unsigned int imgch, unsigned int imgwidth, unsigned int fmt)
++{
++ unsigned int offset0=0;
++ unsigned int offset1=0;
++
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ switch(fmt)
++ {
++ case IMGFMT_1BPP: // 1bpp indexed color
++ offset0 = (1*imgwidth)/8;
++ break;
++ case IMGFMT_2BPP: // 2bpp indexed color
++ offset0 = (1*imgwidth)/4;
++ break;
++ case IMGFMT_4BPP: // 4bpp indexed color
++ offset0 = (1*imgwidth)/2;
++ break;
++ case IMGFMT_8BPP: // 8bpp indexed color
++ offset0 = (1*imgwidth);
++ break;
++ //...
++ case IMGFMT_RGB332: // RGB332 - 1bytes aligned - R[7:5],G[4:2],B[1:0]
++ offset0 = 1*imgwidth;
++ break;
++ case IMGFMT_RGB444: // RGB444 - 2bytes aligned - A[15:12],R[11:8],G[7:3],B[3:0]
++ case IMGFMT_RGB565: // RGB565 - 2bytes aligned - R[15:11],G[10:5],B[4:0]
++ case IMGFMT_RGB555: // RGB555 - 2bytes aligned - A[15],R[14:10],G[9:5],B[4:0]
++ offset0 = 2*imgwidth;
++ break;
++ case IMGFMT_RGB888: // RGB888 - 4bytes aligned - A[31:24],R[23:16],G[15:8],B[7:0]
++ case IMGFMT_RGB666: // RGB666 - 4bytes aligned - A[23:18],R[17:12],G[11:6],B[5:0]
++ offset0 = 4*imgwidth;
++ break;
++ //...
++ case IMGFMT_YUV420: // YCbCr 4:2:0 Separated format - Not Supported for Image 1 and 2
++ //!!!!
++ offset0 = imgwidth;
++ offset1 = imgwidth/2;
++ break;
++ case IMGFMT_YUV422: // YCbCr 4:2:2 Separated format - Not Supported for Image 1 and 2
++ //!!!!
++ offset0 = imgwidth;
++ offset1 = imgwidth/2;
++ break;
++ case IMGFMT_YUV422P: // YCbCr 4:2:2 Sequential format
++ offset0 = 2*imgwidth;
++ break;
++ //...
++ case IMGFMT_YUV420I0: // YCbCr 4:2:0 interleved type 0 format - Not Supported for Image 1 and 2
++ case IMGFMT_YUV420I1: // YCbCr 4:2:0 interleved type 1 format - Not Supported for Image 1 and 2
++ //!!!!
++ offset0 = imgwidth;
++ offset1 = imgwidth;
++ break;
++ case IMGFMT_YUV422I0: // YCbCr 4:2:2 interleved type 0 format - Not Supported for Image 1 and 2
++ case IMGFMT_YUV422I1: // YCbCr 4:2:2 interleved type 1 format - Not Supported for Image 1 and 2
++ //!!!!
++ offset0 = imgwidth;
++ offset1 = imgwidth;
++ break;
++ }
++
++ switch (imgch)
++ {
++ case 0: //IMG_CH0 :
++ BITCSET(pLCDC->LI0O, 0xFFFFFFFF, (offset0&0x0000ffff) | (offset1&0x0000ffff)<<16);
++ break;
++ case 1: //IMG_CH1 :
++ BITCSET(pLCDC->LI1O, 0xFFFFFFFF, (offset0&0x0000ffff));
++ break;
++ case 2: //IMG_CH2 :
++ BITCSET(pLCDC->LI2O, 0xFFFFFFFF, (offset0&0x0000ffff));
++ break;
++ }
++}
++
++/*
++ * Setting LCD IMGx Window
++ *
++ * ch : IMG channel.
++ * 0 - IMG0
++ * 1 - IMG1
++ * 2 - IMG2
++ * sx : start offset x
++ * sy : start offset y
++ * w : width
++ * h : height
++ */
++void tca_lcdc_setimgchwindow(int id, unsigned int imgch, unsigned int sx, unsigned int sy, unsigned int w, unsigned int h)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ switch (imgch)
++ {
++ case 0: //IMG_CH0 :
++ BITCSET(pLCDC->LI0P, 0xFFFFFFFF, (sx&0x0000ffff) | (sy&0x0000ffff)<<16);
++ BITCSET(pLCDC->LI0S, 0xFFFFFFFF, (w &0x0000ffff) | (h &0x0000ffff)<<16);
++ break;
++ case 1: //IMG_CH1 :
++ BITCSET(pLCDC->LI1P, 0xFFFFFFFF, (sx&0x0000ffff) | (sy&0x0000ffff)<<16);
++ BITCSET(pLCDC->LI1S, 0xFFFFFFFF, (w &0x0000ffff) | (h &0x0000ffff)<<16);
++ break;
++ case 2: //IMG_CH2 :
++ BITCSET(pLCDC->LI2P, 0xFFFFFFFF, (sx&0x0000ffff) | (sy&0x0000ffff)<<16);
++ BITCSET(pLCDC->LI2S, 0xFFFFFFFF, (w &0x0000ffff) | (h &0x0000ffff)<<16);
++ break;
++ }
++}
++
++enum {
++ R2Y_CONV_OPTION_0 = 0, // * Y = 0.299*R + 0.587G + 0.114B
++ // * Cb = -0.172*R - 0.339*G + 0.511*B + 128
++ // * Cr = 0.511*R - 0.428*G - 0.083*B + 128
++ // The range for "RGB" is 16 ~ 235, "Studio Color".
++ // The result is "Studio Color" - Normally SDTV.
++
++ R2Y_CONV_OPTION_1 = 1, // * Y = 0.257*R + 0.504*G + 0.098*B + 16
++ // * Cb = -0.148*R - 0.291*G + 0.439*B + 128
++ // * Cr = 0.439*R - 0.368*G - 0.071*B + 128
++ // The range for "RGB" is 0 ~ 255, "Computer System Color"
++ // The result is "Studio Color" - Normally SDTV.
++
++ R2Y_CONV_OPTION_2 = 2, // * Y = 0.213*R + 0.715*G + 0.072*B
++ // * Cb = -0.117*R - 0.394*G + 0.511*B + 128
++ // * Cr = 0.511*R - 0.464*G - 0.047*B + 128
++ // The range for "RGB" is 16 ~ 235, "Studio Color"..
++ // The result is "Studio Color" - Normally HDTV.
++
++ R2Y_CONV_OPTION_3 = 3, // * Y = 0.183*R + 0.614*G + 0.062*B + 16
++ // * Cb = -0.101*R - 0.338*G + 0.439*B + 128
++ // * Cr = 0.439*R - 0.399*G - 0.040*B + 128
++ // The range for "RGB" is 0 ~ 255, "Computer System Color".
++ // The result is "Studio Color" - Normally HDTV.
++};// RGB2YUV_CONV_OPTION_t;
++
++// RGB to YCbCr Conversion Option
++void tca_lcdc_setr2yconvopt(int id, unsigned int conv_opt)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ if(conv_opt > (unsigned int)R2Y_CONV_OPTION_3)
++ return;
++
++ BITCSET(pLCDC->LCTRL, Hw29|Hw28, conv_opt<<28);
++}
++
++void tca_lcdc_getr2yconvopt(int id, unsigned int *conv_opt_out)
++{
++ volatile PLCDC pLCDC;
++ volatile unsigned int value;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ if(conv_opt_out == 0)
++ return;
++
++ value = (pLCDC->LCTRL) & (Hw29|Hw28);
++ *conv_opt_out = (value>>28) & 0x3;;
++}
++
++
++enum {
++ Y2R_CONV_OPTION_0 = 0, // * R = Y + 1.371 * (Cr - 128)
++ // * G = Y + 0.336 * (Cb - 128) - 0.698 * (Cr - 128)
++ // * B = Y + 1.732 * (Cb - 128)
++ // The range for "YCbCr" is 16 ~ 235, "Studio Color".
++ // The result is "Studio Color" - Normally SDTV.
++
++ Y2R_CONV_OPTION_1 = 1, // * R = 1.164 * (Y - 16) + 1.596 * (Cr - 128)
++ // * G = 1.164 * (Y - 16) - 0.391 * (Cb - 128) - 0.813 * (Cr - 128)
++ // * B = 1.164 * (Y - 16) + 2.018 * (Cb - 128)
++ // The range for "YCbCr" is 16 ~ 235, "Studio Color".
++ // The result is "Computer System Color" - Normally SDTV.
++
++ Y2R_CONV_OPTION_2 = 2, // * R = Y + 1.540 * (Cr - 128)
++ // * G = Y - 0.183 * (Cb - 128) - 0.459 * (Cr - 128)
++ // * B = Y + 1.816 * (Cb - 128)
++ // The range for "YCbCr" is 16 ~ 235, "Studio Color".
++ // The result is "Studio Color" - Normally HDTV.
++
++ Y2R_CONV_OPTION_3 = 3, // * R = 1.164 * (Y - 16) + 1.793 * (Cr - 128)
++ // * G = 1.164 * (Y - 16) - 0.213 * (Cb - 128) - 0.534 * (Cr - 128)
++ // * B = 1.164 * (Y - 16) + 2.115 * (Cb - 128)
++ // The range for "YCbCr" is 16 ~ 235, "Studio Color".
++ // The result is "Computer System Color" - Normally HDTV.
++
++};// YUV2RGB_CONV_OPTION_t;
++
++void tca_lcdc_setimgy2rconvopt(int id, unsigned int imgch, unsigned int conv_opt)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ if (id!=1 && imgch>0)
++ return;
++
++ switch (imgch)
++ {
++ case 0: //IMG_CH0 :
++ BITCSET(pLCDC->LI0C, 0x00000600, conv_opt<<9);
++ break;
++ case 1: //IMG_CH1 :
++ BITCSET(pLCDC->LI1C, 0x00000600, conv_opt<<9);
++ break;
++ case 2: //IMG_CH2 :
++ BITCSET(pLCDC->LI2C, 0x00000600, conv_opt<<9);
++ break;
++ }
++}
++
++void tca_lcdc_getimgy2rconvopt(int id, unsigned int imgch, unsigned int *conv_opt_out)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ if (id!=1 && imgch>0)
++ return;
++
++ switch (imgch)
++ {
++ case 0: //IMG_CH0 :
++ *conv_opt_out = ((pLCDC->LI0C)>>9) & 0x3;
++ break;
++ case 1: //IMG_CH1 :
++ *conv_opt_out = ((pLCDC->LI1C)>>9) & 0x3;
++ break;
++ case 2: //IMG_CH2 :
++ *conv_opt_out = ((pLCDC->LI2C)>>9) & 0x3;
++ break;
++ }
++}
++
++
++void tca_lcdc_setcolorenhancement(int id, unsigned int hue, unsigned int bright, unsigned int cont)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ BITCSET(pLCDC->LENH, 0x00ff0000, hue<<16);
++ BITCSET(pLCDC->LENH, 0x0000ff00, bright<<8);
++ BITCSET(pLCDC->LENH, 0x000000ff, cont);
++}
++
++void tca_lcdc_getcolorenhancement(int id, unsigned int *hue, unsigned int *bright, unsigned int *cont)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ *hue = ((pLCDC->LENH)>>16) & 0xff;
++ *bright = ((pLCDC->LENH)>> 8) & 0xff;
++ *cont = ((pLCDC->LENH)>> 0) & 0xff;
++}
++
++void tca_lcdc_setimgenhancement(int id, unsigned int imgch, unsigned int hue, unsigned int bright, unsigned int cont)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ if (id!=1 && imgch>0)
++ return;
++
++ switch (imgch)
++ {
++ case 0: //IMG_CH0 :
++ BITCSET(pLCDC->LI0EN, 0x00ff0000, hue<<16);
++ BITCSET(pLCDC->LI0EN, 0x0000ff00, bright<<8);
++ BITCSET(pLCDC->LI0EN, 0x000000ff, cont);
++ break;
++ case 1: //IMG_CH1 :
++ BITCSET(pLCDC->LI1EN, 0x00ff0000, hue<<16);
++ BITCSET(pLCDC->LI1EN, 0x0000ff00, bright<<8);
++ BITCSET(pLCDC->LI1EN, 0x000000ff, cont);
++ break;
++ case 2: //IMG_CH2 :
++ BITCSET(pLCDC->LI2EN, 0x00ff0000, hue<<16);
++ BITCSET(pLCDC->LI2EN, 0x0000ff00, bright<<8);
++ BITCSET(pLCDC->LI2EN, 0x000000ff, cont);
++ break;
++ }
++}
++
++void tca_lcdc_getimgenhancement(int id, unsigned int imgch, unsigned int *hue, unsigned int *bright, unsigned int *cont)
++{
++ volatile PLCDC pLCDC;
++
++ if (id) pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ else pLCDC = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++
++ if (id!=1 && imgch>0)
++ return;
++
++ switch (imgch)
++ {
++ case 0: //IMG_CH0 :
++ *hue = ((pLCDC->LI0EN)>>16) & 0xff;
++ *bright = ((pLCDC->LI0EN)>> 8) & 0xff;
++ *cont = ((pLCDC->LI0EN)>> 0) & 0xff;
++ break;
++ case 1: //IMG_CH1 :
++ *hue = ((pLCDC->LI1EN)>>16) & 0xff;
++ *bright = ((pLCDC->LI1EN)>> 8) & 0xff;
++ *cont = ((pLCDC->LI1EN)>> 0) & 0xff;
++ break;
++ case 2: //IMG_CH2 :
++ *hue = ((pLCDC->LI2EN)>>16) & 0xff;
++ *bright = ((pLCDC->LI2EN)>> 8) & 0xff;
++ *cont = ((pLCDC->LI2EN)>> 0) & 0xff;
++ break;
++ }
++}
++
++
+diff --git a/drivers/video/tca_tvout.c b/drivers/video/tca_tvout.c
+new file mode 100644
+index 0000000..4c1e592
+--- /dev/null
++++ b/drivers/video/tca_tvout.c
+@@ -0,0 +1,938 @@
++
++/****************************************************************************
++ * FileName : tca_tvo.c
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++/*****************************************************************************
++*
++* Header Files Include
++*
++******************************************************************************/
++
++#ifdef __KERNEL__
++#include <linux/delay.h>
++#include <linux/string.h>
++#include "bsp.h"
++#include <mach/tca_ckc.h>
++#else
++#include <windows.h>
++#include <bsp.h>
++
++#include "TCC89x_Physical.h"
++#include "TCC89x_Structures.h"
++#include "tcc_ckc.h"
++#include "tcc_gpio.h"
++#endif
++
++#include "tca_tvout.h"
++#include <hhtech_gpio.h>
++#include <mach/gpio.h>
++
++/*****************************************************************************
++*
++* Defines
++*
++******************************************************************************/
++// trick.
++
++#if defined(__KERNEL__)
++#define tcc_allocbaseaddress(X) (X)
++
++void tcc_ckc_setperi(unsigned int periname,unsigned int isenable, unsigned int freq, unsigned int sor)
++{
++ tca_ckc_setperi(periname,isenable, freq, sor);
++}
++
++volatile int tcc_ckc_getperi(unsigned int periname)
++{
++ return tca_ckc_getperi(periname);
++}
++
++#endif
++
++#if !defined(__KERNEL__)
++
++#if defined(HwTVE_BASE)
++#undef HwTVE_BASE
++#endif
++#define HwTVE_BASE *(volatile unsigned long *)0xB0240000 // TV Encoder Base Register
++
++#endif //__KERNEL__
++
++#define HwTVESTATA *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x0)//0xB0240000 // R, Status Register
++
++#define HwTVECMDA *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x4)//0xB0240004 // R/W, Encoder Mode Control Register A
++ #define HwTVECMDA_PWDENC_PD Hw7 // Power down mode for entire digital logic of TV encoder
++ #define HwTVECMDA_FDRST_1 Hw6 // Chroma is free running as compared to H-sync
++ #define HwTVECMDA_FDRST_0 HwZERO // Relationship between color burst & H-sync is maintained for video standards
++ #define HwTVECMDA_FSCSEL(X) ((X)*Hw4)
++ #define HwTVECMDA_FSCSEL_NTSC HwTVECMDA_FSCSEL(0) // Color subcarrier frequency is 3.57954545 MHz for NTSC
++ #define HwTVECMDA_FSCSEL_PALX HwTVECMDA_FSCSEL(1) // Color subcarrier frequency is 4.43361875 MHz for PAL-B,D,G,H,I,N
++ #define HwTVECMDA_FSCSEL_PALM HwTVECMDA_FSCSEL(2) // Color subcarrier frequency is 3.57561149 MHz for PAL-M
++ #define HwTVECMDA_FSCSEL_PALCN HwTVECMDA_FSCSEL(3) // Color subcarrier frequency is 3.58205625 MHz for PAL-combination N
++ #define HwTVECMDA_FSCSEL_MASK HwTVECMDA_FSCSEL(3)
++ #define HwTVECMDA_PEDESTAL Hw3 // Video Output has a pedestal
++ #define HwTVECMDA_NO_PEDESTAL HwZERO // Video Output has no pedestal
++ #define HwTVECMDA_PIXEL_SQUARE Hw2 // Input data is at square pixel rates.
++ #define HwTVECMDA_PIXEL_601 HwZERO // Input data is at 601 rates.
++ #define HwTVECMDA_IFMT_625 Hw1 // Output data has 625 lines
++ #define HwTVECMDA_IFMT_525 HwZERO // Output data has 525 lines
++ #define HwTVECMDA_PHALT_PAL Hw0 // PAL encoded chroma signal output
++ #define HwTVECMDA_PHALT_NTSC HwZERO // NTSC encoded chroma signal output
++
++#define HwTVECMDB *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x8)//0xB0240008 // R/W, Encoder Mode Control Register B
++ #define HwTVECMDB_YBIBLK_BLACK Hw4 // Video data is forced to Black level for Vertical non VBI processed lines.
++ #define HwTVECMDB_YBIBLK_BYPASS HwZERO // Input data is passed through forn non VBI processed lines.
++ #define HwTVECMDB_CBW(X) ((X)*Hw2)
++ #define HwTVECMDB_CBW_LOW HwTVECMDB_CBW(0) // Low Chroma band-width
++ #define HwTVECMDB_CBW_MEDIUM HwTVECMDB_CBW(1) // Medium Chroma band-width
++ #define HwTVECMDB_CBW_HIGH HwTVECMDB_CBW(2) // High Chroma band-width
++ #define HwTVECMDB_CBW_MASK HwTVECMDB_CBW(3) //
++ #define HwTVECMDB_YBW(X) ((X)*Hw0)
++ #define HwTVECMDB_YBW_LOW HwTVECMDB_YBW(0) // Low Luma band-width
++ #define HwTVECMDB_YBW_MEDIUM HwTVECMDB_YBW(1) // Medium Luma band-width
++ #define HwTVECMDB_YBW_HIGH HwTVECMDB_YBW(2) // High Luma band-width
++ #define HwTVECMDB_YBW_MASK HwTVECMDB_YBW(3) //
++
++#define HwTVEGLK *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0xc)//0xB024000C // R/W, Encoder Clock Generator Register
++ #define HwTVEGLK_XT24_24MHZ Hw4 // 24MHz Clock input
++ #define HwTVEGLK_XT24_27MHZ HwZERO // 27MHz Clock input
++ #define HwTVEGLK_GLKEN_RST_EN Hw3 // Reset Genlock
++ #define HwTVEGLK_GLKEN_RST_DIS ~Hw3 // Release Genlock
++ #define HwTVEGLK_GLKE(X) ((X)*Hw1)
++ #define HwTVEGLK_GLKE_INT HwTVEGLK_GLKE(0) // Chroma Fsc is generated from internal constants based on current user setting
++ #define HwTVEGLK_GLKE_RTCO HwTVEGLK_GLKE(2) // Chroma Fsc is adjusted based on external RTCO input
++ #define HwTVEGLK_GLKE_CLKI HwTVEGLK_GLKE(3) // Chroma Fsc tracks non standard encoder clock (CLKI) frequency
++ #define HwTVEGLK_GLKE_MASK HwTVEGLK_GLKE(3) //
++ #define HwTVEGLK_GLKEN_GLKPL_HIGH Hw0 // PAL ID polarity is active high
++ #define HwTVEGLK_GLKEN_GLKPL_LOW HwZERO // PAL ID polarity is active low
++
++#define HwTVESCH *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x10)//0xB0240010 // R/W, Color burst phase relation control (relative to Sync trip)
++
++#define HwTVEHUE *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x14)//0xB0240014 // R/W, Active video Color burst phase relation control (relative to color burst)
++
++#define HwTVESAT *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x18)//0xB0240018 // R/W, Active video Chroma gain control relative to color burst gain
++
++#define HwTVECONT *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x1c)//0xB024001C // R/W, Luma gain control
++
++#define HwTVEBRIGHT *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x20)//0xB0240020 // R/W, Luma offset control
++
++#define HwTVEFSC_ADJM *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x24)//0xB0240024 // R/W, MSB of Fsc adjust value
++#define HwTVEFSC_ADJL *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x28)//0xB0240028 // R/W, LSB of Fsc adjust value
++
++#define HwTVECMDC *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x2c)//0xB024002C // R/W, Encoder Mode Control Register C
++ #define HwTVECMDC_CSMDE_EN Hw7 // Composite Sync mode enabled
++ #define HwTVECMDC_CSMDE_DIS ~Hw7 // Composite Sync mode disabled (pin is tri-stated)
++ #define HwTVECMDC_CSMD(X) ((X)*Hw5)
++ #define HwTVECMDC_CSMD_CSYNC HwTVECMDC_CSMD(0) // CSYN pin is Composite sync signal
++ #define HwTVECMDC_CSMD_KEYCLAMP HwTVECMDC_CSMD(1) // CSYN pin is Keyed clamp signal
++ #define HwTVECMDC_CSMD_KEYPULSE HwTVECMDC_CSMD(2) // CSYN pin is Keyed pulse signal
++ #define HwTVECMDC_CSMD_MASK HwTVECMDC_CSMD(3)
++ #define HwTVECMDC_RGBSYNC(X) ((X)*Hw3)
++ #define HwTVECMDC_RGBSYNC_NOSYNC HwTVECMDC_RGBSYNC(0) // Disable RGBSYNC (when output is configured for analog EGB mode)
++ #define HwTVECMDC_RGBSYNC_RGB HwTVECMDC_RGBSYNC(1) // Sync on RGB output signal (when output is configured for analog EGB mode)
++ #define HwTVECMDC_RGBSYNC_G HwTVECMDC_RGBSYNC(2) // Sync on G output signal (when output is configured for analog EGB mode)
++ #define HwTVECMDC_RGBSYNC_MASK HwTVECMDC_RGBSYNC(3)
++
++#define HwTVEDACSEL *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x40)//0xB0240040 // R/W, DAC Output Selection
++ #define HwTVEDACSEL_DACSEL_CODE0 HwZERO // Data output is diabled (output is code '0')
++ #define HwTVEDACSEL_DACSEL_CVBS Hw0 // Data output in CVBS format
++
++#define HwTVEDACPD *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x50)//0xB0240050 // R/W, DAC Power Down
++ #define HwTVEDACPD_PD_EN Hw0 // DAC Power Down Enabled
++ #define HwTVEDACPD_PD_DIS ~Hw0 // DAC Power Down Disabled
++
++#define HwTVEICNTL *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x80)//0xB0240080 // R/W, Sync Control
++ #define HwTVEICNTL_FSIP_ODDHIGH Hw7 // Odd field active high
++ #define HwTVEICNTL_FSIP_ODDLOW HwZERO // Odd field active low
++ #define HwTVEICNTL_VSIP_HIGH Hw6 // V-sync active high
++ #define HwTVEICNTL_VSIP_LOW HwZERO // V-sync active low
++ #define HwTVEICNTL_HSIP_HIGH Hw5 // H-sync active high
++ #define HwTVEICNTL_HSIP_LOW HwZERO // H-sync active low
++ #define HwTVEICNTL_HSVSP_RISING Hw4 // H/V-sync latch enabled at rising edge
++ #define HwTVEICNTL_HVVSP_FALLING HwZERO // H/V-sync latch enabled at falling edge
++ #define HwTVEICNTL_VSMD_START Hw3 // Even/Odd field H/V sync output are aligned to video line start
++ #define HwTVEICNTL_VSMD_MID HwZERO // Even field H/V sync output are aligned to video line midpoint
++ #define HwTVEICNTL_ISYNC(X) ((X)*Hw0)
++ #define HwTVEICNTL_ISYNC_FSI HwTVEICNTL_ISYNC(0) // Alignment input format from FSI pin
++ #define HwTVEICNTL_ISYNC_HVFSI HwTVEICNTL_ISYNC(1) // Alignment input format from HSI,VSI,FSI pin
++ #define HwTVEICNTL_ISYNC_HVSI HwTVEICNTL_ISYNC(2) // Alignment input format from HSI,VSI pin
++ #define HwTVEICNTL_ISYNC_VFSI HwTVEICNTL_ISYNC(3) // Alignment input format from VSI,FSI pin
++ #define HwTVEICNTL_ISYNC_VSI HwTVEICNTL_ISYNC(4) // Alignment input format from VSI pin
++ #define HwTVEICNTL_ISYNC_ESAV_L HwTVEICNTL_ISYNC(5) // Alignment input format from EAV,SAV codes (line by line)
++ #define HwTVEICNTL_ISYNC_ESAV_F HwTVEICNTL_ISYNC(6) // Alignment input format from EAV,SAV codes (frame by frame)
++ #define HwTVEICNTL_ISYNC_FREE HwTVEICNTL_ISYNC(7) // Alignment is free running (Master mode)
++ #define HwTVEICNTL_ISYNC_MASK HwTVEICNTL_ISYNC(7)
++
++#define HwTVEHVOFFST *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x84)//0xB0240084 // R/W, Offset Control
++ #define HwTVEHVOFFST_INSEL(X) ((X)*Hw6)
++ #define HwTVEHVOFFST_INSEL_BW16_27MHZ HwTVEHVOFFST_INSEL(0) // 16bit YUV 4:2:2 sampled at 27MHz
++ #define HwTVEHVOFFST_INSEL_BW16_13P5MHZ HwTVEHVOFFST_INSEL(1) // 16bit YUV 4:2:2 sampled at 13.5MHz
++ #define HwTVEHVOFFST_INSEL_BW8_13P5MHZ HwTVEHVOFFST_INSEL(2) // 8bit YUV 4:2:2 sampled at 13.5MHz
++ #define HwTVEHVOFFST_INSEL_MASK HwTVEHVOFFST_INSEL(3)
++ #define HwTVEHVOFFST_VOFFST_256 Hw3 // Vertical offset bit 8 (Refer to HwTVEVOFFST)
++ #define HwTVEHVOFFST_HOFFST_1024 Hw2 // Horizontal offset bit 10 (Refer to HwTVEHOFFST)
++ #define HwTVEHVOFFST_HOFFST_512 Hw1 // Horizontal offset bit 9 (Refer to HwTVEHOFFST)
++ #define HwTVEHVOFFST_HOFFST_256 Hw0 // Horizontal offset bit 8 (Refer to HwTVEHOFFST)
++
++#define HwTVEHOFFST *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x88)//0xB0240088 // R/W, Horizontal Offset Control (bit [7:0], bit 10~8 is at HwTVEHVOFFST)
++#define HwTVEVOFFST *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x8c)//0xB024008C // R/W, Vertical Offset Control (bit [7:0], bit 8 is at HwTVEHVOFFST)
++
++#define HwTVEHSVSO *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x90)//0xB0240090 // R/W, Sync Output Control
++ #define HwTVEHSVSO_VSOB_256 Hw6 // VSOB bit 8 (Refer to HwVSOB)
++ #define HwTVEHSVSO_HSOB_1024 Hw5 // HSOB bit 10 (Refer to HwHSOB)
++ #define HwTVEHSVSO_HSOB_512 Hw4 // HSOB bit 9 (Refer to HwHSOB)
++ #define HwTVEHSVSO_HSOB_256 Hw3 // HSOB bit 8 (Refer to HwHSOB)
++ #define HwTVEHSVSO_HSOE_1024 Hw2 // HSOE bit 10 (Refer to HwHSOE)
++ #define HwTVEHSVSO_HSOE_512 Hw1 // HSOE bit 9 (Refer to HwHSOE)
++ #define HwTVEHSVSO_HSOE_256 Hw0 // HSOE bit 8 (Refer to HwHSOE)
++
++#define HwTVEHSOE *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x94)//0xB0240094 // R/W, Trailing Edge of Horizontal Sync Control (bit[7:0], bit 10~8 is at HwTVEHSVSO)
++
++#define HwTVEHSOB *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x98)//0xB0240098 // R/W, Leading Edge of Horizontal Sync Control (bit[7:0], bit 10~8 is at HwTVEHSVSO)
++
++#define HwTVEVSOB *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x9c)//0xB024009C // R/W, Leading Edge of Vertical Sync Control (bit[7:0], bit 8 is at HwTVEHSVSO)
++
++#define HwTVEVSOE *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0xa0)//0xB02400A0 // R/W, Trailing Edge of Vertical Sync Control
++ #define HwTVEVSOE_VSOST(X) ((X)*Hw6) // Programs V-sync relative location for Odd/Even Fields.
++ #define HwTVEVSOE_NOVRST_EN Hw5 // No vertical reset on every field
++ #define HwTVEVSOE_NOVRST_NORMAL HwZERO // Normal vertical reset operation (interlaced output timing)
++ #define HwTVEVSOE_VSOE(X) ((X)*Hw0) // Trailing Edge of Vertical Sync Control
++
++#define HwTVEVENCON *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x800)//0xB0240800 // R/W, Connection between LCDC & TVEncoder Control
++ #define HwTVEVENCON_EN_EN Hw0 // Connection between LCDC & TVEncoder Enabled
++ #define HwTVEVENCON_EN_DIS ~Hw0 // Connection between LCDC & TVEncoder Disabled
++
++#define HwTVEVENCIF *(volatile unsigned long *)(((unsigned long)&HwTVE_BASE) + 0x804)//0xB0240804 // R/W, I/F between LCDC & TVEncoder Selection
++ #define HwTVEVENCIF_DAC_EN Hw2 // Enable DAC of TVEncoder
++ #define HwTVEVENCIF_MV_1 Hw1 // reserved
++ #define HwTVEVENCIF_FMT_1 Hw0 // PXDATA[7:0] => CIN[7:0], PXDATA[15:8] => YIN[7:0]
++ #define HwTVEVENCIF_FMT_0 HwZERO // PXDATA[7:0] => YIN[7:0], PXDATA[15:8] => CIN[7:0]
++
++/*****************************************************************************
++*
++* structures
++*
++******************************************************************************/
++
++/*****************************************************************************
++*
++* Variables
++*
++******************************************************************************/
++
++ static unsigned int gTvoutFlag=0;
++ static unsigned int gTvoutFlag_prev=0;
++
++ static unsigned int gTvoutLcdcId = 1;
++
++ unsigned long gRegPCK_LCD;
++ unsigned long gRegLCLKDIV;
++
++ unsigned long gRegLHTIME1;
++ unsigned long gRegLHTIME2;
++
++ unsigned long gRegLVTIME1;
++ unsigned long gRegLVTIME2;
++ unsigned long gRegLVTIME3;
++ unsigned long gRegLVTIME4;
++
++ unsigned long gRegLDS;
++ unsigned long gRegLCTRL;
++
++ unsigned long gRegLI0P;
++ unsigned long gRegLI1P;
++ unsigned long gRegLI2P;
++
++ unsigned long gRegLI0C;
++ unsigned long gRegLI1C;
++ unsigned long gRegLI2C;
++
++ unsigned long gRegLI0S;
++ unsigned long gRegLI1S;
++ unsigned long gRegLI2S;
++
++ static int gHDMIPWRFlag=0;
++
++/*****************************************************************************
++*
++* Functions
++*
++******************************************************************************/
++
++/*****************************************************************************
++* Function Name : tca_tvo_setmode()
++******************************************************************************/
++void tca_tvo_connectlcdc(unsigned int id)
++{
++ PDDICONFIG pDDICfg = (DDICONFIG *)tcc_allocbaseaddress((unsigned int)&HwDDI_CONFIG_BASE);
++
++ if(id)
++ {
++ pDDICfg->NTSCPAL_SEL |= Hw0; // LCDC1 - default
++ gTvoutLcdcId = 1;
++ }
++ else
++ {
++ pDDICfg->NTSCPAL_SEL &= ~Hw0; // LCDC0
++ gTvoutLcdcId= 0;
++ }
++}
++
++
++void tca_tvo_setlclk27mhz(int lcdc_id)
++{
++ const unsigned int dst_lclk = 270000;//540000; // 270000 * ((div))
++ const unsigned int div = 1;
++
++ PLCDC pLCDC_BASE[2] = {(LCDC *)tcc_allocbaseaddress((unsigned int)&HwLCDC0_BASE),
++ (LCDC *)tcc_allocbaseaddress((unsigned int)&HwLCDC1_BASE)};
++ PLCDC pLCDC;
++
++ unsigned int src_pll;
++ unsigned int ret_lclk;
++ unsigned int diff_cur, diff_tmp;
++ int i;
++
++ pLCDC = pLCDC_BASE[lcdc_id];
++
++ src_pll = PCDIRECTPLL0;
++ diff_tmp = dst_lclk*2;
++
++ for(i=PCDIRECTPLL0; i<=PCDIRECTPLL3; i++)
++ {
++ tcc_ckc_setperi(PERI_LCD0+gTvoutLcdcId,ENABLE,dst_lclk,i);
++ ret_lclk = tcc_ckc_getperi(PERI_LCD0+gTvoutLcdcId);
++
++ diff_cur = (ret_lclk>dst_lclk)?(ret_lclk-dst_lclk):(dst_lclk-ret_lclk);
++
++ if(diff_cur <= diff_tmp)
++ {
++ src_pll = i;
++ diff_tmp = diff_cur;
++ }
++
++#ifdef __KERNEL__
++ printk("Check LCLK --> %d, %s%d. pclk(%d)\n", ret_lclk, "PCDIRECTPLL", i, ret_lclk/div);
++#else
++ RETAILMSG(1, (TEXT("Check LCLK --> %d, %s%d. pclk(%d)\r\n"), ret_lclk, TEXT("PCDIRECTPLL"), i, ret_lclk/div));
++#endif
++ }
++
++ tcc_ckc_setperi(PERI_LCD0+gTvoutLcdcId,ENABLE,dst_lclk,PCHDMI);
++ ret_lclk = tcc_ckc_getperi(PERI_LCD0+gTvoutLcdcId);
++
++ pLCDC->LCLKDIV = div/2;
++
++#ifdef __KERNEL__
++ printk("LCDC%d - PCLK[%d] LCLK[%d] , %s%d.\n", gTvoutLcdcId, ret_lclk/div, ret_lclk, "PCDIRECTPLL", src_pll);
++#else
++ RETAILMSG(1, (TEXT("LCDC%d - PCLK[%d] LCLK[%d] , %s%d.\r\n"), gTvoutLcdcId, ret_lclk/div, ret_lclk, TEXT("PCDIRECTPLL"), src_pll));
++#endif
++}
++
++
++/*****************************************************************************
++* Function Name : tca_tvo_setmode()
++******************************************************************************/
++void tca_tvo_setmode(unsigned int type)
++{
++ PPMU lPMU = (PMU *)tcc_allocbaseaddress((unsigned int)&HwPMU_BASE);
++
++ lPMU->PWROFF &= ~Hw0; /* Video DAC */
++
++ switch(type)
++ {
++ case NTSC_M:
++ case NTSC_M_J:
++ default:
++ HwTVECMDA =
++// HwTVECMDA_PWDENC_PD | // [7] Power down mode for entire digital logic of TV encoder
++ HwTVECMDA_FDRST_1 | // [6] Chroma is free running as compared to H-sync
++// HwTVECMDA_FDRST_0 | // [6] Relationship between color burst & H-sync is maintained for video standards
++ HwTVECMDA_FSCSEL_NTSC | // [5:4] Color subcarrier frequency is 3.57954545 MHz for NTSC
++// HwTVECMDA_FSCSEL_PALX | // [5:4] Color subcarrier frequency is 4.43361875 MHz for PAL-B,D,G,H,I,N
++// HwTVECMDA_FSCSEL_PALM | // [5:4] Color subcarrier frequency is 3.57561149 MHz for PAL-M
++// HwTVECMDA_FSCSEL_PALCN | // [5:4] Color subcarrier frequency is 3.58205625 MHz for PAL-combination N
++ HwTVECMDA_PEDESTAL | // [3] Video Output has a pedestal (0 is NTSC-J)
++// HwTVECMDA_PIXEL_SQUARE | // [2] Input data is at square pixel rates.
++ HwTVECMDA_PIXEL_601 | // [2] Input data is at 601 rates.
++// HwTVECMDA_IFMT_625 | // [1] Output data has 625 lines
++ HwTVECMDA_IFMT_525 | // [1] Output data has 525 lines
++// HwTVECMDA_PHALT_PAL | // [0] PAL encoded chroma signal output
++ HwTVECMDA_PHALT_NTSC | // [0] NTSC encoded chroma signal output
++ 0;
++
++ if (type == NTSC_M_J)
++ HwTVECMDA &= ~(HwTVECMDA_PEDESTAL);
++// RETAILMSG(1,(TEXT("[TV Out] Set to NTSC-M Mode\n")));
++ break;
++
++ case NTSC_N:
++ case NTSC_N_J:
++ HwTVECMDA =
++// HwTVECMDA_PWDENC_PD | // [7] Power down mode for entire digital logic of TV encoder
++// HwTVECMDA_FDRST_1 | // [6] Chroma is free running as compared to H-sync
++ HwTVECMDA_FDRST_0 | // [6] Relationship between color burst & H-sync is maintained for video standards
++ HwTVECMDA_FSCSEL_NTSC | // [5:4] Color subcarrier frequency is 3.57954545 MHz for NTSC
++// HwTVECMDA_FSCSEL_PALX | // [5:4] Color subcarrier frequency is 4.43361875 MHz for PAL-B,D,G,H,I,N
++// HwTVECMDA_FSCSEL_PALM | // [5:4] Color subcarrier frequency is 3.57561149 MHz for PAL-M
++// HwTVECMDA_FSCSEL_PALCN | // [5:4] Color subcarrier frequency is 3.58205625 MHz for PAL-combination N
++ HwTVECMDA_PEDESTAL | // [3] Video Output has a pedestal (0 is NTSC-J)
++// HwTVECMDA_PIXEL_SQUARE | // [2] Input data is at square pixel rates.
++ HwTVECMDA_PIXEL_601 | // [2] Input data is at 601 rates.
++ HwTVECMDA_IFMT_625 | // [1] Output data has 625 lines
++// HwTVECMDA_IFMT_525 | // [1] Output data has 525 lines
++// HwTVECMDA_PHALT_PAL | // [0] PAL encoded chroma signal output
++ HwTVECMDA_PHALT_NTSC | // [0] NTSC encoded chroma signal output
++ 0;
++
++ if (type == NTSC_M_J)
++ HwTVECMDA &= ~(HwTVECMDA_PEDESTAL);
++// RETAILMSG(1,(TEXT("[TV Out] Set to NTSC-N Mode\n")));
++ break;
++
++ case NTSC_443:
++ HwTVECMDA =
++// HwTVECMDA_PWDENC_PD | // [7] Power down mode for entire digital logic of TV encoder
++// HwTVECMDA_FDRST_1 | // [6] Chroma is free running as compared to H-sync
++ HwTVECMDA_FDRST_0 | // [6] Relationship between color burst & H-sync is maintained for video standards
++// HwTVECMDA_FSCSEL_NTSC | // [5:4] Color subcarrier frequency is 3.57954545 MHz for NTSC
++ HwTVECMDA_FSCSEL_PALX | // [5:4] Color subcarrier frequency is 4.43361875 MHz for PAL-B,D,G,H,I,N
++// HwTVECMDA_FSCSEL_PALM | // [5:4] Color subcarrier frequency is 3.57561149 MHz for PAL-M
++// HwTVECMDA_FSCSEL_PALCN | // [5:4] Color subcarrier frequency is 3.58205625 MHz for PAL-combination N
++ HwTVECMDA_PEDESTAL | // [3] Video Output has a pedestal (0 is NTSC-J)
++// HwTVECMDA_PIXEL_SQUARE | // [2] Input data is at square pixel rates.
++ HwTVECMDA_PIXEL_601 | // [2] Input data is at 601 rates.
++// HwTVECMDA_IFMT_625 | // [1] Output data has 625 lines
++ HwTVECMDA_IFMT_525 | // [1] Output data has 525 lines
++// HwTVECMDA_PHALT_PAL | // [0] PAL encoded chroma signal output
++ HwTVECMDA_PHALT_NTSC | // [0] NTSC encoded chroma signal output
++ 0;
++// RETAILMSG(1,(TEXT("[TV Out] Set to NTSC 4.43 Mode\n")));
++ break;
++
++ case PAL_M:
++ HwTVECMDA =
++// HwTVECMDA_PWDENC_PD | // [7] Power down mode for entire digital logic of TV encoder
++// HwTVECMDA_FDRST_1 | // [6] Chroma is free running as compared to H-sync
++ HwTVECMDA_FDRST_0 | // [6] Relationship between color burst & H-sync is maintained for video standards
++// HwTVECMDA_FSCSEL_NTSC | // [5:4] Color subcarrier frequency is 3.57954545 MHz for NTSC
++// HwTVECMDA_FSCSEL_PALX | // [5:4] Color subcarrier frequency is 4.43361875 MHz for PAL-B,D,G,H,I,N
++ HwTVECMDA_FSCSEL_PALM | // [5:4] Color subcarrier frequency is 3.57561149 MHz for PAL-M
++// HwTVECMDA_FSCSEL_PALCN | // [5:4] Color subcarrier frequency is 3.58205625 MHz for PAL-combination N
++ HwTVECMDA_PEDESTAL | // [3] Video Output has a pedestal (0 is NTSC-J)
++// HwTVECMDA_PIXEL_SQUARE | // [2] Input data is at square pixel rates.
++ HwTVECMDA_PIXEL_601 | // [2] Input data is at 601 rates.
++// HwTVECMDA_IFMT_625 | // [1] Output data has 625 lines
++ HwTVECMDA_IFMT_525 | // [1] Output data has 525 lines
++ HwTVECMDA_PHALT_PAL | // [0] PAL encoded chroma signal output
++// HwTVECMDA_PHALT_NTSC | // [0] NTSC encoded chroma signal output
++ 0;
++// RETAILMSG(1,(TEXT("[TV Out] Set to PAL-M Mode\n")));
++ break;
++
++ case PAL_N:
++ HwTVECMDA =
++// HwTVECMDA_PWDENC_PD | // [7] Power down mode for entire digital logic of TV encoder
++// HwTVECMDA_FDRST_1 | // [6] Chroma is free running as compared to H-sync
++ HwTVECMDA_FDRST_0 | // [6] Relationship between color burst & H-sync is maintained for video standards
++// HwTVECMDA_FSCSEL_NTSC | // [5:4] Color subcarrier frequency is 3.57954545 MHz for NTSC
++// HwTVECMDA_FSCSEL_PALX | // [5:4] Color subcarrier frequency is 4.43361875 MHz for PAL-B,D,G,H,I,N
++// HwTVECMDA_FSCSEL_PALM | // [5:4] Color subcarrier frequency is 3.57561149 MHz for PAL-M
++ HwTVECMDA_FSCSEL_PALCN | // [5:4] Color subcarrier frequency is 3.58205625 MHz for PAL-combination N
++ HwTVECMDA_PEDESTAL | // [3] Video Output has a pedestal (0 is NTSC-J)
++// HwTVECMDA_PIXEL_SQUARE | // [2] Input data is at square pixel rates.
++ HwTVECMDA_PIXEL_601 | // [2] Input data is at 601 rates.
++ HwTVECMDA_IFMT_625 | // [1] Output data has 625 lines
++// HwTVECMDA_IFMT_525 | // [1] Output data has 525 lines
++ HwTVECMDA_PHALT_PAL | // [0] PAL encoded chroma signal output
++// HwTVECMDA_PHALT_NTSC | // [0] NTSC encoded chroma signal output
++ 0;
++// RETAILMSG(1,(TEXT("[TV Out] Set to PAL-N Mode\n")));
++ break;
++
++ case PAL_B:
++ case PAL_G:
++ case PAL_H:
++ case PAL_I:
++ HwTVECMDA =
++// HwTVECMDA_PWDENC_PD | // [7] Power down mode for entire digital logic of TV encoder
++ HwTVECMDA_FDRST_1 | // [6] Chroma is free running as compared to H-sync
++// HwTVECMDA_FDRST_0 | // [6] Relationship between color burst & H-sync is maintained for video standards
++// HwTVECMDA_FSCSEL_NTSC | // [5:4] Color subcarrier frequency is 3.57954545 MHz for NTSC
++ HwTVECMDA_FSCSEL_PALX | // [5:4] Color subcarrier frequency is 4.43361875 MHz for PAL-B,D,G,H,I,N
++// HwTVECMDA_FSCSEL_PALM | // [5:4] Color subcarrier frequency is 3.57561149 MHz for PAL-M
++// HwTVECMDA_FSCSEL_PALCN | // [5:4] Color subcarrier frequency is 3.58205625 MHz for PAL-combination N
++// HwTVECMDA_PEDESTAL | // [3] Video Output has a pedestal (0 is NTSC-J)
++// HwTVECMDA_PIXEL_SQUARE | // [2] Input data is at square pixel rates.
++ HwTVECMDA_PIXEL_601 | // [2] Input data is at 601 rates.
++ HwTVECMDA_IFMT_625 | // [1] Output data has 625 lines
++// HwTVECMDA_IFMT_525 | // [1] Output data has 525 lines
++ HwTVECMDA_PHALT_PAL | // [0] PAL encoded chroma signal output
++// HwTVECMDA_PHALT_NTSC | // [0] NTSC encoded chroma signal output
++ 0;
++// RETAILMSG(1,(TEXT("[TV Out] Set to PAL_B/G/H/I Mode\n")));
++ break;
++
++ case PSEUDO_PAL:
++ HwTVECMDA =
++// HwTVECMDA_PWDENC_PD | // [7] Power down mode for entire digital logic of TV encoder
++// HwTVECMDA_FDRST_1 | // [6] Chroma is free running as compared to H-sync
++ HwTVECMDA_FDRST_0 | // [6] Relationship between color burst & H-sync is maintained for video standards
++// HwTVECMDA_FSCSEL_NTSC | // [5:4] Color subcarrier frequency is 3.57954545 MHz for NTSC
++ HwTVECMDA_FSCSEL_PALX | // [5:4] Color subcarrier frequency is 4.43361875 MHz for PAL-B,D,G,H,I,N
++// HwTVECMDA_FSCSEL_PALM | // [5:4] Color subcarrier frequency is 3.57561149 MHz for PAL-M
++// HwTVECMDA_FSCSEL_PALCN | // [5:4] Color subcarrier frequency is 3.58205625 MHz for PAL-combination N
++ HwTVECMDA_PEDESTAL | // [3] Video Output has a pedestal (0 is NTSC-J)
++// HwTVECMDA_PIXEL_SQUARE | // [2] Input data is at square pixel rates.
++ HwTVECMDA_PIXEL_601 | // [2] Input data is at 601 rates.
++// HwTVECMDA_IFMT_625 | // [1] Output data has 625 lines
++ HwTVECMDA_IFMT_525 | // [1] Output data has 525 lines
++ HwTVECMDA_PHALT_PAL | // [0] PAL encoded chroma signal output
++// HwTVECMDA_PHALT_NTSC | // [0] NTSC encoded chroma signal output
++ 0;
++// RETAILMSG(1,(TEXT("[TV Out] Set to Pseudo PAL Mode\n")));
++ break;
++
++ case PSEUDO_NTSC:
++ HwTVECMDA =
++// HwTVECMDA_PWDENC_PD | // [7] Power down mode for entire digital logic of TV encoder
++// HwTVECMDA_FDRST_1 | // [6] Chroma is free running as compared to H-sync
++ HwTVECMDA_FDRST_0 | // [6] Relationship between color burst & H-sync is maintained for video standards
++ HwTVECMDA_FSCSEL_NTSC | // [5:4] Color subcarrier frequency is 3.57954545 MHz for NTSC
++// HwTVECMDA_FSCSEL_PALX | // [5:4] Color subcarrier frequency is 4.43361875 MHz for PAL-B,D,G,H,I,N
++// HwTVECMDA_FSCSEL_PALM | // [5:4] Color subcarrier frequency is 3.57561149 MHz for PAL-M
++// HwTVECMDA_FSCSEL_PALCN | // [5:4] Color subcarrier frequency is 3.58205625 MHz for PAL-combination N
++ HwTVECMDA_PEDESTAL | // [3] Video Output has a pedestal (0 is NTSC-J)
++// HwTVECMDA_PIXEL_SQUARE | // [2] Input data is at square pixel rates.
++ HwTVECMDA_PIXEL_601 | // [2] Input data is at 601 rates.
++ HwTVECMDA_IFMT_625 | // [1] Output data has 625 lines
++// HwTVECMDA_IFMT_525 | // [1] Output data has 525 lines
++// HwTVECMDA_PHALT_PAL | // [0] PAL encoded chroma signal output
++ HwTVECMDA_PHALT_NTSC | // [0] NTSC encoded chroma signal output
++ 0;
++// RETAILMSG(0,(TEXT("[TV Out] Set to Pseudo NTSC Mode\n")));
++ break;
++ }
++
++ HwTVECMDB =
++// HwTVECMDB_YBIBLK_BLACK | // [4] Video data is forced to Black level for Vertical non VBI processed lines.
++ HwTVECMDB_YBIBLK_BYPASS | // [4] Input data is passed through forn non VBI processed lines.
++ HwTVECMDB_CBW_LOW | // [3:2] Low Chroma band-width
++// HwTVECMDB_CBW_MEDIUM | // [3:2] Medium Chroma band-width
++// HwTVECMDB_CBW_HIGH | // [3:2] High Chroma band-width
++ HwTVECMDB_YBW_LOW | // [1:0] Low Luma band-width
++// HwTVECMDB_YBW_MEDIUM | // [1:0] Medium Luma band-width
++// HwTVECMDB_YBW_HIGH | // [1:0] High Luma band-width
++ 0;
++
++ //Set DACSEL Register
++ HwTVEDACSEL = 1; //DACSEL0 - CVBS output
++
++ HwTVEICNTL =
++// HwTVEICNTL_FSIP_ODDHIGH | // [7] Odd field active high
++ HwTVEICNTL_VSIP_HIGH | // [6] V-sync active high
++// HwTVEICNTL_HSIP_HIGH | // [5] H-sync active high
++ HwTVEICNTL_HSVSP_RISING | // [4] H/V-sync latch enabled at rising edge
++// HwTVEICNTL_VSMD_START | // [3] Even/Odd field H/V sync output are aligned to video line start
++// HwTVEICNTL_ISYNC_FSI | // [2:0] Alignment input format from FSI pin
++// HwTVEICNTL_ISYNC_HVFSI | // [2:0] Alignment input format from HSI,VSI,FSI pin
++ HwTVEICNTL_ISYNC_HVSI | // [2:0] Alignment input format from HSI,VSI pin
++// HwTVEICNTL_ISYNC_VFSI | // [2:0] Alignment input format from VSI,FSI pin
++// HwTVEICNTL_ISYNC_VSI | // [2:0] Alignment input format from VSI pin
++// HwTVEICNTL_ISYNC_ESAV_L | // [2:0] Alignment input format from EAV,SAV codes (line by line)
++// HwTVEICNTL_ISYNC_ESAV_F | // [2:0] Alignment input format from EAV,SAV codes (frame by frame)
++// HwTVEICNTL_ISYNC_FREE | // [2:0] Alignment is free running (Master mode)
++ 0;
++
++ HwTVEHVOFFST =
++// HwTVEHVOFFST_INSEL_BW16_27MHZ | // [7:6] 16bit YUV 4:2:2 sampled at 27MHz
++// HwTVEHVOFFST_INSEL_BW16_13P5MHZ | // [7:6] 16bit YUV 4:2:2 sampled at 13.5MHz
++ HwTVEHVOFFST_INSEL_BW8_13P5MHZ | // [7:6] 8bit YUV 4:2:2 sampled at 13.5MHz
++ 0;
++
++ HwTVEHOFFST = 0; //48;
++ HwTVEVOFFST = 1; // 8;
++ HwTVEHSVSO = 0;
++ HwTVEHSOB = 0;
++ HwTVEHSOE = 0;
++ HwTVEVSOB = 0;
++ HwTVEVSOE =
++ HwTVEVSOE_VSOST(0) | // [7:6] Programs V-sync relative location for Odd/Even Fields.
++// HwTVEVSOE_NOVRST_EN | // [5] No vertical reset on every field
++ HwTVEVSOE_NOVRST_NORMAL | // [5] Normal vertical reset operation (interlaced output timing)
++ HwTVEVSOE_VSOE(0) | // [4:0] Trailing Edge of Vertical Sync Control
++ 0;
++
++ //Set VENCIF Register
++ BITSET(HwTVEVENCIF, HwTVEVENCIF_FMT_1);
++ //HwTVEVENCIF = 1;
++
++}
++
++
++/*****************************************************************************
++* Function Name : tca_tvo_setlcd2tv()
++******************************************************************************/
++void tca_tvo_setlcd2tv(unsigned int type)
++{
++ PLCDC pLCDC_BASE[2] = {(LCDC *)tcc_allocbaseaddress((unsigned int)&HwLCDC0_BASE),
++ (LCDC *)tcc_allocbaseaddress((unsigned int)&HwLCDC1_BASE)};
++ PLCDC pLCDC;
++
++ PCKC pCKC = (CKC *)tcc_allocbaseaddress((unsigned int)&HwCLK_BASE);
++
++ unsigned int TV_HSIZE, TV_VSIZE = 0;
++ unsigned int TV_HPW, TV_HBP, TV_HFP;
++ unsigned int TV_VPW0, TV_VBP0, TV_VFP0;
++ unsigned int TV_VPW1, TV_VBP1, TV_VFP1;
++
++ pLCDC = pLCDC_BASE[gTvoutLcdcId];
++
++
++ // LCD_DISP Off
++ gpio_direction_output(GPIO_LCD_PWR_EN, 0);
++
++ //todo: Backlight off
++ gpio_direction_output(GPIO_LCD_BACKLIGHT_EN, 0);
++
++ pLCDC->LCTRL &= (~Hw0); // LCDC Disable
++
++ if(!gTvoutFlag)
++ {
++ if(gTvoutLcdcId)
++ gRegPCK_LCD = pCKC->PCLK_LCD1;
++ else
++ gRegPCK_LCD = pCKC->PCLK_LCD0;
++
++ gRegLCLKDIV = pLCDC->LCLKDIV;
++
++ gRegLHTIME1 = pLCDC->LHTIME1;
++ gRegLHTIME2 = pLCDC->LHTIME2;
++
++ gRegLVTIME1 = pLCDC->LVTIME1;
++ gRegLVTIME2 = pLCDC->LVTIME2;
++ gRegLVTIME3 = pLCDC->LVTIME3;
++ gRegLVTIME4 = pLCDC->LVTIME4;
++
++ gRegLDS = pLCDC->LDS;
++ gRegLCTRL = pLCDC->LCTRL;
++
++ gRegLI0P = pLCDC->LI0P;
++ if(gTvoutLcdcId)
++ {
++ gRegLI1P = pLCDC->LI1P;
++ gRegLI2P = pLCDC->LI2P;
++ }
++
++ gRegLI0C = pLCDC->LI0C;
++ if(gTvoutLcdcId)
++ {
++ gRegLI1C = pLCDC->LI1C;
++ gRegLI2C = pLCDC->LI2C;
++ }
++
++ gRegLI0S = pLCDC->LI0S;
++ if(gTvoutLcdcId)
++ {
++ gRegLI1S = pLCDC->LI1S;
++ gRegLI2S = pLCDC->LI2S;
++ }
++
++ gTvoutFlag = 1;
++ }
++
++ while(pLCDC->LSTATUS & Hw30) // BUSY
++ {
++#ifdef __KERNEL__
++ udelay(1000*1);
++#else
++ Sleep(1);
++#endif
++ }
++
++ if (gHDMIPWRFlag == 0)
++ {
++ PPMU pPMU = (PMU *)tcc_allocbaseaddress((unsigned int)&HwPMU_BASE);
++ BITCLR(pPMU->PWROFF, Hw1); /*HD[1]*/
++
++ gHDMIPWRFlag = 1;
++ }
++
++// tcc_ckc_setperi(PERI_LCD0+gTvoutLcdcId,ENABLE,270000,PCHDMI);
++// pLCDC->LCLKDIV = 0;
++
++ tca_tvo_setlclk27mhz(gTvoutLcdcId);
++
++ switch(type)
++ {
++ case NTSC_M:
++ case NTSC_M_J:
++ case PAL_M:
++ case NTSC_443:
++ case PSEUDO_PAL:
++ TV_HSIZE = 720; TV_VSIZE = 480;
++ TV_HPW = 212; TV_HBP = 32; TV_HFP = 32;
++ TV_VPW0 = 1; TV_VBP0 = 37; TV_VFP0 = 7;
++ TV_VPW1 = 1; TV_VBP1 = 38; TV_VFP1 = 6;
++
++ pLCDC->LHTIME1 = ((TV_HPW-1) << 16) | ((TV_HSIZE*2) - 1);
++ pLCDC->LHTIME2 = ((TV_HBP-1) << 16) | (TV_HFP-1);
++
++ pLCDC->LVTIME1 = ((TV_VPW0-1) << 16) | (TV_VSIZE - 1);
++ pLCDC->LVTIME2 = ((TV_VBP0-1) << 16) | (TV_VFP0-1);
++ pLCDC->LVTIME3 = ((TV_VPW1-1) << 16) | (TV_VSIZE - 1);
++ pLCDC->LVTIME4 = ((TV_VBP1-1) << 16) | (TV_VFP1-1);
++ break;
++
++ case NTSC_N:
++ case NTSC_N_J:
++ case PAL_N:
++ case PAL_B:
++ case PAL_G:
++ case PAL_H:
++ case PAL_I:
++ case PSEUDO_NTSC:
++ TV_HSIZE = 720; TV_VSIZE = 576;
++ // TV_HPW = 280; TV_HBP = 2; TV_HFP = 6;
++ TV_HPW = 128; TV_HBP = 138; TV_HFP = 22;
++ TV_VPW0 = 1; TV_VBP0 = 43; TV_VFP0 = 5;
++ TV_VPW1 = 1; TV_VBP1 = 44; TV_VFP1 = 4;
++
++ pLCDC->LHTIME1 = ((TV_HPW-1) << 16) | ((TV_HSIZE*2) - 1);
++ pLCDC->LHTIME2 = ((TV_HBP-1) << 16) | (TV_HFP-1);
++
++ pLCDC->LVTIME1 = ((TV_VPW0-1) << 16) | (TV_VSIZE - 1);
++ pLCDC->LVTIME2 = ((TV_VBP0-1) << 16) | (TV_VFP0-1);
++ pLCDC->LVTIME3 = ((TV_VPW1-1) << 16) | (TV_VSIZE - 1);
++ pLCDC->LVTIME4 = ((TV_VBP1-1) << 16) | (TV_VFP1-1);
++
++ break;
++ }
++
++ pLCDC->LDS = (TV_VSIZE<< 16) | TV_HSIZE;
++
++ #if (1)
++ if(gTvoutFlag_prev == 0)
++ {
++ unsigned int IMGx_HSIZE[3], IMGx_VSIZE[3];
++ unsigned int IMGx_POSX[3], IMGx_POSY[3];
++ unsigned int TMP_POSX=0, TMP_POSY=0;
++
++ memset(IMGx_HSIZE, 0, sizeof(unsigned int)*3);
++ memset(IMGx_VSIZE, 0, sizeof(unsigned int)*3);
++ memset(IMGx_POSX, 0, sizeof(unsigned int)*3);
++ memset(IMGx_POSY, 0, sizeof(unsigned int)*3);
++
++ if(pLCDC->LI0C & Hw28) //IMG0 EN
++ {
++ IMGx_HSIZE[0] = (unsigned int)(pLCDC->LI0S & 0x0fff);
++ IMGx_VSIZE[0] = (unsigned int)((pLCDC->LI0S & 0x0fff0000) >> 16);
++
++ TMP_POSX = (unsigned int)(pLCDC->LI0P & 0x0fff);
++ TMP_POSY = (unsigned int)((pLCDC->LI0P & 0x0fff0000) >> 16);
++
++ if(IMGx_HSIZE[0] < TV_HSIZE)
++ {
++ IMGx_POSX[0] = (TV_HSIZE - IMGx_HSIZE[0]) >> 1;
++ }
++ if(IMGx_VSIZE[0] < TV_VSIZE)
++ {
++ IMGx_POSY[0] = (TV_VSIZE - IMGx_VSIZE[0]) >> 2;
++ }
++
++ pLCDC->LI0P = ((IMGx_POSY[0]+TMP_POSY) << 16) | (IMGx_POSX[0]+TMP_POSX);
++ // pLCDC->LI0C |= 0x80000000;
++
++ pLCDC->LI0S = TV_VSIZE << 16 | TV_HSIZE;
++
++ }
++ pLCDC->LI0C |= 0x80000000;
++
++ if(gTvoutLcdcId)
++ {
++ if(pLCDC->LI1C & Hw28) //IMG1 EN
++ {
++ IMGx_HSIZE[1] = (unsigned int)(pLCDC->LI1S & 0x0fff);
++ IMGx_VSIZE[1] = (unsigned int)((pLCDC->LI1S & 0x0fff0000) >> 16);
++
++ TMP_POSX = (unsigned int)(pLCDC->LI1P & 0x0fff);
++ TMP_POSY = (unsigned int)((pLCDC->LI1P & 0x0fff0000) >> 16);
++
++ if(IMGx_HSIZE[1] < TV_HSIZE)
++ {
++ IMGx_POSX[1] = (TV_HSIZE - IMGx_HSIZE[1]) >> 1;
++ }
++ if(IMGx_VSIZE[1] < TV_VSIZE)
++ {
++ IMGx_POSY[1] = (TV_VSIZE - IMGx_VSIZE[1]) >> 2;
++ }
++
++ pLCDC->LI1P = ((IMGx_POSY[1]+TMP_POSY) << 16) | (IMGx_POSX[1]+TMP_POSX);
++ // pLCDC->LI1C |= 0x80000000;
++
++ pLCDC->LI1S = TV_VSIZE << 16 | TV_HSIZE;
++ }
++ if(pLCDC->LI2C & Hw28) //IMG2 EN
++ {
++ IMGx_HSIZE[2] = (unsigned int)(pLCDC->LI2S & 0x0fff);
++ IMGx_VSIZE[2] = (unsigned int)((pLCDC->LI2S & 0x0fff0000) >> 16);
++
++ TMP_POSX = (unsigned int)(pLCDC->LI2P & 0x0fff);
++ TMP_POSY = (unsigned int)((pLCDC->LI2P & 0x0fff0000) >> 16);
++
++ if(IMGx_HSIZE[2] < TV_HSIZE)
++ {
++ IMGx_POSX[2] = (TV_HSIZE - IMGx_HSIZE[2]) >> 1;
++ }
++ if(IMGx_VSIZE[2] < TV_VSIZE)
++ {
++ IMGx_POSY[2] = (TV_VSIZE - IMGx_VSIZE[2]) >> 2;
++ }
++
++ pLCDC->LI2P = ((IMGx_POSY[2]+TMP_POSY) << 16) | (IMGx_POSX[2]+TMP_POSX);
++ // pLCDC->LI2C |= 0x80000000;
++
++ pLCDC->LI2S = TV_VSIZE << 16 | TV_HSIZE;
++ }
++
++ pLCDC->LI1C |= 0x80000000;
++ pLCDC->LI2C |= 0x80000000;
++ }
++
++ gTvoutFlag_prev = 1;
++ }
++ #endif
++
++ pLCDC->LCTRL = (pLCDC->LCTRL & 0xFFF0001E)
++ | (0xf & 0x6) << 16 // PXDW=6
++ | (0xf & 0xf) << 12 // ID=1, IV=1, IH=1, IP=1
++ | (0x1 & 0x1) << 10 // R2Y=1
++ | (0x1 & 0x0) << 9 // DP=0
++ | (0x1 & 0x0) << 8 // NI=0
++ | (0x7 & 0x4) << 5 // TV=1, TFT=0, STN=0
++ | (0x1 & 0x1) << 0 // LEN=1
++ | 0;
++
++}
++
++
++/*****************************************************************************
++* Function Name : tca_tvo_settv2lcd()
++******************************************************************************/
++void tca_tvo_settv2lcd(void)
++{
++ PLCDC pLCDC_BASE[2] = {(LCDC *)tcc_allocbaseaddress((unsigned int)&HwLCDC0_BASE),
++ (LCDC *)tcc_allocbaseaddress((unsigned int)&HwLCDC1_BASE)};
++ PLCDC pLCDC;
++
++ PCKC pCKC = (CKC *)tcc_allocbaseaddress((unsigned int)&HwCLK_BASE);
++
++ pLCDC = pLCDC_BASE[gTvoutLcdcId];
++
++ // LCD_DISP On
++ gpio_direction_output(GPIO_LCD_PWR_EN, 1);
++
++ pLCDC->LCTRL &= (~Hw0); // LCDC Disable
++
++ while(pLCDC->LSTATUS & Hw30) // BUSY
++ {
++#ifdef __KERNEL__
++ udelay(1000*1);
++#else
++ Sleep(1);
++#endif
++ }
++
++ if(gTvoutLcdcId)
++ pCKC->PCLK_LCD1 = gRegPCK_LCD;
++ else
++ pCKC->PCLK_LCD0 = gRegPCK_LCD;
++
++ pLCDC->LCLKDIV = gRegLCLKDIV;
++
++ pLCDC->LHTIME1 = gRegLHTIME1;
++ pLCDC->LHTIME2 = gRegLHTIME2;
++
++ pLCDC->LVTIME1 = gRegLVTIME1;
++ pLCDC->LVTIME2 = gRegLVTIME2;
++ pLCDC->LVTIME3 = gRegLVTIME3;
++ pLCDC->LVTIME4 = gRegLVTIME4;
++
++ pLCDC->LDS = gRegLDS;
++ pLCDC->LI0P = gRegLI0P;
++ if(gTvoutLcdcId)
++ {
++ pLCDC->LI1P = gRegLI1P;
++ pLCDC->LI2P = gRegLI2P;
++ }
++
++ pLCDC->LI0C = gRegLI0C;
++ if(gTvoutLcdcId)
++ {
++ pLCDC->LI1C = gRegLI1C;
++ /* When the video ended, and the user unplug the TV-out cable, should disable the Chroma-Keying Function in order to prevent the last video image left on the LCD screen */
++ if((pLCDC->LI2C & (1<<29)) == 0)
++ pLCDC->LI2C = gRegLI2C & ~(1<<29);
++ else
++ pLCDC->LI2C = gRegLI2C;
++ }
++
++ pLCDC->LI0S = gRegLI0S;
++ if(gTvoutLcdcId)
++ {
++ pLCDC->LI1S = gRegLI1S;
++ pLCDC->LI2S = gRegLI2S;
++ }
++
++
++ pLCDC->LCTRL = gRegLCTRL | Hw0; // Restore LCD Control and Enable LCD
++
++#if (0)
++{
++ PPMU pPMU = (PMU *)tcc_allocbaseaddress((unsigned int)&HwPMU_BASE, sizeof(PMU));
++ BITSET(pPMU->PWROFF, Hw1); /*HD[1]*/
++}
++#endif
++
++ // todo: Backlight On
++ gpio_direction_output(GPIO_LCD_BACKLIGHT_EN, 1);
++
++ gTvoutFlag = 0;
++ gTvoutFlag_prev = 0;
++}
++
++
++/*****************************************************************************
++* Function Name : tca_tvo_enable()
++******************************************************************************/
++void tca_tvo_enable(unsigned int onoff)
++{
++ PPMU lPMU = (PMU *)tcc_allocbaseaddress((unsigned int)&HwPMU_BASE);
++
++ if (onoff == 1)
++ {
++ lPMU->PWROFF &= ~Hw0; /* Video DAC */
++
++ HwTVEVENCON = 1;
++ HwTVEDACPD = 0; // Normal Operation
++ HwTVECMDA &=~(HwTVECMDA_PWDENC_PD); // Normal Operation
++ }
++ else
++ {
++ HwTVEVENCON = 0;
++ HwTVEDACPD = 1; // Power Down
++ HwTVECMDA |= (HwTVECMDA_PWDENC_PD); // Power Down
++
++ lPMU->PWROFF &= ~Hw0; /* Video DAC */
++ lPMU->PWROFF |= Hw0; /* Video DAC */
++ }
++}
++
+diff --git a/drivers/video/tca_tvout.h b/drivers/video/tca_tvout.h
+new file mode 100644
+index 0000000..a513188
+--- /dev/null
++++ b/drivers/video/tca_tvout.h
+@@ -0,0 +1,84 @@
++
++/****************************************************************************
++ * FileName : tca_tvo.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#ifndef __TCA_TVO_H__
++#define __TCA_TVO_H__
++
++/*****************************************************************************
++*
++* Defines
++*
++******************************************************************************/
++
++#define NTSC_M 0x0000
++#define NTSC_M_J 0x0001
++#define NTSC_N 0x0010
++#define NTSC_N_J 0x0011
++#define NTSC_443 0x0020
++#define PAL_M 0x0100
++#define PAL_N 0x0110
++#define PAL_B 0x0120
++#define PAL_G 0x0130
++#define PAL_H 0x0140
++#define PAL_I 0x0150
++#define PSEUDO_NTSC 0x1000
++#define PSEUDO_PAL 0x1010
++
++/*****************************************************************************
++*
++* Enum
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* Type Defines
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* Structures
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* External Variables
++*
++******************************************************************************/
++
++
++/*****************************************************************************
++*
++* External Functions
++*
++******************************************************************************/
++#ifdef __cplusplus
++extern
++"C" {
++#endif
++
++void tca_tvo_connectlcdc(unsigned int id);
++void tca_tvo_setmode(unsigned int type);
++void tca_tvo_setlcd2tv(unsigned int type);
++void tca_tvo_settv2lcd(void);
++void tca_tvo_enable(unsigned int onoff);
++
++#ifdef __cplusplus
++ }
++#endif
++
++#endif //__TCA_TVO_H__
++
+diff --git a/drivers/video/tcc-lcd.h b/drivers/video/tcc-lcd.h
+new file mode 100644
+index 0000000..1538552
+--- /dev/null
++++ b/drivers/video/tcc-lcd.h
+@@ -0,0 +1,131 @@
++/***************************************************************************************
++* FileName : lcd.h
++* Description : lcd Functions
++****************************************************************************************
++*
++* TCC Board Support Package
++* Copyright (c) Telechips, Inc.
++* ALL RIGHTS RESERVED
++*
++****************************************************************************************/
++#ifndef __LCD_H__
++#define __LCD_H__
++
++
++// #define DEMO_LOADSHOW_LVDS // LCDC1: fb0-LVDS, fb1-LVDS, fb2-LVDS
++// #define DEMO_LOADSHOW_LCD_LVDS // LCDC1: fb0-LVDS, fb1-LVDS / LCDC0: fb2-LCD
++// #define DEMO_LOADSHOW_LCD_HDMI // LCDC1: fb0-HDMI, fb1-HDMI / LCDC0: fb2-LCD
++// #define DEMO_LOADSHOW_LCD_LVDSHDMI // LCDC0: fb0-LVDS|HDMI / LCDC1: fb1-LCD, fb2-LCD
++
++
++#if defined(DEMO_LOADSHOW_LVDS) || defined(DEMO_LOADSHOW_LCD_LVDS) || defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++
++// #define USE_LVDS_1024_768 // disable - HT121WX2-103 12"1 Color TFT LCD (LVDS)
++ // enable - CLAA104XA01CW 10"4 Color TFT LCD (LVDS)
++
++
++ #define USE_LVDS
++#endif
++
++#if !defined(DEMO_LOADSHOW_LVDS)
++ #define USE_LCD
++#endif
++
++
++typedef struct {
++ unsigned int res_width;
++ unsigned int res_height;
++
++ unsigned int devide;
++
++ unsigned int vpw;
++ unsigned int vbp;
++ unsigned int vfp;
++
++ unsigned int hpw;
++ unsigned int hbp;
++ unsigned int hfp;
++
++ unsigned int pwdx; // 0xC : 24Bit(888)
++ // 0x5 : 18Bit(565)
++
++} lcd_cfg_t;
++
++#ifdef CONFIG_LCD_4
++static lcd_cfg_t lcd_cfg[3] =
++{
++////// W H DIV VPW VBP VFP HPW HBP HFP PWDX //
++{800, 480, 2, 1, 34, 10, 1, 215, 40, 0xC},
++// [CLAA104XA01CW 10"4 Color TFT LCD (LVDS)]
++ { 1024, 768, 1, 1, 1, 36, 1, 1, 318, 0xC },
++
++// [HT121WX2-103 12"1 Color TFT LCD (LVDS)]
++ { 1280, 800, 1, 1, 3, 20, 1, 10, 150, 0xC },
++};
++#else
++static lcd_cfg_t lcd_cfg[3] =
++{
++////// W H DIV VPW VBP VFP HPW HBP HFP PWDX //
++{800, 480, 3, 10, 5, 3, 3, 20, 1, 0xC},
++// [CLAA104XA01CW 10"4 Color TFT LCD (LVDS)]
++ { 1024, 768, 1, 1, 1, 36, 1, 1, 318, 0xC },
++
++// [HT121WX2-103 12"1 Color TFT LCD (LVDS)]
++ { 1280, 800, 1, 1, 3, 20, 1, 10, 150, 0xC },
++};
++#endif
++
++#if !defined(USED_IN_KERNEL)
++
++/* Boot-logo Color depth */
++#if (0)
++#define DISP_SRC_32BPP // Enable : RGB888 (32bpp)
++ // Disable: RGB565 (16bpp)
++#endif
++
++#if defined(DEMO_LOADSHOW_LVDS)
++#define DISP_WIDTH 1280
++#define DISP_HEIGHT 800
++#else
++#define DISP_WIDTH 800
++#define DISP_HEIGHT 480
++#endif
++
++
++#if defined(DEMO_LOADSHOW_LVDS) && defined(USE_LVDS_1024_768)
++#undef DISP_WIDTH
++#undef DISP_HEIGHT
++#define DISP_WIDTH 1024
++#define DISP_HEIGHT 768
++#endif
++
++
++#define DISP_MEM_SIZE 0x300000 // 3MB
++
++#define STACK_SIZE_MAX 0x300000
++#define DISP_MEM_PHYBASE ((BSS_OFFSET - STACK_SIZE_MAX) - DISP_MEM_SIZE)
++
++
++#if defined(DISP_SRC_32BPP)
++#define DISP_BYTESPERPIXEL 4
++#else
++#define DISP_BYTESPERPIXEL 2
++#endif
++
++
++#define DISP_BOOTIMG0_BASE_ADDR (DISP_MEM_PHYBASE)
++#define DISP_BOOTIMG0_SIZE_MAX (0x180000) // 1.5MB
++
++#define DISP_BOOTIMG1_BASE_ADDR (DISP_BOOTIMG0_BASE_ADDR + DISP_BOOTIMG0_SIZE_MAX)
++#define DISP_BOOTIMG1_SIZE_MAX (0x180000) // 1.5MB
++
++//
++#define IMAGE1_START (DISP_MEM_PHYBASE)
++
++
++void disp_init(void);
++
++#endif //#if !defined(USED_IN_KERNEL)
++
++#endif /*__LCD_H__*/
++
+diff --git a/drivers/video/tccfb.c b/drivers/video/tccfb.c
+new file mode 100644
+index 0000000..6a48843
+--- /dev/null
++++ b/drivers/video/tccfb.c
+@@ -0,0 +1,3069 @@
++/*
++ * linux/drivers/video/tccfb.c
++ *
++ * Based on: Based on s3c2410fb.c, sa1100fb.c and others
++ * Author: <linux@telechips.com>
++ * Created: June 10, 2008
++ * Description: TCC LCD Controller Frame Buffer Driver
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/fb.h>
++#include <linux/init.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/workqueue.h>
++#include <linux/wait.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <hhtech_gpio.h>
++#include <mach/gpio.h>
++
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/div64.h>
++#include <asm/mach/map.h>
++#ifdef CONFIG_PM
++#include <linux/pm.h>
++#include "tca_backlight.h"
++#endif
++
++#include <bsp.h>
++#include <mach/tca_ckc.h>
++#include <mach/tcc_pca953x.h>
++#include <mach/memory.h>
++
++#include "tccfb.h"
++#include <linux/tccfb_ioctl.h>
++//#include "tcc_lcdc_info.h"
++//#include "tca_lcdc.h"
++
++//#include "tcboot_lcd.h"
++
++#define USED_IN_KERNEL
++#include "tcc-lcd.h"
++
++
++#define TV_OUT_INCLUDE
++
++#define TCC_FB_DOUBLE_
++
++#define MAIN_LCDC_ID 1 // 0: LCDC0, 1: LCDC1
++
++#if 1
++extern void tca_lcdc_getimgchfmt(int id, unsigned int imgch, unsigned int * out_fmt);
++extern void tca_lcdc_setimgchenable(int id, unsigned int ch, unsigned int flag);
++extern void tca_lcdc_setlayeralphablendingenable(int id, unsigned int imgch, unsigned int flag);
++extern void tca_lcdc_setlayeralphavalue(int id, unsigned int imgch, unsigned char alpha);
++extern void tca_lcdc_setalphaselection(int id, unsigned int imgch, unsigned int asel);
++extern void tca_lcdc_setlayerchromakeyenable(int id, unsigned int imgch, unsigned int flag);
++extern void tca_lcdc_setlayerchromakeyvalue(int id, unsigned int imgch, unsigned int ry, unsigned int gu, unsigned int bv);
++extern void tca_lcdc_setlayerchromakeymask(int id, unsigned int imgch, unsigned int mry, unsigned int mgu, unsigned int mbv);
++extern void tca_lcdc_setimgchfmt(int id, unsigned int imgch, unsigned int fmt);
++extern void tca_lcdc_setimgchbase(int id, unsigned int imgch, unsigned int base0, unsigned int base1, unsigned int base2);
++extern void tca_lcdc_getimgchbase(int id, unsigned int imgch, unsigned int * out_base0, unsigned int * out_base1, unsigned int * out_base2);
++extern void tca_lcdc_setimgchOffsetInfo(int id, unsigned int imgch, unsigned int offset0, unsigned int offset1);
++extern void tca_lcdc_setaddroffset(int id, unsigned int imgch, unsigned int imgwidth, unsigned int fmt);
++extern void tca_lcdc_setimgchwindow(int id, unsigned int imgch, unsigned int sx, unsigned int sy, unsigned int w, unsigned int h);
++extern void tca_lcdc_setr2yconvopt(int id, unsigned int conv_opt);
++extern void tca_lcdc_getr2yconvopt(int id, unsigned int *conv_opt_out);
++extern void tca_lcdc_setimgy2rconvopt(int id, unsigned int imgch, unsigned int conv_opt);
++extern void tca_lcdc_getimgy2rconvopt(int id, unsigned int imgch, unsigned int *conv_opt_out);
++extern void tca_lcdc_setcolorenhancement(int id, unsigned int hue, unsigned int bright, unsigned int cont);
++extern void tca_lcdc_getcolorenhancement(int id, unsigned int *hue, unsigned int *bright, unsigned int *cont);
++extern void tca_lcdc_setimgenhancement(int id, unsigned int imgch, unsigned int hue, unsigned int bright, unsigned int cont);
++extern void tca_lcdc_getimgenhancement(int id, unsigned int imgch, unsigned int *hue, unsigned int *bright, unsigned int *cont);
++
++#ifdef TV_OUT_INCLUDE
++extern void tca_tvo_connectlcdc(unsigned int id);
++extern void tca_tvo_setmode(unsigned int type);
++extern void tca_tvo_setlcd2tv(unsigned int type);
++extern void tca_tvo_settv2lcd(void);
++extern void tca_tvo_enable(unsigned int onoff);
++#endif
++#endif
++
++/* Debugging stuff */
++//#ifdef CONFIG_FB_DEBUG
++#if 0
++static int debug = 1;
++#else
++static int debug = 0;
++#endif
++#define dprintk(msg...) if (debug) { printk( "tccfb: " msg); }
++
++#define LCD_SCREEN_WIDTH 800
++#define LCD_SCREEN_HEIGHT 480
++
++#if defined(USE_LVDS_1024_768)
++#define LVDS_SCREEN_WIDTH 1024
++#define LVDS_SCREEN_HEIGHT 768
++#else
++#define LVDS_SCREEN_WIDTH 1280
++#define LVDS_SCREEN_HEIGHT 800
++#endif
++
++#define HDMI_SCREEN_WIDTH 1920
++#define HDMI_SCREEN_HEIGHT 1080
++
++
++#define TCC_LCD_FB_IOCTL 0x46FF
++
++
++#define CONFIG_FB_TCC_DEVS_MAX 3 // do not change!
++#define CONFIG_FB_TCC_DEVS 3
++
++#if (CONFIG_FB_TCC_DEVS > CONFIG_FB_TCC_DEVS_MAX)
++ #undef CONFIG_FB_TCC_DEVS
++ #define CONFIG_FB_TCC_DEVS CONFIG_FB_TCC_DEVS_MAX
++#endif
++
++
++#define SCREEN_DEPTH_MAX 32 // 32 or 16
++// : 32 - 32bpp(alpah+rgb888)
++// : 16 - 16bpp(rgb565)
++
++const unsigned int default_scn_depth[CONFIG_FB_TCC_DEVS_MAX] =
++{
++#if defined (CONFIG_FB_TCC_BPP_32)
++/* fb0, Layer0: bottom */ (SCREEN_DEPTH_MAX), // 32 or 16
++/* fb1, Layer1: middle */ (SCREEN_DEPTH_MAX), // "
++/* fb2, Layer2: top */ (SCREEN_DEPTH_MAX) // "
++#else
++/* fb0, Layer0: bottom */ (16), // 32 or 16
++/* fb1, Layer1: middle */ (16), // "
++/* fb2, Layer2: top */ (16) // "
++#endif
++};
++
++#if defined(DEMO_LOADSHOW_LVDS)
++ const unsigned int fb_width[3] = {LVDS_SCREEN_WIDTH, LVDS_SCREEN_WIDTH, LVDS_SCREEN_WIDTH};
++ const unsigned int fb_height[3] = {LVDS_SCREEN_HEIGHT, LVDS_SCREEN_HEIGHT, LVDS_SCREEN_HEIGHT};
++ const unsigned int fb_lcdcid[3] = {1, 1, 1};
++#elif defined(DEMO_LOADSHOW_LCD_LVDS)
++ const unsigned int fb_width[3] = {LVDS_SCREEN_WIDTH, LVDS_SCREEN_WIDTH, LCD_SCREEN_WIDTH};
++ const unsigned int fb_height[3] = {LVDS_SCREEN_HEIGHT, LVDS_SCREEN_HEIGHT, LCD_SCREEN_HEIGHT};
++ const unsigned int fb_lcdcid[3] = {1, 1, 0};
++#elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ const unsigned int fb_width[3] = {LVDS_SCREEN_WIDTH, LCD_SCREEN_WIDTH, LCD_SCREEN_WIDTH};
++ const unsigned int fb_height[3] = {LVDS_SCREEN_HEIGHT, LCD_SCREEN_HEIGHT, LCD_SCREEN_HEIGHT};
++ const unsigned int fb_lcdcid[3] = {0, 1, 1};
++#elif defined(DEMO_LOADSHOW_LCD_HDMI)
++ const unsigned int fb_width[3] = {LCD_SCREEN_WIDTH, LCD_SCREEN_WIDTH, LCD_SCREEN_WIDTH};
++ const unsigned int fb_height[3] = {LCD_SCREEN_HEIGHT, LCD_SCREEN_HEIGHT, LCD_SCREEN_HEIGHT};
++ const unsigned int fb_lcdcid[3] = {1, 1, 0};
++#else
++ const unsigned int fb_width[3] = {LCD_SCREEN_WIDTH, LCD_SCREEN_WIDTH, LCD_SCREEN_WIDTH};
++ const unsigned int fb_height[3] = {LCD_SCREEN_HEIGHT, LCD_SCREEN_HEIGHT, LCD_SCREEN_HEIGHT};
++ const unsigned int fb_lcdcid[3] = {1, 1, 1};
++#endif
++
++
++// for frame buffer clear
++static u_char *fb_mem_vaddr[CONFIG_FB_TCC_DEVS]= {0,};
++static u_int fb_mem_size [CONFIG_FB_TCC_DEVS]= {0,};
++
++extern unsigned int TCC_VPU_SIZE;
++#define TCC_VPU_OFFSET CAL_VPU_OFFSET(TCC_RAM_TOTAL_SIZE, TCC_VPU_SIZE)
++#define TCC_FB_OFFSET (TCC_VPU_OFFSET - (TCC_FB0_SIZE+TCC_FB1_SIZE+TCC_FB2_SIZE))
++
++// for reserved frame buffer memory.
++static u_long fb_reseved_mem_paddr[CONFIG_FB_TCC_DEVS_MAX];
++static u_int fb_reseved_mem_size [CONFIG_FB_TCC_DEVS_MAX] = {TCC_FB0_SIZE,
++ TCC_FB1_SIZE,
++ TCC_FB2_SIZE};
++
++/* Register */
++PDDICONFIG pDDICfg;
++PLCDC pLCDC0;
++PLCDC pLCDC1;
++static PGPIO pGPIO;
++
++PM2MSCALER pM2MSCALER[2];
++
++typedef struct {
++ volatile unsigned int LIxC; // LCD Image x Control Register
++ volatile unsigned int LIxP; // LCD Image x Position Register
++ volatile unsigned int LIxS; // LCD Image x Size Register
++ volatile unsigned int LIxBA0; // LCD Image x Base Address 0 Register.
++ volatile unsigned int LIxCA; // LCD Image x Current Address Register.
++ volatile unsigned int LIxBA1; // LCD Image x Base Address 1 Register
++ volatile unsigned int LIxBA2; // LCD Image x Base Address 2 Register
++ volatile unsigned int LIxO; // LCD Image x Offset Register
++ volatile unsigned int LIxSR; // LCD Image x Scale ratio
++ volatile unsigned int LIxA; // LCD Image x Alpha Configuration Register
++ volatile unsigned int LIxKR; // LCD Image x Keying Register for RED or LUMA(Y)
++ volatile unsigned int LIxKG; // LCD Image x Keying Register for BLUE or CHROMA(Cb)
++ volatile unsigned int LIxKB; // LCD Image x Keying Register for GREEN or CHROMA(Cr)
++ volatile unsigned int LIxEN; // LCD Image x Enhancement Register
++} LCDC_IMG, *PLCDC_IMG;
++
++PLCDC_IMG pLCDC1_IMG[3], pLCDC0_IMG[1];
++
++static unsigned int gLCDOnOffFlag=1; // 1: LCD controller on, 0: LCD controller off
++
++void tcc_lcd_on(void)
++{
++ PGPIO pGPIO = (GPIO *)&HwGPIO_BASE;
++ PLCDC pLCDC;
++ lcd_cfg_t *cfg = &lcd_cfg[0];
++
++#if defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++
++ pLCDC = pLCDC0;
++
++ #if defined(USE_LVDS_1024_768)
++ tca_ckc_setperi(PERI_LCD0,ENABLE,1300000,PCDIRECTPLL3);
++ cfg = &lcd_cfg[1];
++ #else
++ tca_ckc_setperi(PERI_LCD0,ENABLE,1422200,PCDIRECTPLL2);
++ cfg = &lcd_cfg[2];
++ #endif
++
++#elif defined(DEMO_LOADSHOW_LCD_HDMI)
++
++ return;
++
++#elif defined(DEMO_LOADSHOW_LCD_LVDS)
++
++ pLCDC = pLCDC1;
++
++ #if defined(USE_LVDS_1024_768)
++ tca_ckc_setperi(PERI_LCD1,ENABLE,1300000,PCDIRECTPLL3);
++ cfg = &lcd_cfg[1];
++ #else
++ tca_ckc_setperi(PERI_LCD1,ENABLE,1422200,PCDIRECTPLL2);
++ cfg = &lcd_cfg[2];
++ #endif
++
++#elif defined(DEMO_LOADSHOW_LVDS)
++
++ pLCDC = pLCDC1;
++
++ #if defined(USE_LVDS_1024_768)
++ tca_ckc_setperi(PERI_LCD1,ENABLE,1300000,PCDIRECTPLL3);
++ cfg = &lcd_cfg[1];
++ #else
++ tca_ckc_setperi(PERI_LCD1,ENABLE,1422200,PCDIRECTPLL2);
++ cfg = &lcd_cfg[2];
++ #endif
++
++#else
++
++ pLCDC = pLCDC1;
++ tca_ckc_setperi(PERI_LCD1,ENABLE,1560000,PCDIRECTPLL3);
++
++#endif
++
++
++#if defined(ROADSHOW_DEMO_TYPE1)
++
++// if (gLCDOnOffFlag)
++// return;
++
++ gLCDOnOffFlag = 1;
++
++ BITCLR(pGPIO->GPCFN0, 0xFFFFFFFF);
++ BITCLR(pGPIO->GPCFN1, 0xFFFFFFFF);
++ BITCLR(pGPIO->GPCFN2, 0xFFFFFFFF);
++ BITCLR(pGPIO->GPCFN3, (Hw16-Hw0));
++
++ //LCDC1 RGB Interface
++ BITSET(pGPIO->GPCFN0, 0x55555555);
++ BITSET(pGPIO->GPCFN1, 0x55555555);
++ BITSET(pGPIO->GPCFN2, 0x55555555);
++ BITCSET(pGPIO->GPCFN3, (Hw16-Hw0), 0x5555);
++
++ BITSET(pLCDC1->LI2C, Hw28);
++
++#endif
++
++// Set LCD controller
++ pLCDC->LCTRL = (
++ // Hw31| // EVP[31] - External VSYNC Polarity (0: Direct Input, 1: Inverted Input)
++ // Hw30| // EVS[30] - External VSYNC Enable (0: Disabled, 1: Enabled)
++ (0<<28)| // R2YMD[29:28] - RGB to YCbCr Conversion Option (type0)
++ // (1<<28)| // (type1)
++ // (2<<28)| // (type2)
++ // (3<<28)| // (type3)
++ (0<<26)| // LUT[27:26] - LUT Option Bits (Not used)
++ // (1<<26)| // (Used for Image 0)
++ // (2<<26)| // (Used for Image 0)
++ // (3<<26)| // (Used for Image 0)
++ // Hw25| // GEN[25] - Gamma Corection Enable Bit (0: Disabled, 1: Enabled)
++ // Hw24| // 656[24] - CCIR 656 Mode (0: Disabled, 1: Enabled)
++ // Hw23| // CKG[23] - Clock Gating Enable for Timing Generator
++ // Hw22|Hw21|Hw20| // BPP[22:20] - Bit Per Pixel for STN-LCD
++ (cfg->pwdx<<16)| //PXDW[19:16] - C : 24Bit(888) Hw19(1)|Hw18(1)|Hw17(0)|Hw16(0)|
++ //PXDW[19:16] - 5 : 18Bit(666) Hw19(0)|Hw18(1)|Hw17(0)|Hw16(1)|
++ // Hw15| // Inverted Data Enable (ACBIAS pin)
++ Hw14| // Inverted Vertical Sync
++ Hw13| // Inverted Horizontal Sync
++ // Hw12| // Inverted Pixel Clock
++ // Hw11| // Clipping Enable
++ // Hw10| // RGB to YCbCr Converter Enable for OUTPUT
++ // Hw9 | // Double Pixel Data
++ Hw8 | // Non-interlace
++ (0x2<<5)| // TFT-LCD mode: STN(Hw5), TFT(Hw6), TV(Hw7)
++ // Hw4 | // Master Select for IMG0
++ (0x5<<1)| // OVP[3:1] - 5 : Image2 > Image1 > Image0
++ Hw0 | // LCD Controller Enable
++ 0); // End Of Value
++
++// Set LCD clock
++ pLCDC->LCLKDIV &= 0xFF00FF00;
++ pLCDC->LCLKDIV |= ( (1 << 16) | cfg->devide); //((PCK_LCD+1)/2)/((LCD_DEVIDE)*2)
++
++// Horizontal timing
++ pLCDC->LHTIME1 = ((cfg->hpw-1) << 16) | (cfg->res_width - 1);
++ pLCDC->LHTIME2 = ((cfg->hbp-1) << 16) | (cfg->hfp-1);
++
++// Vertical timing
++ pLCDC->LVTIME1 = ((cfg->vpw-1) << 16) | (cfg->res_height - 1);
++ pLCDC->LVTIME2 = ((cfg->vbp-1) << 16) | (cfg->vfp-1);
++ pLCDC->LVTIME3 = ((cfg->vpw-1) << 16) | (cfg->res_height - 1);
++ pLCDC->LVTIME4 = ((cfg->vbp-1) << 16) | (cfg->vfp-1);
++
++// Display Size
++ pLCDC->LDS = (cfg->res_height << 16) | cfg->res_width;
++
++ // non-interlace mode (progressive mode)
++ {
++ unsigned regl;
++ regl = readl(&pLCDC->LI0C);
++ writel(regl & ~(0x80000000), &pLCDC->LI0C);
++ regl = readl(&pLCDC->LI1C);
++ writel(regl & ~(0x80000000), &pLCDC->LI1C);
++ regl = readl(&pLCDC->LI2C);
++ writel(regl & ~(0x80000000), &pLCDC->LI2C);
++ }
++
++#if defined(DEMO_LOADSHOW_LVDS) || defined(DEMO_LOADSHOW_LCD_LVDS) || defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, LVDSIVT, OUTPUT, HIGH, SET_DIRECTION|SET_VALUE);
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, LVDSLPCTRL, OUTPUT, HIGH, SET_DIRECTION|SET_VALUE);
++// tcc_pca953x_setup(PCA9538_U4_SLAVE_ADDR, SATAHDMI, OUTPUT, HIGH, SET_DIRECTION|SET_VALUE);
++
++#else
++// LCD_DISP On
++ gpio_direction_output(GPIO_LCD_PWR_EN, 1);
++
++// LCD_BL_EN(Backlight) On
++ bl_control(1);
++
++ gLCDOnOffFlag = 1;
++#endif
++}
++EXPORT_SYMBOL(tcc_lcd_on);
++
++void tcc_lcd_off(void)
++{
++#if defined(DEMO_LOADSHOW_LVDS) || defined(DEMO_LOADSHOW_LCD_LVDS) || defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, LVDSIVT, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, LVDSLPCTRL, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++// tcc_pca953x_setup(PCA9538_U4_SLAVE_ADDR, SATAHDMI, OUTPUT, LOW, SET_DIRECTION|SET_VALUE);
++
++#elif defined(DEMO_LOADSHOW_LCD_HDMI)
++
++ return;
++
++#else
++
++ #if defined(ROADSHOW_DEMO_TYPE1)
++
++ PLCDC pLCDC;
++ lcd_cfg_t *cfg = &lcd_cfg[0];
++
++
++// if (gLCDOnOffFlag==0)
++// return;
++
++ gLCDOnOffFlag = 0;
++
++ pLCDC = pLCDC0;
++ tca_ckc_setperi(PERI_LCD0,ENABLE,1560000,PCDIRECTPLL3);
++
++ BITCLR(pLCDC->LCTRL, Hw0);
++
++ while(pLCDC->LSTATUS & Hw30) // BUSY
++ {
++ udelay(1000*1);
++ }
++
++ BITCLR(pGPIO->GPCFN0, 0xFFFFFFFF);
++ BITCLR(pGPIO->GPCFN1, 0xFFFFFFFF);
++ BITCLR(pGPIO->GPCFN2, 0xFFFFFFFF);
++ BITCLR(pGPIO->GPCFN3, (Hw16-Hw0));
++
++ //LCDC0 RGB Interface
++ BITSET(pGPIO->GPCFN0, 0x22222222);
++ BITSET(pGPIO->GPCFN1, 0x22222222);
++ BITSET(pGPIO->GPCFN2, 0x22222222);
++ BITCSET(pGPIO->GPCFN3, (Hw16-Hw0), 0x2222);
++
++ *pLCDC0_IMG[0] = *pLCDC1_IMG[2];
++
++ BITCLR(pLCDC1->LI2C, Hw28);
++
++// Set LCD controller
++ pLCDC->LCTRL = (
++ // Hw31| // EVP[31] - External VSYNC Polarity (0: Direct Input, 1: Inverted Input)
++ // Hw30| // EVS[30] - External VSYNC Enable (0: Disabled, 1: Enabled)
++ (0<<28)| // R2YMD[29:28] - RGB to YCbCr Conversion Option (type0)
++ // (1<<28)| // (type1)
++ // (2<<28)| // (type2)
++ // (3<<28)| // (type3)
++ (0<<26)| // LUT[27:26] - LUT Option Bits (Not used)
++ // (1<<26)| // (Used for Image 0)
++ // (2<<26)| // (Used for Image 0)
++ // (3<<26)| // (Used for Image 0)
++ // Hw25| // GEN[25] - Gamma Corection Enable Bit (0: Disabled, 1: Enabled)
++ // Hw24| // 656[24] - CCIR 656 Mode (0: Disabled, 1: Enabled)
++ // Hw23| // CKG[23] - Clock Gating Enable for Timing Generator
++ // Hw22|Hw21|Hw20| // BPP[22:20] - Bit Per Pixel for STN-LCD
++ (cfg->pwdx<<16)| //PXDW[19:16] - C : 24Bit(888) Hw19(1)|Hw18(1)|Hw17(0)|Hw16(0)|
++ //PXDW[19:16] - 5 : 18Bit(666) Hw19(0)|Hw18(1)|Hw17(0)|Hw16(1)|
++ // Hw15| // Inverted Data Enable (ACBIAS pin)
++ Hw14| // Inverted Vertical Sync
++ Hw13| // Inverted Horizontal Sync
++ // Hw12| // Inverted Pixel Clock
++ // Hw11| // Clipping Enable
++ // Hw10| // RGB to YCbCr Converter Enable for OUTPUT
++ // Hw9 | // Double Pixel Data
++ Hw8 | // Non-interlace
++ (0x2<<5)| // TFT-LCD mode: STN(Hw5), TFT(Hw6), TV(Hw7)
++ // Hw4 | // Master Select for IMG0
++ (0x5<<1)| // OVP[3:1] - 5 : Image2 > Image1 > Image0
++ Hw0 | // LCD Controller Enable
++ 0); // End Of Value
++
++// Set LCD clock
++ pLCDC->LCLKDIV &= 0xFF00FF00;
++ pLCDC->LCLKDIV |= ( (1 << 16) | cfg->devide); //((PCK_LCD+1)/2)/((LCD_DEVIDE)*2)
++
++// Horizontal timing
++ pLCDC->LHTIME1 = ((cfg->hpw-1) << 16) | (cfg->res_width - 1);
++ pLCDC->LHTIME2 = ((cfg->hbp-1) << 16) | (cfg->hfp-1);
++
++// Vertical timing
++ pLCDC->LVTIME1 = ((cfg->vpw-1) << 16) | (cfg->res_height - 1);
++ pLCDC->LVTIME2 = ((cfg->vbp-1) << 16) | (cfg->vfp-1);
++ pLCDC->LVTIME3 = ((cfg->vpw-1) << 16) | (cfg->res_height - 1);
++ pLCDC->LVTIME4 = ((cfg->vbp-1) << 16) | (cfg->vfp-1);
++
++// Display Size
++ pLCDC->LDS = (cfg->res_height << 16) | cfg->res_width;
++
++ BITSET(pLCDC->LI0C, Hw28);
++ BITSET(pLCDC->LCTRL, Hw0);
++
++ return;
++
++ #endif
++
++ PGPIO pGPIO = (GPIO *)&HwGPIO_BASE;
++
++// LCD_DISP Off
++ gpio_direction_output(GPIO_LCD_PWR_EN, 0);
++
++// LCD_BL_EN(Backlight) Off
++ bl_control(0);
++
++ gLCDOnOffFlag = 0;
++#endif
++}
++EXPORT_SYMBOL(tcc_lcd_off);
++
++
++typedef struct _tccfb_m2m_info {
++ int use;
++ int m2m;
++ int lcdc;
++ int img;
++ int direct;
++} tccfb_m2m_info_t;
++
++static tccfb_m2m_info_t gFbM2MInfo = {0, };
++
++//@
++// lcdc_idx : 0 - LCDC0, other - LCDC1
++// m2m_idx : 0 - M2M0, other - M2M1
++// imgch : 0 - IMG0, 1 - IMG1, 2 - IMG2
++static int tcc_m2m_set(int enable)
++{
++ PM2MSCALER pM2MScaler;
++ PLCDC pLCDC;
++ PLCDC_IMG pIMG;
++
++ int lcdc_idx = 1;
++ int img_ch = 2;
++ int m2m_idx = 1;
++
++ volatile unsigned int img_is_en = 0;
++ volatile unsigned int bitIxEOF;
++
++ unsigned int count=0;
++// unsigned int count_max=1;//1000;
++ unsigned int width, height;
++
++ //@ m2m reg-base
++ if (m2m_idx==0)
++ pM2MScaler = pM2MSCALER[0];
++ else
++ pM2MScaler = pM2MSCALER[1];
++
++ //@ lcdc reg-base
++ //@ img reg-base
++ if (lcdc_idx==0) {
++ pLCDC = pLCDC0;
++
++ switch(img_ch) {
++ case 0:
++ pIMG = pLCDC0_IMG[0];
++ bitIxEOF = Hw27;
++ break;
++ default:
++ return -1;
++ }
++ } else {
++ pLCDC = pLCDC1;
++
++ switch(img_ch) {
++ case 0:
++ pIMG = pLCDC1_IMG[0];
++ bitIxEOF = Hw27;
++ break;
++ case 1:
++ pIMG = pLCDC1_IMG[1];
++ bitIxEOF = Hw26;
++ break;
++ case 2:
++ pIMG = pLCDC1_IMG[2];
++ bitIxEOF = Hw25;
++ break;
++ default:
++ return -1;
++ }
++ }
++
++ img_is_en = (pIMG->LIxC & Hw28);
++
++ //! m2m disable
++ if (enable == 0)
++ {
++ // BITCLR(pIMG->LIxC, Hw27);
++
++ if (gFbM2MInfo.use)
++ {
++ if (img_is_en)
++ {
++ count=0;
++
++ BITCLR(pIMG->LIxC, Hw28);
++
++ #if (0)
++ while((pLCDC->LCTRL & Hw0) && !(pLCDC->LSTATUS & bitIxEOF)) //IxEOF
++ {
++ printk("[0x%08x] 0x%08x\n", bitIxEOF, pLCDC->LSTATUS);
++ //{volatile int ttt;for(ttt=0;ttt<0x100;ttt++);}
++ udelay(1000);
++ if(++count == count_max)
++ break;
++ }
++ #else
++ {
++ volatile unsigned int data;
++
++ count = 0;
++ data = (pLCDC->LSTATUS & Hw31);
++ while(1 && (pLCDC->LCTRL & Hw0))
++ {
++ if (data != (pLCDC->LSTATUS & Hw31))
++ break;
++ count++;
++ }
++ }
++ #endif
++ }
++
++ BITCLR(pIMG->LIxC, Hw27);
++
++ #if (1)
++ if (m2m_idx)
++ {
++ BITCSET(pDDICfg->ON_THE_FLY, Hw5|Hw4, 3<<4); // mscl1 - not used
++ BITSET(pDDICfg->SWRESET, Hw6);
++ BITSET(pDDICfg->PWDN,Hw6);
++ BITCLR(pDDICfg->SWRESET, Hw6);
++ }
++ else
++ {
++ BITCSET(pDDICfg->ON_THE_FLY, Hw3|Hw2, 2<<2); // mscl0 - not used
++ BITSET(pDDICfg->SWRESET, Hw5);
++ BITSET(pDDICfg->PWDN,Hw5);
++ BITCLR(pDDICfg->SWRESET, Hw5);
++ }
++ #else
++ pM2MScaler->MSCCTR = 0;
++ #endif
++
++ #if (1)
++ if (img_is_en)
++ BITSET(pIMG->LIxC, Hw28);
++ #endif
++
++ memset(&gFbM2MInfo, 0, sizeof(gFbM2MInfo));
++
++ printk(" -- count-->[%d]\n", count);
++ }
++
++ return 0;
++ }
++
++ if (img_is_en)
++ {
++ count=0;
++
++ BITCLR(pIMG->LIxC, Hw28);
++
++ #if (0)
++ while((pLCDC->LCTRL & Hw0) && !(pLCDC->LSTATUS & bitIxEOF)) //IxEOF
++ {
++ printk("[0x%08x] 0x%08x\n", bitIxEOF, pLCDC->LSTATUS);
++ //{volatile int ttt;for(ttt=0;ttt<0x100;ttt++);}
++ udelay(1000);
++ if(++count == count_max)
++ break;
++ }
++ #else
++ {
++ volatile unsigned int data;
++
++ count = 0;
++ data = (pLCDC->LSTATUS & Hw31);
++ while(1 && (pLCDC->LCTRL & Hw0))
++ {
++ if (data != (pLCDC->LSTATUS & Hw31))
++ break;
++ count++;
++ }
++ }
++ #endif
++
++ }
++
++ if (gFbM2MInfo.use)
++ {
++ // refresh
++
++ }
++ else
++ {
++ gFbM2MInfo.use = 1;
++ gFbM2MInfo.lcdc = lcdc_idx;
++ gFbM2MInfo.m2m = m2m_idx;
++ gFbM2MInfo.img = img_ch;
++ gFbM2MInfo.direct = 1;
++ }
++
++ // !! m2m reset !!
++ if (m2m_idx)
++ {
++ // BITCSET(pDDICfg->ON_THE_FLY, Hw5|Hw4, 3<<4); // mscl1 - not used
++ BITSET(pDDICfg->SWRESET, Hw6);
++ BITCLR(pDDICfg->PWDN,Hw6);
++ BITCLR(pDDICfg->SWRESET, Hw6);
++ }
++ else
++ {
++ // BITCSET(pDDICfg->ON_THE_FLY, Hw3|Hw2, 2<<2); // mscl0 - not used
++ BITSET(pDDICfg->SWRESET, Hw5);
++ BITCLR(pDDICfg->PWDN,Hw5);
++ BITCLR(pDDICfg->SWRESET, Hw5);
++ }
++
++ width = pIMG->LIxS & 0x0fff;
++ height = (pIMG->LIxS>>16) & 0x0fff;
++
++ pM2MScaler->SRCBASEY = pIMG->LIxBA0;
++ pM2MScaler->SRCBASEU = pM2MScaler->SRCBASEY;
++ pM2MScaler->SRCBASEV = pM2MScaler->SRCBASEY;
++ pM2MScaler->SRCSIZE = pIMG->LIxS;
++ pM2MScaler->SRCOFF = (((pIMG->LIxS & 0x0fff)*2)<<16) + ((pIMG->LIxS & 0x0fff)*2);
++ pM2MScaler->SRCCFG = 4; // type 4 - rgb565
++
++ pM2MScaler->DSTBASEY = pIMG->LIxBA0;
++ pM2MScaler->DSTBASEU = pM2MScaler->DSTBASEY;
++ pM2MScaler->DSTBASEV = pM2MScaler->DSTBASEY;
++ pM2MScaler->DSTSIZE = pIMG->LIxS;
++ pM2MScaler->DSTOFF = (((pIMG->LIxS & 0x0fff)*2)<<16) + ((pIMG->LIxS & 0x0fff)*2);
++ pM2MScaler->DSTCFG = 0
++ | ((Hw3-Hw0) & (( 4)<< 0)) // type 4 - rgb565
++ | ((Hw4) & (( 1)<< 4)) // 0: memory, 1: LCDC
++ | ((Hw6) & (( 1)<< 6)) // RDY
++ | 0;
++
++ pM2MScaler->MSCINF = ((256)<<16) + (256); // scale ratio
++ pM2MScaler->MSCCTR = 0
++ | ((Hw5 ) & (( 1)<< 5)) // 0: One-Time Mode, 1: Continuous Mode
++ | ((Hw0 ) & (( 0)<< 0)) // 0: Operation Disable, 1: Operation Enable
++ | 0;
++
++ if (m2m_idx)
++ BITCSET(pDDICfg->ON_THE_FLY, Hw5|Hw4, 1<<4); // mscl1 - lcdc1
++ else
++ BITCSET(pDDICfg->ON_THE_FLY, Hw3|Hw2, 1<<2); // mscl0 - lcdc1
++
++ pM2MScaler->MSCCTR |= Hw0; // Operation Enable
++
++ BITSET(pIMG->LIxC, Hw27);
++
++ if (img_is_en)
++ BITSET(pIMG->LIxC, Hw28);
++
++ printk(" -- count-->[%d]\n", count);
++
++ return 0;
++}
++
++static int tcc_m2m_refresh(void)
++{
++ PM2MSCALER pM2MScaler;
++ PLCDC pLCDC;
++ PLCDC_IMG pIMG;
++
++ if (gFbM2MInfo.use)
++ {
++ //@ m2m reg-base
++ if (gFbM2MInfo.m2m==0)
++ pM2MScaler = pM2MSCALER[0];
++ else
++ pM2MScaler = pM2MSCALER[1];
++
++ //@ lcdc reg-base
++ //@ img reg-base
++ if (gFbM2MInfo.lcdc==0) {
++ pLCDC = pLCDC0;
++
++ switch(gFbM2MInfo.img) {
++ case 0:
++ pIMG = pLCDC0_IMG[0];
++ break;
++ default:
++ return -1;
++ }
++ } else {
++ pLCDC = pLCDC1;
++
++ switch(gFbM2MInfo.img) {
++ case 0:
++ pIMG = pLCDC1_IMG[0];
++ break;
++ case 1:
++ pIMG = pLCDC1_IMG[1];
++ break;
++ case 2:
++ pIMG = pLCDC1_IMG[2];
++ break;
++ default:
++ return -1;
++ }
++ }
++
++ if (pM2MScaler->SRCBASEY != pIMG->LIxBA0 || pM2MScaler->SRCSIZE != pIMG->LIxS)
++ {
++ printk("m2m - refresh\n");
++
++ tcc_m2m_set(1);
++ }
++ }
++
++ return 0;
++}
++
++
++static void tcc_regbase_init(void)
++{
++ pDDICfg = (volatile PDDICONFIG)tcc_p2v(HwDDI_CONFIG_BASE);
++ pLCDC0 = (volatile PLCDC)tcc_p2v(HwLCDC0_BASE);
++ pLCDC1 = (volatile PLCDC)tcc_p2v(HwLCDC1_BASE);
++ pGPIO = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
++
++ pM2MSCALER[0] = (volatile PM2MSCALER)tcc_p2v(HwM2MSCALER0_BASE);
++ pM2MSCALER[1] = (volatile PM2MSCALER)tcc_p2v(HwM2MSCALER1_BASE);
++
++ pLCDC1_IMG[0] = (PLCDC_IMG)&pLCDC1->LI0C;
++ pLCDC1_IMG[1] = (PLCDC_IMG)&pLCDC1->LI1C;
++ pLCDC1_IMG[2] = (PLCDC_IMG)&pLCDC1->LI2C;
++
++ pLCDC0_IMG[0] = (PLCDC_IMG)&pLCDC0->LI0C;
++}
++
++
++static void tcc_lcdc_interrupt(int lcdcid, char onoff)
++{
++ if(lcdcid)
++ {
++ if(onoff == 1)
++ {
++ BITCSET(pLCDC1->LIM, 0xFFFFFFFF, Hw3);
++
++ BITSET(HwPIC->POL0, HwINT0_LCD1);
++ BITSET(HwPIC->SEL0, HwINT0_LCD1);
++ BITSET(HwPIC->MODE0, HwINT0_LCD1);
++
++ BITSET(HwPIC->IEN0, HwINT0_LCD1);
++ }
++ else
++ {
++ BITCLR(HwPIC->IEN0, HwINT0_LCD1);
++ }
++ }
++ else
++ {
++ if(onoff == 1)
++ {
++ BITCSET(pLCDC0->LIM, 0xFFFFFFFF, Hw3);
++
++ BITSET(HwPIC->POL0, HwINT0_LCD0);
++ BITSET(HwPIC->SEL0, HwINT0_LCD0);
++ BITSET(HwPIC->MODE0, HwINT0_LCD0);
++
++ BITSET(HwPIC->IEN0, HwINT0_LCD0);
++ }
++ else
++ {
++ BITCLR(HwPIC->IEN0, HwINT0_LCD0);
++ }
++ }
++}
++
++
++#if 0
++static void tcc_start_lcd_int_dd(void)
++{
++ /* [config] LCD interrupt Masking Register (LIM) */
++ //todo
++
++ /* [config] LCD Status Register (LSTATUS) */
++ //todo
++}
++#endif
++
++static void tcc_stop_lcd_int_dd(void)
++{
++ /* [config] LCD interrupt Masking Register (LIM) */
++ //TODO
++
++ /* [config] LCD Control Registers (LCTRL) */
++ //todo
++}
++
++#if 0
++static void tcc_set_reg_for_int_dd(void)
++{
++ /* [config] LCD Control Registers (LCTRL) */
++ //todo
++}
++#endif
++
++//static struct tccfb_mach_info *mach_info;
++
++/*
++ * tccfb_check_var():
++ * Get the video params out of 'var'. If a value doesn't fit, round it up,
++ * if it's too big, return -EINVAL.
++ *
++ */
++static int tccfb_check_var(struct fb_var_screeninfo *var,
++ struct fb_info *info)
++{
++ dprintk("check_var(var=%p, info=%p)\n", var, info);
++
++#if defined (CONFIG_FB_TCC_BPP_32)
++ var->bits_per_pixel = 32;
++#else
++ var->bits_per_pixel = 16;
++#endif
++
++ /* validate bpp */
++ if (var->bits_per_pixel > 32)
++ var->bits_per_pixel = 32;
++ else if (var->bits_per_pixel < 16)
++ var->bits_per_pixel = 16;
++
++ /* set r/g/b positions */
++ if (var->bits_per_pixel == 16) {
++ var->red.offset = 11;
++ var->green.offset = 5;
++ var->blue.offset = 0;
++ var->red.length = 5;
++ var->green.length = 6;
++ var->blue.length = 5;
++ var->transp.length = 0;
++ } else if (var->bits_per_pixel == 32) {
++ var->red.offset = 16;
++ var->green.offset = 8;
++ var->blue.offset = 0;
++ var->transp.offset = 24;
++ var->red.length = 8;
++ var->green.length = 8;
++ var->blue.length = 8;
++ var->transp.length = 8;
++ } else {
++ var->red.length = var->bits_per_pixel;
++ var->red.offset = 0;
++ var->green.length = var->bits_per_pixel;
++ var->green.offset = 0;
++ var->blue.length = var->bits_per_pixel;
++ var->blue.offset = 0;
++ var->transp.length = 0;
++ }
++
++ return 0;
++}
++
++/* tccfb_pan_display
++ *
++ * pandisplay (set) the controller from the given framebuffer
++ * information
++*/
++struct lcd_struct {
++ spinlock_t lock;
++ wait_queue_head_t waitq;
++ char state;
++};
++
++static struct lcd_struct lcdc_struct[2];
++
++static int tccfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
++{
++ struct tccfb_info *fbi = (struct tccfb_info *)info->par;
++
++ unsigned int parm_lcdcid;
++ unsigned int parm_imgch;
++
++ PLCDC pLCDC;
++
++// return 0;
++
++ unsigned int status;
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = fbi->imgch;
++
++#if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(fbi->imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++#elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(fbi->imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++#endif
++
++ if(parm_lcdcid)
++ pLCDC = pLCDC1;
++ else
++ pLCDC = pLCDC0;
++
++ status = pLCDC->LSTATUS;
++
++ pLCDC->LSTATUS = status | Hw3;
++ lcdc_struct[parm_lcdcid].state = 0;
++
++ (fbi->fb)->var.yoffset = var->yoffset;
++ (fbi->fb)->var.xoffset = var->xoffset;
++
++ switch (fbi->imgch)
++ {
++ case 2: // IMG2
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ pLCDC0->LI0BA0 = fbi->map_dma + (fbi->fb)->var.xres*(fbi->fb)->var.yoffset*(fbi->fb)->var.bits_per_pixel/8;
++ #else
++ pLCDC1->LI2BA0 = fbi->map_dma + (fbi->fb)->var.xres*(fbi->fb)->var.yoffset*(fbi->fb)->var.bits_per_pixel/8;
++ #endif
++ break;
++ case 1: // IMG1
++ pLCDC1->LI1BA0 = fbi->map_dma + (fbi->fb)->var.xres*(fbi->fb)->var.yoffset*(fbi->fb)->var.bits_per_pixel/8;
++ break;
++ case 0: // IMG0
++ #if defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ pLCDC0->LI0BA0 = fbi->map_dma + (fbi->fb)->var.xres*(fbi->fb)->var.yoffset*(fbi->fb)->var.bits_per_pixel/8;
++ #else
++ pLCDC1->LI0BA0 = fbi->map_dma + (fbi->fb)->var.xres*(fbi->fb)->var.yoffset*(fbi->fb)->var.bits_per_pixel/8;
++ #endif
++ break;
++ }
++
++ tcc_m2m_refresh();
++
++ tcc_lcdc_interrupt(parm_lcdcid, 1);
++ wait_event_interruptible(lcdc_struct[parm_lcdcid].waitq, lcdc_struct[parm_lcdcid].state == 1 );
++
++ dprintk("tccfb_pan_display:%5d, yoffset:%5d \n",fbi->fb->var.xres,var->yoffset );
++
++ return 0;
++}
++
++
++/* tccfb_activate_var
++ *
++ * activate (set) the controller from the given framebuffer
++ * information
++*/
++
++static void tccfb_activate_var(struct tccfb_info *fbi,
++ struct fb_var_screeninfo *var)
++{
++// dprintk("activate_var\n");
++
++ unsigned int imgch = 0;
++ unsigned int bpp_value;
++// unsigned int tmp_value;
++
++ unsigned int sx, sy;
++ int lcdc_channel = 1;
++
++ dprintk("%s:fb%d var->bpp = %d\n", __FUNCTION__, fbi->fb->node, var->bits_per_pixel);
++
++ if((0 <= fbi->fb->node) && (fbi->fb->node < CONFIG_FB_TCC_DEVS))
++ imgch = fbi->fb->node;
++ else
++ return;
++
++ if(fbi->fb->var.bits_per_pixel == 32)
++ bpp_value = IMGFMT_RGB888; //0x000C; //RGB888
++ else if(fbi->fb->var.bits_per_pixel == 16)
++ bpp_value = IMGFMT_RGB565; //0x000A; //RGB565
++ else
++ {
++ dprintk("%s:fb%d Not Supported BPP!\n", __FUNCTION__, fbi->fb->node);
++ return;
++ }
++
++ /* write new registers */
++ #if 0
++ switch(imgch)
++ {
++ case 0:
++ tmp_value = pLCDC1->LI0C;
++ pLCDC1->LI0C = (tmp_value & 0xFFFFFFE0) | (bpp_value & 0x0000001F);
++ pLCDC1->LI0O = (fbi->fb->var.xres*(fbi->fb->var.bits_per_pixel/8));
++ break;
++ case 1:
++ tmp_value = pLCDC1->LI1C;
++ pLCDC1->LI1C = (tmp_value & 0xFFFFFFE0) | (bpp_value & 0x0000001F);
++ pLCDC1->LI1O = (fbi->fb->var.xres*(fbi->fb->var.bits_per_pixel/8));
++ break;
++ case 2:
++ tmp_value = pLCDC1->LI2C;
++ pLCDC1->LI2C = (tmp_value & 0xFFFFFFE0) | (bpp_value & 0x0000001F);
++ pLCDC1->LI2O = (fbi->fb->var.xres*(fbi->fb->var.bits_per_pixel/8));
++ break;
++ }
++ #else
++
++ switch(imgch)
++ {
++ case 0:
++ #if defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ sx = pLCDC0->LI0P & 0x0000ffff;
++ sy = (pLCDC0->LI0P>>16) & 0x0000ffff;
++ lcdc_channel = 0; imgch = 0;
++ #else
++ sx = pLCDC1->LI0P & 0x0000ffff;
++ sy = (pLCDC1->LI0P>>16) & 0x0000ffff;
++ lcdc_channel = 1;
++ #endif
++ break;
++ case 1:
++ sx = pLCDC1->LI1P & 0x0000ffff;
++ sy = (pLCDC1->LI1P>>16) & 0x0000ffff;
++ lcdc_channel = 1;
++ break;
++ case 2:
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ sx = pLCDC0->LI0P & 0x0000ffff;
++ sy = (pLCDC0->LI0P>>16) & 0x0000ffff;
++ lcdc_channel = 0; imgch = 0;
++ #else
++ sx = pLCDC1->LI2P & 0x0000ffff;
++ sy = (pLCDC1->LI2P>>16) & 0x0000ffff;
++ lcdc_channel = 1;
++ #endif
++ break;
++ }
++
++ tca_lcdc_setimgchfmt(lcdc_channel, imgch, bpp_value);
++ tca_lcdc_setimgchwindow(lcdc_channel, imgch, sx, sy, fbi->fb->var.xres, fbi->fb->var.yres);
++ tca_lcdc_setaddroffset(lcdc_channel, imgch, fbi->fb->var.xres, bpp_value);
++
++ tcc_m2m_refresh();
++ #endif
++
++ return;
++}
++
++
++/*
++ * tccfb_set_par - Optional function. Alters the hardware state.
++ * @info: frame buffer structure that represents a single frame buffer
++ *
++ */
++static int tccfb_set_par(struct fb_info *info)
++{
++ struct tccfb_info *fbi = info->par;
++ struct fb_var_screeninfo *var = &info->var;
++
++ dprintk("set_par\n");
++
++ if (var->bits_per_pixel == 16)
++ fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR;
++ else if (var->bits_per_pixel == 32)
++ fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR;
++ else
++ fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
++
++ fbi->fb->fix.line_length = (var->width*var->bits_per_pixel)/8;
++
++ /* activate this new configuration */
++
++ tccfb_activate_var(fbi, var);
++ return 0;
++}
++
++#ifdef TV_OUT_INCLUDE
++
++#include <linux/tcc_ll.h>
++#include <linux/tcc_pwm.h>
++
++static stpwrinfo gTvoPwrInfo = {PWR_STATUS_OFF};
++
++//@tvo
++static unsigned int gTvoType;
++static unsigned int gTvoStatus; // 1: enabled tv-out, 0: disabled tv-out
++
++static int tvo_pwr_ctl(void *h_private, int cmd, void *p_out)
++{
++ int ret = 0;
++
++ switch (cmd) {
++ case PWR_CMD_OFF:
++ tca_tvo_enable(0);
++ gTvoPwrInfo.status = PWR_STATUS_OFF;
++ if (p_out)
++ {
++ memcpy(p_out, &gTvoPwrInfo, sizeof(stpwrinfo));
++ }
++ break;
++ case PWR_CMD_ON:
++ tca_tvo_enable(1);
++ gTvoPwrInfo.status = PWR_STATUS_ON;
++ if (p_out)
++ {
++ memcpy(p_out, &gTvoPwrInfo, sizeof(stpwrinfo));
++ }
++ break;
++ case PWR_CMD_GETSTATUS:
++ if (p_out)
++ {
++ memcpy(p_out, &gTvoPwrInfo, sizeof(stpwrinfo));
++ }
++ else
++ {
++ ret = -EINVAL;
++ }
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ return ret;
++}
++unsigned int tvo_init(void)
++{
++ gTvoStatus = 0;
++ insert_pwm_node(DEVICE_TVOUT, tvo_pwr_ctl, NULL);
++ return 0;
++}
++unsigned int tvo_open(void)
++{
++ return 0;
++}
++unsigned int tvo_close(void)
++{
++ return 0;
++}
++unsigned int tvo_cleanup(void)
++{
++ remove_pwm_node(DEVICE_TVOUT);
++ return 0;
++}
++unsigned int tvo_status(void)
++{
++ /*
++ return 1 when:
++ 1. gTvoStatus = 1
++ 2. HDMI_EN = 1 && LCD_EN = 0
++ */
++ return gTvoStatus | ((gpio_get_value(GPIO_HDMI_EN)
++ & (gpio_get_value(GPIO_HDMI_HPD) == 1) & (gLCDOnOffFlag == 0)));
++}
++void tvo_powerup(void)
++{
++ if(gTvoStatus)
++ {
++ tca_tvo_setmode(gTvoType); // need to input type
++ tca_tvo_enable(1);
++
++ gTvoPwrInfo.status = PWR_STATUS_ON;
++ }
++}
++void tvo_powerdown(void)
++{
++ if(gTvoStatus)
++ {
++ tca_tvo_enable(0);
++
++ gTvoPwrInfo.status = PWR_STATUS_OFF;
++ }
++}
++unsigned int tvo_ioctl(unsigned int cmd,unsigned long arg)
++{
++ unsigned int value;
++
++ switch(cmd)
++ {
++ case TCC_LCD_FB_IOCTL_TVOUT_CONNECT_LCDC:
++ copy_from_user((void *)&value, (const void *)arg, sizeof(unsigned int));
++ tca_tvo_connectlcdc(value);
++ break;
++
++ case TCC_LCD_FB_IOCTL_TVOUT_TYPE:
++ copy_from_user((void *)&gTvoType, (const void *)arg, sizeof(unsigned int));
++ break;
++
++ case TCC_LCD_FB_IOCTL_TVOUT_OPEN:
++ if (gTvoStatus==0)
++ {
++ PTIMER vTimerAddr = (PTIMER)((unsigned int)&HwTMR_BASE);
++ PGPIO vGpioAddr = (PGPIO)((unsigned int)&HwGPIO_BASE);
++
++ tca_bkl_powerdown((unsigned int)vTimerAddr,(unsigned int)vGpioAddr);
++
++ tca_tvo_setlcd2tv(gTvoType);
++ tca_tvo_setmode(gTvoType); // need to input type
++ tca_tvo_enable(1);
++
++ gTvoStatus = 1;
++ gTvoPwrInfo.status = PWR_STATUS_ON;
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_TVOUT_CLOSE:
++ if(gTvoStatus==1)
++ {
++ PTIMER vTimerAddr = (PTIMER)((unsigned int)&HwTMR_BASE);
++ PGPIO vGpioAddr = (PGPIO)((unsigned int)&HwGPIO_BASE);
++
++ tca_tvo_enable(0);
++ tca_tvo_settv2lcd();
++
++ tca_bkl_powerup((unsigned int)vTimerAddr,(unsigned int)vGpioAddr);
++
++ gTvoStatus = 0;
++ gTvoPwrInfo.status = PWR_STATUS_OFF;
++ }
++
++ break;
++
++ default:
++ break;
++
++ }
++
++ return 0;
++}
++#endif
++
++static int tccfb_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg)
++{
++ unsigned int imgch=0;
++
++ unsigned int prev_fmt[CONFIG_FB_TCC_DEVS];
++ unsigned int curr_fmt[CONFIG_FB_TCC_DEVS];
++ int ch_num;
++ int parm_lcdcid=MAIN_LCDC_ID;
++ int parm_imgch;
++
++ if((0 <= info->node) && (info->node < CONFIG_FB_TCC_DEVS))
++ {
++ imgch = info->node;
++ }
++ else
++ {
++ dprintk("ioctl: Error - fix.id[%d]\n", info->node);
++ return 0;
++ }
++
++ for (ch_num=0; ch_num<CONFIG_FB_TCC_DEVS; ch_num++)
++ {
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = ch_num;
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(ch_num == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(ch_num == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++ tca_lcdc_getimgchfmt(parm_lcdcid, parm_imgch, &prev_fmt[ch_num]);
++ }
++
++ switch(cmd)
++ {
++ case TCC_LCD_FB_IOCTL:
++ dprintk("ioctl: ioctl\n");
++ break;
++
++
++#if 1
++ case TCC_LCD_FB_IOCTL_SET_OVP:
++ {
++ unsigned char ovp;
++ copy_from_user((void *)&ovp, (const void *)arg, sizeof(unsigned char));
++
++ BITCSET(pLCDC1->LCTRL, Hw4-Hw1, ovp<<1);
++
++ printk("ioctl: set_ovp (%d)\n", ovp);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_SET_M2M:
++ {
++ unsigned int value;
++ copy_from_user((void *)&value, (const void *)arg, sizeof(unsigned int));
++
++ tcc_m2m_set(value);
++
++ printk("ioctl: set_m2m (%d)\n", value);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_LCD_ONOFF:
++ {//ok
++ unsigned int onoff;
++
++ copy_from_user((void *)&onoff, (const void *)arg, sizeof(unsigned int));
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++ if(onoff)
++ tcc_lcd_on();
++ else
++ tcc_lcd_off();
++ break;
++ default:
++ break;
++ }
++
++ printk("ioctl: lcd_onoff(%d)\n", onoff);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_DISP_ONOFF:
++ {//ok
++ unsigned int onoff;
++
++ copy_from_user((void *)&onoff, (const void *)arg, sizeof(unsigned int));
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++ tca_lcdc_setimgchenable(parm_lcdcid, parm_imgch, onoff);
++ break;
++ default:
++ break;
++ }
++
++ dprintk("ioctl: lcd_img%d_disp_onoff(%d)\n", imgch, onoff);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_ALPHA_ONOFF:
++ {//ok
++ unsigned int onoff;
++
++ copy_from_user((void *)&onoff, (const void *)arg, sizeof(unsigned int));
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++ tca_lcdc_setlayeralphablendingenable(parm_lcdcid, parm_imgch, onoff);
++ break;
++ default:
++ break;
++ }
++
++ dprintk("ioctl: lcd_layer%d_alpha_onoff(%d)\n", imgch, onoff);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_ALPHA_SET:
++ {
++ unsigned char alpha;
++
++ copy_from_user((void *)&alpha, (const void *)arg, sizeof(unsigned char));
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++
++ tca_lcdc_setlayeralphavalue(parm_lcdcid, parm_imgch, alpha);
++ break;
++ default:
++ break;
++ }
++
++ dprintk("ioctl: lcd_layer%d_alpha_%d(0x%x)\n", imgch, alpha, alpha);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_ALPHA_SELECTION:
++ {
++ unsigned int asel;
++
++ copy_from_user((void *)&asel, (const void *)arg, sizeof(unsigned int));
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++
++ tca_lcdc_setalphaselection(parm_lcdcid, parm_imgch, asel);
++ break;
++ default:
++ break;
++ }
++
++ dprintk("ioctl: lcd_layer%d_alpha_sel_%d(0x%x)\n", imgch, asel, asel);
++ }
++ break;
++
++
++ case TCC_LCD_FB_IOCTL_CHROMAKEY_ONOFF:
++ {
++ unsigned int onoff;
++
++ copy_from_user((void *)&onoff, (const void *)arg, sizeof(unsigned int));
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI)
++ break;
++ #endif
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++
++ tca_lcdc_setlayerchromakeyenable(parm_lcdcid, parm_imgch, onoff);
++ break;
++ default:
++ break;
++ }
++
++ dprintk("ioctl: lcd_img%d_chromakey_onoff(%d)\n", imgch, onoff);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_CHROMAKEY_SET_VALUE:
++ {
++ unsigned char value[3];
++
++ copy_from_user((void *)value, (const void *)arg, sizeof(unsigned char)*3);
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++
++ tca_lcdc_setlayerchromakeyvalue(parm_lcdcid, parm_imgch, value[0], value[1], value[2]);
++ break;
++ default:
++ break;
++ }
++
++ dprintk("ioctl: lcd_img%d_chromakey_RY%d(0x%x)GU%d(0x%x)BV%d(0x%x)\n", imgch, value[0], value[0], value[1], value[1], value[2], value[2]);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_CHROMAKEY_SET_MASK:
++ {
++ unsigned char mask[3];
++
++ copy_from_user((void *)mask, (const void *)arg, sizeof(unsigned char)*3);
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++
++ tca_lcdc_setlayerchromakeymask(parm_lcdcid, parm_imgch, mask[0], mask[1], mask[2]);
++ break;
++ default:
++ break;
++ }
++
++ dprintk("ioctl: lcd_img%d_chromakeymask_RY%d(0x%x)GU%d(0x%x)BV%d(0x%x)\n", imgch, mask[0], mask[0], mask[1], mask[1], mask[2], mask[2]);
++ }
++ break;
++#endif
++
++ case TCC_LCD_FB_IOCTL_SET_FORMAT:
++ {
++ unsigned int fmt;
++// unsigned offset0=0, offset1=0;
++ unsigned int img_width=0;
++
++ copy_from_user((void *)&fmt, (const void *)arg, sizeof(unsigned int));
++
++#if defined (CONFIG_FB_TCC_BPP_32)
++ /* if CONFIG_FB_TCC_BPP_32, force fmt to IMGFMT_RGB888 from IMGFMT_RGB565 */
++ if(fmt == 10) fmt = 12;
++#endif
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ #if defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ img_width = pLCDC0->LI0S & 0x0000ffff;
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ #else
++ img_width = pLCDC1->LI0S & 0x0000ffff;
++ #endif
++ break;
++ case 1: //img1
++ img_width = pLCDC1->LI1S & 0x0000ffff;
++ break;
++ case 2: //img2
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ img_width = pLCDC0->LI0S & 0x0000ffff;
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ #else
++ img_width = pLCDC1->LI2S & 0x0000ffff;
++ #endif
++ break;
++ default:
++ break;
++ }
++ tca_lcdc_setimgchfmt(parm_lcdcid, parm_imgch, fmt);
++ tca_lcdc_setaddroffset(parm_lcdcid, parm_imgch, img_width, fmt);
++ // tca_lcdc_setimgchOffsetInfo(parm_lcdcid, parm_imgch, offset0, offset1);
++
++ dprintk("ioctl: lcd_img%d_set_format(%d)\n", imgch, fmt);
++ }
++ break;
++
++
++ case TCC_LCD_FB_IOCTL_SET_BASEADDR:
++ {
++ unsigned int addr[3];
++
++ copy_from_user((void *)addr, (const void *)arg, sizeof(unsigned int)*3);
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++
++ tca_lcdc_setimgchbase(parm_lcdcid, parm_imgch, addr[0], addr[1], addr[2]);
++
++ tcc_m2m_refresh();
++
++ break;
++ default:
++ break;
++ }
++
++ #if (1) // Debug :: LCDC under-run, Base address align.
++ {
++ unsigned int stat=0;
++
++ if(pLCDC1->LCTRL & 0x1)
++ {
++ stat = pLCDC1->LSTATUS;
++ if(stat & 0x01)
++ {
++ printk("LCDC1 Underrun...\n");
++ pLCDC1->LSTATUS = stat;
++ }
++
++#if (0)
++ if ( ((pLCDC1->LI0BA0 & 0x1FF) != 0)
++ || ((pLCDC1->LI1BA0 & 0x1FF) != 0)
++ || ((pLCDC1->LI2BA0 & 0x1FF) != 0)
++ )
++ {
++ printk("LCDC1 IMGxBA: %x %x %x \n", pLCDC1->LI0BA0, pLCDC1->LI1BA0, pLCDC1->LI2BA0);
++ }
++#else
++ if (parm_lcdcid == 0) // lcdc0
++ {
++ if ((pLCDC0->LI0BA0 & 0x1FF) != 0)
++ {
++ printk("(warning) LCDC0 IMG0BA : %x\n", pLCDC0->LI0BA0);
++ }
++ }
++ else // lcdc1
++ {
++ switch(parm_imgch)
++ {
++ case 0:
++ if ((pLCDC1->LI0BA0 & 0x1FF) != 0)
++ printk("(warning) LCDC1 IMG0BA : %x\n", pLCDC1->LI0BA0);
++ break;
++ case 1:
++ if ((pLCDC1->LI1BA0 & 0x1FF) != 0)
++ printk("(warning) LCDC1 IMG1BA : %x\n", pLCDC1->LI1BA0);
++ break;
++ case 2:
++ if ((pLCDC1->LI2BA0 & 0x1FF) != 0)
++ printk("(warning) LCDC1 IMG2BA : %x\n", pLCDC1->LI2BA0);
++ break;
++ }
++ }
++#endif
++ }
++
++ if(pLCDC0->LCTRL & 0x1)
++ {
++ stat = pLCDC0->LSTATUS;
++ if(stat & 0x01)
++ {
++ printk("LCDC0 Underrun...\n");
++ pLCDC0->LSTATUS = stat;
++ }
++
++ if ( ((pLCDC0->LI0BA0 & 0x1FF) != 0))
++ {
++ printk("LCDC0 IMGxBA: %x\n", pLCDC0->LI0BA0);
++ }
++ }
++
++ }
++ #endif
++
++ dprintk("ioctl: lcd_img%d_set_baseaddr(0x%08x, 0x%08x, 0x%08x)\n", imgch, addr[0], addr[1], addr[2]);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_GET_BASEADDR:
++ {
++ unsigned int addr[3];
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++
++ tca_lcdc_getimgchbase(parm_lcdcid, parm_imgch, &addr[0], &addr[1], &addr[2]);
++ break;
++ default:
++ break;
++ }
++
++ copy_to_user((void *)arg, (const void *)addr, sizeof(unsigned int)*3);
++
++ dprintk("ioctl: lcd_img%d_get_baseaddr(0x%08x, 0x%08x, 0x%08x)\n", imgch, addr[0], addr[1], addr[2]);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_SET_ADDROFFSET:
++ {
++ unsigned int offset[2];
++
++ copy_from_user((void *)offset, (const void *)arg, sizeof(unsigned int)*2);
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++
++ tca_lcdc_setimgchOffsetInfo(parm_lcdcid, parm_imgch, offset[0], offset[1]);
++ break;
++ default:
++ break;
++ }
++
++ dprintk("ioctl: lcd_img%d_set_offsetinfo(0x%08x, 0x%08x)\n", imgch, offset[0], offset[1]);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_SET_IMGWINDOW:
++ {
++ unsigned int value[4];
++ unsigned int fmt;
++
++ copy_from_user((void *)value, (const void *)arg, sizeof(unsigned int)*4);
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++
++ tca_lcdc_getimgchfmt(parm_lcdcid, parm_imgch, &fmt);
++ tca_lcdc_setimgchwindow(parm_lcdcid, parm_imgch, value[0], value[1], value[2], value[3]);
++ tca_lcdc_setaddroffset(parm_lcdcid, parm_imgch, value[2], fmt);
++
++ tcc_m2m_refresh();
++
++ break;
++ default:
++ break;
++ }
++
++ dprintk("ioctl: lcd_img%d_setimgwindow_sx(%d)sy(%d)w(%d)h(%d)\n", imgch, value[0], value[1], value[2], value[3]);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_SET_R2YCONV_OPTION:
++ {
++ unsigned int value[2];
++
++ copy_from_user((void *)value, (const void *)arg, sizeof(unsigned int)*2);
++
++ switch(value[0])
++ {
++ case 0:
++ case 1:
++ tca_lcdc_setr2yconvopt(value[0], value[1]);
++ break;
++ default:
++ break;
++ }
++ dprintk("ioctl: lcdc%d_set_r2yconvopt(%d)\n", value[0], value[1]);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_GET_R2YCONV_OPTION:
++ {
++ unsigned int value[2];
++
++ copy_from_user((void *)value, (const void *)arg, sizeof(unsigned int)*2);
++
++ switch(value[0])
++ {
++ case 0:
++ case 1:
++ tca_lcdc_getr2yconvopt(value[0], &value[1]);
++ break;
++ default:
++ break;
++ }
++
++ copy_to_user((void *)arg, (const void *)value, sizeof(unsigned int)*2);
++
++ dprintk("ioctl: lcdc%d_get_r2yconvopt(%d)\n", value[0], value[1]);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_SET_IMG_Y2RCONV_OPTION:
++ {
++ unsigned int value;
++
++ copy_from_user((void *)&value, (const void *)arg, sizeof(unsigned int));
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++ tca_lcdc_setimgy2rconvopt(parm_lcdcid, parm_imgch, value);
++ break;
++ default:
++ break;
++ }
++
++ dprintk("ioctl: lcdc%d.img%d_set_imgconvopt(%d)\n", parm_lcdcid, imgch, value);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_GET_IMG_Y2RCONV_OPTION:
++ {
++ unsigned int value;
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++
++ tca_lcdc_getimgy2rconvopt(parm_lcdcid, parm_imgch, &value);
++ break;
++ default:
++ break;
++ }
++
++ copy_to_user((void *)arg, (const void *)&value, sizeof(unsigned int));
++
++ dprintk("ioctl: lcdc%d.img%d_get_imgconvopt(%d)\n", parm_lcdcid, imgch, value);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_SET_COLOR_ENAHNCEMENT:
++ {
++ unsigned int value[4];
++
++ copy_from_user((void *)value, (const void *)arg, sizeof(unsigned int)*4);
++
++ switch(value[0])
++ {
++ case 0:
++ case 1:
++ tca_lcdc_setcolorenhancement(value[0], value[1], value[2], value[3]);
++ break;
++ default:
++ break;
++ }
++ dprintk("ioctl: lcdc%d_set_colorenhancement(hue:%d,bright:%d,contrast:%d)\n", value[0], value[1], value[2], value[3]);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_GET_COLOR_ENAHNCEMENT:
++ {
++ unsigned int value[4];
++
++ copy_from_user((void *)value, (const void *)arg, sizeof(unsigned int)*4);
++
++ switch(value[0])
++ {
++ case 0:
++ case 1:
++ tca_lcdc_getcolorenhancement(value[0], &value[1], &value[2], &value[3]);
++ break;
++ default:
++ break;
++ }
++
++ copy_to_user((void *)arg, (const void *)value, sizeof(unsigned int)*4);
++
++ dprintk("ioctl: lcdc%d_get_colorenhancement(hue:%d,bright:%d,contrast:%d)\n", value[0], value[1], value[2], value[3]);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_SET_IMAGE_ENAHNCEMENT:
++ {
++ unsigned int value[3];
++
++ copy_from_user((void *)value, (const void *)arg, sizeof(unsigned int)*3);
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++ tca_lcdc_setimgenhancement(parm_lcdcid, parm_imgch, value[0], value[1], value[2]);
++ break;
++ default:
++ break;
++ }
++
++ dprintk("ioctl: lcdc%d.img%d_set_imageenhancement(hue:%d,bright:%d,contrast:%d)\n", parm_lcdcid, imgch, value[0], value[1], value[2]);
++ }
++ break;
++
++ case TCC_LCD_FB_IOCTL_GET_IMAGE_ENAHNCEMENT:
++ {
++ unsigned int value[3];
++
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = imgch;
++
++ switch(imgch)
++ {
++ case 0: //img0
++ case 1: //img1
++ case 2: //img2
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(imgch == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(imgch == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++
++ tca_lcdc_getimgenhancement(parm_lcdcid, parm_imgch, &value[0], &value[1], &value[2]);
++ break;
++ default:
++ break;
++ }
++
++ copy_to_user((void *)arg, (const void *)value, sizeof(unsigned int)*3);
++
++ dprintk("ioctl: lcdc%d.img%d_get_imageenhancement(hue:%d,bright:%d,contrast:%d)\n", parm_lcdcid, imgch, value[0], value[1], value[2]);
++ }
++ break;
++
++#if 0
++ //@lcdc info set/get (new method!)
++ case TCC_LCD_FB_IOCTL_LCDC_SETALLINFO :
++ {
++ copy_from_user((void *)g_pLCDCInfo, (const void *)arg, sizeof(TCC_LCDC_INFO));
++ LCDC_SetAllInfo(g_pLCDCInfo);
++ }
++
++ break;
++
++ case TCC_LCD_FB_IOCTL_LCDC_GETALLINFO :
++ {
++ LCDC_GetAllInfo(g_pLCDCInfo);
++ copy_to_user((void *)arg, (const void *)g_pLCDCInfo, sizeof(TCC_LCDC_INFO));
++ }
++
++ break;
++
++ case TCC_LCD_FB_IOCTL_LCDC_SETDISPLAYINFO :
++ {
++ copy_from_user((void *)g_pLCDCDisInfo, (const void *)arg, sizeof(TCC_LCDC_DISPLAY_INFO));
++ LCDC_SetDisplayInfo(g_pLCDCDisInfo);
++ }
++
++ break;
++
++ case TCC_LCD_FB_IOCTL_LCDC_GETDISPLAYINFO :
++ {
++ LCDC_GetDisplayInfo(g_pLCDCDisInfo);
++ copy_to_user((void *)arg, (const void *)g_pLCDCDisInfo, sizeof(TCC_LCDC_DISPLAY_INFO));
++ }
++
++ break;
++
++ case TCC_LCD_FB_IOCTL_LCDC_SETINTERFACEINFO :
++ {
++ copy_from_user((void *)g_pLCDCIfInfo, (const void *)arg, sizeof(TCC_LCDC_INTERFACE_INFO));
++ LCDC_SetInterfaceInfo(g_pLCDCIfInfo);
++ }
++
++ break;
++
++ case TCC_LCD_FB_IOCTL_LCDC_GETINTERFACEINFO :
++ {
++ LCDC_GetInterfaceInfo(g_pLCDCIfInfo);
++ copy_to_user((void *)arg, (const void *)g_pLCDCIfInfo, sizeof(TCC_LCDC_INTERFACE_INFO));
++ }
++
++ break;
++
++ case TCC_LCD_FB_IOCTL_LCDC_SETIMGCH0INFO :
++ {
++ copy_from_user((void *)g_pLCDCImgChInfo[TCC_LCDC_IMGCH0], (const void *)arg, sizeof(TCC_LCDC_IMGCH_INFO));
++ LCDC_SetImgChInfo(TCC_LCDC_IMGCH0, g_pLCDCImgChInfo[TCC_LCDC_IMGCH0]);
++ }
++
++ break;
++
++ case TCC_LCD_FB_IOCTL_LCDC_SETIMGCH1INFO :
++ {
++ copy_from_user((void *)g_pLCDCImgChInfo[TCC_LCDC_IMGCH1], (const void *)arg, sizeof(TCC_LCDC_IMGCH_INFO));
++ LCDC_SetImgChInfo(TCC_LCDC_IMGCH1, g_pLCDCImgChInfo[TCC_LCDC_IMGCH1]);
++ }
++
++ break;
++
++ case TCC_LCD_FB_IOCTL_LCDC_SETIMGCH2INFO :
++ {
++ copy_from_user((void *)g_pLCDCImgChInfo[TCC_LCDC_IMGCH2], (const void *)arg, sizeof(TCC_LCDC_IMGCH_INFO));
++ LCDC_SetImgChInfo(TCC_LCDC_IMGCH2, g_pLCDCImgChInfo[TCC_LCDC_IMGCH2]);
++ }
++
++ break;
++
++
++ case TCC_LCD_FB_IOCTL_LCDC_GETIMGCH0INFO :
++ {
++ LCDC_GetImgChInfo(TCC_LCDC_IMGCH0, g_pLCDCImgChInfo[TCC_LCDC_IMGCH0]);
++ copy_to_user((void *)arg, (const void *)g_pLCDCImgChInfo[TCC_LCDC_IMGCH0], sizeof(TCC_LCDC_IMGCH_INFO));
++ }
++
++ break;
++
++ case TCC_LCD_FB_IOCTL_LCDC_GETIMGCH1INFO :
++ {
++ LCDC_GetImgChInfo(TCC_LCDC_IMGCH1, g_pLCDCImgChInfo[TCC_LCDC_IMGCH1]);
++ copy_to_user((void *)arg, (const void *)g_pLCDCImgChInfo[TCC_LCDC_IMGCH1], sizeof(TCC_LCDC_IMGCH_INFO));
++ }
++
++ break;
++
++ case TCC_LCD_FB_IOCTL_LCDC_GETIMGCH2INFO :
++ {
++ LCDC_GetImgChInfo(TCC_LCDC_IMGCH2, g_pLCDCImgChInfo[TCC_LCDC_IMGCH2]);
++ copy_to_user((void *)arg, (const void *)g_pLCDCImgChInfo[TCC_LCDC_IMGCH2], sizeof(TCC_LCDC_IMGCH_INFO));
++ }
++
++ break;
++
++
++ case TCC_LCD_FB_IOCTL_LCDC_SETLAYER1INFO :
++ {
++ copy_from_user((void *)g_pLCDCLayerInfo[TCC_LCDC_LAYER1], (const void *)arg, sizeof(TCC_LCDC_LAYER_INFO));
++ LCDC_SetLayerInfo(TCC_LCDC_LAYER1, g_pLCDCLayerInfo[TCC_LCDC_LAYER1]);
++ }
++
++ break;
++
++ case TCC_LCD_FB_IOCTL_LCDC_SETLAYER2INFO :
++ {
++ copy_from_user((void *)g_pLCDCLayerInfo[TCC_LCDC_LAYER2], (const void *)arg, sizeof(TCC_LCDC_LAYER_INFO));
++ LCDC_SetLayerInfo(TCC_LCDC_LAYER2, g_pLCDCLayerInfo[TCC_LCDC_LAYER2]);
++ }
++
++ break;
++
++ case TCC_LCD_FB_IOCTL_LCDC_GETLAYER1INFO :
++ {
++ LCDC_GetLayerInfo(TCC_LCDC_LAYER1, g_pLCDCLayerInfo[TCC_LCDC_LAYER1]);
++ copy_to_user((void *)arg, (const void *)g_pLCDCLayerInfo[TCC_LCDC_LAYER1], sizeof(TCC_LCDC_LAYER_INFO));
++ }
++
++ break;
++
++ case TCC_LCD_FB_IOCTL_LCDC_GETLAYER2INFO :
++ {
++ LCDC_GetLayerInfo(TCC_LCDC_LAYER2, g_pLCDCLayerInfo[TCC_LCDC_LAYER2]);
++ copy_to_user((void *)arg, (const void *)g_pLCDCLayerInfo[TCC_LCDC_LAYER2], sizeof(TCC_LCDC_LAYER_INFO));
++ }
++
++ break;
++ //~end
++#endif
++
++ //@tvo
++ #ifdef TV_OUT_INCLUDE
++ case TCC_LCD_FB_IOCTL_TVOUT_TYPE:
++ case TCC_LCD_FB_IOCTL_TVOUT_OPEN:
++ case TCC_LCD_FB_IOCTL_TVOUT_CLOSE:
++ case TCC_LCD_FB_IOCTL_TVOUT_CONNECT_LCDC:
++ tvo_ioctl(cmd, arg);
++ break;
++ #endif
++
++ default:
++ dprintk("ioctl: Unknown [%d/0x%X]", cmd, cmd);
++ break;
++
++ }
++
++#if 1
++ for (ch_num=0; ch_num<CONFIG_FB_TCC_DEVS; ch_num++)
++ {
++ parm_lcdcid = MAIN_LCDC_ID;
++ parm_imgch = ch_num;
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ if(ch_num == 2)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #elif defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ if(ch_num == 0)
++ {
++ parm_lcdcid = 0;
++ parm_imgch = 0;
++ }
++ #endif
++
++ tca_lcdc_getimgchfmt(parm_lcdcid, parm_imgch, &curr_fmt[ch_num]);
++
++ if (prev_fmt[ch_num] != curr_fmt[ch_num])
++ {
++ if (fb_mem_vaddr[ch_num] != NULL)
++ {
++ memset(fb_mem_vaddr[ch_num], 0, fb_mem_size[ch_num]);
++ }
++ }
++ }
++#endif
++
++ return 0;
++}
++
++static void schedule_palette_update(struct tccfb_info *fbi,
++ unsigned int regno, unsigned int val)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ local_irq_restore(flags);
++}
++
++/* from pxafb.c */
++static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
++{
++ chan &= 0xffff;
++ chan >>= 16 - bf->length;
++ return chan << bf->offset;
++}
++
++static int tccfb_setcolreg(unsigned regno,
++ unsigned red, unsigned green, unsigned blue,
++ unsigned transp, struct fb_info *info)
++{
++ struct tccfb_info *fbi = info->par;
++ unsigned int val;
++
++ /* dprintk("setcol: regno=%d, rgb=%d,%d,%d\n", regno, red, green, blue); */
++
++ switch (fbi->fb->fix.visual) {
++ case FB_VISUAL_TRUECOLOR:
++ /* true-colour, use pseuo-palette */
++
++ if (regno < 16) {
++ u32 *pal = fbi->fb->pseudo_palette;
++
++ val = chan_to_field(red, &fbi->fb->var.red);
++ val |= chan_to_field(green, &fbi->fb->var.green);
++ val |= chan_to_field(blue, &fbi->fb->var.blue);
++
++ pal[regno] = val;
++ }
++ break;
++
++ case FB_VISUAL_PSEUDOCOLOR:
++ if (regno < 256) {
++ /* currently assume RGB 5-6-5 mode */
++
++ val = ((red >> 0) & 0xf800);
++ val |= ((green >> 5) & 0x07e0);
++ val |= ((blue >> 11) & 0x001f);
++
++ //writel(val, S3C2410_TFTPAL(regno));
++ schedule_palette_update(fbi, regno, val);
++ }
++
++ break;
++
++ default:
++ return 1; /* unknown type */
++ }
++
++ return 0;
++}
++
++
++/**
++ * tccfb_blank
++ * @blank_mode: the blank mode we want.
++ * @info: frame buffer structure that represents a single frame buffer
++ *
++ * Blank the screen if blank_mode != 0, else unblank. Return 0 if
++ * blanking succeeded, != 0 if un-/blanking failed due to e.g. a
++ * video mode which doesn't support it. Implements VESA suspend
++ * and powerdown modes on hardware that supports disabling hsync/vsync:
++ * blank_mode == 2: suspend vsync
++ * blank_mode == 3: suspend hsync
++ * blank_mode == 4: powerdown
++ *
++ * Returns negative errno on error, or zero on success.
++ *
++ */
++static int tccfb_blank(int blank_mode, struct fb_info *info)
++{
++// printk(KERN_EMERG"blank(mode=%d, info=%p)\n", blank_mode, info);
++ extern int ts_en;
++ switch (blank_mode) {
++ case VESA_NO_BLANKING: /* lcd on, backlight on */
++ if(0 == tvo_status() && ts_en == 1)
++ bl_control(1);
++ break;
++ case VESA_VSYNC_SUSPEND: /* lcd on, backlight off */
++ case VESA_HSYNC_SUSPEND:
++ bl_control(0);
++ break;
++ case VESA_POWERDOWN + 1: // XXX: compatible with X
++ case VESA_POWERDOWN: /* lcd and backlight off */
++ tcc_lcd_off();
++ break;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static struct fb_ops tccfb_ops = {
++ .owner = THIS_MODULE,
++ .fb_check_var = tccfb_check_var,
++ .fb_set_par = tccfb_set_par,
++ .fb_blank = tccfb_blank,
++ .fb_setcolreg = tccfb_setcolreg,
++ .fb_fillrect = cfb_fillrect,
++ .fb_copyarea = cfb_copyarea,
++ .fb_imageblit = cfb_imageblit,
++ .fb_ioctl = tccfb_ioctl,
++ .fb_pan_display = tccfb_pan_display,
++};
++
++
++/*
++ * tccfb_map_video_memory():
++ * Allocates the DRAM memory for the frame buffer. This buffer is
++ * remapped into a non-cached, non-buffered, memory region to
++ * allow palette and pixel writes to occur without flushing the
++ * cache. Once this area is remapped, all virtual memory
++ * access to the video memory should occur at the new region.
++ */
++static int __init tccfb_map_video_memory(struct tccfb_info *fbi, int plane)
++{
++ dprintk("map_video_memory(fbi=%p), map_size:%08x\n", fbi, fbi->map_size);
++#if (0)
++// if(plane==0)
++ fbi->map_size = PAGE_ALIGN(fbi->fb->fix.smem_len + PAGE_SIZE);
++// else
++/// fbi->map_size = PAGE_ALIGN(fbi->fb->fix.smem_len*4 + PAGE_SIZE);
++ // allocate the memory space for frame buffer,
++ // fbi->map_cpu store the virtual address
++ // fbi->map_dma store the physical address
++ fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
++ &fbi->map_dma, GFP_KERNEL);
++
++ fbi->map_size = fbi->fb->fix.smem_len;
++#else
++
++ fbi->map_dma = 0;
++ fbi->map_size = 0;
++
++ fb_reseved_mem_paddr[0] = TCC_FB_OFFSET;
++ fb_reseved_mem_paddr[1] = TCC_FB_OFFSET + TCC_FB0_SIZE;
++ fb_reseved_mem_paddr[2] = TCC_FB_OFFSET + TCC_FB0_SIZE + TCC_FB1_SIZE;
++
++ if(request_mem_region(fb_reseved_mem_paddr[plane], fb_reseved_mem_size[plane], "tccfb"))
++ {
++ fbi->fb->fix.smem_start = fb_reseved_mem_paddr[plane];
++ fbi->fb->fix.smem_len = fb_reseved_mem_size [plane];
++
++ fbi->map_dma = fbi->fb->fix.smem_start;
++ fbi->map_size = fbi->fb->fix.smem_len;
++
++ fbi->map_cpu = ioremap(fbi->map_dma, fbi->map_size);
++
++ if (!fbi->map_cpu) {
++ printk("fb[%d]: failed ioremap::0x%08lX\n", (int)plane, (unsigned long)fbi->map_dma);
++ }
++ }
++ else
++ {
++ printk("fb[%d]: failed request_mem_region::0x%08lX\n", (int)plane, (unsigned long)fbi->map_dma);
++ }
++#endif
++
++ if (fbi->map_cpu) {
++ /* prevent initial garbage on screen */
++ dprintk("map_video_memory: clear %p:%08x\n",
++ fbi->map_cpu, fbi->map_size);
++ memset(fbi->map_cpu, 0xff, fbi->map_size);
++
++ fbi->screen_dma = fbi->map_dma;
++ fbi->fb->screen_base = fbi->map_cpu;
++ fbi->fb->fix.smem_start = fbi->screen_dma;
++
++ // Set the LCD frame buffer start address
++ switch (plane)
++ {
++ case 2: // IMG2
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ pLCDC0->LI0BA0 = fbi->map_dma;
++ fb_mem_vaddr[plane] = fbi->map_cpu;
++ fb_mem_size [plane] = fbi->map_size;
++ #else
++ pLCDC1->LI2BA0 = fbi->map_dma;
++ fb_mem_vaddr[plane] = fbi->map_cpu;
++ fb_mem_size [plane] = fbi->map_size;
++ #endif
++ break;
++ case 1: // IMG1
++ pLCDC1->LI1BA0 = fbi->map_dma;
++ fb_mem_vaddr[plane] = fbi->map_cpu;
++ fb_mem_size [plane] = fbi->map_size;
++ break;
++ case 0: // IMG0
++ #if defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ pLCDC0->LI0BA0 = fbi->map_dma;
++ fb_mem_vaddr[plane] = fbi->map_cpu;
++ fb_mem_size [plane] = fbi->map_size;
++ #else
++ pLCDC1->LI0BA0 = fbi->map_dma;
++ fb_mem_vaddr[plane] = fbi->map_cpu;
++ fb_mem_size [plane] = fbi->map_size;
++ #endif
++ break;
++ }
++#if 0
++ dprintk("map_video_memory: dma=%08x cpu=%p size=%08x\n",
++ fbi->map_dma, fbi->map_cpu, fbi->fb->fix.smem_len);
++#else
++ printk("fb[%d]::map_video_memory: dma=%08x cpu=%p size=%08x\n",
++ plane, fbi->map_dma, fbi->map_cpu, fbi->fb->fix.smem_len);
++#endif
++ }
++
++ return fbi->map_cpu ? 0 : -ENOMEM;
++}
++
++static inline void tccfb_unmap_video_memory(struct tccfb_info *fbi)
++{
++#if (0)
++ dma_free_writecombine(fbi->dev,fbi->map_size,fbi->map_cpu, fbi->map_dma);
++#else
++ iounmap(fbi->map_cpu);
++ release_mem_region(fbi->map_dma, fbi->map_size);
++#endif
++
++ fb_mem_vaddr[fbi->imgch] = (u_char*)NULL;
++ fb_mem_size [fbi->imgch] = (u_int)NULL;
++}
++
++static irqreturn_t tcc_lcd_handler0(int irq, void *dev_id)
++{
++ if(pLCDC0->LSTATUS & Hw3)
++ {
++ tcc_lcdc_interrupt(0, 0);
++
++ lcdc_struct[0].state = 1;
++ wake_up_interruptible(&lcdc_struct[0].waitq);
++
++ }
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t tcc_lcd_handler(int irq, void *dev_id)
++{
++ if(pLCDC1->LSTATUS & Hw3)
++ {
++ tcc_lcdc_interrupt(1, 0);
++
++ lcdc_struct[1].state = 1;
++ wake_up_interruptible(&lcdc_struct[1].waitq);
++
++ }
++ return IRQ_HANDLED;
++}
++
++static char tccfb_driver_name[]="tccfb";
++static int __init tccfb_probe(struct platform_device *pdev)
++{
++ struct tccfb_info *info;
++ struct fb_info *fbinfo;
++ int ret;
++ int plane = 0;
++// unsigned int layer_en = 0;
++ unsigned int tmp_value= 0;
++
++ dprintk("+probe\n");
++
++ // LCD 3-Layer(RGB565) Enable
++ switch(CONFIG_FB_TCC_DEVS)
++ {
++ case 3:
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ pLCDC0->LI0S = (fb_height[2] << 16) | (fb_width[2]); //Size
++ pLCDC0->LI0P = 0|0; // position
++ pLCDC0->LI0SR = 0;
++ tmp_value = pLCDC0->LI0C | (1<<28); // | image enable
++ switch(default_scn_depth[2])
++ {
++ case 32:
++ pLCDC0->LI0C = (tmp_value & 0xFFFFFFE0) | (0x000C);//RGB888
++ pLCDC0->LI0O = (fb_width[2]*4);
++ break;
++ case 16:
++ default:
++ pLCDC0->LI0C = (tmp_value & 0xFFFFFFE0) | (0x000A);//RGB565
++ pLCDC0->LI0O = (fb_width[2]*2);
++ break;
++ }
++
++ pLCDC1->LI2C = pLCDC1->LI2C & ~(1<<28); // image disable
++ #else
++ //HwLI2BA0 =bakHwLI2BA0;
++ pLCDC1->LI2S = (fb_height[2] << 16) | (fb_width[2]); //Size
++ pLCDC1->LI2P = 0|0; // position
++ pLCDC1->LI2SR = 0;
++ tmp_value = pLCDC1->LI2C | (1<<28); // | image enable
++ switch(default_scn_depth[2])
++ {
++ case 32:
++ pLCDC1->LI2C = (tmp_value & 0xFFFFFFE0) | (0x000C);//RGB888
++ pLCDC1->LI2O = (fb_width[2]*4);
++ break;
++ case 16:
++ default:
++ pLCDC1->LI2C = (tmp_value & 0xFFFFFFE0) | (0x000A);//RGB565
++ pLCDC1->LI2O = (fb_width[2]*2);
++ break;
++ }
++ #endif
++ case 2:
++ //HwLI1BA0 =bakHwLI1BA0;
++ pLCDC1->LI1S = (fb_height[1] << 16) | (fb_width[1]); //Size
++ pLCDC1->LI1P = 0|0; // position
++ pLCDC1->LI1SR = 0;
++
++ #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++ tmp_value = pLCDC1->LI1C & ~(1<<28); // | image disable
++ #else
++ tmp_value = pLCDC1->LI1C | (1<<28); // | image enable
++ #endif
++ switch(default_scn_depth[1])
++ {
++ case 32:
++ pLCDC1->LI1C = (tmp_value & 0xFFFFFFE0) | (0x000C);//RGB888
++ pLCDC1->LI1O = (fb_width[1]*4);
++ break;
++ case 16:
++ default:
++ pLCDC1->LI1C = (tmp_value & 0xFFFFFFE0) | (0x000A);//RGB565
++ pLCDC1->LI1O = (fb_width[1]*2);
++ break;
++ }
++ case 1:
++ if(CONFIG_FB_TCC_DEVS < 3)
++ {
++ tmp_value = pLCDC1->LI2C & ~(1<<28);
++ pLCDC1->LI2C = tmp_value;
++
++ if(CONFIG_FB_TCC_DEVS < 2)
++ {
++ tmp_value = pLCDC1->LI1C & ~(1<<28);
++ pLCDC1->LI1C = tmp_value;
++ }
++ }
++ #if defined(DEMO_LOADSHOW_LCD_LVDSHDMI)
++ //HwLI0BA0 =bakHwLI0BA0;
++ pLCDC0->LI0S = (fb_height[0] << 16) | (fb_width[0]); //Size
++ pLCDC0->LI0P = 0|0; // position
++ pLCDC0->LI0SR = 0;
++// #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++// tmp_value = pLCDC1->LI0C & ~(1<<28); // | image disable
++// #else
++ tmp_value = pLCDC0->LI0C | (1<<28); // | image enable
++// #endif
++ switch(default_scn_depth[0])
++ {
++ case 32:
++ pLCDC0->LI0C = (tmp_value & 0xFFFFFFE0) | (0x000C); //RGB888
++ pLCDC0->LI0O = (fb_width[0]*4);
++ break;
++ case 16:
++ default:
++ pLCDC0->LI0C = (tmp_value & 0xFFFFFFE0) | (0x000A); //RGB565
++ pLCDC0->LI0O = (fb_width[0]*2);
++ break;
++ }
++ #else
++ //HwLI0BA0 =bakHwLI0BA0;
++ pLCDC1->LI0S = (fb_height[0] << 16) | (fb_width[0]); //Size
++ pLCDC1->LI0P = 0|0; // position
++ pLCDC1->LI0SR = 0;
++// #if defined(DEMO_LOADSHOW_LCD_HDMI) || defined(DEMO_LOADSHOW_LCD_LVDS)
++// tmp_value = pLCDC1->LI0C & ~(1<<28); // | image disable
++// #else
++ tmp_value = pLCDC1->LI0C | (1<<28); // | image enable
++// #endif
++ switch(default_scn_depth[0])
++ {
++ case 32:
++ pLCDC1->LI0C = (tmp_value & 0xFFFFFFE0) | (0x000C); //RGB888
++ pLCDC1->LI0O = (fb_width[0]*4);
++ break;
++ case 16:
++ default:
++ pLCDC1->LI0C = (tmp_value & 0xFFFFFFE0) | (0x000A); //RGB565
++ pLCDC1->LI0O = (fb_width[0]*2);
++ break;
++ }
++ #endif
++ break;
++ }
++
++ /*mach_info = pdev->dev.platform_data;
++ if (mach_info == NULL) {
++ dev_err(&pdev->dev,"no platform data for lcd, cannot attach\n");
++ //return -EINVAL;
++ }
++ */
++ for (plane = 0; plane < CONFIG_FB_TCC_DEVS; plane++)
++ {
++ fbinfo = framebuffer_alloc(sizeof(struct tccfb_info), &pdev->dev);
++
++ info = fbinfo->par;
++ info->fb = fbinfo;
++ //platform_set_drvdata(pdev, fbinfo);
++
++ strcpy(fbinfo->fix.id, tccfb_driver_name);
++
++ //info->mach_info = pdev->dev.platform_data;
++ //init the lcd
++ lcd_init_hw();
++
++ fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
++ fbinfo->fix.type_aux = 0;
++ fbinfo->fix.xpanstep = 0;
++#ifdef TCC_FB_DOUBLE_
++ if(plane == 0)
++ fbinfo->fix.ypanstep = 1;
++ else
++ fbinfo->fix.ypanstep = 0;
++#else
++ fbinfo->fix.ypanstep = 0;
++#endif
++ fbinfo->fix.ywrapstep = 0;
++ fbinfo->fix.line_length = fb_width[plane] * (default_scn_depth[plane]/8);
++ fbinfo->fix.accel = FB_ACCEL_NONE;
++
++ fbinfo->var.nonstd = 0;
++ fbinfo->var.activate = FB_ACTIVATE_NOW;
++
++ fbinfo->var.height = fb_height[plane];
++ fbinfo->var.width = fb_width[plane];
++ fbinfo->var.accel_flags = 0;
++ fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
++
++ fbinfo->fbops = &tccfb_ops;
++ fbinfo->flags = FBINFO_FLAG_DEFAULT;
++
++ fbinfo->pseudo_palette = info->pseudo_pal;
++
++ fbinfo->var.xres = fb_width[plane];
++ fbinfo->var.xres_virtual = fb_width[plane];
++ fbinfo->var.yres = fb_height[plane];
++#ifdef TCC_FB_DOUBLE_
++ if(plane == 0)
++ fbinfo->var.yres_virtual = fb_height[plane] * 2;
++ else
++ fbinfo->var.yres_virtual = fb_height[plane];
++#else
++ fbinfo->var.yres_virtual = fb_height[plane];
++#endif
++ fbinfo->var.bits_per_pixel = default_scn_depth[plane];
++
++ tccfb_check_var(&fbinfo->var, fbinfo);
++
++#if (0)
++ // the memory size that LCD should occupy
++#ifdef TCC_FB_DOUBLE_
++ fbinfo->fix.smem_len = fbinfo->var.xres *
++ fbinfo->var.yres *
++ SCREEN_DEPTH_MAX / 8 * 2;
++#else
++ fbinfo->fix.smem_len = fbinfo->var.xres *
++ fbinfo->var.yres *
++ SCREEN_DEPTH_MAX / 8;
++#endif
++#endif
++
++//#ifdef POST_SET
++ if (plane == 0)
++ {
++// tca_ckc_setperi(PERI_LCD1,ENABLE,1560000,PCDIRECTPLL1);
++// msleep(1);
++ }
++//#endif
++
++ info->imgch = plane;
++
++ /* Initialize video memory */
++ ret = tccfb_map_video_memory(info, plane);
++ if (ret) {
++ printk( KERN_ERR "Failed to allocate video RAM: %d\n", ret);
++ ret = -ENOMEM;
++ }
++
++ ret = register_framebuffer(fbinfo);
++ if (ret < 0) {
++ printk(KERN_ERR "Failed to register framebuffer device: %d\n", ret);
++ goto free_video_memory;
++ }
++
++ tccfb_set_par(fbinfo);
++ msleep(1);
++
++// if (plane == (CONFIG_FB_TCC_DEVS-1)) // top layer
++ if (fb_prepare_logo(fbinfo, FB_ROTATE_UR)) {
++ /* Start display and show logo on boot */
++ fb_set_cmap(&fbinfo->cmap, fbinfo);
++
++ dprintk("fb_show_logo\n");
++ fb_show_logo(fbinfo, FB_ROTATE_UR);
++ }
++
++ printk(KERN_INFO "fb%d: %s frame buffer device\n",
++ fbinfo->node, fbinfo->fix.id);
++ }
++
++ init_waitqueue_head(&lcdc_struct[0].waitq);
++ init_waitqueue_head(&lcdc_struct[1].waitq);
++
++#if 1
++ request_irq(IRQ_LCD1,
++ tcc_lcd_handler,
++ IRQF_SHARED,
++ "TCC_LCD",
++ tcc_lcd_handler);
++
++ request_irq(IRQ_LCD0,
++ tcc_lcd_handler0,
++ IRQF_SHARED,
++ "TCC_LCD",
++ tcc_lcd_handler0);
++
++#endif
++ /*
++ tcc_start_lcd_int_dd();
++ tcc_set_reg_for_int_dd();
++ */
++ tcc_lcd_on();
++ dprintk("-probe\n");
++ return 0;
++
++free_video_memory:
++ tccfb_unmap_video_memory(info);
++ dprintk("-probe:Error\n");
++ return ret;
++}
++
++/* tccfb_stop_lcd
++ *
++ * shutdown the lcd controller
++*/
++
++static void tccfb_stop_lcd(struct tccfb_info *fbi)
++{
++ dprintk("stop_lcd\n");
++ return;
++}
++
++/*
++ * Cleanup
++ */
++static int tccfb_remove(struct platform_device *pdev)
++{
++ struct fb_info *fbinfo = platform_get_drvdata(pdev);
++ struct tccfb_info *info = fbinfo->par;
++
++ dprintk("remove\n");
++
++ tcc_stop_lcd_int_dd();
++ free_irq(IRQ_LCD1, tcc_lcd_handler);
++
++ tccfb_stop_lcd(info);
++// tca_ckc_setperi(PERI_LCD1,DISABLE,1560000,PCDIRECTPLL1);
++// msleep(1);
++
++ tccfb_unmap_video_memory(info);
++
++ //release_mem_region((unsigned long)S3C24XX_VA_LCD, S3C24XX_SZ_LCD);
++ unregister_framebuffer(fbinfo);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++
++/* suspend and resume support for the lcd controller */
++
++static int tccfb_suspend(struct platform_device *dev, pm_message_t state)
++{
++ PTIMER vTimerAddr = (PTIMER)((unsigned int)&HwTMR_BASE);
++ PGPIO vGpioAddr = (PGPIO)((unsigned int)&HwGPIO_BASE);
++
++ *(volatile unsigned long *)0xF0204000 |= 0x1;// enable LCD0 before suspend
++
++ tca_bkl_powerdown((unsigned int)vTimerAddr,(unsigned int)vGpioAddr);
++
++ //@tvo
++ #ifdef TV_OUT_INCLUDE
++ tvo_powerdown();
++ #endif
++
++ return 0;
++}
++
++extern int curblight;
++static int tccfb_resume(struct platform_device *dev)
++{
++ PTIMER vTimerAddr = (PTIMER)((unsigned int)&HwTMR_BASE);
++ PGPIO vGpioAddr = (PGPIO)((unsigned int)&HwGPIO_BASE);
++
++ //@tvo
++ #ifdef TV_OUT_INCLUDE
++ tvo_powerup();
++ #endif
++
++ tca_bkl_powerup((unsigned int)vTimerAddr,(unsigned int)vGpioAddr);
++ tca_bkl_setpowerval(curblight,(unsigned int)vTimerAddr);
++
++ return 0;
++}
++
++static void tccfb_shutdown(struct platform_device *dev)
++{
++ pm_message_t state = {0};
++ tccfb_suspend(dev, state);
++}
++
++#else
++#define tccfb_suspend NULL
++#define tccfb_resume NULL
++#define tccfb_shutdown NULL
++#endif
++
++static struct platform_driver tccfb_driver = {
++ .probe = tccfb_probe,
++ .remove = tccfb_remove,
++ .suspend = tccfb_suspend,
++ .shutdown = tccfb_shutdown,
++ .resume = tccfb_resume,
++ .driver = {
++ .name = "tccxxx-lcd",
++ .owner = THIS_MODULE,
++ },
++};
++
++//int __devinit tccfb_init(void)
++static int __init tccfb_init(void)
++{
++ dprintk("init\n");
++
++ tcc_regbase_init();
++
++ //@tvo
++ #ifdef TV_OUT_INCLUDE
++ tvo_init();
++ #endif
++
++ return platform_driver_register(&tccfb_driver);
++}
++
++static void __exit tccfb_cleanup(void)
++{
++ //@tvo
++ #ifdef TV_OUT_INCLUDE
++ tvo_cleanup();
++ #endif
++
++ platform_driver_unregister(&tccfb_driver);
++}
++
++
++module_init(tccfb_init);
++module_exit(tccfb_cleanup);
++
++MODULE_AUTHOR("linux <linux@telechips.com>");
++MODULE_DESCRIPTION("Telechips TCC Framebuffer driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/video/tccfb.h b/drivers/video/tccfb.h
+new file mode 100644
+index 0000000..c122b61
+--- /dev/null
++++ b/drivers/video/tccfb.h
+@@ -0,0 +1,55 @@
++/*
++ * linux/drivers/video/tccfb.h
++ *
++ * Author: <linux@telechips.com>
++ * Created: June 10, 2008
++ * Description: TCC LCD Controller Frame Buffer Driver
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#ifndef __TCCFB_H
++#define __TCCFB_H
++
++struct tccfb_info {
++ struct fb_info *fb;
++ struct device *dev;
++
++ //struct tccfb_mach_info *mach_info;
++
++ /* raw memory addresses */
++ dma_addr_t map_dma; /* physical */
++ u_char * map_cpu; /* virtual */
++ u_int map_size;
++
++ /* addresses of pieces placed in raw buffer */
++ u_char * screen_cpu; /* virtual address of buffer */
++ dma_addr_t screen_dma; /* physical address of buffer */
++
++ /* keep these registers in case we need to re-write palette */
++ unsigned int pseudo_pal[16];
++
++ u_int imgch;
++
++};
++
++#define PALETTE_BUFF_CLEAR (0x80000000) /* entry is clear/invalid */
++
++//int tccfb_init(void);
++
++#endif
+diff --git a/drivers/video/tccfb_a070vw04.c b/drivers/video/tccfb_a070vw04.c
+new file mode 100644
+index 0000000..db2a6ba
+--- /dev/null
++++ b/drivers/video/tccfb_a070vw04.c
+@@ -0,0 +1,96 @@
++
++#include <linux/wait.h>
++#include <linux/fb.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++#include <mach/gpio.h>
++
++#define LCD_SCEN TCC_GPC29
++#define LCD_SCL TCC_GPC30
++#define LCD_SDA TCC_GPC31
++
++static void us_delay(unsigned int dly)
++{
++ udelay(dly);
++}
++
++static void write_bit(unsigned char val)
++{
++ gpio_set_value(LCD_SCL, 0); // SCL = 0
++ gpio_set_value(LCD_SDA, val); // SDA = val
++ us_delay(1000);
++ gpio_set_value(LCD_SCL, 1); // SCL = 1
++ us_delay(1000);
++}
++
++static unsigned int read_bit()
++{
++ gpio_set_value(LCD_SCL, 0); // SCL = 0
++ unsigned int data = tcc_gpio_getpin(LCD_SDA); // SDA
++ us_delay(1000);
++ gpio_set_value(LCD_SCL, 1); // SCL = 1
++ us_delay(1000);
++ return data;
++}
++
++static void write_reg(unsigned char addr, unsigned short data)
++{
++ unsigned char i;
++ gpio_set_value(LCD_SCEN, 0); // CSB pin of LCD = 0
++ /* transfer the register address bits (4 bit) */
++ for(i=0; i<4; i++) {
++ if(addr & 0x8)
++ write_bit(1);
++ else
++ write_bit(0);
++ addr <<= 1;
++ }
++ /* transfer the write mode bit (1 bit) */
++ write_bit(0);
++ /* transfer the data bits (11 bits) */
++ write_bit(0);
++ for(i=0; i<10; i++) {
++ if(data & 0x200)
++ write_bit(1);
++ else
++ write_bit(0);
++ data <<= 1;
++ }
++ gpio_set_value(LCD_SCEN, 1); // CSB pin of LCD = 1
++}
++
++static unsigned int read_reg(unsigned char addr)
++{
++ unsigned char i;
++ unsigned int data = 0x0;
++ gpio_set_value(LCD_SCEN, 0); // CSB pin of LCD = 0
++ /* transfer the register address bits (4 bit) */
++ for(i=0; i<4; i++) {
++ if(addr & 0x8)
++ write_bit(1);
++ else
++ write_bit(0);
++ addr <<= 1;
++ }
++ /* transfer the read or read mode (1 bit) */
++ write_bit(1);
++ /* transfer the data (11 bits) */
++ write_bit(0);
++ for(i=0; i<10; i++) {
++ data |= (read_bit() << i);
++ }
++ gpio_set_value(LCD_SCEN, 1); // CSB pin of LCD = 1
++
++ return data;
++}
++
++void lcd_init_hw(void)
++{
++ gpio_direction_output(LCD_SCEN, 1); // GPM0 <---> CSB pin of LCD
++ gpio_direction_output(LCD_SCL, 1); // GPM1 <---> SCL pin of LCD
++ gpio_direction_output(LCD_SDA, 1); // GPM2 <---> SDA pin of LCD
++ write_reg(0x0, 0x2d3);
++ //write_reg(0x1, 0x181);
++ write_reg(0x4, 0x19f);
++}
++
+diff --git a/drivers/video/tccfb_td043mtex.c b/drivers/video/tccfb_td043mtex.c
+new file mode 100644
+index 0000000..0e66a27
+--- /dev/null
++++ b/drivers/video/tccfb_td043mtex.c
+@@ -0,0 +1,124 @@
++#include <linux/wait.h>
++#include <linux/fb.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++
++#include <mach/gpio.h>
++
++#define LCD_SCEN TCC_GPC29
++#define LCD_SCL TCC_GPC30
++#define LCD_SDA TCC_GPC31
++#define S3C_GPIO_OUTP 1
++#define S3C_GPIO_INP 0
++
++static int lcd_write(unsigned char,unsigned char);
++static void lcd_spi_stop(void);
++static void lcd_spi_start(void);
++static void lcd_spi_start(void)
++{
++ gpio_direction_output(LCD_SCEN, 0);
++}
++
++static void lcd_spi_stop(void)
++{
++ gpio_direction_output(LCD_SCEN, 1);
++ gpio_set_value(LCD_SCL,0);
++ gpio_set_value(LCD_SDA,0);
++ gpio_direction_input(LCD_SCL);
++ gpio_direction_input(LCD_SDA);
++}
++
++static int lcd_write(unsigned char addr,unsigned char data)
++{
++ unsigned char myaddr,mydata,i;
++ myaddr = (addr&0x3f)<<1 ;
++ myaddr <<= 1;
++ myaddr |= 0x1;
++ lcd_spi_start();
++
++ gpio_direction_output(LCD_SCL, 0);
++ tcc_gpio_cfgpin(LCD_SDA, 0, TCC_GPIO_OUTPUT);
++
++ for(i=0;i<8;i++){
++ gpio_set_value(LCD_SCL,0);
++ udelay(1);
++ gpio_set_value(LCD_SDA,(myaddr&0x80)>>7);
++ myaddr <<= 1 ;
++ udelay(1);
++ gpio_set_value(LCD_SCL,1);
++ udelay(1);
++ } //8nd is null turn
++ mydata = data;
++ for(i=0;i<8;i++){
++ gpio_set_value(LCD_SCL,0);
++ udelay(1);
++ gpio_set_value(LCD_SDA,(mydata&0x80)>>7);
++ mydata <<= 1;
++ udelay(1);
++ gpio_set_value(LCD_SCL,1);
++ udelay(1);
++ }
++
++ lcd_spi_stop();
++
++ return 0;
++}
++
++void lcd_init_hw(void)
++{
++ lcd_spi_stop();
++
++ lcd_write(0x02,0x07);
++ lcd_write(0x03,0x5f);
++ lcd_write(0x04,0x17);
++
++ lcd_write(0x05,0x20);
++ lcd_write(0x06,0x08);
++
++ lcd_write(0x07,0x20);
++ lcd_write(0x08,0x20);
++ lcd_write(0x09,0x20);
++ lcd_write(0x0a,0x20);
++
++ lcd_write(0x0b,0x20);
++ lcd_write(0x0c,0x20);
++ lcd_write(0x0d,0x22);
++
++ lcd_write(0x0e,0x10);
++ lcd_write(0x0f,0x10);
++ lcd_write(0x10,0x10);
++
++ lcd_write(0x11,0x15);
++ lcd_write(0x12,0xaa);
++ lcd_write(0x13,0xff);
++ lcd_write(0x14,0x86);
++ lcd_write(0x15,0x89);
++ lcd_write(0x16,0xc6);
++ lcd_write(0x17,0xea);
++ lcd_write(0x18,0x0c);
++ lcd_write(0x19,0x33);
++ lcd_write(0x1a,0x5e);
++ lcd_write(0x1b,0xd0);
++ lcd_write(0x1c,0x33);
++ lcd_write(0x1d,0x7e);
++ lcd_write(0x1e,0xb3);
++ lcd_write(0x1f,0xff);
++ lcd_write(0x20,0xf0);
++ lcd_write(0x21,0xf0);
++ lcd_write(0x22,0x08);
++}
++
++void lcd_standby(void)
++{
++ lcd_spi_stop();
++ lcd_write(0x03,0x00);
++}
++EXPORT_SYMBOL(lcd_standby);
++
++
++void lcd_normal(void)
++{
++ lcd_spi_stop();
++ lcd_write(0x03,0x5f);
++}
++EXPORT_SYMBOL(lcd_normal);
+diff --git a/fs/Kconfig b/fs/Kconfig
+index 522469a..6ef091b 100644
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -1122,6 +1122,8 @@ config UFS_DEBUG
+ Y here. This will result in _many_ additional debugging messages to be
+ written to the system log.
+
++source "fs/aufs/Kconfig"
++
+ endmenu
+
+ menuconfig NETWORK_FILESYSTEMS
+diff --git a/fs/Makefile b/fs/Makefile
+index d9f8afe..1f206a2 100644
+--- a/fs/Makefile
++++ b/fs/Makefile
+@@ -122,3 +122,4 @@ obj-$(CONFIG_HPPFS) += hppfs/
+ obj-$(CONFIG_DEBUG_FS) += debugfs/
+ obj-$(CONFIG_OCFS2_FS) += ocfs2/
+ obj-$(CONFIG_GFS2_FS) += gfs2/
++obj-$(CONFIG_AUFS_FS) += aufs/
+diff --git a/fs/aufs/Kconfig b/fs/aufs/Kconfig
+new file mode 100644
+index 0000000..4edbc95
+--- /dev/null
++++ b/fs/aufs/Kconfig
+@@ -0,0 +1,125 @@
++config AUFS_FS
++ tristate "Aufs (Advanced multi layered unification filesystem) support"
++ depends on EXPERIMENTAL
++ help
++ Aufs is a stackable unification filesystem such as Unionfs,
++ which unifies several directories and provides a merged single
++ directory.
++ In the early days, aufs was entirely re-designed and
++ re-implemented Unionfs Version 1.x series. Introducing many
++ original ideas, approaches and improvements, it becomes totally
++ different from Unionfs while keeping the basic features.
++
++if AUFS_FS
++choice
++ prompt "Maximum number of branches"
++ default AUFS_BRANCH_MAX_127
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++config AUFS_BRANCH_MAX_127
++ bool "127"
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++config AUFS_BRANCH_MAX_511
++ bool "511"
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++config AUFS_BRANCH_MAX_1023
++ bool "1023"
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++config AUFS_BRANCH_MAX_32767
++ bool "32767"
++ help
++ Specifies the maximum number of branches (or member directories)
++ in a single aufs. The larger value consumes more system
++ resources and has a minor impact to performance.
++endchoice
++
++config AUFS_HINOTIFY
++ bool "Use inotify to detect actions on a branch"
++ depends on INOTIFY
++ help
++ If you want to modify files on branches directly, eg. bypassing aufs,
++ and want aufs to detect the changes of them fully, then enable this
++ option and use 'udba=inotify' mount option.
++ It will have a negative impact to the performance.
++ See detail in aufs.5.
++
++config AUFS_EXPORT
++ bool "NFS-exportable aufs"
++ depends on (AUFS_FS = y && EXPORTFS = y) || (AUFS_FS = m && EXPORTFS)
++ help
++ If you want to export your mounted aufs via NFS, then enable this
++ option. There are several requirements for this configuration.
++ See detail in aufs.5.
++
++config AUFS_RDU
++ bool "Readdir in userspace"
++ help
++ If you have millions of files under a single aufs directory, and
++ meet the out of memory, then enable this option and set
++ environment variables for your readdir(3).
++ See detail in aufs.5.
++
++config AUFS_SHWH
++ bool "Show whiteouts"
++ help
++ If you want to make the whiteouts in aufs visible, then enable
++ this option and specify 'shwh' mount option. Although it may
++ sounds like philosophy or something, but in technically it
++ simply shows the name of whiteout with keeping its behaviour.
++
++config AUFS_BR_RAMFS
++ bool "Ramfs (initramfs/rootfs) as an aufs branch"
++ help
++ If you want to use ramfs as an aufs branch fs, then enable this
++ option. Generally tmpfs is recommended.
++ Aufs prohibited them to be a branch fs by default, because
++ initramfs becomes unusable after switch_root or something
++ generally. If you sets initramfs as an aufs branch and boot your
++ system by switch_root, you will meet a problem easily since the
++ files in initramfs may be inaccessible.
++ Unless you are going to use ramfs as an aufs branch fs without
++ switch_root or something, leave it N.
++
++config AUFS_DEBUG
++ bool "Debug aufs"
++ help
++ Enable this to compile aufs internal debug code.
++ It will have a negative impact to the performance.
++
++config AUFS_MAGIC_SYSRQ
++ bool
++ depends on AUFS_DEBUG && MAGIC_SYSRQ
++ default y
++ help
++ Automatic configuration for internal use.
++ When aufs supports Magic SysRq, enabled automatically.
++
++config AUFS_BDEV_LOOP
++ bool
++ depends on BLK_DEV_LOOP
++ default y
++ help
++ Automatic configuration for internal use.
++ Convert =[ym] into =y.
++
++config AUFS_INO_T_64
++ bool
++ depends on AUFS_EXPORT
++ depends on 64BIT && !(ALPHA || S390)
++ default y
++ help
++ Automatic configuration for internal use.
++ /* typedef unsigned long/int __kernel_ino_t */
++ /* alpha and s390x are int */
++endif
+diff --git a/fs/aufs/Makefile b/fs/aufs/Makefile
+new file mode 100644
+index 0000000..df6995a
+--- /dev/null
++++ b/fs/aufs/Makefile
+@@ -0,0 +1,23 @@
++
++include ${src}/magic.mk
++-include ${src}/priv_def.mk
++
++obj-$(CONFIG_AUFS_FS) += aufs.o
++aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \
++ wkq.o vfsub.o dcsub.o \
++ cpup.o whout.o plink.o wbr_policy.o \
++ dinfo.o dentry.o \
++ finfo.o file.o f_op.o \
++ dir.o vdir.o \
++ iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \
++ ioctl.o
++
++# all are boolean
++aufs-$(CONFIG_SYSFS) += sysfs.o
++aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o
++aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o
++aufs-$(CONFIG_AUFS_HINOTIFY) += hinotify.o
++aufs-$(CONFIG_AUFS_EXPORT) += export.o
++aufs-$(CONFIG_AUFS_RDU) += rdu.o
++aufs-$(CONFIG_AUFS_DEBUG) += debug.o
++aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o
+diff --git a/fs/aufs/aufs.h b/fs/aufs/aufs.h
+new file mode 100644
+index 0000000..96307bb
+--- /dev/null
++++ b/fs/aufs/aufs.h
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * all header files
++ */
++
++#ifndef __AUFS_H__
++#define __AUFS_H__
++
++#ifdef __KERNEL__
++
++#include "debug.h"
++
++#include "branch.h"
++#include "cpup.h"
++#include "dcsub.h"
++#include "dbgaufs.h"
++#include "dentry.h"
++#include "dir.h"
++#include "file.h"
++#include "fstype.h"
++#include "inode.h"
++#include "loop.h"
++#include "module.h"
++#include "opts.h"
++#include "rwsem.h"
++#include "spl.h"
++#include "super.h"
++#include "sysaufs.h"
++#include "vfsub.h"
++#include "whout.h"
++#include "wkq.h"
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_H__ */
+diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c
+new file mode 100644
+index 0000000..aeedaf4
+--- /dev/null
++++ b/fs/aufs/branch.c
+@@ -0,0 +1,974 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * branch management
++ */
++
++#include <linux/file.h>
++#include "aufs.h"
++
++/*
++ * free a single branch
++ */
++static void au_br_do_free(struct au_branch *br)
++{
++ int i;
++ struct au_wbr *wbr;
++
++ if (br->br_xino.xi_file)
++ fput(br->br_xino.xi_file);
++ mutex_destroy(&br->br_xino.xi_nondir_mtx);
++
++ AuDebugOn(atomic_read(&br->br_count));
++
++ wbr = br->br_wbr;
++ if (wbr) {
++ for (i = 0; i < AuBrWh_Last; i++)
++ dput(wbr->wbr_wh[i]);
++ AuDebugOn(atomic_read(&wbr->wbr_wh_running));
++ AuRwDestroy(&wbr->wbr_wh_rwsem);
++ }
++
++ /* some filesystems acquire extra lock */
++ lockdep_off();
++ mntput(br->br_mnt);
++ lockdep_on();
++
++ kfree(wbr);
++ kfree(br);
++}
++
++/*
++ * frees all branches
++ */
++void au_br_free(struct au_sbinfo *sbinfo)
++{
++ aufs_bindex_t bmax;
++ struct au_branch **br;
++
++ AuRwMustWriteLock(&sbinfo->si_rwsem);
++
++ bmax = sbinfo->si_bend + 1;
++ br = sbinfo->si_branch;
++ while (bmax--)
++ au_br_do_free(*br++);
++}
++
++/*
++ * find the index of a branch which is specified by @br_id.
++ */
++int au_br_index(struct super_block *sb, aufs_bindex_t br_id)
++{
++ aufs_bindex_t bindex, bend;
++
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++)
++ if (au_sbr_id(sb, bindex) == br_id)
++ return bindex;
++ return -1;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * add a branch
++ */
++
++static int test_overlap(struct super_block *sb, struct dentry *h_d1,
++ struct dentry *h_d2)
++{
++ if (unlikely(h_d1 == h_d2))
++ return 1;
++ return !!au_test_subdir(h_d1, h_d2)
++ || !!au_test_subdir(h_d2, h_d1)
++ || au_test_loopback_overlap(sb, h_d1, h_d2)
++ || au_test_loopback_overlap(sb, h_d2, h_d1);
++}
++
++/*
++ * returns a newly allocated branch. @new_nbranch is a number of branches
++ * after adding a branch.
++ */
++static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
++ int perm)
++{
++ struct au_branch *add_branch;
++ struct dentry *root;
++
++ root = sb->s_root;
++ add_branch = kmalloc(sizeof(*add_branch), GFP_NOFS);
++ if (unlikely(!add_branch))
++ goto out;
++
++ add_branch->br_wbr = NULL;
++ if (au_br_writable(perm)) {
++ /* may be freed separately at changing the branch permission */
++ add_branch->br_wbr = kmalloc(sizeof(*add_branch->br_wbr),
++ GFP_NOFS);
++ if (unlikely(!add_branch->br_wbr))
++ goto out_br;
++ }
++
++ if (unlikely(au_sbr_realloc(au_sbi(sb), new_nbranch)
++ || au_di_realloc(au_di(root), new_nbranch)
++ || au_ii_realloc(au_ii(root->d_inode), new_nbranch)))
++ goto out_wbr;
++ return add_branch; /* success */
++
++ out_wbr:
++ kfree(add_branch->br_wbr);
++ out_br:
++ kfree(add_branch);
++ out:
++ return ERR_PTR(-ENOMEM);
++}
++
++/*
++ * test if the branch permission is legal or not.
++ */
++static int test_br(struct inode *inode, int brperm, char *path)
++{
++ int err;
++
++ err = 0;
++ if (unlikely(au_br_writable(brperm) && IS_RDONLY(inode))) {
++ AuErr("write permission for readonly mount or inode, %s\n",
++ path);
++ err = -EINVAL;
++ }
++
++ return err;
++}
++
++/*
++ * returns:
++ * 0: success, the caller will add it
++ * plus: success, it is already unified, the caller should ignore it
++ * minus: error
++ */
++static int test_add(struct super_block *sb, struct au_opt_add *add, int remount)
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct dentry *root;
++ struct inode *inode, *h_inode;
++
++ root = sb->s_root;
++ bend = au_sbend(sb);
++ if (unlikely(bend >= 0
++ && au_find_dbindex(root, add->path.dentry) >= 0)) {
++ err = 1;
++ if (!remount) {
++ err = -EINVAL;
++ AuErr("%s duplicated\n", add->pathname);
++ }
++ goto out;
++ }
++
++ err = -ENOSPC; /* -E2BIG; */
++ if (unlikely(AUFS_BRANCH_MAX <= add->bindex
++ || AUFS_BRANCH_MAX - 1 <= bend)) {
++ AuErr("number of branches exceeded %s\n", add->pathname);
++ goto out;
++ }
++
++ err = -EDOM;
++ if (unlikely(add->bindex < 0 || bend + 1 < add->bindex)) {
++ AuErr("bad index %d\n", add->bindex);
++ goto out;
++ }
++
++ inode = add->path.dentry->d_inode;
++ err = -ENOENT;
++ if (unlikely(!inode->i_nlink)) {
++ AuErr("no existence %s\n", add->pathname);
++ goto out;
++ }
++
++ err = -EINVAL;
++ if (unlikely(inode->i_sb == sb)) {
++ AuErr("%s must be outside\n", add->pathname);
++ goto out;
++ }
++
++ if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) {
++ AuErr("unsupported filesystem, %s (%s)\n",
++ add->pathname, au_sbtype(inode->i_sb));
++ goto out;
++ }
++
++ err = test_br(add->path.dentry->d_inode, add->perm, add->pathname);
++ if (unlikely(err))
++ goto out;
++
++ if (bend < 0)
++ return 0; /* success */
++
++ err = -EINVAL;
++ for (bindex = 0; bindex <= bend; bindex++)
++ if (unlikely(test_overlap(sb, add->path.dentry,
++ au_h_dptr(root, bindex)))) {
++ AuErr("%s is overlapped\n", add->pathname);
++ goto out;
++ }
++
++ err = 0;
++ if (au_opt_test(au_mntflags(sb), WARN_PERM)) {
++ h_inode = au_h_dptr(root, 0)->d_inode;
++ if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO)
++ || h_inode->i_uid != inode->i_uid
++ || h_inode->i_gid != inode->i_gid)
++ AuWarn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n",
++ add->pathname,
++ inode->i_uid, inode->i_gid,
++ (inode->i_mode & S_IALLUGO),
++ h_inode->i_uid, h_inode->i_gid,
++ (h_inode->i_mode & S_IALLUGO));
++ }
++
++ out:
++ return err;
++}
++
++/*
++ * initialize or clean the whiteouts for an adding branch
++ */
++static int au_br_init_wh(struct super_block *sb, struct au_branch *br,
++ int new_perm, struct dentry *h_root)
++{
++ int err, old_perm;
++ aufs_bindex_t bindex;
++ struct mutex *h_mtx;
++ struct au_wbr *wbr;
++ struct au_hinode *hdir;
++
++ wbr = br->br_wbr;
++ old_perm = br->br_perm;
++ br->br_perm = new_perm;
++ hdir = NULL;
++ h_mtx = NULL;
++ bindex = au_br_index(sb, br->br_id);
++ if (0 <= bindex) {
++ hdir = au_hi(sb->s_root->d_inode, bindex);
++ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ } else {
++ h_mtx = &h_root->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_PARENT);
++ }
++ if (!wbr)
++ err = au_wh_init(h_root, br, sb);
++ else {
++ wbr_wh_write_lock(wbr);
++ err = au_wh_init(h_root, br, sb);
++ wbr_wh_write_unlock(wbr);
++ }
++ if (hdir)
++ au_hin_imtx_unlock(hdir);
++ else
++ mutex_unlock(h_mtx);
++ br->br_perm = old_perm;
++
++ if (!err && wbr && !au_br_writable(new_perm)) {
++ kfree(wbr);
++ br->br_wbr = NULL;
++ }
++
++ return err;
++}
++
++static int au_wbr_init(struct au_branch *br, struct super_block *sb,
++ int perm, struct path *path)
++{
++ int err;
++ struct au_wbr *wbr;
++
++ wbr = br->br_wbr;
++ au_rw_init(&wbr->wbr_wh_rwsem);
++ memset(wbr->wbr_wh, 0, sizeof(wbr->wbr_wh));
++ atomic_set(&wbr->wbr_wh_running, 0);
++ wbr->wbr_bytes = 0;
++
++ err = au_br_init_wh(sb, br, perm, path->dentry);
++
++ return err;
++}
++
++/* intialize a new branch */
++static int au_br_init(struct au_branch *br, struct super_block *sb,
++ struct au_opt_add *add)
++{
++ int err;
++
++ err = 0;
++ memset(&br->br_xino, 0, sizeof(br->br_xino));
++ mutex_init(&br->br_xino.xi_nondir_mtx);
++ br->br_perm = add->perm;
++ br->br_mnt = add->path.mnt; /* set first, mntget() later */
++ atomic_set(&br->br_count, 0);
++ br->br_xino_upper = AUFS_XINO_TRUNC_INIT;
++ atomic_set(&br->br_xino_running, 0);
++ br->br_id = au_new_br_id(sb);
++
++ if (au_br_writable(add->perm)) {
++ err = au_wbr_init(br, sb, add->perm, &add->path);
++ if (unlikely(err))
++ goto out;
++ }
++
++ if (au_opt_test(au_mntflags(sb), XINO)) {
++ err = au_xino_br(sb, br, add->path.dentry->d_inode->i_ino,
++ au_sbr(sb, 0)->br_xino.xi_file, /*do_test*/1);
++ if (unlikely(err)) {
++ AuDebugOn(br->br_xino.xi_file);
++ goto out;
++ }
++ }
++
++ sysaufs_br_init(br);
++ mntget(add->path.mnt);
++
++ out:
++ return err;
++}
++
++static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex,
++ struct au_branch *br, aufs_bindex_t bend,
++ aufs_bindex_t amount)
++{
++ struct au_branch **brp;
++
++ AuRwMustWriteLock(&sbinfo->si_rwsem);
++
++ brp = sbinfo->si_branch + bindex;
++ memmove(brp + 1, brp, sizeof(*brp) * amount);
++ *brp = br;
++ sbinfo->si_bend++;
++ if (unlikely(bend < 0))
++ sbinfo->si_bend = 0;
++}
++
++static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex,
++ aufs_bindex_t bend, aufs_bindex_t amount)
++{
++ struct au_hdentry *hdp;
++
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ hdp = dinfo->di_hdentry + bindex;
++ memmove(hdp + 1, hdp, sizeof(*hdp) * amount);
++ au_h_dentry_init(hdp);
++ dinfo->di_bend++;
++ if (unlikely(bend < 0))
++ dinfo->di_bstart = 0;
++}
++
++static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex,
++ aufs_bindex_t bend, aufs_bindex_t amount)
++{
++ struct au_hinode *hip;
++
++ AuRwMustWriteLock(&iinfo->ii_rwsem);
++
++ hip = iinfo->ii_hinode + bindex;
++ memmove(hip + 1, hip, sizeof(*hip) * amount);
++ hip->hi_inode = NULL;
++ au_hin_init(hip, NULL);
++ iinfo->ii_bend++;
++ if (unlikely(bend < 0))
++ iinfo->ii_bstart = 0;
++}
++
++static void au_br_do_add(struct super_block *sb, struct dentry *h_dentry,
++ struct au_branch *br, aufs_bindex_t bindex)
++{
++ struct dentry *root;
++ struct inode *root_inode;
++ aufs_bindex_t bend, amount;
++
++ root = sb->s_root;
++ root_inode = root->d_inode;
++ au_plink_block_maintain(sb);
++ bend = au_sbend(sb);
++ amount = bend + 1 - bindex;
++ au_br_do_add_brp(au_sbi(sb), bindex, br, bend, amount);
++ au_br_do_add_hdp(au_di(root), bindex, bend, amount);
++ au_br_do_add_hip(au_ii(root_inode), bindex, bend, amount);
++ au_set_h_dptr(root, bindex, dget(h_dentry));
++ au_set_h_iptr(root_inode, bindex, au_igrab(h_dentry->d_inode),
++ /*flags*/0);
++}
++
++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount)
++{
++ int err;
++ unsigned long long maxb;
++ aufs_bindex_t bend, add_bindex;
++ struct dentry *root, *h_dentry;
++ struct inode *root_inode;
++ struct au_branch *add_branch;
++
++ root = sb->s_root;
++ root_inode = root->d_inode;
++ IMustLock(root_inode);
++ err = test_add(sb, add, remount);
++ if (unlikely(err < 0))
++ goto out;
++ if (err) {
++ err = 0;
++ goto out; /* success */
++ }
++
++ bend = au_sbend(sb);
++ add_branch = au_br_alloc(sb, bend + 2, add->perm);
++ err = PTR_ERR(add_branch);
++ if (IS_ERR(add_branch))
++ goto out;
++
++ err = au_br_init(add_branch, sb, add);
++ if (unlikely(err)) {
++ au_br_do_free(add_branch);
++ goto out;
++ }
++
++ add_bindex = add->bindex;
++ h_dentry = add->path.dentry;
++ if (!remount)
++ au_br_do_add(sb, h_dentry, add_branch, add_bindex);
++ else {
++ sysaufs_brs_del(sb, add_bindex);
++ au_br_do_add(sb, h_dentry, add_branch, add_bindex);
++ sysaufs_brs_add(sb, add_bindex);
++ }
++
++ if (!add_bindex)
++ au_cpup_attr_all(root_inode, /*force*/1);
++ else
++ au_add_nlink(root_inode, h_dentry->d_inode);
++ maxb = h_dentry->d_sb->s_maxbytes;
++ if (sb->s_maxbytes < maxb)
++ sb->s_maxbytes = maxb;
++
++ /*
++ * this test/set prevents aufs from handling unnecesary inotify events
++ * of xino files, in a case of re-adding a writable branch which was
++ * once detached from aufs.
++ */
++ if (au_xino_brid(sb) < 0
++ && au_br_writable(add_branch->br_perm)
++ && !au_test_fs_bad_xino(h_dentry->d_sb)
++ && add_branch->br_xino.xi_file
++ && add_branch->br_xino.xi_file->f_dentry->d_parent == h_dentry)
++ au_xino_brid_set(sb, add_branch->br_id);
++
++ out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * delete a branch
++ */
++
++/* to show the line number, do not make it inlined function */
++#define AuVerbose(do_info, fmt, args...) do { \
++ if (do_info) \
++ AuInfo(fmt, ##args); \
++} while (0)
++
++/*
++ * test if the branch is deletable or not.
++ */
++static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex,
++ unsigned int sigen)
++{
++ int err, i, j, ndentry;
++ aufs_bindex_t bstart, bend;
++ unsigned char verbose;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry *d;
++ struct inode *inode;
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_dcsub_pages(&dpages, root, NULL, NULL);
++ if (unlikely(err))
++ goto out_dpages;
++
++ verbose = !!au_opt_test(au_mntflags(root->d_sb), VERBOSE);
++ for (i = 0; !err && i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ ndentry = dpage->ndentry;
++ for (j = 0; !err && j < ndentry; j++) {
++ d = dpage->dentries[j];
++ AuDebugOn(!atomic_read(&d->d_count));
++ inode = d->d_inode;
++ if (au_digen(d) == sigen && au_iigen(inode) == sigen)
++ di_read_lock_child(d, AuLock_IR);
++ else {
++ di_write_lock_child(d);
++ err = au_reval_dpath(d, sigen);
++ if (!err)
++ di_downgrade_lock(d, AuLock_IR);
++ else {
++ di_write_unlock(d);
++ break;
++ }
++ }
++
++ bstart = au_dbstart(d);
++ bend = au_dbend(d);
++ if (bstart <= bindex
++ && bindex <= bend
++ && au_h_dptr(d, bindex)
++ && (!S_ISDIR(inode->i_mode) || bstart == bend)) {
++ err = -EBUSY;
++ AuVerbose(verbose, "busy %.*s\n", AuDLNPair(d));
++ }
++ di_read_unlock(d, AuLock_IR);
++ }
++ }
++
++ out_dpages:
++ au_dpages_free(&dpages);
++ out:
++ return err;
++}
++
++static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex,
++ unsigned int sigen)
++{
++ int err;
++ struct inode *i;
++ aufs_bindex_t bstart, bend;
++ unsigned char verbose;
++
++ err = 0;
++ verbose = !!au_opt_test(au_mntflags(sb), VERBOSE);
++ list_for_each_entry(i, &sb->s_inodes, i_sb_list) {
++ AuDebugOn(!atomic_read(&i->i_count));
++ if (!list_empty(&i->i_dentry))
++ continue;
++
++ if (au_iigen(i) == sigen)
++ ii_read_lock_child(i);
++ else {
++ ii_write_lock_child(i);
++ err = au_refresh_hinode_self(i, /*do_attr*/1);
++ if (!err)
++ ii_downgrade_lock(i);
++ else {
++ ii_write_unlock(i);
++ break;
++ }
++ }
++
++ bstart = au_ibstart(i);
++ bend = au_ibend(i);
++ if (bstart <= bindex
++ && bindex <= bend
++ && au_h_iptr(i, bindex)
++ && (!S_ISDIR(i->i_mode) || bstart == bend)) {
++ err = -EBUSY;
++ AuVerbose(verbose, "busy i%lu\n", i->i_ino);
++ ii_read_unlock(i);
++ break;
++ }
++ ii_read_unlock(i);
++ }
++
++ return err;
++}
++
++static int test_children_busy(struct dentry *root, aufs_bindex_t bindex)
++{
++ int err;
++ unsigned int sigen;
++
++ sigen = au_sigen(root->d_sb);
++ DiMustNoWaiters(root);
++ IiMustNoWaiters(root->d_inode);
++ di_write_unlock(root);
++ err = test_dentry_busy(root, bindex, sigen);
++ if (!err)
++ err = test_inode_busy(root->d_sb, bindex, sigen);
++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */
++
++ return err;
++}
++
++static void au_br_do_del_brp(struct au_sbinfo *sbinfo,
++ const aufs_bindex_t bindex,
++ const aufs_bindex_t bend)
++{
++ struct au_branch **brp, **p;
++
++ AuRwMustWriteLock(&sbinfo->si_rwsem);
++
++ brp = sbinfo->si_branch + bindex;
++ if (bindex < bend)
++ memmove(brp, brp + 1, sizeof(*brp) * (bend - bindex));
++ sbinfo->si_branch[0 + bend] = NULL;
++ sbinfo->si_bend--;
++
++ p = krealloc(sbinfo->si_branch, sizeof(*p) * bend, GFP_NOFS);
++ if (p)
++ sbinfo->si_branch = p;
++}
++
++static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex,
++ const aufs_bindex_t bend)
++{
++ struct au_hdentry *hdp, *p;
++
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ hdp = dinfo->di_hdentry + bindex;
++ if (bindex < bend)
++ memmove(hdp, hdp + 1, sizeof(*hdp) * (bend - bindex));
++ dinfo->di_hdentry[0 + bend].hd_dentry = NULL;
++ dinfo->di_bend--;
++
++ p = krealloc(dinfo->di_hdentry, sizeof(*p) * bend, GFP_NOFS);
++ if (p)
++ dinfo->di_hdentry = p;
++}
++
++static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex,
++ const aufs_bindex_t bend)
++{
++ struct au_hinode *hip, *p;
++
++ AuRwMustWriteLock(&iinfo->ii_rwsem);
++
++ hip = iinfo->ii_hinode + bindex;
++ if (bindex < bend)
++ memmove(hip, hip + 1, sizeof(*hip) * (bend - bindex));
++ iinfo->ii_hinode[0 + bend].hi_inode = NULL;
++ au_hin_init(iinfo->ii_hinode + bend, NULL);
++ iinfo->ii_bend--;
++
++ p = krealloc(iinfo->ii_hinode, sizeof(*p) * bend, GFP_NOFS);
++ if (p)
++ iinfo->ii_hinode = p;
++}
++
++static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex,
++ struct au_branch *br)
++{
++ aufs_bindex_t bend;
++ struct au_sbinfo *sbinfo;
++ struct dentry *root;
++ struct inode *inode;
++
++ SiMustWriteLock(sb);
++
++ root = sb->s_root;
++ inode = root->d_inode;
++ au_plink_block_maintain(sb);
++ sbinfo = au_sbi(sb);
++ bend = sbinfo->si_bend;
++
++ dput(au_h_dptr(root, bindex));
++ au_hiput(au_hi(inode, bindex));
++ au_br_do_free(br);
++
++ au_br_do_del_brp(sbinfo, bindex, bend);
++ au_br_do_del_hdp(au_di(root), bindex, bend);
++ au_br_do_del_hip(au_ii(inode), bindex, bend);
++}
++
++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount)
++{
++ int err, rerr, i;
++ unsigned int mnt_flags;
++ aufs_bindex_t bindex, bend, br_id;
++ unsigned char do_wh, verbose;
++ struct au_branch *br;
++ struct au_wbr *wbr;
++
++ err = 0;
++ bindex = au_find_dbindex(sb->s_root, del->h_path.dentry);
++ if (bindex < 0) {
++ if (remount)
++ goto out; /* success */
++ err = -ENOENT;
++ AuErr("%s no such branch\n", del->pathname);
++ goto out;
++ }
++ AuDbg("bindex b%d\n", bindex);
++
++ err = -EBUSY;
++ mnt_flags = au_mntflags(sb);
++ verbose = !!au_opt_test(mnt_flags, VERBOSE);
++ bend = au_sbend(sb);
++ if (unlikely(!bend)) {
++ AuVerbose(verbose, "no more branches left\n");
++ goto out;
++ }
++ br = au_sbr(sb, bindex);
++ i = atomic_read(&br->br_count);
++ if (unlikely(i)) {
++ AuVerbose(verbose, "%d file(s) opened\n", i);
++ goto out;
++ }
++
++ wbr = br->br_wbr;
++ do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph);
++ if (do_wh) {
++ /* instead of WbrWhMustWriteLock(wbr) */
++ SiMustWriteLock(sb);
++ for (i = 0; i < AuBrWh_Last; i++) {
++ dput(wbr->wbr_wh[i]);
++ wbr->wbr_wh[i] = NULL;
++ }
++ }
++
++ err = test_children_busy(sb->s_root, bindex);
++ if (unlikely(err)) {
++ if (do_wh)
++ goto out_wh;
++ goto out;
++ }
++
++ err = 0;
++ br_id = br->br_id;
++ if (!remount)
++ au_br_do_del(sb, bindex, br);
++ else {
++ sysaufs_brs_del(sb, bindex);
++ au_br_do_del(sb, bindex, br);
++ sysaufs_brs_add(sb, bindex);
++ }
++
++ if (!bindex)
++ au_cpup_attr_all(sb->s_root->d_inode, /*force*/1);
++ else
++ au_sub_nlink(sb->s_root->d_inode, del->h_path.dentry->d_inode);
++ if (au_opt_test(mnt_flags, PLINK))
++ au_plink_half_refresh(sb, br_id);
++
++ if (sb->s_maxbytes == del->h_path.dentry->d_sb->s_maxbytes) {
++ bend--;
++ sb->s_maxbytes = 0;
++ for (bindex = 0; bindex <= bend; bindex++) {
++ unsigned long long maxb;
++
++ maxb = au_sbr_sb(sb, bindex)->s_maxbytes;
++ if (sb->s_maxbytes < maxb)
++ sb->s_maxbytes = maxb;
++ }
++ }
++
++ if (au_xino_brid(sb) == br->br_id)
++ au_xino_brid_set(sb, -1);
++ goto out; /* success */
++
++ out_wh:
++ /* revert */
++ rerr = au_br_init_wh(sb, br, br->br_perm, del->h_path.dentry);
++ if (rerr)
++ AuWarn("failed re-creating base whiteout, %s. (%d)\n",
++ del->pathname, rerr);
++ out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * change a branch permission
++ */
++
++static int do_need_sigen_inc(int a, int b)
++{
++ return au_br_whable(a) && !au_br_whable(b);
++}
++
++static int need_sigen_inc(int old, int new)
++{
++ return do_need_sigen_inc(old, new)
++ || do_need_sigen_inc(new, old);
++}
++
++static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex)
++{
++ int err;
++ unsigned long n, ul, bytes, files;
++ aufs_bindex_t bstart;
++ struct file *file, *hf, **a;
++ const int step_bytes = 1024, /* memory allocation unit */
++ step_files = step_bytes / sizeof(*a);
++
++ err = -ENOMEM;
++ n = 0;
++ bytes = step_bytes;
++ files = step_files;
++ a = kmalloc(bytes, GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ /* no need file_list_lock() since sbinfo is locked? defered? */
++ list_for_each_entry(file, &sb->s_files, f_u.fu_list) {
++ if (special_file(file->f_dentry->d_inode->i_mode))
++ continue;
++
++ AuDbg("%.*s\n", AuDLNPair(file->f_dentry));
++ fi_read_lock(file);
++ if (unlikely(au_test_mmapped(file))) {
++ err = -EBUSY;
++ FiMustNoWaiters(file);
++ fi_read_unlock(file);
++ goto out_free;
++ }
++
++ bstart = au_fbstart(file);
++ if (!S_ISREG(file->f_dentry->d_inode->i_mode)
++ || !(file->f_mode & FMODE_WRITE)
++ || bstart != bindex) {
++ FiMustNoWaiters(file);
++ fi_read_unlock(file);
++ continue;
++ }
++
++ hf = au_h_fptr(file, bstart);
++ FiMustNoWaiters(file);
++ fi_read_unlock(file);
++
++ if (n < files)
++ a[n++] = hf;
++ else {
++ void *p;
++
++ err = -ENOMEM;
++ bytes += step_bytes;
++ files += step_files;
++ p = krealloc(a, bytes, GFP_NOFS);
++ if (p) {
++ a = p;
++ a[n++] = hf;
++ } else
++ goto out_free;
++ }
++ }
++
++ err = 0;
++ for (ul = 0; ul < n; ul++) {
++ /* todo: already flushed? */
++ /* cf. fs/super.c:mark_files_ro() */
++ hf = a[ul];
++ hf->f_mode &= ~FMODE_WRITE;
++ if (!file_check_writeable(hf)) {
++ file_release_write(hf);
++ mnt_drop_write(hf->f_vfsmnt);
++ }
++ }
++
++ out_free:
++ kfree(a);
++ out:
++ return err;
++}
++
++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount,
++ int *do_update)
++{
++ int err, rerr;
++ aufs_bindex_t bindex;
++ struct path path;
++ struct dentry *root;
++ struct au_branch *br;
++
++ root = sb->s_root;
++ au_plink_block_maintain(sb);
++ bindex = au_find_dbindex(root, mod->h_root);
++ if (bindex < 0) {
++ if (remount)
++ return 0; /* success */
++ err = -ENOENT;
++ AuErr("%s no such branch\n", mod->path);
++ goto out;
++ }
++ AuDbg("bindex b%d\n", bindex);
++
++ err = test_br(mod->h_root->d_inode, mod->perm, mod->path);
++ if (unlikely(err))
++ goto out;
++
++ br = au_sbr(sb, bindex);
++ if (br->br_perm == mod->perm)
++ return 0; /* success */
++
++ if (au_br_writable(br->br_perm)) {
++ /* remove whiteout base */
++ err = au_br_init_wh(sb, br, mod->perm, mod->h_root);
++ if (unlikely(err))
++ goto out;
++
++ if (!au_br_writable(mod->perm)) {
++ /* rw --> ro, file might be mmapped */
++ DiMustNoWaiters(root);
++ IiMustNoWaiters(root->d_inode);
++ di_write_unlock(root);
++ err = au_br_mod_files_ro(sb, bindex);
++ /* aufs_write_lock() calls ..._child() */
++ di_write_lock_child(root);
++
++ if (unlikely(err)) {
++ rerr = -ENOMEM;
++ br->br_wbr = kmalloc(sizeof(*br->br_wbr),
++ GFP_NOFS);
++ if (br->br_wbr) {
++ path.mnt = br->br_mnt;
++ path.dentry = mod->h_root;
++ rerr = au_wbr_init(br, sb, br->br_perm,
++ &path);
++ }
++ if (unlikely(rerr)) {
++ AuIOErr("nested error %d (%d)\n",
++ rerr, err);
++ br->br_perm = mod->perm;
++ }
++ }
++ }
++ } else if (au_br_writable(mod->perm)) {
++ /* ro --> rw */
++ err = -ENOMEM;
++ br->br_wbr = kmalloc(sizeof(*br->br_wbr), GFP_NOFS);
++ if (br->br_wbr) {
++ path.mnt = br->br_mnt;
++ path.dentry = mod->h_root;
++ err = au_wbr_init(br, sb, mod->perm, &path);
++ if (unlikely(err)) {
++ kfree(br->br_wbr);
++ br->br_wbr = NULL;
++ }
++ }
++ }
++
++ if (!err) {
++ *do_update |= need_sigen_inc(br->br_perm, mod->perm);
++ br->br_perm = mod->perm;
++ }
++
++ out:
++ return err;
++}
+diff --git a/fs/aufs/branch.h b/fs/aufs/branch.h
+new file mode 100644
+index 0000000..1a7219c
+--- /dev/null
++++ b/fs/aufs/branch.h
+@@ -0,0 +1,219 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * branch filesystems and xino for them
++ */
++
++#ifndef __AUFS_BRANCH_H__
++#define __AUFS_BRANCH_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/mount.h>
++#include <linux/aufs_type.h>
++#include "rwsem.h"
++#include "super.h"
++
++/* ---------------------------------------------------------------------- */
++
++/* a xino file */
++struct au_xino_file {
++ struct file *xi_file;
++ struct mutex xi_nondir_mtx;
++
++ /* todo: make xino files an array to support huge inode number */
++
++#ifdef CONFIG_DEBUG_FS
++ struct dentry *xi_dbgaufs;
++#endif
++};
++
++/* members for writable branch only */
++enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last};
++struct au_wbr {
++ struct au_rwsem wbr_wh_rwsem;
++ struct dentry *wbr_wh[AuBrWh_Last];
++ atomic_t wbr_wh_running;
++#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */
++#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */
++#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */
++
++ /* mfs mode */
++ unsigned long long wbr_bytes;
++};
++
++/* protected by superblock rwsem */
++struct au_branch {
++ struct au_xino_file br_xino;
++
++ aufs_bindex_t br_id;
++
++ int br_perm;
++ struct vfsmount *br_mnt;
++ atomic_t br_count;
++
++ struct au_wbr *br_wbr;
++
++ /* xino truncation */
++ blkcnt_t br_xino_upper; /* watermark in blocks */
++ atomic_t br_xino_running;
++
++#ifdef CONFIG_SYSFS
++ /* an entry under sysfs per mount-point */
++ char br_name[8];
++ struct attribute br_attr;
++#endif
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* branch permission and attribute */
++enum {
++ AuBrPerm_RW, /* writable, linkable wh */
++ AuBrPerm_RO, /* readonly, no wh */
++ AuBrPerm_RR, /* natively readonly, no wh */
++
++ AuBrPerm_RWNoLinkWH, /* un-linkable whiteouts */
++
++ AuBrPerm_ROWH, /* whiteout-able */
++ AuBrPerm_RRWH, /* whiteout-able */
++
++ AuBrPerm_Last
++};
++
++static inline int au_br_writable(int brperm)
++{
++ return brperm == AuBrPerm_RW || brperm == AuBrPerm_RWNoLinkWH;
++}
++
++static inline int au_br_whable(int brperm)
++{
++ return brperm == AuBrPerm_RW
++ || brperm == AuBrPerm_ROWH
++ || brperm == AuBrPerm_RRWH;
++}
++
++static inline int au_br_rdonly(struct au_branch *br)
++{
++ return ((br->br_mnt->mnt_sb->s_flags & MS_RDONLY)
++ || !au_br_writable(br->br_perm))
++ ? -EROFS : 0;
++}
++
++static inline int au_br_hinotifyable(int brperm __maybe_unused)
++{
++#ifdef CONFIG_AUFS_HINOTIFY
++ return brperm != AuBrPerm_RR && brperm != AuBrPerm_RRWH;
++#else
++ return 0;
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* branch.c */
++struct au_sbinfo;
++void au_br_free(struct au_sbinfo *sinfo);
++int au_br_index(struct super_block *sb, aufs_bindex_t br_id);
++struct au_opt_add;
++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount);
++struct au_opt_del;
++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount);
++struct au_opt_mod;
++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount,
++ int *do_update);
++
++/* xino.c */
++static const loff_t au_loff_max = LLONG_MAX;
++
++int au_xib_trunc(struct super_block *sb);
++ssize_t xino_fread(au_readf_t func, struct file *file, void *buf, size_t size,
++ loff_t *pos);
++ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size,
++ loff_t *pos);
++struct file *au_xino_create2(struct file *base_file, struct file *copy_src);
++struct file *au_xino_create(struct super_block *sb, char *fname, int silent);
++ino_t au_xino_new_ino(struct super_block *sb);
++int au_xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ ino_t ino);
++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ ino_t ino);
++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ ino_t *ino);
++int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t hino,
++ struct file *base_file, int do_test);
++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex);
++
++struct au_opt_xino;
++int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount);
++void au_xino_clr(struct super_block *sb);
++struct file *au_xino_def(struct super_block *sb);
++int au_xino_path(struct seq_file *seq, struct file *file);
++
++/* ---------------------------------------------------------------------- */
++
++/* Superblock to branch */
++static inline
++aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_sbr(sb, bindex)->br_id;
++}
++
++static inline
++struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_sbr(sb, bindex)->br_mnt;
++}
++
++static inline
++struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_sbr_mnt(sb, bindex)->mnt_sb;
++}
++
++static inline void au_sbr_put(struct super_block *sb, aufs_bindex_t bindex)
++{
++ atomic_dec_return(&au_sbr(sb, bindex)->br_count);
++}
++
++static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_sbr(sb, bindex)->br_perm;
++}
++
++static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex)
++{
++ return au_br_whable(au_sbr_perm(sb, bindex));
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * wbr_wh_read_lock, wbr_wh_write_lock
++ * wbr_wh_read_unlock, wbr_wh_write_unlock, wbr_wh_downgrade_lock
++ */
++AuSimpleRwsemFuncs(wbr_wh, struct au_wbr *wbr, &wbr->wbr_wh_rwsem);
++
++#define WbrWhMustNoWaiters(wbr) AuRwMustNoWaiters(&wbr->wbr_wh_rwsem)
++#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&wbr->wbr_wh_rwsem)
++#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&wbr->wbr_wh_rwsem)
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_BRANCH_H__ */
+diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c
+new file mode 100644
+index 0000000..7f70e2f
+--- /dev/null
++++ b/fs/aufs/cpup.c
+@@ -0,0 +1,1048 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * copy-up functions, see wbr_policy.c for copy-down
++ */
++
++#include <linux/file.h>
++#include <linux/fs_stack.h>
++#include <linux/mm.h>
++#include <linux/uaccess.h>
++#include "aufs.h"
++
++void au_cpup_attr_flags(struct inode *dst, struct inode *src)
++{
++ const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE
++ | S_NOATIME | S_NOCMTIME;
++
++ dst->i_flags |= src->i_flags & ~mask;
++ if (au_test_fs_notime(dst->i_sb))
++ dst->i_flags |= S_NOATIME | S_NOCMTIME;
++}
++
++void au_cpup_attr_timesizes(struct inode *inode)
++{
++ struct inode *h_inode;
++
++ h_inode = au_h_iptr(inode, au_ibstart(inode));
++ fsstack_copy_attr_times(inode, h_inode);
++ vfsub_copy_inode_size(inode, h_inode);
++}
++
++void au_cpup_attr_nlink(struct inode *inode, int force)
++{
++ struct inode *h_inode;
++ struct super_block *sb;
++ aufs_bindex_t bindex, bend;
++
++ sb = inode->i_sb;
++ bindex = au_ibstart(inode);
++ h_inode = au_h_iptr(inode, bindex);
++ if (!force
++ && !S_ISDIR(h_inode->i_mode)
++ && au_opt_test(au_mntflags(sb), PLINK)
++ && au_plink_test(inode))
++ return;
++
++ inode->i_nlink = h_inode->i_nlink;
++
++ /*
++ * fewer nlink makes find(1) noisy, but larger nlink doesn't.
++ * it may includes whplink directory.
++ */
++ if (S_ISDIR(h_inode->i_mode)) {
++ bend = au_ibend(inode);
++ for (bindex++; bindex <= bend; bindex++) {
++ h_inode = au_h_iptr(inode, bindex);
++ if (h_inode)
++ au_add_nlink(inode, h_inode);
++ }
++ }
++}
++
++void au_cpup_attr_changeable(struct inode *inode)
++{
++ struct inode *h_inode;
++
++ h_inode = au_h_iptr(inode, au_ibstart(inode));
++ inode->i_mode = h_inode->i_mode;
++ inode->i_uid = h_inode->i_uid;
++ inode->i_gid = h_inode->i_gid;
++ au_cpup_attr_timesizes(inode);
++ au_cpup_attr_flags(inode, h_inode);
++}
++
++void au_cpup_igen(struct inode *inode, struct inode *h_inode)
++{
++ struct au_iinfo *iinfo = au_ii(inode);
++
++ IiMustWriteLock(inode);
++
++ iinfo->ii_higen = h_inode->i_generation;
++ iinfo->ii_hsb1 = h_inode->i_sb;
++}
++
++void au_cpup_attr_all(struct inode *inode, int force)
++{
++ struct inode *h_inode;
++
++ h_inode = au_h_iptr(inode, au_ibstart(inode));
++ au_cpup_attr_changeable(inode);
++ if (inode->i_nlink > 0)
++ au_cpup_attr_nlink(inode, force);
++ inode->i_rdev = h_inode->i_rdev;
++ inode->i_blkbits = h_inode->i_blkbits;
++ au_cpup_igen(inode, h_inode);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */
++
++/* keep the timestamps of the parent dir when cpup */
++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry,
++ struct path *h_path)
++{
++ struct inode *h_inode;
++
++ dt->dt_dentry = dentry;
++ dt->dt_h_path = *h_path;
++ h_inode = h_path->dentry->d_inode;
++ dt->dt_atime = h_inode->i_atime;
++ dt->dt_mtime = h_inode->i_mtime;
++ /* smp_mb(); */
++}
++
++void au_dtime_revert(struct au_dtime *dt)
++{
++ struct iattr attr;
++ int err;
++
++ attr.ia_atime = dt->dt_atime;
++ attr.ia_mtime = dt->dt_mtime;
++ attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET
++ | ATTR_ATIME | ATTR_ATIME_SET;
++
++ err = vfsub_notify_change(&dt->dt_h_path, &attr);
++ if (unlikely(err))
++ AuWarn("restoring timestamps failed(%d). ignored\n", err);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static noinline_for_stack
++int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src)
++{
++ int err, sbits;
++ struct iattr ia;
++ struct path h_path;
++ struct inode *h_isrc, *h_idst;
++
++ h_path.dentry = au_h_dptr(dst, bindex);
++ h_idst = h_path.dentry->d_inode;
++ h_path.mnt = au_sbr_mnt(dst->d_sb, bindex);
++ h_isrc = h_src->d_inode;
++ ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID
++ | ATTR_ATIME | ATTR_MTIME
++ | ATTR_ATIME_SET | ATTR_MTIME_SET;
++ ia.ia_uid = h_isrc->i_uid;
++ ia.ia_gid = h_isrc->i_gid;
++ ia.ia_atime = h_isrc->i_atime;
++ ia.ia_mtime = h_isrc->i_mtime;
++ if (h_idst->i_mode != h_isrc->i_mode
++ && !S_ISLNK(h_idst->i_mode)) {
++ ia.ia_valid |= ATTR_MODE;
++ ia.ia_mode = h_isrc->i_mode;
++ }
++ sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID));
++ au_cpup_attr_flags(h_idst, h_isrc);
++ err = vfsub_notify_change(&h_path, &ia);
++
++ /* is this nfs only? */
++ if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) {
++ ia.ia_valid = ATTR_FORCE | ATTR_MODE;
++ ia.ia_mode = h_isrc->i_mode;
++ err = vfsub_notify_change(&h_path, &ia);
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_do_copy_file(struct file *dst, struct file *src, loff_t len,
++ char *buf, unsigned long blksize)
++{
++ int err;
++ size_t sz, rbytes, wbytes;
++ unsigned char all_zero;
++ char *p, *zp;
++ struct mutex *h_mtx;
++ /* reduce stack usage */
++ struct iattr *ia;
++
++ zp = page_address(ZERO_PAGE(0));
++ if (unlikely(!zp))
++ return -ENOMEM; /* possible? */
++
++ err = 0;
++ all_zero = 0;
++ while (len) {
++ AuDbg("len %lld\n", len);
++ sz = blksize;
++ if (len < blksize)
++ sz = len;
++
++ rbytes = 0;
++ /* todo: signal_pending? */
++ while (!rbytes || err == -EAGAIN || err == -EINTR) {
++ rbytes = vfsub_read_k(src, buf, sz, &src->f_pos);
++ err = rbytes;
++ }
++ if (unlikely(err < 0))
++ break;
++
++ all_zero = 0;
++ if (len >= rbytes && rbytes == blksize)
++ all_zero = !memcmp(buf, zp, rbytes);
++ if (!all_zero) {
++ wbytes = rbytes;
++ p = buf;
++ while (wbytes) {
++ size_t b;
++
++ b = vfsub_write_k(dst, p, wbytes, &dst->f_pos);
++ err = b;
++ /* todo: signal_pending? */
++ if (unlikely(err == -EAGAIN || err == -EINTR))
++ continue;
++ if (unlikely(err < 0))
++ break;
++ wbytes -= b;
++ p += b;
++ }
++ } else {
++ loff_t res;
++
++ AuLabel(hole);
++ res = vfsub_llseek(dst, rbytes, SEEK_CUR);
++ err = res;
++ if (unlikely(res < 0))
++ break;
++ }
++ len -= rbytes;
++ err = 0;
++ }
++
++ /* the last block may be a hole */
++ if (!err && all_zero) {
++ AuLabel(last hole);
++
++ err = 1;
++ if (au_test_nfs(dst->f_dentry->d_sb)) {
++ /* nfs requires this step to make last hole */
++ /* is this only nfs? */
++ do {
++ /* todo: signal_pending? */
++ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos);
++ } while (err == -EAGAIN || err == -EINTR);
++ if (err == 1)
++ dst->f_pos--;
++ }
++
++ if (err == 1) {
++ ia = (void *)buf;
++ ia->ia_size = dst->f_pos;
++ ia->ia_valid = ATTR_SIZE | ATTR_FILE;
++ ia->ia_file = dst;
++ h_mtx = &dst->f_dentry->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD2);
++ err = vfsub_notify_change(&dst->f_path, ia);
++ mutex_unlock(h_mtx);
++ }
++ }
++
++ return err;
++}
++
++int au_copy_file(struct file *dst, struct file *src, loff_t len)
++{
++ int err;
++ unsigned long blksize;
++ unsigned char do_kfree;
++ char *buf;
++
++ err = -ENOMEM;
++ blksize = dst->f_dentry->d_sb->s_blocksize;
++ if (!blksize || PAGE_SIZE < blksize)
++ blksize = PAGE_SIZE;
++ AuDbg("blksize %lu\n", blksize);
++ do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *));
++ if (do_kfree)
++ buf = kmalloc(blksize, GFP_NOFS);
++ else
++ buf = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!buf))
++ goto out;
++
++ if (len > (1 << 22))
++ AuDbg("copying a large file %lld\n", (long long)len);
++
++ src->f_pos = 0;
++ dst->f_pos = 0;
++ err = au_do_copy_file(dst, src, len, buf, blksize);
++ if (do_kfree)
++ kfree(buf);
++ else
++ free_page((unsigned long)buf);
++
++ out:
++ return err;
++}
++
++/*
++ * to support a sparse file which is opened with O_APPEND,
++ * we need to close the file.
++ */
++static int au_cp_regular(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len)
++{
++ int err, i;
++ enum { SRC, DST };
++ struct {
++ aufs_bindex_t bindex;
++ unsigned int flags;
++ struct dentry *dentry;
++ struct file *file;
++ void *label, *label_file;
++ } *f, file[] = {
++ {
++ .bindex = bsrc,
++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE,
++ .file = NULL,
++ .label = &&out,
++ .label_file = &&out_src
++ },
++ {
++ .bindex = bdst,
++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE,
++ .file = NULL,
++ .label = &&out_src,
++ .label_file = &&out_dst
++ }
++ };
++ struct super_block *sb;
++
++ /* bsrc branch can be ro/rw. */
++ sb = dentry->d_sb;
++ f = file;
++ for (i = 0; i < 2; i++, f++) {
++ f->dentry = au_h_dptr(dentry, f->bindex);
++ f->file = au_h_open(dentry, f->bindex, f->flags, /*file*/NULL);
++ err = PTR_ERR(f->file);
++ if (IS_ERR(f->file))
++ goto *f->label;
++ err = -EINVAL;
++ if (unlikely(!f->file->f_op))
++ goto *f->label_file;
++ }
++
++ /* try stopping to update while we copyup */
++ IMustLock(file[SRC].dentry->d_inode);
++ err = au_copy_file(file[DST].file, file[SRC].file, len);
++
++ out_dst:
++ fput(file[DST].file);
++ au_sbr_put(sb, file[DST].bindex);
++ out_src:
++ fput(file[SRC].file);
++ au_sbr_put(sb, file[SRC].bindex);
++ out:
++ return err;
++}
++
++static int au_do_cpup_regular(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len,
++ struct inode *h_dir, struct path *h_path)
++{
++ int err, rerr;
++ loff_t l;
++
++ err = 0;
++ l = i_size_read(au_h_iptr(dentry->d_inode, bsrc));
++ if (len == -1 || l < len)
++ len = l;
++ if (len)
++ err = au_cp_regular(dentry, bdst, bsrc, len);
++ if (!err)
++ goto out; /* success */
++
++ rerr = vfsub_unlink(h_dir, h_path, /*force*/0);
++ if (rerr) {
++ AuIOErr("failed unlinking cpup-ed %.*s(%d, %d)\n",
++ AuDLNPair(h_path->dentry), err, rerr);
++ err = -EIO;
++ }
++
++ out:
++ return err;
++}
++
++static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src,
++ struct inode *h_dir)
++{
++ int err, symlen;
++ mm_segment_t old_fs;
++ char *sym;
++
++ err = -ENOSYS;
++ if (unlikely(!h_src->d_inode->i_op->readlink))
++ goto out;
++
++ err = -ENOMEM;
++ sym = __getname();
++ if (unlikely(!sym))
++ goto out;
++
++ old_fs = get_fs();
++ set_fs(KERNEL_DS);
++ symlen = h_src->d_inode->i_op->readlink(h_src, (char __user *)sym,
++ PATH_MAX);
++ err = symlen;
++ set_fs(old_fs);
++
++ if (symlen > 0) {
++ sym[symlen] = 0;
++ err = vfsub_symlink(h_dir, h_path, sym);
++ }
++ __putname(sym);
++
++ out:
++ return err;
++}
++
++/* return with the lower dst inode is locked */
++static noinline_for_stack
++int cpup_entry(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len, unsigned int flags,
++ struct dentry *dst_parent)
++{
++ int err;
++ umode_t mode;
++ unsigned int mnt_flags;
++ unsigned char isdir;
++ const unsigned char do_dt = !!au_ftest_cpup(flags, DTIME);
++ struct au_dtime dt;
++ struct path h_path;
++ struct dentry *h_src, *h_dst, *h_parent;
++ struct inode *h_inode, *h_dir;
++ struct super_block *sb;
++
++ /* bsrc branch can be ro/rw. */
++ h_src = au_h_dptr(dentry, bsrc);
++ h_inode = h_src->d_inode;
++ AuDebugOn(h_inode != au_h_iptr(dentry->d_inode, bsrc));
++
++ /* try stopping to be referenced while we are creating */
++ h_dst = au_h_dptr(dentry, bdst);
++ h_parent = h_dst->d_parent; /* dir inode is locked */
++ h_dir = h_parent->d_inode;
++ IMustLock(h_dir);
++ AuDebugOn(h_parent != h_dst->d_parent);
++
++ sb = dentry->d_sb;
++ h_path.mnt = au_sbr_mnt(sb, bdst);
++ if (do_dt) {
++ h_path.dentry = h_parent;
++ au_dtime_store(&dt, dst_parent, &h_path);
++ }
++ h_path.dentry = h_dst;
++
++ isdir = 0;
++ mode = h_inode->i_mode;
++ switch (mode & S_IFMT) {
++ case S_IFREG:
++ /* try stopping to update while we are referencing */
++ IMustLock(h_inode);
++ err = vfsub_create(h_dir, &h_path, mode | S_IWUSR);
++ if (!err)
++ err = au_do_cpup_regular
++ (dentry, bdst, bsrc, len,
++ au_h_iptr(dst_parent->d_inode, bdst), &h_path);
++ break;
++ case S_IFDIR:
++ isdir = 1;
++ err = vfsub_mkdir(h_dir, &h_path, mode);
++ if (!err) {
++ /*
++ * strange behaviour from the users view,
++ * particularry setattr case
++ */
++ if (au_ibstart(dst_parent->d_inode) == bdst)
++ au_cpup_attr_nlink(dst_parent->d_inode,
++ /*force*/1);
++ au_cpup_attr_nlink(dentry->d_inode, /*force*/1);
++ }
++ break;
++ case S_IFLNK:
++ err = au_do_cpup_symlink(&h_path, h_src, h_dir);
++ break;
++ case S_IFCHR:
++ case S_IFBLK:
++ AuDebugOn(!capable(CAP_MKNOD));
++ /*FALLTHROUGH*/
++ case S_IFIFO:
++ case S_IFSOCK:
++ err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev);
++ break;
++ default:
++ AuIOErr("Unknown inode type 0%o\n", mode);
++ err = -EIO;
++ }
++
++ mnt_flags = au_mntflags(sb);
++ if (!au_opt_test(mnt_flags, UDBA_NONE)
++ && !isdir
++ && au_opt_test(mnt_flags, XINO)
++ && h_inode->i_nlink == 1
++ /* todo: unnecessary? */
++ /* && dentry->d_inode->i_nlink == 1 */
++ && bdst < bsrc
++ && !au_ftest_cpup(flags, KEEPLINO))
++ au_xino_write(sb, bsrc, h_inode->i_ino, /*ino*/0);
++ /* ignore this error */
++
++ if (do_dt)
++ au_dtime_revert(&dt);
++ return err;
++}
++
++/*
++ * copyup the @dentry from @bsrc to @bdst.
++ * the caller must set the both of lower dentries.
++ * @len is for truncating when it is -1 copyup the entire file.
++ * in link/rename cases, @dst_parent may be different from the real one.
++ */
++static int au_cpup_single(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len, unsigned int flags,
++ struct dentry *dst_parent)
++{
++ int err, rerr;
++ aufs_bindex_t old_ibstart;
++ unsigned char isdir, plink;
++ struct au_dtime dt;
++ struct path h_path;
++ struct dentry *h_src, *h_dst, *h_parent;
++ struct inode *dst_inode, *h_dir, *inode;
++ struct super_block *sb;
++
++ AuDebugOn(bsrc <= bdst);
++
++ sb = dentry->d_sb;
++ h_path.mnt = au_sbr_mnt(sb, bdst);
++ h_dst = au_h_dptr(dentry, bdst);
++ h_parent = h_dst->d_parent; /* dir inode is locked */
++ h_dir = h_parent->d_inode;
++ IMustLock(h_dir);
++
++ h_src = au_h_dptr(dentry, bsrc);
++ inode = dentry->d_inode;
++
++ if (!dst_parent)
++ dst_parent = dget_parent(dentry);
++ else
++ dget(dst_parent);
++
++ plink = !!au_opt_test(au_mntflags(sb), PLINK);
++ dst_inode = au_h_iptr(inode, bdst);
++ if (dst_inode) {
++ if (unlikely(!plink)) {
++ err = -EIO;
++ AuIOErr("i%lu exists on a upper branch "
++ "but plink is disabled\n", inode->i_ino);
++ goto out;
++ }
++
++ if (dst_inode->i_nlink) {
++ const int do_dt = au_ftest_cpup(flags, DTIME);
++
++ h_src = au_plink_lkup(inode, bdst);
++ err = PTR_ERR(h_src);
++ if (IS_ERR(h_src))
++ goto out;
++ if (unlikely(!h_src->d_inode)) {
++ err = -EIO;
++ AuIOErr("i%lu exists on a upper branch "
++ "but plink is broken\n", inode->i_ino);
++ dput(h_src);
++ goto out;
++ }
++
++ if (do_dt) {
++ h_path.dentry = h_parent;
++ au_dtime_store(&dt, dst_parent, &h_path);
++ }
++ h_path.dentry = h_dst;
++ err = vfsub_link(h_src, h_dir, &h_path);
++ if (do_dt)
++ au_dtime_revert(&dt);
++ dput(h_src);
++ goto out;
++ } else
++ /* todo: cpup_wh_file? */
++ /* udba work */
++ au_update_brange(inode, 1);
++ }
++
++ old_ibstart = au_ibstart(inode);
++ err = cpup_entry(dentry, bdst, bsrc, len, flags, dst_parent);
++ if (unlikely(err))
++ goto out;
++ dst_inode = h_dst->d_inode;
++ mutex_lock_nested(&dst_inode->i_mutex, AuLsc_I_CHILD2);
++
++ err = cpup_iattr(dentry, bdst, h_src);
++ isdir = S_ISDIR(dst_inode->i_mode);
++ if (!err) {
++ if (bdst < old_ibstart)
++ au_set_ibstart(inode, bdst);
++ au_set_h_iptr(inode, bdst, au_igrab(dst_inode),
++ au_hi_flags(inode, isdir));
++ mutex_unlock(&dst_inode->i_mutex);
++ if (!isdir
++ && h_src->d_inode->i_nlink > 1
++ && plink)
++ au_plink_append(inode, bdst, h_dst);
++ goto out; /* success */
++ }
++
++ /* revert */
++ h_path.dentry = h_parent;
++ mutex_unlock(&dst_inode->i_mutex);
++ au_dtime_store(&dt, dst_parent, &h_path);
++ h_path.dentry = h_dst;
++ if (!isdir)
++ rerr = vfsub_unlink(h_dir, &h_path, /*force*/0);
++ else
++ rerr = vfsub_rmdir(h_dir, &h_path);
++ au_dtime_revert(&dt);
++ if (rerr) {
++ AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr);
++ err = -EIO;
++ }
++
++ out:
++ dput(dst_parent);
++ return err;
++}
++
++struct au_cpup_single_args {
++ int *errp;
++ struct dentry *dentry;
++ aufs_bindex_t bdst, bsrc;
++ loff_t len;
++ unsigned int flags;
++ struct dentry *dst_parent;
++};
++
++static void au_call_cpup_single(void *args)
++{
++ struct au_cpup_single_args *a = args;
++ *a->errp = au_cpup_single(a->dentry, a->bdst, a->bsrc, a->len,
++ a->flags, a->dst_parent);
++}
++
++int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len, unsigned int flags,
++ struct dentry *dst_parent)
++{
++ int err, wkq_err;
++ umode_t mode;
++ struct dentry *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bsrc);
++ mode = h_dentry->d_inode->i_mode & S_IFMT;
++ if ((mode != S_IFCHR && mode != S_IFBLK)
++ || capable(CAP_MKNOD))
++ err = au_cpup_single(dentry, bdst, bsrc, len, flags,
++ dst_parent);
++ else {
++ struct au_cpup_single_args args = {
++ .errp = &err,
++ .dentry = dentry,
++ .bdst = bdst,
++ .bsrc = bsrc,
++ .len = len,
++ .flags = flags,
++ .dst_parent = dst_parent
++ };
++ wkq_err = au_wkq_wait(au_call_cpup_single, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ return err;
++}
++
++/*
++ * copyup the @dentry from the first active lower branch to @bdst,
++ * using au_cpup_single().
++ */
++static int au_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ unsigned int flags)
++{
++ int err;
++ aufs_bindex_t bsrc, bend;
++
++ bend = au_dbend(dentry);
++ for (bsrc = bdst + 1; bsrc <= bend; bsrc++)
++ if (au_h_dptr(dentry, bsrc))
++ break;
++
++ err = au_lkup_neg(dentry, bdst);
++ if (!err) {
++ err = au_cpup_single(dentry, bdst, bsrc, len, flags, NULL);
++ if (!err)
++ return 0; /* success */
++
++ /* revert */
++ au_set_h_dptr(dentry, bdst, NULL);
++ au_set_dbstart(dentry, bsrc);
++ }
++
++ return err;
++}
++
++struct au_cpup_simple_args {
++ int *errp;
++ struct dentry *dentry;
++ aufs_bindex_t bdst;
++ loff_t len;
++ unsigned int flags;
++};
++
++static void au_call_cpup_simple(void *args)
++{
++ struct au_cpup_simple_args *a = args;
++ *a->errp = au_cpup_simple(a->dentry, a->bdst, a->len, a->flags);
++}
++
++int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ unsigned int flags)
++{
++ int err, wkq_err;
++ unsigned char do_sio;
++ struct dentry *parent;
++ struct inode *h_dir;
++
++ parent = dget_parent(dentry);
++ h_dir = au_h_iptr(parent->d_inode, bdst);
++ do_sio = !!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE);
++ if (!do_sio) {
++ /*
++ * testing CAP_MKNOD is for generic fs,
++ * but CAP_FSETID is for xfs only, currently.
++ */
++ umode_t mode = dentry->d_inode->i_mode;
++ do_sio = (((mode & (S_IFCHR | S_IFBLK))
++ && !capable(CAP_MKNOD))
++ || ((mode & (S_ISUID | S_ISGID))
++ && !capable(CAP_FSETID)));
++ }
++ if (!do_sio)
++ err = au_cpup_simple(dentry, bdst, len, flags);
++ else {
++ struct au_cpup_simple_args args = {
++ .errp = &err,
++ .dentry = dentry,
++ .bdst = bdst,
++ .len = len,
++ .flags = flags
++ };
++ wkq_err = au_wkq_wait(au_call_cpup_simple, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ dput(parent);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * copyup the deleted file for writing.
++ */
++static int au_do_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *wh_dentry, struct file *file,
++ loff_t len)
++{
++ int err;
++ aufs_bindex_t bstart;
++ struct au_dinfo *dinfo;
++ struct dentry *h_d_dst, *h_d_start;
++
++ dinfo = au_di(dentry);
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ bstart = dinfo->di_bstart;
++ h_d_dst = dinfo->di_hdentry[0 + bdst].hd_dentry;
++ dinfo->di_bstart = bdst;
++ dinfo->di_hdentry[0 + bdst].hd_dentry = wh_dentry;
++ h_d_start = dinfo->di_hdentry[0 + bstart].hd_dentry;
++ if (file)
++ dinfo->di_hdentry[0 + bstart].hd_dentry
++ = au_h_fptr(file, au_fbstart(file))->f_dentry;
++ err = au_cpup_single(dentry, bdst, bstart, len, !AuCpup_DTIME,
++ /*h_parent*/NULL);
++ if (!err && file) {
++ err = au_reopen_nondir(file);
++ dinfo->di_hdentry[0 + bstart].hd_dentry = h_d_start;
++ }
++ dinfo->di_hdentry[0 + bdst].hd_dentry = h_d_dst;
++ dinfo->di_bstart = bstart;
++
++ return err;
++}
++
++static int au_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ struct file *file)
++{
++ int err;
++ struct au_dtime dt;
++ struct dentry *parent, *h_parent, *wh_dentry;
++ struct au_branch *br;
++ struct path h_path;
++
++ br = au_sbr(dentry->d_sb, bdst);
++ parent = dget_parent(dentry);
++ h_parent = au_h_dptr(parent, bdst);
++ wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out;
++
++ h_path.dentry = h_parent;
++ h_path.mnt = br->br_mnt;
++ au_dtime_store(&dt, parent, &h_path);
++ err = au_do_cpup_wh(dentry, bdst, wh_dentry, file, len);
++ if (unlikely(err))
++ goto out_wh;
++
++ dget(wh_dentry);
++ h_path.dentry = wh_dentry;
++ err = vfsub_unlink(h_parent->d_inode, &h_path, /*force*/0);
++ if (unlikely(err)) {
++ AuIOErr("failed remove copied-up tmp file %.*s(%d)\n",
++ AuDLNPair(wh_dentry), err);
++ err = -EIO;
++ }
++ au_dtime_revert(&dt);
++ au_set_hi_wh(dentry->d_inode, bdst, wh_dentry);
++
++ out_wh:
++ dput(wh_dentry);
++ out:
++ dput(parent);
++ return err;
++}
++
++struct au_cpup_wh_args {
++ int *errp;
++ struct dentry *dentry;
++ aufs_bindex_t bdst;
++ loff_t len;
++ struct file *file;
++};
++
++static void au_call_cpup_wh(void *args)
++{
++ struct au_cpup_wh_args *a = args;
++ *a->errp = au_cpup_wh(a->dentry, a->bdst, a->len, a->file);
++}
++
++int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ struct file *file)
++{
++ int err, wkq_err;
++ struct dentry *parent, *h_orph, *h_parent, *h_dentry;
++ struct inode *dir, *h_dir, *h_tmpdir, *h_inode;
++ struct au_wbr *wbr;
++
++ parent = dget_parent(dentry);
++ dir = parent->d_inode;
++ h_orph = NULL;
++ h_parent = NULL;
++ h_dir = au_igrab(au_h_iptr(dir, bdst));
++ h_tmpdir = h_dir;
++ if (!h_dir->i_nlink) {
++ wbr = au_sbr(dentry->d_sb, bdst)->br_wbr;
++ h_orph = wbr->wbr_orph;
++
++ h_parent = dget(au_h_dptr(parent, bdst));
++ au_set_h_dptr(parent, bdst, NULL);
++ au_set_h_dptr(parent, bdst, dget(h_orph));
++ h_tmpdir = h_orph->d_inode;
++ au_set_h_iptr(dir, bdst, NULL, 0);
++ au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0);
++
++ /* this temporary unlock is safe */
++ if (file)
++ h_dentry = au_h_fptr(file, au_fbstart(file))->f_dentry;
++ else
++ h_dentry = au_h_dptr(dentry, au_dbstart(dentry));
++ h_inode = h_dentry->d_inode;
++ IMustLock(h_inode);
++ mutex_unlock(&h_inode->i_mutex);
++ mutex_lock_nested(&h_tmpdir->i_mutex, AuLsc_I_PARENT3);
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ }
++
++ if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE))
++ err = au_cpup_wh(dentry, bdst, len, file);
++ else {
++ struct au_cpup_wh_args args = {
++ .errp = &err,
++ .dentry = dentry,
++ .bdst = bdst,
++ .len = len,
++ .file = file
++ };
++ wkq_err = au_wkq_wait(au_call_cpup_wh, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ if (h_orph) {
++ mutex_unlock(&h_tmpdir->i_mutex);
++ au_set_h_iptr(dir, bdst, NULL, 0);
++ au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0);
++ au_set_h_dptr(parent, bdst, NULL);
++ au_set_h_dptr(parent, bdst, h_parent);
++ }
++ iput(h_dir);
++ dput(parent);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * generic routine for both of copy-up and copy-down.
++ */
++/* cf. revalidate function in file.c */
++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst,
++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *h_parent, void *arg),
++ void *arg)
++{
++ int err;
++ struct au_pin pin;
++ struct dentry *d, *parent, *h_parent, *real_parent;
++
++ err = 0;
++ parent = dget_parent(dentry);
++ if (IS_ROOT(parent))
++ goto out;
++
++ au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2,
++ au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE);
++
++ /* do not use au_dpage */
++ real_parent = parent;
++ while (1) {
++ dput(parent);
++ parent = dget_parent(dentry);
++ h_parent = au_h_dptr(parent, bdst);
++ if (h_parent)
++ goto out; /* success */
++
++ /* find top dir which is necessary to cpup */
++ do {
++ d = parent;
++ dput(parent);
++ parent = dget_parent(d);
++ di_read_lock_parent3(parent, !AuLock_IR);
++ h_parent = au_h_dptr(parent, bdst);
++ di_read_unlock(parent, !AuLock_IR);
++ } while (!h_parent);
++
++ if (d != real_parent)
++ di_write_lock_child3(d);
++
++ /* somebody else might create while we were sleeping */
++ if (!au_h_dptr(d, bdst) || !au_h_dptr(d, bdst)->d_inode) {
++ if (au_h_dptr(d, bdst))
++ au_update_dbstart(d);
++
++ au_pin_set_dentry(&pin, d);
++ err = au_do_pin(&pin);
++ if (!err) {
++ err = cp(d, bdst, h_parent, arg);
++ au_unpin(&pin);
++ }
++ }
++
++ if (d != real_parent)
++ di_write_unlock(d);
++ if (unlikely(err))
++ break;
++ }
++
++ out:
++ dput(parent);
++ return err;
++}
++
++static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *h_parent __maybe_unused ,
++ void *arg __maybe_unused)
++{
++ return au_sio_cpup_simple(dentry, bdst, -1, AuCpup_DTIME);
++}
++
++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst)
++{
++ return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL);
++}
++
++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst)
++{
++ int err;
++ struct dentry *parent;
++ struct inode *dir;
++
++ parent = dget_parent(dentry);
++ dir = parent->d_inode;
++ err = 0;
++ if (au_h_iptr(dir, bdst))
++ goto out;
++
++ di_read_unlock(parent, AuLock_IR);
++ di_write_lock_parent(parent);
++ /* someone else might change our inode while we were sleeping */
++ if (!au_h_iptr(dir, bdst))
++ err = au_cpup_dirs(dentry, bdst);
++ di_downgrade_lock(parent, AuLock_IR);
++
++ out:
++ dput(parent);
++ return err;
++}
+diff --git a/fs/aufs/cpup.h b/fs/aufs/cpup.h
+new file mode 100644
+index 0000000..29e2508
+--- /dev/null
++++ b/fs/aufs/cpup.h
+@@ -0,0 +1,81 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * copy-up/down functions
++ */
++
++#ifndef __AUFS_CPUP_H__
++#define __AUFS_CPUP_H__
++
++#ifdef __KERNEL__
++
++#include <linux/path.h>
++#include <linux/time.h>
++#include <linux/aufs_type.h>
++
++struct inode;
++struct file;
++
++void au_cpup_attr_flags(struct inode *dst, struct inode *src);
++void au_cpup_attr_timesizes(struct inode *inode);
++void au_cpup_attr_nlink(struct inode *inode, int force);
++void au_cpup_attr_changeable(struct inode *inode);
++void au_cpup_igen(struct inode *inode, struct inode *h_inode);
++void au_cpup_attr_all(struct inode *inode, int force);
++
++/* ---------------------------------------------------------------------- */
++
++/* cpup flags */
++#define AuCpup_DTIME 1 /* do dtime_store/revert */
++#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino,
++ for link(2) */
++#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name)
++#define au_fset_cpup(flags, name) { (flags) |= AuCpup_##name; }
++#define au_fclr_cpup(flags, name) { (flags) &= ~AuCpup_##name; }
++
++int au_copy_file(struct file *dst, struct file *src, loff_t len);
++int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst,
++ aufs_bindex_t bsrc, loff_t len, unsigned int flags,
++ struct dentry *dst_parent);
++int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ unsigned int flags);
++int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len,
++ struct file *file);
++
++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst,
++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *h_parent, void *arg),
++ void *arg);
++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst);
++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst);
++
++/* ---------------------------------------------------------------------- */
++
++/* keep timestamps when copyup */
++struct au_dtime {
++ struct dentry *dt_dentry;
++ struct path dt_h_path;
++ struct timespec dt_atime, dt_mtime;
++};
++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry,
++ struct path *h_path);
++void au_dtime_revert(struct au_dtime *dt);
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_CPUP_H__ */
+diff --git a/fs/aufs/dbgaufs.c b/fs/aufs/dbgaufs.c
+new file mode 100644
+index 0000000..6b19d09
+--- /dev/null
++++ b/fs/aufs/dbgaufs.c
+@@ -0,0 +1,331 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * debugfs interface
++ */
++
++#include <linux/debugfs.h>
++#include "aufs.h"
++
++#ifndef CONFIG_SYSFS
++#error DEBUG_FS depends upon SYSFS
++#endif
++
++static struct dentry *dbgaufs;
++static const mode_t dbgaufs_mode = S_IRUSR | S_IRGRP | S_IROTH;
++
++/* 20 is max digits length of ulong 64 */
++struct dbgaufs_arg {
++ int n;
++ char a[20 * 4];
++};
++
++/*
++ * common function for all XINO files
++ */
++static int dbgaufs_xi_release(struct inode *inode __maybe_unused,
++ struct file *file)
++{
++ kfree(file->private_data);
++ return 0;
++}
++
++static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt)
++{
++ int err;
++ struct kstat st;
++ struct dbgaufs_arg *p;
++
++ err = -ENOMEM;
++ p = kmalloc(sizeof(*p), GFP_NOFS);
++ if (unlikely(!p))
++ goto out;
++
++ err = 0;
++ p->n = 0;
++ file->private_data = p;
++ if (!xf)
++ goto out;
++
++ err = vfs_getattr(xf->f_vfsmnt, xf->f_dentry, &st);
++ if (!err) {
++ if (do_fcnt)
++ p->n = snprintf
++ (p->a, sizeof(p->a), "%ld, %llux%lu %lld\n",
++ (long)file_count(xf), st.blocks, st.blksize,
++ (long long)st.size);
++ else
++ p->n = snprintf(p->a, sizeof(p->a), "%llux%lu %lld\n",
++ st.blocks, st.blksize,
++ (long long)st.size);
++ AuDebugOn(p->n >= sizeof(p->a));
++ } else {
++ p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err);
++ err = 0;
++ }
++
++ out:
++ return err;
++
++}
++
++static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct dbgaufs_arg *p;
++
++ p = file->private_data;
++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int dbgaufs_xib_open(struct inode *inode, struct file *file)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++ struct super_block *sb;
++
++ sbinfo = inode->i_private;
++ sb = sbinfo->si_sb;
++ si_noflush_read_lock(sb);
++ err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0);
++ si_read_unlock(sb);
++ return err;
++}
++
++static struct file_operations dbgaufs_xib_fop = {
++ .open = dbgaufs_xib_open,
++ .release = dbgaufs_xi_release,
++ .read = dbgaufs_xi_read
++};
++
++/* ---------------------------------------------------------------------- */
++
++#define DbgaufsXi_PREFIX "xi"
++
++static int dbgaufs_xino_open(struct inode *inode, struct file *file)
++{
++ int err;
++ long l;
++ struct au_sbinfo *sbinfo;
++ struct super_block *sb;
++ struct file *xf;
++ struct qstr *name;
++
++ err = -ENOENT;
++ xf = NULL;
++ name = &file->f_dentry->d_name;
++ if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX)
++ || memcmp(name->name, DbgaufsXi_PREFIX,
++ sizeof(DbgaufsXi_PREFIX) - 1)))
++ goto out;
++ err = strict_strtol(name->name + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l);
++ if (unlikely(err))
++ goto out;
++
++ sbinfo = inode->i_private;
++ sb = sbinfo->si_sb;
++ si_noflush_read_lock(sb);
++ if (l <= au_sbend(sb)) {
++ xf = au_sbr(sb, (aufs_bindex_t)l)->br_xino.xi_file;
++ err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1);
++ } else
++ err = -ENOENT;
++ si_read_unlock(sb);
++
++ out:
++ return err;
++}
++
++static struct file_operations dbgaufs_xino_fop = {
++ .open = dbgaufs_xino_open,
++ .release = dbgaufs_xi_release,
++ .read = dbgaufs_xi_read
++};
++
++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
++{
++ aufs_bindex_t bend;
++ struct au_branch *br;
++ struct au_xino_file *xi;
++
++ if (!au_sbi(sb)->si_dbgaufs)
++ return;
++
++ bend = au_sbend(sb);
++ for (; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ xi = &br->br_xino;
++ if (xi->xi_dbgaufs) {
++ debugfs_remove(xi->xi_dbgaufs);
++ xi->xi_dbgaufs = NULL;
++ }
++ }
++}
++
++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
++{
++ struct au_sbinfo *sbinfo;
++ struct dentry *parent;
++ struct au_branch *br;
++ struct au_xino_file *xi;
++ aufs_bindex_t bend;
++ char name[sizeof(DbgaufsXi_PREFIX) + 5]; /* "xi" bindex NULL */
++
++ sbinfo = au_sbi(sb);
++ parent = sbinfo->si_dbgaufs;
++ if (!parent)
++ return;
++
++ bend = au_sbend(sb);
++ for (; bindex <= bend; bindex++) {
++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex);
++ br = au_sbr(sb, bindex);
++ xi = &br->br_xino;
++ AuDebugOn(xi->xi_dbgaufs);
++ xi->xi_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent,
++ sbinfo, &dbgaufs_xino_fop);
++ /* ignore an error */
++ if (unlikely(!xi->xi_dbgaufs))
++ AuWarn1("failed %s under debugfs\n", name);
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_EXPORT
++static int dbgaufs_xigen_open(struct inode *inode, struct file *file)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++ struct super_block *sb;
++
++ sbinfo = inode->i_private;
++ sb = sbinfo->si_sb;
++ si_noflush_read_lock(sb);
++ err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0);
++ si_read_unlock(sb);
++ return err;
++}
++
++static struct file_operations dbgaufs_xigen_fop = {
++ .open = dbgaufs_xigen_open,
++ .release = dbgaufs_xi_release,
++ .read = dbgaufs_xi_read
++};
++
++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo)
++{
++ int err;
++
++ /*
++ * This function is a dynamic '__init' fucntion actually,
++ * so the tiny check for si_rwsem is unnecessary.
++ */
++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
++
++ err = -EIO;
++ sbinfo->si_dbgaufs_xigen = debugfs_create_file
++ ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo,
++ &dbgaufs_xigen_fop);
++ if (sbinfo->si_dbgaufs_xigen)
++ err = 0;
++
++ return err;
++}
++#else
++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo)
++{
++ return 0;
++}
++#endif /* CONFIG_AUFS_EXPORT */
++
++/* ---------------------------------------------------------------------- */
++
++void dbgaufs_si_fin(struct au_sbinfo *sbinfo)
++{
++ /*
++ * This function is a dynamic '__init' fucntion actually,
++ * so the tiny check for si_rwsem is unnecessary.
++ */
++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
++
++ debugfs_remove_recursive(sbinfo->si_dbgaufs);
++ sbinfo->si_dbgaufs = NULL;
++ kobject_put(&sbinfo->si_kobj);
++}
++
++int dbgaufs_si_init(struct au_sbinfo *sbinfo)
++{
++ int err;
++ char name[SysaufsSiNameLen];
++
++ /*
++ * This function is a dynamic '__init' fucntion actually,
++ * so the tiny check for si_rwsem is unnecessary.
++ */
++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
++
++ err = -ENOENT;
++ if (!dbgaufs) {
++ AuErr1("/debug/aufs is uninitialized\n");
++ goto out;
++ }
++
++ err = -EIO;
++ sysaufs_name(sbinfo, name);
++ sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs);
++ if (unlikely(!sbinfo->si_dbgaufs))
++ goto out;
++ kobject_get(&sbinfo->si_kobj);
++
++ sbinfo->si_dbgaufs_xib = debugfs_create_file
++ ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo,
++ &dbgaufs_xib_fop);
++ if (unlikely(!sbinfo->si_dbgaufs_xib))
++ goto out_dir;
++
++ err = dbgaufs_xigen_init(sbinfo);
++ if (!err)
++ goto out; /* success */
++
++ out_dir:
++ dbgaufs_si_fin(sbinfo);
++ out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void dbgaufs_fin(void)
++{
++ debugfs_remove(dbgaufs);
++}
++
++int __init dbgaufs_init(void)
++{
++ int err;
++
++ err = -EIO;
++ dbgaufs = debugfs_create_dir(AUFS_NAME, NULL);
++ if (dbgaufs)
++ err = 0;
++ return err;
++}
+diff --git a/fs/aufs/dbgaufs.h b/fs/aufs/dbgaufs.h
+new file mode 100644
+index 0000000..67a7964
+--- /dev/null
++++ b/fs/aufs/dbgaufs.h
+@@ -0,0 +1,79 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * debugfs interface
++ */
++
++#ifndef __DBGAUFS_H__
++#define __DBGAUFS_H__
++
++#ifdef __KERNEL__
++
++#include <linux/init.h>
++#include <linux/aufs_type.h>
++
++struct super_block;
++struct au_sbinfo;
++
++#ifdef CONFIG_DEBUG_FS
++/* dbgaufs.c */
++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex);
++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex);
++void dbgaufs_si_fin(struct au_sbinfo *sbinfo);
++int dbgaufs_si_init(struct au_sbinfo *sbinfo);
++void dbgaufs_fin(void);
++int __init dbgaufs_init(void);
++
++#else
++
++static inline
++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
++{
++ /* empty */
++}
++
++static inline
++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
++{
++ /* empty */
++}
++
++static inline
++void dbgaufs_si_fin(struct au_sbinfo *sbinfo)
++{
++ /* empty */
++}
++
++static inline
++int dbgaufs_si_init(struct au_sbinfo *sbinfo)
++{
++ return 0;
++}
++
++#define dbgaufs_fin() do {} while (0)
++
++static inline
++int __init dbgaufs_init(void)
++{
++ return 0;
++}
++#endif /* CONFIG_DEBUG_FS */
++
++#endif /* __KERNEL__ */
++#endif /* __DBGAUFS_H__ */
+diff --git a/fs/aufs/dcsub.c b/fs/aufs/dcsub.c
+new file mode 100644
+index 0000000..43a8cb4
+--- /dev/null
++++ b/fs/aufs/dcsub.c
+@@ -0,0 +1,223 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * sub-routines for dentry cache
++ */
++
++#include "aufs.h"
++
++static void au_dpage_free(struct au_dpage *dpage)
++{
++ int i;
++ struct dentry **p;
++
++ p = dpage->dentries;
++ for (i = 0; i < dpage->ndentry; i++)
++ dput(*p++);
++ free_page((unsigned long)dpage->dentries);
++}
++
++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp)
++{
++ int err;
++ void *p;
++
++ err = -ENOMEM;
++ dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp);
++ if (unlikely(!dpages->dpages))
++ goto out;
++
++ p = (void *)__get_free_page(gfp);
++ if (unlikely(!p))
++ goto out_dpages;
++
++ dpages->dpages[0].ndentry = 0;
++ dpages->dpages[0].dentries = p;
++ dpages->ndpage = 1;
++ return 0; /* success */
++
++ out_dpages:
++ kfree(dpages->dpages);
++ out:
++ return err;
++}
++
++void au_dpages_free(struct au_dcsub_pages *dpages)
++{
++ int i;
++ struct au_dpage *p;
++
++ p = dpages->dpages;
++ for (i = 0; i < dpages->ndpage; i++)
++ au_dpage_free(p++);
++ kfree(dpages->dpages);
++}
++
++static int au_dpages_append(struct au_dcsub_pages *dpages,
++ struct dentry *dentry, gfp_t gfp)
++{
++ int err, sz;
++ struct au_dpage *dpage;
++ void *p;
++
++ dpage = dpages->dpages + dpages->ndpage - 1;
++ sz = PAGE_SIZE / sizeof(dentry);
++ if (unlikely(dpage->ndentry >= sz)) {
++ AuLabel(new dpage);
++ err = -ENOMEM;
++ sz = dpages->ndpage * sizeof(*dpages->dpages);
++ p = au_kzrealloc(dpages->dpages, sz,
++ sz + sizeof(*dpages->dpages), gfp);
++ if (unlikely(!p))
++ goto out;
++
++ dpages->dpages = p;
++ dpage = dpages->dpages + dpages->ndpage;
++ p = (void *)__get_free_page(gfp);
++ if (unlikely(!p))
++ goto out;
++
++ dpage->ndentry = 0;
++ dpage->dentries = p;
++ dpages->ndpage++;
++ }
++
++ dpage->dentries[dpage->ndentry++] = dget(dentry);
++ return 0; /* success */
++
++ out:
++ return err;
++}
++
++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
++ au_dpages_test test, void *arg)
++{
++ int err;
++ struct dentry *this_parent = root;
++ struct list_head *next;
++ struct super_block *sb = root->d_sb;
++
++ err = 0;
++ spin_lock(&dcache_lock);
++ repeat:
++ next = this_parent->d_subdirs.next;
++ resume:
++ if (this_parent->d_sb == sb
++ && !IS_ROOT(this_parent)
++ && atomic_read(&this_parent->d_count)
++ && this_parent->d_inode
++ && (!test || test(this_parent, arg))) {
++ err = au_dpages_append(dpages, this_parent, GFP_ATOMIC);
++ if (unlikely(err))
++ goto out;
++ }
++
++ while (next != &this_parent->d_subdirs) {
++ struct list_head *tmp = next;
++ struct dentry *dentry = list_entry(tmp, struct dentry,
++ d_u.d_child);
++ next = tmp->next;
++ if (/*d_unhashed(dentry) || */!dentry->d_inode)
++ continue;
++ if (!list_empty(&dentry->d_subdirs)) {
++ this_parent = dentry;
++ goto repeat;
++ }
++ if (dentry->d_sb == sb
++ && atomic_read(&dentry->d_count)
++ && (!test || test(dentry, arg))) {
++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
++ if (unlikely(err))
++ goto out;
++ }
++ }
++
++ if (this_parent != root) {
++ next = this_parent->d_u.d_child.next;
++ this_parent = this_parent->d_parent; /* dcache_lock is locked */
++ goto resume;
++ }
++ out:
++ spin_unlock(&dcache_lock);
++ return err;
++}
++
++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry,
++ int do_include, au_dpages_test test, void *arg)
++{
++ int err;
++
++ err = 0;
++ spin_lock(&dcache_lock);
++ if (do_include && (!test || test(dentry, arg))) {
++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
++ if (unlikely(err))
++ goto out;
++ }
++ while (!IS_ROOT(dentry)) {
++ dentry = dentry->d_parent; /* dcache_lock is locked */
++ if (!test || test(dentry, arg)) {
++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
++ if (unlikely(err))
++ break;
++ }
++ }
++
++ out:
++ spin_unlock(&dcache_lock);
++
++ return err;
++}
++
++struct dentry *au_test_subdir(struct dentry *d1, struct dentry *d2)
++{
++ struct dentry *trap, **dentries;
++ int err, i, j;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++
++ trap = ERR_PTR(-ENOMEM);
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_dcsub_pages_rev(&dpages, d1, /*do_include*/1, NULL, NULL);
++ if (unlikely(err))
++ goto out_dpages;
++
++ trap = d1;
++ for (i = 0; !err && i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ dentries = dpage->dentries;
++ for (j = 0; !err && j < dpage->ndentry; j++) {
++ struct dentry *d;
++
++ d = dentries[j];
++ err = (d == d2);
++ if (!err)
++ trap = d;
++ }
++ }
++ if (!err)
++ trap = NULL;
++
++ out_dpages:
++ au_dpages_free(&dpages);
++ out:
++ return trap;
++}
+diff --git a/fs/aufs/dcsub.h b/fs/aufs/dcsub.h
+new file mode 100644
+index 0000000..bb934b4
+--- /dev/null
++++ b/fs/aufs/dcsub.h
+@@ -0,0 +1,54 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * sub-routines for dentry cache
++ */
++
++#ifndef __AUFS_DCSUB_H__
++#define __AUFS_DCSUB_H__
++
++#ifdef __KERNEL__
++
++#include <linux/types.h>
++
++struct dentry;
++
++struct au_dpage {
++ int ndentry;
++ struct dentry **dentries;
++};
++
++struct au_dcsub_pages {
++ int ndpage;
++ struct au_dpage *dpages;
++};
++
++/* ---------------------------------------------------------------------- */
++
++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp);
++void au_dpages_free(struct au_dcsub_pages *dpages);
++typedef int (*au_dpages_test)(struct dentry *dentry, void *arg);
++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
++ au_dpages_test test, void *arg);
++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry,
++ int do_include, au_dpages_test test, void *arg);
++struct dentry *au_test_subdir(struct dentry *d1, struct dentry *d2);
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_DCSUB_H__ */
+diff --git a/fs/aufs/debug.c b/fs/aufs/debug.c
+new file mode 100644
+index 0000000..32bdb72
+--- /dev/null
++++ b/fs/aufs/debug.c
+@@ -0,0 +1,431 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * debug print functions
++ */
++
++#include <linux/module.h>
++#include <linux/vt_kern.h>
++#include "aufs.h"
++
++int aufs_debug;
++MODULE_PARM_DESC(debug, "debug print");
++module_param_named(debug, aufs_debug, int, S_IRUGO | S_IWUSR | S_IWGRP);
++
++char *au_plevel = KERN_DEBUG;
++#define dpri(fmt, arg...) do { \
++ if (au_debug_test()) \
++ printk("%s" fmt, au_plevel, ##arg); \
++} while (0)
++
++/* ---------------------------------------------------------------------- */
++
++void au_dpri_whlist(struct au_nhash *whlist)
++{
++ unsigned long ul, n;
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos;
++
++ n = whlist->nh_num;
++ head = whlist->nh_head;
++ for (ul = 0; ul < n; ul++) {
++ hlist_for_each_entry(tpos, pos, head, wh_hash)
++ dpri("b%d, %.*s, %d\n",
++ tpos->wh_bindex,
++ tpos->wh_str.len, tpos->wh_str.name,
++ tpos->wh_str.len);
++ head++;
++ }
++}
++
++void au_dpri_vdir(struct au_vdir *vdir)
++{
++ unsigned long ul;
++ union au_vdir_deblk_p p;
++ unsigned char *o;
++
++ if (!vdir || IS_ERR(vdir)) {
++ dpri("err %ld\n", PTR_ERR(vdir));
++ return;
++ }
++
++ dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %lu\n",
++ vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk,
++ vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version);
++ for (ul = 0; ul < vdir->vd_nblk; ul++) {
++ p.deblk = vdir->vd_deblk[ul];
++ o = p.deblk;
++ dpri("[%lu]: %p\n", ul, o);
++ }
++}
++
++static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode,
++ struct dentry *wh)
++{
++ char *n = NULL;
++ int l = 0;
++
++ if (!inode || IS_ERR(inode)) {
++ dpri("i%d: err %ld\n", bindex, PTR_ERR(inode));
++ return -1;
++ }
++
++ /* the type of i_blocks depends upon CONFIG_LSF */
++ BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long)
++ && sizeof(inode->i_blocks) != sizeof(u64));
++ if (wh) {
++ n = (void *)wh->d_name.name;
++ l = wh->d_name.len;
++ }
++
++ dpri("i%d: i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu,"
++ " ct %lld, np %lu, st 0x%lx, f 0x%x, g %x%s%.*s\n",
++ bindex,
++ inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??",
++ atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode,
++ i_size_read(inode), (unsigned long long)inode->i_blocks,
++ (long long)timespec_to_ns(&inode->i_ctime) & 0x0ffff,
++ inode->i_mapping ? inode->i_mapping->nrpages : 0,
++ inode->i_state, inode->i_flags, inode->i_generation,
++ l ? ", wh " : "", l, n);
++ return 0;
++}
++
++void au_dpri_inode(struct inode *inode)
++{
++ struct au_iinfo *iinfo;
++ aufs_bindex_t bindex;
++ int err;
++
++ err = do_pri_inode(-1, inode, NULL);
++ if (err || !au_test_aufs(inode->i_sb))
++ return;
++
++ iinfo = au_ii(inode);
++ if (!iinfo)
++ return;
++ dpri("i-1: bstart %d, bend %d, gen %d\n",
++ iinfo->ii_bstart, iinfo->ii_bend, au_iigen(inode));
++ if (iinfo->ii_bstart < 0)
++ return;
++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; bindex++)
++ do_pri_inode(bindex, iinfo->ii_hinode[0 + bindex].hi_inode,
++ iinfo->ii_hinode[0 + bindex].hi_whdentry);
++}
++
++static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry)
++{
++ struct dentry *wh = NULL;
++
++ if (!dentry || IS_ERR(dentry)) {
++ dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry));
++ return -1;
++ }
++ /* do not call dget_parent() here */
++ dpri("d%d: %.*s?/%.*s, %s, cnt %d, flags 0x%x\n",
++ bindex,
++ AuDLNPair(dentry->d_parent), AuDLNPair(dentry),
++ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??",
++ atomic_read(&dentry->d_count), dentry->d_flags);
++ if (bindex >= 0 && dentry->d_inode && au_test_aufs(dentry->d_sb)) {
++ struct au_iinfo *iinfo = au_ii(dentry->d_inode);
++ if (iinfo)
++ wh = iinfo->ii_hinode[0 + bindex].hi_whdentry;
++ }
++ do_pri_inode(bindex, dentry->d_inode, wh);
++ return 0;
++}
++
++void au_dpri_dentry(struct dentry *dentry)
++{
++ struct au_dinfo *dinfo;
++ aufs_bindex_t bindex;
++ int err;
++
++ err = do_pri_dentry(-1, dentry);
++ if (err || !au_test_aufs(dentry->d_sb))
++ return;
++
++ dinfo = au_di(dentry);
++ if (!dinfo)
++ return;
++ dpri("d-1: bstart %d, bend %d, bwh %d, bdiropq %d, gen %d\n",
++ dinfo->di_bstart, dinfo->di_bend,
++ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry));
++ if (dinfo->di_bstart < 0)
++ return;
++ for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; bindex++)
++ do_pri_dentry(bindex, dinfo->di_hdentry[0 + bindex].hd_dentry);
++}
++
++static int do_pri_file(aufs_bindex_t bindex, struct file *file)
++{
++ char a[32];
++
++ if (!file || IS_ERR(file)) {
++ dpri("f%d: err %ld\n", bindex, PTR_ERR(file));
++ return -1;
++ }
++ a[0] = 0;
++ if (bindex < 0
++ && file->f_dentry
++ && au_test_aufs(file->f_dentry->d_sb)
++ && au_fi(file))
++ snprintf(a, sizeof(a), ", mmapped %d", au_test_mmapped(file));
++ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, pos %llu%s\n",
++ bindex, file->f_mode, file->f_flags, (long)file_count(file),
++ file->f_pos, a);
++ if (file->f_dentry)
++ do_pri_dentry(bindex, file->f_dentry);
++ return 0;
++}
++
++void au_dpri_file(struct file *file)
++{
++ struct au_finfo *finfo;
++ aufs_bindex_t bindex;
++ int err;
++
++ err = do_pri_file(-1, file);
++ if (err || !file->f_dentry || !au_test_aufs(file->f_dentry->d_sb))
++ return;
++
++ finfo = au_fi(file);
++ if (!finfo)
++ return;
++ if (finfo->fi_bstart < 0)
++ return;
++ for (bindex = finfo->fi_bstart; bindex <= finfo->fi_bend; bindex++) {
++ struct au_hfile *hf;
++
++ hf = finfo->fi_hfile + bindex;
++ do_pri_file(bindex, hf ? hf->hf_file : NULL);
++ }
++}
++
++static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br)
++{
++ struct vfsmount *mnt;
++ struct super_block *sb;
++
++ if (!br || IS_ERR(br))
++ goto out;
++ mnt = br->br_mnt;
++ if (!mnt || IS_ERR(mnt))
++ goto out;
++ sb = mnt->mnt_sb;
++ if (!sb || IS_ERR(sb))
++ goto out;
++
++ dpri("s%d: {perm 0x%x, cnt %d, wbr %p}, "
++ "%s, dev 0x%02x%02x, flags 0x%lx, cnt(BIAS) %d, active %d, "
++ "xino %d\n",
++ bindex, br->br_perm, atomic_read(&br->br_count), br->br_wbr,
++ au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev),
++ sb->s_flags, sb->s_count - S_BIAS,
++ atomic_read(&sb->s_active), !!br->br_xino.xi_file);
++ return 0;
++
++ out:
++ dpri("s%d: err %ld\n", bindex, PTR_ERR(br));
++ return -1;
++}
++
++void au_dpri_sb(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++ aufs_bindex_t bindex;
++ int err;
++ /* to reuduce stack size */
++ struct {
++ struct vfsmount mnt;
++ struct au_branch fake;
++ } *a;
++
++ /* this function can be called from magic sysrq */
++ a = kzalloc(sizeof(*a), GFP_ATOMIC);
++ if (unlikely(!a)) {
++ dpri("no memory\n");
++ return;
++ }
++
++ a->mnt.mnt_sb = sb;
++ a->fake.br_perm = 0;
++ a->fake.br_mnt = &a->mnt;
++ a->fake.br_xino.xi_file = NULL;
++ atomic_set(&a->fake.br_count, 0);
++ smp_mb(); /* atomic_set */
++ err = do_pri_br(-1, &a->fake);
++ kfree(a);
++ dpri("dev 0x%x\n", sb->s_dev);
++ if (err || !au_test_aufs(sb))
++ return;
++
++ sbinfo = au_sbi(sb);
++ if (!sbinfo)
++ return;
++ dpri("nw %d, gen %u, kobj %d\n",
++ atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation,
++ atomic_read(&sbinfo->si_kobj.kref.refcount));
++ for (bindex = 0; bindex <= sbinfo->si_bend; bindex++)
++ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]);
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_dbg_sleep_jiffy(int jiffy)
++{
++ while (jiffy)
++ jiffy = schedule_timeout_uninterruptible(jiffy);
++}
++
++void au_dbg_iattr(struct iattr *ia)
++{
++#define AuBit(name) if (ia->ia_valid & ATTR_ ## name) \
++ dpri(#name "\n")
++ AuBit(MODE);
++ AuBit(UID);
++ AuBit(GID);
++ AuBit(SIZE);
++ AuBit(ATIME);
++ AuBit(MTIME);
++ AuBit(CTIME);
++ AuBit(ATIME_SET);
++ AuBit(MTIME_SET);
++ AuBit(FORCE);
++ AuBit(ATTR_FLAG);
++ AuBit(KILL_SUID);
++ AuBit(KILL_SGID);
++ AuBit(FILE);
++ AuBit(KILL_PRIV);
++ AuBit(OPEN);
++ AuBit(TIMES_SET);
++#undef AuBit
++ dpri("ia_file %p\n", ia->ia_file);
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen)
++{
++ struct dentry *parent;
++
++ parent = dget_parent(dentry);
++ AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode)
++ || IS_ROOT(dentry)
++ || au_digen(parent) != sigen);
++ dput(parent);
++}
++
++void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen)
++{
++ struct dentry *parent;
++
++ parent = dget_parent(dentry);
++ AuDebugOn(S_ISDIR(dentry->d_inode->i_mode)
++ || au_digen(parent) != sigen);
++ dput(parent);
++}
++
++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen)
++{
++ int err, i, j;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry **dentries;
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ AuDebugOn(err);
++ err = au_dcsub_pages_rev(&dpages, parent, /*do_include*/1, NULL, NULL);
++ AuDebugOn(err);
++ for (i = dpages.ndpage - 1; !err && i >= 0; i--) {
++ dpage = dpages.dpages + i;
++ dentries = dpage->dentries;
++ for (j = dpage->ndentry - 1; !err && j >= 0; j--)
++ AuDebugOn(au_digen(dentries[j]) != sigen);
++ }
++ au_dpages_free(&dpages);
++}
++
++void au_dbg_verify_hf(struct au_finfo *finfo)
++{
++ struct au_hfile *hf;
++ aufs_bindex_t bend, bindex;
++
++ if (finfo->fi_bstart >= 0) {
++ bend = finfo->fi_bend;
++ for (bindex = finfo->fi_bstart; bindex <= bend; bindex++) {
++ hf = finfo->fi_hfile + bindex;
++ AuDebugOn(hf->hf_file || hf->hf_br);
++ }
++ }
++}
++
++void au_dbg_verify_kthread(void)
++{
++ if (au_test_wkq(current)) {
++ au_dbg_blocked();
++ BUG();
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_debug_sbinfo_init(struct au_sbinfo *sbinfo __maybe_unused)
++{
++#ifdef AuForceNoPlink
++ au_opt_clr(sbinfo->si_mntflags, PLINK);
++#endif
++#ifdef AuForceNoXino
++ au_opt_clr(sbinfo->si_mntflags, XINO);
++#endif
++#ifdef AuForceNoRefrof
++ au_opt_clr(sbinfo->si_mntflags, REFROF);
++#endif
++#ifdef AuForceHinotify
++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_HINOTIFY);
++#endif
++#ifdef AuForceRd0
++ sbinfo->si_rdblk = 0;
++ sbinfo->si_rdhash = 0;
++#endif
++}
++
++int __init au_debug_init(void)
++{
++ aufs_bindex_t bindex;
++ struct au_vdir_destr destr;
++
++ bindex = -1;
++ AuDebugOn(bindex >= 0);
++
++ destr.len = -1;
++ AuDebugOn(destr.len < NAME_MAX);
++
++#ifdef CONFIG_4KSTACKS
++ AuWarn("CONFIG_4KSTACKS is defined.\n");
++#endif
++
++#ifdef AuForceNoBrs
++ sysaufs_brs = 0;
++#endif
++
++ return 0;
++}
+diff --git a/fs/aufs/debug.h b/fs/aufs/debug.h
+new file mode 100644
+index 0000000..dab15f7
+--- /dev/null
++++ b/fs/aufs/debug.h
+@@ -0,0 +1,260 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * debug print functions
++ */
++
++#ifndef __AUFS_DEBUG_H__
++#define __AUFS_DEBUG_H__
++
++#ifdef __KERNEL__
++
++#include <linux/bug.h>
++/* #include <linux/err.h> */
++/* #include <linux/init.h> */
++/* #include <linux/kernel.h> */
++#include <linux/delay.h>
++/* #include <linux/kd.h> */
++/* #include <linux/vt_kern.h> */
++#include <linux/sysrq.h>
++#include <linux/aufs_type.h>
++
++#ifdef CONFIG_AUFS_DEBUG
++#define AuDebugOn(a) BUG_ON(a)
++
++/* module parameter */
++extern int aufs_debug;
++static inline void au_debug(int n)
++{
++ aufs_debug = n;
++ smp_mb();
++}
++
++static inline int au_debug_test(void)
++{
++ return aufs_debug;
++}
++#else
++#define AuDebugOn(a) do {} while (0)
++#define au_debug() do {} while (0)
++static inline int au_debug_test(void)
++{
++ return 0;
++}
++#endif /* CONFIG_AUFS_DEBUG */
++
++/* ---------------------------------------------------------------------- */
++
++/* debug print */
++
++#define AuDpri(lvl, fmt, arg...) \
++ printk(lvl AUFS_NAME " %s:%d:%s[%d]: " fmt, \
++ __func__, __LINE__, current->comm, current->pid, ##arg)
++#define AuDbg(fmt, arg...) do { \
++ if (au_debug_test()) \
++ AuDpri(KERN_DEBUG, "DEBUG: " fmt, ##arg); \
++} while (0)
++#define AuLabel(l) AuDbg(#l "\n")
++#define AuInfo(fmt, arg...) AuDpri(KERN_INFO, fmt, ##arg)
++#define AuWarn(fmt, arg...) AuDpri(KERN_WARNING, fmt, ##arg)
++#define AuErr(fmt, arg...) AuDpri(KERN_ERR, fmt, ##arg)
++#define AuIOErr(fmt, arg...) AuErr("I/O Error, " fmt, ##arg)
++#define AuWarn1(fmt, arg...) do { \
++ static unsigned char _c; \
++ if (!_c++) \
++ AuWarn(fmt, ##arg); \
++} while (0)
++
++#define AuErr1(fmt, arg...) do { \
++ static unsigned char _c; \
++ if (!_c++) \
++ AuErr(fmt, ##arg); \
++} while (0)
++
++#define AuIOErr1(fmt, arg...) do { \
++ static unsigned char _c; \
++ if (!_c++) \
++ AuIOErr(fmt, ##arg); \
++} while (0)
++
++#define AuUnsupportMsg "This operation is not supported." \
++ " Please report this application to aufs-users ML."
++#define AuUnsupport(fmt, args...) do { \
++ AuErr(AuUnsupportMsg "\n" fmt, ##args); \
++ dump_stack(); \
++} while (0)
++
++#define AuTraceErr(e) do { \
++ if (unlikely((e) < 0)) \
++ AuDbg("err %d\n", (int)(e)); \
++} while (0)
++
++#define AuTraceErrPtr(p) do { \
++ if (IS_ERR(p)) \
++ AuDbg("err %ld\n", PTR_ERR(p)); \
++} while (0)
++
++/* dirty macros for debug print, use with "%.*s" and caution */
++#define AuLNPair(qstr) (qstr)->len, (qstr)->name
++#define AuDLNPair(d) AuLNPair(&(d)->d_name)
++
++/* ---------------------------------------------------------------------- */
++
++struct au_sbinfo;
++struct au_finfo;
++struct dentry;
++#ifdef CONFIG_AUFS_DEBUG
++extern char *au_plevel;
++struct au_nhash;
++void au_dpri_whlist(struct au_nhash *whlist);
++struct au_vdir;
++void au_dpri_vdir(struct au_vdir *vdir);
++struct inode;
++void au_dpri_inode(struct inode *inode);
++void au_dpri_dentry(struct dentry *dentry);
++struct file;
++void au_dpri_file(struct file *filp);
++struct super_block;
++void au_dpri_sb(struct super_block *sb);
++
++void au_dbg_sleep_jiffy(int jiffy);
++struct iattr;
++void au_dbg_iattr(struct iattr *ia);
++
++void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen);
++void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen);
++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen);
++void au_dbg_verify_hf(struct au_finfo *finfo);
++void au_dbg_verify_kthread(void);
++
++int __init au_debug_init(void);
++void au_debug_sbinfo_init(struct au_sbinfo *sbinfo);
++#define AuDbgWhlist(w) do { \
++ AuDbg(#w "\n"); \
++ au_dpri_whlist(w); \
++} while (0)
++
++#define AuDbgVdir(v) do { \
++ AuDbg(#v "\n"); \
++ au_dpri_vdir(v); \
++} while (0)
++
++#define AuDbgInode(i) do { \
++ AuDbg(#i "\n"); \
++ au_dpri_inode(i); \
++} while (0)
++
++#define AuDbgDentry(d) do { \
++ AuDbg(#d "\n"); \
++ au_dpri_dentry(d); \
++} while (0)
++
++#define AuDbgFile(f) do { \
++ AuDbg(#f "\n"); \
++ au_dpri_file(f); \
++} while (0)
++
++#define AuDbgSb(sb) do { \
++ AuDbg(#sb "\n"); \
++ au_dpri_sb(sb); \
++} while (0)
++
++#define AuDbgSleep(sec) do { \
++ AuDbg("sleep %d sec\n", sec); \
++ ssleep(sec); \
++} while (0)
++
++#define AuDbgSleepJiffy(jiffy) do { \
++ AuDbg("sleep %d jiffies\n", jiffy); \
++ au_dbg_sleep_jiffy(jiffy); \
++} while (0)
++
++#define AuDbgIAttr(ia) do { \
++ AuDbg("ia_valid 0x%x\n", (ia)->ia_valid); \
++ au_dbg_iattr(ia); \
++} while (0)
++#else
++static inline void au_dbg_verify_dir_parent(struct dentry *dentry,
++ unsigned int sigen)
++{
++ /* empty */
++}
++static inline void au_dbg_verify_nondir_parent(struct dentry *dentry,
++ unsigned int sigen)
++{
++ /* empty */
++}
++static inline void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen)
++{
++ /* empty */
++}
++static inline void au_dbg_verify_hf(struct au_finfo *finfo)
++{
++ /* empty */
++}
++static inline void au_dbg_verify_kthread(void)
++{
++ /* empty */
++}
++
++static inline int au_debug_init(void)
++{
++ return 0;
++}
++static inline void au_debug_sbinfo_init(struct au_sbinfo *sbinfo)
++{
++ /* empty */
++}
++#define AuDbgWhlist(w) do {} while (0)
++#define AuDbgVdir(v) do {} while (0)
++#define AuDbgInode(i) do {} while (0)
++#define AuDbgDentry(d) do {} while (0)
++#define AuDbgFile(f) do {} while (0)
++#define AuDbgSb(sb) do {} while (0)
++#define AuDbgSleep(sec) do {} while (0)
++#define AuDbgSleepJiffy(jiffy) do {} while (0)
++#define AuDbgIAttr(ia) do {} while (0)
++#endif /* CONFIG_AUFS_DEBUG */
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_MAGIC_SYSRQ
++int __init au_sysrq_init(void);
++void au_sysrq_fin(void);
++
++#ifdef CONFIG_HW_CONSOLE
++#define au_dbg_blocked() do { \
++ WARN_ON(1); \
++ handle_sysrq('w', vc_cons[fg_console].d->vc_tty); \
++} while (0)
++#else
++#define au_dbg_blocked() do {} while (0)
++#endif
++
++#else
++static inline int au_sysrq_init(void)
++{
++ return 0;
++}
++#define au_sysrq_fin() do {} while (0)
++#define au_dbg_blocked() do {} while (0)
++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_DEBUG_H__ */
+diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c
+new file mode 100644
+index 0000000..a428d9c
+--- /dev/null
++++ b/fs/aufs/dentry.c
+@@ -0,0 +1,880 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * lookup and dentry operations
++ */
++
++#include <linux/namei.h>
++#include "aufs.h"
++
++static void au_h_nd(struct nameidata *h_nd, struct nameidata *nd)
++{
++ if (nd) {
++ *h_nd = *nd;
++
++ /*
++ * gave up supporting LOOKUP_CREATE/OPEN for lower fs,
++ * due to whiteout and branch permission.
++ */
++ h_nd->flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE
++ | LOOKUP_FOLLOW);
++ /* unnecessary? */
++ h_nd->intent.open.file = NULL;
++ } else
++ memset(h_nd, 0, sizeof(*h_nd));
++}
++
++struct au_lkup_one_args {
++ struct dentry **errp;
++ struct qstr *name;
++ struct dentry *h_parent;
++ struct au_branch *br;
++ struct nameidata *nd;
++};
++
++struct dentry *au_lkup_one(struct qstr *name, struct dentry *h_parent,
++ struct au_branch *br, struct nameidata *nd)
++{
++ struct dentry *h_dentry;
++ int err;
++ struct nameidata h_nd;
++
++ if (au_test_fs_null_nd(h_parent->d_sb))
++ return vfsub_lookup_one_len(name->name, h_parent, name->len);
++
++ au_h_nd(&h_nd, nd);
++ h_nd.path.dentry = h_parent;
++ h_nd.path.mnt = br->br_mnt;
++
++ err = __lookup_one_len(name->name, &h_nd.last, NULL, name->len);
++ h_dentry = ERR_PTR(err);
++ if (!err) {
++ path_get(&h_nd.path);
++ h_dentry = vfsub_lookup_hash(&h_nd);
++ path_put(&h_nd.path);
++ }
++
++ return h_dentry;
++}
++
++static void au_call_lkup_one(void *args)
++{
++ struct au_lkup_one_args *a = args;
++ *a->errp = au_lkup_one(a->name, a->h_parent, a->br, a->nd);
++}
++
++#define AuLkup_ALLOW_NEG 1
++#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name)
++#define au_fset_lkup(flags, name) { (flags) |= AuLkup_##name; }
++#define au_fclr_lkup(flags, name) { (flags) &= ~AuLkup_##name; }
++
++struct au_do_lookup_args {
++ unsigned int flags;
++ mode_t type;
++ struct nameidata *nd;
++};
++
++/*
++ * returns positive/negative dentry, NULL or an error.
++ * NULL means whiteout-ed or not-found.
++ */
++static struct dentry*
++au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
++ aufs_bindex_t bindex, struct qstr *wh_name,
++ struct au_do_lookup_args *args)
++{
++ struct dentry *h_dentry;
++ struct inode *h_inode, *inode;
++ struct qstr *name;
++ struct au_branch *br;
++ int wh_found, opq;
++ unsigned char wh_able;
++ const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG);
++
++ name = &dentry->d_name;
++ wh_found = 0;
++ br = au_sbr(dentry->d_sb, bindex);
++ wh_able = !!au_br_whable(br->br_perm);
++ if (wh_able)
++ wh_found = au_wh_test(h_parent, wh_name, br, /*try_sio*/0);
++ h_dentry = ERR_PTR(wh_found);
++ if (!wh_found)
++ goto real_lookup;
++ if (unlikely(wh_found < 0))
++ goto out;
++
++ /* We found a whiteout */
++ /* au_set_dbend(dentry, bindex); */
++ au_set_dbwh(dentry, bindex);
++ if (!allow_neg)
++ return NULL; /* success */
++
++ real_lookup:
++ h_dentry = au_lkup_one(name, h_parent, br, args->nd);
++ if (IS_ERR(h_dentry))
++ goto out;
++
++ h_inode = h_dentry->d_inode;
++ if (!h_inode) {
++ if (!allow_neg)
++ goto out_neg;
++ } else if (wh_found
++ || (args->type && args->type != (h_inode->i_mode & S_IFMT)))
++ goto out_neg;
++
++ if (au_dbend(dentry) <= bindex)
++ au_set_dbend(dentry, bindex);
++ if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry))
++ au_set_dbstart(dentry, bindex);
++ au_set_h_dptr(dentry, bindex, h_dentry);
++
++ inode = dentry->d_inode;
++ if (!h_inode || !S_ISDIR(h_inode->i_mode) || !wh_able
++ || (inode && !S_ISDIR(inode->i_mode)))
++ goto out; /* success */
++
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ opq = au_diropq_test(h_dentry, br);
++ mutex_unlock(&h_inode->i_mutex);
++ if (opq > 0)
++ au_set_dbdiropq(dentry, bindex);
++ else if (unlikely(opq < 0)) {
++ au_set_h_dptr(dentry, bindex, NULL);
++ h_dentry = ERR_PTR(opq);
++ }
++ goto out;
++
++ out_neg:
++ dput(h_dentry);
++ h_dentry = NULL;
++ out:
++ return h_dentry;
++}
++
++static int au_test_shwh(struct super_block *sb, const struct qstr *name)
++{
++ if (unlikely(!au_opt_test(au_mntflags(sb), SHWH)
++ && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)))
++ return -EPERM;
++ return 0;
++}
++
++/*
++ * returns the number of lower positive dentries,
++ * otherwise an error.
++ * can be called at unlinking with @type is zero.
++ */
++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type,
++ struct nameidata *nd)
++{
++ int npositive, err;
++ aufs_bindex_t bindex, btail, bdiropq;
++ unsigned char isdir;
++ struct qstr whname;
++ struct au_do_lookup_args args = {
++ .flags = 0,
++ .type = type,
++ .nd = nd
++ };
++ const struct qstr *name = &dentry->d_name;
++ struct dentry *parent;
++ struct inode *inode;
++
++ parent = dget_parent(dentry);
++ err = au_test_shwh(dentry->d_sb, name);
++ if (unlikely(err))
++ goto out;
++
++ err = au_wh_name_alloc(&whname, name);
++ if (unlikely(err))
++ goto out;
++
++ inode = dentry->d_inode;
++ isdir = !!(inode && S_ISDIR(inode->i_mode));
++ if (!type)
++ au_fset_lkup(args.flags, ALLOW_NEG);
++
++ npositive = 0;
++ btail = au_dbtaildir(parent);
++ for (bindex = bstart; bindex <= btail; bindex++) {
++ struct dentry *h_parent, *h_dentry;
++ struct inode *h_inode, *h_dir;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry) {
++ if (h_dentry->d_inode)
++ npositive++;
++ if (type != S_IFDIR)
++ break;
++ continue;
++ }
++ h_parent = au_h_dptr(parent, bindex);
++ if (!h_parent)
++ continue;
++ h_dir = h_parent->d_inode;
++ if (!h_dir || !S_ISDIR(h_dir->i_mode))
++ continue;
++
++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
++ h_dentry = au_do_lookup(h_parent, dentry, bindex, &whname,
++ &args);
++ mutex_unlock(&h_dir->i_mutex);
++ err = PTR_ERR(h_dentry);
++ if (IS_ERR(h_dentry))
++ goto out_wh;
++ au_fclr_lkup(args.flags, ALLOW_NEG);
++
++ if (au_dbwh(dentry) >= 0)
++ break;
++ if (!h_dentry)
++ continue;
++ h_inode = h_dentry->d_inode;
++ if (!h_inode)
++ continue;
++ npositive++;
++ if (!args.type)
++ args.type = h_inode->i_mode & S_IFMT;
++ if (args.type != S_IFDIR)
++ break;
++ else if (isdir) {
++ /* the type of lower may be different */
++ bdiropq = au_dbdiropq(dentry);
++ if (bdiropq >= 0 && bdiropq <= bindex)
++ break;
++ }
++ }
++
++ if (npositive) {
++ AuLabel(positive);
++ au_update_dbstart(dentry);
++ }
++ err = npositive;
++ if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE)
++ && au_dbstart(dentry) < 0))
++ /* both of real entry and whiteout found */
++ err = -EIO;
++
++ out_wh:
++ kfree(whname.name);
++ out:
++ dput(parent);
++ return err;
++}
++
++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent,
++ struct au_branch *br)
++{
++ struct dentry *dentry;
++ int wkq_err;
++
++ if (!au_test_h_perm_sio(parent->d_inode, MAY_EXEC))
++ dentry = au_lkup_one(name, parent, br, /*nd*/NULL);
++ else {
++ struct au_lkup_one_args args = {
++ .errp = &dentry,
++ .name = name,
++ .h_parent = parent,
++ .br = br,
++ .nd = NULL
++ };
++
++ wkq_err = au_wkq_wait(au_call_lkup_one, &args);
++ if (unlikely(wkq_err))
++ dentry = ERR_PTR(wkq_err);
++ }
++
++ return dentry;
++}
++
++/*
++ * lookup @dentry on @bindex which should be negative.
++ */
++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ int err;
++ struct dentry *parent, *h_parent, *h_dentry;
++ struct qstr *name;
++
++ name = &dentry->d_name;
++ parent = dget_parent(dentry);
++ h_parent = au_h_dptr(parent, bindex);
++ h_dentry = au_sio_lkup_one(name, h_parent,
++ au_sbr(dentry->d_sb, bindex));
++ err = PTR_ERR(h_dentry);
++ if (IS_ERR(h_dentry))
++ goto out;
++ if (unlikely(h_dentry->d_inode)) {
++ err = -EIO;
++ AuIOErr("b%d %.*s should be negative.\n",
++ bindex, AuDLNPair(h_dentry));
++ dput(h_dentry);
++ goto out;
++ }
++
++ if (bindex < au_dbstart(dentry))
++ au_set_dbstart(dentry, bindex);
++ if (au_dbend(dentry) < bindex)
++ au_set_dbend(dentry, bindex);
++ au_set_h_dptr(dentry, bindex, h_dentry);
++ err = 0;
++
++ out:
++ dput(parent);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* subset of struct inode */
++struct au_iattr {
++ unsigned long i_ino;
++ /* unsigned int i_nlink; */
++ uid_t i_uid;
++ gid_t i_gid;
++ u64 i_version;
++/*
++ loff_t i_size;
++ blkcnt_t i_blocks;
++*/
++ umode_t i_mode;
++};
++
++static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode)
++{
++ ia->i_ino = h_inode->i_ino;
++ /* ia->i_nlink = h_inode->i_nlink; */
++ ia->i_uid = h_inode->i_uid;
++ ia->i_gid = h_inode->i_gid;
++ ia->i_version = h_inode->i_version;
++/*
++ ia->i_size = h_inode->i_size;
++ ia->i_blocks = h_inode->i_blocks;
++*/
++ ia->i_mode = (h_inode->i_mode & S_IFMT);
++}
++
++static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode)
++{
++ return ia->i_ino != h_inode->i_ino
++ /* || ia->i_nlink != h_inode->i_nlink */
++ || ia->i_uid != h_inode->i_uid
++ || ia->i_gid != h_inode->i_gid
++ || ia->i_version != h_inode->i_version
++/*
++ || ia->i_size != h_inode->i_size
++ || ia->i_blocks != h_inode->i_blocks
++*/
++ || ia->i_mode != (h_inode->i_mode & S_IFMT);
++}
++
++static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent,
++ struct au_branch *br)
++{
++ int err;
++ struct au_iattr ia;
++ struct inode *h_inode;
++ struct dentry *h_d;
++ struct super_block *h_sb;
++
++ err = 0;
++ memset(&ia, -1, sizeof(ia));
++ h_sb = h_dentry->d_sb;
++ h_inode = h_dentry->d_inode;
++ if (h_inode)
++ au_iattr_save(&ia, h_inode);
++ else if (au_test_nfs(h_sb) || au_test_fuse(h_sb))
++ /* nfs d_revalidate may return 0 for negative dentry */
++ /* fuse d_revalidate always return 0 for negative dentry */
++ goto out;
++
++ /* main purpose is namei.c:cached_lookup() and d_revalidate */
++ h_d = au_lkup_one(&h_dentry->d_name, h_parent, br, /*nd*/NULL);
++ err = PTR_ERR(h_d);
++ if (IS_ERR(h_d))
++ goto out;
++
++ err = 0;
++ if (unlikely(h_d != h_dentry
++ || h_d->d_inode != h_inode
++ || (h_inode && au_iattr_test(&ia, h_inode))))
++ err = au_busy_or_stale();
++ dput(h_d);
++
++ out:
++ AuTraceErr(err);
++ return err;
++}
++
++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir,
++ struct dentry *h_parent, struct au_branch *br)
++{
++ int err;
++
++ err = 0;
++ if (udba == AuOpt_UDBA_REVAL) {
++ IMustLock(h_dir);
++ err = (h_dentry->d_parent->d_inode != h_dir);
++ } else if (udba == AuOpt_UDBA_HINOTIFY)
++ err = au_h_verify_dentry(h_dentry, h_parent, br);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void au_do_refresh_hdentry(struct au_hdentry *p, struct au_dinfo *dinfo,
++ struct dentry *parent)
++{
++ struct dentry *h_d, *h_dp;
++ struct au_hdentry tmp, *q;
++ struct super_block *sb;
++ aufs_bindex_t new_bindex, bindex, bend, bwh, bdiropq;
++
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ bend = dinfo->di_bend;
++ bwh = dinfo->di_bwh;
++ bdiropq = dinfo->di_bdiropq;
++ for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) {
++ h_d = p->hd_dentry;
++ if (!h_d)
++ continue;
++
++ h_dp = dget_parent(h_d);
++ if (h_dp == au_h_dptr(parent, bindex)) {
++ dput(h_dp);
++ continue;
++ }
++
++ new_bindex = au_find_dbindex(parent, h_dp);
++ dput(h_dp);
++ if (dinfo->di_bwh == bindex)
++ bwh = new_bindex;
++ if (dinfo->di_bdiropq == bindex)
++ bdiropq = new_bindex;
++ if (new_bindex < 0) {
++ au_hdput(p);
++ p->hd_dentry = NULL;
++ continue;
++ }
++
++ /* swap two lower dentries, and loop again */
++ q = dinfo->di_hdentry + new_bindex;
++ tmp = *q;
++ *q = *p;
++ *p = tmp;
++ if (tmp.hd_dentry) {
++ bindex--;
++ p--;
++ }
++ }
++
++ sb = parent->d_sb;
++ dinfo->di_bwh = -1;
++ if (bwh >= 0 && bwh <= au_sbend(sb) && au_sbr_whable(sb, bwh))
++ dinfo->di_bwh = bwh;
++
++ dinfo->di_bdiropq = -1;
++ if (bdiropq >= 0
++ && bdiropq <= au_sbend(sb)
++ && au_sbr_whable(sb, bdiropq))
++ dinfo->di_bdiropq = bdiropq;
++
++ bend = au_dbend(parent);
++ p = dinfo->di_hdentry;
++ for (bindex = 0; bindex <= bend; bindex++, p++)
++ if (p->hd_dentry) {
++ dinfo->di_bstart = bindex;
++ break;
++ }
++
++ p = dinfo->di_hdentry + bend;
++ for (bindex = bend; bindex >= 0; bindex--, p--)
++ if (p->hd_dentry) {
++ dinfo->di_bend = bindex;
++ break;
++ }
++}
++
++/*
++ * returns the number of found lower positive dentries,
++ * otherwise an error.
++ */
++int au_refresh_hdentry(struct dentry *dentry, mode_t type)
++{
++ int npositive, err;
++ unsigned int sigen;
++ aufs_bindex_t bstart;
++ struct au_dinfo *dinfo;
++ struct super_block *sb;
++ struct dentry *parent;
++
++ DiMustWriteLock(dentry);
++
++ sb = dentry->d_sb;
++ AuDebugOn(IS_ROOT(dentry));
++ sigen = au_sigen(sb);
++ parent = dget_parent(dentry);
++ AuDebugOn(au_digen(parent) != sigen
++ || au_iigen(parent->d_inode) != sigen);
++
++ dinfo = au_di(dentry);
++ err = au_di_realloc(dinfo, au_sbend(sb) + 1);
++ npositive = err;
++ if (unlikely(err))
++ goto out;
++ au_do_refresh_hdentry(dinfo->di_hdentry + dinfo->di_bstart, dinfo,
++ parent);
++
++ npositive = 0;
++ bstart = au_dbstart(parent);
++ if (type != S_IFDIR && dinfo->di_bstart == bstart)
++ goto out_dgen; /* success */
++
++ npositive = au_lkup_dentry(dentry, bstart, type, /*nd*/NULL);
++ if (npositive < 0)
++ goto out;
++ if (dinfo->di_bwh >= 0 && dinfo->di_bwh <= dinfo->di_bstart)
++ d_drop(dentry);
++
++ out_dgen:
++ au_update_digen(dentry);
++ out:
++ dput(parent);
++ AuTraceErr(npositive);
++ return npositive;
++}
++
++static noinline_for_stack
++int au_do_h_d_reval(struct dentry *h_dentry, struct nameidata *nd,
++ struct dentry *dentry, aufs_bindex_t bindex)
++{
++ int err, valid;
++ int (*reval)(struct dentry *, struct nameidata *);
++
++ err = 0;
++ reval = NULL;
++ if (h_dentry->d_op)
++ reval = h_dentry->d_op->d_revalidate;
++ if (!reval)
++ goto out;
++
++ AuDbg("b%d\n", bindex);
++ if (au_test_fs_null_nd(h_dentry->d_sb))
++ /* it may return tri-state */
++ valid = reval(h_dentry, NULL);
++ else {
++ struct nameidata h_nd;
++ int locked;
++ struct dentry *parent;
++
++ au_h_nd(&h_nd, nd);
++ parent = nd->path.dentry;
++ locked = (nd && nd->path.dentry != dentry);
++ if (locked)
++ di_read_lock_parent(parent, AuLock_IR);
++ BUG_ON(bindex > au_dbend(parent));
++ h_nd.path.dentry = au_h_dptr(parent, bindex);
++ BUG_ON(!h_nd.path.dentry);
++ h_nd.path.mnt = au_sbr(parent->d_sb, bindex)->br_mnt;
++ path_get(&h_nd.path);
++ valid = reval(h_dentry, &h_nd);
++ path_put(&h_nd.path);
++ if (locked)
++ di_read_unlock(parent, AuLock_IR);
++ }
++
++ if (unlikely(valid < 0))
++ err = valid;
++ else if (!valid)
++ err = -EINVAL;
++
++ out:
++ AuTraceErr(err);
++ return err;
++}
++
++/* todo: remove this */
++static int h_d_revalidate(struct dentry *dentry, struct inode *inode,
++ struct nameidata *nd, int do_udba)
++{
++ int err;
++ umode_t mode, h_mode;
++ aufs_bindex_t bindex, btail, bstart, ibs, ibe;
++ unsigned char plus, unhashed, is_root, h_plus;
++ struct inode *first, *h_inode, *h_cached_inode;
++ struct dentry *h_dentry;
++ struct qstr *name, *h_name;
++
++ err = 0;
++ plus = 0;
++ mode = 0;
++ first = NULL;
++ ibs = -1;
++ ibe = -1;
++ unhashed = !!d_unhashed(dentry);
++ is_root = !!IS_ROOT(dentry);
++ name = &dentry->d_name;
++
++ /*
++ * Theoretically, REVAL test should be unnecessary in case of INOTIFY.
++ * But inotify doesn't fire some necessary events,
++ * IN_ATTRIB for atime/nlink/pageio
++ * IN_DELETE for NFS dentry
++ * Let's do REVAL test too.
++ */
++ if (do_udba && inode) {
++ mode = (inode->i_mode & S_IFMT);
++ plus = (inode->i_nlink > 0);
++ first = au_h_iptr(inode, au_ibstart(inode));
++ ibs = au_ibstart(inode);
++ ibe = au_ibend(inode);
++ }
++
++ bstart = au_dbstart(dentry);
++ btail = bstart;
++ if (inode && S_ISDIR(inode->i_mode))
++ btail = au_dbtaildir(dentry);
++ for (bindex = bstart; bindex <= btail; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++
++ AuDbg("b%d, %.*s\n", bindex, AuDLNPair(h_dentry));
++ h_name = &h_dentry->d_name;
++ if (unlikely(do_udba
++ && !is_root
++ && (unhashed != !!d_unhashed(h_dentry)
++ || name->len != h_name->len
++ || memcmp(name->name, h_name->name, name->len))
++ )) {
++ AuDbg("unhash 0x%x 0x%x, %.*s %.*s\n",
++ unhashed, d_unhashed(h_dentry),
++ AuDLNPair(dentry), AuDLNPair(h_dentry));
++ goto err;
++ }
++
++ err = au_do_h_d_reval(h_dentry, nd, dentry, bindex);
++ if (unlikely(err))
++ /* do not goto err, to keep the errno */
++ break;
++
++ /* todo: plink too? */
++ if (!do_udba)
++ continue;
++
++ /* UDBA tests */
++ h_inode = h_dentry->d_inode;
++ if (unlikely(!!inode != !!h_inode))
++ goto err;
++
++ h_plus = plus;
++ h_mode = mode;
++ h_cached_inode = h_inode;
++ if (h_inode) {
++ h_mode = (h_inode->i_mode & S_IFMT);
++ h_plus = (h_inode->i_nlink > 0);
++ }
++ if (inode && ibs <= bindex && bindex <= ibe)
++ h_cached_inode = au_h_iptr(inode, bindex);
++
++ if (unlikely(plus != h_plus
++ || mode != h_mode
++ || h_cached_inode != h_inode))
++ goto err;
++ continue;
++
++ err:
++ err = -EINVAL;
++ break;
++ }
++
++ return err;
++}
++
++static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen)
++{
++ int err;
++ struct dentry *parent;
++ struct inode *inode;
++
++ inode = dentry->d_inode;
++ if (au_digen(dentry) == sigen && au_iigen(inode) == sigen)
++ return 0;
++
++ parent = dget_parent(dentry);
++ di_read_lock_parent(parent, AuLock_IR);
++ AuDebugOn(au_digen(parent) != sigen
++ || au_iigen(parent->d_inode) != sigen);
++ au_dbg_verify_gen(parent, sigen);
++
++ /* returns a number of positive dentries */
++ err = au_refresh_hdentry(dentry, inode->i_mode & S_IFMT);
++ if (err >= 0)
++ err = au_refresh_hinode(inode, dentry);
++
++ di_read_unlock(parent, AuLock_IR);
++ dput(parent);
++ return err;
++}
++
++int au_reval_dpath(struct dentry *dentry, unsigned int sigen)
++{
++ int err;
++ struct dentry *d, *parent;
++ struct inode *inode;
++
++ if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS))
++ return simple_reval_dpath(dentry, sigen);
++
++ /* slow loop, keep it simple and stupid */
++ /* cf: au_cpup_dirs() */
++ err = 0;
++ parent = NULL;
++ while (au_digen(dentry) != sigen
++ || au_iigen(dentry->d_inode) != sigen) {
++ d = dentry;
++ while (1) {
++ dput(parent);
++ parent = dget_parent(d);
++ if (au_digen(parent) == sigen
++ && au_iigen(parent->d_inode) == sigen)
++ break;
++ d = parent;
++ }
++
++ inode = d->d_inode;
++ if (d != dentry)
++ di_write_lock_child(d);
++
++ /* someone might update our dentry while we were sleeping */
++ if (au_digen(d) != sigen || au_iigen(d->d_inode) != sigen) {
++ di_read_lock_parent(parent, AuLock_IR);
++ /* returns a number of positive dentries */
++ err = au_refresh_hdentry(d, inode->i_mode & S_IFMT);
++ if (err >= 0)
++ err = au_refresh_hinode(inode, d);
++ di_read_unlock(parent, AuLock_IR);
++ }
++
++ if (d != dentry)
++ di_write_unlock(d);
++ dput(parent);
++ if (unlikely(err))
++ break;
++ }
++
++ return err;
++}
++
++/*
++ * if valid returns 1, otherwise 0.
++ */
++static int aufs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
++{
++ int valid, err;
++ unsigned int sigen;
++ unsigned char do_udba;
++ struct super_block *sb;
++ struct inode *inode;
++
++ err = -EINVAL;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW);
++ sigen = au_sigen(sb);
++ if (au_digen(dentry) != sigen) {
++ AuDebugOn(IS_ROOT(dentry));
++ if (inode)
++ err = au_reval_dpath(dentry, sigen);
++ if (unlikely(err))
++ goto out_dgrade;
++ AuDebugOn(au_digen(dentry) != sigen);
++ }
++ if (inode && au_iigen(inode) != sigen) {
++ AuDebugOn(IS_ROOT(dentry));
++ err = au_refresh_hinode(inode, dentry);
++ if (unlikely(err))
++ goto out_dgrade;
++ AuDebugOn(au_iigen(inode) != sigen);
++ }
++ di_downgrade_lock(dentry, AuLock_IR);
++
++ AuDebugOn(au_digen(dentry) != sigen);
++ AuDebugOn(inode && au_iigen(inode) != sigen);
++ err = -EINVAL;
++ do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE);
++ if (do_udba && inode) {
++ aufs_bindex_t bstart = au_ibstart(inode);
++
++ if (bstart >= 0
++ && au_test_higen(inode, au_h_iptr(inode, bstart)))
++ goto out;
++ }
++
++ err = h_d_revalidate(dentry, inode, nd, do_udba);
++ if (unlikely(!err && do_udba && au_dbstart(dentry) < 0))
++ /* both of real entry and whiteout found */
++ err = -EIO;
++ goto out;
++
++ out_dgrade:
++ di_downgrade_lock(dentry, AuLock_IR);
++ out:
++ au_store_oflag(nd, inode);
++ aufs_read_unlock(dentry, AuLock_IR);
++ AuTraceErr(err);
++ valid = !err;
++ if (!valid)
++ AuDbg("%.*s invalid\n", AuDLNPair(dentry));
++ return valid;
++}
++
++static void aufs_d_release(struct dentry *dentry)
++{
++ struct au_dinfo *dinfo;
++ aufs_bindex_t bend, bindex;
++
++ dinfo = dentry->d_fsdata;
++ if (!dinfo)
++ return;
++
++ /* dentry may not be revalidated */
++ bindex = dinfo->di_bstart;
++ if (bindex >= 0) {
++ struct au_hdentry *p;
++
++ bend = dinfo->di_bend;
++ p = dinfo->di_hdentry + bindex;
++ while (bindex++ <= bend) {
++ if (p->hd_dentry)
++ au_hdput(p);
++ p++;
++ }
++ }
++ kfree(dinfo->di_hdentry);
++ AuRwDestroy(&dinfo->di_rwsem);
++ au_cache_free_dinfo(dinfo);
++ au_hin_di_reinit(dentry);
++}
++
++struct dentry_operations aufs_dop = {
++ .d_revalidate = aufs_d_revalidate,
++ .d_release = aufs_d_release
++};
+diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h
+new file mode 100644
+index 0000000..b1f9a6e
+--- /dev/null
++++ b/fs/aufs/dentry.h
+@@ -0,0 +1,231 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * lookup and dentry operations
++ */
++
++#ifndef __AUFS_DENTRY_H__
++#define __AUFS_DENTRY_H__
++
++#ifdef __KERNEL__
++
++#include <linux/dcache.h>
++#include <linux/aufs_type.h>
++#include "rwsem.h"
++
++/* make a single member structure for future use */
++/* todo: remove this structure */
++struct au_hdentry {
++ struct dentry *hd_dentry;
++};
++
++struct au_dinfo {
++ atomic_t di_generation;
++
++ struct au_rwsem di_rwsem;
++ aufs_bindex_t di_bstart, di_bend, di_bwh, di_bdiropq;
++ struct au_hdentry *di_hdentry;
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* dentry.c */
++extern struct dentry_operations aufs_dop;
++struct au_branch;
++struct dentry *au_lkup_one(struct qstr *name, struct dentry *h_parent,
++ struct au_branch *br, struct nameidata *nd);
++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent,
++ struct au_branch *br);
++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir,
++ struct dentry *h_parent, struct au_branch *br);
++
++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type,
++ struct nameidata *nd);
++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex);
++int au_refresh_hdentry(struct dentry *dentry, mode_t type);
++int au_reval_dpath(struct dentry *dentry, unsigned int sigen);
++
++/* dinfo.c */
++int au_alloc_dinfo(struct dentry *dentry);
++int au_di_realloc(struct au_dinfo *dinfo, int nbr);
++
++void di_read_lock(struct dentry *d, int flags, unsigned int lsc);
++void di_read_unlock(struct dentry *d, int flags);
++void di_downgrade_lock(struct dentry *d, int flags);
++void di_write_lock(struct dentry *d, unsigned int lsc);
++void di_write_unlock(struct dentry *d);
++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir);
++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir);
++void di_write_unlock2(struct dentry *d1, struct dentry *d2);
++
++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex);
++aufs_bindex_t au_dbtail(struct dentry *dentry);
++aufs_bindex_t au_dbtaildir(struct dentry *dentry);
++
++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_dentry);
++void au_update_digen(struct dentry *dentry);
++void au_update_dbrange(struct dentry *dentry, int do_put_zero);
++void au_update_dbstart(struct dentry *dentry);
++void au_update_dbend(struct dentry *dentry);
++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry);
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct au_dinfo *au_di(struct dentry *dentry)
++{
++ return dentry->d_fsdata;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* lock subclass for dinfo */
++enum {
++ AuLsc_DI_CHILD, /* child first */
++ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hinotify */
++ AuLsc_DI_CHILD3, /* copyup dirs */
++ AuLsc_DI_PARENT,
++ AuLsc_DI_PARENT2,
++ AuLsc_DI_PARENT3
++};
++
++/*
++ * di_read_lock_child, di_write_lock_child,
++ * di_read_lock_child2, di_write_lock_child2,
++ * di_read_lock_child3, di_write_lock_child3,
++ * di_read_lock_parent, di_write_lock_parent,
++ * di_read_lock_parent2, di_write_lock_parent2,
++ * di_read_lock_parent3, di_write_lock_parent3,
++ */
++#define AuReadLockFunc(name, lsc) \
++static inline void di_read_lock_##name(struct dentry *d, int flags) \
++{ di_read_lock(d, flags, AuLsc_DI_##lsc); }
++
++#define AuWriteLockFunc(name, lsc) \
++static inline void di_write_lock_##name(struct dentry *d) \
++{ di_write_lock(d, AuLsc_DI_##lsc); }
++
++#define AuRWLockFuncs(name, lsc) \
++ AuReadLockFunc(name, lsc) \
++ AuWriteLockFunc(name, lsc)
++
++AuRWLockFuncs(child, CHILD);
++AuRWLockFuncs(child2, CHILD2);
++AuRWLockFuncs(child3, CHILD3);
++AuRWLockFuncs(parent, PARENT);
++AuRWLockFuncs(parent2, PARENT2);
++AuRWLockFuncs(parent3, PARENT3);
++
++#undef AuReadLockFunc
++#undef AuWriteLockFunc
++#undef AuRWLockFuncs
++
++#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem)
++#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem)
++#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem)
++
++/* ---------------------------------------------------------------------- */
++
++/* todo: memory barrier? */
++static inline unsigned int au_digen(struct dentry *d)
++{
++ return atomic_read(&au_di(d)->di_generation);
++}
++
++static inline void au_h_dentry_init(struct au_hdentry *hdentry)
++{
++ hdentry->hd_dentry = NULL;
++}
++
++static inline void au_hdput(struct au_hdentry *hd)
++{
++ dput(hd->hd_dentry);
++}
++
++static inline aufs_bindex_t au_dbstart(struct dentry *dentry)
++{
++ DiMustAnyLock(dentry);
++ return au_di(dentry)->di_bstart;
++}
++
++static inline aufs_bindex_t au_dbend(struct dentry *dentry)
++{
++ DiMustAnyLock(dentry);
++ return au_di(dentry)->di_bend;
++}
++
++static inline aufs_bindex_t au_dbwh(struct dentry *dentry)
++{
++ DiMustAnyLock(dentry);
++ return au_di(dentry)->di_bwh;
++}
++
++static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry)
++{
++ DiMustAnyLock(dentry);
++ return au_di(dentry)->di_bdiropq;
++}
++
++/* todo: hard/soft set? */
++static inline void au_set_dbstart(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ DiMustWriteLock(dentry);
++ au_di(dentry)->di_bstart = bindex;
++}
++
++static inline void au_set_dbend(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ DiMustWriteLock(dentry);
++ au_di(dentry)->di_bend = bindex;
++}
++
++static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ DiMustWriteLock(dentry);
++ /* dbwh can be outside of bstart - bend range */
++ au_di(dentry)->di_bwh = bindex;
++}
++
++static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ DiMustWriteLock(dentry);
++ au_di(dentry)->di_bdiropq = bindex;
++}
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_HINOTIFY
++static inline void au_digen_dec(struct dentry *d)
++{
++ atomic_dec_return(&au_di(d)->di_generation);
++}
++
++static inline void au_hin_di_reinit(struct dentry *dentry)
++{
++ dentry->d_fsdata = NULL;
++}
++#else
++static inline void au_hin_di_reinit(struct dentry *dentry __maybe_unused)
++{
++ /* empty */
++}
++#endif /* CONFIG_AUFS_HINOTIFY */
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_DENTRY_H__ */
+diff --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c
+new file mode 100644
+index 0000000..0010c99
+--- /dev/null
++++ b/fs/aufs/dinfo.c
+@@ -0,0 +1,367 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * dentry private data
++ */
++
++#include "aufs.h"
++
++int au_alloc_dinfo(struct dentry *dentry)
++{
++ struct au_dinfo *dinfo;
++ struct super_block *sb;
++ int nbr;
++
++ dinfo = au_cache_alloc_dinfo();
++ if (unlikely(!dinfo))
++ goto out;
++
++ sb = dentry->d_sb;
++ nbr = au_sbend(sb) + 1;
++ if (nbr <= 0)
++ nbr = 1;
++ dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS);
++ if (unlikely(!dinfo->di_hdentry))
++ goto out_dinfo;
++
++ atomic_set(&dinfo->di_generation, au_sigen(sb));
++ /* smp_mb(); */ /* atomic_set */
++ au_rw_init_wlock_nested(&dinfo->di_rwsem, AuLsc_DI_CHILD);
++ dinfo->di_bstart = -1;
++ dinfo->di_bend = -1;
++ dinfo->di_bwh = -1;
++ dinfo->di_bdiropq = -1;
++
++ dentry->d_fsdata = dinfo;
++ dentry->d_op = &aufs_dop;
++ return 0; /* success */
++
++ out_dinfo:
++ au_cache_free_dinfo(dinfo);
++ out:
++ return -ENOMEM;
++}
++
++int au_di_realloc(struct au_dinfo *dinfo, int nbr)
++{
++ int err, sz;
++ struct au_hdentry *hdp;
++
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ err = -ENOMEM;
++ sz = sizeof(*hdp) * (dinfo->di_bend + 1);
++ if (!sz)
++ sz = sizeof(*hdp);
++ hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS);
++ if (hdp) {
++ dinfo->di_hdentry = hdp;
++ err = 0;
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void do_ii_write_lock(struct inode *inode, unsigned int lsc)
++{
++ switch (lsc) {
++ case AuLsc_DI_CHILD:
++ ii_write_lock_child(inode);
++ break;
++ case AuLsc_DI_CHILD2:
++ ii_write_lock_child2(inode);
++ break;
++ case AuLsc_DI_CHILD3:
++ ii_write_lock_child3(inode);
++ break;
++ case AuLsc_DI_PARENT:
++ ii_write_lock_parent(inode);
++ break;
++ case AuLsc_DI_PARENT2:
++ ii_write_lock_parent2(inode);
++ break;
++ case AuLsc_DI_PARENT3:
++ ii_write_lock_parent3(inode);
++ break;
++ default:
++ BUG();
++ }
++}
++
++static void do_ii_read_lock(struct inode *inode, unsigned int lsc)
++{
++ switch (lsc) {
++ case AuLsc_DI_CHILD:
++ ii_read_lock_child(inode);
++ break;
++ case AuLsc_DI_CHILD2:
++ ii_read_lock_child2(inode);
++ break;
++ case AuLsc_DI_CHILD3:
++ ii_read_lock_child3(inode);
++ break;
++ case AuLsc_DI_PARENT:
++ ii_read_lock_parent(inode);
++ break;
++ case AuLsc_DI_PARENT2:
++ ii_read_lock_parent2(inode);
++ break;
++ case AuLsc_DI_PARENT3:
++ ii_read_lock_parent3(inode);
++ break;
++ default:
++ BUG();
++ }
++}
++
++void di_read_lock(struct dentry *d, int flags, unsigned int lsc)
++{
++ au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc);
++ if (d->d_inode) {
++ if (au_ftest_lock(flags, IW))
++ do_ii_write_lock(d->d_inode, lsc);
++ else if (au_ftest_lock(flags, IR))
++ do_ii_read_lock(d->d_inode, lsc);
++ }
++}
++
++void di_read_unlock(struct dentry *d, int flags)
++{
++ if (d->d_inode) {
++ if (au_ftest_lock(flags, IW))
++ ii_write_unlock(d->d_inode);
++ else if (au_ftest_lock(flags, IR))
++ ii_read_unlock(d->d_inode);
++ }
++ au_rw_read_unlock(&au_di(d)->di_rwsem);
++}
++
++void di_downgrade_lock(struct dentry *d, int flags)
++{
++ if (d->d_inode && au_ftest_lock(flags, IR))
++ ii_downgrade_lock(d->d_inode);
++ au_rw_dgrade_lock(&au_di(d)->di_rwsem);
++}
++
++void di_write_lock(struct dentry *d, unsigned int lsc)
++{
++ au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc);
++ if (d->d_inode)
++ do_ii_write_lock(d->d_inode, lsc);
++}
++
++void di_write_unlock(struct dentry *d)
++{
++ if (d->d_inode)
++ ii_write_unlock(d->d_inode);
++ au_rw_write_unlock(&au_di(d)->di_rwsem);
++}
++
++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir)
++{
++ AuDebugOn(d1 == d2
++ || d1->d_inode == d2->d_inode
++ || d1->d_sb != d2->d_sb);
++
++ if (isdir && au_test_subdir(d1, d2)) {
++ di_write_lock_child(d1);
++ di_write_lock_child2(d2);
++ } else {
++ /* there should be no races */
++ di_write_lock_child(d2);
++ di_write_lock_child2(d1);
++ }
++}
++
++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir)
++{
++ AuDebugOn(d1 == d2
++ || d1->d_inode == d2->d_inode
++ || d1->d_sb != d2->d_sb);
++
++ if (isdir && au_test_subdir(d1, d2)) {
++ di_write_lock_parent(d1);
++ di_write_lock_parent2(d2);
++ } else {
++ /* there should be no races */
++ di_write_lock_parent(d2);
++ di_write_lock_parent2(d1);
++ }
++}
++
++void di_write_unlock2(struct dentry *d1, struct dentry *d2)
++{
++ di_write_unlock(d1);
++ if (d1->d_inode == d2->d_inode)
++ au_rw_write_unlock(&au_di(d2)->di_rwsem);
++ else
++ di_write_unlock(d2);
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ struct dentry *d;
++
++ DiMustAnyLock(dentry);
++
++ if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry))
++ return NULL;
++ AuDebugOn(bindex < 0);
++ d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry;
++ AuDebugOn(d && (atomic_read(&d->d_count) <= 0));
++ return d;
++}
++
++aufs_bindex_t au_dbtail(struct dentry *dentry)
++{
++ aufs_bindex_t bend, bwh;
++
++ bend = au_dbend(dentry);
++ if (0 <= bend) {
++ bwh = au_dbwh(dentry);
++ if (!bwh)
++ return bwh;
++ if (0 < bwh && bwh < bend)
++ return bwh - 1;
++ }
++ return bend;
++}
++
++aufs_bindex_t au_dbtaildir(struct dentry *dentry)
++{
++ aufs_bindex_t bend, bopq;
++
++ bend = au_dbtail(dentry);
++ if (0 <= bend) {
++ bopq = au_dbdiropq(dentry);
++ if (0 <= bopq && bopq < bend)
++ bend = bopq;
++ }
++ return bend;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_dentry)
++{
++ struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex;
++
++ DiMustWriteLock(dentry);
++
++ if (hd->hd_dentry)
++ au_hdput(hd);
++ hd->hd_dentry = h_dentry;
++}
++
++void au_update_digen(struct dentry *dentry)
++{
++ atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb));
++ /* smp_mb(); */ /* atomic_set */
++}
++
++void au_update_dbrange(struct dentry *dentry, int do_put_zero)
++{
++ struct au_dinfo *dinfo;
++ struct dentry *h_d;
++
++ DiMustWriteLock(dentry);
++
++ dinfo = au_di(dentry);
++ if (!dinfo || dinfo->di_bstart < 0)
++ return;
++
++ if (do_put_zero) {
++ aufs_bindex_t bindex, bend;
++
++ bend = dinfo->di_bend;
++ for (bindex = dinfo->di_bstart; bindex <= bend; bindex++) {
++ h_d = dinfo->di_hdentry[0 + bindex].hd_dentry;
++ if (h_d && !h_d->d_inode)
++ au_set_h_dptr(dentry, bindex, NULL);
++ }
++ }
++
++ dinfo->di_bstart = -1;
++ while (++dinfo->di_bstart <= dinfo->di_bend)
++ if (dinfo->di_hdentry[0 + dinfo->di_bstart].hd_dentry)
++ break;
++ if (dinfo->di_bstart > dinfo->di_bend) {
++ dinfo->di_bstart = -1;
++ dinfo->di_bend = -1;
++ return;
++ }
++
++ dinfo->di_bend++;
++ while (0 <= --dinfo->di_bend)
++ if (dinfo->di_hdentry[0 + dinfo->di_bend].hd_dentry)
++ break;
++ AuDebugOn(dinfo->di_bstart > dinfo->di_bend || dinfo->di_bend < 0);
++}
++
++void au_update_dbstart(struct dentry *dentry)
++{
++ aufs_bindex_t bindex, bend;
++ struct dentry *h_dentry;
++
++ bend = au_dbend(dentry);
++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++ if (h_dentry->d_inode) {
++ au_set_dbstart(dentry, bindex);
++ return;
++ }
++ au_set_h_dptr(dentry, bindex, NULL);
++ }
++}
++
++void au_update_dbend(struct dentry *dentry)
++{
++ aufs_bindex_t bindex, bstart;
++ struct dentry *h_dentry;
++
++ bstart = au_dbstart(dentry);
++ for (bindex = au_dbend(dentry); bindex <= bstart; bindex--) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++ if (h_dentry->d_inode) {
++ au_set_dbend(dentry, bindex);
++ return;
++ }
++ au_set_h_dptr(dentry, bindex, NULL);
++ }
++}
++
++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry)
++{
++ aufs_bindex_t bindex, bend;
++
++ bend = au_dbend(dentry);
++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++)
++ if (au_h_dptr(dentry, bindex) == h_dentry)
++ return bindex;
++ return -1;
++}
+diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c
+new file mode 100644
+index 0000000..2d12c78
+--- /dev/null
++++ b/fs/aufs/dir.c
+@@ -0,0 +1,591 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * directory operations
++ */
++
++#include <linux/file.h>
++#include <linux/fs_stack.h>
++#include "aufs.h"
++
++void au_add_nlink(struct inode *dir, struct inode *h_dir)
++{
++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode));
++
++ dir->i_nlink += h_dir->i_nlink - 2;
++ if (h_dir->i_nlink < 2)
++ dir->i_nlink += 2;
++}
++
++void au_sub_nlink(struct inode *dir, struct inode *h_dir)
++{
++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode));
++
++ dir->i_nlink -= h_dir->i_nlink - 2;
++ if (h_dir->i_nlink < 2)
++ dir->i_nlink -= 2;
++}
++
++loff_t au_dir_size(struct file *file, struct dentry *dentry)
++{
++ loff_t sz;
++ aufs_bindex_t bindex, bend;
++ struct file *h_file;
++ struct dentry *h_dentry;
++
++ sz = 0;
++ if (file) {
++ AuDebugOn(!file->f_dentry);
++ AuDebugOn(!file->f_dentry->d_inode);
++ AuDebugOn(!S_ISDIR(file->f_dentry->d_inode->i_mode));
++
++ bend = au_fbend(file);
++ for (bindex = au_fbstart(file);
++ bindex <= bend && sz < KMALLOC_MAX_SIZE;
++ bindex++) {
++ h_file = au_h_fptr(file, bindex);
++ if (h_file
++ && h_file->f_dentry
++ && h_file->f_dentry->d_inode)
++ sz += i_size_read(h_file->f_dentry->d_inode);
++ }
++ } else {
++ AuDebugOn(!dentry);
++ AuDebugOn(!dentry->d_inode);
++ AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode));
++
++ bend = au_dbtaildir(dentry);
++ for (bindex = au_dbstart(dentry);
++ bindex <= bend && sz < KMALLOC_MAX_SIZE;
++ bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry && h_dentry->d_inode)
++ sz += i_size_read(h_dentry->d_inode);
++ }
++ }
++ if (sz < KMALLOC_MAX_SIZE)
++ sz = roundup_pow_of_two(sz);
++ if (sz > KMALLOC_MAX_SIZE)
++ sz = KMALLOC_MAX_SIZE;
++ else if (sz < NAME_MAX) {
++ BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX);
++ sz = AUFS_RDBLK_DEF;
++ }
++ return sz;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int reopen_dir(struct file *file)
++{
++ int err;
++ unsigned int flags;
++ aufs_bindex_t bindex, btail, bstart;
++ struct dentry *dentry, *h_dentry;
++ struct file *h_file;
++
++ /* open all lower dirs */
++ dentry = file->f_dentry;
++ bstart = au_dbstart(dentry);
++ for (bindex = au_fbstart(file); bindex < bstart; bindex++)
++ au_set_h_fptr(file, bindex, NULL);
++ au_set_fbstart(file, bstart);
++
++ btail = au_dbtaildir(dentry);
++ for (bindex = au_fbend(file); btail < bindex; bindex--)
++ au_set_h_fptr(file, bindex, NULL);
++ au_set_fbend(file, btail);
++
++ flags = file->f_flags;
++ for (bindex = bstart; bindex <= btail; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++ h_file = au_h_fptr(file, bindex);
++ if (h_file)
++ continue;
++
++ h_file = au_h_open(dentry, bindex, flags, file);
++ err = PTR_ERR(h_file);
++ if (IS_ERR(h_file))
++ goto out; /* close all? */
++ au_set_h_fptr(file, bindex, h_file);
++ }
++ au_update_figen(file);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ err = 0;
++
++ out:
++ return err;
++}
++
++static int do_open_dir(struct file *file, int flags)
++{
++ int err;
++ aufs_bindex_t bindex, btail;
++ struct dentry *dentry, *h_dentry;
++ struct file *h_file;
++
++ FiMustWriteLock(file);
++
++ err = 0;
++ dentry = file->f_dentry;
++ au_set_fvdir_cache(file, NULL);
++ au_fi(file)->fi_maintain_plink = 0;
++ file->f_version = dentry->d_inode->i_version;
++ bindex = au_dbstart(dentry);
++ au_set_fbstart(file, bindex);
++ btail = au_dbtaildir(dentry);
++ au_set_fbend(file, btail);
++ for (; !err && bindex <= btail; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!h_dentry)
++ continue;
++
++ h_file = au_h_open(dentry, bindex, flags, file);
++ if (IS_ERR(h_file)) {
++ err = PTR_ERR(h_file);
++ break;
++ }
++ au_set_h_fptr(file, bindex, h_file);
++ }
++ au_update_figen(file);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ if (!err)
++ return 0; /* success */
++
++ /* close all */
++ for (bindex = au_fbstart(file); bindex <= btail; bindex++)
++ au_set_h_fptr(file, bindex, NULL);
++ au_set_fbstart(file, -1);
++ au_set_fbend(file, -1);
++ return err;
++}
++
++static int aufs_open_dir(struct inode *inode __maybe_unused,
++ struct file *file)
++{
++ return au_do_open(file, do_open_dir);
++}
++
++static int aufs_release_dir(struct inode *inode __maybe_unused,
++ struct file *file)
++{
++ struct au_vdir *vdir_cache;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++
++ sb = file->f_dentry->d_sb;
++ si_noflush_read_lock(sb);
++ fi_write_lock(file);
++ vdir_cache = au_fvdir_cache(file);
++ if (vdir_cache)
++ au_vdir_free(vdir_cache);
++ if (au_fi(file)->fi_maintain_plink) {
++ sbinfo = au_sbi(sb);
++ /* clear the flag without write-lock */
++ sbinfo->au_si_status &= ~AuSi_MAINTAIN_PLINK;
++ smp_mb();
++ wake_up_all(&sbinfo->si_plink_wq);
++ }
++ fi_write_unlock(file);
++ au_finfo_fin(file);
++ si_read_unlock(sb);
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync)
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct inode *inode;
++ struct super_block *sb;
++
++ err = 0;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ IMustLock(inode);
++ bend = au_dbend(dentry);
++ for (bindex = au_dbstart(dentry); !err && bindex <= bend; bindex++) {
++ struct path h_path;
++ struct inode *h_inode;
++
++ if (au_test_ro(sb, bindex, inode))
++ continue;
++ h_path.dentry = au_h_dptr(dentry, bindex);
++ if (!h_path.dentry)
++ continue;
++ h_inode = h_path.dentry->d_inode;
++ if (!h_inode)
++ continue;
++
++ /* no mnt_want_write() */
++ /* cf. fs/nsfd/vfs.c and fs/nfsd/nfs4recover.c */
++ /* todo: inotiry fired? */
++ h_path.mnt = au_sbr_mnt(sb, bindex);
++ mutex_lock(&h_inode->i_mutex);
++ err = filemap_fdatawrite(h_inode->i_mapping);
++ AuDebugOn(!h_inode->i_fop);
++ if (!err && h_inode->i_fop->fsync)
++ err = h_inode->i_fop->fsync(NULL, h_path.dentry,
++ datasync);
++ if (!err)
++ err = filemap_fdatawrite(h_inode->i_mapping);
++ if (!err)
++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
++ mutex_unlock(&h_inode->i_mutex);
++ }
++
++ return err;
++}
++
++static int au_do_fsync_dir(struct file *file, int datasync)
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct file *h_file;
++ struct super_block *sb;
++ struct inode *inode;
++ struct mutex *h_mtx;
++
++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ sb = file->f_dentry->d_sb;
++ inode = file->f_dentry->d_inode;
++ bend = au_fbend(file);
++ for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) {
++ h_file = au_h_fptr(file, bindex);
++ if (!h_file || au_test_ro(sb, bindex, inode))
++ continue;
++
++ err = (int)do_fsync(h_file, datasync);
++ if (!err) {
++ h_mtx = &h_file->f_dentry->d_inode->i_mutex;
++ mutex_lock(h_mtx);
++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL);
++ /*ignore*/
++ mutex_unlock(h_mtx);
++ }
++ }
++
++ out:
++ return err;
++}
++
++/*
++ * @file may be NULL
++ */
++static int aufs_fsync_dir(struct file *file, struct dentry *dentry,
++ int datasync)
++{
++ int err;
++ struct super_block *sb;
++
++ IMustLock(dentry->d_inode);
++
++ err = 0;
++ sb = dentry->d_sb;
++ si_noflush_read_lock(sb);
++ if (file)
++ err = au_do_fsync_dir(file, datasync);
++ else {
++ di_write_lock_child(dentry);
++ err = au_do_fsync_dir_no_file(dentry, datasync);
++ }
++ au_cpup_attr_timesizes(dentry->d_inode);
++ di_write_unlock(dentry);
++ if (file)
++ fi_write_unlock(file);
++
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_readdir(struct file *file, void *dirent, filldir_t filldir)
++{
++ int err;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ IMustLock(inode);
++
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++ err = au_vdir_init(file);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++
++ if (!au_test_nfsd(current)) {
++ err = au_vdir_fill_de(file, dirent, filldir);
++ fsstack_copy_attr_atime(inode,
++ au_h_iptr(inode, au_ibstart(inode)));
++ } else {
++ /*
++ * nfsd filldir may call lookup_one_len(), vfs_getattr(),
++ * encode_fh() and others.
++ */
++ struct inode *h_inode = au_h_iptr(inode, au_ibstart(inode));
++
++ di_read_unlock(dentry, AuLock_IR);
++ si_read_unlock(sb);
++ lockdep_off();
++ err = au_vdir_fill_de(file, dirent, filldir);
++ lockdep_on();
++ fsstack_copy_attr_atime(inode, h_inode);
++ fi_write_unlock(file);
++
++ AuTraceErr(err);
++ return err;
++ }
++
++ out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++ out:
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++#define AuTestEmpty_WHONLY 1
++#define AuTestEmpty_CALLED (1 << 1)
++#define AuTestEmpty_SHWH (1 << 2)
++#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name)
++#define au_fset_testempty(flags, name) { (flags) |= AuTestEmpty_##name; }
++#define au_fclr_testempty(flags, name) { (flags) &= ~AuTestEmpty_##name; }
++
++#ifndef CONFIG_AUFS_SHWH
++#undef AuTestEmpty_SHWH
++#define AuTestEmpty_SHWH 0
++#endif
++
++struct test_empty_arg {
++ struct au_nhash *whlist;
++ unsigned int flags;
++ int err;
++ aufs_bindex_t bindex;
++};
++
++static int test_empty_cb(void *__arg, const char *__name, int namelen,
++ loff_t offset __maybe_unused, u64 ino,
++ unsigned int d_type)
++{
++ struct test_empty_arg *arg = __arg;
++ char *name = (void *)__name;
++
++ arg->err = 0;
++ au_fset_testempty(arg->flags, CALLED);
++ /* smp_mb(); */
++ if (name[0] == '.'
++ && (namelen == 1 || (name[1] == '.' && namelen == 2)))
++ goto out; /* success */
++
++ if (namelen <= AUFS_WH_PFX_LEN
++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
++ if (au_ftest_testempty(arg->flags, WHONLY)
++ && !au_nhash_test_known_wh(arg->whlist, name, namelen))
++ arg->err = -ENOTEMPTY;
++ goto out;
++ }
++
++ name += AUFS_WH_PFX_LEN;
++ namelen -= AUFS_WH_PFX_LEN;
++ if (!au_nhash_test_known_wh(arg->whlist, name, namelen))
++ arg->err = au_nhash_append_wh
++ (arg->whlist, name, namelen, ino, d_type, arg->bindex,
++ au_ftest_testempty(arg->flags, SHWH));
++
++ out:
++ /* smp_mb(); */
++ AuTraceErr(arg->err);
++ return arg->err;
++}
++
++static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg)
++{
++ int err;
++ struct file *h_file;
++
++ h_file = au_h_open(dentry, arg->bindex,
++ O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE,
++ /*file*/NULL);
++ err = PTR_ERR(h_file);
++ if (IS_ERR(h_file))
++ goto out;
++
++ err = 0;
++ if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE)
++ && !h_file->f_dentry->d_inode->i_nlink)
++ goto out_put;
++
++ do {
++ arg->err = 0;
++ au_fclr_testempty(arg->flags, CALLED);
++ /* smp_mb(); */
++ err = vfsub_readdir(h_file, test_empty_cb, arg);
++ if (err >= 0)
++ err = arg->err;
++ } while (!err && au_ftest_testempty(arg->flags, CALLED));
++
++ out_put:
++ fput(h_file);
++ au_sbr_put(dentry->d_sb, arg->bindex);
++ out:
++ return err;
++}
++
++struct do_test_empty_args {
++ int *errp;
++ struct dentry *dentry;
++ struct test_empty_arg *arg;
++};
++
++static void call_do_test_empty(void *args)
++{
++ struct do_test_empty_args *a = args;
++ *a->errp = do_test_empty(a->dentry, a->arg);
++}
++
++static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg)
++{
++ int err, wkq_err;
++ struct dentry *h_dentry;
++ struct inode *h_inode;
++
++ h_dentry = au_h_dptr(dentry, arg->bindex);
++ h_inode = h_dentry->d_inode;
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ);
++ mutex_unlock(&h_inode->i_mutex);
++ if (!err)
++ err = do_test_empty(dentry, arg);
++ else {
++ struct do_test_empty_args args = {
++ .errp = &err,
++ .dentry = dentry,
++ .arg = arg
++ };
++ unsigned int flags = arg->flags;
++
++ wkq_err = au_wkq_wait(call_do_test_empty, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ arg->flags = flags;
++ }
++
++ return err;
++}
++
++int au_test_empty_lower(struct dentry *dentry)
++{
++ int err;
++ unsigned int rdhash;
++ aufs_bindex_t bindex, bstart, btail;
++ struct au_nhash whlist;
++ struct test_empty_arg arg;
++
++ SiMustAnyLock(dentry->d_sb);
++
++ rdhash = au_sbi(dentry->d_sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry));
++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++
++ arg.flags = 0;
++ arg.whlist = &whlist;
++ bstart = au_dbstart(dentry);
++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH))
++ au_fset_testempty(arg.flags, SHWH);
++ arg.bindex = bstart;
++ err = do_test_empty(dentry, &arg);
++ if (unlikely(err))
++ goto out_whlist;
++
++ au_fset_testempty(arg.flags, WHONLY);
++ btail = au_dbtaildir(dentry);
++ for (bindex = bstart + 1; !err && bindex <= btail; bindex++) {
++ struct dentry *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry && h_dentry->d_inode) {
++ arg.bindex = bindex;
++ err = do_test_empty(dentry, &arg);
++ }
++ }
++
++ out_whlist:
++ au_nhash_wh_free(&whlist);
++ out:
++ return err;
++}
++
++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist)
++{
++ int err;
++ struct test_empty_arg arg;
++ aufs_bindex_t bindex, btail;
++
++ err = 0;
++ arg.whlist = whlist;
++ arg.flags = AuTestEmpty_WHONLY;
++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH))
++ au_fset_testempty(arg.flags, SHWH);
++ btail = au_dbtaildir(dentry);
++ for (bindex = au_dbstart(dentry); !err && bindex <= btail; bindex++) {
++ struct dentry *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry && h_dentry->d_inode) {
++ arg.bindex = bindex;
++ err = sio_test_empty(dentry, &arg);
++ }
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct file_operations aufs_dir_fop = {
++ .read = generic_read_dir,
++ .readdir = aufs_readdir,
++ .unlocked_ioctl = aufs_ioctl_dir,
++ .open = aufs_open_dir,
++ .release = aufs_release_dir,
++ .flush = aufs_flush,
++ .fsync = aufs_fsync_dir
++};
+diff --git a/fs/aufs/dir.h b/fs/aufs/dir.h
+new file mode 100644
+index 0000000..dc40539
+--- /dev/null
++++ b/fs/aufs/dir.h
+@@ -0,0 +1,127 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * directory operations
++ */
++
++#ifndef __AUFS_DIR_H__
++#define __AUFS_DIR_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/aufs_type.h>
++
++/* ---------------------------------------------------------------------- */
++
++/* need to be faster and smaller */
++
++struct au_nhash {
++ unsigned int nh_num;
++ struct hlist_head *nh_head;
++};
++
++struct au_vdir_destr {
++ unsigned char len;
++ unsigned char name[0];
++} __packed;
++
++struct au_vdir_dehstr {
++ struct hlist_node hash;
++ struct au_vdir_destr *str;
++};
++
++struct au_vdir_de {
++ ino_t de_ino;
++ unsigned char de_type;
++ /* caution: packed */
++ struct au_vdir_destr de_str;
++} __packed;
++
++struct au_vdir_wh {
++ struct hlist_node wh_hash;
++#ifdef CONFIG_AUFS_SHWH
++ ino_t wh_ino;
++ aufs_bindex_t wh_bindex;
++ unsigned char wh_type;
++#else
++ aufs_bindex_t wh_bindex;
++#endif
++ /* caution: packed */
++ struct au_vdir_destr wh_str;
++} __packed;
++
++union au_vdir_deblk_p {
++ unsigned char *deblk;
++ struct au_vdir_de *de;
++};
++
++struct au_vdir {
++ unsigned char **vd_deblk;
++ unsigned long vd_nblk;
++ struct {
++ unsigned long ul;
++ union au_vdir_deblk_p p;
++ } vd_last;
++
++ unsigned long vd_version;
++ unsigned int vd_deblk_sz;
++ unsigned long vd_jiffy;
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* dir.c */
++extern struct file_operations aufs_dir_fop;
++void au_add_nlink(struct inode *dir, struct inode *h_dir);
++void au_sub_nlink(struct inode *dir, struct inode *h_dir);
++loff_t au_dir_size(struct file *file, struct dentry *dentry);
++int au_test_empty_lower(struct dentry *dentry);
++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist);
++
++/* vdir.c */
++unsigned int au_rdhash_est(loff_t sz);
++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp);
++void au_nhash_wh_free(struct au_nhash *whlist);
++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt,
++ int limit);
++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen);
++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino,
++ unsigned int d_type, aufs_bindex_t bindex,
++ unsigned char shwh);
++void au_vdir_free(struct au_vdir *vdir);
++int au_vdir_init(struct file *file);
++int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir);
++
++/* ioctl.c */
++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg);
++
++#ifdef CONFIG_AUFS_RDU
++/* rdu.c */
++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
++#else
++static inline long au_rdu_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ return -EINVAL;
++}
++#endif
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_DIR_H__ */
+diff --git a/fs/aufs/export.c b/fs/aufs/export.c
+new file mode 100644
+index 0000000..13bef9a
+--- /dev/null
++++ b/fs/aufs/export.c
+@@ -0,0 +1,745 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * export via nfs
++ */
++
++#include <linux/exportfs.h>
++#include <linux/file.h>
++#include <linux/mnt_namespace.h>
++#include <linux/namei.h>
++#include <linux/random.h>
++#include "aufs.h"
++
++union conv {
++#ifdef CONFIG_AUFS_INO_T_64
++ __u32 a[2];
++#else
++ __u32 a[1];
++#endif
++ ino_t ino;
++};
++
++static ino_t decode_ino(__u32 *a)
++{
++ union conv u;
++
++ BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a));
++ u.a[0] = a[0];
++#ifdef CONFIG_AUFS_INO_T_64
++ u.a[1] = a[1];
++#endif
++ return u.ino;
++}
++
++static void encode_ino(__u32 *a, ino_t ino)
++{
++ union conv u;
++
++ u.ino = ino;
++ a[0] = u.a[0];
++#ifdef CONFIG_AUFS_INO_T_64
++ a[1] = u.a[1];
++#endif
++}
++
++/* NFS file handle */
++enum {
++ Fh_br_id,
++ Fh_sigen,
++#ifdef CONFIG_AUFS_INO_T_64
++ /* support 64bit inode number */
++ Fh_ino1,
++ Fh_ino2,
++ Fh_dir_ino1,
++ Fh_dir_ino2,
++#else
++ Fh_ino1,
++ Fh_dir_ino1,
++#endif
++ Fh_igen,
++ Fh_h_type,
++ Fh_tail,
++
++ Fh_ino = Fh_ino1,
++ Fh_dir_ino = Fh_dir_ino1
++};
++
++static int au_test_anon(struct dentry *dentry)
++{
++ return !!(dentry->d_flags & DCACHE_DISCONNECTED);
++}
++
++/* ---------------------------------------------------------------------- */
++/* inode generation external table */
++
++int au_xigen_inc(struct inode *inode)
++{
++ int err;
++ loff_t pos;
++ ssize_t sz;
++ __u32 igen;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++
++ err = 0;
++ sb = inode->i_sb;
++ sbinfo = au_sbi(sb);
++ /*
++ * temporary workaround for escaping from SiMustAnyLock() in
++ * au_mntflags(), since this function is called from au_iinfo_fin().
++ */
++ if (unlikely(!au_opt_test(sbinfo->si_mntflags, XINO)))
++ goto out;
++
++ pos = inode->i_ino;
++ pos *= sizeof(igen);
++ igen = inode->i_generation + 1;
++ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen,
++ sizeof(igen), &pos);
++ if (sz == sizeof(igen))
++ goto out; /* success */
++
++ err = sz;
++ if (unlikely(sz >= 0)) {
++ err = -EIO;
++ AuIOErr("xigen error (%zd)\n", sz);
++ }
++
++ out:
++ return err;
++}
++
++int au_xigen_new(struct inode *inode)
++{
++ int err;
++ loff_t pos;
++ ssize_t sz;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++
++ err = 0;
++ /* todo: dirty, at mount time */
++ if (inode->i_ino == AUFS_ROOT_INO)
++ goto out;
++ sb = inode->i_sb;
++ SiMustAnyLock(sb);
++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO)))
++ goto out;
++
++ err = -EFBIG;
++ pos = inode->i_ino;
++ if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) {
++ AuIOErr1("too large i%lld\n", pos);
++ goto out;
++ }
++ pos *= sizeof(inode->i_generation);
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ file = sbinfo->si_xigen;
++ BUG_ON(!file);
++
++ if (i_size_read(file->f_dentry->d_inode)
++ < pos + sizeof(inode->i_generation)) {
++ inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next);
++ sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation,
++ sizeof(inode->i_generation), &pos);
++ } else
++ sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation,
++ sizeof(inode->i_generation), &pos);
++ if (sz == sizeof(inode->i_generation))
++ goto out; /* success */
++
++ err = sz;
++ if (unlikely(sz >= 0)) {
++ err = -EIO;
++ AuIOErr("xigen error (%zd)\n", sz);
++ }
++
++ out:
++ return err;
++}
++
++int au_xigen_set(struct super_block *sb, struct file *base)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ file = au_xino_create2(base, sbinfo->si_xigen);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++ err = 0;
++ if (sbinfo->si_xigen)
++ fput(sbinfo->si_xigen);
++ sbinfo->si_xigen = file;
++
++ out:
++ return err;
++}
++
++void au_xigen_clr(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ if (sbinfo->si_xigen) {
++ fput(sbinfo->si_xigen);
++ sbinfo->si_xigen = NULL;
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino,
++ ino_t dir_ino)
++{
++ struct dentry *dentry, *d;
++ struct inode *inode;
++ unsigned int sigen;
++
++ dentry = NULL;
++ inode = ilookup(sb, ino);
++ if (!inode)
++ goto out;
++
++ dentry = ERR_PTR(-ESTALE);
++ sigen = au_sigen(sb);
++ if (unlikely(is_bad_inode(inode)
++ || IS_DEADDIR(inode)
++ || sigen != au_iigen(inode)))
++ goto out_iput;
++
++ dentry = NULL;
++ if (!dir_ino || S_ISDIR(inode->i_mode))
++ dentry = d_find_alias(inode);
++ else {
++ spin_lock(&dcache_lock);
++ list_for_each_entry(d, &inode->i_dentry, d_alias)
++ if (!au_test_anon(d)
++ && d->d_parent->d_inode->i_ino == dir_ino) {
++ dentry = dget_locked(d);
++ break;
++ }
++ spin_unlock(&dcache_lock);
++ }
++ if (unlikely(dentry && sigen != au_digen(dentry))) {
++ dput(dentry);
++ dentry = ERR_PTR(-ESTALE);
++ }
++
++ out_iput:
++ iput(inode);
++ out:
++ return dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* todo: dirty? */
++/* if exportfs_decode_fh() passed vfsmount*, we could be happy */
++static struct vfsmount *au_mnt_get(struct super_block *sb)
++{
++ struct mnt_namespace *ns;
++ struct vfsmount *pos, *mnt;
++
++ spin_lock(&vfsmount_lock);
++ /* no get/put ?? */
++ AuDebugOn(!current->nsproxy);
++ ns = current->nsproxy->mnt_ns;
++ AuDebugOn(!ns);
++ mnt = NULL;
++ /* the order (reverse) will not be a problem */
++ list_for_each_entry(pos, &ns->list, mnt_list)
++ if (pos->mnt_sb == sb) {
++ mnt = mntget(pos);
++ break;
++ }
++ spin_unlock(&vfsmount_lock);
++ AuDebugOn(!mnt);
++
++ return mnt;
++}
++
++struct au_nfsd_si_lock {
++ const unsigned int sigen;
++ const aufs_bindex_t br_id;
++ unsigned char force_lock;
++};
++
++static aufs_bindex_t si_nfsd_read_lock(struct super_block *sb,
++ struct au_nfsd_si_lock *nsi_lock)
++{
++ aufs_bindex_t bindex;
++
++ si_read_lock(sb, AuLock_FLUSH);
++
++ /* branch id may be wrapped around */
++ bindex = au_br_index(sb, nsi_lock->br_id);
++ if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb))
++ goto out; /* success */
++
++ if (!nsi_lock->force_lock)
++ si_read_unlock(sb);
++ bindex = -1;
++
++ out:
++ return bindex;
++}
++
++struct find_name_by_ino {
++ int called, found;
++ ino_t ino;
++ char *name;
++ int namelen;
++};
++
++static int
++find_name_by_ino(void *arg, const char *name, int namelen, loff_t offset,
++ u64 ino, unsigned int d_type)
++{
++ struct find_name_by_ino *a = arg;
++
++ a->called++;
++ if (a->ino != ino)
++ return 0;
++
++ memcpy(a->name, name, namelen);
++ a->namelen = namelen;
++ a->found = 1;
++ return 1;
++}
++
++static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino,
++ struct au_nfsd_si_lock *nsi_lock)
++{
++ struct dentry *dentry, *parent;
++ struct file *file;
++ struct inode *dir;
++ struct find_name_by_ino arg;
++ int err;
++
++ parent = path->dentry;
++ if (nsi_lock)
++ si_read_unlock(parent->d_sb);
++ path_get(path);
++ file = dentry_open(parent, path->mnt, au_dir_roflags);
++ dentry = (void *)file;
++ if (IS_ERR(file))
++ goto out;
++
++ dentry = ERR_PTR(-ENOMEM);
++ arg.name = __getname();
++ if (unlikely(!arg.name))
++ goto out_file;
++ arg.ino = ino;
++ arg.found = 0;
++ do {
++ arg.called = 0;
++ /* smp_mb(); */
++ err = vfsub_readdir(file, find_name_by_ino, &arg);
++ } while (!err && !arg.found && arg.called);
++ dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_name;
++ dentry = ERR_PTR(-ENOENT);
++ if (!arg.found)
++ goto out_name;
++
++ /* do not call au_lkup_one() */
++ dir = parent->d_inode;
++ mutex_lock(&dir->i_mutex);
++ dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen);
++ mutex_unlock(&dir->i_mutex);
++ AuTraceErrPtr(dentry);
++ if (IS_ERR(dentry))
++ goto out_name;
++ AuDebugOn(au_test_anon(dentry));
++ if (unlikely(!dentry->d_inode)) {
++ dput(dentry);
++ dentry = ERR_PTR(-ENOENT);
++ }
++
++ out_name:
++ __putname(arg.name);
++ out_file:
++ fput(file);
++ out:
++ if (unlikely(nsi_lock
++ && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0))
++ if (!IS_ERR(dentry)) {
++ dput(dentry);
++ dentry = ERR_PTR(-ESTALE);
++ }
++ AuTraceErrPtr(dentry);
++ return dentry;
++}
++
++static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino,
++ ino_t dir_ino,
++ struct au_nfsd_si_lock *nsi_lock)
++{
++ struct dentry *dentry;
++ struct path path;
++
++ if (dir_ino != AUFS_ROOT_INO) {
++ path.dentry = decode_by_ino(sb, dir_ino, 0);
++ dentry = path.dentry;
++ if (!path.dentry || IS_ERR(path.dentry))
++ goto out;
++ AuDebugOn(au_test_anon(path.dentry));
++ } else
++ path.dentry = dget(sb->s_root);
++
++ path.mnt = au_mnt_get(sb);
++ dentry = au_lkup_by_ino(&path, ino, nsi_lock);
++ path_put(&path);
++
++ out:
++ AuTraceErrPtr(dentry);
++ return dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int h_acceptable(void *expv, struct dentry *dentry)
++{
++ return 1;
++}
++
++static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath,
++ char *buf, int len, struct super_block *sb)
++{
++ char *p;
++ int n;
++ struct path path;
++
++ p = d_path(h_rootpath, buf, len);
++ if (IS_ERR(p))
++ goto out;
++ n = strlen(p);
++
++ path.mnt = h_rootpath->mnt;
++ path.dentry = h_parent;
++ p = d_path(&path, buf, len);
++ if (IS_ERR(p))
++ goto out;
++ if (n != 1)
++ p += n;
++
++ path.mnt = au_mnt_get(sb);
++ path.dentry = sb->s_root;
++ p = d_path(&path, buf, len - strlen(p));
++ mntput(path.mnt);
++ if (IS_ERR(p))
++ goto out;
++ if (n != 1)
++ p[strlen(p)] = '/';
++
++ out:
++ AuTraceErrPtr(p);
++ return p;
++}
++
++static
++struct dentry *decode_by_path(struct super_block *sb, aufs_bindex_t bindex,
++ ino_t ino, __u32 *fh, int fh_len,
++ struct au_nfsd_si_lock *nsi_lock)
++{
++ struct dentry *dentry, *h_parent, *root;
++ struct super_block *h_sb;
++ char *pathname, *p;
++ struct vfsmount *h_mnt;
++ struct au_branch *br;
++ int err;
++ struct path path;
++
++ br = au_sbr(sb, bindex);
++ /* au_br_get(br); */
++ h_mnt = br->br_mnt;
++ h_sb = h_mnt->mnt_sb;
++ /* todo: call lower fh_to_dentry()? fh_to_parent()? */
++ h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail),
++ fh_len - Fh_tail, fh[Fh_h_type],
++ h_acceptable, /*context*/NULL);
++ dentry = h_parent;
++ if (unlikely(!h_parent || IS_ERR(h_parent))) {
++ AuWarn1("%s decode_fh failed, %ld\n",
++ au_sbtype(h_sb), PTR_ERR(h_parent));
++ goto out;
++ }
++ dentry = NULL;
++ if (unlikely(au_test_anon(h_parent))) {
++ AuWarn1("%s decode_fh returned a disconnected dentry\n",
++ au_sbtype(h_sb));
++ goto out_h_parent;
++ }
++
++ dentry = ERR_PTR(-ENOMEM);
++ pathname = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!pathname))
++ goto out_h_parent;
++
++ root = sb->s_root;
++ path.mnt = h_mnt;
++ di_read_lock_parent(root, !AuLock_IR);
++ path.dentry = au_h_dptr(root, bindex);
++ di_read_unlock(root, !AuLock_IR);
++ p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb);
++ dentry = (void *)p;
++ if (IS_ERR(p))
++ goto out_pathname;
++
++ si_read_unlock(sb);
++ err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
++ dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_relock;
++
++ dentry = ERR_PTR(-ENOENT);
++ AuDebugOn(au_test_anon(path.dentry));
++ if (unlikely(!path.dentry->d_inode))
++ goto out_path;
++
++ if (ino != path.dentry->d_inode->i_ino)
++ dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL);
++ else
++ dentry = dget(path.dentry);
++
++ out_path:
++ path_put(&path);
++ out_relock:
++ if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0))
++ if (!IS_ERR(dentry)) {
++ dput(dentry);
++ dentry = ERR_PTR(-ESTALE);
++ }
++ out_pathname:
++ free_page((unsigned long)pathname);
++ out_h_parent:
++ dput(h_parent);
++ out:
++ /* au_br_put(br); */
++ AuTraceErrPtr(dentry);
++ return dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct dentry *
++aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
++ int fh_type)
++{
++ struct dentry *dentry;
++ __u32 *fh = fid->raw;
++ ino_t ino, dir_ino;
++ aufs_bindex_t bindex;
++ struct au_nfsd_si_lock nsi_lock = {
++ .sigen = fh[Fh_sigen],
++ .br_id = fh[Fh_br_id],
++ .force_lock = 0
++ };
++
++ AuDebugOn(fh_len < Fh_tail);
++
++ dentry = ERR_PTR(-ESTALE);
++ /* branch id may be wrapped around */
++ bindex = si_nfsd_read_lock(sb, &nsi_lock);
++ if (unlikely(bindex < 0))
++ goto out;
++ nsi_lock.force_lock = 1;
++
++ /* is this inode still cached? */
++ ino = decode_ino(fh + Fh_ino);
++ AuDebugOn(ino == AUFS_ROOT_INO);
++ dir_ino = decode_ino(fh + Fh_dir_ino);
++ dentry = decode_by_ino(sb, ino, dir_ino);
++ if (IS_ERR(dentry))
++ goto out_unlock;
++ if (dentry)
++ goto accept;
++
++ /* is the parent dir cached? */
++ dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock);
++ if (IS_ERR(dentry))
++ goto out_unlock;
++ if (dentry)
++ goto accept;
++
++ /* lookup path */
++ dentry = decode_by_path(sb, bindex, ino, fh, fh_len, &nsi_lock);
++ if (IS_ERR(dentry))
++ goto out_unlock;
++ if (unlikely(!dentry))
++ /* todo?: make it ESTALE */
++ goto out_unlock;
++
++ accept:
++ if (dentry->d_inode->i_generation == fh[Fh_igen])
++ goto out_unlock; /* success */
++
++ dput(dentry);
++ dentry = ERR_PTR(-ESTALE);
++ out_unlock:
++ si_read_unlock(sb);
++ out:
++ AuTraceErrPtr(dentry);
++ return dentry;
++}
++
++#if 0 /* reserved for future use */
++/* support subtreecheck option */
++static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid,
++ int fh_len, int fh_type)
++{
++ struct dentry *parent;
++ __u32 *fh = fid->raw;
++ ino_t dir_ino;
++
++ dir_ino = decode_ino(fh + Fh_dir_ino);
++ parent = decode_by_ino(sb, dir_ino, 0);
++ if (IS_ERR(parent))
++ goto out;
++ if (!parent)
++ parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]),
++ dir_ino, fh, fh_len);
++
++ out:
++ AuTraceErrPtr(parent);
++ return parent;
++}
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
++ int connectable)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ struct super_block *sb, *h_sb;
++ struct inode *inode;
++ struct dentry *parent, *h_parent;
++ struct au_branch *br;
++
++ AuDebugOn(au_test_anon(dentry));
++
++ parent = NULL;
++ err = -ENOSPC;
++ if (unlikely(*max_len <= Fh_tail)) {
++ AuWarn1("NFSv2 client (max_len %d)?\n", *max_len);
++ goto out;
++ }
++
++ err = FILEID_ROOT;
++ if (IS_ROOT(dentry)) {
++ AuDebugOn(dentry->d_inode->i_ino != AUFS_ROOT_INO);
++ goto out;
++ }
++
++ err = -EIO;
++ h_parent = NULL;
++ sb = dentry->d_sb;
++ aufs_read_lock(dentry, AuLock_FLUSH | AuLock_IR);
++ parent = dget_parent(dentry);
++ di_read_lock_parent(parent, !AuLock_IR);
++ inode = dentry->d_inode;
++ AuDebugOn(!inode);
++#ifdef CONFIG_AUFS_DEBUG
++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO)))
++ AuWarn1("NFS-exporting requires xino\n");
++#endif
++
++ bend = au_dbtaildir(parent);
++ for (bindex = au_dbstart(parent); bindex <= bend; bindex++) {
++ h_parent = au_h_dptr(parent, bindex);
++ if (h_parent) {
++ dget(h_parent);
++ break;
++ }
++ }
++ if (unlikely(!h_parent))
++ goto out_unlock;
++
++ err = -EPERM;
++ br = au_sbr(sb, bindex);
++ h_sb = br->br_mnt->mnt_sb;
++ if (unlikely(!h_sb->s_export_op)) {
++ AuErr1("%s branch is not exportable\n", au_sbtype(h_sb));
++ goto out_dput;
++ }
++
++ fh[Fh_br_id] = br->br_id;
++ fh[Fh_sigen] = au_sigen(sb);
++ encode_ino(fh + Fh_ino, inode->i_ino);
++ encode_ino(fh + Fh_dir_ino, parent->d_inode->i_ino);
++ fh[Fh_igen] = inode->i_generation;
++
++ *max_len -= Fh_tail;
++ fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail),
++ max_len,
++ /*connectable or subtreecheck*/0);
++ err = fh[Fh_h_type];
++ *max_len += Fh_tail;
++ /* todo: macros? */
++ if (err != 255)
++ err = 99;
++ else
++ AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb));
++
++ out_dput:
++ dput(h_parent);
++ out_unlock:
++ di_read_unlock(parent, !AuLock_IR);
++ dput(parent);
++ aufs_read_unlock(dentry, AuLock_IR);
++ out:
++ if (unlikely(err < 0))
++ err = 255;
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct export_operations aufs_export_op = {
++ .fh_to_dentry = aufs_fh_to_dentry,
++ /* .fh_to_parent = aufs_fh_to_parent, */
++ .encode_fh = aufs_encode_fh
++};
++
++void au_export_init(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++ __u32 u;
++
++ sb->s_export_op = &aufs_export_op;
++ sbinfo = au_sbi(sb);
++ sbinfo->si_xigen = NULL;
++ get_random_bytes(&u, sizeof(u));
++ BUILD_BUG_ON(sizeof(u) != sizeof(int));
++ atomic_set(&sbinfo->si_xigen_next, u);
++}
+diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c
+new file mode 100644
+index 0000000..fc196e4
+--- /dev/null
++++ b/fs/aufs/f_op.c
+@@ -0,0 +1,799 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * file and vm operations
++ */
++
++#include <linux/file.h>
++#include <linux/fs_stack.h>
++#include <linux/mm.h>
++#include <linux/security.h>
++#include "aufs.h"
++
++/* common function to regular file and dir */
++int aufs_flush(struct file *file, fl_owner_t id)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ struct dentry *dentry;
++ struct file *h_file;
++
++ dentry = file->f_dentry;
++ si_noflush_read_lock(dentry->d_sb);
++ fi_read_lock(file);
++ di_read_lock_child(dentry, AuLock_IW);
++
++ err = 0;
++ bend = au_fbend(file);
++ for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) {
++ h_file = au_h_fptr(file, bindex);
++ if (!h_file || !h_file->f_op || !h_file->f_op->flush)
++ continue;
++
++ err = h_file->f_op->flush(h_file, id);
++ if (!err)
++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL);
++ /*ignore*/
++ }
++ au_cpup_attr_timesizes(dentry->d_inode);
++
++ di_read_unlock(dentry, AuLock_IW);
++ fi_read_unlock(file);
++ si_read_unlock(dentry->d_sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int do_open_nondir(struct file *file, int flags)
++{
++ int err;
++ aufs_bindex_t bindex;
++ struct file *h_file;
++ struct dentry *dentry;
++ struct au_finfo *finfo;
++
++ FiMustWriteLock(file);
++
++ err = 0;
++ dentry = file->f_dentry;
++ finfo = au_fi(file);
++ finfo->fi_h_vm_ops = NULL;
++ finfo->fi_vm_ops = NULL;
++ bindex = au_dbstart(dentry);
++ /* O_TRUNC is processed already */
++ BUG_ON(au_test_ro(dentry->d_sb, bindex, dentry->d_inode)
++ && (flags & O_TRUNC));
++
++ h_file = au_h_open(dentry, bindex, flags, file);
++ if (IS_ERR(h_file))
++ err = PTR_ERR(h_file);
++ else {
++ au_set_fbstart(file, bindex);
++ au_set_fbend(file, bindex);
++ au_set_h_fptr(file, bindex, h_file);
++ au_update_figen(file);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ }
++ return err;
++}
++
++static int aufs_open_nondir(struct inode *inode __maybe_unused,
++ struct file *file)
++{
++ return au_do_open(file, do_open_nondir);
++}
++
++static int aufs_release_nondir(struct inode *inode __maybe_unused,
++ struct file *file)
++{
++ struct super_block *sb = file->f_dentry->d_sb;
++
++ si_noflush_read_lock(sb);
++ kfree(au_fi(file)->fi_vm_ops);
++ au_finfo_fin(file);
++ si_read_unlock(sb);
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static ssize_t aufs_read(struct file *file, char __user *buf, size_t count,
++ loff_t *ppos)
++{
++ ssize_t err;
++ struct dentry *dentry;
++ struct file *h_file;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
++ if (unlikely(err))
++ goto out;
++
++ h_file = au_h_fptr(file, au_fbstart(file));
++ err = vfsub_read_u(h_file, buf, count, ppos);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode);
++
++ di_read_unlock(dentry, AuLock_IR);
++ fi_read_unlock(file);
++ out:
++ si_read_unlock(sb);
++ return err;
++}
++
++static ssize_t aufs_write(struct file *file, const char __user *ubuf,
++ size_t count, loff_t *ppos)
++{
++ ssize_t err;
++ aufs_bindex_t bstart;
++ struct au_pin pin;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct super_block *sb;
++ struct file *h_file;
++ char __user *buf = (char __user *)ubuf;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ mutex_lock(&inode->i_mutex);
++ si_read_lock(sb, AuLock_FLUSH);
++
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++
++ bstart = au_fbstart(file);
++ h_file = au_h_fptr(file, bstart);
++ au_unpin(&pin);
++ err = vfsub_write_u(h_file, buf, count, ppos);
++ au_cpup_attr_timesizes(inode);
++ inode->i_mode = h_file->f_dentry->d_inode->i_mode;
++
++ out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++ out:
++ si_read_unlock(sb);
++ mutex_unlock(&inode->i_mutex);
++ return err;
++}
++
++static ssize_t aufs_aio_read(struct kiocb *kio, const struct iovec *iov,
++ unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ struct file *file, *h_file;
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ file = kio->ki_filp;
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
++ if (unlikely(err))
++ goto out;
++
++ err = -ENOSYS;
++ h_file = au_h_fptr(file, au_fbstart(file));
++ if (h_file->f_op && h_file->f_op->aio_read) {
++ err = security_file_permission(h_file, MAY_READ);
++ if (unlikely(err))
++ goto out_unlock;
++ if (!is_sync_kiocb(kio)) {
++ get_file(h_file);
++ fput(file);
++ }
++ kio->ki_filp = h_file;
++ err = h_file->f_op->aio_read(kio, iov, nv, pos);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ fsstack_copy_attr_atime(dentry->d_inode,
++ h_file->f_dentry->d_inode);
++ } else
++ /* currently there is no such fs */
++ WARN_ON_ONCE(h_file->f_op && h_file->f_op->read);
++
++ out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_read_unlock(file);
++ out:
++ si_read_unlock(sb);
++ return err;
++}
++
++static ssize_t aufs_aio_write(struct kiocb *kio, const struct iovec *iov,
++ unsigned long nv, loff_t pos)
++{
++ ssize_t err;
++ aufs_bindex_t bstart;
++ struct au_pin pin;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct super_block *sb;
++ struct file *file, *h_file;
++
++ file = kio->ki_filp;
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ mutex_lock(&inode->i_mutex);
++ si_read_lock(sb, AuLock_FLUSH);
++
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++
++ err = -ENOSYS;
++ bstart = au_fbstart(file);
++ h_file = au_h_fptr(file, bstart);
++ au_unpin(&pin);
++ if (h_file->f_op && h_file->f_op->aio_write) {
++ err = security_file_permission(h_file, MAY_WRITE);
++ if (unlikely(err))
++ goto out_unlock;
++ if (!is_sync_kiocb(kio)) {
++ get_file(h_file);
++ fput(file);
++ }
++ kio->ki_filp = h_file;
++ err = h_file->f_op->aio_write(kio, iov, nv, pos);
++ au_cpup_attr_timesizes(inode);
++ inode->i_mode = h_file->f_dentry->d_inode->i_mode;
++ } else
++ /* currently there is no such fs */
++ WARN_ON_ONCE(h_file->f_op && h_file->f_op->write);
++
++ out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++ out:
++ si_read_unlock(sb);
++ mutex_unlock(&inode->i_mutex);
++ return err;
++}
++
++static ssize_t aufs_splice_read(struct file *file, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
++{
++ ssize_t err;
++ struct file *h_file;
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
++ if (unlikely(err))
++ goto out;
++
++ err = -EINVAL;
++ h_file = au_h_fptr(file, au_fbstart(file));
++ if (au_test_loopback_kthread()) {
++ file->f_mapping = h_file->f_mapping;
++ smp_mb(); /* unnecessary? */
++ }
++ err = vfsub_splice_to(h_file, ppos, pipe, len, flags);
++ /* todo: necessasry? */
++ /* file->f_ra = h_file->f_ra; */
++ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode);
++
++ di_read_unlock(dentry, AuLock_IR);
++ fi_read_unlock(file);
++
++ out:
++ si_read_unlock(sb);
++ return err;
++}
++
++static ssize_t
++aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos,
++ size_t len, unsigned int flags)
++{
++ ssize_t err;
++ struct au_pin pin;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct super_block *sb;
++ struct file *h_file;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ mutex_lock(&inode->i_mutex);
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++
++ h_file = au_h_fptr(file, au_fbstart(file));
++ au_unpin(&pin);
++ err = vfsub_splice_from(pipe, h_file, ppos, len, flags);
++ au_cpup_attr_timesizes(inode);
++ inode->i_mode = h_file->f_dentry->d_inode->i_mode;
++
++ out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++ out:
++ si_read_unlock(sb);
++ mutex_unlock(&inode->i_mutex);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct file *au_safe_file(struct vm_area_struct *vma)
++{
++ struct file *file;
++
++ file = vma->vm_file;
++ if (file->private_data && au_test_aufs(file->f_dentry->d_sb))
++ return file;
++ return NULL;
++}
++
++static void au_reset_file(struct vm_area_struct *vma, struct file *file)
++{
++ vma->vm_file = file;
++ /* smp_mb(); */ /* flush vm_file */
++}
++
++static int aufs_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
++{
++ int err;
++ static DECLARE_WAIT_QUEUE_HEAD(wq);
++ struct file *file, *h_file;
++ struct au_finfo *finfo;
++
++ /* todo: non-robr mode, user vm_file as it is? */
++ wait_event(wq, (file = au_safe_file(vma)));
++
++ /* do not revalidate, no si lock */
++ finfo = au_fi(file);
++ h_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file;
++ AuDebugOn(!h_file || !finfo->fi_h_vm_ops);
++
++ fi_write_lock(file);
++ vma->vm_file = h_file;
++ err = finfo->fi_h_vm_ops->fault(vma, vmf);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++ au_reset_file(vma, file);
++ fi_write_unlock(file);
++#if 0 /* def CONFIG_SMP */
++ /* wake_up_nr(&wq, online_cpu - 1); */
++ wake_up_all(&wq);
++#else
++ wake_up(&wq);
++#endif
++
++ return err;
++}
++
++static int aufs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
++{
++ int err;
++ static DECLARE_WAIT_QUEUE_HEAD(wq);
++ struct file *file, *h_file;
++ struct au_finfo *finfo;
++
++ wait_event(wq, (file = au_safe_file(vma)));
++
++ finfo = au_fi(file);
++ h_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file;
++ AuDebugOn(!h_file || !finfo->fi_h_vm_ops);
++
++ fi_write_lock(file);
++ vma->vm_file = h_file;
++ err = finfo->fi_h_vm_ops->page_mkwrite(vma, page);
++ au_reset_file(vma, file);
++ fi_write_unlock(file);
++ wake_up(&wq);
++
++ return err;
++}
++
++static void aufs_vm_close(struct vm_area_struct *vma)
++{
++ static DECLARE_WAIT_QUEUE_HEAD(wq);
++ struct file *file, *h_file;
++ struct au_finfo *finfo;
++
++ wait_event(wq, (file = au_safe_file(vma)));
++
++ finfo = au_fi(file);
++ h_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file;
++ AuDebugOn(!h_file || !finfo->fi_h_vm_ops);
++
++ fi_write_lock(file);
++ vma->vm_file = h_file;
++ finfo->fi_h_vm_ops->close(vma);
++ au_reset_file(vma, file);
++ fi_write_unlock(file);
++ wake_up(&wq);
++}
++
++static struct vm_operations_struct aufs_vm_ops = {
++ /* .close and .page_mkwrite are not set by default */
++ .fault = aufs_fault,
++};
++
++/* ---------------------------------------------------------------------- */
++
++static struct vm_operations_struct *au_vm_ops(struct file *h_file,
++ struct vm_area_struct *vma)
++{
++ struct vm_operations_struct *vm_ops;
++ int err;
++
++ vm_ops = ERR_PTR(-ENODEV);
++ if (!h_file->f_op || !h_file->f_op->mmap)
++ goto out;
++
++ err = h_file->f_op->mmap(h_file, vma);
++ vm_ops = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ vm_ops = vma->vm_ops;
++ err = do_munmap(current->mm, vma->vm_start,
++ vma->vm_end - vma->vm_start);
++ if (unlikely(err)) {
++ AuIOErr("failed internal unmapping %.*s, %d\n",
++ AuDLNPair(h_file->f_dentry), err);
++ vm_ops = ERR_PTR(-EIO);
++ }
++
++ out:
++ return vm_ops;
++}
++
++static int au_custom_vm_ops(struct au_finfo *finfo, struct vm_area_struct *vma)
++{
++ int err;
++ struct vm_operations_struct *h_ops;
++
++ AuRwMustAnyLock(&finfo->fi_rwsem);
++
++ err = 0;
++ h_ops = finfo->fi_h_vm_ops;
++ AuDebugOn(!h_ops);
++ if ((!h_ops->page_mkwrite && !h_ops->close)
++ || finfo->fi_vm_ops)
++ goto out;
++
++ err = -ENOMEM;
++ finfo->fi_vm_ops = kmemdup(&aufs_vm_ops, sizeof(aufs_vm_ops), GFP_NOFS);
++ if (unlikely(!finfo->fi_vm_ops))
++ goto out;
++
++ err = 0;
++ if (h_ops->page_mkwrite)
++ finfo->fi_vm_ops->page_mkwrite = aufs_page_mkwrite;
++ if (h_ops->close)
++ finfo->fi_vm_ops->close = aufs_vm_close;
++
++ vma->vm_ops = finfo->fi_vm_ops;
++
++ out:
++ return err;
++}
++
++static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ int err;
++ unsigned char wlock, mmapped;
++ struct dentry *dentry;
++ struct super_block *sb;
++ struct file *h_file;
++ struct vm_operations_struct *vm_ops;
++
++ dentry = file->f_dentry;
++ wlock = !!(file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED);
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ mmapped = !!au_test_mmapped(file);
++ if (wlock) {
++ struct au_pin pin;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++ au_unpin(&pin);
++ } else
++ di_downgrade_lock(dentry, AuLock_IR);
++
++ h_file = au_h_fptr(file, au_fbstart(file));
++ if (!mmapped && au_test_fs_bad_mapping(h_file->f_dentry->d_sb)) {
++ /*
++ * by this assignment, f_mapping will differs from aufs inode
++ * i_mapping.
++ * if someone else mixes the use of f_dentry->d_inode and
++ * f_mapping->host, then a problem may arise.
++ */
++ file->f_mapping = h_file->f_mapping;
++ }
++
++ vm_ops = NULL;
++ if (!mmapped) {
++ vm_ops = au_vm_ops(h_file, vma);
++ err = PTR_ERR(vm_ops);
++ if (IS_ERR(vm_ops))
++ goto out_unlock;
++ }
++
++ /*
++ * unnecessary to handle MAP_DENYWRITE and deny_write_access()?
++ * currently MAP_DENYWRITE from userspace is ignored, but elf loader
++ * sets it. when FMODE_EXEC is set (by open_exec() or sys_uselib()),
++ * both of the aufs file and the lower file is deny_write_access()-ed.
++ * finally I hope we can skip handlling MAP_DENYWRITE here.
++ */
++ err = generic_file_mmap(file, vma);
++ if (unlikely(err))
++ goto out_unlock;
++
++ vma->vm_ops = &aufs_vm_ops;
++ /* test again */
++ if (!au_test_mmapped(file))
++ au_fi(file)->fi_h_vm_ops = vm_ops;
++
++ err = au_custom_vm_ops(au_fi(file), vma);
++ if (unlikely(err))
++ goto out_unlock;
++
++ vfsub_file_accessed(h_file);
++ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode);
++
++ out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++ out:
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_fsync_nondir(struct file *file, struct dentry *dentry,
++ int datasync)
++{
++ int err;
++ struct au_pin pin;
++ struct inode *inode;
++ struct file *h_file;
++ struct super_block *sb;
++
++ inode = dentry->d_inode;
++ IMustLock(file->f_mapping->host);
++ if (inode != file->f_mapping->host) {
++ mutex_unlock(&file->f_mapping->host->i_mutex);
++ mutex_lock(&inode->i_mutex);
++ }
++ IMustLock(inode);
++
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++
++ err = 0; /* -EBADF; */ /* posix? */
++ if (unlikely(!(file->f_mode & FMODE_WRITE)))
++ goto out;
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++ au_unpin(&pin);
++
++ err = -EINVAL;
++ h_file = au_h_fptr(file, au_fbstart(file));
++ if (h_file->f_op && h_file->f_op->fsync) {
++ struct dentry *h_d;
++ struct mutex *h_mtx;
++
++ /*
++ * no filemap_fdatawrite() since aufs file has no its own
++ * mapping, but dir.
++ */
++ h_d = h_file->f_dentry;
++ h_mtx = &h_d->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ err = h_file->f_op->fsync(h_file, h_d, datasync);
++ if (!err)
++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL);
++ /*ignore*/
++ au_cpup_attr_timesizes(inode);
++ mutex_unlock(h_mtx);
++ }
++
++ out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++ out:
++ si_read_unlock(sb);
++ if (inode != file->f_mapping->host) {
++ mutex_unlock(&inode->i_mutex);
++ mutex_lock(&file->f_mapping->host->i_mutex);
++ }
++ return err;
++}
++
++/* no one supports this operation, currently */
++#if 0
++static int aufs_aio_fsync_nondir(struct kiocb *kio, int datasync)
++{
++ int err;
++ struct au_pin pin;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct file *file, *h_file;
++ struct super_block *sb;
++
++ file = kio->ki_filp;
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ mutex_lock(&inode->i_mutex);
++
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++
++ err = 0; /* -EBADF; */ /* posix? */
++ if (unlikely(!(file->f_mode & FMODE_WRITE)))
++ goto out;
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
++ if (unlikely(err))
++ goto out;
++
++ err = au_ready_to_write(file, -1, &pin);
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ goto out_unlock;
++ au_unpin(&pin);
++
++ err = -ENOSYS;
++ h_file = au_h_fptr(file, au_fbstart(file));
++ if (h_file->f_op && h_file->f_op->aio_fsync) {
++ struct dentry *h_d;
++ struct mutex *h_mtx;
++
++ h_d = h_file->f_dentry;
++ h_mtx = &h_d->d_inode->i_mutex;
++ if (!is_sync_kiocb(kio)) {
++ get_file(h_file);
++ fput(file);
++ }
++ kio->ki_filp = h_file;
++ err = h_file->f_op->aio_fsync(kio, datasync);
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ if (!err)
++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL);
++ /*ignore*/
++ au_cpup_attr_timesizes(inode);
++ mutex_unlock(h_mtx);
++ }
++
++ out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ fi_write_unlock(file);
++ out:
++ si_read_unlock(sb);
++ mutex_unlock(&inode->i_mutex);
++ return err;
++}
++#endif
++
++static int aufs_fasync(int fd, struct file *file, int flag)
++{
++ int err;
++ struct file *h_file;
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0);
++ if (unlikely(err))
++ goto out;
++
++ h_file = au_h_fptr(file, au_fbstart(file));
++ if (h_file->f_op && h_file->f_op->fasync)
++ err = h_file->f_op->fasync(fd, h_file, flag);
++
++ di_read_unlock(dentry, AuLock_IR);
++ fi_read_unlock(file);
++
++ out:
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* no one supports this operation, currently */
++#if 0
++static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset,
++ size_t len, loff_t *pos , int more)
++{
++}
++#endif
++
++/* ---------------------------------------------------------------------- */
++
++struct file_operations aufs_file_fop = {
++ /*
++ * while generic_file_llseek/_unlocked() don't use BKL,
++ * don't use it since it operates file->f_mapping->host.
++ * in aufs, it may be a real file and may confuse users by UDBA.
++ */
++ /* .llseek = generic_file_llseek, */
++
++ .read = aufs_read,
++ .write = aufs_write,
++ .aio_read = aufs_aio_read,
++ .aio_write = aufs_aio_write,
++ .mmap = aufs_mmap,
++ .open = aufs_open_nondir,
++ .flush = aufs_flush,
++ .release = aufs_release_nondir,
++ .fsync = aufs_fsync_nondir,
++ /* .aio_fsync = aufs_aio_fsync_nondir, */
++ .fasync = aufs_fasync,
++ /* .sendpage = aufs_sendpage, */
++ .splice_write = aufs_splice_write,
++ .splice_read = aufs_splice_read,
++#if 0
++ .aio_splice_write = aufs_aio_splice_write,
++ .aio_splice_read = aufs_aio_splice_read
++#endif
++};
+diff --git a/fs/aufs/file.c b/fs/aufs/file.c
+new file mode 100644
+index 0000000..0cf5ef1
+--- /dev/null
++++ b/fs/aufs/file.c
+@@ -0,0 +1,577 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * handling file/dir, and address_space operation
++ */
++
++#include <linux/file.h>
++#include <linux/fsnotify.h>
++#include <linux/namei.h>
++#include <linux/pagemap.h>
++#include "aufs.h"
++
++/*
++ * a dirty trick for handling deny_write_access().
++ * because FMODE_EXEC flag is not passed to f_op->open(),
++ * set it to file->private_data temporary.
++ */
++void au_store_oflag(struct nameidata *nd, struct inode *inode)
++{
++ if (nd
++ /* && !(nd->flags & LOOKUP_CONTINUE) */
++ && (nd->flags & LOOKUP_OPEN)
++ && (nd->intent.open.flags & vfsub_fmode_to_uint(FMODE_EXEC))
++ && inode
++ && S_ISREG(inode->i_mode)) {
++ /* suppress a warning in lp64 */
++ unsigned long flags = nd->intent.open.flags;
++ nd->intent.open.file->private_data = (void *)flags;
++ /* smp_mb(); */
++ }
++}
++
++/* drop flags for writing */
++unsigned int au_file_roflags(unsigned int flags)
++{
++ flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC);
++ flags |= O_RDONLY | O_NOATIME;
++ return flags;
++}
++
++/* common functions to regular file and dir */
++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
++ struct file *file)
++{
++ struct file *h_file;
++ struct dentry *h_dentry;
++ struct inode *h_inode;
++ struct super_block *sb;
++ struct au_branch *br;
++ int err;
++
++ /* a race condition can happen between open and unlink/rmdir */
++ h_file = ERR_PTR(-ENOENT);
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (au_test_nfsd(current) && !h_dentry)
++ goto out;
++ h_inode = h_dentry->d_inode;
++ if (au_test_nfsd(current) && !h_inode)
++ goto out;
++ if (unlikely((!d_unhashed(dentry) && d_unhashed(h_dentry))
++ || !h_inode))
++ goto out;
++
++ sb = dentry->d_sb;
++ br = au_sbr(sb, bindex);
++ h_file = ERR_PTR(-EACCES);
++ if (file && (file->f_mode & FMODE_EXEC)
++ && (br->br_mnt->mnt_flags & MNT_NOEXEC))
++ goto out;
++
++ /* drop flags for writing */
++ if (au_test_ro(sb, bindex, dentry->d_inode))
++ flags = au_file_roflags(flags);
++ flags &= ~O_CREAT;
++ atomic_inc(&br->br_count);
++ h_file = dentry_open(dget(h_dentry), mntget(br->br_mnt), flags);
++ if (IS_ERR(h_file))
++ goto out_br;
++
++ if (file && (file->f_mode & FMODE_EXEC)) {
++ h_file->f_mode |= FMODE_EXEC;
++ err = deny_write_access(h_file);
++ if (unlikely(err)) {
++ fput(h_file);
++ h_file = ERR_PTR(err);
++ goto out_br;
++ }
++ }
++ fsnotify_open(h_dentry);
++ goto out; /* success */
++
++ out_br:
++ atomic_dec(&br->br_count);
++ out:
++ return h_file;
++}
++
++int au_do_open(struct file *file, int (*open)(struct file *file, int flags))
++{
++ int err;
++ struct dentry *dentry;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ err = au_finfo_init(file);
++ if (unlikely(err))
++ goto out;
++
++ di_read_lock_child(dentry, AuLock_IR);
++ err = open(file, file->f_flags);
++ di_read_unlock(dentry, AuLock_IR);
++
++ fi_write_unlock(file);
++ if (unlikely(err))
++ au_finfo_fin(file);
++ out:
++ si_read_unlock(sb);
++ return err;
++}
++
++int au_reopen_nondir(struct file *file)
++{
++ int err;
++ aufs_bindex_t bstart, bindex, bend;
++ struct dentry *dentry;
++ struct file *h_file, *h_file_tmp;
++
++ dentry = file->f_dentry;
++ bstart = au_dbstart(dentry);
++ h_file_tmp = NULL;
++ if (au_fbstart(file) == bstart) {
++ h_file = au_h_fptr(file, bstart);
++ if (file->f_mode == h_file->f_mode)
++ return 0; /* success */
++ h_file_tmp = h_file;
++ get_file(h_file_tmp);
++ au_set_h_fptr(file, bstart, NULL);
++ }
++ AuDebugOn(au_fbstart(file) < bstart
++ || au_fi(file)->fi_hfile[0 + bstart].hf_file);
++
++ h_file = au_h_open(dentry, bstart, file->f_flags & ~O_TRUNC, file);
++ err = PTR_ERR(h_file);
++ if (IS_ERR(h_file))
++ goto out; /* todo: close all? */
++
++ err = 0;
++ au_set_fbstart(file, bstart);
++ au_set_h_fptr(file, bstart, h_file);
++ au_update_figen(file);
++ /* todo: necessary? */
++ /* file->f_ra = h_file->f_ra; */
++
++ /* close lower files */
++ bend = au_fbend(file);
++ for (bindex = bstart + 1; bindex <= bend; bindex++)
++ au_set_h_fptr(file, bindex, NULL);
++ au_set_fbend(file, bstart);
++
++ out:
++ if (h_file_tmp)
++ fput(h_file_tmp);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_reopen_wh(struct file *file, aufs_bindex_t btgt,
++ struct dentry *hi_wh)
++{
++ int err;
++ aufs_bindex_t bstart;
++ struct au_dinfo *dinfo;
++ struct dentry *h_dentry;
++
++ dinfo = au_di(file->f_dentry);
++ AuRwMustWriteLock(&dinfo->di_rwsem);
++
++ bstart = dinfo->di_bstart;
++ dinfo->di_bstart = btgt;
++ h_dentry = dinfo->di_hdentry[0 + btgt].hd_dentry;
++ dinfo->di_hdentry[0 + btgt].hd_dentry = hi_wh;
++ err = au_reopen_nondir(file);
++ dinfo->di_hdentry[0 + btgt].hd_dentry = h_dentry;
++ dinfo->di_bstart = bstart;
++
++ return err;
++}
++
++static int au_ready_to_write_wh(struct file *file, loff_t len,
++ aufs_bindex_t bcpup)
++{
++ int err;
++ struct inode *inode;
++ struct dentry *dentry, *hi_wh;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++ hi_wh = au_hi_wh(inode, bcpup);
++ if (!hi_wh)
++ err = au_sio_cpup_wh(dentry, bcpup, len, file);
++ else
++ /* already copied-up after unlink */
++ err = au_reopen_wh(file, bcpup, hi_wh);
++
++ sb = dentry->d_sb;
++ if (!err && inode->i_nlink > 1 && au_opt_test(au_mntflags(sb), PLINK))
++ au_plink_append(inode, bcpup, au_h_dptr(dentry, bcpup));
++
++ return err;
++}
++
++/*
++ * prepare the @file for writing.
++ */
++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
++{
++ int err;
++ aufs_bindex_t bstart, bcpup;
++ struct dentry *dentry, *parent, *h_dentry;
++ struct inode *h_inode, *inode;
++ struct super_block *sb;
++
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ bstart = au_fbstart(file);
++ inode = dentry->d_inode;
++ err = au_test_ro(sb, bstart, inode);
++ if (!err && (au_h_fptr(file, bstart)->f_mode & FMODE_WRITE)) {
++ err = au_pin(pin, dentry, bstart, AuOpt_UDBA_NONE, /*flags*/0);
++ goto out;
++ }
++
++ /* need to cpup */
++ parent = dget_parent(dentry);
++ di_write_lock_parent(parent);
++ err = AuWbrCopyup(au_sbi(sb), dentry);
++ bcpup = err;
++ if (unlikely(err < 0))
++ goto out_dgrade;
++ err = 0;
++
++ if (!au_h_dptr(parent, bcpup)) {
++ err = au_cpup_dirs(dentry, bcpup);
++ if (unlikely(err))
++ goto out_dgrade;
++ }
++
++ err = au_pin(pin, dentry, bcpup, AuOpt_UDBA_NONE,
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ if (unlikely(err))
++ goto out_dgrade;
++
++ h_dentry = au_h_fptr(file, bstart)->f_dentry;
++ h_inode = h_dentry->d_inode;
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ if (d_unhashed(dentry) /* || d_unhashed(h_dentry) */
++ /* || !h_inode->i_nlink */) {
++ err = au_ready_to_write_wh(file, len, bcpup);
++ di_downgrade_lock(parent, AuLock_IR);
++ } else {
++ di_downgrade_lock(parent, AuLock_IR);
++ if (!au_h_dptr(dentry, bcpup))
++ err = au_sio_cpup_simple(dentry, bcpup, len,
++ AuCpup_DTIME);
++ if (!err)
++ err = au_reopen_nondir(file);
++ }
++ mutex_unlock(&h_inode->i_mutex);
++
++ if (!err) {
++ au_pin_set_parent_lflag(pin, /*lflag*/0);
++ goto out_dput; /* success */
++ }
++ au_unpin(pin);
++ goto out_unlock;
++
++ out_dgrade:
++ di_downgrade_lock(parent, AuLock_IR);
++ out_unlock:
++ di_read_unlock(parent, AuLock_IR);
++ out_dput:
++ dput(parent);
++ out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_file_refresh_by_inode(struct file *file, int *need_reopen)
++{
++ int err;
++ aufs_bindex_t bstart;
++ struct au_pin pin;
++ struct au_finfo *finfo;
++ struct dentry *dentry, *parent, *hi_wh;
++ struct inode *inode;
++ struct super_block *sb;
++
++ FiMustWriteLock(file);
++
++ err = 0;
++ finfo = au_fi(file);
++ dentry = file->f_dentry;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ bstart = au_ibstart(inode);
++ if (bstart == finfo->fi_bstart)
++ goto out;
++
++ parent = dget_parent(dentry);
++ if (au_test_ro(sb, bstart, inode)) {
++ di_read_lock_parent(parent, !AuLock_IR);
++ err = AuWbrCopyup(au_sbi(sb), dentry);
++ bstart = err;
++ di_read_unlock(parent, !AuLock_IR);
++ if (unlikely(err < 0))
++ goto out_parent;
++ err = 0;
++ }
++
++ di_read_lock_parent(parent, AuLock_IR);
++ hi_wh = au_hi_wh(inode, bstart);
++ if (au_opt_test(au_mntflags(sb), PLINK)
++ && au_plink_test(inode)
++ && !d_unhashed(dentry)) {
++ err = au_test_and_cpup_dirs(dentry, bstart);
++ if (unlikely(err))
++ goto out_unlock;
++
++ /* always superio. */
++ err = au_pin(&pin, dentry, bstart, AuOpt_UDBA_NONE,
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ if (!err)
++ err = au_sio_cpup_simple(dentry, bstart, -1,
++ AuCpup_DTIME);
++ au_unpin(&pin);
++ } else if (hi_wh) {
++ /* already copied-up after unlink */
++ err = au_reopen_wh(file, bstart, hi_wh);
++ *need_reopen = 0;
++ }
++
++ out_unlock:
++ di_read_unlock(parent, AuLock_IR);
++ out_parent:
++ dput(parent);
++ out:
++ return err;
++}
++
++static void au_do_refresh_file(struct file *file)
++{
++ aufs_bindex_t bindex, bend, new_bindex, brid;
++ struct au_hfile *p, tmp, *q;
++ struct au_finfo *finfo;
++ struct super_block *sb;
++
++ FiMustWriteLock(file);
++
++ sb = file->f_dentry->d_sb;
++ finfo = au_fi(file);
++ p = finfo->fi_hfile + finfo->fi_bstart;
++ brid = p->hf_br->br_id;
++ bend = finfo->fi_bend;
++ for (bindex = finfo->fi_bstart; bindex <= bend; bindex++, p++) {
++ if (!p->hf_file)
++ continue;
++
++ new_bindex = au_br_index(sb, p->hf_br->br_id);
++ if (new_bindex == bindex)
++ continue;
++ if (new_bindex < 0) {
++ au_set_h_fptr(file, bindex, NULL);
++ continue;
++ }
++
++ /* swap two lower inode, and loop again */
++ q = finfo->fi_hfile + new_bindex;
++ tmp = *q;
++ *q = *p;
++ *p = tmp;
++ if (tmp.hf_file) {
++ bindex--;
++ p--;
++ }
++ }
++
++ p = finfo->fi_hfile;
++ if (!au_test_mmapped(file) && !d_unhashed(file->f_dentry)) {
++ bend = au_sbend(sb);
++ for (finfo->fi_bstart = 0; finfo->fi_bstart <= bend;
++ finfo->fi_bstart++, p++)
++ if (p->hf_file) {
++ if (p->hf_file->f_dentry
++ && p->hf_file->f_dentry->d_inode)
++ break;
++ else
++ au_hfput(p, file);
++ }
++ } else {
++ bend = au_br_index(sb, brid);
++ for (finfo->fi_bstart = 0; finfo->fi_bstart < bend;
++ finfo->fi_bstart++, p++)
++ if (p->hf_file)
++ au_hfput(p, file);
++ bend = au_sbend(sb);
++ }
++
++ p = finfo->fi_hfile + bend;
++ for (finfo->fi_bend = bend; finfo->fi_bend >= finfo->fi_bstart;
++ finfo->fi_bend--, p--)
++ if (p->hf_file) {
++ if (p->hf_file->f_dentry
++ && p->hf_file->f_dentry->d_inode)
++ break;
++ else
++ au_hfput(p, file);
++ }
++ AuDebugOn(finfo->fi_bend < finfo->fi_bstart);
++}
++
++/*
++ * after branch manipulating, refresh the file.
++ */
++static int refresh_file(struct file *file, int (*reopen)(struct file *file))
++{
++ int err, need_reopen;
++ struct dentry *dentry;
++ aufs_bindex_t bend, bindex;
++
++ dentry = file->f_dentry;
++ err = au_fi_realloc(au_fi(file), au_sbend(dentry->d_sb) + 1);
++ if (unlikely(err))
++ goto out;
++ au_do_refresh_file(file);
++
++ err = 0;
++ need_reopen = 1;
++ if (!au_test_mmapped(file))
++ err = au_file_refresh_by_inode(file, &need_reopen);
++ if (!err && need_reopen && !d_unhashed(dentry))
++ err = reopen(file);
++ if (!err) {
++ au_update_figen(file);
++ return 0; /* success */
++ }
++
++ /* error, close all lower files */
++ bend = au_fbend(file);
++ for (bindex = au_fbstart(file); bindex <= bend; bindex++)
++ au_set_h_fptr(file, bindex, NULL);
++
++ out:
++ return err;
++}
++
++/* common function to regular file and dir */
++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
++ int wlock)
++{
++ int err;
++ unsigned int sigen, figen;
++ aufs_bindex_t bstart;
++ unsigned char pseudo_link;
++ struct dentry *dentry;
++
++ err = 0;
++ dentry = file->f_dentry;
++ sigen = au_sigen(dentry->d_sb);
++ fi_write_lock(file);
++ figen = au_figen(file);
++ di_write_lock_child(dentry);
++ bstart = au_dbstart(dentry);
++ pseudo_link = (bstart != au_ibstart(dentry->d_inode));
++ if (sigen == figen && !pseudo_link && au_fbstart(file) == bstart) {
++ if (!wlock) {
++ di_downgrade_lock(dentry, AuLock_IR);
++ fi_downgrade_lock(file);
++ }
++ goto out; /* success */
++ }
++
++ AuDbg("sigen %d, figen %d\n", sigen, figen);
++ if (sigen != au_digen(dentry)
++ || sigen != au_iigen(dentry->d_inode)) {
++ err = au_reval_dpath(dentry, sigen);
++ if (unlikely(err < 0))
++ goto out;
++ AuDebugOn(au_digen(dentry) != sigen
++ || au_iigen(dentry->d_inode) != sigen);
++ }
++
++ err = refresh_file(file, reopen);
++ if (!err) {
++ if (!wlock) {
++ di_downgrade_lock(dentry, AuLock_IR);
++ fi_downgrade_lock(file);
++ }
++ } else {
++ di_write_unlock(dentry);
++ fi_write_unlock(file);
++ }
++
++ out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* cf. aufs_nopage() */
++/* for madvise(2) */
++static int aufs_readpage(struct file *file __maybe_unused, struct page *page)
++{
++ unlock_page(page);
++ return 0;
++}
++
++/* they will never be called. */
++#ifdef CONFIG_AUFS_DEBUG
++static int aufs_write_begin(struct file *file, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned flags,
++ struct page **pagep, void **fsdata)
++{ AuUnsupport(); return 0; }
++static int aufs_write_end(struct file *file, struct address_space *mapping,
++ loff_t pos, unsigned len, unsigned copied,
++ struct page *page, void *fsdata)
++{ AuUnsupport(); return 0; }
++static int aufs_writepage(struct page *page, struct writeback_control *wbc)
++{ AuUnsupport(); return 0; }
++static void aufs_sync_page(struct page *page)
++{ AuUnsupport(); }
++
++static int aufs_set_page_dirty(struct page *page)
++{ AuUnsupport(); return 0; }
++static void aufs_invalidatepage(struct page *page, unsigned long offset)
++{ AuUnsupport(); }
++static int aufs_releasepage(struct page *page, gfp_t gfp)
++{ AuUnsupport(); return 0; }
++static ssize_t aufs_direct_IO(int rw, struct kiocb *iocb,
++ const struct iovec *iov, loff_t offset,
++ unsigned long nr_segs)
++{ AuUnsupport(); return 0; }
++#endif /* CONFIG_AUFS_DEBUG */
++
++struct address_space_operations aufs_aop = {
++ .readpage = aufs_readpage,
++#ifdef CONFIG_AUFS_DEBUG
++ .writepage = aufs_writepage,
++ .sync_page = aufs_sync_page,
++ .set_page_dirty = aufs_set_page_dirty,
++ .write_begin = aufs_write_begin,
++ .write_end = aufs_write_end,
++ .invalidatepage = aufs_invalidatepage,
++ .releasepage = aufs_releasepage,
++ .direct_IO = aufs_direct_IO,
++#endif /* CONFIG_AUFS_DEBUG */
++};
+diff --git a/fs/aufs/file.h b/fs/aufs/file.h
+new file mode 100644
+index 0000000..7697af7
+--- /dev/null
++++ b/fs/aufs/file.h
+@@ -0,0 +1,169 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * file operations
++ */
++
++#ifndef __AUFS_FILE_H__
++#define __AUFS_FILE_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/aufs_type.h>
++#include "rwsem.h"
++
++struct au_branch;
++struct au_hfile {
++ struct file *hf_file;
++ struct au_branch *hf_br;
++};
++
++struct au_vdir;
++struct au_finfo {
++ atomic_t fi_generation;
++
++ struct au_rwsem fi_rwsem;
++ struct au_hfile *fi_hfile;
++ aufs_bindex_t fi_bstart, fi_bend;
++
++ union {
++ /* non-dir only */
++ struct {
++ struct vm_operations_struct *fi_h_vm_ops;
++ struct vm_operations_struct *fi_vm_ops;
++ };
++
++ /* dir only */
++ struct {
++ struct au_vdir *fi_vdir_cache;
++ int fi_maintain_plink;
++ };
++ };
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* file.c */
++extern struct address_space_operations aufs_aop;
++void au_store_oflag(struct nameidata *nd, struct inode *inode);
++unsigned int au_file_roflags(unsigned int flags);
++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
++ struct file *file);
++int au_do_open(struct file *file, int (*open)(struct file *file, int flags));
++int au_reopen_nondir(struct file *file);
++struct au_pin;
++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin);
++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
++ int wlock);
++
++/* f_op.c */
++extern struct file_operations aufs_file_fop;
++int aufs_flush(struct file *file, fl_owner_t id);
++
++/* finfo.c */
++void au_hfput(struct au_hfile *hf, struct file *file);
++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex,
++ struct file *h_file);
++
++void au_update_figen(struct file *file);
++
++void au_finfo_fin(struct file *file);
++int au_finfo_init(struct file *file);
++int au_fi_realloc(struct au_finfo *finfo, int nbr);
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct au_finfo *au_fi(struct file *file)
++{
++ return file->private_data;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * fi_read_lock, fi_write_lock,
++ * fi_read_unlock, fi_write_unlock, fi_downgrade_lock
++ */
++AuSimpleRwsemFuncs(fi, struct file *f, &au_fi(f)->fi_rwsem);
++
++#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem)
++#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem)
++#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem)
++
++/* ---------------------------------------------------------------------- */
++
++/* todo: hard/soft set? */
++static inline aufs_bindex_t au_fbstart(struct file *file)
++{
++ FiMustAnyLock(file);
++ return au_fi(file)->fi_bstart;
++}
++
++static inline aufs_bindex_t au_fbend(struct file *file)
++{
++ FiMustAnyLock(file);
++ return au_fi(file)->fi_bend;
++}
++
++static inline struct au_vdir *au_fvdir_cache(struct file *file)
++{
++ FiMustAnyLock(file);
++ return au_fi(file)->fi_vdir_cache;
++}
++
++static inline void au_set_fbstart(struct file *file, aufs_bindex_t bindex)
++{
++ FiMustWriteLock(file);
++ au_fi(file)->fi_bstart = bindex;
++}
++
++static inline void au_set_fbend(struct file *file, aufs_bindex_t bindex)
++{
++ FiMustWriteLock(file);
++ au_fi(file)->fi_bend = bindex;
++}
++
++static inline void au_set_fvdir_cache(struct file *file,
++ struct au_vdir *vdir_cache)
++{
++ FiMustWriteLock(file);
++ au_fi(file)->fi_vdir_cache = vdir_cache;
++}
++
++static inline struct file *au_h_fptr(struct file *file, aufs_bindex_t bindex)
++{
++ FiMustAnyLock(file);
++ return au_fi(file)->fi_hfile[0 + bindex].hf_file;
++}
++
++/* todo: memory barrier? */
++static inline unsigned int au_figen(struct file *f)
++{
++ return atomic_read(&au_fi(f)->fi_generation);
++}
++
++static inline int au_test_mmapped(struct file *f)
++{
++ /* FiMustAnyLock(f); */
++ return !!(au_fi(f)->fi_h_vm_ops);
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_FILE_H__ */
+diff --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c
+new file mode 100644
+index 0000000..16e5c67
+--- /dev/null
++++ b/fs/aufs/finfo.c
+@@ -0,0 +1,133 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * file private data
++ */
++
++#include <linux/file.h>
++#include "aufs.h"
++
++void au_hfput(struct au_hfile *hf, struct file *file)
++{
++ if (file->f_mode & FMODE_EXEC)
++ allow_write_access(hf->hf_file);
++ fput(hf->hf_file);
++ hf->hf_file = NULL;
++ atomic_dec_return(&hf->hf_br->br_count);
++ hf->hf_br = NULL;
++}
++
++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val)
++{
++ struct au_finfo *finfo = au_fi(file);
++ struct au_hfile *hf;
++
++ hf = finfo->fi_hfile + bindex;
++ if (hf->hf_file)
++ au_hfput(hf, file);
++ if (val) {
++ hf->hf_file = val;
++ hf->hf_br = au_sbr(file->f_dentry->d_sb, bindex);
++ }
++}
++
++void au_update_figen(struct file *file)
++{
++ atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_dentry));
++ /* smp_mb(); */ /* atomic_set */
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_finfo_fin(struct file *file)
++{
++ struct au_finfo *finfo;
++ aufs_bindex_t bindex, bend;
++
++ fi_write_lock(file);
++ bend = au_fbend(file);
++ bindex = au_fbstart(file);
++ if (bindex >= 0)
++ /*
++ * calls fput() instead of filp_close(),
++ * since no dnotify or lock for the lower file.
++ */
++ for (; bindex <= bend; bindex++)
++ au_set_h_fptr(file, bindex, NULL);
++
++ finfo = au_fi(file);
++ au_dbg_verify_hf(finfo);
++ kfree(finfo->fi_hfile);
++ fi_write_unlock(file);
++ AuRwDestroy(&finfo->fi_rwsem);
++ au_cache_free_finfo(finfo);
++}
++
++int au_finfo_init(struct file *file)
++{
++ struct au_finfo *finfo;
++ struct dentry *dentry;
++ unsigned long ul;
++
++ dentry = file->f_dentry;
++ finfo = au_cache_alloc_finfo();
++ if (unlikely(!finfo))
++ goto out;
++
++ finfo->fi_hfile = kcalloc(au_sbend(dentry->d_sb) + 1,
++ sizeof(*finfo->fi_hfile), GFP_NOFS);
++ if (unlikely(!finfo->fi_hfile))
++ goto out_finfo;
++
++ au_rw_init_wlock(&finfo->fi_rwsem);
++ finfo->fi_bstart = -1;
++ finfo->fi_bend = -1;
++ atomic_set(&finfo->fi_generation, au_digen(dentry));
++ /* smp_mb(); */ /* atomic_set */
++
++ /* cf. au_store_oflag() */
++ /* suppress a warning in lp64 */
++ ul = (unsigned long)file->private_data;
++ file->f_mode |= (vfsub_uint_to_fmode(ul) & FMODE_EXEC);
++ file->private_data = finfo;
++ return 0; /* success */
++
++ out_finfo:
++ au_cache_free_finfo(finfo);
++ out:
++ return -ENOMEM;
++}
++
++int au_fi_realloc(struct au_finfo *finfo, int nbr)
++{
++ int err, sz;
++ struct au_hfile *hfp;
++
++ err = -ENOMEM;
++ sz = sizeof(*hfp) * (finfo->fi_bend + 1);
++ if (!sz)
++ sz = sizeof(*hfp);
++ hfp = au_kzrealloc(finfo->fi_hfile, sz, sizeof(*hfp) * nbr, GFP_NOFS);
++ if (hfp) {
++ finfo->fi_hfile = hfp;
++ err = 0;
++ }
++
++ return err;
++}
+diff --git a/fs/aufs/fstype.h b/fs/aufs/fstype.h
+new file mode 100644
+index 0000000..d8a6456
+--- /dev/null
++++ b/fs/aufs/fstype.h
+@@ -0,0 +1,444 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * judging filesystem type
++ */
++
++#ifndef __AUFS_FSTYPE_H__
++#define __AUFS_FSTYPE_H__
++
++#ifdef __KERNEL__
++
++#include <linux/cramfs_fs.h>
++#include <linux/fs.h>
++#include <linux/magic.h>
++#include <linux/romfs_fs.h>
++#include <linux/aufs_type.h>
++
++static inline int au_test_aufs(struct super_block *sb)
++{
++ return sb->s_magic == AUFS_SUPER_MAGIC;
++}
++
++static inline const char *au_sbtype(struct super_block *sb)
++{
++ return sb->s_type->name;
++}
++
++static inline int au_test_iso9660(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_ROMFS_FS) || defined(CONFIG_ROMFS_FS_MODULE)
++ return sb->s_magic == ROMFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_romfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_ISO9660_FS) || defined(CONFIG_ISO9660_FS_MODULE)
++ return sb->s_magic == ISOFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_cramfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_CRAMFS) || defined(CONFIG_CRAMFS_MODULE)
++ return sb->s_magic == CRAMFS_MAGIC;
++#endif
++ return 0;
++}
++
++static inline int au_test_nfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE)
++ return sb->s_magic == NFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_fuse(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_FUSE_FS) || defined(CONFIG_FUSE_FS_MODULE)
++ return sb->s_magic == FUSE_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_xfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_XFS_FS) || defined(CONFIG_XFS_FS_MODULE)
++ return sb->s_magic == XFS_SB_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_tmpfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_TMPFS
++ return sb->s_magic == TMPFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_ECRYPT_FS) || defined(CONFIG_ECRYPT_FS_MODULE)
++ return !strcmp(au_sbtype(sb), "ecryptfs");
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_smbfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_SMB_FS) || defined(CONFIG_SMB_FS_MODULE)
++ return sb->s_magic == SMB_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ocfs2(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_OCFS2_FS) || defined(CONFIG_OCFS2_FS_MODULE)
++ return sb->s_magic == OCFS2_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ocfs2_dlmfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_OCFS2_FS_O2CB) || defined(CONFIG_OCFS2_FS_O2CB_MODULE)
++ return sb->s_magic == DLMFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_coda(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_CODA_FS) || defined(CONFIG_CODA_FS_MODULE)
++ return sb->s_magic == CODA_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_v9fs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_9P_FS) || defined(CONFIG_9P_FS_MODULE)
++ return sb->s_magic == V9FS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ext4(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_EXT4DEV_FS) || defined(CONFIG_EXT4DEV_FS_MODULE)
++ return sb->s_magic == EXT4_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_sysv(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_SYSV_FS) || defined(CONFIG_SYSV_FS_MODULE)
++ return !strcmp(au_sbtype(sb), "sysv");
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_ramfs(struct super_block *sb)
++{
++ return sb->s_magic == RAMFS_MAGIC;
++}
++
++static inline int au_test_ubifs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_UBIFS_FS) || defined(CONFIG_UBIFS_FS_MODULE)
++ return sb->s_magic == UBIFS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_procfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_PROC_FS
++ return sb->s_magic == PROC_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_sysfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_SYSFS
++ return sb->s_magic == SYSFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_configfs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_CONFIGFS_FS) || defined(CONFIG_CONFIGFS_FS_MODULE)
++ return sb->s_magic == CONFIGFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_minix(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_MINIX_FS) || defined(CONFIG_MINIX_FS_MODULE)
++ return sb->s_magic == MINIX3_SUPER_MAGIC
++ || sb->s_magic == MINIX2_SUPER_MAGIC
++ || sb->s_magic == MINIX2_SUPER_MAGIC2
++ || sb->s_magic == MINIX_SUPER_MAGIC
++ || sb->s_magic == MINIX_SUPER_MAGIC2;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_cifs(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_CIFS_FS) || defined(CONFIGCIFS_FS_MODULE)
++ return sb->s_magic == CIFS_MAGIC_NUMBER;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_fat(struct super_block *sb __maybe_unused)
++{
++#if defined(CONFIG_FAT_FS) || defined(CONFIG_FAT_FS_MODULE)
++ return sb->s_magic == MSDOS_SUPER_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_msdos(struct super_block *sb)
++{
++ return au_test_fat(sb);
++}
++
++static inline int au_test_vfat(struct super_block *sb)
++{
++ return au_test_fat(sb);
++}
++
++static inline int au_test_securityfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_SECURITYFS
++ return sb->s_magic == SECURITYFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++static inline int au_test_debugfs(struct super_block *sb __maybe_unused)
++{
++#ifdef CONFIG_DEBUG_FS
++ return sb->s_magic == DEBUGFS_MAGIC;
++#else
++ return 0;
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
++/*
++ * they can't be an aufs branch.
++ */
++static inline int au_test_fs_unsuppoted(struct super_block *sb)
++{
++ return
++#ifndef CONFIG_AUFS_BR_RAMFS
++ au_test_ramfs(sb) ||
++#endif
++ au_test_procfs(sb)
++ || au_test_sysfs(sb)
++ || au_test_configfs(sb)
++ || au_test_debugfs(sb)
++ || au_test_securityfs(sb)
++ /* || !strcmp(au_sbtype(sb), "unionfs") */
++ || au_test_aufs(sb); /* will be supported in next version */
++}
++
++/*
++ * If the filesystem supports NFS-export, then it has to support NULL as
++ * a nameidata parameter for ->create(), ->lookup() and ->d_revalidate().
++ * We can apply this principle when we handle a lower filesystem.
++ */
++static inline int au_test_fs_null_nd(struct super_block *sb)
++{
++ return !!sb->s_export_op;
++}
++
++static inline int au_test_fs_remote(struct super_block *sb)
++{
++ return !au_test_tmpfs(sb)
++#ifdef CONFIG_AUFS_BR_RAMFS
++ && !au_test_ramfs(sb)
++#endif
++ && !(sb->s_type->fs_flags & FS_REQUIRES_DEV);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * Note: these functions (below) are created after reading ->getattr() in all
++ * filesystems under linux/fs. it means we have to do so in every update...
++ */
++
++/*
++ * some filesystems require getattr to refresh the inode attributes before
++ * referencing.
++ * in most cases, we can rely on the inode attribute in NFS (or every remote fs)
++ * and leave the work for d_revalidate()
++ */
++static inline int au_test_fs_refresh_iattr(struct super_block *sb)
++{
++ return au_test_nfs(sb)
++ || au_test_fuse(sb)
++ /* || au_test_smbfs(sb) */ /* untested */
++ /* || au_test_ocfs2(sb) */ /* untested */
++ /* || au_test_coda(sb) */ /* untested */
++ /* || au_test_v9fs(sb) */ /* untested */
++ ;
++}
++
++/*
++ * filesystems which don't maintain i_size or i_blocks.
++ */
++static inline int au_test_fs_bad_iattr_size(struct super_block *sb)
++{
++ return au_test_xfs(sb)
++ /* || au_test_ext4(sb) */ /* untested */
++ /* || au_test_ocfs2(sb) */ /* untested */
++ /* || au_test_ocfs2_dlmfs(sb) */ /* untested */
++ /* || au_test_sysv(sb) */ /* untested */
++ /* || au_test_ubifs(sb) */ /* untested */
++ /* || au_test_minix(sb) */ /* untested */
++ ;
++}
++
++/*
++ * filesystems which don't store the correct value in some of their inode
++ * attributes.
++ */
++static inline int au_test_fs_bad_iattr(struct super_block *sb)
++{
++ return au_test_fs_bad_iattr_size(sb)
++ /* || au_test_cifs(sb) */ /* untested */
++ || au_test_fat(sb)
++ || au_test_msdos(sb)
++ || au_test_vfat(sb);
++}
++
++/* they don't check i_nlink in link(2) */
++static inline int au_test_fs_no_limit_nlink(struct super_block *sb)
++{
++ return au_test_tmpfs(sb)
++#ifdef CONFIG_AUFS_BR_RAMFS
++ || au_test_ramfs(sb)
++#endif
++ || au_test_ubifs(sb);
++}
++
++/*
++ * filesystems which sets S_NOATIME and S_NOCMTIME.
++ */
++static inline int au_test_fs_notime(struct super_block *sb)
++{
++ return au_test_nfs(sb)
++ || au_test_fuse(sb)
++ || au_test_ubifs(sb)
++ /* || au_test_cifs(sb) */ /* untested */
++ ;
++}
++
++/*
++ * filesystems which requires replacing i_mapping.
++ */
++static inline int au_test_fs_bad_mapping(struct super_block *sb)
++{
++ return au_test_fuse(sb)
++ || au_test_ubifs(sb);
++}
++
++/* temporary support for i#1 in cramfs */
++static inline int au_test_fs_unique_ino(struct inode *inode)
++{
++ if (au_test_cramfs(inode->i_sb))
++ return inode->i_ino != 1;
++ return 1;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * the filesystem where the xino files placed must support i/o after unlink and
++ * maintain i_size and i_blocks.
++ */
++static inline int au_test_fs_bad_xino(struct super_block *sb)
++{
++ return au_test_fs_remote(sb)
++ || au_test_fs_bad_iattr_size(sb)
++#ifdef CONFIG_AUFS_BR_RAMFS
++ || !(au_test_ramfs(sb) || au_test_fs_null_nd(sb))
++#else
++ || !au_test_fs_null_nd(sb) /* to keep xino code simple */
++#endif
++ /* don't want unnecessary work for xino */
++ || au_test_aufs(sb)
++ || au_test_ecryptfs(sb);
++}
++
++static inline int au_test_fs_trunc_xino(struct super_block *sb)
++{
++ return au_test_tmpfs(sb)
++ || au_test_ramfs(sb);
++}
++
++/*
++ * test if the @sb is real-readonly.
++ */
++static inline int au_test_fs_rr(struct super_block *sb)
++{
++ return au_test_iso9660(sb)
++ || au_test_cramfs(sb)
++ || au_test_romfs(sb);
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_FSTYPE_H__ */
+diff --git a/fs/aufs/hinotify.c b/fs/aufs/hinotify.c
+new file mode 100644
+index 0000000..66b761f
+--- /dev/null
++++ b/fs/aufs/hinotify.c
+@@ -0,0 +1,755 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * inotify for the lower directories
++ */
++
++#include "aufs.h"
++
++static const __u32 AuHinMask = (IN_MOVE | IN_DELETE | IN_CREATE);
++static struct inotify_handle *au_hin_handle;
++
++AuCacheFuncs(hinotify, HINOTIFY);
++
++int au_hin_alloc(struct au_hinode *hinode, struct inode *inode,
++ struct inode *h_inode)
++{
++ int err;
++ struct au_hinotify *hin;
++ s32 wd;
++
++ err = -ENOMEM;
++ hin = au_cache_alloc_hinotify();
++ if (hin) {
++ AuDebugOn(hinode->hi_notify);
++ hinode->hi_notify = hin;
++ hin->hin_aufs_inode = inode;
++
++ inotify_init_watch(&hin->hin_watch);
++ wd = inotify_add_watch(au_hin_handle, &hin->hin_watch, h_inode,
++ AuHinMask);
++ if (wd >= 0)
++ return 0; /* success */
++
++ err = wd;
++ put_inotify_watch(&hin->hin_watch);
++ au_cache_free_hinotify(hin);
++ hinode->hi_notify = NULL;
++ }
++
++ return err;
++}
++
++void au_hin_free(struct au_hinode *hinode)
++{
++ int err;
++ struct au_hinotify *hin;
++
++ hin = hinode->hi_notify;
++ if (hin) {
++ err = 0;
++ if (atomic_read(&hin->hin_watch.count))
++ err = inotify_rm_watch(au_hin_handle, &hin->hin_watch);
++ if (unlikely(err))
++ /* it means the watch is already removed */
++ AuWarn("failed inotify_rm_watch() %d\n", err);
++ au_cache_free_hinotify(hin);
++ hinode->hi_notify = NULL;
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_hin_ctl(struct au_hinode *hinode, int do_set)
++{
++ struct inode *h_inode;
++ struct inotify_watch *watch;
++
++ if (!hinode->hi_notify)
++ return;
++
++ h_inode = hinode->hi_inode;
++ IMustLock(h_inode);
++
++ /* todo: try inotify_find_update_watch()? */
++ watch = &hinode->hi_notify->hin_watch;
++ mutex_lock(&h_inode->inotify_mutex);
++ /* mutex_lock(&watch->ih->mutex); */
++ if (do_set) {
++ AuDebugOn(watch->mask & AuHinMask);
++ watch->mask |= AuHinMask;
++ } else {
++ AuDebugOn(!(watch->mask & AuHinMask));
++ watch->mask &= ~AuHinMask;
++ }
++ /* mutex_unlock(&watch->ih->mutex); */
++ mutex_unlock(&h_inode->inotify_mutex);
++}
++
++void au_reset_hinotify(struct inode *inode, unsigned int flags)
++{
++ aufs_bindex_t bindex, bend;
++ struct inode *hi;
++ struct dentry *iwhdentry;
++
++ bend = au_ibend(inode);
++ for (bindex = au_ibstart(inode); bindex <= bend; bindex++) {
++ hi = au_h_iptr(inode, bindex);
++ if (!hi)
++ continue;
++
++ /* mutex_lock_nested(&hi->i_mutex, AuLsc_I_CHILD); */
++ iwhdentry = au_hi_wh(inode, bindex);
++ if (iwhdentry)
++ dget(iwhdentry);
++ au_igrab(hi);
++ au_set_h_iptr(inode, bindex, NULL, 0);
++ au_set_h_iptr(inode, bindex, au_igrab(hi),
++ flags & ~AuHi_XINO);
++ iput(hi);
++ dput(iwhdentry);
++ /* mutex_unlock(&hi->i_mutex); */
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int hin_xino(struct inode *inode, struct inode *h_inode)
++{
++ int err;
++ aufs_bindex_t bindex, bend, bfound, bstart;
++ struct inode *h_i;
++
++ err = 0;
++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
++ AuWarn("branch root dir was changed\n");
++ goto out;
++ }
++
++ bfound = -1;
++ bend = au_ibend(inode);
++ bstart = au_ibstart(inode);
++#if 0 /* reserved for future use */
++ if (bindex == bend) {
++ /* keep this ino in rename case */
++ goto out;
++ }
++#endif
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ if (au_h_iptr(inode, bindex) == h_inode) {
++ bfound = bindex;
++ break;
++ }
++ }
++ if (bfound < 0)
++ goto out;
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ h_i = au_h_iptr(inode, bindex);
++ if (!h_i)
++ continue;
++
++ err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0);
++ /* ignore this error */
++ /* bad action? */
++ }
++
++ /* children inode number will be broken */
++
++ out:
++ AuTraceErr(err);
++ return err;
++}
++
++static int hin_gen_tree(struct dentry *dentry)
++{
++ int err, i, j, ndentry;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry **dentries;
++
++ err = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_dcsub_pages(&dpages, dentry, NULL, NULL);
++ if (unlikely(err))
++ goto out_dpages;
++
++ for (i = 0; i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ dentries = dpage->dentries;
++ ndentry = dpage->ndentry;
++ for (j = 0; j < ndentry; j++) {
++ struct dentry *d;
++
++ d = dentries[j];
++ if (IS_ROOT(d))
++ continue;
++
++ d_drop(d);
++ au_digen_dec(d);
++ if (d->d_inode)
++ /* todo: reset children xino?
++ cached children only? */
++ au_iigen_dec(d->d_inode);
++ }
++ }
++
++ out_dpages:
++ au_dpages_free(&dpages);
++
++ /* discard children */
++ dentry_unhash(dentry);
++ dput(dentry);
++ out:
++ return err;
++}
++
++/*
++ * return 0 if processed.
++ */
++static int hin_gen_by_inode(char *name, unsigned int nlen, struct inode *inode,
++ const unsigned int isdir)
++{
++ int err;
++ struct dentry *d;
++ struct qstr *dname;
++
++ err = 1;
++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
++ AuWarn("branch root dir was changed\n");
++ err = 0;
++ goto out;
++ }
++
++ if (!isdir) {
++ AuDebugOn(!name);
++ au_iigen_dec(inode);
++ spin_lock(&dcache_lock);
++ list_for_each_entry(d, &inode->i_dentry, d_alias) {
++ dname = &d->d_name;
++ if (dname->len != nlen
++ && memcmp(dname->name, name, nlen))
++ continue;
++ err = 0;
++ spin_lock(&d->d_lock);
++ __d_drop(d);
++ au_digen_dec(d);
++ spin_unlock(&d->d_lock);
++ break;
++ }
++ spin_unlock(&dcache_lock);
++ } else {
++ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIRS);
++ d = d_find_alias(inode);
++ if (!d) {
++ au_iigen_dec(inode);
++ goto out;
++ }
++
++ dname = &d->d_name;
++ if (dname->len == nlen && !memcmp(dname->name, name, nlen))
++ err = hin_gen_tree(d);
++ dput(d);
++ }
++
++ out:
++ AuTraceErr(err);
++ return err;
++}
++
++static int hin_gen_by_name(struct dentry *dentry, const unsigned int isdir)
++{
++ int err;
++ struct inode *inode;
++
++ inode = dentry->d_inode;
++ if (IS_ROOT(dentry)
++ /* || (inode && inode->i_ino == AUFS_ROOT_INO) */
++ ) {
++ AuWarn("branch root dir was changed\n");
++ return 0;
++ }
++
++ err = 0;
++ if (!isdir) {
++ d_drop(dentry);
++ au_digen_dec(dentry);
++ if (inode)
++ au_iigen_dec(inode);
++ } else {
++ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS);
++ if (inode)
++ err = hin_gen_tree(dentry);
++ }
++
++ AuTraceErr(err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* hinotify job flags */
++#define AuHinJob_XINO0 1
++#define AuHinJob_GEN (1 << 1)
++#define AuHinJob_DIRENT (1 << 2)
++#define AuHinJob_ISDIR (1 << 3)
++#define AuHinJob_TRYXINO0 (1 << 4)
++#define AuHinJob_MNTPNT (1 << 5)
++#define au_ftest_hinjob(flags, name) ((flags) & AuHinJob_##name)
++#define au_fset_hinjob(flags, name) { (flags) |= AuHinJob_##name; }
++#define au_fclr_hinjob(flags, name) { (flags) &= ~AuHinJob_##name; }
++
++struct hin_job_args {
++ unsigned int flags;
++ struct inode *inode, *h_inode, *dir, *h_dir;
++ struct dentry *dentry;
++ char *h_name;
++ int h_nlen;
++};
++
++static int hin_job(struct hin_job_args *a)
++{
++ const unsigned int isdir = au_ftest_hinjob(a->flags, ISDIR);
++
++ /* reset xino */
++ if (au_ftest_hinjob(a->flags, XINO0) && a->inode)
++ hin_xino(a->inode, a->h_inode); /* ignore this error */
++
++ if (au_ftest_hinjob(a->flags, TRYXINO0)
++ && a->inode
++ && a->h_inode) {
++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
++ if (!a->h_inode->i_nlink)
++ hin_xino(a->inode, a->h_inode); /* ignore this error */
++ mutex_unlock(&a->h_inode->i_mutex);
++ }
++
++ /* make the generation obsolete */
++ if (au_ftest_hinjob(a->flags, GEN)) {
++ int err = -1;
++ if (a->inode)
++ err = hin_gen_by_inode(a->h_name, a->h_nlen, a->inode,
++ isdir);
++ if (err && a->dentry)
++ hin_gen_by_name(a->dentry, isdir);
++ /* ignore this error */
++ }
++
++ /* make dir entries obsolete */
++ if (au_ftest_hinjob(a->flags, DIRENT) && a->inode) {
++ struct au_vdir *vdir;
++
++ vdir = au_ivdir(a->inode);
++ if (vdir)
++ vdir->vd_jiffy = 0;
++ /* IMustLock(a->inode); */
++ /* a->inode->i_version++; */
++ }
++
++ /* can do nothing but warn */
++ if (au_ftest_hinjob(a->flags, MNTPNT)
++ && a->dentry
++ && d_mountpoint(a->dentry))
++ AuWarn("mount-point %.*s is removed or renamed\n",
++ AuDLNPair(a->dentry));
++
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static char *in_name(u32 mask)
++{
++#ifdef CONFIG_AUFS_DEBUG
++#define test_ret(flag) if (mask & flag) \
++ return #flag;
++ test_ret(IN_ACCESS);
++ test_ret(IN_MODIFY);
++ test_ret(IN_ATTRIB);
++ test_ret(IN_CLOSE_WRITE);
++ test_ret(IN_CLOSE_NOWRITE);
++ test_ret(IN_OPEN);
++ test_ret(IN_MOVED_FROM);
++ test_ret(IN_MOVED_TO);
++ test_ret(IN_CREATE);
++ test_ret(IN_DELETE);
++ test_ret(IN_DELETE_SELF);
++ test_ret(IN_MOVE_SELF);
++ test_ret(IN_UNMOUNT);
++ test_ret(IN_Q_OVERFLOW);
++ test_ret(IN_IGNORED);
++ return "";
++#undef test_ret
++#else
++ return "??";
++#endif
++}
++
++static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen,
++ struct inode *dir)
++{
++ struct dentry *dentry, *d, *parent;
++ struct qstr *dname;
++
++ parent = d_find_alias(dir);
++ if (!parent)
++ return NULL;
++
++ dentry = NULL;
++ spin_lock(&dcache_lock);
++ list_for_each_entry(d, &parent->d_subdirs, d_u.d_child) {
++ /* AuDbg("%.*s\n", AuDLNPair(d)); */
++ dname = &d->d_name;
++ if (dname->len != nlen || memcmp(dname->name, name, nlen))
++ continue;
++ if (!atomic_read(&d->d_count) || !d->d_fsdata) {
++ spin_lock(&d->d_lock);
++ __d_drop(d);
++ spin_unlock(&d->d_lock);
++ continue;
++ }
++
++ dentry = dget(d);
++ break;
++ }
++ spin_unlock(&dcache_lock);
++ dput(parent);
++
++ if (dentry)
++ di_write_lock_child(dentry);
++
++ return dentry;
++}
++
++static struct inode *lookup_wlock_by_ino(struct super_block *sb,
++ aufs_bindex_t bindex, ino_t h_ino)
++{
++ struct inode *inode;
++ ino_t ino;
++ int err;
++
++ inode = NULL;
++ err = au_xino_read(sb, bindex, h_ino, &ino);
++ if (!err && ino)
++ inode = ilookup(sb, ino);
++ if (!inode)
++ goto out;
++
++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
++ AuWarn("wrong root branch\n");
++ iput(inode);
++ inode = NULL;
++ goto out;
++ }
++
++ ii_write_lock_child(inode);
++
++ out:
++ return inode;
++}
++
++enum { CHILD, PARENT };
++struct postproc_args {
++ struct inode *h_dir, *dir, *h_child_inode;
++ u32 mask;
++ unsigned int flags[2];
++ unsigned int h_child_nlen;
++ char h_child_name[];
++};
++
++static void postproc(void *_args)
++{
++ struct postproc_args *a = _args;
++ struct super_block *sb;
++ aufs_bindex_t bindex, bend, bfound;
++ unsigned char xino, try_iput;
++ int err;
++ struct inode *inode;
++ ino_t h_ino;
++ struct hin_job_args args;
++ struct dentry *dentry;
++ struct au_sbinfo *sbinfo;
++
++ AuDebugOn(!_args);
++ AuDebugOn(!a->h_dir);
++ AuDebugOn(!a->dir);
++ AuDebugOn(!a->mask);
++ AuDbg("mask 0x%x %s, i%lu, hi%lu, hci%lu\n",
++ a->mask, in_name(a->mask), a->dir->i_ino, a->h_dir->i_ino,
++ a->h_child_inode ? a->h_child_inode->i_ino : 0);
++
++ inode = NULL;
++ dentry = NULL;
++ /*
++ * do not lock a->dir->i_mutex here
++ * because of d_revalidate() may cause a deadlock.
++ */
++ sb = a->dir->i_sb;
++ AuDebugOn(!sb);
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!sbinfo);
++ /* big aufs lock */
++ si_noflush_write_lock(sb);
++
++ ii_read_lock_parent(a->dir);
++ bfound = -1;
++ bend = au_ibend(a->dir);
++ for (bindex = au_ibstart(a->dir); bindex <= bend; bindex++)
++ if (au_h_iptr(a->dir, bindex) == a->h_dir) {
++ bfound = bindex;
++ break;
++ }
++ ii_read_unlock(a->dir);
++ if (unlikely(bfound < 0))
++ goto out;
++
++ xino = !!au_opt_test(au_mntflags(sb), XINO);
++ h_ino = 0;
++ if (a->h_child_inode)
++ h_ino = a->h_child_inode->i_ino;
++
++ if (a->h_child_nlen
++ && (au_ftest_hinjob(a->flags[CHILD], GEN)
++ || au_ftest_hinjob(a->flags[CHILD], MNTPNT)))
++ dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen,
++ a->dir);
++ try_iput = 0;
++ if (dentry)
++ inode = dentry->d_inode;
++ if (xino && !inode && h_ino
++ && (au_ftest_hinjob(a->flags[CHILD], XINO0)
++ || au_ftest_hinjob(a->flags[CHILD], TRYXINO0)
++ || au_ftest_hinjob(a->flags[CHILD], GEN))) {
++ inode = lookup_wlock_by_ino(sb, bfound, h_ino);
++ try_iput = 1;
++ }
++
++ args.flags = a->flags[CHILD];
++ args.dentry = dentry;
++ args.inode = inode;
++ args.h_inode = a->h_child_inode;
++ args.dir = a->dir;
++ args.h_dir = a->h_dir;
++ args.h_name = a->h_child_name;
++ args.h_nlen = a->h_child_nlen;
++ err = hin_job(&args);
++ if (dentry) {
++ if (dentry->d_fsdata)
++ di_write_unlock(dentry);
++ dput(dentry);
++ }
++ if (inode && try_iput) {
++ ii_write_unlock(inode);
++ iput(inode);
++ }
++
++ ii_write_lock_parent(a->dir);
++ args.flags = a->flags[PARENT];
++ args.dentry = NULL;
++ args.inode = a->dir;
++ args.h_inode = a->h_dir;
++ args.dir = NULL;
++ args.h_dir = NULL;
++ args.h_name = NULL;
++ args.h_nlen = 0;
++ err = hin_job(&args);
++ ii_write_unlock(a->dir);
++
++ out:
++ au_nwt_done(&sbinfo->si_nowait);
++ si_write_unlock(sb);
++
++ iput(a->h_child_inode);
++ iput(a->h_dir);
++ iput(a->dir);
++ kfree(a);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void aufs_inotify(struct inotify_watch *watch, u32 wd __maybe_unused,
++ u32 mask, u32 cookie __maybe_unused,
++ const char *h_child_name, struct inode *h_child_inode)
++{
++ struct au_hinotify *hinotify;
++ struct postproc_args *args;
++ int len, wkq_err;
++ unsigned char isdir, isroot, wh;
++ char *p;
++ struct inode *dir;
++ unsigned int flags[2];
++
++ /* if IN_UNMOUNT happens, there must be another bug */
++ AuDebugOn(mask & IN_UNMOUNT);
++ if (mask & (IN_IGNORED | IN_UNMOUNT)) {
++ put_inotify_watch(watch);
++ return;
++ }
++#ifdef AuDbgHinotify
++ au_debug(1);
++ if (1 || !h_child_name || strcmp(h_child_name, AUFS_XINO_FNAME)) {
++ AuDbg("i%lu, wd %d, mask 0x%x %s, cookie 0x%x, hcname %s,"
++ " hi%lu\n",
++ watch->inode->i_ino, wd, mask, in_name(mask), cookie,
++ h_child_name ? h_child_name : "",
++ h_child_inode ? h_child_inode->i_ino : 0);
++ WARN_ON(1);
++ }
++ au_debug(0);
++#endif
++
++ hinotify = container_of(watch, struct au_hinotify, hin_watch);
++ AuDebugOn(!hinotify || !hinotify->hin_aufs_inode);
++ dir = igrab(hinotify->hin_aufs_inode);
++ if (!dir)
++ return;
++
++ isroot = (dir->i_ino == AUFS_ROOT_INO);
++ len = 0;
++ wh = 0;
++ if (h_child_name) {
++ len = strlen(h_child_name);
++ if (!memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
++ h_child_name += AUFS_WH_PFX_LEN;
++ len -= AUFS_WH_PFX_LEN;
++ wh = 1;
++ }
++ }
++
++ isdir = 0;
++ if (h_child_inode)
++ isdir = !!S_ISDIR(h_child_inode->i_mode);
++ flags[PARENT] = AuHinJob_ISDIR;
++ flags[CHILD] = 0;
++ if (isdir)
++ flags[CHILD] = AuHinJob_ISDIR;
++ switch (mask & IN_ALL_EVENTS) {
++ case IN_MOVED_FROM:
++ case IN_MOVED_TO:
++ AuDebugOn(!h_child_name || !h_child_inode);
++ au_fset_hinjob(flags[CHILD], GEN);
++ au_fset_hinjob(flags[CHILD], XINO0);
++ au_fset_hinjob(flags[CHILD], MNTPNT);
++ au_fset_hinjob(flags[PARENT], DIRENT);
++ break;
++
++ case IN_CREATE:
++ AuDebugOn(!h_child_name || !h_child_inode);
++ au_fset_hinjob(flags[PARENT], DIRENT);
++ au_fset_hinjob(flags[CHILD], GEN);
++ break;
++
++ case IN_DELETE:
++ /*
++ * aufs never be able to get this child inode.
++ * revalidation should be in d_revalidate()
++ * by checking i_nlink, i_generation or d_unhashed().
++ */
++ AuDebugOn(!h_child_name);
++ au_fset_hinjob(flags[PARENT], DIRENT);
++ au_fset_hinjob(flags[CHILD], GEN);
++ au_fset_hinjob(flags[CHILD], TRYXINO0);
++ au_fset_hinjob(flags[CHILD], MNTPNT);
++ break;
++
++ default:
++ AuDebugOn(1);
++ }
++
++ if (wh)
++ h_child_inode = NULL;
++
++ /* iput() and kfree() will be called in postproc() */
++ /*
++ * inotify_mutex is already acquired and kmalloc/prune_icache may lock
++ * iprune_mutex. strange.
++ */
++ lockdep_off();
++ args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS);
++ lockdep_on();
++ if (unlikely(!args)) {
++ AuErr1("no memory\n");
++ iput(dir);
++ return;
++ }
++ args->flags[PARENT] = flags[PARENT];
++ args->flags[CHILD] = flags[CHILD];
++ args->mask = mask;
++ args->dir = dir;
++ args->h_dir = igrab(watch->inode);
++ if (h_child_inode)
++ h_child_inode = igrab(h_child_inode); /* can be NULL */
++ args->h_child_inode = h_child_inode;
++ args->h_child_nlen = len;
++ if (len) {
++ p = (void *)args;
++ p += sizeof(*args);
++ memcpy(p, h_child_name, len + 1);
++ }
++
++ lockdep_off();
++ wkq_err = au_wkq_nowait(postproc, args, dir->i_sb);
++ lockdep_on();
++ if (unlikely(wkq_err))
++ AuErr("wkq %d\n", wkq_err);
++}
++
++static void aufs_inotify_destroy(struct inotify_watch *watch __maybe_unused)
++{
++ return;
++}
++
++static struct inotify_operations aufs_inotify_ops = {
++ .handle_event = aufs_inotify,
++ .destroy_watch = aufs_inotify_destroy
++};
++
++/* ---------------------------------------------------------------------- */
++
++static void au_hin_destroy_cache(void)
++{
++ kmem_cache_destroy(au_cachep[AuCache_HINOTIFY]);
++ au_cachep[AuCache_HINOTIFY] = NULL;
++}
++
++int __init au_hinotify_init(void)
++{
++ int err;
++
++ err = -ENOMEM;
++ au_cachep[AuCache_HINOTIFY] = AuCache(au_hinotify);
++ if (au_cachep[AuCache_HINOTIFY]) {
++ err = 0;
++ au_hin_handle = inotify_init(&aufs_inotify_ops);
++ if (IS_ERR(au_hin_handle)) {
++ err = PTR_ERR(au_hin_handle);
++ au_hin_destroy_cache();
++ }
++ }
++ AuTraceErr(err);
++ return err;
++}
++
++void au_hinotify_fin(void)
++{
++ inotify_destroy(au_hin_handle);
++ if (au_cachep[AuCache_HINOTIFY])
++ au_hin_destroy_cache();
++}
+diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c
+new file mode 100644
+index 0000000..23ad23d
+--- /dev/null
++++ b/fs/aufs/i_op.c
+@@ -0,0 +1,885 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * inode operations (except add/del/rename)
++ */
++
++#include <linux/device_cgroup.h>
++#include <linux/fs_stack.h>
++#include <linux/mm.h>
++#include <linux/namei.h>
++#include <linux/security.h>
++#include <linux/uaccess.h>
++#include "aufs.h"
++
++static int h_permission(struct inode *h_inode, int mask,
++ struct vfsmount *h_mnt, int brperm)
++{
++ int err;
++ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND));
++
++ err = -EACCES;
++ if ((write_mask && IS_IMMUTABLE(h_inode))
++ || ((mask & MAY_EXEC)
++ && S_ISREG(h_inode->i_mode)
++ && ((h_mnt->mnt_flags & MNT_NOEXEC)
++ || !(h_inode->i_mode & S_IXUGO))))
++ goto out;
++
++ /*
++ * - skip the lower fs test in the case of write to ro branch.
++ * - nfs dir permission write check is optimized, but a policy for
++ * link/rename requires a real check.
++ */
++ if ((write_mask && !au_br_writable(brperm))
++ || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode)
++ && write_mask && !(mask & MAY_READ))
++ || !h_inode->i_op
++ || !h_inode->i_op->permission) {
++ /* AuLabel(generic_permission); */
++ err = generic_permission(h_inode, mask, NULL);
++ } else {
++ /* AuLabel(h_inode->permission); */
++ err = h_inode->i_op->permission(h_inode, mask);
++ AuTraceErr(err);
++ }
++
++ if (!err)
++ err = devcgroup_inode_permission(h_inode, mask);
++ if (!err)
++ err = security_inode_permission
++ (h_inode, mask & (MAY_READ | MAY_WRITE | MAY_EXEC
++ | MAY_APPEND));
++
++ out:
++ return err;
++}
++
++static int aufs_permission(struct inode *inode, int mask)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ const unsigned char isdir = !!S_ISDIR(inode->i_mode);
++ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND));
++ struct inode *h_inode;
++ struct super_block *sb;
++ struct au_branch *br;
++
++ sb = inode->i_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ ii_read_lock_child(inode);
++
++ if (!isdir || write_mask) {
++ err = au_busy_or_stale();
++ h_inode = au_h_iptr(inode, au_ibstart(inode));
++ if (unlikely(!h_inode
++ || (h_inode->i_mode & S_IFMT)
++ != (inode->i_mode & S_IFMT)))
++ goto out;
++
++ err = 0;
++ bindex = au_ibstart(inode);
++ br = au_sbr(sb, bindex);
++ err = h_permission(h_inode, mask, br->br_mnt, br->br_perm);
++ if (write_mask && !err) {
++ /* test whether the upper writable branch exists */
++ err = -EROFS;
++ for (; bindex >= 0; bindex--)
++ if (!au_br_rdonly(au_sbr(sb, bindex))) {
++ err = 0;
++ break;
++ }
++ }
++ goto out;
++ }
++
++ /* non-write to dir */
++ err = 0;
++ bend = au_ibend(inode);
++ for (bindex = au_ibstart(inode); !err && bindex <= bend; bindex++) {
++ h_inode = au_h_iptr(inode, bindex);
++ if (h_inode) {
++ err = au_busy_or_stale();
++ if (unlikely(!S_ISDIR(h_inode->i_mode)))
++ break;
++
++ br = au_sbr(sb, bindex);
++ err = h_permission(h_inode, mask, br->br_mnt,
++ br->br_perm);
++ }
++ }
++
++ out:
++ ii_read_unlock(inode);
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry,
++ struct nameidata *nd)
++{
++ struct dentry *ret, *parent;
++ struct inode *inode, *h_inode;
++ struct mutex *mtx;
++ struct super_block *sb;
++ int err, npositive;
++ aufs_bindex_t bstart;
++
++ /* temporary workaround for a bug in NFSD readdir */
++ if (!au_test_nfsd(current))
++ IMustLock(dir);
++ else
++ WARN_ONCE(!mutex_is_locked(&dir->i_mutex),
++ "a known problem of NFSD readdir in 2.6.28\n");
++
++ sb = dir->i_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ err = au_alloc_dinfo(dentry);
++ ret = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ parent = dentry->d_parent; /* dir inode is locked */
++ di_read_lock_parent(parent, AuLock_IR);
++ npositive = au_lkup_dentry(dentry, au_dbstart(parent), /*type*/0, nd);
++ di_read_unlock(parent, AuLock_IR);
++ err = npositive;
++ ret = ERR_PTR(err);
++ if (unlikely(err < 0))
++ goto out_unlock;
++
++ inode = NULL;
++ if (npositive) {
++ bstart = au_dbstart(dentry);
++ h_inode = au_h_dptr(dentry, bstart)->d_inode;
++ if (!S_ISDIR(h_inode->i_mode)) {
++ /*
++ * stop 'race'-ing between hardlinks under different
++ * parents.
++ */
++ mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx;
++ mutex_lock(mtx);
++ inode = au_new_inode(dentry, /*must_new*/0);
++ mutex_unlock(mtx);
++ } else
++ inode = au_new_inode(dentry, /*must_new*/0);
++ ret = (void *)inode;
++ }
++ if (IS_ERR(inode))
++ goto out_unlock;
++
++ ret = d_splice_alias(inode, dentry);
++ if (unlikely(IS_ERR(ret) && inode))
++ ii_write_unlock(inode);
++ au_store_oflag(nd, inode);
++
++ out_unlock:
++ di_write_unlock(dentry);
++ out:
++ si_read_unlock(sb);
++ return ret;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent,
++ const unsigned char add_entry, aufs_bindex_t bcpup,
++ aufs_bindex_t bstart)
++{
++ int err;
++ struct dentry *h_parent;
++ struct inode *h_dir;
++
++ if (add_entry) {
++ au_update_dbstart(dentry);
++ IMustLock(parent->d_inode);
++ } else
++ di_write_lock_parent(parent);
++
++ err = 0;
++ if (!au_h_dptr(parent, bcpup)) {
++ if (bstart < bcpup)
++ err = au_cpdown_dirs(dentry, bcpup);
++ else
++ err = au_cpup_dirs(dentry, bcpup);
++ }
++ if (!err && add_entry) {
++ h_parent = au_h_dptr(parent, bcpup);
++ h_dir = h_parent->d_inode;
++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
++ err = au_lkup_neg(dentry, bcpup);
++ /* todo: no unlock here */
++ mutex_unlock(&h_dir->i_mutex);
++ if (bstart < bcpup && au_dbstart(dentry) < 0) {
++ au_set_dbstart(dentry, 0);
++ au_update_dbrange(dentry, /*do_put_zero*/0);
++ }
++ }
++
++ if (!add_entry)
++ di_write_unlock(parent);
++ if (!err)
++ err = bcpup; /* success */
++
++ return err;
++}
++
++/*
++ * decide the branch and the parent dir where we will create a new entry.
++ * returns new bindex or an error.
++ * copyup the parent dir if needed.
++ */
++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry,
++ struct au_wr_dir_args *args)
++{
++ int err;
++ aufs_bindex_t bcpup, bstart, src_bstart;
++ const unsigned char add_entry = !!au_ftest_wrdir(args->flags,
++ ADD_ENTRY);
++ struct super_block *sb;
++ struct dentry *parent;
++ struct au_sbinfo *sbinfo;
++
++ sb = dentry->d_sb;
++ sbinfo = au_sbi(sb);
++ parent = dget_parent(dentry);
++ bstart = au_dbstart(dentry);
++ bcpup = bstart;
++ if (args->force_btgt < 0) {
++ if (src_dentry) {
++ src_bstart = au_dbstart(src_dentry);
++ if (src_bstart < bstart)
++ bcpup = src_bstart;
++ } else if (add_entry) {
++ err = AuWbrCreate(sbinfo, dentry,
++ au_ftest_wrdir(args->flags, ISDIR));
++ bcpup = err;
++ }
++
++ if (bcpup < 0 || au_test_ro(sb, bcpup, dentry->d_inode)) {
++ if (add_entry)
++ err = AuWbrCopyup(sbinfo, dentry);
++ else {
++ if (!IS_ROOT(dentry)) {
++ di_read_lock_parent(parent, !AuLock_IR);
++ err = AuWbrCopyup(sbinfo, dentry);
++ di_read_unlock(parent, !AuLock_IR);
++ } else
++ err = AuWbrCopyup(sbinfo, dentry);
++ }
++ bcpup = err;
++ if (unlikely(err < 0))
++ goto out;
++ }
++ } else {
++ bcpup = args->force_btgt;
++ AuDebugOn(au_test_ro(sb, bcpup, dentry->d_inode));
++ }
++ AuDbg("bstart %d, bcpup %d\n", bstart, bcpup);
++ if (bstart < bcpup)
++ au_update_dbrange(dentry, /*do_put_zero*/1);
++
++ err = bcpup;
++ if (bcpup == bstart)
++ goto out; /* success */
++
++ /* copyup the new parent into the branch we process */
++ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart);
++
++ out:
++ dput(parent);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct dentry *au_pinned_h_parent(struct au_pin *pin)
++{
++ if (pin && pin->parent)
++ return au_h_dptr(pin->parent, pin->bindex);
++ return NULL;
++}
++
++void au_unpin(struct au_pin *p)
++{
++ if (au_ftest_pin(p->flags, MNT_WRITE))
++ mnt_drop_write(p->h_mnt);
++ if (!p->hdir)
++ return;
++
++ au_hin_imtx_unlock(p->hdir);
++ if (!au_ftest_pin(p->flags, DI_LOCKED))
++ di_read_unlock(p->parent, AuLock_IR);
++ iput(p->hdir->hi_inode);
++ dput(p->parent);
++ p->parent = NULL;
++ p->hdir = NULL;
++ p->h_mnt = NULL;
++}
++
++int au_do_pin(struct au_pin *p)
++{
++ int err;
++ struct super_block *sb;
++ struct dentry *h_dentry, *h_parent;
++ struct au_branch *br;
++ struct inode *h_dir;
++
++ err = 0;
++ sb = p->dentry->d_sb;
++ br = au_sbr(sb, p->bindex);
++ if (IS_ROOT(p->dentry)) {
++ if (au_ftest_pin(p->flags, MNT_WRITE)) {
++ p->h_mnt = br->br_mnt;
++ err = mnt_want_write(p->h_mnt);
++ if (unlikely(err)) {
++ au_fclr_pin(p->flags, MNT_WRITE);
++ goto out_err;
++ }
++ }
++ goto out;
++ }
++
++ h_dentry = NULL;
++ if (p->bindex <= au_dbend(p->dentry))
++ h_dentry = au_h_dptr(p->dentry, p->bindex);
++
++ p->parent = dget_parent(p->dentry);
++ if (!au_ftest_pin(p->flags, DI_LOCKED))
++ di_read_lock(p->parent, AuLock_IR, p->lsc_di);
++
++ h_dir = NULL;
++ h_parent = au_h_dptr(p->parent, p->bindex);
++ p->hdir = au_hi(p->parent->d_inode, p->bindex);
++ if (p->hdir)
++ h_dir = p->hdir->hi_inode;
++
++ /* udba case */
++ if (unlikely(!p->hdir || !h_dir)) {
++ if (!au_ftest_pin(p->flags, DI_LOCKED))
++ di_read_unlock(p->parent, AuLock_IR);
++ dput(p->parent);
++ p->parent = NULL;
++ goto out_err;
++ }
++
++ au_igrab(h_dir);
++ au_hin_imtx_lock_nested(p->hdir, p->lsc_hi);
++
++ if (unlikely(p->hdir->hi_inode != h_parent->d_inode)) {
++ err = -EBUSY;
++ goto out_unpin;
++ }
++ if (h_dentry) {
++ err = au_h_verify(h_dentry, p->udba, h_dir, h_parent, br);
++ if (unlikely(err)) {
++ au_fclr_pin(p->flags, MNT_WRITE);
++ goto out_unpin;
++ }
++ }
++
++ if (au_ftest_pin(p->flags, MNT_WRITE)) {
++ p->h_mnt = br->br_mnt;
++ err = mnt_want_write(p->h_mnt);
++ if (unlikely(err)) {
++ au_fclr_pin(p->flags, MNT_WRITE);
++ goto out_unpin;
++ }
++ }
++ goto out; /* success */
++
++ out_unpin:
++ au_unpin(p);
++ out_err:
++ AuErr("err %d\n", err);
++ err = au_busy_or_stale();
++ out:
++ return err;
++}
++
++void au_pin_init(struct au_pin *p, struct dentry *dentry,
++ aufs_bindex_t bindex, int lsc_di, int lsc_hi,
++ unsigned int udba, unsigned char flags)
++{
++ p->dentry = dentry;
++ p->udba = udba;
++ p->lsc_di = lsc_di;
++ p->lsc_hi = lsc_hi;
++ p->flags = flags;
++ p->bindex = bindex;
++
++ p->parent = NULL;
++ p->hdir = NULL;
++ p->h_mnt = NULL;
++}
++
++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int udba, unsigned char flags)
++{
++ au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2,
++ udba, flags);
++ return au_do_pin(pin);
++}
++
++/* ---------------------------------------------------------------------- */
++
++#define AuIcpup_DID_CPUP 1
++#define au_ftest_icpup(flags, name) ((flags) & AuIcpup_##name)
++#define au_fset_icpup(flags, name) { (flags) |= AuIcpup_##name; }
++#define au_fclr_icpup(flags, name) { (flags) &= ~AuIcpup_##name; }
++
++struct au_icpup_args {
++ unsigned char flags;
++ unsigned char pin_flags;
++ aufs_bindex_t btgt;
++ struct au_pin pin;
++ struct path h_path;
++ struct inode *h_inode;
++};
++
++static int au_lock_and_icpup(struct dentry *dentry, struct iattr *ia,
++ struct au_icpup_args *a)
++{
++ int err;
++ unsigned int udba;
++ loff_t sz;
++ aufs_bindex_t bstart;
++ struct dentry *hi_wh, *parent;
++ struct inode *inode;
++ struct au_wr_dir_args wr_dir_args = {
++ .force_btgt = -1,
++ .flags = 0
++ };
++
++ di_write_lock_child(dentry);
++ bstart = au_dbstart(dentry);
++ inode = dentry->d_inode;
++ if (S_ISDIR(inode->i_mode))
++ au_fset_wrdir(wr_dir_args.flags, ISDIR);
++ /* plink or hi_wh() case */
++ if (bstart != au_ibstart(inode))
++ wr_dir_args.force_btgt = au_ibstart(inode);
++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args);
++ if (unlikely(err < 0))
++ goto out_dentry;
++ a->btgt = err;
++ if (err != bstart)
++ au_fset_icpup(a->flags, DID_CPUP);
++
++ err = 0;
++ a->pin_flags = AuPin_MNT_WRITE;
++ parent = NULL;
++ if (!IS_ROOT(dentry)) {
++ au_fset_pin(a->pin_flags, DI_LOCKED);
++ parent = dget_parent(dentry);
++ di_write_lock_parent(parent);
++ }
++
++ udba = au_opt_udba(dentry->d_sb);
++ if (d_unhashed(dentry) || (ia->ia_valid & ATTR_FILE))
++ udba = AuOpt_UDBA_NONE;
++ err = au_pin(&a->pin, dentry, a->btgt, udba, a->pin_flags);
++ if (unlikely(err)) {
++ if (parent) {
++ di_write_unlock(parent);
++ dput(parent);
++ }
++ goto out_dentry;
++ }
++ a->h_path.dentry = au_h_dptr(dentry, bstart);
++ a->h_inode = a->h_path.dentry->d_inode;
++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
++ sz = -1;
++ if ((ia->ia_valid & ATTR_SIZE) && ia->ia_size < i_size_read(a->h_inode))
++ sz = ia->ia_size;
++
++ hi_wh = NULL;
++ if (au_ftest_icpup(a->flags, DID_CPUP) && d_unhashed(dentry)) {
++ hi_wh = au_hi_wh(inode, a->btgt);
++ if (!hi_wh) {
++ err = au_sio_cpup_wh(dentry, a->btgt, sz, /*file*/NULL);
++ if (unlikely(err))
++ goto out_unlock;
++ hi_wh = au_hi_wh(inode, a->btgt);
++ /* todo: revalidate hi_wh? */
++ }
++ }
++
++ if (parent) {
++ au_pin_set_parent_lflag(&a->pin, /*lflag*/0);
++ di_downgrade_lock(parent, AuLock_IR);
++ dput(parent);
++ }
++ if (!au_ftest_icpup(a->flags, DID_CPUP))
++ goto out; /* success */
++
++ if (!d_unhashed(dentry)) {
++ err = au_sio_cpup_simple(dentry, a->btgt, sz, AuCpup_DTIME);
++ if (!err)
++ a->h_path.dentry = au_h_dptr(dentry, a->btgt);
++ } else if (!hi_wh)
++ a->h_path.dentry = au_h_dptr(dentry, a->btgt);
++ else
++ a->h_path.dentry = hi_wh; /* do not dget here */
++
++ out_unlock:
++ mutex_unlock(&a->h_inode->i_mutex);
++ a->h_inode = a->h_path.dentry->d_inode;
++ if (!err) {
++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
++ goto out; /* success */
++ }
++
++ au_unpin(&a->pin);
++
++ out_dentry:
++ di_write_unlock(dentry);
++ out:
++ return err;
++}
++
++static int aufs_setattr(struct dentry *dentry, struct iattr *ia)
++{
++ int err;
++ struct inode *inode;
++ struct super_block *sb;
++ struct file *file;
++ struct au_icpup_args *a;
++
++ err = -ENOMEM;
++ a = kzalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ inode = dentry->d_inode;
++ IMustLock(inode);
++ sb = dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++
++ file = NULL;
++ if (ia->ia_valid & ATTR_FILE) {
++ /* currently ftruncate(2) only */
++ file = ia->ia_file;
++ fi_write_lock(file);
++ ia->ia_file = au_h_fptr(file, au_fbstart(file));
++ }
++
++ if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
++ ia->ia_valid &= ~ATTR_MODE;
++
++ err = au_lock_and_icpup(dentry, ia, a);
++ if (unlikely(err < 0))
++ goto out_si;
++ if (au_ftest_icpup(a->flags, DID_CPUP)) {
++ ia->ia_file = NULL;
++ ia->ia_valid &= ~ATTR_FILE;
++ }
++
++ a->h_path.mnt = au_sbr_mnt(sb, a->btgt);
++ if (ia->ia_valid & ATTR_SIZE) {
++ struct file *f;
++
++ if (ia->ia_size < i_size_read(inode)) {
++ /* unmap only */
++ err = vmtruncate(inode, ia->ia_size);
++ if (unlikely(err))
++ goto out_unlock;
++ }
++
++ f = NULL;
++ if (ia->ia_valid & ATTR_FILE)
++ f = ia->ia_file;
++ mutex_unlock(&a->h_inode->i_mutex);
++ err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f);
++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
++ } else
++ err = vfsub_notify_change(&a->h_path, ia);
++ if (!err)
++ au_cpup_attr_changeable(inode);
++
++ out_unlock:
++ mutex_unlock(&a->h_inode->i_mutex);
++ au_unpin(&a->pin);
++ di_write_unlock(dentry);
++ out_si:
++ if (file) {
++ fi_write_unlock(file);
++ ia->ia_file = file;
++ ia->ia_valid |= ATTR_FILE;
++ }
++ si_read_unlock(sb);
++ kfree(a);
++ out:
++ return err;
++}
++
++static int au_getattr_lock_reval(struct dentry *dentry, unsigned int sigen)
++{
++ int err;
++ struct inode *inode;
++ struct dentry *parent;
++
++ err = 0;
++ inode = dentry->d_inode;
++ di_write_lock_child(dentry);
++ if (au_digen(dentry) != sigen || au_iigen(inode) != sigen) {
++ parent = dget_parent(dentry);
++ di_read_lock_parent(parent, AuLock_IR);
++ /* returns a number of positive dentries */
++ err = au_refresh_hdentry(dentry, inode->i_mode & S_IFMT);
++ if (err > 0)
++ err = au_refresh_hinode(inode, dentry);
++ di_read_unlock(parent, AuLock_IR);
++ dput(parent);
++ if (unlikely(!err))
++ err = -EIO;
++ }
++ di_downgrade_lock(dentry, AuLock_IR);
++ if (unlikely(err))
++ di_read_unlock(dentry, AuLock_IR);
++
++ return err;
++}
++
++static void au_refresh_iattr(struct inode *inode, struct kstat *st,
++ unsigned int nlink)
++{
++ inode->i_mode = st->mode;
++ inode->i_uid = st->uid;
++ inode->i_gid = st->gid;
++ inode->i_atime = st->atime;
++ inode->i_mtime = st->mtime;
++ inode->i_ctime = st->ctime;
++
++ au_cpup_attr_nlink(inode, /*force*/0);
++ if (S_ISDIR(inode->i_mode)) {
++ inode->i_nlink -= nlink;
++ inode->i_nlink += st->nlink;
++ }
++
++ spin_lock(&inode->i_lock);
++ inode->i_blocks = st->blocks;
++ i_size_write(inode, st->size);
++ spin_unlock(&inode->i_lock);
++}
++
++static int aufs_getattr(struct vfsmount *mnt __maybe_unused,
++ struct dentry *dentry, struct kstat *st)
++{
++ int err;
++ unsigned int mnt_flags;
++ aufs_bindex_t bindex;
++ unsigned char udba_none, positive;
++ struct super_block *sb, *h_sb;
++ struct inode *inode;
++ struct vfsmount *h_mnt;
++ struct dentry *h_dentry;
++
++ err = 0;
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ si_read_lock(sb, AuLock_FLUSH);
++ mnt_flags = au_mntflags(sb);
++ udba_none = !!au_opt_test(mnt_flags, UDBA_NONE);
++
++ /* support fstat(2) */
++ if (!d_unhashed(dentry) && !udba_none) {
++ unsigned int sigen = au_sigen(sb);
++ if (au_digen(dentry) == sigen && au_iigen(inode) == sigen)
++ di_read_lock_child(dentry, AuLock_IR);
++ else {
++ /* NFSD may skip the revalidation */
++ if (!au_test_nfsd(current))
++ AuDebugOn(!IS_ROOT(dentry));
++ else {
++ err = au_busy_or_stale();
++ if (unlikely(!IS_ROOT(dentry)))
++ goto out;
++ }
++ err = au_getattr_lock_reval(dentry, sigen);
++ if (unlikely(err))
++ goto out;
++ }
++ } else
++ di_read_lock_child(dentry, AuLock_IR);
++
++ bindex = au_ibstart(inode);
++ h_mnt = au_sbr_mnt(sb, bindex);
++ h_sb = h_mnt->mnt_sb;
++ if (!au_test_fs_bad_iattr(h_sb) && udba_none)
++ goto out_fill; /* success */
++
++ h_dentry = NULL;
++ if (au_dbstart(dentry) == bindex)
++ h_dentry = dget(au_h_dptr(dentry, bindex));
++ else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) {
++ h_dentry = au_plink_lkup(inode, bindex);
++ if (IS_ERR(h_dentry))
++ goto out_fill; /* pretending success */
++ }
++ /* illegally overlapped or something */
++ if (unlikely(!h_dentry))
++ goto out_fill; /* pretending success */
++
++ positive = !!h_dentry->d_inode;
++ if (positive)
++ err = vfs_getattr(h_mnt, h_dentry, st);
++ dput(h_dentry);
++ if (!err) {
++ if (positive)
++ au_refresh_iattr(inode, st, h_dentry->d_inode->i_nlink);
++ goto out_fill; /* success */
++ }
++ goto out_unlock;
++
++ out_fill:
++ generic_fillattr(inode, st);
++ out_unlock:
++ di_read_unlock(dentry, AuLock_IR);
++ out:
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int h_readlink(struct dentry *dentry, int bindex, char __user *buf,
++ int bufsiz)
++{
++ int err;
++ struct super_block *sb;
++ struct dentry *h_dentry;
++
++ err = -EINVAL;
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (unlikely(/* !h_dentry
++ || !h_dentry->d_inode
++ || */ !h_dentry->d_inode->i_op
++ || !h_dentry->d_inode->i_op->readlink))
++ goto out;
++
++ err = security_inode_readlink(h_dentry);
++ if (unlikely(err))
++ goto out;
++
++ sb = dentry->d_sb;
++ if (!au_test_ro(sb, bindex, dentry->d_inode)) {
++ vfsub_touch_atime(au_sbr_mnt(sb, bindex), h_dentry);
++ fsstack_copy_attr_atime(dentry->d_inode, h_dentry->d_inode);
++ }
++ err = h_dentry->d_inode->i_op->readlink(h_dentry, buf, bufsiz);
++
++ out:
++ return err;
++}
++
++static int aufs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
++{
++ int err;
++
++ aufs_read_lock(dentry, AuLock_IR);
++ err = h_readlink(dentry, au_dbstart(dentry), buf, bufsiz);
++ aufs_read_unlock(dentry, AuLock_IR);
++
++ return err;
++}
++
++static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ int err;
++ char *buf;
++ mm_segment_t old_fs;
++
++ err = -ENOMEM;
++ buf = __getname();
++ if (unlikely(!buf))
++ goto out;
++
++ aufs_read_lock(dentry, AuLock_IR);
++ old_fs = get_fs();
++ set_fs(KERNEL_DS);
++ err = h_readlink(dentry, au_dbstart(dentry), (char __user *)buf,
++ PATH_MAX);
++ set_fs(old_fs);
++ aufs_read_unlock(dentry, AuLock_IR);
++
++ if (err >= 0) {
++ buf[err] = 0;
++ /* will be freed by put_link */
++ nd_set_link(nd, buf);
++ return NULL; /* success */
++ }
++ __putname(buf);
++
++ out:
++ path_put(&nd->path);
++ AuTraceErr(err);
++ return ERR_PTR(err);
++}
++
++static void aufs_put_link(struct dentry *dentry __maybe_unused,
++ struct nameidata *nd, void *cookie __maybe_unused)
++{
++ __putname(nd_get_link(nd));
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void aufs_truncate_range(struct inode *inode __maybe_unused,
++ loff_t start __maybe_unused,
++ loff_t end __maybe_unused)
++{
++ AuUnsupport();
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct inode_operations aufs_symlink_iop = {
++ .permission = aufs_permission,
++ .setattr = aufs_setattr,
++ .getattr = aufs_getattr,
++ .readlink = aufs_readlink,
++ .follow_link = aufs_follow_link,
++ .put_link = aufs_put_link
++};
++
++struct inode_operations aufs_dir_iop = {
++ .create = aufs_create,
++ .lookup = aufs_lookup,
++ .link = aufs_link,
++ .unlink = aufs_unlink,
++ .symlink = aufs_symlink,
++ .mkdir = aufs_mkdir,
++ .rmdir = aufs_rmdir,
++ .mknod = aufs_mknod,
++ .rename = aufs_rename,
++
++ .permission = aufs_permission,
++ .setattr = aufs_setattr,
++ .getattr = aufs_getattr
++};
++
++struct inode_operations aufs_iop = {
++ .permission = aufs_permission,
++ .setattr = aufs_setattr,
++ .getattr = aufs_getattr,
++ .truncate_range = aufs_truncate_range
++};
+diff --git a/fs/aufs/i_op_add.c b/fs/aufs/i_op_add.c
+new file mode 100644
+index 0000000..39b7a48
+--- /dev/null
++++ b/fs/aufs/i_op_add.c
+@@ -0,0 +1,649 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * inode operations (add entry)
++ */
++
++#include "aufs.h"
++
++/*
++ * final procedure of adding a new entry, except link(2).
++ * remove whiteout, instantiate, copyup the parent dir's times and size
++ * and update version.
++ * if it failed, re-create the removed whiteout.
++ */
++static int epilog(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct dentry *dentry)
++{
++ int err, rerr;
++ aufs_bindex_t bwh;
++ struct path h_path;
++ struct inode *inode, *h_dir;
++ struct dentry *wh;
++
++ bwh = -1;
++ if (wh_dentry) {
++ h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */
++ IMustLock(h_dir);
++ AuDebugOn(au_h_iptr(dir, bindex) != h_dir);
++ bwh = au_dbwh(dentry);
++ h_path.dentry = wh_dentry;
++ h_path.mnt = au_sbr_mnt(dir->i_sb, bindex);
++ err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path,
++ dentry);
++ if (unlikely(err))
++ goto out;
++ }
++
++ inode = au_new_inode(dentry, /*must_new*/1);
++ if (!IS_ERR(inode)) {
++ d_instantiate(dentry, inode);
++ dir = dentry->d_parent->d_inode; /* dir inode is locked */
++ IMustLock(dir);
++ if (au_ibstart(dir) == au_dbstart(dentry))
++ au_cpup_attr_timesizes(dir);
++ dir->i_version++;
++ return 0; /* success */
++ }
++
++ err = PTR_ERR(inode);
++ if (!wh_dentry)
++ goto out;
++
++ /* revert */
++ /* dir inode is locked */
++ wh = au_wh_create(dentry, bwh, wh_dentry->d_parent);
++ rerr = PTR_ERR(wh);
++ if (IS_ERR(wh)) {
++ AuIOErr("%.*s reverting whiteout failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ } else
++ dput(wh);
++
++ out:
++ return err;
++}
++
++/*
++ * simple tests for the adding inode operations.
++ * following the checks in vfs, plus the parent-child relationship.
++ */
++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent, int isdir)
++{
++ int err;
++ umode_t h_mode;
++ struct dentry *h_dentry;
++ struct inode *h_inode;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ h_inode = h_dentry->d_inode;
++ if (!dentry->d_inode) {
++ err = -EEXIST;
++ if (unlikely(h_inode))
++ goto out;
++ } else {
++ /* rename(2) case */
++ err = -EIO;
++ if (unlikely(!h_inode || !h_inode->i_nlink))
++ goto out;
++
++ h_mode = h_inode->i_mode;
++ if (!isdir) {
++ err = -EISDIR;
++ if (unlikely(S_ISDIR(h_mode)))
++ goto out;
++ } else if (unlikely(!S_ISDIR(h_mode))) {
++ err = -ENOTDIR;
++ goto out;
++ }
++ }
++
++ err = -EIO;
++ /* expected parent dir is locked */
++ if (unlikely(h_parent != h_dentry->d_parent))
++ goto out;
++ err = 0;
++
++ out:
++ return err;
++}
++
++/*
++ * initial procedure of adding a new entry.
++ * prepare writable branch and the parent dir, lock it,
++ * and lookup whiteout for the new entry.
++ */
++static struct dentry*
++lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt,
++ struct dentry *src_dentry, struct au_pin *pin,
++ struct au_wr_dir_args *wr_dir_args)
++{
++ struct dentry *wh_dentry, *h_parent;
++ struct super_block *sb;
++ struct au_branch *br;
++ int err;
++ unsigned int udba;
++ aufs_bindex_t bcpup;
++
++ err = au_wr_dir(dentry, src_dentry, wr_dir_args);
++ bcpup = err;
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err < 0))
++ goto out;
++
++ sb = dentry->d_sb;
++ udba = au_opt_udba(sb);
++ err = au_pin(pin, dentry, bcpup, udba,
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ h_parent = au_pinned_h_parent(pin);
++ if (udba != AuOpt_UDBA_NONE
++ && au_dbstart(dentry) == bcpup) {
++ err = au_may_add(dentry, bcpup, h_parent,
++ au_ftest_wrdir(wr_dir_args->flags, ISDIR));
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_unpin;
++ }
++
++ br = au_sbr(sb, bcpup);
++ if (dt) {
++ struct path tmp = {
++ .dentry = h_parent,
++ .mnt = br->br_mnt
++ };
++ au_dtime_store(dt, au_pinned_parent(pin), &tmp);
++ }
++
++ wh_dentry = NULL;
++ if (bcpup != au_dbwh(dentry))
++ goto out; /* success */
++
++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br);
++
++ out_unpin:
++ if (IS_ERR(wh_dentry))
++ au_unpin(pin);
++ out:
++ return wh_dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++enum { Mknod, Symlink, Creat };
++struct simple_arg {
++ int type;
++ union {
++ struct {
++ int mode;
++ struct nameidata *nd;
++ } c;
++ struct {
++ const char *symname;
++ } s;
++ struct {
++ int mode;
++ dev_t dev;
++ } m;
++ } u;
++};
++
++static int add_simple(struct inode *dir, struct dentry *dentry,
++ struct simple_arg *arg)
++{
++ int err;
++ aufs_bindex_t bstart;
++ unsigned char created;
++ struct au_dtime dt;
++ struct au_pin pin;
++ struct path h_path;
++ struct dentry *wh_dentry, *parent;
++ struct inode *h_dir;
++ struct au_wr_dir_args wr_dir_args = {
++ .force_btgt = -1,
++ .flags = AuWrDir_ADD_ENTRY
++ };
++
++ IMustLock(dir);
++
++ parent = dentry->d_parent; /* dir inode is locked */
++ aufs_read_lock(dentry, AuLock_DW);
++ di_write_lock_parent(parent);
++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, &pin,
++ &wr_dir_args);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out;
++
++ bstart = au_dbstart(dentry);
++ h_path.dentry = au_h_dptr(dentry, bstart);
++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
++ h_dir = au_pinned_h_dir(&pin);
++ switch (arg->type) {
++ case Creat:
++ err = vfsub_create(h_dir, &h_path, arg->u.c.mode);
++ break;
++ case Symlink:
++ err = vfsub_symlink(h_dir, &h_path, arg->u.s.symname);
++ break;
++ case Mknod:
++ err = vfsub_mknod(h_dir, &h_path, arg->u.m.mode, arg->u.m.dev);
++ break;
++ default:
++ BUG();
++ }
++ created = !err;
++ if (!err)
++ err = epilog(dir, bstart, wh_dentry, dentry);
++
++ /* revert */
++ if (unlikely(created && err && h_path.dentry->d_inode)) {
++ int rerr;
++ rerr = vfsub_unlink(h_dir, &h_path, /*force*/0);
++ if (rerr) {
++ AuIOErr("%.*s revert failure(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ }
++ au_dtime_revert(&dt);
++ d_drop(dentry);
++ }
++
++ au_unpin(&pin);
++ dput(wh_dentry);
++
++ out:
++ if (unlikely(err)) {
++ au_update_dbstart(dentry);
++ d_drop(dentry);
++ }
++ di_write_unlock(parent);
++ aufs_read_unlock(dentry, AuLock_DW);
++ return err;
++}
++
++int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
++{
++ struct simple_arg arg = {
++ .type = Mknod,
++ .u.m = {
++ .mode = mode,
++ .dev = dev
++ }
++ };
++ return add_simple(dir, dentry, &arg);
++}
++
++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
++{
++ struct simple_arg arg = {
++ .type = Symlink,
++ .u.s.symname = symname
++ };
++ return add_simple(dir, dentry, &arg);
++}
++
++int aufs_create(struct inode *dir, struct dentry *dentry, int mode,
++ struct nameidata *nd)
++{
++ struct simple_arg arg = {
++ .type = Creat,
++ .u.c = {
++ .mode = mode,
++ .nd = nd
++ }
++ };
++ return add_simple(dir, dentry, &arg);
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_link_args {
++ aufs_bindex_t bdst, bsrc;
++ struct au_pin pin;
++ struct path h_path;
++ struct dentry *src_parent, *parent;
++};
++
++static int au_cpup_before_link(struct dentry *src_dentry,
++ struct au_link_args *a)
++{
++ int err;
++ struct dentry *h_src_dentry;
++ struct mutex *h_mtx;
++
++ di_read_lock_parent(a->src_parent, AuLock_IR);
++ err = au_test_and_cpup_dirs(src_dentry, a->bdst);
++ if (unlikely(err))
++ goto out;
++
++ h_src_dentry = au_h_dptr(src_dentry, a->bsrc);
++ h_mtx = &h_src_dentry->d_inode->i_mutex;
++ err = au_pin(&a->pin, src_dentry, a->bdst,
++ au_opt_udba(src_dentry->d_sb),
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ if (unlikely(err))
++ goto out;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ err = au_sio_cpup_simple(src_dentry, a->bdst, -1,
++ AuCpup_DTIME /* | AuCpup_KEEPLINO */);
++ mutex_unlock(h_mtx);
++ au_unpin(&a->pin);
++
++ out:
++ di_read_unlock(a->src_parent, AuLock_IR);
++ return err;
++}
++
++static int au_cpup_or_link(struct dentry *src_dentry, struct au_link_args *a)
++{
++ int err;
++ unsigned char plink;
++ struct inode *h_inode, *inode;
++ struct dentry *h_src_dentry;
++ struct super_block *sb;
++
++ plink = 0;
++ h_inode = NULL;
++ sb = src_dentry->d_sb;
++ inode = src_dentry->d_inode;
++ if (au_ibstart(inode) <= a->bdst)
++ h_inode = au_h_iptr(inode, a->bdst);
++ if (!h_inode || !h_inode->i_nlink) {
++ /* copyup src_dentry as the name of dentry. */
++ au_set_dbstart(src_dentry, a->bdst);
++ au_set_h_dptr(src_dentry, a->bdst, dget(a->h_path.dentry));
++ h_inode = au_h_dptr(src_dentry, a->bsrc)->d_inode;
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ err = au_sio_cpup_single(src_dentry, a->bdst, a->bsrc, -1,
++ AuCpup_KEEPLINO, a->parent);
++ mutex_unlock(&h_inode->i_mutex);
++ au_set_h_dptr(src_dentry, a->bdst, NULL);
++ au_set_dbstart(src_dentry, a->bsrc);
++ } else {
++ /* the inode of src_dentry already exists on a.bdst branch */
++ h_src_dentry = d_find_alias(h_inode);
++ if (!h_src_dentry && au_plink_test(inode)) {
++ plink = 1;
++ h_src_dentry = au_plink_lkup(inode, a->bdst);
++ err = PTR_ERR(h_src_dentry);
++ if (IS_ERR(h_src_dentry))
++ goto out;
++
++ if (unlikely(!h_src_dentry->d_inode)) {
++ dput(h_src_dentry);
++ h_src_dentry = NULL;
++ }
++
++ }
++ if (h_src_dentry) {
++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin),
++ &a->h_path);
++ dput(h_src_dentry);
++ } else {
++ AuIOErr("no dentry found for hi%lu on b%d\n",
++ h_inode->i_ino, a->bdst);
++ err = -EIO;
++ }
++ }
++
++ if (!err && !plink)
++ au_plink_append(inode, a->bdst, a->h_path.dentry);
++
++out:
++ return err;
++}
++
++int aufs_link(struct dentry *src_dentry, struct inode *dir,
++ struct dentry *dentry)
++{
++ int err, rerr;
++ struct au_dtime dt;
++ struct au_link_args *a;
++ struct dentry *wh_dentry, *h_src_dentry;
++ struct inode *inode;
++ struct super_block *sb;
++ struct au_wr_dir_args wr_dir_args = {
++ /* .force_btgt = -1, */
++ .flags = AuWrDir_ADD_ENTRY
++ };
++
++ IMustLock(dir);
++ inode = src_dentry->d_inode;
++ IMustLock(inode);
++
++ err = -ENOENT;
++ if (unlikely(!inode->i_nlink))
++ goto out;
++
++ err = -ENOMEM;
++ a = kzalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ a->parent = dentry->d_parent; /* dir inode is locked */
++ aufs_read_and_write_lock2(dentry, src_dentry, /*AuLock_FLUSH*/0);
++ a->src_parent = dget_parent(src_dentry);
++ wr_dir_args.force_btgt = au_dbstart(src_dentry);
++
++ di_write_lock_parent(a->parent);
++ wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt);
++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin,
++ &wr_dir_args);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_unlock;
++
++ err = 0;
++ sb = dentry->d_sb;
++ a->bdst = au_dbstart(dentry);
++ a->h_path.dentry = au_h_dptr(dentry, a->bdst);
++ a->h_path.mnt = au_sbr_mnt(sb, a->bdst);
++ a->bsrc = au_dbstart(src_dentry);
++ if (au_opt_test(au_mntflags(sb), PLINK)) {
++ if (a->bdst < a->bsrc
++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */)
++ err = au_cpup_or_link(src_dentry, a);
++ else {
++ h_src_dentry = au_h_dptr(src_dentry, a->bdst);
++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin),
++ &a->h_path);
++ }
++ } else {
++ /*
++ * copyup src_dentry to the branch we process,
++ * and then link(2) to it.
++ */
++ if (a->bdst < a->bsrc
++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) {
++ au_unpin(&a->pin);
++ di_write_unlock(a->parent);
++ err = au_cpup_before_link(src_dentry, a);
++ di_write_lock_parent(a->parent);
++ if (!err)
++ err = au_pin(&a->pin, dentry, a->bdst,
++ au_opt_udba(sb),
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ if (unlikely(err))
++ goto out_wh;
++ }
++ if (!err) {
++ h_src_dentry = au_h_dptr(src_dentry, a->bdst);
++ err = -ENOENT;
++ if (h_src_dentry && h_src_dentry->d_inode)
++ err = vfsub_link(h_src_dentry,
++ au_pinned_h_dir(&a->pin),
++ &a->h_path);
++ }
++ }
++ if (unlikely(err))
++ goto out_unpin;
++
++ if (wh_dentry) {
++ a->h_path.dentry = wh_dentry;
++ err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path,
++ dentry);
++ if (unlikely(err))
++ goto out_revert;
++ }
++
++ dir->i_version++;
++ if (au_ibstart(dir) == au_dbstart(dentry))
++ au_cpup_attr_timesizes(dir);
++ inc_nlink(inode);
++ inode->i_ctime = dir->i_ctime;
++ if (!d_unhashed(a->h_path.dentry))
++ d_instantiate(dentry, au_igrab(inode));
++ else
++ /* some filesystem calls d_drop() */
++ d_drop(dentry);
++ goto out_unpin; /* success */
++
++ out_revert:
++ rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, /*force*/0);
++ if (!rerr)
++ goto out_dt;
++ AuIOErr("%.*s reverting failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ out_dt:
++ d_drop(dentry);
++ au_dtime_revert(&dt);
++ out_unpin:
++ au_unpin(&a->pin);
++ out_wh:
++ dput(wh_dentry);
++ out_unlock:
++ if (unlikely(err)) {
++ au_update_dbstart(dentry);
++ d_drop(dentry);
++ }
++ di_write_unlock(a->parent);
++ dput(a->src_parent);
++ aufs_read_and_write_unlock2(dentry, src_dentry);
++ kfree(a);
++ out:
++ return err;
++}
++
++int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++{
++ int err, rerr;
++ aufs_bindex_t bindex;
++ unsigned char diropq;
++ struct path h_path;
++ struct dentry *wh_dentry, *parent, *opq_dentry;
++ struct mutex *h_mtx;
++ struct super_block *sb;
++ struct {
++ struct au_pin pin;
++ struct au_dtime dt;
++ } *a; /* reduce the stack usage */
++ struct au_wr_dir_args wr_dir_args = {
++ .force_btgt = -1,
++ .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR
++ };
++
++ IMustLock(dir);
++
++ err = -ENOMEM;
++ a = kmalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ aufs_read_lock(dentry, AuLock_DW);
++ parent = dentry->d_parent; /* dir inode is locked */
++ di_write_lock_parent(parent);
++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL,
++ &a->pin, &wr_dir_args);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_free;
++
++ sb = dentry->d_sb;
++ bindex = au_dbstart(dentry);
++ h_path.dentry = au_h_dptr(dentry, bindex);
++ h_path.mnt = au_sbr_mnt(sb, bindex);
++ err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode);
++ if (unlikely(err))
++ goto out_unlock;
++
++ /* make the dir opaque */
++ diropq = 0;
++ h_mtx = &h_path.dentry->d_inode->i_mutex;
++ if (wh_dentry
++ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) {
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ opq_dentry = au_diropq_create(dentry, bindex);
++ mutex_unlock(h_mtx);
++ err = PTR_ERR(opq_dentry);
++ if (IS_ERR(opq_dentry))
++ goto out_dir;
++ dput(opq_dentry);
++ diropq = 1;
++ }
++
++ err = epilog(dir, bindex, wh_dentry, dentry);
++ if (!err) {
++ inc_nlink(dir);
++ goto out_unlock; /* success */
++ }
++
++ /* revert */
++ if (diropq) {
++ AuLabel(revert opq);
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ rerr = au_diropq_remove(dentry, bindex);
++ mutex_unlock(h_mtx);
++ if (rerr) {
++ AuIOErr("%.*s reverting diropq failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ }
++ }
++
++ out_dir:
++ AuLabel(revert dir);
++ rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path);
++ if (rerr) {
++ AuIOErr("%.*s reverting dir failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ err = -EIO;
++ }
++ d_drop(dentry);
++ au_dtime_revert(&a->dt);
++ out_unlock:
++ au_unpin(&a->pin);
++ dput(wh_dentry);
++ out_free:
++ if (unlikely(err)) {
++ au_update_dbstart(dentry);
++ d_drop(dentry);
++ }
++ di_write_unlock(parent);
++ aufs_read_unlock(dentry, AuLock_DW);
++ kfree(a);
++ out:
++ return err;
++}
+diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c
+new file mode 100644
+index 0000000..c0ee77d
+--- /dev/null
++++ b/fs/aufs/i_op_del.c
+@@ -0,0 +1,468 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * inode operations (del entry)
++ */
++
++#include "aufs.h"
++
++/*
++ * decide if a new whiteout for @dentry is necessary or not.
++ * when it is necessary, prepare the parent dir for the upper branch whose
++ * branch index is @bcpup for creation. the actual creation of the whiteout will
++ * be done by caller.
++ * return value:
++ * 0: wh is unnecessary
++ * plus: wh is necessary
++ * minus: error
++ */
++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup)
++{
++ int need_wh, err;
++ aufs_bindex_t bstart;
++ struct super_block *sb;
++
++ sb = dentry->d_sb;
++ bstart = au_dbstart(dentry);
++ if (*bcpup < 0) {
++ *bcpup = bstart;
++ if (au_test_ro(sb, bstart, dentry->d_inode)) {
++ err = AuWbrCopyup(au_sbi(sb), dentry);
++ *bcpup = err;
++ if (unlikely(err < 0))
++ goto out;
++ }
++ } else
++ AuDebugOn(bstart < *bcpup
++ || au_test_ro(sb, *bcpup, dentry->d_inode));
++ AuDbg("bcpup %d, bstart %d\n", *bcpup, bstart);
++
++ if (*bcpup != bstart) {
++ err = au_cpup_dirs(dentry, *bcpup);
++ if (unlikely(err))
++ goto out;
++ need_wh = 1;
++ } else {
++ aufs_bindex_t old_bend, new_bend, bdiropq = -1;
++
++ old_bend = au_dbend(dentry);
++ if (isdir) {
++ bdiropq = au_dbdiropq(dentry);
++ au_set_dbdiropq(dentry, -1);
++ }
++ need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0,
++ /*nd*/NULL);
++ err = need_wh;
++ if (isdir)
++ au_set_dbdiropq(dentry, bdiropq);
++ if (unlikely(err < 0))
++ goto out;
++ new_bend = au_dbend(dentry);
++ if (!need_wh && old_bend != new_bend) {
++ au_set_h_dptr(dentry, new_bend, NULL);
++ au_set_dbend(dentry, old_bend);
++ }
++ }
++ AuDbg("need_wh %d\n", need_wh);
++ err = need_wh;
++
++ out:
++ return err;
++}
++
++/*
++ * simple tests for the del-entry operations.
++ * following the checks in vfs, plus the parent-child relationship.
++ */
++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent, int isdir)
++{
++ int err;
++ umode_t h_mode;
++ struct dentry *h_dentry, *h_latest;
++ struct inode *h_inode;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ h_inode = h_dentry->d_inode;
++ if (dentry->d_inode) {
++ err = -ENOENT;
++ if (unlikely(!h_inode || !h_inode->i_nlink))
++ goto out;
++
++ h_mode = h_inode->i_mode;
++ if (!isdir) {
++ err = -EISDIR;
++ if (unlikely(S_ISDIR(h_mode)))
++ goto out;
++ } else if (unlikely(!S_ISDIR(h_mode))) {
++ err = -ENOTDIR;
++ goto out;
++ }
++ } else {
++ /* rename(2) case */
++ err = -EIO;
++ if (unlikely(h_inode))
++ goto out;
++ }
++
++ err = -ENOENT;
++ /* expected parent dir is locked */
++ if (unlikely(h_parent != h_dentry->d_parent))
++ goto out;
++ err = 0;
++
++ /*
++ * rmdir a dir may break the consistency on some filesystem.
++ * let's try heavy test.
++ */
++ err = -EACCES;
++ if (unlikely(au_test_h_perm(h_parent->d_inode, MAY_EXEC | MAY_WRITE)))
++ goto out;
++
++ h_latest = au_sio_lkup_one(&dentry->d_name, h_parent,
++ au_sbr(dentry->d_sb, bindex));
++ err = -EIO;
++ if (IS_ERR(h_latest))
++ goto out;
++ if (h_latest == h_dentry)
++ err = 0;
++ dput(h_latest);
++
++ out:
++ return err;
++}
++
++/*
++ * decide the branch where we operate for @dentry. the branch index will be set
++ * @rbcpup. after diciding it, 'pin' it and store the timestamps of the parent
++ * dir for reverting.
++ * when a new whiteout is necessary, create it.
++ */
++static struct dentry*
++lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup,
++ struct au_dtime *dt, struct au_pin *pin)
++{
++ struct dentry *wh_dentry;
++ struct super_block *sb;
++ struct path h_path;
++ int err, need_wh;
++ unsigned int udba;
++ aufs_bindex_t bcpup;
++
++ need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup);
++ wh_dentry = ERR_PTR(need_wh);
++ if (unlikely(need_wh < 0))
++ goto out;
++
++ sb = dentry->d_sb;
++ udba = au_opt_udba(sb);
++ bcpup = *rbcpup;
++ err = au_pin(pin, dentry, bcpup, udba,
++ AuPin_DI_LOCKED | AuPin_MNT_WRITE);
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++
++ h_path.dentry = au_pinned_h_parent(pin);
++ if (udba != AuOpt_UDBA_NONE
++ && au_dbstart(dentry) == bcpup) {
++ err = au_may_del(dentry, bcpup, h_path.dentry, isdir);
++ wh_dentry = ERR_PTR(err);
++ if (unlikely(err))
++ goto out_unpin;
++ }
++
++ h_path.mnt = au_sbr_mnt(sb, bcpup);
++ au_dtime_store(dt, au_pinned_parent(pin), &h_path);
++ wh_dentry = NULL;
++ if (!need_wh)
++ goto out; /* success, no need to create whiteout */
++
++ wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry);
++ if (!IS_ERR(wh_dentry))
++ goto out; /* success */
++ /* returns with the parent is locked and wh_dentry is dget-ed */
++
++ out_unpin:
++ au_unpin(pin);
++ out:
++ return wh_dentry;
++}
++
++/*
++ * when removing a dir, rename it to a unique temporary whiteout-ed name first
++ * in order to be revertible and save time for removing many child whiteouts
++ * under the dir.
++ * returns 1 when there are too many child whiteout and caller should remove
++ * them asynchronously. returns 0 when the number of children is enough small to
++ * remove now or the branch fs is a remote fs.
++ * otherwise return an error.
++ */
++static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex,
++ struct au_nhash *whlist, struct inode *dir)
++{
++ int rmdir_later, err, dirwh;
++ struct dentry *h_dentry;
++ struct super_block *sb;
++
++ sb = dentry->d_sb;
++ SiMustAnyLock(sb);
++ h_dentry = au_h_dptr(dentry, bindex);
++ err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex));
++ if (unlikely(err))
++ goto out;
++
++ /* stop monitoring */
++ au_hin_free(au_hi(dentry->d_inode, bindex));
++
++ if (!au_test_fs_remote(h_dentry->d_sb)) {
++ dirwh = au_sbi(sb)->si_dirwh;
++ rmdir_later = (dirwh <= 1);
++ if (!rmdir_later)
++ rmdir_later = au_nhash_test_longer_wh(whlist, bindex,
++ dirwh);
++ if (rmdir_later)
++ return rmdir_later;
++ }
++
++ err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist);
++ if (unlikely(err)) {
++ AuIOErr("rmdir %.*s, b%d failed, %d. ignored\n",
++ AuDLNPair(h_dentry), bindex, err);
++ err = 0;
++ }
++
++ out:
++ return err;
++}
++
++/*
++ * final procedure for deleting a entry.
++ * maintain dentry and iattr.
++ */
++static void epilog(struct inode *dir, struct dentry *dentry,
++ aufs_bindex_t bindex)
++{
++ struct inode *inode;
++
++ inode = dentry->d_inode;
++ d_drop(dentry);
++ inode->i_ctime = dir->i_ctime;
++
++ if (atomic_read(&dentry->d_count) == 1) {
++ au_set_h_dptr(dentry, au_dbstart(dentry), NULL);
++ au_update_dbstart(dentry);
++ }
++ if (au_ibstart(dir) == bindex)
++ au_cpup_attr_timesizes(dir);
++ dir->i_version++;
++}
++
++/*
++ * when an error happened, remove the created whiteout and revert everything.
++ */
++static int do_revert(int err, struct inode *dir, aufs_bindex_t bwh,
++ struct dentry *wh_dentry, struct dentry *dentry,
++ struct au_dtime *dt)
++{
++ int rerr;
++ struct path h_path = {
++ .dentry = wh_dentry,
++ .mnt = au_sbr_mnt(dir->i_sb, bwh)
++ };
++
++ rerr = au_wh_unlink_dentry(au_h_iptr(dir, bwh), &h_path, dentry);
++ if (!rerr) {
++ au_set_dbwh(dentry, bwh);
++ au_dtime_revert(dt);
++ return 0;
++ }
++
++ AuIOErr("%.*s reverting whiteout failed(%d, %d)\n",
++ AuDLNPair(dentry), err, rerr);
++ return -EIO;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int aufs_unlink(struct inode *dir, struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bwh, bindex, bstart;
++ struct au_dtime dt;
++ struct au_pin pin;
++ struct path h_path;
++ struct inode *inode, *h_dir;
++ struct dentry *parent, *wh_dentry;
++
++ IMustLock(dir);
++ inode = dentry->d_inode;
++ if (unlikely(!inode))
++ return -ENOENT; /* possible? */
++ IMustLock(inode);
++
++ aufs_read_lock(dentry, AuLock_DW);
++ parent = dentry->d_parent; /* dir inode is locked */
++ di_write_lock_parent(parent);
++
++ bstart = au_dbstart(dentry);
++ bwh = au_dbwh(dentry);
++ bindex = -1;
++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt, &pin);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out;
++
++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
++ h_path.dentry = au_h_dptr(dentry, bstart);
++ dget(h_path.dentry);
++ if (bindex == bstart) {
++ h_dir = au_pinned_h_dir(&pin);
++ err = vfsub_unlink(h_dir, &h_path, /*force*/0);
++ } else {
++ /* dir inode is locked */
++ h_dir = wh_dentry->d_parent->d_inode;
++ IMustLock(h_dir);
++ err = 0;
++ }
++
++ if (!err) {
++ drop_nlink(inode);
++ epilog(dir, dentry, bindex);
++
++ /* update target timestamps */
++ if (bindex == bstart) {
++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
++ inode->i_ctime = h_path.dentry->d_inode->i_ctime;
++ } else
++ /* todo: this timestamp may be reverted later */
++ inode->i_ctime = h_dir->i_ctime;
++ goto out_unlock; /* success */
++ }
++
++ /* revert */
++ if (wh_dentry) {
++ int rerr;
++
++ rerr = do_revert(err, dir, bwh, wh_dentry, dentry, &dt);
++ if (rerr)
++ err = rerr;
++ }
++
++ out_unlock:
++ au_unpin(&pin);
++ dput(wh_dentry);
++ dput(h_path.dentry);
++ out:
++ di_write_unlock(parent);
++ aufs_read_unlock(dentry, AuLock_DW);
++ return err;
++}
++
++int aufs_rmdir(struct inode *dir, struct dentry *dentry)
++{
++ int err, rmdir_later;
++ aufs_bindex_t bwh, bindex, bstart;
++ struct au_dtime dt;
++ struct au_pin pin;
++ struct inode *inode;
++ struct dentry *parent, *wh_dentry, *h_dentry;
++ struct au_whtmp_rmdir *args;
++
++ IMustLock(dir);
++ inode = dentry->d_inode;
++ err = -ENOENT; /* possible? */
++ if (unlikely(!inode))
++ goto out;
++ IMustLock(inode);
++
++ aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH);
++ err = -ENOMEM;
++ args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS);
++ if (unlikely(!args))
++ goto out_unlock;
++
++ parent = dentry->d_parent; /* dir inode is locked */
++ di_write_lock_parent(parent);
++ err = au_test_empty(dentry, &args->whlist);
++ if (unlikely(err))
++ goto out_args;
++
++ bstart = au_dbstart(dentry);
++ bwh = au_dbwh(dentry);
++ bindex = -1;
++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &dt, &pin);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out_args;
++
++ h_dentry = au_h_dptr(dentry, bstart);
++ dget(h_dentry);
++ rmdir_later = 0;
++ if (bindex == bstart) {
++ err = renwh_and_rmdir(dentry, bstart, &args->whlist, dir);
++ if (err > 0) {
++ rmdir_later = err;
++ err = 0;
++ }
++ } else {
++ /* stop monitoring */
++ au_hin_free(au_hi(inode, bstart));
++
++ /* dir inode is locked */
++ IMustLock(wh_dentry->d_parent->d_inode);
++ err = 0;
++ }
++
++ if (!err) {
++ clear_nlink(inode);
++ au_set_dbdiropq(dentry, -1);
++ epilog(dir, dentry, bindex);
++
++ if (rmdir_later) {
++ au_whtmp_kick_rmdir(dir, bstart, h_dentry, args);
++ args = NULL;
++ }
++
++ goto out_unpin; /* success */
++ }
++
++ /* revert */
++ AuLabel(revert);
++ if (wh_dentry) {
++ int rerr;
++
++ rerr = do_revert(err, dir, bwh, wh_dentry, dentry, &dt);
++ if (rerr)
++ err = rerr;
++ }
++
++ out_unpin:
++ au_unpin(&pin);
++ dput(wh_dentry);
++ dput(h_dentry);
++ out_args:
++ di_write_unlock(parent);
++ if (args)
++ au_whtmp_rmdir_free(args);
++ out_unlock:
++ aufs_read_unlock(dentry, AuLock_DW);
++ out:
++ return err;
++}
+diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c
+new file mode 100644
+index 0000000..006148e
+--- /dev/null
++++ b/fs/aufs/i_op_ren.c
+@@ -0,0 +1,957 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * inode operation (rename entry)
++ * todo: this is crazy monster
++ */
++
++#include "aufs.h"
++
++enum { AuSRC, AuDST, AuSrcDst };
++enum { AuPARENT, AuCHILD, AuParentChild };
++
++#define AuRen_ISDIR 1
++#define AuRen_ISSAMEDIR (1 << 1)
++#define AuRen_WHSRC (1 << 2)
++#define AuRen_WHDST (1 << 3)
++#define AuRen_MNT_WRITE (1 << 4)
++#define AuRen_DT_DSTDIR (1 << 5)
++#define AuRen_DIROPQ (1 << 6)
++#define AuRen_CPUP (1 << 7)
++#define au_ftest_ren(flags, name) ((flags) & AuRen_##name)
++#define au_fset_ren(flags, name) { (flags) |= AuRen_##name; }
++#define au_fclr_ren(flags, name) { (flags) &= ~AuRen_##name; }
++
++struct au_ren_args {
++ struct {
++ struct dentry *dentry, *h_dentry, *parent, *h_parent,
++ *wh_dentry;
++ struct inode *dir, *inode;
++ struct au_hinode *hdir;
++ struct au_dtime dt[AuParentChild];
++ aufs_bindex_t bstart;
++ } sd[AuSrcDst];
++
++#define src_dentry sd[AuSRC].dentry
++#define src_dir sd[AuSRC].dir
++#define src_inode sd[AuSRC].inode
++#define src_h_dentry sd[AuSRC].h_dentry
++#define src_parent sd[AuSRC].parent
++#define src_h_parent sd[AuSRC].h_parent
++#define src_wh_dentry sd[AuSRC].wh_dentry
++#define src_hdir sd[AuSRC].hdir
++#define src_h_dir sd[AuSRC].hdir->hi_inode
++#define src_dt sd[AuSRC].dt
++#define src_bstart sd[AuSRC].bstart
++
++#define dst_dentry sd[AuDST].dentry
++#define dst_dir sd[AuDST].dir
++#define dst_inode sd[AuDST].inode
++#define dst_h_dentry sd[AuDST].h_dentry
++#define dst_parent sd[AuDST].parent
++#define dst_h_parent sd[AuDST].h_parent
++#define dst_wh_dentry sd[AuDST].wh_dentry
++#define dst_hdir sd[AuDST].hdir
++#define dst_h_dir sd[AuDST].hdir->hi_inode
++#define dst_dt sd[AuDST].dt
++#define dst_bstart sd[AuDST].bstart
++
++ struct dentry *h_trap;
++ struct au_branch *br;
++ struct au_hinode *src_hinode;
++ struct path h_path;
++ struct au_nhash whlist;
++ aufs_bindex_t btgt;
++
++ unsigned int flags;
++
++ struct au_whtmp_rmdir *thargs;
++ struct dentry *h_dst;
++};
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * functions for reverting.
++ * when an error happened in a single rename systemcall, we should revert
++ * everything as if nothing happend.
++ * we don't need to revert the copied-up/down the parent dir since they are
++ * harmless.
++ */
++
++#define RevertFailure(fmt, args...) do { \
++ AuIOErr("revert failure: " fmt " (%d, %d)\n", \
++ ##args, err, rerr); \
++ err = -EIO; \
++} while (0)
++
++static void au_ren_rev_diropq(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ au_hin_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
++ rerr = au_diropq_remove(a->src_dentry, a->btgt);
++ au_hin_imtx_unlock(a->src_hinode);
++ if (rerr)
++ RevertFailure("remove diropq %.*s", AuDLNPair(a->src_dentry));
++}
++
++
++static void au_ren_rev_rename(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ a->h_path.dentry = au_lkup_one(&a->src_dentry->d_name, a->src_h_parent,
++ a->br, /*nd*/NULL);
++ rerr = PTR_ERR(a->h_path.dentry);
++ if (IS_ERR(a->h_path.dentry)) {
++ RevertFailure("au_lkup_one %.*s", AuDLNPair(a->src_dentry));
++ return;
++ }
++
++ rerr = vfsub_rename(a->dst_h_dir,
++ au_h_dptr(a->src_dentry, a->btgt),
++ a->src_h_dir, &a->h_path);
++ d_drop(a->h_path.dentry);
++ dput(a->h_path.dentry);
++ /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */
++ if (rerr)
++ RevertFailure("rename %.*s", AuDLNPair(a->src_dentry));
++}
++
++static void au_ren_rev_cpup(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ a->h_path.dentry = a->dst_h_dentry;
++ rerr = vfsub_unlink(a->dst_h_dir, &a->h_path, /*force*/0);
++ au_set_h_dptr(a->src_dentry, a->btgt, NULL);
++ au_set_dbstart(a->src_dentry, a->src_bstart);
++ if (rerr)
++ RevertFailure("unlink %.*s", AuDLNPair(a->dst_h_dentry));
++}
++
++
++static void au_ren_rev_whtmp(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ a->h_path.dentry = au_lkup_one(&a->dst_dentry->d_name, a->dst_h_parent,
++ a->br, /*nd*/NULL);
++ rerr = PTR_ERR(a->h_path.dentry);
++ if (IS_ERR(a->h_path.dentry)) {
++ RevertFailure("lookup %.*s", AuDLNPair(a->dst_dentry));
++ return;
++ }
++ if (a->h_path.dentry->d_inode) {
++ d_drop(a->h_path.dentry);
++ dput(a->h_path.dentry);
++ return;
++ }
++
++ rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path);
++ d_drop(a->h_path.dentry);
++ dput(a->h_path.dentry);
++ if (!rerr) {
++ au_set_h_dptr(a->dst_dentry, a->btgt, NULL);
++ au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst));
++ } else
++ RevertFailure("rename %.*s", AuDLNPair(a->h_dst));
++}
++
++static void au_ren_rev_whsrc(int err, struct au_ren_args *a)
++{
++ int rerr;
++
++ a->h_path.dentry = a->src_wh_dentry;
++ rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry);
++ if (rerr)
++ RevertFailure("unlink %.*s", AuDLNPair(a->src_wh_dentry));
++}
++
++static void au_ren_rev_drop(struct au_ren_args *a)
++{
++ struct dentry *d, *h_d;
++ int i;
++ aufs_bindex_t bend, bindex;
++
++ for (i = 0; i < AuSrcDst; i++) {
++ d = a->sd[i].dentry;
++ d_drop(d);
++ bend = au_dbend(d);
++ for (bindex = au_dbstart(d); bindex <= bend; bindex++) {
++ h_d = au_h_dptr(d, bindex);
++ if (h_d)
++ d_drop(h_d);
++ }
++ }
++
++ au_update_dbstart(a->dst_dentry);
++ if (a->thargs)
++ d_drop(a->h_dst);
++}
++#undef RevertFailure
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * when we have to copyup the renaming entry, do it with the rename-target name
++ * in order to minimize the cost (the later actual rename is unnecessary).
++ * otherwise rename it on the target branch.
++ */
++static int au_ren_or_cpup(struct au_ren_args *a)
++{
++ int err;
++ struct dentry *d;
++
++ d = a->src_dentry;
++ if (au_dbstart(d) == a->btgt) {
++ a->h_path.dentry = a->dst_h_dentry;
++ if (au_ftest_ren(a->flags, DIROPQ)
++ && au_dbdiropq(d) == a->btgt)
++ au_fclr_ren(a->flags, DIROPQ);
++ AuDebugOn(au_dbstart(d) != a->btgt);
++ err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt),
++ a->dst_h_dir, &a->h_path);
++ } else {
++ struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex;
++
++ au_fset_ren(a->flags, CPUP);
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ au_set_dbstart(d, a->btgt);
++ au_set_h_dptr(d, a->btgt, dget(a->dst_h_dentry));
++ err = au_sio_cpup_single(d, a->btgt, a->src_bstart, -1,
++ !AuCpup_DTIME, a->dst_parent);
++ if (unlikely(err)) {
++ au_set_h_dptr(d, a->btgt, NULL);
++ au_set_dbstart(d, a->src_bstart);
++ }
++ mutex_unlock(h_mtx);
++ }
++
++ return err;
++}
++
++/* cf. aufs_rmdir() */
++static int au_ren_del_whtmp(struct au_ren_args *a)
++{
++ int err;
++ struct inode *dir;
++
++ dir = a->dst_dir;
++ SiMustAnyLock(dir->i_sb);
++ if (!au_nhash_test_longer_wh(&a->whlist, a->btgt,
++ au_sbi(dir->i_sb)->si_dirwh)
++ || au_test_fs_remote(a->h_dst->d_sb)) {
++ err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist);
++ if (unlikely(err))
++ AuWarn("failed removing whtmp dir %.*s (%d), "
++ "ignored.\n", AuDLNPair(a->h_dst), err);
++ } else {
++ au_nhash_wh_free(&a->thargs->whlist);
++ a->thargs->whlist = a->whlist;
++ a->whlist.nh_num = 0;
++ au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs);
++ dput(a->h_dst);
++ a->thargs = NULL;
++ }
++
++ return 0;
++}
++
++/* make it 'opaque' dir. */
++static int au_ren_diropq(struct au_ren_args *a)
++{
++ int err;
++ struct dentry *diropq;
++
++ err = 0;
++ a->src_hinode = au_hi(a->src_inode, a->btgt);
++ au_hin_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
++ diropq = au_diropq_create(a->src_dentry, a->btgt);
++ au_hin_imtx_unlock(a->src_hinode);
++ if (IS_ERR(diropq))
++ err = PTR_ERR(diropq);
++ dput(diropq);
++
++ return err;
++}
++
++static int do_rename(struct au_ren_args *a)
++{
++ int err;
++ struct dentry *d, *h_d;
++
++ /* prepare workqueue args for asynchronous rmdir */
++ h_d = a->dst_h_dentry;
++ if (au_ftest_ren(a->flags, ISDIR) && h_d->d_inode) {
++ err = -ENOMEM;
++ a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, GFP_NOFS);
++ if (unlikely(!a->thargs))
++ goto out;
++ a->h_dst = dget(h_d);
++ }
++
++ /* create whiteout for src_dentry */
++ if (au_ftest_ren(a->flags, WHSRC)) {
++ a->src_wh_dentry
++ = au_wh_create(a->src_dentry, a->btgt, a->src_h_parent);
++ err = PTR_ERR(a->src_wh_dentry);
++ if (IS_ERR(a->src_wh_dentry))
++ goto out_thargs;
++ }
++
++ /* lookup whiteout for dentry */
++ if (au_ftest_ren(a->flags, WHDST)) {
++ h_d = au_wh_lkup(a->dst_h_parent, &a->dst_dentry->d_name,
++ a->br);
++ err = PTR_ERR(h_d);
++ if (IS_ERR(h_d))
++ goto out_whsrc;
++ if (!h_d->d_inode)
++ dput(h_d);
++ else
++ a->dst_wh_dentry = h_d;
++ }
++
++ /* rename dentry to tmpwh */
++ if (a->thargs) {
++ err = au_whtmp_ren(a->dst_h_dentry, a->br);
++ if (unlikely(err))
++ goto out_whdst;
++
++ d = a->dst_dentry;
++ au_set_h_dptr(d, a->btgt, NULL);
++ err = au_lkup_neg(d, a->btgt);
++ if (unlikely(err))
++ goto out_whtmp;
++ a->dst_h_dentry = au_h_dptr(d, a->btgt);
++ }
++
++ /* cpup src */
++ if (a->dst_h_dentry->d_inode && a->src_bstart != a->btgt) {
++ struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex;
++
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ err = au_sio_cpup_simple(a->src_dentry, a->btgt, -1,
++ !AuCpup_DTIME);
++ mutex_unlock(h_mtx);
++ if (unlikely(err))
++ goto out_whtmp;
++ }
++
++ /* rename by vfs_rename or cpup */
++ d = a->dst_dentry;
++ if (au_ftest_ren(a->flags, ISDIR)
++ && (a->dst_wh_dentry
++ || au_dbdiropq(d) == a->btgt
++ /* hide the lower to keep xino */
++ || a->btgt < au_dbend(d)
++ || au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ)))
++ au_fset_ren(a->flags, DIROPQ);
++ err = au_ren_or_cpup(a);
++ if (unlikely(err))
++ /* leave the copied-up one */
++ goto out_whtmp;
++
++ /* make dir opaque */
++ if (au_ftest_ren(a->flags, DIROPQ)) {
++ err = au_ren_diropq(a);
++ if (unlikely(err))
++ goto out_rename;
++ }
++
++ /* update target timestamps */
++ AuDebugOn(au_dbstart(a->src_dentry) != a->btgt);
++ a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt);
++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/
++ a->src_inode->i_ctime = a->h_path.dentry->d_inode->i_ctime;
++
++ /* remove whiteout for dentry */
++ if (a->dst_wh_dentry) {
++ a->h_path.dentry = a->dst_wh_dentry;
++ err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path,
++ a->dst_dentry);
++ if (unlikely(err))
++ goto out_diropq;
++ }
++
++ /* remove whtmp */
++ if (a->thargs)
++ au_ren_del_whtmp(a); /* ignore this error */
++
++ err = 0;
++ goto out_success;
++
++ out_diropq:
++ if (au_ftest_ren(a->flags, DIROPQ))
++ au_ren_rev_diropq(err, a);
++ out_rename:
++ if (!au_ftest_ren(a->flags, CPUP))
++ au_ren_rev_rename(err, a);
++ else
++ au_ren_rev_cpup(err, a);
++ out_whtmp:
++ if (a->thargs)
++ au_ren_rev_whtmp(err, a);
++ out_whdst:
++ dput(a->dst_wh_dentry);
++ a->dst_wh_dentry = NULL;
++ out_whsrc:
++ if (a->src_wh_dentry)
++ au_ren_rev_whsrc(err, a);
++ au_ren_rev_drop(a);
++ out_success:
++ dput(a->src_wh_dentry);
++ dput(a->dst_wh_dentry);
++ out_thargs:
++ if (a->thargs) {
++ dput(a->h_dst);
++ au_whtmp_rmdir_free(a->thargs);
++ a->thargs = NULL;
++ }
++ out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * test if @dentry dir can be rename destination or not.
++ * success means, it is a logically empty dir.
++ */
++static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist)
++{
++ return au_test_empty(dentry, whlist);
++}
++
++/*
++ * test if @dentry dir can be rename source or not.
++ * if it can, return 0 and @children is filled.
++ * success means,
++ * - it is a logically empty dir.
++ * - or, it exists on writable branch and has no children including whiteouts
++ * on the lower branch.
++ */
++static int may_rename_srcdir(struct dentry *dentry, aufs_bindex_t btgt)
++{
++ int err;
++ unsigned int rdhash;
++ aufs_bindex_t bstart;
++
++ bstart = au_dbstart(dentry);
++ if (bstart != btgt) {
++ struct au_nhash whlist;
++
++ SiMustAnyLock(dentry->d_sb);
++ rdhash = au_sbi(dentry->d_sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL,
++ dentry));
++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_test_empty(dentry, &whlist);
++ au_nhash_wh_free(&whlist);
++ goto out;
++ }
++
++ if (bstart == au_dbtaildir(dentry))
++ return 0; /* success */
++
++ err = au_test_empty_lower(dentry);
++
++ out:
++ if (err == -ENOTEMPTY) {
++ AuWarn1("renaming dir who has child(ren) on multiple branches,"
++ " is not supported\n");
++ err = -EXDEV;
++ }
++ return err;
++}
++
++/* side effect: sets whlist and h_dentry */
++static int au_ren_may_dir(struct au_ren_args *a)
++{
++ int err;
++ unsigned int rdhash;
++ struct dentry *d;
++
++ d = a->dst_dentry;
++ SiMustAnyLock(d->d_sb);
++
++ err = 0;
++ if (au_ftest_ren(a->flags, ISDIR) && a->dst_inode) {
++ rdhash = au_sbi(d->d_sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d));
++ err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++
++ au_set_dbstart(d, a->dst_bstart);
++ err = may_rename_dstdir(d, &a->whlist);
++ au_set_dbstart(d, a->btgt);
++ }
++ a->dst_h_dentry = au_h_dptr(d, au_dbstart(d));
++ if (unlikely(err))
++ goto out;
++
++ d = a->src_dentry;
++ a->src_h_dentry = au_h_dptr(d, au_dbstart(d));
++ if (au_ftest_ren(a->flags, ISDIR)) {
++ err = may_rename_srcdir(d, a->btgt);
++ if (unlikely(err)) {
++ au_nhash_wh_free(&a->whlist);
++ a->whlist.nh_num = 0;
++ }
++ }
++ out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * simple tests for rename.
++ * following the checks in vfs, plus the parent-child relationship.
++ */
++static int au_may_ren(struct au_ren_args *a)
++{
++ int err, isdir;
++ struct inode *h_inode;
++
++ if (a->src_bstart == a->btgt) {
++ err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent,
++ au_ftest_ren(a->flags, ISDIR));
++ if (unlikely(err))
++ goto out;
++ err = -EINVAL;
++ if (unlikely(a->src_h_dentry == a->h_trap))
++ goto out;
++ }
++
++ err = 0;
++ if (a->dst_bstart != a->btgt)
++ goto out;
++
++ err = -EIO;
++ h_inode = a->dst_h_dentry->d_inode;
++ isdir = !!au_ftest_ren(a->flags, ISDIR);
++ if (!a->dst_dentry->d_inode) {
++ if (unlikely(h_inode))
++ goto out;
++ err = au_may_add(a->dst_dentry, a->btgt, a->dst_h_parent,
++ isdir);
++ } else {
++ if (unlikely(!h_inode || !h_inode->i_nlink))
++ goto out;
++ err = au_may_del(a->dst_dentry, a->btgt, a->dst_h_parent,
++ isdir);
++ if (unlikely(err))
++ goto out;
++ err = -ENOTEMPTY;
++ if (unlikely(a->dst_h_dentry == a->h_trap))
++ goto out;
++ err = 0;
++ }
++
++ out:
++ if (unlikely(err == -ENOENT || err == -EEXIST))
++ err = -EIO;
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * locking order
++ * (VFS)
++ * - src_dir and dir by lock_rename()
++ * - inode if exitsts
++ * (aufs)
++ * - lock all
++ * + src_dentry and dentry by aufs_read_and_write_lock2() which calls,
++ * + si_read_lock
++ * + di_write_lock2_child()
++ * + di_write_lock_child()
++ * + ii_write_lock_child()
++ * + di_write_lock_child2()
++ * + ii_write_lock_child2()
++ * + src_parent and parent
++ * + di_write_lock_parent()
++ * + ii_write_lock_parent()
++ * + di_write_lock_parent2()
++ * + ii_write_lock_parent2()
++ * + lower src_dir and dir by vfsub_lock_rename()
++ * + verify the every relationships between child and parent. if any
++ * of them failed, unlock all and return -EBUSY.
++ */
++static void au_ren_unlock(struct au_ren_args *a)
++{
++ struct super_block *sb;
++
++ sb = a->dst_dentry->d_sb;
++ if (au_ftest_ren(a->flags, MNT_WRITE))
++ mnt_drop_write(a->br->br_mnt);
++ vfsub_unlock_rename(a->src_h_parent, a->src_hdir,
++ a->dst_h_parent, a->dst_hdir);
++}
++
++static int au_ren_lock(struct au_ren_args *a)
++{
++ int err;
++ unsigned int udba;
++
++ err = 0;
++ a->src_h_parent = au_h_dptr(a->src_parent, a->btgt);
++ a->src_hdir = au_hi(a->src_dir, a->btgt);
++ a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt);
++ a->dst_hdir = au_hi(a->dst_dir, a->btgt);
++ a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir,
++ a->dst_h_parent, a->dst_hdir);
++ udba = au_opt_udba(a->src_dentry->d_sb);
++ if (unlikely(a->src_hdir->hi_inode != a->src_h_parent->d_inode
++ || a->dst_hdir->hi_inode != a->dst_h_parent->d_inode))
++ err = au_busy_or_stale();
++ if (!err && au_dbstart(a->src_dentry) == a->btgt)
++ err = au_h_verify(a->src_h_dentry, udba,
++ a->src_h_parent->d_inode, a->src_h_parent,
++ a->br);
++ if (!err && au_dbstart(a->dst_dentry) == a->btgt)
++ err = au_h_verify(a->dst_h_dentry, udba,
++ a->dst_h_parent->d_inode, a->dst_h_parent,
++ a->br);
++ if (!err) {
++ err = mnt_want_write(a->br->br_mnt);
++ if (unlikely(err))
++ goto out_unlock;
++ au_fset_ren(a->flags, MNT_WRITE);
++ goto out; /* success */
++ }
++
++ err = au_busy_or_stale();
++
++ out_unlock:
++ au_ren_unlock(a);
++ out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static void au_ren_refresh_dir(struct au_ren_args *a)
++{
++ struct inode *dir;
++
++ dir = a->dst_dir;
++ dir->i_version++;
++ if (au_ftest_ren(a->flags, ISDIR)) {
++ /* is this updating defined in POSIX? */
++ au_cpup_attr_timesizes(a->src_inode);
++ au_cpup_attr_nlink(dir, /*force*/1);
++ if (a->dst_inode) {
++ clear_nlink(a->dst_inode);
++ au_cpup_attr_timesizes(a->dst_inode);
++ }
++ }
++ if (au_ibstart(dir) == a->btgt)
++ au_cpup_attr_timesizes(dir);
++
++ if (au_ftest_ren(a->flags, ISSAMEDIR))
++ return;
++
++ dir = a->src_dir;
++ dir->i_version++;
++ if (au_ftest_ren(a->flags, ISDIR))
++ au_cpup_attr_nlink(dir, /*force*/1);
++ if (au_ibstart(dir) == a->btgt)
++ au_cpup_attr_timesizes(dir);
++}
++
++static void au_ren_refresh(struct au_ren_args *a)
++{
++ aufs_bindex_t bend, bindex;
++ struct dentry *d, *h_d;
++ struct inode *i, *h_i;
++ struct super_block *sb;
++
++ d = a->src_dentry;
++ au_set_dbwh(d, -1);
++ bend = au_dbend(d);
++ for (bindex = a->btgt + 1; bindex <= bend; bindex++) {
++ h_d = au_h_dptr(d, bindex);
++ if (h_d)
++ au_set_h_dptr(d, bindex, NULL);
++ }
++ au_set_dbend(d, a->btgt);
++
++ sb = d->d_sb;
++ i = a->src_inode;
++ if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i))
++ return; /* success */
++
++ bend = au_ibend(i);
++ for (bindex = a->btgt + 1; bindex <= bend; bindex++) {
++ h_i = au_h_iptr(i, bindex);
++ if (h_i) {
++ au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0);
++ /* ignore this error */
++ au_set_h_iptr(i, bindex, NULL, 0);
++ }
++ }
++ au_set_ibend(i, a->btgt);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* mainly for link(2) and rename(2) */
++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt)
++{
++ aufs_bindex_t bdiropq, bwh;
++ struct dentry *parent;
++ struct au_branch *br;
++
++ parent = dentry->d_parent;
++ IMustLock(parent->d_inode); /* dir is locked */
++
++ bdiropq = au_dbdiropq(parent);
++ bwh = au_dbwh(dentry);
++ br = au_sbr(dentry->d_sb, btgt);
++ if (au_br_rdonly(br)
++ || (0 <= bdiropq && bdiropq < btgt)
++ || (0 <= bwh && bwh < btgt))
++ btgt = -1;
++
++ AuDbg("btgt %d\n", btgt);
++ return btgt;
++}
++
++/* sets src_bstart, dst_bstart and btgt */
++static int au_ren_wbr(struct au_ren_args *a)
++{
++ int err;
++ struct au_wr_dir_args wr_dir_args = {
++ /* .force_btgt = -1, */
++ .flags = AuWrDir_ADD_ENTRY
++ };
++
++ a->src_bstart = au_dbstart(a->src_dentry);
++ a->dst_bstart = au_dbstart(a->dst_dentry);
++ if (au_ftest_ren(a->flags, ISDIR))
++ au_fset_wrdir(wr_dir_args.flags, ISDIR);
++ wr_dir_args.force_btgt = a->src_bstart;
++ if (a->dst_inode && a->dst_bstart < a->src_bstart)
++ wr_dir_args.force_btgt = a->dst_bstart;
++ wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt);
++ err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args);
++ a->btgt = err;
++
++ return err;
++}
++
++static void au_ren_dt(struct au_ren_args *a)
++{
++ a->h_path.dentry = a->src_h_parent;
++ au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path);
++ if (!au_ftest_ren(a->flags, ISSAMEDIR)) {
++ a->h_path.dentry = a->dst_h_parent;
++ au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path);
++ }
++
++ au_fclr_ren(a->flags, DT_DSTDIR);
++ if (!au_ftest_ren(a->flags, ISDIR))
++ return;
++
++ a->h_path.dentry = a->src_h_dentry;
++ au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path);
++ if (a->dst_h_dentry->d_inode) {
++ au_fset_ren(a->flags, DT_DSTDIR);
++ a->h_path.dentry = a->dst_h_dentry;
++ au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path);
++ }
++}
++
++static void au_ren_rev_dt(int err, struct au_ren_args *a)
++{
++ struct dentry *h_d;
++ struct mutex *h_mtx;
++
++ au_dtime_revert(a->src_dt + AuPARENT);
++ if (!au_ftest_ren(a->flags, ISSAMEDIR))
++ au_dtime_revert(a->dst_dt + AuPARENT);
++
++ if (au_ftest_ren(a->flags, ISDIR) && err != -EIO) {
++ h_d = a->src_dt[AuCHILD].dt_h_path.dentry;
++ h_mtx = &h_d->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ au_dtime_revert(a->src_dt + AuCHILD);
++ mutex_unlock(h_mtx);
++
++ if (au_ftest_ren(a->flags, DT_DSTDIR)) {
++ h_d = a->dst_dt[AuCHILD].dt_h_path.dentry;
++ h_mtx = &h_d->d_inode->i_mutex;
++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
++ au_dtime_revert(a->dst_dt + AuCHILD);
++ mutex_unlock(h_mtx);
++ }
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry,
++ struct inode *_dst_dir, struct dentry *_dst_dentry)
++{
++ int err;
++ /* reduce stack space */
++ struct au_ren_args *a;
++
++ IMustLock(_src_dir);
++ IMustLock(_dst_dir);
++
++ err = -ENOMEM;
++ BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE);
++ a = kzalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ a->src_dir = _src_dir;
++ a->src_dentry = _src_dentry;
++ a->src_inode = a->src_dentry->d_inode;
++ a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */
++ a->dst_dir = _dst_dir;
++ a->dst_dentry = _dst_dentry;
++ a->dst_inode = a->dst_dentry->d_inode;
++ a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */
++ if (a->dst_inode) {
++ IMustLock(a->dst_inode);
++ au_igrab(a->dst_inode);
++ }
++
++ err = -ENOTDIR;
++ if (S_ISDIR(a->src_inode->i_mode)) {
++ au_fset_ren(a->flags, ISDIR);
++ if (unlikely(a->dst_inode && !S_ISDIR(a->dst_inode->i_mode)))
++ goto out_free;
++ aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry,
++ AuLock_DIR | AuLock_FLUSH);
++ } else
++ aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry,
++ AuLock_FLUSH);
++
++ au_fset_ren(a->flags, ISSAMEDIR); /* temporary */
++ di_write_lock_parent(a->dst_parent);
++
++ /* which branch we process */
++ err = au_ren_wbr(a);
++ if (unlikely(err < 0))
++ goto out_unlock;
++ a->br = au_sbr(a->dst_dentry->d_sb, a->btgt);
++ a->h_path.mnt = a->br->br_mnt;
++
++ /* are they available to be renamed */
++ err = au_ren_may_dir(a);
++ if (unlikely(err))
++ goto out_children;
++
++ /* prepare the writable parent dir on the same branch */
++ if (a->dst_bstart == a->btgt) {
++ au_fset_ren(a->flags, WHDST);
++ } else {
++ err = au_cpup_dirs(a->dst_dentry, a->btgt);
++ if (unlikely(err))
++ goto out_children;
++ }
++
++ if (a->src_dir != a->dst_dir) {
++ /*
++ * this temporary unlock is safe,
++ * because both dir->i_mutex are locked.
++ */
++ di_write_unlock(a->dst_parent);
++ di_write_lock_parent(a->src_parent);
++ err = au_wr_dir_need_wh(a->src_dentry,
++ au_ftest_ren(a->flags, ISDIR),
++ &a->btgt);
++ di_write_unlock(a->src_parent);
++ di_write_lock2_parent(a->src_parent, a->dst_parent, /*isdir*/1);
++ au_fclr_ren(a->flags, ISSAMEDIR);
++ } else
++ err = au_wr_dir_need_wh(a->src_dentry,
++ au_ftest_ren(a->flags, ISDIR),
++ &a->btgt);
++ if (unlikely(err < 0))
++ goto out_children;
++ if (err)
++ au_fset_ren(a->flags, WHSRC);
++
++ /* lock them all */
++ err = au_ren_lock(a);
++ if (unlikely(err))
++ goto out_children;
++
++ if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) {
++ err = au_may_ren(a);
++ if (unlikely(err))
++ goto out_hdir;
++ }
++
++ /* store timestamps to be revertible */
++ au_ren_dt(a);
++
++ /* here we go */
++ err = do_rename(a);
++ if (unlikely(err))
++ goto out_dt;
++
++ /* update dir attributes */
++ au_ren_refresh_dir(a);
++
++ /* dput/iput all lower dentries */
++ au_ren_refresh(a);
++
++ goto out_hdir; /* success */
++
++ out_dt:
++ au_ren_rev_dt(err, a);
++ out_hdir:
++ au_ren_unlock(a);
++ out_children:
++ au_nhash_wh_free(&a->whlist);
++ out_unlock:
++ if (unlikely(err && au_ftest_ren(a->flags, ISDIR))) {
++ au_update_dbstart(a->dst_dentry);
++ d_drop(a->dst_dentry);
++ }
++ if (!err)
++ d_move(a->src_dentry, a->dst_dentry);
++ if (au_ftest_ren(a->flags, ISSAMEDIR))
++ di_write_unlock(a->dst_parent);
++ else
++ di_write_unlock2(a->src_parent, a->dst_parent);
++ aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry);
++ out_free:
++ iput(a->dst_inode);
++ if (a->thargs)
++ au_whtmp_rmdir_free(a->thargs);
++ kfree(a);
++ out:
++ return err;
++}
+diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c
+new file mode 100644
+index 0000000..072ddfc
+--- /dev/null
++++ b/fs/aufs/iinfo.c
+@@ -0,0 +1,283 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * inode private data
++ */
++
++#include "aufs.h"
++
++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex)
++{
++ struct inode *h_inode;
++
++ IiMustAnyLock(inode);
++
++ h_inode = au_ii(inode)->ii_hinode[0 + bindex].hi_inode;
++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0);
++ return h_inode;
++}
++
++/* todo: hard/soft set? */
++void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex)
++{
++ struct au_iinfo *iinfo = au_ii(inode);
++ struct inode *h_inode;
++
++ IiMustWriteLock(inode);
++
++ iinfo->ii_bstart = bindex;
++ h_inode = iinfo->ii_hinode[bindex + 0].hi_inode;
++ if (h_inode)
++ au_cpup_igen(inode, h_inode);
++}
++
++void au_hiput(struct au_hinode *hinode)
++{
++ au_hin_free(hinode);
++ dput(hinode->hi_whdentry);
++ iput(hinode->hi_inode);
++}
++
++unsigned int au_hi_flags(struct inode *inode, int isdir)
++{
++ unsigned int flags;
++ const unsigned int mnt_flags = au_mntflags(inode->i_sb);
++
++ flags = 0;
++ if (au_opt_test(mnt_flags, XINO))
++ au_fset_hi(flags, XINO);
++ if (isdir && au_opt_test(mnt_flags, UDBA_HINOTIFY))
++ au_fset_hi(flags, HINOTIFY);
++ return flags;
++}
++
++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
++ struct inode *h_inode, unsigned int flags)
++{
++ struct au_hinode *hinode;
++ struct inode *hi;
++ struct au_iinfo *iinfo = au_ii(inode);
++
++ IiMustWriteLock(inode);
++
++ hinode = iinfo->ii_hinode + bindex;
++ hi = hinode->hi_inode;
++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0);
++ AuDebugOn(h_inode && hi);
++
++ if (hi)
++ au_hiput(hinode);
++ hinode->hi_inode = h_inode;
++ if (h_inode) {
++ int err;
++ struct super_block *sb = inode->i_sb;
++ struct au_branch *br;
++
++ if (bindex == iinfo->ii_bstart)
++ au_cpup_igen(inode, h_inode);
++ br = au_sbr(sb, bindex);
++ hinode->hi_id = br->br_id;
++ if (au_ftest_hi(flags, XINO)) {
++ err = au_xino_write(sb, bindex, h_inode->i_ino,
++ inode->i_ino);
++ if (unlikely(err))
++ AuIOErr1("failed au_xino_write() %d\n", err);
++ }
++
++ if (au_ftest_hi(flags, HINOTIFY)
++ && au_br_hinotifyable(br->br_perm)) {
++ err = au_hin_alloc(hinode, inode, h_inode);
++ if (unlikely(err))
++ AuIOErr1("au_hin_alloc() %d\n", err);
++ }
++ }
++}
++
++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_wh)
++{
++ struct au_hinode *hinode;
++
++ IiMustWriteLock(inode);
++
++ hinode = au_ii(inode)->ii_hinode + bindex;
++ AuDebugOn(hinode->hi_whdentry);
++ hinode->hi_whdentry = h_wh;
++}
++
++void au_update_iigen(struct inode *inode)
++{
++ atomic_set(&au_ii(inode)->ii_generation, au_sigen(inode->i_sb));
++ /* smp_mb(); */ /* atomic_set */
++}
++
++/* it may be called at remount time, too */
++void au_update_brange(struct inode *inode, int do_put_zero)
++{
++ struct au_iinfo *iinfo;
++
++ iinfo = au_ii(inode);
++ if (!iinfo || iinfo->ii_bstart < 0)
++ return;
++
++ IiMustWriteLock(inode);
++
++ if (do_put_zero) {
++ aufs_bindex_t bindex;
++
++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend;
++ bindex++) {
++ struct inode *h_i;
++
++ h_i = iinfo->ii_hinode[0 + bindex].hi_inode;
++ if (h_i && !h_i->i_nlink)
++ au_set_h_iptr(inode, bindex, NULL, 0);
++ }
++ }
++
++ iinfo->ii_bstart = -1;
++ while (++iinfo->ii_bstart <= iinfo->ii_bend)
++ if (iinfo->ii_hinode[0 + iinfo->ii_bstart].hi_inode)
++ break;
++ if (iinfo->ii_bstart > iinfo->ii_bend) {
++ iinfo->ii_bstart = -1;
++ iinfo->ii_bend = -1;
++ return;
++ }
++
++ iinfo->ii_bend++;
++ while (0 <= --iinfo->ii_bend)
++ if (iinfo->ii_hinode[0 + iinfo->ii_bend].hi_inode)
++ break;
++ AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend || iinfo->ii_bend < 0);
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_iinfo_init(struct inode *inode)
++{
++ struct au_iinfo *iinfo;
++ struct super_block *sb;
++ int nbr, i;
++
++ sb = inode->i_sb;
++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo);
++ nbr = au_sbend(sb) + 1;
++ if (unlikely(nbr <= 0))
++ nbr = 1;
++ iinfo->ii_hinode = kcalloc(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS);
++ if (iinfo->ii_hinode) {
++ for (i = 0; i < nbr; i++)
++ iinfo->ii_hinode[i].hi_id = -1;
++
++ atomic_set(&iinfo->ii_generation, au_sigen(sb));
++ /* smp_mb(); */ /* atomic_set */
++ au_rw_init(&iinfo->ii_rwsem);
++ iinfo->ii_bstart = -1;
++ iinfo->ii_bend = -1;
++ iinfo->ii_vdir = NULL;
++ return 0;
++ }
++ return -ENOMEM;
++}
++
++int au_ii_realloc(struct au_iinfo *iinfo, int nbr)
++{
++ int err, sz;
++ struct au_hinode *hip;
++
++ AuRwMustWriteLock(&iinfo->ii_rwsem);
++
++ err = -ENOMEM;
++ sz = sizeof(*hip) * (iinfo->ii_bend + 1);
++ if (!sz)
++ sz = sizeof(*hip);
++ hip = au_kzrealloc(iinfo->ii_hinode, sz, sizeof(*hip) * nbr, GFP_NOFS);
++ if (hip) {
++ iinfo->ii_hinode = hip;
++ err = 0;
++ }
++
++ return err;
++}
++
++static int au_iinfo_write0(struct super_block *sb, struct au_hinode *hinode,
++ ino_t ino)
++{
++ int err;
++ aufs_bindex_t bindex;
++ unsigned char locked;
++
++ err = 0;
++ locked = !!si_noflush_read_trylock(sb);
++ bindex = au_br_index(sb, hinode->hi_id);
++ if (bindex >= 0)
++ err = au_xino_write0(sb, bindex, hinode->hi_inode->i_ino, ino);
++ /* error action? */
++ if (locked)
++ si_read_unlock(sb);
++ return err;
++}
++
++void au_iinfo_fin(struct inode *inode)
++{
++ ino_t ino;
++ aufs_bindex_t bend;
++ unsigned char unlinked = !inode->i_nlink;
++ struct au_iinfo *iinfo;
++ struct au_hinode *hi;
++ struct super_block *sb;
++
++ if (unlinked) {
++ int err = au_xigen_inc(inode);
++ if (unlikely(err))
++ AuWarn1("failed resetting i_generation, %d\n", err);
++ }
++
++ iinfo = au_ii(inode);
++ /* bad_inode case */
++ if (!iinfo)
++ return;
++
++ if (iinfo->ii_vdir)
++ au_vdir_free(iinfo->ii_vdir);
++
++ if (iinfo->ii_bstart >= 0) {
++ sb = inode->i_sb;
++ ino = 0;
++ if (unlinked)
++ ino = inode->i_ino;
++ hi = iinfo->ii_hinode + iinfo->ii_bstart;
++ bend = iinfo->ii_bend;
++ while (iinfo->ii_bstart++ <= bend) {
++ if (hi->hi_inode) {
++ if (unlinked || !hi->hi_inode->i_nlink) {
++ au_iinfo_write0(sb, hi, ino);
++ /* ignore this error */
++ ino = 0;
++ }
++ au_hiput(hi);
++ }
++ hi++;
++ }
++ }
++
++ kfree(iinfo->ii_hinode);
++ AuRwDestroy(&iinfo->ii_rwsem);
++}
+diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c
+new file mode 100644
+index 0000000..ae9c64a
+--- /dev/null
++++ b/fs/aufs/inode.c
+@@ -0,0 +1,413 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * inode functions
++ */
++
++#include "aufs.h"
++
++struct inode *au_igrab(struct inode *inode)
++{
++ if (inode) {
++ AuDebugOn(!atomic_read(&inode->i_count));
++ atomic_inc_return(&inode->i_count);
++ }
++ return inode;
++}
++
++static void au_refresh_hinode_attr(struct inode *inode, int do_version)
++{
++ au_cpup_attr_all(inode, /*force*/0);
++ au_update_iigen(inode);
++ if (do_version)
++ inode->i_version++;
++}
++
++int au_refresh_hinode_self(struct inode *inode, int do_attr)
++{
++ int err;
++ aufs_bindex_t bindex, new_bindex;
++ unsigned char update;
++ struct inode *first;
++ struct au_hinode *p, *q, tmp;
++ struct super_block *sb;
++ struct au_iinfo *iinfo;
++
++ IiMustWriteLock(inode);
++
++ update = 0;
++ sb = inode->i_sb;
++ iinfo = au_ii(inode);
++ err = au_ii_realloc(iinfo, au_sbend(sb) + 1);
++ if (unlikely(err))
++ goto out;
++
++ p = iinfo->ii_hinode + iinfo->ii_bstart;
++ first = p->hi_inode;
++ err = 0;
++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend;
++ bindex++, p++) {
++ if (!p->hi_inode)
++ continue;
++
++ new_bindex = au_br_index(sb, p->hi_id);
++ if (new_bindex == bindex)
++ continue;
++
++ if (new_bindex < 0) {
++ update++;
++ au_hiput(p);
++ p->hi_inode = NULL;
++ continue;
++ }
++
++ if (new_bindex < iinfo->ii_bstart)
++ iinfo->ii_bstart = new_bindex;
++ if (iinfo->ii_bend < new_bindex)
++ iinfo->ii_bend = new_bindex;
++ /* swap two lower inode, and loop again */
++ q = iinfo->ii_hinode + new_bindex;
++ tmp = *q;
++ *q = *p;
++ *p = tmp;
++ if (tmp.hi_inode) {
++ bindex--;
++ p--;
++ }
++ }
++ au_update_brange(inode, /*do_put_zero*/0);
++ if (do_attr)
++ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode));
++
++ out:
++ return err;
++}
++
++int au_refresh_hinode(struct inode *inode, struct dentry *dentry)
++{
++ int err, update;
++ unsigned int flags;
++ aufs_bindex_t bindex, bend;
++ unsigned char isdir;
++ struct inode *first;
++ struct au_hinode *p;
++ struct au_iinfo *iinfo;
++
++ err = au_refresh_hinode_self(inode, /*do_attr*/0);
++ if (unlikely(err))
++ goto out;
++
++ update = 0;
++ iinfo = au_ii(inode);
++ p = iinfo->ii_hinode + iinfo->ii_bstart;
++ first = p->hi_inode;
++ isdir = S_ISDIR(inode->i_mode);
++ flags = au_hi_flags(inode, isdir);
++ bend = au_dbend(dentry);
++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) {
++ struct inode *h_i;
++ struct dentry *h_d;
++
++ h_d = au_h_dptr(dentry, bindex);
++ if (!h_d || !h_d->d_inode)
++ continue;
++
++ if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) {
++ h_i = au_h_iptr(inode, bindex);
++ if (h_i) {
++ if (h_i == h_d->d_inode)
++ continue;
++ err = -EIO;
++ break;
++ }
++ }
++ if (bindex < iinfo->ii_bstart)
++ iinfo->ii_bstart = bindex;
++ if (iinfo->ii_bend < bindex)
++ iinfo->ii_bend = bindex;
++ au_set_h_iptr(inode, bindex, au_igrab(h_d->d_inode), flags);
++ update = 1;
++ }
++ au_update_brange(inode, /*do_put_zero*/0);
++
++ if (unlikely(err))
++ goto out;
++
++ au_refresh_hinode_attr(inode, update && isdir);
++
++ out:
++ return err;
++}
++
++static int set_inode(struct inode *inode, struct dentry *dentry)
++{
++ int err;
++ unsigned int flags;
++ umode_t mode;
++ aufs_bindex_t bindex, bstart, btail;
++ unsigned char isdir;
++ struct dentry *h_dentry;
++ struct inode *h_inode;
++ struct au_iinfo *iinfo;
++
++ IiMustWriteLock(inode);
++
++ err = 0;
++ isdir = 0;
++ bstart = au_dbstart(dentry);
++ h_inode = au_h_dptr(dentry, bstart)->d_inode;
++ mode = h_inode->i_mode;
++ switch (mode & S_IFMT) {
++ case S_IFREG:
++ btail = au_dbtail(dentry);
++ inode->i_op = &aufs_iop;
++ inode->i_fop = &aufs_file_fop;
++ inode->i_mapping->a_ops = &aufs_aop;
++ break;
++ case S_IFDIR:
++ isdir = 1;
++ btail = au_dbtaildir(dentry);
++ inode->i_op = &aufs_dir_iop;
++ inode->i_fop = &aufs_dir_fop;
++ break;
++ case S_IFLNK:
++ btail = au_dbtail(dentry);
++ inode->i_op = &aufs_symlink_iop;
++ break;
++ case S_IFBLK:
++ case S_IFCHR:
++ case S_IFIFO:
++ case S_IFSOCK:
++ btail = au_dbtail(dentry);
++ inode->i_op = &aufs_iop;
++ init_special_inode(inode, mode, h_inode->i_rdev);
++ break;
++ default:
++ AuIOErr("Unknown file type 0%o\n", mode);
++ err = -EIO;
++ goto out;
++ }
++
++ /* do not set inotify for whiteouted dirs (SHWH mode) */
++ flags = au_hi_flags(inode, isdir);
++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)
++ && au_ftest_hi(flags, HINOTIFY)
++ && dentry->d_name.len > AUFS_WH_PFX_LEN
++ && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))
++ au_fclr_hi(flags, HINOTIFY);
++ iinfo = au_ii(inode);
++ iinfo->ii_bstart = bstart;
++ iinfo->ii_bend = btail;
++ for (bindex = bstart; bindex <= btail; bindex++) {
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (h_dentry)
++ au_set_h_iptr(inode, bindex,
++ au_igrab(h_dentry->d_inode), flags);
++ }
++ au_cpup_attr_all(inode, /*force*/1);
++
++ out:
++ return err;
++}
++
++/* successful returns with iinfo write_locked */
++static int reval_inode(struct inode *inode, struct dentry *dentry, int *matched)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ struct inode *h_inode, *h_dinode;
++
++ *matched = 0;
++
++ /*
++ * before this function, if aufs got any iinfo lock, it must be only
++ * one, the parent dir.
++ * it can happen by UDBA and the obsoleted inode number.
++ */
++ err = -EIO;
++ if (unlikely(inode->i_ino == parent_ino(dentry)))
++ goto out;
++
++ err = 0;
++ ii_write_lock_new_child(inode);
++ h_dinode = au_h_dptr(dentry, au_dbstart(dentry))->d_inode;
++ bend = au_ibend(inode);
++ for (bindex = au_ibstart(inode); bindex <= bend; bindex++) {
++ h_inode = au_h_iptr(inode, bindex);
++ if (h_inode && h_inode == h_dinode) {
++ *matched = 1;
++ err = 0;
++ if (au_iigen(inode) != au_digen(dentry))
++ err = au_refresh_hinode(inode, dentry);
++ break;
++ }
++ }
++
++ if (unlikely(err))
++ ii_write_unlock(inode);
++ out:
++ return err;
++}
++
++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ unsigned int d_type, ino_t *ino)
++{
++ int err;
++ struct mutex *mtx;
++ const int isdir = (d_type == DT_DIR);
++
++ /* prevent hardlinks from race condition */
++ mtx = NULL;
++ if (!isdir) {
++ mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx;
++ mutex_lock(mtx);
++ }
++ err = au_xino_read(sb, bindex, h_ino, ino);
++ if (unlikely(err))
++ goto out;
++
++ if (!*ino) {
++ err = -EIO;
++ *ino = au_xino_new_ino(sb);
++ if (unlikely(!*ino))
++ goto out;
++ err = au_xino_write(sb, bindex, h_ino, *ino);
++ if (unlikely(err))
++ goto out;
++ }
++
++ out:
++ if (!isdir)
++ mutex_unlock(mtx);
++ return err;
++}
++
++/* successful returns with iinfo write_locked */
++/* todo: return with unlocked? */
++struct inode *au_new_inode(struct dentry *dentry, int must_new)
++{
++ struct inode *inode;
++ struct dentry *h_dentry;
++ struct super_block *sb;
++ ino_t h_ino, ino;
++ int err, match;
++ aufs_bindex_t bstart;
++
++ sb = dentry->d_sb;
++ bstart = au_dbstart(dentry);
++ h_dentry = au_h_dptr(dentry, bstart);
++ h_ino = h_dentry->d_inode->i_ino;
++ err = au_xino_read(sb, bstart, h_ino, &ino);
++ inode = ERR_PTR(err);
++ if (unlikely(err))
++ goto out;
++ new_ino:
++ if (!ino) {
++ ino = au_xino_new_ino(sb);
++ if (unlikely(!ino)) {
++ inode = ERR_PTR(-EIO);
++ goto out;
++ }
++ }
++
++ AuDbg("i%lu\n", (unsigned long)ino);
++ inode = au_iget_locked(sb, ino);
++ err = PTR_ERR(inode);
++ if (IS_ERR(inode))
++ goto out;
++
++ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW));
++ if (inode->i_state & I_NEW) {
++ ii_write_lock_new_child(inode);
++ err = set_inode(inode, dentry);
++ unlock_new_inode(inode);
++ if (!err)
++ goto out; /* success */
++
++ iget_failed(inode);
++ ii_write_unlock(inode);
++ goto out_iput;
++ } else if (!must_new) {
++ err = reval_inode(inode, dentry, &match);
++ if (!err)
++ goto out; /* success */
++ else if (match)
++ goto out_iput;
++ }
++
++ if (unlikely(au_test_fs_unique_ino(h_dentry->d_inode)))
++ AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir,"
++ " b%d, %s, %.*s, hi%lu, i%lu.\n",
++ bstart, au_sbtype(h_dentry->d_sb), AuDLNPair(dentry),
++ (unsigned long)h_ino, (unsigned long)ino);
++ ino = 0;
++ err = au_xino_write(sb, bstart, h_ino, /*ino*/0);
++ if (!err) {
++ iput(inode);
++ goto new_ino;
++ }
++
++ out_iput:
++ iput(inode);
++ inode = ERR_PTR(err);
++ out:
++ return inode;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex,
++ struct inode *inode)
++{
++ int err;
++
++ err = au_br_rdonly(au_sbr(sb, bindex));
++
++ /* pseudo-link after flushed may happen out of bounds */
++ if (!err
++ && inode
++ && au_ibstart(inode) <= bindex
++ && bindex <= au_ibend(inode)) {
++ /*
++ * permission check is unnecessary since vfsub routine
++ * will be called later
++ */
++ struct inode *hi = au_h_iptr(inode, bindex);
++ if (hi)
++ err = IS_IMMUTABLE(hi) ? -EROFS : 0;
++ }
++
++ return err;
++}
++
++int au_test_h_perm(struct inode *h_inode, int mask)
++{
++ if (!current->fsuid)
++ return 0;
++ return inode_permission(h_inode, mask);
++}
++
++int au_test_h_perm_sio(struct inode *h_inode, int mask)
++{
++ if (au_test_nfs(h_inode->i_sb)
++ && (mask & MAY_WRITE)
++ && S_ISDIR(h_inode->i_mode))
++ mask |= MAY_READ; /* force permission check */
++ return au_test_h_perm(h_inode, mask);
++}
+diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h
+new file mode 100644
+index 0000000..1c5559b
+--- /dev/null
++++ b/fs/aufs/inode.h
+@@ -0,0 +1,497 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * inode operations
++ */
++
++#ifndef __AUFS_INODE_H__
++#define __AUFS_INODE_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/inotify.h>
++#include <linux/aufs_type.h>
++#include "rwsem.h"
++
++struct vfsmount;
++
++struct au_hinotify {
++#ifdef CONFIG_AUFS_HINOTIFY
++ struct inotify_watch hin_watch;
++ struct inode *hin_aufs_inode; /* no get/put */
++#endif
++};
++
++struct au_hinode {
++ struct inode *hi_inode;
++ aufs_bindex_t hi_id;
++#ifdef CONFIG_AUFS_HINOTIFY
++ struct au_hinotify *hi_notify;
++#endif
++
++ /* reference to the copied-up whiteout with get/put */
++ struct dentry *hi_whdentry;
++};
++
++struct au_vdir;
++struct au_iinfo {
++ atomic_t ii_generation;
++ struct super_block *ii_hsb1; /* no get/put */
++
++ struct au_rwsem ii_rwsem;
++ aufs_bindex_t ii_bstart, ii_bend;
++ __u32 ii_higen;
++ struct au_hinode *ii_hinode;
++ struct au_vdir *ii_vdir;
++};
++
++struct au_icntnr {
++ struct au_iinfo iinfo;
++ struct inode vfs_inode;
++};
++
++/* au_pin flags */
++#define AuPin_DI_LOCKED 1
++#define AuPin_MNT_WRITE (1 << 1)
++#define au_ftest_pin(flags, name) ((flags) & AuPin_##name)
++#define au_fset_pin(flags, name) { (flags) |= AuPin_##name; }
++#define au_fclr_pin(flags, name) { (flags) &= ~AuPin_##name; }
++
++struct au_pin {
++ /* input */
++ struct dentry *dentry;
++ unsigned int udba;
++ unsigned char lsc_di, lsc_hi, flags;
++ aufs_bindex_t bindex;
++
++ /* output */
++ struct dentry *parent;
++ struct au_hinode *hdir;
++ struct vfsmount *h_mnt;
++};
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct au_iinfo *au_ii(struct inode *inode)
++{
++ struct au_iinfo *iinfo;
++
++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo);
++ if (iinfo->ii_hinode)
++ return iinfo;
++ return NULL; /* debugging bad_inode case */
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* inode.c */
++struct inode *au_igrab(struct inode *inode);
++int au_refresh_hinode_self(struct inode *inode, int do_attr);
++int au_refresh_hinode(struct inode *inode, struct dentry *dentry);
++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ unsigned int d_type, ino_t *ino);
++struct inode *au_new_inode(struct dentry *dentry, int must_new);
++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex,
++ struct inode *inode);
++int au_test_h_perm(struct inode *h_inode, int mask);
++int au_test_h_perm_sio(struct inode *h_inode, int mask);
++
++static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex,
++ ino_t h_ino, unsigned int d_type, ino_t *ino)
++{
++#ifdef CONFIG_AUFS_SHWH
++ return au_ino(sb, bindex, h_ino, d_type, ino);
++#else
++ return 0;
++#endif
++}
++
++/* i_op.c */
++extern struct inode_operations aufs_iop, aufs_symlink_iop, aufs_dir_iop;
++
++/* au_wr_dir flags */
++#define AuWrDir_ADD_ENTRY 1
++#define AuWrDir_ISDIR (1 << 1)
++#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name)
++#define au_fset_wrdir(flags, name) { (flags) |= AuWrDir_##name; }
++#define au_fclr_wrdir(flags, name) { (flags) &= ~AuWrDir_##name; }
++
++struct au_wr_dir_args {
++ aufs_bindex_t force_btgt;
++ unsigned char flags;
++};
++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry,
++ struct au_wr_dir_args *args);
++
++struct dentry *au_pinned_h_parent(struct au_pin *pin);
++void au_pin_init(struct au_pin *pin, struct dentry *dentry,
++ aufs_bindex_t bindex, int lsc_di, int lsc_hi,
++ unsigned int udba, unsigned char flags);
++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int udba, unsigned char flags) __must_check;
++int au_do_pin(struct au_pin *pin) __must_check;
++void au_unpin(struct au_pin *pin);
++
++/* i_op_add.c */
++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent, int isdir);
++int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev);
++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname);
++int aufs_create(struct inode *dir, struct dentry *dentry, int mode,
++ struct nameidata *nd);
++int aufs_link(struct dentry *src_dentry, struct inode *dir,
++ struct dentry *dentry);
++int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
++
++/* i_op_del.c */
++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup);
++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent, int isdir);
++int aufs_unlink(struct inode *dir, struct dentry *dentry);
++int aufs_rmdir(struct inode *dir, struct dentry *dentry);
++
++/* i_op_ren.c */
++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt);
++int aufs_rename(struct inode *src_dir, struct dentry *src_dentry,
++ struct inode *dir, struct dentry *dentry);
++
++/* iinfo.c */
++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex);
++void au_hiput(struct au_hinode *hinode);
++void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex);
++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_wh);
++unsigned int au_hi_flags(struct inode *inode, int isdir);
++
++/* hinode flags */
++#define AuHi_XINO 1
++#define AuHi_HINOTIFY (1 << 1)
++#define au_ftest_hi(flags, name) ((flags) & AuHi_##name)
++#define au_fset_hi(flags, name) { (flags) |= AuHi_##name; }
++#define au_fclr_hi(flags, name) { (flags) &= ~AuHi_##name; }
++
++#ifndef CONFIG_AUFS_HINOTIFY
++#undef AuHi_HINOTIFY
++#define AuHi_HINOTIFY 0
++#endif
++
++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
++ struct inode *h_inode, unsigned int flags);
++
++void au_update_iigen(struct inode *inode);
++void au_update_brange(struct inode *inode, int do_put_zero);
++
++int au_iinfo_init(struct inode *inode);
++void au_iinfo_fin(struct inode *inode);
++int au_ii_realloc(struct au_iinfo *iinfo, int nbr);
++
++/* plink.c */
++void au_plink_block_maintain(struct super_block *sb);
++#ifdef CONFIG_AUFS_DEBUG
++void au_plink_list(struct super_block *sb);
++#else
++static inline void au_plink_list(struct super_block *sb)
++{
++ /* nothing */
++}
++#endif
++int au_plink_test(struct inode *inode);
++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex);
++void au_plink_append(struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_dentry);
++void au_plink_put(struct super_block *sb);
++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id);
++long au_plink_ioctl(struct file *file, unsigned int cmd);
++
++/* ---------------------------------------------------------------------- */
++
++/* lock subclass for iinfo */
++enum {
++ AuLsc_II_CHILD, /* child first */
++ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hinotify */
++ AuLsc_II_CHILD3, /* copyup dirs */
++ AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */
++ AuLsc_II_PARENT2,
++ AuLsc_II_PARENT3, /* copyup dirs */
++ AuLsc_II_NEW_CHILD
++};
++
++/*
++ * ii_read_lock_child, ii_write_lock_child,
++ * ii_read_lock_child2, ii_write_lock_child2,
++ * ii_read_lock_child3, ii_write_lock_child3,
++ * ii_read_lock_parent, ii_write_lock_parent,
++ * ii_read_lock_parent2, ii_write_lock_parent2,
++ * ii_read_lock_parent3, ii_write_lock_parent3,
++ * ii_read_lock_new_child, ii_write_lock_new_child,
++ */
++#define AuReadLockFunc(name, lsc) \
++static inline void ii_read_lock_##name(struct inode *i) \
++{ \
++ au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \
++}
++
++#define AuWriteLockFunc(name, lsc) \
++static inline void ii_write_lock_##name(struct inode *i) \
++{ \
++ au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \
++}
++
++#define AuRWLockFuncs(name, lsc) \
++ AuReadLockFunc(name, lsc) \
++ AuWriteLockFunc(name, lsc)
++
++AuRWLockFuncs(child, CHILD);
++AuRWLockFuncs(child2, CHILD2);
++AuRWLockFuncs(child3, CHILD3);
++AuRWLockFuncs(parent, PARENT);
++AuRWLockFuncs(parent2, PARENT2);
++AuRWLockFuncs(parent3, PARENT3);
++AuRWLockFuncs(new_child, NEW_CHILD);
++
++#undef AuReadLockFunc
++#undef AuWriteLockFunc
++#undef AuRWLockFuncs
++
++/*
++ * ii_read_unlock, ii_write_unlock, ii_downgrade_lock
++ */
++AuSimpleUnlockRwsemFuncs(ii, struct inode *i, &au_ii(i)->ii_rwsem);
++
++#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem)
++#define IiMustAnyLock(i) AuRwMustAnyLock(&au_ii(i)->ii_rwsem)
++#define IiMustWriteLock(i) AuRwMustWriteLock(&au_ii(i)->ii_rwsem)
++
++/* ---------------------------------------------------------------------- */
++
++static inline unsigned int au_iigen(struct inode *inode)
++{
++ return atomic_read(&au_ii(inode)->ii_generation);
++}
++
++/* tiny test for inode number */
++/* tmpfs generation is too rough */
++static inline int au_test_higen(struct inode *inode, struct inode *h_inode)
++{
++ struct au_iinfo *iinfo;
++
++ iinfo = au_ii(inode);
++ AuRwMustAnyLock(&iinfo->ii_rwsem);
++ return !(iinfo->ii_hsb1 == h_inode->i_sb
++ && iinfo->ii_higen == h_inode->i_generation);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static inline aufs_bindex_t au_ii_br_id(struct inode *inode,
++ aufs_bindex_t bindex)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_hinode[0 + bindex].hi_id;
++}
++
++static inline aufs_bindex_t au_ibstart(struct inode *inode)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_bstart;
++}
++
++static inline aufs_bindex_t au_ibend(struct inode *inode)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_bend;
++}
++
++static inline struct au_vdir *au_ivdir(struct inode *inode)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_vdir;
++}
++
++static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_hinode[0 + bindex].hi_whdentry;
++}
++
++static inline void au_set_ibend(struct inode *inode, aufs_bindex_t bindex)
++{
++ IiMustWriteLock(inode);
++ au_ii(inode)->ii_bend = bindex;
++}
++
++static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir)
++{
++ IiMustWriteLock(inode);
++ au_ii(inode)->ii_vdir = vdir;
++}
++
++static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex)
++{
++ IiMustAnyLock(inode);
++ return au_ii(inode)->ii_hinode + bindex;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct dentry *au_pinned_parent(struct au_pin *pin)
++{
++ if (pin)
++ return pin->parent;
++ return NULL;
++}
++
++static inline struct inode *au_pinned_h_dir(struct au_pin *pin)
++{
++ if (pin && pin->hdir)
++ return pin->hdir->hi_inode;
++ return NULL;
++}
++
++static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin)
++{
++ if (pin)
++ return pin->hdir;
++ return NULL;
++}
++
++static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry)
++{
++ if (pin)
++ pin->dentry = dentry;
++}
++
++static inline void au_pin_set_parent_lflag(struct au_pin *pin,
++ unsigned char lflag)
++{
++ if (pin) {
++ /* dirty macros require brackets */
++ if (lflag) {
++ au_fset_pin(pin->flags, DI_LOCKED);
++ } else {
++ au_fclr_pin(pin->flags, DI_LOCKED);
++ }
++ }
++}
++
++static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent)
++{
++ if (pin) {
++ dput(pin->parent);
++ pin->parent = dget(parent);
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_HINOTIFY
++/* hinotify.c */
++int au_hin_alloc(struct au_hinode *hinode, struct inode *inode,
++ struct inode *h_inode);
++void au_hin_free(struct au_hinode *hinode);
++void au_hin_ctl(struct au_hinode *hinode, int do_set);
++void au_reset_hinotify(struct inode *inode, unsigned int flags);
++
++int __init au_hinotify_init(void);
++void au_hinotify_fin(void);
++
++static inline
++void au_hin_init(struct au_hinode *hinode, struct au_hinotify *val)
++{
++ hinode->hi_notify = val;
++}
++
++static inline void au_iigen_dec(struct inode *inode)
++{
++ atomic_dec_return(&au_ii(inode)->ii_generation);
++}
++
++#else
++static inline
++int au_hin_alloc(struct au_hinode *hinode __maybe_unused,
++ struct inode *inode __maybe_unused,
++ struct inode *h_inode __maybe_unused)
++{
++ return -EOPNOTSUPP;
++}
++
++static inline void au_hin_free(struct au_hinode *hinode __maybe_unused)
++{
++ /* nothing */
++}
++
++static inline void au_hin_ctl(struct au_hinode *hinode __maybe_unused,
++ int do_set __maybe_unused)
++{
++ /* nothing */
++}
++
++static inline void au_reset_hinotify(struct inode *inode __maybe_unused,
++ unsigned int flags __maybe_unused)
++{
++ /* nothing */
++}
++
++static inline int au_hinotify_init(void)
++{
++ return 0;
++}
++
++#define au_hinotify_fin() do {} while (0)
++
++static inline
++void au_hin_init(struct au_hinode *hinode __maybe_unused,
++ struct au_hinotify *val __maybe_unused)
++{
++ /* empty */
++}
++#endif /* CONFIG_AUFS_HINOTIFY */
++
++static inline void au_hin_suspend(struct au_hinode *hdir)
++{
++ au_hin_ctl(hdir, /*do_set*/0);
++}
++
++static inline void au_hin_resume(struct au_hinode *hdir)
++{
++ au_hin_ctl(hdir, /*do_set*/1);
++}
++
++static inline void au_hin_imtx_lock(struct au_hinode *hdir)
++{
++ mutex_lock(&hdir->hi_inode->i_mutex);
++ au_hin_suspend(hdir);
++}
++
++static inline void au_hin_imtx_lock_nested(struct au_hinode *hdir,
++ unsigned int sc __maybe_unused)
++{
++ mutex_lock_nested(&hdir->hi_inode->i_mutex, sc);
++ au_hin_suspend(hdir);
++}
++
++static inline void au_hin_imtx_unlock(struct au_hinode *hdir)
++{
++ au_hin_resume(hdir);
++ mutex_unlock(&hdir->hi_inode->i_mutex);
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_INODE_H__ */
+diff --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c
+new file mode 100644
+index 0000000..012361a
+--- /dev/null
++++ b/fs/aufs/ioctl.c
+@@ -0,0 +1,47 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * ioctl
++ * plink-management and readdir in userspace.
++ */
++
++#include "aufs.h"
++
++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ long err;
++
++ switch (cmd) {
++ case AUFS_CTL_PLINK_MAINT:
++ case AUFS_CTL_PLINK_CLEAN:
++ err = au_plink_ioctl(file, cmd);
++ break;
++
++ case AUFS_CTL_RDU:
++ case AUFS_CTL_RDU_INO:
++ err = au_rdu_ioctl(file, cmd, arg);
++ break;
++
++ default:
++ err = -EINVAL;
++ }
++
++ AuTraceErr(err);
++ return err;
++}
+diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c
+new file mode 100644
+index 0000000..277011f
+--- /dev/null
++++ b/fs/aufs/loop.c
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * support for loopback block device as a branch
++ */
++
++#include <linux/loop.h>
++#include "aufs.h"
++
++/*
++ * test if two lower dentries have overlapping branches.
++ */
++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_d1,
++ struct dentry *h_d2)
++{
++ struct inode *h_inode;
++ struct loop_device *l;
++
++ h_inode = h_d1->d_inode;
++ if (MAJOR(h_inode->i_sb->s_dev) != LOOP_MAJOR)
++ return 0;
++
++ l = h_inode->i_sb->s_bdev->bd_disk->private_data;
++ h_d1 = l->lo_backing_file->f_dentry;
++ /* h_d1 can be local NFS. in this case aufs cannot detect the loop */
++ if (unlikely(h_d1->d_sb == sb))
++ return 1;
++ return !!au_test_subdir(h_d1, h_d2);
++}
++
++/* true if a kernel thread named 'loop[0-9].*' accesses a file */
++int au_test_loopback_kthread(void)
++{
++ const char c = current->comm[4];
++
++ return current->mm == NULL
++ && '0' <= c && c <= '9'
++ && strncmp(current->comm, "loop", 4) == 0;
++}
+diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h
+new file mode 100644
+index 0000000..5a0fd87
+--- /dev/null
++++ b/fs/aufs/loop.h
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * support for loopback mount as a branch
++ */
++
++#ifndef __AUFS_LOOP_H__
++#define __AUFS_LOOP_H__
++
++#ifdef __KERNEL__
++
++struct dentry;
++struct super_block;
++
++#ifdef CONFIG_AUFS_BDEV_LOOP
++/* loop.c */
++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_d1,
++ struct dentry *h_d2);
++int au_test_loopback_kthread(void);
++#else
++static inline
++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_d1,
++ struct dentry *h_d2)
++{
++ return 0;
++}
++
++static inline int au_test_loopback_kthread(void)
++{
++ return 0;
++}
++#endif /* BLK_DEV_LOOP */
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_LOOP_H__ */
+diff --git a/fs/aufs/magic.mk b/fs/aufs/magic.mk
+new file mode 100644
+index 0000000..83d613c
+--- /dev/null
++++ b/fs/aufs/magic.mk
+@@ -0,0 +1,52 @@
++
++# defined in ${srctree}/fs/fuse/inode.c
++# tristate
++ifdef CONFIG_FUSE_FS
++ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546
++endif
++
++# defined in ${srctree}/fs/ocfs2/ocfs2_fs.h
++# tristate
++ifdef CONFIG_OCFS2_FS
++ccflags-y += -DOCFS2_SUPER_MAGIC=0x7461636f
++endif
++
++# defined in ${srctree}/fs/ocfs2/dlm/userdlm.h
++# tristate
++ifdef CONFIG_OCFS2_FS_O2CB
++ccflags-y += -DDLMFS_MAGIC=0x76a9f425
++endif
++
++# defined in ${srctree}/fs/ramfs/inode.c
++# always true
++ccflags-y += -DRAMFS_MAGIC=0x858458f6
++
++# defined in ${srctree}/fs/cifs/cifsfs.c
++# tristate
++ifdef CONFIG_CIFS_FS
++ccflags-y += -DCIFS_MAGIC_NUMBER=0xFF534D42
++endif
++
++# defined in ${srctree}/fs/xfs/xfs_sb.h
++# tristate
++ifdef CONFIG_XFS_FS
++ccflags-y += -DXFS_SB_MAGIC=0x58465342
++endif
++
++# defined in ${srctree}/fs/configfs/mount.c
++# tristate
++ifdef CONFIG_CONFIGFS_FS
++ccflags-y += -DCONFIGFS_MAGIC=0x62656570
++endif
++
++# defined in ${srctree}/fs/9p/v9fs.h
++# tristate
++ifdef CONFIG_9P_FS
++ccflags-y += -DV9FS_MAGIC=0x01021997
++endif
++
++# defined in ${srctree}/fs/ubifs/ubifs.h
++# tristate
++ifdef CONFIG_UBIFS_FS
++ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905
++endif
+diff --git a/fs/aufs/module.c b/fs/aufs/module.c
+new file mode 100644
+index 0000000..dbfb2c4
+--- /dev/null
++++ b/fs/aufs/module.c
+@@ -0,0 +1,173 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * module global variables and operations
++ */
++
++#include <linux/module.h>
++#include <linux/seq_file.h>
++#include "aufs.h"
++
++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp)
++{
++ if (new_sz <= nused)
++ return p;
++
++ p = krealloc(p, new_sz, gfp);
++ if (p)
++ memset(p + nused, 0, new_sz - nused);
++ return p;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * aufs caches
++ */
++struct kmem_cache *au_cachep[AuCache_Last];
++static int __init au_cache_init(void)
++{
++ au_cachep[AuCache_DINFO] = AuCache(au_dinfo);
++ if (au_cachep[AuCache_DINFO])
++ au_cachep[AuCache_ICNTNR] = AuCache(au_icntnr);
++ if (au_cachep[AuCache_ICNTNR])
++ au_cachep[AuCache_FINFO] = AuCache(au_finfo);
++ if (au_cachep[AuCache_FINFO])
++ au_cachep[AuCache_VDIR] = AuCache(au_vdir);
++ if (au_cachep[AuCache_VDIR])
++ au_cachep[AuCache_DEHSTR] = AuCache(au_vdir_dehstr);
++ if (au_cachep[AuCache_DEHSTR])
++ return 0;
++
++ return -ENOMEM;
++}
++
++static void au_cache_fin(void)
++{
++ int i;
++ for (i = 0; i < AuCache_Last; i++)
++ if (au_cachep[i]) {
++ kmem_cache_destroy(au_cachep[i]);
++ au_cachep[i] = NULL;
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_dir_roflags;
++
++/*
++ * functions for module interface.
++ */
++MODULE_LICENSE("GPL");
++/* MODULE_LICENSE("GPL v2"); */
++MODULE_AUTHOR("Junjiro R. Okajima <aufs-users@lists.sourceforge.net>");
++MODULE_DESCRIPTION(AUFS_NAME
++ " -- Advanced multi layered unification filesystem");
++MODULE_VERSION(AUFS_VERSION);
++
++/* it should be 'byte', but param_set_byte() prints it by "%c" */
++short aufs_nwkq = AUFS_NWKQ_DEF;
++MODULE_PARM_DESC(nwkq, "the number of workqueue thread, " AUFS_WKQ_NAME);
++module_param_named(nwkq, aufs_nwkq, short, S_IRUGO);
++
++/* this module parameter has no meaning when SYSFS is disabled */
++int sysaufs_brs = 1;
++MODULE_PARM_DESC(brs, "use <sysfs>/fs/aufs/si_*/brN");
++module_param_named(brs, sysaufs_brs, int, S_IRUGO);
++
++/* ---------------------------------------------------------------------- */
++
++static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */
++
++int au_seq_path(struct seq_file *seq, struct path *path)
++{
++ return seq_path(seq, path, au_esc_chars);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int __init aufs_init(void)
++{
++ int err, i;
++ char *p;
++
++ p = au_esc_chars;
++ for (i = 1; i <= ' '; i++)
++ *p++ = i;
++ *p++ = '\\';
++ *p++ = '\x7f';
++ *p = 0;
++
++ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE);
++
++ sysaufs_brs_init();
++ au_debug_init();
++
++ err = -EINVAL;
++ if (unlikely(aufs_nwkq <= 0))
++ goto out;
++
++ err = sysaufs_init();
++ if (unlikely(err))
++ goto out;
++ err = au_wkq_init();
++ if (unlikely(err))
++ goto out_sysaufs;
++ err = au_hinotify_init();
++ if (unlikely(err))
++ goto out_wkq;
++ err = au_sysrq_init();
++ if (unlikely(err))
++ goto out_hin;
++ err = au_cache_init();
++ if (unlikely(err))
++ goto out_sysrq;
++ err = register_filesystem(&aufs_fs_type);
++ if (unlikely(err))
++ goto out_cache;
++ pr_info(AUFS_NAME " " AUFS_VERSION "\n");
++ goto out; /* success */
++
++ out_cache:
++ au_cache_fin();
++ out_sysrq:
++ au_sysrq_fin();
++ out_hin:
++ au_hinotify_fin();
++ out_wkq:
++ au_wkq_fin();
++ out_sysaufs:
++ sysaufs_fin();
++ out:
++ return err;
++}
++
++static void __exit aufs_exit(void)
++{
++ unregister_filesystem(&aufs_fs_type);
++ au_cache_fin();
++ au_sysrq_fin();
++ au_hinotify_fin();
++ au_wkq_fin();
++ sysaufs_fin();
++}
++
++module_init(aufs_init);
++module_exit(aufs_exit);
+diff --git a/fs/aufs/module.h b/fs/aufs/module.h
+new file mode 100644
+index 0000000..cea7bc7
+--- /dev/null
++++ b/fs/aufs/module.h
+@@ -0,0 +1,78 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * module initialization and module-global
++ */
++
++#ifndef __AUFS_MODULE_H__
++#define __AUFS_MODULE_H__
++
++#ifdef __KERNEL__
++
++#include <linux/slab.h>
++
++struct path;
++struct seq_file;
++
++/* module parameters */
++extern short aufs_nwkq;
++extern int sysaufs_brs;
++
++/* ---------------------------------------------------------------------- */
++
++extern int au_dir_roflags;
++
++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp);
++int au_seq_path(struct seq_file *seq, struct path *path);
++
++/* ---------------------------------------------------------------------- */
++
++/* kmem cache */
++enum {
++ AuCache_DINFO,
++ AuCache_ICNTNR,
++ AuCache_FINFO,
++ AuCache_VDIR,
++ AuCache_DEHSTR,
++#ifdef CONFIG_AUFS_HINOTIFY
++ AuCache_HINOTIFY,
++#endif
++ AuCache_Last
++};
++
++#define AuCache(type) KMEM_CACHE(type, SLAB_RECLAIM_ACCOUNT)
++
++extern struct kmem_cache *au_cachep[];
++
++#define AuCacheFuncs(name, index) \
++static inline void *au_cache_alloc_##name(void) \
++{ return kmem_cache_alloc(au_cachep[AuCache_##index], GFP_NOFS); } \
++static inline void au_cache_free_##name(void *p) \
++{ kmem_cache_free(au_cachep[AuCache_##index], p); }
++
++AuCacheFuncs(dinfo, DINFO);
++AuCacheFuncs(icntnr, ICNTNR);
++AuCacheFuncs(finfo, FINFO);
++AuCacheFuncs(vdir, VDIR);
++AuCacheFuncs(dehstr, DEHSTR);
++
++/* ---------------------------------------------------------------------- */
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_MODULE_H__ */
+diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c
+new file mode 100644
+index 0000000..70f8be9
+--- /dev/null
++++ b/fs/aufs/opts.c
+@@ -0,0 +1,1543 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * mount options/flags
++ */
++
++#include <linux/file.h>
++#include <linux/namei.h>
++#include <linux/types.h> /* a distribution requires */
++#include <linux/parser.h>
++#include "aufs.h"
++
++/* ---------------------------------------------------------------------- */
++
++enum {
++ Opt_br,
++ Opt_add, Opt_del, Opt_mod, Opt_reorder, Opt_append, Opt_prepend,
++ Opt_idel, Opt_imod, Opt_ireorder,
++ Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, Opt_rendir,
++ Opt_rdblk_def, Opt_rdhash_def,
++ Opt_xino, Opt_zxino, Opt_noxino,
++ Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino,
++ Opt_trunc_xino_path, Opt_itrunc_xino,
++ Opt_trunc_xib, Opt_notrunc_xib,
++ Opt_shwh, Opt_noshwh,
++ Opt_plink, Opt_noplink, Opt_list_plink,
++ Opt_udba,
++ /* Opt_lock, Opt_unlock, */
++ Opt_cmd, Opt_cmd_args,
++ Opt_diropq_a, Opt_diropq_w,
++ Opt_warn_perm, Opt_nowarn_perm,
++ Opt_wbr_copyup, Opt_wbr_create,
++ Opt_refrof, Opt_norefrof,
++ Opt_verbose, Opt_noverbose,
++ Opt_sum, Opt_nosum, Opt_wsum,
++ Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err
++};
++
++static match_table_t options = {
++ {Opt_br, "br=%s"},
++ {Opt_br, "br:%s"},
++
++ {Opt_add, "add=%d:%s"},
++ {Opt_add, "add:%d:%s"},
++ {Opt_add, "ins=%d:%s"},
++ {Opt_add, "ins:%d:%s"},
++ {Opt_append, "append=%s"},
++ {Opt_append, "append:%s"},
++ {Opt_prepend, "prepend=%s"},
++ {Opt_prepend, "prepend:%s"},
++
++ {Opt_del, "del=%s"},
++ {Opt_del, "del:%s"},
++ /* {Opt_idel, "idel:%d"}, */
++ {Opt_mod, "mod=%s"},
++ {Opt_mod, "mod:%s"},
++ /* {Opt_imod, "imod:%d:%s"}, */
++
++ {Opt_dirwh, "dirwh=%d"},
++
++ {Opt_xino, "xino=%s"},
++ {Opt_noxino, "noxino"},
++ {Opt_trunc_xino, "trunc_xino"},
++ {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"},
++ {Opt_notrunc_xino, "notrunc_xino"},
++ {Opt_trunc_xino_path, "trunc_xino=%s"},
++ {Opt_itrunc_xino, "itrunc_xino=%d"},
++ /* {Opt_zxino, "zxino=%s"}, */
++ {Opt_trunc_xib, "trunc_xib"},
++ {Opt_notrunc_xib, "notrunc_xib"},
++
++ {Opt_plink, "plink"},
++ {Opt_noplink, "noplink"},
++#ifdef CONFIG_AUFS_DEBUG
++ {Opt_list_plink, "list_plink"},
++#endif
++
++ {Opt_udba, "udba=%s"},
++
++ {Opt_diropq_a, "diropq=always"},
++ {Opt_diropq_a, "diropq=a"},
++ {Opt_diropq_w, "diropq=whiteouted"},
++ {Opt_diropq_w, "diropq=w"},
++
++ {Opt_warn_perm, "warn_perm"},
++ {Opt_nowarn_perm, "nowarn_perm"},
++
++ /* keep them temporary */
++ {Opt_ignore_silent, "coo=%s"},
++ {Opt_ignore_silent, "nodlgt"},
++ {Opt_ignore_silent, "nodirperm1"},
++ {Opt_ignore_silent, "clean_plink"},
++
++#ifdef CONFIG_AUFS_SHWH
++ {Opt_shwh, "shwh"},
++#endif
++ {Opt_noshwh, "noshwh"},
++
++ {Opt_rendir, "rendir=%d"},
++
++ {Opt_refrof, "refrof"},
++ {Opt_norefrof, "norefrof"},
++
++ {Opt_verbose, "verbose"},
++ {Opt_verbose, "v"},
++ {Opt_noverbose, "noverbose"},
++ {Opt_noverbose, "quiet"},
++ {Opt_noverbose, "q"},
++ {Opt_noverbose, "silent"},
++
++ {Opt_sum, "sum"},
++ {Opt_nosum, "nosum"},
++ {Opt_wsum, "wsum"},
++
++ {Opt_rdcache, "rdcache=%d"},
++ {Opt_rdblk, "rdblk=%d"},
++ {Opt_rdblk_def, "rdblk=def"},
++ {Opt_rdhash, "rdhash=%d"},
++ {Opt_rdhash_def, "rdhash=def"},
++
++ {Opt_wbr_create, "create=%s"},
++ {Opt_wbr_create, "create_policy=%s"},
++ {Opt_wbr_copyup, "cpup=%s"},
++ {Opt_wbr_copyup, "copyup=%s"},
++ {Opt_wbr_copyup, "copyup_policy=%s"},
++
++ /* internal use for the scripts */
++ {Opt_ignore_silent, "si=%s"},
++
++ {Opt_br, "dirs=%s"},
++ {Opt_ignore, "debug=%d"},
++ {Opt_ignore, "delete=whiteout"},
++ {Opt_ignore, "delete=all"},
++ {Opt_ignore, "imap=%s"},
++
++ {Opt_err, NULL}
++};
++
++/* ---------------------------------------------------------------------- */
++
++static const char *au_parser_pattern(int val, struct match_token *token)
++{
++ while (token->pattern) {
++ if (token->token == val)
++ return token->pattern;
++ token++;
++ }
++ BUG();
++ return "??";
++}
++
++/* ---------------------------------------------------------------------- */
++
++static match_table_t brperms = {
++ {AuBrPerm_RO, AUFS_BRPERM_RO},
++ {AuBrPerm_RR, AUFS_BRPERM_RR},
++ {AuBrPerm_RW, AUFS_BRPERM_RW},
++
++ {AuBrPerm_ROWH, AUFS_BRPERM_ROWH},
++ {AuBrPerm_RRWH, AUFS_BRPERM_RRWH},
++ {AuBrPerm_RWNoLinkWH, AUFS_BRPERM_RWNLWH},
++
++ {AuBrPerm_ROWH, "nfsro"},
++ {AuBrPerm_RO, NULL}
++};
++
++static int br_perm_val(char *perm)
++{
++ int val;
++ substring_t args[MAX_OPT_ARGS];
++
++ val = match_token(perm, brperms, args);
++ return val;
++}
++
++const char *au_optstr_br_perm(int brperm)
++{
++ return au_parser_pattern(brperm, (void *)brperms);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static match_table_t udbalevel = {
++ {AuOpt_UDBA_REVAL, "reval"},
++ {AuOpt_UDBA_NONE, "none"},
++#ifdef CONFIG_AUFS_HINOTIFY
++ {AuOpt_UDBA_HINOTIFY, "inotify"},
++#endif
++ {-1, NULL}
++};
++
++static int udba_val(char *str)
++{
++ substring_t args[MAX_OPT_ARGS];
++
++ return match_token(str, udbalevel, args);
++}
++
++const char *au_optstr_udba(int udba)
++{
++ return au_parser_pattern(udba, (void *)udbalevel);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static match_table_t au_wbr_create_policy = {
++ {AuWbrCreate_TDP, "tdp"},
++ {AuWbrCreate_TDP, "top-down-parent"},
++ {AuWbrCreate_RR, "rr"},
++ {AuWbrCreate_RR, "round-robin"},
++ {AuWbrCreate_MFS, "mfs"},
++ {AuWbrCreate_MFS, "most-free-space"},
++ {AuWbrCreate_MFSV, "mfs:%d"},
++ {AuWbrCreate_MFSV, "most-free-space:%d"},
++
++ {AuWbrCreate_MFSRR, "mfsrr:%d"},
++ {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"},
++ {AuWbrCreate_PMFS, "pmfs"},
++ {AuWbrCreate_PMFSV, "pmfs:%d"},
++
++ {-1, NULL}
++};
++
++/*
++ * cf. linux/lib/parser.c and cmdline.c
++ * gave up calling memparse() since it uses simple_strtoull() instead of
++ * strict_...().
++ */
++static int au_match_ull(substring_t *s, unsigned long long *result)
++{
++ int err;
++ unsigned int len;
++ char a[32];
++
++ err = -ERANGE;
++ len = s->to - s->from;
++ if (len + 1 <= sizeof(a)) {
++ memcpy(a, s->from, len);
++ a[len] = '\0';
++ err = strict_strtoull(a, 0, result);
++ }
++ return err;
++}
++
++static int au_wbr_mfs_wmark(substring_t *arg, char *str,
++ struct au_opt_wbr_create *create)
++{
++ int err;
++ unsigned long long ull;
++
++ err = 0;
++ if (!au_match_ull(arg, &ull))
++ create->mfsrr_watermark = ull;
++ else {
++ AuErr("bad integer in %s\n", str);
++ err = -EINVAL;
++ }
++
++ return err;
++}
++
++static int au_wbr_mfs_sec(substring_t *arg, char *str,
++ struct au_opt_wbr_create *create)
++{
++ int n, err;
++
++ err = 0;
++ if (!match_int(arg, &n) && 0 <= n)
++ create->mfs_second = n;
++ else {
++ AuErr("bad integer in %s\n", str);
++ err = -EINVAL;
++ }
++
++ return err;
++}
++
++static int au_wbr_create_val(char *str, struct au_opt_wbr_create *create)
++{
++ int err, e;
++ substring_t args[MAX_OPT_ARGS];
++
++ err = match_token(str, au_wbr_create_policy, args);
++ create->wbr_create = err;
++ switch (err) {
++ case AuWbrCreate_MFSRRV:
++ e = au_wbr_mfs_wmark(&args[0], str, create);
++ if (!e)
++ e = au_wbr_mfs_sec(&args[1], str, create);
++ if (unlikely(e))
++ err = e;
++ break;
++ case AuWbrCreate_MFSRR:
++ e = au_wbr_mfs_wmark(&args[0], str, create);
++ if (unlikely(e)) {
++ err = e;
++ break;
++ }
++ /*FALLTHROUGH*/
++ case AuWbrCreate_MFS:
++ case AuWbrCreate_PMFS:
++ create->mfs_second = AUFS_MFS_SECOND_DEF;
++ break;
++ case AuWbrCreate_MFSV:
++ case AuWbrCreate_PMFSV:
++ e = au_wbr_mfs_sec(&args[0], str, create);
++ if (unlikely(e))
++ err = e;
++ break;
++ }
++
++ return err;
++}
++
++const char *au_optstr_wbr_create(int wbr_create)
++{
++ return au_parser_pattern(wbr_create, (void *)au_wbr_create_policy);
++}
++
++static match_table_t au_wbr_copyup_policy = {
++ {AuWbrCopyup_TDP, "tdp"},
++ {AuWbrCopyup_TDP, "top-down-parent"},
++ {AuWbrCopyup_BUP, "bup"},
++ {AuWbrCopyup_BUP, "bottom-up-parent"},
++ {AuWbrCopyup_BU, "bu"},
++ {AuWbrCopyup_BU, "bottom-up"},
++ {-1, NULL}
++};
++
++static int au_wbr_copyup_val(char *str)
++{
++ substring_t args[MAX_OPT_ARGS];
++
++ return match_token(str, au_wbr_copyup_policy, args);
++}
++
++const char *au_optstr_wbr_copyup(int wbr_copyup)
++{
++ return au_parser_pattern(wbr_copyup, (void *)au_wbr_copyup_policy);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
++
++static void dump_opts(struct au_opts *opts)
++{
++#ifdef CONFIG_AUFS_DEBUG
++ /* reduce stack space */
++ union {
++ struct au_opt_add *add;
++ struct au_opt_del *del;
++ struct au_opt_mod *mod;
++ struct au_opt_xino *xino;
++ struct au_opt_xino_itrunc *xino_itrunc;
++ struct au_opt_wbr_create *create;
++ } u;
++ struct au_opt *opt;
++
++ opt = opts->opt;
++ while (opt->type != Opt_tail) {
++ switch (opt->type) {
++ case Opt_add:
++ u.add = &opt->add;
++ AuDbg("add {b%d, %s, 0x%x, %p}\n",
++ u.add->bindex, u.add->pathname, u.add->perm,
++ u.add->path.dentry);
++ break;
++ case Opt_del:
++ case Opt_idel:
++ u.del = &opt->del;
++ AuDbg("del {%s, %p}\n",
++ u.del->pathname, u.del->h_path.dentry);
++ break;
++ case Opt_mod:
++ case Opt_imod:
++ u.mod = &opt->mod;
++ AuDbg("mod {%s, 0x%x, %p}\n",
++ u.mod->path, u.mod->perm, u.mod->h_root);
++ break;
++ case Opt_append:
++ u.add = &opt->add;
++ AuDbg("append {b%d, %s, 0x%x, %p}\n",
++ u.add->bindex, u.add->pathname, u.add->perm,
++ u.add->path.dentry);
++ break;
++ case Opt_prepend:
++ u.add = &opt->add;
++ AuDbg("prepend {b%d, %s, 0x%x, %p}\n",
++ u.add->bindex, u.add->pathname, u.add->perm,
++ u.add->path.dentry);
++ break;
++ case Opt_dirwh:
++ AuDbg("dirwh %d\n", opt->dirwh);
++ break;
++ case Opt_rdcache:
++ AuDbg("rdcache %d\n", opt->rdcache);
++ break;
++ case Opt_rdblk:
++ AuDbg("rdblk %u\n", opt->rdblk);
++ break;
++ case Opt_rdblk_def:
++ AuDbg("rdblk_def\n");
++ break;
++ case Opt_rdhash:
++ AuDbg("rdhash %u\n", opt->rdhash);
++ break;
++ case Opt_rdhash_def:
++ AuDbg("rdhash_def\n");
++ break;
++ case Opt_xino:
++ u.xino = &opt->xino;
++ AuDbg("xino {%s %.*s}\n",
++ u.xino->path,
++ AuDLNPair(u.xino->file->f_dentry));
++ break;
++ case Opt_trunc_xino:
++ AuLabel(trunc_xino);
++ break;
++ case Opt_notrunc_xino:
++ AuLabel(notrunc_xino);
++ break;
++ case Opt_trunc_xino_path:
++ case Opt_itrunc_xino:
++ u.xino_itrunc = &opt->xino_itrunc;
++ AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex);
++ break;
++
++ case Opt_noxino:
++ AuLabel(noxino);
++ break;
++ case Opt_trunc_xib:
++ AuLabel(trunc_xib);
++ break;
++ case Opt_notrunc_xib:
++ AuLabel(notrunc_xib);
++ break;
++ case Opt_shwh:
++ AuLabel(shwh);
++ break;
++ case Opt_noshwh:
++ AuLabel(noshwh);
++ break;
++ case Opt_plink:
++ AuLabel(plink);
++ break;
++ case Opt_noplink:
++ AuLabel(noplink);
++ break;
++ case Opt_list_plink:
++ AuLabel(list_plink);
++ break;
++ case Opt_udba:
++ AuDbg("udba %d, %s\n",
++ opt->udba, au_optstr_udba(opt->udba));
++ break;
++ case Opt_diropq_a:
++ AuLabel(diropq_a);
++ break;
++ case Opt_diropq_w:
++ AuLabel(diropq_w);
++ break;
++ case Opt_warn_perm:
++ AuLabel(warn_perm);
++ break;
++ case Opt_nowarn_perm:
++ AuLabel(nowarn_perm);
++ break;
++ case Opt_refrof:
++ AuLabel(refrof);
++ break;
++ case Opt_norefrof:
++ AuLabel(norefrof);
++ break;
++ case Opt_verbose:
++ AuLabel(verbose);
++ break;
++ case Opt_noverbose:
++ AuLabel(noverbose);
++ break;
++ case Opt_sum:
++ AuLabel(sum);
++ break;
++ case Opt_nosum:
++ AuLabel(nosum);
++ break;
++ case Opt_wsum:
++ AuLabel(wsum);
++ break;
++ case Opt_wbr_create:
++ u.create = &opt->wbr_create;
++ AuDbg("create %d, %s\n", u.create->wbr_create,
++ au_optstr_wbr_create(u.create->wbr_create));
++ switch (u.create->wbr_create) {
++ case AuWbrCreate_MFSV:
++ case AuWbrCreate_PMFSV:
++ AuDbg("%d sec\n", u.create->mfs_second);
++ break;
++ case AuWbrCreate_MFSRR:
++ AuDbg("%llu watermark\n",
++ u.create->mfsrr_watermark);
++ break;
++ case AuWbrCreate_MFSRRV:
++ AuDbg("%llu watermark, %d sec\n",
++ u.create->mfsrr_watermark,
++ u.create->mfs_second);
++ break;
++ }
++ break;
++ case Opt_wbr_copyup:
++ AuDbg("copyup %d, %s\n", opt->wbr_copyup,
++ au_optstr_wbr_copyup(opt->wbr_copyup));
++ break;
++ default:
++ BUG();
++ }
++ opt++;
++ }
++#endif
++}
++
++void au_opts_free(struct au_opts *opts)
++{
++ struct au_opt *opt;
++
++ opt = opts->opt;
++ while (opt->type != Opt_tail) {
++ switch (opt->type) {
++ case Opt_add:
++ case Opt_append:
++ case Opt_prepend:
++ path_put(&opt->add.path);
++ break;
++ case Opt_del:
++ case Opt_idel:
++ path_put(&opt->del.h_path);
++ break;
++ case Opt_mod:
++ case Opt_imod:
++ dput(opt->mod.h_root);
++ break;
++ case Opt_xino:
++ fput(opt->xino.file);
++ break;
++ }
++ opt++;
++ }
++}
++
++static int opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags,
++ aufs_bindex_t bindex)
++{
++ int err;
++ struct au_opt_add *add = &opt->add;
++ char *p;
++
++ add->bindex = bindex;
++ add->perm = AuBrPerm_Last;
++ add->pathname = opt_str;
++ p = strchr(opt_str, '=');
++ if (p) {
++ *p++ = 0;
++ if (*p)
++ add->perm = br_perm_val(p);
++ }
++
++ err = vfsub_kern_path(add->pathname, lkup_dirflags, &add->path);
++ if (!err) {
++ if (!p) {
++ add->perm = AuBrPerm_RO;
++ if (au_test_fs_rr(add->path.dentry->d_sb))
++ add->perm = AuBrPerm_RR;
++ else if (!bindex && !(sb_flags & MS_RDONLY))
++ add->perm = AuBrPerm_RW;
++ }
++ opt->type = Opt_add;
++ goto out;
++ }
++ AuErr("lookup failed %s (%d)\n", add->pathname, err);
++ err = -EINVAL;
++
++ out:
++ return err;
++}
++
++static int au_opts_parse_del(struct au_opt_del *del, substring_t args[])
++{
++ int err;
++
++ del->pathname = args[0].from;
++ AuDbg("del path %s\n", del->pathname);
++
++ err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path);
++ if (unlikely(err))
++ AuErr("lookup failed %s (%d)\n", del->pathname, err);
++
++ return err;
++}
++
++#if 0 /* reserved for future use */
++static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex,
++ struct au_opt_del *del, substring_t args[])
++{
++ int err;
++ struct dentry *root;
++
++ err = -EINVAL;
++ root = sb->s_root;
++ aufs_read_lock(root, AuLock_FLUSH);
++ if (bindex < 0 || au_sbend(sb) < bindex) {
++ AuErr("out of bounds, %d\n", bindex);
++ goto out;
++ }
++
++ err = 0;
++ del->h_path.dentry = dget(au_h_dptr(root, bindex));
++ del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex));
++
++ out:
++ aufs_read_unlock(root, !AuLock_IR);
++ return err;
++}
++#endif
++
++static int au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[])
++{
++ int err;
++ struct path path;
++ char *p;
++
++ err = -EINVAL;
++ mod->path = args[0].from;
++ p = strchr(mod->path, '=');
++ if (unlikely(!p)) {
++ AuErr("no permssion %s\n", args[0].from);
++ goto out;
++ }
++
++ *p++ = 0;
++ err = vfsub_kern_path(mod->path, lkup_dirflags, &path);
++ if (unlikely(err)) {
++ AuErr("lookup failed %s (%d)\n", mod->path, err);
++ goto out;
++ }
++
++ mod->perm = br_perm_val(p);
++ AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p);
++ mod->h_root = dget(path.dentry);
++ path_put(&path);
++
++ out:
++ return err;
++}
++
++#if 0 /* reserved for future use */
++static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex,
++ struct au_opt_mod *mod, substring_t args[])
++{
++ int err;
++ struct dentry *root;
++
++ err = -EINVAL;
++ root = sb->s_root;
++ aufs_read_lock(root, AuLock_FLUSH);
++ if (bindex < 0 || au_sbend(sb) < bindex) {
++ AuErr("out of bounds, %d\n", bindex);
++ goto out;
++ }
++
++ err = 0;
++ mod->perm = br_perm_val(args[1].from);
++ AuDbg("mod path %s, perm 0x%x, %s\n",
++ mod->path, mod->perm, args[1].from);
++ mod->h_root = dget(au_h_dptr(root, bindex));
++
++ out:
++ aufs_read_unlock(root, !AuLock_IR);
++ return err;
++}
++#endif
++
++static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino,
++ substring_t args[])
++{
++ int err;
++ struct file *file;
++
++ file = au_xino_create(sb, args[0].from, /*silent*/0);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++
++ err = -EINVAL;
++ if (unlikely(file->f_dentry->d_sb == sb)) {
++ fput(file);
++ AuErr("%s must be outside\n", args[0].from);
++ goto out;
++ }
++
++ err = 0;
++ xino->file = file;
++ xino->path = args[0].from;
++
++ out:
++ return err;
++}
++
++static
++int au_opts_parse_xino_itrunc_path(struct super_block *sb,
++ struct au_opt_xino_itrunc *xino_itrunc,
++ substring_t args[])
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct path path;
++ struct dentry *root;
++
++ err = vfsub_kern_path(args[0].from, lkup_dirflags, &path);
++ if (unlikely(err)) {
++ AuErr("lookup failed %s (%d)\n", args[0].from, err);
++ goto out;
++ }
++
++ xino_itrunc->bindex = -1;
++ root = sb->s_root;
++ aufs_read_lock(root, AuLock_FLUSH);
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ if (au_h_dptr(root, bindex) == path.dentry) {
++ xino_itrunc->bindex = bindex;
++ break;
++ }
++ }
++ aufs_read_unlock(root, !AuLock_IR);
++ path_put(&path);
++
++ if (unlikely(xino_itrunc->bindex < 0)) {
++ AuErr("no such branch %s\n", args[0].from);
++ err = -EINVAL;
++ }
++
++ out:
++ return err;
++}
++
++/* called without aufs lock */
++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts)
++{
++ int err, n, token;
++ aufs_bindex_t bindex;
++ unsigned char skipped;
++ struct dentry *root;
++ struct au_opt *opt, *opt_tail;
++ char *opt_str;
++ /* reduce the stack space */
++ union {
++ struct au_opt_xino_itrunc *xino_itrunc;
++ struct au_opt_wbr_create *create;
++ } u;
++ struct {
++ substring_t args[MAX_OPT_ARGS];
++ } *a;
++
++ err = -ENOMEM;
++ a = kmalloc(sizeof(*a), GFP_NOFS);
++ if (unlikely(!a))
++ goto out;
++
++ root = sb->s_root;
++ err = 0;
++ bindex = 0;
++ opt = opts->opt;
++ opt_tail = opt + opts->max_opt - 1;
++ opt->type = Opt_tail;
++ while (!err && (opt_str = strsep(&str, ",")) && *opt_str) {
++ err = -EINVAL;
++ skipped = 0;
++ token = match_token(opt_str, options, a->args);
++ switch (token) {
++ case Opt_br:
++ err = 0;
++ while (!err && (opt_str = strsep(&a->args[0].from, ":"))
++ && *opt_str) {
++ err = opt_add(opt, opt_str, opts->sb_flags,
++ bindex++);
++ if (unlikely(!err && ++opt > opt_tail)) {
++ err = -E2BIG;
++ break;
++ }
++ opt->type = Opt_tail;
++ skipped = 1;
++ }
++ break;
++ case Opt_add:
++ if (unlikely(match_int(&a->args[0], &n))) {
++ AuErr("bad integer in %s\n", opt_str);
++ break;
++ }
++ bindex = n;
++ err = opt_add(opt, a->args[1].from, opts->sb_flags,
++ bindex);
++ if (!err)
++ opt->type = token;
++ break;
++ case Opt_append:
++ err = opt_add(opt, a->args[0].from, opts->sb_flags,
++ /*dummy bindex*/1);
++ if (!err)
++ opt->type = token;
++ break;
++ case Opt_prepend:
++ err = opt_add(opt, a->args[0].from, opts->sb_flags,
++ /*bindex*/0);
++ if (!err)
++ opt->type = token;
++ break;
++ case Opt_del:
++ err = au_opts_parse_del(&opt->del, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++#if 0 /* reserved for future use */
++ case Opt_idel:
++ del->pathname = "(indexed)";
++ if (unlikely(match_int(&args[0], &n))) {
++ AuErr("bad integer in %s\n", opt_str);
++ break;
++ }
++ err = au_opts_parse_idel(sb, n, &opt->del, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++#endif
++ case Opt_mod:
++ err = au_opts_parse_mod(&opt->mod, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++#ifdef IMOD /* reserved for future use */
++ case Opt_imod:
++ u.mod->path = "(indexed)";
++ if (unlikely(match_int(&a->args[0], &n))) {
++ AuErr("bad integer in %s\n", opt_str);
++ break;
++ }
++ err = au_opts_parse_imod(sb, n, &opt->mod, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++#endif
++ case Opt_xino:
++ err = au_opts_parse_xino(sb, &opt->xino, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++
++ case Opt_trunc_xino_path:
++ err = au_opts_parse_xino_itrunc_path
++ (sb, &opt->xino_itrunc, a->args);
++ if (!err)
++ opt->type = token;
++ break;
++
++ case Opt_itrunc_xino:
++ u.xino_itrunc = &opt->xino_itrunc;
++ if (unlikely(match_int(&a->args[0], &n))) {
++ AuErr("bad integer in %s\n", opt_str);
++ break;
++ }
++ u.xino_itrunc->bindex = n;
++ aufs_read_lock(root, AuLock_FLUSH);
++ if (n < 0 || au_sbend(sb) < n) {
++ AuErr("out of bounds, %d\n", n);
++ aufs_read_unlock(root, !AuLock_IR);
++ break;
++ }
++ aufs_read_unlock(root, !AuLock_IR);
++ err = 0;
++ opt->type = token;
++ break;
++
++ case Opt_dirwh:
++ if (unlikely(match_int(&a->args[0], &opt->dirwh)))
++ break;
++ err = 0;
++ opt->type = token;
++ break;
++
++ case Opt_rdcache:
++ if (unlikely(match_int(&a->args[0], &opt->rdcache)))
++ break;
++ err = 0;
++ opt->type = token;
++ break;
++ case Opt_rdblk:
++ if (unlikely(match_int(&a->args[0], &n)
++ || n < 0
++ || n > KMALLOC_MAX_SIZE)) {
++ AuErr("bad integer in %s\n", opt_str);
++ break;
++ }
++ if (unlikely(n && n < NAME_MAX)) {
++ AuErr("rdblk must be larger than %d\n",
++ NAME_MAX);
++ break;
++ }
++ opt->rdblk = n;
++ err = 0;
++ opt->type = token;
++ break;
++ case Opt_rdhash:
++ if (unlikely(match_int(&a->args[0], &n)
++ || n < 0
++ || n * sizeof(struct hlist_head)
++ > KMALLOC_MAX_SIZE)) {
++ AuErr("bad integer in %s\n", opt_str);
++ break;
++ }
++ opt->rdhash = n;
++ err = 0;
++ opt->type = token;
++ break;
++
++ case Opt_trunc_xino:
++ case Opt_notrunc_xino:
++ case Opt_noxino:
++ case Opt_trunc_xib:
++ case Opt_notrunc_xib:
++ case Opt_shwh:
++ case Opt_noshwh:
++ case Opt_plink:
++ case Opt_noplink:
++ case Opt_list_plink:
++ case Opt_diropq_a:
++ case Opt_diropq_w:
++ case Opt_warn_perm:
++ case Opt_nowarn_perm:
++ case Opt_refrof:
++ case Opt_norefrof:
++ case Opt_verbose:
++ case Opt_noverbose:
++ case Opt_sum:
++ case Opt_nosum:
++ case Opt_wsum:
++ case Opt_rdblk_def:
++ case Opt_rdhash_def:
++ err = 0;
++ opt->type = token;
++ break;
++
++ case Opt_udba:
++ opt->udba = udba_val(a->args[0].from);
++ if (opt->udba >= 0) {
++ err = 0;
++ opt->type = token;
++ } else
++ AuErr("wrong value, %s\n", opt_str);
++ break;
++
++ case Opt_wbr_create:
++ u.create = &opt->wbr_create;
++ u.create->wbr_create
++ = au_wbr_create_val(a->args[0].from, u.create);
++ if (u.create->wbr_create >= 0) {
++ err = 0;
++ opt->type = token;
++ } else
++ AuErr("wrong value, %s\n", opt_str);
++ break;
++ case Opt_wbr_copyup:
++ opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from);
++ if (opt->wbr_copyup >= 0) {
++ err = 0;
++ opt->type = token;
++ } else
++ AuErr("wrong value, %s\n", opt_str);
++ break;
++
++ case Opt_ignore:
++ AuWarn("ignored %s\n", opt_str);
++ /*FALLTHROUGH*/
++ case Opt_ignore_silent:
++ skipped = 1;
++ err = 0;
++ break;
++ case Opt_err:
++ AuErr("unknown option %s\n", opt_str);
++ break;
++ }
++
++ if (!err && !skipped) {
++ if (unlikely(++opt > opt_tail)) {
++ err = -E2BIG;
++ opt--;
++ opt->type = Opt_tail;
++ break;
++ }
++ opt->type = Opt_tail;
++ }
++ }
++
++ kfree(a);
++ dump_opts(opts);
++ if (unlikely(err))
++ au_opts_free(opts);
++
++ out:
++ return err;
++}
++
++static int au_opt_wbr_create(struct super_block *sb,
++ struct au_opt_wbr_create *create)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ err = 1; /* handled */
++ sbinfo = au_sbi(sb);
++ if (sbinfo->si_wbr_create_ops->fin) {
++ err = sbinfo->si_wbr_create_ops->fin(sb);
++ if (!err)
++ err = 1;
++ }
++
++ sbinfo->si_wbr_create = create->wbr_create;
++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create;
++ switch (create->wbr_create) {
++ case AuWbrCreate_MFSRRV:
++ case AuWbrCreate_MFSRR:
++ sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark;
++ /*FALLTHROUGH*/
++ case AuWbrCreate_MFS:
++ case AuWbrCreate_MFSV:
++ case AuWbrCreate_PMFS:
++ case AuWbrCreate_PMFSV:
++ sbinfo->si_wbr_mfs.mfs_expire = create->mfs_second * HZ;
++ break;
++ }
++
++ if (sbinfo->si_wbr_create_ops->init)
++ sbinfo->si_wbr_create_ops->init(sb); /* ignore */
++
++ return err;
++}
++
++/*
++ * returns,
++ * plus: processed without an error
++ * zero: unprocessed
++ */
++static int au_opt_simple(struct super_block *sb, struct au_opt *opt,
++ struct au_opts *opts)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ err = 1; /* handled */
++ sbinfo = au_sbi(sb);
++ switch (opt->type) {
++ case Opt_udba:
++ sbinfo->si_mntflags &= ~AuOptMask_UDBA;
++ sbinfo->si_mntflags |= opt->udba;
++ opts->given_udba |= opt->udba;
++ break;
++
++ case Opt_plink:
++ au_opt_set(sbinfo->si_mntflags, PLINK);
++ break;
++ case Opt_noplink:
++ if (au_opt_test(sbinfo->si_mntflags, PLINK))
++ au_plink_put(sb);
++ au_opt_clr(sbinfo->si_mntflags, PLINK);
++ break;
++ case Opt_list_plink:
++ if (au_opt_test(sbinfo->si_mntflags, PLINK))
++ au_plink_list(sb);
++ break;
++
++ case Opt_diropq_a:
++ au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ);
++ break;
++ case Opt_diropq_w:
++ au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ);
++ break;
++
++ case Opt_warn_perm:
++ au_opt_set(sbinfo->si_mntflags, WARN_PERM);
++ break;
++ case Opt_nowarn_perm:
++ au_opt_clr(sbinfo->si_mntflags, WARN_PERM);
++ break;
++
++ case Opt_refrof:
++ au_opt_set(sbinfo->si_mntflags, REFROF);
++ break;
++ case Opt_norefrof:
++ au_opt_clr(sbinfo->si_mntflags, REFROF);
++ break;
++
++ case Opt_verbose:
++ au_opt_set(sbinfo->si_mntflags, VERBOSE);
++ break;
++ case Opt_noverbose:
++ au_opt_clr(sbinfo->si_mntflags, VERBOSE);
++ break;
++
++ case Opt_sum:
++ au_opt_set(sbinfo->si_mntflags, SUM);
++ break;
++ case Opt_wsum:
++ au_opt_clr(sbinfo->si_mntflags, SUM);
++ au_opt_set(sbinfo->si_mntflags, SUM_W);
++ case Opt_nosum:
++ au_opt_clr(sbinfo->si_mntflags, SUM);
++ au_opt_clr(sbinfo->si_mntflags, SUM_W);
++ break;
++
++ case Opt_wbr_create:
++ err = au_opt_wbr_create(sb, &opt->wbr_create);
++ break;
++ case Opt_wbr_copyup:
++ sbinfo->si_wbr_copyup = opt->wbr_copyup;
++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup;
++ break;
++
++ case Opt_dirwh:
++ sbinfo->si_dirwh = opt->dirwh;
++ break;
++
++ case Opt_rdcache:
++ sbinfo->si_rdcache = opt->rdcache * HZ;
++ break;
++ case Opt_rdblk:
++ sbinfo->si_rdblk = opt->rdblk;
++ break;
++ case Opt_rdblk_def:
++ sbinfo->si_rdblk = AUFS_RDBLK_DEF;
++ break;
++ case Opt_rdhash:
++ sbinfo->si_rdhash = opt->rdhash;
++ break;
++ case Opt_rdhash_def:
++ sbinfo->si_rdhash = AUFS_RDHASH_DEF;
++ break;
++
++ case Opt_shwh:
++ au_opt_set(sbinfo->si_mntflags, SHWH);
++ break;
++ case Opt_noshwh:
++ au_opt_clr(sbinfo->si_mntflags, SHWH);
++ break;
++
++ case Opt_trunc_xino:
++ au_opt_set(sbinfo->si_mntflags, TRUNC_XINO);
++ break;
++ case Opt_notrunc_xino:
++ au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO);
++ break;
++
++ case Opt_trunc_xino_path:
++ case Opt_itrunc_xino:
++ err = au_xino_trunc(sb, opt->xino_itrunc.bindex);
++ if (!err)
++ err = 1;
++ break;
++
++ case Opt_trunc_xib:
++ au_fset_opts(opts->flags, TRUNC_XIB);
++ break;
++ case Opt_notrunc_xib:
++ au_fclr_opts(opts->flags, TRUNC_XIB);
++ break;
++
++ default:
++ err = 0;
++ break;
++ }
++
++ return err;
++}
++
++/*
++ * returns tri-state.
++ * plus: processed without an error
++ * zero: unprocessed
++ * minus: error
++ */
++static int au_opt_br(struct super_block *sb, struct au_opt *opt,
++ struct au_opts *opts)
++{
++ int err, do_refresh;
++
++ err = 0;
++ switch (opt->type) {
++ case Opt_append:
++ opt->add.bindex = au_sbend(sb) + 1;
++ if (opt->add.bindex < 0)
++ opt->add.bindex = 0;
++ goto add;
++ case Opt_prepend:
++ opt->add.bindex = 0;
++ add:
++ case Opt_add:
++ err = au_br_add(sb, &opt->add,
++ au_ftest_opts(opts->flags, REMOUNT));
++ if (!err) {
++ err = 1;
++ au_fset_opts(opts->flags, REFRESH_DIR);
++ if (au_br_whable(opt->add.perm))
++ au_fset_opts(opts->flags, REFRESH_NONDIR);
++ }
++ break;
++
++ case Opt_del:
++ case Opt_idel:
++ err = au_br_del(sb, &opt->del,
++ au_ftest_opts(opts->flags, REMOUNT));
++ if (!err) {
++ err = 1;
++ au_fset_opts(opts->flags, TRUNC_XIB);
++ au_fset_opts(opts->flags, REFRESH_DIR);
++ au_fset_opts(opts->flags, REFRESH_NONDIR);
++ }
++ break;
++
++ case Opt_mod:
++ case Opt_imod:
++ err = au_br_mod(sb, &opt->mod,
++ au_ftest_opts(opts->flags, REMOUNT),
++ &do_refresh);
++ if (!err) {
++ err = 1;
++ if (do_refresh) {
++ au_fset_opts(opts->flags, REFRESH_DIR);
++ au_fset_opts(opts->flags, REFRESH_NONDIR);
++ }
++ }
++ break;
++ }
++
++ return err;
++}
++
++static int au_opt_xino(struct super_block *sb, struct au_opt *opt,
++ struct au_opt_xino **opt_xino,
++ struct au_opts *opts)
++{
++ int err;
++ aufs_bindex_t bend, bindex;
++ struct dentry *root, *parent, *h_root;
++
++ err = 0;
++ switch (opt->type) {
++ case Opt_xino:
++ err = au_xino_set(sb, &opt->xino,
++ !!au_ftest_opts(opts->flags, REMOUNT));
++ if (unlikely(err))
++ break;
++
++ *opt_xino = &opt->xino;
++ au_xino_brid_set(sb, -1);
++
++ /* safe d_parent access */
++ parent = opt->xino.file->f_dentry->d_parent;
++ root = sb->s_root;
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ h_root = au_h_dptr(root, bindex);
++ if (h_root == parent) {
++ au_xino_brid_set(sb, au_sbr_id(sb, bindex));
++ break;
++ }
++ }
++ break;
++
++ case Opt_noxino:
++ au_xino_clr(sb);
++ au_xino_brid_set(sb, -1);
++ *opt_xino = (void *)-1;
++ break;
++ }
++
++ return err;
++}
++
++int au_opts_verify(struct super_block *sb, unsigned long sb_flags,
++ unsigned int pending)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ unsigned char do_plink, skip, do_free;
++ struct au_branch *br;
++ struct au_wbr *wbr;
++ struct dentry *root;
++ struct inode *dir, *h_dir;
++ struct au_sbinfo *sbinfo;
++ struct au_hinode *hdir;
++
++ SiMustAnyLock(sb);
++
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA));
++
++ if (!(sb_flags & MS_RDONLY)) {
++ if (unlikely(!au_br_writable(au_sbr_perm(sb, 0))))
++ AuWarn("first branch should be rw\n");
++ if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH)))
++ AuWarn("shwh should be used with ro\n");
++ }
++
++ if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HINOTIFY)
++ && !au_opt_test(sbinfo->si_mntflags, XINO))
++ AuWarn("udba=inotify requires xino\n");
++
++ err = 0;
++ root = sb->s_root;
++ dir = sb->s_root->d_inode;
++ do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK);
++ bend = au_sbend(sb);
++ for (bindex = 0; !err && bindex <= bend; bindex++) {
++ skip = 0;
++ h_dir = au_h_iptr(dir, bindex);
++ br = au_sbr(sb, bindex);
++ do_free = 0;
++
++ wbr = br->br_wbr;
++ if (wbr)
++ wbr_wh_read_lock(wbr);
++
++ switch (br->br_perm) {
++ case AuBrPerm_RO:
++ case AuBrPerm_ROWH:
++ case AuBrPerm_RR:
++ case AuBrPerm_RRWH:
++ do_free = !!wbr;
++ skip = (!wbr
++ || (!wbr->wbr_whbase
++ && !wbr->wbr_plink
++ && !wbr->wbr_orph));
++ break;
++
++ case AuBrPerm_RWNoLinkWH:
++ /* skip = (!br->br_whbase && !br->br_orph); */
++ skip = (!wbr || !wbr->wbr_whbase);
++ if (skip && wbr) {
++ if (do_plink)
++ skip = !!wbr->wbr_plink;
++ else
++ skip = !wbr->wbr_plink;
++ }
++ break;
++
++ case AuBrPerm_RW:
++ /* skip = (br->br_whbase && br->br_ohph); */
++ skip = (wbr && wbr->wbr_whbase);
++ if (skip) {
++ if (do_plink)
++ skip = !!wbr->wbr_plink;
++ else
++ skip = !wbr->wbr_plink;
++ }
++ break;
++
++ default:
++ BUG();
++ }
++ if (wbr)
++ wbr_wh_read_unlock(wbr);
++
++ if (skip)
++ continue;
++
++ hdir = au_hi(dir, bindex);
++ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ if (wbr)
++ wbr_wh_write_lock(wbr);
++ err = au_wh_init(au_h_dptr(root, bindex), br, sb);
++ if (wbr)
++ wbr_wh_write_unlock(wbr);
++ au_hin_imtx_unlock(hdir);
++
++ if (!err && do_free) {
++ kfree(wbr);
++ br->br_wbr = NULL;
++ }
++ }
++
++ return err;
++}
++
++int au_opts_mount(struct super_block *sb, struct au_opts *opts)
++{
++ int err;
++ unsigned int tmp;
++ aufs_bindex_t bend;
++ struct au_opt *opt;
++ struct au_opt_xino *opt_xino, xino;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ err = 0;
++ opt_xino = NULL;
++ opt = opts->opt;
++ while (err >= 0 && opt->type != Opt_tail)
++ err = au_opt_simple(sb, opt++, opts);
++ if (err > 0)
++ err = 0;
++ else if (unlikely(err < 0))
++ goto out;
++
++ /* disable xino and udba temporary */
++ sbinfo = au_sbi(sb);
++ tmp = sbinfo->si_mntflags;
++ au_opt_clr(sbinfo->si_mntflags, XINO);
++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL);
++
++ opt = opts->opt;
++ while (err >= 0 && opt->type != Opt_tail)
++ err = au_opt_br(sb, opt++, opts);
++ if (err > 0)
++ err = 0;
++ else if (unlikely(err < 0))
++ goto out;
++
++ bend = au_sbend(sb);
++ if (unlikely(bend < 0)) {
++ err = -EINVAL;
++ AuErr("no branches\n");
++ goto out;
++ }
++
++ if (au_opt_test(tmp, XINO))
++ au_opt_set(sbinfo->si_mntflags, XINO);
++ opt = opts->opt;
++ while (!err && opt->type != Opt_tail)
++ err = au_opt_xino(sb, opt++, &opt_xino, opts);
++ if (unlikely(err))
++ goto out;
++
++ err = au_opts_verify(sb, sb->s_flags, tmp);
++ if (unlikely(err))
++ goto out;
++
++ /* restore xino */
++ if (au_opt_test(tmp, XINO) && !opt_xino) {
++ xino.file = au_xino_def(sb);
++ err = PTR_ERR(xino.file);
++ if (IS_ERR(xino.file))
++ goto out;
++
++ err = au_xino_set(sb, &xino, /*remount*/0);
++ fput(xino.file);
++ if (unlikely(err))
++ goto out;
++ }
++
++ /* restore udba */
++ sbinfo->si_mntflags &= ~AuOptMask_UDBA;
++ sbinfo->si_mntflags |= (tmp & AuOptMask_UDBA);
++ if (au_opt_test(tmp, UDBA_HINOTIFY)) {
++ struct inode *dir = sb->s_root->d_inode;
++ au_reset_hinotify(dir,
++ au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO);
++ }
++
++ out:
++ return err;
++}
++
++int au_opts_remount(struct super_block *sb, struct au_opts *opts)
++{
++ int err, rerr;
++ struct inode *dir;
++ struct au_opt_xino *opt_xino;
++ struct au_opt *opt;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ dir = sb->s_root->d_inode;
++ sbinfo = au_sbi(sb);
++ err = 0;
++ opt_xino = NULL;
++ opt = opts->opt;
++ while (err >= 0 && opt->type != Opt_tail) {
++ err = au_opt_simple(sb, opt, opts);
++ if (!err)
++ err = au_opt_br(sb, opt, opts);
++ if (!err)
++ err = au_opt_xino(sb, opt, &opt_xino, opts);
++ opt++;
++ }
++ if (err > 0)
++ err = 0;
++ AuTraceErr(err);
++ /* go on even err */
++
++ rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0);
++ if (unlikely(rerr && !err))
++ err = rerr;
++
++ if (au_ftest_opts(opts->flags, TRUNC_XIB)) {
++ rerr = au_xib_trunc(sb);
++ if (unlikely(rerr && !err))
++ err = rerr;
++ }
++
++ /* will be handled by the caller */
++ if (!au_ftest_opts(opts->flags, REFRESH_DIR)
++ && (opts->given_udba || au_opt_test(sbinfo->si_mntflags, XINO)))
++ au_fset_opts(opts->flags, REFRESH_DIR);
++
++ AuDbg("status 0x%x\n", opts->flags);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++unsigned int au_opt_udba(struct super_block *sb)
++{
++ return au_mntflags(sb) & AuOptMask_UDBA;
++}
+diff --git a/fs/aufs/opts.h b/fs/aufs/opts.h
+new file mode 100644
+index 0000000..27439b1
+--- /dev/null
++++ b/fs/aufs/opts.h
+@@ -0,0 +1,196 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * mount options/flags
++ */
++
++#ifndef __AUFS_OPTS_H__
++#define __AUFS_OPTS_H__
++
++#ifdef __KERNEL__
++
++#include <linux/path.h>
++#include <linux/aufs_type.h>
++
++struct file;
++struct super_block;
++
++/* ---------------------------------------------------------------------- */
++
++/* mount flags */
++#define AuOpt_XINO 1 /* external inode number bitmap
++ and translation table */
++#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */
++#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */
++#define AuOpt_UDBA_REVAL (1 << 3)
++#define AuOpt_UDBA_HINOTIFY (1 << 4)
++#define AuOpt_SHWH (1 << 5) /* show whiteout */
++#define AuOpt_PLINK (1 << 6) /* pseudo-link */
++#define AuOpt_DIRPERM1 (1 << 7) /* unimplemented */
++#define AuOpt_REFROF (1 << 8) /* unimplemented */
++#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */
++#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */
++#define AuOpt_SUM_W (1 << 11) /* unimplemented */
++#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */
++#define AuOpt_VERBOSE (1 << 13) /* busy inode when del-branch */
++
++#ifndef CONFIG_AUFS_HINOTIFY
++#undef AuOpt_UDBA_HINOTIFY
++#define AuOpt_UDBA_HINOTIFY 0
++#endif
++#ifndef CONFIG_AUFS_SHWH
++#undef AuOpt_SHWH
++#define AuOpt_SHWH 0
++#endif
++
++#define AuOpt_Def (AuOpt_XINO \
++ | AuOpt_UDBA_REVAL \
++ | AuOpt_PLINK \
++ /* | AuOpt_DIRPERM1 */ \
++ | AuOpt_WARN_PERM)
++#define AuOptMask_UDBA (AuOpt_UDBA_NONE \
++ | AuOpt_UDBA_REVAL \
++ | AuOpt_UDBA_HINOTIFY)
++
++#define au_opt_test(flags, name) (flags & AuOpt_##name)
++#define au_opt_set(flags, name) do { \
++ BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \
++ ((flags) |= AuOpt_##name); \
++} while (0)
++#define au_opt_set_udba(flags, name) do { \
++ (flags) &= ~AuOptMask_UDBA; \
++ ((flags) |= AuOpt_##name); \
++} while (0)
++#define au_opt_clr(flags, name) { ((flags) &= ~AuOpt_##name); }
++
++/* ---------------------------------------------------------------------- */
++
++/* policies to select one among multiple writable branches */
++enum {
++ AuWbrCreate_TDP, /* top down parent */
++ AuWbrCreate_RR, /* round robin */
++ AuWbrCreate_MFS, /* most free space */
++ AuWbrCreate_MFSV, /* mfs with seconds */
++ AuWbrCreate_MFSRR, /* mfs then rr */
++ AuWbrCreate_MFSRRV, /* mfs then rr with seconds */
++ AuWbrCreate_PMFS, /* parent and mfs */
++ AuWbrCreate_PMFSV, /* parent and mfs with seconds */
++
++ AuWbrCreate_Def = AuWbrCreate_TDP
++};
++
++enum {
++ AuWbrCopyup_TDP, /* top down parent */
++ AuWbrCopyup_BUP, /* bottom up parent */
++ AuWbrCopyup_BU, /* bottom up */
++
++ AuWbrCopyup_Def = AuWbrCopyup_TDP
++};
++
++/* ---------------------------------------------------------------------- */
++
++struct au_opt_add {
++ aufs_bindex_t bindex;
++ char *pathname;
++ int perm;
++ struct path path;
++};
++
++struct au_opt_del {
++ char *pathname;
++ struct path h_path;
++};
++
++struct au_opt_mod {
++ char *path;
++ int perm;
++ struct dentry *h_root;
++};
++
++struct au_opt_xino {
++ char *path;
++ struct file *file;
++};
++
++struct au_opt_xino_itrunc {
++ aufs_bindex_t bindex;
++};
++
++struct au_opt_wbr_create {
++ int wbr_create;
++ int mfs_second;
++ unsigned long long mfsrr_watermark;
++};
++
++struct au_opt {
++ int type;
++ union {
++ struct au_opt_xino xino;
++ struct au_opt_xino_itrunc xino_itrunc;
++ struct au_opt_add add;
++ struct au_opt_del del;
++ struct au_opt_mod mod;
++ int dirwh;
++ int rdcache;
++ unsigned int rdblk;
++ unsigned int rdhash;
++ int udba;
++ struct au_opt_wbr_create wbr_create;
++ int wbr_copyup;
++ };
++};
++
++/* opts flags */
++#define AuOpts_REMOUNT 1
++#define AuOpts_REFRESH_DIR (1 << 1)
++#define AuOpts_REFRESH_NONDIR (1 << 2)
++#define AuOpts_TRUNC_XIB (1 << 3)
++#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name)
++#define au_fset_opts(flags, name) { (flags) |= AuOpts_##name; }
++#define au_fclr_opts(flags, name) { (flags) &= ~AuOpts_##name; }
++
++struct au_opts {
++ struct au_opt *opt;
++ int max_opt;
++
++ unsigned int given_udba;
++ unsigned int flags;
++ unsigned long sb_flags;
++};
++
++/* ---------------------------------------------------------------------- */
++
++const char *au_optstr_br_perm(int brperm);
++const char *au_optstr_udba(int udba);
++const char *au_optstr_wbr_copyup(int wbr_copyup);
++const char *au_optstr_wbr_create(int wbr_create);
++
++void au_opts_free(struct au_opts *opts);
++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts);
++int au_opts_verify(struct super_block *sb, unsigned long sb_flags,
++ unsigned int pending);
++int au_opts_mount(struct super_block *sb, struct au_opts *opts);
++int au_opts_remount(struct super_block *sb, struct au_opts *opts);
++
++unsigned int au_opt_udba(struct super_block *sb);
++
++/* ---------------------------------------------------------------------- */
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_OPTS_H__ */
+diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c
+new file mode 100644
+index 0000000..31fc923
+--- /dev/null
++++ b/fs/aufs/plink.c
+@@ -0,0 +1,396 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * pseudo-link
++ */
++
++#include "aufs.h"
++
++/*
++ * during a user process maintains the pseudo-links,
++ * prohibit adding a new plink and branch manipulation.
++ */
++void au_plink_block_maintain(struct super_block *sb)
++{
++ struct au_sbinfo *sbi = au_sbi(sb);
++
++ SiMustAnyLock(sb);
++
++ /* gave up wake_up_bit() */
++ wait_event(sbi->si_plink_wq, !au_ftest_si(sbi, MAINTAIN_PLINK));
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct pseudo_link {
++ struct list_head list;
++ struct inode *inode;
++};
++
++#ifdef CONFIG_AUFS_DEBUG
++void au_plink_list(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink;
++
++ SiMustAnyLock(sb);
++
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++
++ plink_list = &sbinfo->si_plink.head;
++ spin_lock(&sbinfo->si_plink.spin);
++ list_for_each_entry(plink, plink_list, list)
++ AuDbg("%lu\n", plink->inode->i_ino);
++ spin_unlock(&sbinfo->si_plink.spin);
++}
++#endif
++
++/* is the inode pseudo-linked? */
++int au_plink_test(struct inode *inode)
++{
++ int found;
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink;
++
++ sbinfo = au_sbi(inode->i_sb);
++ AuRwMustAnyLock(&sbinfo->si_rwsem);
++ AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK));
++
++ found = 0;
++ plink_list = &sbinfo->si_plink.head;
++ spin_lock(&sbinfo->si_plink.spin);
++ list_for_each_entry(plink, plink_list, list)
++ if (plink->inode == inode) {
++ found = 1;
++ break;
++ }
++ spin_unlock(&sbinfo->si_plink.spin);
++ return found;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * generate a name for plink.
++ * the file will be stored under AUFS_WH_PLINKDIR.
++ */
++/* 20 is max digits length of ulong 64 */
++#define PLINK_NAME_LEN ((20 + 1) * 2)
++
++static int plink_name(char *name, int len, struct inode *inode,
++ aufs_bindex_t bindex)
++{
++ int rlen;
++ struct inode *h_inode;
++
++ h_inode = au_h_iptr(inode, bindex);
++ rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino);
++ return rlen;
++}
++
++/* lookup the plink-ed @inode under the branch at @bindex */
++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex)
++{
++ struct dentry *h_dentry, *h_parent;
++ struct au_branch *br;
++ struct inode *h_dir;
++ char a[PLINK_NAME_LEN];
++ struct qstr tgtname = {
++ .name = a
++ };
++
++ br = au_sbr(inode->i_sb, bindex);
++ h_parent = br->br_wbr->wbr_plink;
++ h_dir = h_parent->d_inode;
++ tgtname.len = plink_name(a, sizeof(a), inode, bindex);
++
++ /* always superio. */
++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_CHILD2);
++ h_dentry = au_sio_lkup_one(&tgtname, h_parent, br);
++ mutex_unlock(&h_dir->i_mutex);
++ return h_dentry;
++}
++
++/* create a pseudo-link */
++static int do_whplink(struct qstr *tgt, struct dentry *h_parent,
++ struct dentry *h_dentry, struct au_branch *br)
++{
++ int err;
++ struct path h_path = {
++ .mnt = br->br_mnt
++ };
++ struct inode *h_dir;
++
++ h_dir = h_parent->d_inode;
++ again:
++ h_path.dentry = au_lkup_one(tgt, h_parent, br, /*nd*/NULL);
++ err = PTR_ERR(h_path.dentry);
++ if (IS_ERR(h_path.dentry))
++ goto out;
++
++ err = 0;
++ /* wh.plink dir is not monitored */
++ if (h_path.dentry->d_inode
++ && h_path.dentry->d_inode != h_dentry->d_inode) {
++ err = vfsub_unlink(h_dir, &h_path, /*force*/0);
++ dput(h_path.dentry);
++ h_path.dentry = NULL;
++ if (!err)
++ goto again;
++ }
++ if (!err && !h_path.dentry->d_inode)
++ err = vfsub_link(h_dentry, h_dir, &h_path);
++ dput(h_path.dentry);
++
++ out:
++ return err;
++}
++
++struct do_whplink_args {
++ int *errp;
++ struct qstr *tgt;
++ struct dentry *h_parent;
++ struct dentry *h_dentry;
++ struct au_branch *br;
++};
++
++static void call_do_whplink(void *args)
++{
++ struct do_whplink_args *a = args;
++ *a->errp = do_whplink(a->tgt, a->h_parent, a->h_dentry, a->br);
++}
++
++static int whplink(struct dentry *h_dentry, struct inode *inode,
++ aufs_bindex_t bindex, struct au_branch *br)
++{
++ int err, wkq_err;
++ struct au_wbr *wbr;
++ struct dentry *h_parent;
++ struct inode *h_dir;
++ char a[PLINK_NAME_LEN];
++ struct qstr tgtname = {
++ .name = a
++ };
++
++ wbr = au_sbr(inode->i_sb, bindex)->br_wbr;
++ h_parent = wbr->wbr_plink;
++ h_dir = h_parent->d_inode;
++ tgtname.len = plink_name(a, sizeof(a), inode, bindex);
++
++ /* always superio. */
++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_CHILD2);
++ if (!au_test_wkq(current)) {
++ struct do_whplink_args args = {
++ .errp = &err,
++ .tgt = &tgtname,
++ .h_parent = h_parent,
++ .h_dentry = h_dentry,
++ .br = br
++ };
++ wkq_err = au_wkq_wait(call_do_whplink, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ } else
++ err = do_whplink(&tgtname, h_parent, h_dentry, br);
++ mutex_unlock(&h_dir->i_mutex);
++
++ return err;
++}
++
++/* free a single plink */
++static void do_put_plink(struct pseudo_link *plink, int do_del)
++{
++ iput(plink->inode);
++ if (do_del)
++ list_del(&plink->list);
++ kfree(plink);
++}
++
++/*
++ * create a new pseudo-link for @h_dentry on @bindex.
++ * the linked inode is held in aufs @inode.
++ */
++void au_plink_append(struct inode *inode, aufs_bindex_t bindex,
++ struct dentry *h_dentry)
++{
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink;
++ int found, err, cnt;
++
++ sb = inode->i_sb;
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++
++ err = 0;
++ cnt = 0;
++ found = 0;
++ plink_list = &sbinfo->si_plink.head;
++ spin_lock(&sbinfo->si_plink.spin);
++ list_for_each_entry(plink, plink_list, list) {
++ cnt++;
++ if (plink->inode == inode) {
++ found = 1;
++ break;
++ }
++ }
++ if (found) {
++ spin_unlock(&sbinfo->si_plink.spin);
++ return;
++ }
++
++ plink = NULL;
++ if (!found) {
++ plink = kmalloc(sizeof(*plink), GFP_ATOMIC);
++ if (plink) {
++ plink->inode = au_igrab(inode);
++ list_add(&plink->list, plink_list);
++ cnt++;
++ } else
++ err = -ENOMEM;
++ }
++ spin_unlock(&sbinfo->si_plink.spin);
++
++ if (!err) {
++ au_plink_block_maintain(sb);
++ err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex));
++ }
++
++ if (unlikely(cnt > AUFS_PLINK_WARN))
++ AuWarn1("unexpectedly many pseudo links, %d\n", cnt);
++ if (unlikely(err)) {
++ AuWarn("err %d, damaged pseudo link.\n", err);
++ if (!found && plink)
++ do_put_plink(plink, /*do_del*/1);
++ }
++}
++
++/* free all plinks */
++void au_plink_put(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink, *tmp;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++
++ plink_list = &sbinfo->si_plink.head;
++ /* no spin_lock since sbinfo is write-locked */
++ list_for_each_entry_safe(plink, tmp, plink_list, list)
++ do_put_plink(plink, 0);
++ INIT_LIST_HEAD(plink_list);
++}
++
++/* free the plinks on a branch specified by @br_id */
++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id)
++{
++ struct au_sbinfo *sbinfo;
++ struct list_head *plink_list;
++ struct pseudo_link *plink, *tmp;
++ struct inode *inode;
++ aufs_bindex_t bstart, bend, bindex;
++ unsigned char do_put;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK));
++
++ plink_list = &sbinfo->si_plink.head;
++ /* no spin_lock since sbinfo is write-locked */
++ list_for_each_entry_safe(plink, tmp, plink_list, list) {
++ do_put = 0;
++ inode = au_igrab(plink->inode);
++ ii_write_lock_child(inode);
++ bstart = au_ibstart(inode);
++ bend = au_ibend(inode);
++ if (bstart >= 0) {
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ if (!au_h_iptr(inode, bindex)
++ || au_ii_br_id(inode, bindex) != br_id)
++ continue;
++ au_set_h_iptr(inode, bindex, NULL, 0);
++ do_put = 1;
++ break;
++ }
++ } else
++ do_put_plink(plink, 1);
++
++ if (do_put) {
++ for (bindex = bstart; bindex <= bend; bindex++)
++ if (au_h_iptr(inode, bindex)) {
++ do_put = 0;
++ break;
++ }
++ if (do_put)
++ do_put_plink(plink, 1);
++ }
++ ii_write_unlock(inode);
++ iput(inode);
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++long au_plink_ioctl(struct file *file, unsigned int cmd)
++{
++ long err;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++
++ err = -EACCES;
++ if (!capable(CAP_SYS_ADMIN))
++ goto out;
++
++ err = 0;
++ sb = file->f_dentry->d_sb;
++ sbinfo = au_sbi(sb);
++ switch (cmd) {
++ case AUFS_CTL_PLINK_MAINT:
++ /*
++ * pseudo-link maintenance mode,
++ * cleared by aufs_release_dir()
++ */
++ si_write_lock(sb);
++ if (!au_ftest_si(sbinfo, MAINTAIN_PLINK)) {
++ au_fset_si(sbinfo, MAINTAIN_PLINK);
++ au_fi(file)->fi_maintain_plink = 1;
++ } else
++ err = -EBUSY;
++ si_write_unlock(sb);
++ break;
++ case AUFS_CTL_PLINK_CLEAN:
++ aufs_write_lock(sb->s_root);
++ if (au_opt_test(sbinfo->si_mntflags, PLINK))
++ au_plink_put(sb);
++ aufs_write_unlock(sb->s_root);
++ break;
++ default:
++ err = -EINVAL;
++ }
++ out:
++ return err;
++}
+diff --git a/fs/aufs/rdu.c b/fs/aufs/rdu.c
+new file mode 100644
+index 0000000..3a14040
+--- /dev/null
++++ b/fs/aufs/rdu.c
+@@ -0,0 +1,328 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * readdir in userspace.
++ */
++
++#include <linux/security.h>
++#include <linux/uaccess.h>
++#include <linux/aufs_type.h>
++#include "aufs.h"
++
++/* bits for struct aufs_rdu.flags */
++#define AuRdu_CALLED 1
++#define AuRdu_CONT (1 << 1)
++#define AuRdu_FULL (1 << 2)
++#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name)
++#define au_fset_rdu(flags, name) { (flags) |= AuRdu_##name; }
++#define au_fclr_rdu(flags, name) { (flags) &= ~AuRdu_##name; }
++
++struct au_rdu_arg {
++ struct aufs_rdu *rdu;
++ union au_rdu_ent_ul ent;
++ unsigned long end;
++
++ struct super_block *sb;
++ int err;
++};
++
++static int au_rdu_fill(void *__arg, const char *name, int nlen,
++ loff_t offset, u64 h_ino, unsigned int d_type)
++{
++ int err, len;
++ struct au_rdu_arg *arg = __arg;
++ struct aufs_rdu *rdu = arg->rdu;
++ struct au_rdu_ent ent;
++
++ err = 0;
++ arg->err = 0;
++ au_fset_rdu(rdu->cookie.flags, CALLED);
++ len = au_rdu_len(nlen);
++ if (arg->ent.ul + len < arg->end) {
++ ent.ino = h_ino;
++ ent.bindex = rdu->cookie.bindex;
++ ent.type = d_type;
++ ent.nlen = nlen;
++
++ err = -EFAULT;
++ if (copy_to_user(arg->ent.e, &ent, sizeof(ent)))
++ goto out;
++ if (copy_to_user(arg->ent.e->name, name, nlen))
++ goto out;
++ /* the terminating NULL */
++ if (__put_user(0, arg->ent.e->name + nlen))
++ goto out;
++ err = 0;
++ /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */
++ arg->ent.ul += len;
++ rdu->rent++;
++ } else {
++ err = -EFAULT;
++ au_fset_rdu(rdu->cookie.flags, FULL);
++ rdu->full = 1;
++ rdu->tail = arg->ent;
++ }
++
++ out:
++ /* AuTraceErr(err); */
++ return err;
++}
++
++static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg)
++{
++ int err;
++ loff_t offset;
++ struct au_rdu_cookie *cookie = &arg->rdu->cookie;
++
++ offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET);
++ err = offset;
++ if (unlikely(offset != cookie->h_pos))
++ goto out;
++
++ err = 0;
++ do {
++ arg->err = 0;
++ au_fclr_rdu(cookie->flags, CALLED);
++ /* smp_mb(); */
++ err = vfsub_readdir(h_file, au_rdu_fill, arg);
++ if (err >= 0)
++ err = arg->err;
++ } while (!err
++ && au_ftest_rdu(cookie->flags, CALLED)
++ && !au_ftest_rdu(cookie->flags, FULL));
++ cookie->h_pos = h_file->f_pos;
++
++ out:
++ AuTraceErr(err);
++ return err;
++}
++
++static int au_rdu(struct file *file, struct aufs_rdu *rdu)
++{
++ int err;
++ aufs_bindex_t bend;
++ struct au_rdu_arg arg;
++ struct dentry *dentry;
++ struct inode *inode;
++ struct file *h_file;
++ struct au_rdu_cookie *cookie = &rdu->cookie;
++
++ err = !access_ok(VERIFY_WRITE, rdu->ent.e, rdu->sz);
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ goto out;
++ }
++ rdu->rent = 0;
++ rdu->tail = rdu->ent;
++ rdu->full = 0;
++ arg.rdu = rdu;
++ arg.ent = rdu->ent;
++ arg.end = arg.ent.ul;
++ arg.end += rdu->sz;
++
++ err = -ENOTDIR;
++ if (unlikely(!file->f_op || !file->f_op->readdir))
++ goto out;
++
++ err = security_file_permission(file, MAY_READ);
++ AuTraceErr(err);
++ if (unlikely(err))
++ goto out;
++
++ dentry = file->f_dentry;
++ inode = dentry->d_inode;
++#if 1
++ mutex_lock(&inode->i_mutex);
++#else
++ err = mutex_lock_killable(&inode->i_mutex);
++ AuTraceErr(err);
++ if (unlikely(err))
++ goto out;
++#endif
++ err = -ENOENT;
++ if (unlikely(IS_DEADDIR(inode)))
++ goto out_mtx;
++
++ arg.sb = inode->i_sb;
++ si_read_lock(arg.sb, AuLock_FLUSH);
++ fi_read_lock(file);
++
++ err = -EAGAIN;
++ if (unlikely(au_ftest_rdu(cookie->flags, CONT)
++ && cookie->generation != au_figen(file)))
++ goto out_unlock;
++
++ err = 0;
++ if (!rdu->blk) {
++ rdu->blk = au_sbi(arg.sb)->si_rdblk;
++ if (!rdu->blk)
++ rdu->blk = au_dir_size(file, /*dentry*/NULL);
++ }
++ bend = au_fbend(file);
++ /* AuDbg("b%d, b%d\n", cookie->bindex, bend); */
++ for (; !err && cookie->bindex <= bend;
++ cookie->bindex++, cookie->h_pos = 0) {
++ h_file = au_h_fptr(file, cookie->bindex);
++ if (!h_file)
++ continue;
++
++ au_fclr_rdu(cookie->flags, FULL);
++ err = au_rdu_do(h_file, &arg);
++ AuTraceErr(err);
++ if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err))
++ break;
++ }
++ AuDbg("rent %llu\n", rdu->rent);
++
++ if (!err && !au_ftest_rdu(cookie->flags, CONT)) {
++ rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH);
++ au_fset_rdu(cookie->flags, CONT);
++ cookie->generation = au_figen(file);
++ }
++
++ ii_read_lock_child(inode);
++ fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibstart(inode)));
++ ii_read_unlock(inode);
++
++ out_unlock:
++ fi_read_unlock(file);
++ si_read_unlock(arg.sb);
++ out_mtx:
++ mutex_unlock(&inode->i_mutex);
++ out:
++ AuTraceErr(err);
++ return err;
++}
++
++static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu)
++{
++ int err;
++ ino_t ino;
++ unsigned long long nent;
++ union au_rdu_ent_ul *u;
++ struct au_rdu_ent ent;
++ struct super_block *sb;
++
++ err = 0;
++ nent = rdu->nent;
++ u = &rdu->ent;
++ sb = file->f_dentry->d_sb;
++ si_read_lock(sb, AuLock_FLUSH);
++ while (nent-- > 0) {
++ err = !access_ok(VERIFY_WRITE, u->e, sizeof(ent));
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ break;
++ }
++
++ err = copy_from_user(&ent, u->e, sizeof(ent));
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ break;
++ }
++
++ /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */
++ if (!ent.wh)
++ err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino);
++ else
++ err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type,
++ &ino);
++ if (unlikely(err)) {
++ AuTraceErr(err);
++ break;
++ }
++
++ err = __put_user(ino, &u->e->ino);
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ break;
++ }
++ u->ul += au_rdu_len(ent.nlen);
++ }
++ si_read_unlock(sb);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_rdu_verify(struct aufs_rdu *rdu)
++{
++ AuDbg("rdu{%llu, %p, (%u, %u) | %u | %llu, %u, %u | "
++ "%llu, b%d, 0x%x, g%u}\n",
++ rdu->sz, rdu->ent.e, rdu->verify[0], rdu->verify[1],
++ rdu->blk,
++ rdu->rent, rdu->shwh, rdu->full,
++ rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags,
++ rdu->cookie.generation);
++
++ if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu)
++ && rdu->verify[AufsCtlRduV_SZ_PTR] == sizeof(rdu))
++ return 0;
++
++ AuDbg("%u:%u, %u:%u\n",
++ rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu),
++ rdu->verify[AufsCtlRduV_SZ_PTR], (unsigned int)sizeof(rdu));
++ return -EINVAL;
++}
++
++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ long err, e;
++ struct aufs_rdu rdu;
++ void __user *p = (void __user *)arg;
++
++ err = copy_from_user(&rdu, p, sizeof(rdu));
++ if (unlikely(err)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ goto out;
++ }
++ err = au_rdu_verify(&rdu);
++ if (unlikely(err))
++ goto out;
++
++ switch (cmd) {
++ case AUFS_CTL_RDU:
++ err = au_rdu(file, &rdu);
++ if (unlikely(err))
++ break;
++
++ e = copy_to_user(p, &rdu, sizeof(rdu));
++ if (unlikely(e)) {
++ err = -EFAULT;
++ AuTraceErr(err);
++ }
++ break;
++ case AUFS_CTL_RDU_INO:
++ err = au_rdu_ino(file, &rdu);
++ break;
++
++ default:
++ err = -EINVAL;
++ }
++
++ out:
++ AuTraceErr(err);
++ return err;
++}
+diff --git a/fs/aufs/rwsem.h b/fs/aufs/rwsem.h
+new file mode 100644
+index 0000000..dfd2c68
+--- /dev/null
++++ b/fs/aufs/rwsem.h
+@@ -0,0 +1,186 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * simple read-write semaphore wrappers
++ */
++
++#ifndef __AUFS_RWSEM_H__
++#define __AUFS_RWSEM_H__
++
++#ifdef __KERNEL__
++
++#include <linux/rwsem.h>
++
++struct au_rwsem {
++ struct rw_semaphore rwsem;
++#ifdef CONFIG_AUFS_DEBUG
++ /* just for debugging, not almighty counter */
++ atomic_t rcnt, wcnt;
++#endif
++};
++
++#ifdef CONFIG_AUFS_DEBUG
++#define AuDbgCntInit(rw) do { \
++ atomic_set(&(rw)->rcnt, 0); \
++ atomic_set(&(rw)->wcnt, 0); \
++ smp_mb(); /* atomic set */ \
++} while (0)
++
++#define AuDbgRcntInc(rw) atomic_inc_return(&(rw)->rcnt)
++#define AuDbgRcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->rcnt) < 0)
++#define AuDbgWcntInc(rw) WARN_ON(atomic_inc_return(&(rw)->wcnt) > 1)
++#define AuDbgWcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->wcnt) < 0)
++#else
++#define AuDbgCntInit(rw) do {} while (0)
++#define AuDbgRcntInc(rw) do {} while (0)
++#define AuDbgRcntDec(rw) do {} while (0)
++#define AuDbgWcntInc(rw) do {} while (0)
++#define AuDbgWcntDec(rw) do {} while (0)
++#endif /* CONFIG_AUFS_DEBUG */
++
++/* to debug easier, do not make them inlined functions */
++#define AuRwMustNoWaiters(rw) AuDebugOn(!list_empty(&(rw)->rwsem.wait_list))
++/* rwsem_is_locked() is unusable */
++#define AuRwMustReadLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0)
++#define AuRwMustWriteLock(rw) AuDebugOn(atomic_read(&(rw)->wcnt) <= 0)
++#define AuRwMustAnyLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0 \
++ && atomic_read(&(rw)->wcnt) <= 0)
++#define AuRwDestroy(rw) AuDebugOn(atomic_read(&(rw)->rcnt) \
++ || atomic_read(&(rw)->wcnt))
++
++static inline void au_rw_init(struct au_rwsem *rw)
++{
++ AuDbgCntInit(rw);
++ init_rwsem(&rw->rwsem);
++}
++
++static inline void au_rw_init_wlock(struct au_rwsem *rw)
++{
++ au_rw_init(rw);
++ down_write(&rw->rwsem);
++ AuDbgWcntInc(rw);
++}
++
++static inline void au_rw_init_wlock_nested(struct au_rwsem *rw,
++ unsigned int lsc)
++{
++ au_rw_init(rw);
++ down_write_nested(&rw->rwsem, lsc);
++ AuDbgWcntInc(rw);
++}
++
++static inline void au_rw_read_lock(struct au_rwsem *rw)
++{
++ down_read(&rw->rwsem);
++ AuDbgRcntInc(rw);
++}
++
++static inline void au_rw_read_lock_nested(struct au_rwsem *rw, unsigned int lsc)
++{
++ down_read_nested(&rw->rwsem, lsc);
++ AuDbgRcntInc(rw);
++}
++
++static inline void au_rw_read_unlock(struct au_rwsem *rw)
++{
++ AuRwMustReadLock(rw);
++ AuDbgRcntDec(rw);
++ up_read(&rw->rwsem);
++}
++
++static inline void au_rw_dgrade_lock(struct au_rwsem *rw)
++{
++ AuRwMustWriteLock(rw);
++ AuDbgRcntInc(rw);
++ AuDbgWcntDec(rw);
++ downgrade_write(&rw->rwsem);
++}
++
++static inline void au_rw_write_lock(struct au_rwsem *rw)
++{
++ down_write(&rw->rwsem);
++ AuDbgWcntInc(rw);
++}
++
++static inline void au_rw_write_lock_nested(struct au_rwsem *rw,
++ unsigned int lsc)
++{
++ down_write_nested(&rw->rwsem, lsc);
++ AuDbgWcntInc(rw);
++}
++
++static inline void au_rw_write_unlock(struct au_rwsem *rw)
++{
++ AuRwMustWriteLock(rw);
++ AuDbgWcntDec(rw);
++ up_write(&rw->rwsem);
++}
++
++/* why is not _nested version defined */
++static inline int au_rw_read_trylock(struct au_rwsem *rw)
++{
++ int ret = down_read_trylock(&rw->rwsem);
++ if (ret)
++ AuDbgRcntInc(rw);
++ return ret;
++}
++
++static inline int au_rw_write_trylock(struct au_rwsem *rw)
++{
++ int ret = down_write_trylock(&rw->rwsem);
++ if (ret)
++ AuDbgWcntInc(rw);
++ return ret;
++}
++
++#undef AuDbgCntInit
++#undef AuDbgRcntInc
++#undef AuDbgRcntDec
++#undef AuDbgWcntInc
++#undef AuDbgWcntDec
++
++#define AuSimpleLockRwsemFuncs(prefix, param, rwsem) \
++static inline void prefix##_read_lock(param) \
++{ au_rw_read_lock(rwsem); } \
++static inline void prefix##_write_lock(param) \
++{ au_rw_write_lock(rwsem); } \
++static inline int prefix##_read_trylock(param) \
++{ return au_rw_read_trylock(rwsem); } \
++static inline int prefix##_write_trylock(param) \
++{ return au_rw_write_trylock(rwsem); }
++/* why is not _nested version defined */
++/* static inline void prefix##_read_trylock_nested(param, lsc)
++{ au_rw_read_trylock_nested(rwsem, lsc)); }
++static inline void prefix##_write_trylock_nestd(param, lsc)
++{ au_rw_write_trylock_nested(rwsem, lsc); } */
++
++#define AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) \
++static inline void prefix##_read_unlock(param) \
++{ au_rw_read_unlock(rwsem); } \
++static inline void prefix##_write_unlock(param) \
++{ au_rw_write_unlock(rwsem); } \
++static inline void prefix##_downgrade_lock(param) \
++{ au_rw_dgrade_lock(rwsem); }
++
++#define AuSimpleRwsemFuncs(prefix, param, rwsem) \
++ AuSimpleLockRwsemFuncs(prefix, param, rwsem) \
++ AuSimpleUnlockRwsemFuncs(prefix, param, rwsem)
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_RWSEM_H__ */
+diff --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c
+new file mode 100644
+index 0000000..f0650e5
+--- /dev/null
++++ b/fs/aufs/sbinfo.c
+@@ -0,0 +1,208 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * superblock private data
++ */
++
++#include "aufs.h"
++
++/*
++ * they are necessary regardless sysfs is disabled.
++ */
++void au_si_free(struct kobject *kobj)
++{
++ struct au_sbinfo *sbinfo;
++ struct super_block *sb;
++
++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
++ AuDebugOn(!list_empty(&sbinfo->si_plink.head));
++
++ sb = sbinfo->si_sb;
++ si_write_lock(sb);
++ au_xino_clr(sb);
++ au_br_free(sbinfo);
++ kfree(sbinfo->si_branch);
++ mutex_destroy(&sbinfo->si_xib_mtx);
++ si_write_unlock(sb);
++ AuRwDestroy(&sbinfo->si_rwsem);
++
++ kfree(sbinfo);
++}
++
++int au_si_alloc(struct super_block *sb)
++{
++ int err;
++ struct au_sbinfo *sbinfo;
++
++ err = -ENOMEM;
++ sbinfo = kmalloc(sizeof(*sbinfo), GFP_NOFS);
++ if (unlikely(!sbinfo))
++ goto out;
++
++ /* will be reallocated separately */
++ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS);
++ if (unlikely(!sbinfo->si_branch))
++ goto out_sbinfo;
++
++ memset(&sbinfo->si_kobj, 0, sizeof(sbinfo->si_kobj));
++ err = sysaufs_si_init(sbinfo);
++ if (unlikely(err))
++ goto out_br;
++
++ au_nwt_init(&sbinfo->si_nowait);
++ au_rw_init_wlock(&sbinfo->si_rwsem);
++ sbinfo->si_generation = 0;
++ sbinfo->au_si_status = 0;
++ sbinfo->si_bend = -1;
++ sbinfo->si_last_br_id = 0;
++
++ sbinfo->si_wbr_copyup = AuWbrCopyup_Def;
++ sbinfo->si_wbr_create = AuWbrCreate_Def;
++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + AuWbrCopyup_Def;
++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + AuWbrCreate_Def;
++
++ sbinfo->si_mntflags = AuOpt_Def;
++
++ sbinfo->si_xread = NULL;
++ sbinfo->si_xwrite = NULL;
++ sbinfo->si_xib = NULL;
++ mutex_init(&sbinfo->si_xib_mtx);
++ sbinfo->si_xib_buf = NULL;
++ sbinfo->si_xino_brid = -1;
++ /* leave si_xib_last_pindex and si_xib_next_bit */
++
++ sbinfo->si_rdcache = AUFS_RDCACHE_DEF * HZ;
++ sbinfo->si_rdblk = AUFS_RDBLK_DEF;
++ sbinfo->si_rdhash = AUFS_RDHASH_DEF;
++ sbinfo->si_dirwh = AUFS_DIRWH_DEF;
++
++ au_spl_init(&sbinfo->si_plink);
++ init_waitqueue_head(&sbinfo->si_plink_wq);
++
++ /* leave other members for sysaufs and si_mnt. */
++ sbinfo->si_sb = sb;
++ sb->s_fs_info = sbinfo;
++ au_debug_sbinfo_init(sbinfo);
++ return 0; /* success */
++
++ out_br:
++ kfree(sbinfo->si_branch);
++ out_sbinfo:
++ kfree(sbinfo);
++ out:
++ return err;
++}
++
++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr)
++{
++ int err, sz;
++ struct au_branch **brp;
++
++ AuRwMustWriteLock(&sbinfo->si_rwsem);
++
++ err = -ENOMEM;
++ sz = sizeof(*brp) * (sbinfo->si_bend + 1);
++ if (unlikely(!sz))
++ sz = sizeof(*brp);
++ brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS);
++ if (brp) {
++ sbinfo->si_branch = brp;
++ err = 0;
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++unsigned int au_sigen_inc(struct super_block *sb)
++{
++ unsigned int gen;
++
++ SiMustWriteLock(sb);
++
++ gen = ++au_sbi(sb)->si_generation;
++ au_update_digen(sb->s_root);
++ au_update_iigen(sb->s_root->d_inode);
++ sb->s_root->d_inode->i_version++;
++ return gen;
++}
++
++aufs_bindex_t au_new_br_id(struct super_block *sb)
++{
++ aufs_bindex_t br_id;
++ int i;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ for (i = 0; i <= AUFS_BRANCH_MAX; i++) {
++ br_id = ++sbinfo->si_last_br_id;
++ if (br_id && au_br_index(sb, br_id) < 0)
++ return br_id;
++ }
++
++ return -1;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* dentry and super_block lock. call at entry point */
++void aufs_read_lock(struct dentry *dentry, int flags)
++{
++ si_read_lock(dentry->d_sb, flags);
++ if (au_ftest_lock(flags, DW))
++ di_write_lock_child(dentry);
++ else
++ di_read_lock_child(dentry, flags);
++}
++
++void aufs_read_unlock(struct dentry *dentry, int flags)
++{
++ if (au_ftest_lock(flags, DW))
++ di_write_unlock(dentry);
++ else
++ di_read_unlock(dentry, flags);
++ si_read_unlock(dentry->d_sb);
++}
++
++void aufs_write_lock(struct dentry *dentry)
++{
++ si_write_lock(dentry->d_sb);
++ di_write_lock_child(dentry);
++}
++
++void aufs_write_unlock(struct dentry *dentry)
++{
++ di_write_unlock(dentry);
++ si_write_unlock(dentry->d_sb);
++}
++
++void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags)
++{
++ si_read_lock(d1->d_sb, flags);
++ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR));
++}
++
++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2)
++{
++ di_write_unlock2(d1, d2);
++ si_read_unlock(d1->d_sb);
++}
+diff --git a/fs/aufs/spl.h b/fs/aufs/spl.h
+new file mode 100644
+index 0000000..bcbbd9a
+--- /dev/null
++++ b/fs/aufs/spl.h
+@@ -0,0 +1,57 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * simple list protected by a spinlock
++ */
++
++#ifndef __AUFS_SPL_H__
++#define __AUFS_SPL_H__
++
++#ifdef __KERNEL__
++
++#include <linux/spinlock.h>
++#include <linux/list.h>
++
++struct au_splhead {
++ spinlock_t spin;
++ struct list_head head;
++};
++
++static inline void au_spl_init(struct au_splhead *spl)
++{
++ spin_lock_init(&spl->spin);
++ INIT_LIST_HEAD(&spl->head);
++}
++
++static inline void au_spl_add(struct list_head *list, struct au_splhead *spl)
++{
++ spin_lock(&spl->spin);
++ list_add(list, &spl->head);
++ spin_unlock(&spl->spin);
++}
++
++static inline void au_spl_del(struct list_head *list, struct au_splhead *spl)
++{
++ spin_lock(&spl->spin);
++ list_del(list);
++ spin_unlock(&spl->spin);
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_SPL_H__ */
+diff --git a/fs/aufs/super.c b/fs/aufs/super.c
+new file mode 100644
+index 0000000..f5ee1fc
+--- /dev/null
++++ b/fs/aufs/super.c
+@@ -0,0 +1,874 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * mount and super_block operations
++ */
++
++#include <linux/buffer_head.h>
++#include <linux/module.h>
++#include <linux/seq_file.h>
++#include <linux/statfs.h>
++#include "aufs.h"
++
++/*
++ * super_operations
++ */
++static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused)
++{
++ struct au_icntnr *c;
++
++ c = au_cache_alloc_icntnr();
++ if (c) {
++ inode_init_once(&c->vfs_inode);
++ c->vfs_inode.i_version = 1; /* sigen(sb); */
++ c->iinfo.ii_hinode = NULL;
++ return &c->vfs_inode;
++ }
++ return NULL;
++}
++
++static void aufs_destroy_inode(struct inode *inode)
++{
++ au_iinfo_fin(inode);
++ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode));
++}
++
++struct inode *au_iget_locked(struct super_block *sb, ino_t ino)
++{
++ struct inode *inode;
++ int err;
++
++ inode = iget_locked(sb, ino);
++ if (unlikely(!inode)) {
++ inode = ERR_PTR(-ENOMEM);
++ goto out;
++ }
++ if (!(inode->i_state & I_NEW))
++ goto out;
++
++ err = au_xigen_new(inode);
++ if (!err)
++ err = au_iinfo_init(inode);
++ if (!err)
++ inode->i_version++;
++ else {
++ iget_failed(inode);
++ inode = ERR_PTR(err);
++ }
++
++ out:
++ /* never return NULL */
++ AuDebugOn(!inode);
++ AuTraceErrPtr(inode);
++ return inode;
++}
++
++/* lock free root dinfo */
++static int au_show_brs(struct seq_file *seq, struct super_block *sb)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ struct path path;
++ struct au_hdentry *hd;
++ struct au_branch *br;
++
++ err = 0;
++ bend = au_sbend(sb);
++ hd = au_di(sb->s_root)->di_hdentry;
++ for (bindex = 0; !err && bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ path.mnt = br->br_mnt;
++ path.dentry = hd[bindex].hd_dentry;
++ err = au_seq_path(seq, &path);
++ if (err > 0)
++ err = seq_printf(seq, "=%s",
++ au_optstr_br_perm(br->br_perm));
++ if (!err && bindex != bend)
++ err = seq_putc(seq, ':');
++ }
++
++ return err;
++}
++
++static void au_show_wbr_create(struct seq_file *m, int v,
++ struct au_sbinfo *sbinfo)
++{
++ const char *pat;
++
++ AuRwMustAnyLock(&sbinfo->si_rwsem);
++
++ seq_printf(m, ",create=");
++ pat = au_optstr_wbr_create(v);
++ switch (v) {
++ case AuWbrCreate_TDP:
++ case AuWbrCreate_RR:
++ case AuWbrCreate_MFS:
++ case AuWbrCreate_PMFS:
++ seq_printf(m, pat);
++ break;
++ case AuWbrCreate_MFSV:
++ seq_printf(m, /*pat*/"mfs:%lu",
++ sbinfo->si_wbr_mfs.mfs_expire / HZ);
++ break;
++ case AuWbrCreate_PMFSV:
++ seq_printf(m, /*pat*/"pmfs:%lu",
++ sbinfo->si_wbr_mfs.mfs_expire / HZ);
++ break;
++ case AuWbrCreate_MFSRR:
++ seq_printf(m, /*pat*/"mfsrr:%llu",
++ sbinfo->si_wbr_mfs.mfsrr_watermark);
++ break;
++ case AuWbrCreate_MFSRRV:
++ seq_printf(m, /*pat*/"mfsrr:%llu:%lu",
++ sbinfo->si_wbr_mfs.mfsrr_watermark,
++ sbinfo->si_wbr_mfs.mfs_expire / HZ);
++ break;
++ }
++}
++
++static int au_show_xino(struct seq_file *seq, struct vfsmount *mnt)
++{
++#ifdef CONFIG_SYSFS
++ return 0;
++#else
++ int err;
++ const int len = sizeof(AUFS_XINO_FNAME) - 1;
++ aufs_bindex_t bindex, brid;
++ struct super_block *sb;
++ struct qstr *name;
++ struct file *f;
++ struct dentry *d, *h_root;
++
++ AuRwMustAnyLock(&sbinfo->si_rwsem);
++
++ err = 0;
++ sb = mnt->mnt_sb;
++ f = au_sbi(sb)->si_xib;
++ if (!f)
++ goto out;
++
++ /* stop printing the default xino path on the first writable branch */
++ h_root = NULL;
++ brid = au_xino_brid(sb);
++ if (brid >= 0) {
++ bindex = au_br_index(sb, brid);
++ h_root = au_di(sb->s_root)->di_hdentry[0 + bindex].hd_dentry;
++ }
++ d = f->f_dentry;
++ name = &d->d_name;
++ /* safe ->d_parent because the file is unlinked */
++ if (d->d_parent == h_root
++ && name->len == len
++ && !memcmp(name->name, AUFS_XINO_FNAME, len))
++ goto out;
++
++ seq_puts(seq, ",xino=");
++ err = au_xino_path(seq, f);
++
++ out:
++ return err;
++#endif
++}
++
++/* seq_file will re-call me in case of too long string */
++static int aufs_show_options(struct seq_file *m, struct vfsmount *mnt)
++{
++ int err, n;
++ unsigned int mnt_flags, v;
++ struct super_block *sb;
++ struct au_sbinfo *sbinfo;
++
++#define AuBool(name, str) do { \
++ v = au_opt_test(mnt_flags, name); \
++ if (v != au_opt_test(AuOpt_Def, name)) \
++ seq_printf(m, ",%s" #str, v ? "" : "no"); \
++} while (0)
++
++#define AuStr(name, str) do { \
++ v = mnt_flags & AuOptMask_##name; \
++ if (v != (AuOpt_Def & AuOptMask_##name)) \
++ seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \
++} while (0)
++
++#define AuUInt(name, str, val) do { \
++ if (val != AUFS_##name##_DEF) \
++ seq_printf(m, "," #str "=%u", val); \
++} while (0)
++
++ /* lock free root dinfo */
++ sb = mnt->mnt_sb;
++ si_noflush_read_lock(sb);
++ sbinfo = au_sbi(sb);
++ seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo));
++
++ mnt_flags = au_mntflags(sb);
++ if (au_opt_test(mnt_flags, XINO)) {
++ err = au_show_xino(m, mnt);
++ if (unlikely(err))
++ goto out;
++ } else
++ seq_puts(m, ",noxino");
++
++ AuBool(TRUNC_XINO, trunc_xino);
++ AuStr(UDBA, udba);
++ AuBool(SHWH, shwh);
++ AuBool(PLINK, plink);
++ /* AuBool(DIRPERM1, dirperm1); */
++ /* AuBool(REFROF, refrof); */
++
++ v = sbinfo->si_wbr_create;
++ if (v != AuWbrCreate_Def)
++ au_show_wbr_create(m, v, sbinfo);
++
++ v = sbinfo->si_wbr_copyup;
++ if (v != AuWbrCopyup_Def)
++ seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v));
++
++ v = au_opt_test(mnt_flags, ALWAYS_DIROPQ);
++ if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ))
++ seq_printf(m, ",diropq=%c", v ? 'a' : 'w');
++
++ AuUInt(DIRWH, dirwh, sbinfo->si_dirwh);
++
++ n = sbinfo->si_rdcache / HZ;
++ AuUInt(RDCACHE, rdcache, n);
++
++ AuUInt(RDBLK, rdblk, sbinfo->si_rdblk);
++ AuUInt(RDHASH, rdhash, sbinfo->si_rdhash);
++
++ AuBool(SUM, sum);
++ /* AuBool(SUM_W, wsum); */
++ AuBool(WARN_PERM, warn_perm);
++ AuBool(VERBOSE, verbose);
++
++ out:
++ /* be sure to print "br:" last */
++ if (!sysaufs_brs) {
++ seq_puts(m, ",br:");
++ au_show_brs(m, sb);
++ }
++ si_read_unlock(sb);
++ return 0;
++
++#undef Deleted
++#undef AuBool
++#undef AuStr
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* sum mode which returns the summation for statfs(2) */
++
++static u64 au_add_till_max(u64 a, u64 b)
++{
++ u64 old;
++
++ old = a;
++ a += b;
++ if (old < a)
++ return a;
++ return ULLONG_MAX;
++}
++
++static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf)
++{
++ int err;
++ u64 blocks, bfree, bavail, files, ffree;
++ aufs_bindex_t bend, bindex, i;
++ unsigned char shared;
++ struct vfsmount *h_mnt;
++ struct super_block *h_sb;
++
++ blocks = 0;
++ bfree = 0;
++ bavail = 0;
++ files = 0;
++ ffree = 0;
++
++ err = 0;
++ bend = au_sbend(sb);
++ for (bindex = bend; bindex >= 0; bindex--) {
++ h_mnt = au_sbr_mnt(sb, bindex);
++ h_sb = h_mnt->mnt_sb;
++ shared = 0;
++ for (i = bindex + 1; !shared && i <= bend; i++)
++ shared = (au_sbr_sb(sb, i) == h_sb);
++ if (shared)
++ continue;
++
++ /* sb->s_root for NFS is unreliable */
++ err = vfs_statfs(h_mnt->mnt_root, buf);
++ if (unlikely(err))
++ goto out;
++
++ blocks = au_add_till_max(blocks, buf->f_blocks);
++ bfree = au_add_till_max(bfree, buf->f_bfree);
++ bavail = au_add_till_max(bavail, buf->f_bavail);
++ files = au_add_till_max(files, buf->f_files);
++ ffree = au_add_till_max(ffree, buf->f_ffree);
++ }
++
++ buf->f_blocks = blocks;
++ buf->f_bfree = bfree;
++ buf->f_bavail = bavail;
++ buf->f_files = files;
++ buf->f_ffree = ffree;
++
++ out:
++ return err;
++}
++
++static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++ int err;
++ struct super_block *sb;
++
++ /* lock free root dinfo */
++ sb = dentry->d_sb;
++ si_noflush_read_lock(sb);
++ if (!au_opt_test(au_mntflags(sb), SUM))
++ /* sb->s_root for NFS is unreliable */
++ err = vfs_statfs(au_sbr_mnt(sb, 0)->mnt_root, buf);
++ else
++ err = au_statfs_sum(sb, buf);
++ si_read_unlock(sb);
++
++ if (!err) {
++ buf->f_type = AUFS_SUPER_MAGIC;
++ buf->f_namelen -= AUFS_WH_PFX_LEN;
++ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid));
++ }
++ /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* try flushing the lower fs at aufs remount/unmount time */
++
++static void au_fsync_br(struct super_block *sb)
++{
++ aufs_bindex_t bend, bindex;
++ int brperm;
++ struct au_branch *br;
++ struct super_block *h_sb;
++
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex < bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ brperm = br->br_perm;
++ if (brperm == AuBrPerm_RR || brperm == AuBrPerm_RRWH)
++ continue;
++ h_sb = br->br_mnt->mnt_sb;
++ if (bdev_read_only(h_sb->s_bdev))
++ continue;
++
++ lockdep_off();
++ down_write(&h_sb->s_umount);
++ shrink_dcache_sb(h_sb);
++ fsync_super(h_sb);
++ up_write(&h_sb->s_umount);
++ lockdep_on();
++ }
++}
++
++/*
++ * this IS NOT for super_operations.
++ * I guess it will be reverted someday.
++ */
++static void aufs_umount_begin(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ sbinfo = au_sbi(sb);
++ if (!sbinfo)
++ return;
++
++ si_write_lock(sb);
++ au_fsync_br(sb);
++ if (au_opt_test(au_mntflags(sb), PLINK))
++ au_plink_put(sb);
++ if (sbinfo->si_wbr_create_ops->fin)
++ sbinfo->si_wbr_create_ops->fin(sb);
++ si_write_unlock(sb);
++}
++
++/* final actions when unmounting a file system */
++static void aufs_put_super(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ sbinfo = au_sbi(sb);
++ if (!sbinfo)
++ return;
++
++ aufs_umount_begin(sb);
++ dbgaufs_si_fin(sbinfo);
++ kobject_put(&sbinfo->si_kobj);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * refresh dentry and inode at remount time.
++ */
++static int do_refresh(struct dentry *dentry, mode_t type,
++ unsigned int dir_flags)
++{
++ int err;
++ struct dentry *parent;
++
++ di_write_lock_child(dentry);
++ parent = dget_parent(dentry);
++ di_read_lock_parent(parent, AuLock_IR);
++
++ /* returns the number of positive dentries */
++ err = au_refresh_hdentry(dentry, type);
++ if (err >= 0) {
++ struct inode *inode = dentry->d_inode;
++ err = au_refresh_hinode(inode, dentry);
++ if (!err && type == S_IFDIR)
++ au_reset_hinotify(inode, dir_flags);
++ }
++ if (unlikely(err))
++ AuErr("unrecoverable error %d, %.*s\n", err, AuDLNPair(dentry));
++
++ di_read_unlock(parent, AuLock_IR);
++ dput(parent);
++ di_write_unlock(dentry);
++
++ return err;
++}
++
++static int test_dir(struct dentry *dentry, void *arg __maybe_unused)
++{
++ return S_ISDIR(dentry->d_inode->i_mode);
++}
++
++/* gave up consolidating with refresh_nondir() */
++static int refresh_dir(struct dentry *root, unsigned int sigen)
++{
++ int err, i, j, ndentry, e;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry **dentries;
++ struct inode *inode;
++ const unsigned int flags = au_hi_flags(root->d_inode, /*isdir*/1);
++
++ err = 0;
++ list_for_each_entry(inode, &root->d_sb->s_inodes, i_sb_list)
++ if (S_ISDIR(inode->i_mode) && au_iigen(inode) != sigen) {
++ ii_write_lock_child(inode);
++ e = au_refresh_hinode_self(inode, /*do_attr*/1);
++ ii_write_unlock(inode);
++ if (unlikely(e)) {
++ AuDbg("e %d, i%lu\n", e, inode->i_ino);
++ if (!err)
++ err = e;
++ /* go on even if err */
++ }
++ }
++
++ e = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(e)) {
++ if (!err)
++ err = e;
++ goto out;
++ }
++ e = au_dcsub_pages(&dpages, root, test_dir, NULL);
++ if (unlikely(e)) {
++ if (!err)
++ err = e;
++ goto out_dpages;
++ }
++
++ for (i = 0; !e && i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ dentries = dpage->dentries;
++ ndentry = dpage->ndentry;
++ for (j = 0; !e && j < ndentry; j++) {
++ struct dentry *d;
++
++ d = dentries[j];
++ au_dbg_verify_dir_parent(d, sigen);
++ if (au_digen(d) != sigen) {
++ e = do_refresh(d, S_IFDIR, flags);
++ if (unlikely(e && !err))
++ err = e;
++ /* break on err */
++ }
++ }
++ }
++
++ out_dpages:
++ au_dpages_free(&dpages);
++ out:
++ return err;
++}
++
++static int test_nondir(struct dentry *dentry, void *arg __maybe_unused)
++{
++ return !S_ISDIR(dentry->d_inode->i_mode);
++}
++
++static int refresh_nondir(struct dentry *root, unsigned int sigen,
++ int do_dentry)
++{
++ int err, i, j, ndentry, e;
++ struct au_dcsub_pages dpages;
++ struct au_dpage *dpage;
++ struct dentry **dentries;
++ struct inode *inode;
++
++ err = 0;
++ list_for_each_entry(inode, &root->d_sb->s_inodes, i_sb_list)
++ if (!S_ISDIR(inode->i_mode) && au_iigen(inode) != sigen) {
++ ii_write_lock_child(inode);
++ e = au_refresh_hinode_self(inode, /*do_attr*/1);
++ ii_write_unlock(inode);
++ if (unlikely(e)) {
++ AuDbg("e %d, i%lu\n", e, inode->i_ino);
++ if (!err)
++ err = e;
++ /* go on even if err */
++ }
++ }
++
++ if (!do_dentry)
++ goto out;
++
++ e = au_dpages_init(&dpages, GFP_NOFS);
++ if (unlikely(e)) {
++ if (!err)
++ err = e;
++ goto out;
++ }
++ e = au_dcsub_pages(&dpages, root, test_nondir, NULL);
++ if (unlikely(e)) {
++ if (!err)
++ err = e;
++ goto out_dpages;
++ }
++
++ for (i = 0; i < dpages.ndpage; i++) {
++ dpage = dpages.dpages + i;
++ dentries = dpage->dentries;
++ ndentry = dpage->ndentry;
++ for (j = 0; j < ndentry; j++) {
++ struct dentry *d;
++
++ d = dentries[j];
++ au_dbg_verify_nondir_parent(d, sigen);
++ inode = d->d_inode;
++ if (inode && au_digen(d) != sigen) {
++ e = do_refresh(d, inode->i_mode & S_IFMT,
++ /*dir_flags*/0);
++ if (unlikely(e && !err))
++ err = e;
++ /* go on even err */
++ }
++ }
++ }
++
++ out_dpages:
++ au_dpages_free(&dpages);
++ out:
++ return err;
++}
++
++static void au_remount_refresh(struct super_block *sb, unsigned int flags)
++{
++ int err;
++ unsigned int sigen;
++ struct au_sbinfo *sbinfo;
++ struct dentry *root;
++ struct inode *inode;
++
++ au_sigen_inc(sb);
++ sigen = au_sigen(sb);
++ sbinfo = au_sbi(sb);
++ au_fclr_si(sbinfo, FAILED_REFRESH_DIRS);
++
++ root = sb->s_root;
++ DiMustNoWaiters(root);
++ inode = root->d_inode;
++ IiMustNoWaiters(inode);
++ au_reset_hinotify(inode, au_hi_flags(inode, /*isdir*/1));
++ di_write_unlock(root);
++
++ err = refresh_dir(root, sigen);
++ if (unlikely(err)) {
++ au_fset_si(sbinfo, FAILED_REFRESH_DIRS);
++ AuWarn("Refreshing directories failed, ignored (%d)\n", err);
++ }
++
++ if (au_ftest_opts(flags, REFRESH_NONDIR)) {
++ err = refresh_nondir(root, sigen, !err);
++ if (unlikely(err))
++ AuWarn("Refreshing non-directories failed, ignored"
++ "(%d)\n", err);
++ }
++
++ /* aufs_write_lock() calls ..._child() */
++ di_write_lock_child(root);
++ au_cpup_attr_all(root->d_inode, /*force*/1);
++}
++
++/* stop extra interpretation of errno in mount(8), and strange error messages */
++static int cvt_err(int err)
++{
++ AuTraceErr(err);
++
++ switch (err) {
++ case -ENOENT:
++ case -ENOTDIR:
++ case -EEXIST:
++ case -EIO:
++ err = -EINVAL;
++ }
++ return err;
++}
++
++static int aufs_remount_fs(struct super_block *sb, int *flags, char *data)
++{
++ int err;
++ struct au_opts opts;
++ struct dentry *root;
++ struct inode *inode;
++ struct au_sbinfo *sbinfo;
++
++ err = 0;
++ root = sb->s_root;
++ if (!data || !*data) {
++ aufs_write_lock(root);
++ err = au_opts_verify(sb, *flags, /*pending*/0);
++ if (!err)
++ au_fsync_br(sb);
++ aufs_write_unlock(root);
++ goto out;
++ }
++
++ err = -ENOMEM;
++ memset(&opts, 0, sizeof(opts));
++ opts.opt = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!opts.opt))
++ goto out;
++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt);
++ opts.flags = AuOpts_REMOUNT;
++ opts.sb_flags = *flags;
++
++ /* parse it before aufs lock */
++ err = au_opts_parse(sb, data, &opts);
++ if (unlikely(err))
++ goto out_opts;
++
++ sbinfo = au_sbi(sb);
++ inode = root->d_inode;
++ mutex_lock(&inode->i_mutex);
++ aufs_write_lock(root);
++ au_fsync_br(sb);
++
++ /* au_opts_remount() may return an error */
++ err = au_opts_remount(sb, &opts);
++ au_opts_free(&opts);
++
++ if (au_ftest_opts(opts.flags, REFRESH_DIR)
++ || au_ftest_opts(opts.flags, REFRESH_NONDIR))
++ au_remount_refresh(sb, opts.flags);
++
++ aufs_write_unlock(root);
++ mutex_unlock(&inode->i_mutex);
++
++ out_opts:
++ free_page((unsigned long)opts.opt);
++ out:
++ err = cvt_err(err);
++ AuTraceErr(err);
++ return err;
++}
++
++static struct super_operations aufs_sop = {
++ .alloc_inode = aufs_alloc_inode,
++ .destroy_inode = aufs_destroy_inode,
++ .drop_inode = generic_delete_inode,
++ .show_options = aufs_show_options,
++ .statfs = aufs_statfs,
++ .put_super = aufs_put_super,
++ .remount_fs = aufs_remount_fs
++};
++
++/* ---------------------------------------------------------------------- */
++
++static int alloc_root(struct super_block *sb)
++{
++ int err;
++ struct inode *inode;
++ struct dentry *root;
++
++ err = -ENOMEM;
++ inode = au_iget_locked(sb, AUFS_ROOT_INO);
++ err = PTR_ERR(inode);
++ if (IS_ERR(inode))
++ goto out;
++
++ inode->i_op = &aufs_dir_iop;
++ inode->i_fop = &aufs_dir_fop;
++ inode->i_mode = S_IFDIR;
++ inode->i_nlink = 2;
++ unlock_new_inode(inode);
++
++ root = d_alloc_root(inode);
++ if (unlikely(!root))
++ goto out_iput;
++ err = PTR_ERR(root);
++ if (IS_ERR(root))
++ goto out_iput;
++
++ err = au_alloc_dinfo(root);
++ if (!err) {
++ sb->s_root = root;
++ return 0; /* success */
++ }
++ dput(root);
++ goto out; /* do not iput */
++
++ out_iput:
++ iget_failed(inode);
++ iput(inode);
++ out:
++ return err;
++
++}
++
++static int aufs_fill_super(struct super_block *sb, void *raw_data,
++ int silent __maybe_unused)
++{
++ int err;
++ struct au_opts opts;
++ struct dentry *root;
++ struct inode *inode;
++ char *arg = raw_data;
++
++ if (unlikely(!arg || !*arg)) {
++ err = -EINVAL;
++ AuErr("no arg\n");
++ goto out;
++ }
++
++ err = -ENOMEM;
++ memset(&opts, 0, sizeof(opts));
++ opts.opt = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!opts.opt))
++ goto out;
++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt);
++ opts.sb_flags = sb->s_flags;
++
++ err = au_si_alloc(sb);
++ if (unlikely(err))
++ goto out_opts;
++
++ /* all timestamps always follow the ones on the branch */
++ sb->s_flags |= MS_NOATIME | MS_NODIRATIME;
++ sb->s_op = &aufs_sop;
++ sb->s_magic = AUFS_SUPER_MAGIC;
++ sb->s_maxbytes = 0;
++ au_export_init(sb);
++
++ err = alloc_root(sb);
++ if (unlikely(err)) {
++ si_write_unlock(sb);
++ goto out_info;
++ }
++ root = sb->s_root;
++ inode = root->d_inode;
++
++ /*
++ * actually we can parse options regardless aufs lock here.
++ * but at remount time, parsing must be done before aufs lock.
++ * so we follow the same rule.
++ */
++ ii_write_lock_parent(inode);
++ aufs_write_unlock(root);
++ err = au_opts_parse(sb, arg, &opts);
++ if (unlikely(err))
++ goto out_root;
++
++ /* lock vfs_inode first, then aufs. */
++ mutex_lock(&inode->i_mutex);
++ inode->i_op = &aufs_dir_iop;
++ inode->i_fop = &aufs_dir_fop;
++ aufs_write_lock(root);
++ err = au_opts_mount(sb, &opts);
++ au_opts_free(&opts);
++ if (unlikely(err))
++ goto out_unlock;
++ aufs_write_unlock(root);
++ mutex_unlock(&inode->i_mutex);
++ goto out_opts; /* success */
++
++ out_unlock:
++ aufs_write_unlock(root);
++ mutex_unlock(&inode->i_mutex);
++ out_root:
++ dput(root);
++ sb->s_root = NULL;
++ out_info:
++ kobject_put(&au_sbi(sb)->si_kobj);
++ sb->s_fs_info = NULL;
++ out_opts:
++ free_page((unsigned long)opts.opt);
++ out:
++ AuTraceErr(err);
++ err = cvt_err(err);
++ AuTraceErr(err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int aufs_get_sb(struct file_system_type *fs_type, int flags,
++ const char *dev_name __maybe_unused, void *raw_data,
++ struct vfsmount *mnt)
++{
++ int err;
++ struct super_block *sb;
++
++ /* all timestamps always follow the ones on the branch */
++ /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */
++ err = get_sb_nodev(fs_type, flags, raw_data, aufs_fill_super, mnt);
++ if (!err) {
++ sb = mnt->mnt_sb;
++ si_write_lock(sb);
++ sysaufs_brs_add(sb, 0);
++ si_write_unlock(sb);
++ }
++ return err;
++}
++
++struct file_system_type aufs_fs_type = {
++ .name = AUFS_FSTYPE,
++ .fs_flags =
++ FS_RENAME_DOES_D_MOVE /* a race between rename and others */
++ | FS_REVAL_DOT, /* for NFS branch and udba */
++ .get_sb = aufs_get_sb,
++ .kill_sb = generic_shutdown_super,
++ /* no need to __module_get() and module_put(). */
++ .owner = THIS_MODULE,
++};
+diff --git a/fs/aufs/super.h b/fs/aufs/super.h
+new file mode 100644
+index 0000000..850cddb
+--- /dev/null
++++ b/fs/aufs/super.h
+@@ -0,0 +1,384 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * super_block operations
++ */
++
++#ifndef __AUFS_SUPER_H__
++#define __AUFS_SUPER_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/aufs_type.h>
++#include "rwsem.h"
++#include "spl.h"
++#include "wkq.h"
++
++typedef ssize_t (*au_readf_t)(struct file *, char __user *, size_t, loff_t *);
++typedef ssize_t (*au_writef_t)(struct file *, const char __user *, size_t,
++ loff_t *);
++
++/* policies to select one among multiple writable branches */
++struct au_wbr_copyup_operations {
++ int (*copyup)(struct dentry *dentry);
++};
++
++struct au_wbr_create_operations {
++ int (*create)(struct dentry *dentry, int isdir);
++ int (*init)(struct super_block *sb);
++ int (*fin)(struct super_block *sb);
++};
++
++struct au_wbr_mfs {
++ struct mutex mfs_lock; /* protect this structure */
++ unsigned long mfs_jiffy;
++ unsigned long mfs_expire;
++ aufs_bindex_t mfs_bindex;
++
++ unsigned long long mfsrr_bytes;
++ unsigned long long mfsrr_watermark;
++};
++
++struct au_branch;
++struct au_sbinfo {
++ /* nowait tasks in the system-wide workqueue */
++ struct au_nowait_tasks si_nowait;
++
++ struct au_rwsem si_rwsem;
++
++ /* branch management */
++ unsigned int si_generation;
++
++ /* see above flags */
++ unsigned char au_si_status;
++
++ aufs_bindex_t si_bend;
++ aufs_bindex_t si_last_br_id;
++ struct au_branch **si_branch;
++
++ /* policy to select a writable branch */
++ unsigned char si_wbr_copyup;
++ unsigned char si_wbr_create;
++ struct au_wbr_copyup_operations *si_wbr_copyup_ops;
++ struct au_wbr_create_operations *si_wbr_create_ops;
++
++ /* round robin */
++ atomic_t si_wbr_rr_next;
++
++ /* most free space */
++ struct au_wbr_mfs si_wbr_mfs;
++
++ /* mount flags */
++ /* include/asm-ia64/siginfo.h defines a macro named si_flags */
++ unsigned int si_mntflags;
++
++ /* external inode number (bitmap and translation table) */
++ au_readf_t si_xread;
++ au_writef_t si_xwrite;
++ struct file *si_xib;
++ struct mutex si_xib_mtx; /* protect xib members */
++ unsigned long *si_xib_buf;
++ unsigned long si_xib_last_pindex;
++ int si_xib_next_bit;
++ aufs_bindex_t si_xino_brid;
++ /* reserved for future use */
++ /* unsigned long long si_xib_limit; */ /* Max xib file size */
++
++#ifdef CONFIG_AUFS_EXPORT
++ /* i_generation */
++ struct file *si_xigen;
++ atomic_t si_xigen_next;
++#endif
++
++ /* vdir parameters */
++ unsigned long si_rdcache; /* max cache time in HZ */
++ unsigned int si_rdblk; /* deblk size */
++ unsigned int si_rdhash; /* hash size */
++
++ /*
++ * If the number of whiteouts are larger than si_dirwh, leave all of
++ * them after au_whtmp_ren to reduce the cost of rmdir(2).
++ * future fsck.aufs or kernel thread will remove them later.
++ * Otherwise, remove all whiteouts and the dir in rmdir(2).
++ */
++ unsigned int si_dirwh;
++
++ /*
++ * rename(2) a directory with all children.
++ */
++ /* reserved for future use */
++ /* int si_rendir; */
++
++ /* pseudo_link list */
++ struct au_splhead si_plink;
++ wait_queue_head_t si_plink_wq;
++
++ /*
++ * sysfs and lifetime management.
++ * this is not a small structure and it may be a waste of memory in case
++ * of sysfs is disabled, particulary when many aufs-es are mounted.
++ * but using sysfs is majority.
++ */
++ struct kobject si_kobj;
++#ifdef CONFIG_DEBUG_FS
++ struct dentry *si_dbgaufs, *si_dbgaufs_xib;
++#ifdef CONFIG_AUFS_EXPORT
++ struct dentry *si_dbgaufs_xigen;
++#endif
++#endif
++
++ /* dirty, necessary for unmounting, sysfs and sysrq */
++ struct super_block *si_sb;
++};
++
++/* sbinfo status flags */
++/*
++ * set true when refresh_dirs() failed at remount time.
++ * then try refreshing dirs at access time again.
++ * if it is false, refreshing dirs at access time is unnecesary
++ */
++#define AuSi_FAILED_REFRESH_DIRS 1
++#define AuSi_MAINTAIN_PLINK (1 << 1) /* ioctl */
++static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi,
++ unsigned int flag)
++{
++ AuRwMustAnyLock(&sbi->si_rwsem);
++ return sbi->au_si_status & flag;
++}
++#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name)
++#define au_fset_si(sbinfo, name) do { \
++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \
++ (sbinfo)->au_si_status |= AuSi_##name; \
++} while (0)
++#define au_fclr_si(sbinfo, name) do { \
++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \
++ (sbinfo)->au_si_status &= ~AuSi_##name; \
++} while (0)
++
++/* ---------------------------------------------------------------------- */
++
++/* policy to select one among writable branches */
++#define AuWbrCopyup(sbinfo, args...) \
++ ((sbinfo)->si_wbr_copyup_ops->copyup(args))
++#define AuWbrCreate(sbinfo, args...) \
++ ((sbinfo)->si_wbr_create_ops->create(args))
++
++/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */
++#define AuLock_DW 1 /* write-lock dentry */
++#define AuLock_IR (1 << 1) /* read-lock inode */
++#define AuLock_IW (1 << 2) /* write-lock inode */
++#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */
++#define AuLock_DIR (1 << 4) /* target is a dir */
++#define au_ftest_lock(flags, name) ((flags) & AuLock_##name)
++#define au_fset_lock(flags, name) { (flags) |= AuLock_##name; }
++#define au_fclr_lock(flags, name) { (flags) &= ~AuLock_##name; }
++
++/* ---------------------------------------------------------------------- */
++
++/* super.c */
++extern struct file_system_type aufs_fs_type;
++struct inode *au_iget_locked(struct super_block *sb, ino_t ino);
++
++/* sbinfo.c */
++void au_si_free(struct kobject *kobj);
++int au_si_alloc(struct super_block *sb);
++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr);
++
++unsigned int au_sigen_inc(struct super_block *sb);
++aufs_bindex_t au_new_br_id(struct super_block *sb);
++
++void aufs_read_lock(struct dentry *dentry, int flags);
++void aufs_read_unlock(struct dentry *dentry, int flags);
++void aufs_write_lock(struct dentry *dentry);
++void aufs_write_unlock(struct dentry *dentry);
++void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int isdir);
++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2);
++
++/* wbr_policy.c */
++extern struct au_wbr_copyup_operations au_wbr_copyup_ops[];
++extern struct au_wbr_create_operations au_wbr_create_ops[];
++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst);
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct au_sbinfo *au_sbi(struct super_block *sb)
++{
++ return sb->s_fs_info;
++}
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_EXPORT
++void au_export_init(struct super_block *sb);
++
++static inline int au_test_nfsd(struct task_struct *tsk)
++{
++ return !tsk->mm && !strcmp(tsk->comm, "nfsd");
++}
++
++int au_xigen_inc(struct inode *inode);
++int au_xigen_new(struct inode *inode);
++int au_xigen_set(struct super_block *sb, struct file *base);
++void au_xigen_clr(struct super_block *sb);
++
++static inline int au_busy_or_stale(void)
++{
++ if (!au_test_nfsd(current))
++ return -EBUSY;
++ return -ESTALE;
++}
++#else
++static inline void au_export_init(struct super_block *sb)
++{
++ /* nothing */
++}
++
++static inline int au_test_nfsd(struct task_struct *tsk)
++{
++ return 0;
++}
++
++static inline int au_xigen_inc(struct inode *inode)
++{
++ return 0;
++}
++
++static inline int au_xigen_new(struct inode *inode)
++{
++ return 0;
++}
++
++static inline int au_xigen_set(struct super_block *sb, struct file *base)
++{
++ return 0;
++}
++
++static inline void au_xigen_clr(struct super_block *sb)
++{
++ /* empty */
++}
++
++static inline int au_busy_or_stale(void)
++{
++ return -EBUSY;
++}
++#endif /* CONFIG_AUFS_EXPORT */
++
++/* ---------------------------------------------------------------------- */
++
++static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo)
++{
++ /*
++ * This function is a dynamic '__init' fucntion actually,
++ * so the tiny check for si_rwsem is unnecessary.
++ */
++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */
++#ifdef CONFIG_DEBUG_FS
++ sbinfo->si_dbgaufs = NULL;
++ sbinfo->si_dbgaufs_xib = NULL;
++#ifdef CONFIG_AUFS_EXPORT
++ sbinfo->si_dbgaufs_xigen = NULL;
++#endif
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* lock superblock. mainly for entry point functions */
++/*
++ * si_noflush_read_lock, si_noflush_write_lock,
++ * si_read_unlock, si_write_unlock, si_downgrade_lock
++ */
++AuSimpleLockRwsemFuncs(si_noflush, struct super_block *sb,
++ &au_sbi(sb)->si_rwsem);
++AuSimpleUnlockRwsemFuncs(si, struct super_block *sb, &au_sbi(sb)->si_rwsem);
++
++#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem)
++#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem)
++#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem)
++
++static inline void si_read_lock(struct super_block *sb, int flags)
++{
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&au_sbi(sb)->si_nowait);
++ si_noflush_read_lock(sb);
++}
++
++static inline void si_write_lock(struct super_block *sb)
++{
++ au_nwt_flush(&au_sbi(sb)->si_nowait);
++ si_noflush_write_lock(sb);
++}
++
++static inline int si_read_trylock(struct super_block *sb, int flags)
++{
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&au_sbi(sb)->si_nowait);
++ return si_noflush_read_trylock(sb);
++}
++
++static inline int si_write_trylock(struct super_block *sb, int flags)
++{
++ if (au_ftest_lock(flags, FLUSH))
++ au_nwt_flush(&au_sbi(sb)->si_nowait);
++ return si_noflush_write_trylock(sb);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static inline aufs_bindex_t au_sbend(struct super_block *sb)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_bend;
++}
++
++static inline unsigned int au_mntflags(struct super_block *sb)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_mntflags;
++}
++
++static inline unsigned int au_sigen(struct super_block *sb)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_generation;
++}
++
++static inline struct au_branch *au_sbr(struct super_block *sb,
++ aufs_bindex_t bindex)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_branch[0 + bindex];
++}
++
++static inline void au_xino_brid_set(struct super_block *sb, aufs_bindex_t brid)
++{
++ SiMustWriteLock(sb);
++ au_sbi(sb)->si_xino_brid = brid;
++}
++
++static inline aufs_bindex_t au_xino_brid(struct super_block *sb)
++{
++ SiMustAnyLock(sb);
++ return au_sbi(sb)->si_xino_brid;
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_SUPER_H__ */
+diff --git a/fs/aufs/sysaufs.c b/fs/aufs/sysaufs.c
+new file mode 100644
+index 0000000..b796330
+--- /dev/null
++++ b/fs/aufs/sysaufs.c
+@@ -0,0 +1,104 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * sysfs interface and lifetime management
++ * they are necessary regardless sysfs is disabled.
++ */
++
++#include <linux/fs.h>
++#include <linux/random.h>
++#include <linux/sysfs.h>
++#include "aufs.h"
++
++unsigned long sysaufs_si_mask;
++struct kset *sysaufs_ket;
++
++#define AuSiAttr(_name) { \
++ .attr = { .name = __stringify(_name), .mode = 0444 }, \
++ .show = sysaufs_si_##_name, \
++}
++
++static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path);
++struct attribute *sysaufs_si_attrs[] = {
++ &sysaufs_si_attr_xi_path.attr,
++ NULL,
++};
++
++static struct sysfs_ops au_sbi_ops = {
++ .show = sysaufs_si_show
++};
++
++static struct kobj_type au_sbi_ktype = {
++ .release = au_si_free,
++ .sysfs_ops = &au_sbi_ops,
++ .default_attrs = sysaufs_si_attrs
++};
++
++/* ---------------------------------------------------------------------- */
++
++int sysaufs_si_init(struct au_sbinfo *sbinfo)
++{
++ int err;
++
++ sbinfo->si_kobj.kset = sysaufs_ket;
++ /* cf. sysaufs_name() */
++ err = kobject_init_and_add
++ (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_ket->kobj*/NULL,
++ SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo));
++
++ dbgaufs_si_null(sbinfo);
++ if (!err) {
++ err = dbgaufs_si_init(sbinfo);
++ if (unlikely(err))
++ kobject_put(&sbinfo->si_kobj);
++ }
++ return err;
++}
++
++void sysaufs_fin(void)
++{
++ dbgaufs_fin();
++ sysfs_remove_group(&sysaufs_ket->kobj, sysaufs_attr_group);
++ kset_unregister(sysaufs_ket);
++}
++
++int __init sysaufs_init(void)
++{
++ int err;
++
++ do {
++ get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask));
++ } while (!sysaufs_si_mask);
++
++ sysaufs_ket = kset_create_and_add(AUFS_NAME, NULL, fs_kobj);
++ err = PTR_ERR(sysaufs_ket);
++ if (IS_ERR(sysaufs_ket))
++ goto out;
++ err = sysfs_create_group(&sysaufs_ket->kobj, sysaufs_attr_group);
++ if (unlikely(err)) {
++ kset_unregister(sysaufs_ket);
++ goto out;
++ }
++
++ err = dbgaufs_init();
++ if (unlikely(err))
++ sysaufs_fin();
++ out:
++ return err;
++}
+diff --git a/fs/aufs/sysaufs.h b/fs/aufs/sysaufs.h
+new file mode 100644
+index 0000000..379033a
+--- /dev/null
++++ b/fs/aufs/sysaufs.h
+@@ -0,0 +1,120 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * sysfs interface and mount lifetime management
++ */
++
++#ifndef __SYSAUFS_H__
++#define __SYSAUFS_H__
++
++#ifdef __KERNEL__
++
++#include <linux/sysfs.h>
++#include <linux/aufs_type.h>
++#include "module.h"
++
++struct super_block;
++struct au_sbinfo;
++
++struct sysaufs_si_attr {
++ struct attribute attr;
++ int (*show)(struct seq_file *seq, struct super_block *sb);
++};
++
++/* ---------------------------------------------------------------------- */
++
++/* sysaufs.c */
++extern unsigned long sysaufs_si_mask;
++extern struct kset *sysaufs_ket;
++extern struct attribute *sysaufs_si_attrs[];
++int sysaufs_si_init(struct au_sbinfo *sbinfo);
++int __init sysaufs_init(void);
++void sysaufs_fin(void);
++
++/* ---------------------------------------------------------------------- */
++
++/* some people doesn't like to show a pointer in kernel */
++static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo)
++{
++ return sysaufs_si_mask ^ (unsigned long)sbinfo;
++}
++
++#define SysaufsSiNamePrefix "si_"
++#define SysaufsSiNameLen (sizeof(SysaufsSiNamePrefix) + 16)
++static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name)
++{
++ snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx",
++ sysaufs_si_id(sbinfo));
++}
++
++struct au_branch;
++#ifdef CONFIG_SYSFS
++/* sysfs.c */
++extern struct attribute_group *sysaufs_attr_group;
++
++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb);
++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
++ char *buf);
++
++void sysaufs_br_init(struct au_branch *br);
++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex);
++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex);
++
++#define sysaufs_brs_init() do {} while (0)
++
++#else
++#define sysaufs_attr_group NULL
++
++static inline
++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb)
++{
++ return 0;
++}
++
++static inline
++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
++ char *buf)
++{
++ return 0;
++}
++
++static inline void sysaufs_br_init(struct au_branch *br)
++{
++ /* empty */
++}
++
++static inline void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
++{
++ /* nothing */
++}
++
++static inline void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
++{
++ /* nothing */
++}
++
++static inline void sysaufs_brs_init(void)
++{
++ sysaufs_brs = 0;
++}
++
++#endif /* CONFIG_SYSFS */
++
++#endif /* __KERNEL__ */
++#endif /* __SYSAUFS_H__ */
+diff --git a/fs/aufs/sysfs.c b/fs/aufs/sysfs.c
+new file mode 100644
+index 0000000..55602fa
+--- /dev/null
++++ b/fs/aufs/sysfs.c
+@@ -0,0 +1,210 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * sysfs interface
++ */
++
++#include <linux/fs.h>
++#include <linux/module.h>
++#include <linux/seq_file.h>
++#include <linux/sysfs.h>
++#include "aufs.h"
++
++static struct attribute *au_attr[] = {
++ NULL, /* need to NULL terminate the list of attributes */
++};
++
++static struct attribute_group sysaufs_attr_group_body = {
++ .attrs = au_attr
++};
++
++struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body;
++
++/* ---------------------------------------------------------------------- */
++
++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb)
++{
++ int err;
++
++ SiMustAnyLock(sb);
++
++ err = 0;
++ if (au_opt_test(au_mntflags(sb), XINO)) {
++ err = au_xino_path(seq, au_sbi(sb)->si_xib);
++ seq_putc(seq, '\n');
++ }
++ return err;
++}
++
++/*
++ * the lifetime of branch is independent from the entry under sysfs.
++ * sysfs handles the lifetime of the entry, and never call ->show() after it is
++ * unlinked.
++ */
++static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb,
++ aufs_bindex_t bindex)
++{
++ struct path path;
++ struct dentry *root;
++ struct au_branch *br;
++
++ AuDbg("b%d\n", bindex);
++
++ root = sb->s_root;
++ di_read_lock_parent(root, !AuLock_IR);
++ br = au_sbr(sb, bindex);
++ path.mnt = br->br_mnt;
++ path.dentry = au_h_dptr(root, bindex);
++ au_seq_path(seq, &path);
++ di_read_unlock(root, !AuLock_IR);
++ seq_printf(seq, "=%s\n", au_optstr_br_perm(br->br_perm));
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static struct seq_file *au_seq(char *p, ssize_t len)
++{
++ struct seq_file *seq;
++
++ seq = kzalloc(sizeof(*seq), GFP_NOFS);
++ if (seq) {
++ /* mutex_init(&seq.lock); */
++ seq->buf = p;
++ seq->size = len;
++ return seq; /* success */
++ }
++
++ seq = ERR_PTR(-ENOMEM);
++ return seq;
++}
++
++#define SysaufsBr_PREFIX "br"
++
++/* todo: file size may exceed PAGE_SIZE */
++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
++ char *buf)
++{
++ ssize_t err;
++ long l;
++ aufs_bindex_t bend;
++ struct au_sbinfo *sbinfo;
++ struct super_block *sb;
++ struct seq_file *seq;
++ char *name;
++ struct attribute **cattr;
++
++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
++ sb = sbinfo->si_sb;
++ si_noflush_read_lock(sb);
++
++ seq = au_seq(buf, PAGE_SIZE);
++ err = PTR_ERR(seq);
++ if (IS_ERR(seq))
++ goto out;
++
++ name = (void *)attr->name;
++ cattr = sysaufs_si_attrs;
++ while (*cattr) {
++ if (!strcmp(name, (*cattr)->name)) {
++ err = container_of(*cattr, struct sysaufs_si_attr, attr)
++ ->show(seq, sb);
++ goto out_seq;
++ }
++ cattr++;
++ }
++
++ bend = au_sbend(sb);
++ if (!strncmp(name, SysaufsBr_PREFIX, sizeof(SysaufsBr_PREFIX) - 1)) {
++ name += sizeof(SysaufsBr_PREFIX) - 1;
++ err = strict_strtol(name, 10, &l);
++ if (!err) {
++ if (l <= bend)
++ err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l);
++ else
++ err = -ENOENT;
++ }
++ goto out_seq;
++ }
++ BUG();
++
++ out_seq:
++ if (!err) {
++ err = seq->count;
++ /* sysfs limit */
++ if (unlikely(err == PAGE_SIZE))
++ err = -EFBIG;
++ }
++ kfree(seq);
++ out:
++ si_read_unlock(sb);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void sysaufs_br_init(struct au_branch *br)
++{
++ br->br_attr.name = br->br_name;
++ br->br_attr.mode = S_IRUGO;
++ br->br_attr.owner = THIS_MODULE;
++}
++
++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
++{
++ struct au_branch *br;
++ struct kobject *kobj;
++ aufs_bindex_t bend;
++
++ dbgaufs_brs_del(sb, bindex);
++
++ if (!sysaufs_brs)
++ return;
++
++ kobj = &au_sbi(sb)->si_kobj;
++ bend = au_sbend(sb);
++ for (; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ sysfs_remove_file(kobj, &br->br_attr);
++ }
++}
++
++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
++{
++ int err;
++ aufs_bindex_t bend;
++ struct kobject *kobj;
++ struct au_branch *br;
++
++ dbgaufs_brs_add(sb, bindex);
++
++ if (!sysaufs_brs)
++ return;
++
++ kobj = &au_sbi(sb)->si_kobj;
++ bend = au_sbend(sb);
++ for (; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ snprintf(br->br_name, sizeof(br->br_name), SysaufsBr_PREFIX
++ "%d", bindex);
++ err = sysfs_create_file(kobj, &br->br_attr);
++ if (unlikely(err))
++ AuWarn("failed %s under sysfs(%d)\n", br->br_name, err);
++ }
++}
+diff --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c
+new file mode 100644
+index 0000000..2e7fbef
+--- /dev/null
++++ b/fs/aufs/sysrq.c
+@@ -0,0 +1,115 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * magic sysrq hanlder
++ */
++
++#include <linux/fs.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++/* #include <linux/sysrq.h> */
++#include "aufs.h"
++
++/* ---------------------------------------------------------------------- */
++
++static void sysrq_sb(struct super_block *sb)
++{
++ char *plevel;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++
++ plevel = au_plevel;
++ au_plevel = KERN_WARNING;
++ au_debug(1);
++
++ sbinfo = au_sbi(sb);
++ pr_warning("si=%lx\n", sysaufs_si_id(sbinfo));
++ pr_warning(AUFS_NAME ": superblock\n");
++ au_dpri_sb(sb);
++ pr_warning(AUFS_NAME ": root dentry\n");
++ au_dpri_dentry(sb->s_root);
++ pr_warning(AUFS_NAME ": root inode\n");
++ au_dpri_inode(sb->s_root->d_inode);
++#if 0
++ struct inode *i;
++ pr_warning(AUFS_NAME ": isolated inode\n");
++ list_for_each_entry(i, &sb->s_inodes, i_sb_list)
++ if (list_empty(&i->i_dentry))
++ au_dpri_inode(i);
++#endif
++ pr_warning(AUFS_NAME ": files\n");
++ list_for_each_entry(file, &sb->s_files, f_u.fu_list)
++ if (!special_file(file->f_dentry->d_inode->i_mode))
++ au_dpri_file(file);
++
++ au_plevel = plevel;
++ au_debug(0);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* module parameter */
++static char *aufs_sysrq_key = "a";
++module_param_named(sysrq, aufs_sysrq_key, charp, S_IRUGO);
++MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME);
++
++static void au_sysrq(int key __maybe_unused,
++ struct tty_struct *tty __maybe_unused)
++{
++ struct kobject *kobj;
++ struct au_sbinfo *sbinfo;
++
++ /* spin_lock(&sysaufs_ket->list_lock); */
++ list_for_each_entry(kobj, &sysaufs_ket->list, entry) {
++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
++ sysrq_sb(sbinfo->si_sb);
++ }
++ /* spin_unlock(&sysaufs_ket->list_lock); */
++}
++
++static struct sysrq_key_op au_sysrq_op = {
++ .handler = au_sysrq,
++ .help_msg = "Aufs",
++ .action_msg = "Aufs",
++ .enable_mask = SYSRQ_ENABLE_DUMP
++};
++
++/* ---------------------------------------------------------------------- */
++
++int __init au_sysrq_init(void)
++{
++ int err;
++ char key;
++
++ err = -1;
++ key = *aufs_sysrq_key;
++ if ('a' <= key && key <= 'z')
++ err = register_sysrq_key(key, &au_sysrq_op);
++ if (unlikely(err))
++ AuErr("err %d, sysrq=%c\n", err, key);
++ return err;
++}
++
++void au_sysrq_fin(void)
++{
++ int err;
++ err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op);
++ if (unlikely(err))
++ AuErr("err %d (ignored)\n", err);
++}
+diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c
+new file mode 100644
+index 0000000..47a0d12
+--- /dev/null
++++ b/fs/aufs/vdir.c
+@@ -0,0 +1,879 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * virtual or vertical directory
++ */
++
++#include <linux/hash.h>
++#include "aufs.h"
++
++static unsigned int calc_size(int nlen)
++{
++ BUILD_BUG_ON(sizeof(ino_t) != sizeof(long));
++ return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t));
++}
++
++static int set_deblk_end(union au_vdir_deblk_p *p,
++ union au_vdir_deblk_p *deblk_end)
++{
++ if (calc_size(0) <= deblk_end->deblk - p->deblk) {
++ p->de->de_str.len = 0;
++ /* smp_mb(); */
++ return 0;
++ }
++ return -1; /* error */
++}
++
++/* returns true or false */
++static int is_deblk_end(union au_vdir_deblk_p *p,
++ union au_vdir_deblk_p *deblk_end)
++{
++ if (calc_size(0) <= deblk_end->deblk - p->deblk)
++ return !p->de->de_str.len;
++ return 1;
++}
++
++static unsigned char *last_deblk(struct au_vdir *vdir)
++{
++ return vdir->vd_deblk[vdir->vd_nblk - 1];
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* estimate the apropriate size for name hash table */
++unsigned int au_rdhash_est(loff_t sz)
++{
++ unsigned int n;
++
++ n = UINT_MAX;
++ sz >>= 10;
++ if (sz < n)
++ n = sz;
++ if (sz < AUFS_RDHASH_DEF)
++ n = AUFS_RDHASH_DEF;
++ /* AuInfo("n %u\n", n); */
++ return n;
++}
++
++/*
++ * the allocated memory has to be freed by
++ * au_nhash_wh_free() or au_nhash_de_free().
++ */
++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp)
++{
++ struct hlist_head *head;
++ unsigned int u;
++
++ head = kmalloc(sizeof(*nhash->nh_head) * num_hash, gfp);
++ if (head) {
++ nhash->nh_num = num_hash;
++ nhash->nh_head = head;
++ for (u = 0; u < num_hash; u++)
++ INIT_HLIST_HEAD(head++);
++ return 0; /* success */
++ }
++
++ return -ENOMEM;
++}
++
++static void nhash_count(struct hlist_head *head)
++{
++#if 0
++ unsigned long n;
++ struct hlist_node *pos;
++
++ n = 0;
++ hlist_for_each(pos, head)
++ n++;
++ AuInfo("%lu\n", n);
++#endif
++}
++
++static void au_nhash_wh_do_free(struct hlist_head *head)
++{
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos, *node;
++
++ hlist_for_each_entry_safe(tpos, pos, node, head, wh_hash) {
++ /* hlist_del(pos); */
++ kfree(tpos);
++ }
++}
++
++static void au_nhash_de_do_free(struct hlist_head *head)
++{
++ struct au_vdir_dehstr *tpos;
++ struct hlist_node *pos, *node;
++
++ hlist_for_each_entry_safe(tpos, pos, node, head, hash) {
++ /* hlist_del(pos); */
++ au_cache_free_dehstr(tpos);
++ }
++}
++
++static void au_nhash_do_free(struct au_nhash *nhash,
++ void (*free)(struct hlist_head *head))
++{
++ unsigned int n;
++ struct hlist_head *head;
++
++ n = nhash->nh_num;
++ if (!n)
++ return;
++
++ head = nhash->nh_head;
++ while (n-- > 0) {
++ nhash_count(head);
++ free(head++);
++ }
++ kfree(nhash->nh_head);
++}
++
++void au_nhash_wh_free(struct au_nhash *whlist)
++{
++ au_nhash_do_free(whlist, au_nhash_wh_do_free);
++}
++
++static void au_nhash_de_free(struct au_nhash *delist)
++{
++ au_nhash_do_free(delist, au_nhash_de_do_free);
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt,
++ int limit)
++{
++ int num;
++ unsigned int u, n;
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos;
++
++ num = 0;
++ n = whlist->nh_num;
++ head = whlist->nh_head;
++ for (u = 0; u < n; u++, head++)
++ hlist_for_each_entry(tpos, pos, head, wh_hash)
++ if (tpos->wh_bindex == btgt && ++num > limit)
++ return 1;
++ return 0;
++}
++
++static struct hlist_head *au_name_hash(struct au_nhash *nhash,
++ unsigned char *name,
++ unsigned int len)
++{
++ unsigned int v;
++ /* const unsigned int magic_bit = 12; */
++
++ AuDebugOn(!nhash->nh_num || !nhash->nh_head);
++
++ v = 0;
++ while (len--)
++ v += *name++;
++ /* v = hash_long(v, magic_bit); */
++ v %= nhash->nh_num;
++ return nhash->nh_head + v;
++}
++
++static int au_nhash_test_name(struct au_vdir_destr *str, const char *name,
++ int nlen)
++{
++ return str->len == nlen && !memcmp(str->name, name, nlen);
++}
++
++/* returns found or not */
++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen)
++{
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos;
++ struct au_vdir_destr *str;
++
++ head = au_name_hash(whlist, name, nlen);
++ hlist_for_each_entry(tpos, pos, head, wh_hash) {
++ str = &tpos->wh_str;
++ AuDbg("%.*s\n", str->len, str->name);
++ if (au_nhash_test_name(str, name, nlen))
++ return 1;
++ }
++ return 0;
++}
++
++/* returns found(true) or not */
++static int test_known(struct au_nhash *delist, char *name, int nlen)
++{
++ struct hlist_head *head;
++ struct au_vdir_dehstr *tpos;
++ struct hlist_node *pos;
++ struct au_vdir_destr *str;
++
++ head = au_name_hash(delist, name, nlen);
++ hlist_for_each_entry(tpos, pos, head, hash) {
++ str = tpos->str;
++ AuDbg("%.*s\n", str->len, str->name);
++ if (au_nhash_test_name(str, name, nlen))
++ return 1;
++ }
++ return 0;
++}
++
++static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino,
++ unsigned char d_type)
++{
++#ifdef CONFIG_AUFS_SHWH
++ wh->wh_ino = ino;
++ wh->wh_type = d_type;
++#endif
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino,
++ unsigned int d_type, aufs_bindex_t bindex,
++ unsigned char shwh)
++{
++ int err;
++ struct au_vdir_destr *str;
++ struct au_vdir_wh *wh;
++
++ AuDbg("%.*s\n", nlen, name);
++ AuDebugOn(!whlist->nh_num || !whlist->nh_head);
++
++ err = -ENOMEM;
++ wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS);
++ if (unlikely(!wh))
++ goto out;
++
++ err = 0;
++ wh->wh_bindex = bindex;
++ if (shwh)
++ au_shwh_init_wh(wh, ino, d_type);
++ str = &wh->wh_str;
++ str->len = nlen;
++ memcpy(str->name, name, nlen);
++ hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen));
++ /* smp_mb(); */
++
++ out:
++ return err;
++}
++
++static int append_deblk(struct au_vdir *vdir)
++{
++ int err;
++ unsigned long ul;
++ const unsigned int deblk_sz = vdir->vd_deblk_sz;
++ union au_vdir_deblk_p p, deblk_end;
++ unsigned char **o;
++
++ err = -ENOMEM;
++ o = krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1),
++ GFP_NOFS);
++ if (unlikely(!o))
++ goto out;
++
++ vdir->vd_deblk = o;
++ p.deblk = kmalloc(deblk_sz, GFP_NOFS);
++ if (p.deblk) {
++ ul = vdir->vd_nblk++;
++ vdir->vd_deblk[ul] = p.deblk;
++ vdir->vd_last.ul = ul;
++ vdir->vd_last.p.deblk = p.deblk;
++ deblk_end.deblk = p.deblk + deblk_sz;
++ err = set_deblk_end(&p, &deblk_end);
++ }
++
++ out:
++ return err;
++}
++
++static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino,
++ unsigned int d_type, struct au_nhash *delist)
++{
++ int err;
++ unsigned int sz;
++ const unsigned int deblk_sz = vdir->vd_deblk_sz;
++ union au_vdir_deblk_p p, *room, deblk_end;
++ struct au_vdir_dehstr *dehstr;
++
++ p.deblk = last_deblk(vdir);
++ deblk_end.deblk = p.deblk + deblk_sz;
++ room = &vdir->vd_last.p;
++ AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk
++ || !is_deblk_end(room, &deblk_end));
++
++ sz = calc_size(nlen);
++ if (unlikely(sz > deblk_end.deblk - room->deblk)) {
++ err = append_deblk(vdir);
++ if (unlikely(err))
++ goto out;
++
++ p.deblk = last_deblk(vdir);
++ deblk_end.deblk = p.deblk + deblk_sz;
++ /* smp_mb(); */
++ AuDebugOn(room->deblk != p.deblk);
++ }
++
++ err = -ENOMEM;
++ dehstr = au_cache_alloc_dehstr();
++ if (unlikely(!dehstr))
++ goto out;
++
++ dehstr->str = &room->de->de_str;
++ hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen));
++ room->de->de_ino = ino;
++ room->de->de_type = d_type;
++ room->de->de_str.len = nlen;
++ memcpy(room->de->de_str.name, name, nlen);
++
++ err = 0;
++ room->deblk += sz;
++ if (unlikely(set_deblk_end(room, &deblk_end)))
++ err = append_deblk(vdir);
++ /* smp_mb(); */
++
++ out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_vdir_free(struct au_vdir *vdir)
++{
++ unsigned char **deblk;
++
++ deblk = vdir->vd_deblk;
++ while (vdir->vd_nblk--)
++ kfree(*deblk++);
++ kfree(vdir->vd_deblk);
++ au_cache_free_vdir(vdir);
++}
++
++static struct au_vdir *alloc_vdir(struct file *file)
++{
++ struct au_vdir *vdir;
++ struct super_block *sb;
++ int err;
++
++ sb = file->f_dentry->d_sb;
++ SiMustAnyLock(sb);
++
++ err = -ENOMEM;
++ vdir = au_cache_alloc_vdir();
++ if (unlikely(!vdir))
++ goto out;
++
++ vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS);
++ if (unlikely(!vdir->vd_deblk))
++ goto out_free;
++
++ vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk;
++ if (!vdir->vd_deblk_sz) {
++ /* estimate the apropriate size for deblk */
++ vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL);
++ /* AuInfo("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */
++ }
++ vdir->vd_nblk = 0;
++ vdir->vd_version = 0;
++ vdir->vd_jiffy = 0;
++ err = append_deblk(vdir);
++ if (!err)
++ return vdir; /* success */
++
++ kfree(vdir->vd_deblk);
++
++ out_free:
++ au_cache_free_vdir(vdir);
++ out:
++ vdir = ERR_PTR(err);
++ return vdir;
++}
++
++static int reinit_vdir(struct au_vdir *vdir)
++{
++ int err;
++ union au_vdir_deblk_p p, deblk_end;
++
++ while (vdir->vd_nblk > 1) {
++ kfree(vdir->vd_deblk[vdir->vd_nblk - 1]);
++ /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */
++ vdir->vd_nblk--;
++ }
++ p.deblk = vdir->vd_deblk[0];
++ deblk_end.deblk = p.deblk + vdir->vd_deblk_sz;
++ err = set_deblk_end(&p, &deblk_end);
++ /* keep vd_dblk_sz */
++ vdir->vd_last.ul = 0;
++ vdir->vd_last.p.deblk = vdir->vd_deblk[0];
++ vdir->vd_version = 0;
++ vdir->vd_jiffy = 0;
++ /* smp_mb(); */
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++#define AuFillVdir_CALLED 1
++#define AuFillVdir_WHABLE (1 << 1)
++#define AuFillVdir_SHWH (1 << 2)
++#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name)
++#define au_fset_fillvdir(flags, name) { (flags) |= AuFillVdir_##name; }
++#define au_fclr_fillvdir(flags, name) { (flags) &= ~AuFillVdir_##name; }
++
++#ifndef CONFIG_AUFS_SHWH
++#undef AuFillVdir_SHWH
++#define AuFillVdir_SHWH 0
++#endif
++
++struct fillvdir_arg {
++ struct file *file;
++ struct au_vdir *vdir;
++ struct au_nhash delist;
++ struct au_nhash whlist;
++ aufs_bindex_t bindex;
++ unsigned int flags;
++ int err;
++};
++
++static int fillvdir(void *__arg, const char *__name, int nlen,
++ loff_t offset __maybe_unused, u64 h_ino,
++ unsigned int d_type)
++{
++ struct fillvdir_arg *arg = __arg;
++ char *name = (void *)__name;
++ struct super_block *sb;
++ ino_t ino;
++ const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH);
++
++ arg->err = 0;
++ sb = arg->file->f_dentry->d_sb;
++ au_fset_fillvdir(arg->flags, CALLED);
++ /* smp_mb(); */
++ if (nlen <= AUFS_WH_PFX_LEN
++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
++ if (test_known(&arg->delist, name, nlen)
++ || au_nhash_test_known_wh(&arg->whlist, name, nlen))
++ goto out; /* already exists or whiteouted */
++
++ sb = arg->file->f_dentry->d_sb;
++ arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino);
++ if (!arg->err)
++ arg->err = append_de(arg->vdir, name, nlen, ino,
++ d_type, &arg->delist);
++ } else if (au_ftest_fillvdir(arg->flags, WHABLE)) {
++ name += AUFS_WH_PFX_LEN;
++ nlen -= AUFS_WH_PFX_LEN;
++ if (au_nhash_test_known_wh(&arg->whlist, name, nlen))
++ goto out; /* already whiteouted */
++
++ if (shwh)
++ arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type,
++ &ino);
++ if (!arg->err)
++ arg->err = au_nhash_append_wh
++ (&arg->whlist, name, nlen, ino, d_type,
++ arg->bindex, shwh);
++ }
++
++ out:
++ if (!arg->err)
++ arg->vdir->vd_jiffy = jiffies;
++ /* smp_mb(); */
++ AuTraceErr(arg->err);
++ return arg->err;
++}
++
++static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir,
++ struct au_nhash *whlist, struct au_nhash *delist)
++{
++#ifdef CONFIG_AUFS_SHWH
++ int err;
++ unsigned int nh, u;
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos, *n;
++ char *p, *o;
++ struct au_vdir_destr *destr;
++
++ AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH));
++
++ err = -ENOMEM;
++ o = p = __getname();
++ if (unlikely(!p))
++ goto out;
++
++ err = 0;
++ nh = whlist->nh_num;
++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
++ p += AUFS_WH_PFX_LEN;
++ for (u = 0; u < nh; u++) {
++ head = whlist->nh_head + u;
++ hlist_for_each_entry_safe(tpos, pos, n, head, wh_hash) {
++ destr = &tpos->wh_str;
++ memcpy(p, destr->name, destr->len);
++ err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN,
++ tpos->wh_ino, tpos->wh_type, delist);
++ if (unlikely(err))
++ break;
++ }
++ }
++
++ __putname(o);
++
++ out:
++ AuTraceErr(err);
++ return err;
++#else
++ return 0;
++#endif
++}
++
++static int au_do_read_vdir(struct fillvdir_arg *arg)
++{
++ int err;
++ unsigned int rdhash;
++ loff_t offset;
++ aufs_bindex_t bend, bindex, bstart;
++ unsigned char shwh;
++ struct file *hf, *file;
++ struct super_block *sb;
++
++ file = arg->file;
++ sb = file->f_dentry->d_sb;
++ SiMustAnyLock(sb);
++
++ rdhash = au_sbi(sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL));
++ err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out;
++ err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS);
++ if (unlikely(err))
++ goto out_delist;
++
++ err = 0;
++ arg->flags = 0;
++ shwh = 0;
++ if (au_opt_test(au_mntflags(sb), SHWH)) {
++ shwh = 1;
++ au_fset_fillvdir(arg->flags, SHWH);
++ }
++ bstart = au_fbstart(file);
++ bend = au_fbend(file);
++ for (bindex = bstart; !err && bindex <= bend; bindex++) {
++ hf = au_h_fptr(file, bindex);
++ if (!hf)
++ continue;
++
++ offset = vfsub_llseek(hf, 0, SEEK_SET);
++ err = offset;
++ if (unlikely(offset))
++ break;
++
++ arg->bindex = bindex;
++ au_fclr_fillvdir(arg->flags, WHABLE);
++ if (shwh
++ || (bindex != bend
++ && au_br_whable(au_sbr_perm(sb, bindex))))
++ au_fset_fillvdir(arg->flags, WHABLE);
++ do {
++ arg->err = 0;
++ au_fclr_fillvdir(arg->flags, CALLED);
++ /* smp_mb(); */
++ err = vfsub_readdir(hf, fillvdir, arg);
++ if (err >= 0)
++ err = arg->err;
++ } while (!err && au_ftest_fillvdir(arg->flags, CALLED));
++ }
++
++ if (!err && shwh)
++ err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist);
++
++ au_nhash_wh_free(&arg->whlist);
++
++ out_delist:
++ au_nhash_de_free(&arg->delist);
++ out:
++ return err;
++}
++
++static int read_vdir(struct file *file, int may_read)
++{
++ int err;
++ unsigned long expire;
++ unsigned char do_read;
++ struct fillvdir_arg arg;
++ struct inode *inode;
++ struct au_vdir *vdir, *allocated;
++
++ err = 0;
++ inode = file->f_dentry->d_inode;
++ IMustLock(inode);
++ SiMustAnyLock(inode->i_sb);
++
++ allocated = NULL;
++ do_read = 0;
++ expire = au_sbi(inode->i_sb)->si_rdcache;
++ vdir = au_ivdir(inode);
++ if (!vdir) {
++ do_read = 1;
++ vdir = alloc_vdir(file);
++ err = PTR_ERR(vdir);
++ if (IS_ERR(vdir))
++ goto out;
++ err = 0;
++ allocated = vdir;
++ } else if (may_read
++ && (inode->i_version != vdir->vd_version
++ || time_after(jiffies, vdir->vd_jiffy + expire))) {
++ do_read = 1;
++ err = reinit_vdir(vdir);
++ if (unlikely(err))
++ goto out;
++ }
++
++ if (!do_read)
++ return 0; /* success */
++
++ arg.file = file;
++ arg.vdir = vdir;
++ err = au_do_read_vdir(&arg);
++ if (!err) {
++ /* file->f_pos = 0; */
++ vdir->vd_version = inode->i_version;
++ vdir->vd_last.ul = 0;
++ vdir->vd_last.p.deblk = vdir->vd_deblk[0];
++ if (allocated)
++ au_set_ivdir(inode, allocated);
++ } else if (allocated)
++ au_vdir_free(allocated);
++
++ out:
++ return err;
++}
++
++static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src)
++{
++ int err, rerr;
++ unsigned long ul, n;
++ const unsigned int deblk_sz = src->vd_deblk_sz;
++
++ AuDebugOn(tgt->vd_nblk != 1);
++
++ err = -ENOMEM;
++ if (tgt->vd_nblk < src->vd_nblk) {
++ unsigned char **p;
++
++ p = krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk,
++ GFP_NOFS);
++ if (unlikely(!p))
++ goto out;
++ tgt->vd_deblk = p;
++ }
++
++ if (tgt->vd_deblk_sz != deblk_sz) {
++ unsigned char *p;
++
++ tgt->vd_deblk_sz = deblk_sz;
++ p = krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS);
++ if (unlikely(!p))
++ goto out;
++ tgt->vd_deblk[0] = p;
++ }
++ memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz);
++ tgt->vd_version = src->vd_version;
++ tgt->vd_jiffy = src->vd_jiffy;
++
++ n = src->vd_nblk;
++ for (ul = 1; ul < n; ul++) {
++ tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz,
++ GFP_NOFS);
++ if (unlikely(!tgt->vd_deblk[ul]))
++ goto out;
++ tgt->vd_nblk++;
++ }
++ tgt->vd_nblk = n;
++ tgt->vd_last.ul = tgt->vd_last.ul;
++ tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul];
++ tgt->vd_last.p.deblk += src->vd_last.p.deblk
++ - src->vd_deblk[src->vd_last.ul];
++ /* smp_mb(); */
++ return 0; /* success */
++
++ out:
++ rerr = reinit_vdir(tgt);
++ BUG_ON(rerr);
++ return err;
++}
++
++int au_vdir_init(struct file *file)
++{
++ int err;
++ struct inode *inode;
++ struct au_vdir *vdir_cache, *allocated;
++
++ err = read_vdir(file, !file->f_pos);
++ if (unlikely(err))
++ goto out;
++
++ allocated = NULL;
++ vdir_cache = au_fvdir_cache(file);
++ if (!vdir_cache) {
++ vdir_cache = alloc_vdir(file);
++ err = PTR_ERR(vdir_cache);
++ if (IS_ERR(vdir_cache))
++ goto out;
++ allocated = vdir_cache;
++ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) {
++ err = reinit_vdir(vdir_cache);
++ if (unlikely(err))
++ goto out;
++ } else
++ return 0; /* success */
++
++ inode = file->f_dentry->d_inode;
++ err = copy_vdir(vdir_cache, au_ivdir(inode));
++ if (!err) {
++ file->f_version = inode->i_version;
++ if (allocated)
++ au_set_fvdir_cache(file, allocated);
++ } else if (allocated)
++ au_vdir_free(allocated);
++
++ out:
++ return err;
++}
++
++static loff_t calc_offset(struct au_vdir *vdir)
++{
++ loff_t offset;
++ union au_vdir_deblk_p p;
++
++ p.deblk = vdir->vd_deblk[vdir->vd_last.ul];
++ offset = vdir->vd_last.p.deblk - p.deblk;
++ offset += vdir->vd_deblk_sz * vdir->vd_last.ul;
++ return offset;
++}
++
++/* returns true or false */
++static int seek_vdir(struct file *file)
++{
++ int valid;
++ unsigned int deblk_sz;
++ unsigned long ul, n;
++ loff_t offset;
++ union au_vdir_deblk_p p, deblk_end;
++ struct au_vdir *vdir_cache;
++
++ valid = 1;
++ vdir_cache = au_fvdir_cache(file);
++ offset = calc_offset(vdir_cache);
++ AuDbg("offset %lld\n", offset);
++ if (file->f_pos == offset)
++ goto out;
++
++ vdir_cache->vd_last.ul = 0;
++ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0];
++ if (!file->f_pos)
++ goto out;
++
++ valid = 0;
++ deblk_sz = vdir_cache->vd_deblk_sz;
++ ul = div64_u64(file->f_pos, deblk_sz);
++ AuDbg("ul %lu\n", ul);
++ if (ul >= vdir_cache->vd_nblk)
++ goto out;
++
++ n = vdir_cache->vd_nblk;
++ for (; ul < n; ul++) {
++ p.deblk = vdir_cache->vd_deblk[ul];
++ deblk_end.deblk = p.deblk + deblk_sz;
++ offset = ul;
++ offset *= deblk_sz;
++ while (!is_deblk_end(&p, &deblk_end) && offset < file->f_pos) {
++ unsigned int l;
++
++ l = calc_size(p.de->de_str.len);
++ offset += l;
++ p.deblk += l;
++ }
++ if (!is_deblk_end(&p, &deblk_end)) {
++ valid = 1;
++ vdir_cache->vd_last.ul = ul;
++ vdir_cache->vd_last.p = p;
++ break;
++ }
++ }
++
++ out:
++ /* smp_mb(); */
++ AuTraceErr(!valid);
++ return valid;
++}
++
++int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir)
++{
++ int err;
++ unsigned int l, deblk_sz;
++ union au_vdir_deblk_p deblk_end;
++ struct au_vdir *vdir_cache;
++ struct au_vdir_de *de;
++
++ vdir_cache = au_fvdir_cache(file);
++ if (!seek_vdir(file))
++ return 0;
++
++ deblk_sz = vdir_cache->vd_deblk_sz;
++ while (1) {
++ deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul];
++ deblk_end.deblk += deblk_sz;
++ while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) {
++ de = vdir_cache->vd_last.p.de;
++ AuDbg("%.*s, off%lld, i%lu, dt%d\n",
++ de->de_str.len, de->de_str.name, file->f_pos,
++ (unsigned long)de->de_ino, de->de_type);
++ err = filldir(dirent, de->de_str.name, de->de_str.len,
++ file->f_pos, de->de_ino, de->de_type);
++ if (unlikely(err)) {
++ AuTraceErr(err);
++ /* todo: ignore the error caused by udba? */
++ /* return err; */
++ return 0;
++ }
++
++ l = calc_size(de->de_str.len);
++ vdir_cache->vd_last.p.deblk += l;
++ file->f_pos += l;
++ }
++ if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) {
++ vdir_cache->vd_last.ul++;
++ vdir_cache->vd_last.p.deblk
++ = vdir_cache->vd_deblk[vdir_cache->vd_last.ul];
++ file->f_pos = deblk_sz * vdir_cache->vd_last.ul;
++ continue;
++ }
++ break;
++ }
++
++ /* smp_mb(); */
++ return 0;
++}
+diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c
+new file mode 100644
+index 0000000..ecc8f80
+--- /dev/null
++++ b/fs/aufs/vfsub.c
+@@ -0,0 +1,658 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * sub-routines for VFS
++ */
++
++#include <linux/namei.h>
++#include <linux/splice.h>
++#include <linux/uaccess.h>
++#include "aufs.h"
++
++int vfsub_update_h_iattr(struct path *h_path, int *did)
++{
++ int err;
++ struct kstat st;
++ struct super_block *h_sb;
++
++ /* for remote fs, leave work for its getattr or d_revalidate */
++ /* for bad i_attr fs, handle them in aufs_getattr() */
++ /* still some fs may acquire i_mutex. we need to skip them */
++ err = 0;
++ if (!did)
++ did = &err;
++ h_sb = h_path->dentry->d_sb;
++ *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb));
++ if (*did)
++ err = vfs_getattr(h_path->mnt, h_path->dentry, &st);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct file *vfsub_filp_open(const char *path, int oflags, int mode)
++{
++ struct file *file;
++
++ lockdep_off();
++ file = filp_open(path, oflags, mode);
++ lockdep_on();
++ if (IS_ERR(file))
++ goto out;
++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
++
++ out:
++ return file;
++}
++
++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path)
++{
++ int err;
++
++ /* lockdep_off(); */
++ err = kern_path(name, flags, path);
++ /* lockdep_on(); */
++ if (!err && path->dentry->d_inode)
++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
++ int len)
++{
++ struct path path = {
++ .mnt = NULL
++ };
++
++ IMustLock(parent->d_inode);
++
++ path.dentry = lookup_one_len(name, parent, len);
++ if (IS_ERR(path.dentry))
++ goto out;
++ if (path.dentry->d_inode)
++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/
++
++ out:
++ return path.dentry;
++}
++
++struct dentry *vfsub_lookup_hash(struct nameidata *nd)
++{
++ struct path path = {
++ .mnt = nd->path.mnt
++ };
++
++ IMustLock(nd->path.dentry->d_inode);
++
++ path.dentry = lookup_hash(nd);
++ if (!IS_ERR(path.dentry) && path.dentry->d_inode)
++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/
++
++ return path.dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1,
++ struct dentry *d2, struct au_hinode *hdir2)
++{
++ struct dentry *d;
++
++ lockdep_off();
++ d = lock_rename(d1, d2);
++ lockdep_on();
++ au_hin_suspend(hdir1);
++ if (hdir1 != hdir2)
++ au_hin_suspend(hdir2);
++
++ return d;
++}
++
++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1,
++ struct dentry *d2, struct au_hinode *hdir2)
++{
++ au_hin_resume(hdir1);
++ if (hdir1 != hdir2)
++ au_hin_resume(hdir2);
++ lockdep_off();
++ unlock_rename(d1, d2);
++ lockdep_on();
++}
++
++/* ---------------------------------------------------------------------- */
++
++int vfsub_create(struct inode *dir, struct path *path, int mode)
++{
++ int err;
++
++ IMustLock(dir);
++
++ if (au_test_fs_null_nd(dir->i_sb))
++ err = vfs_create(dir, path->dentry, mode, NULL);
++ else {
++ struct nameidata h_nd;
++
++ memset(&h_nd, 0, sizeof(h_nd));
++ h_nd.flags = LOOKUP_CREATE;
++ h_nd.intent.open.flags = O_CREAT
++ | vfsub_fmode_to_uint(FMODE_READ);
++ h_nd.intent.open.create_mode = mode;
++ h_nd.path.dentry = path->dentry->d_parent;
++ h_nd.path.mnt = path->mnt;
++ path_get(&h_nd.path);
++ err = vfs_create(dir, path->dentry, mode, &h_nd);
++ path_put(&h_nd.path);
++ }
++
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++
++ return err;
++}
++
++int vfsub_symlink(struct inode *dir, struct path *path, const char *symname)
++{
++ int err;
++
++ IMustLock(dir);
++
++ err = vfs_symlink(dir, path->dentry, symname);
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++ return err;
++}
++
++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev)
++{
++ int err;
++
++ IMustLock(dir);
++
++ err = vfs_mknod(dir, path->dentry, mode, dev);
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++ return err;
++}
++
++static int au_test_nlink(struct inode *inode)
++{
++ const unsigned int link_max = UINT_MAX >> 1; /* rough margin */
++
++ if (!au_test_fs_no_limit_nlink(inode->i_sb)
++ || inode->i_nlink < link_max)
++ return 0;
++ return -EMLINK;
++}
++
++int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path)
++{
++ int err;
++
++ IMustLock(dir);
++
++ err = au_test_nlink(src_dentry->d_inode);
++ if (unlikely(err))
++ return err;
++
++ lockdep_off();
++ err = vfs_link(src_dentry, dir, path->dentry);
++ lockdep_on();
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ /* fuse has different memory inode for the same inumber */
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ tmp.dentry = src_dentry;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++ return err;
++}
++
++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry,
++ struct inode *dir, struct path *path)
++{
++ int err;
++ struct path tmp = {
++ .dentry = path->dentry->d_parent,
++ .mnt = path->mnt
++ };
++
++ IMustLock(dir);
++ IMustLock(src_dir);
++
++ lockdep_off();
++ err = vfs_rename(src_dir, src_dentry, dir, path->dentry);
++ lockdep_on();
++ if (!err) {
++ int did;
++
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = src_dentry;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ tmp.dentry = src_dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++ return err;
++}
++
++int vfsub_mkdir(struct inode *dir, struct path *path, int mode)
++{
++ int err;
++
++ IMustLock(dir);
++
++ err = vfs_mkdir(dir, path->dentry, mode);
++ if (!err) {
++ struct path tmp = *path;
++ int did;
++
++ vfsub_update_h_iattr(&tmp, &did);
++ if (did) {
++ tmp.dentry = path->dentry->d_parent;
++ vfsub_update_h_iattr(&tmp, /*did*/NULL);
++ }
++ /*ignore*/
++ }
++ return err;
++}
++
++int vfsub_rmdir(struct inode *dir, struct path *path)
++{
++ int err;
++
++ IMustLock(dir);
++
++ lockdep_off();
++ err = vfs_rmdir(dir, path->dentry);
++ lockdep_on();
++ if (!err) {
++ struct path tmp = {
++ .dentry = path->dentry->d_parent,
++ .mnt = path->mnt
++ };
++
++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count,
++ loff_t *ppos)
++{
++ ssize_t err;
++
++ err = vfs_read(file, ubuf, count, ppos);
++ if (err >= 0)
++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++/* todo: kernel_read()? */
++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count,
++ loff_t *ppos)
++{
++ ssize_t err;
++ mm_segment_t oldfs;
++
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ err = vfsub_read_u(file, (char __user *)kbuf, count, ppos);
++ set_fs(oldfs);
++ return err;
++}
++
++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count,
++ loff_t *ppos)
++{
++ ssize_t err;
++
++ lockdep_off();
++ err = vfs_write(file, ubuf, count, ppos);
++ lockdep_on();
++ if (err >= 0)
++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos)
++{
++ ssize_t err;
++ mm_segment_t oldfs;
++
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ err = vfsub_write_u(file, (const char __user *)kbuf, count, ppos);
++ set_fs(oldfs);
++ return err;
++}
++
++int vfsub_readdir(struct file *file, filldir_t filldir, void *arg)
++{
++ int err;
++
++ lockdep_off();
++ err = vfs_readdir(file, filldir, arg);
++ lockdep_on();
++ if (err >= 0)
++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++long vfsub_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
++{
++ long err;
++
++ lockdep_off();
++ err = do_splice_to(in, ppos, pipe, len, flags);
++ lockdep_on();
++ if (err >= 0)
++ vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags)
++{
++ long err;
++
++ lockdep_off();
++ err = do_splice_from(pipe, out, ppos, len, flags);
++ lockdep_on();
++ if (err >= 0)
++ vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/
++ return err;
++}
++
++/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */
++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
++ struct file *h_file)
++{
++ int err;
++ struct inode *h_inode;
++
++ h_inode = h_path->dentry->d_inode;
++ if (!h_file) {
++ err = mnt_want_write(h_path->mnt);
++ if (err)
++ goto out;
++ err = inode_permission(h_inode, MAY_WRITE);
++ if (err)
++ goto out_mnt;
++ err = get_write_access(h_inode);
++ if (err)
++ goto out_mnt;
++ err = break_lease(h_inode, vfsub_fmode_to_uint(FMODE_WRITE));
++ if (err)
++ goto out_inode;
++ }
++
++ err = locks_verify_truncate(h_inode, h_file, length);
++ if (!err) {
++ lockdep_off();
++ err = do_truncate(h_path->dentry, length, attr, h_file);
++ lockdep_on();
++ }
++
++ out_inode:
++ if (!h_file)
++ put_write_access(h_inode);
++ out_mnt:
++ if (!h_file)
++ mnt_drop_write(h_path->mnt);
++ out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_vfsub_mkdir_args {
++ int *errp;
++ struct inode *dir;
++ struct path *path;
++ int mode;
++};
++
++static void au_call_vfsub_mkdir(void *args)
++{
++ struct au_vfsub_mkdir_args *a = args;
++ *a->errp = vfsub_mkdir(a->dir, a->path, a->mode);
++}
++
++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode)
++{
++ int err, do_sio, wkq_err;
++
++ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
++ if (!do_sio)
++ err = vfsub_mkdir(dir, path, mode);
++ else {
++ struct au_vfsub_mkdir_args args = {
++ .errp = &err,
++ .dir = dir,
++ .path = path,
++ .mode = mode
++ };
++ wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ return err;
++}
++
++struct au_vfsub_rmdir_args {
++ int *errp;
++ struct inode *dir;
++ struct path *path;
++};
++
++static void au_call_vfsub_rmdir(void *args)
++{
++ struct au_vfsub_rmdir_args *a = args;
++ *a->errp = vfsub_rmdir(a->dir, a->path);
++}
++
++int vfsub_sio_rmdir(struct inode *dir, struct path *path)
++{
++ int err, do_sio, wkq_err;
++
++ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
++ if (!do_sio)
++ err = vfsub_rmdir(dir, path);
++ else {
++ struct au_vfsub_rmdir_args args = {
++ .errp = &err,
++ .dir = dir,
++ .path = path
++ };
++ wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct notify_change_args {
++ int *errp;
++ struct path *path;
++ struct iattr *ia;
++};
++
++static void call_notify_change(void *args)
++{
++ struct notify_change_args *a = args;
++ struct inode *h_inode;
++
++ h_inode = a->path->dentry->d_inode;
++ IMustLock(h_inode);
++
++ *a->errp = -EPERM;
++ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) {
++ lockdep_off();
++ *a->errp = notify_change(a->path->dentry, a->ia);
++ lockdep_on();
++ if (!*a->errp)
++ vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/
++ }
++ AuTraceErr(*a->errp);
++}
++
++int vfsub_notify_change(struct path *path, struct iattr *ia)
++{
++ int err;
++ struct notify_change_args args = {
++ .errp = &err,
++ .path = path,
++ .ia = ia
++ };
++
++ call_notify_change(&args);
++
++ return err;
++}
++
++int vfsub_sio_notify_change(struct path *path, struct iattr *ia)
++{
++ int err, wkq_err;
++ struct notify_change_args args = {
++ .errp = &err,
++ .path = path,
++ .ia = ia
++ };
++
++ wkq_err = au_wkq_wait(call_notify_change, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct unlink_args {
++ int *errp;
++ struct inode *dir;
++ struct path *path;
++};
++
++static void call_unlink(void *args)
++{
++ struct unlink_args *a = args;
++ struct dentry *d = a->path->dentry;
++ struct inode *h_inode;
++ const int stop_sillyrename = (au_test_nfs(d->d_sb)
++ && atomic_read(&d->d_count) == 1);
++
++ IMustLock(a->dir);
++
++ if (!stop_sillyrename)
++ dget(d);
++ h_inode = d->d_inode;
++ if (h_inode)
++ atomic_inc(&h_inode->i_count);
++
++ lockdep_off();
++ *a->errp = vfs_unlink(a->dir, d);
++ lockdep_on();
++ if (!*a->errp) {
++ struct path tmp = {
++ .dentry = d->d_parent,
++ .mnt = a->path->mnt
++ };
++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/
++ }
++
++ if (!stop_sillyrename)
++ dput(d);
++ if (h_inode)
++ iput(h_inode);
++
++ AuTraceErr(*a->errp);
++}
++
++/*
++ * @dir: must be locked.
++ * @dentry: target dentry.
++ */
++int vfsub_unlink(struct inode *dir, struct path *path, int force)
++{
++ int err;
++ struct unlink_args args = {
++ .errp = &err,
++ .dir = dir,
++ .path = path
++ };
++
++ if (!force)
++ call_unlink(&args);
++ else {
++ int wkq_err;
++
++ wkq_err = au_wkq_wait(call_unlink, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++
++ return err;
++}
+diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h
+new file mode 100644
+index 0000000..00e7e62
+--- /dev/null
++++ b/fs/aufs/vfsub.h
+@@ -0,0 +1,172 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * sub-routines for VFS
++ */
++
++#ifndef __AUFS_VFSUB_H__
++#define __AUFS_VFSUB_H__
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++#include <linux/fs_stack.h>
++
++/* ---------------------------------------------------------------------- */
++
++/* lock subclass for lower inode */
++/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */
++/* reduce? gave up. */
++enum {
++ AuLsc_I_Begin = I_MUTEX_QUOTA, /* 4 */
++ AuLsc_I_PARENT, /* lower inode, parent first */
++ AuLsc_I_PARENT2, /* copyup dirs */
++ AuLsc_I_PARENT3, /* copyup wh */
++ AuLsc_I_CHILD,
++ AuLsc_I_CHILD2,
++ AuLsc_I_End
++};
++
++/* to debug easier, do not make them inlined functions */
++#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx))
++#define IMustLock(i) MtxMustLock(&(i)->i_mutex)
++
++/* ---------------------------------------------------------------------- */
++
++static inline void vfsub_copy_inode_size(struct inode *inode,
++ struct inode *h_inode)
++{
++ spin_lock(&inode->i_lock);
++ fsstack_copy_inode_size(inode, h_inode);
++ spin_unlock(&inode->i_lock);
++}
++
++int vfsub_update_h_iattr(struct path *h_path, int *did);
++struct file *vfsub_filp_open(const char *path, int oflags, int mode);
++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path);
++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent,
++ int len);
++struct dentry *vfsub_lookup_hash(struct nameidata *nd);
++
++/* ---------------------------------------------------------------------- */
++
++struct au_hinode;
++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1,
++ struct dentry *d2, struct au_hinode *hdir2);
++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1,
++ struct dentry *d2, struct au_hinode *hdir2);
++
++int vfsub_create(struct inode *dir, struct path *path, int mode);
++int vfsub_symlink(struct inode *dir, struct path *path,
++ const char *symname);
++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev);
++int vfsub_link(struct dentry *src_dentry, struct inode *dir,
++ struct path *path);
++int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry,
++ struct inode *hdir, struct path *path);
++int vfsub_mkdir(struct inode *dir, struct path *path, int mode);
++int vfsub_rmdir(struct inode *dir, struct path *path);
++
++/* ---------------------------------------------------------------------- */
++
++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count,
++ loff_t *ppos);
++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count,
++ loff_t *ppos);
++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count,
++ loff_t *ppos);
++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count,
++ loff_t *ppos);
++int vfsub_readdir(struct file *file, filldir_t filldir, void *arg);
++
++static inline void vfsub_file_accessed(struct file *h_file)
++{
++ file_accessed(h_file);
++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/
++}
++
++static inline void vfsub_touch_atime(struct vfsmount *h_mnt,
++ struct dentry *h_dentry)
++{
++ struct path h_path = {
++ .dentry = h_dentry,
++ .mnt = h_mnt
++ };
++ touch_atime(h_mnt, h_dentry);
++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/
++}
++
++long vfsub_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags);
++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags);
++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
++ struct file *h_file);
++
++/* ---------------------------------------------------------------------- */
++
++static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin)
++{
++ loff_t err;
++
++ lockdep_off();
++ err = vfs_llseek(file, offset, origin);
++ lockdep_on();
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* dirty workaround for strict type of fmode_t */
++union vfsub_fmu {
++ fmode_t fm;
++ unsigned int ui;
++};
++
++static inline unsigned int vfsub_fmode_to_uint(fmode_t fm)
++{
++ union vfsub_fmu u = {
++ .fm = fm
++ };
++
++ BUILD_BUG_ON(sizeof(u.fm) != sizeof(u.ui));
++
++ return u.ui;
++}
++
++static inline fmode_t vfsub_uint_to_fmode(unsigned int ui)
++{
++ union vfsub_fmu u = {
++ .ui = ui
++ };
++
++ return u.fm;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode);
++int vfsub_sio_rmdir(struct inode *dir, struct path *path);
++int vfsub_sio_notify_change(struct path *path, struct iattr *ia);
++int vfsub_notify_change(struct path *path, struct iattr *ia);
++int vfsub_unlink(struct inode *dir, struct path *path, int force);
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_VFSUB_H__ */
+diff --git a/fs/aufs/wbr_policy.c b/fs/aufs/wbr_policy.c
+new file mode 100644
+index 0000000..05a8c1e
+--- /dev/null
++++ b/fs/aufs/wbr_policy.c
+@@ -0,0 +1,641 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * policies for selecting one among multiple writable branches
++ */
++
++#include <linux/statfs.h>
++#include "aufs.h"
++
++/* subset of cpup_attr() */
++static noinline_for_stack
++int au_cpdown_attr(struct path *h_path, struct dentry *h_src)
++{
++ int err, sbits;
++ struct iattr ia;
++ struct inode *h_isrc;
++
++ h_isrc = h_src->d_inode;
++ ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID;
++ ia.ia_mode = h_isrc->i_mode;
++ ia.ia_uid = h_isrc->i_uid;
++ ia.ia_gid = h_isrc->i_gid;
++ sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID));
++ au_cpup_attr_flags(h_path->dentry->d_inode, h_isrc);
++ err = vfsub_sio_notify_change(h_path, &ia);
++
++ /* is this nfs only? */
++ if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) {
++ ia.ia_valid = ATTR_FORCE | ATTR_MODE;
++ ia.ia_mode = h_isrc->i_mode;
++ err = vfsub_sio_notify_change(h_path, &ia);
++ }
++
++ return err;
++}
++
++#define AuCpdown_PARENT_OPQ 1
++#define AuCpdown_WHED (1 << 1)
++#define AuCpdown_MADE_DIR (1 << 2)
++#define AuCpdown_DIROPQ (1 << 3)
++#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name)
++#define au_fset_cpdown(flags, name) { (flags) |= AuCpdown_##name; }
++#define au_fclr_cpdown(flags, name) { (flags) &= ~AuCpdown_##name; }
++
++struct au_cpdown_dir_args {
++ struct dentry *parent;
++ unsigned int flags;
++};
++
++static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst,
++ struct au_cpdown_dir_args *a)
++{
++ int err;
++ struct dentry *opq_dentry;
++
++ opq_dentry = au_diropq_create(dentry, bdst);
++ err = PTR_ERR(opq_dentry);
++ if (IS_ERR(opq_dentry))
++ goto out;
++ dput(opq_dentry);
++ au_fset_cpdown(a->flags, DIROPQ);
++
++ out:
++ return err;
++}
++
++static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent,
++ struct inode *dir, aufs_bindex_t bdst)
++{
++ int err;
++ struct path h_path;
++ struct au_branch *br;
++
++ br = au_sbr(dentry->d_sb, bdst);
++ h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br);
++ err = PTR_ERR(h_path.dentry);
++ if (IS_ERR(h_path.dentry))
++ goto out;
++
++ err = 0;
++ if (h_path.dentry->d_inode) {
++ h_path.mnt = br->br_mnt;
++ err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path,
++ dentry);
++ }
++ dput(h_path.dentry);
++
++ out:
++ return err;
++}
++
++static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst,
++ struct dentry *h_parent, void *arg)
++{
++ int err, rerr;
++ aufs_bindex_t bend, bopq, bstart;
++ unsigned char parent_opq;
++ struct path h_path;
++ struct dentry *parent;
++ struct inode *h_dir, *h_inode, *inode, *dir;
++ struct au_cpdown_dir_args *args = arg;
++
++ bstart = au_dbstart(dentry);
++ /* dentry is di-locked */
++ parent = dget_parent(dentry);
++ dir = parent->d_inode;
++ h_dir = h_parent->d_inode;
++ AuDebugOn(h_dir != au_h_iptr(dir, bdst));
++ IMustLock(h_dir);
++
++ err = au_lkup_neg(dentry, bdst);
++ if (unlikely(err < 0))
++ goto out;
++ h_path.dentry = au_h_dptr(dentry, bdst);
++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst);
++ err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path,
++ S_IRWXU | S_IRUGO | S_IXUGO);
++ if (unlikely(err))
++ goto out_put;
++ au_fset_cpdown(args->flags, MADE_DIR);
++
++ bend = au_dbend(dentry);
++ bopq = au_dbdiropq(dentry);
++ au_fclr_cpdown(args->flags, WHED);
++ au_fclr_cpdown(args->flags, DIROPQ);
++ if (au_dbwh(dentry) == bdst)
++ au_fset_cpdown(args->flags, WHED);
++ if (!au_ftest_cpdown(args->flags, PARENT_OPQ) && bopq <= bdst)
++ au_fset_cpdown(args->flags, PARENT_OPQ);
++ parent_opq = (au_ftest_cpdown(args->flags, PARENT_OPQ)
++ && args->parent == dentry);
++ h_inode = h_path.dentry->d_inode;
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ if (au_ftest_cpdown(args->flags, WHED)) {
++ err = au_cpdown_dir_opq(dentry, bdst, args);
++ if (unlikely(err)) {
++ mutex_unlock(&h_inode->i_mutex);
++ goto out_dir;
++ }
++ }
++
++ err = au_cpdown_attr(&h_path, au_h_dptr(dentry, bstart));
++ mutex_unlock(&h_inode->i_mutex);
++ if (unlikely(err))
++ goto out_opq;
++
++ if (au_ftest_cpdown(args->flags, WHED)) {
++ err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst);
++ if (unlikely(err))
++ goto out_opq;
++ }
++
++ inode = dentry->d_inode;
++ if (au_ibend(inode) < bdst)
++ au_set_ibend(inode, bdst);
++ au_set_h_iptr(inode, bdst, au_igrab(h_inode),
++ au_hi_flags(inode, /*isdir*/1));
++ goto out; /* success */
++
++ /* revert */
++ out_opq:
++ if (au_ftest_cpdown(args->flags, DIROPQ)) {
++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
++ rerr = au_diropq_remove(dentry, bdst);
++ mutex_unlock(&h_inode->i_mutex);
++ if (unlikely(rerr)) {
++ AuIOErr("failed removing diropq for %.*s b%d (%d)\n",
++ AuDLNPair(dentry), bdst, rerr);
++ err = -EIO;
++ goto out;
++ }
++ }
++ out_dir:
++ if (au_ftest_cpdown(args->flags, MADE_DIR)) {
++ rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path);
++ if (unlikely(rerr)) {
++ AuIOErr("failed removing %.*s b%d (%d)\n",
++ AuDLNPair(dentry), bdst, rerr);
++ err = -EIO;
++ }
++ }
++ out_put:
++ au_set_h_dptr(dentry, bdst, NULL);
++ if (au_dbend(dentry) == bdst)
++ au_update_dbend(dentry);
++ out:
++ dput(parent);
++ return err;
++}
++
++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst)
++{
++ int err;
++ struct au_cpdown_dir_args args = {
++ .parent = dget_parent(dentry),
++ .flags = 0
++ };
++
++ err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &args);
++ dput(args.parent);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* policies for create */
++
++static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex)
++{
++ for (; bindex >= 0; bindex--)
++ if (!au_br_rdonly(au_sbr(sb, bindex)))
++ return bindex;
++ return -EROFS;
++}
++
++/* top down parent */
++static int au_wbr_create_tdp(struct dentry *dentry, int isdir __maybe_unused)
++{
++ int err;
++ aufs_bindex_t bstart, bindex;
++ struct super_block *sb;
++ struct dentry *parent, *h_parent;
++
++ sb = dentry->d_sb;
++ bstart = au_dbstart(dentry);
++ err = bstart;
++ if (!au_br_rdonly(au_sbr(sb, bstart)))
++ goto out;
++
++ err = -EROFS;
++ parent = dget_parent(dentry);
++ for (bindex = au_dbstart(parent); bindex < bstart; bindex++) {
++ h_parent = au_h_dptr(parent, bindex);
++ if (!h_parent || !h_parent->d_inode)
++ continue;
++
++ if (!au_br_rdonly(au_sbr(sb, bindex))) {
++ err = bindex;
++ break;
++ }
++ }
++ dput(parent);
++
++ /* bottom up here */
++ if (unlikely(err < 0))
++ err = au_wbr_bu(sb, bstart - 1);
++
++ out:
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* an exception for the policy other than tdp */
++static int au_wbr_create_exp(struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bwh, bdiropq;
++ struct dentry *parent;
++
++ err = -1;
++ bwh = au_dbwh(dentry);
++ parent = dget_parent(dentry);
++ bdiropq = au_dbdiropq(parent);
++ if (bwh >= 0) {
++ if (bdiropq >= 0)
++ err = min(bdiropq, bwh);
++ else
++ err = bwh;
++ AuDbg("%d\n", err);
++ } else if (bdiropq >= 0) {
++ err = bdiropq;
++ AuDbg("%d\n", err);
++ }
++ dput(parent);
++
++ if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err)))
++ err = -1;
++
++ AuDbg("%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* round robin */
++static int au_wbr_create_init_rr(struct super_block *sb)
++{
++ int err;
++
++ err = au_wbr_bu(sb, au_sbend(sb));
++ atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */
++ /* smp_mb(); */
++
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++static int au_wbr_create_rr(struct dentry *dentry, int isdir)
++{
++ int err, nbr;
++ unsigned int u;
++ aufs_bindex_t bindex, bend;
++ struct super_block *sb;
++ atomic_t *next;
++
++ err = au_wbr_create_exp(dentry);
++ if (err >= 0)
++ goto out;
++
++ sb = dentry->d_sb;
++ next = &au_sbi(sb)->si_wbr_rr_next;
++ bend = au_sbend(sb);
++ nbr = bend + 1;
++ for (bindex = 0; bindex <= bend; bindex++) {
++ if (!isdir) {
++ err = atomic_dec_return(next) + 1;
++ /* modulo for 0 is meaningless */
++ if (unlikely(!err))
++ err = atomic_dec_return(next) + 1;
++ } else
++ err = atomic_read(next);
++ AuDbg("%d\n", err);
++ u = err;
++ err = u % nbr;
++ AuDbg("%d\n", err);
++ if (!au_br_rdonly(au_sbr(sb, err)))
++ break;
++ err = -EROFS;
++ }
++
++ out:
++ AuDbg("%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* most free space */
++static void au_mfs(struct dentry *dentry)
++{
++ struct super_block *sb;
++ struct au_branch *br;
++ struct au_wbr_mfs *mfs;
++ aufs_bindex_t bindex, bend;
++ int err;
++ unsigned long long b, bavail;
++ /* reduce the stack usage */
++ struct kstatfs *st;
++
++ st = kmalloc(sizeof(*st), GFP_NOFS);
++ if (unlikely(!st)) {
++ AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM);
++ return;
++ }
++
++ bavail = 0;
++ sb = dentry->d_sb;
++ mfs = &au_sbi(sb)->si_wbr_mfs;
++ MtxMustLock(&mfs->mfs_lock);
++ mfs->mfs_bindex = -EROFS;
++ mfs->mfsrr_bytes = 0;
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ if (au_br_rdonly(br))
++ continue;
++
++ /* sb->s_root for NFS is unreliable */
++ err = vfs_statfs(br->br_mnt->mnt_root, st);
++ if (unlikely(err)) {
++ AuWarn1("failed statfs, b%d, %d\n", bindex, err);
++ continue;
++ }
++
++ /* when the available size is equal, select the lower one */
++ BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail)
++ || sizeof(b) < sizeof(st->f_bsize));
++ b = st->f_bavail * st->f_bsize;
++ br->br_wbr->wbr_bytes = b;
++ if (b >= bavail) {
++ bavail = b;
++ mfs->mfs_bindex = bindex;
++ mfs->mfs_jiffy = jiffies;
++ }
++ }
++
++ mfs->mfsrr_bytes = bavail;
++ AuDbg("b%d\n", mfs->mfs_bindex);
++ kfree(st);
++}
++
++static int au_wbr_create_mfs(struct dentry *dentry, int isdir __maybe_unused)
++{
++ int err;
++ struct super_block *sb;
++ struct au_wbr_mfs *mfs;
++
++ err = au_wbr_create_exp(dentry);
++ if (err >= 0)
++ goto out;
++
++ sb = dentry->d_sb;
++ mfs = &au_sbi(sb)->si_wbr_mfs;
++ mutex_lock(&mfs->mfs_lock);
++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire)
++ || mfs->mfs_bindex < 0
++ || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex)))
++ au_mfs(dentry);
++ mutex_unlock(&mfs->mfs_lock);
++ err = mfs->mfs_bindex;
++
++ out:
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++static int au_wbr_create_init_mfs(struct super_block *sb)
++{
++ struct au_wbr_mfs *mfs;
++
++ mfs = &au_sbi(sb)->si_wbr_mfs;
++ mutex_init(&mfs->mfs_lock);
++ mfs->mfs_jiffy = 0;
++ mfs->mfs_bindex = -EROFS;
++
++ return 0;
++}
++
++static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused)
++{
++ mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock);
++ return 0;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* most free space and then round robin */
++static int au_wbr_create_mfsrr(struct dentry *dentry, int isdir)
++{
++ int err;
++ struct au_wbr_mfs *mfs;
++
++ err = au_wbr_create_mfs(dentry, isdir);
++ if (err >= 0) {
++ mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs;
++ mutex_lock(&mfs->mfs_lock);
++ if (mfs->mfsrr_bytes < mfs->mfsrr_watermark)
++ err = au_wbr_create_rr(dentry, isdir);
++ mutex_unlock(&mfs->mfs_lock);
++ }
++
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++static int au_wbr_create_init_mfsrr(struct super_block *sb)
++{
++ int err;
++
++ au_wbr_create_init_mfs(sb); /* ignore */
++ err = au_wbr_create_init_rr(sb);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* top down parent and most free space */
++static int au_wbr_create_pmfs(struct dentry *dentry, int isdir)
++{
++ int err, e2;
++ unsigned long long b;
++ aufs_bindex_t bindex, bstart, bend;
++ struct super_block *sb;
++ struct dentry *parent, *h_parent;
++ struct au_branch *br;
++
++ err = au_wbr_create_tdp(dentry, isdir);
++ if (unlikely(err < 0))
++ goto out;
++ parent = dget_parent(dentry);
++ bstart = au_dbstart(parent);
++ bend = au_dbtaildir(parent);
++ if (bstart == bend)
++ goto out_parent; /* success */
++
++ e2 = au_wbr_create_mfs(dentry, isdir);
++ if (e2 < 0)
++ goto out_parent; /* success */
++
++ /* when the available size is equal, select upper one */
++ sb = dentry->d_sb;
++ br = au_sbr(sb, err);
++ b = br->br_wbr->wbr_bytes;
++ AuDbg("b%d, %llu\n", err, b);
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ h_parent = au_h_dptr(parent, bindex);
++ if (!h_parent || !h_parent->d_inode)
++ continue;
++
++ br = au_sbr(sb, bindex);
++ if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) {
++ b = br->br_wbr->wbr_bytes;
++ err = bindex;
++ AuDbg("b%d, %llu\n", err, b);
++ }
++ }
++
++ out_parent:
++ dput(parent);
++ out:
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* policies for copyup */
++
++/* top down parent */
++static int au_wbr_copyup_tdp(struct dentry *dentry)
++{
++ return au_wbr_create_tdp(dentry, /*isdir, anything is ok*/0);
++}
++
++/* bottom up parent */
++static int au_wbr_copyup_bup(struct dentry *dentry)
++{
++ int err;
++ aufs_bindex_t bindex, bstart;
++ struct dentry *parent, *h_parent;
++ struct super_block *sb;
++
++ err = -EROFS;
++ sb = dentry->d_sb;
++ parent = dget_parent(dentry);
++ bstart = au_dbstart(parent);
++ for (bindex = au_dbstart(dentry); bindex >= bstart; bindex--) {
++ h_parent = au_h_dptr(parent, bindex);
++ if (!h_parent || !h_parent->d_inode)
++ continue;
++
++ if (!au_br_rdonly(au_sbr(sb, bindex))) {
++ err = bindex;
++ break;
++ }
++ }
++ dput(parent);
++
++ /* bottom up here */
++ if (unlikely(err < 0))
++ err = au_wbr_bu(sb, bstart - 1);
++
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++/* bottom up */
++static int au_wbr_copyup_bu(struct dentry *dentry)
++{
++ int err;
++
++ err = au_wbr_bu(dentry->d_sb, au_dbstart(dentry));
++
++ AuDbg("b%d\n", err);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_wbr_copyup_operations au_wbr_copyup_ops[] = {
++ [AuWbrCopyup_TDP] = {
++ .copyup = au_wbr_copyup_tdp
++ },
++ [AuWbrCopyup_BUP] = {
++ .copyup = au_wbr_copyup_bup
++ },
++ [AuWbrCopyup_BU] = {
++ .copyup = au_wbr_copyup_bu
++ }
++};
++
++struct au_wbr_create_operations au_wbr_create_ops[] = {
++ [AuWbrCreate_TDP] = {
++ .create = au_wbr_create_tdp
++ },
++ [AuWbrCreate_RR] = {
++ .create = au_wbr_create_rr,
++ .init = au_wbr_create_init_rr
++ },
++ [AuWbrCreate_MFS] = {
++ .create = au_wbr_create_mfs,
++ .init = au_wbr_create_init_mfs,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_MFSV] = {
++ .create = au_wbr_create_mfs,
++ .init = au_wbr_create_init_mfs,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_MFSRR] = {
++ .create = au_wbr_create_mfsrr,
++ .init = au_wbr_create_init_mfsrr,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_MFSRRV] = {
++ .create = au_wbr_create_mfsrr,
++ .init = au_wbr_create_init_mfsrr,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_PMFS] = {
++ .create = au_wbr_create_pmfs,
++ .init = au_wbr_create_init_mfs,
++ .fin = au_wbr_create_fin_mfs
++ },
++ [AuWbrCreate_PMFSV] = {
++ .create = au_wbr_create_pmfs,
++ .init = au_wbr_create_init_mfs,
++ .fin = au_wbr_create_fin_mfs
++ }
++};
+diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c
+new file mode 100644
+index 0000000..2b910bd
+--- /dev/null
++++ b/fs/aufs/whout.c
+@@ -0,0 +1,1052 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * whiteout for logical deletion and opaque directory
++ */
++
++#include <linux/fs.h>
++#include "aufs.h"
++
++#define WH_MASK S_IRUGO
++
++/*
++ * If a directory contains this file, then it is opaque. We start with the
++ * .wh. flag so that it is blocked by lookup.
++ */
++static struct qstr diropq_name = {
++ .name = AUFS_WH_DIROPQ,
++ .len = sizeof(AUFS_WH_DIROPQ) - 1
++};
++
++/*
++ * generate whiteout name, which is NOT terminated by NULL.
++ * @name: original d_name.name
++ * @len: original d_name.len
++ * @wh: whiteout qstr
++ * returns zero when succeeds, otherwise error.
++ * succeeded value as wh->name should be freed by kfree().
++ */
++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name)
++{
++ char *p;
++
++ if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN))
++ return -ENAMETOOLONG;
++
++ wh->len = name->len + AUFS_WH_PFX_LEN;
++ p = kmalloc(wh->len, GFP_NOFS);
++ wh->name = p;
++ if (p) {
++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
++ memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len);
++ /* smp_mb(); */
++ return 0;
++ }
++ return -ENOMEM;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * test if the @wh_name exists under @h_parent.
++ * @try_sio specifies the necessary of super-io.
++ */
++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name,
++ struct au_branch *br, int try_sio)
++{
++ int err;
++ struct dentry *wh_dentry;
++ struct inode *h_dir;
++
++ h_dir = h_parent->d_inode;
++ if (!try_sio)
++ wh_dentry = au_lkup_one(wh_name, h_parent, br, /*nd*/NULL);
++ else
++ wh_dentry = au_sio_lkup_one(wh_name, h_parent, br);
++ err = PTR_ERR(wh_dentry);
++ if (IS_ERR(wh_dentry))
++ goto out;
++
++ err = 0;
++ if (!wh_dentry->d_inode)
++ goto out_wh; /* success */
++
++ err = 1;
++ if (S_ISREG(wh_dentry->d_inode->i_mode))
++ goto out_wh; /* success */
++
++ err = -EIO;
++ AuIOErr("%.*s Invalid whiteout entry type 0%o.\n",
++ AuDLNPair(wh_dentry), wh_dentry->d_inode->i_mode);
++
++ out_wh:
++ dput(wh_dentry);
++ out:
++ return err;
++}
++
++/*
++ * test if the @h_dentry sets opaque or not.
++ */
++int au_diropq_test(struct dentry *h_dentry, struct au_branch *br)
++{
++ int err;
++ struct inode *h_dir;
++
++ h_dir = h_dentry->d_inode;
++ err = au_wh_test(h_dentry, &diropq_name, br,
++ au_test_h_perm_sio(h_dir, MAY_EXEC));
++ return err;
++}
++
++/*
++ * returns a negative dentry whose name is unique and temporary.
++ */
++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
++ struct qstr *prefix)
++{
++#define HEX_LEN 4
++ struct dentry *dentry;
++ int i;
++ char defname[AUFS_WH_PFX_LEN * 2 + DNAME_INLINE_LEN_MIN + 1
++ + HEX_LEN + 1], *name, *p;
++ static unsigned short cnt;
++ struct qstr qs;
++
++ name = defname;
++ qs.len = sizeof(defname) - DNAME_INLINE_LEN_MIN + prefix->len - 1;
++ if (unlikely(prefix->len > DNAME_INLINE_LEN_MIN)) {
++ dentry = ERR_PTR(-ENAMETOOLONG);
++ if (unlikely(qs.len >= PATH_MAX))
++ goto out;
++ dentry = ERR_PTR(-ENOMEM);
++ name = kmalloc(qs.len + 1, GFP_NOFS);
++ if (unlikely(!name))
++ goto out;
++ }
++
++ /* doubly whiteout-ed */
++ memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2);
++ p = name + AUFS_WH_PFX_LEN * 2;
++ memcpy(p, prefix->name, prefix->len);
++ p += prefix->len;
++ *p++ = '.';
++ AuDebugOn(name + qs.len + 1 - p <= HEX_LEN);
++
++ qs.name = name;
++ for (i = 0; i < 3; i++) {
++ sprintf(p, "%.*d", HEX_LEN, cnt++);
++ dentry = au_sio_lkup_one(&qs, h_parent, br);
++ if (IS_ERR(dentry) || !dentry->d_inode)
++ goto out_name;
++ dput(dentry);
++ }
++ /* AuWarn("could not get random name\n"); */
++ dentry = ERR_PTR(-EEXIST);
++ AuDbg("%.*s\n", AuLNPair(&qs));
++ BUG();
++
++ out_name:
++ if (name != defname)
++ kfree(name);
++ out:
++ return dentry;
++#undef HEX_LEN
++}
++
++/*
++ * rename the @h_dentry on @br to the whiteouted temporary name.
++ */
++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br)
++{
++ int err;
++ struct path h_path = {
++ .mnt = br->br_mnt
++ };
++ struct inode *h_dir;
++ struct dentry *h_parent;
++
++ h_parent = h_dentry->d_parent; /* dir inode is locked */
++ h_dir = h_parent->d_inode;
++ IMustLock(h_dir);
++
++ h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name);
++ err = PTR_ERR(h_path.dentry);
++ if (IS_ERR(h_path.dentry))
++ goto out;
++
++ /* under the same dir, no need to lock_rename() */
++ err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path);
++ AuTraceErr(err);
++ dput(h_path.dentry);
++
++ out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++/*
++ * functions for removing a whiteout
++ */
++
++static int do_unlink_wh(struct inode *h_dir, struct path *h_path)
++{
++ int force;
++
++ /*
++ * forces superio when the dir has a sticky bit.
++ * this may be a violation of unix fs semantics.
++ */
++ force = (h_dir->i_mode & S_ISVTX)
++ && h_path->dentry->d_inode->i_uid != current->fsuid;
++ return vfsub_unlink(h_dir, h_path, force);
++}
++
++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path,
++ struct dentry *dentry)
++{
++ int err;
++
++ err = do_unlink_wh(h_dir, h_path);
++ if (!err && dentry)
++ au_set_dbwh(dentry, -1);
++
++ return err;
++}
++
++static int unlink_wh_name(struct dentry *h_parent, struct qstr *wh,
++ struct au_branch *br)
++{
++ int err;
++ struct path h_path = {
++ .mnt = br->br_mnt
++ };
++
++ err = 0;
++ h_path.dentry = au_lkup_one(wh, h_parent, br, /*nd*/NULL);
++ if (IS_ERR(h_path.dentry))
++ err = PTR_ERR(h_path.dentry);
++ else {
++ if (h_path.dentry->d_inode
++ && S_ISREG(h_path.dentry->d_inode->i_mode))
++ err = do_unlink_wh(h_parent->d_inode, &h_path);
++ dput(h_path.dentry);
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++/*
++ * initialize/clean whiteout for a branch
++ */
++
++static void au_wh_clean(struct inode *h_dir, struct path *whpath,
++ const int isdir)
++{
++ int err;
++
++ if (!whpath->dentry->d_inode)
++ return;
++
++ err = mnt_want_write(whpath->mnt);
++ if (!err) {
++ if (isdir)
++ err = vfsub_rmdir(h_dir, whpath);
++ else
++ err = vfsub_unlink(h_dir, whpath, /*force*/0);
++ mnt_drop_write(whpath->mnt);
++ }
++ if (unlikely(err))
++ AuWarn("failed removing %.*s (%d), ignored.\n",
++ AuDLNPair(whpath->dentry), err);
++}
++
++static int test_linkable(struct dentry *h_root)
++{
++ struct inode *h_dir = h_root->d_inode;
++
++ if (h_dir->i_op && h_dir->i_op->link)
++ return 0;
++
++ AuErr("%.*s (%s) doesn't support link(2), use noplink and rw+nolwh\n",
++ AuDLNPair(h_root), au_sbtype(h_root->d_sb));
++ return -ENOSYS;
++}
++
++/* todo: should this mkdir be done in /sbin/mount.aufs helper? */
++static int au_whdir(struct inode *h_dir, struct path *path)
++{
++ int err;
++
++ err = -EEXIST;
++ if (!path->dentry->d_inode) {
++ int mode = S_IRWXU;
++
++ if (au_test_nfs(path->dentry->d_sb))
++ mode |= S_IXUGO;
++ err = mnt_want_write(path->mnt);
++ if (!err) {
++ err = vfsub_mkdir(h_dir, path, mode);
++ mnt_drop_write(path->mnt);
++ }
++ } else if (S_ISDIR(path->dentry->d_inode->i_mode))
++ err = 0;
++ else
++ AuErr("unknown %.*s exists\n", AuDLNPair(path->dentry));
++
++ return err;
++}
++
++struct au_wh_base {
++ const struct qstr *name;
++ struct dentry *dentry;
++};
++
++static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[],
++ struct path *h_path)
++{
++ h_path->dentry = base[AuBrWh_BASE].dentry;
++ au_wh_clean(h_dir, h_path, /*isdir*/0);
++ h_path->dentry = base[AuBrWh_PLINK].dentry;
++ au_wh_clean(h_dir, h_path, /*isdir*/1);
++ h_path->dentry = base[AuBrWh_ORPH].dentry;
++ au_wh_clean(h_dir, h_path, /*isdir*/1);
++}
++
++/*
++ * returns tri-state,
++ * minus: error, caller should print the mesage
++ * zero: succuess
++ * plus: error, caller should NOT print the mesage
++ */
++static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr,
++ int do_plink, struct au_wh_base base[],
++ struct path *h_path)
++{
++ int err;
++ struct inode *h_dir;
++
++ h_dir = h_root->d_inode;
++ h_path->dentry = base[AuBrWh_BASE].dentry;
++ au_wh_clean(h_dir, h_path, /*isdir*/0);
++ h_path->dentry = base[AuBrWh_PLINK].dentry;
++ if (do_plink) {
++ err = test_linkable(h_root);
++ if (unlikely(err)) {
++ err = 1;
++ goto out;
++ }
++
++ err = au_whdir(h_dir, h_path);
++ if (unlikely(err))
++ goto out;
++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry);
++ } else
++ au_wh_clean(h_dir, h_path, /*isdir*/1);
++ h_path->dentry = base[AuBrWh_ORPH].dentry;
++ err = au_whdir(h_dir, h_path);
++ if (unlikely(err))
++ goto out;
++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry);
++
++ out:
++ return err;
++}
++
++/*
++ * for the moment, aufs supports the branch filesystem which does not support
++ * link(2). testing on FAT which does not support i_op->setattr() fully either,
++ * copyup failed. finally, such filesystem will not be used as the writable
++ * branch.
++ *
++ * returns tri-state, see above.
++ */
++static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr,
++ int do_plink, struct au_wh_base base[],
++ struct path *h_path)
++{
++ int err;
++ struct inode *h_dir;
++
++ WbrWhMustWriteLock(wbr);
++
++ err = test_linkable(h_root);
++ if (unlikely(err)) {
++ err = 1;
++ goto out;
++ }
++
++ /*
++ * todo: should this create be done in /sbin/mount.aufs helper?
++ */
++ err = -EEXIST;
++ h_dir = h_root->d_inode;
++ if (!base[AuBrWh_BASE].dentry->d_inode) {
++ err = mnt_want_write(h_path->mnt);
++ if (!err) {
++ h_path->dentry = base[AuBrWh_BASE].dentry;
++ err = vfsub_create(h_dir, h_path, WH_MASK);
++ mnt_drop_write(h_path->mnt);
++ }
++ } else if (S_ISREG(base[AuBrWh_BASE].dentry->d_inode->i_mode))
++ err = 0;
++ else
++ AuErr("unknown %.*s/%.*s exists\n",
++ AuDLNPair(h_root), AuDLNPair(base[AuBrWh_BASE].dentry));
++ if (unlikely(err))
++ goto out;
++
++ h_path->dentry = base[AuBrWh_PLINK].dentry;
++ if (do_plink) {
++ err = au_whdir(h_dir, h_path);
++ if (unlikely(err))
++ goto out;
++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry);
++ } else
++ au_wh_clean(h_dir, h_path, /*isdir*/1);
++ wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry);
++
++ h_path->dentry = base[AuBrWh_ORPH].dentry;
++ err = au_whdir(h_dir, h_path);
++ if (unlikely(err))
++ goto out;
++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry);
++
++ out:
++ return err;
++}
++
++/*
++ * initialize the whiteout base file/dir for @br.
++ */
++int au_wh_init(struct dentry *h_root, struct au_branch *br,
++ struct super_block *sb)
++{
++ int err, i;
++ const unsigned char do_plink
++ = !!au_opt_test(au_mntflags(sb), PLINK);
++ struct path path = {
++ .mnt = br->br_mnt
++ };
++ struct inode *h_dir;
++ struct au_wbr *wbr = br->br_wbr;
++ static const struct qstr base_name[] = {
++ [AuBrWh_BASE] = {
++ .name = AUFS_BASE_NAME,
++ .len = sizeof(AUFS_BASE_NAME) - 1
++ },
++ [AuBrWh_PLINK] = {
++ .name = AUFS_PLINKDIR_NAME,
++ .len = sizeof(AUFS_PLINKDIR_NAME) - 1
++ },
++ [AuBrWh_ORPH] = {
++ .name = AUFS_ORPHDIR_NAME,
++ .len = sizeof(AUFS_ORPHDIR_NAME) - 1
++ }
++ };
++ struct au_wh_base base[] = {
++ [AuBrWh_BASE] = {
++ .name = base_name + AuBrWh_BASE,
++ .dentry = NULL
++ },
++ [AuBrWh_PLINK] = {
++ .name = base_name + AuBrWh_PLINK,
++ .dentry = NULL
++ },
++ [AuBrWh_ORPH] = {
++ .name = base_name + AuBrWh_ORPH,
++ .dentry = NULL
++ }
++ };
++
++ if (wbr)
++ WbrWhMustWriteLock(wbr);
++
++ h_dir = h_root->d_inode;
++ for (i = 0; i < AuBrWh_Last; i++) {
++ /* doubly whiteouted */
++ struct dentry *d;
++
++ d = au_wh_lkup(h_root, (void *)base[i].name, br);
++ err = PTR_ERR(d);
++ if (IS_ERR(d))
++ goto out;
++
++ base[i].dentry = d;
++ AuDebugOn(wbr
++ && wbr->wbr_wh[i]
++ && wbr->wbr_wh[i] != base[i].dentry);
++ }
++
++ if (wbr)
++ for (i = 0; i < AuBrWh_Last; i++) {
++ dput(wbr->wbr_wh[i]);
++ wbr->wbr_wh[i] = NULL;
++ }
++
++ err = 0;
++
++ switch (br->br_perm) {
++ case AuBrPerm_RO:
++ case AuBrPerm_ROWH:
++ case AuBrPerm_RR:
++ case AuBrPerm_RRWH:
++ au_wh_init_ro(h_dir, base, &path);
++ break;
++
++ case AuBrPerm_RWNoLinkWH:
++ err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path);
++ if (err > 0)
++ goto out;
++ else if (err)
++ goto out_err;
++ break;
++
++ case AuBrPerm_RW:
++ err = au_wh_init_rw(h_root, wbr, do_plink, base, &path);
++ if (err > 0)
++ goto out;
++ else if (err)
++ goto out_err;
++ break;
++
++ default:
++ BUG();
++ }
++ goto out; /* success */
++
++ out_err:
++ AuErr("an error(%d) on the writable branch %.*s(%s)\n",
++ err, AuDLNPair(h_root), au_sbtype(h_root->d_sb));
++ out:
++ for (i = 0; i < AuBrWh_Last; i++)
++ dput(base[i].dentry);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++/*
++ * whiteouts are all hard-linked usually.
++ * when its link count reaches a ceiling, we create a new whiteout base
++ * asynchronously.
++ */
++
++struct reinit_br_wh {
++ struct super_block *sb;
++ struct au_branch *br;
++};
++
++static void reinit_br_wh(void *arg)
++{
++ int err;
++ aufs_bindex_t bindex;
++ struct path h_path;
++ struct reinit_br_wh *a = arg;
++ struct au_wbr *wbr;
++ struct inode *dir;
++ struct dentry *h_root;
++ struct au_hinode *hdir;
++
++ err = 0;
++ wbr = a->br->br_wbr;
++ /* big aufs lock */
++ si_noflush_write_lock(a->sb);
++ if (!au_br_writable(a->br->br_perm))
++ goto out;
++ bindex = au_br_index(a->sb, a->br->br_id);
++ if (unlikely(bindex < 0))
++ goto out;
++
++ di_read_lock_parent(a->sb->s_root, AuLock_IR);
++ dir = a->sb->s_root->d_inode;
++ hdir = au_hi(dir, bindex);
++ h_root = au_h_dptr(a->sb->s_root, bindex);
++
++ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ wbr_wh_write_lock(wbr);
++ err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode,
++ h_root, a->br);
++ if (!err) {
++ err = mnt_want_write(a->br->br_mnt);
++ if (!err) {
++ h_path.dentry = wbr->wbr_whbase;
++ h_path.mnt = a->br->br_mnt;
++ err = vfsub_unlink(hdir->hi_inode, &h_path, /*force*/0);
++ mnt_drop_write(a->br->br_mnt);
++ }
++ } else {
++ AuWarn("%.*s is moved, ignored\n", AuDLNPair(wbr->wbr_whbase));
++ err = 0;
++ }
++ dput(wbr->wbr_whbase);
++ wbr->wbr_whbase = NULL;
++ if (!err)
++ err = au_wh_init(h_root, a->br, a->sb);
++ wbr_wh_write_unlock(wbr);
++ au_hin_imtx_unlock(hdir);
++ di_read_unlock(a->sb->s_root, AuLock_IR);
++
++ out:
++ if (wbr)
++ atomic_dec(&wbr->wbr_wh_running);
++ atomic_dec(&a->br->br_count);
++ au_nwt_done(&au_sbi(a->sb)->si_nowait);
++ si_write_unlock(a->sb);
++ kfree(arg);
++ if (unlikely(err))
++ AuIOErr("err %d\n", err);
++}
++
++static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br)
++{
++ int do_dec, wkq_err;
++ struct reinit_br_wh *arg;
++
++ do_dec = 1;
++ if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1)
++ goto out;
++
++ /* ignore ENOMEM */
++ arg = kmalloc(sizeof(*arg), GFP_NOFS);
++ if (arg) {
++ /*
++ * dec(wh_running), kfree(arg) and dec(br_count)
++ * in reinit function
++ */
++ arg->sb = sb;
++ arg->br = br;
++ atomic_inc(&br->br_count);
++ wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb);
++ if (unlikely(wkq_err)) {
++ atomic_dec(&br->br_wbr->wbr_wh_running);
++ atomic_dec(&br->br_count);
++ kfree(arg);
++ }
++ do_dec = 0;
++ }
++
++ out:
++ if (do_dec)
++ atomic_dec(&br->br_wbr->wbr_wh_running);
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * create the whiteout @wh.
++ */
++static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex,
++ struct dentry *wh)
++{
++ int err;
++ struct path h_path = {
++ .dentry = wh
++ };
++ struct au_branch *br;
++ struct au_wbr *wbr;
++ struct dentry *h_parent;
++ struct inode *h_dir;
++
++ h_parent = wh->d_parent; /* dir inode is locked */
++ h_dir = h_parent->d_inode;
++ IMustLock(h_dir);
++
++ br = au_sbr(sb, bindex);
++ h_path.mnt = br->br_mnt;
++ wbr = br->br_wbr;
++ wbr_wh_read_lock(wbr);
++ if (wbr->wbr_whbase) {
++ err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path);
++ if (!err || err != -EMLINK)
++ goto out;
++
++ /* link count full. re-initialize br_whbase. */
++ kick_reinit_br_wh(sb, br);
++ }
++
++ /* return this error in this context */
++ err = vfsub_create(h_dir, &h_path, WH_MASK);
++
++ out:
++ wbr_wh_read_unlock(wbr);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * create or remove the diropq.
++ */
++static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int flags)
++{
++ struct dentry *opq_dentry, *h_dentry;
++ struct super_block *sb;
++ struct au_branch *br;
++ int err;
++
++ sb = dentry->d_sb;
++ br = au_sbr(sb, bindex);
++ h_dentry = au_h_dptr(dentry, bindex);
++ opq_dentry = au_lkup_one(&diropq_name, h_dentry, br, /*nd*/NULL);
++ if (IS_ERR(opq_dentry))
++ goto out;
++
++ if (au_ftest_diropq(flags, CREATE)) {
++ err = link_or_create_wh(sb, bindex, opq_dentry);
++ if (!err) {
++ au_set_dbdiropq(dentry, bindex);
++ goto out; /* success */
++ }
++ } else {
++ struct path tmp = {
++ .dentry = opq_dentry,
++ .mnt = br->br_mnt
++ };
++ err = do_unlink_wh(au_h_iptr(dentry->d_inode, bindex), &tmp);
++ if (!err)
++ au_set_dbdiropq(dentry, -1);
++ }
++ dput(opq_dentry);
++ opq_dentry = ERR_PTR(err);
++
++ out:
++ return opq_dentry;
++}
++
++struct do_diropq_args {
++ struct dentry **errp;
++ struct dentry *dentry;
++ aufs_bindex_t bindex;
++ unsigned int flags;
++};
++
++static void call_do_diropq(void *args)
++{
++ struct do_diropq_args *a = args;
++ *a->errp = do_diropq(a->dentry, a->bindex, a->flags);
++}
++
++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int flags)
++{
++ struct dentry *diropq, *h_dentry;
++
++ h_dentry = au_h_dptr(dentry, bindex);
++ if (!au_test_h_perm_sio(h_dentry->d_inode, MAY_EXEC | MAY_WRITE))
++ diropq = do_diropq(dentry, bindex, flags);
++ else {
++ int wkq_err;
++ struct do_diropq_args args = {
++ .errp = &diropq,
++ .dentry = dentry,
++ .bindex = bindex,
++ .flags = flags
++ };
++
++ wkq_err = au_wkq_wait(call_do_diropq, &args);
++ if (unlikely(wkq_err))
++ diropq = ERR_PTR(wkq_err);
++ }
++
++ return diropq;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * lookup whiteout dentry.
++ * @h_parent: lower parent dentry which must exist and be locked
++ * @base_name: name of dentry which will be whiteouted
++ * returns dentry for whiteout.
++ */
++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name,
++ struct au_branch *br)
++{
++ int err;
++ struct qstr wh_name;
++ struct dentry *wh_dentry;
++
++ err = au_wh_name_alloc(&wh_name, base_name);
++ wh_dentry = ERR_PTR(err);
++ if (!err) {
++ wh_dentry = au_lkup_one(&wh_name, h_parent, br, /*nd*/NULL);
++ kfree(wh_name.name);
++ }
++ return wh_dentry;
++}
++
++/*
++ * link/create a whiteout for @dentry on @bindex.
++ */
++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent)
++{
++ struct dentry *wh_dentry;
++ struct super_block *sb;
++ int err;
++
++ sb = dentry->d_sb;
++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex));
++ if (!IS_ERR(wh_dentry) && !wh_dentry->d_inode) {
++ err = link_or_create_wh(sb, bindex, wh_dentry);
++ if (!err)
++ au_set_dbwh(dentry, bindex);
++ else {
++ dput(wh_dentry);
++ wh_dentry = ERR_PTR(err);
++ }
++ }
++
++ return wh_dentry;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* Delete all whiteouts in this directory on branch bindex. */
++static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist,
++ aufs_bindex_t bindex, struct au_branch *br)
++{
++ int err;
++ unsigned long ul, n;
++ struct qstr wh_name;
++ char *p;
++ struct hlist_head *head;
++ struct au_vdir_wh *tpos;
++ struct hlist_node *pos;
++ struct au_vdir_destr *str;
++
++ err = -ENOMEM;
++ p = __getname();
++ wh_name.name = p;
++ if (unlikely(!wh_name.name))
++ goto out;
++
++ err = 0;
++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN);
++ p += AUFS_WH_PFX_LEN;
++ n = whlist->nh_num;
++ head = whlist->nh_head;
++ for (ul = 0; !err && ul < n; ul++, head++) {
++ hlist_for_each_entry(tpos, pos, head, wh_hash) {
++ if (tpos->wh_bindex != bindex)
++ continue;
++
++ str = &tpos->wh_str;
++ if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) {
++ memcpy(p, str->name, str->len);
++ wh_name.len = AUFS_WH_PFX_LEN + str->len;
++ err = unlink_wh_name(h_dentry, &wh_name, br);
++ if (!err)
++ continue;
++ break;
++ }
++ AuIOErr("whiteout name too long %.*s\n",
++ str->len, str->name);
++ err = -EIO;
++ break;
++ }
++ }
++ __putname(wh_name.name);
++
++ out:
++ return err;
++}
++
++struct del_wh_children_args {
++ int *errp;
++ struct dentry *h_dentry;
++ struct au_nhash *whlist;
++ aufs_bindex_t bindex;
++ struct au_branch *br;
++};
++
++static void call_del_wh_children(void *args)
++{
++ struct del_wh_children_args *a = args;
++ *a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->br);
++}
++
++/* ---------------------------------------------------------------------- */
++
++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp)
++{
++ struct au_whtmp_rmdir *whtmp;
++ int err;
++ unsigned int rdhash;
++
++ SiMustAnyLock(sb);
++
++ whtmp = kmalloc(sizeof(*whtmp), gfp);
++ if (unlikely(!whtmp)) {
++ whtmp = ERR_PTR(-ENOMEM);
++ goto out;
++ }
++
++ whtmp->dir = NULL;
++ whtmp->wh_dentry = NULL;
++ /* no estimation for dir size */
++ rdhash = au_sbi(sb)->si_rdhash;
++ if (!rdhash)
++ rdhash = AUFS_RDHASH_DEF;
++ err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp);
++ if (unlikely(err)) {
++ kfree(whtmp);
++ whtmp = ERR_PTR(err);
++ }
++
++ out:
++ return whtmp;
++}
++
++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp)
++{
++ dput(whtmp->wh_dentry);
++ iput(whtmp->dir);
++ au_nhash_wh_free(&whtmp->whlist);
++ kfree(whtmp);
++}
++
++/*
++ * rmdir the whiteouted temporary named dir @h_dentry.
++ * @whlist: whiteouted children.
++ */
++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct au_nhash *whlist)
++{
++ int err;
++ struct path h_tmp;
++ struct inode *wh_inode, *h_dir;
++ struct au_branch *br;
++
++ h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */
++ IMustLock(h_dir);
++
++ br = au_sbr(dir->i_sb, bindex);
++ wh_inode = wh_dentry->d_inode;
++ mutex_lock_nested(&wh_inode->i_mutex, AuLsc_I_CHILD);
++
++ /*
++ * someone else might change some whiteouts while we were sleeping.
++ * it means this whlist may have an obsoleted entry.
++ */
++ if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE))
++ err = del_wh_children(wh_dentry, whlist, bindex, br);
++ else {
++ int wkq_err;
++ struct del_wh_children_args args = {
++ .errp = &err,
++ .h_dentry = wh_dentry,
++ .whlist = whlist,
++ .bindex = bindex,
++ .br = br
++ };
++
++ wkq_err = au_wkq_wait(call_del_wh_children, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ }
++ mutex_unlock(&wh_inode->i_mutex);
++
++ if (!err) {
++ h_tmp.dentry = wh_dentry;
++ h_tmp.mnt = br->br_mnt;
++ err = vfsub_rmdir(h_dir, &h_tmp);
++ /* d_drop(h_dentry); */
++ }
++
++ if (!err) {
++ if (au_ibstart(dir) == bindex) {
++ au_cpup_attr_timesizes(dir);
++ drop_nlink(dir);
++ }
++ return 0; /* success */
++ }
++
++ AuWarn("failed removing %.*s(%d), ignored\n",
++ AuDLNPair(wh_dentry), err);
++ return err;
++}
++
++static void call_rmdir_whtmp(void *args)
++{
++ int err;
++ struct au_whtmp_rmdir *a = args;
++ struct super_block *sb;
++ struct dentry *h_parent;
++ struct inode *h_dir;
++ struct au_branch *br;
++ struct au_hinode *hdir;
++
++ /* rmdir by nfsd may cause deadlock with this i_mutex */
++ /* mutex_lock(&a->dir->i_mutex); */
++ sb = a->dir->i_sb;
++ si_noflush_read_lock(sb);
++ err = au_test_ro(sb, a->bindex, NULL);
++ if (unlikely(err))
++ goto out;
++
++ err = -EIO;
++ br = au_sbr(sb, a->bindex);
++ ii_write_lock_parent(a->dir);
++ h_parent = dget_parent(a->wh_dentry);
++ h_dir = h_parent->d_inode;
++ hdir = au_hi(a->dir, a->bindex);
++ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT);
++ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, br);
++ if (!err) {
++ err = mnt_want_write(br->br_mnt);
++ if (!err) {
++ err = au_whtmp_rmdir(a->dir, a->bindex, a->wh_dentry,
++ &a->whlist);
++ mnt_drop_write(br->br_mnt);
++ }
++ }
++ au_hin_imtx_unlock(hdir);
++ dput(h_parent);
++ ii_write_unlock(a->dir);
++
++ out:
++ /* mutex_unlock(&a->dir->i_mutex); */
++ au_nwt_done(&au_sbi(sb)->si_nowait);
++ si_read_unlock(sb);
++ au_whtmp_rmdir_free(a);
++ if (unlikely(err))
++ AuIOErr("err %d\n", err);
++}
++
++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args)
++{
++ int wkq_err;
++
++ IMustLock(dir);
++
++ /* all post-process will be done in do_rmdir_whtmp(). */
++ args->dir = au_igrab(dir);
++ args->bindex = bindex;
++ args->wh_dentry = dget(wh_dentry);
++ wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, dir->i_sb);
++ if (unlikely(wkq_err)) {
++ AuWarn("rmdir error %.*s (%d), ignored\n",
++ AuDLNPair(wh_dentry), wkq_err);
++ au_whtmp_rmdir_free(args);
++ }
++}
+diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h
+new file mode 100644
+index 0000000..40c6926
+--- /dev/null
++++ b/fs/aufs/whout.h
+@@ -0,0 +1,87 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * whiteout for logical deletion and opaque directory
++ */
++
++#ifndef __AUFS_WHOUT_H__
++#define __AUFS_WHOUT_H__
++
++#ifdef __KERNEL__
++
++#include <linux/aufs_type.h>
++#include "dir.h"
++
++/* whout.c */
++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name);
++struct au_branch;
++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name,
++ struct au_branch *br, int try_sio);
++int au_diropq_test(struct dentry *h_dentry, struct au_branch *br);
++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
++ struct qstr *prefix);
++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br);
++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path,
++ struct dentry *dentry);
++int au_wh_init(struct dentry *h_parent, struct au_branch *br,
++ struct super_block *sb);
++
++/* diropq flags */
++#define AuDiropq_CREATE 1
++#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name)
++#define au_fset_diropq(flags, name) { (flags) |= AuDiropq_##name; }
++#define au_fclr_diropq(flags, name) { (flags) &= ~AuDiropq_##name; }
++
++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex,
++ unsigned int flags);
++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name,
++ struct au_branch *br);
++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex,
++ struct dentry *h_parent);
++
++/* real rmdir for the whiteout-ed dir */
++struct au_whtmp_rmdir {
++ struct inode *dir;
++ aufs_bindex_t bindex;
++ struct dentry *wh_dentry;
++ struct au_nhash whlist;
++};
++
++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp);
++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp);
++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct au_nhash *whlist);
++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex,
++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args);
++
++/* ---------------------------------------------------------------------- */
++
++static inline struct dentry *au_diropq_create(struct dentry *dentry,
++ aufs_bindex_t bindex)
++{
++ return au_diropq_sio(dentry, bindex, AuDiropq_CREATE);
++}
++
++static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex)
++{
++ return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE));
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_WHOUT_H__ */
+diff --git a/fs/aufs/wkq.c b/fs/aufs/wkq.c
+new file mode 100644
+index 0000000..89656e9
+--- /dev/null
++++ b/fs/aufs/wkq.c
+@@ -0,0 +1,259 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * workqueue for asynchronous/super-io operations
++ * todo: try new dredential scheme
++ */
++
++#include <linux/module.h>
++#include "aufs.h"
++
++/* internal workqueue named AUFS_WKQ_NAME */
++static struct au_wkq {
++ struct workqueue_struct *q;
++
++ /* balancing */
++ atomic_t busy;
++} *au_wkq;
++
++struct au_wkinfo {
++ struct work_struct wk;
++ struct super_block *sb;
++
++ unsigned int flags; /* see wkq.h */
++
++ au_wkq_func_t func;
++ void *args;
++
++ atomic_t *busyp;
++ struct completion *comp;
++};
++
++/* ---------------------------------------------------------------------- */
++
++static int enqueue(struct au_wkq *wkq, struct au_wkinfo *wkinfo)
++{
++ wkinfo->busyp = &wkq->busy;
++ if (au_ftest_wkq(wkinfo->flags, WAIT))
++ return !queue_work(wkq->q, &wkinfo->wk);
++ else
++ return !schedule_work(&wkinfo->wk);
++}
++
++static void do_wkq(struct au_wkinfo *wkinfo)
++{
++ unsigned int idle, n;
++ int i, idle_idx;
++
++ while (1) {
++ if (au_ftest_wkq(wkinfo->flags, WAIT)) {
++ idle_idx = 0;
++ idle = UINT_MAX;
++ for (i = 0; i < aufs_nwkq; i++) {
++ n = atomic_inc_return(&au_wkq[i].busy);
++ if (n == 1 && !enqueue(au_wkq + i, wkinfo))
++ return; /* success */
++
++ if (n < idle) {
++ idle_idx = i;
++ idle = n;
++ }
++ atomic_dec(&au_wkq[i].busy);
++ }
++ } else
++ idle_idx = aufs_nwkq;
++
++ atomic_inc(&au_wkq[idle_idx].busy);
++ if (!enqueue(au_wkq + idle_idx, wkinfo))
++ return; /* success */
++
++ /* impossible? */
++ AuWarn1("failed to queue_work()\n");
++ yield();
++ }
++}
++
++static void wkq_func(struct work_struct *wk)
++{
++ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk);
++
++ wkinfo->func(wkinfo->args);
++ atomic_dec_return(wkinfo->busyp);
++ if (au_ftest_wkq(wkinfo->flags, WAIT))
++ complete(wkinfo->comp);
++ else {
++ kobject_put(&au_sbi(wkinfo->sb)->si_kobj);
++ module_put(THIS_MODULE);
++ kfree(wkinfo);
++ }
++}
++
++/*
++ * Since struct completion is large, try allocating it dynamically.
++ */
++#if defined(CONFIG_4KSTACKS) || defined(AuTest4KSTACKS)
++#define AuWkqCompDeclare(name) struct completion *comp = NULL
++
++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp)
++{
++ *comp = kmalloc(sizeof(**comp), GFP_NOFS);
++ if (*comp) {
++ init_completion(*comp);
++ wkinfo->comp = *comp;
++ return 0;
++ }
++ return -ENOMEM;
++}
++
++static void au_wkq_comp_free(struct completion *comp)
++{
++ kfree(comp);
++}
++
++#else
++
++/* no braces */
++#define AuWkqCompDeclare(name) \
++ DECLARE_COMPLETION_ONSTACK(_ ## name); \
++ struct completion *comp = &_ ## name
++
++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp)
++{
++ wkinfo->comp = *comp;
++ return 0;
++}
++
++static void au_wkq_comp_free(struct completion *comp __maybe_unused)
++{
++ /* empty */
++}
++#endif /* 4KSTACKS */
++
++static void au_wkq_run(struct au_wkinfo *wkinfo)
++{
++ au_dbg_verify_kthread();
++ INIT_WORK(&wkinfo->wk, wkq_func);
++ do_wkq(wkinfo);
++}
++
++int au_wkq_wait(au_wkq_func_t func, void *args)
++{
++ int err;
++ AuWkqCompDeclare(comp);
++ struct au_wkinfo wkinfo = {
++ .flags = AuWkq_WAIT,
++ .func = func,
++ .args = args
++ };
++
++ err = au_wkq_comp_alloc(&wkinfo, &comp);
++ if (!err) {
++ au_wkq_run(&wkinfo);
++ /* no timeout, no interrupt */
++ wait_for_completion(wkinfo.comp);
++ au_wkq_comp_free(comp);
++ }
++
++ return err;
++
++}
++
++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb)
++{
++ int err;
++ struct au_wkinfo *wkinfo;
++
++ atomic_inc(&au_sbi(sb)->si_nowait.nw_len);
++
++ /*
++ * wkq_func() must free this wkinfo.
++ * it highly depends upon the implementation of workqueue.
++ */
++ err = 0;
++ wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS);
++ if (wkinfo) {
++ wkinfo->sb = sb;
++ wkinfo->flags = !AuWkq_WAIT;
++ wkinfo->func = func;
++ wkinfo->args = args;
++ wkinfo->comp = NULL;
++ kobject_get(&au_sbi(sb)->si_kobj);
++ __module_get(THIS_MODULE);
++
++ au_wkq_run(wkinfo);
++ } else {
++ err = -ENOMEM;
++ atomic_dec(&au_sbi(sb)->si_nowait.nw_len);
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++void au_nwt_init(struct au_nowait_tasks *nwt)
++{
++ atomic_set(&nwt->nw_len, 0);
++ /* smp_mb();*/ /* atomic_set */
++ init_waitqueue_head(&nwt->nw_wq);
++}
++
++void au_wkq_fin(void)
++{
++ int i;
++
++ for (i = 0; i < aufs_nwkq; i++)
++ if (au_wkq[i].q && !IS_ERR(au_wkq[i].q))
++ destroy_workqueue(au_wkq[i].q);
++ kfree(au_wkq);
++}
++
++int __init au_wkq_init(void)
++{
++ int err, i;
++ struct au_wkq *nowaitq;
++
++ /* '+1' is for accounting of nowait queue */
++ err = -ENOMEM;
++ au_wkq = kcalloc(aufs_nwkq + 1, sizeof(*au_wkq), GFP_NOFS);
++ if (unlikely(!au_wkq))
++ goto out;
++
++ err = 0;
++ for (i = 0; i < aufs_nwkq; i++) {
++ au_wkq[i].q = create_singlethread_workqueue(AUFS_WKQ_NAME);
++ if (au_wkq[i].q && !IS_ERR(au_wkq[i].q)) {
++ atomic_set(&au_wkq[i].busy, 0);
++ continue;
++ }
++
++ err = PTR_ERR(au_wkq[i].q);
++ au_wkq_fin();
++ goto out;
++ }
++
++ /* nowait accounting */
++ nowaitq = au_wkq + aufs_nwkq;
++ atomic_set(&nowaitq->busy, 0);
++ nowaitq->q = NULL;
++ /* smp_mb(); */ /* atomic_set */
++
++ out:
++ return err;
++}
+diff --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h
+new file mode 100644
+index 0000000..b5b6a61
+--- /dev/null
++++ b/fs/aufs/wkq.h
+@@ -0,0 +1,82 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * workqueue for asynchronous/super-io operations
++ * todo: try new credentials management scheme
++ */
++
++#ifndef __AUFS_WKQ_H__
++#define __AUFS_WKQ_H__
++
++#ifdef __KERNEL__
++
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/aufs_type.h>
++
++struct super_block;
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * in the next operation, wait for the 'nowait' tasks in system-wide workqueue
++ */
++struct au_nowait_tasks {
++ atomic_t nw_len;
++ wait_queue_head_t nw_wq;
++};
++
++/* ---------------------------------------------------------------------- */
++
++typedef void (*au_wkq_func_t)(void *args);
++
++/* wkq flags */
++#define AuWkq_WAIT 1
++#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name)
++#define au_fset_wkq(flags, name) { (flags) |= AuWkq_##name; }
++#define au_fclr_wkq(flags, name) { (flags) &= ~AuWkq_##name; }
++
++/* wkq.c */
++int au_wkq_wait(au_wkq_func_t func, void *args);
++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb);
++void au_nwt_init(struct au_nowait_tasks *nwt);
++int __init au_wkq_init(void);
++void au_wkq_fin(void);
++
++/* ---------------------------------------------------------------------- */
++
++static inline int au_test_wkq(struct task_struct *tsk)
++{
++ return !tsk->mm && !strcmp(tsk->comm, AUFS_WKQ_NAME);
++}
++
++static inline void au_nwt_done(struct au_nowait_tasks *nwt)
++{
++ if (!atomic_dec_return(&nwt->nw_len))
++ wake_up_all(&nwt->nw_wq);
++}
++
++static inline int au_nwt_flush(struct au_nowait_tasks *nwt)
++{
++ wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len));
++ return 0;
++}
++
++#endif /* __KERNEL__ */
++#endif /* __AUFS_WKQ_H__ */
+diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c
+new file mode 100644
+index 0000000..25826ef
+--- /dev/null
++++ b/fs/aufs/xino.c
+@@ -0,0 +1,1199 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * external inode number translation table and bitmap
++ */
++
++#include <linux/file.h>
++#include <linux/seq_file.h>
++#include <linux/uaccess.h>
++#include "aufs.h"
++
++ssize_t xino_fread(au_readf_t func, struct file *file, void *buf, size_t size,
++ loff_t *pos)
++{
++ ssize_t err;
++ mm_segment_t oldfs;
++
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ do {
++ /* todo: signal_pending? */
++ err = func(file, (char __user *)buf, size, pos);
++ } while (err == -EAGAIN || err == -EINTR);
++ set_fs(oldfs);
++
++#if 0 /* reserved for future use */
++ if (err > 0)
++ fsnotify_access(file->f_dentry);
++#endif
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++static ssize_t do_xino_fwrite(au_writef_t func, struct file *file, void *buf,
++ size_t size, loff_t *pos)
++{
++ ssize_t err;
++ mm_segment_t oldfs;
++
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ lockdep_off();
++ do {
++ /* todo: signal_pending? */
++ err = func(file, (const char __user *)buf, size, pos);
++ } while (err == -EAGAIN || err == -EINTR);
++ lockdep_on();
++ set_fs(oldfs);
++
++#if 0 /* reserved for future use */
++ if (err > 0)
++ fsnotify_modify(file->f_dentry);
++#endif
++
++ return err;
++}
++
++struct do_xino_fwrite_args {
++ ssize_t *errp;
++ au_writef_t func;
++ struct file *file;
++ void *buf;
++ size_t size;
++ loff_t *pos;
++};
++
++static void call_do_xino_fwrite(void *args)
++{
++ struct do_xino_fwrite_args *a = args;
++ *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos);
++}
++
++ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size,
++ loff_t *pos)
++{
++ ssize_t err;
++
++ /* todo: signal block and no wkq? */
++ /* todo: new credential scheme */
++ /*
++ * it breaks RLIMIT_FSIZE and normal user's limit,
++ * users should care about quota and real 'filesystem full.'
++ */
++ if (!au_test_wkq(current)) {
++ int wkq_err;
++ struct do_xino_fwrite_args args = {
++ .errp = &err,
++ .func = func,
++ .file = file,
++ .buf = buf,
++ .size = size,
++ .pos = pos
++ };
++
++ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args);
++ if (unlikely(wkq_err))
++ err = wkq_err;
++ } else
++ err = do_xino_fwrite(func, file, buf, size, pos);
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * create a new xinofile at the same place/path as @base_file.
++ */
++struct file *au_xino_create2(struct file *base_file, struct file *copy_src)
++{
++ struct file *file;
++ struct dentry *base, *dentry, *parent;
++ struct inode *dir;
++ struct qstr *name;
++ int err;
++
++ base = base_file->f_dentry;
++ parent = base->d_parent; /* dir inode is locked */
++ dir = parent->d_inode;
++ IMustLock(dir);
++
++ file = ERR_PTR(-EINVAL);
++ name = &base->d_name;
++ dentry = vfsub_lookup_one_len(name->name, parent, name->len);
++ if (IS_ERR(dentry)) {
++ file = (void *)dentry;
++ AuErr("%.*s lookup err %ld\n", AuLNPair(name), PTR_ERR(dentry));
++ goto out;
++ }
++
++ /* no need to mnt_want_write() since we call dentry_open() later */
++ err = vfs_create(dir, dentry, S_IRUGO | S_IWUGO, NULL);
++ if (unlikely(err)) {
++ file = ERR_PTR(err);
++ AuErr("%.*s create err %d\n", AuLNPair(name), err);
++ goto out_dput;
++ }
++
++ file = dentry_open(dget(dentry), mntget(base_file->f_vfsmnt),
++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE);
++ if (IS_ERR(file)) {
++ AuErr("%.*s open err %ld\n", AuLNPair(name), PTR_ERR(file));
++ goto out_dput;
++ }
++
++ err = vfsub_unlink(dir, &file->f_path, /*force*/0);
++ if (unlikely(err)) {
++ AuErr("%.*s unlink err %d\n", AuLNPair(name), err);
++ goto out_fput;
++ }
++
++ if (copy_src) {
++ /* no one can touch copy_src xino */
++ err = au_copy_file(file, copy_src,
++ i_size_read(copy_src->f_dentry->d_inode));
++ if (unlikely(err)) {
++ AuErr("%.*s copy err %d\n", AuLNPair(name), err);
++ goto out_fput;
++ }
++ }
++ goto out_dput; /* success */
++
++ out_fput:
++ fput(file);
++ file = ERR_PTR(err);
++ out_dput:
++ dput(dentry);
++ out:
++ return file;
++}
++
++struct au_xino_lock_dir {
++ struct au_hinode *hdir;
++ struct dentry *parent;
++ struct mutex *mtx;
++};
++
++static void au_xino_lock_dir(struct super_block *sb, struct file *xino,
++ struct au_xino_lock_dir *ldir)
++{
++ aufs_bindex_t brid, bindex;
++
++ ldir->hdir = NULL;
++ bindex = -1;
++ brid = au_xino_brid(sb);
++ if (brid >= 0)
++ bindex = au_br_index(sb, brid);
++ if (bindex >= 0) {
++ ldir->hdir = au_hi(sb->s_root->d_inode, bindex);
++ au_hin_imtx_lock_nested(ldir->hdir, AuLsc_I_PARENT);
++ } else {
++ ldir->parent = dget_parent(xino->f_dentry);
++ ldir->mtx = &ldir->parent->d_inode->i_mutex;
++ mutex_lock_nested(ldir->mtx, AuLsc_I_PARENT);
++ }
++}
++
++static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir)
++{
++ if (ldir->hdir)
++ au_hin_imtx_unlock(ldir->hdir);
++ else {
++ mutex_unlock(ldir->mtx);
++ dput(ldir->parent);
++ }
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* trucate xino files asynchronously */
++
++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex)
++{
++ int err;
++ aufs_bindex_t bi, bend;
++ struct au_branch *br;
++ struct file *new_xino, *file;
++ struct super_block *h_sb;
++ struct au_xino_lock_dir ldir;
++
++ err = -EINVAL;
++ bend = au_sbend(sb);
++ if (unlikely(bindex < 0 || bend < bindex))
++ goto out;
++ br = au_sbr(sb, bindex);
++ file = br->br_xino.xi_file;
++ if (!file)
++ goto out;
++
++ au_xino_lock_dir(sb, file, &ldir);
++ /* mnt_want_write() is unnecessary here */
++ new_xino = au_xino_create2(file, file);
++ au_xino_unlock_dir(&ldir);
++ err = PTR_ERR(new_xino);
++ if (IS_ERR(new_xino))
++ goto out;
++ err = 0;
++ fput(file);
++ br->br_xino.xi_file = new_xino;
++
++ h_sb = br->br_mnt->mnt_sb;
++ for (bi = 0; bi <= bend; bi++) {
++ if (unlikely(bi == bindex))
++ continue;
++ br = au_sbr(sb, bi);
++ if (br->br_mnt->mnt_sb != h_sb)
++ continue;
++
++ fput(br->br_xino.xi_file);
++ br->br_xino.xi_file = new_xino;
++ get_file(new_xino);
++ }
++
++ out:
++ return err;
++}
++
++struct xino_do_trunc_args {
++ struct super_block *sb;
++ struct au_branch *br;
++};
++
++static void xino_do_trunc(void *_args)
++{
++ struct xino_do_trunc_args *args = _args;
++ struct super_block *sb;
++ struct au_branch *br;
++ struct inode *dir;
++ int err;
++ aufs_bindex_t bindex;
++
++ err = 0;
++ sb = args->sb;
++ dir = sb->s_root->d_inode;
++ br = args->br;
++
++ si_noflush_write_lock(sb);
++ ii_read_lock_parent(dir);
++ bindex = au_br_index(sb, br->br_id);
++ err = au_xino_trunc(sb, bindex);
++ if (!err
++ && br->br_xino.xi_file->f_dentry->d_inode->i_blocks
++ >= br->br_xino_upper)
++ br->br_xino_upper += AUFS_XINO_TRUNC_STEP;
++
++ ii_read_unlock(dir);
++ if (unlikely(err))
++ AuWarn("err b%d, (%d)\n", bindex, err);
++ atomic_dec(&br->br_xino_running);
++ atomic_dec(&br->br_count);
++ au_nwt_done(&au_sbi(sb)->si_nowait);
++ si_write_unlock(sb);
++ kfree(args);
++}
++
++static void xino_try_trunc(struct super_block *sb, struct au_branch *br)
++{
++ struct xino_do_trunc_args *args;
++ int wkq_err;
++
++ if (br->br_xino.xi_file->f_dentry->d_inode->i_blocks
++ < br->br_xino_upper)
++ return;
++
++ if (atomic_inc_return(&br->br_xino_running) > 1)
++ goto out;
++
++ /* lock and kfree() will be called in trunc_xino() */
++ args = kmalloc(sizeof(*args), GFP_NOFS);
++ if (unlikely(!args)) {
++ AuErr1("no memory\n");
++ goto out_args;
++ }
++
++ atomic_inc_return(&br->br_count);
++ args->sb = sb;
++ args->br = br;
++ wkq_err = au_wkq_nowait(xino_do_trunc, args, sb);
++ if (!wkq_err)
++ return; /* success */
++
++ AuErr("wkq %d\n", wkq_err);
++ atomic_dec_return(&br->br_count);
++
++ out_args:
++ kfree(args);
++ out:
++ atomic_dec_return(&br->br_xino_running);
++}
++
++/* ---------------------------------------------------------------------- */
++
++static int au_xino_do_write(au_writef_t write, struct file *file,
++ ino_t h_ino, ino_t ino)
++{
++ loff_t pos;
++ ssize_t sz;
++
++ pos = h_ino;
++ if (unlikely(au_loff_max / sizeof(ino) - 1 < pos)) {
++ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino);
++ return -EFBIG;
++ }
++ pos *= sizeof(ino);
++ sz = xino_fwrite(write, file, &ino, sizeof(ino), &pos);
++ if (sz == sizeof(ino))
++ return 0; /* success */
++
++ AuIOErr("write failed (%zd)\n", sz);
++ return -EIO;
++}
++
++/*
++ * write @ino to the xinofile for the specified branch{@sb, @bindex}
++ * at the position of @h_ino.
++ * even if @ino is zero, it is written to the xinofile and means no entry.
++ * if the size of the xino file on a specific filesystem exceeds the watermark,
++ * try truncating it.
++ */
++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ ino_t ino)
++{
++ int err;
++ unsigned int mnt_flags;
++ struct au_branch *br;
++
++ BUILD_BUG_ON(sizeof(long long) != sizeof(au_loff_max)
++ || ((loff_t)-1) > 0);
++ SiMustAnyLock(sb);
++
++ mnt_flags = au_mntflags(sb);
++ if (!au_opt_test(mnt_flags, XINO))
++ return 0;
++
++ br = au_sbr(sb, bindex);
++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file,
++ h_ino, ino);
++ if (!err) {
++ if (au_opt_test(mnt_flags, TRUNC_XINO)
++ && au_test_fs_trunc_xino(br->br_mnt->mnt_sb))
++ xino_try_trunc(sb, br);
++ return 0; /* success */
++ }
++
++ AuIOErr("write failed (%d)\n", err);
++ return -EIO;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* aufs inode number bitmap */
++
++static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE;
++static ino_t xib_calc_ino(unsigned long pindex, int bit)
++{
++ ino_t ino;
++
++ AuDebugOn(bit < 0 || page_bits <= bit);
++ ino = AUFS_FIRST_INO + pindex * page_bits + bit;
++ return ino;
++}
++
++static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit)
++{
++ AuDebugOn(ino < AUFS_FIRST_INO);
++ ino -= AUFS_FIRST_INO;
++ *pindex = ino / page_bits;
++ *bit = ino % page_bits;
++}
++
++static int xib_pindex(struct super_block *sb, unsigned long pindex)
++{
++ int err;
++ loff_t pos;
++ ssize_t sz;
++ struct au_sbinfo *sbinfo;
++ struct file *xib;
++ unsigned long *p;
++
++ sbinfo = au_sbi(sb);
++ MtxMustLock(&sbinfo->si_xib_mtx);
++ AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE
++ || !au_opt_test(sbinfo->si_mntflags, XINO));
++
++ if (pindex == sbinfo->si_xib_last_pindex)
++ return 0;
++
++ xib = sbinfo->si_xib;
++ p = sbinfo->si_xib_buf;
++ pos = sbinfo->si_xib_last_pindex;
++ pos *= PAGE_SIZE;
++ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos);
++ if (unlikely(sz != PAGE_SIZE))
++ goto out;
++
++ pos = pindex;
++ pos *= PAGE_SIZE;
++ if (i_size_read(xib->f_dentry->d_inode) >= pos + PAGE_SIZE)
++ sz = xino_fread(sbinfo->si_xread, xib, p, PAGE_SIZE, &pos);
++ else {
++ memset(p, 0, PAGE_SIZE);
++ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos);
++ }
++ if (sz == PAGE_SIZE) {
++ sbinfo->si_xib_last_pindex = pindex;
++ return 0; /* success */
++ }
++
++ out:
++ AuIOErr1("write failed (%zd)\n", sz);
++ err = sz;
++ if (sz >= 0)
++ err = -EIO;
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ ino_t ino)
++{
++ int err, bit;
++ unsigned long pindex;
++ struct au_sbinfo *sbinfo;
++
++ if (!au_opt_test(au_mntflags(sb), XINO))
++ return 0;
++
++ err = 0;
++ if (ino) {
++ sbinfo = au_sbi(sb);
++ xib_calc_bit(ino, &pindex, &bit);
++ AuDebugOn(page_bits <= bit);
++ mutex_lock(&sbinfo->si_xib_mtx);
++ err = xib_pindex(sb, pindex);
++ if (!err) {
++ clear_bit(bit, sbinfo->si_xib_buf);
++ sbinfo->si_xib_next_bit = bit;
++ }
++ mutex_unlock(&sbinfo->si_xib_mtx);
++ }
++
++ if (!err)
++ err = au_xino_write(sb, bindex, h_ino, 0);
++ return err;
++}
++
++/* get an unused inode number from bitmap */
++ino_t au_xino_new_ino(struct super_block *sb)
++{
++ ino_t ino;
++ unsigned long *p, pindex, ul, pend;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++ int free_bit, err;
++
++ if (!au_opt_test(au_mntflags(sb), XINO))
++ return iunique(sb, AUFS_FIRST_INO);
++
++ sbinfo = au_sbi(sb);
++ mutex_lock(&sbinfo->si_xib_mtx);
++ p = sbinfo->si_xib_buf;
++ free_bit = sbinfo->si_xib_next_bit;
++ if (free_bit < page_bits && !test_bit(free_bit, p))
++ goto out; /* success */
++ free_bit = find_first_zero_bit(p, page_bits);
++ if (free_bit < page_bits)
++ goto out; /* success */
++
++ pindex = sbinfo->si_xib_last_pindex;
++ for (ul = pindex - 1; ul < ULONG_MAX; ul--) {
++ err = xib_pindex(sb, ul);
++ if (unlikely(err))
++ goto out_err;
++ free_bit = find_first_zero_bit(p, page_bits);
++ if (free_bit < page_bits)
++ goto out; /* success */
++ }
++
++ file = sbinfo->si_xib;
++ pend = i_size_read(file->f_dentry->d_inode) / PAGE_SIZE;
++ for (ul = pindex + 1; ul <= pend; ul++) {
++ err = xib_pindex(sb, ul);
++ if (unlikely(err))
++ goto out_err;
++ free_bit = find_first_zero_bit(p, page_bits);
++ if (free_bit < page_bits)
++ goto out; /* success */
++ }
++ BUG();
++
++ out:
++ set_bit(free_bit, p);
++ sbinfo->si_xib_next_bit++;
++ pindex = sbinfo->si_xib_last_pindex;
++ mutex_unlock(&sbinfo->si_xib_mtx);
++ ino = xib_calc_ino(pindex, free_bit);
++ AuDbg("i%lu\n", (unsigned long)ino);
++ return ino;
++ out_err:
++ mutex_unlock(&sbinfo->si_xib_mtx);
++ AuDbg("i0\n");
++ return 0;
++}
++
++/*
++ * read @ino from xinofile for the specified branch{@sb, @bindex}
++ * at the position of @h_ino.
++ * if @ino does not exist and @do_new is true, get new one.
++ */
++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
++ ino_t *ino)
++{
++ int err;
++ ssize_t sz;
++ loff_t pos;
++ struct file *file;
++ struct au_sbinfo *sbinfo;
++
++ *ino = 0;
++ if (!au_opt_test(au_mntflags(sb), XINO))
++ return 0; /* no xino */
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ pos = h_ino;
++ if (unlikely(au_loff_max / sizeof(*ino) - 1 < pos)) {
++ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino);
++ return -EFBIG;
++ }
++ pos *= sizeof(*ino);
++
++ file = au_sbr(sb, bindex)->br_xino.xi_file;
++ if (i_size_read(file->f_dentry->d_inode) < pos + sizeof(*ino))
++ return 0; /* no ino */
++
++ sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &pos);
++ if (sz == sizeof(*ino))
++ return 0; /* success */
++
++ err = sz;
++ if (unlikely(sz >= 0)) {
++ err = -EIO;
++ AuIOErr("xino read error (%zd)\n", sz);
++ }
++
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* create and set a new xino file */
++
++struct file *au_xino_create(struct super_block *sb, char *fname, int silent)
++{
++ struct file *file;
++ struct dentry *h_parent, *d;
++ struct inode *h_dir;
++ int err;
++
++ /*
++ * at mount-time, and the xino file is the default path,
++ * hinotify is disabled so we have no inotify events to ignore.
++ * when a user specified the xino, we cannot get au_hdir to be ignored.
++ */
++ file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE,
++ S_IRUGO | S_IWUGO);
++ if (IS_ERR(file)) {
++ if (!silent)
++ AuErr("open %s(%ld)\n", fname, PTR_ERR(file));
++ return file;
++ }
++
++ /* keep file count */
++ h_parent = dget_parent(file->f_dentry);
++ h_dir = h_parent->d_inode;
++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
++ /* mnt_want_write() is unnecessary here */
++ err = vfsub_unlink(h_dir, &file->f_path, /*force*/0);
++ mutex_unlock(&h_dir->i_mutex);
++ dput(h_parent);
++ if (unlikely(err)) {
++ if (!silent)
++ AuErr("unlink %s(%d)\n", fname, err);
++ goto out;
++ }
++
++ err = -EINVAL;
++ d = file->f_dentry;
++ if (unlikely(sb == d->d_sb)) {
++ if (!silent)
++ AuErr("%s must be outside\n", fname);
++ goto out;
++ }
++ if (unlikely(au_test_fs_bad_xino(d->d_sb))) {
++ if (!silent)
++ AuErr("xino doesn't support %s(%s)\n",
++ fname, au_sbtype(d->d_sb));
++ goto out;
++ }
++ return file; /* success */
++
++ out:
++ fput(file);
++ file = ERR_PTR(err);
++ return file;
++}
++
++/*
++ * find another branch who is on the same filesystem of the specified
++ * branch{@btgt}. search until @bend.
++ */
++static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt,
++ aufs_bindex_t bend)
++{
++ aufs_bindex_t bindex;
++ struct super_block *tgt_sb = au_sbr_sb(sb, btgt);
++
++ for (bindex = 0; bindex < btgt; bindex++)
++ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex)))
++ return bindex;
++ for (bindex++; bindex <= bend; bindex++)
++ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex)))
++ return bindex;
++ return -1;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * initialize the xinofile for the specified branch @br
++ * at the place/path where @base_file indicates.
++ * test whether another branch is on the same filesystem or not,
++ * if @do_test is true.
++ */
++int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t h_ino,
++ struct file *base_file, int do_test)
++{
++ int err;
++ ino_t ino;
++ aufs_bindex_t bend, bindex;
++ struct au_branch *shared_br, *b;
++ struct file *file;
++ struct super_block *tgt_sb;
++
++ shared_br = NULL;
++ bend = au_sbend(sb);
++ if (do_test) {
++ tgt_sb = br->br_mnt->mnt_sb;
++ for (bindex = 0; bindex <= bend; bindex++) {
++ b = au_sbr(sb, bindex);
++ if (tgt_sb == b->br_mnt->mnt_sb) {
++ shared_br = b;
++ break;
++ }
++ }
++ }
++
++ if (!shared_br || !shared_br->br_xino.xi_file) {
++ struct au_xino_lock_dir ldir;
++
++ au_xino_lock_dir(sb, base_file, &ldir);
++ /* mnt_want_write() is unnecessary here */
++ file = au_xino_create2(base_file, NULL);
++ au_xino_unlock_dir(&ldir);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++ br->br_xino.xi_file = file;
++ } else {
++ br->br_xino.xi_file = shared_br->br_xino.xi_file;
++ get_file(br->br_xino.xi_file);
++ }
++
++ ino = AUFS_ROOT_INO;
++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file,
++ h_ino, ino);
++ if (!err)
++ return 0; /* success */
++
++
++ out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/* trucate a xino bitmap file */
++
++/* todo: slow */
++static int do_xib_restore(struct super_block *sb, struct file *file, void *page)
++{
++ int err, bit;
++ ssize_t sz;
++ unsigned long pindex;
++ loff_t pos, pend;
++ struct au_sbinfo *sbinfo;
++ au_readf_t func;
++ ino_t *ino;
++ unsigned long *p;
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ MtxMustLock(&sbinfo->si_xib_mtx);
++ p = sbinfo->si_xib_buf;
++ func = sbinfo->si_xread;
++ pend = i_size_read(file->f_dentry->d_inode);
++ pos = 0;
++ while (pos < pend) {
++ sz = xino_fread(func, file, page, PAGE_SIZE, &pos);
++ err = sz;
++ if (unlikely(sz <= 0))
++ goto out;
++
++ err = 0;
++ for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) {
++ if (unlikely(*ino < AUFS_FIRST_INO))
++ continue;
++
++ xib_calc_bit(*ino, &pindex, &bit);
++ AuDebugOn(page_bits <= bit);
++ err = xib_pindex(sb, pindex);
++ if (!err)
++ set_bit(bit, p);
++ else
++ goto out;
++ }
++ }
++
++ out:
++ return err;
++}
++
++static int xib_restore(struct super_block *sb)
++{
++ int err;
++ aufs_bindex_t bindex, bend;
++ void *page;
++
++ err = -ENOMEM;
++ page = (void *)__get_free_page(GFP_NOFS);
++ if (unlikely(!page))
++ goto out;
++
++ err = 0;
++ bend = au_sbend(sb);
++ for (bindex = 0; !err && bindex <= bend; bindex++)
++ if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0)
++ err = do_xib_restore
++ (sb, au_sbr(sb, bindex)->br_xino.xi_file, page);
++ else
++ AuDbg("b%d\n", bindex);
++ free_page((unsigned long)page);
++
++ out:
++ return err;
++}
++
++int au_xib_trunc(struct super_block *sb)
++{
++ int err;
++ ssize_t sz;
++ loff_t pos;
++ struct au_xino_lock_dir ldir;
++ struct au_sbinfo *sbinfo;
++ unsigned long *p;
++ struct file *file;
++
++ SiMustWriteLock(sb);
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ if (!au_opt_test(sbinfo->si_mntflags, XINO))
++ goto out;
++
++ file = sbinfo->si_xib;
++ if (i_size_read(file->f_dentry->d_inode) <= PAGE_SIZE)
++ goto out;
++
++ au_xino_lock_dir(sb, file, &ldir);
++ /* mnt_want_write() is unnecessary here */
++ file = au_xino_create2(sbinfo->si_xib, NULL);
++ au_xino_unlock_dir(&ldir);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++ fput(sbinfo->si_xib);
++ sbinfo->si_xib = file;
++
++ p = sbinfo->si_xib_buf;
++ memset(p, 0, PAGE_SIZE);
++ pos = 0;
++ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xib, p, PAGE_SIZE, &pos);
++ if (unlikely(sz != PAGE_SIZE)) {
++ err = sz;
++ AuIOErr("err %d\n", err);
++ if (sz >= 0)
++ err = -EIO;
++ goto out;
++ }
++
++ mutex_lock(&sbinfo->si_xib_mtx);
++ /* mnt_want_write() is unnecessary here */
++ err = xib_restore(sb);
++ mutex_unlock(&sbinfo->si_xib_mtx);
++
++out:
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * xino mount option handlers
++ */
++static au_readf_t find_readf(struct file *h_file)
++{
++ const struct file_operations *fop = h_file->f_op;
++
++ if (fop) {
++ if (fop->read)
++ return fop->read;
++ if (fop->aio_read)
++ return do_sync_read;
++ }
++ return ERR_PTR(-ENOSYS);
++}
++
++static au_writef_t find_writef(struct file *h_file)
++{
++ const struct file_operations *fop = h_file->f_op;
++
++ if (fop) {
++ if (fop->write)
++ return fop->write;
++ if (fop->aio_write)
++ return do_sync_write;
++ }
++ return ERR_PTR(-ENOSYS);
++}
++
++/* xino bitmap */
++static void xino_clear_xib(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ sbinfo->si_xread = NULL;
++ sbinfo->si_xwrite = NULL;
++ if (sbinfo->si_xib)
++ fput(sbinfo->si_xib);
++ sbinfo->si_xib = NULL;
++ free_page((unsigned long)sbinfo->si_xib_buf);
++ sbinfo->si_xib_buf = NULL;
++}
++
++static int au_xino_set_xib(struct super_block *sb, struct file *base)
++{
++ int err;
++ loff_t pos;
++ struct au_sbinfo *sbinfo;
++ struct file *file;
++
++ SiMustWriteLock(sb);
++
++ sbinfo = au_sbi(sb);
++ file = au_xino_create2(base, sbinfo->si_xib);
++ err = PTR_ERR(file);
++ if (IS_ERR(file))
++ goto out;
++ if (sbinfo->si_xib)
++ fput(sbinfo->si_xib);
++ sbinfo->si_xib = file;
++ sbinfo->si_xread = find_readf(file);
++ sbinfo->si_xwrite = find_writef(file);
++
++ err = -ENOMEM;
++ if (!sbinfo->si_xib_buf)
++ sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS);
++ if (unlikely(!sbinfo->si_xib_buf))
++ goto out_unset;
++
++ sbinfo->si_xib_last_pindex = 0;
++ sbinfo->si_xib_next_bit = 0;
++ if (i_size_read(file->f_dentry->d_inode) < PAGE_SIZE) {
++ pos = 0;
++ err = xino_fwrite(sbinfo->si_xwrite, file, sbinfo->si_xib_buf,
++ PAGE_SIZE, &pos);
++ if (unlikely(err != PAGE_SIZE))
++ goto out_free;
++ }
++ err = 0;
++ goto out; /* success */
++
++ out_free:
++ free_page((unsigned long)sbinfo->si_xib_buf);
++ sbinfo->si_xib_buf = NULL;
++ if (err >= 0)
++ err = -EIO;
++ out_unset:
++ fput(sbinfo->si_xib);
++ sbinfo->si_xib = NULL;
++ sbinfo->si_xread = NULL;
++ sbinfo->si_xwrite = NULL;
++ out:
++ return err;
++}
++
++/* xino for each branch */
++static void xino_clear_br(struct super_block *sb)
++{
++ aufs_bindex_t bindex, bend;
++ struct au_branch *br;
++
++ bend = au_sbend(sb);
++ for (bindex = 0; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ if (!br || !br->br_xino.xi_file)
++ continue;
++
++ fput(br->br_xino.xi_file);
++ br->br_xino.xi_file = NULL;
++ }
++}
++
++static int au_xino_set_br(struct super_block *sb, struct file *base)
++{
++ int err;
++ ino_t ino;
++ aufs_bindex_t bindex, bend, bshared;
++ struct {
++ struct file *old, *new;
++ } *fpair, *p;
++ struct au_branch *br;
++ struct inode *inode;
++ au_writef_t writef;
++
++ SiMustWriteLock(sb);
++
++ err = -ENOMEM;
++ bend = au_sbend(sb);
++ fpair = kcalloc(bend + 1, sizeof(*fpair), GFP_NOFS);
++ if (unlikely(!fpair))
++ goto out;
++
++ inode = sb->s_root->d_inode;
++ ino = AUFS_ROOT_INO;
++ writef = au_sbi(sb)->si_xwrite;
++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) {
++ br = au_sbr(sb, bindex);
++ bshared = is_sb_shared(sb, bindex, bindex - 1);
++ if (bshared >= 0) {
++ /* shared xino */
++ *p = fpair[bshared];
++ get_file(p->new);
++ }
++
++ if (!p->new) {
++ /* new xino */
++ p->old = br->br_xino.xi_file;
++ p->new = au_xino_create2(base, br->br_xino.xi_file);
++ err = PTR_ERR(p->new);
++ if (IS_ERR(p->new)) {
++ p->new = NULL;
++ goto out_pair;
++ }
++ }
++
++ err = au_xino_do_write(writef, p->new,
++ au_h_iptr(inode, bindex)->i_ino, ino);
++ if (unlikely(err))
++ goto out_pair;
++ }
++
++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) {
++ br = au_sbr(sb, bindex);
++ if (br->br_xino.xi_file)
++ fput(br->br_xino.xi_file);
++ get_file(p->new);
++ br->br_xino.xi_file = p->new;
++ }
++
++ out_pair:
++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++)
++ if (p->new)
++ fput(p->new);
++ else
++ break;
++ kfree(fpair);
++ out:
++ return err;
++}
++
++void au_xino_clr(struct super_block *sb)
++{
++ struct au_sbinfo *sbinfo;
++
++ au_xigen_clr(sb);
++ xino_clear_xib(sb);
++ xino_clear_br(sb);
++ sbinfo = au_sbi(sb);
++ /* lvalue, do not call au_mntflags() */
++ au_opt_clr(sbinfo->si_mntflags, XINO);
++}
++
++int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount)
++{
++ int err, skip;
++ struct dentry *parent, *cur_parent;
++ struct qstr *dname, *cur_name;
++ struct file *cur_xino;
++ struct inode *dir;
++ struct au_sbinfo *sbinfo;
++
++ SiMustWriteLock(sb);
++
++ err = 0;
++ sbinfo = au_sbi(sb);
++ parent = dget_parent(xino->file->f_dentry);
++ if (remount) {
++ skip = 0;
++ dname = &xino->file->f_dentry->d_name;
++ cur_xino = sbinfo->si_xib;
++ if (cur_xino) {
++ cur_parent = dget_parent(cur_xino->f_dentry);
++ cur_name = &cur_xino->f_dentry->d_name;
++ skip = (cur_parent == parent
++ && dname->len == cur_name->len
++ && !memcmp(dname->name, cur_name->name,
++ dname->len));
++ dput(cur_parent);
++ }
++ if (skip)
++ goto out;
++ }
++
++ au_opt_set(sbinfo->si_mntflags, XINO);
++ dir = parent->d_inode;
++ mutex_lock_nested(&dir->i_mutex, AuLsc_I_PARENT);
++ /* mnt_want_write() is unnecessary here */
++ err = au_xino_set_xib(sb, xino->file);
++ if (!err)
++ err = au_xigen_set(sb, xino->file);
++ if (!err)
++ err = au_xino_set_br(sb, xino->file);
++ mutex_unlock(&dir->i_mutex);
++ if (!err)
++ goto out; /* success */
++
++ /* reset all */
++ AuIOErr("failed creating xino(%d).\n", err);
++
++ out:
++ dput(parent);
++ return err;
++}
++
++/* ---------------------------------------------------------------------- */
++
++/*
++ * create a xinofile at the default place/path.
++ */
++struct file *au_xino_def(struct super_block *sb)
++{
++ struct file *file;
++ char *page, *p;
++ struct au_branch *br;
++ struct super_block *h_sb;
++ struct path path;
++ aufs_bindex_t bend, bindex, bwr;
++
++ br = NULL;
++ bend = au_sbend(sb);
++ bwr = -1;
++ for (bindex = 0; bindex <= bend; bindex++) {
++ br = au_sbr(sb, bindex);
++ if (au_br_writable(br->br_perm)
++ && !au_test_fs_bad_xino(br->br_mnt->mnt_sb)) {
++ bwr = bindex;
++ break;
++ }
++ }
++
++ if (bwr >= 0) {
++ file = ERR_PTR(-ENOMEM);
++ page = __getname();
++ if (unlikely(!page))
++ goto out;
++ path.mnt = br->br_mnt;
++ path.dentry = au_h_dptr(sb->s_root, bwr);
++ p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME));
++ file = (void *)p;
++ if (!IS_ERR(p)) {
++ strcat(p, "/" AUFS_XINO_FNAME);
++ AuDbg("%s\n", p);
++ file = au_xino_create(sb, p, /*silent*/0);
++ if (!IS_ERR(file))
++ au_xino_brid_set(sb, br->br_id);
++ }
++ __putname(page);
++ } else {
++ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0);
++ if (IS_ERR(file))
++ goto out;
++ h_sb = file->f_dentry->d_sb;
++ if (unlikely(au_test_fs_bad_xino(h_sb))) {
++ AuErr("xino doesn't support %s(%s)\n",
++ AUFS_XINO_DEFPATH, au_sbtype(h_sb));
++ fput(file);
++ file = ERR_PTR(-EINVAL);
++ }
++ if (!IS_ERR(file))
++ au_xino_brid_set(sb, -1);
++ }
++
++ out:
++ return file;
++}
++
++/* ---------------------------------------------------------------------- */
++
++int au_xino_path(struct seq_file *seq, struct file *file)
++{
++ int err;
++
++ err = au_seq_path(seq, &file->f_path);
++ if (unlikely(err < 0))
++ goto out;
++
++ err = 0;
++#define Deleted "\\040(deleted)"
++ seq->count -= sizeof(Deleted) - 1;
++ AuDebugOn(memcmp(seq->buf + seq->count, Deleted,
++ sizeof(Deleted) - 1));
++#undef Deleted
++
++ out:
++ return err;
++}
+diff --git a/fs/namei.c b/fs/namei.c
+index d34e0f9..2779304 100644
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -341,6 +341,7 @@ int deny_write_access(struct file * file)
+
+ return 0;
+ }
++EXPORT_SYMBOL(deny_write_access);
+
+ /**
+ * path_get - get a reference to a path
+@@ -1212,7 +1213,7 @@ out:
+ * needs parent already locked. Doesn't follow mounts.
+ * SMP-safe.
+ */
+-static struct dentry *lookup_hash(struct nameidata *nd)
++struct dentry *lookup_hash(struct nameidata *nd)
+ {
+ int err;
+
+@@ -1221,8 +1222,9 @@ static struct dentry *lookup_hash(struct nameidata *nd)
+ return ERR_PTR(err);
+ return __lookup_hash(&nd->last, nd->path.dentry, nd);
+ }
++EXPORT_SYMBOL(lookup_hash);
+
+-static int __lookup_one_len(const char *name, struct qstr *this,
++int __lookup_one_len(const char *name, struct qstr *this,
+ struct dentry *base, int len)
+ {
+ unsigned long hash;
+@@ -1243,6 +1245,7 @@ static int __lookup_one_len(const char *name, struct qstr *this,
+ this->hash = end_name_hash(hash);
+ return 0;
+ }
++EXPORT_SYMBOL(__lookup_one_len);
+
+ /**
+ * lookup_one_len - filesystem helper to lookup single pathname component
+diff --git a/fs/namespace.c b/fs/namespace.c
+index 65b3dc8..39fbbac 100644
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -37,6 +37,7 @@
+
+ /* spinlock for vfsmount related operations, inplace of dcache_lock */
+ __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
++EXPORT_SYMBOL(vfsmount_lock);
+
+ static int event;
+ static DEFINE_IDA(mnt_id_ida);
+diff --git a/fs/open.c b/fs/open.c
+index 83cdb9d..bb43dab 100644
+--- a/fs/open.c
++++ b/fs/open.c
+@@ -222,6 +222,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
+ mutex_unlock(&dentry->d_inode->i_mutex);
+ return err;
+ }
++EXPORT_SYMBOL(do_truncate);
+
+ static long do_sys_truncate(const char __user *pathname, loff_t length)
+ {
+diff --git a/fs/splice.c b/fs/splice.c
+index 1abab5c..7b7d65e 100644
+--- a/fs/splice.c
++++ b/fs/splice.c
+@@ -887,8 +887,8 @@ EXPORT_SYMBOL(generic_splice_sendpage);
+ /*
+ * Attempt to initiate a splice from pipe to file.
+ */
+-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+- loff_t *ppos, size_t len, unsigned int flags)
++long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags)
+ {
+ int ret;
+
+@@ -907,13 +907,14 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+
+ return out->f_op->splice_write(pipe, out, ppos, len, flags);
+ }
++EXPORT_SYMBOL(do_splice_from);
+
+ /*
+ * Attempt to initiate a splice from a file to a pipe.
+ */
+-static long do_splice_to(struct file *in, loff_t *ppos,
+- struct pipe_inode_info *pipe, size_t len,
+- unsigned int flags)
++long do_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
+ {
+ int ret;
+
+@@ -929,6 +930,7 @@ static long do_splice_to(struct file *in, loff_t *ppos,
+
+ return in->f_op->splice_read(in, ppos, pipe, len, flags);
+ }
++EXPORT_SYMBOL(do_splice_to);
+
+ /**
+ * splice_direct_to_actor - splices data directly between two non-pipes
+diff --git a/fs/super.c b/fs/super.c
+index 400a760..a1df361 100644
+--- a/fs/super.c
++++ b/fs/super.c
+@@ -270,6 +270,7 @@ int fsync_super(struct super_block *sb)
+ __fsync_super(sb);
+ return sync_blockdev(sb->s_bdev);
+ }
++EXPORT_SYMBOL(fsync_super);
+
+ /**
+ * generic_shutdown_super - common helper for ->kill_sb()
+diff --git a/fs/sync.c b/fs/sync.c
+index 2967562..34040d6 100644
+--- a/fs/sync.c
++++ b/fs/sync.c
+@@ -104,6 +104,7 @@ long do_fsync(struct file *file, int datasync)
+ out:
+ return ret;
+ }
++EXPORT_SYMBOL(do_fsync);
+
+ static long __do_fsync(unsigned int fd, int datasync)
+ {
+diff --git a/include/linux/Kbuild b/include/linux/Kbuild
+index e531783..14ecb7c 100644
+--- a/include/linux/Kbuild
++++ b/include/linux/Kbuild
+@@ -34,6 +34,7 @@ header-y += atmppp.h
+ header-y += atmsap.h
+ header-y += atmsvc.h
+ header-y += atm_zatm.h
++header-y += aufs_type.h
+ header-y += auto_fs4.h
+ header-y += ax25.h
+ header-y += b1lli.h
+diff --git a/include/linux/aufs_type.h b/include/linux/aufs_type.h
+new file mode 100644
+index 0000000..aae5225
+--- /dev/null
++++ b/include/linux/aufs_type.h
+@@ -0,0 +1,184 @@
++/*
++ * Copyright (C) 2005-2009 Junjiro R. Okajima
++ *
++ * This program, aufs 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#ifndef __AUFS_TYPE_H__
++#define __AUFS_TYPE_H__
++
++#include <linux/ioctl.h>
++#include <linux/types.h>
++
++#define AUFS_VERSION "2-standalone.tree-28-20090831"
++
++/* todo? move this to linux-2.6.19/include/magic.h */
++#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
++
++/* ---------------------------------------------------------------------- */
++
++#ifdef CONFIG_AUFS_BRANCH_MAX_127
++typedef __s8 aufs_bindex_t;
++#define AUFS_BRANCH_MAX 127
++#else
++typedef __s16 aufs_bindex_t;
++#ifdef CONFIG_AUFS_BRANCH_MAX_511
++#define AUFS_BRANCH_MAX 511
++#elif defined(CONFIG_AUFS_BRANCH_MAX_1023)
++#define AUFS_BRANCH_MAX 1023
++#elif defined(CONFIG_AUFS_BRANCH_MAX_32767)
++#define AUFS_BRANCH_MAX 32767
++#endif
++#endif
++
++#ifdef __KERNEL__
++#ifndef AUFS_BRANCH_MAX
++#error unknown CONFIG_AUFS_BRANCH_MAX value
++#endif
++#endif /* __KERNEL__ */
++
++/* ---------------------------------------------------------------------- */
++
++#define AUFS_NAME "aufs"
++#define AUFS_FSTYPE AUFS_NAME
++
++#define AUFS_ROOT_INO 2
++#define AUFS_FIRST_INO 11
++
++#define AUFS_WH_PFX ".wh."
++#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1)
++#define AUFS_XINO_FNAME "." AUFS_NAME ".xino"
++#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME
++#define AUFS_XINO_TRUNC_INIT 64 /* blocks */
++#define AUFS_XINO_TRUNC_STEP 4 /* blocks */
++#define AUFS_DIRWH_DEF 3
++#define AUFS_RDCACHE_DEF 10 /* seconds */
++#define AUFS_RDBLK_DEF 512 /* bytes */
++#define AUFS_RDHASH_DEF 32
++#define AUFS_WKQ_NAME AUFS_NAME "d"
++#define AUFS_NWKQ_DEF 4
++#define AUFS_MFS_SECOND_DEF 30 /* seconds */
++#define AUFS_PLINK_WARN 100 /* number of plinks */
++
++#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */
++#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME
++
++#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME
++#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk"
++#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph"
++
++/* doubly whiteouted */
++#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME
++#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME
++#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME
++
++/* branch permission */
++#define AUFS_BRPERM_RW "rw"
++#define AUFS_BRPERM_RO "ro"
++#define AUFS_BRPERM_RR "rr"
++#define AUFS_BRPERM_WH "wh"
++#define AUFS_BRPERM_NLWH "nolwh"
++#define AUFS_BRPERM_ROWH AUFS_BRPERM_RO "+" AUFS_BRPERM_WH
++#define AUFS_BRPERM_RRWH AUFS_BRPERM_RR "+" AUFS_BRPERM_WH
++#define AUFS_BRPERM_RWNLWH AUFS_BRPERM_RW "+" AUFS_BRPERM_NLWH
++
++/* ---------------------------------------------------------------------- */
++
++/* ioctl */
++enum {
++ AuCtl_PLINK_MAINT,
++ AuCtl_PLINK_CLEAN,
++
++ /* readdir in userspace */
++ AuCtl_RDU,
++ AuCtl_RDU_INO
++};
++
++/* borrowed from linux/include/linux/kernel.h */
++#ifndef ALIGN
++#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
++#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
++#endif
++
++/* borrowed from linux/include/linux/compiler-gcc3.h */
++#ifndef __aligned
++#define __aligned(x) __attribute__((aligned(x)))
++#define __packed __attribute__((packed))
++#endif
++
++struct au_rdu_cookie {
++ __u64 h_pos;
++ __s16 bindex;
++ __u8 flags;
++ __u8 pad;
++ __u32 generation;
++} __aligned(8);
++
++struct au_rdu_ent {
++ __u64 ino;
++ __s16 bindex;
++ __u8 type;
++ __u8 nlen;
++ __u8 wh;
++ char name[0];
++} __aligned(8);
++
++static inline int au_rdu_len(int nlen)
++{
++ /* include the terminating NULL */
++ return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1,
++ sizeof(__u64));
++}
++
++union au_rdu_ent_ul {
++ struct au_rdu_ent __user *e;
++ unsigned long ul;
++};
++
++enum {
++ AufsCtlRduV_SZ,
++ AufsCtlRduV_SZ_PTR,
++ AufsCtlRduV_End
++};
++
++struct aufs_rdu {
++ /* input */
++ union {
++ __u64 sz; /* AuCtl_RDU */
++ __u64 nent; /* AuCtl_RDU_INO */
++ };
++ union au_rdu_ent_ul ent;
++ __u16 verify[AufsCtlRduV_End];
++
++ /* input/output */
++ __u32 blk;
++
++ /* output */
++ union au_rdu_ent_ul tail;
++ /* number of entries which were added in a single call */
++ __u64 rent;
++ __u8 full;
++ __u8 shwh;
++
++ struct au_rdu_cookie cookie;
++} __aligned(8);
++
++#define AuCtlType 'A'
++#define AUFS_CTL_PLINK_MAINT _IO(AuCtlType, AuCtl_PLINK_MAINT)
++#define AUFS_CTL_PLINK_CLEAN _IO(AuCtlType, AuCtl_PLINK_CLEAN)
++#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu)
++#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu)
++
++#endif /* __AUFS_TYPE_H__ */
+diff --git a/include/linux/device.h b/include/linux/device.h
+index 1a3686d..d2d4609 100644
+--- a/include/linux/device.h
++++ b/include/linux/device.h
+@@ -402,7 +402,9 @@ struct device {
+ struct device_dma_parameters *dma_parms;
+
+ struct list_head dma_pools; /* dma pools (if dma'ble) */
+-
++#ifdef CONFIG_DPM
++ struct constraints *constraints;
++#endif
+ struct dma_coherent_mem *dma_mem; /* internal for coherent mem
+ override */
+ /* arch specific additions */
+diff --git a/include/linux/dpm-trace.h b/include/linux/dpm-trace.h
+new file mode 100644
+index 0000000..8914e0e
+--- /dev/null
++++ b/include/linux/dpm-trace.h
+@@ -0,0 +1,63 @@
++/*
++ * include/linux/dpm.h DPM policy management
++ *
++ * 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
++ *
++ * Copyright (C) 2002, International Business Machines Corporation
++ * All Rights Reserved
++ *
++ * Robert Paulsen
++ * IBM Linux Technology Center
++ * rpaulsen@us.ibm.com
++ * August, 2002
++ *
++ */
++
++#ifndef __DPM_TRACE_H_
++#define __DPM_TRACE_H_
++
++#ifdef CONFIG_DPM_TRACE
++
++#define DPM_TRACE_SET_OPT_ASYNC 0x00000001
++#define DPM_TRACE_SET_OPT_SYNC 0x00000002
++#define DPM_TRACE_RESYNC 0x00000004
++#define DPM_TRACE_UNLOCK 0x00000008
++#define DPM_TRACE_SET_OS 0x00000010
++#define DPM_TRACE_SET_POLICY 0x00000020
++#define DPM_TRACE_START 0x00000040
++#define DPM_TRACE_STOP 0x00000080
++#define DPM_TRACE_SET_TASK_STATE 0x00000100
++
++#define DPM_TRACE_ALL 0x000001ff
++
++void dpm_trace(unsigned event, ...);
++void dpm_trace_start(unsigned events);
++void dpm_trace_stop(void);
++void dpm_trace_reset(void);
++
++int
++read_proc_dpm_trace(char *page, char **start, off_t offset,
++ int count, int *eof, void *data);
++int
++write_proc_dpm_trace(struct file *file, const char *buffer,
++ unsigned long count, void *data);
++
++#else
++
++#define dpm_trace(args...) do {} while (0)
++
++#endif /* CONFIG_DPM_TRACE */
++
++#endif /*__DPM_TRACE_H_*/
+diff --git a/include/linux/dpm.h b/include/linux/dpm.h
+new file mode 100644
+index 0000000..4146d66
+--- /dev/null
++++ b/include/linux/dpm.h
+@@ -0,0 +1,410 @@
++/*
++ * include/linux/dpm.h DPM policy management
++ *
++ * 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
++ *
++ * Copyright (C) 2002, International Business Machines Corporation
++ * All Rights Reserved
++ *
++ * Robert Paulsen
++ * IBM Linux Technology Center
++ * rpaulsen@us.ibm.com
++ * August, 2002
++ *
++ */
++
++#ifndef __DPM_H__
++#define __DPM_H__
++
++#include <linux/device.h>
++
++#define DPM_NO_STATE -1
++
++#ifndef CONFIG_DPM
++
++/* The above and following constants must always be defined for the
++ benefit of the init task and system tasks, although they are
++ otherwise ignored if DPM is not configured. */
++
++#define DPM_TASK_STATE 0
++#define dpm_set_os(task_state) do {} while (0);
++
++#else /* CONFIG_DPM */
++
++#include <plat/dpm.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/unistd.h>
++#include <linux/notifier.h>
++
++/* max size of DPM names */
++enum {DPM_NAME_SIZE=256};
++
++#include <linux/dpm-trace.h>
++#include <linux/list.h>
++#include <linux/semaphore.h>
++#include <asm/atomic.h>
++
++/* statistics */
++struct dpm_stats {
++ unsigned long count;
++ unsigned long long total_time;
++ unsigned long long start_time;
++};
++
++extern struct dpm_stats dpm_state_stats[DPM_STATES];
++
++/* update statistics structures */
++extern unsigned long long dpm_update_stats(struct dpm_stats *new,
++ struct dpm_stats *old);
++
++typedef int dpm_state_t;
++typedef int dpm_md_pp_t;
++
++/* A table of processor-dependent routines, must be initialized by
++ platform-dependent boot code. None of the entries (that will actually be
++ called) are allowed to be NULL if DPM is enabled. */
++
++struct dpm_opt;
++
++struct dpm_md {
++ void (*init)(void);
++ int (*init_opt)(struct dpm_opt *opt);
++ int (*set_opt)(struct dpm_opt *cur, struct dpm_opt *new);
++ int (*get_opt)(struct dpm_opt *opt);
++ int (*check_constraint)(struct constraint_param *param,
++ struct dpm_opt *opt);
++ void (*idle)(void);
++ void (*startup)(void);
++ void (*cleanup)(void);
++};
++
++
++/*****************************************************************************
++ * Search a list looking for a named entity.
++ * A pointer to the found element is put in the variable named by the
++ * "answer" argument (or it is set to zero if not found).
++ * The structure's type name is given by the "element_type" argument.
++ * The name being looked for is given by the "find_me" argument.
++ * The name of the stand-alone list_head is given by the "list_name" argument.
++ * Assumes the proper semaphore is held.
++ * Assumes the structure's list_head is named "list".
++ * Assumes the structure's name is in a field called "name"
++ *****************************************************************************/
++#define list_find(answer,find_me,list_name,element_type) \
++ do { \
++ element_type *elm; \
++ struct list_head *scan; \
++ (answer)=0; \
++ for(scan=list_name.next;scan!=&list_name; \
++ scan=scan->next) { \
++ elm=list_entry(scan,element_type,list); \
++ if (strncmp((find_me),elm->name, \
++ DPM_NAME_SIZE)==0) { \
++ (answer)=elm; \
++ break; \
++ } \
++ } \
++ } while(0)
++
++/* internal representation of an operating point */
++
++#define DPM_OP_FORCE 0x0001
++#define DPM_OP_NOP 0x0002
++
++struct dpm_opt {
++ char *name; /* name */
++ struct list_head list; /* all installed op points */
++ dpm_md_pp_t pp[DPM_PP_NBR]; /* initialization params */
++ struct dpm_md_opt md_opt; /* machine dependent part */
++ int constrained; /* is this opt constrained? */
++ struct kobject kobj; /* kobject */
++ struct dpm_stats stats; /* statistics */
++ int flags;
++};
++
++/* internal representation of a class of op points (to be mapped to an
++ * operating state */
++struct dpm_class {
++ char *name; /* name */
++ struct list_head list; /* all installed classes */
++ unsigned nops; /* nbr ops in this class */
++ struct dpm_opt **ops; /* the ops in this class */
++ struct kobject kobj; /* kobject */
++ struct dpm_stats stats; /* statistics */
++};
++
++/*
++ * temporary support for policies to map operating points to either
++ * operating pts or classes. Only one field allowed to be set.
++ */
++
++struct dpm_classopt {
++ struct dpm_opt *opt;
++ struct dpm_class *class;
++};
++
++/* internal representation of an installed power policy */
++struct dpm_policy {
++ char *name; /* name */
++ struct list_head list; /* all installed policies */
++ struct dpm_classopt classopt[DPM_STATES]; /* classes/op pts */
++ struct kobject kobj; /* kobject */
++ struct dpm_stats stats; /* statistics */
++};
++
++/*
++ * internal use utility functions for use by DPM
++ */
++
++/* DPM semaphore locking. To simplify future expansion, don't 'down' _dpm_lock
++ directly. Also, _dpm_lock must be 'up'ed only by dpm_unlock(). */
++
++extern struct semaphore _dpm_lock;
++
++static inline void
++dpm_lock(void)
++{
++ down(&_dpm_lock);
++}
++
++static inline int
++dpm_lock_interruptible(void)
++{
++ if (down_interruptible(&_dpm_lock))
++ return -ERESTARTSYS;
++ return 0;
++}
++
++static inline int
++dpm_trylock(void)
++{
++ if (down_trylock(&_dpm_lock))
++ return -EBUSY;
++ return 0;
++}
++
++void dpm_unlock(void);
++void dpm_idle(void);
++
++/* set operating state */
++void dpm_set_os(dpm_state_t state);
++
++/*
++ * names of DPM stuff for userspace interfaces
++ */
++
++extern char *dpm_state_names[DPM_STATES];
++extern char *dpm_param_names[DPM_PP_NBR];
++
++/* initialize/terminate the DPM */
++int dynamicpower_init(void);
++int dynamicpower_terminate(void);
++
++/* (temporarily) disable the DPM */
++int dynamicpower_disable(void);
++
++/* re-enable the DPM */
++int dynamicpower_enable(void);
++
++/* suspend/resume DPM across a system shutdown */
++int dynamicpm_suspend(void);
++void dynamicpm_resume(void);
++
++/* create operating point */
++int dpm_create_opt(const char *name, const dpm_md_pp_t *pp, int npp);
++
++/* create class of operating points */
++int dpm_create_class(const char *name, char **op_names, unsigned nops);
++
++/* create policy */
++int dpm_create_policy(const char *name, char **opt_names, int nopts);
++int dpm_map_policy_state(struct dpm_policy *policy, int state, char *classopt);
++
++/* destroy policy */
++int dpm_destroy_policy(const char *name);
++
++/* activate a power policy */
++int dpm_set_policy(const char *name);
++
++/* get name of active power policy */
++int dpm_get_policy(char *name);
++
++/* set a raw operating state */
++int dpm_set_op_state(const char *name);
++int dpm_set_opt(struct dpm_opt *opt, unsigned flags);
++
++/* choose unconstrained operating point from policy */
++extern struct dpm_opt *dpm_choose_opt(struct dpm_policy *policy, int state);
++
++
++/* constraints */
++int dpm_check_constraints(struct dpm_opt *opt);
++int dpm_default_check_constraint(struct constraint_param *param, struct dpm_opt *opt);
++int dpm_show_opconstraints(struct dpm_opt *opt, char * buf);
++
++/* driver scale callbacks */
++void dpm_driver_scale(int level, struct dpm_opt *newop);
++void dpm_register_scale(struct notifier_block *nb, int level);
++void dpm_unregister_scale(struct notifier_block *nb, int level);
++
++
++/* utils */
++extern void dpm_udelay(unsigned uS);
++extern void dpm_udelay_from(u64 start, unsigned uS);
++extern unsigned long dpm_compute_lpj(unsigned long ref, u_int div, u_int mult);
++
++/*
++ * sysfs interface
++ */
++
++extern void dpm_sysfs_new_policy(struct dpm_policy *policy);
++extern void dpm_sysfs_destroy_policy(struct dpm_policy *policy);
++extern void dpm_sysfs_new_class(struct dpm_class *class);
++extern void dpm_sysfs_destroy_class(struct dpm_class *class);
++extern void dpm_sysfs_new_op(struct dpm_opt *opt);
++extern void dpm_sysfs_destroy_op(struct dpm_opt *opt);
++
++extern int proc_pid_dpm_read(struct task_struct*,char*);
++
++
++/*
++ * global data for power management system
++ */
++
++/* curently installed policies, classes and operating points */
++extern struct list_head dpm_policies;
++extern struct list_head dpm_classes;
++extern struct list_head dpm_opts;
++extern struct semaphore dpm_policy_sem;
++extern spinlock_t dpm_policy_lock;
++
++/* the currently active policy, class, state, point */
++extern struct dpm_policy *dpm_active_policy;
++extern struct dpm_class *dpm_active_class;
++extern dpm_state_t dpm_active_state;
++extern struct dpm_opt *dpm_active_opt;
++
++/* is DPM initialized and enabled? */
++extern int dpm_initialized;
++extern int dpm_enabled;
++
++extern inline void
++dpm_quick_enter_state(int new_state)
++{
++#ifdef CONFIG_DPM_STATS
++ dpm_update_stats(new_state != DPM_NO_STATE ?
++ &dpm_state_stats[new_state] : NULL,
++ dpm_active_state != DPM_NO_STATE ?
++ &dpm_state_stats[dpm_active_state] : NULL);
++#endif
++
++ dpm_active_state = new_state;
++}
++
++/* Flags for dpm_set_opt(). By default, dpm_set_op() is guaranteed not
++ to block the caller, and will arrange to complete asynchronously if
++ necessary.
++
++ DPM_SYNC The operating point is guaranteed to be set when the call
++ returns. The call may block.
++
++ DPM_UNLOCK The caller requires dpm_md_set_opt() to unlock the DPM system
++ once the operating point is set.
++*/
++
++#define DPM_SYNC 0x01
++#define DPM_UNLOCK 0x02
++
++/*
++ * Common machine-dependent and board-dependent function wrappers.
++ */
++
++extern struct dpm_md dpm_md;
++
++static inline void
++dpm_md_startup(void)
++{
++ printk("dpm_md_startup\n");
++ if (dpm_md.startup)
++ dpm_md.startup();
++}
++
++
++static inline void
++dpm_md_cleanup(void)
++{
++ if (dpm_md.cleanup)
++ dpm_md.cleanup();
++}
++
++
++static inline void
++dpm_md_idle(void)
++{
++ printk("dpm_md_idle\n");
++ if (dpm_md.idle)
++ dpm_md.idle();
++}
++
++
++/* Machine-dependent operating point creating/query/setting */
++
++
++static inline int
++dpm_md_init_opt(struct dpm_opt *opt)
++{
++ if (dpm_md.init_opt)
++ return dpm_md.init_opt(opt);
++ return 0;
++}
++
++static inline int
++dpm_md_set_opt(struct dpm_opt *cur, struct dpm_opt *new)
++{
++ if (dpm_md.set_opt)
++ return dpm_md.set_opt(cur, new);
++ return 0;
++}
++
++static inline int
++dpm_md_get_opt(struct dpm_opt *opt)
++{
++ if (dpm_md.get_opt)
++ return dpm_md.get_opt(opt);
++ return 0;
++}
++
++static inline int
++dpm_md_check_constraint(struct constraint_param *param, struct dpm_opt *opt)
++{
++ return dpm_md.check_constraint ?
++ dpm_md.check_constraint(param, opt) : 1;
++}
++
++/*
++ * Helper functions
++ */
++
++static inline char *
++dpm_classopt_name(struct dpm_policy *policy, int state)
++{
++ return policy->classopt[state].opt ?
++ policy->classopt[state].opt->name :
++ policy->classopt[state].class->name;
++}
++
++#endif /* CONFIG_DPM */
++#endif /*__DPM_H__*/
+diff --git a/include/linux/i2c-dev.h b/include/linux/i2c-dev.h
+index 311315b..8873229 100644
+--- a/include/linux/i2c-dev.h
++++ b/include/linux/i2c-dev.h
+@@ -50,6 +50,10 @@
+ #define I2C_PEC 0x0708 /* != 0 to use PEC with SMBus */
+ #define I2C_SMBUS 0x0720 /* SMBus transfer */
+
++/* for TCC DIBCOM module */
++#define I2C_SLAVE_DIBCOM 0x0730 /* DIBCOM DVB-T slave address */
++#define I2C_DIBCOM_WR_RD 0x0731 /* DIBCOM protocol */
++
+
+ /* This is the structure as used in the I2C_SMBUS ioctl call */
+ struct i2c_smbus_ioctl_data {
+diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
+index 01d67ba..518e368 100644
+--- a/include/linux/i2c-id.h
++++ b/include/linux/i2c-id.h
+@@ -81,6 +81,17 @@
+ #define I2C_DRIVERID_CS4270 94 /* Cirrus Logic 4270 audio codec */
+ #define I2C_DRIVERID_M52790 95 /* Mitsubishi M52790SP/FP AV switch */
+ #define I2C_DRIVERID_CS5345 96 /* cs5345 audio processor */
++#define I2C_DRIVERID_WM8987 97 /* Wolfson WM8987 audio codec */
++
++/*
++ * @telechips --------------------
++ */
++#define I2C_DRIVERID_MT9D111 100
++#define I2C_DRIVERID_MT9D112 101
++#define I2C_DRIVERID_MT9P111 102
++#define I2C_DRIVERID_MV9317 103
++#define I2C_DRIVERID_S5K4BAFB 104
++
+
+ #define I2C_DRIVERID_OV7670 1048 /* Omnivision 7670 camera */
+
+diff --git a/include/linux/i2c.h b/include/linux/i2c.h
+index 33a5992..fe563a1 100644
+--- a/include/linux/i2c.h
++++ b/include/linux/i2c.h
+@@ -521,6 +521,9 @@ struct i2c_msg {
+ #define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
+ #define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
+ #define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
++/* for TCC DIBCOM module */
++#define I2C_M_DIBCOM_MODE 0x0040 /* if slave is DIBCOM DVB-T chip */
++#define I2C_M_DIBCOM_WR_RD 0x0080 /* if write->read operation */
+ __u16 len; /* msg length */
+ __u8 *buf; /* pointer to msg data */
+ };
+diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h
+index ea1bf5b..71df958 100644
+--- a/include/linux/mmc/sdio_ids.h
++++ b/include/linux/mmc/sdio_ids.h
+@@ -26,4 +26,7 @@
+ #define SDIO_VENDOR_ID_MARVELL 0x02df
+ #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103
+
++#define SDIO_VENDOR_ID_CSR 0x032a
++#define SDIO_DEVICE_ID_CSR_DEV 0x0001
++
+ #endif
+diff --git a/include/linux/namei.h b/include/linux/namei.h
+index 99eb803..f6cdf1c 100644
+--- a/include/linux/namei.h
++++ b/include/linux/namei.h
+@@ -75,6 +75,9 @@ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry
+ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);
+ extern void release_open_intent(struct nameidata *);
+
++extern struct dentry *lookup_hash(struct nameidata *nd);
++extern int __lookup_one_len(const char *name, struct qstr *this,
++ struct dentry *base, int len);
+ extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
+ extern struct dentry *lookup_one_noperm(const char *, struct dentry *);
+
+diff --git a/include/linux/pm.h b/include/linux/pm.h
+index 42de400..dfaa300 100644
+--- a/include/linux/pm.h
++++ b/include/linux/pm.h
+@@ -30,6 +30,39 @@ extern void (*pm_idle)(void);
+ extern void (*pm_power_off)(void);
+ extern void (*pm_power_off_prepare)(void);
+
++#ifdef CONFIG_DPM
++struct device;
++
++struct constraint_param {
++ int id;
++ int min;
++ int max;
++};
++
++#define DPM_CONSTRAINT_PARAMS_MAX 20
++
++struct constraints {
++ int asserted;
++ int count;
++ int violations;
++ struct constraint_param param[DPM_CONSTRAINT_PARAMS_MAX];
++ struct list_head entry;
++};
++
++enum {
++ SCALE_PRECHANGE,
++ SCALE_POSTCHANGE,
++ SCALE_MAX
++};
++
++extern void assert_constraints(struct constraints *);
++extern void deassert_constraints(struct constraints *);
++extern void power_event(char *eventstr);
++extern void device_power_event(struct device * dev, char *eventstr);
++#endif
++
++
++
+ /*
+ * Device power management
+ */
+diff --git a/include/linux/sched.h b/include/linux/sched.h
+index 55e30d1..a888ce0 100644
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -1079,6 +1079,9 @@ struct task_struct {
+ unsigned int flags; /* per process flags, defined below */
+ unsigned int ptrace;
+
++ int dpm_state; /* DPM operating state to use for this task */
++
++
+ int lock_depth; /* BKL lock depth */
+
+ #ifdef CONFIG_SMP
+diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
+index 4e4f127..8034129 100644
+--- a/include/linux/serial_core.h
++++ b/include/linux/serial_core.h
+@@ -158,6 +158,10 @@
+ /* SH-SCI */
+ #define PORT_SCIFA 83
+
++/* Telechips uart */
++#define PORT_TCC 84
++
++
+ #ifdef __KERNEL__
+
+ #include <linux/compiler.h>
+diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
+index 4be01bb..cb75fd2 100644
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -264,6 +264,12 @@ struct spi_master {
+
+ /* called on release() to free memory provided by spi_master */
+ void (*cleanup)(struct spi_device *spi);
++
++ /* Telechips spi hw open/close */
++ int (*tcc_open)(struct spi_device *spi);
++ void (*tcc_close)(struct spi_device *spi);
++ int tcc_irq_no;
++ u32 tcc_reg_base;
+ };
+
+ static inline void *spi_master_get_devdata(struct spi_master *master)
+@@ -571,6 +577,20 @@ spi_async(struct spi_device *spi, struct spi_message *message)
+ return spi->master->transfer(spi, message);
+ }
+
++/*
++ * Telechips spi hw open/close
++ */
++static inline int
++spi_tcc_open(struct spi_device *spi)
++{
++ return spi->master->tcc_open(spi);
++}
++static inline void
++spi_tcc_close(struct spi_device *spi)
++{
++ return spi->master->tcc_close(spi);
++}
++
+ /*---------------------------------------------------------------------------*/
+
+ /* All these synchronous SPI transfer routines are utilities layered
+diff --git a/include/linux/spi/tcc_tsif.h b/include/linux/spi/tcc_tsif.h
+new file mode 100644
+index 0000000..36da879
+--- /dev/null
++++ b/include/linux/spi/tcc_tsif.h
+@@ -0,0 +1,51 @@
++/*
++ * include/linux/spi/tcc_tsif.h
++ *
++ * Author: <linux@telechips.com>
++ * Created: 1st April, 2009
++ * Description: Driver for Telechips SPI (GPSB) Controllers
++ * SPI slave mode for DXB TSIF (Transport Stream Interface) modules
++ *
++ * Copyright (c) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++#ifndef __TCC_TSIF_H__
++#define __TCC_TSIF_H__
++
++/* Select GPSB channel */
++#define TSIF_SPI_NUM 1
++
++#define TSIF_DEV_MAJOR 252
++#define TSIF_DEV_NAME "tcc-tsif"
++
++#define TSIF_PACKET_SIZE 188
++#define PID_MATCH_TABLE_MAX_CNT 32
++
++
++struct tcc_tsif_param {
++ unsigned int ts_total_packet_cnt;
++ unsigned int ts_intr_packet_cnt;
++ unsigned int mode;
++ unsigned int dma_mode; // DMACTR[MD]: DMA mode register
++#define DMA_NORMAL_MODE 0x00
++#define DMA_MPEG2TS_MODE 0x01
++};
++
++struct tcc_tsif_pid_param {
++ unsigned int pid_data[PID_MATCH_TABLE_MAX_CNT];
++ unsigned int valid_data_cnt;
++};
++
++
++#define IOCTL_TSIF_DMA_START _IO(TSIF_DEV_MAJOR, 1)
++#define IOCTL_TSIF_DMA_STOP _IO(TSIF_DEV_MAJOR, 2)
++#define IOCTL_TSIF_GET_MAX_DMA_SIZE _IO(TSIF_DEV_MAJOR, 3)
++#define IOCTL_TSIF_SET_PID _IO(TSIF_DEV_MAJOR, 4)
++#define IOCTL_TSIF_DXB_POWER _IO(TSIF_DEV_MAJOR, 5)
++
++
++#endif /*__TCC_TSIF_H__*/
+diff --git a/include/linux/splice.h b/include/linux/splice.h
+index 528dcb9..5123bc6 100644
+--- a/include/linux/splice.h
++++ b/include/linux/splice.h
+@@ -71,4 +71,10 @@ extern ssize_t splice_to_pipe(struct pipe_inode_info *,
+ extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
+ splice_direct_actor *);
+
++extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags);
++extern long do_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags);
++
+ #endif
+diff --git a/include/linux/tcc_intr.h b/include/linux/tcc_intr.h
+new file mode 100644
+index 0000000..964e414
+--- /dev/null
++++ b/include/linux/tcc_intr.h
+@@ -0,0 +1,41 @@
++/*
++ * include/linux/tcc_intr.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: 31th March, 2009
++ * Description: User-level interrupt Driver
++ *
++ * Copyright (c) Telechips, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *-----------------------------------------------
++ * 1. TCC_INTR_DEV_VIDEO_CODEC
++ * - dev node: tcc-intr-vc
++ * - Video Codec interrupt handling
++ * 2. TCC_INTR_DEV_M2M_SCALER
++ * - dev node: tcc-intr-sc, tcc-intr-sc1
++ * - Mem-to-Mem scaler 0/1 interrupt handling
++ * 3. TCC_INTR_DEV_BROADCAST
++ * - dev node: tcc-intr-bc
++ * - Broadcasting (External Interrupt for DXB) interrupt handling
++ *
++ */
++#ifndef __TCC_INTR_H__
++#define __TCC_INTR_H__
++
++#define TCC_INTR_DEV_MAJOR 246
++#define TCC_INTR_DEV_TEST "/dev/tcc-intr-test"
++
++#define TCC_INTR_DEV_VIDEO_CODEC "/dev/tcc-intr-vc"
++#define TCC_INTR_DEV_M2M_SCALER "/dev/tcc-intr-sc"
++#define TCC_INTR_DEV_M2M_SCALER1 "/dev/tcc-intr-sc1"
++#define TCC_INTR_DEV_BROADCAST "/dev/tcc-intr-bc"
++
++#define IOCTL_INTR_SET _IO(TCC_INTR_DEV_MAJOR, 1)
++#define IOCTL_INTR_GET _IO(TCC_INTR_DEV_MAJOR, 2)
++#define IOCTL_INTR_TEST _IO(TCC_INTR_DEV_MAJOR, 3)
++
++#endif /* __TCC_INTR_H__ */
+diff --git a/include/linux/tcc_ioctl.h b/include/linux/tcc_ioctl.h
+new file mode 100644
+index 0000000..5426ac8
+--- /dev/null
++++ b/include/linux/tcc_ioctl.h
+@@ -0,0 +1,83 @@
++/*
++ * File: include/linux/tcc_ioctl.h
++ *
++ * Created: June 10, 2008
++ * Copyright (C) 2008-2009 Telechips <linux@telechips.com>
++ * Description: header file of driver/char/tcc_ioctl.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++#ifndef __TCC_IOCTL_H__
++#define __TCC_IOCTL_H__
++
++#include <mach/ioctl_ckcstr.h>
++
++#define MAJOR_NUM 247
++
++#define IOCTL_CKC_SET_PERI _IO(MAJOR_NUM, 0)
++#define IOCTL_CKC_GET_PERI _IO(MAJOR_NUM, 1)
++#define IOCTL_CKC_SET_PERIBUS _IO(MAJOR_NUM, 2)
++#define IOCTL_CKC_GET_PERIBUS _IO(MAJOR_NUM, 3)
++#define IOCTL_CKC_SET_PERISWRESET _IO(MAJOR_NUM, 4)
++#define IOCTL_CKC_SET_CPU _IO(MAJOR_NUM, 5)
++#define IOCTL_CKC_SET_SMUI2C _IO(MAJOR_NUM, 6)
++#define IOCTL_CKC_GET_CPU _IO(MAJOR_NUM, 7)
++#define IOCTL_CKC_GET_BUS _IO(MAJOR_NUM, 8)
++
++#define IOCTL_CKC_GET_VALIDPLLINFO _IO(MAJOR_NUM, 9)
++#define IOCTL_CKC_GET_CLOCKINFO _IO(MAJOR_NUM, 10)
++
++#define IOCTL_CKC_SET_FBUS _IO(MAJOR_NUM, 11)
++#define IOCTL_CKC_GET_FBUS _IO(MAJOR_NUM, 12)
++#define IOCTL_CKC_SET_PMUPOWER _IO(MAJOR_NUM, 13)
++#define IOCTL_CKC_GET_PMUPOWER _IO(MAJOR_NUM, 14)
++
++#define IOCTL_CKC_SET_CHANGECPU _IO(MAJOR_NUM, 15)
++#define IOCTL_CKC_SET_CHANGEMEM _IO(MAJOR_NUM, 16)
++#define IOCTL_CKC_SET_CHANGEFBUS _IO(MAJOR_NUM, 17)
++
++#define IOCTL_CKC_SET_FBUSSWRESET _IO(MAJOR_NUM, 18)
++
++#define IOCTL_CKC_SET_DDIPWDN _IO(MAJOR_NUM, 19)
++#define IOCTL_CKC_GET_DDIPWDN _IO(MAJOR_NUM, 20)
++
++#define IOCTL_CKC_SET_ETCBLOCK _IO(MAJOR_NUM, 21)
++
++#define IOCTL_BLK_SETPOWER _IO(MAJOR_NUM, 22)
++#define IOCTL_BLK_GETPOWER _IO(MAJOR_NUM, 23)
++
++
++
++struct ckc_ioctl{
++ stckcioctl in_ckc;
++ stckcinfo out_ckc;
++};
++
++//AlenOh
++struct storage_direct{
++ void *buf;
++ size_t count;
++ loff_t pos;
++ ssize_t actual;
++ unsigned int user_space;
++};
++
++#define IOCTL_STORAGE_DIRECT_READ _IO(MAJOR_NUM, 100)
++#define IOCTL_STORAGE_DIRECT_WRITE _IO(MAJOR_NUM, 101)
++#define IOCTL_STORAGE_PING _IO(MAJOR_NUM, 102)
++
++
++#endif /* __TCC_IOCTL_H__ */
+diff --git a/include/linux/tcc_ll.h b/include/linux/tcc_ll.h
+new file mode 100644
+index 0000000..fbc24b6
+--- /dev/null
++++ b/include/linux/tcc_ll.h
+@@ -0,0 +1,53 @@
++
++#ifndef __TCC_LL_H__
++#define __TCC_LL_H__
++
++/* *****************************************
++ * void *: h_pri (private handle)
++ * int : cmd (power control command)
++ * *****************************************/
++typedef int (*power_control_t)(void *, int, void *);
++
++typedef struct data_node data_node_t;
++struct data_node {
++ unsigned int id;
++
++ /**** customer data ****/
++ power_control_t callback;
++ void *h_pri;
++ /***********************/
++
++ data_node_t *p_next;
++};
++
++typedef struct list_handle {
++ data_node_t *p_head;
++ data_node_t *p_tail;
++ data_node_t *p_pos;
++ unsigned int node_cnt;
++} list_handle_t;
++
++
++#if 0
++extern int init_ll(list_handle_t *h);
++extern int insert_ll(list_handle_t *h, data_node_t *p_node);
++extern int remove_ll(list_handle_t *h, unsigned int id);
++extern void remove_all_ll(list_handle_t *h);
++extern data_node_t *find_by_id(list_handle_t *h, unsigned int id);
++#endif
++
++#define set_next_node(p_node, p) ((p_node)->p_next = (p))
++#define get_next_node(p) ((p)->p_next)
++#define get_node_id(p) ((p)->id)
++#define get_node_cb(p) ((p)->callback)
++#define get_node_pri(p) ((p)->h_pri)
++
++extern int init_pwm_list(void);
++extern int insert_pwm_node(unsigned int id, power_control_t func, void *h_pri);
++extern int remove_pwm_node(unsigned int id);
++extern int callback_pwm_node(unsigned int id, unsigned int cmd, void *p_info);
++
++
++#endif /* __TCC_LL_H__ */
++
++
+diff --git a/include/linux/tcc_pwm.h b/include/linux/tcc_pwm.h
+new file mode 100644
+index 0000000..2c08ecd
+--- /dev/null
++++ b/include/linux/tcc_pwm.h
+@@ -0,0 +1,79 @@
++/****************************************************************************
++ * FileName : ioctl_pwrstr.h
++ * Description :
++ ****************************************************************************
++*
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++*
++ ****************************************************************************/
++
++
++/************************************************************************************************
++* Revision History *
++* *
++* Version : 1.0 : 2009, 8, 19 *
++************************************************************************************************/
++
++#ifndef __IOCTL_PWRSTR_H__
++#define __IOCTL_PWRSTR_H__
++
++
++typedef enum {
++ DEVICE_LCD = 0, // display device (LCD, ...)
++ DEVICE_BACKLIGHT, // backlight only.
++ DEVICE_ADC,
++ DEVICE_CAMERA,
++ DEVICE_GPSB,
++ DEVICE_HDMI,
++ DEVICE_KEYPAD,
++ DEVICE_POWERBUTTON,
++ DEVICE_SDHC,
++ DEVICE_UART,
++ DEVICE_TOUCH,
++ DEVICE_TVOUT,
++ DEVICE_OTG, // usb
++ DEVICE_OHCI, // usb
++ DEVICE_USERINTR, // Linux Uesr Interrupt
++ DEVICE_SATA,
++ DEVICE_GPIOEXP,
++// DEIVCE_XXXX,
++// ...
++
++ DEVICE_MAX
++} PWR_DEVICE_ID_TYPE;
++
++typedef enum {
++ PWR_CMD_OFF = 0,
++ PWR_CMD_ON,
++ PWR_CMD_GETSTATUS,
++ PWR_CMD_MAX
++} PWR_CMD_TYPE;
++
++typedef enum {
++ PWR_STATUS_OFF = 0,
++ PWR_STATUS_ON,
++ PWR_STATUS_UNKNOWN,
++ PWR_STATUS_MAX
++} PWR_STATUS_TYPE;
++
++// for input
++typedef struct _stpwrioctl{
++ unsigned int deviceid; // refer to 'PWR_DEVICE_ID_TYPE'
++ unsigned int cmd; // refer to 'PWR_CMD_TYPE'
++}stpwrioctl;
++
++// for ouput
++typedef struct _stpwrinfo{
++ unsigned int status; // refer to 'PWR_STATUS_TYPE'
++}stpwrinfo;
++
++
++typedef struct pwr_ioctl_param {
++ stpwrioctl in;
++ stpwrinfo out; // refer to 'PWR_STATUS_TYPE'
++} pwr_ioctl_param_t;
++
++#endif /* __IOCTL_STR_H__ */
++
+diff --git a/include/linux/tcc_pwm_ioctl.h b/include/linux/tcc_pwm_ioctl.h
+new file mode 100644
+index 0000000..d9b1276
+--- /dev/null
++++ b/include/linux/tcc_pwm_ioctl.h
+@@ -0,0 +1,10 @@
++
++#ifndef __TCC_PWM_IOCTL_H__
++#define __TCC_PWM_IOCTL_H__
++
++#define TCC_PWM_DEV_MAJOR 248
++#define IOCTL_PWR_CONTROL _IO(TCC_PWM_DEV_MAJOR, 1)
++
++#endif /* __TCC_PWM_IOCTL_H__ */
++
++
+diff --git a/include/linux/tccfb_ioctl.h b/include/linux/tccfb_ioctl.h
+new file mode 100644
+index 0000000..869d8ec
+--- /dev/null
++++ b/include/linux/tccfb_ioctl.h
+@@ -0,0 +1,308 @@
++/****************************************************************************
++ * FileName : tccfb_ioctl.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#ifndef __TCCFB_IOCTL_CODE_H_
++#define __TCCFB_IOCTL_CODE_H_
++
++//
++#define TCC_LCD_FB_IOCTL_DISP_ONOFF 0x10
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned int [1] - 0: Off, 1: On
++ *---------------------------------------------------------------------------------------*/
++
++
++#define TCC_LCD_FB_IOCTL_ALPHA_ONOFF 0x11
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned int [1] - 0: Off, 1: On
++ *---------------------------------------------------------------------------------------*/
++
++
++#define TCC_LCD_FB_IOCTL_ALPHA_SET 0x12
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned char [1] - Alpah value(0~0xFF)
++ *---------------------------------------------------------------------------------------*/
++
++
++#define TCC_LCD_FB_IOCTL_CHROMAKEY_ONOFF 0x13
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned int [1] - 0: Off, 1: On
++ *---------------------------------------------------------------------------------------*/
++
++
++#define TCC_LCD_FB_IOCTL_CHROMAKEY_SET_VALUE 0x14
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned char [3] - [0]: red
++ * [1]: green
++ * [2]: blue
++ *---------------------------------------------------------------------------------------*/
++
++
++#define TCC_LCD_FB_IOCTL_CHROMAKEY_SET_MASK 0x15
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned char [3] - [0]: red
++ * [1]: green
++ * [2]: blue
++ *---------------------------------------------------------------------------------------*/
++
++#define TCC_LCD_FB_IOCTL_ALPHA_SELECTION 0x16
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned int [1] - 0 : A10 bits and A11 are used as alpha value
++ * 1 : Alpha bits in the pixel are used as alpha value.
++ *---------------------------------------------------------------------------------------*/
++
++
++#define TCC_LCD_FB_IOCTL_SET_FORMAT 0x17
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned int [1] - Ref to IMGCH_FMT_t Type
++ *---------------------------------------------------------------------------------------*/
++enum {
++ IMGFMT_1BPP = 0, // 1bpp indexed color
++ IMGFMT_2BPP = 1, // 2bpp indexed color
++ IMGFMT_4BPP = 2, // 4bpp indexed color
++ IMGFMT_8BPP = 3, // 8bpp indexed color
++ //...
++ IMGFMT_RGB332 = 8, // RGB332 - 1bytes aligned - R[7:5],G[4:2],B[1:0]
++ IMGFMT_RGB444 = 9, // RGB444 - 2bytes aligned - A[15:12],R[11:8],G[7:3],B[3:0]
++ IMGFMT_RGB565 = 10, // RGB565 - 2bytes aligned - R[15:11],G[10:5],B[4:0]
++ IMGFMT_RGB555 = 11, // RGB555 - 2bytes aligned - A[15],R[14:10],G[9:5],B[4:0]
++ IMGFMT_RGB888 = 12, // RGB888 - 4bytes aligned - A[31:24],R[23:16],G[15:8],B[7:0]
++ IMGFMT_RGB666 = 13, // RGB666 - 4bytes aligned - A[23:18],R[17:12],G[11:6],B[5:0]
++ //...
++ IMGFMT_YUV420 = 24, // YCbCr 4:2:0 Separated format - Not Supported for Image 1 and 2
++ IMGFMT_YUV422 = 25, // YCbCr 4:2:2 Separated format - Not Supported for Image 1 and 2
++ IMGFMT_YUV422P = 26, // YCbCr 4:2:2 Sequential format
++ //...
++ IMGFMT_YUV420I0 = 28, // YCbCr 4:2:0 interleved type 0 format - Not Supported for Image 1 and 2
++ IMGFMT_YUV420I1 = 29, // YCbCr 4:2:0 interleved type 1 format - Not Supported for Image 1 and 2
++ IMGFMT_YUV422I0 = 30, // YCbCr 4:2:2 interleved type 0 format - Not Supported for Image 1 and 2
++ IMGFMT_YUV422I1 = 31, // YCbCr 4:2:2 interleved type 1 format - Not Supported for Image 1 and 2
++
++} IMGCH_FMT_t;
++/*---------------------------------------------------------------------------------------*/
++
++
++#define TCC_LCD_FB_IOCTL_SET_BASEADDR 0x18
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned int [3] - [0]: base0 - IMGx base address. IMG0 Y base address.
++ * [1]: base1 - IMG0 U base address.
++ * [2]: base2 - IMG0 V base address.
++ *---------------------------------------------------------------------------------------*/
++
++
++#define TCC_LCD_FB_IOCTL_GET_BASEADDR 0x19
++/*----------------------------------------------------------------------------------------
++ * [OUT] unsigned int [3] - [0]: base0 - IMGx base address. IMG0 Y base address.
++ * [1]: base1 - IMG0 U base address.
++ * [2]: base2 - IMG0 V base address.
++ *---------------------------------------------------------------------------------------*/
++
++
++#define TCC_LCD_FB_IOCTL_SET_ADDROFFSET 0x1A
++/*----------------------------------------------------------------------------------------
++ * [OUT] unsigned int [2] - [0]: offset0 - Address Offset Y or RGB channel of FIFO(0)
++ * [1]: offset1 - Address Offset In U or V channel of FIFO(1,2)
++ * Invalid for Image1 and Image2
++ *---------------------------------------------------------------------------------------*/
++
++#define TCC_LCD_FB_IOCTL_SET_IMGWINDOW 0x1B
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned int [4] - [0]: Image start offset X
++ * [1]: Image start offset Y
++ * [2]: Image width
++ * [3]: Image height
++ *---------------------------------------------------------------------------------------*/
++
++#define TCC_LCD_FB_IOCTL_LCD_ONOFF 0x1C
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned int [1] - 0: Off, 1: On
++ *---------------------------------------------------------------------------------------*/
++
++
++
++#define TCC_LCD_FB_IOCTL_SET_R2YCONV_OPTION 0x30
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned int [2] - [0]: LCDC Index. (0 - LCDC0, 1 - LCDC1)
++ - [1]: Ref to RGB2YUV_CONV_OPTION_t Type
++ *---------------------------------------------------------------------------------------*/
++
++#define TCC_LCD_FB_IOCTL_GET_R2YCONV_OPTION 0x31
++/*----------------------------------------------------------------------------------------
++ * [IN/OUT] unsigned int [2] - (IN ) [0]: LCDC Index. (0 - LCDC0, 1 - LCDC1)
++ * - (OUT) [1]: Ref to RGB2YUV_CONV_OPTION_t Type
++ *---------------------------------------------------------------------------------------*/
++
++enum {
++ R2Y_CONV_OPTION_0 = 0, // * Y = 0.299*R + 0.587G + 0.114B
++ // * Cb = -0.172*R - 0.339*G + 0.511*B + 128
++ // * Cr = 0.511*R - 0.428*G - 0.083*B + 128
++ // The range for "RGB" is 16 ~ 235, "Studio Color".
++ // The result is "Studio Color" - Normally SDTV.
++
++ R2Y_CONV_OPTION_1 = 1, // * Y = 0.257*R + 0.504*G + 0.098*B + 16
++ // * Cb = -0.148*R - 0.291*G + 0.439*B + 128
++ // * Cr = 0.439*R - 0.368*G - 0.071*B + 128
++ // The range for "RGB" is 0 ~ 255, "Computer System Color"
++ // The result is "Studio Color" - Normally SDTV.
++
++ R2Y_CONV_OPTION_2 = 2, // * Y = 0.213*R + 0.715*G + 0.072*B
++ // * Cb = -0.117*R - 0.394*G + 0.511*B + 128
++ // * Cr = 0.511*R - 0.464*G - 0.047*B + 128
++ // The range for "RGB" is 16 ~ 235, "Studio Color"..
++ // The result is "Studio Color" - Normally HDTV.
++
++ R2Y_CONV_OPTION_3 = 3, // * Y = 0.183*R + 0.614*G + 0.062*B + 16
++ // * Cb = -0.101*R - 0.338*G + 0.439*B + 128
++ // * Cr = 0.439*R - 0.399*G - 0.040*B + 128
++ // The range for "RGB" is 0 ~ 255, "Computer System Color".
++ // The result is "Studio Color" - Normally HDTV.
++} RGB2YUV_CONV_OPTION_t;
++
++
++
++#define TCC_LCD_FB_IOCTL_SET_IMG_Y2RCONV_OPTION 0x32
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned int [1] - [1]: Ref to YUV2RGB_CONV_OPTION_t Type
++ *---------------------------------------------------------------------------------------*/
++
++#define TCC_LCD_FB_IOCTL_GET_IMG_Y2RCONV_OPTION 0x33
++/*----------------------------------------------------------------------------------------
++ * [OUT] unsigned int [1] - [1]: Ref to YUV2RGB_CONV_OPTION_t Type
++ *---------------------------------------------------------------------------------------*/
++
++enum {
++ Y2R_CONV_OPTION_0 = 0, // * R = Y + 1.371 * (Cr - 128)
++ // * G = Y + 0.336 * (Cb - 128) - 0.698 * (Cr - 128)
++ // * B = Y + 1.732 * (Cb - 128)
++ // The range for "YCbCr" is 16 ~ 235, "Studio Color".
++ // The result is "Studio Color" - Normally SDTV.
++
++ Y2R_CONV_OPTION_1 = 1, // * R = 1.164 * (Y - 16) + 1.596 * (Cr - 128)
++ // * G = 1.164 * (Y - 16) - 0.391 * (Cb - 128) - 0.813 * (Cr - 128)
++ // * B = 1.164 * (Y - 16) + 2.018 * (Cb - 128)
++ // The range for "YCbCr" is 16 ~ 235, "Studio Color".
++ // The result is "Computer System Color" - Normally SDTV.
++
++ Y2R_CONV_OPTION_2 = 2, // * R = Y + 1.540 * (Cr - 128)
++ // * G = Y - 0.183 * (Cb - 128) - 0.459 * (Cr - 128)
++ // * B = Y + 1.816 * (Cb - 128)
++ // The range for "YCbCr" is 16 ~ 235, "Studio Color".
++ // The result is "Studio Color" - Normally HDTV.
++
++ Y2R_CONV_OPTION_3 = 3, // * R = 1.164 * (Y - 16) + 1.793 * (Cr - 128)
++ // * G = 1.164 * (Y - 16) - 0.213 * (Cb - 128) - 0.534 * (Cr - 128)
++ // * B = 1.164 * (Y - 16) + 2.115 * (Cb - 128)
++ // The range for "YCbCr" is 16 ~ 235, "Studio Color".
++ // The result is "Computer System Color" - Normally HDTV.
++
++} YUV2RGB_CONV_OPTION_t;
++
++
++#define TCC_LCD_FB_IOCTL_SET_COLOR_ENAHNCEMENT 0x20
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned int [4] - [0]: LCDC Index. (0 - LCDC0, 1 - LCDC1)
++ * [1]: Hue
++ * [2]: Brightness
++ * [3]: Contrast
++ *---------------------------------------------------------------------------------------*/
++
++#define TCC_LCD_FB_IOCTL_GET_COLOR_ENAHNCEMENT 0x21
++/*----------------------------------------------------------------------------------------
++ * [IN/OUT] unsigned int [4] - (IN ) [0]: LCDC Index. (0 - LCDC0, 1 - LCDC1)
++ * (OUT) [1]: Hue
++ * (OUT) [2]: Brightness
++ * (OUT) [3]: Contrast
++ *---------------------------------------------------------------------------------------*/
++
++#define TCC_LCD_FB_IOCTL_SET_IMAGE_ENAHNCEMENT 0x22
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned int [3] - [0]: Hue
++ * [1]: Brightness
++ * [2]: Contrast
++ *---------------------------------------------------------------------------------------*/
++
++#define TCC_LCD_FB_IOCTL_GET_IMAGE_ENAHNCEMENT 0x23
++/*----------------------------------------------------------------------------------------
++ * [OUT] unsigned int [3] - [0]: Hue
++ * [1]: Brightness
++ * [2]: Contrast
++ *---------------------------------------------------------------------------------------*/
++
++// Hue Calibration Register - 2¡¯s complement signed value
++// * -30 ~ 30 degree
++// * 0x80 for -30 degree
++// * 0x00 for 0 degree for default value
++// * 0x7F for about 30 degree
++
++// Brightness Calibration Register - 2¡¯s complement signed value
++// * -128 ~ 128 value
++// * 0x80 for -128 offset
++// * 0x00 for 0 offset
++// * 0x7F for 127 offset
++
++// Contrast Calibration Register - 2¡¯s complement signed value
++// * -4 ~ 4
++// * 0x80 for -4.0 value
++// * 0xFF for -1.0 value
++// * 0x20 for 1.0 value
++// * 0x7F for about 4.0 value
++
++
++#define TCC_LCD_FB_IOCTL_SET_OVP 0x50
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned char [1] - [0]: ovp
++ *---------------------------------------------------------------------------------------*/
++
++#define TCC_LCD_FB_IOCTL_SET_M2M 0x51
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned int [1] - [0]: 0 - disable, 1 - enable
++ *
++ * !! M2M1 -->(On-the-Fly)-->LCDC1.IMG2
++ *---------------------------------------------------------------------------------------*/
++
++
++//TVOUT Controller IOCTL CODE
++#define TCC_LCD_FB_IOCTL_TVOUT_TYPE 0X60
++/*----------------------------------------------------------------------------------------
++ * [IN ] unsigned int [1] - mode
++ *---------------------------------------------------------------------------------------*/
++
++#define NTSC_M 0x0000
++#define NTSC_M_J 0x0001
++#define NTSC_N 0x0010
++#define NTSC_N_J 0x0011
++#define NTSC_443 0x0020
++#define PAL_M 0x0100
++#define PAL_N 0x0110
++#define PAL_B 0x0120
++#define PAL_G 0x0130
++#define PAL_H 0x0140
++#define PAL_I 0x0150
++#define PSEUDO_NTSC 0x1000
++#define PSEUDO_PAL 0x1010
++
++#define TCC_LCD_FB_IOCTL_TVOUT_OPEN 0x61
++/*----------------------------------------------------------------------------------------
++ *
++ *---------------------------------------------------------------------------------------*/
++
++#define TCC_LCD_FB_IOCTL_TVOUT_CLOSE 0x62
++/*----------------------------------------------------------------------------------------
++ *
++ *---------------------------------------------------------------------------------------*/
++
++#define TCC_LCD_FB_IOCTL_TVOUT_CONNECT_LCDC 0x63
++/*----------------------------------------------------------------------------------------
++ *
++ *---------------------------------------------------------------------------------------*/
++
++
++#endif //__TCCFB_IOCTL_CODE_H_
++
++
+diff --git a/include/sound/pcm.h b/include/sound/pcm.h
+index 40c5a6f..16937aa 100644
+--- a/include/sound/pcm.h
++++ b/include/sound/pcm.h
+@@ -112,22 +112,25 @@ struct snd_pcm_ops {
+ #define SNDRV_PCM_RATE_5512 (1<<0) /* 5512Hz */
+ #define SNDRV_PCM_RATE_8000 (1<<1) /* 8000Hz */
+ #define SNDRV_PCM_RATE_11025 (1<<2) /* 11025Hz */
+-#define SNDRV_PCM_RATE_16000 (1<<3) /* 16000Hz */
+-#define SNDRV_PCM_RATE_22050 (1<<4) /* 22050Hz */
+-#define SNDRV_PCM_RATE_32000 (1<<5) /* 32000Hz */
+-#define SNDRV_PCM_RATE_44100 (1<<6) /* 44100Hz */
+-#define SNDRV_PCM_RATE_48000 (1<<7) /* 48000Hz */
+-#define SNDRV_PCM_RATE_64000 (1<<8) /* 64000Hz */
+-#define SNDRV_PCM_RATE_88200 (1<<9) /* 88200Hz */
+-#define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */
+-#define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */
+-#define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */
++#define SNDRV_PCM_RATE_12000 (1<<3) /* 12000Hz */
++#define SNDRV_PCM_RATE_16000 (1<<4) /* 16000Hz */
++#define SNDRV_PCM_RATE_22050 (1<<5) /* 22050Hz */
++#define SNDRV_PCM_RATE_24000 (1<<6) /* 24000Hz */
++#define SNDRV_PCM_RATE_32000 (1<<7) /* 32000Hz */
++#define SNDRV_PCM_RATE_44100 (1<<8) /* 44100Hz */
++#define SNDRV_PCM_RATE_48000 (1<<9) /* 48000Hz */
++#define SNDRV_PCM_RATE_64000 (1<<10) /* 64000Hz */
++#define SNDRV_PCM_RATE_88200 (1<<11) /* 88200Hz */
++#define SNDRV_PCM_RATE_96000 (1<<12) /* 96000Hz */
++#define SNDRV_PCM_RATE_176400 (1<<13) /* 176400Hz */
++#define SNDRV_PCM_RATE_192000 (1<<14) /* 192000Hz */
+
+ #define SNDRV_PCM_RATE_CONTINUOUS (1<<30) /* continuous range */
+ #define SNDRV_PCM_RATE_KNOT (1<<31) /* supports more non-continuos rates */
+
+ #define SNDRV_PCM_RATE_8000_44100 (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_11025|\
+- SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_22050|\
++ SNDRV_PCM_RATE_12000|SNDRV_PCM_RATE_16000|\
++ SNDRV_PCM_RATE_22050|SNDRV_PCM_RATE_24000|\
+ SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100)
+ #define SNDRV_PCM_RATE_8000_48000 (SNDRV_PCM_RATE_8000_44100|SNDRV_PCM_RATE_48000)
+ #define SNDRV_PCM_RATE_8000_96000 (SNDRV_PCM_RATE_8000_48000|SNDRV_PCM_RATE_64000|\
+diff --git a/init/initramfs.c b/init/initramfs.c
+index 4f5ba75..4222b81 100644
+--- a/init/initramfs.c
++++ b/init/initramfs.c
+@@ -582,6 +582,7 @@ static int __init populate_rootfs(void)
+ if (initrd_start) {
+ #ifdef CONFIG_BLK_DEV_RAM
+ int fd;
++ printk(KERN_INFO "initrd_start:0x%lx, initrd_end:0x%lx\n", initrd_start, initrd_end);
+ printk(KERN_INFO "checking if image is initramfs...");
+ err = unpack_to_rootfs((char *)initrd_start,
+ initrd_end - initrd_start, 1);
+diff --git a/initrd_tcc_mkrd.sh b/initrd_tcc_mkrd.sh
+new file mode 100755
+index 0000000..1a81c6b
+--- /dev/null
++++ b/initrd_tcc_mkrd.sh
+@@ -0,0 +1,31 @@
++#=======================================================================================
++# FileName : tcc_mkrd.sh
++# Description : Make linux.rom
++# Mark linux.rom with CRC & ramdisk size
++#=======================================================================================
++#
++# TCC Board Support Package
++# Copyright (c) Telechips, Inc.
++# ALL RIGHTS RESERVED
++#
++#=======================================================================================
++
++echo "======================================================"
++K_SIZE=4M
++if test $1; then
++ K_SIZE=$1;
++fi
++
++echo "dd if=arch/arm/boot/Image of=Img bs=$K_SIZE conv=sync"
++
++dd if=arch/arm/boot/Image of=Img bs=$K_SIZE conv=sync
++cat Img ../ramdisk/initrd_1.5M.rom > linux.img
++
++./tcc_crc -o linux.rom -v 1700 linux.img
++
++rm -f Img
++rm -f linux.img
++
++echo "======================================================"
++exit
++
+diff --git a/make_zImage_initramfs.sh b/make_zImage_initramfs.sh
+new file mode 100755
+index 0000000..5c688d3
+--- /dev/null
++++ b/make_zImage_initramfs.sh
+@@ -0,0 +1,24 @@
++#!/bin/bash
++ ################################################################
++ # $ID: make_linux.sh Fri, 06 Mar 2009 10:04:31 +0800 root $ #
++ # #
++ # Description: #
++ # #
++ # Maintainer: (Meihui Fan) <mhfan@hhcn.com> #
++ # #
++ # Copyright (C) 2009 HHTech #
++ # www.hhcn.com, www.hhcn.org #
++ # All rights reserved. #
++ # #
++ # This file is free software; #
++ # you are free to modify and/or redistribute it #
++ # under the terms of the GNU General Public Licence (GPL). #
++ # #
++ # Last modified: 五, 25 9月 2009 11:47:57 +0800 by root #
++ ################################################################
++
++sudo make -j 3
++sudo ./tcc_mk_initramfs.sh
++
++ ################## End Of File: make_linux.sh ##################
++# vim:sts=4:ts=8:
+diff --git a/make_zImage_ramdisk.sh b/make_zImage_ramdisk.sh
+new file mode 100755
+index 0000000..1682cfd
+--- /dev/null
++++ b/make_zImage_ramdisk.sh
+@@ -0,0 +1,24 @@
++#!/bin/bash
++ ################################################################
++ # $ID: make_linux.sh Fri, 06 Mar 2009 10:04:31 +0800 root $ #
++ # #
++ # Description: #
++ # #
++ # Maintainer: (Meihui Fan) <mhfan@hhcn.com> #
++ # #
++ # Copyright (C) 2009 HHTech #
++ # www.hhcn.com, www.hhcn.org #
++ # All rights reserved. #
++ # #
++ # This file is free software; #
++ # you are free to modify and/or redistribute it #
++ # under the terms of the GNU General Public Licence (GPL). #
++ # #
++ # Last modified: 五, 25 9月 2009 14:30:30 +0800 by root #
++ ################################################################
++
++sudo make -j 3
++sudo ./tcc_mk_rd.sh
++
++ ################## End Of File: make_linux.sh ##################
++# vim:sts=4:ts=8:
+diff --git a/make_zImage_rootfs.sh b/make_zImage_rootfs.sh
+new file mode 100755
+index 0000000..1eca7a8
+--- /dev/null
++++ b/make_zImage_rootfs.sh
+@@ -0,0 +1,25 @@
++#!/bin/bash
++ ################################################################
++ # $ID: make_linux.sh Fri, 06 Mar 2009 10:04:31 +0800 root $ #
++ # #
++ # Description: #
++ # #
++ # Maintainer: (Meihui Fan) <mhfan@hhcn.com> #
++ # #
++ # Copyright (C) 2009 HHTech #
++ # www.hhcn.com, www.hhcn.org #
++ # All rights reserved. #
++ # #
++ # This file is free software; #
++ # you are free to modify and/or redistribute it #
++ # under the terms of the GNU General Public Licence (GPL). #
++ # #
++ # Last modified: 五, 25 9月 2009 11:57:29 +0800 by root #
++ ################################################################
++
++sudo make -j 3
++sudo ./tcc_mk_rootfs.sh
++sudo mv linux.rom ../fw-utils/
++
++ ################## End Of File: make_linux.sh ##################
++# vim:sts=4:ts=8:
+diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
+index d3340dd..e8eb7e3 100644
+--- a/net/bluetooth/rfcomm/tty.c
++++ b/net/bluetooth/rfcomm/tty.c
+@@ -818,6 +818,7 @@ static int rfcomm_tty_write_room(struct tty_struct *tty)
+ return room;
+ }
+
++extern int rfcomm_tty_ioctl_called;
+ static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg)
+ {
+ BT_DBG("tty %p cmd 0x%02x", tty, cmd);
+@@ -840,6 +841,7 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned
+ break;
+
+ case TIOCGSERIAL:
++ rfcomm_tty_ioctl_called = 1;
+ BT_ERR("TIOCGSERIAL is not supported");
+ return -ENOIOCTLCMD;
+
+diff --git a/security/device_cgroup.c b/security/device_cgroup.c
+index 5ba7870..8f880c2 100644
+--- a/security/device_cgroup.c
++++ b/security/device_cgroup.c
+@@ -507,6 +507,7 @@ acc_check:
+
+ return -EPERM;
+ }
++EXPORT_SYMBOL(devcgroup_inode_permission);
+
+ int devcgroup_inode_mknod(int mode, dev_t dev)
+ {
+diff --git a/security/security.c b/security/security.c
+index c0acfa7..812ebf4 100644
+--- a/security/security.c
++++ b/security/security.c
+@@ -434,6 +434,7 @@ int security_inode_readlink(struct dentry *dentry)
+ return 0;
+ return security_ops->inode_readlink(dentry);
+ }
++EXPORT_SYMBOL(security_inode_readlink);
+
+ int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
+ {
+@@ -448,6 +449,7 @@ int security_inode_permission(struct inode *inode, int mask)
+ return 0;
+ return security_ops->inode_permission(inode, mask);
+ }
++EXPORT_SYMBOL(security_inode_permission);
+
+ int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
+ {
+@@ -548,6 +550,7 @@ int security_file_permission(struct file *file, int mask)
+ {
+ return security_ops->file_permission(file, mask);
+ }
++EXPORT_SYMBOL(security_file_permission);
+
+ int security_file_alloc(struct file *file)
+ {
+diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
+index a789efc..5284235 100644
+--- a/sound/core/pcm_native.c
++++ b/sound/core/pcm_native.c
+@@ -1742,11 +1742,11 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
+ return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+ }
+
+-#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12
++#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 14
+ #error "Change this table"
+ #endif
+
+-static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100,
++static unsigned int rates[] = { 5512, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100,
+ 48000, 64000, 88200, 96000, 176400, 192000 };
+
+ const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {
+@@ -1758,6 +1758,8 @@ static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+ {
+ struct snd_pcm_hardware *hw = rule->private;
++ //12KHz and 24KHz bits are all zero, you need set 1
++ hw->rates |= (SNDRV_PCM_RATE_12000|SNDRV_PCM_RATE_24000);
+ return snd_interval_list(hw_param_interval(params, rule->var),
+ snd_pcm_known_rates.count,
+ snd_pcm_known_rates.list, hw->rates);
+diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
+index 4dfda66..7398c38 100644
+--- a/sound/soc/Kconfig
++++ b/sound/soc/Kconfig
+@@ -33,6 +33,7 @@ source "sound/soc/fsl/Kconfig"
+ source "sound/soc/davinci/Kconfig"
+ source "sound/soc/omap/Kconfig"
+ source "sound/soc/blackfin/Kconfig"
++source "sound/soc/tcc/Kconfig"
+
+ # Supported codecs
+ source "sound/soc/codecs/Kconfig"
+diff --git a/sound/soc/Makefile b/sound/soc/Makefile
+index d849349..f969d41 100644
+--- a/sound/soc/Makefile
++++ b/sound/soc/Makefile
+@@ -2,4 +2,4 @@ snd-soc-core-objs := soc-core.o soc-dapm.o
+
+ obj-$(CONFIG_SND_SOC) += snd-soc-core.o
+ obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/
+-obj-$(CONFIG_SND_SOC) += omap/ au1x/ blackfin/
++obj-$(CONFIG_SND_SOC) += omap/ au1x/ blackfin/ tcc/
+diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
+index 38a0e3b..1da98e9 100644
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -19,6 +19,7 @@ config SND_SOC_ALL_CODECS
+ select SND_SOC_WM8900
+ select SND_SOC_WM8903
+ select SND_SOC_WM8971
++ select SND_SOC_WM8987
+ select SND_SOC_WM8990
+ help
+ Normally ASoC codec drivers are only built if a machine driver which
+@@ -84,6 +85,9 @@ config SND_SOC_WM8510
+ config SND_SOC_WM8580
+ tristate
+
++config SND_SOC_WM8581
++ tristate
++
+ config SND_SOC_WM8731
+ tristate
+
+@@ -102,6 +106,9 @@ config SND_SOC_WM8903
+ config SND_SOC_WM8971
+ tristate
+
++config SND_SOC_WM8987
++ tristate
++
+ config SND_SOC_WM8990
+ tristate
+
+diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
+index 90f0a58..f763453 100644
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -10,12 +10,14 @@ snd-soc-tlv320aic3x-objs := tlv320aic3x.o
+ snd-soc-uda1380-objs := uda1380.o
+ snd-soc-wm8510-objs := wm8510.o
+ snd-soc-wm8580-objs := wm8580.o
++snd-soc-wm8581-objs := wm8581.o
+ snd-soc-wm8731-objs := wm8731.o
+ snd-soc-wm8750-objs := wm8750.o
+ snd-soc-wm8753-objs := wm8753.o
+ snd-soc-wm8900-objs := wm8900.o
+ snd-soc-wm8903-objs := wm8903.o
+ snd-soc-wm8971-objs := wm8971.o
++snd-soc-wm8987-objs := wm8987.o
+ snd-soc-wm8990-objs := wm8990.o
+ snd-soc-wm9712-objs := wm9712.o
+ snd-soc-wm9713-objs := wm9713.o
+@@ -31,6 +33,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
+ obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
+ obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
+ obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
++obj-$(CONFIG_SND_SOC_WM8581) += snd-soc-wm8581.o
+ obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o
+ obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
+ obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
+@@ -38,6 +41,7 @@ obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
+ obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
+ obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
+ obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
++obj-$(CONFIG_SND_SOC_WM8987) += snd-soc-wm8987.o
+ obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
+ obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
+ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
+diff --git a/sound/soc/codecs/wm8581.c b/sound/soc/codecs/wm8581.c
+new file mode 100644
+index 0000000..2069048
+--- /dev/null
++++ b/sound/soc/codecs/wm8581.c
+@@ -0,0 +1,1296 @@
++/*
++ * wm8581.c -- WM8581 ALSA Soc Audio driver
++ *
++ * Copyright 2008 Wolfson Microelectronics PLC.
++ *
++ * 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.
++ *
++ * Notes:
++ * The WM8581 is a multichannel codec with S/PDIF support, featuring six
++ * DAC channels and two ADC channels.
++ *
++ * Currently only the primary audio interface is supported - S/PDIF and
++ * the secondary audio interfaces are not.
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/i2c.h>
++#include <linux/platform_device.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/soc-dapm.h>
++#include <sound/tlv.h>
++#include <sound/initval.h>
++#include <asm/div64.h>
++
++#include "wm8581.h"
++
++#define WM8581_VERSION "0.1"
++
++struct pll_state {
++ unsigned int in;
++ unsigned int out;
++};
++
++/* codec private data */
++struct wm8581_priv {
++ struct pll_state a;
++ struct pll_state b;
++};
++
++/* WM8581 register space */
++#define WM8581_PLLA1 0x00
++#define WM8581_PLLA2 0x01
++#define WM8581_PLLA3 0x02
++#define WM8581_PLLA4 0x03
++#define WM8581_PLLB1 0x04
++#define WM8581_PLLB2 0x05
++#define WM8581_PLLB3 0x06
++#define WM8581_PLLB4 0x07
++#define WM8581_CLKSEL 0x08
++#define WM8581_PAIF1 0x09
++#define WM8581_PAIF2 0x0A
++#define WM8581_SAIF1 0x0B
++#define WM8581_PAIF3 0x0C
++#define WM8581_PAIF4 0x0D
++#define WM8581_SAIF2 0x0E
++#define WM8581_DAC_CONTROL1 0x0F
++#define WM8581_DAC_CONTROL2 0x10
++#define WM8581_DAC_CONTROL3 0x11
++#define WM8581_DAC_CONTROL4 0x12
++#define WM8581_DAC_CONTROL5 0x13
++#define WM8581_DIGITAL_ATTENUATION_DACL1 0x14
++#define WM8581_DIGITAL_ATTENUATION_DACR1 0x15
++#define WM8581_DIGITAL_ATTENUATION_DACL2 0x16
++#define WM8581_DIGITAL_ATTENUATION_DACR2 0x17
++#define WM8581_DIGITAL_ATTENUATION_DACL3 0x18
++#define WM8581_DIGITAL_ATTENUATION_DACR3 0x19
++#define WM8581_DIGITAL_ATTENUATION_DACL4 0x1A
++#define WM8581_DIGITAL_ATTENUATION_DACR4 0x1B
++#define WM8581_MASTER_DIGITAL_ATTENUATION 0x1C
++#define WM8581_ADC_CONTROL1 0x1D
++#define WM8581_SPDTXCHAN0 0x1E
++#define WM8581_SPDTXCHAN1 0x1F
++#define WM8581_SPDTXCHAN2 0x20
++#define WM8581_SPDTXCHAN3 0x21
++#define WM8581_SPDTXCHAN4 0x22
++#define WM8581_SPDTXCHAN5 0x23
++#define WM8581_SPDMODE 0x24
++#define WM8581_INTMASK 0x25
++#define WM8581_GPO1 0x26
++#define WM8581_GPO2 0x27
++#define WM8581_GPO3 0x28
++#define WM8581_GPO4 0x29
++#define WM8581_GPO5 0x2A
++#define WM8581_INTSTAT 0x2B
++#define WM8581_SPDRXCHAN1 0x2C
++#define WM8581_SPDRXCHAN2 0x2D
++#define WM8581_SPDRXCHAN3 0x2E
++#define WM8581_SPDRXCHAN4 0x2F
++#define WM8581_SPDRXCHAN5 0x30
++#define WM8581_SPDSTAT 0x31
++#define WM8581_PWRDN1 0x32
++#define WM8581_PWRDN2 0x33
++#define WM8581_READBACK 0x34
++#define WM8581_RESET 0x35
++
++/* PLLB4 (register 7h) */
++#define WM8581_PLLB4_MCLKOUTSRC_MASK 0x60
++#define WM8581_PLLB4_MCLKOUTSRC_PLLA 0x20
++#define WM8581_PLLB4_MCLKOUTSRC_PLLB 0x40
++#define WM8581_PLLB4_MCLKOUTSRC_OSC 0x60
++
++#define WM8581_PLLB4_CLKOUTSRC_MASK 0x180
++#define WM8581_PLLB4_CLKOUTSRC_PLLACLK 0x080
++#define WM8581_PLLB4_CLKOUTSRC_PLLBCLK 0x100
++#define WM8581_PLLB4_CLKOUTSRC_OSCCLK 0x180
++
++/* CLKSEL (register 8h) */
++#define WM8581_CLKSEL_DAC_CLKSEL_MASK 0x03
++#define WM8581_CLKSEL_DAC_CLKSEL_PLLA 0x01
++#define WM8581_CLKSEL_DAC_CLKSEL_PLLB 0x02
++
++/* AIF control 1 (registers 9h-bh) */
++#define WM8581_AIF_RATE_MASK 0x7
++#define WM8581_AIF_RATE_128 0x0
++#define WM8581_AIF_RATE_192 0x1
++#define WM8581_AIF_RATE_256 0x2
++#define WM8581_AIF_RATE_384 0x3
++#define WM8581_AIF_RATE_512 0x4
++#define WM8581_AIF_RATE_768 0x5
++#define WM8581_AIF_RATE_1152 0x6
++
++#define WM8581_AIF_BCLKSEL_MASK 0x18
++#define WM8581_AIF_BCLKSEL_64 0x00
++#define WM8581_AIF_BCLKSEL_128 0x08
++#define WM8581_AIF_BCLKSEL_256 0x10
++#define WM8581_AIF_BCLKSEL_SYSCLK 0x18
++
++#define WM8581_AIF_MS 0x20
++
++#define WM8581_AIF_CLKSRC_MASK 0xc0
++#define WM8581_AIF_CLKSRC_PLLA 0x40
++#define WM8581_AIF_CLKSRC_PLLB 0x40
++#define WM8581_AIF_CLKSRC_MCLK 0xc0
++
++/* AIF control 2 (registers ch-eh) */
++#define WM8581_AIF_FMT_MASK 0x03
++#define WM8581_AIF_FMT_RIGHTJ 0x00
++#define WM8581_AIF_FMT_LEFTJ 0x01
++#define WM8581_AIF_FMT_I2S 0x02
++#define WM8581_AIF_FMT_DSP 0x03
++
++#define WM8581_AIF_LENGTH_MASK 0x0c
++#define WM8581_AIF_LENGTH_16 0x00
++#define WM8581_AIF_LENGTH_20 0x04
++#define WM8581_AIF_LENGTH_24 0x08
++#define WM8581_AIF_LENGTH_32 0x0c
++
++#define WM8581_AIF_LRP 0x10
++#define WM8581_AIF_BCP 0x20
++
++/* Powerdown Register 1 (register 32h) */
++#define WM8581_PWRDN1_PWDN 0x001
++#define WM8581_PWRDN1_ALLDACPD 0x040
++
++/* Powerdown Register 2 (register 33h) */
++#define WM8581_PWRDN2_OSSCPD 0x001
++#define WM8581_PWRDN2_PLLAPD 0x002
++#define WM8581_PWRDN2_PLLBPD 0x004
++#define WM8581_PWRDN2_SPDIFPD 0x008
++#define WM8581_PWRDN2_SPDIFTXD 0x010
++#define WM8581_PWRDN2_SPDIFRXD 0x020
++
++#define WM8581_DAC_CONTROL5_MUTEALL 0x10
++
++/*
++ * wm8581 register cache
++ * We can't read the WM8581 register space when we
++ * are using 2 wire for device control, so we cache them instead.
++ */
++static const u16 wm8581_reg[] = {
++ 0x0121, 0x017e, 0x007d, 0x0014, /*R3*/
++ 0x0121, 0x017e, 0x007d, 0x0194, /*R7*/
++ 0x001c, 0x0002, 0x0002, 0x00c2, /*R11*/
++ //0x0182, 0x0082, 0x000a, 0x0024, /*R15*/
++ 0x0182, 0x0082, 0x000a, 0x00E4, /*R15*/
++ 0x0009, 0x0000, 0x00ff, 0x0000, /*R19*/
++ 0x00c8, 0x00c8, 0x00c8, 0x00c8, /*R23*/
++ 0x00c8, 0x00c8, 0x00c8, 0x00c8, /*R27*/
++ 0x01c8, 0x0040, 0x0000, 0x0000, /*R31(0x1F)*/
++ 0x0000, 0x0000, 0x0031, 0x000b, /*R35*/
++ 0x0039, 0x0000, 0x0010, 0x0032, /*R39*/
++ 0x0054, 0x0076, 0x0098, 0x0000, /*R43(0x2B)*/
++ 0x0000, 0x0000, 0x0000, 0x0000, /*R47*/
++ //0x0000, 0x0000, 0x005e, 0x003e, /*R51(0x33)*/
++ 0x0000, 0x0000, 0x0002, 0x0000, /*R51(0x33)*/
++ 0x0000, 0x0000 /*R53*/
++};
++
++/*
++ * read wm8581 register cache
++ */
++static inline unsigned int wm8581_read_reg_cache(struct snd_soc_codec *codec,
++ unsigned int reg)
++{
++ u16 *cache = codec->reg_cache;
++ BUG_ON(reg > ARRAY_SIZE(wm8581_reg));
++ return cache[reg];
++}
++
++/*
++ * write wm8581 register cache
++ */
++static inline void wm8581_write_reg_cache(struct snd_soc_codec *codec,
++ unsigned int reg, unsigned int value)
++{
++ u16 *cache = codec->reg_cache;
++
++ cache[reg] = value;
++}
++
++
++#if 0
++static void print_reg(unsigned int reg, unsigned int val)
++{
++ switch (reg) {
++ case 0x00:
++ printk("PLLA1 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x01:
++ printk("PLLA2 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x02:
++ printk("PLLA3 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x03:
++ printk("PLLA4 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x04:
++ printk("PLLB1 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x05:
++ printk("PLLB2 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x06:
++ printk("PLLB3 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x07:
++ printk("PLLB4 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x08:
++ printk("CLKSEL reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x09:
++ printk("PAIF1 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x0A:
++ printk("PAIF2 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x0B:
++ printk("SAIF1 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x0C:
++ printk("PAIF3 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x0D:
++ printk("PAIF4 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x0E:
++ printk("SAIF2 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x0F:
++ printk("DAC_CONTROL1 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x10:
++ printk("DAC_CONTROL2 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x11:
++ printk("DAC_CONTROL3 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x12:
++ printk("DAC_CONTROL4 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x13:
++ printk("DAC_CONTROL5 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x14:
++ printk("DIGITAL_ATTENUATION_DACL1 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x15:
++ printk("DIGITAL_ATTENUATION_DACR1 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x16:
++ printk("DIGITAL_ATTENUATION_DACL2 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x17:
++ printk("DIGITAL_ATTENUATION_DACR2 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x18:
++ printk("DIGITAL_ATTENUATION_DACL3 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x19:
++ printk("DIGITAL_ATTENUATION_DACR3 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x1C:
++ printk("MASTER_DIGITAL_ATTENUATION reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x1D:
++ printk("ADC_CONTROL1 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x1E:
++ printk("SPDTXCHAN0 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x1F:
++ printk("SPDTXCHAN1 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x20:
++ printk("SPDTXCHAN2 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x21:
++ printk("SPDTXCHAN3 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x22:
++ printk("SPDTXCHAN4 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x23:
++ printk("SPDTXCHAN5 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x24:
++ printk("SPDMODE reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x25:
++ printk("INTMASK reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x26:
++ printk("GPO1 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x27:
++ printk("GPO2 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x28:
++ printk("GPO3 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x29:
++ printk("GPO4 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x2A:
++ printk("GPO5 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x2B:
++ printk("INTSTAT reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x2C:
++ printk("SPDRXCHAN1 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x2D:
++ printk("SPDRXCHAN2 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x2E:
++ printk("SPDRXCHAN3 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x2F:
++ printk("SPDRXCHAN4 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x30:
++ printk("SPDRXCHAN5 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x31:
++ printk("SPDSTAT reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x32:
++ printk("PWRDN1 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x33:
++ printk("PWRDN2 reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x34:
++ printk("READBACK reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ case 0x35:
++ printk("RESET reg[0x%X], val[0x%X]\n", reg, val);
++ break;
++ }
++}
++#endif
++
++
++/*
++ * write to the WM8581 register space
++ */
++static int wm8581_write(struct snd_soc_codec *codec, unsigned int reg,
++ unsigned int value)
++{
++ u8 data[2];
++
++ BUG_ON(reg > ARRAY_SIZE(wm8581_reg));
++
++ /* Registers are 9 bits wide */
++ value &= 0x1ff;
++
++ switch (reg) {
++ case WM8581_RESET:
++ /* Uncached */
++ break;
++#if 0
++ default:
++ if (value == wm8581_read_reg_cache(codec, reg))
++ return 0;
++#endif
++ }
++
++ /* data is
++ * D15..D9 WM8581 register offset
++ * D8...D0 register data
++ */
++ data[0] = (reg << 1) | ((value >> 8) & 0x0001);
++ data[1] = value & 0x00ff;
++
++ wm8581_write_reg_cache(codec, reg, value);
++
++ //print_reg(reg, value);
++
++ if (codec->hw_write(codec->control_data, data, 2) == 2)
++ return 0;
++ else
++ return -EIO;
++}
++
++static inline unsigned int wm8581_read(struct snd_soc_codec *codec,
++ unsigned int reg)
++{
++ switch (reg) {
++ default:
++ return wm8581_read_reg_cache(codec, reg);
++ }
++}
++
++static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
++
++static int wm8581_out_vu(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++#if 0
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++ int reg = kcontrol->private_value & 0xff;
++ int reg2 = (kcontrol->private_value >> 24) & 0xff;
++ int ret;
++ u16 val;
++
++ /* Clear the register cache so we write without VU set */
++ wm8581_write_reg_cache(codec, reg, 0);
++ wm8581_write_reg_cache(codec, reg2, 0);
++
++ ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
++ if (ret < 0)
++ return ret;
++
++ /* Now write again with the volume update bit set */
++ val = wm8581_read_reg_cache(codec, reg);
++ wm8581_write(codec, reg, val | 0x0100);
++
++ val = wm8581_read_reg_cache(codec, reg2);
++ wm8581_write(codec, reg2, val | 0x0100);
++#else
++ struct soc_mixer_control *mc =
++ (struct soc_mixer_control *)kcontrol->private_value;
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++ unsigned int reg = mc->reg;
++ unsigned int reg2 = mc->rreg;
++ int ret;
++ unsigned short val;
++
++ /* Clear the register cache so we write without VU set */
++ wm8581_write_reg_cache(codec, reg, 0);
++ wm8581_write_reg_cache(codec, reg2, 0);
++
++ ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
++ if (ret < 0)
++ return ret;
++
++ /* Now write again with the volume update bit set */
++ val = wm8581_read_reg_cache(codec, reg);
++ wm8581_write(codec, reg, val | 0x0100);
++
++ val = wm8581_read_reg_cache(codec, reg2);
++ wm8581_write(codec, reg2, val | 0x0100);
++#endif
++
++ return 0;
++}
++
++#if 0
++#define SOC_WM8581_OUT_DOUBLE_R_TLV(xname, reg_left, reg_right, shift, max, invert, tlv_array) \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
++ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
++ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
++ .tlv.p = (tlv_array), \
++ .info = snd_soc_info_volsw_2r, \
++ .get = snd_soc_get_volsw_2r, .put = wm8581_out_vu, \
++ .private_value = (reg_left) | ((shift) << 8) | \
++ ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) }
++#else
++#define SOC_WM8581_OUT_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
++ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
++ SNDRV_CTL_ELEM_ACCESS_READWRITE,\
++ .tlv.p = (tlv_array), \
++ .info = snd_soc_info_volsw_2r, \
++ .get = snd_soc_get_volsw_2r, .put = wm8581_out_vu, \
++ .private_value = (unsigned long)&(struct soc_mixer_control) \
++ {.reg = reg_left, .rreg = reg_right, .shift = xshift, \
++ .max = xmax, .invert = xinvert} }
++#endif
++
++static const struct snd_kcontrol_new wm8581_snd_controls[] = {
++#if 1
++SOC_WM8581_OUT_DOUBLE_R_TLV("DAC1 Playback Volume",
++ WM8581_DIGITAL_ATTENUATION_DACL1,
++ WM8581_DIGITAL_ATTENUATION_DACR1,
++ 0, 0xff, 0, dac_tlv),
++SOC_WM8581_OUT_DOUBLE_R_TLV("DAC2 Playback Volume",
++ WM8581_DIGITAL_ATTENUATION_DACL2,
++ WM8581_DIGITAL_ATTENUATION_DACR2,
++ 0, 0xff, 0, dac_tlv),
++SOC_WM8581_OUT_DOUBLE_R_TLV("DAC3 Playback Volume",
++ WM8581_DIGITAL_ATTENUATION_DACL3,
++ WM8581_DIGITAL_ATTENUATION_DACR3,
++ 0, 0xff, 0, dac_tlv),
++SOC_WM8581_OUT_DOUBLE_R_TLV("DAC4 Playback Volume",
++ WM8581_DIGITAL_ATTENUATION_DACL4,
++ WM8581_DIGITAL_ATTENUATION_DACR4,
++ 0, 0xff, 0, dac_tlv),
++#else
++SOC_SINGLE_TLV("DAC Master Volume", WM8581_MASTER_DIGITAL_ATTENUATION, 0, 0xFF, 0, dac_tlv),
++
++SOC_DOUBLE_R_TLV("DAC1 Playback Volume", WM8581_DIGITAL_ATTENUATION_DACL1, WM8581_DIGITAL_ATTENUATION_DACR1, 0, 0xFF, 0, dac_tlv),
++SOC_DOUBLE_R_TLV("DAC2 Playback Volume", WM8581_DIGITAL_ATTENUATION_DACL2, WM8581_DIGITAL_ATTENUATION_DACR2, 0, 0xFF, 0, dac_tlv),
++SOC_DOUBLE_R_TLV("DAC3 Playback Volume", WM8581_DIGITAL_ATTENUATION_DACL3, WM8581_DIGITAL_ATTENUATION_DACR3, 0, 0xFF, 0, dac_tlv),
++SOC_DOUBLE_R_TLV("DAC4 Playback Volume", WM8581_DIGITAL_ATTENUATION_DACL4, WM8581_DIGITAL_ATTENUATION_DACR4, 0, 0xFF, 0, dac_tlv),
++#endif
++
++SOC_SINGLE("DAC1 Deemphasis Switch", WM8581_DAC_CONTROL3, 0, 1, 0),
++SOC_SINGLE("DAC2 Deemphasis Switch", WM8581_DAC_CONTROL3, 1, 1, 0),
++SOC_SINGLE("DAC3 Deemphasis Switch", WM8581_DAC_CONTROL3, 2, 1, 0),
++SOC_SINGLE("DAC4 Deemphasis Switch", WM8581_DAC_CONTROL3, 3, 1, 0),
++
++SOC_DOUBLE("DAC1 Invert Switch", WM8581_DAC_CONTROL4, 0, 1, 1, 0),
++SOC_DOUBLE("DAC2 Invert Switch", WM8581_DAC_CONTROL4, 2, 3, 1, 0),
++SOC_DOUBLE("DAC3 Invert Switch", WM8581_DAC_CONTROL4, 4, 5, 1, 0),
++SOC_DOUBLE("DAC4 Invert Switch", WM8581_DAC_CONTROL4, 6, 7, 1, 0),
++
++SOC_SINGLE("DAC ZC Switch", WM8581_DAC_CONTROL5, 5, 1, 0),
++SOC_SINGLE("DAC1 Switch", WM8581_DAC_CONTROL5, 0, 1, 0),
++SOC_SINGLE("DAC2 Switch", WM8581_DAC_CONTROL5, 1, 1, 0),
++SOC_SINGLE("DAC3 Switch", WM8581_DAC_CONTROL5, 2, 1, 0),
++SOC_SINGLE("DAC4 Switch", WM8581_DAC_CONTROL5, 3, 1, 0),
++
++SOC_DOUBLE("ADC Mute Switch", WM8581_ADC_CONTROL1, 0, 1, 1, 0),
++SOC_SINGLE("ADC High-Pass Filter Switch", WM8581_ADC_CONTROL1, 4, 1, 0),
++};
++
++/* Add non-DAPM controls */
++static int wm8581_add_controls(struct snd_soc_codec *codec)
++{
++ int err, i;
++
++ for (i = 0; i < ARRAY_SIZE(wm8581_snd_controls); i++) {
++ err = snd_ctl_add(codec->card,
++ snd_soc_cnew(&wm8581_snd_controls[i],
++ codec, NULL));
++ if (err < 0)
++ return err;
++ }
++ return 0;
++}
++static const struct snd_soc_dapm_widget wm8581_dapm_widgets[] = {
++SND_SOC_DAPM_DAC("DAC1", "Playback", WM8581_PWRDN1, 2, 1),
++SND_SOC_DAPM_DAC("DAC2", "Playback", WM8581_PWRDN1, 3, 1),
++SND_SOC_DAPM_DAC("DAC3", "Playback", WM8581_PWRDN1, 4, 1),
++SND_SOC_DAPM_DAC("DAC4", "Playback", WM8581_PWRDN1, 5, 1),
++
++SND_SOC_DAPM_OUTPUT("VOUT1L"),
++SND_SOC_DAPM_OUTPUT("VOUT1R"),
++SND_SOC_DAPM_OUTPUT("VOUT2L"),
++SND_SOC_DAPM_OUTPUT("VOUT2R"),
++SND_SOC_DAPM_OUTPUT("VOUT3L"),
++SND_SOC_DAPM_OUTPUT("VOUT3R"),
++SND_SOC_DAPM_OUTPUT("VOUT4L"),
++SND_SOC_DAPM_OUTPUT("VOUT4R"),
++
++SND_SOC_DAPM_ADC("ADC", "Capture", WM8581_PWRDN1, 1, 1),
++
++SND_SOC_DAPM_INPUT("AINL"),
++SND_SOC_DAPM_INPUT("AINR"),
++};
++
++static const struct snd_soc_dapm_route audio_map[] = {
++ { "VOUT1L", NULL, "DAC1" },
++ { "VOUT1R", NULL, "DAC1" },
++
++ { "VOUT2L", NULL, "DAC2" },
++ { "VOUT2R", NULL, "DAC2" },
++
++ { "VOUT3L", NULL, "DAC3" },
++ { "VOUT3R", NULL, "DAC3" },
++
++ { "VOUT4L", NULL, "DAC4" },
++ { "VOUT4R", NULL, "DAC4" },
++
++ { "ADC", NULL, "AINL" },
++ { "ADC", NULL, "AINR" },
++};
++
++static int wm8581_add_widgets(struct snd_soc_codec *codec)
++{
++ snd_soc_dapm_new_controls(codec, wm8581_dapm_widgets,
++ ARRAY_SIZE(wm8581_dapm_widgets));
++
++ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
++
++ snd_soc_dapm_new_widgets(codec);
++ return 0;
++}
++
++/* PLL divisors */
++struct _pll_div {
++ u32 prescale:1;
++ u32 postscale:1;
++ u32 freqmode:2;
++ u32 n:4;
++ u32 k:24;
++};
++
++/* The size in bits of the pll divide */
++#define FIXED_PLL_SIZE (1 << 22)
++
++/* PLL rate to output rate divisions */
++static struct {
++ unsigned int div;
++ unsigned int freqmode;
++ unsigned int postscale;
++} post_table[] = {
++ { 2, 0, 0 },
++ { 4, 0, 1 },
++ { 4, 1, 0 },
++ { 8, 1, 1 },
++ { 8, 2, 0 },
++ { 16, 2, 1 },
++ { 12, 3, 0 },
++ { 24, 3, 1 }
++};
++
++static int pll_factors(struct _pll_div *pll_div, unsigned int target,
++ unsigned int source)
++{
++ u64 Kpart;
++ unsigned int K, Ndiv, Nmod;
++ int i;
++
++ pr_debug("wm8581: PLL %dHz->%dHz\n", source, target);
++
++ /* Scale the output frequency up; the PLL should run in the
++ * region of 90-100MHz.
++ */
++ for (i = 0; i < ARRAY_SIZE(post_table); i++) {
++ if (target * post_table[i].div >= 90000000 &&
++ target * post_table[i].div <= 100000000) {
++ pll_div->freqmode = post_table[i].freqmode;
++ pll_div->postscale = post_table[i].postscale;
++ target *= post_table[i].div;
++ break;
++ }
++ }
++
++ if (i == ARRAY_SIZE(post_table)) {
++ printk(KERN_ERR "wm8581: Unable to scale output frequency "
++ "%u\n", target);
++ return -EINVAL;
++ }
++
++ Ndiv = target / source;
++
++ if (Ndiv < 5) {
++ source /= 2;
++ pll_div->prescale = 1;
++ Ndiv = target / source;
++ } else
++ pll_div->prescale = 0;
++
++ if ((Ndiv < 5) || (Ndiv > 13)) {
++ printk(KERN_ERR
++ "WM8581 N=%d outside supported range\n", Ndiv);
++ return -EINVAL;
++ }
++
++ pll_div->n = Ndiv;
++ Nmod = target % source;
++ Kpart = FIXED_PLL_SIZE * (long long)Nmod;
++
++ do_div(Kpart, source);
++
++ K = Kpart & 0xFFFFFFFF;
++
++ pll_div->k = K;
++
++ pr_debug("PLL %x.%x prescale %d freqmode %d postscale %d\n",
++ pll_div->n, pll_div->k, pll_div->prescale, pll_div->freqmode,
++ pll_div->postscale);
++
++ return 0;
++}
++
++static int wm8581_set_dai_pll(struct snd_soc_dai *codec_dai,
++ int pll_id, unsigned int freq_in, unsigned int freq_out)
++{
++ int offset;
++ struct snd_soc_codec *codec = codec_dai->codec;
++ struct wm8581_priv *wm8581 = codec->private_data;
++ struct pll_state *state;
++ struct _pll_div pll_div;
++ unsigned int reg;
++ unsigned int pwr_mask;
++ int ret;
++
++ /* GCC isn't able to work out the ifs below for initialising/using
++ * pll_div so suppress warnings.
++ */
++ memset(&pll_div, 0, sizeof(pll_div));
++
++ switch (pll_id) {
++ case WM8581_PLLA:
++ state = &wm8581->a;
++ offset = 0;
++ pwr_mask = WM8581_PWRDN2_PLLAPD;
++ break;
++ case WM8581_PLLB:
++ state = &wm8581->b;
++ offset = 4;
++ pwr_mask = WM8581_PWRDN2_PLLBPD;
++ break;
++ default:
++ return -ENODEV;
++ }
++
++ if (freq_in && freq_out) {
++ ret = pll_factors(&pll_div, freq_out, freq_in);
++ if (ret != 0)
++ return ret;
++ }
++
++ state->in = freq_in;
++ state->out = freq_out;
++
++ /* Always disable the PLL - it is not safe to leave it running
++ * while reprogramming it.
++ */
++ reg = wm8581_read(codec, WM8581_PWRDN2);
++ wm8581_write(codec, WM8581_PWRDN2, reg | pwr_mask);
++
++ if (!freq_in || !freq_out)
++ return 0;
++
++ wm8581_write(codec, WM8581_PLLA1 + offset, pll_div.k & 0x1ff);
++ wm8581_write(codec, WM8581_PLLA2 + offset, (pll_div.k >> 9) & 0xff);
++ wm8581_write(codec, WM8581_PLLA3 + offset,
++ (pll_div.k >> 18 & 0xf) | (pll_div.n << 4));
++
++ reg = wm8581_read(codec, WM8581_PLLA4 + offset);
++ reg &= ~0x3f;
++ reg |= pll_div.prescale | pll_div.postscale << 1 |
++ pll_div.freqmode << 4;
++
++ wm8581_write(codec, WM8581_PLLA4 + offset, reg);
++
++ /* All done, turn it on */
++ reg = wm8581_read(codec, WM8581_PWRDN2);
++ wm8581_write(codec, WM8581_PWRDN2, reg & ~pwr_mask);
++
++ return 0;
++}
++
++/*
++ * Set PCM DAI bit size and sample rate.
++ */
++static int wm8581_paif_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai_link *dai = rtd->dai;
++ struct snd_soc_device *socdev = rtd->socdev;
++ struct snd_soc_codec *codec = socdev->codec;
++ u16 paifb = wm8581_read(codec, WM8581_PAIF3 + dai->codec_dai->id);
++
++ paifb &= ~WM8581_AIF_LENGTH_MASK;
++ /* bit size */
++ switch (params_format(params)) {
++ case SNDRV_PCM_FORMAT_S16_LE:
++ break;
++ case SNDRV_PCM_FORMAT_S20_3LE:
++ paifb |= WM8581_AIF_LENGTH_20;
++ break;
++ case SNDRV_PCM_FORMAT_S24_LE:
++ paifb |= WM8581_AIF_LENGTH_24;
++ break;
++ case SNDRV_PCM_FORMAT_S32_LE:
++ paifb |= WM8581_AIF_LENGTH_24;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ wm8581_write(codec, WM8581_PAIF3 + dai->codec_dai->id, paifb);
++ return 0;
++}
++
++static int wm8581_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
++ unsigned int fmt)
++{
++ struct snd_soc_codec *codec = codec_dai->codec;
++ unsigned int aifa;
++ unsigned int aifb;
++ int can_invert_lrclk;
++
++ aifa = wm8581_read(codec, WM8581_PAIF1 + codec_dai->id);
++ aifb = wm8581_read(codec, WM8581_PAIF3 + codec_dai->id);
++
++ aifb &= ~(WM8581_AIF_FMT_MASK | WM8581_AIF_LRP | WM8581_AIF_BCP);
++
++ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
++ case SND_SOC_DAIFMT_CBS_CFS:
++ aifa &= ~WM8581_AIF_MS;
++ break;
++ case SND_SOC_DAIFMT_CBM_CFM:
++ aifa |= WM8581_AIF_MS;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
++ case SND_SOC_DAIFMT_I2S:
++ can_invert_lrclk = 1;
++ aifb |= WM8581_AIF_FMT_I2S;
++ break;
++ case SND_SOC_DAIFMT_RIGHT_J:
++ can_invert_lrclk = 1;
++ aifb |= WM8581_AIF_FMT_RIGHTJ;
++ break;
++ case SND_SOC_DAIFMT_LEFT_J:
++ can_invert_lrclk = 1;
++ aifb |= WM8581_AIF_FMT_LEFTJ;
++ break;
++ case SND_SOC_DAIFMT_DSP_A:
++ can_invert_lrclk = 0;
++ aifb |= WM8581_AIF_FMT_DSP;
++ break;
++ case SND_SOC_DAIFMT_DSP_B:
++ can_invert_lrclk = 0;
++ aifb |= WM8581_AIF_FMT_DSP;
++ aifb |= WM8581_AIF_LRP;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
++ case SND_SOC_DAIFMT_NB_NF:
++ break;
++
++ case SND_SOC_DAIFMT_IB_IF:
++ if (!can_invert_lrclk)
++ return -EINVAL;
++ aifb |= WM8581_AIF_BCP;
++ aifb |= WM8581_AIF_LRP;
++ break;
++
++ case SND_SOC_DAIFMT_IB_NF:
++ aifb |= WM8581_AIF_BCP;
++ break;
++
++ case SND_SOC_DAIFMT_NB_IF:
++ if (!can_invert_lrclk)
++ return -EINVAL;
++ aifb |= WM8581_AIF_LRP;
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ wm8581_write(codec, WM8581_PAIF1 + codec_dai->id, aifa);
++ wm8581_write(codec, WM8581_PAIF3 + codec_dai->id, aifb);
++
++ return 0;
++}
++
++static int wm8581_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
++ int div_id, int div)
++{
++ struct snd_soc_codec *codec = codec_dai->codec;
++ unsigned int reg;
++
++ switch (div_id) {
++ case WM8581_MCLK:
++ reg = wm8581_read(codec, WM8581_PLLB4);
++ reg &= ~WM8581_PLLB4_MCLKOUTSRC_MASK;
++
++ switch (div) {
++ case WM8581_CLKSRC_MCLK:
++ /* Input */
++ break;
++
++ case WM8581_CLKSRC_PLLA:
++ reg |= WM8581_PLLB4_MCLKOUTSRC_PLLA;
++ break;
++ case WM8581_CLKSRC_PLLB:
++ reg |= WM8581_PLLB4_MCLKOUTSRC_PLLB;
++ break;
++
++ case WM8581_CLKSRC_OSC:
++ reg |= WM8581_PLLB4_MCLKOUTSRC_OSC;
++ break;
++
++ default:
++ return -EINVAL;
++ }
++ wm8581_write(codec, WM8581_PLLB4, reg);
++ break;
++
++ case WM8581_DAC_CLKSEL:
++ reg = wm8581_read(codec, WM8581_CLKSEL);
++ reg &= ~WM8581_CLKSEL_DAC_CLKSEL_MASK;
++
++ switch (div) {
++ case WM8581_CLKSRC_MCLK:
++ break;
++
++ case WM8581_CLKSRC_PLLA:
++ reg |= WM8581_CLKSEL_DAC_CLKSEL_PLLA;
++ break;
++
++ case WM8581_CLKSRC_PLLB:
++ reg |= WM8581_CLKSEL_DAC_CLKSEL_PLLB;
++ break;
++
++ default:
++ return -EINVAL;
++ }
++ wm8581_write(codec, WM8581_CLKSEL, reg);
++ break;
++
++ case WM8581_CLKOUTSRC:
++ reg = wm8581_read(codec, WM8581_PLLB4);
++ reg &= ~WM8581_PLLB4_CLKOUTSRC_MASK;
++
++ switch (div) {
++ case WM8581_CLKSRC_NONE:
++ break;
++
++ case WM8581_CLKSRC_PLLA:
++ reg |= WM8581_PLLB4_CLKOUTSRC_PLLACLK;
++ break;
++
++ case WM8581_CLKSRC_PLLB:
++ reg |= WM8581_PLLB4_CLKOUTSRC_PLLBCLK;
++ break;
++
++ case WM8581_CLKSRC_OSC:
++ reg |= WM8581_PLLB4_CLKOUTSRC_OSCCLK;
++ break;
++
++ default:
++ return -EINVAL;
++ }
++ wm8581_write(codec, WM8581_PLLB4, reg);
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int wm8581_digital_mute(struct snd_soc_dai *codec_dai, int mute)
++{
++ struct snd_soc_codec *codec = codec_dai->codec;
++ unsigned int reg;
++
++ reg = wm8581_read(codec, WM8581_DAC_CONTROL5);
++
++ if (mute)
++ reg |= WM8581_DAC_CONTROL5_MUTEALL;
++ else
++ reg &= ~WM8581_DAC_CONTROL5_MUTEALL;
++
++ wm8581_write(codec, WM8581_DAC_CONTROL5, reg);
++
++ return 0;
++}
++
++static int wm8581_set_bias_level(struct snd_soc_codec *codec,
++ enum snd_soc_bias_level level)
++{
++ u16 reg;
++ switch (level) {
++ case SND_SOC_BIAS_ON:
++ case SND_SOC_BIAS_PREPARE:
++ case SND_SOC_BIAS_STANDBY:
++ break;
++ case SND_SOC_BIAS_OFF:
++ reg = wm8581_read(codec, WM8581_PWRDN1);
++ wm8581_write(codec, WM8581_PWRDN1, reg | WM8581_PWRDN1_PWDN);
++ break;
++ }
++ codec->bias_level = level;
++ return 0;
++}
++
++#define WM8581_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
++ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
++
++struct snd_soc_dai wm8581_dai[] = {
++ {
++ .name = "WM8581 PAIFRX",
++ .id = 0,
++ .playback = {
++ .stream_name = "Playback",
++ .channels_min = 1,
++ .channels_max = 8,
++ .rates = SNDRV_PCM_RATE_8000_192000,
++ .formats = WM8581_FORMATS,
++ },
++ .ops = {
++ .hw_params = wm8581_paif_hw_params,
++ },
++ .dai_ops = {
++ .set_fmt = wm8581_set_paif_dai_fmt,
++ .set_clkdiv = wm8581_set_dai_clkdiv,
++ .set_pll = wm8581_set_dai_pll,
++ .digital_mute = wm8581_digital_mute,
++ },
++ },
++ {
++ .name = "WM8581 PAIFTX",
++ .id = 1,
++ .capture = {
++ .stream_name = "Capture",
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = SNDRV_PCM_RATE_8000_192000,
++ .formats = WM8581_FORMATS,
++ },
++ .ops = {
++ .hw_params = wm8581_paif_hw_params,
++ },
++ .dai_ops = {
++ .set_fmt = wm8581_set_paif_dai_fmt,
++ .set_clkdiv = wm8581_set_dai_clkdiv,
++ .set_pll = wm8581_set_dai_pll,
++ },
++ },
++};
++EXPORT_SYMBOL_GPL(wm8581_dai);
++
++/*
++ * initialise the WM8581 driver
++ * register the mixer and dsp interfaces with the kernel
++ */
++static int wm8581_init(struct snd_soc_device *socdev)
++{
++ struct snd_soc_codec *codec = socdev->codec;
++ int ret = 0;
++
++ codec->name = "WM8581";
++ codec->owner = THIS_MODULE;
++ codec->read = wm8581_read_reg_cache;
++ codec->write = wm8581_write;
++ codec->set_bias_level = wm8581_set_bias_level;
++ codec->dai = wm8581_dai;
++ codec->num_dai = ARRAY_SIZE(wm8581_dai);
++ codec->reg_cache_size = ARRAY_SIZE(wm8581_reg);
++ codec->reg_cache = kmemdup(wm8581_reg, sizeof(wm8581_reg),
++ GFP_KERNEL);
++
++ if (codec->reg_cache == NULL)
++ return -ENOMEM;
++
++ /* Get the codec into a known state */
++ wm8581_write(codec, WM8581_RESET, 0);
++
++ /* Power up and get individual control of the DACs */
++ wm8581_write(codec, WM8581_PWRDN1, wm8581_read(codec, WM8581_PWRDN1) &
++ ~(WM8581_PWRDN1_PWDN | WM8581_PWRDN1_ALLDACPD));
++
++ /* Make VMID high impedence */
++ wm8581_write(codec, WM8581_ADC_CONTROL1,
++ wm8581_read(codec, WM8581_ADC_CONTROL1) & ~0x100);
++
++ /* register pcms */
++ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1,
++ SNDRV_DEFAULT_STR1);
++ if (ret < 0) {
++ printk(KERN_ERR "wm8581: failed to create pcms\n");
++ goto pcm_err;
++ }
++
++ wm8581_add_controls(codec);
++ wm8581_add_widgets(codec);
++
++ ret = snd_soc_register_card(socdev);
++ if (ret < 0) {
++ printk(KERN_ERR "wm8581: failed to register card\n");
++ goto card_err;
++ }
++
++ {
++ int i = 0;
++ for (i = 0; i < WM8581_RESET; i++) {
++ wm8581_write(codec, i, wm8581_reg[i]);
++ }
++ }
++ return ret;
++
++card_err:
++ snd_soc_free_pcms(socdev);
++ snd_soc_dapm_free(socdev);
++pcm_err:
++ kfree(codec->reg_cache);
++ return ret;
++}
++
++/* If the i2c layer weren't so broken, we could pass this kind of data
++ around */
++static struct snd_soc_device *wm8581_socdev;
++
++#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
++
++static int wm8581_i2c_probe(struct i2c_client *i2c,
++ const struct i2c_device_id *id)
++{
++ struct snd_soc_device *socdev = wm8581_socdev;
++ struct snd_soc_codec *codec = socdev->codec;
++ int ret;
++
++ i2c_set_clientdata(i2c, codec);
++ codec->control_data = i2c;
++
++ ret = wm8581_init(socdev);
++ if (ret < 0)
++ pr_err("failed to initialise WM8581\n");
++
++ return ret;
++}
++
++static int wm8581_i2c_remove(struct i2c_client *client)
++{
++ struct snd_soc_codec *codec = i2c_get_clientdata(client);
++ kfree(codec->reg_cache);
++ return 0;
++}
++
++static const struct i2c_device_id wm8581_i2c_id[] = {
++ { "wm8581", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, wm8581_i2c_id);
++
++static struct i2c_driver wm8581_i2c_driver = {
++ .driver = {
++ .name = "WM8581 I2C Codec",
++ .owner = THIS_MODULE,
++ },
++ .probe = wm8581_i2c_probe,
++ .remove = wm8581_i2c_remove,
++ .id_table = wm8581_i2c_id,
++};
++
++static int wm8581_add_i2c_device(struct platform_device *pdev,
++ const struct wm8581_setup_data *setup)
++{
++ struct i2c_board_info info;
++ struct i2c_adapter *adapter;
++ struct i2c_client *client;
++ int ret;
++
++ ret = i2c_add_driver(&wm8581_i2c_driver);
++ if (ret != 0) {
++ dev_err(&pdev->dev, "can't add i2c driver\n");
++ return ret;
++ }
++
++ memset(&info, 0, sizeof(struct i2c_board_info));
++ info.addr = setup->i2c_address;
++ strlcpy(info.type, "wm8581", I2C_NAME_SIZE);
++
++ adapter = i2c_get_adapter(setup->i2c_bus);
++ if (!adapter) {
++ dev_err(&pdev->dev, "can't get i2c adapter %d\n",
++ setup->i2c_bus);
++ goto err_driver;
++ }
++
++ client = i2c_new_device(adapter, &info);
++ i2c_put_adapter(adapter);
++ if (!client) {
++ dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
++ (unsigned int)info.addr);
++ goto err_driver;
++ }
++
++ return 0;
++
++err_driver:
++ i2c_del_driver(&wm8581_i2c_driver);
++ return -ENODEV;
++}
++#endif
++
++static int wm8581_probe(struct platform_device *pdev)
++{
++ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
++ struct wm8581_setup_data *setup;
++ struct snd_soc_codec *codec;
++ struct wm8581_priv *wm8581;
++ int ret = 0;
++
++ pr_info("WM8581 Audio Codec %s\n", WM8581_VERSION);
++
++ setup = socdev->codec_data;
++ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
++ if (codec == NULL)
++ return -ENOMEM;
++
++ wm8581 = kzalloc(sizeof(struct wm8581_priv), GFP_KERNEL);
++ if (wm8581 == NULL) {
++ kfree(codec);
++ return -ENOMEM;
++ }
++
++ codec->private_data = wm8581;
++ socdev->codec = codec;
++ mutex_init(&codec->mutex);
++ INIT_LIST_HEAD(&codec->dapm_widgets);
++ INIT_LIST_HEAD(&codec->dapm_paths);
++ wm8581_socdev = socdev;
++
++#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
++ if (setup->i2c_address) {
++#if 0
++ normal_i2c[0] = setup->i2c_address;
++ codec->hw_write = (hw_write_t)i2c_master_send;
++ ret = i2c_add_driver(&wm8581_i2c_driver);
++#else
++ printk("\n wm8581 i2c_address [0x%X]\n", setup->i2c_address);
++ codec->hw_write = (hw_write_t)i2c_master_send;
++ ret = wm8581_add_i2c_device(pdev, setup);
++#endif
++ if (ret != 0)
++ printk(KERN_ERR "can't add i2c driver");
++ }
++#else
++ /* Add other interfaces here */
++#endif
++ return ret;
++}
++
++/* power down chip */
++static int wm8581_remove(struct platform_device *pdev)
++{
++ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
++ struct snd_soc_codec *codec = socdev->codec;
++
++ if (codec->control_data)
++ wm8581_set_bias_level(codec, SND_SOC_BIAS_OFF);
++ snd_soc_free_pcms(socdev);
++ snd_soc_dapm_free(socdev);
++#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
++ i2c_unregister_device(codec->control_data);
++ i2c_del_driver(&wm8581_i2c_driver);
++#endif
++ kfree(codec->private_data);
++ kfree(codec);
++
++ return 0;
++}
++
++struct snd_soc_codec_device soc_codec_dev_wm8581 = {
++ .probe = wm8581_probe,
++ .remove = wm8581_remove,
++};
++EXPORT_SYMBOL_GPL(soc_codec_dev_wm8581);
++
++MODULE_DESCRIPTION("ASoC WM8581 driver");
++MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
++MODULE_LICENSE("GPL");
+diff --git a/sound/soc/codecs/wm8581.h b/sound/soc/codecs/wm8581.h
+new file mode 100644
+index 0000000..2792e0a
+--- /dev/null
++++ b/sound/soc/codecs/wm8581.h
+@@ -0,0 +1,43 @@
++/*
++ * wm8581.h -- audio driver for WM8581
++ *
++ * Copyright 2008 Wolfson Microelectronics PLC.
++ * Copyright (C) 2009 Telechips
++ *
++ * 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 _WM8581_H
++#define _WM8581_H
++
++#define WM8581_PLLA 1
++#define WM8581_PLLB 2
++
++#define WM8581_MCLK 1
++#define WM8581_DAC_CLKSEL 2
++#define WM8581_CLKOUTSRC 3
++
++#define WM8581_CLKSRC_MCLK 1
++#define WM8581_CLKSRC_PLLA 2
++#define WM8581_CLKSRC_PLLB 3
++#define WM8581_CLKSRC_OSC 4
++#define WM8581_CLKSRC_NONE 5
++
++struct wm8581_setup_data {
++ int spi;
++ int i2c_bus;
++ unsigned short i2c_address;
++};
++
++#define WM8581_DAI_PAIFRX 0
++#define WM8581_DAI_PAIFTX 1
++
++extern struct snd_soc_dai wm8581_dai[];
++extern struct snd_soc_codec_device soc_codec_dev_wm8581;
++
++#endif
++
+diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
+index 7f8a7e3..912d3d5 100644
+--- a/sound/soc/codecs/wm8731.c
++++ b/sound/soc/codecs/wm8731.c
+@@ -1,15 +1,29 @@
+ /*
+- * wm8731.c -- WM8731 ALSA SoC Audio driver
+- *
+- * Copyright 2005 Openedhand Ltd.
++ * linux/sound/soc/codecs/wm8731.c
+ *
++ * Based on: wm8753.c by Liam Girdwood
+ * Author: Richard Purdie <richard@openedhand.com>
++ * Rewritten by: <linux@telechips.com>
++ * Created: June 10, 2008
++ * Description: WM8731 ALSA SoC Audio driver
+ *
+- * Based on wm8753.c by Liam Girdwood
++ * Copyright 2005 Openedhand Ltd.
++ * Copyright (C) 2008-2009 Telechips
+ *
+ * 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.
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ #include <linux/module.h>
+@@ -27,7 +41,9 @@
+ #include <sound/soc-dapm.h>
+ #include <sound/initval.h>
+
++
+ #include "wm8731.h"
++#include "../tcc/tcc-pcm.h"
+
+ #define WM8731_VERSION "0.13"
+
+@@ -44,11 +60,19 @@ struct wm8731_priv {
+ * using 2 wire for device control, so we cache them instead.
+ * There is no point in caching the reset register
+ */
++#if 0
++static const u16 wm8731_reg[WM8731_CACHEREGNUM] = {
++ 0x0097, 0x0097, 0x0064, 0x0064,
++ 0x0090, 0x0008, 0x0061, 0x000a,
++ 0x0000, 0x0000
++};
++#else
+ static const u16 wm8731_reg[WM8731_CACHEREGNUM] = {
+- 0x0097, 0x0097, 0x0079, 0x0079,
+- 0x000a, 0x0008, 0x009f, 0x000a,
++ 0x0017, 0x0017, 0x0064, 0x0064,
++ 0x0090, 0x0008, 0x009f, 0x000a,
+ 0x0000, 0x0000
+ };
++#endif
+
+ /*
+ * read wm8731 register cache
+@@ -76,6 +100,40 @@ static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec,
+ cache[reg] = value;
+ }
+
++#ifdef _WM8731_REG_DEBUG_
++static char *get_wm8731_reg_name(unsigned int i)
++{
++ switch (i) {
++ case 0xF:
++ return "@ Reset Register ";
++ case 0x0:
++ return "@ Left Line In ";
++ case 0x1:
++ return "@ Right Line In ";
++ case 0x2:
++ return "@ Left Headphone Out ";
++ case 0x3:
++ return "@ Right Headphone Out ";
++ case 0x4:
++ return "@ Analogue Audio Path Control ";
++ case 0x5:
++ return "@ Digital Audio Path Control ";
++ case 0x6:
++ return "@ Power Down Control ";
++ case 0x7:
++ return "@ Digital Audio Interface Format";
++ case 0x8:
++ return "@ Sampling Control ";
++ case 0x9:
++ return "@ Active Control ";
++ default:
++ return "@ Unknown reg ";
++ break;
++ }
++ return NULL;
++}
++#endif
++
+ /*
+ * write to the WM8731 register space
+ */
+@@ -91,11 +149,24 @@ static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg,
+ data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+ data[1] = value & 0x00ff;
+
++#if 0
++ if ((reg == WM8731_PWR) && tcc_alsa_info.flag) {
++ data[1] &= ~(0x6F);
++ }
++#endif
++
++#ifdef _WM8731_REG_DEBUG_
++ printk(" ***** write reg <%s> data[%X:0x%X]\n",
++ get_wm8731_reg_name(data[0] >> 1), (data[0] & ~0x1), data[1]);
++#endif
++
++ //wm8731_write_reg_cache(codec, reg, value);
+ wm8731_write_reg_cache(codec, reg, value);
+- if (codec->hw_write(codec->control_data, data, 2) == 2)
++ if (codec->hw_write(codec->control_data, data, 2) == 2) {
+ return 0;
+- else
+- return -EIO;
++ }
++
++ return -EIO;
+ }
+
+ #define wm8731_reset(c) wm8731_write(c, WM8731_RESET, 0)
+@@ -269,13 +340,15 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+- struct wm8731_priv *wm8731 = codec->private_data;
+ u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3;
++#if 0
++ struct wm8731_priv *wm8731 = codec->private_data;
+ int i = get_coeff(wm8731->sysclk, params_rate(params));
+ u16 srate = (coeff_div[i].sr << 2) |
+ (coeff_div[i].bosr << 1) | coeff_div[i].usb;
+
+ wm8731_write(codec, WM8731_SRATE, srate);
++#endif
+
+ /* bit size */
+ switch (params_format(params)) {
+@@ -507,6 +580,7 @@ static int wm8731_init(struct snd_soc_device *socdev)
+ {
+ struct snd_soc_codec *codec = socdev->codec;
+ int reg, ret = 0;
++ int i = 0;
+
+ codec->name = "WM8731";
+ codec->owner = THIS_MODULE;
+@@ -529,18 +603,11 @@ static int wm8731_init(struct snd_soc_device *socdev)
+ goto pcm_err;
+ }
+
+- /* power on device */
+- wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+-
+- /* set the update bits */
+- reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
+- wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100);
+- reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V);
+- wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100);
+- reg = wm8731_read_reg_cache(codec, WM8731_LINVOL);
+- wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100);
+- reg = wm8731_read_reg_cache(codec, WM8731_RINVOL);
+- wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100);
++ wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
++ for (i = 0; i <= WM8731_ACTIVE; i++) {
++ reg = wm8731_read_reg_cache(codec, i);
++ wm8731_write(codec, i, reg & ~0x0100);
++ }
+
+ wm8731_add_controls(codec);
+ wm8731_add_widgets(codec);
+@@ -571,6 +638,35 @@ static struct snd_soc_device *wm8731_socdev;
+ * high = 0x1b
+ */
+
++#ifdef CONFIG_TCC_I2C_WM8731
++extern struct i2c_client *wm8731_i2c_client;
++static int wm8731_codec_probe(void)
++{
++ struct snd_soc_device *socdev = wm8731_socdev;
++ //struct wm8731_setup_data *setup = socdev->codec_data;
++ struct snd_soc_codec *codec = socdev->codec;
++ //struct i2c_client *i2c;
++ int ret;
++
++ if (!wm8731_i2c_client) {
++ printk("wm8731_i2c_client is NULL !!! \n");
++ return -1;
++ }
++ i2c_set_clientdata(wm8731_i2c_client, codec);
++ codec->control_data = wm8731_i2c_client;
++
++ ret = wm8731_init(socdev);
++ if (ret < 0) {
++ printk("failed to initialise WM8731\n");
++ goto err;
++ }
++ return ret;
++
++err:
++ kfree(codec);
++ return ret;
++}
++#else
+ static int wm8731_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+ {
+@@ -651,6 +747,7 @@ err_driver:
+ return -ENODEV;
+ }
+ #endif
++#endif
+
+ #if defined(CONFIG_SPI_MASTER)
+ static int __devinit wm8731_spi_probe(struct spi_device *spi)
+@@ -740,8 +837,15 @@ static int wm8731_probe(struct platform_device *pdev)
+
+ #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ if (setup->i2c_address) {
++ printk("\n wm8731 i2c_address [0x%X]\n", setup->i2c_address);
+ codec->hw_write = (hw_write_t)i2c_master_send;
++#ifdef CONFIG_TCC_I2C_WM8731
++ ret = wm8731_codec_probe();
++ if (ret != 0)
++ printk(KERN_ERR "can't add i2c driver");
++#else
+ ret = wm8731_add_i2c_device(pdev, setup);
++#endif
+ }
+ #endif
+ #if defined(CONFIG_SPI_MASTER)
+@@ -765,18 +869,26 @@ static int wm8731_remove(struct platform_device *pdev)
+ {
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->codec;
++ struct wm8731_setup_data *setup;
+
+ if (codec->control_data)
+ wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
++ setup = socdev->codec_data;
++
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+ #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+- i2c_unregister_device(codec->control_data);
++ /* i2c_unregister_device(codec->control_data); */
++#ifdef CONFIG_TCC_I2C_WM8731
++#else
+ i2c_del_driver(&wm8731_i2c_driver);
+ #endif
++
++#endif
+ #if defined(CONFIG_SPI_MASTER)
+- spi_unregister_driver(&wm8731_spi_driver);
++ if (setup->spi)
++ spi_unregister_driver(&wm8731_spi_driver);
+ #endif
+ kfree(codec->private_data);
+ kfree(codec);
+@@ -795,3 +907,4 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
+ MODULE_DESCRIPTION("ASoC WM8731 driver");
+ MODULE_AUTHOR("Richard Purdie");
+ MODULE_LICENSE("GPL");
++
+diff --git a/sound/soc/codecs/wm8987.c b/sound/soc/codecs/wm8987.c
+new file mode 100755
+index 0000000..d1db8fd
+--- /dev/null
++++ b/sound/soc/codecs/wm8987.c
+@@ -0,0 +1,1209 @@
++/*
++ * wm8987.c -- WM8987 ALSA SoC audio driver
++ *
++ * Copyright 2005 Openedhand Ltd.
++ *
++ * Author: Richard Purdie <richard@openedhand.com>
++ *
++ * Based on WM8753.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/i2c.h>
++#include <linux/platform_device.h>
++#include <linux/spi/spi.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/soc-dapm.h>
++#include <sound/initval.h>
++#include <hhtech_gpio.h>
++#include <mach/gpio.h>
++
++#include "wm8987.h"
++
++#define WM8987_VERSION "0.12"
++
++static struct snd_soc_codec *p_codec = NULL;
++static struct delayed_work wm8987_unmute_work;
++static struct delayed_work wm8987_bias_standby_work;
++static unsigned char wm8987_first_bias_on = 0;
++static unsigned char wm8987_bias_on = 0;
++unsigned char wm8987_is_playing = 0;
++
++/* codec private data */
++struct wm8987_priv {
++ unsigned int sysclk;
++};
++
++/*
++ * wm8987 register cache
++ * We can't read the WM8987 register space when we
++ * are using 2 wire for device control, so we cache them instead.
++ */
++static const u16 wm8987_reg[] = {
++ 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */
++ 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */
++ 0x0000, 0x0000, 0x00c7, 0x00c7, /* 8 */
++ 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */
++ 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */
++ 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */
++ 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */
++ 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */
++ 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */
++ 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */
++ 0x0079, 0x0079, 0x0079, /* 40 */
++};
++
++/*
++ * read wm8987 register cache
++ */
++static inline unsigned int wm8987_read_reg_cache(struct snd_soc_codec *codec,
++ unsigned int reg)
++{
++ u16 *cache = codec->reg_cache;
++ if (reg > WM8987_CACHE_REGNUM)
++ return -1;
++ return cache[reg];
++}
++
++/*
++ * write wm8987 register cache
++ */
++static inline void wm8987_write_reg_cache(struct snd_soc_codec *codec,
++ unsigned int reg, unsigned int value)
++{
++ u16 *cache = codec->reg_cache;
++ if (reg > WM8987_CACHE_REGNUM)
++ return;
++ cache[reg] = value;
++}
++
++static int wm8987_write(struct snd_soc_codec *codec, unsigned int reg,
++ unsigned int value)
++{
++ u8 data[2];
++
++ wm8987_write_reg_cache(codec, reg, value);
++
++ /* don't enable DAC Left, DAC Right, LOUT2 Output Buffer and ROUT2 Output Buffer of
++ WM8987 (bit8, bit7, bit4 and bit3 of R26) separately, and don't disable DAC Left
++ and DAC Right when wm8987 is bias on, this can minimum the pop and click noise */
++ if(reg == 0x1a) {
++ switch(value) {
++ case 0x000:
++ /* when disable them all, if wm8987 is bias on, do nothing */
++ if(wm8987_bias_on)
++ return 0;
++ else
++ break;
++ case 0x1f8:
++ /* if wm8987 is bias off, enable them together. or
++ * do nothing */
++ if(wm8987_bias_on)
++ return 0;
++ else
++ break;
++ default:
++ // don't enable them separately
++ return 0;
++ }
++ }
++
++ /* data is
++ * D15..D9 WM8987 register offset
++ * D8...D0 register data
++ */
++ data[0] = (reg << 1) | ((value >> 8) & 0x0001);
++ data[1] = value & 0x00ff;
++
++ if (codec->hw_write(codec->control_data, data, 2) == 2)
++ return 0;
++ else
++ return -EIO;
++}
++
++#define wm8987_reset(c) wm8987_write(c, WM8987_RESET, 0)
++
++/*
++ * WM8987 Controls
++ */
++static const char *wm8987_bass[] = {"Linear Control", "Adaptive Boost"};
++static const char *wm8987_bass_filter[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };
++static const char *wm8987_treble[] = {"8kHz", "4kHz"};
++static const char *wm8987_3d_lc[] = {"200Hz", "500Hz"};
++static const char *wm8987_3d_uc[] = {"2.2kHz", "1.5kHz"};
++static const char *wm8987_3d_func[] = {"Capture", "Playback"};
++static const char *wm8987_alc_func[] = {"Off", "Right", "Left", "Stereo"};
++static const char *wm8987_ng_type[] = {"Constant PGA Gain",
++ "Mute ADC Output"};
++static const char *wm8987_line_mux[] = {"Line 1", "Line 2", "Line 3", "PGA",
++ "Differential"};
++static const char *wm8987_pga_sel[] = {"Line 1", "Line 2", "Line 3",
++ "Differential"};
++static const char *wm8987_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut",
++ "ROUT1"};
++static const char *wm8987_diff_sel[] = {"Line 1", "Line 2"};
++static const char *wm8987_adcpol[] = {"Normal", "L Invert", "R Invert",
++ "L + R Invert"};
++static const char *wm8987_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
++static const char *wm8987_mono_mux[] = {"Stereo", "Mono (Left)",
++ "Mono (Right)", "Digital Mono"};
++
++static const struct soc_enum wm8987_enum[] = {
++SOC_ENUM_SINGLE(WM8987_BASS, 7, 2, wm8987_bass),
++SOC_ENUM_SINGLE(WM8987_BASS, 6, 2, wm8987_bass_filter),
++SOC_ENUM_SINGLE(WM8987_TREBLE, 6, 2, wm8987_treble),
++SOC_ENUM_SINGLE(WM8987_3D, 5, 2, wm8987_3d_lc),
++SOC_ENUM_SINGLE(WM8987_3D, 6, 2, wm8987_3d_uc),
++SOC_ENUM_SINGLE(WM8987_3D, 7, 2, wm8987_3d_func),
++SOC_ENUM_SINGLE(WM8987_ALC1, 7, 4, wm8987_alc_func),
++SOC_ENUM_SINGLE(WM8987_NGATE, 1, 2, wm8987_ng_type),
++SOC_ENUM_SINGLE(WM8987_LOUTM1, 0, 5, wm8987_line_mux),
++SOC_ENUM_SINGLE(WM8987_ROUTM1, 0, 5, wm8987_line_mux),
++SOC_ENUM_SINGLE(WM8987_LADCIN, 6, 4, wm8987_pga_sel), /* 10 */
++SOC_ENUM_SINGLE(WM8987_RADCIN, 6, 4, wm8987_pga_sel),
++SOC_ENUM_SINGLE(WM8987_ADCTL2, 7, 4, wm8987_out3),
++SOC_ENUM_SINGLE(WM8987_ADCIN, 8, 2, wm8987_diff_sel),
++SOC_ENUM_SINGLE(WM8987_ADCDAC, 5, 4, wm8987_adcpol),
++SOC_ENUM_SINGLE(WM8987_ADCDAC, 1, 4, wm8987_deemph),
++SOC_ENUM_SINGLE(WM8987_ADCIN, 6, 4, wm8987_mono_mux), /* 16 */
++
++};
++
++static const struct snd_kcontrol_new wm8987_snd_controls[] = {
++
++SOC_DOUBLE_R("Capture Volume", WM8987_LINVOL, WM8987_RINVOL, 0, 63, 0),
++SOC_DOUBLE_R("Capture ZC Switch", WM8987_LINVOL, WM8987_RINVOL, 6, 1, 0),
++SOC_DOUBLE_R("Capture Switch", WM8987_LINVOL, WM8987_RINVOL, 7, 1, 1),
++
++SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8987_LOUT1V,
++ WM8987_ROUT1V, 7, 1, 0),
++SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8987_LOUT2V,
++ WM8987_ROUT2V, 7, 1, 0),
++
++SOC_ENUM("Playback De-emphasis", wm8987_enum[15]),
++
++SOC_ENUM("Capture Polarity", wm8987_enum[14]),
++SOC_SINGLE("Playback 6dB Attenuate", WM8987_ADCDAC, 7, 1, 0),
++SOC_SINGLE("Capture 6dB Attenuate", WM8987_ADCDAC, 8, 1, 0),
++
++SOC_DOUBLE_R("PCM Volume", WM8987_LDAC, WM8987_RDAC, 0, 255, 0),
++
++SOC_ENUM("Bass Boost", wm8987_enum[0]),
++SOC_ENUM("Bass Filter", wm8987_enum[1]),
++SOC_SINGLE("Bass Volume", WM8987_BASS, 0, 15, 1),
++
++SOC_SINGLE("Treble Volume", WM8987_TREBLE, 0, 15, 1),
++SOC_ENUM("Treble Cut-off", wm8987_enum[2]),
++
++SOC_SINGLE("3D Switch", WM8987_3D, 0, 1, 0),
++SOC_SINGLE("3D Volume", WM8987_3D, 1, 15, 0),
++SOC_ENUM("3D Lower Cut-off", wm8987_enum[3]),
++SOC_ENUM("3D Upper Cut-off", wm8987_enum[4]),
++SOC_ENUM("3D Mode", wm8987_enum[5]),
++
++SOC_SINGLE("ALC Capture Target Volume", WM8987_ALC1, 0, 7, 0),
++SOC_SINGLE("ALC Capture Max Volume", WM8987_ALC1, 4, 7, 0),
++SOC_ENUM("ALC Capture Function", wm8987_enum[6]),
++SOC_SINGLE("ALC Capture ZC Switch", WM8987_ALC2, 7, 1, 0),
++SOC_SINGLE("ALC Capture Hold Time", WM8987_ALC2, 0, 15, 0),
++SOC_SINGLE("ALC Capture Decay Time", WM8987_ALC3, 4, 15, 0),
++SOC_SINGLE("ALC Capture Attack Time", WM8987_ALC3, 0, 15, 0),
++SOC_SINGLE("ALC Capture NG Threshold", WM8987_NGATE, 3, 31, 0),
++SOC_ENUM("ALC Capture NG Type", wm8987_enum[4]),
++SOC_SINGLE("ALC Capture NG Switch", WM8987_NGATE, 0, 1, 0),
++
++SOC_SINGLE("Left ADC Capture Volume", WM8987_LADC, 0, 255, 0),
++SOC_SINGLE("Right ADC Capture Volume", WM8987_RADC, 0, 255, 0),
++
++SOC_SINGLE("ZC Timeout Switch", WM8987_ADCTL1, 0, 1, 0),
++SOC_SINGLE("Playback Invert Switch", WM8987_ADCTL1, 1, 1, 0),
++
++SOC_SINGLE("Right Speaker Playback Invert Switch", WM8987_ADCTL2, 4, 1, 0),
++
++/* Unimplemented */
++/* ADCDAC Bit 0 - ADCHPD */
++/* ADCDAC Bit 4 - HPOR */
++/* ADCTL1 Bit 2,3 - DATSEL */
++/* ADCTL1 Bit 4,5 - DMONOMIX */
++/* ADCTL1 Bit 6,7 - VSEL */
++/* ADCTL2 Bit 2 - LRCM */
++/* ADCTL2 Bit 3 - TRI */
++/* ADCTL3 Bit 5 - HPFLREN */
++/* ADCTL3 Bit 6 - VROI */
++/* ADCTL3 Bit 7,8 - ADCLRM */
++/* ADCIN Bit 4 - LDCM */
++/* ADCIN Bit 5 - RDCM */
++
++SOC_DOUBLE_R("Mic Boost", WM8987_LADCIN, WM8987_RADCIN, 4, 3, 0),
++
++SOC_DOUBLE_R("Bypass Left Playback Volume", WM8987_LOUTM1,
++ WM8987_LOUTM2, 4, 7, 1),
++SOC_DOUBLE_R("Bypass Right Playback Volume", WM8987_ROUTM1,
++ WM8987_ROUTM2, 4, 7, 1),
++SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8987_MOUTM1,
++ WM8987_MOUTM2, 4, 7, 1),
++
++SOC_SINGLE("Mono Playback ZC Switch", WM8987_MOUTV, 7, 1, 0),
++
++SOC_DOUBLE_R("Headphone Playback Volume", WM8987_LOUT1V, WM8987_ROUT1V,
++ 0, 127, 0),
++SOC_DOUBLE_R("Speaker Playback Volume", WM8987_LOUT2V, WM8987_ROUT2V,
++ 0, 127, 0),
++
++SOC_SINGLE("Mono Playback Volume", WM8987_MOUTV, 0, 127, 0),
++
++};
++
++/* add non dapm controls */
++static int wm8987_add_controls(struct snd_soc_codec *codec)
++{
++ int err, i;
++
++ for (i = 0; i < ARRAY_SIZE(wm8987_snd_controls); i++) {
++ err = snd_ctl_add(codec->card,
++ snd_soc_cnew(&wm8987_snd_controls[i],
++ codec, NULL));
++ if (err < 0)
++ return err;
++ }
++ return 0;
++}
++
++/*
++ * DAPM Controls
++ */
++
++/* Left Mixer */
++static const struct snd_kcontrol_new wm8987_left_mixer_controls[] = {
++SOC_DAPM_SINGLE("Playback Switch", WM8987_LOUTM1, 8, 1, 0),
++SOC_DAPM_SINGLE("Left Bypass Switch", WM8987_LOUTM1, 7, 1, 0),
++SOC_DAPM_SINGLE("Right Playback Switch", WM8987_LOUTM2, 8, 1, 0),
++SOC_DAPM_SINGLE("Right Bypass Switch", WM8987_LOUTM2, 7, 1, 0),
++};
++
++/* Right Mixer */
++static const struct snd_kcontrol_new wm8987_right_mixer_controls[] = {
++SOC_DAPM_SINGLE("Left Playback Switch", WM8987_ROUTM1, 8, 1, 0),
++SOC_DAPM_SINGLE("Left Bypass Switch", WM8987_ROUTM1, 7, 1, 0),
++SOC_DAPM_SINGLE("Playback Switch", WM8987_ROUTM2, 8, 1, 0),
++SOC_DAPM_SINGLE("Right Bypass Switch", WM8987_ROUTM2, 7, 1, 0),
++};
++
++/* Mono Mixer */
++static const struct snd_kcontrol_new wm8987_mono_mixer_controls[] = {
++SOC_DAPM_SINGLE("Left Playback Switch", WM8987_MOUTM1, 8, 1, 0),
++SOC_DAPM_SINGLE("Left Bypass Switch", WM8987_MOUTM1, 7, 1, 0),
++SOC_DAPM_SINGLE("Right Playback Switch", WM8987_MOUTM2, 8, 1, 0),
++SOC_DAPM_SINGLE("Right Bypass Switch", WM8987_MOUTM2, 7, 1, 0),
++};
++
++/* Left Line Mux */
++static const struct snd_kcontrol_new wm8987_left_line_controls =
++SOC_DAPM_ENUM("Route", wm8987_enum[8]);
++
++/* Right Line Mux */
++static const struct snd_kcontrol_new wm8987_right_line_controls =
++SOC_DAPM_ENUM("Route", wm8987_enum[9]);
++
++/* Left PGA Mux */
++static const struct snd_kcontrol_new wm8987_left_pga_controls =
++SOC_DAPM_ENUM("Route", wm8987_enum[10]);
++
++/* Right PGA Mux */
++static const struct snd_kcontrol_new wm8987_right_pga_controls =
++SOC_DAPM_ENUM("Route", wm8987_enum[11]);
++
++/* Out 3 Mux */
++static const struct snd_kcontrol_new wm8987_out3_controls =
++SOC_DAPM_ENUM("Route", wm8987_enum[12]);
++
++/* Differential Mux */
++static const struct snd_kcontrol_new wm8987_diffmux_controls =
++SOC_DAPM_ENUM("Route", wm8987_enum[13]);
++
++/* Mono ADC Mux */
++static const struct snd_kcontrol_new wm8987_monomux_controls =
++SOC_DAPM_ENUM("Route", wm8987_enum[16]);
++
++static const struct snd_soc_dapm_widget wm8987_dapm_widgets[] = {
++ SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
++ &wm8987_left_mixer_controls[0],
++ ARRAY_SIZE(wm8987_left_mixer_controls)),
++ SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
++ &wm8987_right_mixer_controls[0],
++ ARRAY_SIZE(wm8987_right_mixer_controls)),
++ SND_SOC_DAPM_MIXER("Mono Mixer", WM8987_PWR2, 2, 0,
++ &wm8987_mono_mixer_controls[0],
++ ARRAY_SIZE(wm8987_mono_mixer_controls)),
++
++ SND_SOC_DAPM_PGA("Right Out 2", WM8987_PWR2, 3, 0, NULL, 0),
++ SND_SOC_DAPM_PGA("Left Out 2", WM8987_PWR2, 4, 0, NULL, 0),
++ SND_SOC_DAPM_PGA("Right Out 1", WM8987_PWR2, 5, 0, NULL, 0),
++ SND_SOC_DAPM_PGA("Left Out 1", WM8987_PWR2, 6, 0, NULL, 0),
++ SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8987_PWR2, 7, 0),
++ SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8987_PWR2, 8, 0),
++
++ SND_SOC_DAPM_MICBIAS("Mic Bias", WM8987_PWR1, 1, 0),
++ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8987_PWR1, 2, 0),
++ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8987_PWR1, 3, 0),
++
++ SND_SOC_DAPM_MUX("Left PGA Mux", WM8987_PWR1, 5, 0,
++ &wm8987_left_pga_controls),
++ SND_SOC_DAPM_MUX("Right PGA Mux", WM8987_PWR1, 4, 0,
++ &wm8987_right_pga_controls),
++ SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
++ &wm8987_left_line_controls),
++ SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
++ &wm8987_right_line_controls),
++
++ SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8987_out3_controls),
++ SND_SOC_DAPM_PGA("Out 3", WM8987_PWR2, 1, 0, NULL, 0),
++ SND_SOC_DAPM_PGA("Mono Out 1", WM8987_PWR2, 2, 0, NULL, 0),
++
++ SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
++ &wm8987_diffmux_controls),
++ SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
++ &wm8987_monomux_controls),
++ SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
++ &wm8987_monomux_controls),
++
++ SND_SOC_DAPM_OUTPUT("LOUT1"),
++ SND_SOC_DAPM_OUTPUT("ROUT1"),
++ SND_SOC_DAPM_OUTPUT("LOUT2"),
++ SND_SOC_DAPM_OUTPUT("ROUT2"),
++ SND_SOC_DAPM_OUTPUT("MONO1"),
++ SND_SOC_DAPM_OUTPUT("OUT3"),
++ SND_SOC_DAPM_OUTPUT("VREF"),
++
++ SND_SOC_DAPM_INPUT("LINPUT1"),
++ SND_SOC_DAPM_INPUT("LINPUT2"),
++ SND_SOC_DAPM_INPUT("LINPUT3"),
++ SND_SOC_DAPM_INPUT("RINPUT1"),
++ SND_SOC_DAPM_INPUT("RINPUT2"),
++ SND_SOC_DAPM_INPUT("RINPUT3"),
++};
++
++static const struct snd_soc_dapm_route audio_map[] = {
++ /* left mixer */
++ {"Left Mixer", "Playback Switch", "Left DAC"},
++ {"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
++ {"Left Mixer", "Right Playback Switch", "Right DAC"},
++ {"Left Mixer", "Right Bypass Switch", "Right Line Mux"},
++
++ /* right mixer */
++ {"Right Mixer", "Left Playback Switch", "Left DAC"},
++ {"Right Mixer", "Left Bypass Switch", "Left Line Mux"},
++ {"Right Mixer", "Playback Switch", "Right DAC"},
++ {"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
++
++ /* left out 1 */
++ {"Left Out 1", NULL, "Left Mixer"},
++ {"LOUT1", NULL, "Left Out 1"},
++
++ /* left out 2 */
++ {"Left Out 2", NULL, "Left Mixer"},
++ {"LOUT2", NULL, "Left Out 2"},
++
++ /* right out 1 */
++ {"Right Out 1", NULL, "Right Mixer"},
++ {"ROUT1", NULL, "Right Out 1"},
++
++ /* right out 2 */
++ {"Right Out 2", NULL, "Right Mixer"},
++ {"ROUT2", NULL, "Right Out 2"},
++
++ /* mono mixer */
++ {"Mono Mixer", "Left Playback Switch", "Left DAC"},
++ {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"},
++ {"Mono Mixer", "Right Playback Switch", "Right DAC"},
++ {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"},
++
++ /* mono out */
++ {"Mono Out 1", NULL, "Mono Mixer"},
++ {"MONO1", NULL, "Mono Out 1"},
++
++ /* out 3 */
++ {"Out3 Mux", "VREF", "VREF"},
++ {"Out3 Mux", "ROUT1 + Vol", "ROUT1"},
++ {"Out3 Mux", "ROUT1", "Right Mixer"},
++ {"Out3 Mux", "MonoOut", "MONO1"},
++ {"Out 3", NULL, "Out3 Mux"},
++ {"OUT3", NULL, "Out 3"},
++
++ /* Left Line Mux */
++ {"Left Line Mux", "Line 1", "LINPUT1"},
++ {"Left Line Mux", "Line 2", "LINPUT2"},
++ {"Left Line Mux", "Line 3", "LINPUT3"},
++ {"Left Line Mux", "PGA", "Left PGA Mux"},
++ {"Left Line Mux", "Differential", "Differential Mux"},
++
++ /* Right Line Mux */
++ {"Right Line Mux", "Line 1", "RINPUT1"},
++ {"Right Line Mux", "Line 2", "RINPUT2"},
++ {"Right Line Mux", "Line 3", "RINPUT3"},
++ {"Right Line Mux", "PGA", "Right PGA Mux"},
++ {"Right Line Mux", "Differential", "Differential Mux"},
++
++ /* Left PGA Mux */
++ {"Left PGA Mux", "Line 1", "LINPUT1"},
++ {"Left PGA Mux", "Line 2", "LINPUT2"},
++ {"Left PGA Mux", "Line 3", "LINPUT3"},
++ {"Left PGA Mux", "Differential", "Differential Mux"},
++
++ /* Right PGA Mux */
++ {"Right PGA Mux", "Line 1", "RINPUT1"},
++ {"Right PGA Mux", "Line 2", "RINPUT2"},
++ {"Right PGA Mux", "Line 3", "RINPUT3"},
++ {"Right PGA Mux", "Differential", "Differential Mux"},
++
++ /* Differential Mux */
++ {"Differential Mux", "Line 1", "LINPUT1"},
++ {"Differential Mux", "Line 1", "RINPUT1"},
++ {"Differential Mux", "Line 2", "LINPUT2"},
++ {"Differential Mux", "Line 2", "RINPUT2"},
++
++ /* Left ADC Mux */
++ {"Left ADC Mux", "Stereo", "Left PGA Mux"},
++ {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
++ {"Left ADC Mux", "Digital Mono", "Left PGA Mux"},
++
++ /* Right ADC Mux */
++ {"Right ADC Mux", "Stereo", "Right PGA Mux"},
++ {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
++ {"Right ADC Mux", "Digital Mono", "Right PGA Mux"},
++
++ /* ADC */
++ {"Left ADC", NULL, "Left ADC Mux"},
++ {"Right ADC", NULL, "Right ADC Mux"},
++};
++
++static int wm8987_add_widgets(struct snd_soc_codec *codec)
++{
++ snd_soc_dapm_new_controls(codec, wm8987_dapm_widgets,
++ ARRAY_SIZE(wm8987_dapm_widgets));
++
++ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
++
++ snd_soc_dapm_new_widgets(codec);
++ return 0;
++}
++
++struct _coeff_div {
++ u32 mclk;
++ u32 rate;
++ u16 fs;
++ u8 sr:5;
++ u8 usb:1;
++};
++
++/* codec hifi mclk clock divider coefficients */
++static const struct _coeff_div coeff_div[] = {
++ /* 8k */
++ {12288000, 8000, 1536, 0x10, 0x0},
++ {11289600, 8000, 1408, 0x16, 0x0},
++ {18432000, 8000, 2304, 0x7, 0x0},
++ {16934400, 8000, 2112, 0x17, 0x0},
++ {12000000, 8000, 1500, 0x6, 0x1},
++
++ /* 11.025k */
++ {11289600, 11025, 1024, 0x18, 0x0},
++ {16934400, 11025, 1536, 0x19, 0x0},
++ {12000000, 11025, 1088, 0x19, 0x1},
++
++ /* 12k */
++ {12288000, 12000, 1024, 0x8, 0x0},
++ {18432000, 12000, 1536, 0x9, 0x0},
++ {12000000, 12000, 1000, 0x8, 0x1},
++
++ /* 16k */
++ {12288000, 16000, 768, 0xa, 0x0},
++ {18432000, 16000, 1152, 0xb, 0x0},
++ {12000000, 16000, 750, 0xa, 0x1},
++
++ /* 22.05k */
++ {11289600, 22050, 512, 0x1a, 0x0},
++ {16934400, 22050, 768, 0x1b, 0x0},
++ {12000000, 22050, 544, 0x1b, 0x1},
++
++ /* 24k */
++ {12288000, 24000, 512, 0x1c, 0x0},
++ {18432000, 24000, 768, 0x1d, 0x0},
++ {12000000, 24000, 500, 0x1c, 0x1},
++
++ /* 32k */
++ {12288000, 32000, 384, 0xc, 0x0},
++ {18432000, 32000, 576, 0xd, 0x0},
++ {12000000, 32000, 375, 0xa, 0x1},
++
++ /* 44.1k */
++ {11289600, 44100, 256, 0x10, 0x0},
++ {16934400, 44100, 384, 0x11, 0x0},
++ {12000000, 44100, 272, 0x11, 0x1},
++
++ /* 48k */
++ {12288000, 48000, 256, 0x0, 0x0},
++ {18432000, 48000, 384, 0x1, 0x0},
++ {12000000, 48000, 250, 0x0, 0x1},
++
++ /* 88.2k */
++ {11289600, 88200, 128, 0x1e, 0x0},
++ {16934400, 88200, 192, 0x1f, 0x0},
++ {12000000, 88200, 136, 0x1f, 0x1},
++
++ /* 96k */
++ {12288000, 96000, 128, 0xe, 0x0},
++ {18432000, 96000, 192, 0xf, 0x0},
++ {12000000, 96000, 125, 0xe, 0x1},
++};
++
++static inline int get_coeff(int mclk, int rate)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
++ if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
++ return i;
++ }
++
++ printk(KERN_ERR "wm8987: could not get coeff for mclk %d @ rate %d\n",
++ mclk, rate);
++ return -EINVAL;
++}
++
++static int wm8987_set_dai_sysclk(struct snd_soc_dai *codec_dai,
++ int clk_id, unsigned int freq, int dir)
++{
++ struct snd_soc_codec *codec = codec_dai->codec;
++ struct wm8987_priv *wm8987 = codec->private_data;
++
++ switch (freq) {
++ case 11289600:
++ case 12000000:
++ case 12288000:
++ case 16934400:
++ case 18432000:
++ wm8987->sysclk = freq;
++ return 0;
++ }
++ return -EINVAL;
++}
++
++static int wm8987_set_dai_fmt(struct snd_soc_dai *codec_dai,
++ unsigned int fmt)
++{
++ struct snd_soc_codec *codec = codec_dai->codec;
++ u16 iface = 0;
++
++ /* set master/slave audio interface */
++ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
++ case SND_SOC_DAIFMT_CBM_CFM:
++ iface = 0x0040;
++ break;
++ case SND_SOC_DAIFMT_CBS_CFS:
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ /* interface format */
++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
++ case SND_SOC_DAIFMT_I2S:
++ iface |= 0x0002;
++ break;
++ case SND_SOC_DAIFMT_RIGHT_J:
++ break;
++ case SND_SOC_DAIFMT_LEFT_J:
++ iface |= 0x0001;
++ break;
++ case SND_SOC_DAIFMT_DSP_A:
++ iface |= 0x0003;
++ break;
++ case SND_SOC_DAIFMT_DSP_B:
++ iface |= 0x0013;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ /* clock inversion */
++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
++ case SND_SOC_DAIFMT_NB_NF:
++ break;
++ case SND_SOC_DAIFMT_IB_IF:
++ iface |= 0x0090;
++ break;
++ case SND_SOC_DAIFMT_IB_NF:
++ iface |= 0x0080;
++ break;
++ case SND_SOC_DAIFMT_NB_IF:
++ iface |= 0x0010;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ wm8987_write(codec, WM8987_IFACE, iface);
++ return 0;
++}
++
++static int wm8987_pcm_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_device *socdev = rtd->socdev;
++ struct snd_soc_codec *codec = socdev->codec;
++ struct wm8987_priv *wm8987 = codec->private_data;
++ u16 iface = wm8987_read_reg_cache(codec, WM8987_IFACE) & 0x1f3;
++ u16 srate = wm8987_read_reg_cache(codec, WM8987_SRATE) & 0x1c0;
++ int coeff = get_coeff(wm8987->sysclk, params_rate(params));
++
++ /* bit size */
++ switch (params_format(params)) {
++ case SNDRV_PCM_FORMAT_S16_LE:
++ break;
++ case SNDRV_PCM_FORMAT_S20_3LE:
++ iface |= 0x0004;
++ break;
++ case SNDRV_PCM_FORMAT_S24_LE:
++ iface |= 0x0008;
++ break;
++ case SNDRV_PCM_FORMAT_S32_LE:
++ iface |= 0x000c;
++ break;
++ }
++
++ /* set iface & srate */
++ wm8987_write(codec, WM8987_IFACE, iface);
++ if (coeff >= 0)
++ wm8987_write(codec, WM8987_SRATE, srate |
++ (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
++
++ return 0;
++}
++
++static void wm8987_delayed_unmute(struct work_struct* work)
++{
++ u16 mute_reg;
++
++ if (p_codec == NULL)
++ return;
++ else {
++ mute_reg = wm8987_read_reg_cache(p_codec, WM8987_ADCDAC) & 0xfff7;
++ wm8987_write(p_codec, WM8987_ADCDAC, mute_reg);
++ if(wm8987_first_bias_on)
++ wm8987_first_bias_on = 0;
++ }
++}
++
++static int wm8987_mute(struct snd_soc_dai *dai, int mute)
++{
++ struct snd_soc_codec *codec = dai->codec;
++ u16 mute_reg = wm8987_read_reg_cache(codec, WM8987_ADCDAC);
++
++ if (mute)
++ wm8987_write(codec, WM8987_ADCDAC, mute_reg | 0x8);
++ else if(mute_reg & 0x8) {
++ cancel_delayed_work(&wm8987_unmute_work);
++ if(wm8987_first_bias_on)
++ schedule_delayed_work(&wm8987_unmute_work, msecs_to_jiffies(500));
++ else
++ schedule_delayed_work(&wm8987_unmute_work, msecs_to_jiffies(250));
++ }
++
++ return 0;
++}
++
++static void wm8987_delayed_bias_standby(struct work_struct* work)
++{
++ if (p_codec == NULL)
++ return;
++ else {
++ /* disable DAC Left, DAC Right, LOUT2 Output Buffer and ROUT2 Output Buffer of
++ * WM8987 (bit8, bit7, bit4 and bit3 of R26) together */
++ wm8987_write(p_codec, WM8987_PWR2, 0x0000);
++ /* mute dac and disable VREF, this results the minimum power consumption */
++ wm8987_write(p_codec, WM8987_PWR1, 0x0001);
++ wm8987_bias_on = 0;
++ }
++}
++
++static int wm8987_set_bias_level(struct snd_soc_codec *codec,
++ enum snd_soc_bias_level level)
++{
++ u16 pwr_reg = wm8987_read_reg_cache(codec, WM8987_PWR1) & 0xfe3e;
++
++ switch (level) {
++ case SND_SOC_BIAS_ON:
++ wm8987_is_playing = 1;
++ wm8987_first_bias_on = 1;
++ /* do nothing, because 'case SND_SOC_BIAS_PREPARE' has done everything */
++ break;
++ case SND_SOC_BIAS_PREPARE:
++ cancel_delayed_work(&wm8987_bias_standby_work);
++ if(wm8987_bias_on == 0) {
++ /* set vmid to 500k and unmute dac, this results the longest start-up time
++ * and least pop and click noise */
++ wm8987_write(codec, WM8987_PWR1, pwr_reg | 0x0140);
++ mdelay(500);
++ /* enable DAC Left, DAC Right, LOUT2 Output Buffer and ROUT2 Output Buffer of
++ * WM8987 (bit8, bit7, bit4 and bit3 of R26) together */
++ wm8987_write(codec, WM8987_PWR2, 0x01f8);
++ wm8987_bias_on = 1;
++ }
++ break;
++ case SND_SOC_BIAS_STANDBY:
++ wm8987_is_playing = 0;
++ schedule_delayed_work(&wm8987_bias_standby_work, msecs_to_jiffies(300000)); // 5 minutes
++ break;
++ case SND_SOC_BIAS_OFF:
++ wm8987_bias_on = 0;
++ wm8987_write(codec, WM8987_PWR1, 0x0001);
++ break;
++ }
++ codec->bias_level = level;
++ return 0;
++}
++
++#define WM8987_RATES SNDRV_PCM_RATE_8000_96000
++
++#define WM8987_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
++ SNDRV_PCM_FMTBIT_S24_LE)
++
++struct snd_soc_dai wm8987_dai = {
++ .name = "WM8987",
++ .playback = {
++ .stream_name = "Playback",
++ .channels_min = 1,
++ .channels_max = 2,
++ .rates = WM8987_RATES,
++ .formats = WM8987_FORMATS,},
++ .capture = {
++ .stream_name = "Capture",
++ .channels_min = 1,
++ .channels_max = 2,
++ .rates = WM8987_RATES,
++ .formats = WM8987_FORMATS,},
++ .ops = {
++ .hw_params = wm8987_pcm_hw_params,
++ },
++ .dai_ops = {
++ .digital_mute = wm8987_mute,
++ .set_fmt = wm8987_set_dai_fmt,
++ .set_sysclk = wm8987_set_dai_sysclk,
++ },
++};
++EXPORT_SYMBOL_GPL(wm8987_dai);
++
++static void wm8987_work(struct work_struct *work)
++{
++ struct snd_soc_codec *codec =
++ container_of(work, struct snd_soc_codec, delayed_work.work);
++ wm8987_set_bias_level(codec, codec->bias_level);
++}
++
++static int wm8987_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
++ struct snd_soc_codec *codec = socdev->codec;
++
++ wm8987_set_bias_level(codec, SND_SOC_BIAS_OFF);
++ return 0;
++}
++
++static int wm8987_resume(struct platform_device *pdev)
++{
++ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
++ struct snd_soc_codec *codec = socdev->codec;
++ int i;
++ u8 data[2];
++ u16 *cache = codec->reg_cache;
++
++ /* Sync reg_cache with the hardware */
++ for (i = 0; i < ARRAY_SIZE(wm8987_reg); i++) {
++ if (i == WM8987_RESET)
++ continue;
++ data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
++ data[1] = cache[i] & 0x00ff;
++ codec->hw_write(codec->control_data, data, 2);
++ }
++
++ wm8987_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
++
++ /* charge wm8987 caps */
++ if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
++ wm8987_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
++ codec->bias_level = SND_SOC_BIAS_ON;
++ schedule_delayed_work(&codec->delayed_work,
++ msecs_to_jiffies(1000));
++ }
++
++ return 0;
++}
++
++#if defined (CONFIG_LCD_4)
++void headp_update_mixer(struct work_struct* work)
++{
++ int reg;
++
++ if (p_codec == NULL)
++ return;
++ if (gpio_get_value(GPIO_HEADPHONE_S)) { // headphone inserted
++ reg = wm8987_read_reg_cache(p_codec, WM8987_ROUTM1);
++ wm8987_write(p_codec, WM8987_ROUTM1, reg & (~0x0100)); // Disable Left DAC to Right Mixer
++ reg = wm8987_read_reg_cache(p_codec, WM8987_LOUTM2);
++ wm8987_write(p_codec, WM8987_LOUTM2, reg & (~0x0100)); // Disable Right DAC to Left Mixer
++ } else { // headphone out
++ reg = wm8987_read_reg_cache(p_codec, WM8987_ROUTM1);
++ wm8987_write(p_codec, WM8987_ROUTM1, reg | 0x0100); // Enable Left DAC to Right Mixer
++ reg = wm8987_read_reg_cache(p_codec, WM8987_LOUTM2);
++ wm8987_write(p_codec, WM8987_LOUTM2, reg | 0x0100); // Enable Right DAC to Left Mixer
++ }
++}
++EXPORT_SYMBOL(headp_update_mixer);
++#endif
++
++/*
++ * initialise the WM8987 driver
++ * register the mixer and dsp interfaces with the kernel
++ */
++static int wm8987_init(struct snd_soc_device *socdev)
++{
++ struct snd_soc_codec *codec = socdev->codec;
++ int reg, ret = 0;
++
++ codec->name = "WM8987";
++ codec->owner = THIS_MODULE;
++ codec->read = wm8987_read_reg_cache;
++ codec->write = wm8987_write;
++ codec->set_bias_level = wm8987_set_bias_level;
++ codec->dai = &wm8987_dai;
++ codec->num_dai = 1;
++ codec->reg_cache_size = ARRAY_SIZE(wm8987_reg);
++ codec->reg_cache = kmemdup(wm8987_reg, sizeof(wm8987_reg), GFP_KERNEL);
++ if (codec->reg_cache == NULL)
++ return -ENOMEM;
++
++ wm8987_reset(codec);
++
++ /* register pcms */
++ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
++ if (ret < 0) {
++ printk(KERN_ERR "wm8987: failed to create pcms\n");
++ goto pcm_err;
++ }
++
++ /* charge output caps */
++ codec->bias_level = SND_SOC_BIAS_STANDBY;
++ schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000));
++
++ /* set the update bits */
++ reg = wm8987_read_reg_cache(codec, WM8987_ADCDAC) & 0xfff7;
++ wm8987_write(codec, WM8987_ADCDAC, reg | 0x008); // Mute at first
++ reg = wm8987_read_reg_cache(codec, WM8987_LOUTM1);
++ wm8987_write(codec, WM8987_LOUTM1, reg | 0x0100); // Enable Left DAC to Left Mixer
++ reg = wm8987_read_reg_cache(codec, WM8987_ROUTM2);
++ wm8987_write(codec, WM8987_ROUTM2, reg | 0x0100); // Enable Right DAC to Right Mixer
++ reg = wm8987_read_reg_cache(codec, WM8987_LDAC);
++ wm8987_write(codec, WM8987_LDAC, reg | 0x0100);
++ reg = wm8987_read_reg_cache(codec, WM8987_RDAC);
++ wm8987_write(codec, WM8987_RDAC, reg | 0x0100);
++ reg = wm8987_read_reg_cache(codec, WM8987_LOUT1V);
++ wm8987_write(codec, WM8987_LOUT1V, reg | 0x0100);
++ reg = wm8987_read_reg_cache(codec, WM8987_ROUT1V);
++ wm8987_write(codec, WM8987_ROUT1V, reg | 0x0100);
++ reg = wm8987_read_reg_cache(codec, WM8987_LOUT2V);
++ wm8987_write(codec, WM8987_LOUT2V, reg | 0x0100);
++ reg = wm8987_read_reg_cache(codec, WM8987_ROUT2V);
++ wm8987_write(codec, WM8987_ROUT2V, reg | 0x0100);
++ reg = wm8987_read_reg_cache(codec, WM8987_LINVOL);
++ wm8987_write(codec, WM8987_LINVOL, (reg & ~0x080) | 0x0140);
++ reg = wm8987_read_reg_cache(codec, WM8987_RINVOL);
++ wm8987_write(codec, WM8987_RINVOL, (reg & ~0x080) | 0x0140);
++
++ wm8987_add_controls(codec);
++ wm8987_add_widgets(codec);
++ ret = snd_soc_register_card(socdev);
++ if (ret < 0) {
++ printk(KERN_ERR "wm8987: failed to register card\n");
++ goto card_err;
++ }
++ p_codec = codec;
++ INIT_DELAYED_WORK(&wm8987_unmute_work, wm8987_delayed_unmute);
++ INIT_DELAYED_WORK(&wm8987_bias_standby_work, wm8987_delayed_bias_standby);
++
++ return ret;
++
++card_err:
++ snd_soc_free_pcms(socdev);
++ snd_soc_dapm_free(socdev);
++pcm_err:
++ kfree(codec->reg_cache);
++ return ret;
++}
++
++/* If the i2c layer weren't so broken, we could pass this kind of data
++ around */
++static struct snd_soc_device *wm8987_socdev;
++
++#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
++
++/*
++ * WM8987 2 wire address is determined by GPIO5
++ * state during powerup.
++ * low = 0x1a
++ * high = 0x1b
++ */
++
++static int wm8987_i2c_probe(struct i2c_client *i2c,
++ const struct i2c_device_id *id)
++{
++ struct snd_soc_device *socdev = wm8987_socdev;
++ struct snd_soc_codec *codec = socdev->codec;
++ int ret;
++
++ i2c_set_clientdata(i2c, codec);
++ codec->control_data = i2c;
++
++ ret = wm8987_init(socdev);
++ if (ret < 0)
++ pr_err("failed to initialise WM8987\n");
++
++ return ret;
++}
++
++static int wm8987_i2c_remove(struct i2c_client *client)
++{
++ struct snd_soc_codec *codec = i2c_get_clientdata(client);
++ kfree(codec->reg_cache);
++ return 0;
++}
++
++static const struct i2c_device_id wm8987_i2c_id[] = {
++ { "wm8987", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, wm8987_i2c_id);
++
++static struct i2c_driver wm8987_i2c_driver = {
++ .driver = {
++ .name = "WM8987 I2C Codec",
++ .owner = THIS_MODULE,
++ },
++ .probe = wm8987_i2c_probe,
++ .remove = wm8987_i2c_remove,
++ .id_table = wm8987_i2c_id,
++};
++
++static int wm8987_add_i2c_device(struct platform_device *pdev,
++ const struct wm8987_setup_data *setup)
++{
++ struct i2c_board_info info;
++ struct i2c_adapter *adapter;
++ struct i2c_client *client;
++ int ret;
++
++ ret = i2c_add_driver(&wm8987_i2c_driver);
++ if (ret != 0) {
++ dev_err(&pdev->dev, "can't add i2c driver\n");
++ return ret;
++ }
++
++ memset(&info, 0, sizeof(struct i2c_board_info));
++ info.addr = setup->i2c_address;
++ strlcpy(info.type, "wm8987", I2C_NAME_SIZE);
++
++ adapter = i2c_get_adapter(setup->i2c_bus);
++ if (!adapter) {
++ dev_err(&pdev->dev, "can't get i2c adapter %d\n",
++ setup->i2c_bus);
++ goto err_driver;
++ }
++
++ client = i2c_new_device(adapter, &info);
++ i2c_put_adapter(adapter);
++ if (!client) {
++ dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
++ (unsigned int)info.addr);
++ goto err_driver;
++ }
++
++ return 0;
++
++err_driver:
++ i2c_del_driver(&wm8987_i2c_driver);
++ return -ENODEV;
++}
++#endif
++
++#if defined(CONFIG_SPI_MASTER)
++static int __devinit wm8987_spi_probe(struct spi_device *spi)
++{
++ struct snd_soc_device *socdev = wm8987_socdev;
++ struct snd_soc_codec *codec = socdev->codec;
++ int ret;
++
++ codec->control_data = spi;
++
++ ret = wm8987_init(socdev);
++ if (ret < 0)
++ dev_err(&spi->dev, "failed to initialise WM8987\n");
++
++ return ret;
++}
++
++static int __devexit wm8987_spi_remove(struct spi_device *spi)
++{
++ return 0;
++}
++
++static struct spi_driver wm8987_spi_driver = {
++ .driver = {
++ .name = "wm8987",
++ .bus = &spi_bus_type,
++ .owner = THIS_MODULE,
++ },
++ .probe = wm8987_spi_probe,
++ .remove = __devexit_p(wm8987_spi_remove),
++};
++
++static int wm8987_spi_write(struct spi_device *spi, const char *data, int len)
++{
++ struct spi_transfer t;
++ struct spi_message m;
++ u8 msg[2];
++
++ if (len <= 0)
++ return 0;
++
++ msg[0] = data[0];
++ msg[1] = data[1];
++
++ spi_message_init(&m);
++ memset(&t, 0, (sizeof t));
++
++ t.tx_buf = &msg[0];
++ t.len = len;
++
++ spi_message_add_tail(&t, &m);
++ spi_sync(spi, &m);
++
++ return len;
++}
++#endif
++
++static int wm8987_probe(struct platform_device *pdev)
++{
++ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
++ struct wm8987_setup_data *setup = socdev->codec_data;
++ struct snd_soc_codec *codec;
++ struct wm8987_priv *wm8987;
++ int ret;
++
++ pr_info("WM8987 Audio Codec %s", WM8987_VERSION);
++ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
++ if (codec == NULL)
++ return -ENOMEM;
++
++ wm8987 = kzalloc(sizeof(struct wm8987_priv), GFP_KERNEL);
++ if (wm8987 == NULL) {
++ kfree(codec);
++ return -ENOMEM;
++ }
++
++ codec->private_data = wm8987;
++ socdev->codec = codec;
++ mutex_init(&codec->mutex);
++ INIT_LIST_HEAD(&codec->dapm_widgets);
++ INIT_LIST_HEAD(&codec->dapm_paths);
++ wm8987_socdev = socdev;
++ INIT_DELAYED_WORK(&codec->delayed_work, wm8987_work);
++
++ ret = -ENODEV;
++
++#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
++ if (setup->i2c_address) {
++ codec->hw_write = (hw_write_t)i2c_master_send;
++ ret = wm8987_add_i2c_device(pdev, setup);
++ }
++#endif
++#if defined(CONFIG_SPI_MASTER)
++ if (setup->spi) {
++ codec->hw_write = (hw_write_t)wm8987_spi_write;
++ ret = spi_register_driver(&wm8987_spi_driver);
++ if (ret != 0)
++ printk(KERN_ERR "can't add spi driver");
++ }
++#endif
++
++ if (ret != 0) {
++ kfree(codec->private_data);
++ kfree(codec);
++ }
++ return ret;
++}
++
++/*
++ * This function forces any delayed work to be queued and run.
++ */
++static int run_delayed_work(struct delayed_work *dwork)
++{
++ int ret;
++
++ /* cancel any work waiting to be queued. */
++ ret = cancel_delayed_work(dwork);
++
++ /* if there was any work waiting then we run it now and
++ * wait for it's completion */
++ if (ret) {
++ schedule_delayed_work(dwork, 0);
++ flush_scheduled_work();
++ }
++ return ret;
++}
++
++/* power down chip */
++static int wm8987_remove(struct platform_device *pdev)
++{
++ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
++ struct snd_soc_codec *codec = socdev->codec;
++
++ if (codec->control_data)
++ wm8987_set_bias_level(codec, SND_SOC_BIAS_OFF);
++ run_delayed_work(&codec->delayed_work);
++ snd_soc_free_pcms(socdev);
++ snd_soc_dapm_free(socdev);
++#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
++ i2c_unregister_device(codec->control_data);
++ i2c_del_driver(&wm8987_i2c_driver);
++#endif
++#if defined(CONFIG_SPI_MASTER)
++ spi_unregister_driver(&wm8987_spi_driver);
++#endif
++ kfree(codec->private_data);
++ kfree(codec);
++
++ return 0;
++}
++
++struct snd_soc_codec_device soc_codec_dev_wm8987 = {
++ .probe = wm8987_probe,
++ .remove = wm8987_remove,
++ .suspend = wm8987_suspend,
++ .resume = wm8987_resume,
++};
++EXPORT_SYMBOL_GPL(soc_codec_dev_wm8987);
++
++MODULE_DESCRIPTION("ASoC WM8987 driver");
++MODULE_AUTHOR("Liam Girdwood");
++MODULE_LICENSE("GPL");
+diff --git a/sound/soc/codecs/wm8987.h b/sound/soc/codecs/wm8987.h
+new file mode 100755
+index 0000000..cdf8ff3
+--- /dev/null
++++ b/sound/soc/codecs/wm8987.h
+@@ -0,0 +1,69 @@
++/*
++ * Copyright 2005 Openedhand Ltd.
++ *
++ * Author: Richard Purdie <richard@openedhand.com>
++ *
++ * Based on WM8753.h
++ *
++ * 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 _WM8987_H
++#define _WM8987_H
++
++/* WM8987 register space */
++
++#define WM8987_LINVOL 0x00
++#define WM8987_RINVOL 0x01
++#define WM8987_LOUT1V 0x02
++#define WM8987_ROUT1V 0x03
++#define WM8987_ADCDAC 0x05
++#define WM8987_IFACE 0x07
++#define WM8987_SRATE 0x08
++#define WM8987_LDAC 0x0a
++#define WM8987_RDAC 0x0b
++#define WM8987_BASS 0x0c
++#define WM8987_TREBLE 0x0d
++#define WM8987_RESET 0x0f
++#define WM8987_3D 0x10
++#define WM8987_ALC1 0x11
++#define WM8987_ALC2 0x12
++#define WM8987_ALC3 0x13
++#define WM8987_NGATE 0x14
++#define WM8987_LADC 0x15
++#define WM8987_RADC 0x16
++#define WM8987_ADCTL1 0x17
++#define WM8987_ADCTL2 0x18
++#define WM8987_PWR1 0x19
++#define WM8987_PWR2 0x1a
++#define WM8987_ADCTL3 0x1b
++#define WM8987_ADCIN 0x1f
++#define WM8987_LADCIN 0x20
++#define WM8987_RADCIN 0x21
++#define WM8987_LOUTM1 0x22
++#define WM8987_LOUTM2 0x23
++#define WM8987_ROUTM1 0x24
++#define WM8987_ROUTM2 0x25
++#define WM8987_MOUTM1 0x26
++#define WM8987_MOUTM2 0x27
++#define WM8987_LOUT2V 0x28
++#define WM8987_ROUT2V 0x29
++#define WM8987_MOUTV 0x2a
++
++#define WM8987_CACHE_REGNUM 0x2a
++
++#define WM8987_SYSCLK 0
++
++struct wm8987_setup_data {
++ int spi;
++ int i2c_bus;
++ unsigned short i2c_address;
++};
++
++extern struct snd_soc_dai wm8987_dai;
++extern struct snd_soc_codec_device soc_codec_dev_wm8987;
++
++#endif
+diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
+index 16c7453..b72561a 100644
+--- a/sound/soc/soc-core.c
++++ b/sound/soc/soc-core.c
+@@ -359,10 +359,12 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
+ cpu_dai->runtime = NULL;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+- /* start delayed pop wq here for playback streams */
+- codec_dai->pop_wait = 1;
+- schedule_delayed_work(&socdev->delayed_work,
+- msecs_to_jiffies(pmdown_time));
++ if (codec->bias_level == SND_SOC_BIAS_ON) { //XXX: FIX VLC
++ /* start delayed pop wq here for playback streams */
++ codec_dai->pop_wait = 1;
++ schedule_delayed_work(&socdev->delayed_work,
++ msecs_to_jiffies(pmdown_time));
++ }
+ } else {
+ /* capture streams can be powered down now */
+ snd_soc_dapm_stream_event(codec,
+diff --git a/sound/soc/tcc/Kconfig b/sound/soc/tcc/Kconfig
+new file mode 100644
+index 0000000..16f4367
+--- /dev/null
++++ b/sound/soc/tcc/Kconfig
+@@ -0,0 +1,49 @@
++config SND_TCC_SOC
++ tristate "SoC Audio for the Telechips TCC chip"
++ depends on (MACH_TCC8900) && SND_SOC
++ help
++ Say Y or M if you want to add support for codecs attached to
++ the TCC I2S interface. You will also need
++ to select the audio interfaces to support below.
++
++config SND_TCC_SOC_I2S
++ tristate
++
++choice
++ prompt "SoC Audio support for TCC Board"
++ depends on SND_TCC_SOC
++ default SND_TCC_SOC_BOARD_WM8731
++ help
++ TCC Audio Codec
++
++config SND_TCC_SOC_BOARD_WM8731
++ tristate "WM8731"
++ select SND_TCC_SOC_I2S
++ select SND_SOC_WM8731
++ help
++ Say Y if you want to add support for SoC audio on Telechips
++ TCC (WM8731).
++
++config SND_TCC_SOC_BOARD_WM8581
++ tristate "WM8581"
++ select SND_TCC_SOC_I2S
++ select SND_SOC_WM8581
++ help
++ Say Y if you want to add support for SoC audio on Telechips
++ TCC (WM8581).
++
++config SND_TCC_SOC_BOARD_WM8987
++ tristate "WM8987"
++ select SND_TCC_SOC_I2S
++ select SND_SOC_WM8987
++ help
++ Say Y if you want to add support for SoC audio on Telechips
++ TCC (WM8987).
++
++config AUDIO_CODEC_PROCFS
++ bool "Proc-FS interface for audio codec control"
++ depends on SND_TCC_SOC_BOARD_WM8987 && PROC_FS
++ default y
++
++endchoice
++
+diff --git a/sound/soc/tcc/Makefile b/sound/soc/tcc/Makefile
+new file mode 100644
+index 0000000..8bcbefc
+--- /dev/null
++++ b/sound/soc/tcc/Makefile
+@@ -0,0 +1,20 @@
++# TCC Platform Support
++
++ifeq ($(CONFIG_ARCH_TCC),y)
++$(shell ln -fsn $(CONFIG_TCC_STRING) $(srctree)/sound/soc/tcc/tcc)
++endif
++
++# TCC Machine Support
++#snd-soc-tcc-i2s-objs := tcc-pcm.o tcc-i2s.o
++
++snd-soc-tcc-board-objs := tcc_board.o
++snd-soc-tcc-i2s-objs := tcc-pcm.o tcc-i2s.o tcc/tca_tcchwcontrol.o
++snd-soc-tcc-board-wm8581-objs := tcc_board_wm8581.o
++snd-soc-tcc-board-wm8987-objs := tcc_board_wm8987.o
++
++obj-$(CONFIG_SND_TCC_SOC_I2S) += snd-soc-tcc-i2s.o
++obj-$(CONFIG_SND_TCC_SOC_BOARD_WM8731) += snd-soc-tcc-board.o
++obj-$(CONFIG_SND_TCC_SOC_BOARD_WM8581) += snd-soc-tcc-board-wm8581.o
++obj-$(CONFIG_SND_TCC_SOC_BOARD_WM8987) += snd-soc-tcc-board-wm8987.o
++
++
+diff --git a/sound/soc/tcc/tcc-i2s.c b/sound/soc/tcc/tcc-i2s.c
+new file mode 100644
+index 0000000..cabbb57
+--- /dev/null
++++ b/sound/soc/tcc/tcc-i2s.c
+@@ -0,0 +1,347 @@
++/*
++ * linux/sound/soc/tcc/tcc-i2s.c
++ *
++ * Based on: linux/sound/soc/pxa/pxa2xx-i2s.h
++ * Author: Liam Girdwood<liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com>
++ * Rewritten by: <linux@telechips.com>
++ * Created: 12th Aug 2005 Initial version.
++ * Modified: Nov 25, 2008
++ * Description: ALSA PCM interface for the Intel PXA2xx chip
++ *
++ * Copyright 2005 Wolfson Microelectronics PLC.
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/delay.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/initval.h>
++#include <sound/soc.h>
++
++#include <bsp.h>
++#include <mach/hardware.h>
++#include <mach/irqs.h>
++#include <mach/tca_ckc.h>
++
++#include "tcc-pcm.h"
++#include "tcc-i2s.h"
++#include "tcc/tca_tcchwcontrol.h"
++
++static struct tcc_pcm_dma_params tcc_i2s_pcm_stereo_out = {
++ .name = "I2S PCM Stereo out",
++ .dma_addr = 0,
++ .channel =0,
++ // .dma_size
++
++};
++
++static struct tcc_pcm_dma_params tcc_i2s_pcm_stereo_in = {
++ .name = "I2S PCM Stereo in",
++ .dma_addr = 0,
++ .channel =1,
++ // .dma_size
++};
++
++static struct tcc_pcm_dma_params tcc_i2s_pcm_spdif_out = {
++ .name = "I2S PCM S/PDIF out",
++ .dma_addr = 0,
++ .channel =0,
++ // .dma_size
++
++};
++
++static int alsa_i2s_init(void)
++{
++ volatile PADMADAI pADMA_DAI = (volatile PADMADAI)tcc_p2v(HwADMA_DAIBASE);
++ volatile PPIC pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
++ volatile ADMASPDIFTX *p_adma_spdif_tx_base = (volatile ADMASPDIFTX *)tcc_p2v(HwADMA_SPDIFTXBASE);
++
++ tca_i2s_dai_init(pADMA_DAI);
++
++ tca_ckc_setiobus(RB_SPDIFTXCONTROLLER, 1);
++ tca_ckc_setiobus(RB_DAICDIFCONTROLLER, 1);
++ tca_ckc_setiobus(RB_ADMACONTROLLER, 1);
++
++ tca_ckc_set_iobus_swreset(RB_ADMACONTROLLER, 0);
++ tca_ckc_set_iobus_swreset(RB_ADMACONTROLLER, 1);
++
++ //Clear DAI TX INT
++ //BITCLR(HwCLR, HwCLR_DAITX);
++ //BITCLR(HwCLR, HwCLR_DAIRX);
++
++ //Config DMA Interrupt
++ BITSET(pPIC->SEL1, 1 << (INT_ADMA - 32));
++ BITSET(pPIC->MODE1, 1 << (INT_ADMA - 32));
++ BITCLR(pPIC->POL1, 1 << (INT_ADMA - 32));
++
++ tca_i2s_stop((void *)pADMA_DAI, (void *)p_adma_spdif_tx_base, 0);
++ tca_i2s_stop((void *)pADMA_DAI, (void *)p_adma_spdif_tx_base, 1);
++
++ return 0;
++}
++
++static int alsa_spdif_init(void)
++{
++ tca_ckc_setiobus(RB_SPDIFTXCONTROLLER, 1);
++
++ return 0;
++}
++
++/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++Function: StartI2SClock()
++
++Description: Enables the I2S clock that drives the audio codec chip.
++
++Returns: N/A
++-------------------------------------------------------------------*/
++static int tcc_i2s_startup(struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
++
++ if (!cpu_dai->active) {
++ //alsa_i2s_init();
++ }
++
++ return 0;
++}
++
++static int tcc_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
++{
++ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
++ case SND_SOC_DAIFMT_CBS_CFS:
++ break;
++ case SND_SOC_DAIFMT_CBM_CFS:
++ break;
++ default:
++ break;
++ }
++
++
++ /* interface format */
++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
++ case SND_SOC_DAIFMT_I2S:
++ break;
++ case SND_SOC_DAIFMT_LEFT_J:
++ break;
++ }
++ return 0;
++}
++
++static int tcc_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
++ int clk_id, unsigned int freq, int dir)
++{
++ if (clk_id != TCC_I2S_SYSCLK)
++ return -ENODEV;
++
++ return 0;
++}
++static int tcc_i2s_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
++
++ if (substream->pcm->device == __I2S_DEV_NUM__) {
++ cpu_dai->dma_data = ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ ? &tcc_i2s_pcm_stereo_out : &tcc_i2s_pcm_stereo_in);
++ tea_i2s_setclock(params_rate(params));
++ }
++ return 0;
++}
++
++static int tcc_spdif_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
++
++ if (substream->pcm->device == __SPDIF_DEV_NUM__) {
++ cpu_dai->dma_data = &tcc_i2s_pcm_spdif_out;
++ tea_spdif_setclock(params_rate(params));
++ }
++ return 0;
++}
++
++
++static int tcc_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
++{
++ int ret = 0;
++ volatile PADMADAI pDAI = (volatile PADMADAI)tcc_p2v(HwADMA_DAIBASE);
++
++ switch (cmd) {
++ case SNDRV_PCM_TRIGGER_START:
++ case SNDRV_PCM_TRIGGER_RESUME:
++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++ //tca_i2s_start(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1);
++ BITSET(pDAI->DAMR, Hw15);
++ break;
++
++ case SNDRV_PCM_TRIGGER_STOP:
++ case SNDRV_PCM_TRIGGER_SUSPEND:
++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++ //tca_i2s_stop(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1);
++ //mutex_lock(&(tcc_alsa_info.mutex));
++ if (!(tcc_alsa_info.flag)) {
++ BITCLR(pDAI->DAMR, Hw15);
++ }
++ //mutex_unlock(&(tcc_alsa_info.mutex));
++ break;
++
++ default:
++ ret = -EINVAL;
++ }
++ return ret;
++}
++
++static void tcc_i2s_shutdown(struct snd_pcm_substream *substream)
++{
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ } else {
++ }
++
++ //mutex_lock(&(tcc_alsa_info.mutex));
++ if (!(tcc_alsa_info.flag)) {
++ //BITCLR(HwPCLKCFG7, HwPCLKCFG7_DCLK1_EN_ON);
++ }
++ //mutex_unlock(&(tcc_alsa_info.mutex));
++}
++
++static int tcc_i2s_suspend(struct platform_device *dev, struct snd_soc_dai *dai)
++{
++// pm_printk("info ==========> [%s], [%u:%u]\n", dai->name, dai->id, (unsigned int)dai->type);
++// pm_printk("***************> PM \n");
++
++ if (dai->id == __I2S_DEV_NUM__) {
++ tca_ckc_setiobus(RB_DAICDIFCONTROLLER, 0);
++ tca_ckc_setiobus(RB_ADMACONTROLLER, 0);
++ }
++ if (dai->id == __SPDIF_DEV_NUM__) {
++ tca_ckc_setiobus(RB_SPDIFTXCONTROLLER, 0);
++ }
++
++ return 0;
++}
++
++static int tcc_i2s_resume(struct platform_device *pdev, struct snd_soc_dai *dai)
++{
++// pm_printk("info ==========> [%s], [%u:%u]\n", dai->name, dai->id, (unsigned int)dai->type);
++// pm_printk("***************> PM \n");
++
++ if (dai->id == __I2S_DEV_NUM__) {
++ tca_ckc_setiobus(RB_ADMACONTROLLER, 1);
++ tca_ckc_setiobus(RB_DAICDIFCONTROLLER, 1);
++ }
++ if (dai->id == __SPDIF_DEV_NUM__) {
++ tca_ckc_setiobus(RB_SPDIFTXCONTROLLER, 1);
++ }
++
++ return 0;
++}
++
++#define TCC89XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
++ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
++ SNDRV_PCM_RATE_32000 |SNDRV_PCM_RATE_44100 |\
++ SNDRV_PCM_RATE_48000 )
++
++int tcc_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
++{
++ ((void)(dai));
++ alsa_i2s_init();
++ tea_i2s_setclock(44100);
++ return 0;
++}
++
++int tcc_spdif_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
++{
++ ((void)(dai));
++ alsa_spdif_init();
++ tea_spdif_setclock(44100);
++ return 0;
++}
++
++struct snd_soc_dai tcc_i2s_dai[] = {
++ [__I2S_DEV_NUM__] = {
++ .name = "tcc-i2s",
++ .id = 0,
++ .type = SND_SOC_DAI_I2S,
++ .suspend = tcc_i2s_suspend,
++ .resume = tcc_i2s_resume,
++ .playback = {
++ .channels_min = 2,
++#if defined(CONFIG_SND_SOC_WM8581) || defined(CONFIG_SND_SOC_WM8581_MODULE)
++ .channels_max = 8,
++#else
++ .channels_max = 2,
++#endif
++ .rates = TCC89XX_I2S_RATES,
++ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,}, //should be change? phys:32 width:16
++ .capture = {
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = TCC89XX_I2S_RATES,
++ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, //should be change? phys:32 width:16
++ .ops = {
++ .startup = tcc_i2s_startup,
++ .shutdown = tcc_i2s_shutdown,
++ .trigger = tcc_i2s_trigger,
++ .hw_params = tcc_i2s_hw_params,},
++ .dai_ops = {
++ .set_fmt = tcc_i2s_set_dai_fmt,
++ .set_sysclk = tcc_i2s_set_dai_sysclk,
++ },
++ .probe = tcc_i2s_probe,
++ },
++ [__SPDIF_DEV_NUM__] = {
++ .name = "tcc-spdif",
++ .id = 1,
++ .type = SND_SOC_DAI_I2S,
++ .suspend = tcc_i2s_suspend,
++ .resume = tcc_i2s_resume,
++ .playback = {
++ .channels_min = 2,
++#if defined(CONFIG_SND_SOC_WM8581) || defined(CONFIG_SND_SOC_WM8581_MODULE)
++ .channels_max = 8,
++#else
++ .channels_max = 2,
++#endif
++ .rates = TCC89XX_I2S_RATES,
++ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,}, //should be change? phys:32 width:16
++ .ops = {
++ .startup = tcc_i2s_startup,
++ .shutdown = tcc_i2s_shutdown,
++ .trigger = tcc_i2s_trigger,
++ .hw_params = tcc_spdif_hw_params,},
++ .dai_ops = {
++ .set_fmt = tcc_i2s_set_dai_fmt,
++ .set_sysclk = tcc_i2s_set_dai_sysclk,
++ },
++ .probe = tcc_spdif_probe,
++ }
++};
++
++EXPORT_SYMBOL_GPL(tcc_i2s_dai);
++
++/* Module information */
++MODULE_AUTHOR("linux <linux@telechips.com>");
++MODULE_DESCRIPTION("Telechips TCC I2S SoC Interface");
++MODULE_LICENSE("GPL");
++
+diff --git a/sound/soc/tcc/tcc-i2s.h b/sound/soc/tcc/tcc-i2s.h
+new file mode 100644
+index 0000000..367d354
+--- /dev/null
++++ b/sound/soc/tcc/tcc-i2s.h
+@@ -0,0 +1,136 @@
++/*
++ * linux/sound/soc/tcc/tcc-i2s.h
++ *
++ * Based on: linux/sound/soc/pxa/pxa2xx-i2s.h
++ * Author: <linux@telechips.com>
++ * Created: Nov 25, 2008
++ * Description: ALSA PCM interface for the Intel PXA2xx chip
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#ifndef _TCC_I2S_H
++#define _TCC_I2S_H
++
++/* pxa2xx DAI ID's */
++#define TCC_DAI_I2S 0
++
++/* I2S clock */
++#define TCC_I2S_SYSCLK 0
++
++extern struct snd_soc_dai tcc_i2s_dai[];
++
++//=============================================================================
++#define AUDIO_DMA_PAGE_NUMBER (2) // Number of DMA Buffer
++#define AUDIO_DMA_OUT_PAGE_SIZE (1024) // Size in bytes
++#define AUDIO_DMA_IN_PAGE_SIZE (1024) // Size in bytes
++#define AUDIO_DMA_OUT_BUF_SIZE (AUDIO_DMA_PAGE_NUMBER * AUDIO_DMA_OUT_PAGE_SIZE)
++#define AUDIO_DMA_IN_BUF_SIZE (AUDIO_DMA_PAGE_NUMBER * AUDIO_DMA_IN_PAGE_SIZE)
++
++//===================== Register Configuration Constants ======================
++
++#define IIS_INTERNAL_CLOCK_ENABLE (1<<17) // Enable CPU clock to IIS controller
++
++//----- GPIO Configuration Masks -----
++#define ENABLE_I2SSDO 0x00000200
++#define ENABLE_I2SSDI 0x00000080
++#define ENABLE_I2SCDCLK 0x00000020
++#define ENABLE_I2SSCLK 0x00000008
++#define ENABLE_I2SLRCLK 0x00000002
++#define DISABLE_I2S_PULLUPS 0x0000001F
++
++//----- Register definitions for IISCON control register (global config register) -----
++#define LR_CHANNEL_INDEX 0x00000100 // Left/right channel index (read-only)
++#define TRANSMIT_FIFO_READY 0x00000080 // Indicates transmit FIFO is ready (read-only)
++#define RECEIVE_FIFO_READY 0x00000040 // Indicates receive FIFO is ready (read-only)
++#define TRANSMIT_DMA_REQUEST_ENABLE 0x00000020 // Enables transmit DMA request
++#define RECEIVE_DMA_REQUEST_ENABLE 0x00000010 // Enables receive DMA request
++#define TRANSMIT_IDLE_CMD 0x00000008 // Pauses transmit
++#define RECEIVE_IDLE_CMD 0x00000004 // Pauses receive
++#define IIS_PRESCALER_ENABLE 0x00000002 // Enables clock prescaler
++#define IIS_INTERFACE_ENABLE 0x00000001 // Enables IIS controller
++
++//----- Register definitions for IISMOD status register (global status register) -----
++#define IIS_MASTER_MODE 0x00000000 // Selects master/slave mode
++#define IIS_SLAVE_MODE 0x00000100
++#define IIS_NOTRANSFER_MODE 0x00000000 // Selects transfer mode
++#define IIS_RECEIVE_MODE 0x00000040
++#define IIS_TRANSMIT_MODE 0x00000080
++#define IIS_TRANSMIT_RECEIVE_MODE 0x000000C0
++#define ACTIVE_CHANNEL_LEFT 0x00000000 // Selects active channel
++#define ACTIVE_CHANNEL_RIGHT 0x00000020
++#define SERIAL_INTERFACE_IIS_COMPAT 0x00000000 // Selects serial interface format
++#define SERIAL_INTERFACE_MSBL_COMPAT 0x00000010
++#define DATA_8_BITS_PER_CHANNEL 0x00000000 // Selects # of data bits per channel
++#define DATA_16_BITS_PER_CHANNEL 0x00000008
++#define MASTER_CLOCK_FREQ_256fs 0x00000000 // Selects master clock frequency
++#define MASTER_CLOCK_FREQ_384fs 0x00000004
++#define SERIAL_BIT_CLOCK_FREQ_16fs 0x00000000 // Selects serial data bit clock frequency
++#define SERIAL_BIT_CLOCK_FREQ_32fs 0x00000001
++#define SERIAL_BIT_CLOCK_FREQ_48fs 0x00000002
++
++
++//----- Register definitions for IISPSR control register (global config register) -----
++// FORMAT: bits[9:5] - Prescaler Control A
++// bits[4:0] - Prescaler Control B
++//
++// Range: 0-31 and the division factor is N+1 (a.k.a. 1-32)
++//
++// The I2SLRCLK frequency is determined as follows:
++//
++// I2SLRCLK = CODECLK / I2SCDCLK and (prescaler+1) = PCLK / CODECLK
++//
++// Thus, rearranging the equations a bit we can see that:
++//
++// prescaler = (PCLK / CODECLK) - 1
++// or
++// prescaler = ((PCLK / (IS2LRCLK * IS2CDCLK)) - 1
++//
++// Here are some popular values for IS2LRCLK:
++//
++#define IS2LRCLK_800 800
++#define IS2LRCLK_11025 11025
++#define IS2LRCLK_16000 16000
++#define IS2LRCLK_22050 22050
++#define IS2LRCLK_32000 32000
++#define IS2LRCLK_44100 44100
++#define IS2LRCLK_48000 48000
++#define IS2LRCLK_64000 64000
++#define IS2LRCLK_88200 88200
++#define IS2LRCLK_96000 96000
++
++
++//----- Register definitions for IISFCON control register (global config register) -----
++#define TRANSMIT_FIFO_ACCESS_NORMAL 0x00000000 // Selects the transmit FIFO access mode
++#define TRANSMIT_FIFO_ACCESS_DMA 0x00008000
++#define RECEIVE_FIFO_ACCESS_NORMAL 0x00000000 // Selects the receive FIFO access mode
++#define RECEIVE_FIFO_ACCESS_DMA 0x00004000
++#define TRANSMIT_FIFO_ENABLE 0x00002000 // Enables transmit FIFO
++#define RECEIVE_FIFO_ENABLE 0x00001000 // Enables receive FIFO
++//
++// READ-ONLY Fields: bits[11:6] - Transmit FIFO datacount
++// bits[5:0] - Receive FIFO datacount
++
++//----- Register definitions for IISFIFO control register (global config register) -----
++// NOTE: This register is used to access the transmit/receive FIFO
++#define MAX_TRANSMIT_FIFO_ENTRIES 24
++#define MAX_RECEIVE_FIFO_ENTRIES 24
++
++#define __I2S_DEV_NUM__ 0
++#define __SPDIF_DEV_NUM__ 1
++
++#endif
+diff --git a/sound/soc/tcc/tcc-loopback.c b/sound/soc/tcc/tcc-loopback.c
+new file mode 100644
+index 0000000..8a0d765
+--- /dev/null
++++ b/sound/soc/tcc/tcc-loopback.c
+@@ -0,0 +1,177 @@
++/*
++ * linux/sound/soc/tcc/tcc-loopback.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: Nov 25, 2008
++ * Description: ALSA loopback driver
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/miscdevice.h>
++#include <linux/delay.h>
++#include <linux/poll.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++
++#include "tcc-loopback.h"
++
++/* static function */
++static void alb_lock(tcc_alsa_lb_handle_t *h)
++{
++ mutex_lock(&(h->alb_mutex));
++}
++
++static void alb_unlock(tcc_alsa_lb_handle_t *h)
++{
++ mutex_unlock(&(h->alb_mutex));
++}
++
++static int alb_init(tcc_alsa_lb_handle_t *h)
++{
++ if (h) {
++ init_waitqueue_head(&(h->wait_q));
++ mutex_init(&(h->alb_mutex));
++ return 0;
++ }
++ return -1;
++}
++
++static int alb_get_pop_size(tcc_alsa_lb_handle_t *h)
++{
++ if (h) {
++ if (h->top != h->bottom) {
++ return ((h->top > h->bottom)
++ ? h->top - h->bottom : h->top + (h->lb_buf_size - h->bottom));
++ }
++ }
++ return 0;
++}
++
++static int alb_pop_user(tcc_alsa_lb_handle_t *h, char *p_buf, int buf_size)
++{
++ if (h && p_buf) {
++ int pop_size = alb_get_pop_size(h);
++
++ if (pop_size > buf_size) {
++ pop_size = buf_size;
++ }
++
++ if (pop_size > 0) {
++ if ((h->lb_buf_size - h->bottom) < pop_size) {
++ /* end of buffer */
++ int first_copy_size = h->lb_buf_size - h->bottom;
++ copy_to_user(p_buf, h->p_lb_buf + h->bottom, first_copy_size);
++ copy_to_user(p_buf + first_copy_size, h->p_lb_buf, pop_size - first_copy_size);
++ h->bottom = pop_size - first_copy_size;
++
++ } else {
++ copy_to_user(p_buf, h->p_lb_buf + h->bottom, pop_size);
++ h->bottom += pop_size;
++ if (h->bottom >= h->lb_buf_size) {
++ h->bottom = 0;
++ }
++ }
++ return pop_size;
++ }
++ return 0;
++ }
++ return -1;
++}
++
++static int alb_push(tcc_alsa_lb_handle_t *h, char *p_buf, int buf_size)
++{
++ if (h && p_buf) {
++ if (h->lb_buf_size > buf_size) {
++ if ((h->lb_buf_size - h->top) < buf_size) {
++ /* end of buffer */
++ int first_copy_size = h->lb_buf_size - h->top;
++ memcpy(h->p_lb_buf + h->top, p_buf, first_copy_size);
++ memcpy(h->p_lb_buf, p_buf + first_copy_size, buf_size - first_copy_size);
++ h->top = buf_size - first_copy_size;
++ } else {
++ memcpy(h->p_lb_buf + h->top, p_buf, buf_size);
++ h->top += buf_size;
++ if (h->top >= h->lb_buf_size) {
++ h->top = 0;
++ }
++ }
++ }
++ }
++ return -1;
++}
++
++static void alb_set_dma_info(tcc_alsa_lb_handle_t *h,
++ unsigned int cur_dma_addr,
++ unsigned int dma_addr,
++ unsigned int dma_size,
++ char *v_addr)
++{
++ h->cur_dma_addr = cur_dma_addr;
++ h->dma_addr = dma_addr;
++ h->dma_size = dma_size;
++ h->v_addr = v_addr;
++}
++
++/* extern function */
++tcc_alsa_lb_handle_t *new_alsa_lb(int dma_buf_size)
++{
++ tcc_alsa_lb_handle_t *handle = NULL;
++
++ handle = (struct tcc_alsa_lb_handle *)kmalloc(sizeof(tcc_alsa_lb_handle_t), GFP_KERNEL);
++ if (handle && dma_buf_size >= 1024) {
++ memset(handle, 0, sizeof(tcc_alsa_lb_handle_t));
++ handle->p_lb_buf = (char *)kmalloc(dma_buf_size, GFP_KERNEL);
++ if (handle->p_lb_buf) {
++ handle->lb_buf_size = dma_buf_size;
++ handle->init = alb_init;
++ handle->get_pop_size = alb_get_pop_size;
++ handle->pop_user = alb_pop_user;
++ handle->push = alb_push;
++
++ handle->lock = alb_lock;
++ handle->unlock = alb_unlock;
++
++ handle->set_dma_info = alb_set_dma_info;
++ } else {
++ printk("[%s:%d] cannot allocate memory !!!\n", __func__, __LINE__);
++ handle = delete_alsa_lb(handle);
++ }
++ }
++ return handle;
++}
++
++tcc_alsa_lb_handle_t *delete_alsa_lb(tcc_alsa_lb_handle_t *h)
++{
++ if (h) {
++ if (h->p_lb_buf) {
++ kfree(h->p_lb_buf);
++ h->p_lb_buf = NULL;
++ }
++ kfree(h);
++ }
++ return NULL;
++}
++
++
+diff --git a/sound/soc/tcc/tcc-loopback.h b/sound/soc/tcc/tcc-loopback.h
+new file mode 100644
+index 0000000..3145312
+--- /dev/null
++++ b/sound/soc/tcc/tcc-loopback.h
+@@ -0,0 +1,74 @@
++/*
++ * linux/sound/soc/tcc/tcc-loopback.h
++ *
++ * Author: <linux@telechips.com>
++ * Created: Nov 25, 2008
++ * Description: ALSA loopback driver
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++
++#ifndef __TCC_LOOPBACK_H__
++#define __TCC_LOOPBACK_H__
++
++#define LOOPBACK_MAJOR_NUM 245
++#define DEVICE_NAME "tcc_alsa_loopback"
++
++typedef struct tcc_alsa_lb_handle tcc_alsa_lb_handle_t;
++struct tcc_alsa_lb_handle {
++ int open_cnt;
++ wait_queue_head_t wait_q;
++
++ /* queue */
++ int top, bottom;
++ int lb_buf_size;
++ char *p_lb_buf;
++
++ /* dam */
++ unsigned int cur_dma_addr;
++ unsigned int dma_addr;
++ unsigned int dma_size;
++ char *v_addr;
++
++ struct mutex alb_mutex;
++
++ int (*init)(tcc_alsa_lb_handle_t *h);
++ int (*get_pop_size)(tcc_alsa_lb_handle_t *h);
++ int (*pop_user)(tcc_alsa_lb_handle_t *h, char *p_buf, int buf_size);
++ int (*push)(tcc_alsa_lb_handle_t *h, char *p_buf, int buf_size);
++ void (*lock)(tcc_alsa_lb_handle_t *h);
++ void (*unlock)(tcc_alsa_lb_handle_t *h);
++ void (*set_dma_info)(tcc_alsa_lb_handle_t *h,
++ unsigned int cur_dma_addr,
++ unsigned int dma_addr,
++ unsigned int dma_size,
++ char *v_addr);
++
++
++};
++
++extern tcc_alsa_lb_handle_t *new_alsa_lb(int dma_buf_size);
++extern tcc_alsa_lb_handle_t *delete_alsa_lb(tcc_alsa_lb_handle_t *h);
++
++#define ALB_START(H) do { if ((H)) { (H)->open_cnt++; } } while (0)
++#define ALB_STOP(H) do { if ((H)) { if ((H)->open_cnt > 0) (H)->open_cnt--; } } while (0)
++
++
++#endif /* __TCC_LOOPBACK_H__ */
++
+diff --git a/sound/soc/tcc/tcc-pcm.c b/sound/soc/tcc/tcc-pcm.c
+new file mode 100644
+index 0000000..21616de
+--- /dev/null
++++ b/sound/soc/tcc/tcc-pcm.c
+@@ -0,0 +1,918 @@
++/*
++ * linux/sound/soc/tcc/tcc-pcm.c
++ *
++ * Based on: linux/sound/arm/pxa2xx-pcm.c
++ * Author: <linux@telechips.com>
++ * Created: Nov 30, 2004
++ * Modified: Nov 25, 2008
++ * Description: ALSA PCM interface for the Intel PXA2xx chip
++ *
++ * Copyright: MontaVista Software, Inc.
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++
++#include <linux/delay.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++
++#include <bsp.h>
++#include <mach/hardware.h>
++#include <mach/irqs.h>
++#include <mach/tca_ckc.h>
++
++#include "tcc-i2s.h"
++#include "tcc-pcm.h"
++
++#include "tcc/tca_tcchwcontrol.h"
++
++#define alsa_dbg(f, a...) printk("== alsa-debug == " f, ##a)
++//#define alsa_dbg(f, a...)
++
++tcc_interrupt_info_x tcc_alsa_info;
++EXPORT_SYMBOL(tcc_alsa_info);
++
++static const struct snd_pcm_hardware tcc_pcm_hardware_play = {
++ .info = (SNDRV_PCM_INFO_MMAP
++ | SNDRV_PCM_INFO_MMAP_VALID
++ | SNDRV_PCM_INFO_INTERLEAVED
++ | SNDRV_PCM_INFO_BLOCK_TRANSFER
++ | SNDRV_PCM_INFO_PAUSE
++ | SNDRV_PCM_INFO_RESUME),
++
++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE),
++ .rates = SNDRV_PCM_RATE_8000_48000,
++ .rate_min = 8000,
++ .rate_max = 48000,
++ .channels_min = 2,
++#if defined(CONFIG_SND_SOC_WM8581) || defined(CONFIG_SND_SOC_WM8581_MODULE)
++ .channels_max = 8,
++#else
++ .channels_max = 2,
++#endif
++
++#if 1
++ .period_bytes_min = 8 * 1024,
++ .period_bytes_max = 8 * 1024,
++ .periods_min = 2,
++ .periods_max = 128,
++ .buffer_bytes_max = 64 * 1024,
++ .fifo_size = 16, //ignored
++#else
++ .period_bytes_min = 128,
++ .period_bytes_max = __play_buf_cnt * __play_buf_size,
++ .periods_min = 1,
++ .periods_max = __play_buf_cnt,
++ .buffer_bytes_max = __play_buf_cnt * __play_buf_size,
++ .fifo_size = 16, //ignored
++#endif
++};
++
++static const struct snd_pcm_hardware tcc_pcm_hardware_capture = {
++ .info = (SNDRV_PCM_INFO_MMAP
++ | SNDRV_PCM_INFO_MMAP_VALID
++ | SNDRV_PCM_INFO_INTERLEAVED
++ | SNDRV_PCM_INFO_BLOCK_TRANSFER
++ | SNDRV_PCM_INFO_PAUSE
++ | SNDRV_PCM_INFO_RESUME),
++
++ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
++ .rates = SNDRV_PCM_RATE_8000_48000,
++ .rate_min = 8000,
++ .rate_max = 48000,
++ .channels_min = 2,
++ .channels_max = 2,
++
++#if 1
++ .period_bytes_min = __cap_buf_size,
++ .period_bytes_max = __cap_buf_size,
++ .periods_min = __cap_buf_cnt,
++ .periods_max = __cap_buf_cnt,
++ .buffer_bytes_max = __cap_buf_cnt * __cap_buf_size,
++ .fifo_size = 16, //ignored
++#else
++ .period_bytes_min = 128,
++ .period_bytes_max = __cap_buf_cnt * __cap_buf_size,
++ .periods_min = 1,
++ .periods_max = __cap_buf_cnt,
++ .buffer_bytes_max = __cap_buf_cnt * __cap_buf_size,
++ .fifo_size = 16, //ignored
++#endif
++};
++
++/*** tea module ***/
++static unsigned int io_ckc_get_dai_clock(unsigned int freq)
++{
++ switch (freq) {
++ default:
++ case 44100: return ((441 * 256) / 10);
++ case 22000: return (((22050 * 256) / 100) / 10);
++ case 11000: return (((11025 * 256) / 100) / 10);
++ case 22050:
++ case 11025:
++ case 48000:
++ case 24000:
++ case 12000:
++ case 8000:
++ case 32000:
++ case 16000: return (((freq * 256) / 100) / 10);
++ }
++ return 0;
++}
++
++static int alsa_get_intr_num(struct snd_pcm_substream *substream)
++{
++ if (substream) {
++ return IRQ_ADMA;
++ }
++ return -1;
++}
++
++void tea_i2s_setclock(unsigned int clock_rate)
++{
++ unsigned int ckc = 0;
++ ckc = io_ckc_get_dai_clock(clock_rate);
++ tca_ckc_setperi(PERI_DAI, 1, ckc * 10, DIRECTPLL2);
++}
++EXPORT_SYMBOL(tea_i2s_setclock);
++
++void tea_spdif_setclock(unsigned int clock_rate)
++{
++ unsigned int daihz = 0;
++ unsigned tmpCfg, tmpStatus;
++ volatile ADMASPDIFTX *p_adma_spdif_tx_base = (volatile ADMASPDIFTX *)tcc_p2v(HwADMA_SPDIFTXBASE);
++
++ daihz = ((clock_rate * 512) / 100);
++ tca_ckc_setperi(PERI_SPDIF, ENABLE, daihz, DIRECTPLL2);
++
++ tmpCfg = p_adma_spdif_tx_base->TxConfig;
++ tmpStatus = p_adma_spdif_tx_base->TxChStat;
++
++ if (clock_rate == 44100) { /* 44.1KHz */
++ p_adma_spdif_tx_base->TxConfig = ((tmpCfg & 0xFFFF00FF) | (2 << 8));
++ p_adma_spdif_tx_base->TxChStat = ((tmpStatus & 0xFFFFFF3F) | (0/*FREQ_44_1KHz*/ << 6));
++ } else if (clock_rate == 48000) { /* 48KHz */
++ p_adma_spdif_tx_base->TxConfig = ((tmpCfg & 0xFFFF00FF) | (2 << 8));
++ p_adma_spdif_tx_base->TxChStat = ((tmpStatus & 0xFFFFFF3F) | (1/*FREQ_48KHz*/ << 6));
++ } else if (clock_rate == 32000) { /* 32KHz */
++ p_adma_spdif_tx_base->TxConfig = ((tmpCfg & 0xFFFF00FF) | (2 << 8));
++ p_adma_spdif_tx_base->TxChStat = ((tmpStatus & 0xFFFFFF3F) | (2/*FREQ_32KHz*/ << 6));
++ } else { /* Sampling Rate Converter */
++ p_adma_spdif_tx_base->TxConfig = ((tmpCfg & 0xFFFF00FF) | (2 << 8));
++ p_adma_spdif_tx_base->TxChStat = ((tmpStatus & 0xFFFFFF3F) | (3/*FREQ_SRC*/ << 6));
++ }
++}
++EXPORT_SYMBOL(tea_spdif_setclock);
++
++
++static void set_dma_outbuffer(unsigned int addr, unsigned int length, unsigned int period)
++{
++ volatile PADMA pADMA = (volatile PADMA)tcc_p2v(HwADMA_BASE);
++ unsigned long dma_buffer = 0;
++
++ alsa_dbg("%s, addr[0x%08X], len[%u], period[%u]\n", __func__, addr, length, period);
++ BITCLR(pADMA->ChCtrl, Hw28);
++
++ dma_buffer = 0xFFFFFF00 / (((tcc_pcm_hardware_play.buffer_bytes_max) >> 4) << 8);
++ dma_buffer = dma_buffer * (((tcc_pcm_hardware_play.buffer_bytes_max) >> 4) << 8);
++
++ pADMA->TxDaParam = dma_buffer | 4;
++
++ // generate interrupt when half of buffer was played
++ pADMA->TxDaTCnt = (period >> 0x04) - 1;
++
++ alsa_dbg("[%s] HwTxDaParam [0x%X]\n", __func__, (int)(dma_buffer | 4));
++ alsa_dbg("[%s] HwTxDaTCnt [%d]\n", __func__, ((period) >> 0x04) - 1);
++ pADMA->TxDaSar = addr;
++
++ pADMA->TransCtrl |= (Hw28 | Hw16 | Hw9 | (Hw0 | Hw1) | Hw24);
++
++ pADMA->RptCtrl = 0;
++ BITCLR(pADMA->RptCtrl, Hw31);
++ if (length < tcc_pcm_hardware_play.buffer_bytes_max) {
++ BITSET(pADMA->RptCtrl, (length / period) - 1);
++ }
++
++ pADMA->ChCtrl |= (Hw28 | Hw12 | Hw0);
++}
++
++static void set_dma_spdif_outbuffer(unsigned int addr, unsigned int length, unsigned int period)
++{
++ volatile PADMA pADMA = (volatile PADMA)tcc_p2v(HwADMA_BASE);
++ volatile ADMASPDIFTX *p_adma_spdif_tx_base = (volatile ADMASPDIFTX *)tcc_p2v(HwADMA_SPDIFTXBASE);
++ unsigned long dma_buffer = 0;
++
++ alsa_dbg("%s, addr[0x%08X], len[%u], period[%u]\n", __func__, addr, length, period);
++ BITCLR(pADMA->ChCtrl, Hw29);
++
++ memset((void *)p_adma_spdif_tx_base->UserData, 0, 24);
++ memset((void *)p_adma_spdif_tx_base->ChStatus, 0, 24);
++ memset((void *)p_adma_spdif_tx_base->TxBuffer, 0, 128);
++
++ dma_buffer = 0xFFFFFF00 / (((tcc_pcm_hardware_play.buffer_bytes_max) >> 4) << 8);
++ dma_buffer = dma_buffer * (((tcc_pcm_hardware_play.buffer_bytes_max) >> 4) << 8);
++
++ pADMA->TxSpParam = dma_buffer | 4;
++
++ // generate interrupt when half of buffer was played
++ pADMA->TxSpTCnt = (period >> 0x04) - 1;
++
++ alsa_dbg("[%s] HwTxDaParam [0x%X]\n", __func__, (int)(dma_buffer | 4));
++ alsa_dbg("[%s] HwTxDaTCnt [%d]\n", __func__, ((period) >> 0x04) - 1);
++ pADMA->TxSpSar = addr;
++
++ pADMA->TransCtrl |= (Hw28 | Hw17 | Hw11 | (Hw3 | Hw2));
++
++ pADMA->RptCtrl = 0;
++ BITCLR(pADMA->RptCtrl, Hw31);
++ if (length < tcc_pcm_hardware_play.buffer_bytes_max) {
++ BITSET(pADMA->RptCtrl, (length / period) - 1);
++ }
++
++ //pADMA->ChCtrl |= (Hw29 | Hw13 | Hw1);
++ //pADMA->ChCtrl |= (Hw29 | Hw13);
++
++
++ {
++ //unsigned int bitSet = 0x0;
++
++ p_adma_spdif_tx_base->TxConfig = HwZERO
++ //16bits
++ |Hw9|Hw8 //Clock Divider Ratio is 2(384*fs to default)
++ //| Hw7 | Hw6 //User Data Enalbe Bits is set reserved
++ //| Hw5 | Hw4 //Channel Status Enalbe Bits is set reserved
++ //| Hw2 //interrupt output enable
++ | Hw1 //data being valid
++ //| Hw0 //enable the transmission
++ ;
++ //Set SPDIF Transmit Channel Status
++ p_adma_spdif_tx_base->TxChStat |= HwZERO
++ //| 0x00000400 // Store Channel Status bit
++ //| 0x00000200 // Store User Data bit
++ //| 0x00000100 // Store Validity bit
++ //44.1kHz
++ //| Hw3 //Original/Commercially Pre-recored data
++ //| Hw2 //Pre-emphasis is 50/15us
++ //| Hw1 //Copy permitted
++ //Audio format
++ ;
++
++ //p_adma_spdif_tx_base->TxIntMask = HwZERO
++ // | Hw2//Higher Data buffer is empty
++ // | Hw1//Lower Data buffer is empty
++ // ;
++
++ p_adma_spdif_tx_base->DMACFG = Hw7;
++ msleep(100);
++
++ p_adma_spdif_tx_base->DMACFG = HwZERO
++ //| Hw14 //Swap Sample Enable
++ | Hw13 //Read Address 16bit Mode
++ | Hw11 //DMA Request enable for user data buffer
++ | Hw10 //DMA Request enable for sample data buffer
++ //| Hw8 //Enable address
++ //| Hw3 //FIFO Threshold for DMA request
++ | Hw1| Hw0 // [3:0] FIFO Threshold for DMA Request
++ ;
++
++ /* Initialize Sample Data Buffer */
++ //while(p_adma_spdif_tx_base->DMACFG & 0x00300000) p_adma_spdif_tx_base->TxBuffer[0] = 0;
++ p_adma_spdif_tx_base->TxBuffer[0] = 0;
++
++ p_adma_spdif_tx_base->TxConfig |= HwZERO
++ //| Hw2 //interrupt output enable
++ | Hw1 //data being valid
++ | Hw0 //enable the transmission
++ ;
++
++#if 0
++ while((p_adma_spdif_tx_base->DMACFG & 0x00100000)); /* Wait until first data TX */
++ while((p_adma_spdif_tx_base->DMACFG & 0x001F0000) > 0x00080000);
++
++ while(!(p_adma_spdif_tx_base->TxIntStat & Hw1)); /* Wait for Interrupt Status */
++#endif
++
++ p_adma_spdif_tx_base->TxIntStat = 0x1E; /* Clear Interrupt Status */
++
++#if 0
++ p_adma_spdif_tx_base->TxConfig |= HwZERO
++ | Hw2 //interrupt output enable
++ | Hw1 //data being valid
++ //| Hw0 //enable the transmission
++ ;
++
++ // Tx channel Control Register Setting
++ //Start DMA
++ bitSet = ( HwZERO
++ |Hw1 //Interrupt Enable of SPDIF Tx
++ );
++
++ pADMA->ChCtrl |= bitSet;
++#endif
++ }
++
++ alsa_dbg("%s, spdif current addr[0x%08X] \n", __func__, pADMA->TxSpCsar);
++ pADMA->ChCtrl |= (Hw13);
++}
++
++static void set_dma_inbuffer(unsigned int addr, unsigned int length, unsigned int period)
++{
++ volatile PADMA pADMA = (volatile PADMA)tcc_p2v(HwADMA_BASE);
++ unsigned long dma_buffer = 0;
++
++ alsa_dbg("%s, addr[0x%08X], len[%d]\n", __func__, addr, length);
++
++ BITCLR(pADMA->ChCtrl, Hw30);
++
++ dma_buffer = 0xFFFFFF00 / (((tcc_pcm_hardware_capture.buffer_bytes_max) >> 4) << 8);
++ dma_buffer = dma_buffer * (((tcc_pcm_hardware_capture.buffer_bytes_max) >> 4) << 8);
++
++ //dma_buffer = 0xFFFFF8000;
++ pADMA->RxDaParam = dma_buffer | 4;
++
++ // generate interrupt when half of buffer was filled
++ pADMA->RxDaTCnt = (period >> 0x04) - 1;
++
++ alsa_dbg("[%s] HwRxDaParam [0x%X]\n", __func__, (int)dma_buffer | 4);
++ alsa_dbg("[%s] HwRxDaTCnt [%d]\n", __func__, ((period) >> 0x04) - 1);
++ pADMA->RxDaDar = addr;
++
++ pADMA->TransCtrl |= (Hw29 | Hw18 | Hw13 | (Hw4 | Hw5) | Hw26);
++
++ //pADMA->RptCtrl = 0;
++ BITCLR(pADMA->RptCtrl, Hw31);
++ if (length<tcc_pcm_hardware_capture.buffer_bytes_max) {
++ BITSET(pADMA->RptCtrl, (length / period) - 1);
++ }
++
++ pADMA->ChCtrl |= (Hw30 | Hw14 | Hw2);
++}
++
++static irqreturn_t tcc_dma_done_handler(int irq, void *dev_id)
++{
++ volatile PADMA pADMA = (volatile PADMA)tcc_p2v(HwADMA_BASE);
++ struct snd_pcm_runtime *runtime;
++ struct tcc_runtime_data *prtd;
++ dma_addr_t cur_ptr;
++ int dmaInterruptSource = 0;
++
++ unsigned long reg_temp = 0;
++
++ if (pADMA->IntStatus & (Hw4 | Hw0)) {
++ dmaInterruptSource |= DMA_CH_OUT;
++ reg_temp |= Hw4 | Hw0;
++ }
++ if (pADMA->IntStatus & (Hw6 | Hw2)) {
++ dmaInterruptSource |= DMA_CH_IN;
++ reg_temp |= Hw6 | Hw2;
++ }
++ if (pADMA->IntStatus & (Hw5 | Hw1)) {
++ dmaInterruptSource |= DMA_CH_SPDIF;
++ reg_temp |= Hw5 | Hw1;
++ }
++
++ if (reg_temp) {
++ pADMA->IntStatus |= reg_temp;
++ }
++
++ if ((dmaInterruptSource & DMA_CH_SPDIF)
++ && (tcc_alsa_info.flag & TCC_RUNNING_SPDIF)) {
++
++ snd_pcm_period_elapsed(tcc_alsa_info.spdif_ptr);
++
++ runtime = tcc_alsa_info.spdif_ptr->runtime;
++ prtd = (struct tcc_runtime_data *)runtime->private_data;
++
++ cur_ptr = pADMA->TxSpCsar;
++ if (prtd->dma_buffer_end <= cur_ptr) {
++ BITSET(pADMA->ChCtrl, Hw29);
++ }
++ }
++
++ if ((dmaInterruptSource & DMA_CH_OUT)
++ && (tcc_alsa_info.flag & TCC_RUNNING_PLAY)) {
++ snd_pcm_period_elapsed(tcc_alsa_info.play_ptr);
++
++ runtime = tcc_alsa_info.play_ptr->runtime;
++ prtd = (struct tcc_runtime_data *) runtime->private_data;
++
++ cur_ptr = pADMA->TxDaCsar;
++ if (prtd->dma_buffer_end <= cur_ptr) {
++ BITSET(pADMA->ChCtrl, Hw28);
++ }
++ }
++ if ((dmaInterruptSource & DMA_CH_IN)
++ && (tcc_alsa_info.flag & TCC_RUNNING_CAPTURE)) {
++ snd_pcm_period_elapsed(tcc_alsa_info.cap_ptr);
++
++ runtime = tcc_alsa_info.cap_ptr->runtime;
++ prtd = (struct tcc_runtime_data *)runtime->private_data;
++
++ cur_ptr = pADMA->RxDaCdar;
++ if (prtd->dma_buffer_end <= cur_ptr) {
++ BITSET(pADMA->ChCtrl, Hw30);
++ }
++ }
++
++ return IRQ_HANDLED;
++}
++
++static int tcc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct tcc_runtime_data *prtd = runtime->private_data;
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct tcc_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
++ size_t totsize = params_buffer_bytes(params);
++ //size_t period = params_period_bytes(params);
++ size_t period_bytes = params_period_bytes(params);
++ int chs = params_channels(params);
++ int ret = 0;
++
++ /* return if this is a bufferless transfer e.g.
++ * codec <--> BT codec or GSM modem -- lg FIXME */
++ if (!dma)
++ return 0;
++
++ /* this may get called several times by oss emulation
++ * with different params */
++ if (prtd->params == NULL) {
++ prtd->params = dma;
++
++ mutex_lock(&(tcc_alsa_info.mutex));
++ if (!(tcc_alsa_info.flag & TCC_INTERRUPT_REQUESTED)) {
++ ret = request_irq(alsa_get_intr_num(substream),
++ tcc_dma_done_handler,
++ IRQF_SHARED,
++ "alsa-audio",
++ &tcc_alsa_info);
++ if (ret < 0) {
++ mutex_unlock(&(tcc_alsa_info.mutex));
++ return -EBUSY;
++ }
++ tcc_alsa_info.flag |= TCC_INTERRUPT_REQUESTED;
++ }
++ mutex_unlock(&(tcc_alsa_info.mutex));
++
++ if (substream->pcm->device == __SPDIF_DEV_NUM__) {
++ prtd->dma_ch = DMA_CH_SPDIF;
++ } else {
++ prtd->dma_ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? DMA_CH_OUT : DMA_CH_IN;
++ }
++ } else {
++ /* should works more? */
++ }
++
++ //DMA ¹öÆÛ ÄÁÆ®·Ñ
++ //DMA Àü¼Û ¹öÆÛ Æ÷ÀÎÅÍ ÃʱâÈ­
++
++ //printk("ssssssssssssssssssssssubstream addr [%p]\n", substream);
++ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
++ runtime->dma_bytes = totsize;
++
++ prtd->dma_buffer_end = runtime->dma_addr + totsize;
++ prtd->dma_buffer = runtime->dma_addr;
++ alsa_dbg("\n totsize=0x%X period=0x%X period num=%d\n", totsize, period_bytes, params_periods(params));
++
++
++ if (substream->pcm->device == __SPDIF_DEV_NUM__) {
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ set_dma_spdif_outbuffer(substream->dma_buffer.addr, totsize, period_bytes);
++ } else {
++ printk("cannot support S/PDIF capture !!!!!\n");
++ return -1;
++ }
++ } else {
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ set_dma_outbuffer(substream->dma_buffer.addr, totsize, period_bytes);
++ } else {
++ set_dma_inbuffer(substream->dma_buffer.addr, totsize, period_bytes);
++ }
++ }
++
++ {
++ volatile PADMA pADMA = (volatile PADMA)tcc_p2v(HwADMA_BASE);
++ volatile PADMADAI pADMA_DAI = (volatile PADMADAI)tcc_p2v(HwADMA_DAIBASE);
++ if (chs > 2) {
++ pADMA_DAI->DAMR |= (Hw29 | Hw28);
++ pADMA->RptCtrl |= (Hw26 | Hw25 | Hw24);
++ pADMA->ChCtrl |= (Hw24 | Hw21 | Hw20);
++ } else {
++ BITCLR(pADMA_DAI->DAMR, (Hw29 | Hw28));
++ BITCLR(pADMA->RptCtrl, (Hw26 | Hw25 | Hw24));
++ BITCLR(pADMA->ChCtrl,(Hw24 | Hw21 | Hw20));
++ }
++ }
++ printk("======================================\n");
++ printk(" set [%d] channels\n", chs);
++ printk("======================================\n");
++ return ret;
++}
++
++static int tcc_pcm_hw_free(struct snd_pcm_substream *substream)
++{
++ struct tcc_runtime_data *prtd = substream->runtime->private_data;
++
++ if (prtd->dma_ch) {
++ snd_pcm_set_runtime_buffer(substream, NULL);
++ //Ãß°¡ ÇÊ¿ä ??
++ }
++
++ return 0;
++}
++
++static int tcc_pcm_prepare(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++
++ //DMA initialize
++
++ /* Disable Noise */
++ //memset((void *)(&HwDADO_L0), 0, 32);
++
++#if 0
++ if (substream->pcm->device == __SPDIF_DEV_NUM__) {
++ volatile PADMA pADMA = (volatile PADMA)tcc_p2v(HwADMA_BASE);
++ printk("---------------------------------\n");
++ printk("* spdif current addr [0x%X] - prepare\n", pADMA->TxSpCsar);
++ printk("---------------------------------\n");
++ }
++#endif
++
++ memset(runtime->dma_area, 0x00, runtime->dma_bytes);
++
++ return 0;
++}
++
++static int tcc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
++{
++ //struct tcc_runtime_data *prtd = substream->runtime->private_data;
++ // audio_stream_t *s = &output_stream;
++ int ret = 0;
++ volatile PADMADAI pDAI = (volatile PADMADAI)tcc_p2v(HwADMA_DAIBASE);
++ volatile PADMA pADMA = (volatile PADMA)tcc_p2v(HwADMA_BASE);
++ volatile ADMASPDIFTX *p_adma_spdif_tx_base = (volatile ADMASPDIFTX *)tcc_p2v(HwADMA_SPDIFTXBASE);
++
++ switch (cmd) {
++ case SNDRV_PCM_TRIGGER_START:
++ case SNDRV_PCM_TRIGGER_RESUME:
++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++ if (substream->pcm->device == __SPDIF_DEV_NUM__) {
++#if 0
++ //tca_i2s_start(pDAI, p_adma_spdif_tx_base, 0);
++ p_adma_spdif_tx_base->TxIntStat = 0x1E; /* Clear Interrupt Status */
++ p_adma_spdif_tx_base->TxConfig |= HwZERO | Hw0;
++ BITSET(pADMA->ChCtrl, Hw1 | Hw29);
++#else
++ p_adma_spdif_tx_base->TxConfig |= HwZERO | Hw0 | Hw2 | Hw1;
++ BITSET(pADMA->ChCtrl, Hw1 | Hw29);
++#endif
++ } else {
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ //tca_i2s_start(pDAI, p_adma_spdif_tx_base, 0);
++ pDAI->DAMR |= Hw14;
++ BITSET(pADMA->ChCtrl, Hw0 | Hw28);
++ } else {
++ //tca_i2s_start(pDAI, p_adma_spdif_tx_base, 1);
++ pDAI->DAMR |= Hw13;
++ BITSET(pADMA->ChCtrl, Hw2 | Hw30);
++ }
++ }
++ break;
++
++ case SNDRV_PCM_TRIGGER_STOP:
++ case SNDRV_PCM_TRIGGER_SUSPEND:
++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++ if (substream->pcm->device == __SPDIF_DEV_NUM__) {
++#if 0
++ //tca_i2s_stop(pDAI, p_adma_spdif_tx_base, 0);
++ p_adma_spdif_tx_base->TxConfig &= ~Hw0;
++ BITCLR(pADMA->ChCtrl, Hw1);
++#else
++ p_adma_spdif_tx_base->TxConfig &= ~(Hw0 | Hw2 | Hw1);
++ BITCLR(pADMA->ChCtrl, Hw1 | Hw29);
++#endif
++ } else {
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ //tca_i2s_stop(pDAI, p_adma_spdif_tx_base, 0);
++ pDAI->DAMR &= ~Hw14;
++ BITCLR(pADMA->ChCtrl, Hw0);
++ } else {
++ //tca_i2s_stop(pDAI, p_adma_spdif_tx_base, 1);
++ pDAI->DAMR &= ~Hw13;
++ BITCLR(pADMA->ChCtrl, Hw2);
++ }
++ }
++ if (!(tcc_alsa_info.flag)) {
++ BITCLR(pADMA->ChCtrl, Hw28);
++ }
++ break;
++
++ default:
++ ret = -EINVAL;
++ }
++ return ret;
++}
++
++
++//buffer point update
++//current position range 0-(buffer_size-1)
++static snd_pcm_uframes_t tcc_pcm_pointer(struct snd_pcm_substream *substream)
++{
++ volatile PADMA pADMA = (volatile PADMA)tcc_p2v(HwADMA_BASE);
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ //struct tcc_runtime_data *prtd = runtime->private_data;
++ snd_pcm_uframes_t x;
++ dma_addr_t ptr = 0;
++
++ if (substream->pcm->device == __SPDIF_DEV_NUM__) {
++ ptr = pADMA->TxSpCsar;
++ } else {
++ ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? pADMA->TxDaCsar : pADMA->RxDaCdar;
++ }
++
++ x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
++
++ if (x < runtime->buffer_size) {
++ return x;
++ }
++ return 0;
++}
++
++static int tcc_pcm_open(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct tcc_runtime_data *prtd;
++ int ret;
++
++ mutex_lock(&(tcc_alsa_info.mutex));
++ if (substream->pcm->device == __SPDIF_DEV_NUM__) {
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ tcc_alsa_info.flag |= TCC_RUNNING_SPDIF;
++ tcc_alsa_info.spdif_ptr = substream;
++ snd_soc_set_runtime_hwparams(substream, &tcc_pcm_hardware_play);
++ } else {
++ printk("cannot support S/PDIF capture !!!!!\n");
++ return -1;
++ }
++ } else {
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ tcc_alsa_info.flag |= TCC_RUNNING_PLAY;
++ tcc_alsa_info.play_ptr = substream;
++ snd_soc_set_runtime_hwparams(substream, &tcc_pcm_hardware_play);
++ } else {
++ tcc_alsa_info.flag |= TCC_RUNNING_CAPTURE;
++ tcc_alsa_info.cap_ptr = substream;
++ snd_soc_set_runtime_hwparams(substream, &tcc_pcm_hardware_capture);
++ }
++ }
++ mutex_unlock(&(tcc_alsa_info.mutex));
++
++ prtd = kzalloc(sizeof(struct tcc_runtime_data), GFP_KERNEL);
++
++ if (prtd == NULL) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ runtime->private_data = prtd;
++
++ return 0;
++ kfree(prtd);
++out:
++ return ret;
++}
++
++static int tcc_pcm_close(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct tcc_runtime_data *prtd = runtime->private_data;
++ volatile PADMADAI pDAI = (volatile PADMADAI)tcc_p2v(HwADMA_DAIBASE);
++ volatile ADMASPDIFTX *p_adma_spdif_tx_base = (volatile ADMASPDIFTX *)tcc_p2v(HwADMA_SPDIFTXBASE);
++
++ mutex_lock(&(tcc_alsa_info.mutex));
++ if (substream->pcm->device == __SPDIF_DEV_NUM__) {
++ tcc_alsa_info.flag &= ~TCC_RUNNING_SPDIF;
++ //tca_i2s_stop(pDAI, p_adma_spdif_tx_base, 0);
++ p_adma_spdif_tx_base->TxConfig &= ~Hw0;
++
++#if 0
++ {
++ volatile PADMA pADMA = (volatile PADMA)tcc_p2v(HwADMA_BASE);
++ printk("---------------------------------\n");
++ printk("# spdif current addr [0x%X] - close\n", pADMA->TxSpCsar);
++ printk("---------------------------------\n");
++ }
++#endif
++
++ } else {
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ tcc_alsa_info.flag &= ~TCC_RUNNING_PLAY;
++ //tca_i2s_stop(pDAI, p_adma_spdif_tx_base, 0);
++ pDAI->DAMR &= ~Hw14;
++ } else {
++ tcc_alsa_info.flag &= ~TCC_RUNNING_CAPTURE;
++ //tca_i2s_stop(pDAI, p_adma_spdif_tx_base, 1);
++ pDAI->DAMR &= ~Hw13;
++ }
++ }
++ // dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,);
++
++ if (prtd) {
++ kfree(prtd);
++ }
++
++ if (tcc_alsa_info.flag & TCC_INTERRUPT_REQUESTED) {
++ if (!(tcc_alsa_info.flag & (TCC_RUNNING_SPDIF | TCC_RUNNING_PLAY | TCC_RUNNING_CAPTURE))) {
++ free_irq(alsa_get_intr_num(substream), &tcc_alsa_info);
++ tcc_alsa_info.flag &= ~TCC_INTERRUPT_REQUESTED;
++ }
++ }
++ mutex_unlock(&(tcc_alsa_info.mutex));
++
++ return 0;
++}
++
++static int tcc_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ return dma_mmap_writecombine(substream->pcm->card->dev,
++ vma,
++ runtime->dma_area,
++ runtime->dma_addr,
++ runtime->dma_bytes);
++}
++
++struct snd_pcm_ops tcc_pcm_ops = {
++ .open = tcc_pcm_open,
++ .close = tcc_pcm_close,
++ .ioctl = snd_pcm_lib_ioctl,
++ .hw_params = tcc_pcm_hw_params,
++ .hw_free = tcc_pcm_hw_free,
++ .prepare = tcc_pcm_prepare,
++ .trigger = tcc_pcm_trigger,
++ .pointer = tcc_pcm_pointer,
++ .mmap = tcc_pcm_mmap,
++};
++
++static int tcc_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
++{
++ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
++ struct snd_dma_buffer *buf = &substream->dma_buffer;
++ size_t size = 0;
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ size = tcc_pcm_hardware_play.buffer_bytes_max;
++ } else {
++ size = tcc_pcm_hardware_capture.buffer_bytes_max;
++ }
++
++ buf->dev.type = SNDRV_DMA_TYPE_DEV;
++ buf->dev.dev = pcm->card->dev;
++ buf->private_data = NULL;
++
++ alsa_dbg("tcc_pcm_preallocate_dma_buffer size [%d]\n", size);
++ buf->area = dma_alloc_writecombine(pcm->card->dev, size, &buf->addr, GFP_KERNEL);
++ if (!buf->area) {
++ return -ENOMEM;
++ }
++
++ buf->bytes = size;
++
++ return 0;
++}
++
++
++static void tcc_pcm_free_dma_buffers(struct snd_pcm *pcm)
++{
++ struct snd_pcm_substream *substream;
++ struct snd_dma_buffer *buf;
++ int stream;
++
++ for (stream = 0; stream < 2; stream++) {
++ substream = pcm->streams[stream].substream;
++ if (!substream) { continue; }
++
++ buf = &substream->dma_buffer;
++ if (!buf->area) { continue; }
++
++ dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area, buf->addr);
++ buf->area = NULL;
++ }
++ mutex_init(&(tcc_alsa_info.mutex));
++}
++
++static u64 tcc_pcm_dmamask = DMA_32BIT_MASK;
++
++int tcc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm)
++{
++ int ret = 0;
++
++ memset(&tcc_alsa_info, 0, sizeof(tcc_interrupt_info_x));
++ mutex_init(&(tcc_alsa_info.mutex));
++
++ if (!card->dev->dma_mask) {
++ card->dev->dma_mask = &tcc_pcm_dmamask;
++ }
++ if (!card->dev->coherent_dma_mask) {
++ card->dev->coherent_dma_mask = DMA_32BIT_MASK;
++ }
++ if (dai->playback.channels_min) {
++ ret = tcc_pcm_preallocate_dma_buffer(pcm,SNDRV_PCM_STREAM_PLAYBACK);
++ if (ret) { goto out; }
++ }
++
++ if (dai->capture.channels_min) {
++ ret = tcc_pcm_preallocate_dma_buffer(pcm,SNDRV_PCM_STREAM_CAPTURE);
++ if (ret) { goto out; }
++ }
++out:
++ return ret;
++}
++
++#if 0
++int tcc_pcm_suspend(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai)
++{
++ return 0;
++}
++
++int tcc_pcm_resume(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai)
++{
++ return 0;
++}
++#endif
++
++struct snd_soc_platform tcc_soc_platform = {
++ .name = "tcc-audio",
++ .pcm_ops = &tcc_pcm_ops,
++ .pcm_new = tcc_pcm_new,
++ .pcm_free = tcc_pcm_free_dma_buffers,
++#if 0
++ .suspend = tcc_pcm_suspend,
++ .resume = tcc_pcm_resume,
++#endif
++};
++
++EXPORT_SYMBOL_GPL(tcc_soc_platform);
++
++
++/************************************************************************
++ * Dummy function for S/PDIF. This is a codec part.
++************************************************************************/
++static int iec958_pcm_prepare(struct snd_pcm_substream *substream) { return 0; }
++static int iec958_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { return 0; }
++static void iec958_shutdown(struct snd_pcm_substream *substream) { }
++static int iec958_mute(struct snd_soc_dai *dai, int mute) { return 0; }
++static int iec958_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { return 0; }
++static int iec958_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { return 0; }
++
++struct snd_soc_dai iec958_dai = {
++ .name = "IEC958",
++ .playback = {
++ .stream_name = "Playback",
++ .channels_min = 1,
++ .channels_max = 2,
++ .rates = (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000),
++ .formats = (SNDRV_PCM_FMTBIT_S16_LE),},
++ .ops = {
++ .prepare = iec958_pcm_prepare,
++ .hw_params = iec958_hw_params,
++ .shutdown = iec958_shutdown,
++ },
++ .dai_ops = {
++ .digital_mute = iec958_mute,
++ .set_sysclk = iec958_set_dai_sysclk,
++ .set_fmt = iec958_set_dai_fmt,
++ }
++};
++EXPORT_SYMBOL_GPL(iec958_dai);
++/***********************************************************************/
++
++
++MODULE_AUTHOR("Telechips");
++MODULE_DESCRIPTION("Telechips TCC PCM DMA module");
++MODULE_LICENSE("GPL");
++
+diff --git a/sound/soc/tcc/tcc-pcm.h b/sound/soc/tcc/tcc-pcm.h
+new file mode 100644
+index 0000000..06ee0d2
+--- /dev/null
++++ b/sound/soc/tcc/tcc-pcm.h
+@@ -0,0 +1,119 @@
++/*
++ * linux/sound/soc/tcc/tcc-pcm.h
++ *
++ * Based on: linux/sound/arm/pxa2xx-pcm.h
++ * Author: <linux@telechips.com>
++ * Created: Nov 30, 2004
++ * Modified: Nov 25, 2008
++ * Description: ALSA PCM interface for the Intel PXA2xx chip
++ *
++ * Copyright: MontaVista Software, Inc.
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#ifndef _tcc_PCM_H
++#define _tcc_PCM_H
++
++#include <mach/hardware.h>
++
++#define __play_buf_size 16384
++#define __play_buf_cnt 4
++
++#define __cap_buf_size 4096
++#define __cap_buf_cnt 16
++
++#define DMA_CH_OUT 0x0001
++#define DMA_CH_IN 0x0002
++#define DMA_CH_SPDIF 0x0004
++
++#define TCC_INTERRUPT_REQUESTED 0x0001
++#define TCC_RUNNING_PLAY 0x0002
++#define TCC_RUNNING_CAPTURE 0x0004
++#define TCC_RUNNING_SPDIF 0x0008
++
++#define TCC_TX_INTERRUPT_REQUESTED 0x0010
++#define TCC_RX_INTERRUPT_REQUESTED 0x0020
++
++#define __SPDIF_DEV_NUM__ 1
++
++#define NEXT_BUF(_s_,_b_) { \
++ (_s_)->_b_##_idx++; \
++ (_s_)->_b_##_idx %= (_s_)->nbfrags; \
++ (_s_)->_b_ = (_s_)->buffers + (_s_)->_b_##_idx; }
++
++typedef struct _tcc_interrupt_info_x {
++ struct snd_pcm_substream *play_ptr;
++ struct snd_pcm_substream *cap_ptr;
++ struct snd_pcm_substream *spdif_ptr;
++ struct mutex mutex;
++ unsigned int flag;
++} tcc_interrupt_info_x;
++
++extern tcc_interrupt_info_x tcc_alsa_info;
++
++struct tcc_pcm_dma_params {
++ char *name; /* stream identifier */
++ int channel;
++ dma_addr_t dma_addr;
++ int dma_size; /* Size of the DMA transfer */
++};
++
++struct tcc_runtime_data {
++ int dma_ch;
++ struct tcc_pcm_dma_params *params;
++ dma_addr_t dma_buffer; /* physical address of dma buffer */
++ dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */
++ size_t period_size;
++ size_t nperiod;
++ dma_addr_t period_ptr; /* physical address of next period */
++};
++
++typedef struct {
++ int size; /* buffer size */
++ char *start; /* point to actual buffer */
++ dma_addr_t dma_addr; /* physical buffer address */
++ struct semaphore sem; /* down before touching the buffer */
++ int master; /* owner for buffer allocation, contain size when true */
++ int dma_size;
++} audio_buf_t;
++
++typedef struct {
++ audio_buf_t *buffers; /* pointer to audio buffer structures */
++ audio_buf_t *buf; /* current buffer used by read/write */
++ u_int buf_idx; /* index for the pointer above */
++ u_int play_idx; /* the current buffer that playing */
++ u_int fragsize; /* fragment i.e. buffer size */
++ u_int nbfrags; /* nbr of fragments */
++} audio_stream_t;
++
++typedef struct {
++ char *addr;
++ dma_addr_t dma_addr;
++ int buf_size; // total size of DMA
++ int page_size; // size of each page
++ int dma_half; // 0 or 1, mark the next available buffer
++}dma_buf_t;
++
++extern void tea_i2s_setclock(unsigned int clock_rate);
++extern void tea_spdif_setclock(unsigned int clock_rate);
++extern struct snd_soc_dai iec958_dai;
++
++/* platform data */
++//extern struct snd_soc_platform tcc_soc_platform;
++
++#endif
+diff --git a/sound/soc/tcc/tcc8900/tca_tcchwcontrol.c b/sound/soc/tcc/tcc8900/tca_tcchwcontrol.c
+new file mode 100644
+index 0000000..b7b83b9
+--- /dev/null
++++ b/sound/soc/tcc/tcc8900/tca_tcchwcontrol.c
+@@ -0,0 +1,629 @@
++
++/****************************************************************************
++ * FileName : tca_tcchwcontrol.c
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++/*****************************************************************************
++*
++* includes
++*
++******************************************************************************/
++#include <linux/module.h>
++#include <bsp.h>
++#include "tca_tcchwcontrol.h"
++#if defined(SPDIF_2CH_ONLY)
++unsigned int OutputADMIntStatusForSPDIF = 0;
++int OutputADMADAITxIntCnt = 0, OutputADMASPDIFTxIntCnt = 0;
++#endif
++/*****************************************************************************
++* Function Name : tca_dma_clrstatus()
++******************************************************************************
++* Desription :
++* Parameter :
++* Return : success(SUCCESS)
++******************************************************************************/
++unsigned int tca_dma_clrstatus(void *pADMABaseAddr, unsigned int nDmanum)
++{
++ ADMA *pStrADMABaseReg = (ADMA *)pADMABaseAddr;
++ if (nDmanum) {
++ //If you use this register to write, set interrupt status is cleared.
++ pStrADMABaseReg->IntStatus |= (Hw6 | Hw2);
++ }
++ else
++ {
++#if defined(SPDIF_2CH_ONLY)
++ pStrADMABaseReg->IntStatus |= (Hw5 | Hw1);
++#else
++ //If you use this register to write, set interrupt status is cleared.
++ pStrADMABaseReg->IntStatus |= (Hw4 | Hw0);
++#endif
++ }
++
++ return 0/*SUCCESS*/;
++}
++
++/*****************************************************************************
++* Function Name : tca_irq_getnumber()
++******************************************************************************
++* Desription :
++* Parameter :
++* Return : DMA number
++******************************************************************************/
++unsigned int tca_irq_getnumber(void)
++{
++ return IRQ_ADMA; // audio output interrupt.
++}
++
++/*****************************************************************************
++* Function Name : tca_dma_getstatus()
++******************************************************************************
++* Desription : dma status check
++* Parameter :
++* Return :
++******************************************************************************/
++unsigned int tca_dma_getstatus(void *pADMABaseAddr, unsigned int nDmanum)
++{
++ ADMA *pStrADMABaseReg = (ADMA *)pADMABaseAddr;
++#if defined(SPDIF_2CH_ONLY)
++ return nDmanum ? (pStrADMABaseReg->IntStatus & (Hw6 | Hw2)) : (pStrADMABaseReg->IntStatus & (Hw5 | Hw1));
++#else
++ return nDmanum ? (pStrADMABaseReg->IntStatus & (Hw6 | Hw2)) : (pStrADMABaseReg->IntStatus & (Hw4 | Hw0));
++#endif
++}
++
++/*****************************************************************************
++* Function Name : tca_tcc_initport()
++******************************************************************************
++* Desription : GPIO port init
++* Parameter :
++* Return :
++******************************************************************************/
++unsigned int tca_tcc_initport(void *pGPIOBaseAddr)
++{
++ GPIO *pStrGPIOBaseReg = (GPIO *)pGPIOBaseAddr;
++
++ //Set GPIO for Audio
++ pStrGPIOBaseReg->GPDFN0 |= 0
++ | Hw0 //BCLK(1)
++ | Hw4 //LRCLK(1)
++ | Hw8 //MCLK(1)
++ | Hw12 //DAO0(1)
++ | Hw16 //DAI0(1)
++ ;
++ pStrGPIOBaseReg->GPDFN1 |= 0
++#if defined(SPDIF_2CH_ONLY)
++ | Hw12 //SPD_TX(1)
++#endif
++ ;
++ return 0/*SUCCESS*/;
++}
++EXPORT_SYMBOL(tca_tcc_initport);
++
++/*****************************************************************************
++* Function Name : tca_dma_setsrcaddr()
++******************************************************************************
++* Desription : dma set source address
++* Parameter : dma number
++* Return : address
++******************************************************************************/
++unsigned int tca_dma_setsrcaddr(void *pADMABaseAddr, unsigned int DADONum, unsigned int nDmanum, unsigned int nAddr)
++{
++ ADMA *pStrADMABaseReg = (ADMA *)pADMABaseAddr;
++
++ switch(DADONum)
++ {
++ case 0:
++ pStrADMABaseReg->TxDaSar = nAddr;
++ break;
++ case 1:
++ pStrADMABaseReg->TxDaSar1 = nAddr;
++ break;
++ case 2:
++ pStrADMABaseReg->TxDaSar2 = nAddr;
++ break;
++ case 3:
++ pStrADMABaseReg->TxDaSar3 = nAddr;
++ break;
++#if defined(SPDIF_2CH_ONLY)
++ case 4:
++ pStrADMABaseReg->TxSpSar = nAddr;
++#endif
++ default:
++ break;
++ }
++
++ return 0/*SUCCESS*/;
++}
++
++/*****************************************************************************
++* Function Name : tca_dma_setdestaddr()
++******************************************************************************
++* Desription : set dest address
++* Parameter : dma number, dest address
++* Return : SUCCESS
++******************************************************************************/
++unsigned int tca_dma_setdestaddr(void *pADMABaseAddr, unsigned int DADINum, unsigned int nDmanum, unsigned int nAddr)
++{
++ ADMA *pStrADMABaseReg = (ADMA *)pADMABaseAddr;
++
++ switch(DADINum)
++ {
++ case 0:
++ pStrADMABaseReg->RxDaDar = nAddr;
++ break;
++ case 1:
++ pStrADMABaseReg->RxDaDar1 = nAddr;
++ break;
++ case 2:
++ pStrADMABaseReg->RxDaDar2 = nAddr;
++ break;
++ case 3:
++ pStrADMABaseReg->RxDaDar3 = nAddr;
++ break;
++ default:
++ break;
++ }
++ return 0/*SUCCESS*/;
++}
++
++/*****************************************************************************
++* Function Name : tca_dma_control()
++******************************************************************************
++* Desription : dma input control
++* Parameter : mode 1: on, 0:off
++* Return : success(SUCCESS)
++******************************************************************************/
++unsigned int tca_dma_control(void *pADMABaseAddr, void *pADMADAIBaseAddr, void *pADMASPDIFTXBaseAddr,
++ unsigned int nMode, unsigned int nDmanum, unsigned int nInMode)
++{
++ ADMA *pStrADMABaseReg = (ADMA *)pADMABaseAddr;
++ //ADMADAI *pStrADMADAIBaseReg = (ADMADAI *)pADMADAIBaseAddr;
++ ADMASPDIFTX *pStrADMASPDIFTxBaseReg = (ADMASPDIFTX *)pADMASPDIFTXBaseAddr;
++
++ if(nMode)
++ { //run
++ tca_i2s_start(pADMADAIBaseAddr, pADMASPDIFTXBaseAddr, nInMode);
++#if defined(_MULTIL_DAO_INCLUDE_)
++ pStrADMABaseReg->RptCtrl = Hw26|Hw25|Hw24;//DAI Buffer Threshod is set Multi-Port
++#else
++ pStrADMABaseReg->RptCtrl = 0;//Initialize repeat control register
++#endif
++ if(nInMode)//input
++ {
++ pStrADMABaseReg->ChCtrl |= 0
++ | Hw30 //DMA Channel enable of DAI Rx
++#if defined(_MULTIL_DAO_INCLUDE_)
++ | Hw25 //DMA Multi Channel Mode of DAI Rx
++ | Hw23 | Hw22//DMA Multi channel select : DAO0, DAO1, DAO2, DAO3
++#endif
++ | Hw14 //Width of Audio Data of DAI Rx 16bites
++ | Hw2; //Interrupt enable of DAI Rx
++ }
++ else//output
++ {
++ pStrADMABaseReg->ChCtrl |= 0
++#if defined(SPDIF_2CH_ONLY)
++ | Hw29 //DMA Channel enable of SPDIF Tx
++#endif
++ | Hw28 //DMA Channel enable of DAI Tx
++#if defined(_MULTIL_DAO_INCLUDE_)
++ | Hw24 //DMA Multi Channel Mode of DAI Tx
++ | Hw21 | Hw20//DMA Multi channel select : DAI0, DAI1, DAI2, DAI3
++#endif
++#if defined(SPDIF_2CH_ONLY)
++ | Hw13 //Width of Audio Data of SPDIF Tx 16bites
++#endif
++ | Hw12 //Width of Audio Data of DAI Tx 16bites
++#if defined(SPDIF_2CH_ONLY)
++ | Hw1 //Interrupt enable of SPDIF Tx
++#endif
++
++ | Hw0; //Interrupt enable of DAI Tx
++#if defined(_MULTIL_DAO_INCLUDE_)
++/*
++ pStrADMADAIBaseReg->MCCR0 |= 0
++ | Hw13|Hw21//Disable BCLK Divider Select of TDM
++ ;
++ */
++#endif
++ }
++ }
++ else
++ {
++ tca_i2s_stop(pADMADAIBaseAddr, pStrADMASPDIFTxBaseReg, nInMode);
++ if(nInMode)//input
++ {
++ pStrADMABaseReg->ChCtrl &= ~Hw30; //DMA Channel disable of DAI Rx
++ }
++ else//output
++ {
++#if defined(SPDIF_2CH_ONLY)
++ pStrADMABaseReg->ChCtrl &= ~(Hw29|Hw28); //DMA Channel disable of SPDIF Tx, DAI Tx
++#else
++ pStrADMABaseReg->ChCtrl &= ~Hw28; //DMA Channel disable of DAI Tx
++#endif
++
++ }
++ }
++ return 0/*SUCCESS*/;
++}
++
++/*****************************************************************************
++* Function Name : tca_i2s_setregister()
++******************************************************************************
++* Desription : set dai register
++* Parameter :
++* Return : success(SUCCESS)
++******************************************************************************/
++unsigned int tca_i2s_setregister(void *pADMADAIBaseAddr, unsigned int nRegval)
++{
++ ADMADAI*pStrADMADAIBaseReg = (ADMADAI *)pADMADAIBaseAddr;
++ pStrADMADAIBaseReg->DAMR = nRegval;
++ return 0;
++}
++
++/*****************************************************************************
++* Function Name : tca_i2s_getregister()
++******************************************************************************
++* Desription : get dai register
++* Parameter :
++* Return : success(SUCCESS)
++******************************************************************************/
++unsigned int tca_i2s_getregister(void *pADMADAIBaseAddr)
++{
++ ADMADAI *pStrADMADAIBaseReg = (ADMADAI *)pADMADAIBaseAddr;
++ return (pStrADMADAIBaseReg->DAMR);
++}
++
++/*****************************************************************************
++* Function Name : tca_i2s_dai_init()
++******************************************************************************
++* Desription : i2s init
++* Parameter :
++* Return : success(SUCCESS)
++******************************************************************************/
++unsigned int tca_i2s_dai_init(void *pADMADAIBaseAddr)
++{
++ ADMADAI *pStrADMADAIBaseReg = (ADMADAI *)pADMADAIBaseAddr;
++
++ //Not used volume control
++ pStrADMADAIBaseReg->DAVC = 0;
++
++ pStrADMADAIBaseReg->DAMR = 0
++ | Hw31 //BCLK direct at master mode
++ | Hw30 //LRCLK direct at master mode
++#if defined(_MULTIL_DAO_INCLUDE_)
++ | Hw29 //DAI Buffer Threshold Enable
++ | Hw28 //Multi-Port Enable
++ //| Hw17 //Loop back test
++#endif
++ | Hw21| Hw20 //DAI Rx shift Bit-pack LSB and 16bit mode
++ | Hw19| Hw18 //DAI Tx shift Bit-pack LSB and 16bit mode
++ | Hw15 //DAI Master enable
++ | Hw11 //DAI System Clock master select
++ | Hw10 //DAI Bit Clock master select
++ | Hw9 //DAI Frame clock(LRCLK) master selcet
++ | Hw5 //DAI LRCLK(64fs->fs)
++ ;
++
++ return(0);
++}
++
++/*****************************************************************************
++* Function Name : tca_i2s_initoutput()
++******************************************************************************
++* Desription : i2s init output
++* Parameter :
++* Return : success(SUCCESS)
++******************************************************************************/
++void tca_i2s_initoutput(void *pADMABaseAddr, unsigned int nOutputDma, unsigned int AUDIO_DMA_PAGE_SIZE, unsigned int SAMPLERATE )
++{
++ ADMA *pStrADMABaseReg = (ADMA *)pADMABaseAddr;
++ unsigned int bitSet=0x0;
++ unsigned uSize;
++ unsigned int DMABuffer = 0;
++
++ //DMA Channel enable of DAI Tx
++ pStrADMABaseReg->ChCtrl &= ~Hw28;
++
++ DMABuffer = 0xFFFFFF00 / (((AUDIO_DMA_PAGE_SIZE*2) >> 4)<<8);
++ DMABuffer = DMABuffer * (((AUDIO_DMA_PAGE_SIZE*2) >> 4)<<8);
++
++ uSize = AUDIO_DMA_PAGE_SIZE*2;
++
++ // DAI Tx (Right) Source Address
++ pStrADMABaseReg->TxDaParam = DMABuffer | 4; //(4|0xFFFFFE00);
++
++ // ADMA Count Reginster setting
++ pStrADMABaseReg->TxDaTCnt = (((AUDIO_DMA_PAGE_SIZE)>>0x2)>>0x2) - 1;
++
++ // Tx Transfer Control Refister Setting
++ bitSet = ( HwZERO
++ //Tx Trigger Type is edge-trigger
++ |Hw28 //DMA transfer begins from current source/destination address
++ //|Hw24 //Issue Locked Transfer of DAI Tx DMA
++ |Hw16 //Enable repeat mode control of DAI Tx DMA
++ |Hw9/*|Hw8*/ //Burst size of DAI Tx DMA is 4 cycle
++ |Hw1|Hw0 //Word size of DAI Tx DMA is 32bit
++ );
++
++ pStrADMABaseReg->TransCtrl |= bitSet;
++#if defined(_MULTIL_DAO_INCLUDE_)
++ pStrADMABaseReg->RptCtrl = Hw26|Hw25|Hw24;//DAI Buffer Threshod is set Multi-Port
++#else
++ pStrADMABaseReg->RptCtrl = 0;
++#endif
++
++ /* ADMA Repeat register setting */
++ // BITCLR(HwRptCtrl,HwRptCtrl_DRI_EN); //DMA Interrupt is occurred when the end of each Repeated DMAoperation.
++
++ // Tx channel Control Register Setting
++ //Start DMA
++ bitSet = ( HwZERO
++ |Hw0 //Interrupt Enable of DAI Tx
++ );
++
++ pStrADMABaseReg->ChCtrl |= bitSet;
++}
++
++#if defined(SPDIF_2CH_ONLY)
++void tca_i2s_initoutputbyspdif(void *pADMABaseAddr, void *pADMASPDIFTXBaseAddr,
++ unsigned int nOutputDma, unsigned int AUDIO_DMA_PAGE_SIZE_SPIDF, unsigned int SAMPLERATE )
++{
++ ADMA *pStrADMABaseReg = (ADMA *)pADMABaseAddr;
++ ADMASPDIFTX *pStrADMASPDIFTXBaseReg = pADMASPDIFTXBaseAddr;
++ unsigned int bitSet=0x0;
++ unsigned uSize;
++ unsigned int DMABuffer = 0;
++
++ memset((void *)pStrADMASPDIFTXBaseReg->UserData, 0, 24);
++ memset((void *)pStrADMASPDIFTXBaseReg->ChStatus, 0, 24);
++ memset((void *)pStrADMASPDIFTXBaseReg->TxBuffer, 0, 128);
++
++ //DMA Channel enable of SPDIF Tx
++ pStrADMABaseReg->ChCtrl &= ~Hw29;
++
++ DMABuffer = 0xFFFFFF00 / (((AUDIO_DMA_PAGE_SIZE_SPIDF*2) >> 4)<<8);
++ DMABuffer = DMABuffer * (((AUDIO_DMA_PAGE_SIZE_SPIDF*2) >> 4)<<8);
++
++ uSize = AUDIO_DMA_PAGE_SIZE_SPIDF*2;
++
++ // SPDIF Tx (Right) Source Address
++ pStrADMABaseReg->TxSpParam = DMABuffer | 4; //(4|0xFFFFFE00);
++
++ // ADMA Count Reginster setting
++ pStrADMABaseReg->TxSpTCnt = (((AUDIO_DMA_PAGE_SIZE_SPIDF)>>0x2)>>0x2) - 1;
++
++ // Tx Transfer Control Refister Setting
++ bitSet |= (HwZERO
++ //Tx Trigger Type is edge-trigger
++ |Hw28 //DMA transfer begins from current source/destination address
++ //|Hw25 //Issue Locked Transfer of SPDIF Tx DMA
++ |Hw17 //Enable repeat mode control of SPDIF Tx DMA
++ |Hw11/*|Hw10*/ //Burst size of SPDIF Tx DMA is 4 cycle
++ |Hw3|Hw2 //Word size of SPDIF Tx DMA is 32bit
++ );
++
++ pStrADMABaseReg->TransCtrl |= bitSet;
++
++#if defined(_MULTIL_DAO_INCLUDE_)
++ pStrADMABaseReg->RptCtrl = Hw26|Hw25|Hw24;//DAI Buffer Threshod is set Multi-Port
++#else
++ pStrADMABaseReg->RptCtrl = 0;
++#endif
++
++ /* ADMA Repeat register setting */
++ // BITCLR(HwRptCtrl,HwRptCtrl_DRI_EN); //DMA Interrupt is occurred when the end of each Repeated DMAoperation.
++
++ //Set SPDIF Transmit Configuration
++ pStrADMASPDIFTXBaseReg->TxConfig = HwZERO
++ //16bits
++ |Hw9|Hw8 //Clock Divider Ratio is 2(384*fs to default)
++ //| Hw7 | Hw6 //User Data Enalbe Bits is set reserved
++ //| Hw5 | Hw4 //Channel Status Enalbe Bits is set reserved
++ //| Hw2 //interrupt output enable
++ | Hw1 //data being valid
++ //| Hw0 //enable the transmission
++ ;
++ //Set SPDIF Transmit Channel Status
++ pStrADMASPDIFTXBaseReg->TxChStat |= HwZERO
++ //| 0x00000400 // Store Channel Status bit
++ //| 0x00000200 // Store User Data bit
++ //| 0x00000100 // Store Validity bit
++ //44.1kHz
++ //| Hw3 //Original/Commercially Pre-recored data
++ //| Hw2 //Pre-emphasis is 50/15us
++ //| Hw1 //Copy permitted
++ //Audio format
++ ;
++
++ //pStrADMASPDIFTXBaseReg->TxIntMask = HwZERO
++ // | Hw2//Higher Data buffer is empty
++ // | Hw1//Lower Data buffer is empty
++ // ;
++
++ pStrADMASPDIFTXBaseReg->DMACFG = HwZERO
++ //| Hw14 //Swap Sample Enable
++ | Hw13 //Read Address 16bit Mode
++ | Hw11 //DMA Request enable for user data buffer
++ | Hw10 //DMA Request enable for sample data buffer
++ | Hw8 //Enable address
++ //| Hw3 //FIFO Threshold for DMA request
++ | Hw1| Hw0 // [3:0] FIFO Threshold for DMA Request
++ ;
++
++ /* Initialize Sample Data Buffer */
++ while(pStrADMASPDIFTXBaseReg->DMACFG & 0x00300000) pStrADMASPDIFTXBaseReg->TxBuffer[0] = 0;
++
++ pStrADMASPDIFTXBaseReg->TxConfig |= HwZERO
++ //| Hw2 //interrupt output enable
++ | Hw1 //data being valid
++ | Hw0 //enable the transmission
++ ;
++
++ while((pStrADMASPDIFTXBaseReg->DMACFG & 0x00100000)); /* Wait until first data TX */
++ while((pStrADMASPDIFTXBaseReg->DMACFG & 0x001F0000) > 0x00080000);
++
++ while(!(pStrADMASPDIFTXBaseReg->TxIntStat & Hw1)); /* Wait for Interrupt Status */
++
++ pStrADMASPDIFTXBaseReg->TxIntStat = 0x1E; /* Clear Interrupt Status */
++
++ pStrADMASPDIFTXBaseReg->TxConfig |= HwZERO
++ | Hw2 //interrupt output enable
++ | Hw1 //data being valid
++ //| Hw0 //enable the transmission
++ ;
++
++ // Tx channel Control Register Setting
++ //Start DMA
++ bitSet = ( HwZERO
++ |Hw1 //Interrupt Enable of SPDIF Tx
++ );
++
++ pStrADMABaseReg->ChCtrl |= bitSet;
++}
++#endif
++
++/*****************************************************************************
++* Function Name : tca_i2s_deinit()
++******************************************************************************
++* Desription : i2s deinit
++* Parameter :
++* Return : success(SUCCESS)
++******************************************************************************/
++
++unsigned int tca_i2s_deinit(void *pADMADAIBaseAddr, void *pADMASPDIFTXBaseAddr)
++{
++ //----- 1. Stop the I2S clocks -----
++ tca_i2s_stop(pADMADAIBaseAddr, pADMASPDIFTXBaseAddr, 0);
++ tca_i2s_stop(pADMADAIBaseAddr, pADMASPDIFTXBaseAddr, 1);
++
++ return 0/*SUCCESS*/;
++}
++
++
++/*****************************************************************************
++* Function Name : tca_i2s_start()
++******************************************************************************
++* Desription :
++* Parameter :
++* Return : success(SUCCESS)
++******************************************************************************/
++void tca_i2s_start(void *pADMADAIBaseAddr, void *pADMASPDIFTXBaseAddr, unsigned int nMode)
++{
++ ADMADAI *pStrADMADAIBaseReg = (ADMADAI *)pADMADAIBaseAddr;
++#if defined(SPDIF_2CH_ONLY)
++ ADMASPDIFTX *pStrADMASPDIFTXBaseReg = pADMASPDIFTXBaseAddr;
++#endif
++
++ if(nMode) //input
++ {
++ //ADMADAI Receiver enable
++ pStrADMADAIBaseReg->DAMR |= Hw13;
++ }
++ else
++ {
++ //ADMADAI Transmitter enable
++ pStrADMADAIBaseReg->DAMR |= Hw14;
++#if defined(SPDIF_2CH_ONLY)
++ pStrADMASPDIFTXBaseReg->TxIntStat = 0x1E; /* Clear Interrupt Status */
++ pStrADMASPDIFTXBaseReg->TxConfig |= HwZERO
++ |Hw0
++ ;
++#endif
++ }
++}
++
++
++/*****************************************************************************
++* Function Name : tca_i2s_stop()
++******************************************************************************
++* Desription :
++* Parameter :
++* Return : success(SUCCESS)
++******************************************************************************/
++void tca_i2s_stop(void *pADMADAIBaseAddr, void *pADMASPDIFTXBaseAddr, unsigned int nMode)
++{
++ ADMADAI *pStrADMADAIBaseReg = (ADMADAI *)pADMADAIBaseAddr;
++#if defined(SPDIF_2CH_ONLY)
++ ADMASPDIFTX *pStrADMASPDIFTXBaseReg = (ADMASPDIFTX *)pADMASPDIFTXBaseAddr;
++#endif
++
++ if(nMode)
++ {
++ //DAI Receiver disable
++ pStrADMADAIBaseReg->DAMR &= ~Hw13;
++ }
++ else
++ {
++ //DAI Transmitter disable
++ pStrADMADAIBaseReg->DAMR &= ~Hw14;
++#if defined(SPDIF_2CH_ONLY)
++ pStrADMASPDIFTXBaseReg->TxConfig &= ~Hw0;
++#endif
++ }
++
++}
++
++/*****************************************************************************
++* Function Name : tca_i2s_initinput()
++******************************************************************************
++* Desription :
++* Parameter :
++* Return : success(SUCCESS)
++******************************************************************************/
++void tca_i2s_initinput(void *pADMABaseAddr, unsigned int nInputDma, unsigned int AUDIO_DMA_IN_PAGE_SIZE, unsigned int SAMPLERATE)
++{
++ ADMA *pStrADMABaseReg = (ADMA *)pADMABaseAddr;
++ unsigned int bitSet=0x0;
++ unsigned uSize;
++ unsigned int DMABuffer = 0;
++
++ //DMA Channel enable of DAI Rx
++ pStrADMABaseReg->ChCtrl &= ~Hw30;//
++
++ DMABuffer = 0xFFFFFF00 / (((AUDIO_DMA_IN_PAGE_SIZE*2) >> 4)<<8);
++ DMABuffer = DMABuffer * (((AUDIO_DMA_IN_PAGE_SIZE*2) >> 4)<<8);
++
++ uSize = AUDIO_DMA_IN_PAGE_SIZE*2;
++
++ // DAI Rx (Right) Source Address
++ pStrADMABaseReg->RxDaParam = DMABuffer | 4; //(4|0xFFFFFE00);
++
++ // ADMA Count Reginster setting
++ pStrADMABaseReg->RxDaTCnt = (((AUDIO_DMA_IN_PAGE_SIZE)>>0x02)>>0x02) - 1;
++
++ //Rx Transfer Control Refister Setting
++ bitSet = ( HwZERO
++ //Rx Trigger Type is edge-trigger
++ |Hw29 //DMA transfer begins from current source/destination address
++ //|Hw26 //Issue Locked Transfer of DAI Rx DMA
++ |Hw18 //Enable repeat mode control of DAI Rx DMA
++ |Hw13 //Burst size of DAI Rx DMA is 4 cycle
++ |(Hw5|Hw4) //Word size of DAI Rx DMA is 32bit
++ );
++
++ pStrADMABaseReg->TransCtrl |= bitSet;
++#if defined(_MULTIL_DAO_INCLUDE_)
++ pStrADMABaseReg->RptCtrl = Hw26|Hw25|Hw24;//DAI Buffer Threshod is set Multi-Port
++#else
++ pStrADMABaseReg->RptCtrl = 0;
++#endif
++
++ /* ADMA Repeat register setting */
++ //BITCLR(HwRptCtrl,HwRptCtrl_DRI_EN); //DMA Interrupt is occurred when the end of each Repeated DMAoperation.
++
++ // Rx channel Control Register Setting
++ //Start DMA
++ bitSet = ( HwZERO
++ |Hw2//Interrupt Enable of DAI Rx
++ );
++
++ pStrADMABaseReg->ChCtrl |= bitSet;
++}
+diff --git a/sound/soc/tcc/tcc8900/tca_tcchwcontrol.h b/sound/soc/tcc/tcc8900/tca_tcchwcontrol.h
+new file mode 100644
+index 0000000..b094913
+--- /dev/null
++++ b/sound/soc/tcc/tcc8900/tca_tcchwcontrol.h
+@@ -0,0 +1,60 @@
++/****************************************************************************
++ * FileName : tca_tcchwcontrol.h
++ * Description :
++ ****************************************************************************
++ *
++ * TCC Version 1.0
++ * Copyright (c) Telechips, Inc.
++ * ALL RIGHTS RESERVED
++ *
++ ****************************************************************************/
++#ifndef __TCA_TCCHWCONTROL_H__
++#define __TCA_TCCHWCONTROL_H__
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/*****************************************************************************
++*
++* Defines
++*
++******************************************************************************/
++
++//#define AUDIO_DMA_PAGE_SIZE (256) // Size in bytes
++//#define AUDIO_DMA_IN_PAGE_SIZE (256) // Size in bytes
++
++//i2s control api
++extern unsigned int tca_i2s_dai_init(void *pADMADAIBaseAddr);
++extern unsigned int tca_i2s_deinit(void *pADMADAIBaseAddr, void *pADMASPDIFTXBaseAddr);
++extern unsigned int tca_i2s_setregister(void *pADMADAIBaseAddr, unsigned int nRegval);
++extern unsigned int tca_i2s_getregister(void *pADMADAIBaseAddr);
++
++extern void tca_i2s_start(void *pADMADAIBaseAddr, void *pADMASPDIFTXBaseAddr, unsigned int nMode);
++extern void tca_i2s_stop(void *pADMADAIBaseAddr, void *pADMASPDIFTXBaseAddr, unsigned int nMode);
++
++extern void tca_i2s_initoutput(void *pADMABaseAddr, unsigned int,unsigned int,unsigned int);
++#if defined(SPDIF_2CH_ONLY)
++void tca_i2s_initoutputbyspdif(void *pADMABaseAddr, void *pADMASPDIFTXBaseAddr,
++ unsigned int nOutputDma, unsigned int AUDIO_DMA_PAGE_SIZE_SPIDF, unsigned int SAMPLERATE );
++#endif
++extern void tca_i2s_initinput(void *pADMABaseAddr, unsigned int,unsigned int,unsigned int);
++
++//Get IRQ GetNumber
++extern unsigned int tca_irq_getnumber(void);
++
++//dma control api
++extern unsigned int tca_dma_clrstatus(void *pADMABaseAddr, unsigned int nDmanum);
++extern unsigned int tca_dma_getstatus(void *pADMABaseAddr, unsigned int nDmanum);
++extern unsigned int tca_dma_control(void *pADMABaseAddr, void *pADMADAIBaseAddr, void *pADMASPDIFTXBaseAddr,
++ unsigned int nMode, unsigned int nDmanum, unsigned int nInMode);
++extern unsigned int tca_dma_setsrcaddr(void *pADMABaseAddr, unsigned int DADONum, unsigned int nDmanum, unsigned int nAddr);
++extern unsigned int tca_dma_setdestaddr(void *pADMABaseAddr, unsigned int DADINum, unsigned int nDmanum, unsigned int nAddr);
++
++//GPIO port INIT
++extern unsigned int tca_tcc_initport(void *pGPIOBaseAddr);
++#ifdef __cplusplus
++}
++#endif
++#endif
++
+diff --git a/sound/soc/tcc/tcc_board.c b/sound/soc/tcc/tcc_board.c
+new file mode 100644
+index 0000000..1eb773d
+--- /dev/null
++++ b/sound/soc/tcc/tcc_board.c
+@@ -0,0 +1,444 @@
++/*
++ * linux/sound/soc/tcc/tcc_board.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: Nov 30, 2007
++ * Description: SoC audio for TCCxx
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/moduleparam.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/soc.h>
++#include <sound/soc-dapm.h>
++
++#include <bsp.h>
++#include <mach/hardware.h>
++#include <mach/irqs.h>
++#include <mach/tca_ckc.h>
++#include <mach/tcc_pca953x.h>
++
++
++#include "tcc/tca_tcchwcontrol.h"
++#include "../codecs/wm8731.h"
++#include "tcc-pcm.h"
++#include "tcc-i2s.h"
++
++#define TCC_HP 0
++#define TCC_MIC 1
++#define TCC_LINE 2
++#define TCC_HEADSET 3
++#define TCC_HP_OFF 4
++#define TCC_SPK_ON 0
++#define TCC_SPK_OFF 1
++
++// /* audio clock in Hz - rounded from 12.235MHz */
++//#define TCC83X_AUDIO_CLOCK 12288000
++
++static int tcc_jack_func;
++static int tcc_spk_func;
++
++static void tcc_ext_control(struct snd_soc_codec *codec)
++{
++ int spk = 0, mic = 0, line = 0, hp = 0, hs = 0;
++
++ /* set up jack connection */
++ switch (tcc_jack_func) {
++ case TCC_HP:
++ hp = 1;
++ /* set = unmute headphone */
++// set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
++// set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
++ break;
++ case TCC_MIC:
++ mic = 1;
++ /* reset = mute headphone */
++// reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
++// reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
++ break;
++ case TCC_LINE:
++ line = 1;
++// reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
++// reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
++ break;
++ case TCC_HEADSET:
++ hs = 1;
++ mic = 1;
++// reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
++// set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
++ break;
++ }
++
++ if (tcc_spk_func == TCC_SPK_ON)
++ spk = 1;
++
++ /* set the enpoints to their new connetion states */
++ //snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk);
++ snd_soc_dapm_enable_pin(codec, "Ext Spk");
++ //snd_soc_dapm_set_endpoint(codec, "Mic Jack", mic);
++ snd_soc_dapm_enable_pin(codec, "Mic Jack");
++ //snd_soc_dapm_set_endpoint(codec, "Line Jack", line);
++ snd_soc_dapm_enable_pin(codec, "Line Jack");
++ //snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp);
++ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
++ //snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs);
++ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
++
++ /* signal a DAPM event */
++ //snd_soc_dapm_sync_endpoints(codec);
++ snd_soc_dapm_sync(codec);
++}
++
++static int tcc_startup(struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->socdev->codec;
++
++ /* check the jack status at stream startup */
++ tcc_ext_control(codec);
++ return 0;
++}
++
++/* we need to unmute the HP at shutdown as the mute burns power on tcc83x */
++static void tcc_shutdown(struct snd_pcm_substream *substream)
++{
++ //struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ //struct snd_soc_codec *codec = rtd->socdev->codec;
++
++ /* set = unmute headphone */
++// set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
++// set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
++ //return 0;
++}
++
++static int tcc_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
++ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
++ unsigned int clk = 0;
++ int ret = 0;
++
++ switch (params_rate(params)) {
++ case 8000:
++ case 16000:
++ case 48000:
++ case 96000:
++ clk = 12288000;
++ break;
++ case 11025:
++ case 22050:
++ case 32000:
++ case 44100:
++ clk = 11289600;
++ break;
++ }
++
++ /* set codec DAI configuration */
++ /*
++ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ */
++ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ if (ret < 0)
++ return ret;
++
++ /* set cpu DAI configuration */
++ /*
++ ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ */
++ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ if (ret < 0)
++ return ret;
++
++ /* set the codec system clock for DAC and ADC */
++ /*
++ ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk,
++ SND_SOC_CLOCK_IN);
++ */
++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk,
++ SND_SOC_CLOCK_IN);
++ if (ret < 0)
++ return ret;
++
++ /* set the I2S system clock as input (unused) */
++// ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,SND_SOC_CLOCK_IN);
++ // ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_IN);
++ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_IN);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++static struct snd_soc_ops tcc_ops = {
++ .startup = tcc_startup,
++ .hw_params = tcc_hw_params,
++ .shutdown = tcc_shutdown,
++};
++
++static int tcc_get_jack(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
++{
++ ucontrol->value.integer.value[0] = tcc_jack_func;
++ return 0;
++}
++
++static int tcc_set_jack(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++
++ if (tcc_jack_func == ucontrol->value.integer.value[0])
++ return 0;
++
++ tcc_jack_func = ucontrol->value.integer.value[0];
++ tcc_ext_control(codec);
++ return 1;
++}
++
++static int tcc_get_spk(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
++{
++ ucontrol->value.integer.value[0] = tcc_spk_func;
++ return 0;
++}
++
++static int tcc_set_spk(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++
++ if (tcc_spk_func == ucontrol->value.integer.value[0])
++ return 0;
++
++ tcc_spk_func = ucontrol->value.integer.value[0];
++ tcc_ext_control(codec);
++ return 1;
++}
++
++static int tcc_amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
++{
++
++#if 0
++ if (SND_SOC_DAPM_EVENT_ON(event))
++ set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
++ else
++ reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
++#endif
++
++ return 0;
++}
++
++static int tcc_mic_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
++{
++#if 0
++ if (SND_SOC_DAPM_EVENT_ON(event))
++// set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
++ else
++// reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
++#endif
++
++ return 0;
++
++}
++
++/* tcc machine dapm widgets */
++static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
++SND_SOC_DAPM_HP("Headphone Jack", NULL),
++SND_SOC_DAPM_MIC("Mic Jack", tcc_mic_event),
++SND_SOC_DAPM_SPK("Ext Spk", tcc_amp_event),
++SND_SOC_DAPM_LINE("Line Jack", NULL),
++SND_SOC_DAPM_HP("Headset Jack", NULL),
++};
++
++/* tcc machine audio map (connections to the codec pins) */
++static const struct snd_soc_dapm_route audio_map[] = {
++
++
++ /* headset Jack - in = micin, out = LHPOUT*/
++ {"Headset Jack", NULL, "LHPOUT"},
++
++ /* headphone connected to LHPOUT1, RHPOUT1 */
++ {"Headphone Jack", NULL, "LHPOUT"},
++ {"Headphone Jack", NULL, "RHPOUT"},
++
++ /* speaker connected to LOUT, ROUT */
++ {"Ext Spk", NULL, "ROUT"},
++ {"Ext Spk", NULL, "LOUT"},
++
++ /* mic is connected to MICIN (via right channel of headphone jack) */
++ {"MICIN", NULL, "Mic Jack"},
++
++ /* Same as the above but no mic bias for line signals */
++ {"MICIN", NULL, "Line Jack"},
++};
++
++static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
++ "Off"};
++static const char *spk_function[] = {"On", "Off"};
++static const struct soc_enum tcc_enum[] = {
++ SOC_ENUM_SINGLE_EXT(5, jack_function),
++ SOC_ENUM_SINGLE_EXT(2, spk_function),
++};
++
++static const struct snd_kcontrol_new wm8731_tcc_controls[] = {
++ SOC_ENUM_EXT("Jack Function", tcc_enum[0], tcc_get_jack,
++ tcc_set_jack),
++ SOC_ENUM_EXT("Speaker Function", tcc_enum[1], tcc_get_spk,
++ tcc_set_spk),
++};
++
++/*
++ * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
++ */
++static int tcc_wm8731_init(struct snd_soc_codec *codec)
++{
++ int i, err;
++
++ //snd_soc_dapm_nc_pin(codec, "LLINEIN");
++ //snd_soc_dapm_nc_pin(codec, "RLINEIN");
++ snd_soc_dapm_enable_pin(codec, "MICIN");
++
++ /* Add tcc specific controls */
++ for (i = 0; i < ARRAY_SIZE(wm8731_tcc_controls); i++) {
++ err = snd_ctl_add(codec->card,
++ snd_soc_cnew(&wm8731_tcc_controls[i],codec, NULL));
++ if (err < 0)
++ return err;
++ }
++
++ /* Add tcc specific widgets */
++ snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets,
++ ARRAY_SIZE(wm8731_dapm_widgets));
++
++ /* Set up tcc specific audio path audio_map */
++ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
++
++ snd_soc_dapm_sync(codec);
++ return 0;
++}
++
++static int tcc_iec958_dummy_init(struct snd_soc_codec *codec)
++{
++ return 0;
++}
++
++/* tcc digital audio interface glue - connects codec <--> CPU */
++static struct snd_soc_dai_link tcc_dai[] = {
++ {
++ .name = "WM8731",
++ .stream_name = "WM8731",
++ .cpu_dai = &tcc_i2s_dai,
++ .codec_dai = &wm8731_dai,
++ .init = tcc_wm8731_init,
++ .ops = &tcc_ops,
++ },
++ {
++ .name = "TCC",
++ .stream_name = "IEC958",
++ .cpu_dai = &tcc_i2s_dai,
++ .codec_dai = &iec958_dai,
++ .init = tcc_iec958_dummy_init,
++ .ops = &tcc_ops,
++ }
++};
++
++static int tcc_board_probe(struct platform_device *pdev)
++{
++ GPIO *pStrGPIOBaseReg = (GPIO *)tcc_p2v(HwGPIO_BASE);
++ printk("TCC Board probe [%s]\n", __FUNCTION__);
++
++ tca_tcc_initport(pStrGPIOBaseReg);
++ /* For S/PDIF setting */
++ pStrGPIOBaseReg->GPDFN1 |= Hw12; //SPD_TX(1)
++ // tca_ckc_com_setperibus(RB_DAI, 1);
++ tca_ckc_setiobus(RB_DAICDIFCONTROLLER, ENABLE);
++ return 0;
++}
++
++/* tcc audio machine driver */
++static struct snd_soc_machine snd_soc_machine_tcc = {
++ .name = "tccx_board",
++ .probe = tcc_board_probe,
++ .dai_link = tcc_dai,
++ .num_links = 2,
++};
++
++
++/* tcc audio private data */
++static struct wm8731_setup_data tcc_wm8731_setup = {
++ .i2c_bus = 0,
++#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
++ .i2c_address = 0x1a,
++#else
++ .i2c_address = 0x34,
++#endif
++};
++
++/* tcc audio subsystem */
++extern struct snd_soc_platform tcc_soc_platform;
++static struct snd_soc_device tcc_snd_devdata = {
++ .machine = &snd_soc_machine_tcc,
++ .platform = &tcc_soc_platform,
++ .codec_dev = &soc_codec_dev_wm8731,
++ .codec_data = &tcc_wm8731_setup,
++};
++
++static struct platform_device *tcc_snd_device;
++
++static int __init tcc_init(void)
++{
++ int ret;
++
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, CODEC_ON, OUTPUT, HIGH, SET_DIRECTION | SET_VALUE);
++ tcc_pca953x_setup(PCA9539_U2_SLAVE_ADDR, MUTE_CTL, OUTPUT, HIGH, SET_DIRECTION | SET_VALUE);
++
++ tcc_snd_device = platform_device_alloc("soc-audio", -1);
++ if (!tcc_snd_device)
++ return -ENOMEM;
++
++ platform_set_drvdata(tcc_snd_device, &tcc_snd_devdata);
++ tcc_snd_devdata.dev = &tcc_snd_device->dev;
++ ret = platform_device_add(tcc_snd_device);
++
++ if (ret)
++ platform_device_put(tcc_snd_device);
++
++ return ret;
++}
++
++static void __exit tcc_exit(void)
++{
++ platform_device_unregister(tcc_snd_device);
++}
++
++module_init(tcc_init);
++module_exit(tcc_exit);
++
++/* Module information */
++MODULE_AUTHOR("linux <linux@telechips.com>");
++MODULE_DESCRIPTION("ALSA SoC TCCxx Board");
++MODULE_LICENSE("GPL");
+diff --git a/sound/soc/tcc/tcc_board_wm8581.c b/sound/soc/tcc/tcc_board_wm8581.c
+new file mode 100644
+index 0000000..22cd122
+--- /dev/null
++++ b/sound/soc/tcc/tcc_board_wm8581.c
+@@ -0,0 +1,456 @@
++/*
++ * linux/sound/soc/tcc/tcc_board.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: Nov 30, 2007
++ * Description: SoC audio for TCCxx
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/moduleparam.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/soc.h>
++#include <sound/soc-dapm.h>
++
++#include <bsp.h>
++#include <mach/hardware.h>
++#include <mach/irqs.h>
++#include <mach/tca_ckc.h>
++#include <mach/tcc_pca953x.h>
++
++#include "tcc/tca_tcchwcontrol.h"
++#include "../codecs/wm8581.h"
++#include "tcc-pcm.h"
++#include "tcc-i2s.h"
++
++#define TCC_HP 0
++#define TCC_MIC 1
++#define TCC_LINE 2
++#define TCC_HEADSET 3
++#define TCC_HP_OFF 4
++#define TCC_SPK_ON 0
++#define TCC_SPK_OFF 1
++
++// /* audio clock in Hz - rounded from 12.235MHz */
++//#define TCC83X_AUDIO_CLOCK 12288000
++
++static int tcc_jack_func;
++static int tcc_spk_func;
++
++static void tcc_ext_control(struct snd_soc_codec *codec)
++{
++ int spk = 0, mic = 0, line = 0, hp = 0, hs = 0;
++
++ /* set up jack connection */
++ switch (tcc_jack_func) {
++ case TCC_HP:
++ hp = 1;
++ /* set = unmute headphone */
++// set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
++// set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
++ break;
++ case TCC_MIC:
++ mic = 1;
++ /* reset = mute headphone */
++// reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
++// reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
++ break;
++ case TCC_LINE:
++ line = 1;
++// reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
++// reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
++ break;
++ case TCC_HEADSET:
++ hs = 1;
++ mic = 1;
++// reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
++// set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
++ break;
++ }
++
++ if (tcc_spk_func == TCC_SPK_ON)
++ spk = 1;
++
++ /* set the enpoints to their new connetion states */
++ //snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk);
++ snd_soc_dapm_enable_pin(codec, "Ext Spk");
++ //snd_soc_dapm_set_endpoint(codec, "Mic Jack", mic);
++ snd_soc_dapm_enable_pin(codec, "Mic Jack");
++ //snd_soc_dapm_set_endpoint(codec, "Line Jack", line);
++ snd_soc_dapm_enable_pin(codec, "Line Jack");
++ //snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp);
++ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
++ //snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs);
++ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
++
++ /* signal a DAPM event */
++ //snd_soc_dapm_sync_endpoints(codec);
++ snd_soc_dapm_sync(codec);
++}
++
++static int tcc_startup(struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->socdev->codec;
++
++ /* check the jack status at stream startup */
++ tcc_ext_control(codec);
++ return 0;
++}
++
++/* we need to unmute the HP at shutdown as the mute burns power on tcc83x */
++static void tcc_shutdown(struct snd_pcm_substream *substream)
++{
++ //struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ //struct snd_soc_codec *codec = rtd->socdev->codec;
++
++ /* set = unmute headphone */
++// set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
++// set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
++ //return 0;
++}
++
++static int tcc_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
++ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
++ unsigned int clk = 0;
++ int ret = 0;
++
++ switch (params_rate(params)) {
++ case 8000:
++ case 16000:
++ case 48000:
++ case 96000:
++ clk = 12288000;
++ break;
++ case 11025:
++ case 22050:
++ case 32000:
++ case 44100:
++ clk = 11289600;
++ break;
++ }
++
++ /* set codec DAI configuration */
++ /*
++ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ */
++ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ if (ret < 0)
++ return ret;
++
++ /* set cpu DAI configuration */
++ /*
++ ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ */
++ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ if (ret < 0)
++ return ret;
++
++ /* set the codec system clock for DAC and ADC */
++ /*
++ ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8581_SYSCLK, clk,
++ SND_SOC_CLOCK_IN);
++ */
++#if 0
++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8581_SYSCLK, clk,
++ SND_SOC_CLOCK_IN);
++ if (ret < 0)
++ return ret;
++#endif
++
++ /* set the I2S system clock as input (unused) */
++// ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,SND_SOC_CLOCK_IN);
++ // ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_IN);
++ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_IN);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++static struct snd_soc_ops tcc_ops = {
++ .startup = tcc_startup,
++ .hw_params = tcc_hw_params,
++ .shutdown = tcc_shutdown,
++};
++
++static int tcc_get_jack(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
++{
++ ucontrol->value.integer.value[0] = tcc_jack_func;
++ return 0;
++}
++
++static int tcc_set_jack(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++
++ if (tcc_jack_func == ucontrol->value.integer.value[0])
++ return 0;
++
++ tcc_jack_func = ucontrol->value.integer.value[0];
++ tcc_ext_control(codec);
++ return 1;
++}
++
++static int tcc_get_spk(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
++{
++ ucontrol->value.integer.value[0] = tcc_spk_func;
++ return 0;
++}
++
++static int tcc_set_spk(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++
++ if (tcc_spk_func == ucontrol->value.integer.value[0])
++ return 0;
++
++ tcc_spk_func = ucontrol->value.integer.value[0];
++ tcc_ext_control(codec);
++ return 1;
++}
++
++static int tcc_amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
++{
++
++#if 0
++ if (SND_SOC_DAPM_EVENT_ON(event))
++ set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
++ else
++ reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_APM_ON);
++#endif
++
++ return 0;
++}
++
++static int tcc_mic_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
++{
++#if 0
++ if (SND_SOC_DAPM_EVENT_ON(event))
++// set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
++ else
++// reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
++#endif
++
++ return 0;
++
++}
++
++#if 1
++/* tcc machine dapm widgets */
++static const struct snd_soc_dapm_widget wm8581_dapm_widgets[] = {
++SND_SOC_DAPM_HP("Headphone Jack", NULL),
++SND_SOC_DAPM_MIC("Mic Jack", tcc_mic_event),
++SND_SOC_DAPM_SPK("Ext Spk", tcc_amp_event),
++SND_SOC_DAPM_LINE("Line Jack", NULL),
++SND_SOC_DAPM_HP("Headset Jack", NULL),
++};
++
++/* tcc machine audio map (connections to the codec pins) */
++static const struct snd_soc_dapm_route audio_map[] = {
++
++
++ /* headset Jack - in = micin, out = LHPOUT*/
++ {"Headset Jack", NULL, "LHPOUT"},
++
++ /* headphone connected to LHPOUT1, RHPOUT1 */
++ {"Headphone Jack", NULL, "LHPOUT"},
++ {"Headphone Jack", NULL, "RHPOUT"},
++
++ /* speaker connected to LOUT, ROUT */
++ {"Ext Spk", NULL, "ROUT"},
++ {"Ext Spk", NULL, "LOUT"},
++
++ /* mic is connected to MICIN (via right channel of headphone jack) */
++ {"MICIN", NULL, "Mic Jack"},
++
++ /* Same as the above but no mic bias for line signals */
++ {"MICIN", NULL, "Line Jack"},
++};
++
++static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
++ "Off"};
++static const char *spk_function[] = {"On", "Off"};
++static const struct soc_enum tcc_enum[] = {
++ SOC_ENUM_SINGLE_EXT(5, jack_function),
++ SOC_ENUM_SINGLE_EXT(2, spk_function),
++};
++
++static const struct snd_kcontrol_new wm8581_tcc_controls[] = {
++ SOC_ENUM_EXT("Jack Function", tcc_enum[0], tcc_get_jack,
++ tcc_set_jack),
++ SOC_ENUM_EXT("Speaker Function", tcc_enum[1], tcc_get_spk,
++ tcc_set_spk),
++};
++#endif
++
++/*
++ * Logic for a wm8581 as connected on a Sharp SL-C7x0 Device
++ */
++static int tcc_wm8581_init(struct snd_soc_codec *codec)
++{
++#if 1
++ int i, err;
++
++ //snd_soc_dapm_nc_pin(codec, "LLINEIN");
++ //snd_soc_dapm_nc_pin(codec, "RLINEIN");
++ //snd_soc_dapm_enable_pin(codec, "MICIN");
++
++ /* Add tcc specific controls */
++ for (i = 0; i < ARRAY_SIZE(wm8581_tcc_controls); i++) {
++ err = snd_ctl_add(codec->card,
++ snd_soc_cnew(&wm8581_tcc_controls[i], codec, NULL));
++ if (err < 0)
++ return err;
++ }
++
++ /* Add tcc specific widgets */
++ snd_soc_dapm_new_controls(codec, wm8581_dapm_widgets,
++ ARRAY_SIZE(wm8581_dapm_widgets));
++
++#if 0
++ /* Set up tcc specific audio path audio_map */
++ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
++#endif
++
++#endif
++
++ snd_soc_dapm_sync(codec);
++ return 0;
++}
++
++static int tcc_wm8581_dummy_init(struct snd_soc_codec *codec)
++{
++ return 0;
++}
++
++
++extern struct snd_soc_platform tcc_soc_platform;
++
++/* tcc digital audio interface glue - connects codec <--> CPU */
++static struct snd_soc_dai_link tcc_dai[] = {
++ {
++ .name = "WM8581",
++ .stream_name = "WM8581",
++ .cpu_dai = &tcc_i2s_dai,
++ .codec_dai = &(wm8581_dai[0]),
++ .init = tcc_wm8581_init,
++ .ops = &tcc_ops,
++ },
++ {
++ .name = "TCC",
++ .stream_name = "IEC958",
++ .cpu_dai = &tcc_i2s_dai,
++ .codec_dai = &(wm8581_dai[0]),
++ .init = tcc_wm8581_dummy_init,
++ .ops = &tcc_ops,
++ },
++};
++
++static int tcc_board_probe(struct platform_device *pdev)
++{
++ GPIO *pStrGPIOBaseReg = (GPIO *)tcc_p2v(HwGPIO_BASE);
++ printk("TCC Board probe [%s]\n", __FUNCTION__);
++
++ tca_tcc_initport(pStrGPIOBaseReg);
++ /* For S/PDIF setting */
++ pStrGPIOBaseReg->GPDFN1 |= Hw12; //SPD_TX(1)
++
++ // tca_ckc_com_setperibus(RB_DAI, 1);
++ tca_ckc_setiobus(RB_DAICDIFCONTROLLER, ENABLE);
++ return 0;
++}
++
++/* tcc audio machine driver */
++static struct snd_soc_machine snd_soc_machine_tcc = {
++ .name = "tccx_board",
++ .probe = tcc_board_probe,
++ .dai_link = tcc_dai,
++ .num_links = 2,
++};
++
++
++/* tcc audio private data */
++static struct wm8581_setup_data tcc_wm8581_setup = {
++ .i2c_bus = 0,
++#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
++ .i2c_address = 0x1B,
++#else
++ .i2c_address = 0x34,
++#endif
++};
++
++/* tcc audio subsystem */
++static struct snd_soc_device tcc_snd_devdata = {
++ .machine = &snd_soc_machine_tcc,
++ .platform = &tcc_soc_platform,
++ .codec_dev = &soc_codec_dev_wm8581,
++ .codec_data = &tcc_wm8581_setup,
++};
++
++static struct platform_device *tcc_snd_device;
++
++static int __init tcc_init(void)
++{
++ int ret;
++
++ tcc_pca953x_setup(PCA9539_U3_SLAVE_ADDR, CODEC_ON, OUTPUT, HIGH, SET_DIRECTION | SET_VALUE);
++ tcc_pca953x_setup(PCA9539_U2_SLAVE_ADDR, MUTE_CTL, OUTPUT, LOW, SET_DIRECTION | SET_VALUE);
++
++ tcc_snd_device = platform_device_alloc("soc-audio", -1);
++ if (!tcc_snd_device)
++ return -ENOMEM;
++
++ platform_set_drvdata(tcc_snd_device, &tcc_snd_devdata);
++ tcc_snd_devdata.dev = &tcc_snd_device->dev;
++ ret = platform_device_add(tcc_snd_device);
++
++ if (ret)
++ platform_device_put(tcc_snd_device);
++
++ return ret;
++}
++
++static void __exit tcc_exit(void)
++{
++ platform_device_unregister(tcc_snd_device);
++}
++
++module_init(tcc_init);
++module_exit(tcc_exit);
++
++/* Module information */
++MODULE_AUTHOR("linux <linux@telechips.com>");
++MODULE_DESCRIPTION("ALSA SoC TCCxx Board");
++MODULE_LICENSE("GPL");
++
+diff --git a/sound/soc/tcc/tcc_board_wm8987.c b/sound/soc/tcc/tcc_board_wm8987.c
+new file mode 100644
+index 0000000..e5883d5
+--- /dev/null
++++ b/sound/soc/tcc/tcc_board_wm8987.c
+@@ -0,0 +1,432 @@
++/*
++ * linux/sound/soc/tcc/tcc_board.c
++ *
++ * Author: <linux@telechips.com>
++ * Created: Nov 30, 2007
++ * Description: SoC audio for TCCxx
++ *
++ * Copyright (C) 2008-2009 Telechips
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see the file COPYING, or write
++ * to the Free Software Foundation, Inc.,
++ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/moduleparam.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/soc.h>
++#include <sound/soc-dapm.h>
++
++#include <bsp.h>
++#include <mach/hardware.h>
++#include <mach/irqs.h>
++#include <mach/tca_ckc.h>
++#include <mach/tcc_pca953x.h>
++#include <linux/proc_fs.h>
++#include <linux/ctype.h>
++
++#include "tcc/tca_tcchwcontrol.h"
++#include "../codecs/wm8987.h"
++#include "tcc-pcm.h"
++#include "tcc-i2s.h"
++
++/* define the scenarios */
++#define TCC_AUDIO_OFF 0
++#define TCC_CAPTURE_MIC1 3
++#define TCC_STEREO_TO_HEADPHONES 2
++#define TCC_CAPTURE_LINE_IN 1
++
++// /* audio clock in Hz - rounded from 12.235MHz */
++//#define TCC83X_AUDIO_CLOCK 12288000
++
++static int tcc_jack_func = 0;
++
++static void tcc_ext_control(struct snd_soc_codec *codec)
++{
++ switch(tcc_jack_func) {
++ printk("tcc_jack_func is %d\n", tcc_jack_func);
++ case TCC_AUDIO_OFF:
++ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
++ snd_soc_dapm_enable_pin(codec, "Mic Bias");
++ snd_soc_dapm_enable_pin(codec, "Line In Jack");
++ break;
++ case TCC_STEREO_TO_HEADPHONES:
++ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
++ snd_soc_dapm_enable_pin(codec, "Mic Bias");
++ snd_soc_dapm_enable_pin(codec, "Line In Jack");
++ break;
++ case TCC_CAPTURE_MIC1:
++ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
++ snd_soc_dapm_enable_pin(codec, "Mic Bias");
++ snd_soc_dapm_enable_pin(codec, "Line In Jack");
++ break;
++ case TCC_CAPTURE_LINE_IN:
++ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
++ snd_soc_dapm_enable_pin(codec, "Mic Bias");
++ snd_soc_dapm_enable_pin(codec, "Line In Jack");
++ break;
++ default:
++ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
++ snd_soc_dapm_enable_pin(codec, "Mic Bias");
++ snd_soc_dapm_enable_pin(codec, "Line In Jack");
++ break;
++ }
++
++ /* signal a DAPM event */
++ //snd_soc_dapm_sync_endpoints(codec);
++ snd_soc_dapm_sync(codec);
++}
++
++static int tcc_startup(struct snd_pcm_substream *substream)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_codec *codec = rtd->socdev->codec;
++
++ /* check the jack status at stream startup */
++ tcc_ext_control(codec);
++ return 0;
++}
++
++static int tcc_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
++ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
++ unsigned int clk = 0;
++ int ret = 0;
++
++ switch (params_rate(params)) {
++ case 8000:
++ case 12000:
++ case 16000:
++ case 24000:
++ case 48000:
++ case 96000:
++ case 32000:
++ clk = 12288000;
++ break;
++ case 11025:
++ case 22050:
++ case 44100:
++ clk = 11289600;
++ break;
++ }
++
++ /* set codec DAI configuration */
++ /*
++ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ */
++ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ if (ret < 0)
++ return ret;
++
++ /* set cpu DAI configuration */
++ /*
++ ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ */
++ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
++ if (ret < 0)
++ return ret;
++
++ /* set the codec system clock for DAC and ADC */
++ /*
++ ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8987_SYSCLK, clk,
++ SND_SOC_CLOCK_IN);
++ */
++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8987_SYSCLK, clk,
++ SND_SOC_CLOCK_IN);
++ if (ret < 0)
++ return ret;
++
++ /* set the I2S system clock as input (unused) */
++// ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,SND_SOC_CLOCK_IN);
++ // ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_IN);
++ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_IN);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++static struct snd_soc_ops tcc_ops = {
++ .startup = tcc_startup,
++ .hw_params = tcc_hw_params,
++};
++
++static int tcc_get_jack(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
++{
++ ucontrol->value.integer.value[0] = tcc_jack_func;
++ return 0;
++}
++
++static int tcc_set_jack(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++
++ if (tcc_jack_func == ucontrol->value.integer.value[0])
++ return 0;
++
++ tcc_jack_func = ucontrol->value.integer.value[0];
++ tcc_ext_control(codec);
++ return 1;
++}
++
++/* tcc machine dapm widgets */
++static const struct snd_soc_dapm_widget wm8987_dapm_widgets[] = {
++ SND_SOC_DAPM_HP("Headphone Jack", NULL),
++ SND_SOC_DAPM_MIC("Mic Bias", NULL),
++ SND_SOC_DAPM_LINE("Line In Jack", NULL),
++};
++
++/* tcc machine audio map (connections to the codec pins) */
++static const struct snd_soc_dapm_route audio_map[] = {
++ {"Headphone Jack", NULL, "LOUT2"},
++ {"Headphone Jack", NULL, "ROUT2"},
++
++ { "LINPUT2", NULL, "Mic Bias" },
++
++ {"LINPUT1", NULL, "Line In Jack"},
++ {"RINPUT1", NULL, "Line In Jack"},
++};
++
++static const char *jack_function[] = {
++ "Off",
++ "Capture Line In",
++ "Headphones",
++ "Capture Mic1",
++};
++
++static const struct soc_enum tcc_enum[] = {
++ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
++};
++
++static const struct snd_kcontrol_new wm8987_tcc_controls[] = {
++ SOC_ENUM_EXT("Jack Function", tcc_enum[0], tcc_get_jack,
++ tcc_set_jack),
++};
++
++/*
++ * Logic for a wm8987 as connected on a Sharp SL-C7x0 Device
++ */
++static int tcc_wm8987_init(struct snd_soc_codec *codec)
++{
++ int i, err;
++
++ /* set endpoints to default mode */
++ tcc_jack_func = TCC_AUDIO_OFF;
++
++ /* Add tcc specific controls */
++ for (i = 0; i < ARRAY_SIZE(wm8987_tcc_controls); i++) {
++ err = snd_ctl_add(codec->card,
++ snd_soc_cnew(&wm8987_tcc_controls[i],codec, NULL));
++ if (err < 0)
++ return err;
++ }
++
++ /* Add tcc specific widgets */
++ snd_soc_dapm_new_controls(codec, wm8987_dapm_widgets,
++ ARRAY_SIZE(wm8987_dapm_widgets));
++
++ /* Set up tcc specific audio path audio_map */
++ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
++
++ /* always connected */
++ snd_soc_dapm_enable_pin(codec, "Mic Bias");
++ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
++ snd_soc_dapm_enable_pin(codec, "Line In Jack");
++
++ snd_soc_dapm_sync(codec);
++ return 0;
++}
++
++extern struct snd_soc_platform tcc_soc_platform;
++
++/* tcc digital audio interface glue - connects codec <--> CPU */
++static struct snd_soc_dai_link tcc_dai[] = {
++ { /* Hifi Playback - for similatious use with voice below */
++ .name = "WM8987",
++ .stream_name = "WM8987 HiFi",
++ .cpu_dai = &tcc_i2s_dai,
++ .codec_dai = &wm8987_dai,
++ .init = tcc_wm8987_init,
++ .ops = &tcc_ops,
++ },
++};
++
++static int tcc_board_probe(struct platform_device *pdev)
++{
++ GPIO *pStrGPIOBaseReg = (GPIO *)tcc_p2v(HwGPIO_BASE);
++ printk("TCC Board probe [%s]\n", __FUNCTION__);
++
++ tca_tcc_initport(pStrGPIOBaseReg);
++ /* For S/PDIF setting */
++ pStrGPIOBaseReg->GPDFN1 |= Hw12; //SPD_TX(1)
++ // tca_ckc_com_setperibus(RB_DAI, 1);
++ tca_ckc_setiobus(RB_DAICDIFCONTROLLER, ENABLE);
++ return 0;
++}
++
++/* tcc audio machine driver */
++static struct snd_soc_machine snd_soc_machine_tcc = {
++ .name = "tccx_board",
++ .probe = tcc_board_probe,
++ .dai_link = tcc_dai,
++ .num_links = ARRAY_SIZE(tcc_dai),
++};
++
++/* tcc audio private data */
++static struct wm8987_setup_data tcc_wm8987_setup = {
++ .i2c_bus = 4,
++#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
++ .i2c_address = 0x1a,
++#else
++ .i2c_address = 0x34,
++#endif
++};
++
++/* tcc audio subsystem */
++static struct snd_soc_device tcc_snd_devdata = {
++ .machine = &snd_soc_machine_tcc,
++ .platform = &tcc_soc_platform,
++ .codec_dev = &soc_codec_dev_wm8987,
++ .codec_data = &tcc_wm8987_setup,
++};
++
++static struct platform_device *tcc_snd_device;
++
++#ifdef CONFIG_AUDIO_CODEC_PROCFS
++static int aud_proc_read(char* page, char** start, off_t off, int count,
++ int* eof, void* data)
++{
++ struct snd_soc_codec* codec = tcc_snd_devdata.codec;
++
++ if (!codec || !codec->read) return count;
++
++ if (off) return 0; data = (void*)page;
++
++ page += sprintf(page, "%s registers cached settings: ", codec->name);
++ for (count=0; count < codec->reg_cache_size; ++count) {
++ if (!(count % 16)) page += sprintf(page, "\n R%02x: ", count);
++ page += sprintf(page, "%03x ", codec->read(codec, count));
++ if ((count % 8) == 7) page += sprintf(page, " ");
++ }
++
++ return ((page += sprintf(page, "\n")) - (char*)data);
++}
++
++
++static int aud_proc_write(struct file* file, const char* buffer,
++ unsigned long count, void* data)
++{
++#define MAX_BUFLEN 16
++ u8 reg;
++ u16 val = MAX_BUFLEN - 1;
++ char *ptr, tmp_buf[MAX_BUFLEN];
++ struct snd_soc_codec* codec = tcc_snd_devdata.codec;
++
++ if (!codec || !codec->write) return count;
++
++ if (count < MAX_BUFLEN) val = count - 1; tmp_buf[val] = 0;
++ if (copy_from_user(tmp_buf, buffer, val)) return -EFAULT;
++
++ for (ptr = tmp_buf; isspace(*ptr); ++ptr) ;
++
++ reg = simple_strtoul(ptr, &ptr, 16);
++
++ if (!(reg < codec->reg_cache_size)) {
++ printk(KERN_DEBUG "wrong register no %d, max %d\n",
++ reg, codec->reg_cache_size);
++ return count;
++ }
++
++ while (isspace(*ptr)) ++ptr;
++ val = simple_strtoul(ptr, &ptr, 16);
++
++ if (codec->write(codec, reg, val)) ;
++
++ return count;
++}
++
++#define AUD_PROC_ENTRY "driver/audregs"
++
++static int __init aud_proc_init(void)
++{
++ struct proc_dir_entry* aud_entry;
++
++ if (!(aud_entry = create_proc_entry(AUD_PROC_ENTRY,
++ S_IRUGO | S_IWUSR, NULL))) return -ENOMEM;
++
++ printk(KERN_INFO "Proc-FS interface for audio codec\n");
++
++ aud_entry->owner = THIS_MODULE;
++ aud_entry->write_proc = aud_proc_write;
++ aud_entry->read_proc = aud_proc_read;
++ aud_entry->data = NULL;
++
++ return 0;
++}
++
++static void __exit aud_proc_exit(void)
++{
++ remove_proc_entry(AUD_PROC_ENTRY, NULL);
++}
++#endif//CONFIG_AUDIO_CODEC_PROCFS
++
++static int __init tcc_init(void)
++{
++ int ret;
++
++ tcc_snd_device = platform_device_alloc("soc-audio", -1);
++ if (!tcc_snd_device)
++ return -ENOMEM;
++
++ platform_set_drvdata(tcc_snd_device, &tcc_snd_devdata);
++ tcc_snd_devdata.dev = &tcc_snd_device->dev;
++ ret = platform_device_add(tcc_snd_device);
++
++ if (ret)
++ platform_device_put(tcc_snd_device);
++#ifdef CONFIG_AUDIO_CODEC_PROCFS
++ aud_proc_init();
++#endif//CONFIG_AUDIO_CODEC_PROCFS
++
++ return ret;
++}
++
++static void __exit tcc_exit(void)
++{
++#ifdef CONFIG_AUDIO_CODEC_PROCFS
++ aud_proc_exit();
++#endif//CONFIG_AUDIO_CODEC_PROCFS
++ platform_device_unregister(tcc_snd_device);
++}
++
++module_init(tcc_init);
++module_exit(tcc_exit);
++
++/* Module information */
++MODULE_AUTHOR("linux <linux@telechips.com>");
++MODULE_DESCRIPTION("ALSA SoC TCCxx Board");
++MODULE_LICENSE("GPL");
+diff --git a/tcc_crc b/tcc_crc
+new file mode 100755
+index 0000000..49667bc
+Binary files /dev/null and b/tcc_crc differ
+diff --git a/tcc_mk_initramfs.sh b/tcc_mk_initramfs.sh
+new file mode 100755
+index 0000000..596d112
+--- /dev/null
++++ b/tcc_mk_initramfs.sh
+@@ -0,0 +1,42 @@
++#=======================================================================================
++# FileName : tcc_mkrd.sh
++# Description : Make linux.rom
++# Mark linux.rom with CRC & ramdisk size
++#=======================================================================================
++#
++# TCC Board Support Package
++# Copyright (c) Telechips, Inc.
++# ALL RIGHTS RESERVED
++#
++#=======================================================================================
++
++source .config
++
++#
++# ramdisk.rom size (MByte)
++#
++RAMDISK_SIZE=0
++
++echo
++echo "======================================================"
++if test $CONFIG_ARCH_TCC; then
++echo -e "[\x1b[1;33mTelechips TCC8900\x1b[0m]"
++fi
++
++# make linux.img
++echo
++echo -e "[\x1b[1;33mMAKE\x1b[0m] \x1b[1;31mlinux.rom\x1b[0m"
++dd if=arch/arm/boot/Image of=linux.img bs=8M conv=sync
++
++# insert CRC & ramdisk.rom size
++echo
++echo -e "[\x1b[1;33mMARK\x1b[0m] CRC & ramdisk size \x1b[1;31m$RAMDISK_SIZE\x1b[0m Mbyte"
++./tcc_crc -o linux.rom -v 1700 -r $RAMDISK_SIZE linux.img
++
++
++# remove Img, linux.img
++rm -f linux.img
++echo "======================================================"
++echo
++
++exit
+diff --git a/tcc_mk_rootfs.sh b/tcc_mk_rootfs.sh
+new file mode 100755
+index 0000000..5b75549
+--- /dev/null
++++ b/tcc_mk_rootfs.sh
+@@ -0,0 +1,21 @@
++#=======================================================================================
++# FileName : tcc_mkrd.sh
++# Description : Make linux.rom
++# Mark linux.rom with CRC & ramdisk size
++#=======================================================================================
++#
++# TCC Board Support Package
++# Copyright (c) Telechips, Inc.
++# ALL RIGHTS RESERVED
++#
++#=======================================================================================
++
++# make linux.rom
++echo
++echo -e "[\x1b[1;33mMAKE\x1b[0m] \x1b[1;31mlinux.rom\x1b[0m"
++dd if=arch/arm/boot/Image of=linux.rom bs=3M conv=sync
++
++echo "======================================================"
++echo
++
++exit
+diff --git a/tcc_mkrd.sh b/tcc_mkrd.sh
+new file mode 100755
+index 0000000..86c3c58
+--- /dev/null
++++ b/tcc_mkrd.sh
+@@ -0,0 +1,42 @@
++#=======================================================================================
++# FileName : tcc_mkrd.sh
++# Description : Make linux.rom
++# Mark linux.rom with CRC & ramdisk size
++#=======================================================================================
++#
++# TCC Board Support Package
++# Copyright (c) Telechips, Inc.
++# ALL RIGHTS RESERVED
++#
++#=======================================================================================
++
++source .config
++
++#
++# ramdisk.rom size (MByte)
++#
++RAMDISK_SIZE=16
++
++echo
++echo "======================================================"
++if test $CONFIG_ARCH_TCC; then
++echo -e "[\x1b[1;33mTelechips TCC8900\x1b[0m]"
++fi
++
++# make linux.img
++echo
++echo -e "[\x1b[1;33mMAKE\x1b[0m] \x1b[1;31mlinux.rom\x1b[0m"
++dd if=arch/arm/boot/Image of=linux.img bs=4M conv=sync
++
++# insert CRC & ramdisk.rom size
++echo
++echo -e "[\x1b[1;33mMARK\x1b[0m] CRC & ramdisk size \x1b[1;31m$RAMDISK_SIZE\x1b[0m Mbyte"
++./tcc_crc -o linux.rom -v 1700 -r $RAMDISK_SIZE linux.img
++
++
++# remove Img, linux.img
++rm -f linux.img
++echo "======================================================"
++echo
++
++exit