diff -purN linux-2.6.30-rc4-git/arch/arm/configs/karo_tx25_defconfig linux-2.6.30-rc4-karo3/arch/arm/configs/karo_tx25_defconfig --- linux-2.6.30-rc4-git/arch/arm/configs/karo_tx25_defconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/configs/karo_tx25_defconfig 2009-07-14 13:49:57.000000000 +0200 @@ -0,0 +1,1442 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.30-rc4 +# Tue Jul 14 13:40:27 2009 +# +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_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_MTD_XIP=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +CONFIG_CLASSIC_RCU=y +# CONFIG_TREE_RCU is not set +# CONFIG_PREEMPT_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_PREEMPT_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=17 +# CONFIG_GROUP_SCHED is not set +# CONFIG_CGROUPS is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_RELAY is not set +# CONFIG_NAMESPACES is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +# CONFIG_ELF_CORE is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +# CONFIG_AIO is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_CLK=y +# CONFIG_SLOW_WORK is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +CONFIG_LBD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" +CONFIG_FREEZER=y + +# +# System Type +# +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_MV78XX0 is not set +CONFIG_ARCH_MXC=y +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_W90X900 is not set + +# +# Freescale MXC Implementations +# +# CONFIG_ARCH_MX1 is not set +CONFIG_ARCH_MX2=y +# CONFIG_ARCH_MX3 is not set +# CONFIG_MACH_MX21 is not set +# CONFIG_MACH_MX27 is not set +CONFIG_MACH_MX25=y + +# +# MX2 platforms: +# +CONFIG_MACH_TX25=y +# CONFIG_KARO_DEBUG is not set +CONFIG_MACH_STK5_BASEBOARD=y +# CONFIG_MXC_IRQ_PRIOR is not set +# CONFIG_MXC_PWM is not set +CONFIG_ARCH_MXC_IOMUX_V3=y + +# +# 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 +CONFIG_COMMON_CLKDEV=y + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PREEMPT=y +CONFIG_HZ=100 +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_FLATMEM_HAS_HOLES=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_HIGHMEM is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +CONFIG_UNEVICTABLE_LRU=y +CONFIG_HAVE_MLOCK=y +CONFIG_HAVE_MLOCKED_PAGE_BIT=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CMDLINE="init=/linuxrc root=1f01 rootfstype=jffs2 ro console=ttymxc0,115200 panic=1" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set + +# +# CPU Power Management +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_PM=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_VERBOSE is not set +CONFIG_CAN_PM_TRACE=y +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_APM_EMULATION=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES 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=y +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_TESTS=m +CONFIG_MTD_REDBOOT_PARTS=y +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-5 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +CONFIG_MTD_REDBOOT_PARTS_READONLY=y +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_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=y +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_GPIO 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_ALAUDA is not set +CONFIG_MTD_NAND_MXC=y +CONFIG_MTD_NAND_MXC_FLASH_BBT=y +CONFIG_ARCH_MXC_HAS_NFC_V1=y +CONFIG_ARCH_MXC_HAS_NFC_V1_1=y +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR 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=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_93CX6 is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=m +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +CONFIG_COMPAT_NET_DEV_OPS=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +CONFIG_SMSC_PHY=y +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_AX88796 is not set +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set +# CONFIG_ETHOC is not set +# CONFIG_SMC911X is not set +# CONFIG_SMSC911X is not set +# CONFIG_DNET is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_B44 is not set +CONFIG_FEC=y +# CONFIG_FEC2 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +CONFIG_NETCONSOLE=y +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_TRAP is not set +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=m +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_EVBUG=m +# CONFIG_INPUT_APMPOWER is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +CONFIG_KEYBOARD_GPIO=m +CONFIG_INPUT_MOUSE=y +# CONFIG_MOUSE_PS2 is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +CONFIG_TOUCHSCREEN_MXC_TSADCC=m +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_USB_EGALAX=y +# CONFIG_TOUCHSCREEN_USB_PANJIT is not set +# CONFIG_TOUCHSCREEN_USB_3M is not set +# CONFIG_TOUCHSCREEN_USB_ITM is not set +# CONFIG_TOUCHSCREEN_USB_ETURBO is not set +# CONFIG_TOUCHSCREEN_USB_GUNZE is not set +# CONFIG_TOUCHSCREEN_USB_DMC_TSC10 is not set +# CONFIG_TOUCHSCREEN_USB_IRTOUCH is not set +# CONFIG_TOUCHSCREEN_USB_IDEALTEK is not set +# CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH is not set +# CONFIG_TOUCHSCREEN_USB_GOTOP is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_DEVKMEM=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_IMX=y +CONFIG_SERIAL_IMX_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=16 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set +# CONFIG_SPI is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO expanders: +# + +# +# I2C GPIO expanders: +# + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +CONFIG_FB_IMX=y +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +# 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 +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT 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=y +CONFIG_USB=m +CONFIG_USB_DEBUG=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +CONFIG_USB_DEVICE_CLASS=y +CONFIG_USB_DYNAMIC_MINORS=y +CONFIG_USB_SUSPEND=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_MON=m +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_OXU210HP_HCD is not set +CONFIG_USB_EHCI_MXC=y +CONFIG_ARCH_MXC_EHCI_USBH2=y +# CONFIG_ARCH_MXC_EHCI_USBOTG is not set +CONFIG_ARCH_MXC_HAS_USBH2=y +CONFIG_ARCH_MXC_HAS_USBOTG=y +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HWA_HCD is not set + +# +# Enable Host or Gadget support to see Inventra options +# +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=m +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +CONFIG_USB_STORAGE_SDDR09=m +CONFIG_USB_STORAGE_SDDR55=m +CONFIG_USB_STORAGE_JUMPSHOT=m +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_EZUSB is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +CONFIG_USB_SERIAL_BELKIN=m +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_VST is not set +# CONFIG_USB_GADGET is not set + +# +# OTG and related infrastructure +# +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_GPIO_PLATFORM=y + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_TIMER is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_REGULATOR is not set +# CONFIG_UIO is not set +# CONFIG_STAGING is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=m +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4_FS is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=m +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_FILE_LOCKING=y +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +CONFIG_DNOTIFY=y +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_RW=y + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_FS_XATTR is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_CRAMFS=y +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +CONFIG_NLS_CODEPAGE_850=y +# 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=m +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +# 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=y +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=1 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +CONFIG_DEBUG_SLAB=y +CONFIG_DEBUG_SLAB_LEAK=y +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_LOCK_ALLOC=y +# CONFIG_PROVE_LOCKING is not set +CONFIG_LOCKDEP=y +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_LOCKDEP is not set +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +# CONFIG_PAGE_POISONING is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_TRACING_SUPPORT=y + +# +# Tracers +# +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_EVENT_TRACER is not set +# CONFIG_BOOT_TRACER is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_KMEMTRACE is not set +# CONFIG_WORKQUEUE_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARM_UNWIND=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_T10DIF 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_DECOMPRESS_GZIP=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/Kconfig linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/Kconfig --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/Kconfig 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/Kconfig 2009-07-01 11:09:09.000000000 +0200 @@ -6,14 +6,32 @@ choice config MACH_MX21 bool "i.MX21 support" + select ARCH_MXC_IOMUX_V2 + select ARCH_MXC_HAS_NFC_V1 help This enables support for Freescale's MX2 based i.MX21 processor. config MACH_MX27 bool "i.MX27 support" + select ARCH_MXC_IOMUX_V2 + select ARCH_MXC_HAS_NFC_V1 + select USB_ARCH_HAS_EHCI + select ARCH_MXC_HAS_USBH2 + select ARCH_MXC_HAS_USBOTG help This enables support for Freescale's MX2 based i.MX27 processor. +config MACH_MX25 + bool "i.MX25 support" + select ARCH_MXC_IOMUX_V3 + select ARCH_MXC_HAS_NFC_V1_1 + select USB_ARCH_HAS_EHCI + select ARCH_MXC_HAS_USBH2 + select ARCH_MXC_HAS_USBOTG + select PHYLIB if FEC + help + This enables support for Freescale's MX2 based i.MX25 processor. + endchoice comment "MX2 platforms:" @@ -39,6 +57,26 @@ config MACH_PCM038 Include support for phyCORE-i.MX27 (aka pcm038) platform. This includes specific configurations for the module and its peripherals. +config MACH_TX25 + bool "Support Ka-Ro electronics TX25 module" + depends on MACH_MX25 + help + Include support for Ka-Ro TX25 processor module + +config KARO_DEBUG + bool "Enable Ka-Ro specific debug messages" + depends on MACH_TX25 || MACH_TX27 + help + Compile the architecture specific files with -DDEBUG to enable + additional debug messages + +config MACH_STK5_BASEBOARD + bool "Ka-Ro Starterkit-5 (STK5) development board" + depends on MACH_TX27 || MACH_TX25 + help + This adds board specific devices that can be found on Ka-Ro's + STK5 evaluation board. + choice prompt "Baseboard" depends on MACH_PCM038 @@ -60,3 +98,4 @@ config MACH_MX27_3DS Include support for MX27PDK platform. This includes specific configurations for the board and its peripherals. endif + diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/Makefile linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/Makefile --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/Makefile 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/Makefile 2009-06-02 17:59:14.000000000 +0200 @@ -2,17 +2,31 @@ # Makefile for the linux kernel. # +ifeq ($(CONFIG_KARO_DEBUG),y) + EXTRA_CFLAGS += -DDEBUG +endif + # Object file lists. -obj-y := generic.o devices.o serial.o +obj-y := generic.o serial.o +obj-$(CONFIG_MACH_MX25) += devices_mx25.o +ifeq ($(CONFIG_MACH_MX25),) +obj-y += devices.o +endif + +obj-$(CONFIG_MACH_MX21) += clock_imx21.o -obj-$(CONFIG_MACH_MX21) += clock_imx21.o +obj-$(CONFIG_MACH_MX25) += clock_imx25.o +obj-$(CONFIG_MACH_MX25) += cpu_imx25.o -obj-$(CONFIG_MACH_MX27) += cpu_imx27.o -obj-$(CONFIG_MACH_MX27) += clock_imx27.o +obj-$(CONFIG_MACH_MX27) += cpu_imx27.o +obj-$(CONFIG_MACH_MX27) += clock_imx27.o -obj-$(CONFIG_MACH_MX21ADS) += mx21ads.o -obj-$(CONFIG_MACH_MX27ADS) += mx27ads.o -obj-$(CONFIG_MACH_PCM038) += pcm038.o -obj-$(CONFIG_MACH_PCM970_BASEBOARD) += pcm970-baseboard.o -obj-$(CONFIG_MACH_MX27_3DS) += mx27pdk.o +obj-$(CONFIG_MACH_MX21ADS) += mx21ads.o +obj-$(CONFIG_MACH_MX27ADS) += mx27ads.o +obj-$(CONFIG_MACH_PCM038) += pcm038.o +obj-$(CONFIG_MACH_PCM970_BASEBOARD) += pcm970-baseboard.o +obj-$(CONFIG_MACH_MX27_3DS) += mx27pdk.o +obj-$(CONFIG_MACH_TX27) += karo-tx27.o tx27_gpio.o +obj-$(CONFIG_MACH_TX25) += karo-tx25.o +obj-$(CONFIG_MACH_STK5_BASEBOARD) += stk5-baseboard.o diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/Makefile.boot linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/Makefile.boot --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/Makefile.boot 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/Makefile.boot 2009-06-02 17:59:15.000000000 +0200 @@ -5,3 +5,7 @@ initrd_phys-$(CONFIG_MACH_MX21) := 0xC08 zreladdr-$(CONFIG_MACH_MX27) := 0xA0008000 params_phys-$(CONFIG_MACH_MX27) := 0xA0000100 initrd_phys-$(CONFIG_MACH_MX27) := 0xA0800000 + +zreladdr-$(CONFIG_MACH_MX25) := 0x80008000 +params_phys-$(CONFIG_MACH_MX25) := 0x80000100 +initrd_phys-$(CONFIG_MACH_MX25) := 0x80800000 diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/clock_imx21.c linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/clock_imx21.c --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/clock_imx21.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/clock_imx21.c 2009-06-02 17:59:15.000000000 +0200 @@ -890,7 +890,7 @@ static struct clk clko_clk = { .con_id = n, \ .clk = &c, \ }, -static struct clk_lookup lookups[] __initdata = { +static struct clk_lookup lookups[] = { /* It's unlikely that any driver wants one of them directly: _REGISTER_CLOCK(NULL, "ckih", ckih_clk) _REGISTER_CLOCK(NULL, "ckil", ckil_clk) diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/clock_imx25.c linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/clock_imx25.c --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/clock_imx25.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/clock_imx25.c 2009-07-06 14:10:59.000000000 +0200 @@ -0,0 +1,1861 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* based on mach-mx27/clock.c */ + +#include +#include +#include +//#include + +#include +//#include + +#include +#include +#include + +/* Register offsets */ +#define MXC_CCM_MPCTL (IO_ADDRESS(CCM_BASE_ADDR) + 0x00) +#define MXC_CCM_UPCTL (IO_ADDRESS(CCM_BASE_ADDR) + 0x04) +#define MXC_CCM_CCTL (IO_ADDRESS(CCM_BASE_ADDR) + 0x08) +#define MXC_CCM_CGCR0 (IO_ADDRESS(CCM_BASE_ADDR) + 0x0C) +#define MXC_CCM_CGCR1 (IO_ADDRESS(CCM_BASE_ADDR) + 0x10) +#define MXC_CCM_CGCR2 (IO_ADDRESS(CCM_BASE_ADDR) + 0x14) +#define MXC_CCM_PCDR0 (IO_ADDRESS(CCM_BASE_ADDR) + 0x18) +#define MXC_CCM_PCDR1 (IO_ADDRESS(CCM_BASE_ADDR) + 0x1C) +#define MXC_CCM_PCDR2 (IO_ADDRESS(CCM_BASE_ADDR) + 0x20) +#define MXC_CCM_PCDR3 (IO_ADDRESS(CCM_BASE_ADDR) + 0x24) +#define MXC_CCM_RCSR (IO_ADDRESS(CCM_BASE_ADDR) + 0x28) +#define MXC_CCM_CRDR (IO_ADDRESS(CCM_BASE_ADDR) + 0x2C) +#define MXC_CCM_DCVR0 (IO_ADDRESS(CCM_BASE_ADDR) + 0x30) +#define MXC_CCM_DCVR1 (IO_ADDRESS(CCM_BASE_ADDR) + 0x34) +#define MXC_CCM_DCVR2 (IO_ADDRESS(CCM_BASE_ADDR) + 0x38) +#define MXC_CCM_DCVR3 (IO_ADDRESS(CCM_BASE_ADDR) + 0x3C) +#define MXC_CCM_LTR0 (IO_ADDRESS(CCM_BASE_ADDR) + 0x40) +#define MXC_CCM_LTR1 (IO_ADDRESS(CCM_BASE_ADDR) + 0x44) +#define MXC_CCM_LTR2 (IO_ADDRESS(CCM_BASE_ADDR) + 0x48) +#define MXC_CCM_LTR3 (IO_ADDRESS(CCM_BASE_ADDR) + 0x4C) +#define MXC_CCM_LTBR0 (IO_ADDRESS(CCM_BASE_ADDR) + 0x50) +#define MXC_CCM_LTBR1 (IO_ADDRESS(CCM_BASE_ADDR) + 0x54) +#define MXC_CCM_PMCR0 (IO_ADDRESS(CCM_BASE_ADDR) + 0x58) +#define MXC_CCM_PMCR1 (IO_ADDRESS(CCM_BASE_ADDR) + 0x5C) +#define MXC_CCM_PMCR2 (IO_ADDRESS(CCM_BASE_ADDR) + 0x60) +#define MXC_CCM_MCR (IO_ADDRESS(CCM_BASE_ADDR) + 0x64) + +#define MXC_CCM_MPCTL_BRMO (1 << 31) +#define MXC_CCM_MPCTL_PD_OFFSET 26 +#define MXC_CCM_MPCTL_PD_MASK (0xf << 26) +#define MXC_CCM_MPCTL_MFD_OFFSET 16 +#define MXC_CCM_MPCTL_MFD_MASK (0x3ff << 16) +#define MXC_CCM_MPCTL_MFI_OFFSET 10 +#define MXC_CCM_MPCTL_MFI_MASK (0xf << 10) +#define MXC_CCM_MPCTL_MFN_OFFSET 0 +#define MXC_CCM_MPCTL_MFN_MASK 0x3ff +#define MXC_CCM_MPCTL_LF (1 << 15) + +#define MXC_CCM_UPCTL_BRMO (1 << 31) +#define MXC_CCM_UPCTL_PD_OFFSET 26 +#define MXC_CCM_UPCTL_PD_MASK (0xf << 26) +#define MXC_CCM_UPCTL_MFD_OFFSET 16 +#define MXC_CCM_UPCTL_MFD_MASK (0x3ff << 16) +#define MXC_CCM_UPCTL_MFI_OFFSET 10 +#define MXC_CCM_UPCTL_MFI_MASK (0xf << 10) +#define MXC_CCM_UPCTL_MFN_OFFSET 0 +#define MXC_CCM_UPCTL_MFN_MASK 0x3ff +#define MXC_CCM_UPCTL_LF (1 << 15) + +#define MXC_CCM_CCTL_ARM_OFFSET 30 +#define MXC_CCM_CCTL_ARM_MASK (0x3 << 30) +#define MXC_CCM_CCTL_AHB_OFFSET 28 +#define MXC_CCM_CCTL_AHB_MASK (0x3 << 28) +#define MXC_CCM_CCTL_MPLL_RST (1 << 27) +#define MXC_CCM_CCTL_UPLL_RST (1 << 26) +#define MXC_CCM_CCTL_LP_CTL_OFFSET 24 +#define MXC_CCM_CCTL_LP_CTL_MASK (0x3 << 24) +#define MXC_CCM_CCTL_LP_MODE_RUN (0x0 << 24) +#define MXC_CCM_CCTL_LP_MODE_WAIT (0x1 << 24) +#define MXC_CCM_CCTL_LP_MODE_DOZE (0x2 << 24) +#define MXC_CCM_CCTL_LP_MODE_STOP (0x3 << 24) +#define MXC_CCM_CCTL_UPLL_DISABLE (1 << 23) +#define MXC_CCM_CCTL_MPLL_BYPASS (1 << 22) +#define MXC_CCM_CCTL_USB_DIV_OFFSET 16 +#define MXC_CCM_CCTL_USB_DIV_MASK (0x3 << 16) +#define MXC_CCM_CCTL_CG_CTRL (1 << 15) +#define MXC_CCM_CCTL_ARM_SRC (1 << 14) + +#define MXC_CCM_CGCR0_HCLK_ATA_OFFSET (16 + 0) +#define MXC_CCM_CGCR0_HCLK_BROM_OFFSET (16 + 1) +#define MXC_CCM_CGCR0_HCLK_CSI_OFFSET (16 + 2) +#define MXC_CCM_CGCR0_HCLK_EMI_OFFSET (16 + 3) +#define MXC_CCM_CGCR0_HCLK_ESAI_OFFSET (16 + 4) +#define MXC_CCM_CGCR0_HCLK_ESDHC1_OFFSET (16 + 5) +#define MXC_CCM_CGCR0_HCLK_ESDHC2_OFFSET (16 + 6) +#define MXC_CCM_CGCR0_HCLK_FEC_OFFSET (16 + 7) +#define MXC_CCM_CGCR0_HCLK_LCDC_OFFSET (16 + 8) +#define MXC_CCM_CGCR0_HCLK_RTIC_OFFSET (16 + 9) +#define MXC_CCM_CGCR0_HCLK_SDMA_OFFSET (16 + 10) +#define MXC_CCM_CGCR0_HCLK_SLCDC_OFFSET (16 + 11) +#define MXC_CCM_CGCR0_HCLK_USBOTG_OFFSET (16 + 12) + +#define MXC_CCM_CGCR0_PER_CSI_OFFSET 0 +#define MXC_CCM_CGCR0_PER_EPIT_OFFSET 1 +#define MXC_CCM_CGCR0_PER_ESAI_OFFSET 2 +#define MXC_CCM_CGCR0_PER_ESDHC1_OFFSET 3 +#define MXC_CCM_CGCR0_PER_ESDHC2_OFFSET 4 +#define MXC_CCM_CGCR0_PER_GPT_OFFSET 5 +#define MXC_CCM_CGCR0_PER_I2C_OFFSET 6 +#define MXC_CCM_CGCR0_PER_LCDC_OFFSET 7 +#define MXC_CCM_CGCR0_PER_NFC_OFFSET 8 +#define MXC_CCM_CGCR0_PER_OWIRE_OFFSET 9 +#define MXC_CCM_CGCR0_PER_PWM_OFFSET 10 +#define MXC_CCM_CGCR0_PER_SIM1_OFFSET 11 +#define MXC_CCM_CGCR0_PER_SIM2_OFFSET 12 +#define MXC_CCM_CGCR0_PER_SSI1_OFFSET 13 +#define MXC_CCM_CGCR0_PER_SSI2_OFFSET 14 +#define MXC_CCM_CGCR0_PER_UART_OFFSET 15 + +#define MXC_CCM_CGCR1_AUDMUX_OFFSET 0 +#define MXC_CCM_CGCR1_ATA_OFFSET 1 +#define MXC_CCM_CGCR1_CAN1_OFFSET 2 +#define MXC_CCM_CGCR1_CAN2_OFFSET 3 +#define MXC_CCM_CGCR1_CSI_OFFSET 4 +#define MXC_CCM_CGCR1_CSPI1_OFFSET 5 +#define MXC_CCM_CGCR1_CSPI2_OFFSET 6 +#define MXC_CCM_CGCR1_CSPI3_OFFSET 7 +#define MXC_CCM_CGCR1_DRYICE_OFFSET 8 +#define MXC_CCM_CGCR1_ECT_OFFSET 9 +#define MXC_CCM_CGCR1_EPIT1_OFFSET 10 +#define MXC_CCM_CGCR1_EPIT2_OFFSET 11 +#define MXC_CCM_CGCR1_ESAI_OFFSET 12 +#define MXC_CCM_CGCR1_ESDHC1_OFFSET 13 +#define MXC_CCM_CGCR1_ESDHC2_OFFSET 14 +#define MXC_CCM_CGCR1_FEC_OFFSET 15 +#define MXC_CCM_CGCR1_GPIO1_OFFSET 16 +#define MXC_CCM_CGCR1_GPIO2_OFFSET 17 +#define MXC_CCM_CGCR1_GPIO3_OFFSET 18 +#define MXC_CCM_CGCR1_GPT1_OFFSET 19 +#define MXC_CCM_CGCR1_GPT2_OFFSET 20 +#define MXC_CCM_CGCR1_GPT3_OFFSET 21 +#define MXC_CCM_CGCR1_GPT4_OFFSET 22 +#define MXC_CCM_CGCR1_I2C1_OFFSET 23 +#define MXC_CCM_CGCR1_I2C2_OFFSET 24 +#define MXC_CCM_CGCR1_I2C3_OFFSET 25 +#define MXC_CCM_CGCR1_IIM_OFFSET 26 +#define MXC_CCM_CGCR1_IOMUXC_OFFSET 27 +#define MXC_CCM_CGCR1_KPP_OFFSET 28 +#define MXC_CCM_CGCR1_LCDC_OFFSET 29 +#define MXC_CCM_CGCR1_OWIRE_OFFSET 30 +#define MXC_CCM_CGCR1_PWM1_OFFSET 31 + +#define MXC_CCM_CGCR2_PWM2_OFFSET (32 - 32) +#define MXC_CCM_CGCR2_PWM3_OFFSET (33 - 32) +#define MXC_CCM_CGCR2_PWM4_OFFSET (34 - 32) +#define MXC_CCM_CGCR2_RNGB_OFFSET (35 - 32) +#define MXC_CCM_CGCR2_RTIC_OFFSET (36 - 32) +#define MXC_CCM_CGCR2_SCC_OFFSET (37 - 32) +#define MXC_CCM_CGCR2_SDMA_OFFSET (38 - 32) +#define MXC_CCM_CGCR2_SIM1_OFFSET (39 - 32) +#define MXC_CCM_CGCR2_SIM2_OFFSET (40 - 32) +#define MXC_CCM_CGCR2_SLCDC_OFFSET (41 - 32) +#define MXC_CCM_CGCR2_SPBA_OFFSET (42 - 32) +#define MXC_CCM_CGCR2_SSI1_OFFSET (43 - 32) +#define MXC_CCM_CGCR2_SSI2_OFFSET (44 - 32) +#define MXC_CCM_CGCR2_TSC_OFFSET (45 - 32) +#define MXC_CCM_CGCR2_UART1_OFFSET (46 - 32) +#define MXC_CCM_CGCR2_UART2_OFFSET (47 - 32) +#define MXC_CCM_CGCR2_UART3_OFFSET (48 - 32) +#define MXC_CCM_CGCR2_UART4_OFFSET (49 - 32) +#define MXC_CCM_CGCR2_UART5_OFFSET (50 - 32) +#define MXC_CCM_CGCR2_WDOG_OFFSET (51 - 32) + +#define MXC_CCM_PCDR1_PERDIV1_MASK 0x3f + +#define MXC_CCM_MCR_USB_XTAL_MUX_OFFSET 31 +#define MXC_CCM_MCR_CLKO_EN_OFFSET 30 +#define MXC_CCM_MCR_CLKO_DIV_OFFSET 24 +#define MXC_CCM_MCR_CLKO_DIV_MASK (0x3F << 24) +#define MXC_CCM_MCR_CLKO_SEL_OFFSET 20 +#define MXC_CCM_MCR_CLKO_SEL_MASK (0xF << 20) +#define MXC_CCM_MCR_ESAI_CLK_MUX_OFFSET 19 +#define MXC_CCM_MCR_SSI2_CLK_MUX_OFFSET 18 +#define MXC_CCM_MCR_SSI1_CLK_MUX_OFFSET 17 +#define MXC_CCM_MCR_USB_CLK_MUX_OFFSET 16 + +#define MXC_CCM_MCR_PER_CLK_MUX_MASK (0xFFFF << 0) + +#define OSC24M_CLK_FREQ 24000000 /* 24MHz reference clk */ +#define OSC32K_CLK_FREQ 32768 /* 32.768kHz oscillator in */ + +static struct clk mpll_clk; +static struct clk upll_clk; +static struct clk ahb_clk; +static struct clk upll_24610k_clk; + +static int _clk_enable(struct clk *clk) +{ + unsigned long reg; + + if (!clk->enable_reg) + return 0; + + reg = __raw_readl(clk->enable_reg); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + return 0; +} + +static void _clk_disable(struct clk *clk) +{ + unsigned long reg; + + if (!clk->enable_reg) + return; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(1 << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); +} + +static int _clk_upll_enable(struct clk *clk) +{ + unsigned long reg; + + reg = __raw_readl(MXC_CCM_CCTL); + reg &= ~MXC_CCM_CCTL_UPLL_DISABLE; + __raw_writel(reg, MXC_CCM_CCTL); + + while (!(__raw_readl(MXC_CCM_UPCTL) & MXC_CCM_UPCTL_LF)) + cpu_relax(); + + return 0; +} + +static void _clk_upll_disable(struct clk *clk) +{ + unsigned long reg; + + reg = __raw_readl(MXC_CCM_CCTL); + reg |= MXC_CCM_CCTL_UPLL_DISABLE; + __raw_writel(reg, MXC_CCM_CCTL); +} + +static int _perclk_enable(struct clk *clk) +{ + unsigned long reg; + + reg = __raw_readl(MXC_CCM_CGCR0); + reg |= 1 << clk->id; + __raw_writel(reg, MXC_CCM_CGCR0); + + return 0; +} + +static void _perclk_disable(struct clk *clk) +{ + unsigned long reg; + + reg = __raw_readl(MXC_CCM_CGCR0); + reg &= ~(1 << clk->id); + __raw_writel(reg, MXC_CCM_CGCR0); +} + +static int _clk_pll_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long reg; + unsigned int pd = 1; /* Pre-divider */ + unsigned long mfi; /* Multiplication Factor (Integer part) */ + signed long mfn; /* Multiplication Factor (Integer part) */ + unsigned long mfd; /* Multiplication Factor (Denominator Part) */ + signed long tmp; + unsigned long ref_freq = clk_get_rate(clk->parent); + unsigned long err = ~0; + int best_mfn = -1; + int best_mfd = -1; + + while (((ref_freq / pd) * 10) > rate) + pd++; + + mfi = ((rate / 2) * pd) / ref_freq; + if (mfi < 5 || mfi > 15) + return -EINVAL; + + tmp = ref_freq / 10000; + for (mfd = 1; mfd <= 1024; mfd++) { + unsigned long act_freq; + + mfn = ((((((rate / 2) + (tmp - 1)) / tmp) * pd) * mfd) / 10000) - + (mfi * mfd); + + act_freq = (2 * ref_freq * mfi + (2 * ref_freq * mfn / mfd)) / pd; + act_freq -= rate; + if (abs(act_freq) < err) { + best_mfn = mfn; + best_mfd = mfd; + err = abs(act_freq); + if (err == 0) + break; + } + } + mfn = best_mfn; + mfd = best_mfd; + + mfn = (mfn + ((mfn < 0) ? 1024 : 0)) & 0x3ff; + pd--; + mfd--; + + /* Change the Pll value */ + reg = (mfi << MXC_CCM_MPCTL_MFI_OFFSET) | + (mfn << MXC_CCM_MPCTL_MFN_OFFSET) | + (mfd << MXC_CCM_MPCTL_MFD_OFFSET) | + (pd << MXC_CCM_MPCTL_PD_OFFSET); + + if (clk == &mpll_clk) { + printk(KERN_DEBUG "Changing MPCTL from %08x to %08lx\n", + __raw_readl(MXC_CCM_MPCTL), reg); + } else if (clk == &upll_clk) { + printk(KERN_DEBUG "Changing UPCTL from %08x to %08lx\n", + __raw_readl(MXC_CCM_UPCTL), reg); + } + if (clk == &mpll_clk) + __raw_writel(reg, MXC_CCM_MPCTL); + else if (clk == &upll_clk) + __raw_writel(reg, MXC_CCM_UPCTL); + return 0; +} + +static unsigned long _clk_pll_getrate(struct clk *clk) +{ + unsigned long rate; + unsigned int mfi, mfd, pdf; + int mfn; + unsigned long ref_clk; + unsigned long reg; + + ref_clk = clk_get_rate(clk->parent); + + if (clk == &mpll_clk) { + reg = __raw_readl(MXC_CCM_MPCTL); + pdf = (reg & MXC_CCM_MPCTL_PD_MASK) >> MXC_CCM_MPCTL_PD_OFFSET; + mfd = (reg & MXC_CCM_MPCTL_MFD_MASK) >> MXC_CCM_MPCTL_MFD_OFFSET; + mfi = (reg & MXC_CCM_MPCTL_MFI_MASK) >> MXC_CCM_MPCTL_MFI_OFFSET; + mfn = (reg & MXC_CCM_MPCTL_MFN_MASK) >> MXC_CCM_MPCTL_MFN_OFFSET; + } else if (clk == &upll_clk) { + reg = __raw_readl(MXC_CCM_UPCTL); + pdf = (reg & MXC_CCM_UPCTL_PD_MASK) >> MXC_CCM_UPCTL_PD_OFFSET; + mfd = (reg & MXC_CCM_UPCTL_MFD_MASK) >> MXC_CCM_UPCTL_MFD_OFFSET; + mfi = (reg & MXC_CCM_UPCTL_MFI_MASK) >> MXC_CCM_UPCTL_MFI_OFFSET; + mfn = (reg & MXC_CCM_UPCTL_MFN_MASK) >> MXC_CCM_UPCTL_MFN_OFFSET; + } else { + BUG(); /* oops */ + } + + if (mfn >= 512) + mfn = 1024 - mfn; + + mfi = (mfi < 5) ? 5 : mfi; + rate = 2LL * ref_clk * mfn; + do_div(rate, mfd + 1); + rate = 2LL * ref_clk * mfi + rate; + do_div(rate, pdf + 1); + + return rate; +} + +static unsigned long _clk_cpu_round_rate(struct clk *clk, unsigned long rate) +{ + int div = clk_get_rate(clk->parent) / rate; + + if (clk_get_rate(clk->parent) % rate) + div++; + + if (div > 4) + div = 4; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_cpu_set_rate(struct clk *clk, unsigned long rate) +{ + int div, reg; + unsigned long cctl = __raw_readl(MXC_CCM_CCTL); + + div = clk_get_rate(clk->parent) / rate; + + if (div > 4 || div < 1 || ((clk_get_rate(clk->parent) / div) != rate)) + return -EINVAL; + div--; + + reg = (cctl & ~MXC_CCM_CCTL_ARM_MASK) | + (div << MXC_CCM_CCTL_ARM_OFFSET); + __raw_writel(reg, MXC_CCM_CCTL); + + return 0; +} + +static unsigned long _clk_cpu_getrate(struct clk *clk) +{ + unsigned long div; + unsigned long cctl = __raw_readl(MXC_CCM_CCTL); + unsigned long rate; + + div = (cctl & MXC_CCM_CCTL_ARM_MASK) >> MXC_CCM_CCTL_ARM_OFFSET; + + rate = clk_get_rate(clk->parent) / (div + 1); + + if (cctl & MXC_CCM_CCTL_ARM_SRC) { + rate *= 3; + rate /= 4; + } + return rate; +} + +static unsigned long _clk_ahb_getrate(struct clk *clk) +{ + unsigned long div; + unsigned long cctl = __raw_readl(MXC_CCM_CCTL); + + div = (cctl & MXC_CCM_CCTL_AHB_MASK) >> MXC_CCM_CCTL_AHB_OFFSET; + + return clk_get_rate(clk->parent) / (div + 1); +} + +static void __iomem *pcdr_a[4] = { + MXC_CCM_PCDR0, MXC_CCM_PCDR1, MXC_CCM_PCDR2, MXC_CCM_PCDR3 +}; + +static unsigned long _clk_perclkx_getrate(struct clk *clk) +{ + unsigned long perclk_pdf; + unsigned long pcdr; + + if (clk->id < 0 || clk->id > 15) + return 0; + + pcdr = __raw_readl(pcdr_a[clk->id >> 2]); + + perclk_pdf = (pcdr >> ((clk->id & 3) << 3)) & + MXC_CCM_PCDR1_PERDIV1_MASK; + + return clk_get_rate(clk->parent) / (perclk_pdf + 1); +} + +static unsigned long _clk_perclkx_round_rate(struct clk *clk, + unsigned long rate) +{ + unsigned long div; + + div = clk_get_rate(clk->parent) / rate; + if (clk_get_rate(clk->parent) % rate) + div++; + + if (div > 64) + div = 64; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_perclkx_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long reg; + unsigned long div; + + if (clk->id < 0 || clk->id > 15) + return -EINVAL; + + div = clk_get_rate(clk->parent) / rate; + if (div > 64 || div < 1 || ((clk_get_rate(clk->parent) / div) != rate)) + return -EINVAL; + div--; + + reg = + __raw_readl(pcdr_a[clk->id >> 2]) & ~(MXC_CCM_PCDR1_PERDIV1_MASK << + ((clk->id & 3) << 3)); + reg |= div << ((clk->id & 3) << 3); + __raw_writel(reg, pcdr_a[clk->id >> 2]); + + return 0; +} + +static int _clk_perclkx_set_parent(struct clk *clk, struct clk *parent) +{ + unsigned long mcr; + + if (clk->parent == parent) + return 0; + if (parent != &upll_clk && parent != &ahb_clk) + return -EINVAL; + + clk->parent = parent; + mcr = __raw_readl(MXC_CCM_MCR); + if (parent == &upll_clk) + mcr |= (1 << clk->id); + else + mcr &= ~(1 << clk->id); + + __raw_writel(mcr, MXC_CCM_MCR); + + return 0; +} + +static int _clk_perclkx_set_parent3(struct clk *clk, struct clk *parent) +{ + unsigned long mcr = __raw_readl(MXC_CCM_MCR); + int bit; + + if (clk->parent == parent) + return 0; + if (parent != &upll_clk && parent != &ahb_clk && + parent != &upll_24610k_clk) + return -EINVAL; + + switch (clk->id) { + case 2: + bit = MXC_CCM_MCR_ESAI_CLK_MUX_OFFSET; + break; + case 13: + bit = MXC_CCM_MCR_SSI1_CLK_MUX_OFFSET; + break; + case 14: + bit = MXC_CCM_MCR_SSI2_CLK_MUX_OFFSET; + break; + default: + return -EINVAL; + } + + if (parent == &upll_24610k_clk) { + mcr |= bit; + __raw_writel(mcr, MXC_CCM_MCR); + clk->parent = parent; + } else { + mcr &= ~bit; + __raw_writel(mcr, MXC_CCM_MCR); + return _clk_perclkx_set_parent(clk, parent); + } + + return 0; +} + +static unsigned long _clk_ipg_getrate(struct clk *clk) +{ + unsigned long rate = clk_get_rate(clk->parent) / 2; /* Always AHB / 2 */ + return rate; +} + +/* Top-level clocks */ +static unsigned long ckih_rate = OSC24M_CLK_FREQ; + +static unsigned long clk_ckih_get_rate(struct clk *clk) +{ + return ckih_rate; +} + +static unsigned long clk_ckil_get_rate(struct clk *clk) +{ + return OSC32K_CLK_FREQ; +} + +static struct clk osc24m_clk = { + .get_rate = clk_ckih_get_rate, +}; + +static struct clk osc32k_clk = { + .get_rate = clk_ckil_get_rate, +}; + +static struct clk mpll_clk = { + .parent = &osc24m_clk, + .get_rate = _clk_pll_getrate, + .set_rate = _clk_pll_set_rate, +}; + +static struct clk upll_clk = { + .parent = &osc24m_clk, + .get_rate = _clk_pll_getrate, + .set_rate = _clk_pll_set_rate, + .enable = _clk_upll_enable, + .disable = _clk_upll_disable, +}; + +static unsigned long _clk_24610k_getrate(struct clk *clk) +{ + long long rate = clk_get_rate(clk->parent) * 2461LL; + + do_div(rate, 24000); + + return rate; /* Always (UPLL * 24.61 / 240) */ +} + +static struct clk upll_24610k_clk = { + .parent = &upll_clk, + .get_rate = _clk_24610k_getrate, +}; + +/* Mid-level clocks */ + +static struct clk cpu_clk = { /* ARM clock */ + .parent = &mpll_clk, + .set_rate = _clk_cpu_set_rate, + .get_rate = _clk_cpu_getrate, + .round_rate = _clk_cpu_round_rate, +}; + +static struct clk ahb_clk = { /* a.k.a. HCLK */ + .parent = &cpu_clk, + .get_rate = _clk_ahb_getrate, +}; + +static struct clk ipg_clk = { + .parent = &ahb_clk, + .get_rate = _clk_ipg_getrate, +}; + +/* Bottom-level clocks */ + +static struct clk usbotg_clk = { + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_USBOTG_OFFSET, + .disable = _clk_disable, +}; + +static struct clk rtic_clk[] = { + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_RTIC_OFFSET, + .disable = _clk_disable, + .secondary = &rtic_clk[1], + }, + { + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_RTIC_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk emi_clk = { + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_EMI_OFFSET, + .disable = _clk_disable, +}; + +static struct clk brom_clk = { + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_BROM_OFFSET, + .disable = _clk_disable, +}; + +static struct clk per_clk[] = { + { + .id = 0, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, + { + .id = 1, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, + { + .id = 2, + .parent = &ahb_clk, /* can be AHB or UPLL or 24.61MHz */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent3, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, + { + .id = 3, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + }, + { + .id = 4, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, + { + .id = 5, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, + { + .id = 6, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, + { + .id = 7, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, + { + .id = 8, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, + { + .id = 9, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, + { + .id = 10, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, + { + .id = 11, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, + { + .id = 12, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, + { + .id = 13, + .parent = &ahb_clk, /* can be AHB or UPLL or 24.61MHz */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent3, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, + { + .id = 14, + .parent = &ahb_clk, /* can be AHB or UPLL or 24.61MHz */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent3, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, + { + .id = 15, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .get_rate = _clk_perclkx_getrate, + .enable = _perclk_enable, + .disable = _perclk_disable, + }, +}; + +static struct clk nfc_clk = { + .id = 0, + .parent = &per_clk[8], +}; + +static struct clk audmux_clk = { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_AUDMUX_OFFSET, + .disable = _clk_disable, +}; + +static struct clk ata_clk[] = { + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_ATA_OFFSET, + .disable = _clk_disable, + .secondary = &ata_clk[1], + }, + { + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_ATA_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk can_clk[] = { + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_CAN1_OFFSET, + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_CAN2_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk csi_clk[] = { + { + .id = 0, + .parent = &per_clk[0], + .secondary = &csi_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_CSI_OFFSET, + .disable = _clk_disable, + .secondary = &csi_clk[2], + }, + { + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_CSI_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk cspi_clk[] = { + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_CSPI1_OFFSET, + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_CSPI2_OFFSET, + .disable = _clk_disable, + }, + { + .id = 2, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_CSPI3_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk dryice_clk = { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_DRYICE_OFFSET, + .disable = _clk_disable, +}; + +static struct clk ect_clk = { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_ECT_OFFSET, + .disable = _clk_disable, +}; + +static struct clk epit1_clk[] = { + { + .id = 0, + .parent = &per_clk[1], + .secondary = &epit1_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_EPIT1_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk epit2_clk[] = { + { + .id = 1, + .parent = &per_clk[1], + .secondary = &epit2_clk[1], + }, + { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_EPIT2_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk esai_clk[] = { + { + .id = 0, + .parent = &per_clk[2], + .secondary = &esai_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_ESAI_OFFSET, + .disable = _clk_disable, + .secondary = &esai_clk[2], + }, + { + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_ESAI_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk esdhc1_clk[] = { + { + .id = 0, + .parent = &per_clk[3], + .secondary = &esdhc1_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_ESDHC1_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc1_clk[2], + }, + { + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_ESDHC1_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk esdhc2_clk[] = { + { + .id = 1, + .parent = &per_clk[4], + .secondary = &esdhc2_clk[1], + }, + { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_ESDHC2_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc2_clk[2], + }, + { + .id = 1, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_ESDHC2_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk fec_clk[] = { + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_FEC_OFFSET, + .disable = _clk_disable, + .secondary = &fec_clk[1], + }, + { + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_FEC_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk gpio_clk[] = { + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_GPIO1_OFFSET, + .disable = _clk_disable, + }, + { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_GPIO2_OFFSET, + .disable = _clk_disable, + }, + { + .id = 2, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_GPIO3_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk gpt1_clk[] = { + { + .id = 0, + .parent = &per_clk[5], + .secondary = &gpt1_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_GPT1_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk gpt2_clk[] = { + { + .id = 1, + .parent = &per_clk[5], + .secondary = &gpt2_clk[1], + }, + { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_GPT2_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk gpt3_clk[] = { + { + .id = 2, + .parent = &per_clk[5], + .secondary = &gpt3_clk[1], + }, + { + .id = 2, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_GPT3_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk gpt4_clk[] = { + { + .id = 3, + .parent = &per_clk[5], + .secondary = &gpt4_clk[1], + }, + { + .id = 3, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_GPT4_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk i2c_clk[] = { + { + .id = 0, + .parent = &per_clk[6], + }, + { + .id = 1, + .parent = &per_clk[6], + }, + { + .id = 2, + .parent = &per_clk[6], + }, +}; + +static struct clk iim_clk = { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_IIM_OFFSET, + .disable = _clk_disable, +}; + +static struct clk iomuxc_clk = { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_IOMUXC_OFFSET, + .disable = _clk_disable, +}; + +static struct clk kpp_clk = { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_KPP_OFFSET, + .disable = _clk_disable, +}; + +static struct clk lcdc_clk[] = { + { + .id = 0, + .parent = &per_clk[7], + .secondary = &lcdc_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_LCDC_OFFSET, + .disable = _clk_disable, + .secondary = &lcdc_clk[2], + }, + { + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_LCDC_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk owire_clk[] = { + { + .id = 0, + .parent = &per_clk[9], + .secondary = &owire_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_OWIRE_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk pwm1_clk[] = { + { + .id = 0, + .parent = &per_clk[10], + .secondary = &pwm1_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_PWM1_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk pwm2_clk[] = { + { + .id = 1, + .parent = &per_clk[10], + .secondary = &pwm2_clk[1], + }, + { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_PWM2_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk pwm3_clk[] = { + { + .id = 2, + .parent = &per_clk[10], + .secondary = &pwm3_clk[1], + }, + { + .id = 2, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_PWM3_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk pwm4_clk[] = { + { + .id = 3, + .parent = &per_clk[10], + .secondary = &pwm4_clk[1], + }, + { + .id = 3, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_PWM3_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk rngb_clk = { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_RNGB_OFFSET, + .disable = _clk_disable, +}; + +static struct clk scc_clk = { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SCC_OFFSET, + .disable = _clk_disable, +}; + +static struct clk sdma_clk[] = { + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SDMA_OFFSET, + .disable = _clk_disable, + .secondary = &sdma_clk[1], + }, + { + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_SDMA_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk sim1_clk[] = { + { + .id = 0, + .parent = &per_clk[11], + .secondary = &sim1_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SIM1_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk sim2_clk[] = { + { + .id = 1, + .parent = &per_clk[12], + .secondary = &sim2_clk[1], + }, + { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SIM2_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk slcdc_clk[] = { + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SLCDC_OFFSET, + .disable = _clk_disable, + .secondary = &slcdc_clk[1], + }, + { + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_SLCDC_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk spba_clk = { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SPBA_OFFSET, + .disable = _clk_disable, +}; + +static struct clk ssi1_clk[] = { + { + .id = 0, + .parent = &per_clk[13], + .secondary = &ssi1_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SSI1_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk ssi2_clk[] = { + { + .id = 1, + .parent = &per_clk[14], + .secondary = &ssi2_clk[1], + }, + { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SSI2_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk tsc_clk = { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_TSC_OFFSET, + .disable = _clk_disable, +}; + +static struct clk uart1_clk[] = { + { + .id = 0, + .parent = &per_clk[15], + .secondary = &uart1_clk[1], + }, + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_UART1_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk uart2_clk[] = { + { + .id = 1, + .parent = &per_clk[15], + .secondary = &uart2_clk[1], + }, + { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_UART2_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk uart3_clk[] = { + { + .id = 2, + .parent = &per_clk[15], + .secondary = &uart3_clk[1], + }, + { + .id = 2, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_UART3_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk uart4_clk[] = { + { + .id = 3, + .parent = &per_clk[15], + .secondary = &uart4_clk[1], + }, + { + .id = 3, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_UART4_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk uart5_clk[] = { + { + .id = 4, + .parent = &per_clk[15], + .secondary = &uart5_clk[1], + }, + { + .id = 4, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_UART5_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk wdog_clk = { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_WDOG_OFFSET, + .disable = _clk_disable, +}; + +static unsigned long _clk_usb_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long div; + + div = clk_get_rate(clk->parent) / rate; + if (clk_get_rate(clk->parent) % rate) + div++; + + if (div > 64) + return -EINVAL; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_usb_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long reg; + unsigned long div; + + div = clk_get_rate(clk->parent) / rate; + + if (clk_get_rate(clk->parent) / div != rate) + return -EINVAL; + if (div > 64) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CCTL) & ~MXC_CCM_CCTL_USB_DIV_MASK; + reg |= (div - 1) << MXC_CCM_CCTL_USB_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_MCR); + + return 0; +} + +static unsigned long _clk_usb_getrate(struct clk *clk) +{ + unsigned long div; + + div = __raw_readl(MXC_CCM_MCR) & MXC_CCM_CCTL_USB_DIV_MASK; + div >>= MXC_CCM_CCTL_USB_DIV_OFFSET; + + return clk_get_rate(clk->parent) / (div + 1); +} + +static int _clk_usb_set_parent(struct clk *clk, struct clk *parent) +{ + unsigned long mcr; + + if (clk->parent == parent) + return 0; + if (parent != &upll_clk && parent != &ahb_clk) + return -EINVAL; + + clk->parent = parent; + mcr = __raw_readl(MXC_CCM_MCR); + if (parent == &ahb_clk) + mcr |= (1 << MXC_CCM_MCR_USB_CLK_MUX_OFFSET); + else + mcr &= ~(1 << MXC_CCM_MCR_USB_CLK_MUX_OFFSET); + + __raw_writel(mcr, MXC_CCM_MCR); + + return 0; +} + +static struct clk usb_clk = { + .parent = &upll_clk, + .get_rate = _clk_usb_getrate, + .set_rate = _clk_usb_set_rate, + .round_rate = _clk_usb_round_rate, + .set_parent = _clk_usb_set_parent, + .secondary = &usbotg_clk, +}; + +/* CLKO */ + +static unsigned long _clk_clko_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long div; + + div = clk_get_rate(clk->parent) / rate; + if (clk_get_rate(clk->parent) % rate) + div++; + + if (div > 64) + return -EINVAL; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_clko_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long reg; + unsigned long div; + + div = clk_get_rate(clk->parent) / rate; + + if ((clk_get_rate(clk->parent) / div) != rate) + return -EINVAL; + if (div > 64) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_MCR) & ~MXC_CCM_MCR_CLKO_DIV_MASK; + reg |= (div - 1) << MXC_CCM_MCR_CLKO_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_MCR); + + return 0; +} + +static unsigned long _clk_clko_getrate(struct clk *clk) +{ + unsigned long div = __raw_readl(MXC_CCM_MCR); + + div &= MXC_CCM_MCR_CLKO_DIV_MASK; + div >>= MXC_CCM_MCR_CLKO_DIV_OFFSET; + + return clk_get_rate(clk->parent) / (div + 1); +} + +static struct clk *clko_sources[] = { + &osc32k_clk, /* 0x0 */ + &osc24m_clk, /* 0x1 */ + &cpu_clk, /* 0x2 */ + &ahb_clk, /* 0x3 */ + &ipg_clk, /* 0x4 */ + NULL, /* 0x5 */ + NULL, /* 0x6 */ + NULL, /* 0x7 */ + NULL, /* 0x8 */ + NULL, /* 0x9 */ + &per_clk[0], /* 0xA */ + &per_clk[2], /* 0xB */ + &per_clk[13], /* 0xC */ + &per_clk[14], /* 0xD */ + &usb_clk, /* 0xE */ + NULL, /* 0xF */ +}; + +#define NR_CLKO_SOURCES (sizeof(clko_sources) / sizeof(struct clk *)) + +static int _clk_clko_set_parent(struct clk *clk, struct clk *parent) +{ + unsigned long reg; + struct clk **src; + int i; + + if (clk->parent == parent) + return 0; + for (i = 0, src = clko_sources; i < NR_CLKO_SOURCES; i++, src++) + if (*src == parent) + break; + + if (i == NR_CLKO_SOURCES) + return -EINVAL; + + clk->parent = parent; + + reg = __raw_readl(MXC_CCM_MCR) & ~MXC_CCM_MCR_CLKO_SEL_MASK; + reg |= i << MXC_CCM_MCR_CLKO_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_MCR); + + return 0; +} + +static struct clk clko_clk = { + .set_rate = _clk_clko_set_rate, + .round_rate = _clk_clko_round_rate, + .set_parent = _clk_clko_set_parent, + .get_rate = _clk_clko_getrate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_MCR, + .enable_shift = MXC_CCM_MCR_CLKO_EN_OFFSET, + .disable = _clk_disable, +}; + +#define _REGISTER_CLOCK(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = &c, \ + }, + +static struct clk_lookup lookups[] = { + _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) + _REGISTER_CLOCK(NULL, "audmux", audmux_clk) + _REGISTER_CLOCK(NULL, "ata", ata_clk[0]) + _REGISTER_CLOCK("mxc-flexcan.0", NULL, can_clk[0]) + _REGISTER_CLOCK("mxc-flexcan.1", NULL, can_clk[1]) + _REGISTER_CLOCK(NULL, "csi", csi_clk[0]) + _REGISTER_CLOCK(NULL, "cspi.0", cspi_clk[0]) + _REGISTER_CLOCK(NULL, "cspi.1", cspi_clk[1]) + _REGISTER_CLOCK(NULL, "cspi.2", cspi_clk[2]) + _REGISTER_CLOCK(NULL, "dryice", dryice_clk) + _REGISTER_CLOCK(NULL, "ect", ect_clk) + _REGISTER_CLOCK(NULL, "epit1", epit1_clk[0]) + _REGISTER_CLOCK(NULL, "epit2", epit2_clk[0]) + _REGISTER_CLOCK(NULL, "esai", esai_clk[0]) + _REGISTER_CLOCK("mxc-mmc.0", NULL, esdhc1_clk[0]) + _REGISTER_CLOCK("mxc-mmc.1", NULL, esdhc2_clk[0]) + _REGISTER_CLOCK("fec.0", NULL, fec_clk[0]) + _REGISTER_CLOCK(NULL, "gpio0", gpio_clk[0]) + _REGISTER_CLOCK(NULL, "gpio1", gpio_clk[1]) + _REGISTER_CLOCK(NULL, "gpio2", gpio_clk[2]) + _REGISTER_CLOCK(NULL, "gpt1", gpt1_clk[0]) + _REGISTER_CLOCK(NULL, "gpt2", gpt2_clk[0]) + _REGISTER_CLOCK(NULL, "gpt3", gpt3_clk[0]) + _REGISTER_CLOCK(NULL, "gpt4", gpt4_clk[0]) + _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk[0]) + _REGISTER_CLOCK("imx-i2c.1", NULL, i2c_clk[1]) + _REGISTER_CLOCK("imx-i2c.2", NULL, i2c_clk[2]) + _REGISTER_CLOCK(NULL, "iim", iim_clk) + _REGISTER_CLOCK(NULL, "iomuxc", iomuxc_clk) + _REGISTER_CLOCK(NULL, "kpp", kpp_clk) + _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk[0]) + _REGISTER_CLOCK(NULL, "owire", owire_clk[0]) + _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm1_clk[0]) + _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk[0]) + _REGISTER_CLOCK("mxc_pwm.2", NULL, pwm3_clk[0]) + _REGISTER_CLOCK("mxc_pwm.3", NULL, pwm4_clk[0]) + _REGISTER_CLOCK(NULL, "rngb", rngb_clk) + _REGISTER_CLOCK(NULL, "scc", scc_clk) + _REGISTER_CLOCK(NULL, "sdma", sdma_clk[0]) + _REGISTER_CLOCK(NULL, "sim1", sim1_clk[0]) + _REGISTER_CLOCK(NULL, "sim2", sim2_clk[0]) + _REGISTER_CLOCK(NULL, "slcdc", slcdc_clk[0]) + _REGISTER_CLOCK(NULL, "spba", spba_clk) + _REGISTER_CLOCK(NULL, "ssi1", ssi1_clk[0]) + _REGISTER_CLOCK(NULL, "ssi2", ssi2_clk[0]) + _REGISTER_CLOCK("mxc-tsadcc.0", NULL, tsc_clk) + _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk[0]) + _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk[0]) + _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk[0]) + _REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk[0]) + _REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk[0]) + _REGISTER_CLOCK("imx-wdt.0", NULL, wdog_clk) + _REGISTER_CLOCK(NULL, "usb", usb_clk) + _REGISTER_CLOCK(NULL, "clko", clko_clk) + _REGISTER_CLOCK(NULL, "brom", brom_clk) +}; + +int __init mx25_clocks_init(unsigned long fref) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(lookups); i++) + clkdev_add(&lookups[i]); + + ckih_rate = fref; +#ifndef CONFIG_DEBUG_LL + /* Turn off all possible clocks */ + __raw_writel((1 << MXC_CCM_CGCR0_HCLK_EMI_OFFSET), MXC_CCM_CGCR0); + + __raw_writel((1 << MXC_CCM_CGCR1_GPT1_OFFSET) | + (1 << MXC_CCM_CGCR1_IIM_OFFSET), MXC_CCM_CGCR1); + __raw_writel(1 << MXC_CCM_CGCR2_SCC_OFFSET, MXC_CCM_CGCR2); +#endif +#if 1 + /* Set all perclk sources to upll */ + for (i = 0; i < ARRAY_SIZE(per_clk); i++) { + int ret; + unsigned long rate = per_clk[i].get_rate(&per_clk[i]); + +#ifdef CONFIG_DEBUG_LL + if (i == 15) { + printk(KERN_DEBUG "skipping per_clk[%d] rate=%lu\n", i, rate); + continue; + } +#endif + { + unsigned long new_rate; + + per_clk[i].set_parent(&per_clk[i], &upll_clk); + new_rate = per_clk[i].round_rate(&per_clk[i], rate); + if (rate == new_rate) + break; + if ((ret = per_clk[i].set_rate(&per_clk[i], new_rate)) < 0) { + printk(KERN_ERR "Error %d setting clk[%d] rate to %lu\n", + ret, i, new_rate); + } + } + } + + /* the NFC clock must be derived from AHB clock */ + clk_set_parent(&per_clk[8], &ahb_clk); +#endif + clk_set_rate(&per_clk[8], clk_get_rate(&ahb_clk) / 6); + clk_set_rate(&per_clk[7], clk_get_rate(per_clk[7].parent)); + + /* This will propagate to all children and init all the clock rates */ +#ifdef CONFIG_DEBUG_LL + clk_enable(&uart1_clk[0]); +#endif + clk_enable(&emi_clk); + clk_enable(&iim_clk); + + pr_info("Clock input source is %ld\n", clk_get_rate(&osc24m_clk)); + + pr_info("CPU: %lu.%03luMHz\n", + clk_get_rate(&cpu_clk) / 1000000, clk_get_rate(&cpu_clk) / 1000 % 1000); + pr_info("AHB: %lu.%03luMHz\n", + clk_get_rate(&ahb_clk) / 1000000, clk_get_rate(&ahb_clk) / 1000 % 1000); + pr_info("MPLL: %lu.%03luMHz\n", + clk_get_rate(&mpll_clk) / 1000000, clk_get_rate(&mpll_clk) / 1000 % 1000); + pr_info("UPLL: %lu.%03luMHz\n", + clk_get_rate(&upll_clk) / 1000000, clk_get_rate(&upll_clk) / 1000 % 1000); + clk_set_rate(&mpll_clk, clk_get_rate(&mpll_clk)); + clk_set_rate(&upll_clk, clk_get_rate(&upll_clk)); + + mxc_timer_init(&gpt1_clk[1]); + return 0; +} diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/clock_imx27.c linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/clock_imx27.c --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/clock_imx27.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/clock_imx27.c 2009-06-02 17:59:15.000000000 +0200 @@ -621,7 +621,7 @@ DEFINE_CLOCK1(csi_clk, 0, 0, 0, .clk = &c, \ }, -static struct clk_lookup lookups[] __initdata = { +static struct clk_lookup lookups[] = { _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk) _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk) _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk) diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/cpu_imx25.c linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/cpu_imx25.c --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/cpu_imx25.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/cpu_imx25.c 2009-06-02 17:59:17.000000000 +0200 @@ -0,0 +1,65 @@ +/* + * arch/arm/mach-mx2/cpu_mx25.c + * + * Copyright 2009 Lothar Wassmann + * derived from: cpu_mx27.c + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +/* + * i.MX25 specific CPU detection code + */ + +#include +#include + +#include + +static int cpu_silicon_rev = -1; +static int cpu_partnumber; + +#define IIM_PREV_REG IO_ADDRESS(IIM_BASE_ADDR + 0x20) +#define IIM_SREV_REG IO_ADDRESS(IIM_BASE_ADDR + 0x24) + +static void query_silicon_parameter(void) +{ + cpu_partnumber = __raw_readl(IIM_PREV_REG) >> 3; + cpu_silicon_rev = __raw_readl(IIM_SREV_REG); + + printk(KERN_DEBUG "CPU rev: 0x%02x chip_rev: 0x%02x\n", + cpu_partnumber, cpu_silicon_rev); + if (WARN_ON(cpu_partnumber != 0x1f)) { + printk(KERN_WARNING "Unsupported CPU rev: 0x%02x\n", cpu_partnumber); + } +} + +/* + * Returns: + * the silicon revision of the cpu + * -EINVAL - not a mx25 + */ +int mx25_revision(void) +{ + if (cpu_silicon_rev == -1) + query_silicon_parameter(); + + if (cpu_partnumber != 0x1f) + return -EINVAL; + + return cpu_silicon_rev; +} +EXPORT_SYMBOL(mx25_revision); diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/crm_regs_mx25.h linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/crm_regs_mx25.h --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/crm_regs_mx25.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/crm_regs_mx25.h 2009-06-02 17:59:17.000000000 +0200 @@ -0,0 +1,190 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __ARCH_ARM_MACH_MX25_CRM_REGS_H__ +#define __ARCH_ARM_MACH_MX25_CRM_REGS_H__ + +#include + +/* Register offsets */ +#define MXC_CCM_MPCTL (IO_ADDRESS(CCM_BASE_ADDR) + 0x00) +#define MXC_CCM_UPCTL (IO_ADDRESS(CCM_BASE_ADDR) + 0x04) +#define MXC_CCM_CCTL (IO_ADDRESS(CCM_BASE_ADDR) + 0x08) +#define MXC_CCM_CGCR0 (IO_ADDRESS(CCM_BASE_ADDR) + 0x0C) +#define MXC_CCM_CGCR1 (IO_ADDRESS(CCM_BASE_ADDR) + 0x10) +#define MXC_CCM_CGCR2 (IO_ADDRESS(CCM_BASE_ADDR) + 0x14) +#define MXC_CCM_PCDR0 (IO_ADDRESS(CCM_BASE_ADDR) + 0x18) +#define MXC_CCM_PCDR1 (IO_ADDRESS(CCM_BASE_ADDR) + 0x1C) +#define MXC_CCM_PCDR2 (IO_ADDRESS(CCM_BASE_ADDR) + 0x20) +#define MXC_CCM_PCDR3 (IO_ADDRESS(CCM_BASE_ADDR) + 0x24) +#define MXC_CCM_RCSR (IO_ADDRESS(CCM_BASE_ADDR) + 0x28) +#define MXC_CCM_CRDR (IO_ADDRESS(CCM_BASE_ADDR) + 0x2C) +#define MXC_CCM_DCVR0 (IO_ADDRESS(CCM_BASE_ADDR) + 0x30) +#define MXC_CCM_DCVR1 (IO_ADDRESS(CCM_BASE_ADDR) + 0x34) +#define MXC_CCM_DCVR2 (IO_ADDRESS(CCM_BASE_ADDR) + 0x38) +#define MXC_CCM_DCVR3 (IO_ADDRESS(CCM_BASE_ADDR) + 0x3C) +#define MXC_CCM_LTR0 (IO_ADDRESS(CCM_BASE_ADDR) + 0x40) +#define MXC_CCM_LTR1 (IO_ADDRESS(CCM_BASE_ADDR) + 0x44) +#define MXC_CCM_LTR2 (IO_ADDRESS(CCM_BASE_ADDR) + 0x48) +#define MXC_CCM_LTR3 (IO_ADDRESS(CCM_BASE_ADDR) + 0x4C) +#define MXC_CCM_LTBR0 (IO_ADDRESS(CCM_BASE_ADDR) + 0x50) +#define MXC_CCM_LTBR1 (IO_ADDRESS(CCM_BASE_ADDR) + 0x54) +#define MXC_CCM_PMCR0 (IO_ADDRESS(CCM_BASE_ADDR) + 0x58) +#define MXC_CCM_PMCR1 (IO_ADDRESS(CCM_BASE_ADDR) + 0x5C) +#define MXC_CCM_PMCR2 (IO_ADDRESS(CCM_BASE_ADDR) + 0x60) +#define MXC_CCM_MCR (IO_ADDRESS(CCM_BASE_ADDR) + 0x64) + +#define MXC_CCM_MPCTL_BRMO (1 << 31) +#define MXC_CCM_MPCTL_PD_OFFSET 26 +#define MXC_CCM_MPCTL_PD_MASK (0xf << 26) +#define MXC_CCM_MPCTL_MFD_OFFSET 16 +#define MXC_CCM_MPCTL_MFD_MASK (0x3ff << 16) +#define MXC_CCM_MPCTL_MFI_OFFSET 10 +#define MXC_CCM_MPCTL_MFI_MASK (0xf << 10) +#define MXC_CCM_MPCTL_MFN_OFFSET 0 +#define MXC_CCM_MPCTL_MFN_MASK 0x3ff +#define MXC_CCM_MPCTL_LF (1 << 15) + +#define MXC_CCM_UPCTL_BRMO (1 << 31) +#define MXC_CCM_UPCTL_PD_OFFSET 26 +#define MXC_CCM_UPCTL_PD_MASK (0xf << 26) +#define MXC_CCM_UPCTL_MFD_OFFSET 16 +#define MXC_CCM_UPCTL_MFD_MASK (0x3ff << 16) +#define MXC_CCM_UPCTL_MFI_OFFSET 10 +#define MXC_CCM_UPCTL_MFI_MASK (0xf << 10) +#define MXC_CCM_UPCTL_MFN_OFFSET 0 +#define MXC_CCM_UPCTL_MFN_MASK 0x3ff +#define MXC_CCM_UPCTL_LF (1 << 15) + +#define MXC_CCM_CCTL_ARM_OFFSET 30 +#define MXC_CCM_CCTL_ARM_MASK (0x3 << 30) +#define MXC_CCM_CCTL_AHB_OFFSET 28 +#define MXC_CCM_CCTL_AHB_MASK (0x3 << 28) +#define MXC_CCM_CCTL_MPLL_RST (1 << 27) +#define MXC_CCM_CCTL_UPLL_RST (1 << 26) +#define MXC_CCM_CCTL_LP_CTL_OFFSET 24 +#define MXC_CCM_CCTL_LP_CTL_MASK (0x3 << 24) +#define MXC_CCM_CCTL_LP_MODE_RUN (0x0 << 24) +#define MXC_CCM_CCTL_LP_MODE_WAIT (0x1 << 24) +#define MXC_CCM_CCTL_LP_MODE_DOZE (0x2 << 24) +#define MXC_CCM_CCTL_LP_MODE_STOP (0x3 << 24) +#define MXC_CCM_CCTL_UPLL_DISABLE (1 << 23) +#define MXC_CCM_CCTL_MPLL_BYPASS (1 << 22) +#define MXC_CCM_CCTL_USB_DIV_OFFSET 16 +#define MXC_CCM_CCTL_USB_DIV_MASK (0x3 << 16) +#define MXC_CCM_CCTL_CG_CTRL (1 << 15) +#define MXC_CCM_CCTL_ARM_SRC (1 << 14) + +#define MXC_CCM_CGCR0_HCLK_ATA_OFFSET 16 +#define MXC_CCM_CGCR0_HCLK_BROM_OFFSET 17 +#define MXC_CCM_CGCR0_HCLK_CSI_OFFSET 18 +#define MXC_CCM_CGCR0_HCLK_EMI_OFFSET 19 +#define MXC_CCM_CGCR0_HCLK_ESAI_OFFSET 20 +#define MXC_CCM_CGCR0_HCLK_ESDHC1_OFFSET 21 +#define MXC_CCM_CGCR0_HCLK_ESDHC2_OFFSET 22 +#define MXC_CCM_CGCR0_HCLK_FEC_OFFSET 23 +#define MXC_CCM_CGCR0_HCLK_LCDC_OFFSET 24 +#define MXC_CCM_CGCR0_HCLK_RTIC_OFFSET 25 +#define MXC_CCM_CGCR0_HCLK_SDMA_OFFSET 26 +#define MXC_CCM_CGCR0_HCLK_SLCDC_OFFSET 27 +#define MXC_CCM_CGCR0_HCLK_USBOTG_OFFSET 28 + +#define MXC_CCM_CGCR0_PER_CSI_OFFSET 0 +#define MXC_CCM_CGCR0_PER_EPIT_OFFSET 1 +#define MXC_CCM_CGCR0_PER_ESAI_OFFSET 2 +#define MXC_CCM_CGCR0_PER_ESDHC1_OFFSET 3 +#define MXC_CCM_CGCR0_PER_ESDHC2_OFFSET 4 +#define MXC_CCM_CGCR0_PER_GPT_OFFSET 5 +#define MXC_CCM_CGCR0_PER_I2C_OFFSET 6 +#define MXC_CCM_CGCR0_PER_LCDC_OFFSET 7 +#define MXC_CCM_CGCR0_PER_NFC_OFFSET 8 +#define MXC_CCM_CGCR0_PER_OWIRE_OFFSET 9 +#define MXC_CCM_CGCR0_PER_PWM_OFFSET 10 +#define MXC_CCM_CGCR0_PER_SIM1_OFFSET 11 +#define MXC_CCM_CGCR0_PER_SIM2_OFFSET 12 +#define MXC_CCM_CGCR0_PER_SSI1_OFFSET 13 +#define MXC_CCM_CGCR0_PER_SSI2_OFFSET 14 +#define MXC_CCM_CGCR0_PER_UART_OFFSET 15 + +#define MXC_CCM_CGCR1_AUDMUX_OFFSET 0 +#define MXC_CCM_CGCR1_ATA_OFFSET 1 +#define MXC_CCM_CGCR1_CAN1_OFFSET 2 +#define MXC_CCM_CGCR1_CAN2_OFFSET 3 +#define MXC_CCM_CGCR1_CSI_OFFSET 4 +#define MXC_CCM_CGCR1_CSPI1_OFFSET 5 +#define MXC_CCM_CGCR1_CSPI2_OFFSET 6 +#define MXC_CCM_CGCR1_CSPI3_OFFSET 7 +#define MXC_CCM_CGCR1_DRYICE_OFFSET 8 +#define MXC_CCM_CGCR1_ECT_OFFSET 9 +#define MXC_CCM_CGCR1_EPIT1_OFFSET 10 +#define MXC_CCM_CGCR1_EPIT2_OFFSET 11 +#define MXC_CCM_CGCR1_ESAI_OFFSET 12 +#define MXC_CCM_CGCR1_ESDHC1_OFFSET 13 +#define MXC_CCM_CGCR1_ESDHC2_OFFSET 14 +#define MXC_CCM_CGCR1_FEC_OFFSET 15 +#define MXC_CCM_CGCR1_GPIO1_OFFSET 16 +#define MXC_CCM_CGCR1_GPIO2_OFFSET 17 +#define MXC_CCM_CGCR1_GPIO3_OFFSET 18 +#define MXC_CCM_CGCR1_GPT1_OFFSET 19 +#define MXC_CCM_CGCR1_GPT2_OFFSET 20 +#define MXC_CCM_CGCR1_GPT3_OFFSET 21 +#define MXC_CCM_CGCR1_GPT4_OFFSET 22 +#define MXC_CCM_CGCR1_I2C1_OFFSET 23 +#define MXC_CCM_CGCR1_I2C2_OFFSET 24 +#define MXC_CCM_CGCR1_I2C3_OFFSET 25 +#define MXC_CCM_CGCR1_IIM_OFFSET 26 +#define MXC_CCM_CGCR1_IOMUXC_OFFSET 27 +#define MXC_CCM_CGCR1_KPP_OFFSET 28 +#define MXC_CCM_CGCR1_LCDC_OFFSET 29 +#define MXC_CCM_CGCR1_OWIRE_OFFSET 30 +#define MXC_CCM_CGCR1_PWM1_OFFSET 31 + +#define MXC_CCM_CGCR2_PWM2_OFFSET (32-32) +#define MXC_CCM_CGCR2_PWM3_OFFSET (33-32) +#define MXC_CCM_CGCR2_PWM4_OFFSET (34-32) +#define MXC_CCM_CGCR2_RNGB_OFFSET (35-32) +#define MXC_CCM_CGCR2_RTIC_OFFSET (36-32) +#define MXC_CCM_CGCR2_SCC_OFFSET (37-32) +#define MXC_CCM_CGCR2_SDMA_OFFSET (38-32) +#define MXC_CCM_CGCR2_SIM1_OFFSET (39-32) +#define MXC_CCM_CGCR2_SIM2_OFFSET (40-32) +#define MXC_CCM_CGCR2_SLCDC_OFFSET (41-32) +#define MXC_CCM_CGCR2_SPBA_OFFSET (42-32) +#define MXC_CCM_CGCR2_SSI1_OFFSET (43-32) +#define MXC_CCM_CGCR2_SSI2_OFFSET (44-32) +#define MXC_CCM_CGCR2_TCHSCRN_OFFSET (45-32) +#define MXC_CCM_CGCR2_UART1_OFFSET (46-32) +#define MXC_CCM_CGCR2_UART2_OFFSET (47-32) +#define MXC_CCM_CGCR2_UART3_OFFSET (48-32) +#define MXC_CCM_CGCR2_UART4_OFFSET (49-32) +#define MXC_CCM_CGCR2_UART5_OFFSET (50-32) +#define MXC_CCM_CGCR2_WDOG_OFFSET (51-32) + +#define MXC_CCM_PCDR1_PERDIV1_MASK 0x3f + +#define MXC_CCM_RCSR_NF16B (1 << 14) + +#define MXC_CCM_MCR_USB_XTAL_MUX_OFFSET 31 +#define MXC_CCM_MCR_CLKO_EN_OFFSET 30 +#define MXC_CCM_MCR_CLKO_DIV_OFFSET 24 +#define MXC_CCM_MCR_CLKO_DIV_MASK (0x3F << 24) +#define MXC_CCM_MCR_CLKO_SEL_OFFSET 20 +#define MXC_CCM_MCR_CLKO_SEL_MASK (0xF << 20) +#define MXC_CCM_MCR_ESAI_CLK_MUX_OFFSET 19 +#define MXC_CCM_MCR_SSI2_CLK_MUX_OFFSET 18 +#define MXC_CCM_MCR_SSI1_CLK_MUX_OFFSET 17 +#define MXC_CCM_MCR_USB_CLK_MUX_OFFSET 16 + +#define MXC_CCM_MCR_PER_CLK_MUX_MASK (0xFFFF << 0) + +#endif /* __ARCH_ARM_MACH_MX25_CRM_REGS_H__ */ diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/devices.h linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/devices.h --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/devices.h 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/devices.h 2009-07-01 11:10:15.000000000 +0200 @@ -20,3 +20,12 @@ extern struct platform_device mxc_i2c_de extern struct platform_device mxc_i2c_device1; extern struct platform_device mxc_sdhc_device0; extern struct platform_device mxc_sdhc_device1; +extern struct platform_device mxc_usbh1_device; +extern struct platform_device mxc_usbh2_device; +extern struct platform_device mxc_usbotg_device; +#ifdef CONFIG_MACH_MX25 +extern struct platform_device mx25_i2c_device0; +extern struct platform_device mx25_i2c_device1; +extern struct platform_device mx25_i2c_device2; +extern struct platform_device mxc_sdhc_device2; +#endif diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/devices_mx25.c linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/devices_mx25.c --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/devices_mx25.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/devices_mx25.c 2009-06-29 10:48:40.000000000 +0200 @@ -0,0 +1,452 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "sdma_script_code.h" + +#include "karo.h" + +void mx25_sdma_get_script_info(sdma_script_start_addrs * sdma_script_addr) +{ + sdma_script_addr->mxc_sdma_ap_2_ap_addr = ap_2_ap_ADDR; + sdma_script_addr->mxc_sdma_ap_2_bp_addr = -1; + sdma_script_addr->mxc_sdma_bp_2_ap_addr = -1; + sdma_script_addr->mxc_sdma_loopback_on_dsp_side_addr = -1; + sdma_script_addr->mxc_sdma_mcu_interrupt_only_addr = -1; + + sdma_script_addr->mxc_sdma_firi_2_per_addr = -1; + sdma_script_addr->mxc_sdma_firi_2_mcu_addr = -1; + sdma_script_addr->mxc_sdma_per_2_firi_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_firi_addr = -1; + + sdma_script_addr->mxc_sdma_uart_2_per_addr = uart_2_per_ADDR; + sdma_script_addr->mxc_sdma_uart_2_mcu_addr = uart_2_mcu_ADDR; + sdma_script_addr->mxc_sdma_per_2_app_addr = per_2_app_ADDR; + sdma_script_addr->mxc_sdma_mcu_2_app_addr = mcu_2_app_ADDR; + + sdma_script_addr->mxc_sdma_per_2_per_addr = -1; + + sdma_script_addr->mxc_sdma_uartsh_2_per_addr = uartsh_2_per_ADDR; + sdma_script_addr->mxc_sdma_uartsh_2_mcu_addr = uartsh_2_mcu_ADDR; + sdma_script_addr->mxc_sdma_per_2_shp_addr = per_2_shp_ADDR; + sdma_script_addr->mxc_sdma_mcu_2_shp_addr = mcu_2_shp_ADDR; + + sdma_script_addr->mxc_sdma_ata_2_mcu_addr = ata_2_mcu_ADDR; + sdma_script_addr->mxc_sdma_mcu_2_ata_addr = mcu_2_ata_ADDR; + + sdma_script_addr->mxc_sdma_app_2_per_addr = app_2_per_ADDR; + sdma_script_addr->mxc_sdma_app_2_mcu_addr = app_2_mcu_ADDR; + sdma_script_addr->mxc_sdma_shp_2_per_addr = shp_2_per_ADDR; + sdma_script_addr->mxc_sdma_shp_2_mcu_addr = shp_2_mcu_ADDR; + + sdma_script_addr->mxc_sdma_mshc_2_mcu_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_mshc_addr = -1; + + sdma_script_addr->mxc_sdma_spdif_2_mcu_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_spdif_addr = -1; + + sdma_script_addr->mxc_sdma_asrc_2_mcu_addr = -1; + + sdma_script_addr->mxc_sdma_dptc_dvfs_addr = -1; + sdma_script_addr->mxc_sdma_ext_mem_2_ipu_addr = ext_mem__ipu_ram_ADDR; + sdma_script_addr->mxc_sdma_descrambler_addr = -1; + + sdma_script_addr->mxc_sdma_start_addr = (unsigned short *)sdma_code; + sdma_script_addr->mxc_sdma_ram_code_size = RAM_CODE_SIZE; + sdma_script_addr->mxc_sdma_ram_code_start_addr = RAM_CODE_START_ADDR; +} + +#if defined(CONFIG_MXC_WATCHDOG) || defined(CONFIG_MXC_WATCHDOG_MODULE) +static struct resource wdt_resources[] = { + { + .start = WDOG_BASE_ADDR, + .end = WDOG_BASE_ADDR + 0x2f, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device mx25_wdt_device = { + .name = "mxc_wdt", + .id = 0, + .num_resources = ARRAY_SIZE(wdt_resources), + .resource = wdt_resources, +}; + +static void mx25_init_wdt(void) +{ + (void)platform_device_register(&mx25_wdt_device); +} +#else +static inline void mx25_init_wdt(void) +{ +} +#endif + +/* + * lcdc: + * - i.MX1: the basic controller + * - i.MX21: to be checked + * - i.MX27: like i.MX1, with slightly variations + */ +static struct resource mxc_fb[] = { + { + .start = LCDC_BASE_ADDR, + .end = LCDC_BASE_ADDR + 0xFFF, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_LCDC, + .end = MXC_INT_LCDC, + .flags = IORESOURCE_IRQ, + } +}; + +/* mxc lcd driver */ +struct platform_device mxc_fb_device = { + .name = "imx-fb", + .id = 0, + .num_resources = ARRAY_SIZE(mxc_fb), + .resource = mxc_fb, + .dev = { + .coherent_dma_mask = 0xFFFFFFFF, + }, +}; + +/* SPI controller and device data */ +#if defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE) + +#ifdef CONFIG_SPI_MXC_SELECT1 +/*! + * Resource definition for the CSPI1 + */ +static struct resource mx25_spi1_resources[] = { + { + .start = CSPI1_BASE_ADDR, + .end = CSPI1_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_CSPI1, + .end = MXC_INT_CSPI1, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! Platform Data for MXC CSPI1 */ +static struct mxc_spi_master mx25_spi1_data = { + .maxchipselect = 4, + .spi_version = 7, +}; + +/*! Device Definition for MXC CSPI1 */ +static struct platform_device mx25_spi1_device = { + .name = "mxc_spi", + .id = 0, + .dev = { + .platform_data = &mx25_spi1_data, + }, + .num_resources = ARRAY_SIZE(mx25_spi1_resources), + .resource = mx25_spi1_resources, +}; + +#endif /* CONFIG_SPI_MXC_SELECT1 */ + +#ifdef CONFIG_SPI_MXC_SELECT2 +/*! + * Resource definition for the CSPI2 + */ +static struct resource mx25_spi2_resources[] = { + { + .start = CSPI2_BASE_ADDR, + .end = CSPI2_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_CSPI2, + .end = MXC_INT_CSPI2, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! Platform Data for MXC CSPI2 */ +static struct mxc_spi_master mx25_spi2_data = { + .maxchipselect = 4, + .spi_version = 7, +}; + +/*! Device Definition for MXC CSPI2 */ +static struct platform_device mx25_spi2_device = { + .name = "mxc_spi", + .id = 1, + .dev = { + .platform_data = &mx25_spi2_data, + }, + .num_resources = ARRAY_SIZE(mx25_spi2_resources), + .resource = mx25_spi2_resources, +}; +#endif /* CONFIG_SPI_MXC_SELECT2 */ + +#ifdef CONFIG_SPI_MXC_SELECT3 +/*! + * Resource definition for the CSPI3 + */ +static struct resource mx25_spi3_resources[] = { + { + .start = CSPI3_BASE_ADDR, + .end = CSPI3_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_CSPI3, + .end = MXC_INT_CSPI3, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! Platform Data for MXC CSPI3 */ +static struct mxc_spi_master mx25_spi3_data = { + .maxchipselect = 4, + .spi_version = 7, +}; + +/*! Device Definition for MXC CSPI3 */ +static struct platform_device mx25_spi3_device = { + .name = "mxc_spi", + .id = 2, + .dev = { + .platform_data = &mx25_spi3_data, + }, + .num_resources = ARRAY_SIZE(mx25_spi3_resources), + .resource = mx25_spi3_resources, +}; +#endif /* CONFIG_SPI_MXC_SELECT3 */ + +static inline void mx25_init_spi(void) +{ + spba_take_ownership(SPBA_CSPI2, SPBA_MASTER_A); + spba_take_ownership(SPBA_CSPI3, SPBA_MASTER_A); + +#ifdef CONFIG_SPI_MXC_SELECT1 + if (platform_device_register(&mx25_spi1_device) < 0) + printk(KERN_ERR "Error: Registering the SPI Controller_1\n"); +#endif /* CONFIG_SPI_MXC_SELECT1 */ +#ifdef CONFIG_SPI_MXC_SELECT2 + if (platform_device_register(&mx25_spi2_device) < 0) + printk(KERN_ERR "Error: Registering the SPI Controller_2\n"); +#endif /* CONFIG_SPI_MXC_SELECT2 */ +#ifdef CONFIG_SPI_MXC_SELECT3 + if (platform_device_register(&mx25_spi3_device) < 0) + printk(KERN_ERR "Error: Registering the SPI Controller_3\n"); +#endif /* CONFIG_SPI_MXC_SELECT3 */ +} +#else +static inline void mx25_init_spi(void) +{ +} +#endif + +#if defined(CONFIG_USB_EHCI_MXC) || defined(CONFIG_USB_EHCI_MXC_MODULE) +static struct resource mxc_usbotg_resources[] = { + { + .start = OTG_BASE_ADDR, + .end = OTG_BASE_ADDR + 0x1ff, + .flags = IORESOURCE_MEM, + }, { + .start = MXC_INT_USB_OTG, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 usbotg_dmamask = (u32)~0; + +struct platform_device mxc_usbotg_device = { + .name = "mxc-ehci", + .id = 0, + .dev = { + .coherent_dma_mask = 0xffffffff, + .dma_mask = &usbotg_dmamask, + }, + .num_resources = ARRAY_SIZE(mxc_usbotg_resources), + .resource = mxc_usbotg_resources, +}; + +static struct resource mxc_usbh2_resources[] = { + { + .start = USBH2_BASE_ADDR, + .end = USBH2_BASE_ADDR + 0x1ff, + .flags = IORESOURCE_MEM, + }, { + .start = MXC_INT_USB_H2, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 usbh2_dmamask = (u32)~0; + +struct platform_device mxc_usbh2_device = { + .name = "mxc-ehci", + .id = 1, + .dev = { + .coherent_dma_mask = 0xffffffff, + .dma_mask = &usbh2_dmamask, + }, + .num_resources = ARRAY_SIZE(mxc_usbh2_resources), + .resource = mxc_usbh2_resources, +}; +#endif + +/* I2C controller and device data */ +#if defined(CONFIG_I2C_IMX) || defined(CONFIG_I2C_IMX_MODULE) + +/*! + * Resource definition for the I2C1 + */ +static struct resource mx25_i2c1_resources[] = { + { + .start = I2C_BASE_ADDR, + .end = I2C_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_I2C, + .end = MXC_INT_I2C, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! + * Resource definition for the I2C2 + */ +static struct resource mx25_i2c2_resources[] = { + { + .start = I2C2_BASE_ADDR, + .end = I2C2_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_I2C2, + .end = MXC_INT_I2C2, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! + * Resource definition for the I2C3 + */ +static struct resource mx25_i2c3_resources[] = { + { + .start = I2C3_BASE_ADDR, + .end = I2C3_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_I2C3, + .end = MXC_INT_I2C3, + .flags = IORESOURCE_IRQ, + }, +}; + +/*! Device Definition for MXC I2C1 */ +struct platform_device mx25_i2c_device0 = { + .name = "imx-i2c", + .id = 0, + .num_resources = ARRAY_SIZE(mx25_i2c1_resources), + .resource = mx25_i2c1_resources, +}; + +struct platform_device mx25_i2c_device1 = { + .name = "imx-i2c", + .id = 1, + .num_resources = ARRAY_SIZE(mx25_i2c2_resources), + .resource = mx25_i2c2_resources, +}; + +struct platform_device mx25_i2c_device2 = { + .name = "imx-i2c", + .id = 2, + .num_resources = ARRAY_SIZE(mx25_i2c3_resources), + .resource = mx25_i2c3_resources, +}; +#endif + +static struct mxc_gpio_port mx25_gpio_ports[] = { + { + .chip.label = "gpio-1", + .base = IO_ADDRESS(GPIO1_BASE_ADDR), + .irq = MXC_INT_GPIO1, + .virtual_irq_start = MXC_GPIO_IRQ_START, + }, + { + .chip.label = "gpio-2", + .base = IO_ADDRESS(GPIO2_BASE_ADDR), + .irq = MXC_INT_GPIO2, + .virtual_irq_start = MXC_GPIO_IRQ_START + 1 * 32, + }, + { + .chip.label = "gpio-3", + .base = IO_ADDRESS(GPIO3_BASE_ADDR), + .irq = MXC_INT_GPIO3, + .virtual_irq_start = MXC_GPIO_IRQ_START + 2 * 32, + }, + { + .chip.label = "gpio-4", + .base = IO_ADDRESS(GPIO4_BASE_ADDR), + .irq = MXC_INT_GPIO4, + .virtual_irq_start = MXC_GPIO_IRQ_START + 3 * 32, + }, +}; + +static inline void mx25_init_ssi(void) +{ + /* SPBA configuration for SSI - SDMA and MCU are set */ + spba_take_ownership(SPBA_SSI1, SPBA_MASTER_A | SPBA_MASTER_C); + spba_take_ownership(SPBA_SSI2, SPBA_MASTER_A | SPBA_MASTER_C); +} + +static struct platform_device mx25_dma_device = { + .name = "mxc_dma", + .id = 0, +}; + +static inline void mx25_init_dma(void) +{ + (void)platform_device_register(&mx25_dma_device); +} + +static int __init mx25_init_devices(void) +{ + mx25_init_wdt(); + mx25_init_spi(); + mx25_init_dma(); + mx25_init_ssi(); + + return 0; +} +arch_initcall(mx25_init_devices); + +int __init mxc_register_gpios(void) +{ + return mxc_gpio_init(mx25_gpio_ports, ARRAY_SIZE(mx25_gpio_ports)); +} diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/generic.c linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/generic.c --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/generic.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/generic.c 2009-06-02 17:59:16.000000000 +0200 @@ -26,6 +26,7 @@ #include /* MX27 memory map definition */ +#if defined(CONFIG_MACH_MX27) || defined(CONFIG_MACH_MX21) static struct map_desc mxc_io_desc[] __initdata = { /* * this fixed mapping covers: @@ -61,7 +62,7 @@ static struct map_desc mxc_io_desc[] __i .pfn = __phys_to_pfn(X_MEMC_BASE_ADDR), .length = X_MEMC_SIZE, .type = MT_DEVICE - } + }, }; /* @@ -82,4 +83,46 @@ void __init mx27_map_io(void) iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc)); } +#endif + +#ifdef CONFIG_MACH_MX25 +static struct map_desc mx25_io_desc[] __initdata = { + { + .virtual = (unsigned long)X_MEMC_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(X_MEMC_BASE_ADDR), + .length = X_MEMC_SIZE, + .type = MT_DEVICE + }, + { + .virtual = (unsigned long)ASIC_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(ASIC_BASE_ADDR), + .length = ASIC_SIZE, + .type = MT_DEVICE_NONSHARED + }, + { + .virtual = (unsigned long)AIPS1_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(AIPS1_BASE_ADDR), + .length = AIPS1_SIZE, + .type = MT_DEVICE_NONSHARED + }, + { + .virtual = (unsigned long)AIPS2_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(AIPS2_BASE_ADDR), + .length = AIPS2_SIZE, + .type = MT_DEVICE_NONSHARED + }, + { + .virtual = (unsigned long)SPBA0_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(SPBA0_BASE_ADDR), + .length = SPBA0_SIZE, + .type = MT_DEVICE_NONSHARED + }, +}; + +void __init mx25_map_io(void) +{ + mxc_set_cpu_type(MXC_CPU_MX25); + iotable_init(mx25_io_desc, ARRAY_SIZE(mx25_io_desc)); +} +#endif diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/karo-tx25.c linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/karo-tx25.c --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/karo-tx25.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/karo-tx25.c 2009-07-14 13:50:45.000000000 +0200 @@ -0,0 +1,981 @@ +/* + * arch/arm/mach-mx2/karo-tx25.c + * + * Copyright (C) 2008 Lothar Wassmann + * + * based on: arch/arm/mach-mx27ads.c (C) Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * + * This file adds support for the Ka-Ro electronics TX25 processor modules + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE) +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crm_regs.h" +#include "devices.h" +#include "karo.h" + +#ifdef DEBUG +int tx25_debug = 1; +module_param(tx25_debug, int, S_IRUGO | S_IWUSR); +#else +static int tx25_debug; +module_param(tx25_debug, int, 0); +#endif + +int karo_board_type = 0; +int karo_mod_type = -1; + + +static int karo_tx25_gpio_config(struct pad_desc *pd, int num) +{ + int ret; + int i; + int count = 0; + + for (i = 0; i < num; i++) { + ret = mxc_iomux_v3_setup_pad(&pd[i]); + if (ret == 0) { + DBG(0, "%s: PAD[%d] %s set up as GPIO\n", __FUNCTION__, i, + MXC_PAD_NAME(&pd[i])); + count++; + mxc_iomux_v3_release_pad(&pd[i]); + } else { + DBG(0, "%s: PAD[%d] %s skipped\n", __FUNCTION__, i, + MXC_PAD_NAME(&pd[i])); + } + } + return count; +} + +//#define FEC_MII_IRQ IRQ_GPIOD(8) + +#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE) +static struct resource fec_resources[] = { + { + .start = FEC_BASE_ADDR, + .end = FEC_BASE_ADDR + 0x18f, + .flags = IORESOURCE_MEM, + }, { + .start = FEC_BASE_ADDR + 0x200, + .end = FEC_BASE_ADDR + 0x30b, + .flags = IORESOURCE_MEM, + }, { + .start = MXC_INT_FEC, + .end = MXC_INT_FEC, + .flags = IORESOURCE_IRQ, +#ifdef FEC_MII_IRQ + }, { + .start = FEC_MII_IRQ, + .end = FEC_MII_IRQ, + .flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +#endif + }, +}; + +/* + * Setup GPIO for FEC device to be active + * + */ +static struct pad_desc karo_tx25_fec_gpios_off[] = { + MX25_PAD_FEC_MDC__GPIO_3_5, + MX25_PAD_FEC_MDIO__GPIO_3_6, + MX25_PAD_FEC_TDATA0__GPIO_3_7, + MX25_PAD_FEC_TDATA1__GPIO_3_8, + MX25_PAD_FEC_TX_EN__GPIO_3_9, + MX25_PAD_FEC_RDATA0__GPIO_3_10, + MX25_PAD_FEC_RDATA1__GPIO_3_11, + MX25_PAD_FEC_RX_DV__GPIO_3_12, + MX25_PAD_FEC_TX_CLK__GPIO_3_13, + MX25_PAD_D12__GPIO_4_8, + MX25_PAD_D10__GPIO_4_10, +}; + +static struct pad_desc karo_tx25_fec_pwr_gpios[] = { + MX25_PAD_D11__GPIO_4_9, /* FEC PHY power on pin */ + MX25_PAD_D13__GPIO_4_7, /* FEC reset */ +}; + +static struct pad_desc karo_tx25_fec_gpios_on[] = { + MX25_PAD_FEC_MDC__FEC_MDC, + MX25_PAD_FEC_MDIO__FEC_MDIO, + MX25_PAD_FEC_TDATA0__FEC_TDATA0, + MX25_PAD_FEC_TDATA1__FEC_TDATA1, + MX25_PAD_FEC_TX_EN__FEC_TX_EN, + MX25_PAD_FEC_RDATA0__FEC_RDATA0, + MX25_PAD_FEC_RDATA1__FEC_RDATA1, + MX25_PAD_FEC_RX_DV__FEC_RX_DV, + MX25_PAD_FEC_TX_CLK__FEC_TX_CLK, + MX25_PAD_D12__GPIO_4_8, + MX25_PAD_D10__GPIO_4_10, +}; + +static struct gpio_desc { + unsigned int gpio:7; + unsigned int dir:1; + unsigned int level:1; +} karo_tx25_fec_strap_gpios[] = { + /* configure the PHY strap pins to the correct values */ + { GPIO_PORTC | 5, 1, 0, }, + { GPIO_PORTC | 6, 1, 0, }, + { GPIO_PORTC | 7, 1, 0, }, + { GPIO_PORTC | 8, 1, 0, }, + { GPIO_PORTC | 9, 1, 0, }, + { GPIO_PORTC | 10, 1, 1, }, + { GPIO_PORTC | 11, 1, 1, }, + { GPIO_PORTC | 12, 0, 1, }, + { GPIO_PORTC | 13, 1, 0, }, + + { GPIO_PORTD | 8, 0, 0, }, + { GPIO_PORTD | 10, 0, 0, }, + { GPIO_PORTD | 9, 1, 1, }, + { GPIO_PORTD | 7, 1, 0, }, +}; + +#define TX25_FEC_PWR_GPIO (GPIO_PORTD | 9) +#define TX25_FEC_RST_GPIO (GPIO_PORTD | 7) + +static int gpio_fec_active(void) +{ + int ret; + int i; + +#ifdef FEC_MII_IRQ + DBG(0, "%s: Using IRQ %d (GPIO %d) for MII\n", __FUNCTION__, + FEC_MII_IRQ, irq_to_gpio(FEC_MII_IRQ)); + + set_irq_type(FEC_MII_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING); +#endif + ret = mxc_iomux_v3_setup_multiple_pads(karo_tx25_fec_pwr_gpios, + ARRAY_SIZE(karo_tx25_fec_pwr_gpios)); + if (ret) { + return ret; + } + /* + * If the PHY is already powered on, assume it has been + * correctly configured (by the boot loader) + */ + if (0 && gpio_get_value(TX25_FEC_PWR_GPIO) && + gpio_get_value(TX25_FEC_RST_GPIO)) { + ret = mxc_iomux_v3_setup_multiple_pads(karo_tx25_fec_gpios_on, + ARRAY_SIZE(karo_tx25_fec_gpios_on)); + if (ret) { + mxc_iomux_v3_release_multiple_pads(karo_tx25_fec_pwr_gpios, + ARRAY_SIZE(karo_tx25_fec_pwr_gpios)); + return ret; + } + } else { + /* switch PHY strap pins into required state */ + ret = mxc_iomux_v3_setup_multiple_pads(karo_tx25_fec_gpios_off, + ARRAY_SIZE(karo_tx25_fec_gpios_off)); + if (ret) { + mxc_iomux_v3_release_multiple_pads(karo_tx25_fec_pwr_gpios, + ARRAY_SIZE(karo_tx25_fec_pwr_gpios)); + return ret; + } + DBG(0, "%s: Switching FEC PHY power on\n", __FUNCTION__); + DBG(0, "%s: Asserting FEC PHY reset\n", __FUNCTION__); + for (i = 0; i < ARRAY_SIZE(karo_tx25_fec_strap_gpios); i++) { + struct gpio_desc *pd = &karo_tx25_fec_strap_gpios[i]; + + ret = gpio_request(pd->gpio, "FEC"); + if (ret < 0) { + DBG(0, "%s: Failed to request GPIO%d_%d: %d\n", + __FUNCTION__, pd->gpio / 32 + 1, pd->gpio % 32, ret); + goto rel_mux; + } + if (pd->dir) { + gpio_direction_output(pd->gpio, + pd->level); + } else { + gpio_direction_input(pd->gpio); + } + } +#ifdef DEBUG + for (i = 0; i < ARRAY_SIZE(karo_tx25_fec_strap_gpios); i++) { + struct gpio_desc *pd = &karo_tx25_fec_strap_gpios[i]; + int grp = pd->gpio / 32 + 1; + int ofs = pd->gpio % 32; + + if (pd->dir && pd->level != gpio_get_value(pd->gpio)) { + DBG(0, "%s: GPIO%d_%d is %d instead of %d\n", __FUNCTION__, + grp, ofs, gpio_get_value(pd->gpio), + pd->level); + } + } +#endif + DBG(0, "%s: Delaying for 22ms\n", __FUNCTION__); + mdelay(22); + DBG(0, "%s: Deasserting FEC PHY reset\n", __FUNCTION__); + gpio_set_value(TX25_FEC_RST_GPIO, 1); +#ifdef DEBUG + for (i = 0; i < ARRAY_SIZE(karo_tx25_fec_strap_gpios); i++) { + struct gpio_desc *pd = &karo_tx25_fec_strap_gpios[i]; + int grp = pd->gpio / 32 + 1; + int ofs = pd->gpio % 32; + + DBG(0, "%s: GPIO%d_%d is %d\n", __FUNCTION__, + grp, ofs, gpio_get_value(pd->gpio)); + } +#endif + mxc_iomux_v3_release_multiple_pads(karo_tx25_fec_gpios_off, + ARRAY_SIZE(karo_tx25_fec_gpios_off)); + ret = mxc_iomux_v3_setup_multiple_pads(karo_tx25_fec_gpios_on, + ARRAY_SIZE(karo_tx25_fec_gpios_on)); + if (ret) { + goto rel_gpio; + } +#ifdef DEBUG + for (i = 0; i < ARRAY_SIZE(karo_tx25_fec_strap_gpios); i++) { + struct gpio_desc *pd = &karo_tx25_fec_strap_gpios[i]; + int grp = pd->gpio / 32 + 1; + int ofs = pd->gpio % 32; + + DBG(0, "%s: GPIO%d_%d is %d\n", __FUNCTION__, + grp, ofs, gpio_get_value(pd->gpio)); + } +#endif + } + return ret; + + rel_mux: + mxc_iomux_v3_release_multiple_pads(karo_tx25_fec_gpios_off, + ARRAY_SIZE(karo_tx25_fec_gpios_off)); + rel_gpio: + while (--i >= 0) { + struct gpio_desc *pd = &karo_tx25_fec_strap_gpios[i]; + gpio_free(pd->gpio); + } + mxc_iomux_v3_release_multiple_pads(karo_tx25_fec_pwr_gpios, + ARRAY_SIZE(karo_tx25_fec_pwr_gpios)); + return ret; +} + +/* + * Setup GPIO for FEC device to be inactive + * + */ +static void gpio_fec_inactive(void) +{ + int i; + + mxc_iomux_v3_release_multiple_pads(karo_tx25_fec_gpios_on, + ARRAY_SIZE(karo_tx25_fec_gpios_on)); + mxc_iomux_v3_setup_multiple_pads(karo_tx25_fec_gpios_off, + ARRAY_SIZE(karo_tx25_fec_gpios_off)); + DBG(0, "%s: Asserting FEC PHY reset\n", __FUNCTION__); + gpio_set_value(TX25_FEC_RST_GPIO, 0); + DBG(0, "%s: Switching FEC PHY power off\n", __FUNCTION__); + gpio_set_value(TX25_FEC_PWR_GPIO, 0); + + mxc_iomux_v3_release_multiple_pads(karo_tx25_fec_gpios_off, + ARRAY_SIZE(karo_tx25_fec_gpios_off)); + mxc_iomux_v3_release_multiple_pads(karo_tx25_fec_pwr_gpios, + ARRAY_SIZE(karo_tx25_fec_pwr_gpios)); + for (i = 0; i < ARRAY_SIZE(karo_tx25_fec_strap_gpios); i++) { + struct gpio_desc *pd = &karo_tx25_fec_strap_gpios[i]; + gpio_free(pd->gpio); + } +} + +static struct clk *tx25_fec_clk; + +static int tx25_fec_suspend(struct platform_device *pdev) +{ + BUG_ON(tx25_fec_clk == NULL); + DBG(1, "%s: Switching FEC PHY off\n", __FUNCTION__); + gpio_fec_inactive(); + clk_disable(tx25_fec_clk); + return 0; +} + +static int tx25_fec_resume(struct platform_device *pdev) +{ + BUG_ON(tx25_fec_clk == NULL); + DBG(1, "%s: Switching FEC PHY on\n", __FUNCTION__); + clk_enable(tx25_fec_clk); + gpio_fec_active(); + return 0; +} + +static int fec_arch_init(struct platform_device *pdev) +{ + int ret; + + DBG(0, "%s: Activating FEC GPIOs\n", __FUNCTION__); + dump_regs(); + + ret = gpio_fec_active(); + if (ret) { + printk(KERN_ERR "%s: could not enable FEC gpios: %d\n", __FUNCTION__, ret); + return ret; + } + + BUG_ON(tx25_fec_clk != NULL); + tx25_fec_clk = clk_get(&pdev->dev, NULL); + if (unlikely(IS_ERR(tx25_fec_clk))) { + printk(KERN_ERR "Failed to get fec_clk\n"); + return PTR_ERR(tx25_fec_clk); + } + DBG(0, "%s: Enabling FEC clock\n", __FUNCTION__); + clk_enable(tx25_fec_clk); + dump_regs(); + return 0; +} + +static void fec_arch_exit(struct platform_device *pdev) +{ + BUG_ON(tx25_fec_clk == NULL); + if (unlikely(IS_ERR(tx25_fec_clk))) { + printk(KERN_ERR "Failed to get fec_clk\n"); + return; + } + DBG(0, "%s: Disabling FEC clock\n", __FUNCTION__); + clk_disable(tx25_fec_clk); + clk_put(tx25_fec_clk); + tx25_fec_clk = NULL; + DBG(0, "%s: Deactivating FEC GPIOs\n", __FUNCTION__); + gpio_fec_inactive(); +} + +static struct fec_enet_platform_data fec_data = { + .arch_init = fec_arch_init, + .arch_exit = fec_arch_exit, + .suspend = tx25_fec_suspend, + .resume = tx25_fec_resume, +}; + +static struct platform_device fec_device = { + .name = "fec", + .id = 0, + .num_resources = ARRAY_SIZE(fec_resources), + .resource = fec_resources, + .dev = { + .platform_data = &fec_data, + .coherent_dma_mask = 0xFFFFFFFF, + }, +}; +#endif + +/* MTD NAND flash */ +#if defined(CONFIG_MTD_NAND_MXC) || defined(CONFIG_MTD_NAND_MXC_MODULE) +static struct pad_desc karo_tx25_nand_pads[] = { + MX25_PAD_NF_CE0__NF_CE0, + MX25_PAD_NFWE_B__NFWE_B, + MX25_PAD_NFRE_B__NFRE_B, + MX25_PAD_NFALE__NFALE, + MX25_PAD_NFCLE__NFCLE, + MX25_PAD_NFWP_B__NFWP_B, + MX25_PAD_NFRB__NFRB, + MX25_PAD_D7__D7, + MX25_PAD_D6__D6, + MX25_PAD_D5__D5, + MX25_PAD_D4__D4, + MX25_PAD_D3__D3, + MX25_PAD_D2__D2, + MX25_PAD_D1__D1, + MX25_PAD_D0__D0, +}; + +static struct mxc_nand_platform_data tx25_nand_data = { + .hw_ecc = 1, + .width = 1, +}; + +static int tx25_nand_init(void) +{ + int ret; + + DBG(0, "%s: Configuring NAND pins\n", __FUNCTION__); + ret = mxc_iomux_v3_setup_multiple_pads(karo_tx25_nand_pads, + ARRAY_SIZE(karo_tx25_nand_pads)); + if (ret) { + return ret; + } + return 0; +} +arch_initcall(tx25_nand_init); + +static struct resource tx25_nand_resources[] = { + { + .start = NFC_BASE_ADDR + 0x1e00, + .end = NFC_BASE_ADDR + 0x1e2f, + .flags = IORESOURCE_MEM, + }, { + .start = NFC_BASE_ADDR, + .end = NFC_BASE_ADDR + 0x11ff, + .flags = IORESOURCE_MEM, + }, { + .start = MXC_INT_NANDFC, + .end = MXC_INT_NANDFC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device tx25_nand_mtd_device = { + .name = "mxc_nand", + .id = 0, + .num_resources = ARRAY_SIZE(tx25_nand_resources), + .resource = tx25_nand_resources, + .dev = { + .platform_data = &tx25_nand_data, + }, +}; +#endif + +#if defined(CONFIG_VIDEO_MXC_EMMA_OUTPUT) || defined(CONFIG_VIDEO_MXC_EMMA_OUTPUT_MODULE) +static u64 mxc_emma_dmamask = 0xffffffffUL; + +static struct platform_device tx25_v4l2out_device = { + .name = "MXC Video Output", + .id = 0, + .dev = { + .dma_mask = &mxc_emma_dmamask, + .coherent_dma_mask = ~0UL, + }, +}; +#endif + +#if 0 +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static struct pad_desc mxc_i2c0_pins[] = { + MX25_PAD_I2C1_CLK__I2C1_CLK, + MX25_PAD_I2C1_DAT__I2C1_DAT, +}; + +static int karo_tx25_i2c_0_init(struct device *dev) +{ + DBG(-1, "%s: \n", __FUNCTION__); + return mxc_iomux_v3_setup_multiple_pads(mxc_i2c0_pins, + ARRAY_SIZE(mxc_i2c0_pins)); +} + +static void karo_tx25_i2c_0_exit(struct device *dev) +{ + DBG(-1, "%s: \n", __FUNCTION__); + mxc_iomux_v3_release_multiple_pads(mxc_i2c0_pins, + ARRAY_SIZE(mxc_i2c0_pins)); +} + +static struct imxi2c_platform_data karo_tx25_i2c_0_data = { + .bitrate = 100000, + .init = karo_tx25_i2c_0_init, + .exit = karo_tx25_i2c_0_exit, +}; + +static struct at24_platform_data karo_tx25_eeprom = { + .byte_len = 2048, + .page_size = 32, + .flags = AT24_FLAG_ADDR16 | AT24_FLAG_TAKE8ADDR, +}; + +static struct i2c_board_info karo_i2c_0_boardinfo[] __initdata = { + { + I2C_BOARD_INFO("24c16", 0x50), + .platform_data = &karo_tx25_eeprom, + .type = "24c16", + }, +}; + +int __init karo_i2c_init(void) +{ + int ret; + + DBG(0, "%s: Registering I2C bus 0\n", __FUNCTION__); + ret = mxc_register_device(&mx25_i2c_device0, &karo_tx25_i2c_0_data); + if (ret != 0) { + printk(KERN_ERR "Failed to register I2C device: %d\n", ret); + return ret; + } + ret = i2c_register_board_info(0, karo_i2c_0_boardinfo, + ARRAY_SIZE(karo_i2c_0_boardinfo)); + if (ret != 0) { + printk(KERN_ERR "Failed to register I2C board info: %d\n", ret); + } + return ret; +} +device_initcall(karo_i2c_init); +#endif +#endif + +#if defined(CONFIG_TOUCHSCREEN_MXC_TSADCC) || defined(CONFIG_TOUCHSCREEN_MXC_TSADCC_MODULE) +static struct resource mxc_tsadcc_resources[] = { + { + .start = TSC_BASE_ADDR, + .end = TSC_BASE_ADDR + 0x85f, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_TSC, + .end = MXC_INT_TSC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mxc_tsadcc_pdata mxc_tsadcc_pdata = { + .pen_debounce_time = 32, + .intref = 1, + .adc_clk = 1750000, + .tsc_mode = MXC_TSC_4WIRE, + .hsyncen = 0, +}; + +static struct platform_device mxc_tsadcc_device = { + .id = 0, + .name = "mxc-tsadcc", + .num_resources = ARRAY_SIZE(mxc_tsadcc_resources), + .resource = mxc_tsadcc_resources, + .dev = { + .platform_data = &mxc_tsadcc_pdata, + }, +}; +#endif + +#if defined(CONFIG_CAN_FLEXCAN) || defined(CONFIG_CAN_FLEXCAN_MODULE) + +#ifdef CONFIG_CAN_FLEXCAN_CAN1 +static struct pad_desc tx25_flexcan1_pads[] = { + MX25_PAD_GPIO_A__CAN1_TX, + MX25_PAD_GPIO_B__CAN1_RX, +}; + +static struct resource tx25_flexcan1_resources[] = { + { + .start = CAN1_BASE_ADDR, + .end = CAN1_BASE_ADDR + 0x97f, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_CAN1, + .end = MXC_INT_CAN1, + .flags = IORESOURCE_IRQ, + }, +}; + +static int tx25_flexcan1_active(struct platform_device *pdev) +{ + return mxc_iomux_v3_setup_multiple_pads(tx25_flexcan1_pads, + ARRAY_SIZE(tx25_flexcan1_pads)); +} + +static void tx25_flexcan1_inactive(struct platform_device *pdev) +{ + mxc_iomux_v3_release_multiple_pads(tx25_flexcan1_pads, + ARRAY_SIZE(tx25_flexcan1_pads)); + karo_tx25_gpio_config(tx25_flexcan1_pads, + ARRAY_SIZE(tx25_flexcan1_pads)); +} + +static struct flexcan_platform_data tx25_flexcan1_pdata = { + //.core_reg = NULL; + //.io_reg = NULL; + //.xcvr_enable = NULL, + .active = tx25_flexcan1_active, + .inactive = tx25_flexcan1_inactive, +}; + +static struct platform_device tx25_flexcan1_device = { + .id = 0, + .name = "mxc-flexcan", + .num_resources = ARRAY_SIZE(tx25_flexcan1_resources), + .resource = tx25_flexcan1_resources, + .dev = { + .platform_data = &tx25_flexcan1_pdata, + }, +}; +#endif // CONFIG_CAN_FLEXCAN_CAN1 + +#ifdef CONFIG_CAN_FLEXCAN_CAN2 +static struct pad_desc tx25_flexcan2_pads[] = { + MX25_PAD_GPIO_C__CAN2_TX, + MX25_PAD_GPIO_D__CAN2_RX, +}; + +static struct resource tx25_flexcan2_resources[] = { + { + .start = CAN2_BASE_ADDR, + .end = CAN2_BASE_ADDR + 0x97f, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_CAN2, + .end = MXC_INT_CAN2, + .flags = IORESOURCE_IRQ, + }, +}; + +static int tx25_flexcan2_active(struct platform_device *pdev) +{ + return mxc_iomux_v3_setup_multiple_pads(tx25_flexcan2_pads, + ARRAY_SIZE(tx25_flexcan2_pads)); +} + +static void tx25_flexcan2_inactive(struct platform_device *pdev) +{ + mxc_iomux_v3_release_multiple_pads(tx25_flexcan2_pads, + ARRAY_SIZE(tx25_flexcan2_pads)); + karo_tx25_gpio_config(tx25_flexcan2_pads, + ARRAY_SIZE(tx25_flexcan2_pads)); +} + +static struct flexcan_platform_data tx25_flexcan2_pdata = { + //.core_reg = NULL; + //.io_reg = NULL; + //.xcvr_enable = NULL, + .active = tx25_flexcan2_active, + .inactive = tx25_flexcan2_inactive, +}; + +static struct platform_device tx25_flexcan2_device = { + .id = 1, + .name = "mxc-flexcan", + .num_resources = ARRAY_SIZE(tx25_flexcan2_resources), + .resource = tx25_flexcan2_resources, + .dev = { + .platform_data = &tx25_flexcan2_pdata, + }, +}; +#endif // CONFIG_CAN_FLEXCAN_CAN2 +#endif // CONFIG_CAN_FLEXCAN || CONFIG_CAN_FLEXCAN_MODULE + +struct platform_dev_list { + struct platform_device *pdev; + int flag; +} tx25_devices[] __initdata = { +#if defined(CONFIG_RTC_MXC) || defined(CONFIG_RTC_MXC_MODULE) + { .pdev = &mxc_rtc_device, .flag = -1, }, +#endif +#if defined(CONFIG_MTD_NAND_MXC) || defined(CONFIG_MTD_NAND_MXC_MODULE) + { .pdev = &tx25_nand_mtd_device, .flag = -1, }, +#endif +#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE) + { .pdev = &fec_device, .flag = -1, }, +#endif +#if defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE) + { .pdev = &mxcspi1_device, .flag = -1, }, +#endif +#if defined(CONFIG_VIDEO_MXC_EMMA_OUTPUT) || defined(CONFIG_VIDEO_MXC_EMMA_OUTPUT_MODULE) + { .pdev = &tx25_v4l2out_device, .flag = -1, }, +#endif +#if defined(CONFIG_MXC_VPU) || defined(CONFIG_MXC_VPU_MODULE) + { .pdev = &mxc_vpu_device, .flag = -1, }, +#endif +#if defined(CONFIG_TOUCHSCREEN_MXC_TSADCC) || defined(CONFIG_TOUCHSCREEN_MXC_TSADCC_MODULE) + { .pdev = &mxc_tsadcc_device, .flag = -1, }, +#endif +#ifdef CONFIG_CAN_FLEXCAN_CAN1 + { .pdev = &tx25_flexcan1_device, .flag = -1, }, +#endif +#ifdef CONFIG_CAN_FLEXCAN_CAN2 + { .pdev = &tx25_flexcan2_device, .flag = -1, }, +#endif +}; +#define TX25_NUM_DEVICES ARRAY_SIZE(tx25_devices) + +static __init void karo_tx25_board_init(void) +{ + int i; + + DBG(0, "%s: \n", __FUNCTION__); + + dump_regs(); + + for (i = 0; i < TX25_NUM_DEVICES; i++) { + int ret; + + if (tx25_devices[i].pdev == NULL) continue; + if (!tx25_devices[i].flag) { + DBG(0, "%s: Skipping platform device[%d] @ %p dev %p: %s\n", + __FUNCTION__, i, tx25_devices[i].pdev, &tx25_devices[i].pdev->dev, + tx25_devices[i].pdev->name); + continue; + } + DBG(0, "%s: Registering platform device[%d] @ %p dev %p: %s\n", + __FUNCTION__, i, tx25_devices[i].pdev, &tx25_devices[i].pdev->dev, + tx25_devices[i].pdev->name); + ret = platform_device_register(tx25_devices[i].pdev); + if (ret) { + printk(KERN_WARNING "%s: Failed to register platform_device[%d]: %s: %d\n", + __FUNCTION__, i, tx25_devices[i].pdev->name, ret); + } + } + DBG(0, "%s: Done\n", __FUNCTION__); +} + +static struct pad_desc karo_tx25_gpios[] __initdata = { + MX25_PAD_GPIO_A__GPIO_A, + MX25_PAD_GPIO_B__GPIO_B, + MX25_PAD_GPIO_C__GPIO_C, + MX25_PAD_GPIO_D__GPIO_D, + MX25_PAD_GPIO_E__GPIO_E, + MX25_PAD_GPIO_F__GPIO_F, + MX25_PAD_CSI_D7__GPIO_1_6, + MX25_PAD_CSI_D8__GPIO_1_7, + MX25_PAD_CSI_MCLK__GPIO_1_8, + MX25_PAD_CSI_VSYNC__GPIO_1_9, + MX25_PAD_CSI_HSYNC__GPIO_1_10, + MX25_PAD_CSI_PIXCLK__GPIO_1_11, + MX25_PAD_I2C1_CLK__GPIO_1_12, + MX25_PAD_I2C1_DAT__GPIO_1_13, + MX25_PAD_CSPI1_MOSI__GPIO_1_14, + MX25_PAD_CSPI1_MISO__GPIO_1_15, + MX25_PAD_CSPI1_SS0__GPIO_1_16, + MX25_PAD_CSPI1_SS1__GPIO_1_17, + MX25_PAD_CSPI1_SCLK__GPIO_1_18, + MX25_PAD_LD5__GPIO_1_19, + MX25_PAD_LD6__GPIO_1_20, + MX25_PAD_LD7__GPIO_1_21, + MX25_PAD_HSYNC__GPIO_1_22, + MX25_PAD_VSYNC__GPIO_1_23, + MX25_PAD_LSCLK__GPIO_1_24, + MX25_PAD_OE_ACD__GPIO_1_25, + MX25_PAD_PWM__GPIO_1_26, + MX25_PAD_CSI_D2__GPIO_1_27, + MX25_PAD_CSI_D3__GPIO_1_28, + MX25_PAD_CSI_D4__GPIO_1_29, + MX25_PAD_CSI_D5__GPIO_1_30, + MX25_PAD_CSI_D6__GPIO_1_31, + + MX25_PAD_A14__GPIO_2_0, + MX25_PAD_A15__GPIO_2_1, + MX25_PAD_A16__GPIO_2_2, + MX25_PAD_A17__GPIO_2_3, + MX25_PAD_A18__GPIO_2_4, + MX25_PAD_A19__GPIO_2_5, + MX25_PAD_A20__GPIO_2_6, + MX25_PAD_A21__GPIO_2_7, + MX25_PAD_A22__GPIO_2_8, + MX25_PAD_A23__GPIO_2_9, + MX25_PAD_A24__GPIO_2_10, + MX25_PAD_A25__GPIO_2_11, + MX25_PAD_EB0__GPIO_2_12, + MX25_PAD_EB1__GPIO_2_13, + MX25_PAD_OE__GPIO_2_14, + MX25_PAD_LD0__GPIO_2_15, + MX25_PAD_LD1__GPIO_2_16, + MX25_PAD_LD2__GPIO_2_17, + MX25_PAD_LD3__GPIO_2_18, + MX25_PAD_LD4__GPIO_2_19, + MX25_PAD_DE_B__GPIO_2_20, + MX25_PAD_CLKO__GPIO_2_21, + MX25_PAD_CSPI1_RDY__GPIO_2_22, + MX25_PAD_SD1_CMD__GPIO_2_23, + MX25_PAD_SD1_CLK__GPIO_2_24, + MX25_PAD_SD1_DATA0__GPIO_2_25, + MX25_PAD_SD1_DATA1__GPIO_2_26, + MX25_PAD_SD1_DATA2__GPIO_2_27, + MX25_PAD_SD1_DATA3__GPIO_2_28, + MX25_PAD_KPP_ROW0__GPIO_2_29, + MX25_PAD_KPP_ROW1__GPIO_2_30, + MX25_PAD_KPP_ROW2__GPIO_2_31, + + MX25_PAD_KPP_ROW3__GPIO_3_0, + MX25_PAD_KPP_COL0__GPIO_3_1, + MX25_PAD_KPP_COL1__GPIO_3_2, + MX25_PAD_KPP_COL2__GPIO_3_3, + MX25_PAD_KPP_COL3__GPIO_3_4, + MX25_PAD_FEC_MDC__GPIO_3_5, + MX25_PAD_FEC_MDIO__GPIO_3_6, + MX25_PAD_FEC_TDATA0__GPIO_3_7, + MX25_PAD_FEC_TDATA1__GPIO_3_8, + MX25_PAD_FEC_TX_EN__GPIO_3_9, + MX25_PAD_FEC_RDATA0__GPIO_3_10, + MX25_PAD_FEC_RDATA1__GPIO_3_11, + MX25_PAD_FEC_RX_DV__GPIO_3_12, + MX25_PAD_FEC_TX_CLK__GPIO_3_13, + MX25_PAD_RTCK__GPIO_3_14, + MX25_PAD_EXT_ARMCLK__GPIO_3_15, + MX25_PAD_UPLL_BYPCLK__GPIO_3_16, + MX25_PAD_VSTBY_REQ__GPIO_3_17, + MX25_PAD_VSTBY_ACK__GPIO_3_18, + MX25_PAD_POWER_FAIL__GPIO_3_19, + MX25_PAD_CS4__GPIO_3_20, + MX25_PAD_CS5__GPIO_3_21, + MX25_PAD_NF_CE0__GPIO_3_22, + MX25_PAD_ECB__GPIO_3_23, + MX25_PAD_LBA__GPIO_3_24, + MX25_PAD_RW__GPIO_3_25, + MX25_PAD_NFWE_B__GPIO_3_26, + MX25_PAD_NFRE_B__GPIO_3_27, + MX25_PAD_NFALE__GPIO_3_28, + MX25_PAD_NFCLE__GPIO_3_29, + MX25_PAD_NFWP_B__GPIO_3_30, + MX25_PAD_NFRB__GPIO_3_31, + + MX25_PAD_A10__GPIO_4_0, + MX25_PAD_A13__GPIO_4_1, + MX25_PAD_CS0__GPIO_4_2, + MX25_PAD_CS1__GPIO_4_3, + MX25_PAD_BCLK__GPIO_4_4, + MX25_PAD_D15__GPIO_4_5, + MX25_PAD_D14__GPIO_4_6, + MX25_PAD_D13__GPIO_4_7, + MX25_PAD_D12__GPIO_4_8, + MX25_PAD_D11__GPIO_4_9, + MX25_PAD_D10__GPIO_4_10, + MX25_PAD_D9__GPIO_4_11, + MX25_PAD_D8__GPIO_4_12, + MX25_PAD_D7__GPIO_4_13, + MX25_PAD_D6__GPIO_4_14, + MX25_PAD_D5__GPIO_4_15, + MX25_PAD_D4__GPIO_4_16, + MX25_PAD_D3__GPIO_4_17, + MX25_PAD_D2__GPIO_4_18, + MX25_PAD_D1__GPIO_4_19, + MX25_PAD_D0__GPIO_4_20, + MX25_PAD_CSI_D9__GPIO_4_21, + MX25_PAD_UART1_RXD__GPIO_4_22, + MX25_PAD_UART1_TXD__GPIO_4_23, + MX25_PAD_UART1_RTS__GPIO_4_24, + MX25_PAD_UART1_CTS__GPIO_4_25, + MX25_PAD_UART2_RXD__GPIO_4_26, + MX25_PAD_UART2_TXD__GPIO_4_27, + MX25_PAD_UART2_RTS__GPIO_4_28, + MX25_PAD_UART2_CTS__GPIO_4_29, + MX25_PAD_BOOT_MODE0__GPIO_4_30, + MX25_PAD_BOOT_MODE1__GPIO_4_31, +}; + +static int __init karo_tx25_setup_gpios(void) +{ +#if 1 + int count; + + count = karo_tx25_gpio_config(karo_tx25_gpios, ARRAY_SIZE(karo_tx25_gpios)); + DBG(0, "%s: %d out of %d pins set up as GPIO\n", __FUNCTION__, + count, ARRAY_SIZE(karo_tx25_gpios)); +#else + int i; + int ret; + int count = 0; + + for (i = 0; i < ARRAY_SIZE(karo_tx25_gpios); i++) { + struct pad_desc *pd = &karo_tx25_gpios[i]; + + ret = mxc_iomux_v3_setup_pad(pd); + if (ret == 0) { +#ifdef IOMUX_DEBUG + DBG(0, "%s: PAD[%d] %s set up as GPIO\n", __FUNCTION__, i, pd->name); +#else + DBG(0, "%s: PAD[%d] set up as GPIO\n", __FUNCTION__, i); +#endif + count++; + mxc_iomux_v3_release_pad(pd); + } else { +#ifdef IOMUX_DEBUG + DBG(0, "%s: PAD[%d] %s skipped\n", __FUNCTION__, i, pd->name); +#else + DBG(0, "%s: PAD[%d] skipped\n", __FUNCTION__, i); +#endif + } + } + DBG(0, "%s: %d out of %d pins set up as GPIO\n", __FUNCTION__, count, i); +#endif + return 0; +} +late_initcall(karo_tx25_setup_gpios); + +static void __init karo_tx25_map_io(void) +{ + mx25_map_io(); +} + +static void __init karo_tx25_fixup(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ +} + +static void __init karo_tx25_timer_init(void) +{ + DBG(0, "%s: \n", __FUNCTION__); + mx25_clocks_init(24000000); + DBG(0, "%s: Done\n", __FUNCTION__); +} + +struct sys_timer karo_tx25_timer = { + .init = karo_tx25_timer_init, +}; + +static int __init karo_mod_type_setup(char *line) +{ + get_option(&line, &karo_mod_type); + DBG(0, "%s: Module type set to 0x%02x by kernel cmd line\n", __FUNCTION__, karo_mod_type); + + return 1; +} +__setup("module_type=", karo_mod_type_setup); + +static int __init karo_board_type_setup(char *line) +{ + get_option(&line, &karo_board_type); + DBG(0, "%s: Board type set to 0x%02x by kernel cmd line\n", __FUNCTION__, karo_board_type); + + return 1; +} +__setup("board_type=", karo_board_type_setup); + +MACHINE_START(TX25, "Ka-Ro electronics TX25 module (Freescale i.MX25)") + /* Maintainer: */ + .phys_io = AIPS1_BASE_ADDR, + .io_pg_offst = ((unsigned long)AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc, + .fixup = karo_tx25_fixup, + .map_io = karo_tx25_map_io, + .init_irq = mxc_init_irq, + .init_machine = karo_tx25_board_init, + .timer = &karo_tx25_timer, +MACHINE_END diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/karo.h linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/karo.h --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/karo.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/karo.h 2009-06-02 17:59:18.000000000 +0200 @@ -0,0 +1,99 @@ +/* + * arch/arm/mach-mx2/karo.h + * + * Copyright (C) 2009 Lothar Wassmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * + * This file provides platform specific definitions for the + * Ka-Ro electronics TX25 processor modules + */ + +#include +#include "crm_regs_mx25.h" + +enum { + BOARD_KARO_STK5, +}; + +extern int karo_board_type; +extern int karo_mod_type; + +#ifdef DEBUG +extern int tx25_debug; +#define dbg_lvl(n) ((n) < tx25_debug) +#define DBG(lvl, fmt...) do { if (dbg_lvl(lvl)) printk(KERN_DEBUG fmt); } while (0) +#else +#define dbg_lvl(n) 0 +#define DBG(lvl, fmt...) do { } while (0) +#endif + +static inline int karo_get_board_type(void) +{ + return karo_board_type; +} + +static inline int karo_get_module_type(void) +{ + return karo_mod_type; +} + +#define SHOW_REG(reg) DBG(0, "%s[%08lx]=%08x\n", #reg, MXC_PHYS_ADDRESS(reg), __raw_readl(reg)) + +#define SHOW_GPIO_REG(port, reg) \ + DBG(0, "GPIO%d_%s[%08lx]=%08x\n", port, #reg, \ + GPIO_BASE_ADDR(port) + GPIO_##reg, \ + __raw_readl(IO_ADDRESS(GPIO_BASE_ADDR(port) + GPIO_##reg))) + +static inline void dump_regs(void) +{ + int i; + + SHOW_REG(MXC_CCM_MPCTL); + SHOW_REG(MXC_CCM_UPCTL); + SHOW_REG(MXC_CCM_CCTL); + SHOW_REG(MXC_CCM_RCSR); + SHOW_REG(MXC_CCM_CRDR); + SHOW_REG(MXC_CCM_PCDR0); + SHOW_REG(MXC_CCM_PCDR1); + SHOW_REG(MXC_CCM_PCDR2); + SHOW_REG(MXC_CCM_PCDR3); + SHOW_REG(MXC_CCM_CGCR0); + SHOW_REG(MXC_CCM_CGCR1); + SHOW_REG(MXC_CCM_CGCR2); + SHOW_REG(MXC_CCM_MCR); + SHOW_REG(MXC_CCM_PMCR0); + SHOW_REG(MXC_CCM_PMCR1); + SHOW_REG(MXC_CCM_PMCR2); + SHOW_REG(MXC_CCM_LTBR0); + SHOW_REG(MXC_CCM_LTBR1); + SHOW_REG(MXC_CCM_LTR0); + SHOW_REG(MXC_CCM_LTR1); + SHOW_REG(MXC_CCM_LTR2); + SHOW_REG(MXC_CCM_LTR3); + SHOW_REG(MXC_CCM_DCVR0); + SHOW_REG(MXC_CCM_DCVR1); + SHOW_REG(MXC_CCM_DCVR2); + SHOW_REG(MXC_CCM_DCVR3); + + for (i = 1; i <= 4; i++) { + SHOW_GPIO_REG(i, DR); + SHOW_GPIO_REG(i, GDIR); + SHOW_GPIO_REG(i, PSR); + SHOW_GPIO_REG(i, ICR1); + SHOW_GPIO_REG(i, ICR2); + SHOW_GPIO_REG(i, IMR); + SHOW_GPIO_REG(i, ISR); + } +} diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/sdma_script_code.h linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/sdma_script_code.h --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/sdma_script_code.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/sdma_script_code.h 2009-06-02 17:59:18.000000000 +0200 @@ -0,0 +1,159 @@ + +/* + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 + */ + +/*! + * @file sdma_script_code.h + * @brief This file contains functions of SDMA scripts code initialization + * + * The file was generated automatically. Based on sdma scripts library. + * + * @ingroup SDMA + */ +/************************************************************************ + + SDMA RELEASE LABEL: "SS15_SENNA" + +************************************************************************/ + +#ifndef SDMA_SCRIPT_CODE_H +#define SDMA_SCRIPT_CODE_H + +/*! + * SDMA ROM scripts start addresses and sizes + */ +#define start_ADDR 0 +#define start_SIZE 22 + +#define core_ADDR 80 +#define core_SIZE 233 + +#define common_ADDR 313 +#define common_SIZE 416 + +#define ap_2_ap_ADDR 729 +#define ap_2_ap_SIZE 41 + +#define app_2_mcu_ADDR 770 +#define app_2_mcu_SIZE 64 + +#define mcu_2_app_ADDR 834 +#define mcu_2_app_SIZE 70 + +#define uart_2_mcu_ADDR 904 +#define uart_2_mcu_SIZE 75 + +#define shp_2_mcu_ADDR 979 +#define shp_2_mcu_SIZE 69 + +#define mcu_2_shp_ADDR 1048 +#define mcu_2_shp_SIZE 72 + +#define uartsh_2_mcu_ADDR 1120 +#define uartsh_2_mcu_SIZE 69 + +#define app_2_per_ADDR 1189 +#define app_2_per_SIZE 66 + +#define per_2_app_ADDR 1255 +#define per_2_app_SIZE 74 + +#define per_2_shp_ADDR 1329 +#define per_2_shp_SIZE 78 + +#define shp_2_per_ADDR 1407 +#define shp_2_per_SIZE 72 + +#define mcu_2_ata_ADDR 1479 +#define mcu_2_ata_SIZE 81 + +#define ata_2_mcu_ADDR 1560 +#define ata_2_mcu_SIZE 96 + +#define loop_DMAs_routines_ADDR 1656 +#define loop_DMAs_routines_SIZE 227 + +#define test_ADDR 1883 +#define test_SIZE 63 + +#define signature_ADDR 1022 +#define signature_SIZE 1 + +/*! + * SDMA RAM scripts start addresses and sizes + */ +#define ext_mem__ipu_ram_ADDR 6144 +#define ext_mem__ipu_ram_SIZE 123 + +#define uart_2_per_ADDR 6267 +#define uart_2_per_SIZE 73 + +#define uartsh_2_per_ADDR 6340 +#define uartsh_2_per_SIZE 67 + +/*! + * SDMA RAM image start address and size + */ +#define RAM_CODE_START_ADDR 6144 +#define RAM_CODE_SIZE 263 + +/*! + * Buffer that holds the SDMA RAM image + */ +__attribute__ ((__aligned__(4))) +#ifndef CONFIG_XIP_KERNEL +const +#endif +static const short sdma_code[] = { + 0x0e70, 0x0611, 0x5616, 0xc18a, 0x7d2a, 0x5ade, 0x008e, 0xc19c, + 0x7c26, 0x5be0, 0x5ef0, 0x5ce8, 0x0688, 0x08ff, 0x0011, 0x28ff, + 0x00bc, 0x53f6, 0x05df, 0x7d0b, 0x6dc5, 0x03df, 0x7d03, 0x6bd5, + 0xd84f, 0x982b, 0x6b05, 0xc6d8, 0x7e27, 0x7f29, 0x982b, 0x6d01, + 0x03df, 0x7d05, 0x6bd5, 0xc702, 0x7e18, 0x7f1a, 0x982b, 0x6b05, + 0xc678, 0x7e07, 0x7f06, 0x52de, 0x53e6, 0xc1a8, 0x7dd7, 0x0200, + 0x9803, 0x0007, 0x6004, 0x680c, 0x53f6, 0x028e, 0x00a3, 0xc2ad, + 0x048b, 0x0498, 0x0454, 0x068a, 0x982b, 0x0207, 0x680c, 0x6ddf, + 0x0107, 0x68ff, 0x60d0, 0x9834, 0x0207, 0x68ff, 0x6d28, 0x0107, + 0x6004, 0x680c, 0x9834, 0x0007, 0x68ff, 0x60d0, 0x9834, 0x0288, + 0x03a5, 0x3b03, 0x3d03, 0x4d00, 0x7d0a, 0x0804, 0x00a5, 0x00da, + 0x7d1a, 0x02a0, 0x7b01, 0x65d8, 0x7eee, 0x65ff, 0x7eec, 0x0804, + 0x02d0, 0x7d11, 0x4b00, 0x7c0f, 0x008a, 0x3003, 0x6dcf, 0x6bdf, + 0x0015, 0x0015, 0x7b02, 0x65d8, 0x0000, 0x7edd, 0x63ff, 0x7edb, + 0x3a03, 0x6dcd, 0x6bdd, 0x008a, 0x7b02, 0x65d8, 0x0000, 0x7ed3, + 0x65ff, 0x7ed1, 0x0006, 0xc23a, 0x57db, 0x52f3, 0x6ad5, 0x56fb, + 0x028e, 0x1a94, 0x6ac3, 0x62c8, 0x0269, 0x7d1e, 0x1e94, 0x6ee3, + 0x62d0, 0x5aeb, 0x62c8, 0x0248, 0x6ed3, 0x6ac8, 0x2694, 0x52eb, + 0x6ad5, 0x6ee3, 0x62c8, 0x026e, 0x7d27, 0x6ac8, 0x7f23, 0x2501, + 0x4d00, 0x7d26, 0x028e, 0x1a98, 0x6ac3, 0x62c8, 0x6ec3, 0x0260, + 0x7df1, 0x62d0, 0xc2d1, 0x98c0, 0x6ee3, 0x008f, 0x2001, 0x00d5, + 0x7d01, 0x008d, 0x05a0, 0x62c8, 0x026e, 0x7d0e, 0x6ac8, 0x7f0a, + 0x2001, 0x7cf9, 0x6add, 0x7f06, 0x0000, 0x4d00, 0x7d09, 0xc251, + 0x57db, 0x987f, 0x0007, 0x6aff, 0x62d0, 0xc2d1, 0x0458, 0x0454, + 0x6add, 0x7ff8, 0xc261, 0x987c, 0xc230, 0xc23a, 0x57db, 0x52f3, + 0x6ad5, 0x56fb, 0x028e, 0x1a94, 0x5202, 0x0269, 0x7d17, 0x1e94, + 0x5206, 0x0248, 0x5a06, 0x2694, 0x5206, 0x026e, 0x7d26, 0x6ac8, + 0x7f22, 0x2501, 0x4d00, 0x7d27, 0x028e, 0x1a98, 0x5202, 0x0260, + 0x7df3, 0x6add, 0x7f18, 0x62d0, 0xc2d1, 0x9903, 0x008f, 0x2001, + 0x00d5, 0x7d01, 0x008d, 0x05a0, 0x5206, 0x026e, 0x7d0e, 0x6ac8, + 0x7f0a, 0x2001, 0x7cf9, 0x6add, 0x7f06, 0x0000, 0x4d00, 0x7d0b, + 0xc251, 0x57db, 0x98c9, 0x0007, 0x6aff, 0x6add, 0x7ffc, 0x62d0, + 0xc2d1, 0x0458, 0x0454, 0x6add, 0x7ff6, 0xc261, 0x98c6 +}; +#endif diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx2/stk5-baseboard.c linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/stk5-baseboard.c --- linux-2.6.30-rc4-git/arch/arm/mach-mx2/stk5-baseboard.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx2/stk5-baseboard.c 2009-07-14 13:51:43.000000000 +0200 @@ -0,0 +1,1187 @@ +/* + * arch/arm/mach-mx2/stk5-baseboard.c + * + * Copyright (C) 2009 Lothar Wassmann + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * + * This file adds support for devices found on Ka-Ro electronics + * Starterkit-5 (STK5) baseboard + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include + +#include "crm_regs.h" +#include "devices.h" +#include "karo.h" + +#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE) +static struct pad_desc stk5_uart_pads[][4] = { + { + MX25_PAD_UART1_TXD__UART1_TXD, + MX25_PAD_UART1_RXD__UART1_RXD, + MX25_PAD_UART1_CTS__UART1_CTS, + MX25_PAD_UART1_RTS__UART1_RTS, + }, { + MX25_PAD_UART2_TXD__UART2_TXD, + MX25_PAD_UART2_RXD__UART2_RXD, + MX25_PAD_UART2_CTS__UART2_CTS, + MX25_PAD_UART2_RTS__UART2_RTS, + }, { + MX25_PAD_ECB__UART5_TXD_MUX, + MX25_PAD_LBA__UART5_RXD_MUX, + MX25_PAD_CS4__UART5_CTS, + MX25_PAD_CS5__UART5_RTS, +#if 0 + }, { + MX25_PAD_UART4_TXD__UART4_TXD, + MX25_PAD_UART4_RXD__UART4_RXD, + MX25_PAD_UART4_CTS__UART4_CTS, + MX25_PAD_UART4_RTS__UART4_RTS, + }, { + MX25_PAD_UART5_TXD__UART5_TXD, + MX25_PAD_UART5_RXD__UART5_RXD, + MX25_PAD_UART5_CTS__UART5_CTS, + MX25_PAD_UART5_RTS__UART5_RTS, +#endif + }, +}; + +static int stk5_uart_init(struct platform_device *pdev) +{ + DBG(0, "%s: \n", __FUNCTION__); + return mxc_iomux_v3_setup_multiple_pads(stk5_uart_pads[pdev->id], + ARRAY_SIZE(stk5_uart_pads[pdev->id])); +} + +static void stk5_uart_exit(struct platform_device *pdev) +{ + DBG(0, "%s: \n", __FUNCTION__); + mxc_iomux_v3_release_multiple_pads(stk5_uart_pads[pdev->id], + ARRAY_SIZE(stk5_uart_pads[pdev->id])); +} + +static struct imxuart_platform_data stk5_uart_ports[] = { + { + .init = stk5_uart_init, + .exit = stk5_uart_exit, + .flags = IMXUART_HAVE_RTSCTS, + }, { + .init = stk5_uart_init, + .exit = stk5_uart_exit, + .flags = IMXUART_HAVE_RTSCTS, + }, { + .init = stk5_uart_init, + .exit = stk5_uart_exit, + .flags = IMXUART_HAVE_RTSCTS, + }, { + .init = stk5_uart_init, + .exit = stk5_uart_exit, + .flags = IMXUART_HAVE_RTSCTS, + }, { + .init = stk5_uart_init, + .exit = stk5_uart_exit, + .flags = IMXUART_HAVE_RTSCTS, + }, { + .init = stk5_uart_init, + .exit = stk5_uart_exit, + .flags = IMXUART_HAVE_RTSCTS, + }, +}; + +#ifdef CONFIG_USB_EHCI_MXC + +/* USB register offsets */ +#define REG_USBCTRL 0x600 +#define REG_PHY_CTRL 0x608 + +#define PHY_CTRL_USBEN (1 << 24) + +/* USB Host/OTG register offsets */ +#define REG_USBCMD 0x140 +#define REG_USBSTS 0x144 +#define REG_PORTSC1 0x184 +#define REG_USBMODE 0x1a8 + +#define USBCMD_RST (1 << 1) +#define USBCMD_RUN (1 << 0) + +#define USBSTS_HCH (1 << 12) + +/* USB_CTRL register bits */ +#define USBCTRL_OCPOL_HST (1 << 2) +#define USBCTRL_OCPOL_OTG (1 << 3) +#define USBCTRL_USBTE (1 << 4) +#define USBCTRL_HSDT (1 << 5) +#define USBCTRL_PUE_DWN (1 << 6) +#define USBCTRL_XCSH (1 << 9) +#define USBCTRL_XCSO (1 << 10) +#define USBCTRL_PP_OTG (1 << 11) +#define USBCTRL_HLKEN (1 << 12) +#define USBCTRL_OLKEN (1 << 13) +#define USBCTRL_HPM (1 << 16) +#define USBCTRL_PP_HST (1 << 18) +#define USBCTRL_HWIE (1 << 19) +#define USBCTRL_HUIE (1 << 20) +#define USBCTRL_OPM (1 << 24) +#define USBCTRL_OEXTEN (1 << 25) +#define USBCTRL_HEXTEN (1 << 26) +#define USBCTRL_OWIE (1 << 27) +#define USBCTRL_OUIE (1 << 28) + +#ifdef DEBUG +#define usb_reg_write(v,b,r) _usb_reg_write(v,b,r,#r) +static inline void _usb_reg_write(unsigned long val, void __iomem *base, int reg, + const char *name) +{ + DBG(0, "%s: Writing %08lx to %s[%03x]\n", __FUNCTION__, val, name, reg); + __raw_writel(val, base + reg); +} + +#define usb_reg_read(b,r) _usb_reg_read(b,r,#r) +static inline unsigned long _usb_reg_read(void __iomem *base, int reg, const char *name) +{ + unsigned long val; + + val = __raw_readl(base + reg); + DBG(0, "%s: Read %08lx from %s[%03x]\n", __FUNCTION__, val, name, reg); + return val; +} +#else +static inline void usb_reg_write(unsigned long val, void __iomem *base, int reg) +{ + __raw_writel(val, base + reg); +} + +static inline unsigned long usb_reg_read(void __iomem *base, int reg) +{ + return __raw_readl(base + reg); +} +#endif + +static int tx25_usb_init(struct platform_device *pdev, void __iomem *base, int host_mode) +{ + unsigned long val; + unsigned long flags; + const char __maybe_unused *name = pdev->id ? "USBH2" : "USBOTG"; + unsigned int loops = 0; + void __iomem *otg_base = IO_ADDRESS(OTG_BASE_ADDR); + int ll = console_loglevel; + + console_loglevel = 8; + + if (!(usb_reg_read(base, REG_USBSTS) & USBSTS_HCH)) { + unsigned int loops = 0; + + DBG(0, "%s: %s[%p] is busy: %08lx\n", __FUNCTION__, name, + base + REG_USBSTS, usb_reg_read(base, REG_USBSTS)); + usb_reg_write(usb_reg_read(base, REG_USBCTRL) & ~USBCMD_RUN, + base, REG_USBCTRL); + while (usb_reg_read(base, REG_USBCTRL) & USBCMD_RUN) { + usb_reg_write(usb_reg_read(base, REG_USBCTRL) & ~USBCMD_RUN, + base, REG_USBCTRL); + cpu_relax(); + loops++; + if (loops > 100) + break; + } + if (usb_reg_read(base, REG_USBSTS) & USBSTS_HCH) { + DBG(0, "USB controller idle after %u loops\n", loops); + } else { + DBG(0, "USB controller NOT idle after %u loops\n", loops); + } + } + DBG(0, "%s: PHY_CTRL[%p]=%08lx\n", __FUNCTION__, otg_base + REG_PHY_CTRL, + usb_reg_read(otg_base, REG_PHY_CTRL)); + DBG(0, "%s: USBCMD[%p]=%08lx\n", __FUNCTION__, base + REG_USBCMD, + usb_reg_read(base, REG_USBCMD)); + DBG(0, "%s: USBSTS[%p]=%08lx\n", __FUNCTION__, base + REG_USBSTS, + usb_reg_read(base, REG_USBSTS)); + + /* reset USB Host controller */ + usb_reg_write(USBCMD_RST, base, REG_USBCMD); + while (usb_reg_read(base, REG_USBCMD) & USBCMD_RST) { + cpu_relax(); + loops++; + } + DBG(0, "USB controller reset finished after %u loops\n", loops); + + /* Switch to Host mode */ + val = usb_reg_read(base, REG_USBMODE); + DBG(0, "%s: Changing %s_USBMODE from %08lx to %08lx\n", __FUNCTION__, name, + val, val | (host_mode ? 0x3 : 0x02)); + usb_reg_write(val | (host_mode ? 0x3 : 0x02), base, REG_USBMODE); + + local_irq_save(flags); + val = usb_reg_read(otg_base, REG_USBCTRL); + if (pdev->id == 1) { + val &= ~(USBCTRL_OCPOL_HST | USBCTRL_HPM | + USBCTRL_HEXTEN | USBCTRL_HWIE); + val |= USBCTRL_PP_HST | USBCTRL_HSDT | USBCTRL_USBTE | + USBCTRL_XCSH | USBCTRL_PUE_DWN; + } else { + val &= ~(USBCTRL_OCPOL_OTG | USBCTRL_OPM | + USBCTRL_OEXTEN | USBCTRL_OWIE); + val |= USBCTRL_PP_OTG | USBCTRL_XCSO; + } + DBG(0, "%s: Changing %s_USBCTRL from %08lx to %08lx\n", __FUNCTION__, name, + usb_reg_read(otg_base, REG_USBCTRL), val); + usb_reg_write(val, otg_base, REG_USBCTRL); + local_irq_restore(flags); + + val = usb_reg_read(base, REG_PORTSC1); + if (pdev->id == 1) { + /* select serial transceiver */ + val = (val & ~(3 << 30)) | (3 << 30); + } else { + /* select UTMI transceiver */ + val = (val & ~((3 << 30) | (0 << 28))) | (0 << 30); + } + DBG(0, "%s: Changing %s_PORTSC1 from %08lx to %08lx\n", __FUNCTION__, name, + usb_reg_read(base, REG_PORTSC1), val); + usb_reg_write(val, base, REG_PORTSC1); + + console_loglevel = ll; + return 0; +} + +#ifdef CONFIG_ARCH_MXC_EHCI_USBH2 +/* + * The USB power switch (MAX893L) used on the STK5 base board + * produces a pulse (~100us) on the OC output whenever + * the ON input is activated. This disturbs the USB controller. + * As a workaround don't use USB power switching. + * If you have a hardware that works cleanly you may + * #define USE_USB_PWR to enable port power control for + * the EHCI controller. + */ +static struct pad_desc karo_tx25_usbh2_pads[] = { +#ifdef USE_USB_PWR + MX25_PAD_D9__USBH2_PWR, +#endif + MX25_PAD_D8__USBH2_OC, +}; + +static int tx25_usbh2_init(struct platform_device *pdev) +{ + int ret; + void __iomem *base = IO_ADDRESS(OTG_BASE_ADDR + 0x400); +#ifndef USE_USB_PWR + const int pwr_gpio = 3 * 32 + 11; +#endif + ret = mxc_iomux_v3_setup_multiple_pads(karo_tx25_usbh2_pads, + ARRAY_SIZE(karo_tx25_usbh2_pads)); +#ifdef USE_USB_PWR + if (ret) { + return ret; + } +#else + ret = gpio_request(pwr_gpio, "USBH2_PWR"); + if (ret) { + DBG(0, "%s: Failed to request GPIO %d\n", __FUNCTION__, + pwr_gpio); + mxc_iomux_v3_release_multiple_pads(karo_tx25_usbh2_pads, + ARRAY_SIZE(karo_tx25_usbh2_pads)); + return ret; + } + + gpio_direction_output(pwr_gpio, 1); +#endif + if (ret != 0) { + mxc_iomux_v3_release_multiple_pads(karo_tx25_usbh2_pads, + ARRAY_SIZE(karo_tx25_usbh2_pads)); + goto exit; + } + ret = tx25_usb_init(pdev, base, 1); + + exit: +#ifndef USE_USB_PWR + gpio_free(pwr_gpio); +#endif + return ret; +} + +static int tx25_usbh2_exit(struct platform_device *pdev) +{ + mxc_iomux_v3_release_multiple_pads(karo_tx25_usbh2_pads, + ARRAY_SIZE(karo_tx25_usbh2_pads)); + return 0; +} + +static struct mxc_usbh_platform_data tx25_usbh2_data = { + .init = tx25_usbh2_init, + .exit = tx25_usbh2_exit, +}; + +int tx25_usbh2_register(void) +{ + int ret; + + ret = mxc_register_device(&mxc_usbh2_device, &tx25_usbh2_data); + return ret; +} +device_initcall(tx25_usbh2_register); +#endif // CONFIG_ARCH_MXC_EHCI_USBH2 + +#ifdef CONFIG_ARCH_MXC_EHCI_USBOTG +static struct pad_desc karo_tx25_usbotg_pads[] = { +#ifdef USE_USB_PWR + MX25_PAD_GPIO_A__USBOTG_PWR, +#endif + MX25_PAD_GPIO_B__USBOTG_OC, +}; + +static int tx25_usbotg_init(struct platform_device *pdev) +{ + int ret; + void __iomem *base = IO_ADDRESS(OTG_BASE_ADDR + 0x000); +#ifndef USE_USB_PWR + const int pwr_gpio = 0 * 32 + 0; +#endif + DBG(0, "%s: \n", __FUNCTION__); + + ret = mxc_iomux_v3_setup_multiple_pads(karo_tx25_usbotg_pads, + ARRAY_SIZE(karo_tx25_usbotg_pads)); +#ifdef USE_USB_PWR + if (ret) { + return ret; + } +#else + ret = gpio_request(pwr_gpio, "USBOTG_PWR"); + if (ret) { + DBG(0, "%s: Failed to request GPIO %d\n", __FUNCTION__, + pwr_gpio); + mxc_iomux_v3_release_multiple_pads(karo_tx25_usbh2_pads, + ARRAY_SIZE(karo_tx25_usbh2_pads)); + return ret; + } + + gpio_direction_output(pwr_gpio, 1); +#endif + if (ret != 0) { + mxc_iomux_v3_release_multiple_pads(karo_tx25_usbotg_pads, + ARRAY_SIZE(karo_tx25_usbotg_pads)); + goto exit; + } + ret = tx25_usb_init(pdev, base, 1); + + exit: +#ifndef USE_USB_PWR + gpio_free(pwr_gpio); +#endif + return ret; +} + +static int tx25_usbotg_exit(struct platform_device *pdev) +{ + mxc_iomux_v3_release_multiple_pads(karo_tx25_usbotg_pads, + ARRAY_SIZE(karo_tx25_usbotg_pads)); + return 0; +} + +static struct mxc_usbh_platform_data tx25_usbotg_data = { + .init = tx25_usbotg_init, + .exit = tx25_usbotg_exit, +}; + +int tx25_usbotg_register(void) +{ + int ret; + + ret = mxc_register_device(&mxc_usbotg_device, &tx25_usbotg_data); + return ret; +} +device_initcall(tx25_usbotg_register); +#endif // CONFIG_ARCH_MXC_EHCI_USBOTG +#endif // CONFIG_USB_EHCI_MXC + +static struct platform_device *stk5_uart_devices[] = { +#if UART1_ENABLED + &mxc_uart_device0, +#endif +#if UART2_ENABLED + &mxc_uart_device1, +#endif +#if UART3_ENABLED + &mxc_uart_device2, +#endif +#if UART4_ENABLED + &mxc_uart_device3, +#endif +#if UART5_ENABLED + &mxc_uart_device4, +#endif +}; + +static void __init karo_stk5_serial_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(stk5_uart_devices); i++) { + int ret; + int port = stk5_uart_devices[i]->id; + + DBG(0, "%s: Registering platform device[%d] @ %p dev %p: %s\n", + __FUNCTION__, i, stk5_uart_devices[i], + &stk5_uart_devices[i]->dev, stk5_uart_devices[i]->name); + ret = mxc_register_device(stk5_uart_devices[i], + &stk5_uart_ports[port]); + if (ret != 0) { + printk(KERN_WARNING "%s: Failed to register platform_device[%d]: %s: %d\n", + __FUNCTION__, i, stk5_uart_devices[i]->name, ret); + } + } +} +#else +static void __init karo_stk5_serial_init(void) +{ +} +#endif + +#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE) +static struct gpio_led stk5_leds[] = { + { + .name = "GPIO-LED", + .default_trigger = "heartbeat", + .gpio = GPIO_PORTB | 7, + }, +}; + +static struct gpio_led_platform_data stk5_led_data = { + .leds = stk5_leds, + .num_leds = ARRAY_SIZE(stk5_leds), +}; + +static struct platform_device stk5_led_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &stk5_led_data, + }, +}; +#endif + +#if defined(CONFIG_KEYBOARD_MXC) || defined(CONFIG_KEYBOARD_MXC_MODULE) +/*! + * This array is used for mapping mx25 ADS keypad scancodes to input keyboard + * keycodes. + */ +static u16 stk5_kpd_keycodes[] = { + KEY_POWER, +}; + +static struct keypad_data stk5_keypad = { + .rowmax = 1, + .colmax = 1, + .irq = MXC_INT_KPP, + .learning = 0, + //.delay = 2, /* unused in the driver! */ + .matrix = stk5_kpd_keycodes, +}; + +static struct resource stk5_kpp_resources[] = { + { + .start = MXC_INT_KPP, + .end = MXC_INT_KPP, + .flags = IORESOURCE_IRQ, + }, +}; + +/* stk5 keypad driver */ +static struct platform_device stk5_keypad_device = { + .name = "mxc_keypad", + .id = 0, + .num_resources = ARRAY_SIZE(stk5_kpp_resources), + .resource = stk5_kpp_resources, + .dev = { + .platform_data = &stk5_keypad, + }, +}; +#endif + +#if defined(CONFIG_FB_IMX) || defined(CONFIG_FB_IMX_MODULE) +/* + * Setup GPIO for LCDC device to be active + * + */ +static struct pad_desc mx25_lcdc_gpios[] = { +#if 0 + MXC_PIN(A, 30, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA30 */ + MXC_PIN(A, 25, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA25 */ + MXC_PIN(A, 26, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA26 */ + MXC_PIN(A, 24, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA24 */ + MXC_PIN(A, 27, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA27 */ +#endif + MX25_PAD_LSCLK__LSCLK, + MX25_PAD_LD0__LD0, + MX25_PAD_LD1__LD1, + MX25_PAD_LD2__LD2, + MX25_PAD_LD3__LD3, + MX25_PAD_LD4__LD4, + MX25_PAD_LD5__LD5, + MX25_PAD_LD6__LD6, + MX25_PAD_LD7__LD7, + MX25_PAD_LD8__LD8, + MX25_PAD_LD9__LD9, + MX25_PAD_LD10__LD10, + MX25_PAD_LD11__LD11, + MX25_PAD_LD12__LD12, + MX25_PAD_LD13__LD13, + MX25_PAD_LD14__LD14, + MX25_PAD_LD15__LD15, + MX25_PAD_D15__LD16, + MX25_PAD_D14__LD17, + MX25_PAD_HSYNC__HSYNC, + MX25_PAD_VSYNC__VSYNC, + MX25_PAD_OE_ACD__OE_ACD, +}; + +static int stk5_gpio_lcdc_active(struct platform_device *dev) +{ + int ret; + + DBG(0, "%s: Setting up GPIO pins for LCD\n", __FUNCTION__); + ret = mxc_iomux_v3_setup_multiple_pads(mx25_lcdc_gpios, + ARRAY_SIZE(mx25_lcdc_gpios)); + if (ret) { + DBG(0, "%s: Failed to setup GPIO pins for LCD: %d\n", + __FUNCTION__, ret); + return ret; + } + return 0; +} + +/* + * Setup GPIO for LCDC device to be inactive + * + */ +static void stk5_gpio_lcdc_inactive(struct platform_device *dev) +{ + mxc_iomux_v3_release_multiple_pads(mx25_lcdc_gpios, + ARRAY_SIZE(mx25_lcdc_gpios)); +} + +static struct imx_fb_platform_data stk5_fb_data[] __initdata = { + { +#if 1 + //.fb_mode = "Xenarc_700_Y-18", + .init = stk5_gpio_lcdc_active, + .exit = stk5_gpio_lcdc_inactive, + .lcd_power = NULL, + .backlight_power = NULL, + + .pixclock = 45833, + + .xres = 640, + .yres = 480, + + .bpp = 8, + + .hsync_len = 64, + .right_margin = 28 + 1, + .left_margin = 20 + 3, + + .vsync_len = 1, + .lower_margin = 0, + .upper_margin = 16, + + .pcr = PCR_TFT | PCR_COLOR | PCR_END_BYTE_SWAP | + PCR_BPIX_8 | PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL, + .dmacr = 0x80040060, + + .cmap_greyscale = 0, + .cmap_inverse = 0, + .cmap_static = 0, + + .fixed_screen_cpu = NULL, + }, { +#endif + //.fb_mode = "Xenarc_700_Y-18", + .init = stk5_gpio_lcdc_active, + .exit = stk5_gpio_lcdc_inactive, + .lcd_power = NULL, + .backlight_power = NULL, +#if 1 + .pixclock = 34576, +#else + .pixclock = 38033, +#endif + .xres = 640, + .yres = 480, + + .bpp = 32, +#if 1 + .hsync_len = 64, + .right_margin = 60 + 1, + .left_margin = 80 + 3, +#else + .hsync_len = 64, + .right_margin = 79 + 1, + .left_margin = 57 + 3, +#endif +#if 1 + .vsync_len = 2, + .lower_margin = 54, + .upper_margin = 54, +#else + .vsync_len = 4, + .lower_margin = 54, + .upper_margin = 54, +#endif +#if 0 + /* currently not used by driver! */ + .sync = ((0*FB_SYNC_HOR_HIGH_ACT) | + (0*FB_SYNC_VERT_HIGH_ACT) | + (1*FB_SYNC_OE_ACT_HIGH)), +#else + .pcr = PCR_TFT | PCR_COLOR | PCR_PBSIZ_8 | + PCR_BPIX_18 | PCR_END_SEL | PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL, + .dmacr = 0x80040060, +#endif + .cmap_greyscale = 0, + .cmap_inverse = 0, + .cmap_static = 0, + + .fixed_screen_cpu = NULL, + }, { + //.fb_mode = "Xenarc_700_Y-16", + .init = stk5_gpio_lcdc_active, + .exit = stk5_gpio_lcdc_inactive, + .lcd_power = NULL, + .backlight_power = NULL, + + .pixclock = 34576, + .xres = 640, + .yres = 480, + + .bpp = 16, + + .hsync_len = 64, + .right_margin = 138 + 1, + .left_margin = 118 + 3, + + .vsync_len = 7, + .lower_margin = 44, + .upper_margin = 44, +#if 0 + /* currently not used by driver! */ + .sync = ((0*FB_SYNC_HOR_HIGH_ACT) | + (0*FB_SYNC_VERT_HIGH_ACT) | + (1*FB_SYNC_OE_ACT_HIGH)), +#else + .pcr = PCR_TFT | PCR_COLOR | PCR_PBSIZ_8 | + PCR_BPIX_16 | PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL, + .dmacr = 0x80040060, +#endif + .cmap_greyscale = 0, + .cmap_inverse = 0, + .cmap_static = 0, + + .fixed_screen_cpu = NULL, + }, { + //.fb_mode = "SHARP LQ10D42-16", + .init = stk5_gpio_lcdc_active, + .exit = stk5_gpio_lcdc_inactive, + .lcd_power = NULL, + .backlight_power = NULL, + + .pixclock = 34576, + .xres = 640, + .yres = 480, + +#ifdef USE_18BPP + .bpp = 32, +#else + .bpp = 16, +#endif + .hsync_len = 64, + .right_margin = 138 + 1, + .left_margin = 118 + 3, + + .vsync_len = 7, + .lower_margin = 60, + .upper_margin = 28, +#if 0 + /* currently not used by driver! */ + .sync = ((0*FB_SYNC_HOR_HIGH_ACT) | + (0*FB_SYNC_VERT_HIGH_ACT) | + (1*FB_SYNC_OE_ACT_HIGH)), +#else + .pcr = PCR_TFT | PCR_COLOR | PCR_PBSIZ_8 | +#ifdef USE_18BPP + PCR_BPIX_18 | PCR_END_SEL | PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL, +#else + PCR_BPIX_16 | PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL, +#endif + .dmacr = 0x80040060, +#endif + .cmap_greyscale = 0, + .cmap_inverse = 0, + .cmap_static = 0, + + .fixed_screen_cpu = NULL, + }, { + //.fb_mode = "SHARP LQ104V1DG61-16", + .init = stk5_gpio_lcdc_active, + .exit = stk5_gpio_lcdc_inactive, + .lcd_power = NULL, + .backlight_power = NULL, + + .pixclock = 40000, + .xres = 640, + .yres = 480, + +#ifdef USE_18BPP + .bpp = 32, +#else + .bpp = 16, +#endif + .hsync_len = 32, + .right_margin = 32 + 1, + .left_margin = 0 + 3, + + .vsync_len = 35, + .lower_margin = 0, + .upper_margin = 0, +#if 0 + /* currently not used by driver! */ + .sync = ((0*FB_SYNC_HOR_HIGH_ACT) | + (0*FB_SYNC_VERT_HIGH_ACT) | + (1*FB_SYNC_OE_ACT_HIGH)), +#else + .pcr = PCR_TFT | PCR_COLOR | PCR_PBSIZ_8 | +#ifdef USE_18BPP + PCR_BPIX_18 | PCR_END_SEL | PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL, +#else + PCR_BPIX_16 | PCR_FLMPOL | PCR_LPPOL | PCR_CLKPOL | PCR_SCLK_SEL, +#endif + .dmacr = 0x80040060, +#endif + .cmap_greyscale = 0, + .cmap_inverse = 0, + .cmap_static = 0, + + .fixed_screen_cpu = NULL, + }, +}; + +static int __init karo_stk5_fb_register(void) +{ + int ret; + + ret = mxc_register_device(&mxc_fb_device, &stk5_fb_data[0]); + if (ret != 0) { + DBG(0, "%s: Failed to register FB device: %d\n", __FUNCTION__, ret); + } + return ret; +} +#else +static inline int karo_stk5_fb_register(void) +{ + return 0; +} +#endif + +#if defined(CONFIG_MMC_MXC) || defined(CONFIG_MMC_MXC_MODULE) +/*! + * Resource definition for the SDHC1 + */ +static struct resource stk5_sdhc1_resources[] = { + { + .start = MMC_SDHC1_BASE_ADDR, + .end = MMC_SDHC1_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, { + .start = MXC_INT_SDHC1, + .end = MXC_INT_SDHC1, + .flags = IORESOURCE_IRQ, + }, { + .start = gpio_to_irq(4 * 32 + 4), + .end = gpio_to_irq(4 * 32 + 4), + .flags = IORESOURCE_IRQ, +#if 0 + }, { + .name = "sdhc1", + .start = DMA_REQ_SDHC1, + .end = DMA_REQ_SDHC1, + .flags = IORESOURCE_DMA +#endif + }, +}; + +static inline int stk5_mmc_get_irq(int id) +{ + int irq; + + switch (id) { + case 0: + irq = stk5_sdhc1_resources[2].start; + break; + default: + BUG(); + } + return irq; +} + +static const char *stk5_mmc_irqdesc[] = { + "MMC card 0 detect", +}; + +static struct pad_desc stk5_sdhc_pads[] = { +}; + +static int stk5_mmc_init(struct device *dev, irqreturn_t (*mmc_detect_irq)(int, void *), + void *data) +{ + int err; + int id = to_platform_device(dev)->id; + struct mmc_host *host = data; + int irq = stk5_mmc_get_irq(id); + + err = mxc_iomux_v3_setup_multiple_pads(stk5_sdhc_pads, + ARRAY_SIZE(stk5_sdhc_pads)); + if (err) { + return err; + } + + host->caps |= MMC_CAP_4_BIT_DATA; + + err = request_irq(irq, mmc_detect_irq, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + stk5_mmc_irqdesc[id], data); + if (err) { + printk(KERN_ERR "%s: MMC/SD: can't request MMC card detect IRQ %d\n", + __FUNCTION__, irq); + return err; + } + device_set_wakeup_capable(dev, 1); + + return 0; +} + +static void stk5_mmc_exit(struct device *dev, void *data) +{ + int id = to_platform_device(dev)->id; + int irq = stk5_mmc_get_irq(id); + + free_irq(irq, data); + mxc_iomux_v3_release_multiple_pads(stk5_sdhc_pads, + ARRAY_SIZE(stk5_sdhc_pads)); +} + +#if 0 +static int stk5_mmc_suspend(struct device *dev, pm_message_t state) +{ + int id = to_platform_device(dev)->id; + int irq = stk5_mmc_get_irq(id); + + if (device_may_wakeup(dev)) { + DBG(0, "%s: Enabling IRQ %d wakeup\n", __FUNCTION__, irq); + return enable_irq_wake(irq); + } + return 0; +} + +static int stk5_mmc_resume(struct device *dev) +{ + int id = to_platform_device(dev)->id; + int irq = stk5_mmc_get_irq(id); + + if (device_may_wakeup(dev)) { + DBG(0, "%s: Disabling IRQ %d wakeup\n", __FUNCTION__, irq); + return disable_irq_wake(irq); + } + return 0; +} +#endif + +static struct imxmmc_platform_data stk5_sdhc1_data = { + //.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, + //.min_clk = 150000, + //.max_clk = 25000000, + //.detect_delay = 20, + .init = stk5_mmc_init, + .exit = stk5_mmc_exit, +// .suspend = stk5_mmc_suspend, +// .resume = stk5_mmc_resume, +}; + +static struct platform_device stk5_sdhc1_device = { + .name = "imx-mmc", + .id = 0, + .dev = { + .platform_data = &stk5_sdhc1_data, + }, + .num_resources = ARRAY_SIZE(stk5_sdhc1_resources), + .resource = stk5_sdhc1_resources, +}; +#endif + +#if defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE) +static struct resource mxcspi1_resources[] = { + { + .start = CSPI1_BASE_ADDR, + .end = CSPI1_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, { + .start = MXC_INT_CSPI1, + .end = MXC_INT_CSPI1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mxc_spi_master mxcspi1_data = { + .maxchipselect = 2, + .spi_version = 0, +}; + +static struct platform_device mxcspi1_device = { + .name = "mxc_spi", + .id = 0, + .dev = { + .platform_data = &mxcspi1_data, + }, + .num_resources = ARRAY_SIZE(mxcspi1_resources), + .resource = mxcspi1_resources, +}; +#endif // defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE) + +#if defined(CONFIG_AC97_BUS) || defined(CONFIG_AC97_BUS_MODULE) +static u64 stk5_dma_mask = ~0UL; + +static struct pad_desc stk5_ac97_pads_on[] = { + MX25_PAD_VSTBY_ACK__GPIO_3_18, /* UCB1400 Reset */ + MX25_PAD_RW__AUD4_TXFS, + MX25_PAD_EB0__AUD4_TXD, + MX25_PAD_EB1__AUD4_RXD, + MX25_PAD_OE__AUD4_TXC, +}; + +static struct pad_desc stk5_ac97_pads_off[] = { + MX25_PAD_VSTBY_ACK__GPIO_3_18, /* UCB1400 Reset */ + MX25_PAD_RW__GPIO_3_25, + MX25_PAD_EB0__GPIO_2_12, + MX25_PAD_EB1__AUD4_RXD, + MX25_PAD_OE__AUD4_TXC, +}; + +static struct gpio_desc { + unsigned int gpio:7; + unsigned int dir:1; + unsigned int level:1; +} stk5_ac97_gpios[] = { + /* configure the PHY strap pins to the correct values */ + { GPIO_PORTC | 18, 1, 0, }, + { GPIO_PORTC | 25, 1, 0, }, + { GPIO_PORTB | 12, 1, 0, }, +}; + +static int stk5_ac97_init(struct platform_device *dev) +{ + int ret; + int i; + + DBG(0, "%s: \n", __FUNCTION__); + + ret = mxc_iomux_v3_setup_multiple_pads(stk5_ac97_pads_off, + ARRAY_SIZE(stk5_ac97_pads_off)); + if (ret == 0) { + for (i = 0; i < ARRAY_SIZE(stk5_ac97_gpios); i++) { + struct gpio_desc *pd = &stk5_ac97_gpios[i]; + + ret = gpio_request(pd->gpio, "AC97"); + if (ret < 0) { + DBG(0, "%s: Failed to request GPIO%d_%d: %d\n", + __FUNCTION__, pd->gpio / 32 + 1, pd->gpio % 32, ret); + goto rel_mux; + } + if (pd->dir) { + gpio_direction_output(pd->gpio, + pd->level); + } else { + gpio_direction_input(pd->gpio); + } + } + + ret = mxc_iomux_v3_setup_multiple_pads(stk5_ac97_pads_on, + ARRAY_SIZE(stk5_ac97_pads_on)); + if (ret != 0) { + goto rel_gpio; + } + udelay(1); + gpio_set_value(stk5_ac97_gpios[0].gpio, !stk5_ac97_gpios[0].level); + } + return ret; + + rel_mux: + mxc_iomux_v3_release_multiple_pads(stk5_ac97_gpios_off, + ARRAY_SIZE(stk5_ac97_gpios_off)); + rel_gpio: + while (--i >= 0) { + struct gpio_desc *pd = &stk5_ac97_gpios[i]; + int grp = pd->gpio / 32 + 1; + int ofs = pd->gpio % 32; + + DBG(0, "%s: Freeing GPIO%d_%d\n", __FUNCTION__, + grp, ofs); + gpio_free(pd->gpio); + } + return ret; +} + +static void stk5_ac97_exit(struct platform_device *dev) +{ + int i; + + DBG(0, "%s: Releasing AC97 GPIO pins\n", __FUNCTION__); + + mxc_iomux_v3_release_multiple_pads(stk5_ac97_pads_on, + ARRAY_SIZE(stk5_ac97_pads_on)); + for (i = 0; i < ARRAY_SIZE(stk5_ac97_gpios); i++) { + struct gpio_desc *pd = &stk5_ac97_gpios[i]; + int grp = pd->gpio / 32 + 1; + int ofs = pd->gpio % 32; + + DBG(0, "%s: Freeing GPIO%d_%d\n", __FUNCTION__, + grp, ofs); + gpio_free(pd->gpio); + } +} + +static struct mxc_ac97_audio_ops stk5_ac97_ops = { + .init = stk5_ac97_init, + .exit = stk5_ac97_exit, + .startup = NULL, + .shutdown = NULL, + .suspend = NULL, + .resume = NULL, + .priv = NULL, +}; + +static struct platform_device ac97_device = { + .name = "mx25-ac97", + .id = -1, + .dev = { + .dma_mask = &stk5_dma_mask, + .coherent_dma_mask = ~0UL, + .platform_data = &stk5_ac97_ops, + }, +}; +#endif + +static struct platform_dev_list { + struct platform_device *pdev; + int flag; +} stk5_devices[] __initdata = { +#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE) + { .pdev = &stk5_led_device, .flag = -1, }, +#endif +#if defined(CONFIG_KEYBOARD_MXC) || defined(CONFIG_KEYBOARD_MXC_MODULE) + { .pdev = &stk5_keypad_device, .flag = 1, }, +#endif +#if defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE) + { .pdev = &mxcspi1_device, .flag = 1, }, +#endif +#if defined(CONFIG_AC97_BUS) || defined(CONFIG_AC97_BUS_MODULE) + { .pdev = &ac97_device, .flag = 1, }, +#endif +#if defined(CONFIG_MMC_MXC) || defined(CONFIG_MMC_MXC_MODULE) + { .pdev = &stk5_sdhc1_device, .flag = 1, }, +#endif +}; +#define STK5_NUM_DEVICES ARRAY_SIZE(stk5_devices) + +static __init int karo_stk5_board_init(void) +{ + int ret; + int i; + + if (karo_get_board_type() != BOARD_KARO_STK5) { + return -ENODEV; + } + DBG(0, "%s: \n", __FUNCTION__); + + karo_stk5_serial_init(); + + dump_regs(); + + /* enable SSI1_INT (GPIO_3_15) for IRQ probing */ + set_irq_flags(gpio_to_irq(GPIO_PORTC | 15), IRQF_VALID | IRQF_PROBE); + + ret = karo_stk5_fb_register(); + if (ret) { + printk(KERN_WARNING "%s: karo_stk5_fb_register() failed: %d\n", + __FUNCTION__, ret); + } + + for (i = 0; i < STK5_NUM_DEVICES; i++) { + if (stk5_devices[i].pdev == NULL) continue; + if (!stk5_devices[i].flag) { + DBG(0, "%s: Skipping platform device[%d] @ %p dev %p: %s\n", + __FUNCTION__, i, stk5_devices[i].pdev, &stk5_devices[i].pdev->dev, + stk5_devices[i].pdev->name); + continue; + } + DBG(0, "%s: Registering platform device[%d] @ %p dev %p: %s\n", + __FUNCTION__, i, stk5_devices[i].pdev, &stk5_devices[i].pdev->dev, + stk5_devices[i].pdev->name); + ret = platform_device_register(stk5_devices[i].pdev); + if (ret) { + printk(KERN_WARNING "%s: Failed to register platform_device[%d]: %s: %d\n", + __FUNCTION__, i, stk5_devices[i].pdev->name, ret); + } + } + DBG(0, "%s: Done\n", __FUNCTION__); + return 0; +} +subsys_initcall(karo_stk5_board_init); diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx3/clock-imx35.c linux-2.6.30-rc4-karo3/arch/arm/mach-mx3/clock-imx35.c --- linux-2.6.30-rc4-git/arch/arm/mach-mx3/clock-imx35.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx3/clock-imx35.c 2009-06-02 17:59:19.000000000 +0200 @@ -381,7 +381,7 @@ DEFINE_CLOCK(gpu2d_clk, 0, CCM_CGR3, 4 .clk = &c, \ }, -static struct clk_lookup lookups[] __initdata = { +static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, "asrc", asrc_clk) _REGISTER_CLOCK(NULL, "ata", ata_clk) _REGISTER_CLOCK(NULL, "audmux", audmux_clk) diff -purN linux-2.6.30-rc4-git/arch/arm/mach-mx3/clock.c linux-2.6.30-rc4-karo3/arch/arm/mach-mx3/clock.c --- linux-2.6.30-rc4-git/arch/arm/mach-mx3/clock.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/mach-mx3/clock.c 2009-06-02 17:59:19.000000000 +0200 @@ -516,7 +516,7 @@ DEFINE_CLOCK(ipg_clk, 0, NULL, .clk = &c, \ }, -static struct clk_lookup lookups[] __initdata = { +static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, "emi", emi_clk) _REGISTER_CLOCK(NULL, "cspi", cspi1_clk) _REGISTER_CLOCK(NULL, "cspi", cspi2_clk) diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/Kconfig linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/Kconfig --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/Kconfig 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/Kconfig 2009-06-02 18:01:59.000000000 +0200 @@ -56,6 +56,9 @@ config ARCH_HAS_RNGA bool depends on ARCH_MXC +config ARCH_MXC_IOMUX_V2 + bool + config ARCH_MXC_IOMUX_V3 bool endif diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/Makefile linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/Makefile --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/Makefile 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/Makefile 2009-06-02 18:02:00.000000000 +0200 @@ -5,7 +5,7 @@ # Common support obj-y := irq.o clock.o gpio.o time.o devices.o cpu.o system.o -obj-$(CONFIG_ARCH_MX1) += iomux-mx1-mx2.o dma-mx1-mx2.o -obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o -obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o -obj-$(CONFIG_MXC_PWM) += pwm.o +obj-$(CONFIG_ARCH_MXC_IOMUX_V2) += iomux-mx1-mx2.o dma-mx1-mx2.o +obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o +obj-$(CONFIG_MXC_PWM) += pwm.o +obj-$(CONFIG_MACH_MX25) += spba.o diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/board-stk5.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/board-stk5.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/board-stk5.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/board-stk5.h 2009-06-02 18:02:13.000000000 +0200 @@ -0,0 +1,17 @@ +/* + * Copyright 2009 + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#define UART1_ENABLED 1 +#define UART2_ENABLED 1 +#define UART3_ENABLED 1 +/* Not available on TX25 */ +#define UART4_ENABLED 0 +#define UART5_ENABLED 0 diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/board-tx25.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/board-tx25.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/board-tx25.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/board-tx25.h 2009-06-02 18:02:13.000000000 +0200 @@ -0,0 +1,13 @@ +/* + * Copyright 2009 + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#define MXC_LL_UART_PADDR UART1_BASE_ADDR +#define MXC_LL_UART_VADDR AIPS1_IO_ADDRESS(UART1_BASE_ADDR) diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/common.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/common.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/common.h 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/common.h 2009-06-02 18:02:05.000000000 +0200 @@ -17,6 +17,7 @@ struct clk; extern void mx1_map_io(void); extern void mx21_map_io(void); extern void mx27_map_io(void); +extern void mx25_map_io(void); extern void mx31_map_io(void); extern void mx35_map_io(void); extern void mxc_init_irq(void); @@ -24,6 +25,7 @@ extern void mxc_timer_init(struct clk *t extern int mx1_clocks_init(unsigned long fref); extern int mx21_clocks_init(unsigned long lref, unsigned long fref); extern int mx27_clocks_init(unsigned long fref); +extern int mx25_clocks_init(unsigned long fref); extern int mx31_clocks_init(unsigned long fref); extern int mx35_clocks_init(void); extern int mxc_register_gpios(void); diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/dma.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/dma.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/dma.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/dma.h 2009-06-02 18:02:13.000000000 +0200 @@ -0,0 +1,259 @@ +/* + * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARCH_MXC_DMA_H__ +#define __ASM_ARCH_MXC_DMA_H__ + +#include + +#define MXC_DMA_DYNAMIC_CHANNEL 255 + +#define MXC_DMA_DONE 0x0 +#define MXC_DMA_REQUEST_TIMEOUT 0x1 +#define MXC_DMA_TRANSFER_ERROR 0x2 + +/*! This defines the list of device ID's for DMA */ +typedef enum mxc_dma_device { + MXC_DMA_UART1_RX, + MXC_DMA_UART1_TX, + MXC_DMA_UART2_RX, + MXC_DMA_UART2_TX, + MXC_DMA_UART3_RX, + MXC_DMA_UART3_TX, + MXC_DMA_UART4_RX, + MXC_DMA_UART4_TX, + MXC_DMA_UART5_RX, + MXC_DMA_UART5_TX, + MXC_DMA_UART6_RX, + MXC_DMA_UART6_TX, + MXC_DMA_MMC1_WIDTH_1, + MXC_DMA_MMC1_WIDTH_4, + MXC_DMA_MMC2_WIDTH_1, + MXC_DMA_MMC2_WIDTH_4, + MXC_DMA_SSI1_8BIT_RX0, + MXC_DMA_SSI1_8BIT_TX0, + MXC_DMA_SSI1_16BIT_RX0, + MXC_DMA_SSI1_16BIT_TX0, + MXC_DMA_SSI1_24BIT_RX0, + MXC_DMA_SSI1_24BIT_TX0, + MXC_DMA_SSI1_8BIT_RX1, + MXC_DMA_SSI1_8BIT_TX1, + MXC_DMA_SSI1_16BIT_RX1, + MXC_DMA_SSI1_16BIT_TX1, + MXC_DMA_SSI1_24BIT_RX1, + MXC_DMA_SSI1_24BIT_TX1, + MXC_DMA_SSI2_8BIT_RX0, + MXC_DMA_SSI2_8BIT_TX0, + MXC_DMA_SSI2_16BIT_RX0, + MXC_DMA_SSI2_16BIT_TX0, + MXC_DMA_SSI2_24BIT_RX0, + MXC_DMA_SSI2_24BIT_TX0, + MXC_DMA_SSI2_8BIT_RX1, + MXC_DMA_SSI2_8BIT_TX1, + MXC_DMA_SSI2_16BIT_RX1, + MXC_DMA_SSI2_16BIT_TX1, + MXC_DMA_SSI2_24BIT_RX1, + MXC_DMA_SSI2_24BIT_TX1, + MXC_DMA_FIR_RX, + MXC_DMA_FIR_TX, + MXC_DMA_CSPI1_RX, + MXC_DMA_CSPI1_TX, + MXC_DMA_CSPI2_RX, + MXC_DMA_CSPI2_TX, + MXC_DMA_CSPI3_RX, + MXC_DMA_CSPI3_TX, + MXC_DMA_ATA_RX, + MXC_DMA_ATA_TX, + MXC_DMA_MEMORY, + MXC_DMA_FIFO_MEMORY, + MXC_DMA_DSP_PACKET_DATA0_RD, + MXC_DMA_DSP_PACKET_DATA0_WR, + MXC_DMA_DSP_PACKET_DATA1_RD, + MXC_DMA_DSP_PACKET_DATA1_WR, + MXC_DMA_DSP_LOG0_CHNL, + MXC_DMA_DSP_LOG1_CHNL, + MXC_DMA_DSP_LOG2_CHNL, + MXC_DMA_DSP_LOG3_CHNL, + MXC_DMA_CSI_RX, + MXC_DMA_SPDIF_16BIT_TX, + MXC_DMA_SPDIF_16BIT_RX, + MXC_DMA_SPDIF_32BIT_TX, + MXC_DMA_SPDIF_32BIT_RX, + MXC_DMA_ASRC_A_RX, + MXC_DMA_ASRC_A_TX, + MXC_DMA_ASRC_B_RX, + MXC_DMA_ASRC_B_TX, + MXC_DMA_ASRC_C_RX, + MXC_DMA_ASRC_C_TX, + MXC_DMA_ESAI_16BIT_RX, + MXC_DMA_ESAI_16BIT_TX, + MXC_DMA_ESAI_24BIT_RX, + MXC_DMA_ESAI_24BIT_TX, + MXC_DMA_TEST_RAM2D2RAM, + MXC_DMA_TEST_RAM2RAM2D, + MXC_DMA_TEST_RAM2D2RAM2D, + MXC_DMA_TEST_RAM2RAM, + MXC_DMA_TEST_HW_CHAINING, + MXC_DMA_TEST_SW_CHAINING +} mxc_dma_device_t; + +/*! This defines the prototype of callback funtion registered by the drivers */ +typedef void (*mxc_dma_callback_t) (void *arg, int error_status, + unsigned int count); + +/*! This defines the type of DMA transfer requested */ +typedef enum mxc_dma_mode { + MXC_DMA_MODE_READ, + MXC_DMA_MODE_WRITE, +} mxc_dma_mode_t; + +/*! This defines the DMA channel parameters */ +typedef struct mxc_dma_channel { + unsigned int active:1; /*!< When there has a active tranfer, it is set to 1 */ + unsigned int lock; /*!< Defines the channel is allocated or not */ + int curr_buf; /*!< Current buffer */ + mxc_dma_mode_t mode; /*!< Read or Write */ + unsigned int channel; /*!< Channel info */ + unsigned int dynamic:1; /*!< Channel not statically allocated when 1 */ + char *dev_name; /*!< Device name */ + void *private; /*!< Private structure for platform */ + mxc_dma_callback_t cb_fn; /*!< The callback function */ + void *cb_args; /*!< The argument of callback function */ +} mxc_dma_channel_t; + +/*! This structure contains the information about a dma transfer */ +typedef struct mxc_dma_requestbuf { + dma_addr_t src_addr; /*!< source address */ + dma_addr_t dst_addr; /*!< destination address */ + int num_of_bytes; /*!< the length of this transfer : bytes */ +} mxc_dma_requestbuf_t; + +/*! + * This function is generally called by the driver at open time. + * The DMA driver would do any initialization steps that is required + * to get the channel ready for data transfer. + * + * @param channel_id a pre-defined id. The peripheral driver would specify + * the id associated with its peripheral. This would be + * used by the DMA driver to identify the peripheral + * requesting DMA and do the necessary setup on the + * channel associated with the particular peripheral. + * The DMA driver could use static or dynamic DMA channel + * allocation. + * @param dev_name module name or device name + * @return returns a negative number on error if request for a DMA channel did not + * succeed, returns the channel number to be used on success. + */ +extern int mxc_dma_request(mxc_dma_device_t channel_id, char *dev_name); + +/*! + * This function is generally called by the driver at close time. The DMA + * driver would do any cleanup associated with this channel. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +extern int mxc_dma_free(int channel_num); + +/*! + * This function would just configure the buffers specified by the user into + * dma channel. The caller must call mxc_dma_enable to start this transfer. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param dma_buf an array of physical addresses to the user defined + * buffers. The caller must guarantee the dma_buf is + * available until the transfer is completed. + * @param num_buf number of buffers in the array + * @param mode specifies whether this is READ or WRITE operation + * @return This function returns a negative number on error if buffer could not be + * added with DMA for transfer. On Success, it returns 0 + */ +extern int mxc_dma_config(int channel_num, mxc_dma_requestbuf_t * dma_buf, + int num_buf, mxc_dma_mode_t mode); + +/*! + * This function would just configure the scatterlist specified by the + * user into dma channel. This is a slight variation of mxc_dma_config(), + * it is provided for the convenience of drivers that have a scatterlist + * passed into them. It is the calling driver's responsibility to have the + * correct physical address filled in the "dma_address" field of the + * scatterlist. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param sg a scatterlist of buffers. The caller must guarantee + * the dma_buf is available until the transfer is + * completed. + * @param num_buf number of buffers in the array + * @param num_of_bytes total number of bytes to transfer. If set to 0, this + * would imply to use the length field of the scatterlist + * for each DMA transfer. Else it would calculate the size + * for each DMA transfer. + * @param mode specifies whether this is READ or WRITE operation + * @return This function returns a negative number on error if buffer could not + * be added with DMA for transfer. On Success, it returns 0 + */ +extern int mxc_dma_sg_config(int channel_num, struct scatterlist *sg, + int num_buf, int num_of_bytes, + mxc_dma_mode_t mode); + +/*! + * This function is provided if the driver would like to set/change its + * callback function. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param callback a callback function to provide notification on transfer + * completion, user could specify NULL if he does not wish + * to be notified + * @param arg an argument that gets passed in to the callback + * function, used by the user to do any driver specific + * operations. + * @return this function returns a negative number on error if the callback + * could not be set for the channel or 0 on success + */ +extern int mxc_dma_callback_set(int channel_num, mxc_dma_callback_t callback, + void *arg); + +/*! + * This stops the DMA channel and any ongoing transfers. Subsequent use of + * mxc_dma_enable() will restart the channel and restart the transfer. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +extern int mxc_dma_disable(int channel_num); + +/*! + * This starts DMA transfer. Or it restarts DMA on a stopped channel + * previously stopped with mxc_dma_disable(). + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +extern int mxc_dma_enable(int channel_num); + +#endif diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/hardware.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/hardware.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/hardware.h 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/hardware.h 2009-06-02 18:02:06.000000000 +0200 @@ -29,13 +29,18 @@ #endif #ifdef CONFIG_ARCH_MX2 +#ifndef CONFIG_MACH_MX25 # include +#endif # ifdef CONFIG_MACH_MX21 # include # endif # ifdef CONFIG_MACH_MX27 # include # endif +# ifdef CONFIG_MACH_MX25 +# include +# endif #endif #ifdef CONFIG_ARCH_MX1 diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/imxfb.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/imxfb.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/imxfb.h 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/imxfb.h 2009-06-02 18:02:06.000000000 +0200 @@ -13,7 +13,8 @@ #define PCR_BPIX_4 (2 << 25) #define PCR_BPIX_8 (3 << 25) #define PCR_BPIX_12 (4 << 25) -#define PCR_BPIX_16 (4 << 25) +#define PCR_BPIX_16 (5 << 25) +#define PCR_BPIX_18 (6 << 25) #define PCR_PIXPOL (1 << 24) #define PCR_FLMPOL (1 << 23) #define PCR_LPPOL (1 << 22) diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/iomux-mx25.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/iomux-mx25.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/iomux-mx25.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/iomux-mx25.h 2009-07-01 11:50:13.000000000 +0200 @@ -0,0 +1,774 @@ +/* + * arch/arm/plat-mxc/include/mach/iomux-mx25.h + * + * Copyright (C) 2009 by Lothar Wassmann + * + * based on arch/arm/mach-mx25/mx25_pins.h + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + * and + * arch/arm/plat-mxc/include/mach/iomux-mx35.h + * Copyright (C, NO_PAD_CTRL) 2009 by Jan Weitzel Phytec Messtechnik GmbH + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __IOMUX_MX25_H__ +#define __IOMUX_MX25_H__ + +#include + +/* + * + * @brief MX25 I/O Pin List + * + * @ingroup GPIO_MX25 + */ + +#ifndef __ASSEMBLY__ + +/* + * IOMUX/PAD Bit field definitions + */ + +#define MX25_PAD_A10__A10 IOMUX_PAD(A10, A10, 0x000, 0x008, 0x00, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_A10__GPIO_4_0 IOMUX_PAD(A10, GPIO_4_0, 0x000, 0x008, 0x05, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_A13__A13 IOMUX_PAD(A13, A13, 0x22C, 0x00c, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A13__GPIO_4_1 IOMUX_PAD(A13, GPIO_4_1, 0x22C, 0x00c, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A14__A14 IOMUX_PAD(A14, A14, 0x230, 0x010, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A14__GPIO_2_0 IOMUX_PAD(A14, GPIO_2_0, 0x230, 0x010, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A15__A15 IOMUX_PAD(A15, A15, 0x234, 0x014, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A15__GPIO_2_1 IOMUX_PAD(A15, GPIO_2_1, 0x234, 0x014, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A16__A16 IOMUX_PAD(A16, A16, 0x000, 0x018, 0x10, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_A16__GPIO_2_2 IOMUX_PAD(A16, GPIO_2_2, 0x000, 0x018, 0x15, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_A17__A17 IOMUX_PAD(A17, A17, 0x238, 0x01c, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A17__GPIO_2_3 IOMUX_PAD(A17, GPIO_2_3, 0x238, 0x01c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A18__A18 IOMUX_PAD(A18, A18, 0x23c, 0x020, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A18__GPIO_2_4 IOMUX_PAD(A18, GPIO_2_4, 0x23c, 0x020, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A18__FEC_COL IOMUX_PAD(A18, FEC_COL, 0x23c, 0x020, 0x17, 0x504, 0, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_A19__A19 IOMUX_PAD(A19, A19, 0x240, 0x024, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A19__FEC_RX_ER IOMUX_PAD(A19, FEC_RX_ER, 0x240, 0x024, 0x17, 0x518, 0, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_A19__GPIO_2_5 IOMUX_PAD(A19, GPIO_2_5, 0x240, 0x024, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A20__A20 IOMUX_PAD(A20, A20, 0x244, 0x028, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A20__GPIO_2_6 IOMUX_PAD(A20, GPIO_2_6, 0x244, 0x028, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A20__FEC_RDATA2 IOMUX_PAD(A20, FEC_RDATA2, 0x244, 0x028, 0x17, 0x50c, 0, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_A21__A21 IOMUX_PAD(A21, A21, 0x248, 0x02c, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A21__GPIO_2_7 IOMUX_PAD(A21, GPIO_2_7, 0x248, 0x02c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A21__FEC_RDATA3 IOMUX_PAD(A21, FEC_RDATA3, 0x248, 0x02c, 0x17, 0x510, 0, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_A22__A22 IOMUX_PAD(A22, A22, 0x000, 0x030, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A22__GPIO_2_8 IOMUX_PAD(A22, GPIO_2_8, 0x000, 0x030, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A23__A23 IOMUX_PAD(A23, A23, 0x24c, 0x034, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A23__GPIO_2_9 IOMUX_PAD(A23, GPIO_2_9, 0x24c, 0x034, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A24__A24 IOMUX_PAD(A24, A24, 0x250, 0x038, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A24__GPIO_2_10 IOMUX_PAD(A24, GPIO_2_10, 0x250, 0x038, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A24__FEC_RX_CLK IOMUX_PAD(A24, FEC_RX_CLK, 0x250, 0x038, 0x17, 0x514, 0, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_A25__A25 IOMUX_PAD(A25, A25, 0x254, 0x03c, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A25__GPIO_2_11 IOMUX_PAD(A25, GPIO_2_11, 0x254, 0x03c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_A25__FEC_CRS IOMUX_PAD(A25, FEC_CRS, 0x254, 0x03c, 0x17, 0x508, 0, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_EB0__EB0 IOMUX_PAD(EB0, EB0, 0x258, 0x040, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_EB0__AUD4_TXD IOMUX_PAD(EB0, AUD4_TXD, 0x258, 0x040, 0x14, 0x464, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_EB0__GPIO_2_12 IOMUX_PAD(EB0, GPIO_2_12, 0x258, 0x040, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_EB1__EB1 IOMUX_PAD(EB1, EB1, 0x25c, 0x044, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_EB1__AUD4_RXD IOMUX_PAD(EB1, AUD4_RXD, 0x25c, 0x044, 0x14, 0x460, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_EB1__GPIO_2_13 IOMUX_PAD(EB1, GPIO_2_13, 0x25c, 0x044, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_OE__OE IOMUX_PAD(OE, OE, 0x260, 0x048, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_OE__AUD4_TXC IOMUX_PAD(OE, AUD4_TXC, 0x260, 0x048, 0x14, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_OE__GPIO_2_14 IOMUX_PAD(OE, GPIO_2_14, 0x260, 0x048, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CS0__CS0 IOMUX_PAD(CS0, CS0, 0x000, 0x04c, 0x00, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CS0__GPIO_4_2 IOMUX_PAD(CS0, GPIO_4_2, 0x000, 0x04c, 0x05, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CS1__CS1 IOMUX_PAD(CS1, CS1, 0x000, 0x050, 0x00, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CS1__GPIO_4_3 IOMUX_PAD(CS1, GPIO_4_3, 0x000, 0x050, 0x05, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CS4__CS4 IOMUX_PAD(CS4, CS4, 0x264, 0x054, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CS4__UART5_CTS IOMUX_PAD(CS4, UART5_CTS, 0x264, 0x054, 0x13, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CS4__GPIO_3_20 IOMUX_PAD(CS4, GPIO_3_20, 0x264, 0x054, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CS5__CS5 IOMUX_PAD(CS5, CS5, 0x268, 0x058, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CS5__UART5_RTS IOMUX_PAD(CS5, UART5_RTS, 0x268, 0x058, 0x13, 0x574, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CS5__GPIO_3_21 IOMUX_PAD(CS5, GPIO_3_21, 0x268, 0x058, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_NF_CE0__NF_CE0 IOMUX_PAD(NF_CE0, NF_CE0, 0x26c, 0x05c, 0x10, 0, 0, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_NF_CE0__GPIO_3_22 IOMUX_PAD(NF_CE0, GPIO_3_22, 0x26c, 0x05c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_ECB__ECB IOMUX_PAD(ECB, ECB, 0x270, 0x060, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_ECB__UART5_TXD_MUX IOMUX_PAD(ECB, UART5_TXD_MUX, 0x270, 0x060, 0x13, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_ECB__GPIO_3_23 IOMUX_PAD(ECB, GPIO_3_23, 0x270, 0x060, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LBA__LBA IOMUX_PAD(LBA, LBA, 0x274, 0x064, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LBA__UART5_RXD_MUX IOMUX_PAD(LBA, UART5_RXD_MUX, 0x274, 0x064, 0x13, 0x578, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LBA__GPIO_3_24 IOMUX_PAD(LBA, GPIO_3_24, 0x274, 0x064, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_BCLK__BCLK IOMUX_PAD(BCLK, BCLK, 0x000, 0x068, 0x00, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_BCLK__GPIO_4_4 IOMUX_PAD(BCLK, GPIO_4_4, 0x000, 0x068, 0x05, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_RW__RW IOMUX_PAD(RW, RW, 0x278, 0x06c, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_RW__AUD4_TXFS IOMUX_PAD(RW, AUD4_TXFS, 0x278, 0x06c, 0x14, 0x474, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_RW__GPIO_3_25 IOMUX_PAD(RW, GPIO_3_25, 0x278, 0x06c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_NFWE_B__NFWE_B IOMUX_PAD(NFWE_B, NFWE_B, 0x000, 0x070, 0x10, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_NFWE_B__GPIO_3_26 IOMUX_PAD(NFWE_B, GPIO_3_26, 0x000, 0x070, 0x15, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_NFRE_B__NFRE_B IOMUX_PAD(NFRE_B, NFRE_B, 0x000, 0x074, 0x10, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_NFRE_B__GPIO_3_27 IOMUX_PAD(NFRE_B, GPIO_3_27, 0x000, 0x074, 0x15, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_NFALE__NFALE IOMUX_PAD(NFALE, NFALE, 0x000, 0x078, 0x10, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_NFALE__GPIO_3_28 IOMUX_PAD(NFALE, GPIO_3_28, 0x000, 0x078, 0x15, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_NFCLE__NFCLE IOMUX_PAD(NFCLE, NFCLE, 0x000, 0x07c, 0x10, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_NFCLE__GPIO_3_29 IOMUX_PAD(NFCLE, GPIO_3_29, 0x000, 0x07c, 0x15, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_NFWP_B__NFWP_B IOMUX_PAD(NFWP_B, NFWP_B, 0x000, 0x080, 0x10, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_NFWP_B__GPIO_3_30 IOMUX_PAD(NFWP_B, GPIO_3_30, 0x000, 0x080, 0x15, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_NFRB__NFRB IOMUX_PAD(NFRB, NFRB, 0x27c, 0x084, 0x10, 0, 0, PAD_CTL_PULL_KEEPER) +#define MX25_PAD_NFRB__GPIO_3_31 IOMUX_PAD(NFRB, GPIO_3_31, 0x27c, 0x084, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D15__D15 IOMUX_PAD(D15, D15, 0x280, 0x088, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D15__LD16 IOMUX_PAD(D15, LD16, 0x280, 0x088, 0x01, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D15__GPIO_4_5 IOMUX_PAD(D15, GPIO_4_5, 0x280, 0x088, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D14__D14 IOMUX_PAD(D14, D14, 0x284, 0x08c, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D14__LD17 IOMUX_PAD(D14, LD17, 0x284, 0x08c, 0x01, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D14__GPIO_4_6 IOMUX_PAD(D14, GPIO_4_6, 0x284, 0x08c, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D13__D13 IOMUX_PAD(D13, D13, 0x288, 0x090, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D13__LD18 IOMUX_PAD(D13, LD18, 0x288, 0x090, 0x01, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D13__GPIO_4_7 IOMUX_PAD(D13, GPIO_4_7, 0x288, 0x090, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D12__D12 IOMUX_PAD(D12, D12, 0x28c, 0x094, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D12__GPIO_4_8 IOMUX_PAD(D12, GPIO_4_8, 0x28c, 0x094, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D11__D11 IOMUX_PAD(D11, D11, 0x290, 0x098, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D11__GPIO_4_9 IOMUX_PAD(D11, GPIO_4_9, 0x290, 0x098, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D10__D10 IOMUX_PAD(D10, D10, 0x294, 0x09c, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D10__GPIO_4_10 IOMUX_PAD(D10, GPIO_4_10, 0x294, 0x09c, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D10__USBOTG_OC IOMUX_PAD(D10, USBOTG_OC, 0x294, 0x09c, 0x06, 0x57c, 0, PAD_CTL_PULL_UP_100K) +#define MX25_PAD_D9__D9 IOMUX_PAD(D9, D9, 0x298, 0x0a0, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D9__GPIO_4_11 IOMUX_PAD(D9, GPIO_4_11, 0x298, 0x0a0, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D9__USBH2_PWR IOMUX_PAD(D9, USBH2_PWR, 0x298, 0x0a0, 0x06, 0, 0, PAD_CTL_PULL_KEEPER) +#define MX25_PAD_D8__D8 IOMUX_PAD(D8, D8, 0x29c, 0x0a4, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D8__GPIO_4_12 IOMUX_PAD(D8, GPIO_4_12, 0x29c, 0x0a4, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D8__USBH2_OC IOMUX_PAD(D8, USBH2_OC, 0x29c, 0x0a4, 0x06, 0x580, 0, PAD_CTL_PULL_UP_100K) +#define MX25_PAD_D7__D7 IOMUX_PAD(D7, D7, 0x2a0, 0x0a8, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D7__GPIO_4_13 IOMUX_PAD(D7, GPIO_4_13, 0x2a0, 0x0a8, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D6__D6 IOMUX_PAD(D6, D6, 0x2a4, 0x0ac, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D6__GPIO_4_14 IOMUX_PAD(D6, GPIO_4_14, 0x2a4, 0x0ac, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D5__D5 IOMUX_PAD(D5, D5, 0x2a8, 0x0b0, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D5__GPIO_4_15 IOMUX_PAD(D5, GPIO_4_15, 0x2a8, 0x0b0, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D4__D4 IOMUX_PAD(D4, D4, 0x2ac, 0x0b4, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D4__GPIO_4_16 IOMUX_PAD(D4, GPIO_4_16, 0x2ac, 0x0b4, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D3__D3 IOMUX_PAD(D3, D3, 0x2b0, 0x0b8, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D3__GPIO_4_17 IOMUX_PAD(D3, GPIO_4_17, 0x2b0, 0x0b8, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D2__D2 IOMUX_PAD(D2, D2, 0x2b4, 0x0bc, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D2__GPIO_4_18 IOMUX_PAD(D2, GPIO_4_18, 0x2b4, 0x0bc, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D1__D1 IOMUX_PAD(D1, D1, 0x2b8, 0x0c0, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D1__GPIO_4_19 IOMUX_PAD(D1, GPIO_4_19, 0x2b8, 0x0c0, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D0__D0 IOMUX_PAD(D0, D0, 0x2bc, 0x0c4, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_D0__GPIO_4_20 IOMUX_PAD(D0, GPIO_4_20, 0x2bc, 0x0c4, 0x05, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD0__LD0 IOMUX_PAD(LD0, LD0, 0x2c0, 0x0c8, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD0__CSI_D0 IOMUX_PAD(LD0, CSI_D0, 0x2c0, 0x0c8, 0x12, 0x488, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD0__GPIO_2_15 IOMUX_PAD(LD0, GPIO_2_15, 0x2c0, 0x0c8, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD1__LD1 IOMUX_PAD(LD1, LD1, 0x2c4, 0x0cc, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD1__CSI_D1 IOMUX_PAD(LD1, CSI_D1, 0x2c4, 0x0cc, 0x12, 0x48c, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD1__GPIO_2_16 IOMUX_PAD(LD1, GPIO_2_16, 0x2c4, 0x0cc, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD2__LD2 IOMUX_PAD(LD2, LD2, 0x2c8, 0x0d0, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD2__GPIO_2_17 IOMUX_PAD(LD2, GPIO_2_17, 0x2c8, 0x0d0, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD3__LD3 IOMUX_PAD(LD3, LD3, 0x2cc, 0x0d4, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD3__GPIO_2_18 IOMUX_PAD(LD3, GPIO_2_18, 0x2cc, 0x0d4, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD4__LD4 IOMUX_PAD(LD4, LD4, 0x2d0, 0x0d8, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD4__GPIO_2_19 IOMUX_PAD(LD4, GPIO_2_19, 0x2d0, 0x0d8, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD5__LD5 IOMUX_PAD(LD5, LD5, 0x2d4, 0x0dc, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD5__GPIO_1_19 IOMUX_PAD(LD5, GPIO_1_19, 0x2d4, 0x0dc, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD6__LD6 IOMUX_PAD(LD6, LD6, 0x2d8, 0x0e0, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD6__GPIO_1_20 IOMUX_PAD(LD6, GPIO_1_20, 0x2d8, 0x0e0, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD7__LD7 IOMUX_PAD(LD7, LD7, 0x2dc, 0x0e4, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD7__GPIO_1_21 IOMUX_PAD(LD7, GPIO_1_21, 0x2dc, 0x0e4, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD8__LD8 IOMUX_PAD(LD8, LD8, 0x2e0, 0x0e8, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD8__FEC_TX_ERR IOMUX_PAD(LD8, FEC_TX_ERR, 0x2e0, 0x0e8, 0x15, 0, 0, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_LD9__LD9 IOMUX_PAD(LD9, LD9, 0x2e4, 0x0ec, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD9__FEC_COL IOMUX_PAD(LD9, FEC_COL, 0x2e4, 0x0ec, 0x15, 0x504, 1, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_LD10__LD10 IOMUX_PAD(LD10, LD10, 0x2e8, 0x0f0, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD10__FEC_RX_ER IOMUX_PAD(LD10, FEC_RX_ER, 0x2e8, 0x0f0, 0x15, 0x518, 1, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_LD11__LD11 IOMUX_PAD(LD11, LD11, 0x2ec, 0x0f4, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD11__FEC_RDATA2 IOMUX_PAD(LD11, FEC_RDATA2, 0x2ec, 0x0f4, 0x15, 0x50c, 1, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_LD12__LD12 IOMUX_PAD(LD12, LD12, 0x2f0, 0x0f8, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD12__FEC_RDATA3 IOMUX_PAD(LD12, FEC_RDATA3, 0x2f0, 0x0f8, 0x15, 0x510, 1, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_LD13__LD13 IOMUX_PAD(LD13, LD13, 0x2f4, 0x0fc, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD13__FEC_TDATA2 IOMUX_PAD(LD13, FEC_TDATA2, 0x2f4, 0x0fc, 0x15, 0, 0, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_LD14__LD14 IOMUX_PAD(LD14, LD14, 0x2f8, 0x100, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD14__FEC_TDATA3 IOMUX_PAD(LD14, FEC_TDATA3, 0x2f8, 0x100, 0x15, 0, 0, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_LD15__LD15 IOMUX_PAD(LD15, LD15, 0x2fc, 0x104, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LD15__FEC_RX_CLK IOMUX_PAD(LD15, FEC_RX_CLK, 0x2fc, 0x104, 0x15, 0x514, 1, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_HSYNC__HSYNC IOMUX_PAD(HSYNC, HSYNC, 0x300, 0x108, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_HSYNC__GPIO_1_22 IOMUX_PAD(HSYNC, GPIO_1_22, 0x300, 0x108, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_VSYNC__VSYNC IOMUX_PAD(VSYNC, VSYNC, 0x304, 0x10c, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_VSYNC__GPIO_1_23 IOMUX_PAD(VSYNC, GPIO_1_23, 0x304, 0x10c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LSCLK__LSCLK IOMUX_PAD(LSCLK, LSCLK, 0x308, 0x110, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_LSCLK__GPIO_1_24 IOMUX_PAD(LSCLK, GPIO_1_24, 0x308, 0x110, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_OE_ACD__OE_ACD IOMUX_PAD(OE_ACD, OE_ACD, 0x30c, 0x114, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_OE_ACD__GPIO_1_25 IOMUX_PAD(OE_ACD, GPIO_1_25, 0x30c, 0x114, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CONTRAST__CONTRAST IOMUX_PAD(CONTRAST, CONTRAST, 0x310, 0x118, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CONTRAST__FEC_CRS IOMUX_PAD(CONTRAST, FEC_CRS, 0x310, 0x118, 0x15, 0x508, 1, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_PWM__PWM IOMUX_PAD(PWM, PWM, 0x314, 0x11c, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_PWM__GPIO_1_26 IOMUX_PAD(PWM, GPIO_1_26, 0x314, 0x11c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_PWM__USBH2_OC IOMUX_PAD(PWM, USBH2_OC, 0x314, 0x11c, 0x16, 0x580, 1, PAD_CTL_PULL_UP_100K) +#define MX25_PAD_CSI_D2__CSI_D2 IOMUX_PAD(CSI_D2, CSI_D2, 0x318, 0x120, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D2__UART5_RXD_MUX IOMUX_PAD(CSI_D2, UART5_RXD_MUX, 0x318, 0x120, 0x11, 0x578, 1, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D2__GPIO_1_27 IOMUX_PAD(CSI_D2, GPIO_1_27, 0x318, 0x120, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D3__CSI_D3 IOMUX_PAD(CSI_D3, CSI_D3, 0x31c, 0x124, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D3__GPIO_1_28 IOMUX_PAD(CSI_D3, GPIO_1_28, 0x31c, 0x124, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D4__CSI_D4 IOMUX_PAD(CSI_D4, CSI_D4, 0x320, 0x128, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D4__UART5_RTS IOMUX_PAD(CSI_D4, UART5_RTS, 0x320, 0x128, 0x11, 0x574, 1, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D4__GPIO_1_29 IOMUX_PAD(CSI_D4, GPIO_1_29, 0x320, 0x128, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D5__CSI_D5 IOMUX_PAD(CSI_D5, CSI_D5, 0x324, 0x12c, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D5__GPIO_1_30 IOMUX_PAD(CSI_D5, GPIO_1_30, 0x324, 0x12c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D6__CSI_D6 IOMUX_PAD(CSI_D6, CSI_D6, 0x328, 0x130, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D6__GPIO_1_31 IOMUX_PAD(CSI_D6, GPIO_1_31, 0x328, 0x130, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D7__CSI_D7 IOMUX_PAD(CSI_D7, CSI_D7, 0x32c, 0x134, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D7__GPIO_1_6 IOMUX_PAD(CSI_D7, GPIO_1_6, 0x32c, 0x134, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D8__CSI_D8 IOMUX_PAD(CSI_D8, CSI_D8, 0x330, 0x138, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D8__GPIO_1_7 IOMUX_PAD(CSI_D8, GPIO_1_7, 0x330, 0x138, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D9__CSI_D9 IOMUX_PAD(CSI_D9, CSI_D9, 0x334, 0x13c, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_D9__GPIO_4_21 IOMUX_PAD(CSI_D9, GPIO_4_21, 0x334, 0x13c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_MCLK__CSI_MCLK IOMUX_PAD(CSI_MCLK, CSI_MCLK, 0x338, 0x140, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_MCLK__GPIO_1_8 IOMUX_PAD(CSI_MCLK, GPIO_1_8, 0x338, 0x140, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_VSYNC__CSI_VSYNC IOMUX_PAD(CSI_VSYNC, CSI_VSYNC, 0x33c, 0x144, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_VSYNC__GPIO_1_9 IOMUX_PAD(CSI_VSYNC, GPIO_1_9, 0x33c, 0x144, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_HSYNC__CSI_HSYNC IOMUX_PAD(CSI_HSYNC, CSI_HSYNC, 0x340, 0x148, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_HSYNC__GPIO_1_10 IOMUX_PAD(CSI_HSYNC, GPIO_1_10, 0x340, 0x148, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_PIXCLK__CSI_PIXCLK IOMUX_PAD(CSI_PIXCLK, CSI_PIXCLK, 0x344, 0x14c, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSI_PIXCLK__GPIO_1_11 IOMUX_PAD(CSI_PIXCLK, GPIO_1_11, 0x344, 0x14c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_I2C1_CLK__I2C1_CLK IOMUX_PAD(I2C1_CLK, I2C1_CLK, 0x348, 0x150, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_I2C1_CLK__GPIO_1_12 IOMUX_PAD(I2C1_CLK, GPIO_1_12, 0x348, 0x150, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_I2C1_DAT__I2C1_DAT IOMUX_PAD(I2C1_DAT, I2C1_DAT, 0x34c, 0x154, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_I2C1_DAT__GPIO_1_13 IOMUX_PAD(I2C1_DAT, GPIO_1_13, 0x34c, 0x154, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSPI1_MOSI__CSPI1_MOSI IOMUX_PAD(CSPI1_MOSI, CSPI1_MOSI, 0x350, 0x158, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSPI1_MOSI__GPIO_1_14 IOMUX_PAD(CSPI1_MOSI, GPIO_1_14, 0x350, 0x158, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSPI1_MISO__CSPI1_MISO IOMUX_PAD(CSPI1_MISO, CSPI1_MISO, 0x354, 0x15c, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSPI1_MISO__GPIO_1_15 IOMUX_PAD(CSPI1_MISO, GPIO_1_15, 0x354, 0x15c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSPI1_SS0__CSPI1_SS0 IOMUX_PAD(CSPI1_SS0, CSPI1_SS0, 0x358, 0x160, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSPI1_SS0__GPIO_1_16 IOMUX_PAD(CSPI1_SS0, GPIO_1_16, 0x358, 0x160, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSPI1_SS1__CSPI1_SS1 IOMUX_PAD(CSPI1_SS1, CSPI1_SS1, 0x35c, 0x164, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSPI1_SS1__GPIO_1_17 IOMUX_PAD(CSPI1_SS1, GPIO_1_17, 0x35c, 0x164, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSPI1_SCLK__CSPI1_SCLK IOMUX_PAD(CSPI1_SCLK, CSPI1_SCLK, 0x360, 0x168, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSPI1_SCLK__GPIO_1_18 IOMUX_PAD(CSPI1_SCLK, GPIO_1_18, 0x360, 0x168, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CSPI1_RDY__CSPI1_RDY IOMUX_PAD(CSPI1_RDY, CSPI1_RDY, 0x364, 0x16c, 0x10, 0, 0, PAD_CTL_PULL_KEEPER) +#define MX25_PAD_CSPI1_RDY__GPIO_2_22 IOMUX_PAD(CSPI1_RDY, GPIO_2_22, 0x364, 0x16c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART1_RXD__UART1_RXD IOMUX_PAD(UART1_RXD, UART1_RXD, 0x368, 0x170, 0x10, 0, 0, PAD_CTL_PULL_DOWN_100K) +#define MX25_PAD_UART1_RXD__GPIO_4_22 IOMUX_PAD(UART1_RXD, GPIO_4_22, 0x368, 0x170, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART1_TXD__UART1_TXD IOMUX_PAD(UART1_TXD, UART1_TXD, 0x36c, 0x174, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART1_TXD__GPIO_4_23 IOMUX_PAD(UART1_TXD, GPIO_4_23, 0x36c, 0x174, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART1_RTS__UART1_RTS IOMUX_PAD(UART1_RTS, UART1_RTS, 0x370, 0x178, 0x10, 0, 0, PAD_CTL_PULL_UP_100K) +#define MX25_PAD_UART1_RTS__CSI_D0 IOMUX_PAD(UART1_RTS, CSI_D0, 0x370, 0x178, 0x11, 0x488, 1, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART1_RTS__GPIO_4_24 IOMUX_PAD(UART1_RTS, GPIO_4_24, 0x370, 0x178, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART1_CTS__UART1_CTS IOMUX_PAD(UART1_CTS, UART1_CTS, 0x374, 0x17c, 0x10, 0, 0, PAD_CTL_PULL_UP_100K) +#define MX25_PAD_UART1_CTS__CSI_D1 IOMUX_PAD(UART1_CTS, CSI_D1, 0x374, 0x17c, 0x11, 0x48c, 1, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART1_CTS__GPIO_4_25 IOMUX_PAD(UART1_CTS, GPIO_4_25, 0x374, 0x17c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART2_RXD__UART2_RXD IOMUX_PAD(UART2_RXD, UART2_RXD, 0x378, 0x180, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART2_RXD__GPIO_4_26 IOMUX_PAD(UART2_RXD, GPIO_4_26, 0x378, 0x180, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART2_TXD__UART2_TXD IOMUX_PAD(UART2_TXD, UART2_TXD, 0x37c, 0x184, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART2_TXD__GPIO_4_27 IOMUX_PAD(UART2_TXD, GPIO_4_27, 0x37c, 0x184, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART2_RTS__UART2_RTS IOMUX_PAD(UART2_RTS, UART2_RTS, 0x380, 0x188, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART2_RTS__FEC_COL IOMUX_PAD(UART2_RTS, FEC_COL, 0x380, 0x188, 0x12, 0x504, 2, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_UART2_RTS__GPIO_4_28 IOMUX_PAD(UART2_RTS, GPIO_4_28, 0x380, 0x188, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART2_CTS__FEC_RX_ER IOMUX_PAD(UART2_CTS, FEC_RX_ER, 0x384, 0x18c, 0x12, 0x518, 2, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_UART2_CTS__UART2_CTS IOMUX_PAD(UART2_CTS, UART2_CTS, 0x384, 0x18c, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_UART2_CTS__GPIO_4_29 IOMUX_PAD(UART2_CTS, GPIO_4_29, 0x384, 0x18c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_SD1_CMD__SD1_CMD IOMUX_PAD(SD1_CMD, SD1_CMD, 0x388, 0x190, 0x10, 0, 0, PAD_CTL_PULL_UP_47K | PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_SD1_CMD__FEC_RDATA2 IOMUX_PAD(SD1_CMD, FEC_RDATA2, 0x388, 0x190, 0x12, 0x50c, 2, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_SD1_CMD__GPIO_2_23 IOMUX_PAD(SD1_CMD, GPIO_2_23, 0x388, 0x190, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_SD1_CLK__SD1_CLK IOMUX_PAD(SD1_CLK, SD1_CLK, 0x38c, 0x194, 0x10, 0, 0, PAD_CTL_PULL_UP_47K | PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_SD1_CLK__FEC_RDATA3 IOMUX_PAD(SD1_CLK, FEC_RDATA3, 0x38c, 0x194, 0x12, 0x510, 2, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_SD1_CLK__GPIO_2_24 IOMUX_PAD(SD1_CLK, GPIO_2_24, 0x38c, 0x194, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_SD1_DATA0__SD1_DATA0 IOMUX_PAD(SD1_DATA0, SD1_DATA0, 0x390, 0x198, 0x10, 0, 0, PAD_CTL_PULL_UP_47K | PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_SD1_DATA0__GPIO_2_25 IOMUX_PAD(SD1_DATA0, GPIO_2_25, 0x390, 0x198, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_SD1_DATA1__SD1_DATA1 IOMUX_PAD(SD1_DATA1, SD1_DATA1, 0x394, 0x19c, 0x10, 0, 0, PAD_CTL_PULL_UP_47K | PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_SD1_DATA1__AUD7_RXD IOMUX_PAD(SD1_DATA1, AUD7_RXD, 0x394, 0x19c, 0x13, 0x478, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_SD1_DATA1__GPIO_2_26 IOMUX_PAD(SD1_DATA1, GPIO_2_26, 0x394, 0x19c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_SD1_DATA2__SD1_DATA2 IOMUX_PAD(SD1_DATA2, SD1_DATA2, 0x398, 0x1a0, 0x10, 0, 0, PAD_CTL_PULL_UP_47K | PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_SD1_DATA2__FEC_RX_CLK IOMUX_PAD(SD1_DATA2, FEC_RX_CLK, 0x398, 0x1a0, 0x15, 0x514, 2, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_SD1_DATA2__GPIO_2_27 IOMUX_PAD(SD1_DATA2, GPIO_2_27, 0x398, 0x1a0, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_SD1_DATA3__SD1_DATA3 IOMUX_PAD(SD1_DATA3, SD1_DATA3, 0x39c, 0x1a4, 0x10, 0, 0, PAD_CTL_PULL_UP_47K | PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_SD1_DATA3__FEC_CRS IOMUX_PAD(SD1_DATA3, FEC_CRS, 0x39c, 0x1a4, 0x10, 0x508, 2, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_SD1_DATA3__GPIO_2_28 IOMUX_PAD(SD1_DATA3, GPIO_2_28, 0x39c, 0x1a4, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_KPP_ROW0__KPP_ROW0 IOMUX_PAD(KPP_ROW0, KPP_ROW0, 0x3a0, 0x1a8, 0x10, 0, 0, PAD_CTL_PULL_KEEPER) +#define MX25_PAD_KPP_ROW0__GPIO_2_29 IOMUX_PAD(KPP_ROW0, GPIO_2_29, 0x3a0, 0x1a8, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_KPP_ROW1__KPP_ROW1 IOMUX_PAD(KPP_ROW1, KPP_ROW1, 0x3a4, 0x1ac, 0x10, 0, 0, PAD_CTL_PULL_KEEPER) +#define MX25_PAD_KPP_ROW1__GPIO_2_30 IOMUX_PAD(KPP_ROW1, GPIO_2_30, 0x3a4, 0x1ac, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_KPP_ROW2__KPP_ROW2 IOMUX_PAD(KPP_ROW2, KPP_ROW2, 0x3a8, 0x1b0, 0x10, 0, 0, PAD_CTL_PULL_KEEPER) +#define MX25_PAD_KPP_ROW2__CSI_D0 IOMUX_PAD(KPP_ROW2, CSI_D0, 0x3a8, 0x1b0, 0x13, 0x488, 2, 0 | NO_PAD_CTRL) +#define MX25_PAD_KPP_ROW2__GPIO_2_31 IOMUX_PAD(KPP_ROW2, GPIO_2_31, 0x3a8, 0x1b0, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_KPP_ROW3__KPP_ROW3 IOMUX_PAD(KPP_ROW3, KPP_ROW3, 0x3ac, 0x1b4, 0x10, 0, 0, PAD_CTL_PULL_KEEPER) +#define MX25_PAD_KPP_ROW3__CSI_LD1 IOMUX_PAD(KPP_ROW3, CSI_LD1, 0x3ac, 0x1b4, 0x13, 0x48c, 2, 0 | NO_PAD_CTRL) +#define MX25_PAD_KPP_ROW3__GPIO_3_0 IOMUX_PAD(KPP_ROW3, GPIO_3_0, 0x3ac, 0x1b4, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_KPP_COL0__KPP_COL0 IOMUX_PAD(KPP_COL0, KPP_COL0, 0x3b0, 0x1b8, 0x10, 0, 0, PAD_CTL_PULL_KEEPER | PAD_CTL_OUTPUT_OPEN_DRAIN) +#define MX25_PAD_KPP_COL0__GPIO_3_1 IOMUX_PAD(KPP_COL0, GPIO_3_1, 0x3b0, 0x1b8, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_KPP_COL1__KPP_COL1 IOMUX_PAD(KPP_COL1, KPP_COL1, 0x3b4, 0x1bc, 0x10, 0, 0, PAD_CTL_PULL_KEEPER | PAD_CTL_OUTPUT_OPEN_DRAIN) +#define MX25_PAD_KPP_COL1__GPIO_3_2 IOMUX_PAD(KPP_COL1, GPIO_3_2, 0x3b4, 0x1bc, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_KPP_COL2__KPP_COL2 IOMUX_PAD(KPP_COL2, KPP_COL2, 0x3b8, 0x1c0, 0x10, 0, 0, PAD_CTL_PULL_KEEPER | PAD_CTL_OUTPUT_OPEN_DRAIN) +#define MX25_PAD_KPP_COL2__GPIO_3_3 IOMUX_PAD(KPP_COL2, GPIO_3_3, 0x3b8, 0x1c0, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_KPP_COL3__KPP_COL3 IOMUX_PAD(KPP_COL3, KPP_COL3, 0x3bc, 0x1c4, 0x10, 0, 0, PAD_CTL_PULL_KEEPER | PAD_CTL_OUTPUT_OPEN_DRAIN) +#define MX25_PAD_KPP_COL3__GPIO_3_4 IOMUX_PAD(KPP_COL3, GPIO_3_4, 0x3bc, 0x1c4, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_FEC_MDC__FEC_MDC IOMUX_PAD(FEC_MDC, FEC_MDC, 0x3c0, 0x1c8, 0x10, 0, 0, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_FEC_MDC__AUD4_TXD IOMUX_PAD(FEC_MDC, AUD4_TXD, 0x3c0, 0x1c8, 0x12, 0x464, 1, 0 | NO_PAD_CTRL) +#define MX25_PAD_FEC_MDC__GPIO_3_5 IOMUX_PAD(FEC_MDC, GPIO_3_5, 0x3c0, 0x1c8, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_FEC_MDIO__FEC_MDIO IOMUX_PAD(FEC_MDIO, FEC_MDIO, 0x3c4, 0x1cc, 0x10, 0, 0, PAD_CTL_HYSTERESIS | PAD_CTL_PULL_UP_22K | PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_FEC_MDIO__AUD4_RXD IOMUX_PAD(FEC_MDIO, AUD4_RXD, 0x3c4, 0x1cc, 0x12, 0x460, 1, 0 | NO_PAD_CTRL) +#define MX25_PAD_FEC_MDIO__GPIO_3_6 IOMUX_PAD(FEC_MDIO, GPIO_3_6, 0x3c4, 0x1cc, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_FEC_TDATA0__FEC_TDATA0 IOMUX_PAD(FEC_TDATA0, FEC_TDATA0, 0x3c8, 0x1d0, 0x10, 0, 0, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_FEC_TDATA0__GPIO_3_7 IOMUX_PAD(FEC_TDATA0, GPIO_3_7, 0x3c8, 0x1d0, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_FEC_TDATA1__FEC_TDATA1 IOMUX_PAD(FEC_TDATA1, FEC_TDATA1, 0x3cc, 0x1d4, 0x10, 0, 0, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_FEC_TDATA1__AUD4_TXFS IOMUX_PAD(FEC_TDATA1, AUD4_TXFS, 0x3cc, 0x1d4, 0x12, 0x474, 1, 0 | NO_PAD_CTRL) +#define MX25_PAD_FEC_TDATA1__GPIO_3_8 IOMUX_PAD(FEC_TDATA1, GPIO_3_8, 0x3cc, 0x1d4, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_FEC_TX_EN__FEC_TX_EN IOMUX_PAD(FEC_TX_EN, FEC_TX_EN, 0x3d0, 0x1d8, 0x10, 0, 0, PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_FEC_TX_EN__GPIO_3_9 IOMUX_PAD(FEC_TX_EN, GPIO_3_9 , 0x3d0, 0x1d8, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_FEC_RDATA0__FEC_RDATA0 IOMUX_PAD(FEC_RDATA0, FEC_RDATA0, 0x3d4, 0x1dc, 0x10, 0, 0, PAD_CTL_PULL_DOWN_100K | PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_FEC_RDATA0__GPIO_3_10 IOMUX_PAD(FEC_RDATA0, GPIO_3_10, 0x3d4, 0x1dc, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_FEC_RDATA1__FEC_RDATA1 IOMUX_PAD(FEC_RDATA1, FEC_RDATA1, 0x3d8, 0x1e0, 0x10, 0, 0, PAD_CTL_PULL_DOWN_100K | PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_FEC_RDATA1__GPIO_3_11 IOMUX_PAD(FEC_RDATA1, GPIO_3_11, 0x3d8, 0x1e0, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_FEC_RX_DV__FEC_RX_DV IOMUX_PAD(FEC_RX_DV, FEC_RX_DV, 0x3dc, 0x1e4, 0x10, 0, 0, PAD_CTL_PULL_DOWN_100K | PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_FEC_RX_DV__CAN2_RX IOMUX_PAD(FEC_RX_DV, CAN2_RX, 0x3dc, 0x1e4, 0x14, 0x484, 0, PAD_CTL_PULL_UP_22K) +#define MX25_PAD_FEC_RX_DV__GPIO_3_12 IOMUX_PAD(FEC_RX_DV, GPIO_3_12, 0x3dc, 0x1e4, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_FEC_TX_CLK__FEC_TX_CLK IOMUX_PAD(FEC_TX_CLK, FEC_TX_CLK, 0x3e0, 0x1e8, 0x10, 0, 0, PAD_CTL_HYSTERESIS | PAD_CTL_PULL_DOWN_100K | PAD_CTL_SLEW_RATE_FAST) +#define MX25_PAD_FEC_TX_CLK__GPIO_3_13 IOMUX_PAD(FEC_TX_CLK, GPIO_3_13, 0x3e0, 0x1e8, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_RTCK__RTCK IOMUX_PAD(RTCK, RTCK, 0x3e4, 0x1ec, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_RTCK__OWIRE IOMUX_PAD(RTCK, OWIRE, 0x3e4, 0x1ec, 0x11, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_RTCK__GPIO_3_14 IOMUX_PAD(RTCK, GPIO_3_14, 0x3e4, 0x1ec, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_DE_B__DE_B IOMUX_PAD(DE_B, DE_B, 0x3ec, 0x1f0, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_DE_B__GPIO_2_20 IOMUX_PAD(DE_B, GPIO_2_20, 0x3ec, 0x1f0, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_TDO__TDO IOMUX_PAD(TDO, TDO, 0x3e8, 0x000, 0x00, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_GPIO_A__GPIO_A IOMUX_PAD(GPIO_A, GPIO_A, 0x3f0, 0x1f4, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_GPIO_A__CAN1_TX IOMUX_PAD(GPIO_A, CAN1_TX, 0x3f0, 0x1f4, 0x16, 0, 0, PAD_CTL_PULL_UP_22K | PAD_CTL_OUTPUT_OPEN_DRAIN | PAD_CTL_DRIVE_STRENGTH_MAX) +#define MX25_PAD_GPIO_A__USBOTG_PWR IOMUX_PAD(GPIO_A, USBOTG_PWR, 0x3f0, 0x1f4, 0x12, 0, 0, PAD_CTL_PULL_KEEPER) +#define MX25_PAD_GPIO_B__GPIO_B IOMUX_PAD(GPIO_B, GPIO_B, 0x3f4, 0x1f8, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_GPIO_B__CAN1_RX IOMUX_PAD(GPIO_B, CAN1_RX, 0x3f4, 0x1f8, 0x16, 0x480, 1, PAD_CTL_PULL_UP_22K | PAD_CTL_OUTPUT_OPEN_DRAIN) +#define MX25_PAD_GPIO_B__USBOTG_OC IOMUX_PAD(GPIO_B, USBOTG_OC, 0x3f4, 0x1f8, 0x12, 0x57c, 1, PAD_CTL_PULL_UP_100K) +#define MX25_PAD_GPIO_C__GPIO_C IOMUX_PAD(GPIO_C, GPIO_C, 0x3f8, 0x1fc, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_GPIO_C__CAN2_TX IOMUX_PAD(GPIO_C, CAN2_TX, 0x3f8, 0x1fc, 0x16, 0, 0, PAD_CTL_PULL_UP_22K | PAD_CTL_OUTPUT_OPEN_DRAIN | PAD_CTL_DRIVE_STRENGTH_MAX) +#define MX25_PAD_GPIO_D__GPIO_D IOMUX_PAD(GPIO_D, GPIO_D, 0x3fc, 0x200, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_GPIO_D__CAN2_RX IOMUX_PAD(GPIO_D, CAN2_RX, 0x3fc, 0x200, 0x16, 0x484, 1, PAD_CTL_PULL_UP_22K) +#define MX25_PAD_GPIO_E__GPIO_E IOMUX_PAD(GPIO_E, GPIO_E, 0x400, 0x204, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_GPIO_E__AUD7_TXD IOMUX_PAD(GPIO_E, AUD7_TXD, 0x400, 0x204, 0x14, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_GPIO_F__GPIO_F IOMUX_PAD(GPIO_F, GPIO_F, 0x404, 0x208, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_GPIO_F__AUD7_TXC IOMUX_PAD(GPIO_F, AUD7_TXC, 0x404, 0x208, 0x14, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_EXT_ARMCLK__EXT_ARMCLK IOMUX_PAD(EXT_ARMCLK, EXT_ARMCLK, 0x000, 0x20c, 0x10, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_EXT_ARMCLK__GPIO_3_15 IOMUX_PAD(EXT_ARMCLK, GPIO_3_15, 0x000, 0x20c, 0x15, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_UPLL_BYPCLK__UPLL_BYPCLK IOMUX_PAD(UPLL_BYPCLK, UPLL_BYPCLK, 0x000, 0x210, 0x10, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_UPLL_BYPCLK__GPIO_3_16 IOMUX_PAD(UPLL_BYPCLK, GPIO_3_16, 0x000, 0x210, 0x15, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_VSTBY_REQ__VSTBY_REQ IOMUX_PAD(VSTBY_REQ, VSTBY_REQ, 0x408, 0x214, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_VSTBY_REQ__AUD7_TXFS IOMUX_PAD(VSTBY_REQ, AUD7_TXFS, 0x408, 0x214, 0x14, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_VSTBY_REQ__GPIO_3_17 IOMUX_PAD(VSTBY_REQ, GPIO_3_17, 0x408, 0x214, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_VSTBY_ACK__VSTBY_ACK IOMUX_PAD(VSTBY_ACK, VSTBY_ACK, 0x40c, 0x218, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_VSTBY_ACK__GPIO_3_18 IOMUX_PAD(VSTBY_ACK, GPIO_3_18, 0x40c, 0x218, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_POWER_FAIL__POWER_FAIL IOMUX_PAD(POWER_FAIL, POWER_FAIL, 0x410, 0x21c, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_POWER_FAIL__AUD7_RXD IOMUX_PAD(POWER_FAIL, AUD7_RXD, 0x410, 0x21c, 0x14, 0x478, 1, 0 | NO_PAD_CTRL) +#define MX25_PAD_POWER_FAIL__GPIO_3_19 IOMUX_PAD(POWER_FAIL, GPIO_3_19, 0x410, 0x21c, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CLKO__CLKO IOMUX_PAD(CLKO, CLKO, 0x414, 0x220, 0x10, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_CLKO__GPIO_2_21 IOMUX_PAD(CLKO, GPIO_2_21, 0x414, 0x220, 0x15, 0, 0, 0 | NO_PAD_CTRL) +#define MX25_PAD_BOOT_MODE0__BOOT_MODE0 IOMUX_PAD(BOOT_MODE0, BOOT_MODE0, 0x000, 0x224, 0x00, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_BOOT_MODE0__GPIO_4_30 IOMUX_PAD(BOOT_MODE0, GPIO_4_30, 0x000, 0x224, 0x05, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_BOOT_MODE1__BOOT_MODE1 IOMUX_PAD(BOOT_MODE1, BOOT_MODE1, 0x000, 0x228, 0x00, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_BOOT_MODE1__GPIO_4_31 IOMUX_PAD(BOOT_MODE1, GPIO_4_31, 0x000, 0x228, 0x05, 0, 0, NO_PAD_CTRL) + +#define MX25_PAD_CTL_GRP_DVS_MISC IOMUX_PAD(0x418, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DSE_FEC IOMUX_PAD(0x41c, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DVS_JTAG IOMUX_PAD(0x420, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DSE_NFC IOMUX_PAD(0x424, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DSE_CSI IOMUX_PAD(0x428, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DSE_WEIM IOMUX_PAD(0x42c, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DSE_DDR IOMUX_PAD(0x430, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DVS_CRM IOMUX_PAD(0x434, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DSE_KPP IOMUX_PAD(0x438, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DSE_SDHC1 IOMUX_PAD(0x43c, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DSE_LCD IOMUX_PAD(0x440, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DSE_UART IOMUX_PAD(0x444, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DVS_NFC IOMUX_PAD(0x448, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DVS_CSI IOMUX_PAD(0x44c, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DSE_CSPI1 IOMUX_PAD(0x450, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DDRTYPE IOMUX_PAD(0x454, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DVS_SDHC1 IOMUX_PAD(0x458, 0x000, 0, 0, 0, NO_PAD_CTRL) +#define MX25_PAD_CTL_GRP_DVS_LCD IOMUX_PAD(0x45c, 0x000, 0, 0, 0, NO_PAD_CTRL) + +#define IOMUX_TO_GPIO(__pad_desc) ({ \ + int __gpio = -1; \ + struct pad_desc *__pd = __pad_desc; \ + \ + switch (__pd->mux_ctrl_ofs) { \ + case MX25_PAD_GPIO_A__GPIO_A: \ + __gpio = GPIO_A; \ + break; \ + case MX25_PAD_GPIO_B__GPIO_B: \ + __gpio = GPIO_B; \ + break; \ + case MX25_PAD_GPIO_C__GPIO_C: \ + __gpio = GPIO_C; \ + break; \ + case MX25_PAD_GPIO_D__GPIO_D: \ + __gpio = GPIO_D; \ + break; \ + case MX25_PAD_GPIO_E__GPIO_E: \ + __gpio = GPIO_E; \ + break; \ + case MX25_PAD_GPIO_F__GPIO_F: \ + __gpio = GPIO_F; \ + break; \ + case MX25_PAD_CSI_D7__GPIO_1_6: \ + __gpio = GPIO_1_6; \ + break; \ + case MX25_PAD_CSI_D8__GPIO_1_7: \ + __gpio = GPIO_1_7; \ + break; \ + case MX25_PAD_CSI_MCLK__GPIO_1_8: \ + __gpio = GPIO_1_8; \ + break; \ + case MX25_PAD_CSI_VSYNC__GPIO_1_9: \ + __gpio = GPIO_1_9; \ + break; \ + case MX25_PAD_CSI_HSYNC__GPIO_1_10: \ + __gpio = GPIO_1_10; \ + break; \ + case MX25_PAD_CSI_PIXCLK__GPIO_1_11: \ + __gpio = GPIO_1_11; \ + break; \ + case MX25_PAD_I2C1_CLK__GPIO_1_12: \ + __gpio = GPIO_1_12; \ + break; \ + case MX25_PAD_I2C1_DAT__GPIO_1_13: \ + __gpio = GPIO_1_13; \ + break; \ + case MX25_PAD_CSPI1_MOSI__GPIO_1_14: \ + __gpio = GPIO_1_14; \ + break; \ + case MX25_PAD_CSPI1_MISO__GPIO_1_15: \ + __gpio = GPIO_1_15; \ + break; \ + case MX25_PAD_CSPI1_SS0__GPIO_1_16: \ + __gpio = GPIO_1_16; \ + break; \ + case MX25_PAD_CSPI1_SS1__GPIO_1_17: \ + __gpio = GPIO_1_17; \ + break; \ + case MX25_PAD_CSPI1_SCLK__GPIO_1_18: \ + __gpio = GPIO_1_18; \ + break; \ + case MX25_PAD_LD5__GPIO_1_19: \ + __gpio = GPIO_1_19; \ + break; \ + case MX25_PAD_LD6__GPIO_1_20: \ + __gpio = GPIO_1_20; \ + break; \ + case MX25_PAD_LD7__GPIO_1_21: \ + __gpio = GPIO_1_21; \ + break; \ + case MX25_PAD_HSYNC__GPIO_1_22: \ + __gpio = GPIO_1_22; \ + break; \ + case MX25_PAD_VSYNC__GPIO_1_23: \ + __gpio = GPIO_1_23; \ + break; \ + case MX25_PAD_LSCLK__GPIO_1_24: \ + __gpio = GPIO_1_24; \ + break; \ + case MX25_PAD_OE_ACD__GPIO_1_25: \ + __gpio = GPIO_1_25; \ + break; \ + case MX25_PAD_PWM__GPIO_1_26: \ + __gpio = GPIO_1_26; \ + break; \ + case MX25_PAD_CSI_D2__GPIO_1_27: \ + __gpio = GPIO_1_27; \ + break; \ + case MX25_PAD_CSI_D3__GPIO_1_28: \ + __gpio = GPIO_1_28; \ + break; \ + case MX25_PAD_CSI_D4__GPIO_1_29: \ + __gpio = GPIO_1_29; \ + break; \ + case MX25_PAD_CSI_D5__GPIO_1_30: \ + __gpio = GPIO_1_30; \ + break; \ + case MX25_PAD_CSI_D6__GPIO_1_31: \ + __gpio = GPIO_1_31; \ + break; \ + \ + case MX25_PAD_A14__GPIO_2_0: \ + __gpio = GPIO_2_0; \ + break; \ + case MX25_PAD_A15__GPIO_2_1: \ + __gpio = GPIO_2_1; \ + break; \ + case MX25_PAD_A16__GPIO_2_2: \ + __gpio = GPIO_2_2; \ + break; \ + case MX25_PAD_A17__GPIO_2_3: \ + __gpio = GPIO_2_3; \ + break; \ + case MX25_PAD_A18__GPIO_2_4: \ + __gpio = GPIO_2_4; \ + break; \ + case MX25_PAD_A19__GPIO_2_5: \ + __gpio = GPIO_2_5; \ + break; \ + case MX25_PAD_A20__GPIO_2_6: \ + __gpio = GPIO_2_6; \ + break; \ + case MX25_PAD_A21__GPIO_2_7: \ + __gpio = GPIO_2_7; \ + break; \ + case MX25_PAD_A22__GPIO_2_8: \ + __gpio = GPIO_2_8; \ + break; \ + case MX25_PAD_A23__GPIO_2_9: \ + __gpio = GPIO_2_9; \ + break; \ + case MX25_PAD_A24__GPIO_2_10: \ + __gpio = GPIO_2_10; \ + break; \ + case MX25_PAD_A25__GPIO_2_11: \ + __gpio = GPIO_2_11; \ + break; \ + case MX25_PAD_EB0__GPIO_2_12: \ + __gpio = GPIO_2_12; \ + break; \ + case MX25_PAD_EB1__GPIO_2_13: \ + __gpio = GPIO_2_13; \ + break; \ + case MX25_PAD_OE__GPIO_2_14: \ + __gpio = GPIO_2_14; \ + break; \ + case MX25_PAD_LD0__GPIO_2_15: \ + __gpio = GPIO_2_15; \ + break; \ + case MX25_PAD_LD1__GPIO_2_16: \ + __gpio = GPIO_2_16; \ + break; \ + case MX25_PAD_LD2__GPIO_2_17: \ + __gpio = GPIO_2_17; \ + break; \ + case MX25_PAD_LD3__GPIO_2_18: \ + __gpio = GPIO_2_18; \ + break; \ + case MX25_PAD_LD4__GPIO_2_19: \ + __gpio = GPIO_2_19; \ + break; \ + case MX25_PAD_DE_B__GPIO_2_20: \ + __gpio = GPIO_2_20; \ + break; \ + case MX25_PAD_CLKO__GPIO_2_21: \ + __gpio = GPIO_2_21; \ + break; \ + case MX25_PAD_CSPI1_RDY__GPIO_2_22: \ + __gpio = GPIO_2_22; \ + break; \ + case MX25_PAD_SD1_CMD__GPIO_2_23: \ + __gpio = GPIO_2_23; \ + break; \ + case MX25_PAD_SD1_CLK__GPIO_2_24: \ + __gpio = GPIO_2_24; \ + break; \ + case MX25_PAD_SD1_DATA0__GPIO_2_25: \ + __gpio = GPIO_2_25; \ + break; \ + case MX25_PAD_SD1_DATA1__GPIO_2_26: \ + __gpio = GPIO_2_26; \ + break; \ + case MX25_PAD_SD1_DATA2__GPIO_2_27: \ + __gpio = GPIO_2_27; \ + break; \ + case MX25_PAD_SD1_DATA3__GPIO_2_28: \ + __gpio = GPIO_2_28; \ + break; \ + case MX25_PAD_KPP_ROW0__GPIO_2_29: \ + __gpio = GPIO_2_29; \ + break; \ + case MX25_PAD_KPP_ROW1__GPIO_2_30: \ + __gpio = GPIO_2_30; \ + break; \ + case MX25_PAD_KPP_ROW2__GPIO_2_31: \ + __gpio = GPIO_2_31; \ + break; \ + \ + case MX25_PAD_KPP_ROW3__GPIO_3_0: \ + __gpio = GPIO_3_0; \ + break; \ + case MX25_PAD_KPP_COL0__GPIO_3_1: \ + __gpio = GPIO_3_1; \ + break; \ + case MX25_PAD_KPP_COL1__GPIO_3_2: \ + __gpio = GPIO_3_2; \ + break; \ + case MX25_PAD_KPP_COL2__GPIO_3_3: \ + __gpio = GPIO_3_3; \ + break; \ + case MX25_PAD_KPP_COL3__GPIO_3_4: \ + __gpio = GPIO_3_4; \ + break; \ + case MX25_PAD_FEC_MDC__GPIO_3_5: \ + __gpio = GPIO_3_5; \ + break; \ + case MX25_PAD_FEC_MDIO__GPIO_3_6: \ + __gpio = GPIO_3_6; \ + break; \ + case MX25_PAD_FEC_TDATA0__GPIO_3_7: \ + __gpio = GPIO_3_7; \ + break; \ + case MX25_PAD_FEC_TDATA1__GPIO_3_8: \ + __gpio = GPIO_3_8; \ + break; \ + case MX25_PAD_FEC_TX_EN__GPIO_3_9: \ + __gpio = GPIO_3_9; \ + break; \ + case MX25_PAD_FEC_RDATA0__GPIO_3_10: \ + __gpio = GPIO_3_10; \ + break; \ + case MX25_PAD_FEC_RDATA1__GPIO_3_11: \ + __gpio = GPIO_3_11; \ + break; \ + case MX25_PAD_FEC_RX_DV__GPIO_3_12: \ + __gpio = GPIO_3_12; \ + break; \ + case MX25_PAD_FEC_TX_CLK__GPIO_3_13: \ + __gpio = GPIO_3_13; \ + break; \ + case MX25_PAD_RTCK__GPIO_3_14: \ + __gpio = GPIO_3_14; \ + break; \ + case MX25_PAD_EXT_ARMCLK__GPIO_3_15: \ + __gpio = GPIO_3_15; \ + break; \ + case MX25_PAD_UPLL_BYPCLK__GPIO_3_16: \ + __gpio = GPIO_3_16; \ + break; \ + case MX25_PAD_VSTBY_REQ__GPIO_3_17: \ + __gpio = GPIO_3_17; \ + break; \ + case MX25_PAD_VSTBY_ACK__GPIO_3_18: \ + __gpio = GPIO_3_18; \ + break; \ + case MX25_PAD_POWER_FAIL__GPIO_3_19: \ + __gpio = GPIO_3_19; \ + break; \ + case MX25_PAD_CS4__GPIO_3_20: \ + __gpio = GPIO_3_20; \ + break; \ + case MX25_PAD_CS5__GPIO_3_21: \ + __gpio = GPIO_3_21; \ + break; \ + case MX25_PAD_NF_CE0__GPIO_3_22: \ + __gpio = GPIO_3_22; \ + break; \ + case MX25_PAD_ECB__GPIO_3_23: \ + __gpio = GPIO_3_23; \ + break; \ + case MX25_PAD_LBA__GPIO_3_24: \ + __gpio = GPIO_3_24; \ + break; \ + case MX25_PAD_RW__GPIO_3_25: \ + __gpio = GPIO_3_25; \ + break; \ + case MX25_PAD_NFWE_B__GPIO_3_26: \ + __gpio = GPIO_3_26; \ + break; \ + case MX25_PAD_NFRE_B__GPIO_3_27: \ + __gpio = GPIO_3_27; \ + break; \ + case MX25_PAD_NFALE__GPIO_3_28: \ + __gpio = GPIO_3_28; \ + break; \ + case MX25_PAD_NFCLE__GPIO_3_29: \ + __gpio = GPIO_3_29; \ + break; \ + case MX25_PAD_NFWP_B__GPIO_3_30: \ + __gpio = GPIO_3_30; \ + break; \ + case MX25_PAD_NFRB__GPIO_3_31: \ + __gpio = GPIO_3_31; \ + break; \ + \ + case MX25_PAD_A10__GPIO_4_0: \ + __gpio = GPIO_4_0; \ + break; \ + case MX25_PAD_A13__GPIO_4_1: \ + __gpio = GPIO_4_1; \ + break; \ + case MX25_PAD_CS0__GPIO_4_2: \ + __gpio = GPIO_4_2; \ + break; \ + case MX25_PAD_CS1__GPIO_4_3: \ + __gpio = GPIO_4_3; \ + break; \ + case MX25_PAD_BCLK__GPIO_4_4: \ + __gpio = GPIO_4_4; \ + break; \ + case MX25_PAD_D15__GPIO_4_5: \ + __gpio = GPIO_4_5; \ + break; \ + case MX25_PAD_D14__GPIO_4_6: \ + __gpio = GPIO_4_6; \ + break; \ + case MX25_PAD_D13__GPIO_4_7: \ + __gpio = GPIO_4_7; \ + break; \ + case MX25_PAD_D12__GPIO_4_8: \ + __gpio = GPIO_4_8; \ + break; \ + case MX25_PAD_D11__GPIO_4_9: \ + __gpio = GPIO_4_9; \ + break; \ + case MX25_PAD_D10__GPIO_4_10: \ + __gpio = GPIO_4_10; \ + break; \ + case MX25_PAD_D9__GPIO_4_11: \ + __gpio = GPIO_4_11; \ + break; \ + case MX25_PAD_D8__GPIO_4_12: \ + __gpio = GPIO_4_12; \ + break; \ + case MX25_PAD_D7__GPIO_4_13: \ + __gpio = GPIO_4_13; \ + break; \ + case MX25_PAD_D6__GPIO_4_14: \ + __gpio = GPIO_4_14; \ + break; \ + case MX25_PAD_D5__GPIO_4_15: \ + __gpio = GPIO_4_15; \ + break; \ + case MX25_PAD_D4__GPIO_4_16: \ + __gpio = GPIO_4_16; \ + break; \ + case MX25_PAD_D3__GPIO_4_17: \ + __gpio = GPIO_4_17; \ + break; \ + case MX25_PAD_D2__GPIO_4_18: \ + __gpio = GPIO_4_18; \ + break; \ + case MX25_PAD_D1__GPIO_4_19: \ + __gpio = GPIO_4_19; \ + break; \ + case MX25_PAD_D0__GPIO_4_20: \ + __gpio = GPIO_4_20; \ + break; \ + case MX25_PAD_CSI_D9__GPIO_4_21: \ + __gpio = GPIO_4_21; \ + break; \ + case MX25_PAD_UART1_RXD__GPIO_4_22: \ + __gpio = GPIO_4_22; \ + break; \ + case MX25_PAD_UART1_TXD__GPIO_4_23: \ + __gpio = GPIO_4_23; \ + break; \ + case MX25_PAD_UART1_RTS__GPIO_4_24: \ + __gpio = GPIO_4_24; \ + break; \ + case MX25_PAD_UART1_CTS__GPIO_4_25: \ + __gpio = GPIO_4_25; \ + break; \ + case MX25_PAD_UART2_RXD__GPIO_4_26: \ + __gpio = GPIO_4_26; \ + break; \ + case MX25_PAD_UART2_TXD__GPIO_4_27: \ + __gpio = GPIO_4_27; \ + break; \ + case MX25_PAD_UART2_RTS__GPIO_4_28: \ + __gpio = GPIO_4_28; \ + break; \ + case MX25_PAD_UART2_CTS__GPIO_4_29: \ + __gpio = GPIO_4_29; \ + break; \ + case MX25_PAD_BOOT_MODE0__GPIO_4_30: \ + __gpio = GPIO_4_30; \ + break; \ + case MX25_PAD_BOOT_MODE1__GPIO_4_31: \ + __gpio = GPIO_4_31; \ + break; \ + } \ + __gpio; \ +}) + +#endif // __ASSEMBLY__ +#endif // __IOMUX_MX25_H__ diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/iomux-v3.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/iomux-v3.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/iomux-v3.h 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/iomux-v3.h 2009-06-25 15:27:32.000000000 +0200 @@ -52,44 +52,63 @@ struct pad_desc { unsigned pad_ctrl:17; unsigned select_input_ofs:12; /* IOMUXC_SELECT_INPUT offset */ unsigned select_input:3; +#ifdef IOMUX_DEBUG + char *name; +#endif }; -#define IOMUX_PAD(_pad_ctrl_ofs, _mux_ctrl_ofs, _mux_mode, _select_input_ofs, \ - _select_input, _pad_ctrl) \ - { \ - .mux_ctrl_ofs = _mux_ctrl_ofs, \ - .mux_mode = _mux_mode, \ - .pad_ctrl_ofs = _pad_ctrl_ofs, \ - .pad_ctrl = _pad_ctrl, \ - .select_input_ofs = _select_input_ofs, \ - .select_input = _select_input, \ +#ifdef IOMUX_DEBUG +#define MXC_PAD_NAME(pd) (pd)->name +#define IOMUX_PAD(_pad, _func, _pad_ctrl_ofs, _mux_ctrl_ofs, _mux_mode, _select_input_ofs, \ + _select_input, _pad_ctrl) \ + { \ + .mux_ctrl_ofs = _mux_ctrl_ofs, \ + .mux_mode = _mux_mode, \ + .pad_ctrl_ofs = _pad_ctrl_ofs, \ + .pad_ctrl = _pad_ctrl, \ + .select_input_ofs = _select_input_ofs, \ + .select_input = _select_input, \ + .name = #_pad"__"#_func, \ } +#else +#define MXC_PAD_NAME(pd) "" +#define IOMUX_PAD(_pad, _func, _pad_ctrl_ofs, _mux_ctrl_ofs, _mux_mode, _select_input_ofs, \ + _select_input, _pad_ctrl) \ + { \ + .mux_ctrl_ofs = _mux_ctrl_ofs, \ + .mux_mode = _mux_mode, \ + .pad_ctrl_ofs = _pad_ctrl_ofs, \ + .pad_ctrl = _pad_ctrl, \ + .select_input_ofs = _select_input_ofs, \ + .select_input = _select_input, \ + } +#endif /* * Use to set PAD control */ -#define PAD_CTL_DRIVE_VOLTAGE_3_3_V 0 -#define PAD_CTL_DRIVE_VOLTAGE_1_8_V 1 +#define PAD_CTL_DRIVE_VOLTAGE_3_3_V (0 << 13) +#define PAD_CTL_DRIVE_VOLTAGE_1_8_V (1 << 13) -#define PAD_CTL_NO_HYSTERESIS 0 -#define PAD_CTL_HYSTERESIS 1 +#define PAD_CTL_NO_HYSTERESIS (0 << 8) +#define PAD_CTL_HYSTERESIS (1 << 8) -#define PAD_CTL_PULL_DISABLED 0x0 -#define PAD_CTL_PULL_KEEPER 0xa -#define PAD_CTL_PULL_DOWN_100K 0xc -#define PAD_CTL_PULL_UP_47K 0xd -#define PAD_CTL_PULL_UP_100K 0xe -#define PAD_CTL_PULL_UP_22K 0xf - -#define PAD_CTL_OUTPUT_CMOS 0 -#define PAD_CTL_OUTPUT_OPEN_DRAIN 1 - -#define PAD_CTL_DRIVE_STRENGTH_NORM 0 -#define PAD_CTL_DRIVE_STRENGTH_HIGH 1 -#define PAD_CTL_DRIVE_STRENGTH_MAX 2 +#define PAD_CTL_PULL_DISABLED (0x0 << 4) +#define PAD_CTL_PULL_KEEPER (0x8 << 4) +#define PAD_CTL_PULL_DOWN_100K (0xc << 4) +#define PAD_CTL_PULL_UP_47K (0xd << 4) +#define PAD_CTL_PULL_UP_100K (0xe << 4) +#define PAD_CTL_PULL_UP_22K (0xf << 4) + +#define PAD_CTL_OUTPUT_CMOS (0 << 3) +#define PAD_CTL_OUTPUT_OPEN_DRAIN (1 << 3) + +#define PAD_CTL_DRIVE_STRENGTH_NORM (0 << 1) +#define PAD_CTL_DRIVE_STRENGTH_HIGH (1 << 1) +#define PAD_CTL_DRIVE_STRENGTH_MAX (2 << 1) -#define PAD_CTL_SLEW_RATE_SLOW 0 -#define PAD_CTL_SLEW_RATE_FAST 1 +#define PAD_CTL_SLEW_RATE_SLOW (0 << 0) +#define PAD_CTL_SLEW_RATE_FAST (1 << 0) /* * setups a single pad: diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/iomux.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/iomux.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/iomux.h 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/iomux.h 2009-06-02 18:02:08.000000000 +0200 @@ -24,10 +24,14 @@ * GPIO Module and I/O Multiplexer * x = 0..3 for reg_A, reg_B, reg_C, reg_D */ +#ifndef CONFIG_MACH_MX25 #define VA_GPIO_BASE IO_ADDRESS(GPIO_BASE_ADDR) +#endif #define MXC_DDIR(x) (0x00 + ((x) << 8)) +#ifndef CONFIG_MACH_MX25 #define MXC_OCR1(x) (0x04 + ((x) << 8)) #define MXC_OCR2(x) (0x08 + ((x) << 8)) +#endif #define MXC_ICONFA1(x) (0x0c + ((x) << 8)) #define MXC_ICONFA2(x) (0x10 + ((x) << 8)) #define MXC_ICONFB1(x) (0x14 + ((x) << 8)) @@ -96,16 +100,20 @@ #ifdef CONFIG_ARCH_MX1 -#include +# include #endif #ifdef CONFIG_ARCH_MX2 -#include -#ifdef CONFIG_MACH_MX21 -#include -#endif -#ifdef CONFIG_MACH_MX27 -#include -#endif +# ifndef CONFIG_MACH_MX25 +# include +# ifdef CONFIG_MACH_MX21 +# include +# endif +# endif +# ifdef CONFIG_MACH_MX27 +# include +# else +# include +# endif #endif diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/irqs.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/irqs.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/irqs.h 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/irqs.h 2009-06-02 18:02:09.000000000 +0200 @@ -21,7 +21,11 @@ #if defined CONFIG_ARCH_MX1 #define MXC_GPIO_IRQS (32 * 4) #elif defined CONFIG_ARCH_MX2 +#ifndef CONFIG_MACH_MX25 #define MXC_GPIO_IRQS (32 * 6) +#else +#define MXC_GPIO_IRQS (32 * 4) +#endif #elif defined CONFIG_ARCH_MX3 #define MXC_GPIO_IRQS (32 * 3) #endif diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/memory.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/memory.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/memory.h 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/memory.h 2009-06-02 18:02:09.000000000 +0200 @@ -14,12 +14,13 @@ #if defined CONFIG_ARCH_MX1 #define PHYS_OFFSET UL(0x08000000) #elif defined CONFIG_ARCH_MX2 -#ifdef CONFIG_MACH_MX21 +# if defined(CONFIG_MACH_MX21) #define PHYS_OFFSET UL(0xC0000000) -#endif -#ifdef CONFIG_MACH_MX27 +# elif defined(CONFIG_MACH_MX27) #define PHYS_OFFSET UL(0xA0000000) -#endif +# elif defined(CONFIG_MACH_MX25) +#define PHYS_OFFSET UL(0x80000000) +# endif #elif defined CONFIG_ARCH_MX3 #define PHYS_OFFSET UL(0x80000000) #endif diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/mx25.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/mx25.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/mx25.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/mx25.h 2009-07-01 11:21:51.000000000 +0200 @@ -0,0 +1,483 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file arch-mxc/mx25.h + * @brief This file contains register definitions. + * + * @ingroup MSL_MX25 + */ + +#ifndef __ASM_ARCH_MXC_MX25_H__ +#define __ASM_ARCH_MXC_MX25_H__ + +#ifndef __ASM_ARCH_MXC_HARDWARE_H__ +#error "Do not include directly." +#endif + +#ifdef CONFIG_DEBUG_LL +#ifdef CONFIG_MACH_TX25 +#include +#endif +#endif // CONFIG_DEBUG_LL + +/* + * MX25 memory map: + * + * Virt Phys Size What + * --------------------------------------------------------------------------- + * FC000000 43F00000 1M AIPS 1 + * FC100000 50000000 1M SPBA + * FC200000 53F00000 1M AIPS 2 + * FC300000 60000000 1M ROMPATCH (128M) + * FC400000 68000000 1M ASIC (128M) + * FC500000 78000000 128K FBC RAM (IRAM) + * 80000000 256M SDRAM0 + * 90000000 256M SDRAM1 + * A0000000 128M CS0 Flash + * A8000000 128M CS1 Flash + * B0000000 32M CS2 SRAM + * B2000000 32M CS3 + * B4000000 32M CS4 + * B6000000 32M CS5 + * FC520000 B8000000 64K SDRAM, WEIM, M3IF, EMI controllers + * FC530000 BB000000 8K NFC + */ + +#include +#define VA(x) _AT(void __force __iomem *,x) + +/* + * IRAM + */ +#define IRAM_BASE_ADDR UL(0x78000000) /* internal ram */ +#define IRAM_BASE_ADDR_VIRT VA(0xFC500000) +#define IRAM_SIZE SZ_128K + +/* + * AIPS 1 + */ +#define AIPS1_BASE_ADDR UL(0x43F00000) +#define AIPS1_BASE_ADDR_VIRT VA(0xFC000000) +#define AIPS1_SIZE SZ_1M + +#define MAX_BASE_ADDR (AIPS1_BASE_ADDR + 0x00004000) +#define CLKCTL_BASE_ADDR (AIPS1_BASE_ADDR + 0x00008000) +#define ETB_SLOT4_BASE_ADDR (AIPS1_BASE_ADDR + 0x0000C000) +#define ETB_SLOT5_BASE_ADDR (AIPS1_BASE_ADDR + 0x00010000) +#define AAPE_BASE_ADDR (AIPS1_BASE_ADDR + 0x00014000) +#define I2C_BASE_ADDR (AIPS1_BASE_ADDR + 0x00080000) +#define I2C3_BASE_ADDR (AIPS1_BASE_ADDR + 0x00084000) +#define CAN1_BASE_ADDR (AIPS1_BASE_ADDR + 0x00088000) +#define CAN2_BASE_ADDR (AIPS1_BASE_ADDR + 0x0008C000) +#define UART1_BASE_ADDR (AIPS1_BASE_ADDR + 0x00090000) +#define UART2_BASE_ADDR (AIPS1_BASE_ADDR + 0x00094000) +#define I2C2_BASE_ADDR (AIPS1_BASE_ADDR + 0x00098000) +#define OWIRE_BASE_ADDR (AIPS1_BASE_ADDR + 0x0009C000) +#define ATA_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A0000) +#define CSPI1_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A4000) +#define KPP_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A8000) +#define IOMUXC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000AC000) +#define AUDMUX_BASE_ADDR (AIPS1_BASE_ADDR + 0x000B0000) +#define ECT_A_BASE_ADDR (AIPS1_BASE_ADDR + 0x000B8000) +#define ECT_B_BASE_ADDR (AIPS1_BASE_ADDR + 0x000BC000) + +/* + * SPBA global module enabled #0 + */ +#define SPBA0_BASE_ADDR UL(0x50000000) +#define SPBA0_BASE_ADDR_VIRT VA(0xFC100000) +#define SPBA0_SIZE SZ_1M + +#define CSPI3_BASE_ADDR (SPBA0_BASE_ADDR + 0x00004000) +#define UART4_BASE_ADDR (SPBA0_BASE_ADDR + 0x00008000) +#define UART3_BASE_ADDR (SPBA0_BASE_ADDR + 0x0000C000) +#define CSPI2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00010000) +#define SSI2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00014000) +#define ESAI_BASE_ADDR (SPBA0_BASE_ADDR + 0x00018000) +#define ATA_DMA_BASE_ADDR (SPBA0_BASE_ADDR + 0x00020000) +#define SIM1_BASE_ADDR (SPBA0_BASE_ADDR + 0x00024000) +#define SIM2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00028000) +#define UART5_BASE_ADDR (SPBA0_BASE_ADDR + 0x0002C000) +#define TSC_BASE_ADDR (SPBA0_BASE_ADDR + 0x00030000) +#define SSI1_BASE_ADDR (SPBA0_BASE_ADDR + 0x00034000) +#define FEC_BASE_ADDR (SPBA0_BASE_ADDR + 0x00038000) +#define SPBA_CTRL_BASE_ADDR (SPBA0_BASE_ADDR + 0x0003C000) + +/*! + * defines for SPBA modules + */ +#define SPBA_CSPI3 (0x1 << 2) +#define SPBA_UART4 (0x2 << 2) +#define SPBA_UART3 (0x3 << 2) +#define SPBA_CSPI2 (0x4 << 2) +#define SPBA_SSI2 (0x5 << 2) +#define SPBA_ESAI (0x6 << 2) +#define SPBA_ATA (0x8 << 2) +#define SPBA_SIM1 (0x9 << 2) +#define SPBA_SIM2 (0xA << 2) +#define SPBA_UART5 (0xB << 2) +#define SPBA_ANALOG (0xC << 2) +#define SPBA_SSI1 (0xD << 2) +#define SPBA_FEC (0xE << 2) + +/*! + * Defines for modules using static and dynamic DMA channels + */ +#define MXC_DMA_CHANNEL_IRAM 30 +#define MXC_DMA_CHANNEL_UART1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART3_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART3_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART4_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART4_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART5_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART5_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MMC1 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI1_RX MXC_DMA_DYNAMIC_CHANNEL +#ifdef CONFIG_SDMA_IRAM +#define MXC_DMA_CHANNEL_SSI1_TX (MXC_DMA_CHANNEL_IRAM + 1) +#else +#define MXC_DMA_CHANNEL_SSI1_TX MXC_DMA_DYNAMIC_CHANNEL +#endif +#define MXC_DMA_CHANNEL_SSI2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI3_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI3_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ATA_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ATA_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MEMORY MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ESAI_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ESAI_TX MXC_DMA_DYNAMIC_CHANNEL + +/* + * AIPS 2 + */ +#define AIPS2_BASE_ADDR UL(0x53F00000) +#define AIPS2_BASE_ADDR_VIRT VA(0xFC200000) +#define AIPS2_SIZE SZ_1M + +#define CCM_BASE_ADDR (AIPS2_BASE_ADDR + 0x00080000) +#define GPT4_BASE_ADDR (AIPS2_BASE_ADDR + 0x00084000) +#define GPT3_BASE_ADDR (AIPS2_BASE_ADDR + 0x00088000) +#define GPT2_BASE_ADDR (AIPS2_BASE_ADDR + 0x0008C000) +#define GPT1_BASE_ADDR (AIPS2_BASE_ADDR + 0x00090000) +#define EPIT1_BASE_ADDR (AIPS2_BASE_ADDR + 0x00094000) +#define EPIT2_BASE_ADDR (AIPS2_BASE_ADDR + 0x00098000) +#define GPIO4_BASE_ADDR (AIPS2_BASE_ADDR + 0x0009C000) +#define PWM2_BASE_ADDR (AIPS2_BASE_ADDR + 0x000A0000) +#define GPIO3_BASE_ADDR (AIPS2_BASE_ADDR + 0x000A4000) +#define PWM3_BASE_ADDR (AIPS2_BASE_ADDR + 0x000A8000) +#define SCC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000AC000) +#define RNGD_BASE_ADDR (AIPS2_BASE_ADDR + 0x000B0000) +#define MMC_SDHC1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000B4000) +#define MMC_SDHC2_BASE_ADDR (AIPS2_BASE_ADDR + 0x000B8000) +#define LCDC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000BC000) +#define SLCDC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000C0000) +#define PWM4_BASE_ADDR (AIPS2_BASE_ADDR + 0x000C8000) +#define GPIO1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000CC000) +#define GPIO2_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D0000) +#define SDMA_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D4000) +#define WDOG_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DC000) +#define PWM1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000E0000) +#define RTIC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000EC000) +#define IIM_BASE_ADDR (AIPS2_BASE_ADDR + 0x000F0000) +#define USBOTG_BASE_ADDR (AIPS2_BASE_ADDR + 0x000F4000) +#define OTG_BASE_ADDR (USBOTG_BASE_ADDR + 0x000) +#define USBH2_BASE_ADDR (USBOTG_BASE_ADDR + 0x400) +#define CSI_BASE_ADDR (AIPS2_BASE_ADDR + 0x000F8000) +#define DRYICE_BASE_ADDR (AIPS2_BASE_ADDR + 0x000FC000) + +/* + * ROMP and ASIC + */ +#define ROMP_BASE_ADDR UL(0x60000000) +#define ROMP_BASE_ADDR_VIRT VA(0xFC300000) +#define ROMP_SIZE SZ_1M + +#define ASIC_BASE_ADDR UL(0x68000000) +#define ASIC_BASE_ADDR_VIRT VA(0xFC400000) +#define ASIC_SIZE SZ_1M +#define AVIC_BASE_ADDR ASIC_BASE_ADDR +#define AVIC_BASE_ADDR_VIRT ASIC_BASE_ADDR_VIRT +#define AVIC_SIZE ASIC_SIZE + +/* + * SDRAM, WEIM, M3IF, EMI controllers + */ +#define X_MEMC_BASE_ADDR UL(0xB8000000) +#define X_MEMC_BASE_ADDR_VIRT VA(0xFC520000) +#define X_MEMC_SIZE SZ_64K + +#define SDRAMC_BASE_ADDR (X_MEMC_BASE_ADDR + 0x1000) +#define WEIM_BASE_ADDR (X_MEMC_BASE_ADDR + 0x2000) +#define M3IF_BASE_ADDR (X_MEMC_BASE_ADDR + 0x3000) +#define EMI_CTL_BASE_ADDR (X_MEMC_BASE_ADDR + 0x4000) + +/* + * NFC controller + */ +#define NFC_BASE_ADDR UL(0xBB000000) +#define NFC_BASE_ADDR_VIRT VA(0xFC530000) +#define NFC_SIZE SZ_8K + +/* + * Memory regions and CS + */ +#define CSD0_BASE_ADDR UL(0x80000000) +#define CSD1_BASE_ADDR UL(0x90000000) + +#define SDRAM_BASE_ADDR CSD0_BASE_ADDR + +#define CS0_BASE_ADDR UL(0xA0000000) +#define CS1_BASE_ADDR UL(0xA8000000) +#define CS2_BASE_ADDR UL(0xB0000000) +#define CS3_BASE_ADDR UL(0xB2000000) +#define CS4_BASE_ADDR UL(0xB4000000) +#define CS4_SIZE SZ_32M +#define CS5_BASE_ADDR UL(0xB6000000) +#define CS5_SIZE SZ_32M + +/*! + * This macro defines the physical to virtual address mapping for all the + * peripheral modules. It is used by passing in the physical address as x + * and returning the virtual address. If the physical address is not mapped, + * it returns 0 + */ +#define IO_ADDRESS(x) \ + VA((((x) >= AIPS1_BASE_ADDR) && ((x) < (AIPS1_BASE_ADDR + AIPS1_SIZE))) ? AIPS1_IO_ADDRESS(x): \ + (((x) >= SPBA0_BASE_ADDR) && ((x) < (SPBA0_BASE_ADDR + SPBA0_SIZE))) ? SPBA0_IO_ADDRESS(x): \ + (((x) >= AIPS2_BASE_ADDR) && ((x) < (AIPS2_BASE_ADDR + AIPS2_SIZE))) ? AIPS2_IO_ADDRESS(x): \ + (((x) >= ROMP_BASE_ADDR) && ((x) < (ROMP_BASE_ADDR + ROMP_SIZE))) ? ROMP_IO_ADDRESS(x): \ + (((x) >= ASIC_BASE_ADDR) && ((x) < (ASIC_BASE_ADDR + AVIC_SIZE))) ? ASIC_IO_ADDRESS(x): \ + (((x) >= IRAM_BASE_ADDR) && ((x) < (IRAM_BASE_ADDR + IRAM_SIZE))) ? IRAM_IO_ADDRESS(x): \ + (((x) >= X_MEMC_BASE_ADDR) && ((x) < (X_MEMC_BASE_ADDR + X_MEMC_SIZE))) ? X_MEMC_IO_ADDRESS(x): \ + (((x) >= NFC_BASE_ADDR) && ((x) < (NFC_BASE_ADDR + NFC_SIZE))) ? NFC_IO_ADDRESS(x): \ + 0) + +#define MXC_VADDR_RANGE(v,n) \ + (((v)) >= n##_BASE_ADDR_VIRT) && \ + (((v)) < n##_BASE_ADDR_VIRT + n##_SIZE) ? \ + ((v)-n##_BASE_ADDR_VIRT + n##_BASE_ADDR) : + +#define MXC_PHYS_ADDRESS(v) \ + UL(MXC_VADDR_RANGE(v,AIPS1) \ + MXC_VADDR_RANGE(v,AIPS2) \ + MXC_VADDR_RANGE(v,SPBA0) \ + MXC_VADDR_RANGE(v,ROMP) \ + MXC_VADDR_RANGE(v,ASIC) \ + MXC_VADDR_RANGE(v,IRAM) \ + MXC_VADDR_RANGE(v,X_MEMC) \ + MXC_VADDR_RANGE(v,NFC) \ + 0) + +#define GPIO_BASE_ADDR(port) \ + ((port == 1 ? GPIO1_BASE_ADDR : \ + (port == 2 ? GPIO2_BASE_ADDR : \ + (port == 3 ? GPIO3_BASE_ADDR : \ + (port == 4 ? GPIO4_BASE_ADDR : 0))))) + +/* + * define the address mapping macros: in physical address order + */ + +#define AIPS1_IO_ADDRESS(x) \ + (((x) - AIPS1_BASE_ADDR) + AIPS1_BASE_ADDR_VIRT) + +#define SPBA0_IO_ADDRESS(x) \ + (((x) - SPBA0_BASE_ADDR) + SPBA0_BASE_ADDR_VIRT) + +#define AIPS2_IO_ADDRESS(x) \ + (((x) - AIPS2_BASE_ADDR) + AIPS2_BASE_ADDR_VIRT) + +#define ROMP_IO_ADDRESS(x) \ + (((x) - ROMP_BASE_ADDR) + ROMP_BASE_ADDR_VIRT) + +#define ASIC_IO_ADDRESS(x) \ + (((x) - ASIC_BASE_ADDR) + ASIC_BASE_ADDR_VIRT) + +/* for entry-macro.S */ +#define AVIC_IO_ADDRESS(x) ASIC_IO_ADDRESS(x) + +#define IRAM_IO_ADDRESS(x) \ + (((x) - IRAM_BASE_ADDR) + IRAM_BASE_ADDR_VIRT) + +#define X_MEMC_IO_ADDRESS(x) \ + (((x) - X_MEMC_BASE_ADDR) + X_MEMC_BASE_ADDR_VIRT) + +#define NFC_IO_ADDRESS(x) \ + (((x) - NFC_BASE_ADDR) + NFC_BASE_ADDR_VIRT) + +/* + * DMA request assignments + */ +#define DMA_REQ_EXTREQ0 0 +#define DMA_REQ_CCM 1 +#define DMA_REQ_ATA_TX_END 2 +#define DMA_REQ_ATA_TX 3 +#define DMA_REQ_ATA_RX 4 +#define DMA_REQ_CSPI2_RX 6 +#define DMA_REQ_CSPI2_TX 7 +#define DMA_REQ_CSPI1_RX 8 +#define DMA_REQ_CSPI1_TX 9 +#define DMA_REQ_UART3_RX 10 +#define DMA_REQ_UART3_TX 11 +#define DMA_REQ_UART4_RX 12 +#define DMA_REQ_UART4_TX 13 +#define DMA_REQ_EXTREQ1 14 +#define DMA_REQ_EXTREQ2 15 +#define DMA_REQ_UART2_RX 16 +#define DMA_REQ_UART2_TX 17 +#define DMA_REQ_UART1_RX 18 +#define DMA_REQ_UART1_TX 19 +#define DMA_REQ_SSI2_RX1 22 +#define DMA_REQ_SSI2_TX1 23 +#define DMA_REQ_SSI2_RX0 24 +#define DMA_REQ_SSI2_TX0 25 +#define DMA_REQ_SSI1_RX1 26 +#define DMA_REQ_SSI1_TX1 27 +#define DMA_REQ_SSI1_RX0 28 +#define DMA_REQ_SSI1_TX0 29 +#define DMA_REQ_NFC 30 +#define DMA_REQ_ECT 31 +#define DMA_REQ_ESAI_RX 32 +#define DMA_REQ_ESAI_TX 33 +#define DMA_REQ_CSPI3_RX 34 +#define DMA_REQ_CSPI3_TX 35 +#define DMA_REQ_SIM2_RX 36 +#define DMA_REQ_SIM2_TX 37 +#define DMA_REQ_SIM1_RX 38 +#define DMA_REQ_SIM1_TX 39 +#define DMA_REQ_TSC_GCQ 44 +#define DMA_REQ_TSC_TCQ 45 +#define DMA_REQ_UART5_RX 46 +#define DMA_REQ_UART5_TX 47 + +/* + * Interrupt numbers + */ +#define MXC_INT_CSPI3 0 +#define MXC_INT_GPT4 1 +#define MXC_INT_OWIRE 2 +#define MXC_INT_I2C 3 +#define MXC_INT_I2C2 4 +#define MXC_INT_UART4 5 +#define MXC_INT_RTIC 6 +#define MXC_INT_ESAI 7 +#define MXC_INT_SDHC2 8 +#define MXC_INT_SDHC1 9 +#define MXC_INT_I2C3 10 +#define MXC_INT_SSI2 11 +#define MXC_INT_SSI1 12 +#define MXC_INT_CSPI2 13 +#define MXC_INT_CSPI1 14 +#define MXC_INT_ATA 15 +#define MXC_INT_GPIO3 16 +#define MXC_INT_CSI 17 +#define MXC_INT_UART3 18 +#define MXC_INT_IIM 19 +#define MXC_INT_SIM1 20 +#define MXC_INT_SIM2 21 +#define MXC_INT_RNGD 22 +#define MXC_INT_GPIO4 23 +#define MXC_INT_KPP 24 +#define MXC_INT_DRYICE_RTC 25 +#define MXC_INT_PWM 26 +#define MXC_INT_EPIT2 27 +#define MXC_INT_EPIT1 28 +#define MXC_INT_GPT3 29 +#define MXC_INT_POWER_FAIL 30 +#define MXC_INT_CRM 31 +#define MXC_INT_UART2 32 +#define MXC_INT_NANDFC 33 +#define MXC_INT_SDMA 34 +#define MXC_INT_USB_H2 35 +#define MXC_INT_PWM2 36 +#define MXC_INT_USB_OTG 37 +#define MXC_INT_SLCDC 38 +#define MXC_INT_LCDC 39 +#define MXC_INT_UART5 40 +#define MXC_INT_PWM3 41 +#define MXC_INT_PWM4 42 +#define MXC_INT_CAN1 43 +#define MXC_INT_CAN2 44 +#define MXC_INT_UART1 45 +#define MXC_INT_TSC 46 +#define MXC_INT_ECT 48 +#define MXC_INT_SCC_SCM 49 +#define MXC_INT_SCC_SMN 50 +#define MXC_INT_GPIO2 51 +#define MXC_INT_GPIO1 52 +#define MXC_INT_GPT2 53 +#define MXC_INT_GPT1 54 +#define MXC_INT_WDOG 55 +#define MXC_INT_DRYICE 56 +#define MXC_INT_FEC 57 +#define MXC_INT_EXT_INT5 58 +#define MXC_INT_EXT_INT4 59 +#define MXC_INT_EXT_INT3 60 +#define MXC_INT_EXT_INT2 61 +#define MXC_INT_EXT_INT1 62 +#define MXC_INT_EXT_INT0 63 + +#define MXC_INT_GPT MXC_INT_GPT1 + +/* silicon revisions specific to i.MX25 */ +#define CHIP_REV_1_0 0x00 +#define CHIP_REV_1_1 0x01 + +/* gpio and gpio based interrupt handling */ +#define GPIO_DR 0x00 +#define GPIO_GDIR 0x04 +#define GPIO_PSR 0x08 +#define GPIO_ICR1 0x0C +#define GPIO_ICR2 0x10 +#define GPIO_IMR 0x14 +#define GPIO_ISR 0x18 +#define GPIO_INT_LOW_LEV 0x0 +#define GPIO_INT_HIGH_LEV 0x1 +#define GPIO_INT_RISE_EDGE 0x2 +#define GPIO_INT_FALL_EDGE 0x3 +#define GPIO_INT_NONE 0x4 + +/* Mandatory defines used globally */ + +/* this CPU supports up to 96 GPIOs */ +#define ARCH_NR_GPIOS 128 + +#define MXC_TIMER_GPT1 1 +#define MXC_TIMER_GPT2 2 +#define MXC_TIMER_GPT3 3 +#define MXC_TIMER_GPT4 4 + +/*! + * NFMS bit in RCSR register for pagesize of nandflash + */ +#define NFMS_REG IO_ADDRESS(CCM_BASE_ADDR + 0x28) +#define NFMS_NF_DWIDTH 14 +#define NFMS_NF_PG_SZ 8 + +#if !defined(__ASSEMBLY__) && !defined(__MXC_BOOT_UNCOMPRESS) +#include + +extern int mx25_revision(void); + +#endif + +#endif /* __ASM_ARCH_MXC_MX25_H__ */ diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/mx2x.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/mx2x.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/mx2x.h 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/mx2x.h 2009-06-02 18:02:11.000000000 +0200 @@ -79,7 +79,7 @@ * This macro defines the physical to virtual address mapping for all the * peripheral modules. It is used by passing in the physical address as x * and returning the virtual address. If the physical address is not mapped, - * it returns 0xDEADBEEF + * it returns 0 */ #define IO_ADDRESS(x) \ (void __force __iomem *) \ @@ -88,7 +88,7 @@ ((x >= SAHB1_BASE_ADDR) && (x < (SAHB1_BASE_ADDR + SAHB1_SIZE))) ? \ SAHB1_IO_ADDRESS(x) : \ ((x >= X_MEMC_BASE_ADDR) && (x < (X_MEMC_BASE_ADDR + X_MEMC_SIZE))) ? \ - X_MEMC_IO_ADDRESS(x) : 0xDEADBEEF) + X_MEMC_IO_ADDRESS(x) : 0) /* define the address mapping macros: in physical address order */ #define AIPI_IO_ADDRESS(x) \ diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/mxc.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/mxc.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/mxc.h 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/mxc.h 2009-06-02 18:02:12.000000000 +0200 @@ -27,6 +27,7 @@ #define MXC_CPU_MX1 1 #define MXC_CPU_MX21 21 #define MXC_CPU_MX27 27 +#define MXC_CPU_MX25 25 #define MXC_CPU_MX31 31 #define MXC_CPU_MX35 35 @@ -70,6 +71,18 @@ extern unsigned int __mxc_cpu_type; # define cpu_is_mx27() (0) #endif +#ifdef CONFIG_MACH_MX25 +# ifdef mxc_cpu_type +# undef mxc_cpu_type +# define mxc_cpu_type __mxc_cpu_type +# else +# define mxc_cpu_type MXC_CPU_MX25 +# endif +# define cpu_is_mx25() (mxc_cpu_type == MXC_CPU_MX25) +#else +# define cpu_is_mx25() (0) +#endif + #ifdef CONFIG_ARCH_MX31 # ifdef mxc_cpu_type # undef mxc_cpu_type @@ -101,6 +114,6 @@ extern unsigned int __mxc_cpu_type; #endif #define cpu_is_mx3() (cpu_is_mx31() || cpu_is_mx35()) -#define cpu_is_mx2() (cpu_is_mx21() || cpu_is_mx27()) +#define cpu_is_mx2() (cpu_is_mx21() || cpu_is_mx25() || cpu_is_mx27()) #endif /* __ASM_ARCH_MXC_H__ */ diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/mxc_can.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/mxc_can.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/mxc_can.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/mxc_can.h 2009-07-01 11:31:19.000000000 +0200 @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2009 Lothar Wassmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + */ + +#include + +struct flexcan_platform_data { + char *core_reg; + char *io_reg; + int (*xcvr_enable)(struct platform_device *pdev, int en); + int (*active)(struct platform_device *pdev); + void (*inactive)(struct platform_device *pdev); +}; diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/mxc_ehci.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/mxc_ehci.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/mxc_ehci.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/mxc_ehci.h 2009-07-01 11:31:34.000000000 +0200 @@ -0,0 +1,9 @@ +#ifndef __INCLUDE_ASM_ARCH_MXC_EHCI_H +#define __INCLUDE_ASM_ARCH_MXC_EHCI_H + +struct mxc_usbh_platform_data { + int (*init)(struct platform_device *pdev); + int (*exit)(struct platform_device *pdev); +}; +#endif /* __INCLUDE_ASM_ARCH_MXC_EHCI_H */ + diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/mxc_tsadcc.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/mxc_tsadcc.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/mxc_tsadcc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/mxc_tsadcc.h 2009-07-01 11:23:07.000000000 +0200 @@ -0,0 +1,28 @@ +/* + * Freescale i.MX25 Touch Screen Driver + * + * Copyright (c) 2009 Lothar Wassmann + * + * Based on code from Freescale BSP + * + * 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. + */ + +typedef enum { + MXC_TSC_4WIRE, + MXC_TSC_5WIRE, +} mxc_tsc_mode; + +struct mxc_tsadcc_pdata { + int pen_debounce_time; /* 0: disable debounce; + * 1..128: # of ADC clock cycles / 8 */ + unsigned int intref:1, /* 0|1: internal reference disabled|enabled */ + hsyncen:1; /* synchronize measurements with LCD HSYNC */ + unsigned int r_xplate; /* resistance (in Ohms) of X plate + * (required for pressure measurement */ + int adc_clk; /* ADC clock frequency in Hz (max. 1750000); + * <= 0: use default (1666667) */ + mxc_tsc_mode tsc_mode; /* select 4 wire or 5 wire mode */ +}; diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/sdma.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/sdma.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/sdma.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/sdma.h 2009-06-02 18:02:13.000000000 +0200 @@ -0,0 +1,504 @@ + +/* + * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __ASM_ARCH_MXC_SDMA_H__ +#define __ASM_ARCH_MXC_SDMA_H__ + +/*! + * @defgroup SDMA Smart Direct Memory Access (SDMA) Driver + */ + +/*! + * @file arch-mxc/sdma.h + * + * @brief This file contains the SDMA API declarations. + * + * SDMA is responsible on moving data between peripherals and memories (MCU, EMI and DSP). + * + * @ingroup SDMA + */ + +#include +#include +#include +#include + +/*! + * This defines maximum DMA address + */ +#define MAX_DMA_ADDRESS 0xffffffff + +/*! + * This defines maximum number of DMA channels + */ +#ifdef CONFIG_MXC_SDMA_API +#define MAX_DMA_CHANNELS 32 +#define MAX_BD_NUMBER 16 +#define MXC_SDMA_DEFAULT_PRIORITY 1 +#define MXC_SDMA_MIN_PRIORITY 1 +#define MXC_SDMA_MAX_PRIORITY 7 +#else +#define MAX_DMA_CHANNELS 0 +#endif + +#define MXC_FIFO_MEM_DEST_FIXED 0x1 +#define MXC_FIFO_MEM_SRC_FIXED 0x2 +/*! + * This enumerates transfer types + */ +typedef enum { + emi_2_per = 0, /*!< EMI memory to peripheral */ + emi_2_int, /*!< EMI memory to internal RAM */ + emi_2_emi, /*!< EMI memory to EMI memory */ + emi_2_dsp, /*!< EMI memory to DSP memory */ + per_2_int, /*!< Peripheral to internal RAM */ + per_2_emi, /*!< Peripheral to internal EMI memory */ + per_2_dsp, /*!< Peripheral to DSP memory */ + per_2_per, /*!< Peripheral to Peripheral */ + int_2_per, /*!< Internal RAM to peripheral */ + int_2_int, /*!< Internal RAM to Internal RAM */ + int_2_emi, /*!< Internal RAM to EMI memory */ + int_2_dsp, /*!< Internal RAM to DSP memory */ + dsp_2_per, /*!< DSP memory to peripheral */ + dsp_2_int, /*!< DSP memory to internal RAM */ + dsp_2_emi, /*!< DSP memory to EMI memory */ + dsp_2_dsp, /*!< DSP memory to DSP memory */ + emi_2_dsp_loop, /*!< EMI memory to DSP memory loopback */ + dsp_2_emi_loop, /*!< DSP memory to EMI memory loopback */ + dvfs_pll, /*!< DVFS script with PLL change */ + dvfs_pdr /*!< DVFS script without PLL change */ +} sdma_transferT; + +/*! + * This enumerates peripheral types + */ +typedef enum { + SSI, /*!< MCU domain SSI */ + SSI_SP, /*!< Shared SSI */ + MMC, /*!< MMC */ + SDHC, /*!< SDHC */ + UART, /*!< MCU domain UART */ + UART_SP, /*!< Shared UART */ + FIRI, /*!< FIRI */ + CSPI, /*!< MCU domain CSPI */ + CSPI_SP, /*!< Shared CSPI */ + SIM, /*!< SIM */ + ATA, /*!< ATA */ + CCM, /*!< CCM */ + EXT, /*!< External peripheral */ + MSHC, /*!< Memory Stick Host Controller */ + MSHC_SP, /*!< Shared Memory Stick Host Controller */ + DSP, /*!< DSP */ + MEMORY, /*!< Memory */ + FIFO_MEMORY, /*!< FIFO type Memory */ + SPDIF, /*!< SPDIF */ + IPU_MEMORY, /*!< IPU Memory */ + ASRC, /*!< ASRC */ + ESAI, /*!< ESAI */ +} sdma_periphT; + +#ifndef TRANSFER_32BIT +/*! + * This defines SDMA access data size + */ +#define TRANSFER_32BIT 0x00 +#define TRANSFER_8BIT 0x01 +#define TRANSFER_16BIT 0x02 +#define TRANSFER_24BIT 0x03 + +#endif + +/*! + * This defines maximum device name length passed during mxc_request_dma(). + */ +#define MAX_DEVNAME_LENGTH 32 + +/*! + * This defines SDMA interrupt callback function prototype. + */ +typedef void (*dma_callback_t) (void *arg); + +/*! + * Structure containing sdma channel parameters. + */ +typedef struct { + __u32 watermark_level; /*!< Lower/upper threshold that + * triggers SDMA event + */ + __u32 per_address; /*!< Peripheral source/destination + * physical address + */ + sdma_periphT peripheral_type; /*!< Peripheral type */ + sdma_transferT transfer_type; /*!< Transfer type */ + int event_id; /*!< Event number, + * needed by all channels + * that started by peripherals dma + * request (per_2_*,*_2_per) + * Not used for memory and DSP + * transfers. + */ + int event_id2; /*!< Second event number, + * used in ATA scripts only. + */ + int bd_number; /*!< Buffer descriptors number. + * If not set, single buffer + * descriptor will be used. + */ + dma_callback_t callback; /*! callback function */ + void *arg; /*! callback argument */ + unsigned long word_size:8; /*!< SDMA data access word size */ +} dma_channel_params; + +/*! + * Structure containing sdma request parameters. + */ +typedef struct { + /*! physical source memory address */ + __u8 *sourceAddr; + /*! physical destination memory address */ + __u8 *destAddr; + /*! amount of data to transfer, + * updated during mxc_dma_get_config + */ + __u16 count; + /*!< DONE bit of the buffer descriptor, + * updated during mxc_dma_get_config + * 0 - means the BD is done and closed by SDMA + * 1 - means the BD is still being processed by SDMA + */ + int bd_done; + /*!< CONT bit of the buffer descriptor, + * set it if full multi-buffer descriptor mechanism + * required. + */ + int bd_cont; + /*!< ERROR bit of the buffer descriptor, + * updated during mxc_dma_get_config. + * If it is set - there was an error during BD processing. + */ + int bd_error; +} dma_request_t; + +/*! + * Structure containing sdma request parameters. + */ +typedef struct { + /*! address of ap_2_ap script */ + int mxc_sdma_ap_2_ap_addr; + /*! address of ap_2_bp script */ + int mxc_sdma_ap_2_bp_addr; + /*! address of ap_2_ap_fixed script */ + int mxc_sdma_ap_2_ap_fixed_addr; + /*! address of bp_2_ap script */ + int mxc_sdma_bp_2_ap_addr; + /*! address of loopback_on_dsp_side script */ + int mxc_sdma_loopback_on_dsp_side_addr; + /*! address of mcu_interrupt_only script */ + int mxc_sdma_mcu_interrupt_only_addr; + + /*! address of firi_2_per script */ + int mxc_sdma_firi_2_per_addr; + /*! address of firi_2_mcu script */ + int mxc_sdma_firi_2_mcu_addr; + /*! address of per_2_firi script */ + int mxc_sdma_per_2_firi_addr; + /*! address of mcu_2_firi script */ + int mxc_sdma_mcu_2_firi_addr; + + /*! address of uart_2_per script */ + int mxc_sdma_uart_2_per_addr; + /*! address of uart_2_mcu script */ + int mxc_sdma_uart_2_mcu_addr; + /*! address of per_2_app script */ + int mxc_sdma_per_2_app_addr; + /*! address of mcu_2_app script */ + int mxc_sdma_mcu_2_app_addr; + /*! address of per_2_per script */ + int mxc_sdma_per_2_per_addr; + + /*! address of uartsh_2_per script */ + int mxc_sdma_uartsh_2_per_addr; + /*! address of uartsh_2_mcu script */ + int mxc_sdma_uartsh_2_mcu_addr; + /*! address of per_2_shp script */ + int mxc_sdma_per_2_shp_addr; + /*! address of mcu_2_shp script */ + int mxc_sdma_mcu_2_shp_addr; + + /*! address of ata_2_mcu script */ + int mxc_sdma_ata_2_mcu_addr; + /*! address of mcu_2_ata script */ + int mxc_sdma_mcu_2_ata_addr; + + /*! address of app_2_per script */ + int mxc_sdma_app_2_per_addr; + /*! address of app_2_mcu script */ + int mxc_sdma_app_2_mcu_addr; + /*! address of shp_2_per script */ + int mxc_sdma_shp_2_per_addr; + /*! address of shp_2_mcu script */ + int mxc_sdma_shp_2_mcu_addr; + + /*! address of mshc_2_mcu script */ + int mxc_sdma_mshc_2_mcu_addr; + /*! address of mcu_2_mshc script */ + int mxc_sdma_mcu_2_mshc_addr; + + /*! address of spdif_2_mcu script */ + int mxc_sdma_spdif_2_mcu_addr; + /*! address of mcu_2_spdif script */ + int mxc_sdma_mcu_2_spdif_addr; + + /*! address of asrc_2_mcu script */ + int mxc_sdma_asrc_2_mcu_addr; + + /*! address of ext_mem_2_ipu script */ + int mxc_sdma_ext_mem_2_ipu_addr; + + /*! address of descrambler script */ + int mxc_sdma_descrambler_addr; + + /*! address of dptc_dvfs script */ + int mxc_sdma_dptc_dvfs_addr; + + int mxc_sdma_utra_addr; + + /*! address where ram code starts */ + int mxc_sdma_ram_code_start_addr; + /*! size of the ram code */ + int mxc_sdma_ram_code_size; + /*! RAM image address */ + unsigned short *mxc_sdma_start_addr; +} sdma_script_start_addrs; + +/*! Structure to store the initialized dma_channel parameters */ +typedef struct mxc_sdma_channel_params { + /*! Channel params */ + dma_channel_params chnl_params; + /*! Channel type (static channel number or dynamic channel) */ + unsigned int channel_num; + /*! Channel priority [0x1(lowest) - 0x7(highest)] */ + unsigned int chnl_priority; +} mxc_sdma_channel_params_t; + +/*! Private SDMA data structure */ +typedef struct mxc_dma_channel_private { + /*! ID of the buffer that was processed */ + unsigned int buf_tail; + /*! Tasklet for the channel */ + struct tasklet_struct chnl_tasklet; + /*! Flag indicates if interrupt is required after every BD transfer */ + int intr_after_every_bd; +} mxc_dma_channel_private_t; + +/*! + * Setup channel according to parameters. + * Must be called once after mxc_request_dma() + * + * @param channel channel number + * @param p channel parameters pointer + * @return 0 on success, error code on fail + */ +int mxc_dma_setup_channel(int channel, dma_channel_params * p); + +/*! + * Setup the channel priority. This can be used to change the default priority + * for the channel. + * + * @param channel channel number + * @param priority priority to be set for the channel + * + * @return 0 on success, error code on failure + */ +int mxc_dma_set_channel_priority(unsigned int channel, unsigned int priority); + +/*! + * Allocates dma channel. + * If channel's value is 0, then the function allocates a free channel + * dynamically and sets its value to channel. + * Else allocates requested channel if it is free. + * If the channel is busy or no free channels (in dynamic allocation) -EBUSY returned. + * + * @param channel pointer to channel number + * @param devicename device name + * @return 0 on success, error code on fail + */ +int mxc_request_dma(int *channel, const char *devicename); + +/*! + * Configures request parameters. Can be called multiple times after + * mxc_request_dma() and mxc_dma_setup_channel(). + * + * + * @param channel channel number + * @param p request parameters pointer + * @param bd_index index of buffer descriptor to set + * @return 0 on success, error code on fail + */ +/* int mxc_dma_set_config(int channel, dma_request_t *p, int bd_index); */ +int mxc_dma_set_config(int channel, dma_request_t * p, int bd_index); + +/*! + * Returns request parameters. + * + * @param channel channel number + * @param p request parameters pointer + * @param bd_index index of buffer descriptor to get + * @return 0 on success, error code on fail + */ +/* int mxc_dma_get_config(int channel, dma_request_t *p, int bd_index); */ +int mxc_dma_get_config(int channel, dma_request_t * p, int bd_index); + +/*! + * This function is used by MXC IPC's write_ex2. It passes the a pointer to the + * data control structure to iapi_write_ipcv2() + * + * @param channel SDMA channel number + * @param ctrl_ptr Data Control structure pointer + */ +int mxc_sdma_write_ipcv2(int channel, void *ctrl_ptr); + +/*! + * This function is used by MXC IPC's read_ex2. It passes the a pointer to the + * data control structure to iapi_read_ipcv2() + * + * @param channel SDMA channel number + * @param ctrl_ptr Data Control structure pointer + */ +int mxc_sdma_read_ipcv2(int channel, void *ctrl_ptr); + +/*! + * Starts dma channel. + * + * @param channel channel number + */ +int mxc_dma_start(int channel); + +/*! + * Stops dma channel. + * + * @param channel channel number + */ +int mxc_dma_stop(int channel); + +/*! + * Frees dma channel. + * + * @param channel channel number + */ +void mxc_free_dma(int channel); + +/*! + * Sets callback function. Used with standard dma api + * for supporting interrupts + * + * @param channel channel number + * @param callback callback function pointer + * @param arg argument for callback function + */ +void mxc_dma_set_callback(int channel, dma_callback_t callback, void *arg); + +/*! + * Allocates uncachable buffer. Uses hash table. + * + * @param size size of allocated buffer + * @return pointer to buffer + */ +void *sdma_malloc(size_t size); + +#ifdef CONFIG_SDMA_IRAM +/*! + * Allocates uncachable buffer from IRAM.. + * + * @param size size of allocated buffer + * @return pointer to buffer + */ +void *sdma_iram_malloc(size_t size); +#endif /*CONFIG_SDMA_IRAM */ + +/*! + * Frees uncachable buffer. Uses hash table. + */ +void sdma_free(void *buf); + +/*! + * Converts virtual to physical address. Uses hash table. + * + * @param buf virtual address pointer + * @return physical address value + */ +unsigned long sdma_virt_to_phys(void *buf); + +/*! + * Converts physical to virtual address. Uses hash table. + * + * @param buf physical address value + * @return virtual address pointer + */ +void *sdma_phys_to_virt(unsigned long buf); + +/*! + * Configures the BD_INTR bit on a buffer descriptor parameters. + * + * + * @param channel channel number + * @param bd_index index of buffer descriptor to set + * @param bd_intr flag to set or clear the BD_INTR bit + */ +void mxc_dma_set_bd_intr(int channel, int bd_index, int bd_intr); + +/*! + * Gets the BD_INTR bit on a buffer descriptor. + * + * + * @param channel channel number + * @param bd_index index of buffer descriptor to set + * + * @return returns the BD_INTR bit status + */ +int mxc_dma_get_bd_intr(int channel, int bd_index); + +/*! + * Stop the current transfer + * + * @param channel channel number + * @param buffer_number number of buffers (beginning with 0), + * whose done bits should be reset to 0 + */ +int mxc_dma_reset(int channel, int buffer_number); + +/*! + * This functions Returns the SDMA paramaters associated for a module + * + * @param channel_id the ID of the module requesting DMA + * @return returns the sdma parameters structure for the device + */ +mxc_sdma_channel_params_t *mxc_sdma_get_channel_params(mxc_dma_device_t + channel_id); + +/*! + * This functions marks the SDMA channels that are statically allocated + * + * @param chnl the channel array used to store channel information + */ +void mxc_get_static_channels(mxc_dma_channel_t * chnl); + +/*! + * Initializes SDMA driver + */ +int __init sdma_init(void); + +#define DEFAULT_ERR 1 + +#endif diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/spba.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/spba.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/spba.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/spba.h 2009-06-02 18:02:13.000000000 +0200 @@ -0,0 +1,66 @@ + +/* + * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @defgroup SPBA Shared Peripheral Bus Arbiter (SPBA) + * @ingroup MSL_MX31 MSL_MX35 MSL_MX37 MSL_MX51 MSL_MXC91321 + */ + +/*! + * @file arch-mxc/spba.h + * @brief This file contains the Shared Peripheral Bus Arbiter (spba) API. + * + * @ingroup SPBA + */ + +#ifndef __ASM_ARCH_MXC_SPBA_H__ +#define __ASM_ARCH_MXC_SPBA_H__ + +#ifdef __KERNEL__ + +#define MXC_SPBA_RAR_MASK 0x7 + +/*! + * Defines three SPBA masters: A - ARM, C - SDMA (no master B for MX31) + */ +enum spba_masters { + SPBA_MASTER_A = 1, + SPBA_MASTER_B = 2, + SPBA_MASTER_C = 4, +}; + +/*! + * This function allows the three masters (A, B, C) to take ownership of a + * shared peripheral. + * + * @param mod specified module as defined in \b enum \b #spba_module + * @param master one of more (or-ed together) masters as defined in \b enum \b #spba_masters + * + * @return 0 if successful; -1 otherwise. + */ +int spba_take_ownership(int mod, int master); + +/*! + * This function releases the ownership for a shared peripheral. + * + * @param mod specified module as defined in \b enum \b #spba_module + * @param master one of more (or-ed together) masters as defined in \b enum \b #spba_masters + * + * @return 0 if successful; -1 otherwise. + */ +int spba_rel_ownership(int mod, int master); + +#endif /* __KERNEL__ */ + +#endif /* __ASM_ARCH_MXC_SPBA_H__ */ diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/timex.h linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/timex.h --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/include/mach/timex.h 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/include/mach/timex.h 2009-07-02 16:20:37.000000000 +0200 @@ -23,7 +23,11 @@ #if defined CONFIG_ARCH_MX1 #define CLOCK_TICK_RATE 16000000 #elif defined CONFIG_ARCH_MX2 +#ifndef CONFIG_MACH_MX25 #define CLOCK_TICK_RATE 13300000 +#else +#define CLOCK_TICK_RATE 66500000 +#endif #elif defined CONFIG_ARCH_MX3 #define CLOCK_TICK_RATE 16625000 #endif diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/iomux-mx1-mx2.c linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/iomux-mx1-mx2.c --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/iomux-mx1-mx2.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/iomux-mx1-mx2.c 2009-06-02 18:02:01.000000000 +0200 @@ -74,11 +74,12 @@ void mxc_gpio_mode(int gpio_mode) __raw_writel(tmp, VA_GPIO_BASE + MXC_GIUS(port)); if (pin < 16) { +#ifndef CONFIG_MACH_MX25 tmp = __raw_readl(VA_GPIO_BASE + MXC_OCR1(port)); tmp &= ~(3 << (pin * 2)); tmp |= (ocr << (pin * 2)); __raw_writel(tmp, VA_GPIO_BASE + MXC_OCR1(port)); - +#endif tmp = __raw_readl(VA_GPIO_BASE + MXC_ICONFA1(port)); tmp &= ~(3 << (pin * 2)); tmp |= ((gpio_mode >> GPIO_AOUT_SHIFT) & 3) << (pin * 2); @@ -90,12 +91,12 @@ void mxc_gpio_mode(int gpio_mode) __raw_writel(tmp, VA_GPIO_BASE + MXC_ICONFB1(port)); } else { pin -= 16; - +#ifndef CONFIG_MACH_MX25 tmp = __raw_readl(VA_GPIO_BASE + MXC_OCR2(port)); tmp &= ~(3 << (pin * 2)); tmp |= (ocr << (pin * 2)); __raw_writel(tmp, VA_GPIO_BASE + MXC_OCR2(port)); - +#endif tmp = __raw_readl(VA_GPIO_BASE + MXC_ICONFA2(port)); tmp &= ~(3 << (pin * 2)); tmp |= ((gpio_mode >> GPIO_AOUT_SHIFT) & 3) << (pin * 2); diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/iomux-v3.c linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/iomux-v3.c --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/iomux-v3.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/iomux-v3.c 2009-06-02 18:02:02.000000000 +0200 @@ -31,7 +31,24 @@ #define IOMUX_BASE IO_ADDRESS(IOMUXC_BASE_ADDR) -static unsigned long iomux_v3_pad_alloc_map[0x200 / BITS_PER_LONG]; +#ifdef CONFIG_MACH_MX25 +#define NUM_PADS 0x228 +#else +#define NUM_PADS 0x200 +#endif + +static unsigned long iomux_v3_pad_alloc_map[NUM_PADS / BITS_PER_LONG]; + +static inline int mxc_iomux_v3_pad_offset(struct pad_desc *pad) +{ + int pad_ofs; + if (cpu_is_mx25()) + pad_ofs = pad->mux_ctrl_ofs; + else + pad_ofs = pad->pad_ctrl_ofs; + BUG_ON((pad_ofs >> 7) >= ARRAY_SIZE(iomux_v3_pad_alloc_map)); + return pad_ofs; +} /* * setups a single pin: @@ -40,7 +57,7 @@ static unsigned long iomux_v3_pad_alloc_ */ int mxc_iomux_v3_setup_pad(struct pad_desc *pad) { - unsigned int pad_ofs = pad->pad_ctrl_ofs; + unsigned int pad_ofs = mxc_iomux_v3_pad_offset(pad); if (test_and_set_bit(pad_ofs >> 2, iomux_v3_pad_alloc_map)) return -EBUSY; @@ -65,8 +82,10 @@ int mxc_iomux_v3_setup_multiple_pads(str for (i = 0; i < count; i++) { ret = mxc_iomux_v3_setup_pad(p); - if (ret) + if (ret) { + printk(KERN_ERR "Failed to setup PAD[%d]: %d\n", i, ret); goto setup_error; + } p++; } return 0; @@ -79,7 +98,7 @@ EXPORT_SYMBOL(mxc_iomux_v3_setup_multipl void mxc_iomux_v3_release_pad(struct pad_desc *pad) { - unsigned int pad_ofs = pad->pad_ctrl_ofs; + unsigned int pad_ofs = mxc_iomux_v3_pad_offset(pad); clear_bit(pad_ofs >> 2, iomux_v3_pad_alloc_map); } diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/pwm.c linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/pwm.c --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/pwm.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/pwm.c 2009-06-02 18:02:02.000000000 +0200 @@ -55,7 +55,7 @@ int pwm_config(struct pwm_device *pwm, i if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) return -EINVAL; - if (cpu_is_mx27() || cpu_is_mx3()) { + if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25()) { unsigned long long c; unsigned long period_cycles, duty_cycles, prescale; c = clk_get_rate(pwm->clk); diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/spba.c linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/spba.c --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/spba.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/spba.c 2009-06-02 18:02:03.000000000 +0200 @@ -0,0 +1,143 @@ +/* + * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include + +/*! + * @file plat-mxc/spba.c + * + * @brief This file contains the SPBA API implementation details. + * + * @ingroup SPBA + */ + +static DEFINE_SPINLOCK(spba_lock); + +#define SPBA_MASTER_MIN 1 +#define SPBA_MASTER_MAX 7 + +/*! + * the base addresses for the SPBA modules + */ +static unsigned long spba_base = (unsigned long)IO_ADDRESS(SPBA_CTRL_BASE_ADDR); + +/*! + * SPBA clock + */ +static struct clk *spba_clk; +/*! + * This function allows the three masters (A, B, C) to take ownership of a + * shared peripheral. + * + * @param mod specified module as defined in \b enum \b #spba_module + * @param master one of more (or-ed together) masters as defined in \b enum \b #spba_masters + * + * @return 0 if successful; a negative errno value otherwise. + */ +int spba_take_ownership(int mod, int master) +{ + unsigned long spba_flags; + int rtn_val = -EIO; + + if (master < SPBA_MASTER_MIN || master > SPBA_MASTER_MAX) { + printk("%s() invalid master %d\n", __FUNCTION__, master); + return -EINVAL; + } + + if (spba_clk == NULL) { + spba_clk = clk_get(NULL, "spba"); + if (IS_ERR(spba_clk)) { + int ret = PTR_ERR(spba_clk); + + spba_clk = NULL; + return ret; + } + } + clk_enable(spba_clk); + + spin_lock_irqsave(&spba_lock, spba_flags); + __raw_writel(master, spba_base + mod); + + if ((__raw_readl(spba_base + mod) & MXC_SPBA_RAR_MASK) == master) { + rtn_val = 0; + } + + spin_unlock_irqrestore(&spba_lock, spba_flags); + + clk_disable(spba_clk); + return rtn_val; +} + +/*! + * This function releases the ownership for a shared peripheral. + * + * @param mod specified module as defined in \b enum \b #spba_module + * @param master one of more (or-ed together) masters as defined in \b enum \b #spba_masters + * + * @return 0 if successful; a negativ errno value otherwise. + */ +int spba_rel_ownership(int mod, int master) +{ + unsigned long spba_flags; + volatile unsigned long rar; + + if (master < SPBA_MASTER_MIN || master > SPBA_MASTER_MAX) { + printk("%s() invalid master %d\n", __FUNCTION__, master); + return -EINVAL; + } + + if (spba_clk == NULL) { + spba_clk = clk_get(NULL, "spba"); + if (IS_ERR(spba_clk)) { + int ret = PTR_ERR(spba_clk); + spba_clk = NULL; + return ret; + } + } + clk_enable(spba_clk); + + if ((__raw_readl(spba_base + mod) & master) == 0) { + clk_disable(spba_clk); + return -EBUSY; /* does not own it */ + } + + spin_lock_irqsave(&spba_lock, spba_flags); + + /* Since only the last 3 bits are writeable, doesn't need to mask off + bits 31-3 */ + rar = __raw_readl(spba_base + mod) & (~master); + __raw_writel(rar, spba_base + mod); + + if ((__raw_readl(spba_base + mod) & master) != 0) { + spin_unlock_irqrestore(&spba_lock, spba_flags); + clk_disable(spba_clk); + return -EIO; + } + spin_unlock_irqrestore(&spba_lock, spba_flags); + + clk_disable(spba_clk); + return 0; +} + +EXPORT_SYMBOL(spba_take_ownership); +EXPORT_SYMBOL(spba_rel_ownership); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("SPBA"); +MODULE_LICENSE("GPL"); diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/system.c linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/system.c --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/system.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/system.c 2009-06-29 10:49:32.000000000 +0200 @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -43,14 +44,6 @@ */ void arch_reset(char mode, const char *cmd) { - if (!cpu_is_mx1()) { - struct clk *clk; - - clk = clk_get_sys("imx-wdt.0", NULL); - if (!IS_ERR(clk)) - clk_enable(clk); - } - /* Assert SRS signal */ __raw_writew(WDOG_WCR_ENABLE, WDOG_WCR_REG); @@ -65,3 +58,22 @@ void arch_reset(char mode, const char *c /* we'll take a jump through zero as a poor second */ cpu_reset(0); } + +static int mxc_wdt_init(void) +{ + struct clk *wdt_clk; + + if (cpu_is_mx1()) + return 0; + + wdt_clk = clk_get_sys("imx-wdt.0", NULL); + if (IS_ERR(wdt_clk)) { + printk(KERN_ERR "%s: Failed to get imx-wdt.0 clk: %ld\n", + __FUNCTION__, PTR_ERR(wdt_clk)); + return PTR_ERR(wdt_clk); + } + clk_enable(wdt_clk); + clk_put(wdt_clk); + return 0; +} +arch_initcall(mxc_wdt_init); diff -purN linux-2.6.30-rc4-git/arch/arm/plat-mxc/time.c linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/time.c --- linux-2.6.30-rc4-git/arch/arm/plat-mxc/time.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/plat-mxc/time.c 2009-07-06 14:12:36.000000000 +0200 @@ -66,7 +66,7 @@ static inline void gpt_irq_disable(void) { unsigned int tmp; - if (cpu_is_mx3()) + if (cpu_is_mx3() || cpu_is_mx25()) __raw_writel(0, timer_base + MX3_IR); else { tmp = __raw_readl(timer_base + MXC_TCTL); @@ -76,7 +76,7 @@ static inline void gpt_irq_disable(void) static inline void gpt_irq_enable(void) { - if (cpu_is_mx3()) + if (cpu_is_mx3() || cpu_is_mx25()) __raw_writel(1<<0, timer_base + MX3_IR); else { __raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN, @@ -88,9 +88,9 @@ static void gpt_irq_acknowledge(void) { if (cpu_is_mx1()) __raw_writel(0, timer_base + MX1_2_TSTAT); - if (cpu_is_mx2()) + if (cpu_is_mx2() && !cpu_is_mx25()) __raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP, timer_base + MX1_2_TSTAT); - if (cpu_is_mx3()) + if (cpu_is_mx3() || cpu_is_mx25()) __raw_writel(MX3_TSTAT_OF1, timer_base + MX3_TSTAT); } @@ -117,7 +117,7 @@ static int __init mxc_clocksource_init(s { unsigned int c = clk_get_rate(timer_clk); - if (cpu_is_mx3()) + if (cpu_is_mx3() || cpu_is_mx25()) clocksource_mxc.read = mx3_get_cycles; clocksource_mxc.mult = clocksource_hz2mult(c, @@ -180,7 +180,7 @@ static void mxc_set_mode(enum clock_even if (mode != clockevent_mode) { /* Set event time into far-far future */ - if (cpu_is_mx3()) + if (cpu_is_mx3() || cpu_is_mx25()) __raw_writel(__raw_readl(timer_base + MX3_TCN) - 3, timer_base + MX3_TCMP); else @@ -233,7 +233,7 @@ static irqreturn_t mxc_timer_interrupt(i struct clock_event_device *evt = &clockevent_mxc; uint32_t tstat; - if (cpu_is_mx3()) + if (cpu_is_mx3() || cpu_is_mx25()) tstat = __raw_readl(timer_base + MX3_TSTAT); else tstat = __raw_readl(timer_base + MX1_2_TSTAT); @@ -264,7 +264,7 @@ static int __init mxc_clockevent_init(st { unsigned int c = clk_get_rate(timer_clk); - if (cpu_is_mx3()) + if (cpu_is_mx3() || cpu_is_mx25()) clockevent_mxc.set_next_event = mx3_set_next_event; clockevent_mxc.mult = div_sc(c, NSEC_PER_SEC, @@ -313,7 +313,7 @@ void __init mxc_timer_init(struct clk *t __raw_writel(0, timer_base + MXC_TCTL); __raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */ - if (cpu_is_mx3()) + if (cpu_is_mx3() || cpu_is_mx25()) tctl_val = MX3_TCTL_CLK_IPG | MX3_TCTL_FRR | MX3_TCTL_WAITEN | MXC_TCTL_TEN; else tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN; diff -purN linux-2.6.30-rc4-git/arch/arm/tools/mach-types linux-2.6.30-rc4-karo3/arch/arm/tools/mach-types --- linux-2.6.30-rc4-git/arch/arm/tools/mach-types 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/arch/arm/tools/mach-types 2009-06-02 18:02:54.000000000 +0200 @@ -12,7 +12,7 @@ # # http://www.arm.linux.org.uk/developer/machines/?action=new # -# Last update: Mon Mar 23 20:09:01 2009 +# Last update: Mon Apr 20 10:31:38 2009 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -1721,7 +1721,7 @@ sapphire MACH_SAPPHIRE SAPPHIRE 1729 csb637xo MACH_CSB637XO CSB637XO 1730 evisiong MACH_EVISIONG EVISIONG 1731 stmp37xx MACH_STMP37XX STMP37XX 1732 -stmp378x MACH_STMP38XX STMP38XX 1733 +stmp378x MACH_STMP378X STMP378X 1733 tnt MACH_TNT TNT 1734 tbxt MACH_TBXT TBXT 1735 playmate MACH_PLAYMATE PLAYMATE 1736 @@ -2132,3 +2132,41 @@ apollo MACH_APOLLO APOLLO 2141 at91cap9stk MACH_AT91CAP9STK AT91CAP9STK 2142 spc300 MACH_SPC300 SPC300 2143 eko MACH_EKO EKO 2144 +ccw9m2443 MACH_CCW9M2443 CCW9M2443 2145 +ccw9m2443js MACH_CCW9M2443JS CCW9M2443JS 2146 +m2m_router_device MACH_M2M_ROUTER_DEVICE M2M_ROUTER_DEVICE 2147 +str9104nas MACH_STAR9104NAS STAR9104NAS 2148 +pca100 MACH_PCA100 PCA100 2149 +z3_dm365_mod_01 MACH_Z3_DM365_MOD_01 Z3_DM365_MOD_01 2150 +hipox MACH_HIPOX HIPOX 2151 +omap3_piteds MACH_OMAP3_PITEDS OMAP3_PITEDS 2152 +bm150r MACH_BM150R BM150R 2153 +tbone MACH_TBONE TBONE 2154 +merlin MACH_MERLIN MERLIN 2155 +falcon MACH_FALCON FALCON 2156 +davinci_da850_evm MACH_DAVINCI_DA850_EVM DAVINCI_DA850_EVM 2157 +s5p6440 MACH_S5P6440 S5P6440 2158 +at91sam9g10ek MACH_AT91SAM9G10EK AT91SAM9G10EK 2159 +omap_4430sdp MACH_OMAP_4430SDP OMAP_4430SDP 2160 +lpc313x MACH_LPC313X LPC313X 2161 +magx_zn5 MACH_MAGX_ZN5 MAGX_ZN5 2162 +magx_em30 MACH_MAGX_EM30 MAGX_EM30 2163 +magx_ve66 MACH_MAGX_VE66 MAGX_VE66 2164 +meesc MACH_MEESC MEESC 2165 +otc570 MACH_OTC570 OTC570 2166 +bcu2412 MACH_BCU2412 BCU2412 2167 +beacon MACH_BEACON BEACON 2168 +actia_tgw MACH_ACTIA_TGW ACTIA_TGW 2169 +e4430 MACH_E4430 E4430 2170 +ql300 MACH_QL300 QL300 2171 +btmavb101 MACH_BTMAVB101 BTMAVB101 2172 +btmawb101 MACH_BTMAWB101 BTMAWB101 2173 +sq201 MACH_SQ201 SQ201 2174 +quatro45xx MACH_QUATRO45XX QUATRO45XX 2175 +openpad MACH_OPENPAD OPENPAD 2176 +tx25 MACH_TX25 TX25 2177 +omap3_torpedo MACH_OMAP3_TORPEDO OMAP3_TORPEDO 2178 +htcraphael_k MACH_HTCRAPHAEL_K HTCRAPHAEL_K 2179 +pxa255 MACH_PXA255 PXA255 2180 +lal43 MACH_LAL43 LAL43 2181 +htcraphael_cdma500 MACH_HTCRAPHAEL_CDMA500 HTCRAPHAEL_CDMA500 2182 diff -purN linux-2.6.30-rc4-git/drivers/input/touchscreen/Kconfig linux-2.6.30-rc4-karo3/drivers/input/touchscreen/Kconfig --- linux-2.6.30-rc4-git/drivers/input/touchscreen/Kconfig 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/drivers/input/touchscreen/Kconfig 2009-06-23 13:33:58.000000000 +0200 @@ -287,6 +287,18 @@ config TOUCHSCREEN_ATMEL_TSADCC To compile this driver as a module, choose M here: the module will be called atmel_tsadcc. +config TOUCHSCREEN_MXC_TSADCC + tristate "i.MX25 Touchscreen Interface" + depends on MACH_MX25 + help + Say Y here if you have a 4-wire touchscreen connected to the + ADC Controller on your Freescale i.MX25 SoC. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called atmel_tsadcc. + config TOUCHSCREEN_UCB1400 tristate "Philips UCB1400 touchscreen" depends on AC97_BUS diff -purN linux-2.6.30-rc4-git/drivers/input/touchscreen/Makefile linux-2.6.30-rc4-karo3/drivers/input/touchscreen/Makefile --- linux-2.6.30-rc4-git/drivers/input/touchscreen/Makefile 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/drivers/input/touchscreen/Makefile 2009-06-23 13:33:59.000000000 +0200 @@ -16,19 +16,20 @@ obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunz obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o -obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o -obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o -obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o -obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o +obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o +obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o +obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o +obj-$(CONFIG_TOUCHSCREEN_MXC_TSADCC) += mxc_tsadcc.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o +obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o diff -purN linux-2.6.30-rc4-git/drivers/input/touchscreen/mxc_tsadcc.c linux-2.6.30-rc4-karo3/drivers/input/touchscreen/mxc_tsadcc.c --- linux-2.6.30-rc4-git/drivers/input/touchscreen/mxc_tsadcc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/drivers/input/touchscreen/mxc_tsadcc.c 2009-07-01 11:27:20.000000000 +0200 @@ -0,0 +1,897 @@ +/* + * Freescale i.MX25 Touch Screen Driver + * + * Copyright (c) 2009 Lothar Wassmann + * + * Based on atmel_tsadcc.c + * Copyright (c) 2008 ATMEL et. al. + * and code from Freescale BSP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mxc_tsadcc.h" + +#define TSC_NUM_SAMPLES 1 +#define ADC_NUM_SAMPLES 1 + +#ifdef DEBUG +static int debug = 4; +#define dbg_lvl(n) ((n) < debug) +module_param(debug, int, S_IRUGO | S_IWUSR); + +#define DBG(lvl, fmt...) do { if (dbg_lvl(lvl)) printk(KERN_DEBUG fmt); } while (0) +#else +static int debug; +#define dbg_lvl(n) 0 +module_param(debug, int, 0); + +#define DBG(lvl, fmt...) do { } while (0) +#endif + +#define DEFAULT_ADC_CLOCK 1666667 +#define DEFAULT_RX_VALUE 360 + +//#define REPORT_PRESSURE + +struct mxc_tsadcc_fifo_data { + unsigned int id:4, + data:12; +}; + +/* The layout of this structure depends on the setup created by mxc_tsadcc_config() */ +struct mxc_tsadcc_tsc_data { + struct mxc_tsadcc_fifo_data pendown[TSC_NUM_SAMPLES]; + struct mxc_tsadcc_fifo_data pos_x[TSC_NUM_SAMPLES]; + struct mxc_tsadcc_fifo_data pos_y[TSC_NUM_SAMPLES]; +#ifdef REPORT_PRESSURE + struct mxc_tsadcc_fifo_data yn[TSC_NUM_SAMPLES]; + struct mxc_tsadcc_fifo_data xp[TSC_NUM_SAMPLES]; +#endif + struct mxc_tsadcc_fifo_data pendown2[TSC_NUM_SAMPLES]; +}; + +struct mxc_tsadcc_adc_data { + struct mxc_tsadcc_fifo_data data[ADC_NUM_SAMPLES]; +}; + +struct mxc_tsadcc { + struct input_dev *input; + char phys[32]; + void __iomem *reg_base; + struct clk *clk; + int irq; + struct work_struct work; + struct timer_list timer; + wait_queue_head_t wq; + unsigned int pendown:1, + clk_enabled:1, + attrs:1, + valid_measure:1; + mxc_tsc_mode tsc_mode; + struct mxc_tsadcc_tsc_data *tsc_data; + struct mxc_tsadcc_adc_data *adc_data; + unsigned int r_xplate; + + struct mutex convert_mutex; + unsigned short pressure; + unsigned short prev_absx; + unsigned short prev_absy; +}; + +#ifdef DEBUG +#define mxc_tsadcc_read(s,reg) _mxc_tsadcc_read(s,reg,#reg,__FUNCTION__) +#define mxc_tsadcc_write(s,reg,val) _mxc_tsadcc_write(s,reg,val,#reg,__FUNCTION__) + +static inline unsigned long _mxc_tsadcc_read(struct mxc_tsadcc *ts_dev, int reg, + const char *name, const char *fn) +{ + unsigned long val = __raw_readl(ts_dev->reg_base + reg); + DBG(3, "%s: Read %08lx from %s\n", fn, val, name); + return val; +} + +static inline void _mxc_tsadcc_write(struct mxc_tsadcc *ts_dev, int reg, unsigned long val, + const char *name, const char *fn) +{ + __raw_writel(val, ts_dev->reg_base + reg); + DBG(3, "%s: Wrote %08lx to %s\n", fn, val, name); +} +#else +static inline unsigned long mxc_tsadcc_read(struct mxc_tsadcc *ts_dev, int reg) +{ + return __raw_readl(ts_dev->reg_base + reg); +} +static inline void mxc_tsadcc_write(struct mxc_tsadcc *ts_dev, int reg, unsigned long val) +{ + __raw_writel(val, ts_dev->reg_base + reg); +} +#endif + +static void tsc_clk_enable(struct mxc_tsadcc *ts_dev) +{ + if (!ts_dev->clk_enabled) { + unsigned long reg; + clk_enable(ts_dev->clk); + + reg = mxc_tsadcc_read(ts_dev, TGCR); + reg |= TGCR_IPG_CLK_EN; + mxc_tsadcc_write(ts_dev, TGCR, reg); + ts_dev->clk_enabled = 1; + } +} + +static void tsc_clk_disable(struct mxc_tsadcc *ts_dev) +{ + if (ts_dev->clk_enabled) { + unsigned long reg; + + reg = mxc_tsadcc_read(ts_dev, TGCR); + reg &= ~TGCR_IPG_CLK_EN; + mxc_tsadcc_write(ts_dev, TGCR, reg); + + clk_disable(ts_dev->clk); + ts_dev->clk_enabled = 0; + } +} + +static inline int mxc_tsadcc_pendown(struct mxc_tsadcc *ts_dev) +{ + return ts_dev->pendown; +} + +static int mxc_tsadcc_read_adc(struct mxc_tsadcc *ts_dev, int chan) +{ + int ret = 1; + unsigned long reg; + unsigned int data_num = 0; + int i; + union { + unsigned int fifo[sizeof(struct mxc_tsadcc_tsc_data) / sizeof(int)]; + struct mxc_tsadcc_tsc_data data; + } *fifo_data = (void *)ts_dev->adc_data; + struct mxc_tsadcc_adc_data *adc_data = ts_dev->adc_data; + int lastitemid = 0; + struct input_dev *input_dev = ts_dev->input; + long timeout = msecs_to_jiffies(1 * ADC_NUM_SAMPLES); + + mutex_lock(&ts_dev->convert_mutex); + reg = (0xf << CQCR_FIFOWATERMARK_SHIFT) | + (lastitemid << CQCR_LAST_ITEM_ID_SHIFT) | CQCR_QSM_FQS; + mxc_tsadcc_write(ts_dev, GCQCR, reg); + + reg = ((ADC_NUM_SAMPLES - 1) << CC_NOS_SHIFT) | + (16 << CC_SETTLING_TIME_SHIFT) | + CC_YPLLSW_OFF | CC_XNURSW_OFF | CC_XPULSW | + CC_SELREFP_INT | chan | CC_SEL_REFN_AGND; + mxc_tsadcc_write(ts_dev, GCC0, reg); + + memset(adc_data, 0, sizeof(*adc_data)); + + reg = mxc_tsadcc_read(ts_dev, GCQCR); + reg |= CQCR_FQS; + mxc_tsadcc_write(ts_dev, GCQCR, reg); + + /* enable end of conversion interrupt */ + reg = mxc_tsadcc_read(ts_dev, GCQMR); + reg &= ~CQMR_EOQ_IRQ_MSK; + mxc_tsadcc_write(ts_dev, GCQMR, reg); + + timeout = wait_event_timeout(ts_dev->wq, + mxc_tsadcc_read(ts_dev, GCQSR) & + CQSR_EOQ, timeout); + if (timeout == 0 && + !(mxc_tsadcc_read(ts_dev, GCQSR) & CQSR_EOQ)) { + dev_err(&input_dev->dev, + "Timeout waiting for data on channel %d\n", + chan); + ret = -ETIME; + goto exit; + } + + reg = mxc_tsadcc_read(ts_dev, GCQCR); + reg &= ~CQCR_FQS; + mxc_tsadcc_write(ts_dev, GCQCR, reg); + reg = mxc_tsadcc_read(ts_dev, GCQSR); + + /* clear interrupt status bit */ + reg = CQSR_EOQ; + mxc_tsadcc_write(ts_dev, GCQSR, reg); + + while (!(mxc_tsadcc_read(ts_dev, GCQSR) & CQSR_EMPT)) { + BUG_ON(data_num >= ARRAY_SIZE(fifo_data->fifo)); + reg = mxc_tsadcc_read(ts_dev, GCQFIFO); + fifo_data->fifo[data_num] = reg; + data_num++; + } + DBG(0, "%s: Read %u words from fifo\n", __FUNCTION__, data_num); + for (i = 0; i < data_num; i++) { + DBG(0, "%s: data[%d]=%03x ID %d\n", __FUNCTION__, i, + adc_data->data[i].data, adc_data->data[i].id); + } + exit: + mutex_unlock(&ts_dev->convert_mutex); + + return ret; +} + +struct mxc_tsadcc_attr { + struct device_attribute attr; + unsigned int reg; +}; + +#define to_mxc_tsadcc_attr(a) container_of(a, struct mxc_tsadcc_attr, attr) + +#define MXC_TSADCC_DEV_ATTR(_name, _mode, _reg, _read, _write) \ + struct mxc_tsadcc_attr mxc_tsadcc_attr_##_name = { \ + .attr = __ATTR(_name,_mode,_read,_write), \ + .reg = _reg, \ + } + +static ssize_t mxc_tsadcc_attr_get(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t ret = -EIO; + struct mxc_tsadcc *ts_dev = dev_get_drvdata(dev); + struct mxc_tsadcc_attr *mxc_tsadcc_attr = to_mxc_tsadcc_attr(attr); + + if (mxc_tsadcc_read_adc(ts_dev, mxc_tsadcc_attr->reg)) { + ret = sprintf(buf, "0x%04x\n", ts_dev->adc_data->data[0].data); + } + return ret; +} + +#if 0 +static ssize_t mxc_tsadcc_attr_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t ret; + struct mxc_tsadcc *ts_dev = dev_get_drvdata(dev); + struct mxc_tsadcc_attr *mxc_tsadcc_attr = to_mxc_tsadcc_attr(attr); + unsigned long val = simple_strtoul(buf, NULL, 0); + + mxc_tsadcc_write(ts_dev, mxc_tsadcc_attr->reg, val); + return count; +} +#endif + +MXC_TSADCC_DEV_ATTR(inaux0, S_IRUGO, CC_SELIN_INAUX0, mxc_tsadcc_attr_get, NULL); +MXC_TSADCC_DEV_ATTR(inaux1, S_IRUGO, CC_SELIN_INAUX1, mxc_tsadcc_attr_get, NULL); +MXC_TSADCC_DEV_ATTR(inaux2, S_IRUGO, CC_SELIN_INAUX2, mxc_tsadcc_attr_get, NULL); + +static struct attribute *mxc_tsadcc_attrs[] = { + &mxc_tsadcc_attr_inaux0.attr.attr, + &mxc_tsadcc_attr_inaux1.attr.attr, + &mxc_tsadcc_attr_inaux2.attr.attr, + NULL +}; + +static const struct attribute_group mxc_tsadcc_attr_group = { + .attrs = mxc_tsadcc_attrs, +}; + +static int mxc_tsadcc_read_ts(struct mxc_tsadcc *ts_dev, int force) +{ + int ret; + unsigned long reg; + unsigned int data_num = 0; + union { + unsigned int fifo[sizeof(struct mxc_tsadcc_tsc_data) / sizeof(int)]; + struct mxc_tsadcc_tsc_data data; + } *fifo_data = (void *)ts_dev->tsc_data; + struct mxc_tsadcc_tsc_data *tsc_data = ts_dev->tsc_data; + struct input_dev *input_dev = ts_dev->input; + long timeout = msecs_to_jiffies(1 * TSC_NUM_SAMPLES); + + mutex_lock(&ts_dev->convert_mutex); + memset(tsc_data, 0, sizeof(*tsc_data)); + if (force) { + reg = (0x1 << CC_YPLLSW_SHIFT) | (0x1 << CC_XNURSW_SHIFT) | + CC_XPULSW; + mxc_tsadcc_write(ts_dev, TICR, reg); + + /* FQS */ + reg = mxc_tsadcc_read(ts_dev, TCQCR); + reg &= ~CQCR_QSM_MASK; + reg |= CQCR_QSM_FQS; + mxc_tsadcc_write(ts_dev, TCQCR, reg); + reg = mxc_tsadcc_read(ts_dev, TCQCR); + reg |= CQCR_FQS; + mxc_tsadcc_write(ts_dev, TCQCR, reg); + + timeout = wait_event_timeout(ts_dev->wq, + mxc_tsadcc_read(ts_dev, TCQSR) & + CQSR_EOQ, timeout); + if (timeout == 0 && + !(mxc_tsadcc_read(ts_dev, TCQSR) & CQSR_EOQ)) { + dev_err(&input_dev->dev, + "Timeout waiting for TSC data\n"); + ret = -ETIME; + goto exit; + } + + /* stop FQS */ + reg = mxc_tsadcc_read(ts_dev, TCQCR); + reg &= ~CQCR_QSM_MASK; + mxc_tsadcc_write(ts_dev, TCQCR, reg); + reg = mxc_tsadcc_read(ts_dev, TCQCR); + reg &= ~CQCR_FQS; + mxc_tsadcc_write(ts_dev, TCQCR, reg); + + /* clear status bit */ + reg = mxc_tsadcc_read(ts_dev, TCQSR); + reg = CQSR_EOQ; + mxc_tsadcc_write(ts_dev, TCQSR, reg); + } else { + /* Config idle for 4-wire */ + reg = TSC_4WIRE_TOUCH_DETECT; + mxc_tsadcc_write(ts_dev, TICR, reg); + + /* Pen interrupt starts new conversion queue */ + reg = mxc_tsadcc_read(ts_dev, TCQCR); + reg &= ~CQCR_QSM_MASK; + reg |= CQCR_QSM_PEN; + mxc_tsadcc_write(ts_dev, TCQCR, reg); + + /* PDEN and PDBEN */ + reg = mxc_tsadcc_read(ts_dev, TGCR); + reg |= (TGCR_PDB_EN | TGCR_PD_EN); + mxc_tsadcc_write(ts_dev, TGCR, reg); + + wait_event_timeout(ts_dev->wq, + mxc_tsadcc_read(ts_dev, TCQSR) & + CQSR_EOQ, timeout); + if (timeout == 0 && + !(mxc_tsadcc_read(ts_dev, TCQSR) & CQSR_EOQ)) { + dev_err(&input_dev->dev, + "Timeout waiting for TSC data\n"); + ret = -ETIME; + goto exit; + } + + /* stop the conversion */ + reg = mxc_tsadcc_read(ts_dev, TCQCR); + reg &= ~CQCR_QSM_MASK; + mxc_tsadcc_write(ts_dev, TCQCR, reg); + + /* clear interrupt status flags */ + reg = CQSR_PD | CQSR_EOQ; + mxc_tsadcc_write(ts_dev, TCQSR, reg); + + /* change configuration for FQS mode */ + reg = (0x1 << CC_YPLLSW_SHIFT) | (0x1 << CC_XNURSW_SHIFT) | + CC_XPULSW; + mxc_tsadcc_write(ts_dev, TICR, reg); + } + + while (!(mxc_tsadcc_read(ts_dev, TCQSR) & CQSR_EMPT)) { + BUG_ON(data_num >= ARRAY_SIZE(fifo_data->fifo)); + reg = mxc_tsadcc_read(ts_dev, TCQFIFO); + fifo_data->fifo[data_num] = reg; + data_num++; + } + DBG(0, "%s: Read %u words from fifo\n", __FUNCTION__, data_num); + + ret = tsc_data->pendown[0].data <= 0x600 && + tsc_data->pendown2[0].data <= 0x600; + + if (ret) { + DBG(0, "%s: pos_x=%03x pos_y=%03x\n", + __FUNCTION__, tsc_data->pos_x[0].data, + tsc_data->pos_y[0].data); +#ifdef REPORT_PRESSURE + DBG(0, "%s: pos_x=%03x pos_y=%03x xp=%03x yn=%03x\n", + __FUNCTION__, tsc_data->xp[0].data, + tsc_data->yn[0].data); +#endif + if (/*(mxc_tsadcc_read(ts_dev, TCQSR) & CQSR_PD) && */ + tsc_data->pos_x[0].data && + tsc_data->pos_x[1].data && + tsc_data->pos_x[2].data) { +#ifdef REPORT_PRESSURE + ts_dev->pressure = ts_dev->r_xplate * + (tsc_data->pos_x[0].data / 4096) * + ((tsc_data->yn[0].data - tsc_data->xp[0].data) / + tsc_data->xp[0].data); +#else + ts_dev->pressure = 4095; +#endif + DBG(0, "%s: Detected PEN DOWN with pressure %03x\n", + __FUNCTION__, ts_dev->pressure); + ts_dev->pendown = 1; + } else { + DBG(0, "%s: Detected PEN UP\n", __FUNCTION__); + ts_dev->pendown = 0; + } + } else { + DBG(0, "%s: Discarding measurement\n", __FUNCTION__); + ts_dev->pendown = 0; + } + exit: + mutex_unlock(&ts_dev->convert_mutex); + + return ret; +} + +static inline void mxc_tsadcc_enable_pendown(struct mxc_tsadcc *ts_dev) +{ + unsigned long reg; + + /* Config idle for 4-wire */ + reg = TSC_4WIRE_TOUCH_DETECT; + mxc_tsadcc_write(ts_dev, TICR, reg); + + DBG(0, "%s: Enable PD detect\n", __FUNCTION__); + reg = mxc_tsadcc_read(ts_dev, TGCR); + reg |= TGCR_PD_EN; + mxc_tsadcc_write(ts_dev, TGCR, reg); +} + +static void mxc_tsadcc_work(struct work_struct *w) +{ + struct mxc_tsadcc *ts_dev = container_of(w, struct mxc_tsadcc, work); + struct input_dev *input_dev = ts_dev->input; + + if (mxc_tsadcc_read_ts(ts_dev, 1)) { + DBG(0, "%s: Got sample %d\n", __FUNCTION__, ts_dev->pendown); + if (mxc_tsadcc_pendown(ts_dev)) { + if (!ts_dev->valid_measure) { + ts_dev->valid_measure = 1; + } else { + DBG(0, "%s: Reporting PD event %03x @ %03x,%03x\n", + __FUNCTION__, ts_dev->pressure, + ts_dev->tsc_data->pos_x[0].data, + ts_dev->tsc_data->pos_y[0].data); + + input_report_abs(input_dev, ABS_X, + ts_dev->tsc_data->pos_x[0].data); + input_report_abs(input_dev, ABS_Y, + ts_dev->tsc_data->pos_y[0].data); +#ifdef REPORT_PRESSURE + input_report_abs(input_dev, ABS_PRESSURE, + ts_dev->pressure); +#endif + input_report_key(input_dev, BTN_TOUCH, 1); + input_sync(input_dev); + } + ts_dev->prev_absx = ts_dev->tsc_data->pos_x[0].data; + ts_dev->prev_absy = ts_dev->tsc_data->pos_y[0].data; + DBG(0, "%s: Enabling timer\n", __FUNCTION__); + mod_timer(&ts_dev->timer, jiffies + + msecs_to_jiffies(10)); + return; + } + } + if (ts_dev->valid_measure) { + DBG(0, "%s: Reporting PU event: %03x,%03x\n", __FUNCTION__, + ts_dev->prev_absx, ts_dev->prev_absy); + input_report_abs(input_dev, ABS_X, + ts_dev->prev_absx); + input_report_abs(input_dev, ABS_Y, + ts_dev->prev_absy); +#ifdef REPORT_PRESSURE + input_report_abs(input_dev, ABS_PRESSURE, 0); +#endif + input_report_key(input_dev, BTN_TOUCH, 0); + input_sync(input_dev); + } + ts_dev->valid_measure = 0; + mxc_tsadcc_enable_pendown(ts_dev); +} + +static void mxc_tsadcc_timer(unsigned long data) +{ + struct mxc_tsadcc *ts_dev = (void *)data; + schedule_work(&ts_dev->work); +} + +static irqreturn_t mxc_tsadcc_interrupt(int irq, void *dev) +{ + struct mxc_tsadcc *ts_dev = dev; + //struct input_dev *input_dev = ts_dev->input; + unsigned long reg; + unsigned long status = mxc_tsadcc_read(ts_dev, TGSR); + + DBG(0, "%s: TCSR= %08lx\n", __FUNCTION__, status); + + if (status & TGSR_TCQ_INT) { + DBG(0, "%s: TCQSR=%08lx\n", __FUNCTION__, + mxc_tsadcc_read(ts_dev, TCQSR)); + reg = mxc_tsadcc_read(ts_dev, TCQSR); + if (reg & CQSR_PD) { + /* disable pen down detect */ + DBG(0, "%s: Disable PD detect\n", __FUNCTION__); + reg = mxc_tsadcc_read(ts_dev, TGCR); + reg &= ~TGCR_PD_EN; + mxc_tsadcc_write(ts_dev, TGCR, reg); + + /* Now schedule new measurement */ + schedule_work(&ts_dev->work); + } + } + if (status & TGSR_GCQ_INT) { + DBG(0, "%s: GCQSR=%08lx\n", __FUNCTION__, + mxc_tsadcc_read(ts_dev, GCQSR)); + reg = mxc_tsadcc_read(ts_dev, GCQSR); + if (reg & CQSR_EOQ) { + reg = mxc_tsadcc_read(ts_dev, GCQMR); + reg |= CQMR_EOQ_IRQ_MSK; + mxc_tsadcc_write(ts_dev, GCQMR, reg); + } + } + return IRQ_HANDLED; +} + +static void mxc_tsadcc_4wire_config(struct mxc_tsadcc *ts_dev) +{ + unsigned long reg; + int lastitemid; + + /* Level sense */ + reg = mxc_tsadcc_read(ts_dev, TCQCR); + reg |= CQCR_PD_CFG; + reg |= (0xf << CQCR_FIFOWATERMARK_SHIFT); /* watermark */ + mxc_tsadcc_write(ts_dev, TCQCR, reg); + + /* Configure 4-wire */ + reg = TSC_4WIRE_PRECHARGE; + reg |= CC_IGS; + mxc_tsadcc_write(ts_dev, TCC0, reg); + + reg = TSC_4WIRE_TOUCH_DETECT; + reg |= (TSC_NUM_SAMPLES - 1) << CC_NOS_SHIFT; /* 4 samples */ + reg |= 32 << CC_SETTLING_TIME_SHIFT; /* it's important! */ + mxc_tsadcc_write(ts_dev, TCC1, reg); + + reg = TSC_4WIRE_X_MEASURE; + reg |= (TSC_NUM_SAMPLES - 1) << CC_NOS_SHIFT; /* 4 samples */ + reg |= 16 << CC_SETTLING_TIME_SHIFT; /* settling time */ + mxc_tsadcc_write(ts_dev, TCC2, reg); + + reg = TSC_4WIRE_Y_MEASURE; + reg |= (TSC_NUM_SAMPLES - 1) << CC_NOS_SHIFT; /* 4 samples */ + reg |= 16 << CC_SETTLING_TIME_SHIFT; /* settling time */ + mxc_tsadcc_write(ts_dev, TCC3, reg); + + reg = TSC_4WIRE_YN_MEASURE; + reg |= (TSC_NUM_SAMPLES - 1) << CC_NOS_SHIFT; /* 4 samples */ + reg |= 16 << CC_SETTLING_TIME_SHIFT; /* settling time */ + mxc_tsadcc_write(ts_dev, TCC4, reg); + + reg = TSC_4WIRE_XP_MEASURE; + reg |= (TSC_NUM_SAMPLES - 1) << CC_NOS_SHIFT; /* 4 samples */ + reg |= 16 << CC_SETTLING_TIME_SHIFT; /* settling time */ + mxc_tsadcc_write(ts_dev, TCC5, reg); + + reg = (TCQ_ITEM_TCC0 << CQ_ITEM0_SHIFT) | + (TCQ_ITEM_TCC1 << CQ_ITEM1_SHIFT) | + (TCQ_ITEM_TCC2 << CQ_ITEM2_SHIFT) | + (TCQ_ITEM_TCC3 << CQ_ITEM3_SHIFT) | + (TCQ_ITEM_TCC0 << CQ_ITEM4_SHIFT) | + (TCQ_ITEM_TCC1 << CQ_ITEM5_SHIFT); + mxc_tsadcc_write(ts_dev, TCQ_ITEM_7_0, reg); + + lastitemid = 5; + reg = mxc_tsadcc_read(ts_dev, TCQCR); + reg = (reg & ~CQCR_LAST_ITEM_ID_MASK) | + (lastitemid << CQCR_LAST_ITEM_ID_SHIFT); + mxc_tsadcc_write(ts_dev, TCQCR, reg); + + /* pen down enable */ + reg = mxc_tsadcc_read(ts_dev, TCQCR); + reg &= ~CQCR_PD_MSK; + mxc_tsadcc_write(ts_dev, TCQCR, reg); + reg = mxc_tsadcc_read(ts_dev, TCQMR); + reg &= ~CQMR_PD_IRQ_MSK; + mxc_tsadcc_write(ts_dev, TCQMR, reg); + + /* Config idle for 4-wire */ + reg = TSC_4WIRE_TOUCH_DETECT; + mxc_tsadcc_write(ts_dev, TICR, reg); + + /* Pen interrupt starts new conversion queue */ + reg = mxc_tsadcc_read(ts_dev, TCQCR); + reg &= ~CQCR_QSM_MASK; + reg |= CQCR_QSM_PEN; + mxc_tsadcc_write(ts_dev, TCQCR, reg); +} + +static void mxc_tsadcc_config(struct platform_device *pdev) +{ + struct mxc_tsadcc *ts_dev = platform_get_drvdata(pdev); + struct mxc_tsadcc_pdata *pdata = pdev->dev.platform_data; + unsigned int tgcr; + unsigned int pdbt; + unsigned int pdben; + unsigned int intref; + unsigned int adc_clk = DEFAULT_ADC_CLOCK; + unsigned long ipg_clk; + unsigned int clkdiv; + + if (pdata) { + pdbt = pdata->pen_debounce_time - 1; + pdben = pdata->pen_debounce_time > 0; + intref = !!pdata->intref; + if (pdata->adc_clk > 0) { + adc_clk = pdata->adc_clk; + } + ts_dev->r_xplate = pdata->r_xplate; + } else { + dev_dbg(&pdev->dev, "No platform_data; using defaults\n"); + pdbt = TGCR_PDBTIME128; + pdben = 1; + intref = 1; + } + if (ts_dev->r_xplate == 0) { + ts_dev->r_xplate = DEFAULT_RX_VALUE; + DBG(0, "%s: Assuming default Rx value of %u Ohms\n", + __FUNCTION__, ts_dev->r_xplate); + } + ipg_clk = clk_get_rate(ts_dev->clk); + dev_info(&pdev->dev, "Master clock is: %lu.%06luMHz requested ADC clock: %u.%06uMHz\n", + ipg_clk / 1000000, ipg_clk % 1000000, + adc_clk / 1000000, adc_clk % 1000000); + /* + * adc_clk = ipg_clk / (2 * clkdiv + 2) + * The exact formula for the clock divider would be: + * clkdiv = ipg_clk / (2 * adc_clk) - 1 + * but we drop the '- 1' due to integer truncation + * and to make sure the actual clock is always less or equal + * to the designated clock. + */ + clkdiv = ipg_clk / (2 * adc_clk + 1); + if (clkdiv > 31) { + clkdiv = 31; + dev_warn(&pdev->dev, + "cannot accomodate designated clock of %u.%06uMHz; using %lu.%06luMHz\n", + adc_clk / 1000000, adc_clk % 1000000, + ipg_clk / (2 * clkdiv + 2) / 1000000, + ipg_clk / (2 * clkdiv + 2) % 1000000); + } else { + dev_dbg(&pdev->dev, + "clkdiv=%u actual ADC clock: %lu.%06luMHz\n", + clkdiv, ipg_clk / (2 * (clkdiv + 1)) / 1000000, + ipg_clk / (2 * clkdiv + 2) % 1000000); + } + + tgcr = ((pdbt << TGCR_PDBTIME_SHIFT) & TGCR_PDBTIME_MASK) | /* pen debounce time */ + (pdben * TGCR_PDB_EN) | /* pen debounce enable */ + (intref * TGCR_INTREFEN) | /* pen debounce enable */ + TGCR_POWER_SAVE | /* Switch TSC on */ + TGCR_PD_EN | /* Enable Pen Detect */ + ((clkdiv << TGCR_ADCCLKCFG_SHIFT) & TGCR_ADCCLKCFG_MASK); + + /* reset TSC */ + mxc_tsadcc_write(ts_dev, TGCR, TGCR_TSC_RST); + while (mxc_tsadcc_read(ts_dev, TGCR) & TGCR_TSC_RST) { + cpu_relax(); + } + mxc_tsadcc_write(ts_dev, TGCR, tgcr); + + mxc_tsadcc_4wire_config(ts_dev); + tsc_clk_enable(ts_dev); +} + +static int __devinit mxc_tsadcc_probe(struct platform_device *pdev) +{ + int err; + struct mxc_tsadcc *ts_dev; + struct input_dev *input_dev; + struct resource *res; + int irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "No mmio resource defined\n"); + return -ENODEV; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "No IRQ assigned\n"); + return -ENODEV; + } + + if (!request_mem_region(res->start, resource_size(res), + "mxc tsadcc regs")) { + return -EBUSY; + } + + /* Allocate memory for device */ + ts_dev = kzalloc(sizeof(struct mxc_tsadcc), GFP_KERNEL); + if (!ts_dev) { + dev_err(&pdev->dev, "Failed to allocate memory\n"); + err = -ENOMEM; + goto err_release_mem; + } + + /* allocate conversion buffers separately to prevent + * cacheline alignment issues when using DMA */ + ts_dev->tsc_data = kzalloc(sizeof(struct mxc_tsadcc_tsc_data), GFP_KERNEL); + ts_dev->adc_data = kzalloc(sizeof(struct mxc_tsadcc_adc_data), GFP_KERNEL); + if (ts_dev->tsc_data == NULL || ts_dev->adc_data == NULL) { + err = -ENOMEM; + goto err_free_mem; + } + ts_dev->irq = irq; + INIT_WORK(&ts_dev->work, mxc_tsadcc_work); + mutex_init(&ts_dev->convert_mutex); + setup_timer(&ts_dev->timer, mxc_tsadcc_timer, (unsigned long)ts_dev); + init_waitqueue_head(&ts_dev->wq); + + platform_set_drvdata(pdev, ts_dev); + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&pdev->dev, "Failed to allocate input device\n"); + err = -ENOMEM; + goto err_free_mem; + } + + ts_dev->reg_base = ioremap(res->start, resource_size(res)); + if (!ts_dev->reg_base) { + dev_err(&pdev->dev, "Failed to map registers\n"); + err = -ENOMEM; + goto err_free_dev; + } + + err = request_irq(ts_dev->irq, mxc_tsadcc_interrupt, 0, + pdev->dev.driver->name, ts_dev); + if (err) { + dev_err(&pdev->dev, "Failed to install irq handler: %d\n", err); + goto err_unmap_regs; + } + + ts_dev->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(ts_dev->clk)) { + dev_err(&pdev->dev, "Failed to get ts_clk\n"); + err = PTR_ERR(ts_dev->clk); + goto err_free_irq; + } + + ts_dev->input = input_dev; + + snprintf(ts_dev->phys, sizeof(ts_dev->phys), + "%s/input0", dev_name(&pdev->dev)); + + input_dev->name = "mxc touch screen controller"; + input_dev->phys = ts_dev->phys; + input_dev->dev.parent = &pdev->dev; + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_dev->absbit[0] = BIT_MASK(ABS_X) | + BIT_MASK(ABS_Y) | + BIT_MASK(ABS_PRESSURE); + + input_set_abs_params(input_dev, ABS_X, 0, 0xFFF, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 0xFFF, 0, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xFFF, 0, 0); + + mxc_tsadcc_config(pdev); + + /* All went ok, so register to the input system */ + err = input_register_device(input_dev); + if (err) + goto err_fail; + + err = sysfs_create_group(&pdev->dev.kobj, &mxc_tsadcc_attr_group); + if (err) { + dev_warn(&pdev->dev, "Failed to create sysfs attributes: %d\n", + err); + } + ts_dev->attrs = !err; + + return 0; + +err_fail: + clk_disable(ts_dev->clk); + clk_put(ts_dev->clk); +err_free_irq: + free_irq(ts_dev->irq, ts_dev); +err_unmap_regs: + iounmap(ts_dev->reg_base); +err_free_dev: + input_free_device(ts_dev->input); +err_free_mem: + kfree(ts_dev->tsc_data); + kfree(ts_dev->adc_data); + kfree(ts_dev); +err_release_mem: + release_mem_region(res->start, resource_size(res)); + return err; +} + +static int __devexit mxc_tsadcc_remove(struct platform_device *pdev) +{ + struct mxc_tsadcc *ts_dev = dev_get_drvdata(&pdev->dev); + struct resource *res; + + if (ts_dev->attrs) { + DBG(0, "%s: Removing sysfs attributes\n", __FUNCTION__); + sysfs_remove_group(&pdev->dev.kobj, &mxc_tsadcc_attr_group); + } + del_timer_sync(&ts_dev->timer); + input_unregister_device(ts_dev->input); + + clk_disable(ts_dev->clk); + clk_put(ts_dev->clk); + + free_irq(ts_dev->irq, ts_dev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iounmap(ts_dev->reg_base); + release_mem_region(res->start, resource_size(res)); + + kfree(ts_dev->tsc_data); + kfree(ts_dev->adc_data); + kfree(ts_dev); + return 0; +} + +#ifdef CONFIG_PM +static int mxc_tsadcc_suspend(struct platform_device *pdev, pm_message_t msg) +{ + struct mxc_tsadcc *ts_dev = dev_get_drvdata(&pdev->dev); + + if (ts_dev->clk_enabled) { + tsc_clk_disable(ts_dev); + ts_dev->clk_enabled = 1; + } + return 0; +} + +static int mxc_tsadcc_resume(struct platform_device *pdev) +{ + struct mxc_tsadcc *ts_dev = dev_get_drvdata(&pdev->dev); + + if (ts_dev->clk_enabled) { + ts_dev->clk_enabled = 0; + tsc_clk_enable(ts_dev); + } + return 0; +} +#else +#define mxc_tsadcc_suspend NULL +#define mxc_tsadcc_resume NULL +#endif + +static struct platform_driver mxc_tsadcc_driver = { + .probe = mxc_tsadcc_probe, + .remove = __devexit_p(mxc_tsadcc_remove), + .suspend = mxc_tsadcc_suspend, + .resume = mxc_tsadcc_resume, + .driver = { + .name = "mxc-tsadcc", + }, +}; + +static int __init mxc_tsadcc_init(void) +{ + return platform_driver_register(&mxc_tsadcc_driver); +} + +static void __exit mxc_tsadcc_exit(void) +{ + platform_driver_unregister(&mxc_tsadcc_driver); +} + +module_init(mxc_tsadcc_init); +module_exit(mxc_tsadcc_exit); + + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("i.MX25 TouchScreen Driver"); +MODULE_AUTHOR("Lothar Wassmann "); + diff -purN linux-2.6.30-rc4-git/drivers/input/touchscreen/mxc_tsadcc.h linux-2.6.30-rc4-karo3/drivers/input/touchscreen/mxc_tsadcc.h --- linux-2.6.30-rc4-git/drivers/input/touchscreen/mxc_tsadcc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/drivers/input/touchscreen/mxc_tsadcc.h 2009-07-01 11:27:51.000000000 +0200 @@ -0,0 +1,243 @@ +/* + * Freescale i.MX25 Touch Screen Driver + * + * Copyright (c) 2009 Lothar Wassmann + * + * Based on code from Freescale BSP + * + * 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. + */ + +/* TSC General Config Register */ +#define TGCR 0x000 +#define TGCR_IPG_CLK_EN (1 << 0) +#define TGCR_TSC_RST (1 << 1) +#define TGCR_FUNC_RST (1 << 2) +#define TGCR_SLPC (1 << 4) +#define TGCR_STLC (1 << 5) +#define TGCR_HSYNC_EN (1 << 6) +#define TGCR_HSYNC_POL (1 << 7) +#define TGCR_POWERMODE_SHIFT 8 +#define TGCR_POWER_OFF (0x0 << TGCR_POWERMODE_SHIFT) +#define TGCR_POWER_SAVE (0x1 << TGCR_POWERMODE_SHIFT) +#define TGCR_POWER_ON (0x3 << TGCR_POWERMODE_SHIFT) +#define TGCR_POWER_MASK (0x3 << TGCR_POWERMODE_SHIFT) +#define TGCR_INTREFEN (1 << 10) +#define TGCR_ADCCLKCFG_SHIFT 16 +#define TGCR_ADCCLKCFG_MASK (0x1f << TGCR_ADCCLKCFG_SHIFT) +#define TGCR_PD_EN (1 << 23) +#define TGCR_PDB_EN (1 << 24) +#define TGCR_PDBTIME_SHIFT 25 +#define TGCR_PDBTIME128 (0x3f << TGCR_PDBTIME_SHIFT) +#define TGCR_PDBTIME_MASK (0x7f << TGCR_PDBTIME_SHIFT) + +/* TSC General Status Register */ +#define TGSR 0x004 +#define TGSR_TCQ_INT (1 << 0) +#define TGSR_GCQ_INT (1 << 1) +#define TGSR_SLP_INT (1 << 2) +#define TGSR_TCQ_DMA (1 << 16) +#define TGSR_GCQ_DMA (1 << 17) + +/* TSC IDLE Config Register */ +#define TICR 0x008 + +/* TouchScreen Convert Queue FIFO Register */ +#define TCQFIFO 0x400 +/* TouchScreen Convert Queue Control Register */ +#define TCQCR 0x404 +#define CQCR_QSM_SHIFT 0 +#define CQCR_QSM_STOP (0x0 << CQCR_QSM_SHIFT) +#define CQCR_QSM_PEN (0x1 << CQCR_QSM_SHIFT) +#define CQCR_QSM_FQS (0x2 << CQCR_QSM_SHIFT) +#define CQCR_QSM_FQS_PEN (0x3 << CQCR_QSM_SHIFT) +#define CQCR_QSM_MASK (0x3 << CQCR_QSM_SHIFT) +#define CQCR_FQS (1 << 2) +#define CQCR_RPT (1 << 3) +#define CQCR_LAST_ITEM_ID_SHIFT 4 +#define CQCR_LAST_ITEM_ID_MASK (0xf << CQCR_LAST_ITEM_ID_SHIFT) +#define CQCR_FIFOWATERMARK_SHIFT 8 +#define CQCR_FIFOWATERMARK_MASK (0xf << CQCR_FIFOWATERMARK_SHIFT) +#define CQCR_REPEATWAIT_SHIFT 12 +#define CQCR_REPEATWAIT_MASK (0xf << CQCR_REPEATWAIT_SHIFT) +#define CQCR_QRST (1 << 16) +#define CQCR_FRST (1 << 17) +#define CQCR_PD_MSK (1 << 18) +#define CQCR_PD_CFG (1 << 19) + +/* TouchScreen Convert Queue Status Register */ +#define TCQSR 0x408 +#define CQSR_PD (1 << 0) +#define CQSR_EOQ (1 << 1) +#define CQSR_FOR (1 << 4) +#define CQSR_FUR (1 << 5) +#define CQSR_FER (1 << 6) +#define CQSR_EMPT (1 << 13) +#define CQSR_FULL (1 << 14) +#define CQSR_FDRY (1 << 15) + +/* TouchScreen Convert Queue Mask Register */ +#define TCQMR 0x40c +#define CQMR_PD_IRQ_MSK (1 << 0) +#define CQMR_EOQ_IRQ_MSK (1 << 1) +#define CQMR_FOR_IRQ_MSK (1 << 4) +#define CQMR_FUR_IRQ_MSK (1 << 5) +#define CQMR_FER_IRQ_MSK (1 << 6) +#define CQMR_PD_DMA_MSK (1 << 16) +#define CQMR_EOQ_DMA_MSK (1 << 17) +#define CQMR_FOR_DMA_MSK (1 << 20) +#define CQMR_FUR_DMA_MSK (1 << 21) +#define CQMR_FER_DMA_MSK (1 << 22) +#define CQMR_FDRY_DMA_MSK (1 << 31) + +/* TouchScreen Convert Queue ITEM 7~0 */ +#define TCQ_ITEM_7_0 0x420 + +/* TouchScreen Convert Queue ITEM 15~8 */ +#define TCQ_ITEM_15_8 0x424 + +#define TCQ_ITEM_TCC0 0x0 +#define TCQ_ITEM_TCC1 0x1 +#define TCQ_ITEM_TCC2 0x2 +#define TCQ_ITEM_TCC3 0x3 +#define TCQ_ITEM_TCC4 0x4 +#define TCQ_ITEM_TCC5 0x5 +#define TCQ_ITEM_TCC6 0x6 +#define TCQ_ITEM_TCC7 0x7 +#define TCQ_ITEM_GCC7 0x8 +#define TCQ_ITEM_GCC6 0x9 +#define TCQ_ITEM_GCC5 0xa +#define TCQ_ITEM_GCC4 0xb +#define TCQ_ITEM_GCC3 0xc +#define TCQ_ITEM_GCC2 0xd +#define TCQ_ITEM_GCC1 0xe +#define TCQ_ITEM_GCC0 0xf + +/* TouchScreen Convert Config 0-7 */ +#define TCC0 0x440 +#define TCC1 0x444 +#define TCC2 0x448 +#define TCC3 0x44c +#define TCC4 0x450 +#define TCC5 0x454 +#define TCC6 0x458 +#define TCC7 0x45c +#define CC_PEN_IACK (1 << 1) +#define CC_SEL_REFN_SHIFT 2 +#define CC_SEL_REFN_YNLR (0x1 << CC_SEL_REFN_SHIFT) +#define CC_SEL_REFN_AGND (0x2 << CC_SEL_REFN_SHIFT) +#define CC_SEL_REFN_MASK (0x3 << CC_SEL_REFN_SHIFT) +#define CC_SELIN_SHIFT 4 +#define CC_SELIN_XPUL (0x0 << CC_SELIN_SHIFT) +#define CC_SELIN_YPLL (0x1 << CC_SELIN_SHIFT) +#define CC_SELIN_XNUR (0x2 << CC_SELIN_SHIFT) +#define CC_SELIN_YNLR (0x3 << CC_SELIN_SHIFT) +#define CC_SELIN_WIPER (0x4 << CC_SELIN_SHIFT) +#define CC_SELIN_INAUX0 (0x5 << CC_SELIN_SHIFT) +#define CC_SELIN_INAUX1 (0x6 << CC_SELIN_SHIFT) +#define CC_SELIN_INAUX2 (0x7 << CC_SELIN_SHIFT) +#define CC_SELIN_MASK (0x7 << CC_SELIN_SHIFT) +#define CC_SELREFP_SHIFT 7 +#define CC_SELREFP_YPLL (0x0 << CC_SELREFP_SHIFT) +#define CC_SELREFP_XPUL (0x1 << CC_SELREFP_SHIFT) +#define CC_SELREFP_EXT (0x2 << CC_SELREFP_SHIFT) +#define CC_SELREFP_INT (0x3 << CC_SELREFP_SHIFT) +#define CC_SELREFP_MASK (0x3 << CC_SELREFP_SHIFT) +#define CC_XPULSW (1 << 9) +#define CC_XNURSW_SHIFT 10 +#define CC_XNURSW_HIGH (0x0 << CC_XNURSW_SHIFT) +#define CC_XNURSW_OFF (0x1 << CC_XNURSW_SHIFT) +#define CC_XNURSW_LOW (0x3 << CC_XNURSW_SHIFT) +#define CC_XNURSW_MASK (0x3 << CC_XNURSW_SHIFT) +#define CC_YPLLSW_SHIFT 12 +#define CC_YPLLSW_HIGH (0x0 << CC_YPLLSW_SHIFT) +#define CC_YPLLSW_OFF (0x1 << CC_YPLLSW_SHIFT) +#define CC_YPLLSW_LOW (0x3 << CC_YPLLSW_SHIFT) +#define CC_YPLLSW_MASK (0x3 << CC_YPLLSW_SHIFT) +#define CC_YNLRSW (1 << 14) +#define CC_WIPERSW (1 << 15) +#define CC_NOS_SHIFT 16 +#define CC_NOS_MASK (0xf << CC_NOS_SHIFT) +#define CC_IGS (1 << 20) +#define CC_SETTLING_TIME_SHIFT 24 +#define CC_SETTLING_TIME_MASK (0xff << CC_SETTLING_TIME_SHIFT) + +#define TSC_4WIRE_PRECHARGE 0x158c +#define TSC_4WIRE_TOUCH_DETECT 0x578e + +#define TSC_4WIRE_X_MEASURE 0x1c90 +#define TSC_4WIRE_Y_MEASURE 0x4604 +#define TSC_4WIRE_XP_MEASURE 0x0f8c +#define TSC_4WIRE_YN_MEASURE 0x0fbc + +#define TSC_GENERAL_ADC_GCC0 0x17dc +#define TSC_GENERAL_ADC_GCC1 0x17ec +#define TSC_GENERAL_ADC_GCC2 0x17fc + +/* GeneralADC Convert Queue FIFO Register */ +#define GCQFIFO 0x800 +#define GCQFIFO_ADCOUT_SHIFT 4 +#define GCQFIFO_ADCOUT_MASK (0xfff << GCQFIFO_ADCOUT_SHIFT) + +/* GeneralADC Convert Queue Control Register */ +#define GCQCR 0x804 + +/* GeneralADC Convert Queue Status Register */ +#define GCQSR 0x808 + +/* GeneralADC Convert Queue Mask Register */ +#define GCQMR 0x80c + +/* GeneralADC Convert Queue ITEM 7~0 */ +#define GCQ_ITEM_7_0 0x820 + +/* GeneralADC Convert Queue ITEM 15~8 */ +#define GCQ_ITEM_15_8 0x824 + +#define CQ_ITEM7_SHIFT 28 +#define CQ_ITEM6_SHIFT 24 +#define CQ_ITEM5_SHIFT 20 +#define CQ_ITEM4_SHIFT 16 +#define CQ_ITEM3_SHIFT 12 +#define CQ_ITEM2_SHIFT 8 +#define CQ_ITEM1_SHIFT 4 +#define CQ_ITEM0_SHIFT 0 + +#define CQ_ITEM8_SHIFT 28 +#define CQ_ITEM9_SHIFT 24 +#define CQ_ITEM10_SHIFT 20 +#define CQ_ITEM11_SHIFT 16 +#define CQ_ITEM12_SHIFT 12 +#define CQ_ITEM13_SHIFT 8 +#define CQ_ITEM14_SHIFT 4 +#define CQ_ITEM15_SHIFT 0 + +#define GCQ_ITEM_GCC0 0x0 +#define GCQ_ITEM_GCC1 0x1 +#define GCQ_ITEM_GCC2 0x2 +#define GCQ_ITEM_GCC3 0x3 + +/* GeneralADC Convert Config 0-7 */ +#define GCC0 0x840 +#define GCC1 0x844 +#define GCC2 0x848 +#define GCC3 0x84c +#define GCC4 0x850 +#define GCC5 0x854 +#define GCC6 0x858 +#define GCC7 0x85c + +/* TSC Test Register R/W */ +#define TTR 0xc00 +/* TSC Monitor Register 1, 2 */ +#define MNT1 0xc04 +#define MNT2 0xc04 + +#define DETECT_ITEM_ID_1 1 +#define DETECT_ITEM_ID_2 5 +#define TS_X_ITEM_ID 2 +#define TS_Y_ITEM_ID 3 +#define TSI_DATA 1 +#define FQS_DATA 0 diff -purN linux-2.6.30-rc4-git/drivers/leds/leds-gpio.c linux-2.6.30-rc4-karo3/drivers/leds/leds-gpio.c --- linux-2.6.30-rc4-git/drivers/leds/leds-gpio.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/drivers/leds/leds-gpio.c 2009-06-02 18:36:36.000000000 +0200 @@ -82,7 +82,7 @@ static int __devinit create_gpio_led(con if (!gpio_is_valid(template->gpio)) { printk(KERN_INFO "Skipping unavilable LED gpio %d (%s)\n", template->gpio, template->name); - return 0; + return -EINVAL; } ret = gpio_request(template->gpio, template->name); diff -purN linux-2.6.30-rc4-git/drivers/mtd/nand/Kconfig linux-2.6.30-rc4-karo3/drivers/mtd/nand/Kconfig --- linux-2.6.30-rc4-git/drivers/mtd/nand/Kconfig 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/drivers/mtd/nand/Kconfig 2009-06-02 18:42:05.000000000 +0200 @@ -420,6 +420,27 @@ config MTD_NAND_MXC This enables the driver for the NAND flash controller on the MXC processors. +config MTD_NAND_MXC_FLASH_BBT + bool "Support a flash based bad block table" + depends on MTD_NAND_MXC + +config ARCH_MXC_HAS_NFC_V1 + bool + +config ARCH_MXC_HAS_NFC_V1_1 + select ARCH_MXC_HAS_NFC_V1 + bool + +config ARCH_MXC_HAS_NFC_V2 + bool + +config ARCH_MXC_HAS_NFC_V2_1 + bool + select ARCH_MXC_HAS_NFC_V2 + +config ARCH_MXC_HAS_NFC_V3 + bool + config MTD_NAND_SH_FLCTL tristate "Support for NAND on Renesas SuperH FLCTL" depends on MTD_NAND && SUPERH && CPU_SUBTYPE_SH7723 diff -purN linux-2.6.30-rc4-git/drivers/mtd/nand/mxc_nand.c linux-2.6.30-rc4-karo3/drivers/mtd/nand/mxc_nand.c --- linux-2.6.30-rc4-git/drivers/mtd/nand/mxc_nand.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/drivers/mtd/nand/mxc_nand.c 2009-07-14 14:10:27.000000000 +0200 @@ -32,25 +32,58 @@ #include #include +#include #include +#ifdef CONFIG_MTD_DEBUG +static int debug; +module_param(debug, int, S_IRUGO | S_IWUSR); + +#define dbg_lvl(n) ((n) < debug) +#define DBG(lvl, fmt...) do { if (dbg_lvl(lvl)) printk(KERN_DEBUG fmt); } while (0) +#undef DEBUG +#define DEBUG(l, fmt...) DBG(l, fmt) +#else +static int debug; +module_param(debug, int, 0); + +#define dbg_lvl(n) 0 +#define DBG(lvl, fmt...) do { } while (0) +#endif + + #define DRIVER_NAME "mxc_nand" /* Addresses for NFC registers */ -#define NFC_BUF_SIZE 0xE00 -#define NFC_BUF_ADDR 0xE04 -#define NFC_FLASH_ADDR 0xE06 -#define NFC_FLASH_CMD 0xE08 -#define NFC_CONFIG 0xE0A -#define NFC_ECC_STATUS_RESULT 0xE0C -#define NFC_RSLTMAIN_AREA 0xE0E -#define NFC_RSLTSPARE_AREA 0xE10 -#define NFC_WRPROT 0xE12 -#define NFC_UNLOCKSTART_BLKADDR 0xE14 -#define NFC_UNLOCKEND_BLKADDR 0xE16 -#define NFC_NF_WRPRST 0xE18 -#define NFC_CONFIG1 0xE1A -#define NFC_CONFIG2 0xE1C +#define NFC_BUF_SIZE 0x000 +#define NFC_BUF_ADDR 0x004 +#define NFC_FLASH_ADDR 0x006 +#define NFC_FLASH_CMD 0x008 +#define NFC_CONFIG 0x00A +#define NFC_ECC_STATUS_RESULT 0x00C +#define NFC_WRPROT 0x012 +#ifndef CONFIG_ARCH_MXC_HAS_NFC_V1_1 +#define NFC_RSLTMAIN_AREA 0x00E +#define NFC_RSLTSPARE_AREA 0x010 +#define NFC_UNLOCKSTART_BLKADDR 0x014 +#define NFC_UNLOCKEND_BLKADDR 0x016 +#else +#define NFC_ECC_STATUS_RESULT2 0x00E +#define NFC_SPAS 0x010 +#endif +#define NFC_NF_WRPRST 0x018 +#define NFC_CONFIG1 0x01A +#define NFC_CONFIG2 0x01C +#ifdef CONFIG_ARCH_MXC_HAS_NFC_V1_1 +#define NFC_UNLOCKSTART_BLKADDR 0x020 +#define NFC_UNLOCKEND_BLKADDR 0x022 +#define NFC_UNLOCKSTART_BLKADDR1 0x024 +#define NFC_UNLOCKEND_BLKADDR1 0x026 +#define NFC_UNLOCKSTART_BLKADDR2 0x028 +#define NFC_UNLOCKEND_BLKADDR2 0x02a +#define NFC_UNLOCKSTART_BLKADDR3 0x02c +#define NFC_UNLOCKEND_BLKADDR3 0x02e +#endif /* Addresses for NFC RAM BUFFER Main area 0 */ #define MAIN_AREA0 0x000 @@ -59,10 +92,27 @@ #define MAIN_AREA3 0x600 /* Addresses for NFC SPARE BUFFER Spare area 0 */ +#ifndef CONFIG_ARCH_MXC_HAS_NFC_V1_1 +#define SPARE_AREA_SIZE 16 #define SPARE_AREA0 0x800 #define SPARE_AREA1 0x810 #define SPARE_AREA2 0x820 #define SPARE_AREA3 0x830 +#else +#define SPARE_AREA_SIZE 64 +#define MAIN_AREA4 0x800 +#define MAIN_AREA5 0xa00 +#define MAIN_AREA6 0xc00 +#define MAIN_AREA7 0xe00 +#define SPARE_AREA0 0x1000 +#define SPARE_AREA1 0x1040 +#define SPARE_AREA2 0x1080 +#define SPARE_AREA3 0x10c0 +#define SPARE_AREA4 0x1100 +#define SPARE_AREA5 0x1140 +#define SPARE_AREA6 0x1180 +#define SPARE_AREA7 0x11c0 +#endif /* Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register * for Command operation */ @@ -107,10 +157,12 @@ struct mxc_nand_host { struct device *dev; void __iomem *regs; + void __iomem *nfc_buf; int spare_only; int status_request; int pagesize_2k; uint16_t col_addr; + unsigned int page_addr; struct clk *clk; int clk_act; int irq; @@ -120,40 +172,134 @@ struct mxc_nand_host { /* Define delays in microsec for NAND device operations */ #define TROP_US_DELAY 2000 -/* Macros to get byte and bit positions of ECC */ -#define COLPOS(x) ((x) >> 3) -#define BITPOS(x) ((x) & 0xf) - -/* Define single bit Error positions in Main & Spare area */ -#define MAIN_SINGLEBIT_ERROR 0x4 -#define SPARE_SINGLEBIT_ERROR 0x1 +#ifndef CONFIG_ARCH_MXC_HAS_NFC_V1_1 /* OOB placement block for use with hardware ecc generation */ +static struct nand_ecclayout nand_hw_eccoob2k_8 = { + .eccbytes = 20, + .eccpos = { + 6, 7, 8, 9, 10, + 22, 23, 24, 25, 26, + 38, 39, 40, 41, 42, + 54, 55, 56, 57, 58, + }, + .oobfree = {{2, 4}, {11, 11}, {27, 11}, {43, 11}, {59, 5}}, +}; + static struct nand_ecclayout nand_hw_eccoob_8 = { .eccbytes = 5, - .eccpos = {6, 7, 8, 9, 10}, - .oobfree = {{0, 5}, {11, 5}, } + .eccpos = { 6, 7, 8, 9, 10 }, + .oobfree = {{0, 6}, {11, 5}} +}; +#ifdef CONFIG_MTD_NAND_MXC_FLASH_BBT +static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = (NAND_BBT_LASTBLOCK | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP), + .offs = 12, + .len = 4, + .veroffs = 11, + .maxblocks = 4, + .pattern = bbt_pattern, }; -static struct nand_ecclayout nand_hw_eccoob_16 = { - .eccbytes = 5, - .eccpos = {6, 7, 8, 9, 10}, - .oobfree = {{0, 6}, {12, 4}, } +static struct nand_bbt_descr bbt_mirror_descr = { + .options = (NAND_BBT_LASTBLOCK | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP), + .offs = 12, + .len = 4, + .veroffs = 11, + .maxblocks = 4, + .pattern = mirror_pattern, +}; +#endif +#else +/* + * OOB placement block for use with hardware ecc generation + */ +static struct nand_ecclayout nand_hw_eccoob2k_8 = { + .eccbytes = 36, + .eccpos = { + 7, 8, 9, 10, 11, 12, 13, 14, 15, + 23, 24, 25, 26, 27, 28, 29, 30, 31, + 39, 40, 41, 42, 43, 44, 45, 46, 47, + 55, 56, 57, 58, 59, 60, 61, 62, 63, + }, + .oobfree = {{2, 5}, {16, 7}, {32, 7}, {48, 7}}, +}; + +static struct nand_ecclayout nand_hw_eccoob_8 = { + .eccbytes = 9, + .eccpos = { 7, 8, 9, 10, 11, 12, 13, 14, 15, }, + .oobfree = {{0, 4}}, +}; + +#ifdef CONFIG_MTD_NAND_MXC_FLASH_BBT +/* Generic flash bbt decriptors +*/ +static u8 bbt_pattern[] = { 'B', 'b', 't', '0' }; +static u8 mirror_pattern[] = { '1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 0, + .len = 4, + .veroffs = 4, + .maxblocks = 4, + .pattern = bbt_pattern }; +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | + NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 0, + .len = 4, + .veroffs = 4, + .maxblocks = 4, + .pattern = mirror_pattern +}; +#endif +#endif + #ifdef CONFIG_MTD_PARTITIONS static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; #endif +#ifdef CONFIG_MTD_DEBUG +#define nfc_read_reg(b, r) __nfc_read_reg(b, r, #r, __FUNCTION__) +static inline u16 __nfc_read_reg(void __iomem *base, unsigned int reg, + const char *name, const char *fn) +{ + u16 val = readw(base + reg); + DBG(3, "%s: Read %04x from %s[%02x]\n", fn, val, name, reg); + return val; +} + +#define nfc_write_reg(v, b, r) __nfc_write_reg(v, b, r, #r, __FUNCTION__) +static inline void __nfc_write_reg(u16 val, void __iomem *base, unsigned int reg, + const char *name, const char *fn) +{ + DBG(3, "%s: Writing %04x to %s[%02x]\n", fn, val, name, reg); + writew(val, base + reg); +} +#else +#define nfc_read_reg(b, r) readw(b + r) +#define nfc_write_reg(v, b, r) writew(v, b + r) +#endif + static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) { struct mxc_nand_host *host = dev_id; - uint16_t tmp; - tmp = readw(host->regs + NFC_CONFIG1); + DEBUG(MTD_DEBUG_LEVEL3, "%s(%d)\n", __FUNCTION__, irq); + + tmp = nfc_read_reg(host->regs, NFC_CONFIG1); tmp |= NFC_INT_MSK; /* Disable interrupt */ - writew(tmp, host->regs + NFC_CONFIG1); + nfc_write_reg(tmp, host->regs, NFC_CONFIG1); wake_up(&host->irq_waitq); @@ -166,35 +312,29 @@ static irqreturn_t mxc_nfc_irq(int irq, static void wait_op_done(struct mxc_nand_host *host, int max_retries, uint16_t param, int useirq) { - uint32_t tmp; - if (useirq) { - if ((readw(host->regs + NFC_CONFIG2) & NFC_INT) == 0) { - - tmp = readw(host->regs + NFC_CONFIG1); - tmp &= ~NFC_INT_MSK; /* Enable interrupt */ - writew(tmp, host->regs + NFC_CONFIG1); - - wait_event(host->irq_waitq, - readw(host->regs + NFC_CONFIG2) & NFC_INT); - - tmp = readw(host->regs + NFC_CONFIG2); - tmp &= ~NFC_INT; - writew(tmp, host->regs + NFC_CONFIG2); + if (!(nfc_read_reg(host->regs, NFC_CONFIG2) & NFC_INT)) { + uint32_t cfg1; + const unsigned long timeout = max_retries; + + cfg1 = nfc_read_reg(host->regs, NFC_CONFIG1); + cfg1 &= ~NFC_INT_MSK; /* Enable interrupt */ + nfc_write_reg(cfg1, host->regs, NFC_CONFIG1); + + max_retries = wait_event_timeout(host->irq_waitq, + nfc_read_reg(host->regs, NFC_CONFIG2) & + NFC_INT, timeout); } } else { - while (max_retries-- > 0) { - if (readw(host->regs + NFC_CONFIG2) & NFC_INT) { - tmp = readw(host->regs + NFC_CONFIG2); - tmp &= ~NFC_INT; - writew(tmp, host->regs + NFC_CONFIG2); - break; - } + while (!(nfc_read_reg(host->regs, NFC_CONFIG2) & NFC_INT) && + max_retries-- > 0) { udelay(1); } - if (max_retries <= 0) - DEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n", - __func__, param); + } + WARN_ON(nfc_read_reg(host->regs, NFC_CONFIG2) & ~NFC_INT); + nfc_write_reg(0, host->regs, NFC_CONFIG2); + if (WARN_ON(max_retries <= 0)) { + printk(KERN_ERR "%s(%d): INT not set\n", __func__, param); } } @@ -204,8 +344,9 @@ static void send_cmd(struct mxc_nand_hos { DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq); - writew(cmd, host->regs + NFC_FLASH_CMD); - writew(NFC_CMD, host->regs + NFC_CONFIG2); + nfc_write_reg(cmd, host->regs, NFC_FLASH_CMD); + WARN_ON(nfc_read_reg(host->regs, NFC_CONFIG2)); + nfc_write_reg(NFC_CMD, host->regs, NFC_CONFIG2); /* Wait for operation to complete */ wait_op_done(host, TROP_US_DELAY, cmd, useirq); @@ -218,34 +359,72 @@ static void send_addr(struct mxc_nand_ho { DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast); - writew(addr, host->regs + NFC_FLASH_ADDR); - writew(NFC_ADDR, host->regs + NFC_CONFIG2); + nfc_write_reg(addr, host->regs, NFC_FLASH_ADDR); + WARN_ON(nfc_read_reg(host->regs, NFC_CONFIG2)); + nfc_write_reg(NFC_ADDR, host->regs, NFC_CONFIG2); /* Wait for operation to complete */ wait_op_done(host, TROP_US_DELAY, addr, islast); } +static inline void nfc_buf_read(const void __iomem *nfc, void *buf, int len) +{ + u32 *wp = buf; + int i; + + BUG_ON((unsigned long)nfc & 3); + BUG_ON((unsigned long)buf & 3); + + for (i = 0; i < len; i += sizeof(long)) { + wp[i >> 2] = readl(nfc + i); + } +} + +static inline void nfc_buf_write(void __iomem *nfc, const void *buf, int len) +{ + const u32 *rp = buf; + int i; + + BUG_ON((unsigned long)nfc & 3); + BUG_ON((unsigned long)buf & 3); + + for (i = 0; i < len; i += sizeof(long)) { + writel(rp[i >> 2], nfc + i); + } +} + /* This function requests the NANDFC to initate the transfer * of data currently in the NANDFC RAM buffer to the NAND device. */ static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id, int spare_only) { - DEBUG(MTD_DEBUG_LEVEL3, "send_prog_page (%d)\n", spare_only); + int i; + + if (spare_only) + DEBUG(MTD_DEBUG_LEVEL1, "send_prog_page (%d)\n", spare_only); + if (cpu_is_mx25()) { + for (i = 0; i < 4; i++) { + void __iomem *src = host->nfc_buf + SPARE_AREA0 + i * 16; + void __iomem *dst = host->nfc_buf + SPARE_AREA0 + i * 64; + + memcpy(dst, src, 16); + } + } /* NANDFC buffer 0 is used for page read/write */ - writew(buf_id, host->regs + NFC_BUF_ADDR); + nfc_write_reg(buf_id, host->regs, NFC_BUF_ADDR); /* Configure spare or page+spare access */ if (!host->pagesize_2k) { - uint16_t config1 = readw(host->regs + NFC_CONFIG1); + uint16_t config1 = nfc_read_reg(host->regs, NFC_CONFIG1); if (spare_only) config1 |= NFC_SP_EN; else - config1 &= ~(NFC_SP_EN); - writew(config1, host->regs + NFC_CONFIG1); + config1 &= ~NFC_SP_EN; + nfc_write_reg(config1, host->regs, NFC_CONFIG1); } - - writew(NFC_INPUT, host->regs + NFC_CONFIG2); + WARN_ON(nfc_read_reg(host->regs, NFC_CONFIG2)); + nfc_write_reg(NFC_INPUT, host->regs, NFC_CONFIG2); /* Wait for operation to complete */ wait_op_done(host, TROP_US_DELAY, spare_only, true); @@ -256,25 +435,37 @@ static void send_prog_page(struct mxc_na static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id, int spare_only) { + int i; + DEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only); /* NANDFC buffer 0 is used for page read/write */ - writew(buf_id, host->regs + NFC_BUF_ADDR); + nfc_write_reg(buf_id, host->regs, NFC_BUF_ADDR); /* Configure spare or page+spare access */ if (!host->pagesize_2k) { - uint32_t config1 = readw(host->regs + NFC_CONFIG1); + uint32_t config1 = nfc_read_reg(host->regs, NFC_CONFIG1); if (spare_only) config1 |= NFC_SP_EN; else config1 &= ~NFC_SP_EN; - writew(config1, host->regs + NFC_CONFIG1); + nfc_write_reg(config1, host->regs, NFC_CONFIG1); } - writew(NFC_OUTPUT, host->regs + NFC_CONFIG2); + WARN_ON(nfc_read_reg(host->regs, NFC_CONFIG2)); + nfc_write_reg(NFC_OUTPUT, host->regs, NFC_CONFIG2); /* Wait for operation to complete */ wait_op_done(host, TROP_US_DELAY, spare_only, true); + if (!cpu_is_mx25()) + return; + + for (i = 0; i < 4; i++) { + void __iomem *src = host->nfc_buf + SPARE_AREA0 + i * 64; + void __iomem *dst = host->nfc_buf + SPARE_AREA0 + i * 16; + + memcpy(dst, src, 16); + } } /* Request the NANDFC to perform a read of the NAND device ID. */ @@ -284,20 +475,23 @@ static void send_read_id(struct mxc_nand uint16_t tmp; /* NANDFC buffer 0 is used for device ID output */ - writew(0x0, host->regs + NFC_BUF_ADDR); + nfc_write_reg(0x0, host->regs, NFC_BUF_ADDR); - /* Read ID into main buffer */ - tmp = readw(host->regs + NFC_CONFIG1); + tmp = nfc_read_reg(host->regs, NFC_CONFIG1); tmp &= ~NFC_SP_EN; - writew(tmp, host->regs + NFC_CONFIG1); + nfc_write_reg(tmp, host->regs, NFC_CONFIG1); - writew(NFC_ID, host->regs + NFC_CONFIG2); + WARN_ON(nfc_read_reg(host->regs, NFC_CONFIG2)); + /* Read ID into main buffer */ + nfc_write_reg(NFC_ID, host->regs, NFC_CONFIG2); /* Wait for operation to complete */ wait_op_done(host, TROP_US_DELAY, 0, true); if (this->options & NAND_BUSWIDTH_16) { - void __iomem *main_buf = host->regs + MAIN_AREA0; + /* FIXME: This cannot work, because the NFC buffer + * cannot be accessed with byte accesses! */ + void __iomem *main_buf = host->nfc_buf + MAIN_AREA0; /* compress the ID info */ writeb(readb(main_buf + 2), main_buf + 1); writeb(readb(main_buf + 4), main_buf + 2); @@ -311,32 +505,35 @@ static void send_read_id(struct mxc_nand * NAND device status and returns the current status. */ static uint16_t get_dev_status(struct mxc_nand_host *host) { - void __iomem *main_buf = host->regs + MAIN_AREA1; + void __iomem *main_buf = host->nfc_buf + MAIN_AREA1; uint32_t store; uint16_t ret, tmp; - /* Issue status request to NAND device */ - /* store the main area1 first word, later do recovery */ + /* store the main area first word, later do recovery */ store = readl(main_buf); /* NANDFC buffer 1 is used for device status to prevent * corruption of read/write buffer on status requests. */ - writew(1, host->regs + NFC_BUF_ADDR); + nfc_write_reg(1, host->regs, NFC_BUF_ADDR); /* Read status into main buffer */ - tmp = readw(host->regs + NFC_CONFIG1); + tmp = nfc_read_reg(host->regs, NFC_CONFIG1); tmp &= ~NFC_SP_EN; - writew(tmp, host->regs + NFC_CONFIG1); + nfc_write_reg(tmp, host->regs, NFC_CONFIG1); - writew(NFC_STATUS, host->regs + NFC_CONFIG2); + /* Issue status request to NAND device */ + WARN_ON(nfc_read_reg(host->regs, NFC_CONFIG2)); + nfc_write_reg(NFC_STATUS, host->regs, NFC_CONFIG2); /* Wait for operation to complete */ wait_op_done(host, TROP_US_DELAY, 0, true); /* Status is placed in first word of main buffer */ - /* get status, then recovery area 1 data */ + /* get status, then recover area 1 data */ ret = readw(main_buf); writel(store, main_buf); + DEBUG(MTD_DEBUG_LEVEL2, "%s: status=%02x\n", __FUNCTION__, ret); + return ret; } @@ -352,10 +549,290 @@ static int mxc_nand_dev_ready(struct mtd static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) { - /* - * If HW ECC is enabled, we turn it on during init. There is - * no need to enable again here. - */ + switch (mode) { + case NAND_ECC_WRITE: + DBG(0, "ECC_MODE=NAND_ECC_WRITE\n"); + break; + case NAND_ECC_READSYN: + DBG(0, "ECC_MODE=NAND_ECC_READSYN\n"); + break; + case NAND_ECC_READ: + DBG(0, "ECC_MODE=NAND_ECC_READ\n"); + break; + default: + DBG(-1, "%s: Unknown ECC_MODE: %d\n", __FUNCTION__, mode); + } +} + +static void _mxc_nand_enable_hwecc(struct mtd_info *mtd, int on) +{ + struct nand_chip *nand_chip = mtd->priv; + struct mxc_nand_host *host = nand_chip->priv; + uint16_t ecc = nfc_read_reg(host->regs, NFC_CONFIG1); + + if (on) { + ecc |= NFC_ECC_EN; + } else { + ecc &= ~NFC_ECC_EN; + } + nfc_write_reg(ecc, host->regs, NFC_CONFIG1); +} + +static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, + int page, int sndcmd) +{ + struct mxc_nand_host *host = chip->priv; + uint8_t *buf = chip->oob_poi; + int length = mtd->oobsize; + int eccpitch = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; + uint8_t *bufpoi = buf; + int i, toread; + + DEBUG(MTD_DEBUG_LEVEL0, "%s: Reading OOB area of page %u to oob %p\n", + __FUNCTION__, host->page_addr, buf); + + chip->cmdfunc(mtd, NAND_CMD_READOOB, mtd->writesize, page); + for (i = 0; i < chip->ecc.steps; i++) { + toread = min_t(int, length, chip->ecc.prepad); + if (toread) { + chip->read_buf(mtd, bufpoi, toread); + bufpoi += toread; + length -= toread; + } + bufpoi += chip->ecc.bytes; + host->col_addr += chip->ecc.bytes; + length -= chip->ecc.bytes; + + toread = min_t(int, length, chip->ecc.postpad); + if (toread) { + chip->read_buf(mtd, bufpoi, toread); + bufpoi += toread; + length -= toread; + } + } + if (length > 0) + chip->read_buf(mtd, bufpoi, length); + + _mxc_nand_enable_hwecc(mtd, 0); + chip->cmdfunc(mtd, NAND_CMD_READOOB, mtd->writesize + chip->ecc.prepad, page); + bufpoi = buf + chip->ecc.prepad; + length = mtd->oobsize - chip->ecc.prepad; + for (i = 0; i < chip->ecc.steps; i++) { + toread = min_t(int, length, chip->ecc.bytes); + chip->read_buf(mtd, bufpoi, toread); + bufpoi += eccpitch; + length -= eccpitch; + host->col_addr += chip->ecc.postpad + chip->ecc.prepad; + } + _mxc_nand_enable_hwecc(mtd, 1); + return 1; +} + +static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf) +{ + struct mxc_nand_host *host = chip->priv; + int eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; + uint8_t *oob = chip->oob_poi; + int steps, size; + int n; + + _mxc_nand_enable_hwecc(mtd, 0); + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, host->page_addr); + + for (n = 0, steps = chip->ecc.steps; steps > 0; n++, steps--) { + host->col_addr = n * eccsize; + chip->read_buf(mtd, buf, eccsize); + buf += eccsize; + + host->col_addr = mtd->writesize + n * eccpitch; + if (chip->ecc.prepad) { + chip->read_buf(mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + chip->read_buf(mtd, oob, eccbytes); + oob += eccbytes; + + if (chip->ecc.postpad) { + chip->read_buf(mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + + size = mtd->oobsize - (oob - chip->oob_poi); + if (size) + chip->read_buf(mtd, oob, size); + _mxc_nand_enable_hwecc(mtd, 0); + + return 0; +} + +static int mxc_nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf) +{ + struct mxc_nand_host *host = chip->priv; + int n, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *oob = chip->oob_poi; + + DEBUG(MTD_DEBUG_LEVEL1, "%s: Reading page %u to buf %p oob %p\n", __FUNCTION__, + host->page_addr, buf, oob); + + /* first read out the data area and the available portion of OOB */ + for (n = 0; eccsteps; n++, eccsteps--, p += eccsize) { + int stat; + + host->col_addr = n * eccsize; + + chip->read_buf(mtd, p, eccsize); + + host->col_addr = mtd->writesize + n * eccpitch; + + if (chip->ecc.prepad) { + chip->read_buf(mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + stat = chip->ecc.correct(mtd, p, oob, NULL); + + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + oob += eccbytes; + + if (chip->ecc.postpad) { + chip->read_buf(mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + + /* Calculate remaining oob bytes */ + n = mtd->oobsize - (oob - chip->oob_poi); + if (n) + chip->read_buf(mtd, oob, n); + + /* Then switch ECC off and read the OOB area to get the ECC code */ + _mxc_nand_enable_hwecc(mtd, 0); + chip->cmdfunc(mtd, NAND_CMD_READOOB, mtd->writesize, host->page_addr); + eccsteps = chip->ecc.steps; + oob = chip->oob_poi + chip->ecc.prepad; + for (n = 0; eccsteps; n++, eccsteps--, p += eccsize) { + host->col_addr = mtd->writesize + n * eccpitch + chip->ecc.prepad; + chip->read_buf(mtd, oob, eccbytes); + oob += eccbytes + chip->ecc.postpad; + } + _mxc_nand_enable_hwecc(mtd, 1); + return 0; +} + +static int mxc_nand_write_oob_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, int page) +{ + struct mxc_nand_host *host = chip->priv; + int eccpitch = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; + int length = mtd->oobsize; + int i, len, status, steps = chip->ecc.steps; + const uint8_t *bufpoi = chip->oob_poi; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + for (i = 0; i < steps; i++) { + len = min_t(int, length, eccpitch); + + chip->write_buf(mtd, bufpoi, len); + bufpoi += len; + length -= len; + host->col_addr += chip->ecc.prepad + chip->ecc.postpad; + } + if (length > 0) + chip->write_buf(mtd, bufpoi, length); + + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); + return status & NAND_STATUS_FAIL ? -EIO : 0; +} + +static void mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf) +{ + struct mxc_nand_host *host = chip->priv; + int eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; + uint8_t *oob = chip->oob_poi; + int steps, size; + int n; + + for (n = 0, steps = chip->ecc.steps; steps > 0; n++, steps--) { + host->col_addr = n * eccsize; + chip->write_buf(mtd, buf, eccsize); + buf += eccsize; + + host->col_addr = mtd->writesize + n * eccpitch; + + if (chip->ecc.prepad) { + chip->write_buf(mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + host->col_addr += eccbytes; + oob += eccbytes; + + if (chip->ecc.postpad) { + chip->write_buf(mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + + size = mtd->oobsize - (oob - chip->oob_poi); + if (size) + chip->write_buf(mtd, oob, size); +} + +static void mxc_nand_write_page_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf) +{ + struct mxc_nand_host *host = chip->priv; + int i, n, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; + int eccsteps = chip->ecc.steps; + const uint8_t *p = buf; + uint8_t *oob = chip->oob_poi; + + chip->ecc.hwctl(mtd, NAND_ECC_WRITE); + + for (i = n = 0; eccsteps; n++, eccsteps--, i += eccbytes, p += eccsize) { + host->col_addr = n * eccsize; + + chip->write_buf(mtd, p, eccsize); + + host->col_addr = mtd->writesize + n * eccpitch; + + if (chip->ecc.prepad) { + chip->write_buf(mtd, oob, chip->ecc.prepad); + oob += chip->ecc.prepad; + } + + chip->write_buf(mtd, oob, eccbytes); + oob += eccbytes; + + if (chip->ecc.postpad) { + chip->write_buf(mtd, oob, chip->ecc.postpad); + oob += chip->ecc.postpad; + } + } + + /* Calculate remaining oob bytes */ + i = mtd->oobsize - (oob - chip->oob_poi); + if (i) + chip->write_buf(mtd, oob, i); } static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, @@ -363,18 +840,41 @@ static int mxc_nand_correct_data(struct { struct nand_chip *nand_chip = mtd->priv; struct mxc_nand_host *host = nand_chip->priv; + uint16_t ecc_status = nfc_read_reg(host->regs, NFC_ECC_STATUS_RESULT); /* * 1-Bit errors are automatically corrected in HW. No need for * additional correction. 2-Bit errors cannot be corrected by * HW ECC, so we need to return failure */ - uint16_t ecc_status = readw(host->regs + NFC_ECC_STATUS_RESULT); - - if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { - DEBUG(MTD_DEBUG_LEVEL0, - "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); - return -1; + if (!(nfc_read_reg(host->regs, NFC_CONFIG1) & NFC_ECC_EN)) { + DEBUG(MTD_DEBUG_LEVEL1, "%s: ECC turned off\n", __FUNCTION__); + return 0; + } + + if (ecc_status) + DBG(ecc_status ? -1 : 0, "%s: ECC_STATUS=%04x\n", __FUNCTION__, ecc_status); + + if (cpu_is_mx25()) { + int subpages = mtd->writesize / nand_chip->subpagesize; + + do { + if ((ecc_status & 0xf) > 4) { + printk(KERN_ERR + "MXC_NAND: HWECC uncorrectable ECC error in page %u subpage %d\n", + host->page_addr, + mtd->writesize / nand_chip->subpagesize - subpages); + return -1; + } + ecc_status >>= 4; + subpages--; + } while (subpages > 0); + } else { + if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { + DEBUG(MTD_DEBUG_LEVEL0, + "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); + return -1; + } } return 0; @@ -383,6 +883,7 @@ static int mxc_nand_correct_data(struct static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { + /* HW ECC calculation is done transparently by the controller */ return 0; } @@ -392,8 +893,13 @@ static u_char mxc_nand_read_byte(struct struct mxc_nand_host *host = nand_chip->priv; uint8_t ret = 0; uint16_t col, rd_word; - uint16_t __iomem *main_buf = host->regs + MAIN_AREA0; - uint16_t __iomem *spare_buf = host->regs + SPARE_AREA0; + uint16_t __iomem *main_buf = host->nfc_buf + MAIN_AREA0; + uint16_t __iomem *spare_buf = host->nfc_buf + SPARE_AREA0; + + DEBUG(MTD_DEBUG_LEVEL3, + "%s(col = %d)\n", __FUNCTION__, host->col_addr); + + BUG_ON(host->spare_only && host->col_addr >= 16); /* Check for status request */ if (host->status_request) @@ -424,28 +930,27 @@ static uint16_t mxc_nand_read_word(struc { struct nand_chip *nand_chip = mtd->priv; struct mxc_nand_host *host = nand_chip->priv; - uint16_t col, rd_word, ret; + uint16_t col, ret; uint16_t __iomem *p; - DEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_read_word(col = %d)\n", host->col_addr); + DEBUG(MTD_DEBUG_LEVEL1, + "%s(col = %d)\n", __FUNCTION__, host->col_addr); col = host->col_addr; + /* Adjust saved column address */ if (col < mtd->writesize && host->spare_only) col += mtd->writesize; + BUG_ON(col >= mtd->writesize + 16); if (col < mtd->writesize) - p = (host->regs + MAIN_AREA0) + (col >> 1); + p = (host->nfc_buf + MAIN_AREA0) + (col >> 1); else - p = (host->regs + SPARE_AREA0) + ((col - mtd->writesize) >> 1); + p = (host->nfc_buf + SPARE_AREA0) + ((col - mtd->writesize) >> 1); if (col & 1) { - rd_word = readw(p); - ret = (rd_word >> 8) & 0xff; - rd_word = readw(&p[1]); - ret |= (rd_word << 8) & 0xff00; - + ret = readw(p++) >> 8; + ret |= readw(p) << 8; } else ret = readw(p); @@ -466,31 +971,32 @@ static void mxc_nand_write_buf(struct mt int n, col, i = 0; DEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_write_buf(col = %d, len = %d)\n", host->col_addr, - len); - + "%s(buf=%p col=%03x, len=%03x)\n", __FUNCTION__, + buf, host->col_addr, len); col = host->col_addr; /* Adjust saved column address */ if (col < mtd->writesize && host->spare_only) col += mtd->writesize; - n = mtd->writesize + mtd->oobsize - col; - n = min(len, n); + /* If more data is requested to be written than free space in + * the flash buffer this is clearly a BUG! */ + BUG_ON(len > mtd->writesize + mtd->oobsize - col); + n = len; DEBUG(MTD_DEBUG_LEVEL3, - "%s:%d: col = %d, n = %d\n", __func__, __LINE__, col, n); + "%s:%d: col=%03x, n=%03x\n", __func__, __LINE__, col, n); while (n) { void __iomem *p; if (col < mtd->writesize) - p = host->regs + MAIN_AREA0 + (col & ~3); + p = host->nfc_buf + MAIN_AREA0 + (col & ~3); else - p = host->regs + SPARE_AREA0 - - mtd->writesize + (col & ~3); + p = host->nfc_buf + SPARE_AREA0 + + (col & ~3) - mtd->writesize; - DEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p = %p\n", __func__, + DEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p=%p\n", __func__, __LINE__, p); if (((col | (int)&buf[i]) & 3) || n < 16) { @@ -538,11 +1044,6 @@ static void mxc_nand_write_buf(struct mt m += mtd->oobsize; m = min(n, m) & ~3; - - DEBUG(MTD_DEBUG_LEVEL3, - "%s:%d: n = %d, m = %d, i = %d, col = %d\n", - __func__, __LINE__, n, m, i, col); - memcpy(p, &buf[i], m); col += m; i += m; @@ -563,26 +1064,28 @@ static void mxc_nand_read_buf(struct mtd struct mxc_nand_host *host = nand_chip->priv; int n, col, i = 0; - DEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_read_buf(col = %d, len = %d)\n", host->col_addr, len); - col = host->col_addr; + DEBUG(MTD_DEBUG_LEVEL1, + "%s(col=%03x len=%03x)\n", __FUNCTION__, col, len); + /* Adjust saved column address */ if (col < mtd->writesize && host->spare_only) col += mtd->writesize; - n = mtd->writesize + mtd->oobsize - col; - n = min(len, n); + /* If more data is requested to be read than is available in + * the flash buffer this is clearly a BUG! */ + BUG_ON(len > mtd->writesize + mtd->oobsize - col); + n = len; while (n) { - void __iomem *p; + const void __iomem *p; if (col < mtd->writesize) - p = host->regs + MAIN_AREA0 + (col & ~3); + p = host->nfc_buf + MAIN_AREA0 + (col & ~3); else - p = host->regs + SPARE_AREA0 - - mtd->writesize + (col & ~3); + p = host->nfc_buf + SPARE_AREA0 + + (col & ~3) - mtd->writesize; if (((col | (int)&buf[i]) & 3) || n < 16) { uint32_t data; @@ -629,7 +1132,6 @@ static void mxc_nand_read_buf(struct mtd } /* Update saved column address */ host->col_addr = col; - } /* Used by the upper layer to verify the data in NAND Flash @@ -637,7 +1139,38 @@ static void mxc_nand_read_buf(struct mtd static int mxc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) { - return -EFAULT; + struct nand_chip *nand_chip = mtd->priv; + struct mxc_nand_host *host = nand_chip->priv; + int i; + u16 *wp = host->nfc_buf + MAIN_AREA0; + const u_char *b = buf; + + for (i = 0; i < len >> 1; i++) { + u16 w = *wp++; + u16 data = *buf++; + + if (len - i > 1) + data |= (*buf++) << 8; + else + data |= 0xff << 8; + + /* This is crappy! The upper layer always sends us a + * whole page buffer to verify, even if only a partial page + * was written. So, ignore all 0xff bytes in the reference buffer. + */ + if ((data & w) != w) { + printk(KERN_ERR + "%s: verify error @ %03x: read: %02x %02x expected: %02x %02x\n", + __FUNCTION__, i, w & 0xff, w >> 8, data & 0xff, data >> 8); + print_hex_dump(KERN_DEBUG, "ver: ", DUMP_PREFIX_ADDRESS, + 16, 2, b + ((i << 1) & ~0xf), min(len - i, 64), 0); + print_hex_dump(KERN_DEBUG, "ref: ", DUMP_PREFIX_ADDRESS, + 16, 2, host->nfc_buf + MAIN_AREA0 + ((i << 1) & ~0xf), + min(len - i, 64), 0); + return -EFAULT; + } + } + return 0; } /* This function is used by upper layer for select and @@ -655,13 +1188,13 @@ static void mxc_nand_select_chip(struct } if (chip == -1) { - writew(readw(host->regs + NFC_CONFIG1) & ~NFC_CE, - host->regs + NFC_CONFIG1); + nfc_write_reg(nfc_read_reg(host->regs, NFC_CONFIG1) & ~NFC_CE, + host->regs, NFC_CONFIG1); return; } - writew(readw(host->regs + NFC_CONFIG1) | NFC_CE, - host->regs + NFC_CONFIG1); + nfc_write_reg(nfc_read_reg(host->regs, NFC_CONFIG1) | NFC_CE, + host->regs, NFC_CONFIG1); #endif switch (chip) { @@ -679,9 +1212,6 @@ static void mxc_nand_select_chip(struct host->clk_act = 1; } break; - - default: - break; } } @@ -692,10 +1222,10 @@ static void mxc_nand_command(struct mtd_ { struct nand_chip *nand_chip = mtd->priv; struct mxc_nand_host *host = nand_chip->priv; - int useirq = true; + int useirq = false; DEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", + "%s: cmd 0x%08x, col 0x%03x, page 0x%04x\n", __FUNCTION__, command, column, page_addr); /* Reset command state information */ @@ -710,15 +1240,14 @@ static void mxc_nand_command(struct mtd_ break; case NAND_CMD_READ0: + host->page_addr = page_addr; host->col_addr = column; host->spare_only = false; - useirq = false; break; case NAND_CMD_READOOB: host->col_addr = column; host->spare_only = true; - useirq = false; if (host->pagesize_2k) command = NAND_CMD_READ0; /* only READ0 is valid */ break; @@ -726,9 +1255,9 @@ static void mxc_nand_command(struct mtd_ case NAND_CMD_SEQIN: if (column >= mtd->writesize) { /* - * FIXME: before send SEQIN command for write OOB, - * We must read one page out. - * For K9F1GXX has no READ1 command to set current HW + * Before sending the SEQIN command for writing OOB + * we must read one page out. + * Because K9F1GXX has no READ1 command to set current HW * pointer to spare area, we must write the whole page * including OOB together. */ @@ -751,23 +1280,23 @@ static void mxc_nand_command(struct mtd_ if (!host->pagesize_2k) send_cmd(host, NAND_CMD_READ0, false); } - useirq = false; break; case NAND_CMD_PAGEPROG: send_prog_page(host, 0, host->spare_only); - - if (host->pagesize_2k) { + if (host->pagesize_2k && !cpu_is_mx25()) { /* data in 4 areas datas */ send_prog_page(host, 1, host->spare_only); send_prog_page(host, 2, host->spare_only); send_prog_page(host, 3, host->spare_only); } - + useirq = true; break; case NAND_CMD_ERASE1: - useirq = false; + break; + case NAND_CMD_ERASE2: + useirq = true; break; } @@ -791,23 +1320,13 @@ static void mxc_nand_command(struct mtd_ /* Write out page address, if necessary */ if (page_addr != -1) { - /* paddr_0 - p_addr_7 */ - send_addr(host, (page_addr & 0xff), false); + u32 page_mask = nand_chip->pagemask; - if (host->pagesize_2k) { - send_addr(host, (page_addr >> 8) & 0xFF, false); - if (mtd->size >= 0x40000000) - send_addr(host, (page_addr >> 16) & 0xff, true); - } else { - /* One more address cycle for higher density devices */ - if (mtd->size >= 0x4000000) { - /* paddr_8 - paddr_15 */ - send_addr(host, (page_addr >> 8) & 0xff, false); - send_addr(host, (page_addr >> 16) & 0xff, true); - } else - /* paddr_8 - paddr_15 */ - send_addr(host, (page_addr >> 8) & 0xff, true); - } + do { + send_addr(host, (page_addr & 0xff), false); + page_mask >>= 8; + page_addr >>= 8; + } while (page_mask != 0); } /* Command post-processing step */ @@ -823,14 +1342,17 @@ static void mxc_nand_command(struct mtd_ send_cmd(host, NAND_CMD_READSTART, true); /* read for each AREA */ send_read_page(host, 0, host->spare_only); - send_read_page(host, 1, host->spare_only); - send_read_page(host, 2, host->spare_only); - send_read_page(host, 3, host->spare_only); + if (!cpu_is_mx25()) { + send_read_page(host, 1, host->spare_only); + send_read_page(host, 2, host->spare_only); + send_read_page(host, 3, host->spare_only); + } } else send_read_page(host, 0, host->spare_only); break; case NAND_CMD_READID: + host->col_addr = 0; send_read_id(host); break; @@ -851,9 +1373,9 @@ static int __init mxcnd_probe(struct pla struct mtd_info *mtd; struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; struct mxc_nand_host *host; - struct resource *res; + struct resource *res1, *res2; uint16_t tmp; - int err = 0, nr_parts = 0; + int err, nr_parts; /* Allocate memory for MTD device structure and private data */ host = kzalloc(sizeof(struct mxc_nand_host), GFP_KERNEL); @@ -868,9 +1390,6 @@ static int __init mxcnd_probe(struct pla mtd->owner = THIS_MODULE; mtd->dev.parent = &pdev->dev; - /* 50 us command delay time */ - this->chip_delay = 5; - this->priv = host; this->dev_ready = mxc_nand_dev_ready; this->cmdfunc = mxc_nand_command; @@ -880,29 +1399,54 @@ static int __init mxcnd_probe(struct pla this->write_buf = mxc_nand_write_buf; this->read_buf = mxc_nand_read_buf; this->verify_buf = mxc_nand_verify_buf; +#ifdef CONFIG_MTD_NAND_MXC_FLASH_BBT + this->bbt_td = &bbt_main_descr; + this->bbt_md = &bbt_mirror_descr; + this->options |= NAND_USE_FLASH_BBT; +#endif - host->clk = clk_get(&pdev->dev, "nfc"); - if (IS_ERR(host->clk)) + host->clk = clk_get(&pdev->dev, "nfc_clk"); + if (IS_ERR(host->clk)) { + err = PTR_ERR(host->clk); goto eclk; + } clk_enable(host->clk); host->clk_act = 1; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { + res1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res1 || !res2) { err = -ENODEV; goto eres; } - host->regs = ioremap(res->start, res->end - res->start + 1); + if (!request_mem_region(res1->start, resource_size(res1), "mxc_nand regs")) { + err = -EBUSY; + goto ereq1; + } + + if (!request_mem_region(res2->start, resource_size(res2), "mxc_nand buffer")) { + err = -EBUSY; + goto ereq2; + } + + host->regs = ioremap(res1->start, resource_size(res1)); if (!host->regs) { - err = -EIO; - goto eres; + err = -ENOMEM; + goto eunmap1; } - tmp = readw(host->regs + NFC_CONFIG1); + host->nfc_buf = ioremap(res2->start, resource_size(res2)); + if (!host->nfc_buf) { + err = -ENOMEM; + goto eunmap2; + } + + tmp = nfc_read_reg(host->regs, NFC_CONFIG1); tmp |= NFC_INT_MSK; - writew(tmp, host->regs + NFC_CONFIG1); + nfc_write_reg(tmp, host->regs, NFC_CONFIG1); + nfc_write_reg(0, host->regs, NFC_CONFIG2); init_waitqueue_head(&host->irq_waitq); @@ -912,57 +1456,89 @@ static int __init mxcnd_probe(struct pla if (err) goto eirq; - if (pdata->hw_ecc) { - this->ecc.calculate = mxc_nand_calculate_ecc; - this->ecc.hwctl = mxc_nand_enable_hwecc; - this->ecc.correct = mxc_nand_correct_data; - this->ecc.mode = NAND_ECC_HW; - this->ecc.size = 512; - this->ecc.bytes = 3; - this->ecc.layout = &nand_hw_eccoob_8; - tmp = readw(host->regs + NFC_CONFIG1); - tmp |= NFC_ECC_EN; - writew(tmp, host->regs + NFC_CONFIG1); - } else { - this->ecc.size = 512; - this->ecc.bytes = 3; - this->ecc.layout = &nand_hw_eccoob_8; - this->ecc.mode = NAND_ECC_SOFT; - tmp = readw(host->regs + NFC_CONFIG1); - tmp &= ~NFC_ECC_EN; - writew(tmp, host->regs + NFC_CONFIG1); - } - /* Reset NAND */ this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); /* preset operation */ /* Unlock the internal RAM Buffer */ - writew(0x2, host->regs + NFC_CONFIG); + nfc_write_reg(0x2, host->regs, NFC_CONFIG); /* Blocks to be unlocked */ - writew(0x0, host->regs + NFC_UNLOCKSTART_BLKADDR); - writew(0x4000, host->regs + NFC_UNLOCKEND_BLKADDR); + nfc_write_reg(0x0, host->regs, NFC_UNLOCKSTART_BLKADDR); + nfc_write_reg(0x4000, host->regs, NFC_UNLOCKEND_BLKADDR); /* Unlock Block Command for given address range */ - writew(0x4, host->regs + NFC_WRPROT); + nfc_write_reg(0x4, host->regs, NFC_WRPROT); /* NAND bus width determines access funtions used by upper layer */ if (pdata->width == 2) { this->options |= NAND_BUSWIDTH_16; - this->ecc.layout = &nand_hw_eccoob_16; } - host->pagesize_2k = 0; - /* Scan to find existence of the device */ - if (nand_scan(mtd, 1)) { + err = nand_scan_ident(mtd, 1); + if (err) { DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND: Unable to find any NAND device.\n"); - err = -ENXIO; goto escan; } + /* this is required before completing the scan */ + host->pagesize_2k = (mtd->writesize == 2048); + tmp = nfc_read_reg(host->regs, NFC_CONFIG1); + if (cpu_is_mx25()) + tmp |= NFC_ONE_CYCLE; + + tmp &= ~(3 << 9); /* clear PPB mask */ + /* set PPB (pages per block) */ + tmp |= (ffs(mtd->erasesize / mtd->writesize) - 6) << 9; + nfc_write_reg(tmp, host->regs, NFC_CONFIG1); + + if (pdata->hw_ecc) { + this->ecc.calculate = mxc_nand_calculate_ecc; + this->ecc.hwctl = mxc_nand_enable_hwecc; + this->ecc.correct = mxc_nand_correct_data; + if (cpu_is_mx25()) { + this->ecc.mode = NAND_ECC_HW_SYNDROME; + this->ecc.read_page = mxc_nand_read_page_syndrome; + this->ecc.read_page_raw = mxc_nand_read_page_raw_syndrome; + this->ecc.read_oob = mxc_nand_read_oob_syndrome; + this->ecc.write_page = mxc_nand_write_page_syndrome; + this->ecc.write_page_raw = mxc_nand_write_page_raw_syndrome; + this->ecc.write_oob = mxc_nand_write_oob_syndrome; + this->ecc.bytes = 9; + this->ecc.prepad = 7; + } else { + this->ecc.mode = NAND_ECC_HW; + } + if (host->pagesize_2k) { + this->ecc.layout = &nand_hw_eccoob2k_8; + } else { + this->ecc.layout = &nand_hw_eccoob_8; + } + this->ecc.size = 512; + tmp = nfc_read_reg(host->regs, NFC_CONFIG1); + tmp |= NFC_ECC_EN; + nfc_write_reg(tmp, host->regs, NFC_CONFIG1); + } else { + this->ecc.mode = NAND_ECC_SOFT; + tmp = nfc_read_reg(host->regs, NFC_CONFIG1); + tmp &= ~NFC_ECC_EN; + nfc_write_reg(tmp, host->regs, NFC_CONFIG1); + } + + err = nand_scan_tail(mtd); + if (err) { + goto escan; + } + if (cpu_is_mx25()) { + mtd->flags &= ~MTD_OOB_WRITEABLE; + } + + pr_info("MXC MTD nand Driver IRQ %d bus width: %u bit %s ECC IO: %08lx\n", + host->irq, pdata->width * 8, pdata->hw_ecc ? "HW" : "SW", + (unsigned long)res1->start); + /* Register the partitions */ #ifdef CONFIG_MTD_PARTITIONS nr_parts = @@ -981,10 +1557,19 @@ static int __init mxcnd_probe(struct pla return 0; escan: - free_irq(host->irq, NULL); + free_irq(host->irq, host); eirq: + if (res2) + iounmap(host->nfc_buf); +eunmap2: iounmap(host->regs); +eunmap1: + release_mem_region(res2->start, resource_size(res2)); +ereq2: + release_mem_region(res1->start, resource_size(res1)); +ereq1: eres: + clk_disable(host->clk); clk_put(host->clk); eclk: kfree(host); @@ -995,46 +1580,63 @@ eclk: static int __devexit mxcnd_remove(struct platform_device *pdev) { struct mxc_nand_host *host = platform_get_drvdata(pdev); + struct resource *res; + if (host->clk_act) + clk_disable(host->clk); clk_put(host->clk); - platform_set_drvdata(pdev, NULL); - nand_release(&host->mtd); - free_irq(host->irq, NULL); + free_irq(host->irq, host); iounmap(host->regs); kfree(host); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + release_mem_region(res->start, resource_size(res)); + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) { + release_mem_region(res->start, resource_size(res)); + } return 0; } #ifdef CONFIG_PM static int mxcnd_suspend(struct platform_device *pdev, pm_message_t state) { - struct mtd_info *info = platform_get_drvdata(pdev); + struct mtd_info *mtd = platform_get_drvdata(pdev); + struct nand_chip *nand_chip = mtd->priv; + struct mxc_nand_host *host = nand_chip->priv; int ret = 0; DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND suspend\n"); - if (info) - ret = info->suspend(info); + if (mtd) + ret = mtd->suspend(mtd); - /* Disable the NFC clock */ - clk_disable(nfc_clk); /* FIXME */ + if (host->clk_act) { + /* Disable the NFC clock */ + clk_disable(host->clk); + } return ret; } static int mxcnd_resume(struct platform_device *pdev) { - struct mtd_info *info = platform_get_drvdata(pdev); + struct mtd_info *mtd = platform_get_drvdata(pdev); + struct nand_chip *nand_chip = mtd->priv; + struct mxc_nand_host *host = nand_chip->priv; int ret = 0; DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND resume\n"); - /* Enable the NFC clock */ - clk_enable(nfc_clk); /* FIXME */ - if (info) - info->resume(info); + if (host->clk_act) { + /* Enable the NFC clock */ + clk_enable(host->clk); + } + if (mtd) + mtd->resume(mtd); return ret; } @@ -1047,7 +1649,7 @@ static int mxcnd_resume(struct platform_ static struct platform_driver mxcnd_driver = { .driver = { .name = DRIVER_NAME, - }, + }, .remove = __exit_p(mxcnd_remove), .suspend = mxcnd_suspend, .resume = mxcnd_resume, @@ -1055,13 +1657,14 @@ static struct platform_driver mxcnd_driv static int __init mxc_nd_init(void) { + int ret; + /* Register the device driver structure. */ - pr_info("MXC MTD nand Driver\n"); - if (platform_driver_probe(&mxcnd_driver, mxcnd_probe) != 0) { + ret = platform_driver_probe(&mxcnd_driver, mxcnd_probe); + if (ret != 0) { printk(KERN_ERR "Driver register failed for mxcnd_driver\n"); - return -ENODEV; } - return 0; + return ret; } static void __exit mxc_nd_cleanup(void) diff -purN linux-2.6.30-rc4-git/drivers/net/Kconfig linux-2.6.30-rc4-karo3/drivers/net/Kconfig --- linux-2.6.30-rc4-git/drivers/net/Kconfig 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/drivers/net/Kconfig 2009-06-02 18:42:32.000000000 +0200 @@ -1859,7 +1859,7 @@ config 68360_ENET config FEC bool "FEC ethernet controller (of ColdFire CPUs)" - depends on M523x || M527x || M5272 || M528x || M520x || M532x || MACH_MX27 + depends on M523x || M527x || M5272 || M528x || M520x || M532x || MACH_MX27 || MACH_TX25 help Say Y here if you want to use the built-in 10/100 Fast ethernet controller on some Motorola ColdFire and Freescale i.MX processors. diff -purN linux-2.6.30-rc4-git/drivers/net/can/Kconfig linux-2.6.30-rc4-karo3/drivers/net/can/Kconfig --- linux-2.6.30-rc4-git/drivers/net/can/Kconfig 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/drivers/net/can/Kconfig 2009-07-01 11:28:55.000000000 +0200 @@ -22,4 +22,21 @@ config CAN_DEBUG_DEVICES a problem with CAN support and want to see more of what is going on. +config CAN_FLEXCAN + tristate "Freescale FlexCAN" + depends on CAN && (MACH_MX25 || ARCH_MX35) + default m + ---help--- + This select the support of Freescale CAN(FlexCAN). + This driver can also be built as a module. + If unsure, say N. + +config CAN_FLEXCAN_CAN1 + bool "Enable CAN1 interface on i.MX25/i.MX35" + depends on CAN_FLEXCAN && (MACH_MX25 && !ARCH_MXC_EHCI_USBOTG) + +config CAN_FLEXCAN_CAN2 + bool "Enable CAN2 interface on i.MX25/i.MX35" + depends on CAN_FLEXCAN + endmenu diff -purN linux-2.6.30-rc4-git/drivers/net/can/Makefile linux-2.6.30-rc4-karo3/drivers/net/can/Makefile --- linux-2.6.30-rc4-git/drivers/net/can/Makefile 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/drivers/net/can/Makefile 2009-07-01 11:29:31.000000000 +0200 @@ -1,5 +1,9 @@ # # Makefile for the Linux Controller Area Network drivers. # +ifneq ($(CONFIG_CAN_DEBUG_DEVICES),) + EXTRA_CFLAGS += -DDEBUG +endif obj-$(CONFIG_CAN_VCAN) += vcan.o +obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o diff -purN linux-2.6.30-rc4-git/drivers/net/can/flexcan.c linux-2.6.30-rc4-karo3/drivers/net/can/flexcan.c --- linux-2.6.30-rc4-git/drivers/net/can/flexcan.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/drivers/net/can/flexcan.c 2009-07-06 15:17:41.000000000 +0200 @@ -0,0 +1,1784 @@ +/* + * drivers/net/can/flexcan.c + * + * Copyright (C) 2009 Lothar Wassmann + * + * based on: drivers/net/can/flexcan/ + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + */ + +/* + * Driver for Freescale CAN Controller FlexCAN. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "flexcan.h" + +#ifdef DEBUG +static int debug = 0; +#define dbg_lvl(n) ((n) < debug) +module_param(debug, int, S_IRUGO | S_IWUSR); + +#define DBG(lvl, fmt...) do { if (dbg_lvl(lvl)) printk(KERN_DEBUG fmt); } while (0) +#else +static int debug; +#define dbg_lvl(n) 0 +module_param(debug, int, 0); + +#define DBG(lvl, fmt...) do { } while (0) +#endif + +#define ndev_dbg(d, l, fmt...) do { if (dbg_lvl(l)) dev_dbg(&(d)->dev, fmt); } while (0) +#define pdev_dbg(p, l, fmt...) do { if (dbg_lvl(l)) dev_dbg(&(p)->dev, fmt); } while (0) +#define flexcan_dbg(f, l, fmt...) do { if (dbg_lvl(l)) dev_dbg(&(f)->dev->dev, fmt); } while (0) + +#define ndev_err(d, fmt...) dev_err(&(d)->dev, fmt) +#define pdev_err(p, fmt...) dev_err(&(p)->dev, fmt) + +enum { + FLEXCAN_ATTR_STATE = 0, + FLEXCAN_ATTR_BITRATE, + FLEXCAN_ATTR_BR_PRESDIV, + FLEXCAN_ATTR_BR_RJW, + FLEXCAN_ATTR_BR_PROPSEG, + FLEXCAN_ATTR_BR_PSEG1, + FLEXCAN_ATTR_BR_PSEG2, + FLEXCAN_ATTR_BR_CLKSRC, + FLEXCAN_ATTR_MAXMB, + FLEXCAN_ATTR_XMIT_MAXMB, + FLEXCAN_ATTR_FIFO, + FLEXCAN_ATTR_WAKEUP, + FLEXCAN_ATTR_SRX_DIS, + FLEXCAN_ATTR_WAK_SRC, + FLEXCAN_ATTR_BCC, + FLEXCAN_ATTR_LOCAL_PRIORITY, + FLEXCAN_ATTR_ABORT, + FLEXCAN_ATTR_LOOPBACK, + FLEXCAN_ATTR_SMP, + FLEXCAN_ATTR_BOFF_REC, + FLEXCAN_ATTR_TSYN, + FLEXCAN_ATTR_LISTEN, + FLEXCAN_ATTR_EXTEND_MSG, + FLEXCAN_ATTR_STANDARD_MSG, +#ifdef CONFIG_CAN_DEBUG_DEVICES + FLEXCAN_ATTR_DUMP_REG, + FLEXCAN_ATTR_DUMP_XMIT_MB, + FLEXCAN_ATTR_DUMP_RX_MB, +#endif + FLEXCAN_ATTR_MAX +}; + +#ifdef DEBUG +#define flexcan_reg_read(f,r) _flexcan_reg_read(f, r, #r, __FUNCTION__) +static inline unsigned long _flexcan_reg_read(struct flexcan_device *flexcan, int reg, + const char *name, const char *fn) +{ + unsigned long val; + val = __raw_readl(flexcan->io_base + reg); + DBG(2, "%s: Read %08lx from %s[%p]\n", fn, val, name, + flexcan->io_base + reg); + return val; +} + +#define flexcan_reg_write(f,r,v) _flexcan_reg_write(f, r, v, #r, __FUNCTION__) +static inline void _flexcan_reg_write(struct flexcan_device *flexcan, int reg, unsigned long val, + const char *name, const char *fn) +{ + DBG(2, "%s: Writing %08lx to %s[%p]\n", fn, val, name, flexcan->io_base + reg); + __raw_writel(val, flexcan->io_base + reg); +} +#else +static inline unsigned long flexcan_reg_read(struct flexcan_device *flexcan, int reg) +{ + return __raw_readl(flexcan->io_base + reg); +} + +static inline void flexcan_reg_write(struct flexcan_device *flexcan, int reg, unsigned long val) +{ + __raw_writel(val, flexcan->io_base + reg); +} +#endif + +static ssize_t flexcan_show_attr(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t flexcan_set_attr(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count); + +static struct device_attribute flexcan_dev_attr[FLEXCAN_ATTR_MAX] = { + [FLEXCAN_ATTR_STATE] = __ATTR(state, 0444, flexcan_show_attr, NULL), + [FLEXCAN_ATTR_BITRATE] = + __ATTR(bitrate, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_BR_PRESDIV] = + __ATTR(br_presdiv, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_BR_RJW] = + __ATTR(br_rjw, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_BR_PROPSEG] = + __ATTR(br_propseg, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_BR_PSEG1] = + __ATTR(br_pseg1, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_BR_PSEG2] = + __ATTR(br_pseg2, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_BR_CLKSRC] = + __ATTR(br_clksrc, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_MAXMB] = + __ATTR(maxmb, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_XMIT_MAXMB] = + __ATTR(xmit_maxmb, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_FIFO] = + __ATTR(fifo, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_WAKEUP] = + __ATTR(wakeup, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_SRX_DIS] = + __ATTR(srx_dis, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_WAK_SRC] = + __ATTR(wak_src, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_BCC] = + __ATTR(bcc, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_LOCAL_PRIORITY] = + __ATTR(local_priority, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_ABORT] = + __ATTR(abort, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_LOOPBACK] = + __ATTR(loopback, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_SMP] = + __ATTR(smp, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_BOFF_REC] = + __ATTR(boff_rec, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_TSYN] = + __ATTR(tsyn, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_LISTEN] = + __ATTR(listen, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_EXTEND_MSG] = + __ATTR(ext_msg, 0644, flexcan_show_attr, flexcan_set_attr), + [FLEXCAN_ATTR_STANDARD_MSG] = + __ATTR(std_msg, 0644, flexcan_show_attr, flexcan_set_attr), +#ifdef CONFIG_CAN_DEBUG_DEVICES + [FLEXCAN_ATTR_DUMP_REG] = + __ATTR(dump_reg, 0444, flexcan_show_attr, NULL), + [FLEXCAN_ATTR_DUMP_XMIT_MB] = + __ATTR(dump_xmit_mb, 0444, flexcan_show_attr, NULL), + [FLEXCAN_ATTR_DUMP_RX_MB] = + __ATTR(dump_rx_mb, 0444, flexcan_show_attr, NULL), +#endif +}; + +static void flexcan_set_bitrate(struct flexcan_device *flexcan, int bitrate) +{ + /* TODO:: implement in future + * based on the bitrate to get the timing of + * presdiv, pseg1, pseg2, propseg + */ +} + +static void flexcan_update_bitrate(struct flexcan_device *flexcan) +{ + int rate, div; + + if (flexcan->br_clksrc) + rate = clk_get_rate(flexcan->clk); + else { + struct clk *clk; + clk = clk_get_sys(NULL, "ckih"); + if (IS_ERR(clk)) + return; + rate = clk_get_rate(clk); + clk_put(clk); + } + if (!rate) + return; + + flexcan_dbg(flexcan, 0, "%s: master clock rate %u from %s\n", + __FUNCTION__, rate, flexcan->br_clksrc ? "osc" : "pll"); + + div = flexcan->br_presdiv + 1; + div *= flexcan->br_propseg + flexcan->br_pseg1 + flexcan->br_pseg2 + 4; + flexcan->bitrate = (rate + div - 1) / div; + + flexcan_dbg(flexcan, 0, "%s: flexcan bitrate %u time quantum %uns\n", + __FUNCTION__, flexcan->bitrate, + 1000000000 / (flexcan->bitrate * + (flexcan->br_propseg + flexcan->br_pseg1 + + flexcan->br_pseg2 + 4))); +} + +static inline void flexcan_read_hw_mb(struct flexcan_device *flexcan, struct can_hw_mb *mb, + int buf_no) +{ + __raw_readsl(mb, flexcan->hwmb + buf_no * sizeof(*mb), sizeof(*mb)); +} + +static inline void flexcan_write_hw_mb(struct flexcan_device *flexcan, struct can_hw_mb *mb, + int buf_no) +{ + __raw_writesl(flexcan->hwmb + buf_no * sizeof(*mb), mb, sizeof(*mb)); +} + +#ifdef CONFIG_CAN_DEBUG_DEVICES +static int flexcan_dump_reg(struct flexcan_device *flexcan, char *buf) +{ + int ret = 0; + unsigned int reg; + + reg = flexcan_reg_read(flexcan, CAN_HW_REG_MCR); + ret += sprintf(buf + ret, "MCR::0x%08x\n", reg); + reg = flexcan_reg_read(flexcan, CAN_HW_REG_CTRL); + ret += sprintf(buf + ret, "CTRL::0x%08x\n", reg); + reg = flexcan_reg_read(flexcan, CAN_HW_REG_RXGMASK); + ret += sprintf(buf + ret, "RXGMASK::0x%08x\n", reg); + reg = flexcan_reg_read(flexcan, CAN_HW_REG_RX14MASK); + ret += sprintf(buf + ret, "RX14MASK::0x%08x\n", reg); + reg = flexcan_reg_read(flexcan, CAN_HW_REG_RX15MASK); + ret += sprintf(buf + ret, "RX15MASK::0x%08x\n", reg); + reg = flexcan_reg_read(flexcan, CAN_HW_REG_ECR); + ret += sprintf(buf + ret, "ECR::0x%08x\n", reg); + reg = flexcan_reg_read(flexcan, CAN_HW_REG_ESR); + ret += sprintf(buf + ret, "ESR::0x%08x\n", reg); + reg = flexcan_reg_read(flexcan, CAN_HW_REG_IMASK2); + ret += sprintf(buf + ret, "IMASK2::0x%08x\n", reg); + reg = flexcan_reg_read(flexcan, CAN_HW_REG_IMASK1); + ret += sprintf(buf + ret, "IMASK1::0x%08x\n", reg); + reg = flexcan_reg_read(flexcan, CAN_HW_REG_IFLAG2); + ret += sprintf(buf + ret, "IFLAG2::0x%08x\n", reg); + reg = flexcan_reg_read(flexcan, CAN_HW_REG_IFLAG1); + ret += sprintf(buf + ret, "IFLAG1::0x%08x\n", reg); + return ret; +} + +static int flexcan_dump_xmit_mb(struct flexcan_device *flexcan, char *buf) +{ + int ret = 0, i; + + clk_enable(flexcan->clk); + for (i = flexcan->xmit_maxmb + 1; i <= flexcan->maxmb; i++) { + int j; + + ret += sprintf(buf + ret, + "mb[%d]::CS:0x%08x ID:0x%08x DATA", + i, flexcan->hwmb[i].mb_cs.data, + flexcan->hwmb[i].mb_id); + for (j = 0; j < sizeof(flexcan->hwmb[i].mb_data); j++) { + ret += sprintf(buf + ret, ":%02x", + flexcan->hwmb[i].mb_data[j]); + } + ret += sprintf(buf + ret, "\n"); + } + clk_disable(flexcan->clk); + return ret; +} + +static int flexcan_dump_rx_mb(struct flexcan_device *flexcan, char *buf) +{ + int ret = 0, i; + + clk_enable(flexcan->clk); + for (i = 0; i <= flexcan->xmit_maxmb; i++) { + int j; + + ret += sprintf(buf + ret, + "mb[%d]::CS:0x%08x ID:0x%08x DATA", + i, flexcan->hwmb[i].mb_cs.data, + flexcan->hwmb[i].mb_id); + for (j = 0; j < sizeof(flexcan->hwmb[i].mb_data); j++) { + ret += sprintf(buf + ret, ":%02x", + flexcan->hwmb[i].mb_data[j]); + } + ret += sprintf(buf + ret, "\n"); + } + clk_disable(flexcan->clk); + return ret; +} +#endif + +static ssize_t flexcan_show_state(struct net_device *net, char *buf) +{ + int ret, esr; + struct flexcan_device *flexcan = netdev_priv(net); + + ret = sprintf(buf, "%s::", netif_running(net) ? "Start" : "Stop"); + if (netif_carrier_ok(net)) { + esr = flexcan_reg_read(flexcan, CAN_HW_REG_ESR); + switch ((esr & __ESR_FLT_CONF_MASK) >> __ESR_FLT_CONF_OFF) { + case 0: + ret += sprintf(buf + ret, "normal\n"); + break; + case 1: + ret += sprintf(buf + ret, "error passive\n"); + break; + default: + ret += sprintf(buf + ret, "bus off\n"); + } + } else + ret += sprintf(buf + ret, "bus off\n"); + return ret; +} + +static ssize_t flexcan_show_attr(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int attr_id; + struct net_device *net = dev_get_drvdata(dev); + struct flexcan_device *flexcan = netdev_priv(net); + + attr_id = attr - flexcan_dev_attr; + switch (attr_id) { + case FLEXCAN_ATTR_STATE: + return flexcan_show_state(net, buf); + case FLEXCAN_ATTR_BITRATE: + return sprintf(buf, "%d\n", flexcan->bitrate); + case FLEXCAN_ATTR_BR_PRESDIV: + return sprintf(buf, "%d\n", flexcan->br_presdiv + 1); + case FLEXCAN_ATTR_BR_RJW: + return sprintf(buf, "%d\n", flexcan->br_rjw); + case FLEXCAN_ATTR_BR_PROPSEG: + return sprintf(buf, "%d\n", flexcan->br_propseg + 1); + case FLEXCAN_ATTR_BR_PSEG1: + return sprintf(buf, "%d\n", flexcan->br_pseg1 + 1); + case FLEXCAN_ATTR_BR_PSEG2: + return sprintf(buf, "%d\n", flexcan->br_pseg2 + 1); + case FLEXCAN_ATTR_BR_CLKSRC: + return sprintf(buf, "%s\n", flexcan->br_clksrc ? "bus" : "osc"); + case FLEXCAN_ATTR_MAXMB: + return sprintf(buf, "%d\n", flexcan->maxmb + 1); + case FLEXCAN_ATTR_XMIT_MAXMB: + return sprintf(buf, "%d\n", flexcan->xmit_maxmb + 1); + case FLEXCAN_ATTR_FIFO: + return sprintf(buf, "%d\n", flexcan->fifo); + case FLEXCAN_ATTR_WAKEUP: + return sprintf(buf, "%d\n", flexcan->wakeup); + case FLEXCAN_ATTR_SRX_DIS: + return sprintf(buf, "%d\n", flexcan->srx_dis); + case FLEXCAN_ATTR_WAK_SRC: + return sprintf(buf, "%d\n", flexcan->wak_src); + case FLEXCAN_ATTR_BCC: + return sprintf(buf, "%d\n", flexcan->bcc); + case FLEXCAN_ATTR_LOCAL_PRIORITY: + return sprintf(buf, "%d\n", flexcan->lprio); + case FLEXCAN_ATTR_ABORT: + return sprintf(buf, "%d\n", flexcan->abort); + case FLEXCAN_ATTR_LOOPBACK: + return sprintf(buf, "%d\n", flexcan->loopback); + case FLEXCAN_ATTR_SMP: + return sprintf(buf, "%d\n", flexcan->smp); + case FLEXCAN_ATTR_BOFF_REC: + return sprintf(buf, "%d\n", flexcan->boff_rec); + case FLEXCAN_ATTR_TSYN: + return sprintf(buf, "%d\n", flexcan->tsyn); + case FLEXCAN_ATTR_LISTEN: + return sprintf(buf, "%d\n", flexcan->listen); + case FLEXCAN_ATTR_EXTEND_MSG: + return sprintf(buf, "%d\n", flexcan->ext_msg); + case FLEXCAN_ATTR_STANDARD_MSG: + return sprintf(buf, "%d\n", flexcan->std_msg); +#ifdef CONFIG_CAN_DEBUG_DEVICES + case FLEXCAN_ATTR_DUMP_REG: + return flexcan_dump_reg(flexcan, buf); + case FLEXCAN_ATTR_DUMP_XMIT_MB: + return flexcan_dump_xmit_mb(flexcan, buf); + case FLEXCAN_ATTR_DUMP_RX_MB: + return flexcan_dump_rx_mb(flexcan, buf); +#endif + default: + return sprintf(buf, "%s:%p->%p\n", __func__, flexcan_dev_attr, + attr); + } +} + +static ssize_t flexcan_set_attr(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + int attr_id, tmp; + struct net_device *net = dev_get_drvdata(dev); + struct flexcan_device *flexcan = netdev_priv(net); + + attr_id = attr - flexcan_dev_attr; + + mutex_lock(&flexcan->mutex); + + if (netif_running(net)) + goto set_finish; + + if (attr_id == FLEXCAN_ATTR_BR_CLKSRC) { + if (!strcasecmp(buf, "bus")) + flexcan->br_clksrc = 1; + else if (!strcasecmp(buf, "osc")) + flexcan->br_clksrc = 0; + goto set_finish; + } + + tmp = simple_strtoul(buf, NULL, 0); + switch (attr_id) { + case FLEXCAN_ATTR_BITRATE: + flexcan_set_bitrate(flexcan, tmp); + break; + case FLEXCAN_ATTR_BR_PRESDIV: + if ((tmp > 0) && (tmp <= FLEXCAN_MAX_PRESDIV)) { + flexcan->br_presdiv = tmp - 1; + flexcan_update_bitrate(flexcan); + } + break; + case FLEXCAN_ATTR_BR_RJW: + if ((tmp > 0) && (tmp <= FLEXCAN_MAX_RJW)) + flexcan->br_rjw = tmp - 1; + break; + case FLEXCAN_ATTR_BR_PROPSEG: + if ((tmp > 0) && (tmp <= FLEXCAN_MAX_PROPSEG)) { + flexcan->br_propseg = tmp - 1; + flexcan_update_bitrate(flexcan); + } + break; + case FLEXCAN_ATTR_BR_PSEG1: + if ((tmp > 0) && (tmp <= FLEXCAN_MAX_PSEG1)) { + flexcan->br_pseg1 = tmp - 1; + flexcan_update_bitrate(flexcan); + } + break; + case FLEXCAN_ATTR_BR_PSEG2: + if ((tmp > 0) && (tmp <= FLEXCAN_MAX_PSEG2)) { + flexcan->br_pseg2 = tmp - 1; + flexcan_update_bitrate(flexcan); + } + break; + case FLEXCAN_ATTR_MAXMB: + if ((tmp > 0) && (tmp <= FLEXCAN_MAX_MB)) { + if (flexcan->maxmb != (tmp - 1)) { + flexcan->maxmb = tmp - 1; + if (flexcan->xmit_maxmb < flexcan->maxmb) + flexcan->xmit_maxmb = flexcan->maxmb; + } + } + break; + case FLEXCAN_ATTR_XMIT_MAXMB: + if ((tmp > 0) && (tmp <= (flexcan->maxmb + 1))) { + if (flexcan->xmit_maxmb != (tmp - 1)) + flexcan->xmit_maxmb = tmp - 1; + } + break; + case FLEXCAN_ATTR_FIFO: + flexcan->fifo = !!tmp; + break; + case FLEXCAN_ATTR_WAKEUP: + flexcan->wakeup = !!tmp; + break; + case FLEXCAN_ATTR_SRX_DIS: + flexcan->srx_dis = !!tmp; + break; + case FLEXCAN_ATTR_WAK_SRC: + flexcan->wak_src = !!tmp; + break; + case FLEXCAN_ATTR_BCC: + flexcan->bcc = !!tmp; + break; + case FLEXCAN_ATTR_LOCAL_PRIORITY: + flexcan->lprio = !!tmp; + break; + case FLEXCAN_ATTR_ABORT: + flexcan->abort = !!tmp; + break; + case FLEXCAN_ATTR_LOOPBACK: + flexcan->loopback = !!tmp; + break; + case FLEXCAN_ATTR_SMP: + flexcan->smp = !!tmp; + break; + case FLEXCAN_ATTR_BOFF_REC: + flexcan->boff_rec = !!tmp; + break; + case FLEXCAN_ATTR_TSYN: + flexcan->tsyn = !!tmp; + break; + case FLEXCAN_ATTR_LISTEN: + flexcan->listen = !!tmp; + break; + case FLEXCAN_ATTR_EXTEND_MSG: + flexcan->ext_msg = !!tmp; + break; + case FLEXCAN_ATTR_STANDARD_MSG: + flexcan->std_msg = !!tmp; + break; + } + set_finish: + mutex_unlock(&flexcan->mutex); + return count; +} + +static void flexcan_device_default(struct flexcan_device *dev) +{ + dev->br_clksrc = 1; + dev->br_rjw = 2; + dev->br_presdiv = 6; + dev->br_propseg = 4; + dev->br_pseg1 = 4; + dev->br_pseg2 = 7; + + dev->bcc = 1; + dev->srx_dis = 1; + dev->smp = 1; + dev->abort = 1; + + dev->maxmb = FLEXCAN_MAX_MB - 1; + dev->xmit_maxmb = (FLEXCAN_MAX_MB >> 1) - 1; + dev->xmit_mb = dev->maxmb - dev->xmit_maxmb; + + dev->ext_msg = 1; + dev->std_msg = 1; +} + +static int flexcan_device_attach(struct flexcan_device *flexcan) +{ + int ret; + struct resource *res; + struct platform_device *pdev = flexcan->dev; + struct flexcan_platform_data *plat_data = pdev->dev.platform_data; + int irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -ENODEV; + + if (!request_mem_region(res->start, resource_size(res), "flexcan")) { + return -EBUSY; + } + + flexcan->irq = irq; + flexcan->io_base = ioremap_nocache(res->start, resource_size(res)); + if (!flexcan->io_base) { + ret = -ENOMEM; + goto release; + } + pdev_dbg(pdev, 0, "controller registers %08lx remapped to %p\n", + (unsigned long)res->start, flexcan->io_base); + + flexcan->hwmb = flexcan->io_base + CAN_MB_BASE; + flexcan->rx_mask = flexcan->io_base + CAN_RXMASK_BASE; + + flexcan->clk = clk_get(&pdev->dev, "can_clk"); + if (IS_ERR(flexcan->clk)) { + ret = PTR_ERR(flexcan->clk); + dev_err(&pdev->dev, "Failed to get clock: %d\n", ret); + goto unmap; + } + + if (plat_data) { + if (plat_data->active) { + ret = plat_data->active(pdev); + if (ret) + goto put_clk; + } + if (plat_data->core_reg) { + flexcan->core_reg = regulator_get(&pdev->dev, + plat_data->core_reg); + if (IS_ERR(flexcan->core_reg)) { + ret = PTR_ERR(flexcan->core_reg); + goto deactivate; + } + } + + if (plat_data->io_reg) { + flexcan->io_reg = regulator_get(&pdev->dev, + plat_data->io_reg); + if (IS_ERR(flexcan->core_reg)) { + ret = PTR_ERR(flexcan->io_reg); + goto put_reg; + } + } + } + return 0; + + put_reg: + regulator_put(flexcan->core_reg); + deactivate: + if (plat_data->inactive) + plat_data->inactive(pdev); + put_clk: + clk_put(flexcan->clk); + unmap: + iounmap(flexcan->io_base); + release: + release_mem_region(res->start, resource_size(res)); + return ret; +} + +static void flexcan_device_detach(struct flexcan_device *flexcan) +{ + struct platform_device *pdev = flexcan->dev; + struct flexcan_platform_data *plat_data = pdev->dev.platform_data; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + BUG_ON(!res); + + clk_put(flexcan->clk); + + if (flexcan->io_reg) { + regulator_put(flexcan->io_reg); + } + + if (flexcan->core_reg) { + regulator_put(flexcan->core_reg); + } + + if (plat_data && plat_data->inactive) + plat_data->inactive(pdev); + + iounmap(flexcan->io_base); + release_mem_region(res->start, resource_size(res)); +} + +static void flexcan_mbm_isr(struct work_struct *work); +static void flexcan_err_handler(struct work_struct *work); + +static struct net_device *flexcan_device_alloc(struct platform_device *pdev, + void (*setup)(struct net_device *dev)) +{ + struct flexcan_device *flexcan; + struct net_device *net; + int i, num; + int ret; + + net = alloc_netdev(sizeof(*flexcan), "can%d", setup); + if (net == NULL) { + pdev_err(pdev, "Failed to allocate netdevice\n"); + return ERR_PTR(-ENOMEM); + } + flexcan = netdev_priv(net); + + init_timer(&flexcan->timer); + mutex_init(&flexcan->mutex); + INIT_WORK(&flexcan->mb_work, flexcan_mbm_isr); + INIT_WORK(&flexcan->err_work, flexcan_err_handler); + + flexcan->dev = pdev; + ret = flexcan_device_attach(flexcan); + if (ret) { + free_netdev(net); + return ERR_PTR(ret); + } + flexcan_device_default(flexcan); + flexcan_update_bitrate(flexcan); + + num = ARRAY_SIZE(flexcan_dev_attr); + + for (i = 0; i < num; i++) { + ret = device_create_file(&pdev->dev, flexcan_dev_attr + i); + if (ret) { + pdev_err(pdev, "Failed to create attribute file %s: %d\n", + (flexcan_dev_attr + i)->attr.name, ret); + for (i--; i >= 0; i--) + device_remove_file(&pdev->dev, flexcan_dev_attr + i); + flexcan_device_detach(flexcan); + free_netdev(net); + return ERR_PTR(ret); + } + } + platform_set_drvdata(pdev, net); + return net; +} + +static void flexcan_device_free(struct net_device *dev) +{ + struct flexcan_device *flexcan = netdev_priv(dev); + struct platform_device *pdev = flexcan->dev; + int i; + + ndev_dbg(dev, 0, "%s: Deleting timer\n", __FUNCTION__); + del_timer_sync(&flexcan->timer); + + ndev_dbg(dev, 0, "%s: Removing sysfs files\n", __FUNCTION__); + for (i = 0; i < ARRAY_SIZE(flexcan_dev_attr); i++) + device_remove_file(&pdev->dev, flexcan_dev_attr + i); + + ndev_dbg(dev, 0, "%s: Detaching can device\n", __FUNCTION__); + flexcan_device_detach(flexcan); + ndev_dbg(dev, 0, "%s: Freeing net_device\n", __FUNCTION__); + free_netdev(dev); +} + +#define flexcan_swab32(x) \ + (((x) << 24) | ((x) >> 24) | \ + (((x) & (__u32)0x0000ff00UL) << 8) | \ + (((x) & (__u32)0x00ff0000UL) >> 8)) + +static inline void flexcan_mb_write(struct can_frame *frame, struct can_hw_mb __iomem *hwmb, + int code) +{ + int i; + unsigned long __iomem *s = (unsigned long *)&frame->data[0]; + unsigned long __iomem *d = (unsigned long *)&hwmb->mb_data[0]; + struct can_hw_mb mb; + unsigned int can_id; + int n_words = (frame->can_dlc + 3) / sizeof(unsigned int); + + mb.mb_cs.data = 0; + mb.mb_cs.cs.code = code; + mb.mb_cs.cs.length = frame->can_dlc; + + mb.mb_cs.cs.rtr = !!(frame->can_id & CAN_RTR_FLAG); + + if (frame->can_id & CAN_EFF_FLAG) { + mb.mb_cs.cs.ide = 1; + mb.mb_cs.cs.srr = 1; + can_id = frame->can_id & CAN_EFF_MASK; + } else { + mb.mb_cs.cs.ide = 0; + can_id = (frame->can_id & CAN_SFF_MASK) << 18; + } + + DBG(0, "%s: writing can_id %08x to mb_id %p\n", __FUNCTION__, can_id, &hwmb->mb_id); + __raw_writel(can_id, &hwmb->mb_id); + for (i = 0; i < n_words; i++, s++, d++) { + DBG(0, "%s: writing data %08lx to mb_data %p\n", __FUNCTION__, + flexcan_swab32(*s), d); + __raw_writel(flexcan_swab32(*s), d); + } + DBG(0, "%s: Writing CS %08x to mb_cs %p\n", __FUNCTION__, mb.mb_cs.data, &hwmb->mb_cs); + __raw_writel(mb.mb_cs.data, &hwmb->mb_cs.data); +} + +static inline void flexcan_mb_read(struct can_frame *frame, struct can_hw_mb __iomem *hwmb) +{ + int i; + unsigned long __iomem *s = (unsigned long *)&hwmb->mb_data[0]; + unsigned long __iomem *d = (unsigned long *)&frame->data[0]; + struct can_hw_mb mb; + unsigned int can_id; + int n_words; + + mb.mb_cs.data = __raw_readl(&hwmb->mb_cs); + BUG_ON(mb.mb_cs.cs.code & CAN_MB_RX_BUSY); + + can_id = __raw_readl(&hwmb->mb_id); + + if (mb.mb_cs.cs.ide) + frame->can_id = (can_id & CAN_EFF_MASK) | CAN_EFF_FLAG; + else + frame->can_id = (can_id >> 18) & CAN_SFF_MASK; + if (mb.mb_cs.cs.rtr) + frame->can_id |= CAN_RTR_FLAG; + + frame->can_dlc = mb.mb_cs.cs.length; + if (frame->can_dlc == 0 || frame->can_dlc > 8) + return; + + n_words = (frame->can_dlc + 3) / sizeof(unsigned int); + for (i = 0; i < n_words; i++, s++, d++) + *d = flexcan_swab32(__raw_readl(s)); +} + +static inline void flexcan_memcpy(void *dst, void *src, int len) +{ + int i; + unsigned int __iomem *d = dst, *s = src; + + DBG(2, "%s: Copying %u byte from %p to %p\n", __FUNCTION__, len, s, d); + WARN_ON(len & 3); + len = (len + 3) >> 2; + for (i = 0; i < len; i++, s++, d++) + __raw_writel(flexcan_swab32(*s), d); + if (dbg_lvl(1)) { + print_hex_dump(KERN_DEBUG, "swdat: ", DUMP_PREFIX_OFFSET, 16, 4, + src, len << 2, 0); + print_hex_dump(KERN_DEBUG, "hwdat: ", DUMP_PREFIX_OFFSET, 16, 4, + dst, len << 2, 0); + } +} + +static inline struct can_frame *flexcan_skb_put(struct sk_buff *skb, unsigned int len) +{ + return (struct can_frame *)skb_put(skb, len); +} + +static inline struct can_frame *flexcan_skb_data(struct sk_buff *skb) +{ + BUG_ON(skb == NULL); + return (struct can_frame *)skb->data; +} + +static struct net_device_stats *flexcan_get_stats(struct net_device *dev) +{ + ndev_dbg(dev, 3, "%s@%d: \n", __FUNCTION__, __LINE__); + if (!netif_running(dev)) + return &dev->stats; + ndev_dbg(dev, 3, "%s@%d: \n", __FUNCTION__, __LINE__); + return &dev->stats; +} + +static void flexcan_mb_bottom(struct net_device *dev, int index) +{ + struct flexcan_device *flexcan = netdev_priv(dev); + struct net_device_stats *stats = flexcan_get_stats(dev); + struct can_hw_mb __iomem *hwmb; + struct can_frame *frame; + struct sk_buff *skb; + struct can_hw_mb mb; + + ndev_dbg(dev, 1, "%s: index: %d\n", __FUNCTION__, index); + + hwmb = flexcan->hwmb + index; + mb.mb_cs.data = __raw_readl(&hwmb->mb_cs.data); + if (flexcan->fifo || + index >= flexcan->maxmb - flexcan->xmit_maxmb) { + /* handle transmit MBs */ + + if (mb.mb_cs.cs.code == CAN_MB_TX_ABORT) { + mb.mb_cs.cs.code = CAN_MB_TX_INACTIVE; + __raw_writel(mb.mb_cs.data, &hwmb->mb_cs.data); + } + if (mb.mb_cs.cs.code & CAN_MB_TX_INACTIVE) { + if (flexcan->xmit_buffers++ == 0) { + ndev_dbg(dev, 1, "%s: Starting netif queue\n", __FUNCTION__); + netif_start_queue(dev); + } + BUG_ON(flexcan->xmit_buffers > flexcan->maxmb - flexcan->xmit_maxmb); + return; + } + /* if fifo is enabled all RX MBs should be handled in the fifo_isr */ + BUG(); + } + if (dbg_lvl(1)) + print_hex_dump(KERN_DEBUG, "rx_mb: ", DUMP_PREFIX_OFFSET, 16, 4, + hwmb, sizeof(*hwmb), 0); + /* handle RX MB in case fifo is not used */ + BUG_ON(flexcan->fifo); + if (mb.mb_cs.cs.code & CAN_MB_RX_BUSY) { + ndev_dbg(dev, -1, "%s: MB[%02x] is busy: %x\n", __FUNCTION__, + index, mb.mb_cs.cs.code); + /* unlock buffer */ + (void)flexcan_reg_read(flexcan, CAN_HW_REG_TIMER); + return; + } + + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (skb) { + frame = flexcan_skb_put(skb, sizeof(*frame)); + flexcan_mb_read(frame, hwmb); + /* unlock buffer */ + (void)flexcan_reg_read(flexcan, CAN_HW_REG_TIMER); + + dev->last_rx = jiffies; + stats->rx_packets++; + stats->rx_bytes += frame->can_dlc; + + skb->dev = dev; + skb->protocol = __constant_htons(ETH_P_CAN); + skb->ip_summed = CHECKSUM_UNNECESSARY; + netif_receive_skb(skb); + } else { + flexcan_dbg(flexcan, 0, "%s: Could not allocate SKB; dropping packet\n", + __FUNCTION__); + + stats->rx_dropped++; + } +} + +static void flexcan_fifo_isr(struct net_device *dev, unsigned int iflag1) +{ + struct flexcan_device *flexcan = netdev_priv(dev); + struct net_device_stats *stats = flexcan_get_stats(dev); + struct sk_buff *skb; + struct can_hw_mb __iomem *hwmb = flexcan->hwmb; + struct can_frame *frame; + + ndev_dbg(dev, 2, "%s: \n", __FUNCTION__); + if (dbg_lvl(1)) + print_hex_dump(KERN_DEBUG, "rx_mb: ", DUMP_PREFIX_OFFSET, 16, 4, + hwmb, sizeof(*hwmb), 0); + if (iflag1 & __FIFO_RDY_INT) { + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (skb) { + frame = flexcan_skb_put(skb, sizeof(*frame)); + flexcan_mb_read(frame, hwmb); + /* unlock mb */ + (void) flexcan_reg_read(flexcan, CAN_HW_REG_TIMER); + + dev->last_rx = jiffies; + + stats->rx_packets++; + stats->rx_bytes += frame->can_dlc; + + skb->dev = dev; + skb->protocol = __constant_htons(ETH_P_CAN); + skb->ip_summed = CHECKSUM_UNNECESSARY; + netif_receive_skb(skb); + } else { + (void)__raw_readl(&hwmb->mb_cs.data); + /* unlock mb */ + (void) flexcan_reg_read(flexcan, CAN_HW_REG_TIMER); + } + } + + if (iflag1 & (__FIFO_OV_INT | __FIFO_WARN_INT)) { + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (skb) { + frame = flexcan_skb_put(skb, sizeof(*frame)); + frame->can_id = CAN_ERR_FLAG | CAN_ERR_CRTL; + frame->can_dlc = CAN_ERR_DLC; + if (iflag1 & __FIFO_WARN_INT) + frame->data[1] |= + CAN_ERR_CRTL_TX_WARNING | + CAN_ERR_CRTL_RX_WARNING; + if (iflag1 & __FIFO_OV_INT) + frame->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; + if (dbg_lvl(1)) + print_hex_dump(KERN_DEBUG, "err_mb: ", DUMP_PREFIX_OFFSET, 16, 4, + frame, sizeof(*frame), 0); + + skb->dev = dev; + skb->protocol = __constant_htons(ETH_P_CAN); + skb->ip_summed = CHECKSUM_UNNECESSARY; + netif_receive_skb(skb); + } + } +} + +/* + * called by CAN ISR to handle mb events. + */ +static void flexcan_mbm_isr(struct work_struct *work) +{ + struct flexcan_device *flexcan = container_of(work, struct flexcan_device, mb_work); + struct net_device *dev = platform_get_drvdata(flexcan->dev); + int i, iflag1, iflag2, maxmb; + + i = 0; + + ndev_dbg(dev, 2, "%s: \n", __FUNCTION__); + + iflag1 = flexcan_reg_read(flexcan, CAN_HW_REG_IFLAG1) & + flexcan_reg_read(flexcan, CAN_HW_REG_IMASK1); + if (flexcan->maxmb > 31) { + maxmb = flexcan->maxmb + 1 - 32; + iflag2 = flexcan_reg_read(flexcan, CAN_HW_REG_IFLAG2) & + flexcan_reg_read(flexcan, CAN_HW_REG_IMASK2); + iflag2 &= (1 << maxmb) - 1; + maxmb = 32; + } else { + maxmb = flexcan->maxmb + 1; + iflag1 &= (1 << maxmb) - 1; + iflag2 = 0; + } + + ndev_dbg(dev, 2, "%s: loop=%d iflag1=%08x\n", __FUNCTION__, i, iflag1); + + flexcan_reg_write(flexcan, CAN_HW_REG_IFLAG1, iflag1); + flexcan_reg_write(flexcan, CAN_HW_REG_IFLAG2, iflag2); + + if (flexcan->fifo) { + flexcan_fifo_isr(dev, iflag1); + iflag1 &= ~0xFF; + } + for (i = 0; iflag1 && (i < maxmb); i++) { + if (iflag1 & (1 << i)) { + iflag1 &= ~(1 << i); + flexcan_mb_bottom(dev, i); + } + } + + for (i = maxmb; iflag2 && (i <= flexcan->maxmb); i++) { + if (iflag2 & (1 << (i - 32))) { + iflag2 &= ~(1 << (i - 32)); + flexcan_mb_bottom(dev, i); + } + } + enable_irq(flexcan->irq); +} + +static int flexcan_mbm_xmit(struct flexcan_device *flexcan, struct can_frame *frame) +{ + int i = flexcan->xmit_mb; + struct can_hw_mb __iomem *hwmb = flexcan->hwmb; + static int last; + + if (flexcan->xmit_buffers != last) { + flexcan_dbg(flexcan, 1, "%s: %d free buffers\n", __FUNCTION__, + flexcan->xmit_buffers); + last = flexcan->xmit_buffers; + } + do { + struct can_hw_mb mb; + + mb.mb_cs.data = __raw_readl(&hwmb[i].mb_cs); + + if (mb.mb_cs.cs.code == CAN_MB_TX_INACTIVE) + break; + if (++i > flexcan->maxmb) { + if (flexcan->fifo) + i = FLEXCAN_MAX_FIFO_MB; + else + i = flexcan->xmit_maxmb + 1; + } + if (i == flexcan->xmit_mb) { + flexcan_dbg(flexcan, 0, "%s: no free xmit buffer\n", __FUNCTION__); + return 0; + } + } while (1); + + flexcan->xmit_mb = i + 1; + if (flexcan->xmit_mb > flexcan->maxmb) { + if (flexcan->fifo) + flexcan->xmit_mb = FLEXCAN_MAX_FIFO_MB; + else + flexcan->xmit_mb = flexcan->xmit_maxmb + 1; + } + + flexcan_dbg(flexcan, 1, "%s: Enabling transmission of buffer %d\n", __FUNCTION__, i); + flexcan_mb_write(frame, &hwmb[i], CAN_MB_TX_ONCE); + + if (dbg_lvl(1)) + print_hex_dump(KERN_DEBUG, "tx_mb: ", DUMP_PREFIX_OFFSET, 16, 4, + &hwmb[i], sizeof(*hwmb), 0); + return 1; +} + +static void flexcan_mbm_init(struct flexcan_device *flexcan) +{ + struct can_hw_mb __iomem *hwmb; + int rx_mb, i; + + flexcan_dbg(flexcan, 0, "%s@%d: \n", __FUNCTION__, __LINE__); + + /* Set global mask to receive all messages */ + flexcan_reg_write(flexcan, CAN_HW_REG_RXGMASK, 0); + flexcan_reg_write(flexcan, CAN_HW_REG_RX14MASK, 0); + flexcan_reg_write(flexcan, CAN_HW_REG_RX15MASK, 0); + + for (i = 0; i < FLEXCAN_MAX_MB; i++) { + int j; + void __iomem *mb = &flexcan->hwmb[i]; + void __iomem *rxm = &flexcan->rx_mask[i]; + + __raw_writel(0, rxm); + for (j = 0; j < sizeof(*flexcan->hwmb); j += 4) { + __raw_writel(0, mb + j); + } + } + + if (flexcan->fifo) + rx_mb = FLEXCAN_MAX_FIFO_MB; + else + rx_mb = flexcan->maxmb - flexcan->xmit_maxmb; + + hwmb = flexcan->hwmb; + if (flexcan->fifo) { + unsigned long *id_table = flexcan->io_base + CAN_FIFO_BASE; + for (i = 0; i < rx_mb; i++) + __raw_writel(0, &id_table[i]); + } else { + for (i = 0; i < rx_mb; i++) { + struct can_hw_mb mb; + + mb.mb_cs.data = 0; + mb.mb_cs.cs.code = CAN_MB_RX_EMPTY; + if (flexcan->ext_msg && flexcan->std_msg) + mb.mb_cs.cs.ide = i & 1; + else if (flexcan->ext_msg) + mb.mb_cs.cs.ide = 1; + + __raw_writel(mb.mb_cs.data, &hwmb[i]); + } + } + + for (; i <= flexcan->maxmb; i++) { + struct can_hw_mb mb; + + mb.mb_cs.data = 0; + mb.mb_cs.cs.code = CAN_MB_TX_INACTIVE; + __raw_writel(mb.mb_cs.data, &hwmb[i]); + } + + flexcan->xmit_mb = rx_mb; + flexcan->xmit_buffers = flexcan->maxmb - flexcan->xmit_maxmb; +} + +static void flexcan_hw_start(struct flexcan_device *flexcan) +{ + unsigned int reg; + + flexcan_dbg(flexcan, 0, "%s: \n", __FUNCTION__); + + if ((flexcan->maxmb + 1) > 32) { + flexcan_reg_write(flexcan, CAN_HW_REG_IMASK1, ~0); + reg = (1 << (flexcan->maxmb - 31)) - 1; + flexcan_reg_write(flexcan, CAN_HW_REG_IMASK2, reg); + } else { + reg = (1 << (flexcan->maxmb + 1)) - 1; + flexcan_reg_write(flexcan, CAN_HW_REG_IMASK1, reg); + flexcan_reg_write(flexcan, CAN_HW_REG_IMASK2, 0); + } + + reg = flexcan_reg_read(flexcan, CAN_HW_REG_MCR); + flexcan_reg_write(flexcan, CAN_HW_REG_MCR, reg & ~__MCR_HALT); +} + +static void flexcan_hw_stop(struct flexcan_device *flexcan) +{ + unsigned int reg; + + flexcan_dbg(flexcan, 0, "%s: \n", __FUNCTION__); + + reg = flexcan_reg_read(flexcan, CAN_HW_REG_MCR); + flexcan_reg_write(flexcan, CAN_HW_REG_MCR, reg | __MCR_HALT); +} + +static int flexcan_hw_reset(struct flexcan_device *flexcan) +{ + struct platform_device *pdev __attribute__((unused)) = flexcan->dev; + unsigned int reg; + int timeout = 100000; + + flexcan_dbg(flexcan, 0, "%s: \n", __FUNCTION__); + + reg = flexcan_reg_read(flexcan, CAN_HW_REG_MCR); + flexcan_reg_write(flexcan, CAN_HW_REG_MCR, reg | __MCR_MDIS); + + reg = flexcan_reg_read(flexcan, CAN_HW_REG_CTRL); + if (flexcan->br_clksrc) + reg |= __CTRL_CLK_SRC; + else + reg &= ~__CTRL_CLK_SRC; + flexcan_reg_write(flexcan, CAN_HW_REG_CTRL, reg); + + reg = flexcan_reg_read(flexcan, CAN_HW_REG_MCR) & ~__MCR_MDIS; + flexcan_reg_write(flexcan, CAN_HW_REG_MCR, reg); + reg |= __MCR_SOFT_RST; + flexcan_reg_write(flexcan, CAN_HW_REG_MCR, reg); + + reg = flexcan_reg_read(flexcan, CAN_HW_REG_MCR); + while (reg & __MCR_SOFT_RST) { + if (--timeout <= 0) { + dev_err(&pdev->dev, "Flexcan software Reset Timeout\n"); + return -ETIME; + } + udelay(10); + reg = flexcan_reg_read(flexcan, CAN_HW_REG_MCR); + } + return 0; +} + +static void flexcan_mcr_setup(struct flexcan_device *flexcan) +{ + unsigned int reg; + + flexcan_dbg(flexcan, 0, "%s: \n", __FUNCTION__); + + reg = flexcan_reg_read(flexcan, CAN_HW_REG_MCR); + reg &= ~(__MCR_MAX_MB_MASK | __MCR_WAK_MSK | __MCR_MAX_IDAM_MASK); + + if (flexcan->fifo) + reg |= __MCR_FEN; + else + reg &= ~__MCR_FEN; + + if (flexcan->wakeup) + reg |= __MCR_SLF_WAK | __MCR_WAK_MSK; + else + reg &= ~(__MCR_SLF_WAK | __MCR_WAK_MSK); + + if (flexcan->wak_src) + reg |= __MCR_WAK_SRC; + else + reg &= ~__MCR_WAK_SRC; + + if (flexcan->srx_dis) + reg |= __MCR_SRX_DIS; + else + reg &= ~__MCR_SRX_DIS; + + if (flexcan->bcc) + reg |= __MCR_BCC; + else + reg &= ~__MCR_BCC; + + if (flexcan->lprio) + reg |= __MCR_LPRIO_EN; + else + reg &= ~__MCR_LPRIO_EN; + + if (flexcan->abort) + reg |= __MCR_AEN; + else + reg &= ~__MCR_AEN; + + reg |= (flexcan->maxmb << __MCR_MAX_MB_OFFSET); + reg |= __MCR_DOZE | __MCR_MAX_IDAM_C; + flexcan_reg_write(flexcan, CAN_HW_REG_MCR, reg); +} + +static void flexcan_ctrl_setup(struct flexcan_device *flexcan) +{ + unsigned int reg; + + flexcan_dbg(flexcan, 0, "%s: \n", __FUNCTION__); + + reg = flexcan_reg_read(flexcan, CAN_HW_REG_CTRL); + reg &= ~(__CTRL_PRESDIV_MASK | __CTRL_RJW_MASK | __CTRL_PSEG1_MASK | + __CTRL_PSEG2_MASK | __CTRL_PROPSEG_MASK); + + if (flexcan->loopback) + reg |= __CTRL_LPB; + else + reg &= ~__CTRL_LPB; + + if (flexcan->smp) + reg |= __CTRL_SMP; + else + reg &= ~__CTRL_SMP; + + if (flexcan->boff_rec) + reg |= __CTRL_BOFF_REC; + else + reg &= ~__CTRL_BOFF_REC; + + if (flexcan->tsyn) + reg |= __CTRL_TSYN; + else + reg &= ~__CTRL_TSYN; + + if (flexcan->listen) + reg |= __CTRL_LOM; + else + reg &= ~__CTRL_LOM; + + reg |= (flexcan->br_presdiv << __CTRL_PRESDIV_OFFSET) | + (flexcan->br_rjw << __CTRL_RJW_OFFSET) | + (flexcan->br_pseg1 << __CTRL_PSEG1_OFFSET) | + (flexcan->br_pseg2 << __CTRL_PSEG2_OFFSET) | + (flexcan->br_propseg << __CTRL_PROPSEG_OFFSET); + + reg &= ~__CTRL_LBUF; + + reg |= __CTRL_TWRN_MSK | __CTRL_RWRN_MSK | __CTRL_BOFF_MSK | + __CTRL_ERR_MSK; + + flexcan_reg_write(flexcan, CAN_HW_REG_CTRL, reg); +} + +static int flexcan_hw_restart(struct net_device *dev) +{ + unsigned int reg; + struct flexcan_device *flexcan = netdev_priv(dev); + + ndev_dbg(dev, 0, "%s: \n", __FUNCTION__); + + reg = flexcan_reg_read(flexcan, CAN_HW_REG_MCR); + if (reg & __MCR_SOFT_RST) + return 1; + + flexcan_mcr_setup(flexcan); + + flexcan_reg_write(flexcan, CAN_HW_REG_IMASK2, 0); + flexcan_reg_write(flexcan, CAN_HW_REG_IMASK1, 0); + + flexcan_reg_write(flexcan, CAN_HW_REG_IFLAG2, 0xFFFFFFFF); + flexcan_reg_write(flexcan, CAN_HW_REG_IFLAG1, 0xFFFFFFFF); + + flexcan_reg_write(flexcan, CAN_HW_REG_ECR, 0); + + flexcan_mbm_init(flexcan); + netif_carrier_on(dev); + flexcan_hw_start(flexcan); + + if (netif_queue_stopped(dev)) { + ndev_dbg(dev, 1, "%s@%d: Starting netif queue\n", + __FUNCTION__, __LINE__); + netif_start_queue(dev); + } + return 0; +} + +static void flexcan_hw_watch(unsigned long data) +{ + unsigned int reg, ecr; + struct net_device *dev = (struct net_device *)data; + struct flexcan_device *flexcan = netdev_priv(dev); + + ndev_dbg(dev, 1, "%s: \n", __FUNCTION__); + + reg = flexcan_reg_read(flexcan, CAN_HW_REG_MCR); + if (reg & __MCR_MDIS) { + if (flexcan_hw_restart(dev)) + mod_timer(&flexcan->timer, HZ / 20); + return; + } + ecr = flexcan_reg_read(flexcan, CAN_HW_REG_ECR); + if (flexcan->boff_rec) { + if (((reg & __ESR_FLT_CONF_MASK) >> __ESR_FLT_CONF_OFF) > 1) { + reg |= __MCR_SOFT_RST; + ndev_dbg(dev, 1, "%s: Initiating soft reset\n", __FUNCTION__); + flexcan_reg_write(flexcan, CAN_HW_REG_MCR, reg); + mod_timer(&flexcan->timer, HZ / 20); + return; + } + netif_carrier_on(dev); + } + ndev_dbg(dev, 1, "%s: Done\n", __FUNCTION__); +} + +static void flexcan_hw_busoff(struct net_device *dev) +{ + struct flexcan_device *flexcan = netdev_priv(dev); + unsigned int reg; + + netif_carrier_off(dev); + + flexcan->timer.function = flexcan_hw_watch; + flexcan->timer.data = (unsigned long)dev; + + if (flexcan->boff_rec) { + mod_timer(&flexcan->timer, HZ / 10); + return; + } + reg = flexcan_reg_read(flexcan, CAN_HW_REG_MCR); + flexcan_reg_write(flexcan, CAN_HW_REG_MCR, reg | __MCR_SOFT_RST); + mod_timer(&flexcan->timer, HZ / 20); +} + +static int flexcan_hw_open(struct flexcan_device *flexcan) +{ + int ret; + + if ((ret = flexcan_hw_reset(flexcan)) != 0) + return ret; + + flexcan_mcr_setup(flexcan); + flexcan_ctrl_setup(flexcan); + + flexcan_reg_write(flexcan, CAN_HW_REG_IMASK2, 0); + flexcan_reg_write(flexcan, CAN_HW_REG_IMASK1, 0); + + flexcan_reg_write(flexcan, CAN_HW_REG_IFLAG2, 0xFFFFFFFF); + flexcan_reg_write(flexcan, CAN_HW_REG_IFLAG1, 0xFFFFFFFF); + + flexcan_reg_write(flexcan, CAN_HW_REG_ECR, 0); + return 0; +} + +static void flexcan_err_handler(struct work_struct *work) +{ + struct flexcan_device *flexcan = container_of(work, struct flexcan_device, err_work); + struct net_device *dev = platform_get_drvdata(flexcan->dev); + struct sk_buff *skb; + struct can_frame *frame; + unsigned int esr, ecr; + + ndev_dbg(dev, 1, "%s@%d: \n", __FUNCTION__, __LINE__); + + esr = flexcan_reg_read(flexcan, CAN_HW_REG_ESR); + flexcan_reg_write(flexcan, CAN_HW_REG_ESR, esr & __ESR_INTERRUPTS); + enable_irq(flexcan->irq); + + if (esr & __ESR_WAK_INT) { + ndev_dbg(dev, 0, "%s@%d: \n", __FUNCTION__, __LINE__); + return; + } + + skb = dev_alloc_skb(sizeof(struct can_frame)); + if (!skb) { + ndev_err(dev, "%s: Failed to allocate skb\n", __func__); + return; + } + frame = flexcan_skb_put(skb, sizeof(*frame)); + frame->can_id = CAN_ERR_FLAG | CAN_ERR_CRTL; + frame->can_dlc = CAN_ERR_DLC; + + if (esr & __ESR_TWRN_INT) { + ndev_err(dev, "%s: TX_WARNING\n", __FUNCTION__); + frame->data[1] |= CAN_ERR_CRTL_TX_WARNING; + } + if (esr & __ESR_RWRN_INT) { + ndev_err(dev, "%s: RX_WARNING\n", __FUNCTION__); + frame->data[1] |= CAN_ERR_CRTL_RX_WARNING; + } + if (esr & __ESR_BOFF_INT) { + ndev_err(dev, "%s: BUS_OFF\n", __FUNCTION__); + frame->can_id |= CAN_ERR_BUSOFF; + } + if (esr & __ESR_ERR_INT) { + ndev_dbg(dev, 1, "%s@%d: \n", __FUNCTION__, __LINE__); + if (esr & __ESR_BIT1_ERR) { + ndev_err(dev, "%s: BIT1_ERR\n", __FUNCTION__); + frame->data[2] |= CAN_ERR_PROT_BIT1; + } + + if (esr & __ESR_BIT0_ERR) { + ndev_err(dev, "%s: BIT0_ERR\n", __FUNCTION__); + frame->data[2] |= CAN_ERR_PROT_BIT0; + } + + if (esr & __ESR_ACK_ERR) { + ndev_err(dev, "%s: ACK_ERR\n", __FUNCTION__); + frame->can_id |= CAN_ERR_ACK; + } + + /*TODO:// if (esr & __ESR_CRC_ERR) */ + + if (esr & __ESR_FRM_ERR) { + ndev_err(dev, "%s: FRM_ERR\n", __FUNCTION__); + frame->data[2] |= CAN_ERR_PROT_FORM; + } + + if (esr & __ESR_STF_ERR) { + ndev_err(dev, "%s: STF_ERR\n", __FUNCTION__); + frame->data[2] |= CAN_ERR_PROT_STUFF; + } + + ecr = flexcan_reg_read(flexcan, CAN_HW_REG_ECR); + switch ((esr & __ESR_FLT_CONF_MASK) >> __ESR_FLT_CONF_OFF) { + case 0: + ndev_dbg(dev, 0, "%s@%d: \n", __FUNCTION__, __LINE__); + if (__ECR_TX_ERR_COUNTER(ecr) >= __ECR_ACTIVE_THRESHOLD) + frame->data[1] |= CAN_ERR_CRTL_TX_WARNING; + if (__ECR_RX_ERR_COUNTER(ecr) >= __ECR_ACTIVE_THRESHOLD) + frame->data[1] |= CAN_ERR_CRTL_RX_WARNING; + break; + case 1: + ndev_dbg(dev, 0, "%s@%d: \n", __FUNCTION__, __LINE__); + if (__ECR_TX_ERR_COUNTER(ecr) >= + __ECR_PASSIVE_THRESHOLD) + frame->data[1] |= CAN_ERR_CRTL_TX_PASSIVE; + + if (__ECR_RX_ERR_COUNTER(ecr) >= + __ECR_PASSIVE_THRESHOLD) + frame->data[1] |= CAN_ERR_CRTL_RX_PASSIVE; + break; + default: + ndev_dbg(dev, 0, "%s@%d: \n", __FUNCTION__, __LINE__); + frame->can_id |= CAN_ERR_BUSOFF; + } + } + + if (frame->can_id & CAN_ERR_BUSOFF) { + ndev_dbg(dev, 0, "%s: switchung bus off\n", __FUNCTION__); + flexcan_hw_busoff(dev); + } + skb->dev = dev; + skb->ip_summed = CHECKSUM_UNNECESSARY; + netif_receive_skb(skb); +} + +static irqreturn_t flexcan_irq_handler(int irq, void *data) +{ + struct net_device *dev = data; + struct flexcan_device *flexcan = netdev_priv(dev); + unsigned int reg; + + ndev_dbg(dev, 1, "%s: \n", __FUNCTION__); + disable_irq_nosync(irq); + + reg = flexcan_reg_read(flexcan, CAN_HW_REG_ESR); + if (reg & __ESR_INTERRUPTS) { + ndev_dbg(dev, 1, "%s: Scheduling err handler\n", __FUNCTION__); + schedule_work(&flexcan->err_work); + return IRQ_HANDLED; + } + + ndev_dbg(dev, 1, "%s: Scheduling mbm handler\n", __FUNCTION__); + schedule_work(&flexcan->mb_work); + return IRQ_HANDLED; +} + +static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct can_frame *frame = flexcan_skb_data(skb); + struct flexcan_device *flexcan = netdev_priv(dev); + struct net_device_stats *stats = flexcan_get_stats(dev); + + ndev_dbg(dev, 1, "%s: \n", __FUNCTION__); + + if (frame->can_dlc > 8) + return -EINVAL; + + if (flexcan_mbm_xmit(flexcan, frame)) { + dev_kfree_skb(skb); + stats->tx_bytes += frame->can_dlc; + stats->tx_packets++; + dev->trans_start = jiffies; + if (--flexcan->xmit_buffers == 0) { + ndev_dbg(dev, 1, "%s: Stopping netif queue\n", __FUNCTION__); + netif_stop_queue(dev); + } + BUG_ON(flexcan->xmit_buffers < 0); + return NETDEV_TX_OK; + } + ndev_dbg(dev, 1, "%s: could not transmit message\n", __FUNCTION__); + return NETDEV_TX_BUSY; +} + +static int flexcan_open(struct net_device *dev) +{ + int ret; + struct flexcan_device *flexcan = netdev_priv(dev); + struct platform_device *pdev = flexcan->dev; + struct flexcan_platform_data *plat_data = pdev->dev.platform_data; + + ndev_dbg(dev, 0, "%s: \n", __FUNCTION__); + + ret = clk_enable(flexcan->clk); + if (ret) + goto clk_err; + + if (flexcan->core_reg) { + ret = regulator_enable(flexcan->core_reg); + if (ret) + goto core_reg_err; + } + + if (flexcan->io_reg) { + ret = regulator_enable(flexcan->io_reg); + if (ret) + goto io_reg_err; + } + + if (plat_data && plat_data->xcvr_enable) { + ret = plat_data->xcvr_enable(pdev, 1); + if (ret) + goto enable_err; + } + + ret = request_irq(flexcan->irq, flexcan_irq_handler, IRQF_SAMPLE_RANDOM, + dev->name, dev); + if (ret) + goto irq_err; + + ret = flexcan_hw_open(flexcan); + if (ret) + goto open_err; + + flexcan_mbm_init(flexcan); + netif_carrier_on(dev); + flexcan_hw_start(flexcan); + return 0; + + open_err: + free_irq(flexcan->irq, dev); + irq_err: + if (plat_data && plat_data->xcvr_enable) + plat_data->xcvr_enable(pdev, 0); + enable_err: + if (flexcan->io_reg) + regulator_disable(flexcan->io_reg); + io_reg_err: + if (flexcan->core_reg) + regulator_disable(flexcan->core_reg); + core_reg_err: + if (flexcan->clk) + clk_disable(flexcan->clk); + clk_err: + return ret; +} + +static int flexcan_stop(struct net_device *dev) +{ + struct flexcan_device *flexcan = netdev_priv(dev); + struct platform_device *pdev = flexcan->dev; + struct flexcan_platform_data *plat_data = pdev->dev.platform_data; + + flexcan_hw_stop(flexcan); + + free_irq(flexcan->irq, dev); + + if (plat_data && plat_data->xcvr_enable) + plat_data->xcvr_enable(pdev, 0); + + if (flexcan->io_reg) + regulator_disable(flexcan->io_reg); + if (flexcan->core_reg) + regulator_disable(flexcan->core_reg); + clk_disable(flexcan->clk); + return 0; +} + +static const struct net_device_ops flexcan_netdev_ops = { + .ndo_open = flexcan_open, + .ndo_stop = flexcan_stop, + .ndo_start_xmit = flexcan_start_xmit, + .ndo_get_stats = flexcan_get_stats, +}; + +static void flexcan_setup(struct net_device *dev) +{ + dev->type = ARPHRD_CAN; + dev->mtu = sizeof(struct can_frame); + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->tx_queue_len = FLEXCAN_MAX_MB; + dev->flags = IFF_NOARP; + dev->features = NETIF_F_NO_CSUM; + + dev->netdev_ops = &flexcan_netdev_ops; + dev->destructor = flexcan_device_free; +} + +static int flexcan_probe(struct platform_device *pdev) +{ + int ret; + struct net_device *net; + + net = flexcan_device_alloc(pdev, flexcan_setup); + if (IS_ERR(net)) + return PTR_ERR(net); + + ret = register_netdev(net); + if (ret) { + flexcan_device_free(net); + } + return ret; +} + +static int flexcan_remove(struct platform_device *pdev) +{ + struct net_device *net = platform_get_drvdata(pdev); + + unregister_netdev(net); + return 0; +} + +#ifdef CONFIG_PM +static int flexcan_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct net_device *net = platform_get_drvdata(pdev); + struct flexcan_device *flexcan = netdev_priv(net); + struct flexcan_platform_data *plat_data; + + if (!(net->flags & IFF_UP)) + return 0; + + if (flexcan->wakeup) + set_irq_wake(flexcan->irq, 1); + else { + int ret; + + plat_data = pdev->dev.platform_data; + + if (plat_data && plat_data->xcvr_enable) { + ret = plat_data->xcvr_enable(pdev, 0); + if (ret) + return ret; + } + if (flexcan->io_reg) { + ret = regulator_disable(flexcan->io_reg); + if (ret) + return ret; + } + if (flexcan->core_reg) { + ret = regulator_disable(flexcan->core_reg); + if (ret) + return ret; + } + clk_disable(flexcan->clk); + if (plat_data && plat_data->inactive) { + plat_data->inactive(pdev); + } + } + return 0; +} + +static int flexcan_resume(struct platform_device *pdev) +{ + int ret; + struct net_device *net = platform_get_drvdata(pdev); + struct flexcan_device *flexcan = netdev_priv(net); + struct flexcan_platform_data *plat_data; + + if (!(net->flags & IFF_UP)) + return 0; + + if (flexcan->wakeup) + set_irq_wake(flexcan->irq, 0); + else { + plat_data = pdev->dev.platform_data; + if (plat_data && plat_data->active) { + ret = plat_data->active(pdev); + if (ret) + printk(KERN_ERR "%s: Failed activate hardware: %d\n", + __func__, ret); + } + ret = clk_enable(flexcan->clk); + if (ret) + printk(KERN_ERR "%s: Failed to enable clock: %d\n", + __func__, ret); + + if (flexcan->core_reg) { + ret = regulator_enable(flexcan->core_reg); + if (ret) + printk(KERN_ERR "%s: Failed to enable core voltage: %d\n", + __func__, ret); + } + if (flexcan->io_reg) { + ret = regulator_enable(flexcan->io_reg); + if (ret) + printk(KERN_ERR "%s: Failed to enable io voltage: %d\n", + __func__, ret); + } + + if (plat_data && plat_data->xcvr_enable) { + ret = plat_data->xcvr_enable(pdev, 1); + if (ret) + printk(KERN_ERR "%s: Failed to enable transceiver: %d\n", + __func__, ret); + } + } + return 0; +} +#else +#define flexcan_suspend NULL +#define flexcan_resume NULL +#endif + +static struct platform_driver flexcan_driver = { + .driver = { + .name = "mxc-flexcan", + }, + .probe = flexcan_probe, + .remove = flexcan_remove, + .suspend = flexcan_suspend, + .resume = flexcan_resume, +}; + +static __init int flexcan_init(void) +{ + pr_info("Freescale FlexCAN Driver \n"); + return platform_driver_register(&flexcan_driver); +} + +static __exit void flexcan_exit(void) +{ + return platform_driver_unregister(&flexcan_driver); +} + +module_init(flexcan_init); +module_exit(flexcan_exit); + +MODULE_LICENSE("GPL"); diff -purN linux-2.6.30-rc4-git/drivers/net/can/flexcan.h linux-2.6.30-rc4-karo3/drivers/net/can/flexcan.h --- linux-2.6.30-rc4-git/drivers/net/can/flexcan.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/drivers/net/can/flexcan.h 2009-07-06 15:17:55.000000000 +0200 @@ -0,0 +1,214 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file flexcan.h + * + * @brief FlexCan definitions. + * + * @ingroup can + */ + +#ifndef __CAN_FLEXCAN_H__ +#define __CAN_FLEXCAN_H__ + +#include +#include +#include +#include +#include +#include +#include + +struct can_mb_cs { + unsigned int time_stamp:16; + unsigned int length:4; + unsigned int rtr:1; + unsigned int ide:1; + unsigned int srr:1; + unsigned int nouse1:1; + unsigned int code:4; + unsigned int nouse2:4; +}; + +#define CAN_MB_RX_INACTIVE 0x0 +#define CAN_MB_RX_EMPTY 0x4 +#define CAN_MB_RX_FULL 0x2 +#define CAN_MB_RX_OVERRUN 0x6 +#define CAN_MB_RX_BUSY 0x1 + +#define CAN_MB_TX_INACTIVE 0x8 +#define CAN_MB_TX_ABORT 0x9 +#define CAN_MB_TX_ONCE 0xC +#define CAN_MB_TX_REMOTE 0xA + +struct can_hw_mb { + union { + struct can_mb_cs cs; + unsigned int data; + } mb_cs; + unsigned int mb_id; + unsigned char mb_data[8]; +}; + +#define CAN_HW_REG_MCR 0x00 +#define CAN_HW_REG_CTRL 0x04 +#define CAN_HW_REG_TIMER 0x08 +#define CAN_HW_REG_RXGMASK 0x10 +#define CAN_HW_REG_RX14MASK 0x14 +#define CAN_HW_REG_RX15MASK 0x18 +#define CAN_HW_REG_ECR 0x1C +#define CAN_HW_REG_ESR 0x20 +#define CAN_HW_REG_IMASK2 0x24 +#define CAN_HW_REG_IMASK1 0x28 +#define CAN_HW_REG_IFLAG2 0x2C +#define CAN_HW_REG_IFLAG1 0x30 + +#define CAN_MB_BASE 0x0080 +#define CAN_RXMASK_BASE 0x0880 +#define CAN_FIFO_BASE 0xE0 + +#define __MCR_MDIS (1 << 31) +#define __MCR_FRZ (1 << 30) +#define __MCR_FEN (1 << 29) +#define __MCR_HALT (1 << 28) +#define __MCR_NOTRDY (1 << 27) +#define __MCR_WAK_MSK (1 << 26) +#define __MCR_SOFT_RST (1 << 25) +#define __MCR_FRZ_ACK (1 << 24) +#define __MCR_SLF_WAK (1 << 22) +#define __MCR_WRN_EN (1 << 21) +#define __MCR_LPM_ACK (1 << 20) +#define __MCR_WAK_SRC (1 << 19) +#define __MCR_DOZE (1 << 18) +#define __MCR_SRX_DIS (1 << 17) +#define __MCR_BCC (1 << 16) +#define __MCR_LPRIO_EN (1 << 13) +#define __MCR_AEN (1 << 12) +#define __MCR_MAX_IDAM_OFFSET 8 +#define __MCR_MAX_IDAM_MASK (0x3 << __MCR_MAX_IDAM_OFFSET) +#define __MCR_MAX_IDAM_A (0x0 << __MCR_MAX_IDAM_OFFSET) +#define __MCR_MAX_IDAM_B (0x1 << __MCR_MAX_IDAM_OFFSET) +#define __MCR_MAX_IDAM_C (0x2 << __MCR_MAX_IDAM_OFFSET) +#define __MCR_MAX_IDAM_D (0x3 << __MCR_MAX_IDAM_OFFSET) +#define __MCR_MAX_MB_OFFSET 0 +#define __MCR_MAX_MB_MASK (0x3F) + +#define __CTRL_PRESDIV_OFFSET 24 +#define __CTRL_PRESDIV_MASK (0xFF << __CTRL_PRESDIV_OFFSET) +#define __CTRL_RJW_OFFSET 22 +#define __CTRL_RJW_MASK (0x3 << __CTRL_RJW_OFFSET) +#define __CTRL_PSEG1_OFFSET 19 +#define __CTRL_PSEG1_MASK (0x7 << __CTRL_PSEG1_OFFSET) +#define __CTRL_PSEG2_OFFSET 16 +#define __CTRL_PSEG2_MASK (0x7 << __CTRL_PSEG2_OFFSET) +#define __CTRL_BOFF_MSK (0x1 << 15) +#define __CTRL_ERR_MSK (0x1 << 14) +#define __CTRL_CLK_SRC (0x1 << 13) +#define __CTRL_LPB (0x1 << 12) +#define __CTRL_TWRN_MSK (0x1 << 11) +#define __CTRL_RWRN_MSK (0x1 << 10) +#define __CTRL_SMP (0x1 << 7) +#define __CTRL_BOFF_REC (0x1 << 6) +#define __CTRL_TSYN (0x1 << 5) +#define __CTRL_LBUF (0x1 << 4) +#define __CTRL_LOM (0x1 << 3) +#define __CTRL_PROPSEG_OFFSET 0 +#define __CTRL_PROPSEG_MASK (0x7) + +#define __ECR_TX_ERR_COUNTER(x) ((x) & 0xFF) +#define __ECR_RX_ERR_COUNTER(x) (((x) >> 8) & 0xFF) +#define __ECR_PASSIVE_THRESHOLD 128 +#define __ECR_ACTIVE_THRESHOLD 96 + +#define __ESR_TWRN_INT (0x1 << 17) +#define __ESR_RWRN_INT (0x1 << 16) +#define __ESR_BIT1_ERR (0x1 << 15) +#define __ESR_BIT0_ERR (0x1 << 14) +#define __ESR_ACK_ERR (0x1 << 13) +#define __ESR_CRC_ERR (0x1 << 12) +#define __ESR_FRM_ERR (0x1 << 11) +#define __ESR_STF_ERR (0x1 << 10) +#define __ESR_TX_WRN (0x1 << 9) +#define __ESR_RX_WRN (0x1 << 8) +#define __ESR_IDLE (0x1 << 7) +#define __ESR_TXRX (0x1 << 6) +#define __ESR_FLT_CONF_OFF 4 +#define __ESR_FLT_CONF_MASK (0x3 << __ESR_FLT_CONF_OFF) +#define __ESR_BOFF_INT (0x1 << 2) +#define __ESR_ERR_INT (0x1 << 1) +#define __ESR_WAK_INT (0x1) + +#define __ESR_INTERRUPTS (__ESR_WAK_INT | __ESR_ERR_INT | \ + __ESR_BOFF_INT | __ESR_TWRN_INT | \ + __ESR_RWRN_INT) + +#define __FIFO_OV_INT (1 << 7) +#define __FIFO_WARN_INT (1 << 6) +#define __FIFO_RDY_INT (1 << 5) + +#define FLEXCAN_MAX_FIFO_MB 8 +#define FLEXCAN_MAX_MB 64 +#define FLEXCAN_MAX_PRESDIV 256 +#define FLEXCAN_MAX_RJW 4 +#define FLEXCAN_MAX_PSEG1 8 +#define FLEXCAN_MAX_PSEG2 8 +#define FLEXCAN_MAX_PROPSEG 8 +#define FLEXCAN_MAX_BITRATE 1000000 + +struct flexcan_device { + struct mutex mutex; + struct work_struct err_work; + struct work_struct mb_work; + void __iomem *io_base; + struct can_hw_mb __iomem *hwmb; + unsigned int __iomem *rx_mask; + int xmit_buffers; + unsigned int xmit_mb; + unsigned int bitrate; + /* word 1 */ + unsigned int br_presdiv:8; + unsigned int br_rjw:2; + unsigned int br_propseg:3; + unsigned int br_pseg1:3; + unsigned int br_pseg2:3; + unsigned int maxmb:6; + unsigned int xmit_maxmb:6; + unsigned int rsrvd:1; + + /* word 2 */ + unsigned int fifo:1; + unsigned int wakeup:1; + unsigned int srx_dis:1; + unsigned int wak_src:1; + unsigned int bcc:1; + unsigned int lprio:1; + unsigned int abort:1; + unsigned int br_clksrc:1; + unsigned int loopback:1; + unsigned int smp:1; + unsigned int boff_rec:1; + unsigned int tsyn:1; + unsigned int listen:1; + + unsigned int ext_msg:1; + unsigned int std_msg:1; + + struct timer_list timer; + struct platform_device *dev; + struct regulator *core_reg; + struct regulator *io_reg; + struct clk *clk; + int irq; +}; +#endif /* __CAN_FLEXCAN_H__ */ diff -purN linux-2.6.30-rc4-git/drivers/net/fec.c linux-2.6.30-rc4-karo3/drivers/net/fec.c --- linux-2.6.30-rc4-git/drivers/net/fec.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/drivers/net/fec.c 2009-07-01 12:59:40.000000000 +0200 @@ -2,6 +2,12 @@ * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) * + * This version of the driver is specific to the FADS implementation, + * since the board contains control registers external to the processor + * for the control of the LevelOne LXT970 transceiver. The MPC860T manual + * describes connections using the internal parallel port I/O, which + * is basically all of Port D. + * * Right now, I am very wasteful with the buffers. I allocate memory * pages and then divide them into 2K frame buffers. This way I know I * have buffers large enough to hold one frame within one buffer descriptor. @@ -18,77 +24,123 @@ * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) * Copyright (c) 2004-2006 Macq Electronique SA. */ +/* + * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ #include #include -#include -#include +#include #include #include #include #include -#include -#include +#include #include +#include #include #include #include #include -#include -#include -#include -#include +#include #include -#include +#include +#include -#include +#include +#include -#ifndef CONFIG_ARCH_MXC -#include -#include +#define DRV_NAME "fec" +#define DEBUG + +#ifdef DEBUG +static int debug = 0; +#define dbg_lvl(n) ((n) < debug) +module_param(debug, int, S_IRUGO | S_IWUSR); + +#define DBG(lvl, fmt...) do { if (dbg_lvl(lvl)) printk(KERN_DEBUG fmt); } while (0) +#else +static int debug; +#define dbg_lvl(n) 0 +module_param(debug, int, 0); + +#define DBG(lvl, fmt...) do { } while (0) #endif +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \ + defined(CONFIG_M5272) || defined(CONFIG_M528x) || \ + defined(CONFIG_M520x) || defined(CONFIG_M532x) +#include +#include #include "fec.h" - -#ifdef CONFIG_ARCH_MXC +#define FEC_ALIGNMENT (0x03) /*FEC needs 4bytes alignment*/ +#elif defined(CONFIG_ARCH_MXC) #include -#define FEC_ALIGNMENT 0xf +#include +#include "fec.h" +#define FEC_ALIGNMENT (0x0F) /*FEC needs 128bits(16bytes) alignment*/ #else -#define FEC_ALIGNMENT 0x3 +#include +#include +#include "commproc.h" +#define FEC_ALIGNMENT (0x03) /*FEC needs 4bytes alignment */ #endif +#define FEC_ADDR_ALIGNMENT(x) ((unsigned char *)(((unsigned long)(x) + (FEC_ALIGNMENT)) & (~FEC_ALIGNMENT))) + +#if 0 /* * Define the fixed address of the FEC hardware. */ +/* USE resources provided by platform_device! */ +static unsigned int fec_hw[] = { #if defined(CONFIG_M5272) -#define HAVE_mii_link_interrupt - -static unsigned char fec_mac_default[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + (MCF_MBAR + 0x840), +#elif defined(CONFIG_M527x) + (MCF_MBAR + 0x1000), + (MCF_MBAR + 0x1800), +#elif defined(CONFIG_M523x) || defined(CONFIG_M528x) + (MCF_MBAR + 0x1000), +#elif defined(CONFIG_M520x) + (MCF_MBAR+0x30000), +#elif defined(CONFIG_M532x) + (MCF_MBAR+0xfc030000), +#elif defined(CONFIG_ARCH_MXC) + (IO_ADDRESS(FEC_BASE_ADDR)), +#else + &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec), +#endif }; +#endif +#if 0 /* * Some hardware gets it MAC address out of local flash memory. * if this is non-zero then assume it is the address to get MAC from. */ +/* implemented using platform_data! */ #if defined(CONFIG_NETtel) #define FEC_FLASHMAC 0xf0006006 #elif defined(CONFIG_GILBARCONAP) || defined(CONFIG_SCALES) #define FEC_FLASHMAC 0xf0006000 +#elif defined (CONFIG_MTD_KeyTechnology) +#define FEC_FLASHMAC 0xffe04000 #elif defined(CONFIG_CANCam) #define FEC_FLASHMAC 0xf0020000 #elif defined (CONFIG_M5272C3) #define FEC_FLASHMAC (0xffe04000 + 4) #elif defined(CONFIG_MOD5272) -#define FEC_FLASHMAC 0xffc0406b +#define FEC_FLASHMAC 0xffc0406b #else #define FEC_FLASHMAC 0 #endif -#endif /* CONFIG_M5272 */ +#endif + +#define platform_func(p, args...) ((p) ? (p)(args) : 0) /* Forward declarations of some structures to support different PHYs */ - +#ifndef CONFIG_PHYLIB typedef struct { uint mii_data; void (*funct)(uint mii_reg, struct net_device *dev); @@ -103,6 +155,7 @@ typedef struct { const phy_cmd_t *ack_int; const phy_cmd_t *shutdown; } phy_info_t; +#endif /* The number of Tx and Rx buffers. These are allocated from the page * pool. The code may assume these are power of two, so it it best @@ -116,12 +169,13 @@ typedef struct { #define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES) #define FEC_ENET_TX_FRSIZE 2048 #define FEC_ENET_TX_FRPPG (PAGE_SIZE / FEC_ENET_TX_FRSIZE) -#define TX_RING_SIZE 16 /* Must be power of two */ -#define TX_RING_MOD_MASK 15 /* for this to work */ +#define TX_RING_SIZE 16 /* Must be power of two */ +#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) /* for this to work */ #if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE) #error "FEC: descriptor ring size constants too large" #endif +#define CBD_BUF_SIZE ((RX_RING_SIZE + TX_RING_SIZE) * sizeof(cbd_t)) /* Interrupt events/masks. */ @@ -136,6 +190,17 @@ typedef struct { #define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ #define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ +/* MXC arch interrupt bits */ +#define FEC_ENET_LC ((uint)0x00200000) /* Late collision */ +#define FEC_ENET_RL ((uint)0x00100000) /* Collision retry limit exceeded */ +#define FEC_ENET_UN ((uint)0x00080000) /* TX Fifo underrun */ + +#ifndef CONFIG_ARCH_MXC +#define FEC_ENET_MASK ((uint)0xffc00000) +#else +#define FEC_ENET_MASK ((uint)0xfff80000) +#endif + /* The FEC stores dest/src/type, data, and checksum for receive packets. */ #define PKT_MAXBUF_SIZE 1518 @@ -150,7 +215,7 @@ typedef struct { */ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARCH_MXC) -#define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) +#define OPT_FRAME_SIZE (RCR_MAX_FL_set(PKT_MAXBUF_SIZE)) #else #define OPT_FRAME_SIZE 0 #endif @@ -165,31 +230,45 @@ typedef struct { */ struct fec_enet_private { /* Hardware registers of the FEC device */ - volatile fec_t *hwp; - - struct net_device *netdev; - - struct clk *clk; + void __iomem *reg_base; + void __iomem *mib_base; + struct resource *res_mem1; + struct resource *res_mem2; + int etn_irq; + int mii_irq; +#ifndef CONFIG_PHYLIB + struct timer_list *phy_timer; +#else + struct mii_bus *mii; + int mii_complete; +#endif + u32 msg_enable; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - unsigned char *tx_bounce[TX_RING_SIZE]; + void *tx_bounce[TX_RING_SIZE]; struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct sk_buff* rx_skbuff[RX_RING_SIZE]; ushort skb_cur; ushort skb_dirty; /* CPM dual port RAM relative addresses. */ - dma_addr_t bd_dma; + struct device *dma_dev; /* pointer to (platform_)device for dma_sync*() functions */ + void *cbd_mem_base; /* save the virtual base address of rx&tx buffer descriptor */ + dma_addr_t cbd_phys_base; /* physical address of buffer descriptor memory for access by FEC HW */ + cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ cbd_t *tx_bd_base; - cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ - cbd_t *dirty_tx; /* The ring entries to be free()ed. */ + cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ + cbd_t *dirty_tx; /* The ring entries to be free()ed. */ + struct net_device_stats stats; uint tx_full; - /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */ - spinlock_t hw_lock; - /* hold while accessing the mii_list_t() elements */ - spinlock_t mii_lock; + spinlock_t lock; +#ifdef CONFIG_PHYLIB + struct phy_device *phy; + uint phy_speed; +#else uint phy_id; uint phy_id_done; uint phy_status; @@ -199,28 +278,41 @@ struct fec_enet_private { uint sequence_done; uint mii_phy_task_queued; - +#endif uint phy_addr; - int index; - int opened; - int link; - int old_link; - int full_duplex; + unsigned int opened:1; + unsigned int phy_int_enabled:1; + unsigned int linkstatus:1; +#ifndef CONFIG_PHYLIB + unsigned int old_linkstatus:1; +#endif + unsigned int full_duplex:1; + + struct clk *clk; }; -static int fec_enet_open(struct net_device *dev); -static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); -static void fec_enet_mii(struct net_device *dev); -static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); +#ifdef CONFIG_PHYLIB +static int fec_connect_phy(struct net_device *dev, struct fec_enet_private *fep); +#else +static irqreturn_t mii_link_interrupt(int irq, void *dev_id); +#endif +static void fec_restart(struct net_device *dev, int duplex); static void fec_enet_tx(struct net_device *dev); static void fec_enet_rx(struct net_device *dev); -static int fec_enet_close(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static void fec_restart(struct net_device *dev, int duplex); +static void fec_enet_mii(struct net_device *dev); static void fec_stop(struct net_device *dev); -static void fec_set_mac_address(struct net_device *dev); +static void _fec_set_mac_address(struct net_device *dev); +/* + * fec_copy_threshold controls the copy when receiving ethernet frame. + * If ethernet header is aligned on a 4byte boundary, the ip header and + * higher level header will not be aligned. + * The reason is, that an ethernet header is 14bytes long. + * And the max size of tcp & ip header is 128bytes. Normally it is 40bytes. + * So I set the default value between 128 to 256. + */ +static int fec_copy_threshold = 192; /* MII processing. We keep this as simple as possible. Requests are * placed on the list (if there is room). When the request is finished @@ -232,14 +324,16 @@ typedef struct mii_list { struct mii_list *mii_next; } mii_list_t; +#ifndef CONFIG_PHYLIB #define NMII 20 static mii_list_t mii_cmds[NMII]; static mii_list_t *mii_free; static mii_list_t *mii_head; static mii_list_t *mii_tail; -static int mii_queue(struct net_device *dev, int request, - void (*func)(uint, struct net_device *)); +static int mii_queue(struct net_device *dev, int request, + void (*func)(uint, struct net_device *)); +#endif /* Make MII read/write commands for the FEC. */ @@ -284,47 +378,160 @@ static int mii_queue(struct net_device * #define PHY_STAT_100HDX 0x4000 /* 100 Mbit half duplex selected */ #define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */ +#ifndef DEBUG +static inline unsigned long fec_reg_read(struct fec_enet_private *fep, unsigned int reg) +{ + return readl(fep->reg_base + reg); +} + +static inline void fec_reg_write(struct fec_enet_private *fep, unsigned int reg, unsigned long val) +{ + writel(val, fep->reg_base + reg); +} +#else +#define fec_reg_read(fep, reg) __fec_reg_read(fep, reg, __FUNCTION__, #reg) +#define fec_reg_write(fep, reg, val) __fec_reg_write(fep, reg, val, __FUNCTION__, #reg) + +static inline unsigned long __fec_reg_read(struct fec_enet_private *fep, unsigned int reg, + const char *func, const char *reg_name) +{ + unsigned long val = readl(fep->reg_base + reg); + DBG(3, "%s: Read %08lx from %s(%03x)\n", func, val, reg_name, reg); + return val; +} + +static inline void __fec_reg_write(struct fec_enet_private *fep, unsigned int reg, + unsigned long val, const char *func, const char *reg_name) +{ + DBG(3, "%s: Writing %08lx to %s(%03x)\n", func, val, reg_name, reg); + writel(val, fep->reg_base + reg); +} +#endif + +static inline void fec_enet_cbd_get(struct fec_enet_private *fep) +{ + DBG(2, "%s: Requesting cbd area: %08lx\n", __FUNCTION__, + (unsigned long)fep->cbd_phys_base); + dma_sync_single_for_cpu(fep->dma_dev, fep->cbd_phys_base, + CBD_BUF_SIZE, DMA_BIDIRECTIONAL); +} + +static inline void fec_enet_cbd_put(struct fec_enet_private *fep) +{ + DBG(2, "%s: Flushing changes to cbd area\n", __FUNCTION__); + dma_sync_single_for_device(fep->dma_dev, fep->cbd_phys_base, + CBD_BUF_SIZE, DMA_BIDIRECTIONAL); +} + +static inline void fec_enet_rxbuf_get(struct fec_enet_private *fep, cbd_t *bdp, ushort len) +{ + DBG(2, "%s: Requesting RX buffer %08lx(%u)\n", __FUNCTION__, + (unsigned long)bdp->cbd_bufaddr, len); + dma_sync_single_for_cpu(fep->dma_dev, bdp->cbd_bufaddr, + len, DMA_FROM_DEVICE); +} + +static inline void fec_enet_rxbuf_put(struct fec_enet_private *fep, cbd_t *bdp, ushort len) +{ + DBG(2, "%s: Releasing RX buffer %08lx(%u)\n", __FUNCTION__, (ulong)bdp->cbd_bufaddr, len); + dma_sync_single_for_device(fep->dma_dev, bdp->cbd_bufaddr, len, DMA_FROM_DEVICE); +} + +static inline void fec_enet_rxbuf_map(struct fec_enet_private *fep, cbd_t *bdp, + void *buf, ushort len) +{ + BUG_ON(!dma_mapping_error(fep->dma_dev, bdp->cbd_bufaddr)); + bdp->cbd_bufaddr = dma_map_single(fep->dma_dev, buf, + len, DMA_FROM_DEVICE); + DBG(2, "%s: RX buffer %p(%u) mapped to %08lx\n", __FUNCTION__, + buf, len, (unsigned long)bdp->cbd_bufaddr); +} + +static inline void fec_enet_rxbuf_unmap(struct fec_enet_private *fep, cbd_t *bdp, ushort len) +{ + DBG(2, "%s: Unmapping RX buffer %08lx(%u)\n", __FUNCTION__, + (unsigned long)bdp->cbd_bufaddr, len); + BUG_ON(dma_mapping_error(fep->dma_dev, bdp->cbd_bufaddr)); + dma_unmap_single(fep->dma_dev, bdp->cbd_bufaddr, + len, DMA_FROM_DEVICE); + bdp->cbd_bufaddr = ~0; +} + +static inline void fec_enet_txbuf_map(struct fec_enet_private *fep, cbd_t *bdp, + void *buf, ushort len) +{ + BUG_ON(!dma_mapping_error(fep->dma_dev, bdp->cbd_bufaddr)); + bdp->cbd_bufaddr = dma_map_single(fep->dma_dev, buf, + len, DMA_TO_DEVICE); + DBG(2, "%s: TX buffer %p(%u) mapped to %08lx\n", __FUNCTION__, + buf, len, (unsigned long)bdp->cbd_bufaddr); +} + +static inline void fec_enet_txbuf_unmap(struct fec_enet_private *fep, cbd_t *bdp, ushort len) +{ + DBG(2, "%s: Unmapping TX buffer %08lx(%u)\n", __FUNCTION__, + (unsigned long)bdp->cbd_bufaddr, len); + BUG_ON(dma_mapping_error(fep->dma_dev, bdp->cbd_bufaddr)); + dma_unmap_single(fep->dma_dev, bdp->cbd_bufaddr, + len, DMA_TO_DEVICE); + bdp->cbd_bufaddr = ~0; +} + +static inline void fec_enet_txbuf_get(struct fec_enet_private *fep, cbd_t *bdp, ushort len) +{ + DBG(2, "%s: Requesting TX buffer %08lx(%u)\n", __FUNCTION__, + (unsigned long)bdp->cbd_bufaddr, len); + dma_sync_single_for_cpu(fep->dma_dev, bdp->cbd_bufaddr, + len, DMA_TO_DEVICE); +} + +static inline void fec_enet_txbuf_put(struct fec_enet_private *fep, cbd_t *bdp, ushort len) +{ + DBG(2, "%s: Releasing TX buffer %08lx(%u)\n", __FUNCTION__, + (unsigned long)bdp->cbd_bufaddr, len); + dma_sync_single_for_device(fep->dma_dev, bdp->cbd_bufaddr, + len, DMA_TO_DEVICE); +} static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct fec_enet_private *fep; - volatile fec_t *fecp; - volatile cbd_t *bdp; - unsigned short status; + struct fec_enet_private *fep = netdev_priv(dev); + cbd_t *bdp; + unsigned short status; unsigned long flags; - fep = netdev_priv(dev); - fecp = (volatile fec_t*)dev->base_addr; - - if (!fep->link) { + if (!fep->linkstatus) { + DBG(0, "%s: Cannot send packet; link is down\n", __FUNCTION__); /* Link is down or autonegotiation is in progress. */ - return 1; + return NETDEV_TX_BUSY; } - spin_lock_irqsave(&fep->hw_lock, flags); + spin_lock_irqsave(&fep->lock, flags); + + fec_enet_cbd_get(fep); + /* Fill in a Tx ring entry */ bdp = fep->cur_tx; status = bdp->cbd_sc; -#ifndef final_version +#ifdef DEBUG if (status & BD_ENET_TX_READY) { /* Ooops. All transmit buffers are full. Bail out. * This should not happen, since dev->tbusy should be set. */ printk("%s: tx queue full!.\n", dev->name); - spin_unlock_irqrestore(&fep->hw_lock, flags); - return 1; + fec_enet_cbd_put(fep); + spin_unlock_irqrestore(&fep->lock, flags); + return NETDEV_TX_BUSY; } #endif - /* Clear all of the status flags. */ status &= ~BD_ENET_TX_STATS; /* Set buffer length and buffer pointer. */ - bdp->cbd_bufaddr = __pa(skb->data); bdp->cbd_datlen = skb->len; /* @@ -332,39 +539,31 @@ fec_enet_start_xmit(struct sk_buff *skb, * 4-byte boundaries. Use bounce buffers to copy data * and get it aligned. Ugh. */ - if (bdp->cbd_bufaddr & FEC_ALIGNMENT) { + if (unlikely((bdp->cbd_bufaddr) & FEC_ALIGNMENT)) { unsigned int index; index = bdp - fep->tx_bd_base; - memcpy(fep->tx_bounce[index], (void *)skb->data, skb->len); - bdp->cbd_bufaddr = __pa(fep->tx_bounce[index]); + memcpy(fep->tx_bounce[index], skb->data, skb->len); + fec_enet_txbuf_map(fep, bdp, fep->tx_bounce[index], skb->len); + } else { + fec_enet_txbuf_map(fep, bdp, skb->data, skb->len); } /* Save skb pointer. */ fep->tx_skbuff[fep->skb_cur] = skb; - dev->stats.tx_bytes += skb->len; - fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK; - - /* Push the data cache so the CPM does not get stale memory - * data. - */ - dma_sync_single(NULL, bdp->cbd_bufaddr, - bdp->cbd_datlen, DMA_TO_DEVICE); + fep->stats.tx_bytes += skb->len; + fep->skb_cur = (fep->skb_cur + 1) & TX_RING_MOD_MASK; /* Send it on its way. Tell FEC it's ready, interrupt when done, * it's the last BD of the frame, and to put the CRC on the end. */ - status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); bdp->cbd_sc = status; dev->trans_start = jiffies; - /* Trigger transmission start */ - fecp->fec_x_des_active = 0; - /* If this was the last BD in the ring, start at the beginning again. */ if (status & BD_ENET_TX_WRAP) { @@ -375,14 +574,19 @@ fec_enet_start_xmit(struct sk_buff *skb, if (bdp == fep->dirty_tx) { fep->tx_full = 1; + DBG(0, "TX ring full, stopping netif queue\n"); netif_stop_queue(dev); } - fep->cur_tx = (cbd_t *)bdp; + fep->cur_tx = bdp; + fec_enet_cbd_put(fep); + + /* Trigger transmission start */ + fec_reg_write(fep, FEC_TDAR, DONT_CARE); - spin_unlock_irqrestore(&fep->hw_lock, flags); + spin_unlock_irqrestore(&fep->lock, flags); - return 0; + return NETDEV_TX_OK; } static void @@ -390,101 +594,125 @@ fec_timeout(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - printk("%s: transmit timed out.\n", dev->name); - dev->stats.tx_errors++; -#ifndef final_version + printk(KERN_WARNING "%s: transmit timed out.\n", dev->name); + fep->stats.tx_errors++; +#ifdef DEBUG { - int i; - cbd_t *bdp; + int i; + cbd_t *bdp; - printk("Ring data dump: cur_tx %lx%s, dirty_tx %lx cur_rx: %lx\n", - (unsigned long)fep->cur_tx, fep->tx_full ? " (full)" : "", - (unsigned long)fep->dirty_tx, - (unsigned long)fep->cur_rx); + fec_enet_cbd_get(fep); - bdp = fep->tx_bd_base; - printk(" tx: %u buffers\n", TX_RING_SIZE); - for (i = 0 ; i < TX_RING_SIZE; i++) { - printk(" %08x: %04x %04x %08x\n", - (uint) bdp, - bdp->cbd_sc, - bdp->cbd_datlen, - (int) bdp->cbd_bufaddr); - bdp++; - } + printk(KERN_DEBUG "%s: Ring data dump: cur_tx %p%s, dirty_tx %p cur_rx: %p\n", + __FUNCTION__, + fep->cur_tx, fep->tx_full ? " (full)" : "", + fep->dirty_tx, + fep->cur_rx); - bdp = fep->rx_bd_base; - printk(" rx: %lu buffers\n", (unsigned long) RX_RING_SIZE); - for (i = 0 ; i < RX_RING_SIZE; i++) { - printk(" %08x: %04x %04x %08x\n", - (uint) bdp, - bdp->cbd_sc, - bdp->cbd_datlen, - (int) bdp->cbd_bufaddr); - bdp++; - } + bdp = fep->tx_bd_base; + printk(" tx: %u buffers\n", TX_RING_SIZE); + for (i = 0; i < TX_RING_SIZE; i++) { + printk(" %p: %04x %04x %08x\n", + bdp, + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + bdp++; + } + + bdp = fep->rx_bd_base; + printk(" rx: %lu buffers\n", RX_RING_SIZE); + for (i = 0; i < RX_RING_SIZE; i++) { + printk(" %p: %04x %04x %08x\n", + bdp, + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + bdp++; + } + fec_enet_cbd_put(fep); } #endif fec_restart(dev, fep->full_duplex); - netif_wake_queue(dev); + DBG(0, "%s: Scheduling netif queue\n", __FUNCTION__); + //netif_schedule(dev); } /* The interrupt handler. * This is called from the MPC core interrupt. */ static irqreturn_t -fec_enet_interrupt(int irq, void * dev_id) +fec_enet_interrupt(int irq, void *dev_id) { - struct net_device *dev = dev_id; - volatile fec_t *fecp; - uint int_events; - irqreturn_t ret = IRQ_NONE; - - fecp = (volatile fec_t*)dev->base_addr; + struct net_device *dev = dev_id; + struct fec_enet_private *fep = netdev_priv(dev); + uint int_events; + int handled = 0; + unsigned int eimr = fec_reg_read(fep, FEC_EIMR); + DBG(2, "%s: %08lx:%08lx\n", __FUNCTION__, + fec_reg_read(fep, FEC_EIR), fec_reg_read(fep, FEC_EIMR)); /* Get the interrupt events that caused us to be here. */ - do { - int_events = fecp->fec_ievent; - fecp->fec_ievent = int_events; + while ((int_events = fec_reg_read(fep, FEC_EIR) & FEC_ENET_MASK) != 0) { + if (int_events & ~eimr) { + printk(KERN_WARNING "%s: masked interrupt condition: %08x\n", + __FUNCTION__, int_events & ~eimr); + } + + fec_reg_write(fep, FEC_EIR, int_events); /* Handle receive event in its own function. */ - if (int_events & FEC_ENET_RXF) { - ret = IRQ_HANDLED; + if (int_events & (FEC_ENET_RXF | FEC_ENET_RXB)) { + DBG(2, "%s: Handling RX Interrupt\n", __FUNCTION__); + handled = 1; fec_enet_rx(dev); } + if (int_events & FEC_ENET_UN) { + printk(KERN_WARNING "TX fifo underrun"); + } /* Transmit OK, or non-fatal error. Update the buffer descriptors. FEC handles all errors, we just discover them as part of the transmit process. */ - if (int_events & FEC_ENET_TXF) { - ret = IRQ_HANDLED; + if (int_events & (FEC_ENET_TXF | FEC_ENET_TXB)) { + DBG(2, "%s: Handling TX Interrupt\n", __FUNCTION__); + handled = 1; fec_enet_tx(dev); } - if (int_events & FEC_ENET_MII) { - ret = IRQ_HANDLED; + if (int_events & (FEC_ENET_MII | FEC_ENET_HBERR)) { + DBG(2, "%s: Handling MII Interrupt\n", __FUNCTION__); + handled = 1; fec_enet_mii(dev); } - - } while (int_events); - - return ret; + } + return IRQ_RETVAL(handled); } +static void fec_free_skb(struct fec_enet_private *fep, cbd_t *bdp, struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + if (!dma_mapping_error(fep->dma_dev, bdp->cbd_bufaddr)) { + fec_enet_txbuf_unmap(fep, bdp, skb->len); + } + dev_kfree_skb_any(skb); + *pskb = NULL; +} static void fec_enet_tx(struct net_device *dev) { - struct fec_enet_private *fep; - volatile cbd_t *bdp; + struct fec_enet_private *fep = netdev_priv(dev); + cbd_t *bdp; unsigned short status; - struct sk_buff *skb; + struct sk_buff *skb; - fep = netdev_priv(dev); - spin_lock_irq(&fep->hw_lock); + spin_lock(&fep->lock); + + fec_enet_cbd_get(fep); bdp = fep->dirty_tx; while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { @@ -495,22 +723,22 @@ fec_enet_tx(struct net_device *dev) if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { - dev->stats.tx_errors++; + fep->stats.tx_errors++; if (status & BD_ENET_TX_HB) /* No heartbeat */ - dev->stats.tx_heartbeat_errors++; + fep->stats.tx_heartbeat_errors++; if (status & BD_ENET_TX_LC) /* Late collision */ - dev->stats.tx_window_errors++; + fep->stats.tx_window_errors++; if (status & BD_ENET_TX_RL) /* Retrans limit */ - dev->stats.tx_aborted_errors++; + fep->stats.tx_aborted_errors++; if (status & BD_ENET_TX_UN) /* Underrun */ - dev->stats.tx_fifo_errors++; + fep->stats.tx_fifo_errors++; if (status & BD_ENET_TX_CSL) /* Carrier lost */ - dev->stats.tx_carrier_errors++; + fep->stats.tx_carrier_errors++; } else { - dev->stats.tx_packets++; + fep->stats.tx_packets++; } -#ifndef final_version +#ifdef DEBUG if (status & BD_ENET_TX_READY) printk("HEY! Enet xmit interrupt and TX_READY.\n"); #endif @@ -518,12 +746,11 @@ fec_enet_tx(struct net_device *dev) * but we eventually sent the packet OK. */ if (status & BD_ENET_TX_DEF) - dev->stats.collisions++; + fep->stats.collisions++; /* Free the sk buffer associated with this last transmit. */ - dev_kfree_skb_any(skb); - fep->tx_skbuff[fep->skb_dirty] = NULL; + fec_free_skb(fep, bdp, &fep->tx_skbuff[fep->skb_dirty]); fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK; /* Update pointer to next buffer descriptor to be transmitted. @@ -538,12 +765,15 @@ fec_enet_tx(struct net_device *dev) */ if (fep->tx_full) { fep->tx_full = 0; - if (netif_queue_stopped(dev)) + if (netif_queue_stopped(dev)) { + DBG(0, "%s: Waking up netif queue\n", __FUNCTION__); netif_wake_queue(dev); + } } } - fep->dirty_tx = (cbd_t *)bdp; - spin_unlock_irq(&fep->hw_lock); + fec_enet_cbd_put(fep); + fep->dirty_tx = bdp; + spin_unlock(&fep->lock); } @@ -555,22 +785,22 @@ fec_enet_tx(struct net_device *dev) static void fec_enet_rx(struct net_device *dev) { - struct fec_enet_private *fep; - volatile fec_t *fecp; - volatile cbd_t *bdp; + struct fec_enet_private *fep = netdev_priv(dev); + cbd_t *bdp; unsigned short status; - struct sk_buff *skb; - ushort pkt_len; - __u8 *data; + struct sk_buff *skb; + ushort pkt_len; + int rx_index; #ifdef CONFIG_M532x + /* This is probably nonsense + Proper use of dma-mapping functions should make this obsolete + */ flush_cache_all(); #endif - - fep = netdev_priv(dev); - fecp = (volatile fec_t*)dev->base_addr; - - spin_lock_irq(&fep->hw_lock); + /* reserve the dual port memory area for our use */ + //WARN_ON(fec_reg_read(fep, FEC_RDAR) & RDAR_BUSY); + fec_enet_cbd_get(fep); /* First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. @@ -578,32 +808,34 @@ fec_enet_rx(struct net_device *dev) bdp = fep->cur_rx; while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { - -#ifndef final_version + rx_index = bdp - fep->rx_bd_base; +#ifdef DEBUG /* Since we have allocated space to hold a complete frame, * the last indicator should be set. */ - if ((status & BD_ENET_RX_LAST) == 0) - printk("FEC ENET: rcv is not +last\n"); + WARN_ON(!(status & BD_ENET_RX_LAST)); #endif - if (!fep->opened) + if (WARN_ON(!fep->opened)) { + DBG(0, "%s: Driver not opened; ignoring packet\n", __FUNCTION__); +#if 0 goto rx_processing_done; - +#endif + } /* Check for errors. */ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { - dev->stats.rx_errors++; + fep->stats.rx_errors++; if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { /* Frame too long or too short. */ - dev->stats.rx_length_errors++; + fep->stats.rx_length_errors++; } if (status & BD_ENET_RX_NO) /* Frame alignment */ - dev->stats.rx_frame_errors++; + fep->stats.rx_frame_errors++; if (status & BD_ENET_RX_CR) /* CRC Error */ - dev->stats.rx_crc_errors++; + fep->stats.rx_crc_errors++; if (status & BD_ENET_RX_OV) /* FIFO overrun */ - dev->stats.rx_fifo_errors++; + fep->stats.rx_fifo_errors++; } /* Report late collisions as a frame error. @@ -611,39 +843,67 @@ while (!((status = bdp->cbd_sc) & BD_ENE * have in the buffer. So, just drop this frame on the floor. */ if (status & BD_ENET_RX_CL) { - dev->stats.rx_errors++; - dev->stats.rx_frame_errors++; + fep->stats.rx_errors++; + fep->stats.rx_frame_errors++; + DBG(0, "%s: Collision detected; dropping packet\n", __FUNCTION__); + goto rx_processing_done; + } + + if (!fep->opened) { + DBG(0, "%s: Driver not opened; ignoring packet\n", __FUNCTION__); goto rx_processing_done; } /* Process the incoming frame. */ - dev->stats.rx_packets++; + fep->stats.rx_packets++; pkt_len = bdp->cbd_datlen; - dev->stats.rx_bytes += pkt_len; - data = (__u8*)__va(bdp->cbd_bufaddr); - - dma_sync_single(NULL, (unsigned long)__pa(data), - pkt_len - 4, DMA_FROM_DEVICE); + fep->stats.rx_bytes += pkt_len; /* This does 16 byte alignment, exactly what we need. * The packet length includes FCS, but we don't want to * include that when passing upstream as it messes up * bridging applications. */ - skb = dev_alloc_skb(pkt_len-4); + if ((pkt_len - 4) < fec_copy_threshold) { + skb = dev_alloc_skb(pkt_len); + } else { + skb = dev_alloc_skb(FEC_ENET_RX_FRSIZE); + } if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); - dev->stats.rx_dropped++; + fep->stats.rx_dropped++; } else { - skb_put(skb,pkt_len-4); /* Make room */ - skb_copy_to_linear_data(skb, data, pkt_len-4); - skb->protocol=eth_type_trans(skb,dev); + if ((pkt_len - 4) < fec_copy_threshold) { + /* skip 2 bytes, so IP header is on a 4 bytes boundary */ + skb_reserve(skb, 2); + skb_put(skb, pkt_len - 4); /* Make room */ + fec_enet_rxbuf_get(fep, bdp, pkt_len - 4); + skb_copy_to_linear_data(skb, + fep->rx_skbuff[rx_index]->data, + pkt_len - 4); + fec_enet_rxbuf_put(fep, bdp, pkt_len - 4); + } else { + struct sk_buff *pskb = fep->rx_skbuff[rx_index]; + + /* unmap the skb we are going to hand down to the network layer */ + fec_enet_rxbuf_unmap(fep, bdp, FEC_ENET_RX_FRSIZE); + + /* init the newly allocated skb */ + fep->rx_skbuff[rx_index] = skb; + skb->data = FEC_ADDR_ALIGNMENT(skb->data); + /* map the newly allocated skb's data buffer for DMA */ + fec_enet_rxbuf_map(fep, bdp, skb->data, FEC_ENET_RX_FRSIZE); + + skb_put(pskb, pkt_len - 4); /* Make room */ + skb = pskb; + } + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); } rx_processing_done: - /* Clear the status flags for this buffer. */ status &= ~BD_ENET_RX_STATS; @@ -653,6 +913,9 @@ while (!((status = bdp->cbd_sc) & BD_ENE status |= BD_ENET_RX_EMPTY; bdp->cbd_sc = status; + /* release the dual port memory area for use by the FEC hardware */ + fec_enet_cbd_put(fep); + /* Update BD pointer to next entry. */ if (status & BD_ENET_RX_WRAP) @@ -665,10 +928,10 @@ while (!((status = bdp->cbd_sc) & BD_ENE * incoming frames. On a heavily loaded network, we should be * able to keep up at the expense of system resources. */ - fecp->fec_r_des_active = 0; + fec_reg_write(fep, FEC_RDAR, DONT_CARE); #endif } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */ - fep->cur_rx = (cbd_t *)bdp; + fep->cur_rx = bdp; #if 0 /* Doing this here will allow us to process all frames in the @@ -678,27 +941,28 @@ while (!((status = bdp->cbd_sc) & BD_ENE * our way back to the interrupt return only to come right back * here. */ - fecp->fec_r_des_active = 0; + fec_reg_write(fep, FEC_RDAR, DONT_CARE); #endif - - spin_unlock_irq(&fep->hw_lock); } - +#ifdef CONFIG_PHYLIB /* called from interrupt context */ +static void fec_enet_mii(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + fep->mii_complete = 1; +} +#else static void fec_enet_mii(struct net_device *dev) { - struct fec_enet_private *fep; - volatile fec_t *ep; + struct fec_enet_private *fep = netdev_priv(dev); mii_list_t *mip; uint mii_reg; - fep = netdev_priv(dev); - spin_lock_irq(&fep->mii_lock); + mii_reg = fec_reg_read(fep, FEC_MMFR); - ep = fep->hwp; - mii_reg = ep->fec_mii_data; + spin_lock(&fep->lock); if ((mip = mii_head) == NULL) { printk("MII and no head!\n"); @@ -713,27 +977,27 @@ fec_enet_mii(struct net_device *dev) mii_free = mip; if ((mip = mii_head) != NULL) - ep->fec_mii_data = mip->mii_regval; + fec_reg_write(fep, FEC_MMFR, mip->mii_regval); unlock: - spin_unlock_irq(&fep->mii_lock); + spin_unlock(&fep->lock); } static int mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *)) { - struct fec_enet_private *fep; + struct fec_enet_private *fep = netdev_priv(dev); unsigned long flags; mii_list_t *mip; int retval; + retval = 0; + + spin_lock_irqsave(&fep->lock,flags); + /* Add PHY address to register command. */ - fep = netdev_priv(dev); - spin_lock_irqsave(&fep->mii_lock, flags); - regval |= fep->phy_addr << 23; - retval = 0; if ((mip = mii_free) != NULL) { mii_free = mip->mii_next; @@ -745,32 +1009,32 @@ mii_queue(struct net_device *dev, int re mii_tail = mip; } else { mii_head = mii_tail = mip; - fep->hwp->fec_mii_data = regval; + fec_reg_write(fep, FEC_MMFR, regval); } } else { retval = 1; } - spin_unlock_irqrestore(&fep->mii_lock, flags); - return retval; + spin_unlock_irqrestore(&fep->lock,flags); + + return(retval); } static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c) { - if(!c) - return; + int k; - for (; c->mii_data != mk_mii_end; c++) - mii_queue(dev, c->mii_data, c->funct); + for (k = 0; c != NULL && c[k].mii_data != mk_mii_end; k++) { + mii_queue(dev, c[k].mii_data, c[k].funct); + } } static void mii_parse_sr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile uint *s = &(fep->phy_status); uint status; - status = *s & ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); + status = fep->phy_status & ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); if (mii_reg & 0x0004) status |= PHY_STAT_LINK; @@ -778,31 +1042,30 @@ static void mii_parse_sr(uint mii_reg, s status |= PHY_STAT_FAULT; if (mii_reg & 0x0020) status |= PHY_STAT_ANC; - *s = status; + + fep->phy_status = status; } static void mii_parse_cr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile uint *s = &(fep->phy_status); uint status; - status = *s & ~(PHY_CONF_ANE | PHY_CONF_LOOP); + status = fep->phy_status & ~(PHY_CONF_ANE | PHY_CONF_LOOP); if (mii_reg & 0x1000) status |= PHY_CONF_ANE; if (mii_reg & 0x4000) status |= PHY_CONF_LOOP; - *s = status; + fep->phy_status = status; } static void mii_parse_anar(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile uint *s = &(fep->phy_status); uint status; - status = *s & ~(PHY_CONF_SPMASK); + status = fep->phy_status & ~(PHY_CONF_SPMASK); if (mii_reg & 0x0020) status |= PHY_CONF_10HDX; @@ -812,7 +1075,7 @@ static void mii_parse_anar(uint mii_reg, status |= PHY_CONF_100HDX; if (mii_reg & 0x00100) status |= PHY_CONF_100FDX; - *s = status; + fep->phy_status = status; } /* ------------------------------------------------------------------------- */ @@ -827,10 +1090,9 @@ static void mii_parse_anar(uint mii_reg, static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile uint *s = &(fep->phy_status); uint status; - status = *s & ~(PHY_STAT_SPMASK); + status = fep->phy_status & ~(PHY_STAT_SPMASK); if (mii_reg & 0x0800) { if (mii_reg & 0x1000) status |= PHY_STAT_100FDX; @@ -842,7 +1104,7 @@ static void mii_parse_lxt970_csr(uint mi else status |= PHY_STAT_10HDX; } - *s = status; + fep->phy_status = status; } static phy_cmd_t const phy_cmd_lxt970_config[] = { @@ -898,16 +1160,15 @@ static phy_info_t const phy_info_lxt970 static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile uint *s = &(fep->phy_status); uint status; - status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); + status = fep->phy_status & ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); if (mii_reg & 0x0400) { - fep->link = 1; + fep->linkstatus = 1; status |= PHY_STAT_LINK; } else { - fep->link = 0; + fep->linkstatus = 0; } if (mii_reg & 0x0080) status |= PHY_STAT_ANC; @@ -925,7 +1186,7 @@ static void mii_parse_lxt971_sr2(uint mi if (mii_reg & 0x0008) status |= PHY_STAT_FAULT; - *s = status; + fep->phy_status = status; } static phy_cmd_t const phy_cmd_lxt971_config[] = { @@ -982,10 +1243,9 @@ static phy_info_t const phy_info_lxt971 static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile uint *s = &(fep->phy_status); uint status; - status = *s & ~(PHY_STAT_SPMASK); + status = fep->phy_status & ~(PHY_STAT_SPMASK); switch((mii_reg >> 2) & 7) { case 1: status |= PHY_STAT_10HDX; break; @@ -994,7 +1254,7 @@ static void mii_parse_qs6612_pcr(uint mi case 6: status |= PHY_STAT_100FDX; break; } - *s = status; + fep->phy_status = status; } static phy_cmd_t const phy_cmd_qs6612_config[] = { @@ -1052,10 +1312,9 @@ static phy_info_t const phy_info_qs6612 static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile uint *s = &(fep->phy_status); uint status; - status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_ANC); + status = fep->phy_status & ~(PHY_STAT_SPMASK | PHY_STAT_ANC); if (mii_reg & 0x0080) status |= PHY_STAT_ANC; @@ -1064,7 +1323,7 @@ static void mii_parse_am79c874_dr(uint m else status |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX); - *s = status; + fep->phy_status = status; } static phy_cmd_t const phy_cmd_am79c874_config[] = { @@ -1107,7 +1366,7 @@ static phy_info_t const phy_info_am79c87 /* register definitions for the 8721 */ #define MII_KS8721BL_RXERCR 21 -#define MII_KS8721BL_ICSR 27 +#define MII_KS8721BL_ICSR 22 #define MII_KS8721BL_PHYCR 31 static phy_cmd_t const phy_cmd_ks8721bl_config[] = { @@ -1149,32 +1408,31 @@ static phy_info_t const phy_info_ks8721b static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile uint *s = &(fep->phy_status); - *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); + fep->phy_status &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); /* Link up */ if (mii_reg & 0x0001) { - fep->link = 1; - *s |= PHY_STAT_LINK; + fep->linkstatus = 1; + fep->phy_status |= PHY_STAT_LINK; } else - fep->link = 0; + fep->linkstatus = 0; /* Status of link */ if (mii_reg & 0x0010) /* Autonegotioation complete */ - *s |= PHY_STAT_ANC; + fep->phy_status |= PHY_STAT_ANC; if (mii_reg & 0x0002) { /* 10MBps? */ if (mii_reg & 0x0004) /* Full Duplex? */ - *s |= PHY_STAT_10FDX; + fep->phy_status |= PHY_STAT_10FDX; else - *s |= PHY_STAT_10HDX; + fep->phy_status |= PHY_STAT_10HDX; } else { /* 100 Mbps? */ if (mii_reg & 0x0004) /* Full Duplex? */ - *s |= PHY_STAT_100FDX; + fep->phy_status |= PHY_STAT_100FDX; else - *s |= PHY_STAT_100HDX; + fep->phy_status |= PHY_STAT_100HDX; } if (mii_reg & 0x0008) - *s |= PHY_STAT_FAULT; + fep->phy_status |= PHY_STAT_FAULT; } static phy_info_t phy_info_dp83848= { @@ -1211,122 +1469,391 @@ static phy_info_t const * const phy_info &phy_info_dp83848, NULL }; - -/* ------------------------------------------------------------------------- */ -#ifdef HAVE_mii_link_interrupt -static irqreturn_t -mii_link_interrupt(int irq, void * dev_id); +#endif /* - * This is specific to the MII interrupt setup of the M5272EVB. + * do some initializtion based architecture of this chip +MOVED to platform_data hooks! */ -static void __inline__ fec_request_mii_intr(struct net_device *dev) + +#define PHY_POLL_LINK_ON (1 * HZ) +#define PHY_POLL_LINK_OFF (HZ / 5) + +static int fec_mii_read(struct mii_bus *bus, int phy_id, int regnum); + +#ifdef CONFIG_PHYLIB +static void fec_link_change(struct net_device *dev) { - if (request_irq(66, mii_link_interrupt, IRQF_DISABLED, "fec(MII)", dev) != 0) - printk("FEC: Could not allocate fec(MII) IRQ(66)!\n"); -} + struct fec_enet_private *fep = netdev_priv(dev); + struct phy_device *phydev = fep->phy; -static void __inline__ fec_disable_phy_intr(void) + if (phydev->link != fep->linkstatus || + phydev->duplex != fep->full_duplex) { + DBG(0, "%s: link status changed from %d to %d %s -> %s duplex\n", __FUNCTION__, + fep->linkstatus, phydev->link, fep->full_duplex ? "full" : "half", + phydev->duplex ? "full" : "half"); + if (phydev->link) { + fec_restart(dev, phydev->duplex); + } else { + fec_stop(dev); + } + if (fep->linkstatus != phydev->link && netif_msg_link(fep)) { + phy_print_status(phydev); + } + fep->linkstatus = phydev->link; +#if 0 + int i; + for (i = 0; i < 32; i++) { + DBG(0, "%s: PHY reg[%02x]=%04x\n", __FUNCTION__, i, + fec_mii_read(fep->mii, fep->phy_addr, i)); + } +#endif + } +} +#else +static void fec_link_change(struct net_device *dev) { - volatile unsigned long *icrp; - icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); - *icrp = 0x08000000; + struct fec_enet_private *fep = netdev_priv(dev); + + DBG(0, "%s: link status changed from %d to %d\n", __FUNCTION__, + fep->old_linkstatus, fep->linkstatus); + if (fep->linkstatus) { + int duplex; + + duplex = 0; + if (fep->phy_status & (PHY_STAT_100FDX | PHY_STAT_10FDX)) { + duplex = 1; + } + fec_restart(dev, duplex); + if (fep->phy_timer) { + mod_timer(fep->phy_timer, jiffies + PHY_POLL_LINK_ON); + } + } else { + fec_stop(dev); + if (fep->phy_timer) { + mod_timer(fep->phy_timer, jiffies + PHY_POLL_LINK_OFF); + } + } + + fep->old_linkstatus = fep->linkstatus; } -static void __inline__ fec_phy_ack_intr(void) +static void fec_phy_timer(unsigned long data) { - volatile unsigned long *icrp; - /* Acknowledge the interrupt */ - icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); - *icrp = 0x0d000000; + struct net_device *dev = (struct net_device *)data; + struct fec_enet_private *fep = netdev_priv(dev); + int link_poll_interval = fep->linkstatus ? PHY_POLL_LINK_ON : PHY_POLL_LINK_OFF; + + if (fep->old_linkstatus != fep->linkstatus) { + fec_link_change(dev); + } + mod_timer(fep->phy_timer, link_poll_interval); } #endif -#ifdef CONFIG_M5272 -static void __inline__ fec_get_mac(struct net_device *dev) +/* + * Code specific to Freescale i.MXC + */ +static int fec_request_intrs(struct platform_device *pdev, struct net_device *dev) { + int ret; struct fec_enet_private *fep = netdev_priv(dev); - volatile fec_t *fecp; - unsigned char *iap, tmpaddr[ETH_ALEN]; - fecp = fep->hwp; + fep->etn_irq = platform_get_irq(pdev, 0); + fep->mii_irq = platform_get_irq(pdev, 1); - if (FEC_FLASHMAC) { + /* Setup interrupt handlers. */ + ret = request_irq(fep->etn_irq, fec_enet_interrupt, 0, "fec", dev); + if (ret != 0) { + printk(KERN_ERR "FEC: Could not allocate FEC IRQ(%d)!\n", fep->etn_irq); + return ret; + } +#ifndef CONFIG_PHYLIB + if (fep->mii_irq >= 0) { + /* TODO: disable now due to CPLD issue */ + ret = request_irq(fep->mii_irq, mii_link_interrupt, 0, "fec(MII)", dev); + if (ret != 0) { + printk(KERN_ERR "FEC: Could not allocate FEC(MII) IRQ(%d)!\n", + fep->mii_irq); + free_irq(fep->etn_irq, dev); + return ret; + } /* - * Get MAC address from FLASH. - * If it is all 1's or 0's, use the default. + * board specific workaround should be done in board specific code + * This is unsafe anyway. An interrupt might have been asserted + * already. Use IRQ_NOAUTOEN with request_irq() to have irq initially disabled. */ - iap = (unsigned char *)FEC_FLASHMAC; - if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && - (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) - iap = fec_mac_default; - if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) && - (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) - iap = fec_mac_default; + fep->phy_int_enabled = 1; } else { - *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; - *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); - iap = &tmpaddr[0]; + fep->phy_timer = kzalloc(sizeof(struct timer_list), GFP_KERNEL); + if (fep->phy_timer == NULL) { + free_irq(fep->etn_irq, dev); + return -ENOMEM; + } + init_timer(fep->phy_timer); + fep->phy_timer->function = fec_phy_timer; + fep->phy_timer->data = (unsigned long)dev; + fec_link_change(dev); } - - memcpy(dev->dev_addr, iap, ETH_ALEN); - - /* Adjust MAC if using default MAC address */ - if (iap == fec_mac_default) - dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; -} #endif -/* ------------------------------------------------------------------------- */ + return 0; +} -static void mii_display_status(struct net_device *dev) +static void fec_release_intrs(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile uint *s = &(fep->phy_status); - if (!fep->link && !fep->old_link) { - /* Link is still down - don't print anything */ - return; + free_irq(fep->etn_irq, dev); +#ifndef CONFIG_PHYLIB + if (fep->mii_irq >= 0) { + free_irq(fep->mii_irq, dev); } +#endif +} - printk("%s: status: ", dev->name); - - if (!fep->link) { - printk("link down"); - } else { - printk("link up"); - - switch(*s & PHY_STAT_SPMASK) { - case PHY_STAT_100FDX: printk(", 100MBit Full Duplex"); break; - case PHY_STAT_100HDX: printk(", 100MBit Half Duplex"); break; - case PHY_STAT_10FDX: printk(", 10MBit Full Duplex"); break; - case PHY_STAT_10HDX: printk(", 10MBit Half Duplex"); break; - default: - printk(", Unknown speed/duplex"); - } +#ifdef CONFIG_MACH_MX25 +/* + * i.MX25 allows RMII mode to be configured via a gasket + */ +#define FEC_MIIGSK_CFGR 0x300 +#define FEC_MIIGSK_ENR 0x308 - if (*s & PHY_STAT_ANC) - printk(", auto-negotiation complete"); - } +#define FEC_MIIGSK_CFGR_FRCONT (1 << 6) +#define FEC_MIIGSK_CFGR_LBMODE (1 << 4) +#define FEC_MIIGSK_CFGR_EMODE (1 << 3) +#define FEC_MIIGSK_CFGR_IF_MODE_MASK (3 << 0) +#define FEC_MIIGSK_CFGR_IF_MODE_MII (0 << 0) +#define FEC_MIIGSK_CFGR_IF_MODE_RMII (1 << 0) - if (*s & PHY_STAT_FAULT) - printk(", remote fault"); +#define FEC_MIIGSK_ENR_READY (1 << 2) +#define FEC_MIIGSK_ENR_EN (1 << 1) - printk(".\n"); +#ifndef DEBUG +static inline unsigned long fec_reg_read16(struct fec_enet_private *fep, unsigned int reg) +{ + return readw(fep->reg_base + reg); } -static void mii_display_config(struct work_struct *work) +static inline void fec_reg_write(struct fec_enet_private *fep, unsigned int reg, unsigned long val) { - struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task); - struct net_device *dev = fep->netdev; - uint status = fep->phy_status; + writew(val, fep->reg_base + reg); +} +#else +#define fec_reg_read16(fep, reg) __fec_reg_read16(fep, reg, __FUNCTION__, #reg) +#define fec_reg_write16(fep, reg, val) __fec_reg_write16(fep, reg, val, __FUNCTION__, #reg) + +static inline u16 __fec_reg_read16(struct fec_enet_private *fep, unsigned int reg, + const char *func, const char *reg_name) +{ + u16 val = readw(fep->reg_base + reg); + DBG(0, "%s: Read %04x from %s(%03x)\n", func, val, reg_name, reg); + return val; +} + +static inline void __fec_reg_write16(struct fec_enet_private *fep, unsigned int reg, + u16 val, const char *func, const char *reg_name) +{ + DBG(0, "%s: Writing %04x to %s(%03x)\n", func, val, reg_name, reg); + writew(val, fep->reg_base + reg); +} +#endif + +static void fec_localhw_setup(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + int loops; + const int max_loops = 10000; + + /* + * Set up the MII gasket for RMII mode + */ + dev_dbg(&dev->dev, "enable RMII gasket\n"); + + /* disable the gasket and wait */ + fec_reg_write16(fep, FEC_MIIGSK_ENR, 0); + DBG(0, "%s: Waiting for RMII gasket idle\n", __FUNCTION__); + while (fec_reg_read16(fep, FEC_MIIGSK_ENR) & FEC_MIIGSK_ENR_READY) + udelay(1); + DBG(0, "%s: RMII gasket idle\n", __FUNCTION__); + + /* configure the gasket for RMII, 50 MHz, no loopback, no echo */ + fec_reg_write16(fep, FEC_MIIGSK_CFGR, FEC_MIIGSK_CFGR_IF_MODE_RMII); + + /* re-enable the gasket */ + fec_reg_write16(fep, FEC_MIIGSK_ENR, FEC_MIIGSK_ENR_EN); + fec_reg_read16(fep, FEC_MIIGSK_CFGR); + fec_reg_read16(fep, FEC_MIIGSK_ENR); + +#if 1 + DBG(0, "%s: Waiting for RMII gasket ready\n", __FUNCTION__); + for (loops = 0; loops < max_loops; loops++) { + if (readw(fep->reg_base + FEC_MIIGSK_ENR) & FEC_MIIGSK_ENR_READY) + break; + udelay(1); + } + if (fec_reg_read16(fep, FEC_MIIGSK_ENR) & FEC_MIIGSK_ENR_READY) { + DBG(0, "%s: RMII gasket ready after %u loops\n", __FUNCTION__, loops); + } else { + DBG(0, "%s: RMII gasket NOT ready after %u loops\n", __FUNCTION__, loops); + } +#endif +} +#else +static inline void fec_localhw_setup(struct net_device *dev) +{ +} +#endif + +static int fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) +{ + unsigned long rate; + struct clk *clk; + + DBG(0, "%s: \n", __FUNCTION__); + + fec_reg_write(fep, FEC_RCR, OPT_FRAME_SIZE | RCR_MII_MODE); + fec_reg_write(fep, FEC_TCR, 0x00); + + /* + * Set MII speed to 2.5 MHz + */ + clk = clk_get(fep->dma_dev, NULL); + if (!IS_ERR(clk)) { + rate = clk_get_rate(clk); + clk_put(clk); + } else { + printk(KERN_ERR "Failed to get fec clock: %ld\n", PTR_ERR(clk)); + return PTR_ERR(clk); + } + fep->phy_speed = ((((rate + 4999999) / 2500000) / 2) & 0x3F) << 1; + fec_reg_write(fep, FEC_MSCR, fep->phy_speed); + DBG(0, "%s: clkdiv set to %u for MII clock %u at base clock %lu\n", + __FUNCTION__, fep->phy_speed >> 1, 2500000, rate); + DBG(0, "%s: actual MII clock is: %lu\n", __FUNCTION__, rate / (fep->phy_speed)); + + return 0; +} + +static const unsigned char default_mac[ETH_ALEN] = { + 0x00, 0x04, 0x9f, 0x00, 0x74, 0x4a, +}; + +#define FEC_IIM_BASE IO_ADDRESS(IIM_BASE_ADDR) +static void fec_get_mac(struct net_device *dev) +{ +#if 1 + // keep bootloader assigned MAC address + struct fec_enet_private *fep = netdev_priv(dev); + unsigned long eth_addr = fec_reg_read(fep, FEC_PALR); + dev->dev_addr[0] = eth_addr >> 24; + dev->dev_addr[1] = eth_addr >> 16; + dev->dev_addr[2] = eth_addr >> 8; + dev->dev_addr[3] = eth_addr >> 0; + eth_addr = fec_reg_read(fep, FEC_PAUR); + dev->dev_addr[5] = eth_addr >> 16; + dev->dev_addr[4] = eth_addr >> 24; +#else + int i; + unsigned long fec_mac_base = FEC_IIM_BASE + MXC_IIMKEY0; + + if (cpu_is_mx27_rev(CHIP_REV_2_0) > 0) { + fec_mac_base = FEC_IIM_BASE + MXC_IIMMAC; + } + + DBG(0, "%s: Reading MAC address from %08lx\n", __FUNCTION__, fec_mac_base); + for (i = 0; i < ETH_ALEN; i++) { + dev->dev_addr[ETH_ALEN - 1 - i] = __raw_readb(fec_mac_base + i * 4); + } + //memcpy(dev->dev_addr, default_mac, ETH_ALEN); +#endif +} + +#ifdef CONFIG_PHYLIB +static inline void fec_enable_phy_intr(struct fec_enet_private *fep) +{ +} +static inline void fec_disable_phy_intr(struct fec_enet_private *fep) +{ +} +static inline void fec_phy_ack_intr(struct fec_enet_private *fep) +{ +} +#else +static inline void fec_enable_phy_intr(struct fec_enet_private *fep) +{ + if (!fep->phy_int_enabled) { + fep->phy_int_enabled = 1; + enable_irq(fep->mii_irq); + } +} + +static inline void fec_disable_phy_intr(struct fec_enet_private *fep) +{ + if (fep->phy_int_enabled) { + disable_irq(fep->mii_irq); + fep->phy_int_enabled = 0; + } +} + +static inline void fec_phy_ack_intr(struct fec_enet_private *fep) +{ + if (fep->phy_int_enabled) { + disable_irq(fep->mii_irq); + fep->phy_int_enabled = 0; + } +} +#endif + +/* ------------------------------------------------------------------------- */ + +#ifndef CONFIG_PHYLIB +static void mii_display_status(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + + if (!fep->linkstatus && !fep->old_linkstatus) { + /* Link is still down - don't print anything */ + return; + } + + printk("%s: status: ", dev->name); + + if (!fep->linkstatus) { + printk("link down"); + } else { + printk("link up"); + + switch(fep->phy_status & PHY_STAT_SPMASK) { + case PHY_STAT_100FDX: printk(", 100MBit Full Duplex"); break; + case PHY_STAT_100HDX: printk(", 100MBit Half Duplex"); break; + case PHY_STAT_10FDX: printk(", 10MBit Full Duplex"); break; + case PHY_STAT_10HDX: printk(", 10MBit Half Duplex"); break; + default: + printk(", Unknown speed/duplex"); + } + + if (fep->phy_status & PHY_STAT_ANC) + printk(", auto-negotiation complete"); + } + + if (fep->phy_status & PHY_STAT_FAULT) + printk(", remote fault"); + + printk(".\n"); +} + +static void mii_display_config(struct work_struct *w) +{ + struct fec_enet_private *fep = container_of(w, struct fec_enet_private, phy_task); + uint status = fep->phy_status; /* ** When we get here, phy_task is already removed from ** the workqueue. It is thus safe to allow to reuse it. */ fep->mii_phy_task_queued = 0; - printk("%s: config: auto-negotiation ", dev->name); + //printk("%s: config: auto-negotiation ", dev->name); if (status & PHY_CONF_ANE) printk("on"); @@ -1351,11 +1878,21 @@ static void mii_display_config(struct wo fep->sequence_done = 1; } +#endif -static void mii_relink(struct work_struct *work) +#ifndef CONFIG_PHYLIB +static inline void *priv_netdev(struct fec_enet_private *fep) { - struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task); - struct net_device *dev = fep->netdev; + /* ugly hack, stolen from include linux/netdevice.h */ + return (char *)fep - ((sizeof(struct net_device) + + NETDEV_ALIGN_CONST) + & ~NETDEV_ALIGN_CONST); +} + +static void mii_relink(struct work_struct *w) +{ + struct fec_enet_private *fep = container_of(w, struct fec_enet_private, phy_task); + struct net_device *dev = priv_netdev(fep); int duplex; /* @@ -1363,23 +1900,19 @@ static void mii_relink(struct work_struc ** the workqueue. It is thus safe to allow to reuse it. */ fep->mii_phy_task_queued = 0; - fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0; + fep->linkstatus = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0; mii_display_status(dev); - fep->old_link = fep->link; + fep->old_linkstatus = fep->linkstatus; - if (fep->link) { + if (fep->linkstatus) { duplex = 0; - if (fep->phy_status - & (PHY_STAT_100FDX | PHY_STAT_10FDX)) + if (fep->phy_status & (PHY_STAT_100FDX | PHY_STAT_10FDX)) { duplex = 1; + } fec_restart(dev, duplex); - } else + } else { fec_stop(dev); - -#if 0 - enable_irq(fep->mii_irq); -#endif - + } } /* mii_queue_relink is called in interrupt context from mii_link_interrupt */ @@ -1429,15 +1962,14 @@ phy_cmd_t const phy_cmd_config[] = { static void mii_discover_phy3(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep; + struct fec_enet_private *fep = netdev_priv(dev); int i; - fep = netdev_priv(dev); fep->phy_id |= (mii_reg & 0xffff); printk("fec: PHY @ 0x%x, ID 0x%08x", fep->phy_addr, fep->phy_id); - for(i = 0; phy_info[i]; i++) { - if(phy_info[i]->id == (fep->phy_id >> 4)) + for (i = 0; phy_info[i]; i++) { + if (phy_info[i]->id == (fep->phy_id >> 4)) break; } @@ -1456,13 +1988,9 @@ mii_discover_phy3(uint mii_reg, struct n static void mii_discover_phy(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep; - volatile fec_t *fecp; + struct fec_enet_private *fep = netdev_priv(dev); uint phytype; - fep = netdev_priv(dev); - fecp = fep->hwp; - if (fep->phy_addr < 32) { if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) { @@ -1470,39 +1998,40 @@ mii_discover_phy(uint mii_reg, struct ne */ fep->phy_id = phytype << 16; mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), - mii_discover_phy3); + mii_discover_phy3); } else { fep->phy_addr++; mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), - mii_discover_phy); + mii_discover_phy); } } else { printk("FEC: No PHY device found.\n"); /* Disable external MII interface */ - fecp->fec_mii_speed = fep->phy_speed = 0; -#ifdef HAVE_mii_link_interrupt - fec_disable_phy_intr(); -#endif + fec_disable_phy_intr(fep); + fec_reg_write(fep, FEC_MSCR, 0); } } +#endif -/* This interrupt occurs when the PHY detects a link change. -*/ -#ifdef HAVE_mii_link_interrupt +#ifndef CONFIG_PHYLIB static irqreturn_t -mii_link_interrupt(int irq, void * dev_id) +mii_link_interrupt(int irq, void *dev_id) { - struct net_device *dev = dev_id; + struct net_device *dev = dev_id; struct fec_enet_private *fep = netdev_priv(dev); - fec_phy_ack_intr(); + DBG(0, "%s: \n", __FUNCTION__); -#if 0 - disable_irq(fep->mii_irq); /* disable now, enable later */ -#endif + fec_phy_ack_intr(fep); - mii_do_cmd(dev, fep->phy->ack_int); - mii_do_cmd(dev, phy_cmd_relink); /* restart and display status */ + /* + * Some board will trigger phy interrupt before phy enable. + * And at that moment , fep->phy is not initialized. + */ + if (fep->phy) { + mii_do_cmd(dev, fep->phy->ack_int); + mii_do_cmd(dev, phy_cmd_relink); /* restart and display status */ + } return IRQ_HANDLED; } @@ -1511,16 +2040,31 @@ mii_link_interrupt(int irq, void * dev_i static int fec_enet_open(struct net_device *dev) { + int ret = 0; struct fec_enet_private *fep = netdev_priv(dev); /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. */ - fec_set_mac_address(dev); + DBG(0, "%s: \n", __FUNCTION__); + _fec_set_mac_address(dev); - fep->sequence_done = 0; - fep->link = 0; +#ifdef CONFIG_PHYLIB + fec_restart(dev, 0); + ret = fec_connect_phy(dev, fep); + if (ret != 0) { + DBG(0, "%s: Failed to connect to PHY: %d\n", __FUNCTION__, ret); + return ret; + } + phy_start(fep->phy); + + fep->linkstatus = fep->phy->link; + //fec_restart(dev, 0); + DBG(0, "%s: Link status is: %d\n", __FUNCTION__, fep->linkstatus); +#else + fep->linkstatus = 0; + fep->sequence_done = 0; if (fep->phy) { mii_do_cmd(dev, fep->phy->ack_int); mii_do_cmd(dev, fep->phy->config); @@ -1542,16 +2086,20 @@ fec_enet_open(struct net_device *dev) * based on this device does not implement a PHY interrupt, * so we are never notified of link change. */ - fep->link = 1; + fep->linkstatus = 1; } else { - fep->link = 1; /* lets just try it and see */ + fep->linkstatus = 1; /* lets just try it and see */ /* no phy, go full duplex, it's most likely a hub chip */ fec_restart(dev, 1); } - - netif_start_queue(dev); + fep->old_linkstatus = fep->linkstatus; +#endif fep->opened = 1; - return 0; /* Success */ +#if 1 + /* enable receiver */ + fec_reg_write(fep, FEC_RDAR, DONT_CARE); +#endif + return ret; } static int @@ -1559,15 +2107,46 @@ fec_enet_close(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - /* Don't know what to do yet. - */ + DBG(0, "%s: \n", __FUNCTION__); + fep->opened = 0; - netif_stop_queue(dev); - fec_stop(dev); + if (fep->linkstatus) { + fec_stop(dev); + } +#ifdef CONFIG_PHYLIB + if (fep->phy) { + DBG(0, "%s: Stopping PHY %p\n", __FUNCTION__, fep->phy); + phy_stop(fep->phy); + DBG(0, "%s: Disconnecting PHY %p\n", __FUNCTION__, fep->phy); + phy_disconnect(fep->phy); + fep->phy = NULL; + } +#endif +#if 1 + /* Whack a reset. We should wait for this. + */ + fec_reg_write(fep, FEC_ECR, FEC_ECR_RESET); + udelay(10); + + /* Mask and clear outstanding MII command interrupts. + */ + fec_reg_write(fep, FEC_EIMR, 0); + fec_reg_write(fep, FEC_EIR, FEC_ENET_MII); + fec_disable_phy_intr(fep); + /* Switch off MII */ + fec_reg_write(fep, FEC_MSCR, 0); +#endif return 0; } +static struct net_device_stats *fec_enet_get_stats(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + + return &fep->stats; +} + /* Set or clear the multicast filter for this adaptor. * Skeleton taken from sunlance driver. * The CPM Ethernet implementation allows Multicast as well as individual @@ -1583,37 +2162,32 @@ fec_enet_close(struct net_device *dev) static void set_multicast_list(struct net_device *dev) { - struct fec_enet_private *fep; - volatile fec_t *ep; + struct fec_enet_private *fep = netdev_priv(dev); struct dev_mc_list *dmi; unsigned int i, j, bit, data, crc; unsigned char hash; - fep = netdev_priv(dev); - ep = fep->hwp; - - if (dev->flags&IFF_PROMISC) { - ep->fec_r_cntrl |= 0x0008; + if (dev->flags & IFF_PROMISC) { + fec_reg_write(fep, FEC_RCR, fec_reg_read(fep, FEC_RCR) | RCR_PROM); } else { - ep->fec_r_cntrl &= ~0x0008; + fec_reg_write(fep, FEC_RCR, fec_reg_read(fep, FEC_RCR) & ~RCR_PROM); if (dev->flags & IFF_ALLMULTI) { /* Catch all multicast addresses, so set the * filter to all 1's. */ - ep->fec_grp_hash_table_high = 0xffffffff; - ep->fec_grp_hash_table_low = 0xffffffff; + fec_reg_write(fep, FEC_IAUR, ~0); + fec_reg_write(fep, FEC_IALR, ~0); } else { /* Clear filter and add the addresses in hash register. */ - ep->fec_grp_hash_table_high = 0; - ep->fec_grp_hash_table_low = 0; + fec_reg_write(fep, FEC_IAUR, 0); + fec_reg_write(fep, FEC_IALR, 0); dmi = dev->mc_list; - for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) - { + for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) { /* Only support group multicast for now. */ if (!(dmi->dmi_addr[0] & 1)) @@ -1621,13 +2195,11 @@ static void set_multicast_list(struct ne /* calculate crc32 value of mac address */ - crc = 0xffffffff; + crc = ~0; - for (i = 0; i < dmi->dmi_addrlen; i++) - { + for (i = 0; i < dmi->dmi_addrlen; i++) { data = dmi->dmi_addr[i]; - for (bit = 0; bit < 8; bit++, data >>= 1) - { + for (bit = 0; bit < 8; bit++, data >>= 1) { crc = (crc >> 1) ^ (((crc ^ data) & 1) ? CRC32_POLY : 0); } @@ -1639,9 +2211,13 @@ static void set_multicast_list(struct ne hash = (crc >> (32 - HASH_BITS)) & 0x3f; if (hash > 31) - ep->fec_grp_hash_table_high |= 1 << (hash - 32); + fec_reg_write(fep, FEC_IAUR, + fec_reg_read(fep, FEC_IAUR) | + (1 << (hash - 32))); else - ep->fec_grp_hash_table_low |= 1 << hash; + fec_reg_write(fep, FEC_IALR, + fec_reg_read(fep, FEC_IALR) | + (1 << hash)); } } } @@ -1650,106 +2226,272 @@ static void set_multicast_list(struct ne /* Set a MAC change in hardware. */ static void -fec_set_mac_address(struct net_device *dev) +_fec_set_mac_address(struct net_device *dev) { - volatile fec_t *fecp; - - fecp = ((struct fec_enet_private *)netdev_priv(dev))->hwp; + struct fec_enet_private *fep = netdev_priv(dev); /* Set station address. */ - fecp->fec_addr_low = dev->dev_addr[3] | (dev->dev_addr[2] << 8) | - (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24); - fecp->fec_addr_high = (dev->dev_addr[5] << 16) | - (dev->dev_addr[4] << 24); + fec_reg_write(fep, FEC_PALR, dev->dev_addr[3] | (dev->dev_addr[2] << 8) | + (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24)); + fec_reg_write(fep, FEC_PAUR, (dev->dev_addr[5] << 16) | + (dev->dev_addr[4] << 24)); +} +static int +fec_set_mac_address(struct net_device *dev, void *_addr) +{ + struct sockaddr *addr = _addr; + + if (!is_valid_ether_addr((const char *)&addr->sa_data)) { + printk(KERN_WARNING "Bad ethernet address: %02x:%02x:%02x:%02x:%02x:%02x\n", + addr->sa_data[0], addr->sa_data[1], addr->sa_data[2], addr->sa_data[3], + addr->sa_data[4], addr->sa_data[5]); + return -EINVAL; + } + printk(KERN_DEBUG "Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", + addr->sa_data[0], addr->sa_data[1], addr->sa_data[2], addr->sa_data[3], + addr->sa_data[4], addr->sa_data[5]); + + memcpy(&dev->dev_addr, &addr->sa_data, ETH_ALEN); + + _fec_set_mac_address(dev); + + return 0; } - /* - * XXX: We need to clean up on failure exits here. - * - * index is only used in legacy code - */ -int __init fec_enet_init(struct net_device *dev, int index) +static void fec_enet_free_buffers(struct fec_enet_private *fep) +{ + cbd_t *bdp = fep->rx_bd_base; + int i; + + DBG(0, "%s: Freeing TX bounce buffers %p\n", __FUNCTION__, fep->tx_bounce[0]); + kfree(fep->tx_bounce[0]); + memset(fep->tx_bounce, 0, TX_RING_SIZE * sizeof(void*)); + for (i = 0; i < RX_RING_SIZE; i++, bdp++) { + if (fep->rx_skbuff[i] != NULL) { + DBG(0, "%s: Freeing RX skb %p\n", __FUNCTION__, fep->rx_skbuff[i]); + fec_enet_rxbuf_unmap(fep, bdp, FEC_ENET_RX_FRSIZE); + kfree_skb(fep->rx_skbuff[i]); + fep->rx_skbuff[i] = NULL; + } + } +} + +#ifdef CONFIG_PHYLIB +/* called by the generic PHY layer in interrupt context */ +static int phy_regs[32] = { [0 ... ARRAY_SIZE(phy_regs) - 1] = -1}; +static int fec_mii_read(struct mii_bus *bus, int phy_id, int regnum) { + int ret; + struct net_device *dev = bus->priv; struct fec_enet_private *fep = netdev_priv(dev); - unsigned long mem_addr; - volatile cbd_t *bdp; - cbd_t *cbd_base; - volatile fec_t *fecp; - int i, j; + unsigned long regval = mk_mii_read(regnum) | phy_id << 23; + unsigned long flags; + int loops = 0; - /* Allocate memory for buffer descriptors. - */ - mem_addr = (unsigned long)dma_alloc_coherent(NULL, PAGE_SIZE, - &fep->bd_dma, GFP_KERNEL); - if (mem_addr == 0) { - printk("FEC: allocate descriptor memory failed?\n"); + DBG(1, "%s: \n", __FUNCTION__); +#if 0 + DBG(0, "%s: ECR: %08lx\n", __FUNCTION__, fec_reg_read(fep, FEC_ECR)); + DBG(0, "%s: EIR: %08lx\n", __FUNCTION__, fec_reg_read(fep, FEC_EIR)); + DBG(0, "%s: EIMR: %08lx\n", __FUNCTION__, fec_reg_read(fep, FEC_EIMR)); + DBG(0, "%s: RCR: %08lx\n", __FUNCTION__, fec_reg_read(fep, FEC_RCR)); + DBG(0, "%s: TCR: %08lx\n", __FUNCTION__, fec_reg_read(fep, FEC_TCR)); +#endif + spin_lock_irqsave(&fep->lock, flags); + fep->mii_complete = 0; + fec_reg_write(fep, FEC_MMFR, regval); + spin_unlock_irqrestore(&fep->lock, flags); + + while (!fep->mii_complete) { + if (loops++ == 1000) { + DBG(1, "%s: Waiting for MII completion\n", __FUNCTION__); + } + cpu_relax(); + } + if (loops >= 1000) { + DBG(1, "%s: MII transaction completed\n", __FUNCTION__); + } + ret = fec_reg_read(fep, FEC_MMFR); + if (ret < 0) { + DBG(0, "%s: Failed to read PHY[%02x] reg %02x: %d\n", __FUNCTION__, + phy_id, regnum, ret); + return ret; + } + ret &= 0xffff; + if (phy_regs[regnum] != ret) { + DBG(1, "%s: Read %04x from PHY[%02x] reg %02x\n", __FUNCTION__, + ret, phy_id, regnum); + phy_regs[regnum] = ret; + } + return ret; +} + +static int fec_mii_write(struct mii_bus *bus, int phy_id, int regnum, u16 val) +{ + struct net_device *dev = bus->priv; + struct fec_enet_private *fep = netdev_priv(dev); + unsigned long regval = mk_mii_write(regnum, val) | phy_id << 23; + unsigned long flags; + + DBG(0, "%s: \n", __FUNCTION__); + + spin_lock_irqsave(&fep->lock, flags); + fep->mii_complete = 0; + fec_reg_write(fep, FEC_MMFR, regval); + spin_unlock_irqrestore(&fep->lock, flags); + + while (!fep->mii_complete) { + cpu_relax(); + } + DBG(1, "%s: Wrote %04x to PHY[%02x] reg %02x\n", __FUNCTION__, val, phy_id, regnum); + return 0; +} + +static int fec_mii_reset(struct mii_bus *bus) +{ + DBG(0, "%s: \n", __FUNCTION__); + memset(phy_regs, -1, sizeof(phy_regs)); + return 0; +} + +static int fec_init_phy(struct net_device *dev, struct fec_enet_private *fep) +{ + int ret; + int i; + struct mii_bus *mii; + + mii = mdiobus_alloc(); + if (mii == NULL) { return -ENOMEM; } + mii->name = "fec mii"; + mii->read = fec_mii_read; + mii->write = fec_mii_write; + mii->reset = fec_mii_reset; + mii->priv = dev; + snprintf(mii->id, MII_BUS_ID_SIZE, "%x", 0); + mii->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + for (i = 0; i < PHY_MAX_ADDR; i++) { + mii->irq[i] = fep->mii_irq >= 0 ? fep->mii_irq : PHY_POLL; + } + + ret = mdiobus_register(mii); + if (ret != 0) { + DBG(0, "%s: Failed to register MII bus: %d\n", __FUNCTION__, ret); + kfree(mii->irq); + mdiobus_free(mii); + return ret; + } + fep->phy_addr = -1; + DBG(0, "%s: MII bus registered\n", __FUNCTION__); + for (i = 0; i < PHY_MAX_ADDR; i++) { + if (mii->phy_map[i] != NULL) { + fep->phy_addr = i; + break; + } + } + if (fep->phy_addr == -1) { + DBG(0, "%s: No PHY found\n", __FUNCTION__); + return -ENODEV; + } + DBG(0, "%s: Using PHY at addr %02x\n", __FUNCTION__, fep->phy_addr); + fep->mii = mii; - spin_lock_init(&fep->hw_lock); - spin_lock_init(&fep->mii_lock); + return 0; +} - /* Create an Ethernet device instance. - */ - fecp = (volatile fec_t *)dev->base_addr; +static int fec_connect_phy(struct net_device *dev, struct fec_enet_private *fep) +{ + struct mii_bus *mii = fep->mii; - fep->index = index; - fep->hwp = fecp; - fep->netdev = dev; + DBG(0, "%s: Connecting PHY at addr %02x\n", __FUNCTION__, + fep->phy_addr); - /* Whack a reset. We should wait for this. - */ - fecp->fec_ecntrl = 1; - udelay(10); + fep->phy = phy_connect(dev, dev_name(&mii->phy_map[fep->phy_addr]->dev), + fec_link_change, 0, mii->phy_map[fep->phy_addr]->interface); + if (IS_ERR(fep->phy)) { + int ret = PTR_ERR(fep->phy); + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); + fep->phy = NULL; + return ret; + } + DBG(0, "%s: Registered PHY %s[%02x] IRQ %d with %s\n", __FUNCTION__, + dev_name(&fep->phy->dev), fep->phy_addr, fep->phy->irq, dev->name); - /* Set the Ethernet address */ -#ifdef CONFIG_M5272 - fec_get_mac(dev); + return 0; +} #else - { - unsigned long l; - l = fecp->fec_addr_low; - dev->dev_addr[0] = (unsigned char)((l & 0xFF000000) >> 24); - dev->dev_addr[1] = (unsigned char)((l & 0x00FF0000) >> 16); - dev->dev_addr[2] = (unsigned char)((l & 0x0000FF00) >> 8); - dev->dev_addr[3] = (unsigned char)((l & 0x000000FF) >> 0); - l = fecp->fec_addr_high; - dev->dev_addr[4] = (unsigned char)((l & 0xFF000000) >> 24); - dev->dev_addr[5] = (unsigned char)((l & 0x00FF0000) >> 16); - } +static int fec_init_phy(struct net_device *dev, struct fec_enet_private *fep) +{ + /* Queue up command to detect the PHY and initialize the + * remainder of the interface. + */ + fep->phy_id_done = 0; + fep->phy_addr = 0; + mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); + + return 0; +} #endif - cbd_base = (cbd_t *)mem_addr; +/* Initialize the FEC Ethernet on 860T (or ColdFire 5272). + */ + /* + * XXX: We need to clean up on failure exits here. + */ + +int __devinit fec_enet_init(struct platform_device *pdev, struct net_device *dev) +{ + int ret; + struct fec_enet_private *fep = netdev_priv(dev); + cbd_t *bdp; + struct sk_buff *pskb; + int i; + void *mem; - /* Set receive and transmit descriptor base. + spin_lock_init(&fep->lock); + + /* Whack a reset. We should wait for this. */ - fep->rx_bd_base = cbd_base; - fep->tx_bd_base = cbd_base + RX_RING_SIZE; + fec_reg_write(fep, FEC_ECR, FEC_ECR_RESET); + udelay(10); + + /* Set the Ethernet address. If using multiple Enets on the 8xx, + * this needs some work to get unique addresses. + * + * This is our default MAC address unless the user changes + * it via eth_mac_addr (our dev->set_mac_addr handler). + */ + fec_get_mac(dev); fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; fep->cur_rx = fep->rx_bd_base; fep->skb_cur = fep->skb_dirty = 0; - /* Initialize the receive buffer descriptors. + /* allocate memory for TX bounce buffers */ + mem = kzalloc(TX_RING_SIZE * FEC_ENET_TX_FRSIZE, GFP_KERNEL); + if (mem == NULL) { + return -ENOMEM; + } + + fec_enet_cbd_get(fep); + + /* Initialize the transmit buffer descriptors. */ - bdp = fep->rx_bd_base; - for (i=0; itx_bd_base; - /* Allocate a page. - */ - mem_addr = __get_free_page(GFP_KERNEL); - /* XXX: missing check for allocation failure */ + DBG(0, "%s: Allocated %d byte of TX buffer memory @ %p\n", __FUNCTION__, + TX_RING_SIZE * FEC_ENET_TX_FRSIZE, mem); + for (i = 0; i < TX_RING_SIZE; i++) { + fep->tx_bounce[i] = mem; + DBG(0, "%s: TX bounce buffer[%d]=%p\n", __FUNCTION__, i, fep->tx_bounce[i]); + mem = (void *)((unsigned long)(mem + FEC_ENET_TX_FRSIZE)); /* Initialize the BD for every fragment in the page. */ - for (j=0; jcbd_sc = BD_ENET_RX_EMPTY; - bdp->cbd_bufaddr = __pa(mem_addr); - mem_addr += FEC_ENET_RX_FRSIZE; - bdp++; - } + bdp->cbd_bufaddr = ~0; + bdp++; } /* Set the last buffer to wrap. @@ -1757,87 +2499,88 @@ int __init fec_enet_init(struct net_devi bdp--; bdp->cbd_sc |= BD_SC_WRAP; - /* ...and the same for transmmit. + /* ...and the same for receive. */ - bdp = fep->tx_bd_base; - for (i=0, j=FEC_ENET_TX_FRPPG; i= FEC_ENET_TX_FRPPG) { - mem_addr = __get_free_page(GFP_KERNEL); - j = 1; - } else { - mem_addr += FEC_ENET_TX_FRSIZE; - j++; + bdp = fep->rx_bd_base; + for (i = 0; i < RX_RING_SIZE; i++, bdp++) { + pskb = __dev_alloc_skb(FEC_ENET_RX_FRSIZE, GFP_KERNEL); + if (pskb == NULL) { + DBG(0, "%s: Failed to allocate RX skb; cleaning up\n", __FUNCTION__); + ret = -ENOMEM; + goto cleanup; } - fep->tx_bounce[i] = (unsigned char *) mem_addr; - - /* Initialize the BD for every fragment in the page. - */ - bdp->cbd_sc = 0; - bdp->cbd_bufaddr = 0; - bdp++; + DBG(0, "%s: RX skb allocated @ %p\n", __FUNCTION__, pskb); + fep->rx_skbuff[i] = pskb; + pskb->data = FEC_ADDR_ALIGNMENT(pskb->data); + bdp->cbd_sc = BD_ENET_RX_EMPTY; + bdp->cbd_bufaddr = ~0; + fec_enet_rxbuf_map(fep, bdp, pskb->data, FEC_ENET_RX_FRSIZE); } - /* Set the last buffer to wrap. */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; + fec_enet_cbd_put(fep); /* Set receive and transmit descriptor base. */ - fecp->fec_r_des_start = fep->bd_dma; - fecp->fec_x_des_start = (unsigned long)fep->bd_dma + sizeof(cbd_t) - * RX_RING_SIZE; - -#ifdef HAVE_mii_link_interrupt - fec_request_mii_intr(dev); -#endif - - fecp->fec_grp_hash_table_high = 0; - fecp->fec_grp_hash_table_low = 0; - fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; - fecp->fec_ecntrl = 2; - fecp->fec_r_des_active = 0; -#ifndef CONFIG_M5272 - fecp->fec_hash_table_high = 0; - fecp->fec_hash_table_low = 0; -#endif + fec_reg_write(fep, FEC_ERDSR, fep->cbd_phys_base); + fec_reg_write(fep, FEC_ETDSR, fep->cbd_phys_base + RX_RING_SIZE * sizeof(cbd_t)); + /* Install our interrupt handlers. This varies depending on + * the architecture. + */ + ret = fec_request_intrs(pdev, dev); + if (ret != 0) { + goto cleanup; + } + /* Clear and enable interrupts */ + fec_reg_write(fep, FEC_EIR, fec_reg_read(fep, FEC_EIR)); + fec_reg_write(fep, FEC_EIMR, FEC_ENET_TXF | FEC_ENET_TXB | + FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); + + fec_reg_write(fep, FEC_IAUR, 0); + fec_reg_write(fep, FEC_IALR, 0); + fec_reg_write(fep, FEC_EMRBR, PKT_MAXBLR_SIZE); + fec_reg_write(fep, FEC_ECR, FEC_ECR_ETHER_EN); + fec_localhw_setup(dev); +#if 0 + /* do this in enet_open()! */ + fec_reg_write(fep, FEC_RDAR, DONT_CARE); +#endif /* The FEC Ethernet specific entries in the device structure. */ dev->open = fec_enet_open; dev->hard_start_xmit = fec_enet_start_xmit; dev->tx_timeout = fec_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->stop = fec_enet_close; + dev->get_stats = fec_enet_get_stats; dev->set_multicast_list = set_multicast_list; + dev->set_mac_address = fec_set_mac_address; - for (i=0; ifec_r_cntrl = OPT_FRAME_SIZE | 0x04; - fecp->fec_x_cntrl = 0x00; - - /* - * Set MII speed to 2.5 MHz - */ - fep->phy_speed = ((((clk_get_rate(fep->clk) / 2 + 4999999) - / 2500000) / 2) & 0x3F) << 1; - fecp->fec_mii_speed = fep->phy_speed; - fec_restart(dev, 0); - - /* Clear and enable interrupts */ - fecp->fec_ievent = 0xffc00000; - fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII); - - /* Queue up command to detect the PHY and initialize the - * remainder of the interface. - */ - fep->phy_id_done = 0; - fep->phy_addr = 0; - mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); + ret = fec_set_mii(dev, fep); + if (ret) { + DBG(0, "%s: Failed to initialize MII interface: %d\n", __FUNCTION__, ret); + goto cleanup; + } + ret = fec_init_phy(dev, fep); + if (ret) { + DBG(0, "%s: Failed to initialize PHY: %d\n", __FUNCTION__, ret); + goto cleanup; + } return 0; + cleanup: + fec_enet_free_buffers(fep); + fec_enet_cbd_put(fep); + return ret; } /* This function is called to start or restart the FEC during a link @@ -1847,60 +2590,67 @@ int __init fec_enet_init(struct net_devi static void fec_restart(struct net_device *dev, int duplex) { - struct fec_enet_private *fep; - volatile cbd_t *bdp; - volatile fec_t *fecp; + struct fec_enet_private *fep = netdev_priv(dev); + cbd_t *bdp; int i; + u32 rcr = OPT_FRAME_SIZE | RCR_MII_MODE; /* MII enable */ + u32 tcr = TCR_HBC; - fep = netdev_priv(dev); - fecp = fep->hwp; - + DBG(0, "%s: Restarting FEC in %s-duplex mode\n", __FUNCTION__, + duplex ? "full" : "half"); /* Whack a reset. We should wait for this. - */ - fecp->fec_ecntrl = 1; + */ + fec_reg_write(fep, FEC_ECR, FEC_ECR_RESET); udelay(10); + /* Enable interrupts we wish to service. + */ + fec_reg_write(fep, FEC_EIMR, FEC_ENET_TXF | FEC_ENET_TXB | + FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); + /* Clear any outstanding interrupt. - */ - fecp->fec_ievent = 0xffc00000; + * + */ + fec_reg_write(fep, FEC_EIR, FEC_ENET_MASK); + + fec_enable_phy_intr(fep); /* Set station address. - */ - fec_set_mac_address(dev); + */ + _fec_set_mac_address(dev); /* Reset all multicast. - */ - fecp->fec_grp_hash_table_high = 0; - fecp->fec_grp_hash_table_low = 0; + */ + fec_reg_write(fep, FEC_IAUR, 0); + fec_reg_write(fep, FEC_IALR, 0); /* Set maximum receive buffer size. - */ - fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; + */ + fec_reg_write(fep, FEC_EMRBR, PKT_MAXBLR_SIZE); /* Set receive and transmit descriptor base. - */ - fecp->fec_r_des_start = fep->bd_dma; - fecp->fec_x_des_start = (unsigned long)fep->bd_dma + sizeof(cbd_t) - * RX_RING_SIZE; + */ + fec_reg_write(fep, FEC_ERDSR, fep->cbd_phys_base); + fec_reg_write(fep, FEC_ETDSR, fep->cbd_phys_base + RX_RING_SIZE * sizeof(cbd_t)); fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; fep->cur_rx = fep->rx_bd_base; /* Reset SKB transmit buffers. - */ + */ fep->skb_cur = fep->skb_dirty = 0; - for (i=0; i<=TX_RING_MOD_MASK; i++) { + bdp = fep->tx_bd_base; + for (i = 0; i <= TX_RING_MOD_MASK; i++) { if (fep->tx_skbuff[i] != NULL) { - dev_kfree_skb_any(fep->tx_skbuff[i]); - fep->tx_skbuff[i] = NULL; + fec_free_skb(fep, bdp, &fep->tx_skbuff[i]); + bdp++; } } /* Initialize the receive buffer descriptors. - */ + */ bdp = fep->rx_bd_base; - for (i=0; icbd_sc = BD_ENET_RX_EMPTY; @@ -1908,246 +2658,365 @@ fec_restart(struct net_device *dev, int } /* Set the last buffer to wrap. - */ + */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; /* ...and the same for transmmit. - */ + */ bdp = fep->tx_bd_base; - for (i=0; icbd_sc = 0; - bdp->cbd_bufaddr = 0; + bdp->cbd_bufaddr = ~0; bdp++; } /* Set the last buffer to wrap. - */ + */ bdp--; bdp->cbd_sc |= BD_SC_WRAP; /* Enable MII mode. - */ + */ if (duplex) { - fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;/* MII enable */ - fecp->fec_x_cntrl = 0x04; /* FD enable */ + tcr |= TCR_FDEN; /* FD enable */ } else { - /* MII enable|No Rcv on Xmit */ - fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x06; - fecp->fec_x_cntrl = 0x00; + rcr |= RCR_DRT; /* No Rcv on Xmit */ } + fec_reg_write(fep, FEC_RCR, rcr); + fec_reg_write(fep, FEC_TCR, tcr); fep->full_duplex = duplex; /* Set MII speed. - */ - fecp->fec_mii_speed = fep->phy_speed; + */ + fec_reg_write(fep, FEC_MSCR, fep->phy_speed); /* And last, enable the transmit and receive processing. - */ - fecp->fec_ecntrl = 2; - fecp->fec_r_des_active = 0; + */ + fec_reg_write(fep, FEC_ECR, FEC_ECR_ETHER_EN); + fec_localhw_setup(dev); + fec_reg_write(fep, FEC_RDAR, DONT_CARE); - /* Enable interrupts we wish to service. - */ - fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII); + DBG(0, "%s: Starting netif queue\n", __FUNCTION__); + netif_start_queue(dev); } static void fec_stop(struct net_device *dev) { - volatile fec_t *fecp; - struct fec_enet_private *fep; + struct fec_enet_private *fep = netdev_priv(dev); - fep = netdev_priv(dev); - fecp = fep->hwp; + DBG(0, "%s: Stopping netif queue\n", __FUNCTION__); + netif_stop_queue(dev); /* - ** We cannot expect a graceful transmit stop without link !!! - */ - if (fep->link) - { - fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ + * We cannot expect a graceful transmit stop without link! + */ + if (fep->linkstatus) { + fec_reg_write(fep, FEC_TCR, 0x01); /* Graceful transmit stop */ udelay(10); - if (!(fecp->fec_ievent & FEC_ENET_GRA)) - printk("fec_stop : Graceful transmit stop did not complete !\n"); - } - + if (!(fec_reg_read(fep, FEC_EIR) & FEC_ENET_GRA)) + dev_warn(&dev->dev, "Graceful transmit stop did not complete!\n"); + } +#if 0 /* Whack a reset. We should wait for this. - */ - fecp->fec_ecntrl = 1; + */ + fec_reg_write(fep, FEC_ECR, FEC_ECR_RESET); udelay(10); - - /* Clear outstanding MII command interrupts. - */ - fecp->fec_ievent = FEC_ENET_MII; - - fecp->fec_imask = FEC_ENET_MII; - fecp->fec_mii_speed = fep->phy_speed; + /* Mask and clear outstanding MII command interrupts. + */ + fec_reg_write(fep, FEC_EIMR, 0); + fec_reg_write(fep, FEC_EIR, FEC_ENET_MII); + fec_enable_phy_intr(fep); + fec_reg_write(fep, FEC_MSCR, fep->phy_speed); +#endif } -static int __devinit -fec_probe(struct platform_device *pdev) +static int __devinit fec_enet_probe(struct platform_device *pdev) { + int ret; struct fec_enet_private *fep; - struct net_device *ndev; - int i, irq, ret = 0; - struct resource *r; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) - return -ENXIO; + struct net_device *dev; + struct fec_enet_platform_data *pdata = pdev->dev.platform_data; + struct resource *res_mem1; + struct resource *res_mem2; + + res_mem1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res_mem1 == NULL) { + return -ENODEV; + } - r = request_mem_region(r->start, resource_size(r), pdev->name); - if (!r) + res_mem1 = request_mem_region(res_mem1->start, + resource_size(res_mem1), + DRV_NAME); + if (res_mem1 == NULL) { return -EBUSY; + } + res_mem2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res_mem2 != NULL) { + res_mem2 = request_mem_region(res_mem2->start, + resource_size(res_mem2), + DRV_NAME); + if (res_mem2 == NULL) { + ret = -EBUSY; + goto release1; + } + } - /* Init network device */ - ndev = alloc_etherdev(sizeof(struct fec_enet_private)); - if (!ndev) - return -ENOMEM; - - SET_NETDEV_DEV(ndev, &pdev->dev); - - /* setup board info structure */ - fep = netdev_priv(ndev); - memset(fep, 0, sizeof(*fep)); + dev = alloc_etherdev(sizeof(struct fec_enet_private)); + if (dev == NULL) { + ret = -ENOMEM; + goto release2; + } + platform_set_drvdata(pdev, dev); + fep = netdev_priv(dev); + fep->res_mem1 = res_mem1; + fep->res_mem2 = res_mem2; + fep->dma_dev = &pdev->dev; + + fep->reg_base = ioremap(res_mem1->start, resource_size(res_mem1)); + if (fep->reg_base == NULL) { + printk("FEC: Mapping FEC registers failed\n"); + ret = -ENOMEM; + goto free_netdev; + } + DBG(0, "%s: FEC registers @ %08lx mapped to %p\n", __FUNCTION__, + (unsigned long)res_mem1->start, fep->reg_base); - ndev->base_addr = (unsigned long)ioremap(r->start, resource_size(r)); + fep->mib_base = ioremap(res_mem2->start, resource_size(res_mem2)); + if (fep->mib_base == NULL) { + printk("FEC: Mapping FEC registers failed\n"); + ret = -ENOMEM; + goto unmap1; + } + DBG(0, "%s: FEC registers @ %08lx mapped to %p\n", __FUNCTION__, + (unsigned long)res_mem2->start, fep->mib_base); - if (!ndev->base_addr) { + /* Allocate memory for buffer descriptors. */ + fep->cbd_mem_base = dma_alloc_coherent(&pdev->dev, CBD_BUF_SIZE, + &fep->cbd_phys_base, + GFP_KERNEL); + if (fep->cbd_mem_base == NULL) { + printk("FEC: allocate descriptor memory failed\n"); ret = -ENOMEM; - goto failed_ioremap; + goto unmap2; } + DBG(0, "%s: Allocated %lu [(%u + %lu) * %d] byte for CBD buffer @ %p[%08lx]\n", + __FUNCTION__, CBD_BUF_SIZE, TX_RING_SIZE, RX_RING_SIZE, + sizeof(cbd_t), fep->cbd_mem_base, + (unsigned long)fep->cbd_phys_base); - platform_set_drvdata(pdev, ndev); + /* Set receive and transmit descriptor base. + */ + fep->rx_bd_base = fep->cbd_mem_base; + fep->tx_bd_base = fep->rx_bd_base + RX_RING_SIZE; - /* This device has up to three irqs on some platforms */ - for (i = 0; i < 3; i++) { - irq = platform_get_irq(pdev, i); - if (i && irq < 0) - break; - ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev); - if (ret) { - while (i >= 0) { - irq = platform_get_irq(pdev, i); - free_irq(irq, ndev); - i--; - } - goto failed_irq; - } + printk("FEC ENET Driver\n"); + ret = platform_func(pdata->arch_init, pdev); + if (ret != 0) { + dev_err(&pdev->dev, "platform init failed: %d\n", ret); + goto free_dma; } - fep->clk = clk_get(&pdev->dev, "fec_clk"); - if (IS_ERR(fep->clk)) { - ret = PTR_ERR(fep->clk); - goto failed_clk; + ret = fec_enet_init(pdev, dev); + if (ret != 0) { + goto fec_disable; } - clk_enable(fep->clk); - ret = fec_enet_init(ndev, 0); - if (ret) - goto failed_init; + /* Enable most messages by default */ + fep->msg_enable = (NETIF_MSG_IFUP << 1) - 1; + ret = register_netdev(dev); + if (ret != 0) { + /* XXX: missing cleanup here */ + goto free_buffers; + } - ret = register_netdev(ndev); - if (ret) - goto failed_register; + printk(KERN_INFO "%s: ethernet %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); return 0; -failed_register: -failed_init: - clk_disable(fep->clk); - clk_put(fep->clk); -failed_clk: - for (i = 0; i < 3; i++) { - irq = platform_get_irq(pdev, i); - if (irq > 0) - free_irq(irq, ndev); - } -failed_irq: - iounmap((void __iomem *)ndev->base_addr); -failed_ioremap: - free_netdev(ndev); + free_buffers: + fec_enet_free_buffers(fep); + + fec_disable: + platform_func(pdata->arch_exit, pdev); + + free_dma: + dma_free_coherent(&pdev->dev, CBD_BUF_SIZE, fep->cbd_mem_base, fep->cbd_phys_base); + + unmap2: + if (fep->mib_base) + iounmap(fep->mib_base); + + unmap1: + iounmap(fep->reg_base); + + free_netdev: + free_netdev(dev); + + release2: + if (res_mem2 != NULL) { + release_resource(res_mem2); + } + + release1: + release_resource(res_mem1); return ret; } -static int __devexit -fec_drv_remove(struct platform_device *pdev) +static int __devexit fec_enet_remove(struct platform_device *pdev) { - struct net_device *ndev = platform_get_drvdata(pdev); - struct fec_enet_private *fep = netdev_priv(ndev); + struct net_device *dev = platform_get_drvdata(pdev); + struct fec_enet_private *fep = netdev_priv(dev); + + unregister_netdev(dev); +#ifdef CONFIG_PHYLIB + if (fep->mii != NULL) { + kfree(fep->mii->irq); + mdiobus_unregister(fep->mii); + } + mdiobus_free(fep->mii); +#endif + fec_release_intrs(dev); + + DBG(0, "%s: Unmapping FEC registers %p\n", __FUNCTION__, fep->reg_base); + iounmap(fep->reg_base); + if (fep->mib_base) + iounmap(fep->mib_base); + + fec_enet_free_buffers(fep); - platform_set_drvdata(pdev, NULL); + DBG(0, "%s: Freeing CBD buffer area %p[%08lx]\n", __FUNCTION__, + fep->cbd_mem_base, (unsigned long)fep->cbd_phys_base); + dma_free_coherent(&pdev->dev, CBD_BUF_SIZE, fep->cbd_mem_base, fep->cbd_phys_base); - fec_stop(ndev); - clk_disable(fep->clk); - clk_put(fep->clk); - iounmap((void __iomem *)ndev->base_addr); - unregister_netdev(ndev); - free_netdev(ndev); + release_resource(fep->res_mem1); + if (fep->res_mem2 != NULL) { + release_resource(fep->res_mem2); + } + free_netdev(dev); return 0; } -static int -fec_suspend(struct platform_device *dev, pm_message_t state) +static void fec_enet_shutdown(struct platform_device *pdev) { - struct net_device *ndev = platform_get_drvdata(dev); - struct fec_enet_private *fep; + struct fec_enet_platform_data *pdata = pdev->dev.platform_data; + + DBG(0, "%s: Shutting down FEC Hardware\n", __FUNCTION__); + platform_func(pdata->arch_exit, pdev); +} + +#ifdef CONFIG_PM +static int fec_enet_suspend(struct platform_device *pdev, pm_message_t state) +{ + int ret; + struct fec_enet_platform_data *pdata = pdev->dev.platform_data; + struct net_device *ndev = platform_get_drvdata(pdev); + struct fec_enet_private *fep = netdev_priv(ndev); - if (ndev) { - fep = netdev_priv(ndev); - if (netif_running(ndev)) { - netif_device_detach(ndev); - fec_stop(ndev); + if (netif_running(ndev)) { + DBG(0, "%s: Detaching netif\n", __FUNCTION__); + netif_device_detach(ndev); +#ifdef CONFIG_PHYLIB + DBG(0, "%s: Disconnecting PHY %p\n", __FUNCTION__, fep->phy); + phy_disconnect(fep->phy); + fep->phy = NULL; +#endif + } +#ifndef CONFIG_PHYLIB + if (fep->phy_timer) { + ret = del_timer_sync(fep->phy_timer); + if (ret != 0) { + DBG(0, "%s: Failed to delete PHY timer: %d\n", __FUNCTION__, ret); + return ret; } } - return 0; +#endif + DBG(0, "%s: Shutting down FEC Hardware %d\n", __FUNCTION__, + netif_running(ndev)); + ret = platform_func(pdata->suspend, pdev); + if (ret != 0 && netif_running(ndev)) { + DBG(0, "%s: Failed to suspend: %d\n", __FUNCTION__, ret); + /* Undo suspend */ +#ifdef CONFIG_PHYLIB + DBG(0, "%s: Reconnecting PHY\n", __FUNCTION__); + if (fec_connect_phy(ndev, fep) != 0) { + DBG(0, "%s: Failed to connect to PHY\n", __FUNCTION__); + return ret; + } + phy_start(fep->phy); +#endif + fec_link_change(ndev); + netif_device_attach(ndev); + } + return ret; } -static int -fec_resume(struct platform_device *dev) +static int fec_enet_resume(struct platform_device *pdev) { - struct net_device *ndev = platform_get_drvdata(dev); + int ret; + struct fec_enet_platform_data *pdata = pdev->dev.platform_data; + struct net_device *ndev = platform_get_drvdata(pdev); - if (ndev) { - if (netif_running(ndev)) { - fec_enet_init(ndev, 0); - netif_device_attach(ndev); + DBG(0, "%s: Powering up FEC Hardware %d\n", __FUNCTION__, + netif_running(ndev)); + ret = platform_func(pdata->resume, pdev); + if (ret != 0) { + DBG(0, "%s: Failed to resume: %d\n", __FUNCTION__, ret); + return ret; + } + if (netif_running(ndev)) { +#ifdef CONFIG_PHYLIB + struct fec_enet_private *fep = netdev_priv(ndev); + + DBG(0, "%s: Reconnecting PHY\n", __FUNCTION__); + ret = fec_connect_phy(ndev, fep); + if (ret != 0) { + DBG(0, "%s: Failed to connect to PHY: %d\n", __FUNCTION__, ret); + return ret; } + phy_start(fep->phy); +#endif + fec_link_change(ndev); + netif_device_attach(ndev); } return 0; } +#else +#define fec_enet_suspend NULL +#define fec_enet_resume NULL +#endif -static struct platform_driver fec_driver = { - .driver = { - .name = "fec", - .owner = THIS_MODULE, +static struct platform_driver fec_enet_driver = { + .driver = { + .name = DRV_NAME, }, - .probe = fec_probe, - .remove = __devexit_p(fec_drv_remove), - .suspend = fec_suspend, - .resume = fec_resume, + .probe = fec_enet_probe, + .remove = __devexit_p(fec_enet_remove), + .shutdown = fec_enet_shutdown, + .suspend = fec_enet_suspend, + .resume = fec_enet_resume, }; -static int __init -fec_enet_module_init(void) +static int __init fec_enet_module_init(void) { - printk(KERN_INFO "FEC Ethernet Driver\n"); + int ret; + + ret = platform_driver_register(&fec_enet_driver); - return platform_driver_register(&fec_driver); + return ret; } +module_init(fec_enet_module_init); -static void __exit -fec_enet_cleanup(void) +static void __exit fec_enet_module_cleanup(void) { - platform_driver_unregister(&fec_driver); + platform_driver_unregister(&fec_enet_driver); } - -module_exit(fec_enet_cleanup); -module_init(fec_enet_module_init); +module_exit(fec_enet_module_cleanup); MODULE_LICENSE("GPL"); diff -purN linux-2.6.30-rc4-git/drivers/net/fec.h linux-2.6.30-rc4-karo3/drivers/net/fec.h --- linux-2.6.30-rc4-git/drivers/net/fec.h 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/drivers/net/fec.h 2009-06-02 18:43:03.000000000 +0200 @@ -13,6 +13,15 @@ #define FEC_H /****************************************************************************/ +/* + * dummy value to write into RDAR,TDAR. FEC hardware will scan the TX/RX + * descriptors in memory upon any write access to those registers. + * The actual value written to those registers does not matter. +*/ +#define DONT_CARE 0 +#define RDAR_BUSY (1 << 24) +#define TDAR_BUSY (1 << 24) + #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARCH_MXC) /* @@ -20,6 +29,36 @@ * registers in the same peripheral device on different models * of the ColdFire! */ +// relying on structure alignment for hardware register is just evil +#ifndef GARBAGE +#define FEC_EIR 0x004 +#define FEC_EIMR 0x008 +#define FEC_RDAR 0x010 +#define FEC_TDAR 0x014 +#define FEC_ECR 0x024 +#define FEC_MMFR 0x040 +#define FEC_MSCR 0x044 +#define FEC_MIBC 0x064 +#define FEC_RCR 0x084 +#define FEC_TCR 0x0c4 +#define FEC_PALR 0x0e4 +#define FEC_PAUR 0x0e8 +#define FEC_OPD 0x0ec +#define FEC_IAUR 0x118 +#define FEC_IALR 0x11c +#define FEC_GAUR 0x120 +#define FEC_GALR 0x124 +#define FEC_TFWR 0x144 +#define FEC_FRBR 0x14c +#define FEC_FRSR 0x150 +#define FEC_ERDSR 0x180 +#define FEC_ETDSR 0x184 +#define FEC_EMRBR 0x188 + +#define FEC_ECR_RESET (1 << 0) +#define FEC_ECR_ETHER_EN (1 << 1) +#else + typedef struct fec { unsigned long fec_reserved0; unsigned long fec_ievent; /* Interrupt event reg */ @@ -57,6 +96,7 @@ typedef struct fec { unsigned long fec_x_des_start; /* Transmit descriptor ring */ unsigned long fec_r_buff_size; /* Maximum receive buff size */ } fec_t; +#endif #else @@ -88,8 +128,8 @@ typedef struct fec { unsigned long fec_reserved7[158]; unsigned long fec_addr_low; /* Low 32bits MAC address */ unsigned long fec_addr_high; /* High 16bits MAC address */ - unsigned long fec_grp_hash_table_high;/* High 32bits hash table */ - unsigned long fec_grp_hash_table_low; /* Low 32bits hash table */ + unsigned long fec_hash_table_high; /* High 32bits hash table */ + unsigned long fec_hash_table_low; /* Low 32bits hash table */ unsigned long fec_r_des_start; /* Receive descriptor ring */ unsigned long fec_x_des_start; /* Transmit descriptor ring */ unsigned long fec_r_buff_size; /* Maximum receive buff size */ @@ -103,17 +143,20 @@ typedef struct fec { /* * Define the buffer descriptor structure. */ -#ifdef CONFIG_ARCH_MXC +/* Please see "Receive Buffer Descriptor Field Definitions" in Specification. + * It's LE. + */ +#if defined(CONFIG_ARCH_MXC) typedef struct bufdesc { - unsigned short cbd_datlen; /* Data length */ - unsigned short cbd_sc; /* Control and status info */ - unsigned long cbd_bufaddr; /* Buffer address */ + unsigned short cbd_datlen; /* Data length */ + unsigned short cbd_sc; /* Control and status info */ + dma_addr_t cbd_bufaddr; /* Buffer address as seen by FEC Hardware */ } cbd_t; #else typedef struct bufdesc { unsigned short cbd_sc; /* Control and status info */ unsigned short cbd_datlen; /* Data length */ - unsigned long cbd_bufaddr; /* Buffer address */ + dma_addr_t cbd_bufaddr; /* Buffer address */ } cbd_t; #endif @@ -121,7 +164,7 @@ typedef struct bufdesc { * The following definitions courtesy of commproc.h, which where * Copyright (c) 1997 Dan Malek (dmalek@jlc.net). */ -#define BD_SC_EMPTY ((ushort)0x8000) /* Recieve is empty */ +#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */ #define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ #define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */ #define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ @@ -168,5 +211,22 @@ typedef struct bufdesc { #define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ +#define RCR_LOOP (1 << 0) +#define RCR_DRT (1 << 1) +#define RCR_MII_MODE (1 << 2) +#define RCR_PROM (1 << 3) +#define RCR_BC_REJ (1 << 4) +#define RCR_FCE (1 << 5) +#define RCR_MAX_FL_SHIFT 16 +#define RCR_MAX_FL_MASK (0x7ff << (RCR_MAX_FL_SHIFT)) +#define RCR_MAX_FL_set(n) (((n) << (RCR_MAX_FL_SHIFT)) & (RCR_MAX_FL_MASK)) +#define RCR_MAX_FL_get(n) (((n) & (RCR_MAX_FL_MASK)) >> (RCR_MAX_FL_SHIFT)) + +#define TCR_GTS (1 << 0) +#define TCR_HBC (1 << 1) +#define TCR_FDEN (1 << 2) +#define TCR_TFCPAUSE (1 << 3) +#define TCR_RFCPAUSE (1 << 4) + /****************************************************************************/ #endif /* FEC_H */ diff -purN linux-2.6.30-rc4-git/drivers/usb/Kconfig linux-2.6.30-rc4-karo3/drivers/usb/Kconfig --- linux-2.6.30-rc4-git/drivers/usb/Kconfig 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/drivers/usb/Kconfig 2009-06-29 10:49:52.000000000 +0200 @@ -57,6 +57,7 @@ config USB_ARCH_HAS_EHCI default y if PPC_83xx default y if SOC_AU1200 default y if ARCH_IXP4XX + default y if ARCH_MXC default PCI # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. diff -purN linux-2.6.30-rc4-git/drivers/usb/host/Kconfig linux-2.6.30-rc4-karo3/drivers/usb/host/Kconfig --- linux-2.6.30-rc4-git/drivers/usb/host/Kconfig 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/drivers/usb/host/Kconfig 2009-07-06 15:37:48.000000000 +0200 @@ -106,6 +106,37 @@ config USB_OXU210HP_HCD To compile this driver as a module, choose M here: the module will be called oxu210hp-hcd. +config USB_EHCI_MXC + bool "Support for Freescale on-chip EHCI USB controller" + depends on USB_EHCI_HCD && ARCH_MXC + select USB_EHCI_ROOT_HUB_TT + ---help--- + Variation of ARC USB block used in some Freescale chips. + +config ARCH_MXC_EHCI_USBH1 + bool "Enable USB on USBH1 port" + depends on USB_EHCI_MXC && ARCH_MXC_HAS_USBH1 + +config ARCH_MXC_EHCI_USBH2 + bool "Enable USB on USBH2 port" + depends on USB_EHCI_MXC && ARCH_MXC_HAS_USBH2 + +config ARCH_MXC_EHCI_USBOTG + bool "Enable USB on USBOTG port" + depends on USB_EHCI_MXC && ARCH_MXC_HAS_USBOTG + +config ARCH_MXC_HAS_USBH1 + bool + depends on USB_EHCI_MXC + +config ARCH_MXC_HAS_USBH2 + bool + depends on USB_EHCI_MXC + +config ARCH_MXC_HAS_USBOTG + bool + depends on USB_EHCI_MXC + config USB_ISP116X_HCD tristate "ISP116X HCD support" depends on USB diff -purN linux-2.6.30-rc4-git/drivers/usb/host/ehci-hcd.c linux-2.6.30-rc4-karo3/drivers/usb/host/ehci-hcd.c --- linux-2.6.30-rc4-git/drivers/usb/host/ehci-hcd.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/drivers/usb/host/ehci-hcd.c 2009-07-01 11:30:25.000000000 +0200 @@ -1047,6 +1047,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_fsl_driver #endif +#ifdef CONFIG_USB_EHCI_MXC +#include "ehci-mxc.c" +#define PLATFORM_DRIVER ehci_mxc_driver +#endif + #ifdef CONFIG_SOC_AU1200 #include "ehci-au1xxx.c" #define PLATFORM_DRIVER ehci_hcd_au1xxx_driver diff -purN linux-2.6.30-rc4-git/drivers/usb/host/ehci-mxc.c linux-2.6.30-rc4-karo3/drivers/usb/host/ehci-mxc.c --- linux-2.6.30-rc4-git/drivers/usb/host/ehci-mxc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/drivers/usb/host/ehci-mxc.c 2009-07-01 11:31:58.000000000 +0200 @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2008 Sascha Hauer , Pengutronix + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include + +/* called during probe() after chip reset completes */ +static int ehci_mxc_setup(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int retval; + + /* EHCI registers start at offset 0x100 */ + ehci->caps = hcd->regs + 0x100; + ehci->regs = hcd->regs + 0x100 + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); + dbg_hcs_params(ehci, "reset"); + dbg_hcc_params(ehci, "reset"); + + /* cache this readonly data; minimize chip reads */ + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + + retval = ehci_halt(ehci); + if (retval) + return retval; + + /* data structure init */ + retval = ehci_init(hcd); + if (retval) + return retval; + + hcd->has_tt = 1; + + ehci->sbrn = 0x20; + + ehci_reset(ehci); + + ehci_port_power(ehci, 0); + return 0; +} + +static const struct hc_driver ehci_mxc_hc_driver = { + .description = hcd_name, + .product_desc = "Freescale On-Chip EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_USB2 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .reset = ehci_mxc_setup, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, +}; + +static int ehci_mxc_drv_probe(struct platform_device *pdev) +{ + struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data; + struct usb_hcd *hcd; + struct resource *res; + int irq, ret, temp; + struct clk *usbclk, *ahbclk; + + dev_info(&pdev->dev, "initializing i.MX USB Controller\n"); + + /* Need platform data for setup */ + if (!pdata) { + dev_err(&pdev->dev, + "No platform data for %s.\n", dev_name(&pdev->dev)); + return -ENODEV; + } + + irq = platform_get_irq(pdev, 0); + + hcd = usb_create_hcd(&ehci_mxc_hc_driver, &pdev->dev, dev_name(&pdev->dev)); + if (!hcd) { + ret = -ENOMEM; + goto err1; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, + "Found HC with no register addr. Check %s setup!\n", + dev_name(&pdev->dev)); + ret = -ENODEV; + goto err1; + } + + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + dev_dbg(&pdev->dev, "controller already in use\n"); + ret = -EBUSY; + goto err1; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + dev_err(&pdev->dev, "error mapping memory\n"); + ret = -EFAULT; + goto err2; + } + +#if 0 + ahbclk = clk_get(NULL, "usb_ahb_clk"); + if (IS_ERR(ahbclk)) { + ret = PTR_ERR(ahbclk); + printk(KERN_ERR "Failed to get usb_ahb_clk: %d\n", ret); + goto err3; + } + clk_enable(ahbclk); +#endif + usbclk = clk_get(&pdev->dev, "usb"); + if (IS_ERR(usbclk)) { + ret = PTR_ERR(usbclk); + printk(KERN_ERR "Failed to get usb_clk: %d\n", ret); + goto err4; + } + clk_enable(usbclk); + + if (pdata->init) { + ret = pdata->init(pdev); + if (ret) { + dev_err(&pdev->dev, "platform init failed\n"); + goto err5; + } + } + + /* Set to Host mode */ + temp = readl(hcd->regs + 0x1a8); + writel(temp | 0x3, hcd->regs + 0x1a8); + + ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); + if (ret) + goto err6; + + platform_set_drvdata(pdev, hcd); + clk_put(usbclk); + + return 0; +err6: + if (pdata->exit) + pdata->exit(pdev); +err5: + clk_disable(usbclk); + clk_put(usbclk); +err4: +#if 0 + clk_disable(ahbclk); + clk_put(ahbclk); +#endif +err3: + iounmap(hcd->regs); +err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err1: + usb_put_hcd(hcd); + return ret; +} + +static int ehci_mxc_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data; + struct clk *usbclk; + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + platform_set_drvdata(pdev, NULL); + + if (pdata->exit) + pdata->exit(pdev); + + usbclk = clk_get(&pdev->dev, "usb"); + if (!IS_ERR(usbclk)) { + clk_disable(usbclk); + clk_put(usbclk); + } +#if 0 + ahbclk = clk_get(NULL, "usb_ahb_clk"); + if (!IS_ERR(ahbclk)) { + clk_disable(ahbclk); + clk_put(ahbclk); + } +#endif + return 0; +} + +MODULE_ALIAS("platform:mxc-ehci"); + +static struct platform_driver ehci_mxc_driver = { + .probe = ehci_mxc_drv_probe, + .remove = ehci_mxc_drv_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = "mxc-ehci", + }, +}; diff -purN linux-2.6.30-rc4-git/drivers/video/imxfb.c linux-2.6.30-rc4-karo3/drivers/video/imxfb.c --- linux-2.6.30-rc4-git/drivers/video/imxfb.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/drivers/video/imxfb.c 2009-07-02 16:21:35.000000000 +0200 @@ -56,9 +56,9 @@ #define VPW_VPW(x) ((x) & 0x3ff) #define LCDC_CPOS 0x0C -#define CPOS_CC1 (1<<31) -#define CPOS_CC0 (1<<30) -#define CPOS_OP (1<<28) +#define CPOS_CC1 (1 << 31) +#define CPOS_CC0 (1 << 30) +#define CPOS_OP (1 << 28) #define CPOS_CXP(x) (((x) & 3ff) << 16) #ifdef CONFIG_ARCH_MX1 @@ -68,7 +68,7 @@ #endif #define LCDC_LCWHB 0x10 -#define LCWHB_BK_EN (1<<31) +#define LCWHB_BK_EN (1 << 31) #define LCWHB_CW(w) (((w) & 0x1f) << 24) #define LCWHB_CH(h) (((h) & 0x1f) << 16) #define LCWHB_BD(x) ((x) & 0xff) @@ -112,22 +112,22 @@ #define LCDC_RMCR 0x34 #ifdef CONFIG_ARCH_MX1 -#define RMCR_LCDC_EN (1<<1) +#define RMCR_LCDC_EN (1 << 1) #else #define RMCR_LCDC_EN 0 #endif -#define RMCR_SELF_REF (1<<0) +#define RMCR_SELF_REF (1 << 0) #define LCDC_LCDICR 0x38 -#define LCDICR_INT_SYN (1<<2) -#define LCDICR_INT_CON (1) +#define LCDICR_INT_SYN (1 << 2) +#define LCDICR_INT_CON 1 #define LCDC_LCDISR 0x40 -#define LCDISR_UDR_ERR (1<<3) -#define LCDISR_ERR_RES (1<<2) -#define LCDISR_EOF (1<<1) -#define LCDISR_BOF (1<<0) +#define LCDISR_UDR_ERR (1 << 3) +#define LCDISR_ERR_RES (1 << 2) +#define LCDISR_EOF (1 << 1) +#define LCDISR_BOF (1 << 0) /* * These are the bitfields for each @@ -232,11 +232,11 @@ static int imxfb_setpalettereg(u_int reg struct imxfb_info *fbi = info->par; u_int val, ret = 1; -#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) +#define CNVT_TOHW(val,width) ((((val) << (width)) + 0x7FFF - (val)) >> 16) if (regno < fbi->palette_size) { - val = (CNVT_TOHW(red, 4) << 8) | - (CNVT_TOHW(green,4) << 4) | - CNVT_TOHW(blue, 4); + val = (CNVT_TOHW(red, 6) << 12) | + (CNVT_TOHW(green, 6) << 6) | + CNVT_TOHW(blue, 6); writel(val, fbi->regs + 0x800 + (regno << 2)); ret = 0; @@ -265,7 +265,7 @@ static int imxfb_setcolreg(u_int regno, /* * If greyscale is true, then we convert the RGB value - * to greyscale no mater what visual we are using. + * to greyscale no matter what visual we are using. */ if (info->var.grayscale) red = green = blue = (19595 * red + 38470 * green + @@ -527,7 +527,7 @@ static int imxfb_activate_var(struct fb_ if (--pcr > 0x3F) { pcr = 0x3F; printk(KERN_WARNING "Must limit pixel clock to %uHz\n", - lcd_clk / pcr); + lcd_clk / pcr + 1); } /* add sync polarities */ @@ -570,7 +570,7 @@ static int imxfb_resume(struct platform_ #define imxfb_resume NULL #endif -static int __init imxfb_init_fbinfo(struct platform_device *pdev) +static int __devinit imxfb_init_fbinfo(struct platform_device *pdev) { struct imx_fb_platform_data *pdata = pdev->dev.platform_data; struct fb_info *info = dev_get_drvdata(&pdev->dev); @@ -636,7 +636,7 @@ static int __init imxfb_init_fbinfo(stru return 0; } -static int __init imxfb_probe(struct platform_device *pdev) +static int __devinit imxfb_probe(struct platform_device *pdev) { struct imxfb_info *fbi; struct fb_info *info; @@ -754,7 +754,7 @@ failed_map: failed_getclock: iounmap(fbi->regs); failed_ioremap: - release_mem_region(res->start, res->end - res->start); + release_mem_region(res->start, resource_size(res)); failed_req: kfree(info->pseudo_palette); failed_init: @@ -763,7 +763,7 @@ failed_init: return ret; } -static int __devexit imxfb_remove(struct platform_device *pdev) +static int imxfb_remove(struct platform_device *pdev) { struct imx_fb_platform_data *pdata; struct fb_info *info = platform_get_drvdata(pdev); @@ -785,7 +785,7 @@ static int __devexit imxfb_remove(struct framebuffer_release(info); iounmap(fbi->regs); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); clk_disable(fbi->clk); clk_put(fbi->clk); @@ -794,7 +794,7 @@ static int __devexit imxfb_remove(struct return 0; } -void imxfb_shutdown(struct platform_device * dev) +void imxfb_shutdown(struct platform_device *dev) { struct fb_info *info = platform_get_drvdata(dev); struct imxfb_info *fbi = info->par; @@ -804,7 +804,8 @@ void imxfb_shutdown(struct platform_dev static struct platform_driver imxfb_driver = { .suspend = imxfb_suspend, .resume = imxfb_resume, - .remove = __devexit_p(imxfb_remove), +// .remove = __devexit_p(imxfb_remove), + .remove = imxfb_remove, .shutdown = imxfb_shutdown, .driver = { .name = DRIVER_NAME, diff -purN linux-2.6.30-rc4-git/fs/jffs2/erase.c linux-2.6.30-rc4-karo3/fs/jffs2/erase.c --- linux-2.6.30-rc4-git/fs/jffs2/erase.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/fs/jffs2/erase.c 2009-07-14 14:12:12.000000000 +0200 @@ -422,6 +422,7 @@ static void jffs2_mark_erased_block(stru /* Cleanmarker in oob area or no cleanmarker at all ? */ if (jffs2_cleanmarker_oob(c) || c->cleanmarker_size == 0) { + /* We only write cleanmarker in case of SLC NAND */ if (jffs2_cleanmarker_oob(c)) { if (jffs2_write_nand_cleanmarker(c, jeb)) goto filebad; diff -purN linux-2.6.30-rc4-git/fs/jffs2/fs.c linux-2.6.30-rc4-karo3/fs/jffs2/fs.c --- linux-2.6.30-rc4-git/fs/jffs2/fs.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/fs/jffs2/fs.c 2009-07-14 14:12:28.000000000 +0200 @@ -680,7 +680,9 @@ void jffs2_gc_release_page(struct jffs2_ static int jffs2_flash_setup(struct jffs2_sb_info *c) { int ret = 0; - if (jffs2_cleanmarker_oob(c)) { + if (c->mtd->type == MTD_NANDFLASH) { + if (!(c->mtd->flags & MTD_OOB_WRITEABLE)) + printk(KERN_DEBUG "JFFS2 doesn't use OOB.\n"); /* NAND flash... do setup accordingly */ ret = jffs2_nand_flash_setup(c); if (ret) @@ -713,7 +715,7 @@ static int jffs2_flash_setup(struct jffs void jffs2_flash_cleanup(struct jffs2_sb_info *c) { - if (jffs2_cleanmarker_oob(c)) { + if (c->mtd->type == MTD_NANDFLASH) { jffs2_nand_flash_cleanup(c); } diff -purN linux-2.6.30-rc4-git/fs/jffs2/os-linux.h linux-2.6.30-rc4-karo3/fs/jffs2/os-linux.h --- linux-2.6.30-rc4-git/fs/jffs2/os-linux.h 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/fs/jffs2/os-linux.h 2009-07-14 14:12:32.000000000 +0200 @@ -110,7 +110,7 @@ static inline void jffs2_init_inode_info #define jffs2_can_mark_obsolete(c) (c->mtd->flags & (MTD_BIT_WRITEABLE)) #endif -#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH) +#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH && (c->mtd->flags & MTD_OOB_WRITEABLE)) #define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf)) #define jffs2_flash_read_oob(c, ofs, len, retlen, buf) ((c)->mtd->read_oob((c)->mtd, ofs, len, retlen, buf)) diff -purN linux-2.6.30-rc4-git/include/linux/fec_enet.h linux-2.6.30-rc4-karo3/include/linux/fec_enet.h --- linux-2.6.30-rc4-git/include/linux/fec_enet.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/include/linux/fec_enet.h 2009-03-16 12:49:03.000000000 +0100 @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2007 Lothar Wassmann + * + * platform_data definitions for fec_enet device + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + */ + +struct fec_enet_platform_data { + /* callback for platform specific initialization */ + int (*arch_init)(struct platform_device *dev); + void (*arch_exit)(struct platform_device *dev); + int (*suspend)(struct platform_device *dev); + int (*resume)(struct platform_device *dev); +}; diff -purN linux-2.6.30-rc4-git/include/linux/usb/xcvr.h linux-2.6.30-rc4-karo3/include/linux/usb/xcvr.h --- linux-2.6.30-rc4-git/include/linux/usb/xcvr.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.30-rc4-karo3/include/linux/usb/xcvr.h 2009-07-01 11:32:10.000000000 +0200 @@ -0,0 +1,71 @@ +#ifndef __LINUX_USB_XCVR_H +#define __LINUX_USB_XCVR_H + +struct usb_xcvr; + +struct usb_xcvr_access_ops { + int (*read)(struct usb_xcvr *xcvr, u32 reg); + int (*write)(struct usb_xcvr *xcvr, u32 val, u32 reg); +}; + +struct usb_xcvr_driver { + int (*init)(struct usb_xcvr *xcvr); + void (*shutdown)(struct usb_xcvr *xcvr); + int (*set_vbus)(struct usb_xcvr *xcvr, bool en); +}; + +struct usb_xcvr { + struct usb_xcvr_access_ops *access; + struct usb_xcvr_driver *driver; + void __iomem *access_priv; + + /* only set this if you don't want the lowlevel driver to + * handle this */ + int (*set_vbus)(struct usb_xcvr *xcvr, bool en); +}; + +static inline int usb_xcvr_init(struct usb_xcvr *xcvr) +{ + if (xcvr->driver && xcvr->driver->init) + return xcvr->driver->init(xcvr); + + return -EINVAL; +} + +static inline void usb_xcvr_shutdown(struct usb_xcvr *xcvr) +{ + if (xcvr->driver && xcvr->driver->shutdown) + xcvr->driver->shutdown(xcvr); +} + +static inline int usb_xcvr_set_vbus(struct usb_xcvr *xcvr, bool en) +{ + if (xcvr->set_vbus) + return xcvr->set_vbus(xcvr, en); + + if (xcvr->driver && xcvr->driver->set_vbus) + return xcvr->driver->set_vbus(xcvr, en); + + return -EINVAL; +} + +/* lowlowel access helpers */ + +static inline int usb_xcvr_read(struct usb_xcvr *xcvr, u32 reg) +{ + if (xcvr->access->read) + return xcvr->access->read(xcvr, reg); + + return -EINVAL; +} + +static inline int usb_xcvr_write(struct usb_xcvr *xcvr, u32 val, u32 reg) +{ + if (xcvr->access->write) + return xcvr->access->write(xcvr, val, reg); + + return -EINVAL; +} + +#endif /* __LINUX_USB_XCVR_H */ + diff -purN linux-2.6.30-rc4-git/include/mtd/mtd-abi.h linux-2.6.30-rc4-karo3/include/mtd/mtd-abi.h --- linux-2.6.30-rc4-git/include/mtd/mtd-abi.h 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/include/mtd/mtd-abi.h 2009-07-14 14:12:38.000000000 +0200 @@ -30,12 +30,14 @@ struct mtd_oob_buf { #define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */ #define MTD_NO_ERASE 0x1000 /* No erase necessary */ #define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset */ +#define MTD_OOB_WRITEABLE 0x4000 /* Use Out-Of-Band area */ // Some common devices / combinations of capabilities #define MTD_CAP_ROM 0 #define MTD_CAP_RAM (MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE) #define MTD_CAP_NORFLASH (MTD_WRITEABLE | MTD_BIT_WRITEABLE) -#define MTD_CAP_NANDFLASH (MTD_WRITEABLE) +#define MTD_CAP_NANDFLASH (MTD_WRITEABLE | MTD_OOB_WRITEABLE) +#define MTD_CAP_MLC_NANDFLASH (MTD_WRITEABLE) /* ECC byte placement */ #define MTD_NANDECC_OFF 0 // Switch off ECC (Not recommended) diff -purN linux-2.6.30-rc4-git/kernel/printk.c linux-2.6.30-rc4-karo3/kernel/printk.c --- linux-2.6.30-rc4-git/kernel/printk.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/kernel/printk.c 2009-06-02 19:21:25.000000000 +0200 @@ -637,9 +637,12 @@ static int acquire_console_semaphore_for static const char recursion_bug_msg [] = KERN_CRIT "BUG: recent printk recursion!\n"; static int recursion_bug; -static int new_text_line = 1; + static int new_text_line = 1; static char printk_buf[1024]; +#ifdef CONFIG_DEBUG_LL +extern void asmlinkage printascii(const char *); +#endif asmlinkage int vprintk(const char *fmt, va_list args) { int printed_len = 0; @@ -687,6 +690,9 @@ asmlinkage int vprintk(const char *fmt, sizeof(printk_buf) - printed_len, fmt, args); +#ifdef CONFIG_DEBUG_LL + printascii(printk_buf); +#endif /* * Copy the output into log_buf. If the caller didn't provide * appropriate log level tags, we insert them here diff -purN linux-2.6.30-rc4-git/net/can/bcm.c linux-2.6.30-rc4-karo3/net/can/bcm.c --- linux-2.6.30-rc4-git/net/can/bcm.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/net/can/bcm.c 2009-07-14 14:13:01.000000000 +0200 @@ -75,6 +75,7 @@ static __initdata const char banner[] = MODULE_DESCRIPTION("PF_CAN broadcast manager protocol"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Oliver Hartkopp "); +MODULE_ALIAS("can-proto-2"); /* easy access to can_frame payload */ static inline u64 GET_U64(const struct can_frame *cp) @@ -1469,6 +1470,9 @@ static int bcm_release(struct socket *so bo->ifindex = 0; } + sock_orphan(sk); + sock->sk = NULL; + release_sock(sk); sock_put(sk); diff -purN linux-2.6.30-rc4-git/net/can/raw.c linux-2.6.30-rc4-karo3/net/can/raw.c --- linux-2.6.30-rc4-git/net/can/raw.c 2009-05-13 09:46:19.000000000 +0200 +++ linux-2.6.30-rc4-karo3/net/can/raw.c 2009-07-14 14:13:07.000000000 +0200 @@ -62,6 +62,7 @@ static __initdata const char banner[] = MODULE_DESCRIPTION("PF_CAN raw protocol"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Urs Thuermann "); +MODULE_ALIAS("can-proto-1"); #define MASK_ALL 0 @@ -306,6 +307,9 @@ static int raw_release(struct socket *so ro->bound = 0; ro->count = 0; + sock_orphan(sk); + sock->sk = NULL; + release_sock(sk); sock_put(sk);