Merge ../../omap/pristine into omap-merge
diff --git a/Makefile b/Makefile
index 49ed72e..79b3571 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
MAKEFLAGS += -rR --no-print-directory
# Add custom flags here to avoid conflict with updates
-EXTRAVERSION := $(EXTRAVERSION)-omap1
+EXTRAVERSION := $(EXTRAVERSION)-davinci1
# We are using a recursive build, so we need to do a little thinking
# to get the ordering right.
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 2d9ae43..8e2c3dd 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -723,7 +723,8 @@
config LEDS_TIMER
bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \
OMAP_OSK_MISTRAL || MACH_OMAP_H2 \
- || MACH_OMAP_PERSEUS2
+ || MACH_OMAP_PERSEUS2 || MACH_DAVINCI_EVM
+
depends on LEDS
depends on !GENERIC_CLOCKEVENTS
default y if ARCH_EBSA110
@@ -1010,7 +1011,7 @@
if PCMCIA || ARCH_CLPS7500 || ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX \
|| ARCH_L7200 || ARCH_LH7A40X || ARCH_PXA || ARCH_RPC \
|| ARCH_S3C2410 || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE \
- || ARCH_IXP23XX
+ || ARCH_IXP23XX || ARCH_DAVINCI
source "drivers/ide/Kconfig"
endif
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 830816a..587b029 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -130,6 +130,10 @@
machine-$(CONFIG_ARCH_H720X) := h720x
machine-$(CONFIG_ARCH_AAEC2000) := aaec2000
machine-$(CONFIG_ARCH_REALVIEW) := realview
+ machine-$(CONFIG_ARCH_AT91) := at91rm9200
+ machine-$(CONFIG_ARCH_EP93XX) := ep93xx
+ machine-$(CONFIG_ARCH_PNX4008) := pnx4008
+ machine-$(CONFIG_ARCH_NETX) := netx
machine-$(CONFIG_ARCH_AT91) := at91
machine-$(CONFIG_ARCH_EP93XX) := ep93xx
machine-$(CONFIG_ARCH_PNX4008) := pnx4008
diff --git a/arch/arm/configs/davinci_evm_dm644x_defconfig b/arch/arm/configs/davinci_evm_dm644x_defconfig
new file mode 100644
index 0000000..e64431a
--- /dev/null
+++ b/arch/arm/configs/davinci_evm_dm644x_defconfig
@@ -0,0 +1,1354 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23-rc2-davinci1
+# Fri Aug 17 20:43:45 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_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_ZONE_DMA=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=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+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_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# 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
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# 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_CO285 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_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC 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=y
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_MACH_OMAP_APOLLON_PLUS is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# TI DaVinci Implementations
+#
+
+#
+# DaVinci Core Type
+#
+CONFIG_ARCH_DAVINCI644x=y
+
+#
+# DaVinci Board Type
+#
+CONFIG_MACH_DAVINCI_EVM=y
+CONFIG_DAVINCI_I2C_EXPANDER=y
+CONFIG_DAVINCI_MCBSP=y
+
+#
+# DaVinci Options
+#
+# CONFIG_DAVINCI_BLK_DEV_CF is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE 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_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_LEDS=y
+# CONFIG_LEDS_CPU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+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_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 is not set
+# 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=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_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_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
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_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=1
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY 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_IDE_GENERIC=y
+# CONFIG_IDEPCI_PCIBUS_ORDER is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_DAVINCI=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_BLK_DEV_HD 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 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_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+CONFIG_TI_DAVINCI_EMAC=y
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 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_MII is not set
+# CONFIG_USB_USBNET is not set
+# 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 is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=y
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+# 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=m
+# 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=y
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+CONFIG_DAVINCI_RTC=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+CONFIG_I2C_DAVINCI=y
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+CONFIG_SENSORS_TLV320AIC23=y
+CONFIG_SENSORS_TLV320AIC33=y
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+CONFIG_GPIOEXPANDER_DAVINCI=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
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_NEW_LEDS is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_TVP5146 is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_TUNER_TEA5761 is not set
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_QUICKCAM_MESSENGER is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_USB_W9968CF is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_ZC0301 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_ZR364XX is not set
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_RADIO_TEA5761 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_DAVINCI=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_DAVINCI=y
+CONFIG_SOUND_DAVINCI_AIC33=y
+
+#
+# DaVinci Audio Options
+#
+# CONFIG_MONOSTEREO_DIFFJACK is not set
+CONFIG_MONOSTEREO_SAMEJACK=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=m
+CONFIG_USB_MUSB_SOC=y
+
+#
+# DaVinci 644x USB support
+#
+# CONFIG_USB_MUSB_HOST is not set
+CONFIG_USB_MUSB_PERIPHERAL=y
+# CONFIG_USB_MUSB_OTG is not set
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_INVENTRA_FIFO=y
+CONFIG_USB_INVENTRA_HCD_LOGGING=0
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# 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 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_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# 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_AUERSWALD 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
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+
+#
+# MMC/SD Host Controller Drivers
+#
+# CONFIG_MMC_DAVINCI is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=m
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=m
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT 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=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# 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_BUGVERBOSE is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index bac988e..0514c85 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -14,10 +14,36 @@
bool "TI DaVinci EVM"
default y
depends on ARCH_DAVINCI644x
+ select GPIOEXPANDER_DAVINCI
help
Configure this option to specify the whether the board used
for development is a DaVinci EVM
+config DAVINCI_I2C_EXPANDER
+ bool "TI DaVinci I2C Expander"
+ default y
+ depends on I2C && ARCH_DAVINCI644x
+ help
+ Configure this option to specify whether the board used
+ has I2C exapnder with ATA, USB, CF.
+
+config DAVINCI_MCBSP
+ bool
+ prompt "DaVinci McBSP Driver" if SOUND_DAVINCI=n
+ depends on ARCH_DAVINCI
+ default SOUND_DAVINCI
+ ---help---
+ DaVinci McBSP driver. Auto-enabled by DaVinci sound driver.
+
+comment "DaVinci Options"
+
+config DAVINCI_BLK_DEV_CF
+ bool "TI DaVinci CF Card Support"
+ default Y
+ depends on BLK_DEV_DAVINCI
+ help
+ Configure this option to enable CF Card support.
+
endmenu
endif
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index 99ac2e5..666b323 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -5,7 +5,13 @@
# Common objects
obj-y := time.o irq.o clock.o serial.o io.o id.o psc.o \
- gpio.o mux.o
+ gpio.o mux.o dma.o devices.o
# Board specific
-obj-$(CONFIG_MACH_DAVINCI_EVM) += board-evm.o
+obj-$(CONFIG_MACH_DAVINCI_EVM) += board-evm.o i2c-emac.o
+obj-$(CONFIG_DAVINCI_MCBSP) += mcbsp.o
+obj-$(CONFIG_DAVINCI_I2C_EXPANDER) += i2c-client.o
+
+ifeq ($(CONFIG_LEDS),y)
+obj-$(CONFIG_MACH_DAVINCI_EVM) += leds-evm.o
+endif
diff --git a/arch/arm/mach-davinci/board-evm.c b/arch/arm/mach-davinci/board-evm.c
index 9e4024c..8db3411 100644
--- a/arch/arm/mach-davinci/board-evm.c
+++ b/arch/arm/mach-davinci/board-evm.c
@@ -27,6 +27,7 @@
#include <asm/mach/flash.h>
#include <asm/arch/common.h>
+#include <asm/arch/psc.h>
/* other misc. init functions */
void __init davinci_psc_init(void);
@@ -92,8 +93,89 @@
.resource = &davinci_evm_flash_resource,
};
+#if defined(CONFIG_FB_DAVINCI) || defined(CONFIG_FB_DAVINCI_MODULE)
+
+static u64 davinci_fb_dma_mask = DMA_32BIT_MASK;
+
+static struct platform_device davinci_fb_device = {
+ .name = "davincifb",
+ .id = -1,
+ .dev = {
+ .dma_mask = &davinci_fb_dma_mask,
+ .coherent_dma_mask = DMA_32BIT_MASK,
+ },
+ .num_resources = 0,
+};
+#endif
+
+/*
+ * USB
+ */
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+
+#include <linux/usb/musb.h>
+
+static struct musb_hdrc_platform_data usb_data = {
+#if defined(CONFIG_USB_MUSB_OTG)
+ /* OTG requires a Mini-AB connector */
+ .mode = MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_PERIPHERAL)
+ .mode = MUSB_PERIPHERAL,
+#elif defined(CONFIG_USB_MUSB_HOST)
+ .mode = MUSB_HOST,
+#endif
+ /* irlml6401 switches 5V */
+ .power = 250, /* sustains 3.0+ Amps (!) */
+ .potpgt = 4, /* ~8 msec */
+
+ /* REVISIT multipoint is a _chip_ capability; not board specific */
+ .multipoint = 1,
+};
+
+static struct resource usb_resources [] = {
+ {
+ /* physical address */
+ .start = DAVINCI_USB_OTG_BASE,
+ .end = DAVINCI_USB_OTG_BASE + 0x5ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_USBINT,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 usb_dmamask = DMA_32BIT_MASK;
+
+static struct platform_device usb_dev = {
+ .name = "musb_hdrc",
+ .id = -1,
+ .dev = {
+ .platform_data = &usb_data,
+ .dma_mask = &usb_dmamask,
+ .coherent_dma_mask = DMA_32BIT_MASK,
+ },
+ .resource = usb_resources,
+ .num_resources = ARRAY_SIZE(usb_resources),
+};
+
+#define setup_usb(void) do {} while(0)
+#endif /* CONFIG_USB_MUSB_HDRC */
+
+static struct platform_device rtc_dev = {
+ .name = "rtc_davinci_evm",
+ .id = -1,
+};
+
static struct platform_device *davinci_evm_devices[] __initdata = {
&davinci_evm_flash_device,
+#if defined(CONFIG_FB_DAVINCI) || defined(CONFIG_FB_DAVINCI_MODULE)
+ &davinci_fb_device,
+#endif
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+ &usb_dev,
+#endif
+ &rtc_dev,
};
static void __init
@@ -113,6 +195,8 @@
platform_add_devices(davinci_evm_devices,
ARRAY_SIZE(davinci_evm_devices));
+
+ setup_usb();
}
static __init void davinci_evm_irq_init(void)
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index 139ceaa..275e5cf 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -59,7 +59,7 @@
goto found;
}
}
-
+
list_for_each_entry(p, &clocks, node) {
if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
clk = p;
@@ -102,7 +102,7 @@
{
unsigned long flags;
int ret = 0;
-
+
if (clk == NULL || IS_ERR(clk))
return -EINVAL;
@@ -291,10 +291,10 @@
}
static struct seq_operations davinci_ck_op = {
- .start = davinci_ck_start,
- .next = davinci_ck_next,
- .stop = davinci_ck_stop,
- .show = davinci_ck_show
+ .start = davinci_ck_start,
+ .next = davinci_ck_next,
+ .stop = davinci_ck_stop,
+ .show = davinci_ck_show
};
static int davinci_ck_open(struct inode *inode, struct file *file)
@@ -320,4 +320,4 @@
}
__initcall(davinci_ck_proc_init);
-#endif /* CONFIG_DEBUG_PROC_FS */
+#endif /* CONFIG_DEBUG_PROC_FS */
diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
index ed47079..f0061f5 100644
--- a/arch/arm/mach-davinci/clock.h
+++ b/arch/arm/mach-davinci/clock.h
@@ -1,7 +1,7 @@
/*
* TI DaVinci clock definitions
*
- * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2006 Texas Instruments.
*
* 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
diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c
new file mode 100644
index 0000000..ad26dcd
--- /dev/null
+++ b/arch/arm/mach-davinci/devices.c
@@ -0,0 +1,66 @@
+/*
+ * linux/arch/arm/mach-davinci/devices.c
+ *
+ * DaVinci platform device setup/initialization
+ *
+ * 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/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#if defined(CONFIG_I2C_DAVINCI) || defined(CONFIG_I2C_DAVINCI_MODULE)
+
+static struct resource i2c_resources[] = {
+ {
+ .start = IO_ADDRESS(DAVINCI_I2C_BASE),
+ .end = IO_ADDRESS(DAVINCI_I2C_BASE) + 0x40,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device davinci_i2c_device = {
+ .name = "i2c_davinci",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(i2c_resources),
+ .resource = i2c_resources,
+};
+
+static void davinci_init_i2c(void)
+{
+ (void) platform_device_register(&davinci_i2c_device);
+}
+
+#else
+
+static void davinci_init_i2c(void) {}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static int __init davinci_init_devices(void)
+{
+ /* please keep these calls, and their implementations above,
+ * in alphabetical order so they're easier to sort through.
+ */
+ davinci_init_i2c();
+
+ return 0;
+}
+arch_initcall(davinci_init_devices);
+
diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c
new file mode 100644
index 0000000..b6e2dfa
--- /dev/null
+++ b/arch/arm/mach-davinci/dma.c
@@ -0,0 +1,1731 @@
+/*
+ * linux/arch/arm/mach-davinci/dma.c
+ *
+ * TI DaVinci DMA file
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <asm/arch/memory.h>
+#include <linux/kernel.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/irqs.h>
+
+#include <asm/arch/edma.h>
+
+static spinlock_t dma_chan_lock;
+static struct device_driver edma_driver;
+static struct platform_device edma_dev;
+
+#define LOCK_INIT spin_lock_init(&dma_chan_lock)
+#define LOCK spin_lock(&dma_chan_lock)
+#define UNLOCK spin_unlock(&dma_chan_lock)
+
+typedef void (*intr_callback) (void);
+static int register_dma_interrupts(intr_callback, intr_callback, intr_callback,
+ intr_callback);
+
+#define DAVINCI_DMA_REGISTER_BASE DAVINCI_DMA_3PCC_BASE
+
+static edmacc_regs *get_edma_base(void)
+{
+ return ((edmacc_regs *) IO_ADDRESS(DAVINCI_DMA_REGISTER_BASE));
+}
+
+static intr_callback cb[4];
+
+/* Structure containing the dma channel parameters */
+static struct davinci_dma_lch {
+ int dev_id;
+ int in_use; /* 1-used 0-unused */
+ int link_lch;
+ int dma_running;
+ int param_no;
+ int tcc;
+} dma_chan[DAVINCI_EDMA_NUM_PARAMENTRY];
+
+static struct dma_interrupt_data {
+ void (*callback) (int lch, unsigned short ch_status, void *data);
+ void *data;
+} intr_data[64];
+
+/*
+ Each bit field of the elements bellow indicate the corresponding EDMA channel
+ availability on arm side events
+*/
+static unsigned long edma_channels_arm[] = {
+ 0xffffffff,
+ 0xffffffff
+};
+
+/*
+ Each bit field of the elements bellow indicate the corresponding QDMA channel
+ availability on arm side events
+*/
+static unsigned char qdma_channels_arm[] = {
+ 0x00
+};
+
+/*
+ Each bit field of the elements bellow indicate corresponding PARAM entry
+ availibility on arm side events
+*/
+static unsigned long param_entry_arm[] = {
+ 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
+};
+
+/*
+ Each bit field of the elements bellow indicate whether a PARAM entry
+ is free or in use
+ 1 - free
+ 0 - in use
+*/
+static unsigned long param_entry_use_status[] = {
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff
+};
+
+/*
+ Each bit field of the elements bellow indicate whether a intrerrupt
+ is free or in use
+ 1 - free
+ 0 - in use
+*/
+static unsigned long dma_intr_use_status[] = {
+ 0xffffffff,
+ 0xffffffff
+};
+
+/*
+ This lists the DMA channel numbers which does not have any events
+ associated with it
+*/
+static int dma_chan_no_event[] = {
+ 0, 1, 12, 13, 14, 15, 25, 30, 31, 45, 46, 47, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, -1
+};
+
+static int channel_queue_mapping[][2] = {
+/* {channel no, event queue no } */
+ {0, 0}, {1, 1}, {2, 0}, {3, 1}, {4, 0}, {5, 1}, {6, 0}, {7, 1},
+ {8, 0}, {9, 1}, {10, 0}, {11, 1}, {12, 0}, {13, 1}, {14, 0},
+ {15, 1}, {16, 0}, {17, 1}, {18, 0}, {19, 1}, {20, 0}, {21, 1},
+ {22, 0}, {23, 1}, {24, 0}, {25, 1}, {26, 0}, {27, 1}, {28, 0},
+ {29, 1}, {30, 0}, {31, 1}, {32, 0}, {33, 1}, {34, 0}, {35, 1},
+ {36, 0}, {37, 1}, {38, 0}, {39, 1}, {40, 0}, {41, 1}, {42, 0},
+ {43, 1}, {44, 0}, {45, 1}, {46, 0}, {47, 1}, {48, 0}, {49, 1},
+ {50, 0}, {51, 1}, {52, 0}, {53, 1}, {54, 0}, {55, 1}, {56, 0},
+ {57, 1}, {58, 0}, {59, 1}, {60, 0}, {61, 1}, {62, 0}, {63, 1},
+ {64, 0}, {65, 1}, {66, 0}, {67, 1}, {68, 0}, {69, 1}, {70, 0},
+ {71, 1}, {-1, -1}
+};
+
+static int queue_tc_mapping[DAVINCI_EDMA_NUM_EVQUE + 1][2] = {
+/* {event queue no, TC no} */
+ {0, 0},
+ {1, 1},
+ {-1, -1}
+};
+
+static int queue_priority_mapping[DAVINCI_EDMA_NUM_EVQUE + 1][2] = {
+ /* {event queue no, Priority} */
+ {0, 0},
+ {1, 1},
+ {-1, -1}
+};
+
+static int qdam_to_param_mapping[8] = { 0 };
+
+volatile edmacc_regs *ptr_edmacc_regs = NULL;
+
+/*****************************************************************************/
+
+static void map_dmach_queue(int ch_no, int queue_no)
+{
+ if (ch_no < DAVINCI_EDMA_NUM_DMACH) {
+ int bit_start = (ch_no % 8) * 4;
+ ptr_edmacc_regs->dmaqnum[ch_no >> 3] &= (~(0x7 << bit_start));
+ ptr_edmacc_regs->dmaqnum[ch_no >> 3] |=
+ ((queue_no & 0x7) << bit_start);
+ } else if (ch_no >= DAVINCI_EDMA_NUM_DMACH
+ &&
+ ch_no < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ int bit_start = (ch_no - DAVINCI_EDMA_NUM_DMACH) * 4;
+ ptr_edmacc_regs->qdmaqnum &= (~(0x7 << bit_start));
+ ptr_edmacc_regs->qdmaqnum |= ((queue_no & 0x7) << bit_start);
+ }
+}
+
+/* For Davinci this Macro supports mapping only for QDMA channels and PaRam
+ entry */
+static void map_dmach_param(int ch_no, int param_no)
+{
+ if (ch_no >= DAVINCI_EDMA_NUM_DMACH
+ && ch_no < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ ptr_edmacc_regs->qchmap[ch_no - DAVINCI_EDMA_NUM_DMACH] &=
+ ~(PAENTRY | TRWORD);
+ ptr_edmacc_regs->qchmap[ch_no - DAVINCI_EDMA_NUM_DMACH] |=
+ (((param_no & 0x1ff) << 5) | (QDMA_TRWORD << 2));
+ }
+}
+
+static void map_queue_tc(int queue_no, int tc_no)
+{
+ int bit_start = queue_no * 4;
+ ptr_edmacc_regs->quetcmap &= ~(0x7 << bit_start);
+ ptr_edmacc_regs->quetcmap |= ((tc_no & 0x7) << bit_start);
+}
+
+static void assign_priority_to_queue(int queue_no, int priority)
+{
+ int bit_start = queue_no * 4;
+ ptr_edmacc_regs->quepri &= ~(0x7 << bit_start);
+ ptr_edmacc_regs->quepri |= ((priority & 0x7) << bit_start);
+}
+
+/******************************************************************************
+ *
+ * DMA Param entry requests: Requests for the param structure entry for the dma
+ * channel passed
+ * Arguments:
+ * lch - logical channel for which param entry is being requested.
+ *
+ * Return: param number on success, or negative error number on failure
+ *
+ *****************************************************************************/
+static int request_param(int lch, int dev_id)
+{
+ int i = 0, j = 0, is_break = 0;
+ if (lch >= 0 && lch < DAVINCI_EDMA_NUM_DMACH) {
+ /*
+ In davinci there is 1:1 mapping between edma channels
+ and param sets
+ */
+ LOCK;
+ /* It maintains param entry availability bitmap which
+ could be updated by several thread same channel
+ and so requires protection
+ */
+ param_entry_use_status[lch / 32] &= (~(1 << (lch % 32)));
+ UNLOCK;
+ return lch;
+ } else {
+ if (dev_id >= DAVINCI_DMA_QDMA0 &&
+ dev_id <= DAVINCI_DMA_QDMA7) {
+ i = 0;
+ } else if (dev_id == DAVINCI_EDMA_PARAM_ANY) {
+ i = DAVINCI_EDMA_NUM_DMACH;
+ }
+
+ /* This allocation alogrithm requires complete lock because
+ availabilty of param entry is checked from structure
+ param_entry_use_status and same struct is updated back also
+ once allocated
+ */
+
+ LOCK;
+ while (i < DAVINCI_EDMA_NUM_PARAMENTRY) {
+ j = 0, is_break = 1;
+ if ((param_entry_arm[i / 32] & (1 << (i % 32))) &&
+ (param_entry_use_status[i / 32] & (1 << (i % 32))))
+ {
+ if (dev_id != DAVINCI_EDMA_PARAM_ANY) {
+ while (dma_chan_no_event[j] != -1) {
+ if (dma_chan_no_event[j] == i) {
+ is_break = 0;
+ }
+ j++;
+ }
+ if (!is_break) {
+ break;
+ }
+ } else {
+ break;
+ }
+ i++;
+ } else {
+ i++;
+ }
+ }
+ if (i < DAVINCI_EDMA_NUM_PARAMENTRY) {
+ param_entry_use_status[i / 32] &= (~(1 << (i % 32)));
+ UNLOCK;
+ dev_dbg(&edma_dev.dev, "param no=%d\r\n", i);
+ return i;
+ } else {
+ UNLOCK;
+ return -1; /* no free param */
+ }
+ }
+}
+
+/******************************************************************************
+ *
+ * Free dma param entry: Freethe param entry number passed
+ * Arguments:
+ * param_no - Param entry to be released or freed out
+ *
+ * Return: N/A
+ *
+ *****************************************************************************/
+static void free_param(int param_no)
+{
+ if (param_no >= 0 && param_no < DAVINCI_EDMA_NUM_PARAMENTRY) {
+ LOCK;
+ /* This is global data structure and could be accessed
+ by several thread
+ */
+ param_entry_use_status[param_no / 32] |= (1 << (param_no % 32));
+ UNLOCK;
+ }
+}
+
+/******************************************************************************
+ *
+ * DMA interrupt requests: Requests for the interrupt on the free channel
+ *
+ * Arguments:
+ * lch - logical channel number for which the interrupt is to be requested
+ * for the free channel.
+ * callback - callback function registered for the requested interrupt
+ * channel
+ * data - channel private data.
+ *
+ * Return: free interrupt channel number on success, or negative error number
+ * on failure
+ *
+ *****************************************************************************/
+static int request_dma_interrupt(int lch,
+ void (*callback) (int lch,
+ unsigned short ch_status,
+ void *data),
+ void *data, int param_no, int requested_tcc)
+{
+ signed int free_intr_no = -1;
+ int i = 0, j = 0, is_break = 0;
+ /* edma channels */
+ if (lch >= 0 && lch < DAVINCI_EDMA_NUM_DMACH) {
+ /* Bitmap dma_intr_use_status is used to identify availabe tcc
+ for interrupt purpose. This could be modified by several
+ thread and same structure is checked availabilty as well as
+ updated once it's found that resource is avialable */
+ LOCK;
+ if (dma_intr_use_status[lch / 32] & (1 << (lch % 32))) {
+ /* in use */
+ dma_intr_use_status[lch / 32] &= (~(1 << (lch % 32)));
+ UNLOCK;
+ free_intr_no = lch;
+ dev_dbg(&edma_dev.dev, "interrupt no=%d\r\n", free_intr_no);
+ } else {
+ UNLOCK;
+ dev_dbg(&edma_dev.dev, "EDMA:Error\r\n");
+ return -1;
+ }
+ }
+
+ /* qdma channels */
+ else if (lch >= DAVINCI_EDMA_NUM_DMACH
+ && lch < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ if (requested_tcc != TCC_ANY) {
+ /* Complete allocation algo requires lock and as it's
+ shared resources could be invoked by several thread.
+ Structure dma_intr_use_status is used to check
+ whether resource is availabe or not and latter marked
+ as not available in the same structure */
+ LOCK;
+ if (dma_intr_use_status[requested_tcc / 32] &
+ (1 << (requested_tcc % 32))) {
+ j = 0;
+ is_break = 1;
+ while (dma_chan_no_event[j] != -1) {
+ if (dma_chan_no_event[j] ==
+ requested_tcc) {
+ is_break = 0;
+ break;
+ }
+ j++;
+ }
+ if (!is_break) {
+ dma_intr_use_status[requested_tcc / 32]
+ &= (~(1 << (requested_tcc % 32)));
+ free_intr_no = requested_tcc;
+ dev_dbg(&edma_dev.dev,
+ "interrupt no=%d\r\n",
+ free_intr_no);
+ } else {
+ UNLOCK;
+ dev_dbg(&edma_dev.dev,
+ "Error - wrong tcc passed\r\n");
+ return -1;
+ }
+ UNLOCK;
+ } else {
+ UNLOCK;
+ dev_dbg(&edma_dev.dev,
+ "Error - wrong tcc passed\r\n");
+ return -1;
+ }
+ } else {
+ i = 0;
+ LOCK;
+ while (i < DAVINCI_EDMA_NUM_DMACH) {
+ j = 0;
+ is_break = 1;
+ if (dma_intr_use_status[i / 32] &
+ (1 << (i % 32))) {
+ while (dma_chan_no_event[j] != -1) {
+ if (dma_chan_no_event[j] == i) {
+ is_break = 0;
+ break;
+ }
+ j++;
+ }
+ if (!is_break) {
+ dma_intr_use_status[i / 32] &=
+ (~(1 << (i % 32)));
+ free_intr_no = i;
+
+ dev_dbg(&edma_dev.dev,
+ "interrupt no=%d\r\n",
+ free_intr_no);
+ break;
+ }
+ i++;
+ } else {
+ i++;
+ }
+ }
+ UNLOCK;
+ }
+ } else {
+ dev_dbg(&edma_dev.dev, "ERROR lch = %d\r\n", lch);
+ }
+ if (is_break) {
+ dev_dbg(&edma_dev.dev, "While allocating EDMA channel for QDMA");
+ }
+ if (lch >= DAVINCI_EDMA_NUM_DMACH && lch <
+ (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ if (free_intr_no < 32) {
+ ptr_edmacc_regs->dra[0].drae =
+ ptr_edmacc_regs->dra[0].drae | (1 << free_intr_no);
+ } else {
+ ptr_edmacc_regs->dra[0].draeh =
+ ptr_edmacc_regs->dra[0].
+ draeh | (1 << (free_intr_no - 32));
+ }
+ }
+ if (free_intr_no >= 0 && free_intr_no < 64) {
+ (free_intr_no < 32) ?
+ (ptr_edmacc_regs->shadow[0].iesr |= (1UL << free_intr_no))
+ : (ptr_edmacc_regs->shadow[0].iesrh |=
+ (1UL << (free_intr_no - 32)));
+ intr_data[free_intr_no].callback = callback;
+ intr_data[free_intr_no].data = data;
+ }
+ return free_intr_no;
+}
+
+/******************************************************************************
+ *
+ * Free the dma interrupt: Releases the dma interrupt on the channel
+ *
+ * Arguments:
+ * intr_no - interrupt number on the channel to be released or freed out
+ *
+ * Return: N/A
+ *
+ *****************************************************************************/
+static void free_dma_interrupt(int intr_no)
+{
+ if (intr_no >= 0 && intr_no < 64) {
+ (intr_no < 32) ? (ptr_edmacc_regs->shadow[0].icr |=
+ (1UL << (intr_no))) : (ptr_edmacc_regs->
+ shadow[0].icrh |=
+ (1UL <<
+ (intr_no - 32)));
+ LOCK;
+ /* Global structure and could be modified by several task */
+ dma_intr_use_status[intr_no / 32] |= (1 << (intr_no % 32));
+ UNLOCK;
+ intr_data[intr_no].callback = NULL;
+ intr_data[intr_no].data = NULL;
+
+ }
+}
+
+/******************************************************************************
+ *
+ * DMA interrupt handler
+ *
+ *****************************************************************************/
+static void dma_irq_handler(void)
+{
+ int i;
+ unsigned int cnt;
+ cnt = 0;
+ if ((ptr_edmacc_regs->shadow[0].ipr == 0)
+ && (ptr_edmacc_regs->shadow[0].iprh == 0))
+ return;
+ while (1) {
+ if (ptr_edmacc_regs->shadow[0].ipr) {
+ dev_dbg(&edma_dev.dev, "IPR =%d\r\n",
+ ptr_edmacc_regs->shadow[0].ipr);
+ for (i = 0; i < 32; i++) {
+ if (ptr_edmacc_regs->shadow[0].ipr & (1 << i)) {
+ /* Clear the corresponding IPR bits */
+ ptr_edmacc_regs->shadow[0].icr |=
+ (1 << i);
+ if (intr_data[i].callback) {
+ intr_data[i].callback(i,
+ DMA_COMPLETE,
+ intr_data
+ [i].data);
+
+ }
+ }
+ }
+ } else if (ptr_edmacc_regs->shadow[0].iprh) {
+ dev_dbg(&edma_dev.dev, "IPRH =%d\r\n",
+ ptr_edmacc_regs->shadow[0].iprh);
+ for (i = 0; i < 32; i++) {
+ if (ptr_edmacc_regs->shadow[0].iprh & (1 << i)) {
+ /* Clear the corresponding IPR bits */
+ ptr_edmacc_regs->shadow[0].icrh |=
+ (1 << i);
+ if (intr_data[32 + i].callback) {
+ intr_data[32 + i].callback(32 +
+ i,
+ DMA_COMPLETE,
+ intr_data
+ [32 +
+ i].
+ data);
+ }
+ }
+ }
+ }
+ if ((ptr_edmacc_regs->shadow[0].ipr == 0)
+ && (ptr_edmacc_regs->shadow[0].iprh == 0)) {
+ break;
+ }
+ cnt++;
+ if (cnt > 10) {
+ break;
+ }
+ }
+ ptr_edmacc_regs->shadow[0].ieval = 0x1;
+}
+
+/******************************************************************************
+ *
+ * DMA error interrupt handler
+ *
+ *****************************************************************************/
+static void dma_ccerr_handler(void)
+{
+ int i;
+ unsigned int cnt;
+ cnt = 0;
+ if ((ptr_edmacc_regs->emr == 0) && (ptr_edmacc_regs->emr == 0) &&
+ (ptr_edmacc_regs->qemr == 0) && (ptr_edmacc_regs->ccerr == 0))
+ return;
+ while (1) {
+ if (ptr_edmacc_regs->emr) {
+ dev_dbg(&edma_dev.dev, "EMR =%d\r\n", ptr_edmacc_regs->emr);
+ for (i = 0; i < 32; i++) {
+ if (ptr_edmacc_regs->emr & (1 << i)) {
+ /* Clear the corresponding EMR bits */
+ ptr_edmacc_regs->emcr |= (1 << i);
+ /* Clear any SER */
+ ptr_edmacc_regs->shadow[0].secr |=
+ (1 << i);
+ if (intr_data[i].callback) {
+ intr_data[i].callback(i,
+ DMA_CC_ERROR,
+ intr_data
+ [i].data);
+ }
+ }
+ }
+ } else if (ptr_edmacc_regs->emrh) {
+ dev_dbg(&edma_dev.dev, "EMRH =%d\r\n",
+ ptr_edmacc_regs->emrh);
+ for (i = 0; i < 32; i++) {
+ if (ptr_edmacc_regs->emrh & (1 << i)) {
+ /* Clear the corresponding IPR bits */
+ ptr_edmacc_regs->emcrh |= (1 << i);
+ /* Clear any SER */
+ ptr_edmacc_regs->shadow[0].secrh |=
+ (1 << i);
+ if (intr_data[i].callback) {
+ intr_data[i].callback(i,
+ DMA_CC_ERROR,
+ intr_data
+ [i].data);
+ }
+ }
+ }
+ } else if (ptr_edmacc_regs->qemr) {
+ dev_dbg(&edma_dev.dev, "QEMR =%d\r\n",
+ ptr_edmacc_regs->qemr);
+ for (i = 0; i < 8; i++) {
+ if (ptr_edmacc_regs->qemr & (1 << i)) {
+ /* Clear the corresponding IPR bits */
+ ptr_edmacc_regs->qemcr |= (1 << i);
+ ptr_edmacc_regs->shadow[0].qsecr |=
+ (1 << i);
+ }
+ }
+ } else if (ptr_edmacc_regs->ccerr) {
+ dev_dbg(&edma_dev.dev, "CCERR =%d\r\n",
+ ptr_edmacc_regs->ccerr);
+ for (i = 0; i < 8; i++) {
+ if (ptr_edmacc_regs->ccerr & (1 << i)) {
+ /* Clear the corresponding IPR bits */
+ ptr_edmacc_regs->ccerrclr |= (1 << i);
+ }
+ }
+ }
+ if ((ptr_edmacc_regs->emr == 0)
+ && (ptr_edmacc_regs->emrh == 0)
+ && (ptr_edmacc_regs->qemr == 0)
+ && (ptr_edmacc_regs->ccerr == 0)) {
+ break;
+ }
+ cnt++;
+ if (cnt > 10) {
+ break;
+ }
+ }
+ ptr_edmacc_regs->eeval = 0x1;
+}
+
+/******************************************************************************
+ *
+ * DMA error interrupt handler
+ *
+ *****************************************************************************/
+static void dma_tc1err_handler(void)
+{
+
+}
+
+/******************************************************************************
+ *
+ * DMA error interrupt handler
+ *
+ *****************************************************************************/
+static void dma_tc2err_handler(void)
+{
+
+}
+
+/******************************************************************************
+ *
+ * DMA initialisation on davinci
+ *
+ *****************************************************************************/
+int __init arch_dma_init(void)
+{
+ int i;
+ edma_driver.name = "edma";
+ edma_dev.name = "dma";
+ edma_dev.id = -1;
+ edma_dev.dev.driver = &edma_driver;
+
+ ptr_edmacc_regs = get_edma_base();
+ dev_dbg(&edma_dev.dev, "DMA REG BASE ADDR=%x\n",
+ (unsigned int)ptr_edmacc_regs);
+ memset(dma_chan, 0x00, sizeof(dma_chan));
+ memset((void *)&(ptr_edmacc_regs->paramentry[0]), 0x00,
+ sizeof(ptr_edmacc_regs->paramentry));
+ i = 0;
+ /* Channel to queue mapping */
+ while (channel_queue_mapping[i][0] != -1) {
+ map_dmach_queue(channel_queue_mapping[i][0],
+ channel_queue_mapping[i][1]);
+ i++;
+ }
+ i = 0;
+ /* Event queue to TC mapping */
+ while (queue_tc_mapping[i][0] != -1) {
+ map_queue_tc(queue_tc_mapping[i][0], queue_tc_mapping[i][1]);
+ i++;
+ }
+ i = 0;
+ /* Event queue priority mapping */
+ while (queue_priority_mapping[i][0] != -1) {
+ assign_priority_to_queue(queue_priority_mapping[i][0],
+ queue_priority_mapping[i][1]);
+ i++;
+ }
+ for (i = 0; i < DAVINCI_EDMA_NUM_REGIONS; i++) {
+ ptr_edmacc_regs->dra[i].drae = 0x0;
+ ptr_edmacc_regs->dra[i].draeh = 0x0;
+ ptr_edmacc_regs->qrae[i] = 0x0;
+ }
+ LOCK_INIT;
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * DMA channel requests: Requests for the dma device passed if it is free
+ *
+ * Arguments:
+ * dev_id - request for the param entry device id
+ * dev_name - device name
+ * callback - pointer to the channel callback.
+ * Arguments:
+ * lch - channel no, which is the IPR bit position,
+ * indicating from which channel the interrupt arised.
+ * data - channel private data, which is received as one of the
+ * arguments in davinci_request_dma.
+ * data - private data for the channel to be requested, which is used to
+ * pass as a parameter in the callback function
+ * in irq handler.
+ * lch - contains the device id allocated
+ * tcc - Transfer Completion Code, used to set the IPR register bit
+ * after transfer completion on that channel.
+ * eventq_no - Event Queue no to which the channel will be associated with
+ * (valied only if you are requesting for a DMA MasterChannel)
+ * Values : 0 to 7
+ * -1 for Default queue
+ * INPUT: dev_id
+ * OUTPUT: *dma_ch_out
+ *
+ * Return: zero on success, or corresponding error no on failure
+ *
+ *****************************************************************************/
+int davinci_request_dma(int dev_id, const char *dev_name,
+ void (*callback) (int lch, unsigned short ch_status,
+ void *data),
+ void *data, int *lch,
+ int *tcc, enum dma_event_q eventq_no)
+{
+
+ int ret_val = 0, i = 0;
+ static int req_flag = 0;
+ int temp_ch = 0;
+ /* checking the ARM side events */
+ if (dev_id >= 0 && (dev_id < DAVINCI_EDMA_NUM_DMACH)) {
+ if (!(edma_channels_arm[dev_id / 32] & (0x1 << (dev_id % 32)))) {
+ dev_dbg(&edma_dev.dev,
+ "dev_id = %d not supported on ARM side\r\n",
+ dev_id);
+ return -EINVAL;
+ }
+ } else if (dev_id >= DAVINCI_EDMA_NUM_DMACH
+ && dev_id <=
+ (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ if (!(qdma_channels_arm[0] &
+ (0x1 << (dev_id - DAVINCI_EDMA_NUM_DMACH)))) {
+
+ dev_dbg(&edma_dev.dev,
+ "dev_id = %d not supported on ARM side\r\n",
+ dev_id);
+ return -EINVAL;
+ }
+ }
+
+ if ((dev_id != DAVINCI_DMA_CHANNEL_ANY)
+ && (dev_id != DAVINCI_EDMA_PARAM_ANY)) {
+ if (dev_id >= DAVINCI_EDMA_NUM_DMACH
+ &&
+ dev_id < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)
+ ) {
+ ptr_edmacc_regs->qrae[0] =
+ ptr_edmacc_regs->qrae[0] |
+ (1 << (dev_id - DAVINCI_EDMA_NUM_DMACH));
+ } else {
+ if (dev_id < 32) {
+ ptr_edmacc_regs->dra[0].drae =
+ ptr_edmacc_regs->dra[0].drae |
+ (1 << dev_id);
+ } else {
+ ptr_edmacc_regs->dra[0].draeh =
+ ptr_edmacc_regs->dra[0].draeh |
+ (1 << (dev_id - 32));
+ }
+ }
+ }
+
+ if (!req_flag) {
+ if (register_dma_interrupts
+ (dma_irq_handler, dma_ccerr_handler,
+ dma_tc1err_handler, dma_tc2err_handler)) {
+ dev_dbg(&edma_dev.dev,
+ "register_dma_interrupts failed\r\n");
+ return -EINVAL;
+ } else
+ req_flag = 1;
+ }
+
+ if (dev_id >= 0 && dev_id < (DAVINCI_EDMA_NUM_DMACH)) {
+ /* The 64 Channels are mapped to the first 64 PARAM entries */
+ if (!dma_chan[dev_id].in_use) {
+ *lch = dev_id;
+ dma_chan[*lch].param_no = request_param(*lch, dev_id);
+ if (dma_chan[*lch].param_no == -1) {
+ return -EINVAL;
+ } else
+ dev_dbg(&edma_dev.dev, "param_no=%d\r\n",
+ dma_chan[*lch].param_no);
+ if (callback) {
+ dma_chan[*lch].tcc =
+ request_dma_interrupt(*lch, callback, data,
+ dma_chan[*lch].
+ param_no, *tcc);
+ if (dma_chan[*lch].tcc == -1) {
+ return -EINVAL;
+ } else {
+ *tcc = dma_chan[*lch].tcc;
+ dev_dbg(&edma_dev.dev, "tcc_no=%d\r\n",
+ dma_chan[*lch].tcc);
+ }
+ } else
+ dma_chan[*lch].tcc = -1;
+
+ map_dmach_queue(dev_id, eventq_no);
+ ret_val = 0;
+ } else
+ ret_val = -EINVAL;
+ }
+
+ else if (dev_id >= DAVINCI_EDMA_NUM_DMACH && dev_id <
+ (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ if ((qdam_to_param_mapping[dev_id - DAVINCI_EDMA_NUM_DMACH] !=
+ -1)
+ &&
+ (dma_chan
+ [qdam_to_param_mapping[dev_id - DAVINCI_EDMA_NUM_DMACH]].
+ in_use)
+ ) {
+ ret_val = -EINVAL;
+ } else {
+ *lch = dev_id;
+ dma_chan[*lch].param_no = request_param(*lch, dev_id);
+ if (dma_chan[*lch].param_no == -1) {
+ dev_dbg(&edma_dev.dev, "request_param failed\r\n");
+ return -EINVAL;
+ } else {
+ dev_dbg(&edma_dev.dev, "param_no=%d\r\n",
+ dma_chan[*lch].param_no);
+ map_dmach_param(*lch, dma_chan[*lch].param_no);
+ }
+ if (callback) {
+ dma_chan[*lch].tcc =
+ request_dma_interrupt(*lch, callback, data,
+ dma_chan[*lch].
+ param_no, *tcc);
+ if (dma_chan[*lch].tcc == -1) {
+ return -EINVAL;
+ } else {
+ *tcc = dma_chan[*lch].tcc;
+ dev_dbg(&edma_dev.dev, "tcc_no=%d\r\n",
+ dma_chan[*lch].tcc);
+ }
+ } else
+ dma_chan[*lch].tcc = -1;
+ map_dmach_queue(dev_id, eventq_no);
+ ret_val = 0;
+ }
+ } else if (dev_id == DAVINCI_DMA_CHANNEL_ANY) {
+ i = 0;
+ ret_val = 0;
+ while (dma_chan_no_event[i] != -1) {
+ if (!dma_chan[dma_chan_no_event[i]].in_use) {
+ *lch = dma_chan_no_event[i];
+ dma_chan[*lch].param_no =
+ request_param(*lch, dev_id);
+ if (dma_chan[*lch].param_no == -1) {
+ return -EINVAL;
+ }
+ dev_dbg(&edma_dev.dev, "param_no=%d\r\n",
+ dma_chan[*lch].param_no);
+ if (dma_chan[*lch].param_no >=
+ DAVINCI_EDMA_NUM_DMACH
+ &&
+ dma_chan[*lch].param_no <
+ (DAVINCI_EDMA_NUM_DMACH +
+ DAVINCI_EDMA_NUM_QDMACH)
+ ) {
+
+ ptr_edmacc_regs->qrae[0] =
+ ptr_edmacc_regs->qrae[0] |
+ (1 << (dma_chan[*lch].param_no -
+ DAVINCI_EDMA_NUM_DMACH));
+
+ } else {
+ if (dma_chan[*lch].param_no < 32) {
+ ptr_edmacc_regs->dra[0].drae =
+ ptr_edmacc_regs->dra[0].drae
+ |
+ (1 << dma_chan[*lch].
+ param_no);
+ } else {
+ ptr_edmacc_regs->dra[0].draeh =
+ ptr_edmacc_regs->dra[0].
+ draeh | (1 <<
+ (dma_chan[*lch].
+ param_no - 32));
+ }
+ }
+ if (callback) {
+ dma_chan[*lch].tcc =
+ request_dma_interrupt(*lch,
+ callback,
+ data,
+ dma_chan
+ [*lch].
+ param_no,
+ *tcc);
+ if (dma_chan[*lch].tcc == -1) {
+ return -EINVAL;
+ } else {
+ *tcc = dma_chan[*lch].tcc;
+ }
+ } else {
+ dma_chan[*lch].tcc = -1;
+ }
+ map_dmach_queue(dev_id, eventq_no);
+ ret_val = 0;
+ break;
+ }
+ i++;
+ }
+ }
+
+ else if (dev_id == DAVINCI_EDMA_PARAM_ANY) {
+ ret_val = 0;
+ for (i = (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH);
+ i < DAVINCI_EDMA_NUM_PARAMENTRY; i++) {
+ if (!dma_chan[i].in_use) {
+ dev_dbg(&edma_dev.dev, "any link = %d\r\n", i);
+ *lch = i;
+ dma_chan[*lch].param_no =
+ request_param(*lch, dev_id);
+ if (dma_chan[*lch].param_no == -1) {
+ dev_dbg(&edma_dev.dev,
+ "request_param failed\r\n");
+ return -EINVAL;
+ } else {
+ dev_dbg(&edma_dev.dev, "param_no=%d\r\n",
+ dma_chan[*lch].param_no);
+ }
+ if (*tcc != -1)
+ dma_chan[*lch].tcc = *tcc;
+ else
+ dma_chan[*lch].tcc = -1;
+ ret_val = 0;
+ break;
+ }
+ }
+ } else {
+ ret_val = -EINVAL;
+ }
+ if (!ret_val) {
+ if (dev_id >= DAVINCI_EDMA_NUM_DMACH && dev_id <
+ (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ /* Master Channel */
+ qdam_to_param_mapping[dev_id -
+ DAVINCI_EDMA_NUM_DMACH] =
+ dma_chan[*lch].param_no;
+ LOCK;
+ /* It's used global data structure and used to find out
+ whether channel is available or not */
+ dma_chan[qdam_to_param_mapping
+ [dev_id - DAVINCI_EDMA_NUM_DMACH]].in_use = 1;
+ UNLOCK;
+ dma_chan[qdam_to_param_mapping
+ [dev_id - DAVINCI_EDMA_NUM_DMACH]].dev_id =
+ *lch;
+ dma_chan[qdam_to_param_mapping
+ [dev_id - DAVINCI_EDMA_NUM_DMACH]].tcc =
+ dma_chan[*lch].tcc;
+ temp_ch =
+ qdam_to_param_mapping[dev_id -
+ DAVINCI_EDMA_NUM_DMACH];
+ dma_chan[temp_ch].param_no = dma_chan[*lch].param_no;
+ if (dma_chan[*lch].tcc != -1) {
+ ptr_edmacc_regs->paramentry[dma_chan[temp_ch].
+ param_no].opt &=
+ (~TCC);
+ ptr_edmacc_regs->paramentry[dma_chan[temp_ch].
+ param_no].opt |=
+ ((0x3f & dma_chan[*lch].tcc) << 12);
+ /* set TCINTEN bit in PARAM entry */
+ ptr_edmacc_regs->
+ paramentry[dma_chan[temp_ch].param_no].
+ opt |= TCINTEN;
+ } else {
+ ptr_edmacc_regs->paramentry[dma_chan[temp_ch].
+ param_no].opt &=
+ ~TCINTEN;
+ }
+ /* assign the link field to no link. i.e 0xffff */
+ ptr_edmacc_regs->paramentry[dma_chan[temp_ch].
+ param_no].
+ link_bcntrld |= 0xffff;
+ } else {
+ /* Slave Channel */
+ LOCK;
+ /* Global structure to identify whether resoures is
+ available or not */
+ dma_chan[*lch].in_use = 1;
+ UNLOCK;
+ dma_chan[*lch].dev_id = *lch;
+ if (dma_chan[*lch].tcc != -1) {
+ ptr_edmacc_regs->paramentry[dma_chan[*lch].
+ param_no].opt &=
+ (~TCC);
+ ptr_edmacc_regs->paramentry[dma_chan[*lch].
+ param_no].opt |=
+ ((0x3f & dma_chan[*lch].tcc) << 12);
+ /* set TCINTEN bit in PARAM entry */
+ ptr_edmacc_regs->paramentry[dma_chan[*lch].
+ param_no].opt |=
+ TCINTEN;
+ } else {
+ ptr_edmacc_regs->paramentry[dma_chan[*lch].
+ param_no].opt &=
+ ~TCINTEN;
+ }
+ /* assign the link field to no link. i.e 0xffff */
+ ptr_edmacc_regs->paramentry[dma_chan[*lch].
+ param_no].
+ link_bcntrld |= 0xffff;
+ }
+ }
+ return ret_val;
+}
+
+/******************************************************************************
+ *
+ * DMA channel free: Free dma channle
+ * Arguments:
+ * dev_id - request for the param entry device id
+ *
+ * Return: zero on success, or corresponding error no on failure
+ *
+ *****************************************************************************/
+void davinci_free_dma(int lch)
+{
+ int temp_ch = 0;
+ if (lch >= DAVINCI_EDMA_NUM_DMACH && lch <
+ (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch = qdam_to_param_mapping[lch - DAVINCI_EDMA_NUM_DMACH];
+ lch = temp_ch;
+ }
+ LOCK;
+ dma_chan[lch].in_use = 0;
+ UNLOCK;
+ free_param(dma_chan[lch].param_no);
+
+ if (lch >= 0
+ && lch < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ free_dma_interrupt(dma_chan[lch].tcc);
+ }
+}
+
+/******************************************************************************
+ *
+ * DMA source parameters setup
+ * ARGUMENTS:
+ * lch - channel for which the source parameters to be configured
+ * src_port - Source port address
+ * addressMode - indicates wether addressing mode is fifo.
+ *
+ *****************************************************************************/
+void davinci_set_dma_src_params(int lch, unsigned long src_port,
+ enum address_mode mode, enum fifo_width width)
+{
+ int temp_ch = 0;
+ if (lch >= DAVINCI_EDMA_NUM_DMACH && lch <
+ (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch = qdam_to_param_mapping[lch - DAVINCI_EDMA_NUM_DMACH];
+ lch = temp_ch;
+ }
+ if (lch >= 0 && lch < DAVINCI_EDMA_NUM_PARAMENTRY) {
+ /* set the source port address
+ in source register of param structure */
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].src =
+ src_port;
+ /* set the fifo addressing mode */
+ if (mode) { /* reset SAM and FWID */
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].opt
+ &= (~(SAM | EDMA_FWID));
+ /* set SAM and program FWID */
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].opt
+ |= (mode | ((width & 0x7) << 8));
+ }
+ }
+}
+
+/******************************************************************************
+ *
+ * DMA destination parameters setup
+ * ARGUMENTS:
+ * lch - channel or param device for destination parameters to be configured
+ * dest_port - Destination port address
+ * addressMode - indicates wether addressing mode is fifo.
+ *
+ *****************************************************************************/
+void davinci_set_dma_dest_params(int lch, unsigned long dest_port,
+ enum address_mode mode, enum fifo_width width)
+{
+ int temp_ch = 0;
+ if (lch >= DAVINCI_EDMA_NUM_DMACH && lch <
+ (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch = qdam_to_param_mapping[lch - DAVINCI_EDMA_NUM_DMACH];
+ lch = temp_ch;
+ }
+ if (lch >= 0 && lch < DAVINCI_EDMA_NUM_PARAMENTRY) {
+ /* set the destination port address
+ in dest register of param structure */
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].dst =
+ dest_port;
+ /* set the fifo addressing mode */
+ if (mode) { /* reset DAM and FWID */
+
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].opt
+ &= (~(DAM | EDMA_FWID));
+ /* set DAM and program FWID */
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].opt
+ |= ((mode << 1) | ((width & 0x7) << 8));
+ }
+ }
+}
+
+/******************************************************************************
+ *
+ * DMA source index setup
+ * ARGUMENTS:
+ * lch - channel or param device for configuration of source index
+ * srcbidx - source B-register index
+ * srccidx - source C-register index
+ *
+ *****************************************************************************/
+void davinci_set_dma_src_index(int lch, short src_bidx, short src_cidx)
+{
+ int temp_ch = 0;
+ if (lch >= DAVINCI_EDMA_NUM_DMACH && lch <
+ (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch = qdam_to_param_mapping[lch - DAVINCI_EDMA_NUM_DMACH];
+ lch = temp_ch;
+ }
+
+ if (lch >= 0 && lch < DAVINCI_EDMA_NUM_PARAMENTRY) {
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].src_dst_bidx
+ &= 0xffff0000;
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].src_dst_bidx
+ |= src_bidx;
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].src_dst_cidx
+ &= 0xffff0000;
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].src_dst_cidx
+ |= src_cidx;
+ }
+}
+
+/******************************************************************************
+ *
+ * DMA destination index setup
+ * ARGUMENTS:
+ * lch - channel or param device for configuration of destination index
+ * srcbidx - dest B-register index
+ * srccidx - dest C-register index
+ *
+ *****************************************************************************/
+void davinci_set_dma_dest_index(int lch, short dest_bidx, short dest_cidx)
+{
+ int temp_ch = 0;
+ if (lch >= DAVINCI_EDMA_NUM_DMACH && lch <
+ (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch = qdam_to_param_mapping[lch - DAVINCI_EDMA_NUM_DMACH];
+ lch = temp_ch;
+ }
+ if (lch >= 0 && lch < DAVINCI_EDMA_NUM_PARAMENTRY) {
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].src_dst_bidx
+ &= 0x0000ffff;
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].src_dst_bidx
+ |= ((unsigned long)dest_bidx << 16);
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].src_dst_cidx
+ &= 0x0000ffff;
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].src_dst_cidx
+ |= ((unsigned long)dest_cidx << 16);
+ }
+}
+
+/******************************************************************************
+ *
+ * DMA transfer parameters setup
+ * ARGUMENTS:
+ * lch - channel or param device for configuration of aCount, bCount and
+ * cCount regs.
+ * acnt - acnt register value to be configured
+ * bcnt - bcnt register value to be configured
+ * ccnt - ccnt register value to be configured
+ *
+ *****************************************************************************/
+void davinci_set_dma_transfer_params(int lch, unsigned short acnt,
+ unsigned short bcnt, unsigned short ccnt,
+ unsigned short bcntrld,
+ enum sync_dimension sync_mode)
+{
+ int temp_ch = 0;
+ if (lch >= DAVINCI_EDMA_NUM_DMACH && lch <
+ (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch = qdam_to_param_mapping[lch - DAVINCI_EDMA_NUM_DMACH];
+ lch = temp_ch;
+ }
+ if (lch >= 0 && lch < DAVINCI_EDMA_NUM_PARAMENTRY) {
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].link_bcntrld
+ &= 0x0000ffff;
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].link_bcntrld
+ |= (bcntrld << 16);
+ if (sync_mode == ASYNC)
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].opt
+ &= (~SYNCDIM);
+ else
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].opt
+ |= SYNCDIM;
+ /* Set the acount, bcount, ccount registers */
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].a_b_cnt =
+ (bcnt << 16) | acnt;
+ ptr_edmacc_regs->paramentry[dma_chan[lch].param_no].ccnt = ccnt;
+ }
+}
+
+/******************************************************************************
+ *
+ * davinci_set_dma_params -
+ * ARGUMENTS:
+ * lch - logical channel number
+ *
+ *****************************************************************************/
+void davinci_set_dma_params(int lch, edmacc_paramentry_regs * temp)
+{
+ int temp_ch = 0;
+ if (lch >= DAVINCI_EDMA_NUM_DMACH && lch <
+ (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch = qdam_to_param_mapping[lch - DAVINCI_EDMA_NUM_DMACH];
+ lch = temp_ch;
+ }
+ if (lch >= 0 && lch < DAVINCI_EDMA_NUM_PARAMENTRY) {
+ memcpy((void *)
+ &(ptr_edmacc_regs->
+ paramentry[dma_chan[lch].param_no].opt),
+ (void *)temp, sizeof(edmacc_paramentry_regs));
+ }
+}
+
+/******************************************************************************
+ *
+ * davinci_get_dma_params -
+ * ARGUMENTS:
+ * lch - logical channel number
+ *
+ *****************************************************************************/
+void davinci_get_dma_params(int lch, edmacc_paramentry_regs * temp)
+{
+ int temp_ch = 0;
+ if (lch >= DAVINCI_EDMA_NUM_DMACH && lch <
+ (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch = qdam_to_param_mapping[lch - DAVINCI_EDMA_NUM_DMACH];
+ lch = temp_ch;
+ }
+ if (lch >= 0 && lch < DAVINCI_EDMA_NUM_PARAMENTRY) {
+ memcpy((void *)temp,
+ (void *)&(ptr_edmacc_regs->
+ paramentry[dma_chan[lch].param_no].opt),
+ sizeof(edmacc_paramentry_regs));
+ }
+}
+
+/******************************************************************************
+ *
+ * DMA Strat - Starts the dma on the channel passed
+ * ARGUMENTS:
+ * lch - logical channel number
+ *
+ *****************************************************************************/
+int davinci_start_dma(int lch)
+{
+ int ret_val;
+ if (lch >= 0 && (lch < DAVINCI_EDMA_NUM_DMACH)) {
+ int i = 0;
+ int flag = 0;
+ /* If the dma start request is for the unused events */
+ while (dma_chan_no_event[i] != -1) {
+ if (dma_chan_no_event[i] == lch) {
+ /* EDMA channels without event association */
+ dev_dbg(&edma_dev.dev, "ESR=%x\r\n",
+ ptr_edmacc_regs->shadow[0].esr);
+
+ (lch < 32) ?
+ (ptr_edmacc_regs->shadow[0].esr |=
+ (1UL << lch)) : (ptr_edmacc_regs->
+ shadow[0].esrh |=
+ (1UL << (lch - 32)));
+ flag = 1;
+ ret_val = 0;
+ break;
+ }
+ i++;
+ }
+ if (!flag) {
+ /* EDMA channel with event association */
+ dev_dbg(&edma_dev.dev, "ER=%d\r\n",
+ ptr_edmacc_regs->shadow[0].er);
+ /* Clear any pedning error */
+ (lch < 32) ?
+ (ptr_edmacc_regs->emcr |=
+ (1UL << lch)) :
+ (ptr_edmacc_regs->emcrh |= (1UL << (lch - 32)));
+ /* Clear any SER */
+ (lch < 32) ?
+ (ptr_edmacc_regs->shadow[0].secr |=
+ (1UL << lch)) :
+ (ptr_edmacc_regs->shadow[0].secrh |=
+ (1UL << (lch - 32)));
+
+ (lch < 32) ?
+ (ptr_edmacc_regs->shadow[0].eesr |=
+ (1UL << lch)) :
+ (ptr_edmacc_regs->shadow[0].eesrh |=
+ (1UL << (lch - 32)));
+
+ dev_dbg(&edma_dev.dev, "EER=%d\r\n",
+ ptr_edmacc_regs->shadow[0].eer);
+ ret_val = 0;
+ }
+ } else if ((lch >= DAVINCI_EDMA_NUM_DMACH)
+ && (lch <
+ (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH))) {
+ ptr_edmacc_regs->shadow[0].qeesr |=
+ (1 << (lch - DAVINCI_EDMA_NUM_DMACH));
+ ret_val = 0;
+ } else { /* for slaveChannels */
+ ret_val = EINVAL;
+ }
+ return ret_val;
+}
+
+/******************************************************************************
+ *
+ * DMA Stop - Stops the dma on the channel passed
+ * ARGUMENTS:
+ * lch - logical channel number
+ *
+ *****************************************************************************/
+void davinci_stop_dma(int lch)
+{
+ if (lch < DAVINCI_EDMA_NUM_DMACH) {
+ int flag = 0;
+ int i = 0;
+ /* If the dma stop request is for the unused events */
+ while (dma_chan_no_event[i] != -1) {
+ if (dma_chan_no_event[i] == lch) {
+ /* EDMA channels without event association */
+ /* if the requested channel is one of the
+ unused channels then reset the coresponding
+ bit of ESR-Event Set Register */
+ flag = 1;
+ break;
+ }
+ i++;
+ }
+ if (!flag) {
+ /* EDMA channel with event association */
+ (lch < 32) ? (ptr_edmacc_regs->shadow[0].eecr |=
+ (1UL << lch)) :
+ (ptr_edmacc_regs->shadow[0].eecrh |=
+ (1UL << (lch - 32)));
+ if (lch < 32) {
+ if (ptr_edmacc_regs->shadow[0].er & (1 << lch)) {
+ dev_dbg(&edma_dev.dev, "ER=%x\n",
+ ptr_edmacc_regs->shadow[0].er);
+ ptr_edmacc_regs->shadow[0].ecr |=
+ (1 << lch);
+ }
+ } else {
+ if (ptr_edmacc_regs->shadow[0].erh
+ & (1 << (lch - 32))) {
+ dev_dbg(&edma_dev.dev, "ERH=%x\n",
+ ptr_edmacc_regs->shadow[0].erh);
+ ptr_edmacc_regs->shadow[0].ecrh |=
+ (1 << (lch - 32));
+ }
+ }
+ if (lch < 32) {
+ if (ptr_edmacc_regs->shadow[0].ser & (1 << lch)) {
+ dev_dbg(&edma_dev.dev, "SER=%x\n",
+ ptr_edmacc_regs->shadow[0].ser);
+ ptr_edmacc_regs->shadow[0].secr |=
+ (1 << lch);
+ } else {
+ }
+ } else {
+ if (ptr_edmacc_regs->
+ shadow[0].serh & (1 << (lch - 32))) {
+ dev_dbg(&edma_dev.dev, "SERH=%x\n",
+ ptr_edmacc_regs->shadow[0].
+ serh);
+ ptr_edmacc_regs->shadow[0].secrh |=
+ (1 << (lch - 32));
+ }
+ }
+ if (lch < 32) {
+ if (ptr_edmacc_regs->emr & (1 << lch)) {
+ dev_dbg(&edma_dev.dev, "EMR=%x\n",
+ ptr_edmacc_regs->emr);
+ ptr_edmacc_regs->emcr |= (1 << lch);
+ }
+ } else {
+ if (ptr_edmacc_regs->emrh & (1 << (lch - 32))) {
+ dev_dbg(&edma_dev.dev, "EMRH=%x\n",
+ ptr_edmacc_regs->emrh);
+ ptr_edmacc_regs->emcrh |=
+ (1 << (lch - 32));
+ }
+ }
+ dev_dbg(&edma_dev.dev, "EER=%d\r\n",
+ ptr_edmacc_regs->shadow[0].eer);
+ /* if the requested channel is one of the event channels
+ then just set the link field of the corresponding
+ param entry to 0xffff */
+ }
+ } else if ((lch >= DAVINCI_EDMA_NUM_DMACH)
+ &&
+ (lch < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH))) {
+ /* for QDMA channels */
+ ptr_edmacc_regs->qeecr |= (1 << (lch - DAVINCI_EDMA_NUM_DMACH));
+ dev_dbg(&edma_dev.dev, "QER=%d\r\n", ptr_edmacc_regs->qer);
+ dev_dbg(&edma_dev.dev, "QEER=%d\r\n", ptr_edmacc_regs->qeer);
+ } else if ((lch >= (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH))
+ && lch < DAVINCI_EDMA_NUM_PARAMENTRY) {
+ /* for slaveChannels */
+ ptr_edmacc_regs->paramentry[lch].link_bcntrld &= 0xffff0000;
+ ptr_edmacc_regs->paramentry[lch].link_bcntrld |= 0xffff;
+ } else {
+ }
+}
+
+/******************************************************************************
+ *
+ * DMA channel link - link the two logical channels passed through by linking
+ * the link field of head to the param pointed by the lch_queue.
+ * ARGUMENTS:
+ * lch_head - logical channel number, in which the link field is linked
+ * to the param pointed to by lch_queue
+ * lch_queue - logical channel number or the param entry number, which is to be
+ * linked to the lch_head
+ *
+ *****************************************************************************/
+void davinci_dma_link_lch(int lch_head, int lch_queue)
+{
+ unsigned long link;
+ int temp_ch = 0;
+ if (lch_head >=
+ DAVINCI_EDMA_NUM_DMACH
+ && lch_head < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch =
+ qdam_to_param_mapping[lch_head - DAVINCI_EDMA_NUM_DMACH];
+ lch_head = temp_ch;
+ }
+ if (lch_queue >=
+ DAVINCI_EDMA_NUM_DMACH
+ && lch_queue < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch =
+ qdam_to_param_mapping[lch_queue - DAVINCI_EDMA_NUM_DMACH];
+ lch_queue = temp_ch;
+ }
+ if ((lch_head >= 0 && lch_head < DAVINCI_EDMA_NUM_PARAMENTRY)
+ && (lch_queue >= 0 && lch_queue < DAVINCI_EDMA_NUM_PARAMENTRY)) {
+ /* program LINK */
+ link =
+ (unsigned
+ long)(&
+ (ptr_edmacc_regs->
+ paramentry[dma_chan[lch_queue].param_no].opt));
+ ptr_edmacc_regs->
+ paramentry[dma_chan
+ [lch_head].param_no].link_bcntrld &= 0xffff0000;
+ ptr_edmacc_regs->
+ paramentry[dma_chan
+ [lch_head].
+ param_no].link_bcntrld |= ((unsigned short)
+ link);
+ dma_chan[lch_head].link_lch = lch_queue;
+ }
+}
+
+/******************************************************************************
+ *
+ * DMA channel unlink - unlink the two logical channels passed through by
+ * setting the link field of head to 0xffff.
+ * ARGUMENTS:
+ * lch_head - logical channel number, from which the link field is to be removed
+ * lch_queue - logical channel number or the param entry number, which is to be
+ * unlinked from lch_head
+ *
+ *****************************************************************************/
+void davinci_dma_unlink_lch(int lch_head, int lch_queue)
+{
+ int temp_ch = 0;
+ if (lch_head >=
+ DAVINCI_EDMA_NUM_DMACH
+ && lch_head < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch =
+ qdam_to_param_mapping[lch_head - DAVINCI_EDMA_NUM_DMACH];
+ lch_head = temp_ch;
+ }
+ if (lch_queue >=
+ DAVINCI_EDMA_NUM_DMACH
+ && lch_queue < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch =
+ qdam_to_param_mapping[lch_queue - DAVINCI_EDMA_NUM_DMACH];
+ lch_queue = temp_ch;
+ }
+ if ((lch_head >= 0 && lch_head < DAVINCI_EDMA_NUM_PARAMENTRY)
+ && (lch_queue >= 0 && lch_queue < DAVINCI_EDMA_NUM_PARAMENTRY)) {
+ ptr_edmacc_regs->
+ paramentry[dma_chan
+ [lch_head].param_no].link_bcntrld |= 0xffff;
+ dma_chan[lch_head].link_lch = -1;
+ }
+}
+
+/******************************************************************************
+ *
+ * DMA channel chain - chains the two logical channels passed through by
+ * ARGUMENTS:
+ * lch_head - logical channel number, from which the link field is to be removed
+ * lch_queue - logical channel number or the param entry number, which is to be
+ * unlinked from lch_head
+ *
+ *****************************************************************************/
+void davinci_dma_chain_lch(int lch_head, int lch_queue)
+{
+ int temp_ch = 0;
+ if (lch_head >=
+ DAVINCI_EDMA_NUM_DMACH
+ && lch_head < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch =
+ qdam_to_param_mapping[lch_head - DAVINCI_EDMA_NUM_DMACH];
+ lch_head = temp_ch;
+ }
+ if (lch_queue >=
+ DAVINCI_EDMA_NUM_DMACH
+ && lch_queue < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch =
+ qdam_to_param_mapping[lch_queue - DAVINCI_EDMA_NUM_DMACH];
+ lch_queue = temp_ch;
+ }
+ if ((lch_head >= 0
+ && lch_head < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH))
+ &&
+ (lch_queue >= 0
+ && lch_queue < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH))
+ ) { /* set TCCHEN */
+ /* set TCCHEN */
+ ptr_edmacc_regs->paramentry[lch_head].opt |= TCCHEN;
+ /* program tcc */
+ ptr_edmacc_regs->paramentry[lch_head].opt &= (~TCC);
+ ptr_edmacc_regs->
+ paramentry[lch_head].opt |= (lch_queue & 0x3f) << 12;
+ }
+}
+
+/******************************************************************************
+ *
+ * DMA channel unchain - unchain the two logical channels passed through by
+ * ARGUMENTS:
+ * lch_head - logical channel number, from which the link field is to be removed
+ * lch_queue - logical channel number or the param entry number, which is to be
+ * unlinked from lch_head
+ *
+ *****************************************************************************/
+void davinci_dma_unchain_lch(int lch_head, int lch_queue)
+{
+ int temp_ch = 0;
+ if (lch_head >=
+ DAVINCI_EDMA_NUM_DMACH
+ && lch_head < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch =
+ qdam_to_param_mapping[lch_head - DAVINCI_EDMA_NUM_DMACH];
+ lch_head = temp_ch;
+ }
+ if (lch_queue >=
+ DAVINCI_EDMA_NUM_DMACH
+ && lch_queue < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH)) {
+ temp_ch =
+ qdam_to_param_mapping[lch_queue - DAVINCI_EDMA_NUM_DMACH];
+ lch_queue = temp_ch;
+ }
+ if ((lch_head >= 0
+ && lch_head < (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH))
+ && (lch_queue >= 0
+ && lch_queue <
+ (DAVINCI_EDMA_NUM_DMACH + DAVINCI_EDMA_NUM_QDMACH))) {
+ /* reset TCCHEN */
+ ptr_edmacc_regs->paramentry[lch_head].opt &= ~TCCHEN;
+ }
+}
+
+/******************************************************************************
+ *
+ * It cleans ParamEntry qand bring back EDMA to initial state if media has
+ * been removed before EDMA has finished.It is usedful for removable media.
+ * Arguments:
+ * ch_no - channel no
+ *
+ * Return: zero on success, or corresponding error no on failure
+ *
+ *****************************************************************************/
+
+void davinci_clean_channel(int ch_no)
+{
+ int i;
+ dev_dbg(&edma_dev.dev, "EMR =%d\r\n", ptr_edmacc_regs->emr);
+ if (ch_no < 32) {
+ for (i = 0; i < 32; i++) {
+ if (ch_no == i) {
+ ptr_edmacc_regs->shadow[0].ecr |= (1 << i);
+ /* Clear the corresponding EMR bits */
+ ptr_edmacc_regs->emcr |= (1 << i);
+ /* Clear any SER */
+ ptr_edmacc_regs->shadow[0].secr |= (1 << i);
+ ptr_edmacc_regs->ccerrclr |= ((1 << 16) | 0x3);
+ }
+ }
+ }
+
+ if (ch_no > 32) {
+ dev_dbg(&edma_dev.dev, "EMRH =%d\r\n", ptr_edmacc_regs->emrh);
+ for (i = 0; i < 32; i++) {
+ if (ch_no == (i + 32)) {
+ ptr_edmacc_regs->shadow[0].ecrh |= (1 << i);
+ /* Clear the corresponding IPR bits */
+ ptr_edmacc_regs->emcrh |= (1 << i);
+ /* Clear any SER */
+ ptr_edmacc_regs->shadow[0].secrh |= (1 << i);
+ ptr_edmacc_regs->ccerrclr |= ((1 << 16) | 0x3);
+ }
+ }
+ }
+}
+
+/******************************************************************************
+ *
+ * DMA interrupt handlers
+ *
+ *****************************************************************************/
+static int dma_irq_handler_l(int sound_curr_lch, void *ch_status)
+{
+ dev_dbg(&edma_dev.dev, "dma_irq_handler\n");
+ (*cb[0]) ();
+ return IRQ_HANDLED;
+}
+
+static int dma_ccerr_handler_l(int sound_curr_lch, void *ch_status)
+{
+ dev_dbg(&edma_dev.dev, "dma_ccerr_handler\n");
+ (*cb[1]) ();
+ return IRQ_HANDLED;
+}
+
+static int dma_tc1err_handler_l (int sound_curr_lch, void *ch_status)
+{
+ dev_dbg(&edma_dev.dev, "dma_tc1err_handler\n");
+ (*cb[2]) ();
+ return IRQ_HANDLED;
+}
+
+static int dma_tc2err_handler_l(int sound_curr_lch, void *ch_status)
+{
+ dev_dbg(&edma_dev.dev, "dma_tc2err_handler\n");
+ (*cb[3]) ();
+ return IRQ_HANDLED;
+}
+
+int register_dma_interrupts(intr_callback cb1, intr_callback cb2,
+ intr_callback cb3, intr_callback cb4)
+{
+ cb[0] = cb1;
+ cb[1] = cb2;
+ cb[2] = cb3;
+ cb[3] = cb4;
+ if (!cb1 || !cb2 || !cb3 || !cb4) {
+ dev_dbg(&edma_dev.dev, "NULL callback\n");
+ return -1;
+ }
+
+ if (request_irq(IRQ_CCINT0, dma_irq_handler_l, 0, "EDMA", NULL)) {
+ dev_dbg(&edma_dev.dev, "request_irq failed\n");
+ return -1;
+ }
+ if (request_irq
+ (IRQ_CCERRINT, dma_ccerr_handler_l, 0, "EDMA CC Err", NULL)) {
+ dev_dbg(&edma_dev.dev, "request_irq failed\n");
+ return -1;
+ }
+ if (request_irq
+ (IRQ_TCERRINT0, dma_tc1err_handler_l, 0, "EDMA TC1 Err", NULL)) {
+ dev_dbg(&edma_dev.dev, "request_irq failed\n");
+ return -1;
+ }
+ if (request_irq
+ (IRQ_TCERRINT, dma_tc2err_handler_l, 0, "EDMA TC2 Err", NULL)) {
+ dev_dbg(&edma_dev.dev, "request_irq failed\n");
+ return -1;
+ }
+ return 0;
+}
+
+arch_initcall(arch_dma_init);
+EXPORT_SYMBOL(davinci_start_dma);
+EXPORT_SYMBOL(davinci_dma_link_lch);
+EXPORT_SYMBOL(davinci_set_dma_params);
+EXPORT_SYMBOL(davinci_get_dma_params);
+EXPORT_SYMBOL(davinci_set_dma_transfer_params);
+EXPORT_SYMBOL(davinci_set_dma_dest_index);
+EXPORT_SYMBOL(davinci_set_dma_src_index);
+EXPORT_SYMBOL(davinci_set_dma_dest_params);
+EXPORT_SYMBOL(davinci_set_dma_src_params);
+EXPORT_SYMBOL(davinci_request_dma);
+EXPORT_SYMBOL(davinci_stop_dma);
+EXPORT_SYMBOL(davinci_clean_channel);
+EXPORT_SYMBOL(davinci_free_dma);
+EXPORT_SYMBOL(davinci_dma_chain_lch);
+EXPORT_SYMBOL(davinci_dma_unchain_lch);
+EXPORT_SYMBOL(davinci_dma_unlink_lch);
diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c
index 9c67886..cb7b607 100644
--- a/arch/arm/mach-davinci/gpio.c
+++ b/arch/arm/mach-davinci/gpio.c
@@ -77,7 +77,7 @@
*/
int __gpio_get(unsigned gpio)
{
- struct gpio_controller *__iomem g = gpio2controller(gpio);
+ struct gpio_controller *__iomem g = gpio2controller(gpio);
return !!(__gpio_mask(gpio) & __raw_readl(&g->in_data));
}
@@ -93,9 +93,9 @@
int gpio_direction_input(unsigned gpio)
{
- struct gpio_controller *__iomem g = gpio2controller(gpio);
- u32 temp;
- u32 mask;
+ struct gpio_controller *__iomem g = gpio2controller(gpio);
+ u32 temp;
+ u32 mask;
if (!g)
return -EINVAL;
diff --git a/arch/arm/mach-davinci/i2c-client.c b/arch/arm/mach-davinci/i2c-client.c
new file mode 100644
index 0000000..c506ef6
--- /dev/null
+++ b/arch/arm/mach-davinci/i2c-client.c
@@ -0,0 +1,166 @@
+/*
+ * linux/drivers/davinci/i2c-davinci-client.c
+ *
+ * Copyright (C) 2006 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#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/delay.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+
+#include <asm/semaphore.h>
+#include <asm/arch/i2c-client.h>
+
+static DEFINE_MUTEX(expander_lock);
+static struct i2c_client *client_handle;
+
+/* This function is used for internal initialization */
+int davinci_i2c_read(u8 size, u8 * val, u16 client_addr)
+{
+ int err;
+ struct i2c_client *client = client_handle;
+
+ struct i2c_msg msg[1];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg->addr = client_addr;
+ msg->flags = I2C_M_RD;
+ msg->len = size;
+ msg->buf = val;
+
+ err = i2c_transfer(client->adapter, msg, 1);
+
+ if (err >= 0) {
+ return 0;
+ }
+
+ return err;
+}
+
+EXPORT_SYMBOL(davinci_i2c_read);
+
+/* This function is used for internal initialization */
+int davinci_i2c_write(u8 size, u8 * val, u16 client_addr)
+{
+ int err;
+ struct i2c_client *client = client_handle;
+
+ struct i2c_msg msg[1];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg->addr = client_addr;
+ msg->flags = 0;
+ msg->len = size;
+ msg->buf = val;
+
+ err = i2c_transfer(client->adapter, msg, 1);
+ if (err >= 0)
+ return 0;
+
+ return err;
+}
+
+EXPORT_SYMBOL(davinci_i2c_write);
+
+static struct i2c_driver davinci_i2c_client_driver;
+
+static int davinci_i2c_attach_client(struct i2c_adapter *adap, int addr)
+{
+ struct i2c_client *client;
+ int err;
+ u8 data_to_u35 = 0xf6;
+
+ if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ client_handle = client;
+
+ if (client->adapter)
+ return -EBUSY; /* our client is already attached */
+
+ client->addr = addr;
+ client->flags = 0;
+ client->driver = &davinci_i2c_client_driver;
+ client->adapter = adap;
+ strlcpy(client->name, client->driver->driver.name, I2C_NAME_SIZE);
+
+ err = i2c_attach_client(client);
+ if (err) {
+ client->adapter = NULL;
+ goto exit_kfree;
+ }
+
+ err = davinci_i2c_write(1, &data_to_u35, 0x3A);
+
+ return 0;
+
+ exit_kfree:
+ kfree(client);
+ exit:
+ return err;
+}
+
+static int davinci_i2c_detach_client(struct i2c_client *client)
+{
+ int err;
+
+ if (!client->adapter)
+ return -ENODEV; /* our client isn't attached */
+
+ err = i2c_detach_client(client);
+ client->adapter = NULL;
+ return err;
+}
+
+static int davinci_i2c_probe_adapter(struct i2c_adapter *adap)
+{
+ return davinci_i2c_attach_client(adap, 0x3A);
+}
+
+/* This is the driver that will be inserted */
+static struct i2c_driver davinci_i2c_client_driver = {
+ .driver = {
+ /* there are 3 expanders, one is leds-only ... */
+ .name = "davinci_evm_expander1",
+ },
+ .attach_adapter = davinci_i2c_probe_adapter,
+ .detach_client = davinci_i2c_detach_client,
+};
+
+static int __init davinci_i2c_client_init(void)
+{
+ return i2c_add_driver(&davinci_i2c_client_driver);
+}
+
+static void __exit davinci_i2c_client_exit(void)
+{
+ i2c_del_driver(&davinci_i2c_client_driver);
+}
+
+module_init(davinci_i2c_client_init);
+module_exit(davinci_i2c_client_exit);
diff --git a/arch/arm/mach-davinci/i2c-emac.c b/arch/arm/mach-davinci/i2c-emac.c
new file mode 100644
index 0000000..5753e0f
--- /dev/null
+++ b/arch/arm/mach-davinci/i2c-emac.c
@@ -0,0 +1,104 @@
+/*
+ * <arch/arm/mach-davinci/i2c-emac.c
+ *
+ * Read MAC address from i2c-attached EEPROM
+ * FIXME: Move into network driver once stabilized
+ *
+ * Author: Texas Instruments
+ *
+ * 2006 (c) Texas Instruments, 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/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <asm/arch/i2c-client.h>
+
+/* Get Ethernet address from kernel boot params */
+static unsigned char cpmac_eth_string[20] = "deadbeaf";
+
+/* This function gets the Ethernet MAC address from EEPROM
+ * Input buffer to be of atlease 20 bytes in length
+ */
+int davinci_get_macaddr (char *ptr)
+{
+#ifndef CONFIG_I2C_DAVINCI
+ printk(KERN_INFO "DaVinci EMAC: Unable to read MAC from EEPROM, "
+ "no i2c support in kernel.\n");
+#else
+ char data[2] = { 0x7f, 0 };
+ char temp[20];
+ int i = 0;
+
+ if (ptr == NULL) {
+ return -EFAULT;
+ }
+
+ davinci_i2c_write (2, data, 0x50);
+ davinci_i2c_read (8, temp, 0x50);
+
+ /* check whether MAC address is available in ERPROM else try to
+ * to get it from bootparams for now. From Delta EVM MAC address
+ * should be available from I2C EEPROM.
+ */
+ if ((temp [0] != 0xFF) |
+ (temp [1] != 0xFF) |
+ (temp [2] != 0xFF) |
+ (temp [3] != 0xFF) |
+ (temp [4] != 0xFF) |
+ (temp [5] != 0xFF) |
+ (temp [6] != 0xFF) )
+ {
+ ptr[0] = (*(temp+0) & 0xF0) >> 4;
+ ptr[1] = (*(temp+0) & 0x0F);
+ ptr[2] = ':';
+ ptr[3] = (*(temp+1) & 0xF0) >> 4;
+ ptr[4] = (*(temp+1) & 0x0F);
+ ptr[5] = ':';
+ ptr[6] = (*(temp+2) & 0xF0) >> 4;
+ ptr[7] = (*(temp+2) & 0x0F);
+ ptr[8] = ':';
+ ptr[9] = (*(temp+3) & 0xF0) >> 4;
+ ptr[10]= (*(temp+3) & 0x0F);
+ ptr[11]= ':';
+ ptr[12]= (*(temp+4) & 0xF0) >> 4;
+ ptr[13]= (*(temp+4) & 0x0F);
+ ptr[14]= ':';
+ ptr[15]= (*(temp+5) & 0xF0) >> 4;
+ ptr[16]= (*(temp+5) & 0x0F);
+
+ for (i = 0; i < 17; i++)
+ {
+ if (ptr[i] == ':')
+ continue;
+ else if (ptr[i] <= 9)
+ ptr[i] = ptr[i] + 48;
+ else
+ ptr[i] = ptr[i] + 87;
+ }
+ } else
+#endif
+ {
+ strcpy (ptr, cpmac_eth_string);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(davinci_get_macaddr);
+
+static int davinci_cpmac_eth_setup(char *str)
+{
+ /* The first char passed from the bootloader is '=', so ignore it */
+ strcpy(&cpmac_eth_string[0], &str[1]);
+
+ printk("TI DaVinci EMAC: Kernel Boot params Eth address: %s\n",
+ cpmac_eth_string);
+
+ return (1);
+}
+__setup("eth", davinci_cpmac_eth_setup);
+
diff --git a/arch/arm/mach-davinci/irq.c b/arch/arm/mach-davinci/irq.c
index 1333d84..51371f1 100644
--- a/arch/arm/mach-davinci/irq.c
+++ b/arch/arm/mach-davinci/irq.c
@@ -218,9 +218,9 @@
for (i = 0; i < DAVINCI_N_AINTC_IRQ; i++) {
set_irq_chip(i, &davinci_irq_chip_0);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
- if (i != IRQ_TINT1_TINT34)
- set_irq_handler(i, handle_edge_irq);
- else
- set_irq_handler(i, handle_level_irq);
+ if (i != IRQ_TINT1_TINT34)
+ set_irq_handler(i, handle_edge_irq);
+ else
+ set_irq_handler(i, handle_level_irq);
}
}
diff --git a/arch/arm/mach-davinci/leds-evm.c b/arch/arm/mach-davinci/leds-evm.c
new file mode 100644
index 0000000..15245ec
--- /dev/null
+++ b/arch/arm/mach-davinci/leds-evm.c
@@ -0,0 +1,200 @@
+/*
+ * <arch/arm/mach-davinci/leds-evm.c>
+ *
+ * LED support for TI DaVinci EVM
+ *
+ * 2006 (c) Texas Instruments, 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/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/errno.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+
+/* eight leds on a pcf8574a I2C gpio expander; 0 == ON, 1 == OFF
+ * - drivers can use leds_event(led_{green,amber,red,blue}_{on,off})
+ * - userspace can do the same with /sys/devices/leds/leds0/event
+ */
+#define LED_DS8 (1 << 0)
+#define LED_DS7 (1 << 1)
+#define LED_DS6 (1 << 2)
+#define LED_DS5 (1 << 3)
+#define LED_DS4 (1 << 4)
+#define LED_DS3 (1 << 5)
+#define LED_DS2 (1 << 6)
+#define LED_DS1 (1 << 7)
+
+#define LED_STATE_ENABLED (1 << 8)
+#define LED_STATE_CLAIMED (1 << 9)
+
+static u16 hw_led_state;
+static u8 leds_change;
+
+
+/* these leds use I2C not GPIO, so we can't change values
+ * and remain "idle" ... so there's no "idle" LED.
+ */
+#define TIMER_LED LED_DS8
+
+#define GREEN_LED LED_DS1
+#define AMBER_LED LED_DS2
+#define RED_LED LED_DS3
+#define BLUE_LED LED_DS4
+
+#define APP_LEDS (GREEN_LED | AMBER_LED | RED_LED | BLUE_LED)
+
+static DEFINE_SPINLOCK(lock);
+
+
+#define EVM_I2C_ADDR 0x38
+
+static void pcf_work(struct work_struct *unused)
+{
+ struct i2c_adapter *adap;
+ int err;
+ struct i2c_msg msg;
+
+ adap = i2c_get_adapter(0);
+ if (!adap)
+ return;
+
+ for (;;) {
+ static u8 leds;
+
+ spin_lock_irq(&lock);
+ leds = (u8) hw_led_state;
+ err= leds_change;
+ leds_change = 0;
+ spin_unlock_irq(&lock);
+
+ if (!err)
+ break;
+
+ msg.addr = EVM_I2C_ADDR;
+ msg.flags = 0;
+ msg.len = 1;
+ msg.buf = &leds;
+ err = i2c_transfer(adap, &msg, 1);
+ if (err < 0)
+ pr_debug("LED: set to %02x, err %d\n", leds, err);
+ }
+
+}
+
+static DECLARE_WORK(work, pcf_work);
+
+static void evm_leds_event(led_event_t evt)
+{
+ unsigned long flags;
+ u16 leds;
+
+ spin_lock_irqsave(&lock, flags);
+
+ if (!(hw_led_state & LED_STATE_ENABLED) && evt != led_start)
+ goto done;
+
+ leds = hw_led_state;
+ switch (evt) {
+ case led_start:
+ hw_led_state = LED_STATE_ENABLED | 0xff;
+ leds = 0;
+ break;
+
+ case led_halted:
+ case led_stop:
+ hw_led_state = 0xff;
+ // NOTE: work may still be pending!!
+ break;
+
+ case led_claim:
+ hw_led_state |= LED_STATE_CLAIMED;
+ hw_led_state |= APP_LEDS;
+ break;
+
+ case led_release:
+ hw_led_state &= ~LED_STATE_CLAIMED;
+ hw_led_state |= APP_LEDS;
+ break;
+
+#ifdef CONFIG_LEDS_TIMER
+ case led_timer:
+ hw_led_state ^= TIMER_LED;
+ break;
+#endif
+
+ /* actually all the LEDs are green */
+
+ case led_green_on:
+ if (leds & LED_STATE_CLAIMED)
+ hw_led_state &= ~GREEN_LED;
+ break;
+ case led_green_off:
+ if (leds & LED_STATE_CLAIMED)
+ hw_led_state |= GREEN_LED;
+ break;
+
+ case led_amber_on:
+ if (leds & LED_STATE_CLAIMED)
+ hw_led_state &= ~AMBER_LED;
+ break;
+ case led_amber_off:
+ if (leds & LED_STATE_CLAIMED)
+ hw_led_state |= AMBER_LED;
+ break;
+
+ case led_red_on:
+ if (leds & LED_STATE_CLAIMED)
+ hw_led_state &= ~RED_LED;
+ break;
+ case led_red_off:
+ if (leds & LED_STATE_CLAIMED)
+ hw_led_state |= RED_LED;
+ break;
+
+ case led_blue_on:
+ if (leds & LED_STATE_CLAIMED)
+ hw_led_state &= ~BLUE_LED;
+ break;
+ case led_blue_off:
+ if (leds & LED_STATE_CLAIMED)
+ hw_led_state |= BLUE_LED;
+ break;
+
+ default:
+ break;
+ }
+
+ leds ^= hw_led_state;
+ if (leds & 0xff) {
+ leds_change = (u8) leds;
+ schedule_work(&work);
+ }
+
+done:
+ spin_unlock_irqrestore(&lock, flags);
+}
+
+static int __init evm_leds_init(void)
+{
+ if (!machine_is_davinci_evm())
+ return 0;
+
+ leds_event = evm_leds_event;
+ leds_event(led_start);
+ return 0;
+}
+
+/* i2c is subsys_initcall, davinci i2c is device_initcall;
+ * this needs to follow both of them (sigh)
+ */
+late_initcall(evm_leds_init);
diff --git a/arch/arm/mach-davinci/mcbsp.c b/arch/arm/mach-davinci/mcbsp.c
new file mode 100644
index 0000000..95531e3
--- /dev/null
+++ b/arch/arm/mach-davinci/mcbsp.c
@@ -0,0 +1,519 @@
+/*
+ * arch/arm/mach-davinci/mcbsp.c
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Samuel Ortiz <samuel.ortiz@nokia.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.
+ *
+ * Multichannel mode not supported.
+ *
+ * 2005-10-01 Rishi Bhattacharya / Sharath Kumar - Modified to support TI
+ * Davinci DM644x processor
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/memory.h>
+#include <asm/arch/edma.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/mcbsp.h>
+
+struct clk *mbspclk = NULL;
+
+/* #define CONFIG_MCBSP_DEBUG */
+
+#ifdef CONFIG_MCBSP_DEBUG
+#define DBG(x...) printk(KERN_INFO x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
+struct davinci_mcbsp {
+ u32 io_base;
+ u8 id;
+ u8 free;
+ davinci_mcbsp_word_length rx_word_length;
+ davinci_mcbsp_word_length tx_word_length;
+
+ /* IRQ based TX/RX */
+ int rx_irq;
+ int tx_irq;
+
+ /* DMA stuff */
+ u8 dma_rx_sync;
+ short dma_rx_lch;
+ u8 dma_tx_sync;
+ short dma_tx_lch;
+
+ /* Completion queues */
+ struct completion tx_irq_completion;
+ struct completion rx_irq_completion;
+ struct completion tx_dma_completion;
+ struct completion rx_dma_completion;
+
+ spinlock_t lock;
+};
+
+static struct davinci_mcbsp mcbsp[DAVINCI_MAX_MCBSP_COUNT];
+
+unsigned short DAVINCI_MCBSP_READ(int base, int reg)
+{
+ unsigned long data, temp, *p = (unsigned long *)(base + reg);
+
+ temp = (unsigned long)p;
+
+ if (temp & 0x2) {
+ /*non word offset */
+ temp &= 0xfffffffc;
+ p = (unsigned long *)temp;
+ data = inl(p);
+ return (unsigned short)(data >> 16);
+ } else {
+ /*word offset */
+ return ((unsigned short)inl(p));
+ }
+}
+
+void DAVINCI_MCBSP_WRITE(int base, int reg, unsigned short val)
+{
+ unsigned long data, temp, *p = (unsigned long *)(base + reg);
+
+ temp = (unsigned long)p;
+
+ if (temp & 0x2) {
+ /*non word offset */
+ temp &= 0xfffffffc;
+ p = (unsigned long *)temp;
+ data = inl(p);
+ data &= 0x0000ffff;
+ data |= ((unsigned long)val << 16);
+ outl(data, p);
+ } else {
+ /*word offset */
+ data = inl(p);
+ data &= 0xffff0000;
+ data |= val;
+ outl(data, p);
+ }
+}
+
+static void davinci_mcbsp_dump_reg(u8 id)
+{
+ DBG("**** MCBSP%d regs ****\n", mcbsp[id].id);
+
+ DBG("SPCR2: 0x%04x\n", DAVINCI_MCBSP_READ(mcbsp[id].io_base, SPCR2));
+ DBG("SPCR1: 0x%04x\n", DAVINCI_MCBSP_READ(mcbsp[id].io_base, SPCR1));
+ DBG("RCR2: 0x%04x\n", DAVINCI_MCBSP_READ(mcbsp[id].io_base, RCR2));
+ DBG("RCR1: 0x%04x\n", DAVINCI_MCBSP_READ(mcbsp[id].io_base, RCR1));
+ DBG("XCR2: 0x%04x\n", DAVINCI_MCBSP_READ(mcbsp[id].io_base, XCR2));
+ DBG("XCR1: 0x%04x\n", DAVINCI_MCBSP_READ(mcbsp[id].io_base, XCR1));
+ DBG("SRGR2: 0x%04x\n", DAVINCI_MCBSP_READ(mcbsp[id].io_base, SRGR2));
+ DBG("SRGR1: 0x%04x\n", DAVINCI_MCBSP_READ(mcbsp[id].io_base, SRGR1));
+ DBG("PCR0: 0x%04x\n", DAVINCI_MCBSP_READ(mcbsp[id].io_base, PCR0));
+ DBG("***********************\n");
+}
+
+static void davinci_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+ struct davinci_mcbsp *mcbsp_dma_tx = (struct davinci_mcbsp *)(data);
+
+ DBG("TX DMA callback : 0x%x\n",
+ DAVINCI_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2));
+
+ /* We can free the channels */
+ DBG("mcbsp_dma_tx->dma_tx_lch = %d\n",
+ mcbsp_dma_tx->dma_tx_lch);
+ davinci_stop_dma(mcbsp_dma_tx->dma_tx_lch);
+ davinci_free_dma(mcbsp_dma_tx->dma_tx_lch);
+ mcbsp_dma_tx->dma_tx_lch = -1;
+ complete(&mcbsp_dma_tx->tx_dma_completion);
+}
+
+static void davinci_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+ struct davinci_mcbsp *mcbsp_dma_rx = (struct davinci_mcbsp *)(data);
+
+ DBG("RX DMA callback : 0x%x\n",
+ DAVINCI_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2));
+
+ /* We can free the channels */
+ davinci_free_dma(mcbsp_dma_rx->dma_rx_lch);
+ mcbsp_dma_rx->dma_rx_lch = -1;
+
+ complete(&mcbsp_dma_rx->rx_dma_completion);
+}
+
+/*
+ * davinci_mcbsp_config simply write a config to the
+ * appropriate McBSP.
+ * You either call this function or set the McBSP registers
+ * by yourself before calling davinci_mcbsp_start().
+ */
+
+void davinci_mcbsp_config(unsigned int id,
+ const struct davinci_mcbsp_reg_cfg *config)
+{
+ u32 io_base = mcbsp[id].io_base;
+
+ DBG("davinci-McBSP: McBSP%d io_base: 0x%8x\n", id + 1, io_base);
+
+ DAVINCI_MCBSP_WRITE(io_base, PCR0, config->pcr0);
+
+ DAVINCI_MCBSP_WRITE(io_base, RCR2, config->rcr2);
+ DAVINCI_MCBSP_WRITE(io_base, RCR1, config->rcr1);
+
+ DAVINCI_MCBSP_WRITE(io_base, XCR2, config->xcr2);
+ DAVINCI_MCBSP_WRITE(io_base, XCR1, config->xcr1);
+
+ DAVINCI_MCBSP_WRITE(io_base, SRGR2, config->srgr2);
+ DAVINCI_MCBSP_WRITE(io_base, SRGR1, config->srgr1);
+
+ /* We write the given config */
+ DAVINCI_MCBSP_WRITE(io_base, SPCR2, config->spcr2);
+ DAVINCI_MCBSP_WRITE(io_base, SPCR1, config->spcr1);
+}
+
+static int davinci_mcbsp_check(unsigned int id)
+{
+ if (id > DAVINCI_MAX_MCBSP_COUNT - 1) {
+ DBG("DAVINCI-McBSP: McBSP%d doesn't exist\n", id + 1);
+ return -1;
+ }
+ return 0;
+}
+
+int davinci_mcbsp_request(unsigned int id)
+{
+ if (davinci_mcbsp_check(id) < 0)
+ return -EINVAL;
+
+ spin_lock(&mcbsp[id].lock);
+ if (!mcbsp[id].free) {
+ DBG("DAVINCI-McBSP: McBSP%d is currently in use\n", id + 1);
+ spin_unlock(&mcbsp[id].lock);
+ return -1;
+ }
+
+ mcbsp[id].free = 0;
+ spin_unlock(&mcbsp[id].lock);
+
+ return 0;
+}
+
+void davinci_mcbsp_free(unsigned int id)
+{
+ if (davinci_mcbsp_check(id) < 0)
+ return;
+
+ spin_lock(&mcbsp[id].lock);
+ if (mcbsp[id].free) {
+ DBG("DAVINCI-McBSP: McBSP%d was not reserved\n", id + 1);
+ spin_unlock(&mcbsp[id].lock);
+ return;
+ }
+
+ mcbsp[id].free = 1;
+ spin_unlock(&mcbsp[id].lock);
+
+ return;
+}
+
+/*
+ * Here we start the McBSP, by enabling the sample
+ * generator, both transmitter and receivers,
+ * and the frame sync.
+ */
+void davinci_mcbsp_start(unsigned int id)
+{
+ u32 io_base;
+ u16 w;
+
+ if (davinci_mcbsp_check(id) < 0)
+ return;
+
+ io_base = mcbsp[id].io_base;
+
+ mcbsp[id].rx_word_length =
+ ((DAVINCI_MCBSP_READ(io_base, RCR1) >> 5) & 0x7);
+ mcbsp[id].tx_word_length =
+ ((DAVINCI_MCBSP_READ(io_base, XCR1) >> 5) & 0x7);
+
+ /* Start the sample generator */
+ w = DAVINCI_MCBSP_READ(io_base, SPCR2);
+ DAVINCI_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
+
+ /* Enable transmitter and receiver */
+ w = DAVINCI_MCBSP_READ(io_base, SPCR2);
+ DAVINCI_MCBSP_WRITE(io_base, SPCR2, w | 1);
+
+ w = DAVINCI_MCBSP_READ(io_base, SPCR1);
+ DAVINCI_MCBSP_WRITE(io_base, SPCR1, w | 1);
+
+ udelay(100);
+
+ /* Start frame sync */
+ w = DAVINCI_MCBSP_READ(io_base, SPCR2);
+ DAVINCI_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
+
+ /* Dump mcbsp reg */
+ davinci_mcbsp_dump_reg(id);
+}
+
+void davinci_mcbsp_stop(unsigned int id)
+{
+ u32 io_base;
+ u16 w;
+
+ if (davinci_mcbsp_check(id) < 0)
+ return;
+
+ io_base = mcbsp[id].io_base;
+
+ /* Reset transmitter */
+ w = DAVINCI_MCBSP_READ(io_base, SPCR2);
+ DAVINCI_MCBSP_WRITE(io_base, SPCR2, w & ~(1));
+
+ /* Reset receiver */
+ w = DAVINCI_MCBSP_READ(io_base, SPCR1);
+ DAVINCI_MCBSP_WRITE(io_base, SPCR1, w & ~(1));
+
+ /* Reset the sample rate generator */
+ w = DAVINCI_MCBSP_READ(io_base, SPCR2);
+ DAVINCI_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
+
+ /* Reset the frame sync generator */
+ w = DAVINCI_MCBSP_READ(io_base, SPCR2);
+ DAVINCI_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 7));
+}
+
+/*
+ * IRQ based word transmission.
+ */
+void davinci_mcbsp_xmit_word(unsigned int id, u32 word)
+{
+
+ u32 io_base;
+ davinci_mcbsp_word_length word_length = mcbsp[id].tx_word_length;
+
+ if (davinci_mcbsp_check(id) < 0)
+ return;
+
+ io_base = mcbsp[id].io_base;
+
+ if (word_length > DAVINCI_MCBSP_WORD_16)
+ DAVINCI_MCBSP_WRITE(io_base, DXR2, word >> 16);
+ DAVINCI_MCBSP_WRITE(io_base, DXR1, word & 0xffff);
+}
+
+u32 davinci_mcbsp_recv_word(unsigned int id)
+{
+
+ u32 io_base;
+ u16 word_lsb, word_msb = 0;
+
+ davinci_mcbsp_word_length word_length = mcbsp[id].rx_word_length;
+
+ if (davinci_mcbsp_check(id) < 0)
+ return -EINVAL;
+
+ io_base = mcbsp[id].io_base;
+
+ if (word_length > DAVINCI_MCBSP_WORD_16)
+ word_msb = DAVINCI_MCBSP_READ(io_base, DRR2);
+ word_lsb = DAVINCI_MCBSP_READ(io_base, DRR1);
+
+ return (word_lsb | (word_msb << 16));
+}
+
+/*
+ * Simple DMA based buffer rx/tx routines.
+ * Nothing fancy, just a single buffer tx/rx through DMA.
+ * The DMA resources are released once the transfer is done.
+ * For anything fancier, you should use your own customized DMA
+ * routines and callbacks.
+ */
+int davinci_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer,
+ unsigned int length)
+{
+ int dma_tx_ch;
+ int tcc;
+
+ if (davinci_mcbsp_check(id) < 0)
+ return -EINVAL;
+
+ if (davinci_request_dma
+ (mcbsp[id].dma_tx_sync, "McBSP TX", davinci_mcbsp_tx_dma_callback,
+ &mcbsp[id], &dma_tx_ch, &tcc, EVENTQ_0)) {
+ DBG("DAVINCI-McBSP: Unable to request DMA channel for McBSP%d TX."
+ "Trying IRQ based TX\n", id + 1);
+ return -EAGAIN;
+ }
+
+ mcbsp[id].dma_tx_lch = dma_tx_ch;
+
+ DBG("TX DMA on channel %d\n", dma_tx_ch);
+
+ init_completion(&(mcbsp[id].tx_dma_completion));
+
+ davinci_set_dma_transfer_params(mcbsp[id].dma_tx_lch, 2, length / 2, 1,
+ 0, ASYNC);
+
+ davinci_set_dma_dest_params(mcbsp[id].dma_tx_lch,
+ (unsigned long)0x01E02004, 0, 0);
+
+ davinci_set_dma_src_params(mcbsp[id].dma_tx_lch, (buffer), 0, 0);
+ davinci_set_dma_src_index(mcbsp[id].dma_tx_lch, 2, 0);
+ davinci_set_dma_dest_index(mcbsp[id].dma_tx_lch, 0, 0);
+
+ davinci_start_dma(mcbsp[id].dma_tx_lch);
+ wait_for_completion(&(mcbsp[id].tx_dma_completion));
+ return 0;
+}
+
+int davinci_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer,
+ unsigned int length)
+{
+ int dma_rx_ch;
+ int tcc;
+
+ if (davinci_mcbsp_check(id) < 0)
+ return -EINVAL;
+
+ if (davinci_request_dma
+ (mcbsp[id].dma_rx_sync, "McBSP RX", davinci_mcbsp_rx_dma_callback,
+ &mcbsp[id], &dma_rx_ch, &tcc, EVENTQ_0)) {
+ DBG("Unable to request DMA channel for McBSP%d RX."
+ "Trying IRQ based RX\n", id + 1);
+ return -EAGAIN;
+ }
+ mcbsp[id].dma_rx_lch = dma_rx_ch;
+
+ DBG("RX DMA on channel %d\n", dma_rx_ch);
+
+ init_completion(&(mcbsp[id].rx_dma_completion));
+
+ davinci_set_dma_transfer_params(mcbsp[id].dma_rx_lch, 2, length / 2, 1,
+ 0, ASYNC);
+
+ davinci_set_dma_src_params(mcbsp[id].dma_rx_lch,
+ (unsigned long)0x01E02000, 0, 0);
+
+ davinci_set_dma_dest_params(mcbsp[id].dma_rx_lch,
+ (unsigned long)virt_to_phys((void *)buffer),
+ 0, 0);
+ davinci_set_dma_src_index(mcbsp[id].dma_rx_lch, 0, 0);
+ davinci_set_dma_dest_index(mcbsp[id].dma_rx_lch, 2, 0);
+
+ davinci_start_dma(mcbsp[id].dma_rx_lch);
+
+ wait_for_completion(&(mcbsp[id].rx_dma_completion));
+ return 0;
+}
+
+struct clk * davinci_mcbsp_get_clock(void)
+{
+ return mbspclk;
+}
+
+struct davinci_mcbsp_info {
+ u32 virt_base;
+ u8 dma_rx_sync, dma_tx_sync;
+ u16 rx_irq, tx_irq;
+};
+
+static const struct davinci_mcbsp_info mcbsp_davinci[] = {
+ [0] = { .virt_base = IO_ADDRESS(DAVINCI_MCBSP1_BASE),
+ .dma_rx_sync = DAVINCI_DMA_MCBSP1_RX,
+ .dma_tx_sync = DAVINCI_DMA_MCBSP1_TX,
+ .rx_irq = DAVINCI_McBSP1RX,
+ .tx_irq = DAVINCI_McBSP1TX},
+};
+
+static int __init davinci_mcbsp_init(void)
+{
+ int mcbsp_count = 0, i;
+ static const struct davinci_mcbsp_info *mcbsp_info;
+ struct clk *clkp;
+
+ printk(KERN_INFO "Initializing DaVinci McBSP system\n");
+
+ clkp = clk_get (NULL, "McBSPCLK");
+ if (IS_ERR(clkp)) {
+ printk(KERN_ERR "mcbsp: could not acquire McBSP clk\n");
+ return PTR_ERR(clkp);
+ }
+ else {
+ mbspclk = clkp;
+ clk_enable(mbspclk);
+
+ mcbsp_info = mcbsp_davinci;
+ mcbsp_count = ARRAY_SIZE(mcbsp_davinci);
+
+ for (i = 0; i < DAVINCI_MAX_MCBSP_COUNT; i++) {
+ if (i >= mcbsp_count) {
+ mcbsp[i].io_base = 0;
+ mcbsp[i].free = 0;
+ continue;
+ }
+ mcbsp[i].id = i + 1;
+ mcbsp[i].free = 1;
+ mcbsp[i].dma_tx_lch = -1;
+ mcbsp[i].dma_rx_lch = -1;
+
+ mcbsp[i].io_base = mcbsp_info[i].virt_base;
+ mcbsp[i].tx_irq = mcbsp_info[i].tx_irq;
+ mcbsp[i].rx_irq = mcbsp_info[i].rx_irq;
+ mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync;
+ mcbsp[i].dma_tx_sync = mcbsp_info[i].dma_tx_sync;
+ spin_lock_init(&mcbsp[i].lock);
+ }
+ }
+ return 0;
+}
+
+static void __exit davinci_mcbsp_exit(void)
+{
+ int i;
+
+ for (i = 0; i < DAVINCI_MAX_MCBSP_COUNT; i++) {
+ mcbsp[i].free = 0;
+ mcbsp[i].dma_tx_lch = -1;
+ mcbsp[i].dma_rx_lch = -1;
+ }
+
+ clk_disable (mbspclk);
+
+ return;
+}
+
+module_init(davinci_mcbsp_init);
+module_exit(davinci_mcbsp_exit);
+
+EXPORT_SYMBOL(davinci_mcbsp_config);
+EXPORT_SYMBOL(davinci_mcbsp_request);
+EXPORT_SYMBOL(davinci_mcbsp_free);
+EXPORT_SYMBOL(davinci_mcbsp_start);
+EXPORT_SYMBOL(davinci_mcbsp_stop);
+EXPORT_SYMBOL(davinci_mcbsp_xmit_word);
+EXPORT_SYMBOL(davinci_mcbsp_recv_word);
+EXPORT_SYMBOL(davinci_mcbsp_xmit_buffer);
+EXPORT_SYMBOL(davinci_mcbsp_recv_buffer);
+EXPORT_SYMBOL(davinci_mcbsp_get_clock);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("McBSP driver for DaVinci.");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c
index 1334416..0b4d6e7 100644
--- a/arch/arm/mach-davinci/psc.c
+++ b/arch/arm/mach-davinci/psc.c
@@ -134,6 +134,7 @@
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TPTC0, 1);
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TPTC1, 1);
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_GPIO, 1);
+ davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_USB, 1);
/* Turn on WatchDog timer LPSC. Needed for RESET to work */
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TIMER2, 1);
diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c
index 8368c93..d0e7c52 100644
--- a/arch/arm/mach-davinci/serial.c
+++ b/arch/arm/mach-davinci/serial.c
@@ -42,7 +42,7 @@
return (unsigned int)__raw_readb(up->membase + offset);
}
-static inline void davinci_serial_outp(struct plat_serial8250_port *p,
+static inline void davinci_serial_outp(struct plat_serial8250_port *p,
int offset, int value)
{
offset <<= p->regshift;
@@ -71,7 +71,7 @@
.platform_data = serial_platform_data,
},
};
-
+
static void __init davinci_serial_reset(struct plat_serial8250_port *p)
{
/* reset both transmitter and receiver: bits 14,13 = UTRST, URRST */
@@ -89,6 +89,16 @@
static int __init davinci_init(void)
{
+ struct clk *uart_clk;
+ struct device *dev = &serial_device.dev;
+
+ uart_clk = clk_get(dev, "UART");
+ if (IS_ERR(uart_clk))
+ printk(KERN_ERR "%s:%d: failed to get UART clock\n",
+ __FUNCTION__, __LINE__);
+ else
+ clk_enable(uart_clk);
+
davinci_serial_reset(&serial_platform_data[0]);
return platform_device_register(&serial_device);
}
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index b391776..35f8296 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -833,6 +833,12 @@
will get access to the real time clock (or hardware clock) built
into your computer.
+config DAVINCI_RTC
+ bool "TI DaVinci Real Time Clock"
+ depends on ARCH_DAVINCI && MACH_DAVINCI_EVM && I2C_DAVINCI
+ help
+ Support for TI DaVinci RTC
+
config COBALT_LCD
bool "Support for Cobalt LCD"
depends on MIPS_COBALT
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index c78ff26..e08d6c5 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -105,6 +105,7 @@
obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
obj-$(CONFIG_TCG_TPM) += tpm/
+obj-$(CONFIG_DAVINCI_RTC) += davinci-rtc.o
obj-$(CONFIG_PS3_FLASH) += ps3flash.o
diff --git a/drivers/char/davinci-rtc.c b/drivers/char/davinci-rtc.c
new file mode 100644
index 0000000..f138363
--- /dev/null
+++ b/drivers/char/davinci-rtc.c
@@ -0,0 +1,252 @@
+/*
+ * linux/drivers/char/rtc.c
+ *
+ * Copyright (C) 2004 Texas Instruments Inc
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * ----------------------------------------------------------------------------
+ Modifications:
+ ver. 1.0: Jan 2006, Swaminathan S
+ -
+ */
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <asm/rtc.h>
+#include <asm/arch/i2c-client.h>
+
+static unsigned char am;
+
+static int _rtc_read_time(struct rtc_time *tm);
+static int _rtc_set_time(struct rtc_time *tm);
+static void am_or_pm (void);
+
+static struct rtc_ops davinci_rtc_ops = {
+ .owner = THIS_MODULE,
+ .read_time = _rtc_read_time,
+ .set_time = _rtc_set_time,
+};
+
+static unsigned long epoch = 1900; /* year corresponding to 0x00 */
+
+static const unsigned char days_in_mo[] =
+{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static int _rtc_read_time(struct rtc_time *tm)
+{
+ char rtcdata [9] = { 2, 1, 0, 0, 0, 0,
+ 0, 0, 0 };
+
+ davinci_i2c_write (2, rtcdata, 0x23);
+ udelay (1000);
+ davinci_i2c_read (9, rtcdata, 0x23);
+ udelay (1000);
+
+ tm->tm_year = BCD_TO_BIN (rtcdata[3]) * 100 + BCD_TO_BIN (rtcdata[2]) - 1900;
+ tm->tm_mon = BCD_TO_BIN (rtcdata[4]);
+ tm->tm_mday = BCD_TO_BIN (rtcdata[5]);
+ tm->tm_hour = BCD_TO_BIN (rtcdata[6]);
+ tm->tm_min = BCD_TO_BIN (rtcdata[7]);
+ tm->tm_sec = BCD_TO_BIN (rtcdata[8]);
+
+ return 0;
+}
+
+static int _rtc_set_time(struct rtc_time *tm)
+{
+ char rtcdata [9];
+ char ampmdata [9];
+ struct timespec tv;
+ unsigned char mon, day, hrs = 0, min, sec, leap_yr;
+ unsigned char yr_low, yr_high;
+ unsigned int yrs;
+
+ am_or_pm ();
+
+ yrs = tm->tm_year + 1900;
+ yr_high = yrs/100;
+ yr_low = (yrs) % 100;
+
+ mon = tm->tm_mon;
+ hrs = tm->tm_hour;
+ day = tm->tm_mday;
+ min = tm->tm_min;
+ sec = tm->tm_sec;
+
+ if (yrs < 1970 || yrs > 2037)
+ return -EINVAL;
+
+ leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
+
+ if ((mon > 11) || (day == 0))
+ return -EINVAL;
+
+ if (day > (days_in_mo[mon] + ((mon == 1) && leap_yr)))
+ return -EINVAL;
+
+ if ((hrs >= 24) || (min >= 60) || (sec >= 60))
+ return -EINVAL;
+
+ if ((yrs -= epoch) > 255) { /* They are unsigned */
+ return -EINVAL;
+ }
+
+ if (am == 1 && tm->tm_hour <= 12) {
+ hrs = tm->tm_hour;
+ if (tm->tm_hour == 0)
+ hrs = tm->tm_hour + 12;
+ }
+
+ else if ((am == 1 && tm->tm_hour > 12) ||
+ (am == 0 && tm->tm_hour < 12)) {
+ unsigned char mon1 = mon, day1 = day, hrs1 = 11, min1 = 59, sec1 = 59;
+ unsigned char yr_low1 = yr_low, yr_high1 = yr_high;
+
+ ampmdata [0] = 9;
+ ampmdata [1] = 0;
+ ampmdata [2] = BIN_TO_BCD(yr_low1);
+ ampmdata [3] = BIN_TO_BCD(yr_high1);
+ ampmdata [4] = BIN_TO_BCD(mon1);
+ ampmdata [5] = BIN_TO_BCD(day1);
+ ampmdata [6] = BIN_TO_BCD(hrs1);
+ ampmdata [7] = BIN_TO_BCD(min1);
+ ampmdata [8] = BIN_TO_BCD(sec1);
+ davinci_i2c_write (9, ampmdata, 0x23);
+ udelay (1000);
+ mdelay (1000);
+ am = (am == 1) ? 0 : 1;
+
+ if (!am)
+ hrs = tm->tm_hour - 12;
+ else if (tm->tm_hour == 0)
+ hrs = tm->tm_hour + 12;
+ }
+
+ else if (am == 0 && tm->tm_hour > 12) {
+ hrs = tm->tm_hour - 12;
+ }
+
+ rtcdata [0] = 9;
+ rtcdata [1] = 0;
+ rtcdata [2] = BIN_TO_BCD(yr_low);
+ rtcdata [3] = BIN_TO_BCD(yr_high);
+ rtcdata [4] = BIN_TO_BCD(mon);
+ rtcdata [5] = BIN_TO_BCD(day);
+ rtcdata [6] = BIN_TO_BCD(hrs);
+ rtcdata [7] = BIN_TO_BCD(min);
+ rtcdata [8] = BIN_TO_BCD(sec);
+ davinci_i2c_write (9, rtcdata, 0x23);
+ udelay (1000);
+
+ tv.tv_nsec = 0;
+ tv.tv_sec = mktime (tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec+2);
+ do_settimeofday (&tv);
+
+ return 0;
+}
+
+static void am_or_pm (void)
+{
+ char rtcdata [9];
+ struct rtc_time tm, time, temp;
+ unsigned char mon, day, hrs, min, sec;
+ unsigned char yr_low, yr_high;
+ unsigned int yrs;
+
+ _rtc_read_time (&tm);
+
+ temp = tm;
+
+ yrs = temp.tm_year + 1900;
+ yr_high = yrs/100;
+ yr_low = (yrs) % 100;
+
+ mon = temp.tm_mon + 1;
+ day = temp.tm_mday;
+ min = 59;
+ sec = 59;
+ hrs = 11;
+
+ rtcdata [0] = 9;
+ rtcdata [1] = 0;
+ rtcdata [2] = BIN_TO_BCD(yr_low);
+ rtcdata [3] = BIN_TO_BCD(yr_high);
+ mon--;
+ rtcdata [4] = BIN_TO_BCD(mon);
+ rtcdata [5] = BIN_TO_BCD(day);
+ rtcdata [6] = BIN_TO_BCD(hrs);
+ rtcdata [7] = BIN_TO_BCD(min);
+ rtcdata [8] = BIN_TO_BCD(sec);
+ davinci_i2c_write (9, rtcdata, 0x23);
+ udelay (1000);
+ mdelay (1000);
+ _rtc_read_time (&time);
+
+ if (time.tm_mday == temp.tm_mday)
+ am = 1;
+ else
+ am = 0;
+
+ davinci_i2c_write (9, rtcdata, 0x23);
+ udelay (1000);
+ mdelay (1000);
+
+ yrs = tm.tm_year + 1900;
+ yr_high = yrs/100;
+ yr_low = (yrs) % 100;
+
+ mon = tm.tm_mon + 1;
+ day = tm.tm_mday;
+ min = tm.tm_min;
+ hrs = tm.tm_hour;
+ if (tm.tm_sec < 58)
+ {
+ sec = tm.tm_sec + 2;
+ } else {
+ sec = 59;
+ }
+
+ davinci_i2c_write (9, rtcdata, 0x23);
+ udelay (1000);
+}
+
+static int __init davinci_rtc_init(void)
+{
+ struct timespec tv;
+ struct rtc_time tm;
+ register_rtc (&davinci_rtc_ops);
+
+ am_or_pm ();
+
+ _rtc_read_time (&tm);
+
+ tv.tv_nsec = 0;
+ tv.tv_sec = mktime (tm.tm_year + 1900, tm.tm_mon + 1 , tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ do_settimeofday (&tv);
+
+ return 0;
+}
+
+module_init(davinci_rtc_init);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 9f3a4cd..6906436 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -654,4 +654,8 @@
This driver can also be built as module. If so, the module
will be called i2c-pmcmsp.
+config I2C_DAVINCI
+ tristate "Davinci i2c driver"
+ depends on I2C && ARCH_DAVINCI
+
endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 0e4c170..e55051d 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -53,6 +53,7 @@
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
+obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
new file mode 100644
index 0000000..1c2eef4
--- /dev/null
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -0,0 +1,599 @@
+/*
+ * linux/drivers/i2c/i2c-davinci.c
+ *
+ * TI DAVINCI I2C unified algorith+adapter driver
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ Modifications:
+ ver. 1.0: Feb 2005, Vinod/Sudhakar
+ -
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <asm/arch/hardware.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/wait.h>
+#include <asm/arch/irqs.h>
+#include <asm/mach-types.h>
+#include "i2c-davinci.h"
+
+MODULE_AUTHOR("Texas Instruments India");
+MODULE_DESCRIPTION("TI DaVinci I2C bus adapter");
+MODULE_LICENSE("GPL");
+
+static int bus_freq;
+module_param(bus_freq, int, 0);
+MODULE_PARM_DESC(bus_freq,
+ "Set I2C bus frequency in KHz: 100 (Standard Mode) or 400 (Fast Mode)");
+
+/* ----- global defines ----------------------------------------------- */
+static const char driver_name[] = "i2c_davinci";
+
+#define DAVINCI_I2C_TIMEOUT (1*HZ)
+#define MAX_MESSAGES 65536 /* max number of messages */
+#define I2C_DAVINCI_INTR_ALL (DAVINCI_I2C_ICIMR_AAS_MASK | \
+ DAVINCI_I2C_ICIMR_SCD_MASK | \
+ /*DAVINCI_I2C_ICIMR_ICXRDY_MASK | */\
+ /*DAVINCI_I2C_ICIMR_ICRRDY_MASK | */\
+ DAVINCI_I2C_ICIMR_ARDY_MASK | \
+ DAVINCI_I2C_ICIMR_NACK_MASK | \
+ DAVINCI_I2C_ICIMR_AL_MASK)
+
+/* Following are the default values for the module parameters */
+
+
+static int bus_freq = 400; /* Default: Fast Mode = 400 KHz, Standard Mode = 100 KHz */
+
+static int own_addr = 0x1; /* Randomly assigned own address */
+
+/* Instance of the private I2C device structure */
+static struct i2c_davinci_device i2c_davinci_dev;
+
+#define PINMUX1 __REG(0x01c40004)
+#define GPIO __REG(0x01C67000)
+#define GPIO23_DIR __REG(0x01C67038)
+#define GPIO23_SET __REG(0x01C67040)
+#define GPIO23_CLR __REG(0x01C67044)
+
+/*
+ * This functions configures I2C and brings I2C out of reset.
+ * This function is called during I2C init function. This function
+ * also gets called if I2C encounetrs any errors. Clock calculation portion
+ * of this function has been taken from some other driver.
+ */
+static int i2c_davinci_reset(struct i2c_davinci_device *dev)
+{
+ u16 psc;
+ u32 clk;
+ u32 input_clock = clk_get_rate(dev->clk);
+
+ /* put I2C into reset */
+ dev->regs->icmdr &= ~DAVINCI_I2C_ICMDR_IRS_MASK;
+
+ /* NOTE: I2C Clock divider programming info
+ * As per I2C specs the following formulas provide prescalar
+ * and low/high divider values
+ *
+ * input clk --> PSC Div -----------> ICCL/H Div --> output clock
+ * module clk
+ *
+ * output clk = module clk / (PSC + 1) [ (ICCL + d) + (ICCH + d) ]
+ *
+ * Thus,
+ * (ICCL + ICCH) = clk = (input clk / ((psc +1) * output clk)) - 2d;
+ *
+ * where if PSC == 0, d = 7,
+ * if PSC == 1, d = 6
+ * if PSC > 1 , d = 5
+ */
+
+ psc = 26; /* To get 1MHz clock */
+
+ clk = ((input_clock/(psc + 1)) / (bus_freq * 1000)) - 10;
+
+ dev->regs->icpsc = psc;
+ dev->regs->icclkh = (50 * clk) / 100; /* duty cycle should be 27% */
+ dev->regs->icclkl = (clk - dev->regs->icclkh);
+
+ dev_dbg(dev->dev, "CLK = %d\n", clk);
+ dev_dbg(dev->dev, "PSC = %d\n", dev->regs->icpsc);
+ dev_dbg(dev->dev, "CLKL = %d\n", dev->regs->icclkl);
+ dev_dbg(dev->dev, "CLKH = %d\n", dev->regs->icclkh);
+
+ /* Set Own Address: */
+ dev->regs->icoar = own_addr;
+
+ /* Enable interrupts */
+ dev->regs->icimr = I2C_DAVINCI_INTR_ALL;
+
+ /* Take the I2C module out of reset: */
+ dev->regs->icmdr |= DAVINCI_I2C_ICMDR_IRS_MASK;
+
+ return 0;
+}
+
+/*
+ * Waiting on Bus Busy
+ */
+static int i2c_davinci_wait_for_bb(struct i2c_davinci_device *dev,
+ char allow_sleep)
+{
+ unsigned long timeout;
+ int i;
+ static char to_cnt = 0;
+
+ timeout = jiffies + DAVINCI_I2C_TIMEOUT;
+ while ((i2c_davinci_dev.regs->icstr) & DAVINCI_I2C_ICSTR_BB_MASK) {
+ if (to_cnt <= 2) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev,
+ "timeout waiting for bus ready");
+ to_cnt ++;
+ return -ETIMEDOUT;
+ }
+ }
+ else {
+ to_cnt = 0;
+ /* Send the NACK to the slave */
+ dev->regs->icmdr |= DAVINCI_I2C_ICMDR_NACKMOD_MASK;
+ /* Disable I2C */
+ PINMUX1 &= (~(1 << 7));
+
+ /* Set the GPIO direction register */
+ GPIO23_DIR &= ~0x0800;
+
+ /* Send high and low on the SCL line */
+ for (i = 0; i < 10; i++) {
+ GPIO23_SET |= 0x0800;
+ udelay(25);
+ GPIO23_CLR |= 0x0800;
+ udelay(25);
+ }
+ /* Re-enable I2C */
+ PINMUX1 |= (1 << 7);
+
+ i2c_davinci_reset(dev);
+ init_completion(&dev->cmd_complete);
+ }
+ if (allow_sleep)
+ schedule_timeout(1);
+ }
+
+ return 0;
+}
+
+/*
+ * Low level master read/write transaction. This function is called
+ * from i2c_davinci_xfer.
+ */
+static int
+i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
+{
+ struct i2c_davinci_device *dev = i2c_get_adapdata(adap);
+ u8 zero_byte = 0;
+ int r;
+
+ u32 flag = 0, stat = 0;
+ int i;
+
+ /* Introduce a 100musec delay. Required for Davinci EVM board only */
+ if (machine_is_davinci_evm())
+ udelay(100);
+
+ /* set the slave address */
+ dev->regs->icsar = msg->addr;
+
+ /* Sigh, seems we can't do zero length transactions. Thus, we
+ * can't probe for devices w/o actually sending/receiving at least
+ * a single byte. So we'll set count to 1 for the zero length
+ * transaction case and hope we don't cause grief for some
+ * arbitrary device due to random byte write/read during
+ * probes.
+ */
+ if (msg->len == 0) {
+ dev->buf = &zero_byte;
+ dev->buf_len = 1;
+ } else {
+ dev->buf = msg->buf;
+ dev->buf_len = msg->len;
+ }
+
+ dev->regs->iccnt = dev->buf_len;
+ init_completion(&dev->cmd_complete);
+ dev->cmd_err = 0;
+
+ /* Clear any pending interrupts by reading the IVR */
+ stat = dev->regs->icivr;
+
+ /* Take I2C out of reset, configure it as master and set the
+ * start bit */
+ flag =
+ DAVINCI_I2C_ICMDR_IRS_MASK | DAVINCI_I2C_ICMDR_MST_MASK |
+ DAVINCI_I2C_ICMDR_STT_MASK;
+
+ /* if the slave address is ten bit address, enable XA bit */
+ if (msg->flags & I2C_M_TEN)
+ flag |= DAVINCI_I2C_ICMDR_XA_MASK;
+ if (!(msg->flags & I2C_M_RD))
+ flag |= DAVINCI_I2C_ICMDR_TRX_MASK;
+ if (stop)
+ flag |= DAVINCI_I2C_ICMDR_STP_MASK;
+
+ /* Enable receive and transmit interrupts */
+ if (msg->flags & I2C_M_RD)
+ dev->regs->icimr |= DAVINCI_I2C_ICIMR_ICRRDY_MASK;
+ else
+ dev->regs->icimr |= DAVINCI_I2C_ICIMR_ICXRDY_MASK;
+
+ /* write the data into mode register */
+ dev->regs->icmdr = flag;
+
+ r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+ DAVINCI_I2C_TIMEOUT);
+ dev->buf_len = 0;
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+
+ /* Send the NACK to the slave */
+ dev->regs->icmdr |= DAVINCI_I2C_ICMDR_NACKMOD_MASK;
+ /* Disable I2C */
+ PINMUX1 &= (~(1 << 7));
+
+ /* Set the GPIO direction register */
+ GPIO23_DIR &= ~0x0800;
+
+ /* Send high and low on the SCL line */
+ for (i = 0; i < 10; i++) {
+ GPIO23_SET |= 0x0800;
+ udelay(25);
+ GPIO23_CLR |= 0x0800;
+ udelay(25);
+ }
+ /* Re-enable I2C */
+ PINMUX1 |= (1 << 7);
+
+ i2c_davinci_reset(dev);
+ return -ETIMEDOUT;
+ }
+
+ /* no error */
+ if (!dev->cmd_err)
+ return msg->len;
+
+ /* We have an error */
+ if (dev->cmd_err & DAVINCI_I2C_ICSTR_NACK_MASK) {
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return msg->len;
+ if (stop)
+ dev->regs->icmdr |= DAVINCI_I2C_ICMDR_STP_MASK;
+ return -EREMOTEIO;
+ }
+ if (dev->cmd_err & DAVINCI_I2C_ICSTR_AL_MASK) {
+ i2c_davinci_reset(dev);
+ return -EIO;
+ }
+ return msg->len;
+}
+
+/*
+ * Prepare controller for a transaction and call i2c_davinci_xfer_msg
+
+ */
+static int
+i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct i2c_davinci_device *dev = i2c_get_adapdata(adap);
+ int count;
+ int ret = 0;
+ char retries = 5;
+
+ dev_dbg(dev->dev, "%s: msgs: %d\n", __FUNCTION__, num);
+
+ if (num < 1 || num > MAX_MESSAGES)
+ return -EINVAL;
+
+ /* Check for valid parameters in messages */
+ for (count = 0; count < num; count++)
+ if (msgs[count].buf == NULL)
+ return -EINVAL;
+
+ if ((ret = i2c_davinci_wait_for_bb(dev, 1)) < 0) {
+ dev_warn(dev->dev, "timeout waiting for bus ready");
+ return ret;
+ }
+
+ for (count = 0; count < num; count++) {
+ dev_dbg(dev->dev,
+ "%s: %d, addr: 0x%04x, len: %d, flags: 0x%x\n",
+ __FUNCTION__,
+ count, msgs[count].addr, msgs[count].len,
+ msgs[count].flags);
+
+ do {
+ ret = i2c_davinci_xfer_msg(adap, &msgs[count],
+ (count == (num - 1)));
+
+ if (ret < 0) {
+ dev_dbg(dev->dev, "Retrying ...\n");
+ mdelay (1);
+ retries--;
+ } else
+ break;
+ } while (retries);
+
+ dev_dbg(dev->dev, "%s:%d ret: %d\n",
+ __FUNCTION__, __LINE__, ret);
+
+ if (ret != msgs[count].len)
+ break;
+ }
+
+ if (ret >= 0 && num >= 1)
+ ret = num;
+
+ dev_dbg(dev->dev, "%s:%d ret: %d\n",
+ __FUNCTION__, __LINE__, ret);
+
+ return ret;
+}
+
+static u32 i2c_davinci_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+/*
+ * This function marks a transaction as complete.
+ */
+static inline void i2c_davinci_complete_cmd(struct i2c_davinci_device *dev)
+{
+ complete(&dev->cmd_complete);
+ wake_up(&dev->cmd_wait);
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C interrupt
+ * occurs.
+ */
+static irqreturn_t
+i2c_davinci_isr(int this_irq, void *dev_id)
+{
+ struct i2c_davinci_device *dev = dev_id;
+ u32 stat;
+
+ while ((stat = dev->regs->icivr) != 0) {
+ dev_dbg(dev->dev, "%s: stat=0x%x\n", __FUNCTION__, stat);
+
+ switch (stat) {
+ case DAVINCI_I2C_ICIVR_INTCODE_AL:
+ dev->cmd_err |= DAVINCI_I2C_ICSTR_AL_MASK;
+ i2c_davinci_complete_cmd(dev);
+ break;
+
+ case DAVINCI_I2C_ICIVR_INTCODE_NACK:
+ dev->cmd_err |= DAVINCI_I2C_ICSTR_NACK_MASK;
+ i2c_davinci_complete_cmd(dev);
+ break;
+
+ case DAVINCI_I2C_ICIVR_INTCODE_RAR:
+ dev->regs->icstr |= DAVINCI_I2C_ICSTR_ARDY_MASK;
+ i2c_davinci_complete_cmd(dev);
+ break;
+
+ case DAVINCI_I2C_ICIVR_INTCODE_RDR:
+ if (dev->buf_len) {
+ *dev->buf++ = dev->regs->icdrr;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ continue;
+ } else {
+ dev->regs->icimr &=
+ ~DAVINCI_I2C_ICIMR_ICRRDY_MASK;
+ }
+ }
+ break;
+
+ case DAVINCI_I2C_ICIVR_INTCODE_TDR:
+ if (dev->buf_len) {
+ dev->regs->icdxr = *dev->buf++;
+ dev->buf_len--;
+ if (dev->buf_len)
+ continue;
+ else {
+ dev->regs->icimr &=
+ ~DAVINCI_I2C_ICIMR_ICXRDY_MASK;
+ }
+ }
+ break;
+
+ case DAVINCI_I2C_ICIVR_INTCODE_SCD:
+ dev->regs->icstr |= DAVINCI_I2C_ICSTR_SCD_MASK;
+ i2c_davinci_complete_cmd(dev);
+ break;
+
+ case DAVINCI_I2C_ICIVR_INTCODE_AAS:
+ dev_warn(dev->dev, "Address as slave interrupt");
+ break;
+
+ default:
+ break;
+ } /* switch */
+ } /* while */
+ return IRQ_HANDLED;
+}
+
+static struct i2c_algorithm i2c_davinci_algo = {
+ .master_xfer = i2c_davinci_xfer,
+ .functionality = i2c_davinci_func,
+};
+
+static int
+davinci_i2c_probe(struct platform_device *pdev)
+{
+ struct i2c_davinci_device *dev = &i2c_davinci_dev;
+ struct i2c_adapter *adap;
+ struct resource *mem, *irq;
+ int r;
+
+ /* NOTE: driver uses the static register mapping */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -ENODEV;
+ }
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return -ENODEV;
+ }
+
+ r = (int) request_mem_region(mem->start, (mem->end - mem->start) + 1,
+ driver_name);
+ if (!r) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -EBUSY;
+ }
+
+ memset(dev, 0, sizeof(struct i2c_davinci_device));
+ init_waitqueue_head(&dev->cmd_wait);
+ dev->dev = &pdev->dev;
+
+ /*
+ * NOTE: On DaVinci EVM, the i2c bus frequency is set to 20kHz
+ * so that the MSP430, which is doing software i2c, has
+ * some extra processing time
+ */
+ if (machine_is_davinci_evm())
+ bus_freq = 20;
+
+ else if (bus_freq > 200)
+ bus_freq = 400; /* Fast mode */
+ else
+ bus_freq = 100; /* Standard mode */
+
+ dev->clk = clk_get (&pdev->dev, "I2CCLK");
+ if (IS_ERR(dev->clk))
+ return -1;
+ clk_enable(dev->clk);
+
+ dev->regs = (davinci_i2cregsovly)mem->start;
+ i2c_davinci_reset(dev);
+
+ dev->irq = irq->start;
+ platform_set_drvdata(pdev, dev);
+
+ r = request_irq(dev->irq, i2c_davinci_isr, 0, driver_name, dev);
+ if (r) {
+ dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+ goto do_unuse_clocks;
+ }
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strncpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name));
+ adap->algo = &i2c_davinci_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->client_register = NULL;
+ adap->client_unregister = NULL;
+ adap->timeout = 1;
+ adap->retries = 1;
+
+ /* i2c device drivers may be active on return from add_adapter() */
+ r = i2c_add_adapter(adap);
+ if (r) {
+ dev_err(&pdev->dev, "failure adding adapter\n");
+ goto do_free_irq;
+ }
+
+ return 0;
+
+do_free_irq:
+ free_irq(dev->irq, dev);
+do_unuse_clocks:
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+
+ return r;
+}
+
+static int
+davinci_i2c_remove(struct platform_device *pdev)
+{
+ struct i2c_davinci_device *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+
+ i2c_davinci_dev.regs->icmdr = 0;
+ free_irq(IRQ_I2C, &i2c_davinci_dev);
+
+ i2c_del_adapter(&dev->adapter);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+ return 0;
+}
+
+static struct platform_driver davinci_i2c_driver = {
+ .probe = davinci_i2c_probe,
+ .remove = davinci_i2c_remove,
+ .driver = {
+ .name = (char *)driver_name,
+ },
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init
+davinci_i2c_init_driver(void)
+{
+ return platform_driver_register(&davinci_i2c_driver);
+}
+subsys_initcall(davinci_i2c_init_driver);
+
+static void __exit davinci_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&davinci_i2c_driver);
+}
+module_exit(davinci_i2c_exit_driver);
diff --git a/drivers/i2c/busses/i2c-davinci.h b/drivers/i2c/busses/i2c-davinci.h
new file mode 100644
index 0000000..7360077
--- /dev/null
+++ b/drivers/i2c/busses/i2c-davinci.h
@@ -0,0 +1,156 @@
+/*
+ * linux/drivers/i2c/busses/davinci/i2c_davinci.h
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ Modifications:
+ ver. 1.0: Feb 2005, Vinod/Sudhakar
+ -
+ *
+ */
+
+#define DAVINCI_I2C_ICOAR_OADDR_MASK (0x03FFu)
+#define DAVINCI_I2C_ICIMR_AAS_MASK (0x0040u)
+#define DAVINCI_I2C_ICIMR_SCD_MASK (0x0020u)
+#define DAVINCI_I2C_ICIMR_ICXRDY_MASK (0x0010u)
+#define DAVINCI_I2C_ICIMR_ICRRDY_MASK (0x0008u)
+#define DAVINCI_I2C_ICIMR_ARDY_MASK (0x0004u)
+#define DAVINCI_I2C_ICIMR_NACK_MASK (0x0002u)
+#define DAVINCI_I2C_ICIMR_AL_MASK (0x0001u)
+#define DAVINCI_I2C_ICSTR_SDIR_MASK (0x4000u)
+#define DAVINCI_I2C_ICSTR_NACKSNT_MASK (0x2000u)
+#define DAVINCI_I2C_ICSTR_BB_MASK (0x1000u)
+#define DAVINCI_I2C_ICSTR_RSFULL_MASK (0x0800u)
+#define DAVINCI_I2C_ICSTR_XSMT_MASK (0x0400u)
+#define DAVINCI_I2C_ICSTR_AAS_MASK (0x0200u)
+#define DAVINCI_I2C_ICSTR_AD0_MASK (0x0100u)
+#define DAVINCI_I2C_ICSTR_SCD_MASK (0x0020u)
+#define DAVINCI_I2C_ICSTR_ICXRDY_MASK (0x0010u)
+#define DAVINCI_I2C_ICSTR_ICRRDY_MASK (0x0008u)
+#define DAVINCI_I2C_ICSTR_ARDY_MASK (0x0004u)
+#define DAVINCI_I2C_ICSTR_NACK_MASK (0x0002u)
+#define DAVINCI_I2C_ICSTR_AL_MASK (0x0001u)
+#define DAVINCI_I2C_ICCLKL_ICCL_MASK (0xFFFFu)
+#define DAVINCI_I2C_ICCLKH_ICCH_MASK (0xFFFFu)
+#define DAVINCI_I2C_ICCNT_ICDC_MASK (0xFFFFu)
+#define DAVINCI_I2C_ICDRR_D_MASK (0x00FFu)
+#define DAVINCI_I2C_ICSAR_SADDR_MASK (0x03FFu)
+#define DAVINCI_I2C_ICDXR_D_MASK (0x00FFu)
+#define DAVINCI_I2C_ICMDR_NACKMOD_MASK (0x8000u)
+#define DAVINCI_I2C_ICMDR_FREE_MASK (0x4000u)
+#define DAVINCI_I2C_ICMDR_STT_MASK (0x2000u)
+#define DAVINCI_I2C_ICMDR_STP_MASK (0x0800u)
+#define DAVINCI_I2C_ICMDR_MST_MASK (0x0400u)
+#define DAVINCI_I2C_ICMDR_TRX_MASK (0x0200u)
+#define DAVINCI_I2C_ICMDR_XA_MASK (0x0100u)
+#define DAVINCI_I2C_ICMDR_RM_MASK (0x0080u)
+#define DAVINCI_I2C_ICMDR_DLB_MASK (0x0040u)
+#define DAVINCI_I2C_ICMDR_IRS_MASK (0x0020u)
+#define DAVINCI_I2C_ICMDR_STB_MASK (0x0010u)
+#define DAVINCI_I2C_ICMDR_FDF_MASK (0x0008u)
+#define DAVINCI_I2C_ICMDR_BC_MASK (0x0007u)
+#define DAVINCI_I2C_ICIVR_TESTMD_MASK (0x0F00u)
+#define DAVINCI_I2C_ICIVR_INTCODE_MASK (0x0007u)
+
+#define DAVINCI_I2C_ICIVR_INTCODE_NONE (0x0000u)
+#define DAVINCI_I2C_ICIVR_INTCODE_AL (0x0001u)
+#define DAVINCI_I2C_ICIVR_INTCODE_NACK (0x0002u)
+#define DAVINCI_I2C_ICIVR_INTCODE_RAR (0x0003u)
+#define DAVINCI_I2C_ICIVR_INTCODE_RDR (0x0004u)
+#define DAVINCI_I2C_ICIVR_INTCODE_TDR (0x0005u)
+#define DAVINCI_I2C_ICIVR_INTCODE_SCD (0x0006u)
+#define DAVINCI_I2C_ICIVR_INTCODE_AAS (0x0007u)
+
+#define DAVINCI_I2C_ICEMDR_BCM_MASK (0x0001u)
+#define DAVINCI_I2C_ICPSC_IPSC_MASK (0x00FFu)
+#define DAVINCI_I2C_ICPID1_CLASS_MASK (0xFF00u)
+#define DAVINCI_I2C_ICPID1_REVISION_MASK (0x00FFu)
+#define DAVINCI_I2C_ICPID2_TYPE_MASK (0x00FFu)
+#define DAVINCI_I2C_ICPFUNC_PFUNC_MASK (0x00000001u)
+#define DAVINCI_I2C_ICPDIR_PDIR1_MASK (0x00000002u)
+#define DAVINCI_I2C_ICPDIR_PDIR0_MASK (0x00000001u)
+#define DAVINCI_I2C_ICPDIN_PDIN1_MASK (0x00000002u)
+#define DAVINCI_I2C_ICPDIN_PDIN0_MASK (0x00000001u)
+#define DAVINCI_I2C_ICPDOUT_PDOUT1_MASK (0x00000002u)
+#define DAVINCI_I2C_ICPDOUT_PDOUT0_MASK (0x00000001u)
+#define DAVINCI_I2C_ICPDSET_PDSET1_MASK (0x00000002u)
+#define DAVINCI_I2C_ICPDSET_PDSET0_MASK (0x00000001u)
+#define DAVINCI_I2C_ICPDCLR_PDCLR1_MASK (0x00000002u)
+#define DAVINCI_I2C_ICPDCLR_PDCLR0_MASK (0x00000001u)
+
+/**************************************************************************\
+* Register Overlay Structure
+\**************************************************************************/
+typedef struct {
+ u16 icoar;
+ u8 rsvd0[2];
+ u16 icimr;
+ u8 rsvd1[2];
+ u16 icstr;
+ u8 rsvd2[2];
+ u16 icclkl;
+ u8 rsvd3[2];
+ u16 icclkh;
+ u8 rsvd4[2];
+ u16 iccnt;
+ u8 rsvd5[2];
+ u16 icdrr;
+ u8 rsvd6[2];
+ u16 icsar;
+ u8 rsvd7[2];
+ u16 icdxr;
+ u8 rsvd8[2];
+ u16 icmdr;
+ u8 rsvd9[2];
+ u16 icivr;
+ u8 rsvd10[2];
+ u16 icemdr;
+ u8 rsvd11[2];
+ u16 icpsc;
+ u8 rsvd12[2];
+ u16 icpid1;
+ u8 rsvd13[2];
+ u16 icpid2;
+ u8 rsvd14[14];
+ u32 ipcfunc;
+ u32 icpdir;
+ u32 icpdin;
+ u32 icpdout;
+ u32 icpdset;
+ u32 icpdclr;
+} davinci_i2cregs;
+
+/**************************************************************************\
+* Overlay structure typedef definition
+\**************************************************************************/
+typedef volatile davinci_i2cregs *davinci_i2cregsovly;
+
+struct i2c_davinci_device {
+ int cmd_err;
+ struct completion cmd_complete;
+ wait_queue_head_t cmd_wait;
+ u8 *buf;
+ size_t buf_len;
+ davinci_i2cregsovly regs;
+
+ int irq;
+ struct i2c_adapter adapter;
+ struct clk *clk;
+ struct device *dev;
+};
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index f6b492b..04edab7 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -123,6 +123,11 @@
If you say yes here you get support for the I2C control
interface for Texas Instruments TLV320AIC23 audio codec.
+config SENSORS_TLV320AIC33
+ tristate "Texas Instruments TLV320AIC33 Codec"
+ depends on I2C && I2C_DAVINCI
+ select SENSORS_TLV320AIC23
+
config GPIOEXPANDER_OMAP
bool "GPIO Expander PCF8574PWR for OMAP"
depends on I2C && (ARCH_OMAP16XX || ARCH_OMAP24XX)
@@ -187,4 +192,10 @@
and other features that are often used in portable devices like
cell phones and PDAs.
+config GPIOEXPANDER_DAVINCI
+ bool "GPIO Expander for DaVinci"
+ depends on I2C && ARCH_DAVINCI
+ help
+ If you say yes here you get support for I/O expander calls
+
endmenu
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index 116fe15..f1afec2 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -20,6 +20,7 @@
obj-$(CONFIG_TWL4030_CORE) += twl4030_core.o
obj-$(CONFIG_TWL4030_GPIO) += twl4030_gpio.o
obj-$(CONFIG_RTC_X1205_I2C) += x1205.o
+obj-$(CONFIG_GPIOEXPANDER_DAVINCI) += gpio_expander_davinci.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/chips/gpio_expander_davinci.c b/drivers/i2c/chips/gpio_expander_davinci.c
new file mode 100644
index 0000000..33b7c8d
--- /dev/null
+++ b/drivers/i2c/chips/gpio_expander_davinci.c
@@ -0,0 +1,142 @@
+/*
+ * drivers/i2c/chips/gpio_expander_davinci.c
+ *
+ * Author: Vladimir Barinov, MontaVista Software, Inc. <source@mvista.com>
+ *
+ * Copyright (C) 2006 Texas Instruments Inc
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+
+#include <asm/arch/i2c-client.h>
+
+static DEFINE_MUTEX(expander_lock);
+
+static int davinci_i2c_expander_read(u8 size, u8 * val, u16 addr)
+{
+ struct i2c_adapter *adap;
+ int err;
+ struct i2c_msg msg[1];
+
+ adap = i2c_get_adapter(0);
+ if (!adap)
+ return -ENODEV;
+
+ msg->addr = addr;
+ msg->flags = I2C_M_RD;
+ msg->len = size;
+ msg->buf = val;
+
+ err = i2c_transfer(adap, msg, 1);
+ if (err >= 0)
+ return 0;
+
+ return err;
+}
+
+static int davinci_i2c_expander_write(u8 size, u8 * val, u16 addr)
+{
+ struct i2c_adapter *adap;
+ int err;
+ struct i2c_msg msg[1];
+
+ adap = i2c_get_adapter(0);
+ if (!adap)
+ return -ENODEV;
+
+ msg->addr = addr;
+ msg->flags = 0;
+ msg->len = size;
+ msg->buf = val;
+
+ err = i2c_transfer(adap, msg, 1);
+ if (err >= 0)
+ return 0;
+
+ return err;
+}
+
+int davinci_i2c_expander_op(u16 client_addr, u35_expander_ops pin, u8 val)
+{
+ int err = 0;
+ char cmd[4] = { 4, 6, 0x00, 0x09 };
+ u8 data_to_u35 = 0;
+
+ if (val > 1)
+ return -1;
+
+ mutex_lock(&expander_lock);
+
+ err = davinci_i2c_expander_read(1, &data_to_u35, 0x3A);
+ if (err < 0)
+ return err;
+
+ if (client_addr == 0x3A) {
+ switch (pin) {
+ case USB_DRVVBUS:
+ if (val)
+ data_to_u35 |= val;
+ else
+ data_to_u35 &= (val | 0xFE);
+ break;
+ case VDDIMX_EN:
+ if (val)
+ data_to_u35 |= (val << 1);
+ else
+ data_to_u35 &= (val | 0xFD);
+ break;
+ case VLYNQ_ON:
+ if (val)
+ data_to_u35 |= (val << 2);
+ else
+ data_to_u35 &= (val | 0xFB);
+ break;
+ case CF_RESET:
+ if (val)
+ data_to_u35 |= (val << 3);
+ else
+ data_to_u35 &= (val | 0xF7);
+ break;
+ case WLAN_RESET:
+ if (val)
+ data_to_u35 |= (val << 5);
+ else
+ data_to_u35 &= (val | 0xDF);
+ break;
+ case ATA_SEL:
+ if (val)
+ data_to_u35 |= (val << 6);
+ else
+ data_to_u35 &= (val | 0xBF);
+ break;
+ case CF_SEL:
+ davinci_i2c_expander_write(4, cmd, 0x23);
+ if (val)
+ data_to_u35 |= (val << 7);
+ else
+ data_to_u35 &= (val | 0x7F);
+ break;
+ default:
+ break;
+ }
+ } else {
+ printk("Only IO Expander at address 0x3A is suuported\n");
+ mutex_unlock(&expander_lock);
+ return -EINVAL;
+ }
+
+ err = davinci_i2c_expander_write(1, &data_to_u35, 0x3A);
+
+ mutex_unlock(&expander_lock);
+
+ return err;
+}
+EXPORT_SYMBOL(davinci_i2c_expander_op);
diff --git a/drivers/i2c/chips/tlv320aic23.c b/drivers/i2c/chips/tlv320aic23.c
index a2ec4bc..64946ab 100644
--- a/drivers/i2c/chips/tlv320aic23.c
+++ b/drivers/i2c/chips/tlv320aic23.c
@@ -95,6 +95,18 @@
return 0;
}
+#ifdef CONFIG_SENSORS_TLV320AIC33
+int tlv320aic33_write_value(u8 reg, u16 value)
+{
+ static struct i2c_client *client;
+ u8 val = value & 0xff;
+
+ client = new_client;
+
+ return i2c_smbus_write_byte_data(client, reg, val);
+}
+#endif /* CONFIG_SENSORS_TLV320AIC33 */
+
static int aic23_detect_client(struct i2c_adapter *adapter, int address,
int kind)
{
@@ -162,6 +174,7 @@
.detach_client = aic23_detach_client,
};
+#ifdef CONFIG_ARCH_OMAP
/*
* Configures the McBSP3 which is used to send clock to the AIC23 codec.
* The input clock rate from DSP is 12MHz.
@@ -193,6 +206,7 @@
return 0;
}
+#endif
static void update_volume_left(int volume)
{
@@ -639,10 +653,12 @@
selftest = -ENODEV;
return selftest;
}
+#ifdef CONFIG_ARCH_OMAP
/* FIXME: Do in board-specific file */
omap_mcbsp3_aic23_clock_init();
if (!aic23_info_l.power_down)
aic23_power_up();
+#endif
aic23_info_l.initialized = 1;
printk("TLV320AIC23 I2C version %s (%s)\n",
TLV320AIC23_VERSION, TLV320AIC23_DATE);
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 4200251..19eee75 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -944,6 +944,15 @@
normally be on; disable it only if you are running a custom hard
drive subsystem through an expansion card.
+config BLK_DEV_DAVINCI
+ tristate "Davinci IDE interface support "
+ depends on ARCH_DAVINCI && DAVINCI_I2C_EXPANDER
+ select BLK_DEV_IDEDMA
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This is the IDE driver for Davinci platform with Palmchip 3710 IDE
+ controller
+
config BLK_DEV_MPC8xx_IDE
bool "MPC8xx IDE support"
depends on 8xx && IDE=y && BLK_DEV_IDE=y && !PPC_MERGE
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index 75dc696..fda7308 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -52,3 +52,4 @@
obj-$(CONFIG_BLK_DEV_IDE) += legacy/ arm/ mips/
obj-$(CONFIG_BLK_DEV_HD) += legacy/
obj-$(CONFIG_ETRAX_IDE) += cris/
+obj-$(CONFIG_BLK_DEV_DAVINCI) += davinci/
diff --git a/drivers/ide/davinci/Makefile b/drivers/ide/davinci/Makefile
new file mode 100644
index 0000000..12be3bb
--- /dev/null
+++ b/drivers/ide/davinci/Makefile
@@ -0,0 +1,4 @@
+
+obj-$(CONFIG_BLK_DEV_DAVINCI) += palm_bk3710.o
+
+EXTRA_CFLAGS := -Idrivers/ide
diff --git a/drivers/ide/davinci/palm_bk3710.c b/drivers/ide/davinci/palm_bk3710.c
new file mode 100644
index 0000000..07081e5
--- /dev/null
+++ b/drivers/ide/davinci/palm_bk3710.c
@@ -0,0 +1,622 @@
+/*
+ * linux/drivers/ide/davinci/palm_bk3710.c
+ *
+ * TI DaVinci Palm Chip 3710 IDE driver file
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ Modifications:
+ ver. 1.0: Oct 2005, Swaminathan S
+ -
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/i2c-client.h>
+#include "palm_bk3710.h"
+#include "../ide-timing.h"
+
+
+static ide_hwif_t *palm_bk3710_hwif = NULL;
+struct ide_pci_device_s palm_bk3710_dummydata;
+palm_bk3710_ideregs *palm_bk3710_base = NULL;
+long ide_palm_clk = 0;
+/*
+ *
+ * Standard (generic) timings for Taskfile modes, from ATA2 specification.
+ * Some drives may specify a mode, while also specifying a different
+ * value for cycle_time (from drive identification data).
+ */
+const palm_bk3710_piotiming palm_bk3710_tasktimings[6] = {
+ {290, 600}, /* PIO Mode 0 */
+ {290, 383}, /* PIO Mode 1 */
+ {290, 240}, /* PIO Mode 2 */
+ {80, 180}, /* PIO Mode 3 with IORDY */
+ {70, 120} /* PIO Mode 4 with IORDY */
+};
+
+/*
+ *
+ * Standard (generic) timings for PIO modes, from ATA2 specification.
+ * Some drives may specify a mode, while also specifying a different
+ * value for cycle_time (from drive identification data).
+ */
+const palm_bk3710_piotiming palm_bk3710_piotimings[6] = {
+ {165, 600}, /* PIO Mode 0 */
+ {125, 383}, /* PIO Mode 1 */
+ {100, 240}, /* PIO Mode 2 */
+ {80, 180}, /* PIO Mode 3 with IORDY */
+ {70, 120} /* PIO Mode 4 with IORDY */
+};
+
+/*
+ *
+ * Standard (generic) timings for DMA modes, from ATA2 specification.
+ * Some drives may specify a mode, while also specifying a different
+ * value for cycle_time (from drive identification data).
+ */
+const palm_bk3710_dmatiming palm_bk3710_dmatimings[3] = {
+ {215, 215, 480}, /* DMA Mode 0 */
+ {80, 50, 150}, /* DMA Mode 1 */
+ {70, 25, 120} /* DMA Mode 2 */
+};
+
+/*
+ *
+ * Standard (generic) timings for UDMA modes, from ATA2 specification.
+ * Some drives may specify a mode, while also specifying a different
+ * value for cycle_time (from drive identification data).
+ */
+const palm_bk3710_udmatiming palm_bk3710_udmatimings[7] = {
+ {20, 160, 240}, /* UDMA Mode 0 */
+ {20, 125, 160}, /* UDMA Mode 1 */
+ {20, 100, 120}, /* UDMA Mode 2 */
+ {20, 100, 90}, /* UDMA Mode 3 */
+ {20, 85, 60}, /* UDMA Mode 4 */
+ {20, 85, 40} /* UDMA Mode 5 */
+};
+
+struct clk *ideclkp = NULL;
+int palm_bk3710_chipinit(void);
+int palm_bk3710_setdmamode(palm_bk3710_ideregs *, unsigned int, unsigned int,
+ unsigned int);
+u8 palm_bk3710_setpiomode(palm_bk3710_ideregs *, unsigned int, unsigned int, u8);
+
+static void palm_bk3710_tune_drive(ide_drive_t *, u8);
+
+#ifndef CONFIG_DAVINCI_BLK_DEV_CF
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/**
+ * palm_bk3710_setudmamode : Set the device UDMA mode on Palm Chip 3710
+ *
+ * Handle [IN] : IDE Controller info
+ * Dev [IN] : drive to tune
+ * level [IN] : desired level
+ * int : level in UDMA Mode
+ ******************************************************************************/
+int palm_bk3710_setudmamode(palm_bk3710_ideregs * handle, unsigned int dev,
+ unsigned int level)
+{
+ char is_slave = (dev == 1) ? 1 : 0;
+ char ide_tenv, ide_trp, ide_t0;
+
+ /* DMA Data Setup */
+ ide_t0 = (palm_bk3710_udmatimings[level].cycletime / ide_palm_clk) - 1;
+ ide_tenv = (palm_bk3710_udmatimings[level].envtime / ide_palm_clk) - 1;
+ ide_trp = (palm_bk3710_udmatimings[level].rptime / ide_palm_clk) - 1;
+
+ if (!is_slave) {
+ /* setup master device parameters */
+ /* udmatim Register */
+ palm_bk3710_base->config.udmatim &= 0xFFF0;
+ palm_bk3710_base->config.udmatim |= level;
+ /* udmastb Ultra DMA Access Strobe Width */
+ palm_bk3710_base->config.udmastb &= 0xFF00;
+ palm_bk3710_base->config.udmastb |= ide_t0;
+ /* udmatrp Ultra DMA Ready to Pause Time */
+ palm_bk3710_base->config.udmatrp &= 0xFF00;
+ palm_bk3710_base->config.udmatrp |= ide_trp;
+ /* udmaenv Ultra DMA envelop Time */
+ palm_bk3710_base->config.udmaenv &= 0xFF00;
+ palm_bk3710_base->config.udmaenv |= ide_tenv;
+ /* Enable UDMA for Device 0 */
+ palm_bk3710_base->config.udmactl |= 1;
+ } else {
+ /* setup slave device parameters */
+ /* udmatim Register */
+ palm_bk3710_base->config.udmatim &= 0xFF0F;
+ palm_bk3710_base->config.udmatim |= (level << 4);
+ /* udmastb Ultra DMA Access Strobe Width */
+ palm_bk3710_base->config.udmastb &= 0xFF;
+ palm_bk3710_base->config.udmastb |= (ide_t0 << 8);
+ /* udmatrp Ultra DMA Ready to Pause Time */
+ palm_bk3710_base->config.udmatrp &= 0xFF;
+ palm_bk3710_base->config.udmatrp |= (ide_trp << 8);
+ /* udmaenv Ultra DMA envelop Time */
+ palm_bk3710_base->config.udmaenv &= 0xFF;
+ palm_bk3710_base->config.udmaenv |= (ide_tenv << 8);
+ /* Enable UDMA for Device 0 */
+ palm_bk3710_base->config.udmactl |= (1 << 1);
+ }
+
+ return level;
+}
+
+/**
+ * palm_bk3710_setdmamode : Set the device DMA mode on Palm Chip 3710.
+ *
+ * Handle [IN] : IDE Controller info
+ * Dev [IN] : drive to tune
+ * level [IN] : desired level
+ * int : level in DMA Mode
+ ******************************************************************************/
+int palm_bk3710_setdmamode(palm_bk3710_ideregs * handle, unsigned int dev,
+ unsigned int cycletime, unsigned int mode)
+{
+ char is_slave = (dev == 1) ? 1 : 0;
+ char ide_td, ide_tkw, ide_t0;
+
+ if (cycletime < palm_bk3710_dmatimings[mode].cycletime) {
+ cycletime = palm_bk3710_dmatimings[mode].cycletime;
+ }
+
+ /* DMA Data Setup */
+ ide_t0 = cycletime / ide_palm_clk;
+ ide_td = palm_bk3710_dmatimings[mode].activetime / ide_palm_clk;
+ ide_tkw = ide_t0 - ide_td - 1;
+ ide_td -= 1;
+
+ if (!is_slave) {
+ /* setup master device parameters */
+ palm_bk3710_base->config.dmastb &= 0xFF00;
+ palm_bk3710_base->config.dmastb |= ide_td;
+ palm_bk3710_base->config.dmarcvr &= 0xFF00;
+ palm_bk3710_base->config.dmarcvr |= ide_tkw;
+ palm_bk3710_base->dmaengine.bmisp |= 0x20;
+ palm_bk3710_base->config.udmactl &= 0xFF02;
+ } else {
+ /* setup slave device parameters */
+ palm_bk3710_base->config.dmastb &= 0xFF;
+ palm_bk3710_base->config.dmastb |= (ide_td << 8);
+ palm_bk3710_base->config.dmarcvr &= 0xFF;
+ palm_bk3710_base->config.dmarcvr |= (ide_tkw << 8);
+ palm_bk3710_base->dmaengine.bmisp |= 0x40;
+ /* Disable UDMA for Device 1 */
+ palm_bk3710_base->config.udmactl &= 0xFF01;
+ }
+
+ return mode;
+}
+#endif
+#endif
+
+/**
+ * palm_bk3710_setpiomode : Set the device PIO mode on Palm Chip 3710.
+ *
+ * Handle [IN] : IDE Controller info
+ * Dev [IN] : drive to tune
+ * level [IN] : desired level
+ * u8 : level in PIO mode
+ ******************************************************************************/
+u8 palm_bk3710_setpiomode(palm_bk3710_ideregs * handle, unsigned int dev,
+ unsigned int cycletime, u8 mode)
+{
+ int is_slave = (dev == 1) ? 1 : 0;
+ char ide_t2, ide_t2i, ide_t0;
+
+ if (cycletime < palm_bk3710_piotimings[mode].cycletime) {
+ cycletime = palm_bk3710_piotimings[mode].cycletime;
+ }
+ /* PIO Data Setup */
+ ide_t0 = cycletime / ide_palm_clk;
+ ide_t2 = palm_bk3710_piotimings[mode].activetime / ide_palm_clk;
+ ide_t2i = ide_t0 - ide_t2 - 1;
+ ide_t2 -= 1;
+
+ if (!is_slave) {
+ /* setup master device parameters */
+ palm_bk3710_base->config.datstb &= 0xFF00;
+ palm_bk3710_base->config.datstb |= ide_t2;
+ palm_bk3710_base->config.datrcvr &= 0xFF00;
+ palm_bk3710_base->config.datrcvr |= ide_t2i;
+ /* Disable UDMA for Device 0 */
+ } else {
+ /* setup slave device parameters */
+ palm_bk3710_base->config.datstb &= 0xFF;
+ palm_bk3710_base->config.datstb |= (ide_t2 << 8);
+ palm_bk3710_base->config.datrcvr &= 0xFF;
+ palm_bk3710_base->config.datrcvr |= (ide_t2i << 8);
+ /* Disable UDMA for Device 1 */
+ }
+
+ /* TASKFILE Setup */
+ ide_t2 = palm_bk3710_tasktimings[mode].activetime / ide_palm_clk;
+ ide_t2i = ide_t0 - ide_t2 - 1;
+ ide_t2 -= 1;
+
+ if (!is_slave) {
+ /* setup master device parameters */
+ palm_bk3710_base->config.regstb &= 0xFF00;
+ palm_bk3710_base->config.regstb |= ide_t2;
+ palm_bk3710_base->config.regrcvr &= 0xFF00;
+ palm_bk3710_base->config.regrcvr |= ide_t2i;
+ } else {
+ /* setup slave device parameters */
+ palm_bk3710_base->config.regstb &= 0xFF;
+ palm_bk3710_base->config.regstb |= (ide_t2 << 8);
+ palm_bk3710_base->config.regrcvr &= 0xFF;
+ palm_bk3710_base->config.regrcvr |= (ide_t2i << 8);
+ }
+
+ return mode;
+}
+
+#ifndef CONFIG_DAVINCI_BLK_DEV_CF
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/**
+ * palm_bk3710_hostdma -
+ * @drive: IDE drive to tune
+ * @xferspeed: speed to configure
+ *
+ * Set a Palm Chip 3710 interface channel to the desired speeds. This involves
+ * requires the right timing data into the 3710 timing override registers.
+ */
+
+static int palm_bk3710_hostdma(ide_drive_t * drive, u8 xferspeed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 speed = (XFER_UDMA_4 < xferspeed) ? XFER_UDMA_4 : xferspeed;
+ int is_slave = (&hwif->drives[1] == drive);
+ char ide_cycle;
+ struct hd_driveid *id = drive->id;
+ int nspeed = -1;
+
+ switch (speed) {
+ case XFER_UDMA_4:
+ nspeed = 2;
+ break;
+ case XFER_UDMA_3:
+ nspeed = 3;
+ break;
+ case XFER_UDMA_2:
+ nspeed = 4;
+ break;
+ case XFER_UDMA_1:
+ nspeed = 5;
+ break;
+ case XFER_UDMA_0:
+ nspeed = 6;
+ break;
+ case XFER_MW_DMA_2:
+ nspeed = 8;
+ break;
+ case XFER_MW_DMA_1:
+ nspeed = 9;
+ break;
+ case XFER_MW_DMA_0:
+ nspeed = 10;
+ break;
+ default:
+ return -1;
+ }
+
+ if (nspeed != -1) {
+ ide_cycle = (ide_timing[nspeed].cycle < id->eide_dma_min) ?
+ id->eide_dma_min : ide_timing[nspeed].cycle;
+ if ((speed <= XFER_UDMA_4) && (speed >= XFER_UDMA_0)) {
+ palm_bk3710_setudmamode(NULL, is_slave, 6 - nspeed);
+ } else {
+ palm_bk3710_setdmamode(NULL, is_slave, ide_cycle,
+ 10 - nspeed);
+ }
+
+ return (ide_config_drive_speed(drive, speed));
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * palm_bk3710_drivedma - configure drive for DMA
+ * @drive: IDE drive to configure
+ *
+ * Set up a Palm Chip 3710 interface channel for the best available speed.
+ * We prefer UDMA if it is available and then MWDMA. If DMA is
+ * not available we switch to PIO and return 0.
+ */
+
+static inline int palm_bk3710_drivedma(ide_drive_t * pDrive)
+{
+ u8 speed = ide_rate_filter(pDrive, 2); /* We have a 76.5 MHz clock hence only UDMA66 is possible */
+
+ /* If no DMA/single word DMA was available or the chipset has DMA bugs
+ then disable DMA and use PIO */
+ if (!speed) {
+ palm_bk3710_tune_drive(pDrive, 255);
+ } else {
+ palm_bk3710_hostdma(pDrive, speed);
+ ide_tune_dma(pDrive);
+ }
+
+ return 0;
+}
+
+/**
+ * palm_bk3710_checkdma - set up an IDE device
+ * @drive: IDE drive to configure
+ *
+ * Set up the Palm Chip 3710 interface for the best available speed on this
+ * interface, preferring DMA to PIO.
+ */
+
+static int palm_bk3710_checkdma(ide_drive_t * drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ drive->init_speed = 0;
+
+ if ((id->capability & 1) && drive->autodma) {
+ if (id->field_valid & 4) {
+ if (id->dma_ultra & hwif->ultra_mask) {
+ /* Force if Capable UltraDMA */
+ if ((id->field_valid & 2) &&
+ (!palm_bk3710_drivedma(drive)))
+ goto try_dma_modes;
+ }
+ } else if (id->field_valid & 2) {
+ try_dma_modes:
+ if (id->dma_mword & hwif->mwdma_mask) {
+ /* Force if Capable regular DMA modes */
+ if (!palm_bk3710_drivedma(drive))
+ goto no_dma_set;
+ }
+ } else {
+ goto fast_ata_pio;
+ }
+ return hwif->ide_dma_on(drive);
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+ fast_ata_pio:
+ no_dma_set:
+ hwif->tuneproc(drive, 255);
+ hwif->dma_off_quietly(drive);
+ }
+
+ return 0;
+}
+#endif
+#endif
+
+/**
+ * palm_bk3710_tune_drive - tune a drive attached to a Palm Chip 3710
+ * @drive: drive to tune
+ * @pio: desired PIO mode
+ *
+ * Set the interface and device PIO mode
+ *
+ */
+static void palm_bk3710_tune_drive(ide_drive_t * drive, u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned int cycle_time;
+ int is_slave = (&hwif->drives[1] == drive);
+
+ /* Get the best PIO Mode supported by the drive
+ * Obtain the drive PIO data for tuning the Palm Chip registers
+ */
+ pio = ide_get_best_pio_mode(drive, pio, 5);
+ cycle_time = ide_pio_cycle_time(drive, pio);
+ /* Check for IORDY here */
+ if (cycle_time < ide_pio_timings[pio].cycle_time) {
+ cycle_time = ide_pio_timings[pio].cycle_time;
+ }
+ palm_bk3710_setpiomode(NULL, is_slave, cycle_time, pio);
+}
+
+/**
+ * palm_bk3710_init - Init Palm Chip 3710
+ *
+ * Initialize the Palm Chip 3710 IDE controller to default conditions.
+ *
+ */
+int palm_bk3710_init(void)
+{
+ int ret = 0;
+ hw_regs_t ide_ctlr_info;
+ int index = 0;
+ int pribase = IO_ADDRESS(IDE_PALM_REG_MMAP_BASE) +
+ IDE_PALM_ATA_PRI_REG_OFFSET;
+ struct clk *clkp;
+
+ clkp = clk_get (NULL, "IDECLK");
+ if (!IS_ERR(clkp))
+ {
+ ideclkp = clkp;
+ clk_enable (ideclkp);
+ ide_palm_clk = clk_get_rate(ideclkp)/100000;
+ ide_palm_clk = (10000/ide_palm_clk) + 1;
+ /* ATA_SEL is 1 -> Disable 0 -> Enable
+ * CF_SEL is 1 -> Disable 0 -> Enable
+ *
+ * Ensure both are not Enabled.
+ */
+#ifdef CONFIG_DAVINCI_BLK_DEV_CF
+ davinci_i2c_expander_op (0x3A, ATA_SEL, 1);
+ davinci_i2c_expander_op (0x3A, CF_RESET, 1);
+ davinci_i2c_expander_op (0x3A, CF_SEL, 0);
+#else
+ davinci_i2c_expander_op (0x3A, CF_SEL, 1);
+ davinci_i2c_expander_op (0x3A, ATA_SEL, 0);
+#endif
+ /* Register the IDE interface with Linux ATA Interface */
+ memset(&ide_ctlr_info, 0, sizeof(ide_ctlr_info));
+
+ palm_bk3710_base =
+ (palm_bk3710_ideregs *) IO_ADDRESS(IDE_PALM_REG_MMAP_BASE);
+ /* Configure the Palm Chip controller */
+ palm_bk3710_chipinit();
+
+ for (index = 0; index < IDE_NR_PORTS - 2; index++) {
+ ide_ctlr_info.io_ports[index] = pribase + index;
+ }
+ ide_ctlr_info.io_ports[IDE_CONTROL_OFFSET] =
+ IO_ADDRESS(IDE_PALM_REG_MMAP_BASE)
+ + IDE_PALM_ATA_PRI_CTL_OFFSET;
+ ide_ctlr_info.irq = IRQ_IDE;
+ ide_ctlr_info.chipset = ide_palm3710;
+ ide_ctlr_info.ack_intr = NULL;
+ if (ide_register_hw(&ide_ctlr_info, 0, &palm_bk3710_hwif) < 0) {
+ printk("Palm Chip BK3710 IDE Register Fail\n");
+ return -1;
+ }
+
+ palm_bk3710_hwif->tuneproc = &palm_bk3710_tune_drive;
+
+ palm_bk3710_hwif->noprobe = 0;
+#ifndef CONFIG_DAVINCI_BLK_DEV_CF
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ palm_bk3710_hwif->speedproc = &palm_bk3710_hostdma;
+ /* Just put this for using the ide-dma.c init code */
+ palm_bk3710_dummydata.extra = 0;
+ palm_bk3710_hwif->cds = &palm_bk3710_dummydata;
+
+ /* Setup up the memory map base for this instance of hwif */
+ palm_bk3710_hwif->mmio = 0;
+ palm_bk3710_hwif->ide_dma_check = palm_bk3710_checkdma;
+ palm_bk3710_hwif->ultra_mask = 0x1f; /* Ultra DMA Mode 4 Max
+ (input clk 99MHz) */
+ palm_bk3710_hwif->mwdma_mask = 0x7;
+ palm_bk3710_hwif->swdma_mask = 0;
+ palm_bk3710_hwif->dma_command =
+ IO_ADDRESS(IDE_PALM_REG_MMAP_BASE);
+ palm_bk3710_hwif->dma_status =
+ IO_ADDRESS(IDE_PALM_REG_MMAP_BASE) + 2;
+ palm_bk3710_hwif->dma_prdtable =
+ IO_ADDRESS(IDE_PALM_REG_MMAP_BASE) + 4;
+ palm_bk3710_hwif->drives[0].autodma = 1;
+ palm_bk3710_hwif->drives[1].autodma = 1;
+ ide_setup_dma(palm_bk3710_hwif,
+ IO_ADDRESS(IDE_PALM_REG_MMAP_BASE), 8);
+ palm_bk3710_checkdma (&palm_bk3710_hwif->drives[0]);
+ palm_bk3710_checkdma (&palm_bk3710_hwif->drives[1]);
+#endif
+#endif
+ ret = 0;
+ } else {
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+/*
+ *
+ * palm_bk3710_chipinit () : Configures the Palm Chip Controller in the
+ * desired default operating mode
+ *
+ ******************************************************************************/
+int palm_bk3710_chipinit(void)
+{
+ /* enable the reset_en of ATA controller so that when ata signals are brought
+ * out , by writing into device config. at that time por_n signal should not be
+ * 'Z' and have a stable value.
+ */
+ palm_bk3710_base->config.miscctl = 0x0300;
+
+ /* wait for some time and deassert the reset of ATA Device. */
+ mdelay (100);
+
+ /* Deassert the Reset */
+ palm_bk3710_base->config.miscctl = 0x0200;
+
+ /* Program the IDETIMP Register Value based on the following assumptions
+ *
+ * (ATA_IDETIMP_IDEEN ,ENABLE ) |
+ * (ATA_IDETIMP_SLVTIMEN , DISABLE) |
+ * (ATA_IDETIMP_RDYSMPL , 70NS) |
+ * (ATA_IDETIMP_RDYRCVRY , 50NS) |
+ * (ATA_IDETIMP_DMAFTIM1 , PIOCOMP) |
+ * (ATA_IDETIMP_PREPOST1 , DISABLE) |
+ * (ATA_IDETIMP_RDYSEN1 , DISABLE) |
+ * (ATA_IDETIMP_PIOFTIM1 , DISABLE) |
+ * (ATA_IDETIMP_DMAFTIM0 , PIOCOMP) |
+ * (ATA_IDETIMP_PREPOST0 , DISABLE) |
+ * (ATA_IDETIMP_RDYSEN0 , DISABLE) |
+ * (ATA_IDETIMP_PIOFTIM0 , DISABLE)
+ */
+
+ palm_bk3710_base->config.idetimp = 0xb388;
+
+ /* Configure SIDETIM Register
+ * (ATA_SIDETIM_RDYSMPS1 ,120NS ) |
+ * (ATA_SIDETIM_RDYRCYS1 ,120NS )
+ */
+ palm_bk3710_base->config.sidetim = 0;
+
+ /* UDMACTL Ultra-ATA DMA Control
+ * (ATA_UDMACTL_UDMAP1 , 0 ) |
+ * (ATA_UDMACTL_UDMAP0 , 0 )
+ *
+ */
+ palm_bk3710_base->config.udmactl = 0;
+
+ /* MISCCTL Miscellaneous Conrol Register
+ * (ATA_MISCCTL_RSTMODEP , 1) |
+ * (ATA_MISCCTL_RESETP , 0) |
+ * (ATA_MISCCTL_TIMORIDE , 1)
+ */
+ palm_bk3710_base->config.miscctl = 0x201;
+
+ /* IORDYTMP IORDY Timer for Primary Register
+ * (ATA_IORDYTMP_IORDYTMP , 0xffff )
+ */
+
+ palm_bk3710_base->config.iordytmp = 0xffff;
+
+ /*Configure BMISP Register
+ * (ATA_BMISP_DMAEN1 , DISABLE ) |
+ * (ATA_BMISP_DMAEN0 , DISABLE ) |
+ * (ATA_BMISP_IORDYINT , CLEAR) |
+ * (ATA_BMISP_INTRSTAT , CLEAR) |
+ * (ATA_BMISP_DMAERROR , CLEAR)
+ */
+
+ palm_bk3710_base->dmaengine.bmisp = 0;
+
+ palm_bk3710_setpiomode(NULL, 0, 0, 0);
+ palm_bk3710_setpiomode(NULL, 1, 0, 0);
+
+ return 1;
+}
+
+
+module_init(palm_bk3710_init);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/ide/davinci/palm_bk3710.h b/drivers/ide/davinci/palm_bk3710.h
new file mode 100644
index 0000000..995c45b
--- /dev/null
+++ b/drivers/ide/davinci/palm_bk3710.h
@@ -0,0 +1,131 @@
+/*
+ * linux/drivers/ide/davinci/palm_bk3710.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ * DAVINCI Virtual memory definitions
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef PALM_BK3710_H
+#define PALM_BK3710_H
+
+#include <asm/arch/hardware.h>
+
+/*
+ *
+ * PalmChip 3710 IDE Controller Driver Definitions
+ *
+ */
+
+/*
+ *
+ * PalmChip 3710 IDE Controller config Definitions
+ *
+ */
+
+#define IDE_PALM_FREQ 76 /* Palm Chip operating freq (MHZ) */
+#define IDE_PALM_CLK ((3000000/clk_get_rate (ideclkp)) - 1) /* In ns */
+#define IDE_PALM_REG_MMAP_BASE DAVINCI_CFC_ATA_BASE /* Register Memory map address */
+#define IDE_PALM_ATA_PRI_REG_OFFSET 0x1F0 /**< Offset of the primary interface
+registers */
+#define IDE_PALM_ATA_PRI_CTL_OFFSET 0x3F6 /**< Primary Control Offset */
+
+/*
+ *
+ * PalmChip 3710 IDE Controller PIO cycle timing structure Definition
+ */
+typedef struct {
+ unsigned int activetime; /* Active Time */
+ unsigned int cycletime; /* Cycle Time */
+} palm_bk3710_piotiming;
+
+/*
+ *
+ * PalmChip 3710 IDE Controller DMA cycle timing structure Definition
+ */
+typedef struct {
+ unsigned int activetime; /* Active Time */
+ unsigned int recoverytime; /* Recovery Time */
+ unsigned int cycletime; /* Cycle Time */
+} palm_bk3710_dmatiming;
+
+/*
+ *
+ * PalmChip 3710 IDE Controller UDMA timing structure Definition
+ */
+typedef struct {
+ unsigned int envtime; /* Envelope Time */
+ unsigned int rptime; /* Ready to pause time */
+ unsigned int cycletime; /* Cycle Time */
+} palm_bk3710_udmatiming;
+
+/**************************************************************************\
+* Register Overlay Structure for DmaEngine
+\**************************************************************************/
+typedef struct {
+ unsigned short bmpcp;
+ unsigned short bmisp;
+ unsigned int bmidtp;
+ unsigned short bmics;
+ unsigned short bmiss;
+ unsigned int bmidtps;
+} palm_bk3710_dmaengineregs;
+
+/**************************************************************************\
+* Register Overlay Structure for Config
+\**************************************************************************/
+typedef struct {
+ unsigned short idetimp __attribute__ ((packed));
+ unsigned short idetims __attribute__ ((packed));
+ unsigned char sidetim;
+ unsigned short slewctl __attribute__ ((packed));
+ unsigned char idestatus;
+ unsigned short udmactl __attribute__ ((packed));
+ unsigned short udmatim __attribute__ ((packed));
+ unsigned char rsvd0[4];
+ unsigned int miscctl __attribute__ ((packed));
+ unsigned int regstb __attribute__ ((packed));
+ unsigned int regrcvr __attribute__ ((packed));
+ unsigned int datstb __attribute__ ((packed));
+ unsigned int datrcvr __attribute__ ((packed));
+ unsigned int dmastb __attribute__ ((packed));
+ unsigned int dmarcvr __attribute__ ((packed));
+ unsigned int udmastb __attribute__ ((packed));
+ unsigned int udmatrp __attribute__ ((packed));
+ unsigned int udmaenv __attribute__ ((packed));
+ unsigned int iordytmp __attribute__ ((packed));
+ unsigned int iordytms __attribute__ ((packed));
+} palm_bk3710_ideconfigregs;
+
+/**************************************************************************\
+* Register Overlay Structure
+\**************************************************************************/
+typedef struct {
+ palm_bk3710_dmaengineregs dmaengine;
+ unsigned char rsvd0[48];
+ palm_bk3710_ideconfigregs config;
+} palm_bk3710_ideregs;
+
+#endif /* DDC_BK3710_H */
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index fc1d8ae..278d713 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -69,6 +69,7 @@
case ide_au1xxx: name = "au1xxx"; break;
case ide_etrax100: name = "etrax100"; break;
case ide_acorn: name = "acorn"; break;
+ case ide_palm3710: name = "palm3710"; break;
default: name = "(unknown)"; break;
}
len = sprintf(page, "%s\n", name);
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index c374a9b..172df23 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -372,6 +372,25 @@
Say Y here if you want to test video apps or debug V4L devices.
In doubt, say N.
+config VIDEO_TVP5146
+ tristate "TVP5146 video decoder"
+ depends on I2C && ARCH_DAVINCI
+ help
+ Support for I2C bus based TVP5146 configuration.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tvp5146.
+
+config VIDEO_DAVINCI
+ tristate "Davinci Video Capture"
+ depends on VIDEO_DEV && VIDEO_TVP5146 && ARCH_DAVINCI
+ select VIDEO_BUF
+ help
+ Support for Davinci based frame grabber through CCDC.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
+
source "drivers/media/video/bt8xx/Kconfig"
config VIDEO_SAA6588
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index cbf9812..cabb25f 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -11,6 +11,8 @@
msp3400-objs := msp3400-driver.o msp3400-kthreads.o
+davinci-vpfe-objs := ccdc_davinci.o davinci_vpfe.o
+
obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \
v4l2-int-device.o
@@ -120,6 +122,9 @@
obj-$(CONFIG_USB_VICAM) += usbvideo/
obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
+obj-$(CONFIG_VIDEO_DAVINCI) += davinci-vpfe.o
+obj-$(CONFIG_VIDEO_TVP5146) += tvp5146.o
+
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/ccdc_davinci.c b/drivers/media/video/ccdc_davinci.c
new file mode 100644
index 0000000..d3cd333
--- /dev/null
+++ b/drivers/media/video/ccdc_davinci.c
@@ -0,0 +1,124 @@
+/*
+ *
+ *
+ * Copyright (C) 2006 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/* ccdc_davinci.c */
+
+#include <media/ccdc_davinci.h>
+#define debug_print(x...) //printk(x)
+void ccdc_reset()
+{
+ int i;
+ /* disable CCDC */
+ ccdc_enable(0);
+ /* set all registers to default value */
+ for (i = 0; i <= 0x94; i += 4) {
+ regw(0, i);
+ }
+ regw(0, PCR);
+ regw(0, SYN_MODE);
+ regw(0, HD_VD_WID);
+ regw(0, PIX_LINES);
+ regw(0, HORZ_INFO);
+ regw(0, VERT_START);
+ regw(0, VERT_LINES);
+ regw(0xffff00ff, CULLING);
+ regw(0, HSIZE_OFF);
+ regw(0, SDOFST);
+ regw(0, SDR_ADDR);
+ regw(0, VDINT);
+ regw(0, REC656IF);
+ regw(0, CCDCFG);
+ regw(0, FMTCFG);
+ regw(0, VP_OUT);
+}
+
+void ccdc_setwin(ccdc_params_ycbcr * params)
+{
+ int horz_start, horz_nr_pixels;
+ int vert_start, vert_nr_lines;
+
+ /* configure horizonal and vertical starts and sizes */
+ horz_start = params->win.left << 1;
+ horz_nr_pixels = (params->win.width <<1) - 1;
+ regw((horz_start << 16) | horz_nr_pixels, HORZ_INFO);
+
+ vert_start = params->win.top;
+
+ if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ vert_nr_lines = (params->win.height >> 1) - 1;
+ vert_start >>= 1;
+ } else {
+ vert_nr_lines = params->win.height - 1;
+ }
+ regw((vert_start << 16) | vert_start, VERT_START);
+ regw(vert_nr_lines, VERT_LINES);
+}
+
+void ccdc_config_ycbcr(ccdc_params_ycbcr * params)
+{
+ u32 syn_mode;
+
+ /* first reset the CCDC */
+ /* all registers have default values after reset */
+ /* This is important since we assume default values to be set in */
+ /* a lot of registers that we didn't touch */
+ ccdc_reset();
+
+ /* configure pixel format */
+ syn_mode = (params->pix_fmt & 0x3) << 12;
+
+ /* configure video frame format */
+ syn_mode |= (params->frm_fmt & 0x1) << 7;
+
+ /* setup BT.656 sync mode */
+ if (params->bt656_enable) {
+ regw(3, REC656IF);
+
+ /* configure the FID, VD, HD pin polarity */
+ /* fld,hd pol positive, vd negative, 8-bit pack mode */
+ syn_mode |= 0x00000F04;
+ } else {/* y/c external sync mode */
+ syn_mode |= ((params->fid_pol & 0x1) << 4);
+ syn_mode |= ((params->hd_pol & 0x1) << 3);
+ syn_mode |= ((params->vd_pol & 0x1) << 2);
+ }
+
+ /* configure video window */
+ ccdc_setwin(params);
+
+ /* configure the order of y cb cr in SD-RAM */
+ regw((params->pix_order << 11) | 0x8000, CCDCFG);
+
+ /* configure the horizontal line offset */
+ /* this is done by rounding up width to a multiple of 16 pixels */
+ /* and multiply by two to account for y:cb:cr 4:2:2 data */
+ regw(((params->win.width * 2) + 31) & 0xffffffe0, HSIZE_OFF);
+
+ /* configure the memory line offset */
+ if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
+ /* two fields are interleaved in memory */
+ regw(0x00000249, SDOFST);
+ }
+ /* enable output to SDRAM */
+ syn_mode |= (0x1 << 17);
+ /* enable internal timing generator */
+ syn_mode |= (0x1 << 16);
+
+ regw(syn_mode, SYN_MODE);
+}
diff --git a/drivers/media/video/davinci_vpfe.c b/drivers/media/video/davinci_vpfe.c
new file mode 100644
index 0000000..1128eb5
--- /dev/null
+++ b/drivers/media/video/davinci_vpfe.c
@@ -0,0 +1,1136 @@
+/*
+ *
+ *
+ * Copyright (C) 2006 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/* davinci_vpfe.c */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kdev_t.h>
+#include <linux/string.h>
+#include <linux/videodev.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+
+#include <media/davinci_vpfe.h>
+
+#define debug_print(x...) //printk(x)
+
+MODULE_LICENSE("GPL");
+
+static struct v4l2_rect ntsc_bounds = VPFE_WIN_NTSC;
+static struct v4l2_rect pal_bounds = VPFE_WIN_PAL;
+static struct v4l2_fract ntsc_aspect = VPFE_PIXELASPECT_NTSC;
+static struct v4l2_fract pal_aspect = VPFE_PIXELASPECT_PAL;
+static struct v4l2_rect ntscsp_bounds = VPFE_WIN_NTSC_SP;
+static struct v4l2_rect palsp_bounds = VPFE_WIN_PAL_SP;
+static struct v4l2_fract sp_aspect = VPFE_PIXELASPECT_NTSC_SP;
+
+static vpfe_obj vpfe_device = { /* the default format is NTSC */
+ .usrs = 0,
+ .io_usrs = 0,
+ .std = VPFE_STD_AUTO,
+ .vwin = VPFE_WIN_PAL,
+ .bounds = VPFE_WIN_PAL,
+ .pixelaspect = VPFE_PIXELASPECT_NTSC,
+ .pixelfmt = V4L2_PIX_FMT_UYVY,
+ .field = V4L2_FIELD_INTERLACED,
+ .numbuffers = VPFE_DEFNUM_FBUFS,
+ .ccdc_params = {
+ .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
+ .frm_fmt = CCDC_FRMFMT_INTERLACED,
+ .win = VPFE_WIN_PAL,
+ .fid_pol = CCDC_PINPOL_POSITIVE,
+ .vd_pol = CCDC_PINPOL_POSITIVE,
+ .hd_pol = CCDC_PINPOL_POSITIVE,
+ .bt656_enable = TRUE,
+ .pix_order = CCDC_PIXORDER_CBYCRY,
+ .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
+ },
+ .tvp5146_params = {
+ .mode = TVP5146_MODE_AUTO,
+ .amuxmode = TVP5146_AMUX_COMPOSITE,
+ .enablebt656sync = TRUE
+ },
+ .irqlock = SPIN_LOCK_UNLOCKED
+};
+
+struct v4l2_capability vpfe_drvcap = {
+ .driver = "vpfe driver",
+ .card = "DaVinci EVM",
+ .bus_info = "Platform",
+ .version = VPFE_VERSION_CODE,
+ .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING
+};
+
+static int sense_std(v4l2_std_id* std_id)
+{
+ v4l2_std_id id = 0;
+ tvp5146_mode mode;
+ int ret;
+ ret = tvp5146_ctrl(TVP5146_GET_STD, &mode);
+ if(ret < 0)
+ return ret;
+ switch (mode & 0x7) {
+ case TVP5146_MODE_NTSC:
+ id = V4L2_STD_NTSC;
+ break;
+ case TVP5146_MODE_PAL:
+ id = V4L2_STD_PAL;
+ break;
+ case TVP5146_MODE_PAL_M:
+ id = V4L2_STD_PAL_M;
+ break;
+ case TVP5146_MODE_PAL_CN:
+ id = V4L2_STD_PAL_N;
+ break;
+ case TVP5146_MODE_SECAM:
+ id = V4L2_STD_SECAM;
+ break;
+ case TVP5146_MODE_PAL_60:
+ id = V4L2_STD_PAL_60;
+ break;
+ }
+ if (mode & 0x8) { /* square pixel mode */
+ id <<= 32;
+ }
+ if (mode == TVP5146_MODE_AUTO) {
+ id = VPFE_STD_AUTO; /* auto-detection for all other modes */
+ } else if (mode == TVP5146_MODE_AUTO_SQP) {
+ id = VPFE_STD_AUTO_SQP;
+ }
+ if(id == 0)
+ return -EINVAL;
+ *std_id = id;
+ return 0;
+}
+
+static irqreturn_t vpfe_isr(int irq, void *dev_id)
+{
+ vpfe_obj *vpfe = &vpfe_device;
+ int fid;
+
+ /* check which field we are in hardware */
+ fid = ccdc_getfid();
+ vpfe->field_id ^= 1; /* switch the software maintained field id */
+ debug_print(KERN_INFO "field id = %x:%x.\n", fid, vpfe->field_id);
+ if (fid == vpfe->field_id) { /* we are in-sync here, continue */
+ if (fid == 0) {
+ /* One frame is just being captured. If the next frame
+ is available, release the current frame and move on */
+ if (vpfe->curFrm != vpfe->nextFrm) {
+ vpfe->curFrm->state = STATE_DONE;
+ wake_up_interruptible(&vpfe->curFrm->done);
+ vpfe->curFrm = vpfe->nextFrm;
+ }
+ /* based on whether the two fields are stored interleavely */
+ /* or separately in memory, reconfigure the CCDC memory address */
+ if (vpfe->field == V4L2_FIELD_SEQ_TB) {
+ u32 addr =
+ vpfe->curFrm->boff + vpfe->field_offset;
+ ccdc_setfbaddr((unsigned long)addr);
+ }
+ } else if (fid == 1) {
+ /* if one field is just being captured */
+ /* configure the next frame */
+ /* get the next frame from the empty queue */
+ /* if no frame is available, hold on to the current buffer */
+ if (!list_empty(&vpfe->dma_queue)
+ && vpfe->curFrm == vpfe->nextFrm) {
+ vpfe->nextFrm = list_entry(vpfe->dma_queue.next,
+ struct videobuf_buffer, queue);
+ list_del(&vpfe->nextFrm->queue);
+ vpfe->nextFrm->state = STATE_ACTIVE;
+ ccdc_setfbaddr(
+ (unsigned long)vpfe->nextFrm->boff);
+ }
+ if (vpfe->mode_changed) {
+ ccdc_setwin(&vpfe->ccdc_params);
+ /* update the field offset */
+ vpfe->field_offset =
+ (vpfe->vwin.height - 2) * vpfe->vwin.width;
+ vpfe->mode_changed = FALSE;
+ }
+ }
+ } else if (fid == 0) {
+ /* recover from any hardware out-of-sync due to */
+ /* possible switch of video source */
+ /* for fid == 0, sync up the two fids */
+ /* for fid == 1, no action, one bad frame will */
+ /* go out, but it is not a big deal */
+ vpfe->field_id = fid;
+ }
+ debug_print(KERN_INFO "interrupt returned.\n");
+ return IRQ_RETVAL(1);
+}
+
+/* this is the callback function called from videobuf_qbuf() function */
+/* the buffer is prepared and queued into the dma queue */
+static int buffer_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ vpfe_obj *vpfe = &vpfe_device;
+
+
+ if (vb->state == STATE_NEEDS_INIT) {
+ vb->width = vpfe->vwin.width;
+ vb->height = vpfe->vwin.height;
+ vb->size = VPFE_MAX_FBUF_SIZE;
+ vb->field = field;
+ }
+ vb->state = STATE_PREPARED;
+
+ return 0;
+
+}
+static void
+buffer_config(struct videobuf_queue *q, unsigned int count)
+{
+ vpfe_obj *vpfe = &vpfe_device;
+ int i;
+ for(i = 0; i < count; i++) {
+ q->bufs[i]->boff = virt_to_phys(vpfe->fbuffers[i]);
+ debug_print(KERN_INFO "buffer address: %x\n", q->bufs[i]->boff);
+ }
+}
+
+static int
+buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+ vpfe_obj *vpfe = &vpfe_device;
+ int i;
+ *size = VPFE_MAX_FBUF_SIZE;
+
+
+ for (i = VPFE_DEFNUM_FBUFS; i < *count; i++) {
+ u32 size = PAGE_SIZE << VPFE_MAX_FBUF_ORDER;
+ void *mem = (void *)__get_free_pages(GFP_KERNEL |GFP_DMA,
+ VPFE_MAX_FBUF_ORDER);
+ if (mem) {
+ unsigned long adr = (unsigned long)mem;
+ while (size > 0) {
+ /* make sure the frame buffers are never
+ swapped out of memory */
+ SetPageReserved(virt_to_page(adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ vpfe->fbuffers[i] = mem;
+ } else {
+ break;
+ }
+ }
+ *count = vpfe->numbuffers = i;
+
+ return 0;
+}
+
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+ vpfe_obj *vpfe = &vpfe_device;
+ /* add the buffer to the DMA queue */
+ list_add_tail(&vb->queue, &vpfe->dma_queue);
+ vb->state = STATE_QUEUED;
+}
+
+static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+ /* free the buffer if it is not one of the 3 allocated at initializaiton time */
+ if(vb->i < vpfe_device.numbuffers
+ && vb->i >= VPFE_DEFNUM_FBUFS
+ && vpfe_device.fbuffers[vb->i]){
+ free_pages((unsigned long)vpfe_device.fbuffers[vb->i],
+ VPFE_MAX_FBUF_ORDER);
+ vpfe_device.fbuffers[vb->i] = NULL;
+ }
+}
+
+
+static struct videobuf_queue_ops video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+ .buf_config = buffer_config,
+};
+
+
+
+
+static int vpfe_doioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ vpfe_obj *vpfe = &vpfe_device;
+ vpfe_fh *fh = file->private_data;
+ int ret = 0;
+ switch (cmd) {
+ case VIDIOC_S_CTRL:
+ case VIDIOC_S_FMT:
+ case VIDIOC_S_STD:
+ case VIDIOC_S_CROP:
+ ret = v4l2_prio_check(&vpfe->prio, &fh->prio);
+ if (0 != ret) {
+ return ret;
+ }
+ break;
+ }
+
+ switch (cmd) {
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap =
+ (struct v4l2_capability *)arg;
+ memset(cap, 0, sizeof(*cap));
+ *cap = vpfe_drvcap;
+ break;
+ }
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *)arg;
+ u32 index = fmt->index;
+ memset(fmt, 0, sizeof(*fmt));
+ fmt->index = index;
+ if (index == 0) {
+ /* only yuv4:2:2 format is supported at this point */
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strcpy(fmt->description,
+ "YCbCr4:2:2 Interleaved UYUV");
+ fmt->pixelformat = V4L2_PIX_FMT_UYVY;
+ } else if (index == 1) {
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strcpy(fmt->description,
+ "YCbCr4:2:2 Interleaved YUYV");
+ fmt->pixelformat = V4L2_PIX_FMT_YUYV;
+ } else {
+ ret = -EINVAL;
+ }
+ break;
+ }
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *fmt = (struct v4l2_format *)arg;
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ ret = -EINVAL;
+ } else {
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+ down_interruptible(&vpfe->lock);
+ pixfmt->width = vpfe->vwin.width;
+ pixfmt->height = vpfe->vwin.height;
+ pixfmt->field = vpfe->field;
+ pixfmt->pixelformat = vpfe->pixelfmt;
+ pixfmt->bytesperline = pixfmt->width * 2;
+ pixfmt->sizeimage =
+ pixfmt->bytesperline * pixfmt->height;
+ pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ up(&vpfe->lock);
+ }
+ break;
+ }
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *fmt = (struct v4l2_format *)arg;
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+ ccdc_params_ycbcr *params = &vpfe->ccdc_params;
+ if (vpfe->started) { /* make sure streaming is not started */
+ ret = -EBUSY;
+ break;
+ }
+
+ down_interruptible(&vpfe->lock);
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ ret = -EINVAL;
+ up(&vpfe->lock);
+ break;
+ }
+ if ((pixfmt->width + vpfe->vwin.left <=
+ vpfe->bounds.width)
+ & (pixfmt->height + vpfe->vwin.top <=
+ vpfe->bounds.height)) {
+ /* this is the case when no scaling is supported */
+ /* crop window is directed modified */
+ vpfe->vwin.height = pixfmt->height;
+ vpfe->vwin.width = pixfmt->width;
+ params->win.width = pixfmt->width;
+ params->win.height = pixfmt->height;
+ } else {
+ ret = -EINVAL;
+ up(&vpfe->lock);
+ break;
+ }
+ /* setup the CCDC parameters accordingly */
+ if (pixfmt->pixelformat == V4L2_PIX_FMT_YUYV) {
+ params->pix_order = CCDC_PIXORDER_YCBYCR;
+ vpfe->pixelfmt = pixfmt->pixelformat;
+ } else if (pixfmt->pixelformat == V4L2_PIX_FMT_UYVY) {
+ params->pix_order = CCDC_PIXORDER_CBYCRY;
+ vpfe->pixelfmt = pixfmt->pixelformat;
+ } else {
+ ret = -EINVAL; /* not supported format */
+ up(&vpfe->lock);
+ break;
+ }
+ if (pixfmt->field == V4L2_FIELD_NONE
+ || pixfmt->field == V4L2_FIELD_INTERLACED) {
+ params->buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED;
+ vpfe->field = pixfmt->field;
+ } else if (pixfmt->field == V4L2_FIELD_SEQ_TB) {
+ params->buf_type = CCDC_BUFTYPE_FLD_SEPARATED;
+ vpfe->field = pixfmt->field;
+ } else {
+ ret = -EINVAL;
+ }
+ up(&vpfe->lock);
+ break;
+ }
+ case VIDIOC_TRY_FMT:
+ {
+ struct v4l2_format *fmt = (struct v4l2_format *)arg;
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ ret = -EINVAL;
+ } else {
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+ if (pixfmt->width > vpfe->bounds.width
+ || pixfmt->height > vpfe->bounds.height
+ || (pixfmt->pixelformat != V4L2_PIX_FMT_UYVY
+ && pixfmt->pixelformat !=
+ V4L2_PIX_FMT_YUYV)) {
+ ret = -EINVAL;
+ }
+ }
+ break;
+ }
+ case VIDIOC_G_STD:
+ {
+ v4l2_std_id *id = (v4l2_std_id *) arg;
+ *id = vpfe->std;
+ break;
+ }
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id id = *(v4l2_std_id *) arg;
+ tvp5146_mode mode = TVP5146_MODE_INV;
+ int sqp = 0;
+
+ if (vpfe->started) { /* make sure streaming is not started */
+ ret = -EBUSY;
+ break;
+ }
+ down_interruptible(&vpfe->lock);
+ if (id & V4L2_STD_625_50) {
+ vpfe->std = id;
+ vpfe->bounds = vpfe->vwin = pal_bounds;
+ vpfe->pixelaspect = pal_aspect;
+ vpfe->ccdc_params.win = pal_bounds;
+
+ } else if (id & V4L2_STD_525_60) {
+ vpfe->std = id;
+ vpfe->bounds = vpfe->vwin = ntsc_bounds;
+ vpfe->pixelaspect = ntsc_aspect;
+ vpfe->ccdc_params.win = ntsc_bounds;
+ } else if (id & VPFE_STD_625_50_SQP) {
+ vpfe->std = id;
+ vpfe->bounds = vpfe->vwin = palsp_bounds;
+ vpfe->pixelaspect = sp_aspect;
+ sqp = 1;
+ id >>= 32;
+ } else if (id & VPFE_STD_525_60_SQP) {
+ vpfe->std = id;
+ sqp = 1;
+ vpfe->std = id;
+ id >>= 32;
+ vpfe->bounds = vpfe->vwin = ntscsp_bounds;
+ vpfe->pixelaspect = sp_aspect;
+ vpfe->ccdc_params.win = ntscsp_bounds;
+ } else if (id & VPFE_STD_AUTO) {
+ mode = TVP5146_MODE_AUTO;
+ vpfe->bounds = vpfe->vwin = pal_bounds;
+ vpfe->pixelaspect = pal_aspect;
+ vpfe->ccdc_params.win = pal_bounds;
+ vpfe->std = id;
+ } else if (id & VPFE_STD_AUTO_SQP) {
+ vpfe->std = id;
+ vpfe->bounds = vpfe->vwin = palsp_bounds;
+ vpfe->pixelaspect = sp_aspect;
+ sqp = 1;
+ mode = TVP5146_MODE_AUTO_SQP;
+ vpfe->pixelaspect = sp_aspect;
+ } else {
+ ret = -EINVAL;
+ }
+ if (id == V4L2_STD_PAL_60) {
+ mode = TVP5146_MODE_PAL_60;
+ } else if (id == V4L2_STD_PAL_M) {
+ mode = TVP5146_MODE_PAL_M;
+ } else if (id == V4L2_STD_PAL_Nc
+ || id == V4L2_STD_PAL_N) {
+ mode = TVP5146_MODE_PAL_CN;
+ } else if (id & V4L2_STD_PAL) {
+ mode = TVP5146_MODE_PAL;
+ } else if (id & V4L2_STD_NTSC) {
+ mode = TVP5146_MODE_NTSC;
+ } else if (id & V4L2_STD_SECAM) {
+ mode = TVP5146_MODE_SECAM;
+ }
+ vpfe->tvp5146_params.mode = mode | (sqp << 3);
+ tvp5146_ctrl(TVP5146_CONFIG, &vpfe->tvp5146_params);
+
+ up(&vpfe->lock);
+ break;
+ }
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *std = (struct v4l2_standard *)arg;
+ u32 index = std->index;
+ memset(std, 0, sizeof(*std));
+ std->index = index;
+ if (index == 0) {
+ std->id = V4L2_STD_525_60;
+ strcpy(std->name, "SD-525line-30fps");
+ std->framelines = 525;
+ std->frameperiod.numerator = 1001;
+ std->frameperiod.denominator = 30000;
+ } else if (index == 1) {
+ std->id = V4L2_STD_625_50;
+ strcpy(std->name, "SD-625line-25fps");
+ std->framelines = 625;
+ std->frameperiod.numerator = 1;
+ std->frameperiod.denominator = 25;
+ } else if (index == 2) {
+ std->id = VPFE_STD_625_50_SQP;
+ strcpy(std->name,
+ "SD-625line-25fps square pixel");
+ std->framelines = 625;
+ std->frameperiod.numerator = 1;
+ std->frameperiod.denominator = 25;
+ } else if (index == 3) {
+ std->id = VPFE_STD_525_60_SQP;
+ strcpy(std->name,
+ "SD-525line-25fps square pixel");
+ std->framelines = 525;
+ std->frameperiod.numerator = 1001;
+ std->frameperiod.denominator = 30000;
+ } else if (index == 4) {
+ std->id = VPFE_STD_AUTO;
+ strcpy(std->name, "automatic detect");
+ std->framelines = 625;
+ std->frameperiod.numerator = 1;
+ std->frameperiod.denominator = 1;
+ } else if (index == 5) {
+ std->id = VPFE_STD_AUTO_SQP;
+ strcpy(std->name,
+ "automatic detect square pixel");
+ std->framelines = 625;
+ std->frameperiod.numerator = 1;
+ std->frameperiod.denominator = 1;
+ } else {
+ ret = -EINVAL;
+ }
+ break;
+ }
+ case VIDIOC_ENUMINPUT:
+ {
+ u32 index=0;
+ struct v4l2_input *input = (struct v4l2_input *)arg;
+ if (input->index > 1) /* only two inputs are available */
+ ret = -EINVAL;
+ index = input->index;
+ memset(input, 0, sizeof(*input));
+ input->index = index;
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ input->std = V4L2_STD_ALL;
+ if(input->index == 0){
+ sprintf(input->name, "COMPOSITE");
+ }else if(input->index == 1) {
+ sprintf(input->name, "S-VIDEO");
+ }
+ break;
+ }
+ case VIDIOC_G_INPUT:
+ {
+ int *index = (int *)arg;
+ *index = vpfe->tvp5146_params.amuxmode;
+ break;
+ }
+ case VIDIOC_S_INPUT:
+ {
+ int *index = (int *)arg;
+ if (*index > 1 || *index < 0) {
+ ret = -EINVAL;
+ }
+ vpfe->tvp5146_params.amuxmode = *index;
+ tvp5146_ctrl(TVP5146_SET_AMUXMODE, index);
+ break;
+ }
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *cropcap =
+ (struct v4l2_cropcap *)arg;
+ cropcap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ down_interruptible(&vpfe->lock);
+ cropcap->bounds = cropcap->defrect = vpfe->vwin;
+ cropcap->pixelaspect = vpfe->pixelaspect;
+ up(&vpfe->lock);
+ break;
+ }
+ case VIDIOC_G_PARM:
+ {
+ struct v4l2_streamparm *parm =
+ (struct v4l2_streamparm *)arg;
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ /* only capture is supported */
+ ret = -EINVAL;
+ } else {
+ struct v4l2_captureparm *capparm =
+ &parm->parm.capture;
+ memset(capparm, 0,
+ sizeof(struct v4l2_captureparm));
+ down_interruptible(&vpfe->lock);
+ if (vpfe->std & V4L2_STD_625_50) {
+ capparm->timeperframe.numerator = 1;
+ capparm->timeperframe.denominator = 25; /* PAL 25fps */
+ } else {
+ capparm->timeperframe.numerator = 1001;
+ capparm->timeperframe.denominator = 30000; /*NTSC 29.97fps */
+ }
+ capparm->readbuffers = vpfe->numbuffers;
+ up(&vpfe->lock);
+ }
+ break;
+ }
+ case VIDIOC_G_CTRL:
+ down_interruptible(&vpfe->lock);
+ tvp5146_ctrl(VIDIOC_G_CTRL, arg);
+ up(&vpfe->lock);
+ break;
+ case VIDIOC_S_CTRL:
+ down_interruptible(&vpfe->lock);
+ tvp5146_ctrl(VIDIOC_S_CTRL, arg);
+ up(&vpfe->lock);
+ break;
+ case VIDIOC_QUERYCTRL:
+ down_interruptible(&vpfe->lock);
+ tvp5146_ctrl(VIDIOC_QUERYCTRL, arg);
+ up(&vpfe->lock);
+ break;
+ case VIDIOC_G_CROP:
+ {
+ struct v4l2_crop *crop = arg;
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ ret = -EINVAL;
+ } else {
+ crop->c = vpfe->vwin;
+ }
+ break;
+ }
+ case VIDIOC_S_CROP:
+ {
+ struct v4l2_crop *crop = arg;
+ ccdc_params_ycbcr *params = &vpfe->ccdc_params;
+ if (vpfe->started) { /* make sure streaming is not started */
+ ret = -EBUSY;
+ break;
+ }
+ /*adjust the width to 16 pixel boundry */
+ crop->c.width = ((crop->c.width + 15 )/16 ) * 16;
+
+ /* make sure parameters are valid */
+ if (crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
+ && (crop->c.left + crop->c.width
+ <= vpfe->bounds.left + vpfe->bounds.width)
+ && (crop->c.top + crop->c.height
+ <= vpfe->bounds.top + vpfe->bounds.height)) {
+
+ down_interruptible(&vpfe->lock);
+ vpfe->vwin = crop->c;
+ params->win = vpfe->vwin;
+ up(&vpfe->lock);
+ } else {
+ ret = -EINVAL;
+ }
+ break;
+ }
+ case VIDIOC_QUERYSTD:
+ {
+ v4l2_std_id *id = (v4l2_std_id *) arg;
+ down_interruptible(&vpfe->lock);
+ ret = sense_std(id);
+ up(&vpfe->lock);
+ break;
+ }
+ case VIDIOC_G_PRIORITY:
+ {
+ enum v4l2_priority *p = arg;
+ *p = v4l2_prio_max(&vpfe->prio);
+ break;
+ }
+ case VIDIOC_S_PRIORITY:
+ {
+ enum v4l2_priority *p = arg;
+ ret = v4l2_prio_change(&vpfe->prio, &fh->prio, *p);
+ break;
+ }
+
+ case VIDIOC_REQBUFS:
+ if (vpfe->io_usrs != 0) {
+ ret = -EBUSY;
+ break;
+ }
+ down_interruptible(&vpfe->lock);
+ videobuf_queue_init(&vpfe->bufqueue, &video_qops, NULL,
+ &vpfe->irqlock, V4L2_BUF_TYPE_VIDEO_CAPTURE, vpfe->field,
+ sizeof(struct videobuf_buffer), fh);
+
+ videobuf_set_buftype(&vpfe->bufqueue, VIDEOBUF_BUF_LINEAR);
+
+ fh->io_allowed = TRUE;
+ vpfe->io_usrs = 1;
+ INIT_LIST_HEAD(&vpfe->dma_queue);
+ ret = videobuf_reqbufs(&vpfe->bufqueue, arg);
+ up(&vpfe->lock);
+ break;
+ case VIDIOC_QUERYBUF:
+ ret = videobuf_querybuf(&vpfe->bufqueue, arg);
+ break;
+ case VIDIOC_QBUF:
+ if (!fh->io_allowed)
+ ret = -EACCES;
+ else
+ ret = videobuf_qbuf(&vpfe->bufqueue, arg);
+ break;
+ case VIDIOC_DQBUF:
+ if (!fh->io_allowed)
+ ret = -EACCES;
+ else
+ ret = videobuf_dqbuf(&vpfe->bufqueue, arg, 0);
+ break;
+ case VIDIOC_STREAMON:
+ if (!fh->io_allowed) {
+ ret = -EACCES;
+ break;
+ }
+ if(vpfe->started){
+ ret = -EBUSY;
+ break;
+ }
+ ret = videobuf_streamon(&vpfe->bufqueue);
+ if(ret) break;
+
+ down_interruptible(&vpfe->lock);
+ /* get the current and next frame buffers */
+ /* we expect at least one buffer is in driver at this point */
+ /* if not, error is returned */
+ if (list_empty(&vpfe->dma_queue)) {
+ ret = -EIO;
+ break;
+ }
+ debug_print(KERN_INFO "cur frame %x.\n",
+ vpfe->dma_queue.next);
+ vpfe->nextFrm = vpfe->curFrm =
+ list_entry(vpfe->dma_queue.next,
+ struct videobuf_buffer, queue);
+ /* remove the buffer from the queue */
+ list_del(&vpfe->curFrm->queue);
+ vpfe->curFrm->state = STATE_ACTIVE;
+
+ /* sense the current video input standard */
+ tvp5146_ctrl(TVP5146_CONFIG, &vpfe->tvp5146_params);
+ /* configure the ccdc and resizer as needed */
+ /* start capture by enabling CCDC and resizer */
+ ccdc_config_ycbcr(&vpfe->ccdc_params);
+ /* setup the memory address for the frame buffer */
+ ccdc_setfbaddr(((unsigned long)(vpfe->curFrm->boff)));
+ /* enable CCDC */
+ vpfe->field_id = 0;
+ vpfe->started = TRUE;
+ vpfe->mode_changed = FALSE;
+ vpfe->field_offset =
+ (vpfe->vwin.height - 2) * vpfe->vwin.width;
+ ccdc_enable(TRUE);
+ up(&vpfe->lock);
+ debug_print(KERN_INFO "started video streaming.\n");
+ break;
+ case VIDIOC_STREAMOFF:
+ {
+ if (!fh->io_allowed) {
+ ret = -EACCES;
+ break;
+ }
+ if(!vpfe->started){
+ ret = -EINVAL;
+ break;
+ }
+ /* disable CCDC */
+ down_interruptible(&vpfe->lock);
+ ccdc_enable(FALSE);
+ vpfe->started = FALSE;
+ up(&vpfe->lock);
+ ret = videobuf_streamoff(&vpfe->bufqueue);
+ break;
+ }
+ case VPFE_CMD_CONFIG_CCDC:
+ {
+ /* this can be used directly and bypass the V4L2 APIs */
+ ccdc_params_ycbcr *params = &vpfe->ccdc_params;
+ if(vpfe->started){
+ /* only allowed if streaming is not started */
+ ret = -EBUSY;
+ break;
+ }
+ down_interruptible(&vpfe->lock);
+ /* make sure the other v4l2 related fields
+ have consistant settings */
+ *params = (*(ccdc_params_ycbcr *) arg);
+ vpfe->vwin = params->win;
+ if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
+ vpfe->field = V4L2_FIELD_INTERLACED;
+ } else if (params->buf_type ==
+ CCDC_BUFTYPE_FLD_SEPARATED) {
+ vpfe->field = V4L2_FIELD_SEQ_TB;
+ }
+ if (params->pix_order == CCDC_PIXORDER_YCBYCR) {
+ vpfe->pixelfmt = V4L2_PIX_FMT_YUYV;
+ } else if (params->pix_order == CCDC_PIXORDER_CBYCRY) {
+ vpfe->pixelfmt = V4L2_PIX_FMT_UYVY;
+ }
+ up(&vpfe->lock);
+ break;
+ }
+ case VPFE_CMD_CONFIG_TVP5146:
+ /* this can be used directly and bypass the V4L2 APIs */
+ {
+ /* the settings here must be consistant with that of the CCDC's,
+ driver does not check the consistancy */
+ tvp5146_params *params = (tvp5146_params *) arg;
+ v4l2_std_id std = 0;
+ if(vpfe->started){
+ /* only allowed if streaming is not started */
+ ret = -EBUSY;
+ break;
+ }
+ down_interruptible(&vpfe->lock);
+ /*make sure the other v4l2 related fields have consistant settings */
+ switch (params->mode & 0x7) {
+ case TVP5146_MODE_NTSC:
+ std = V4L2_STD_NTSC;
+ break;
+ case TVP5146_MODE_PAL:
+ std = V4L2_STD_PAL;
+ break;
+ case TVP5146_MODE_PAL_M:
+ std = V4L2_STD_PAL_M;
+ break;
+ case TVP5146_MODE_PAL_CN:
+ std = V4L2_STD_PAL_N;
+ break;
+ case TVP5146_MODE_SECAM:
+ std = V4L2_STD_SECAM;
+ break;
+ case TVP5146_MODE_PAL_60:
+ std = V4L2_STD_PAL_60;
+ break;
+ }
+
+ if (params->mode & 0x8) { /* square pixel mode */
+ std <<= 32;
+ }
+
+ if (params->mode == TVP5146_MODE_AUTO) { /* auto-detection modes */
+ std = VPFE_STD_AUTO;
+ } else if (params->mode == TVP5146_MODE_AUTO_SQP) {
+ std = VPFE_STD_AUTO_SQP;
+ }
+
+ if (std & V4L2_STD_625_50) {
+ vpfe->bounds = pal_bounds;
+ vpfe->pixelaspect = pal_aspect;
+ } else if (std & V4L2_STD_525_60) {
+ vpfe->bounds = ntsc_bounds;
+ vpfe->pixelaspect = ntsc_aspect;
+ } else if (std & VPFE_STD_625_50_SQP) {
+ vpfe->bounds = palsp_bounds;
+ vpfe->pixelaspect = sp_aspect;
+ } else if (std & VPFE_STD_525_60_SQP) {
+ vpfe->bounds = ntscsp_bounds;
+ vpfe->pixelaspect = sp_aspect;
+ }
+ vpfe->std = std;
+ tvp5146_ctrl(TVP5146_CONFIG, params);
+ vpfe->tvp5146_params = *params;
+ up(&vpfe->lock);
+ break;
+ }
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ } /* end switch(cmd) */
+ return ret;
+}
+
+static int vpfe_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret;
+ ret = video_usercopy(inode, file, cmd, arg, vpfe_doioctl);
+ if( cmd == VIDIOC_S_FMT || cmd == VIDIOC_TRY_FMT ){
+ ret = video_usercopy(inode, file, VIDIOC_G_FMT,
+ arg, vpfe_doioctl);
+ }
+ return ret;
+}
+
+static int vpfe_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return videobuf_mmap_mapper(&vpfe_device.bufqueue, vma);
+}
+
+static int vpfe_open(struct inode *inode, struct file *filep)
+{
+ int minor = iminor(inode);
+ vpfe_obj *vpfe = NULL;
+ vpfe_fh *fh = NULL;
+
+ debug_print(KERN_INFO "vpfe: open minor=%d\n", minor);
+
+ /* check to make sure the minor numbers match */
+ if (vpfe_device.video_dev && vpfe_device.video_dev->minor == minor) {
+ vpfe = &vpfe_device;
+ } else { /* device not found here */
+ return -ENODEV;
+ }
+
+ /* allocate per filehandle data */
+ if ((fh = kmalloc(sizeof(*fh), GFP_KERNEL)) == NULL) {
+ return -ENOMEM;
+ }
+ filep->private_data = fh;
+ fh->dev = vpfe;
+ fh->io_allowed = FALSE;
+ fh->prio = V4L2_PRIORITY_UNSET;
+ v4l2_prio_open(&vpfe->prio, &fh->prio);
+ vpfe->usrs++;
+
+ return 0;
+}
+
+static int vpfe_release(struct inode *inode, struct file *filep)
+{
+ vpfe_fh *fh = filep->private_data;
+ vpfe_obj *vpfe = fh->dev;
+
+ down_interruptible(&vpfe->lock);
+ if (fh->io_allowed) {
+ vpfe->io_usrs = 0;
+ ccdc_enable(FALSE);
+ vpfe->started = FALSE;
+ videobuf_queue_cancel(&vpfe->bufqueue);
+ vpfe->numbuffers = VPFE_DEFNUM_FBUFS;
+ }
+ vpfe->usrs--;
+ v4l2_prio_close(&vpfe->prio, &fh->prio);
+ filep->private_data = NULL;
+ kfree(fh);
+ up(&vpfe->lock);
+
+ return 0;
+}
+
+static struct file_operations vpfe_fops = {
+ .owner = THIS_MODULE,
+ .open = vpfe_open,
+ .release = vpfe_release,
+ .ioctl = vpfe_ioctl,
+ .mmap = vpfe_mmap
+};
+
+static struct video_device vpfe_video_template = {
+ .name = "vpfe",
+ .type = VID_TYPE_CAPTURE | VID_TYPE_CLIPPING | VID_TYPE_SCALES,
+ .hardware = 0,
+ .fops = &vpfe_fops,
+ .minor = -1,
+};
+
+static void vpfe_platform_release(struct device *device)
+{
+ /* This is called when the reference count goes to zero. */
+}
+
+static int __init vpfe_probe(struct device *device)
+{
+ struct video_device *vfd;
+ vpfe_obj *vpfe = &vpfe_device;
+
+ /* alloc video device */
+ if ((vfd = video_device_alloc()) == NULL) {
+ return -ENOMEM;
+ }
+ *vfd = vpfe_video_template;
+ vfd->dev = device;
+ vfd->release = video_device_release;
+ snprintf(vfd->name, sizeof(vfd->name), "DM644X_VPFE_DRIVER_V%d.%d.%d",
+ (VPFE_VERSION_CODE >> 16) & 0xff,
+ (VPFE_VERSION_CODE >> 8) & 0xff, (VPFE_VERSION_CODE) & 0xff);
+
+ vpfe->video_dev = vfd;
+ vpfe->usrs = 0;
+ vpfe->io_usrs = 0;
+ vpfe->started = FALSE;
+ vpfe->latest_only = TRUE;
+
+ v4l2_prio_init(&vpfe->prio);
+ init_MUTEX(&vpfe->lock);
+ /* register video device */
+ debug_print(KERN_INFO "trying to register vpfe device.\n");
+ debug_print(KERN_INFO "vpfe=%x,vpfe->video_dev=%x\n", (int)vpfe,
+ (int)&vpfe->video_dev);
+ if (video_register_device(vpfe->video_dev, VFL_TYPE_GRABBER, -1) < 0) {
+ video_device_release(vpfe->video_dev);
+ vpfe->video_dev = NULL;
+ return -1;
+ }
+
+ debug_print(KERN_INFO "DM644X vpfe: driver version V%d.%d.%d loaded\n",
+ (VPFE_VERSION_CODE >> 16) & 0xff,
+ (VPFE_VERSION_CODE >> 8) & 0xff,
+ (VPFE_VERSION_CODE) & 0xff);
+
+ debug_print(KERN_INFO "vpfe: registered device video%d\n",
+ vpfe->video_dev->minor & 0x1f);
+
+ /* all done */
+ return 0;
+}
+
+static int vpfe_remove(struct device *device)
+{
+ /* un-register device */
+ video_unregister_device(vpfe_device.video_dev);
+
+ return 0;
+}
+
+#ifdef NEW
+static struct platform_driver vpfe_driver = {
+ .driver = {
+ .name = "VPFE",
+ .owner = THIS_MODULE,
+ },
+ .probe = vpfe_probe,
+ .remove = vpfe_remove,
+};
+
+#else
+static struct device_driver vpfe_driver = {
+ .name = "vpfe",
+ .bus = &platform_bus_type,
+ .probe = vpfe_probe,
+ .remove = vpfe_remove,
+};
+#endif
+
+static struct platform_device _vpfe_device = {
+ .name = "vpfe",
+ .id = 1,
+ .dev = {
+ .release = vpfe_platform_release,
+ }
+};
+
+static int vpfe_init(void)
+{
+ int i = 0;
+ void *mem;
+ /* allocate memory at initialization time to guarentee availability */
+ for (i = 0; i < VPFE_DEFNUM_FBUFS; i++) {
+ mem = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA,
+ VPFE_MAX_FBUF_ORDER);
+ if (mem) {
+ unsigned long adr = (unsigned long)mem;
+ u32 size = PAGE_SIZE << VPFE_MAX_FBUF_ORDER;
+ while (size > 0) {
+ /* make sure the frame buffers
+ are never swapped out of memory */
+ SetPageReserved(virt_to_page(adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ vpfe_device.fbuffers[i] = (u8 *) mem;
+ debug_print(KERN_INFO "memory address %d\t%x\n", i,
+ mem);
+ } else {
+ while (--i >= 0) {
+ free_pages((unsigned long)vpfe_device.fbuffers[i],
+ VPFE_MAX_FBUF_ORDER);
+ }
+ debug_print(KERN_INFO
+ "frame buffer memory allocation failed.\n");
+ return -ENOMEM;
+ }
+ }
+ if (driver_register(&vpfe_driver) != 0) {
+ debug_print(KERN_INFO "driver registration failed\n");
+ return -1;
+ }
+ if (platform_device_register(&_vpfe_device) != 0) {
+ driver_unregister(&vpfe_driver);
+ debug_print(KERN_INFO "device registration failed\n");
+ return -1;
+ }
+
+ ccdc_reset();
+ tvp5146_ctrl(TVP5146_RESET, NULL);
+ /* configure the tvp5146 to default parameters */
+ tvp5146_ctrl(TVP5146_CONFIG, &vpfe_device.tvp5146_params);
+ /* setup interrupt handling */
+ request_irq(IRQ_VDINT0, vpfe_isr, SA_INTERRUPT,
+ "dm644xv4l2", (void *)&vpfe_device);
+
+ printk(KERN_INFO "DaVinci v4l2 capture driver V1.0 loaded\n");
+ return 0;
+}
+
+static void vpfe_cleanup(void)
+{
+ int i = vpfe_device.numbuffers;
+ platform_device_unregister(&_vpfe_device);
+ driver_unregister(&vpfe_driver);
+ /* disable interrupt */
+ free_irq(IRQ_VDINT0, &vpfe_device);
+
+ while (--i >= 0) {
+ free_pages((unsigned long)vpfe_device.fbuffers[i],
+ VPFE_MAX_FBUF_ORDER);
+ }
+ debug_print(KERN_INFO "vpfe: un-registered device video.\n");
+}
+
+module_init(vpfe_init);
+module_exit(vpfe_cleanup);
diff --git a/drivers/media/video/tvp5146.c b/drivers/media/video/tvp5146.c
new file mode 100644
index 0000000..2ba47eb
--- /dev/null
+++ b/drivers/media/video/tvp5146.c
@@ -0,0 +1,649 @@
+/*
+ *
+ *
+ * Copyright (C) 2006 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/* tvp5146.c */
+
+#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/delay.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <media/tvp5146.h>
+
+#define debug_print(x...) //printk(x)
+
+static struct i2c_client tvp5146_i2c_client;
+static struct i2c_driver tvp5146_i2c_driver;
+
+static int i2c_read_reg(struct i2c_client *client, u8 reg, u8 * val);
+static int i2c_write_reg(struct i2c_client *client, u8 reg, u8 val);
+
+static int configtvp5146(void *arg);
+static int clrtvp5146lostlock(void);
+static int enabletvp5146agc(int arg);
+static int getctrl(void *arg);
+static int gettvp5146status(void *arg);
+static int powerdowntvp5146(int powerdownenable);
+static int queryctrl(void *arg);
+static int resettvp5146(void);
+static int setctrl(void *arg);
+static int settvp5146amuxmode(int mode);
+static int settvp5146brightness(int arg);
+static int settvp5146contrast(int arg);
+static int settvp5146hue(int arg);
+static int settvp5146saturation(int arg);
+static int settvp5146std(int arg);
+static int setup656sync(int enable);
+
+/*
+ * ======== configtvp5146 ========
+ */
+static int configtvp5146(void *arg)
+{
+ tvp5146_params *tvp5146params = (tvp5146_params *) arg;
+ int ret = 0;
+
+ ret |= setup656sync(tvp5146params->enablebt656sync);
+ ret |= settvp5146amuxmode(tvp5146params->amuxmode);
+ ret |= settvp5146std(tvp5146params->mode);
+
+ return ret;
+}
+
+/*
+ * ======== clrtvp5146lostlock ========
+ */
+static int clrtvp5146lostlock(void)
+{
+ int ret = 0;
+ u8 clr = 1;
+ ret = i2c_write_reg(&tvp5146_i2c_client, 0x39, clr);
+ return ret;
+}
+
+/*
+ * ======== enabletvp5146agc ========
+ */
+static int enabletvp5146agc(int arg)
+{
+ int ret = 0;
+ int agc;
+ if (arg == TRUE) {
+ agc = 0xF;
+ } else {
+ agc = 0xC;
+ }
+ ret = i2c_write_reg(&tvp5146_i2c_client, 0x01, agc);
+ return ret;
+}
+
+/*
+ * ======== gettvpctrl ========
+ */
+static int getctrl(void *arg)
+{
+ struct v4l2_control *ctrl = arg;
+ int ret = 0;
+ u8 value;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ret = i2c_read_reg(&tvp5146_i2c_client, 0x09, &value);
+ ctrl->value = value;
+ break;
+ case V4L2_CID_CONTRAST:
+ ret = i2c_read_reg(&tvp5146_i2c_client, 0x0A, &value);
+ ctrl->value = value;
+ break;
+ case V4L2_CID_SATURATION:
+ ret = i2c_read_reg(&tvp5146_i2c_client, 0x0B, &value);
+ ctrl->value = value;
+ break;
+ case V4L2_CID_HUE:
+ ret = i2c_read_reg(&tvp5146_i2c_client, 0x0C, &value);
+ ctrl->value = value;
+ break;
+ case V4L2_CID_AUTOGAIN:
+ ret = i2c_read_reg(&tvp5146_i2c_client, 0x01, &value);
+ if ((value & 0x3) == 3) {
+ ctrl->value = TRUE;
+ } else {
+ ctrl->value = FALSE;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+/*
+ * ======== gettvp5146std ========
+ */
+static int gettvp5146std(tvp5146_mode * mode)
+{
+ int ret = 0;
+ u8 output1;
+ u8 std;
+ u8 lock_status;
+
+ ret |= i2c_read_reg(&tvp5146_i2c_client, 0x2, &std);
+ std &= 0x7;
+ if(std == TVP5146_MODE_AUTO){
+ ret |= i2c_read_reg(&tvp5146_i2c_client, 0x3F, &std);
+ }
+ std &= 0x7;
+ ret |= i2c_read_reg(&tvp5146_i2c_client, 0x33, &output1);
+ *mode = std | ((output1 & 0x80) >> 4); /* square pixel status */
+ ret |= i2c_read_reg(&tvp5146_i2c_client, 0x3A, &lock_status);
+ if ((lock_status & 0xe) != 0xe) {
+ /* not quite locked */
+ ret = -EAGAIN;
+ }
+
+ return ret;
+}
+
+/*
+ * ======== gettvp5146status ========
+ */
+static int gettvp5146status(void *arg)
+{
+ int ret = 0;
+ tvp5146_status *status = (tvp5146_status *) arg;
+ u8 agc, brightness, contrast, hue, saturation;
+ u8 status_byte;
+ u8 std;
+ u8 output1;
+
+ ret = i2c_read_reg(&tvp5146_i2c_client, 0x01, &agc);
+ if ((agc & 0x3) == 3) {
+ status->agc_enable = TRUE;
+ } else {
+ status->agc_enable = FALSE;
+ }
+ ret |= i2c_read_reg(&tvp5146_i2c_client, 0x09, &brightness);
+ status->brightness = brightness;
+
+ ret |= i2c_read_reg(&tvp5146_i2c_client, 0x0A, &contrast);
+ status->contrast = contrast;
+
+ ret |= i2c_read_reg(&tvp5146_i2c_client, 0x0B, &saturation);
+ status->saturation = saturation;
+
+ ret |= i2c_read_reg(&tvp5146_i2c_client, 0x0C, &hue);
+ status->hue = hue;
+
+ ret |= i2c_read_reg(&tvp5146_i2c_client, 0x3A, &status_byte);
+ status->field_rate = (status_byte & 0x20) ? 50 : 60;
+ status->lost_lock = (status_byte & 0x10) >> 4;
+ status->csubc_lock = (status_byte & 0x8) >> 3;
+ status->v_lock = (status_byte & 0x4) >> 2;
+ status->h_lock = (status_byte & 0x2) >> 1;
+
+ ret |= i2c_read_reg(&tvp5146_i2c_client, 0x3F, &std);
+ ret |= i2c_read_reg(&tvp5146_i2c_client, 0x33, &output1);
+ if (std | 0x80) { /* auto switch mode */
+ status->video_std = TVP5146_MODE_AUTO;
+ } else {
+ status->video_std = std;
+ }
+ status->video_std |= ((output1 & 0x80) >> 4); /* square pixel status */
+ return ret;
+}
+
+/*
+ * ======== powerdowntvp5146 ========
+ */
+static int powerdowntvp5146(int powerdownenable)
+{
+ u8 powerdownsettings = 0x01;
+
+ /*Put _tvp5146 in power down mode */
+ if (!powerdownenable) {
+ powerdownsettings = 0x00;
+ }
+ return i2c_write_reg(&tvp5146_i2c_client, 0x03, powerdownsettings);
+}
+
+/*
+ * ======== resettvp5146========
+ */
+static int resettvp5146(void)
+{
+ setup656sync(TRUE);
+ settvp5146amuxmode(TVP5146_AMUX_COMPOSITE);
+ return powerdowntvp5146(FALSE);
+}
+
+/*
+ * ======== queryctrl ========
+ */
+static int queryctrl(void *arg)
+{
+ struct v4l2_queryctrl *queryctrl = arg;
+ int ret = 0;
+ int id = queryctrl->id;
+
+ memset(queryctrl, 0, sizeof(*queryctrl));
+ queryctrl->id = id;
+ switch (id) {
+ case V4L2_CID_BRIGHTNESS:
+ strcpy(queryctrl->name, "BRIGHTNESS");
+ queryctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ queryctrl->minimum = 0;
+ queryctrl->maximum = 255;
+ queryctrl->step = 1;
+ queryctrl->default_value = 128;
+ break;
+ case V4L2_CID_CONTRAST:
+ strcpy(queryctrl->name, "CONTRAST");
+ queryctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ queryctrl->minimum = 0;
+ queryctrl->maximum = 255;
+ queryctrl->step = 1;
+ queryctrl->default_value = 128;
+ break;
+
+ case V4L2_CID_SATURATION:
+ strcpy(queryctrl->name, "SATURATION");
+ queryctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ queryctrl->minimum = 0;
+ queryctrl->maximum = 255;
+ queryctrl->step = 1;
+ queryctrl->default_value = 128;
+ break;
+ case V4L2_CID_HUE:
+ strcpy(queryctrl->name, "HUE");
+ queryctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ queryctrl->minimum = -128; /* -180 DEGREE */
+ queryctrl->maximum = 127; /* 180 DEGREE */
+ queryctrl->step = 1;
+ queryctrl->default_value = 0; /* 0 DEGREE */
+ break;
+
+ case V4L2_CID_AUTOGAIN:
+ strcpy(queryctrl->name, "Automatic Gain Control");
+ queryctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+ queryctrl->minimum = 0;
+ queryctrl->maximum = 1;
+ queryctrl->step = 1;
+ queryctrl->default_value = 1;
+ break;
+ default:
+ if (id < V4L2_CID_LASTP1)
+ queryctrl->flags = V4L2_CTRL_FLAG_DISABLED;
+ else
+ ret = -EINVAL;
+ break;
+ } /* end switch (id) */
+ return ret;
+}
+
+/*
+ * ======== setctrl ========
+ */
+static int setctrl(void *arg)
+{
+ struct v4l2_control *ctrl = arg;
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ret = settvp5146brightness(ctrl->value);
+ break;
+ case V4L2_CID_CONTRAST:
+ ret = settvp5146contrast(ctrl->value);
+ break;
+ case V4L2_CID_SATURATION:
+ ret = settvp5146saturation(ctrl->value);
+ break;
+ case V4L2_CID_HUE:
+ ret = settvp5146hue(ctrl->value);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ ret = enabletvp5146agc(ctrl->value);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+/*
+ * ======== settvp5146amuxmode ========
+ */
+static int settvp5146amuxmode(int arg)
+{
+ u8 input_sel;
+
+ if (arg == TVP5146_AMUX_COMPOSITE) { /* composite */
+ input_sel = 0x05;
+ } else if (arg == TVP5146_AMUX_SVIDEO) { /* s-video */
+ input_sel = 0x46;
+ } else {
+ return -EINVAL;
+ }
+ return i2c_write_reg(&tvp5146_i2c_client, 0x00, input_sel);
+}
+
+/*
+ * ======== settvp5146brightness ========
+ */
+static int settvp5146brightness(int arg)
+{
+ int ret = 0;
+ u8 brightness = (u8) arg;
+ ret = i2c_write_reg(&tvp5146_i2c_client, 0x09, brightness);
+ return ret;
+}
+
+/*
+* ======== settvp5146contrast ========
+*/
+static int settvp5146contrast(int arg)
+{
+ int ret = 0;
+ u8 contrast = (u8) arg;
+ ret = i2c_write_reg(&tvp5146_i2c_client, 0x0A, contrast);
+ return ret;
+}
+
+/*
+* ======== settvp5146hue ========
+*/
+static int settvp5146hue(int arg)
+{
+ int ret = 0;
+ u8 hue = (u8) arg;
+ ret = i2c_write_reg(&tvp5146_i2c_client, 0x0C, hue);
+ return ret;
+}
+
+static int settvp5146saturation(int arg)
+{
+ int ret = 0;
+ u8 saturation = (u8) arg;
+ ret = i2c_write_reg(&tvp5146_i2c_client, 0x0B, saturation);
+ return ret;
+}
+
+static int settvp5146std(int arg)
+{
+ int ret = 0;
+ u8 std = (u8) arg & 0x7; /* the 4th-bit is for squre pixel sampling */
+ u8 output1;
+
+ /* setup the sampling rate: 601 or square pixel */
+ debug_print(KERN_INFO "reading i2c registers.\n");
+ ret = i2c_read_reg(&tvp5146_i2c_client, 0x33, &output1);
+ output1 |= ((arg & 0x8) << 4);
+ ret = i2c_write_reg(&tvp5146_i2c_client, 0x33, output1);
+
+ /* setup the video standard */
+ ret |= i2c_write_reg(&tvp5146_i2c_client, 0x02, std);
+ /* if autoswitch mode, enable all modes for autoswitch */
+ if (std == TVP5146_MODE_AUTO) {
+ u8 mask = 0x3F; /* enable autoswitch for all standards */
+ ret = i2c_write_reg(&tvp5146_i2c_client, 0x04, mask);
+ }
+
+ return ret;
+}
+
+/*
+ * ======== setup656sync ========
+ */
+static int setup656sync(int enable)
+{
+ int output1, output2, output3, output4;
+ int output5, output6;
+ int ret = 0;
+
+ if (enable) {
+ output1 = 0x40;
+ output4 = 0xFF;
+ output6 = 0;
+ } else {
+ output1 = 0x43;
+ output4 = 0xAF;
+ output6 = 0x1E;
+ }
+
+ output2 = 0x11; /* enable clock, enable Y[9:0] */
+ output3 = 0x0;
+ output5 = 0x4;
+
+ ret |= i2c_write_reg(&tvp5146_i2c_client, 0x33, output1);
+ ret |= i2c_write_reg(&tvp5146_i2c_client, 0x34, output2);
+ ret |= i2c_write_reg(&tvp5146_i2c_client, 0x36, output4);
+ ret |= i2c_write_reg(&tvp5146_i2c_client, 0x08, output3);
+ ret |= i2c_write_reg(&tvp5146_i2c_client, 0x0e, output5);
+ ret |= i2c_write_reg(&tvp5146_i2c_client, 0x32, output6);
+ return ret;
+}
+
+/*
+ * ======== tvp5146_ctrl ========
+ */
+int tvp5146_ctrl(tvp5146_cmd cmd, void *arg)
+{
+ int ret = 0;
+ switch (cmd) {
+ case TVP5146_CONFIG:
+ ret = configtvp5146(arg);
+ break;
+ case TVP5146_RESET:
+ ret = resettvp5146();
+ break;
+ case TVP5146_POWERDOWN:
+ ret = powerdowntvp5146(*(int *)arg);
+ break;
+ case TVP5146_SET_AMUXMODE:
+ ret = settvp5146amuxmode(*(int *)arg);
+ break;
+ case TVP5146_SET_BRIGHTNESS:
+ ret = settvp5146brightness(*(int *)arg);
+ break;
+ case TVP5146_SET_CONTRAST:
+ ret = settvp5146contrast(*(int *)arg);
+ break;
+ case TVP5146_SET_HUE:
+ ret = settvp5146hue(*(int *)arg);
+ break;
+ case TVP5146_SET_SATURATION:
+ ret = settvp5146saturation(*(int *)arg);
+ break;
+ case TVP5146_SET_AGC:
+ ret = enabletvp5146agc(*(int *)arg);
+ break;
+ case TVP5146_SET_VIDEOSTD:
+ ret = settvp5146std(*(int *)arg);
+ break;
+ case TVP5146_CLR_LOSTLOCK:
+ ret = clrtvp5146lostlock();
+ break;
+ case TVP5146_GET_STATUS:
+ ret = gettvp5146status(arg);
+ break;
+ case TVP5146_GET_STD:
+ ret = gettvp5146std(arg);
+ break;
+ case VIDIOC_QUERYCTRL:
+ ret = queryctrl(arg);
+ break;
+ case VIDIOC_G_CTRL:
+ ret = getctrl(arg);
+ break;
+ case VIDIOC_S_CTRL:
+ ret = setctrl(arg);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int i2c_read_reg(struct i2c_client *client, u8 reg, u8 * val)
+{
+ int err = 0;
+
+ struct i2c_msg msg[1];
+ unsigned char data[1];
+
+ if (!client->adapter) {
+ err = -ENODEV;
+ } else {
+ msg->addr = client->addr;
+ msg->flags = 0;
+ msg->len = 1;
+ msg->buf = data;
+ data[0] = reg;
+ err = i2c_transfer(client->adapter, msg, 1);
+ if (err >= 0) {
+ msg->flags = I2C_M_RD;
+ err = i2c_transfer(client->adapter, msg, 1);
+ if (err >= 0) {
+ *val = data[0];
+ }
+ }
+ }
+ return err;
+}
+
+static int i2c_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+ int err = 0;
+
+ struct i2c_msg msg[1];
+ unsigned char data[2];
+
+ if (!client->adapter) {
+ err = -ENODEV;
+ } else {
+ msg->addr = client->addr;
+ msg->flags = 0;
+ msg->len = 2;
+ msg->buf = data;
+ data[0] = reg;
+ data[1] = val;
+ err = i2c_transfer(client->adapter, msg, 1);
+ }
+ debug_print(KERN_INFO " i2c data write \n");
+
+ return err;
+}
+
+static int _i2c_attach_client(struct i2c_client *client,
+ struct i2c_driver *driver,
+ struct i2c_adapter *adap, int addr)
+{
+ int err = 0;
+
+ if (client->adapter) {
+ err = -EBUSY; /* our client is already attached */
+ } else {
+ client->addr = addr;
+/* client->flags = I2C_CLIENT_ALLOW_USE; */
+ client->driver = driver;
+ client->adapter = adap;
+
+ err = i2c_attach_client(client);
+ if (err) {
+ client->adapter = NULL;
+ }
+ }
+ return err;
+}
+
+static int _i2c_detach_client(struct i2c_client *client)
+{
+ int err = 0;
+
+ if (!client->adapter) {
+ return -ENODEV; /* our client isn't attached */
+ } else {
+ err = i2c_detach_client(client);
+ client->adapter = NULL;
+ }
+ return err;
+}
+
+static int tvp5146_i2c_probe_adapter(struct i2c_adapter *adap)
+{
+ return _i2c_attach_client(&tvp5146_i2c_client, &tvp5146_i2c_driver,
+ adap, TVP5146_I2C_ADDR);
+}
+
+static struct i2c_driver tvp5146_i2c_driver = {
+ .driver = {
+ .name = "tvp5146",
+ },
+ .id = I2C_DRIVERID_TVP5150,
+
+ .attach_adapter = tvp5146_i2c_probe_adapter,
+ .detach_client = _i2c_detach_client,
+};
+
+static int tvp5146_i2c_init(void)
+{
+ int err;
+ struct i2c_driver *driver = &tvp5146_i2c_driver;
+
+/* driver->owner = THIS_MODULE; */
+/* strlcpy(driver->name, "TVP5146 Video Decoder I2C driver", */
+/* sizeof(driver->name)); */
+/* driver->id = I2C_DRIVERID_EXP0; */
+/* driver->flags = I2C_DF_NOTIFY; */
+/* driver->attach_adapter = tvp5146_i2c_probe_adapter; */
+/* driver->detach_client = _i2c_detach_client; */
+
+ err = i2c_add_driver(driver);
+ if (err) {
+ debug_print(KERN_ERR
+ "Failed to register TVP5146 I2C client.\n");
+ }
+ debug_print(KERN_INFO "tvp5146 driver registered.\n");
+ return err;
+}
+
+static void tvp5146_i2c_cleanup(void)
+{
+ struct i2c_driver *driver = &tvp5146_i2c_driver;
+
+ i2c_detach_client(&tvp5146_i2c_client);
+ i2c_del_driver(driver);
+ tvp5146_i2c_client.adapter = NULL;
+}
+
+module_init(tvp5146_i2c_init);
+module_exit(tvp5146_i2c_cleanup);
+
+EXPORT_SYMBOL(tvp5146_ctrl);
+MODULE_LICENSE("GPL");
+
+/**************************************************************************/
+/* End of file */
+/**************************************************************************/
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
index a32dfbe..1c83997 100644
--- a/drivers/media/video/video-buf.c
+++ b/drivers/media/video/video-buf.c
@@ -246,7 +246,8 @@
void *dev=q->dev;
MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
- BUG_ON(!dma->sglen);
+ if(q->buf_type == VIDEOBUF_BUF_FRAGMENTED)
+ BUG_ON(!dma->sglen);
if (!dma->bus_addr && q->ops->vb_dma_sync_sg)
q->ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages,
@@ -448,6 +449,9 @@
q->ops = ops;
q->priv_data = priv;
+ /* The default buffer type is fragmented */
+ q->buf_type = VIDEOBUF_BUF_FRAGMENTED;
+
videobuf_queue_pci(q);
mutex_init(&q->lock);
@@ -642,6 +646,10 @@
goto done;
}
+ if(q->buf_type == VIDEOBUF_BUF_LINEAR){
+ q->ops->buf_config(q, count);
+ }
+
req->count = count;
done:
@@ -1362,9 +1370,23 @@
map->start = vma->vm_start;
map->end = vma->vm_end;
map->q = q;
- vma->vm_ops = &videobuf_vm_ops;
- vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
- vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
+ if(q->buf_type == VIDEOBUF_BUF_LINEAR){
+#ifdef CONFIG_ARM
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#else
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#endif
+ if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ (vma->vm_end - vma->vm_start),
+ vma->vm_page_prot)){
+ return -EAGAIN;
+ }
+ vma->vm_flags |= VM_RESERVED | VM_IO;
+ } else {
+ vma->vm_ops = &videobuf_vm_ops;
+ vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+ vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
+ }
vma->vm_private_data = map;
dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n",
map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last);
@@ -1375,6 +1397,12 @@
return retval;
}
+int videobuf_set_buftype(struct videobuf_queue *q, enum videobuf_buf_type type)
+{
+ q->buf_type = type;
+ return 0;
+}
+
/* --------------------------------------------------------------------- */
EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
@@ -1418,6 +1446,8 @@
EXPORT_SYMBOL_GPL(videobuf_mmap_free);
EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);
+EXPORT_SYMBOL_GPL(videobuf_set_buftype);
+
/*
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 671b9a4..a2327ab 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -101,3 +101,11 @@
To compile this driver as a module, choose M here: the
module will be called tifm_sd.
+config MMC_DAVINCI
+ tristate "TI DAVINCI Multimedia Card Interface support"
+ depends on MMC
+ help
+ This selects the TI DAVINCI Multimedia card Interface.
+ If you have an DAVINCI board with a Multimedia Card slot,
+ say Y or M here. If unsure, say N.
+
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 6685f64..dc99bd6 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -15,4 +15,5 @@
obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_AT91) += at91_mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
+obj-$(CONFIG_MMC_DAVINCI) += davinci_mmc.o
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
new file mode 100644
index 0000000..5d8e79f
--- /dev/null
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -0,0 +1,1239 @@
+/*
+ * linux/drivers/mmc/davinci.c
+ *
+ * TI DaVinci MMC controller file
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ Modifications:
+ ver. 1.0: Oct 2005, Purushotam Kumar Initial version
+ ver 1.1: Nov 2005, Purushotam Kumar Solved bugs
+ ver 1.2: Jan 2066, Purushotam Kumar Added card remove insert support
+ -
+ *
+
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/blkdev.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/hardware.h>
+
+#include "davinci_mmc.h"
+#include <asm/arch/edma.h>
+
+/* FIXME: old defines from old mmc.h */
+/* #define MMC_RSP_NONE (0 << 0) */
+/* #define MMC_RSP_SHORT (1 << 0) */
+/* #define MMC_RSP_LONG (2 << 0) */
+/* #define MMC_RSP_MASK (3 << 0) */
+/* #define MMC_RSP_CRC (1 << 3) /\* expect valid crc *\/ */
+/* #define MMC_RSP_BUSY (1 << 4) /\* card may send busy *\/ */
+#define MMC_RSP_SHORT MMC_RSP_PRESENT
+#define MMC_RSP_LONG MMC_RSP_136
+#define MMC_RSP_MASK (MMC_RSP_PRESENT | MMC_RSP_136)
+
+extern void davinci_clean_channel(int ch_no);
+
+/* MMCSD Init clock in Hz in opendain mode */
+#define MMCSD_INIT_CLOCK 200000
+#define DRIVER_NAME "mmc0"
+#define MMCINT_INTERRUPT IRQ_MMCINT
+#define MMCSD_REGS_BASE_ADDR DAVINCI_MMC_SD_BASE
+#define TCINTEN (0x1<<20)
+
+/* This macro could not be defined to 0 (ZERO) or -ve value.
+ * This value is multiplied to "HZ"
+ * while requesting for timer interrupt every time for probing card.
+ */
+#define MULTIPILER_TO_HZ 1
+
+struct device mmc_dev;
+struct clk *mmc_clkp = NULL;
+mmcsd_config_def mmcsd_cfg = {
+/* read write thresholds (in bytes) can be any power of 2 from 2 to 64 */
+ 32,
+/* To use the DMA or not-- 1- Use DMA, 0-Interrupt mode */
+ 1
+};
+
+volatile mmcsd_regs_base *mmcsd_regs;
+static unsigned int mmc_input_clk = 0;
+
+/* Used to identify whether card being used currently by linux core or not */
+static unsigned int is_card_busy = 0;
+/* used to identify whether card probe(detection) is currently in progress */
+static unsigned int is_card_detect_progress = 0;
+/* used to identify whether core is icurrently initilizing the card or not */
+static unsigned int is_init_progress = 0;
+/* used to identify whether core request has been queue up or
+ * not because request has come when card detection/probe was in progress
+ */
+static unsigned int is_req_queued_up = 0;
+/* data struture to queue one request */
+static struct mmc_host *que_mmc_host = NULL;
+/* data structure to queue one request */
+static struct mmc_request *que_mmc_request = NULL;
+
+/* tells whether card is initizlzed or not */
+static unsigned int is_card_initialized = 0;
+static unsigned int new_card_state = 0; /* tells current state of card */
+
+static DEFINE_SPINLOCK(mmc_lock);
+
+static void mmc_davinci_start_command(struct mmc_davinci_host *host,
+ struct mmc_command *cmd)
+{
+ u32 cmd_reg = 0;
+ u32 resp_type = 0;
+ u32 cmd_type = 0;
+ int byte_cnt = 0, i = 0;
+ unsigned long flags;
+
+ dev_dbg(&mmc_dev, "\nMMCSD : CMD%d, argument 0x%08x",
+ cmd->opcode, cmd->arg);
+ if (cmd->flags & MMC_RSP_SHORT)
+ dev_dbg(&mmc_dev, ", 32-bit response");
+ if (cmd->flags & MMC_RSP_LONG)
+ dev_dbg(&mmc_dev, ", 128-bit response");
+ if (cmd->flags & MMC_RSP_CRC)
+ dev_dbg(&mmc_dev, ", CRC");
+ if (cmd->flags & MMC_RSP_BUSY)
+ dev_dbg(&mmc_dev, ", busy notification");
+ else
+ dev_dbg(&mmc_dev, ", No busy notification");
+ dev_dbg(&mmc_dev, "\n");
+ host->cmd = cmd;
+
+ /* Protocol layer does not provide response type,
+ * but our hardware needs to know exact type, not just size!
+ */
+ switch (cmd->flags & MMC_RSP_MASK) {
+ case MMC_RSP_NONE:
+ /* resp 0 */
+ break;
+ case MMC_RSP_SHORT:
+ /* resp 1, resp 1b */
+ /* OR resp 3!! (assume this if bus is set opendrain) */
+ if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) {
+ resp_type = 3;
+ if (cmd->opcode == 3)
+ resp_type = 1;
+ } else
+ resp_type = 1;
+ break;
+ case MMC_RSP_LONG:
+ /* resp 2 */
+ resp_type = 2;
+ break;
+ }
+
+ /* Protocol layer does not provide command type, but our hardware
+ * needs it!
+ * any data transfer means adtc type (but that information is not
+ * in command structure, so we flagged it into host struct.)
+ * However, telling bc, bcr and ac apart based on response is
+ * not foolproof:
+ * CMD0 = bc = resp0 CMD15 = ac = resp0
+ * CMD2 = bcr = resp2 CMD10 = ac = resp2
+ *
+ * Resolve to best guess with some exception testing:
+ * resp0 -> bc, except CMD15 = ac
+ * rest are ac, except if opendrain
+ */
+
+ if (host->data_dir)
+ cmd_type = DAVINCI_MMC_CMDTYPE_ADTC;
+ else if (resp_type == 0 && cmd->opcode != 15)
+ cmd_type = DAVINCI_MMC_CMDTYPE_BC;
+ else if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
+ cmd_type = DAVINCI_MMC_CMDTYPE_BCR;
+ else
+ cmd_type = DAVINCI_MMC_CMDTYPE_AC;
+
+ /* Set command Busy or not */
+ if (cmd->flags & MMC_RSP_BUSY) {
+ /*
+ * Linux core sending BUSY which is not defined for cmd 24
+ * as per mmc standard
+ */
+ if (cmd->opcode != 24)
+ cmd_reg = cmd_reg | (1 << 8);
+ }
+
+ /* Set command index */
+ cmd_reg |= cmd->opcode;
+
+ /* Setting initialize clock */
+ if (cmd->opcode == 0)
+ cmd_reg = cmd_reg | (1 << 14);
+
+ /* Set for generating DMA Xfer event */
+ if ((host->use_dma == 1) && (host->data != NULL)
+ && ((cmd->opcode == 18) || (cmd->opcode == 25)
+ || (cmd->opcode == 24)
+ || (cmd->opcode == 17)))
+ cmd_reg = cmd_reg | (1 << 16);
+
+ /* Setting whether command involves data transfer or not */
+ if (cmd_type == DAVINCI_MMC_CMDTYPE_ADTC)
+ cmd_reg = cmd_reg | (1 << 13);
+
+ /* Setting whether stream or block transfer */
+ if (cmd->flags & MMC_DATA_STREAM)
+ cmd_reg = cmd_reg | (1 << 12);
+
+ /* Setting whether data read or write */
+ if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE)
+ cmd_reg = cmd_reg | (1 << 11);
+
+ /* Setting response type */
+ cmd_reg = cmd_reg | (resp_type << 9);
+
+ if (host->bus_mode == MMC_BUSMODE_PUSHPULL)
+ cmd_reg = cmd_reg | (1 << 7);
+
+ /* set Command timeout */
+ mmcsd_regs->mmc_tor = 0xFFFF;
+
+ /* Enable interrupt */
+ if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
+ if (host->use_dma != 1)
+ mmcsd_regs->mmc_im = MMCSD_EVENT_EOFCMD
+ | MMCSD_EVENT_WRITE
+ | MMCSD_EVENT_ERROR_CMDCRC
+ | MMCSD_EVENT_ERROR_DATACRC
+ | MMCSD_EVENT_ERROR_CMDTIMEOUT
+ | MMCSD_EVENT_ERROR_DATATIMEOUT
+ | MMCSD_EVENT_BLOCK_XFERRED;
+ else
+ mmcsd_regs->mmc_im = MMCSD_EVENT_EOFCMD
+ | MMCSD_EVENT_ERROR_CMDCRC
+ | MMCSD_EVENT_ERROR_DATACRC
+ | MMCSD_EVENT_ERROR_CMDTIMEOUT
+ | MMCSD_EVENT_ERROR_DATATIMEOUT
+ | MMCSD_EVENT_BLOCK_XFERRED;
+ } else if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
+ if (host->use_dma != 1)
+ mmcsd_regs->mmc_im = MMCSD_EVENT_EOFCMD
+ | MMCSD_EVENT_READ
+ | MMCSD_EVENT_ERROR_CMDCRC
+ | MMCSD_EVENT_ERROR_DATACRC
+ | MMCSD_EVENT_ERROR_CMDTIMEOUT
+ | MMCSD_EVENT_ERROR_DATATIMEOUT
+ | MMCSD_EVENT_BLOCK_XFERRED;
+ else
+ mmcsd_regs->mmc_im = MMCSD_EVENT_EOFCMD
+ | MMCSD_EVENT_ERROR_CMDCRC
+ | MMCSD_EVENT_ERROR_DATACRC
+ | MMCSD_EVENT_ERROR_CMDTIMEOUT
+ | MMCSD_EVENT_ERROR_DATATIMEOUT
+ | MMCSD_EVENT_BLOCK_XFERRED;
+ } else
+ mmcsd_regs->mmc_im = MMCSD_EVENT_EOFCMD
+ | MMCSD_EVENT_ERROR_CMDCRC
+ | MMCSD_EVENT_ERROR_DATACRC
+ | MMCSD_EVENT_ERROR_CMDTIMEOUT
+ | MMCSD_EVENT_ERROR_DATATIMEOUT;
+
+ /*
+ * It is required by controoler b4 WRITE command that
+ * FIFO should be populated with 32 bytes
+ */
+ if ((host->data_dir == DAVINCI_MMC_DATADIR_WRITE)
+ && (cmd_type == DAVINCI_MMC_CMDTYPE_ADTC)
+ && (host->use_dma != 1)) {
+ byte_cnt = mmcsd_cfg.rw_threshold;
+ host->bytes_left -= mmcsd_cfg.rw_threshold;
+ for (i = 0; i < (byte_cnt / 4); i++) {
+ mmcsd_regs->mmc_dxr = *host->buffer;
+ host->buffer++;
+ }
+ }
+
+ if (cmd->opcode == 7) {
+ spin_lock_irqsave(&mmc_lock, flags);
+ new_card_state = 1;
+ is_card_initialized = 1;
+ host->old_card_state = new_card_state;
+ is_init_progress = 0;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ }
+ if (cmd->opcode == 1) {
+ spin_lock_irqsave(&mmc_lock, flags);
+ is_init_progress = 1;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ }
+
+ host->is_core_command = 1;
+ mmcsd_regs->mmc_arghl = cmd->arg;
+ mmcsd_regs->mmc_cmd = cmd_reg;
+
+}
+
+static void mmc_davinci_dma_cb(int lch, u16 ch_status, void *data)
+{
+ int sync_dev = 0;
+ struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;
+
+ if (DMA_COMPLETE == ch_status) {
+
+ if (host->cmd == NULL && host->data == NULL) {
+ if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
+ sync_dev = DAVINCI_DMA_MMCTXEVT;
+ } else {
+ sync_dev = DAVINCI_DMA_MMCRXEVT;
+ }
+ dev_dbg(&mmc_dev,
+ "Interrupt from DMA when no request has been made\n");
+ davinci_stop_dma(sync_dev);
+ return;
+ }
+
+ if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
+ sync_dev = DAVINCI_DMA_MMCTXEVT; /* Write */
+ } else {
+ sync_dev = DAVINCI_DMA_MMCRXEVT; /* Read */
+ }
+ davinci_stop_dma(sync_dev);
+ } else {
+ /* Handing of Event missed interreupt from DMA */
+ dev_dbg(&mmc_dev,
+ "Event miss interrupt has been generated by DMA\n");
+ if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
+ sync_dev = DAVINCI_DMA_MMCTXEVT; /* Write */
+ } else {
+ sync_dev = DAVINCI_DMA_MMCRXEVT; /* Read */
+ }
+ davinci_clean_channel(sync_dev);
+ }
+}
+
+static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host,
+ struct mmc_request *req)
+{
+ const char *dev_name;
+ int sync_dev, r, edma_ch = 0, tcc = 0;
+ unsigned char i, j;
+ unsigned short acnt, bcnt, ccnt;
+ unsigned int src_port, dst_port, temp_ccnt;
+ enum address_mode mode_src, mode_dst;
+ enum fifo_width fifo_width_src, fifo_width_dst;
+ unsigned short src_bidx, dst_bidx;
+ unsigned short src_cidx, dst_cidx;
+ unsigned short bcntrld;
+ enum sync_dimension sync_mode;
+ edmacc_paramentry_regs temp;
+ enum dma_event_q queue_no = EVENTQ_0;
+ int edma_chan_num;
+ unsigned int num_eight_words = (req->data->blocks * 512) / 32;
+ static unsigned int option_read = 0;
+ static unsigned int option_write = 0;
+ static unsigned char dma_read_req = 1;
+ static unsigned char dma_write_req = 1;
+
+#define MAX_C_CNT 64000
+
+ if ((req->data->flags & MMC_DATA_WRITE)) {
+ sync_dev = DAVINCI_DMA_MMCTXEVT; /* Write */
+ dev_name = "MMC_WRITE";
+
+ if (dma_write_req) {
+ r = davinci_request_dma(sync_dev, dev_name,
+ mmc_davinci_dma_cb, host,
+ &edma_ch, &tcc, queue_no);
+ if (r != 0) {
+ dev_dbg(&mmc_dev,
+ "MMC: davinci_request_dma() failed with %d\n",
+r);
+ return r;
+ }
+ dma_write_req = 0;
+ }
+ } else {
+ sync_dev = DAVINCI_DMA_MMCRXEVT; /* Read */
+ dev_name = "MMC_READ";
+ if (dma_read_req) {
+ r = davinci_request_dma(sync_dev, dev_name,
+ mmc_davinci_dma_cb, host,
+ &edma_ch, &tcc, queue_no);
+ if (r != 0) {
+ dev_dbg(&mmc_dev,
+ "MMC: davinci_request_dma() failed with %d\n",
+ r);
+ return r;
+ }
+ dma_read_req = 0;
+ }
+ }
+
+ if ((req->data->flags & MMC_DATA_WRITE)) {
+ /* AB Sync Transfer */
+ /* Acnt =32, Bcnt= , Cnt=1 */
+
+ sync_dev = DAVINCI_DMA_MMCTXEVT; /* Write */
+ acnt = 4;
+ bcnt = 8;
+ if (num_eight_words > MAX_C_CNT) {
+ temp_ccnt = MAX_C_CNT;
+ ccnt = temp_ccnt;
+ } else {
+ ccnt = num_eight_words;
+ temp_ccnt = ccnt;
+ }
+
+ src_port = (unsigned int)virt_to_phys(req->data->mrq->buffer);
+ mode_src = INCR;
+ fifo_width_src = W8BIT; /* It's not cared as modeDsr is INCR */
+ src_bidx = 4;
+ src_cidx = 32;
+ dst_port = MMCSD_REGS_BASE_ADDR + 0x2C;
+ mode_dst = INCR;
+ fifo_width_dst = W8BIT; /* It's not cared as modeDsr is INCR */
+ dst_bidx = 0;
+ dst_cidx = 0;
+ bcntrld = 8;
+ sync_mode = ABSYNC;
+
+ } else {
+ sync_dev = DAVINCI_DMA_MMCRXEVT; /* Read */
+ acnt = 4;
+ bcnt = 8;
+ if (num_eight_words > MAX_C_CNT) {
+ temp_ccnt = MAX_C_CNT;
+ ccnt = temp_ccnt;
+ } else {
+ ccnt = num_eight_words;
+ temp_ccnt = ccnt;
+ }
+
+ src_port = MMCSD_REGS_BASE_ADDR + 0x28;
+ mode_src = INCR;
+ fifo_width_src = W8BIT;
+ src_bidx = 0;
+ src_cidx = 0;
+ dst_port = (unsigned int)virt_to_phys(req->data->mrq->buffer);
+ mode_dst = INCR;
+ fifo_width_dst = W8BIT; /* It's not cared as modeDsr is INCR */
+ dst_bidx = 4;
+ dst_cidx = 32;
+ bcntrld = 8;
+ sync_mode = ABSYNC;
+ }
+
+ davinci_set_dma_src_params(sync_dev, src_port, mode_src,
+ fifo_width_src);
+ davinci_set_dma_dest_params(sync_dev, dst_port, mode_dst,
+ fifo_width_dst);
+ davinci_set_dma_src_index(sync_dev, src_bidx, src_cidx);
+ davinci_set_dma_dest_index(sync_dev, dst_bidx, dst_cidx);
+ davinci_set_dma_transfer_params(sync_dev, acnt, bcnt, ccnt, bcntrld,
+ sync_mode);
+
+ host->edma_ch_details.cnt_chanel = 0;
+ davinci_get_dma_params(sync_dev, &temp);
+ if (sync_dev == DAVINCI_DMA_MMCTXEVT) {
+ if (option_write == 0) {
+ option_write = temp.opt;
+ } else {
+ temp.opt = option_write;
+ davinci_set_dma_params(sync_dev, &temp);
+ }
+ }
+ if (sync_dev == DAVINCI_DMA_MMCRXEVT) {
+ if (option_read == 0) {
+ option_read = temp.opt;
+ } else {
+ temp.opt = option_read;
+ davinci_set_dma_params(sync_dev, &temp);
+ }
+ }
+
+ if (num_eight_words > MAX_C_CNT) { /* Linking will be performed */
+ davinci_get_dma_params(sync_dev, &temp);
+ temp.opt &= ~TCINTEN;
+ davinci_set_dma_params(sync_dev, &temp);
+
+ for (i = 0; i < EDMA_MAX_LOGICAL_CHA_ALLOWED; i++) {
+ if (i != 0) {
+ j = i - 1;
+ davinci_get_dma_params(
+ host->edma_ch_details.chanel_num[j],
+ &temp);
+ temp.opt &= ~TCINTEN;
+ davinci_set_dma_params(
+ host->edma_ch_details.chanel_num[j],
+ &temp);
+ }
+
+ host->edma_ch_details.cnt_chanel++;
+ davinci_request_dma(DAVINCI_EDMA_PARAM_ANY, "LINK",
+ NULL, NULL, &edma_chan_num,
+ &sync_dev, queue_no);
+ host->edma_ch_details.chanel_num[i] = edma_chan_num;
+ ccnt = temp.ccnt & 0x0000FFFF;
+ if (sync_dev == DAVINCI_DMA_MMCTXEVT) {
+ temp.src = temp.src + (acnt * bcnt * ccnt);
+ } else {
+ temp.dst = temp.dst + (acnt * bcnt * ccnt);
+ }
+ temp.opt |= TCINTEN;
+
+ if ((num_eight_words - temp_ccnt) > MAX_C_CNT) {
+ temp.ccnt = (temp.ccnt & 0xFFFF0000)
+ | MAX_C_CNT;
+ ccnt = temp.ccnt & 0x0000FFFF;
+ temp_ccnt = temp_ccnt + ccnt;
+ } else {
+ temp.ccnt = (temp.ccnt & 0xFFFF0000)
+ | (num_eight_words -temp_ccnt);
+ ccnt = temp.ccnt & 0x0000FFFF;
+ temp_ccnt = temp_ccnt + ccnt;
+ }
+ davinci_set_dma_params(edma_chan_num, &temp);
+ if (i != 0) {
+ j = i - 1;
+ davinci_dma_link_lch(host->edma_ch_details.
+ chanel_num[j],
+ edma_chan_num);
+ }
+ if (temp_ccnt == num_eight_words)
+ break;
+ }
+ davinci_dma_link_lch(sync_dev,
+ host->edma_ch_details.chanel_num[0]);
+ }
+
+ davinci_start_dma(sync_dev);
+ return 0;
+}
+
+static void
+mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req)
+{
+ int timeout;
+
+ host->data = req->data;
+ if (req->data == NULL) {
+ host->data_dir = DAVINCI_MMC_DATADIR_NONE;
+ mmcsd_regs->mmc_blen = 0;
+ mmcsd_regs->mmc_nblk = 0;
+ return;
+ }
+ dev_dbg(&mmc_dev,
+ "MMCSD : Data xfer (%s %s), "
+ "DTO %d cycles + %d ns, %d blocks of %d bytes\r\n",
+ (req->data->flags & MMC_DATA_STREAM) ? "stream" : "block",
+ (req->data->flags & MMC_DATA_WRITE) ? "write" : "read",
+ req->data->timeout_clks, req->data->timeout_ns,
+ req->data->blocks, req->data->blksz);
+
+ /* Convert ns to clock cycles by assuming 20MHz frequency
+ * 1 cycle at 20MHz = 500 ns
+ */
+ timeout = req->data->timeout_clks + req->data->timeout_ns / 500;
+ if (timeout > 0xffff)
+ timeout = 0xffff;
+
+ mmcsd_regs->mmc_tod = timeout;
+ mmcsd_regs->mmc_nblk = req->data->blocks;
+ mmcsd_regs->mmc_blen = req->data->blksz;
+ host->data_dir = (req->data->flags & MMC_DATA_WRITE)
+ ? DAVINCI_MMC_DATADIR_WRITE
+ : DAVINCI_MMC_DATADIR_READ;
+
+ /* Configure the FIFO */
+ switch (host->data_dir) {
+ case DAVINCI_MMC_DATADIR_WRITE:
+ mmcsd_regs->mmc_fifo_ctl = mmcsd_regs->mmc_fifo_ctl | 0x1;
+ mmcsd_regs->mmc_fifo_ctl = 0x0;
+ mmcsd_regs->mmc_fifo_ctl = mmcsd_regs->mmc_fifo_ctl | (1 << 1);
+ mmcsd_regs->mmc_fifo_ctl = mmcsd_regs->mmc_fifo_ctl | (1 << 2);
+ break;
+
+ case DAVINCI_MMC_DATADIR_READ:
+ mmcsd_regs->mmc_fifo_ctl = mmcsd_regs->mmc_fifo_ctl | 0x1;
+ mmcsd_regs->mmc_fifo_ctl = 0x0;
+ mmcsd_regs->mmc_fifo_ctl = mmcsd_regs->mmc_fifo_ctl | (1 << 2);
+ break;
+ default:
+ break;
+ }
+
+ if ((host->use_dma == 1)
+ && (mmc_davinci_start_dma_transfer(host, req) == 0)) {
+ host->buffer = NULL;
+ host->bytes_left = 0;
+ } else {
+ /* Revert to CPU Copy */
+ host->buffer = (u32 *) (req->data->mrq->buffer);
+ host->bytes_left = req->data->blocks * req->data->blksz;
+ host->use_dma = 0;
+ }
+}
+
+static void mmc_davinci_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+ struct mmc_davinci_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ if (!is_card_detect_progress) {
+ spin_lock_irqsave(&mmc_lock, flags);
+ is_card_busy = 1;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ mmc_davinci_prepare_data(host, req);
+ mmc_davinci_start_command(host, req->cmd);
+ } else {
+ /* Queu up the request as card dectection is being excuted */
+ que_mmc_host = mmc;
+ que_mmc_request = req;
+ spin_lock_irqsave(&mmc_lock, flags);
+ is_req_queued_up = 1;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ }
+}
+
+static unsigned int calculate_freq_for_card(unsigned int mmc_req_freq)
+{
+ unsigned int mmc_freq = 0, cpu_arm_clk = 0, mmc_push_pull = 0;
+
+ cpu_arm_clk = mmc_input_clk;
+ if (cpu_arm_clk > (2 * mmc_req_freq))
+ mmc_push_pull = ((unsigned int)cpu_arm_clk
+ / (2 * mmc_req_freq)) - 1;
+ else
+ mmc_push_pull = 0;
+
+ mmc_freq = (unsigned int)cpu_arm_clk / (2 * (mmc_push_pull + 1));
+
+ if (mmc_freq > mmc_req_freq)
+ mmc_push_pull = mmc_push_pull + 1;
+
+ return mmc_push_pull;
+}
+
+static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ unsigned short status;
+ unsigned int open_drain_freq = 0, cpu_arm_clk = 0;
+ unsigned int mmc_push_pull_freq = 0;
+ struct mmc_davinci_host *host = mmc_priv(mmc);
+
+ cpu_arm_clk = mmc_input_clk;
+ dev_dbg(&mmc_dev, "clock %dHz busmode %d powermode %d Vdd %d.%02d\r\n",
+ ios->clock, ios->bus_mode, ios->power_mode,
+ ios->vdd / 100, ios->vdd % 100);
+
+ if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) {
+ open_drain_freq = ((unsigned int)cpu_arm_clk
+ / (2 * MMCSD_INIT_CLOCK)) - 1;
+ mmcsd_regs->mmc_clk = (mmcsd_regs->mmc_clk & ~(0xFF))
+ | open_drain_freq;
+ } else {
+ mmc_push_pull_freq = calculate_freq_for_card(ios->clock);
+ mmcsd_regs->mmc_clk = (mmcsd_regs->mmc_clk & ~(0xFF))
+ | mmc_push_pull_freq;
+ }
+ host->bus_mode = ios->bus_mode;
+ if (ios->power_mode == MMC_POWER_UP) {
+ /* Send clock cycles, poll completion */
+ mmcsd_regs->mmc_arghl = 0x0;
+ mmcsd_regs->mmc_cmd = 0x4000;
+ status = 0;
+ while (!(status & (MMCSD_EVENT_EOFCMD))) {
+ status = mmcsd_regs->mmc_st0;
+ }
+ }
+}
+
+static void
+mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data)
+{
+ unsigned long flags;
+
+ host->data = NULL;
+ host->data_dir = DAVINCI_MMC_DATADIR_NONE;
+ if (data->error == MMC_ERR_NONE)
+ data->bytes_xfered += data->blocks * data->blksz;
+
+ if (data->error == MMC_ERR_TIMEOUT) {
+ spin_lock_irqsave(&mmc_lock, flags);
+ is_card_busy = 0;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ mmc_request_done(host->mmc, data->mrq);
+ return;
+ }
+
+ if (!data->stop) {
+ host->req = NULL;
+ spin_lock_irqsave(&mmc_lock, flags);
+ is_card_busy = 0;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ mmc_request_done(host->mmc, data->mrq);
+ return;
+ }
+ mmc_davinci_start_command(host, data->stop);
+}
+
+static void mmc_davinci_cmd_done(struct mmc_davinci_host *host,
+ struct mmc_command *cmd)
+{
+ unsigned long flags;
+
+ host->cmd = NULL;
+ switch (cmd->flags & MMC_RSP_MASK) {
+ case MMC_RSP_NONE:
+ /* resp 0 */
+ break;
+
+ case MMC_RSP_SHORT:
+ /* response types 1, 1b, 3, 4, 5, 6 */
+ cmd->resp[0] = mmcsd_regs->mmc_rsp67;
+ break;
+
+ case MMC_RSP_LONG:
+ /* response type 2 */
+ cmd->resp[3] = mmcsd_regs->mmc_rsp01;
+ cmd->resp[2] = mmcsd_regs->mmc_rsp23;
+ cmd->resp[1] = mmcsd_regs->mmc_rsp45;
+ cmd->resp[0] = mmcsd_regs->mmc_rsp67;
+ break;
+ }
+
+ if (host->data == NULL || cmd->error != MMC_ERR_NONE) {
+ host->req = NULL;
+ if (cmd->error == MMC_ERR_TIMEOUT)
+ cmd->mrq->cmd->retries = 0;
+ spin_lock_irqsave(&mmc_lock, flags);
+ is_card_busy = 0;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ mmc_request_done(host->mmc, cmd->mrq);
+ }
+}
+
+static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
+{
+ struct mmc_davinci_host *host = (struct mmc_davinci_host *)dev_id;
+ u16 status;
+ int end_command;
+ int end_transfer;
+ int byte_cnt = 0, i = 0;
+ unsigned long flags;
+
+ if (host->is_core_command) {
+ if (host->cmd == NULL && host->data == NULL) {
+ status = mmcsd_regs->mmc_st0;
+ dev_dbg(&mmc_dev, "Spurious interrupt 0x%04x\r\n",
+ status);
+ /* Disable the interrupt from mmcsd */
+ mmcsd_regs->mmc_im = 0;
+ return IRQ_HANDLED;
+ }
+ }
+ end_command = 0;
+ end_transfer = 0;
+
+ status = mmcsd_regs->mmc_st0;
+ if (status == 0)
+ return IRQ_HANDLED;
+
+ if (host->is_core_command) {
+ if (is_card_initialized) {
+ if (new_card_state == 0) {
+ if (host->cmd) {
+ host->cmd->error |= MMC_ERR_TIMEOUT;
+ mmc_davinci_cmd_done(host, host->cmd);
+ }
+ dev_dbg(&mmc_dev,
+ "From code segment excuted when card removed\n");
+ return IRQ_HANDLED;
+ }
+ }
+
+ while (status != 0) {
+ if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
+ if (status & MMCSD_EVENT_WRITE) {
+ /* Buffer almost empty */
+ if (host->bytes_left > 0) {
+ byte_cnt =
+ mmcsd_cfg.rw_threshold;
+ host->bytes_left -=
+ mmcsd_cfg.rw_threshold;
+ for (i = 0; i < (byte_cnt / 4);
+ i++) {
+ mmcsd_regs->mmc_dxr =
+ *host->buffer;
+ host->buffer++;
+ }
+ }
+ }
+ }
+
+ if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
+ if (status & MMCSD_EVENT_READ) {
+ /* Buffer almost empty */
+ if (host->bytes_left > 0) {
+ byte_cnt =
+ mmcsd_cfg.rw_threshold;
+ host->bytes_left -=
+ mmcsd_cfg.rw_threshold;
+ for (i = 0; i < (byte_cnt / 4);
+ i++) {
+ *host->buffer =
+ mmcsd_regs->
+ mmc_drr;
+ host->buffer++;
+ }
+ }
+ }
+ }
+
+ if (status & MMCSD_EVENT_BLOCK_XFERRED) {
+ /* Block sent/received */
+ if (host->data != NULL) {
+ end_transfer = 1;
+ }
+ }
+
+ if (status & MMCSD_EVENT_ERROR_DATATIMEOUT) {
+ /* Data timeout */
+ if ((host->data) && (new_card_state != 0)) {
+ host->data->error |= MMC_ERR_TIMEOUT;
+ spin_lock_irqsave(&mmc_lock, flags);
+ new_card_state = 0;
+ is_card_initialized = 0;
+ spin_unlock_irqrestore(&mmc_lock,
+ flags);
+ dev_dbg(&mmc_dev,
+ "MMCSD: Data timeout, CMD%d and status is %x\r\n",
+ host->cmd->opcode, status);
+ end_transfer = 1;
+ host->cmd->error |= MMC_ERR_TIMEOUT;
+ }
+ dev_dbg(&mmc_dev,
+ "MMCSD: Data timeout, CMD%d and status is %x\r\n",
+ host->cmd->opcode, status);
+ }
+
+ if (status & MMCSD_EVENT_ERROR_DATACRC) {
+ /* Data CRC error */
+ if (host->data) {
+ host->data->error |= MMC_ERR_BADCRC;
+ dev_dbg(&mmc_dev,
+ "MMCSD: Data CRC error, bytes left %d\r\n",
+ host->bytes_left);
+ end_transfer = 1;
+ } else {
+ dev_dbg(&mmc_dev,
+ "MMCSD: Data CRC error\r\n");
+ }
+ }
+
+ if (status & MMCSD_EVENT_ERROR_CMDTIMEOUT) {
+ /* Command timeout */
+ if (host->cmd) {
+ /* Timeouts are normal in case of
+ * MMC_SEND_STATUS
+ */
+ if (host->cmd->opcode !=
+ MMC_ALL_SEND_CID) {
+ dev_dbg(&mmc_dev,
+ "MMCSD: CMD%d timeout,"
+ " status %x\r\n",
+ host->cmd->opcode,
+ status);
+ spin_lock_irqsave(&mmc_lock,
+ flags);
+ new_card_state = 0;
+ is_card_initialized = 0;
+ spin_unlock_irqrestore(
+ &mmc_lock, flags);
+ }
+ host->cmd->error |= MMC_ERR_TIMEOUT;
+ end_command = 1;
+
+ }
+ }
+
+ if (status & MMCSD_EVENT_ERROR_CMDCRC) {
+ /* Command CRC error */
+ dev_dbg(&mmc_dev, "Command CRC error\r\n");
+ if (host->cmd) {
+ host->cmd->error |= MMC_ERR_BADCRC;
+ end_command = 1;
+ }
+ }
+
+ if (status & MMCSD_EVENT_EOFCMD) {
+ /* End of command phase */
+ end_command = 1;
+ }
+
+ if (host->data == NULL) {
+ status = mmcsd_regs->mmc_st0;
+ if (status != 0) {
+ dev_dbg(&mmc_dev,
+ "Status is %x at end of ISR when host->data is NULL",
+ status);
+ status = 0;
+
+ }
+ } else {
+ status = mmcsd_regs->mmc_st0;
+ }
+ }
+
+ if (end_command)
+ mmc_davinci_cmd_done(host, host->cmd);
+ if (end_transfer)
+ mmc_davinci_xfer_done(host, host->data);
+
+ } else {
+ if (host->cmd_code == 13) {
+ if (status & MMCSD_EVENT_EOFCMD) {
+ spin_lock_irqsave(&mmc_lock, flags);
+ new_card_state = 1;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+
+ } else {
+ spin_lock_irqsave(&mmc_lock, flags);
+ new_card_state = 0;
+ is_card_initialized = 0;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ }
+
+ spin_lock_irqsave(&mmc_lock, flags);
+ is_card_detect_progress = 0;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+
+ if (is_req_queued_up) {
+ mmc_davinci_request(que_mmc_host,
+ que_mmc_request);
+ spin_lock_irqsave(&mmc_lock, flags);
+ is_req_queued_up = 0;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ }
+
+ }
+
+ if (host->cmd_code == 1) {
+ if (status & MMCSD_EVENT_EOFCMD) {
+ spin_lock_irqsave(&mmc_lock, flags);
+ new_card_state = 1;
+ is_card_initialized = 0;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ } else {
+
+ spin_lock_irqsave(&mmc_lock, flags);
+ new_card_state = 0;
+ is_card_initialized = 0;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ }
+
+ spin_lock_irqsave(&mmc_lock, flags);
+ is_card_detect_progress = 0;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+
+ if (is_req_queued_up) {
+ mmc_davinci_request(que_mmc_host,
+ que_mmc_request);
+ spin_lock_irqsave(&mmc_lock, flags);
+ is_req_queued_up = 0;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ }
+
+ }
+
+ if (host->cmd_code == 0) {
+ if (status & MMCSD_EVENT_EOFCMD) {
+ host->is_core_command = 0;
+ host->cmd_code = 1;
+ dev_dbg(&mmc_dev,
+ "MMC-Probing mmc with cmd1\n");
+ /* Issue cmd1 */
+ mmcsd_regs->mmc_arghl = 0x80300000;
+ mmcsd_regs->mmc_cmd = 0x00000601;
+
+ } else {
+ spin_lock_irqsave(&mmc_lock, flags);
+ new_card_state = 0;
+ is_card_initialized = 0;
+ is_card_detect_progress = 0;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ }
+ }
+
+ }
+ return IRQ_HANDLED;
+}
+
+static struct mmc_host_ops mmc_davinci_ops = {
+ .request = mmc_davinci_request,
+ .set_ios = mmc_davinci_set_ios,
+};
+
+void mmc_check_card(unsigned long data)
+{
+ struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;
+ unsigned long flags;
+
+ if ((!is_card_detect_progress) || (!is_init_progress)) {
+ if (is_card_initialized) {
+ host->is_core_command = 0;
+ host->cmd_code = 13;
+ spin_lock_irqsave(&mmc_lock, flags);
+ is_card_detect_progress = 1;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ /* Issue cmd13 */
+ mmcsd_regs->mmc_arghl = 0x10000;
+ mmcsd_regs->mmc_cmd = 0x0000028D;
+ } else {
+ host->is_core_command = 0;
+ host->cmd_code = 0;
+ spin_lock_irqsave(&mmc_lock, flags);
+ is_card_detect_progress = 1;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ /* Issue cmd0 */
+ mmcsd_regs->mmc_arghl = 0;
+ mmcsd_regs->mmc_cmd = 0x4000;
+ }
+ mmcsd_regs->mmc_im = MMCSD_EVENT_EOFCMD
+ | MMCSD_EVENT_ERROR_CMDCRC
+ | MMCSD_EVENT_ERROR_DATACRC
+ | MMCSD_EVENT_ERROR_CMDTIMEOUT
+ | MMCSD_EVENT_ERROR_DATATIMEOUT;
+ }
+}
+
+static void davinci_mmc_check_status(unsigned long data)
+{
+ unsigned long flags;
+ struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;
+
+ if (!is_card_busy) {
+ if (host->old_card_state ^ new_card_state) {
+ mmc_detect_change(host->mmc, 0);
+ spin_lock_irqsave(&mmc_lock, flags);
+ host->old_card_state = new_card_state;
+ spin_unlock_irqrestore(&mmc_lock, flags);
+ } else
+ mmc_check_card(data);
+ }
+ mod_timer(&host->timer, jiffies + MULTIPILER_TO_HZ * HZ);
+}
+
+static void init_mmcsd_host(void)
+{
+ /* CMD line portion is diabled and in reset state */
+ mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl | 0x1;
+ /* DAT line portion is diabled and in reset state */
+ mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl | (1 << 1);
+
+ mmcsd_regs->mmc_clk = 0x0;
+ mmcsd_regs->mmc_clk = mmcsd_regs->mmc_clk | (1 << 8);
+
+ mmcsd_regs->mmc_tor = 0xFFFF;
+ mmcsd_regs->mmc_tod = 0xFFFF;
+
+ mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl & ~(0x1);
+ mmcsd_regs->mmc_ctl = mmcsd_regs->mmc_ctl & ~(1 << 1);
+}
+
+static int davinci_mmcsd_probe(struct platform_device *pdev)
+{
+ struct mmc_davinci_host *host;
+ struct mmc_host *mmc;
+ int ret;
+
+ mmc = mmc_alloc_host(sizeof(struct mmc_davinci_host), &pdev->dev);
+ if (!mmc) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ mmcsd_regs =
+ (volatile mmcsd_regs_base *)IO_ADDRESS(MMCSD_REGS_BASE_ADDR);
+
+ init_mmcsd_host();
+
+ mmc->ops = &mmc_davinci_ops;
+ mmc->f_min = 312500;
+ mmc->f_max = 20000000;
+ mmc->ocr_avail = MMC_VDD_32_33;
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc; /* Important */
+
+ host->use_dma = mmcsd_cfg.use_dma;
+ host->irq = MMCINT_INTERRUPT;
+ host->sd_support = 1;
+ ret = request_irq(MMCINT_INTERRUPT, mmc_davinci_irq, 0, DRIVER_NAME,
+ host);
+
+ if (ret)
+ goto out;
+
+ platform_set_drvdata(pdev, host);
+ mmc_add_host(mmc);
+
+ init_timer(&host->timer);
+ host->timer.data = (unsigned long)host;
+ host->timer.function = davinci_mmc_check_status;
+ host->timer.expires = jiffies + MULTIPILER_TO_HZ * HZ;
+ add_timer(&host->timer);
+
+ return 0;
+
+out:
+ /* TBD: Free other resources too. */
+
+ return ret;
+}
+
+static int davinci_mmcsd_remove(struct platform_device *pdev)
+{
+ struct mmc_davinci_host *host = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ mmc_remove_host(host->mmc);
+ free_irq(host->irq, host);
+ del_timer(&host->timer);
+ davinci_free_dma(DAVINCI_DMA_MMCTXEVT);
+ davinci_free_dma(DAVINCI_DMA_MMCRXEVT);
+ return 0;
+
+}
+
+#ifdef CONFIG_PM
+static int davinci_mmcsd_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+ struct mmc_davinci_host *host = platform_get_drvdata(pdev);
+
+ return mmc_suspend_host(host->mmc, msg);
+}
+
+static int davinci_mmcsd_resume(struct platform_device *pdev)
+{
+ struct mmc_davinci_host *host = platform_get_drvdata(pdev);
+
+ return mmc_resume_host(host->mmc);
+}
+
+#else
+
+#define davinci_mmcsd_suspend NULL
+#define davinci_mmcsd_resume NULL
+
+#endif
+
+static struct platform_driver davinci_mmcsd_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = davinci_mmcsd_probe,
+ .remove = davinci_mmcsd_remove,
+ .suspend = davinci_mmcsd_suspend,
+ .resume = davinci_mmcsd_resume,
+};
+
+/* FIXME don't be a legacy driver ... register the device as part
+ * of cpu-specific board setup.
+ */
+static void mmc_release(struct device *dev)
+{
+ /* Nothing to release? */
+}
+
+static u64 mmc_dma_mask = 0xffffffff;
+
+static struct resource mmc_resources[] = {
+ {
+ .start = IO_ADDRESS(MMCSD_REGS_BASE_ADDR),
+ .end = IO_ADDRESS((MMCSD_REGS_BASE_ADDR) + 0x74),
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MMCINT_INTERRUPT,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device mmc_davinci_device = {
+ .name = DRIVER_NAME,
+ .id = 1,
+ .dev = {
+ .release = mmc_release,
+ .dma_mask = &mmc_dma_mask,
+ },
+ .num_resources = ARRAY_SIZE(mmc_resources),
+ .resource = mmc_resources,
+};
+
+static int davinci_mmcsd_init(void)
+{
+ int ret = 0;
+ struct clk *clkp = NULL;
+
+ clkp = clk_get(NULL, "MMCSDCLK");
+ if (clkp != NULL) {
+ mmc_clkp = clkp;
+ clk_enable(mmc_clkp);
+ mmc_input_clk = clk_get_rate(mmc_clkp);
+
+ ret = platform_device_register(&mmc_davinci_device);
+ if (ret != 0)
+ goto free1;
+
+ ret = platform_driver_register(&davinci_mmcsd_driver);
+ if (ret == 0)
+ return 0;
+
+free1:
+ platform_device_unregister(&mmc_davinci_device);
+ }
+
+ return -ENODEV;
+}
+
+static void __exit davinci_mmcsd_exit(void)
+{
+ platform_driver_unregister(&davinci_mmcsd_driver);
+ platform_device_unregister(&mmc_davinci_device);
+ clk_disable(mmc_clkp);
+}
+
+module_init(davinci_mmcsd_init);
+module_exit(davinci_mmcsd_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MMCSD driver for Davinci MMC controller");
diff --git a/drivers/mmc/host/davinci_mmc.h b/drivers/mmc/host/davinci_mmc.h
new file mode 100644
index 0000000..a6c4557
--- /dev/null
+++ b/drivers/mmc/host/davinci_mmc.h
@@ -0,0 +1,171 @@
+/*
+ * linux/drivers/mmc/davinci.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ * DAVINCI MMC register and other definitions
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ Modifications:
+ ver. 1.0: Oct 2005, Purushotam Kumar Initial version
+ ver 1.2: Jan 2006, Purushotam Kumar Added hot card remove insert support
+
+ *
+ */
+
+#ifndef DAVINCI_MMC_H_
+#define DAVINCI_MMC_H_
+
+/**************************************************************************\
+* Register Overlay Structure
+\**************************************************************************/
+
+typedef struct {
+ unsigned short mmc_ctl;
+ unsigned char rsvd0[2];
+ unsigned short mmc_clk;
+ unsigned char rsvd1[2];
+ unsigned short mmc_st0;
+ unsigned char rsvd2[2];
+ unsigned short mmc_st1;
+ unsigned char rsvd3[2];
+ unsigned short mmc_im;
+ unsigned char rsvd4[2];
+ unsigned short mmc_tor;
+ unsigned char rsvd5[2];
+ unsigned short mmc_tod;
+ unsigned char rsvd6[2];
+ unsigned short mmc_blen;
+ unsigned char rsvd7[2];
+ unsigned short mmc_nblk;
+ unsigned char rsvd8[2];
+ unsigned short mmc_nblc;
+ unsigned char rsvd9[2];
+ unsigned int mmc_drr;
+ unsigned int mmc_dxr;
+ unsigned int mmc_cmd;
+ unsigned int mmc_arghl;
+ unsigned int mmc_rsp01;
+ unsigned int mmc_rsp23;
+ unsigned int mmc_rsp45;
+ unsigned int mmc_rsp67;
+ unsigned short mmc_drsp;
+ unsigned char rsvd10[2];
+ unsigned short mmc_etok;
+ unsigned char rsvd11[2];
+ unsigned short mmc_cidx;
+ unsigned char rsvd12[2];
+ unsigned short mmc_ckc;
+ unsigned char rsvd13[2];
+ unsigned short mmc_torc;
+ unsigned char rsvd14[2];
+ unsigned short mmc_todc;
+ unsigned char rsvd15[2];
+ unsigned short mmc_blnc;
+ unsigned char rsvd16[2];
+ unsigned short sdio_ctl;
+ unsigned char rsvd17[2];
+ unsigned short sdio_st0;
+ unsigned char rsvd18[2];
+ unsigned short sdio_en;
+ unsigned char rsvd19[2];
+ unsigned short sdio_st;
+ unsigned char rsvd20[2];
+ unsigned short mmc_fifo_ctl;
+} mmcsd_regs_base;
+
+/*
+ * Command types
+ */
+#define DAVINCI_MMC_CMDTYPE_BC 0
+#define DAVINCI_MMC_CMDTYPE_BCR 1
+#define DAVINCI_MMC_CMDTYPE_AC 2
+#define DAVINCI_MMC_CMDTYPE_ADTC 3
+#define EDMA_MAX_LOGICAL_CHA_ALLOWED 1
+
+typedef struct {
+ unsigned char cnt_chanel;
+ unsigned int chanel_num[EDMA_MAX_LOGICAL_CHA_ALLOWED];
+} edma_ch_mmcsd;
+
+struct mmc_davinci_host {
+
+ int initialized;
+ int suspended;
+ struct mmc_request *req;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ struct mmc_host *mmc;
+ struct device *dev;
+ unsigned char id;
+ struct clk *clk;
+ u32 base;
+ int irq;
+ unsigned char bus_mode;
+
+#define DAVINCI_MMC_DATADIR_NONE 0
+#define DAVINCI_MMC_DATADIR_READ 1
+#define DAVINCI_MMC_DATADIR_WRITE 2
+ unsigned char data_dir;
+ u32 *buffer;
+ u32 bytes_left;
+ int power_pin;
+
+ int use_dma;
+ struct completion dma_completion;
+
+ struct timer_list timer;
+ unsigned int is_core_command;
+ unsigned int cmd_code;
+ unsigned int old_card_state;
+
+ unsigned char sd_support;
+
+ edma_ch_mmcsd edma_ch_details;
+
+};
+typedef struct {
+ unsigned short rw_threshold;
+ unsigned short use_dma;
+} mmcsd_config_def;
+
+typedef enum {
+ MMCSD_EVENT_EOFCMD = (1 << 2),
+ MMCSD_EVENT_READ = (1 << 10),
+ MMCSD_EVENT_WRITE = (1 << 9),
+ MMCSD_EVENT_ERROR_CMDCRC = (1 << 7),
+ MMCSD_EVENT_ERROR_DATACRC = ((1 << 6) | (1 << 5)),
+ MMCSD_EVENT_ERROR_CMDTIMEOUT = (1 << 4),
+ MMCSD_EVENT_ERROR_DATATIMEOUT = (1 << 3),
+ MMCSD_EVENT_CARD_EXITBUSY = (1 << 1),
+ MMCSD_EVENT_BLOCK_XFERRED = (1 << 0)
+} mmcsdevent;
+
+#define MMCSD_EVENT_TIMEOUT_ERROR \
+ (MMCSD_EVENT_ERROR_DATATIMEOUT | MMCSD_EVENT_ERROR_CMDTIMEOUT )
+#define MMCSD_EVENT_CRC_ERROR \
+ (MMCSD_EVENT_ERROR_DATACRC | MMCSD_EVENT_ERROR_CMDCRC)
+#define MMCSD_EVENT_ERROR \
+ (MMCSD_EVENT_TIMEOUT_ERROR | MMCSD_EVENT_CRC_ERROR)
+
+#endif /* DAVINCI_MMC_H_ */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index c5519250e..8dd9a86 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -917,6 +917,15 @@
module, say M here and read <file:Documentation/kbuild/modules.txt>
as well as <file:Documentation/networking/net-modules.txt>.
+config TI_DAVINCI_EMAC
+ tristate "TI DaVinci EMAC Support"
+ depends on NETDEVICES && MACH_DAVINCI_EVM
+ help
+ This driver supports TI's DaVinci Ethernet .
+
+ To compile this driver as a module, choose M here: the module
+ will be called ti_davinci_emac. This is recommended.
+
config NET_NETX
tristate "NetX Ethernet support"
select MII
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 9c928a8..32cc79a 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -2,6 +2,9 @@
# Makefile for the Linux network (ethercard) device drivers.
#
+davinci_emac_driver-objs := davinci_emac.o davinci_emac_phy.o
+obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac_driver.o
+
obj-$(CONFIG_E1000) += e1000/
obj-$(CONFIG_IBM_EMAC) += ibm_emac/
obj-$(CONFIG_IXGB) += ixgb/
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
new file mode 100644
index 0000000..d1b6787
--- /dev/null
+++ b/drivers/net/davinci_emac.c
@@ -0,0 +1,6959 @@
+/*
+ * linux/drivers/net/davinci_emac.c
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ Modifications:
+ ver. 0.0 Suraj Iyer - Original Linux drive
+ 0.1 Anant Gole - Recoded as per TI PSPF architecture (converted to DDA)
+ 2.0 Suraj Iyer, Sharath Kumar, Ajay Singh - Completed for TI BCG
+ 3.0 Anant Gole - Modified and ported for DaVinci
+ 4.0 Kevin Hilman, Anant Gole - Linuxification of the driver
+ 4.? Paul Bartholomew - Use PHY_DUPLEX_* constants instead
+ of hard-coded numbers. Also, fixed
+ EMAC_IOCTL_READ_PHY_REG in emac_control() -
+ the phy_num and reg_addr args were swapped
+ in call to emac_mdio_read().
+ */
+
+/*
+ Driver Features:
+
+ The following flags should be defined by the make file for support
+ of the features:
+
+ (1) EMAC_CACHE_WRITEBACK_MODE to support write back cache mode.
+
+ (2) EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY - to support of multiple
+ Tx complete notifications. If this is defined the Tx complete
+ DDA callback function contains multiple packet Tx complete
+ events. Note: BY DEFAULT THIS DRIVER HANDLES MULTIPLE TX
+ COMPLETE VIA ITS CALLBACK IN THE SAME FUNCTION FOR SINGLE
+ PACKET COMPLETE NOTIFY.
+
+
+ (3) CONFIG_EMAC_INIT_BUF_MALLOC - Not required for DaVinci driver
+ - feature was added for another TI platform
+
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/highmem.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/version.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <asm/page.h>
+#include <asm/arch/memory.h>
+#include <asm/arch/hardware.h>
+
+#include "davinci_emac_phy.h"
+
+/* ---------------------------------------------------------------
+ * linux module options
+ * --------------------------------------------------------------- */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Davinci EMAC Maintainer: Anant Gole <anantgole@ti.com>");
+MODULE_DESCRIPTION("DaVinci Ethernet driver - EMAC (EMAC)");
+
+static int cfg_link_speed = 0;
+module_param(cfg_link_speed, int, 0);
+MODULE_PARM_DESC(cfg_link_speed, "Fixed speed of the Link: <100/10>");
+
+static char *cfg_link_mode = "auto";
+module_param(cfg_link_mode, charp, 0);
+MODULE_PARM_DESC(cfg_link_mode, "Fixed mode of the Link: <fd/hd>");
+
+static int debug_mode = 0;
+module_param(debug_mode, int, 0);
+MODULE_PARM_DESC(debug_mode,
+ "Turn on the debug info: <0/1>. Default is 0 (off)");
+
+/* version info */
+#define EMAC_MAJOR_VERSION 4
+#define EMAC_MINOR_VERSION 0
+#define EMAC_MODULE_VERSION "4.0"
+MODULE_VERSION(EMAC_MODULE_VERSION);
+const char emac_version_string[] = "TI DaVinci EMAC Linux version updated 4.0";
+
+/* Debug options */
+#define EMAC_DEBUG
+#define EMAC_CACHE_WRITEBACK_MODE
+#define EMAC_CACHE_INVALIDATE_FIX
+
+/* ---------------------------------------------------------------
+ * types
+ * --------------------------------------------------------------- */
+#define TRUE ((bool) 1)
+#define FALSE ((bool) 0)
+
+typedef void *emac_net_data_token;
+
+/* ---------------------------------------------------------------
+ * defines
+ * --------------------------------------------------------------- */
+#define EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+
+/* NO PHY used in case of external ethernet switches */
+#define CONFIG_EMAC_NOPHY 9999
+
+/* DaVinci specific configuration */
+#define EMAC_BASE_ADDR IO_ADDRESS(DAVINCI_EMAC_CNTRL_REGS_BASE)
+#define EMAC_WRAPPER_REGS_ADDR IO_ADDRESS(DAVINCI_EMAC_WRAPPER_CNTRL_REGS_BASE)
+#define EMAC_WRAPPER_RAM_ADDR IO_ADDRESS(DAVINCI_EMAC_WRAPPER_RAM_BASE)
+#define EMAC_WRAPPER_RAM_SIZE (8 << 10)
+#define EMAC_MDIO_BASE_ADDR IO_ADDRESS(DAVINCI_MDIO_CNTRL_REGS_BASE)
+
+#define EMAC_INTERRUPT 13
+#define EMAC_BUS_FREQUENCY 76500000 /* PLL/6 i.e 76.5 MHz */
+#define EMAC_MDIO_FREQUENCY 2200000 /* PHY bus frequency */
+#define EMAC_PHY_MASK 0x2 /* PHY chip is located at address 1 */
+
+/* Note: For DaVinci, Buffer Descriptors are located in Wrapper RAM
+ * (4K). Half of the Wrapper memory is for RX BD's and other half for
+ * TX BD's
+ */
+#define EMAC_TX_BD_MEM EMAC_WRAPPER_RAM_ADDR
+#define EMAC_RX_BD_MEM (EMAC_WRAPPER_RAM_ADDR + (EMAC_WRAPPER_RAM_SIZE >> 1))
+
+/* feature macros here */
+
+/* If multi packet Tx complete notifications is enabled (via
+ EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY), Max number of Tx packets that
+ can be notified - the actual number will depend upon user
+ configuration for parameter "maxPktsToProcess" */
+#define EMAC_MAX_TX_COMPLETE_PKTS_TO_NOTIFY 8
+
+
+/* config macros */
+#define EMAC_MAX_INSTANCES 1
+#define EMAC_MIN_ETHERNET_PKT_SIZE 60
+
+/* max RX fragments calculation - 1500 byte packet and 64 byte
+ buffer. fragments=1500/64=24 */
+#define EMAC_MAX_RX_FRAGMENTS 24
+
+/* theoratically TX max fragments are equal to 24 */
+#define EMAC_MAX_TX_FRAGMENTS 8
+
+/* EMAC hardware specific */
+#define EMAC_RESET_CLOCKS_WAIT 64
+#define EMAC_MAX_TX_CHANNELS 8
+#define EMAC_MAX_RX_CHANNELS 8
+#define EMAC_MIN_FREQUENCY_FOR_10MBPS 5500000
+#define EMAC_MIN_FREQUENCY_FOR_100MBPS 55000000
+#define EMAC_MIN_FREQUENCY_FOR_1000MBPS 125000000
+
+/*
+ * The following are EMAC registers which have been removed from the
+ * CPGMAC register map. Thus we access them using macros to avoid
+ * having more CSL register overlay structures for older EMAC register
+ * map.
+ */
+
+/* statistics clear value */
+#define EMAC_NUM_STAT_REGS 36
+#define EMAC_STAT_CLEAR 0xFFFFFFFF
+
+/* EMAC all multicast set register value */
+#define EMAC_ALL_MULTI_REG_VALUE 0xFFFFFFFF
+
+/* EMAC number of multicast bits that can be set/cleared - currently
+ 64 bits - hash1/2 regs */
+#define EMAC_NUM_MULTICAST_BITS 64
+
+/* EMAC teardown value */
+#define EMAC_TEARDOWN_VALUE 0xFFFFFFFC
+
+/* TX / RX control bits */
+#define EMAC_TX_CONTROL_TX_ENABLE_VAL 0x1
+#define EMAC_RX_CONTROL_RX_ENABLE_VAL 0x1
+
+/* host interrupt bits */
+#define EMAC_MAC_HOST_ERR_INTMASK_VAL 0x2
+#define EMAC_MAC_STAT_INT_INTMASK_VAL 0x1
+
+/* rx config masks */
+#define EMAC_RX_UNICAST_CLEAR_ALL 0xFF
+
+/* type 0 address filtering macros */
+#define EMAC_TYPE_0_MACSRCADDR0_MASK (0xFF)
+#define EMAC_TYPE_0_MACSRCADDR0_SHIFT 0
+#define EMAC_TYPE_0_MACSRCADDR1_MASK (0xFF)
+#define EMAC_TYPE_0_MACSRCADDR1_SHIFT 0
+
+#define EMAC_TYPE_0_MACSRCADDR2_MASK (0xFF<<24)
+#define EMAC_TYPE_0_MACSRCADDR2_SHIFT 24
+#define EMAC_TYPE_0_MACSRCADDR3_MASK (0xFF<<16)
+#define EMAC_TYPE_0_MACSRCADDR3_SHIFT 16
+#define EMAC_TYPE_0_MACSRCADDR4_MASK (0xFF<<8)
+#define EMAC_TYPE_0_MACSRCADDR4_SHIFT 8
+#define EMAC_TYPE_0_MACSRCADDR5_MASK (0xFF)
+#define EMAC_TYPE_0_MACSRCADDR5_SHIFT 0
+
+/* type 1 address filtering macros */
+#define EMAC_TYPE_1_MACSRCADDR0_MASK (0xFF<<8)
+#define EMAC_TYPE_1_MACSRCADDR0_SHIFT 8
+#define EMAC_TYPE_1_MACSRCADDR1_MASK (0xFF)
+#define EMAC_TYPE_1_MACSRCADDR1_SHIFT 0
+
+#define EMAC_TYPE_1_MACSRCADDR2_MASK (0xFF<<24)
+#define EMAC_TYPE_1_MACSRCADDR2_SHIFT 24
+#define EMAC_TYPE_1_MACSRCADDR3_MASK (0xFF<<16)
+#define EMAC_TYPE_1_MACSRCADDR3_SHIFT 16
+#define EMAC_TYPE_1_MACSRCADDR4_MASK (0xFF<<8)
+#define EMAC_TYPE_1_MACSRCADDR4_SHIFT 8
+#define EMAC_TYPE_1_MACSRCADDR5_MASK (0xFF)
+#define EMAC_TYPE_1_MACSRCADDR5_SHIFT 0
+
+/* CP(G)MAC address filtering bit macros */
+#define CPGMAC_VALID_MASK (0x1<<20)
+#define CPGMAC_VALID_SHIFT 20
+#define CPGMAC_MATCH_FILTER_MASK (0x1<<19)
+#define CPGMAC_MATCH_FILTER_SHIFT 19
+#define CPGMAC_CHANNEL_MASK (0x7<<16)
+#define CPGMAC_CHANNEL_SHIFT 16
+#define CPGMAC_TYPE_2_3_MACSRCADDR0_MASK (0xFF<<8)
+#define CPGMAC_TYPE_2_3_MACSRCADDR0_SHIFT 8
+#define CPGMAC_TYPE_2_3_MACSRCADDR1_MASK (0xFF)
+#define CPGMAC_TYPE_2_3_MACSRCADDR1_SHIFT 0
+
+#define CPGMAC_TYPE_2_3_MACSRCADDR2_MASK (0xFF<<24)
+#define CPGMAC_TYPE_2_3_MACSRCADDR2_SHIFT 24
+#define CPGMAC_TYPE_2_3_MACSRCADDR3_MASK (0xFF<<16)
+#define CPGMAC_TYPE_2_3_MACSRCADDR3_SHIFT 16
+#define CPGMAC_TYPE_2_3_MACSRCADDR4_MASK (0xFF<<8)
+#define CPGMAC_TYPE_2_3_MACSRCADDR4_SHIFT 8
+#define CPGMAC_TYPE_2_3_MACSRCADDR5_MASK (0xFF)
+#define CPGMAC_TYPE_2_3_MACSRCADDR5_SHIFT 0
+
+/* RX MBP register bit positions */
+#define EMAC_RXMBP_PASSCRC_SHIFT 30
+#define EMAC_RXMBP_PASSCRC_MASK (0x1 << 30)
+#define EMAC_RXMBP_QOSEN_SHIFT 29
+#define EMAC_RXMBP_QOSEN_MASK (0x1 << 29)
+#define EMAC_RXMBP_NOCHAIN_SHIFT 28
+#define EMAC_RXMBP_NOCHAIN_MASK (0x1 << 28)
+#define EMAC_RXMBP_CMFEN_SHIFT 24
+#define EMAC_RXMBP_CMFEN_MASK (0x1 << 24)
+#define EMAC_RXMBP_CSFEN_SHIFT 23
+#define EMAC_RXMBP_CSFEN_MASK (0x1 << 23)
+#define EMAC_RXMBP_CEFEN_SHIFT 22
+#define EMAC_RXMBP_CEFEN_MASK (0x1 << 22)
+#define EMAC_RXMBP_CAFEN_SHIFT 21
+#define EMAC_RXMBP_CAFEN_MASK (0x1 << 21)
+#define EMAC_RXMBP_PROMCH_SHIFT 16
+#define EMAC_RXMBP_PROMCH_MASK (0x7 << 16)
+#define EMAC_RXMBP_BROADEN_SHIFT 13
+#define EMAC_RXMBP_BROADEN_MASK (0x1 << 13)
+#define EMAC_RXMBP_BROADCH_SHIFT 8
+#define EMAC_RXMBP_BROADCH_MASK (0x7 << 8)
+#define EMAC_RXMBP_MULTIEN_SHIFT 5
+#define EMAC_RXMBP_MULTIEN_MASK (0x1 << 5)
+#define EMAC_RXMBP_MULTICH_SHIFT 0
+#define EMAC_RXMBP_MULTICH_MASK 0x7
+
+#define EMAC_RXMBP_CHMASK 0x7
+
+/* mac control register bit fields */
+#define EMAC_MACCONTROL_TXSHORTGAPEN_SHIFT 10
+#define EMAC_MACCONTROL_TXSHORTGAPEN_MASK (0x1 << 10)
+#define EMAC_MACCONTROL_TXPTYPE_SHIFT 9
+#define EMAC_MACCONTROL_TXPTYPE_MASK (0x1 << 9)
+#define EMAC_MACCONTROL_GIGABITEN_SHIFT 7
+#define EMAC_MACCONTROL_GIGABITEN_MASK (0x1 << 7)
+#define EMAC_MACCONTROL_TXPACEEN_SHIFT 6
+#define EMAC_MACCONTROL_TXPACEEN_MASK (0x1 << 6)
+#define EMAC_MACCONTROL_MIIEN_SHIFT 5
+#define EMAC_MACCONTROL_MIIEN_MASK (0x1 << 5)
+#define EMAC_MACCONTROL_TXFLOWEN_SHIFT 4
+#define EMAC_MACCONTROL_TXFLOWEN_MASK (0x1 << 4)
+#define EMAC_MACCONTROL_RXFLOWEN_SHIFT 3
+#define EMAC_MACCONTROL_RXFLOWEN_MASK (0x1 << 3)
+#define EMAC_MACCONTROL_LOOPBKEN_SHIFT 1
+#define EMAC_MACCONTROL_LOOPBKEN_MASK (0x1 << 1)
+#define EMAC_MACCONTROL_FULLDUPLEXEN_SHIFT 0
+#define EMAC_MACCONTROL_FULLDUPLEXEN_MASK (0x1)
+
+/* mac_status register */
+#define EMAC_MACSTATUS_TXERRCODE_MASK 0xF00000
+#define EMAC_MACSTATUS_TXERRCODE_SHIFT 20
+#define EMAC_MACSTATUS_TXERRCH_MASK 0x7
+#define EMAC_MACSTATUS_TXERRCH_SHIFT 16
+#define EMAC_MACSTATUS_RXERRCODE_MASK 0xF000
+#define EMAC_MACSTATUS_RXERRCODE_SHIFT 12
+#define EMAC_MACSTATUS_RXERRCH_MASK 0x7
+#define EMAC_MACSTATUS_RXERRCH_SHIFT 8
+
+/* EMAC RX max packet length mask */
+#define EMAC_RX_MAX_LEN_SHIFT 0
+#define EMAC_RX_MAX_LEN_MASK 0xFFFF
+
+/* EMAC RX max packet length mask */
+#define EMAC_RX_BUFFER_OFFSET_SHIFT 0
+#define EMAC_RX_BUFFER_OFFSET_MASK 0xFFFF
+
+/* MAC_IN_VECTOR (0x180) register bit fields */
+#define EMAC_MAC_IN_VECTOR_HOST_INT (0x20000)
+#define EMAC_MAC_IN_VECTOR_STATPEND_INT (0x10000)
+#define EMAC_MAC_IN_VECTOR_RX_INT_VEC (0xFF00)
+#define EMAC_MAC_IN_VECTOR_TX_INT_VEC (0xFF)
+
+/* CPPI bit positions */
+#define EMAC_CPPI_SOP_BIT (1 << 31)
+#define EMAC_CPPI_EOP_BIT (1 << 30)
+#define EMAC_CPPI_OWNERSHIP_BIT (1 << 29)
+#define EMAC_CPPI_EOQ_BIT (1 << 28)
+#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT (1 << 27)
+#define EMAC_CPPI_PASS_CRC_BIT (1 << 26)
+
+/* defining the macro EMAC_INSTANCE_CODE to 0 so that it can be usable in DDA */
+#define EMAC_INSTANCE_CODE 0
+#define EMAC_ERROR_CODE (EMAC_INSTANCE_CODE << 16)
+#define EMAC_ERROR_INFO (EMAC_ERROR_CODE)
+#define EMAC_ERROR_WARNING (EMAC_ERROR_CODE | 0x10000000)
+#define EMAC_ERROR_MINOR (EMAC_ERROR_CODE | 0x20000000)
+#define EMAC_ERROR_MAJOR (EMAC_ERROR_CODE | 0x30000000)
+#define EMAC_ERROR_CRITICAL (EMAC_ERROR_CODE | 0x40000000)
+
+/* EMAC success code */
+#define EMAC_SUCCESS 0
+
+/* EMAC error codes */
+#define EMAC_ERR_DEV_ALREADY_INSTANTIATED(inst_id) \
+ (0x30000000 + ((inst_id) << 16))
+#define EMAC_ERR_DEV_NOT_INSTANTIATED (EMAC_ERROR_MAJOR + 1)
+#define EMAC_INVALID_PARAM (EMAC_ERROR_MAJOR + 2)
+#define EMAC_ERR_TX_CH_INVALID (EMAC_ERROR_CRITICAL + 3)
+#define EMAC_ERR_TX_CH_ALREADY_INIT (EMAC_ERROR_MAJOR + 4)
+#define EMAC_ERR_TX_CH_ALREADY_CLOSED (EMAC_ERROR_MAJOR + 5)
+#define EMAC_ERR_TX_CH_NOT_OPEN (EMAC_ERROR_MAJOR + 6)
+#define EMAC_ERR_TX_NO_LINK (EMAC_ERROR_MAJOR + 7)
+#define EMAC_ERR_TX_OUT_OF_BD (EMAC_ERROR_MAJOR + 8)
+#define EMAC_ERR_RX_CH_INVALID (EMAC_ERROR_CRITICAL + 9)
+#define EMAC_ERR_RX_CH_ALREADY_INIT (EMAC_ERROR_MAJOR + 10)
+#define EMAC_ERR_RX_CH_ALREADY_CLOSED (EMAC_ERROR_MAJOR + 11)
+#define EMAC_ERR_RX_CH_NOT_OPEN (EMAC_ERROR_MAJOR + 12)
+#define EMAC_ERR_DEV_ALREADY_CREATED (EMAC_ERROR_MAJOR + 13)
+#define EMAC_ERR_DEV_NOT_OPEN (EMAC_ERROR_MAJOR + 14)
+#define EMAC_ERR_DEV_ALREADY_CLOSED (EMAC_ERROR_MAJOR + 15)
+#define EMAC_ERR_DEV_ALREADY_OPEN (EMAC_ERROR_MAJOR + 16)
+#define EMAC_ERR_RX_BUFFER_ALLOC_FAIL (EMAC_ERROR_CRITICAL + 17)
+
+/*
+ * ioctls
+ */
+#define EMAC_IOCTL_BASE 0
+
+#define EMAC_IOCTL_GET_STATISTICS (EMAC_IOCTL_BASE + 0)
+#define EMAC_IOCTL_CLR_STATISTICS (EMAC_IOCTL_BASE + 1)
+#define EMAC_IOCTL_GET_SWVER (EMAC_IOCTL_BASE + 2)
+#define EMAC_IOCTL_GET_HWVER (EMAC_IOCTL_BASE + 3)
+#define EMAC_IOCTL_SET_RXCFG (EMAC_IOCTL_BASE + 4)
+#define EMAC_IOCTL_SET_MACCFG (EMAC_IOCTL_BASE + 5)
+#define EMAC_IOCTL_GET_STATUS (EMAC_IOCTL_BASE + 6)
+#define EMAC_IOCTL_READ_PHY_REG (EMAC_IOCTL_BASE + 7)
+#define EMAC_IOCTL_WRITE_PHY_REG (EMAC_IOCTL_BASE + 8)
+#define EMAC_IOCTL_MULTICAST_ADDR (EMAC_IOCTL_BASE + 9) /* add/delete */
+#define EMAC_IOCTL_ALL_MULTI (EMAC_IOCTL_BASE + 10) /* set/clear */
+#define EMAC_IOCTL_TYPE2_3_FILTERING (EMAC_IOCTL_BASE + 11)
+#define EMAC_IOCTL_SET_MAC_ADDRESS (EMAC_IOCTL_BASE + 12)
+#define EMAC_IOCTL_IF_COUNTERS (EMAC_IOCTL_BASE + 13)
+#define EMAC_IOCTL_ETHER_COUNTERS (EMAC_IOCTL_BASE + 14)
+#define EMAC_IOCTL_IF_PARAMS_UPDT (EMAC_IOCTL_BASE + 15)
+
+#define EMAC_IOCTL_TIMER_START (EMAC_IOCTL_BASE + 16)
+#define EMAC_IOCTL_TIMER_STOP (EMAC_IOCTL_BASE + 17)
+#define EMAC_IOCTL_STATUS_UPDATE (EMAC_IOCTL_BASE + 18)
+#define EMAC_IOCTL_MIB64_CNT_TIMER_START (EMAC_IOCTL_BASE + 19)
+#define EMAC_IOCTL_MIB64_CNT_TIMER_STOP (EMAC_IOCTL_BASE + 20)
+
+#define EMAC_PRIV_FILTERING (EMAC_IOCTL_BASE + 21)
+#define EMAC_PRIV_MII_READ (EMAC_IOCTL_BASE + 22)
+#define EMAC_PRIV_MII_WRITE (EMAC_IOCTL_BASE + 23)
+#define EMAC_PRIV_GET_STATS (EMAC_IOCTL_BASE + 24)
+#define EMAC_PRIV_CLR_STATS (EMAC_IOCTL_BASE + 25)
+#define EMAC_EXTERNAL_SWITCH (EMAC_IOCTL_BASE + 26)
+
+/*
+ * MII module port settings
+ *
+ * DDA sets the Phy mode as a combination of the following in "phyMode" parameter
+ * in the init configuration structure
+ */
+#define SNWAY_AUTOMDIX (1<<16) /* bit 16 and above not used by MII register */
+#define SNWAY_FD1000 (1<<13)
+#define SNWAY_HD1000 (1<<12)
+#define SNWAY_NOPHY (1<<10)
+#define SNWAY_LPBK (1<<9)
+#define SNWAY_FD100 (1<<8)
+#define SNWAY_HD100 (1<<7)
+#define SNWAY_FD10 (1<<6)
+#define SNWAY_HD10 (1<<5)
+#define SNWAY_AUTO (1<<0)
+#define SNWAY_AUTOALL (SNWAY_AUTO|SNWAY_FD100|SNWAY_FD10|SNWAY_HD100|SNWAY_HD10)
+
+/**
+ * DDC Status Ioctl - Error status
+ *
+ * Note that each error code is a bit position so that multiple
+ * errors can be clubbed together and passed in a integer value
+ */
+#define EMAC_NO_ERROR 0
+#define EMAC_TX_HOST_ERROR 0x1 /* MSB 8 bits: err code, channel no */
+#define EMAC_RX_HOST_ERROR 0x8 /* LSB 8 bits: err code, channel no */
+
+#define EGRESS_TRAILOR_LEN 0
+
+#define CFG_START_LINK_SPEED (SNWAY_AUTOALL) /* auto nego */
+
+/* defaut configuration values required for passing on to DDC */
+#define EMAC_DEFAULT_MLINK_MASK 0
+#define EMAC_DEFAULT_PASS_CRC FALSE
+#define EMAC_DEFAULT_QOS_ENABLE FALSE
+#define EMAC_DEFAULT_NO_BUFFER_CHAINING FALSE
+#define EMAC_DEFAULT_COPY_MAC_CONTROL_FRAMES_ENABLE FALSE
+#define EMAC_DEFAULT_COPY_SHORT_FRAMES_ENABLE FALSE
+#define EMAC_DEFAULT_COPY_ERROR_FRAMES_ENABLE FALSE
+#define EMAC_DEFAULT_PROMISCOUS_CHANNEL 0
+#define EMAC_DEFAULT_BROADCAST_CHANNEL 0
+#define EMAC_DEFAULT_MULTICAST_CHANNEL 0
+#define EMAC_DEFAULT_BUFFER_OFFSET 0
+#define EMAC_DEFAULT_TX_PRIO_TYPE EMAC_TXPRIO_FIXED
+#define EMAC_DEFAULT_TX_SHORT_GAP_ENABLE FALSE
+#define EMAC_DEFAULT_TX_PACING_ENABLE FALSE
+#define EMAC_DEFAULT_MII_ENABLE TRUE
+#define EMAC_DEFAULT_TX_FLOW_ENABLE FALSE
+#define EMAC_DEFAULT_RX_FLOW_ENABLE FALSE
+#define EMAC_DEFAULT_LOOPBACK_ENABLE FALSE
+#define EMAC_DEFAULT_FULL_DUPLEX_ENABLE TRUE
+#define EMAC_DEFAULT_TX_INTERRUPT_DISABLE TRUE
+#define CONFIG_EMAC_MIB_TIMER_TIMEOUT 5000 /* 5 seconds */
+
+#define EMAC_DEFAULT_PROMISCOUS_ENABLE 0
+#define EMAC_DEFAULT_BROADCAST_ENABLE 1
+#define EMAC_DEFAULT_MULTICAST_ENABLE 1
+
+/* NOT EXPLICIT SUPPORT PROVIDED AS OF NOW - vlan support in the driver */
+#define EMAC_DEFAULT_VLAN_ENABLE FALSE
+
+/* system value for ticks per seconds */
+#define EMAC_TICKS_PER_SEC HZ
+
+/* Extra bytes for Cache alignment of skbuf - should be equal to
+ * processor cache line size - in case of ARM926 its 32 bytes
+ */
+#define EMAC_DEFAULT_EXTRA_RXBUF_SIZE 32
+
+/* default max frame size = 1522 = 1500 byte data + 14 byte eth header
+ + 4 byte checksum + 4 byte vlan tag + 32 bytes for cache
+ alignment */
+#define EMAC_DEFAULT_MAX_FRAME_SIZE (1500 + 14 + 4 + 4 + EGRESS_TRAILOR_LEN + EMAC_DEFAULT_EXTRA_RXBUF_SIZE)
+
+/* default number of TX channels */
+#define EMAC_DEFAULT_NUM_TX_CHANNELS 1
+
+/* default TX channel number */
+#define EMAC_DEFAULT_TX_CHANNEL 0
+
+/* default TX number of BD's/buffers */
+#define EMAC_DEFAULT_TX_NUM_BD 128
+
+/* default TX max service BD's */
+#define EMAC_DEFAULT_TX_MAX_SERVICE 32
+
+/* default number of RX channels */
+#define EMAC_DEFAULT_NUM_RX_CHANNELS 1
+
+/* default RX channel number */
+#define EMAC_DEFAULT_RX_CHANNEL 0
+
+#define EMAC_DEFAULT_RX_NUM_BD 128
+
+/* default RX max service BD's */
+#define EMAC_DEFAULT_RX_MAX_SERVICE 32 /* should = netdev->weight */
+
+#if ((EMAC_DEFAULT_TX_NUM_BD +EMAC_DEFAULT_RX_NUM_BD) > 256)
+#error "Error. DaVinci has space for no more than 256 TX+RX BD's"
+#endif
+
+/*
+ * Size of EMAC peripheral footprint in memory that needs to be
+ * reserved in Linux Note that this value is actually a hardware
+ * memory footprint value taken from the specs and ideally should have
+ * been in the csl files. Keeping it for convinience since EMAC
+ * peripheral footprint will not change unless the peripheral itself
+ * changes drastically and it will be called with a different name and
+ * will have a different driver anyway
+ *
+ * For Davinci size = control regs (4k) + wrapper regs (4k) + wrapper
+ * RAM (8k) + mdio regs (2k)
+ */
+#define EMAC_DEFAULT_EMAC_SIZE 0x4800
+
+/* ENV variable names for obtaining MAC addresses */
+#define EMAC_MAC_ADDR_A "maca"
+#define EMAC_MAC_ADDR_B "macb"
+#define EMAC_MAC_ADDR_C "macc"
+#define EMAC_MAC_ADDR_D "macd"
+#define EMAC_MAC_ADDR_E "mace"
+#define EMAC_MAC_ADDR_F "macf"
+
+/* Maximum multicast addresses list to be handled by the driver - If
+ * this is not restricted then the driver will spend considerable time
+ * in handling multicast lists
+ */
+#define EMAC_DEFAULT_MAX_MULTICAST_ADDRESSES 64
+
+#define NETDEV_PRIV(net_dev) netdev_priv(net_dev)
+#define FREE_NETDEV(net_dev) free_netdev(net_dev)
+
+#define dbg_print if (emac_debug_mode) printk
+#define err_print printk
+
+/* misc error codes */
+#define EMAC_INTERNAL_FAILURE -1
+
+/* LED codes required for controlling LED's */
+#define EMAC_LINK_OFF 0
+#define EMAC_LINK_ON 1
+#define EMAC_SPEED_100 2
+#define EMAC_SPEED_10 3
+#define EMAC_FULL_DPLX 4
+#define EMAC_HALF_DPLX 5
+#define EMAC_TX_ACTIVITY 6
+#define EMAC_RX_ACTIVITY 7
+
+/*
+ * L3 Alignment mechanism: The below given macro returns the number of
+ * bytes required to align the given size to a L3 frame 4 byte
+ * boundry. This is typically required to add 2 bytes to the ethernet
+ * frame start to make sure the IP header (L3) is aligned on a 4 byte
+ * boundry
+ */
+static char emac_L3_align[] = { 0x02, 0x01, 0x00, 0x03 };
+
+#define EMAC_L3_ALIGN(size) emac_L3_align[(size) & 0x3]
+
+/* 4 Byte alignment for skb's:
+ *
+ * Currently Skb's dont need to be on a 4 byte boundry, but other OS's
+ * have such requirements Just to make sure we comply if there is any
+ * such requirement on SKB's in future, we align it on a 4 byte
+ * boundry.
+ */
+char emac_4byte_align[] = { 0x0, 0x03, 0x02, 0x1 };
+
+#define EMAC_4BYTE_ALIGN(size) emac_4byte_align[(size) & 0x3]
+
+#define EMAC_DEBUG_FUNCTION_ENTRY (0x1 << 1)
+#define EMAC_DEBUG_FUNCTION_EXIT (0x1 << 2)
+#define EMAC_DEBUG_BUSY_FUNCTION_ENTRY (0x1 << 3)
+#define EMAC_DEBUG_BUSY_FUNCTION_EXIT (0x1 << 4)
+#define EMAC_DEBUG_TX (0x1 << 6)
+#define EMAC_DEBUG_RX (0x1 << 7)
+#define EMAC_DEBUG_PORT_UPDATE (0x1 << 8)
+#define EMAC_DEBUG_MII (0x1 << 9)
+#define EMAC_DEBUG_TEARDOWN (0x1 << 10)
+
+/* Debug flags
+ *
+ * IMPORTANT NOTE: The debug flags need to be enabled carefully as it
+ * could flood the console/sink point of the debug traces and also
+ * affect the functionality of the overall system
+ */
+#ifdef EMAC_DEBUG
+#define LOG(lvl, format, args...) \
+ printk(lvl "%s:%d[%d]" format, __FUNCTION__, __LINE__, \
+ dev->init_cfg.inst_id, ##args)
+#define LOGERR(format, args...) LOG(KERN_ERR, format, ##args)
+#define LOGMSG(flag, format, args... ) \
+ do { if (flag & emac_debug) LOG(KERN_DEBUG, #flag format, ##args); } while(0)
+#define DBG(format, args...) \
+ if (emac_debug_mode) printk(KERN_DEBUG "davinci_emac: " format, ##args)
+#define ERR(format, args...) \
+ printk(KERN_ERR "ERROR: davinci_emac: " format, ##args)
+
+#else
+#define LOGERR(format, args...)
+#define LOGMSG(flag, format, args... )
+#endif
+
+/* DDC internal macros */
+#define EMAC_RX_BD_BUF_SIZE 0xFFFF;
+#define EMAC_BD_LENGTH_FOR_CACHE 16 /* only CPPI bytes */
+#define EMAC_RX_BD_PKT_LENGTH_MASK 0xFFFF
+
+#define CFG_START_LINK_SPEED (SNWAY_AUTOALL) /* auto nego */
+
+/* defaut configuration values required for passing on to DDC */
+#define EMAC_DEFAULT_MLINK_MASK 0
+#define EMAC_DEFAULT_PASS_CRC FALSE
+#define EMAC_DEFAULT_QOS_ENABLE FALSE
+#define EMAC_DEFAULT_NO_BUFFER_CHAINING FALSE
+#define EMAC_DEFAULT_COPY_MAC_CONTROL_FRAMES_ENABLE FALSE
+#define EMAC_DEFAULT_COPY_SHORT_FRAMES_ENABLE FALSE
+#define EMAC_DEFAULT_COPY_ERROR_FRAMES_ENABLE FALSE
+#define EMAC_DEFAULT_PROMISCOUS_CHANNEL 0
+#define EMAC_DEFAULT_BROADCAST_CHANNEL 0
+#define EMAC_DEFAULT_MULTICAST_CHANNEL 0
+#define EMAC_DEFAULT_BUFFER_OFFSET 0
+#define EMAC_DEFAULT_TX_PRIO_TYPE EMAC_TXPRIO_FIXED
+#define EMAC_DEFAULT_TX_SHORT_GAP_ENABLE FALSE
+#define EMAC_DEFAULT_TX_PACING_ENABLE FALSE
+#define EMAC_DEFAULT_MII_ENABLE TRUE
+#define EMAC_DEFAULT_TX_FLOW_ENABLE FALSE
+#define EMAC_DEFAULT_RX_FLOW_ENABLE FALSE
+#define EMAC_DEFAULT_LOOPBACK_ENABLE FALSE
+#define EMAC_DEFAULT_FULL_DUPLEX_ENABLE TRUE
+#define EMAC_DEFAULT_TX_INTERRUPT_DISABLE TRUE
+#define CONFIG_EMAC_MIB_TIMER_TIMEOUT 5000 /* 5 sec */
+
+#define EMAC_DEFAULT_PROMISCOUS_ENABLE 0
+#define EMAC_DEFAULT_BROADCAST_ENABLE 1
+#define EMAC_DEFAULT_MULTICAST_ENABLE 1
+
+/* ---------------------------------------------------------------
+ * structs, enums
+ * --------------------------------------------------------------- */
+typedef enum {
+ DRV_CREATED,
+ DRV_INITIALIZED,
+ DRV_OPENED,
+ DRV_CLOSED,
+ DRV_DEINITIALIZED,
+ DRV_POWERED_DOWN,
+} emac_drv_state;
+
+/**
+ * Network Buffer Object
+ *
+ * Holds attributes of a buffer/fragment
+ *
+ * Send: Usually when the buffers are allocated by DDA, the
+ * Start of Packet token will be the handle to the whole packet. This
+ * token/handle should be good enough to free the packet or return to
+ * its pool. When the buffers are allocated by DDC, typically token
+ * for each buffer needs to be indicated (TxComplete) rather than
+ * only the Start of Packet token.
+ *
+ * Receive: For each buffer the token will be a handle to the buffer
+ * that can be used by the allocater (DDA or DDC) of the buffer to
+ * free it or return to a pool.
+ */
+typedef struct {
+ emac_net_data_token buf_token;
+ char *data_ptr;
+ int length;
+} net_buf_obj;
+
+/**
+ * Network Packet Object
+ *
+ * Holds attributes of a network packet (NetBufObjs and packet size).
+ */
+typedef struct {
+ emac_net_data_token pkt_token; /* data token may hold tx/rx chan id */
+ net_buf_obj *buf_list; /* array of network buffer objects */
+ int num_bufs; /* number of network buffer objects */
+ int pkt_length; /* packet length (number of bytes) */
+} net_pkt_obj;
+
+/**
+ * Net Channel State
+ *
+ * State of the channel (initialized, about to be closed, closed etc
+ */
+typedef enum {
+ NET_CH_DIR_TX = 0, /* transmit only */
+ NET_CH_DIR_RX, /* receive only */
+ NET_CH_DIR_BIDIRECTIONAL, /* bidirectonaly - TX/RX */
+ NET_CH_DIR_UNDEFINED /* not defined */
+} net_ch_dir;
+
+/**
+ * Net Channel State
+ *
+ * State of the channel (initialized, about to be closed, closed etc
+ */
+typedef enum {
+ NET_CH_UNINITIALIZED = 0,
+ NET_CH_INITIALIZED,
+ NET_CH_OPENED,
+ NET_CH_CLOSE_IN_PROGRESS,
+ NET_CH_CLOSED
+} net_ch_state;
+
+/**
+ * EMAC Peripheral Device Register Memory Layout structure
+ *
+ * The structure instance variable points to CP(G)MAC register space in
+ * SOC memory map directly.
+ * This is a template only, no memory is ever allocated for this!
+ */
+typedef struct {
+ u32 tx_id_ver;
+ u32 tx_control;
+ u32 tx_teardown;
+ u32 reserved1;
+ u32 rx_id_ver;
+ u32 rx_control;
+ u32 rx_teardown;
+ u32 pad2[25];
+ u32 tx_int_stat_raw;
+ u32 tx_int_stat_masked;
+ u32 tx_int_mask_set;
+ u32 tx_int_mask_clear;
+ u32 mac_in_vector;
+ u32 mac_EOI_vector;
+ u32 pad3[2];
+ u32 rx_int_stat_raw;
+ u32 rx_int_stat_masked;
+ u32 rx_int_mask_set;
+ u32 rx_int_mask_clear;
+ u32 mac_int_stat_raw;
+ u32 mac_int_stat_masked;
+ u32 mac_int_mask_set;
+ u32 mac_int_mask_clear;
+ u32 pad4[16];
+ u32 rx_MBP_enable;
+ u32 rx_unicast_set;
+ u32 rx_unicast_clear;
+ u32 rx_maxlen;
+ u32 rx_buffer_offset;
+ u32 rx_filter_low_thresh;
+ u32 pad5[2];
+ u32 rx_flow_thresh[8];
+ u32 rx_free_buffer[8];
+ u32 mac_control;
+ u32 mac_status;
+ u32 EMControl;
+ u32 fifo_control; /* CP(G)MAC added register */
+ u32 mac_cfig; /* CP(G)MAC added register */
+ u32 soft_reset; /* CP(G)MAC 2.6 added register */
+ u32 pad6[22];
+ u32 mac_src_addr_lo; /* CP(G)MAC modified register */
+ u32 mac_src_addr_hi; /* CP(G)MAC modified register */
+ u32 mac_hash1;
+ u32 mac_hash2;
+ u32 boff_test;
+ u32 tpace_test; /* CP(G)MAC modified register */
+ u32 rx_pause;
+ u32 tx_pause;
+ u32 pad7[4];
+ u32 rx_good_frames;
+ u32 rx_broadcast_frames;
+ u32 rx_multicast_frames;
+ u32 rx_pause_frames;
+ u32 rx_crcerrors;
+ u32 rx_align_code_errors;
+ u32 rx_oversized_frames;
+ u32 rx_jabber_frames;
+ u32 rx_undersized_frames;
+ u32 rx_fragments;
+ u32 rx_filtered_frames;
+ u32 rx_qos_filtered_frames;
+ u32 rx_octets;
+ u32 tx_good_frames;
+ u32 tx_broadcast_frames;
+ u32 tx_multicast_frames;
+ u32 tx_pause_frames;
+ u32 tx_deferred_frames;
+ u32 tx_collision_frames;
+ u32 tx_single_coll_frames;
+ u32 tx_mult_coll_frames;
+ u32 tx_excessive_collisions;
+ u32 tx_late_collisions;
+ u32 tx_underrun;
+ u32 tx_carrier_sense_errors;
+ u32 tx_octets;
+ u32 reg64octet_frames;
+ u32 reg65t127octet_frames;
+ u32 reg128t255octet_frames;
+ u32 reg256t511octet_frames;
+ u32 reg512t1023octet_frames;
+ u32 reg1024t_upoctet_frames;
+ u32 net_octets;
+ u32 rx_sof_overruns;
+ u32 rx_mof_overruns;
+ u32 rx_dma_overruns;
+ u32 pad8[156]; /* CP(G)MAC modified register */
+ u32 mac_addr_lo; /* CP(G)MAC added register */
+ u32 mac_addr_hi; /* CP(G)MAC added register */
+ u32 mac_index; /* CP(G)MAC added register */
+ u32 pad9[61]; /* CP(G)MAC modified register */
+ u32 tx_HDP[8];
+ u32 rx_HDP[8];
+ u32 tx_CP[8];
+ u32 rx_CP[8];
+} emac_regs;
+typedef volatile emac_regs *emac_regs_ovly;
+
+/**
+ * EMAC Peripheral Device Register Enumerations
+ */
+typedef enum {
+ tx_id_ver = 0,
+ tx_control,
+ tx_teardown,
+ rx_id_ver = 4,
+ rx_control,
+ rx_teardown,
+ rx_MBP_enable = 64,
+ rx_unicast_set,
+ rx_unicast_clear,
+ rx_maxlen,
+ rx_buffer_offset,
+
+ rx_filter_low_thresh,
+ rx0_flow_thresh = 72,
+ rx1_flow_thresh,
+ rx2_flow_thresh,
+ rx3_flow_thresh,
+ rx4_flow_thresh,
+
+ rx5_flow_thresh,
+ rx6_flow_thresh,
+ rx7_flow_thresh,
+ rx0_free_buffer,
+
+ rx1_free_buffer,
+ rx2_free_buffer,
+ rx3_free_buffer,
+ rx4_free_buffer,
+
+ rx5_free_buffer,
+ rx6_free_buffer,
+ rx7_free_buffer,
+ mac_control,
+ mac_status,
+
+ EMControl,
+ tx_fifo_control,
+ tx_int_stat_raw,
+ tx_int_stat_masked,
+
+ tx_int_mask_set,
+ tx_int_mask_clear,
+ mac_in_vector,
+ mac_EOI_vector,
+ mac_cfig,
+
+ rx_int_stat_raw = 100,
+ rx_int_stat_masked,
+ rx_int_mask_set,
+ rx_int_mask_clear,
+ mac_int_stat_raw,
+
+ mac_int_stat_masked,
+ mac_int_mask_set,
+ mac_int_mask_clear,
+ mac_src_addr_lo = 116,
+ mac_src_addr_hi,
+ mac_hash1,
+ mac_hash2,
+ boff_test,
+ tpace_test,
+ rx_pause,
+
+ tx_pause,
+ rx_good_frames = 128,
+ rx_broadcast_frames,
+ rx_multicast_frames,
+ rx_pause_frames,
+ rx_crcerrors,
+
+ rx_align_code_errors,
+ rx_oversized_frames,
+ rx_jabber_frames,
+ rx_undersized_frames,
+
+ rx_fragments,
+ rx_filtered_frames,
+ rx_qos_filtered_frames,
+ rx_octets,
+
+ tx_good_frames,
+ tx_broadcast_frames,
+ tx_multicast_frames,
+ tx_pause_frames,
+
+ tx_deferred_frames,
+ tx_collision_frames,
+ tx_single_coll_frames,
+ tx_mult_coll_frames,
+
+ tx_excessive_collisions,
+ tx_late_collisions,
+ tx_underrun,
+ tx_carrier_sense_errors,
+
+ tx_octets,
+ reg64octet_frames,
+ reg65t127octet_frames,
+ reg128t255octet_frames,
+
+ reg256t511octet_frames,
+ reg512t1023octet_frames,
+ reg1024t_upoctet_frames,
+
+ net_octets,
+ rx_sof_overruns,
+ rx_mof_overruns,
+ rx_dma_overruns,
+
+ RX_FIFO_processor_test_access = 192, /* first word of RX FIFO */
+ TX_FIFO_processor_test_access = 256, /* first word of TX FIFO */
+ mac_addr_lo = 320,
+ mac_addr_hi,
+ mac_index,
+ tx0_HDP = 384,
+ tx1_HDP,
+ tx2_HDP,
+ tx3_HDP,
+ tx4_HDP,
+ tx5_HDP,
+ tx6_HDP,
+
+ tx7_HDP,
+ rx0_HDP,
+ rx1_HDP,
+ rx2_HDP,
+ rx3_HDP,
+ rx4_HDP,
+
+ rx5_HDP,
+ rx6_HDP,
+ rx7_HDP,
+ tx0_CP,
+ tx1_CP,
+ tx2_CP,
+ tx3_CP,
+
+ tx4_CP,
+ tx5_CP,
+ tx6_CP,
+ tx7_CP,
+ rx0_CP,
+ rx1_CP,
+ rx2_CP,
+
+ rx3_CP,
+ rx4_CP,
+ rx5_CP,
+ rx6_CP,
+ rx7_CP,
+ stateram_test_access = 448 /* first word of state RAM */
+} emac_reg_ids;
+
+/**
+ * EMAC Addressing Type
+ *
+ * Addressing type based upon cfig register. For EMAC peripheral cfig
+ * register reads a value of 0 i.e Type 0 addressing
+ */
+typedef enum {
+ RX_ADDR_TYPE0 = 0, /* old style used in (EMAC) */
+ RX_ADDR_TYPE1 = 1, /* new CPGMAC style */
+ RX_ADDR_TYPE2 = 2, /* new CPGMAC "filtering" style */
+ RX_ADDR_TYPE3 = 3 /* new CPGMAC "filtering" style */
+} emac_rx_addr_type;
+
+/**
+ * EMAC Single Multicast Ioctl - EMAC_IOCTL_MULTICAST_ADDR operations
+ *
+ * Add/Del operations for adding/deleting a single multicast address
+ */
+typedef enum {
+ EMAC_MULTICAST_ADD = 0,
+ EMAC_MULTICAST_DEL
+} emac_single_multi_oper;
+
+/**
+ * EMAC All Multicast Ioctl - EMAC_IOCTL_ALL_MULTI operations
+ *
+ * Set/Clear all multicast operation
+ */
+typedef enum {
+ EMAC_ALL_MULTI_SET = 0,
+ EMAC_ALL_MULTI_CLR
+} emac_all_multi_oper;
+
+/**
+ * MII Read/Write PHY register
+ *
+ * Parameters to read/write a PHY register via MII interface
+ */
+typedef struct {
+ u32 phy_num; /* phy number to be read/written */
+ u32 reg_addr; /* register to be read/written */
+ u32 data; /* data to be read/written */
+} emac_phy_params;
+
+/**
+ * MAC Address params
+ *
+ * Parameters for Configuring Mac address
+ */
+typedef struct {
+ u32 channel;
+ char *mac_address;
+} emac_address_params;
+
+/**
+ * Type 2/3 Addressing
+ *
+ * Parameters for programming CFIG 2/3 addressing mode
+ *
+ */
+typedef struct {
+ u32 channel; /* channel to which this filtering params apply */
+ char *mac_address; /* mac address for filtering */
+ int index; /* index of filtering list to update */
+ bool valid; /* entry valid */
+ int match; /* entry matching */
+} emac_type2_3_addr_filter_params;
+
+/**
+ * EMAC Hardware Statistics
+ *
+ * Statistics counters provided by EMAC Hardware. The names of the
+ * counters in this structure are of "MIB style" and corrospond
+ * directly to the hardware counters provided by EMAC
+ */
+typedef struct {
+ u32 if_in_good_frames;
+ u32 if_in_broadcasts;
+ u32 if_in_multicasts;
+ u32 if_in_pause_frames;
+ u32 if_in_crcerrors;
+ u32 if_in_align_code_errors;
+ u32 if_in_oversized_frames;
+ u32 if_in_jabber_frames;
+ u32 if_in_undersized_frames;
+ u32 if_in_fragments;
+ u32 if_in_filtered_frames;
+ u32 if_in_qos_filtered_frames;
+ u32 if_in_octets;
+ u32 if_out_good_frames;
+ u32 if_out_broadcasts;
+ u32 if_out_multicasts;
+ u32 if_out_pause_frames;
+ u32 if_deferred_transmissions;
+ u32 if_collision_frames;
+ u32 if_single_collision_frames;
+ u32 if_multiple_collision_frames;
+ u32 if_excessive_collision_frames;
+ u32 if_late_collisions;
+ u32 if_out_underrun;
+ u32 if_carrier_sense_errors;
+ u32 if_out_octets;
+ u32 if64octet_frames;
+ u32 if65to127octet_frames;
+ u32 if128to255octet_frames;
+ u32 if256to511octet_frames;
+ u32 if512to1023octet_frames;
+ u32 if1024to_upoctet_frames;
+ u32 if_net_octets;
+ u32 if_rx_sof_overruns;
+ u32 if_rx_mof_overruns;
+ u32 if_rx_dmaoverruns;
+} emac_hw_statistics;
+
+/**************************************************************************
+ * MIB-2 Common MIB Constants *
+ **************************************************************************/
+#define MIB2_TRUTH_VALUE_TRUE 1
+#define MIB2_TRUTH_VALUE_FALSE 2
+
+/* MIB-2 interface admin/oper status values */
+/* device is in operational status unless status is down. */
+#define MIB2_STATUS_UP 1
+#define MIB2_STATUS_DOWN 2
+#define MIB2_STATUS_TEST 3
+#define MIB2_STATUS_UNKNOWN 4
+#define MIB2_STATUS_DORMANT 5
+
+#define TI_SIOC_OFFSET 0
+
+/* definitions for interface group MIB variables: GET */
+#define TI_SIOCGINTFCOUNTERS (TI_SIOC_OFFSET) + 0x01
+#define TI_SIOCGINTFPARAMS (TI_SIOC_OFFSET) + 0x02
+
+/* SET command definitions */
+#define TI_SIOCSINTFADMINSTATUS (TI_SIOC_OFFSET) + 0x03
+
+/* definitions for ether-like group MIB variables: GET */
+#define TI_SIOCGETHERCOUNTERS (TI_SIOC_OFFSET) + 0x04
+#define TI_SIOCGETHERPARAMS (TI_SIOC_OFFSET) + 0x05
+
+/* defines MIB II INTERFACE objects */
+struct mib2_if_counters {
+ unsigned long in_bytes_low;
+ unsigned long in_bytes_high;
+ unsigned long in_unicast_pkts_low;
+ unsigned long in_unicast_pkts_high;
+ unsigned long in_multicast_pkts_low;
+ unsigned long in_multicast_pkts_high;
+ unsigned long in_broadcast_pkts_low;
+ unsigned long in_broadcast_pkts_high;
+ unsigned long in_discard_pkts;
+ unsigned long in_error_pkts;
+ unsigned long in_unknown_prot_pkts;
+ unsigned long out_bytes_low;
+ unsigned long out_bytes_high;
+ unsigned long out_unicast_pkts_low;
+ unsigned long out_unicast_pkts_high;
+ unsigned long out_multicast_pkts_low;
+ unsigned long out_multicast_pkts_high;
+ unsigned long out_broadcast_pkts_low;
+ unsigned long out_broadcast_pkts_high;
+ unsigned long out_discard_pkts;
+ unsigned long out_error_pkts;
+};
+
+struct mib2_if_hccounters {
+ struct mib2_if_counters mib2if_counter;
+ unsigned long long in_bytes_hc;
+ unsigned long long in_unicast_pkts_hc;
+ unsigned long long in_multicast_pkts_hc;
+ unsigned long long in_broadcast_pkts_hc;
+ unsigned long long out_bytes_hc;
+ unsigned long long out_unicast_pkts_hc;
+ unsigned long long out_multicast_pkts_hc;
+ unsigned long long out_broadcast_pkts_hc;
+ unsigned long long in_bytes;
+ unsigned long long in_unicast_pkts;
+ unsigned long long in_multicast_pkts;
+ unsigned long long in_broadcast_pkts;
+ unsigned long long out_bytes;
+ unsigned long long out_unicast_pkts;
+ unsigned long long out_multicast_pkts;
+ unsigned long long out_broadcast_pkts;
+};
+
+struct mib2_if_params {
+ unsigned long if_speed; /* speed in bits per second */
+ unsigned long if_high_speed; /* speed in mega-bits per second */
+ long if_oper_status;
+ long if_promiscuous_mode;
+};
+
+struct mib2_if_command {
+ long if_admin_status; /* desired interface state */
+};
+
+/* ether_like-MIB constants */
+#define MIB2_UNKNOWN_DUPLEX 1
+#define MIB2_HALF_DUPLEX 2
+#define MIB2_FULL_DUPLEX 3
+
+/* ioctl/cmd value to be used by snmpd like applications */
+#define SIOTIMIB2 SIOCDEVPRIVATE + 1
+
+/* defines MIB II ether_like-MIB objects */
+struct mib2_phy_counters {
+ unsigned long eth_alignment_errors;
+ unsigned long eth_fcserrors;
+ unsigned long eth_single_collisions;
+ unsigned long eth_multiple_collisions;
+ unsigned long eth_sqetest_errors;
+ unsigned long eth_deferred_tx_frames;
+ unsigned long eth_late_collisions;
+ unsigned long eth_excessive_collisions;
+ unsigned long eth_internal_mac_tx_errors;
+ unsigned long eth_carrier_sense_errors;
+ unsigned long eth_too_long_rx_frames;
+ unsigned long eth_internal_mac_rx_errors;
+ unsigned long eth_symbol_errors;
+};
+
+struct mib2_eth_params {
+ long eth_duplex_status; /* current emac duplex status */
+};
+
+typedef struct {
+ unsigned long cmd;
+ unsigned long port;
+ void *data;
+} TI_SNMP_CMD_T;
+
+/**
+ * DDC Status values
+ *
+ * Provides status of the device - error status, phy status etc
+ *
+ */
+typedef struct {
+ u32 hw_status;
+ u32 hw_err_info;
+ u32 phy_linked; /* link status: 1=linked, 0=no link */
+ u32 phy_duplex; /* duplex status: 3=full duplex, 2=half duplex */
+
+ u32 phy_speed; /* link speed = 10, 100, 1000 */
+ u32 phy_num; /* phy number - useful if phy number is discovered */
+} emac_status;
+
+/**
+ * EMAC Channel Config Info
+ *
+ * Common to both TX/RX
+ * Used to pass channel config info from DDA to DDC for EMAC channels
+ */
+typedef struct {
+ int ch_num; /* DDC_net_ch_info: channel number */
+ net_ch_dir ch_dir; /* DDC_net_ch_info: channel direction */
+ net_ch_state ch_state; /* DDC_net_ch_info: channel state */
+ int num_bd; /* number of BD (& buffers for RX) */
+ int service_max; /* maximum BD's processed in one go */
+ int buf_size; /* buffer size (applicable for RX only) */
+} emac_ch_info;
+
+/**
+ * EMAC RX configuration
+ *
+ * This data structure configures the RX module of the device
+ */
+typedef struct {
+ bool pass_crc; /* pass CRC bytes to packet memory */
+ bool qos_enable; /* receive qo_s enable ? */
+ bool no_buffer_chaining; /* DEBUG ONLY - ALWAYS SET TO FALSE */
+ bool copy_maccontrol_frames_enable;
+ bool copy_short_frames_enable;
+ bool copy_error_frames_enable;
+ bool promiscous_enable;
+ u32 promiscous_channel; /* promiscous receive channel */
+ bool broadcast_enable; /* receive broadcast frames ? */
+ u32 broadcast_channel; /* broadcast receive channel */
+ bool multicast_enable; /* receive multicast frames ? */
+ u32 multicast_channel; /* multicast receive channel */
+ u32 max_rx_pkt_length; /* max receive packet length */
+ u32 buffer_offset; /* buffer offset for all RX channels */
+} emac_rx_config;
+
+/**
+ * Transmit Queue priority type
+ *
+ * Enums for transmit queue priority type - fixed/round robin
+ * available in hardware
+ */
+typedef enum {
+ EMAC_TXPRIO_ROUND_ROBIN = 0,
+ EMAC_TXPRIO_FIXED = 1
+} emac_tx_queue_priority_type;
+
+/**
+ * EMAC MAC configuration
+ *
+ * This data structure configures the MAC module parameters of the device
+ */
+typedef struct {
+ emac_tx_queue_priority_type p_type;
+ bool tx_short_gap_enable;
+ bool giga_bit_enable;
+ bool tx_pacing_enable;
+ bool mii_enable; /* DEBUG ONLY - ALWAYS SET TO TRUE */
+ bool tx_flow_enable;
+ bool rx_flow_enable;
+ bool loopback_enable;
+ bool full_duplex_enable; /* DEBUG ONLY - based upon phy_mode */
+ bool tx_interrupt_disable;
+} emac_mac_config;
+
+/**
+ * EMAC Init Configuration
+ *
+ * Configuration information provided to DDC layer during
+ * initialization. DDA gets the config information from the OS/PAL
+ * layer and passes the relevant config to the DDC during
+ * initialization. The config info can come from various sources -
+ * static compiled in info, boot time (ENV, Flash) info etc.
+ */
+typedef struct {
+ u32 inst_id;
+ u32 num_tx_channels;
+ u32 num_rx_channels;
+ u32 emac_bus_frequency;
+ u32 base_address;
+ u32 e_wrap_base_address;
+ u32 intr_line;
+ u32 reset_line;
+ u32 mdio_base_address;
+ u32 mdio_reset_line;
+ u32 mdio_intr_line;
+ u32 phy_mask;
+ u32 MLink_mask;
+ u32 mdio_bus_frequency;
+ u32 mdio_clock_frequency;
+ u32 mdio_tick_msec;
+ u32 mib64cnt_msec;
+ u32 phy_mode;
+ emac_rx_config rx_cfg;
+ emac_mac_config mac_cfg;
+} emac_init_config;
+
+typedef struct {
+ u32 rx_pkts; /* number of rx pkts to be processed */
+ u32 tx_pkts; /* number of tx pkts to be processed */
+ u32 ret_rx_pkts; /* number of rx pkts processed */
+ u32 ret_tx_pkts; /* number of tx pkts processed */
+} rx_tx_params;
+
+/*
+ * EMAC Private Ioctl Structure
+ *
+ * Private Ioctl commands provided by the EMAC Linux Driver use this
+ * structure
+ */
+typedef struct {
+ unsigned int cmd;
+ void *data;
+} emac_drv_priv_ioctl;
+
+/*
+ * EMAC DDA maintained statistics
+ *
+ * Driver maintained statistics (apart from Hardware statistics)
+ */
+typedef struct {
+ unsigned long tx_discards;
+ unsigned long rx_discards;
+ unsigned long start_tick;
+} emac_drv_stats;
+
+/**************************************************************************
+ * Register Overlay Structure
+ **************************************************************************/
+typedef struct {
+ u32 RSVD0;
+ u32 EWCTL;
+ u32 EWINTTCNT;
+} ewrap_regs;
+
+/*
+ * TX Buffer Descriptor
+ *
+ * CPPI 3.0 TX BD structure specific to EMAC.
+ */
+typedef struct {
+ int h_next; /* next buffer descriptor pointer */
+ int buff_ptr; /* data buffer pointer */
+ int off_b_len; /* (buffer_offset_16)(buffer_length_16) */
+ int mode; /* SOP, EOP, ownership, EOQ, teardown,
+ * Qstarv, length */
+ void *next; /* next TX buffer descriptor (linked list) */
+ emac_net_data_token buf_token;
+ void *eop_bd; /* pointer to end of packet BD */
+} emac_tx_bd;
+
+/* forward declaration */
+typedef struct _emac_rx_cppi_ch_t emac_rx_cppi_ch;
+
+/**
+ * RX Buffer Descriptor
+ *
+ * CPPI 3.0 RX BD structure specific to EMAC.
+ */
+typedef struct {
+ int h_next; /* next (hardware) buffer descriptor pointer */
+ int buff_ptr; /* data buffer pointer */
+ int off_b_len; /* (buffer_offset_16)(buffer_length_16) */
+ int mode; /* SOP, EOP, ownership, EOQ, teardown,
+ * Q starv, length */
+ void *next; /* pointer to the next RX buffer in BD queue */
+ void *data_ptr; /* virtual address of the buffer allocated */
+ emac_net_data_token buf_token;
+ emac_rx_cppi_ch *rx_cppi;
+} emac_rx_bd;
+
+/**
+ * TX Channel Control Structure
+ *
+ * Used by EMAC DDC code to process TX Buffer Descriptors
+ */
+typedef struct {
+ /** configuration info */
+ emac_ch_info ch_info; /* channel config/info */
+
+ /* CPPI specific */
+ u32 alloc_size; /* BD pool allocated memory size */
+ char *bd_mem; /* buffer descriptor memory pointer */
+ emac_tx_bd *bd_pool_head; /* free BD pool head */
+ emac_tx_bd *active_queue_head; /* head of active packet queue */
+ emac_tx_bd *active_queue_tail; /* last hardware BD written */
+
+ emac_tx_bd *last_hw_bdprocessed; /* last HW BD processed */
+ bool queue_active; /* queue active ? TRUE/FALSE */
+#ifdef EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+ u32 *tx_complete; /* tx complete notification queue */
+#endif
+ /** statistics */
+ u32 proc_count; /* TX: # of times emac_tx_bdproc is called */
+ u32 mis_queued_packets; /* misqueued packets */
+ u32 queue_reinit; /* queue reinit - head ptr reinit */
+ u32 end_of_queue_add; /* packet added to end of queue in send */
+ u32 out_of_tx_bd; /* out of tx bd errors */
+ u32 no_active_pkts; /* IRQ when there were no packets to process */
+ u32 active_queue_count; /* active tx bd count */
+ u32 num_multi_frag_pkts;
+} emac_tx_cppi_ch;
+
+/**
+ * RX Channel Control Structure
+ *
+ * Used by EMAC DDC code to process RX Buffer Descriptors
+ */
+typedef struct _emac_rx_cppi_ch_t {
+ /* configuration info */
+ emac_ch_info ch_info; /* channel config/info */
+
+ /* EMAC (ethernet) specific configuration info */
+ char mac_addr[6]; /* ethernet MAC address */
+
+ /** CPPI specific */
+ u32 alloc_size; /* BD pool allocated memory size */
+ char *bd_mem; /* buffer descriptor memory pointer */
+ emac_rx_bd *bd_pool_head;
+ emac_rx_bd *active_queue_head;
+ emac_rx_bd *active_queue_tail;
+ bool queue_active;
+
+ /* packet and buffer objects required for passing up to DDA
+ * layer for the given instance */
+ net_pkt_obj pkt_queue;
+ net_buf_obj buf_queue[EMAC_MAX_RX_FRAGMENTS];
+#ifdef EMAC_MULTIFRAGMENT
+ u32 rx_buffer_ptr[EMAC_MAX_RX_FRAGMENTS];
+ u32 rx_data_token[EMAC_MAX_RX_FRAGMENTS];
+#endif
+ /** statistics */
+ u32 proc_count; /* number of times emac_rx_bdproc is called */
+ u32 processed_bd; /* number of BD's processed */
+ u32 recycled_bd; /* number of recycled BD's */
+ u32 out_of_rx_bd; /* NO BD's available */
+ u32 out_of_rx_buffers; /* NO buffers available */
+ u32 queue_reinit; /* condition when recycling buffers */
+ u32 end_of_queue_add; /* when adding BD at end */
+ u32 end_of_queue; /* end of queue condition */
+ u32 mis_queued_packets; /* mis-queued packet condition */
+ u32 num_multi_frag_pkts;
+} _emac_rx_cppi_ch;
+
+/* data structures and header files required for MII-MDIO module */
+/* typedef struct _phy_device PHY_DEVICE; */
+
+/**
+ * EMAC Private data structure
+ *
+ * Each EMAC device maintains its own private data structure and has a
+ * pointer to the net_device data structure representing the instance
+ * with the kernel. The private data structure contains a "owner"
+ * member pointing to the net_device structure and the net_device data
+ * structure's "priv" member points back to this data structure.
+ */
+typedef struct emac_dev_s {
+ void *owner; /* pointer to the net_device struct */
+ unsigned int instance_num; /* instance number of the device */
+ struct net_device *next_device;
+ unsigned int link_speed;
+ unsigned int link_mode;
+ unsigned long set_to_close;
+ void *led_handle;
+
+ /* DDC related parameters */
+ emac_status ddc_status;
+
+ /* configuration parameters */
+ unsigned char mac_addr[6];
+ emac_init_config init_cfg;
+ unsigned int rx_buf_size;
+ unsigned int rx_buf_offset;
+
+ /* TODO: VLAN TX not supported as of now */
+ bool vlan_enable;
+
+ /* channel configuration - though only 1 TX/RX channel is
+ * supported, provision is made for max */
+ emac_ch_info tx_ch_info[EMAC_MAX_TX_CHANNELS];
+ emac_ch_info rx_ch_info[EMAC_MAX_RX_CHANNELS];
+
+ /* periodic timer required for MDIO polling */
+ struct timer_list periodic_timer;
+ u32 periodic_ticks; /* ticks for this timer */
+ bool timer_active; /* periodic timer active ??? */
+ struct timer_list mib_timer; /* for 64 bit MIB counter */
+ u32 mib_ticks; /* ticks for this timer */
+ bool mib_timer_active; /* periodic timer active ??? */
+
+ /* statistics */
+ emac_hw_statistics device_mib; /* hardware statistics counters */
+ emac_drv_stats device_stats; /* device statstics */
+ struct net_device_stats net_dev_stats;
+
+ /* statistics counters for debugging */
+ u32 isr_count;
+
+ /* tx_rx_param struct added */
+ rx_tx_params napi_rx_tx;
+
+ /* TX/RX locks */
+ spinlock_t tx_lock;
+ spinlock_t rx_lock;
+
+ emac_drv_state drv_state;
+
+ /** EMAC specific parameters - DDC device specifics */
+ emac_tx_cppi_ch *tx_cppi[EMAC_MAX_TX_CHANNELS];
+ emac_rx_cppi_ch *rx_cppi[EMAC_MAX_RX_CHANNELS];
+ bool tx_is_created[EMAC_MAX_TX_CHANNELS];
+ bool rx_is_created[EMAC_MAX_RX_CHANNELS];
+ bool tx_is_open[EMAC_MAX_TX_CHANNELS];
+ bool rx_is_open[EMAC_MAX_RX_CHANNELS];
+ bool tx_teardown_pending[EMAC_MAX_TX_CHANNELS];
+ bool rx_teardown_pending[EMAC_MAX_RX_CHANNELS];
+ int tx_int_threshold[EMAC_MAX_TX_CHANNELS];
+ bool tx_interrupt_disable;
+
+ /* register mirror values - maintained to avoid costly
+ * register access for reads */
+ u32 rx_unicast_set;
+ u32 rx_unicast_clear;
+ u32 rx_MBP_enable;
+ u32 mac_hash1;
+ u32 mac_hash2;
+ u32 mac_control;
+ emac_status status;
+
+ /* number of multicast hash bits used in hardware */
+ u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS];
+
+ /* EMAC/CPGMAC addressing mechanism */
+ u32 rx_addr_type; /* 0 (EMAC), 1 or 2 (CPGMAC) */
+
+ emac_regs_ovly regs;
+ ewrap_regs *e_wrap_regs;
+
+ struct mib2_if_hccounters mib2if_hccounter;
+} emac_dev_t;
+
+/* ---------------------------------------------------------------
+ * globals
+ * --------------------------------------------------------------- */
+
+/* debug tracing */
+static int emac_link_status = 1;
+static int emac_debug_mode = 0;
+
+/* global variables required during initialization */
+static int g_link_speed = 0; /* 0=auto negotiate, 100=100mbps, 10=10mbps */
+static int g_link_mode = 0; /* 0=Auto Negotiate, Full Duplex = 3;
+ * Half Duplex = 2 Unknown = 1 */
+static int g_init_enable_flag = 0;
+
+/* global device array */
+static struct net_device *emac_net_dev[EMAC_MAX_INSTANCES] = { NULL };
+
+static struct net_device *last_emac_device = NULL;
+static int emac_devices_installed = 0; /* number of EMAC instances */
+
+static struct proc_dir_entry *gp_stats_file = NULL; /* proc entries */
+
+static char emac_cfg[EMAC_MAX_INSTANCES][200];
+
+/* clock frequency for EMAC */
+static struct clk *emac_clk;
+static unsigned long emac_bus_frequency;
+
+/* MAC ethernet address string in 00:00:00:00:00:00 format */
+static unsigned char emac_eth_string[20] = "deadbeaf";
+
+static const char emac_ddcversion_string[] = "EMAC DDC version 0.5";
+
+static u32 emac_debug = 0x0; /* no debug flags by default */
+static u32 emac_wrapper_ptr = EMAC_WRAPPER_RAM_ADDR;
+
+/* ---------------------------------------------------------------
+ * prototypes
+ * --------------------------------------------------------------- */
+extern int davinci_get_macaddr(char *ptr);
+
+static int emac_dev_tx(struct sk_buff *skb, struct net_device *netdev);
+
+static irqreturn_t emac_hal_isr(int irq, void *dev_id);
+
+static void *emac_net_alloc_rx_buf(emac_dev_t * dev, int buf_size,
+ emac_net_data_token * data_token,
+ u32 channel, void *alloc_args);
+
+static int emac_net_free_rx_buf(emac_dev_t * dev, void *buffer,
+ emac_net_data_token data_token,
+ u32 channel, void *free_args);
+
+static int emac_net_tx_complete(emac_dev_t * dev,
+ emac_net_data_token * net_data_tokens,
+ int num_tokens, u32 channel);
+
+static int emac_net_rx_cb(emac_dev_t * dev,
+ net_pkt_obj * net_pkt_list,
+ void *rx_args);
+
+
+static int emac_poll(struct net_device *netdev, int *budget);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void emac_poll_controller(struct net_device *dev);
+#endif
+
+/* net device related private function prototypes */
+static int emac_dev_init(struct net_device *netdev);
+
+static int emac_dev_open(struct net_device *dev);
+
+static int emac_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd);
+
+static int emac_dev_close(struct net_device *netdev);
+
+static void emac_dev_mcast_set(struct net_device *netdev);
+
+static void emac_tx_timeout(struct net_device *netdev);
+
+static struct net_device_stats *emac_dev_get_net_stats(struct net_device
+ *dev);
+
+/* internal function prototypes */
+static int __init emac_p_detect_manual_cfg(int, char *, int);
+
+static int emac_p_read_stats(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data);
+
+static int emac_p_write_stats(struct file *fp, const char *buf,
+ unsigned long count, void *data);
+
+static int emac_p_read_link(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data);
+
+static int emac_dump_config(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data);
+
+static int emac_p_get_version(char *buf, char **start, off_t offset,
+ int count, int *eof, void *data);
+
+static int emac_p_update_statistics(struct net_device *netdev, char *buf,
+ int limit, int *p_len);
+
+static int emac_p_reset_statistics(struct net_device *netdev);
+
+static int emac_p_read_rfc2665_stats(char *buf, char **start, off_t offset,
+ int count, int *eof, void *data);
+
+static int emac_p_dev_enable(emac_dev_t * dev);
+
+static int emac_p_dev_disable(emac_dev_t * dev);
+
+static void emac_p_tick_timer_expiry(emac_dev_t * dev);
+
+static int emac_dev_set_mac_addr(struct net_device *netdev, void *addr);
+
+/* function prototype for emac_p_tick_timer_expiry() function as per
+ * linux timer API */
+typedef void (*timer_tick_func) (unsigned long);
+
+/* DDA function table */
+static int emac_control_cb(emac_dev_t * dev, int cmd,
+ void *cmd_arg, void *param);
+
+/* function prototypes */
+static int emac_send(emac_dev_t * dev, net_pkt_obj * pkt,
+ int channel, bool send_args);
+
+static int emac_tick(emac_dev_t * dev, void *tick_args);
+
+static int emac_pkt_process(emac_dev_t * dev, int *pkts_pending,
+ void *pkt_args);
+
+static int emac_pkt_process_end(emac_dev_t * dev, void *proc_args);
+
+static int emac_tx_bdproc(emac_dev_t * dev, u32 channel, u32 * more_pkts,
+ bool * is_eoq);
+
+static int emac_rx_bdproc(emac_dev_t * dev, u32 channel, int *more_pkts);
+
+#ifdef EMAC_MULTIFRAGMENT
+static void emac_add_bdto_rx_queue(emac_dev_t * dev, emac_rx_cppi_ch * rx_cppi,
+ emac_rx_bd * sop_bd, emac_rx_bd * eop_bd,
+ u32 * buffer,
+ emac_net_data_token * buf_token, u32 num_bd);
+
+#else
+static void emac_add_bdto_rx_queue(emac_dev_t * dev, emac_rx_cppi_ch * rx_cppi,
+ emac_rx_bd * curr_bd, char *buffer,
+ emac_net_data_token buf_token);
+#endif
+
+static int emac_update_phy_status(emac_dev_t * dev);
+
+static int emac_init(emac_dev_t * dev, emac_init_config * init_cfg);
+
+static int emac_de_init(emac_dev_t * dev, void *param);
+
+static int emac_open(emac_dev_t * dev, void *param);
+
+static int emac_close(emac_dev_t * dev, void *param);
+
+static int emac_control(emac_dev_t * dev, int cmd, void *cmd_arg, void *param);
+
+static int emac_ch_open(emac_dev_t * dev, emac_ch_info * ch_info,
+ void *ch_open_args);
+
+static int emac_ch_close(emac_dev_t * dev, int channel,
+ int direction, void *ch_close_args);
+
+static int emac_wait_for_teardown_complete(emac_dev_t * dev,
+ u32 channel,
+ net_ch_dir direction, bool blocking);
+
+static int emac_enable_channel(emac_dev_t * dev, u32 channel, u32 direction);
+
+static int emac_disable_channel(emac_dev_t * dev, u32 channel,
+ net_ch_dir direction);
+
+static int emac_init_tx_channel(emac_dev_t * dev, emac_ch_info * ch_info,
+ void *ch_open_args);
+
+static int emac_init_rx_channel(emac_dev_t * dev, emac_ch_info * ch_info,
+ void *ch_open_args);
+
+static int emac_un_init_tx_channel(emac_dev_t * dev, u32 channel,
+ void *ch_close_args);
+
+static int emac_un_init_rx_channel(emac_dev_t * dev, u32 channel,
+ void *ch_close_args);
+
+static void emac_set_mac_address(emac_dev_t * dev, u32 channel, char *mac_addr);
+
+static void emac_ddcifcnt_clear(emac_dev_t * dev);
+
+static void emac_ddcifcnt_updt(emac_dev_t * dev);
+
+static void emac_ddcphycnt(emac_dev_t * dev, u32 * cmd_arg);
+
+/* ---------------------------------------------------------------
+ * internal utility functions
+ * --------------------------------------------------------------- */
+static inline u32 emac_virt_to_phys(u32 addr)
+{
+ /* NOTE: must handle memory and IO addresses */
+ if ((addr & 0xFFFF0000) == EMAC_BASE_ADDR) {
+ addr = io_v2p(addr);
+ } else {
+ addr = virt_to_phys((void *)addr);
+ }
+
+ return addr;
+}
+
+#define EMAC_VIRT_TO_PHYS(x) emac_virt_to_phys((u32)x)
+#define EMAC_VIRT_NOCACHE(addr)(addr)
+
+/* alloc and zero memoy */
+static inline int emac_malloc(u32 n, void **buf)
+{
+ void *tmp = kcalloc(n, 1, GFP_KERNEL);
+
+ if (!tmp) {
+ printk(KERN_ERR "emac_malloc(): kmalloc() failed.\n");
+ dump_stack();
+ return -1;
+ }
+
+ *buf = tmp;
+ return 0;
+}
+
+static inline void emac_free(void *ptr)
+{
+ kfree(ptr);
+}
+
+#define EMAC_CACHE_INVALIDATE(addr, size) consistent_sync((void *)addr, size, DMA_FROM_DEVICE)
+#define EMAC_CACHE_WRITEBACK(addr, size) consistent_sync((void *)addr, size, DMA_TO_DEVICE)
+#define EMAC_CACHE_WRITEBACK_INVALIDATE(addr, size) consistent_sync((void *)addr,size, DMA_BIDIRECTIONAL)
+
+/* buffer-descriptors in IO space. No cache invalidation needed */
+#define BD_CACHE_INVALIDATE(addr, size)
+#define BD_CACHE_WRITEBACK(addr, size)
+#define BD_CACHE_WRITEBACK_INVALIDATE(addr, size)
+
+/* string to hex conversion */
+static unsigned char emac_str_to_hexnum(unsigned char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return 0;
+}
+
+/* string to ethernet address conversion */
+static void emac_str_to_ethaddr(unsigned char *ea, unsigned char *str)
+{
+ int i;
+ unsigned char num;
+
+ for (i = 0; i < 6; i++) {
+ if ((*str == '.') || (*str == ':')) {
+ str++;
+ }
+ num = emac_str_to_hexnum(*str) << 4;
+ ++str;
+ num |= (emac_str_to_hexnum(*str));
+ ++str;
+ ea[i] = num;
+ }
+}
+
+static int emac_cfg_build(int connect, int external_switch)
+{
+
+ static int cfg_instance = 0;
+
+ unsigned int speed = 0;
+
+ speed = (external_switch) ? CONFIG_EMAC_NOPHY : 0;
+
+ sprintf(emac_cfg[cfg_instance],
+ "%d:%x:%d:%d:%u:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%x:%d:%d:%u:%u:%x:%d",
+ cfg_instance, EMAC_BASE_ADDR,
+ EMAC_INTERRUPT, 0, EMAC_BUS_FREQUENCY,
+ g_link_speed, g_link_mode, EMAC_DEFAULT_PROMISCOUS_ENABLE,
+ EMAC_DEFAULT_BROADCAST_ENABLE,
+ EMAC_DEFAULT_MULTICAST_ENABLE,
+ EMAC_DEFAULT_MAX_FRAME_SIZE,
+ EMAC_DEFAULT_TX_NUM_BD,
+ EMAC_DEFAULT_TX_MAX_SERVICE, EMAC_DEFAULT_RX_NUM_BD,
+ EMAC_DEFAULT_RX_MAX_SERVICE, 0,
+ EMAC_MDIO_BASE_ADDR, 0, 0,
+ EMAC_BUS_FREQUENCY, EMAC_MDIO_FREQUENCY, EMAC_PHY_MASK, 10);
+
+ DBG("Driver Config:\n%s\n", emac_cfg[cfg_instance]);
+
+ cfg_instance++;
+
+ return (0);
+
+}
+
+/* emac_eth_setup() invokes a board specific function that provides
+ * MAC address for this adapter. For DaVinci EVM, the function invoked
+ * is davinci_get_macaddr();
+ */
+static int emac_eth_setup(void)
+{
+ if (davinci_get_macaddr(&emac_eth_string[0]) != 0) {
+ printk("TI DaVinci EMAC: Error getting board specific "
+ "MAC address\n");
+ printk("Assuming default MAC address\n");
+ return (-1);
+ } else {
+ printk("TI DaVinci EMAC: MAC address is %s\n", emac_eth_string);
+ }
+
+ return (0);
+}
+
+static int emac_cfg_probe(void)
+{
+
+ /* for DaVinci there is only 1 EMAC instance */
+ if (emac_cfg_build(0, 0))
+ return (-1);
+ else
+ return (0);
+}
+
+/******************************************************************************
+ * DDA Callback functions
+ *****************************************************************************/
+
+/* emac_control_cb - ioctl function to be called by the DDC */
+static int emac_control_cb(emac_dev_t * dev, int cmd,
+ void *cmd_arg, void *param)
+{
+ switch (cmd) {
+ case EMAC_IOCTL_TIMER_START:
+ {
+ /* cmd will directly have the timer period
+ * of the periodic timer, param not used */
+
+ /* asks for milliSecs. So calculate ticks
+ * from ticks per 1000 mSec
+ */
+ struct timer_list *p_timer = &dev->periodic_timer;
+
+ dev->periodic_ticks =
+ (EMAC_TICKS_PER_SEC * (int)cmd_arg) / 1000;
+ p_timer->expires = jiffies + dev->periodic_ticks;
+ add_timer(&dev->periodic_timer);
+ dev->timer_active = TRUE;
+
+ }
+ break;
+
+ case EMAC_IOCTL_TIMER_STOP:
+ /* cmd and param not used */
+ if (dev->timer_active == TRUE) {
+ del_timer_sync(&dev->periodic_timer);
+ dev->timer_active = FALSE;
+ }
+ break;
+
+ case EMAC_IOCTL_STATUS_UPDATE:
+ {
+ /* cmd_arg will point to status structure,
+ * param not used */
+ struct net_device *netdev = dev->owner;
+
+ emac_status *status = &dev->ddc_status;
+ dev->ddc_status = *((emac_status *) cmd_arg);
+ if ((status->hw_status & EMAC_TX_HOST_ERROR) ==
+ EMAC_TX_HOST_ERROR) {
+ ERR("TX Host Error. "
+ "Transmit Stopped %s\n", netdev->name);
+ }
+ if ((status->hw_status & EMAC_RX_HOST_ERROR) ==
+ EMAC_RX_HOST_ERROR) {
+ ERR("RX Host Error. "
+ "Receive Stopped %s\n", netdev->name);
+ }
+ if (status->phy_linked) {
+ /* link ON */
+ if (!netif_carrier_ok(netdev)) {
+ netif_carrier_on(netdev);
+ }
+ dev->link_speed =
+ ((status->
+ phy_speed == 100) ? 100000000 : 10000000);
+ dev->link_mode =
+ ((status->phy_duplex == PHY_DUPLEX_FULL) ?
+ PHY_DUPLEX_FULL : PHY_DUPLEX_HALF);
+
+ /* reactivate the transmit queue if it
+ * is stopped */
+ if (netif_running(netdev)
+ && netif_queue_stopped(netdev)) {
+ netif_wake_queue(netdev);
+ }
+ } else {
+ /* link OFF */
+ if (netif_carrier_ok(netdev)) {
+ /* do we need to register
+ * synchronization issues with
+ * stats here. */
+ dev->link_speed = 100000000;
+ dev->link_mode = 1;
+ netif_carrier_off(netdev);
+ }
+ if (!netif_queue_stopped(netdev)) {
+ /* so that kernel does not
+ * keep on xmiting pkts. */
+ netif_stop_queue(netdev);
+ }
+ }
+
+ if (emac_link_status)
+ DBG("%s, PhyNum %d, %s, %s, %s\n",
+ ((struct net_device *)dev->owner)->name,
+ status->phy_num,
+ ((status->phy_duplex == PHY_DUPLEX_FULL) ?
+ "Full Duplex" : "Half Duplex"),
+ ((status->phy_speed == 100) ?
+ "100 Mbps" : "10 Mbps"),
+ ((status->phy_linked) ?
+ "Linked" : "NO LINK"));
+ }
+ break;
+
+ case EMAC_IOCTL_MIB64_CNT_TIMER_START:
+ {
+ /* cmd will directly have the timer period of the
+ * periodic timer, param not used */
+
+ /* asks for milli_secs. so calculate ticks
+ * from ticks per 1000 m_sec */
+ struct timer_list *p_timer = &dev->mib_timer;
+
+ dev->mib_ticks =
+ (EMAC_TICKS_PER_SEC * (int)cmd_arg) / 1000;
+ p_timer->expires = jiffies + dev->mib_ticks;
+ add_timer(p_timer);
+ dev->mib_timer_active = TRUE;
+ }
+ break;
+
+ case EMAC_IOCTL_MIB64_CNT_TIMER_STOP:
+ {
+ /* cmd_arg and param not used */
+ if (dev->mib_timer_active == TRUE) {
+ del_timer_sync(&dev->mib_timer);
+ dev->mib_timer_active = FALSE;
+ }
+ }
+ break;
+
+ default:
+ DBG("Unhandled ioctl code %d\n", cmd);
+ break;
+ }
+
+ return (EMAC_SUCCESS);
+}
+
+/*****************************************************************************
+ *
+ * emacEndGetConfig - Extract configuration for given unit number/instance
+ *
+ * This function gets the configuration information from the
+ * configuration service or by some means for the given unit
+ * number/emac instance
+ *
+ * Note: For debug/default, static information is obtained from the
+ * header file
+ *
+ * RETURNS: OK or ERROR.
+ */
+static int emac_net_get_config(emac_dev_t * dev)
+{
+#define EMAC_TOKEN_PARSE(str) \
+ { if ((tok = (char *)strsep ((str), ":")) == NULL) return -1; }
+#define EMAC_TOKEN_GET_INTEGER simple_strtoul (tok, NULL, 10)
+#define EMAC_TOKEN_GET_HEX simple_strtoul (tok, NULL, 16)
+ emac_init_config *i_cfg = &dev->init_cfg;
+ emac_ch_info *tx_ch_cfg = &dev->tx_ch_info[0];
+ emac_ch_info *rx_ch_cfg = &dev->rx_ch_info[0];
+ int speed, duplex, extra;
+ char local_string_val[200];
+ char *local_string = NULL;
+ char *tok;
+ char *p_holder = NULL;
+
+ /* use static config string */
+ switch (dev->instance_num) {
+ case 0:
+ local_string = emac_cfg[0];
+ break;
+ case 1:
+ local_string = emac_cfg[1];
+ break;
+ default:
+ local_string = emac_cfg[0];
+ break;
+ }
+
+ strcpy(&local_string_val[0], local_string);
+ local_string = &local_string_val[0];
+ p_holder = NULL;
+ tok = (char *)strsep(&local_string, ":");
+ if (tok == NULL)
+ return (-1);
+
+ i_cfg->inst_id = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("i_cfg->instId=%d", i_cfg->inst_id);
+
+ i_cfg->base_address = EMAC_TOKEN_GET_HEX;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ni_cfg->baseAddress=%08X", i_cfg->base_address);
+
+ i_cfg->intr_line = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ni_cfg->intrLine=%d", i_cfg->intr_line);
+
+ i_cfg->reset_line = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ni_cfg->resetLine=%d", i_cfg->reset_line);
+
+ i_cfg->emac_bus_frequency = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ni_cfg->emacBusFrequency=%d", i_cfg->emac_bus_frequency);
+
+ speed = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\nspeed=%d", speed);
+
+ duplex = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\nduplex=%d", duplex);
+
+ i_cfg->rx_cfg.promiscous_enable = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ni_cfg->rxCfg.promiscousEnable=%d",
+ i_cfg->rx_cfg.promiscous_enable);
+
+ i_cfg->rx_cfg.broadcast_enable = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ni_cfg->rxCfg.broadcastEnable=%d",
+ i_cfg->rx_cfg.broadcast_enable);
+
+ i_cfg->rx_cfg.multicast_enable = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ni_cfg->rxCfg.multicastEnable=%d",
+ i_cfg->rx_cfg.multicast_enable);
+
+ i_cfg->rx_cfg.max_rx_pkt_length = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ni_cfg->rxCfg.maxRxPktLength=%d",
+ i_cfg->rx_cfg.max_rx_pkt_length);
+
+ tx_ch_cfg->num_bd = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ntx_ch_cfg->num_bd=%d", tx_ch_cfg->num_bd);
+
+ tx_ch_cfg->service_max = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ntx_ch_cfg->service_max=%d", tx_ch_cfg->service_max);
+
+ rx_ch_cfg->num_bd = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\nrx_ch_cfg->num_bd=%d", rx_ch_cfg->num_bd);
+
+ rx_ch_cfg->service_max = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\nrx_ch_cfg->service_max=%d", rx_ch_cfg->service_max);
+
+ extra = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\nextra=%d", extra);
+
+ i_cfg->mdio_base_address = EMAC_TOKEN_GET_HEX;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ni_cfg->mdioBaseAddress=%08X", i_cfg->mdio_base_address);
+
+ i_cfg->mdio_intr_line = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ni_cfg->mdioIntrLine=%d", i_cfg->mdio_intr_line);
+
+ i_cfg->mdio_reset_line = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ni_cfg->mdioResetLine=%d", i_cfg->mdio_reset_line);
+
+ i_cfg->mdio_bus_frequency = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ni_cfg->MdioBusFrequency=%d", i_cfg->mdio_bus_frequency);
+
+ i_cfg->mdio_clock_frequency = EMAC_TOKEN_GET_INTEGER;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ni_cfg->MdioClockFrequency=%d", i_cfg->mdio_clock_frequency);
+
+ i_cfg->phy_mask = EMAC_TOKEN_GET_HEX;
+ EMAC_TOKEN_PARSE(&local_string);
+ DBG("\ni_cfg->PhyMask=%08X", i_cfg->phy_mask);
+
+ i_cfg->mdio_tick_msec = EMAC_TOKEN_GET_INTEGER;
+ DBG("\ni_cfg->MdioTickMSec=%d", i_cfg->mdio_tick_msec);
+ DBG("\n");
+
+ i_cfg->mib64cnt_msec = CONFIG_EMAC_MIB_TIMER_TIMEOUT;
+ rx_ch_cfg->buf_size = i_cfg->rx_cfg.max_rx_pkt_length;
+ dev->rx_buf_offset =
+ EMAC_L3_ALIGN(extra) + EMAC_DEFAULT_EXTRA_RXBUF_SIZE;
+ dev->rx_buf_size = (rx_ch_cfg->buf_size + dev->rx_buf_offset);
+
+ /* align skb's on 4 byte boundry - no hard requirement currently - done for future use */
+ dev->rx_buf_size += EMAC_4BYTE_ALIGN(dev->rx_buf_size);
+
+ /* determine phy speed/duplex mode - to be built as per MDIO
+ * module requirements */
+ if (speed == CONFIG_EMAC_NOPHY) {
+ i_cfg->phy_mode = SNWAY_NOPHY;
+ } else {
+ if ((speed == 0) && (duplex == PHY_DUPLEX_AUTO)) {
+ i_cfg->phy_mode = SNWAY_AUTOALL;
+ } else if (speed == 10) {
+ if (duplex == PHY_DUPLEX_HALF) {
+ i_cfg->phy_mode = SNWAY_HD10;
+ } else if (duplex == PHY_DUPLEX_FULL) {
+ i_cfg->phy_mode = SNWAY_FD10;
+ } else {
+ i_cfg->phy_mode = SNWAY_HD10 | SNWAY_FD10;
+ }
+ } else if (speed == 100) {
+ if (duplex == PHY_DUPLEX_HALF) {
+ i_cfg->phy_mode = SNWAY_HD100;
+ } else if (duplex == PHY_DUPLEX_FULL) {
+ i_cfg->phy_mode = SNWAY_FD100;
+ } else {
+ i_cfg->phy_mode = SNWAY_HD100 | SNWAY_FD100;
+ }
+ } else {
+ if (duplex == PHY_DUPLEX_FULL) {
+ i_cfg->phy_mode = SNWAY_FD10 | SNWAY_FD100;
+ } else {
+ i_cfg->phy_mode = SNWAY_HD10 | SNWAY_HD100;
+ }
+ }
+ }
+
+ dev->vlan_enable = EMAC_DEFAULT_VLAN_ENABLE;
+ i_cfg->num_tx_channels = EMAC_DEFAULT_NUM_TX_CHANNELS;
+ i_cfg->num_rx_channels = EMAC_DEFAULT_NUM_RX_CHANNELS;
+ i_cfg->MLink_mask = EMAC_DEFAULT_MLINK_MASK;
+ i_cfg->rx_cfg.pass_crc = EMAC_DEFAULT_PASS_CRC;
+ i_cfg->rx_cfg.qos_enable = EMAC_DEFAULT_QOS_ENABLE;
+ i_cfg->rx_cfg.no_buffer_chaining = EMAC_DEFAULT_NO_BUFFER_CHAINING;
+ i_cfg->rx_cfg.copy_maccontrol_frames_enable =
+ EMAC_DEFAULT_COPY_MAC_CONTROL_FRAMES_ENABLE;
+ i_cfg->rx_cfg.copy_short_frames_enable =
+ EMAC_DEFAULT_COPY_SHORT_FRAMES_ENABLE;
+ i_cfg->rx_cfg.copy_error_frames_enable =
+ EMAC_DEFAULT_COPY_ERROR_FRAMES_ENABLE;
+ i_cfg->rx_cfg.promiscous_channel = EMAC_DEFAULT_PROMISCOUS_CHANNEL;
+ i_cfg->rx_cfg.broadcast_channel = EMAC_DEFAULT_BROADCAST_CHANNEL;
+ i_cfg->rx_cfg.multicast_channel = EMAC_DEFAULT_MULTICAST_CHANNEL;
+ i_cfg->rx_cfg.buffer_offset = EMAC_DEFAULT_BUFFER_OFFSET;
+ i_cfg->mac_cfg.p_type = EMAC_TXPRIO_FIXED;
+ i_cfg->mac_cfg.tx_short_gap_enable = FALSE;
+
+ if (speed == 1000)
+ i_cfg->mac_cfg.giga_bit_enable = TRUE;
+ else
+ i_cfg->mac_cfg.giga_bit_enable = FALSE;
+
+ i_cfg->mac_cfg.tx_pacing_enable = EMAC_DEFAULT_TX_PACING_ENABLE;
+ i_cfg->mac_cfg.mii_enable = EMAC_DEFAULT_MII_ENABLE;
+ i_cfg->mac_cfg.tx_flow_enable = EMAC_DEFAULT_TX_FLOW_ENABLE;
+ i_cfg->mac_cfg.rx_flow_enable = EMAC_DEFAULT_RX_FLOW_ENABLE;
+ i_cfg->mac_cfg.loopback_enable = EMAC_DEFAULT_LOOPBACK_ENABLE;
+ i_cfg->mac_cfg.full_duplex_enable = EMAC_DEFAULT_FULL_DUPLEX_ENABLE;
+ i_cfg->mac_cfg.tx_interrupt_disable = EMAC_DEFAULT_TX_INTERRUPT_DISABLE;
+ tx_ch_cfg->ch_num = EMAC_DEFAULT_TX_CHANNEL;
+ tx_ch_cfg->ch_dir = NET_CH_DIR_TX;
+ tx_ch_cfg->ch_state = NET_CH_UNINITIALIZED;
+ rx_ch_cfg->ch_num = EMAC_DEFAULT_RX_CHANNEL;
+ rx_ch_cfg->ch_dir = NET_CH_DIR_RX;
+ rx_ch_cfg->ch_state = NET_CH_UNINITIALIZED;
+
+ /* module control EWrap base address for DaVinci */
+ i_cfg->e_wrap_base_address = EMAC_WRAPPER_REGS_ADDR;
+
+ DBG("\n");
+ return (0);
+}
+
+/* detect manual config */
+static int __init emac_p_detect_manual_cfg(int link_speed, char *link_mode,
+ int debug)
+{
+ if (debug == 1) {
+ emac_debug_mode = 1;
+ DBG("Enabled debug print.\n");
+ }
+
+ if ((link_speed == 0) && (!strcmp(link_mode, "auto"))) {
+ /* Auto negotiation */
+ g_link_speed = 0;
+ g_link_mode = 0;
+ DBG("auto negotiation selected\n");
+ }
+
+ if (!link_speed || (link_speed != 10 && link_speed != 100)) {
+ g_link_speed = 0;
+ g_link_mode = 0;
+ DBG("Invalid or No value of link speed specified,"
+ "defaulting to auto negotiation .\n");
+ }
+
+ if (!link_mode
+ || (!strcmp(link_mode, "fd") && !strcmp(link_mode, "hd"))) {
+ g_link_speed = 0;
+ g_link_mode = 0;
+ DBG("Invalid or No value of link mode specified,"
+ "defaulting to auto mode.\n");
+ }
+
+ if ((link_speed == 10) && (!strcmp(link_mode, "fd"))) {
+ g_link_speed = 10;
+ g_link_mode = 3;
+ } else if ((link_speed == 10) && (!strcmp(link_mode, "hd"))) {
+ g_link_speed = 10;
+ g_link_mode = 2;
+ } else if ((link_speed == 100) && (!strcmp(link_mode, "fd"))) {
+ g_link_speed = 100;
+ g_link_mode = 3;
+ } else if ((link_speed == 100) && (!strcmp(link_mode, "hd"))) {
+ g_link_speed = 100;
+ g_link_mode = 2;
+ } else {
+ g_link_speed = 0;
+ g_link_mode = 0;
+ }
+
+ DBG("Link is set to the speed of"
+ "%s speed and %s mode.\n",
+ ((g_link_speed ==
+ 0) ? "auto" : ((g_link_speed == 100) ? "100" : "10")),
+ ((g_link_mode ==
+ 0) ? "auto" : ((g_link_mode == 2) ? "half" : "full")));
+
+ return (0);
+}
+
+/* link read support */
+static int emac_p_read_link(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data)
+{
+ int len = 0;
+ struct net_device *netdev;
+ emac_dev_t *dev;
+ struct net_device *emac_dev_list[emac_devices_installed];
+ int i;
+
+ len +=
+ sprintf(buf + len, "EMAC devices = %d\n", emac_devices_installed);
+ netdev = last_emac_device;
+
+ /* reverse the the device link list to list eth0,eth1...in correct order */
+ for (i = 0; i < emac_devices_installed; i++) {
+ emac_dev_list[emac_devices_installed - (i + 1)] = netdev;
+ dev = NETDEV_PRIV(netdev);
+ netdev = dev->next_device;
+ }
+
+ for (i = 0; i < emac_devices_installed; i++) {
+ netdev = emac_dev_list[i];
+ dev = NETDEV_PRIV(netdev);
+
+ /* this prints them out from high to low because of
+ how the devices are linked */
+ if (netif_carrier_ok(netdev)) {
+ len +=
+ sprintf(buf + len,
+ "eth%d: Link State: %s "
+ "Phy %d, Speed = %s, Duplex = %s\n",
+ dev->instance_num, "UP",
+ dev->ddc_status.phy_num,
+ (dev->link_speed ==
+ 100000000) ? "100" : "10",
+ (dev->link_mode == 2) ? "Half" : "Full");
+
+ } else {
+ len +=
+ sprintf(buf + len, "eth%d: Link State: DOWN\n",
+ dev->instance_num);
+ }
+ netdev = dev->next_device;
+ }
+
+ return len;
+}
+
+/* dump configuration information for debug purposes */
+static int emac_dump_config(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data)
+{
+ int len = 0;
+ struct net_device *netdev;
+ struct net_device *emac_dev_list[emac_devices_installed];
+ int i;
+ emac_dev_t *dev;
+
+ len +=
+ sprintf(buf + len, "EMAC devices = %d\n", emac_devices_installed);
+
+ netdev = last_emac_device;
+
+ /* reverse the the device link list to list eth0,eth1...in
+ correct order */
+ for (i = 0; i < emac_devices_installed; i++) {
+ emac_dev_list[emac_devices_installed - (i + 1)] = netdev;
+ dev = NETDEV_PRIV(netdev);
+ netdev = dev->next_device;
+ }
+
+ for (i = 0; i < emac_devices_installed; i++) {
+ netdev = emac_dev_list[i];
+ dev = NETDEV_PRIV(netdev);
+
+ len +=
+ sprintf(buf + len,
+ "\nEMAC Driver Internal Config Info for Unit %d\n",
+ dev->instance_num);
+ len +=
+ sprintf(buf + len, "vlanEnable = %d\n",
+ dev->vlan_enable);
+ len +=
+ sprintf(buf + len, "rxBufSize = %d\n",
+ dev->rx_buf_size);
+ len +=
+ sprintf(buf + len, "rxBufOffset = %d\n",
+ dev->rx_buf_offset);
+ len +=
+ sprintf(buf + len, "instId = %d\n",
+ dev->init_cfg.inst_id);
+ len +=
+ sprintf(buf + len, "numTxChannels = %d\n",
+ dev->init_cfg.num_tx_channels);
+ len +=
+ sprintf(buf + len, "numRxChannels = %d\n",
+ dev->init_cfg.num_rx_channels);
+ len +=
+ sprintf(buf + len, "emacBusFrequency = %d\n",
+ dev->init_cfg.emac_bus_frequency);
+ len +=
+ sprintf(buf + len, "baseAddress = %08X\n",
+ dev->init_cfg.base_address);
+ len +=
+ sprintf(buf + len, "intrLine = %d\n",
+ dev->init_cfg.intr_line);
+ len +=
+ sprintf(buf + len, "resetLine = %d\n",
+ dev->init_cfg.reset_line);
+ len +=
+ sprintf(buf + len, "mdioBaseAddress = %08X\n",
+ dev->init_cfg.mdio_base_address);
+ len +=
+ sprintf(buf + len, "mdioResetLine = %d\n",
+ dev->init_cfg.mdio_reset_line);
+ len +=
+ sprintf(buf + len, "mdioIntrLine = %d\n",
+ dev->init_cfg.mdio_intr_line);
+ len +=
+ sprintf(buf + len, "PhyMask = %08X\n",
+ dev->init_cfg.phy_mask);
+ len +=
+ sprintf(buf + len, "MLinkMask = %08X\n",
+ dev->init_cfg.MLink_mask);
+ len +=
+ sprintf(buf + len, "MdioBusFrequency = %d\n",
+ dev->init_cfg.mdio_bus_frequency);
+ len +=
+ sprintf(buf + len, "MdioClockFrequency = %d\n",
+ dev->init_cfg.mdio_clock_frequency);
+ len +=
+ sprintf(buf + len, "MdioTickMSec = %d\n",
+ dev->init_cfg.mdio_tick_msec);
+ len +=
+ sprintf(buf + len, "phyMode = %d\n",
+ dev->init_cfg.phy_mode);
+ len +=
+ sprintf(buf + len, "passCRC = %d\n",
+ dev->init_cfg.rx_cfg.pass_crc);
+ len +=
+ sprintf(buf + len, "qosEnable = %d\n",
+ dev->init_cfg.rx_cfg.qos_enable);
+ len +=
+ sprintf(buf + len, "noBufferChaining = %d\n",
+ dev->init_cfg.rx_cfg.no_buffer_chaining);
+ len +=
+ sprintf(buf + len, "copyMACCntrlFrsEne = %d\n",
+ dev->init_cfg.rx_cfg.copy_maccontrol_frames_enable);
+ len +=
+ sprintf(buf + len, "copyShortFramesEn = %d\n",
+ dev->init_cfg.rx_cfg.copy_short_frames_enable);
+ len +=
+ sprintf(buf + len, "copyErrorFramesEn = %d\n",
+ dev->init_cfg.rx_cfg.copy_error_frames_enable);
+ len +=
+ sprintf(buf + len, "promiscousEnable = %d\n",
+ dev->init_cfg.rx_cfg.promiscous_enable);
+ len +=
+ sprintf(buf + len, "promiscousChannel = %d\n",
+ dev->init_cfg.rx_cfg.promiscous_channel);
+ len +=
+ sprintf(buf + len, "broadcastEnable = %d\n",
+ dev->init_cfg.rx_cfg.broadcast_enable);
+ len +=
+ sprintf(buf + len, "broadcastChannel = %d\n",
+ dev->init_cfg.rx_cfg.broadcast_channel);
+ len +=
+ sprintf(buf + len, "multicastEnable = %d\n",
+ dev->init_cfg.rx_cfg.multicast_enable);
+ len +=
+ sprintf(buf + len, "multicastChannel = %d\n",
+ dev->init_cfg.rx_cfg.multicast_channel);
+ len +=
+ sprintf(buf + len, "maxRxPktLength = %d\n",
+ dev->init_cfg.rx_cfg.max_rx_pkt_length);
+ len +=
+ sprintf(buf + len, "bufferOffset = %d\n",
+ dev->init_cfg.rx_cfg.buffer_offset);
+ len +=
+ sprintf(buf + len, "pType = %d\n",
+ dev->init_cfg.mac_cfg.p_type);
+ len +=
+ sprintf(buf + len, "txShortGapEnable = %d\n",
+ dev->init_cfg.mac_cfg.tx_short_gap_enable);
+ len +=
+ sprintf(buf + len, "gigaBitEnable = %d\n",
+ dev->init_cfg.mac_cfg.giga_bit_enable);
+ len +=
+ sprintf(buf + len, "txPacingEnable = %d\n",
+ dev->init_cfg.mac_cfg.tx_pacing_enable);
+ len +=
+ sprintf(buf + len, "miiEnable = %d\n",
+ dev->init_cfg.mac_cfg.mii_enable);
+ len +=
+ sprintf(buf + len, "txFlowEnable = %d\n",
+ dev->init_cfg.mac_cfg.tx_flow_enable);
+ len +=
+ sprintf(buf + len, "rxFlowEnable = %d\n",
+ dev->init_cfg.mac_cfg.rx_flow_enable);
+ len +=
+ sprintf(buf + len, "loopbackEnable = %d\n",
+ dev->init_cfg.mac_cfg.loopback_enable);
+ len +=
+ sprintf(buf + len, "fullDuplexEnable = %d\n",
+ dev->init_cfg.mac_cfg.full_duplex_enable);
+ netdev = dev->next_device;
+ }
+
+ return len;
+}
+
+/* read stats */
+static int emac_p_read_stats(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *netdev = last_emac_device;
+ int len = 0;
+ int limit = count - 80;
+ int i;
+ struct net_device *emac_dev_list[emac_devices_installed];
+ emac_dev_t *dev;
+ emac_hw_statistics *p_device_mib;
+
+ /* reverse the the device link list to list eth0,eth1...in
+ correct order */
+ for (i = 0; i < emac_devices_installed; i++) {
+ emac_dev_list[emac_devices_installed - (i + 1)] = netdev;
+ dev = NETDEV_PRIV(netdev);
+ netdev = dev->next_device;
+ }
+
+ for (i = 0; i < emac_devices_installed; i++) {
+ netdev = emac_dev_list[i];
+ if (!netdev)
+ goto proc_error;
+
+ /* get stats */
+ emac_p_update_statistics(netdev, NULL, 0, NULL);
+ dev = NETDEV_PRIV(netdev);
+ p_device_mib = &dev->device_mib;
+
+ /* transmit stats */
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "\nCpmac %d, Address %lx\n",
+ i + 1, netdev->base_addr);
+ if (len <= limit)
+ len += sprintf(buf + len, " Transmit Stats\n");
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Tx Valid Bytes Sent :%u\n",
+ p_device_mib->if_out_octets);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Good Tx Frames (Hardware) :%u\n",
+ p_device_mib->if_out_good_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Good Tx Frames (Software) :%lu\n",
+ dev->net_dev_stats.tx_packets);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Good Tx Broadcast Frames :%u\n",
+ p_device_mib->if_out_broadcasts);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Good Tx Multicast Frames :%u\n",
+ p_device_mib->if_out_multicasts);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Pause Frames Sent :%u\n",
+ p_device_mib->if_out_pause_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Collisions :%u\n",
+ p_device_mib->if_collision_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Tx Error Frames :%lu\n",
+ dev->net_dev_stats.tx_errors);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Carrier Sense Errors :%u\n",
+ p_device_mib->if_carrier_sense_errors);
+ if (len <= limit)
+ len += sprintf(buf + len, "\n");
+
+ /* receive stats */
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "\nCpmac %d, Address %lx\n",
+ i + 1, netdev->base_addr);
+ if (len <= limit)
+ len += sprintf(buf + len, " Receive Stats\n");
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Rx Valid Bytes Received :%u\n",
+ p_device_mib->if_in_octets);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Good Rx Frames (Hardware) :%u\n",
+ p_device_mib->if_in_good_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Good Rx Frames (Software) :%lu\n",
+ dev->net_dev_stats.rx_packets);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Good Rx Broadcast Frames :%u\n",
+ p_device_mib->if_in_broadcasts);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Good Rx Multicast Frames :%u\n",
+ p_device_mib->if_in_multicasts);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Pause Frames Received :%u\n",
+ p_device_mib->if_in_pause_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Rx CRC Errors :%u\n",
+ p_device_mib->if_in_crcerrors);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Rx Align/Code Errors :%u\n",
+ p_device_mib->if_in_align_code_errors);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Rx Jabbers :%u\n",
+ p_device_mib->if_in_oversized_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Rx Filtered Frames :%u\n",
+ p_device_mib->if_in_filtered_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Rx Fragments :%u\n",
+ p_device_mib->if_in_fragments);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Rx Undersized Frames :%u\n",
+ p_device_mib->if_in_undersized_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len,
+ " Rx Overruns :%u\n",
+ p_device_mib->if_rx_dmaoverruns);
+ }
+
+ return len;
+
+ proc_error:
+ *eof = 1;
+
+ return len;
+}
+
+/* write stats */
+static int emac_p_write_stats(struct file *fp, const char *buf,
+ unsigned long count, void *data)
+{
+ char local_buf[31];
+ int ret_val = 0;
+
+ if (count > 30) {
+ printk("Error : Buffer Overflow\n");
+ printk("Use \"echo 0 > emac_stat\" to reset the statistics\n");
+ return -EFAULT;
+ }
+
+ ret_val = copy_from_user(local_buf, buf, count);
+ if(ret_val)
+ return ret_val;
+ local_buf[count - 1] = '\0'; /* ignoring last \n char */
+ ret_val = count;
+ if (strcmp("0", local_buf) == 0) {
+ struct net_device *netdev = last_emac_device;
+ int i;
+ struct net_device *emac_dev_list[emac_devices_installed];
+ emac_dev_t *dev;
+
+ /* valid command */
+ printk("Resetting statistics for EMAC interface.\n");
+
+ /* reverse the the device link list to list
+ eth0,eth1...in correct order */
+ for (i = 0; i < emac_devices_installed; i++) {
+ emac_dev_list[emac_devices_installed - (i + 1)] =
+ netdev;
+
+ dev = NETDEV_PRIV(netdev);
+ netdev = dev->next_device;
+ }
+
+ for (i = 0; i < emac_devices_installed; i++) {
+ netdev = emac_dev_list[i];
+
+ if (!netdev) {
+ ret_val = -EFAULT;
+ break;
+ }
+
+ emac_p_reset_statistics(netdev);
+ }
+ } else {
+ printk("Error: Unknown operation on emac statistics\n");
+ printk("Use \"echo 0 > emac_stats\" to reset the statistics\n");
+ return -EFAULT;
+ }
+
+ return ret_val;
+}
+
+/* update RFC2665 statistics */
+static int emac_p_read_rfc2665_stats(char *buf, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+ int limit = count - 80;
+ int len = 0;
+ struct net_device *netdev = (struct net_device *)data;
+
+ emac_p_update_statistics(netdev, buf, limit, &len);
+ *eof = 1;
+
+ return len;
+}
+
+/* reset statistics */
+static int emac_p_reset_statistics(struct net_device *netdev)
+{
+ emac_dev_t *dev = NETDEV_PRIV(netdev);
+
+ memset(&dev->device_mib, 0, sizeof(emac_hw_statistics));
+ memset(&dev->device_stats, 0, sizeof(emac_drv_stats));
+ memset(&dev->net_dev_stats, 0, sizeof(struct net_device_stats));
+
+ /* clear statistics */
+ if (emac_control(dev, EMAC_IOCTL_CLR_STATISTICS, NULL, NULL)
+ != EMAC_SUCCESS) {
+ ERR("Error clearing statistics in DDC for %s\n", netdev->name);
+
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* update statistics */
+static int emac_p_update_statistics(struct net_device *netdev, char *buf,
+ int limit, int *p_len)
+{
+ unsigned long rx_hal_errors = 0;
+ unsigned long rx_hal_discards = 0;
+ unsigned long tx_hal_errors = 0;
+ unsigned long if_out_discards = 0;
+ unsigned long if_in_discards = 0;
+ unsigned long if_out_errors = 0;
+ unsigned long if_in_errors = 0;
+ emac_dev_t *dev = NETDEV_PRIV(netdev);
+ emac_hw_statistics *p_device_mib = &dev->device_mib;
+ emac_drv_stats *p_stats = &dev->device_stats;
+ emac_hw_statistics local_mib;
+ emac_hw_statistics *p_local_mib = &local_mib;
+ struct net_device_stats *p_net_dev_stats = &dev->net_dev_stats;
+ int len = 0;
+ int dev_mib_elem_count = 0;
+
+ /* do not access the hardware if it is in the reset state. */
+ if (!test_bit(0, &dev->set_to_close)) {
+ /* get hardware statistics from DDC */
+ if (emac_control
+ (dev, EMAC_IOCTL_GET_STATISTICS, (void *)p_local_mib, NULL)
+ != EMAC_SUCCESS) {
+ ERR("Error getting statistics for %s\n", netdev->name);
+
+ return (-1);
+ }
+
+ dev_mib_elem_count =
+ sizeof(emac_hw_statistics) / sizeof(unsigned long);
+
+ /* Update the history of the stats. This takes care of
+ * any reset of the device and stats that might have
+ * taken place during the life time of the driver.
+ */
+ while (dev_mib_elem_count--) {
+ *((unsigned long *)p_device_mib + dev_mib_elem_count) =
+ *((unsigned long *)p_local_mib +
+ dev_mib_elem_count);
+ }
+ }
+
+ /* RFC2665, section 3.2.7, page 9 */
+ rx_hal_errors =
+ p_device_mib->if_in_fragments +
+ p_device_mib->if_in_crcerrors +
+ p_device_mib->if_in_align_code_errors +
+ p_device_mib->if_in_jabber_frames;
+
+ /* RFC2233 */
+ rx_hal_discards = p_device_mib->if_rx_dmaoverruns;
+
+ /* RFC2665, section 3.2.7, page 9 */
+ tx_hal_errors =
+ p_device_mib->if_excessive_collision_frames +
+ p_device_mib->if_late_collisions +
+ p_device_mib->if_carrier_sense_errors +
+ p_device_mib->if_out_underrun;
+
+ /* if not set, the short frames (< 64 bytes) are considered as
+ errors */
+ if (dev->init_cfg.rx_cfg.copy_short_frames_enable == FALSE)
+ rx_hal_errors += p_device_mib->if_in_undersized_frames;
+
+ /* All frames greater than max rx frame length set in hardware
+ * should be considered error frames RFC2665, section 3.2.7,
+ * page 9. */
+ rx_hal_errors += p_device_mib->if_in_oversized_frames;
+
+ /* if not in promiscous, then non addr matching frames are discarded */
+ /* EMAC 2.0 manual section 2.8.1.14 */
+ if (dev->init_cfg.rx_cfg.promiscous_enable == FALSE) {
+ if_in_discards += p_device_mib->if_in_filtered_frames;
+ }
+
+ /* total rx discards = hal discards */
+ if_in_discards = rx_hal_discards;
+ p_net_dev_stats->rx_dropped = rx_hal_discards;
+ p_net_dev_stats->rx_crc_errors = p_device_mib->if_in_crcerrors;
+ p_net_dev_stats->rx_frame_errors =
+ p_device_mib->if_in_align_code_errors;
+ p_net_dev_stats->multicast = p_device_mib->if_in_multicasts;
+ if_in_errors = rx_hal_errors;
+ if_out_errors = tx_hal_errors;
+ if_out_discards = p_net_dev_stats->tx_dropped;
+
+ /* let us update the net device stats struct. to be updated in
+ the later releases. */
+ dev->net_dev_stats.rx_errors = if_in_errors;
+ dev->net_dev_stats.collisions = p_device_mib->if_collision_frames;
+ dev->net_dev_stats.tx_carrier_errors =
+ p_device_mib->if_carrier_sense_errors;
+
+ if (buf == NULL || limit == 0) {
+ return (0);
+ }
+
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifSpeed",
+ dev->link_speed);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "dot3StatsDuplexStatus",
+ dev->link_mode);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifAdminStatus",
+ (netdev->flags & IFF_UP ? 1 : 2));
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifOperStatus",
+ (((netdev->flags & IFF_UP)
+ && netif_carrier_ok(netdev)) ? 1 : 2));
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %lu\n", "ifLastChange",
+ p_stats->start_tick);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %lu\n", "ifInDiscards",
+ if_in_discards);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %lu\n", "ifInErrors",
+ if_in_errors);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %lu\n", "ifOutDiscards",
+ if_out_discards);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %lu\n", "ifOutErrors",
+ if_out_errors);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifInGoodFrames",
+ p_device_mib->if_in_good_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifInBroadcasts",
+ p_device_mib->if_in_broadcasts);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifInMulticasts",
+ p_device_mib->if_in_multicasts);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifInPauseFrames",
+ p_device_mib->if_in_pause_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifInCRCErrors",
+ p_device_mib->if_in_crcerrors);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifInAlignCodeErrors",
+ p_device_mib->if_in_align_code_errors);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifInOversizedFrames",
+ p_device_mib->if_in_oversized_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifInJabberFrames",
+ p_device_mib->if_in_jabber_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifInUndersizedFrames",
+ p_device_mib->if_in_undersized_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifInFragments",
+ p_device_mib->if_in_fragments);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifInFilteredFrames",
+ p_device_mib->if_in_filtered_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifInQosFilteredFrames",
+ p_device_mib->if_in_qos_filtered_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifInOctets",
+ p_device_mib->if_in_octets);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifOutGoodFrames",
+ p_device_mib->if_out_good_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifOutBroadcasts",
+ p_device_mib->if_out_broadcasts);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifOutMulticasts",
+ p_device_mib->if_out_multicasts);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifOutPauseFrames",
+ p_device_mib->if_out_pause_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifDeferredTransmissions",
+ p_device_mib->if_deferred_transmissions);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifCollisionFrames",
+ p_device_mib->if_collision_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifSingleCollisionFrames",
+ p_device_mib->if_single_collision_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n",
+ "ifMultipleCollisionFrames",
+ p_device_mib->if_multiple_collision_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n",
+ "ifExcessiveCollisionFrames",
+ p_device_mib->if_excessive_collision_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifLateCollisions",
+ p_device_mib->if_late_collisions);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifOutUnderrun",
+ p_device_mib->if_out_underrun);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifCarrierSenseErrors",
+ p_device_mib->if_carrier_sense_errors);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifOutOctets",
+ p_device_mib->if_out_octets);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "if64OctetFrames",
+ p_device_mib->if64octet_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "if65To127POctetFrames",
+ p_device_mib->if65to127octet_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "if128To255OctetFrames",
+ p_device_mib->if128to255octet_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "if256To511OctetFrames",
+ p_device_mib->if256to511octet_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "if512To1023OctetFrames",
+ p_device_mib->if512to1023octet_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "if1024ToUpOctetFrames",
+ p_device_mib->if1024to_upoctet_frames);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifNetOctets",
+ p_device_mib->if_net_octets);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifRxSofOverruns",
+ p_device_mib->if_rx_sof_overruns);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifRxMofOverruns",
+ p_device_mib->if_rx_mof_overruns);
+ if (len <= limit)
+ len +=
+ sprintf(buf + len, "%-35s: %u\n", "ifRxDMAOverruns",
+ p_device_mib->if_rx_dmaoverruns);
+ *p_len = len;
+
+ return (0);
+}
+
+/* version info */
+static int emac_p_get_version(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data)
+{
+ int len = 0;
+
+ len += sprintf(buf + len, "Texas Instruments : %s\n",
+ emac_version_string);
+ return len;
+}
+
+/* tick timer */
+static void emac_p_tick_timer_expiry(emac_dev_t * dev)
+{
+ struct timer_list *p_timer = &dev->periodic_timer;
+
+ if (test_bit(0, &dev->set_to_close)) {
+ return;
+ }
+
+ if (dev->timer_active == TRUE) {
+ emac_tick(dev, NULL);
+
+ /* restart the timer */
+ p_timer->expires = jiffies + dev->periodic_ticks;
+ add_timer(p_timer);
+ }
+}
+
+/* mib timer */
+static void emac_p_mib_timer_expiry(emac_dev_t * dev)
+{
+ struct timer_list *p_timer = &dev->mib_timer;
+
+ if (test_bit(0, &dev->set_to_close)) {
+ return;
+ }
+
+ if (dev->mib_timer_active == TRUE) {
+ emac_control(dev, EMAC_IOCTL_IF_PARAMS_UPDT, NULL, NULL);
+
+ /* restart the timer */
+ p_timer->expires = jiffies + dev->mib_ticks;
+ add_timer(p_timer);
+ }
+}
+
+/******************************************************************************
+ * Device enable/disable functions
+ *****************************************************************************/
+
+/* enable the device - init TX/RX channels and open DDC */
+static int emac_p_dev_enable(emac_dev_t * dev)
+{
+ int ret_code;
+ struct net_device *netdev = dev->owner;
+
+ dev->set_to_close = 0;
+
+ /* create a TX channel */
+ ret_code = emac_ch_open(dev, &dev->tx_ch_info[0], NULL);
+
+ if (ret_code != EMAC_SUCCESS) {
+ ERR("%s error: Error %08X from EMAC TX Channel Open()\n",
+ netdev->name, ret_code);
+
+ return (-1);
+ }
+
+ /* create a RX channel - note that last param contains mac address */
+ ret_code =
+ emac_ch_open(dev, &dev->rx_ch_info[0], (void *)&dev->mac_addr[0]);
+ if (ret_code != EMAC_SUCCESS) {
+ ERR("%s error: Error %08X from EMAC RX Channel Open()\n",
+ netdev->name, ret_code);
+
+ return (-1);
+ }
+
+ /* open DDC instance */
+ ret_code = emac_open(dev, NULL);
+ if (ret_code != EMAC_SUCCESS) {
+ ERR("%s error: Error %08X from EMAC Open()\n",
+ netdev->name, ret_code);
+
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* disable the device - teardown chanels and close DDC */
+static int emac_p_dev_disable(emac_dev_t * dev)
+{
+ int ret_code;
+ struct net_device *netdev = dev->owner;
+
+ /* inform the upper layers. */
+ netif_stop_queue(dev->owner);
+
+ /* prepare to close */
+ set_bit(0, &dev->set_to_close);
+
+ /* closing the DDC instance will close all channels also */
+ ret_code = emac_close(dev, NULL);
+
+ if (ret_code != EMAC_SUCCESS) {
+ ERR("%s error: Error %08X from EMAC Close()\n",
+ netdev->name, ret_code);
+ return (-1);
+ } else {
+ /* DDC should turn off the timer, but just in case */
+ if (dev->timer_active != FALSE) {
+ del_timer_sync(&dev->periodic_timer);
+ dev->timer_active = FALSE;
+ }
+
+ DBG("Device %s Closed.\n", netdev->name);
+ dev->device_stats.start_tick = jiffies;
+ dev->link_speed = 100000000;
+ dev->link_mode = 1;
+ netif_carrier_off(netdev);
+ }
+
+ return (0);
+}
+
+/******************************************************************************
+ * Net Device functions
+ *****************************************************************************/
+
+/* get statistics */
+static struct net_device_stats *emac_dev_get_net_stats(struct net_device
+ *netdev)
+{
+ emac_dev_t *dev = NETDEV_PRIV(netdev);
+
+ emac_p_update_statistics(netdev, NULL, 0, NULL);
+ return &dev->net_dev_stats;
+}
+
+/* set multicast address in the driver */
+static void emac_dev_mcast_set(struct net_device *netdev)
+{
+ emac_dev_t *dev = NETDEV_PRIV(netdev);
+
+ if (netdev->flags & IFF_PROMISC) {
+ /* enable promiscous mode */
+ dev->init_cfg.rx_cfg.promiscous_enable = TRUE;
+
+ emac_control(dev,
+ EMAC_IOCTL_SET_RXCFG,
+ (void *)&dev->init_cfg.rx_cfg, NULL);
+ } else if ((netdev->flags & IFF_ALLMULTI) ||
+ (netdev->mc_count > EMAC_DEFAULT_MAX_MULTICAST_ADDRESSES)) {
+ /* enable multicast - disable promiscous */
+ dev->init_cfg.rx_cfg.promiscous_enable = FALSE;
+ dev->init_cfg.rx_cfg.multicast_enable = TRUE;
+ emac_control(dev,
+ EMAC_IOCTL_SET_RXCFG,
+ (void *)&dev->init_cfg.rx_cfg, NULL);
+
+ /* enable all multicast addresses */
+ emac_control(dev, EMAC_IOCTL_ALL_MULTI, (void *)
+ EMAC_ALL_MULTI_SET, NULL);
+ } else if (netdev->mc_count == 0) {
+ /* only unicast mode to be set - clear promiscous and
+ clear multicast modes */
+ emac_control(dev, EMAC_IOCTL_ALL_MULTI, (void *)
+ EMAC_ALL_MULTI_CLR, NULL);
+
+ /* disable promiscous and multicast modes */
+ dev->init_cfg.rx_cfg.promiscous_enable = FALSE;
+ dev->init_cfg.rx_cfg.multicast_enable = FALSE;
+ emac_control(dev,
+ EMAC_IOCTL_SET_RXCFG,
+ (void *)&dev->init_cfg.rx_cfg, NULL);
+ } else if (netdev->mc_count) {
+ struct dev_mc_list *mc_ptr;
+
+ /* clear multicast list first */
+ emac_control(dev, EMAC_IOCTL_ALL_MULTI, (void *)
+ EMAC_ALL_MULTI_CLR, NULL);
+
+ /* enable multicast - disable promiscous */
+ dev->init_cfg.rx_cfg.promiscous_enable = FALSE;
+ dev->init_cfg.rx_cfg.multicast_enable = TRUE;
+ emac_control(dev,
+ EMAC_IOCTL_SET_RXCFG,
+ (void *)&dev->init_cfg.rx_cfg, NULL);
+
+ /* program multicast address list into EMAC hardware */
+ for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+ emac_control(dev, EMAC_IOCTL_MULTICAST_ADDR, (void *)
+ EMAC_MULTICAST_ADD, (void *)
+ mc_ptr->dmi_addr);
+ }
+ } else {
+ DBG("%s:No Multicast address to set.\n", netdev->name);
+ }
+}
+
+static int emac_dev_set_mac_addr(struct net_device *netdev, void *addr)
+{
+ int ret_code;
+ emac_address_params address_params;
+ struct sockaddr *sa = addr;
+ emac_dev_t *dev = NETDEV_PRIV(netdev);
+
+ address_params.channel = EMAC_DEFAULT_RX_CHANNEL;
+ address_params.mac_address = sa->sa_data;
+
+ ret_code =
+ emac_control(dev,
+ EMAC_IOCTL_SET_MAC_ADDRESS,
+ (emac_address_params *) & address_params, NULL);
+
+ if (ret_code != EMAC_SUCCESS) {
+ ERR("%s error: Error %08X from EMAC TX Channel Open()\n",
+ netdev->name, ret_code);
+
+ return -EIO;
+ }
+ memcpy(dev->mac_addr, sa->sa_data, netdev->addr_len);
+ memcpy(netdev->dev_addr, sa->sa_data, netdev->addr_len);
+ return 0;
+}
+
+static void emac_tx_timeout(struct net_device *netdev)
+{
+ int ret_code;
+ emac_dev_t *dev = NETDEV_PRIV(netdev);
+
+ printk("EMAC Tx Timeout: Closing TX channel\n");
+ emac_ch_close(dev,
+ dev->tx_ch_info[0].ch_num, dev->tx_ch_info[0].ch_dir, 0);
+
+ printk("EMAC Tx Timeout: Opening TX channel\n");
+ ret_code = emac_ch_open(dev, &dev->tx_ch_info[0], NULL);
+
+ if (ret_code != EMAC_SUCCESS) {
+ ERR("%s error: Error %08X from EMAC TX Channel Open()\n",
+ netdev->name, ret_code);
+ } else {
+ ERR("EMAC Tx Timeout: "
+ "successfully closed and opened channels\n");
+ }
+
+ /* update interface statistics */
+ dev->net_dev_stats.tx_errors++;
+}
+
+/***************************************************************
+ * emac_dev_init
+ *
+ * Returns:
+ * 0 on success, error code otherwise.
+ * Parms:
+ * dev The structure of the device to be
+ * init'ed.
+ *
+ * This function completes the initialization of the
+ * device structure and driver. It reserves the IO
+ * addresses and assignes the device's methods.
+ *
+ **************************************************************/
+static int emac_dev_init(struct net_device *netdev)
+{
+ int cnt, init_status = 0;
+ int ret_code;
+ char *mac_name = NULL;
+ char *mac_string = NULL;
+ char *default_mac_string = NULL;
+ emac_dev_t *dev = NETDEV_PRIV(netdev);
+ int instance_num = dev->instance_num;
+
+ /* create mac name */
+ switch (instance_num) {
+ case 0:
+ mac_name = EMAC_MAC_ADDR_A;
+ emac_eth_setup();
+
+ /* we are getting default MAC address from bootloader */
+ if (strcmp(emac_eth_string, "deadbeaf") == 0) {
+ default_mac_string = "08.00.28.32.06.08";
+ } else {
+ default_mac_string = &emac_eth_string[0];
+ }
+ break;
+ default:
+ mac_name = "";
+ default_mac_string = "08.00.28.32.06.08";
+ break;
+ }
+
+ mac_string = default_mac_string;
+ emac_str_to_ethaddr(dev->mac_addr, mac_string);
+ for (cnt = 0; cnt <= ETH_ALEN; cnt++) {
+ netdev->dev_addr[cnt] = dev->mac_addr[cnt];
+ }
+
+ dev->set_to_close = 1;
+
+ /* get configuration information for this instance */
+ /* when config service is available, use it */
+ if (emac_net_get_config(dev) != 0) {
+ ERR("Could not fetch configuration information\n");
+ goto emac_dev_init_exit;
+ }
+
+ dev->init_cfg.inst_id = instance_num;
+ dev->drv_state = DRV_CREATED;
+ init_status = 1; /* instance created */
+
+ /* initialize instance by passing initial configuration struct */
+ ret_code = emac_init(dev, &dev->init_cfg);
+
+ if (ret_code != EMAC_SUCCESS) {
+ ERR("Error %08X from Init()\n", ret_code);
+ goto emac_dev_init_exit;
+ }
+
+ init_status = 2; /* instance initialized */
+
+ /* init spin lock */
+ spin_lock_init(&dev->tx_lock);
+ spin_lock_init(&dev->rx_lock);
+
+ /* set as per RFC 2665 */
+ dev->link_speed = 100000000;
+ dev->link_mode = 1;
+
+ /* initialize the timers for the net device - the timer will
+ be started by DDC calling the ioctl on DDA */
+ init_timer(&dev->periodic_timer);
+ dev->periodic_ticks = 0;
+ dev->periodic_timer.expires = 0;
+ dev->timer_active = FALSE;
+ dev->periodic_timer.data = (unsigned long)dev;
+ dev->periodic_timer.function =
+ (timer_tick_func) emac_p_tick_timer_expiry;
+ init_timer(&dev->mib_timer);
+ dev->mib_timer_active = FALSE;
+ dev->mib_timer.data = (unsigned long)dev;
+ dev->mib_timer.function = (timer_tick_func) emac_p_mib_timer_expiry;
+
+ /* populate the device structure */
+ netdev->addr_len = 6;
+ netdev->open = emac_dev_open; /* i.e. start device */
+ netdev->do_ioctl = emac_ioctl;
+ netdev->hard_start_xmit = emac_dev_tx;
+ netdev->stop = emac_dev_close;
+ netdev->get_stats = emac_dev_get_net_stats;
+ netdev->set_multicast_list = emac_dev_mcast_set;
+ netdev->tx_timeout = emac_tx_timeout;
+ netdev->set_mac_address = emac_dev_set_mac_addr;
+ netdev->poll = emac_poll;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = emac_poll_controller;
+#endif
+ netdev->weight = EMAC_DEFAULT_RX_MAX_SERVICE;
+
+ /* reset the broadcast and multicast flags and enable them
+ based upon configuration of driver */
+ netdev->flags &= ~(IFF_PROMISC | IFF_BROADCAST | IFF_MULTICAST);
+ if (dev->init_cfg.rx_cfg.broadcast_enable == TRUE)
+ netdev->flags |= IFF_BROADCAST;
+ if (dev->init_cfg.rx_cfg.multicast_enable == TRUE)
+ netdev->flags |= IFF_MULTICAST;
+
+ netif_carrier_off(netdev);
+ netdev->irq = dev->init_cfg.intr_line;
+
+ /* request memory region from the kernel */
+ netdev->base_addr = dev->init_cfg.base_address;
+ request_mem_region(netdev->base_addr, EMAC_DEFAULT_EMAC_SIZE,
+ netdev->name);
+
+ /* if following flag ON then open DDC */
+ if (g_init_enable_flag) {
+ if (emac_p_dev_enable(dev)) {
+ ERR("device could not OPEN\n");
+ goto emac_dev_init_exit;
+ }
+ }
+
+ return (0);
+
+ emac_dev_init_exit:
+ /* all resources allocated are freed - call the un-init
+ sequence on DDC */
+ switch (init_status) {
+
+ case 2:
+ ret_code = emac_de_init(dev, NULL);
+
+ if (ret_code != EMAC_SUCCESS)
+ ERR("%s: Error %08X from Deinit()\n",
+ netdev->name, ret_code);
+ default:
+ break;
+ }
+
+ return (-1);
+}
+
+/******************************************************************************
+ * Device Open/Close functions
+ *****************************************************************************/
+
+/* open the adapter */
+static int emac_dev_open(struct net_device *netdev)
+{
+ emac_dev_t *dev = NETDEV_PRIV(netdev);
+
+ if (!g_init_enable_flag) {
+ if (emac_p_dev_enable(dev)) {
+ ERR("%s error: device could not OPEN\n", netdev->name);
+ return (-1);
+ }
+ }
+
+ if (request_irq(dev->init_cfg.intr_line, emac_hal_isr, IRQF_DISABLED,
+ "EMAC", dev)) {
+ ERR("Failed to register the irq %d for TI DaVinci EMAC %s.\n",
+ dev->init_cfg.intr_line, netdev->name);
+
+ return (-1);
+ }
+ if (netif_carrier_ok(netdev))
+ netif_start_queue(netdev);
+ else
+ netif_stop_queue(netdev);
+
+ dev->device_stats.start_tick = jiffies;
+ DBG("Started the network queue for %s.\n", netdev->name);
+ return (0);
+}
+
+/* close the adapter */
+static int emac_dev_close(struct net_device *netdev)
+{
+ emac_dev_t *dev = NETDEV_PRIV(netdev);
+
+ if (!g_init_enable_flag)
+ emac_p_dev_disable(dev);
+
+ /* free ISR */
+ free_irq(dev->init_cfg.intr_line, dev);
+
+ return (0);
+}
+
+/* ioctl function */
+static int emac_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+ emac_drv_priv_ioctl priv_ioctl;
+ emac_dev_t *dev = NETDEV_PRIV(netdev);
+
+ if (cmd == SIOCDEVPRIVATE) {
+ /* copy user data */
+ if (copy_from_user
+ ((char *)&priv_ioctl, (char *)rq->ifr_data,
+ sizeof(emac_drv_priv_ioctl)))
+ return -EFAULT;
+
+ switch (priv_ioctl.cmd) {
+ /* program type 2/3 address filter */
+ case EMAC_PRIV_FILTERING:
+ {
+ emac_type2_3_addr_filter_params filter_params;
+
+ if (copy_from_user
+ ((char *)&filter_params,
+ (char *)priv_ioctl.data,
+ sizeof(emac_type2_3_addr_filter_params)))
+
+ return -EFAULT;
+
+ if (emac_control(dev,
+ EMAC_IOCTL_TYPE2_3_FILTERING,
+ (emac_type2_3_addr_filter_params
+ *) & filter_params, NULL)
+ != EMAC_SUCCESS) {
+ ERR("Failed to read params");
+ return -EFAULT;
+ }
+ break;
+ }
+
+ /* read PHY register via MII interface */
+ case EMAC_PRIV_MII_READ:
+ {
+ emac_phy_params phy_params;
+ unsigned long irq_flags;
+
+ /* copy user data into local variable */
+ if (copy_from_user
+ ((char *)&phy_params,
+ (char *)priv_ioctl.data,
+ sizeof(emac_phy_params)))
+ return -EFAULT;
+
+ /* make sure this function does not
+ * clash with mii access during tick
+ * function */
+ local_irq_save(irq_flags);
+
+ if (emac_control(dev,
+ EMAC_IOCTL_READ_PHY_REG,
+ (void *)&phy_params,
+ NULL) != EMAC_SUCCESS) {
+ ERR("Failed to read params");
+ return -EFAULT;
+ }
+
+ /* copy the local data to user space */
+ if (copy_to_user
+ ((char *)priv_ioctl.data,
+ (char *)&phy_params,
+ sizeof(emac_phy_params)))
+ return -EFAULT;
+
+ /* enable tick timer to access phy now
+ if required */
+ local_irq_restore(irq_flags);
+ }
+
+ break;
+
+ /* write PHY register via MII interface */
+ case EMAC_PRIV_MII_WRITE:
+ {
+ emac_phy_params phy_params;
+ unsigned long irq_flags;
+
+ /* copy user data into local variable */
+ if (copy_from_user
+ ((char *)&phy_params,
+ (char *)priv_ioctl.data,
+ sizeof(emac_phy_params)))
+ return -EFAULT;
+
+ /* make sure this function does not
+ clash with mii access during tick
+ function */
+ local_irq_save(irq_flags);
+
+ if (emac_control(dev,
+ EMAC_IOCTL_WRITE_PHY_REG,
+ (void *)&phy_params,
+ NULL) != EMAC_SUCCESS) {
+ ERR("Failed to read params");
+ return -EFAULT;
+ }
+
+ /* enable tick timer to access phy now
+ if required */
+ local_irq_restore(irq_flags);
+ }
+ break;
+
+ /* get statistics */
+ case EMAC_PRIV_GET_STATS:
+ {
+ emac_hw_statistics stats;
+
+ /* Caller provides memory for HW stats
+ structure via "data" pointer */
+ if (emac_control(dev,
+ EMAC_IOCTL_GET_STATISTICS,
+ (void *)&stats, NULL)
+ != EMAC_SUCCESS) {
+ ERR("Failed to get statistics");
+ return (EMAC_INTERNAL_FAILURE);
+ }
+
+ /* copy the local data to user space */
+ if (copy_to_user
+ ((char *)priv_ioctl.data, (char *)&stats,
+ sizeof(emac_hw_statistics)))
+ return -EFAULT;
+ break;
+ }
+
+ /* clear statistics */
+ case EMAC_PRIV_CLR_STATS:
+ {
+ if (emac_control(dev,
+ EMAC_IOCTL_CLR_STATISTICS,
+ NULL, NULL)
+ != EMAC_SUCCESS) {
+ ERR("Failed to clear statistics");
+ return (EMAC_INTERNAL_FAILURE);
+ }
+ break;
+ }
+ default:
+ return -EFAULT;
+ break;
+ }
+ }
+
+ else if (cmd == SIOTIMIB2) {
+ TI_SNMP_CMD_T ti_snmp_cmd;
+
+ /* now copy the user data */
+ if (copy_from_user
+ ((char *)&ti_snmp_cmd, (char *)rq->ifr_data,
+ sizeof(TI_SNMP_CMD_T)))
+ return -EFAULT;
+
+ switch (ti_snmp_cmd.cmd) {
+ case TI_SIOCGINTFCOUNTERS:
+ {
+ struct mib2_if_counters mib_counter;
+
+ /* Caller provides memory for HW stats
+ structure via "data" pointer */
+ if (emac_control(dev,
+ EMAC_IOCTL_IF_COUNTERS,
+ (void *)&mib_counter, NULL)
+ != EMAC_SUCCESS) {
+ ERR("Failed to get statistics");
+ return (EMAC_INTERNAL_FAILURE);
+ }
+
+ /* copy the local data to user space */
+ if (copy_to_user
+ ((char *)ti_snmp_cmd.data,
+ (char *)&mib_counter,
+ sizeof(struct mib2_if_counters)))
+ return -EFAULT;
+ break;
+ }
+ case TI_SIOCGINTFPARAMS:
+ {
+ struct mib2_if_params local_params;
+
+ local_params.if_speed = dev->link_speed;
+ local_params.if_high_speed =
+ (local_params.if_speed) / 1000000;
+ local_params.if_oper_status =
+ ((netdev->
+ flags & IFF_UP) ? MIB2_STATUS_UP :
+ MIB2_STATUS_DOWN);
+ local_params.if_promiscuous_mode =
+ ((netdev->
+ flags & IFF_PROMISC) ? TRUE : FALSE);
+
+ /* now copy the counters to the user data */
+ if (copy_to_user
+ ((char *)ti_snmp_cmd.data,
+ (char *)&local_params,
+ sizeof(struct mib2_if_params)))
+ return -EFAULT;
+ }
+ break;
+
+ case TI_SIOCGETHERCOUNTERS:
+ {
+ struct mib2_phy_counters phy_counter;
+
+ /* Caller provides memory for HW stats
+ structure via "data" pointer */
+ if (emac_control(dev,
+ EMAC_IOCTL_ETHER_COUNTERS,
+ (void *)&phy_counter, NULL)
+ != EMAC_SUCCESS) {
+ ERR("Failed to get statistics");
+
+ return (EMAC_INTERNAL_FAILURE);
+ }
+
+ /* copy the local data to user space */
+ if (copy_to_user
+ ((char *)ti_snmp_cmd.data,
+ (char *)&phy_counter,
+ sizeof(struct mib2_phy_counters)))
+ return -EFAULT;
+ break;
+ }
+
+ case TI_SIOCGETHERPARAMS:
+ {
+ struct mib2_eth_params local_params;
+
+ local_params.eth_duplex_status =
+ ((dev->link_mode ==
+ PHY_DUPLEX_FULL) ?
+ MIB2_FULL_DUPLEX : MIB2_HALF_DUPLEX);
+
+ /* now copy the counters to the user data */
+ if (copy_to_user
+ ((char *)ti_snmp_cmd.data,
+ (char *)&local_params,
+ sizeof(struct mib2_eth_params)))
+ return -EFAULT;
+ break;
+ }
+
+ default:
+ return -EFAULT;
+ }
+ } else {
+ return -EFAULT;
+ }
+
+ return (0);
+}
+
+/* PHY related interface below */
+#include "davinci_emac_phy.h"
+
+/************************ HASH SUPPORT FUNCTIONS ************************/
+
+/* get hash value using mechainsm in specs */
+static u32 hash_get(u8 * addr)
+{
+ u32 hash;
+ u8 tmpval;
+ int cnt;
+ hash = 0;
+
+ for (cnt = 0; cnt < 2; cnt++) {
+ tmpval = *addr++;
+ hash ^= (tmpval >> 2) ^ (tmpval << 4);
+ tmpval = *addr++;
+ hash ^= (tmpval >> 4) ^ (tmpval << 2);
+ tmpval = *addr++;
+ hash ^= (tmpval >> 6) ^ (tmpval);
+ }
+
+ return (hash & 0x3F);
+}
+
+/**
+ * Hash Table Add
+ * - Adds mac address to hash table and upates hash bits in hardware
+ * - Returns negative if error, 0 if no change to registers, >0 if
+ * hash registers need to change
+ */
+static int hash_add(emac_dev_t * _dev, u8 * mac_address)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ u32 hash_value;
+ u32 hash_bit;
+ u32 status = 0;
+ hash_value = hash_get(mac_address);
+
+ if (hash_value >= EMAC_NUM_MULTICAST_BITS) {
+ LOGERR("Invalid Hash Value=%d. Should not be greater than %d",
+ hash_value, (EMAC_NUM_MULTICAST_BITS - 1));
+ return (EMAC_INVALID_PARAM);
+ }
+
+ /* set the hash bit only if not previously set */
+ if (dev->multicast_hash_cnt[hash_value] == 0) {
+ status = 1;
+ if (hash_value < 32) {
+ hash_bit = (1 << hash_value);
+ dev->mac_hash1 |= hash_bit;
+ } else {
+ hash_bit = (1 << (hash_value - 32));
+ dev->mac_hash2 |= hash_bit;
+ }
+ }
+
+ /* increment counter to maintain number of multicast address
+ that map to this hash bit */
+ ++dev->multicast_hash_cnt[hash_value];
+
+ return (status);
+}
+
+/**
+ * Hash Table Del
+ * - Deletes a mac address from hash table and updates hash register bits
+ * - Returns negative if error, 0 if no change to registers, >0 if
+ * hash registers need to change
+ */
+static int hash_del(emac_dev_t * _dev, u8 * mac_address)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ u32 hash_value;
+ u32 hash_bit;
+
+ hash_value = hash_get(mac_address);
+ if (dev->multicast_hash_cnt[hash_value] > 0) {
+ /* decrement counter to reduce number of multicast
+ * address that map to this hash bit */
+ --dev->multicast_hash_cnt[hash_value];
+ }
+
+ /* if counter still > 0, at least one multicast address refers
+ * to this hash bit. so return 0 */
+ if (dev->multicast_hash_cnt[hash_value] > 0) {
+ return (0);
+ }
+
+ if (hash_value < 32) {
+ hash_bit = (1 << hash_value);
+ dev->mac_hash1 &= ~hash_bit;
+ } else {
+ hash_bit = (1 << (hash_value - 32));
+ dev->mac_hash2 &= ~hash_bit;
+ }
+
+ /* return 1 to indicate change in mac_hash registers reqd */
+ return (1);
+}
+
+/* updates hash register bits with single multicast address add/delete
+ * operation */
+static void emac_single_multi(emac_dev_t * _dev, emac_single_multi_oper oper,
+ u8 * addr)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ int status = -1;
+
+ switch (oper) {
+ case EMAC_MULTICAST_ADD:
+ status = hash_add(_dev, addr);
+ break;
+
+ case EMAC_MULTICAST_DEL:
+ status = hash_del(_dev, addr);
+ break;
+
+ default:
+ LOGERR("Unhandled Single Multicast operation %d", oper);
+ break;
+ }
+
+ /* write to the hardware only if the register status chances */
+ if (status > 0) {
+ dev->regs->mac_hash1 = dev->mac_hash1;
+ dev->regs->mac_hash2 = dev->mac_hash2;
+ }
+}
+
+/* updates hash register bits for all multi operation (set/clear) */
+static void emac_all_multi(emac_dev_t * _dev, emac_all_multi_oper oper)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+
+ switch (oper) {
+ case EMAC_ALL_MULTI_SET:
+ dev->mac_hash1 = EMAC_ALL_MULTI_REG_VALUE;
+ dev->mac_hash2 = EMAC_ALL_MULTI_REG_VALUE;
+ break;
+ case EMAC_ALL_MULTI_CLR:
+ dev->mac_hash1 = 0;
+ dev->mac_hash2 = 0;
+ memset(&(dev->multicast_hash_cnt[0]), 0 ,
+ sizeof(dev->multicast_hash_cnt[0]) * EMAC_NUM_MULTICAST_BITS);
+ break;
+ default:
+ LOGERR("Unhandled All multi operation %d", oper);
+ break;
+ }
+
+ dev->regs->mac_hash1 = dev->mac_hash1;
+ dev->regs->mac_hash2 = dev->mac_hash2;
+}
+
+/************************ PHY related functions ************************/
+
+/* Cpmac Update Phy Status - updates phy status variables in hDDC->status "CpmacDDCStatus" structure */
+static int emac_update_phy_status(emac_dev_t * _dev)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ u32 set_phy_mode;
+
+ LOGMSG(EMAC_DEBUG_BUSY_FUNCTION_ENTRY, "");
+
+ /* verify proper device state */
+ if (dev->drv_state != DRV_OPENED) {
+ LOGERR("Device NOT Open");
+ return (EMAC_ERR_DEV_NOT_OPEN);
+ }
+
+ set_phy_mode = dev->init_cfg.phy_mode;
+
+ /* no phy condition */
+ if (set_phy_mode & SNWAY_NOPHY) {
+ /* no phy condition, always linked */
+ dev->status.phy_linked = 1;
+ dev->status.phy_speed = 100;
+ dev->status.phy_duplex = PHY_DUPLEX_FULL;
+ dev->status.phy_num = 0xFFFFFFFF; /* no phy */
+ dev->mac_control |= (1 << EMAC_MACCONTROL_FULLDUPLEXEN_SHIFT);
+
+ /* write mac control register from stored value */
+ dev->regs->mac_control = dev->mac_control;
+ goto emac_update_phy_status_exit;
+ }
+
+ /* if loopback set in hardware, set link to ON */
+ if (dev->mac_control & EMAC_MACCONTROL_LOOPBKEN_MASK) {
+ dev->status.phy_linked = 1;
+ goto emac_update_phy_status_exit;
+ }
+ if (set_phy_mode & SNWAY_LPBK) {
+ dev->status.phy_linked = emac_mdio_is_loopback();
+ } else {
+ dev->status.phy_linked = emac_mdio_is_linked();
+ }
+
+ if (dev->status.phy_linked) {
+ /* retreive duplex and speed and the phy number */
+ if (set_phy_mode & SNWAY_LPBK) {
+ dev->status.phy_duplex = PHY_DUPLEX_FULL;
+ } else {
+ dev->status.phy_duplex = emac_mdio_get_duplex();
+ }
+ dev->status.phy_speed = emac_mdio_get_speed();
+ dev->status.phy_num = emac_mdio_get_phy_num();
+
+ /* set the duplex bit in maccontrol */
+ if (dev->status.phy_duplex == PHY_DUPLEX_FULL) {
+ dev->mac_control |=
+ (1 << EMAC_MACCONTROL_FULLDUPLEXEN_SHIFT);
+ } else {
+ dev->mac_control &=
+ ~(1 << EMAC_MACCONTROL_FULLDUPLEXEN_SHIFT);
+ }
+
+ }
+
+ /* write mac control register from stored value */
+ dev->regs->mac_control = dev->mac_control;
+
+ emac_update_phy_status_exit:
+ LOGMSG(EMAC_DEBUG_PORT_UPDATE,
+ "MacControl=%08X, Status: Phy=%d, Speed=%s, Duplex=%s",
+ dev->mac_control, dev->status.phy_num,
+ (dev->status.phy_speed == 100) ? "100" : "10",
+ (dev->status.phy_duplex == PHY_DUPLEX_FULL) ? "Full" : "Half");
+ LOGMSG(EMAC_DEBUG_BUSY_FUNCTION_EXIT, "");
+
+ return (EMAC_SUCCESS);
+}
+
+/* set phy mode */
+static int emac_set_phy_mode(emac_dev_t * _dev)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ u32 set_phy_mode;
+ u32 phy_mode;
+
+ LOGMSG(EMAC_DEBUG_BUSY_FUNCTION_ENTRY, "");
+
+ /* verify proper device state */
+ if (dev->drv_state != DRV_OPENED) {
+ LOGERR("Device NOT Open");
+ return (EMAC_ERR_DEV_NOT_OPEN);
+ }
+
+ set_phy_mode = dev->init_cfg.phy_mode;
+ phy_mode = 0;
+ if (set_phy_mode & SNWAY_AUTO)
+ phy_mode |= NWAY_AUTO;
+ if (set_phy_mode & SNWAY_FD10)
+ phy_mode |= NWAY_FD10;
+ if (set_phy_mode & SNWAY_FD100)
+ phy_mode |= NWAY_FD100;
+ if (set_phy_mode & SNWAY_HD10)
+ phy_mode |= NWAY_HD10;
+ if (set_phy_mode & SNWAY_HD100)
+ phy_mode |= NWAY_HD100;
+ if (set_phy_mode & SNWAY_LPBK)
+ phy_mode |= NWAY_LPBK;
+ if (set_phy_mode & SNWAY_AUTOMDIX)
+ phy_mode |= NWAY_AUTOMDIX;
+ /* check for EMAC bus frequency for correct speed operation */
+ if ((set_phy_mode & SNWAY_FD10) || (set_phy_mode & SNWAY_HD10)) {
+ if (dev->init_cfg.emac_bus_frequency <=
+ EMAC_MIN_FREQUENCY_FOR_10MBPS)
+ LOGERR("Bus speedemacSetPhyMode: CpmacFreq(%d) "
+ "is less than required %d freq for "
+ "10Mbps support. CANNOT SUPPORT 10Mbps",
+ dev->init_cfg.emac_bus_frequency,
+ EMAC_MIN_FREQUENCY_FOR_10MBPS);
+ }
+
+ else if ((set_phy_mode & SNWAY_FD100) || (set_phy_mode & SNWAY_HD100)) {
+ if (dev->init_cfg.emac_bus_frequency <=
+ EMAC_MIN_FREQUENCY_FOR_100MBPS)
+
+ LOGERR("freq(%d) is less than required %d freq for "
+ "100Mbps support. CANNOT SUPPORT 100Mbps",
+ dev->init_cfg.emac_bus_frequency,
+ EMAC_MIN_FREQUENCY_FOR_100MBPS);
+ }
+
+ /* TODO: check for gigabit mode when PHY mode defines for
+ * gigabit are available */
+ LOGMSG(EMAC_DEBUG_PORT_UPDATE,
+ "MdioPhyMode=%08X, PhyMode=%08d, Auto:%d, FD10:%d, "
+ "HD10:%d, FD100:%d, HD100:%d",
+ set_phy_mode, phy_mode,
+ (phy_mode & NWAY_AUTO), (phy_mode & NWAY_FD10),
+ (phy_mode & NWAY_HD10),
+ (phy_mode & NWAY_FD100), (phy_mode & NWAY_HD100));
+ emac_mdio_set_phy_mode(phy_mode);
+ emac_update_phy_status(_dev);
+ LOGMSG(EMAC_DEBUG_BUSY_FUNCTION_EXIT, "");
+
+ return (EMAC_SUCCESS);
+}
+
+/***************** MAC ADDRESSING MODE SUPPORT FUNCTIONS ********************/
+
+/* this function sets / clears the unicast flag in hardware */
+static void emac_rx_uni_cast(emac_dev_t * _dev, u32 channel, bool enable)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+
+ /* update local copy of register to save cycles in reading the
+ * register */
+ if (enable == TRUE) {
+ dev->rx_unicast_set |= (1 << channel);
+ dev->rx_unicast_clear &= ~(1 << channel);
+ } else {
+ /* disable unicast channel setting */
+ dev->rx_unicast_clear |= (1 << channel);
+ dev->rx_unicast_set &= ~(1 << channel);
+ }
+
+ /* write to hardware if device is open */
+ if (dev->drv_state == DRV_OPENED) {
+ dev->regs->rx_unicast_set = dev->rx_unicast_set;
+ dev->regs->rx_unicast_clear = dev->rx_unicast_clear;
+ }
+}
+
+/**
+ * EMAC Add Type 0 Address
+ * - set mac address for type 0 addressing (EMAC)
+ *
+ * This is an internal function of the DDC called from channel
+ * enable API which does channel number range checking and hence its
+ * not required. It is assumed that this function will get the
+ * correct channel number always
+ */
+static void emac_add_type0addr(emac_dev_t * _dev, u32 channel,
+ char *mac_address)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+
+ dev->regs->mac_src_addr_lo = (mac_address[0] << 8) | (mac_address[1]);
+ dev->regs->mac_src_addr_hi = (mac_address[2] << 24) |
+ (mac_address[3] << 16) | (mac_address[4] << 8) |
+ (mac_address[5]);
+
+ /* enable unicast */
+ emac_rx_uni_cast(_dev, channel, TRUE);
+}
+
+/**
+ * EMAC Add Type 1 Address
+ * - set mac address for type 1 addressing (EMAC)
+ *
+ * This is an internal function of the DDC called from channel enable
+ * API which does channel number range checking and hence its not required.
+ * It is assumed that this function will get the correct channel number always
+ */
+static void emac_add_type1addr(emac_dev_t * _dev, u32 channel,
+ char *mac_address)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+
+ /* set mac_index register with channel number */
+ dev->regs->mac_index = channel;
+
+ /* set mac_addr_hi register */
+ dev->regs->mac_addr_hi =
+ (mac_address[3] << 24) | (mac_address[2] << 16) |
+ (mac_address[1] << 8) | (mac_address[0]);
+
+ /* set mac_addr_lo register */
+ dev->regs->mac_addr_lo = ((mac_address[5] << 8) | mac_address[4]);
+
+ /* set mac hash */
+ dev->regs->mac_hash1 = 0;
+ dev->regs->mac_hash2 = 0;
+
+ /* As per discussion with hardware folks, it is mandatory to
+ set the source address of the mac, else correct behaviour
+ is not guaranteed */
+ emac_add_type0addr(_dev, channel, mac_address);
+
+ /* enable unicast */
+ emac_rx_uni_cast(_dev, channel, TRUE);
+}
+
+/* CPGMAC CFIG 2/3 type addressing - filtering */
+static void emac_add_type2addr(emac_dev_t * _dev, u32 channel,
+ char *mac_address,
+ int index, bool valid, int match)
+{
+ /* not supported in DaVinci */
+}
+
+/************************ HARDWARE CONFIGURATION SUPPORT FUNCTIONS ************************/
+
+/* set RX hardware configuration */
+void emac_set_rx_hw_cfg(emac_dev_t * _dev)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ emac_rx_config *rx_cfg;
+ u32 rx_mbp_enable;
+
+ if (dev->drv_state != DRV_OPENED) {
+ LOGERR("Function called when device is NOT in open state");
+ return;
+ }
+
+ rx_cfg = &dev->init_cfg.rx_cfg;
+
+ /* set RX MBP enable register */
+ rx_mbp_enable =
+ ((rx_cfg->pass_crc & 0x1) << EMAC_RXMBP_PASSCRC_SHIFT) |
+ ((rx_cfg->qos_enable & 0x1) << EMAC_RXMBP_QOSEN_SHIFT) |
+ ((rx_cfg->no_buffer_chaining & 0x1) << EMAC_RXMBP_NOCHAIN_SHIFT) |
+ ((rx_cfg->
+ copy_maccontrol_frames_enable & 0x1) << EMAC_RXMBP_CMFEN_SHIFT) |
+ ((rx_cfg->
+ copy_short_frames_enable & 0x1) << EMAC_RXMBP_CSFEN_SHIFT) |
+ ((rx_cfg->
+ copy_error_frames_enable & 0x1) << EMAC_RXMBP_CEFEN_SHIFT) |
+ ((rx_cfg->
+ promiscous_enable & 0x1) << EMAC_RXMBP_CAFEN_SHIFT) |
+ ((rx_cfg->promiscous_channel & EMAC_RXMBP_CHMASK)
+ << EMAC_RXMBP_PROMCH_SHIFT) |
+ ((rx_cfg->broadcast_enable & 0x1) << EMAC_RXMBP_BROADEN_SHIFT)|
+ ((rx_cfg->broadcast_channel & EMAC_RXMBP_CHMASK) <<
+ EMAC_RXMBP_BROADCH_SHIFT) |
+ ((rx_cfg->multicast_enable & 0x1) << EMAC_RXMBP_MULTIEN_SHIFT)|
+ ((rx_cfg-> multicast_channel & EMAC_RXMBP_CHMASK) <<
+ EMAC_RXMBP_MULTICH_SHIFT);
+
+ if (rx_cfg->promiscous_enable) {
+ /* disable mcast bcast and unicast: H/W limitation */
+ rx_mbp_enable &= ~(0x1 << EMAC_RXMBP_BROADEN_SHIFT);
+ rx_mbp_enable &= ~(0x1 << EMAC_RXMBP_MULTIEN_SHIFT);
+
+ /* disable unicast - warning!! assuming only one
+ * channel open */
+ emac_rx_uni_cast(_dev, (dev->rx_cppi[0])->ch_info.ch_num,
+ FALSE);
+ } else {
+ /* enable unicast - warning!! assuming only one
+ * channel open */
+ emac_rx_uni_cast(_dev, (dev->rx_cppi[0])->ch_info.ch_num, TRUE);
+ }
+
+ if (dev->rx_MBP_enable != rx_mbp_enable) {
+ dev->rx_MBP_enable = rx_mbp_enable;
+ dev->regs->rx_MBP_enable = rx_mbp_enable;
+ }
+
+ /* set max rx packet length */
+ dev->regs->rx_maxlen =
+ (rx_cfg->max_rx_pkt_length & EMAC_RX_MAX_LEN_MASK);
+
+ /* set rx buffer offset */
+ dev->regs->rx_buffer_offset =
+ (rx_cfg->buffer_offset & EMAC_RX_BUFFER_OFFSET_MASK);
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT,
+ "Rx_MBP_Enable = 0x%08x\n", rx_mbp_enable);
+}
+
+/* set MAC configuration - MACControl register */
+static void emac_set_mac_hw_cfg(emac_dev_t * _dev)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ emac_mac_config *mac_cfg;
+ u32 mac_control;
+
+ if (dev->drv_state != DRV_OPENED) {
+ LOGERR("Function called when device is NOT in open state");
+ return;
+ }
+
+ mac_cfg = &dev->init_cfg.mac_cfg;
+ mac_control =
+ ((mac_cfg->
+ tx_short_gap_enable & 0x1) << EMAC_MACCONTROL_TXSHORTGAPEN_SHIFT)
+ | (((mac_cfg->p_type == EMAC_TXPRIO_FIXED) ? 0x1 : 0) <<
+ EMAC_MACCONTROL_TXPTYPE_SHIFT)
+ | ((mac_cfg->giga_bit_enable & 0x1) <<
+ EMAC_MACCONTROL_GIGABITEN_SHIFT) | ((mac_cfg->
+ tx_pacing_enable & 0x1) <<
+ EMAC_MACCONTROL_TXPACEEN_SHIFT)
+ |
+ /* THIS LINE FOR REFERENCE ONLY ((mac_cfg->mii_enable & 0x1) << EMAC_MACCONTROL_MIIEN_SHIFT) | */
+ (dev->mac_control & EMAC_MACCONTROL_MIIEN_MASK) |
+ ((mac_cfg->
+ tx_flow_enable & 0x1) << EMAC_MACCONTROL_TXFLOWEN_SHIFT) |
+ ((mac_cfg->
+ rx_flow_enable & 0x1) << EMAC_MACCONTROL_RXFLOWEN_SHIFT) |
+ ((mac_cfg->
+ loopback_enable & 0x1) << EMAC_MACCONTROL_LOOPBKEN_SHIFT) |
+ (dev->mac_control & EMAC_MACCONTROL_FULLDUPLEXEN_MASK);
+
+ if (dev->mac_control != mac_control) {
+ dev->mac_control = mac_control;
+ dev->regs->mac_control = mac_control;
+ }
+}
+
+/**
+ * EMAC Init
+ * - validates max TX/RX channels and stores initial configuration
+ *
+ * Initial configuration passed by via the "init_cfg" parameter
+ */
+static int emac_init(emac_dev_t * _dev, emac_init_config * init_cfg)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "");
+
+ /* validate num_tx and num_rx channels */
+ if ((init_cfg->num_tx_channels > EMAC_MAX_TX_CHANNELS) ||
+ (init_cfg->num_rx_channels > EMAC_MAX_RX_CHANNELS)) {
+ LOGERR("Invalid number of TX/RX channels");
+ return (EMAC_INVALID_PARAM);
+ }
+
+ /* save config info for later use */
+ dev->init_cfg = *init_cfg; /* structure copy */
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "");
+ return (EMAC_SUCCESS);
+}
+
+/* EMAC DDC DeInit
+ * Stub function - no functionality required as per this implementation
+ */
+static int emac_de_init(emac_dev_t * _dev, void *param)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "");
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "");
+
+ return (EMAC_SUCCESS);
+}
+
+/**
+ * EMAC DDC Open
+ * - Brings module out of reset
+ * - Open's CSL, programs mandatory hardware init registers
+ * - Open's MII_MDIO module and enable poll timer via DDA
+ * - Enables earlier created TX/RX channels
+ * - Enables TX/RX operation in hardware
+ *
+ * "param" not used in this implementation
+ */
+static int emac_open(emac_dev_t * _dev, void *param)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ u32 channel;
+ u32 mii_mod_id, mii_rev_maj, mii_rev_min;
+ int ret_val;
+ emac_init_config *init_cfg;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "");
+
+ if (dev->drv_state == DRV_OPENED) {
+ LOGERR("Device already open");
+ return (EMAC_ERR_DEV_ALREADY_OPEN);
+ }
+
+ /* get init config info structure pointer for easy access */
+ init_cfg = &dev->init_cfg;
+ dev->regs = (emac_regs_ovly) init_cfg->base_address;
+ dev->e_wrap_regs = (ewrap_regs *) init_cfg->e_wrap_base_address;
+
+ /* set the BD memory pointer */
+ emac_wrapper_ptr = EMAC_WRAPPER_RAM_ADDR;
+
+ /* bring EMAC out of reset - for clean implementation, reset
+ * and then unreset the module */
+ /* for EMAC 2.6 and beyond, reset is internal to the module */
+ dev->regs->soft_reset = 1;
+
+ while (dev->regs->soft_reset) {
+ /* wait for reset to complete - do nothing */
+ }
+
+ /* program TX/RX HDP's to 0 */
+ for (channel = 0; channel < EMAC_MAX_TX_CHANNELS; channel++) {
+ dev->regs->tx_HDP[channel] = 0;
+
+ /* initialize the completion pointers to 0 */
+ dev->regs->tx_CP[channel] = 0;
+ }
+
+ for (channel = 0; channel < EMAC_MAX_RX_CHANNELS; channel++) {
+ dev->regs->rx_HDP[channel] = 0;
+
+ /* initialize the completion pointers to 0 */
+ dev->regs->rx_CP[channel] = 0;
+ }
+
+ /* enable TX/RX DMA */
+ dev->regs->tx_control |= EMAC_TX_CONTROL_TX_ENABLE_VAL;
+ dev->regs->rx_control |= EMAC_RX_CONTROL_RX_ENABLE_VAL;
+
+ /* enable adapter check interrupts - disable stats interupt */
+ dev->regs->mac_int_mask_set = EMAC_MAC_HOST_ERR_INTMASK_VAL;
+
+ /* set device state - opened - useful when opening channels */
+ dev->drv_state = DRV_OPENED;
+
+ /* set the mac_control register */
+ emac_set_mac_hw_cfg(_dev);
+
+ /* start MDIO autonegotiation and set phy mode */
+ emac_mdio_get_ver(init_cfg->mdio_base_address,
+ &mii_mod_id, &mii_rev_maj, &mii_rev_min);
+
+ LOGMSG(EMAC_DEBUG_PORT_UPDATE,
+ "MII Module Id=%d, MII Base Address=%08X, Major Rev=%d, "
+ "Minor Rev=%d",
+ mii_mod_id, init_cfg->mdio_base_address,
+ mii_rev_maj, mii_rev_min);
+
+ /* no failure code returned from this function */
+ emac_mdio_init(init_cfg->mdio_base_address,
+ dev->init_cfg.inst_id,
+ init_cfg->phy_mask,
+ init_cfg->MLink_mask,
+ init_cfg->mdio_bus_frequency,
+ init_cfg->mdio_clock_frequency,
+ (emac_debug & EMAC_DEBUG_MII)
+ );
+
+ /* set the PHY to a given mode - as per config parameters and
+ * update DDA layer */
+ emac_set_phy_mode(_dev);
+
+ emac_control_cb(dev,
+ EMAC_IOCTL_STATUS_UPDATE, (void *)&dev->status, NULL);
+
+ /* start the tick timer via DDA */
+ emac_control_cb(dev,
+ EMAC_IOCTL_TIMER_START,
+ (void *)init_cfg->mdio_tick_msec, NULL);
+
+ /* enable opened TX channels */
+ for (channel = 0; channel < EMAC_MAX_TX_CHANNELS; channel++) {
+ if (dev->tx_cppi[channel] != NULL) {
+ ret_val =
+ emac_enable_channel(_dev, channel, NET_CH_DIR_TX);
+ if (ret_val != EMAC_SUCCESS) {
+ LOGERR("Error enabling TX channel %d", channel);
+
+ /* TODECIDE: should we return from
+ * here or continue enabling other
+ * channels */
+ return (ret_val);
+ }
+ }
+ }
+
+ /* set filter low threshold - not supported, hence set to 0 */
+ dev->regs->rx_filter_low_thresh = 0;
+
+ /* disable unicast on all channels first - enabled if channel
+ * is configured & enabled below */
+ dev->regs->rx_unicast_clear = EMAC_RX_UNICAST_CLEAR_ALL;
+
+ /* set MAC hash register */
+ dev->regs->mac_hash1 = dev->mac_hash1;
+ dev->regs->mac_hash2 = dev->mac_hash2;
+
+ /* RX MBP, RX pkt length and RX buffer offset registers taken
+ * care by this function */
+ emac_set_rx_hw_cfg(_dev);
+
+ /* read RX address matching/filtering type (0/1/2) */
+ dev->rx_addr_type = (dev->regs->mac_cfig >> 8) & 0xFF;
+
+ /* enable opened RX channels */
+ for (channel = 0; channel < EMAC_MAX_RX_CHANNELS; channel++) {
+ if (dev->rx_cppi[channel] != NULL) {
+ ret_val =
+ emac_enable_channel(_dev, channel, NET_CH_DIR_RX);
+ if (ret_val != EMAC_SUCCESS) {
+ LOGERR("Error enabling RX channel %d", channel);
+
+ /* TODECIDE: should we return from
+ * here or continue enabling other
+ * channels */
+ return (ret_val);
+ }
+ }
+
+ /* since flow threshold and free buffer feature is not
+ * supported, set it to 0 */
+ dev->regs->rx_flow_thresh[channel] = 0;
+ dev->regs->rx_free_buffer[channel] = 0;
+ }
+
+ /* finally set MAC control register, enable MII */
+ dev->mac_control |= (1 << EMAC_MACCONTROL_MIIEN_SHIFT);
+ dev->regs->mac_control = dev->mac_control;
+
+ /* start the MIB cnt tick timer via DDA */
+ emac_control_cb(dev,
+ EMAC_IOCTL_MIB64_CNT_TIMER_START,
+ (void *)init_cfg->mib64cnt_msec, NULL);
+
+ /* enable interrupts via module control (wrapper) */
+ ((volatile ewrap_regs *)dev->e_wrap_regs)->EWCTL = 0x1;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "");
+
+ return (EMAC_SUCCESS);
+
+}
+
+/**
+ * EMAC DDC Close
+ * - Disables poll timer via DDA
+ * - Disable and Close all open TX/RX channels
+ * - Closes CSL
+ * - Puts module in reset
+ *
+ * "param" not used in this implementation
+ */
+static int emac_close(emac_dev_t * _dev, void *param)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ int ret_val;
+ int err_val = EMAC_SUCCESS;
+ u32 channel;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "");
+
+ if (dev->drv_state == DRV_CLOSED) {
+ LOGERR("Device already closed");
+ return (EMAC_ERR_DEV_ALREADY_CLOSED);
+ }
+
+ /* stop the tick timer via DDA */
+ emac_control_cb(dev, EMAC_IOCTL_TIMER_STOP, NULL, NULL);
+
+ /* stop the mib timer via DDA */
+ emac_control_cb(dev, EMAC_IOCTL_MIB64_CNT_TIMER_STOP, NULL, NULL);
+ /* close TX channels */
+ for (channel = 0; channel < EMAC_MAX_TX_CHANNELS; channel++) {
+ if (dev->tx_cppi[channel] != NULL) {
+ ret_val =
+ emac_ch_close(_dev, channel, NET_CH_DIR_TX, NULL);
+ if (ret_val != EMAC_SUCCESS) {
+ LOGERR("Error closing TX channel %d", channel);
+
+ /* instead of returning immediatley on
+ * error, we close all possible
+ * channels */
+ err_val = ret_val;
+ }
+ }
+ }
+
+ /* close RX channels */
+ for (channel = 0; channel < EMAC_MAX_RX_CHANNELS; channel++) {
+ if (dev->rx_cppi[channel] != NULL) {
+ ret_val =
+ emac_ch_close(_dev, channel, NET_CH_DIR_RX, NULL);
+
+ if (ret_val != EMAC_SUCCESS) {
+ LOGERR("Error closing RX channel %d", channel);
+
+ /* instead of returning immediatley on
+ * error, we close all possible
+ * channels */
+ err_val = ret_val; /* return (ret_val); */
+ }
+ }
+ }
+
+ /* disable interrupts via module control (wrapper) */
+ ((volatile ewrap_regs *)dev->e_wrap_regs)->EWCTL = 0x0;
+
+ /* put EMAC in reset */
+ dev->regs->soft_reset = 1;
+
+ /* put MDIO in reset - not required for davinci */
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "");
+
+ if (err_val == EMAC_SUCCESS) { /* closed all channels successfully. mark the DDC as closed */
+ dev->drv_state = DRV_CLOSED;
+ }
+
+ return (err_val);
+}
+
+/**
+ * EMAC DDC Ioctl
+ * - Get Software (DDC) and Hardware Versions
+ * - Set/Modify RX and MAC configuration
+ * - Get DDC/module status
+ * - Read/Write MII registers (via PHY)
+ * - Get/Clr Statistics (hardware counters)
+ * - Add/Del/ Multicast operations AllMulti Set/Clear operations
+ * - Type2/3 Filtering operation
+ *
+ * "param" not used in this implementation
+ */
+static int emac_control(emac_dev_t * _dev, int cmd, void *cmd_arg, void *param)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+
+ /* sanity check */
+ if (dev->drv_state != DRV_OPENED) {
+ LOGERR("ioctl called when device is NOT open");
+ return (EMAC_ERR_DEV_NOT_OPEN);
+ }
+
+ switch (cmd) {
+ case EMAC_IOCTL_GET_HWVER:
+ /* read hardware versions only if device is in open
+ * state */
+ /* cmd is a ptr to an integer that will contain Tx Id
+ ver and param is a pointer to an integer that will
+ contain rx id ver after this call */
+ if (dev->drv_state == DRV_OPENED) {
+ *((u32 *) cmd_arg) = dev->regs->tx_id_ver;
+ *((u32 *) param) = dev->regs->rx_id_ver;
+ } else {
+ return (EMAC_ERR_DEV_NOT_OPEN);
+ }
+ break;
+
+ case EMAC_IOCTL_SET_RXCFG:
+ /* rx configuration structure passed in structure
+ * pointed by cmd_arg, params not used */
+ if (cmd_arg != NULL) {
+ dev->init_cfg.rx_cfg = *((emac_rx_config *) cmd_arg);
+ emac_set_rx_hw_cfg(_dev);
+ } else {
+ return (EMAC_INVALID_PARAM);
+ }
+ break;
+
+ case EMAC_IOCTL_SET_MACCFG:
+ /* mac configuration structure passed in a structure
+ * pointed by cmd_arg, params not used */
+ if (cmd_arg != NULL) {
+ dev->init_cfg.mac_cfg = *((emac_mac_config *) cmd_arg);
+ emac_set_mac_hw_cfg(_dev);
+ } else {
+ return (EMAC_INVALID_PARAM);
+ }
+ break;
+
+ case EMAC_IOCTL_GET_STATUS:
+ /* returns emac_status structure back in cmd_arg
+ * pointer pointed structure */
+ {
+ emac_status *status = (emac_status *) cmd_arg;
+ *status = dev->status; /* structure copy */
+ }
+ break;
+
+ case EMAC_IOCTL_READ_PHY_REG:
+ /* cmd = pointer to CpmacPhyParams struct. data read
+ * back into "data" parameter in the structure */
+ {
+ /* \warning: Read to the phy registers - Note
+ that this code loops on a completion bit in
+ the phy so there are chances of hanging" */
+ emac_phy_params *phy_params =
+ (emac_phy_params *) cmd_arg;
+
+ phy_params->data = emac_mdio_read(phy_params->phy_num,
+ phy_params->reg_addr);
+ }
+ break;
+
+ case EMAC_IOCTL_WRITE_PHY_REG:
+ /* cmd = pointer to CpmacPhyParams struct. data to be
+ * written is in "data" parameter in the structure */
+ {
+ emac_phy_params *phy_params =
+ (emac_phy_params *) cmd_arg;
+
+ /* \warning: Write to the phy registers - Note
+ that this code loops on a completion bit in
+ the phy so there are chances of hanging" */
+ emac_mdio_write(phy_params->reg_addr,
+ phy_params->phy_num, phy_params->data);
+ }
+ break;
+
+ case EMAC_IOCTL_GET_STATISTICS:
+ /* cmd_arg points to the user provided structure for
+ * statistics which match with hardware 36 regs, param
+ * is not used */
+ {
+ u32 cnt;
+ u32 *user_stats = (u32 *) cmd_arg;
+ volatile u32 *addr =
+ (u32 *) & dev->regs->rx_good_frames;
+
+ for (cnt = 0; cnt < EMAC_NUM_STAT_REGS;
+ cnt++, user_stats++, addr++) {
+ *user_stats = *addr;
+ }
+ }
+
+ break;
+
+ case EMAC_IOCTL_CLR_STATISTICS:
+ /* cmd_arg or param is not used */
+ {
+ u32 cnt;
+ volatile u32 *addr =
+ (u32 *) & dev->regs->rx_good_frames;
+
+ for (cnt = 0; cnt < EMAC_NUM_STAT_REGS; cnt++, addr++) {
+ *addr = EMAC_STAT_CLEAR; /* 0xFFFFFFFF value */
+ }
+ emac_ddcifcnt_clear(_dev);
+ }
+ break;
+
+ case EMAC_IOCTL_MULTICAST_ADDR:
+ /* cmd_arg= emac_multicast_oper enum, param = pointer
+ * to multicast address - u8 */
+ {
+ u8 *addr = (u8 *) param;
+ emac_single_multi(_dev,
+ (emac_single_multi_oper) cmd_arg,
+ addr);
+ }
+ break;
+
+ case EMAC_IOCTL_ALL_MULTI:
+ /* cmd_arg= emac_all_multi_oper enum, param=not used */
+ emac_all_multi(_dev, (emac_all_multi_oper) cmd_arg);
+ break;
+
+ case EMAC_IOCTL_TYPE2_3_FILTERING:
+ {
+ /* cmd_arg = pointer to
+ * emac_type2_3_addr_filter_params structure,
+ * param=not used */
+ emac_type2_3_addr_filter_params *addr_params;
+
+ addr_params =
+ (emac_type2_3_addr_filter_params *) cmd_arg;
+ emac_add_type2addr(_dev, addr_params->channel,
+ addr_params->mac_address,
+ addr_params->index,
+ addr_params->valid,
+ addr_params->match);
+ }
+ break;
+
+ case EMAC_IOCTL_SET_MAC_ADDRESS:
+ {
+ /* cmd_arg = pointer to
+ * emac_type2_3_addr_filter_params structure,
+ * param=not used */
+ emac_address_params *addr_params;
+ emac_rx_cppi_ch *rx_cppi;
+ int cnt;
+
+ if (dev->drv_state != DRV_OPENED) {
+ LOGERR
+ ("EMAC_IOCTL_TYPE2_3_FILTERING Ioctl called when device is NOT in open state");
+ return (EMAC_ERR_DEV_NOT_OPEN);
+ }
+
+ addr_params = (emac_address_params *) cmd_arg;
+ rx_cppi = dev->rx_cppi[addr_params->channel];
+ if (rx_cppi == NULL) {
+ LOGERR
+ ("Invalid Channel %d. RX CPPI structure NULL",
+ addr_params->channel);
+ return (EMAC_ERR_RX_CH_INVALID);
+ }
+
+ for (cnt = 0; cnt < 6; cnt++)
+ rx_cppi->mac_addr[cnt] =
+ addr_params->mac_address[cnt];
+
+ /* set interface MAC address */
+ emac_set_mac_address(_dev, addr_params->channel,
+ addr_params->mac_address);
+ }
+ break;
+
+ case EMAC_IOCTL_IF_COUNTERS:
+ emac_ddcifcnt_updt(_dev);
+
+ memcpy(cmd_arg, &dev->mib2if_hccounter.mib2if_counter,
+ sizeof(struct mib2_if_counters));
+ break;
+
+ case EMAC_IOCTL_ETHER_COUNTERS:
+ emac_ddcphycnt(_dev, cmd_arg);
+ break;
+
+ case EMAC_IOCTL_IF_PARAMS_UPDT:
+ emac_ddcifcnt_updt(_dev);
+ break;
+
+ default:
+ LOGERR("Unhandled ioctl code %d", cmd);
+ break;
+ }
+
+ return (EMAC_SUCCESS);
+}
+
+/**
+ * EMAC DDC Channel Open
+ * - Verify channel info (range checking etc)
+ * - Allocate memory for the channel
+ * - Book-keep operations for the channel - ready to be enabled in hardware
+ *
+ * 1. If DDC instance is in "Opened" state, the channel is enabled in hardware
+ * 2. "chOpenArgs" is used only for opening RX channel
+ */
+static int emac_ch_open(emac_dev_t * _dev, emac_ch_info * ch_info,
+ void *ch_open_args)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ int ret_val;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY,
+ "ChannelNo=%d, Dir=%s",
+ ch_info->ch_num,
+ ((ch_info->ch_dir == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+ /* if the channel state is not NET_CH_UNINITIALIZED, return error */
+ if (ch_info->ch_state != NET_CH_UNINITIALIZED) {
+ LOGERR
+ ("%s channel %d should be in NET_CH_UNINITIALIZED state",
+ ((ch_info->ch_dir == NET_CH_DIR_TX) ? "TX" : "RX"),
+ ch_info->ch_num);
+ return (EMAC_INVALID_PARAM);
+ }
+
+ /* init channel */
+ if (ch_info->ch_dir == NET_CH_DIR_TX) {
+ if (ch_info->ch_num >= dev->init_cfg.num_tx_channels) {
+ LOGERR
+ ("Invalid TX Channel=%d specified",
+ ch_info->ch_num);
+ return (EMAC_ERR_TX_CH_INVALID);
+ }
+
+ if (dev->tx_is_created[ch_info->ch_num] == TRUE) {
+ LOGERR("TX Channel %d already open", ch_info->ch_num);
+ return (EMAC_ERR_TX_CH_ALREADY_INIT);
+ }
+
+ /* allocate channel memory and perform other book-keep
+ * functions for the channel */
+ ret_val = emac_init_tx_channel(_dev, ch_info, ch_open_args);
+ if (ret_val != EMAC_SUCCESS) {
+ LOGERR
+ ("Error in initializing TX channel %d",
+ ch_info->ch_num);
+ return (ret_val);
+ }
+ } else if (ch_info->ch_dir == NET_CH_DIR_RX) {
+ if (ch_info->ch_num >= dev->init_cfg.num_rx_channels) {
+ LOGERR
+ ("Invalid RX Channel=%d specified",
+ ch_info->ch_num);
+ return (EMAC_ERR_RX_CH_INVALID);
+ }
+
+ if (dev->rx_is_created[ch_info->ch_num] == TRUE) {
+ LOGERR("RX Channel %d already open", ch_info->ch_num);
+ return (EMAC_ERR_RX_CH_ALREADY_INIT);
+ }
+
+ /* allocate channel memory and perform other book-keep
+ * functions for the channel */
+ ret_val = emac_init_rx_channel(_dev, ch_info, ch_open_args);
+
+ if (ret_val != EMAC_SUCCESS) {
+ LOGERR
+ ("Error in initializing RX channel %d",
+ ch_info->ch_num);
+ return (ret_val);
+ }
+ }
+
+ /* if device is opened already, enable this channel for use */
+ if (dev->drv_state == DRV_OPENED) {
+ ret_val =
+ emac_enable_channel(_dev, ch_info->ch_num, ch_info->ch_dir);
+ if (ret_val != EMAC_SUCCESS) {
+ LOGERR
+ ("Error enabling channel %d in %d direction",
+ ch_info->ch_num, ch_info->ch_dir);
+ return (ret_val);
+ }
+ }
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT,
+ "ChannelNo=%d, Dir=%s",
+ ch_info->ch_num,
+ ((ch_info->ch_dir == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+ return (EMAC_SUCCESS);
+}
+
+/**
+ * EMAC DDC Channel Close
+ * - If DDC instance is in "Opened" state, disable the channel in hardware
+ * - Un-initialize the channel (free memory previously allocated)
+ */
+static int emac_ch_close(emac_dev_t * _dev, int channel,
+ int direction, void *ch_close_args)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ int ret_val;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY,
+ "ChannelNo=%d, Dir=%s",
+ channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+ /* disable this channel */
+ if (dev->drv_state == DRV_OPENED) {
+ ret_val = emac_disable_channel(_dev, channel, direction);
+ if (ret_val != EMAC_SUCCESS) {
+ LOGERR
+ ("Error disabling channel %d in %s direction",
+ channel,
+ ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+ return (ret_val);
+ }
+ }
+
+ /* un_init channel */
+ if (direction == NET_CH_DIR_TX) {
+ ret_val = emac_un_init_tx_channel(_dev, channel, ch_close_args);
+ if (ret_val != EMAC_SUCCESS) {
+ LOGERR("Error in UnInit of TX channel %d", channel);
+ return (ret_val);
+ }
+ }
+
+ else if (direction == NET_CH_DIR_RX) {
+ ret_val = emac_un_init_rx_channel(_dev, channel, ch_close_args);
+ if (ret_val != EMAC_SUCCESS) {
+ LOGERR("Error in UnInit of TX channel %d", channel);
+ return (ret_val);
+ }
+ }
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT,
+ "ChannelNo=%d, Dir=%s",
+ channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+ return (EMAC_SUCCESS);
+}
+
+/**
+ * Init Tx Channel
+ * - Allocates memory for TX Ch Control structure, Buffer descriptors
+ * - Initialize the above data structures as per channel configuration
+ * - Chain the TX BD list ready to be given to hardware
+ *
+ * 1. "chOpenArgs" not used in this implementation
+ *
+ * 2. This function assumes that the channel number passed is valid
+ * and the hDDC->txCppi[channel] pointer is NULL. This function will
+ * not do any error check on these parameters to avoid duplicate error
+ * checks (done in caller function).
+ */
+static int emac_init_tx_channel(emac_dev_t * _dev,
+ emac_ch_info * ch_info, void *ch_open_args)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ u32 cnt, bd_size;
+ char *alloc_mem;
+ emac_tx_bd *curr_bd;
+ emac_tx_cppi_ch *tx_cppi = NULL;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "ChannelNo=%d", ch_info->ch_num);
+
+ /* allocate memory for TX CPPI channel and set to 0 */
+ emac_malloc(sizeof(emac_tx_cppi_ch), (void **)&tx_cppi);
+
+ /* update the channel control structure in DDC */
+ dev->tx_cppi[ch_info->ch_num] = tx_cppi;
+
+ /* populate channel info */
+ tx_cppi->ch_info = *ch_info; /* structure copy */
+ tx_cppi->ch_info.ch_state = NET_CH_INITIALIZED;
+ tx_cppi->active_queue_head = 0;
+ tx_cppi->active_queue_tail = 0;
+ tx_cppi->queue_active = FALSE;
+ dev->tx_teardown_pending[ch_info->ch_num] = FALSE;
+
+#ifdef EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+ /* allocate memory for TX CPPI channel on a 4 byte boundry */
+ emac_malloc((ch_info->service_max * sizeof(u32)),
+ (void **)&tx_cppi->tx_complete);
+#endif
+
+ /* allocate buffer descriptor pool align every BD on four word
+ * boundry for future requirements */
+ bd_size = (sizeof(emac_tx_bd) + 0xF) & ~0xF;
+ tx_cppi->alloc_size = (((bd_size * ch_info->num_bd) + 0xF) & ~0xF);
+
+ /* alloc TX BD memory */
+ tx_cppi->bd_mem = (char *)EMAC_TX_BD_MEM;
+ memzero(tx_cppi->bd_mem, tx_cppi->alloc_size);
+
+ /* initialize the BD linked list */
+ alloc_mem = (char *)(((u32) tx_cppi->bd_mem + 0xF) & ~0xF);
+
+ tx_cppi->bd_pool_head = 0;
+ for (cnt = 0; cnt < ch_info->num_bd; cnt++) {
+ curr_bd = (emac_tx_bd *) (alloc_mem + (cnt * bd_size));
+ curr_bd->next = tx_cppi->bd_pool_head;
+ tx_cppi->bd_pool_head = curr_bd;
+ }
+
+ /* reset statistics counters */
+ tx_cppi->out_of_tx_bd = 0;
+ tx_cppi->no_active_pkts = 0;
+ tx_cppi->active_queue_count = 0;
+ dev->tx_is_created[ch_info->ch_num] = TRUE;
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "ChannelNo=%d", ch_info->ch_num);
+
+ return (EMAC_SUCCESS);
+}
+
+/**
+ * Un-Init Tx Channel
+ *
+ * - Frees memory previously allocated for Ch Control structure,
+ * Buffer descriptors
+ *
+ * 1. "chCloseArgs" not used in this implementation
+ * 2. This function assumes that the channel number passed is valid
+ * and this function will not do any error check to avoid duplicate
+ * error checks (done in caller function).
+ */
+static int emac_un_init_tx_channel(emac_dev_t * _dev, u32 channel,
+ void *ch_close_args)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ emac_tx_cppi_ch *tx_cppi;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "ChannelNo=%d", channel);
+
+ /* check if channel structure is already de-allocated */
+ if (dev->tx_is_created[channel] == FALSE) {
+ LOGERR("TX CPPI Channel %d structure already freed", channel);
+ return (EMAC_ERR_TX_CH_ALREADY_CLOSED);
+ }
+
+ tx_cppi = dev->tx_cppi[channel];
+
+ /* free the buffer descriptors memory */
+ if (tx_cppi->bd_mem != NULL) {
+ tx_cppi->bd_mem = NULL;
+ }
+#ifdef EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+ /* free the TX complete queue */
+ emac_free(tx_cppi->tx_complete);
+#endif
+
+ /* free the TX channel structure */
+ emac_free(tx_cppi);
+ dev->tx_cppi[channel] = NULL;
+ dev->tx_is_created[channel] = FALSE;
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "ChannelNo=%d", channel);
+
+ return (EMAC_SUCCESS);
+}
+
+/**
+ * Init Rx Channel
+ * - Allocates memory for RX Ch Control structure, Buffer descriptors
+ * - Initialize the above data structures as per channel configuration
+ * - Allocate receive buffers from DDA and chain the RX BD list ready
+ * to be given to hardware
+ *
+ * 1. "chOpenArgs" Points to MAC address for this channel
+ * 2. This function assumes that the channel number passed is valid
+ * and the hDDC->rxCppi[channel] pointer is NULL. This function will
+ * not do any error check on these parameters to avoid duplicate error
+ * checks (done in caller function).
+ */
+static int emac_init_rx_channel(emac_dev_t * _dev,
+ emac_ch_info * ch_info, void *ch_open_args)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ u32 cnt, bd_size;
+ char *alloc_mem;
+ emac_rx_bd *curr_bd;
+ emac_rx_cppi_ch *rx_cppi = NULL;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "ChannelNo=%d", ch_info->ch_num);
+
+ /* allocate memory for RX CPPI channel */
+ emac_malloc(sizeof(emac_rx_cppi_ch), (void **)&rx_cppi);
+ /* update the channel control structure in DDC */
+ dev->rx_cppi[ch_info->ch_num] = rx_cppi;
+
+ rx_cppi->ch_info = *ch_info; /* structure copy */
+ rx_cppi->ch_info.ch_state = NET_CH_INITIALIZED;
+ dev->rx_teardown_pending[ch_info->ch_num] = FALSE;
+
+ /* save mac address */
+ alloc_mem = (char *)ch_open_args;
+ for (cnt = 0; cnt < 6; cnt++)
+ rx_cppi->mac_addr[cnt] = alloc_mem[cnt];
+
+ /* allocate buffer descriptor pool align every BD on four word
+ * boundry for future requirements */
+ bd_size = (sizeof(emac_rx_bd) + 0xF) & ~0xF;
+ rx_cppi->alloc_size = (((bd_size * ch_info->num_bd) + 0xF) & ~0xF);
+
+ /* alloc RX BD memory */
+ rx_cppi->bd_mem = (char *)EMAC_RX_BD_MEM;
+ memzero(rx_cppi->bd_mem, rx_cppi->alloc_size);
+
+ rx_cppi->pkt_queue.buf_list = &rx_cppi->buf_queue[0];
+
+ /* allocate RX buffer and initialize the BD linked list */
+ alloc_mem = (char *)(((u32) rx_cppi->bd_mem + 0xF) & ~0xF);
+ rx_cppi->active_queue_head = 0;
+ rx_cppi->active_queue_tail = (emac_rx_bd *) alloc_mem;
+ for (cnt = 0; cnt < ch_info->num_bd; cnt++) {
+ curr_bd = (emac_rx_bd *) (alloc_mem + (cnt * bd_size));
+
+ /* for potential future use the last parameter
+ * contains the BD ptr */
+ curr_bd->data_ptr =
+ (void *)(emac_net_alloc_rx_buf(dev,
+ ch_info->buf_size,
+ (emac_net_data_token *) &
+ curr_bd->buf_token, 0,
+ (void *)curr_bd));
+ if (curr_bd->data_ptr == NULL) {
+ LOGERR
+ ("Error in RX Buffer allocation for channel %d",
+ ch_info->ch_num);
+ return (EMAC_ERR_RX_BUFFER_ALLOC_FAIL);
+ }
+
+ /* populate the hardware descriptor */
+ curr_bd->h_next = EMAC_VIRT_TO_PHYS(rx_cppi->active_queue_head);
+ curr_bd->buff_ptr = EMAC_VIRT_TO_PHYS(curr_bd->data_ptr);
+ curr_bd->off_b_len = ch_info->buf_size;
+ curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT;
+
+ /* write back to hardware memory */
+ BD_CACHE_WRITEBACK_INVALIDATE((u32) curr_bd,
+ EMAC_BD_LENGTH_FOR_CACHE);
+ curr_bd->next = (void *)rx_cppi->active_queue_head;
+ rx_cppi->active_queue_head = curr_bd;
+ }
+
+ /* At this point rxCppi->activeQueueHead points to the first
+ RX BD ready to be given to RX HDP and
+ rx_cppi->active_queue_tail points to the last RX BD */
+ dev->rx_is_created[ch_info->ch_num] = TRUE;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "ChannelNo=%d", ch_info->ch_num);
+
+ return (EMAC_SUCCESS);
+}
+
+/**
+ * Un-Init Rx Channel
+ * - Frees memory previously allocated for Ch Control structure,
+ * Buffer descriptors
+ * - Returns (Frees) back receive buffers to DDA layer
+ *
+ * 1. "chCloseArgs" not used in this implementation
+ * 2. This function assumes that the channel number passed is valid
+ * and this function will not do any error check to avoid duplicate
+ * error checks (done in caller function).
+ */
+static int emac_un_init_rx_channel(emac_dev_t * _dev, u32 channel,
+ void *ch_close_args)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ emac_rx_cppi_ch *rx_cppi;
+ emac_rx_bd *curr_bd;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY, "ChannelNo=%d", channel);
+
+ /* check if channel structure is already de-allocated */
+ if (dev->rx_is_created[channel] == FALSE) {
+ LOGERR("RX CPPI Channel %d structure already freed", channel);
+ return (EMAC_ERR_RX_CH_ALREADY_CLOSED);
+ }
+
+ rx_cppi = dev->rx_cppi[channel];
+
+ /* free the receive buffers previously allocated */
+ curr_bd = rx_cppi->active_queue_head;
+ while (curr_bd) {
+ if (emac_net_free_rx_buf(dev,
+ curr_bd->data_ptr,
+ (emac_net_data_token) curr_bd->
+ buf_token, 0, NULL) != EMAC_SUCCESS) {
+ LOGERR("Failed to free RX buffer Ch %d", channel);
+ }
+ curr_bd = curr_bd->next;
+ }
+
+ /* free the buffer descriptors memory */
+ if (rx_cppi->bd_mem != NULL) {
+ rx_cppi->bd_mem = NULL;
+ }
+
+ /* free the RX channel structure */
+ emac_free(rx_cppi);
+ dev->rx_cppi[channel] = NULL;
+ dev->rx_is_created[channel] = FALSE;
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT, "ChannelNo=%d", channel);
+
+ return (EMAC_SUCCESS);
+}
+
+/**
+ * Set EMAC Mac address
+ * Functionality provided:
+ * - EMAC address is set in the hardware based on the address type
+ *
+ * 1. It is assumed that the channel is already "initialized"
+ */
+static void emac_set_mac_address(emac_dev_t * _dev, u32 channel, char *mac_addr)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+
+ /* enable unicast on this channel */
+ dev->regs->rx_unicast_set = (1 << channel);
+
+ /* program MAC address for the channel depending upon emac/cpgmac */
+ if (dev->rx_addr_type == RX_ADDR_TYPE0)
+ emac_add_type0addr(_dev, channel, mac_addr);
+ else if (dev->rx_addr_type == RX_ADDR_TYPE1)
+ emac_add_type1addr(_dev, channel, mac_addr);
+ else if (dev->rx_addr_type == RX_ADDR_TYPE2)
+ emac_add_type2addr(_dev, channel, mac_addr, 0, 1, 1);
+ else
+ LOGERR
+ ("Wrong Rx Addressing Type - (Type2) detected in hardware");
+}
+
+/**
+ * Enable TX/RX Channel
+ * Functionality provided:
+ * - Channel is enabled in hardware. Data transfer can occur on this
+ * channel after this.
+ *
+ * 1. It is assumed that the channel is already "initialized"
+ * 2. To enable a channel after its disabled, it needs to be initialized again
+ */
+static int emac_enable_channel(emac_dev_t * _dev, u32 channel, u32 direction)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY,
+ "ChannelNo=%d, Direction=%s",
+ channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+ if (direction == NET_CH_DIR_TX) {
+ emac_tx_cppi_ch *tx_cppi;
+
+ tx_cppi = dev->tx_cppi[channel];
+ if (tx_cppi == NULL) {
+ LOGERR
+ ("Invalid Channel %d. TX CPPI structure NULL",
+ channel);
+
+ return (EMAC_ERR_TX_CH_INVALID);
+ }
+
+ /* init head descriptor pointer */
+ dev->regs->tx_HDP[channel] = 0;
+ {
+ emac_mac_config *mac_cfg;
+
+ mac_cfg = &dev->init_cfg.mac_cfg;
+ if (mac_cfg->tx_interrupt_disable == TRUE) {
+ /* disable channel interrupt */
+ dev->regs->tx_int_mask_clear = (1 << channel);
+ dev->tx_interrupt_disable = TRUE;
+ dev->tx_int_threshold[channel] =
+ dev->tx_cppi[channel]->ch_info.service_max;
+ } else {
+ /* enable channel interrupt */
+ dev->regs->tx_int_mask_set = (1 << channel);
+ dev->tx_interrupt_disable = FALSE;
+ }
+ }
+
+ /* mark channel open */
+ dev->tx_is_open[channel] = TRUE;
+ tx_cppi->ch_info.ch_state = NET_CH_OPENED;
+ }
+
+ else if (direction == NET_CH_DIR_RX) {
+ emac_rx_cppi_ch *rx_cppi;
+
+ rx_cppi = dev->rx_cppi[channel];
+ if (rx_cppi == NULL) {
+ LOGERR
+ ("Invalid Channel %d. RX CPPI structure NULL",
+ channel);
+
+ return (EMAC_ERR_RX_CH_INVALID);
+ }
+
+ /* set interface MAC address */
+ emac_set_mac_address(_dev, channel, rx_cppi->mac_addr);
+
+ /* enable channel interrupt */
+ dev->regs->rx_int_mask_set = (1 << channel);
+
+ /* mark queue active */
+ rx_cppi->queue_active = TRUE;
+
+ /* enable DMA */
+ dev->regs->rx_HDP[channel] =
+ EMAC_VIRT_TO_PHYS(rx_cppi->active_queue_head);
+
+ /* mark channel open */
+ dev->rx_is_open[channel] = TRUE;
+
+ rx_cppi->ch_info.ch_state = NET_CH_OPENED;
+
+ }
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT,
+ "ChannelNo=%d, Direction=%s",
+ channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+ return (EMAC_SUCCESS);
+
+}
+
+/**
+ * Disable TX/RX Channel
+ * Functionality provided:
+ * - Channel is disabled in hardware. No data transfer can occur on
+ * this channel after this.
+ *
+ * 1. It is assumed that the channel number passed is valid
+ * 2. Resources for the channel will be released only when its closed
+ */
+static int emac_disable_channel(emac_dev_t * _dev, u32 channel,
+ net_ch_dir direction)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY,
+ "ChannelNo=%d, Direction=%s",
+ channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+ if (direction == NET_CH_DIR_TX) {
+
+ dev->tx_teardown_pending[channel] = TRUE; /* set the TX teardown pending flag */
+
+ /* initiate teardown of TX channel */
+ dev->regs->tx_teardown = channel;
+
+ /* wait for teardown complete */
+ if (emac_wait_for_teardown_complete
+ (_dev, channel, direction, TRUE) != EMAC_SUCCESS) {
+
+ LOGERR("Failed to teardown TX channel %d", channel);
+
+ /* instead of quitting on error immediately,
+ * we continue so as to cleanup the channel */
+ }
+
+ dev->tx_teardown_pending[channel] = FALSE;
+
+ /* disable interrupt */
+ dev->regs->tx_int_mask_clear = (1 << channel);
+
+ /* disable DMA */
+
+ /* mark channel closed */
+ dev->tx_is_open[channel] = FALSE;
+ }
+
+ else if (direction == NET_CH_DIR_RX) {
+ dev->rx_teardown_pending[channel] = TRUE;
+
+ /* initiate teardown of TX channel */
+ dev->regs->rx_teardown = channel;
+
+ /* wait for teardown complete */
+ if (emac_wait_for_teardown_complete
+ (_dev, channel, direction, TRUE) != EMAC_SUCCESS) {
+ LOGERR("Failed to teardown RX channel %d", channel);
+ }
+ dev->rx_teardown_pending[channel] = FALSE;
+
+ /* disable interrupt */
+ dev->regs->rx_int_mask_clear = (1 << channel);
+
+ /* mark channel closed */
+ dev->rx_is_open[channel] = FALSE;
+ }
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT,
+ "ChannelNo=%d, Direction=%s",
+ channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+ return (EMAC_SUCCESS);
+}
+
+/**
+ * Wait for Teardown Complete
+ * - This function waits (blocking mode) for teardown completion.
+ * - blocking = TRUE ( waits on OS timer wait untill teardown complete),
+ * = FALSE (returns immediately) - NOT SUPPORTED
+ * As of now this function supports blocking mode in polled mode only
+ */
+static int emac_wait_for_teardown_complete(emac_dev_t * _dev,
+ u32 channel,
+ net_ch_dir direction, bool blocking)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ volatile unsigned int teardown_cnt = 0xFFFFFFF0;
+
+ if (direction == NET_CH_DIR_TX) {
+ emac_tx_bd *curr_bd;
+ emac_tx_cppi_ch *tx_cppi;
+
+ LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY,
+ "ChannelNo=%d, Direction=%s",
+ channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+ while ((dev->regs->tx_CP[channel] & EMAC_TEARDOWN_VALUE) !=
+ EMAC_TEARDOWN_VALUE) {
+ /* wait here for tx teardown completion
+ * interrupt to occur */
+
+ /* A task delay can be called here to pend
+ * rather than occupying CPU cycles - anyway
+ * it has been found that the teardown takes
+ * very few cpu cycles and does not affect
+ * functionality
+ */
+ --teardown_cnt;
+ if (teardown_cnt) {
+ printk("Tx teardown aborted\n");
+ break;
+ }
+ }
+
+ /* write to the completion pointer */
+ dev->regs->tx_CP[channel] = EMAC_TEARDOWN_VALUE;
+
+ /* TX teardown complete - process sent packets and
+ * return sent packets to DDA */
+ tx_cppi = dev->tx_cppi[channel];
+ if (tx_cppi->queue_active == TRUE) {
+ curr_bd = tx_cppi->active_queue_head;
+ while (curr_bd != NULL) {
+ emac_net_tx_complete(dev,
+ &(curr_bd->buf_token),
+ 1, channel);
+
+ if (curr_bd != tx_cppi->active_queue_tail) {
+ curr_bd = curr_bd->next;
+ } else {
+ break;
+ }
+ }
+ tx_cppi->bd_pool_head = tx_cppi->active_queue_head;
+ tx_cppi->active_queue_head =
+ tx_cppi->active_queue_tail = 0;
+ }
+
+ /* At this stage all TX BD's are available linked with
+ * "bdPoolHead" and can be freed */
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT,
+ "ChannelNo=%d, Direction=%s",
+ channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+ } else if (direction == NET_CH_DIR_RX) {
+ LOGMSG(EMAC_DEBUG_FUNCTION_ENTRY,
+ "ChannelNo=%d, Direction=%s",
+ channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+ while ((dev->regs->rx_CP[channel] & EMAC_TEARDOWN_VALUE) !=
+ EMAC_TEARDOWN_VALUE) {
+
+ /* wait here for rx teardown completion
+ * interrupt to occur */
+
+ /* A task delay can be called here to pend
+ * rather than occupying CPU cycles - anyway
+ * it has been found that the teardown takes
+ * very few cpu cycles and does not affect
+ * functionality
+ */
+ --teardown_cnt;
+ if (teardown_cnt) {
+ printk("Rx teardown aborted\n");
+ break;
+ }
+ }
+
+ /* write to the completion pointer */
+ dev->regs->rx_CP[channel] = EMAC_TEARDOWN_VALUE;
+
+ /* At this stage all TX BD's are available linked with
+ * "activeQueueHead" and can be freed */
+ LOGMSG(EMAC_DEBUG_FUNCTION_EXIT,
+ "ChannelNo=%d, Direction=%s",
+ channel, ((direction == NET_CH_DIR_TX) ? "TX" : "RX"));
+
+ }
+
+ return (EMAC_SUCCESS);
+}
+
+static void emac_ddcphycnt(emac_dev_t * dev, u32 * cmd_arg)
+{
+ int result;
+ emac_hw_statistics stats;
+ struct mib2_phy_counters *mib2phy_counters =
+ (struct mib2_phy_counters *)cmd_arg;
+
+ result =
+ emac_control(dev, EMAC_IOCTL_GET_STATISTICS, (u32 *) & stats, NULL);
+
+ if (result != 0) {
+ LOGERR("Error from ioctl for EMAC_IOCTL_GET_STATISTICS \n");
+ return;
+ }
+
+ mib2phy_counters->eth_alignment_errors = stats.if_in_align_code_errors;
+ mib2phy_counters->eth_fcserrors = stats.if_in_crcerrors;
+ mib2phy_counters->eth_single_collisions =
+ stats.if_single_collision_frames;
+ mib2phy_counters->eth_multiple_collisions =
+ stats.if_multiple_collision_frames;
+ mib2phy_counters->eth_sqetest_errors = 0;
+ mib2phy_counters->eth_deferred_tx_frames =
+ stats.if_deferred_transmissions;
+ mib2phy_counters->eth_late_collisions = stats.if_late_collisions;
+ mib2phy_counters->eth_excessive_collisions =
+ stats.if_excessive_collision_frames;
+ mib2phy_counters->eth_internal_mac_tx_errors = 0;
+ mib2phy_counters->eth_carrier_sense_errors =
+ stats.if_carrier_sense_errors;
+ mib2phy_counters->eth_too_long_rx_frames = stats.if_in_oversized_frames;
+ mib2phy_counters->eth_internal_mac_rx_errors = 0;
+ mib2phy_counters->eth_symbol_errors = 0;
+
+ return;
+}
+
+static void emac_ddcifcnt_clear(emac_dev_t * _dev)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+
+ memzero((char *)&dev->mib2if_hccounter, sizeof(dev->mib2if_hccounter));
+}
+
+static void emac_ddcifcnt_updt(emac_dev_t * _dev)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ int result;
+ emac_hw_statistics stats;
+
+ result =
+ emac_control(_dev, EMAC_IOCTL_GET_STATISTICS,
+ (u32 *) & stats, NULL);
+
+ if (result != 0) {
+ LOGERR("Error from ioctl for DDC EMAC_IOCTL_GET_STATISTICS \n");
+ return;
+ }
+
+ if (stats.if_in_octets >= dev->mib2if_hccounter.in_bytes) {
+ dev->mib2if_hccounter.in_bytes_hc +=
+ (stats.if_in_octets - dev->mib2if_hccounter.in_bytes);
+ } else {
+ dev->mib2if_hccounter.in_bytes_hc +=
+ 0xffffffff - (dev->mib2if_hccounter.in_bytes -
+ stats.if_in_octets);
+ }
+
+ dev->mib2if_hccounter.in_bytes = stats.if_in_octets;
+ if (stats.if_in_good_frames >=
+ dev->mib2if_hccounter.in_multicast_pkts +
+ dev->mib2if_hccounter.in_broadcast_pkts +
+ dev->mib2if_hccounter.in_unicast_pkts) {
+ dev->mib2if_hccounter.in_unicast_pkts_hc +=
+ ((stats.if_in_good_frames -
+ (stats.if_in_broadcasts + stats.if_in_multicasts))
+ - dev->mib2if_hccounter.in_unicast_pkts);
+ } else {
+ dev->mib2if_hccounter.in_unicast_pkts_hc +=
+ 0xffffffff - (dev->mib2if_hccounter.in_unicast_pkts -
+ (stats.if_in_good_frames -
+ (stats.if_in_broadcasts +
+ stats.if_in_multicasts)));
+ }
+ dev->mib2if_hccounter.in_unicast_pkts = (stats.if_in_good_frames -
+ (stats.if_in_broadcasts +
+ stats.if_in_multicasts));
+ if (stats.if_in_multicasts >= dev->mib2if_hccounter.in_multicast_pkts) {
+ dev->mib2if_hccounter.in_multicast_pkts_hc +=
+ (stats.if_in_multicasts -
+ dev->mib2if_hccounter.in_multicast_pkts);
+ } else {
+ dev->mib2if_hccounter.in_multicast_pkts_hc +=
+ 0xffffffff - (dev->mib2if_hccounter.in_multicast_pkts -
+ stats.if_in_multicasts);
+ }
+
+ dev->mib2if_hccounter.in_multicast_pkts = stats.if_in_multicasts;
+ if (stats.if_in_broadcasts >= dev->mib2if_hccounter.in_broadcast_pkts) {
+ dev->mib2if_hccounter.in_broadcast_pkts_hc +=
+ (stats.if_in_broadcasts -
+ dev->mib2if_hccounter.in_broadcast_pkts);
+
+ } else {
+ dev->mib2if_hccounter.in_broadcast_pkts_hc +=
+ 0xffffffff - (dev->mib2if_hccounter.in_broadcast_pkts -
+ stats.if_in_broadcasts);
+ }
+
+ dev->mib2if_hccounter.in_broadcast_pkts = stats.if_in_broadcasts;
+ if (stats.if_out_octets >= dev->mib2if_hccounter.out_bytes) {
+ dev->mib2if_hccounter.out_bytes_hc +=
+ (stats.if_out_octets - dev->mib2if_hccounter.out_bytes);
+ } else {
+ dev->mib2if_hccounter.out_bytes_hc +=
+ 0xffffffff - (dev->mib2if_hccounter.out_bytes -
+ stats.if_out_octets);
+ }
+
+ dev->mib2if_hccounter.out_bytes = stats.if_out_octets;
+ if (stats.if_out_good_frames >=
+ dev->mib2if_hccounter.out_multicast_pkts +
+ dev->mib2if_hccounter.out_broadcast_pkts +
+ dev->mib2if_hccounter.out_unicast_pkts) {
+ dev->mib2if_hccounter.out_unicast_pkts_hc +=
+ ((stats.if_out_good_frames -
+ (stats.if_out_broadcasts + stats.if_out_multicasts))
+ - dev->mib2if_hccounter.out_unicast_pkts);
+ }
+
+ else {
+ dev->mib2if_hccounter.out_unicast_pkts_hc +=
+ 0xffffffff - (dev->mib2if_hccounter.out_unicast_pkts -
+ (stats.if_out_good_frames -
+ (stats.if_out_broadcasts +
+ stats.if_out_multicasts)));
+ }
+
+ dev->mib2if_hccounter.out_unicast_pkts = (stats.if_out_good_frames -
+ (stats.if_out_broadcasts +
+ stats.if_out_multicasts));
+
+ if (stats.if_out_multicasts >= dev->mib2if_hccounter.out_multicast_pkts) {
+ dev->mib2if_hccounter.out_multicast_pkts_hc +=
+ (stats.if_out_multicasts -
+ dev->mib2if_hccounter.out_multicast_pkts);
+ } else {
+ dev->mib2if_hccounter.out_multicast_pkts_hc +=
+ 0xffffffff - (dev->mib2if_hccounter.out_multicast_pkts -
+ stats.if_out_multicasts);
+ }
+
+ dev->mib2if_hccounter.out_multicast_pkts = stats.if_out_multicasts;
+ if (stats.if_out_broadcasts >= dev->mib2if_hccounter.out_broadcast_pkts) {
+ dev->mib2if_hccounter.out_broadcast_pkts_hc +=
+ (stats.if_out_broadcasts -
+ dev->mib2if_hccounter.out_broadcast_pkts);
+ } else {
+ dev->mib2if_hccounter.out_broadcast_pkts_hc +=
+ 0xffffffff - (dev->mib2if_hccounter.out_broadcast_pkts -
+ stats.if_out_broadcasts);
+ }
+ dev->mib2if_hccounter.out_broadcast_pkts = stats.if_out_broadcasts;
+
+ /* low 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.in_bytes_low =
+ (unsigned long)dev->mib2if_hccounter.in_bytes_hc;
+
+ /* high 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.in_bytes_high =
+ (dev->mib2if_hccounter.in_bytes_hc >> 32);
+
+ /* low 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.in_unicast_pkts_low =
+ (unsigned long)dev->mib2if_hccounter.in_unicast_pkts_hc;
+
+ /* high 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.in_unicast_pkts_high =
+ (dev->mib2if_hccounter.in_unicast_pkts_hc >> 32);
+
+ /* low 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.in_multicast_pkts_low =
+ (unsigned long)dev->mib2if_hccounter.in_multicast_pkts_hc;
+
+ /* high 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.in_multicast_pkts_high =
+ dev->mib2if_hccounter.in_multicast_pkts_hc >> 32;
+
+ /* low 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.in_broadcast_pkts_low =
+ (unsigned long)dev->mib2if_hccounter.in_broadcast_pkts_hc;
+
+ /* high 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.in_broadcast_pkts_high =
+ dev->mib2if_hccounter.in_broadcast_pkts_hc >> 32;
+
+ /* packets discarded due to resource limit */
+ dev->mib2if_hccounter.mib2if_counter.in_discard_pkts =
+ stats.if_rx_dmaoverruns
+ + stats.if_rx_mof_overruns
+ + stats.
+ if_rx_sof_overruns
+ + stats.if_in_crcerrors
+ + stats.
+ if_in_align_code_errors
+ + stats.if_in_jabber_frames
+ + stats.
+ if_in_fragments
+ + stats.if_in_oversized_frames
+ + stats.
+ if_in_undersized_frames
+ + stats.if_in_filtered_frames + stats.if_in_qos_filtered_frames;
+
+ /* packets discarded due to format errors */
+ dev->mib2if_hccounter.mib2if_counter.in_error_pkts =
+ stats.if_in_crcerrors
+ + stats.if_in_align_code_errors
+ + stats.if_in_jabber_frames + stats.if_in_fragments;
+
+ dev->mib2if_hccounter.mib2if_counter.in_unknown_prot_pkts = 0;
+
+ /* low 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.out_bytes_low =
+ (unsigned long)dev->mib2if_hccounter.out_bytes_hc;
+
+ /* high 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.out_bytes_high =
+ dev->mib2if_hccounter.out_bytes_hc >> 32;
+
+ /* low 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.out_unicast_pkts_low =
+ (unsigned long)dev->mib2if_hccounter.out_unicast_pkts_hc;
+
+ /* high 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.out_unicast_pkts_high =
+ dev->mib2if_hccounter.out_unicast_pkts_hc >> 32;
+
+ /* low 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.out_multicast_pkts_low =
+ (unsigned long)dev->mib2if_hccounter.out_multicast_pkts_hc;
+
+ /* high 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.out_multicast_pkts_high =
+ dev->mib2if_hccounter.out_multicast_pkts_hc >> 32;
+
+ /* low 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.out_broadcast_pkts_low =
+ (unsigned long)dev->mib2if_hccounter.out_broadcast_pkts_hc;
+
+ /* high 32-bit of total octets received from media */
+ dev->mib2if_hccounter.mib2if_counter.out_broadcast_pkts_high =
+ dev->mib2if_hccounter.out_broadcast_pkts_hc >> 32;
+
+ /* packets discarded due to format errors */
+ dev->mib2if_hccounter.mib2if_counter.out_error_pkts =
+ (stats.if_excessive_collision_frames
+ + stats.if_late_collisions + stats.if_carrier_sense_errors);
+
+ /* packets discarded due to resource limit */
+ dev->mib2if_hccounter.mib2if_counter.out_discard_pkts =
+ stats.if_out_underrun +
+ dev->mib2if_hccounter.mib2if_counter.out_error_pkts;
+
+ return;
+}
+
+#define emac_min_val(a,b) ((a > b) ? b : a)
+
+#ifdef EMAC_DEBUG /* used only for debug printing */
+/* static global strings */
+static char *emac_tx_host_error_codes[16] = {
+ /* 0000 */ "No error",
+ /* 0001 */ "SOP error",
+ /* 0010 */ "Ownership bit not set in SOP buffer",
+ /* 0011 */ "Zero Next Buffer Descriptor Pointer Without EOP",
+ /* 0100 */ "Zero Buffer Pointer",
+ /* 0101 */ "Zero Buffer Length",
+ /* 0110 */ "Packet Length Error",
+ /* 0111 */ "Reserved",
+ /* 1000 */ "Reserved",
+ /* 1001 */ "Reserved",
+ /* 1010 */ "Reserved",
+ /* 1011 */ "Reserved",
+ /* 1100 */ "Reserved",
+ /* 1101 */ "Reserved",
+ /* 1110 */ "Reserved",
+ /* 1111 */ "Reserved"
+};
+
+static char *emac_rx_host_error_codes[16] = {
+ /* 0000 */ "No error",
+ /* 0001 */ "Reserved",
+ /* 0010 */ "Ownership bit not set in input buffer",
+ /* 0011 */ "Reserved",
+ /* 0100 */ "Zero Buffer Pointer",
+ /* 0101 */ "Reserved",
+ /* 0110 */ "Reserved",
+ /* 0111 */ "Reserved",
+ /* 1000 */ "Reserved",
+ /* 1001 */ "Reserved",
+ /* 1010 */ "Reserved",
+ /* 1011 */ "Reserved",
+ /* 1100 */ "Reserved",
+ /* 1101 */ "Reserved",
+ /* 1110 */ "Reserved",
+ /* 1111 */ "Reserved"
+};
+
+#endif /* EMAC_DEBUG */
+
+/**
+ * EMAC DDC Periodic Timer (Tick) Function
+ * - calls PHY polling function
+ * - If status changed, invokes DDA callback to propogate PHY / Devicestatus
+ *
+ * "tickArgs" is not used in this implementation
+ */
+static int emac_tick(emac_dev_t * _dev, void *tick_args)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+
+ /* verify proper device state */
+ if (dev->drv_state != DRV_OPENED) {
+ return (EMAC_ERR_DEV_NOT_OPEN);
+ }
+
+ if (!(dev->init_cfg.phy_mode & SNWAY_NOPHY)) {
+ /* opened and phy available */
+ int tick_change;
+
+ tick_change = emac_mdio_tick();
+ if (tick_change == 1) { /* MDIO indicated a change */
+ emac_update_phy_status((emac_dev_t *) dev);
+ emac_control_cb(dev,
+ EMAC_IOCTL_STATUS_UPDATE,
+ (void *)&dev->status, NULL);
+ } else if ((dev->init_cfg.phy_mode & SNWAY_AUTOMDIX)
+ && (tick_change & _MIIMDIO_MDIXFLIP)) {
+ /* DaVinci does not have MDI/MDIX on chip facility */
+ }
+ }
+
+ return (EMAC_SUCCESS);
+}
+
+/**
+ * EMAC DDC Packet processing function
+ * - Detects if there are host errors and invokes the DDA callback to inform
+ * the DDA layer about the hardware error.
+ *
+ */
+static void emac_process_host_error(emac_dev_t * _dev)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ u32 channel = 0;
+ u32 vector = 0;
+ u32 status = 0;
+
+ /* the mac_status register bits starting from rx error channel
+ * have been mapped to hw_err_info LSB 16 bits */
+ status = dev->regs->mac_status;
+
+ /* TX: reading the channel and cause */
+ channel =
+ ((status & EMAC_MACSTATUS_TXERRCH_MASK) >>
+ EMAC_MACSTATUS_TXERRCH_SHIFT);
+
+ dev->status.hw_err_info = channel << 16;
+
+ vector =
+ (status & EMAC_MACSTATUS_TXERRCODE_MASK) >>
+ EMAC_MACSTATUS_TXERRCODE_SHIFT;
+
+ if (vector) {
+ dev->status.hw_status = EMAC_TX_HOST_ERROR;
+ LOGERR
+ ("Ch=%d, EMAC_TX_HOST_ERROR. Cause=%s",
+ dev->status.hw_err_info,
+ &emac_tx_host_error_codes[vector][0]);
+ }
+
+ /* RX: reading the channel and cause (vector variable being
+ * re-used) */
+ channel =
+ ((status & EMAC_MACSTATUS_RXERRCH_MASK) >>
+ EMAC_MACSTATUS_RXERRCH_SHIFT);
+
+ dev->status.hw_err_info |= channel;
+ vector =
+ (status & EMAC_MACSTATUS_RXERRCODE_MASK) >>
+ EMAC_MACSTATUS_RXERRCODE_SHIFT;
+ if (vector) {
+ dev->status.hw_status = EMAC_RX_HOST_ERROR;
+ LOGERR
+ ("Ch=%d, EMAC_RX_HOST_ERROR. Cause=%s",
+ dev->status.hw_err_info,
+ &emac_rx_host_error_codes[vector][0]);
+ }
+
+ /* inform DDA layer about this critical failure */
+ emac_control_cb(dev,
+ EMAC_IOCTL_STATUS_UPDATE, (void *)&dev->status, NULL);
+}
+
+/**
+ * EMAC DDC Packet processing function
+
+ * - Reads the device interrupt status and invokes TX/RX BD processing
+ * function
+ * - Also detects if there are host errors and invokes the
+ * callback to inform about the hardware error.
+ *
+ * "pkts_pending" will contain number of packets still to be processed
+ * (TX + RX)
+ */
+static int emac_pkt_process(emac_dev_t * _dev, int *pkts_pending,
+ void *pkt_args)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ u32 channel = 0;
+ u32 vector = 0;
+ u32 handle_pkts_and_status = 0;
+ u32 vector_channel = 0;
+ int pkts_processed = 0;
+
+ /* disable interrupts via module control (wrapper) */
+ ((volatile ewrap_regs *)dev->e_wrap_regs)->EWCTL = 0x0;
+ vector = dev->regs->mac_in_vector;
+
+ /* handle packet transmit completion */
+ if (vector & EMAC_MAC_IN_VECTOR_TX_INT_VEC) {
+ bool is_eoq;
+
+ vector_channel = (vector & EMAC_MAC_IN_VECTOR_TX_INT_VEC);
+ for (channel = 0; channel < 8; channel++) {
+ if (vector_channel & 0x1)
+ break;
+
+ vector_channel >>= 1;
+ }
+
+ handle_pkts_and_status =
+ dev->tx_cppi[channel]->ch_info.service_max;
+ if (pkt_args)
+ handle_pkts_and_status =
+ emac_min_val(((rx_tx_params *) pkt_args)->tx_pkts,
+ handle_pkts_and_status);
+
+ pkts_processed =
+ emac_tx_bdproc(_dev, channel, &handle_pkts_and_status,
+ &is_eoq);
+ if (pkt_args)
+ ((rx_tx_params *) pkt_args)->ret_tx_pkts =
+ pkts_processed;
+
+ if (dev->tx_interrupt_disable == TRUE) {
+ /* status */
+ if (!handle_pkts_and_status && is_eoq)
+ /* disable channel interrupt */
+ dev->regs->tx_int_mask_clear = (1 << channel);
+ }
+ *pkts_pending = handle_pkts_and_status; /* status. */
+ }
+
+ /* Handle RX packets first - the thought process in this is
+ * that the received packets will be handled immediately
+ * reducing the latency (- but an equally opposite argument
+ * can also be made)
+ */
+ if (vector & EMAC_MAC_IN_VECTOR_RX_INT_VEC) {
+ vector_channel = (vector & EMAC_MAC_IN_VECTOR_RX_INT_VEC);
+ vector_channel >>= 8;
+ for (channel = 0; channel < 8; channel++) {
+ if (vector_channel & 0x1)
+ break;
+ vector_channel >>= 1;
+ }
+
+ handle_pkts_and_status =
+ dev->rx_cppi[channel]->ch_info.service_max;
+ if (pkt_args)
+ handle_pkts_and_status =
+ emac_min_val(((rx_tx_params *) pkt_args)->rx_pkts,
+ handle_pkts_and_status);
+
+ pkts_processed =
+ emac_rx_bdproc(_dev, channel, &handle_pkts_and_status);
+
+ if (pkt_args)
+ ((rx_tx_params *) pkt_args)->ret_rx_pkts =
+ pkts_processed;
+
+ *pkts_pending |= handle_pkts_and_status; /* status */
+ }
+
+ /* handle host errors - being handled last does not mean its
+ * of least priority */
+ if (vector & EMAC_MAC_IN_VECTOR_HOST_INT) {
+ emac_process_host_error(_dev);
+ }
+
+ return (EMAC_SUCCESS);
+}
+
+/**
+ * EMAC DDC Signal Packet processing end to hardware
+ * - programs the EOI vector register so that if there are pending
+ * packets in hardware queue * an interrupt can be generated by the
+ * hardware
+ */
+/* packet processing end */
+static int emac_pkt_process_end(emac_dev_t * _dev, void *proc_args)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+
+ /* enable interrupts via module control (wrapper) */
+ ((volatile ewrap_regs *)dev->e_wrap_regs)->EWCTL = 0x1;
+
+ return (EMAC_SUCCESS);
+}
+
+#ifdef EMAC_MULTIFRAGMENT
+
+#error "EMAC Multi fragment Not supported"
+
+#else
+
+/*************************************
+ * SINGLE-FRAGMENT SUPPORT HERE
+ *************************************/
+
+/**
+ * EMAC DDC Send/Transmit function
+ * - Queues the packet provided by DDA into hardware queue
+ * - If the queue is stalled due to sync issues, re-trigger the hardware
+ *
+ * If "sendArgs" is TRUE (non zero) CRC is calculated by DDA or upper
+ * layer and not by hardware and is part of the packet data send to
+ * this function
+ */
+
+static int emac_send(emac_dev_t * _dev, net_pkt_obj * pkt,
+ int channel, bool send_args)
+{
+ unsigned long flags;
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ int ret_val = EMAC_SUCCESS;
+ emac_tx_bd *curr_bd;
+ emac_tx_cppi_ch *tx_cppi;
+ net_buf_obj *buf_list;
+
+ /* verify proper device state */
+ if (dev->drv_state != DRV_OPENED)
+ return (EMAC_ERR_DEV_NOT_OPEN);
+
+ /* validate channel number and get channel control structure */
+ if (channel > EMAC_MAX_TX_CHANNELS)
+ return (EMAC_ERR_TX_CH_INVALID);
+
+ if (dev->tx_is_open[channel] != TRUE)
+ return (EMAC_ERR_TX_CH_NOT_OPEN);
+
+ /* check ethernet link state. if not linked, return error */
+ if (!dev->status.phy_linked)
+ return (EMAC_ERR_TX_NO_LINK);
+
+ tx_cppi = dev->tx_cppi[channel];
+ buf_list = pkt->buf_list; /* get handle to the buffer array */
+
+ /* check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
+ if (pkt->pkt_length < EMAC_MIN_ETHERNET_PKT_SIZE) {
+ buf_list->length +=
+ (EMAC_MIN_ETHERNET_PKT_SIZE - pkt->pkt_length);
+ pkt->pkt_length = EMAC_MIN_ETHERNET_PKT_SIZE;
+ }
+ spin_lock_irqsave(&dev->tx_lock, flags);
+
+ /* only one tx BD for the packet to be sent */
+ curr_bd = tx_cppi->bd_pool_head;
+ if (curr_bd == NULL) {
+#ifdef EMAC_GETSTATS
+ tx_cppi->out_of_tx_bd++;
+#endif
+ ret_val = EMAC_ERR_TX_OUT_OF_BD;
+ goto exit_emac_send;
+ }
+
+ tx_cppi->bd_pool_head = curr_bd->next;
+
+ /* populate the BD contents to be added to the TX list */
+ curr_bd->buf_token = buf_list->buf_token;
+ curr_bd->buff_ptr = EMAC_VIRT_TO_PHYS((int *)buf_list->data_ptr);
+ curr_bd->off_b_len = buf_list->length;
+ curr_bd->h_next = 0;
+ curr_bd->next = 0;
+ curr_bd->mode =
+ (EMAC_CPPI_SOP_BIT | EMAC_CPPI_OWNERSHIP_BIT | EMAC_CPPI_EOP_BIT
+ | pkt->pkt_length);
+
+ if ((bool) send_args == TRUE)
+ curr_bd->mode |= EMAC_CPPI_PASS_CRC_BIT;
+
+ /* flush the packet from cache if write back cache is present */
+ BD_CACHE_WRITEBACK_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
+
+ /* send the packet */
+ if (tx_cppi->active_queue_head == 0) {
+ tx_cppi->active_queue_head = curr_bd;
+ tx_cppi->active_queue_tail = curr_bd;
+ if (tx_cppi->queue_active != TRUE) {
+ dev->regs->tx_HDP[channel] = EMAC_VIRT_TO_PHYS(curr_bd);
+ tx_cppi->queue_active = TRUE;
+ }
+#ifdef EMAC_GETSTATS
+ ++tx_cppi->queue_reinit;
+#endif
+ } else {
+ register volatile emac_tx_bd *tail_bd;
+ register u32 frame_status;
+
+ tail_bd = tx_cppi->active_queue_tail;
+ tail_bd->next = curr_bd;
+ tx_cppi->active_queue_tail = curr_bd;
+ tail_bd = EMAC_VIRT_NOCACHE(tail_bd);
+ tail_bd->h_next = (int)EMAC_VIRT_TO_PHYS(curr_bd);
+ frame_status = tail_bd->mode;
+ if (frame_status & EMAC_CPPI_EOQ_BIT) {
+ dev->regs->tx_HDP[channel] = EMAC_VIRT_TO_PHYS(curr_bd);
+ frame_status &= ~(EMAC_CPPI_EOQ_BIT);
+ tail_bd->mode = frame_status;
+#ifdef EMAC_GETSTATS
+ ++tx_cppi->end_of_queue_add;
+#endif
+ } else {
+ if (dev->tx_interrupt_disable == TRUE) {
+ /* enable channel interrupt */
+ dev->regs->tx_int_mask_set = (1 << channel);
+ }
+ }
+ }
+#ifdef EMAC_GETSTATS
+ tx_cppi->active_queue_count++;
+#endif
+
+ exit_emac_send:
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
+
+ if (dev->tx_interrupt_disable == TRUE) {
+ if (--dev->tx_int_threshold[channel] <= 0) {
+ bool is_eoq;
+ u32 handle_pkts_and_status;
+
+ handle_pkts_and_status =
+ dev->tx_cppi[channel]->ch_info.service_max;
+ emac_tx_bdproc(_dev, channel, &handle_pkts_and_status,
+ &is_eoq);
+ dev->tx_int_threshold[channel] =
+ dev->tx_cppi[channel]->ch_info.service_max;
+ }
+ }
+
+ return (ret_val);
+}
+
+/**
+ * EMAC DDC TX Buffer Descriptor processing
+ * - processes transmit completed packets and returns the handles to DDA layer
+ * - If the queue is stalled due to sync issues, re-trigger the hardware
+ *
+ * returns number of pkts processed and 1 in morePkts if pkt
+ * completion processing pending
+ */
+static int emac_tx_bdproc(emac_dev_t * _dev, u32 channel,
+ u32 * handle_pkts_and_status, bool * is_eoq)
+{
+ unsigned long flags;
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ emac_tx_bd *curr_bd;
+ emac_tx_cppi_ch *tx_cppi;
+ volatile u32 frame_status;
+ u32 pkts_processed = 0;
+ u32 pkts_to_process = *handle_pkts_and_status;
+#ifdef EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+ u32 tx_complete_cnt = 0;
+ u32 *tx_complete_ptr;
+#endif
+
+ *handle_pkts_and_status = 0; /* status. */
+ *is_eoq = TRUE;
+
+ /* Here no need to validate channel number, since it is taken
+ from the interrupt register instead channel structure
+ should be validated */
+ if (dev->tx_is_open[channel] == FALSE)
+ return (EMAC_ERR_TX_CH_NOT_OPEN);
+
+ if (dev->tx_teardown_pending[channel] == TRUE) {
+ return (EMAC_SUCCESS); /* dont handle any pkt completions */
+ }
+
+ tx_cppi = dev->tx_cppi[channel];
+#ifdef EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+ tx_complete_ptr = &tx_cppi->tx_complete[0];
+#endif
+#ifdef EMAC_GETSTATS
+ ++tx_cppi->proc_count;
+#endif
+ spin_lock_irqsave(&dev->tx_lock, flags);
+
+ /* get first BD to process */
+ curr_bd = tx_cppi->active_queue_head;
+ if (curr_bd == 0) {
+ dev->regs->tx_CP[channel] =
+ EMAC_VIRT_TO_PHYS(tx_cppi->last_hw_bdprocessed);
+#ifdef EMAC_GETSTATS
+ tx_cppi->no_active_pkts++;
+#endif
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
+
+ return (EMAC_SUCCESS);
+ }
+
+ /* invalidate BD */
+ BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
+
+ frame_status = curr_bd->mode;
+ while ((curr_bd) &&
+ ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0) &&
+ (pkts_processed < pkts_to_process)) {
+
+ dev->regs->tx_CP[channel] = EMAC_VIRT_TO_PHYS(curr_bd);
+ tx_cppi->active_queue_head = curr_bd->next;
+ if (frame_status & EMAC_CPPI_EOQ_BIT) {
+ if (curr_bd->next) { /* misqueued packet */
+ dev->regs->tx_HDP[channel] = curr_bd->h_next;
+#ifdef EMAC_GETSTATS
+ ++tx_cppi->mis_queued_packets;
+#endif
+ } else { /* end of queue */
+ tx_cppi->queue_active = FALSE;
+ }
+ }
+#ifdef EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+ *tx_complete_ptr = (u32) curr_bd->buf_token;
+ ++tx_complete_ptr;
+ ++tx_complete_cnt;
+#else
+ /* single packet TX complete notify - this function is
+ * called in the send critical section context */
+ emac_net_tx_complete(dev,
+ &curr_bd->buf_token, 1, (void *)channel);
+#endif
+ curr_bd->next = tx_cppi->bd_pool_head;
+ tx_cppi->bd_pool_head = curr_bd;
+#ifdef EMAC_GETSTATS
+ --tx_cppi->active_queue_count;
+#endif
+ pkts_processed++;
+ tx_cppi->last_hw_bdprocessed = curr_bd;
+ curr_bd = tx_cppi->active_queue_head;
+ if (curr_bd) {
+ BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
+ frame_status = curr_bd->mode;
+ }
+ } /* end of while loop */
+
+ if ((curr_bd) && ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) {
+ *handle_pkts_and_status = 1;
+ }
+ /* this check is same as check for EOQ i.e framestatus and
+ * EMAC_CPPI_EOQ_BIT */
+ if (curr_bd) {
+ *is_eoq = FALSE;
+ }
+
+#ifdef EMAC_MULTIPACKET_TX_COMPLETE_NOTIFY
+ /* multiple packet TX complete notify - this function is NOT
+ * called in the send critical section context */
+ emac_net_tx_complete(dev,
+ (emac_net_data_token *) & tx_cppi->
+ tx_complete[0], tx_complete_cnt, channel);
+#endif
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
+
+ return (pkts_processed);
+}
+
+/**
+ * EMAC DDC Add Buffer to RX queue function
+ * - returns the BD to the Receive queue
+ * - If the queue is stalled due to sync issues, re-trigger the hardware
+ */
+static void emac_add_bdto_rx_queue(emac_dev_t * _dev, emac_rx_cppi_ch * rx_cppi,
+ emac_rx_bd * curr_bd, char *buffer,
+ emac_net_data_token buf_token)
+{
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+
+ /* populate the hardware descriptor */
+ curr_bd->h_next = 0;
+ curr_bd->buff_ptr = EMAC_VIRT_TO_PHYS(buffer);
+ curr_bd->off_b_len = rx_cppi->ch_info.buf_size;
+ curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT;
+ curr_bd->next = 0;
+ curr_bd->data_ptr = buffer;
+ curr_bd->buf_token = buf_token;
+
+ /* write back */
+ BD_CACHE_WRITEBACK_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
+ if (rx_cppi->active_queue_head == 0) {
+ rx_cppi->active_queue_head = curr_bd;
+ rx_cppi->active_queue_tail = curr_bd;
+ if (rx_cppi->queue_active != FALSE) {
+ dev->regs->rx_HDP[rx_cppi->ch_info.ch_num] =
+ EMAC_VIRT_TO_PHYS(rx_cppi->active_queue_head);
+ rx_cppi->queue_active = TRUE;
+ }
+ } else {
+ emac_rx_bd *tail_bd;
+ u32 frame_status;
+
+ tail_bd = rx_cppi->active_queue_tail;
+ rx_cppi->active_queue_tail = curr_bd;
+ tail_bd->next = (void *)curr_bd;
+ tail_bd = EMAC_VIRT_NOCACHE(tail_bd);
+ tail_bd->h_next = EMAC_VIRT_TO_PHYS(curr_bd);
+ frame_status = tail_bd->mode;
+ if (frame_status & EMAC_CPPI_EOQ_BIT) {
+ dev->regs->rx_HDP[rx_cppi->ch_info.ch_num] =
+ EMAC_VIRT_TO_PHYS(curr_bd);
+ frame_status &= ~(EMAC_CPPI_EOQ_BIT);
+ tail_bd->mode = frame_status;
+#ifdef EMAC_GETSTATS
+ ++rx_cppi->end_of_queue_add;
+#endif
+ }
+
+ }
+
+#ifdef EMAC_GETSTATS
+ ++rx_cppi->recycled_bd; /* maintain statistics of how many BD's were queued back - recycled */
+#endif
+}
+
+/**
+ * EMAC DDC RX Buffer Descriptor processing
+ * - processes received packets and passes them to DDA layer
+ * - requeues the buffer descriptor to the receive pool
+ * - If the queue is stalled due to sync issues, re-trigger the hardware
+ */
+static int emac_rx_bdproc(emac_dev_t * _dev, u32 channel,
+ int *handle_pkts_and_status)
+{
+ unsigned long flags;
+ emac_dev_t *dev = (emac_dev_t *) _dev;
+ emac_rx_cppi_ch *rx_cppi;
+ emac_rx_bd *curr_bd, *last_bd;
+ u32 frame_status;
+ char *new_buffer;
+ emac_net_data_token new_buf_token;
+ net_buf_obj *rx_buf_obj;
+ u32 pkts_processed;
+ net_pkt_obj *curr_pkt,pkt_obj;
+ net_buf_obj buf_obj;
+ u32 pkts_to_be_processed = *handle_pkts_and_status;
+
+ /* Here no need to validate channel number, since it is taken
+ from the interrupt register instead channel structure
+ should be validated */
+ if (dev->rx_is_open[channel] == FALSE) {
+ *handle_pkts_and_status = 0;
+ return (EMAC_ERR_RX_CH_NOT_OPEN);
+ }
+
+ /* check if channel teardown pending */
+ rx_cppi = dev->rx_cppi[channel];
+ if (dev->rx_teardown_pending[channel] == TRUE) {
+ *handle_pkts_and_status = 0;
+ return (0);
+ }
+#ifdef EMAC_GETSTATS
+ ++rx_cppi->proc_count;
+#endif
+ *handle_pkts_and_status = 0;
+ pkts_processed = 0;
+
+ spin_lock_irqsave(&dev->rx_lock, flags);
+
+ pkt_obj.buf_list = &buf_obj;
+ curr_pkt = &pkt_obj;
+ curr_bd = rx_cppi->active_queue_head;
+ BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
+ frame_status = curr_bd->mode;
+
+ while ((curr_bd) &&
+ ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0) &&
+ (pkts_processed < pkts_to_be_processed)) {
+
+ /* allocate new buffer */
+ new_buffer =
+ (void *)(emac_net_alloc_rx_buf(dev,
+ rx_cppi->ch_info.buf_size,
+ &new_buf_token, 0, NULL));
+ if (new_buffer == NULL) {
+ /* no buffer available. return error with packets pending */
+#ifdef EMAC_GETSTATS
+ ++rx_cppi->out_of_rx_buffers;
+#endif
+ goto end_emac_rx_bdproc;
+ }
+
+ /* populate received packet data structure */
+ rx_buf_obj = &curr_pkt->buf_list[0];
+ rx_buf_obj->data_ptr = (char *)curr_bd->data_ptr;
+ rx_buf_obj->length = curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE;
+ rx_buf_obj->buf_token = curr_bd->buf_token;
+ curr_pkt->pkt_token = curr_pkt->buf_list->buf_token;
+ curr_pkt->num_bufs = 1;
+ curr_pkt->pkt_length =
+ (frame_status & EMAC_RX_BD_PKT_LENGTH_MASK);
+ /* acknowledge RX interrupt for the channel */
+ dev->regs->rx_CP[channel] = EMAC_VIRT_TO_PHYS(curr_bd);
+#ifdef EMAC_GETSTATS
+ ++rx_cppi->processed_bd;
+#endif
+ last_bd = curr_bd;
+ curr_bd = last_bd->next;
+ rx_cppi->active_queue_head = curr_bd;
+
+ /* check if end of RX queue ? */
+ if (frame_status & EMAC_CPPI_EOQ_BIT) {
+ if (curr_bd) { /* misqueued packet */
+#ifdef EMAC_GETSTATS
+ ++rx_cppi->mis_queued_packets;
+#endif
+ dev->regs->rx_HDP[channel] =
+ EMAC_VIRT_TO_PHYS(curr_bd);
+ } else { /* end of queue */
+#ifdef EMAC_GETSTATS
+ ++rx_cppi->end_of_queue;
+#endif
+ rx_cppi->queue_active = FALSE; /* clear software RX queue */
+ }
+ }
+
+ /* recycle BD */
+ emac_add_bdto_rx_queue(_dev, rx_cppi, last_bd, new_buffer,
+ new_buf_token);
+
+ /* return the packet to the user - BD ptr passed in
+ * last parameter for potential *future* use */
+ spin_unlock_irqrestore(&dev->rx_lock, flags);
+ emac_net_rx_cb(dev,curr_pkt,(void*)channel);
+ spin_lock_irqsave(&dev->rx_lock, flags);
+
+ curr_bd = rx_cppi->active_queue_head;
+ if (curr_bd) {
+ BD_CACHE_INVALIDATE(curr_bd, EMAC_BD_LENGTH_FOR_CACHE);
+ frame_status = curr_bd->mode;
+ }
+ ++pkts_processed;
+ }
+
+ if ((curr_bd) && ((frame_status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) {
+ *handle_pkts_and_status = 1;
+ }
+
+ end_emac_rx_bdproc:
+ spin_unlock_irqrestore(&dev->rx_lock, flags);
+ return (pkts_processed);
+}
+
+#endif /* !EMAC_MULTIFRAGMENT */
+
+/* Linux 2.6 Kernel Ethernet Poll function Call only RX processing in
+ * the poll function - TX is taken care of in interrupt context
+ */
+static int emac_poll(struct net_device *netdev, int *budget)
+{
+ emac_dev_t *dev = netdev_priv(netdev);
+ unsigned int work = min(netdev->quota, *budget);
+ unsigned int pkts_pending = 0;
+ /* this is used to pass the rx packets to be processed and
+ * return the number of rx packets processed */
+ rx_tx_params *napi_params = &dev->napi_rx_tx;
+
+ if (!dev->set_to_close) {
+ napi_params->rx_pkts = work;
+ napi_params->tx_pkts = EMAC_DEFAULT_TX_MAX_SERVICE;
+
+ /* process packets - call the DDC packet processing function */
+ emac_pkt_process(dev, &pkts_pending, napi_params);
+
+ /* if more packets reschedule the tasklet or call
+ * pkt_process_end */
+ if (!pkts_pending) {
+ if (test_bit(__LINK_STATE_RX_SCHED, &netdev->state)) {
+ netif_rx_complete(netdev);
+ }
+ emac_pkt_process_end(dev, NULL);
+ return 0;
+ } else if (!test_bit(0, &dev->set_to_close)) {
+ *budget -= napi_params->ret_rx_pkts;
+ netdev->quota -= napi_params->ret_rx_pkts;
+ return 1;
+ }
+ }
+
+ /* we are closing down, so dont process anything */
+ return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling receive - used by netconsole and other diagnostic tools
+ * to allow network i/o with interrupts disabled.
+ */
+void emac_poll_controller(struct net_device *netdev)
+{
+ emac_dev_t *dev = NETDEV_PRIV(netdev);
+
+ disable_irq(netdev->irq);
+ emac_hal_isr(netdev->irq, dev);
+ enable_irq(netdev->irq);
+}
+#endif
+
+/* allocate RX buffer */
+void *emac_net_alloc_rx_buf(emac_dev_t * dev, int buf_size,
+ emac_net_data_token * data_token,
+ u32 channel, void *alloc_args)
+{
+ struct net_device *netdev = dev->owner;
+ struct sk_buff *p_skb;
+
+ p_skb = dev_alloc_skb(dev->rx_buf_size);
+ if (p_skb == NULL) {
+#ifdef EMAC_DEBUG
+ ERR("emac_net_alloc_rx_buf:Failed to allocate skb for %s.\n",
+ netdev->name);
+#endif
+ return (NULL);
+ }
+
+ /* set device pointer in skb and reserve space for extra bytes */
+ p_skb->dev = netdev;
+ skb_reserve(p_skb, dev->rx_buf_offset);
+
+ /* set the data token */
+ *data_token = (emac_net_data_token) p_skb;
+#ifdef EMAC_CACHE_INVALIDATE_FIX
+ /* invalidate buffer */
+ EMAC_CACHE_INVALIDATE((unsigned long)p_skb->data, buf_size);
+#endif
+
+ return p_skb->data;
+}
+
+/* free RX buffer */
+static int emac_net_free_rx_buf(emac_dev_t * dev, void *buffer,
+ emac_net_data_token data_token,
+ u32 channel, void *free_args)
+{
+ dev_kfree_skb_any((struct sk_buff *)data_token);
+ return (EMAC_SUCCESS);
+}
+
+
+/*
+ * Packet receive notification
+ *
+ * This function gets received packet via the netPktList and
+ * it queues the packet into the higher layer queue
+ *
+ * Note that rxArgs contains "channel" and is ignored for this
+ * implementation
+*/
+static int emac_net_rx_cb(emac_dev_t * dev,
+ net_pkt_obj * net_pkt_list,
+ void *rx_args)
+{
+
+ struct sk_buff *p_skb;
+
+ p_skb = (struct sk_buff *)net_pkt_list->pkt_token;
+
+ /* set length of packet */
+ skb_put(p_skb, net_pkt_list->pkt_length);
+#ifndef EMAC_CACHE_INVALIDATE_FIX
+ /* invalidate cache */
+ EMAC_CACHE_INVALIDATE((unsigned long)p_skb->data, p_skb->len);
+#endif
+ p_skb->protocol = eth_type_trans(p_skb, dev->owner);
+ p_skb->dev->last_rx = jiffies;
+ netif_receive_skb(p_skb);
+ dev->net_dev_stats.rx_bytes += net_pkt_list->pkt_length;
+ dev->net_dev_stats.rx_packets++;
+
+ return (0);
+}
+
+
+/* transmit complete callback */
+static int emac_net_tx_complete(emac_dev_t * dev,
+ emac_net_data_token * net_data_tokens,
+ int num_tokens, u32 channel)
+{
+ u32 cnt;
+
+ if (num_tokens && netif_queue_stopped(dev->owner)) {
+ printk("EMAC: TX Complete: Starting queue\n");
+ netif_start_queue(dev->owner);
+ }
+
+ for (cnt = 0; cnt < num_tokens; cnt++) {
+ struct sk_buff *skb = (struct sk_buff *)net_data_tokens[cnt];
+ if (skb == NULL)
+ continue;
+
+ dev->net_dev_stats.tx_packets++;
+ dev->net_dev_stats.tx_bytes += skb->len;
+ dev_kfree_skb_any(skb);
+ }
+
+ return (0);
+}
+
+/******************************************************************************
+ * Interrupt functions
+ *****************************************************************************/
+
+irqreturn_t emac_hal_isr(int irq, void *dev_id)
+{
+ emac_dev_t *dev = (emac_dev_t *) dev_id;
+
+ ++dev->isr_count;
+ if (!dev->set_to_close) {
+ /* NAPI support */
+ netif_rx_schedule(dev->owner);
+ } else {
+ /* we are closing down, so dont process anything */
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* transmit function - only single fragment supported */
+static int emac_dev_tx(struct sk_buff *skb, struct net_device *netdev)
+{
+ int ret_code;
+ net_buf_obj tx_buf; /* buffer object - only single frame support */
+ net_pkt_obj tx_packet; /* packet object */
+ emac_dev_t *dev = NETDEV_PRIV(netdev);
+ /* ANANT HACK: unsigned long flags; */
+
+ /* Build the buffer and packet objects - Since only single fragment is
+ * supported, need not set length and token in both packet & object.
+ * Doing so for completeness sake & to show that this needs to be done
+ * in multifragment case
+ */
+ tx_packet.buf_list = &tx_buf;
+ tx_packet.num_bufs = 1; /* only single fragment supported */
+ tx_packet.pkt_length = skb->len;
+ tx_packet.pkt_token = (emac_net_data_token) skb;
+ tx_buf.length = skb->len;
+ tx_buf.buf_token = (emac_net_data_token) skb;
+ tx_buf.data_ptr = skb->data;
+
+ /* flush data buffer if write back mode */
+ EMAC_CACHE_WRITEBACK((unsigned long)skb->data, skb->len);
+ netdev->trans_start = jiffies;
+
+ /* ANANT_HACK: Need to lock TX so that there is no contention
+ spin_lock_irqsave(&hDDA->lock, flags);
+ */
+
+ /* DDC send : last param FALSE so that hardware calculates CRC */
+ ret_code = emac_send(dev, &tx_packet, EMAC_DEFAULT_TX_CHANNEL, FALSE);
+
+ /* ANANT_HACK: Need to un-lock TX so that there is no contention
+ between two processes
+ spin_unlock_irqrestore(&hDDA->lock, flags);
+ */
+
+ if (ret_code != EMAC_SUCCESS) {
+ if (ret_code == EMAC_ERR_TX_OUT_OF_BD) {
+ ERR("WARN: emac_dev_tx: Out of TX BD's\n");
+ netif_stop_queue(dev->owner);
+ }
+ dev->net_dev_stats.tx_dropped++;
+ goto emac_dev_tx_drop_pkt;
+ }
+ return (0);
+
+ emac_dev_tx_drop_pkt:
+ dev->net_dev_stats.tx_dropped++;
+
+ return (-1);
+}
+
+/******************************************************************************
+ * Linux Driver Model
+ *****************************************************************************/
+
+/* The real device and driver matching will be done by the
+ * match routine of the platform bus. It is necessary
+ * for the probe function to be non null though.
+ * We have a function that just returns zero. "All matched."
+ */
+static int __devinit emac_probe(struct device *dev)
+{
+ return 0;
+}
+
+/* structure describing the EMAC driver */
+static struct device_driver emac_driver = {
+ .name = "emac",
+ .bus = &platform_bus_type,
+ .probe = emac_probe,
+ .remove = NULL, /* TODO: findout when probe would be called. */
+ .suspend = NULL,
+ .resume = NULL,
+};
+
+/******************************************************************************
+ * Linux Module Init/Exit
+ *****************************************************************************/
+
+static struct platform_device *emac_dev;
+
+static ssize_t emac_show_version(struct device_driver *drv, char *buf)
+{
+ return emac_p_get_version(buf, NULL, 0, 4096, NULL, NULL);
+}
+
+static DRIVER_ATTR(version, S_IRUGO, emac_show_version, NULL);
+
+/* probe number of EMAC instances and register net_device structure */
+static int __init emac_dev_probe(void)
+{
+ int ret_val = 0;
+ int unit;
+ int instance_count = EMAC_MAX_INSTANCES;
+
+ /* obtain clock rate from kernel clock API's */
+ emac_clk = clk_get(0, "EMACCLK");
+ if (IS_ERR(emac_clk)) {
+ printk("TI DAVINCI EMAC: Failed to get clock. Exiting\n");
+ return (-1);
+ }
+ clk_enable(emac_clk);
+ emac_bus_frequency = clk_get_rate(emac_clk);
+
+ emac_dev =
+ platform_device_register_simple("ti_davinci_emac", -1, NULL, 0);
+
+ if (IS_ERR(emac_dev)) {
+ /* if error, free EMAC clock */
+ clk_disable(emac_clk);
+ return -1;
+ }
+
+ if (driver_register(&emac_driver)) {
+ platform_device_unregister(emac_dev);
+
+ /* if error, free EMAC clock */
+ clk_disable(emac_clk);
+ return -1;
+ }
+
+ ret_val = driver_create_file(&emac_driver, &driver_attr_version);
+ if(ret_val)
+ return ret_val;
+ for (unit = 0; unit < instance_count; unit++) {
+ struct net_device *netdev;
+ emac_dev_t *dev;
+ int failed;
+
+ if (!(netdev = alloc_etherdev(sizeof(emac_dev_t)))) {
+ printk
+ ("TI DaVinci EMAC: Etherdev alloc failed for device inst %d.\n",
+ unit);
+
+ ret_val = -ENOMEM;
+ /* if error, free EMAC clock */
+ clk_disable(emac_clk);
+ break;
+ }
+ dev = NETDEV_PRIV(netdev);
+ dev->owner = netdev;
+ dev->instance_num = unit;
+ netdev->init = emac_dev_init;
+ SET_NETDEV_DEV(netdev, &(emac_dev->dev));
+ emac_net_dev[dev->instance_num] = netdev;
+#if defined CONFIG_EMAC_INIT_BUF_MALLOC
+ g_init_enable_flag = 1;
+#endif
+ emac_p_detect_manual_cfg(cfg_link_speed, cfg_link_mode,
+ debug_mode);
+ if (emac_cfg_probe()) {
+ printk("TI DAVINCI EMAC: Error in configuration.\n");
+ return (-1);
+ }
+
+ /* register the network device with linux */
+ failed = register_netdev(netdev);
+
+ if (failed) {
+ ERR("Could not register device: %d\n", failed);
+
+ ret_val = -1;
+
+ clk_disable(emac_clk);
+
+ FREE_NETDEV(netdev);
+ break;
+ } else {
+ dev->next_device = last_emac_device;
+ last_emac_device = netdev;
+ DBG("%s irq=%2d io=%04x\n",
+ netdev->name, (int)netdev->irq,
+ (int)netdev->base_addr);
+ create_proc_read_entry("net/emac_rfc2665_stats", 0,
+ NULL, emac_p_read_rfc2665_stats,
+ netdev);
+ }
+ }
+
+ if (ret_val == 0) {
+ /* to maintain backward compatibility with NSP. */
+ gp_stats_file = create_proc_entry("net/emac_stats", 0644, NULL);
+ if (gp_stats_file) {
+ gp_stats_file->read_proc = emac_p_read_stats;
+ gp_stats_file->write_proc = emac_p_write_stats;
+ }
+ create_proc_read_entry("net/emac_link", 0, NULL,
+ emac_p_read_link, NULL);
+ create_proc_read_entry("net/emac_ver", 0, NULL,
+ emac_p_get_version, NULL);
+ create_proc_read_entry("net/emac_config", 0, NULL,
+ emac_dump_config, NULL);
+ }
+ emac_devices_installed = unit;
+
+ printk("%s\n", emac_version_string);
+ printk("TI DaVinci EMAC: Installed %d instances.\n", unit);
+#if defined CONFIG_EMAC_INIT_BUF_MALLOC
+ printk
+ ("TI DAVINCI EMAC driver is allocating buffer memory at init time.\n");
+#endif
+
+ return ((unit >= 0) ? 0 : -ENODEV);
+}
+
+/* frees the EMAC device structures */
+static void emac_exit(void)
+{
+ struct net_device *netdev;
+ emac_dev_t *dev;
+ int ret_code;
+
+ while (emac_devices_installed) {
+ char proc_name[100];
+ int proc_category_name_len = 0;
+
+ netdev = last_emac_device;
+ dev = NETDEV_PRIV(netdev);
+
+ DBG("Unloading %s irq=%2d io=%04x\n",
+ netdev->name, (int)netdev->irq, (int)netdev->base_addr);
+
+ /* free EMAC clock */
+ clk_disable(emac_clk);
+
+ if (g_init_enable_flag) {
+ emac_p_dev_disable(dev);
+ }
+
+ /* deinit DDC */
+ ret_code = emac_de_init(dev, NULL);
+
+ if (ret_code != EMAC_SUCCESS) {
+ ERR("Error %08X from Deinit()\n", ret_code);
+
+ /* we dont want to quit from here, lets delete
+ * the instance also */
+ }
+
+ /* delete the proc entry */
+ strcpy(proc_name, "davinci/");
+ strcat(proc_name, netdev->name);
+ proc_category_name_len = strlen(proc_name);
+ strcpy(proc_name + proc_category_name_len, "_rfc2665_stats");
+ remove_proc_entry(proc_name, NULL);
+
+ /* release memory region and unregister the device */
+ release_mem_region(netdev->base_addr, EMAC_DEFAULT_EMAC_SIZE);
+ unregister_netdev(netdev);
+
+ last_emac_device = dev->next_device;
+ if (netdev)
+ FREE_NETDEV(netdev);
+
+ emac_devices_installed--;
+ }
+
+ if (gp_stats_file)
+ remove_proc_entry("net/emac_stats", NULL);
+
+ remove_proc_entry("net/emac_link", NULL);
+ remove_proc_entry("net/emac_ver", NULL);
+ remove_proc_entry("net/emac_config", NULL);
+
+ platform_device_unregister(emac_dev);
+
+ printk("TI DAVINCI EMAC: platform device unregistered.\n");
+ driver_remove_file(&emac_driver, &driver_attr_version);
+ printk("TI DAVINCI EMAC: driver file removed.\n");
+ driver_unregister(&emac_driver);
+ printk("TI DAVINCI EMAC: driver unregistered.\n");
+}
+
+module_init(emac_dev_probe);
+module_exit(emac_exit);
diff --git a/drivers/net/davinci_emac_phy.c b/drivers/net/davinci_emac_phy.c
new file mode 100644
index 0000000..61c0917
--- /dev/null
+++ b/drivers/net/davinci_emac_phy.c
@@ -0,0 +1,745 @@
+/*
+ * linux/drivers/net/davinci_emac_phy.c
+ *
+ * EMAC MII-MDIO Module - Polling State Machine.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ Modifications:
+ * HISTORY:
+ * Date Modifier Notes
+ * 2001/02 Denis, Bill, Michael Original
+ * 14Feb2006 Anant Gole Re-written for linux
+ * 07Dec2006 Paul Bartholomew Fix half-duplex,
+ * use PHY_DUPLEX_* constants
+ */
+#include <linux/kernel.h>
+
+#include "davinci_emac_phy.h"
+
+#define EMAC_PHY_DEBUG
+
+#ifdef EMAC_PHY_DEBUG
+/* note: prints function name for you */
+#define DPRINTK(fmt, args...) if (emac_phy->debug_mode) printk(KERN_ERR "\n%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+/* Phy Registers */
+#define PHY_CONTROL_REG 0
+#define MII_PHY_RESET (1<<15)
+#define MII_PHY_LOOP (1<<14)
+#define MII_PHY_100 (1<<13)
+#define MII_AUTO_NEGOTIATE_EN (1<<12)
+#define MII_PHY_PDOWN (1<<11)
+#define MII_PHY_ISOLATE (1<<10)
+#define MII_RENEGOTIATE (1<<9)
+#define MII_PHY_FD (1<<8)
+
+#define PHY_STATUS_REG 1
+#define MII_NWAY_COMPLETE (1<<5)
+#define MII_NWAY_CAPABLE (1<<3)
+#define MII_PHY_LINKED (1<<2)
+
+#define NWAY_ADVERTIZE_REG 4
+#define NWAY_REMADVERTISE_REG 5
+#define MII_NWAY_FD100 (1<<8)
+#define MII_NWAY_HD100 (1<<7)
+#define MII_NWAY_FD10 (1<<6)
+#define MII_NWAY_HD10 (1<<5)
+#define MII_NWAY_SEL (1<<0)
+
+/* Timeout values - since timer tikc is expected to be 10 mSecs fixed these
+ * values are in (value * 10 mSecs) */
+#define PHY_FIND_TIMEOUT (2)
+#define PHY_RECK_TIMEOUT (200)
+#define PHY_LINK_TIMEOUT (500)
+#define PHY_NWST_TIMEOUT (500)
+#define PHY_NWDN_TIMEOUT (800)
+#define PHY_MDIX_TIMEOUT (274) /* 2.74 Seconds <--Spec and empirical */
+
+/* Mask & Control defines */
+#define MDIO_CONTROL_CLKDIV (0xFF)
+#define MDIO_CONTROL_ENABLE (1 << 30)
+#define MDIO_USERACCESS_GO (1 << 31)
+#define MDIO_USERACCESS_WRITE (1 << 30)
+#define MDIO_USERACCESS_READ (0 << 30)
+#define MDIO_USERACCESS_WRITE (1 << 30)
+#define MDIO_USERACCESS_REGADR (0x1F << 21)
+#define MDIO_USERACCESS_PHYADR (0x1F << 16)
+#define MDIO_USERACCESS_DATA (0xFFFF)
+#define MDIO_USERPHYSEL_LINKSEL (1 << 7)
+#define MDIO_VER_MODID (0xFFFF << 16)
+#define MDIO_VER_REVMAJ (0xFF << 8)
+#define MDIO_VER_REVMIN (0xFF)
+
+/* PHY Registers */
+#define MDIO_VER (0x00)
+#define MDIO_CONTROL (0x04)
+#define MDIO_ALIVE (0x08)
+#define MDIO_LINK (0x0C)
+#define MDIO_LINKINTRAW (0x10)
+#define MDIO_LINKINTMASKED (0x14)
+#define MDIO_USERINTRAW (0x20)
+#define MDIO_USERINTMASKED (0x24)
+#define MDIO_USERINTMASKED_SET (0x28)
+#define MDIO_USERINTMASKED_CLR (0x2C)
+#define MDIO_USERACCESS(inst) (0x80+(inst*8))
+#define MDIO_USERPHYSEL(inst) (0x84+(inst*8))
+
+#define MDIO_REG(reg) (*((volatile unsigned int *)(emac_phy->base + (reg))))
+
+#define MDIO_REG_VER MDIO_REG(MDIO_VER)
+#define MDIO_REG_CONTROL MDIO_REG(MDIO_CONTROL)
+#define MDIO_REG_ALIVE MDIO_REG(MDIO_ALIVE)
+#define MDIO_REG_LINK MDIO_REG(MDIO_LINK)
+#define MDIO_REG_LINKINTRAW MDIO_REG(MDIO_LINKINTRAW)
+#define MDIO_REG_LINKINTMASKED MDIO_REG(MDIO_LINKINTMASKED)
+#define MDIO_REG_USERINTMASKED MDIO_REG(MDIO_USERINTMASKED)
+#define MDIO_REG_USERINTMASKED_SET MDIO_REG(MDIO_USERINTMASKED_SET)
+#define MDIO_REG_USERINTMASKED_CLR MDIO_REG(MDIO_USERINTMASKED_CLR)
+#define MDIO_REG_USERACCESS MDIO_REG(MDIO_USERACCESS(emac_phy->inst))
+#define MDIO_REG_USERPHYSEL MDIO_REG(MDIO_USERPHYSEL(emac_phy->inst))
+
+/* Phy State */
+#define PHY_NULL (0)
+#define PHY_INIT (1)
+#define PHY_FINDING (2)
+#define PHY_FOUND (3)
+#define PHY_NWAY_START (4)
+#define PHY_NWAY_WAIT (5)
+#define PHY_LINK_WAIT (6)
+#define PHY_LINKED (7)
+#define PHY_LOOPBACK (8)
+
+static char *phy_state_str[] = {
+ "NULL", "INIT", "FINDING", "FOUND", "NWAY_START", "NWAY_WAIT",
+ "LINK_WAIT", "LINKED", "LOOPBACK"
+};
+
+#define PHY_NOT_FOUND 0xFFFF /* Used in Phy Detection */
+
+struct phy_info {
+ int inst; /* Instance of PHY - for user sel register */
+ unsigned int base; /* Base address of mdio module */
+ int state; /* state of phy */
+ int state_change; /* phy state change ? */
+ unsigned int timeout; /* Timeout counter */
+ unsigned int phy_mode; /* requested phy mode */
+ unsigned int speed; /* current Speed - 10 / 100 */
+ unsigned int duplex; /* 0=Auto Negotiate, Full=3; Half=2, Unknown=1 */
+ unsigned int phy_addr; /* phy address */
+ unsigned int phy_mask; /* phy mask */
+ unsigned int mlink_mask;/* mlink mask */
+ int debug_mode; /* debug mode */
+};
+
+/* Global phy structure instance */
+struct phy_info emac_phy_info;
+struct phy_info *emac_phy = &emac_phy_info;
+
+void emac_mdio_get_ver(unsigned int mdio_base, unsigned int *module_id,
+ unsigned int *rev_major, unsigned int *rev_minor)
+{
+ unsigned int ver;
+
+ emac_phy->base = mdio_base;
+ ver = MDIO_REG_VER;
+
+ *module_id = (ver & MDIO_VER_MODID) >> 16;
+ *rev_major = (ver & MDIO_VER_REVMAJ) >> 8;
+ *rev_minor = (ver & MDIO_VER_REVMIN);
+}
+
+/* Initialize mdio module */
+int emac_mdio_init(unsigned int mdio_base,
+ unsigned int inst,
+ unsigned int phy_mask,
+ unsigned int mlink_mask,
+ unsigned int mdio_bus_freq,
+ unsigned int mdio_clock_freq, unsigned int verbose)
+{
+ unsigned int clk_div;
+
+ /* Set base addr and init phy state */
+ emac_phy->inst = inst;
+ emac_phy->base = mdio_base;
+ emac_phy->phy_mask = phy_mask;
+ emac_phy->mlink_mask = mlink_mask;
+ emac_phy->state = PHY_INIT;
+ emac_phy->debug_mode = verbose;
+ emac_phy->speed = 10;
+ emac_phy->duplex = PHY_DUPLEX_HALF; /* Half duplex */
+
+ if (mdio_clock_freq & mdio_bus_freq) {
+ clk_div = ((mdio_bus_freq / mdio_clock_freq) - 1);
+ } else {
+ clk_div = 0xFF;
+ }
+ clk_div &= MDIO_CONTROL_CLKDIV;
+
+ /* Set enable and clock divider in MDIOControl */
+ MDIO_REG_CONTROL = (clk_div | MDIO_CONTROL_ENABLE);
+
+ return (0);
+}
+
+/* Set PHY mode - autonegotiation or any other */
+void emac_mdio_set_phy_mode(unsigned int phy_mode)
+{
+ emac_phy->phy_mode = phy_mode;
+
+ if ((emac_phy->state == PHY_NWAY_START) ||
+ (emac_phy->state == PHY_NWAY_WAIT) ||
+ (emac_phy->state == PHY_LINK_WAIT) ||
+ (emac_phy->state == PHY_LINKED) ||
+ (emac_phy->state == PHY_LOOPBACK)) {
+ emac_phy->state = PHY_FOUND;
+ emac_phy->state_change = 1;
+ }
+
+ DPRINTK("PhyMode:%08X Auto:%d, FD10:%d, HD10:%d, FD100:%d, HD100:%d\n",
+ phy_mode,
+ phy_mode & NWAY_AUTO, phy_mode & MII_NWAY_FD10,
+ phy_mode & MII_NWAY_HD10, phy_mode & MII_NWAY_FD100,
+ phy_mode & MII_NWAY_HD100);
+}
+
+/* Get linked status - check if link is on - 1=link on, 0=link off */
+int emac_mdio_is_linked(void)
+{
+ return ((emac_phy->state == PHY_LINKED) ? 1 : 0);
+}
+
+/* Get speed - 10 / 100 Mbps */
+int emac_mdio_get_speed(void)
+{
+ return (emac_phy->speed);
+}
+
+/* Get duplex - 0=Auto Negotiate, Full Duplex = 3; Half Duplex = 2 Unknown = 1 */
+int emac_mdio_get_duplex(void)
+{
+ return (emac_phy->duplex);
+}
+
+/* Get Phy number/address */
+int emac_mdio_get_phy_num(void)
+{
+ return (emac_phy->phy_addr);
+}
+
+/* Check if loopback enabled on phy */
+int emac_mdio_is_loopback(void)
+{
+ return ((emac_phy->state == PHY_LOOPBACK) ? 1 : 0);
+}
+
+/* Wait until mdio is ready for next command */
+#define MDIO_WAIT_FOR_USER_ACCESS while ((MDIO_REG_USERACCESS & MDIO_USERACCESS_GO) != 0) {}
+
+/* Read from a phy register via mdio interface */
+unsigned int emac_mdio_read(unsigned int phy_addr, unsigned int phy_reg)
+{
+ unsigned int phy_data = 0;
+ unsigned int phy_control;
+
+ /* Wait until mdio is ready for next command */
+ MDIO_WAIT_FOR_USER_ACCESS;
+
+ phy_control = (MDIO_USERACCESS_GO |
+ MDIO_USERACCESS_READ |
+ ((phy_reg << 21) & MDIO_USERACCESS_REGADR) |
+ ((phy_addr << 16) & MDIO_USERACCESS_PHYADR) |
+ (phy_data & MDIO_USERACCESS_DATA));
+ MDIO_REG_USERACCESS = phy_control;
+
+ /* Wait until mdio is ready for next command */
+ MDIO_WAIT_FOR_USER_ACCESS;
+
+ return (MDIO_REG_USERACCESS & MDIO_USERACCESS_DATA);
+}
+
+/* Write to a phy register via mdio interface */
+void emac_mdio_write(unsigned int phy_addr, unsigned int phy_reg,
+ unsigned int phy_data)
+{
+ unsigned int control;
+
+ /* Wait until mdio is ready for next command */
+ MDIO_WAIT_FOR_USER_ACCESS;
+
+ control = (MDIO_USERACCESS_GO |
+ MDIO_USERACCESS_WRITE |
+ ((phy_reg << 21) & MDIO_USERACCESS_REGADR) |
+ ((phy_addr << 16) & MDIO_USERACCESS_PHYADR) |
+ (phy_data & MDIO_USERACCESS_DATA));
+ MDIO_REG_USERACCESS = control;
+
+}
+
+/* Reset the selected phy */
+void emac_mdio_phy_reset(unsigned int phy_addr)
+{
+ unsigned int control;
+
+ emac_mdio_write(phy_addr, PHY_CONTROL_REG, MII_PHY_RESET);
+
+ do {
+ control = emac_mdio_read(phy_addr, PHY_CONTROL_REG);
+ } while (control & MII_PHY_RESET);
+
+ /* CRITICAL: Fix for increasing PHY signal drive strength for
+ * TX lockup issue. On DaVinci EVM, the Intel LXT971 PHY
+ * signal strength was low causing TX to fail randomly. The
+ * fix is to Set bit 11 (Increased MII drive strength) of PHY
+ * register 26 (Digital Config register) on this phy. */
+ control = emac_mdio_read(phy_addr, 26);
+ emac_mdio_write(phy_addr, 26, (control | 0x800));
+ control = emac_mdio_read(phy_addr, 26);
+}
+
+/* Timeout condition handler in PHY state machine */
+void emac_mdio_phy_timeout(void)
+{
+ emac_phy->state = PHY_FOUND;
+ emac_phy->state_change = 1;
+
+ /* If MDI/MDIX is supported then switch MDIX state */
+}
+
+/* PHY state machine : Init state handler */
+void emac_mdio_init_state(void)
+{
+ emac_phy->state = PHY_FINDING;
+ emac_phy->state_change = 1;
+ emac_phy->timeout = PHY_FIND_TIMEOUT;
+}
+
+/* PHY state machine : Finding state handler */
+void emac_mdio_finding_state(void)
+{
+ unsigned int phy_alive_status;
+ int i, j;
+
+ emac_phy->phy_addr = PHY_NOT_FOUND;
+
+ /* Find if timeout complete */
+ if (emac_phy->timeout) {
+ /* Allow some time for phy to show up in alive register */
+ --emac_phy->timeout;
+ } else {
+
+ phy_alive_status = MDIO_REG_LINK;
+ /* Check phys based upon user mask */
+ phy_alive_status &= emac_phy->phy_mask;
+
+ /* Find the first interesting alive phy */
+ for (i = 0, j = 1;
+ (i < 32) && ((j & phy_alive_status) == 0); i++, j <<= 1) ;
+
+ if ((phy_alive_status) && (i < 32)) {
+ emac_phy->phy_addr = i;
+ }
+
+ if (emac_phy->phy_addr != PHY_NOT_FOUND) {
+ DPRINTK("PHY Found. Phy Number=%d\n",
+ emac_phy->phy_addr);
+ emac_phy->state = PHY_FOUND;
+ emac_phy->state_change = 1;
+ } else {
+ /* Set Timer for finding timeout */
+ DPRINTK("PHY NOT Found. Starting timeout\n");
+ emac_phy->timeout = PHY_RECK_TIMEOUT;
+ }
+ }
+}
+
+/* PHY state machine : Found state handler */
+void emac_mdio_found_state(void)
+{
+ unsigned int phy_status;
+ unsigned int phy_num;
+ unsigned int cnt;
+ unsigned int nway_advertise;
+
+ /* Check if there is any phy mode requested by the user */
+ if (emac_phy->phy_mode == 0) {
+ return;
+ }
+
+ /* Check alive phy's */
+ phy_status = MDIO_REG_LINK;
+ phy_status &= emac_phy->phy_mask; /* Check phys based upon user mask */
+
+ /* we will now isolate all our phys, except the one we have decided to use */
+ for (phy_num = 0, cnt = 1; phy_num < 32; phy_num++, cnt <<= 1) {
+ if (phy_status & cnt) {
+ if (phy_num != emac_phy->phy_addr) {
+ /* Disable a phy that we are not using */
+ /* CRITICAL: Note that this code assums that there is only 1 phy connected
+ * if this is not the case then the next statement should be commented
+ */
+ emac_mdio_write(emac_phy->phy_addr,
+ PHY_CONTROL_REG,
+ (MII_PHY_ISOLATE |
+ MII_PHY_PDOWN));
+ }
+ }
+ }
+
+ /* Reset the Phy and proceed with auto-negotiation */
+ emac_mdio_phy_reset(emac_phy->phy_addr);
+
+ /* Set the way Link will be Monitored, Check the Link Selection Method */
+ if ((1 << emac_phy->phy_addr) & emac_phy->mlink_mask) {
+ MDIO_REG_USERPHYSEL =
+ (emac_phy->phy_addr | MDIO_USERPHYSEL_LINKSEL);
+ }
+
+ /* For Phy Internal loopback , need to wait until Phy found */
+ if (emac_phy->phy_mode & NWAY_LPBK) {
+ /* Set Phy in Loopback and read mdio to confirm */
+ emac_mdio_write(emac_phy->phy_addr, PHY_CONTROL_REG,
+ (MII_PHY_LOOP | MII_PHY_FD));
+ emac_mdio_read(emac_phy->phy_addr, PHY_STATUS_REG);
+ emac_phy->state = PHY_LOOPBACK;
+ emac_phy->state_change = 1;
+ return;
+ }
+
+ /* Start negotiation */
+ nway_advertise = MII_NWAY_SEL;
+ if (emac_phy->phy_mode & NWAY_FD100)
+ nway_advertise |= MII_NWAY_FD100;
+ if (emac_phy->phy_mode & NWAY_HD100)
+ nway_advertise |= MII_NWAY_HD100;
+ if (emac_phy->phy_mode & NWAY_FD10)
+ nway_advertise |= MII_NWAY_FD10;
+ if (emac_phy->phy_mode & NWAY_HD10)
+ nway_advertise |= MII_NWAY_HD10;
+
+ phy_status = emac_mdio_read(emac_phy->phy_addr, PHY_STATUS_REG);
+
+ if ((phy_status & MII_NWAY_CAPABLE) && (emac_phy->phy_mode & NWAY_AUTO)) {
+
+ /* NWAY Phy Detected - following procedure for NWAY compliant Phys */
+ emac_mdio_write(emac_phy->phy_addr, NWAY_ADVERTIZE_REG,
+ nway_advertise);
+ if (emac_phy->debug_mode) {
+ DPRINTK("NWAY Advertising: ");
+ if (nway_advertise & MII_NWAY_FD100)
+ DPRINTK("100 Mbps FullDuplex");
+ if (nway_advertise & MII_NWAY_HD100)
+ DPRINTK("100 Mbps HalfDuplex");
+ if (nway_advertise & MII_NWAY_FD10)
+ DPRINTK("10 Mbps FullDuplex");
+ if (nway_advertise & MII_NWAY_HD10)
+ DPRINTK("10 Mbps HalfDuplex");
+ DPRINTK("\n");
+ }
+
+ /* Start/Restart autonegotiation */
+ emac_mdio_write(emac_phy->phy_addr, PHY_CONTROL_REG,
+ MII_AUTO_NEGOTIATE_EN);
+ emac_mdio_write(emac_phy->phy_addr, PHY_CONTROL_REG,
+ (MII_AUTO_NEGOTIATE_EN | MII_RENEGOTIATE));
+ emac_phy->state = PHY_NWAY_START;
+ emac_phy->state_change = 1;
+ emac_phy->timeout = PHY_NWST_TIMEOUT;
+
+ } else {
+ /* Phy cannot do auto negotiation */
+ emac_phy->phy_mode &= ~NWAY_AUTO;
+ nway_advertise &= ~MII_NWAY_SEL;
+ phy_status = 0;
+
+ if (nway_advertise & (MII_NWAY_FD100 | MII_NWAY_HD100)) {
+ phy_status = MII_PHY_100; /* Set 100 Mbps if requested */
+ nway_advertise &= (MII_NWAY_FD100 | MII_NWAY_HD100);
+ } else {
+ nway_advertise &= (MII_NWAY_FD10 | MII_NWAY_HD10);
+ }
+
+ if (nway_advertise & (MII_NWAY_FD100 | MII_NWAY_FD10)) {
+ phy_status |= MII_PHY_FD; /* Set Full duplex if requested */
+ }
+
+ /* Set requested speed and duplex mode on phy */
+ emac_mdio_write(emac_phy->phy_addr, PHY_CONTROL_REG,
+ phy_status);
+
+ /* Set the phy speed and duplex mode */
+ emac_phy->speed = (phy_status & MII_PHY_100) ? 100 : 10;
+ emac_phy->duplex = (phy_status & MII_PHY_FD) ? 3 : 2;
+
+ emac_phy->state = PHY_LINK_WAIT;
+ emac_phy->state_change = 1;
+ emac_phy->timeout = PHY_LINK_TIMEOUT;
+ }
+
+ /* TODO: When Auto MDIX is supported, add delay here
+ emac_mdio_mdix_delay();
+ */
+}
+
+/* PHY state machine : NWAY Start state handler */
+void emac_mdio_nwaystart_state(void)
+{
+ unsigned int status;
+
+ status = emac_mdio_read(emac_phy->phy_addr, PHY_CONTROL_REG);
+ if ((status & MII_RENEGOTIATE) == 0) {
+ /* Flush pending latched bits */
+ status = emac_mdio_read(emac_phy->phy_addr, PHY_STATUS_REG);
+ emac_phy->state = PHY_NWAY_WAIT;
+ emac_phy->state_change = 1;
+ emac_phy->timeout = PHY_NWDN_TIMEOUT;
+ } else {
+ if (emac_phy->timeout) {
+ --emac_phy->timeout;
+ } else {
+ /* Timed Out for NWAY to start - very unlikely condition, back to Found */
+ emac_mdio_phy_timeout();
+ }
+ }
+}
+
+/* PHY state machine : NWAY Wait state handler */
+void emac_mdio_nwaywait_state(void)
+{
+ unsigned int status;
+ unsigned int my_cap, partner_cap, neg_mode;
+
+ /* Check if nway negotiation complete */
+ status = emac_mdio_read(emac_phy->phy_addr, PHY_STATUS_REG);
+
+ if (status & MII_NWAY_COMPLETE) {
+ /* negotiation complete, check for partner capabilities */
+ emac_phy->state_change = 1;
+ my_cap = emac_mdio_read(emac_phy->phy_addr, NWAY_ADVERTIZE_REG);
+ partner_cap =
+ emac_mdio_read(emac_phy->phy_addr, NWAY_REMADVERTISE_REG);
+
+ /* Negotiated mode is what we and partnet have in common */
+ neg_mode = my_cap & partner_cap;
+ if (emac_phy->debug_mode) {
+ DPRINTK
+ ("Phy %d, neg_mode %04X, my_cap %04X, partner_cap %04X\n",
+ emac_phy->phy_addr, neg_mode, my_cap, partner_cap);
+ }
+
+ /* Limit negotiation to fields below */
+ neg_mode &=
+ (MII_NWAY_FD100 | MII_NWAY_HD100 | MII_NWAY_FD10 |
+ MII_NWAY_HD10);
+ if (neg_mode == 0)
+ DPRINTK
+ ("WARNING: Negotiation complete but NO agreement, default is 10HD\n");
+
+ if (neg_mode & MII_NWAY_FD100)
+ DPRINTK("100 Mbps FullDuplex");
+ if (neg_mode & MII_NWAY_HD100)
+ DPRINTK("100 Mbps HalfDuplex");
+ if (neg_mode & MII_NWAY_FD10)
+ DPRINTK("10 Mbps FullDuplex");
+ if (neg_mode & MII_NWAY_HD10)
+ DPRINTK("10 Mbps HalfDuplex");
+ DPRINTK("\n");
+
+ if (neg_mode != 0) {
+ if (status & MII_PHY_LINKED) {
+ emac_phy->state = PHY_LINKED;
+ } else {
+ emac_phy->state = PHY_LINK_WAIT;
+ }
+ }
+
+ /* Set the phy speed and duplex mode */
+ emac_phy->speed =
+ (neg_mode & (MII_NWAY_FD100 | MII_NWAY_HD100)) ? 100 : 10;
+ emac_phy->duplex =
+ (neg_mode & (MII_NWAY_FD100 | MII_NWAY_FD10)) ?
+ PHY_DUPLEX_FULL : PHY_DUPLEX_HALF;
+
+ } else {
+
+ if (emac_phy->timeout) {
+ --emac_phy->timeout;
+ } else {
+ /* Timed Out for NWAY to start - very unlikely condition, back to Found */
+ emac_mdio_phy_timeout();
+ }
+ }
+}
+
+/* PHY state machine : Link Wait state handler */
+void emac_mdio_linkwait_state(void)
+{
+ unsigned int status;
+
+ /* Check if nway negotiation complete */
+ status = emac_mdio_read(emac_phy->phy_addr, PHY_STATUS_REG);
+ if (status & MII_PHY_LINKED) {
+ emac_phy->state = PHY_LINKED;
+ emac_phy->state_change = 1;
+ } else {
+ if (emac_phy->timeout) {
+ --emac_phy->timeout;
+ } else {
+ /* Timed Out for link - very unlikely condition, back to Found */
+ emac_mdio_phy_timeout();
+ }
+ }
+}
+
+/* PHY state machine : Linked handler */
+void emac_mdio_linked_state(void)
+{
+ if (MDIO_REG_LINK & (1 << emac_phy->phy_addr)) {
+ return; /* do nothing if already linked */
+ }
+
+ /* If not linked, move mode to nway down or waiting for link */
+ emac_phy->state_change = 1;
+ if (emac_phy->phy_mode & NWAY_AUTO) {
+ emac_phy->state = PHY_NWAY_WAIT;
+ emac_phy->timeout = PHY_NWDN_TIMEOUT;
+ } else {
+ emac_phy->state = PHY_LINK_WAIT;
+ emac_phy->timeout = PHY_LINK_TIMEOUT;
+ }
+
+ /* TODO: When Auto MDIX is supported, add delay here
+ emac_mdio_mdix_delay();
+ */
+}
+
+/* PHY state machine : Loopback handler */
+void emac_mdio_loopback_state(void)
+{
+ return;
+}
+
+/* PHY state machine : Default handler */
+void emac_mdio_default_state(void)
+{
+ /* Awaiting a init call */
+ emac_phy->state_change = 1;
+}
+
+/* Detailed PHY dump for debug */
+void emac_mdio_phy_dump(void)
+{
+ unsigned int status;
+
+ DPRINTK("\n");
+ DPRINTK("PHY Addr/Num=%d, PHY State=%s, Speed=%d, Duplex=%d\n",
+ emac_phy->phy_addr, phy_state_str[emac_phy->state],
+ emac_phy->speed, emac_phy->duplex);
+
+ /* 0: Control register */
+ status = emac_mdio_read(emac_phy->phy_addr, PHY_CONTROL_REG);
+ DPRINTK("PhyControl: %04X, Loopback=%s, Speed=%s, Duplex=%s\n",
+ status,
+ status & MII_PHY_LOOP ? "On" : "Off",
+ status & MII_PHY_100 ? "100" : "10",
+ status & MII_PHY_FD ? "Full" : "Half");
+
+ /* 1: Status register */
+ status = emac_mdio_read(emac_phy->phy_addr, PHY_STATUS_REG);
+ DPRINTK("PhyStatus: %04X, AutoNeg=%s, Link=%s\n",
+ status,
+ status & MII_NWAY_COMPLETE ? "Complete" : "NotComplete",
+ status & MII_PHY_LINKED ? "Up" : "Down");
+
+ /* 4: Auto Negotiation Advertisement register */
+ status = emac_mdio_read(emac_phy->phy_addr, NWAY_ADVERTIZE_REG);
+ DPRINTK("PhyMyCapability: %04X, 100FD=%s, 100HD=%s, 10FD=%s, 10HD=%s\n",
+ status,
+ status & MII_NWAY_FD100 ? "Yes" : "No",
+ status & MII_NWAY_HD100 ? "Yes" : "No",
+ status & MII_NWAY_FD10 ? "Yes" : "No",
+ status & MII_NWAY_HD10 ? "Yes" : "No");
+
+ /* 5: Auto Negotiation Advertisement register */
+ status = emac_mdio_read(emac_phy->phy_addr, NWAY_REMADVERTISE_REG);
+ DPRINTK
+ ("PhyPartnerCapability: %04X, 100FD=%s, 100HD=%s, 10FD=%s, 10HD=%s\n",
+ status, status & MII_NWAY_FD100 ? "Yes" : "No",
+ status & MII_NWAY_HD100 ? "Yes" : "No",
+ status & MII_NWAY_FD10 ? "Yes" : "No",
+ status & MII_NWAY_HD10 ? "Yes" : "No");
+}
+
+/* emac_mdio_tick is called every 10 mili seconds to process Phy states */
+int emac_mdio_tick(void)
+{
+
+ switch (emac_phy->state) {
+
+ case PHY_INIT:
+ emac_mdio_init_state();
+ break;
+
+ case PHY_FINDING:
+ emac_mdio_finding_state();
+ break;
+
+ case PHY_FOUND:
+ emac_mdio_found_state();
+ break;
+
+ case PHY_NWAY_START:
+ emac_mdio_nwaystart_state();
+ break;
+
+ case PHY_NWAY_WAIT:
+ emac_mdio_nwaywait_state();
+ break;
+
+ case PHY_LINK_WAIT:
+ emac_mdio_linkwait_state();
+ break;
+
+ case PHY_LINKED:
+ emac_mdio_linked_state();
+ break;
+
+ case PHY_LOOPBACK:
+ emac_mdio_loopback_state();
+ break;
+
+ default:
+ emac_mdio_default_state();
+ break;
+ }
+
+ /* Check is MDI/MDIX mode switch is needed - not supported in DaVinci hardware */
+
+ /* Return state change to user */
+ if (emac_phy->state_change) {
+ emac_mdio_phy_dump();
+ emac_phy->state_change = 0;
+ return (1);
+ } else {
+ return (0);
+ }
+}
diff --git a/drivers/net/davinci_emac_phy.h b/drivers/net/davinci_emac_phy.h
new file mode 100644
index 0000000..3d5ba73
--- /dev/null
+++ b/drivers/net/davinci_emac_phy.h
@@ -0,0 +1,103 @@
+/*
+ * linux/drivers/net/davinci_emac_phy.h
+ *
+ * MDIO Polling State Machine API. Functions will enable mii-Phy
+ * negotiation.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ * Modifications:
+ * HISTORY:
+ * Date Modifier Ver Notes
+ * 01Jan01 Denis, Bill Original
+ * 27Mar02 Michael Hanrahan Original (modified from emacmdio.h)
+ * 04Apr02 Michael Hanrahan Added Interrupt Support
+ * 07Dec06 Paul Bartholomew Added PHY_DUPLEX_* defines
+ */
+#ifndef _DAVINCI_EMAC_PHY_H_
+#define _DAVINCI_EMAC_PHY_H_
+
+/* phy mode values */
+#define NWAY_AUTOMDIX (1<<16)
+#define NWAY_FD1000 (1<<13)
+#define NWAY_HD1000 (1<<12)
+#define NWAY_NOPHY (1<<10)
+#define NWAY_LPBK (1<<9)
+#define NWAY_FD100 (1<<8)
+#define NWAY_HD100 (1<<7)
+#define NWAY_FD10 (1<<6)
+#define NWAY_HD10 (1<<5)
+#define NWAY_AUTO (1<<0)
+
+/* phy duplex values */
+#define PHY_DUPLEX_AUTO 0 /* Auto Negotiate */
+#define PHY_DUPLEX_UNKNOWN 1 /* Unknown */
+#define PHY_DUPLEX_HALF 2 /* Half Duplex */
+#define PHY_DUPLEX_FULL 3 /* Full Duplex */
+
+/*
+ * Tic() return values
+ */
+
+#define _MIIMDIO_MDIXFLIP (1<<28)
+
+#define _AUTOMDIX_DELAY_MIN 80 /* milli-seconds */
+#define _AUTOMDIX_DELAY_MAX 200 /* milli-seconds */
+
+/* Get module version */
+void emac_mdio_get_ver(unsigned int mdio_base, unsigned int *module_id,
+ unsigned int *rev_major, unsigned int *rev_minor);
+
+/* Initialize mdio module */
+int emac_mdio_init(unsigned int mdio_base,
+ unsigned int inst,
+ unsigned int phy_mask,
+ unsigned int mlink_mask,
+ unsigned int mdio_bus_freq,
+ unsigned int mdio_clock_freq, unsigned int verbose);
+
+/* Set PHY mode - autonegotiation or any other */
+void emac_mdio_set_phy_mode(unsigned int phy_mode);
+
+/* Get linked status - check if link is on - 1=link on, 0=link off */
+int emac_mdio_is_linked(void);
+
+/* Get speed - 10 / 100 Mbps */
+int emac_mdio_get_speed(void);
+
+/* Get duplex - 2=full duplex, 1=half duplex */
+int emac_mdio_get_duplex(void);
+
+/* Get Phy number/address */
+int emac_mdio_get_phy_num(void);
+
+/* Check if loopback enabled on phy */
+int emac_mdio_is_loopback(void);
+
+/* Read from a phy register via mdio interface */
+unsigned int emac_mdio_read(unsigned int phy_addr, unsigned int phy_reg);
+
+/* Write to a phy register via mdio interface */
+void emac_mdio_write(unsigned int phy_addr, unsigned int phy_reg,
+ unsigned int phy_data);
+
+/* MDIO tick function - to be called every 10 mSecs */
+int emac_mdio_tick(void);
+
+#endif /* _DAVINIC_EMAC_PHY_H_ */
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index c0d86bb..26d7026 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -122,6 +122,15 @@
if I2C
+config RTC_DRV_DAVINCI_EVM
+ tristate "TI DaVinci EVM RTC"
+ depends on RTC_CLASS && I2C_DAVINCI && MACH_DAVINCI_EVM
+ help
+ Supports the RTC firmware in the MSP430 on the DaVinci EVM.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-davinci-evm.
+
config RTC_DRV_DS1307
tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00"
help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 544fe4d..40c575f 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -21,6 +21,7 @@
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
+obj-$(CONFIG_RTC_DRV_DAVINCI_EVM) += rtc-davinci-evm.o
obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
diff --git a/drivers/rtc/rtc-davinci-evm.c b/drivers/rtc/rtc-davinci-evm.c
new file mode 100644
index 0000000..c825308
--- /dev/null
+++ b/drivers/rtc/rtc-davinci-evm.c
@@ -0,0 +1,270 @@
+/*
+ * rtc-davinci-evm.c
+ *
+ * Copyright (C) 2004 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/arch/i2c-client.h>
+
+
+/* REVISIT
+ * - the firmware expects no I2C writes at all, not just no RTC-via-I2C
+ * writes, for 100 usec after i2c read or write... that can't be
+ * assured here.
+ *
+ * - this am vs pm thing is bizarre ... firmware should just do a 24 hour
+ * clock, rather than 12 hour with hidden am/pm (we must guess).
+ * similarly with it trying to handle DST for us...
+ *
+ * - better (and simpler!!) firmware would support an RTC alarm, and just
+ * count seconds since some UTC instant, letting Linux handle calendar
+ * issues (leapyear, day of week, etc) and DST.
+ */
+static unsigned char am;
+
+
+static int evm_read_time(struct device *dev, struct rtc_time *tm)
+{
+ char rtcdata [9];
+
+ rtcdata[0] = 2;
+ rtcdata[1] = 1;
+ davinci_i2c_write(2, rtcdata, 0x23);
+
+ msleep(1);
+ davinci_i2c_read(9, rtcdata, 0x23);
+ msleep(1);
+
+ /* FIXME the RTC reports 12-hour time, without an AM/PM indicator,
+ * but Linux requires that we report 24 hour time...
+ */
+
+ tm->tm_year = BCD_TO_BIN(rtcdata[3]) * 100
+ + BCD_TO_BIN(rtcdata[2])
+ - 1900;
+ tm->tm_mon = BCD_TO_BIN(rtcdata[4]);
+ tm->tm_mday = BCD_TO_BIN(rtcdata[5]);
+ tm->tm_hour = BCD_TO_BIN(rtcdata[6]);
+ tm->tm_min = BCD_TO_BIN(rtcdata[7]);
+ tm->tm_sec = BCD_TO_BIN(rtcdata[8]);
+
+ return 0;
+}
+
+static void am_or_pm(struct device *dev)
+{
+ char rtcdata [9];
+ struct rtc_time tm, time, temp;
+ unsigned char mon, day, hrs, min, sec;
+ unsigned char yr_low, yr_high;
+ unsigned int yrs;
+
+ evm_read_time(dev, &tm);
+
+ temp = tm;
+
+ yrs = temp.tm_year + 1900;
+ yr_high = yrs / 100;
+ yr_low = yrs % 100;
+
+ mon = temp.tm_mon + 1;
+ day = temp.tm_mday;
+ min = 59;
+ sec = 59;
+ hrs = 11;
+
+ rtcdata [0] = 9;
+ rtcdata [1] = 0;
+ rtcdata [2] = BIN_TO_BCD(yr_low);
+ rtcdata [3] = BIN_TO_BCD(yr_high);
+ mon--;
+ rtcdata [4] = BIN_TO_BCD(mon);
+ rtcdata [5] = BIN_TO_BCD(day);
+ rtcdata [6] = BIN_TO_BCD(hrs);
+ rtcdata [7] = BIN_TO_BCD(min);
+ rtcdata [8] = BIN_TO_BCD(sec);
+ davinci_i2c_write(9, rtcdata, 0x23);
+ msleep(1);
+ msleep(1000);
+ evm_read_time(dev, &time);
+
+ if (time.tm_mday == temp.tm_mday)
+ am = 1;
+ else
+ am = 0;
+
+ davinci_i2c_write(9, rtcdata, 0x23);
+ msleep(1);
+ msleep(1000);
+
+ yrs = tm.tm_year + 1900;
+ yr_high = yrs / 100;
+ yr_low = yrs % 100;
+
+ mon = tm.tm_mon + 1;
+ day = tm.tm_mday;
+ min = tm.tm_min;
+ hrs = tm.tm_hour;
+
+ if (tm.tm_sec < 58)
+ sec = tm.tm_sec + 2;
+ else
+ sec = 59;
+
+ davinci_i2c_write(9, rtcdata, 0x23);
+ msleep(1);
+}
+
+static int evm_set_time(struct device *dev, struct rtc_time *tm)
+{
+ char rtcdata [9];
+ char ampmdata [9];
+ unsigned char mon, day, hrs = 0, min, sec, leap_yr;
+ unsigned char yr_low, yr_high;
+ unsigned int yrs;
+
+ am_or_pm(dev);
+
+ yrs = tm->tm_year + 1900;
+ yr_high = yrs / 100;
+ yr_low = yrs % 100;
+
+ mon = tm->tm_mon;
+ hrs = tm->tm_hour;
+ day = tm->tm_mday;
+ min = tm->tm_min;
+ sec = tm->tm_sec;
+
+ leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
+
+ if (am == 1 && tm->tm_hour <= 12) {
+ hrs = tm->tm_hour;
+ if (tm->tm_hour == 0)
+ hrs = tm->tm_hour + 12;
+
+ } else if ((am == 1 && tm->tm_hour > 12)
+ || (am == 0 && tm->tm_hour < 12)) {
+ unsigned char mon1 = mon, day1 = day, hrs1 = 11;
+ unsigned char min1 = 59, sec1 = 59;
+ unsigned char yr_low1 = yr_low, yr_high1 = yr_high;
+
+ ampmdata [0] = 9;
+ ampmdata [1] = 0;
+ ampmdata [2] = BIN_TO_BCD(yr_low1);
+ ampmdata [3] = BIN_TO_BCD(yr_high1);
+ ampmdata [4] = BIN_TO_BCD(mon1);
+ ampmdata [5] = BIN_TO_BCD(day1);
+ ampmdata [6] = BIN_TO_BCD(hrs1);
+ ampmdata [7] = BIN_TO_BCD(min1);
+ ampmdata [8] = BIN_TO_BCD(sec1);
+ davinci_i2c_write(9, ampmdata, 0x23);
+ msleep(1);
+ msleep(1000);
+ am = (am == 1) ? 0 : 1;
+
+ if (!am)
+ hrs = tm->tm_hour - 12;
+ else if (tm->tm_hour == 0)
+ hrs = tm->tm_hour + 12;
+
+ } else if (am == 0 && tm->tm_hour > 12)
+ hrs = tm->tm_hour - 12;
+
+ rtcdata [0] = 9;
+ rtcdata [1] = 0;
+ rtcdata [2] = BIN_TO_BCD(yr_low);
+ rtcdata [3] = BIN_TO_BCD(yr_high);
+ rtcdata [4] = BIN_TO_BCD(mon);
+ rtcdata [5] = BIN_TO_BCD(day);
+ rtcdata [6] = BIN_TO_BCD(hrs);
+ rtcdata [7] = BIN_TO_BCD(min);
+ rtcdata [8] = BIN_TO_BCD(sec);
+
+ davinci_i2c_write(9, rtcdata, 0x23);
+ msleep(1);
+
+ return 0;
+}
+
+static struct rtc_class_ops evm_rtc_ops = {
+ .read_time = evm_read_time,
+ .set_time = evm_set_time,
+};
+
+static int __devinit evm_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+
+ /* the 2005-12-05 firmware doesn't issue RTC alarms on GPIO(7);
+ * it only uses IRQ for card detect irqs with removable media.
+ * plus it also hides the am/pm indicator and does magic DST...
+ */
+ rtc = rtc_device_register(pdev->name, &pdev->dev,
+ &evm_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ dev_warn(&pdev->dev, "WARNING: hours 12-23 are misreported as "
+ "duplicate hours 00-11\n");
+
+ platform_set_drvdata(pdev, rtc);
+ return 0;
+}
+
+static int __devexit evm_rtc_remove(struct platform_device *pdev)
+{
+ rtc_device_unregister(platform_get_drvdata(pdev));
+ return 0;
+}
+
+static struct platform_driver evm_rtc_driver = {
+ .driver = {
+ .name = "rtc_davinci_evm",
+ },
+ .probe = evm_rtc_probe,
+ .remove = __devexit_p(evm_rtc_remove),
+};
+
+static int evm_rtc_init(void)
+{
+ if (!machine_is_davinci_evm())
+ return -ENODEV;
+
+ return platform_driver_register(&evm_rtc_driver);
+}
+module_init(evm_rtc_init);
+
+static void evm_rtc_exit(void)
+{
+ platform_driver_unregister(&evm_rtc_driver);
+}
+module_exit(evm_rtc_exit);
+
+MODULE_DESCRIPTION("RTC driver for TI DaVinci EVM");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 5216c11..0dfea58 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1801,6 +1801,18 @@
Say Y here to enable support for the IBM GXT4500P display
adaptor, found on some IBM System P (pSeries) machines.
+config FB_DAVINCI
+ bool "Davinci Framebuffer support"
+ depends on FB && ARCH_DAVINCI
+ help
+ This is the frame buffer device driver for the DaVinci video
+ hardware found on the TI DaVinci EVM. If
+ unsure, say N.
+
+config FB_VIRTUAL
+ tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
+ depends on FB
+
config FB_PS3
tristate "PS3 GPU framebuffer driver"
depends on FB && PS3_PS3AV
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index b4668d7..5f2aeb4 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -120,6 +120,7 @@
obj-$(CONFIG_FB_VGA16) += vga16fb.o
obj-$(CONFIG_FB_OF) += offb.o
obj-$(CONFIG_FB_OMAP) += omap/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
+obj-$(CONFIG_FB_DAVINCI) += davincifb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
# the test framebuffer is last
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
diff --git a/drivers/video/davincifb.c b/drivers/video/davincifb.c
new file mode 100644
index 0000000..49f86cc
--- /dev/null
+++ b/drivers/video/davincifb.c
@@ -0,0 +1,1734 @@
+/*
+ * drivers/video/davincifb.c
+ *
+ * Framebuffer driver for Texas Instruments DaVinci display controller.
+ *
+ * Copyright (C) 2006 Texas Instruments, Inc.
+ * Rishi Bhattacharya <support@ti.com>
+ *
+ * Leveraged from the framebuffer driver for OMAP24xx
+ * written by Andy Lowe (source@mvista.com)
+ * Copyright (C) 2004 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/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.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/platform_device.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include <video/davincifb.h>
+#include <asm/system.h>
+
+#define MODULE_NAME "davincifb"
+
+/* Output Format Selection */
+#define MULTIPLE_BUFFERING 1
+
+#ifdef MULTIPLE_BUFFERING
+#define DOUBLE_BUF 2
+#define TRIPLE_BUF 3
+#else
+#define DOUBLE_BUF 1
+#define TRIPLE_BUF 1
+#endif
+
+/*
+ * display controller register I/O routines
+ */
+static __inline__ u32 dispc_reg_in(u32 offset)
+{
+ return (inl(offset));
+}
+static __inline__ u32 dispc_reg_out(u32 offset, u32 val)
+{
+ outl(val, offset);
+ return (val);
+}
+static __inline__ u32 dispc_reg_merge(u32 offset, u32 val, u32 mask)
+{
+ u32 addr = offset;
+ u32 new_val = (inl(addr) & ~mask) | (val & mask);
+ outl(new_val, addr);
+ return (new_val);
+}
+
+/* There are 4 framebuffers, each represented by an fb_info and
+ * a dm_win_info structure */
+#define OSD0_FBNAME "dm_osd0_fb"
+#define OSD1_FBNAME "dm_osd1_fb"
+#define VID0_FBNAME "dm_vid0_fb"
+#define VID1_FBNAME "dm_vid1_fb"
+
+/* usage: if (is_win(info->fix.id, OSD0)) ... */
+#define is_win(name, x) ((strcmp(name, x ## _FBNAME) == 0) ? 1 : 0)
+
+struct dm_win_info {
+ struct fb_info info;
+
+ /* X and Y position */
+ unsigned int x, y;
+
+ /* framebuffer area */
+ dma_addr_t fb_base_phys;
+ unsigned long fb_base;
+ unsigned long fb_size;
+
+ u32 pseudo_palette[17];
+
+ /* flag to identify if framebuffer area is fixed already or not */
+ int alloc_fb_mem;
+ unsigned long sdram_address;
+ struct dm_info *dm;
+};
+
+static struct dm_info {
+ struct dm_win_info *osd0;
+ struct dm_win_info *osd1;
+ struct dm_win_info *vid0;
+ struct dm_win_info *vid1;
+
+ /* to map the registers */
+ dma_addr_t mmio_base_phys;
+ unsigned long mmio_base;
+ unsigned long mmio_size;
+
+ wait_queue_head_t vsync_wait;
+ unsigned long vsync_cnt;
+ int timeout;
+
+ /* this is the function that configures the output device (NTSC/PAL/LCD)
+ * for the required output format (composite/s-video/component/rgb)
+ */
+ void (*output_device_config) (int on);
+
+ struct device *dev;
+} dm_static;
+static struct dm_info *dm = &dm_static;
+
+static struct fb_ops davincifb_ops;
+
+#define BASEX 0x80
+#define BASEY 0x12
+
+#define DISP_XRES 720
+#define DISP_YRES 480
+#define DISP_MEMY 576
+
+/* Random value chosen for now. Should be within the panel's supported range */
+#define LCD_PANEL_CLOCK 180000
+
+/* All window widths have to be rounded up to a multiple of 32 bytes */
+
+/* The OSD0 window has to be always within VID0. Plus, since it is in RGB565
+ * mode, it _cannot_ overlap with VID1.
+ * For defaults, we are setting the OSD0 window to be displayed in the top
+ * left quadrant of the screen, and the VID1 in the bottom right quadrant.
+ * So the default 'xres' and 'yres' are set to half of the screen width and
+ * height respectively. Note however that the framebuffer size is allocated
+ * for the full screen size so the user can change the 'xres' and 'yres' by
+ * using the FBIOPUT_VSCREENINFO ioctl within the limits of the screen size.
+ */
+#define round_32(width) ((((width) + 31) / 32) * 32 )
+
+#define OSD0_XRES round_32((DISP_XRES)*16/8) * 8/16 /* pixels */
+#define OSD0_YRES DISP_YRES
+#define OSD0_FB_PHY 0
+#define OSD0_FB_SIZE (round_32((DISP_XRES)*16/8) * DISP_MEMY * DOUBLE_BUF)
+
+ /* 16 bpp, Double buffered */
+static struct fb_var_screeninfo osd0_default_var = {
+ .xres = OSD0_XRES,
+ .yres = OSD0_YRES,
+ .xres_virtual = OSD0_XRES,
+ .yres_virtual = OSD0_YRES * DOUBLE_BUF,
+ .xoffset = 0,
+ .yoffset = 0,
+ .bits_per_pixel = 16,
+ .grayscale = 0,
+ .red = {11, 5, 0},
+ .green = {5, 6, 0},
+ .blue = {0, 5, 0},
+ .transp = {0, 0, 0},
+ .nonstd = 0,
+ .activate = FB_ACTIVATE_NOW,
+ .height = -1,
+ .width = -1,
+ .accel_flags = 0,
+ .pixclock = LCD_PANEL_CLOCK, /* picoseconds */
+ .left_margin = 40, /* pixclocks */
+ .right_margin = 4, /* pixclocks */
+ .upper_margin = 8, /* line clocks */
+ .lower_margin = 2, /* line clocks */
+ .hsync_len = 4, /* pixclocks */
+ .vsync_len = 2, /* line clocks */
+ .sync = 0,
+ .vmode = FB_VMODE_INTERLACED,
+};
+
+/* Using the full screen for OSD1 by default */
+#define OSD1_XRES round_32(DISP_XRES*4/8) * 8/4 /* pixels */
+#define OSD1_YRES DISP_YRES
+#define OSD1_FB_PHY 0
+#define OSD1_FB_SIZE (round_32(DISP_XRES*4/8) * DISP_MEMY * DOUBLE_BUF)
+
+static struct fb_var_screeninfo osd1_default_var = {
+ .xres = DISP_XRES,
+ .yres = OSD1_YRES,
+ .xres_virtual = OSD1_XRES,
+ .yres_virtual = OSD1_YRES * DOUBLE_BUF,
+ .xoffset = 0,
+ .yoffset = 0,
+ .bits_per_pixel = 4,
+ .activate = FB_ACTIVATE_NOW,
+ .accel_flags = 0,
+ .pixclock = LCD_PANEL_CLOCK, /* picoseconds */
+ .vmode = FB_VMODE_INTERLACED,
+};
+
+/* Using the full screen for OSD0 by default */
+#define VID0_XRES round_32(DISP_XRES*16/8) * 8/16 /* pixels */
+#define VID0_YRES DISP_YRES
+#define VID0_FB_PHY 0
+#define VID0_FB_SIZE (round_32(DISP_XRES*16/8) * DISP_MEMY * TRIPLE_BUF)
+static struct fb_var_screeninfo vid0_default_var = {
+ .xres = VID0_XRES,
+ .yres = VID0_YRES,
+ .xres_virtual = VID0_XRES,
+ .yres_virtual = VID0_YRES * TRIPLE_BUF,
+ .xoffset = 0,
+ .yoffset = 0,
+ .bits_per_pixel = 16,
+ .activate = FB_ACTIVATE_NOW,
+ .accel_flags = 0,
+ .pixclock = LCD_PANEL_CLOCK, /* picoseconds */
+ .vmode = FB_VMODE_INTERLACED,
+};
+
+/* Using the bottom right quadrant of the screen screen for VID1 by default,
+ * but keeping the framebuffer allocated for the full screen, so the user can
+ * change the 'xres' and 'yres' later using the FBIOPUT_VSCREENINFO ioctl.
+ */
+#define VID1_BPP 16 /* Video1 can be in YUV or RGB888 format */
+#define VID1_XRES round_32(DISP_XRES*16/8) * 8/16 /* pixels */
+#define VID1_YRES DISP_YRES
+#define VID1_FB_PHY 0
+#define VID1_FB_SIZE (round_32(DISP_XRES*16/8) * DISP_MEMY * TRIPLE_BUF)
+static struct fb_var_screeninfo vid1_default_var = {
+ .xres = VID1_XRES,
+ .yres = VID1_YRES,
+ .xres_virtual = VID1_XRES,
+ .yres_virtual = VID1_YRES * TRIPLE_BUF,
+ .xoffset = 0,
+ .yoffset = 0,
+ .bits_per_pixel = VID1_BPP,
+ .activate = FB_ACTIVATE_NOW,
+ .accel_flags = 0,
+ .pixclock = LCD_PANEL_CLOCK, /* picoseconds */
+ .vmode = FB_VMODE_INTERLACED,
+};
+
+#define x_pos(w) ((w)->x)
+#define y_pos(w) ((w)->y)
+
+static struct dmparams_t {
+ u8 output;
+ u8 format;
+ u8 windows; /* bitmap flag based on VID0, VID1, OSD0, OSD1
+ * definitions in header file */
+ u32 vid0_xres;
+ u32 vid0_yres;
+ u32 vid0_xpos;
+ u32 vid0_ypos;
+
+ u32 vid1_xres;
+ u32 vid1_yres;
+ u32 vid1_xpos;
+ u32 vid1_ypos;
+
+ u32 osd0_xres;
+ u32 osd0_yres;
+ u32 osd0_xpos;
+ u32 osd0_ypos;
+
+ u32 osd1_xres;
+ u32 osd1_yres;
+ u32 osd1_xpos;
+ u32 osd1_ypos;
+} dmparams = {
+ NTSC, /* output */
+ COMPOSITE, /* format */
+ (1 << VID0) | (1 << VID1) | (1 << OSD0) | (1 << OSD1),
+ /* windows registered */
+ 720, 480, 0, 0, /* vid0 size and position */
+ 720, 480, 0, 0, /* vid1 size and position */
+ 720, 480, 0, 0, /* osd0 size and position */
+ 720, 480, 0, 0, /* osd1 size and position */
+};
+
+/* Must do checks against the limits of the output device */
+static int davincifb_venc_check_mode(const struct dm_win_info *w,
+ const struct fb_var_screeninfo *var)
+{
+ return 0;
+}
+
+static void set_sdram_params(char *id, u32 addr, u32 line_length);
+static irqreturn_t davincifb_isr(int irq, void *arg)
+{
+ struct dm_info *dm = (struct dm_info *)arg;
+ unsigned long addr=0;
+
+ if ((dispc_reg_in(VENC_VSTAT) & 0x00000010) == 0x10) {
+ xchg(&addr, dm->osd0->sdram_address);
+ if (addr) {
+ set_sdram_params(dm->osd0->info.fix.id,
+ dm->osd0->sdram_address,
+ dm->osd0->info.fix.line_length);
+ dm->osd0->sdram_address = 0;
+ }
+ addr = 0;
+ xchg(&addr, dm->osd1->sdram_address);
+ if (addr) {
+ set_sdram_params(dm->osd1->info.fix.id,
+ dm->osd1->sdram_address,
+ dm->osd1->info.fix.line_length);
+ dm->osd1->sdram_address = 0;
+ }
+ addr = 0;
+ xchg(&addr, dm->vid0->sdram_address);
+ if (addr) {
+ set_sdram_params(dm->vid0->info.fix.id,
+ dm->vid0->sdram_address,
+ dm->vid0->info.fix.line_length);
+ dm->vid0->sdram_address = 0;
+ }
+ addr = 0;
+ xchg(&addr, dm->vid1->sdram_address);
+ if (addr) {
+ set_sdram_params(dm->vid1->info.fix.id,
+ dm->vid1->sdram_address,
+ dm->vid1->info.fix.line_length);
+ dm->vid1->sdram_address = 0;
+ }
+ return IRQ_HANDLED;
+ } else {
+ ++dm->vsync_cnt;
+ wake_up_interruptible(&dm->vsync_wait);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* Wait for a vsync interrupt. This routine sleeps so it can only be called
+ * from process context.
+ */
+static int davincifb_wait_for_vsync(struct dm_win_info *w)
+{
+ struct dm_info *dm = w->dm;
+ wait_queue_t wq;
+ unsigned long cnt;
+ int ret;
+
+ init_waitqueue_entry(&wq, current);
+
+ cnt = dm->vsync_cnt;
+ ret = wait_event_interruptible_timeout(dm->vsync_wait,
+ cnt != dm->vsync_cnt,
+ dm->timeout);
+ if (ret < 0)
+ return (ret);
+ if (ret == 0)
+ return (-ETIMEDOUT);
+
+ return (0);
+}
+
+/* Sets a uniform attribute value over a rectangular area on the attribute
+ * window. The attribute value (0 to 7) is passed through the fb_fillrect's
+ * color parameter.
+ */
+static int davincifb_set_attr_blend(struct fb_fillrect *r)
+{
+ struct fb_info *info = &dm->osd1->info;
+ struct fb_var_screeninfo *var = &dm->osd1->info.var;
+ unsigned long start = 0;
+ u8 blend;
+ u32 width_bytes;
+
+ if (r->dx + r->width > var->xres_virtual)
+ return -EINVAL;
+ if (r->dy + r->height > var->yres_virtual)
+ return -EINVAL;
+ if (r->color < 0 || r->color > 7)
+ return -EINVAL;
+
+ /* since bits_per_pixel = 4, this will truncate the width if it is
+ * not even. Similarly r->dx will be rounded down to an even pixel.
+ * ... Do we want to return an error otherwise?
+ */
+ width_bytes = r->width * var->bits_per_pixel / 8;
+ start = dm->osd1->fb_base + r->dy * info->fix.line_length
+ + r->dx * var->bits_per_pixel / 8;
+
+ blend = (((u8) r->color & 0xf) << 4) | ((u8) r->color);
+ while (r->height--) {
+ start += info->fix.line_length;
+ memset((void *)start, blend, width_bytes);
+ }
+
+ return 0;
+}
+
+/* These position parameters are given through fb_var_screeninfo.
+ * xp = var.reserved[0], yp = var.reserved[1],
+ * xl = var.xres, yl = var.yres
+ */
+static void set_win_position(char *id, u32 xp, u32 yp, u32 xl, u32 yl)
+{
+ int i = 0;
+
+ if (is_win(id, VID0)) {
+ i = 0;
+ } else if (is_win(id, VID1)) {
+ i = 1;
+ } else if (is_win(id, OSD0)) {
+ i = 2;
+ } else if (is_win(id, OSD1)) {
+ i = 3;
+ }
+
+ dispc_reg_out(OSD_WINXP(i), xp);
+ dispc_reg_out(OSD_WINYP(i), yp);
+ dispc_reg_out(OSD_WINXL(i), xl);
+ dispc_reg_out(OSD_WINYL(i), yl);
+}
+
+static inline void get_win_position(struct dm_win_info *w,
+ u32 * xp, u32 * yp, u32 * xl, u32 * yl)
+{
+ struct fb_var_screeninfo *v = &w->info.var;
+
+ *xp = x_pos(w);
+ *yp = y_pos(w);
+ *xl = v->xres;
+ *yl = v->yres;
+}
+
+/* Returns 1 if the windows overlap, 0 otherwise */
+static int window_overlap(struct dm_win_info *w, u32 xp, u32 yp, u32 xl, u32 yl)
+{
+ u32 _xp = 0, _yp = 0, _xl = 0, _yl = 0;
+
+#define OVERLAP(x1, y1, x2, y2, x3, y3, x4, y4) \
+(!( ((x1)<(x3) && (x2)<(x3)) || ((x1)>(x4) && (x2)>(x4)) || \
+ ((y1)<(y3) && (y2)<(y3)) || ((y1)>(y4) && (y2)>(y4)) ) \
+)
+
+ if (!w)
+ return (0);
+
+ get_win_position(w, &_xp, &_yp, &_xl, &_yl);
+
+ return (OVERLAP(xp, yp, xp + xl, yp + yl,
+ _xp, _yp, _xp + _xl, _yp + _yl));
+#undef OVERLAP
+}
+
+/* Returns 1 if the window parameters are within VID0, 0 otherwise */
+static int within_vid0_limits(u32 xp, u32 yp, u32 xl, u32 yl)
+{
+ u32 vid0_xp = 0, vid0_yp = 0, vid0_xl = 0, vid0_yl = 0;
+
+ if (!dm->vid0)
+ return (1);
+ get_win_position(dm->vid0, &vid0_xp, &vid0_yp, &vid0_xl, &vid0_yl);
+ if ((xp >= vid0_xp) && (yp >= vid0_yp) &&
+ (xp + xl <= vid0_xp + vid0_xl) && (yp + yl <= vid0_yp + vid0_yl))
+ return (1);
+ return (0);
+}
+
+/* VID0 must be large enough to hold all other windows */
+static int check_new_vid0_size(u32 xp0, u32 yp0, u32 xl0, u32 yl0)
+{
+ u32 _xp = 0, _yp = 0, _xl = 0, _yl = 0;
+#define WITHIN_LIMITS \
+ ((_xp >= xp0) && (_yp >= yp0) && \
+ (_xp + _xl <= xp0 + xl0) && (_yp + _yl <= yp0 + yl0))
+
+ if (dm->osd0) {
+ get_win_position(dm->osd0, &_xp, &_yp, &_xl, &_yl);
+ if (!WITHIN_LIMITS)
+ return (-EINVAL);
+ }
+ if (dm->osd1) {
+ get_win_position(dm->osd1, &_xp, &_yp, &_xl, &_yl);
+ if (!WITHIN_LIMITS)
+ return (-EINVAL);
+ }
+ if (dm->vid1) {
+ get_win_position(dm->vid1, &_xp, &_yp, &_xl, &_yl);
+ if (!WITHIN_LIMITS)
+ return (-EINVAL);
+ }
+ return (0);
+
+#undef WITHIN_LIMITS
+}
+
+/**
+ * davincifb_check_var - Validates a var passed in.
+ * @var: frame buffer variable screen structure
+ * @info: frame buffer structure that represents a single frame buffer
+ *
+ * Checks to see if the hardware supports the state requested by
+ * var passed in. This function does not alter the hardware state!!!
+ * This means the data stored in struct fb_info and struct xxx_par do
+ * not change. This includes the var inside of struct fb_info.
+ * Do NOT change these. This function can be called on its own if we
+ * intent to only test a mode and not actually set it.
+ * If the var passed in is slightly off by what the hardware can support
+ * then we alter the var PASSED in to what we can do.
+ *
+ * Returns negative errno on error, or zero on success.
+ */
+static int davincifb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ const struct dm_win_info *w = (const struct dm_win_info *)info->par;
+ struct fb_var_screeninfo v;
+
+/* Rules:
+ * 1) Vid1, OSD0, OSD1 and Cursor must be fully contained inside of Vid0.
+ * 2) Vid0 and Vid1 are both set to accept YUV 4:2:2 (for now).
+ * 3) OSD window data is always packed into 32-bit words and left justified.
+ * 4) Each horizontal line of window data must be a multiple of 32 bytes.
+ * 32 bytes = 32 bytes / 2 bytes per pixel = 16 pixels.
+ * This implies that 'xres' must be a multiple of 32 bytes.
+ * 5) The offset registers hold the distance between the start of one line and
+ * the start of the next. This offset value must be a multiple of 32 bytes.
+ * This implies that 'xres_virtual' is also a multiple of 32 bytes. Note
+ * that 'xoffset' needn't be a multiple of 32 bytes.
+ * 6) OSD0 is set to accept RGB565.
+ * dispc_reg_merge(OSD_OSDWIN0ND, OSD_OSDWIN0ND_RGB0E, OSD_OSDWIN0ND_RGB0E)
+ * 7) OSD1 is set to be the attribute window.
+ * 8) Vid1 startX = Vid0 startX + N * 16 pixels (32 bytes)
+ * 9) Vid1 width = (16*N - 8) pixels
+ * 10) When one of the OSD windows is in RGB565, it cannot overlap with Vid1.
+ * 11) Vid1 start X position must be offset a multiple of 16 pixels from the
+ * left edge of Vid0.
+ */
+
+ memcpy(&v, var, sizeof(v));
+ return (0);
+
+ /* do board-specific checks on the var */
+ if (davincifb_venc_check_mode(w, &v))
+ return (-EINVAL);
+
+ if (v.xres_virtual < v.xres || v.yres_virtual < v.yres)
+ return (-EINVAL);
+ if (v.xoffset > v.xres_virtual - v.xres)
+ return (-EINVAL);
+ if (v.yoffset > v.yres_virtual - v.yres)
+ return (-EINVAL);
+ if ((v.xres * v.bits_per_pixel / 8) % 32 || (v.xres_virtual * v.bits_per_pixel / 8) % 32) /* Rules 4, 5 */
+ return (-EINVAL);
+ if (v.xres_virtual * v.yres_virtual * v.bits_per_pixel / 8 > w->fb_size)
+ return (-EINVAL);
+
+ if (!is_win(info->fix.id, VID0)) {
+ /* Rule 1 */
+ if (!within_vid0_limits(x_pos(w), y_pos(w), v.xres, v.yres))
+ return (-EINVAL);
+ }
+ if (is_win(info->fix.id, OSD0)) {
+ /* Rule 10 */
+ if (window_overlap(w->dm->vid1,
+ x_pos(w), y_pos(w), v.xres, v.yres))
+ return (-EINVAL);
+ /* Rule 5 */
+ v.bits_per_pixel = 16;
+ v.red.offset = 11;
+ v.green.offset = 5;
+ v.blue.offset = 0;
+ v.red.length = 5;
+ v.green.length = 6;
+ v.blue.length = 5;
+ v.transp.offset = v.transp.length = 0;
+ v.red.msb_right = v.green.msb_right = v.blue.msb_right
+ = v.transp.msb_right = 0;
+ v.nonstd = 0;
+ v.accel_flags = 0;
+ } else if (is_win(info->fix.id, OSD1)) {
+ v.bits_per_pixel = 4;
+ } else if (is_win(info->fix.id, VID0)) {
+ if (check_new_vid0_size(x_pos(w), y_pos(w), v.xres, v.yres))
+ return (-EINVAL);
+ v.bits_per_pixel = 16;
+ } else if (is_win(info->fix.id, VID1)) {
+ /* Rule 11 */
+ if ((x_pos(w->dm->vid0) - x_pos(w)) % 16)
+ return (-EINVAL);
+ /* Video1 may be in YUV or RGB888 format */
+ if ((v.bits_per_pixel != 16) && (v.bits_per_pixel != 32))
+ return (-EINVAL);
+ } else
+ return (-EINVAL);
+
+ memcpy(var, &v, sizeof(v));
+ return (0);
+}
+
+/* Interlaced = Frame mode, Non-interlaced = Field mode */
+static void set_interlaced(char *id, unsigned int on)
+{
+ on = (on == 0) ? 0 : ~0;
+
+ if (is_win(id, VID0))
+ dispc_reg_merge(OSD_VIDWINMD, on, OSD_VIDWINMD_VFF0);
+ else if (is_win(id, VID1))
+ dispc_reg_merge(OSD_VIDWINMD, on, OSD_VIDWINMD_VFF1);
+ else if (is_win(id, OSD0))
+ dispc_reg_merge(OSD_OSDWIN0MD, on, OSD_OSDWIN0MD_OFF0);
+ else if (is_win(id, OSD1))
+ dispc_reg_merge(OSD_OSDWIN1MD, on, OSD_OSDWIN1MD_OFF1);
+}
+
+/* For zooming, we just have to set the start of framebuffer, the zoom factors
+ * and the display size. The hardware will then read only
+ * (display size / zoom factor) area of the framebuffer and zoom and
+ * display it. In the following function, we assume that the start of
+ * framebuffer and the display size parameters are set already.
+ */
+static void set_zoom(int WinID, int h_factor, int v_factor)
+{
+ switch (WinID) {
+ case 0: //VID0
+ dispc_reg_merge(OSD_VIDWINMD,
+ h_factor << OSD_VIDWINMD_VHZ0_SHIFT,
+ OSD_VIDWINMD_VHZ0);
+ dispc_reg_merge(OSD_VIDWINMD,
+ v_factor << OSD_VIDWINMD_VVZ0_SHIFT,
+ OSD_VIDWINMD_VVZ0);
+ break;
+ case 1: //VID1
+ dispc_reg_merge(OSD_VIDWINMD,
+ h_factor << OSD_VIDWINMD_VHZ1_SHIFT,
+ OSD_VIDWINMD_VHZ1);
+ dispc_reg_merge(OSD_VIDWINMD,
+ v_factor << OSD_VIDWINMD_VVZ1_SHIFT,
+ OSD_VIDWINMD_VVZ1);
+ break;
+ case 2: //OSD0
+ dispc_reg_merge(OSD_OSDWIN0MD,
+ h_factor << OSD_OSDWIN0MD_OHZ0_SHIFT,
+ OSD_OSDWIN0MD_OHZ0);
+ dispc_reg_merge(OSD_OSDWIN0MD,
+ v_factor << OSD_OSDWIN0MD_OVZ0_SHIFT,
+ OSD_OSDWIN0MD_OVZ0);
+ break;
+ case 3:
+ dispc_reg_merge(OSD_OSDWIN1MD,
+ h_factor << OSD_OSDWIN1MD_OHZ1_SHIFT,
+ OSD_OSDWIN1MD_OHZ1);
+ dispc_reg_merge(OSD_OSDWIN1MD,
+ v_factor << OSD_OSDWIN1MD_OVZ1_SHIFT,
+ OSD_OSDWIN1MD_OVZ1);
+ break;
+ }
+}
+
+/* Chooses the ROM CLUT for now. Can be extended later. */
+static void set_bg_color(u8 clut, u8 color_offset)
+{
+ clut = 0; /* 0 = ROM, 1 = RAM */
+
+ dispc_reg_merge(OSD_MODE, OSD_MODE_BCLUT & clut, OSD_MODE_BCLUT);
+ dispc_reg_merge(OSD_MODE, color_offset << OSD_MODE_CABG_SHIFT,
+ OSD_MODE_CABG);
+}
+
+static void set_sdram_params(char *id, u32 addr, u32 line_length)
+{
+ /* The parameters to be written to the registers should be in
+ * multiple of 32 bytes
+ */
+ addr = addr; /* div by 32 */
+ line_length = line_length / 32;
+
+ if (is_win(id, VID0)) {
+ dispc_reg_out(OSD_VIDWIN0ADR, addr);
+ dispc_reg_out(OSD_VIDWIN0OFST, line_length);
+ } else if (is_win(id, VID1)) {
+ dispc_reg_out(OSD_VIDWIN1ADR, addr);
+ dispc_reg_out(OSD_VIDWIN1OFST, line_length);
+ } else if (is_win(id, OSD0)) {
+ dispc_reg_out(OSD_OSDWIN0ADR, addr);
+ dispc_reg_out(OSD_OSDWIN0OFST, line_length);
+ } else if (is_win(id, OSD1)) {
+ dispc_reg_out(OSD_OSDWIN1ADR, addr);
+ dispc_reg_out(OSD_OSDWIN1OFST, line_length);
+ }
+}
+
+static void set_win_enable(char *id, unsigned int on)
+{
+ on = (on == 0) ? 0 : ~0;
+
+ if (is_win(id, VID0))
+ /* Turning off VID0 use due to field inversion issue */
+ dispc_reg_merge(OSD_VIDWINMD, 0, OSD_VIDWINMD_ACT0);
+ else if (is_win(id, VID1))
+ dispc_reg_merge(OSD_VIDWINMD, on, OSD_VIDWINMD_ACT1);
+ else if (is_win(id, OSD0))
+ dispc_reg_merge(OSD_OSDWIN0MD, on, OSD_OSDWIN0MD_OACT0);
+ else if (is_win(id, OSD1)) {
+ /* The OACT1 bit is applicable only if OSD1 is not used as
+ * the attribute window
+ */
+ if (!(dispc_reg_in(OSD_OSDWIN1MD) & OSD_OSDWIN1MD_OASW))
+ dispc_reg_merge(OSD_OSDWIN1MD, on, OSD_OSDWIN1MD_OACT1);
+ }
+}
+
+static void set_win_mode(char *id)
+{
+ if (is_win(id, VID0)) ;
+ else if (is_win(id, VID1)) {
+ if (dm->vid1->info.var.bits_per_pixel == 32)
+ dispc_reg_merge(OSD_MISCCT, ~0,
+ OSD_MISCCT_RGBWIN | OSD_MISCCT_RGBEN);
+ } else if (is_win(id, OSD0))
+ /* Set RGB565 mode */
+ dispc_reg_merge(OSD_OSDWIN0MD, OSD_OSDWIN0MD_RGB0E,
+ OSD_OSDWIN0MD_RGB0E);
+ else if (is_win(id, OSD1)) {
+ /* Set as attribute window */
+ dispc_reg_merge(OSD_OSDWIN1MD, OSD_OSDWIN1MD_OASW,
+ OSD_OSDWIN1MD_OASW);
+ }
+
+}
+
+/**
+ * davincifb_set_par - Optional function. Alters the hardware state.
+ * @info: frame buffer structure that represents a single frame buffer
+ *
+ * Using the fb_var_screeninfo in fb_info we set the resolution of the
+ * this particular framebuffer. This function alters the par AND the
+ * fb_fix_screeninfo stored in fb_info. It doesn't not alter var in
+ * fb_info since we are using that data. This means we depend on the
+ * data in var inside fb_info to be supported by the hardware.
+ * davincifb_check_var is always called before dmfb_set_par to ensure this.
+ * Again if you can't can't the resolution you don't need this function.
+ *
+ */
+static int davincifb_set_par(struct fb_info *info)
+{
+ struct dm_win_info *w = (struct dm_win_info *)info->par;
+ struct fb_var_screeninfo *v = &info->var;
+ u32 start = 0, offset = 0;
+
+ info->fix.line_length = v->xres_virtual * v->bits_per_pixel / 8;
+
+ offset = v->yoffset * info->fix.line_length +
+ v->xoffset * v->bits_per_pixel / 8;
+ start = (u32) w->fb_base_phys + offset;
+ set_sdram_params(info->fix.id, start, info->fix.line_length);
+
+ set_interlaced(info->fix.id, 1);
+ set_win_position(info->fix.id,
+ x_pos(w), y_pos(w), v->xres, v->yres / 2);
+ set_win_mode(info->fix.id);
+ set_win_enable(info->fix.id, 1);
+
+ return (0);
+}
+
+/**
+ * davincifb_ioctl - handler for private ioctls.
+ */
+static int davincifb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ struct dm_win_info *w = (struct dm_win_info *)info->par;
+ void __user *argp = (void __user *)arg;
+ struct fb_fillrect rect;
+ struct zoom_params zoom;
+ long std = 0;
+
+ switch (cmd) {
+ case FBIO_WAITFORVSYNC:
+ /* This ioctl accepts an integer argument to specify a
+ * display. We only support one display, so we will
+ * simply ignore the argument.
+ */
+ return (davincifb_wait_for_vsync(w));
+ break;
+ case FBIO_SETATTRIBUTE:
+ if (copy_from_user(&rect, argp, sizeof(rect)))
+ return -EFAULT;
+ return (davincifb_set_attr_blend(&rect));
+ break;
+ case FBIO_SETPOSX:
+ if (arg >= 0 && arg <= DISP_XRES) {
+ w->x = arg;
+ davincifb_check_var(&w->info.var, &w->info);
+ davincifb_set_par(&w->info);
+ return 0;
+ } else
+ return -EINVAL;
+ break;
+ case FBIO_SETPOSY:
+ if (arg >= 0 && arg <= DISP_YRES) {
+ w->y = arg;
+ davincifb_check_var(&w->info.var, &w->info);
+ davincifb_set_par(&w->info);
+ return 0;
+ } else
+ return -EINVAL;
+ break;
+ case FBIO_SETZOOM:
+ if (copy_from_user(&zoom, argp, sizeof(zoom)))
+ return -EFAULT;
+ if ((zoom.zoom_h == 2) || (zoom.zoom_h == 0)
+ || (zoom.zoom_h == 1) || (zoom.zoom_v == 2)
+ || (zoom.zoom_v == 0) || (zoom.zoom_v == 1)) {
+ set_zoom(zoom.window_id, zoom.zoom_h, zoom.zoom_v);
+ return 0;
+ } else {
+ return -EINVAL;
+ }
+ break;
+ case FBIO_GETSTD:
+ std = ((dmparams.output << 16) | (dmparams.format)); //(NTSC <<16) | (COPOSITE);
+ if (copy_to_user(argp, &std, sizeof(u_int32_t)))
+ return -EFAULT;
+ return 0;
+ break;
+ }
+ return (-EINVAL);
+}
+
+/**
+ * davincifb_setcolreg - Optional function. Sets a color register.
+ * @regno: Which register in the CLUT we are programming
+ * @red: The red value which can be up to 16 bits wide
+ * @green: The green value which can be up to 16 bits wide
+ * @blue: The blue value which can be up to 16 bits wide.
+ * @transp: If supported the alpha value which can be up to 16 bits wide.
+ * @info: frame buffer info structure
+ *
+ * Set a single color register. The values supplied have a 16 bit
+ * magnitude which needs to be scaled in this function for the hardware.
+ * Things to take into consideration are how many color registers, if
+ * any, are supported with the current color visual. With truecolor mode
+ * no color palettes are supported. Here a psuedo palette is created
+ * which we store the value in pseudo_palette in struct fb_info. For
+ * pseudocolor mode we have a limited color palette. To deal with this
+ * we can program what color is displayed for a particular pixel value.
+ * DirectColor is similar in that we can program each color field. If
+ * we have a static colormap we don't need to implement this function.
+ *
+ * Returns negative errno on error, or zero on success.
+ */
+static int davincifb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ /* only pseudo-palette (16 bpp) allowed */
+ if (regno >= 16) /* maximum number of palette entries */
+ return (1);
+
+ if (info->var.grayscale) {
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+ }
+
+ /* Truecolor has hardware-independent 16-entry pseudo-palette */
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+ u32 v;
+
+ if (regno >= 16)
+ return (1);
+
+ red >>= (16 - info->var.red.length);
+ green >>= (16 - info->var.green.length);
+ blue >>= (16 - info->var.blue.length);
+
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset);
+
+ switch (info->var.bits_per_pixel) {
+ case 16:
+ ((u16 *) (info->pseudo_palette))[regno] = v;
+ break;
+ default:
+ return (1);
+ }
+ return (0);
+ }
+ return (0);
+}
+
+/**
+ * davincifb_pan_display - NOT a required function. Pans the display.
+ * @var: frame buffer variable screen structure
+ * @info: frame buffer structure that represents a single frame buffer
+ *
+ * Pan (or wrap, depending on the `vmode' field) the display using the
+ * `xoffset' and `yoffset' fields of the `var' structure.
+ * If the values don't fit, return -EINVAL.
+ *
+ * Returns negative errno on error, or zero on success.
+ */
+static int davincifb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct dm_win_info *w = (struct dm_win_info *)info->par;
+ u32 start = 0, offset = 0;
+
+ if (var->xoffset > var->xres_virtual - var->xres)
+ return (-EINVAL);
+ if (var->yoffset > var->yres_virtual - var->yres)
+ return (-EINVAL);
+ if ((var->xres_virtual * var->bits_per_pixel / 8) % 32)
+ return (-EINVAL);
+
+ offset = var->yoffset * info->fix.line_length +
+ var->xoffset * var->bits_per_pixel / 8;
+ start = (u32) w->fb_base_phys + offset;
+
+ if ((dispc_reg_in(VENC_VSTAT) & 0x00000010)==0x10)
+ set_sdram_params(info->fix.id, start, info->fix.line_length);
+ else
+ w->sdram_address = start;
+
+ return (0);
+}
+
+/**
+ * davincifb_blank - NOT a required function. Blanks the display.
+ * @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 davincifb_blank(int blank_mode, struct fb_info *info)
+{
+ return 0;
+}
+
+static int parse_win_params(char *wp,
+ int *xres, int *yres, int *xpos, int *ypos)
+{
+ char *s;
+
+ if ((s = strsep(&wp, "x")) == NULL)
+ return -EINVAL;
+ *xres = simple_strtoul(s, NULL, 0);
+
+ if ((s = strsep(&wp, "@")) == NULL)
+ return -EINVAL;
+ *yres = simple_strtoul(s, NULL, 0);
+
+ if ((s = strsep(&wp, ",")) == NULL)
+ return -EINVAL;
+ *xpos = simple_strtoul(s, NULL, 0);
+
+ if ((s = strsep(&wp, ":")) == NULL)
+ return -EINVAL;
+ *ypos = simple_strtoul(s, NULL, 0);
+
+ return 0;
+}
+
+/*
+ * Pass boot-time options by adding the following string to the boot params:
+ * video=davincifb:[option[:option]]
+ * Valid options:
+ * output=[lcd|ntsc|pal]
+ * format=[composite|s-video|component|rgb]
+ * vid0=[off|MxN@X,Y]
+ * vid1=[off|MxN@X,Y]
+ * osd0=[off|MxN@X,Y]
+ * osd1=[off|MxN@X,Y]
+ * MxN specify the window resolution (displayed size)
+ * X,Y specify the window position
+ * M, N, X, Y are integers
+ * M, X should be multiples of 16
+ */
+
+#ifndef MODULE
+int __init davincifb_setup(char *options)
+{
+ char *this_opt;
+ u32 xres, yres, xpos, ypos;
+ int format_yres = 480;
+
+ pr_debug("davincifb: Options \"%s\"\n", options);
+
+ if (!options || !*options)
+ return 0;
+
+ while ((this_opt = strsep(&options, ":")) != NULL) {
+
+ if (!*this_opt)
+ continue;
+
+ if (!strncmp(this_opt, "output=", 7)) {
+ if (!strncmp(this_opt + 7, "lcd", 3)) {
+ dmparams.output = LCD;
+ dmparams.format = 0;
+ } else if (!strncmp(this_opt + 7, "ntsc", 4))
+ dmparams.output = NTSC;
+ else if (!strncmp(this_opt + 7, "pal", 3))
+ dmparams.output = PAL;
+ } else if (!strncmp(this_opt, "format=", 7)) {
+ if (dmparams.output == LCD)
+ continue;
+ if (!strncmp(this_opt + 7, "composite", 9))
+ dmparams.format = COMPOSITE;
+ else if (!strncmp(this_opt + 7, "s-video", 7))
+ dmparams.format = SVIDEO;
+ else if (!strncmp(this_opt + 7, "component", 9))
+ dmparams.format = COMPONENT;
+ else if (!strncmp(this_opt + 7, "rgb", 3))
+ dmparams.format = RGB;
+ } else if (!strncmp(this_opt, "vid0=", 5)) {
+ if (!strncmp(this_opt + 5, "off", 3))
+ dmparams.windows &= ~(1 << VID0);
+ else if (!parse_win_params(this_opt + 5,
+ &xres, &yres, &xpos,
+ &ypos)) {
+ dmparams.vid0_xres = xres;
+ dmparams.vid0_yres = yres;
+ dmparams.vid0_xpos = xpos;
+ dmparams.vid0_ypos = ypos;
+ }
+ } else if (!strncmp(this_opt, "vid1=", 5)) {
+ if (!strncmp(this_opt + 5, "off", 3))
+ dmparams.windows &= ~(1 << VID1);
+ else if (!parse_win_params(this_opt + 5,
+ &xres, &yres, &xpos,
+ &ypos)) {
+ dmparams.vid1_xres = xres;
+ dmparams.vid1_yres = yres;
+ dmparams.vid1_xpos = xpos;
+ dmparams.vid1_ypos = ypos;
+ }
+ } else if (!strncmp(this_opt, "osd0=", 5)) {
+ if (!strncmp(this_opt + 5, "off", 3))
+ dmparams.windows &= ~(1 << OSD0);
+ else if (!parse_win_params(this_opt + 5,
+ &xres, &yres, &xpos,
+ &ypos)) {
+ dmparams.osd0_xres = xres;
+ dmparams.osd0_yres = yres;
+ dmparams.osd0_xpos = xpos;
+ dmparams.osd0_ypos = ypos;
+ }
+ } else if (!strncmp(this_opt, "osd1=", 5)) {
+ if (!strncmp(this_opt + 5, "off", 3))
+ dmparams.windows &= ~(1 << OSD1);
+ else if (!parse_win_params(this_opt + 5,
+ &xres, &yres, &xpos,
+ &ypos)) {
+ dmparams.osd1_xres = xres;
+ dmparams.osd1_yres = yres;
+ dmparams.osd1_xpos = xpos;
+ dmparams.osd1_ypos = ypos;
+ }
+ }
+ }
+ printk(KERN_INFO "DaVinci: "
+ "Output on %s%s, Enabled windows: %s %s %s %s\n",
+ (dmparams.output == LCD) ? "LCD" :
+ (dmparams.output == NTSC) ? "NTSC" :
+ (dmparams.output == PAL) ? "PAL" : "unknown device!",
+ (dmparams.format == 0) ? "" :
+ (dmparams.format == COMPOSITE) ? " in COMPOSITE format" :
+ (dmparams.format == SVIDEO) ? " in SVIDEO format" :
+ (dmparams.format == COMPONENT) ? " in COMPONENT format" :
+ (dmparams.format == RGB) ? " in RGB format" : "",
+ (dmparams.windows & (1 << VID0)) ? "Video0" : "",
+ (dmparams.windows & (1 << VID1)) ? "Video1" : "",
+ (dmparams.windows & (1 << OSD0)) ? "OSD0" : "",
+ (dmparams.windows & (1 << OSD1)) ? "OSD1" : "");
+ if (dmparams.output == NTSC) {
+ format_yres = 480;
+ } else if (dmparams.output == PAL) {
+ format_yres = 576;
+ } else {
+ printk(KERN_INFO
+ "DaVinci:invalid format..defaulting width to 480\n");
+ }
+ dmparams.osd0_yres = osd0_default_var.yres = format_yres;
+ dmparams.osd1_yres = osd1_default_var.yres = format_yres;
+ dmparams.vid0_yres = vid0_default_var.yres = format_yres;
+ dmparams.vid1_yres = vid1_default_var.yres = format_yres;
+
+ osd0_default_var.yres_virtual = format_yres * DOUBLE_BUF;
+ osd1_default_var.yres_virtual = format_yres * DOUBLE_BUF;
+ vid0_default_var.yres_virtual = format_yres * TRIPLE_BUF;
+ vid1_default_var.yres_virtual = format_yres * TRIPLE_BUF;
+
+ if (dmparams.windows & (1 << VID0))
+ printk(KERN_INFO "Setting Video0 size %dx%d, "
+ "position (%d,%d)\n",
+ dmparams.vid0_xres, dmparams.vid0_yres,
+ dmparams.vid0_xpos, dmparams.vid0_ypos);
+ if (dmparams.windows & (1 << VID1))
+ printk(KERN_INFO "Setting Video1 size %dx%d, "
+ "position (%d,%d)\n",
+ dmparams.vid1_xres, dmparams.vid1_yres,
+ dmparams.vid1_xpos, dmparams.vid1_ypos);
+ if (dmparams.windows & (1 << OSD0))
+ printk(KERN_INFO "Setting OSD0 size %dx%d, "
+ "position (%d,%d)\n",
+ dmparams.osd0_xres, dmparams.osd0_yres,
+ dmparams.osd0_xpos, dmparams.osd0_ypos);
+ if (dmparams.windows & (1 << OSD1))
+ printk(KERN_INFO "Setting OSD1 size %dx%d, "
+ "position (%d,%d)\n",
+ dmparams.osd1_xres, dmparams.osd1_yres,
+ dmparams.osd1_xpos, dmparams.osd1_ypos);
+ return (0);
+}
+#endif
+
+static int mem_release(struct dm_win_info *w)
+{
+ if (!w->alloc_fb_mem) {
+ iounmap((void *)w->fb_base);
+ release_mem_region(w->fb_base_phys, w->fb_size);
+ } else
+ dma_free_coherent(NULL, w->fb_size, (void *)w->fb_base,
+ w->fb_base_phys);
+ kfree(w);
+ return (0);
+}
+
+static int mem_alloc(struct dm_win_info **win, dma_addr_t fb_base_phys,
+ unsigned long fb_size, char *fbname)
+{
+ struct dm_win_info *w;
+ struct device *dev = dm->dev;
+
+ w = kmalloc(sizeof(struct dm_win_info), GFP_KERNEL);
+ if (!w) {
+ dev_err(dev, "%s: could not allocate memory\n", fbname);
+ return (-ENOMEM);
+ }
+ memset(w, 0, sizeof(struct dm_win_info));
+
+ w->fb_base_phys = fb_base_phys;
+ w->fb_size = fb_size;
+
+ /* A null base address indicates that the framebuffer memory should be
+ * dynamically allocated.
+ */
+ if (!w->fb_base_phys)
+ w->alloc_fb_mem = 1;
+
+ if (!w->alloc_fb_mem) {
+ if (!request_mem_region(w->fb_base_phys, w->fb_size, fbname)) {
+ dev_err(dev, "%s: cannot reserve FB region\n", fbname);
+ goto free_par;
+ }
+ w->fb_base =
+ (unsigned long)ioremap(w->fb_base_phys, w->fb_size);
+ if (!w->fb_base) {
+ dev_err(dev, "%s: cannot map framebuffer\n", fbname);
+ goto release_fb;
+ }
+ } else {
+ /* allocate coherent memory for the framebuffer */
+ w->fb_base = (unsigned long)dma_alloc_coherent(dev,
+ w->fb_size,
+ &w->fb_base_phys,
+ GFP_KERNEL |
+ GFP_DMA);
+ if (!w->fb_base) {
+ dev_err(dev, "%s: cannot allocate framebuffer\n",
+ fbname);
+ goto free_par;
+ }
+
+ dev_dbg(dev, "Framebuffer allocated at 0x%x "
+ "mapped to 0x%x, size %dk\n",
+ (unsigned)w->fb_base_phys, (unsigned)w->fb_base,
+ (unsigned)w->fb_size / 1024);
+ }
+
+ *win = w;
+ return (0);
+
+ release_fb:
+ if (!w->alloc_fb_mem)
+ release_mem_region(w->fb_base_phys, w->fb_size);
+ free_par:
+ kfree(w);
+ return (-ENOMEM);
+}
+
+static struct fb_info *init_fb_info(struct dm_win_info *w,
+ struct fb_var_screeninfo *var, char *id)
+{
+ struct fb_info *info = &(w->info);
+ struct dm_info *dm = w->dm;
+
+ /* initialize the fb_info structure */
+ info->flags = FBINFO_DEFAULT;
+ info->fbops = &davincifb_ops;
+ info->screen_base = (char *)(w->fb_base);
+ info->pseudo_palette = w->pseudo_palette;
+ info->par = w;
+
+ /* Initialize variable screeninfo.
+ * The variable screeninfo can be directly specified by the user
+ * via an ioctl.
+ */
+ memcpy(&info->var, var, sizeof(info->var));
+ info->var.activate = FB_ACTIVATE_NOW;
+
+ /* Initialize fixed screeninfo.
+ * The fixed screeninfo cannot be directly specified by the user, but
+ * it may change to reflect changes to the var info.
+ */
+ strlcpy(info->fix.id, id, sizeof(info->fix.id));
+ info->fix.smem_start = w->fb_base_phys;
+ info->fix.line_length =
+ (info->var.xres_virtual * info->var.bits_per_pixel) / 8;
+ info->fix.smem_len = w->fb_size;
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = (info->var.bits_per_pixel <= 8) ?
+ FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+ info->fix.xpanstep = 0;
+ info->fix.ypanstep = 1;
+ info->fix.ywrapstep = 0;
+ info->fix.type_aux = 0;
+ info->fix.mmio_start = dm->mmio_base_phys;
+ info->fix.mmio_len = dm->mmio_size;
+ info->fix.accel = FB_ACCEL_NONE;
+ w->sdram_address = 0;
+
+ return info;
+}
+
+static void davincifb_ntsc_composite_config(int on)
+{
+ if (on) {
+ /* Reset video encoder module */
+ dispc_reg_out(VENC_VMOD, 0);
+
+ /* Enable Composite output and start video encoder */
+ dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC));
+
+ /* Set REC656 Mode */
+ dispc_reg_out(VENC_YCCCTL, 0x1);
+
+ /* Enable output mode and NTSC */
+ dispc_reg_out(VENC_VMOD, 0x1003);
+
+ /* Enable all DACs */
+ dispc_reg_out(VENC_DACTST, 0);
+ } else {
+ /* Reset video encoder module */
+ dispc_reg_out(VENC_VMOD, 0);
+ }
+}
+
+static void davincifb_ntsc_svideo_config(int on)
+{
+ if (on) {
+ /* Reset video encoder module */
+ dispc_reg_out(VENC_VMOD, 0);
+
+ /* Enable Composite output and start video encoder */
+ dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC));
+
+ /* Set REC656 Mode */
+ dispc_reg_out(VENC_YCCCTL, 0x1);
+
+ /* Enable output mode and NTSC */
+ dispc_reg_out(VENC_VMOD, 0x1003);
+
+ /* Enable S-Video Output; DAC B: S-Video Y, DAC C: S-Video C */
+ dispc_reg_out(VENC_DACSEL, 0x210);
+
+ /* Enable all DACs */
+ dispc_reg_out(VENC_DACTST, 0);
+ } else {
+ /* Reset video encoder module */
+ dispc_reg_out(VENC_VMOD, 0);
+ }
+}
+
+static void davincifb_ntsc_component_config(int on)
+{
+ if (on) {
+ /* Reset video encoder module */
+ dispc_reg_out(VENC_VMOD, 0);
+
+ /* Enable Composite output and start video encoder */
+ dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC));
+
+ /* Set REC656 Mode */
+ dispc_reg_out(VENC_YCCCTL, 0x1);
+
+ /* Enable output mode and NTSC */
+ dispc_reg_out(VENC_VMOD, 0x1003);
+
+ /* Enable Component output; DAC A: Y, DAC B: Pb, DAC C: Pr */
+ dispc_reg_out(VENC_DACSEL, 0x543);
+
+ /* Enable all DACs */
+ dispc_reg_out(VENC_DACTST, 0);
+ } else {
+ /* Reset video encoder module */
+ dispc_reg_out(VENC_VMOD, 0);
+ }
+}
+
+static void davincifb_pal_composite_config(int on)
+{
+ if (on) {
+ /* Reset video encoder module */
+ dispc_reg_out(VENC_VMOD, 0);
+
+ /* Enable Composite output and start video encoder */
+ dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC));
+
+ /* Set REC656 Mode */
+ dispc_reg_out(VENC_YCCCTL, 0x1);
+
+ /* Enable output mode and PAL */
+ dispc_reg_out(VENC_VMOD, 0x1043);
+
+ /* Enable all DACs */
+ dispc_reg_out(VENC_DACTST, 0);
+ } else {
+ /* Reset video encoder module */
+ dispc_reg_out(VENC_VMOD, 0);
+ }
+}
+
+static void davincifb_pal_svideo_config(int on)
+{
+ if (on) {
+ /* Reset video encoder module */
+ dispc_reg_out(VENC_VMOD, 0);
+
+ /* Enable Composite output and start video encoder */
+ dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC));
+
+ /* Set REC656 Mode */
+ dispc_reg_out(VENC_YCCCTL, 0x1);
+
+ /* Enable output mode and PAL */
+ dispc_reg_out(VENC_VMOD, 0x1043);
+
+ /* Enable S-Video Output; DAC B: S-Video Y, DAC C: S-Video C */
+ dispc_reg_out(VENC_DACSEL, 0x210);
+
+ /* Enable all DACs */
+ dispc_reg_out(VENC_DACTST, 0);
+ } else {
+ /* Reset video encoder module */
+ dispc_reg_out(VENC_VMOD, 0);
+ }
+}
+
+static void davincifb_pal_component_config(int on)
+{
+ if (on) {
+ /* Reset video encoder module */
+ dispc_reg_out(VENC_VMOD, 0);
+
+ /* Enable Composite output and start video encoder */
+ dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC));
+
+ /* Set REC656 Mode */
+ dispc_reg_out(VENC_YCCCTL, 0x1);
+
+ /* Enable output mode and PAL */
+ dispc_reg_out(VENC_VMOD, 0x1043);
+
+ /* Enable Component output; DAC A: Y, DAC B: Pb, DAC C: Pr */
+ dispc_reg_out(VENC_DACSEL, 0x543);
+
+ /* Enable all DACs */
+ dispc_reg_out(VENC_DACTST, 0);
+ } else {
+ /* Reset video encoder module */
+ dispc_reg_out(VENC_VMOD, 0);
+ }
+}
+
+static inline void fix_default_var(struct dm_win_info *w,
+ u32 xres, u32 yres, u32 xpos, u32 ypos,
+ int n_buf)
+{
+ struct fb_var_screeninfo *v = &w->info.var;
+
+ v->xres = xres;
+ v->yres = yres;
+ v->xres_virtual = v->xres;
+ v->yres_virtual = v->yres * n_buf;
+ x_pos(w) = xpos;
+ y_pos(w) = ypos;
+}
+
+/*
+ * Cleanup
+ */
+static int davincifb_remove(struct platform_device *pdev)
+{
+ free_irq(IRQ_VENCINT, &dm);
+
+ /* Cleanup all framebuffers */
+ if (dm->osd0) {
+ unregister_framebuffer(&dm->osd0->info);
+ mem_release(dm->osd0);
+ }
+ if (dm->osd1) {
+ unregister_framebuffer(&dm->osd1->info);
+ mem_release(dm->osd1);
+ }
+ if (dm->vid0) {
+ unregister_framebuffer(&dm->vid0->info);
+ mem_release(dm->vid0);
+ }
+ if (dm->vid1) {
+ unregister_framebuffer(&dm->vid1->info);
+ mem_release(dm->vid1);
+ }
+
+ /* Turn OFF the output device */
+ dm->output_device_config(0);
+
+ if (dm->mmio_base)
+ iounmap((void *)dm->mmio_base);
+ release_mem_region(dm->mmio_base_phys, dm->mmio_size);
+
+ return 0;
+}
+
+/*
+ * Initialization
+ */
+static int davincifb_probe(struct platform_device *pdev)
+{
+ struct fb_info *info;
+
+ if (dmparams.windows == 0)
+ return 0; /* user disabled all windows through bootargs */
+ dm->dev = &pdev->dev;
+ dm->mmio_base_phys = OSD_REG_BASE;
+ dm->mmio_size = OSD_REG_SIZE;
+
+ if (!request_mem_region
+ (dm->mmio_base_phys, dm->mmio_size, MODULE_NAME)) {
+ dev_err(dm->dev, ": cannot reserve MMIO region\n");
+ return (-ENODEV);
+ }
+
+ /* map the regions */
+ dm->mmio_base =
+ (unsigned long)ioremap(dm->mmio_base_phys, dm->mmio_size);
+ if (!dm->mmio_base) {
+ dev_err(dm->dev, ": cannot map MMIO\n");
+ goto release_mmio;
+ }
+
+ /* initialize the vsync wait queue */
+ init_waitqueue_head(&dm->vsync_wait);
+ dm->timeout = HZ / 5;
+
+ if ((dmparams.output == NTSC) && (dmparams.format == COMPOSITE))
+ dm->output_device_config = davincifb_ntsc_composite_config;
+ else if ((dmparams.output == NTSC) && (dmparams.format == SVIDEO))
+ dm->output_device_config = davincifb_ntsc_svideo_config;
+ else if ((dmparams.output == NTSC) && (dmparams.format == COMPONENT))
+ dm->output_device_config = davincifb_ntsc_component_config;
+ else if ((dmparams.output == PAL) && (dmparams.format == COMPOSITE))
+ dm->output_device_config = davincifb_pal_composite_config;
+ else if ((dmparams.output == PAL) && (dmparams.format == SVIDEO))
+ dm->output_device_config = davincifb_pal_svideo_config;
+ else if ((dmparams.output == PAL) && (dmparams.format == COMPONENT))
+ dm->output_device_config = davincifb_pal_component_config;
+ /* Add support for other displays here */
+ else {
+ printk(KERN_WARNING "Unsupported output device!\n");
+ dm->output_device_config = NULL;
+ }
+
+ printk("Setting Up Clocks for DM420 OSD\n");
+
+ /* Initialize the VPSS Clock Control register */
+ dispc_reg_out(VPSS_CLKCTL, 0x18);
+
+ /* Set Base Pixel X and Base Pixel Y */
+ dispc_reg_out(OSD_BASEPX, BASEX);
+ dispc_reg_out(OSD_BASEPY, BASEY);
+
+ /* Reset OSD registers to default. */
+ dispc_reg_out(OSD_MODE, 0);
+ dispc_reg_out(OSD_OSDWIN0MD, 0);
+
+ /* Set blue background color */
+ set_bg_color(0, 162);
+
+ /* Field Inversion Workaround */
+ dispc_reg_out(OSD_MODE, 0x200);
+
+ /* Setup VID0 framebuffer */
+ if (!(dmparams.windows & (1 << VID0))) {
+ printk(KERN_WARNING "No video/osd windows will be enabled "
+ "because Video0 is disabled\n");
+ return 0; /* background will still be shown */
+ }
+ /* Setup VID0 framebuffer */
+ if (!mem_alloc(&dm->vid0, VID0_FB_PHY, VID0_FB_SIZE, VID0_FBNAME)) {
+ dm->vid0->dm = dm;
+ fix_default_var(dm->vid0,
+ dmparams.vid0_xres, dmparams.vid0_yres,
+ dmparams.vid0_xpos, dmparams.vid0_ypos,
+ TRIPLE_BUF);
+ info = init_fb_info(dm->vid0, &vid0_default_var, VID0_FBNAME);
+ if (davincifb_check_var(&info->var, info)) {
+ dev_err(dm->dev, ": invalid default video mode\n");
+ goto exit;
+ }
+ memset((void *)dm->vid0->fb_base, 0x88, dm->vid0->fb_size);
+ } else
+ goto exit;
+
+ /* Setup OSD0 framebuffer */
+ if ((dmparams.windows & (1 << OSD0)) &&
+ (!mem_alloc(&dm->osd0, OSD0_FB_PHY, OSD0_FB_SIZE, OSD0_FBNAME))) {
+ dm->osd0->dm = dm;
+ fix_default_var(dm->osd0,
+ dmparams.osd0_xres, dmparams.osd0_yres,
+ dmparams.osd0_xpos, dmparams.osd0_ypos,
+ DOUBLE_BUF);
+ info = init_fb_info(dm->osd0, &osd0_default_var, OSD0_FBNAME);
+ if (davincifb_check_var(&info->var, info)) {
+ dev_err(dm->dev, ": invalid default video mode\n");
+ mem_release(dm->osd0);
+ } else
+ memset((void *)dm->osd0->fb_base, 0, dm->osd0->fb_size);
+ }
+
+ /* Setup OSD1 framebuffer */
+ if ((dmparams.windows & (1 << OSD1)) &&
+ (!mem_alloc(&dm->osd1, OSD1_FB_PHY, OSD1_FB_SIZE, OSD1_FBNAME))) {
+ dm->osd1->dm = dm;
+ fix_default_var(dm->osd1,
+ dmparams.osd1_xres, dmparams.osd1_yres,
+ dmparams.osd1_xpos, dmparams.osd1_ypos,
+ DOUBLE_BUF);
+ info = init_fb_info(dm->osd1, &osd1_default_var, OSD1_FBNAME);
+ if (davincifb_check_var(&info->var, info)) {
+ dev_err(dm->dev, ": invalid default video mode\n");
+ mem_release(dm->osd1);
+ } else
+ /* Set blend factor to show OSD windows */
+ memset((void *)dm->osd1->fb_base, 0xff,
+ dm->osd1->fb_size);
+ }
+
+ /* Setup VID1 framebuffer */
+ if ((dmparams.windows & (1 << VID1)) &&
+ (!mem_alloc(&dm->vid1, VID1_FB_PHY, VID1_FB_SIZE, VID1_FBNAME))) {
+ dm->vid1->dm = dm;
+ fix_default_var(dm->vid1,
+ dmparams.vid1_xres, dmparams.vid1_yres,
+ dmparams.vid1_xpos, dmparams.vid1_ypos,
+ TRIPLE_BUF);
+ info = init_fb_info(dm->vid1, &vid1_default_var, VID1_FBNAME);
+ if (davincifb_check_var(&info->var, info)) {
+ dev_err(dm->dev,
+ VID1_FBNAME ": invalid default video mode\n");
+ mem_release(dm->vid1);
+ } else
+ memset((void *)dm->vid1->fb_base, 0x88,
+ dm->vid1->fb_size);
+ }
+
+ /* Register OSD0 framebuffer */
+ if (dm->osd0) {
+ info = &dm->osd0->info;
+ if (register_framebuffer(info) < 0) {
+ dev_err(dm->dev, OSD0_FBNAME
+ "Unable to register OSD0 framebuffer\n");
+ mem_release(dm->osd0);
+ } else {
+ printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ info->node, info->fix.id);
+ davincifb_set_par(info);
+ }
+ }
+
+ /* Register VID0 framebuffer */
+ info = &dm->vid0->info;
+ if (register_framebuffer(info) < 0) {
+ dev_err(dm->dev,
+ VID0_FBNAME "Unable to register VID0 framebuffer\n");
+ goto exit;
+ } else {
+ printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ info->node, info->fix.id);
+ davincifb_set_par(info);
+ }
+
+ /* Register OSD1 framebuffer */
+ if (dm->osd1) {
+ info = &dm->osd1->info;
+ if (register_framebuffer(info) < 0) {
+ dev_err(dm->dev, OSD1_FBNAME
+ "Unable to register OSD1 framebuffer\n");
+ mem_release(dm->osd1);
+ } else {
+ printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ info->node, info->fix.id);
+ davincifb_set_par(info);
+ }
+ }
+
+ /* Register VID1 framebuffer */
+ if (dm->vid1) {
+ info = &dm->vid1->info;
+ if (register_framebuffer(info) < 0) {
+ mem_release(dm->vid1);
+ dev_err(dm->dev, VID1_FBNAME
+ "Unable to register VID1 framebuffer\n");
+ mem_release(dm->vid1);
+ } else {
+ printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ info->node, info->fix.id);
+ davincifb_set_par(info);
+ }
+ }
+
+ /* install our interrupt service routine */
+ if (request_irq(IRQ_VENCINT, davincifb_isr, IRQF_SHARED, MODULE_NAME,
+ dm)) {
+ dev_err(dm->dev, MODULE_NAME
+ ": could not install interrupt service routine\n");
+ goto exit;
+ }
+
+ /* Turn ON the output device */
+ dm->output_device_config(1);
+
+ return (0);
+
+ exit:
+ davincifb_remove(pdev);
+ iounmap((void *)dm->mmio_base);
+ release_mmio:
+ release_mem_region(dm->mmio_base_phys, dm->mmio_size);
+ return (-ENODEV);
+}
+
+/* ------------------------------------------------------------------------- */
+
+ /*
+ * Frame buffer operations
+ */
+static struct fb_ops davincifb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = davincifb_check_var,
+ .fb_set_par = davincifb_set_par,
+ .fb_setcolreg = davincifb_setcolreg,
+ .fb_blank = davincifb_blank,
+ .fb_pan_display = davincifb_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_rotate = NULL,
+ .fb_sync = NULL,
+ .fb_ioctl = davincifb_ioctl,
+};
+
+static struct platform_driver davincifb_driver = {
+ .probe = davincifb_probe,
+ .remove = davincifb_remove,
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+/* Register both the driver and the device */
+int __init davincifb_init(void)
+{
+#ifndef MODULE
+ /* boot-line options */
+ /* handle options for "dm64xxfb" for backwards compatability */
+ char *option;
+ char *names[] = { "davincifb", "dm64xxfb" };
+ int i, num_names = 2, done = 0;
+
+ for (i = 0; i < num_names && !done; i++) {
+ if (fb_get_options(names[i], &option)) {
+ printk(MODULE_NAME
+ ": Disabled on command-line.\n");
+ return -ENODEV;
+ } else if (option) {
+ davincifb_setup(option);
+ done = 1;
+ }
+ }
+#endif
+
+ /* Register the driver with LDM */
+ if (platform_driver_register(&davincifb_driver)) {
+ pr_debug("failed to register omapfb driver\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __exit davincifb_cleanup(void)
+{
+ platform_driver_unregister(&davincifb_driver);
+}
+
+module_init(davincifb_init);
+module_exit(davincifb_cleanup);
+
+MODULE_DESCRIPTION("Framebuffer driver for TI DaVinci");
+MODULE_AUTHOR("Texas Instruments");
+MODULE_LICENSE("GPL");
diff --git a/include/asm-arm/arch-davinci/aic23.h b/include/asm-arm/arch-davinci/aic23.h
new file mode 100644
index 0000000..6513065
--- /dev/null
+++ b/include/asm-arm/arch-davinci/aic23.h
@@ -0,0 +1,116 @@
+/*
+ * linux/include/asm-arm/arch-omap/aic23.h
+ *
+ * Hardware definitions for TI TLV320AIC23 audio codec
+ *
+ * Copyright (C) 2002 RidgeRun, Inc.
+ * Author: Steve Johnson
+ *
+ * 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_AIC23_H
+#define __ASM_ARCH_AIC23_H
+
+// Codec TLV320AIC23
+#define LEFT_LINE_VOLUME_ADDR 0x00
+#define RIGHT_LINE_VOLUME_ADDR 0x01
+#define LEFT_CHANNEL_VOLUME_ADDR 0x02
+#define RIGHT_CHANNEL_VOLUME_ADDR 0x03
+#define ANALOG_AUDIO_CONTROL_ADDR 0x04
+#define DIGITAL_AUDIO_CONTROL_ADDR 0x05
+#define POWER_DOWN_CONTROL_ADDR 0x06
+#define DIGITAL_AUDIO_FORMAT_ADDR 0x07
+#define SAMPLE_RATE_CONTROL_ADDR 0x08
+#define DIGITAL_INTERFACE_ACT_ADDR 0x09
+#define RESET_CONTROL_ADDR 0x0F
+
+// Left (right) line input volume control register
+#define LRS_ENABLED 0x0100
+#define LIM_MUTED 0x0080
+#define LIV_DEFAULT 0x0017
+#define LIV_MAX 0x001f
+#define LIV_MIN 0x0000
+
+// Left (right) channel headphone volume control register
+#define LZC_ON 0x0080
+#define LHV_DEFAULT 0x0079
+#define LHV_MAX 0x007f
+#define LHV_MIN 0x0000
+
+// Analog audio path control register
+#define STA_REG(x) ((x)<<6)
+#define STE_ENABLED 0x0020
+#define DAC_SELECTED 0x0010
+#define BYPASS_ON 0x0008
+#define INSEL_MIC 0x0004
+#define MICM_MUTED 0x0002
+#define MICB_20DB 0x0001
+
+// Digital audio path control register
+#define DACM_MUTE 0x0008
+#define DEEMP_32K 0x0002
+#define DEEMP_44K 0x0004
+#define DEEMP_48K 0x0006
+#define ADCHP_ON 0x0001
+
+// Power control down register
+#define DEVICE_POWER_OFF 0x0080
+#define CLK_OFF 0x0040
+#define OSC_OFF 0x0020
+#define OUT_OFF 0x0010
+#define DAC_OFF 0x0008
+#define ADC_OFF 0x0004
+#define MIC_OFF 0x0002
+#define LINE_OFF 0x0001
+
+// Digital audio interface register
+#define MS_MASTER 0x0040
+#define LRSWAP_ON 0x0020
+#define LRP_ON 0x0010
+#define IWL_16 0x0000
+#define IWL_20 0x0004
+#define IWL_24 0x0008
+#define IWL_32 0x000C
+#define FOR_I2S 0x0002
+#define FOR_DSP 0x0003
+
+// Sample rate control register
+#define CLKOUT_HALF 0x0080
+#define CLKIN_HALF 0x0040
+#define BOSR_384fs 0x0002 // BOSR_272fs when in USB mode
+#define USB_CLK_ON 0x0001
+#define SR_MASK 0xf
+#define CLKOUT_SHIFT 7
+#define CLKIN_SHIFT 6
+#define SR_SHIFT 2
+#define BOSR_SHIFT 1
+
+// Digital interface register
+#define ACT_ON 0x0001
+
+#define TLV320AIC23ID1 (0x1a) // cs low
+#define TLV320AIC23ID2 (0x1b) // cs high
+
+void tlv320aic23_power_up(void);
+void tlv320aic23_power_down(void);
+
+#endif /* __ASM_ARCH_AIC23_H */
diff --git a/include/asm-arm/arch-davinci/cpu.h b/include/asm-arm/arch-davinci/cpu.h
new file mode 100644
index 0000000..c7d190b
--- /dev/null
+++ b/include/asm-arm/arch-davinci/cpu.h
@@ -0,0 +1,32 @@
+/*
+ * linux/include/asm-arm/arch-davinci/cpu.h
+ *
+ * Davinci cpu type detection
+ *
+ * Author: Steve Chen <schen@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef _ASM_ARCH_CPU_H
+#define _ASM_ARCH_CPU_H
+
+extern unsigned int system_rev;
+
+#define GET_DAVINCI_CPU_TYPE ((system_rev >> 16) & 0xffff)
+
+#define IS_DAVINCI_CPU(type, id) \
+static inline int cpu_is_davinci_dm ##type (void) \
+{ \
+ return (GET_DAVINCI_CPU_TYPE == (id)) ? 1 : 0; \
+}
+
+/* following generates the cpu_is_davinci_dmxxx */
+IS_DAVINCI_CPU(6443, 0x6443) /* cpu_is_davinci_dm6443() */
+IS_DAVINCI_CPU(6467, 0x6467) /* cpu_is_davinci_dm6467() */
+IS_DAVINCI_CPU(350, 0x350) /* cpu_is_davinci_dm350() */
+
+#endif
diff --git a/include/asm-arm/arch-davinci/dma.h b/include/asm-arm/arch-davinci/dma.h
index 8e2f2d0..ac325c5 100644
--- a/include/asm-arm/arch-davinci/dma.h
+++ b/include/asm-arm/arch-davinci/dma.h
@@ -11,6 +11,6 @@
#ifndef __ASM_ARCH_DMA_H
#define __ASM_ARCH_DMA_H
-#define MAX_DMA_ADDRESS 0xffffffff
+#define MAX_DMA_ADDRESS 0xffffffff
#endif /* __ASM_ARCH_DMA_H */
diff --git a/include/asm-arm/arch-davinci/edma.h b/include/asm-arm/arch-davinci/edma.h
new file mode 100644
index 0000000..804282d
--- /dev/null
+++ b/include/asm-arm/arch-davinci/edma.h
@@ -0,0 +1,555 @@
+/*
+ * linux/include/asm-arm/arch-davinci/edma.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ * TI DAVINCI dma definitions
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/******************************************************************************
+ * DMA driver for DaVinci
+ * DMA driver for Davinci abstractes each ParamEntry as a Logical DMA channel
+ * for the user.So on Davinci the user can request 128 DAM channels
+ *
+ * Actual Physical DMA channels = 64 EDMA channels + 8 QDMA channels
+ *
+ * On davinci user can request for two kinds of Logical DMA channels
+ * DMA MasterChannel -> ParamEntry which is associated with a DMA channel.
+ * On Davinci there are (64 + 8) MasterChanneles
+ * MasterChannel can be triggered by an event or manually
+ *
+ * DMA SlaveChannel -> ParamEntry which is not associated with DMA cahnnel but
+ * which can be used to associate with MasterChannel.
+ * On Davinci there are (128-(64 + 8)) SlaveChannels
+ * SlaveChannel can only be triggered by a MasterChannel
+ *
+ */
+
+#ifndef EDMA_H_
+#define EDMA_H_
+
+/*Used by driver*/
+
+/**************************************************************************\
+* Register Overlay Structure for DRA
+\**************************************************************************/
+typedef struct {
+ unsigned int drae;
+ unsigned int draeh;
+} edmacc_dra_regs;
+
+/**************************************************************************\
+* Register Overlay Structure for QUEEVTENTRY
+\**************************************************************************/
+typedef struct {
+ unsigned int evt_entry;
+} edmacc_que_evtentry_regs;
+
+/**************************************************************************\
+* Register Overlay Structure for SHADOW
+\**************************************************************************/
+typedef struct {
+ unsigned int er;
+ unsigned int erh;
+ unsigned int ecr;
+ unsigned int ecrh;
+ unsigned int esr;
+ unsigned int esrh;
+ unsigned int cer;
+ unsigned int cerh;
+ unsigned int eer;
+ unsigned int eerh;
+ unsigned int eecr;
+ unsigned int eecrh;
+ unsigned int eesr;
+ unsigned int eesrh;
+ unsigned int ser;
+ unsigned int serh;
+ unsigned int secr;
+ unsigned int secrh;
+ unsigned char rsvd0[8];
+ unsigned int ier;
+ unsigned int ierh;
+ unsigned int iecr;
+ unsigned int iecrh;
+ unsigned int iesr;
+ unsigned int iesrh;
+ unsigned int ipr;
+ unsigned int iprh;
+ unsigned int icr;
+ unsigned int icrh;
+ unsigned int ieval;
+ unsigned char rsvd1[4];
+ unsigned int qer;
+ unsigned int qeer;
+ unsigned int qeecr;
+ unsigned int qeesr;
+ unsigned int qser;
+ unsigned int qsecr;
+ unsigned char rsvd2[360];
+} edmacc_shadow_regs;
+
+/**************************************************************************\
+* Register Overlay Structure for PARAMENTRY
+\**************************************************************************/
+typedef struct {
+ unsigned int opt;
+ unsigned int src;
+ unsigned int a_b_cnt;
+ unsigned int dst;
+ unsigned int src_dst_bidx;
+ unsigned int link_bcntrld;
+ unsigned int src_dst_cidx;
+ unsigned int ccnt;
+} edmacc_paramentry_regs;
+
+/**************************************************************************\
+* Register Overlay Structure
+\**************************************************************************/
+typedef struct {
+ unsigned int rev;
+ unsigned int cccfg;
+ unsigned char rsvd0[504];
+ unsigned int qchmap[8];
+ unsigned char rsvd1[32];
+ unsigned int dmaqnum[8];
+ unsigned int qdmaqnum;
+ unsigned char rsvd2[28];
+ unsigned int quetcmap;
+ unsigned int quepri;
+ unsigned char rsvd3[120];
+ unsigned int emr;
+ unsigned int emrh;
+ unsigned int emcr;
+ unsigned int emcrh;
+ unsigned int qemr;
+ unsigned int qemcr;
+ unsigned int ccerr;
+ unsigned int ccerrclr;
+ unsigned int eeval;
+ unsigned char rsvd4[28];
+ edmacc_dra_regs dra[4];
+ unsigned char rsvd5[32];
+ unsigned int qrae[4];
+ unsigned char rsvd6[112];
+ edmacc_que_evtentry_regs queevtentry[2][16];
+ unsigned char rsvd7[384];
+ unsigned int qstat[2];
+ unsigned char rsvd8[24];
+ unsigned int qwmthra;
+ unsigned int qwmthrb;
+ unsigned char rsvd9[24];
+ unsigned int ccstat;
+ unsigned char rsvd10[188];
+ unsigned int aetctl;
+ unsigned int aetstat;
+ unsigned int aetcmd;
+ unsigned char rsvd11[2292];
+ unsigned int er;
+ unsigned int erh;
+ unsigned int ecr;
+ unsigned int ecrh;
+ unsigned int esr;
+ unsigned int esrh;
+ unsigned int cer;
+ unsigned int cerh;
+ unsigned int eer;
+ unsigned int eerh;
+ unsigned int eecr;
+ unsigned int eecrh;
+ unsigned int eesr;
+ unsigned int eesrh;
+ unsigned int ser;
+ unsigned int serh;
+ unsigned int secr;
+ unsigned int secrh;
+ unsigned char rsvd12[8];
+ unsigned int ier;
+ unsigned int ierh;
+ unsigned int iecr;
+ unsigned int iecrh;
+ unsigned int iesr;
+ unsigned int iesrh;
+ unsigned int ipr;
+ unsigned int iprh;
+ unsigned int icr;
+ unsigned int icrh;
+ unsigned int ieval;
+ unsigned char rsvd13[4];
+ unsigned int qer;
+ unsigned int qeer;
+ unsigned int qeecr;
+ unsigned int qeesr;
+ unsigned int qser;
+ unsigned int qsecr;
+ unsigned char rsvd14[3944];
+ edmacc_shadow_regs shadow[4];
+ unsigned char rsvd15[6144];
+ edmacc_paramentry_regs paramentry[128];
+} edmacc_regs;
+
+#define CCINT0_INTERRUPT 16
+#define CCERRINT_INTERRUPT 17
+#define TCERRINT0_INTERRUPT 18
+#define TCERRINT1_INTERRUPT 19
+
+#define SAM (1)
+#define DAM (1<<1)
+#define SYNCDIM (1<<2)
+#define STATIC (1<<3)
+#define EDMA_FWID (0x7<<8)
+#define TCCMODE (0x1<<11)
+#define TCC (0x3f<<12)
+#define WIMODE (0x1<<19)
+#define TCINTEN (0x1<<20)
+#define ITCINTEN (0x1<<21)
+#define TCCHEN (0x1<<22)
+#define ITCCHEN (0x1<<23)
+#define SECURE (0x1<<30)
+#define PRIV (0x1<<31)
+
+#define TRWORD (0x7<<2)
+#define PAENTRY (0x1ff<<5)
+/*if changing the QDMA_TRWORD do appropriate change in davinci_start_dma */
+#define QDMA_TRWORD (7 & 0x7)
+
+/*Used by driver*/
+
+#define DAVINCI_EDMA_NUM_DMACH 64
+#define DAVINCI_EDMA_NUM_QDMACH 8
+#define DAVINCI_EDMA_NUM_PARAMENTRY 128
+#define DAVINCI_EDMA_NUM_EVQUE 2
+#define DAVINCI_EDMA_CHMAPEXIST 0
+#define DAVINCI_EDMA_NUM_REGIONS 4
+#define DAVINCI_EDMA_MEMPROTECT 0
+
+#define DAVINCI_NUM_UNUSEDCH 21
+
+#define TCC_ANY -1
+
+#define DAVINCI_EDMA_PARAM_ANY -2
+#define DAVINCI_DMA_CHANNEL_ANY -1
+#define DAVINCI_DMA_MCBSP_TX 2
+#define DAVINCI_DMA_MCBSP_RX 3
+#define DAVINCI_DMA_VPSS_HIST 4
+#define DAVINCI_DMA_VPSS_H3A 5
+#define DAVINCI_DMA_VPSS_PRVU 6
+#define DAVINCI_DMA_VPSS_RSZ 7
+#define DAVINCI_DMA_IMCOP_IMXINT 8
+#define DAVINCI_DMA_IMCOP_VLCDINT 9
+#define DAVINCI_DMA_IMCO_PASQINT 10
+#define DAVINCI_DMA_IMCOP_DSQINT 11
+#define DAVINCI_DMA_SPI_SPIX 16
+#define DAVINCI_DMA_SPI_SPIR 17
+#define DAVINCI_DMA_UART0_URXEVT0 18
+#define DAVINCI_DMA_UART0_UTXEVT0 19
+#define DAVINCI_DMA_UART1_URXEVT1 20
+#define DAVINCI_DMA_UART1_UTXEVT1 21
+#define DAVINCI_DMA_UART2_URXEVT2 22
+#define DAVINCI_DMA_UART2_UTXEVT2 23
+#define DAVINCI_DMA_MEMSTK_MSEVT 24
+#define DAVINCI_DMA_MMCRXEVT 26
+#define DAVINCI_DMA_MMCTXEVT 27
+#define DAVINCI_DMA_I2C_ICREVT 28
+#define DAVINCI_DMA_I2C_ICXEVT 29
+#define DAVINCI_DMA_GPIO_GPINT0 32
+#define DAVINCI_DMA_GPIO_GPINT1 33
+#define DAVINCI_DMA_GPIO_GPINT2 34
+#define DAVINCI_DMA_GPIO_GPINT3 35
+#define DAVINCI_DMA_GPIO_GPINT4 36
+#define DAVINCI_DMA_GPIO_GPINT5 37
+#define DAVINCI_DMA_GPIO_GPINT6 38
+#define DAVINCI_DMA_GPIO_GPINT7 39
+#define DAVINCI_DMA_GPIO_GPBNKINT0 40
+#define DAVINCI_DMA_GPIO_GPBNKINT1 41
+#define DAVINCI_DMA_GPIO_GPBNKINT2 42
+#define DAVINCI_DMA_GPIO_GPBNKINT3 43
+#define DAVINCI_DMA_GPIO_GPBNKINT4 44
+#define DAVINCI_DMA_TIMER0_TINT0 48
+#define DAVINCI_DMA_TIMER1_TINT1 49
+#define DAVINCI_DMA_TIMER2_TINT2 50
+#define DAVINCI_DMA_TIMER3_TINT3 51
+#define DAVINCI_DMA_PWM0 52
+#define DAVINCI_DMA_PWM1 53
+#define DAVINCI_DMA_PWM2 54
+#define DAVINCI_DMA_QDMA0 64
+#define DAVINCI_DMA_QDMA1 65
+#define DAVINCI_DMA_QDMA2 66
+#define DAVINCI_DMA_QDMA3 67
+#define DAVINCI_DMA_QDMA4 68
+#define DAVINCI_DMA_QDMA5 69
+#define DAVINCI_DMA_QDMA6 71
+#define DAVINCI_DMA_QDMA7 72
+
+/*ch_status paramater of callback function possible values*/
+#define DMA_COMPLETE 1
+#define DMA_CC_ERROR 2
+#define DMA_TC1_ERROR 3
+#define DMA_TC2_ERROR 4
+
+enum address_mode {
+ INCR = 0,
+ FIFO = 1
+};
+
+enum fifo_width {
+ W8BIT = 0,
+ W16BIT = 1,
+ W32BIT = 2,
+ W64BIT = 3,
+ W128BIT = 4,
+ W256BIT = 5
+};
+
+enum dma_event_q {
+ EVENTQ_0 = 0,
+ EVENTQ_1 = 1,
+ EVENTQ_DEFAULT = -1
+};
+
+enum sync_dimension {
+ ASYNC = 0,
+ ABSYNC = 1
+};
+
+/******************************************************************************
+ * davinci_request_dma - request for the Davinci DMA channel
+ *
+ * dev_id - DMA channel number
+ *
+ * EX: DAVINCI_DMA_MCBSP_TX - For requesting a DMA MasterChannel with MCBSP_TX
+ * event association
+ *
+ * DAVINCI_DMA_ANY - For requesting a DMA Masterchannel which does not has
+ * event association
+ *
+ * DAVINCI_DMA_LINK - for requesting a DMA SlaveChannel
+ *
+ * dev_name - name of the dma channel in human readable format
+ * callback - channel callback function (valied only if you are requesting
+ * for a DMA MasterChannel)
+ * data - private data for the channel to be requested
+ * lch - contains the device id allocated
+ * tcc - specifies the channel number on which the interrupt is
+ * generated
+ * Valied for QDMA and PARAM channes
+ * eventq_no - Event Queue no to which the channel will be associated with
+ * (valied only if you are requesting for a DMA MasterChannel)
+ * Values : EVENTQ_0/EVENTQ_1 for event queue 0/1.
+ * EVENTQ_DEFAULT for Default queue
+ *
+ * Return: zero on success,
+ * -EINVAL - if the requested channel is not supported on the ARM side events
+ * -EBUSY - if the requested channel is already in use
+ * EREQDMA - if failed to request the dma channel
+ *
+ *****************************************************************************/
+int davinci_request_dma(int dev_id,
+ const char *dev_name,
+ void (*callback) (int lch, unsigned short ch_status,
+ void *data), void *data, int *lch,
+ int *tcc, enum dma_event_q
+ );
+
+/******************************************************************************
+ * davinci_set_dma_src_params - DMA source parameters setup
+ *
+ * lch - channel for which the source parameters to be configured
+ * src_port - Source port address
+ * addressMode - indicates whether the address mode is FIFO or not
+ * fifoWidth - valied only if addressMode is FIFO, indicates the vidth of
+ * FIFO
+ * 0 - 8 bit
+ * 1 - 16 bit
+ * 2 - 32 bit
+ * 3 - 64 bit
+ * 4 - 128 bit
+ * 5 - 256 bit
+ *****************************************************************************/
+void davinci_set_dma_src_params(int lch, unsigned long src_port,
+ enum address_mode mode, enum fifo_width);
+
+/******************************************************************************
+ * davinci_set_dma_dest_params - DMA destination parameters setup
+ *
+ * lch - channel or param device for destination parameters to be
+ * configured
+ * dest_port - Destination port address
+ * addressMode - indicates whether the address mode is FIFO or not
+ * fifoWidth - valied only if addressMode is FIFO,indicates the vidth of FIFO
+ * 0 - 8 bit
+ * 1 - 16 bit
+ * 2 - 32 bit
+ * 3 - 64 bit
+ * 4 - 128 bit
+ * 5 - 256 bit
+ *
+ *****************************************************************************/
+void davinci_set_dma_dest_params(int lch, unsigned long dest_port,
+ enum address_mode mode, enum fifo_width);
+
+/******************************************************************************
+ * davinci_set_dma_src_index - DMA source index setup
+ *
+ * lch - channel or param device for configuration of source index
+ * srcbidx - source B-register index
+ * srccidx - source C-register index
+ *
+ *****************************************************************************/
+void davinci_set_dma_src_index(int lch, short srcbidx, short srccidx);
+
+/******************************************************************************
+ * davinci_set_dma_dest_index - DMA destination index setup
+ *
+ * lch - channel or param device for configuration of destination index
+ * destbidx - dest B-register index
+ * destcidx - dest C-register index
+ *
+ *****************************************************************************/
+void davinci_set_dma_dest_index(int lch, short destbidx, short destcidx);
+
+/******************************************************************************
+ * davinci_set_dma_transfer_params - DMA transfer parameters setup
+ *
+ * lch - channel or param device for configuration of aCount, bCount and
+ * cCount regs.
+ * aCnt - aCnt register value to be configured
+ * bCnt - bCnt register value to be configured
+ * cCnt - cCnt register value to be configured
+ *
+ *****************************************************************************/
+void davinci_set_dma_transfer_params(int lch, unsigned short acnt,
+ unsigned short bcnt, unsigned short ccnt,
+ unsigned short bcntrld,
+ enum sync_dimension sync_mode);
+
+/******************************************************************************
+ *
+ * davinci_set_dma_params -
+ * ARGUMENTS:
+ * lch - logical channel number
+ *
+ *****************************************************************************/
+void davinci_set_dma_params(int lch, edmacc_paramentry_regs * temp);
+
+/******************************************************************************
+ *
+ * davinci_get_dma_params -
+ * ARGUMENTS:
+ * lch - logical channel number
+ *
+ *****************************************************************************/
+void davinci_get_dma_params(int lch, edmacc_paramentry_regs * temp);
+
+/******************************************************************************
+ * davinci_start_dma - Starts the dma on the channel passed
+ *
+ * lch - logical channel number
+ *
+ * Note: This API can be used only on DMA MasterChannel
+ *
+ * Return: zero on success
+ * -EINVAL on failure, i.e if requested for the slave channels
+ *
+ *****************************************************************************/
+int davinci_start_dma(int lch);
+
+/******************************************************************************
+ * davinci_stop_dma - Stops the dma on the channel passed
+ *
+ * lch - logical channel number
+ *
+ * Note: This API can be used on MasterChannel and SlaveChannel
+ *****************************************************************************/
+void davinci_stop_dma(int lch);
+
+/******************************************************************************
+ * davinci_dma_link_lch - Link two Logical channels
+ *
+ * lch_head - logical channel number, in which the link field is linked to the
+ * the param pointed to by lch_queue
+ * Can be a MasterChannel or SlaveChannel
+ * lch_queue - logical channel number or the param entry number, which is to be
+ * linked to the lch_head
+ * Must be a SlaveChannel
+ *
+ * |---------------|
+ * v |
+ * Ex: ch1--> ch2-->ch3-->ch4--|
+ *
+ * ch1 must be a MasterChannel
+ *
+ * ch2, ch3, ch4 must be SlaveChannels
+ *
+ * Note: After channel linking,the user should not update any PaRam entry
+ * of MasterChannel ( In the above example ch1 )
+ *
+ *****************************************************************************/
+void davinci_dma_link_lch(int lch_head, int lch_queue);
+
+/******************************************************************************
+ * davinci_dma_unlink_lch - unlink the two logical channels passed through by
+ * setting the link field of head to 0xffff.
+ *
+ * lch_head - logical channel number, from which the link field is to be
+ * removed
+ * lch_queue - logical channel number or the param entry number,which is to be
+ * unlinked from lch_head
+ *
+ *****************************************************************************/
+void davinci_dma_unlink_lch(int lch_head, int lch_queue);
+
+/******************************************************************************
+ *
+ * DMA channel chain - chains the two logical channels passed through by
+ * ARGUMENTS:
+ * lch_head - logical channel number, from which the link field is to be removed
+ * lch_queue - logical channel number or the param entry number, which is to be
+ * unlinked from lch_head
+ *
+ *****************************************************************************/
+void davinci_dma_chain_lch(int lch_head, int lch_queue);
+
+/******************************************************************************
+ *
+ * DMA channel unchain - unchain the two logical channels passed through by
+ * ARGUMENTS:
+ * lch_head - logical channel number, from which the link field is to be removed
+ * lch_queue - logical channel number or the param entry number, which is to be
+ * unlinked from lch_head
+ *
+ *****************************************************************************/
+void davinci_dma_unchain_lch(int lch_head, int lch_queue);
+
+/******************************************************************************
+ *
+ * Free DMA channel - Free the dma channel number passed
+ *
+ * ARGUMENTS:
+ * lch - dma channel number to get free
+ *
+ *****************************************************************************/
+void davinci_free_dma(int lch);
+
+#endif
diff --git a/include/asm-arm/arch-davinci/gpio.h b/include/asm-arm/arch-davinci/gpio.h
index ea24a0e..2e35d8c 100644
--- a/include/asm-arm/arch-davinci/gpio.h
+++ b/include/asm-arm/arch-davinci/gpio.h
@@ -64,11 +64,11 @@
void *__iomem ptr;
if (gpio < 32)
- ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10);
+ ptr = (void *__iomem) IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10);
else if (gpio < 64)
- ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x38);
+ ptr = (void *__iomem) IO_ADDRESS(DAVINCI_GPIO_BASE + 0x38);
else if (gpio < DAVINCI_N_GPIO)
- ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x60);
+ ptr = (void *__iomem) IO_ADDRESS(DAVINCI_GPIO_BASE + 0x60);
else
ptr = NULL;
return ptr;
@@ -122,7 +122,7 @@
static inline int gpio_get_value(unsigned gpio)
{
- struct gpio_controller *__iomem g;
+ struct gpio_controller *__iomem g;
if (!__builtin_constant_p(gpio))
return __gpio_get(gpio);
diff --git a/include/asm-arm/arch-davinci/hdrc_cnf.h b/include/asm-arm/arch-davinci/hdrc_cnf.h
new file mode 100644
index 0000000..3811ce4
--- /dev/null
+++ b/include/asm-arm/arch-davinci/hdrc_cnf.h
@@ -0,0 +1,165 @@
+/*
+ * USB High-Speed Multi-Point Dual-Role Controller Configuration
+ *
+ * Copyright Mentor Graphics Corporation and Licensors 2004
+ * Copyright (C) 2005 by Texas Instruments
+ *
+ * This file contains configuration constants for the (m)hdrc
+ * silicon as integrated into DaVinci CPUs.
+ */
+
+#ifndef __ARCH_MUSB_HDRC_CNF
+#define __ARCH_MUSB_HDRC_CNF
+
+/* ** Number of Tx endpoints ** */
+/* Legal values are 1 - 16 (this value includes EP0) */
+#define MUSB_C_NUM_EPT 5
+
+/* ** Number of Rx endpoints ** */
+/* Legal values are 1 - 16 (this value includes EP0) */
+#define MUSB_C_NUM_EPR 5
+
+/* ** Endpoint 1 to 15 direction types ** */
+/* C_EP1_DEF is defined if either Tx endpoint 1 or Rx endpoint 1 are used */
+#define MUSB_C_EP1_DEF
+
+/* C_EP1_TX_DEF is defined if Tx endpoint 1 is used */
+#define MUSB_C_EP1_TX_DEF
+
+/* C_EP1_RX_DEF is defined if Rx endpoint 1 is used */
+#define MUSB_C_EP1_RX_DEF
+
+/* C_EP1_TOR_DEF is defined if Tx endpoint 1 and Rx endpoint 1 share a FIFO */
+/*`define C_EP1_TOR_DEF */
+
+/* C_EP1_TAR_DEF is defined if both Tx endpoint 1 and Rx endpoint 1 are used */
+/* and do not share a FIFO */
+#define MUSB_C_EP1_TAR_DEF
+
+/* Similarly for all other used endpoints */
+#define MUSB_C_EP2_DEF
+#define MUSB_C_EP2_TX_DEF
+#define MUSB_C_EP2_RX_DEF
+#define MUSB_C_EP2_TAR_DEF
+#define MUSB_C_EP3_DEF
+#define MUSB_C_EP3_TX_DEF
+#define MUSB_C_EP3_RX_DEF
+#define MUSB_C_EP3_TAR_DEF
+#define MUSB_C_EP4_DEF
+#define MUSB_C_EP4_TX_DEF
+#define MUSB_C_EP4_RX_DEF
+#define MUSB_C_EP4_TAR_DEF
+
+/* ** Endpoint 1 to 15 FIFO address bits ** */
+/* Legal values are 3 to 13 - corresponding to FIFO sizes of 8 to 8192 bytes. */
+/* If an Tx endpoint shares a FIFO with an Rx endpoint then the Rx FIFO size */
+/* must be the same as the Tx FIFO size. */
+/* All endpoints 1 to 15 must be defined, unused endpoints should be set to 2. */
+#define MUSB_C_EP1T_BITS 5
+#define MUSB_C_EP1R_BITS 5
+#define MUSB_C_EP2T_BITS 5
+#define MUSB_C_EP2R_BITS 5
+#define MUSB_C_EP3T_BITS 3
+#define MUSB_C_EP3R_BITS 3
+#define MUSB_C_EP4T_BITS 3
+#define MUSB_C_EP4R_BITS 3
+
+#define MUSB_C_EP5T_BITS 2
+#define MUSB_C_EP5R_BITS 2
+#define MUSB_C_EP6T_BITS 2
+#define MUSB_C_EP6R_BITS 2
+#define MUSB_C_EP7T_BITS 2
+#define MUSB_C_EP7R_BITS 2
+#define MUSB_C_EP8T_BITS 2
+#define MUSB_C_EP8R_BITS 2
+#define MUSB_C_EP9T_BITS 2
+#define MUSB_C_EP9R_BITS 2
+#define MUSB_C_EP10T_BITS 2
+#define MUSB_C_EP10R_BITS 2
+#define MUSB_C_EP11T_BITS 2
+#define MUSB_C_EP11R_BITS 2
+#define MUSB_C_EP12T_BITS 2
+#define MUSB_C_EP12R_BITS 2
+#define MUSB_C_EP13T_BITS 2
+#define MUSB_C_EP13R_BITS 2
+#define MUSB_C_EP14T_BITS 2
+#define MUSB_C_EP14R_BITS 2
+#define MUSB_C_EP15T_BITS 2
+#define MUSB_C_EP15R_BITS 2
+
+/* Define the following constant if the USB2.0 Transceiver Macrocell data width is 16-bits. */
+/* `define C_UTM_16 */
+
+/* Define this constant if the CPU uses big-endian byte ordering. */
+/*`define C_BIGEND */
+
+/* Define the following constant if any Tx endpoint is required to support multiple bulk packets. */
+/* `define C_MP_TX */
+
+/* Define the following constant if any Rx endpoint is required to support multiple bulk packets. */
+/* `define C_MP_RX */
+
+/* Define the following constant if any Tx endpoint is required to support high bandwidth ISO. */
+/* `define C_HB_TX */
+
+/* Define the following constant if any Rx endpoint is required to support high bandwidth ISO. */
+/* `define C_HB_RX */
+
+/* Define the following constant if software connect/disconnect control is required. */
+#define MUSB_C_SOFT_CON
+
+/* Define the following constant if Vendor Control Registers are required. */
+/* `define C_VEND_REG */
+
+/* Vendor control register widths. */
+#define MUSB_C_VCTL_BITS 4
+#define MUSB_C_VSTAT_BITS 8
+
+
+/* Define the following constant to include a DMA controller. */
+/*`define C_DMA */
+
+/* Define the following constant if 2 or more DMA channels are required. */
+/*`define C_DMA2 */
+
+/* Define the following constant if 3 or more DMA channels are required. */
+/*`define C_DMA3 */
+
+/* Define the following constant if 4 or more DMA channels are required. */
+/*`define C_DMA4 */
+
+/* Define the following constant if 5 or more DMA channels are required. */
+/*`define C_DMA5 */
+
+/* Define the following constant if 6 or more DMA channels are required. */
+/*`define C_DMA6 */
+
+/* Define the following constant if 7 or more DMA channels are required. */
+/*`define C_DMA7 */
+
+/* Define the following constant if 8 or more DMA channels are required. */
+/*`define C_DMA8 */
+
+
+/* ** Enable Dynamic FIFO Sizing ** */
+#define MUSB_C_DYNFIFO_DEF
+
+/* ** Derived constants ** */
+/* The following constants are derived from the previous configuration constants */
+
+/* Total number of endpoints
+ * Legal values are 2 - 16
+ * This must be equal to the larger of C_NUM_EPT, C_NUM_EPR
+ */
+#define MUSB_C_NUM_EPS 5
+
+/* C_EPMAX_BITS is equal to the largest endpoint FIFO word address bits */
+#define MUSB_C_EPMAX_BITS 11
+
+/* C_RAM_BITS is the number of address bits required to address the RAM (32-bit
+ * addresses). It is defined as log2 of the sum of 2** of all the endpoint FIFO
+ * dword address bits (rounded up).
+ */
+#define MUSB_C_RAM_BITS 10
+
+#endif /* __ARCH_MUSB_HDRC_CNF */
diff --git a/include/asm-arm/arch-davinci/i2c-client.h b/include/asm-arm/arch-davinci/i2c-client.h
new file mode 100644
index 0000000..3619546
--- /dev/null
+++ b/include/asm-arm/arch-davinci/i2c-client.h
@@ -0,0 +1,34 @@
+/*
+ * include/asm-arm/arch-davinci/i2c-client.h
+ *
+ * Copyright (C) 2006 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/* i2c-client.h */
+
+typedef enum {
+ USB_DRVVBUS = 0,
+ VDDIMX_EN = 1,
+ VLYNQ_ON = 2,
+ CF_RESET = 3,
+ WLAN_RESET = 4,
+ ATA_SEL = 5,
+ CF_SEL = 6
+} u35_expander_ops;
+
+int davinci_i2c_expander_op (u16 client_addr, u35_expander_ops pin, u8 val);
+int davinci_i2c_write(u8 size, u8 * val, u16 client_addr);
+int davinci_i2c_read(u8 size, u8 * val, u16 client_addr);
diff --git a/include/asm-arm/arch-davinci/mcbsp.h b/include/asm-arm/arch-davinci/mcbsp.h
new file mode 100644
index 0000000..603f2da
--- /dev/null
+++ b/include/asm-arm/arch-davinci/mcbsp.h
@@ -0,0 +1,255 @@
+/*
+ * include/asm-arm/arch-davinci/mcbsp.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ * DAVINCI McBSP driver Info
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __ASM_ARCH_DAVINCI_MCBSP_H
+#define __ASM_ARCH_DAVINCI_MCBSP_H
+
+#include <asm/hardware.h>
+#include <asm/arch/irqs.h>
+
+#define DAVINCI_MCBSP1_BASE DAVINCI_MCBSP_BASE
+#define DAVINCI_DMA_MCBSP1_RX 3
+#define DAVINCI_DMA_MCBSP1_TX 2
+
+#define DAVINCI_McBSP1RX IRQ_MBRINT
+#define DAVINCI_McBSP1TX IRQ_MBXINT
+
+#define DRR1 0x00
+#define DRR2 0x02
+#define DXR1 0x04
+#define DXR2 0x06
+#define SPCR1 0x08
+#define SPCR2 0x0a
+#define RCR1 0x0c
+#define RCR2 0x0e
+#define XCR1 0x10
+#define XCR2 0x12
+#define SRGR1 0x14
+#define SRGR2 0x16
+#define MCR1 0x18
+#define MCR2 0x1a
+#define RCERA 0x1c
+#define RCERB 0x1e
+#define XCERA 0x20
+#define XCERB 0x22
+#define PCR0 0x24
+#define PCR1 0x26
+#define RCERC 0x28
+#define RCERD 0x2a
+#define XCERC 0x2c
+#define XCERD 0x2e
+#define RCERE 0x30
+#define RCERF 0x32
+#define XCERE 0x34
+#define XCERF 0x36
+#define RCERG 0x38
+#define RCERH 0x3a
+#define XCERG 0x3c
+#define XCERH 0x3e
+
+#define DAVINCI_MAX_MCBSP_COUNT 1
+
+/********************** McBSP SPCR1 bit definitions ***********************/
+#define RRST 0x0001
+#define RRDY 0x0002
+#define RFULL 0x0004
+#define RSYNC_ERR 0x0008
+#define RINTM(value) ((value)<<4) /* bits 4:5 */
+#define ABIS 0x0040
+#define DXENA 0x0080
+#define CLKSTP(value) ((value)<<11) /* bits 11:12 */
+#define RJUST(value) ((value)<<13) /* bits 13:14 */
+#define DLB 0x8000
+
+/********************** McBSP SPCR2 bit definitions ***********************/
+#define XRST 0x0001
+#define XRDY 0x0002
+#define XEMPTY 0x0004
+#define XSYNC_ERR 0x0008
+#define XINTM(value) ((value)<<4) /* bits 4:5 */
+#define GRST 0x0040
+#define FRST 0x0080
+#define SOFT 0x0100
+#define FREE 0x0200
+
+/********************** McBSP PCR bit definitions *************************/
+#define CLKRP 0x0001
+#define CLKXP 0x0002
+#define FSRP 0x0004
+#define FSXP 0x0008
+#define DR_STAT 0x0010
+#define DX_STAT 0x0020
+#define CLKS_STAT 0x0040
+#define SCLKME 0x0080
+#define CLKRM 0x0100
+#define CLKXM 0x0200
+#define FSRM 0x0400
+#define FSXM 0x0800
+#define RIOEN 0x1000
+#define XIOEN 0x2000
+#define IDLE_EN 0x4000
+
+/********************** McBSP RCR1 bit definitions ************************/
+#define RWDLEN1(value) ((value)<<5) /* Bits 5:7 */
+#define RFRLEN1(value) ((value)<<8) /* Bits 8:14 */
+
+/********************** McBSP XCR1 bit definitions ************************/
+#define XWDLEN1(value) ((value)<<5) /* Bits 5:7 */
+#define XFRLEN1(value) ((value)<<8) /* Bits 8:14 */
+
+/*********************** McBSP RCR2 bit definitions ***********************/
+#define RDATDLY(value) (value) /* Bits 0:1 */
+#define RFIG 0x0004
+#define RCOMPAND(value) ((value)<<3) /* Bits 3:4 */
+#define RWDLEN2(value) ((value)<<5) /* Bits 5:7 */
+#define RFRLEN2(value) ((value)<<8) /* Bits 8:14 */
+#define RPHASE 0x8000
+
+/*********************** McBSP XCR2 bit definitions ***********************/
+#define XDATDLY(value) (value) /* Bits 0:1 */
+#define XFIG 0x0004
+#define XCOMPAND(value) ((value)<<3) /* Bits 3:4 */
+#define XWDLEN2(value) ((value)<<5) /* Bits 5:7 */
+#define XFRLEN2(value) ((value)<<8) /* Bits 8:14 */
+#define XPHASE 0x8000
+
+/********************* McBSP SRGR1 bit definitions ************************/
+#define CLKGDV(value) (value) /* Bits 0:7 */
+#define FWID(value) ((value)<<8) /* Bits 8:15 */
+
+/********************* McBSP SRGR2 bit definitions ************************/
+#define FPER(value) (value) /* Bits 0:11 */
+#define FSGM 0x1000
+#define CLKSM 0x2000
+#define CLKSP 0x4000
+#define GSYNC 0x8000
+
+/********************* McBSP MCR1 bit definitions *************************/
+#define RMCM 0x0001
+#define RCBLK(value) ((value)<<2) /* Bits 2:4 */
+#define RPABLK(value) ((value)<<5) /* Bits 5:6 */
+#define RPBBLK(value) ((value)<<7) /* Bits 7:8 */
+
+/********************* McBSP MCR2 bit definitions *************************/
+#define XMCM(value) (value) /* Bits 0:1 */
+#define XCBLK(value) ((value)<<2) /* Bits 2:4 */
+#define XPABLK(value) ((value)<<5) /* Bits 5:6 */
+#define XPBBLK(value) ((value)<<7) /* Bits 7:8 */
+
+/* we don't do multichannel for now */
+struct davinci_mcbsp_reg_cfg {
+ u16 spcr2;
+ u16 spcr1;
+ u16 rcr2;
+ u16 rcr1;
+ u16 xcr2;
+ u16 xcr1;
+ u16 srgr2;
+ u16 srgr1;
+ u16 mcr2;
+ u16 mcr1;
+ u16 pcr2;
+ u16 pcr0;
+ u16 rcerc;
+ u16 rcerd;
+ u16 xcerc;
+ u16 xcerd;
+ u16 rcere;
+ u16 rcerf;
+ u16 xcere;
+ u16 xcerf;
+ u16 rcerg;
+ u16 rcerh;
+ u16 xcerg;
+ u16 xcerh;
+};
+
+typedef enum {
+ DAVINCI_MCBSP1 = 0,
+} davinci_mcbsp_id;
+
+typedef enum {
+ DAVINCI_MCBSP_WORD_8 = 0,
+ DAVINCI_MCBSP_WORD_12,
+ DAVINCI_MCBSP_WORD_16,
+ DAVINCI_MCBSP_WORD_20,
+ DAVINCI_MCBSP_WORD_24,
+ DAVINCI_MCBSP_WORD_32,
+} davinci_mcbsp_word_length;
+
+typedef enum {
+ DAVINCI_MCBSP_CLK_RISING = 0,
+ DAVINCI_MCBSP_CLK_FALLING,
+} davinci_mcbsp_clk_polarity;
+
+typedef enum {
+ DAVINCI_MCBSP_FS_ACTIVE_HIGH = 0,
+ DAVINCI_MCBSP_FS_ACTIVE_LOW,
+} davinci_mcbsp_fs_polarity;
+
+typedef enum {
+ DAVINCI_MCBSP_CLK_STP_MODE_NO_DELAY = 0,
+ DAVINCI_MCBSP_CLK_STP_MODE_DELAY,
+} davinci_mcbsp_clk_stp_mode;
+
+/******* SPI specific mode **********/
+typedef enum {
+ DAVINCI_MCBSP_SPI_MASTER = 0,
+ DAVINCI_MCBSP_SPI_SLAVE,
+} davinci_mcbsp_spi_mode;
+
+struct davinci_mcbsp_spi_cfg {
+ davinci_mcbsp_spi_mode spi_mode;
+ davinci_mcbsp_clk_polarity rx_clock_polarity;
+ davinci_mcbsp_clk_polarity tx_clock_polarity;
+ davinci_mcbsp_fs_polarity fsx_polarity;
+ u8 clk_div;
+ davinci_mcbsp_clk_stp_mode clk_stp_mode;
+ davinci_mcbsp_word_length word_length;
+};
+
+void davinci_mcbsp_config(unsigned int id,
+ const struct davinci_mcbsp_reg_cfg *config);
+int davinci_mcbsp_request(unsigned int id);
+void davinci_mcbsp_free(unsigned int id);
+void davinci_mcbsp_start(unsigned int id);
+void davinci_mcbsp_stop(unsigned int id);
+void davinci_mcbsp_xmit_word(unsigned int id, u32 word);
+u32 davinci_mcbsp_recv_word(unsigned int id);
+
+int davinci_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer,
+ unsigned int length);
+int davinci_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer,
+ unsigned int length);
+
+/* SPI specific API */
+void davinci_mcbsp_set_spi_mode(unsigned int id,
+ const struct davinci_mcbsp_spi_cfg *spi_cfg);
+
+#endif
diff --git a/include/asm-arm/arch-davinci/system.h b/include/asm-arm/arch-davinci/system.h
index 440ac51..851d341 100644
--- a/include/asm-arm/arch-davinci/system.h
+++ b/include/asm-arm/arch-davinci/system.h
@@ -18,7 +18,7 @@
static void arch_idle(void)
{
- cpu_do_idle();
+ cpu_do_idle();
}
static void arch_reset(char mode)
@@ -26,4 +26,4 @@
davinci_watchdog_reset();
}
-#endif /* __ASM_ARCH_SYSTEM_H */
+#endif /* __ASM_ARCH_SYSTEM_H */
diff --git a/include/asm-arm/arch-davinci/timex.h b/include/asm-arm/arch-davinci/timex.h
index 5282756..e4ec97f 100644
--- a/include/asm-arm/arch-davinci/timex.h
+++ b/include/asm-arm/arch-davinci/timex.h
@@ -12,6 +12,6 @@
#define __ASM_ARCH_TIMEX_H
/* The source frequency for the timers is the 27MHz clock */
-#define CLOCK_TICK_RATE 27000000
+#define CLOCK_TICK_RATE 27000000
-#endif /* __ASM_ARCH_TIMEX_H__ */
+#endif /* __ASM_ARCH_TIMEX_H__ */
diff --git a/include/asm-arm/memory.h b/include/asm-arm/memory.h
index d9bfb39..6a779f0 100644
--- a/include/asm-arm/memory.h
+++ b/include/asm-arm/memory.h
@@ -27,6 +27,8 @@
#include <asm/arch/memory.h>
#include <asm/sizes.h>
+#ifdef __KERNEL__
+
#ifdef CONFIG_MMU
#ifndef TASK_SIZE
@@ -328,4 +330,6 @@
#include <asm-generic/memory_model.h>
+#endif // __KERNEL__
+
#endif
diff --git a/include/linux/ide.h b/include/linux/ide.h
index b9f66c1..0cd8b9d 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -206,7 +206,7 @@
ide_rz1000, ide_trm290,
ide_cmd646, ide_cy82c693, ide_4drives,
ide_pmac, ide_etrax100, ide_acorn,
- ide_au1xxx, ide_forced
+ ide_au1xxx, ide_palm3710, ide_forced
} hwif_chipset_t;
/*
diff --git a/include/media/ccdc_davinci.h b/include/media/ccdc_davinci.h
new file mode 100644
index 0000000..9f0a08d
--- /dev/null
+++ b/include/media/ccdc_davinci.h
@@ -0,0 +1,144 @@
+/*
+ *
+ * Copyright (C) 2006 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/* ccdc_davinci.h */
+
+#ifndef CCDC_DAVINCI_H
+#define CCDC_DAVINCI_H
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+#include <asm/arch/hardware.h>
+#include <asm/io.h>
+#endif
+
+#include <linux/videodev.h>
+
+typedef enum ccdc_pixfmt {
+ CCDC_PIXFMT_RAW = 0,
+ CCDC_PIXFMT_YCBCR_16BIT = 1,
+ CCDC_PIXFMT_YCBCR_8BIT = 2
+} ccdc_pixfmt;
+
+typedef enum ccdc_frmfmt {
+ CCDC_FRMFMT_PROGRESSIVE = 0,
+ CCDC_FRMFMT_INTERLACED = 1
+} ccdc_frmfmt;
+
+typedef enum ccdc_pinpol {
+ CCDC_PINPOL_POSITIVE = 0,
+ CCDC_PINPOL_NEGATIVE = 1
+} ccdc_pinpol;
+
+/* PIXEL ORDER IN MEMORY from LSB to MSB */
+/* only applicable for 8-bit input mode */
+typedef enum ccdc_pixorder {
+ CCDC_PIXORDER_CBYCRY = 1,
+ CCDC_PIXORDER_YCBYCR = 0
+} ccdc_pixorder;
+
+typedef enum ccdc_buftype {
+ CCDC_BUFTYPE_FLD_INTERLEAVED,
+ CCDC_BUFTYPE_FLD_SEPARATED
+} ccdc_buftype;
+
+typedef struct v4l2_rect ccdc_imgwin;
+
+typedef struct ccdc_params_ycbcr {
+ ccdc_pixfmt pix_fmt; /* pixel format */
+ ccdc_frmfmt frm_fmt; /* progressive or interlaced frame */
+ ccdc_imgwin win; /* video window */
+ ccdc_pinpol fid_pol; /* field id polarity */
+ ccdc_pinpol vd_pol; /* vertical sync polarity */
+ ccdc_pinpol hd_pol; /* horizontal sync polarity */
+ int bt656_enable; /* enable BT.656 embedded sync mode */
+ ccdc_pixorder pix_order;/* cb:y:cr:y or y:cb:y:cr in memory */
+ ccdc_buftype buf_type; /* interleaved or separated fields */
+} ccdc_params_ycbcr;
+
+#ifdef __KERNEL__
+/**************************************************************************\
+* Register OFFSET Definitions
+\**************************************************************************/
+#define PID 0x0
+#define PCR 0x4
+#define SYN_MODE 0x8
+#define HD_VD_WID 0xc
+#define PIX_LINES 0x10
+#define HORZ_INFO 0x14
+#define VERT_START 0x18
+#define VERT_LINES 0x1c
+#define CULLING 0x20
+#define HSIZE_OFF 0x24
+#define SDOFST 0x28
+#define SDR_ADDR 0x2c
+#define CLAMP 0x30
+#define DCSUB 0x34
+#define COLPTN 0x38
+#define BLKCMP 0x3c
+#define FPC 0x40
+#define FPC_ADDR 0x44
+#define VDINT 0x48
+#define ALAW 0x4c
+#define REC656IF 0x50
+#define CCDCFG 0x54
+#define FMTCFG 0x58
+#define FMT_HORZ 0x5c
+#define FMT_VERT 0x50
+#define FMT_ADDR0 0x64
+#define FMT_ADDR1 0x68
+#define FMT_ADDR2 0x6c
+#define FMT_ADDR3 0x70
+#define FMT_ADDR4 0x74
+#define FMT_ADDR5 0x78
+#define FMT_ADDR6 0x7c
+#define FMT_ADDR7 0x80
+#define PRGEVEN_0 0x84
+#define PRGEVEN_1 0x88
+#define PRGODD_0 0x8c
+#define PRGODD_1 0x90
+#define VP_OUT 0x94
+
+#define CCDC_IOBASE (0x01c70400)
+
+#define regw(val, reg) davinci_writel(val, (reg)+CCDC_IOBASE)
+#define regr(reg) davinci_readl((reg)+CCDC_IOBASE)
+
+extern void ccdc_reset(void);
+extern void ccdc_config_ycbcr(ccdc_params_ycbcr * params);
+extern void ccdc_setwin(ccdc_params_ycbcr * params);
+
+/* inline functions that must be fast because they are called frequently */
+static inline void ccdc_enable(int flag)
+{
+ regw(flag, PCR);
+}
+
+static inline void ccdc_setfbaddr(unsigned long paddr)
+{
+ regw(paddr & 0xffffffe0, SDR_ADDR);
+}
+
+static inline int ccdc_getfid(void)
+{
+ int fid = (regr(SYN_MODE) >> 15) & 0x1;
+ return fid;
+}
+#endif
+
+#endif /* CCDC_DAVINCI_H */
diff --git a/include/media/davinci_vpfe.h b/include/media/davinci_vpfe.h
new file mode 100644
index 0000000..26e7b2c
--- /dev/null
+++ b/include/media/davinci_vpfe.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2006 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/* davinci_vpfe.h */
+
+#ifndef DAVINCI_VPFE_H
+#define DAVINCI_VPFE_H
+#ifdef __KERNEL__
+#include <media/v4l2-dev.h>
+#endif
+
+#include <media/ccdc_davinci.h>
+#include <media/tvp5146.h>
+
+#define TRUE 1
+#define FALSE 0
+
+/* vpfe specific video standards */
+#define VPFE_STD_625_50_SQP ((V4L2_STD_625_50)<<32)
+#define VPFE_STD_525_60_SQP ((V4L2_STD_525_60)<<32)
+#define VPFE_STD_AUTO ((v4l2_std_id)(0x1000000000000000ULL))
+#define VPFE_STD_AUTO_SQP ((v4l2_std_id)(0x2000000000000000ULL))
+
+#define VPFE_CMD_CONFIG_CCDC _IOW('V',BASE_VIDIOC_PRIVATE + 1,ccdc_params_ycbcr)
+#define VPFE_CMD_LATEST_FRM_ONLY _IOW('V',BASE_VIDIOC_PRIVATE + 2,int)
+#define VPFE_CMD_CONFIG_TVP5146 _IOW('V',BASE_VIDIOC_PRIVATE + 3,tvp5146_params)
+
+/* settings for commonly used video formats */
+#define VPFE_WIN_NTSC {0,0,720,480}
+#define VPFE_WIN_PAL {0,0,720,576}
+#define VPFE_WIN_NTSC_SP {0,0,640,480} /* ntsc square pixel */
+#define VPFE_WIN_PAL_SP {0,0,768,576} /* pal square pixel */
+#define VPFE_WIN_CIF {0,0,352,288}
+#define VPFE_WIN_QCIF {0,0,176,144}
+#define VPFE_WIN_QVGA {0,0,320,240}
+#define VPFE_WIN_SIF {0,0,352,240}
+
+
+#ifdef __KERNEL__
+
+#include <media/video-buf.h>
+
+#define VPFE_MAJOR_RELEASE 0
+#define VPFE_MINOR_RELEASE 0
+#define VPFE_BUILD 1
+
+#define VPFE_VERSION_CODE \
+ (VPFE_MAJOR_RELEASE<<16) | (VPFE_MINOR_RELEASE<<8) | VPFE_BUILD
+
+/* By default, the driver is setup for auto-swich mode */
+#define VPFE_DEFAULT_STD VPFE_STD_AUTO
+
+#define VPFE_PIXELASPECT_NTSC {11, 10}
+#define VPFE_PIXELASPECT_PAL {54, 59}
+#define VPFE_PIXELASPECT_NTSC_SP {1, 1}
+#define VPFE_PIXELASPECT_PAL_SP {1, 1}
+#define VPFE_PIXELASPECT_DEFAULT {1, 1}
+
+#define VPFE_MAX_FRAME_WIDTH 768 /* account for PAL Square pixel mode */
+#define VPFE_MAX_FRAME_HEIGHT 576 /* account for PAL */
+/* 4:2:2 data */
+#define VPFE_MAX_FBUF_SIZE (VPFE_MAX_FRAME_WIDTH*VPFE_MAX_FRAME_HEIGHT*2)
+/* frame buffers allocate at driver initialization time */
+#define VPFE_DEFNUM_FBUFS 3
+
+#define VPFE_MAX_FBUF_ORDER \
+ get_order(roundup_pow_of_two(VPFE_MAX_FBUF_SIZE))
+
+/* device object */
+typedef struct vpfe_obj {
+ struct video_device *video_dev;
+ struct videobuf_queue bufqueue;/* queue with frame buffers */
+ struct list_head dma_queue;
+ u32 latest_only; /* indicate whether to return the most */
+ /* recent captured buffers only */
+ u32 usrs;
+ u32 io_usrs;
+ struct v4l2_prio_state prio;
+ v4l2_std_id std;
+ struct v4l2_rect vwin;
+ struct v4l2_rect bounds;
+ struct v4l2_fract pixelaspect;
+ spinlock_t irqlock;
+ struct semaphore lock;
+ enum v4l2_field field;
+ u32 pixelfmt;
+ u32 numbuffers;
+ u8* fbuffers[VIDEO_MAX_FRAME];
+ struct videobuf_buffer *curFrm;
+ struct videobuf_buffer *nextFrm;
+ int field_id;
+ int mode_changed;
+ int started;
+ int field_offset;
+ tvp5146_params tvp5146_params;
+ ccdc_params_ycbcr ccdc_params;
+} vpfe_obj;
+
+/* file handle */
+typedef struct vpfe_fh {
+ struct vpfe_obj *dev;
+ int io_allowed;
+ enum v4l2_priority prio;
+} vpfe_fh;
+#endif
+
+#endif /* DAVINCI_VPFE_H */
diff --git a/include/media/tvp5146.h b/include/media/tvp5146.h
new file mode 100644
index 0000000..c82935f
--- /dev/null
+++ b/include/media/tvp5146.h
@@ -0,0 +1,104 @@
+/*
+ *
+ *
+ * Copyright (C) 2006 Texas Instruments Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/* tvp5146.h file */
+
+#ifndef TVP5146_H
+#define TVP5146_H
+
+#ifdef TRUE
+#undef TRUE
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+
+#define TRUE 1
+#define FALSE 0
+
+/* analog muxing mode */
+#define TVP5146_AMUX_COMPOSITE 0
+#define TVP5146_AMUX_SVIDEO 1
+
+typedef enum {
+ TVP5146_MODE_INV = -1,
+ TVP5146_MODE_AUTO = 0, /* autoswitch mode (default) */
+ TVP5146_MODE_NTSC = 1, /* (M, J) NTSC 525-line */
+ TVP5146_MODE_PAL = 2, /* (B, D, G, H, I, N) PAL */
+ TVP5146_MODE_PAL_M = 3, /* (M) PAL 525-line */
+ TVP5146_MODE_PAL_CN = 4, /* (Combination-N) PAL */
+ TVP5146_MODE_NTSC_443 = 5, /* NTSC 4.43 525-line */
+ TVP5146_MODE_SECAM = 6, /* SECAM */
+ TVP5146_MODE_PAL_60 = 7, /* PAL 60 525-line */
+ TVP5146_MODE_AUTO_SQP = 8, /* autoswitch mode (default) */
+ TVP5146_MODE_NTSC_SQP = 9, /* (M, J) NTSC 525-line */
+ TVP5146_MODE_PAL_SQP = 0xA, /* (B, D, G, H, I, N) PAL */
+ TVP5146_MODE_PAL_M_SQP = 0xB, /* (M) PAL 525-line */
+ TVP5146_MODE_PAL_CN_SQP = 0xC, /* (Combination-N) PAL */
+ TVP5146_MODE_NTSC_443_SQP = 0xD,/* NTSC 4.43 525-line */
+ TVP5146_MODE_SECAM_SQP = 0xE, /* SECAM */
+ TVP5146_MODE_PAL_60_SQP = 0xF, /* PAL 60 525-line */
+} tvp5146_mode;
+
+typedef struct {
+ tvp5146_mode mode;
+ int amuxmode;
+ int enablebt656sync;
+} tvp5146_params;
+
+#ifdef __KERNEL__
+
+typedef struct {
+ int agc_enable;
+ tvp5146_mode video_std;
+ int brightness;
+ int contrast;
+ int saturation;
+ int hue;
+ int field_rate; /* 50 or 60 in Hz */
+ int lost_lock;
+ int csubc_lock;
+ int v_lock;
+ int h_lock;
+} tvp5146_status;
+
+typedef unsigned int tvp5146_cmd;
+
+/* commands for setup the decoder */
+#define TVP5146_SET_AMUXMODE 4
+#define TVP5146_SET_BRIGHTNESS 5
+#define TVP5146_SET_CONTRAST 6
+#define TVP5146_SET_HUE 7
+#define TVP5146_SET_SATURATION 8
+#define TVP5146_SET_AGC 9
+#define TVP5146_SET_VIDEOSTD 10
+#define TVP5146_CLR_LOSTLOCK 11
+#define TVP5146_CONFIG 12
+#define TVP5146_RESET 13
+#define TVP5146_POWERDOWN 14
+
+#define TVP5146_GET_STATUS 15
+#define TVP5146_GET_STD 16
+
+#define TVP5146_I2C_ADDR (0xBA >> 1)
+
+extern int tvp5146_ctrl(tvp5146_cmd cmd, void *arg);
+
+#endif
+#endif
diff --git a/include/media/video-buf.h b/include/media/video-buf.h
index d6f0794..079845b 100644
--- a/include/media/video-buf.h
+++ b/include/media/video-buf.h
@@ -193,6 +193,8 @@
struct videobuf_buffer *vb);
void (*buf_release)(struct videobuf_queue *q,
struct videobuf_buffer *vb);
+ void (*buf_config)(struct videobuf_queue *q,
+ unsigned int count);
/* Helper operations - device dependent.
* If null, videobuf_init defaults all to PCI handling
@@ -203,6 +205,11 @@
vb_map_sg_t *vb_unmap_sg;
};
+enum videobuf_buf_type {
+ VIDEOBUF_BUF_LINEAR = 1,
+ VIDEOBUF_BUF_FRAGMENTED = 2,
+};
+
struct videobuf_queue {
struct mutex lock;
spinlock_t *irqlock;
@@ -219,6 +226,7 @@
/* capture via mmap() + ioctl(QBUF/DQBUF) */
unsigned int streaming;
struct list_head stream;
+ enum videobuf_buf_type buf_type;
/* capture via read() */
unsigned int reading;
@@ -232,7 +240,8 @@
void* videobuf_alloc(unsigned int size);
int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr);
int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
- struct v4l2_framebuffer *fbuf);
+ struct v4l2_framebuffer *fbuf);
+int videobuf_set_buftype(struct videobuf_queue *q, enum videobuf_buf_type type);
/* Maps fops to PCI stuff */
void videobuf_queue_pci(struct videobuf_queue* q);
diff --git a/include/sound/davincisound.h b/include/sound/davincisound.h
new file mode 100644
index 0000000..442a6fa
--- /dev/null
+++ b/include/sound/davincisound.h
@@ -0,0 +1,23 @@
+/*
+ * include/sound/davincisound.h
+ *
+ * Copyright (C) 2006 Texas Instruments, 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:
+ * --------
+ * 2006-03-29 Sudhakar - Created
+ */
+
+#include <linux/soundcard.h>
+
+#define SOUND_MIXER_MICBIAS _IOC_NR(SOUND_MIXER_PRIVATE1)
+#define SOUND_MIXER_READ_MICBIAS _SIOR ('M', SOUND_MIXER_MICBIAS, int)
+#define SOUND_MIXER_WRITE_MICBIAS SOUND_MIXER_PRIVATE1
diff --git a/include/video/davincifb.h b/include/video/davincifb.h
new file mode 100644
index 0000000..f464004
--- /dev/null
+++ b/include/video/davincifb.h
@@ -0,0 +1,442 @@
+/*
+ * include/video/davincifb.h
+ *
+ * Framebuffer driver for Texas Instruments DM644x display controller.
+ *
+ * Copyright (C) 2006 Texas Instruments, Inc.
+ * Rishi Bhattacharya <support@ti.com>
+ *
+ * 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 _DAVINCIFB_H_
+#define _DAVINCIFB_H_
+
+#include <asm/arch/io.h>
+
+/* Base registers */
+#define VPBE_REG_BASE IO_ADDRESS(0x01c72780)
+#define VENC_REG_BASE IO_ADDRESS(0x01c72400)
+#define OSD_REG_BASE IO_ADDRESS(0x01c72600)
+#define OSD_REG_SIZE 0x00000180
+
+/* VPBE Global Registers */
+#define VPBE_PID (VPBE_BASE + 0x0)
+#define VPBE_PCR (VPBE_BASE + 0x4)
+
+/* VPSS Clock Control Register */
+#define VPSS_CLKCTL IO_ADDRESS(0x01c40044)
+
+/* VPBE Video Encoder / Digital LCD Subsystem Registers (VENC) */
+#define VENC_VMOD (VENC_REG_BASE + 0x00)
+#define VENC_VIDCTL (VENC_REG_BASE + 0x04)
+#define VENC_VDPRO (VENC_REG_BASE + 0x08)
+#define VENC_SYNCCTL (VENC_REG_BASE + 0x0C)
+#define VENC_HSPLS (VENC_REG_BASE + 0x10)
+#define VENC_VSPLS (VENC_REG_BASE + 0x14)
+#define VENC_HINT (VENC_REG_BASE + 0x18)
+#define VENC_HSTART (VENC_REG_BASE + 0x1C)
+#define VENC_HVALID (VENC_REG_BASE + 0x20)
+#define VENC_VINT (VENC_REG_BASE + 0x24)
+#define VENC_VSTART (VENC_REG_BASE + 0x28)
+#define VENC_VVALID (VENC_REG_BASE + 0x2C)
+#define VENC_HSDLY (VENC_REG_BASE + 0x30)
+#define VENC_VSDLY (VENC_REG_BASE + 0x34)
+#define VENC_YCCCTL (VENC_REG_BASE + 0x38)
+#define VENC_RGBCTL (VENC_REG_BASE + 0x3C)
+#define VENC_RGBCLP (VENC_REG_BASE + 0x40)
+#define VENC_LINECTL (VENC_REG_BASE + 0x44)
+#define VENC_CULLLINE (VENC_REG_BASE + 0x48)
+#define VENC_LCDOUT (VENC_REG_BASE + 0x4C)
+#define VENC_BRTS (VENC_REG_BASE + 0x50)
+#define VENC_BRTW (VENC_REG_BASE + 0x54)
+#define VENC_ACCTL (VENC_REG_BASE + 0x58)
+#define VENC_PWMP (VENC_REG_BASE + 0x5C)
+#define VENC_PWMW (VENC_REG_BASE + 0x60)
+#define VENC_DCLKCTL (VENC_REG_BASE + 0x64)
+#define VENC_DCLKPTN0 (VENC_REG_BASE + 0x68)
+#define VENC_DCLKPTN1 (VENC_REG_BASE + 0x6C)
+#define VENC_DCLKPTN2 (VENC_REG_BASE + 0x70)
+#define VENC_DCLKPTN3 (VENC_REG_BASE + 0x74)
+#define VENC_DCLKPTN0A (VENC_REG_BASE + 0x78)
+#define VENC_DCLKPTN1A (VENC_REG_BASE + 0x7C)
+#define VENC_DCLKPTN2A (VENC_REG_BASE + 0x80)
+#define VENC_DCLKPTN3A (VENC_REG_BASE + 0x84)
+#define VENC_DCLKHS (VENC_REG_BASE + 0x88)
+#define VENC_DCLKHSA (VENC_REG_BASE + 0x8C)
+#define VENC_DCLKHR (VENC_REG_BASE + 0x90)
+#define VENC_DCLKVS (VENC_REG_BASE + 0x94)
+#define VENC_DCLKVR (VENC_REG_BASE + 0x98)
+#define VENC_CAPCTL (VENC_REG_BASE + 0x9C)
+#define VENC_CAPDO (VENC_REG_BASE + 0xA0)
+#define VENC_CAPDE (VENC_REG_BASE + 0xA4)
+#define VENC_ATR0 (VENC_REG_BASE + 0xA8)
+#define VENC_ATR1 (VENC_REG_BASE + 0xAC)
+#define VENC_ATR2 (VENC_REG_BASE + 0xB0)
+#define VENC_EPSON_LCDCTL (VENC_REG_BASE + 0xB4)
+#define VENC_CASIO_LCDCTL (VENC_REG_BASE + 0xB4)
+#define VENC_UDISP_LCDCT (VENC_REG_BASE + 0xB4)
+#define VENC_STN_LCDCT (VENC_REG_BASE + 0xB4)
+#define VENC_VSTAT (VENC_REG_BASE + 0xB8)
+#define VENC_RAMADR (VENC_REG_BASE + 0xBC)
+#define VENC_RAMPORT (VENC_REG_BASE + 0xC0)
+#define VENC_DACTST (VENC_REG_BASE + 0xC4)
+#define VENC_YCOLVL (VENC_REG_BASE + 0xC8)
+#define VENC_SCPROG (VENC_REG_BASE + 0xCC)
+#define VENC_CVBS (VENC_REG_BASE + 0xDC)
+#define VENC_CMPNT (VENC_REG_BASE + 0xE0)
+#define VENC_ETMG0 (VENC_REG_BASE + 0xE4)
+#define VENC_ETMG1 (VENC_REG_BASE + 0xE8)
+#define VENC_ETMG2 (VENC_REG_BASE + 0xEC)
+#define VENC_ETMG3 (VENC_REG_BASE + 0xF0)
+#define VENC_DACSEL (VENC_REG_BASE + 0xF4)
+#define VENC_ARGBX0 (VENC_REG_BASE + 0x100)
+#define VENC_ARGBX1 (VENC_REG_BASE + 0x104)
+#define VENC_ARGBX2 (VENC_REG_BASE + 0x108)
+#define VENC_ARGBX3 (VENC_REG_BASE + 0x10C)
+#define VENC_ARGBX4 (VENC_REG_BASE + 0x110)
+#define VENC_DRGBX0 (VENC_REG_BASE + 0x114)
+#define VENC_DRGBX1 (VENC_REG_BASE + 0x118)
+#define VENC_DRGBX2 (VENC_REG_BASE + 0x11C)
+#define VENC_DRGBX3 (VENC_REG_BASE + 0x120)
+#define VENC_DRGBX4 (VENC_REG_BASE + 0x124)
+#define VENC_VSTARTA (VENC_REG_BASE + 0x128)
+#define VENC_OSDCLK0 (VENC_REG_BASE + 0x12C)
+#define VENC_OSDCLK1 (VENC_REG_BASE + 0x130)
+#define VENC_HVLDCL0 (VENC_REG_BASE + 0x134)
+#define VENC_HVLDCL1 (VENC_REG_BASE + 0x138)
+#define VENC_OSDHAD (VENC_REG_BASE + 0x13C)
+
+#define VID0 0
+#define VID1 1
+#define OSD0 3
+#define OSD1 4
+
+/* VPBE On-Screen Display Subsystem Registers (OSD) */
+#define OSD_MODE (OSD_REG_BASE + 0x00)
+#define OSD_VIDWINMD (OSD_REG_BASE + 0x04)
+#define OSD_OSDWIN0MD (OSD_REG_BASE + 0x08)
+#define OSD_OSDWIN1MD (OSD_REG_BASE + 0x0C)
+#define OSD_OSDATRMD (OSD_REG_BASE + 0x0C)
+#define OSD_RECTCUR (OSD_REG_BASE + 0x10)
+#define OSD_WINOFST(i) (OSD_REG_BASE + 0x18 + (i)*0x4)
+#define OSD_VIDWIN0OFST (OSD_REG_BASE + 0x18)
+#define OSD_VIDWIN1OFST (OSD_REG_BASE + 0x1C)
+#define OSD_OSDWIN0OFST (OSD_REG_BASE + 0x20)
+#define OSD_OSDWIN1OFST (OSD_REG_BASE + 0x24)
+#define OSD_WINADR(i) (OSD_REG_BASE + 0x2C + (i)*0x4)
+#define OSD_VIDWIN0ADR (OSD_REG_BASE + 0x2C)
+#define OSD_VIDWIN1ADR (OSD_REG_BASE + 0x30)
+#define OSD_OSDWIN0ADR (OSD_REG_BASE + 0x38)
+#define OSD_OSDWIN1ADR (OSD_REG_BASE + 0x3C)
+#define OSD_BASEPX (OSD_REG_BASE + 0x40)
+#define OSD_BASEPY (OSD_REG_BASE + 0x44)
+#define OSD_WINXP(i) (OSD_REG_BASE + 0x48 + (i)*0x10)
+#define OSD_WINYP(i) (OSD_REG_BASE + 0x4C + (i)*0x10)
+#define OSD_WINXL(i) (OSD_REG_BASE + 0x50 + (i)*0x10)
+#define OSD_WINYL(i) (OSD_REG_BASE + 0x54 + (i)*0x10)
+#define OSD_VIDWIN0XP (OSD_REG_BASE + 0x48)
+#define OSD_VIDWIN0YP (OSD_REG_BASE + 0x4C)
+#define OSD_VIDWIN0XL (OSD_REG_BASE + 0x50)
+#define OSD_VIDWIN0YL (OSD_REG_BASE + 0x54)
+#define OSD_VIDWIN1XP (OSD_REG_BASE + 0x58)
+#define OSD_VIDWIN1YP (OSD_REG_BASE + 0x5C)
+#define OSD_VIDWIN1XL (OSD_REG_BASE + 0x60)
+#define OSD_VIDWIN1YL (OSD_REG_BASE + 0x64)
+#define OSD_OSDWIN0XP (OSD_REG_BASE + 0x68)
+#define OSD_OSDWIN0YP (OSD_REG_BASE + 0x6C)
+#define OSD_OSDWIN0XL (OSD_REG_BASE + 0x70)
+#define OSD_OSDWIN0YL (OSD_REG_BASE + 0x74)
+#define OSD_OSDWIN1XP (OSD_REG_BASE + 0x78)
+#define OSD_OSDWIN1YP (OSD_REG_BASE + 0x7C)
+#define OSD_OSDWIN1XL (OSD_REG_BASE + 0x80)
+#define OSD_OSDWIN1YL (OSD_REG_BASE + 0x84)
+#define OSD_CURXP (OSD_REG_BASE + 0x88)
+#define OSD_CURYP (OSD_REG_BASE + 0x8C)
+#define OSD_CURXL (OSD_REG_BASE + 0x90)
+#define OSD_CURYL (OSD_REG_BASE + 0x94)
+#define OSD_W0BMP01 (OSD_REG_BASE + 0xA0)
+#define OSD_W0BMP23 (OSD_REG_BASE + 0xA4)
+#define OSD_W0BMP45 (OSD_REG_BASE + 0xA8)
+#define OSD_W0BMP67 (OSD_REG_BASE + 0xAC)
+#define OSD_W0BMP89 (OSD_REG_BASE + 0xB0)
+#define OSD_W0BMPAB (OSD_REG_BASE + 0xB4)
+#define OSD_W0BMPCD (OSD_REG_BASE + 0xB8)
+#define OSD_W0BMPEF (OSD_REG_BASE + 0xBC)
+#define OSD_W1BMP0 (OSD_REG_BASE + 0xC0)
+#define OSD_W1BMP2 (OSD_REG_BASE + 0xC4)
+#define OSD_W1BMP4 (OSD_REG_BASE + 0xC8)
+#define OSD_W1BMP6 (OSD_REG_BASE + 0xCC)
+#define OSD_W1BMP8 (OSD_REG_BASE + 0xD0)
+#define OSD_W1BMPA (OSD_REG_BASE + 0xD4)
+#define OSD_W1BMPC (OSD_REG_BASE + 0xD8)
+#define OSD_W1BMPE (OSD_REG_BASE + 0xDC)
+#define OSD_TI_TES (OSD_REG_BASE + 0xE0)
+#define OSD_MISCCT (OSD_REG_BASE + 0xE8)
+#define OSD_CLUTRAMYC (OSD_REG_BASE + 0xEC)
+#define OSD_CLUTRAMC (OSD_REG_BASE + 0xF0)
+#define OSD_TRANSPVA (OSD_REG_BASE + 0xF0)
+#define OSD_PPVWIN0AD (OSD_REG_BASE + 0xFC)
+
+/* bit definitions */
+#define VPBE_PCR_VENC_DIV (1 << 1)
+#define VPBE_PCR_CLK_OFF (1 << 0)
+#define VENC_VMOD_VDMD_SHIFT 12
+#define VENC_VMOD_VDMD_YCBCR16 0
+#define VENC_VMOD_VDMD_YCBCR8 1
+#define VENC_VMOD_VDMD_RGB666 2
+#define VENC_VMOD_VDMD_RGB8 3
+#define VENC_VMOD_VDMD_EPSON 4
+#define VENC_VMOD_VDMD_CASIO 5
+#define VENC_VMOD_VDMD_UDISPQVGA 6
+#define VENC_VMOD_VDMD_STNLCD 7
+#define VENC_VMOD_VDMD (7 << 12)
+#define VENC_VMOD_ITLCL (1 << 11)
+#define VENC_VMOD_ITLC (1 << 10)
+#define VENC_VMOD_NSIT (1 << 9)
+#define VENC_VMOD_HDMD (1 << 8)
+#define VENC_VMOD_TVTYP (3 << 6)
+#define VENC_VMOD_SLAVE (1 << 5)
+#define VENC_VMOD_VMD (1 << 4)
+#define VENC_VMOD_BLNK (1 << 3)
+#define VENC_VMOD_VIE (1 << 1)
+#define VENC_VMOD_VENC (1 << 0)
+/* other VENC registers' bit positions not defined yet */
+
+#define OSD_MODE_CS (1 << 15)
+#define OSD_MODE_OVRSZ (1 << 14)
+#define OSD_MODE_OHRSZ (1 << 13)
+#define OSD_MODE_EF (1 << 12)
+#define OSD_MODE_VVRSZ (1 << 11)
+#define OSD_MODE_VHRSZ (1 << 10)
+#define OSD_MODE_FSINV (1 << 9)
+#define OSD_MODE_BCLUT (1 << 8)
+#define OSD_MODE_CABG (0xff << 0)
+#define OSD_MODE_CABG_SHIFT 0
+
+#define OSD_VIDWINMD_VFINV (1 << 15)
+#define OSD_VIDWINMD_V1EFC (1 << 14)
+#define OSD_VIDWINMD_VHZ1 (3 << 12)
+#define OSD_VIDWINMD_VHZ1_SHIFT 12
+#define OSD_VIDWINMD_VVZ1 (3 << 10)
+#define OSD_VIDWINMD_VVZ1_SHIFT 10
+#define OSD_VIDWINMD_VFF1 (1 << 9)
+#define OSD_VIDWINMD_ACT1 (1 << 8)
+#define OSD_VIDWINMD_V0EFC (1 << 6)
+#define OSD_VIDWINMD_VHZ0 (3 << 4)
+#define OSD_VIDWINMD_VHZ0_SHIFT 4
+#define OSD_VIDWINMD_VVZ0 (3 << 2)
+#define OSD_VIDWINMD_VVZ0_SHIFT 2
+#define OSD_VIDWINMD_VFF0 (1 << 1)
+#define OSD_VIDWINMD_ACT0 (1 << 0)
+
+#define OSD_OSDWIN0MD_ATN0E (1 << 14)
+#define OSD_OSDWIN0MD_RGB0E (1 << 13)
+#define OSD_OSDWIN0MD_CLUTS0 (1 << 12)
+#define OSD_OSDWIN0MD_OHZ0 (3 << 10)
+#define OSD_OSDWIN0MD_OHZ0_SHIFT 10
+#define OSD_OSDWIN0MD_OVZ0 (3 << 8)
+#define OSD_OSDWIN0MD_OVZ0_SHIFT 8
+#define OSD_OSDWIN0MD_BMW0 (3 << 6)
+#define OSD_OSDWIN0MD_BMW0_SHIFT 6
+#define OSD_OSDWIN0MD_BLND0 (3 << 3)
+#define OSD_OSDWIN0MD_BLND0_SHIFT 3
+#define OSD_OSDWIN0MD_TE0 (1 << 2)
+#define OSD_OSDWIN0MD_OFF0 (1 << 1)
+#define OSD_OSDWIN0MD_OACT0 (1 << 0)
+
+#define OSD_OSDWIN1MD_OASW (1 << 15)
+#define OSD_OSDWIN1MD_ATN1E (1 << 14)
+#define OSD_OSDWIN1MD_RGB1E (1 << 13)
+#define OSD_OSDWIN1MD_CLUTS1 (1 << 12)
+#define OSD_OSDWIN1MD_OHZ1 (3 << 10)
+#define OSD_OSDWIN1MD_OHZ1_SHIFT 10
+#define OSD_OSDWIN1MD_OVZ1 (3 << 8)
+#define OSD_OSDWIN1MD_OVZ1_SHIFT 8
+#define OSD_OSDWIN1MD_BMW1 (3 << 6)
+#define OSD_OSDWIN1MD_BMW1_SHIFT 6
+#define OSD_OSDWIN1MD_BLND1 (3 << 3)
+#define OSD_OSDWIN1MD_BLND1_SHIFT 3
+#define OSD_OSDWIN1MD_TE1 (1 << 2)
+#define OSD_OSDWIN1MD_OFF1 (1 << 1)
+#define OSD_OSDWIN1MD_OACT1 (1 << 0)
+
+
+#define OSD_OSDATRMD_OASW (1 << 15)
+#define OSD_OSDATRMD_OHZA (3 << 10)
+#define OSD_OSDATRMD_OHZA_SHIFT 10
+#define OSD_OSDATRMD_OVZA (3 << 8)
+#define OSD_OSDATRMD_OVZA_SHIFT 8
+#define OSD_OSDATRMD_BLNKINT (3 << 6)
+#define OSD_OSDATRMD_BLNKINT_SHIFT 6
+#define OSD_OSDATRMD_OFFA (1 << 1)
+#define OSD_OSDATRMD_BLNK (1 << 0)
+
+#define OSD_RECTCUR_RCAD (0xff << 8)
+#define OSD_RECTCUR_RCAD_SHIFT 8
+#define OSD_RECTCUR_CLUTSR (1 << 7)
+#define OSD_RECTCUR_RCHW (3 << 4)
+#define OSD_RECTCUR_RCHW_SHIFT 4
+#define OSD_RECTCUR_RCVW (3 << 1)
+#define OSD_RECTCUR_RCVW_SHIFT 1
+#define OSD_RECTCUR_RCACT (1 << 0)
+
+#define OSD_VIDWIN0OFST_V0LO (0x1ff << 0)
+#define OSD_VIDWIN0OFST_V0LO_SHIFT 0
+#define OSD_VIDWIN1OFST_V1LO (0x1ff << 0)
+#define OSD_VIDWIN1OFST_V1LO_SHIFT 0
+#define OSD_OSDWIN0OFST_O0LO (0x1ff << 0)
+#define OSD_OSDWIN0OFST_O0LO_SHIFT 0
+#define OSD_OSDWIN1OFST_O1LO (0x1ff << 0)
+#define OSD_OSDWIN1OFST_O1LO_SHIFT 0
+#define OSD_BASEPX_BPX (0x3ff << 0)
+#define OSD_BASEPX_BPX_SHIFT 0
+#define OSD_BASEPY_BPY (0x1ff << 0)
+#define OSD_BASEPY_BPY_SHIFT 0
+#define OSD_VIDWIN0XP_V0X (0x3ff << 0)
+#define OSD_VIDWIN0XP_V0X_SHIFT 0
+#define OSD_VIDWIN0YP_V0Y (0x1ff << 0)
+#define OSD_VIDWIN0YP_V0Y_SHIFT 0
+#define OSD_VIDWIN0XL_V0W (0xfff << 0)
+#define OSD_VIDWIN0XL_V0W_SHIFT 0
+#define OSD_VIDWIN0YL_V0H (0x7ff << 0)
+#define OSD_VIDWIN0YL_V0H_SHIFT 0
+#define OSD_VIDWIN1XP_V1X (0x3ff << 0)
+#define OSD_VIDWIN1XP_V1X_SHIFT 0
+#define OSD_VIDWIN1YP_V1Y (0x1ff << 0)
+#define OSD_VIDWIN1YP_V1Y_SHIFT 0
+#define OSD_VIDWIN1XL_V1W (0xfff << 0)
+#define OSD_VIDWIN1XL_V1W_SHIFT 0
+#define OSD_VIDWIN1YL_V1H (0x7ff << 0)
+#define OSD_VIDWIN1YL_V1H_SHIFT 0
+#define OSD_OSDWIN0XP_W0X (0x3ff << 0)
+#define OSD_OSDWIN0XP_W0X_SHIFT 0
+#define OSD_OSDWIN0YP_W0Y (0x1ff << 0)
+#define OSD_OSDWIN0YP_W0Y_SHIFT 0
+#define OSD_OSDWIN0XL_W0W (0xfff << 0)
+#define OSD_OSDWIN0XL_W0W_SHIFT 0
+#define OSD_OSDWIN0YL_W0H (0x7ff << 0)
+#define OSD_OSDWIN0YL_W0H_SHIFT 0
+#define OSD_OSDWIN1XP_W1X (0x3ff << 0)
+#define OSD_OSDWIN1XP_W1X_SHIFT 0
+#define OSD_OSDWIN1YP_W1Y (0x1ff << 0)
+#define OSD_OSDWIN1YP_W1Y_SHIFT 0
+#define OSD_OSDWIN1XL_W1W (0xfff << 0)
+#define OSD_OSDWIN1XL_W1W_SHIFT 0
+#define OSD_OSDWIN1YL_W1H (0x7ff << 0)
+#define OSD_OSDWIN1YL_W1H_SHIFT 0
+#define OSD_CURXP_RCSX (0x3ff << 0)
+#define OSD_CURXP_RCSX_SHIFT 0
+#define OSD_CURYP_RCSY (0x1ff << 0)
+#define OSD_CURYP_RCSY_SHIFT 0
+#define OSD_CURYL_RCSH (0x7ff << 0)
+#define OSD_CURYL_RCSH_SHIFT 0
+#define OSD_W0BMP01_PAL01 (0xff << 8)
+#define OSD_W0BMP01_PAL01_SHIFT 8
+#define OSD_W0BMP01_PAL00 (0xff << 0)
+#define OSD_W0BMP01_PAL00_SHIFT 0
+#define OSD_W0BMP23_PAL03 (0xff << 8)
+#define OSD_W0BMP23_PAL03_SHIFT 8
+#define OSD_W0BMP23_PAL02 (0xff << 0)
+#define OSD_W0BMP23_PAL02_SHIFT 0
+#define OSD_W0BMP45_PAL05 (0xff << 8)
+#define OSD_W0BMP45_PAL05_SHIFT 8
+#define OSD_W0BMP45_PAL04 (0xff << 0)
+#define OSD_W0BMP45_PAL04_SHIFT 0
+#define OSD_W0BMP67_PAL07 (0xff << 8)
+#define OSD_W0BMP67_PAL07_SHIFT 8
+#define OSD_W0BMP67_PAL06 (0xff << 0)
+#define OSD_W0BMP67_PAL06_SHIFT 0
+#define OSD_W0BMP89_PAL09 (0xff << 8)
+#define OSD_W0BMP89_PAL09_SHIFT 8
+#define OSD_W0BMP89_PAL08 (0xff << 0)
+#define OSD_W0BMP89_PAL08_SHIFT 0
+#define OSD_W0BMPAB_PAL11 (0xff << 8)
+#define OSD_W0BMPAB_PAL11_SHIFT 8
+#define OSD_W0BMPAB_PAL10 (0xff << 0)
+#define OSD_W0BMPAB_PAL10_SHIFT 0
+#define OSD_W0BMPCD_PAL13 (0xff << 8)
+#define OSD_W0BMPCD_PAL13_SHIFT 8
+#define OSD_W0BMPCD_PAL12 (0xff << 0)
+#define OSD_W0BMPCD_PAL12_SHIFT 0
+#define OSD_W0BMPEF_PAL15 (0xff << 8)
+#define OSD_W0BMPEF_PAL15_SHIFT 8
+#define OSD_W0BMPEF_PAL14 (0xff << 0)
+#define OSD_W0BMPEF_PAL14_SHIFT 0
+#define OSD_W1BMP0_PAL01 (0xff << 8)
+#define OSD_W1BMP0_PAL01_SHIFT 8
+#define OSD_W1BMP0_PAL00 (0xff << 0)
+#define OSD_W1BMP0_PAL00_SHIFT 0
+#define OSD_W1BMP2_PAL03 (0xff << 8)
+#define OSD_W1BMP2_PAL03_SHIFT 8
+#define OSD_W1BMP2_PAL02 (0xff << 0)
+#define OSD_W1BMP2_PAL02_SHIFT 0
+#define OSD_W1BMP4_PAL05 (0xff << 8)
+#define OSD_W1BMP4_PAL05_SHIFT 8
+#define OSD_W1BMP4_PAL04 (0xff << 0)
+#define OSD_W1BMP4_PAL04_SHIFT 0
+#define OSD_W1BMP6_PAL07 (0xff << 8)
+#define OSD_W1BMP6_PAL07_SHIFT 8
+#define OSD_W1BMP6_PAL06 (0xff << 0)
+#define OSD_W1BMP6_PAL06_SHIFT 0
+#define OSD_W1BMP8_PAL09 (0xff << 8)
+#define OSD_W1BMP8_PAL09_SHIFT 8
+#define OSD_W1BMP8_PAL08 (0xff << 0)
+#define OSD_W1BMP8_PAL08_SHIFT 0
+#define OSD_W1BMPA_PAL11 (0xff << 8)
+#define OSD_W1BMPA_PAL11_SHIFT 8
+#define OSD_W1BMPA_PAL10 (0xff << 0)
+#define OSD_W1BMPA_PAL10_SHIFT 0
+#define OSD_W1BMPC_PAL13 (0xff << 8)
+#define OSD_W1BMPC_PAL13_SHIFT 8
+#define OSD_W1BMPC_PAL12 (0xff << 0)
+#define OSD_W1BMPC_PAL12_SHIFT 0
+#define OSD_W1BMPE_PAL15 (0xff << 8)
+#define OSD_W1BMPE_PAL15_SHIFT 8
+#define OSD_W1BMPE_PAL14 (0xff << 0)
+#define OSD_W1BMPE_PAL14_SHIFT 0
+
+#define OSD_MISCCT_RGBEN (1 << 7)
+#define OSD_MISCCT_RGBWIN (1 << 6)
+#define OSD_MISCCT_TMON (1 << 5)
+#define OSD_MISCCT_RSEL (1 << 4)
+#define OSD_MISCCT_CPBSY (1 << 3)
+#define OSD_MISCCT_PPSW (1 << 2)
+#define OSD_MISCCT_PPRV (1 << 1)
+
+#define OSD_CLUTRAMY_Y (0xff << 8)
+#define OSD_CLUTRAMY_Y_SHIFT 8
+#define OSD_CLUTRAMY_CB (0xff << 0)
+#define OSD_CLUTRAMY_CB_SHIFT 0
+#define OSD_CLUTRAM_CR (0xff << 8)
+#define OSD_CLUTRAM_CR_SHIFT 8
+#define OSD_CLUTRAM_CADDR (0xff << 0)
+#define OSD_CLUTRAM_CADDR_SHIFT 0
+#define OSD_TRANSPVA_RGBTRANS (0xff << 0)
+#define OSD_TRANSPVA_RGBTRANS_SHIFT 0
+
+
+#define LCD 0
+#define NTSC 1
+#define PAL 2
+
+#define COMPOSITE 1
+#define SVIDEO 2
+#define COMPONENT 3
+#define RGB 4
+
+/* define the custom FBIO_WAITFORVSYNC ioctl */
+#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t)
+#define FBIO_SETATTRIBUTE _IOW('F', 0x21, struct fb_fillrect)
+#define FBIO_SETPOSX _IOW('F', 0x22, u_int32_t)
+#define FBIO_SETPOSY _IOW('F', 0x23, u_int32_t)
+struct zoom_params
+{
+ u_int32_t window_id;
+ u_int32_t zoom_h;
+ u_int32_t zoom_v;
+};
+#define FBIO_SETZOOM _IOW('F', 0x24, struct zoom_params)
+#define FBIO_GETSTD _IOR('F', 0x25, u_int32_t)
+#endif /* _DAVINCIFB_H_ */
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index af37cd0..a8f2055 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -654,3 +654,35 @@
int "DAC channel"
default "1"
depends on SOUND_SH_DAC_AUDIO
+
+config SOUND_DAVINCI
+ tristate "DaVinci Sound Driver"
+ depends on ARCH_DAVINCI && SOUND_PRIME!=n && SOUND
+ ---help---
+ DaVinci Sound driver
+
+config SOUND_DAVINCI_AIC33
+ tristate "AIC33 Stereo Codec"
+ depends on SOUND_DAVINCI
+ select SENSORS_TLV320AIC33
+ ---help---
+ If you say yes here you get support for the I2C control
+ interface for Texas Instruments TLV320AIC33 audio codec.
+
+menu "DaVinci Audio Options"
+ depends on SOUND_DAVINCI
+
+choice
+ prompt "Mono/Stereo Jack Support"
+ default MONOSTEREO_SAMEJACK
+
+config MONOSTEREO_DIFFJACK
+ bool "Mono and Stereo on different jacks"
+
+config MONOSTEREO_SAMEJACK
+ bool "Mono and Stereo on same jacks"
+
+endchoice
+
+endmenu
+
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index 1f81a2f..9914451 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -12,6 +12,9 @@
obj-$(CONFIG_SOUND_OMAP_TSC2101)+= omap-audio-tsc2101.o
obj-$(CONFIG_SOUND_OMAP_AIC23) += omap-audio-aic23.o
+obj-$(CONFIG_SOUND_DAVINCI) += davinci-audio-dma-intfc.o davinci-audio.o
+obj-$(CONFIG_SOUND_DAVINCI_AIC33) += davinci-audio-aic33.o
+
# Please leave it as is, cause the link order is significant !
obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o
diff --git a/sound/oss/davinci-aic33.h b/sound/oss/davinci-aic33.h
new file mode 100644
index 0000000..768469b
--- /dev/null
+++ b/sound/oss/davinci-aic33.h
@@ -0,0 +1,246 @@
+/*
+ * linux/sound/oss/davinci-aic33.h
+ *
+ * Glue driver for AIC33 for Davinci processors
+ *
+ * Copyright (C) 2006 Texas Instruments, 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:
+ * -------
+ * 2005-10-18 Rishi Bhattacharya - Support for AIC33 codec and Davinci DM644x Processor
+ */
+
+#ifndef __ASM_ARCH_AIC33_H
+#define __ASM_ARCH_AIC33_H
+
+/* Codec TLV320AIC33 */
+#define REGISTER_ADDR0 0x00
+#define REGISTER_ADDR1 0x01
+#define REGISTER_ADDR2 0x02
+#define REGISTER_ADDR3 0x03
+#define REGISTER_ADDR4 0x04
+#define REGISTER_ADDR5 0x05
+#define REGISTER_ADDR6 0x06
+#define REGISTER_ADDR7 0x07
+#define REGISTER_ADDR8 0x08
+#define REGISTER_ADDR9 0x09
+#define REGISTER_ADDR10 0x0A
+#define REGISTER_ADDR11 0x0B
+#define REGISTER_ADDR12 0x0C
+#define REGISTER_ADDR15 0x0F
+#define REGISTER_ADDR16 0x10
+#define REGISTER_ADDR17 0x11
+#define REGISTER_ADDR18 0x12
+#define REGISTER_ADDR19 0x13
+#define REGISTER_ADDR20 0x14
+#define REGISTER_ADDR21 0x15
+#define REGISTER_ADDR22 0x16
+#define REGISTER_ADDR23 0x17
+#define REGISTER_ADDR24 0x18
+#define REGISTER_ADDR25 0x19
+#define REGISTER_ADDR26 0x1A
+#define REGISTER_ADDR27 0x1B
+#define REGISTER_ADDR28 0x1C
+#define REGISTER_ADDR29 0x1D
+#define REGISTER_ADDR30 0x1E
+#define REGISTER_ADDR31 0x1F
+#define REGISTER_ADDR32 0x20
+#define REGISTER_ADDR33 0x21
+#define REGISTER_ADDR37 0x25
+#define REGISTER_ADDR38 0x26
+#define REGISTER_ADDR40 0x28
+#define REGISTER_ADDR41 0x29
+#define REGISTER_ADDR43 0x2B
+#define REGISTER_ADDR44 0x2C
+#define REGISTER_ADDR45 0x2D
+#define REGISTER_ADDR46 0x2E
+#define REGISTER_ADDR47 0x2F
+#define REGISTER_ADDR51 0x33
+#define REGISTER_ADDR58 0x3A
+#define REGISTER_ADDR64 0x40
+#define REGISTER_ADDR65 0x41
+#define REGISTER_ADDR73 0x49
+#define REGISTER_ADDR74 0x4A
+#define REGISTER_ADDR75 0x4B
+#define REGISTER_ADDR76 0x4C
+#define REGISTER_ADDR77 0x4D
+#define REGISTER_ADDR78 0x4E
+#define REGISTER_ADDR79 0x4F
+#define REGISTER_ADDR80 0x50
+#define REGISTER_ADDR81 0x51
+#define REGISTER_ADDR82 0x52
+#define REGISTER_ADDR83 0x53
+#define REGISTER_ADDR84 0x54
+#define REGISTER_ADDR85 0x55
+#define REGISTER_ADDR86 0x56
+#define REGISTER_ADDR87 0x57
+#define REGISTER_ADDR88 0x58
+#define REGISTER_ADDR89 0x59
+#define REGISTER_ADDR90 0x5A
+#define REGISTER_ADDR91 0x5B
+#define REGISTER_ADDR92 0x5C
+#define REGISTER_ADDR93 0x5D
+#define REGISTER_ADDR94 0x5E
+
+// Page Select register 0
+#define PAGE_SELECT0 0
+#define PAGE_SELECT1 1
+
+// Software reset register 1
+#define SOFT_RESET 0x80
+
+// Codec sample rate select register 2
+#define ADC_FS_MAX 0xA0
+#define ADC_FS_MIN 0x00
+
+#define DAC_FS_MAX 0x0A
+#define DAC_FS_MIN 0x00
+
+// PLL Programming registerA 3
+#define PLL_ENABLE 0x80
+
+// Codec Datapath setup register 7
+#define FS_REF_44_1 0x80
+#define FS_REF_DEFAULT_48 0x00
+#define ADC_DUAL_RATE_MODE 0x40
+#define DAC_DUAL_RATE_MODE 0x20
+#define LDAC_LCHAN 0x08
+#define LDAC_RCHAN 0x10
+#define LDAC_MONO_MIX 0x18
+
+#define RDAC_RCHAN 0x02
+#define RDAC_LCHAN 0x04
+#define RDAC_MONO_MIX 0x06
+
+//Audio serial data interface control registerA 8
+#define BIT_CLK_MASTER 0x80
+#define WORD_CLK_MASTER 0x40
+#define DOUT_TRI_STATE 0x20
+#define CLK_TRANS_MASTER 0x10
+#define ENABLE_3D 0x04
+#define DM_ENABLE_128 0x01
+#define DM_ENABLE_64 0x02
+#define DM_ENABLE_32 0x03
+
+//Audio serial data interface control registerB 9
+#define DSP_MODE 0x40
+#define RJ_MODE 0x80
+#define LJ_MODE 0xC0
+#define WORD_LENGTH20 0x10
+#define WORD_LENGTH24 0x20
+#define WORD_LENGTH32 0x30
+#define BITCLOCK_256CLK_FRAME 0x08
+
+//Left/Right ADC PGA gain control register 15 & 16
+#define ADC_PGA_MUTE 0x80
+#define ADC_PGA_GAIN_MAX 0x78
+#define ADC_PGA_GAIN_MIN 0x00
+
+// MIC3L/R to left/right ADC control register 17 & 18
+#define ADCPGA_GAIN_MAX 0x00
+#define MIC3L_ADCPGA_GAIN_MIN 0x80
+#define MIC3L_ADCPGA_DISCONNECT 0xF0
+
+#define MIC3R_ADCPGA_GAIN_MIN 0x08
+#define MIC3R_ADCPGA_DISCONNECT 0x0F
+
+//LINE1L to left ADC Control Register 19
+#define DIFF_MODE 0x80
+#define LINE_ADCPGA_GAIN_MIN 0x40
+#define LINE_ADCPGA_DISCONNECT 0x78
+#define ADC_CHAN_ON 0x04
+#define ADCPGA_SOFT_STEP2FS 0x01
+#define ADCPGA_SOFT_STEP_OFF 0x03
+
+//LINE2L to left ADC Control Register 20
+#define ADC_WEAK_INPUT_BIAS 0x04
+
+//MICBIAS control register 25
+#define MICBIAS_OUTPUT_2_0V 0x40
+#define MICBIAS_OUTPUT_2_5V 0x80
+#define MICBIAS_OUTPUT_AVDD 0xC0
+
+//LEFT/RIGHT AGC Control registerA 26 & 29
+#define AGC_ENABLE 0x80
+#define AGC_TARGET_GAIN_MAX 0x00
+#define AGC_TARGET_GAIN_MIN 0x70
+#define AGC_ATTACK_TIME_11 0x04
+#define AGC_ATTACK_TIME_16 0x08
+#define AGC_ATTACK_TIME_20 0x0C
+#define AGC_DECAY_TIME_200 0x01
+#define AGC_DECAY_TIME_400 0x02
+#define AGC_DECAY_TIME_500 0x03
+
+//LEFT AGC Control registerB 27 & 30
+#define AGC_GAIN_ALLOWED_MAX 0xEE
+#define AGC_GAIN_ALLOWED_MIN 0x00
+
+//DAC Power and output driver control register 37
+#define LEFT_DAC_POWER_ON 0x80
+#define RIGHT_DAC_POWER_ON 0x40
+
+//High Power Output Stage Control Register 40
+#define LINE2L_BYPASS_DISABLE_DEFAULT 0x00
+#define LINE2LP_BYPASS_SINGLE 0x10
+#define LINE2LM_BYPASS_SINGLE 0x20
+#define LINE2LPM_BYPASS_DIFFERENTIAL 0x30
+
+#define LINE2R_BYPASS_DISABLE_DEFAULT 0x00
+#define LINE2RP_BYPASS_SINGLE 0x04
+#define LINE2RM_BYPASS_SINGLE 0x08
+#define LINE2RPM_BYPASS_DIFFERENTIAL 0x0C
+
+//DAC Output Switching Control Register 41
+#define LEFT_DAC_DEFAULT_L1 0x00
+#define LEFT_DAC_L2 0x80
+#define LEFT_DAC_L3 0x40
+#define RIGHT_DAC_DEFAULT_R1 0x00
+#define RIGHT_DAC_R2 0x08
+#define RIGHT_DAC_R3 0x04
+
+//LEFT/RIGHT DAC Digital volume control register 43 & 44
+#define DAC_CHAN_MUTE 0x80
+#define DAC_DIG_VOL_GAIN_MAX 0x00 // 0.0db
+#define DAC_DIG_VOL_GAIN_MIN 0x7F // -63.5db
+
+//LINE2L to HPLOUT Volume Control Register 45
+#define LINE2L_HPLOUT_ROUTED 0x80
+
+//PGA_L to HPLOUT Volume Control Register 46
+#define PGAL_HPLOUT_ROUTED 0x80
+
+//any to LOP/M Volume control
+#define LOPM_ON 0x80
+#define LOPM_VOL_GAIN_MAX 0x00 //0 db
+#define LOPM_VOL_GAIN_MIN 0x76 //-78.3 db is MUTE
+
+//MONO_LOP/M output level volume control register 79
+#define LOPM_POWER_ON 0x01
+#define LOPM_MUTE_OFF 0x08
+#define LOPM_OUTPUT_LEVEL_MIN 0x00
+#define LOPM_OUTPUT_LEVEL_MAX 0x90
+
+//Module Power Status Register 94
+#define HPROUT_DRIVER_POWER_ON 0x02
+
+#define LIV_MAX 0x0077
+#define LIV_MIN 0x0000
+
+#define LHV_MAX 0x0077
+#define LHV_MIN 0x0000
+
+#define LIG_MAX 0x0077
+#define LIG_MIN 0x0000
+
+#define LOG_MAX 0x007f
+#define LOG_MIN 0x0000
+
+#endif /* __ASM_ARCH_AIC33_H */
diff --git a/sound/oss/davinci-audio-aic33.c b/sound/oss/davinci-audio-aic33.c
new file mode 100644
index 0000000..0a4a7c9
--- /dev/null
+++ b/sound/oss/davinci-audio-aic33.c
@@ -0,0 +1,1066 @@
+/*
+ * linux/sound/oss/davinci-audio-aic33.c
+ *
+ * Glue driver for AIC33 for Davinci processors
+ *
+ * Copyright (C) 2006 Texas Instruments, 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:
+ * -------
+ * 2005-10-18 Rishi Bhattacharya - Support for AIC33 codec and Davinci DM644x Processor
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/clk.h>
+#include <sound/davincisound.h>
+
+#include <asm/uaccess.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/mcbsp.h>
+#include "davinci-aic33.h"
+
+#include "davinci-audio.h"
+#include "davinci-audio-dma-intfc.h"
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#define PROC_START_FILE "driver/aic33-audio-start"
+#define PROC_STOP_FILE "driver/aic33-audio-stop"
+#endif
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTK(ARGS...) do { \
+ printk("<%s>: ",__FUNCTION__);printk(ARGS); \
+ } while (0)
+#else
+#define DPRINTK( x... )
+#endif
+
+#define CODEC_NAME "AIC33"
+#define PLATFORM_NAME "DAVINCI"
+
+/* Define to set the AIC33 as the master w.r.t McBSP */
+#define AIC33_MASTER
+
+/* codec clock frequency */
+#define MCLK 22
+
+/*
+ * AUDIO related MACROS
+ */
+#define DEFAULT_BITPERSAMPLE 16
+#define AUDIO_RATE_DEFAULT 48000
+#define DEFAULT_MCBSP_CLOCK 81000000
+
+/* Select the McBSP For Audio */
+#define AUDIO_MCBSP DAVINCI_MCBSP1
+
+#define REC_MASK (SOUND_MASK_LINE | SOUND_MASK_MIC)
+#define DEV_MASK (REC_MASK | SOUND_MASK_VOLUME)
+
+#define MONO 1
+#define STEREO 2
+
+#define SET_VOLUME 1
+#define SET_LINE 2
+#define SET_MIC 3
+#define SET_RECSRC 4
+#define SET_IGAIN 5
+#define SET_OGAIN 6
+#define SET_BASS 7
+#define SET_TREBLE 8
+#define SET_MICBIAS 9
+
+#define DEFAULT_OUTPUT_VOLUME 50
+#define DEFAULT_INPUT_VOLUME 20 /* 0 ==> mute line in */
+#define DEFAULT_INPUT_IGAIN 20
+#define DEFAULT_INPUT_OGAIN 100
+
+#define OUTPUT_VOLUME_MIN LHV_MIN
+#define OUTPUT_VOLUME_MAX LHV_MAX
+#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
+
+#define INPUT_VOLUME_MIN LIV_MIN
+#define INPUT_VOLUME_MAX LIV_MAX
+#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+
+#define INPUT_GAIN_MIN LIG_MIN
+#define INPUT_GAIN_MAX LIG_MAX
+#define INPUT_GAIN_RANGE (INPUT_GAIN_MAX - INPUT_GAIN_MIN)
+
+#define OUTPUT_GAIN_MIN LOG_MIN
+#define OUTPUT_GAIN_MAX LOG_MAX
+#define OUTPUT_GAIN_RANGE (INPUT_GAIN_MAX - INPUT_GAIN_MIN)
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED 11
+
+static audio_stream_t output_stream = {
+ .id = "AIC33 out",
+ .dma_dev = DAVINCI_DMA_MCBSP1_TX,
+ .input_or_output = FMODE_WRITE
+};
+
+static audio_stream_t input_stream = {
+ .id = "AIC33 in",
+ .dma_dev = DAVINCI_DMA_MCBSP1_RX,
+ .input_or_output = FMODE_READ
+};
+
+static int audio_dev_id, mixer_dev_id;
+
+static struct aic33_local_info {
+ u8 volume;
+ u16 volume_reg;
+ u8 line;
+ u8 mic;
+ int recsrc;
+ int nochan;
+ u8 igain;
+ u8 ogain;
+ u8 micbias;
+ u8 bass;
+ u8 treble;
+ u16 input_volume_reg;
+ int mod_cnt;
+} aic33_local;
+
+struct sample_rate_reg_info {
+ u32 sample_rate;
+ u32 Fsref;
+ float divider;
+ u8 data;
+};
+
+/* To Store the default sample rate */
+static long audio_samplerate = AUDIO_RATE_DEFAULT;
+
+extern struct clk *davinci_mcbsp_get_clock(void);
+
+/* DAC USB-mode sampling rates*/
+static const struct sample_rate_reg_info
+ reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+/* {sample_rate, Fsref, divider, data}*/
+ {96000, 96000, 1, 0x00},
+ {88200, 88200, 1, 0x00},
+ {48000, 48000, 1, 0x00},
+ {44100, 44100, 1, 0x00},
+ {32000, 48000, 1.5, 0x11},
+ {24000, 96000, 4, 0x66},
+ {22050, 44100, 2, 0x22},
+ {16000, 48000, 3, 0x44},
+ {12000, 48000, 4, 0x66},
+ {11025, 44100, 4, 0x66},
+ {8000, 48000, 6, 0xAA},
+};
+
+static struct davinci_mcbsp_reg_cfg initial_config = {
+ .spcr2 = FREE | XINTM(3),
+ .spcr1 = RINTM(3),
+ .rcr2 = RWDLEN2(DAVINCI_MCBSP_WORD_16) | RDATDLY(1),
+ .rcr1 = RFRLEN1(1) | RWDLEN1(DAVINCI_MCBSP_WORD_16),
+ .xcr2 = XWDLEN2(DAVINCI_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
+ .xcr1 = XFRLEN1(1) | XWDLEN1(DAVINCI_MCBSP_WORD_16),
+ .srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1),
+ .srgr2 = FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1),
+#ifndef AIC33_MASTER
+ /* configure McBSP to be the I2S master */
+ .pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,
+#else
+ /* configure McBSP to be the I2S slave */
+ .pcr0 = CLKXP | CLKRP,
+#endif /* AIC33_MASTER */
+};
+
+static void davinci_aic33_initialize(void *dummy);
+static void davinci_aic33_shutdown(void *dummy);
+static int davinci_aic33_ioctl(struct inode *inode, struct file *file,
+ uint cmd, ulong arg);
+static int davinci_aic33_probe(void);
+
+#ifdef MODULE
+static void davinci_aic33_remove(void);
+#endif
+
+static int davinci_aic33_suspend(void);
+static int davinci_aic33_resume(void);
+static inline void aic33_configure(void);
+static int mixer_open(struct inode *inode, struct file *file);
+static int mixer_release(struct inode *inode, struct file *file);
+static int mixer_ioctl(struct inode *inode, struct file *file, uint cmd,
+ ulong arg);
+
+#ifdef CONFIG_PROC_FS
+static int codec_start(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data);
+static int codec_stop(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data);
+#endif
+
+/* File Op structure for mixer */
+static struct file_operations davinci_mixer_fops = {
+ .open = mixer_open,
+ .release = mixer_release,
+ .ioctl = mixer_ioctl,
+ .owner = THIS_MODULE
+};
+
+/* To store characteristic info regarding the codec for the audio driver */
+static audio_state_t aic33_state = {
+ .owner = THIS_MODULE,
+ .output_stream = &output_stream,
+ .input_stream = &input_stream,
+/* .need_tx_for_rx = 1, //Once the Full Duplex works */
+ .need_tx_for_rx = 0,
+ .hw_init = davinci_aic33_initialize,
+ .hw_shutdown = davinci_aic33_shutdown,
+ .client_ioctl = davinci_aic33_ioctl,
+ .hw_probe = davinci_aic33_probe,
+ .hw_remove = __exit_p(davinci_aic33_remove),
+ .hw_suspend = davinci_aic33_suspend,
+ .hw_resume = davinci_aic33_resume,
+ .sem = __SEMAPHORE_INIT(aic33_state.sem, 1),
+};
+
+/* This will be defined in the audio.h */
+static struct file_operations *davinci_audio_fops;
+
+extern int tlv320aic33_write_value(u8 reg, u16 value);
+
+/* TLV320AIC33 write */
+static __inline__ void audio_aic33_write(u8 address, u16 data)
+{
+ if (tlv320aic33_write_value(address, data) < 0)
+ printk(KERN_INFO "aic33 write failed for reg = %d\n", address);
+}
+
+static int aic33_update(int flag, int val)
+{
+ u16 volume;
+ u16 gain;
+
+ /* Ignore separate left/right channel for now,
+ even the codec does support it. */
+ val &= 0xff;
+
+ switch (flag) {
+ case SET_VOLUME:
+
+ if (val < 0 || val > 100) {
+ DPRINTK("Trying a bad volume value(%d)!\n", val);
+ return -EPERM;
+ }
+ // Convert 0 -> 100 volume to 0x77 (LHV_MIN) -> 0x00 (LHV_MAX)
+ volume =
+ ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN;
+
+ aic33_local.volume_reg = OUTPUT_VOLUME_MAX - volume;
+
+ if (aic33_local.nochan == STEREO) {
+ audio_aic33_write(47, LOPM_ON | aic33_local.volume_reg);
+ audio_aic33_write(64, LOPM_ON | aic33_local.volume_reg);
+ audio_aic33_write(82, LOPM_ON | aic33_local.volume_reg);
+ audio_aic33_write(92, LOPM_ON | aic33_local.volume_reg);
+ } else if (aic33_local.nochan == MONO) {
+#ifdef CONFIG_MONOSTEREO_DIFFJACK
+ /* DACL1 to MONO_LOP/M routing and volume control */
+ audio_aic33_write(75, LOPM_ON | aic33_local.volume_reg);
+
+ /* DACR1 to MONO_LOP/M routing and volume control */
+ audio_aic33_write(78, LOPM_ON | aic33_local.volume_reg);
+#else
+ audio_aic33_write(47, LOPM_ON | aic33_local.volume_reg);
+ audio_aic33_write(64, LOPM_ON | aic33_local.volume_reg);
+ audio_aic33_write(82, LOPM_ON | aic33_local.volume_reg);
+ audio_aic33_write(92, LOPM_ON | aic33_local.volume_reg);
+#endif
+ }
+
+ break;
+
+ case SET_LINE:
+ case SET_MIC:
+
+ if (val < 0 || val > 100) {
+ DPRINTK("Trying a bad volume value(%d)!\n", val);
+ return -EPERM;
+ }
+
+ volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+
+ aic33_local.input_volume_reg = volume;
+
+ audio_aic33_write(15, aic33_local.input_volume_reg);
+ audio_aic33_write(16, aic33_local.input_volume_reg);
+
+ break;
+
+ case SET_RECSRC:
+ if (hweight32(val) > 1)
+ val &= ~aic33_local.recsrc;
+
+ if (val == SOUND_MASK_MIC) {
+ /* enable the mic input*/
+ DPRINTK("Enabling mic\n");
+ audio_aic33_write(17, 0x0);
+ audio_aic33_write(18, 0x0);
+
+ /* enable ADC's and disable the line input*/
+ audio_aic33_write(19, 0x7C);
+ audio_aic33_write(22, 0x7C);
+
+ }
+ else if (val == SOUND_MASK_LINE) {
+ /* enable ADC's, enable line iput */
+ DPRINTK(" Enabling line in\n");
+ audio_aic33_write(19, 0x4);
+ audio_aic33_write(22, 0x4);
+
+ /* disable the mic input */
+ audio_aic33_write(17, 0xff);
+ audio_aic33_write(18, 0xff);
+ }
+ else {
+ /* do nothing */
+ }
+ aic33_local.recsrc = val;
+ break;
+
+ case SET_IGAIN:
+
+ if (val < 0 || val > 100) {
+ DPRINTK("Trying a bad igain value(%d)!\n", val);
+ return -EPERM;
+ }
+
+ gain = ((val * INPUT_GAIN_RANGE) / 100) + INPUT_GAIN_MIN;
+
+ DPRINTK("gain reg val = 0x%x", gain << 1);
+
+ /* Left AGC control */
+ audio_aic33_write(26, 0x80);
+ audio_aic33_write(27, gain << 1);
+ audio_aic33_write(28, 0x0);
+
+ /* Right AGC control */
+ audio_aic33_write(29, 0x80);
+ audio_aic33_write(30, gain << 1);
+ audio_aic33_write(31, 0x0);
+
+ break;
+
+ case SET_OGAIN:
+
+ if (val < 0 || val > 100) {
+ DPRINTK("Trying a bad igain value(%d)!\n", val);
+ return -EPERM;
+ }
+
+ gain = ((val * OUTPUT_GAIN_RANGE) / 100) + OUTPUT_GAIN_MIN;
+ gain = OUTPUT_GAIN_MAX - gain;
+
+ /* Left/Right DAC digital volume gain */
+ audio_aic33_write(43, gain);
+ audio_aic33_write(44, gain);
+ break;
+
+ case SET_MICBIAS:
+
+ if (val < 0 || val > 3) {
+ DPRINTK
+ ("Request for non supported mic bias level(%d)!\n",
+ val);
+ return -EPERM;
+ }
+
+ if (val == 0)
+ audio_aic33_write(25, 0x00);
+
+ else if (val == 1)
+ audio_aic33_write(25, MICBIAS_OUTPUT_2_0V);
+
+ else if (val == 2)
+ audio_aic33_write(25, MICBIAS_OUTPUT_2_5V);
+
+ else if (val == 3)
+ audio_aic33_write(25, MICBIAS_OUTPUT_AVDD);
+
+ break;
+
+ case SET_BASS:
+ break;
+
+ case SET_TREBLE:
+ break;
+ }
+ return 0;
+}
+
+static int mixer_open(struct inode *inode, struct file *file)
+{
+ /* Any mixer specific initialization */
+ return 0;
+}
+
+static int mixer_release(struct inode *inode, struct file *file)
+{
+ /* Any mixer specific Un-initialization */
+ return 0;
+}
+
+static int
+mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+ int val;
+ int ret = 0;
+ int nr = _IOC_NR(cmd);
+
+ /*
+ * We only accept mixer (type 'M') ioctls.
+ */
+ if (_IOC_TYPE(cmd) != 'M')
+ return -EINVAL;
+
+ DPRINTK(" 0x%08x\n", cmd);
+
+ if (cmd == SOUND_MIXER_INFO) {
+ struct mixer_info mi;
+
+ strncpy(mi.id, "AIC33", sizeof(mi.id));
+ strncpy(mi.name, "TI AIC33", sizeof(mi.name));
+ mi.modify_counter = aic33_local.mod_cnt;
+
+ return copy_to_user((void *)arg, &mi, sizeof(mi));
+ }
+
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ ret = get_user(val, (int *)arg);
+ if (ret)
+ goto out;
+
+ switch (nr) {
+ case SOUND_MIXER_VOLUME:
+ aic33_local.mod_cnt++;
+ ret = aic33_update(SET_VOLUME, val);
+ if (!ret)
+ aic33_local.volume = val;
+ break;
+
+ case SOUND_MIXER_LINE:
+ aic33_local.mod_cnt++;
+ ret = aic33_update(SET_LINE, val);
+ if (!ret)
+ aic33_local.line = val;
+ break;
+
+ case SOUND_MIXER_MIC:
+ aic33_local.mod_cnt++;
+ ret = aic33_update(SET_MIC, val);
+ if (!ret)
+ aic33_local.mic = val;
+ break;
+
+ case SOUND_MIXER_RECSRC:
+ if ((val & SOUND_MASK_LINE) ||
+ (val & SOUND_MASK_MIC)) {
+ if (aic33_local.recsrc != val) {
+ aic33_local.mod_cnt++;
+ aic33_update(SET_RECSRC, val);
+ }
+ }
+ else {
+ ret = -EINVAL;
+ }
+ break;
+
+ case SOUND_MIXER_BASS:
+ aic33_local.mod_cnt++;
+ ret = aic33_update(SET_BASS, val);
+ if (!ret)
+ aic33_local.bass = val;
+ break;
+
+ case SOUND_MIXER_TREBLE:
+ aic33_local.mod_cnt++;
+ ret = aic33_update(SET_TREBLE, val);
+ if (!ret)
+ aic33_local.treble = val;
+ break;
+
+ case SOUND_MIXER_IGAIN:
+ aic33_local.mod_cnt++;
+ ret = aic33_update(SET_IGAIN, val);
+ if (!ret)
+ aic33_local.igain = val;
+ break;
+
+ case SOUND_MIXER_OGAIN:
+ aic33_local.mod_cnt++;
+ ret = aic33_update(SET_OGAIN, val);
+ if (!ret)
+ aic33_local.ogain = val;
+ break;
+
+ case SOUND_MIXER_MICBIAS:
+ aic33_local.mod_cnt++;
+ ret = aic33_update(SET_MICBIAS, val);
+ if (!ret)
+ aic33_local.micbias = val;
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+ }
+
+ if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
+ ret = 0;
+
+ switch (nr) {
+ case SOUND_MIXER_VOLUME:
+ val = aic33_local.volume;
+ break;
+ case SOUND_MIXER_LINE:
+ val = aic33_local.line;
+ break;
+ case SOUND_MIXER_MIC:
+ val = aic33_local.mic;
+ break;
+ case SOUND_MIXER_RECSRC:
+ val = aic33_local.recsrc;
+ break;
+ case SOUND_MIXER_RECMASK:
+ val = REC_MASK;
+ break;
+ case SOUND_MIXER_IGAIN:
+ val = aic33_local.igain;
+ break;
+ case SOUND_MIXER_OGAIN:
+ val = aic33_local.ogain;
+ break;
+ case SOUND_MIXER_DEVMASK:
+ val = DEV_MASK;
+ break;
+ case SOUND_MIXER_BASS:
+ val = aic33_local.bass;
+ break;
+ case SOUND_MIXER_TREBLE:
+ val = aic33_local.treble;
+ break;
+ case SOUND_MIXER_CAPS:
+ val = 0;
+ break;
+ case SOUND_MIXER_STEREODEVS:
+ val = SOUND_MASK_VOLUME;
+ break;
+ case SOUND_MIXER_MICBIAS:
+ val = aic33_local.micbias;
+ break;
+ default:
+ val = 0;
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret == 0)
+ ret = put_user(val, (int *)arg);
+ }
+ out:
+ return ret;
+}
+
+int davinci_set_samplerate(long sample_rate)
+{
+ u8 count = 0;
+
+ /* wait for any frame to complete */
+ udelay(125);
+
+ /* Search for the right sample rate */
+ while ((reg_info[count].sample_rate != sample_rate) &&
+ (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
+ count++;
+ }
+
+ if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
+ DPRINTK("Invalid Sample Rate %d requested\n", (int)sample_rate);
+ return -EPERM;
+ }
+
+ /* CODEC DATAPATH SETUP */
+
+ /* Fsref to 48kHz, dual rate mode upto 96kHz */
+ if (reg_info[count].Fsref == 96000)
+ audio_aic33_write(7,
+ FS_REF_DEFAULT_48 | ADC_DUAL_RATE_MODE |
+ DAC_DUAL_RATE_MODE | LDAC_LCHAN | RDAC_RCHAN);
+
+ /* Fsref to 44.1kHz, dual rate mode upto 88.2kHz */
+ else if (reg_info[count].Fsref == 88200)
+ audio_aic33_write(7,
+ FS_REF_44_1 | ADC_DUAL_RATE_MODE |
+ DAC_DUAL_RATE_MODE | LDAC_LCHAN | RDAC_RCHAN);
+
+ /* Fsref to 48kHz */
+ else if (reg_info[count].Fsref == 48000)
+ audio_aic33_write(7,
+ FS_REF_DEFAULT_48 | LDAC_LCHAN | RDAC_RCHAN);
+
+ /* Fsref to 44.1kHz */
+ else if (reg_info[count].Fsref == 44100)
+ audio_aic33_write(7, FS_REF_44_1 | LDAC_LCHAN | RDAC_RCHAN);
+
+
+ /* Codec sample rate select */
+ audio_aic33_write(2, reg_info[count].data);
+
+ /* If PLL is to be used for generation of Fsref
+ Generate the Fsref using the PLL */
+#if(MCLK==33)
+
+ if ((reg_info[count].Fsref == 96000) | (reg_info[count].Fsref == 48000)) {
+ /* For MCLK = 33.8688 MHz and to get Fsref = 48kHz
+ Fsref = (MCLK * k * R)/(2048 * p);
+ Select P = 2, R= 1, K = 5.8049, which results in J = 5, D = 8049 */
+
+ /*Enable the PLL | Q-value | P-value */
+ audio_aic33_write(3, PLL_ENABLE | 0x10 | 0x02);
+ audio_aic33_write(4, 0x14); /* J-value */
+ audio_aic33_write(5, 0x7D); /* D-value 8-MSB's */
+ audio_aic33_write(6, 0x04); /* D-value 6-LSB's */
+
+ }
+
+ else if ((reg_info[count].Fsref == 88200) | (reg_info[count].Fsref ==
+ 44100)) {
+
+ /* MCLK = 33.8688 MHz and to get Fsref = 44.1kHz
+ Fsref = (MCLK * k * R)/(2048 * p);
+ Select P = 2, R =1, K = 5.3333, which results in J = 5, D = 3333 */
+
+ /*Enable the PLL | Q-value | P-value */
+ audio_aic33_write(3, PLL_ENABLE | 0x10 | 0x02);
+ audio_aic33_write(4, 0x14); /* J-value */
+ audio_aic33_write(5, 0x34); /* D-value 8-MSB's */
+ audio_aic33_write(6, 0x14); /* D-value 6-LSB's */
+ }
+#elif(MCLK==22)
+
+ if ((reg_info[count].Fsref == 96000) | (reg_info[count].Fsref == 48000)) {
+ /* For MCLK = 22.5792 MHz and to get Fsref = 48kHz
+ Fsref = (MCLK * k * R)/(2048 * p);
+ Select P = 2, R= 1, K = 8.7075, which results in J = 8, D = 7075 */
+
+ /*Enable the PLL | Q-value | P-value */
+ audio_aic33_write(3, PLL_ENABLE | 0x10 | 0x02);
+ audio_aic33_write(4, (8 << 2)); /* J-value */
+ audio_aic33_write(5, (unsigned char)(7075 >> 6)); /* D-value 8-MSB's */
+ audio_aic33_write(6, (unsigned char)(7075 << 2)); /* D-value 6-LSB's */
+
+ }
+
+ else if ((reg_info[count].Fsref == 88200) | (reg_info[count].Fsref ==
+ 44100)) {
+
+ /* MCLK = 22.5792 MHz and to get Fsref = 44.1kHz
+ Fsref = (MCLK * k * R)/(2048 * p);
+ Select P = 2, R =1, K = 8.0000, which results in J = 8, D = 0000 */
+
+ /*Enable the PLL | Q-value | P-value */
+ audio_aic33_write(3, PLL_ENABLE | 0x10 | 0x02);
+ audio_aic33_write(4, (8 << 2)); /* J-value */
+ audio_aic33_write(5, 0x00); /* D-value 8-MSB's */
+ audio_aic33_write(6, 0x00); /* D-value 6-LSB's */
+ }
+#else
+#error "unknown audio codec frequency"
+#endif
+
+ audio_samplerate = sample_rate;
+
+#ifndef AIC33_MASTER
+ {
+ int clkgdv = 0;
+ unsigned long clkval = 0;
+ struct clk *mbspclk;
+
+ /*
+ Set Sample Rate at McBSP
+
+ Formula :
+ Codec System Clock = Input clock to McBSP;
+ clkgdv = ((Codec System Clock / (SampleRate * BitsPerSample * 2)) - 1);
+
+ FWID = BitsPerSample - 1;
+ FPER = (BitsPerSample * 2) - 1;
+ */
+
+ mbspclk = davinci_mcbsp_get_clock();
+ if (mbspclk == NULL) {
+ DPRINTK(" Failed to get internal clock to MCBSP");
+ return -EPERM;
+ }
+
+ clkval = clk_get_rate(mbspclk);
+ DPRINTK("mcbsp_clk = %ld\n", clkval);
+
+ if (clkval)
+ clkgdv =
+ (clkval /
+ (sample_rate * DEFAULT_BITPERSAMPLE * 2)) - 1;
+ else {
+ DPRINTK(" Failed to get the MCBSP clock\n");
+ return -EPERM;
+ }
+
+ DPRINTK("clkgdv = %d\n", clkgdv);
+
+ if (clkgdv > 255 || clkgdv < 0) {
+
+ /* For requested sampling rate, the input clock to MCBSP cant be devided
+ down to get the in range clock devider value for 16 bits sample */
+ DPRINTK("Invalid Sample Rate %d requested\n",
+ (int)sample_rate);
+ return -EPERM;
+ }
+
+ initial_config.srgr1 =
+ (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+
+ initial_config.srgr2 =
+ (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
+
+ davinci_mcbsp_stop(AUDIO_MCBSP);
+ davinci_mcbsp_config(AUDIO_MCBSP, &initial_config);
+ }
+#endif /* AIC33_MASTER */
+
+ return 0;
+}
+
+static void davinci_aic33_shutdown(void *dummy)
+{
+ /*
+ Turn off codec after it is done.
+ Can't do it immediately, since it may still have
+ buffered data.
+
+ Wait 20ms (arbitrary value) and then turn it off.
+ */
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(2);
+
+ davinci_mcbsp_stop(AUDIO_MCBSP);
+ davinci_mcbsp_free(AUDIO_MCBSP);
+
+ /* Self clearing aic33 software reset */
+ audio_aic33_write(1, 0x80);
+}
+
+static void davinci_set_mono_stereo(int mode)
+{
+ if (mode == MONO) {
+
+#ifdef CONFIG_MONOSTEREO_DIFFJACK
+ /* MONO_LOP/M Output level control register */
+ audio_aic33_write(79, 0x99);
+#else
+ /* Driver power ON pop control */
+ audio_aic33_write(42, 0x6C);
+
+ /* LEFT_LOP/M, RIGHT_LOP/M output level control */
+ audio_aic33_write(86, 0x99);
+ audio_aic33_write(93, 0x99);
+#endif
+ /* Left DAC power up, Right DAC power down */
+ audio_aic33_write(37, 0xa0);
+ } else if (mode == STEREO) {
+ /* Driver power ON pop control */
+ audio_aic33_write(42, 0x6C);
+
+ /* HPLOUT/HPROUT output level control */
+ audio_aic33_write(51, 0x99);
+ audio_aic33_write(65, 0x99);
+
+ /* LEFT_LOP/M, RIGHT_LOP/M output level control */
+ audio_aic33_write(86, 0x99);
+ audio_aic33_write(93, 0x99);
+
+ /* Left/Right DAC power up */
+ audio_aic33_write(37, 0xe0);
+ } else
+ DPRINTK(" REQUEST FOR INVALID MODE\n");
+}
+
+static inline void aic33_configure()
+{
+ DPRINTK(" CONFIGURING AIC33\n");
+
+ /* Page select register */
+ audio_aic33_write(0, 0x0);
+
+ //audio_aic33_write(38, 0x10);
+
+ davinci_set_mono_stereo(aic33_local.nochan);
+
+#ifdef AIC33_MASTER
+ /* Enable bit and word clock as Master mode, 3-d disabled */
+ audio_aic33_write(8, 0xc0 /*0xc4 */ );
+#endif
+
+ aic33_update(SET_LINE, aic33_local.line);
+ aic33_update(SET_VOLUME, aic33_local.volume);
+ aic33_update(SET_RECSRC, aic33_local.recsrc);
+ aic33_update(SET_IGAIN, aic33_local.igain);
+ aic33_update(SET_OGAIN, aic33_local.ogain);
+ aic33_update(SET_MICBIAS, aic33_local.micbias);
+}
+
+static void davinci_aic33_initialize(void *dummy)
+{
+ DPRINTK("entry\n");
+
+ /* initialize with default sample rate */
+ audio_samplerate = AUDIO_RATE_DEFAULT;
+
+ if (davinci_mcbsp_request(AUDIO_MCBSP) < 0) {
+ DPRINTK("MCBSP request failed\n");
+ return;
+ }
+
+ /* if configured, then stop mcbsp */
+ davinci_mcbsp_stop(AUDIO_MCBSP);
+
+ /* set initial (default) sample rate */
+ davinci_set_samplerate(audio_samplerate);
+
+ davinci_mcbsp_config(AUDIO_MCBSP, &initial_config);
+
+ DPRINTK("exit\n");
+}
+
+static int
+davinci_aic33_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+ long val;
+ int ret = 0;
+
+ DPRINTK(" 0x%08x\n", cmd);
+
+ /*
+ * These are platform dependent ioctls which are not handled by the
+ * generic davinci-audio module.
+ */
+ switch (cmd) {
+ case SNDCTL_DSP_STEREO:
+ ret = get_user(val, (int *)arg);
+ if (ret)
+ return ret;
+ /* the Davinci supports AIC33 as stereo, mono on stereo jack */
+ ret = (val == 0) ? -EINVAL : 1;
+ return put_user(ret, (int *)arg);
+
+ case SNDCTL_DSP_CHANNELS:
+
+ ret = get_user(val, (long *)arg);
+ if (ret) {
+ DPRINTK("get_user failed\n");
+ break;
+ }
+ if (val == STEREO) {
+ DPRINTK("Driver support for AIC33 as stereo\n");
+ aic33_local.nochan = STEREO;
+ davinci_set_mono_stereo(aic33_local.nochan);
+ } else if (val == MONO) {
+ DPRINTK("Driver support for AIC33 as mono\n");
+ aic33_local.nochan = MONO;
+ davinci_set_mono_stereo(aic33_local.nochan);
+ } else {
+ DPRINTK
+ ("Driver support for AIC33 as stereo/mono mode\n");
+ return -EPERM;
+ }
+
+ case SOUND_PCM_READ_CHANNELS:
+ /* the Davinci supports AIC33 as stereo, mono on stereo jack */
+ if (aic33_local.nochan == MONO)
+ return put_user(MONO, (long *)arg);
+ else
+ return put_user(STEREO, (long *)arg);
+
+ case SNDCTL_DSP_SPEED:
+ ret = get_user(val, (long *)arg);
+ if (ret) {
+ DPRINTK("get_user failed\n");
+ break;
+ }
+ ret = davinci_set_samplerate(val);
+ if (ret) {
+ DPRINTK("davinci_set_samplerate failed\n");
+ break;
+ }
+ /* fall through */
+
+ case SOUND_PCM_READ_RATE:
+ return put_user(audio_samplerate, (long *)arg);
+
+ case SNDCTL_DSP_SETFMT: /* set Format */
+ ret = get_user(val, (long *)arg);
+ if (ret) {
+ DPRINTK("get_user failed\n");
+ break;
+ }
+ if (val != AFMT_S16_LE) {
+ DPRINTK
+ ("Driver supports only AFMT_S16_LE audio format\n");
+ return -EPERM;
+ }
+
+ case SOUND_PCM_READ_BITS:
+ case SNDCTL_DSP_GETFMTS:
+ /* we can do 16-bit only */
+ return put_user(AFMT_S16_LE, (long *)arg);
+
+ default:
+ /* Maybe this is meant for the mixer (As per OSS Docs) */
+ return mixer_ioctl(inode, file, cmd, arg);
+ }
+
+ return ret;
+}
+
+static int davinci_aic33_probe(void)
+{
+ /* Get the fops from audio oss driver */
+ if (!(davinci_audio_fops = audio_get_fops())) {
+ DPRINTK
+ ("Unable to get the file operations for AIC33 OSS driver\n");
+ audio_unregister_codec(&aic33_state);
+ return -EPERM;
+ }
+
+ aic33_local.volume = DEFAULT_OUTPUT_VOLUME;
+ aic33_local.line = DEFAULT_INPUT_VOLUME;
+ aic33_local.recsrc = SOUND_MASK_LINE; /* either of SOUND_MASK_LINE/SOUND_MASK_MIC */
+ aic33_local.igain = DEFAULT_INPUT_IGAIN;
+ aic33_local.ogain = DEFAULT_INPUT_OGAIN;
+ aic33_local.nochan = STEREO;
+ aic33_local.micbias = 1;
+ aic33_local.mod_cnt = 0;
+
+ /* register devices */
+ audio_dev_id = register_sound_dsp(davinci_audio_fops, -1);
+ mixer_dev_id = register_sound_mixer(&davinci_mixer_fops, -1);
+
+#ifdef CONFIG_PROC_FS
+ create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ ,
+ NULL /* parent dir */ ,
+ codec_start, NULL /* client data */ );
+
+ create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ ,
+ NULL /* parent dir */ ,
+ codec_stop, NULL /* client data */ );
+#endif
+
+ /* Announcement Time */
+ DPRINTK(PLATFORM_NAME " " CODEC_NAME " audio support initialized\n");
+ return 0;
+}
+
+#ifdef MODULE
+static void __exit davinci_aic33_remove(void)
+{
+ /* Un-Register the codec with the audio driver */
+ unregister_sound_dsp(audio_dev_id);
+ unregister_sound_mixer(mixer_dev_id);
+
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry(PROC_START_FILE, NULL);
+ remove_proc_entry(PROC_STOP_FILE, NULL);
+#endif
+}
+#endif /* MODULE */
+
+static int davinci_aic33_suspend(void)
+{
+ /* Empty for the moment */
+ return 0;
+}
+
+static int davinci_aic33_resume(void)
+{
+ /* Empty for the moment */
+ return 0;
+}
+
+static int __init audio_aic33_init(void)
+{
+ int err = 0;
+
+ /* register the codec with the audio driver */
+ if ((err = audio_register_codec(&aic33_state))) {
+ DPRINTK
+ ("Failed to register AIC33 driver with Audio OSS Driver\n");
+ } else {
+ DPRINTK("codec driver register success\n");
+ }
+
+ /* configure aic33 with default params */
+ aic33_configure();
+
+ return err;
+}
+
+static void __exit audio_aic33_exit(void)
+{
+ davinci_aic33_shutdown(NULL);
+ (void)audio_unregister_codec(&aic33_state);
+ return;
+}
+
+#ifdef CONFIG_PROC_FS
+static int codec_start(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data)
+{
+ davinci_aic33_initialize(NULL);
+
+ DPRINTK("AIC33 codec initialization done.\n");
+ return 0;
+}
+
+static int codec_stop(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data)
+{
+ davinci_aic33_shutdown(NULL);
+
+ DPRINTK("AIC33 codec shutdown.\n");
+ return 0;
+}
+#endif /* CONFIG_PROC_FS */
+
+module_init(audio_aic33_init);
+module_exit(audio_aic33_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("Glue audio driver for the TI AIC33 codec.");
+MODULE_LICENSE("GPL");
diff --git a/sound/oss/davinci-audio-dma-intfc.c b/sound/oss/davinci-audio-dma-intfc.c
new file mode 100644
index 0000000..e505014
--- /dev/null
+++ b/sound/oss/davinci-audio-dma-intfc.c
@@ -0,0 +1,1018 @@
+
+/*
+ * linux/sound/oss/davinci-audio-dma-intfc.c
+ *
+ * Common audio DMA handling for the Davinci processors
+ *
+ * Copyright (C) 2006 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * 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:
+ *
+ * 2004-06-07 Sriram Kannan - Created new file from omap_audio_dma_intfc.c. This file
+ * will contain only the DMA interface and buffer handling of OMAP
+ * audio driver.
+ *
+ * 2004-06-22 Sriram Kannan - removed legacy code (auto-init). Self-linking of DMA logical channel.
+ *
+ * 2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ * 2004-11-01 Nishanth Menon - 16xx platform code base modified to support multi channel chaining.
+ *
+ * 2004-12-15 Nishanth Menon - Improved 16xx platform channel logic introduced - tasklets, queue handling updated
+ *
+ * 2005-10-01 Rishi Bhattacharya / Sharath Kumar - Added support for TI Davinci DM644x processor
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/sysrq.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/semaphore.h>
+#include <asm/delay.h>
+
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/edma.h>
+#include <asm/arch/memory.h>
+
+#include "davinci-audio-dma-intfc.h"
+#include "davinci-audio.h"
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
+#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__)
+#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n)
+#else
+
+#define DPRINTK( x... )
+#define FN_IN
+#define FN_OUT(x)
+#endif
+
+#define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS);
+
+#define AUDIO_NAME "davinci-audio"
+#define MCBSP_DXR 0x01E02004
+#define MCBSP_DRR 0x01E02000
+
+#define AUDIO_ACTIVE(state) ((state)->rd_ref || (state)->wr_ref)
+
+#define SPIN_ADDR (dma_addr_t)0
+#define SPIN_SIZE 2048
+
+#define NUMBER_OF_CHANNELS_TO_LINK 2
+
+/* Channel Queue Handling macros
+ * tail always points to the current free entry
+ * Head always points to the current entry being used
+ * end is either head or tail
+ */
+#define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0;
+#define AUDIO_QUEUE_FULL(s) (NUMBER_OF_CHANNELS_TO_LINK == s->dma_q_count)
+#define AUDIO_QUEUE_LAST(s) (1 == s->dma_q_count)
+#define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count)
+#define __AUDIO_INCREMENT_QUEUE(end) ((end)=((end)+1)%NUMBER_OF_CHANNELS_TO_LINK)
+#define AUDIO_INCREMENT_HEAD(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_head);\
+ s->dma_q_count--;
+#define AUDIO_INCREMENT_TAIL(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_tail);\
+ s->dma_q_count++;
+
+/* DMA buffer fragmentation sizes */
+#define MAX_DMA_SIZE (0xffff*2)
+#define CUT_DMA_SIZE MAX_DMA_SIZE
+
+/**************************** DATA STRUCTURES *********************************/
+
+struct audio_isr_work_item {
+ int current_lch;
+ u16 ch_status;
+ audio_stream_t *s;
+};
+
+static char work_item_running = 0;
+static struct audio_isr_work_item work1, work2;
+
+/*********************** MODULE SPECIFIC FUNCTIONS PROTOTYPES ****************/
+
+static void audio_dsr_handler(unsigned long);
+DECLARE_TASKLET(audio_isr_work1, audio_dsr_handler, (unsigned long)&work1);
+DECLARE_TASKLET(audio_isr_work2, audio_dsr_handler, (unsigned long)&work2);
+
+static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
+static void audio_dma_callback(int lch, u16 ch_status, void *data);
+static int davinci_start_sound_dma(audio_stream_t * s, dma_addr_t dma_ptr,
+ u_int size);
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+ u_int dma_size);
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+ u_int dma_size);
+static int audio_start_dma_chain(audio_stream_t * s);
+
+/************************** GLOBAL FUNCTIONS DEFINTIONS ***********************/
+
+/*******************************************************************************
+ *
+ * Buffer creation/destruction
+ *
+ ******************************************************************************/
+int audio_setup_buf(audio_stream_t * s)
+{
+ int frag;
+ int dmasize = 0;
+ char *dmabuf = NULL;
+ dma_addr_t dmaphys = 0;
+ FN_IN;
+
+ if (s->buffers) {
+ FN_OUT(1);
+ return -EBUSY;
+ }
+
+ /* Allocate memory for all buffer fragments */
+ s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);
+ if (!s->buffers)
+ goto err;
+
+ /* Initialise all the memory to 0 */
+ memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags);
+
+ for (frag = 0; frag < s->nbfrags; frag++) {
+ audio_buf_t *b = &s->buffers[frag];
+
+ /*
+ * Let's allocate non-cached memory for DMA buffers.
+ * We try to allocate all memory at once.
+ * If this fails (a common reason is memory fragmentation),
+ * then we allocate more smaller buffers.
+ */
+ if (!dmasize) {
+ dmasize = (s->nbfrags - frag) * s->fragsize;
+ do {
+ /* allocate consistent memory for DMA
+ dmaphys(handle)= device viewed address.
+ dmabuf = CPU-viewed address */
+ dmabuf =
+ dma_alloc_coherent(NULL, dmasize, &dmaphys,
+ 0);
+
+ /* For allocating the IRAM memory */
+ //dmaphys = (dma_addr_t)(DAVINCI_IRAM_BASE + 0x1000);
+ //dmabuf = (DAVINCI_IRAM_VIRT + 0x1000);
+ if (!dmabuf)
+ dmasize -= s->fragsize;
+ }
+ while (!dmabuf && dmasize);
+
+ if (!dmabuf)
+ goto err;
+
+ b->master = dmasize;
+ memzero(dmabuf, dmasize);
+ }
+ b->data = dmabuf;
+ b->dma_addr = dmaphys;
+ dmabuf += s->fragsize;
+ dmaphys += s->fragsize;
+ dmasize -= s->fragsize;
+ }
+ s->usr_head = s->dma_head = s->dma_tail = 0;
+ AUDIO_QUEUE_INIT(s);
+ s->started = 0;
+
+ s->dma_started = 0;
+ s->bytecount = 0;
+ s->fragcount = 0;
+ s->prevbuf = 0;
+
+ init_completion(&s->wfc);
+ s->wfc.done = s->nbfrags;
+
+ FN_OUT(0);
+ return 0;
+ err:
+ audio_discard_buf(s);
+ FN_OUT(1);
+ return -ENOMEM;
+}
+
+void audio_discard_buf(audio_stream_t * s)
+{
+ FN_IN;
+ /* ensure DMA isn't using those buffers */
+ audio_reset(s);
+ if (s->buffers) {
+ int frag;
+ for (frag = 0; frag < s->nbfrags; frag++) {
+ if (!s->buffers[frag].master)
+ continue;
+
+ dma_free_coherent(NULL,
+ s->buffers[frag].master,
+ s->buffers[frag].data,
+ s->buffers[frag].dma_addr);
+
+ }
+ kfree(s->buffers);
+ s->buffers = NULL;
+ }
+ FN_OUT(0);
+}
+
+/*******************************************************************************
+ *
+ * DMA channel requests
+ *
+ ******************************************************************************/
+int
+davinci_request_sound_dma(int device_id, const char *device_name, void *data,
+ int *master_ch, int **channels)
+{
+ int i, err = 0;
+ int *chan = NULL;
+ int tcc;
+
+ FN_IN;
+ if (unlikely((NULL == channels) || (NULL == device_name))) {
+ BUG();
+ return -EPERM;
+ }
+ /* Try allocate memory for the num channels */
+ *channels = (int *)kmalloc(sizeof(int) * NUMBER_OF_CHANNELS_TO_LINK,
+ GFP_KERNEL);
+ chan = *channels;
+ if (NULL == chan) {
+ ERR("No Memory for channel allocs!\n");
+ FN_OUT(-ENOMEM);
+ return -ENOMEM;
+ }
+
+ /* request for the Master channel and setup the params */
+ i = 0;
+ err = davinci_request_dma(device_id, device_name,
+ sound_dma_irq_handler, data, master_ch, &tcc,
+ EVENTQ_0);
+
+ /* Handle Failure condition here */
+ if (err < 0) {
+ ERR("Error in requesting Master channel %d = 0x%x\n", device_id,
+ err);
+
+ FN_OUT(err);
+ return err;
+
+ }
+
+ DPRINTK("Master chan = %d\n", *master_ch);
+
+ for (i = 0; i < NUMBER_OF_CHANNELS_TO_LINK; i++) {
+ err = davinci_request_dma(DAVINCI_EDMA_PARAM_ANY, device_name,
+ sound_dma_irq_handler, data, &chan[i],
+ &tcc, EVENTQ_0);
+
+ /* Handle Failure condition here */
+ if (err < 0) {
+ int j;
+
+ for (j = 0; j < i; j++)
+ davinci_free_dma(chan[j]);
+
+ kfree(chan);
+ *channels = NULL;
+ ERR("Error in requesting channel %d=0x%x\n", i, err);
+ FN_OUT(err);
+ return err;
+ }
+ }
+
+ /* Chain the channels together */
+ for (i = 0; i < NUMBER_OF_CHANNELS_TO_LINK; i++) {
+ int cur_chan = chan[i];
+ int nex_chan = ((NUMBER_OF_CHANNELS_TO_LINK - 1 ==
+ i) ? chan[0] : chan[i + 1]);
+ davinci_dma_link_lch(cur_chan, nex_chan);
+ }
+
+ FN_OUT(0);
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * DMA channel requests Freeing
+ *
+ ******************************************************************************/
+int davinci_free_sound_dma(int master_ch, int **channels)
+{
+ int i;
+ int *chan = NULL;
+ FN_IN;
+ if (unlikely(NULL == channels)) {
+ BUG();
+ return -EPERM;
+ }
+ if (unlikely(NULL == *channels)) {
+ BUG();
+ return -EPERM;
+ }
+ chan = (*channels);
+
+ /* release the Master channel */
+ davinci_free_dma(master_ch);
+
+ for (i = 0; i < NUMBER_OF_CHANNELS_TO_LINK; i++) {
+ int cur_chan = chan[i];
+ int nex_chan = ((NUMBER_OF_CHANNELS_TO_LINK - 1 == i) ?
+ chan[0] : chan[i + 1]);
+
+ davinci_dma_unlink_lch(cur_chan, nex_chan);
+ davinci_free_dma(cur_chan);
+ }
+ kfree(*channels);
+ *channels = NULL;
+ FN_OUT(0);
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Process DMA requests - This will end up starting the transfer.
+ * Proper fragments of Transfers will be initiated.
+ *
+ ******************************************************************************/
+int audio_process_dma(audio_stream_t * s)
+{
+ int ret = 0;
+ unsigned long flags;
+ FN_IN;
+
+ /* Dont let the ISR over ride touching the in_use flag */
+ local_irq_save(flags);
+ if (1 == s->in_use) {
+ local_irq_restore(flags);
+ DPRINTK("Called again while In Use\n");
+ return 0;
+ }
+ s->in_use = 1;
+ local_irq_restore(flags);
+
+ if (s->stopped)
+ goto spin;
+
+ if (s->dma_spinref > 0 && s->pending_frags) {
+ s->dma_spinref = 0;
+ DMA_CLEAR(s);
+ }
+
+ while (s->pending_frags) {
+ audio_buf_t *b = &s->buffers[s->dma_head];
+ u_int dma_size = s->fragsize - b->offset;
+
+ if (dma_size > MAX_DMA_SIZE) {
+ DPRINTK("dma_size > MAX_DMA_SIZE\n");
+ dma_size = CUT_DMA_SIZE;
+ }
+
+ ret = davinci_start_sound_dma(s, b->dma_addr + b->offset,
+ dma_size);
+ if (ret) {
+ DPRINTK("error\n");
+ goto process_out;
+ }
+
+ b->dma_ref++;
+ b->offset += dma_size;
+ if (b->offset >= s->fragsize) {
+ s->pending_frags--;
+ if (++s->dma_head >= s->nbfrags)
+ s->dma_head = 0;
+ }
+ }
+ spin:
+ if (s->spin_idle) {
+ int spincnt = 0;
+ DPRINTK("we are spinning\n");
+ while (davinci_start_sound_dma(s, SPIN_ADDR, SPIN_SIZE) == 0)
+ spincnt++;
+ /*
+ * Note: if there is still a data buffer being
+ * processed then the ref count is negative. This
+ * allows for the DMA termination to be accounted in
+ * the proper order. Of course dma_spinref can't be
+ * greater than 0 if dma_ref is not 0 since we kill
+ * the spinning above as soon as there is real data to process.
+ */
+ if (s->buffers && s->buffers[s->dma_tail].dma_ref)
+ spincnt = -spincnt;
+ s->dma_spinref += spincnt;
+ }
+
+ process_out:
+ s->in_use = 0;
+
+ FN_OUT(ret);
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Prime Rx - Since the recieve buffer has no time limit as to when it would
+ * arrive, we need to prime it
+ *
+ ******************************************************************************/
+void audio_prime_rx(audio_state_t * state)
+{
+ audio_stream_t *is = state->input_stream;
+
+ FN_IN;
+ if (state->need_tx_for_rx) {
+ /*
+ * With some codecs like the Philips UDA1341 we must ensure
+ * there is an output stream at any time while recording since
+ * this is how the UDA1341 gets its clock from the SA1100.
+ * So while there is no playback data to send, the output DMA
+ * will spin with all zeroes. We use the cache flush special
+ * area for that.
+ */
+ state->output_stream->spin_idle = 1;
+ audio_process_dma(state->output_stream);
+ }
+ is->pending_frags = is->nbfrags;
+
+ init_completion(&is->wfc);
+ is->wfc.done = 0;
+
+ is->active = 1;
+ audio_process_dma(is);
+
+ FN_OUT(0);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * set the fragment size
+ *
+ ******************************************************************************/
+int audio_set_fragments(audio_stream_t * s, int val)
+{
+ FN_IN;
+ if (s->active)
+ return -EBUSY;
+ if (s->buffers)
+ audio_discard_buf(s);
+ s->nbfrags = (val >> 16) & 0x7FFF;
+ val &= 0xFFFF;
+ if (val < 4)
+ val = 4;
+ if (val > 15)
+ val = 15;
+ s->fragsize = 1 << val;
+ if (s->nbfrags < 2)
+ s->nbfrags = 2;
+ if (s->nbfrags * s->fragsize > 128 * 1024)
+ s->nbfrags = 128 * 1024 / s->fragsize;
+ FN_OUT(0);
+ if (audio_setup_buf(s))
+ return -ENOMEM;
+ return val | (s->nbfrags << 16);
+
+}
+
+/*******************************************************************************
+ *
+ * Sync up the buffers before we shutdown, else under-run errors will happen
+ *
+ ******************************************************************************/
+int audio_sync(struct file *file)
+{
+ audio_state_t *state = file->private_data;
+ audio_stream_t *s = state->output_stream;
+ audio_buf_t *b;
+ u_int shiftval = 0;
+ unsigned long flags;
+
+ DECLARE_WAITQUEUE(wait, current);
+
+ FN_IN;
+
+ if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped) {
+ FN_OUT(1);
+ return 0;
+ }
+
+ /*
+ * Send current buffer if it contains data. Be sure to send
+ * a full sample count.
+ */
+ b = &s->buffers[s->usr_head];
+ mdelay(20);
+ if (b->offset &= ~3) {
+ /*wait for a buffer to become free */
+ if (wait_for_completion_interruptible(&s->wfc))
+ return 0;
+ /*
+ * HACK ALERT !
+ * To avoid increased complexity in the rest of the code
+ * where full fragment sizes are assumed, we cheat a little
+ * with the start pointer here and don't forget to restore
+ * it later.
+ */
+ shiftval = s->fragsize - b->offset;
+ b->offset = shiftval;
+ b->dma_addr -= shiftval;
+ b->data -= shiftval;
+ local_irq_save(flags);
+ s->bytecount -= shiftval;
+ if (++s->usr_head >= s->nbfrags)
+ s->usr_head = 0;
+
+ s->pending_frags++;
+ audio_process_dma(s);
+ local_irq_restore(flags);
+ }
+
+ /* Let's wait for all buffers to complete */
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&s->wq, &wait);
+
+ while ((s->pending_frags || (s->wfc.done < s->nbfrags))
+ && !signal_pending(current)) {
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&s->wq, &wait);
+
+ /* undo the pointer hack above */
+ if (shiftval) {
+ local_irq_save(flags);
+ b->dma_addr += shiftval;
+ b->data += shiftval;
+ /* ensure sane DMA code behavior if not yet processed */
+ if (b->offset != 0)
+ b->offset = s->fragsize;
+ local_irq_restore(flags);
+ }
+
+ FN_OUT(0);
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Stop all the DMA channels of the stream
+ *
+ ******************************************************************************/
+void audio_stop_dma(audio_stream_t * s)
+{
+
+ unsigned long flags;
+ FN_IN;
+ DPRINTK("audio_stop_dma\n");
+
+ if (s->dma_spinref > 0 || !s->buffers)
+ return;
+
+ local_irq_save(flags);
+
+ davinci_stop_dma(s->master_ch);
+ s->dma_started = 0;
+
+ if (s->spin_idle) {
+#if 0
+ DMA_START(s, SPIN_ADDR, SPIN_SIZE);
+ DMA_START(s, SPIN_ADDR, SPIN_SIZE);
+#endif
+ s->dma_spinref = 2;
+ } else
+ s->dma_spinref = 0;
+
+ local_irq_restore(flags);
+
+ FN_OUT(0);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Get the dma posn
+ *
+ ******************************************************************************/
+u_int audio_get_dma_pos(audio_stream_t * s)
+{
+ audio_buf_t *b = &s->buffers[s->dma_tail];
+ u_int offset = 0;
+
+ FN_IN;
+ if (b->dma_ref) {
+ edmacc_paramentry_regs temp;
+
+ davinci_get_dma_params(s->master_ch, &temp);
+
+ if (s->input_or_output == FMODE_WRITE)
+ offset = temp.src - b->dma_addr;
+ else if (s->input_or_output == FMODE_READ)
+ offset = temp.dst - b->dma_addr;
+ if (offset >= s->fragsize)
+ offset = s->fragsize - 4;
+ } else if (s->pending_frags) {
+ offset = b->offset;
+ } else {
+ offset = 0;
+ }
+ FN_OUT(offset);
+ return offset;
+}
+
+/*******************************************************************************
+ *
+ * Reset the audio buffers
+ *
+ ******************************************************************************/
+void audio_reset(audio_stream_t * s)
+{
+ audio_buf_t *b;
+ FN_IN;
+ if (s->buffers) {
+
+ davinci_mcbsp_stop(0);
+ s->started = 0;
+ audio_stop_dma(s);
+ /* back up pointers to be ready to restart from the same spot */
+ while (s->dma_head != s->dma_tail) {
+ b = &s->buffers[s->dma_head];
+ if (b->dma_ref) {
+ b->dma_ref = 0;
+ b->offset = 0;
+ }
+ s->pending_frags++;
+ if (s->dma_head == 0)
+ s->dma_head = s->nbfrags;
+ s->dma_head--;
+ }
+ b = &s->buffers[s->dma_head];
+ if (b->dma_ref) {
+ b->offset = 0;
+ b->dma_ref = 0;
+ }
+
+ s->buffers[s->dma_head].offset = 0;
+ s->buffers[s->usr_head].offset = 0;
+ s->usr_head = s->dma_head;
+ s->pending_frags = 0;
+ init_completion(&s->wfc);
+ s->wfc.done = s->nbfrags;
+ }
+ AUDIO_QUEUE_INIT(s);
+ s->active = 0;
+ s->stopped = 0;
+
+ FN_OUT(0);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Clear any pending transfers
+ *
+ ******************************************************************************/
+void davinci_clear_sound_dma(audio_stream_t * s)
+{
+#if 0
+ FN_IN;
+ davinci_clear_dma(s->lch[s->dma_q_head]);
+ FN_OUT(0);
+#endif
+ return;
+}
+
+/*******************************************************************************
+ *
+ * DMA related functions
+ *
+ ******************************************************************************/
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ FN_IN;
+ DPRINTK("audio_set_dma_params_play channel = %d dma_ptr = %x \
+ dma_size=%x\n", channel, dma_ptr, dma_size);
+
+ davinci_set_dma_src_params(channel, (unsigned long)(dma_ptr), 0, 0);
+ davinci_set_dma_dest_params(channel, (unsigned long)MCBSP_DXR, 0, 0);
+ davinci_set_dma_src_index(channel, 2, 0);
+ davinci_set_dma_dest_index(channel, 0, 0);
+ davinci_set_dma_transfer_params(channel, 2, dma_size / 2, 1, 0, ASYNC);
+
+ FN_OUT(0);
+ return 0;
+}
+
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ FN_IN;
+ DPRINTK("audio_set_dma_params_capture channel = %d dma_ptr = %x \
+ dma_size=%x\n", channel, dma_ptr, dma_size);
+
+ davinci_set_dma_src_params(channel, (unsigned long)MCBSP_DRR, 0, 0);
+ davinci_set_dma_dest_params(channel, (unsigned long)(dma_ptr), 0, 0);
+ davinci_set_dma_src_index(channel, 0, 0);
+ davinci_set_dma_dest_index(channel, 2, 0);
+ davinci_set_dma_transfer_params(channel, 2, dma_size / 2, 1, 0, ASYNC);
+
+ FN_OUT(0);
+ return 0;
+}
+
+static int audio_start_dma_chain(audio_stream_t * s)
+{
+ int channel = s->lch[s->dma_q_head];
+ FN_IN;
+
+ if (!s->dma_started) {
+ edmacc_paramentry_regs temp;
+ davinci_get_dma_params(channel, &temp);
+ davinci_set_dma_params(s->master_ch, &temp);
+
+ davinci_start_dma(s->master_ch);
+ s->dma_started = 1;
+ }
+
+ if (!s->started) {
+ davinci_mcbsp_start(0);
+ s->started = 1;
+ }
+
+ /* else the dma itself will progress forward with out our help */
+ FN_OUT(0);
+ return 0;
+}
+
+/* Start DMA -
+ * Do the initial set of work to initialize all the channels as required.
+ * We shall then initate a transfer
+ */
+
+static int davinci_start_sound_dma(audio_stream_t * s, dma_addr_t dma_ptr,
+ u_int dma_size)
+{
+ int ret = -EPERM;
+
+ FN_IN;
+ if (unlikely(dma_size > MAX_DMA_SIZE)) {
+ ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
+ MAX_DMA_SIZE);
+ return -EOVERFLOW;
+ }
+
+ if (AUDIO_QUEUE_FULL(s)) {
+ DPRINTK("queue full\n");
+ ret = -2;
+ goto sound_out;
+ }
+ if (s->input_or_output == FMODE_WRITE)
+ /*playback */
+ {
+ ret = audio_set_dma_params_play(s->lch[s->dma_q_tail],
+ dma_ptr, dma_size);
+ } else {
+ ret = audio_set_dma_params_capture(s->lch[s->dma_q_tail],
+ dma_ptr, dma_size);
+ }
+ if (ret != 0) {
+ ret = -2; /* indicate queue full */
+ goto sound_out;
+ }
+ AUDIO_INCREMENT_TAIL(s);
+ ret = audio_start_dma_chain(s);
+ if (ret) {
+ ERR("dma start failed");
+ }
+ sound_out:
+ FN_OUT(ret);
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * ISR related functions
+ *
+ ******************************************************************************/
+/* The work item handler */
+static void audio_dsr_handler(unsigned long inData)
+{
+ void *data = (void *)inData;
+ struct audio_isr_work_item *work = data;
+ audio_stream_t *s = (work->s);
+ int sound_curr_lch = work->current_lch;
+ u16 ch_status = work->ch_status;
+
+ FN_IN;
+ DPRINTK("lch=%d,status=0x%x, data=%p as=%p\n", sound_curr_lch,
+ ch_status, data, s);
+ if (AUDIO_QUEUE_EMPTY(s)) {
+ DPRINTK("Interrupt(%d) for empty queue(h=%d, T=%d)???\n",
+ sound_curr_lch, s->dma_q_head, s->dma_q_tail);
+ DPRINTK("nbfrag=%d,pendfrags=%d,USR-H=%d, QH-%d QT-%d\n",
+ s->nbfrags, s->pending_frags, s->usr_head, s->dma_head,
+ s->dma_tail);
+ AUDIO_INCREMENT_HEAD(s); /* Empty the queue */
+ FN_OUT(-1);
+ return;
+ }
+
+ AUDIO_INCREMENT_HEAD(s); /* Empty the queue */
+
+ /* Try to fill again */
+ audio_dma_callback(sound_curr_lch, ch_status, s);
+ FN_OUT(0);
+
+}
+
+/* Macro to trace the IRQ calls - checks for multi-channel irqs */
+//#define IRQ_TRACE
+#ifdef IRQ_TRACE
+#define MAX_UP 10
+static char xyz[MAX_UP] = { 0 };
+static int h = 0;
+#endif
+
+/* ISRs have to be short and smart.. So we transfer every heavy duty stuff to
+ * the work item
+ */
+static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status, void *data)
+{
+ audio_stream_t *s = (audio_stream_t *) data;
+ FN_IN;
+
+ if (ch_status == DMA_COMPLETE) {
+
+#ifdef IRQ_TRACE
+ xyz[h++] = '0' + sound_curr_lch;
+ if (h == MAX_UP - 1) {
+ DPRINTK("%s-", xyz);
+ h = 0;
+ }
+#endif
+
+ sound_curr_lch = s->lch[s->dma_q_head];
+
+ DPRINTK("lch=%d,status=0x%x, data=%p\n", sound_curr_lch,
+ ch_status, data);
+
+ if (AUDIO_QUEUE_LAST(s)) {
+ audio_stream_t *s = data;
+ audio_buf_t *b = &s->buffers[s->dma_tail];
+
+ if (s->dma_spinref > 0) {
+ s->dma_spinref--;
+ } else if (!s->buffers) {
+ DPRINTK
+ ("davinci_audio: received DMA IRQ for non\
+ existent buffers!\n");
+ return;
+ } else if (b->dma_ref && --b->dma_ref == 0 &&
+ b->offset >= s->fragsize) {
+ /* This fragment is done */
+ b->offset = 0;
+ s->bytecount += s->fragsize;
+ s->fragcount++;
+ s->dma_spinref = -s->dma_spinref;
+
+ if (++s->dma_tail >= s->nbfrags)
+ s->dma_tail = 0;
+
+ if (!s->mapped) {
+ complete(&s->wfc);
+ } else
+ s->pending_frags++;
+
+ wake_up(&s->wq);
+ }
+
+ AUDIO_INCREMENT_HEAD(s);
+ audio_stop_dma(s);
+ return;
+ }
+
+ /* Start the work item - we ping pong the work items */
+ if (!work_item_running) {
+ work1.current_lch = sound_curr_lch;
+ work1.ch_status = ch_status;
+ work1.s = s;
+ /* schedule tasklet 1 */
+ tasklet_schedule(&audio_isr_work1);
+ work_item_running = 1;
+ } else {
+ work2.current_lch = sound_curr_lch;
+ work2.ch_status = ch_status;
+ work2.s = s;
+ /* schedule tasklet 2 */
+ tasklet_schedule(&audio_isr_work2);
+ work_item_running = 0;
+ }
+ } else {
+ DPRINTK("Error in DMA \n");
+ }
+
+ FN_OUT(0);
+ return;
+}
+
+/* The call back that handles buffer stuff */
+static void audio_dma_callback(int lch, u16 ch_status, void *data)
+{
+ audio_stream_t *s = data;
+ audio_buf_t *b = &s->buffers[s->dma_tail];
+ FN_IN;
+
+ if (s->dma_spinref > 0) {
+ s->dma_spinref--;
+ } else if (!s->buffers) {
+ DPRINTK
+ ("davinci_audio: received DMA IRQ for non existent buffers!\n");
+ return;
+ } else if (b->dma_ref && --b->dma_ref == 0 && b->offset >= s->fragsize) {
+ /* This fragment is done */
+ b->offset = 0;
+ s->bytecount += s->fragsize;
+ s->fragcount++;
+ s->dma_spinref = -s->dma_spinref;
+
+ if (++s->dma_tail >= s->nbfrags)
+ s->dma_tail = 0;
+
+ if (!s->mapped) {
+ complete(&s->wfc);
+ } else
+ s->pending_frags++;
+
+ wake_up(&s->wq);
+ }
+
+ audio_process_dma(s);
+
+ FN_OUT(0);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * audio_get_dma_callback(): return the dma interface call back function
+ *
+ ******************************************************************************/
+dma_callback_t audio_get_dma_callback(void)
+{
+ FN_IN;
+ FN_OUT(0);
+ return audio_dma_callback;
+}
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION
+ ("Common DMA handling for Audio driver on DAVINCI processors");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(davinci_clear_sound_dma);
+EXPORT_SYMBOL(davinci_request_sound_dma);
+EXPORT_SYMBOL(davinci_free_sound_dma);
+
+EXPORT_SYMBOL(audio_get_dma_callback);
+EXPORT_SYMBOL(audio_setup_buf);
+EXPORT_SYMBOL(audio_process_dma);
+EXPORT_SYMBOL(audio_prime_rx);
+EXPORT_SYMBOL(audio_set_fragments);
+EXPORT_SYMBOL(audio_sync);
+EXPORT_SYMBOL(audio_stop_dma);
+EXPORT_SYMBOL(audio_get_dma_pos);
+EXPORT_SYMBOL(audio_reset);
+EXPORT_SYMBOL(audio_discard_buf);
diff --git a/sound/oss/davinci-audio-dma-intfc.h b/sound/oss/davinci-audio-dma-intfc.h
new file mode 100644
index 0000000..2d48cd9a
--- /dev/null
+++ b/sound/oss/davinci-audio-dma-intfc.h
@@ -0,0 +1,63 @@
+/*
+ * linux/sound/oss/davinci-audio-dma-intfc.h
+ *
+ * Common audio DMA handling for the Davinci processors
+ *
+ * Copyright (C) 2006 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * 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:
+ *
+ * 2005-10-01 Rishi Bhattacharya / Sharath Kumar - Added support for TI Davinci DM644x processor
+ */
+
+#ifndef __DAVINCI_AUDIO_DMA_INTFC_H
+#define __DAVINCI_AUDIO_DMA_INTFC_H
+
+/******************************* INCLUDES *************************************/
+
+/* Requires davinci-audio.h */
+#include "davinci-audio.h"
+
+/************************** GLOBAL MACROS *************************************/
+
+/* Provide the Macro interfaces common across platforms */
+#define DMA_REQUEST(e,s, cb) {e=davinci_request_sound_dma(s->dma_dev, s->id, s, &s->master_ch, &s->lch);}
+#define DMA_FREE(s) davinci_free_sound_dma(s->master_ch,&s->lch)
+#define DMA_CLEAR(s) davinci_clear_sound_dma(s)
+
+/************************** GLOBAL DATA STRUCTURES ****************************/
+
+typedef void (*dma_callback_t) (int lch, u16 ch_status, void *data);
+
+/************************** GLOBAL FUNCTIONS **********************************/
+
+dma_callback_t audio_get_dma_callback(void);
+int audio_setup_buf(audio_stream_t * s);
+int audio_process_dma(audio_stream_t * s);
+void audio_prime_rx(audio_state_t * state);
+int audio_set_fragments(audio_stream_t * s, int val);
+int audio_sync(struct file *file);
+void audio_stop_dma(audio_stream_t * s);
+u_int audio_get_dma_pos(audio_stream_t * s);
+void audio_reset(audio_stream_t * s);
+void audio_discard_buf(audio_stream_t * s);
+
+/**************** ARCH SPECIFIC FUNCIONS **************************************/
+
+void davinci_clear_sound_dma(audio_stream_t * s);
+
+int davinci_request_sound_dma(int device_id, const char *device_name,
+ void *data, int *master_ch, int **channels);
+int davinci_free_sound_dma(int master_ch, int **channels);
+
+#endif /* #ifndef __DAVINCI_AUDIO_DMA_INTFC_H */
diff --git a/sound/oss/davinci-audio.c b/sound/oss/davinci-audio.c
new file mode 100644
index 0000000..b8b2fbc
--- /dev/null
+++ b/sound/oss/davinci-audio.c
@@ -0,0 +1,1176 @@
+/*
+ * linux/sound/oss/davinci-audio.c
+ *
+ * Common audio handling for the Davinci processors
+ *
+ * Copyright (C) 2006 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * 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:
+ *
+ * 2004/08/12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms
+ *
+ * 2004-11-01 Nishanth Menon - modified to support 16xx and 17xx
+ * platform multi channel chaining.
+ *
+ * 2004-11-04 Nishanth Menon - Added support for power management
+ *
+ * 2004-12-17 Nishanth Menon - Provided proper module handling support
+ *
+ * 2005-10-01 Rishi Bhattacharya - Adapted to TI Davinci Family of processors
+ */
+
+/***************************** INCLUDES ************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/sysrq.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/semaphore.h>
+
+#include "davinci-audio-dma-intfc.h"
+#include "davinci-audio.h"
+
+/***************************** MACROS ************************************/
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#define FN_IN printk("[davinci_audio.c:[%s] start\n", __FUNCTION__)
+#define FN_OUT(n) printk("[davinci_audio.c:[%s] end(%d)\n", __FUNCTION__ , n)
+#else
+#define DPRINTK( x... )
+#define FN_IN
+#define FN_OUT(x)
+#endif
+
+#define DAVINCI_AUDIO_NAME "davinci-audio"
+
+#define AUDIO_NBFRAGS_DEFAULT 4
+#define AUDIO_FRAGSIZE_DEFAULT 3072
+
+/*************/
+
+/* HACK ALERT!: These values will bave to be tuned as this is a trade off b/w
+ * Sampling Rate vs buffer size and delay we are prepared to do before giving up
+ */
+#define MAX_QUEUE_FULL_RETRIES 1000000
+#define QUEUE_WAIT_TIME 10
+
+#define AUDIO_ACTIVE(state) ((state)->rd_ref || (state)->wr_ref)
+
+#define SPIN_ADDR (dma_addr_t)0
+#define SPIN_SIZE 2048
+
+/********************** MODULES SPECIFIC FUNCTION PROTOTYPES ***************/
+
+static int audio_write(struct file *file, const char *buffer,
+ size_t count, loff_t * ppos);
+
+static int audio_read(struct file *file, char *buffer, size_t count,
+ loff_t * ppos);
+
+static int audio_mmap(struct file *file, struct vm_area_struct *vma);
+
+static unsigned int audio_poll(struct file *file,
+ struct poll_table_struct *wait);
+
+static loff_t audio_llseek(struct file *file, loff_t offset, int origin);
+
+static int audio_ioctl(struct inode *inode, struct file *file, uint cmd,
+ ulong arg);
+
+static int audio_open(struct inode *inode, struct file *file);
+
+static int audio_release(struct inode *inode, struct file *file);
+
+static int audio_probe(struct device *dev);
+
+static int audio_remove(struct device *dev);
+
+static void audio_shutdown(struct device *dev);
+
+static int audio_suspend(struct device *dev, pm_message_t state);
+
+static int audio_resume(struct device *dev);
+
+static void audio_free(struct device *dev);
+
+/***************************** Data Structures ********************************/
+
+/*
+ * The function pointer set to be registered by the codec.
+ */
+static audio_state_t audio_state = { 0 };
+
+/* DMA Call back function */
+static dma_callback_t audio_dma_callback = 0;
+
+/* File Ops structure */
+static struct file_operations davinci_audio_fops = {
+ .open = audio_open,
+ .release = audio_release,
+ .write = audio_write,
+ .read = audio_read,
+ .mmap = audio_mmap,
+ .poll = audio_poll,
+ .ioctl = audio_ioctl,
+ .llseek = audio_llseek,
+ .owner = THIS_MODULE
+};
+
+/* Driver information */
+static struct device_driver davinci_audio_driver = {
+ .name = DAVINCI_AUDIO_NAME,
+ .bus = &platform_bus_type,
+ .probe = audio_probe,
+ .remove = audio_remove,
+ .suspend = audio_suspend,
+ .resume = audio_resume,
+ .shutdown = audio_shutdown,
+};
+
+/* Device Information */
+static struct platform_device davinci_audio_device = {
+ .name = DAVINCI_AUDIO_NAME,
+ .dev = {
+ .driver_data = &audio_state,
+ .release = audio_free,
+ },
+ .id = 0,
+};
+
+/***************************** GLOBAL FUNCTIONs *******************************/
+
+/* Power Management Functions for Linux Device Model */
+/* DEBUG PUPOSES ONLY! */
+#ifdef CONFIG_PM
+//#undef CONFIG_PM
+#endif
+
+#ifdef CONFIG_PM
+/*******************************************************************************
+ *
+ * audio_ldm_suspend(): Suspend operation
+ *
+ ******************************************************************************/
+static int audio_ldm_suspend(void *data)
+{
+ audio_state_t *state = data;
+
+ FN_IN;
+
+ /*
+ * Reject the suspend request if we are already actively transmitting data
+ * Rationale: We dont want to be suspended while in the middle of a call!
+ */
+ if (AUDIO_ACTIVE(state) && state->hw_init) {
+ DPRINTK("Audio device Active, Cannot Suspend");
+ return -EPERM;
+#if 0
+ /* NOTE:
+ * This Piece of code is commented out in hope
+ * That one day we would need to suspend the device while
+ * audio operations are in progress and resume the operations
+ * once the resume is done.
+ * This is just a sample implementation of how it could be done.
+ * Currently NOT SUPPORTED
+ */
+ audio_stream_t *is = state->input_stream;
+ audio_stream_t *os = state->output_stream;
+ int stopstate;
+ if (is && is->buffers) {
+ DPRINTK("IS Suspend\n");
+ stopstate = is->stopped;
+ audio_stop_dma(is);
+ DMA_CLEAR(is);
+ is->dma_spinref = 0;
+ is->stopped = stopstate;
+ }
+ if (os && os->buffers) {
+ DPRINTK("OS Suspend\n");
+ stopstate = os->stopped;
+ audio_stop_dma(os);
+ DMA_CLEAR(os);
+ os->dma_spinref = 0;
+ os->stopped = stopstate;
+ }
+#endif
+ }
+
+ FN_OUT(0);
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * audio_ldm_resume(): Resume Operations
+ *
+ ******************************************************************************/
+static int audio_ldm_resume(void *data)
+{
+ audio_state_t *state = data;
+
+ FN_IN;
+ if (AUDIO_ACTIVE(state) && state->hw_init) {
+ /* Should never occur - since we never suspend with active state */
+ BUG();
+ return -EPERM;
+#if 0
+ /* NOTE:
+ * This Piece of code is commented out in hope
+ * That one day we would need to suspend the device while
+ * audio operations are in progress and resume the operations
+ * once the resume is done.
+ * This is just a sample implementation of how it could be done.
+ * Currently NOT SUPPORTED
+ */
+ audio_stream_t *is = state->input_stream;
+ audio_stream_t *os = state->output_stream;
+ if (os && os->buffers) {
+ DPRINTK("OS Resume\n");
+ audio_reset(os);
+ audio_process_dma(os);
+ }
+ if (is && is->buffers) {
+ DPRINTK("IS Resume\n");
+ audio_reset(is);
+ audio_process_dma(is);
+ }
+#endif
+ }
+ FN_OUT(0);
+ return 0;
+}
+#endif /* End of #ifdef CONFIG_PM */
+
+/*******************************************************************************
+ *
+ * audio_free(): The Audio driver release function
+ * This is a dummy function required by the platform driver
+ *
+ ******************************************************************************/
+static void audio_free(struct device *dev)
+{
+ /* Nothing to Release! */
+}
+
+/*******************************************************************************
+ *
+ * audio_probe(): The Audio driver probe function
+ * WARNING!!!! : It is expected that the codec would have registered with us by now
+ *
+ ******************************************************************************/
+static int audio_probe(struct device *dev)
+{
+ int ret;
+ FN_IN;
+ if (!audio_state.hw_probe) {
+ DPRINTK("Probe Function Not Registered\n");
+ return -ENODEV;
+ }
+ ret = audio_state.hw_probe();
+ FN_OUT(ret);
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * audio_remove() Function to handle removal operations
+ *
+ ******************************************************************************/
+static int audio_remove(struct device *dev)
+{
+ FN_IN;
+ if (audio_state.hw_remove) {
+ audio_state.hw_remove();
+ }
+ FN_OUT(0);
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * audio_shutdown(): Function to handle shutdown operations
+ *
+ ******************************************************************************/
+static void audio_shutdown(struct device *dev)
+{
+ FN_IN;
+ if (audio_state.hw_cleanup) {
+ audio_state.hw_cleanup();
+ }
+ FN_OUT(0);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * audio_suspend(): Function to handle suspend operations
+ *
+ ******************************************************************************/
+static int audio_suspend(struct device *dev, pm_message_t state)
+{
+ int ret = 0;
+
+#ifdef CONFIG_PM
+ void *data = dev->driver_data;
+ FN_IN;
+ if (audio_state.hw_suspend) {
+ ret = audio_ldm_suspend(data);
+ if (ret == 0)
+ ret = audio_state.hw_suspend();
+ }
+ if (ret) {
+ DPRINTK("Audio Suspend Failed \n");
+ } else {
+ DPRINTK("Audio Suspend Success \n");
+ }
+#endif /* CONFIG_PM */
+
+ FN_OUT(ret);
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * audio_resume(): Function to handle resume operations
+ *
+ ******************************************************************************/
+static int audio_resume(struct device *dev)
+{
+ int ret = 0;
+
+#ifdef CONFIG_PM
+ void *data = dev->driver_data;
+ FN_IN;
+ if (audio_state.hw_resume) {
+ ret = audio_ldm_resume(data);
+ if (ret == 0)
+ ret = audio_state.hw_resume();
+ }
+ if (ret) {
+ DPRINTK(" Audio Resume Failed \n");
+ } else {
+ DPRINTK(" Audio Resume Success \n");
+ }
+#endif /* CONFIG_PM */
+
+ FN_OUT(ret);
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * audio_get_fops(): Return the fops required to get the function pointers of
+ * DAVINCI Audio Driver
+ *
+ ******************************************************************************/
+struct file_operations *audio_get_fops(void)
+{
+ FN_IN;
+ FN_OUT(0);
+ return &davinci_audio_fops;
+}
+
+/*******************************************************************************
+ *
+ * audio_register_codec(): Register a Codec fn points using this function
+ * WARNING!!!!! : Codecs should ensure that they do so! no sanity checks
+ * during runtime is done due to obvious performance
+ * penalties.
+ *
+ ******************************************************************************/
+int audio_register_codec(audio_state_t * codec_state)
+{
+ int ret;
+ FN_IN;
+
+ /* We dont handle multiple codecs now */
+ if (audio_state.hw_init) {
+ DPRINTK(" Codec Already registered\n");
+ return -EPERM;
+ }
+
+ /* Grab the dma Callback */
+ audio_dma_callback = audio_get_dma_callback();
+ if (!audio_dma_callback) {
+ DPRINTK("Unable to get call back function\n");
+ return -EPERM;
+ }
+
+ /* Sanity checks */
+ if (!codec_state) {
+ DPRINTK("NULL ARGUMENT!\n");
+ return -EPERM;
+ }
+
+ if (!codec_state->hw_probe || !codec_state->hw_init
+ || !codec_state->hw_shutdown || !codec_state->client_ioctl) {
+ DPRINTK
+ ("Required Fn Entry point Missing probe=%p init=%p,down=%p,ioctl=%p!\n",
+ codec_state->hw_probe, codec_state->hw_init,
+ codec_state->hw_shutdown, codec_state->client_ioctl);
+ return -EPERM;
+ }
+
+ memcpy(&audio_state, codec_state, sizeof(audio_state_t));
+ sema_init(&audio_state.sem, 1);
+
+ ret = platform_device_register(&davinci_audio_device);
+ if (ret != 0) {
+ DPRINTK("Platform dev_register failed =%d\n", ret);
+ ret = -ENODEV;
+ goto register_out;
+ }
+
+ ret = driver_register(&davinci_audio_driver);
+ if (ret != 0) {
+ DPRINTK("Device Register failed =%d\n", ret);
+ ret = -ENODEV;
+ platform_device_unregister(&davinci_audio_device);
+ goto register_out;
+ }
+
+ DPRINTK("audio driver register success\n");
+
+ register_out:
+
+ FN_OUT(ret);
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * audio_unregister_codec(): Un-Register a Codec using this function
+ *
+ ******************************************************************************/
+int audio_unregister_codec(audio_state_t * codec_state)
+{
+ FN_IN;
+
+ /* We dont handle multiple codecs now */
+ if (!audio_state.hw_init) {
+ DPRINTK(" No Codec registered\n");
+ return -EPERM;
+ }
+ /* Security check */
+ if (audio_state.hw_init != codec_state->hw_init) {
+ DPRINTK
+ ("Attempt to unregister codec which was not registered with us\n");
+ return -EPERM;
+ }
+
+ driver_unregister(&davinci_audio_driver);
+ platform_device_unregister(&davinci_audio_device);
+
+ memset(&audio_state, 0, sizeof(audio_state_t));
+
+ FN_OUT(0);
+ return 0;
+}
+
+/***************************** MODULES SPECIFIC FUNCTION **********************/
+
+/*******************************************************************************
+ *
+ * audio_write(): Exposed to write() call
+ *
+ ******************************************************************************/
+static int
+audio_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
+{
+ const char *buffer0 = buffer;
+ audio_state_t *state = file->private_data;
+ audio_stream_t *s = state->output_stream;
+ int chunksize, ret = 0;
+
+ DPRINTK("audio_write: count=%d\n", count);
+ if (*ppos != file->f_pos) {
+ DPRINTK("FPOS not ppos ppos=0x%x fpos =0x%x\n", (u32) * ppos,
+ (u32) file->f_pos);
+ return -ESPIPE;
+ }
+ if (s->mapped) {
+ DPRINTK("s already mapped\n");
+ return -ENXIO;
+ }
+ if (!s->buffers && audio_setup_buf(s)) {
+ DPRINTK("NO MEMORY\n");
+ return -ENOMEM;
+ }
+
+ while (count > 0) {
+ audio_buf_t *b = &s->buffers[s->usr_head];
+
+ /* Wait for a buffer to become free */
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ if (!s->wfc.done)
+ break;
+ } else {
+ ret = -ERESTARTSYS;
+ if (wait_for_completion_interruptible(&s->wfc))
+ break;
+ }
+
+ /* Feed the current buffer */
+ chunksize = s->fragsize - b->offset;
+ if (chunksize > count)
+ chunksize = count;
+ DPRINTK("write %d to %d\n", chunksize, s->usr_head);
+ if (copy_from_user(b->data + b->offset, buffer, chunksize)) {
+ DPRINTK("Audio: CopyFrom User failed \n");
+ complete(&s->wfc);
+ return -EFAULT;
+ }
+
+ buffer += chunksize;
+ count -= chunksize;
+ b->offset += chunksize;
+
+ if (b->offset < s->fragsize) {
+ complete(&s->wfc);
+ break;
+ }
+
+ /* Update pointers and send current fragment to DMA */
+ b->offset = 0;
+ if (++s->usr_head >= s->nbfrags)
+ s->usr_head = 0;
+ /* Add the num of frags pending */
+ s->pending_frags++;
+ s->active = 1;
+
+ audio_process_dma(s);
+ }
+
+ if ((buffer - buffer0))
+ ret = buffer - buffer0;
+
+ DPRINTK("audio_write: return=%d\n", ret);
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * audio_read(): Exposed as read() function
+ *
+ ******************************************************************************/
+static int
+audio_read(struct file *file, char *buffer, size_t count, loff_t * ppos)
+{
+ char *buffer0 = buffer;
+ audio_state_t *state = file->private_data;
+ audio_stream_t *s = state->input_stream;
+ int chunksize, ret = 0;
+ unsigned long flags;
+
+ DPRINTK("audio_read: count=%d\n", count);
+
+ if (*ppos != file->f_pos) {
+ DPRINTK("AudioRead - FPOS not ppos ppos=0x%x fpos =0x%x\n",
+ (u32) * ppos, (u32) file->f_pos);
+ return -ESPIPE;
+ }
+ if (s->mapped) {
+ DPRINTK("AudioRead - s already mapped\n");
+ return -ENXIO;
+ }
+
+ if (!s->active) {
+ if (!s->buffers && audio_setup_buf(s)) {
+ DPRINTK("AudioRead - No Memory\n");
+ return -ENOMEM;
+ }
+ audio_prime_rx(state);
+ }
+
+ while (count > 0) {
+ audio_buf_t *b = &s->buffers[s->usr_head];
+
+ /* Wait for a buffer to become full */
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ if (!s->wfc.done)
+ break;
+ } else {
+ ret = -ERESTARTSYS;
+ if (wait_for_completion_interruptible(&s->wfc))
+ break;
+ }
+
+ /* Grab data from the current buffer */
+ chunksize = s->fragsize - b->offset;
+ if (chunksize > count)
+ chunksize = count;
+
+ DPRINTK("read %d from %d\n", chunksize, s->usr_head);
+ if (copy_to_user(buffer, b->data + b->offset, chunksize)) {
+ complete(&s->wfc);
+ return -EFAULT;
+ }
+ buffer += chunksize;
+ count -= chunksize;
+ b->offset += chunksize;
+ if (b->offset < s->fragsize) {
+ complete(&s->wfc);
+ break;
+ }
+
+ /* Update pointers and return current fragment to DMA */
+ local_irq_save(flags);
+ b->offset = 0;
+ if (++s->usr_head >= s->nbfrags)
+ s->usr_head = 0;
+
+ s->pending_frags++;
+ local_irq_restore(flags);
+ DPRINTK(KERN_INFO
+ "calling audio_process_dma from audio_read\n");
+ audio_process_dma(s);
+ }
+
+ if ((buffer - buffer0))
+ ret = buffer - buffer0;
+ DPRINTK("audio_read: return=%d\n", ret);
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * audio_mmap(): Exposed as mmap Function
+ * !!WARNING: Still under development
+ *
+ ******************************************************************************/
+static int audio_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ audio_state_t *state = file->private_data;
+ audio_stream_t *s;
+ unsigned long size, vma_addr;
+ int i, ret = 0;
+
+ FN_IN;
+ if (vma->vm_pgoff != 0)
+ return -EINVAL;
+
+ if (vma->vm_flags & VM_WRITE) {
+ if (!state->wr_ref)
+ return -EINVAL;;
+ s = state->output_stream;
+ } else if (vma->vm_flags & VM_READ) {
+ if (!state->rd_ref)
+ return -EINVAL;
+ s = state->input_stream;
+ } else
+ return -EINVAL;
+
+ if (s->mapped)
+ return -EINVAL;
+ size = vma->vm_end - vma->vm_start;
+ if (size != s->fragsize * s->nbfrags)
+ return -EINVAL;
+ if (!s->buffers && audio_setup_buf(s))
+ return -ENOMEM;
+ vma_addr = vma->vm_start;
+ for (i = 0; i < s->nbfrags; i++) {
+ audio_buf_t *buf = &s->buffers[i];
+ if (!buf->master)
+ continue;
+#if 0
+ ret =
+ remap_pfn_range(vma, vma_addr, buf->dma_addr >> PAGE_SHIFT,
+ buf->master, vma->vm_page_prot);
+#endif
+ if (ret)
+ return ret;
+ vma_addr += buf->master;
+ }
+ s->mapped = 1;
+
+ FN_OUT(0);
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * audio_poll(): Exposed as poll function
+ *
+ ******************************************************************************/
+static unsigned int
+audio_poll(struct file *file, struct poll_table_struct *wait)
+{
+ audio_state_t *state = file->private_data;
+ audio_stream_t *is = state->input_stream;
+ audio_stream_t *os = state->output_stream;
+ unsigned int mask = 0;
+
+ DPRINTK("audio_poll(): mode=%s%s\n",
+ (file->f_mode & FMODE_READ) ? "r" : "",
+ (file->f_mode & FMODE_WRITE) ? "w" : "");
+
+ if (file->f_mode & FMODE_READ) {
+ /* Start audio input if not already active */
+ if (!is->active) {
+ if (!is->buffers && audio_setup_buf(is))
+ return -ENOMEM;
+ audio_prime_rx(state);
+ }
+ poll_wait(file, &is->wq, wait);
+ }
+
+ if (file->f_mode & FMODE_WRITE) {
+ if (!os->buffers && audio_setup_buf(os))
+ return -ENOMEM;
+ poll_wait(file, &os->wq, wait);
+ }
+
+ if (file->f_mode & FMODE_READ)
+ if ((is->mapped && is->bytecount > 0) ||
+ (!is->mapped && is->wfc.done > 0))
+ mask |= POLLIN | POLLRDNORM;
+
+ if (file->f_mode & FMODE_WRITE)
+ if ((os->mapped && os->bytecount > 0) ||
+ (!os->mapped && os->wfc.done > 0))
+ mask |= POLLOUT | POLLWRNORM;
+
+ DPRINTK("audio_poll() returned mask of %s%s\n",
+ (mask & POLLIN) ? "r" : "", (mask & POLLOUT) ? "w" : "");
+
+ FN_OUT(mask);
+ return mask;
+}
+
+/*******************************************************************************
+ *
+ * audio_llseek(): Exposed as lseek() function.
+ *
+ ******************************************************************************/
+static loff_t audio_llseek(struct file *file, loff_t offset, int origin)
+{
+ FN_IN;
+ FN_OUT(0);
+ return -ESPIPE;
+}
+
+/*******************************************************************************
+ *
+ * audio_ioctl(): Handles generic ioctls. If there is a request for something this
+ * fn cannot handle, its then given to client specific ioctl routine, that will take
+ * up platform specific requests
+ *
+ ******************************************************************************/
+static int
+audio_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+ audio_state_t *state = file->private_data;
+ audio_stream_t *os = state->output_stream;
+ audio_stream_t *is = state->input_stream;
+ long val;
+
+ DPRINTK(__FILE__ " audio_ioctl 0x%08x\n", cmd);
+
+ /* dispatch based on command */
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, (int *)arg);
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ if (file->f_mode & FMODE_WRITE)
+ return put_user(os->fragsize, (int *)arg);
+ else
+ return put_user(is->fragsize, (int *)arg);
+
+ case SNDCTL_DSP_GETCAPS:
+ val = DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP;
+ if (is && os)
+ val |= DSP_CAP_DUPLEX;
+ FN_OUT(1);
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ if (get_user(val, (long *)arg)) {
+ FN_OUT(2);
+ return -EFAULT;
+ }
+ if (file->f_mode & FMODE_READ) {
+ int ret = audio_set_fragments(is, val);
+ if (ret < 0) {
+ FN_OUT(3);
+ return ret;
+ }
+ ret = put_user(ret, (int *)arg);
+ if (ret) {
+ FN_OUT(4);
+ return ret;
+ }
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ int ret = audio_set_fragments(os, val);
+ if (ret < 0) {
+ FN_OUT(5);
+ return ret;
+ }
+ ret = put_user(ret, (int *)arg);
+ if (ret) {
+ FN_OUT(6);
+ return ret;
+ }
+ }
+ FN_OUT(7);
+ return 0;
+
+ case SNDCTL_DSP_SYNC:
+ FN_OUT(8);
+ return audio_sync(file);
+
+ case SNDCTL_DSP_SETDUPLEX:
+ FN_OUT(9);
+ return 0;
+
+ case SNDCTL_DSP_POST:
+ FN_OUT(10);
+ return 0;
+
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & FMODE_READ && is->active && !is->stopped)
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & FMODE_WRITE && os->active && !os->stopped)
+ val |= PCM_ENABLE_OUTPUT;
+ FN_OUT(11);
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_SETTRIGGER:
+ if (get_user(val, (int *)arg)) {
+ FN_OUT(12);
+ return -EFAULT;
+ }
+ if (file->f_mode & FMODE_READ) {
+ if (val & PCM_ENABLE_INPUT) {
+ unsigned long flags;
+ if (!is->active) {
+ if (!is->buffers && audio_setup_buf(is)) {
+ FN_OUT(13);
+ return -ENOMEM;
+ }
+ audio_prime_rx(state);
+ }
+ local_irq_save(flags);
+ is->stopped = 0;
+ local_irq_restore(flags);
+ audio_process_dma(is);
+
+ } else {
+ is->stopped = 1;
+ audio_stop_dma(is);
+ }
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if (val & PCM_ENABLE_OUTPUT) {
+ unsigned long flags;
+ if (!os->buffers && audio_setup_buf(os)) {
+ FN_OUT(14);
+ return -ENOMEM;
+ }
+ local_irq_save(flags);
+ if (os->mapped && !os->pending_frags) {
+ os->pending_frags = os->nbfrags;
+ init_completion(&os->wfc);
+ os->wfc.done = 0;
+ os->active = 1;
+ }
+ os->stopped = 0;
+ local_irq_restore(flags);
+ audio_process_dma(os);
+ } else {
+ os->stopped = 1;
+ audio_stop_dma(os);
+ }
+ }
+ FN_OUT(15);
+ return 0;
+
+ case SNDCTL_DSP_GETOPTR:
+ case SNDCTL_DSP_GETIPTR:
+ {
+ count_info inf = { 0, };
+ audio_stream_t *s =
+ (cmd == SNDCTL_DSP_GETOPTR) ? os : is;
+ int bytecount, offset;
+ unsigned long flags;
+
+ if ((s == is && !(file->f_mode & FMODE_READ)) ||
+ (s == os && !(file->f_mode & FMODE_WRITE))) {
+ FN_OUT(16);
+ return -EINVAL;
+ }
+ if (s->active) {
+ local_irq_save(flags);
+ offset = audio_get_dma_pos(s);
+ inf.ptr = s->dma_tail * s->fragsize + offset;
+ bytecount = s->bytecount + offset;
+ s->bytecount = -offset;
+ inf.blocks = s->fragcount;
+ s->fragcount = 0;
+ local_irq_restore(flags);
+ if (bytecount < 0)
+ bytecount = 0;
+ inf.bytes = bytecount;
+ }
+ FN_OUT(17);
+ return copy_to_user((void *)arg, &inf, sizeof(inf));
+ }
+
+ case SNDCTL_DSP_GETOSPACE:
+ case SNDCTL_DSP_GETISPACE:
+ {
+ audio_buf_info inf = { 0, };
+ audio_stream_t *s =
+ (cmd == SNDCTL_DSP_GETOSPACE) ? os : is;
+ audio_buf_t *b = NULL;
+
+ if ((s == is && !(file->f_mode & FMODE_READ)) ||
+ (s == os && !(file->f_mode & FMODE_WRITE))) {
+ FN_OUT(18);
+ return -EINVAL;
+ }
+ if (!s->buffers && audio_setup_buf(s)) {
+ FN_OUT(19);
+ return -ENOMEM;
+ }
+ b = &s->buffers[s->usr_head];
+ inf.bytes = s->wfc.done * s->fragsize;
+ inf.bytes -= b->offset;
+ if(inf.bytes < 0)
+ inf.bytes = 0;
+
+ inf.fragments = inf.bytes / s->fragsize;
+ inf.fragsize = s->fragsize;
+ inf.fragstotal = s->nbfrags;
+ FN_OUT(20);
+ return copy_to_user((void *)arg, &inf, sizeof(inf));
+ }
+
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ FN_OUT(21);
+ return 0;
+
+ case SNDCTL_DSP_RESET:
+ if (file->f_mode & FMODE_READ) {
+ audio_reset(is);
+ if (state->need_tx_for_rx) {
+ unsigned long flags;
+ local_irq_save(flags);
+ os->spin_idle = 0;
+ local_irq_restore(flags);
+ }
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ audio_reset(os);
+ }
+ FN_OUT(22);
+ return 0;
+
+ default:
+ /*
+ * Let the client of this module handle the
+ * non generic ioctls
+ */
+ FN_OUT(23);
+ return state->client_ioctl(inode, file, cmd, arg);
+ }
+
+ FN_OUT(0);
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * audio_open(): Exposed as open() function
+ *
+ ******************************************************************************/
+static int audio_open(struct inode *inode, struct file *file)
+{
+ audio_state_t *state = (&audio_state);
+ audio_stream_t *os = state->output_stream;
+ audio_stream_t *is = state->input_stream;
+ int err, need_tx_dma;
+ static unsigned char aic33_init_flag = 0;
+
+ FN_IN;
+
+ /* Lock the module */
+ if (!try_module_get(THIS_MODULE)) {
+ DPRINTK("Failed to get module\n");
+ return -ESTALE;
+ }
+ /* Lock the codec module */
+ if (!try_module_get(state->owner)) {
+ DPRINTK("Failed to get codec module\n");
+ module_put(THIS_MODULE);
+ return -ESTALE;
+ }
+
+ down(&state->sem);
+
+ /* access control */
+ err = -ENODEV;
+ if ((file->f_mode & FMODE_WRITE) && !os)
+ goto out;
+ if ((file->f_mode & FMODE_READ) && !is)
+ goto out;
+ err = -EBUSY;
+ if ((file->f_mode & FMODE_WRITE) && state->wr_ref)
+ goto out;
+ if ((file->f_mode & FMODE_READ) && state->rd_ref)
+ goto out;
+ err = -EINVAL;
+ if ((file->f_mode & FMODE_READ) && state->need_tx_for_rx && !os)
+ goto out;
+
+ /* request DMA channels */
+ need_tx_dma = ((file->f_mode & FMODE_WRITE) ||
+ ((file->f_mode & FMODE_READ) && state->need_tx_for_rx));
+ if (state->wr_ref || (state->rd_ref && state->need_tx_for_rx))
+ need_tx_dma = 0;
+ if (need_tx_dma) {
+ DPRINTK("DMA REQUEST FOR playback\n");
+ DMA_REQUEST(err, os, audio_dma_callback);
+ if (err < 0)
+ goto out;
+ }
+ if (file->f_mode & FMODE_READ) {
+ DPRINTK("DMA REQUEST FOR record\n");
+ DMA_REQUEST(err, is, audio_dma_callback);
+ if (err < 0) {
+ if (need_tx_dma)
+ DMA_FREE(os);
+ goto out;
+ }
+ }
+
+ /* now complete initialisation */
+ if (!AUDIO_ACTIVE(state)) {
+ if (state->hw_init && !aic33_init_flag) {
+ state->hw_init(state->data);
+ aic33_init_flag = 0;
+ }
+ }
+
+ if ((file->f_mode & FMODE_WRITE)) {
+ DPRINTK("SETUP FOR PLAYBACK\n");
+ state->wr_ref = 1;
+ audio_reset(os);
+ os->fragsize = AUDIO_FRAGSIZE_DEFAULT;
+ os->nbfrags = AUDIO_NBFRAGS_DEFAULT;
+ os->mapped = 0;
+ init_waitqueue_head(&os->wq);
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ DPRINTK("SETUP FOR RECORD\n");
+ state->rd_ref = 1;
+ audio_reset(is);
+ is->fragsize = AUDIO_FRAGSIZE_DEFAULT;
+ is->nbfrags = AUDIO_NBFRAGS_DEFAULT;
+ is->mapped = 0;
+ init_waitqueue_head(&is->wq);
+ }
+
+ file->private_data = state;
+ err = 0;
+
+ out:
+ up(&state->sem);
+ if (err) {
+ module_put(state->owner);
+ module_put(THIS_MODULE);
+ }
+ FN_OUT(err);
+ return err;
+}
+
+/*******************************************************************************
+ *
+ * audio_release(): Exposed as release function()
+ *
+ ******************************************************************************/
+static int audio_release(struct inode *inode, struct file *file)
+{
+ audio_state_t *state = file->private_data;
+ audio_stream_t *os = state->output_stream;
+ audio_stream_t *is = state->input_stream;
+
+ FN_IN;
+
+ down(&state->sem);
+
+ if (file->f_mode & FMODE_READ) {
+ audio_discard_buf(is);
+ DMA_FREE(is);
+ is->dma_spinref = 0;
+ if (state->need_tx_for_rx) {
+ os->spin_idle = 0;
+ if (!state->wr_ref) {
+ DMA_FREE(os);
+ os->dma_spinref = 0;
+ }
+ }
+ state->rd_ref = 0;
+ }
+
+ if (file->f_mode & FMODE_WRITE) {
+ audio_sync(file);
+ audio_discard_buf(os);
+ if (!state->need_tx_for_rx || !state->rd_ref) {
+ DMA_FREE(os);
+ os->dma_spinref = 0;
+ }
+ state->wr_ref = 0;
+ }
+
+ up(&state->sem);
+
+ module_put(state->owner);
+ module_put(THIS_MODULE);
+
+ FN_OUT(0);
+ return 0;
+}
+
+EXPORT_SYMBOL(audio_register_codec);
+EXPORT_SYMBOL(audio_unregister_codec);
+EXPORT_SYMBOL(audio_get_fops);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("Common audio handling for DAVINCI processors");
+MODULE_LICENSE("GPL");
diff --git a/sound/oss/davinci-audio.h b/sound/oss/davinci-audio.h
new file mode 100644
index 0000000..a37f635
--- /dev/null
+++ b/sound/oss/davinci-audio.h
@@ -0,0 +1,115 @@
+/*
+ * linux/sound/oss/davinci-audio.h
+ *
+ * Common audio handling for the Davinci processors
+ *
+ * Copyright (C) 2006 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * 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:
+ *
+ * 2005-10-01 Rishi Bhattacharya - Adapted to TI Davinci Family of processors
+ */
+
+#ifndef __DAVINCI_AUDIO_H
+#define __DAVINCI_AUDIO_H
+
+/* Requires dma.h */
+#include <asm/arch/dma.h>
+
+/*
+ * Buffer Management
+ */
+typedef struct {
+ int offset; /* current offset */
+ char *data; /* points to actual buffer */
+ dma_addr_t dma_addr; /* physical buffer address */
+ int dma_ref; /* DMA refcount */
+ int master; /* owner for buffer allocation, contain size when true */
+} audio_buf_t;
+
+/*
+ * Structure describing the data stream related information
+ */
+typedef struct {
+ char *id; /* identification string */
+ audio_buf_t *buffers; /* pointer to audio buffer structures */
+ u_int usr_head; /* user fragment index */
+ u_int dma_head; /* DMA fragment index to go */
+ u_int dma_tail; /* DMA fragment index to complete */
+ u_int fragsize; /* fragment i.e. buffer size */
+ u_int nbfrags; /* nbr of fragments i.e. buffers */
+ u_int pending_frags; /* Fragments sent to DMA */
+ int dma_dev; /* device identifier for DMA */
+ u_int prevbuf; /* Prev pending frag size sent to DMA */
+ char started; /* to store if the chain was started or not */
+ int dma_q_head; /* DMA Channel Q Head */
+ int dma_q_tail; /* DMA Channel Q Tail */
+ char dma_q_count; /* DMA Channel Q Count */
+ char in_use; /* Is this is use? */
+ int master_ch;
+ int *lch; /* Chain of channels this stream is linked to */
+ int input_or_output; /* Direction of this data stream */
+ int bytecount; /* nbr of processed bytes */
+ int fragcount; /* nbr of fragment transitions */
+ struct completion wfc; /* wait for "nbfrags" fragment completion */
+ wait_queue_head_t wq; /* for poll */
+ int dma_spinref; /* DMA is spinning */
+ int mapped:1; /* mmap()'ed buffers */
+ int active:1; /* actually in progress */
+ int stopped:1; /* might be active but stopped */
+ int spin_idle:1; /* have DMA spin on zeros when idle */
+ int dma_started; /* to store if DMA was started or not */
+} audio_stream_t;
+
+/*
+ * State structure for one instance
+ */
+typedef struct {
+ struct module *owner; /* Codec module ID */
+ audio_stream_t *output_stream;
+ audio_stream_t *input_stream;
+ int rd_ref:1; /* open reference for recording */
+ int wr_ref:1; /* open reference for playback */
+ int need_tx_for_rx:1; /* if data must be sent while receiving */
+ void *data;
+ void (*hw_init) (void *);
+ void (*hw_shutdown) (void *);
+ int (*client_ioctl) (struct inode *, struct file *, uint, ulong);
+ int (*hw_probe) (void);
+ void (*hw_remove) (void);
+ void (*hw_cleanup) (void);
+ int (*hw_suspend) (void);
+ int (*hw_resume) (void);
+ struct pm_dev *pm_dev;
+ struct semaphore sem; /* to protect against races in attach() */
+} audio_state_t;
+
+#ifdef AUDIO_PM
+void audio_ldm_suspend(void *data);
+
+void audio_ldm_resume(void *data);
+
+#endif
+
+/* Register a Codec using this function */
+extern int audio_register_codec(audio_state_t * codec_state);
+/* Un-Register a Codec using this function */
+extern int audio_unregister_codec(audio_state_t * codec_state);
+/* Function to provide fops of davinci audio driver */
+extern struct file_operations *audio_get_fops(void);
+/* Function to initialize the device info for audio driver */
+extern int audio_dev_init(void);
+/* Function to un-initialize the device info for audio driver */
+void audio_dev_uninit(void);
+
+#endif /* End of #ifndef __DAVINCI_AUDIO_H */