diff options
361 files changed, 20865 insertions, 9231 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3f1b470beacf..7f161d76e5d2 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1502,6 +1502,8 @@ source "drivers/accessibility/Kconfig" source "drivers/leds/Kconfig" +source "drivers/switch/Kconfig" + source "drivers/rtc/Kconfig" source "drivers/dma/Kconfig" diff --git a/arch/arm/configs/imx23evk_defconfig b/arch/arm/configs/imx23evk_defconfig index 31a22aa4c274..d65c1fbdd21b 100644 --- a/arch/arm/configs/imx23evk_defconfig +++ b/arch/arm/configs/imx23evk_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.31 -# Tue Apr 13 15:44:41 2010 +# Mon May 24 17:09:02 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -20,6 +20,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_ZONE_DMA=y +CONFIG_FIQ=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y CONFIG_VECTORS_BASE=0xffff0000 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -184,6 +185,7 @@ CONFIG_ARCH_MXS=y # CONFIG_ARCH_OMAP is not set CONFIG_IRAM_ALLOC=y CONFIG_DMA_ZONE_SIZE=12 +CONFIG_VECTORS_PHY_ADDR=0 # # Freescale i.MXS implementations @@ -191,6 +193,8 @@ CONFIG_DMA_ZONE_SIZE=12 # CONFIG_ARCH_MX28 is not set CONFIG_ARCH_MX23=y CONFIG_MACH_MX23EVK=y +CONFIG_MXS_UNIQUE_ID=y +CONFIG_MXS_UNIQUE_ID_OTP=y CONFIG_MXS_ICOLL=y CONFIG_MXS_EARLY_CONSOLE=y CONFIG_MXS_DMA_ENGINE=y @@ -345,7 +349,8 @@ CONFIG_NET=y # # Networking options # -# CONFIG_PACKET is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set @@ -357,7 +362,10 @@ CONFIG_INET=y CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_FIB_HASH=y -# CONFIG_IP_PNP is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set @@ -456,8 +464,9 @@ CONFIG_NETFILTER_ADVANCED=y # CONFIG_AF_RXRPC is not set CONFIG_WIRELESS=y # CONFIG_CFG80211 is not set -# CONFIG_WIRELESS_OLD_REGULATORY is not set -# CONFIG_WIRELESS_EXT is not set +CONFIG_WIRELESS_OLD_REGULATORY=y +CONFIG_WIRELESS_EXT=y +CONFIG_WIRELESS_EXT_SYSFS=y # CONFIG_LIB80211 is not set # @@ -465,7 +474,8 @@ CONFIG_WIRELESS=y # CONFIG_MAC80211_DEFAULT_PS_VALUE=0 # CONFIG_WIMAX is not set -# CONFIG_RFKILL is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_INPUT=y # CONFIG_NET_9P is not set # @@ -485,16 +495,112 @@ CONFIG_EXTRA_FIRMWARE="" # CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set # CONFIG_CONNECTOR is not set -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_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_DATAFLASH is not set +# CONFIG_MTD_MXC_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +# CONFIG_MTD_NAND_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_GPMI_NFC=y +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ALAUDA is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +CONFIG_MTD_UBI_GLUEBI=y + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_MTD_UBI_BLOCK=y # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_COW_COMMON is not set -# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_COUNT=4 +CONFIG_BLK_DEV_RAM_SIZE=16384 # CONFIG_BLK_DEV_XIP is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set @@ -510,6 +616,7 @@ CONFIG_MXS_PERSISTENT=y # EEPROM support # # CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set # CONFIG_EEPROM_LEGACY is not set # CONFIG_EEPROM_MAX6875 is not set # CONFIG_EEPROM_93CX6 is not set @@ -567,6 +674,8 @@ CONFIG_NET_ETHERNET=y # CONFIG_AX88796 is not set # CONFIG_SMC91X is not set # CONFIG_DM9000 is not set +CONFIG_ENC28J60=y +# CONFIG_ENC28J60_WRITEVERIFY is not set # CONFIG_ETHOC is not set # CONFIG_SMC911X is not set # CONFIG_SMSC911X is not set @@ -580,6 +689,7 @@ CONFIG_NET_ETHERNET=y # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set # CONFIG_B44 is not set # CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set CONFIG_NETDEV_1000=y CONFIG_NETDEV_10000=y @@ -601,6 +711,7 @@ CONFIG_NETDEV_10000=y # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RTL8150 is not set # CONFIG_USB_USBNET is not set +# CONFIG_USB_HSO is not set # CONFIG_WAN is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -644,7 +755,10 @@ CONFIG_KEYBOARD_MXS=y # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_TABLET is not set CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set # CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set # CONFIG_TOUCHSCREEN_AD7879 is not set # CONFIG_TOUCHSCREEN_EETI is not set # CONFIG_TOUCHSCREEN_FUJITSU is not set @@ -704,6 +818,7 @@ CONFIG_MXS_VIIM=y CONFIG_SERIAL_MXS_DUART=y CONFIG_SERIAL_MXS_AUART=y CONFIG_SERIAL_MXS_DUART_CONSOLE=y +# CONFIG_SERIAL_MAX3100 is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y @@ -760,7 +875,22 @@ CONFIG_I2C_MXS_SELECT0=y # CONFIG_I2C_DEBUG_BUS is not set # CONFIG_I2C_DEBUG_CHIP is not set # CONFIG_I2C_SLAVE is not set -# CONFIG_SPI is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +CONFIG_SPI_MXS=y + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set CONFIG_ARCH_REQUIRE_GPIOLIB=y CONFIG_GPIOLIB=y # CONFIG_DEBUG_GPIO is not set @@ -784,6 +914,8 @@ CONFIG_GPIOLIB=y # # SPI GPIO expanders: # +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set # CONFIG_W1 is not set CONFIG_POWER_SUPPLY=y # CONFIG_POWER_SUPPLY_DEBUG is not set @@ -798,6 +930,7 @@ CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_AD7414 is not set # CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set @@ -818,6 +951,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_GL520SM is not set # CONFIG_SENSORS_IT87 is not set # CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set # CONFIG_SENSORS_LM75 is not set # CONFIG_SENSORS_LM77 is not set # CONFIG_SENSORS_LM78 is not set @@ -831,6 +965,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_LTC4215 is not set # CONFIG_SENSORS_LTC4245 is not set # CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_MAX1111 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_MAX6650 is not set # CONFIG_SENSORS_PC87360 is not set @@ -853,6 +988,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_W83L786NG is not set # CONFIG_SENSORS_W83627HF is not set # CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_LIS3_SPI is not set # CONFIG_HWMON_DEBUG_CHIP is not set CONFIG_MXC_MMA7450=m # CONFIG_THERMAL is not set @@ -896,6 +1032,7 @@ CONFIG_SSB_POSSIBLE=y # CONFIG_MFD_WM8350_I2C is not set # CONFIG_MFD_PCF50633 is not set # CONFIG_AB3100_CORE is not set +# CONFIG_EZX_PCAP is not set CONFIG_MEDIA_SUPPORT=y # @@ -1028,6 +1165,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y CONFIG_FB_MXS=y # CONFIG_FB_MXS_LCD_43WVF1G is not set CONFIG_FB_MXS_LCD_LMS430=y +# CONFIG_FB_MXS_TVENC is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set @@ -1081,6 +1219,7 @@ CONFIG_SND_VERBOSE_PROCFS=y # CONFIG_SND_EMU10K1_SEQ is not set # CONFIG_SND_DRIVERS is not set # CONFIG_SND_ARM is not set +CONFIG_SND_SPI=y # CONFIG_SND_USB is not set CONFIG_SND_SOC=y CONFIG_SND_MXS_SOC=y @@ -1264,6 +1403,7 @@ CONFIG_MMC_BLOCK_BOUNCE=y # MMC/SD/SDIO Host Controller Drivers # # CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SPI is not set # CONFIG_MMC_IMX_ESDHCI_PIO_MODE is not set CONFIG_MMC_MXS=y # CONFIG_MEMSTICK is not set @@ -1305,6 +1445,13 @@ CONFIG_RTC_INTF_DEV=y # # SPI RTC drivers # +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set # # Platform RTC drivers @@ -1413,6 +1560,13 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_XATTR is not set +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +# CONFIG_UBIFS_FS_DEBUG is not set # CONFIG_CRAMFS is not set # CONFIG_SQUASHFS is not set # CONFIG_VXFS_FS is not set @@ -1425,8 +1579,18 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_UFS_FS is not set # CONFIG_NILFS2_FS is not set CONFIG_NETWORK_FILESYSTEMS=y -# CONFIG_NFS_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set @@ -1436,8 +1600,24 @@ CONFIG_NETWORK_FILESYSTEMS=y # # Partition Types # -# CONFIG_PARTITION_ADVANCED is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SYSV68_PARTITION is not set CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_NLS_CODEPAGE_437=y @@ -1518,7 +1698,7 @@ CONFIG_DEBUG_PREEMPT=y # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_BUGVERBOSE is not set -# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_INFO=y # CONFIG_DEBUG_VM is not set # CONFIG_DEBUG_WRITECOUNT is not set # CONFIG_DEBUG_MEMORY_INIT is not set diff --git a/arch/arm/configs/imx28evk_defconfig b/arch/arm/configs/imx28evk_defconfig index 44cfd4dc0f06..9d3b1c98d198 100644 --- a/arch/arm/configs/imx28evk_defconfig +++ b/arch/arm/configs/imx28evk_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.31 -# Tue Mar 23 23:51:39 2010 +# Tue Aug 3 11:34:57 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -195,6 +195,7 @@ CONFIG_ARCH_MXS=y # CONFIG_ARCH_OMAP is not set CONFIG_IRAM_ALLOC=y CONFIG_DMA_ZONE_SIZE=16 +CONFIG_VECTORS_PHY_ADDR=0 # # Freescale i.MXS implementations @@ -225,6 +226,8 @@ CONFIG_MXS_AUART3_DEVICE_ENABLE=y CONFIG_MXS_AUART4_DEVICE_ENABLE=y # CONFIG_MXS_AUART4_DMA_ENABLE is not set CONFIG_MXS_RAM_FREQ_SCALING=y +# CONFIG_MXS_RAM_MDDR is not set +# CONFIG_MXS_RAM_DDR is not set # # Processor Type @@ -438,9 +441,20 @@ CONFIG_CAN_FLEXCAN=m # CONFIG_IRDA is not set # CONFIG_BT is not set # CONFIG_AF_RXRPC is not set -# CONFIG_WIRELESS is not set +CONFIG_WIRELESS=y +# CONFIG_CFG80211 is not set +CONFIG_WIRELESS_OLD_REGULATORY=y +CONFIG_WIRELESS_EXT=y +CONFIG_WIRELESS_EXT_SYSFS=y +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +CONFIG_MAC80211_DEFAULT_PS_VALUE=0 # CONFIG_WIMAX is not set -# CONFIG_RFKILL is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_INPUT=y # CONFIG_NET_9P is not set # @@ -460,11 +474,11 @@ CONFIG_EXTRA_FIRMWARE="" # CONFIG_CONNECTOR is not set CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set -# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_CONCAT=y CONFIG_MTD_PARTITIONS=y # CONFIG_MTD_TESTS is not set # CONFIG_MTD_REDBOOT_PARTS is not set -# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y # CONFIG_MTD_AFS_PARTS is not set # CONFIG_MTD_AR7_PARTS is not set @@ -528,7 +542,7 @@ CONFIG_MTD_NAND=y CONFIG_MTD_NAND_IDS=y # CONFIG_MTD_NAND_DISKONCHIP is not set # CONFIG_MTD_NAND_NANDSIM is not set -CONFIG_MTD_NAND_GPMI1=y +CONFIG_MTD_NAND_GPMI_NFC=y # CONFIG_MTD_NAND_PLATFORM is not set # CONFIG_MTD_ALAUDA is not set # CONFIG_MTD_ONENAND is not set @@ -550,16 +564,17 @@ CONFIG_MTD_UBI_BEB_RESERVE=1 # UBI debugging options # # CONFIG_MTD_UBI_DEBUG is not set -# CONFIG_MTD_UBI_BLOCK is not set +CONFIG_MTD_UBI_BLOCK=y # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_COW_COMMON is not set -# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=4 -CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_RAM_SIZE=16384 # CONFIG_BLK_DEV_XIP is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set @@ -568,6 +583,7 @@ CONFIG_MISC_DEVICES=y # CONFIG_ICS932S401 is not set # CONFIG_ENCLOSURE_SERVICES is not set # CONFIG_ISL29003 is not set +CONFIG_MXS_PERSISTENT=y # CONFIG_C2PORT is not set # @@ -669,6 +685,7 @@ CONFIG_MII=y # CONFIG_B44 is not set # CONFIG_KS8842 is not set CONFIG_FEC=y +# CONFIG_FEC_1588 is not set # CONFIG_FEC2 is not set # CONFIG_NETDEV_1000 is not set # CONFIG_NETDEV_10000 is not set @@ -691,6 +708,7 @@ CONFIG_FEC=y # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RTL8150 is not set # CONFIG_USB_USBNET is not set +# CONFIG_USB_HSO is not set # CONFIG_WAN is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -833,6 +851,7 @@ CONFIG_MXS_VIIM=y # CONFIG_SERIAL_MXS_DUART=y CONFIG_SERIAL_MXS_AUART=y +# CONFIG_SERIAL_MXS_AUART_CONSOLE is not set CONFIG_SERIAL_MXS_DUART_CONSOLE=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y @@ -931,6 +950,7 @@ CONFIG_POWER_SUPPLY=y # CONFIG_BATTERY_BQ27x00 is not set # CONFIG_BATTERY_MAX17040 is not set CONFIG_BATTERY_MXS=y +# CONFIG_MXS_VBUS_CURRENT_DRAW is not set # CONFIG_HWMON is not set # CONFIG_THERMAL is not set # CONFIG_THERMAL_HWMON is not set @@ -1117,6 +1137,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y CONFIG_FB_MXS=y CONFIG_FB_MXS_LCD_43WVF1G=y # CONFIG_FB_MXS_LCD_LMS430 is not set +# CONFIG_FB_MXS_TVENC is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set @@ -1175,8 +1196,6 @@ CONFIG_SND_MXS_SOC=y CONFIG_SND_MXS_SOC_SPDIF_DAI=y CONFIG_SND_MXS_SOC_EVK_DEVB=y CONFIG_SND_MXS_SOC_DAI=y -CONFIG_SND_MXS_SOC_SAIF0_SELECT=y -# CONFIG_SND_MXS_SOC_SAIF1_SELECT is not set CONFIG_SND_MXS_SOC_EVK_DEVB_SPDIF=y CONFIG_SND_SOC_I2C_AND_SPI=y # CONFIG_SND_SOC_ALL_CODECS is not set @@ -1237,16 +1256,18 @@ CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_EHCI=y CONFIG_USB=y # CONFIG_USB_DEBUG is not set -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set # # Miscellaneous USB options # # CONFIG_USB_DEVICEFS is not set # CONFIG_USB_DEVICE_CLASS is not set -CONFIG_USB_DYNAMIC_MINORS=y -# CONFIG_USB_SUSPEND is not set -# CONFIG_USB_OTG is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set # CONFIG_USB_MON is not set # CONFIG_USB_WUSB is not set # CONFIG_USB_WUSB_CBAF is not set @@ -1255,7 +1276,7 @@ CONFIG_USB_DYNAMIC_MINORS=y # USB Host Controller Drivers # # CONFIG_USB_C67X00_HCD is not set -CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ARC=y CONFIG_USB_EHCI_ARC_H1=y CONFIG_USB_EHCI_ARC_OTG=y @@ -1340,7 +1361,7 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_TEST is not set # CONFIG_USB_ISIGHTFW is not set # CONFIG_USB_VST is not set -CONFIG_USB_GADGET=m +CONFIG_USB_GADGET=y # CONFIG_USB_GADGET_DEBUG_FILES is not set # CONFIG_USB_GADGET_DEBUG_FS is not set CONFIG_USB_GADGET_VBUS_DRAW=2 @@ -1362,7 +1383,7 @@ CONFIG_USB_GADGET_SELECTED=y # CONFIG_USB_GADGET_NET2280 is not set # CONFIG_USB_GADGET_GOKU is not set CONFIG_USB_GADGET_ARC=y -CONFIG_USB_ARC=m +CONFIG_USB_ARC=y CONFIG_WORKAROUND_ARCUSB_REG_RW=y # CONFIG_USB_GADGET_LANGWELL is not set # CONFIG_USB_GADGET_DUMMY_HCD is not set @@ -1386,7 +1407,7 @@ CONFIG_USB_G_SERIAL=m CONFIG_USB_OTG_UTILS=y # CONFIG_USB_GPIO_VBUS is not set # CONFIG_NOP_USB_XCEIV is not set -# CONFIG_MXC_OTG is not set +CONFIG_MXC_OTG=y CONFIG_MMC=y # CONFIG_MMC_DEBUG is not set CONFIG_MMC_UNSAFE_RESUME=y @@ -1485,6 +1506,7 @@ CONFIG_DMADEVICES=y # # DMA Devices # +# CONFIG_MXC_PXP is not set # CONFIG_AUXDISPLAY is not set CONFIG_REGULATOR=y # CONFIG_REGULATOR_DEBUG is not set @@ -1495,6 +1517,7 @@ CONFIG_REGULATOR=y # CONFIG_REGULATOR_MAX1586 is not set # CONFIG_REGULATOR_LP3971 is not set CONFIG_REGULATOR_MXS=y +# CONFIG_REGULATOR_MAX17135 is not set # CONFIG_UIO is not set # CONFIG_STAGING is not set @@ -1506,13 +1529,13 @@ CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y CONFIG_EXT2_FS_SECURITY=y # CONFIG_EXT2_FS_XIP is not set -CONFIG_EXT3_FS=m -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_DEFAULTS_TO_ORDERED=y CONFIG_EXT3_FS_XATTR=y CONFIG_EXT3_FS_POSIX_ACL=y CONFIG_EXT3_FS_SECURITY=y # CONFIG_EXT4_FS is not set -CONFIG_JBD=m +CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set diff --git a/arch/arm/configs/imx28evk_updater_defconfig b/arch/arm/configs/imx28evk_updater_defconfig index f2ced40e1b14..fe9a908e7e62 100644 --- a/arch/arm/configs/imx28evk_updater_defconfig +++ b/arch/arm/configs/imx28evk_updater_defconfig @@ -1,7 +1,6 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.31 -# Fri Apr 9 13:26:15 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -180,6 +179,7 @@ CONFIG_ARCH_MXS=y # CONFIG_ARCH_OMAP is not set CONFIG_IRAM_ALLOC=y CONFIG_DMA_ZONE_SIZE=16 +CONFIG_VECTORS_PHY_ADDR=0 # # Freescale i.MXS implementations @@ -210,6 +210,8 @@ CONFIG_MXS_AUART_PORTS=5 # CONFIG_MXS_AUART4_DEVICE_ENABLE is not set # CONFIG_MXS_AUART4_DMA_ENABLE is not set CONFIG_MXS_RAM_FREQ_SCALING=y +# CONFIG_MXS_RAM_MDDR is not set +# CONFIG_MXS_RAM_DDR is not set # # Processor Type @@ -289,6 +291,21 @@ CONFIG_CMDLINE="console=ttyAM0,115200 rdinit=/linuxrc" # # CPU Power Management # +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set # CONFIG_CPU_IDLE is not set # @@ -337,9 +354,107 @@ CONFIG_FW_LOADER=y CONFIG_FIRMWARE_IN_KERNEL=y CONFIG_EXTRA_FIRMWARE="" # CONFIG_SYS_HYPERVISOR is not set -# CONFIG_MTD is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_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 is not set +# 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_GPMI_NFC=y +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ALAUDA is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_GLUEBI is not set + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set +# CONFIG_MTD_UBI_BLOCK is not set # CONFIG_PARPORT is not set -# CONFIG_BLK_DEV is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_UB is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_MG_DISK is not set # CONFIG_MISC_DEVICES is not set CONFIG_HAVE_IDE=y # CONFIG_IDE is not set @@ -391,6 +506,7 @@ CONFIG_INPUT=y # CONFIG_VT is not set # CONFIG_DEVKMEM is not set # CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_MXS_VIIM is not set # # Serial drivers @@ -415,6 +531,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_I2C is not set # CONFIG_I2C_SLAVE is not set # CONFIG_SPI is not set +CONFIG_FSL_OTP=y CONFIG_ARCH_REQUIRE_GPIOLIB=y CONFIG_GPIOLIB=y # CONFIG_GPIO_SYSFS is not set @@ -467,6 +584,7 @@ CONFIG_SSB_POSSIBLE=y # CONFIG_VGASTATE is not set # CONFIG_VIDEO_OUTPUT_CONTROL is not set # CONFIG_FB is not set +# CONFIG_FB_MXS_TVENC is not set # CONFIG_BACKLIGHT_LCD_SUPPORT is not set # @@ -649,15 +767,15 @@ CONFIG_EXT2_FS_POSIX_ACL=y CONFIG_EXT2_FS_SECURITY=y # CONFIG_EXT2_FS_XIP is not set CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_DEFAULTS_TO_ORDERED=y CONFIG_EXT3_FS_XATTR=y -# CONFIG_EXT3_FS_POSIX_ACL is not set -# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y CONFIG_EXT4_FS=y -# CONFIG_EXT4DEV_COMPAT is not set +CONFIG_EXT4DEV_COMPAT=y CONFIG_EXT4_FS_XATTR=y -# CONFIG_EXT4_FS_POSIX_ACL is not set -# CONFIG_EXT4_FS_SECURITY is not set +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y CONFIG_JBD=y CONFIG_JBD2=y CONFIG_FS_MBCACHE=y @@ -706,7 +824,32 @@ CONFIG_TMPFS=y # CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set # CONFIG_CONFIGFS_FS is not set -# CONFIG_MISC_FILESYSTEMS is not set +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 is not set +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_XATTR is not set +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +# CONFIG_UBIFS_FS_DEBUG is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_NILFS2_FS is not set # # Partition Types @@ -787,7 +930,96 @@ CONFIG_HAVE_ARCH_KGDB=y # CONFIG_SECURITY is not set # CONFIG_SECURITYFS is not set # CONFIG_SECURITY_FILE_CAPABILITIES is not set -# CONFIG_CRYPTO 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_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_CRYPTODEV is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_DCP is not set # CONFIG_BINARY_PRINTF is not set # @@ -803,6 +1035,9 @@ CONFIG_CRC32=y # CONFIG_CRC7 is not set # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y CONFIG_DECOMPRESS_GZIP=y CONFIG_GENERIC_ALLOCATOR=y CONFIG_HAS_IOMEM=y diff --git a/arch/arm/configs/imx35_3stack_defconfig b/arch/arm/configs/imx35_3stack_defconfig index 308c94789192..733771b53ced 100644 --- a/arch/arm/configs/imx35_3stack_defconfig +++ b/arch/arm/configs/imx35_3stack_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.31 -# Sat Dec 5 22:30:18 2009 +# Wed Jul 14 14:01:59 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -152,6 +152,7 @@ CONFIG_FREEZER=y # CONFIG_ARCH_FOOTBRIDGE is not set CONFIG_ARCH_MXC=y # CONFIG_ARCH_STMP3XXX is not set +# CONFIG_ARCH_MXS is not set # CONFIG_ARCH_NETX is not set # CONFIG_ARCH_H720X is not set # CONFIG_ARCH_IOP13XX is not set @@ -181,6 +182,7 @@ CONFIG_ARCH_MXC=y # CONFIG_ARCH_U300 is not set # CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP is not set +CONFIG_IRAM_ALLOC=y CONFIG_DMA_ZONE_SIZE=24 CONFIG_UTMI_MXC=y @@ -193,10 +195,9 @@ CONFIG_UTMI_MXC=y # CONFIG_ARCH_MX25 is not set CONFIG_ARCH_MX35=y # CONFIG_ARCH_MX37 is not set -# CONFIG_ARCH_MX51 is not set +# CONFIG_ARCH_MX5 is not set CONFIG_MXC_SDMA_API=y CONFIG_SDMA_IRAM=y -CONFIG_SDMA_IRAM_SIZE=0x1000 CONFIG_ARCH_MXC_HAS_NFC_V2=y CONFIG_I2C_MXC_SELECT1=y # CONFIG_I2C_MXC_SELECT2 is not set @@ -213,14 +214,11 @@ CONFIG_MACH_MX35_3DS=y # CONFIG_MX35_DOZE_DURING_IDLE is not set # -# SDMA options -# - -# # Device options # CONFIG_MXC_PSEUDO_IRQS=y CONFIG_ARCH_HAS_EVTMON=y +CONFIG_ISP1504_MXC=y # CONFIG_MXC_IRQ_PRIOR is not set # CONFIG_MXC_PWM is not set CONFIG_ARCH_HAS_RNGC=y @@ -540,7 +538,6 @@ CONFIG_MTD_NAND=y CONFIG_MTD_NAND_IDS=y # CONFIG_MTD_NAND_DISKONCHIP is not set # CONFIG_MTD_NAND_NANDSIM is not set -# CONFIG_MTD_NAND_IMX_NFC is not set CONFIG_MTD_NAND_MXC_V2=y # CONFIG_MTD_NAND_MXC_SWECC is not set # CONFIG_MTD_NAND_MXC_FORCE_CE is not set @@ -630,6 +627,7 @@ CONFIG_SCSI_LOWLEVEL=y CONFIG_ATA=m # CONFIG_ATA_NONSTANDARD is not set # CONFIG_SATA_PMP is not set +# CONFIG_SATA_AHCI_PLATFORM is not set CONFIG_ATA_SFF=y # CONFIG_SATA_MV is not set # CONFIG_PATA_PLATFORM is not set @@ -1273,6 +1271,7 @@ CONFIG_SND_SOC_IMX_3STACK_AK4647=y CONFIG_SND_SOC_IMX_3STACK_WM8580=y # CONFIG_SND_SOC_IMX_3STACK_AK5702 is not set CONFIG_SND_SOC_IMX_3STACK_BLUETOOTH=y +# CONFIG_SND_SOC_IMX_3STACK_CS42888 is not set CONFIG_SND_SOC_I2C_AND_SPI=y # CONFIG_SND_SOC_ALL_CODECS is not set CONFIG_SND_SOC_WM8580=y @@ -1465,17 +1464,13 @@ CONFIG_USB_ARC=m # CONFIG_USB_GADGET_LANGWELL is not set # CONFIG_USB_GADGET_DUMMY_HCD is not set CONFIG_USB_GADGET_DUALSPEED=y -CONFIG_USB_GADGET_ARC_OTG=y -# CONFIG_USB_GADGET_FSL_MC13783 is not set -# CONFIG_USB_GADGET_FSL_1301 is not set -# CONFIG_USB_GADGET_FSL_1504 is not set -CONFIG_USB_GADGET_FSL_UTMI=y # CONFIG_USB_ZERO is not set # CONFIG_USB_AUDIO is not set CONFIG_USB_ETH=m CONFIG_USB_ETH_RNDIS=y CONFIG_USB_GADGETFS=m CONFIG_USB_FILE_STORAGE=m +# CONFIG_FSL_UTP is not set # CONFIG_USB_FILE_STORAGE_TEST is not set CONFIG_USB_G_SERIAL=m # CONFIG_USB_MIDI_GADGET is not set @@ -1485,8 +1480,10 @@ CONFIG_USB_G_SERIAL=m # # OTG and related infrastructure # +CONFIG_USB_OTG_UTILS=y # CONFIG_USB_GPIO_VBUS is not set # CONFIG_NOP_USB_XCEIV is not set +# CONFIG_MXC_OTG is not set CONFIG_MMC=y # CONFIG_MMC_DEBUG is not set CONFIG_MMC_UNSAFE_RESUME=y @@ -1589,6 +1586,7 @@ CONFIG_REGULATOR=y # CONFIG_REGULATOR_LP3971 is not set CONFIG_REGULATOR_MC13892=y CONFIG_REGULATOR_MC9S08DZ60=y +# CONFIG_REGULATOR_MAX17135 is not set # CONFIG_UIO is not set # CONFIG_STAGING is not set @@ -1682,6 +1680,11 @@ CONFIG_MXC_MLB=m # CONFIG_IMX_ADC is not set # +# MXC GPU support +# +CONFIG_MXC_AMD_GPU=m + +# # File systems # CONFIG_EXT2_FS=y @@ -1980,6 +1983,7 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +CONFIG_GENERIC_ALLOCATOR=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y diff --git a/arch/arm/configs/imx35_updater_defconfig b/arch/arm/configs/imx35_updater_defconfig index 83ecdac1de88..6d1fed3c8944 100644 --- a/arch/arm/configs/imx35_updater_defconfig +++ b/arch/arm/configs/imx35_updater_defconfig @@ -1,6 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.31 +# Sun Jun 13 10:46:18 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -39,10 +40,7 @@ CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_SYSVIPC_SYSCTL=y -# CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_TASKSTATS is not set -# CONFIG_AUDIT is not set # # RCU Subsystem @@ -102,7 +100,6 @@ CONFIG_TRACEPOINTS=y CONFIG_MARKERS=y CONFIG_OPROFILE=y CONFIG_HAVE_OPROFILE=y -# CONFIG_KPROBES is not set CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y @@ -115,12 +112,7 @@ 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_MODULES is not set CONFIG_BLOCK=y CONFIG_LBDAF=y # CONFIG_BLK_DEV_BSG is not set @@ -155,6 +147,7 @@ CONFIG_FREEZER=y # CONFIG_ARCH_FOOTBRIDGE is not set CONFIG_ARCH_MXC=y # CONFIG_ARCH_STMP3XXX is not set +# CONFIG_ARCH_MXS is not set # CONFIG_ARCH_NETX is not set # CONFIG_ARCH_H720X is not set # CONFIG_ARCH_IOP13XX is not set @@ -197,7 +190,7 @@ CONFIG_UTMI_MXC=y # CONFIG_ARCH_MX25 is not set CONFIG_ARCH_MX35=y # CONFIG_ARCH_MX37 is not set -# CONFIG_ARCH_MX51 is not set +# CONFIG_ARCH_MX5 is not set CONFIG_MXC_SDMA_API=y CONFIG_SDMA_IRAM=y CONFIG_ARCH_MXC_HAS_NFC_V2=y @@ -341,105 +334,7 @@ CONFIG_SUSPEND=y CONFIG_SUSPEND_FREEZER=y # CONFIG_APM_EMULATION is not set CONFIG_ARCH_SUSPEND_POSSIBLE=y -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_UNIX=y -CONFIG_XFRM=y -# CONFIG_XFRM_USER is not set -# CONFIG_XFRM_SUB_POLICY is not set -# CONFIG_XFRM_MIGRATE is not set -# CONFIG_XFRM_STATISTICS is not set -# CONFIG_NET_KEY is not set -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_FIB_HASH=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_XFRM_TUNNEL is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_INET_XFRM_MODE_TRANSPORT=y -CONFIG_INET_XFRM_MODE_TUNNEL=y -CONFIG_INET_XFRM_MODE_BEET=y -# CONFIG_INET_LRO is not set -CONFIG_INET_DIAG=y -CONFIG_INET_TCP_DIAG=y -# CONFIG_TCP_CONG_ADVANCED 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_IEEE802154 is not set -# CONFIG_NET_SCHED is not set -# CONFIG_DCB is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_NET_DROP_MONITOR is not set -# CONFIG_HAMRADIO is not set -CONFIG_CAN=y -CONFIG_CAN_RAW=y -CONFIG_CAN_BCM=y - -# -# CAN Device Drivers -# -CONFIG_CAN_VCAN=y -# CONFIG_CAN_DEV is not set -# CONFIG_CAN_DEBUG_DEVICES is not set -CONFIG_CAN_FLEXCAN=m -# CONFIG_IRDA is not set -# CONFIG_BT is not set -# CONFIG_AF_RXRPC is not set -CONFIG_WIRELESS=y -# CONFIG_CFG80211 is not set -CONFIG_WIRELESS_OLD_REGULATORY=y -CONFIG_WIRELESS_EXT=y -CONFIG_WIRELESS_EXT_SYSFS=y -# CONFIG_LIB80211 is not set - -# -# CFG80211 needs to be enabled for MAC80211 -# -CONFIG_MAC80211_DEFAULT_PS_VALUE=0 -# CONFIG_WIMAX is not set -# CONFIG_RFKILL is not set -# CONFIG_NET_9P is not set +# CONFIG_NET is not set # # Device Drivers @@ -455,13 +350,10 @@ CONFIG_FW_LOADER=y CONFIG_FIRMWARE_IN_KERNEL=y CONFIG_EXTRA_FIRMWARE="" # CONFIG_SYS_HYPERVISOR is not set -CONFIG_CONNECTOR=y -CONFIG_PROC_EVENTS=y CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set # CONFIG_MTD_CONCAT is not set CONFIG_MTD_PARTITIONS=y -# CONFIG_MTD_TESTS is not set # CONFIG_MTD_REDBOOT_PARTS is not set CONFIG_MTD_CMDLINE_PARTS=y # CONFIG_MTD_AFS_PARTS is not set @@ -540,13 +432,11 @@ CONFIG_MTD_NAND=y CONFIG_MTD_NAND_IDS=y # CONFIG_MTD_NAND_DISKONCHIP is not set # CONFIG_MTD_NAND_NANDSIM is not set -# CONFIG_MTD_NAND_IMX_NFC is not set CONFIG_MTD_NAND_MXC_V2=y # CONFIG_MTD_NAND_MXC_SWECC is not set # CONFIG_MTD_NAND_MXC_FORCE_CE is not set # CONFIG_MXC_NAND_LOW_LEVEL_ERASE is not set # CONFIG_MTD_NAND_PLATFORM is not set -# CONFIG_MTD_ALAUDA is not set # CONFIG_MTD_ONENAND is not set # @@ -557,17 +447,23 @@ CONFIG_MTD_NAND_MXC_V2=y # # UBI - Unsorted block images # -# CONFIG_MTD_UBI is not set +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +# CONFIG_MTD_UBI_GLUEBI is not set + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set +CONFIG_MTD_UBI_BLOCK=y # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_UB is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_CDROM_PKTCDVD is not set -# CONFIG_ATA_OVER_ETH is not set # CONFIG_MG_DISK is not set CONFIG_MISC_DEVICES=y # CONFIG_ICS932S401 is not set @@ -610,121 +506,28 @@ CONFIG_SCSI_MULTI_LUN=y # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set # CONFIG_SCSI_SCAN_ASYNC is not set -CONFIG_SCSI_WAIT_SCAN=m # # SCSI Transports # # CONFIG_SCSI_SPI_ATTRS is not set # CONFIG_SCSI_FC_ATTRS is not set -# CONFIG_SCSI_ISCSI_ATTRS is not set # CONFIG_SCSI_SAS_LIBSAS is not set # CONFIG_SCSI_SRP_ATTRS is not set CONFIG_SCSI_LOWLEVEL=y -# CONFIG_ISCSI_TCP is not set # CONFIG_LIBFC is not set # CONFIG_LIBFCOE is not set # CONFIG_SCSI_DEBUG is not set # CONFIG_SCSI_DH is not set # CONFIG_SCSI_OSD_INITIATOR is not set -CONFIG_ATA=m +CONFIG_ATA=y # CONFIG_ATA_NONSTANDARD is not set # CONFIG_SATA_PMP is not set CONFIG_ATA_SFF=y # CONFIG_SATA_MV is not set # CONFIG_PATA_PLATFORM is not set -CONFIG_PATA_FSL=m +CONFIG_PATA_FSL=y # CONFIG_MD is not set -CONFIG_NETDEVICES=y -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_MACVLAN is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set -# CONFIG_VETH is not set -CONFIG_PHYLIB=y - -# -# MII PHY device drivers -# -# CONFIG_MARVELL_PHY is not set -# CONFIG_DAVICOM_PHY is not set -# CONFIG_QSEMI_PHY is not set -# CONFIG_LXT_PHY is not set -# CONFIG_CICADA_PHY is not set -# CONFIG_VITESSE_PHY is not set -# CONFIG_SMSC_PHY is not set -# CONFIG_BROADCOM_PHY is not set -# CONFIG_ICPLUS_PHY is not set -# CONFIG_REALTEK_PHY is not set -# CONFIG_NATIONAL_PHY is not set -# CONFIG_STE10XP is not set -# CONFIG_LSI_ET1011C_PHY is not set -# CONFIG_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_ENC28J60 is not set -# CONFIG_ETHOC is not set -# CONFIG_SMC911X is not set -CONFIG_SMSC911X=y -# 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_CS89x0 is not set -# CONFIG_KS8842 is not set -# CONFIG_KS8851 is not set -# CONFIG_FEC 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=m -# CONFIG_USB_NET_AX8817X is not set -CONFIG_USB_NET_CDCETHER=m -# CONFIG_USB_NET_CDC_EEM is not set -# CONFIG_USB_NET_DM9601 is not set -# CONFIG_USB_NET_SMSC95XX is not set -# CONFIG_USB_NET_GL620A is not set -# CONFIG_USB_NET_NET1080 is not set -# CONFIG_USB_NET_PLUSB is not set -# CONFIG_USB_NET_MCS7830 is not set -# CONFIG_USB_NET_RNDIS_HOST is not set -# CONFIG_USB_NET_CDC_SUBSET is not set -# CONFIG_USB_NET_ZAURUS is not set -# CONFIG_USB_NET_INT51X1 is not set -# CONFIG_WAN is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set -# CONFIG_NETCONSOLE is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_ISDN is not set # # Input device support @@ -798,7 +601,7 @@ CONFIG_HW_CONSOLE=y # CONFIG_VT_HW_CONSOLE_BINDING is not set CONFIG_DEVKMEM=y # CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_FM_SI4702=m +CONFIG_FM_SI4702=y CONFIG_MXC_IIM=y # @@ -849,13 +652,11 @@ CONFIG_I2C_MXC=y # # CONFIG_I2C_PARPORT_LIGHT is not set # CONFIG_I2C_TAOS_EVM is not set -# CONFIG_I2C_TINY_USB is not set # # Other I2C/SMBus bus drivers # # CONFIG_I2C_PCA_PLATFORM is not set -# CONFIG_I2C_STUB is not set # # Miscellaneous I2C Chip support @@ -925,11 +726,6 @@ CONFIG_WATCHDOG_NOWAYOUT=y # # CONFIG_SOFT_WATCHDOG is not set CONFIG_MXC_WATCHDOG=y - -# -# USB-based Watchdog Cards -# -# CONFIG_USBPCWATCHDOG is not set CONFIG_SSB_POSSIBLE=y # @@ -964,13 +760,11 @@ CONFIG_VIDEO_DEV=y CONFIG_VIDEO_V4L2_COMMON=y CONFIG_VIDEO_ALLOW_V4L1=y CONFIG_VIDEO_V4L1_COMPAT=y -# CONFIG_DVB_CORE is not set CONFIG_VIDEO_MEDIA=y # # Multimedia drivers # -# CONFIG_MEDIA_ATTACH is not set CONFIG_MEDIA_TUNER=y CONFIG_MEDIA_TUNER_CUSTOMISE=y # CONFIG_MEDIA_TUNER_SIMPLE is not set @@ -1068,89 +862,26 @@ CONFIG_VIDEO_CAPTURE_DRIVERS=y # CONFIG_VIDEO_UPD64031A is not set # CONFIG_VIDEO_UPD64083 is not set # CONFIG_VIDEO_VIVI is not set -CONFIG_VIDEO_MXC_CAMERA=m +CONFIG_VIDEO_MXC_CAMERA=y # # MXC Camera/V4L2 PRP Features support # -CONFIG_VIDEO_MXC_IPU_CAMERA=y # CONFIG_VIDEO_MXC_CSI_CAMERA is not set # CONFIG_MXC_CAMERA_MC521DA is not set # CONFIG_MXC_EMMA_CAMERA_MICRON111 is not set # CONFIG_MXC_CAMERA_OV2640_EMMA is not set # CONFIG_MXC_CAMERA_MICRON111 is not set -CONFIG_MXC_CAMERA_OV2640=m -# CONFIG_MXC_CAMERA_OV3640 is not set -CONFIG_MXC_TVIN_ADV7180=m -CONFIG_MXC_IPU_PRP_VF_SDC=m -CONFIG_MXC_IPU_PRP_ENC=m -CONFIG_MXC_IPU_CSI_ENC=m +# CONFIG_MXC_CAMERA_OV2640 is not set +CONFIG_MXC_CAMERA_OV3640=y +# CONFIG_MXC_TVIN_ADV7180 is not set CONFIG_VIDEO_MXC_OUTPUT=y -CONFIG_VIDEO_MXC_IPU_OUTPUT=y -# CONFIG_VIDEO_MXC_IPUV1_WVGA_OUTPUT is not set # CONFIG_VIDEO_MXC_OPL is not set # CONFIG_VIDEO_CPIA is not set -# CONFIG_VIDEO_CPIA2 is not set # CONFIG_VIDEO_SAA5246A is not set # CONFIG_VIDEO_SAA5249 is not set # CONFIG_SOC_CAMERA is not set -CONFIG_V4L_USB_DRIVERS=y -# CONFIG_USB_VIDEO_CLASS is not set -CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y -CONFIG_USB_GSPCA=m -# CONFIG_USB_M5602 is not set -# CONFIG_USB_STV06XX is not set -# CONFIG_USB_GSPCA_CONEX is not set -# CONFIG_USB_GSPCA_ETOMS is not set -# CONFIG_USB_GSPCA_FINEPIX is not set -# CONFIG_USB_GSPCA_MARS is not set -# CONFIG_USB_GSPCA_MR97310A is not set -# CONFIG_USB_GSPCA_OV519 is not set -# CONFIG_USB_GSPCA_OV534 is not set -# CONFIG_USB_GSPCA_PAC207 is not set -# CONFIG_USB_GSPCA_PAC7311 is not set -# CONFIG_USB_GSPCA_SN9C20X is not set -# CONFIG_USB_GSPCA_SONIXB is not set -# CONFIG_USB_GSPCA_SONIXJ is not set -# CONFIG_USB_GSPCA_SPCA500 is not set -# CONFIG_USB_GSPCA_SPCA501 is not set -# CONFIG_USB_GSPCA_SPCA505 is not set -# CONFIG_USB_GSPCA_SPCA506 is not set -# CONFIG_USB_GSPCA_SPCA508 is not set -# CONFIG_USB_GSPCA_SPCA561 is not set -# CONFIG_USB_GSPCA_SQ905 is not set -# CONFIG_USB_GSPCA_SQ905C is not set -# CONFIG_USB_GSPCA_STK014 is not set -# CONFIG_USB_GSPCA_SUNPLUS is not set -# CONFIG_USB_GSPCA_T613 is not set -# CONFIG_USB_GSPCA_TV8532 is not set -# CONFIG_USB_GSPCA_VC032X is not set -# CONFIG_USB_GSPCA_ZC3XX is not set -# CONFIG_VIDEO_PVRUSB2 is not set -# CONFIG_VIDEO_HDPVR is not set -# CONFIG_VIDEO_EM28XX is not set -# CONFIG_VIDEO_CX231XX is not set -# CONFIG_VIDEO_USBVISION is not set -# CONFIG_USB_VICAM is not set -# CONFIG_USB_IBMCAM is not set -# CONFIG_USB_KONICAWC is not set -# CONFIG_USB_QUICKCAM_MESSENGER is not set -# CONFIG_USB_ET61X251 is not set -# CONFIG_VIDEO_OVCAMCHIP is not set -# CONFIG_USB_OV511 is not set -# CONFIG_USB_SE401 is not set -# CONFIG_USB_SN9C102 is not set -# CONFIG_USB_STV680 is not set -# CONFIG_USB_ZC0301 is not set -# CONFIG_USB_PWC is not set -CONFIG_USB_PWC_INPUT_EVDEV=y -# CONFIG_USB_ZR364XX is not set -# CONFIG_USB_STKWEBCAM is not set -# CONFIG_USB_S2255 is not set CONFIG_RADIO_ADAPTERS=y -# CONFIG_USB_DSBR is not set -# CONFIG_USB_SI470X is not set -# CONFIG_USB_MR800 is not set # CONFIG_RADIO_TEA5764 is not set # CONFIG_DAB is not set @@ -1163,9 +894,9 @@ 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_FILLRECT is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set # CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set # CONFIG_FB_SYS_FILLRECT is not set # CONFIG_FB_SYS_COPYAREA is not set @@ -1181,14 +912,6 @@ CONFIG_FB_MODE_HELPERS=y # # Frame buffer hardware drivers # -CONFIG_FB_MXC=y -CONFIG_FB_MXC_SYNC_PANEL=y -# CONFIG_FB_MXC_EPSON_VGA_SYNC_PANEL is not set -CONFIG_FB_MXC_CLAA_WVGA_SYNC_PANEL=y -# CONFIG_FB_MXC_CH7026 is not set -# CONFIG_FB_MXC_TVOUT_CH7024 is not set -# CONFIG_FB_MXC_ASYNC_PANEL is not set -# CONFIG_FB_UVESA is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set @@ -1199,7 +922,6 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_GENERIC=y CONFIG_BACKLIGHT_MXC=y -CONFIG_BACKLIGHT_MXC_IPU=y CONFIG_BACKLIGHT_MXC_MC13892=y # @@ -1230,211 +952,28 @@ CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set CONFIG_LOGO_LINUX_CLUT224=y -CONFIG_SOUND=y -CONFIG_SOUND_OSS_CORE=y -CONFIG_SND=y -CONFIG_SND_TIMER=y -CONFIG_SND_PCM=y -CONFIG_SND_JACK=y -# CONFIG_SND_SEQUENCER is not set -CONFIG_SND_OSSEMUL=y -CONFIG_SND_MIXER_OSS=y -CONFIG_SND_PCM_OSS=y -CONFIG_SND_PCM_OSS_PLUGINS=y -# CONFIG_SND_HRTIMER is not set -# CONFIG_SND_DYNAMIC_MINORS is not set -CONFIG_SND_SUPPORT_OLD_API=y -CONFIG_SND_VERBOSE_PROCFS=y -# CONFIG_SND_VERBOSE_PRINTK is not set -# CONFIG_SND_DEBUG is not set -# CONFIG_SND_RAWMIDI_SEQ is not set -# CONFIG_SND_OPL3_LIB_SEQ is not set -# CONFIG_SND_OPL4_LIB_SEQ is not set -# CONFIG_SND_SBAWE_SEQ is not set -# CONFIG_SND_EMU10K1_SEQ is not set -CONFIG_SND_DRIVERS=y -# CONFIG_SND_DUMMY is not set -# CONFIG_SND_MTPAV is not set -# CONFIG_SND_SERIAL_U16550 is not set -# CONFIG_SND_MPU401 is not set -CONFIG_SND_ARM=y -CONFIG_SND_MXC_SPDIF=m -CONFIG_SND_SPI=y -CONFIG_SND_USB=y -# CONFIG_SND_USB_AUDIO is not set -# CONFIG_SND_USB_CAIAQ is not set -CONFIG_SND_SOC=y -CONFIG_SND_MXC_SOC=y -CONFIG_SND_MXC_SOC_SSI=y -CONFIG_SND_MXC_SOC_ESAI=y -CONFIG_SND_MXC_SOC_IRAM=y -CONFIG_SND_SOC_IMX_3STACK_SGTL5000=y -CONFIG_SND_SOC_IMX_3STACK_AK4647=y -CONFIG_SND_SOC_IMX_3STACK_WM8580=y -# CONFIG_SND_SOC_IMX_3STACK_AK5702 is not set -CONFIG_SND_SOC_IMX_3STACK_BLUETOOTH=y -CONFIG_SND_SOC_I2C_AND_SPI=y -# CONFIG_SND_SOC_ALL_CODECS is not set -CONFIG_SND_SOC_WM8580=y -CONFIG_SND_SOC_SGTL5000=y -CONFIG_SND_SOC_AK4647=y -CONFIG_SND_SOC_BLUETOOTH=y -# CONFIG_SOUND_PRIME is not set +# CONFIG_SOUND is not set CONFIG_HID_SUPPORT=y CONFIG_HID=y # CONFIG_HID_DEBUG is not set # CONFIG_HIDRAW is not set - -# -# USB Input Devices -# -CONFIG_USB_HID=m # CONFIG_HID_PID is not set -# CONFIG_USB_HIDDEV is not set - -# -# USB HID Boot Protocol drivers -# -# CONFIG_USB_KBD is not set -# CONFIG_USB_MOUSE is not set # # Special HID drivers # -CONFIG_HID_A4TECH=m -CONFIG_HID_APPLE=m -CONFIG_HID_BELKIN=m -CONFIG_HID_CHERRY=m -CONFIG_HID_CHICONY=m -CONFIG_HID_CYPRESS=m -# CONFIG_HID_DRAGONRISE is not set -CONFIG_HID_EZKEY=m -# CONFIG_HID_KYE is not set -CONFIG_HID_GYRATION=m -# CONFIG_HID_KENSINGTON is not set -CONFIG_HID_LOGITECH=m -# CONFIG_LOGITECH_FF is not set -# CONFIG_LOGIRUMBLEPAD2_FF is not set -CONFIG_HID_MICROSOFT=m -CONFIG_HID_MONTEREY=m -# CONFIG_HID_NTRIG is not set -CONFIG_HID_PANTHERLORD=m -# CONFIG_PANTHERLORD_FF is not set -CONFIG_HID_PETALYNX=m -CONFIG_HID_SAMSUNG=m -CONFIG_HID_SONY=m -CONFIG_HID_SUNPLUS=m -# CONFIG_HID_GREENASIA is not set -# CONFIG_HID_SMARTJOYPLUS is not set -# CONFIG_HID_TOPSEED is not set -# CONFIG_HID_THRUSTMASTER is not set -# CONFIG_HID_ZEROPLUS 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=y -# CONFIG_USB_DEBUG is not set -# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set - -# -# Miscellaneous USB options -# -CONFIG_USB_DEVICEFS=y -CONFIG_USB_DEVICE_CLASS=y -# CONFIG_USB_DYNAMIC_MINORS is not set -CONFIG_USB_SUSPEND=y -# CONFIG_USB_OTG is not set +# CONFIG_USB is not set # CONFIG_USB_OTG_WHITELIST is not set # CONFIG_USB_OTG_BLACKLIST_HUB is not set -CONFIG_USB_MON=y -# 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_ARC=y -CONFIG_USB_EHCI_ARC_H2=y -# CONFIG_USB_EHCI_ARC_OTG is not set -# CONFIG_USB_STATIC_IRAM is not set -CONFIG_USB_EHCI_ROOT_HUB_TT=y -# CONFIG_USB_EHCI_TT_NEWSCHED is not set -# CONFIG_USB_OXU210HP_HCD is not set -# CONFIG_USB_ISP116X_HCD is not set -# CONFIG_USB_ISP1760_HCD is not set -# CONFIG_USB_SL811_HCD is not set -# CONFIG_USB_R8A66597_HCD is not set -# CONFIG_USB_HWA_HCD is not set # CONFIG_USB_GADGET_MUSB_HDRC is not set # -# USB Device Class drivers -# -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set -# CONFIG_USB_WDM is not set -# CONFIG_USB_TMC is not set - -# # NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may # - -# -# also be needed; see USB_STORAGE Help for more info -# -CONFIG_USB_STORAGE=y -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_USBAT is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_SDDR55 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set -# CONFIG_USB_STORAGE_ALAUDA is not set -# CONFIG_USB_STORAGE_ONETOUCH is not set -# CONFIG_USB_STORAGE_KARMA is not set -# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set -# CONFIG_USB_LIBUSUAL is not set - -# -# USB Imaging devices -# -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_MICROTEK is not set - -# -# USB port drivers -# -# CONFIG_USB_SERIAL is not set - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_EMI62 is not set -# CONFIG_USB_EMI26 is not set -# CONFIG_USB_ADUTUX is not set -# CONFIG_USB_SEVSEG is not set -# CONFIG_USB_RIO500 is not set -# CONFIG_USB_LEGOTOWER is not set -# CONFIG_USB_LCD is not set -# CONFIG_USB_BERRY_CHARGE is not set -# CONFIG_USB_LED is not set -# CONFIG_USB_CYPRESS_CY7C63 is not set -# CONFIG_USB_CYTHERM is not set -# CONFIG_USB_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=y # CONFIG_USB_GADGET_DEBUG_FILES is not set # CONFIG_USB_GADGET_DEBUG_FS is not set @@ -1465,7 +1004,7 @@ CONFIG_USB_GADGET_DUALSPEED=y # CONFIG_USB_AUDIO is not set # CONFIG_USB_ETH is not set # CONFIG_USB_GADGETFS is not set -CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_FILE_STORAGE=y CONFIG_FSL_UTP=y # CONFIG_USB_FILE_STORAGE_TEST is not set # CONFIG_USB_G_SERIAL is not set @@ -1479,7 +1018,6 @@ CONFIG_FSL_UTP=y CONFIG_USB_OTG_UTILS=y # CONFIG_USB_GPIO_VBUS is not set # CONFIG_NOP_USB_XCEIV is not set -# CONFIG_MXC_OTG is not set CONFIG_MMC=y # CONFIG_MMC_DEBUG is not set CONFIG_MMC_UNSAFE_RESUME=y @@ -1491,7 +1029,7 @@ CONFIG_MMC_BLOCK=y CONFIG_MMC_BLOCK_BOUNCE=y # CONFIG_SDIO_UART is not set # CONFIG_MMC_TEST is not set -CONFIG_SDIO_UNIFI_FS=m +CONFIG_SDIO_UNIFI_FS=y # # MMC/SD/SDIO Host Controller Drivers @@ -1499,7 +1037,7 @@ CONFIG_SDIO_UNIFI_FS=m # CONFIG_MMC_SDHCI is not set # CONFIG_MMC_MXC is not set # CONFIG_MMC_SPI is not set -CONFIG_MMC_IMX_ESDHCI=m +CONFIG_MMC_IMX_ESDHCI=y # CONFIG_MMC_IMX_ESDHCI_PIO_MODE is not set # CONFIG_MEMSTICK is not set # CONFIG_ACCESSIBILITY is not set @@ -1588,9 +1126,7 @@ CONFIG_REGULATOR_MC9S08DZ60=y # # MXC support drivers # -CONFIG_MXC_IPU=y -CONFIG_MXC_IPU_V1=y -CONFIG_MXC_IPU_PF=y +# CONFIG_MXC_IPU is not set # # MXC SSI support @@ -1657,17 +1193,17 @@ CONFIG_MXC_ASRC=y # # MXC Bluetooth support # -CONFIG_MXC_BLUETOOTH=m +CONFIG_MXC_BLUETOOTH=y # # Broadcom GPS ioctrl support # -CONFIG_GPS_IOCTRL=m +CONFIG_GPS_IOCTRL=y # # MXC Media Local Bus Driver # -CONFIG_MXC_MLB=m +CONFIG_MXC_MLB=y # # i.MX ADC support @@ -1677,15 +1213,25 @@ CONFIG_MXC_MLB=m # # File systems # -# CONFIG_EXT2_FS is not set -# CONFIG_EXT3_FS is not set +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_DEFAULTS_TO_ORDERED=y +CONFIG_EXT3_FS_XATTR=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y # CONFIG_EXT4_FS is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set -# CONFIG_FS_POSIX_ACL is not set +CONFIG_FS_POSIX_ACL=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_FILE_LOCKING=y CONFIG_FSNOTIFY=y @@ -1694,7 +1240,7 @@ CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set -CONFIG_AUTOFS4_FS=m +CONFIG_AUTOFS4_FS=y # CONFIG_FUSE_FS is not set # @@ -1740,6 +1286,12 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set # CONFIG_JFFS2_FS is not set +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_XATTR is not set +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +# CONFIG_UBIFS_FS_DEBUG is not set # CONFIG_CRAMFS is not set # CONFIG_SQUASHFS is not set # CONFIG_VXFS_FS is not set @@ -1751,7 +1303,6 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set # CONFIG_NILFS2_FS is not set -# CONFIG_NETWORK_FILESYSTEMS is not set # # Partition Types @@ -1783,7 +1334,7 @@ CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set -CONFIG_NLS_ASCII=m +CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -1797,8 +1348,7 @@ CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set # CONFIG_NLS_KOI8_U is not set -CONFIG_NLS_UTF8=m -# CONFIG_DLM is not set +CONFIG_NLS_UTF8=y # # Kernel hacking @@ -1847,13 +1397,14 @@ CONFIG_CRYPTO=y # Crypto core or helper # # CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y # CONFIG_CRYPTO_MANAGER is not set # CONFIG_CRYPTO_MANAGER2 is not set # CONFIG_CRYPTO_GF128MUL is not set # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_CRYPTD is not set # CONFIG_CRYPTO_AUTHENC is not set -# CONFIG_CRYPTO_TEST is not set # CONFIG_CRYPTO_CRYPTODEV is not set # @@ -1919,9 +1470,9 @@ CONFIG_CRYPTO=y # # Compression # -# CONFIG_CRYPTO_DEFLATE is not set +CONFIG_CRYPTO_DEFLATE=y # CONFIG_CRYPTO_ZLIB is not set -# CONFIG_CRYPTO_LZO is not set +CONFIG_CRYPTO_LZO=y # # Random Number Generation @@ -1935,17 +1486,19 @@ CONFIG_BINARY_PRINTF=y # CONFIG_BITREVERSE=y CONFIG_GENERIC_FIND_LAST_BIT=y -CONFIG_CRC_CCITT=m -# CONFIG_CRC16 is not set +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y # 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_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y CONFIG_DECOMPRESS_GZIP=y CONFIG_GENERIC_ALLOCATOR=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y -CONFIG_NLATTR=y diff --git a/arch/arm/configs/imx5_defconfig b/arch/arm/configs/imx5_defconfig index 9934ad7403f6..47cf51acaa53 100644 --- a/arch/arm/configs/imx5_defconfig +++ b/arch/arm/configs/imx5_defconfig @@ -178,7 +178,7 @@ CONFIG_ARCH_MXC=y # CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP is not set CONFIG_IRAM_ALLOC=y -CONFIG_DMA_ZONE_SIZE=64 +CONFIG_DMA_ZONE_SIZE=96 CONFIG_UTMI_MXC=y # @@ -197,11 +197,15 @@ CONFIG_FORCE_MAX_ZONEORDER=13 CONFIG_ARCH_MXC_HAS_NFC_V3=y CONFIG_ARCH_MX51=y CONFIG_ARCH_MX53=y +CONFIG_ARCH_MX50=y CONFIG_MX5_OPTIONS=y CONFIG_MX5_MULTI_ARCH=y CONFIG_MACH_MX51_3DS=y CONFIG_MACH_MX51_BABBAGE=y CONFIG_MACH_MX53_EVK=y +CONFIG_MACH_MX50_ARM2=y +CONFIG_MACH_MX50_RDP=y +CONFIG_ARCH_MXC_IOMUX_V3=y # # MX5x Options: @@ -418,7 +422,17 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # # CONFIG_NET_PKTGEN is not set # CONFIG_HAMRADIO is not set -# CONFIG_CAN is not set +CONFIG_CAN=y +CONFIG_CAN_RAW=y +CONFIG_CAN_BCM=y + +# +# CAN Device Drivers +# +CONFIG_CAN_VCAN=y +# CONFIG_CAN_DEV is not set +CONFIG_CAN_DEBUG_DEVICES=y +CONFIG_CAN_FLEXCAN=y # CONFIG_IRDA is not set CONFIG_BT=y CONFIG_BT_L2CAP=y @@ -475,7 +489,7 @@ CONFIG_CONNECTOR=y CONFIG_PROC_EVENTS=y CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set -# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_CONCAT=y CONFIG_MTD_PARTITIONS=y # CONFIG_MTD_TESTS is not set # CONFIG_MTD_REDBOOT_PARTS is not set @@ -622,6 +636,7 @@ CONFIG_SCSI_LOWLEVEL=y CONFIG_ATA=m # CONFIG_ATA_NONSTANDARD is not set # CONFIG_SATA_PMP is not set +CONFIG_SATA_AHCI_PLATFORM=m CONFIG_ATA_SFF=y # CONFIG_SATA_MV is not set # CONFIG_PATA_PLATFORM is not set @@ -676,6 +691,7 @@ CONFIG_SMSC911X=y # CONFIG_KS8842 is not set # CONFIG_KS8851 is not set CONFIG_FEC=y +# CONFIG_FEC_1588 is not set # CONFIG_FEC2 is not set # CONFIG_NETDEV_1000 is not set # CONFIG_NETDEV_10000 is not set @@ -811,6 +827,7 @@ CONFIG_DEVKMEM=y # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_FM_SI4702=m CONFIG_MXC_IIM=y +CONFIG_MXS_VIIM=y CONFIG_IMX_SIM=m # @@ -1186,7 +1203,7 @@ CONFIG_VIDEO_MXC_IPU_CAMERA=y # CONFIG_MXC_CAMERA_MICRON111 is not set # CONFIG_MXC_CAMERA_OV2640 is not set CONFIG_MXC_CAMERA_OV3640=m -# CONFIG_MXC_TVIN_ADV7180 is not set +CONFIG_MXC_TVIN_ADV7180=m CONFIG_MXC_IPU_PRP_VF_SDC=m CONFIG_MXC_IPU_PRP_ENC=m CONFIG_MXC_IPU_CSI_ENC=m @@ -1277,6 +1294,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y # CONFIG_FB_SYS_IMAGEBLIT is not set # CONFIG_FB_FOREIGN_ENDIAN is not set # CONFIG_FB_SYS_FOPS is not set +CONFIG_FB_DEFERRED_IO=y # CONFIG_FB_SVGALIB is not set # CONFIG_FB_MACMODES is not set # CONFIG_FB_BACKLIGHT is not set @@ -1290,10 +1308,14 @@ CONFIG_FB_MXC=y CONFIG_FB_MXC_SYNC_PANEL=y CONFIG_FB_MXC_EPSON_VGA_SYNC_PANEL=y CONFIG_FB_MXC_TVOUT_TVE=y +CONFIG_FB_MXC_LDB=y # CONFIG_FB_MXC_CLAA_WVGA_SYNC_PANEL is not set +CONFIG_FB_MXC_SII9022=y CONFIG_FB_MXC_CH7026=y # CONFIG_FB_MXC_TVOUT_CH7024 is not set # CONFIG_FB_MXC_ASYNC_PANEL is not set +CONFIG_FB_MXC_EINK_PANEL=y +# CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE is not set # CONFIG_FB_UVESA is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set @@ -1372,14 +1394,17 @@ CONFIG_SND_USB=y CONFIG_SND_SOC=y CONFIG_SND_MXC_SOC=y CONFIG_SND_MXC_SOC_SSI=y +CONFIG_SND_MXC_SOC_ESAI=y CONFIG_SND_MXC_SOC_IRAM=y CONFIG_SND_SOC_IMX_3STACK_SGTL5000=y # CONFIG_SND_SOC_IMX_3STACK_AK4647 is not set # CONFIG_SND_SOC_IMX_3STACK_WM8580 is not set # CONFIG_SND_SOC_IMX_3STACK_AK5702 is not set # CONFIG_SND_SOC_IMX_3STACK_BLUETOOTH is not set +CONFIG_SND_SOC_IMX_3STACK_CS42888=y CONFIG_SND_SOC_I2C_AND_SPI=y # CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_CS42888=y CONFIG_SND_SOC_SGTL5000=y # CONFIG_SOUND_PRIME is not set CONFIG_HID_SUPPORT=y @@ -1684,7 +1709,21 @@ CONFIG_RTC_INTF_DEV_UIE_EMUL=y # CONFIG_RTC_DRV_MXC_V2 is not set # CONFIG_RTC_DRV_IMXDI is not set CONFIG_RTC_MC13892=y -# CONFIG_DMADEVICES is not set +CONFIG_DMADEVICES=y + +# +# DMA Devices +# +CONFIG_MXC_PXP=y +CONFIG_MXC_PXP_CLIENT_DEVICE=y +CONFIG_DMA_ENGINE=y + +# +# DMA Clients +# +# CONFIG_NET_DMA is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set # CONFIG_AUXDISPLAY is not set CONFIG_REGULATOR=y # CONFIG_REGULATOR_DEBUG is not set @@ -1695,6 +1734,7 @@ CONFIG_REGULATOR=y # CONFIG_REGULATOR_MAX1586 is not set # CONFIG_REGULATOR_LP3971 is not set CONFIG_REGULATOR_MC13892=y +CONFIG_REGULATOR_MAX17135=y CONFIG_UIO=y # CONFIG_UIO_PDRV is not set CONFIG_UIO_PDRV_GENIRQ=m @@ -1787,6 +1827,7 @@ CONFIG_GPS_IOCTRL=m # # MXC Media Local Bus Driver # +CONFIG_MXC_MLB=m # # i.MX ADC support @@ -1794,6 +1835,11 @@ CONFIG_GPS_IOCTRL=m # CONFIG_IMX_ADC is not set # +# MXC GPU support +# +CONFIG_MXC_AMD_GPU=m + +# # File systems # CONFIG_EXT2_FS=y @@ -2019,8 +2065,8 @@ CONFIG_CRYPTO=y # CONFIG_CRYPTO_NULL is not set # CONFIG_CRYPTO_CRYPTD is not set # CONFIG_CRYPTO_AUTHENC is not set -# CONFIG_CRYPTO_TEST is not set -# CONFIG_CRYPTO_CRYPTODEV is not set +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_CRYPTODEV=y # # Authenticated Encryption with Associated Data @@ -2032,10 +2078,10 @@ CONFIG_CRYPTO=y # # Block modes # -# CONFIG_CRYPTO_CBC is not set +CONFIG_CRYPTO_CBC=y # CONFIG_CRYPTO_CTR is not set # CONFIG_CRYPTO_CTS is not set -# CONFIG_CRYPTO_ECB 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 @@ -2066,7 +2112,7 @@ CONFIG_CRYPTO=y # # Ciphers # -# CONFIG_CRYPTO_AES is not set +CONFIG_CRYPTO_AES=y # CONFIG_CRYPTO_ANUBIS is not set # CONFIG_CRYPTO_ARC4 is not set # CONFIG_CRYPTO_BLOWFISH is not set diff --git a/arch/arm/include/asm/mach/flash.h b/arch/arm/include/asm/mach/flash.h index 4ca69fe2c850..8b57c2ed6d7e 100644 --- a/arch/arm/include/asm/mach/flash.h +++ b/arch/arm/include/asm/mach/flash.h @@ -34,6 +34,7 @@ struct flash_platform_data { void (*mmcontrol)(struct mtd_info *mtd, int sync_read); struct mtd_partition *parts; unsigned int nr_parts; + char *type; }; #endif diff --git a/arch/arm/mach-mx23/Kconfig b/arch/arm/mach-mx23/Kconfig index 0a122b009687..28009b0d62cb 100644 --- a/arch/arm/mach-mx23/Kconfig +++ b/arch/arm/mach-mx23/Kconfig @@ -7,3 +7,19 @@ config MACH_MX23EVK select USB_ARCH_HAS_EHCI endchoice + + +config MXS_UNIQUE_ID + bool "Support for UniqueID on boot media" + default y + +config MXS_UNIQUE_ID_OTP + bool "UniqueID on OTP" + depends on MXS_UNIQUE_ID + default y + +config VECTORS_PHY_ADDR + int "vectors address" + default 0 + help + This config set vectors table is located which physical address diff --git a/arch/arm/mach-mx23/Makefile b/arch/arm/mach-mx23/Makefile index 622981c9572d..a5e278190326 100644 --- a/arch/arm/mach-mx23/Makefile +++ b/arch/arm/mach-mx23/Makefile @@ -7,6 +7,7 @@ obj-y += pinctrl.o clock.o device.o serial.o power.o pm.o sleep.o bus_freq.o obj-$(CONFIG_MACH_MX23EVK) += mx23evk.o mx23evk_pins.o obj-$(CONFIG_GENERIC_GPIO) += gpio.o obj-$(CONFIG_MXS_RAM_FREQ_SCALING) +=emi.o +obj-$(CONFIG_MXS_UNIQUE_ID_OTP) += otp.o # USB support ifneq ($(strip $(CONFIG_USB_GADGET_ARC) $(CONFIG_USB_EHCI_ARC_OTG)),) diff --git a/arch/arm/mach-mx23/bus_freq.c b/arch/arm/mach-mx23/bus_freq.c index b4efabdfefcc..9133e6b1080a 100644 --- a/arch/arm/mach-mx23/bus_freq.c +++ b/arch/arm/mach-mx23/bus_freq.c @@ -46,36 +46,32 @@ #define CLKCTRL_BASE_ADDR IO_ADDRESS(CLKCTRL_PHYS_ADDR) #define DIGCTRL_BASE_ADDR IO_ADDRESS(DIGCTL_PHYS_ADDR) -#define BP_CLKCTRL_HBUS_ASM_ENABLE 20 -#define CLKCTRL_PLL_PWD_BIT 17 -#define CLKCTRL_PLL_BYPASS 0x1ff #define BF(value, field) (((value) << BP_##field) & BM_##field) struct profile profiles[] = { { 454736, 151580, 130910, 0, 1550000, - 1450000, 355000, 3300000, 1750000, 0 }, - { 392727, 130910, 130910, 0, 1475000, - 1375000, 225000, 3300000, 1750000, 0 }, - { 360000, 120000, 120000, 0, 1375000, - 1275000, 200000, 3300000, 1750000, 0 }, + 1450000, 355000, 3300000, 1750000, 24000, 0 }, + { 392727, 130910, 130910, 0, 1450000, + 1375000, 225000, 3300000, 1750000, 24000, 0x1CF3 }, + { 360000, 120000, 130910, 0, 1375000, + 1275000, 200000, 3300000, 1750000, 24000, 0x1CF3 }, { 261818, 130910, 130910, 0, 1275000, - 1175000, 173000, 3300000, 1750000, 0 }, + 1175000, 173000, 3300000, 1750000, 24000, 0x1CF3 }, #ifdef CONFIG_MXS_RAM_MDDR { 64000, 64000, 48000, 3, 1050000, - 975000, 150000, 3300000, 1750000, 0 }, + 975000, 150000, 3300000, 1750000, 24000, 0x1CF3 }, { 24000, 24000, 24000, 3, 1050000, - 975000, 150000, 3075000, 1725000, 1 }, + 975000, 150000, 3075000, 1725000, 6000, 0x1C93 }, #else { 64000, 64000, 96000, 3, 1050000, - 975000, 150000, 3300000, 1750000, 0 }, - { 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 }, + 975000, 150000, 3300000, 1750000, 24000, 0x1CF3 }, + { 24000, 24000, 96000, 3, 1050000, + 975000, 150000, 3300000, 1725000, 6000, 0x1C93 }, #endif }; static struct clk *usb_clk; static struct clk *lcdif_clk; -u32 clkseq_setting; int low_freq_used(void) { @@ -84,60 +80,14 @@ int low_freq_used(void) return 1; else return 0; - } - -void hbus_auto_slow_mode_enable(void) -{ - __raw_writel(BP_CLKCTRL_HBUS_ASM_ENABLE, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_SET); -} -EXPORT_SYMBOL(hbus_auto_slow_mode_enable); - -void hbus_auto_slow_mode_disable(void) -{ - __raw_writel(BP_CLKCTRL_HBUS_ASM_ENABLE, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR); } -EXPORT_SYMBOL(hbus_auto_slow_mode_disable); -int cpu_clk_set_pll_on(struct clk *clk, unsigned int freq) +int is_hclk_autoslow_ok(void) { - struct cpufreq_freqs freqs; - - freqs.old = clk_get_rate(clk); - freqs.cpu = 0; - freqs.new = freq; - - if (freqs.old == 24000 && freqs.new > 24000) { - /* turn pll on */ - __raw_writel(CLKCTRL_PLL_PWD_BIT, CLKCTRL_BASE_ADDR + - HW_CLKCTRL_PLLCTRL0_SET); - udelay(10); - } else if (freqs.old > 24000 && freqs.new == 24000) - clkseq_setting = __raw_readl(CLKCTRL_BASE_ADDR + - HW_CLKCTRL_CLKSEQ); - return 0; -} - -int cpu_clk_set_pll_off(struct clk *clk, unsigned int freq) -{ - struct cpufreq_freqs freqs; - - freqs.old = clk_get_rate(clk); - freqs.cpu = 0; - freqs.new = freq; - - if (freqs.old > 24000 && freqs.new == 24000) { - /* turn pll off */ - __raw_writel(CLKCTRL_PLL_PWD_BIT, CLKCTRL_BASE_ADDR + - HW_CLKCTRL_PLLCTRL0_CLR); - __raw_writel(CLKCTRL_PLL_BYPASS, CLKCTRL_BASE_ADDR + - HW_CLKCTRL_CLKSEQ); - } else if (freqs.old == 24000 && freqs.new > 24000) - __raw_writel(clkseq_setting, CLKCTRL_BASE_ADDR + - HW_CLKCTRL_CLKSEQ); - - return 0; + if (clk_get_usecount(usb_clk) == 0) + return 1; + else + return 0; } int timing_ctrl_rams(int ss) diff --git a/arch/arm/mach-mx23/clock.c b/arch/arm/mach-mx23/clock.c index 957a70213399..9e18dbc74337 100644 --- a/arch/arm/mach-mx23/clock.c +++ b/arch/arm/mach-mx23/clock.c @@ -18,10 +18,12 @@ #include <linux/kernel.h> #include <linux/init.h> +#include <linux/err.h> #include <linux/irq.h> #include <linux/io.h> #include <linux/clk.h> #include <linux/delay.h> +#include <linux/iram_alloc.h> #include <linux/platform_device.h> #include <mach/clock.h> @@ -29,17 +31,130 @@ #include "regs-clkctrl.h" #include "regs-digctl.h" +#include <mach/regs-rtc.h> #include <mach/mx23.h> #define CLKCTRL_BASE_ADDR IO_ADDRESS(CLKCTRL_PHYS_ADDR) #define DIGCTRL_BASE_ADDR IO_ADDRESS(DIGCTL_PHYS_ADDR) +#define RTC_BASE_ADDR IO_ADDRESS(RTC_PHYS_ADDR) + +/* these are the maximum clock speeds that have been + * validated to run at the minumum VddD target voltage level for cpu operation + * (presently 1.05V target, .975V Brownout). Higher clock speeds for GPMI and + * SSP have not been validated. + */ +#define PLL_ENABLED_MAX_CLK_SSP 96000000 +#define PLL_ENABLED_MAX_CLK_GPMI 96000000 + /* external clock input */ -static struct clk xtal_clk[]; -static unsigned long xtal_clk_rate[3] = { 24000000, 24000000, 32000 }; +static struct clk pll_clk; +static struct clk ref_xtal_clk; + +#ifdef DEBUG +static void print_ref_counts(void); +#endif static unsigned long enet_mii_phy_rate; +static inline int clk_is_busy(struct clk *clk) +{ + if ((clk->parent == &ref_xtal_clk) && (clk->xtal_busy_bits)) + return __raw_readl(clk->busy_reg) & (1 << clk->xtal_busy_bits); + else if (clk->busy_bits && clk->busy_reg) + return __raw_readl(clk->busy_reg) & (1 << clk->busy_bits); + else { + printk(KERN_ERR "WARNING: clock has no assigned busy \ + register or bits\n"); + udelay(10); + return 0; + } +} + +static inline int clk_busy_wait(struct clk *clk) +{ + int i; + + for (i = 10000000; i; i--) + if (!clk_is_busy(clk)) + break; + if (!i) + return -ETIMEDOUT; + else + return 0; +} + +static bool mx23_enable_h_autoslow(bool enable) +{ + bool currently_enabled; + + if (__raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_HBUS) & + BM_CLKCTRL_HBUS_AUTO_SLOW_MODE) + currently_enabled = true; + else + currently_enabled = false; + + if (enable) + __raw_writel(BM_CLKCTRL_HBUS_AUTO_SLOW_MODE, + CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_SET); + else + __raw_writel(BM_CLKCTRL_HBUS_AUTO_SLOW_MODE, + CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR); + return currently_enabled; +} + + +static void mx23_set_hbus_autoslow_flags(u16 mask) +{ + u32 reg; + + reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); + reg &= 0xFFFF; + reg |= mask << 16; + __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); +} + +static void local_clk_disable(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk) || !clk->ref) + return; + + if ((--clk->ref) & CLK_EN_MASK) + return; + + if (clk->disable) + clk->disable(clk); + local_clk_disable(clk->secondary); + local_clk_disable(clk->parent); +} + +static int local_clk_enable(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + if ((clk->ref++) & CLK_EN_MASK) + return 0; + if (clk->parent) + local_clk_enable(clk->parent); + if (clk->secondary) + local_clk_enable(clk->secondary); + if (clk->enable) + clk->enable(clk); + return 0; +} + + +static bool mx23_is_clk_enabled(struct clk *clk) +{ + if (clk->enable_reg) + return (__raw_readl(clk->enable_reg) & + clk->enable_bits) ? 0 : 1; + else + return (clk->ref & CLK_EN_MASK) ? 1 : 0; +} + + static int mx23_raw_enable(struct clk *clk) { unsigned int reg; @@ -48,6 +163,9 @@ static int mx23_raw_enable(struct clk *clk) reg &= ~clk->enable_bits; __raw_writel(reg, clk->enable_reg); } + if (clk->busy_reg) + clk_busy_wait(clk); + return 0; } @@ -61,29 +179,14 @@ static void mx23_raw_disable(struct clk *clk) } } -static unsigned long xtal_get_rate(struct clk *clk) +static unsigned long ref_xtal_get_rate(struct clk *clk) { - int id = clk - xtal_clk; - return xtal_clk_rate[id]; + return 24000000; } -static struct clk xtal_clk[] = { - { - .flags = RATE_FIXED, - .get_rate = xtal_get_rate, - }, - { - .flags = RATE_FIXED, - .get_rate = xtal_get_rate, - }, - { - .flags = RATE_FIXED, - .get_rate = xtal_get_rate, - }, -}; - static struct clk ref_xtal_clk = { - .parent = &xtal_clk[0], + .flags = RATE_FIXED, + .get_rate = ref_xtal_get_rate, }; static unsigned long pll_get_rate(struct clk *clk); @@ -107,20 +210,23 @@ static unsigned long pll_get_rate(struct clk *clk) static int pll_enable(struct clk *clk) { - int timeout = 100; - unsigned long reg; + u32 reg; + + reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_PLLCTRL0); + + if ((reg & BM_CLKCTRL_PLLCTRL0_POWER) && + (reg & BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS)) + return 0; __raw_writel(BM_CLKCTRL_PLLCTRL0_POWER | BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS, CLKCTRL_BASE_ADDR + HW_CLKCTRL_PLLCTRL0_SET); - do { - udelay(10); - reg = __raw_readl(CLKCTRL_BASE_ADDR + - HW_CLKCTRL_PLLCTRL1); - timeout--; - } while ((timeout > 0) && !(reg & BM_CLKCTRL_PLLCTRL1_LOCK)); - if (timeout <= 0) - return -EFAULT; + /* only a 10us delay is need. PLLCTRL1 LOCK bitfied is only a timer + * and is incorrect (excessive). Per definition of the PLLCTRL0 + * POWER field, waiting at least 10us. + */ + udelay(10); + return 0; } @@ -171,6 +277,8 @@ static unsigned long ref_cpu_get_rate(struct clk *clk) static struct clk ref_cpu_clk = { .parent = &pll_clk, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, .get_rate = ref_cpu_get_rate, .round_rate = ref_clk_round_rate, .set_rate = ref_clk_set_rate, @@ -178,6 +286,8 @@ static struct clk ref_cpu_clk = { .enable_bits = BM_CLKCTRL_FRAC_CLKGATECPU, .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC, .scale_bits = BP_CLKCTRL_FRAC_CPUFRAC, + .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU, + .busy_bits = 28, }; static unsigned long ref_emi_get_rate(struct clk *clk) @@ -191,6 +301,8 @@ static unsigned long ref_emi_get_rate(struct clk *clk) static struct clk ref_emi_clk = { .parent = &pll_clk, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, .get_rate = ref_emi_get_rate, .set_rate = ref_clk_set_rate, .round_rate = ref_clk_round_rate, @@ -202,10 +314,12 @@ static struct clk ref_emi_clk = { static unsigned long ref_io_get_rate(struct clk *clk); static struct clk ref_io_clk = { - .parent = &pll_clk, - .get_rate = ref_io_get_rate, - .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC, - .enable_bits = BM_CLKCTRL_FRAC_CLKGATEIO, + .parent = &pll_clk, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, + .get_rate = ref_io_get_rate, + .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC, + .enable_bits = BM_CLKCTRL_FRAC_CLKGATEIO, }; static unsigned long ref_io_get_rate(struct clk *clk) @@ -229,6 +343,8 @@ static unsigned long ref_pix_get_rate(struct clk *clk) static struct clk ref_pix_clk = { .parent = &pll_clk, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, .get_rate = ref_pix_get_rate, .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC, .enable_bits = BM_CLKCTRL_FRAC_CLKGATEPIX, @@ -237,63 +353,20 @@ static struct clk ref_pix_clk = { static struct clk cpu_clk, h_clk; static int clkseq_set_parent(struct clk *clk, struct clk *parent) { - int ret = -EINVAL; - int shift = 8; + int shift; + if (clk->parent == parent) + return 0; /* clock parent already at target. nothing to do */ /* bypass? */ if (parent == &ref_xtal_clk) shift = 4; + else + shift = 8; - if (clk->bypass_reg) { - u32 hbus_val, cpu_val; - - if (clk == &cpu_clk && shift == 4) { - hbus_val = __raw_readl(CLKCTRL_BASE_ADDR + - HW_CLKCTRL_HBUS); - cpu_val = __raw_readl(CLKCTRL_BASE_ADDR + - HW_CLKCTRL_CPU); - - hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN | - BM_CLKCTRL_HBUS_DIV); - hbus_val |= 1; - - cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU; - cpu_val |= 1; - - __raw_writel(1 << clk->bypass_bits, - clk->bypass_reg + shift); - - __raw_writel(hbus_val, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); - __raw_writel(cpu_val, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); - /* h_clk.rate = 0; */ - } else if (clk == &cpu_clk && shift == 8) { - hbus_val = __raw_readl(CLKCTRL_BASE_ADDR + - HW_CLKCTRL_HBUS); - cpu_val = __raw_readl(CLKCTRL_BASE_ADDR + - HW_CLKCTRL_CPU); - hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN | - BM_CLKCTRL_HBUS_DIV); - hbus_val |= 2; - cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU; - cpu_val |= 2; - - __raw_writel(hbus_val, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); - __raw_writel(cpu_val, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); - /* h_clk.rate = 0; */ + if (clk->bypass_reg) + __raw_writel(1 << clk->bypass_bits, clk->bypass_reg + shift); - __raw_writel(1 << clk->bypass_bits, - clk->bypass_reg + shift); - } else - __raw_writel(1 << clk->bypass_bits, - clk->bypass_reg + shift); - ret = 0; - } - - return ret; + return 0; } static unsigned long lcdif_get_rate(struct clk *clk) @@ -336,6 +409,8 @@ static int lcdif_set_rate(struct clk *clk, unsigned long rate) ns_cycle *= 2; /* Fix calculate double frequency */ + + for (div = 1; div < 256; ++div) { u32 fracdiv; u32 ps_result; @@ -394,16 +469,9 @@ static int lcdif_set_rate(struct clk *clk, unsigned long rate) __raw_writel(reg_val, clk->scale_reg); /* Wait for divider update */ - if (clk->busy_reg) { - int i; - for (i = 10000; i; i--) - if (!clk_is_busy(clk)) - break; - if (!i) { - ret = -ETIMEDOUT; - goto out; - } - } + ret = clk_busy_wait(clk); + if (ret) + goto out; /* Switch to ref_pix source */ reg_val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ); @@ -414,6 +482,14 @@ out: return ret; } +/* + * We set lcdif_clk's parent as &pll_clk deliberately, although + * in IC spec lcdif_clk(CLK_PIX) is derived from ref_pix which in turn + * is derived from PLL. By doing so, users just need to set/get clock rate + * for lcdif_clk, without need to take care of ref_pix, because the clock + * driver will automatically calculate the fracdivider for HW_CLKCTRL_FRAC + * and the divider for HW_CLKCTRL_PIX conjointly. + */ static struct clk lcdif_clk = { .parent = &pll_clk, .enable = mx23_raw_enable, @@ -464,20 +540,77 @@ static unsigned long cpu_round_rate(struct clk *clk, unsigned long rate) static int cpu_set_rate(struct clk *clk, unsigned long rate) { - unsigned long root_rate = - clk->parent->parent->get_rate(clk->parent->parent); - int i; + unsigned long root_rate = pll_clk.get_rate(&pll_clk); + int ret = -EINVAL; u32 clkctrl_cpu = 1; u32 c = clkctrl_cpu; u32 clkctrl_frac = 1; u32 val; - u32 reg_val; + u32 reg_val, hclk_reg; + bool h_autoslow; - if (rate < 24000000) + /* make sure the cpu div_xtal is 1 */ + reg_val = __raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_CPU); + reg_val &= ~(BM_CLKCTRL_CPU_DIV_XTAL); + reg_val |= (1 << BP_CLKCTRL_CPU_DIV_XTAL); + __raw_writel(reg_val, CLKCTRL_BASE_ADDR+HW_CLKCTRL_CPU); + + if (rate < ref_xtal_get_rate(&ref_xtal_clk)) return -EINVAL; - else if (rate == 24000000) { + + if (rate == clk_get_rate(clk)) + return 0; + /* temporaily disable h autoslow to avoid + * hclk getting too slow while temporarily + * changing clocks + */ + h_autoslow = mx23_enable_h_autoslow(false); + + if (rate == ref_xtal_get_rate(&ref_xtal_clk)) { + /* switch to the 24M source */ clk_set_parent(clk, &ref_xtal_clk); + + /* to avoid bus starvation issues, we'll go ahead + * and change hbus clock divider to 1 now. Cpufreq + * or other clock management can lower it later if + * desired for power savings or other reasons, but + * there should be no need to with hbus autoslow + * functionality enabled. + */ + + ret = clk_busy_wait(&cpu_clk); + if (ret) { + printk(KERN_ERR "* couldn't set\ + up CPU divisor\n"); + return ret; + } + + ret = clk_busy_wait(&h_clk); + if (ret) { + printk(KERN_ERR "* H_CLK busy timeout\n"); + return ret; + } + + hclk_reg = __raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_HBUS); + hclk_reg &= ~(BM_CLKCTRL_HBUS_DIV); + hclk_reg |= (1 << BP_CLKCTRL_HBUS_DIV); + + __raw_writel(hclk_reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_SET); + + ret = clk_busy_wait(&cpu_clk); + if (ret) { + printk(KERN_ERR "** couldn't set\ + up CPU divisor\n"); + return ret; + } + + ret = clk_busy_wait(&h_clk); + if (ret) { + printk(KERN_ERR "** CLK busy timeout\n"); + return ret; + } + } else { for ( ; c < 0x40; c++) { u32 f = ((root_rate/1000)*18/c + (rate/1000)/2) / @@ -502,33 +635,116 @@ static int cpu_set_rate(struct clk *clk, unsigned long rate) if ((abs(d) > 100) || (clkctrl_frac < 18) || (clkctrl_frac > 35)) return -EINVAL; - } + } - /* Set Frac div */ + /* prepare Frac div */ val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); - val &= ~(BM_CLKCTRL_FRAC_CPUFRAC << BP_CLKCTRL_FRAC_CPUFRAC); - val |= clkctrl_frac; - __raw_writel(val, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); - /* Do not gate */ - __raw_writel(BM_CLKCTRL_FRAC_CLKGATECPU, CLKCTRL_BASE_ADDR + - HW_CLKCTRL_FRAC_CLR); + val &= ~(BM_CLKCTRL_FRAC_CPUFRAC); + val |= (clkctrl_frac << BP_CLKCTRL_FRAC_CPUFRAC); - /* write clkctrl_cpu */ + /* prepare clkctrl_cpu div*/ reg_val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); reg_val &= ~0x3F; reg_val |= clkctrl_cpu; + /* set safe hbus clock divider. A divider of 3 ensure that + * the Vddd voltage required for the cpuclk is sufficiently + * high for the hbus clock and under 24MHz cpuclk conditions, + * a divider of at least 3 ensures hbusclk doesn't remain + * uneccesarily low which hurts performance + */ + hclk_reg = __raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_HBUS); + hclk_reg &= ~(BM_CLKCTRL_HBUS_DIV); + hclk_reg |= (3 << BP_CLKCTRL_HBUS_DIV); + + /* if the pll was OFF, we need to turn it ON. + * Even if it was ON, we want to temporarily + * increment it by 1 to avoid turning off + * in the upcoming parent clock change to xtal. This + * avoids waiting an extra 10us for every cpu clock + * change between ref_cpu sourced frequencies. + */ + pll_enable(&pll_clk); + pll_clk.ref++; + + /* switch to XTAL CLK source temparily while + * we manipulate ref_cpu frequency */ + clk_set_parent(clk, &ref_xtal_clk); + + ret = clk_busy_wait(&h_clk); + + if (ret) { + printk(KERN_ERR "-* HCLK busy wait timeout\n"); + return ret; + } + + ret = clk_busy_wait(clk); + + if (ret) { + printk(KERN_ERR "-* couldn't set\ + up CPU divisor\n"); + return ret; + } + + __raw_writel(val, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); + + /* clear the gate */ + __raw_writel(BM_CLKCTRL_FRAC_CLKGATECPU, CLKCTRL_BASE_ADDR + + HW_CLKCTRL_FRAC_CLR); + + /* set the ref_cpu integer divider */ __raw_writel(reg_val, CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); - for (i = 10000; i; i--) - if (!clk_is_busy(clk)) - break; - if (!i) { - printk(KERN_ERR "couldn't set up CPU divisor\n"); - return -ETIMEDOUT; + /* wait for the ref_cpu path to become stable before + * switching over to it + */ + + ret = clk_busy_wait(&ref_cpu_clk); + + if (ret) { + printk(KERN_ERR "-** couldn't set\ + up CPU divisor\n"); + return ret; } + + /* change hclk divider to safe value for any ref_cpu + * value. + */ + __raw_writel(hclk_reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); + + ret = clk_busy_wait(&h_clk); + + if (ret) { + printk(KERN_ERR "-** HCLK busy wait timeout\n"); + return ret; + } + + clk_set_parent(clk, &ref_cpu_clk); + + /* decrement the pll_clk ref count because + * we temporarily enabled/incremented the count + * above. + */ + pll_clk.ref--; + + ret = clk_busy_wait(&cpu_clk); + + if (ret) { + printk(KERN_ERR "-*** Couldn't set\ + up CPU divisor\n"); + return ret; + } + + ret = clk_busy_wait(&h_clk); + + if (ret) { + printk(KERN_ERR "-*** HCLK busy wait timeout\n"); + return ret; + } + } - return 0; + mx23_enable_h_autoslow(h_autoslow); + return ret; } static struct clk cpu_clk = { @@ -543,6 +759,7 @@ static struct clk cpu_clk = { .bypass_bits = 7, .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU, .busy_bits = 28, + .xtal_busy_bits = 29, }; static unsigned long uart_get_rate(struct clk *clk) @@ -598,25 +815,99 @@ static unsigned long x_get_rate(struct clk *clk) return clk->parent->get_rate(clk->parent) / reg; } +static unsigned long x_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned int root_rate, frac_rate; + unsigned int div; + root_rate = clk->parent->get_rate(clk->parent); + frac_rate = root_rate % rate; + div = root_rate / rate; + /* while the reference manual specifies that divider + * values up to 1023 are aloud, other critial SoC compents + * require higher x clock values at all times. Through + * limited testing, the lradc functionality to measure + * the battery voltage and copy this value to the + * power supply requires at least a 64kHz xclk. + * so the divider will be limited to 375. + */ + if ((div == 0) || (div > 375)) + return root_rate; + if (frac_rate == 0) + return rate; + else + return root_rate / (div + 1); +} + +static int x_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long root_rate; + unsigned long round_rate; + unsigned int reg, div; + root_rate = clk->parent->get_rate(clk->parent); + + if ((!clk->round_rate) || !(clk->scale_reg)) + return -EINVAL; + + round_rate = clk->round_rate(clk, rate); + div = root_rate / round_rate; + + if (root_rate % round_rate) + return -EINVAL; + + reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS); + reg &= ~(BM_CLKCTRL_XBUS_DIV_FRAC_EN | BM_CLKCTRL_XBUS_DIV); + reg |= BF_CLKCTRL_XBUS_DIV(div); + __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS); + + return clk_busy_wait(clk); + +} + static struct clk x_clk = { .parent = &ref_xtal_clk, .get_rate = x_get_rate, + .set_rate = x_set_rate, + .round_rate = x_round_rate, + .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS, + .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS, + .busy_bits = 31, }; + + static struct clk ana_clk = { .parent = &ref_xtal_clk, }; -static unsigned long rtc_get_rate(struct clk *clk) + + +static unsigned long xtal_clock32k_get_rate(struct clk *clk) { - if (clk->parent == &xtal_clk[2]) - return clk->parent->get_rate(clk->parent); - return clk->parent->get_rate(clk->parent) / 768; + if (__raw_readl(RTC_BASE_ADDR + HW_RTC_PERSISTENT0) & + BM_RTC_PERSISTENT0_XTAL32_FREQ) + return 32000; + else + return 32768; } -static struct clk rtc_clk = { - .parent = &ref_xtal_clk, - .get_rate = rtc_get_rate, +static struct clk xtal_clock32k_clk = { + .get_rate = xtal_clock32k_get_rate, +}; + +static unsigned long rtc32k_get_rate(struct clk *clk) +{ + if (clk->parent == &ref_xtal_clk) + /* mx23 reference manual had error. + * fixed divider is 750 not 768 + */ + return clk->parent->get_rate(clk->parent) / 750; + else + return xtal_clock32k_get_rate(clk); +} + +static struct clk rtc32k_clk = { + .parent = &xtal_clock32k_clk, + .get_rate = rtc32k_get_rate, }; static unsigned long h_get_rate(struct clk *clk) @@ -656,23 +947,14 @@ static int h_set_rate(struct clk *clk, unsigned long rate) if (root_rate % round_rate) return -EINVAL; - if ((root_rate < rate) && (root_rate == 64000000)) - div = 3; - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); reg &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN | BM_CLKCTRL_HBUS_DIV); reg |= BF_CLKCTRL_HBUS_DIV(div); __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); - if (clk->busy_reg) { - int i; - for (i = 10000; i; i--) - if (!clk_is_busy(clk)) - break; - if (!i) { - printk(KERN_ERR "couldn't set up AHB divisor\n"); - return -ETIMEDOUT; - } + if (clk_busy_wait(clk)) { + printk(KERN_ERR "couldn't set up AHB divisor\n"); + return -EINVAL; } return 0; @@ -720,29 +1002,39 @@ static unsigned long emi_round_rate(struct clk *clk, unsigned long rate) return root_rate / div; } +/* when changing the emi clock, dram access must be + * disabled. Special handling is needed to perform + * the emi clock change without touching sdram. + */ static int emi_set_rate(struct clk *clk, unsigned long rate) { int ret = 0; - if (rate < 24000) + struct mxs_emi_scaling_data sc_data; + + unsigned long clkctrl_emi; + unsigned long clkctrl_frac; + int div = 1; + unsigned long root_rate, cur_emi_div, cur_emi_frac; + struct clk *target_parent_p = &ref_xtal_clk; + + if (rate < ref_xtal_get_rate(&ref_xtal_clk)) return -EINVAL; - else { - int i; - struct mxs_emi_scaling_data sc_data; - int (*scale)(struct mxs_emi_scaling_data *) = - (void *)(MX23_OCRAM_BASE + 0x1000); - void *saved_ocram; - unsigned long clkctrl_emi; - unsigned long clkctrl_frac; - int div = 1; - unsigned long root_rate = - clk->parent->parent->get_rate(clk->parent->parent); - /* - * We've been setting div to HW_CLKCTRL_CPU_RD() & 0x3f so far. - * TODO: verify 1 is still valid. - */ - if (!mxs_ram_funcs_sz) - goto out; + + if (!mxs_ram_funcs_sz) + goto out; + + sc_data.cur_freq = (clk->get_rate(clk)) / 1000 / 1000; + sc_data.new_freq = rate / 1000 / 1000; + + if (sc_data.cur_freq == sc_data.new_freq) + goto out; + + if (rate != ref_xtal_get_rate(&ref_xtal_clk)) { + target_parent_p = &ref_emi_clk; + pll_enable(&pll_clk); + + root_rate = pll_clk.get_rate(&pll_clk); for (clkctrl_emi = div; clkctrl_emi < 0x3f; clkctrl_emi += div) { @@ -764,37 +1056,62 @@ static int emi_set_rate(struct clk *clk, unsigned long rate) pr_debug("%s: clkctrl_emi %ld, clkctrl_frac %ld\n", __func__, clkctrl_emi, clkctrl_frac); - saved_ocram = kmalloc(mxs_ram_funcs_sz, GFP_KERNEL); - if (!saved_ocram) - return -ENOMEM; - memcpy(saved_ocram, scale, mxs_ram_funcs_sz); - memcpy(scale, mxs_ram_freq_scale, mxs_ram_funcs_sz); - sc_data.emi_div = clkctrl_emi; sc_data.frac_div = clkctrl_frac; - sc_data.cur_freq = (clk->get_rate(clk)) / 1000 / 1000; - sc_data.new_freq = rate / 1000 / 1000; + } + + + cur_emi_div = ((__raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_EMI) & + BM_CLKCTRL_EMI_DIV_EMI) >> BP_CLKCTRL_EMI_DIV_EMI); + cur_emi_frac = ((__raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_FRAC) & + BM_CLKCTRL_EMI_DIV_EMI) >> BP_CLKCTRL_FRAC_EMIFRAC); + + if ((cur_emi_div == sc_data.emi_div) && + (cur_emi_frac == sc_data.frac_div)) + goto out; + { + unsigned long iram_phy; + bool h_autoslow; + int (*scale)(struct mxs_emi_scaling_data *) = + iram_alloc(mxs_ram_funcs_sz, &iram_phy); + + if (NULL == scale) { + pr_err("%s Not enough iram\n", __func__); + return -ENOMEM; + } + + /* temporaily disable h autoslow to maximize + * performance/minimize time spent with no + * sdram access + */ + h_autoslow = mx23_enable_h_autoslow(false); + + memcpy(scale, mxs_ram_freq_scale, mxs_ram_funcs_sz); local_irq_disable(); local_fiq_disable(); scale(&sc_data); + iram_free(iram_phy, mxs_ram_funcs_sz); + local_fiq_enable(); local_irq_enable(); - for (i = 10000; i; i--) - if (!clk_is_busy(clk)) - break; - memcpy(scale, saved_ocram, mxs_ram_funcs_sz); - kfree(saved_ocram); - - if (!i) { - printk(KERN_ERR "couldn't set up EMI divisor\n"); - ret = -ETIMEDOUT; - goto out; - } + /* temporaily disable h autoslow to avoid + * hclk getting too slow while temporarily + * changing clocks + */ + mx23_enable_h_autoslow(h_autoslow); } + + /* this code is for keeping track of ref counts. + * and disabling previous parent if necessary + * actual clkseq changes have already + * been made. + */ + clk_set_parent(clk, target_parent_p); + out: return ret; } @@ -812,8 +1129,9 @@ static struct clk emi_clk = { .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC, .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_EMI, .busy_bits = 28, + .xtal_busy_bits = 29, .bypass_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ, - .bypass_bits = 7, + .bypass_bits = 6, }; static unsigned long ssp_get_rate(struct clk *clk); @@ -821,37 +1139,40 @@ static unsigned long ssp_get_rate(struct clk *clk); static int ssp_set_rate(struct clk *clk, unsigned long rate) { int ret = -EINVAL; - int div = (clk_get_rate(clk->parent) + rate - 1) / rate; - u32 reg_frac; - const int mask = 0x1FF; - int try = 10; - int i = -1; + u32 reg, div; + bool is_clk_enable; - if (div == 0 || div > mask) - goto out; + is_clk_enable = mx23_is_clk_enabled(clk); + if (!is_clk_enable) + local_clk_enable(clk); - reg_frac = __raw_readl(clk->scale_reg); - reg_frac &= ~(mask << clk->scale_bits); + /* if the desired clock can be sourced from ref_xtal, + * use ref_xtal to save power + */ + if ((rate <= ref_xtal_get_rate(&ref_xtal_clk)) && + ((ref_xtal_get_rate(&ref_xtal_clk) % rate) == 0)) + clk_set_parent(clk, &ref_xtal_clk); + else + clk_set_parent(clk, &ref_io_clk); - while (try--) { - __raw_writel(reg_frac | (div << clk->scale_bits), - clk->scale_reg); + if (rate > PLL_ENABLED_MAX_CLK_SSP) + rate = PLL_ENABLED_MAX_CLK_SSP; - if (clk->busy_reg) { - for (i = 10000; i; i--) - if (!clk_is_busy(clk)) - break; - } - if (i) - break; - } + div = (clk_get_rate(clk->parent) + rate - 1) / rate; - if (!i) - ret = -ETIMEDOUT; - else - ret = 0; + if (div == 0 || div > BM_CLKCTRL_SSP_DIV) + goto out; + + reg = __raw_readl(clk->scale_reg); + reg &= ~(BM_CLKCTRL_SSP_DIV | BM_CLKCTRL_SSP_DIV_FRAC_EN); + reg |= div << clk->scale_bits; + __raw_writel(reg, clk->scale_reg); + ret = clk_busy_wait(clk); out: + if (!is_clk_enable) + local_clk_disable(clk); + if (ret != 0) printk(KERN_ERR "%s: error %d\n", __func__, ret); return ret; @@ -877,6 +1198,26 @@ static int ssp_set_parent(struct clk *clk, struct clk *parent) return ret; } +/* handle peripheral clocks whose optimal parent dependent on + * system parameters such as cpu_clk rate. For now, this optimization + * only occurs to the peripheral clock when it's not in use to avoid + * handling more complex system clock coordination issues. + */ +static int ssp_set_sys_dependent_parent(struct clk *clk) +{ + if ((clk->ref & CLK_EN_MASK) == 0) { + if (clk_get_rate(&cpu_clk) > ref_xtal_get_rate(&ref_xtal_clk)) { + clk_set_parent(clk, &ref_io_clk); + clk_set_rate(clk, PLL_ENABLED_MAX_CLK_SSP); + } else { + clk_set_parent(clk, &ref_xtal_clk); + clk_set_rate(clk, ref_xtal_get_rate(&ref_xtal_clk)); + } + } + + return 0; +} + static struct clk ssp_clk = { .parent = &ref_io_clk, .get_rate = ssp_get_rate, @@ -889,9 +1230,10 @@ static struct clk ssp_clk = { .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP, .scale_bits = 0, .bypass_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ, - .bypass_bits = 3, + .bypass_bits = 5, .set_rate = ssp_set_rate, .set_parent = ssp_set_parent, + .set_sys_dependent_parent = ssp_set_sys_dependent_parent, }; static unsigned long ssp_get_rate(struct clk *clk) @@ -903,6 +1245,123 @@ static unsigned long ssp_get_rate(struct clk *clk) return clk->parent->get_rate(clk->parent) / reg; } +static unsigned long gpmi_get_rate(struct clk *clk) +{ + unsigned int reg; + reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI) & + BM_CLKCTRL_GPMI_DIV; + + return clk->parent->get_rate(clk->parent) / reg; +} + +static int gpmi_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = -EINVAL; + u32 reg, div; + + /* Make absolutely certain the clock is enabled. */ + local_clk_enable(clk); + + /* if the desired clock can be sourced from ref_xtal, + * use ref_xtal to save power + */ + if ((rate <= ref_xtal_get_rate(&ref_xtal_clk)) && + ((ref_xtal_get_rate(&ref_xtal_clk) % rate) == 0)) + clk_set_parent(clk, &ref_xtal_clk); + else + clk_set_parent(clk, &ref_io_clk); + + if (rate > PLL_ENABLED_MAX_CLK_SSP) + rate = PLL_ENABLED_MAX_CLK_GPMI; + + div = (clk_get_rate(clk->parent) + rate - 1) / rate; + + if (div == 0 || div > BM_CLKCTRL_GPMI_DIV) + goto out; + + reg = __raw_readl(clk->scale_reg); + reg &= ~(BM_CLKCTRL_GPMI_DIV | BM_CLKCTRL_GPMI_DIV_FRAC_EN); + reg |= div << clk->scale_bits; + __raw_writel(reg, clk->scale_reg); + + ret = clk_busy_wait(clk); + +out: + + /* Undo the enable above. */ + local_clk_disable(clk); + + if (ret != 0) + printk(KERN_ERR "%s: error %d\n", __func__, ret); + return ret; +} + +static int gpmi_set_parent(struct clk *clk, struct clk *parent) +{ + int ret = -EINVAL; + + if (clk->bypass_reg) { + if (clk->parent == parent) + return 0; + if (parent == &ref_io_clk) + __raw_writel(1 << clk->bypass_bits, + clk->bypass_reg + CLR_REGISTER); + else + __raw_writel(1 << clk->bypass_bits, + clk->bypass_reg + SET_REGISTER); + clk->parent = parent; + ret = 0; + } + + return ret; +} + +/* handle peripheral clocks whose optimal parent dependent on + * system parameters such as cpu_clk rate. For now, this optimization + * only occurs to the peripheral clock when it's not in use to avoid + * handling more complex system clock coordination issues. + */ +static int gpmi_set_sys_dependent_parent(struct clk *clk) +{ + + if ((clk->ref & CLK_EN_MASK) == 0) { + if (clk_get_rate(&cpu_clk) > ref_xtal_get_rate(&ref_xtal_clk)) { + clk_set_parent(clk, &ref_io_clk); + clk_set_rate(clk, PLL_ENABLED_MAX_CLK_GPMI); + } else { + clk_set_parent(clk, &ref_xtal_clk); + clk_set_rate(clk, ref_xtal_get_rate(&ref_xtal_clk)); + } + } + + return 0; +} + +static struct clk gpmi_clk = { + .parent = &ref_io_clk, + .secondary = 0, + .flags = 0, + .set_parent = gpmi_set_parent, + .set_sys_dependent_parent = gpmi_set_sys_dependent_parent, + + .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI, + .enable_bits = BM_CLKCTRL_GPMI_CLKGATE, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, + + .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI, + .scale_bits = 0, + .round_rate = 0, + .set_rate = gpmi_set_rate, + .get_rate = gpmi_get_rate, + + .bypass_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ, + .bypass_bits = 4, + + .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI, + .busy_bits = 29, +}; + static unsigned long pcmspdif_get_rate(struct clk *clk) { return clk->parent->get_rate(clk->parent) / 4; @@ -935,21 +1394,34 @@ static struct clk audio_clk = { .enable_bits = BM_CLKCTRL_XTAL_FILT_CLK24M_GATE, }; +static struct clk vid_clk = { + .parent = &ref_xtal_clk, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, + .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC1, + .enable_bits = BM_CLKCTRL_FRAC1_CLKGATEVID, +}; + +static struct clk tv108M_ng_clk = { + .parent = &vid_clk, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, + .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_TV, + .enable_bits = BM_CLKCTRL_TV_CLK_TV108M_GATE, + .flags = RATE_FIXED, +}; + +static struct clk tv27M_clk = { + .parent = &vid_clk, + .enable = mx23_raw_enable, + .disable = mx23_raw_disable, + .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_TV, + .enable_bits = BM_CLKCTRL_TV_CLK_TV_GATE, + .flags = RATE_FIXED, +}; static struct clk_lookup onchip_clocks[] = { { - .con_id = "xtal.0", - .clk = &xtal_clk[0], - }, - { - .con_id = "xtal.1", - .clk = &xtal_clk[1], - }, - { - .con_id = "xtal.2", - .clk = &xtal_clk[2], - }, - { .con_id = "pll.0", .clk = &pll_clk, }, @@ -978,8 +1450,12 @@ static struct clk_lookup onchip_clocks[] = { .clk = &lcdif_clk, }, { + .con_id = "xtal_clock32k", + .clk = &xtal_clock32k_clk, + }, + { .con_id = "rtc", - .clk = &rtc_clk, + .clk = &rtc32k_clk, }, { .con_id = "cpu", @@ -1032,9 +1508,53 @@ static struct clk_lookup onchip_clocks[] = { { .con_id = "spdif", .clk = &pcmspdif_clk, - } + }, + { + .con_id = "ref_vid", + .clk = &vid_clk, + }, + { + .con_id = "tv108M_ng", + .clk = &tv108M_ng_clk, + }, + { + .con_id = "tv27M", + .clk = &tv27M_clk, + }, + { + .con_id = "gpmi", + .clk = &gpmi_clk, + }, }; +/* for debugging */ +#ifdef DEBUG +static void print_ref_counts(void) +{ + + printk(KERN_INFO "pll_clk ref count: %i\n", + pll_clk.ref & CLK_EN_MASK); + + printk(KERN_INFO "ref_cpu_clk ref count: %i\n", + ref_cpu_clk.ref & CLK_EN_MASK); + + printk(KERN_INFO "ref_emi_clk ref count: %i\n", + ref_emi_clk.ref & CLK_EN_MASK); + + printk(KERN_INFO "lcdif_clk ref count: %i\n", + lcdif_clk.ref & CLK_EN_MASK); + + printk(KERN_INFO "ref_io_clk ref count: %i\n", + ref_io_clk.ref & CLK_EN_MASK); + + printk(KERN_INFO "ssp_clk ref count: %i\n", + ssp_clk.ref & CLK_EN_MASK); + + printk(KERN_INFO "gpmi_clk ref count: %i\n", + gpmi_clk.ref & CLK_EN_MASK); + +} +#endif static void mx23_clock_scan(void) { @@ -1046,16 +1566,19 @@ static void mx23_clock_scan(void) emi_clk.parent = &ref_xtal_clk; if (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SSP) ssp_clk.parent = &ref_xtal_clk; -}; + if (reg & BM_CLKCTRL_CLKSEQ_BYPASS_GPMI) + gpmi_clk.parent = &ref_xtal_clk; + reg = __raw_readl(RTC_BASE_ADDR + HW_RTC_PERSISTENT0); + if (!(reg & BM_RTC_PERSISTENT0_CLOCKSOURCE)) + rtc32k_clk.parent = &ref_xtal_clk; +}; void __init mx23_set_input_clk(unsigned long xtal0, unsigned long xtal1, unsigned long xtal2, unsigned long enet) { - xtal_clk_rate[0] = xtal0; - xtal_clk_rate[1] = xtal1; - xtal_clk_rate[2] = xtal2; + } void __init mx23_clock_init(void) @@ -1067,4 +1590,7 @@ void __init mx23_clock_init(void) clk_enable(&cpu_clk); clk_enable(&emi_clk); + + clk_en_public_h_asm_ctrl(mx23_enable_h_autoslow, + mx23_set_hbus_autoslow_flags); } diff --git a/arch/arm/mach-mx23/device.c b/arch/arm/mach-mx23/device.c index 38ad3f77181f..cda2285ec3bc 100644 --- a/arch/arm/mach-mx23/device.c +++ b/arch/arm/mach-mx23/device.c @@ -28,6 +28,7 @@ #include <linux/mmc/host.h> #include <linux/phy.h> #include <linux/fec.h> +#include <linux/gpmi-nfc.h> #include <asm/mach/map.h> @@ -43,6 +44,7 @@ #include "device.h" #include "mx23_pins.h" +#include "mx23evk.h" #include "mach/mx23.h" #if defined(CONFIG_SERIAL_MXS_DUART) || \ @@ -510,69 +512,97 @@ static void __init mx23_init_dcp(void) } #endif -#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE) -#define MMC0_POWER MXS_PIN_TO_GPIO(PINID_PWM3) -#define MMC0_WP MXS_PIN_TO_GPIO(PINID_PWM4) +#if defined(CONFIG_MTD_NAND_GPMI_NFC) -static int mxs_mmc_get_wp_mmc0(void) +static int gpmi_nfc_platform_init(unsigned int max_chip_count) { - return gpio_get_value(MMC0_WP); + return 0; } -static int mxs_mmc_hw_init_mmc0(void) +static void gpmi_nfc_platform_exit(unsigned int max_chip_count) { - int ret = 0; - - /* Configure write protect GPIO pin */ - ret = gpio_request(MMC0_WP, "mmc0_wp"); - if (ret) { - pr_err("wp\r\n"); - goto out_wp; - } - gpio_set_value(MMC0_WP, 0); - gpio_direction_input(MMC0_WP); - - /* Configure POWER pin as gpio to drive power to MMC slot */ - ret = gpio_request(MMC0_POWER, "mmc0_power"); - if (ret) { - pr_err("power\r\n"); - goto out_power; - } - gpio_direction_output(MMC0_POWER, 0); - mdelay(100); +} - return 0; +static const char *gpmi_nfc_partition_source_types[] = { "cmdlinepart", 0 }; + +static struct gpmi_nfc_platform_data gpmi_nfc_platform_data = { + .nfc_version = 0, + .boot_rom_version = 0, + .clock_name = "gpmi", + .platform_init = gpmi_nfc_platform_init, + .platform_exit = gpmi_nfc_platform_exit, + .min_prop_delay_in_ns = 5, + .max_prop_delay_in_ns = 9, + .max_chip_count = 2, + .boot_area_size_in_bytes = 20 * SZ_1M, + .partition_source_types = gpmi_nfc_partition_source_types, + .partitions = 0, + .partition_count = 0, +}; -out_power: - gpio_free(MMC0_WP); -out_wp: - return ret; -} +static struct resource gpmi_nfc_resources[] = { + { + .name = GPMI_NFC_GPMI_REGS_ADDR_RES_NAME, + .flags = IORESOURCE_MEM, + .start = GPMI_PHYS_ADDR, + .end = GPMI_PHYS_ADDR + SZ_8K - 1, + }, + { + .name = GPMI_NFC_GPMI_INTERRUPT_RES_NAME, + .flags = IORESOURCE_IRQ, + .start = IRQ_GPMI_ATTENTION, + .end = IRQ_GPMI_ATTENTION, + }, + { + .name = GPMI_NFC_BCH_REGS_ADDR_RES_NAME, + .flags = IORESOURCE_MEM, + .start = BCH_PHYS_ADDR, + .end = BCH_PHYS_ADDR + SZ_8K - 1, + }, + { + .name = GPMI_NFC_BCH_INTERRUPT_RES_NAME, + .flags = IORESOURCE_IRQ, + .start = IRQ_BCH, + .end = IRQ_BCH, + }, + { + .name = GPMI_NFC_DMA_CHANNELS_RES_NAME, + .flags = IORESOURCE_DMA, + .start = MXS_DMA_CHANNEL_AHB_APBH_GPMI0, + .end = MXS_DMA_CHANNEL_AHB_APBH_GPMI3, + }, + { + .name = GPMI_NFC_DMA_INTERRUPT_RES_NAME, + .flags = IORESOURCE_IRQ, + .start = IRQ_GPMI_DMA, + .end = IRQ_GPMI_DMA, + }, +}; -static void mxs_mmc_hw_release_mmc0(void) +static void __init mx23_init_gpmi_nfc(void) { - gpio_free(MMC0_POWER); - gpio_free(MMC0_WP); + struct platform_device *pdev; + pdev = mxs_get_device(GPMI_NFC_DRIVER_NAME, 0); + if (pdev == NULL || IS_ERR(pdev)) + return; + pdev->dev.platform_data = &gpmi_nfc_platform_data; + pdev->resource = gpmi_nfc_resources; + pdev->num_resources = ARRAY_SIZE(gpmi_nfc_resources); + mxs_add_device(pdev, 1); } - -static void mxs_mmc_cmd_pullup_mmc0(int enable) +#else +static void mx23_init_gpmi_nfc(void) { - mxs_set_pullup(PINID_SSP1_CMD, enable, "mmc0_cmd"); } +#endif +#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE) static unsigned long mxs_mmc_setclock_mmc0(unsigned long hz) { - struct clk *ssp = clk_get(NULL, "ssp.0"), *parent; - - if (hz > 1000000) - parent = clk_get(NULL, "ref_io.0"); - else - parent = clk_get(NULL, "xtal.0"); + struct clk *ssp = clk_get(NULL, "ssp.0"); - clk_set_parent(ssp, parent); clk_set_rate(ssp, 2 * hz); - clk_put(parent); clk_put(ssp); return hz; @@ -583,7 +613,11 @@ static struct mxs_mmc_platform_data mx23_mmc0_data = { .hw_release = mxs_mmc_hw_release_mmc0, .get_wp = mxs_mmc_get_wp_mmc0, .cmd_pullup = mxs_mmc_cmd_pullup_mmc0, - .setclock = mxs_mmc_setclock_mmc0, + /* + Don't change ssp clock because ssp1 and ssp2 share one ssp clock source + ssp module have own divider. + .setclock = mxs_mmc_setclock_mmc0, + */ .caps = MMC_CAP_4_BIT_DATA, .min_clk = 400000, .max_clk = 48000000, @@ -636,6 +670,68 @@ static void mx23_init_mmc(void) } #endif +#if defined(CONFIG_SPI_MXS) || defined(CONFIG_SPI_MXS_MODULE) +static struct resource ssp1_resources[] = { + { + .start = SSP1_PHYS_ADDR, + .end = SSP1_PHYS_ADDR + 0x1FFF, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_SSP1_DMA, + .end = IRQ_SSP1_DMA, + .flags = IORESOURCE_IRQ, + }, { + .start = IRQ_SSP_ERROR, + .end = IRQ_SSP_ERROR, + .flags = IORESOURCE_IRQ, + }, { + .start = MXS_DMA_CHANNEL_AHB_APBH_SSP1, + .end = MXS_DMA_CHANNEL_AHB_APBH_SSP1, + .flags = IORESOURCE_DMA, + }, +}; + +static void __init mx23_init_spi1(void) +{ + struct platform_device *pdev; + + pdev = mxs_get_device("mxs-spi", 0); + if (pdev == NULL || IS_ERR(pdev)) + return; + pdev->resource = ssp1_resources; + pdev->num_resources = ARRAY_SIZE(ssp1_resources); + + mxs_add_device(pdev, 3); +} +#else +static void mx23_init_spi1(void) +{ + ; +} +#endif + +#define CMDLINE_DEVICE_CHOOSE(name, dev1, dev2) \ + static char *cmdline_device_##name; \ + static int cmdline_device_##name##_setup(char *dev) \ + { \ + cmdline_device_##name = dev + 1; \ + return 0; \ + } \ + __setup(#name, cmdline_device_##name##_setup); \ + void mx23_init_##name(void) \ + { \ + if (!cmdline_device_##name || \ + !strcmp(cmdline_device_##name, #dev1)) \ + mx23_init_##dev1(); \ + else if (!strcmp(cmdline_device_##name, #dev2)) \ + mx23_init_##dev2(); \ + else \ + pr_err("Unknown %s assignment '%s'.\n", \ + #name, cmdline_device_##name); \ + } + +CMDLINE_DEVICE_CHOOSE(ssp1, mmc, spi1) + #if defined(CONFIG_BATTERY_MXS) /* battery info data */ static ddi_bc_Cfg_t battery_data = { @@ -729,7 +825,7 @@ void __init mx23_init_spdif(void) mxs_add_device(pdev, 3); } #else -static inline mx23_init_spdif(void) +static inline void mx23_init_spdif(void) { } #endif @@ -835,6 +931,49 @@ static void mx23_init_persistent() } #endif +#if defined(CONFIG_FSL_OTP) +/* Building up eight registers's names of a bank */ +#define BANK(a, b, c, d, e, f, g, h) \ + {\ + ("HW_OCOTP_"#a), ("HW_OCOTP_"#b), ("HW_OCOTP_"#c), ("HW_OCOTP_"#d), \ + ("HW_OCOTP_"#e), ("HW_OCOTP_"#f), ("HW_OCOTP_"#g), ("HW_OCOTP_"#h) \ + } + +#define BANKS (4) +#define BANK_ITEMS (8) +static const char *bank_reg_desc[BANKS][BANK_ITEMS] = { + BANK(CUST0, CUST1, CUST2, CUST3, CRYPTO0, CRYPTO1, CRYPTO2, CRYPTO3), + BANK(HWCAP0, HWCAP1, HWCAP2, HWCAP3, HWCAP4, HWCAP5, SWCAP, CUSTCAP), + BANK(LOCK, OPS0, OPS1, OPS2, OPS3, UN0, UN1, UN2), + BANK(ROM0, ROM1, ROM2, ROM3, ROM4, ROM5, ROM6, ROM7), +}; + +static struct fsl_otp_data otp_data = { + .fuse_name = (char **)bank_reg_desc, + .regulator_name = "vddio", + .fuse_num = BANKS * BANK_ITEMS, +}; +#undef BANK +#undef BANKS +#undef BANK_ITEMS + +static void mx23_init_otp(void) +{ + struct platform_device *pdev; + pdev = mxs_get_device("ocotp", 0); + if (pdev == NULL || IS_ERR(pdev)) + return; + pdev->dev.platform_data = &otp_data; + pdev->resource = NULL; + pdev->num_resources = 0; + mxs_add_device(pdev, 3); +} +#else +static void mx23_init_otp(void) +{ +} +#endif + int __init mx23_device_init(void) { mx23_init_dma(); @@ -848,12 +987,14 @@ int __init mx23_device_init(void) mx23_init_ts(); mx23_init_rtc(); mx23_init_dcp(); - mx23_init_mmc(); + mx23_init_ssp1(); + mx23_init_gpmi_nfc(); mx23_init_spdif(); mx23_init_lcdif(); mx23_init_pxp(); mx23_init_battery(); mx23_init_persistent(); + mx23_init_otp(); return 0; } diff --git a/arch/arm/mach-mx23/emi.S b/arch/arm/mach-mx23/emi.S index 5799ca23be8f..41e1ea6abe71 100644 --- a/arch/arm/mach-mx23/emi.S +++ b/arch/arm/mach-mx23/emi.S @@ -38,6 +38,8 @@ #define SCALING_DATA_NEW_FREQ_OFFSET 12 #define REGS_CLKCTRL_BASE MX23_SOC_IO_ADDRESS(CLKCTRL_PHYS_ADDR) #define HW_CLKCTRL_EMI_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI) +#define HW_CLKCTRL_FRAC_SET_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC_SET) +#define HW_CLKCTRL_FRAC_CLR_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC_CLR) #define HW_CLKCTRL_FRAC_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC) #define HW_EMI_CTRL_ADDR MX23_SOC_IO_ADDRESS(REGS_EMI_PHYS + HW_EMI_CTRL) #define HW_DRAM_CTL04_ADDR MX23_SOC_IO_ADDRESS(REGS_DRAM_PHYS + HW_DRAM_CTL04) @@ -72,53 +74,82 @@ ENTRY(mxs_ram_freq_scale) beq 1b nop + + @ RAM to clk from xtal + mov r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000) + mov r1, #(1<<6) + str r1, [r0, #4] + mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) +101: ldr r1, [r0] + tst r1, #BM_CLKCTRL_EMI_BUSY_REF_XTAL + bne 101b + + @ Gate ref_emi + mov r0, #(HW_CLKCTRL_FRAC_SET_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_FRAC_SET_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_FRAC_SET_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_FRAC_SET_ADDR & 0xFF000000) + + mov r1, #(BM_CLKCTRL_FRAC_CLKGATEEMI) + str r1, [r0] + + @ prepare for change cmp r5, #24 bgt 2f bl mx23_ram_24M_set_timings - b 100f + b 44f 2: cmp r5, #48 bgt 3f bl mx23_ram_48M_set_timings - b 100f + b 55f 3: cmp r5, #60 bgt 4f bl mx23_ram_60M_set_timings - b 100f + b 55f 4: cmp r5, #80 bgt 5f bl mx23_ram_80M_set_timings - b 100f + b 55f 5: cmp r5, #96 bgt 6f bl mx23_ram_96M_set_timings - b 100f + b 55f 6: cmp r5, #120 bgt 7f bl mx23_ram_120M_set_timings - b 100f + b 55f 7: cmp r5, #133 bgt 8f bl mx23_ram_133M_set_timings - b 100f + b 55f 8: bl mx23_ram_150M_set_timings -100: - @ RAM to clk from xtal - mov r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF) - orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00) - orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000) - orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000) - mov r1, #(1<<6) - str r1, [r0, #4] - mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) - orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) - orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) - orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) -101: ldr r1, [r0] - tst r1, #BM_CLKCTRL_EMI_BUSY_REF_XTAL - bne 101b +44: + + bl __mx23_emi_set_values_xtal + + @ resttore normal DRAM mode + ldr r0, __mx23_dram_ctl00 + ldr r1, [r0, #0x20] + bic r1, r1, #(1 << 8) + str r1, [r0, #0x20] + + @ wait for it to actually happen + ldr r0, __mx23_dram_emi00 +99: ldr r1, [r0, #0x10] + tst r1, #(1 << 1) + bne 99b + b 110f + +55: @When are using the DLL, reset the DRAM controller and DLL @start point logic (via DLL_SHIFT_RESET and DLL_RESET). @After changing clock dividers and loading @@ -136,14 +167,15 @@ ENTRY(mxs_ram_freq_scale) orr r1, r1, #BM_EMI_CTRL_DLL_RESET str r1, [r0] @write back values to HW_EMI_CTRL register. - bl __mx23_emi_set_values + bl __mx23_emi_set_values2 @ EMI back to PLL mov r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF) orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00) orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000) orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000) - mov r1, #(1<<6) + mov r1, #(BM_CLKCTRL_CLKSEQ_BYPASS_EMI) + @clear bypass bit str r1, [r0, #8] @ Wait for BUSY_REF_EMI, to assure new clock dividers @@ -179,16 +211,6 @@ ENTRY(mxs_ram_freq_scale) bic r1, #BM_EMI_CTRL_DLL_RESET str r1, [r0] -@Wait for BUSY_REF_EMI, to assure new clock dividers are done transferring. -@(\todo is that necessary. we already did this above. - mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) - orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) - orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) - orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) -66: ldr r1, [r0] - tst r1, #BM_CLKCTRL_EMI_BUSY_REF_EMI - bne 66b - @ Wait for DLL locking. @ while(HW_DRAM_CTL04.B.DLLLOCKREG==0); @@ -200,7 +222,7 @@ ENTRY(mxs_ram_freq_scale) tst r1, #BM_DRAM_CTL04_DLLLOCKREG beq 77b - +88: @ resttore normal DRAM mode ldr r0, __mx23_dram_ctl00 ldr r1, [r0, #0x20] @@ -213,6 +235,7 @@ ENTRY(mxs_ram_freq_scale) tst r1, #(1 << 1) bne 102b +110: @ restore regs and return ldmfd sp!, {r1 - r9, lr} mov pc, lr diff --git a/arch/arm/mach-mx23/emi.inc b/arch/arm/mach-mx23/emi.inc index 194181f9f753..290d35ed2729 100644 --- a/arch/arm/mach-mx23/emi.inc +++ b/arch/arm/mach-mx23/emi.inc @@ -20,15 +20,38 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -__mx23_emi_set_values: + +/* + * 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 + */ + + +__mx23_emi_set_values_xtal: stmfd r9!, {r0 - r4, lr} + mov r1, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) -@ DDC_RESNCY is deprecated at mx23 -@ mov r3, #BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE +32: ldr r4, [r1] + tst r4, #BM_CLKCTRL_EMI_BUSY_REF_XTAL + bne 32b + b 4f + +__mx23_emi_set_values2: + + stmfd r9!, {r0 - r4, lr} + + mov r1, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) + orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) + orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) + orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) mov r0, #(HW_CLKCTRL_FRAC_ADDR & 0x000000FF) orr r0, r0, #(HW_CLKCTRL_FRAC_ADDR & 0x0000FF00) @@ -36,17 +59,34 @@ __mx23_emi_set_values: orr r0, r0, #(HW_CLKCTRL_FRAC_ADDR & 0xFF000000) ldr r2, [r0] - and r4, r2, #BM_CLKCTRL_FRAC_EMIFRAC - lsr r4, r4, #8 - /* new pll div > cur pll div? */ - cmp r4, r8 - bgt 1f + @clear EMIFRAC bits and store result in r4 bic r4, r2, #BM_CLKCTRL_FRAC_EMIFRAC - orr r4, r4, r8, lsl #8 - str r4, [r0] - nop - nop - nop + + orr r4, r4, r8, lsl #BP_CLKCTRL_FRAC_EMIFRAC + str r4, [r0] + + @ ungate ref_emi + mov r0, #(HW_CLKCTRL_FRAC_CLR_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_FRAC_CLR_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_FRAC_CLR_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_FRAC_CLR_ADDR & 0xFF000000) + + mov r2, #(BM_CLKCTRL_FRAC_CLKGATEEMI) + str r2, [r0] + + + @ set the integer divider + ldr r2, [r1] + bic r2, r2, #BM_CLKCTRL_EMI_DIV_EMI + orr r2, r2, r7, lsl #BP_CLKCTRL_EMI_DIV_EMI + + str r2, [r1] + + @ wait for clock to stabilize +50: ldr r2, [r1] + tst r2, #BM_CLKCTRL_EMI_BUSY_REF_EMI + bne 50b + b 4f @ Change integer/fractional dividers. @@ -103,8 +143,6 @@ __mx23_emi_set_values: 31: ldr r4, [r1] tst r4, #BM_CLKCTRL_EMI_BUSY_REF_EMI bne 31b - tst r4, #BM_CLKCTRL_EMI_BUSY_REF_XTAL - bne 31b 4: ldmfd r9!, {r0 - r4, lr} mov pc, lr diff --git a/arch/arm/mach-mx23/include/mach/lcdif.h b/arch/arm/mach-mx23/include/mach/lcdif.h index f0ee0d5e5c1a..f12802087320 100644 --- a/arch/arm/mach-mx23/include/mach/lcdif.h +++ b/arch/arm/mach-mx23/include/mach/lcdif.h @@ -201,10 +201,10 @@ static inline void setup_dotclk_panel(u16 v_pulse_width, BM_LCDIF_CTRL_INPUT_DATA_SWIZZLE | BM_LCDIF_CTRL_LCD_DATABUS_WIDTH, REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); - __raw_writel(BF_LCDIF_CTRL_WORD_LENGTH(3) | /* 24 bit */ - BM_LCDIF_CTRL_DATA_SELECT | /* data mode */ - BF_LCDIF_CTRL_INPUT_DATA_SWIZZLE(0) | /* no swap */ - BF_LCDIF_CTRL_LCD_DATABUS_WIDTH(3), /* 24 bit */ + __raw_writel(BF_LCDIF_CTRL_WORD_LENGTH(3) |/* 24 bit */ + BM_LCDIF_CTRL_DATA_SELECT |/* data mode */ + BF_LCDIF_CTRL_INPUT_DATA_SWIZZLE(0) |/* no swap */ + BF_LCDIF_CTRL_LCD_DATABUS_WIDTH(3),/* 24 bit */ REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_VDCTRL0); @@ -275,4 +275,167 @@ static inline void release_dotclk_panel(void) __raw_writel(0, REGS_LCDIF_BASE + HW_LCDIF_VDCTRL3); } +static inline void setup_dvi_panel(u16 h_active, u16 v_active, + u16 h_blanking, u16 v_lines, + u16 v1_blank_start, u16 v1_blank_end, + u16 v2_blank_start, u16 v2_blank_end, + u16 f1_start, u16 f1_end, + u16 f2_start, u16 f2_end) +{ + u32 val; + /* 32bit packed format (RGB) */ + __raw_writel(BM_LCDIF_CTRL1_BYTE_PACKING_FORMAT, + REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR); + __raw_writel(BF_LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x7) | + BM_LCDIF_CTRL1_RECOVER_ON_UNDERFLOW, + REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET); + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_TRANSFER_COUNT); + val &= ~(BM_LCDIF_TRANSFER_COUNT_V_COUNT | + BM_LCDIF_TRANSFER_COUNT_H_COUNT); + val |= BF_LCDIF_TRANSFER_COUNT_H_COUNT(h_active) | + BF_LCDIF_TRANSFER_COUNT_V_COUNT(v_active); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_TRANSFER_COUNT); + + /* set lcdif to DVI mode */ + __raw_writel(BM_LCDIF_CTRL_DVI_MODE, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); + __raw_writel(BM_LCDIF_CTRL_VSYNC_MODE, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); + __raw_writel(BM_LCDIF_CTRL_DOTCLK_MODE, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); + + __raw_writel(BM_LCDIF_CTRL_BYPASS_COUNT, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); + /* convert input RGB -> YCbCr */ + __raw_writel(BM_LCDIF_CTRL_RGB_TO_YCBCR422_CSC, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); + /* interlace odd and even fields */ + __raw_writel(BM_LCDIF_CTRL1_INTERLACE_FIELDS, + REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET); + + __raw_writel(BM_LCDIF_CTRL_WORD_LENGTH | + BM_LCDIF_CTRL_INPUT_DATA_SWIZZLE | + BM_LCDIF_CTRL_LCD_DATABUS_WIDTH, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); + __raw_writel(BF_LCDIF_CTRL_WORD_LENGTH(3) | /* 24 bit */ + BM_LCDIF_CTRL_DATA_SELECT | /* data mode */ + BF_LCDIF_CTRL_INPUT_DATA_SWIZZLE(0) | /* no swap */ + BF_LCDIF_CTRL_LCD_DATABUS_WIDTH(1), /* 8 bit */ + REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); + + /* LCDIF_DVI */ + /* set frame size */ + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL0); + val &= ~(BM_LCDIF_DVICTRL0_H_ACTIVE_CNT | + BM_LCDIF_DVICTRL0_H_BLANKING_CNT | + BM_LCDIF_DVICTRL0_V_LINES_CNT); + val |= BF_LCDIF_DVICTRL0_H_ACTIVE_CNT(1440) | + BF_LCDIF_DVICTRL0_H_BLANKING_CNT(h_blanking) | + BF_LCDIF_DVICTRL0_V_LINES_CNT(v_lines); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL0); + + /* set start/end of field-1 and start of field-2 */ + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL1); + val &= ~(BM_LCDIF_DVICTRL1_F1_START_LINE | + BM_LCDIF_DVICTRL1_F1_END_LINE | + BM_LCDIF_DVICTRL1_F2_START_LINE); + val |= BF_LCDIF_DVICTRL1_F1_START_LINE(f1_start) | + BF_LCDIF_DVICTRL1_F1_END_LINE(f1_end) | + BF_LCDIF_DVICTRL1_F2_START_LINE(f2_start); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL1); + + /* set first vertical blanking interval and end of filed-2 */ + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL2); + val &= ~(BM_LCDIF_DVICTRL2_F2_END_LINE | + BM_LCDIF_DVICTRL2_V1_BLANK_START_LINE | + BM_LCDIF_DVICTRL2_V1_BLANK_END_LINE); + val |= BF_LCDIF_DVICTRL2_F2_END_LINE(f2_end) | + BF_LCDIF_DVICTRL2_V1_BLANK_START_LINE(v1_blank_start) | + BF_LCDIF_DVICTRL2_V1_BLANK_END_LINE(v1_blank_end); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL2); + + /* set second vertical blanking interval */ + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL3); + val &= ~(BM_LCDIF_DVICTRL3_V2_BLANK_START_LINE | + BM_LCDIF_DVICTRL3_V2_BLANK_END_LINE); + val |= BF_LCDIF_DVICTRL3_V2_BLANK_START_LINE(v2_blank_start) | + BF_LCDIF_DVICTRL3_V2_BLANK_END_LINE(v2_blank_end); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL3); + + /* fill the rest area black color if the input frame + * is not 720 pixels/line + */ + if (h_active != 720) { + /* the input frame can't be less then (720-256) pixels/line */ + if (720 - h_active > 0xff) + h_active = 720 - 0xff; + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL4); + val &= ~(BM_LCDIF_DVICTRL4_H_FILL_CNT | + BM_LCDIF_DVICTRL4_Y_FILL_VALUE | + BM_LCDIF_DVICTRL4_CB_FILL_VALUE | + BM_LCDIF_DVICTRL4_CR_FILL_VALUE); + val |= BF_LCDIF_DVICTRL4_H_FILL_CNT(720 - h_active) | + BF_LCDIF_DVICTRL4_Y_FILL_VALUE(16) | + BF_LCDIF_DVICTRL4_CB_FILL_VALUE(128) | + BF_LCDIF_DVICTRL4_CR_FILL_VALUE(128); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL4); + } + + /* Color Space Conversion RGB->YCbCr */ + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF0); + val &= ~(BM_LCDIF_CSC_COEFF0_C0 | + BM_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER); + val |= BF_LCDIF_CSC_COEFF0_C0(0x41) | + BF_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER(3); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF0); + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF1); + val &= ~(BM_LCDIF_CSC_COEFF1_C1 | BM_LCDIF_CSC_COEFF1_C2); + val |= BF_LCDIF_CSC_COEFF1_C1(0x81) | + BF_LCDIF_CSC_COEFF1_C2(0x19); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF1); + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF2); + val &= ~(BM_LCDIF_CSC_COEFF2_C3 | BM_LCDIF_CSC_COEFF2_C4); + val |= BF_LCDIF_CSC_COEFF2_C3(0x3DB) | + BF_LCDIF_CSC_COEFF2_C4(0x3B6); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF2); + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF3); + val &= ~(BM_LCDIF_CSC_COEFF3_C5 | BM_LCDIF_CSC_COEFF3_C6); + val |= BF_LCDIF_CSC_COEFF3_C5(0x70) | + BF_LCDIF_CSC_COEFF3_C6(0x70); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF3); + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF4); + val &= ~(BM_LCDIF_CSC_COEFF4_C7 | BM_LCDIF_CSC_COEFF4_C8); + val |= BF_LCDIF_CSC_COEFF4_C7(0x3A2) | BF_LCDIF_CSC_COEFF4_C8(0x3EE); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF4); + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_OFFSET); + val &= ~(BM_LCDIF_CSC_OFFSET_CBCR_OFFSET + | BM_LCDIF_CSC_OFFSET_Y_OFFSET); + val |= BF_LCDIF_CSC_OFFSET_CBCR_OFFSET(0x80) | + BF_LCDIF_CSC_OFFSET_Y_OFFSET(0x10); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_OFFSET); + + val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_LIMIT); + val &= ~(BM_LCDIF_CSC_LIMIT_CBCR_MIN | + BM_LCDIF_CSC_LIMIT_CBCR_MAX | + BM_LCDIF_CSC_LIMIT_Y_MIN | + BM_LCDIF_CSC_LIMIT_Y_MAX); + val |= BF_LCDIF_CSC_LIMIT_CBCR_MIN(16) | + BF_LCDIF_CSC_LIMIT_CBCR_MAX(240) | + BF_LCDIF_CSC_LIMIT_Y_MIN(16) | + BF_LCDIF_CSC_LIMIT_Y_MAX(235); + __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_LIMIT); +} + +static inline void release_dvi_panel(void) +{ + __raw_writel(BM_LCDIF_CTRL_DVI_MODE, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); +} #endif /* _ARCH_ARM_LCDIF_H */ diff --git a/arch/arm/mach-mx23/include/mach/mx23.h b/arch/arm/mach-mx23/include/mach/mx23.h index 09269524a4f0..6e1d2aa7106e 100644 --- a/arch/arm/mach-mx23/include/mach/mx23.h +++ b/arch/arm/mach-mx23/include/mach/mx23.h @@ -50,6 +50,7 @@ #define OCOTP_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x02C000) #define AXI_AHB0_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x02E000) #define LCDIF_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x030000) +#define TVENC_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x038000) #define CLKCTRL_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x040000) #define SAIF0_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x042000) #define POWER_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x044000) @@ -72,12 +73,17 @@ #define MX23_SOC_IO_ADDRESS(x) \ ((x) - MX23_SOC_IO_PHYS_BASE + MX23_SOC_IO_VIRT_BASE) +#ifdef __ASSEMBLER__ +#define IO_ADDRESS(x) \ + MX23_SOC_IO_ADDRESS(x) +#else #define IO_ADDRESS(x) \ (void __force __iomem *) \ (((x) >= (unsigned long)MX23_SOC_IO_PHYS_BASE) && \ ((x) < (unsigned long)MX23_SOC_IO_PHYS_BASE + \ MX23_SOC_IO_AREA_SIZE) ? \ MX23_SOC_IO_ADDRESS(x) : 0xDEADBEEF) +#endif #ifdef CONFIG_MXS_EARLY_CONSOLE #define MXS_DEBUG_CONSOLE_PHYS DUART_PHYS_ADDR diff --git a/arch/arm/mach-mx23/mx23_pins.h b/arch/arm/mach-mx23/mx23_pins.h index 4659315e29f6..9811bfdd0cad 100644 --- a/arch/arm/mach-mx23/mx23_pins.h +++ b/arch/arm/mach-mx23/mx23_pins.h @@ -47,7 +47,7 @@ #define PINID_GPMI_D15 MXS_PIN_ENCODE(0, 15) #define PINID_GPMI_CLE MXS_PIN_ENCODE(0, 16) #define PINID_GPMI_ALE MXS_PIN_ENCODE(0, 17) -#define PINID_GMPI_CE2N MXS_PIN_ENCODE(0, 18) +#define PINID_GPMI_CE2N MXS_PIN_ENCODE(0, 18) #define PINID_GPMI_RDY0 MXS_PIN_ENCODE(0, 19) #define PINID_GPMI_RDY1 MXS_PIN_ENCODE(0, 20) #define PINID_GPMI_RDY2 MXS_PIN_ENCODE(0, 21) diff --git a/arch/arm/mach-mx23/mx23evk.c b/arch/arm/mach-mx23/mx23evk.c index 53f958779c1c..6ce1583e28eb 100644 --- a/arch/arm/mach-mx23/mx23evk.c +++ b/arch/arm/mach-mx23/mx23evk.c @@ -22,6 +22,7 @@ #include <linux/clk.h> #include <linux/platform_device.h> #include <linux/i2c.h> +#include <linux/spi/spi.h> #include <asm/setup.h> #include <asm/mach-types.h> @@ -30,6 +31,7 @@ #include <mach/hardware.h> #include <mach/device.h> #include <mach/pinctrl.h> +#include <mach/regs-ocotp.h> #include "device.h" #include "mx23evk.h" @@ -58,6 +60,28 @@ static void i2c_device_init(void) i2c_register_board_info(0, &mma7450_i2c_device, 1); } +static struct mxs_spi_platform_data enc_data = { + .hw_pin_init = mxs_spi_enc_pin_init, + .hw_pin_release = mxs_spi_enc_pin_release, +}; +static struct spi_board_info spi_board_info[] __initdata = { +#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE) + { + .modalias = "enc28j60", + .max_speed_hz = 6 * 1000 * 1000, + .bus_num = 1, + .chip_select = 0, + .platform_data = &enc_data, + }, +#endif +}; + +static void spi_device_init(void) +{ + spi_board_info[0].irq = gpio_to_irq(MXS_PIN_TO_GPIO(PINID_SSP1_DATA1)); + spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); +} + static void __init fixup_board(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) { @@ -80,11 +104,23 @@ static void __init mx23evk_init_adc(void) } #endif +#define REGS_OCOTP_BASE IO_ADDRESS(OCOTP_PHYS_ADDR) +int get_evk_board_version() +{ + int boardid; + boardid = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CUSTCAP); + boardid &= 0x30000000; + boardid = boardid >> 28; + + return boardid; +} +EXPORT_SYMBOL_GPL(get_evk_board_version); static void __init mx23evk_device_init(void) { /* Add mx23evk special code */ i2c_device_init(); + spi_device_init(); mx23evk_init_adc(); } @@ -94,7 +130,12 @@ static void __init mx23evk_init_machine(void) mx23_pinctrl_init(); /* Init iram allocate */ +#ifdef CONFIG_VECTORS_PHY_ADDR + /* reserve the first page for irq vectors table*/ + iram_init(MX23_OCRAM_PHBASE + PAGE_SIZE, MX23_OCRAM_SIZE - PAGE_SIZE); +#else iram_init(MX23_OCRAM_PHBASE, MX23_OCRAM_SIZE); +#endif mx23_gpio_init(); mx23evk_pins_init(); diff --git a/arch/arm/mach-mx23/mx23evk.h b/arch/arm/mach-mx23/mx23evk.h index afe7bcf4ffe1..ea2ab4def477 100644 --- a/arch/arm/mach-mx23/mx23evk.h +++ b/arch/arm/mach-mx23/mx23evk.h @@ -22,5 +22,11 @@ extern void __init mx23evk_pins_init(void); extern void mx23evk_mma7450_pin_init(void); extern int mx23evk_mma7450_pin_release(void); +extern int mxs_spi_enc_pin_init(void); +extern int mxs_spi_enc_pin_release(void); +extern int mxs_mmc_get_wp_mmc0(void); +extern int mxs_mmc_hw_init_mmc0(void); +extern void mxs_mmc_hw_release_mmc0(void); +extern void mxs_mmc_cmd_pullup_mmc0(int enable); #endif /* __ASM_ARM_MACH_MX23EVK_H */ diff --git a/arch/arm/mach-mx23/mx23evk_pins.c b/arch/arm/mach-mx23/mx23evk_pins.c index 5e60a2b1e387..cdf86cfbea63 100644 --- a/arch/arm/mach-mx23/mx23evk_pins.c +++ b/arch/arm/mach-mx23/mx23evk_pins.c @@ -21,6 +21,7 @@ #include <linux/platform_device.h> #include <linux/irq.h> #include <linux/gpio.h> +#include <linux/delay.h> #include <mach/pinctrl.h> @@ -60,6 +61,28 @@ static struct pin_desc mx23evk_fixed_pins[] = { }, #endif +#ifdef CONFIG_MXS_AUART2_DEVICE_ENABLE + { + .name = "AUART2.RX", + .id = PINID_GPMI_D14, + .fun = PIN_FUN2, + }, + { + .name = "AUART2.TX", + .id = PINID_GPMI_D15, + .fun = PIN_FUN2, + }, + { + .name = "AUART2.CTS", + .id = PINID_ROTARYB, + .fun = PIN_FUN2, + }, + { + .name = "AUART2.RTS", + .id = PINID_ROTARYA, + .fun = PIN_FUN2, + }, +#endif #if defined(CONFIG_I2C_MXS) || \ defined(CONFIG_I2C_MXS_MODULE) { @@ -321,79 +344,6 @@ static struct pin_desc mx23evk_fixed_pins[] = { .drive = 1, }, #endif -#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE) - /* Configurations of SSP0 SD/MMC port pins */ - { - .name = "SSP1_DATA0", - .id = PINID_SSP1_DATA0, - .fun = PIN_FUN1, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, - }, - { - .name = "SSP1_DATA1", - .id = PINID_SSP1_DATA1, - .fun = PIN_FUN1, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, - }, - { - .name = "SSP1_DATA2", - .id = PINID_SSP1_DATA2, - .fun = PIN_FUN1, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, - }, - { - .name = "SSP1_DATA3", - .id = PINID_SSP1_DATA3, - .fun = PIN_FUN1, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, - }, - { - .name = "SSP1_CMD", - .id = PINID_SSP1_CMD, - .fun = PIN_FUN1, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, - }, - { - .name = "SSP1_DETECT", - .id = PINID_SSP1_DETECT, - .fun = PIN_FUN1, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 0, - .drive = 1, - .pull = 0, - }, - { - .name = "SSP1_SCK", - .id = PINID_SSP1_SCK, - .fun = PIN_FUN1, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 0, - .drive = 1, - .pull = 0, - }, -#endif #if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE) { @@ -510,8 +460,323 @@ static struct pin_desc mx23evk_fixed_pins[] = { .pull = 1, }, #endif + +#if defined(CONFIG_MTD_NAND_GPMI_NFC) || \ + defined(CONFIG_MTD_NAND_GPMI_NFC_MODULE) + { + .name = "GPMI D0", + .id = PINID_GPMI_D00, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI D1", + .id = PINID_GPMI_D01, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI D2", + .id = PINID_GPMI_D02, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI D3", + .id = PINID_GPMI_D03, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI D4", + .id = PINID_GPMI_D04, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI D5", + .id = PINID_GPMI_D05, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI D6", + .id = PINID_GPMI_D06, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI D7", + .id = PINID_GPMI_D07, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI CLE", + .id = PINID_GPMI_CLE, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI ALE", + .id = PINID_GPMI_ALE, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI WPN-", + .id = PINID_GPMI_WPN, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI WR-", + .id = PINID_GPMI_WRN, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI RD-", + .id = PINID_GPMI_RDN, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI RDY0", + .id = PINID_GPMI_RDY0, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI RDY1", + .id = PINID_GPMI_RDY1, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI CE0-", + .id = PINID_GPMI_CE0N, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, + { + .name = "GPMI CE1-", + .id = PINID_GPMI_CE1N, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = !0 + }, +#endif + }; +#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE) +static struct pin_desc mx23evk_mmc_pins[] = { + /* Configurations of SSP0 SD/MMC port pins */ + { + .name = "SSP1_DATA0", + .id = PINID_SSP1_DATA0, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SSP1_DATA1", + .id = PINID_SSP1_DATA1, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SSP1_DATA2", + .id = PINID_SSP1_DATA2, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SSP1_DATA3", + .id = PINID_SSP1_DATA3, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SSP1_CMD", + .id = PINID_SSP1_CMD, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SSP1_DETECT", + .id = PINID_SSP1_DETECT, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = 1, + .pull = 0, + }, + { + .name = "SSP1_SCK", + .id = PINID_SSP1_SCK, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 0, + .drive = 1, + .pull = 0, + }, +}; +#endif + +#if defined(CONFIG_SPI_MXS) || defined(CONFIG_SPI_MXS_MODULE) +static struct pin_desc mx23evk_spi_pins[] = { + { + .name = "SSP1_DATA0", + .id = PINID_SSP1_DATA0, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .drive = 1, + }, + { + .name = "SSP1_DATA3", + .id = PINID_SSP1_DATA3, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .drive = 1, + }, + { + .name = "SSP1_CMD", + .id = PINID_SSP1_CMD, + .fun = PIN_FUN1, + .strength = PAD_4MA, + .voltage = PAD_3_3V, + .drive = 1, + }, + { + .name = "SSP1_SCK", + .id = PINID_SSP1_SCK, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .drive = 1, + }, +}; +#endif + + +static void mxs_request_pins(struct pin_desc *pins, int nr) +{ + int i; + struct pin_desc *pin; + + /* configure the pins */ + for (i = 0; i < nr; i++) { + pin = &pins[i]; + if (pin->fun == PIN_GPIO) + gpio_request(MXS_PIN_TO_GPIO(pin->id), pin->name); + else + mxs_request_pin(pin->id, pin->fun, pin->name); + if (pin->drive) { + mxs_set_strength(pin->id, pin->strength, pin->name); + mxs_set_voltage(pin->id, pin->voltage, pin->name); + } + if (pin->pull) + mxs_set_pullup(pin->id, pin->pullup, pin->name); + if (pin->fun == PIN_GPIO) { + if (pin->output) + gpio_direction_output(MXS_PIN_TO_GPIO(pin->id), + pin->data); + else + gpio_direction_input(MXS_PIN_TO_GPIO(pin->id)); + } + } +} + +static void mxs_release_pins(struct pin_desc *pins, int nr) +{ + int i; + struct pin_desc *pin; + + /* release the pins */ + for (i = 0; i < nr; i++) { + pin = &pins[i]; + if (pin->fun == PIN_GPIO) + gpio_free(MXS_PIN_TO_GPIO(pin->id)); + else + mxs_release_pin(pin->id, pin->name); + } +} + #if defined(CONFIG_MXC_MMA7450) || defined(CONFIG_MXC_MMA7450_MODULE) int mx23evk_mma7450_pin_init(void) { @@ -537,6 +802,116 @@ int mx23evk_mma7450_pin_release(void) } #endif +#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE) +#define MMC0_POWER MXS_PIN_TO_GPIO(PINID_PWM3) +#define MMC0_WP MXS_PIN_TO_GPIO(PINID_PWM4) + +int mxs_mmc_get_wp_mmc0(void) +{ + return gpio_get_value(MMC0_WP); +} + +int mxs_mmc_hw_init_mmc0(void) +{ + int ret = 0; + + mxs_request_pins(mx23evk_mmc_pins, ARRAY_SIZE(mx23evk_mmc_pins)); + + /* Configure write protect GPIO pin */ + ret = gpio_request(MMC0_WP, "mmc0_wp"); + if (ret) { + pr_err("wp\n"); + goto out_wp; + } + gpio_set_value(MMC0_WP, 0); + gpio_direction_input(MMC0_WP); + + /* Configure POWER pin as gpio to drive power to MMC slot */ + ret = gpio_request(MMC0_POWER, "mmc0_power"); + if (ret) { + pr_err("power\n"); + goto out_power; + } + gpio_direction_output(MMC0_POWER, 0); + mdelay(100); + + return 0; + +out_power: + gpio_free(MMC0_WP); +out_wp: + mxs_release_pins(mx23evk_mmc_pins, ARRAY_SIZE(mx23evk_mmc_pins)); + return ret; +} + +void mxs_mmc_hw_release_mmc0(void) +{ + gpio_free(MMC0_POWER); + gpio_free(MMC0_WP); + + mxs_release_pins(mx23evk_mmc_pins, ARRAY_SIZE(mx23evk_mmc_pins)); +} + +void mxs_mmc_cmd_pullup_mmc0(int enable) +{ + mxs_set_pullup(PINID_SSP1_CMD, enable, "mmc0_cmd"); +} +#else +int mxs_mmc_get_wp_mmc0(void) +{ + return 0; +} +int mxs_mmc_hw_init_mmc0(void) +{ + return 0; +} + +void mxs_mmc_hw_release_mmc0(void) +{ +} + +void mxs_mmc_cmd_pullup_mmc0(int enable) +{ +} +#endif + +#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE) +int mxs_spi_enc_pin_init(void) +{ + unsigned gpio = MXS_PIN_TO_GPIO(PINID_SSP1_DATA1); + + mxs_request_pins(mx23evk_spi_pins, ARRAY_SIZE(mx23evk_spi_pins)); + + gpio_request(gpio, "ENC28J60_INTR"); + gpio_direction_input(gpio); + set_irq_type(gpio_to_irq(gpio), IRQ_TYPE_EDGE_FALLING); + + return 0; +} +int mxs_spi_enc_pin_release(void) +{ + unsigned gpio = MXS_PIN_TO_GPIO(PINID_SSP1_DATA1); + + + gpio_free(gpio); + set_irq_type(gpio_to_irq(gpio), IRQ_TYPE_NONE); + + /* release the pins */ + mxs_release_pins(mx23evk_spi_pins, ARRAY_SIZE(mx23evk_spi_pins)); + + return 0; +} +#else +int mxs_spi_enc_pin_init(void) +{ + return 0; +} +int mxs_spi_enc_pin_release(void) +{ + return 0; +} +#endif + #if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE) int mx23evk_enet_gpio_init(void) { @@ -560,26 +935,5 @@ int mx23evk_enet_gpio_init(void) void __init mx23evk_pins_init(void) { - int i; - struct pin_desc *pin; - for (i = 0; i < ARRAY_SIZE(mx23evk_fixed_pins); i++) { - pin = &mx23evk_fixed_pins[i]; - if (pin->fun == PIN_GPIO) - gpio_request(MXS_PIN_TO_GPIO(pin->id), pin->name); - else - mxs_request_pin(pin->id, pin->fun, pin->name); - if (pin->drive) { - mxs_set_strength(pin->id, pin->strength, pin->name); - mxs_set_voltage(pin->id, pin->voltage, pin->name); - } - if (pin->pull) - mxs_set_pullup(pin->id, pin->pullup, pin->name); - if (pin->fun == PIN_GPIO) { - if (pin->output) - gpio_direction_output(MXS_PIN_TO_GPIO(pin->id), - pin->data); - else - gpio_direction_input(MXS_PIN_TO_GPIO(pin->id)); - } - } + mxs_request_pins(mx23evk_fixed_pins, ARRAY_SIZE(mx23evk_fixed_pins)); } diff --git a/arch/arm/mach-mx23/pm.c b/arch/arm/mach-mx23/pm.c index c44a81f94b5e..0538326f441c 100644 --- a/arch/arm/mach-mx23/pm.c +++ b/arch/arm/mach-mx23/pm.c @@ -280,6 +280,7 @@ static inline void do_standby(void) } local_fiq_disable(); + mxs_nomatch_suspend_timer(); __raw_writel(BM_POWER_CTRL_ENIRQ_PSWITCH, REGS_POWER_BASE + HW_POWER_CTRL_SET); @@ -502,7 +503,6 @@ static suspend_state_t saved_state; static int mx23_pm_begin(suspend_state_t state) { - mxs_nomatch_suspend_timer(); saved_state = state; return 0; } diff --git a/arch/arm/mach-mx23/usb_dr.c b/arch/arm/mach-mx23/usb_dr.c index 13f9a296909c..4c702ffcd07c 100644 --- a/arch/arm/mach-mx23/usb_dr.c +++ b/arch/arm/mach-mx23/usb_dr.c @@ -27,7 +27,7 @@ #include "usb.h" #include "mx23_pins.h" -#define USB_POWER_ENABLE MXS_PIN_TO_GPIO(PINID_GMPI_CE2N) +#define USB_POWER_ENABLE MXS_PIN_TO_GPIO(PINID_GPMI_CE2N) #define USB_ID_PIN MXS_PIN_TO_GPIO(PINID_ROTARYA) static void usb_host_phy_resume(struct fsl_usb2_platform_data *plat) @@ -64,7 +64,7 @@ static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = { }; /* - * resources + * OTG resources */ static struct resource otg_resources[] = { [0] = { @@ -84,6 +84,28 @@ static struct resource otg_resources[] = { }, }; +/* + * UDC resources (same as OTG resource) + */ +static struct resource udc_resources[] = { + [0] = { + .start = (u32)USBCTRL_PHYS_ADDR, + .end = (u32)(USBCTRL_PHYS_ADDR + 0x1ff), + .flags = IORESOURCE_MEM, + }, + + [1] = { + .start = IRQ_USB_CTRL, + .flags = IORESOURCE_IRQ, + }, + + [2] = { + .start = IRQ_USB_WAKEUP, + .flags = IORESOURCE_IRQ, + }, +}; + + static u64 dr_udc_dmamask = ~(u32) 0; static void dr_udc_release(struct device *dev) { @@ -101,8 +123,8 @@ static struct platform_device dr_udc_device = { .dma_mask = &dr_udc_dmamask, .coherent_dma_mask = 0xffffffff, }, - .resource = otg_resources, - .num_resources = ARRAY_SIZE(otg_resources), + .resource = udc_resources, + .num_resources = ARRAY_SIZE(udc_resources), }; static u64 dr_otg_dmamask = ~(u32) 0; @@ -167,5 +189,5 @@ void fsl_phy_set_power(struct fsl_xcvr_ops *this, #ifdef CONFIG_MXS_VBUS_CURRENT_DRAW fs_initcall(usb_dr_init); #else - module_init(usb_dr_init); + subsys_initcall(usb_dr_init); #endif diff --git a/arch/arm/mach-mx25/devices.c b/arch/arm/mach-mx25/devices.c index 093e8e146f20..73ed01ab6b57 100644 --- a/arch/arm/mach-mx25/devices.c +++ b/arch/arm/mach-mx25/devices.c @@ -555,11 +555,58 @@ static inline void mxc_init_flexcan(void) } #endif +#if defined(CONFIG_SND_MXC_SOC_ESAI) || defined(CONFIG_SND_MXC_SOC_ESAI_MODULE) + +static struct mxc_esai_platform_data esai_data = { + .activate_esai_ports = gpio_activate_esai_ports, + .deactivate_esai_ports = gpio_deactivate_esai_ports, +}; + +static struct resource esai_resources[] = { + { + .start = ESAI_BASE_ADDR, + .end = ESAI_BASE_ADDR + 0x100, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_ESAI, + .end = MXC_INT_ESAI, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_esai_device = { + .name = "mxc_esai", + .id = 0, + .num_resources = ARRAY_SIZE(esai_resources), + .resource = esai_resources, + .dev = { + .release = mxc_nop_release, + .platform_data = &esai_data, + }, +}; + +static void mxc_init_esai(void) +{ + platform_device_register(&mxc_esai_device); +} +#else +static void mxc_init_esai(void) +{ + +} +#endif + +static struct mxc_audio_platform_data mxc_surround_audio_data = { + .ext_ram = 1, +}; + static struct platform_device mxc_alsa_surround_device = { .name = "imx-3stack-wm8580", .id = 0, .dev = { .release = mxc_nop_release, + .platform_data = &mxc_surround_audio_data, }, }; @@ -670,7 +717,7 @@ static int __init mxc_init_devices(void) mxc_init_flexcan(); mxc_init_iim(); mxc_init_ssi(); - + mxc_init_esai(); return 0; } diff --git a/arch/arm/mach-mx25/mx25_3stack.c b/arch/arm/mach-mx25/mx25_3stack.c index 557447964d09..c73bcbf6371e 100644 --- a/arch/arm/mach-mx25/mx25_3stack.c +++ b/arch/arm/mach-mx25/mx25_3stack.c @@ -22,6 +22,7 @@ #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/smsc911x.h> +#include <linux/fec.h> #if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE) #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -100,13 +101,17 @@ static struct resource mxc_kpp_resources[] = { .start = MXC_INT_KPP, .end = MXC_INT_KPP, .flags = IORESOURCE_IRQ, - } + }, + [1] = { + .start = KPP_BASE_ADDR, + .end = KPP_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, }; static struct keypad_data keypad_plat_data = { .rowmax = 4, .colmax = 4, - .irq = MXC_INT_KPP, .learning = 0, .delay = 2, .matrix = keymapping, @@ -161,6 +166,21 @@ static struct mtd_partition mxc_nand_partitions[] = { .size = MTDPART_SIZ_FULL}, }; +static struct resource mxc_nand_resources[] = { + { + .flags = IORESOURCE_MEM, + .name = "NFC_AXI_BASE", + .start = NFC_BASE_ADDR, + .end = NFC_BASE_ADDR + SZ_8K - 1, + }, + { + .flags = IORESOURCE_IRQ, + .start = MXC_INT_NANDFC, + .end = MXC_INT_NANDFC, + }, +}; + + static struct flash_platform_data mxc_nand_data = { .parts = mxc_nand_partitions, .nr_parts = ARRAY_SIZE(mxc_nand_partitions), @@ -174,6 +194,8 @@ static struct platform_device mxc_nand_mtd_device = { .release = mxc_nop_release, .platform_data = &mxc_nand_data, }, + .resource = mxc_nand_resources, + .num_resources = ARRAY_SIZE(mxc_nand_resources), }; static void mxc_init_nand_mtd(void) @@ -296,7 +318,7 @@ static struct spi_board_info mxc_spi_board_info[] __initdata = { .max_speed_hz = 18000000, .bus_num = 1, .chip_select = 0, - .mode = SPI_MODE_2, + .mode = SPI_MODE_0, }, { .modalias = "wm8580_spi", @@ -458,9 +480,16 @@ static struct resource mxc_fec_resources[] = { }, }; +static struct fec_platform_data fec_data = { + .phy = PHY_INTERFACE_MODE_RMII, +}; + struct platform_device mxc_fec_device = { .name = "fec", .id = 0, + .dev = { + .platform_data = &fec_data, + }, .num_resources = ARRAY_SIZE(mxc_fec_resources), .resource = mxc_fec_resources, }; diff --git a/arch/arm/mach-mx25/mx25_3stack_gpio.c b/arch/arm/mach-mx25/mx25_3stack_gpio.c index 5f7dd4f63b06..23d9505e7941 100644 --- a/arch/arm/mach-mx25/mx25_3stack_gpio.c +++ b/arch/arm/mach-mx25/mx25_3stack_gpio.c @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -1333,10 +1333,10 @@ void gpio_activate_audio_ports(void) EXPORT_SYMBOL(gpio_activate_audio_ports); /*! - * This function inactivates DAM port 4 for + * This function deactivates DAM port 4 for * audio I/O */ -void gpio_inactive_audio_ports(void) +void gpio_deactive_audio_ports(void) { gpio_request(IOMUX_TO_GPIO(MX25_PIN_EB0), NULL); /*SSI4_STXD*/ gpio_request(IOMUX_TO_GPIO(MX25_PIN_EB1), NULL); /*SSI4_SRXD*/ @@ -1352,7 +1352,7 @@ void gpio_inactive_audio_ports(void) mxc_free_iomux(MX25_PIN_A10, MUX_CONFIG_GPIO); mxc_free_iomux(MX25_PIN_D13, MUX_CONFIG_GPIO); } -EXPORT_SYMBOL(gpio_inactive_audio_ports); +EXPORT_SYMBOL(gpio_deactive_audio_ports); int headphone_det_status(void) { diff --git a/arch/arm/mach-mx25/usb_dr.c b/arch/arm/mach-mx25/usb_dr.c index b185d5cdeff5..b3d024cb06f8 100644 --- a/arch/arm/mach-mx25/usb_dr.c +++ b/arch/arm/mach-mx25/usb_dr.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -39,7 +39,7 @@ static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = { }; /* - * resources + * OTG resources */ static struct resource otg_resources[] = { [0] = { @@ -53,6 +53,22 @@ static struct resource otg_resources[] = { }, }; +/* + * UDC resources (same as OTG resource) + */ +static struct resource udc_resources[] = { + [0] = { + .start = (u32)(USB_OTGREGS_BASE), + .end = (u32)(USB_OTGREGS_BASE + 0x1ff), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_USB_OTG, + .flags = IORESOURCE_IRQ, + }, +}; + + static u64 dr_udc_dmamask = ~(u32) 0; static void dr_udc_release(struct device *dev) { @@ -75,8 +91,8 @@ static struct platform_device __maybe_unused dr_udc_device = { .dma_mask = &dr_udc_dmamask, .coherent_dma_mask = 0xffffffff, }, - .resource = otg_resources, - .num_resources = ARRAY_SIZE(otg_resources), + .resource = udc_resources, + .num_resources = ARRAY_SIZE(udc_resources), }; static struct platform_device __maybe_unused dr_otg_device = { diff --git a/arch/arm/mach-mx28/Kconfig b/arch/arm/mach-mx28/Kconfig index fdca0f6900ca..cbbf45230472 100644 --- a/arch/arm/mach-mx28/Kconfig +++ b/arch/arm/mach-mx28/Kconfig @@ -9,4 +9,14 @@ config MACH_MX28EVK config MXS_TIMER_WITH_MACH bool "Timer with architecture." +config MXS_TIMER_WITH_MACH + bool "System Timer support Compare Match interrupt" + endchoice + +config VECTORS_PHY_ADDR + int "vectors address" + default 0 + help + This config set vectors table is located which physical address + diff --git a/arch/arm/mach-mx28/bus_freq.c b/arch/arm/mach-mx28/bus_freq.c index a997eaa9a01f..ef01a41fc095 100644 --- a/arch/arm/mach-mx28/bus_freq.c +++ b/arch/arm/mach-mx28/bus_freq.c @@ -46,24 +46,19 @@ #define CLKCTRL_BASE_ADDR IO_ADDRESS(CLKCTRL_PHYS_ADDR) #define DIGCTRL_BASE_ADDR IO_ADDRESS(DIGCTL_PHYS_ADDR) -#define BP_CLKCTRL_HBUS_ASM_ENABLE 20 -#define CLKCTRL_PLL_PWD_BIT 17 -#define CLKCTRL_PLL_BYPASS 0x1ff #define BF(value, field) (((value) << BP_##field) & BM_##field) struct profile profiles[] = { - { 454736, 151580, 196360, 0, 1550000, - 1450000, 355000, 3300000, 1750000, 0 }, - { 392727, 130910, 160000, 0, 1475000, - 1375000, 225000, 3300000, 1750000, 0 }, - { 360000, 120000, 130910, 0, 1375000, - 1275000, 200000, 3300000, 1750000, 0 }, - { 261818, 130910, 130910, 0, 1275000, - 1175000, 173000, 3300000, 1750000, 0 }, - { 64000, 64000, 130910, 3, 1050000, - 975000, 150000, 3300000, 1750000, 0 }, + { 454736, 151570, 205710, 0, 1550000, + 1450000, 355000, 3300000, 1750000, 24000, 0 }, + { 360000, 120000, 130910, 0, 1350000, + 1250000, 200000, 3300000, 1750000, 24000, 0 }, + { 261818, 130910, 130910, 0, 1350000, + 1250000, 173000, 3300000, 1750000, 24000, 0 }, + { 64000, 64000, 130910, 3, 1350000, + 1250000, 150000, 3300000, 1750000, 24000, 0 }, { 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 }, + 0, 0, 0, 0, 0, 0 }, }; static struct device *busfreq_dev; @@ -82,58 +77,13 @@ int low_freq_used(void) return 0; } -void hbus_auto_slow_mode_enable(void) +int is_hclk_autoslow_ok(void) { - __raw_writel(BP_CLKCTRL_HBUS_ASM_ENABLE, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_SET); -} -EXPORT_SYMBOL(hbus_auto_slow_mode_enable); - -void hbus_auto_slow_mode_disable(void) -{ - __raw_writel(BP_CLKCTRL_HBUS_ASM_ENABLE, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR); -} -EXPORT_SYMBOL(hbus_auto_slow_mode_disable); - -int cpu_clk_set_pll_on(struct clk *clk, unsigned int freq) -{ - struct cpufreq_freqs freqs; - - freqs.old = clk_get_rate(clk); - freqs.cpu = 0; - freqs.new = freq; - - if (freqs.old == 24000 && freqs.new > 24000) { - /* turn pll on */ - __raw_writel(CLKCTRL_PLL_PWD_BIT, CLKCTRL_BASE_ADDR + - HW_CLKCTRL_PLL0CTRL0_SET); - udelay(10); - } else if (freqs.old > 24000 && freqs.new == 24000) - clkseq_setting = __raw_readl(CLKCTRL_BASE_ADDR + - HW_CLKCTRL_CLKSEQ); - return 0; -} - -int cpu_clk_set_pll_off(struct clk *clk, unsigned int freq) -{ - struct cpufreq_freqs freqs; - - freqs.old = clk_get_rate(clk); - freqs.cpu = 0; - freqs.new = freq; - - if (freqs.old > 24000 && freqs.new == 24000) { - /* turn pll off */ - __raw_writel(CLKCTRL_PLL_PWD_BIT, CLKCTRL_BASE_ADDR + - HW_CLKCTRL_PLL0CTRL0_CLR); - __raw_writel(CLKCTRL_PLL_BYPASS, CLKCTRL_BASE_ADDR + - HW_CLKCTRL_CLKSEQ); - } else if (freqs.old == 24000 && freqs.new > 24000) - __raw_writel(clkseq_setting, CLKCTRL_BASE_ADDR + - HW_CLKCTRL_CLKSEQ); - - return 0; + if ((clk_get_usecount(usb_clk0) == 0) + && (clk_get_usecount(usb_clk1) == 0)) + return 1; + else + return 0; } int timing_ctrl_rams(int ss) diff --git a/arch/arm/mach-mx28/clock.c b/arch/arm/mach-mx28/clock.c index 8e7adea7c09d..ae6f49d4ae41 100644 --- a/arch/arm/mach-mx28/clock.c +++ b/arch/arm/mach-mx28/clock.c @@ -22,6 +22,7 @@ #include <linux/io.h> #include <linux/clk.h> #include <linux/delay.h> +#include <linux/iram_alloc.h> #include <linux/platform_device.h> #include <mach/clock.h> @@ -47,6 +48,41 @@ static unsigned long xtal_clk_rate[3] = { 24000000, 24000000, 32000 }; static unsigned long enet_mii_phy_rate; +static inline int clk_is_busy(struct clk *clk) +{ + return __raw_readl(clk->busy_reg) & (1 << clk->busy_bits); +} + +static bool mx28_enable_h_autoslow(bool enable) +{ + bool currently_enabled; + + if (__raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_HBUS) & + BM_CLKCTRL_HBUS_ASM_ENABLE) + currently_enabled = true; + else + currently_enabled = false; + + if (enable) + __raw_writel(BM_CLKCTRL_HBUS_ASM_ENABLE, + CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_SET); + else + __raw_writel(BM_CLKCTRL_HBUS_ASM_ENABLE, + CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR); + return currently_enabled; +} + + +static void mx28_set_hbus_autoslow_flags(u16 mask) +{ + u32 reg; + + reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); + reg &= 0xFFFF; + reg |= mask << 16; + __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); +} + static int mx28_raw_enable(struct clk *clk) { unsigned int reg; @@ -460,6 +496,7 @@ static unsigned long cpu_round_rate(struct clk *clk, unsigned long rate) return rate; } +static struct clk h_clk; static int cpu_set_rate(struct clk *clk, unsigned long rate) { unsigned long root_rate = @@ -469,7 +506,7 @@ static int cpu_set_rate(struct clk *clk, unsigned long rate) u32 c = clkctrl_cpu; u32 clkctrl_frac = 1; u32 val; - u32 reg_val; + u32 reg_val, hclk_reg; if (rate < 24000) return -EINVAL; @@ -500,7 +537,31 @@ static int cpu_set_rate(struct clk *clk, unsigned long rate) if ((abs(d) > 100) || (clkctrl_frac < 18) || (clkctrl_frac > 35)) return -EINVAL; - } + } + + /* Set safe hbus clock divider. A divider of 3 ensure that + * the Vddd voltage required for the cpuclk is sufficiently + * high for the hbus clock. + */ + hclk_reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); + if ((hclk_reg & BP_CLKCTRL_HBUS_DIV) != 3) { + hclk_reg &= ~(BM_CLKCTRL_HBUS_DIV); + hclk_reg |= BF_CLKCTRL_HBUS_DIV(3); + + /* change hclk divider to safe value for any ref_cpu + * value. + */ + __raw_writel(hclk_reg, CLKCTRL_BASE_ADDR + + HW_CLKCTRL_HBUS); + } + + for (i = 10000; i; i--) + if (!clk_is_busy(&h_clk)) + break; + if (!i) { + printk(KERN_ERR "couldn't set up HCLK divisor\n"); + return -ETIMEDOUT; + } /* Set Frac div */ val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC0); @@ -510,6 +571,7 @@ static int cpu_set_rate(struct clk *clk, unsigned long rate) /* Do not gate */ __raw_writel(BM_CLKCTRL_FRAC0_CLKGATECPU, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC0_CLR); + /* write clkctrl_cpu */ reg_val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); reg_val &= ~0x3F; @@ -824,8 +886,14 @@ static int emi_set_rate(struct clk *clk, unsigned long rate) { int i; struct mxs_emi_scaling_data emi; + unsigned long iram_phy; void (*f) (struct mxs_emi_scaling_data *, unsigned int *); - f = (void *)MX28_OCRAM_BASE; + f = iram_alloc((unsigned int)mxs_ram_freq_scale_end - + (unsigned int)mxs_ram_freq_scale, &iram_phy); + if (NULL == f) { + pr_err("%s Not enough iram\n", __func__); + return -ENOMEM; + } memcpy(f, mxs_ram_freq_scale, (unsigned int)mxs_ram_freq_scale_end - (unsigned int)mxs_ram_freq_scale); @@ -852,6 +920,9 @@ static int emi_set_rate(struct clk *clk, unsigned long rate) f(&emi, get_current_emidata()); local_fiq_enable(); local_irq_enable(); + iram_free(iram_phy, + (unsigned int)mxs_ram_freq_scale_end - + (unsigned int)mxs_ram_freq_scale); for (i = 10000; i; i--) if (!clk_is_busy(clk)) @@ -1681,6 +1752,8 @@ void mx28_enet_clk_hook(void) reg &= ~BM_CLKCTRL_ENET_SLEEP; reg |= BM_CLKCTRL_ENET_CLK_OUT_EN; + /* select clock for 1588 module */ + reg |= BM_CLKCTRL_ENET_1588_40MHZ; __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_ENET); } @@ -1695,4 +1768,7 @@ void __init mx28_clock_init(void) clk_enable(&cpu_clk); clk_enable(&emi_clk); + + clk_en_public_h_asm_ctrl(mx28_enable_h_autoslow, + mx28_set_hbus_autoslow_flags); } diff --git a/arch/arm/mach-mx28/device.c b/arch/arm/mach-mx28/device.c index 8e1d27fb1213..35e8f14a5568 100644 --- a/arch/arm/mach-mx28/device.c +++ b/arch/arm/mach-mx28/device.c @@ -27,13 +27,16 @@ #include <linux/platform_device.h> #include <linux/mmc/host.h> #include <linux/phy.h> +#include <linux/etherdevice.h> #include <linux/fec.h> +#include <linux/gpmi-nfc.h> #include <asm/mach/map.h> #include <mach/hardware.h> #include <mach/regs-timrot.h> #include <mach/regs-lradc.h> +#include <mach/regs-ocotp.h> #include <mach/device.h> #include <mach/dma.h> #include <mach/lradc.h> @@ -43,6 +46,7 @@ #include "regs-digctl.h" #include "device.h" +#include "mx28evk.h" #include "mx28_pins.h" #if defined(CONFIG_SERIAL_MXS_DUART) || \ @@ -328,76 +332,93 @@ static void __init mx28_init_i2c(void) } #endif - -#if defined(CONFIG_MTD_NAND_GPMI1) +#if defined(CONFIG_MTD_NAND_GPMI_NFC) extern int enable_gpmi; -static int gpmi_pinmux_handler(void) +static int gpmi_nfc_platform_init(unsigned int max_chip_count) { return !enable_gpmi; } -static const char *gpmi_partition_source_types[] = { "cmdlinepart", 0 }; +static void gpmi_nfc_platform_exit(unsigned int max_chip_count) +{ +} -static struct gpmi_platform_data gpmi_platform_data = { - .io_uA = 70000, +static const char *gpmi_nfc_partition_source_types[] = { "cmdlinepart", 0 }; + +static struct gpmi_nfc_platform_data gpmi_nfc_platform_data = { + .nfc_version = 1, + .boot_rom_version = 1, + .clock_name = "gpmi", + .platform_init = gpmi_nfc_platform_init, + .platform_exit = gpmi_nfc_platform_exit, .min_prop_delay_in_ns = 5, .max_prop_delay_in_ns = 9, - .pinmux_handler = gpmi_pinmux_handler, + .max_chip_count = 2, .boot_area_size_in_bytes = 20 * SZ_1M, + .partition_source_types = gpmi_nfc_partition_source_types, .partitions = 0, .partition_count = 0, - .partition_source_types = gpmi_partition_source_types, }; -static struct resource gpmi_resources[] = { +static struct resource gpmi_nfc_resources[] = { { + .name = GPMI_NFC_GPMI_REGS_ADDR_RES_NAME, .flags = IORESOURCE_MEM, .start = GPMI_PHYS_ADDR, .end = GPMI_PHYS_ADDR + SZ_8K - 1, }, { + .name = GPMI_NFC_GPMI_INTERRUPT_RES_NAME, .flags = IORESOURCE_IRQ, - .start = IRQ_GPMI_DMA, - .end = IRQ_GPMI_DMA, - }, - { - .flags = IORESOURCE_DMA, - .start = MXS_DMA_CHANNEL_AHB_APBH_GPMI0, - .end = MXS_DMA_CHANNEL_AHB_APBH_GPMI7, - }, + .start = IRQ_GPMI, + .end = IRQ_GPMI, + }, { + .name = GPMI_NFC_BCH_REGS_ADDR_RES_NAME, .flags = IORESOURCE_MEM, .start = BCH_PHYS_ADDR, .end = BCH_PHYS_ADDR + SZ_8K - 1, }, { + .name = GPMI_NFC_BCH_INTERRUPT_RES_NAME, .flags = IORESOURCE_IRQ, .start = IRQ_BCH, .end = IRQ_BCH, }, + { + .name = GPMI_NFC_DMA_CHANNELS_RES_NAME, + .flags = IORESOURCE_DMA, + .start = MXS_DMA_CHANNEL_AHB_APBH_GPMI0, + .end = MXS_DMA_CHANNEL_AHB_APBH_GPMI7, + }, + { + .name = GPMI_NFC_DMA_INTERRUPT_RES_NAME, + .flags = IORESOURCE_IRQ, + .start = IRQ_GPMI_DMA, + .end = IRQ_GPMI_DMA, + }, }; -static void __init mx28_init_gpmi(void) +static void __init mx28_init_gpmi_nfc(void) { struct platform_device *pdev; - pdev = mxs_get_device("gpmi", 0); + pdev = mxs_get_device(GPMI_NFC_DRIVER_NAME, 0); if (pdev == NULL || IS_ERR(pdev)) return; - pdev->dev.platform_data = &gpmi_platform_data; - pdev->resource = gpmi_resources; - pdev->num_resources = ARRAY_SIZE(gpmi_resources); + pdev->dev.platform_data = &gpmi_nfc_platform_data; + pdev->resource = gpmi_nfc_resources; + pdev->num_resources = ARRAY_SIZE(gpmi_nfc_resources); mxs_add_device(pdev, 1); } #else -static void mx28_init_gpmi(void) +static void mx28_init_gpmi_nfc(void) { } #endif - #if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE) #if defined(CONFIG_MACH_MX28EVK) #define MMC0_POWER MXS_PIN_TO_GPIO(PINID_PWM3) @@ -535,9 +556,10 @@ static struct mxs_mmc_platform_data mmc0_data = { .get_wp = mxs_mmc_get_wp_ssp0, .cmd_pullup = mxs_mmc_cmd_pullup_ssp0, .setclock = mxs_mmc_setclock_ssp0, - .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA + | MMC_CAP_DATA_DDR, .min_clk = 400000, - .max_clk = 52000000, + .max_clk = 48000000, .read_uA = 50000, .write_uA = 70000, .clock_mmc = "ssp.0", @@ -573,9 +595,10 @@ static struct mxs_mmc_platform_data mmc1_data = { .get_wp = mxs_mmc_get_wp_ssp1, .cmd_pullup = mxs_mmc_cmd_pullup_ssp1, .setclock = mxs_mmc_setclock_ssp1, - .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA + | MMC_CAP_DATA_DDR, .min_clk = 400000, - .max_clk = 52000000, + .max_clk = 48000000, .read_uA = 50000, .write_uA = 70000, .clock_mmc = "ssp.1", @@ -697,22 +720,25 @@ static void __init mx28_init_rtc(void) #endif #if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE) -static struct resource fec_resources[] = { +static struct resource fec0_resource[] = { { .start = ENET_PHYS_ADDR, - .end = ENET_PHYS_ADDR + 0xffff, + .end = ENET_PHYS_ADDR + 0x3fff, .flags = IORESOURCE_MEM }, { - .start = IRQ_ENET_SWI, - .end = IRQ_ENET_SWI, - .flags = IORESOURCE_IRQ - }, - { .start = IRQ_ENET_MAC0, .end = IRQ_ENET_MAC0, .flags = IORESOURCE_IRQ }, +}; + +static struct resource fec1_resource[] = { + { + .start = ENET_PHYS_ADDR + 0x4000, + .end = ENET_PHYS_ADDR + 0x7fff, + .flags = IORESOURCE_MEM + }, { .start = IRQ_ENET_MAC1, .end = IRQ_ENET_MAC1, @@ -721,7 +747,12 @@ static struct resource fec_resources[] = { }; extern int mx28evk_enet_gpio_init(void); -static struct fec_platform_data fec_pdata = { +static struct fec_platform_data fec_pdata0 = { + .phy = PHY_INTERFACE_MODE_RMII, + .init = mx28evk_enet_gpio_init, +}; + +static struct fec_platform_data fec_pdata1 = { .phy = PHY_INTERFACE_MODE_RMII, .init = mx28evk_enet_gpio_init, }; @@ -729,22 +760,133 @@ static struct fec_platform_data fec_pdata = { static void __init mx28_init_fec(void) { struct platform_device *pdev; + struct mxs_dev_lookup *lookup; + struct fec_platform_data *pfec; + int i; + u32 val; + + __raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN, + IO_ADDRESS(OCOTP_PHYS_ADDR) + HW_OCOTP_CTRL_SET); + + while (BM_OCOTP_CTRL_BUSY & + __raw_readl(IO_ADDRESS(OCOTP_PHYS_ADDR) + HW_OCOTP_CTRL)) + udelay(10); + + lookup = mxs_get_devices("mxs-fec"); + if (lookup == NULL || IS_ERR(lookup)) + return; + + for (i = 0; i < lookup->size; i++) { + pdev = lookup->pdev + i; + val = __raw_readl(IO_ADDRESS(OCOTP_PHYS_ADDR) + + HW_OCOTP_CUSTn(pdev->id)); + switch (pdev->id) { + case 0: + pdev->resource = fec0_resource; + pdev->num_resources = ARRAY_SIZE(fec0_resource); + pdev->dev.platform_data = &fec_pdata0; + break; + case 1: + pdev->resource = fec1_resource; + pdev->num_resources = ARRAY_SIZE(fec1_resource); + pdev->dev.platform_data = &fec_pdata1; + break; + default: + return; + } + + pfec = (struct fec_platform_data *)pdev->dev.platform_data; + pfec->mac[0] = 0x00; + pfec->mac[1] = 0x04; + pfec->mac[2] = (val >> 24) & 0xFF; + pfec->mac[3] = (val >> 16) & 0xFF; + pfec->mac[4] = (val >> 8) & 0xFF; + pfec->mac[5] = (val >> 0) & 0xFF; + + mxs_add_device(pdev, 2); + } +} +#else +static void __init mx28_init_fec(void) +{ + ; +} +#endif + +#if defined(CONFIG_FEC_L2SWITCH) +static struct resource l2switch_resources[] = { + { + .start = ENET_PHYS_ADDR, + .end = ENET_PHYS_ADDR + 0x17FFC, + .flags = IORESOURCE_MEM + }, + { + .start = IRQ_ENET_SWI, + .end = IRQ_ENET_SWI, + .flags = IORESOURCE_IRQ + }, +}; + +/* Define the fixed address of the L2 Switch hardware. */ +static unsigned int switch_platform_hw[2] = { + (0x800F8000), + (0x800FC000), +}; + +static struct fec_platform_data fec_enet = { + .phy = PHY_INTERFACE_MODE_RMII, + .init = mx28evk_enet_gpio_init, +}; + +static struct switch_platform_data l2switch_data = { + .id = 0, + .fec_enet = &fec_enet, + .hash_table = 0, + .switch_hw = switch_platform_hw, +}; + +static void __init mx28_init_l2switch(void) +{ + struct platform_device *pdev; + struct switch_platform_data *pswitch; + struct fec_platform_data *pfec; + u32 val; - pdev = mxs_get_device("mxs-fec", 0); + __raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN, + IO_ADDRESS(OCOTP_PHYS_ADDR) + HW_OCOTP_CTRL_SET); + + while (BM_OCOTP_CTRL_BUSY & + __raw_readl(IO_ADDRESS(OCOTP_PHYS_ADDR) + HW_OCOTP_CTRL)) + udelay(10); + + pdev = mxs_get_device("mxs-l2switch", 0); if (pdev == NULL || IS_ERR(pdev)) return; - pdev->resource = fec_resources; - pdev->num_resources = ARRAY_SIZE(fec_resources); - pdev->dev.platform_data = &fec_pdata; + val = __raw_readl(IO_ADDRESS(OCOTP_PHYS_ADDR) + + HW_OCOTP_CUSTn(pdev->id)); + pdev->resource = l2switch_resources; + pdev->num_resources = ARRAY_SIZE(l2switch_resources); + pdev->dev.platform_data = &l2switch_data; + + pswitch = (struct switch_platform_data *)pdev->dev.platform_data; + pfec = pswitch->fec_enet; + pfec->mac[0] = 0x00; + pfec->mac[1] = 0x04; + pfec->mac[2] = (val >> 24) & 0xFF; + pfec->mac[3] = (val >> 16) & 0xFF; + pfec->mac[4] = (val >> 8) & 0xFF; + pfec->mac[5] = (val >> 0) & 0xFF; + mxs_add_device(pdev, 2); } #else -static void __init mx28_init_fec(void) +static void __init mx28_init_l2switch(void) { ; } #endif + #ifdef CONFIG_MXS_LRADC struct mxs_lradc_plat_data mx28_lradc_data = { .vddio_voltage = BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL10, @@ -1211,6 +1353,156 @@ static inline mx28_init_spdif(void) } #endif +#if defined(CONFIG_MXS_PERSISTENT) +static const struct mxs_persistent_bit_config +mx28_persistent_bit_config[] = { + { .reg = 0, .start = 0, .width = 1, + .name = "CLOCKSOURCE" }, + { .reg = 0, .start = 1, .width = 1, + .name = "ALARM_WAKE_EN" }, + { .reg = 0, .start = 2, .width = 1, + .name = "ALARM_EN" }, + { .reg = 0, .start = 3, .width = 1, + .name = "CLK_SECS" }, + { .reg = 0, .start = 4, .width = 1, + .name = "XTAL24MHZ_PWRUP" }, + { .reg = 0, .start = 5, .width = 1, + .name = "XTAL32MHZ_PWRUP" }, + { .reg = 0, .start = 6, .width = 1, + .name = "XTAL32_FREQ" }, + { .reg = 0, .start = 7, .width = 1, + .name = "ALARM_WAKE" }, + { .reg = 0, .start = 8, .width = 5, + .name = "MSEC_RES" }, + { .reg = 0, .start = 13, .width = 1, + .name = "DISABLE_XTALOK" }, + { .reg = 0, .start = 14, .width = 2, + .name = "LOWERBIAS" }, + { .reg = 0, .start = 16, .width = 1, + .name = "DISABLE_PSWITCH" }, + { .reg = 0, .start = 17, .width = 1, + .name = "AUTO_RESTART" }, + { .reg = 0, .start = 18, .width = 1, + .name = "ENABLE_LRADC_PWRUP" }, + { .reg = 0, .start = 20, .width = 1, + .name = "THERMAL_RESET" }, + { .reg = 0, .start = 21, .width = 1, + .name = "EXTERNAL_RESET" }, + { .reg = 0, .start = 28, .width = 4, + .name = "ADJ_POSLIMITBUCK" }, + { .reg = 1, .start = 0, .width = 1, + .name = "FORCE_RECOVERY" }, + { .reg = 1, .start = 1, .width = 1, + .name = "ROM_REDUNDANT_BOOT" }, + { .reg = 1, .start = 2, .width = 1, + .name = "NAND_SDK_BLOCK_REWRITE" }, + { .reg = 1, .start = 3, .width = 1, + .name = "SD_SPEED_ENABLE" }, + { .reg = 1, .start = 4, .width = 1, + .name = "SD_INIT_SEQ_1_DISABLE" }, + { .reg = 1, .start = 5, .width = 1, + .name = "SD_CMD0_DISABLE" }, + { .reg = 1, .start = 6, .width = 1, + .name = "SD_INIT_SEQ_2_ENABLE" }, + { .reg = 1, .start = 7, .width = 1, + .name = "OTG_ATL_ROLE_BIT" }, + { .reg = 1, .start = 8, .width = 1, + .name = "OTG_HNP_BIT" }, + { .reg = 1, .start = 9, .width = 1, + .name = "USB_LOW_POWER_MODE" }, + { .reg = 1, .start = 10, .width = 1, + .name = "SKIP_CHECKDISK" }, + { .reg = 1, .start = 11, .width = 1, + .name = "USB_BOOT_PLAYER_MODE" }, + { .reg = 1, .start = 12, .width = 1, + .name = "ENUMERATE_500MA_TWICE" }, + { .reg = 1, .start = 13, .width = 19, + .name = "SPARE_GENERAL" }, + + { .reg = 2, .start = 0, .width = 32, + .name = "SPARE_2" }, + { .reg = 3, .start = 0, .width = 32, + .name = "SPARE_3" }, + { .reg = 4, .start = 0, .width = 32, + .name = "SPARE_4" }, + { .reg = 5, .start = 0, .width = 32, + .name = "SPARE_5" }, +}; + +static struct mxs_platform_persistent_data mx28_persistent_data = { + .bit_config_tab = mx28_persistent_bit_config, + .bit_config_cnt = ARRAY_SIZE(mx28_persistent_bit_config), +}; + +static struct resource mx28_persistent_res[] = { + { + .flags = IORESOURCE_MEM, + .start = RTC_PHYS_ADDR, + .end = RTC_PHYS_ADDR + 0x2000 - 1, + }, +}; + +static void mx28_init_persistent(void) +{ + struct platform_device *pdev; + pdev = mxs_get_device("mxs-persistent", 0); + if (pdev == NULL || IS_ERR(pdev)) + return; + pdev->dev.platform_data = &mx28_persistent_data; + pdev->resource = mx28_persistent_res, + pdev->num_resources = ARRAY_SIZE(mx28_persistent_res), + mxs_add_device(pdev, 3); +} +#else +static void mx28_init_persistent() +{ +} +#endif + +#if defined(CONFIG_FSL_OTP) +/* Building up eight registers's names of a bank */ +#define BANK(a, b, c, d, e, f, g, h) \ + {\ + ("HW_OCOTP_"#a), ("HW_OCOTP_"#b), ("HW_OCOTP_"#c), ("HW_OCOTP_"#d), \ + ("HW_OCOTP_"#e), ("HW_OCOTP_"#f), ("HW_OCOTP_"#g), ("HW_OCOTP_"#h) \ + } + +#define BANKS (5) +#define BANK_ITEMS (8) +static const char *bank_reg_desc[BANKS][BANK_ITEMS] = { + BANK(CUST0, CUST1, CUST2, CUST3, CRYPTO0, CRYPTO1, CRYPTO2, CRYPTO3), + BANK(HWCAP0, HWCAP1, HWCAP2, HWCAP3, HWCAP4, HWCAP5, SWCAP, CUSTCAP), + BANK(LOCK, OPS0, OPS1, OPS2, OPS3, UN0, UN1, UN2), + BANK(ROM0, ROM1, ROM2, ROM3, ROM4, ROM5, ROM6, ROM7), + BANK(SRK0, SRK1, SRK2, SRK3, SRK4, SRK5, SRK6, SRK7), +}; + +static struct fsl_otp_data otp_data = { + .fuse_name = (char **)bank_reg_desc, + .regulator_name = "vddio", + .fuse_num = BANKS * BANK_ITEMS, +}; +#undef BANK +#undef BANKS +#undef BANK_ITEMS + +static void __init mx28_init_otp(void) +{ + struct platform_device *pdev; + pdev = mxs_get_device("ocotp", 0); + if (pdev == NULL || IS_ERR(pdev)) + return; + pdev->dev.platform_data = &otp_data; + pdev->resource = NULL; + pdev->num_resources = 0; + mxs_add_device(pdev, 3); +} +#else +static void mx28_init_otp(void) +{ +} +#endif + int __init mx28_device_init(void) { mx28_init_dma(); @@ -1220,10 +1512,11 @@ int __init mx28_device_init(void) mx28_init_lradc(); mx28_init_auart(); mx28_init_mmc(); - mx28_init_gpmi(); + mx28_init_gpmi_nfc(); mx28_init_wdt(); mx28_init_rtc(); mx28_init_fec(); + mx28_init_l2switch(); mx28_init_flexcan(); mx28_init_kbd(); mx28_init_ts(); @@ -1233,7 +1526,8 @@ int __init mx28_device_init(void) mx28_init_pxp(); mx28_init_dcp(); mx28_init_battery(); - + mx28_init_persistent(); + mx28_init_otp(); return 0; } diff --git a/arch/arm/mach-mx28/emi_settings.c b/arch/arm/mach-mx28/emi_settings.c index 7dd62b9dd65a..56df6ad0c0d4 100644 --- a/arch/arm/mach-mx28/emi_settings.c +++ b/arch/arm/mach-mx28/emi_settings.c @@ -27,7 +27,6 @@ #include <linux/platform_device.h> #include <linux/mmc/host.h> #include <linux/phy.h> -#include <linux/fec.h> #include <asm/mach/map.h> diff --git a/arch/arm/mach-mx28/include/mach/mx28.h b/arch/arm/mach-mx28/include/mach/mx28.h index f74b8941fad2..097253266709 100644 --- a/arch/arm/mach-mx28/include/mach/mx28.h +++ b/arch/arm/mach-mx28/include/mach/mx28.h @@ -226,12 +226,17 @@ #define MX28_SOC_IO_ADDRESS(x) \ ((x) - MX28_SOC_IO_PHYS_BASE + MX28_SOC_IO_VIRT_BASE) +#ifdef __ASSEMBLER__ +#define IO_ADDRESS(x) \ + MX28_SOC_IO_ADDRESS(x) +#else #define IO_ADDRESS(x) \ (void __force __iomem *) \ (((x) >= (unsigned long)MX28_SOC_IO_PHYS_BASE) && \ ((x) < (unsigned long)MX28_SOC_IO_PHYS_BASE + \ MX28_SOC_IO_AREA_SIZE) ? \ MX28_SOC_IO_ADDRESS(x) : 0xDEADBEEF) +#endif #ifdef CONFIG_MXS_EARLY_CONSOLE #define MXS_DEBUG_CONSOLE_PHYS DUART_PHYS_ADDR diff --git a/arch/arm/mach-mx28/mx28evk.c b/arch/arm/mach-mx28/mx28evk.c index 650d16a4fb0a..37beb27f7065 100644 --- a/arch/arm/mach-mx28/mx28evk.c +++ b/arch/arm/mach-mx28/mx28evk.c @@ -39,7 +39,7 @@ static struct i2c_board_info __initdata mxs_i2c_device[] = { { I2C_BOARD_INFO("sgtl5000-i2c", 0x14), .flags = I2C_M_TEN } }; -static void i2c_device_init(void) +static void __init i2c_device_init(void) { i2c_register_board_info(0, mxs_i2c_device, ARRAY_SIZE(mxs_i2c_device)); } @@ -104,7 +104,12 @@ static void __init mx28evk_init_machine(void) { mx28_pinctrl_init(); /* Init iram allocate */ +#ifdef CONFIG_VECTORS_PHY_ADDR + /* reserve the first page for irq vector table*/ + iram_init(MX28_OCRAM_PHBASE + PAGE_SIZE, MX28_OCRAM_SIZE - PAGE_SIZE); +#else iram_init(MX28_OCRAM_PHBASE, MX28_OCRAM_SIZE); +#endif mx28_gpio_init(); mx28evk_pins_init(); diff --git a/arch/arm/mach-mx28/mx28evk.h b/arch/arm/mach-mx28/mx28evk.h index c141749cc183..d973c0f7ef19 100644 --- a/arch/arm/mach-mx28/mx28evk.h +++ b/arch/arm/mach-mx28/mx28evk.h @@ -20,4 +20,9 @@ #define __ASM_ARM_MACH_MX28EVK_H extern void __init mx28evk_pins_init(void); +extern int mx28evk_enet_gpio_init(void); +void mx28evk_enet_io_lowerpower_enter(void); +void mx28evk_enet_io_lowerpower_exit(void); + + #endif /* __ASM_ARM_MACH_MX28EVK_H */ diff --git a/arch/arm/mach-mx28/mx28evk_pins.c b/arch/arm/mach-mx28/mx28evk_pins.c index 8bb253607658..7d5b64328324 100644 --- a/arch/arm/mach-mx28/mx28evk_pins.c +++ b/arch/arm/mach-mx28/mx28evk_pins.c @@ -21,6 +21,7 @@ #include <linux/platform_device.h> #include <linux/irq.h> #include <linux/gpio.h> +#include <linux/delay.h> #include <mach/pinctrl.h> @@ -530,15 +531,106 @@ static struct pin_desc mx28evk_fixed_pins[] = { .name = "SSP0_SCK", .id = PINID_SSP0_SCK, .fun = PIN_FUN1, - .strength = PAD_8MA, + .strength = PAD_12MA, .voltage = PAD_3_3V, .pullup = 0, - .drive = 1, + .drive = 2, .pull = 0, }, #endif +#if defined(CONFIG_LEDS_MXS) || defined(CONFIG_LEDS_MXS_MODULE) + { + .name = "LEDS_PWM0", + .id = PINID_AUART1_RX, + .fun = PIN_FUN3, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "LEDS_PWM1", + .id = PINID_AUART1_TX, + .fun = PIN_FUN3, + .strength = PAD_8MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, +#endif +#if defined(CONFIG_SND_MXS_SOC_DAI) || defined(CONFIG_SND_MXS_SOC_DAI_MODULE) + /* Configurations of SAIF0 port pins */ + { + .name = "SAIF0_MCLK", + .id = PINID_SAIF0_MCLK, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SAIF0_LRCLK", + .id = PINID_SAIF0_LRCLK, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SAIF0_BITCLK", + .id = PINID_SAIF0_BITCLK, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SAIF0_SDATA0", + .id = PINID_SAIF0_SDATA0, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, + { + .name = "SAIF1_SDATA0", + .id = PINID_SAIF1_SDATA0, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, +#endif +#if defined(CONFIG_SND_SOC_MXS_SPDIF) || \ + defined(CONFIG_SND_SOC_MXS_SPDIF_MODULE) + { + .name = "SPDIF", + .id = PINID_SPDIF, + .fun = PIN_FUN1, + .strength = PAD_12MA, + .voltage = PAD_3_3V, + .pullup = 1, + .drive = 1, + .pull = 1, + }, +#endif +}; -#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE) +#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)\ + || defined(CONFIG_FEC_L2SWITCH) +static struct pin_desc mx28evk_eth_pins[] = { { .name = "ENET0_MDC", .id = PINID_ENET0_MDC, @@ -620,106 +712,77 @@ static struct pin_desc mx28evk_fixed_pins[] = { .drive = 1, }, { - .name = "ENET_CLK", - .id = PINID_ENET_CLK, - .fun = PIN_FUN1, + .name = "ENET1_RX_EN", + .id = PINID_ENET0_CRS, + .fun = PIN_FUN2, .strength = PAD_8MA, .pull = 1, .pullup = 1, .voltage = PAD_3_3V, - .drive = 1, - }, -#endif -#if defined(CONFIG_LEDS_MXS) || defined(CONFIG_LEDS_MXS_MODULE) - { - .name = "LEDS_PWM0", - .id = PINID_AUART1_RX, - .fun = PIN_FUN3, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, + .drive = 1, }, { - .name = "LEDS_PWM1", - .id = PINID_AUART1_TX, - .fun = PIN_FUN3, - .strength = PAD_8MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, + .name = "ENET1_RXD0", + .id = PINID_ENET0_RXD2, + .fun = PIN_FUN2, + .strength = PAD_8MA, + .pull = 1, + .pullup = 1, + .voltage = PAD_3_3V, + .drive = 1, }, -#endif -#if defined(CONFIG_SND_MXS_SOC_DAI) || defined(CONFIG_SND_MXS_SOC_DAI_MODULE) - /* Configurations of SAIF0 port pins */ { - .name = "SAIF0_MCLK", - .id = PINID_SAIF0_MCLK, - .fun = PIN_FUN1, - .strength = PAD_12MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, + .name = "ENET1_RXD1", + .id = PINID_ENET0_RXD3, + .fun = PIN_FUN2, + .strength = PAD_8MA, + .pull = 1, + .pullup = 1, + .voltage = PAD_3_3V, + .drive = 1, }, { - .name = "SAIF0_LRCLK", - .id = PINID_SAIF0_LRCLK, - .fun = PIN_FUN1, - .strength = PAD_12MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, + .name = "ENET1_TX_EN", + .id = PINID_ENET0_COL, + .fun = PIN_FUN2, + .strength = PAD_8MA, + .pull = 1, + .pullup = 1, + .voltage = PAD_3_3V, + .drive = 1, }, { - .name = "SAIF0_BITCLK", - .id = PINID_SAIF0_BITCLK, - .fun = PIN_FUN1, - .strength = PAD_12MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, + .name = "ENET1_TXD0", + .id = PINID_ENET0_TXD2, + .fun = PIN_FUN2, + .strength = PAD_8MA, + .pull = 1, + .pullup = 1, + .voltage = PAD_3_3V, + .drive = 1, }, { - .name = "SAIF0_SDATA0", - .id = PINID_SAIF0_SDATA0, - .fun = PIN_FUN1, - .strength = PAD_12MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, + .name = "ENET1_TXD1", + .id = PINID_ENET0_TXD3, + .fun = PIN_FUN2, + .strength = PAD_8MA, + .pull = 1, + .pullup = 1, + .voltage = PAD_3_3V, + .drive = 1, }, { - .name = "SAIF1_SDATA0", - .id = PINID_SAIF1_SDATA0, - .fun = PIN_FUN1, - .strength = PAD_12MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, + .name = "ENET_CLK", + .id = PINID_ENET_CLK, + .fun = PIN_FUN1, + .strength = PAD_8MA, + .pull = 1, + .pullup = 1, + .voltage = PAD_3_3V, + .drive = 1, }, -#endif -#if defined(CONFIG_SND_SOC_MXS_SPDIF) || \ - defined(CONFIG_SND_SOC_MXS_SPDIF_MODULE) - { - .name = "SPDIF", - .id = PINID_SPDIF, - .fun = PIN_FUN1, - .strength = PAD_12MA, - .voltage = PAD_3_3V, - .pullup = 1, - .drive = 1, - .pull = 1, - }, -#endif }; - +#endif static int __initdata enable_ssp1 = { 0 }; static int __init ssp1_setup(char *__unused) @@ -835,16 +898,16 @@ static struct pin_desc mx28evk_ssp1_pins[] = { .name = "SSP1_SCK", .id = PINID_GPMI_WRN, .fun = PIN_FUN2, - .strength = PAD_8MA, + .strength = PAD_12MA, .voltage = PAD_3_3V, .pullup = 0, - .drive = 1, + .drive = 2, .pull = 0, }, }; -int __initdata enable_gpmi = { 0 }; +int enable_gpmi = { 0 }; static int __init gpmi_setup(char *__unused) { enable_gpmi = 1; @@ -1009,7 +1072,8 @@ static struct pin_desc mx28evk_gpmi_pins[] = { }, }; -#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE) +#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)\ + || defined(CONFIG_FEC_L2SWITCH) int mx28evk_enet_gpio_init(void) { /* pwr */ @@ -1019,15 +1083,54 @@ int mx28evk_enet_gpio_init(void) /* reset phy */ gpio_request(MXS_PIN_TO_GPIO(PINID_ENET0_RX_CLK), "PHY_RESET"); gpio_direction_output(MXS_PIN_TO_GPIO(PINID_ENET0_RX_CLK), 0); + mdelay(10); gpio_direction_output(MXS_PIN_TO_GPIO(PINID_ENET0_RX_CLK), 1); return 0; } + +void mx28evk_enet_io_lowerpower_enter(void) +{ + int i; + gpio_direction_output(MXS_PIN_TO_GPIO(PINID_SSP1_DATA3), 1); + gpio_direction_output(MXS_PIN_TO_GPIO(PINID_ENET0_RX_CLK), 0); + gpio_request(MXS_PIN_TO_GPIO(PINID_ENET0_TX_CLK), "ETH_INT"); + gpio_direction_output(MXS_PIN_TO_GPIO(PINID_ENET0_TX_CLK), 0); + + for (i = 0; i < ARRAY_SIZE(mx28evk_eth_pins); i++) { + mxs_release_pin(mx28evk_eth_pins[i].id, + mx28evk_eth_pins[i].name); + gpio_request(MXS_PIN_TO_GPIO(mx28evk_eth_pins[i].id), + mx28evk_eth_pins[i].name); + gpio_direction_output( + MXS_PIN_TO_GPIO(mx28evk_eth_pins[i].id), 0); + } + +} + +void mx28evk_enet_io_lowerpower_exit(void) +{ + int i; + gpio_direction_output(MXS_PIN_TO_GPIO(PINID_SSP1_DATA3), 0); + gpio_direction_output(MXS_PIN_TO_GPIO(PINID_ENET0_RX_CLK), 1); + gpio_free(MXS_PIN_TO_GPIO(PINID_ENET0_TX_CLK)); + for (i = 0; i < ARRAY_SIZE(mx28evk_eth_pins); i++) { + gpio_free(MXS_PIN_TO_GPIO(mx28evk_eth_pins[i].id)); + mxs_request_pin(mx28evk_eth_pins[i].id, + mx28evk_eth_pins[i].fun, + mx28evk_eth_pins[i].name); + } +} + #else int mx28evk_enet_gpio_init(void) { return 0; } +void mx28evk_enet_io_lowerpower_enter(void) +{} +void mx28evk_enet_io_lowerpower_exit(void) +{} #endif void __init mx28evk_init_pin_group(struct pin_desc *pins, unsigned count) @@ -1071,5 +1174,9 @@ void __init mx28evk_pins_init(void) mx28evk_init_pin_group(mx28evk_gpmi_pins, ARRAY_SIZE(mx28evk_gpmi_pins)); } - +#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)\ + || defined(CONFIG_FEC_L2SWITCH) + mx28evk_init_pin_group(mx28evk_eth_pins, + ARRAY_SIZE(mx28evk_eth_pins)); +#endif } diff --git a/arch/arm/mach-mx28/pm.c b/arch/arm/mach-mx28/pm.c index c26a495f59e2..4ac13bc3248c 100644 --- a/arch/arm/mach-mx28/pm.c +++ b/arch/arm/mach-mx28/pm.c @@ -36,12 +36,13 @@ #include <mach/dma.h> #include <mach/regs-rtc.h> #include "regs-clkctrl.h" -#include "regs-pinctrl.h" #include <mach/regs-power.h> #include <mach/regs-pwm.h> #include <mach/regs-rtc.h> #include <mach/../../regs-icoll.h> #include "regs-dram.h" +#include "mx28_pins.h" +#include "mx28evk.h" #include "sleep.h" @@ -79,7 +80,8 @@ static inline void do_standby(void) u32 reg_clkctrl_clkseq, reg_clkctrl_xtal; unsigned long iram_phy_addr; void *iram_virtual_addr; - + int wakeupirq; + mx28evk_enet_io_lowerpower_enter(); /* * 1) switch clock domains from PLL to 24MHz * 2) lower voltage (TODO) @@ -110,7 +112,8 @@ static inline void do_standby(void) cpu_parent = clk_get_parent(cpu_clk); hbus_rate = clk_get_rate(hbus_clk); clk_set_parent(cpu_clk, osc_clk); - } + } else + pr_err("fail to get cpu clk\n"); local_fiq_disable(); @@ -122,15 +125,18 @@ static inline void do_standby(void) reg_clkctrl_xtal = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL); + /* do suspend */ mx28_cpu_standby_ptr = iram_virtual_addr; mx28_cpu_standby_ptr(); + wakeupirq = __raw_readl(IO_ADDRESS(ICOLL_PHYS_ADDR) + HW_ICOLL_STAT); + + pr_info("wakeup irq = %d\n", wakeupirq); __raw_writel(reg_clkctrl_clkseq, REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ); __raw_writel(reg_clkctrl_xtal, REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL); - saved_sleep_state = 0; /* waking from standby */ __raw_writel(BM_POWER_CTRL_PSWITCH_IRQ, REGS_POWER_BASE + HW_POWER_CTRL_CLR); @@ -149,6 +155,7 @@ static inline void do_standby(void) clk_put(cpu_clk); iram_free(iram_phy_addr, MAX_POWEROFF_CODE_SIZE); + mx28evk_enet_io_lowerpower_exit(); } static noinline void do_mem(void) @@ -255,38 +262,52 @@ static struct mx28_pswitch_state pswitch_state = { .dev_running = 0, }; -static irqreturn_t pswitch_interrupt(int irq, void *dev) +#define PSWITCH_POWER_DOWN_DELAY 30 +static struct delayed_work pswitch_work; +static void pswitch_check_work(struct work_struct *work) { int pin_value, i; - - /* check if irq by pswitch */ - if (!(__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & - BM_POWER_CTRL_PSWITCH_IRQ)) - return IRQ_HANDLED; - for (i = 0; i < 3000; i++) { + for (i = 0; i < PSWITCH_POWER_DOWN_DELAY; i++) { pin_value = __raw_readl(REGS_POWER_BASE + HW_POWER_STS) & BF_POWER_STS_PSWITCH(0x1); if (pin_value == 0) break; - mdelay(1); + msleep(100); } - if (i < 3000) { + if (i < PSWITCH_POWER_DOWN_DELAY) { pr_info("pswitch goto suspend\n"); complete(&suspend_request); } else { pr_info("release pswitch to power down\n"); - for (i = 0; i < 5000; i++) { + for (i = 0; i < 500; i++) { pin_value = __raw_readl(REGS_POWER_BASE + HW_POWER_STS) & BF_POWER_STS_PSWITCH(0x1); if (pin_value == 0) break; - mdelay(1); + msleep(10); } pr_info("pswitch power down\n"); mx28_pm_power_off(); } __raw_writel(BM_POWER_CTRL_PSWITCH_IRQ, REGS_POWER_BASE + HW_POWER_CTRL_CLR); + __raw_writel(BM_POWER_CTRL_ENIRQ_PSWITCH, + REGS_POWER_BASE + HW_POWER_CTRL_SET); + __raw_writel(BM_POWER_CTRL_PSWITCH_IRQ, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); +} + + +static irqreturn_t pswitch_interrupt(int irq, void *dev) +{ + + /* check if irq by pswitch */ + if (!(__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) & + BM_POWER_CTRL_PSWITCH_IRQ)) + return IRQ_HANDLED; + __raw_writel(BM_POWER_CTRL_ENIRQ_PSWITCH, + REGS_POWER_BASE + HW_POWER_CTRL_CLR); + schedule_delayed_work(&pswitch_work, 1); return IRQ_HANDLED; } @@ -299,6 +320,7 @@ static struct irqaction pswitch_irq = { static void init_pswitch(void) { + INIT_DELAYED_WORK(&pswitch_work, pswitch_check_work); kthread_run(suspend_thread_fn, NULL, "pswitch"); __raw_writel(BM_POWER_CTRL_PSWITCH_IRQ, REGS_POWER_BASE + HW_POWER_CTRL_CLR); diff --git a/arch/arm/mach-mx28/regs-clkctrl.h b/arch/arm/mach-mx28/regs-clkctrl.h index 161860c2fcf0..9de19275fa91 100644 --- a/arch/arm/mach-mx28/regs-clkctrl.h +++ b/arch/arm/mach-mx28/regs-clkctrl.h @@ -478,6 +478,7 @@ #define BM_CLKCTRL_ENET_RSRVD0 0x0000FFFF #define BF_CLKCTRL_ENET_RSRVD0(v) \ (((v) << 0) & BM_CLKCTRL_ENET_RSRVD0) +#define BM_CLKCTRL_ENET_1588_40MHZ 0x01880000 #define HW_CLKCTRL_HSADC (0x00000150) diff --git a/arch/arm/mach-mx28/sleep.S b/arch/arm/mach-mx28/sleep.S index 438f588f85d3..54e86bd4f717 100644 --- a/arch/arm/mach-mx28/sleep.S +++ b/arch/arm/mach-mx28/sleep.S @@ -25,6 +25,7 @@ #include <mach/hardware.h> #include <mach/regs-power.h> #include <mach/regs-rtc.h> +#include "regs-pinctrl.h" #include "regs-clkctrl.h" #include "regs-dram.h" #include "sleep.h" @@ -39,11 +40,104 @@ #define HW_DRAM_CTL17_ADDR \ (MX28_SOC_IO_ADDRESS(DRAM_PHYS_ADDR) + HW_DRAM_CTL17) +#define HW_DRAM_CTL22_ADDR \ + (MX28_SOC_IO_ADDRESS(DRAM_PHYS_ADDR) + HW_DRAM_CTL22) + #define HW_RTC_PERSISTENT0_ADDR \ (MX28_SOC_IO_ADDRESS(RTC_PHYS_ADDR) + HW_RTC_PERSISTENT0) +#define HW_CLKCTRL_EMI_ADDR \ + (MX28_SOC_IO_ADDRESS(CLKCTRL_PHYS_ADDR) + HW_CLKCTRL_EMI) +#define HW_CLKCTRL_PLL0CTRL0_ADDR \ + (MX28_SOC_IO_ADDRESS(CLKCTRL_PHYS_ADDR) + HW_CLKCTRL_PLL0CTRL0) +#define HW_POWER_VDDIOCTRL_ADDR \ + (MX28_SOC_IO_ADDRESS(POWER_PHYS_ADDR) + HW_POWER_VDDIOCTRL) +#define HW_POWER_VDDDCTRL_ADDR \ + (MX28_SOC_IO_ADDRESS(POWER_PHYS_ADDR) + HW_POWER_VDDDCTRL) +#define HW_POWER_VDDACTRL_ADDR \ + (MX28_SOC_IO_ADDRESS(POWER_PHYS_ADDR) + HW_POWER_VDDACTRL) +#define HW_PINCTRL_EMI_DS_CTRL_ADDR \ + (MX28_SOC_IO_ADDRESS(PINCTRL_PHYS_ADDR) + HW_PINCTRL_EMI_DS_CTRL) + +#define HW_POWER_LOOPCTRL_ADDR \ + (MX28_SOC_IO_ADDRESS(POWER_PHYS_ADDR) + HW_POWER_LOOPCTRL) + +#define HW_POWER_MINPWR_ADDR \ + (MX28_SOC_IO_ADDRESS(POWER_PHYS_ADDR) + HW_POWER_MINPWR) #define PHYS_RAM_START 0x40000000 +#define LOWER_VDDIO 6 +#define LOWER_VDDA 9 +#define LOWER_VDDD 0x16 + +#define VDDIOCTRL_BACKUP 0 +#define VDDACTRL_BACKUP 1 +#define VDDDCTRL_BACKUP 2 +#define POWER_LOOPCTRL_BACKUP 3 +#define POWER_MINPWR_BACKUP 4 + +.macro PM_BITS_SET, addr, val + mov r0, #(\addr & 0x000000FF) + orr r0, r0, #(\addr & 0x0000FF00) + orr r0, r0, #(\addr & 0x00FF0000) + orr r0, r0, #(\addr & 0xFF000000) + ldr r1, [r0] + orr r1, r1, #(\val) + str r1, [r0] +.endm + +.macro PM_BITS_CLR, addr, val + mov r0, #(\addr & 0x000000FF) + orr r0, r0, #(\addr & 0x0000FF00) + orr r0, r0, #(\addr & 0x00FF0000) + orr r0, r0, #(\addr & 0xFF000000) + ldr r1, [r0] + bic r1, r1, #(\val) + str r1, [r0] +.endm + +.macro PM_BACKUP_REG, addr, num + mov r0, #(\addr & 0x000000FF) + orr r0, r0, #(\addr & 0x0000FF00) + orr r0, r0, #(\addr & 0x00FF0000) + orr r0, r0, #(\addr & 0xFF000000) + ldr r1, [r0] + str r1, __mx28_temp_stack + \num * 4 +.endm + +.macro PM_WRITE_REG_MASK, addr, bitmask, val + mov r0, #(\addr & 0x000000FF) + orr r0, r0, #(\addr & 0x0000FF00) + orr r0, r0, #(\addr & 0x00FF0000) + orr r0, r0, #(\addr & 0xFF000000) + ldr r1, [r0] + bic r1, r1, #(\bitmask) + orr r1, r1, #(\val) + str r1, [r0] +.endm + +.macro PM_SET_AND_BACKUP_REG, addr, bitmask, val, num + mov r0, #(\addr & 0x000000FF) + orr r0, r0, #(\addr & 0x0000FF00) + orr r0, r0, #(\addr & 0x00FF0000) + orr r0, r0, #(\addr & 0xFF000000) + ldr r1, [r0] + str r1, __mx28_temp_stack + \num * 4 + bic r1, r1, #(\bitmask) + orr r1, r1, #(\val) + str r1, [r0] +.endm + +.macro PM_SET_RESTORE_REG, addr, num + mov r0, #(\addr & 0x000000FF) + orr r0, r0, #(\addr & 0x0000FF00) + orr r0, r0, #(\addr & 0x00FF0000) + orr r0, r0, #(\addr & 0xFF000000) + ldr r1, __mx28_temp_stack + \num * 4 + str r1, [r0] +.endm + + .global cpu_arm926_switch_mm .text @@ -59,7 +153,6 @@ ENTRY(mx28_cpu_standby) ldr r1, __mx28_flush_cache_addr mov lr, pc mov pc, r1 - @ put DRAM into self refresh mov r0, #(HW_DRAM_CTL17_ADDR & 0x000000FF) orr r0, r0, #(HW_DRAM_CTL17_ADDR & 0x0000FF00) @@ -69,6 +162,67 @@ ENTRY(mx28_cpu_standby) orr r1, r1, #(BM_DRAM_CTL17_SREFRESH) str r1, [r0] @ wait for it to actually happen + mov r0, #24 << 5 +11: sub r0, r0, #1 + cmp r0, #0 + bne 11b + + @ gate clk + mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) + ldr r1, [r0] + orr r1, r1, #(BM_CLKCTRL_EMI_CLKGATE) + str r1, [r0] + +// PM_SET_AND_BACKUP_REG HW_PINCTRL_EMI_DS_CTRL_ADDR,\ +// BM_PINCTRL_EMI_DS_CTRL_DDR_MODE,\ +// BF_PINCTRL_EMI_DS_CTRL_DDR_MODE(0x1), 4 + + // vddio + PM_SET_AND_BACKUP_REG HW_POWER_VDDIOCTRL_ADDR,\ + BM_POWER_VDDIOCTRL_TRG, LOWER_VDDIO, VDDIOCTRL_BACKUP + mov r0, #24 << 10 +1: sub r0, r0, #1 + cmp r0, #0 + bne 1b + + PM_SET_AND_BACKUP_REG HW_POWER_VDDACTRL_ADDR,\ + BM_POWER_VDDACTRL_TRG, LOWER_VDDA, VDDACTRL_BACKUP + mov r0, #24 << 10 +2: sub r0, r0, #1 + cmp r0, #0 + bne 2b + + PM_SET_AND_BACKUP_REG HW_POWER_VDDDCTRL_ADDR,\ + BM_POWER_VDDDCTRL_TRG, LOWER_VDDD, VDDDCTRL_BACKUP + mov r0, #24 << 10 +3: sub r0, r0, #1 + cmp r0, #0 + bne 3b + + PM_BACKUP_REG HW_POWER_LOOPCTRL_ADDR, POWER_LOOPCTRL_BACKUP + PM_BACKUP_REG HW_POWER_MINPWR_ADDR, POWER_MINPWR_BACKUP + +// PM_BITS_CLR HW_POWER_LOOPCTRL_ADDR, BM_POWER_LOOPCTRL_EN_RCSCALE +// PM_WRITE_REG_MASK HW_POWER_LOOPCTRL_ADDR, BM_POWER_LOOPCTRL_DC_R,\ +// (2<<BP_POWER_LOOPCTRL_DC_R) + + // half fets + PM_BITS_SET HW_POWER_MINPWR_ADDR, BM_POWER_MINPWR_HALF_FETS + + PM_BITS_CLR HW_POWER_LOOPCTRL_ADDR, BM_POWER_LOOPCTRL_CM_HYST_THRESH + PM_BITS_CLR HW_POWER_LOOPCTRL_ADDR, BM_POWER_LOOPCTRL_EN_CM_HYST + PM_BITS_CLR HW_POWER_LOOPCTRL_ADDR, BM_POWER_LOOPCTRL_EN_DF_HYST + + // enable PFM + PM_BITS_SET HW_POWER_LOOPCTRL_ADDR, BM_POWER_LOOPCTRL_HYST_SIGN + PM_BITS_SET HW_POWER_MINPWR_ADDR, BM_POWER_MINPWR_EN_DC_PFM + + + //Gated PLL0 + PM_BITS_CLR HW_CLKCTRL_PLL0CTRL0_ADDR, BM_CLKCTRL_PLL0CTRL0_POWER @ do enter standby mov r0, #(HW_CLKCTRL_CPU_ADDR & 0x000000FF) @@ -89,6 +243,39 @@ ENTRY(mx28_cpu_standby) nop nop + PM_BITS_SET HW_CLKCTRL_PLL0CTRL0_ADDR, BM_CLKCTRL_PLL0CTRL0_POWER + + PM_SET_RESTORE_REG HW_POWER_MINPWR_ADDR, POWER_MINPWR_BACKUP + + PM_SET_RESTORE_REG HW_POWER_LOOPCTRL_ADDR, POWER_LOOPCTRL_BACKUP + + // vddio + PM_SET_RESTORE_REG HW_POWER_VDDIOCTRL_ADDR, VDDIOCTRL_BACKUP + mov r0, #24 << 10 +10: sub r0, r0, #1 + cmp r0, #0 + bne 10b + PM_SET_RESTORE_REG HW_POWER_VDDACTRL_ADDR, VDDACTRL_BACKUP + mov r0, #24 << 10 +20: sub r0, r0, #1 + cmp r0, #0 + bne 20b + PM_SET_RESTORE_REG HW_POWER_VDDDCTRL_ADDR, VDDDCTRL_BACKUP + mov r0, #24 << 10 +30: sub r0, r0, #1 + cmp r0, #0 + bne 30b + + @ ungate clk + mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000) + orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000) + ldr r1, [r0] + bic r1, r1, #(BM_CLKCTRL_EMI_CLKGATE) + str r1, [r0] + +// PM_SET_RESTORE_REG HW_PINCTRL_EMI_DS_CTRL_ADDR, 4 @ restore normal DRAM mode mov r0, #(HW_DRAM_CTL17_ADDR & 0x000000FF) orr r0, r0, #(HW_DRAM_CTL17_ADDR & 0x0000FF00) @@ -98,6 +285,10 @@ ENTRY(mx28_cpu_standby) bic r1, r1, #BM_DRAM_CTL17_SREFRESH str r1, [r0] @ wait for it to actually happen + mov r0, #24 << 5 +12: sub r0, r0, #1 + cmp r0, #0 + bne 12b nop nop @@ -108,7 +299,7 @@ ENTRY(mx28_cpu_standby) .space 0x100 __mx28_temp_stack: - .word 0 + .space 128 #ifdef CONFIG_STMP378X_RAM_FREQ_SCALING #include "emi.inc" diff --git a/arch/arm/mach-mx28/usb_dr.c b/arch/arm/mach-mx28/usb_dr.c index 13344ef0e26f..50a2f8b381af 100644 --- a/arch/arm/mach-mx28/usb_dr.c +++ b/arch/arm/mach-mx28/usb_dr.c @@ -63,7 +63,7 @@ static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = { }; /* - * resources + * OTG resources */ static struct resource otg_resources[] = { [0] = { @@ -78,6 +78,22 @@ static struct resource otg_resources[] = { }, }; +/* + * UDC resources (same as OTG resource) + */ +static struct resource udc_resources[] = { + [0] = { + .start = (u32)USBCTRL0_PHYS_ADDR, + .end = (u32)(USBCTRL0_PHYS_ADDR + 0x1ff), + .flags = IORESOURCE_MEM, + }, + + [1] = { + .start = IRQ_USB0, + .flags = IORESOURCE_IRQ, + }, +}; + static u64 dr_udc_dmamask = ~(u32) 0; static void dr_udc_release(struct device *dev) { @@ -111,8 +127,8 @@ static struct platform_device __maybe_unused dr_otg_device = { .dma_mask = &dr_otg_dmamask, .coherent_dma_mask = 0xffffffff, }, - .resource = otg_resources, - .num_resources = ARRAY_SIZE(otg_resources), + .resource = udc_resources, + .num_resources = ARRAY_SIZE(udc_resources), }; @@ -156,5 +172,5 @@ void fsl_phy_set_power(struct fsl_xcvr_ops *this, #ifdef CONFIG_MXS_VBUS_CURRENT_DRAW fs_initcall(usb_dr_init); #else - module_init(usb_dr_init); + subsys_initcall(usb_dr_init); #endif diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c index 2861ecf81235..c7d9560f0850 100644 --- a/arch/arm/mach-mx3/devices.c +++ b/arch/arm/mach-mx3/devices.c @@ -891,6 +891,22 @@ static inline void mxc_init_iim(void) } #endif +static struct platform_device mxc_v4l2_device = { + .name = "mxc_v4l2_capture", + .id = 0, +}; + +static struct platform_device mxc_v4l2out_device = { + .name = "mxc_v4l2_output", + .id = 0, +}; + +static inline void mxc_init_v4l2() +{ + platform_device_register(&mxc_v4l2_device); + platform_device_register(&mxc_v4l2out_device); +} + int __init mxc_init_devices(void) { mxc_init_wdt(); @@ -910,6 +926,7 @@ int __init mxc_init_devices(void) mxc_init_vpu(); mxc_init_rnga(); mxc_init_iim(); + mxc_init_v4l2(); return 0; } diff --git a/arch/arm/mach-mx3/mx31ads.c b/arch/arm/mach-mx3/mx31ads.c index 92c16045e391..b5d63339b498 100644 --- a/arch/arm/mach-mx3/mx31ads.c +++ b/arch/arm/mach-mx3/mx31ads.c @@ -1241,16 +1241,16 @@ static struct fsl_ata_platform_data ata_data = { }; static struct resource pata_fsl_resources[] = { - [0] = { /* I/O */ - .start = ATA_BASE_ADDR + 0x00, - .end = ATA_BASE_ADDR + 0xD8, - .flags = IORESOURCE_MEM, - }, - [2] = { /* IRQ */ - .start = MXC_INT_ATA, - .end = MXC_INT_ATA, - .flags = IORESOURCE_IRQ, - }, + { + .start = ATA_BASE_ADDR, + .end = ATA_BASE_ADDR + 0x000000D8, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_ATA, + .end = MXC_INT_ATA, + .flags = IORESOURCE_IRQ, + }, }; static struct platform_device pata_fsl_device = { diff --git a/arch/arm/mach-mx3/mx3_3stack.c b/arch/arm/mach-mx3/mx3_3stack.c index 4a97f688a75d..516890f020a4 100644 --- a/arch/arm/mach-mx3/mx3_3stack.c +++ b/arch/arm/mach-mx3/mx3_3stack.c @@ -92,13 +92,17 @@ static struct resource mxc_kpp_resources[] = { .start = MXC_INT_KPP, .end = MXC_INT_KPP, .flags = IORESOURCE_IRQ, - } + }, + [1] = { + .start = KPP_BASE_ADDR, + .end = KPP_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, }; static struct keypad_data keypad_plat_data = { .rowmax = 3, .colmax = 4, - .irq = MXC_INT_KPP, .learning = 0, .delay = 2, .matrix = keymapping, @@ -168,6 +172,20 @@ static struct platform_device mxc_nand_mtd_device = { }, }; +static struct resource mxc_nand_resources[] = { + { + .flags = IORESOURCE_MEM, + .name = "NFC_AXI_BASE", + .start = NFC_BASE_ADDR, + .end = NFC_BASE_ADDR + SZ_4K - 1, + }, + { + .flags = IORESOURCE_IRQ, + .start = MXC_INT_NANDFC, + .end = MXC_INT_NANDFC, + }, +}; + static struct platform_device mxc_nandv2_mtd_device = { .name = "mxc_nandv2_flash", .id = 0, @@ -175,6 +193,8 @@ static struct platform_device mxc_nandv2_mtd_device = { .release = mxc_nop_release, .platform_data = &mxc_nand_data, }, + .resource = mxc_nand_resources, + .num_resources = ARRAY_SIZE(mxc_nand_resources), }; static void mxc_init_nand_mtd(void) @@ -835,16 +855,16 @@ static struct fsl_ata_platform_data ata_data = { }; static struct resource pata_fsl_resources[] = { - [0] = { /* I/O */ - .start = ATA_BASE_ADDR + 0x00, - .end = ATA_BASE_ADDR + 0xD8, - .flags = IORESOURCE_MEM, - }, - [2] = { /* IRQ */ - .start = MXC_INT_ATA, - .end = MXC_INT_ATA, - .flags = IORESOURCE_IRQ, - }, + { + .start = ATA_BASE_ADDR, + .end = ATA_BASE_ADDR + 0x000000D8, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_ATA, + .end = MXC_INT_ATA, + .flags = IORESOURCE_IRQ, + }, }; static struct platform_device pata_fsl_device = { diff --git a/arch/arm/mach-mx3/usb_dr.c b/arch/arm/mach-mx3/usb_dr.c index 7331463173e9..d84fea7f1a80 100644 --- a/arch/arm/mach-mx3/usb_dr.c +++ b/arch/arm/mach-mx3/usb_dr.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -59,7 +59,7 @@ static struct fsl_usb2_platform_data __maybe_unused dr_1504_config = { /* - * resources + * OTG resources */ static struct resource otg_resources[] = { [0] = { @@ -73,6 +73,20 @@ static struct resource otg_resources[] = { }, }; +/* + * UDC resources (same as OTG resource) + */ +static struct resource udc_resources[] = { + [0] = { + .start = (u32)(USB_OTGREGS_BASE), + .end = (u32)(USB_OTGREGS_BASE + 0x1ff), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_USB3, + .flags = IORESOURCE_IRQ, + }, +}; static u64 dr_udc_dmamask = ~(u32) 0; static void dr_udc_release(struct device *dev) @@ -96,8 +110,8 @@ static struct platform_device __maybe_unused dr_udc_device = { .dma_mask = &dr_udc_dmamask, .coherent_dma_mask = 0xffffffff, }, - .resource = otg_resources, - .num_resources = ARRAY_SIZE(otg_resources), + .resource = udc_resources, + .num_resources = ARRAY_SIZE(udc_resources), }; static struct platform_device __maybe_unused dr_otg_device = { diff --git a/arch/arm/mach-mx35/devices.c b/arch/arm/mach-mx35/devices.c index 7687d0e0b09d..02c971659bd4 100644 --- a/arch/arm/mach-mx35/devices.c +++ b/arch/arm/mach-mx35/devices.c @@ -585,11 +585,58 @@ static inline void mxc_init_spdif(void) platform_device_register(&mxc_alsa_spdif_device); } +#if defined(CONFIG_SND_MXC_SOC_ESAI) || defined(CONFIG_SND_MXC_SOC_ESAI_MODULE) + +static struct mxc_esai_platform_data esai_data = { + .activate_esai_ports = gpio_activate_esai_ports, + .deactivate_esai_ports = gpio_deactivate_esai_ports, +}; + +static struct resource esai_resources[] = { + { + .start = ESAI_BASE_ADDR, + .end = ESAI_BASE_ADDR + 0x100, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_ESAI, + .end = MXC_INT_ESAI, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_esai_device = { + .name = "mxc_esai", + .id = 0, + .num_resources = ARRAY_SIZE(esai_resources), + .resource = esai_resources, + .dev = { + .release = mxc_nop_release, + .platform_data = &esai_data, + }, +}; + +static void mxc_init_esai(void) +{ + platform_device_register(&mxc_esai_device); +} +#else +static void mxc_init_esai(void) +{ + +} +#endif + +static struct mxc_audio_platform_data mxc_surround_audio_data = { + .ext_ram = 1, +}; + static struct platform_device mxc_alsa_surround_device = { .name = "imx-3stack-wm8580", .id = 0, .dev = { .release = mxc_nop_release, + .platform_data = &mxc_surround_audio_data, }, }; @@ -855,6 +902,22 @@ static inline void mxc_init_ssi(void) } #endif /* CONFIG_SND_MXC_SOC_SSI */ +static struct platform_device mxc_v4l2_device = { + .name = "mxc_v4l2_capture", + .id = 0, +}; + +static struct platform_device mxc_v4l2out_device = { + .name = "mxc_v4l2_output", + .id = 0, +}; + +static inline void mxc_init_v4l2() +{ + platform_device_register(&mxc_v4l2_device); + platform_device_register(&mxc_v4l2out_device); +} + int __init mxc_init_devices(void) { mxc_init_wdt(); @@ -873,6 +936,8 @@ int __init mxc_init_devices(void) mxc_init_iim(); mxc_init_gpu(); mxc_init_ssi(); + mxc_init_esai(); + mxc_init_v4l2(); return 0; } diff --git a/arch/arm/mach-mx35/mx35_3stack.c b/arch/arm/mach-mx35/mx35_3stack.c index c6752fe10c5c..868cf12ca2e6 100644 --- a/arch/arm/mach-mx35/mx35_3stack.c +++ b/arch/arm/mach-mx35/mx35_3stack.c @@ -171,6 +171,20 @@ static struct mtd_partition mxc_nand_partitions[] = { .size = MTDPART_SIZ_FULL}, }; +static struct resource mxc_nand_resources[] = { + { + .flags = IORESOURCE_MEM, + .name = "NFC_AXI_BASE", + .start = NFC_BASE_ADDR, + .end = NFC_BASE_ADDR + SZ_8K - 1, + }, + { + .flags = IORESOURCE_IRQ, + .start = MXC_INT_NANDFC, + .end = MXC_INT_NANDFC, + }, +}; + static struct flash_platform_data mxc_nand_data = { .parts = mxc_nand_partitions, .nr_parts = ARRAY_SIZE(mxc_nand_partitions), @@ -184,6 +198,8 @@ static struct platform_device mxc_nand_mtd_device = { .release = mxc_nop_release, .platform_data = &mxc_nand_data, }, + .resource = mxc_nand_resources, + .num_resources = ARRAY_SIZE(mxc_nand_resources), }; static void mxc_init_nand_mtd(void) @@ -402,7 +418,7 @@ static struct mxc_fm_platform_data si4702_data = { static void adv7180_pwdn(int pwdn) { - pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_1, 1, pwdn); + pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_1, 1, ~pwdn); } static void adv7180_reset(void) @@ -589,6 +605,13 @@ static struct mxc_mmc_platform_data mmc1_data = { #endif .min_clk = 150000, .max_clk = 52000000, + /* Do not disable the eSDHC clk on MX35 3DS board, + * since SYSTEM can't boot up after the reset key + * is pressed when the SD/MMC boot mode is used. + * The root cause is that the ROM code don't ensure + * the SD/MMC clk is running when boot system. + * */ + .clk_always_on = 1, .card_inserted_state = 0, .status = sdhc_get_card_det_status, .wp_status = sdhc_write_protect, @@ -635,6 +658,7 @@ static struct mxc_mmc_platform_data mmc2_data = { .caps = MMC_CAP_4_BIT_DATA, .min_clk = 150000, .max_clk = 50000000, + .clk_always_on = 1, .card_inserted_state = 0, .status = sdhc_get_card_det_status, .wp_status = sdhc_write_protect, @@ -765,16 +789,16 @@ static struct fsl_ata_platform_data ata_data = { }; static struct resource pata_fsl_resources[] = { - [0] = { /* I/O */ - .start = ATA_BASE_ADDR, - .end = ATA_BASE_ADDR + 0x000000C8, - .flags = IORESOURCE_MEM, - }, - [2] = { /* IRQ */ - .start = MXC_INT_ATA, - .end = MXC_INT_ATA, - .flags = IORESOURCE_IRQ, - }, + { + .start = ATA_BASE_ADDR, + .end = ATA_BASE_ADDR + 0x000000C8, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_ATA, + .end = MXC_INT_ATA, + .flags = IORESOURCE_IRQ, + }, }; static struct platform_device pata_fsl_device = { diff --git a/arch/arm/mach-mx35/usb_dr.c b/arch/arm/mach-mx35/usb_dr.c index 18f76b90907a..4ebb27c5342b 100644 --- a/arch/arm/mach-mx35/usb_dr.c +++ b/arch/arm/mach-mx35/usb_dr.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -37,7 +37,7 @@ static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = { /* - * resources + * OTG resources */ static struct resource otg_resources[] = { [0] = { @@ -51,6 +51,20 @@ static struct resource otg_resources[] = { }, }; +/* + * UDC resources (same as OTG resource) + */ +static struct resource udc_resources[] = { + [0] = { + .start = (u32)(USB_OTGREGS_BASE), + .end = (u32)(USB_OTGREGS_BASE + 0x1ff), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_USBOTG, + .flags = IORESOURCE_IRQ, + }, +}; static u64 dr_udc_dmamask = ~(u32) 0; static void dr_udc_release(struct device *dev) @@ -74,8 +88,8 @@ static struct platform_device __maybe_unused dr_udc_device = { .dma_mask = &dr_udc_dmamask, .coherent_dma_mask = 0xffffffff, }, - .resource = otg_resources, - .num_resources = ARRAY_SIZE(otg_resources), + .resource = udc_resources, + .num_resources = ARRAY_SIZE(udc_resources), }; static struct platform_device __maybe_unused dr_otg_device = { diff --git a/arch/arm/mach-mx37/cpu.c b/arch/arm/mach-mx37/cpu.c index 3729ac11ca80..3832473f781e 100644 --- a/arch/arm/mach-mx37/cpu.c +++ b/arch/arm/mach-mx37/cpu.c @@ -25,6 +25,7 @@ #include <asm/hardware/cache-l2x0.h> void __iomem *gpc_base; +void __iomem *ccm_base; /*! * CPU initialization. It is called by fixup_mxc_board() @@ -73,6 +74,7 @@ static int __init post_cpu_init(void) iram_init(IRAM_BASE_ADDR, iram_size); gpc_base = ioremap(GPC_BASE_ADDR, SZ_4K); + ccm_base = ioremap(CCM_BASE_ADDR, SZ_4K); /* Set ALP bits to 000. Set ALP_EN bit in Arm Memory Controller reg. */ reg = __raw_readl(MXC_ARM1176_BASE + 0x1C); diff --git a/arch/arm/mach-mx37/crm_regs.h b/arch/arm/mach-mx37/crm_regs.h index a03bc4e103f5..bfb9bff13d46 100644 --- a/arch/arm/mach-mx37/crm_regs.h +++ b/arch/arm/mach-mx37/crm_regs.h @@ -1,5 +1,5 @@ /* - * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -10,6 +10,7 @@ * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html */ + #ifndef __ARCH_ARM_MACH_MX37_CRM_REGS_H__ #define __ARCH_ARM_MACH_MX37_CRM_REGS_H__ @@ -501,6 +502,11 @@ #define MXC_CCM_CCGR5_CG1_OFFSET 2 #define MXC_CCM_CCGR5_CG0_OFFSET 0 +/* CCM Register Offsets. */ +#define MXC_CCM_CDCR_OFFSET 0x6C +#define MXC_CCM_CACRR_OFFSET 0x10 +#define MXC_CCM_CDHIPR_OFFSET 0x68 + #define MXC_ARM1176_BASE IO_ADDRESS(ARM1176_BASE_ADDR) #define MXC_GPC_BASE IO_ADDRESS(GPC_BASE_ADDR) #define MXC_DPTC_LP_BASE IO_ADDRESS(GPC_BASE_ADDR + 0x80) @@ -529,6 +535,11 @@ #define MXC_GPC_PGR (MXC_GPC_BASE + 0x4) #define MXC_GPC_VCR (MXC_GPC_BASE + 0x8) +/*GPC OFFSETS */ +#define MXC_GPC_CNTR_OFFSET 0x0 +#define MXC_GPC_PGR_OFFSET 0x4 +#define MXC_GPC_VCR_OFFSET 0x8 + /* DVFS CORE */ #define MXC_DVFSTHRS (MXC_DVFS_CORE_BASE + 0x00) #define MXC_DVFSCOUN (MXC_DVFS_CORE_BASE + 0x04) @@ -548,21 +559,13 @@ #define MXC_DVFSPT2 (MXC_DVFS_CORE_BASE + 0x3C) #define MXC_DVFSPT3 (MXC_DVFS_CORE_BASE + 0x40) -/* DPTC GP */ -#define MXC_GP_DPTCCR (MXC_DPTC_GP_BASE + 0x00) -#define MXC_GP_DPTCDBG (MXC_DPTC_GP_BASE + 0x04) -#define MXC_GP_DCVR0 (MXC_DPTC_GP_BASE + 0x08) -#define MXC_GP_DCVR1 (MXC_DPTC_GP_BASE + 0x0C) -#define MXC_GP_DCVR2 (MXC_DPTC_GP_BASE + 0x10) -#define MXC_GP_DCVR3 (MXC_DPTC_GP_BASE + 0x14) - -/* DPTC LP */ -#define MXC_LP_DPTCCR (MXC_DPTC_LP_BASE + 0x00) -#define MXC_LP_DPTCDBG (MXC_DPTC_LP_BASE + 0x04) -#define MXC_LP_DCVR0 (MXC_DPTC_LP_BASE + 0x08) -#define MXC_LP_DCVR1 (MXC_DPTC_LP_BASE + 0x0C) -#define MXC_LP_DCVR2 (MXC_DPTC_LP_BASE + 0x10) -#define MXC_LP_DCVR3 (MXC_DPTC_LP_BASE + 0x14) +/* DPTC register offset */ +#define MXC_DPTCCR 0x00 +#define MXC_DPTCDBG 0x04 +#define MXC_DCVR0 0x08 +#define MXC_DCVR1 0x0C +#define MXC_DCVR2 0x10 +#define MXC_DCVR3 0x14 #define MXC_DPTCCR_DRCE3 0x00400000 #define MXC_DPTCCR_DRCE2 0x00200000 diff --git a/arch/arm/mach-mx37/devices.c b/arch/arm/mach-mx37/devices.c index e346899cb2cf..ce1f33112396 100644 --- a/arch/arm/mach-mx37/devices.c +++ b/arch/arm/mach-mx37/devices.c @@ -645,8 +645,8 @@ void __init mxc_init_tve(void) */ static struct resource dvfs_core_resources[] = { [0] = { - .start = MXC_DVFS_CORE_BASE, - .end = MXC_DVFS_CORE_BASE + 4 * SZ_16 - 1, + .start = DVFSCORE_BASE_ADDR, + .end = DVFSCORE_BASE_ADDR + 4 * SZ_16 - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -661,15 +661,11 @@ struct mxc_dvfs_platform_data dvfs_core_data = { .reg_id = "SW1", .clk1_id = "cpu_clk", .clk2_id = "gpc_dvfs_clk", - .gpc_cntr_reg_addr = MXC_GPC_CNTR, - .gpc_vcr_reg_addr = MXC_GPC_VCR, - .ccm_cdcr_reg_addr = MXC_CCM_CDCR, - .ccm_cacrr_reg_addr = MXC_CCM_CACRR, - .ccm_cdhipr_reg_addr = MXC_CCM_CDHIPR, - .dvfs_thrs_reg_addr = MXC_DVFSTHRS, - .dvfs_coun_reg_addr = MXC_DVFSCOUN, - .dvfs_emac_reg_addr = MXC_DVFSEMAC, - .dvfs_cntr_reg_addr = MXC_DVFSCNTR, + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, .prediv_mask = 0x3800, .prediv_offset = 11, .prediv_val = 1, @@ -710,8 +706,8 @@ static inline void mxc_init_dvfs_core(void) */ static struct resource dptc_gp_resources[] = { [0] = { - .start = MXC_DPTC_GP_BASE, - .end = MXC_DPTC_GP_BASE + 8 * SZ_16 - 1, + .start = DPTCGP_BASE_ADDR, + .end = DPTCGP_BASE_ADDR + 8 * SZ_16 - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -725,8 +721,8 @@ static struct resource dptc_gp_resources[] = { struct mxc_dptc_data dptc_gp_data = { .reg_id = "SW1", .clk_id = "cpu_clk", - .dptccr_reg_addr = MXC_GP_DPTCCR, - .dcvr0_reg_addr = MXC_GP_DCVR0, + .dptccr_reg_addr = MXC_DPTCCR, + .dcvr0_reg_addr = MXC_DCVR0, .gpc_cntr_reg_addr = MXC_GPC_CNTR, .dptccr = MXC_GPCCNTR_DPTC0CR, .dptc_wp_supported = DPTC_GP_WP_SUPPORTED, @@ -754,8 +750,8 @@ struct mxc_dptc_data dptc_gp_data = { */ static struct resource dptc_lp_resources[] = { [0] = { - .start = MXC_DPTC_LP_BASE, - .end = MXC_DPTC_LP_BASE + 8 * SZ_16 - 1, + .start = DPTCLP_BASE_ADDR, + .end = DPTCLP_BASE_ADDR + 8 * SZ_16 - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -769,8 +765,8 @@ static struct resource dptc_lp_resources[] = { struct mxc_dptc_data dptc_lp_data = { .reg_id = "SW2", .clk_id = "ahb_clk", - .dptccr_reg_addr = MXC_LP_DPTCCR, - .dcvr0_reg_addr = MXC_LP_DCVR0, + .dptccr_reg_addr = MXC_DPTCCR, + .dcvr0_reg_addr = MXC_DCVR0, .gpc_cntr_reg_addr = MXC_GPC_CNTR, .dptccr = MXC_GPCCNTR_DPTC1CR, .dptc_wp_supported = DPTC_LP_WP_SUPPORTED, @@ -1172,6 +1168,22 @@ static inline void mxc_init_ssi(void) } #endif /* CONFIG_SND_MXC_SOC_SSI */ +static struct platform_device mxc_v4l2_device = { + .name = "mxc_v4l2_capture", + .id = 0, +}; + +static struct platform_device mxc_v4l2out_device = { + .name = "mxc_v4l2_output", + .id = 0, +}; + +static inline void mxc_init_v4l2() +{ + platform_device_register(&mxc_v4l2_device); + platform_device_register(&mxc_v4l2out_device); +} + int __init mxc_init_devices(void) { mxc_init_wdt(); @@ -1193,6 +1205,7 @@ int __init mxc_init_devices(void) mxc_init_rngc(); mxc_init_iim(); mxc_init_ssi(); + mxc_init_v4l2(); return 0; } diff --git a/arch/arm/mach-mx37/mx37_3stack.c b/arch/arm/mach-mx37/mx37_3stack.c index 2a5200031af5..26be2f49d316 100644 --- a/arch/arm/mach-mx37/mx37_3stack.c +++ b/arch/arm/mach-mx37/mx37_3stack.c @@ -206,6 +206,26 @@ static struct mtd_partition mxc_nand_partitions[] = { .size = MTDPART_SIZ_FULL}, }; +static struct resource mxc_nand_resources[] = { + { + .flags = IORESOURCE_MEM, + .name = "NFC_AXI_BASE", + .start = NFC_BASE_ADDR_AXI, + .end = NFC_BASE_ADDR_AXI + SZ_8K - 1, + }, + { + .flags = IORESOURCE_MEM, + .name = "NFC_IP_BASE", + .start = NFC_BASE_ADDR + 0x00, + .end = NFC_BASE_ADDR + 0x34 - 1, + }, + { + .flags = IORESOURCE_IRQ, + .start = MXC_INT_EMI, + .end = MXC_INT_EMI, + }, +}; + static struct flash_platform_data mxc_nand_data = { .parts = mxc_nand_partitions, .nr_parts = ARRAY_SIZE(mxc_nand_partitions), @@ -219,6 +239,9 @@ static struct platform_device mxc_nandv2_mtd_device = { .release = mxc_nop_release, .platform_data = &mxc_nand_data, }, + .resource = mxc_nand_resources, + .num_resources = ARRAY_SIZE(mxc_nand_resources), + }; static void mxc_init_nand_mtd(void) @@ -425,6 +448,7 @@ static void mxc_init_fb(void) printk(KERN_INFO "TV is primary display\n"); fb_data.interface_pix_fmt = IPU_PIX_FMT_YUV444; fb_data.mode = &tv_mode; + fb_data.num_modes = 1; mxc_fb_device[1].dev.platform_data = &fb_data; (void)platform_device_register(&mxc_fb_device[1]); (void)platform_device_register(&mxc_fb_device[0]); @@ -525,16 +549,16 @@ static struct fsl_ata_platform_data ata_data = { }; static struct resource pata_fsl_resources[] = { - [0] = { /* I/O */ - .start = ATA_BASE_ADDR, - .end = ATA_BASE_ADDR + 0x000000C8, - .flags = IORESOURCE_MEM, - }, - [2] = { /* IRQ */ - .start = MXC_INT_ATA, - .end = MXC_INT_ATA, - .flags = IORESOURCE_IRQ, - }, + { + .start = ATA_BASE_ADDR, + .end = ATA_BASE_ADDR + 0x000000C8, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_ATA, + .end = MXC_INT_ATA, + .flags = IORESOURCE_IRQ, + }, }; static struct platform_device pata_fsl_device = { diff --git a/arch/arm/mach-mx37/usb_dr.c b/arch/arm/mach-mx37/usb_dr.c index c8cbed1cc2d4..eb7fc463526c 100644 --- a/arch/arm/mach-mx37/usb_dr.c +++ b/arch/arm/mach-mx37/usb_dr.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -43,7 +43,7 @@ static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = { /* - * resources + * OTG resources */ static struct resource otg_resources[] = { [0] = { @@ -57,7 +57,20 @@ static struct resource otg_resources[] = { }, }; - +/* + * UDC resources (same as OTG resource) + */ +static struct resource udc_resources[] = { + [0] = { + .start = (u32)(OTG_BASE_ADDR), + .end = (u32)(OTG_BASE_ADDR + 0x620), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_USB_OTG, + .flags = IORESOURCE_IRQ, + }, +}; static u64 dr_udc_dmamask = ~(u32) 0; static void dr_udc_release(struct device *dev) { @@ -75,8 +88,8 @@ static struct platform_device dr_udc_device = { .dma_mask = &dr_udc_dmamask, .coherent_dma_mask = 0xffffffff, }, - .resource = otg_resources, - .num_resources = ARRAY_SIZE(otg_resources), + .resource = udc_resources, + .num_resources = ARRAY_SIZE(udc_resources), }; static u64 dr_otg_dmamask = ~(u32) 0; diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig index 5dd3e0fa0b99..7152e3c0f34f 100644 --- a/arch/arm/mach-mx5/Kconfig +++ b/arch/arm/mach-mx5/Kconfig @@ -2,10 +2,15 @@ if ARCH_MX5 config ARCH_MX51 bool "MX51" + select ARCH_MXC_IOMUX_V3 config ARCH_MX53 bool "MX53" +config ARCH_MX50 + bool + select ARCH_HAS_RNGC + config FORCE_MAX_ZONEORDER int "MAX_ORDER" default "13" @@ -21,7 +26,8 @@ config MX5_MULTI_ARCH bool default y select RUNTIME_PHYS_OFFSET - depends on ARCH_MX51 && ARCH_MX53 + depends on ARCH_MX51 + depends on ARCH_MX50 || ARCH_MX53 config MACH_MX51_3DS bool "Support MX51 3-Stack platform" @@ -44,12 +50,31 @@ config MACH_MX53_EVK Include support for MX53 EVK platform. This includes specific configurations for the board and its peripherals. +config MACH_MX50_ARM2 + bool "Support MX50 Armadillo2 platform" + select ARCH_MX50 + help + Include support for MX50 EVK platform. This includes specific + configurations for the board and its peripherals. + + config MODULE_CCXMX51 bool +config LATE_CPU_CLK_ENABLE + bool + +config MACH_MX50_RDP + bool "Support MX50 Reference Design Platform" + select ARCH_MX50 + help + Include support for MX50 RDP platform. This includes specific + configurations for the board and its peripherals. + config MACH_CCWMX51JS bool "Support for the ConnectCore Wi-i.MX51 module, on the JSK base board" select MODULE_CCXMX51 + select LATE_CPU_CLK_ENABLE help Include support for the Digi ConnectCore Wi-i.MX51 Embedded Module, on the JumpStart Kit base board. This includes specific configurations for the @@ -58,11 +83,64 @@ config MACH_CCWMX51JS config MACH_CCWMX51 bool "Support for the ConnectCore Wi-i.MX51 module" select MODULE_CCXMX51 + select LATE_CPU_CLK_ENABLE help Include support for the Digi ConnectCore Wi-i.MX51 Embedded Module, on a custom board. The machine file should be modified to include support for the interfaces available in that board. +config MACH_CCMX51JS + bool "Support for the ConnectCore i.MX51 module, on the JSK base board" + select MODULE_CCXMX51 + select LATE_CPU_CLK_ENABLE + help + Include support for the Digi ConnectCore i.MX51 Embedded Module, on the + JumpStart Kit base board. This includes specific configurations for the + peripherals on that base board. + +config MACH_CCMX51 + bool "Support for the ConnectCore i.MX51 module" + select MODULE_CCXMX51 + select LATE_CPU_CLK_ENABLE + help + Include support for the Digi ConnectCore i.MX51 Embedded Module, on a + custom board. The machine file should be modified to include support for + the interfaces available in that board. + +choice + prompt "Select development board variant:" + default JSCCWMX51_V2 + +config JSCCWMX51_V1 + bool "ConnectCore for i.MX51 Early Availability Development Board" + depends on MODULE_CCXMX51 + select CCWMX51_DISP0_RGB888 if CCWMX51_DISP0 + help + Select this option if you are using the development board included in + the Early Availability (EA) kit. The Digi part number for this board + revision is 30011032-01. It is printed on the top side of the + development board, close to the connectors of Signal Rail 1. + +config JSCCWMX51_V2 + bool "ConnectCore for i.MX51 JumpStart Kit Development Board" + depends on MODULE_CCXMX51 + select CCWMX51_DISP0_RGB666 if CCWMX51_DISP0 + help + Select this option if you are using the development board included in + Digi JumpStart Kit. The Digi part number for this board revision is + 30011032-03. It is printed on the top side of the development board, + close to the connectors of Signal Rail 1. + +config JSCCWMX51_CUSTOM + bool "Custom ConnectCore for i.MX51 Carrier Board" + depends on MODULE_CCXMX51 + help + Select this option if you are using your own custom-designed carrier + board. + +endchoice + + comment "MX5x Options:" config MXC_SDMA_API @@ -72,6 +150,9 @@ config MXC_SDMA_API This selects the Freescale MXC SDMA API. If unsure, say N. +config MXC_NAND_SWAP_BI + bool + config ARCH_MXC_HAS_NFC_V3 bool "MXC NFC Hardware Version 3" depends on ARCH_MX5 @@ -83,9 +164,10 @@ config ARCH_MXC_HAS_NFC_V3 config ARCH_MXC_HAS_NFC_V3_2 bool "MXC NFC Hardware Version 3.2" depends on ARCH_MXC_HAS_NFC_V3 + select MXC_NAND_SWAP_BI if MODULE_CCXMX51 default y help - This selects the Freescale MXC Nand Flash Controller Hardware Version 3.1 + This selects the Freescale MXC Nand Flash Controller Hardware Version 3.2 If unsure, say N. config SDMA_IRAM @@ -100,50 +182,112 @@ menu "Serial Port Options" config UART1_ENABLED bool "Enable UART1" default y - depends on SERIAL_MXC && MACH_CCWMX51JS + depends on SERIAL_MXC && MODULE_CCXMX51 help Enable the MX51 UART1 interface +choice + prompt "Select the configuration for the UART lines:" + default UART1_2WIRE_ENABLED + depends on UART1_ENABLED + +config UART1_2WIRE_ENABLED + bool "Configure UART1 as 2 wire UART (RX/TX)" + +config UART1_CTS_RTS_ENABLED + bool "Configure UART1 as 4 wire UART (RX/TX/RTS/CTS)" + +config UART1_FULL_UART_ENABLED + bool "Configure UART1 as full UART (RX/TX/RTS/CTS/DCD/DTR/DSR/RI)" +endchoice + +config UART1_IRDA_ENABLED + bool "Enable IRDA mode" + default n + depends on UART1_ENABLED + help + Enable IRDA mode + config UART2_ENABLED bool "Enable UART2" default y - depends on SERIAL_MXC && MACH_CCWMX51JS + depends on SERIAL_MXC && MODULE_CCXMX51 help Enable the MX51 UART2 interface +config UART2_CTS_RTS_ENABLED + bool "Configure RTS/CTS lines for UART2 hardware flow control" + default n + depends on UART2_ENABLED + depends on !USB_EHCI_ARC_H1 + help + Configure the UART2 RTS/CTS lines for hardware flow control operation + +comment "UART2 CTS/RTS is not available on the ConnectCore Wi-i.MX51 JumpStart board if" + depends on USB_EHCI_ARC_H1 +comment "the support for Host1 of the Freescale USB controller is enabled." + depends on USB_EHCI_ARC_H1 + +config UART2_IRDA_ENABLED + bool "Enable IRDA mode" + default n + depends on UART2_ENABLED + help + Enable IRDA mode + +comment "UART3 is not available on the ConnectCore Wi-i.MX51 JumpStart board if UART1" + depends on UART1_FULL_UART_ENABLED +comment "is configured as full UART. This may not be the case in a custom base board." + depends on UART1_FULL_UART_ENABLED + config UART3_ENABLED bool "Enable UART3" default y - depends on SERIAL_MXC && MACH_CCWMX51JS + depends on SERIAL_MXC && MODULE_CCXMX51 && !UART1_FULL_UART_ENABLED help Enable the MX51 UART3 interface + +config UART3_CTS_RTS_ENABLED + bool "Configure RTS/CTS lines for UART3 hardware flow control" + default n + depends on UART3_ENABLED + help + Configure the UART3 RTS/CTS lines for hardware flow control operation + +config UART3_IRDA_ENABLED + bool "Enable IRDA mode" + default n + depends on UART3_ENABLED + help + Enable IRDA mode + endmenu menu "SPI Interface Options" config SPI_MXC_SELECT1 bool "Enable CSPI1" - depends on SPI_MXC && MACH_CCWMX51JS + depends on SPI_MXC && MODULE_CCXMX51 default y help Enable the CSPI1 interface config SPI_MXC_SELECT1_SS1 bool "Enable SS1 line for CSPI1" - depends on SPI_MXC_SELECT1 && MACH_CCWMX51JS + depends on SPI_MXC_SELECT1 && MODULE_CCXMX51 default y help Enable SS1 (slave select 1) line, used on ConnectCore Wi-i.MX51 base board SPI connector config SPI_MXC_SELECT2 bool "Enable CSPI2" - depends on SPI_MXC && MACH_CCWMX51JS + depends on SPI_MXC && MODULE_CCXMX51 default n help Enable the CSPI2 interface config SPI_MXC_SELECT3 bool "Enable CSPI3" - depends on SPI_MXC && MACH_CCWMX51JS + depends on SPI_MXC && MODULE_CCXMX51 default n help Enable the CSPI3 interface @@ -155,6 +299,7 @@ config I2C_MXC_SELECT1 bool "Enable I2C1 module" default y depends on I2C_MXC + depends on !MACH_CCWMX51JS help Enable MX51 I2C1 module. @@ -174,4 +319,106 @@ config I2C_MXC_SELECT3 endmenu -source "arch/arm/mach-mx5/displays/Kconfig"
\ No newline at end of file +menu "SD/MMC Interface options" + +config ESDHCI_MXC_SELECT1 + bool "Enable SDHC 1" + default y + depends on MMC_IMX_ESDHCI + help + Enable the SD Host Controller 1. + +config ESDHCI_MXC_SELECT3 + bool "Enable SDHC 3" + default y + depends on MMC_IMX_ESDHCI + help + Enable the SD Host Controller 3. + +endmenu + +if !FB_MXC_SYNC_PANEL +comment "---Video interface disabled" +endif + +if FB_MXC_SYNC_PANEL +menu "Video Interface(s)" + +choice + prompt "Video color depth" + default CCWMX51_DEFAULT_VIDEO_32BPP + depends on MODULE_CCXMX51 + +config CCWMX51_DEFAULT_VIDEO_32BPP + bool "32 bits per pixel" + +config CCWMX51_DEFAULT_VIDEO_16BPP + bool "16 bits per pixel" +endchoice + +config CCWMX51_DEFAULT_VIDEO_BPP + int + depends on MODULE_CCXMX51 + default 32 if CCWMX51_DEFAULT_VIDEO_32BPP + default 16 if CCWMX51_DEFAULT_VIDEO_16BPP + +config CCWMX51_DISP0 + bool "Enable Display Interface 1 (primary)" + help + This enables the i.MX51 Display Interface 1. + +if CCWMX51_DISP0 +choice + prompt "Display 1 color mode" + +config CCWMX51_DISP0_RGB888 + bool "24bit color mode" + depends on JSCCWMX51_V1 + help + Configure Display 1 in 24bit color mode. + + WARNING: The JumpStart Kit Development Board (30011032-02) is designed + to work in 18bit mode. To work in 24bit mode you need an Early Availability + Kit Development Board (30011032-01) or a custom designed board that + populates all 24 data lines of the video interface. + + IMPORTANT: If Display 1 is configured for 24bit color depth, Display 2 + will not be available. + +config CCWMX51_DISP0_RGB666 + bool "18bit color mode" + depends on JSCCWMX51_V2 + help + Configure Display 1 in 18bit color mode. Use this mode if working + on a JumpStart Kit Development Board. + + WARNING: The Early Availability Development Board (30011032-01) is + designed to work in 24bit mode. To work in 18bit mode you need a + JumpStart Kit Development Board (30011032-02) or a custom designed + board that only populates 18 data lines of the video interface. + +endchoice +endif + +comment "To enable the Display 2 Video interface, disable the FEC (under network drivers)" + depends on FEC || CCWMX51_DISP0_RGB888 +comment "and set 18bit color mode for the Display 1" + depends on FEC || CCWMX51_DISP0_RGB888 + +config CCWMX51_DISP1 + bool "Enable Display Interface 2 (secondary)" + depends on !FEC && !CCWMX51_DISP0_RGB888 + help + This enables the i.MX51 Display Interface 2 (18bit color mode only). + +config CCWMX51_SECOND_TOUCH + bool "Enable support for external touch controller (ADS7843)" + depends on SPI_MXC_SELECT1 + select TOUCHSCREEN_ADS7846 + help + This enables the support for the external touch interface (ADS7843) available on the + High Resolution Display board, connected to the processor through SPI and that can be + used with the secondary display (but also with the primary) + +endmenu +endif diff --git a/arch/arm/mach-mx5/Makefile b/arch/arm/mach-mx5/Makefile index 683ba5a78dc2..90baa14638fe 100644 --- a/arch/arm/mach-mx5/Makefile +++ b/arch/arm/mach-mx5/Makefile @@ -4,12 +4,21 @@ # Object file lists. +obj-y := system.o iomux.o cpu.o mm.o devices.o serial.o dma.o lpmodes.o pm.o \ +sdram_autogating.o bus_freq.o usb_dr.o usb_h1.o usb_h2.o dummy_gpio.o early_setup.o -obj-y := system.o iomux.o cpu.o mm.o clock.o devices.o serial.o dma.o lpmodes.o pm.o \ -sdram_autogating.o bus_freq.o usb_dr.o usb_h1.o usb_h2.o dummy_gpio.o wfi.o suspend.o +-obj-$(CONFIG_ARCH_MX51) += clock.o +-obj-$(CONFIG_ARCH_MX53) += clock.o +-obj-$(CONFIG_ARCH_MX50) += clock_mx50.o +obj-$(CONFIG_ARCH_MX51) += clock.o suspend.o +obj-$(CONFIG_ARCH_MX53) += clock.o suspend.o +obj-$(CONFIG_ARCH_MX50) += clock_mx50.o dmaengine.o dma-apbh.o mx50_suspend.o mx50_ddr_freq.o mx50_wfi.o obj-$(CONFIG_MACH_MX51_3DS) += mx51_3stack.o mx51_3stack_gpio.o mx51_3stack_pmic_mc13892.o -obj-$(CONFIG_MACH_MX51_BABBAGE) += mx51_babbage.o mx51_babbage_gpio.o mx51_babbage_pmic_mc13892.o -obj-$(CONFIG_MACH_MX53_EVK) += mx53_evk.o mx53_evk_gpio.o mx53_evk_pmic_mc13892.o +obj-$(CONFIG_MACH_MX51_BABBAGE) += mx51_babbage.o mx51_babbage_pmic_mc13892.o +obj-$(CONFIG_MACH_MX53_EVK) += mx53_evk.o mx53_evk_pmic_mc13892.o +obj-$(CONFIG_MACH_MX50_ARM2) += mx50_arm2.o mx50_arm2_pmic_mc13892.o obj-$(CONFIG_MACH_CCWMX51JS) += devices_ccwmx51.o mx51_ccwmx51js.o mx51_ccwmx51js_gpio.o +obj-$(CONFIG_MACH_CCMX51JS) += devices_ccwmx51.o mx51_ccwmx51js.o mx51_ccwmx51js_gpio.o obj-$(CONFIG_MXC_PMIC_MC13892) += mx51_ccwmx51js_pmic_mc13892.o +obj-$(CONFIG_MACH_MX50_RDP) += mx50_rdp.o mx50_rdp_pmic_mc13892.o diff --git a/arch/arm/mach-mx5/Makefile.boot b/arch/arm/mach-mx5/Makefile.boot index 741f60437582..434ef85a32dc 100644 --- a/arch/arm/mach-mx5/Makefile.boot +++ b/arch/arm/mach-mx5/Makefile.boot @@ -4,3 +4,6 @@ initrd_phys-$(CONFIG_ARCH_MX51) := 0x90800000 zreladdr-$(CONFIG_ARCH_MX53) := 0x70008000 params_phys-$(CONFIG_ARCH_MX53) := 0x70000100 initrd_phys-$(CONFIG_ARCH_MX53) := 0x70800000 + zreladdr-$(CONFIG_ARCH_MX50) := 0x70008000 +params_phys-$(CONFIG_ARCH_MX50) := 0x70000100 +initrd_phys-$(CONFIG_ARCH_MX50) := 0x70800000 diff --git a/arch/arm/mach-mx5/board-ccwmx51.h b/arch/arm/mach-mx5/board-ccwmx51.h index 6696c27c5c36..54376d190e82 100644 --- a/arch/arm/mach-mx5/board-ccwmx51.h +++ b/arch/arm/mach-mx5/board-ccwmx51.h @@ -20,8 +20,14 @@ #else #define UART1_ENABLED 0 #endif -#define UART1_MODE MODE_DCE +#if defined CONFIG_UART1_IRDA_ENABLED +#define UART1_IR IRDA +#else #define UART1_IR NO_IRDA +#endif +#define UART1_MODE MODE_DCE +#define UART1_DMA_ENABLED 0 + /* UART 2 configuration */ #if defined CONFIG_UART2_ENABLED @@ -29,8 +35,13 @@ #else #define UART2_ENABLED 0 #endif -#define UART2_MODE MODE_DCE +#if defined CONFIG_UART2_IRDA_ENABLED +#define UART2_IR IRDA +#else #define UART2_IR NO_IRDA +#endif +#define UART2_MODE MODE_DCE +#define UART2_DMA_ENABLED 0 /* UART 3 configuration */ #if defined CONFIG_UART3_ENABLED @@ -38,19 +49,71 @@ #else #define UART3_ENABLED 0 #endif -#define UART3_MODE MODE_DCE +#if defined CONFIG_UART3_IRDA_ENABLED +#define UART3_IR IRDA +#else #define UART3_IR NO_IRDA +#endif +#define UART3_MODE MODE_DCE +#define UART3_DMA_ENABLED 0 /*! * Specifies if the Irda transmit path is inverting */ #define MXC_IRDA_TX_INV 0 -/*! - * Specifies if the Irda receive path is inverting - */ -#define MXC_IRDA_RX_INV 0 #define MXC_LL_UART_PADDR UART1_BASE_ADDR #define MXC_LL_UART_VADDR AIPS1_IO_ADDRESS(UART1_BASE_ADDR) +/* Second touch interface configuration */ +#ifdef CONFIG_CCWMX51_SECOND_TOUCH +#ifdef CONFIG_JSCCWMX51_V1 +/* Settings for the JSCCWMX51 Board RevA, for the DISP0 */ +#elif defined(CONFIG_JSCCWMX51_V2) +/* Settings for the JSCCWMX51 Board RevB, for the DISP0/DISP1 */ +#endif /* CONFIG_JSCCWMX51_VX */ +#endif /* CONFIG_CCWMX51_SECOND_TOUCH */ + +/* AD9389 interrupt */ +#ifdef CONFIG_JSCCWMX51_V1 +#define AD9389_GPIO_IRQ MX51_PIN_GPIO1_4 +#elif defined(CONFIG_JSCCWMX51_V2) +#define AD9389_GPIO_IRQ MX51_PIN_GPIO1_0 +#endif + + +/* Set Base board revision */ +#ifdef CONFIG_JSCCWMX51_V1 +/* Board revision and mach name postfix */ +#define BASE_BOARD_REV 1 +#define BOARD_NAME " on a EAK board" +/* SD1 card detect irq */ +#define CCWMX51_SD1_CD_IRQ IOMUX_TO_IRQ(MX51_PIN_GPIO1_0) +/* Second touch settings */ +#define SECOND_TS_IRQ_PIN MX51_PIN_DI1_D0_CS +#define SECOND_TS_SPI_SS_PIN MX51_PIN_DI1_D1_CS +#elif defined(CONFIG_JSCCWMX51_V2) +/* Board revision */ +#define BASE_BOARD_REV 2 +#define BOARD_NAME " on a JSK board" +/* SD1 card detect irq, not present CD line... */ +#define CCWMX51_SD1_CD_IRQ 0 +/* Second touch settings */ +#define SECOND_TS_IRQ_PIN MX51_PIN_DI1_D0_CS +#define SECOND_TS_SPI_SS_PIN MX51_PIN_CSPI1_RDY +#else +#define BASE_BOARD_REV 0 +#define BOARD_NAME " on an undefined board" +#endif + +/* framebuffer settings */ +#if defined(CONFIG_CCWMX51_DISP1) && defined(CONFIG_CCWMX51_DISP2) +#define FB_MEM_SIZE SZ_32M +#else +#define FB_MEM_SIZE SZ_16M +#endif + +void ccwmx51_2nd_touch_gpio_init(void); +void ccwmx51_init_2nd_touch(void); + #endif /* __ASM_ARCH_MXC_BOARD_CCWMX51_H__ */ diff --git a/arch/arm/mach-mx5/bus_freq.c b/arch/arm/mach-mx5/bus_freq.c index 4ab60ec6386d..ec2addfd977b 100644 --- a/arch/arm/mach-mx5/bus_freq.c +++ b/arch/arm/mach-mx5/bus_freq.c @@ -27,45 +27,56 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> +#include <linux/iram_alloc.h> +#include <linux/mutex.h> #include <mach/hardware.h> #include <mach/clock.h> #include <mach/mxc_dvfs.h> #include <mach/sdram_autogating.h> +#include <asm/mach/map.h> +#include <asm/cacheflush.h> +#include <asm/tlb.h> #include "crm_regs.h" -#define LP_NORMAL_CLK 133000000 -#define LP_MED_CLK 83125000 +#define LP_LOW_VOLTAGE 1050000 +#define LP_NORMAL_VOLTAGE 1250000 #define LP_APM_CLK 24000000 #define NAND_LP_APM_CLK 12000000 -#define DDR_LOW_FREQ_CLK 133000000 -#define DDR_NORMAL_CLK 200000000 #define AXI_A_NORMAL_CLK 166250000 #define AXI_A_CLK_NORMAL_DIV 4 #define AXI_B_CLK_NORMAL_DIV 5 #define AHB_CLK_NORMAL_DIV AXI_B_CLK_NORMAL_DIV #define EMI_SLOW_CLK_NORMAL_DIV AXI_B_CLK_NORMAL_DIV #define NFC_CLK_NORMAL_DIV 4 +#define SPIN_DELAY 1000000 /* in nanoseconds */ + +DEFINE_SPINLOCK(ddr_freq_lock); + +static unsigned long lp_normal_rate; +static unsigned long lp_med_rate; +static unsigned long ddr_normal_rate; +static unsigned long ddr_low_rate; static struct clk *ddr_clk; +static struct clk *pll1_sw_clk; +static struct clk *pll1; static struct clk *pll2; static struct clk *pll3; +static struct clk *pll4; static struct clk *main_bus_clk; static struct clk *axi_a_clk; static struct clk *axi_b_clk; static struct clk *cpu_clk; static struct clk *ddr_hf_clk; -static struct clk *nfc_clk; static struct clk *ahb_clk; -static struct clk *vpu_clk; -static struct clk *vpu_core_clk; -static struct clk *emi_slow_clk; static struct clk *ddr_clk; -static struct clk *ipu_clk; static struct clk *periph_apm_clk; static struct clk *lp_apm; static struct clk *osc; static struct clk *gpc_dvfs_clk; static struct clk *emi_garb_clk; +static void __iomem *pll1_base; +static void __iomem *pll4_base; struct regulator *lp_regulator; int low_bus_freq_mode; @@ -77,14 +88,28 @@ char *lp_reg_id = "SW2"; static struct cpu_wp *cpu_wp_tbl; static struct device *busfreq_dev; static int busfreq_suspended; +static int cpu_podf; /* True if bus_frequency is scaled not using DVFS-PER */ int bus_freq_scaling_is_active; -extern int lp_high_freq; -extern int lp_med_freq; +int cpu_wp_nr; +int lp_high_freq; +int lp_med_freq; + +void enter_lpapm_mode_mx50(void); +void enter_lpapm_mode_mx51(void); +void exit_lpapm_mode_mx50(void); +void exit_lpapm_mode_mx51(void); +void *ddr_freq_change_iram_base; +void (*change_ddr_freq)(void *ccm_addr, void *databahn_addr, u32 freq) = NULL; + +extern void mx50_ddr_freq_change(u32 ccm_base, + u32 databahn_addr, u32 freq); extern int dvfs_core_is_active; extern struct cpu_wp *(*get_cpu_wp)(int *wp); -extern int cpu_wp_nr; +extern void propagate_rate(struct clk *tclk); +extern void __iomem *ccm_base; +extern void __iomem *databahn_base; struct dvfs_wp dvfs_core_setpoint[] = { {33, 8, 33, 10, 10, 0x08}, @@ -92,121 +117,267 @@ struct dvfs_wp dvfs_core_setpoint[] = { {28, 8, 33, 20, 30, 0x08}, {29, 0, 33, 20, 10, 0x08},}; - int set_low_bus_freq(void) { u32 reg; + struct timespec nstimeofday; + struct timespec curtime; if (busfreq_suspended) return 0; if (bus_freq_scaling_initialized) { - if (clk_get_rate(cpu_clk) != cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate) + /* can not enter low bus freq, when cpu is in highest freq */ + if (clk_get_rate(cpu_clk) != + cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate) { return 0; + } stop_dvfs_per(); stop_sdram_autogating(); - /*Change the DDR freq to 133Mhz. */ - clk_set_rate(ddr_hf_clk, - clk_round_rate(ddr_hf_clk, DDR_LOW_FREQ_CLK)); - /* Set PLL3 to 133Mhz if no-one is using it. */ - if (clk_get_usecount(pll3) == 0) { + if ((clk_get_usecount(pll3) == 0) && !cpu_is_mx53()) { u32 pll3_rate = clk_get_rate(pll3); clk_enable(pll3); clk_set_rate(pll3, clk_round_rate(pll3, 133000000)); - /* Set the parent of Periph_apm_clk to be PLL3 */ - clk_set_parent(periph_apm_clk, pll3); - clk_set_parent(main_bus_clk, periph_apm_clk); - - /* Set the AHB dividers to be 1. */ - /* Set the dividers to be 1, so the clock rates - * are at 133MHz. - */ - reg = __raw_readl(MXC_CCM_CBCDR); - reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK - | MXC_CCM_CBCDR_AXI_B_PODF_MASK - | MXC_CCM_CBCDR_AHB_PODF_MASK - | MXC_CCM_CBCDR_EMI_PODF_MASK - | MXC_CCM_CBCDR_NFC_PODF_OFFSET); - reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET - | 0 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET - | 0 << MXC_CCM_CBCDR_AHB_PODF_OFFSET - | 0 << MXC_CCM_CBCDR_EMI_PODF_OFFSET - | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET); - __raw_writel(reg, MXC_CCM_CBCDR); - - clk_enable(emi_garb_clk); - while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F) - udelay(10); - clk_disable(emi_garb_clk); - - /* Set the source of Periph_APM_Clock to be lp-apm. */ - clk_set_parent(periph_apm_clk, lp_apm); + if (cpu_is_mx50()) + enter_lpapm_mode_mx50(); + else + enter_lpapm_mode_mx51(); /* Set PLL3 back to original rate. */ clk_set_rate(pll3, clk_round_rate(pll3, pll3_rate)); clk_disable(pll3); + } else if (cpu_is_mx53()) { + /*Change the DDR freq to 133Mhz. */ + clk_set_rate(ddr_hf_clk, + clk_round_rate(ddr_hf_clk, ddr_low_rate)); + + /* move cpu clk to pll2, 400 / 3 = 133Mhz for cpu */ + clk_set_parent(pll1_sw_clk, pll2); + + cpu_podf = __raw_readl(MXC_CCM_CACRR); + reg = __raw_readl(MXC_CCM_CDHIPR); + if ((reg & MXC_CCM_CDHIPR_ARM_PODF_BUSY) == 0) + __raw_writel(0x2, MXC_CCM_CACRR); + else + printk(KERN_DEBUG "ARM_PODF still in busy!!!!\n"); + + /* ahb = 400/8, axi_b = 400/8, axi_a = 133*/ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK); + reg |= (2 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 7 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 7 << MXC_CCM_CBCDR_AHB_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & + (MXC_CCM_CDHIPR_AXI_A_PODF_BUSY | + MXC_CCM_CDHIPR_AXI_B_PODF_BUSY | + MXC_CCM_CDHIPR_AHB_PODF_BUSY)) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec + > SPIN_DELAY) + panic("low bus freq set rate error\n"); + } + + /* keep this infront of propagating */ low_bus_freq_mode = 1; high_bus_freq_mode = 0; + + propagate_rate(main_bus_clk); + propagate_rate(pll1_sw_clk); + + if (clk_get_usecount(pll1) == 0) { + reg = __raw_readl(pll1_base + MXC_PLL_DP_CTL); + reg &= ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL); + } + if (clk_get_usecount(pll4) == 0) { + reg = __raw_readl(pll4_base + MXC_PLL_DP_CTL); + reg &= ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pll4_base + MXC_PLL_DP_CTL); + } } } return 0; } +void enter_lpapm_mode_mx50() +{ + u32 reg; + unsigned long flags; + + spin_lock_irqsave(&ddr_freq_lock, flags); + + /* Set the parent of main_bus_clk to be PLL3 */ + clk_set_parent(main_bus_clk, pll3); + + /* Set the AHB dividers to be 1. */ + /* Set the dividers to be 1, so the clock rates + * are at 133MHz. + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + | 0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + while (__raw_readl(MXC_CCM_CDHIPR) & 0x0F) + udelay(10); + low_bus_freq_mode = 1; + high_bus_freq_mode = 0; + + /* Set the source of main_bus_clk to be lp-apm. */ + clk_set_parent(main_bus_clk, lp_apm); + + /* Set SYS_CLK to 24MHz. sourced from XTAL*/ + /* Turn on the XTAL_CLK_GATE. */ + reg = __raw_readl(MXC_CCM_CLK_SYS); + reg |= 3 << MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_OFFSET; + __raw_writel(reg, MXC_CCM_CLK_SYS); + + /* Set the divider. */ + reg = __raw_readl(MXC_CCM_CLK_SYS); + reg &= ~MXC_CCM_CLK_SYS_DIV_XTAL_MASK; + reg |= 1 << MXC_CCM_CLK_SYS_DIV_XTAL_OFFSET; + __raw_writel(reg, MXC_CCM_CLK_SYS); + while (__raw_readl(MXC_CCM_CSR2) & 0x1) + udelay(10); + + /* Set the source to be XTAL. */ + reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS); + reg &= ~0x1; + __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS); + while (!(__raw_readl(MXC_CCM_CSR2) & 0x400)) + udelay(10); + + /* Turn OFF the PLL_CLK_GATE. */ + reg = __raw_readl(MXC_CCM_CLK_SYS); + reg &= ~MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_CLK_SYS); + spin_unlock_irqrestore(&ddr_freq_lock, flags); + +} + +void enter_lpapm_mode_mx51() +{ + u32 reg; + + /*Change the DDR freq to 133Mhz. */ + clk_set_rate(ddr_hf_clk, + clk_round_rate(ddr_hf_clk, ddr_low_rate)); + + /* Set the parent of Periph_apm_clk to be PLL3 */ + clk_set_parent(periph_apm_clk, pll3); + clk_set_parent(main_bus_clk, periph_apm_clk); + + /* Set the dividers to be 1, so the clock rates + * are at 133MHz. + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MXC_CCM_CBCDR_EMI_PODF_MASK + | MXC_CCM_CBCDR_NFC_PODF_OFFSET); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_EMI_PODF_OFFSET + | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + clk_enable(emi_garb_clk); + while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F) + udelay(10); + clk_disable(emi_garb_clk); + + /* Set the source of Periph_APM_Clock to be lp-apm. */ + clk_set_parent(periph_apm_clk, lp_apm); +} + int set_high_bus_freq(int high_bus_freq) { u32 reg; + struct timespec nstimeofday; + struct timespec curtime; if (bus_freq_scaling_initialized) { + stop_sdram_autogating(); if (low_bus_freq_mode) { /* Relock PLL3 to 133MHz */ - if (clk_get_usecount(pll3) == 0) { + if ((clk_get_usecount(pll3) == 0) && !cpu_is_mx53()) { u32 pll3_rate = clk_get_rate(pll3); clk_enable(pll3); clk_set_rate(pll3, clk_round_rate(pll3, 133000000)); - clk_set_parent(periph_apm_clk, pll3); - /* Set the dividers to the default dividers */ + if (cpu_is_mx50()) + exit_lpapm_mode_mx50(); + else + exit_lpapm_mode_mx51(); + + /* Relock PLL3 to its original rate */ + clk_set_rate(pll3, + clk_round_rate(pll3, pll3_rate)); + clk_disable(pll3); + } else if (cpu_is_mx53()) { + /* move cpu clk to pll1 */ + reg = __raw_readl(MXC_CCM_CDHIPR); + if ((reg & MXC_CCM_CDHIPR_ARM_PODF_BUSY) == 0) + __raw_writel(cpu_podf & 0x7, + MXC_CCM_CACRR); + else + printk(KERN_DEBUG + "ARM_PODF still in busy!!!!\n"); + + clk_set_parent(pll1_sw_clk, pll1); + + /* ahb = 400/3, axi_b = 400/3, axi_a = 400*/ reg = __raw_readl(MXC_CCM_CBCDR); reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK | MXC_CCM_CBCDR_AXI_B_PODF_MASK - | MXC_CCM_CBCDR_AHB_PODF_MASK - | MXC_CCM_CBCDR_EMI_PODF_MASK - | MXC_CCM_CBCDR_NFC_PODF_OFFSET); - reg |= (3 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET - | 4 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET - | 4 << MXC_CCM_CBCDR_AHB_PODF_OFFSET - | 4 << MXC_CCM_CBCDR_EMI_PODF_OFFSET - | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET); + | MXC_CCM_CBCDR_AHB_PODF_MASK); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 2 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 2 << MXC_CCM_CBCDR_AHB_PODF_OFFSET); __raw_writel(reg, MXC_CCM_CBCDR); - clk_enable(emi_garb_clk); - while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F) - udelay(10); - - low_bus_freq_mode = 0; - high_bus_freq_mode = 1; - clk_disable(emi_garb_clk); - - /*Set the main_bus_clk parent to be PLL2. */ - clk_set_parent(main_bus_clk, pll2); + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & + (MXC_CCM_CDHIPR_AXI_A_PODF_BUSY | + MXC_CCM_CDHIPR_AXI_B_PODF_BUSY | + MXC_CCM_CDHIPR_AHB_PODF_BUSY)) { + getnstimeofday(&curtime); + if (curtime.tv_nsec + - nstimeofday.tv_nsec + > SPIN_DELAY) + panic("bus freq error\n"); + } + + /* keep this infront of propagating */ + low_bus_freq_mode = 1; + high_bus_freq_mode = 0; - /* Relock PLL3 to its original rate */ - clk_set_rate(pll3, - clk_round_rate(pll3, pll3_rate)); - clk_disable(pll3); + propagate_rate(main_bus_clk); + propagate_rate(pll1_sw_clk); + /*Change the DDR freq to mormal_rate*/ + clk_set_rate(ddr_hf_clk, + clk_round_rate(ddr_hf_clk, ddr_normal_rate)); } - - /*Change the DDR freq to 200MHz*/ - clk_set_rate(ddr_hf_clk, - clk_round_rate(ddr_hf_clk, DDR_NORMAL_CLK)); start_dvfs_per(); } if (bus_freq_scaling_is_active) { @@ -218,24 +389,28 @@ int set_high_bus_freq(int high_bus_freq) cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate) high_bus_freq = 1; - if (((clk_get_rate(ahb_clk) == LP_MED_CLK) + if (((clk_get_rate(ahb_clk) == lp_med_rate) && lp_high_freq) || high_bus_freq) { /* Set to the high setpoint. */ high_bus_freq_mode = 1; + clk_set_rate(ahb_clk, - clk_round_rate(ahb_clk, LP_NORMAL_CLK)); + clk_round_rate(ahb_clk, lp_normal_rate)); + clk_set_rate(ddr_hf_clk, - clk_round_rate(ddr_hf_clk, DDR_NORMAL_CLK)); + clk_round_rate(ddr_hf_clk, ddr_normal_rate)); } + if (!lp_high_freq && !high_bus_freq) { /* Set to the medium setpoint. */ high_bus_freq_mode = 0; low_bus_freq_mode = 0; + clk_set_rate(ddr_hf_clk, - clk_round_rate(ddr_hf_clk, - DDR_LOW_FREQ_CLK)); + clk_round_rate(ddr_hf_clk, ddr_low_rate)); + clk_set_rate(ahb_clk, - clk_round_rate(ahb_clk, LP_MED_CLK)); + clk_round_rate(ahb_clk, lp_med_rate)); } } start_sdram_autogating(); @@ -243,11 +418,105 @@ int set_high_bus_freq(int high_bus_freq) return 0; } +void exit_lpapm_mode_mx50() +{ + u32 reg; + unsigned long flags; + + spin_lock_irqsave(&ddr_freq_lock, flags); + + /* Set SYS_CLK to source from PLL1 */ + /* Set sys_clk back to 200MHz. */ + /* Set the divider to 4. */ + reg = __raw_readl(MXC_CCM_CLK_SYS); + reg &= ~MXC_CCM_CLK_SYS_DIV_PLL_MASK; + reg |= 0x4 << MXC_CCM_CLK_SYS_DIV_PLL_OFFSET; + __raw_writel(reg, MXC_CCM_CLK_SYS); + udelay(100); + + /* Turn ON the PLL CLK_GATE. */ + reg = __raw_readl(MXC_CCM_CLK_SYS); + reg |= 3 << MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_OFFSET; + __raw_writel(reg, MXC_CCM_CLK_SYS); + + /* Source the SYS_CLK from PLL */ + reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS); + reg |= 0x3; + __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS); + while (__raw_readl(MXC_CCM_CSR2) & 0x400) + udelay(10); + + /* Turn OFF the XTAL_CLK_GATE. */ + reg = __raw_readl(MXC_CCM_CLK_SYS); + reg &= ~MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_CLK_SYS); + + clk_set_parent(main_bus_clk, pll3); + + /* Set the dividers to the default dividers */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + |1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + |2 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + |0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + while (__raw_readl(MXC_CCM_CDHIPR) & 0xF) + udelay(10); + + low_bus_freq_mode = 0; + high_bus_freq_mode = 1; + + /*Set the main_bus_clk parent to be PLL2. */ + clk_set_parent(main_bus_clk, pll2); + spin_unlock_irqrestore(&ddr_freq_lock, flags); + + udelay(100); +} + +void exit_lpapm_mode_mx51() +{ + u32 reg; + + clk_set_parent(periph_apm_clk, pll3); + + /* Set the dividers to the default dividers */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MXC_CCM_CBCDR_EMI_PODF_MASK + | MXC_CCM_CBCDR_NFC_PODF_OFFSET); + reg |= (3 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 4 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 4 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + | 4 << MXC_CCM_CBCDR_EMI_PODF_OFFSET + | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + clk_enable(emi_garb_clk); + while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F) + udelay(10); + + low_bus_freq_mode = 0; + high_bus_freq_mode = 1; + clk_disable(emi_garb_clk); + + /*Set the main_bus_clk parent to be PLL2. */ + clk_set_parent(main_bus_clk, pll2); + + /*Change the DDR freq to 200MHz*/ + clk_set_rate(ddr_hf_clk, + clk_round_rate(ddr_hf_clk, ddr_normal_rate)); +} + int low_freq_bus_used(void) { - if ((clk_get_usecount(ipu_clk) == 0) - && (clk_get_usecount(vpu_clk) == 0) - && (lp_high_freq == 0) + if ((lp_high_freq == 0) && (lp_med_freq == 0)) return 1; else @@ -273,8 +542,7 @@ static ssize_t bus_freq_scaling_enable_store(struct device *dev, { u32 reg; - - if (strstr(buf, "1") != NULL) { + if (strncmp(buf, "1", 1) == 0) { if (dvfs_per_active()) { printk(KERN_INFO "bus frequency scaling cannot be\ enabled when DVFS-PER is active\n"); @@ -288,12 +556,13 @@ static ssize_t bus_freq_scaling_enable_store(struct device *dev, clk_set_parent(main_bus_clk, pll2); bus_freq_scaling_is_active = 1; - } - else if (strstr(buf, "0") != NULL) { + set_high_bus_freq(0); + } else if (strncmp(buf, "0", 1) == 0) { if (bus_freq_scaling_is_active) set_high_bus_freq(1); bus_freq_scaling_is_active = 0; } + return size; } @@ -325,6 +594,12 @@ static DEVICE_ATTR(enable, 0644, bus_freq_scaling_enable_show, static int __devinit busfreq_probe(struct platform_device *pdev) { int err = 0; + unsigned long pll2_rate, pll1_rate; + unsigned long iram_paddr; + + pll1_base = ioremap(MX53_BASE_ADDR(PLL1_BASE_ADDR), SZ_4K); + if (cpu_is_mx53()) + pll4_base = ioremap(MX53_BASE_ADDR(PLL4_BASE_ADDR), SZ_4K); busfreq_dev = &pdev->dev; @@ -335,6 +610,18 @@ static int __devinit busfreq_probe(struct platform_device *pdev) return PTR_ERR(main_bus_clk); } + pll1_sw_clk = clk_get(NULL, "pll1_sw_clk"); + if (IS_ERR(pll1_sw_clk)) { + printk(KERN_DEBUG "%s: failed to get pll1_sw_clk\n", __func__); + return PTR_ERR(pll1_sw_clk); + } + + pll1 = clk_get(NULL, "pll1_main_clk"); + if (IS_ERR(pll1)) { + printk(KERN_DEBUG "%s: failed to get pll1\n", __func__); + return PTR_ERR(pll1); + } + pll2 = clk_get(NULL, "pll2"); if (IS_ERR(pll2)) { printk(KERN_DEBUG "%s: failed to get pll2\n", __func__); @@ -347,6 +634,14 @@ static int __devinit busfreq_probe(struct platform_device *pdev) return PTR_ERR(pll3); } + if (cpu_is_mx53()) { + pll4 = clk_get(NULL, "pll4"); + if (IS_ERR(pll4)) { + printk(KERN_DEBUG "%s: failed to get pll4\n", __func__); + return PTR_ERR(pll4); + } + } + axi_a_clk = clk_get(NULL, "axi_a_clk"); if (IS_ERR(axi_a_clk)) { printk(KERN_DEBUG "%s: failed to get axi_a_clk\n", @@ -361,25 +656,19 @@ static int __devinit busfreq_probe(struct platform_device *pdev) return PTR_ERR(axi_b_clk); } - ddr_hf_clk = clk_get(NULL, "ddr_hf_clk"); - if (IS_ERR(ddr_hf_clk)) { - printk(KERN_DEBUG "%s: failed to get ddr_hf_clk\n", + ddr_clk = clk_get(NULL, "ddr_clk"); + if (IS_ERR(ddr_clk)) { + printk(KERN_DEBUG "%s: failed to get ddr_clk\n", __func__); - return PTR_ERR(ddr_hf_clk); + return PTR_ERR(ddr_clk); } - emi_slow_clk = clk_get(NULL, "emi_slow_clk"); - if (IS_ERR(emi_slow_clk)) { - printk(KERN_DEBUG "%s: failed to get emi_slow_clk\n", - __func__); - return PTR_ERR(emi_slow_clk); - } + ddr_hf_clk = clk_get_parent(ddr_clk); - nfc_clk = clk_get(NULL, "nfc_clk"); - if (IS_ERR(nfc_clk)) { - printk(KERN_DEBUG "%s: failed to get nfc_clk\n", + if (IS_ERR(ddr_hf_clk)) { + printk(KERN_DEBUG "%s: failed to get ddr_hf_clk\n", __func__); - return PTR_ERR(nfc_clk); + return PTR_ERR(ddr_hf_clk); } ahb_clk = clk_get(NULL, "ahb_clk"); @@ -389,20 +678,6 @@ static int __devinit busfreq_probe(struct platform_device *pdev) return PTR_ERR(ahb_clk); } - vpu_core_clk = clk_get(NULL, "vpu_core_clk"); - if (IS_ERR(vpu_core_clk)) { - printk(KERN_DEBUG "%s: failed to get vpu_core_clk\n", - __func__); - return PTR_ERR(vpu_core_clk); - } - - ddr_clk = clk_get(NULL, "ddr_clk"); - if (IS_ERR(ddr_clk)) { - printk(KERN_DEBUG "%s: failed to get ddr_clk\n", - __func__); - return PTR_ERR(ddr_clk); - } - cpu_clk = clk_get(NULL, "cpu_clk"); if (IS_ERR(cpu_clk)) { printk(KERN_DEBUG "%s: failed to get cpu_clk\n", @@ -410,35 +685,25 @@ static int __devinit busfreq_probe(struct platform_device *pdev) return PTR_ERR(cpu_clk); } - ipu_clk = clk_get(NULL, "ipu_clk"); - if (IS_ERR(ipu_clk)) { - printk(KERN_DEBUG "%s: failed to get ipu_clk\n", - __func__); - return PTR_ERR(ipu_clk); - } - if (cpu_is_mx51()) emi_garb_clk = clk_get(NULL, "emi_garb_clk"); - else + else if (cpu_is_mx53()) emi_garb_clk = clk_get(NULL, "emi_intr_clk.1"); + else + emi_garb_clk = clk_get(NULL, "ocram_clk"); if (IS_ERR(emi_garb_clk)) { printk(KERN_DEBUG "%s: failed to get emi_garb_clk\n", __func__); return PTR_ERR(emi_garb_clk); } - vpu_clk = clk_get(NULL, "vpu_clk"); - if (IS_ERR(vpu_clk)) { - printk(KERN_DEBUG "%s: failed to get vpu_clk\n", - __func__); - return PTR_ERR(vpu_clk); - } - - periph_apm_clk = clk_get(NULL, "periph_apm_clk"); - if (IS_ERR(periph_apm_clk)) { - printk(KERN_DEBUG "%s: failed to get periph_apm_clk\n", - __func__); - return PTR_ERR(periph_apm_clk); + if (cpu_is_mx51() || cpu_is_mx53()) { + periph_apm_clk = clk_get(NULL, "periph_apm_clk"); + if (IS_ERR(periph_apm_clk)) { + printk(KERN_DEBUG "%s: failed to get periph_apm_clk\n", + __func__); + return PTR_ERR(periph_apm_clk); + } } lp_apm = clk_get(NULL, "lp_apm"); @@ -467,6 +732,49 @@ static int __devinit busfreq_probe(struct platform_device *pdev) return err; } + pll1_rate = clk_get_rate(pll1_sw_clk); + pll2_rate = clk_get_rate(pll2); + + if (pll2_rate == 665000000) { + /* for mx51 */ + lp_normal_rate = pll2_rate / 5; + lp_med_rate = pll2_rate / 8; + ddr_normal_rate = pll1_rate / 4; /* 200M */ + ddr_low_rate = pll1_rate / 6; /* 133M */ + } else if (pll2_rate == 600000000) { + /* for mx53 evk rev.A */ + lp_normal_rate = pll2_rate / 5; + lp_med_rate = pll2_rate / 8; + ddr_normal_rate = pll2_rate / 2; + ddr_low_rate = pll2_rate / 2; + } else if (pll2_rate == 400000000) { + /* for mx53 evk rev.B */ + lp_normal_rate = pll2_rate / 3; + lp_med_rate = pll2_rate / 5; + if (cpu_is_mx53()) { + ddr_normal_rate = pll2_rate / 1; + ddr_low_rate = pll2_rate / 3; + } else if (cpu_is_mx50()) { + ddr_normal_rate = clk_get_rate(ddr_clk); + ddr_low_rate = LP_APM_CLK; + } + } + if (cpu_is_mx50()) { + iram_alloc(SZ_8K, &iram_paddr); + /* Need to remap the area here since we want the memory region + to be executable. */ + ddr_freq_change_iram_base = __arm_ioremap(iram_paddr, + SZ_8K, MT_HIGH_VECTORS); + memcpy(ddr_freq_change_iram_base, mx50_ddr_freq_change, SZ_8K); + change_ddr_freq = (void *)ddr_freq_change_iram_base; + + lp_regulator = regulator_get(NULL, "SW2"); + if (IS_ERR(lp_regulator)) { + printk(KERN_DEBUG + "%s: failed to get lp regulator\n", __func__); + return PTR_ERR(lp_regulator); + } + } cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr); low_bus_freq_mode = 0; high_bus_freq_mode = 1; diff --git a/arch/arm/mach-mx5/clock.c b/arch/arm/mach-mx5/clock.c index 7c6f614bf97f..5ec89a6570cd 100644 --- a/arch/arm/mach-mx5/clock.c +++ b/arch/arm/mach-mx5/clock.c @@ -42,6 +42,7 @@ static struct clk emi_slow_clk; static struct clk emi_intr_clk[]; static struct clk ddr_clk; static struct clk ipu_clk[]; +static struct clk ldb_di_clk[]; static struct clk axi_a_clk; static struct clk axi_b_clk; static struct clk ddr_hf_clk; @@ -52,16 +53,26 @@ static struct clk vpu_clk[]; static int cpu_curr_wp; static struct cpu_wp *cpu_wp_tbl; -void __iomem *pll1_base; -void __iomem *pll2_base; -void __iomem *pll3_base; -void __iomem *pll4_base; +static void __iomem *pll1_base; +static void __iomem *pll2_base; +static void __iomem *pll3_base; +static void __iomem *pll4_base; + +extern int cpu_wp_nr; +extern int lp_high_freq; +extern int lp_med_freq; +int max_axi_a_clk; +int max_axi_b_clk; -int cpu_wp_nr; -int lp_high_freq; -int lp_med_freq; #define SPIN_DELAY 1000000 /* in nanoseconds */ +#define MAX_AXI_A_CLK_MX51 166250000 +#define MAX_AXI_A_CLK_MX53 400000000 +#define MAX_AXI_B_CLK_MX51 133000000 +#define MAX_AXI_B_CLK_MX53 200000000 +#define MAX_AHB_CLK 133000000 +#define MAX_EMI_SLOW_CLK 133000000 +#define MAX_DDR_HF_RATE 200000000 extern int mxc_jtag_enabled; extern int uart_at_24; @@ -70,8 +81,8 @@ extern int low_bus_freq_mode; static int cpu_clk_set_wp(int wp); extern void propagate_rate(struct clk *tclk); -struct cpu_wp *(*get_cpu_wp)(int *wp); -void (*set_num_cpu_wp)(int num); +extern struct cpu_wp *(*get_cpu_wp)(int *wp); +extern void (*set_num_cpu_wp)(int num); static struct clk esdhc3_clk[]; @@ -394,7 +405,12 @@ static int _clk_pll_enable(struct clk *clk) struct timespec curtime; pllbase = _get_pll_base(clk); - reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) | MXC_PLL_DP_CTL_UPEN; + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); + + if (reg & MXC_PLL_DP_CTL_UPEN) + return 0; + + reg |= MXC_PLL_DP_CTL_UPEN; __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); /* Wait for lock */ @@ -738,10 +754,18 @@ static unsigned long _clk_axi_a_round_rate(struct clk *clk, u32 div; div = clk->parent->rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (clk->parent->rate / div > max_axi_a_clk) + div++; + if (div > 8) div = 8; - else if (div == 0) - div++; + return clk->parent->rate / div; } @@ -771,10 +795,18 @@ static unsigned long _clk_ddr_hf_round_rate(struct clk *clk, u32 div; div = clk->parent->rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (clk->parent->rate / div > MAX_DDR_HF_RATE) + div++; + if (div > 8) div = 8; - else if (div == 0) - div++; + return clk->parent->rate / div; } @@ -875,10 +907,18 @@ static unsigned long _clk_axi_b_round_rate(struct clk *clk, u32 div; div = clk->parent->rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (clk->parent->rate / div > max_axi_b_clk) + div++; + if (div > 8) div = 8; - else if (div == 0) - div++; + return clk->parent->rate / div; } @@ -945,10 +985,18 @@ static unsigned long _clk_ahb_round_rate(struct clk *clk, u32 div; div = clk->parent->rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (clk->parent->rate / div > MAX_AHB_CLK) + div++; + if (div > 8) div = 8; - else if (div == 0) - div++; + return clk->parent->rate / div; } @@ -973,7 +1021,7 @@ static int _clk_max_enable(struct clk *clk) if (cpu_is_mx51()) reg &= ~MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX51; else - reg &= ~MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX53; + reg &= ~MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS; __raw_writel(reg, MXC_CCM_CLPCR); return 0; @@ -991,7 +1039,7 @@ static void _clk_max_disable(struct clk *clk) if (cpu_is_mx51()) reg |= MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX51; else - reg |= MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX53; + reg |= MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS; __raw_writel(reg, MXC_CCM_CLPCR); } @@ -1078,10 +1126,18 @@ static unsigned long _clk_emi_slow_round_rate(struct clk *clk, u32 div; div = clk->parent->rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (clk->parent->rate / div > MAX_EMI_SLOW_CLK) + div++; + if (div > 8) div = 8; - else if (div == 0) - div++; + return clk->parent->rate / div; } @@ -1143,6 +1199,9 @@ static struct clk emi_intr_clk[] = { .disable = _clk_disable_inwait, }, { + /* On MX51 - this clock is name emi_garb_clk, and controls the + * access of ARM to GARB. + */ .name = "emi_intr_clk", .id = 1, .parent = &ahb_clk, @@ -1311,7 +1370,7 @@ static int _clk_sdma_enable(struct clk *clk) if (cpu_is_mx51()) reg &= ~MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX51; else - reg &= ~MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX53; + reg &= ~MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS; __raw_writel(reg, MXC_CCM_CLPCR); return 0; @@ -1327,7 +1386,7 @@ static void _clk_sdma_disable(struct clk *clk) if (cpu_is_mx51()) reg |= MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX51; else - reg |= MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX53; + reg |= MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS; __raw_writel(reg, MXC_CCM_CLPCR); } @@ -1357,7 +1416,10 @@ static int _clk_ipu_enable(struct clk *clk) _clk_enable(clk); /* Handshake with IPU when certain clock rates are changed. */ reg = __raw_readl(MXC_CCM_CCDR); - reg &= ~MXC_CCM_CCDR_IPU_HS_MASK; + if (cpu_is_mx51()) + reg &= ~MXC_CCM_CCDR_IPU_HS_MASK; + else + reg &= ~MXC_CCM_CCDR_IPU_HS_MX53_MASK; __raw_writel(reg, MXC_CCM_CCDR); /* Handshake with IPU when LPM is entered as its enabled. */ @@ -1445,6 +1507,8 @@ static int _clk_ipu_di_set_parent(struct clk *clk, struct clk *parent) reg |= 3 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); } else if ((parent == &tve_clk) && (clk->id == 1)) reg |= 3 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + else if ((parent == &ldb_di_clk[clk->id]) && cpu_is_mx53()) + reg |= 5 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); else /* Assume any other clock is external clock pin */ reg |= 4 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); __raw_writel(reg, MXC_CCM_CSCMR2); @@ -1498,7 +1562,10 @@ static int _clk_ipu_di_set_rate(struct clk *clk, unsigned long rate) __raw_writel(reg, MXC_CCM_CDCDR); } else if ((clk->parent == &tve_clk) && (clk->id == 1)) clk->rate = rate; /*the rate decided by tve hw actually*/ - else + else if ((clk->parent == &ldb_di_clk[clk->id]) && cpu_is_mx53()) { + clk->rate = clk->parent->rate; + return 0; + } else return -EINVAL; clk->rate = rate; @@ -1511,12 +1578,16 @@ static unsigned long _clk_ipu_di_round_rate(struct clk *clk, { u32 div; - div = clk->parent->rate / rate; - if (div > 8) - div = 8; - else if (div == 0) - div++; - return clk->parent->rate / div; + if ((clk->parent == &ldb_di_clk[clk->id]) && cpu_is_mx53()) + return clk->parent->rate; + else { + div = clk->parent->rate / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return clk->parent->rate / div; + } } static struct clk ipu_di_clk[] = { @@ -1550,6 +1621,128 @@ static struct clk ipu_di_clk[] = { }, }; +static int _clk_ldb_di_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR2); + + if ((parent == &pll3_sw_clk)) { + if (clk->id == 0) + reg &= ~(MXC_CCM_CSCMR2_LDB_DI0_CLK_SEL); + else + reg &= ~(MXC_CCM_CSCMR2_LDB_DI1_CLK_SEL); + } else if ((parent == &pll4_sw_clk)) { + if (clk->id == 0) + reg |= MXC_CCM_CSCMR2_LDB_DI0_CLK_SEL; + else + reg |= MXC_CCM_CSCMR2_LDB_DI1_CLK_SEL; + } else { + BUG(); + } + + __raw_writel(reg, MXC_CCM_CSCMR2); + return 0; +} + +static void _clk_ldb_di_recalc(struct clk *clk) +{ + u32 div; + + if (clk->id == 0) + div = __raw_readl(MXC_CCM_CSCMR2) & + MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV; + else + div = __raw_readl(MXC_CCM_CSCMR2) & + MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV; + + if (div) + clk->rate = clk->parent->rate / 7; + else + clk->rate = 2 * clk->parent->rate / 7; +} + +static unsigned long _clk_ldb_di_round_rate(struct clk *clk, + unsigned long rate) +{ + if (rate * 7 <= clk->parent->rate) + return clk->parent->rate / 7; + else + return 2 * clk->parent->rate / 7; +} + +static int _clk_ldb_di_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div = 0; + + if (rate * 7 <= clk->parent->rate) { + div = 7; + rate = clk->parent->rate / 7; + } else + rate = 2 * clk->parent->rate / 7; + + reg = __raw_readl(MXC_CCM_CSCMR2); + if (div == 7) + reg |= (clk->id ? MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV : + MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV); + else + reg &= ~(clk->id ? MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV : + MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV); + __raw_writel(reg, MXC_CCM_CSCMR2); + + clk->rate = rate; + return 0; +} + +static int _clk_ldb_di_enable(struct clk *clk) +{ + _clk_enable(clk); + ipu_di_clk[clk->id].set_parent(&ipu_di_clk[clk->id], clk); + ipu_di_clk[clk->id].parent = clk; + ipu_di_clk[clk->id].rate = clk->rate; + ipu_di_clk[clk->id].enable(&ipu_di_clk[clk->id]); + ipu_di_clk[clk->id].usecount++; + return 0; +} + +static void _clk_ldb_di_disable(struct clk *clk) +{ + _clk_disable(clk); + ipu_di_clk[clk->id].disable(&ipu_di_clk[clk->id]); + ipu_di_clk[clk->id].usecount--; +} + +static struct clk ldb_di_clk[] = { + { + .name = "ldb_di0_clk", + .id = 0, + .parent = &pll4_sw_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGR6_CG14_OFFSET, + .recalc = _clk_ldb_di_recalc, + .set_parent = _clk_ldb_di_set_parent, + .round_rate = _clk_ldb_di_round_rate, + .set_rate = _clk_ldb_di_set_rate, + .enable = _clk_ldb_di_enable, + .disable = _clk_ldb_di_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT, + }, + { + .name = "ldb_di1_clk", + .id = 1, + .parent = &pll4_sw_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGR6_CG15_OFFSET, + .recalc = _clk_ldb_di_recalc, + .set_parent = _clk_ldb_di_set_parent, + .round_rate = _clk_ldb_di_round_rate, + .set_rate = _clk_ldb_di_set_rate, + .enable = _clk_ldb_di_enable, + .disable = _clk_ldb_di_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT, + }, +}; + static int _clk_csi0_set_parent(struct clk *clk, struct clk *parent) { u32 reg, mux; @@ -2060,28 +2253,6 @@ static struct clk uart5_clk[] = { }, }; -static struct clk esai_clk[] = { - { - .name = "esai_clk", - .id = 2, - .parent = &pll3_sw_clk, - .secondary = &esai_clk[1], - .enable_reg = MXC_CCM_CCGR6, - .enable_shift = MXC_CCM_CCGR6_CG9_OFFSET, - .enable = _clk_enable, - .disable = _clk_disable, - }, - { - .name = "esai_ipg_clk", - .id = 2, - .parent = &pll3_sw_clk, - .enable_reg = MXC_CCM_CCGR6, - .enable_shift = MXC_CCM_CCGR6_CG8_OFFSET, - .enable = _clk_enable, - .disable = _clk_disable, - }, -}; - static struct clk gpt_clk[] = { { .name = "gpt_clk", @@ -2311,23 +2482,15 @@ static struct clk cspi2_clk[] = { }, }; -static struct clk cspi3_clk[] = { - { - .name = "cspi_clk", - .id = 2, - .parent = &cspi_main_clk, - .enable_reg = MXC_CCM_CCGR4, - .enable_shift = MXC_CCM_CCGR4_CG13_OFFSET, - .enable = _clk_enable, - .disable = _clk_disable, - .secondary = &cspi3_clk[1], - }, - { - .name = "cspi_ipg_clk", - .id = 2, - .parent = &ipg_clk, - .secondary = &aips_tz2_clk, - }, +static struct clk cspi3_clk = { + .name = "cspi_ipg_clk", + .id = 2, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGR4_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &aips_tz2_clk, }; static int _clk_ssi_lp_apm_set_parent(struct clk *clk, struct clk *parent) @@ -2612,6 +2775,83 @@ static struct clk ssi_ext2_clk = { .disable = _clk_disable, }; +static int _clk_esai_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR2); + if (parent == &pll1_sw_clk || parent == &pll2_sw_clk || + parent == &pll3_sw_clk) { + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + NULL); + reg &= ~MXC_CCM_CSCMR2_ESAI_PRE_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR2_ESAI_PRE_SEL_OFFSET; + reg &= ~MXC_CCM_CSCMR2_ESAI_POST_SEL_MASK; + reg |= 0 << MXC_CCM_CSCMR2_ESAI_POST_SEL_OFFSET; + /* divider setting */ + } else { + mux = _get_mux(parent, &ssi1_clk[0], &ssi2_clk[0], &ckih_clk, + &ckih2_clk); + reg &= ~MXC_CCM_CSCMR2_ESAI_POST_SEL_MASK; + reg |= (mux + 1) << MXC_CCM_CSCMR2_ESAI_POST_SEL_OFFSET; + /* divider setting */ + } + + __raw_writel(reg, MXC_CCM_CSCMR2); + + /* set podf = 0 */ + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK; + __raw_writel(reg, MXC_CCM_CS1CDR); + + return 0; +} + +static void _clk_esai_recalc(struct clk *clk) +{ + u32 reg, pred, podf; + + reg = __raw_readl(MXC_CCM_CS1CDR); + if (clk->parent == &pll1_sw_clk || clk->parent == &pll2_sw_clk || + clk->parent == &pll3_sw_clk) { + pred = ((reg & MXC_CCM_CS1CDR_ESAI_CLK_PRED_MASK) >> + MXC_CCM_CS1CDR_ESAI_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK) >> + MXC_CCM_CS1CDR_ESAI_CLK_PODF_OFFSET) + 1; + + clk->rate = clk->parent->rate / (pred * podf); + } else { + podf = ((reg & MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK) >> + MXC_CCM_CS1CDR_ESAI_CLK_PODF_OFFSET) + 1; + + clk->rate = clk->parent->rate / podf; + } +} + +static struct clk esai_clk[] = { + { + .name = "esai_clk", + .id = 0, + .parent = &pll3_sw_clk, + .set_parent = _clk_esai_set_parent, + .recalc = _clk_esai_recalc, + .secondary = &esai_clk[1], + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGR6_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + .name = "esai_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGR6_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + static struct clk iim_clk = { .name = "iim_clk", .parent = &ipg_clk, @@ -3135,51 +3375,63 @@ static struct clk ieee_1588_clk = { .disable = _clk_disable, }; -static struct clk mlb_clk = { +static struct clk mlb_clk[] = { + { .name = "mlb_clk", .parent = &ipg_clk, .enable = _clk_enable, .enable_reg = MXC_CCM_CCGR7, .enable_shift = MXC_CCM_CCGR7_CG2_OFFSET, .disable = _clk_disable, + .secondary = &mlb_clk[1], + }, + { + .name = "mlb_mem_clk", + .parent = &emi_fast_clk, + .secondary = &emi_intr_clk[1], + }, }; static struct clk can1_clk[] = { { - .name = "can1_clk", - .parent = &pll3_sw_clk, - .secondary = &can1_clk[1], + .name = "can_clk", + .id = 0, + .parent = &ipg_clk, .enable = _clk_enable, + .secondary = &can1_clk[1], .enable_reg = MXC_CCM_CCGR6, - .enable_shift = MXC_CCM_CCGR6_CG11_OFFSET, + .enable_shift = MXC_CCM_CCGR6_CG10_OFFSET, .disable = _clk_disable, }, { - .name = "can1_ipg_clk", - .parent = &ipg_clk, + .name = "can_cpi_clk", + .id = 0, + .parent = &lp_apm_clk, .enable = _clk_enable, .enable_reg = MXC_CCM_CCGR6, - .enable_shift = MXC_CCM_CCGR6_CG10_OFFSET, + .enable_shift = MXC_CCM_CCGR6_CG11_OFFSET, .disable = _clk_disable, }, }; static struct clk can2_clk[] = { { - .name = "can2_clk", - .parent = &pll3_sw_clk, - .secondary = &can2_clk[1], + .name = "can_clk", + .id = 1, + .parent = &ipg_clk, .enable = _clk_enable, + .secondary = &can2_clk[1], .enable_reg = MXC_CCM_CCGR4, - .enable_shift = MXC_CCM_CCGR4_CG4_OFFSET, + .enable_shift = MXC_CCM_CCGR4_CG3_OFFSET, .disable = _clk_disable, }, { - .name = "can2_ipg_clk", - .parent = &ipg_clk, + .name = "can_cpi_clk", + .id = 1, + .parent = &lp_apm_clk, .enable = _clk_enable, .enable_reg = MXC_CCM_CCGR4, - .enable_shift = MXC_CCM_CCGR4_CG3_OFFSET, + .enable_shift = MXC_CCM_CCGR4_CG4_OFFSET, .disable = _clk_disable, }, }; @@ -3680,7 +3932,6 @@ static struct clk pgc_clk = { }; /*usb OTG clock */ - static struct clk usb_clk = { .name = "usb_clk", .rate = 60000000, @@ -3716,7 +3967,8 @@ static struct clk ata_clk = { }; static struct clk owire_clk = { - .name = "owire_clk", + /* 1w driver come from upstream and use owire as clock name*/ + .name = "owire", .parent = &ipg_perclk, .enable = _clk_enable, .enable_reg = MXC_CCM_CCGR2, @@ -3796,16 +4048,6 @@ static int _clk_gpu3d_set_parent(struct clk *clk, struct clk *parent) return 0; } -static struct clk gpu3d_clk = { - .name = "gpu3d_clk", - .parent = &axi_a_clk, - .set_parent = _clk_gpu3d_set_parent, - .enable = _clk_enable, - .enable_reg = MXC_CCM_CCGR5, - .enable_shift = MXC_CCM_CCGR5_CG1_OFFSET, - .disable = _clk_disable, - .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, -}; static struct clk garb_clk = { .name = "garb_clk", @@ -3816,13 +4058,16 @@ static struct clk garb_clk = { .disable = _clk_disable, }; -static struct clk emi_garb_clk = { - .name = "emi_garb_clk", +static struct clk gpu3d_clk = { + .name = "gpu3d_clk", .parent = &axi_a_clk, + .set_parent = _clk_gpu3d_set_parent, .enable = _clk_enable, - .enable_reg = MXC_CCM_CCGR6, - .enable_shift = MXC_CCM_CCGR6_CG4_OFFSET, - .disable = _clk_disable_inwait, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG1_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + .secondary = &garb_clk, }; static int _clk_gpu2d_set_parent(struct clk *clk, struct clk *parent) @@ -4008,8 +4253,7 @@ static struct clk *mxc_clks[] = { &cspi1_clk[1], &cspi2_clk[0], &cspi2_clk[1], - &cspi3_clk[0], - &cspi3_clk[1], + &cspi3_clk, &ssi_lp_apm_clk, &ssi1_clk[0], &ssi1_clk[1], @@ -4043,6 +4287,7 @@ static struct clk *mxc_clks[] = { &emi_enfc_clk, &emi_fast_clk, &emi_intr_clk[0], + &emi_intr_clk[1], &spdif_xtal_clk, &spdif0_clk[0], &spdif0_clk[1], @@ -4111,9 +4356,6 @@ static void clk_tree_init(void) pll4_sw_clk.parent = &osc_clk; } - if (cpu_is_mx53()) - tve_clk.parent = &pll4_sw_clk; - /* set emi_slow_clk parent */ emi_slow_clk.parent = &main_bus_clk; reg = __raw_readl(MXC_CCM_CBCDR); @@ -4191,6 +4433,7 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long esdhc2_clk[0].recalc = _clk_esdhc2_recalc; esdhc2_clk[0].set_rate = _clk_esdhc2_set_rate; + emi_intr_clk[1].name = "emi_garb_clk"; clk_tree_init(); for (clkp = mxc_clks; clkp < mxc_clks + ARRAY_SIZE(mxc_clks); clkp++) @@ -4209,7 +4452,9 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long clk_register(&spdif1_clk[0]); clk_register(&spdif1_clk[1]); clk_register(&ddr_hf_clk); - clk_register(&emi_garb_clk); + + max_axi_a_clk = MAX_AXI_A_CLK_MX51; + max_axi_b_clk = MAX_AXI_B_CLK_MX51; /* set DDR clock parent */ reg = 0; @@ -4261,8 +4506,10 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long propagate_rate(&pll1_sw_clk); propagate_rate(&pll2_sw_clk); +#ifndef CONFIG_LATE_CPU_CLK_ENABLE + /* See comment below where cpu_clk is enabled for further information */ clk_enable(&cpu_clk); - +#endif /* Set SDHC parents to be PLL2 */ clk_set_parent(&esdhc1_clk[0], &pll2_sw_clk); clk_set_parent(&esdhc2_clk[0], &pll2_sw_clk); @@ -4396,13 +4643,6 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long if (i > cpu_wp_nr) BUG(); - /*Allow for automatic gating of the EMI internal clock. - * If this is done, emi_intr CCGR bits should be set to 11. - */ - reg = __raw_readl((IO_ADDRESS(M4IF_BASE_ADDR) + 0x8c)); - reg &= ~0x1; - __raw_writel(reg, (IO_ADDRESS(M4IF_BASE_ADDR) + 0x8c)); - clk_set_parent(&arm_axi_clk, &axi_a_clk); clk_set_parent(&ipu_clk[0], &axi_b_clk); @@ -4418,8 +4658,8 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long (0 << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET); __raw_writel(reg, MXC_CCM_CSCDR1); } else { - /* Move UART to run from PLL1 */ - clk_set_parent(&uart_main_clk, &pll1_sw_clk); + /* Move UART to run from PLL2 */ + clk_set_parent(&uart_main_clk, &pll2_sw_clk); /* Set the UART dividers to divide, * so the UART_CLK is 66.5MHz. @@ -4427,7 +4667,7 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long reg = __raw_readl(MXC_CCM_CSCDR1); reg &= ~MXC_CCM_CSCDR1_UART_CLK_PODF_MASK; reg &= ~MXC_CCM_CSCDR1_UART_CLK_PRED_MASK; - reg |= (5 << MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) | + reg |= (4 << MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) | (1 << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET); __raw_writel(reg, MXC_CCM_CSCDR1); } @@ -4446,6 +4686,15 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long base = ioremap(GPT1_BASE_ADDR, SZ_4K); mxc_timer_init(&gpt_clk[0], base, MXC_INT_GPT); +#ifdef CONFIG_LATE_CPU_CLK_ENABLE + /** + * Late enable of the cpu clock. This is causing a random crash at boot + * time on the ConnectCore Wi-i.MX51. Enabling the cpu clock here seems + * to work around the problem. Must be in order to better understand the + * reason of the problem and the real solution to the problem. + */ + clk_enable(&cpu_clk); +#endif return 0; } @@ -4493,15 +4742,15 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long 1 << MXC_CCM_CCGR5_CG6_OFFSET | 3 << MXC_CCM_CCGR5_CG7_OFFSET | 1 << MXC_CCM_CCGR5_CG8_OFFSET | - 3 << MXC_CCM_CCGR5_CG9_OFFSET | + 1 << MXC_CCM_CCGR5_CG9_OFFSET | 1 << MXC_CCM_CCGR5_CG10_OFFSET | 3 << MXC_CCM_CCGR5_CG11_OFFSET, MXC_CCM_CCGR5); - __raw_writel(3 << MXC_CCM_CCGR6_CG0_OFFSET | + __raw_writel(1 << MXC_CCM_CCGR6_CG0_OFFSET | 3 << MXC_CCM_CCGR6_CG1_OFFSET | - 3 << MXC_CCM_CCGR6_CG4_OFFSET | - 3 << MXC_CCM_CCGR6_CG8_OFFSET | - 3 << MXC_CCM_CCGR6_CG9_OFFSET | + 1 << MXC_CCM_CCGR6_CG4_OFFSET | + 1 << MXC_CCM_CCGR6_CG8_OFFSET | + 1 << MXC_CCM_CCGR6_CG9_OFFSET | 3 << MXC_CCM_CCGR6_CG12_OFFSET | 3 << MXC_CCM_CCGR6_CG13_OFFSET , MXC_CCM_CCGR6); @@ -4544,7 +4793,6 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long clk_register(*clkp); clk_register(&pll4_sw_clk); - clk_register(&emi_intr_clk[1]); clk_register(&uart4_clk[0]); clk_register(&uart4_clk[1]); clk_register(&uart5_clk[0]); @@ -4554,7 +4802,21 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long clk_register(&ocram_clk); clk_register(&sata_clk); clk_register(&ieee_1588_clk); - clk_register(&mlb_clk); + clk_register(&mlb_clk[0]); + clk_register(&can1_clk[0]); + clk_register(&can2_clk[0]); + clk_register(&ldb_di_clk[0]); + clk_register(&ldb_di_clk[1]); + /* OSC of 22.5792M or 24.576M for ESAI */ + clk_register(&esai_clk[0]); + clk_set_parent(&esai_clk[0], &ckih_clk); + clk_register(&esai_clk[1]); + + ldb_di_clk[0].parent = ldb_di_clk[1].parent = + tve_clk.parent = &pll4_sw_clk; + + max_axi_a_clk = MAX_AXI_A_CLK_MX53; + max_axi_b_clk = MAX_AXI_B_CLK_MX53; /* set DDR clock parent */ reg = __raw_readl(MXC_CCM_CBCMR) & @@ -4575,6 +4837,8 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long clk_set_parent(&esdhc2_clk[0], &esdhc1_clk[0]); clk_set_parent(&esdhc3_clk[0], &pll2_sw_clk); + clk_set_parent(&ipu_di_clk[0], &pll4_sw_clk); + #if 0 /*Setup the LPM bypass bits */ reg = __raw_readl(MXC_CCM_CLPCR); @@ -4585,13 +4849,6 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long __raw_writel(reg, MXC_CCM_CLPCR); #endif - /* Disable the handshake with HSC block as its not - * initialised right now. - */ - reg = __raw_readl(MXC_CCM_CCDR); - reg |= MXC_CCM_CCDR_EMI_HS_MASK; - __raw_writel(reg, MXC_CCM_CCDR); - /* This will propagate to all children and init all the clock rates */ propagate_rate(&osc_clk); propagate_rate(&ckih_clk); @@ -4605,14 +4862,15 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long clk_enable(&main_bus_clk); + /* Set AXI_B_CLK to be 200MHz */ + clk_set_rate(&axi_b_clk, 200000000); + /* Initialise the parents to be axi_b, parents are set to * axi_a when the clocks are enabled. */ clk_set_parent(&vpu_clk[0], &axi_b_clk); clk_set_parent(&vpu_clk[1], &axi_b_clk); - clk_set_parent(&gpu3d_clk, &axi_a_clk); - clk_set_parent(&gpu2d_clk, &axi_a_clk); /* move cspi to 24MHz */ clk_set_parent(&cspi_main_clk, &lp_apm_clk); @@ -4797,27 +5055,27 @@ static int cpu_clk_set_wp(int wp) __raw_writel(reg, MXC_CCM_CCSR); /* Stop the PLL */ - reg = __raw_readl(MXC_DPLL1_BASE + MXC_PLL_DP_CTL); + reg = __raw_readl(pll1_base + MXC_PLL_DP_CTL); reg &= ~MXC_PLL_DP_CTL_UPEN; - __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_CTL); + __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL); /* PDF and MFI */ reg = p->pdf | p->mfi << MXC_PLL_DP_OP_MFI_OFFSET; - __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_OP); + __raw_writel(reg, pll1_base + MXC_PLL_DP_OP); /* MFD */ - __raw_writel(p->mfd, MXC_DPLL1_BASE + MXC_PLL_DP_MFD); + __raw_writel(p->mfd, pll1_base + MXC_PLL_DP_MFD); /* MFI */ - __raw_writel(p->mfn, MXC_DPLL1_BASE + MXC_PLL_DP_MFN); + __raw_writel(p->mfn, pll1_base + MXC_PLL_DP_MFN); - reg = __raw_readl(MXC_DPLL1_BASE + MXC_PLL_DP_CTL); + reg = __raw_readl(pll1_base + MXC_PLL_DP_CTL); reg |= MXC_PLL_DP_CTL_UPEN; /* Set the UPEN bits */ - __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_CTL); + __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL); /* Forcefully restart the PLL */ reg |= MXC_PLL_DP_CTL_RST; - __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_CTL); + __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL); /* Wait for the PLL to lock */ getnstimeofday(&nstimeofday); @@ -4825,7 +5083,7 @@ static int cpu_clk_set_wp(int wp) getnstimeofday(&curtime); if ((curtime.tv_nsec - nstimeofday.tv_nsec) > SPIN_DELAY) panic("pll1 relock failed\n"); - stat = __raw_readl(MXC_DPLL1_BASE + MXC_PLL_DP_CTL) & + stat = __raw_readl(pll1_base + MXC_PLL_DP_CTL) & MXC_PLL_DP_CTL_LRF; } while (!stat); diff --git a/arch/arm/mach-mx5/cpu.c b/arch/arm/mach-mx5/cpu.c index 692d258a4a0c..44440569f041 100644 --- a/arch/arm/mach-mx5/cpu.c +++ b/arch/arm/mach-mx5/cpu.c @@ -19,6 +19,7 @@ * @ingroup MSL_MX51 */ +#include <linux/proc_fs.h> #include <linux/types.h> #include <linux/err.h> #include <linux/kernel.h> @@ -28,10 +29,29 @@ #include <linux/clk.h> #include <mach/common.h> #include <mach/hardware.h> -#include "crm_regs.h" +#include <asm/mach/map.h> + +#define CORTEXA8_PLAT_AMC 0x18 +#define SRPG_NEON_PUPSCR 0x284 +#define SRPG_NEON_PDNSCR 0x288 +#define SRPG_ARM_PUPSCR 0x2A4 +#define SRPG_ARM_PDNSCR 0x2A8 +#define SRPG_EMPGC0_PUPSCR 0x2E4 +#define SRPG_EMPGC0_PDNSCR 0x2E8 +#define SRPG_EMPGC1_PUPSCR 0x304 +#define SRPG_EMPGC1_PDNSCR 0x308 void __iomem *arm_plat_base; void __iomem *gpc_base; +void __iomem *ccm_base; +void __iomem *databahn_base; +void *wait_in_iram_base; +void (*wait_in_iram)(void *ccm_addr, void *databahn_addr); + +extern void mx50_wait(u32 ccm_base, u32 databahn_addr); + +struct cpu_wp *(*get_cpu_wp)(int *wp); +void (*set_num_cpu_wp)(int num); static void __init mipi_hsc_disable(void) { @@ -54,7 +74,8 @@ static void __init mipi_hsc_disable(void) if (cpu_is_mx51_rev(CHIP_REV_2_0) > 0) { temp = __raw_readl(reg_hsc_mxt_conf); - __raw_writel(temp | 0x10000, reg_hsc_mxt_conf); + __raw_writel(0xf003008b, reg_hsc_mxt_conf); + /* Previous value of reg_hsc_mxt_conf was 0xf00100ff */ } clk_disable(clk); @@ -102,6 +123,7 @@ static int __init post_cpu_init(void) { void __iomem *base; unsigned int reg; + struct clk *gpcclk = clk_get(NULL, "gpc_dvfs_clk"); int iram_size = IRAM_SIZE; if (cpu_is_mx51()) { @@ -116,11 +138,30 @@ static int __init post_cpu_init(void) } gpc_base = ioremap(MX53_BASE_ADDR(GPC_BASE_ADDR), SZ_4K); + ccm_base = ioremap(MX53_BASE_ADDR(CCM_BASE_ADDR), SZ_4K); + + clk_enable(gpcclk); + + /* Setup the number of clock cycles to wait for SRPG + * power up and power down requests. + */ + __raw_writel(0x010F0201, gpc_base + SRPG_ARM_PUPSCR); + __raw_writel(0x010F0201, gpc_base + SRPG_NEON_PUPSCR); + __raw_writel(0x00000008, gpc_base + SRPG_EMPGC0_PUPSCR); + __raw_writel(0x00000008, gpc_base + SRPG_EMPGC1_PUPSCR); + + __raw_writel(0x01010101, gpc_base + SRPG_ARM_PDNSCR); + __raw_writel(0x01010101, gpc_base + SRPG_NEON_PDNSCR); + __raw_writel(0x00000018, gpc_base + SRPG_EMPGC0_PDNSCR); + __raw_writel(0x00000018, gpc_base + SRPG_EMPGC1_PDNSCR); + + clk_disable(gpcclk); + clk_put(gpcclk); /* Set ALP bits to 000. Set ALP_EN bit in Arm Memory Controller reg. */ arm_plat_base = ioremap(MX53_BASE_ADDR(ARM_BASE_ADDR), SZ_4K); reg = 0x8; - __raw_writel(reg, MXC_CORTEXA8_PLAT_AMC); + __raw_writel(reg, arm_plat_base + CORTEXA8_PLAT_AMC); base = ioremap(MX53_BASE_ADDR(AIPS1_BASE_ADDR), SZ_4K); __raw_writel(0x0, base + 0x40); @@ -140,15 +181,53 @@ static int __init post_cpu_init(void) __raw_writel(reg, base + 0x50); iounmap(base); - /*Allow for automatic gating of the EMI internal clock. - * If this is done, emi_intr CCGR bits should be set to 11. - */ - base = ioremap(MX53_BASE_ADDR(M4IF_BASE_ADDR), SZ_4K); - reg = __raw_readl(base + 0x8c); - reg &= ~0x1; - __raw_writel(reg, base + 0x8c); - iounmap(base); + if (cpu_is_mx51() || cpu_is_mx53()) { + /*Allow for automatic gating of the EMI internal clock. + * If this is done, emi_intr CCGR bits should be set to 11. + */ + base = ioremap(MX53_BASE_ADDR(M4IF_BASE_ADDR), SZ_4K); + reg = __raw_readl(base + 0x8c); + reg &= ~0x1; + __raw_writel(reg, base + 0x8c); + iounmap(base); + } + databahn_base = ioremap(MX50_DATABAHN_BASE_ADDR, SZ_16K); + + if (cpu_is_mx50()) { + struct clk *ddr_clk = clk_get(NULL, "ddr_clk"); + unsigned long iram_paddr; + + iram_alloc(SZ_4K, &iram_paddr); + /* Need to remap the area here since we want the memory region + to be executable. */ + wait_in_iram_base = __arm_ioremap(iram_paddr, + SZ_4K, MT_HIGH_VECTORS); + memcpy(wait_in_iram_base, mx50_wait, SZ_4K); + wait_in_iram = (void *)wait_in_iram_base; + + clk_enable(ddr_clk); + + /* Set the DDR to enter automatic self-refresh. */ + /* Set the DDR to automatically enter lower power mode 4. */ + reg = __raw_readl(databahn_base + DATABAHN_CTL_REG22); + reg &= ~LOWPOWER_AUTOENABLE_MASK; + reg |= 1 << 1; + __raw_writel(reg, databahn_base + DATABAHN_CTL_REG22); + + /* set the counter for entering mode 4. */ + reg = __raw_readl(databahn_base + DATABAHN_CTL_REG21); + reg &= ~LOWPOWER_EXTERNAL_CNT_MASK; + reg = 128 << LOWPOWER_EXTERNAL_CNT_OFFSET; + __raw_writel(reg, databahn_base + DATABAHN_CTL_REG21); + + /* Enable low power mode 4 */ + reg = __raw_readl(databahn_base + DATABAHN_CTL_REG20); + reg &= ~LOWPOWER_CONTROL_MASK; + reg |= 1 << 1; + __raw_writel(reg, databahn_base + DATABAHN_CTL_REG20); + clk_disable(ddr_clk); + } return 0; } diff --git a/arch/arm/mach-mx5/crm_regs.h b/arch/arm/mach-mx5/crm_regs.h index e53f55d258eb..b2660a34c0e9 100644 --- a/arch/arm/mach-mx5/crm_regs.h +++ b/arch/arm/mach-mx5/crm_regs.h @@ -13,17 +13,7 @@ #ifndef __ARCH_ARM_MACH_MX51_CRM_REGS_H__ #define __ARCH_ARM_MACH_MX51_CRM_REGS_H__ -extern void __iomem *ccm_base; -extern void __iomem *pll1_base; -extern void __iomem *pll2_base; -extern void __iomem *pll3_base; -extern void __iomem *pll4_base; - #define MXC_CCM_BASE (IO_ADDRESS(CCM_BASE_ADDR)) -#define MXC_DPLL1_BASE (pll1_base) -#define MXC_DPLL2_BASE (pll2_base) -#define MXC_DPLL3_BASE (pll3_base) -#define MXC_DPLL4_BASE (pll4_base) /* PLL Register Offsets */ #define MXC_PLL_DP_CTL 0x00 @@ -80,6 +70,56 @@ extern void __iomem *pll4_base; #define MXC_PLL_DP_DESTAT_TOG_SEL (1 << 31) #define MXC_PLL_DP_DESTAT_MFN 0x07FFFFFF +/* Register addresses of apll and pfd*/ +#define MXC_ANADIG_FRAC0 0x10 +#define MXC_ANADIG_FRAC0_SET 0x14 +#define MXC_ANADIG_FRAC0_CLR 0x18 +#define MXC_ANADIG_FRAC1 0x20 +#define MXC_ANADIG_FRAC1_SET 0x24 +#define MXC_ANADIG_FRAC1_CLR 0x28 +#define MXC_ANADIG_MISC 0x60 +#define MXC_ANADIG_MISC_SET 0x64 +#define MXC_ANADIG_MISC_CLR 0x68 +#define MXC_ANADIG_PLLCTRL 0x70 +#define MXC_ANADIG_PLLCTRL_SET 0x74 +#define MXC_ANADIG_PLLCTRL_CLR 0x78 + +/* apll and pfd Register Bit definitions */ + +#define MXC_ANADIG_PFD3_CLKGATE (1 << 31) +#define MXC_ANADIG_PFD3_STABLE (1 << 30) +#define MXC_ANADIG_PFD3_FRAC_OFFSET 24 +#define MXC_ANADIG_PFD_FRAC_MASK 0x3F +#define MXC_ANADIG_PFD2_CLKGATE (1 << 23) +#define MXC_ANADIG_PFD2_STABLE (1 << 22) +#define MXC_ANADIG_PFD2_FRAC_OFFSET 16 +#define MXC_ANADIG_PFD1_CLKGATE (1 << 15) +#define MXC_ANADIG_PFD1_STABLE (1 << 14) +#define MXC_ANADIG_PFD1_FRAC_OFFSET 8 +#define MXC_ANADIG_PFD0_CLKGATE (1 << 7) +#define MXC_ANADIG_PFD0_STABLE (1 << 6) +#define MXC_ANADIG_PFD0_FRAC_OFFSET 0 + +#define MXC_ANADIG_PFD7_CLKGATE (1 << 31) +#define MXC_ANADIG_PFD7_STABLE (1 << 30) +#define MXC_ANADIG_PFD7_FRAC_OFFSET 24 +#define MXC_ANADIG_PFD6_CLKGATE (1 << 23) +#define MXC_ANADIG_PFD6_STABLE (1 << 22) +#define MXC_ANADIG_PFD6_FRAC_OFFSET 16 +#define MXC_ANADIG_PFD5_CLKGATE (1 << 15) +#define MXC_ANADIG_PFD5_STABLE (1 << 14) +#define MXC_ANADIG_PFD5_FRAC_OFFSET 8 +#define MXC_ANADIG_PFD4_CLKGATE (1 << 7) +#define MXC_ANADIG_PFD4_STABLE (1 << 6) +#define MXC_ANADIG_PFD4_FRAC_OFFSET 0 + +#define MXC_ANADIG_APLL_LOCK (1 << 31) +#define MXC_ANADIG_APLL_FORCE_LOCK (1 << 30) +#define MXC_ANADIG_PFD_DIS_OFFSET 16 +#define MXC_ANADIG_PFD_DIS_MASK 0xff +#define MXC_ANADIG_APLL_LOCK_CNT_OFFSET 0 +#define MXC_ANADIG_APLL_LOCK_CNT_MASK 0xffff + /* Register addresses of CCM*/ #define MXC_CCM_CCR (MXC_CCM_BASE + 0x00) #define MXC_CCM_CCDR (MXC_CCM_BASE + 0x04) @@ -116,6 +156,22 @@ extern void __iomem *pll4_base; #define MXC_CCM_CCGR6 (MXC_CCM_BASE + 0x80) #define MXC_CCM_CCGR7 (MXC_CCM_BASE + 0x84) #define MXC_CCM_CMEOR (MXC_CCM_BASE + 0x88) +#define MXC_CCM_CSR2 (MXC_CCM_BASE + 0x8C) +#define MXC_CCM_CLKSEQ_BYPASS (MXC_CCM_BASE + 0x90) +#define MXC_CCM_CLK_SYS (MXC_CCM_BASE + 0x94) +#define MXC_CCM_CLK_DDR (MXC_CCM_BASE + 0x98) +#define MXC_CCM_ELCDIFPIX (MXC_CCM_BASE + 0x9C) +#define MXC_CCM_EPDCPIX (MXC_CCM_BASE + 0xA0) +#define MXC_CCM_DISPLAY_AXI (MXC_CCM_BASE + 0xA4) +#define MXC_CCM_EPDC_AXI (MXC_CCM_BASE + 0xA8) +#define MXC_CCM_GPMI (MXC_CCM_BASE + 0xAC) +#define MXC_CCM_BCH (MXC_CCM_BASE + 0xB0) +#define MXC_CCM_MSHC_XMSCKI (MXC_CCM_BASE + 0xB4) + +/* CCM Register Offsets. */ +#define MXC_CCM_CDCR_OFFSET 0x4C +#define MXC_CCM_CACRR_OFFSET 0x10 +#define MXC_CCM_CDHIPR_OFFSET 0x48 /* Define the bits in register CCR */ #define MXC_CCM_CCR_COSC_EN (1 << 12) @@ -149,8 +205,11 @@ extern void __iomem *pll4_base; #define MXC_CCM_CSR_REF_EN_B (1 << 0) /* Define the bits in register CCSR */ -#define MXC_CCM_CCSR_LP_APM_SEL (0x1 << 9) -#define MXC_CCM_CCSR_LP_APM_SEL_MX53 (0x1 << 10) +#define MXC_CCM_CCSR_PLL3_PFD_EN (0x1 << 13) +#define MXC_CCM_CCSR_PLL2_PFD_EN (0x1 << 12) +#define MXC_CCM_CCSR_PLL1_PFD_EN (0x1 << 11) +#define MXC_CCM_CCSR_LP_APM_SEL (0x1 << 10) +#define MXC_CCM_CCSR_LP_APM_SE_MX51L (0x1 << 9) #define MXC_CCM_CCSR_PLL4_SW_CLK_SEL (1 << 9) #define MXC_CCM_CCSR_STEP_SEL_OFFSET (7) #define MXC_CCM_CCSR_STEP_SEL_MASK (0x3 << 7) @@ -167,12 +226,17 @@ extern void __iomem *pll4_base; #define MXC_CCM_CACRR_ARM_PODF_MASK (0x7) /* Define the bits in register CBCDR */ +#define MX50_CCM_CBCDR_WEIM_CLK_SEL (0x1 << 27) #define MXC_CCM_CBCDR_EMI_CLK_SEL (0x1 << 26) #define MXC_CCM_CBCDR_PERIPH_CLK_SEL (0x1 << 25) +#define MX50_CCM_CBCDR_PERIPH_CLK_SEL_OFFSET (25) +#define MX50_CCM_CBCDR_PERIPH_CLK_SEL_MASK (0x3 << 25) #define MXC_CCM_CBCDR_DDR_HF_SEL_OFFSET (30) #define MXC_CCM_CBCDR_DDR_HF_SEL (0x1 << 30) #define MXC_CCM_CBCDR_DDR_PODF_OFFSET (27) -#define MXC_CCM_CBCDR_DDR_PODF_MASK (0x7 << 27) +#define MXC_CCM_CBCDR_DDR_PODF_MASK (0x7 << 27) +#define MX50_CCM_CBCDR_WEIM_PODF_OFFSET (22) +#define MX50_CCM_CBCDR_WEIM_PODF_MASK (0x7 << 22) #define MXC_CCM_CBCDR_EMI_PODF_OFFSET (22) #define MXC_CCM_CBCDR_EMI_PODF_MASK (0x7 << 22) #define MXC_CCM_CBCDR_AXI_B_PODF_OFFSET (19) @@ -209,6 +273,8 @@ extern void __iomem *pll4_base; #define MXC_CCM_CBCMR_GPU_CLK_SEL_MASK (0x3 << 4) #define MXC_CCM_CBCMR_GPU2D_CLK_SEL_OFFSET (14) #define MXC_CCM_CBCMR_GPU2D_CLK_SEL_MASK (0x3 << 14) +#define MXC_CCM_CBCMR_DBG_APB_CLK_SEL_OFFSET (2) +#define MXC_CCM_CBCMR_DBG_APB_CLK_SEL_MASK (0x3 << 2) #define MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL (0x1 << 1) #define MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL (0x1 << 0) @@ -228,6 +294,12 @@ extern void __iomem *pll4_base; #define MXC_CCM_CSCMR1_ESDHC3_CLK_SEL_MX51 (0x1 << 19) #define MXC_CCM_CSCMR1_ESDHC2_CLK_SEL (0x1 << 19) #define MXC_CCM_CSCMR1_ESDHC4_CLK_SEL (0x1 << 18) +#define MX50_CCM_CSCMR1_ESDHC1_CLK_SEL_OFFSET (21) +#define MX50_CCM_CSCMR1_ESDHC1_CLK_SEL_MASK (0x3 << 21) +#define MX50_CCM_CSCMR1_ESDHC2_CLK_SEL (0x1 << 20) +#define MX50_CCM_CSCMR1_ESDHC4_CLK_SEL (0x1 << 19) +#define MX50_CCM_CSCMR1_ESDHC3_CLK_SEL_OFFSET (16) +#define MX50_CCM_CSCMR1_ESDHC3_CLK_SEL_MASK (0x7 << 16) #define MXC_CCM_CSCMR1_ESDHC3_MSHC2_CLK_SEL_OFFSET (16) #define MXC_CCM_CSCMR1_ESDHC3_MSHC2_CLK_SEL_MASK (0x3 << 16) #define MXC_CCM_CSCMR1_SSI1_CLK_SEL_OFFSET (14) @@ -279,11 +351,11 @@ extern void __iomem *pll4_base; #define MXC_CCM_CSCMR2_SLIMBUS_COM (0x1 << 9) #define MXC_CCM_CSCMR2_SLIMBUS_CLK_SEL_OFFSET (6) #define MXC_CCM_CSCMR2_SLIMBUS_CLK_SEL_MASK (0x7 << 6) -/* MX51 */ -#define MXC_CCM_CSCMR2_LBD_DI1_IPU_DIV (0x1 << 11) -#define MXC_CCM_CSCMR2_LBD_DI0_IPU_DIV (0x1 << 10) -#define MXC_CCM_CSCMR2_LBD_DI1_CLK_SEL (0x1 << 9) -#define MXC_CCM_CSCMR2_LBD_DI0_CLK_SEL (0x1 << 8) +/* MX53 */ +#define MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV (0x1 << 11) +#define MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV (0x1 << 10) +#define MXC_CCM_CSCMR2_LDB_DI1_CLK_SEL (0x1 << 9) +#define MXC_CCM_CSCMR2_LDB_DI0_CLK_SEL (0x1 << 8) #define MXC_CCM_CSCMR2_CAN_CLK_SEL_OFFSET (6) #define MXC_CCM_CSCMR2_CAN_CLK_SEL_MASK (0x3 << 6) #define MXC_CCM_CSCMR2_SPDIF1_COM (1 << 5) @@ -439,6 +511,9 @@ extern void __iomem *pll4_base; #define MXC_CCM_CDHIPR_AXI_A_PODF_BUSY (1 << 0) /* Define the bits in register CDCR */ +#define MX50_CCM_CDCR_SW_PERIPH_CLK_DIV_REQ_STATUS (0x1 << 7) +#define MX50_CCM_CDCR_SW_PERIPH_CLK_DIV_REQ (0x1 << 6) +#define MX50_CCM_CDCR_SW_DVFS_EN (0x1 << 5) #define MXC_CCM_CDCR_ARM_FREQ_SHIFT_DIVIDER (0x1 << 2) #define MXC_CCM_CDCR_PERIPH_CLK_DVFS_PODF_OFFSET (0) #define MXC_CCM_CDCR_PERIPH_CLK_DVFS_PODF_MASK (0x3) @@ -453,9 +528,10 @@ extern void __iomem *pll4_base; #define MXC_CCM_CLPCR_BYPASS_CAN2_LPM_HS (0x1 << 27) #define MXC_CCM_CLPCR_BYPASS_CAN1_LPM_HS (0x1 << 27) #define MXC_CCM_CLPCR_BYPASS_SCC_LPM_HS_MX53 (0x1 << 26) -#define MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX53 (0x1 << 25) -#define MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX53 (0x1 << 24) +#define MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS (0x1 << 25) +#define MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS (0x1 << 24) #define MXC_CCM_CLPCR_BYPASS_EMI_INT2_LPM_HS (0x1 << 23) +#define MX50_CCM_CLPCR_BYPASS_RNGB_LPM_HS (0x1 << 23) #define MXC_CCM_CLPCR_BYPASS_EMI_INT1_LPM_HS (0x1 << 22) #define MXC_CCM_CLPCR_BYPASS_EMI_SLOW_LPM_HS (0x1 << 21) #define MXC_CCM_CLPCR_BYPASS_EMI_FAST_LPM_HS (0x1 << 20) @@ -472,12 +548,13 @@ extern void __iomem *pll4_base; #define MXC_CCM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) #define MXC_CCM_CLPCR_LPSR_CLK_SEL_OFFSET (3) #define MXC_CCM_CLPCR_LPSR_CLK_SEL_MASK (0x3 << 3) +#define MXC_CCM_CLPCR_BYPASS_PMIC_VFUNC_READY (0x1 << 2) #define MXC_CCM_CLPCR_LPM_OFFSET (0) #define MXC_CCM_CLPCR_LPM_MASK (0x3) /* Define the bits in register CISR */ #define MXC_CCM_CISR_ARM_PODF_LOADED_MX51 (0x1 << 25) -#define MXC_CCM_CISR_ARM_PODF_LOADED_MX53 (0x1 << 26) +#define MXC_CCM_CISR_ARM_PODF_LOADED (0x1 << 26) #define MXC_CCM_CISR_TEMP_MON_ALARM (0x1 << 25) #define MXC_CCM_CISR_EMI_CLK_SEL_LOADED (0x1 << 23) #define MXC_CCM_CISR_PER_CLK_SEL_LOADED (0x1 << 22) @@ -490,6 +567,7 @@ extern void __iomem *pll4_base; #define MXC_CCM_CISR_COSC_READY (0x1 << 6) #define MXC_CCM_CISR_CKIH2_READY (0x1 << 5) #define MXC_CCM_CISR_CKIH_READY (0x1 << 4) +#define MX50_CCM_CISR_CAMP1_READY (0x1 << 4) #define MXC_CCM_CISR_FPM_READY (0x1 << 3) #define MXC_CCM_CISR_LRF_PLL3 (0x1 << 2) #define MXC_CCM_CISR_LRF_PLL2 (0x1 << 1) @@ -499,13 +577,14 @@ extern void __iomem *pll4_base; #define MXC_CCM_CIMR_MASK_ARM_PODF_LOADED_MX51 (0x1 << 25) #define MXC_CCM_CIMR_MASK_EMI_PODF_LOADED_MX51 (0x1 << 20) #define MXC_CCM_CIMR_MASK_AXI_C_PODF_LOADED_MX51 (0x1 << 19) -#define MXC_CCM_CIMR_MASK_ARM_PODF_LOADED_MX53 (0x1 << 26) +#define MXC_CCM_CIMR_MASK_ARM_PODF_LOADED (0x1 << 26) #define MXC_CCM_CIMR_MASK_TEMP_MON_ALARM (0x1 << 25) #define MXC_CCM_CIMR_MASK_EMI_CLK_SEL_LOADED (0x1 << 23) #define MXC_CCM_CIMR_MASK_PER_CLK_SEL_LOADED (0x1 << 22) #define MXC_CCM_CIMR_MASK_NFC_IPG_INT_MEM_PODF_LOADED (0x1 << 21) #define MXC_CCM_CIMR_MASK_AHB_PODF_LOADED_MX53 (0x1 << 20) #define MXC_CCM_CIMR_MASK_EMI_SLOW_PODF_LOADED_MX53 (0x1 << 19) +#define MX50_CCM_CIMR_MASK_WEIM_PODF_LOADED (0x1 << 19) #define MXC_CCM_CIMR_MASK_AXI_B_PODF_LOADED (0x1 << 18) #define MXC_CCM_CIMR_MASK_AXI_A_PODF_LOADED (0x1 << 17) #define MXC_CCM_CIMR_MASK_DIVIDER_LOADED (0x1 << 16) @@ -513,8 +592,8 @@ extern void __iomem *pll4_base; #define MXC_CCM_CIMR_MASK_COSC_READY_MX51 (0x1 << 5) #define MXC_CCM_CIMR_MASK_CKIH_READY (0x1 << 4) #define MXC_CCM_CIMR_MASK_FPM_READY (0x1 << 3) -/* MX53 */ -#define MXC_CCM_CIMR_MASK_COSC_READY_MX53 (0x1 << 6) +/* MX53/MX50 */ +#define MXC_CCM_CIMR_MASK_COSC_READY (0x1 << 6) #define MXC_CCM_CIMR_MASK_CAMP2_READY (0x1 << 5) #define MXC_CCM_CIMR_MASK_CAMP1_READY (0x1 << 4) #define MXC_CCM_CIMR_MASK_LRF_PLL4 (0x1 << 3) @@ -542,6 +621,13 @@ extern void __iomem *pll4_base; #define MXC_CCM_CGPR_VL_L2BIST_CLKDIV_OFFSET (0) #define MXC_CCM_CGPR_VL_L2BIST_CLKDIV_MASK (0x7) +#define MX50_CCM_CCOSR_CKO1_SLOW_SEL (0x1 << 8) +#define MX50_CCM_CCOSR_CKO1_EN (0x1 << 7) +#define MX50_CCM_CCOSR_CKO1_DIV_OFFSET (4) +#define MX50_CCM_CCOSR_CKO1_DIV_MASK (0x7 << 4) +#define MX50_CCM_CCOSR_CKO1_SEL_OFFSET (0) +#define MX50_CCM_CCOSR_CKO1_SEL_MASK (0xF) + /* Define the bits in registers CCGRx */ #define MXC_CCM_CCGR_CG_MASK 0x3 @@ -729,6 +815,82 @@ extern void __iomem *pll4_base; #define MXC_CCM_CCGR7_CG1_OFFSET 2 #define MXC_CCM_CCGR7_CG0_OFFSET 0 +/* Define the bits in registers CSR2 */ +#define MXC_CCM_CSR2_ELCDIF_PIX_BUSY (0x1 << 9) +#define MXC_CCM_CSR2_EPDC_PIX_BUSY (0x1 << 8) +#define MXC_CCM_CSR2_EPDC_AXI_BUSY (0x1 << 4) +#define MXC_CCM_CSR2_DISPLAY_AXI_BUSY (0x1 << 3) + +/* Define the bits in registers CLKSEQ_BYPASS */ +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_ELCDIF_PIX_CLK_SEL_OFFSET 14 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_ELCDIF_PIX_CLK_SEL_MASK (0x3 << 14) +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_PIX_CLK_SEL_OFFSET 12 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_PIX_CLK_SEL_MASK (0x3 << 12) +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_AXI_CLK_SEL_OFFSET 4 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_AXI_CLK_SEL_MASK (0x3 << 4) +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_DISPLAY_AXI_CLK_SEL_OFFSET 2 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_DISPLAY_AXI_CLK_SEL_MASK (0x3 << 2) + + +/* Define the bits in registers CLK_SYS */ +#define MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_OFFSET (30) +#define MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_OFFSET (28) +#define MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_MASK (0x3 << 28) +#define MXC_CCM_CLK_SYS_DIV_XTAL_OFFSET (6) +#define MXC_CCM_CLK_SYS_DIV_XTAL_MASK (0xF << 6) +#define MXC_CCM_CLK_SYS_DIV_PLL_OFFSET (0) +#define MXC_CCM_CLK_SYS_DIV_PLL_MASK (0x3F) + + +/* Define the bits in registers CLK_DDR */ +#define MXC_CCM_CLK_DDR_DDR_CLKGATE_OFFSET (30) +#define MXC_CCM_CLK_DDR_DDR_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_CLK_DDR_DDR_PFD_SEL (1 << 6) +#define MXC_CCM_CLK_DDR_DDR_DIV_PLL_OFFSET (0) +#define MXC_CCM_CLK_DDR_DDR_DIV_PLL_MASK (0x3F) + +/* Define the bits in register DISPLAY_AXI */ +#define MXC_CCM_DISPLAY_AXI_CLKGATE_OFFSET (30) +#define MXC_CCM_DISPLAY_AXI_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_DISPLAY_AXI_DIV_OFFSET (0) +#define MXC_CCM_DISPLAY_AXI_DIV_MASK (0x3F) + +/* Define the bits in register EPDC_AXI */ +#define MXC_CCM_EPDC_AXI_CLKGATE_OFFSET (30) +#define MXC_CCM_EPDC_AXI_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_EPDC_AXI_DIV_OFFSET (0) +#define MXC_CCM_EPDC_AXI_DIV_MASK (0x3F) + +/* Define the bits in register EPDCPIX */ +#define MXC_CCM_EPDC_PIX_CLKGATE_OFFSET (30) +#define MXC_CCM_EPDC_PIX_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_EPDC_PIX_CLK_PRED_OFFSET (12) +#define MXC_CCM_EPDC_PIX_CLK_PRED_MASK (0x3 << 12) +#define MXC_CCM_EPDC_PIX_CLK_PODF_OFFSET (0) +#define MXC_CCM_EPDC_PIX_CLK_PODF_MASK (0xFFF) + +/* Define the bits in register ELCDIFPIX */ +#define MXC_CCM_ELCDIFPIX_CLKGATE_OFFSET (30) +#define MXC_CCM_ELCDIFPIX_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_ELCDIFPIX_CLK_PRED_OFFSET (12) +#define MXC_CCM_ELCDIFPIX_CLK_PRED_MASK (0x3 << 12) +#define MXC_CCM_ELCDIFPIX_CLK_PODF_OFFSET (0) +#define MXC_CCM_ELCDIFPIX_CLK_PODF_MASK (0xFFF) + + +/* Define the bits in register GPMI */ +#define MXC_CCM_GPMI_CLKGATE_OFFSET (30) +#define MXC_CCM_GPMI_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_GPMI_CLK_DIV_OFFSET (0) +#define MXC_CCM_GPMI_CLK_DIV_MASK (0x3F) + +/* Define the bits in register BCH */ +#define MXC_CCM_BCH_CLKGATE_OFFSET (30) +#define MXC_CCM_BCH_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_BCH_CLK_DIV_OFFSET (0) +#define MXC_CCM_BCH_CLK_DIV_MASK (0x3F) + #define MXC_GPC_BASE (IO_ADDRESS(GPC_BASE_ADDR)) #define MXC_DPTC_LP_BASE (MXC_GPC_BASE + 0x80) #define MXC_DPTC_GP_BASE (MXC_GPC_BASE + 0x100) @@ -787,11 +949,12 @@ extern void __iomem *arm_plat_base; #define MXC_DVFSPER_PMCR1 (MXC_DVFS_PER_BASE + 0x1C) /* GPC */ -#define MXC_GPC_CNTR (MXC_GPC_BASE + 0x0) -#define MXC_GPC_PGR (MXC_GPC_BASE + 0x4) -#define MXC_GPC_VCR (MXC_GPC_BASE + 0x8) -#define MXC_GPC_ALL_PU (MXC_GPC_BASE + 0xC) -#define MXC_GPC_NEON (MXC_GPC_BASE + 0x10) +#define MXC_GPC_CNTR (MXC_GPC_BASE + 0x0) +#define MXC_GPC_PGR (MXC_GPC_BASE + 0x4) +#define MXC_GPC_VCR (MXC_GPC_BASE + 0x8) +#define MXC_GPC_CNTR_OFFSET 0x0 +#define MXC_GPC_PGR_OFFSET 0x4 +#define MXC_GPC_VCR_OFFSET 0x8 /* PGC */ #define MXC_PGC_IPU_PGCR (MXC_PGC_IPU_BASE + 0x0) diff --git a/arch/arm/mach-mx5/devices.c b/arch/arm/mach-mx5/devices.c index 06f16db88993..09188c771c9d 100644 --- a/arch/arm/mach-mx5/devices.c +++ b/arch/arm/mach-mx5/devices.c @@ -17,17 +17,20 @@ #include <linux/dma-mapping.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/ipu.h> +#include <linux/fb.h> #include <linux/delay.h> #include <linux/uio_driver.h> #include <linux/mxc_scc2_driver.h> #include <linux/iram_alloc.h> +#include <linux/gpmi-nfc.h> #include <mach/common.h> #include <mach/hardware.h> #include <mach/gpio.h> #include <mach/sdma.h> -#include "crm_regs.h" #include "mx51_pins.h" #include "devices.h" +#include "dma-apbh.h" /* Flag used to indicate when IRAM has been initialized */ int iram_ready; @@ -95,6 +98,11 @@ struct platform_device mxc_keypad_device = { .resource = mxc_kpp_resources, }; +struct platform_device mxc_powerkey_device = { + .name = "mxcpwrkey", + .id = 0, +}; + static struct resource rtc_resources[] = { { .start = SRTC_BASE_ADDR, @@ -114,9 +122,80 @@ struct platform_device mxc_rtc_device = { .resource = rtc_resources, }; +static struct resource mxc_nand_resources[] = { + { + .flags = IORESOURCE_MEM, + .name = "NFC_AXI_BASE", + .start = MX51_NFC_BASE_ADDR_AXI, + .end = MX51_NFC_BASE_ADDR_AXI + SZ_8K - 1, + }, + { + .flags = IORESOURCE_MEM, + .name = "NFC_IP_BASE", + .start = NFC_BASE_ADDR + 0x00, + .end = NFC_BASE_ADDR + 0x34 - 1, + }, + { + .flags = IORESOURCE_IRQ, + .start = MXC_INT_NFC, + .end = MXC_INT_NFC, + }, +}; + struct platform_device mxc_nandv2_mtd_device = { .name = "mxc_nandv2_flash", .id = 0, + .resource = mxc_nand_resources, + .num_resources = ARRAY_SIZE(mxc_nand_resources), +}; + +static struct resource gpmi_nfc_resources[] = { + { + .name = GPMI_NFC_GPMI_REGS_ADDR_RES_NAME, + .flags = IORESOURCE_MEM, + .start = GPMI_BASE_ADDR, + .end = GPMI_BASE_ADDR + SZ_8K - 1, + }, + { + .name = GPMI_NFC_GPMI_INTERRUPT_RES_NAME, + .flags = IORESOURCE_IRQ, + .start = MXC_INT_RAWNAND_GPMI, + .end = MXC_INT_RAWNAND_GPMI, + }, + { + .name = GPMI_NFC_BCH_REGS_ADDR_RES_NAME, + .flags = IORESOURCE_MEM, + .start = BCH_BASE_ADDR, + .end = BCH_BASE_ADDR + SZ_8K - 1, + }, + { + .name = GPMI_NFC_BCH_INTERRUPT_RES_NAME, + .flags = IORESOURCE_IRQ, + .start = MXC_INT_RAWNAND_BCH, + .end = MXC_INT_RAWNAND_BCH, + }, + { + .name = GPMI_NFC_DMA_CHANNELS_RES_NAME, + .flags = IORESOURCE_DMA, + .start = MXS_DMA_CHANNEL_AHB_APBH_GPMI0, + .end = MXS_DMA_CHANNEL_AHB_APBH_GPMI7, + }, + { + .name = GPMI_NFC_DMA_INTERRUPT_RES_NAME, + .flags = IORESOURCE_IRQ, + .start = MXC_INT_APBHDMA_CHAN0, + .end = MXC_INT_APBHDMA_CHAN7, + }, +}; + +struct platform_device gpmi_nfc_device = { + .name = GPMI_NFC_DRIVER_NAME, + .id = 0, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = gpmi_nfc_resources, + .num_resources = ARRAY_SIZE(gpmi_nfc_resources), }; static struct resource imx_nfc_resources[] = { @@ -213,6 +292,46 @@ struct platform_device mxc_pwm_backlight_device = { .id = -1, }; +static struct resource flexcan0_resources[] = { + { + .start = CAN1_BASE_ADDR, + .end = CAN1_BASE_ADDR + 0x3FFF, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_CAN1, + .end = MXC_INT_CAN1, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_flexcan0_device = { + .name = "FlexCAN", + .id = 0, + .num_resources = ARRAY_SIZE(flexcan0_resources), + .resource = flexcan0_resources, +}; + +static struct resource flexcan1_resources[] = { + { + .start = CAN2_BASE_ADDR, + .end = CAN2_BASE_ADDR + 0x3FFF, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_CAN2, + .end = MXC_INT_CAN2, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_flexcan1_device = { + .name = "FlexCAN", + .id = 1, + .num_resources = ARRAY_SIZE(flexcan1_resources), + .resource = flexcan1_resources, +}; + static struct resource ipu_resources[] = { { .start = MX51_IPU_CTRL_BASE_ADDR, @@ -236,6 +355,52 @@ struct platform_device mxc_ipu_device = { .resource = ipu_resources, }; +static struct resource epdc_resources[] = { + { + .start = EPDC_BASE_ADDR, + .end = EPDC_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_EPDC, + .end = MXC_INT_EPDC, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device epdc_device = { + .name = "mxc_epdc_fb", + .id = -1, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(epdc_resources), + .resource = epdc_resources, +}; + +static struct resource elcdif_resources[] = { + { + .start = ELCDIF_BASE_ADDR, + .end = ELCDIF_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_ELCDIF, + .end = MXC_INT_ELCDIF, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device elcdif_device = { + .name = "mxc_elcdif_fb", + .id = -1, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(elcdif_resources), + .resource = elcdif_resources, +}; + struct platform_device mxc_fb_devices[] = { { .name = "mxc_sdc_fb", @@ -260,11 +425,37 @@ struct platform_device mxc_fb_devices[] = { }, }; -struct platform_device lcd_pdev = { - .name = "ccwmx51_display", - .dev = { - .coherent_dma_mask = DMA_BIT_MASK(32), - }, +static struct resource ldb_resources[] = { + { + .start = IOMUXC_BASE_ADDR, + .end = IOMUXC_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device mxc_ldb_device = { + .name = "mxc_ldb", + .id = -1, + .num_resources = ARRAY_SIZE(ldb_resources), + .resource = ldb_resources, +}; + + +struct platform_device lcd_pdev[] = { + { + .name = "ccwmx51_display", + .id = 0, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + }, + { + .name = "ccwmx51_display", + .id = 1, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + }, }; static struct resource vpu_resources[] = { @@ -307,6 +498,53 @@ struct platform_device mxcscc_device = { .resource = scc_resources, }; +static struct resource dcp_resources[] = { + + { + .flags = IORESOURCE_MEM, + .start = DCP_BASE_ADDR, + .end = DCP_BASE_ADDR + 0x2000 - 1, + }, { + .flags = IORESOURCE_IRQ, + .start = MXC_INT_DCP_CHAN0, + .end = MXC_INT_DCP_CHAN0, + }, { + .flags = IORESOURCE_IRQ, + .start = MXC_INT_DCP_CHAN1_3, + .end = MXC_INT_DCP_CHAN1_3, + }, +}; + +struct platform_device dcp_device = { + .name = "dcp", + .id = 0, + .num_resources = ARRAY_SIZE(dcp_resources), + .resource = dcp_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + + +static struct resource rngb_resources[] = { + { + .start = RNGB_BASE_ADDR, + .end = RNGB_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_RNGB_BLOCK, + .flags = IORESOURCE_IRQ, + }, +}; + +/* the RNGC driver applies for MX50's RNGB hw */ +struct platform_device mxc_rngb_device = { + .name = "fsl_rngc", + .id = 0, + .num_resources = ARRAY_SIZE(rngb_resources), + .resource = rngb_resources, +}; static struct resource mxc_fec_resources[] = { { @@ -508,6 +746,26 @@ struct platform_device mxc_ssi2_device = { .resource = ssi2_resources, }; +static struct resource esai_resources[] = { + { + .start = ESAI_BASE_ADDR, + .end = ESAI_BASE_ADDR + 0x100, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_ESAI, + .end = MXC_INT_ESAI, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_esai_device = { + .name = "mxc_esai", + .id = 0, + .num_resources = ARRAY_SIZE(esai_resources), + .resource = esai_resources, +}; + static struct resource tve_resources[] = { { .start = TVE_BASE_ADDR, @@ -623,6 +881,8 @@ int __init mxc_register_gpios(void) { if (cpu_is_mx51()) return mxc_gpio_init(mxc_gpio_ports, 4); + else if (cpu_is_mx50()) + return mxc_gpio_init(mxc_gpio_ports, 6); return mxc_gpio_init(mxc_gpio_ports, ARRAY_SIZE(mxc_gpio_ports)); } @@ -803,9 +1063,58 @@ struct platform_device pata_fsl_device = { }, }; +/* On-Chip OTP device and resource */ +static struct resource otp_resource = { + .start = OCOTP_CTRL_BASE_ADDR, + .end = OCOTP_CTRL_BASE_ADDR + SZ_8K - 1, + .flags = IORESOURCE_MEM, +}; + +struct platform_device fsl_otp_device = { + .name = "ocotp", + .id = -1, + .resource = &otp_resource, + .num_resources = 1, +}; + +static struct resource ahci_fsl_resources[] = { + { + .start = MX53_SATA_BASE_ADDR, + .end = MX53_SATA_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_SATA, + .end = MXC_INT_SATA, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device ahci_fsl_device = { + .name = "ahci", + .id = 0, + .num_resources = ARRAY_SIZE(ahci_fsl_resources), + .resource = ahci_fsl_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + static u64 usb_dma_mask = DMA_BIT_MASK(32); -static struct resource usbotg_resources[] = { +static struct resource usbotg_host_resources[] = { + { + .start = OTG_BASE_ADDR, + .end = OTG_BASE_ADDR + 0x1ff, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_USB_OTG, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource usbotg_udc_resources[] = { { .start = OTG_BASE_ADDR, .end = OTG_BASE_ADDR + 0x1ff, @@ -836,8 +1145,8 @@ struct platform_device mxc_usbdr_udc_device = { .dma_mask = &usb_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), }, - .resource = usbotg_resources, - .num_resources = ARRAY_SIZE(usbotg_resources), + .resource = usbotg_udc_resources, + .num_resources = ARRAY_SIZE(usbotg_udc_resources), }; struct platform_device mxc_usbdr_otg_device = { @@ -854,8 +1163,8 @@ struct platform_device mxc_usbdr_otg_device = { struct platform_device mxc_usbdr_host_device = { .name = "fsl-ehci", .id = 0, - .num_resources = ARRAY_SIZE(usbotg_resources), - .resource = usbotg_resources, + .num_resources = ARRAY_SIZE(usbotg_host_resources), + .resource = usbotg_host_resources, .dev = { .dma_mask = &usb_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), @@ -970,23 +1279,31 @@ static struct resource mxc_gpu2d_resources[] = { #if defined(CONFIG_UIO_PDRV_GENIRQ) || defined(CONFIG_UIO_PDRV_GENIRQ_MODULE) static struct clk *gpu_clk; +static atomic_t *gpu_use_count; int gpu2d_open(struct uio_info *info, struct inode *inode) { - gpu_clk = clk_get(NULL, "gpu2d_clk"); - if (IS_ERR(gpu_clk)) - return PTR_ERR(gpu_clk); + int err = 0; + + if (atomic_inc_return(gpu_use_count) == 1) { + gpu_clk = clk_get(NULL, "gpu2d_clk"); + if (IS_ERR(gpu_clk)) + err = PTR_ERR(gpu_clk); - return clk_enable(gpu_clk); + err = clk_enable(gpu_clk); + } + return err; } int gpu2d_release(struct uio_info *info, struct inode *inode) { - if (IS_ERR(gpu_clk)) - return PTR_ERR(gpu_clk); + if (atomic_dec_and_test(gpu_use_count)) { + if (IS_ERR(gpu_clk)) + return PTR_ERR(gpu_clk); - clk_disable(gpu_clk); - clk_put(gpu_clk); + clk_disable(gpu_clk); + clk_put(gpu_clk); + } return 0; } @@ -1027,8 +1344,11 @@ static struct platform_device mxc_gpu2d_device = { static inline void mxc_init_gpu2d(void) { - dma_alloc_coherent(&mxc_gpu2d_device.dev, SZ_8K, &mxc_gpu2d_resources[1].start, GFP_DMA); - mxc_gpu2d_resources[1].end = mxc_gpu2d_resources[1].start + SZ_8K - 1; + void *gpu_mem; + gpu_mem = dma_alloc_coherent(&mxc_gpu2d_device.dev, SZ_64K, &mxc_gpu2d_resources[1].start, GFP_DMA); + mxc_gpu2d_resources[1].end = mxc_gpu2d_resources[1].start + SZ_64K - 1; + memset(gpu_mem, 0, SZ_64K); + gpu_use_count = gpu_mem + SZ_64K - 4; dma_alloc_coherent(&mxc_gpu2d_device.dev, 88 * SZ_1K, &mxc_gpu2d_resources[2].start, GFP_DMA); mxc_gpu2d_resources[2].end = mxc_gpu2d_resources[2].start + (88 * SZ_1K) - 1; @@ -1041,6 +1361,118 @@ static inline void mxc_init_gpu2d(void) } #endif +static struct resource mlb_resources[] = { + [0] = { + .start = MLB_BASE_ADDR, + .end = MLB_BASE_ADDR + 0x300, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MXC_INT_MLB, + .end = MXC_INT_MLB, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_mlb_device = { + .name = "mxc_mlb", + .id = 0, + .num_resources = ARRAY_SIZE(mlb_resources), + .resource = mlb_resources, +}; + +static struct resource pxp_resources[] = { + { + .start = EPXP_BASE_ADDR, + .end = EPXP_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MXC_INT_EPXP, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_pxp_device = { + .name = "mxc-pxp", + .id = -1, + .num_resources = ARRAY_SIZE(pxp_resources), + .resource = pxp_resources, +}; + +struct platform_device mxc_pxp_client_device = { + .name = "pxp-device", + .id = -1, +}; + +static u64 pxp_dma_mask = DMA_BIT_MASK(32); +struct platform_device mxc_pxp_v4l2 = { + .name = "pxp-v4l2", + .id = -1, + .dev = { + .dma_mask = &pxp_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +struct platform_device mxc_v4l2_device = { + .name = "mxc_v4l2_capture", + .id = 0, +}; + +struct platform_device mxc_v4l2out_device = { + .name = "mxc_v4l2_output", + .id = 0, +}; + +struct resource viim_resources[] = { + [0] = { + .start = (GPT1_BASE_ADDR - 0x20000000), + .end = (GPT1_BASE_ADDR - 0x20000000) + PAGE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = OCOTP_CTRL_BASE_ADDR, + .end = OCOTP_CTRL_BASE_ADDR + PAGE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; +struct platform_device mxs_viim = { + .name = "mxs_viim", + .id = -1, + .num_resources = ARRAY_SIZE(viim_resources), + .resource = viim_resources, +}; + +static struct resource dma_apbh_resources[] = { + { + .start = APBHDMA_BASE_ADDR, + .end = APBHDMA_BASE_ADDR + 0x2000 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device mxs_dma_apbh_device = { + .name = "mxs-dma-apbh", + .num_resources = ARRAY_SIZE(dma_apbh_resources), + .resource = dma_apbh_resources, +}; + +struct platform_device mxc_android_pmem_device = { + .name = "android_pmem", + .id = 0, +}; + +struct platform_device mxc_android_pmem_gpu_device = { + .name = "android_pmem", + .id = 1, +}; + +struct platform_device android_usb_device = { + .name = "android_usb", + .id = -1, +}; + void __init mx5_init_irq(void) { unsigned long tzic_addr; @@ -1049,7 +1481,7 @@ void __init mx5_init_irq(void) tzic_addr = MX51_TZIC_BASE_ADDR_T01; else if (cpu_is_mx51_rev(CHIP_REV_2_0) > 0) tzic_addr = MX51_TZIC_BASE_ADDR; - else /* mx53 */ + else /* mx53 and mx50 */ tzic_addr = MX53_TZIC_BASE_ADDR; mxc_tzic_init_irq(tzic_addr); @@ -1266,7 +1698,7 @@ exit: int __init mxc_init_devices(void) { - if (cpu_is_mx53()) { + if (cpu_is_mx53() || cpu_is_mx50()) { sdma_resources[0].start -= MX53_OFFSET; sdma_resources[0].end -= MX53_OFFSET; mxc_w1_master_resources[0].start -= MX53_OFFSET; @@ -1287,6 +1719,10 @@ int __init mxc_init_devices(void) pwm1_resources[0].end -= MX53_OFFSET; pwm2_resources[0].start -= MX53_OFFSET; pwm2_resources[0].end -= MX53_OFFSET; + flexcan0_resources[0].start -= MX53_OFFSET; + flexcan0_resources[0].end -= MX53_OFFSET; + flexcan1_resources[0].start -= MX53_OFFSET; + flexcan1_resources[0].end -= MX53_OFFSET; mxc_fec_resources[0].start -= MX53_OFFSET; mxc_fec_resources[0].end -= MX53_OFFSET; vpu_resources[0].start -= MX53_OFFSET; @@ -1295,6 +1731,8 @@ int __init mxc_init_devices(void) scc_resources[0].end -= MX53_OFFSET; scc_resources[1].start = MX53_SCC_RAM_BASE_ADDR; scc_resources[1].end = MX53_SCC_RAM_BASE_ADDR + SZ_16K - 1; + rngb_resources[0].start -= MX53_OFFSET; + rngb_resources[0].end -= MX53_OFFSET; mxcspi1_resources[0].start -= MX53_OFFSET; mxcspi1_resources[0].end -= MX53_OFFSET; mxcspi2_resources[0].start -= MX53_OFFSET; @@ -1311,8 +1749,12 @@ int __init mxc_init_devices(void) ssi1_resources[0].end -= MX53_OFFSET; ssi2_resources[0].start -= MX53_OFFSET; ssi2_resources[0].end -= MX53_OFFSET; + esai_resources[0].start -= MX53_OFFSET; + esai_resources[0].end -= MX53_OFFSET; tve_resources[0].start -= MX53_OFFSET; tve_resources[0].end -= MX53_OFFSET; + dvfs_core_resources[0].start -= MX53_OFFSET; + dvfs_core_resources[0].end -= MX53_OFFSET; dvfs_per_resources[0].start -= MX53_OFFSET; dvfs_per_resources[0].end -= MX53_OFFSET; spdif_resources[0].start -= MX53_OFFSET; @@ -1331,8 +1773,10 @@ int __init mxc_init_devices(void) mxcsdhc2_resources[0].end -= MX53_OFFSET; mxcsdhc3_resources[0].start -= MX53_OFFSET; mxcsdhc3_resources[0].end -= MX53_OFFSET; - usbotg_resources[0].start -= MX53_OFFSET; - usbotg_resources[0].end -= MX53_OFFSET; + usbotg_host_resources[0].start -= MX53_OFFSET; + usbotg_host_resources[0].end -= MX53_OFFSET; + usbotg_udc_resources[0].start -= MX53_OFFSET; + usbotg_udc_resources[0].end -= MX53_OFFSET; usbotg_xcvr_resources[0].start -= MX53_OFFSET; usbotg_xcvr_resources[0].end -= MX53_OFFSET; usbh1_resources[0].start -= MX53_OFFSET; @@ -1341,19 +1785,40 @@ int __init mxc_init_devices(void) usbh2_resources[0].end -= MX53_OFFSET; mxc_gpu_resources[2].start = MX53_GPU2D_BASE_ADDR; mxc_gpu_resources[2].end = MX53_GPU2D_BASE_ADDR + SZ_4K - 1; - mxc_gpu_resources[4].start = MX53_GPU_GMEM_BASE_ADDR; - mxc_gpu_resources[4].end = MX53_GPU_GMEM_BASE_ADDR + SZ_256K - 1; mxc_gpu2d_resources[0].start = MX53_GPU2D_BASE_ADDR; mxc_gpu2d_resources[0].end = MX53_GPU2D_BASE_ADDR + SZ_4K - 1; + if (cpu_is_mx53()) { + mxc_gpu_resources[4].start = MX53_GPU_GMEM_BASE_ADDR; + mxc_gpu_resources[4].end = MX53_GPU_GMEM_BASE_ADDR + + SZ_256K - 1; + } else { + mxc_gpu_resources[1].start = 0; + mxc_gpu_resources[1].end = 0; + mxc_gpu_resources[3].start = 0; + mxc_gpu_resources[3].end = 0; + mxc_gpu_resources[4].start = 0; + mxc_gpu_resources[4].end = 0; + } ipu_resources[0].start = MX53_IPU_CTRL_BASE_ADDR; ipu_resources[0].end = MX53_IPU_CTRL_BASE_ADDR + SZ_128M - 1; + mlb_resources[0].start -= MX53_OFFSET; + mlb_resources[0].end -= MX53_OFFSET; + mxc_nandv2_mtd_device.resource[0].start = + MX53_NFC_BASE_ADDR_AXI; + mxc_nandv2_mtd_device.resource[0].end = + MX53_NFC_BASE_ADDR_AXI + SZ_8K - 1; + mxc_nandv2_mtd_device.resource[1].start -= MX53_OFFSET; + mxc_nandv2_mtd_device.resource[1].end -= MX53_OFFSET; + ldb_resources[0].start -= MX53_OFFSET; + ldb_resources[0].end -= MX53_OFFSET; } else if (cpu_is_mx51_rev(CHIP_REV_2_0) < 0) { scc_resources[1].start += 0x8000; scc_resources[1].end += 0x8000; } + if (cpu_is_mx51() || cpu_is_mx53()) + mxc_init_scc_iram(); - mxc_init_scc_iram(); mxc_init_gpu2d(); #if defined (CONFIG_MACH_CCWMX51JS) ccwmx51_init_devices(); diff --git a/arch/arm/mach-mx5/devices.h b/arch/arm/mach-mx5/devices.h index 13b9c2838fd5..da6c6ac96428 100644 --- a/arch/arm/mach-mx5/devices.h +++ b/arch/arm/mach-mx5/devices.h @@ -27,8 +27,11 @@ extern struct platform_device mxc_wdt_device; extern struct platform_device mxc_pwm1_device; extern struct platform_device mxc_pwm2_device; extern struct platform_device mxc_pwm_backlight_device; +extern struct platform_device mxc_flexcan0_device; +extern struct platform_device mxc_flexcan1_device; extern struct platform_device mxc_ipu_device; extern struct platform_device mxc_fb_devices[]; +extern struct platform_device mxc_ldb_device; extern struct platform_device mxcvpu_device; extern struct platform_device mxcscc_device; extern struct platform_device mxcspi1_device; @@ -41,6 +44,7 @@ extern struct platform_device mxc_dvfs_core_device; extern struct platform_device mxc_dvfs_per_device; extern struct platform_device mxc_ssi1_device; extern struct platform_device mxc_ssi2_device; +extern struct platform_device mxc_esai_device; extern struct platform_device mxc_alsa_spdif_device; extern struct platform_device mx51_lpmode_device; extern struct platform_device mx53_lpmode_device; @@ -51,7 +55,9 @@ extern struct platform_device mxc_sim_device; extern struct platform_device mxcsdhc1_device; extern struct platform_device mxcsdhc2_device; extern struct platform_device mxcsdhc3_device; +extern struct platform_device ahci_fsl_device; extern struct platform_device pata_fsl_device; +extern struct platform_device fsl_otp_device; extern struct platform_device gpu_device; extern struct platform_device mxc_fec_device; extern struct platform_device mxc_usbdr_udc_device; @@ -59,6 +65,25 @@ extern struct platform_device mxc_usbdr_otg_device; extern struct platform_device mxc_usbdr_host_device; extern struct platform_device mxc_usbh1_device; extern struct platform_device mxc_usbh2_device; -extern struct platform_device lcd_pdev; +extern struct platform_device lcd_pdev[]; extern struct platform_device mxc_wm8753_device; +extern struct platform_device mxc_mlb_device; extern void __init ccwmx51_init_devices ( void ); +extern struct platform_device mxc_nandv2_mtd_device; +extern struct platform_device mxc_pxp_device; +extern struct platform_device mxc_pxp_client_device; +extern struct platform_device mxc_pxp_v4l2; +extern struct platform_device epdc_device; +extern struct platform_device elcdif_device; +extern struct platform_device mxc_v4l2_device; +extern struct platform_device mxc_v4l2out_device; +extern struct platform_device mxs_viim; +extern struct platform_device mxs_dma_apbh_device; +extern struct platform_device gpmi_nfc_device; +extern struct platform_device mxc_rngb_device; +extern struct platform_device dcp_device; +extern struct platform_device mxc_android_pmem_device; +extern struct platform_device mxc_android_pmem_gpu_device; +extern struct platform_device android_usb_device; +extern struct platform_device mxc_powerkey_device; +extern struct platform_device ccwmx51js_keys_gpio; diff --git a/arch/arm/mach-mx5/devices_ccwmx51.c b/arch/arm/mach-mx5/devices_ccwmx51.c index 4e4a07f7c4a7..27eb3dc32064 100644 --- a/arch/arm/mach-mx5/devices_ccwmx51.c +++ b/arch/arm/mach-mx5/devices_ccwmx51.c @@ -25,6 +25,7 @@ #include <linux/platform_device.h> #include <linux/fsl_devices.h> #include <linux/spi/spi.h> +#include <linux/spi/ads7846.h> #include <linux/i2c.h> #include <linux/ata.h> #include <linux/regulator/consumer.h> @@ -34,6 +35,7 @@ #include <linux/mxcfb.h> #include <linux/pwm_backlight.h> #include <linux/smsc911x.h> +#include <linux/sysfs.h> #include <mach/common.h> #include <mach/hardware.h> #include <asm/irq.h> @@ -45,6 +47,7 @@ #include <mach/gpio.h> #include <mach/mmc.h> #include <mach/mxc_dvfs.h> +#include <video/ad9389.h> #include "board-ccwmx51.h" #include "iomux.h" #include "crm_regs.h" @@ -52,6 +55,8 @@ #include "mx51_pins.h" #include "displays/displays.h" #include <linux/smc911x.h> +#include <linux/fec.h> +#include <linux/gpio_keys.h> #if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE) #include <linux/mtd/mtd.h> @@ -60,65 +65,159 @@ #include <asm/mach/flash.h> #endif -#if defined(CONFIG_MTD_NAND_MXC) \ - || defined(CONFIG_MTD_NAND_MXC_MODULE) \ - || defined(CONFIG_MTD_NAND_MXC_V2) \ - || defined(CONFIG_MTD_NAND_MXC_V2_MODULE) \ - || defined(CONFIG_MTD_NAND_MXC_V3) \ - || defined(CONFIG_MTD_NAND_MXC_V3_MODULE) +#if defined(CONFIG_VIDEO_AD9389) || defined(CONFIG_VIDEO_AD9389_MODULE) +static int debug = 0; +#endif -extern void gpio_nand_active(void); -extern void gpio_nand_inactive(void); +#define AD9389_DBG 0x0001 +#define DBG(flag, fmt, args...) do { \ + if (debug & flag) \ + printk(fmt, ## args); \ + } while (0) -static int nand_init(void) +static u8 ccwmx51_mod_variant = 0; +static u8 ccwmx51_mod_rev = 0; +static u32 ccwmx51_mod_sn = 0; +static u8 ccwmx51_bb_rev = BASE_BOARD_REV; + +void ccwmx51_set_mod_variant(u8 variant) { - /* Configure the pins */ - gpio_nand_active(); - return 0; + ccwmx51_mod_variant = variant; +} +void ccwmx51_set_mod_revision(u8 revision) +{ + ccwmx51_mod_rev = revision; +} +void ccwmx51_set_mod_sn(u32 sn) +{ + ccwmx51_mod_sn = sn; } -static void nand_exit(void) +#ifdef CONFIG_SYSFS +static ssize_t ccwmx51_mod_variant_attr_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { - /* Free the pins */ - gpio_nand_inactive(); + return snprintf(buf, PAGE_SIZE, "%d\n", ccwmx51_mod_variant); } -struct flash_platform_data mxc_nand_data = { - .width = 1, - .init = nand_init, - .exit = nand_exit, -}; -#endif +static ssize_t ccwmx51_mod_rev_attr_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ccwmx51_mod_rev); +} -#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) -struct smsc911x_platform_config ccwmx51_smsc9118 = { - .flags = SMSC911X_USE_32BIT, - .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, - .irq_type = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, /* push-pull irq */ -}; -#endif +static ssize_t ccwmx51_mod_sn_attr_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ccwmx51_mod_sn); +} + +static ssize_t cccwmx51_bb_rev_attr_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ccwmx51_bb_rev); +} + +static struct kobj_attribute ccwmx51_mod_variant_attr = + __ATTR(mod_variant, S_IRUGO, ccwmx51_mod_variant_attr_show, NULL); +static struct kobj_attribute ccwmx51_mod_rev_attr = + __ATTR(mod_rev, S_IRUGO, ccwmx51_mod_rev_attr_show, NULL); +static struct kobj_attribute ccwmx51_mod_sn_attr = + __ATTR(mod_sn, S_IRUGO, ccwmx51_mod_sn_attr_show, NULL); +static struct kobj_attribute ccwmx51_bb_rev_attr = + __ATTR(bb_rev, S_IRUGO, cccwmx51_bb_rev_attr_show, NULL); + +int ccwmx51_create_sysfs_entries(void) +{ + struct kobject *ccwmx51_kobj; + int ret; + + ccwmx51_kobj = kobject_create_and_add("ccwmx51", kernel_kobj); + if (!ccwmx51_kobj) { + printk(KERN_WARNING "kobject_create_and_add ccwmx51 failed\n"); + return -EINVAL; + } + + ret = sysfs_create_file(ccwmx51_kobj, &ccwmx51_mod_variant_attr.attr); + if (ret) { + printk(KERN_ERR + "Unable to register sysdev entry for ccwmx51 hardware variant\n"); + return ret; + } + ret = sysfs_create_file(ccwmx51_kobj, &ccwmx51_mod_rev_attr.attr); + if (ret) { + printk(KERN_ERR + "Unable to register sysdev entry for ccwmx51 hardware revision\n"); + return ret; + } + ret = sysfs_create_file(ccwmx51_kobj, &ccwmx51_mod_sn_attr.attr); + if (ret) { + printk(KERN_ERR + "Unable to register sysdev entry for ccwmx51 hardware SN\n"); + return ret; + } + ret = sysfs_create_file(ccwmx51_kobj, &ccwmx51_bb_rev_attr.attr); + if (ret) { + printk(KERN_ERR + "Unable to register sysdev entry for ccwmx51 base board hardware revision\n"); + return ret; + } + + return 0; +} +#endif /* CONFIG_SYSFS */ + +#if defined(CONFIG_HAS_EARLY_USER_LEDS) +void ccwmx51_user_led(int led, int val) +{ + __iomem void *base; + u32 reg, mask; + + if (led == 1) + mask = 1 << 10; + else if (led == 2) + mask = 1 << 9; + else + return; + + base = ioremap(GPIO3_BASE_ADDR, SZ_4K); + reg = __raw_readl(base); + + if (val) + reg |= mask; + else + reg &= ~mask; + + __raw_writel(reg, base); + iounmap(base); +} +#endif /* CONFIG_HAS_EARLY_USER_LEDS */ #if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE) static int sdhc_write_protect(struct device *dev) { - unsigned short rc = 0; + unsigned short rc = 0; - if (to_platform_device(dev)->id == 0) - rc = 0; /* Not supported WP on JSK board, therefore write is enabled */ - else if (to_platform_device(dev)->id == 2) - rc = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_NANDF_CS1)); - return rc; + if (to_platform_device(dev)->id == 0) + rc = 0; /* Not supported WP on JSK board, therefore write is enabled */ + else if (to_platform_device(dev)->id == 2) + rc = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_NANDF_CS1)); + return rc; } static unsigned int sdhc_get_card_det_status(struct device *dev) { - int ret = 0; + int ret = 1; - if (to_platform_device(dev)->id == 0) - ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_0)); - else if (to_platform_device(dev)->id == 2) - ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO_NAND)); - return ret; + if (to_platform_device(dev)->id == 0) +#ifdef CONFIG_JSCCWMX51_V1 + ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_0)); +#else + ret = 0; +#endif + else if (to_platform_device(dev)->id == 2) + ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO_NAND)); + return ret; } struct mxc_mmc_platform_data mmc1_data = { @@ -135,7 +234,7 @@ struct mxc_mmc_platform_data mmc1_data = { struct mxc_mmc_platform_data mmc3_data = { .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | - MMC_VDD_31_32, + MMC_VDD_31_32, .caps = MMC_CAP_4_BIT_DATA, .min_clk = 150000, .max_clk = 50000000, @@ -145,12 +244,73 @@ struct mxc_mmc_platform_data mmc3_data = { .clock_mmc = "esdhc_clk", .power_mmc = NULL, }; + +void ccwmx51_register_sdio(int interface) +{ + switch (interface) { + case 0: + mxcsdhc1_device.resource[2].start = CCWMX51_SD1_CD_IRQ; + mxcsdhc1_device.resource[2].end = CCWMX51_SD1_CD_IRQ; + mxc_register_device(&mxcsdhc1_device, &mmc1_data); + break; + case 2: + mxcsdhc3_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO_NAND); + mxcsdhc3_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO_NAND); + mxc_register_device(&mxcsdhc3_device, &mmc3_data); + break; + } +} +#endif + +#if defined(CONFIG_MTD_NAND_MXC) \ + || defined(CONFIG_MTD_NAND_MXC_MODULE) \ + || defined(CONFIG_MTD_NAND_MXC_V2) \ + || defined(CONFIG_MTD_NAND_MXC_V2_MODULE) \ + || defined(CONFIG_MTD_NAND_MXC_V3) \ + || defined(CONFIG_MTD_NAND_MXC_V3_MODULE) + +extern void gpio_nand_active(void); +extern void gpio_nand_inactive(void); + +static int nand_init(void) +{ + /* Configure the pins */ + gpio_nand_active(); + return 0; +} + +static void nand_exit(void) +{ + /* Free the pins */ + gpio_nand_inactive(); +} + +struct flash_platform_data mxc_nand_data = { + .width = 1, + .init = nand_init, + .exit = nand_exit, +}; +#endif + +#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) +struct smsc911x_platform_config ccwmx51_smsc9118 = { + .flags = SMSC911X_USE_32BIT, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, /* push-pull irq */ +}; #endif #if defined(CONFIG_FB_MXC_SYNC_PANEL) || defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) -struct resource mxcfb_resources[1] = { +struct resource mxcfb_resources[2] = { { - .flags = IORESOURCE_MEM, + .flags = IORESOURCE_MEM, + .start = 0, + .end = 0, + }, + { + .flags = IORESOURCE_MEM, + .start = 0, + .end = 0, }, }; #endif @@ -158,13 +318,24 @@ struct resource mxcfb_resources[1] = { static struct i2c_board_info ccwmx51_i2c_devices[] __initdata = { #if defined(CONFIG_INPUT_MMA7455L) || defined(CONFIG_INPUT_MMA7455L_MODULE) { - I2C_BOARD_INFO("mma7455l", 0x1d), + I2C_BOARD_INFO("mma7455l", 0x1d), .irq = IOMUX_TO_IRQ(MX51_PIN_GPIO1_7), }, #endif #if defined(CONFIG_SND_SOC_IMX_CCWMX51_WM8753) || defined(CONFIG_SND_SOC_IMX_CCWMX51_WM8753_MODULE) { - I2C_BOARD_INFO("wm8753", 0x1A), + I2C_BOARD_INFO("wm8753", 0x1A), + }, +#endif + +#if defined (CONFIG_MXC_CAMERA_MICRON111_1) || defined(CONFIG_MXC_CAMERA_MICRON111_1_MODULE) + { + I2C_BOARD_INFO("mt9v111_1", 0xB8>>1), + }, +#endif +#if defined (CONFIG_MXC_CAMERA_MICRON111_2) || defined(CONFIG_MXC_CAMERA_MICRON111_2_MODULE) + { + I2C_BOARD_INFO("mt9v111_2", 0x90>>1), }, #endif }; @@ -183,16 +354,54 @@ struct mxc_i2c_platform_data mxci2c_hs_data = { }; #if defined(CONFIG_SPI_MXC_SELECT1_SS1) && (defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE)) +#if defined(CONFIG_CCWMX51_SECOND_TOUCH) +static int touch_pendown_state(void) +{ + return gpio_get_value(IOMUX_TO_GPIO(SECOND_TS_IRQ_PIN)) ? 0 : 1; +} + +static struct ads7846_platform_data ccwmx51js_touch_data = { + .model = 7843, + .x_min = 0, + .y_min = 0, + .x_max = 4095, + .y_max = 4095, + .get_pendown_state = touch_pendown_state, + .buflen = 10, + .skip_samples = 2, + .rotate = 0, +}; + +static struct spi_board_info ccwmx51_2nd_touch[] = { + { + .modalias = "ads7846", + .max_speed_hz = 500000, + .irq = IOMUX_TO_IRQ(SECOND_TS_IRQ_PIN), + .bus_num = 1, + .chip_select = 3, + .platform_data = &ccwmx51js_touch_data, + }, +}; + +void ccwmx51_init_2nd_touch(void) +{ + ccwmx51_2nd_touch_gpio_init(); + spi_register_board_info(ccwmx51_2nd_touch, ARRAY_SIZE(ccwmx51_2nd_touch)); +} +#else +void ccwmx51_init_2nd_touch(void) {} +#endif + static struct spi_board_info spi_devices[] = { #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) - { /* SPIDEV */ - .modalias = "spidev", - .max_speed_hz = 6000000, - .bus_num = 1, - .chip_select = 1, + { /* SPIDEV */ + .modalias = "spidev", + .max_speed_hz = 6000000, + .bus_num = 1, + .chip_select = 1, }, - /* Add here other SPI devices, if any... */ #endif + /* Add here other SPI devices, if any... */ }; void ccwmx51_init_spidevices(void) @@ -234,7 +443,7 @@ struct mxc_w1_config mxc_w1_data = { #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) static struct resource smsc911x_device_resources[] = { - { + { .name = "smsc911x-memory", .start = CS5_BASE_ADDR, .end = CS5_BASE_ADDR + SZ_4K - 1, @@ -248,10 +457,10 @@ static struct resource smsc911x_device_resources[] = { }; struct platform_device smsc911x_device = { - .name = "smsc911x", - .id = -1, - .num_resources = ARRAY_SIZE(smsc911x_device_resources), - .resource = smsc911x_device_resources, + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(smsc911x_device_resources), + .resource = smsc911x_device_resources, }; /* WEIM registers */ @@ -261,9 +470,9 @@ struct platform_device smsc911x_device = { #define CSRCR2 0x0C #define CSWCR1 0x10 -static void __init ccwmx51_init_ext_eth_mac(void) +static void ccwmx51_init_ext_eth_mac(void) { - __iomem u32 *weim_vbaddr; + __iomem void *weim_vbaddr; weim_vbaddr = ioremap(WEIM_BASE_ADDR, SZ_4K); if (weim_vbaddr == 0) { @@ -276,11 +485,11 @@ static void __init ccwmx51_init_ext_eth_mac(void) * RWSC=50, RADVA=2, RADVN=6, OEA=0, OEN=0, RCSA=0, RCSN=0, APR=0 * WAL=0, WBED=1, WWSC=50, WADVA=2, WADVN=6, WEA=0, WEN=0, WCSA=0 */ - writel(0x00420081, (unsigned int)(weim_vbaddr) + 0x78 + CSGCR1); - writel(0, (unsigned int)(weim_vbaddr) + 0x78 + CSGCR2); - writel(0x32260000, (unsigned int)(weim_vbaddr) + 0x78 + CSRCR1); - writel(0, (unsigned int)(weim_vbaddr) + 0x78 + CSRCR2); - writel(0x72080f00, (unsigned int)(weim_vbaddr) + 0x78 + CSWCR1); + __raw_writel(0x00420081, (u32)weim_vbaddr + 0x78 + CSGCR1); + __raw_writel(0, (u32)weim_vbaddr + 0x78 + CSGCR2); + __raw_writel(0x32260000, (u32)weim_vbaddr + 0x78 + CSRCR1); + __raw_writel(0, (u32)weim_vbaddr + 0x78 + CSRCR2); + __raw_writel(0x72080f00, (u32)weim_vbaddr + 0x78 + CSWCR1); iounmap(weim_vbaddr); @@ -314,15 +523,11 @@ struct mxc_dvfs_platform_data dvfs_core_data = { .reg_id = "SW1", .clk1_id = "cpu_clk", .clk2_id = "gpc_dvfs_clk", - .gpc_cntr_reg_addr = MXC_GPC_CNTR, - .gpc_vcr_reg_addr = MXC_GPC_VCR, - .ccm_cdcr_reg_addr = MXC_CCM_CDCR, - .ccm_cacrr_reg_addr = MXC_CCM_CACRR, - .ccm_cdhipr_reg_addr = MXC_CCM_CDHIPR, - .dvfs_thrs_reg_addr = MXC_DVFSTHRS, - .dvfs_coun_reg_addr = MXC_DVFSCOUN, - .dvfs_emac_reg_addr = MXC_DVFSEMAC, - .dvfs_cntr_reg_addr = MXC_DVFSCNTR, + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, .prediv_mask = 0x1F800, .prediv_offset = 11, .prediv_val = 3, @@ -356,6 +561,11 @@ struct mxc_dvfsper_data dvfs_per_data = { .lp_low = 1200000, }; +struct fec_platform_data fec_data = { + .phy = PHY_INTERFACE_MODE_MII, + .phy_mask = ~1UL, +}; + struct platform_pwm_backlight_data mxc_pwm_backlight_data = { .pwm_id = 0, .max_brightness = 255, @@ -364,90 +574,649 @@ struct platform_pwm_backlight_data mxc_pwm_backlight_data = { }; struct mxc_audio_platform_data wm8753_data = { - .ssi_num = 1, - .src_port = 2, - .ext_port = 3, - .sysclk = 12000000, + .ssi_num = 1, + .src_port = 2, + .ext_port = 3, + .sysclk = 0 /* Set on the fly */, }; -struct mxc_fb_platform_data mx51_fb_data[] = { - /*VGA*/ +struct mxc_fb_platform_data mx51_fb_data[2] = { + /* DISP0 */ { - .interface_pix_fmt = IPU_PIX_FMT_RGB24, - .mode_str = "1024x768M-16@60", /* Default */ + .interface_pix_fmt = VIDEO_PIX_FMT, + .mode_str = "1024x768M-16@60", /* Default */ + }, + /* DISP1 */ + { + .interface_pix_fmt = IPU_PIX_FMT_RGB666, + .mode_str = "800x480-16@60", /* Default */ } }; -#if defined(CONFIG_UIO_PDRV_GENIRQ) || defined(CONFIG_UIO_PDRV_GENIRQ_MODULE) -struct uio_info gpu2d_platform_data = { - .name = "imx_gpu2d", - .version = "1", - .irq = MXC_INT_GPU2_IRQ, - .open = gpu2d_open, - .release = gpu2d_release, - .mmap = gpu2d_mmap, -}; + +#if defined(CONFIG_KEYBOARD_GPIO) + +#define GPIO_BUTTON(gpio_num, ev_type, ev_code, act_low, descr) \ +{ \ + .gpio = gpio_num, \ + .type = ev_type, \ + .code = ev_code, \ + .active_low = act_low, \ + .desc = "btn " descr, \ +} + +#define GPIO_BUTTON_LOW(gpio_num, event_code, description) \ + GPIO_BUTTON(gpio_num, EV_KEY, event_code, 1, description) + +// user key 1 +#if defined(CONFIG_JSCCWMX51_V2) +#define USER_KEY2_GPIO_NR 70 +#else +#define USER_KEY2_GPIO_NR 8 #endif +// user key 2 +#define USER_KEY1_GPIO_NR 1 + +static struct gpio_keys_button ccwmx51js_gpio_keys[] = { + GPIO_BUTTON_LOW(USER_KEY1_GPIO_NR, KEY_MENU, "menu"), + GPIO_BUTTON_LOW(USER_KEY2_GPIO_NR, KEY_HOME, "home"), +}; + + +struct gpio_keys_platform_data ccwmx51js_gpio_key_info = { + .buttons = ccwmx51js_gpio_keys, + .nbuttons = ARRAY_SIZE(ccwmx51js_gpio_keys), +}; + +struct platform_device ccwmx51js_keys_gpio = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &ccwmx51js_gpio_key_info, + }, +}; +#endif // KEYBOARD_GPIO #if defined(CONFIG_FB_MXC_SYNC_PANEL) || defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) -struct ccwmx51_lcd_pdata * plcd_platform_data; +struct ccwmx51_lcd_pdata plcd_platform_data[2]; + +#if defined(CONFIG_VIDEO_AD9389) || defined(CONFIG_VIDEO_AD9389_MODULE) +static u32 ccwmx51_get_max_video_pclk(void) +{ + /** + * TODO get this value from the clock subsystem. + * 133MHz seems to cause problems with the ext clk. + */ + return KHZ2PICOS(132000); +} +#endif + +#if defined(CONFIG_CCWMX51_DISP1) +static char *video2_options[FB_MAX] __read_mostly; +static int ofonly2 __read_mostly; + +int fb2_get_options(char *name, char **option) +{ + char *opt, *options = NULL; + int opt_len, retval = 0; + int name_len = strlen(name), i; + + if (name_len && ofonly2 && strncmp(name, "offb", 4)) + retval = 1; + + if (name_len && !retval) { + for (i = 0; i < FB_MAX; i++) { + if (video2_options[i] == NULL) + continue; + opt_len = strlen(video2_options[i]); + if (!opt_len) + continue; + opt = video2_options[i]; + if (!strncmp(name, opt, name_len) && + opt[name_len] == ':') + options = opt + name_len + 1; + } + } + if (options && !strncmp(options, "off", 3)) + retval = 1; + + if (option) + *option = options; + + return retval; +} + +static int __init video2_setup(char *options) +{ + int i, global = 0; + + if (!options || !*options) + global = 1; + + if (!global && !strncmp(options, "ofonly", 6)) { + ofonly2 = 1; + global = 1; + } -struct ccwmx51_lcd_pdata * ccwmx51_get_display(char *name) + if (!global && !strstr(options, "fb:")) { + fb_mode_option = options; + global = 1; + } + + if (!global) { + for (i = 0; i < FB_MAX; i++) { + if (video2_options[i] == NULL) { + video2_options[i] = options; + break; + } + } + } + + return 1; +} +__setup("video2=", video2_setup); +#endif /* defined(CONFIG_CCWMX51_DISP1) */ + +struct ccwmx51_lcd_pdata * ccwmx51_find_video_config(struct ccwmx51_lcd_pdata list[], + int len, + const char *name) { -#if defined(CONFIG_CCWMX51_LQ070Y3DG3B) || defined(CONFIG_CCWMX51_CUSTOM) int i; - for (i = 0; i < ARRAY_SIZE(lcd_display_list); i++) - if (!strncmp(lcd_display_list[i].fb_pdata.mode->name, - name, strlen(lcd_display_list[i].fb_pdata.mode->name))) - return &lcd_display_list[i]; + for (i = 0; i < len; i++) + if (!strncmp(list[i].fb_pdata.mode->name, + name, strlen(list[i].fb_pdata.mode->name))) + return &list[i]; + return NULL; +} + +static char *ccwmx51_get_video_cmdline_opt(int dispif, const char *str) +{ + char *options = NULL; + int ret = 1; + int len = strlen(str); + +#if defined(CONFIG_CCWMX51_DISP0) + if (dispif == 0) { + ret = fb_get_options("displayfb", &options); + } #endif +#if defined(CONFIG_CCWMX51_DISP1) + if (dispif == 1) { + ret = fb2_get_options("displayfb", &options); + } +#endif + if (ret || !options) + return NULL; + if (!len || !strncasecmp(options, str, len)) + return &options[len]; + return NULL; } -int __init ccwmx51_init_fb(void) +#if defined(CONFIG_VIDEO_AD9389) || defined(CONFIG_VIDEO_AD9389_MODULE) +static void fb_dump_mode(const char *str, const struct fb_videomode *vm) +{ + if (!(debug & AD9389_DBG)) + return; + if (vm == NULL) + return; + + printk(KERN_INFO "%s geometry %u %u %u\n", + str, vm->xres, vm->yres, vm->pixclock); + printk(KERN_INFO "%s timings %u %u %u %u %u %u %u\n", str, vm->pixclock, vm->left_margin, + vm->right_margin, vm->upper_margin, vm->lower_margin, vm->hsync_len, vm->vsync_len); + printk(KERN_INFO "%s flag %u sync %u vmode %u %s\n", str, vm->flag, vm->sync, vm->vmode, + vm->flag & FB_MODE_IS_FIRST ? "preferred" : ""); +} + +static void fb_dump_var(const char *str, struct fb_var_screeninfo *var) { - char *options = NULL, *p; + if (!(debug & AD9389_DBG)) + return; + if (var == NULL) + return; - if (fb_get_options("displayfb", &options)) - pr_warning("no display information available in command line\n"); + printk(KERN_INFO "%s geometry %u %u %u %u\n", + str, var->xres, var->yres, var->xres_virtual, var->yres_virtual); + printk(KERN_INFO "%s offset %u %u %u %u %u\n", + str, var->xoffset, var->yoffset, var->height, var->width, var->bits_per_pixel); + printk(KERN_INFO "%s timings %u %u %u %u %u %u %u\n", + str, var->pixclock, var->left_margin, var->right_margin, + var->upper_margin, var->lower_margin, var->hsync_len, var->vsync_len); + printk(KERN_INFO "%s accel_flags %u sync %u vmode %u\n", + str, var->accel_flags, var->sync, var->vmode); + printk(KERN_INFO "%d bpp\n", var->bits_per_pixel); +} - if (!options) - return -ENODEV; +enum hdmi_mode get_hdmi_mode(struct ad9389_dev *ad9389, struct fb_videomode **vm, char **str, unsigned int *vpclk, int *ext_clk) +{ + struct ad9389_pdata *pdata = ad9389->client->dev.platform_data; + struct ccwmx51_lcd_pdata *panel; + char *p, *temp; - if (!strncasecmp(options, "VGA", 3)) { - pr_info("VGA interface is primary\n"); + if ((p = ccwmx51_get_video_cmdline_opt(pdata->dispif, "HDMI")) != NULL) { + DBG(AD9389_DBG, "HDMI: %s config on DISP%d\n", p, pdata->dispif); /* Get the desired configuration provided by the bootloader */ - if (options[3] != '@') { - pr_info("Video resolution for VGA interface not provided, using default\n"); - /* TODO set default video here */ + if (vpclk != NULL ) { + *vpclk = 0; + /* Parse pclk, it was passed through cmdline */ + if ((temp = strstr(p, "pclk=")) != NULL) { + *vpclk = (unsigned int)simple_strtoul(temp + 5, NULL, 10); + if (*vpclk < ccwmx51_get_max_video_pclk()) + *vpclk = 0; + } + DBG(AD9389_DBG, "HDMI: using cmdline pclk %d\n", *vpclk); + } + if (ext_clk != NULL ) { + /* For single display, default is internal clk and can be overrided by cmdline */ +#if !defined(CONFIG_CCWMX51_DISP0) || !defined(CONFIG_CCWMX51_DISP1) + *ext_clk = 1; +#else + *ext_clk = 0; +#endif + /* Parse ext_clk, it was passed through cmdline */ + if ((temp = strstr(p, "int_clk")) != NULL) + *ext_clk = 0; + if ((temp = strstr(p, "ext_clk")) != NULL) + *ext_clk = 1; + DBG(AD9389_DBG, "HDMI: using %s\n", ext_clk ? "ext_clk" : "int_clk"); + } + if (*p++ != '@') { + pr_info("Video resolution for HDMI interface not provided, using auto\n"); + return MODE_AUTO; + } else if (!strncasecmp(p, "auto@", 5)) { + *str = p + 5; + if ((temp = strchr(*str, ',')) != NULL) + *temp = '\0'; + DBG(AD9389_DBG, "HDMI: auto string %s\n", *str); + return MODE_AUTO_STRING; + } else if (!strncasecmp(p, "auto", 4)) { + DBG(AD9389_DBG, "HDMI: auto\n"); + return MODE_AUTO; + } else if ((panel = ccwmx51_find_video_config(ad9389_panel_list, + ARRAY_SIZE(ad9389_panel_list), + p)) != NULL) { + *vm = panel->fb_pdata.mode; + memcpy(&mx51_fb_data[pdata->dispif], + &plcd_platform_data[pdata->dispif].fb_pdata, + sizeof(struct mxc_fb_platform_data)); + DBG(AD9389_DBG, "HDMI: forced mode\n"); + return MODE_FORCED; } else { - options = &options[4]; - if (((p = strsep (&options, "@")) != NULL) && *p) { - if (!strcmp(p, "640x480x16")) { - strcpy(mx51_fb_data[0].mode_str, "640x480M-16@60"); - } else if (!strcmp(p, "800x600x16")) { - strcpy(mx51_fb_data[0].mode_str, "800x600M-16@60"); - } else if (!strcmp(p, "1024x768x16")) { - strcpy(mx51_fb_data[0].mode_str, "1024x768M-16@60"); - } else if (!strcmp(p, "1280x1024x16")) { - strcpy(mx51_fb_data[0].mode_str, "1280x1024M-16@60"); - } else - pr_warning("Unsuported video resolution: %s, using default\n", p); + *str = p; + if ((temp = strchr(*str, ',')) != NULL) + *temp = '\0'; + DBG(AD9389_DBG, "HDMI: string %s\n", *str); + return MODE_STRING; + } + } + return MODE_UNKNOWN; +} + +#define AD9389_STR_LEN 30 +static void mxc_videomode_to_var(struct ad9389_dev *ad9389, struct fb_var_screeninfo *var) +{ + struct fb_info *info = ad9389->fbi; + const struct fb_videomode *fbvmode = NULL; + char *modestr = NULL, str[AD9389_STR_LEN]; + unsigned int tpclk; + int modeidx, ext_clk; + enum hdmi_mode mode; + + var->bits_per_pixel = CONFIG_CCWMX51_DEFAULT_VIDEO_BPP; /* Set default bpp */ + /* First, check if we have a predefined mode through the kernel command line */ + mode = get_hdmi_mode(ad9389, (struct fb_videomode **)&fbvmode, &modestr, &tpclk, &ext_clk); + if (mode == MODE_AUTO) { + /* auto, or no video mode provided */ + strncpy(str, "HDMI auto selected mode:", AD9389_STR_LEN - 1); + fbvmode = fb_find_best_mode(var, &info->modelist); + if (!fbvmode) { + fbvmode = fb_find_best_display(&info->monspecs, &info->modelist); + if (!fbvmode) { + printk(KERN_WARNING + "HDMI: unable to find a valid video mode/screen," + " try forcing a mode\n"); + /* Use default... */ + fbvmode = &ad9389_1024x768x24; + strncpy(str, "HDMI default mode:", AD9389_STR_LEN - 1); } } - } else { - if ((plcd_platform_data = ccwmx51_get_display(options)) != NULL) { - memcpy(&mx51_fb_data[0], &plcd_platform_data->fb_pdata, sizeof(struct mxc_fb_platform_data)); - plcd_platform_data->vif = 0; /* Select video interface 0 */ + } else if (mode == MODE_FORCED) { + /* Selected video mode through cmd line parameters provided */ + strncpy(str, "HDMI forced mode:", AD9389_STR_LEN - 1); + } else if ((mode == MODE_STRING || mode == MODE_AUTO_STRING) && modestr) { + DBG(AD9389_DBG, "HDMI mode string: %s\n", modestr); + modeidx = fb_find_mode(var, info, modestr, + info->monspecs.modedb, + info->monspecs.modedb_len, + NULL, var->bits_per_pixel); + if (!(modeidx == 1 || modeidx == 1)) { + DBG(AD9389_DBG, "HDMI: unable to find valid mode (%s)\n", modestr); + return; } + strncpy(str, "HDMI string mode:", AD9389_STR_LEN - 1); + } + str[AD9389_STR_LEN - 1] = 0; + if ((mode == MODE_AUTO) || (mode == MODE_FORCED)) { + fb_dump_mode(str, fbvmode); + fb_videomode_to_var(var, fbvmode); } + + if (ext_clk) + var->sync |= FB_SYNC_EXT; + + /* Check if clock must be readjusted */ + if (tpclk != 0) + var->pixclock = tpclk; + + fb_dump_var(str, var); +} + +/** + * This function parses the list of supported video modes (got from fb_edid_to_monspecs) and + * filters out not supported configurations + */ +static void mxcfb_vmode_to_modelist(struct fb_videomode *modedb, int num, + struct list_head *head, struct fb_var_screeninfo *var) +{ + int i, xres = 0, yres = 0, aspratio = 0; + + INIT_LIST_HEAD(head); + + /** + * Add the modes we got through the monitor specs, filtering out those + * unsupported configurations. + */ + for (i = 0; i < num; i++) { + struct list_head *pos, *n; + struct fb_modelist *modelist; + int remove, vmaspratio; + + remove = 0; + vmaspratio = -1; + + /* Use the preferred mode to compute the aspect ratio */ + if (modedb[i].flag & FB_MODE_IS_FIRST) { + DBG(AD9389_DBG, "PREFERRED: %ux%u%s%u pclk=%u\n", + modedb[i].xres, modedb[i].yres, + (modedb[i].vmode & FB_VMODE_INTERLACED ) ? "i@" : "@", + modedb[i].refresh, modedb[i].pixclock); + + aspratio = modedb[i].xres * 10 / modedb[i].yres; + DBG(AD9389_DBG, "Aspect Ratio: %d\n", aspratio); + } + + if (modedb[i].yres) + vmaspratio = modedb[i].xres * 10 / modedb[i].yres; + + if (vmaspratio != aspratio) { + DBG(AD9389_DBG, "REMOVED: %ux%u%s%u pclk=%u (aspect ratio)\n", + modedb[i].xres, modedb[i].yres, + (modedb[i].vmode & FB_VMODE_INTERLACED ) ? "i@" : "@", + modedb[i].refresh, modedb[i].pixclock); + continue; + } + + /* Interlaced not supported */ + if (modedb[i].vmode & FB_VMODE_INTERLACED) { + DBG(AD9389_DBG, "REMOVED: %ux%u%s%u pclk=%u (interlaced modes not supported)\n", + modedb[i].xres, modedb[i].yres, + (modedb[i].vmode & FB_VMODE_INTERLACED ) ? "i@" : "@", + modedb[i].refresh, modedb[i].pixclock); + continue; + } + + /* If clock exceeds the max pixel clock supported, remove that video mode */ + if ((modedb[i].pixclock * 115 / 100) < ccwmx51_get_max_video_pclk()) { + DBG(AD9389_DBG, "REMOVED: %ux%u%s%u pclk=%u (exceed %u limit)\n", + modedb[i].xres, modedb[i].yres, + (modedb[i].vmode & FB_VMODE_INTERLACED ) ? "i@" : "@", + modedb[i].refresh, modedb[i].pixclock, ccwmx51_get_max_video_pclk()); + continue; + } + + /* If over the pixel clock limix, but close enough, set the max pixel clock freq */ + if (modedb[i].pixclock < ccwmx51_get_max_video_pclk()) + modedb[i].pixclock = ccwmx51_get_max_video_pclk(); + + /** + * Adjust timing to IPU restrictions (better done here, to avoid ipu driver to + * incorrectly calculate settings based on our configuration). + */ + if (modedb[i].lower_margin < 2) { + /* This will not affect much, so we dont adjust the pixel clock */ + DBG(AD9389_DBG, "ADJUSTED: lower margin from %u to 2\n", + modedb[i].lower_margin); + modedb[i].lower_margin = 2; + } + + /** + * Remove duplicated modes, selecting the best modes accordingly to the + * platform video constraints. + */ + list_for_each_safe(pos, n, head) { + modelist = list_entry(pos, struct fb_modelist, list); + + if ((modelist->mode.xres == modedb[i].xres) && + (modelist->mode.yres == modedb[i].yres)) { + + if (modedb[i].pixclock == ccwmx51_get_max_video_pclk()) { + /* If current mode pixclk is set to max clock, do not + * add this mode and use the existing one. */ + remove = 1; + } else if ((modelist->mode.refresh == modedb[i].refresh) && + (modedb[i].flag & FB_MODE_IS_DETAILED)) { + DBG(AD9389_DBG, "REMOVED: %ux%u%s%u pclk=%u (duplicated)\n", + modelist->mode.xres, modelist->mode.yres, + (modelist->mode.vmode & FB_VMODE_INTERLACED ) ? "i@" : "@", + modelist->mode.refresh, modelist->mode.pixclock); + list_del(pos); + kfree(pos); + } else { + /* Do not add this mode, it is not a detailed timing */ + remove = 1; + } + } + } + + if (!remove) { + fb_add_videomode(&modedb[i], head); + DBG(AD9389_DBG, "ADDING: Video mode %ux%u%s%u pclk=%u, %s detailed\n", + modedb[i].xres, modedb[i].yres, + (modedb[i].vmode & FB_VMODE_INTERLACED ) ? "i@" : "@", + modedb[i].refresh, modedb[i].pixclock, + (modedb[i].flag & FB_MODE_IS_DETAILED) ? "" : "no"); + + if (modedb[i].xres > xres && modedb[i].yres > yres) { + xres = modedb[i].xres; + yres = modedb[i].yres; + } + } + } + + /* Update var->xres and var->yres, used to determine the best video mode*/ + if (var->xres != xres || var->yres != yres) { + var->xres = xres; + var->yres = yres; + } +} + +static int ccwmx51_hdmi_hw_init(struct ad9389_dev *ad9389) +{ + struct ad9389_pdata *pdata = ad9389->client->dev.platform_data; + + if (pdata->dispif == 0) { + mxc_request_iomux(AD9389_GPIO_IRQ, IOMUX_CONFIG_GPIO | IOMUX_CONFIG_SION); + mxc_iomux_set_pad(AD9389_GPIO_IRQ, PAD_CTL_SRE_SLOW | PAD_CTL_DRV_MEDIUM | + PAD_CTL_100K_PU | PAD_CTL_HYS_ENABLE | + PAD_CTL_DRV_VOT_HIGH); + + gpio_request(IOMUX_TO_GPIO(AD9389_GPIO_IRQ), "ad9389_irq"); + gpio_direction_input(IOMUX_TO_GPIO(AD9389_GPIO_IRQ)); + + set_irq_type(IOMUX_TO_GPIO(AD9389_GPIO_IRQ), IRQ_TYPE_EDGE_BOTH); + } + + /* Configure here the hot plug detection for HDMI on DISP1 */ + /* if (pdata->dispif == 1) { } */ + + gpio_video_active(pdata->dispif, + PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST); + return 0; } -device_initcall(ccwmx51_init_fb); + +static void ccwmx51_hdmi_disp_connected(struct ad9389_dev *ad9389) +{ + printk(KERN_DEBUG "%s: display connected\n", __func__); +} + +static void ccwmx51_hdmi_disp_disconnected(struct ad9389_dev *ad9389) +{ + printk(KERN_DEBUG "%s: display disconnected\n", __func__); +} + +static struct ad9389_pdata hdmi_pdata = { + .hw_init = &ccwmx51_hdmi_hw_init, + .disp_connected = &ccwmx51_hdmi_disp_connected, + .disp_disconnected = &ccwmx51_hdmi_disp_disconnected, + .vmode_to_modelist = &mxcfb_vmode_to_modelist, + .vmode_to_var = &mxc_videomode_to_var, + .edid_addr = (0x7e >> 1), + .dispif = 0, +}; + +struct i2c_board_info ccwmx51_hdmi[] __initdata = { + { + I2C_BOARD_INFO("ad9389", 0x39), + .irq = IOMUX_TO_IRQ(AD9389_GPIO_IRQ), + .platform_data = &hdmi_pdata, + }, +}; +#endif + +#define MAX_VIDEO_IF 2 +int __init ccwmx51_init_fb(void) +{ + struct ccwmx51_lcd_pdata *panel; + char *p, *mstr; + int i; + + plcd_platform_data[0].vif = -1; + plcd_platform_data[1].vif = -1; + + for (i = 0; i < MAX_VIDEO_IF; i++) { +#if !defined(CONFIG_CCWMX51_DISP0) + if (i == 0) continue; +#endif +#if !defined(CONFIG_CCWMX51_DISP1) + if (i == 1) continue; +#endif + if ((p = ccwmx51_get_video_cmdline_opt(i, "HDMI")) != NULL) { +#if defined(CONFIG_VIDEO_AD9389) || defined(CONFIG_VIDEO_AD9389_MODULE) + pr_info("HDMI interface in DISP%d\n", i); + i2c_register_board_info(1, ccwmx51_hdmi, 1); +#else + pr_info("HDMI selected in DISP%d, but driver unavailable\n", i); + continue; +#endif + } else if ((p = ccwmx51_get_video_cmdline_opt(i, "LCD")) != NULL) { + pr_info("LCD interface in DISP%d", i); + if (*p++ != '@') { + pr_info("Panel not provided, video interface will be disabled\n"); + continue; + } + if ((panel = ccwmx51_find_video_config(lcd_panel_list, + ARRAY_SIZE(lcd_panel_list), + p)) != NULL) { + pr_info("Panel: %s", p); + memcpy(&plcd_platform_data[i], + panel, + sizeof(struct ccwmx51_lcd_pdata)); + memcpy(&mx51_fb_data[i], + &plcd_platform_data[i].fb_pdata, + sizeof(struct mxc_fb_platform_data)); + plcd_platform_data[i].vif = i; + mxc_register_device(&lcd_pdev[i], (void *)&plcd_platform_data[i]); + } + } else if ((p = ccwmx51_get_video_cmdline_opt(i, "VGA")) != NULL) { + pr_info("VGA interface in DISP%d\n", i); + gpio_video_active(i, PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST); + mstr = p - 3; + + /* Get the desired configuration provided by the bootloader */ + if (*p++ != '@') { + pr_info("Video resolution for VGA interface not provided, using default\n"); + } else { + /* Check string to see if its one of the configurations we alaredy have... + * and if not, pass it as mode string, just in case we want to use one + * of the standard video configurations + */ + if ((panel = ccwmx51_find_video_config(vga_panel_list, + ARRAY_SIZE(vga_panel_list), + p)) != NULL) { + pr_info("Panel: %s", p); + memcpy(&mx51_fb_data[i], + &plcd_platform_data[i].fb_pdata, + sizeof(struct mxc_fb_platform_data)); + } else { + /* Pass the video configuration as mode string */ + pr_info("VGA: string %s", p); + + if (!strcmp(p, "800x600")) { + strcpy(mx51_fb_data[0].mode_str, "VGA@800x600M-32"); + } else if (!strcmp(p, "1280x1024")) { + strcpy(mx51_fb_data[0].mode_str, "VGA@1280x1024M-32"); + } else { + strcpy(mx51_fb_data[0].mode_str, mstr); + } + } + } + } + mxc_fb_devices[i].num_resources = 1; + mxc_fb_devices[i].resource = &mxcfb_resources[i]; + mxc_register_device(&mxc_fb_devices[i], &mx51_fb_data[i]); + } + + /* DI0/1 DP-FG channel, used by the VPU */ + mxc_register_device(&mxc_fb_devices[2], NULL); + + return 0; +} +#endif + +#if defined(CONFIG_PATA_FSL) || defined(CONFIG_PATA_FSL_MODULE) +extern void gpio_ata_active(void); +extern void gpio_ata_inactive(void); + +static int ccwmx51_init_ata(struct platform_device *pdev) +{ + gpio_ata_active(); + return 0; +} + +static void ccwmx51_deinit_ata(void) +{ + gpio_ata_inactive(); +} + +struct fsl_ata_platform_data ata_data = { +#ifndef CONFIG_PATA_FSL_DISABLE_DMA + .udma_mask = ATA_UDMA3, + .mwdma_mask = ATA_MWDMA2, +#endif + .pio_mask = ATA_PIO4, + .fifo_alarm = MXC_IDE_DMA_WATERMARK / 2, + .max_sg = MXC_IDE_DMA_BD_NR, + .init = ccwmx51_init_ata, + .exit = ccwmx51_deinit_ata, + .core_reg = NULL, + .io_reg = NULL, +}; #endif -void __init ccwmx51_init_devices ( void ) +void ccwmx51_init_devices(void) { #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) ccwmx51_init_ext_eth_mac(); diff --git a/arch/arm/mach-mx5/devices_ccwmx51.h b/arch/arm/mach-mx5/devices_ccwmx51.h index 7208099b6e2d..6e53be44a5f5 100644 --- a/arch/arm/mach-mx5/devices_ccwmx51.h +++ b/arch/arm/mach-mx5/devices_ccwmx51.h @@ -28,17 +28,29 @@ extern struct mxc_w1_config mxc_w1_data; extern struct mxc_spdif_platform_data mxc_spdif_data; extern struct tve_platform_data tve_data; extern struct mxc_dvfs_platform_data dvfs_core_data; +extern struct fec_platform_data fec_data; extern struct mxc_dvfsper_data dvfs_per_data; extern struct platform_pwm_backlight_data mxc_pwm_backlight_data; extern struct mxc_audio_platform_data wm8753_data; extern struct mxc_fb_platform_data mx51_fb_data[]; extern struct uio_info gpu2d_platform_data; -extern struct ccwmx51_lcd_pdata * plcd_platform_data; +extern struct ccwmx51_lcd_pdata plcd_platform_data[2]; +extern struct fsl_ata_platform_data ata_data; extern int __init ccwmx51_init_i2c2(void); extern void ccwmx51_init_spidevices(void); extern int __init ccwmx51_init_fb(void); extern void __init ccwmx51_io_init(void); extern int __init ccwmx51_init_mc13892(void); extern struct platform_device smsc911x_device; +extern void ccwmx51_set_mod_variant(u8 variant); +extern void ccwmx51_set_mod_revision(u8 revision); +extern void ccwmx51_set_mod_sn(u32 sn); +extern void ccwmx51_register_sdio(int interface); +extern void ccwmx51_init_devices(void); +extern int ccwmx51_create_sysfs_entries(void); +extern struct gpio_keys_platform_data ccwmx51js_gpio_key_info; +extern void ccwmx51_init_devices(void); +extern int ccwmx51_create_sysfs_entries(void); + #endif /* DEVICES_CCWMX51_H_ */ diff --git a/arch/arm/mach-mx5/displays/displays.h b/arch/arm/mach-mx5/displays/displays.h index 1fa2c1d05b5d..d738781a31e2 100644 --- a/arch/arm/mach-mx5/displays/displays.h +++ b/arch/arm/mach-mx5/displays/displays.h @@ -1,7 +1,7 @@ /* - * arch/arm/mach-s3c2443/displays/displays.h + * arch/arm/mach-mx5/displays/displays.h * - * Copyright (C) 2009 by Digi International Inc. + * Copyright (C) 2009-2010 by Digi International Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -12,20 +12,17 @@ #ifndef __ASM_ARCH_MXC_CCWMX51_DISPLAYS_H__ #define __ASM_ARCH_MXC_CCWMX51_DISPLAYS_H__ -#if defined(CONFIG_CCWMX51_LQ070Y3DG3B) -#include "LQ070Y3DG3B.h" -#endif -#if defined(CONFIG_CCWMX51_CUSTOM) -#include "CUSTOM.h" -#endif +extern void gpio_video_active(int vif, u32 pad); +extern void gpio_video_inactive(int vif); -struct ccwmx51_lcd_pdata lcd_display_list[] = { -#if defined(CONFIG_CCWMX51_LQ070Y3DG3B) - LQ070Y3DG3B_DISPLAY, +#ifdef CONFIG_CCWMX51_DISP0_RGB888 +#define VIDEO_PIX_FMT IPU_PIX_FMT_RGB24 +#else +#define VIDEO_PIX_FMT IPU_PIX_FMT_RGB666 #endif -#if defined(CONFIG_CCWMX51_CUSTOM) - CUSTOM_DISPLAY, -#endif -}; + +#include "hdmi_ad9389.h" +#include "vga.h" +#include "lcd.h" #endif /* __ASM_ARCH_MXC_CCWMX51_DISPLAYS_H__ */ diff --git a/arch/arm/mach-mx5/dma.c b/arch/arm/mach-mx5/dma.c index b79fab73e41f..39b7776c6d15 100644 --- a/arch/arm/mach-mx5/dma.c +++ b/arch/arm/mach-mx5/dma.c @@ -13,11 +13,14 @@ #include <linux/init.h> #include <linux/device.h> #include <asm/dma.h> +#include <mach/dma.h> #include <mach/hardware.h> +#include <mach/mxc_uart.h> #include "serial.h" #include "sdma_script_code.h" #include "sdma_script_code_mx53.h" +#include "sdma_script_code_mx50.h" #define MXC_MMC_BUFFER_ACCESS 0x20 #define MXC_SDHC_MMC_WML 64 @@ -1344,16 +1347,82 @@ static void __init mx53_sdma_get_script_info(sdma_script_start_addrs *sdma_scrip sdma_script_addr->mxc_sdma_dptc_dvfs_addr = -1; /* core */ - sdma_script_addr->mxc_sdma_start_addr = (unsigned short *)sdma_code; + sdma_script_addr->mxc_sdma_start_addr = (unsigned short *)sdma_code_mx53; sdma_script_addr->mxc_sdma_ram_code_start_addr = RAM_CODE_START_ADDR_MX53; sdma_script_addr->mxc_sdma_ram_code_size = RAM_CODE_SIZE_MX53; } +static void __init mx50_sdma_get_script_info(sdma_script_start_addrs *sdma_script_addr) +{ + /* AP<->BP */ + sdma_script_addr->mxc_sdma_ap_2_ap_addr = ap_2_ap_ADDR_MX50; + 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_ap_2_ap_fixed_addr = -1; + + /*misc */ + sdma_script_addr->mxc_sdma_loopback_on_dsp_side_addr = -1; + sdma_script_addr->mxc_sdma_mcu_interrupt_only_addr = -1; + + /* firi */ + 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; + + /* uart */ + sdma_script_addr->mxc_sdma_uart_2_per_addr = uart_2_mcu_ADDR_MX50; + sdma_script_addr->mxc_sdma_uart_2_mcu_addr = uart_2_mcu_ADDR_MX50; + + /* UART SH */ + sdma_script_addr->mxc_sdma_uartsh_2_per_addr = uartsh_2_mcu_ADDR_MX50; + sdma_script_addr->mxc_sdma_uartsh_2_mcu_addr = uartsh_2_mcu_ADDR_MX50; + + /* SHP */ + sdma_script_addr->mxc_sdma_per_2_shp_addr = mcu_2_shp_ADDR_MX50; + sdma_script_addr->mxc_sdma_shp_2_per_addr = shp_2_mcu_ADDR_MX50; + sdma_script_addr->mxc_sdma_mcu_2_shp_addr = mcu_2_shp_ADDR_MX50; + sdma_script_addr->mxc_sdma_shp_2_mcu_addr = shp_2_mcu_ADDR_MX50; + + /* ATA use it's own DMA */ + sdma_script_addr->mxc_sdma_mcu_2_ata_addr = -1; + sdma_script_addr->mxc_sdma_ata_2_mcu_addr = -1; + + /* app */ + sdma_script_addr->mxc_sdma_app_2_per_addr = app_2_mcu_ADDR_MX50; + sdma_script_addr->mxc_sdma_app_2_mcu_addr = app_2_mcu_ADDR_MX50; + sdma_script_addr->mxc_sdma_per_2_app_addr = mcu_2_app_ADDR_MX50; + sdma_script_addr->mxc_sdma_mcu_2_app_addr = mcu_2_app_ADDR_MX50; + + /* MSHC */ + sdma_script_addr->mxc_sdma_mshc_2_mcu_addr = -1; + sdma_script_addr->mxc_sdma_mcu_2_mshc_addr = -1; + + /* spdif */ + 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; + + /* IPU */ + sdma_script_addr->mxc_sdma_ext_mem_2_ipu_addr = -1; + + /* DVFS */ + sdma_script_addr->mxc_sdma_dptc_dvfs_addr = -1; + + /* core */ + sdma_script_addr->mxc_sdma_start_addr = (unsigned short *)sdma_code_mx50; + sdma_script_addr->mxc_sdma_ram_code_start_addr = RAM_CODE_START_ADDR_MX50; + sdma_script_addr->mxc_sdma_ram_code_size = RAM_CODE_SIZE_MX50; +} + void __init mxc_sdma_get_script_info(sdma_script_start_addrs *sdma_script_addr) { if (cpu_is_mx51()) mx51_sdma_get_script_info(sdma_script_addr); - else + else if (cpu_is_mx53()) mx53_sdma_get_script_info(sdma_script_addr); + else + mx50_sdma_get_script_info(sdma_script_addr); } diff --git a/arch/arm/mach-mx5/dummy_gpio.c b/arch/arm/mach-mx5/dummy_gpio.c index 8eb771d29a06..9d4cd07d28f9 100644 --- a/arch/arm/mach-mx5/dummy_gpio.c +++ b/arch/arm/mach-mx5/dummy_gpio.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -53,12 +53,6 @@ EXPORT_SYMBOL(gpio_pmic_active); void gpio_activate_audio_ports(void) {} EXPORT_SYMBOL(gpio_activate_audio_ports); -void gpio_sdhc_active(int module) {} -EXPORT_SYMBOL(gpio_sdhc_active); - -void gpio_sdhc_inactive(int module) {} -EXPORT_SYMBOL(gpio_sdhc_inactive); - void gpio_sensor_select(int sensor) {} void gpio_sensor_active(unsigned int csi) {} @@ -67,12 +61,6 @@ EXPORT_SYMBOL(gpio_sensor_active); void gpio_sensor_inactive(unsigned int csi) {} EXPORT_SYMBOL(gpio_sensor_inactive); -void gpio_ata_active(void) {} -EXPORT_SYMBOL(gpio_ata_active); - -void gpio_ata_inactive(void) {} -EXPORT_SYMBOL(gpio_ata_inactive); - void gpio_nand_active(void) {} EXPORT_SYMBOL(gpio_nand_active); @@ -105,3 +93,9 @@ EXPORT_SYMBOL(gpio_spdif_active); void gpio_spdif_inactive(void) {} EXPORT_SYMBOL(gpio_spdif_inactive); + +void gpio_mlb_active(void) {} +EXPORT_SYMBOL(gpio_mlb_active); + +void gpio_mlb_inactive(void) {} +EXPORT_SYMBOL(gpio_mlb_inactive); diff --git a/arch/arm/mach-mx5/iomux.c b/arch/arm/mach-mx5/iomux.c index 319980ad176a..4cca66447443 100644 --- a/arch/arm/mach-mx5/iomux.c +++ b/arch/arm/mach-mx5/iomux.c @@ -37,6 +37,9 @@ #define INPUT_CTL_START_MX53 0x730 #define MUX_I_END_MX53 (PAD_I_START_MX53 - 4) +#define PAD_I_START_MX50 0x2CC +#define INPUT_CTL_START_MX50 0x6C4 + /*! * IOMUX register (base) addressesf */ @@ -52,8 +55,10 @@ static inline void *_get_sw_pad(void) { if (cpu_is_mx51()) return IO_ADDRESS(IOMUXC_BASE_ADDR) + PAD_I_START_MX51; - else + else if (cpu_is_mx53()) return IO_ADDRESS(IOMUXC_BASE_ADDR) + PAD_I_START_MX53; + else + return IO_ADDRESS(IOMUXC_BASE_ADDR) + PAD_I_START_MX50; } static inline void * _get_mux_reg(iomux_pin_name_t pin) @@ -102,6 +107,9 @@ static inline void * _get_pad_reg(iomux_pin_name_t pin) static inline void * _get_mux_end(void) { + if (cpu_is_mx50()) + return IO_ADDRESS(IOMUXC_BASE_ADDR) + 0x2C8; + if (cpu_is_mx51_rev(CHIP_REV_2_0) < 0) return(IO_ADDRESS(IOMUXC_BASE_ADDR) + (0x3F8 - 4)); else @@ -264,8 +272,10 @@ void mxc_iomux_set_input(iomux_input_select_t input, u32 config) reg = IOMUXSW_INPUT_CTL + (input << 2) + INPUT_CTL_START_MX51_TO1; } else if (cpu_is_mx51()) { reg = IOMUXSW_INPUT_CTL + (input << 2) + INPUT_CTL_START_MX51; - } else + } else if (cpu_is_mx53()) { reg = IOMUXSW_INPUT_CTL + (input << 2) + INPUT_CTL_START_MX53; + } else + reg = IOMUXSW_INPUT_CTL + (input << 2) + INPUT_CTL_START_MX50; BUG_ON(input >= MUX_INPUT_NUM_MUX); __raw_writel(config, reg); diff --git a/arch/arm/mach-mx5/lpmodes.c b/arch/arm/mach-mx5/lpmodes.c index 32af9ccc4f6a..c9d770231b54 100644 --- a/arch/arm/mach-mx5/lpmodes.c +++ b/arch/arm/mach-mx5/lpmodes.c @@ -37,7 +37,6 @@ #include <mach/clock.h> #include <mach/hardware.h> #include <linux/regulator/machine.h> -#include "crm_regs.h" #define ARM_LP_CLK 166250000 #define GP_LPM_VOLTAGE 775000 diff --git a/arch/arm/mach-mx5/mm.c b/arch/arm/mach-mx5/mm.c index 8ac23c100bd9..21d654298b54 100644 --- a/arch/arm/mach-mx5/mm.c +++ b/arch/arm/mach-mx5/mm.c @@ -16,6 +16,7 @@ #include <mach/hardware.h> #include <asm/pgtable.h> #include <asm/mach/map.h> +#include <mach/iomux-v3.h> /*! * @file mach-mx51/mm.c @@ -60,8 +61,9 @@ void __init mx5_map_io(void) { int i; + mxc_iomux_v3_init(IO_ADDRESS(IOMUXC_BASE_ADDR)); /* Fixup the mappings for MX53 */ - if (cpu_is_mx53()) { + if (cpu_is_mx53() || cpu_is_mx50()) { for (i = 0; i < ARRAY_SIZE(mx5_io_desc); i++) mx5_io_desc[i].pfn -= __phys_to_pfn(0x20000000); } diff --git a/arch/arm/mach-mx5/mx51_3stack.c b/arch/arm/mach-mx5/mx51_3stack.c index 7c3d80938777..cc5a205d594d 100644 --- a/arch/arm/mach-mx5/mx51_3stack.c +++ b/arch/arm/mach-mx5/mx51_3stack.c @@ -47,7 +47,6 @@ #include <mach/mxc_dvfs.h> #include "devices.h" -#include "board-mx51_3stack.h" #include "iomux.h" #include "mx51_pins.h" #include "crm_regs.h" @@ -60,6 +59,44 @@ * * @ingroup MSL_MX51 */ +#define DEBUG_BOARD_BASE_ADDRESS(n) (n) +/* LAN9217 ethernet base address */ +#define LAN9217_BASE_ADDR(n) (DEBUG_BOARD_BASE_ADDRESS(n)) + +#define BOARD_IO_ADDR(n) (DEBUG_BOARD_BASE_ADDRESS(n) + 0x20000) +/* LED switchs */ +#define LED_SWITCH_REG 0x00 +/* buttons */ +#define SWITCH_BUTTONS_REG 0x08 +/* status, interrupt */ +#define INTR_STATUS_REG 0x10 +#define INTR_MASK_REG 0x38 +#define INTR_RESET_REG 0x20 +/* magic word for debug CPLD */ +#define MAGIC_NUMBER1_REG 0x40 +#define MAGIC_NUMBER2_REG 0x48 +/* CPLD code version */ +#define CPLD_CODE_VER_REG 0x50 +/* magic word for debug CPLD */ +#define MAGIC_NUMBER3_REG 0x58 +/* module reset register*/ +#define MODULE_RESET_REG 0x60 +/* CPU ID and Personality ID */ +#define MCU_BOARD_ID_REG 0x68 + +/* interrupts like external uart , external ethernet etc*/ +#define EXPIO_PARENT_INT IOMUX_TO_IRQ(MX51_PIN_GPIO1_6) + +#define EXPIO_INT_ENET (MXC_BOARD_IRQ_START + 0) +#define EXPIO_INT_XUART_A (MXC_BOARD_IRQ_START + 1) +#define EXPIO_INT_XUART_B (MXC_BOARD_IRQ_START + 2) +#define EXPIO_INT_BUTTON_A (MXC_BOARD_IRQ_START + 3) +#define EXPIO_INT_BUTTON_B (MXC_BOARD_IRQ_START + 4) + +/*! This is System IRQ used by LAN9217 */ +#define LAN9217_IRQ EXPIO_INT_ENET + +extern int __init mx51_3stack_init_mc13892(void); extern void __init mx51_3stack_io_init(void); extern struct cpu_wp *(*get_cpu_wp)(int *wp); extern void (*set_num_cpu_wp)(int num); @@ -147,15 +184,77 @@ static struct mxc_vpu_platform_data mxc_vpu_data = { .reset = mx5_vpu_reset, }; -extern void mx51_babbage_gpio_spi_chipselect_active(int cspi_mode, int status, - int chipselect); -extern void mx51_babbage_gpio_spi_chipselect_inactive(int cspi_mode, int status, - int chipselect); +/* workaround for ecspi chipselect pin may not keep correct level when idle */ +static void mx51_3ds_gpio_spi_chipselect_active(int cspi_mode, int status, + int chipselect) +{ + u32 gpio; + + switch (cspi_mode) { + case 1: + switch (chipselect) { + case 0x1: + mxc_request_iomux(MX51_PIN_CSPI1_SS0, + IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX51_PIN_CSPI1_SS0, + PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST); + break; + case 0x2: + gpio = IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS0); + mxc_request_iomux(MX51_PIN_CSPI1_SS0, + IOMUX_CONFIG_GPIO); + gpio_request(gpio, "cspi1_ss0"); + gpio_direction_output(gpio, 0); + gpio_set_value(gpio, 1 & (~status)); + break; + default: + break; + } + break; + case 2: + break; + case 3: + break; + default: + break; + } +} + +static void mx51_3ds_gpio_spi_chipselect_inactive(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + switch (chipselect) { + case 0x1: + mxc_free_iomux(MX51_PIN_CSPI1_SS0, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX51_PIN_CSPI1_SS0, + IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX51_PIN_CSPI1_SS0, IOMUX_CONFIG_GPIO); + break; + case 0x2: + mxc_free_iomux(MX51_PIN_CSPI1_SS0, IOMUX_CONFIG_GPIO); + break; + default: + break; + } + break; + case 2: + break; + case 3: + break; + default: + break; + } +} + static struct mxc_spi_master mxcspi1_data = { .maxchipselect = 4, .spi_version = 23, - .chipselect_active = mx51_babbage_gpio_spi_chipselect_active, - .chipselect_inactive = mx51_babbage_gpio_spi_chipselect_inactive, + .chipselect_active = mx51_3ds_gpio_spi_chipselect_active, + .chipselect_inactive = mx51_3ds_gpio_spi_chipselect_inactive, }; static struct mxc_i2c_platform_data mxci2c_data = { @@ -179,15 +278,11 @@ static struct mxc_dvfs_platform_data dvfs_core_data = { .reg_id = "SW1", .clk1_id = "cpu_clk", .clk2_id = "gpc_dvfs_clk", - .gpc_cntr_reg_addr = MXC_GPC_CNTR, - .gpc_vcr_reg_addr = MXC_GPC_VCR, - .ccm_cdcr_reg_addr = MXC_CCM_CDCR, - .ccm_cacrr_reg_addr = MXC_CCM_CACRR, - .ccm_cdhipr_reg_addr = MXC_CCM_CDHIPR, - .dvfs_thrs_reg_addr = MXC_DVFSTHRS, - .dvfs_coun_reg_addr = MXC_DVFSCOUN, - .dvfs_emac_reg_addr = MXC_DVFSEMAC, - .dvfs_cntr_reg_addr = MXC_DVFSCNTR, + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, .prediv_mask = 0x1F800, .prediv_offset = 11, .prediv_val = 3, @@ -685,30 +780,6 @@ static struct fsl_ata_platform_data ata_data = { .io_reg = NULL, }; -static int __init mxc_init_srpgconfig(void) -{ - struct clk *gpcclk = clk_get(NULL, "gpc_dvfs_clk"); - clk_enable(gpcclk); - - /* Setup the number of clock cycles to wait for SRPG - * power up and power down requests. - */ - __raw_writel(0x010F0201, MXC_SRPG_ARM_PUPSCR); - __raw_writel(0x010F0201, MXC_SRPG_NEON_PUPSCR); - __raw_writel(0x00000008, MXC_SRPG_EMPGC0_PUPSCR); - __raw_writel(0x00000008, MXC_SRPG_EMPGC1_PUPSCR); - - __raw_writel(0x01010101, MXC_SRPG_ARM_PDNSCR); - __raw_writel(0x01010101, MXC_SRPG_NEON_PDNSCR); - __raw_writel(0x00000018, MXC_SRPG_EMPGC0_PDNSCR); - __raw_writel(0x00000018, MXC_SRPG_EMPGC1_PDNSCR); - - clk_disable(gpcclk); - clk_put(gpcclk); - - return 0; -} - static struct platform_device mxc_wm8903_device = { .name = "imx-3stack-wm8903", .id = 0, @@ -879,6 +950,8 @@ static void __init mxc_board_init(void) mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk"); mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk"); + mxc_ipu_data.csi_clk[0] = clk_get(NULL, "csi_mclk1"); + mxc_ipu_data.csi_clk[1] = clk_get(NULL, "csi_mclk2"); mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); clk_put(mxc_spdif_data.spdif_core_clk); @@ -909,8 +982,8 @@ static void __init mxc_board_init(void) mxc_register_device(&mxc_pwm1_device, NULL); mxc_register_device(&mxc_pwm_backlight_device, &mxc_pwm_backlight_data); mxc_register_device(&mxc_keypad_device, &keypad_plat_data); - mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0), - mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0), + mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0); + mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0); mxc_register_device(&mxcsdhc1_device, &mmc1_data); mxc_register_device(&mxcsdhc2_device, &mmc2_data); mxc_register_device(&mxc_sim_device, &sim_data); @@ -936,7 +1009,6 @@ static void __init mxc_board_init(void) #else mxc_register_device(&mxc_nandv2_mtd_device, &mxc_nand_data); #endif - mxc_init_srpgconfig(); mx51_3stack_init_mc13892(); i2c_register_board_info(1, mxc_i2c1_board_info, @@ -948,6 +1020,8 @@ static void __init mxc_board_init(void) mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data); mxc_register_device(&mxc_bt_device, &mxc_bt_data); mxc_register_device(&mxc_gps_device, &gps_data); + mxc_register_device(&mxc_v4l2_device, NULL); + mxc_register_device(&mxc_v4l2out_device, NULL); mx5_usb_dr_init(); mx5_usbh1_init(); diff --git a/arch/arm/mach-mx5/mx51_babbage.c b/arch/arm/mach-mx5/mx51_babbage.c index 4a962ab6f647..1acc44937e65 100644 --- a/arch/arm/mach-mx5/mx51_babbage.c +++ b/arch/arm/mach-mx5/mx51_babbage.c @@ -25,13 +25,13 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> -#include <linux/spi/flash.h> #include <linux/regulator/consumer.h> #include <linux/pmic_external.h> #include <linux/pmic_status.h> #include <linux/ipu.h> #include <linux/mxcfb.h> #include <linux/pwm_backlight.h> +#include <linux/fec.h> #include <mach/common.h> #include <mach/hardware.h> #include <asm/setup.h> @@ -39,17 +39,21 @@ #include <asm/mach/arch.h> #include <asm/mach/time.h> #include <asm/mach/keypad.h> +#include <asm/mach/flash.h> #include <mach/gpio.h> #include <mach/mmc.h> #include <mach/mxc_dvfs.h> #include <mach/mxc_edid.h> +#include <mach/iomux-mx51.h> +#include <mach/gpio.h> #include "devices.h" -#include "board-mx51_babbage.h" -#include "iomux.h" -#include "mx51_pins.h" #include "crm_regs.h" #include "usb.h" +#include <mach/mxc_edid.h> +#include <linux/android_pmem.h> +#include <linux/usb/android.h> +#include <linux/switch.h> /*! * @file mach-mx51/mx51_babbage.c @@ -58,11 +62,181 @@ * * @ingroup MSL_MX51 */ -extern void __init mx51_babbage_io_init(void); + +#define BABBAGE_SD1_CD (0*32 + 0) /* GPIO_1_0 */ +#define BABBAGE_SD1_WP (0*32 + 1) /* GPIO_1_1 */ +#define BABBAGE_SD2_CD_2_0 (0*32 + 4) /* GPIO_1_4 */ +#define BABBAGE_SD2_WP (0*32 + 5) /* GPIO_1_5 */ +#define BABBAGE_SD2_CD_2_5 (0*32 + 6) /* GPIO_1_6 */ +#define BABBAGE_USBH1_HUB_RST (0*32 + 7) /* GPIO_1_7 */ +#define BABBAGE_PMIC_INT (0*32 + 8) /* GPIO_1_8 */ + +#define BABBAGE_USB_CLK_EN_B (1*32 + 1) /* GPIO_2_1 */ +#define BABBAGE_OSC_EN_B (1*32 + 2) /* GPIO_2_2 */ +#define BABBAGE_PHY_RESET (1*32 + 5) /* GPIO_2_5 */ +#define BABBAGE_CAM_RESET (1*32 + 7) /* GPIO_2_7 */ +#define BABBAGE_FM_PWR (1*32 + 12) /* GPIO_2_12 */ +#define BABBAGE_VGA_RESET (1*32 + 13) /* GPIO_2_13 */ +#define BABBAGE_FEC_PHY_RESET (1*32 + 14) /* GPIO_2_14 */ +#define BABBAGE_FM_RESET (1*32 + 15) /* GPIO_2_15 */ +#define BABBAGE_AUDAMP_STBY (1*32 + 17) /* GPIO_2_17 */ +#define BABBAGE_POWER_KEY (1*32 + 21) /* GPIO_2_21 */ + +#define BABBAGE_26M_OSC_EN (2*32 + 1) /* GPIO_3_1 */ +#define BABBAGE_LVDS_POWER_DOWN (2*32 + 3) /* GPIO_3_3 */ +#define BABBAGE_DISP_BRIGHTNESS_CTL (2*32 + 4) /* GPIO_3_4 */ +#define BABBAGE_DVI_RESET (2*32 + 5) /* GPIO_3_5 */ +#define BABBAGE_DVI_POWER (2*32 + 6) /* GPIO_3_6 */ +#define BABBAGE_HEADPHONE_DET (2*32 + 26) /* GPIO_3_26 */ +#define BABBAGE_DVI_DET (2*32 + 28) /* GPIO_3_28 */ + +#define BABBAGE_LCD_3V3_ON (3*32 + 9) /* GPIO_4_9 */ +#define BABBAGE_LCD_5V_ON (3*32 + 10) /* GPIO_4_10 */ +#define BABBAGE_CAM_LOW_POWER (3*32 + 10) /* GPIO_4_12 */ +#define BABBAGE_DVI_I2C_EN (3*32 + 14) /* GPIO_4_14 */ +#define BABBAGE_CSP1_SS0_GPIO (3*32 + 24) /* GPIO_4_24 */ +#define BABBAGE_AUDIO_CLK_EN (3*32 + 26) /* GPIO_4_26 */ + +extern int __init mx51_babbage_init_mc13892(void); extern struct cpu_wp *(*get_cpu_wp)(int *wp); extern void (*set_num_cpu_wp)(int num); static int num_cpu_wp = 3; +static struct pad_desc mx51babbage_pads[] = { + /* UART1 */ + MX51_PAD_UART1_RXD__UART1_RXD, + MX51_PAD_UART1_TXD__UART1_TXD, + MX51_PAD_UART1_RTS__UART1_RTS, + MX51_PAD_UART1_CTS__UART1_CTS, + + /* USB HOST1 */ + MX51_PAD_USBH1_STP__USBH1_STP, + MX51_PAD_USBH1_CLK__USBH1_CLK, + MX51_PAD_USBH1_DIR__USBH1_DIR, + MX51_PAD_USBH1_NXT__USBH1_NXT, + MX51_PAD_USBH1_DATA0__USBH1_DATA0, + MX51_PAD_USBH1_DATA1__USBH1_DATA1, + MX51_PAD_USBH1_DATA2__USBH1_DATA2, + MX51_PAD_USBH1_DATA3__USBH1_DATA3, + MX51_PAD_USBH1_DATA4__USBH1_DATA4, + MX51_PAD_USBH1_DATA5__USBH1_DATA5, + MX51_PAD_USBH1_DATA6__USBH1_DATA6, + MX51_PAD_USBH1_DATA7__USBH1_DATA7, + + MX51_PAD_GPIO_1_0__GPIO_1_0, + MX51_PAD_GPIO_1_1__GPIO_1_1, + MX51_PAD_GPIO_1_4__GPIO_1_4, + MX51_PAD_GPIO_1_5__GPIO_1_5, + MX51_PAD_GPIO_1_6__GPIO_1_6, + MX51_PAD_GPIO_1_7__GPIO_1_7, + MX51_PAD_GPIO_1_8__GPIO_1_8, + MX51_PAD_UART3_RXD__GPIO_1_22, + + MX51_PAD_EIM_D17__GPIO_2_1, + MX51_PAD_EIM_D18__GPIO_2_2, + MX51_PAD_EIM_D21__GPIO_2_5, + MX51_PAD_EIM_D23__GPIO_2_7, + MX51_PAD_EIM_A16__GPIO_2_10, + MX51_PAD_EIM_A17__GPIO_2_11, + MX51_PAD_EIM_A18__GPIO_2_12, + MX51_PAD_EIM_A19__GPIO_2_13, + MX51_PAD_EIM_A20__GPIO_2_14, + MX51_PAD_EIM_A21__GPIO_2_15, + MX51_PAD_EIM_A22__GPIO_2_16, + MX51_PAD_EIM_A23__GPIO_2_17, + MX51_PAD_EIM_A27__GPIO_2_21, + MX51_PAD_EIM_DTACK__GPIO_2_31, + + MX51_PAD_EIM_LBA__GPIO_3_1, + MX51_PAD_DI1_D0_CS__GPIO_3_3, + MX51_PAD_DISPB2_SER_DIN__GPIO_3_5, + MX51_PAD_DISPB2_SER_DIO__GPIO_3_6, + MX51_PAD_NANDF_CS0__GPIO_3_16, + MX51_PAD_NANDF_CS1__GPIO_3_17, + MX51_PAD_NANDF_D14__GPIO_3_26, + MX51_PAD_NANDF_D12__GPIO_3_28, + + MX51_PAD_CSI2_D12__GPIO_4_9, + MX51_PAD_CSI2_D13__GPIO_4_10, + MX51_PAD_CSI2_D19__GPIO_4_12, + MX51_PAD_CSI2_HSYNC__GPIO_4_14, + MX51_PAD_CSPI1_RDY__GPIO_4_26, + + MX51_PAD_EIM_EB2__FEC_MDIO, + MX51_PAD_EIM_EB3__FEC_RDAT1, + MX51_PAD_EIM_CS2__FEC_RDAT2, + MX51_PAD_EIM_CS3__FEC_RDAT3, + MX51_PAD_EIM_CS4__FEC_RX_ER, + MX51_PAD_EIM_CS5__FEC_CRS, + MX51_PAD_NANDF_RB2__FEC_COL, + MX51_PAD_NANDF_RB3__FEC_RXCLK, + MX51_PAD_NANDF_RB6__FEC_RDAT0, + MX51_PAD_NANDF_RB7__FEC_TDAT0, + MX51_PAD_NANDF_CS2__FEC_TX_ER, + MX51_PAD_NANDF_CS3__FEC_MDC, + MX51_PAD_NANDF_CS4__FEC_TDAT1, + MX51_PAD_NANDF_CS5__FEC_TDAT2, + MX51_PAD_NANDF_CS6__FEC_TDAT3, + MX51_PAD_NANDF_CS7__FEC_TX_EN, + MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK, + + MX51_PAD_GPIO_NAND__PATA_INTRQ, + + MX51_PAD_DI_GP4__DI2_PIN15, +#ifdef CONFIG_FB_MXC_CLAA_WVGA_SYNC_PANEL + MX51_PAD_DISP1_DAT22__DISP2_DAT16, + MX51_PAD_DISP1_DAT23__DISP2_DAT17, + + MX51_PAD_DI1_D1_CS__GPIO_3_4, +#endif + MX51_PAD_I2C1_CLK__HSI2C_CLK, + MX51_PAD_I2C1_DAT__HSI2C_DAT, + MX51_PAD_EIM_D16__I2C1_SDA, + MX51_PAD_EIM_D19__I2C1_SCL, + + MX51_PAD_GPIO_1_2__PWM_PWMO, + + MX51_PAD_KEY_COL5__I2C2_SDA, + MX51_PAD_KEY_COL4__I2C2_SCL, + + MX51_PAD_SD1_CMD__SD1_CMD, + MX51_PAD_SD1_CLK__SD1_CLK, + MX51_PAD_SD1_DATA0__SD1_DATA0, + MX51_PAD_SD1_DATA1__SD1_DATA1, + MX51_PAD_SD1_DATA2__SD1_DATA2, + MX51_PAD_SD1_DATA3__SD1_DATA3, + + MX51_PAD_SD2_CMD__SD2_CMD, + MX51_PAD_SD2_CLK__SD2_CLK, + MX51_PAD_SD2_DATA0__SD2_DATA0, + MX51_PAD_SD2_DATA1__SD2_DATA1, + MX51_PAD_SD2_DATA2__SD2_DATA2, + MX51_PAD_SD2_DATA3__SD2_DATA3, + + MX51_PAD_AUD3_BB_TXD__AUD3_BB_TXD, + MX51_PAD_AUD3_BB_RXD__AUD3_BB_RXD, + MX51_PAD_AUD3_BB_CK__AUD3_BB_CK, + MX51_PAD_AUD3_BB_FS__AUD3_BB_FS, + + MX51_PAD_CSPI1_SS1__CSPI1_SS1, + + MX51_PAD_DI_GP3__CSI1_DATA_EN, + MX51_PAD_CSI1_D10__CSI1_D10, + MX51_PAD_CSI1_D11__CSI1_D11, + MX51_PAD_CSI1_D12__CSI1_D12, + MX51_PAD_CSI1_D13__CSI1_D13, + MX51_PAD_CSI1_D14__CSI1_D14, + MX51_PAD_CSI1_D15__CSI1_D15, + MX51_PAD_CSI1_D16__CSI1_D16, + MX51_PAD_CSI1_D17__CSI1_D17, + MX51_PAD_CSI1_D18__CSI1_D18, + MX51_PAD_CSI1_D19__CSI1_D19, + MX51_PAD_CSI1_VSYNC__CSI1_VSYNC, + MX51_PAD_CSI1_HSYNC__CSI1_HSYNC, + + MX51_PAD_OWIRE_LINE__SPDIF_OUT1, +}; + /* working point(wp): 0 - 800MHz; 1 - 166.25MHz; */ static struct cpu_wp cpu_wp_auto[] = { { @@ -96,6 +270,24 @@ static struct cpu_wp cpu_wp_auto[] = { static struct fb_videomode video_modes[] = { { + /* NTSC TV output */ + "TV-NTSC", 60, 720, 480, 74074, + 122, 15, + 18, 26, + 1, 1, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | FB_SYNC_EXT, + FB_VMODE_INTERLACED, + 0,}, + { + /* PAL TV output */ + "TV-PAL", 50, 720, 576, 74074, + 132, 11, + 22, 26, + 1, 1, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | FB_SYNC_EXT, + FB_VMODE_INTERLACED | FB_VMODE_ODD_FLD_FIRST, + 0,}, + { /* 720p60 TV output */ "720P60", 60, 1280, 720, 13468, 260, 109, @@ -106,7 +298,7 @@ static struct fb_videomode video_modes[] = { FB_VMODE_NONINTERLACED, 0,}, { - /* MITSUBISHI LVDS panel */ + /*MITSUBISHI LVDS panel */ "XGA", 60, 1024, 768, 15385, 220, 40, 21, 7, @@ -114,6 +306,12 @@ static struct fb_videomode video_modes[] = { 0, FB_VMODE_NONINTERLACED, 0,}, + { + /* 800x480 @ 57 Hz , pixel clk @ 27MHz */ + "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, }; struct cpu_wp *mx51_babbage_get_cpu_wp(int *wp) @@ -166,10 +364,73 @@ static struct mxc_vpu_platform_data mxc_vpu_data = { .reset = mx5_vpu_reset, }; -extern void mx51_babbage_gpio_spi_chipselect_active(int cspi_mode, int status, - int chipselect); -extern void mx51_babbage_gpio_spi_chipselect_inactive(int cspi_mode, int status, - int chipselect); +static struct fec_platform_data fec_data = { + .phy = PHY_INTERFACE_MODE_MII, + .phy_mask = ~1UL, +}; + +/* workaround for ecspi chipselect pin may not keep correct level when idle */ +static void mx51_babbage_gpio_spi_chipselect_active(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + switch (chipselect) { + case 0x1: + { + struct pad_desc cspi1_ss0 = MX51_PAD_CSPI1_SS0__CSPI1_SS0; + + mxc_iomux_v3_setup_pad(&cspi1_ss0); + break; + } + case 0x2: + { + struct pad_desc cspi1_ss0_gpio = MX51_PAD_CSPI1_SS0__GPIO_4_24; + + mxc_iomux_v3_setup_pad(&cspi1_ss0_gpio); + gpio_request(BABBAGE_CSP1_SS0_GPIO, "cspi1-gpio"); + gpio_direction_output(BABBAGE_CSP1_SS0_GPIO, 0); + gpio_set_value(BABBAGE_CSP1_SS0_GPIO, 1 & (~status)); + break; + } + default: + break; + } + break; + case 2: + break; + case 3: + break; + default: + break; + } +} + +static void mx51_babbage_gpio_spi_chipselect_inactive(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + switch (chipselect) { + case 0x1: + break; + case 0x2: + gpio_free(BABBAGE_CSP1_SS0_GPIO); + break; + + default: + break; + } + break; + case 2: + break; + case 3: + break; + default: + break; + } +} + static struct mxc_spi_master mxcspi1_data = { .maxchipselect = 4, .spi_version = 23, @@ -197,15 +458,11 @@ static struct mxc_dvfs_platform_data dvfs_core_data = { .reg_id = "SW1", .clk1_id = "cpu_clk", .clk2_id = "gpc_dvfs_clk", - .gpc_cntr_reg_addr = MXC_GPC_CNTR, - .gpc_vcr_reg_addr = MXC_GPC_VCR, - .ccm_cdcr_reg_addr = MXC_CCM_CDCR, - .ccm_cacrr_reg_addr = MXC_CCM_CACRR, - .ccm_cdhipr_reg_addr = MXC_CCM_CDHIPR, - .dvfs_thrs_reg_addr = MXC_DVFSTHRS, - .dvfs_coun_reg_addr = MXC_DVFSCOUN, - .dvfs_emac_reg_addr = MXC_DVFSEMAC, - .dvfs_cntr_reg_addr = MXC_DVFSCNTR, + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, .prediv_mask = 0x1F800, .prediv_offset = 11, .prediv_val = 3, @@ -258,30 +515,73 @@ static struct mxc_fb_platform_data fb_data[] = { { .interface_pix_fmt = IPU_PIX_FMT_RGB24, .mode_str = "1024x768M-16@60", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), }, { .interface_pix_fmt = IPU_PIX_FMT_RGB565, - .mode_str = "1024x768M-16@60", + .mode_str = "CLAA-WVGA", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), }, }; -static int __initdata enable_vga = { 0 }; -static int __initdata enable_wvga = { 0 }; -static int __initdata enable_tv = { 0 }; -static int __initdata enable_mitsubishi_xga = { 0 }; - -static void wvga_reset(void) +extern int primary_di; +static int __init mxc_init_fb(void) { - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DI1_D1_CS), 1); -} + if (!machine_is_mx51_babbage()) + return 0; -static struct mxc_lcd_platform_data lcd_wvga_data = { - .reset = wvga_reset, -}; + /* DI0-LVDS */ + gpio_set_value(BABBAGE_LVDS_POWER_DOWN, 0); + msleep(1); + gpio_set_value(BABBAGE_LVDS_POWER_DOWN, 1); + gpio_set_value(BABBAGE_LCD_3V3_ON, 1); + gpio_set_value(BABBAGE_LCD_5V_ON, 1); -static struct platform_device lcd_wvga_device = { - .name = "lcd_claa", -}; + /* DVI Detect */ + gpio_request(BABBAGE_DVI_DET, "dvi-detect"); + gpio_direction_input(BABBAGE_DVI_DET); + /* DVI Reset - Assert for i2c disabled mode */ + gpio_request(BABBAGE_DVI_RESET, "dvi-reset"); + gpio_direction_output(BABBAGE_DVI_RESET, 0); + /* DVI Power-down */ + gpio_request(BABBAGE_DVI_POWER, "dvi-power"); + gpio_direction_output(BABBAGE_DVI_POWER, 1); + + /* WVGA Reset */ + gpio_set_value(BABBAGE_DISP_BRIGHTNESS_CTL, 1); + + if (primary_di) { + printk(KERN_INFO "DI1 is primary\n"); + + /* DI1 -> DP-BG channel: */ + mxc_fb_devices[1].num_resources = ARRAY_SIZE(mxcfb_resources); + mxc_fb_devices[1].resource = mxcfb_resources; + mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); + + /* DI0 -> DC channel: */ + mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); + } else { + printk(KERN_INFO "DI0 is primary\n"); + + /* DI0 -> DP-BG channel: */ + mxc_fb_devices[0].num_resources = ARRAY_SIZE(mxcfb_resources); + mxc_fb_devices[0].resource = mxcfb_resources; + mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); + + /* DI1 -> DC channel: */ + mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); + } + + /* + * DI0/1 DP-FG channel: + */ + mxc_register_device(&mxc_fb_devices[2], NULL); + + return 0; +} +device_initcall(mxc_init_fb); static int handle_edid(int *pixclk) { @@ -370,171 +670,17 @@ static int handle_edid(int *pixclk) return 0; } -static int __init mxc_init_fb(void) -{ - int pixclk = 0; - - if (!machine_is_mx51_babbage()) - return 0; - - if (cpu_is_mx51_rev(CHIP_REV_1_1) == 1) { - enable_vga = 1; - fb_data[0].mode_str = NULL; - fb_data[1].mode_str = NULL; - } - - /* DI1: Dumb LCD */ - if (enable_wvga) { - fb_data[1].interface_pix_fmt = IPU_PIX_FMT_RGB565; - fb_data[1].mode_str = "800x480M-16@55"; - } - - /* DI0: lVDS */ - if (enable_mitsubishi_xga) { - fb_data[0].interface_pix_fmt = IPU_PIX_FMT_LVDS666; - fb_data[0].mode = &(video_modes[1]); - - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DI1_D0_CS), 0); - msleep(1); - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DI1_D0_CS), 1); - - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSI2_D12), 1); - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSI2_D13), 1); - } - - /* DVI Detect */ - gpio_request(IOMUX_TO_GPIO(MX51_PIN_NANDF_D12), "nandf_d12"); - gpio_direction_input(IOMUX_TO_GPIO(MX51_PIN_NANDF_D12)); - /* DVI Reset - Assert for i2c disabled mode */ - gpio_request(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIN), "dispb2_ser_din"); - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIN), 0); - gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIN), 0); - /* DVI Power-down */ - gpio_request(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIO), "dispb2_ser_di0"); - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIO), 1); - gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIO), 0); - - mxc_register_device(&lcd_wvga_device, &lcd_wvga_data); - - if (cpu_is_mx51_rev(CHIP_REV_1_1) == 2) - handle_edid(&pixclk); - - if (enable_vga) { - printk(KERN_INFO "VGA monitor is primary\n"); - } else if (enable_wvga) { - printk(KERN_INFO "WVGA LCD panel is primary\n"); - } else if (enable_tv == 2) - printk(KERN_INFO "HDTV is primary\n"); - else - printk(KERN_INFO "DVI monitor is primary\n"); - - if (enable_tv) { - printk(KERN_INFO "HDTV is specified as %d\n", enable_tv); - fb_data[1].interface_pix_fmt = IPU_PIX_FMT_YUV444; - fb_data[1].mode = &(video_modes[0]); - } - - /* Once a customer knows the platform configuration, - this should be simplified to what is desired. - */ - if (enable_vga || enable_wvga || enable_tv == 2) { - /* - * DI1 -> DP-BG channel: - * - * dev di-out-fmt default-videmode - * - * 1. VGA RGB 1024x768M-16@60 - * 2. WVGA RGB 800x480M-16@55 - * 3. TVE YUV video_modes[0] - */ - mxc_fb_devices[1].num_resources = ARRAY_SIZE(mxcfb_resources); - mxc_fb_devices[1].resource = mxcfb_resources; - mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); - if (fb_data[0].mode_str || fb_data[0].mode) - /* - * DI0 -> DC channel: - * - * dev di-out-fmt default-videmode - * - * 1. LVDS RGB video_modes[1] - * 2. DVI RGB 1024x768M-16@60 - */ - mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); - } else { - /* - * DI0 -> DP-BG channel: - * - * dev di-out-fmt default-videmode - * - * 1. LVDS RGB video_modes[1] - * 2. DVI RGB 1024x768M-16@60 - */ - mxc_fb_devices[0].num_resources = ARRAY_SIZE(mxcfb_resources); - mxc_fb_devices[0].resource = mxcfb_resources; - mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); - if (fb_data[1].mode_str || fb_data[1].mode) - /* - * DI1 -> DC channel: - * - * dev di-out-fmt default-videmode - * - * 1. VGA RGB 1024x768M-16@60 - * 2. WVGA RGB 800x480M-16@55 - * 3. TVE YUV video_modes[0] - */ - mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); - } - - /* - * DI0/1 DP-FG channel: - */ - mxc_register_device(&mxc_fb_devices[2], NULL); - - return 0; -} -device_initcall(mxc_init_fb); - -static int __init vga_setup(char *__unused) -{ - enable_vga = 1; - return 1; -} -__setup("vga", vga_setup); - -static int __init wvga_setup(char *__unused) -{ - enable_wvga = 1; - return 1; -} -__setup("wvga", wvga_setup); - -static int __init mitsubishi_xga_setup(char *__unused) -{ - enable_mitsubishi_xga = 1; - return 1; -} -__setup("mitsubishi_xga", mitsubishi_xga_setup); - -static int __init tv_setup(char *s) -{ - enable_tv = 1; - if (strcmp(s, "2") == 0 || strcmp(s, "=2") == 0) - enable_tv = 2; - return 1; -} -__setup("hdtv", tv_setup); - static void dvi_reset(void) { - gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIN), 0); - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIN), 0); + gpio_direction_output(BABBAGE_DVI_RESET, 0); + gpio_set_value(BABBAGE_DVI_RESET, 0); msleep(50); /* do reset */ - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIN), 1); + gpio_set_value(BABBAGE_DVI_RESET, 1); msleep(20); /* tRES >= 50us */ - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIN), 0); + gpio_set_value(BABBAGE_DVI_RESET, 0); } static struct mxc_lcd_platform_data dvi_data = { @@ -545,14 +691,13 @@ static struct mxc_lcd_platform_data dvi_data = { static void vga_reset(void) { - gpio_request(IOMUX_TO_GPIO(MX51_PIN_EIM_A19), "eim_a19"); - gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A19), 0); - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A19), 0); + + gpio_set_value(BABBAGE_VGA_RESET, 0); msleep(50); /* do reset */ - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A19), 1); + gpio_set_value(BABBAGE_VGA_RESET, 1); msleep(10); /* tRES >= 50us */ - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A19), 0); + gpio_set_value(BABBAGE_VGA_RESET, 0); } static struct mxc_lcd_platform_data vga_data = { @@ -565,22 +710,23 @@ static struct mxc_lcd_platform_data vga_data = { static void si4702_reset(void) { return; - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A21), 0); + + gpio_set_value(BABBAGE_FM_RESET, 0); msleep(100); - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A21), 1); + gpio_set_value(BABBAGE_FM_RESET, 1); msleep(100); } static void si4702_clock_ctl(int flag) { - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A18), flag); + gpio_set_value(BABBAGE_FM_PWR, flag); msleep(100); } static void si4702_gpio_get(void) { - gpio_request(IOMUX_TO_GPIO(MX51_PIN_EIM_A18), "eim_a18"); - gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A18), 0); + gpio_request(BABBAGE_FM_PWR, "fm-power"); + gpio_direction_output(BABBAGE_FM_PWR, 0); } static void si4702_gpio_put(void) @@ -706,9 +852,9 @@ static int sdhc_write_protect(struct device *dev) unsigned short rc = 0; if (to_platform_device(dev)->id == 0) - rc = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_1)); + rc = gpio_get_value(BABBAGE_SD1_WP); else - rc = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5)); + rc = gpio_get_value(BABBAGE_SD2_WP); return rc; } @@ -718,25 +864,26 @@ static unsigned int sdhc_get_card_det_status(struct device *dev) int ret; if (to_platform_device(dev)->id == 0) { - ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_0)); + ret = gpio_get_value(BABBAGE_SD1_CD); return ret; } else { /* config the det pin for SDHC2 */ if (board_is_rev(BOARD_REV_2)) /* BB2.5 */ - ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_6)); + ret = gpio_get_value(BABBAGE_SD2_CD_2_5); else /* BB2.0 */ - ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_4)); + ret = gpio_get_value(BABBAGE_SD2_CD_2_0); return ret; } } static struct mxc_mmc_platform_data mmc1_data = { - .ocr_mask = MMC_VDD_31_32, + .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | + MMC_VDD_31_32, .caps = MMC_CAP_4_BIT_DATA, - .min_clk = 400000, + .min_clk = 150000, .max_clk = 52000000, - .card_inserted_state = 1, + .card_inserted_state = 0, .status = sdhc_get_card_det_status, .wp_status = sdhc_write_protect, .clock_mmc = "esdhc_clk", @@ -753,27 +900,25 @@ static struct mxc_mmc_platform_data mmc2_data = { .status = sdhc_get_card_det_status, .wp_status = sdhc_write_protect, .clock_mmc = "esdhc_clk", + .clk_always_on = 1, }; static int mxc_sgtl5000_amp_enable(int enable) { - gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A23), enable ? 1 : 0); + gpio_set_value(BABBAGE_AUDAMP_STBY, enable ? 1 : 0); return 0; } static int headphone_det_status(void) { - if (cpu_is_mx51_rev(CHIP_REV_1_1) == 2) - return (gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_NANDF_D14)) == 0); - - return gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_NANDF_CS0)); + return (gpio_get_value(BABBAGE_HEADPHONE_DET) == 0); } static struct mxc_audio_platform_data sgtl5000_data = { .ssi_num = 1, .src_port = 2, .ext_port = 3, - .hp_irq = IOMUX_TO_IRQ(MX51_PIN_NANDF_D14), + .hp_irq = IOMUX_TO_IRQ_V3(BABBAGE_HEADPHONE_DET), .hp_status = headphone_det_status, .amp_enable = mxc_sgtl5000_amp_enable, .sysclk = 12288000, @@ -783,6 +928,41 @@ static struct platform_device mxc_sgtl5000_device = { .name = "imx-3stack-sgtl5000", }; +static int __initdata enable_w1 = { 0 }; +static int __init w1_setup(char *__unused) +{ + enable_w1 = 1; + return cpu_is_mx51(); +} + +__setup("w1", w1_setup); + +static struct android_pmem_platform_data android_pmem_pdata = { + .name = "pmem_adsp", + .start = 0, + .size = SZ_32M, + .no_allocator = 0, + .cached = PMEM_NONCACHE_NORMAL, +}; + +static struct android_pmem_platform_data android_pmem_gpu_pdata = { + .name = "pmem_gpu", + .start = 0, + .size = SZ_32M, + .no_allocator = 0, + .cached = PMEM_CACHE_ENABLE, +}; + +static struct android_usb_platform_data android_usb_pdata = { + .vendor_id = 0x0bb4, + .product_id = 0x0c01, + .adb_product_id = 0x0c02, + .version = 0x0100, + .product_name = "Android Phone", + .manufacturer_name = "Freescale", + .nluns = 3, +}; + /*! * Board specific fixup function. It is called by \b setup_arch() in * setup.c file very early on during kernel starts. It allows the user to @@ -804,12 +984,32 @@ static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, int left_mem = 0; int gpu_mem = SZ_64M; int fb_mem = SZ_32M; + int size; mxc_set_cpu_type(MXC_CPU_MX51); get_cpu_wp = mx51_babbage_get_cpu_wp; set_num_cpu_wp = mx51_babbage_set_num_cpu_wp; + for_each_tag(t, tags) { + if (t->hdr.tag != ATAG_MEM) + continue; + size = t->u.mem.size; + + android_pmem_pdata.start = + PHYS_OFFSET + size - android_pmem_pdata.size; + android_pmem_gpu_pdata.start = + android_pmem_pdata.start - android_pmem_gpu_pdata.size; + gpu_device.resource[5].start = + android_pmem_gpu_pdata.start - SZ_16M; + gpu_device.resource[5].end = + gpu_device.resource[5].start + SZ_16M - 1; + size -= android_pmem_pdata.size; + size -= android_pmem_gpu_pdata.size; + size -= SZ_16M; + t->u.mem.size = size; + } +#if 0 for_each_tag(mem_tag, tags) { if (mem_tag->hdr.tag == ATAG_MEM) { total_mem = mem_tag->u.mem.size; @@ -866,7 +1066,82 @@ static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, } #endif } +#endif +} + +static struct switch_dev dvi_sdev; +static int state; +static struct delayed_work dvi_det_work; +static void dvi_update_detect_status(void) +{ + int level; + + level = gpio_get_value(BABBAGE_DVI_DET); + if (level == 1) { + pr_info(KERN_INFO "DVI device plug-in\n"); + state = 1; + } else { + pr_info(KERN_INFO "DVI device plug-out\n"); + state = 0; + } + switch_set_state(&dvi_sdev, state); +} + +static void dvi_work_func(struct work_struct *work) +{ + dvi_update_detect_status(); +} + +static irqreturn_t dvi_det_int(int irq, void *dev_id) +{ + schedule_delayed_work(&dvi_det_work, msecs_to_jiffies(10)); + return 0; +} + +static ssize_t print_switch_name(struct switch_dev *sdev, char *buf) +{ + return sprintf(buf, "dvi_det\n"); +} + +static ssize_t print_switch_state(struct switch_dev *sdev, char *buf) +{ + return sprintf(buf, "%s\n", (state ? "online" : "offline")); +} + +static int __init mxc_init_dvi_det(void) +{ + int irq, level, ret; + + if (!machine_is_mx51_babbage()) + return 0; + + dvi_sdev.name = "dvi_det"; + dvi_sdev.print_name = print_switch_name; + dvi_sdev.print_state = print_switch_state; + switch_dev_register(&dvi_sdev); + + level = gpio_get_value(BABBAGE_DVI_DET); + if (level == 1) { + pr_info(KERN_INFO "DVI device plug-in\n"); + state = 1; + } else { + pr_info(KERN_INFO "DVI device plug-out\n"); + state = 0; + } + + INIT_DELAYED_WORK(&dvi_det_work, dvi_work_func); + + irq = IOMUX_TO_IRQ_V3(BABBAGE_DVI_DET); + set_irq_type(irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING); + ret = request_irq(irq, dvi_det_int, 0, "dvi_det", 0); + if (ret) { + pr_info("register DVI detect interrupt failed\n"); + return -1; + } + return 0; } +late_initcall(mxc_init_dvi_det); + #define PWGT1SPIEN (1<<15) #define PWGT2SPIEN (1<<16) @@ -899,7 +1174,7 @@ static int __init mxc_init_power_key(void) { /* Set power key as wakeup resource */ int irq, ret; - irq = IOMUX_TO_IRQ(MX51_PIN_EIM_A27); + irq = IOMUX_TO_IRQ_V3(BABBAGE_POWER_KEY); set_irq_type(irq, IRQF_TRIGGER_RISING); ret = request_irq(irq, power_key_int, 0, "power_key", 0); if (ret) @@ -910,6 +1185,113 @@ static int __init mxc_init_power_key(void) } late_initcall(mxc_init_power_key); +static void __init mx51_babbage_io_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads, + ARRAY_SIZE(mx51babbage_pads)); + + gpio_request(BABBAGE_PMIC_INT, "pmic-int"); + gpio_request(BABBAGE_SD1_CD, "sdhc1-detect"); + gpio_request(BABBAGE_SD1_WP, "sdhc1-wp"); + + gpio_direction_input(BABBAGE_PMIC_INT); + gpio_direction_input(BABBAGE_SD1_CD); + gpio_direction_input(BABBAGE_SD1_WP); + + if (board_is_rev(BOARD_REV_2)) { + /* SD2 CD for BB2.5 */ + gpio_request(BABBAGE_SD2_CD_2_5, "sdhc2-detect"); + gpio_direction_input(BABBAGE_SD2_CD_2_5); + } else { + /* SD2 CD for BB2.0 */ + gpio_request(BABBAGE_SD2_CD_2_0, "sdhc2-detect"); + gpio_direction_input(BABBAGE_SD2_CD_2_0); + } + gpio_request(BABBAGE_SD2_WP, "sdhc2-wp"); + gpio_direction_input(BABBAGE_SD2_WP); + + /* reset usbh1 hub */ + gpio_request(BABBAGE_USBH1_HUB_RST, "hub-rst"); + gpio_direction_output(BABBAGE_USBH1_HUB_RST, 0); + gpio_set_value(BABBAGE_USBH1_HUB_RST, 0); + msleep(1); + gpio_set_value(BABBAGE_USBH1_HUB_RST, 1); + + /* reset FEC PHY */ + gpio_request(BABBAGE_FEC_PHY_RESET, "fec-phy-reset"); + gpio_direction_output(BABBAGE_FEC_PHY_RESET, 0); + msleep(10); + gpio_set_value(BABBAGE_FEC_PHY_RESET, 1); + + /* reset FM */ + gpio_request(BABBAGE_FM_RESET, "fm-reset"); + gpio_direction_output(BABBAGE_FM_RESET, 0); + msleep(10); + gpio_set_value(BABBAGE_FM_RESET, 1); + + /* Drive 26M_OSC_EN line high */ + gpio_request(BABBAGE_26M_OSC_EN, "26m-osc-en"); + gpio_direction_output(BABBAGE_26M_OSC_EN, 1); + + /* Drive USB_CLK_EN_B line low */ + gpio_request(BABBAGE_USB_CLK_EN_B, "usb-clk_en_b"); + gpio_direction_output(BABBAGE_USB_CLK_EN_B, 0); + + /* De-assert USB PHY RESETB */ + gpio_request(BABBAGE_PHY_RESET, "usb-phy-reset"); + gpio_direction_output(BABBAGE_PHY_RESET, 1); + + /* hphone_det_b */ + gpio_request(BABBAGE_HEADPHONE_DET, "hphone-det"); + gpio_direction_input(BABBAGE_HEADPHONE_DET); + + /* audio_clk_en_b */ + gpio_request(BABBAGE_AUDIO_CLK_EN, "audio-clk-en"); + gpio_direction_output(BABBAGE_AUDIO_CLK_EN, 0); + + /* power key */ + gpio_request(BABBAGE_POWER_KEY, "power-key"); + gpio_direction_input(BABBAGE_POWER_KEY); + + if (cpu_is_mx51_rev(CHIP_REV_3_0) > 0) { + /* DVI_I2C_ENB = 0 tristates the DVI I2C level shifter */ + gpio_request(BABBAGE_DVI_I2C_EN, "dvi-i2c-en"); + gpio_direction_output(BABBAGE_DVI_I2C_EN, 0); + } + + /* Deassert VGA reset to free i2c bus */ + gpio_request(BABBAGE_VGA_RESET, "vga-reset"); + gpio_direction_output(BABBAGE_VGA_RESET, 1); + + /* LCD related gpio */ + gpio_request(BABBAGE_DISP_BRIGHTNESS_CTL, "disp-brightness-ctl"); + gpio_request(BABBAGE_LVDS_POWER_DOWN, "lvds-power-down"); + gpio_request(BABBAGE_LCD_3V3_ON, "lcd-3v3-on"); + gpio_request(BABBAGE_LCD_5V_ON, "lcd-5v-on"); + gpio_direction_output(BABBAGE_DISP_BRIGHTNESS_CTL, 0); + gpio_direction_output(BABBAGE_LVDS_POWER_DOWN, 0); + gpio_direction_output(BABBAGE_LCD_3V3_ON, 0); + gpio_direction_output(BABBAGE_LCD_5V_ON, 0); + + /* Camera reset */ + gpio_request(BABBAGE_CAM_RESET, "cam-reset"); + gpio_direction_output(BABBAGE_CAM_RESET, 1); + + /* Camera low power */ + gpio_request(BABBAGE_CAM_LOW_POWER, "cam-low-power"); + gpio_direction_output(BABBAGE_CAM_LOW_POWER, 0); + + /* OSC_EN */ + gpio_request(BABBAGE_OSC_EN_B, "osc-en"); + gpio_direction_output(BABBAGE_OSC_EN_B, 1); + + if (enable_w1) { + /* OneWire */ + struct pad_desc onewire = MX51_PAD_OWIRE_LINE__OWIRE_LINE; + mxc_iomux_v3_setup_pad(&onewire); + } +} + /*! * Board specific initialization. */ @@ -917,14 +1299,16 @@ static void __init mxc_board_init(void) { mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk"); mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk"); + mxc_ipu_data.csi_clk[0] = clk_get(NULL, "csi_mclk1"); + mxc_ipu_data.csi_clk[1] = clk_get(NULL, "csi_mclk2"); mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); clk_put(mxc_spdif_data.spdif_core_clk); /* SD card detect irqs */ - mxcsdhc2_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO1_6); - mxcsdhc2_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO1_6); - mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0); - mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0); + mxcsdhc2_device.resource[2].start = IOMUX_TO_IRQ_V3(BABBAGE_SD2_CD_2_5); + mxcsdhc2_device.resource[2].end = IOMUX_TO_IRQ_V3(BABBAGE_SD2_CD_2_5); + mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ_V3(BABBAGE_SD1_CD); + mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ_V3(BABBAGE_SD1_CD); mxc_cpu_common_init(); mxc_register_gpios(); @@ -952,14 +1336,17 @@ static void __init mxc_board_init(void) mxc_register_device(&mxc_pwm1_device, NULL); mxc_register_device(&mxc_pwm_backlight_device, &mxc_pwm_backlight_data); mxc_register_device(&mxc_keypad_device, &keypad_plat_data); - mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0), - mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0), mxc_register_device(&mxcsdhc1_device, &mmc1_data); mxc_register_device(&mxcsdhc2_device, &mmc2_data); mxc_register_device(&mxc_ssi1_device, NULL); mxc_register_device(&mxc_ssi2_device, NULL); mxc_register_device(&mxc_alsa_spdif_device, &mxc_spdif_data); - mxc_register_device(&mxc_fec_device, NULL); + mxc_register_device(&mxc_fec_device, &fec_data); + mxc_register_device(&mxc_v4l2_device, NULL); + mxc_register_device(&mxc_v4l2out_device, NULL); + mxc_register_device(&mxc_android_pmem_device, &android_pmem_pdata); + mxc_register_device(&mxc_android_pmem_gpu_device, &android_pmem_gpu_pdata); + mxc_register_device(&android_usb_device, &android_usb_pdata); mx51_babbage_init_mc13892(); @@ -990,8 +1377,8 @@ static void __init mxc_board_init(void) if (cpu_is_mx51_rev(CHIP_REV_1_1) == 2) { sgtl5000_data.sysclk = 26000000; } - gpio_request(IOMUX_TO_GPIO(MX51_PIN_EIM_A23), "eim_a23"); - gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A23), 0); + gpio_request(BABBAGE_AUDAMP_STBY, "audioamp-stdby"); + gpio_direction_output(BABBAGE_AUDAMP_STBY, 0); mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data); mx5_usb_dr_init(); diff --git a/arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c b/arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c index 4aa15f3c2515..1626c95d54d2 100644 --- a/arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c +++ b/arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c @@ -23,8 +23,8 @@ #include <linux/regulator/machine.h> #include <linux/mfd/mc13892/core.h> #include <mach/irqs.h> -#include "iomux.h" -#include "mx51_pins.h" +#include <mach/hardware.h> +#include <mach/iomux-mx51.h> /* * Convenience conversion. @@ -406,8 +406,8 @@ static struct mc13892_platform_data mc13892_plat = { static struct spi_board_info __initdata mc13892_spi_device = { .modalias = "pmic_spi", - .irq = IOMUX_TO_IRQ(MX51_PIN_GPIO1_8), - .max_speed_hz = 1000000, /* max spi SCK clock speed in HZ */ + .irq = IOMUX_TO_IRQ_V3(8), + .max_speed_hz = 6000000, /* max spi SCK clock speed in HZ */ .bus_num = 1, .chip_select = 0, .platform_data = &mc13892_plat, diff --git a/arch/arm/mach-mx5/mx51_ccwmx51js.c b/arch/arm/mach-mx5/mx51_ccwmx51js.c index 63e0377e751b..bbacfc981d73 100644 --- a/arch/arm/mach-mx5/mx51_ccwmx51js.c +++ b/arch/arm/mach-mx5/mx51_ccwmx51js.c @@ -41,8 +41,6 @@ #include <asm/mach/arch.h> #include <asm/mach/time.h> #include <mach/memory.h> -#include <linux/input.h> -#include <linux/gpio_keys.h> #include <mach/gpio.h> #include <mach/mmc.h> #include <mach/mxc_dvfs.h> @@ -53,13 +51,16 @@ #include "mx51_pins.h" #include "devices_ccwmx51.h" #include "usb.h" +#include "linux/android_pmem.h" +#include "linux/usb/android.h" extern struct cpu_wp *(*get_cpu_wp)(int *wp); extern void (*set_num_cpu_wp)(int num); static int num_cpu_wp = 3; +u8 ccwmx51_swap_bi = 0; /* working point(wp): 0 - 800MHz; 1 - 166.25MHz; */ -static struct cpu_wp cpu_wp_auto[] = { +static struct cpu_wp cpu_wp_auto_800[] = { { .pll_rate = 1000000000, .cpu_rate = 1000000000, @@ -86,13 +87,56 @@ static struct cpu_wp cpu_wp_auto[] = { .mfd = 2, .mfn = 1, .cpu_podf = 4, - .cpu_voltage = 850000,}, + .cpu_voltage = 900000,}, +}; + +static struct cpu_wp cpu_wp_auto_600[] = { + { + .pll_rate = 600000000, + .cpu_rate = 600000000, + .pdf = 0, + .mfi = 6, + .mfd = 3, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1000000,}, + { + .pll_rate = 600000000, + .cpu_rate = 150000000, + .pdf = 3, + .mfi = 6, + .mfd = 3, + .mfn = 1, + .cpu_podf = 3, + .cpu_voltage = 950000,}, }; +static u32 ccwmx51_get_cpu_freq(void) +{ + u32 cpu_freq = 800000000; + + switch (system_serial_low & 0xff) { + case 4: + case 5: cpu_freq = 600000000; + num_cpu_wp = 2; + break; + } + + return cpu_freq; +} + struct cpu_wp *mx51_get_cpu_wp(int *wp) { + u32 cpu_clk_rate = ccwmx51_get_cpu_freq(); + *wp = num_cpu_wp; - return cpu_wp_auto; + + if (cpu_clk_rate == 800000000) { + return cpu_wp_auto_800; + } else if (cpu_clk_rate == 600000000) { + return cpu_wp_auto_600; + } + return NULL; } void mx51_set_num_cpu_wp(int num) @@ -101,6 +145,36 @@ void mx51_set_num_cpu_wp(int num) return; } +#if defined CONFIG_ANDROID_PMEM +static struct android_pmem_platform_data android_pmem_pdata = { + .name = "pmem_adsp", + .start = 0, + .size = SZ_32M, + .no_allocator = 0, + .cached = PMEM_NONCACHE_NORMAL, +}; + +static struct android_pmem_platform_data android_pmem_gpu_pdata = { + .name = "pmem_gpu", + .start = 0, + .size = SZ_32M, + .no_allocator = 0, + .cached = PMEM_CACHE_ENABLE, +}; +#endif + +#ifdef CONFIG_USB_ANDROID +static struct android_usb_platform_data android_usb_pdata = { + .vendor_id = 0x0bb4, + .product_id = 0x0c01, + .adb_product_id = 0x0c02, + .version = 0x0100, + .product_name = "Android Phone", + .manufacturer_name = "Freescale", + .nluns = 3, +}; +#endif + /*! * Board specific fixup function. It is called by \b setup_arch() in * setup.c file very early on during kernel starts. It allows the user to @@ -115,19 +189,48 @@ void mx51_set_num_cpu_wp(int num) static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) { - char *str; struct tag *t; +#ifdef CONFIG_ANDROID + int size; +#else + char *str; struct tag *mem_tag = 0; int total_mem = SZ_512M; int left_mem = 0; int gpu_mem = SZ_64M; - int fb_mem = SZ_32M; + int fb_mem = FB_MEM_SIZE; +#endif mxc_set_cpu_type(MXC_CPU_MX51); get_cpu_wp = mx51_get_cpu_wp; set_num_cpu_wp = mx51_set_num_cpu_wp; +#ifdef CONFIG_ANDROID + // TODO: Dual head support for Android. + // See commit 358e938e78b3380357f8f0c6dd54fa9fe4cc84c5 + // This commit removes Digi's dual display customizations + + for_each_tag(t, tags) { + if (t->hdr.tag != ATAG_MEM) + continue; + size = t->u.mem.size; + + android_pmem_pdata.start = + PHYS_OFFSET + size - android_pmem_pdata.size; + android_pmem_gpu_pdata.start = + android_pmem_pdata.start - android_pmem_gpu_pdata.size; + gpu_device.resource[5].start = + android_pmem_gpu_pdata.start - SZ_16M; + gpu_device.resource[5].end = + gpu_device.resource[5].start + SZ_16M - 1; + size -= android_pmem_pdata.size; + size -= android_pmem_gpu_pdata.size; + size -= SZ_16M; + t->u.mem.size = size; + } + +#else for_each_tag(mem_tag, tags) { if (mem_tag->hdr.tag == ATAG_MEM) { total_mem = mem_tag->u.mem.size; @@ -166,6 +269,9 @@ static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, } mem_tag->u.mem.size = left_mem; +#if defined(CONFIG_CCWMX51_DISP1) && defined(CONFIG_CCWMX51_DISP2) + fb_mem = fb_mem / 2; /* Divide the mem for between the displays */ +#endif /*reserve memory for gpu*/ gpu_device.resource[5].start = mem_tag->u.mem.start + left_mem; @@ -178,12 +284,23 @@ static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, gpu_device.resource[5].end + 1; mxcfb_resources[0].end = mxcfb_resources[0].start + fb_mem - 1; +#if defined(CONFIG_CCWMX51_DISP1) && defined(CONFIG_CCWMX51_DISP2) + mxcfb_resources[1].start = + mxcfb_resources[0].end + 1; + mxcfb_resources[1].end = + mxcfb_resources[1].start + fb_mem - 1; +#endif } else { mxcfb_resources[0].start = 0; mxcfb_resources[0].end = 0; + mxcfb_resources[1].start = 0; + mxcfb_resources[1].end = 0; } #endif } +#endif + + } #define PWGT1SPIEN (1<<15) @@ -203,97 +320,20 @@ static void mxc_power_off(void) #endif } -/* - * GPIO Buttons - */ -#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) -static struct gpio_keys_button ccwmx51js_buttons[] = { - { - .gpio = IOMUX_TO_GPIO(MX51_PIN_GPIO1_8), - .code = BTN_1, - .desc = "Button 1", - .active_low = 1, - .wakeup = 1, - }, - { - .gpio = IOMUX_TO_GPIO(MX51_PIN_GPIO1_1), - .code = BTN_2, - .desc = "Button 2", - .active_low = 1, - .wakeup = 1, - } -}; - -static struct gpio_keys_platform_data ccwmx51js_button_data = { - .buttons = ccwmx51js_buttons, - .nbuttons = ARRAY_SIZE(ccwmx51js_buttons), -}; - -static struct platform_device ccwmx51js_button_device = { - .name = "gpio-keys", - .id = -1, - .num_resources = 0, - .dev = { - .platform_data = &ccwmx51js_button_data, - } -}; - -static void __init ccwmx51js_add_device_buttons(void) -{ - platform_device_register(&ccwmx51js_button_device); -} -#else -static void __init ek_add_device_buttons(void) {} -#endif - - -#if defined(CONFIG_NEW_LEDS) - -/* - * GPIO LEDs - */ -static struct gpio_led_platform_data led_data; - -static struct gpio_led ccwmx51js_leds[] = { - { - .name = "LED1", - .gpio = IOMUX_TO_GPIO(MX51_PIN_NANDF_RB2), - .active_low = 1, - .default_trigger = "none", - }, - { - .name = "LED2", - .gpio = IOMUX_TO_GPIO(MX51_PIN_NANDF_RB1), - .active_low = 1, - .default_trigger = "none", - } -}; - -static struct platform_device ccwmx51js_gpio_leds_device = { - .name = "leds-gpio", - .id = -1, - .dev.platform_data = &led_data, -}; - -void __init ccwmx51js_gpio_leds(struct gpio_led *leds, int nr) -{ - if (!nr) - return; - - led_data.leds = leds; - led_data.num_leds = nr; - platform_device_register(&ccwmx51js_gpio_leds_device); -} - -#else -void __init at91_gpio_leds(struct gpio_led *leds, int nr) {} -#endif - /*! * Board specific initialization. */ static void __init mxc_board_init(void) { + /* Setup hwid information, passed through Serial ATAG */ + ccwmx51_set_mod_variant(system_serial_low & 0xff); + ccwmx51_set_mod_revision((system_serial_low >> 8) & 0xff); + ccwmx51_set_mod_sn(((system_serial_low << 8) & 0xff000000) | + ((system_serial_low >> 8) & 0x00ff0000) | + ((system_serial_high << 8) & 0x0000ff00) | + ((system_serial_high >> 8) & 0xff)); + + ccwmx51_swap_bi = system_serial_high >> 16; mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk"); mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk"); @@ -304,6 +344,7 @@ static void __init mxc_board_init(void) mxc_cpu_common_init(); mxc_register_gpios(); ccwmx51_io_init(); + ccwmx51_init_devices(); mxc_register_device(&mxc_wdt_device, NULL); mxc_register_device(&mxcspi1_device, &mxcspi1_data); @@ -330,23 +371,29 @@ static void __init mxc_board_init(void) mxc_register_device(&mxc_dvfs_per_device, &dvfs_per_data); mxc_register_device(&mxc_iim_device, NULL); mxc_register_device(&gpu_device, NULL); -#if defined(CONFIG_UIO_PDRV_GENIRQ) || defined(CONFIG_UIO_PDRV_GENIRQ_MODULE) - mxc_register_device(&mxc_gpu2d_device, &gpu2d_platform_data); +#if defined (CONFIG_MXC_SECURITY_SCC2) + mxc_register_device(&mxcscc_device, NULL); #endif mxc_register_device(&mxc_pwm1_device, NULL); mxc_register_device(&mxc_pwm_backlight_device, &mxc_pwm_backlight_data); - -#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE) - /* SD card detect irqs */ - mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0); - mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0); - mxcsdhc3_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO_NAND); - mxcsdhc3_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO_NAND); - mxc_register_device(&mxcsdhc1_device, &mmc1_data); - mxc_register_device(&mxcsdhc3_device, &mmc3_data); +#ifdef CONFIG_ANDROID_PMEM + mxc_register_device(&mxc_android_pmem_device, &android_pmem_pdata); + mxc_register_device(&mxc_android_pmem_gpu_device, &android_pmem_gpu_pdata); #endif +#ifdef CONFIG_USB_ANDROID + mxc_register_device(&android_usb_device, &android_usb_pdata); +#endif + +#ifdef CONFIG_ESDHCI_MXC_SELECT1 + ccwmx51_register_sdio(0); /* SDHC1 */ +#endif /* CONFIG_ESDHCI_MXC_SELECT1 */ +#if defined(CONFIG_ESDHCI_MXC_SELECT3) && \ + (!defined(CONFIG_PATA_FSL) && !defined(CONFIG_PATA_FSL_MODULE)) + ccwmx51_register_sdio(2); /* SDHC3 */ +#endif /* CONFIG_ESDHCI_MXC_SELECT3 && !CONFIG_PATA_FSL && !CONFIG_PATA_FSL_MODULE */ + #if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE) - mxc_register_device(&mxc_fec_device, NULL); + mxc_register_device(&mxc_fec_device, &fec_data); #endif #if defined(CONFIG_MTD_NAND_MXC) \ || defined(CONFIG_MTD_NAND_MXC_MODULE) \ @@ -356,6 +403,9 @@ static void __init mxc_board_init(void) || defined(CONFIG_MTD_NAND_MXC_V3_MODULE) mxc_register_device(&mxc_nandv2_mtd_device, &mxc_nand_data); #endif +#if defined(CONFIG_PATA_FSL) || defined(CONFIG_PATA_FSL_MODULE) + mxc_register_device(&pata_fsl_device, &ata_data); +#endif #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) mxc_register_device(&smsc911x_device, &ccwmx51_smsc9118); #endif @@ -368,23 +418,26 @@ static void __init mxc_board_init(void) mx5_usbh1_init(); #endif mx5_usb_dr_init(); -#if defined(CONFIG_FB_MXC_SYNC_PANEL) || defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) - mxc_register_device(&lcd_pdev, plcd_platform_data); - mxc_fb_devices[0].num_resources = ARRAY_SIZE(mxcfb_resources); - mxc_fb_devices[0].resource = mxcfb_resources; - mxc_register_device(&mxc_fb_devices[0], &mx51_fb_data[0]); -// mxc_register_device(&mxc_fb_devices[1], &mx51_fb_data[1]); -// mxc_register_device(&mxc_fb_devices[2], NULL); -#endif +#if defined(CONFIG_FB_MXC_SYNC_PANEL) || defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) && \ + (defined(CONFIG_CCWMX51_DISP0) || defined(CONFIG_CCWMX51_DISP1)) + ccwmx51_init_fb(); +#endif /* defined(CONFIG_FB_MXC_SYNC_PANEL) || ... */ #ifdef CONFIG_MXC_PMIC_MC13892 ccwmx51_init_mc13892(); /* Configure PMIC irq line */ set_irq_type(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5), IRQ_TYPE_EDGE_BOTH); #endif - ccwmx51js_add_device_buttons(); - ccwmx51js_gpio_leds(ccwmx51js_leds, ARRAY_SIZE(ccwmx51js_leds)); +#ifdef CONFIG_SYSFS + ccwmx51_create_sysfs_entries(); +#endif +#ifdef CONFIG_CCWMX51_SECOND_TOUCH + ccwmx51_init_2nd_touch(); +#endif +#if defined(CONFIG_KEYBOARD_GPIO) + mxc_register_device(&ccwmx51js_keys_gpio, &ccwmx51js_gpio_key_info); +#endif pm_power_off = mxc_power_off; } @@ -394,9 +447,9 @@ static void __init ccwmx51_timer_init(void) /* Change the CPU voltages for TO2*/ if (cpu_is_mx51_rev(CHIP_REV_2_0) <= 1) { - cpu_wp_auto[0].cpu_voltage = 1175000; - cpu_wp_auto[1].cpu_voltage = 1100000; - cpu_wp_auto[2].cpu_voltage = 1000000; + cpu_wp_auto_800[0].cpu_voltage = 1175000; + cpu_wp_auto_800[1].cpu_voltage = 1100000; + cpu_wp_auto_800[2].cpu_voltage = 1000000; } mx51_clocks_init(32768, 24000000, 22579200, 24576000); @@ -409,14 +462,30 @@ static struct sys_timer mxc_timer = { .init = ccwmx51_timer_init, }; -MACHINE_START(CCWMX51JS, "ConnectCore Wi-i.MX51 on a JSK board") +#if defined(CONFIG_MACH_CCWMX51JS) +MACHINE_START(CCWMX51JS, "ConnectCore Wi-i.MX51"BOARD_NAME) + /* Maintainer: Digi International, Inc. */ + .phys_io = AIPS1_BASE_ADDR, + .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, + .boot_params = PHYS_OFFSET + 0x100, + .fixup = fixup_mxc_board, + .map_io = mx5_map_io, + .init_irq = mx5_init_irq, + .init_machine = mxc_board_init, + .timer = &mxc_timer, +MACHINE_END +#endif /* CONFIG_MACH_CCWMX51JS */ + +#if defined(CONFIG_MACH_CCMX51JS) +MACHINE_START(CCMX51JS, "ConnectCore i.MX51"BOARD_NAME) /* Maintainer: Digi International, Inc. */ - .phys_io = AIPS1_BASE_ADDR, - .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, - .boot_params = PHYS_OFFSET + 0x100, - .fixup = fixup_mxc_board, - .map_io = mx5_map_io, - .init_irq = mx5_init_irq, - .init_machine = mxc_board_init, - .timer = &mxc_timer, + .phys_io = AIPS1_BASE_ADDR, + .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, + .boot_params = PHYS_OFFSET + 0x100, + .fixup = fixup_mxc_board, + .map_io = mx5_map_io, + .init_irq = mx5_init_irq, + .init_machine = mxc_board_init, + .timer = &mxc_timer, MACHINE_END +#endif /* CONFIG_MACH_CCMX51JS */ diff --git a/arch/arm/mach-mx5/mx51_ccwmx51js_gpio.c b/arch/arm/mach-mx5/mx51_ccwmx51js_gpio.c index 51b9301a3547..b626605bd8fa 100644 --- a/arch/arm/mach-mx5/mx51_ccwmx51js_gpio.c +++ b/arch/arm/mach-mx5/mx51_ccwmx51js_gpio.c @@ -21,8 +21,7 @@ #include "iomux.h" #include "mx51_pins.h" - -static void ccwmx51_mmc2_gpio_active(void); +#include "board-ccwmx51.h" /** @@ -30,8 +29,8 @@ static void ccwmx51_mmc2_gpio_active(void); */ #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_ext_eth_pins[] = { - {MX51_PIN_EIM_CS5, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_KEEPER | PAD_CTL_DRV_MEDIUM), }, + {MX51_PIN_EIM_CS5, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_KEEPER | PAD_CTL_DRV_MEDIUM), }, {MX51_PIN_EIM_OE, IOMUX_CONFIG_ALT0,}, {MX51_PIN_EIM_DA0, IOMUX_CONFIG_ALT0,}, {MX51_PIN_EIM_DA1, IOMUX_CONFIG_ALT0,}, @@ -62,7 +61,7 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_ext_eth_pins[] = { #endif #if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE) -static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_mmc_pins[] = { +static struct mxc_iomux_pin_cfg ccwmx51_iomux_mmc1_pins[] = { /* SDHC1*/ { MX51_PIN_SD1_CMD, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, @@ -94,11 +93,49 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_mmc_pins[] = { (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | PAD_CTL_47K_PU | PAD_CTL_SRE_FAST), }, +#ifdef CONFIG_JSCCWMX51_V1 { MX51_PIN_GPIO1_0, IOMUX_CONFIG_GPIO | IOMUX_CONFIG_SION, (PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU), }, +#endif +}; + +#ifdef CONFIG_MACH_CCWMX51JS +/* IOMUX settings, for the wireless interface on Wi-i.MX51 module */ +#define SD2_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_DRV_VOT_HIGH | \ + PAD_CTL_22K_PU | PAD_CTL_PUE_PULL | \ + PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST) +static struct mxc_iomux_pin_cfg ccwmx51_iomux_mmc2_pins[] = { + /* SDHC2*/ + { + MX51_PIN_SD2_CMD, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + SD2_PAD_CFG, + }, + { + MX51_PIN_SD2_CLK, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + SD2_PAD_CFG, + }, + { + MX51_PIN_SD2_DATA0, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + SD2_PAD_CFG, + }, + { + MX51_PIN_SD2_DATA1, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + SD2_PAD_CFG, + }, + { + MX51_PIN_SD2_DATA2, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + SD2_PAD_CFG, + }, + { + MX51_PIN_SD2_DATA3, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + SD2_PAD_CFG, + }, +}; +#endif +static struct mxc_iomux_pin_cfg ccwmx51_iomux_mmc3_pins[] = { /* SDHC3*/ { MX51_PIN_NANDF_RDY_INT, IOMUX_CONFIG_ALT5 | IOMUX_CONFIG_SION, @@ -137,6 +174,56 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_mmc_pins[] = { (PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU), }, }; + +void gpio_sdhc_active(int interface) +{ + int i; + + switch (interface) { + case 0: + for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_mmc1_pins); i++) { + mxc_request_iomux(ccwmx51_iomux_mmc1_pins[i].pin, + ccwmx51_iomux_mmc1_pins[i].mux_mode); + if (ccwmx51_iomux_mmc1_pins[i].pad_cfg) + mxc_iomux_set_pad(ccwmx51_iomux_mmc1_pins[i].pin, + ccwmx51_iomux_mmc1_pins[i].pad_cfg); + if (ccwmx51_iomux_mmc1_pins[i].in_select) + mxc_iomux_set_input(ccwmx51_iomux_mmc1_pins[i].in_select, + ccwmx51_iomux_mmc1_pins[i].in_mode); + } + break; + case 1: +#ifdef CONFIG_MACH_CCWMX51JS + for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_mmc2_pins); i++) { + mxc_request_iomux(ccwmx51_iomux_mmc2_pins[i].pin, + ccwmx51_iomux_mmc2_pins[i].mux_mode); + if (ccwmx51_iomux_mmc2_pins[i].pad_cfg) + mxc_iomux_set_pad(ccwmx51_iomux_mmc2_pins[i].pin, + ccwmx51_iomux_mmc2_pins[i].pad_cfg); + if (ccwmx51_iomux_mmc2_pins[i].in_select) + mxc_iomux_set_input(ccwmx51_iomux_mmc2_pins[i].in_select, + ccwmx51_iomux_mmc2_pins[i].in_mode); + } +#endif + break; + + case 2: + for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_mmc3_pins); i++) { + mxc_request_iomux(ccwmx51_iomux_mmc3_pins[i].pin, + ccwmx51_iomux_mmc3_pins[i].mux_mode); + if (ccwmx51_iomux_mmc3_pins[i].pad_cfg) + mxc_iomux_set_pad(ccwmx51_iomux_mmc3_pins[i].pin, + ccwmx51_iomux_mmc3_pins[i].pad_cfg); + if (ccwmx51_iomux_mmc3_pins[i].in_select) + mxc_iomux_set_input(ccwmx51_iomux_mmc3_pins[i].in_select, + ccwmx51_iomux_mmc3_pins[i].in_mode); + } + break; + } +} +EXPORT_SYMBOL(gpio_sdhc_active); +void gpio_sdhc_inactive(int module) {} +EXPORT_SYMBOL(gpio_sdhc_inactive); #endif #if defined(CONFIG_USB_EHCI_ARC_H1) || defined(CONFIG_USB_EHCI_ARC_H1_MODULE) @@ -202,122 +289,218 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_usbh1_pins[] = { PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE), }, { /* USBH PHY RESET */ - MX51_PIN_DISPB2_SER_RS, IOMUX_CONFIG_GPIO, + MX51_PIN_DISPB2_SER_RS, IOMUX_CONFIG_ALT4, (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_47K_PU | PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE), + MUX_IN_GPIO3_IPP_IND_G_IN_8_SELECT_INPUT, INPUT_CTL_PATH1 }, }; #endif #if defined(CONFIG_FB_MXC_SYNC_PANEL) || defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) -static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_video1_pins[] = { - { /* DISP1 DAT0 */ +#if defined(CONFIG_CCWMX51_DISP0) +#define DISP1_PAD0 (PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST) +static struct mxc_iomux_pin_cfg ccwmx51_iomux_video1_pins[] = { + { /* DISP1 DAT0 */ MX51_PIN_DISP1_DAT0, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT1 */ MX51_PIN_DISP1_DAT1, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT2 */ MX51_PIN_DISP1_DAT2, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT3 */ MX51_PIN_DISP1_DAT3, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT4 */ MX51_PIN_DISP1_DAT4, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT5 */ MX51_PIN_DISP1_DAT5, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT6 */ MX51_PIN_DISP1_DAT6, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT7 */ MX51_PIN_DISP1_DAT7, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT8 */ MX51_PIN_DISP1_DAT8, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT9 */ MX51_PIN_DISP1_DAT9, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT10 */ MX51_PIN_DISP1_DAT10, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT11 */ MX51_PIN_DISP1_DAT11, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT12 */ MX51_PIN_DISP1_DAT12, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT13 */ MX51_PIN_DISP1_DAT13, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT14 */ MX51_PIN_DISP1_DAT14, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT15 */ MX51_PIN_DISP1_DAT15, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT16 */ MX51_PIN_DISP1_DAT16, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT17 */ MX51_PIN_DISP1_DAT17, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT18 */ MX51_PIN_DISP1_DAT18, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT19 */ MX51_PIN_DISP1_DAT19, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT20 */ MX51_PIN_DISP1_DAT20, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + DISP1_PAD0, }, { /* DISP1 DAT21 */ - MX51_PIN_DISP1_DAT21, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), - }, - { /* DISP1 DAT22 */ - MX51_PIN_DISP1_DAT22, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + MX51_PIN_DISP1_DAT21, IOMUX_CONFIG_ALT0, + DISP1_PAD0, + }, +#if !defined(CONFIG_CCWMX51_DISP1) + { /* DISP1 DAT22 */ + MX51_PIN_DISP1_DAT22, IOMUX_CONFIG_ALT0, + DISP1_PAD0, }, { /* DISP1 DAT23 */ - MX51_PIN_DISP1_DAT23, IOMUX_CONFIG_ALT0, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), - }, - { /* LCD1 Power Enable, as gpio */ - MX51_PIN_DI1_PIN11, IOMUX_CONFIG_GPIO, - (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_47K_PU | - PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE), - }, + MX51_PIN_DISP1_DAT23, IOMUX_CONFIG_ALT0, + DISP1_PAD0, + }, +#endif }; #endif +#if defined(CONFIG_CCWMX51_DISP1) +#define DISP2_PAD0 (PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST) +static struct mxc_iomux_pin_cfg ccwmx51_iomux_video2_pins[] = { + /* This interface can be enabled only if the FEC interface is disabled */ + { /* DISP2 DAT0 */ + MX51_PIN_DISP2_DAT0, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT1 */ + MX51_PIN_DISP2_DAT1, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT2 */ + MX51_PIN_DISP2_DAT2, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT3 */ + MX51_PIN_DISP2_DAT3, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT4 */ + MX51_PIN_DISP2_DAT4, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT5 */ + MX51_PIN_DISP2_DAT5, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT6 */ + MX51_PIN_DISP2_DAT6, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT7 */ + MX51_PIN_DISP2_DAT7, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT8 */ + MX51_PIN_DISP2_DAT8, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT9 */ + MX51_PIN_DISP2_DAT9, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT10 */ + MX51_PIN_DISP2_DAT10, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT11 */ + MX51_PIN_DISP2_DAT11, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT12 */ + MX51_PIN_DISP2_DAT12, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT13 */ + MX51_PIN_DISP2_DAT13, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT14 */ + MX51_PIN_DISP2_DAT14, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DAT15 */ + MX51_PIN_DISP2_DAT15, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 16 (also DISP1 DAT22) */ + MX51_PIN_DISP1_DAT22, IOMUX_CONFIG_ALT5, + DISP2_PAD0, + }, + { /* DISP2 17 (also DISP1 DAT23) */ + MX51_PIN_DISP1_DAT23, IOMUX_CONFIG_ALT5, + DISP2_PAD0, + }, + { /* DISP2 HSYNC */ + MX51_PIN_DI2_PIN2, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 VSYNC */ + MX51_PIN_DI2_PIN3, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 PCLK */ + MX51_PIN_DI2_DISP_CLK, IOMUX_CONFIG_ALT0, + DISP2_PAD0, + }, + { /* DISP2 DRDY */ + MX51_PIN_DI_GP4, IOMUX_CONFIG_ALT4, + DISP2_PAD0, + }, +}; +#endif +#endif + #if defined(CONFIG_I2C_MXC) || defined(CONFIG_I2C_MXC_MODULE) static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_i2c_pins[] = { -#ifdef CONFIG_I2C_MXC_SELECT1 +#if defined (CONFIG_I2C_MXC_SELECT1) { MX51_PIN_SD2_CMD, IOMUX_CONFIG_ALT1 | IOMUX_CONFIG_SION, (PAD_CTL_SRE_FAST | PAD_CTL_ODE_OPENDRAIN_ENABLE | PAD_CTL_HYS_ENABLE | @@ -376,28 +559,6 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_devices_pins[] = { PAD_CTL_100K_PU | PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST), }, #endif - /* Push Buttons */ -#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) - { /* Button 1 */ - MX51_PIN_GPIO1_8, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), - }, - { /* Button 2 */ - MX51_PIN_GPIO1_1, IOMUX_CONFIG_ALT1 | IOMUX_CONFIG_SION, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), - }, -#endif - /* LEDs */ -#if defined(CONFIG_NEW_LEDS) - { /* LED1 */ - MX51_PIN_NANDF_RB2, IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), - }, - { /* LED2 */ - MX51_PIN_NANDF_RB1, IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION, - (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), - }, -#endif }; #if defined(CONFIG_SND_SOC_WM8753) || defined(CONFIG_SND_SOC_WM8753_MODULE) @@ -429,6 +590,93 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_audio_pins[] = { }; #endif +#if defined CONFIG_VIDEO_MXC_IPU_CAMERA +static struct mxc_iomux_pin_cfg __initdata ccwmx51_camera_pins[] = { + /* CSI0 camera interface 1 */ + { + MX51_PIN_CSI1_D12, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D13, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D14, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D15, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D16, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D17, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D18, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_D19, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI1_VSYNC, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + (PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW), + }, + { + MX51_PIN_CSI1_HSYNC, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + (PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW), + }, + /* Configure GPIO3_13 as RESET for camera 1 */ + { + MX51_PIN_CSI1_D9, IOMUX_CONFIG_ALT3, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_MEDIUM | PAD_CTL_SRE_FAST), + }, + /* CSI2 camera interface 2 */ + { + MX51_PIN_CSI2_D12, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI2_D13, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI2_D14, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI2_D15, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI2_D16, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI2_D17, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI2_D18, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI2_D19, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE, + }, + { + MX51_PIN_CSI2_VSYNC, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + (PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW), + }, + { + MX51_PIN_CSI2_HSYNC, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + (PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW), + }, + { + MX51_PIN_CSI2_PIXCLK, IOMUX_CONFIG_ALT0, + (PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW), + }, + /* Configure GPIO3_7 as RESET for camera 2 */ + { + MX51_PIN_DISPB2_SER_CLK, IOMUX_CONFIG_ALT4, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_MEDIUM | PAD_CTL_SRE_FAST | IOMUX_CONFIG_SION), + MUX_IN_GPIO3_IPP_IND_G_IN_7_SELECT_INPUT, + INPUT_CTL_PATH1 + }, +}; +#endif /* #if defined CONFIG_VIDEO_MXC_IPU_CAMERA */ + #if defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE) static struct mxc_iomux_pin_cfg __initdata ccwmx51_cspi_pins[] = { #ifdef CONFIG_SPI_MXC_SELECT1 @@ -453,6 +701,29 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_cspi_pins[] = { (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_47K_PU | PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE), }, + +#if defined(CONFIG_JSCCWMX51_V1) + { /* TS CS for LCD1 on CCWMX51 EAK */ + MX51_PIN_DI1_D1_CS, IOMUX_CONFIG_ALT4, + (PAD_CTL_SRE_SLOW | PAD_CTL_DRV_MEDIUM | PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PUE_KEEPER | PAD_CTL_HYS_NONE), + MUX_IN_GPIO3_IPP_IND_G_IN_4_SELECT_INPUT,INPUT_CTL_PATH1 + }, + { /* TS CS for LCD2 on CCWMX51 EAK */ + MX51_PIN_CSPI1_RDY, IOMUX_CONFIG_ALT3, + (PAD_CTL_SRE_SLOW | PAD_CTL_DRV_MEDIUM | PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PUE_PULL | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_NONE), + MUX_IN_AUDMUX_P4_INPUT_TXFS_AMX_SELECT_INPUT,INPUT_CTL_PATH1 + }, +#else + { /* TS CS for LCD1 and LCD2 on CCWMX51 JSK */ + MX51_PIN_CSPI1_RDY, IOMUX_CONFIG_ALT3, + (PAD_CTL_SRE_SLOW | PAD_CTL_DRV_MEDIUM | PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PUE_PULL | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_NONE), + MUX_IN_AUDMUX_P4_INPUT_TXFS_AMX_SELECT_INPUT,INPUT_CTL_PATH1 + }, +#endif + #ifdef CONFIG_SPI_MXC_SELECT1_SS1 { /* SS1 */ MX51_PIN_CSPI1_SS1, IOMUX_CONFIG_GPIO, @@ -461,7 +732,7 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_cspi_pins[] = { }, #endif #endif -#ifdef CONFIG_SPI_MXC_SELECT2 +#if defined(CONFIG_SPI_MXC_SELECT2) && (!defined(CONFIG_PATA_FSL) && !defined(CONFIG_PATA_FSL_MODULE)) /* ECSPI2 */ { /* SCLK */ MX51_PIN_NANDF_RB2, IOMUX_CONFIG_ALT2, @@ -534,17 +805,37 @@ void ccwmx51_gpio_spi_chipselect_active(int busnum, int ssb_pol, int chipselect) { u8 mask = 0x1 << (chipselect - 1); + /* Deassert/Assert the different CS lines for the different buses */ switch (busnum) { case 1: switch (chipselect) { case 0x1: + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS1), + (ssb_pol & mask) ? 0 : 1); +#ifdef CONFIG_CCWMX51_SECOND_TOUCH + gpio_set_value(IOMUX_TO_GPIO(SECOND_TS_SPI_SS_PIN), 1); +#endif gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS0), (ssb_pol & mask) ? 1 : 0); break; case 0x2: + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS0), + (ssb_pol & mask) ? 0 : 1); +#ifdef CONFIG_CCWMX51_SECOND_TOUCH + gpio_set_value(IOMUX_TO_GPIO(SECOND_TS_SPI_SS_PIN), 1); +#endif gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS1), (ssb_pol & mask) ? 1 : 0); break; +#ifdef CONFIG_CCWMX51_SECOND_TOUCH + case 0x4: + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS0), + (ssb_pol & mask) ? 0 : 1); + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS1), + (ssb_pol & mask) ? 0 : 1); + gpio_set_value(IOMUX_TO_GPIO(SECOND_TS_SPI_SS_PIN), 0); + break; +#endif default: break; } @@ -573,6 +864,11 @@ void ccwmx51_gpio_spi_chipselect_inactive(int busnum, int ssb_pol, gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS1), (ssb_pol & mask) ? 0 : 1); break; +#ifdef CONFIG_CCWMX51_SECOND_TOUCH + case 0x4: + gpio_set_value(IOMUX_TO_GPIO(SECOND_TS_SPI_SS_PIN), 1); + break; +#endif default: break; } @@ -581,20 +877,159 @@ void ccwmx51_gpio_spi_chipselect_inactive(int busnum, int ssb_pol, case 3: default: break; - } + } } EXPORT_SYMBOL(ccwmx51_gpio_spi_chipselect_inactive); - #endif /* defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE) */ -void __init ccwmx51_io_init(void) +#if defined(CONFIG_PATA_FSL) || defined(CONFIG_PATA_FSL_MODULE) +static struct mxc_iomux_pin_cfg ata_iomux_pins[] = { + { + MX51_PIN_NANDF_ALE, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_CS2, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_CS3, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_CS4, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_CS5, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_CS6, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_RE_B, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_WE_B, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_CLE, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_RB0, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_WP_B, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_GPIO_NAND, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_RB1, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D0, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D1, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D2, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D3, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D4, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D5, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D6, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D7, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D8, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D9, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D10, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D11, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D12, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D13, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D14, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, + { + MX51_PIN_NANDF_D15, IOMUX_CONFIG_ALT1, + (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH), + }, +}; + +void gpio_ata_active(void) { int i; + for (i = 0; i < ARRAY_SIZE(ata_iomux_pins); i++) { + mxc_request_iomux(ata_iomux_pins[i].pin, + ata_iomux_pins[i].mux_mode); + if (ata_iomux_pins[i].pad_cfg) + mxc_iomux_set_pad(ata_iomux_pins[i].pin, + ata_iomux_pins[i].pad_cfg); + if (ata_iomux_pins[i].in_select) + mxc_iomux_set_input(ata_iomux_pins[i].in_select, + ata_iomux_pins[i].in_mode); + } +} +EXPORT_SYMBOL(gpio_ata_active); +void gpio_ata_inactive(void) {} +EXPORT_SYMBOL(gpio_ata_inactive); +#endif /* CONFIG_PATA_FSL || CONFIG_PATA_FSL_MODULE */ + +void __init ccwmx51_io_init(void) +{ + int i; + #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) - for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_ext_eth_pins); i++) { - mxc_request_iomux(ccwmx51_iomux_ext_eth_pins[i].pin, - ccwmx51_iomux_ext_eth_pins[i].mux_mode); + for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_ext_eth_pins); i++) { + mxc_request_iomux(ccwmx51_iomux_ext_eth_pins[i].pin, + ccwmx51_iomux_ext_eth_pins[i].mux_mode); if (ccwmx51_iomux_ext_eth_pins[i].pad_cfg) mxc_iomux_set_pad(ccwmx51_iomux_ext_eth_pins[i].pin, ccwmx51_iomux_ext_eth_pins[i].pad_cfg); @@ -604,17 +1039,40 @@ void __init ccwmx51_io_init(void) } #endif -#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE) - for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_mmc_pins); i++) { - mxc_request_iomux(ccwmx51_iomux_mmc_pins[i].pin, - ccwmx51_iomux_mmc_pins[i].mux_mode); - if (ccwmx51_iomux_mmc_pins[i].pad_cfg) - mxc_iomux_set_pad(ccwmx51_iomux_mmc_pins[i].pin, - ccwmx51_iomux_mmc_pins[i].pad_cfg); - if (ccwmx51_iomux_mmc_pins[i].in_select) - mxc_iomux_set_input(ccwmx51_iomux_mmc_pins[i].in_select, - ccwmx51_iomux_mmc_pins[i].in_mode); +#if defined CONFIG_VIDEO_MXC_IPU_CAMERA + for (i = 0; i < ARRAY_SIZE(ccwmx51_camera_pins); i++) { + mxc_request_iomux(ccwmx51_camera_pins[i].pin, + ccwmx51_camera_pins[i].mux_mode); + if (ccwmx51_camera_pins[i].pad_cfg) + mxc_iomux_set_pad(ccwmx51_camera_pins[i].pin, + ccwmx51_camera_pins[i].pad_cfg); + if (ccwmx51_camera_pins[i].in_select) + mxc_iomux_set_input(ccwmx51_camera_pins[i].in_select, + ccwmx51_camera_pins[i].in_mode); } + + /* Configure non muxed pins */ + mxc_iomux_set_pad(MX51_PIN_CSI1_PIXCLK,PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW); + mxc_iomux_set_pad(MX51_PIN_CSI2_PIXCLK,PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW); + mxc_iomux_set_pad(MX51_PIN_CSI1_MCLK,PAD_CTL_DRV_HIGH | PAD_CTL_SRE_SLOW); + + /* Camera 1 reset */ + gpio_request(IOMUX_TO_GPIO(MX51_PIN_CSI1_D9), "gpio3_13"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_CSI1_D9), 0); + // Take camera out of reset + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSI1_D9), 0); + msleep(100); + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSI1_D9), 1); + msleep(100); + + /* Camera 2 reset */ + gpio_request(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_CLK), "gpio3_7"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_CLK), 0); + // Take camera out of reset + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_CLK), 0); + msleep(100); + gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_CLK), 1); + msleep(100); #endif #if defined(CONFIG_USB_EHCI_ARC_H1) || defined(CONFIG_USB_EHCI_ARC_H1_MODULE) @@ -630,25 +1088,9 @@ void __init ccwmx51_io_init(void) } #endif -#if defined(CONFIG_FB_MXC_SYNC_PANEL) || defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) - for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_video1_pins); i++) { - mxc_request_iomux(ccwmx51_iomux_video1_pins[i].pin, - ccwmx51_iomux_video1_pins[i].mux_mode); - if (ccwmx51_iomux_video1_pins[i].pad_cfg) - mxc_iomux_set_pad(ccwmx51_iomux_video1_pins[i].pin, - ccwmx51_iomux_video1_pins[i].pad_cfg); - if (ccwmx51_iomux_video1_pins[i].in_select) - mxc_iomux_set_input(ccwmx51_iomux_video1_pins[i].in_select, - ccwmx51_iomux_video1_pins[i].in_mode); - } - /* LCD Power Enable */ - gpio_request(IOMUX_TO_GPIO(MX51_PIN_DI1_PIN11), "gpio3_0"); - gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DI1_PIN11), 0); -#endif - #if defined(CONFIG_I2C_MXC) || defined(CONFIG_I2C_MXC_MODULE) - for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_i2c_pins); i++) { - mxc_request_iomux(ccwmx51_iomux_i2c_pins[i].pin, + for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_i2c_pins); i++) { + mxc_request_iomux(ccwmx51_iomux_i2c_pins[i].pin, ccwmx51_iomux_i2c_pins[i].mux_mode); if (ccwmx51_iomux_i2c_pins[i].pad_cfg) mxc_iomux_set_pad(ccwmx51_iomux_i2c_pins[i].pin, @@ -695,16 +1137,18 @@ void __init ccwmx51_io_init(void) #endif #ifndef CONFIG_SPI_MXC_SELECT2 - /* Configure as GPIO to be used to read LED status */ - mxc_config_iomux(MX51_PIN_NANDF_RB2,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); - mxc_iomux_set_pad(MX51_PIN_NANDF_RB2,PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU); - mxc_config_iomux(MX51_PIN_NANDF_RB1,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); - mxc_iomux_set_pad(MX51_PIN_NANDF_RB1,PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU); + /* Configure as GPIO to be used to read LED status */ + mxc_config_iomux(MX51_PIN_NANDF_RB2,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); + mxc_iomux_set_pad(MX51_PIN_NANDF_RB2,PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU); +#if !defined(CONFIG_PATA_FSL) && !defined(CONFIG_PATA_FSL_MODULE) + mxc_config_iomux(MX51_PIN_NANDF_RB1,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); + mxc_iomux_set_pad(MX51_PIN_NANDF_RB1,PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU); +#endif /* !defined(CONFIG_PATA_FSL) && !defined(CONFIG_PATA_FSL_MODULE) */ #endif #endif - for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_devices_pins); i++) { + for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_devices_pins); i++) { mxc_request_iomux(ccwmx51_iomux_devices_pins[i].pin, ccwmx51_iomux_devices_pins[i].mux_mode); if (ccwmx51_iomux_devices_pins[i].pad_cfg) @@ -727,67 +1171,91 @@ void __init ccwmx51_io_init(void) gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_RS), 1); #endif -#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE) - /* For the wireless module */ - ccwmx51_mmc2_gpio_active(); + /* Configure user key 1 as GPIO */ +#if defined(CONFIG_JSCCWMX51_V2) + mxc_config_iomux(MX51_PIN_DISPB2_SER_DIO,IOMUX_CONFIG_ALT4 | IOMUX_CONFIG_SION); + mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_6_SELECT_INPUT,INPUT_CTL_PATH1); #endif -} -#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE) -/* IOMUX settings, for the wireless interface */ -static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_mmc2_pins[] = { - /* SDHC2*/ - { - MX51_PIN_SD2_CMD, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, - (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | - PAD_CTL_47K_PU | PAD_CTL_SRE_FAST), - }, - { - MX51_PIN_SD2_CLK, IOMUX_CONFIG_ALT0, - (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | - PAD_CTL_47K_PU | PAD_CTL_SRE_FAST), - }, - { - MX51_PIN_SD2_DATA0, IOMUX_CONFIG_ALT0, - (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | - PAD_CTL_47K_PU | PAD_CTL_SRE_FAST), - }, - { - MX51_PIN_SD2_DATA1, IOMUX_CONFIG_ALT0, - (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | - PAD_CTL_47K_PU | PAD_CTL_SRE_FAST), - }, - { - MX51_PIN_SD2_DATA2, IOMUX_CONFIG_ALT0, - (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | - PAD_CTL_47K_PU | PAD_CTL_SRE_FAST), - }, - { - MX51_PIN_SD2_DATA3, IOMUX_CONFIG_ALT0, - (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | - PAD_CTL_47K_PU | PAD_CTL_SRE_FAST), - }, -}; + /* Configure Digital IO as GPIO */ +#if defined(CONFIG_JSCCWMX51_V1) +#if !defined(CONFIG_PATA_FSL) && !defined(CONFIG_PATA_FSL_MODULE) + mxc_config_iomux(MX51_PIN_NANDF_CS4,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); + mxc_config_iomux(MX51_PIN_NANDF_CS5,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); + mxc_config_iomux(MX51_PIN_NANDF_CS6,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); +#endif +#if !defined(CONFIG_MMC_IMX_ESDHCI) && !defined(CONFIG_MMC_IMX_ESDHCI_MODULE) + mxc_config_iomux(MX51_PIN_NANDF_CS7,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); +#endif -static void ccwmx51_mmc2_gpio_active(void) -{ - int i; + mxc_config_iomux(MX51_PIN_DISPB2_SER_DIN,IOMUX_CONFIG_ALT4 | IOMUX_CONFIG_SION); + mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_5_SELECT_INPUT,INPUT_CTL_PATH1); + mxc_config_iomux(MX51_PIN_DISPB2_SER_DIO,IOMUX_CONFIG_ALT4 | IOMUX_CONFIG_SION); + mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_6_SELECT_INPUT,INPUT_CTL_PATH1); +#if !defined (CONFIG_VIDEO_MXC_IPU_CAMERA) + mxc_config_iomux(MX51_PIN_DISPB2_SER_CLK,IOMUX_CONFIG_ALT4 | IOMUX_CONFIG_SION); + mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_7_SELECT_INPUT,INPUT_CTL_PATH1); +#endif +#if !defined(CONFIG_USB_EHCI_ARC_H1) && !defined(CONFIG_USB_EHCI_ARC_H1_MODULE) + mxc_config_iomux(MX51_PIN_DISPB2_SER_RS,IOMUX_CONFIG_ALT4 | IOMUX_CONFIG_SION); + mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_8_SELECT_INPUT,INPUT_CTL_PATH1); +#endif +#endif + +#if defined(CONFIG_JSCCWMX51_V2) +#if !defined (CONFIG_SPI_MXC_SELECT2) + mxc_config_iomux(MX51_PIN_NANDF_RB3,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); +#endif + +#if !defined(CONFIG_PATA_FSL) && !defined(CONFIG_PATA_FSL_MODULE) + mxc_config_iomux(MX51_PIN_NANDF_CS2,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); + mxc_config_iomux(MX51_PIN_NANDF_CS4,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); + mxc_config_iomux(MX51_PIN_NANDF_CS5,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); + mxc_config_iomux(MX51_PIN_NANDF_CS6,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); +#endif + +#if !defined(CONFIG_SPI_MXC_SELECT2) || (!defined(CONFIG_PATA_FSL) && !defined(CONFIG_PATA_FSL_MODULE)) + mxc_config_iomux(MX51_PIN_NANDF_RB1,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); + mxc_config_iomux(MX51_PIN_NANDF_RB2,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION); +#endif + mxc_config_iomux(MX51_PIN_DISPB2_SER_DIO,IOMUX_CONFIG_ALT4 | IOMUX_CONFIG_SION); + mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_6_SELECT_INPUT,INPUT_CTL_PATH1); +#endif - for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_mmc2_pins); i++) { - mxc_request_iomux(ccwmx51_iomux_mmc2_pins[i].pin, - ccwmx51_iomux_mmc2_pins[i].mux_mode); - if (ccwmx51_iomux_mmc2_pins[i].pad_cfg) - mxc_iomux_set_pad(ccwmx51_iomux_mmc2_pins[i].pin, - ccwmx51_iomux_mmc2_pins[i].pad_cfg); - if (ccwmx51_iomux_mmc2_pins[i].in_select) - mxc_iomux_set_input(ccwmx51_iomux_mmc2_pins[i].in_select, - ccwmx51_iomux_mmc2_pins[i].in_mode); - } } -void ccwmx51_mmc2_gpio_inactive(void) +#ifdef CONFIG_CCWMX51_SECOND_TOUCH +void ccwmx51_2nd_touch_gpio_init(void) { + /* Second touch interface interrupt line */ + mxc_request_iomux(SECOND_TS_IRQ_PIN, IOMUX_CONFIG_GPIO); + mxc_iomux_set_pad(SECOND_TS_IRQ_PIN, PAD_CTL_SRE_FAST | PAD_CTL_HYS_ENABLE); + mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_3_SELECT_INPUT, INPUT_CTL_PATH1); + + /* SECOND_TS_SPI_SS_PIN depends on configuration, check board-ccwmx51 to see options */ + mxc_request_iomux(SECOND_TS_SPI_SS_PIN, IOMUX_CONFIG_GPIO); + mxc_iomux_set_pad(SECOND_TS_SPI_SS_PIN, PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | + PAD_CTL_47K_PU | PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE); + + /* Configure the Slave Select signal as gpio, to workaround a silicon errata */ + gpio_request(IOMUX_TO_GPIO(SECOND_TS_SPI_SS_PIN), "ts2_spi_ss"); + gpio_direction_output(IOMUX_TO_GPIO(SECOND_TS_SPI_SS_PIN), 1); + gpio_set_value(IOMUX_TO_GPIO(SECOND_TS_SPI_SS_PIN), 1); + + /* Configure 2nd touch interrupt line */ + gpio_request(IOMUX_TO_GPIO(SECOND_TS_IRQ_PIN), "ts2_irq"); + gpio_direction_input(IOMUX_TO_GPIO(SECOND_TS_IRQ_PIN)); + + /** + * Configure gpio line to detect which touch is connected to each + * display interface + */ + mxc_config_iomux(MX51_PIN_DI1_D1_CS, IOMUX_CONFIG_GPIO); + mxc_iomux_set_pad(MX51_PIN_DI1_D1_CS, PAD_CTL_SRE_FAST | PAD_CTL_HYS_ENABLE); + mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_4_SELECT_INPUT, INPUT_CTL_PATH1); } +#else +void ccwmx51_2nd_touch_gpio_init(void) {} #endif #if defined(CONFIG_SERIAL_MXC) || defined(CONFIG_SERIAL_MXC_MODULE) @@ -808,8 +1276,24 @@ void gpio_uart_active(int port, int no_irda) mxc_iomux_set_pad(MX51_PIN_UART1_TXD, SERIAL_PORT_PAD); mxc_iomux_set_input(MUX_IN_UART1_IPP_UART_RXD_MUX_SELECT_INPUT, INPUT_CTL_PATH0); - /* TODO enable CTS/RTS if selected */ -#endif +#if defined(CONFIG_UART1_CTS_RTS_ENABLED) || defined(CONFIG_UART1_FULL_UART_ENABLED) + mxc_request_iomux(MX51_PIN_UART1_CTS, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX51_PIN_UART1_RTS, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX51_PIN_UART1_CTS, SERIAL_PORT_PAD); + mxc_iomux_set_pad(MX51_PIN_UART1_RTS, SERIAL_PORT_PAD); + mxc_iomux_set_input(MUX_IN_UART1_IPP_UART_RTS_B_SELECT_INPUT, INPUT_CTL_PATH0); +#endif /* CONFIG_UART1_CTS_RTS_ENABLED */ +#ifdef CONFIG_UART1_FULL_UART_ENABLED + mxc_request_iomux(MX51_PIN_KEY_COL5, IOMUX_CONFIG_ALT1); /* DCD */ + mxc_request_iomux(MX51_PIN_KEY_COL4, IOMUX_CONFIG_ALT1); /* RI */ + mxc_request_iomux(MX51_PIN_UART3_TXD, IOMUX_CONFIG_ALT0); /* DSR */ + mxc_request_iomux(MX51_PIN_UART3_RXD, IOMUX_CONFIG_ALT0); /* DTR */ + mxc_iomux_set_pad(MX51_PIN_KEY_COL5, SERIAL_PORT_PAD); + mxc_iomux_set_pad(MX51_PIN_KEY_COL4, SERIAL_PORT_PAD); + mxc_iomux_set_pad(MX51_PIN_UART3_TXD, SERIAL_PORT_PAD); + mxc_iomux_set_pad(MX51_PIN_UART3_RXD, SERIAL_PORT_PAD); +#endif /* CONFIG_UART1_FULL_UART_ENABLED */ +#endif /* CONFIG_UART1_ENABLED */ break; case 1: /* UART 2 IOMUX Configs */ @@ -820,8 +1304,16 @@ void gpio_uart_active(int port, int no_irda) mxc_iomux_set_pad(MX51_PIN_UART2_TXD, SERIAL_PORT_PAD); mxc_iomux_set_input(MUX_IN_UART2_IPP_UART_RXD_MUX_SELECT_INPUT, INPUT_CTL_PATH2); - /* TODO enable CTS/RTS if selected */ -#endif +#ifdef CONFIG_UART2_CTS_RTS_ENABLED +#if !defined(CONFIG_USB_EHCI_ARC_H1) && !defined(CONFIG_USB_EHCI_ARC_H1_MODULE) + mxc_request_iomux(MX51_PIN_USBH1_DATA0, IOMUX_CONFIG_ALT1); /* CTS */ + mxc_request_iomux(MX51_PIN_USBH1_DATA3, IOMUX_CONFIG_ALT1); /* RTS */ + mxc_iomux_set_pad(MX51_PIN_USBH1_DATA0, SERIAL_PORT_PAD); + mxc_iomux_set_pad(MX51_PIN_USBH1_DATA3, SERIAL_PORT_PAD); + mxc_iomux_set_input(MUX_IN_UART2_IPP_UART_RTS_B_SELECT_INPUT, INPUT_CTL_PATH5); +#endif /* CONFIG_USB_EHCI_ARC_H1 && CONFIG_USB_EHCI_ARC_H1_MODULE */ +#endif /* CONFIG_UART2_CTS_RTS_ENABLED */ +#endif /* CONFIG_UART2_CTS_RTS_ENABLED */ break; case 2: /* UART 3 IOMUX Configs */ #ifdef CONFIG_UART3_ENABLED @@ -831,15 +1323,19 @@ void gpio_uart_active(int port, int no_irda) mxc_iomux_set_pad(MX51_PIN_UART3_TXD, SERIAL_PORT_PAD); mxc_iomux_set_input(MUX_IN_UART3_IPP_UART_RXD_MUX_SELECT_INPUT, INPUT_CTL_PATH4); - /* TODO enable CTS/RTS if selected */ -#endif +#ifdef CONFIG_UART3_CTS_RTS_ENABLED + mxc_request_iomux(MX51_PIN_KEY_COL5, IOMUX_CONFIG_ALT2); /* CTS */ + mxc_request_iomux(MX51_PIN_KEY_COL4, IOMUX_CONFIG_ALT2); /* RTS */ + mxc_iomux_set_pad(MX51_PIN_KEY_COL5, SERIAL_PORT_PAD); + mxc_iomux_set_pad(MX51_PIN_KEY_COL4, SERIAL_PORT_PAD); + mxc_iomux_set_input(MUX_IN_UART3_IPP_UART_RTS_B_SELECT_INPUT, INPUT_CTL_PATH4); +#endif /* CONFIG_UART3_CTS_RTS_ENABLED */ +#endif /* CONFIG_UART3_ENABLED */ break; default: break; } - } - #else void gpio_uart_active(int port, int no_irda) {} #endif @@ -847,5 +1343,74 @@ void gpio_uart_inactive(int port, int no_irda) {} EXPORT_SYMBOL(gpio_uart_active); EXPORT_SYMBOL(gpio_uart_inactive); +void gpio_video_active(int vif, u32 pad) +{ + int i; + +#if defined(CONFIG_CCWMX51_DISP0) + if (vif == 0) { + for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_video1_pins); i++) { + mxc_request_iomux(ccwmx51_iomux_video1_pins[i].pin, + ccwmx51_iomux_video1_pins[i].mux_mode); + + if (ccwmx51_iomux_video1_pins[i].in_select) + mxc_iomux_set_input(ccwmx51_iomux_video1_pins[i].in_select, + ccwmx51_iomux_video1_pins[i].in_mode); + if (!pad) + mxc_iomux_set_pad(ccwmx51_iomux_video1_pins[i].pin, + ccwmx51_iomux_video1_pins[i].pad_cfg); + else + mxc_iomux_set_pad(ccwmx51_iomux_video1_pins[i].pin, + pad); + } + + /* LCD1 Power Enable, as gpio */ + mxc_request_iomux(MX51_PIN_DI1_PIN11, IOMUX_CONFIG_GPIO); + mxc_iomux_set_pad(MX51_PIN_DI1_PIN11, + PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_47K_PU | + PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE); + gpio_request(IOMUX_TO_GPIO(MX51_PIN_DI1_PIN11), "gpio3_0"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DI1_PIN11), 0); + } +#endif +#if defined(CONFIG_CCWMX51_DISP1) + if (vif == 1) { + for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_video2_pins); i++) { + mxc_request_iomux(ccwmx51_iomux_video2_pins[i].pin, + ccwmx51_iomux_video2_pins[i].mux_mode); + + if (ccwmx51_iomux_video2_pins[i].in_select) + mxc_iomux_set_input(ccwmx51_iomux_video2_pins[i].in_select, + ccwmx51_iomux_video2_pins[i].in_mode); + if (!pad) + mxc_iomux_set_pad(ccwmx51_iomux_video2_pins[i].pin, + ccwmx51_iomux_video2_pins[i].pad_cfg); + else + mxc_iomux_set_pad(ccwmx51_iomux_video2_pins[i].pin, + pad); + } + + /* LCD2 Power Enable, as gpio */ +#ifdef CONFIG_JSCCWMX51_V1 + mxc_request_iomux(MX51_PIN_DI2_PIN4, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX51_PIN_DI2_PIN4, pad); +#else + mxc_request_iomux(MX51_PIN_DI1_PIN12, IOMUX_CONFIG_GPIO); + mxc_iomux_set_pad(MX51_PIN_DI1_PIN12, + PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_47K_PU | + PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE); + + gpio_request(IOMUX_TO_GPIO(MX51_PIN_DI1_PIN12), "gpio3_1"); + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DI1_PIN12), 0); +#endif + } +#endif /* defined(CONFIG_CCWMX51_DISP1) */ +} + +void gpio_video_inactive(int vif, u32 pad) +{ +} +EXPORT_SYMBOL(gpio_video_active); +EXPORT_SYMBOL(gpio_video_inactive); diff --git a/arch/arm/mach-mx5/mx53_evk.c b/arch/arm/mach-mx5/mx53_evk.c index 104e5f93d6e9..702d7d8912d0 100644 --- a/arch/arm/mach-mx5/mx53_evk.c +++ b/arch/arm/mach-mx5/mx53_evk.c @@ -36,13 +36,14 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> -#include <linux/spi/flash.h> #include <linux/regulator/consumer.h> #include <linux/pmic_external.h> #include <linux/pmic_status.h> #include <linux/ipu.h> #include <linux/mxcfb.h> #include <linux/pwm_backlight.h> +#include <linux/fec.h> +#include <linux/ahci_platform.h> #include <mach/common.h> #include <mach/hardware.h> #include <asm/irq.h> @@ -51,16 +52,52 @@ #include <asm/mach/arch.h> #include <asm/mach/time.h> #include <asm/mach/keypad.h> +#include <asm/mach/flash.h> #include <mach/memory.h> #include <mach/gpio.h> #include <mach/mmc.h> #include <mach/mxc_dvfs.h> -#include "board-mx53_evk.h" -#include "iomux.h" -#include "mx53_pins.h" +#include <mach/iomux-mx53.h> + #include "crm_regs.h" #include "devices.h" #include "usb.h" +#include <linux/android_pmem.h> +#include <linux/usb/android.h> + +#define ARM2_SD1_CD (0*32 + 1) /* GPIO_1_1 */ + +#define MX53_HP_DETECT (1*32 + 5) /* GPIO_2_5 */ + +#define EVK_SD3_CD (2*32 + 11) /* GPIO_3_11 */ +#define EVK_SD3_WP (2*32 + 12) /* GPIO_3_12 */ +#define EVK_SD1_CD (2*32 + 13) /* GPIO_3_13 */ +#define EVK_SD1_WP (2*32 + 14) /* GPIO_3_14 */ +#define ARM2_OTG_VBUS (2*32 + 22) /* GPIO_3_22 */ +#define MX53_DVI_PD (2*32 + 24) /* GPIO_3_24 */ +#define EVK_TS_INT (2*32 + 26) /* GPIO_3_26 */ +#define MX53_DVI_I2C (2*32 + 28) /* GPIO_3_28 */ +#define MX53_DVI_DETECT (2*32 + 31) /* GPIO_3_31 */ + +#define MX53_CAM_RESET (3*32 + 0) /* GPIO_4_0 */ +#define MX53_ESAI_RESET (3*32 + 2) /* GPIO_4_2 */ +#define MX53_CAN2_EN2 (3*32 + 4) /* GPIO_4_4 */ +#define MX53_12V_EN (3*32 + 5) /* GPIO_4_5 */ +#define ARM2_LCD_CONTRAST (3*32 + 20) /* GPIO_4_20 */ + +#define MX53_DVI_RESET (4*32 + 0) /* GPIO_5_0 */ +#define EVK_USB_HUB_RESET (4*32 + 20) /* GPIO_5_20 */ +#define MX53_TVIN_PWR (4*32 + 23) /* GPIO_5_23 */ +#define MX53_CAN2_EN1 (4*32 + 24) /* GPIO_5_24 */ +#define MX53_TVIN_RESET (4*32 + 25) /* GPIO_5_25 */ + +#define EVK_OTG_VBUS (5*32 + 6) /* GPIO_6_6 */ + +#define EVK_FEC_PHY_RESET (6*32 + 6) /* GPIO_7_6 */ +#define EVK_USBH1_VBUS (6*32 + 8) /* GPIO_7_8 */ +#define MX53_PMIC_INT (6*32 + 11) /* GPIO_7_11 */ +#define MX53_CAN1_EN1 (6*32 + 12) /* GPIO_7_12 */ +#define MX53_CAN1_EN2 (6*32 + 13) /* GPIO_7_13 */ /*! * @file mach-mx53/mx53_evk.c @@ -69,11 +106,298 @@ * * @ingroup MSL_MX53 */ -extern void __init mx53_evk_io_init(void); +extern int __init mx53_evk_init_mc13892(void); extern struct cpu_wp *(*get_cpu_wp)(int *wp); extern void (*set_num_cpu_wp)(int num); static int num_cpu_wp = 3; +static struct pad_desc mx53common_pads[] = { + MX53_PAD_EIM_WAIT__GPIO_5_0, + + MX53_PAD_EIM_OE__DI1_PIN7, + MX53_PAD_EIM_RW__DI1_PIN8, + + MX53_PAD_EIM_A25__DI0_D1_CS, + + MX53_PAD_EIM_D16__CSPI1_SCLK, + MX53_PAD_EIM_D17__CSPI1_MISO, + MX53_PAD_EIM_D18__CSPI1_MOSI, + + MX53_PAD_EIM_D20__SER_DISP0_CS, + + MX53_PAD_EIM_D23__DI0_D0_CS, + + MX53_PAD_EIM_D24__GPIO_3_24, + MX53_PAD_EIM_D26__GPIO_3_26, + + MX53_PAD_EIM_D29__DISPB0_SER_RS, + + MX53_PAD_EIM_D30__DI0_PIN11, + MX53_PAD_EIM_D31__DI0_PIN12, + + MX53_PAD_ATA_DA_1__GPIO_7_7, + MX53_PAD_ATA_DATA4__GPIO_2_4, + MX53_PAD_ATA_DATA5__GPIO_2_5, + MX53_PAD_ATA_DATA6__GPIO_2_6, + + MX53_PAD_SD2_CLK__SD2_CLK, + MX53_PAD_SD2_CMD__SD2_CMD, + MX53_PAD_SD2_DATA0__SD2_DAT0, + MX53_PAD_SD2_DATA1__SD2_DAT1, + MX53_PAD_SD2_DATA2__SD2_DAT2, + MX53_PAD_SD2_DATA3__SD2_DAT3, + MX53_PAD_ATA_DATA12__SD2_DAT4, + MX53_PAD_ATA_DATA13__SD2_DAT5, + MX53_PAD_ATA_DATA14__SD2_DAT6, + MX53_PAD_ATA_DATA15__SD2_DAT7, + + MX53_PAD_CSI0_D10__UART1_TXD, + MX53_PAD_CSI0_D11__UART1_RXD, + + MX53_PAD_ATA_BUFFER_EN__UART2_RXD, + MX53_PAD_ATA_DMARQ__UART2_TXD, + MX53_PAD_ATA_DIOR__UART2_RTS, + MX53_PAD_ATA_INTRQ__UART2_CTS, + + MX53_PAD_ATA_CS_0__UART3_TXD, + MX53_PAD_ATA_CS_1__UART3_RXD, + + MX53_PAD_KEY_COL0__AUD5_TXC, + MX53_PAD_KEY_ROW0__AUD5_TXD, + MX53_PAD_KEY_COL1__AUD5_TXFS, + MX53_PAD_KEY_ROW1__AUD5_RXD, + + MX53_PAD_CSI0_D7__GPIO_5_25, + + MX53_PAD_GPIO_2__MLBDAT, + MX53_PAD_GPIO_3__MLBCLK, + + MX53_PAD_GPIO_6__MLBSIG, + + MX53_PAD_GPIO_4__GPIO_1_4, + MX53_PAD_GPIO_7__GPIO_1_7, + MX53_PAD_GPIO_8__GPIO_1_8, + + MX53_PAD_GPIO_10__GPIO_4_0, + + MX53_PAD_KEY_COL2__TXCAN1, + MX53_PAD_KEY_ROW2__RXCAN1, + + /* CAN1 -- EN */ + MX53_PAD_GPIO_18__GPIO_7_13, + /* CAN1 -- STBY */ + MX53_PAD_GPIO_17__GPIO_7_12, + /* CAN1 -- NERR */ + MX53_PAD_GPIO_5__GPIO_1_5, + + MX53_PAD_KEY_COL4__TXCAN2, + MX53_PAD_KEY_ROW4__RXCAN2, + + /* CAN2 -- EN */ + MX53_PAD_CSI0_D6__GPIO_5_24, + /* CAN2 -- STBY */ + MX53_PAD_GPIO_14__GPIO_4_4, + /* CAN2 -- NERR */ + MX53_PAD_CSI0_D4__GPIO_5_22, + + MX53_PAD_GPIO_11__GPIO_4_1, + MX53_PAD_GPIO_12__GPIO_4_2, + MX53_PAD_GPIO_13__GPIO_4_3, + MX53_PAD_GPIO_16__GPIO_7_11, + MX53_PAD_GPIO_19__GPIO_4_5, + + /* DI0 display clock */ + MX53_PAD_DI0_DISP_CLK__DI0_DISP_CLK, + + /* DI0 data enable */ + MX53_PAD_DI0_PIN15__DI0_PIN15, + /* DI0 HSYNC */ + MX53_PAD_DI0_PIN2__DI0_PIN2, + /* DI0 VSYNC */ + MX53_PAD_DI0_PIN3__DI0_PIN3, + + MX53_PAD_DISP0_DAT0__DISP0_DAT0, + MX53_PAD_DISP0_DAT1__DISP0_DAT1, + MX53_PAD_DISP0_DAT2__DISP0_DAT2, + MX53_PAD_DISP0_DAT3__DISP0_DAT3, + MX53_PAD_DISP0_DAT4__DISP0_DAT4, + MX53_PAD_DISP0_DAT5__DISP0_DAT5, + MX53_PAD_DISP0_DAT6__DISP0_DAT6, + MX53_PAD_DISP0_DAT7__DISP0_DAT7, + MX53_PAD_DISP0_DAT8__DISP0_DAT8, + MX53_PAD_DISP0_DAT9__DISP0_DAT9, + MX53_PAD_DISP0_DAT10__DISP0_DAT10, + MX53_PAD_DISP0_DAT11__DISP0_DAT11, + MX53_PAD_DISP0_DAT12__DISP0_DAT12, + MX53_PAD_DISP0_DAT13__DISP0_DAT13, + MX53_PAD_DISP0_DAT14__DISP0_DAT14, + MX53_PAD_DISP0_DAT15__DISP0_DAT15, + MX53_PAD_DISP0_DAT16__DISP0_DAT16, + MX53_PAD_DISP0_DAT17__DISP0_DAT17, + MX53_PAD_DISP0_DAT18__DISP0_DAT18, + MX53_PAD_DISP0_DAT19__DISP0_DAT19, + MX53_PAD_DISP0_DAT20__DISP0_DAT20, + MX53_PAD_DISP0_DAT21__DISP0_DAT21, + MX53_PAD_DISP0_DAT22__DISP0_DAT22, + MX53_PAD_DISP0_DAT23__DISP0_DAT23, + + MX53_PAD_LVDS0_TX3_P__LVDS0_TX3, + MX53_PAD_LVDS0_CLK_P__LVDS0_CLK, + MX53_PAD_LVDS0_TX2_P__LVDS0_TX2, + MX53_PAD_LVDS0_TX1_P__LVDS0_TX1, + MX53_PAD_LVDS0_TX0_P__LVDS0_TX0, + + MX53_PAD_LVDS1_TX3_P__LVDS1_TX3, + MX53_PAD_LVDS1_CLK_P__LVDS1_CLK, + MX53_PAD_LVDS1_TX2_P__LVDS1_TX2, + MX53_PAD_LVDS1_TX1_P__LVDS1_TX1, + MX53_PAD_LVDS1_TX0_P__LVDS1_TX0, + + /* audio and CSI clock out */ + MX53_PAD_GPIO_0__SSI_EXT1_CLK, + + MX53_PAD_CSI0_D12__CSI0_D12, + MX53_PAD_CSI0_D13__CSI0_D13, + MX53_PAD_CSI0_D14__CSI0_D14, + MX53_PAD_CSI0_D15__CSI0_D15, + MX53_PAD_CSI0_D16__CSI0_D16, + MX53_PAD_CSI0_D17__CSI0_D17, + MX53_PAD_CSI0_D18__CSI0_D18, + MX53_PAD_CSI0_D19__CSI0_D19, + + MX53_PAD_CSI0_VSYNC__CSI0_VSYNC, + MX53_PAD_CSI0_MCLK__CSI0_HSYNC, + MX53_PAD_CSI0_PIXCLK__CSI0_PIXCLK, + /* Camera low power */ + MX53_PAD_CSI0_D5__GPIO_5_23, + + /* esdhc1 */ + MX53_PAD_SD1_CMD__SD1_CMD, + MX53_PAD_SD1_CLK__SD1_CLK, + MX53_PAD_SD1_DATA0__SD1_DATA0, + MX53_PAD_SD1_DATA1__SD1_DATA1, + MX53_PAD_SD1_DATA2__SD1_DATA2, + MX53_PAD_SD1_DATA3__SD1_DATA3, + + /* esdhc3 */ + MX53_PAD_ATA_DATA8__SD3_DAT0, + MX53_PAD_ATA_DATA9__SD3_DAT1, + MX53_PAD_ATA_DATA10__SD3_DAT2, + MX53_PAD_ATA_DATA11__SD3_DAT3, + MX53_PAD_ATA_DATA0__SD3_DAT4, + MX53_PAD_ATA_DATA1__SD3_DAT5, + MX53_PAD_ATA_DATA2__SD3_DAT6, + MX53_PAD_ATA_DATA3__SD3_DAT7, + MX53_PAD_ATA_RESET_B__SD3_CMD, + MX53_PAD_ATA_IORDY__SD3_CLK, + + /* FEC pins */ + MX53_PAD_FEC_MDIO__FEC_MDIO, + MX53_PAD_FEC_REF_CLK__FEC_REF_CLK, + MX53_PAD_FEC_RX_ER__FEC_RX_ER, + MX53_PAD_FEC_CRS_DV__FEC_CRS_DV, + MX53_PAD_FEC_RXD1__FEC_RXD1, + MX53_PAD_FEC_RXD0__FEC_RXD0, + MX53_PAD_FEC_TX_EN__FEC_TX_EN, + MX53_PAD_FEC_TXD1__FEC_TXD1, + MX53_PAD_FEC_TXD0__FEC_TXD0, + MX53_PAD_FEC_MDC__FEC_MDC, + + MX53_PAD_CSI0_D8__I2C1_SDA, + MX53_PAD_CSI0_D9__I2C1_SCL, + + MX53_PAD_KEY_COL3__I2C2_SCL, + MX53_PAD_KEY_ROW3__I2C2_SDA, +}; + +static struct pad_desc mx53evk_pads[] = { + /* USB OTG USB_OC */ + MX53_PAD_EIM_A24__GPIO_5_4, + + /* USB OTG USB_PWR */ + MX53_PAD_EIM_A23__GPIO_6_6, + + /* DISPB0_SER_CLK */ + MX53_PAD_EIM_D21__DISPB0_SER_CLK, + + /* DI0_PIN1 */ + MX53_PAD_EIM_D22__DISPB0_SER_DIN, + + /* DVI I2C ENABLE */ + MX53_PAD_EIM_D28__GPIO_3_28, + + /* DVI DET */ + MX53_PAD_EIM_D31__GPIO_3_31, + + /* SDHC1 SD_CD */ + MX53_PAD_EIM_DA13__GPIO_3_13, + + /* SDHC1 SD_WP */ + MX53_PAD_EIM_DA14__GPIO_3_14, + + /* SDHC3 SD_CD */ + MX53_PAD_EIM_DA11__GPIO_3_11, + + /* SDHC3 SD_WP */ + MX53_PAD_EIM_DA12__GPIO_3_12, + + /* PWM backlight */ + MX53_PAD_GPIO_1__PWMO, + + /* USB HOST USB_PWR */ + MX53_PAD_ATA_DA_2__GPIO_7_8, + + /* USB HOST USB_RST */ + MX53_PAD_CSI0_DATA_EN__GPIO_5_20, + + /* USB HOST CARD_ON */ + MX53_PAD_EIM_DA15__GPIO_3_15, + + /* USB HOST CARD_RST */ + MX53_PAD_ATA_DATA7__GPIO_2_7, + + /* USB HOST WAN_WAKE */ + MX53_PAD_EIM_D25__GPIO_3_25, + + /* FEC_RST */ + MX53_PAD_ATA_DA_0__GPIO_7_6, +}; + +static struct pad_desc mx53arm2_pads[] = { + /* USB OTG USB_OC */ + MX53_PAD_EIM_D21__GPIO_3_21, + + /* USB OTG USB_PWR */ + MX53_PAD_EIM_D22__GPIO_3_22, + + /* SDHC1 SD_CD */ + MX53_PAD_GPIO_1__GPIO_1_1, + + /* gpio backlight */ + MX53_PAD_DI0_PIN4__GPIO_4_20, +}; + +static struct pad_desc mx53_nand_pads[] = { + MX53_PAD_NANDF_CLE__NANDF_CLE, + MX53_PAD_NANDF_ALE__NANDF_ALE, + MX53_PAD_NANDF_WP_B__NANDF_WP_B, + MX53_PAD_NANDF_WE_B__NANDF_WE_B, + MX53_PAD_NANDF_RE_B__NANDF_RE_B, + MX53_PAD_NANDF_RB0__NANDF_RB0, + MX53_PAD_NANDF_CS0__NANDF_CS0, + MX53_PAD_NANDF_CS1__NANDF_CS1 , + MX53_PAD_NANDF_CS2__NANDF_CS2, + MX53_PAD_NANDF_CS3__NANDF_CS3 , + MX53_PAD_EIM_DA0__EIM_DA0, + MX53_PAD_EIM_DA1__EIM_DA1, + MX53_PAD_EIM_DA2__EIM_DA2, + MX53_PAD_EIM_DA3__EIM_DA3, + MX53_PAD_EIM_DA4__EIM_DA4, + MX53_PAD_EIM_DA5__EIM_DA5, + MX53_PAD_EIM_DA6__EIM_DA6, + MX53_PAD_EIM_DA7__EIM_DA7, +}; + /* working point(wp): 0 - 800MHz; 1 - 166.25MHz; */ static struct cpu_wp cpu_wp_auto[] = { { @@ -84,7 +408,7 @@ static struct cpu_wp cpu_wp_auto[] = { .mfd = 11, .mfn = 5, .cpu_podf = 0, - .cpu_voltage = 1175000,}, + .cpu_voltage = 1150000,}, { .pll_rate = 800000000, .cpu_rate = 800000000, @@ -93,10 +417,10 @@ static struct cpu_wp cpu_wp_auto[] = { .mfd = 2, .mfn = 1, .cpu_podf = 0, - .cpu_voltage = 1100000,}, + .cpu_voltage = 1050000,}, { .pll_rate = 800000000, - .cpu_rate = 166250000, + .cpu_rate = 160000000, .pdf = 4, .mfi = 8, .mfd = 2, @@ -107,7 +431,24 @@ static struct cpu_wp cpu_wp_auto[] = { static struct fb_videomode video_modes[] = { { - /* 720p60 TV output */ + /* NTSC TV output */ + "TV-NTSC", 60, 720, 480, 74074, + 122, 15, + 18, 26, + 1, 1, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | FB_SYNC_EXT, + FB_VMODE_INTERLACED, + 0,}, + { + /* PAL TV output */ + "TV-PAL", 50, 720, 576, 74074, + 132, 11, + 22, 26, + 1, 1, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | FB_SYNC_EXT, + FB_VMODE_INTERLACED | FB_VMODE_ODD_FLD_FIRST, + 0,}, + { "720P60", 60, 1280, 720, 13468, 260, 109, 25, 4, @@ -117,12 +458,35 @@ static struct fb_videomode video_modes[] = { FB_VMODE_NONINTERLACED, 0,}, { - /* MITSUBISHI LVDS panel */ + /* 800x480 @ 57 Hz , pixel clk @ 27MHz */ + "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, + { + /* 1600x1200 @ 60 Hz 162M pixel clk*/ + "UXGA", 60, 1600, 1200, 6172, + 304, 64, + 1, 46, + 192, 3, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT | + FB_SYNC_EXT, + FB_VMODE_NONINTERLACED, + 0,}, + { + "1080P60", 60, 1920, 1080, 7692, + 100, 40, + 30, 3, + 10, 2, + FB_SYNC_EXT, + FB_VMODE_NONINTERLACED, + 0,}, + { "XGA", 60, 1024, 768, 15385, 220, 40, 21, 7, 60, 10, - 0, + FB_SYNC_EXT, FB_VMODE_NONINTERLACED, 0,}, }; @@ -147,9 +511,76 @@ static struct platform_pwm_backlight_data mxc_pwm_backlight_data = { .pwm_id = 1, .max_brightness = 255, .dft_brightness = 128, - .pwm_period_ns = 78770, + .pwm_period_ns = 50000, }; +static void flexcan_xcvr_enable(int id, int en) +{ + static int pwdn; + if (id < 0 || id > 1) + return; + + if (en) { + if (!(pwdn++)) + gpio_set_value(MX53_12V_EN, 1); + + if (id == 0) { + gpio_set_value(MX53_CAN1_EN1, 1); + gpio_set_value(MX53_CAN1_EN2, 1); + } else { + gpio_set_value(MX53_CAN2_EN1, 1); + gpio_set_value(MX53_CAN2_EN2, 1); + } + + } else { + if (!(--pwdn)) + gpio_set_value(MX53_12V_EN, 0); + + if (id == 0) { + gpio_set_value(MX53_CAN1_EN1, 0); + gpio_set_value(MX53_CAN1_EN2, 0); + } else { + gpio_set_value(MX53_CAN2_EN1, 0); + gpio_set_value(MX53_CAN2_EN2, 0); + } + } +} + +static struct flexcan_platform_data flexcan0_data = { + .core_reg = NULL, + .io_reg = NULL, + .xcvr_enable = flexcan_xcvr_enable, + .br_clksrc = 1, + .br_rjw = 2, + .br_presdiv = 5, + .br_propseg = 5, + .br_pseg1 = 4, + .br_pseg2 = 7, + .bcc = 1, + .srx_dis = 1, + .smp = 1, + .boff_rec = 1, + .ext_msg = 1, + .std_msg = 1, +}; +static struct flexcan_platform_data flexcan1_data = { + .core_reg = NULL, + .io_reg = NULL, + .xcvr_enable = flexcan_xcvr_enable, + .br_clksrc = 1, + .br_rjw = 2, + .br_presdiv = 5, + .br_propseg = 5, + .br_pseg1 = 4, + .br_pseg2 = 7, + .bcc = 1, + .srx_dis = 1, + .boff_rec = 1, + .ext_msg = 1, + .std_msg = 1, +}; + + extern void mx5_ipu_reset(void); static struct mxc_ipu_config mxc_ipu_data = { .rev = 3, @@ -161,10 +592,74 @@ static struct mxc_vpu_platform_data mxc_vpu_data = { .reset = mx5_vpu_reset, }; -extern void mx53_evk_gpio_spi_chipselect_active(int cspi_mode, int status, - int chipselect); -extern void mx53_evk_gpio_spi_chipselect_inactive(int cspi_mode, int status, - int chipselect); +static struct fec_platform_data fec_data = { + .phy = PHY_INTERFACE_MODE_RMII, + .phy_mask = ~1UL, +}; + +/* workaround for ecspi chipselect pin may not keep correct level when idle */ +static void mx53_evk_gpio_spi_chipselect_active(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + switch (chipselect) { + case 0x1: + { + struct pad_desc eim_d19_gpio = MX53_PAD_EIM_D19__GPIO_3_19; + struct pad_desc cspi_ss0 = MX53_PAD_EIM_EB2__CSPI_SS0; + + /* de-select SS1 of instance: ecspi1. */ + mxc_iomux_v3_setup_pad(&eim_d19_gpio); + mxc_iomux_v3_setup_pad(&cspi_ss0); + } + break; + case 0x2: + { + struct pad_desc eim_eb2_gpio = MX53_PAD_EIM_EB2__GPIO_2_30; + struct pad_desc cspi_ss1 = MX53_PAD_EIM_D19__CSPI_SS1; + + /* de-select SS0 of instance: ecspi1. */ + mxc_iomux_v3_setup_pad(&eim_eb2_gpio); + mxc_iomux_v3_setup_pad(&cspi_ss1); + } + break; + default: + break; + } + break; + case 2: + break; + case 3: + break; + default: + break; + } +} + +static void mx53_evk_gpio_spi_chipselect_inactive(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + switch (chipselect) { + case 0x1: + break; + case 0x2: + break; + default: + break; + } + break; + case 2: + break; + case 3: + break; + default: + break; + } +} + static struct mxc_spi_master mxcspi1_data = { .maxchipselect = 4, .spi_version = 23, @@ -180,10 +675,143 @@ static struct mxc_srtc_platform_data srtc_data = { .srtc_sec_mode_addr = 0x83F98840, }; +static struct mxc_dvfs_platform_data dvfs_core_data = { + .reg_id = "SW1", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 30, + .num_wp = 3, +}; + static struct tve_platform_data tve_data = { .dac_reg = "VVIDEO", }; +static struct ldb_platform_data ldb_data = { + .lvds_bg_reg = "VAUDIO", + .ext_ref = 1, +}; + +static struct pad_desc mx53esai_pads[] = { + MX53_PAD_FEC_MDIO__ESAI_SCKR, + MX53_PAD_FEC_REF_CLK__ESAI_FSR, + MX53_PAD_FEC_RX_ER__ESAI_HCKR, + MX53_PAD_FEC_CRS_DV__ESAI_SCKT, + MX53_PAD_FEC_RXD1__ESAI_FST, + MX53_PAD_FEC_RXD0__ESAI_HCKT, + MX53_PAD_FEC_TX_EN__ESAI_TX3_RX2, + MX53_PAD_FEC_TXD1__ESAI_TX2_RX3, + MX53_PAD_FEC_TXD0__ESAI_TX4_RX1, + MX53_PAD_FEC_MDC__ESAI_TX5_RX0, + MX53_PAD_NANDF_CS2__ESAI_TX0, + MX53_PAD_NANDF_CS3__ESAI_TX1, +}; + +void gpio_activate_esai_ports(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx53esai_pads, + ARRAY_SIZE(mx53esai_pads)); +} + +static struct mxc_esai_platform_data esai_data = { + .activate_esai_ports = gpio_activate_esai_ports, +}; + +void gpio_cs42888_pdwn(int pdwn) +{ + if (pdwn) + gpio_set_value(MX53_ESAI_RESET, 0); + else + gpio_set_value(MX53_ESAI_RESET, 1); +} +EXPORT_SYMBOL(gpio_cs42888_pdwn); + +static void gpio_usbotg_vbus_active(void) +{ + if (board_is_mx53_arm2()) { + /* MX53 ARM2 CPU board */ + /* Enable OTG VBus with GPIO low */ + gpio_set_value(ARM2_OTG_VBUS, 0); + } else if (board_is_mx53_evk_a()) { + /* MX53 EVK board ver A*/ + /* Enable OTG VBus with GPIO low */ + gpio_set_value(EVK_OTG_VBUS, 0); + } else if (board_is_mx53_evk_b()) { + /* MX53 EVK board ver B*/ + /* Enable OTG VBus with GPIO high */ + gpio_set_value(EVK_OTG_VBUS, 1); + } +} + +static void gpio_usbotg_vbus_inactive(void) +{ + if (board_is_mx53_arm2()) { + /* MX53 ARM2 CPU board */ + /* Disable OTG VBus with GPIO high */ + gpio_set_value(ARM2_OTG_VBUS, 1); + } else if (board_is_mx53_evk_a()) { + /* MX53 EVK board ver A*/ + /* Disable OTG VBus with GPIO high */ + gpio_set_value(EVK_OTG_VBUS, 1); + } else if (board_is_mx53_evk_b()) { + /* MX53 EVK board ver B*/ + /* Disable OTG VBus with GPIO low */ + gpio_set_value(EVK_OTG_VBUS, 0); + } +} + +static void mx53_gpio_usbotg_driver_vbus(bool on) +{ + if (on) + gpio_usbotg_vbus_active(); + else + gpio_usbotg_vbus_inactive(); +} + +static void mx53_gpio_host1_driver_vbus(bool on) +{ + if (on) + gpio_set_value(EVK_USBH1_VBUS, 1); + else + gpio_set_value(EVK_USBH1_VBUS, 0); +} + +static void adv7180_pwdn(int pwdn) +{ + gpio_request(MX53_TVIN_PWR, "tvin-pwr"); + gpio_direction_output(MX53_TVIN_PWR, 0); + if (pwdn) + gpio_set_value(MX53_TVIN_PWR, 0); + else + gpio_set_value(MX53_TVIN_PWR, 1); +} + +static struct mxc_tvin_platform_data adv7180_data = { + .dvddio_reg = NULL, + .dvdd_reg = NULL, + .avdd_reg = NULL, + .pvdd_reg = NULL, + .pwdn = adv7180_pwdn, + .reset = NULL, +}; + static struct resource mxcfb_resources[] = { [0] = { .flags = IORESOURCE_MEM, @@ -193,101 +821,43 @@ static struct resource mxcfb_resources[] = { static struct mxc_fb_platform_data fb_data[] = { { .interface_pix_fmt = IPU_PIX_FMT_RGB565, - .mode_str = "800x480M-16@55", + .mode_str = "CLAA-WVGA", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), }, { - .interface_pix_fmt = IPU_PIX_FMT_RGB24, + .interface_pix_fmt = IPU_PIX_FMT_BGR24, .mode_str = "1024x768M-16@60", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), }, }; -static int __initdata enable_vga = { 0 }; -static int __initdata enable_tv = { 0 }; -static int __initdata enable_dvi = { 0 }; - -static void wvga_reset(void) -{ -} - -static struct mxc_lcd_platform_data lcd_wvga_data = { - .reset = wvga_reset, -}; - -static struct platform_device lcd_wvga_device = { - .name = "lcd_claa", -}; - +extern int primary_di; static int __init mxc_init_fb(void) { if (!machine_is_mx53_evk()) return 0; - /* by default, fb0 is wvga, fb1 is vga or tv */ - if (enable_vga) { - printk(KERN_INFO "VGA monitor is primary\n"); - } else if (enable_tv == 2) - printk(KERN_INFO "HDTV is primary\n"); - else if (enable_dvi) - printk(KERN_INFO "DVI is primary\n"); - else - printk(KERN_INFO "WVGA LCD panel is primary\n"); - - if (enable_tv) { - printk(KERN_INFO "HDTV is specified as %d\n", enable_tv); - fb_data[1].interface_pix_fmt = IPU_PIX_FMT_YUV444; - fb_data[1].mode = &(video_modes[0]); - } - - if (enable_dvi) { - fb_data[0].mode_str = "1024x768M-16@60"; - fb_data[0].interface_pix_fmt = IPU_PIX_FMT_RGB24; - } - - /* Once a customer knows the platform configuration, - this should be simplified to what is desired. - */ - if (enable_vga || enable_tv == 2) { - /* - * DI1 -> DP-BG channel: - * - * dev di-out-fmt default-videmode - * - * 1. VGA RGB 1024x768M-16@60 - * 2. TVE YUV video_modes[0] - */ + if (primary_di) { + printk(KERN_INFO "DI1 is primary\n"); + /* DI1 -> DP-BG channel: */ mxc_fb_devices[1].num_resources = ARRAY_SIZE(mxcfb_resources); mxc_fb_devices[1].resource = mxcfb_resources; mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); - if (fb_data[0].mode_str || fb_data[0].mode) - /* - * DI0 -> DC channel: - * - * dev di-out-fmt default-videmode - * - * 1. WVGA RGB 800x480M-16@55 - */ - mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); + + /* DI0 -> DC channel: */ + mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); } else { - /* - * DI0 -> DP-BG channel: - * - * dev di-out-fmt default-videmode - * - * 1. WVGA RGB 800x480M-16@55 - */ + printk(KERN_INFO "DI0 is primary\n"); + + /* DI0 -> DP-BG channel: */ mxc_fb_devices[0].num_resources = ARRAY_SIZE(mxcfb_resources); mxc_fb_devices[0].resource = mxcfb_resources; mxc_register_device(&mxc_fb_devices[0], &fb_data[0]); - if (fb_data[1].mode_str || fb_data[1].mode) - /* - * DI1 -> DC channel: - * - * dev di-out-fmt default-videmode - * - * 1. VGA RGB 1024x768M-16@60 - * 2. TVE YUV video_modes[0] - */ - mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); + + /* DI1 -> DC channel: */ + mxc_register_device(&mxc_fb_devices[1], &fb_data[1]); } /* @@ -299,33 +869,19 @@ static int __init mxc_init_fb(void) } device_initcall(mxc_init_fb); -static int __init dvi_setup(char *s) -{ - enable_dvi = 1; - return 1; -} -__setup("dvi", dvi_setup); - -static int __init vga_setup(char *__unused) -{ - enable_vga = 1; - return 1; -} -__setup("vga", vga_setup); - -static int __init tv_setup(char *s) +static void camera_pwdn(int pwdn) { - enable_tv = 1; - if (strcmp(s, "2") == 0 || strcmp(s, "=2") == 0) - enable_tv = 2; - return 1; + gpio_request(MX53_TVIN_PWR, "tvin-pwr"); + gpio_direction_output(MX53_TVIN_PWR, 0); + gpio_set_value(MX53_TVIN_PWR, pwdn); } -__setup("hdtv", tv_setup); static struct mxc_camera_platform_data camera_data = { .analog_regulator = "VSD", + .gpo_regulator = "VVIDEO", .mclk = 24000000, .csi = 0, + .pwdn = camera_pwdn, }; static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { @@ -334,6 +890,27 @@ static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { .addr = 0x3C, .platform_data = (void *)&camera_data, }, + { + .type = "adv7180", + .addr = 0x21, + .platform_data = (void *)&adv7180_data, + }, + { + .type = "cs42888", + .addr = 0x48, + }, +}; + +static void sii9022_hdmi_reset(void) +{ + gpio_set_value(MX53_DVI_RESET, 0); + msleep(10); + gpio_set_value(MX53_DVI_RESET, 1); + msleep(10); +} + +static struct mxc_lcd_platform_data sii9022_hdmi_data = { + .reset = sii9022_hdmi_reset, }; /* TO DO add platform data */ @@ -345,7 +922,7 @@ static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { { .type = "tsc2007", .addr = 0x48, - .irq = IOMUX_TO_IRQ(MX53_PIN_EIM_A25), + .irq = IOMUX_TO_IRQ_V3(EVK_TS_INT), }, { .type = "backlight-i2c", @@ -359,6 +936,40 @@ static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { .type = "eeprom", .addr = 0x50, }, + { + .type = "sii9022", + .addr = 0x39, + .platform_data = &sii9022_hdmi_data, + }, +}; + +static struct mtd_partition mxc_dataflash_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x000100000,}, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL,}, +}; + +static struct flash_platform_data mxc_spi_flash_data[] = { + { + .name = "mxc_dataflash", + .parts = mxc_dataflash_partitions, + .nr_parts = ARRAY_SIZE(mxc_dataflash_partitions), + .type = "at45db321d",} +}; + + +static struct spi_board_info mxc_dataflash_device[] __initdata = { + { + .modalias = "mxc_dataflash", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 1, + .platform_data = &mxc_spi_flash_data[0],}, }; static int sdhc_write_protect(struct device *dev) @@ -367,9 +978,9 @@ static int sdhc_write_protect(struct device *dev) if (!board_is_mx53_arm2()) { if (to_platform_device(dev)->id == 0) - rc = gpio_get_value(IOMUX_TO_GPIO(MX53_PIN_EIM_DA14)); + rc = gpio_get_value(EVK_SD1_WP); else - rc = gpio_get_value(IOMUX_TO_GPIO(MX53_PIN_EIM_DA12)); + rc = gpio_get_value(EVK_SD3_WP); } return rc; @@ -380,14 +991,14 @@ static unsigned int sdhc_get_card_det_status(struct device *dev) int ret; if (board_is_mx53_arm2()) { if (to_platform_device(dev)->id == 0) - ret = gpio_get_value(IOMUX_TO_GPIO(MX53_PIN_GPIO_1)); + ret = gpio_get_value(ARM2_SD1_CD); else ret = 1; } else { if (to_platform_device(dev)->id == 0) { - ret = gpio_get_value(IOMUX_TO_GPIO(MX53_PIN_EIM_DA13)); + ret = gpio_get_value(EVK_SD1_CD); } else{ /* config the det pin for SDHC3 */ - ret = gpio_get_value(IOMUX_TO_GPIO(MX53_PIN_EIM_DA11)); + ret = gpio_get_value(EVK_SD3_CD); } } @@ -410,13 +1021,170 @@ static struct mxc_mmc_platform_data mmc1_data = { static struct mxc_mmc_platform_data mmc3_data = { .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | MMC_VDD_31_32, - .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA + | MMC_CAP_DATA_DDR, .min_clk = 400000, .max_clk = 50000000, .card_inserted_state = 0, .status = sdhc_get_card_det_status, .wp_status = sdhc_write_protect, .clock_mmc = "esdhc_clk", + .clk_always_on = 1, +}; + +/* return value 1 failure, 0 success */ +static int write_phy_ctl_ack_polling(u32 data, void __iomem *mmio, + int max_iterations, u32 exp_val) +{ + enum { + PORT_PHY_CTL = 0x178, /* Port0 PHY Control */ + PORT_PHY_SR = 0x17c, /* Port0 PHY Status */ + /* PORT_PHY_SR */ + PORT_PHY_STAT_DATA_LOC = 0, + PORT_PHY_STAT_ACK_LOC = 18, + }; + int i; + u32 val; + + writel(data, mmio + PORT_PHY_CTL); + + for (i = 0; i < max_iterations + 1; i++) { + val = readl(mmio + PORT_PHY_SR); + val = (val >> PORT_PHY_STAT_ACK_LOC) & 0x1; + if (val == exp_val) + return 0; + if (i == max_iterations) { + printk(KERN_ERR "Wait for CR ACK error!\n"); + return 1; + } + msleep(1); + } + return 0; +} + +/* HW Initialization, if return 1, initialization is failed. */ +static int sata_init(struct device *dev) +{ + enum { + HOST_CAP = 0x00, + HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ + HOST_PORTS_IMPL = 0x0c, + HOST_TIMER1MS = 0xe0, /* Timer 1-ms */ + /* Offest used to control the MPLL input clk */ + PHY_CR_CLOCK_FREQ_OVRD = 0x12, + + PORT_PHY_CTL = 0x178, /* Port0 PHY Control */ + /* PORT_PHY_CTL bits */ + PORT_PHY_CTL_CAP_ADR_LOC = 0x10000, + PORT_PHY_CTL_CAP_DAT_LOC = 0x20000, + PORT_PHY_CTL_WRITE_LOC = 0x40000, + }; + void __iomem *mmio; + struct clk *clk; + int rc = 0; + u32 tmpdata; + + clk = clk_get(dev, "sata_clk"); + clk_enable(clk); + + mmio = ioremap(MX53_SATA_BASE_ADDR, SZ_4K); + + tmpdata = readl(mmio + HOST_CAP); + if (!(tmpdata & HOST_CAP_SSS)) { + tmpdata |= HOST_CAP_SSS; + writel(tmpdata, mmio + HOST_CAP); + } + + if (!(readl(mmio + HOST_PORTS_IMPL) & 0x1)) + writel((readl(mmio + HOST_PORTS_IMPL) | 0x1), + mmio + HOST_PORTS_IMPL); + + /* Get the AHB clock rate, and configure the TIMER1MS reg */ + clk = clk_get(NULL, "ahb_clk"); + tmpdata = clk_get_rate(clk) / 1000; + writel(tmpdata, mmio + HOST_TIMER1MS); + + /* write addr */ + tmpdata = PHY_CR_CLOCK_FREQ_OVRD; + writel(tmpdata, mmio + PORT_PHY_CTL); + /* capture addr */ + tmpdata |= PORT_PHY_CTL_CAP_ADR_LOC; + /* Wait for ack */ + if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 1)) { + rc = 1; + goto err0; + } + + /* deassert cap data */ + tmpdata &= 0xFFFF; + /* wait for ack de-assertion */ + if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 0)) { + rc = 1; + goto err0; + } + + /* write data */ + /* Configure the PHY CLK input refer to different OSC + * For 25MHz, pre[13,14]:01, ncy[12,8]:06, + * ncy5[7,6]:02, int_ctl[5,3]:0, prop_ctl[2,0]:7. + * For 50MHz, pre:00, ncy:06, ncy5:02, int_ctl:0, prop_ctl:7. + */ + /* EVK revA */ + if (board_is_mx53_evk_a()) + tmpdata = (0x1 << 15) | (0x1 << 13) | (0x6 << 8) + | (0x2 << 6) | 0x7; + /* EVK revB */ + else if (board_is_mx53_evk_b()) + tmpdata = (0x1 << 15) | (0x0 << 13) | (0x6 << 8) + | (0x2 << 6) | 0x7; + + writel(tmpdata, mmio + PORT_PHY_CTL); + /* capture data */ + tmpdata |= PORT_PHY_CTL_CAP_DAT_LOC; + /* wait for ack */ + if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 1)) { + rc = 1; + goto err0; + } + + /* deassert cap data */ + tmpdata &= 0xFFFF; + /* wait for ack de-assertion */ + if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 0)) { + rc = 1; + goto err0; + } + + /* assert wr signal and wait for ack */ + if (write_phy_ctl_ack_polling(PORT_PHY_CTL_WRITE_LOC, mmio, 100, 1)) { + rc = 1; + goto err0; + } + /* deassert rd _signal and wait for ack de-assertion */ + if (write_phy_ctl_ack_polling(0, mmio, 100, 0)) { + rc = 1; + goto err0; + } + + msleep(10); + +err0: + iounmap(mmio); + return rc; +} + +static void sata_exit(struct device *dev) +{ + struct clk *clk; + + clk = clk_get(dev, "sata_clk"); + clk_disable(clk); + clk_put(clk); +} + +static struct ahci_platform_data sata_data = { + .init = sata_init, + .exit = sata_exit, }; static int mxc_sgtl5000_amp_enable(int enable) @@ -427,7 +1195,7 @@ return 0; static int headphone_det_status(void) { - return (gpio_get_value(IOMUX_TO_GPIO(MX53_PIN_ATA_DATA5)) == 0); + return (gpio_get_value(MX53_HP_DETECT) == 0); } static int mxc_sgtl5000_init(void); @@ -436,7 +1204,7 @@ static struct mxc_audio_platform_data sgtl5000_data = { .ssi_num = 1, .src_port = 2, .ext_port = 5, - .hp_irq = IOMUX_TO_IRQ(MX53_PIN_ATA_DATA5), + .hp_irq = IOMUX_TO_IRQ(MX53_HP_DETECT), .hp_status = headphone_det_status, .amp_enable = mxc_sgtl5000_amp_enable, .init = mxc_sgtl5000_init, @@ -474,6 +1242,139 @@ static struct platform_device mxc_sgtl5000_device = { .name = "imx-3stack-sgtl5000", }; +static struct mxc_mlb_platform_data mlb_data = { + .reg_nvcc = "VCAM", + .mlb_clk = "mlb_clk", +}; + +/* NAND Flash Partitions */ +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition nand_flash_partitions[] = { + { + .name = "BOOT", + .offset = 0, + .size = 7 * 1024 * 1024}, + { + .name = "MISC", + .offset = MTDPART_OFS_APPEND, + .size = 1 * 1024 * 1024}, + { + .name = "RECOVERY", + .offset = MTDPART_OFS_APPEND, + .size = 20 * 1024 * 1024}, + { + .name = "ROOT", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL}, +}; +#endif + +static int nand_init(void) +{ + u32 i, reg; + void __iomem *base; + + #define M4IF_GENP_WEIM_MM_MASK 0x00000001 + #define WEIM_GCR2_MUX16_BYP_GRANT_MASK 0x00001000 + + base = ioremap(MX53_BASE_ADDR(M4IF_BASE_ADDR), SZ_4K); + reg = __raw_readl(base + 0xc); + reg &= ~M4IF_GENP_WEIM_MM_MASK; + __raw_writel(reg, base + 0xc); + + iounmap(base); + + base = ioremap(MX53_BASE_ADDR(WEIM_BASE_ADDR), SZ_4K); + for (i = 0x4; i < 0x94; i += 0x18) { + reg = __raw_readl((u32)base + i); + reg &= ~WEIM_GCR2_MUX16_BYP_GRANT_MASK; + __raw_writel(reg, (u32)base + i); + } + + iounmap(base); + + return 0; +} + +static struct flash_platform_data mxc_nand_data = { +#ifdef CONFIG_MTD_PARTITIONS + .parts = nand_flash_partitions, + .nr_parts = ARRAY_SIZE(nand_flash_partitions), +#endif + .width = 1, + .init = nand_init, +}; + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = 0, /* Souce from CKIH1 for 44.1K */ + .spdif_clk_48000 = 7, /* Source from CKIH2 for 48k and 32k */ + .spdif_clkid = 0, + .spdif_clk = NULL, /* spdif bus clk */ +}; + +static struct mxc_audio_platform_data mxc_surround_audio_data = { + .ext_ram = 1, +}; + + +static struct platform_device mxc_alsa_surround_device = { + .name = "imx-3stack-cs42888", +}; + +static int __initdata mxc_apc_on = { 0 }; /* OFF: 0 (default), ON: 1 */ +static int __init apc_setup(char *__unused) +{ + mxc_apc_on = 1; + printk(KERN_INFO "Automotive Port Card is Plugged on\n"); + return 1; +} +__setup("apc", apc_setup); + +static int __initdata enable_w1 = { 0 }; +static int __init w1_setup(char *__unused) +{ + enable_w1 = 1; + return cpu_is_mx53(); +} +__setup("w1", w1_setup); + + +static int __initdata enable_spdif = { 0 }; +static int __init spdif_setup(char *__unused) +{ + enable_spdif = 1; + return 1; +} +__setup("spdif", spdif_setup); + +static struct android_pmem_platform_data android_pmem_pdata = { + .name = "pmem_adsp", + .start = 0, + .size = SZ_64M, + .no_allocator = 0, + .cached = PMEM_NONCACHE_NORMAL, +}; + +static struct android_pmem_platform_data android_pmem_gpu_pdata = { + .name = "pmem_gpu", + .start = 0, + .size = SZ_32M, + .no_allocator = 0, + .cached = PMEM_CACHE_ENABLE, +}; + +static struct android_usb_platform_data android_usb_pdata = { + .vendor_id = 0x0bb4, + .product_id = 0x0c01, + .adb_product_id = 0x0c02, + .version = 0x0100, + .product_name = "Android Phone", + .manufacturer_name = "Freescale", + .nluns = 3, +}; + /*! * Board specific fixup function. It is called by \b setup_arch() in * setup.c file very early on during kernel starts. It allows the user to @@ -495,17 +1396,38 @@ static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, int gpu_mem = SZ_128M; int fb_mem = SZ_32M; char *str; + int size; mxc_set_cpu_type(MXC_CPU_MX53); get_cpu_wp = mx53_evk_get_cpu_wp; set_num_cpu_wp = mx53_evk_set_num_cpu_wp; + for_each_tag(t, tags) { + if (t->hdr.tag != ATAG_MEM) + continue; + size = t->u.mem.size; + + android_pmem_pdata.start = + PHYS_OFFSET + size - android_pmem_pdata.size; + android_pmem_gpu_pdata.start = + android_pmem_pdata.start - android_pmem_gpu_pdata.size; + gpu_device.resource[5].start = + android_pmem_gpu_pdata.start - SZ_16M; + gpu_device.resource[5].end = + gpu_device.resource[5].start + SZ_16M - 1; + size -= android_pmem_pdata.size; + size -= android_pmem_gpu_pdata.size; + size -= SZ_16M; + t->u.mem.size = size; + } +#if 0 for_each_tag(mem_tag, tags) { if (mem_tag->hdr.tag == ATAG_MEM) { total_mem = mem_tag->u.mem.size; left_mem = total_mem - gpu_mem - fb_mem; break; + } } @@ -557,6 +1479,140 @@ static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, } #endif } +#endif +} + +static void __init mx53_evk_io_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx53common_pads, + ARRAY_SIZE(mx53common_pads)); + + if (board_is_mx53_arm2()) { + /* MX53 ARM2 CPU board */ + pr_info("MX53 ARM2 board \n"); + mxc_iomux_v3_setup_multiple_pads(mx53arm2_pads, + ARRAY_SIZE(mx53arm2_pads)); + + /* Config GPIO for OTG VBus */ + gpio_request(ARM2_OTG_VBUS, "otg-vbus"); + gpio_direction_output(ARM2_OTG_VBUS, 1); + + gpio_request(ARM2_SD1_CD, "sdhc1-cd"); + gpio_direction_input(ARM2_SD1_CD); /* SD1 CD */ + + gpio_request(ARM2_LCD_CONTRAST, "lcd-contrast"); + gpio_direction_output(ARM2_LCD_CONTRAST, 1); + } else { + /* MX53 EVK board */ + pr_info("MX53 EVK board \n"); + mxc_iomux_v3_setup_multiple_pads(mx53evk_pads, + ARRAY_SIZE(mx53evk_pads)); + + /* Host1 Vbus with GPIO high */ + gpio_request(EVK_USBH1_VBUS, "usbh1-vbus"); + gpio_direction_output(EVK_USBH1_VBUS, 1); + /* shutdown the Host1 Vbus when system bring up, + * Vbus will be opened in Host1 driver's probe function */ + gpio_set_value(EVK_USBH1_VBUS, 0); + + /* USB HUB RESET - De-assert USB HUB RESET_N */ + gpio_request(EVK_USB_HUB_RESET, "usb-hub-reset"); + gpio_direction_output(EVK_USB_HUB_RESET, 0); + msleep(1); + gpio_set_value(EVK_USB_HUB_RESET, 1); + + /* Config GPIO for OTG VBus */ + gpio_request(EVK_OTG_VBUS, "otg-vbus"); + gpio_direction_output(EVK_OTG_VBUS, 0); + if (board_is_mx53_evk_a()) /*rev A,"1" disable, "0" enable vbus*/ + gpio_set_value(EVK_OTG_VBUS, 1); + else if (board_is_mx53_evk_b()) /* rev B,"0" disable,"1" enable Vbus*/ + gpio_set_value(EVK_OTG_VBUS, 0); + + gpio_request(EVK_SD1_CD, "sdhc1-cd"); + gpio_direction_input(EVK_SD1_CD); /* SD1 CD */ + gpio_request(EVK_SD1_WP, "sdhc1-wp"); + gpio_direction_input(EVK_SD1_WP); /* SD1 WP */ + + /* SD3 CD */ + gpio_request(EVK_SD3_CD, "sdhc3-cd"); + gpio_direction_input(EVK_SD3_CD); + + /* SD3 WP */ + gpio_request(EVK_SD3_WP, "sdhc3-wp"); + gpio_direction_input(EVK_SD3_WP); + + /* reset FEC PHY */ + gpio_request(EVK_FEC_PHY_RESET, "fec-phy-reset"); + gpio_direction_output(EVK_FEC_PHY_RESET, 0); + msleep(1); + gpio_set_value(EVK_FEC_PHY_RESET, 1); + + gpio_request(MX53_ESAI_RESET, "fesai-reset"); + gpio_direction_output(MX53_ESAI_RESET, 0); + } + + /* DVI Detect */ + gpio_request(MX53_DVI_DETECT, "dvi-detect"); + gpio_direction_input(MX53_DVI_DETECT); + /* DVI Reset - Assert for i2c disabled mode */ + gpio_request(MX53_DVI_RESET, "dvi-reset"); + gpio_set_value(MX53_DVI_RESET, 0); + + /* DVI Power-down */ + gpio_request(MX53_DVI_PD, "dvi-pd"); + gpio_direction_output(MX53_DVI_PD, 1); + + /* DVI I2C enable */ + gpio_request(MX53_DVI_I2C, "dvi-i2c"); + gpio_direction_output(MX53_DVI_I2C, 0); + + mxc_iomux_v3_setup_multiple_pads(mx53_nand_pads, + ARRAY_SIZE(mx53_nand_pads)); + + gpio_request(MX53_PMIC_INT, "pmic-int"); + gpio_direction_input(MX53_PMIC_INT); /*PMIC_INT*/ + + /* headphone_det_b */ + gpio_request(MX53_HP_DETECT, "hp-detect"); + gpio_direction_input(MX53_HP_DETECT); + + /* power key */ + + /* LCD related gpio */ + + /* Camera reset */ + gpio_request(MX53_CAM_RESET, "cam-reset"); + gpio_direction_output(MX53_CAM_RESET, 1); + + /* TVIN reset */ + gpio_request(MX53_TVIN_RESET, "tvin-reset"); + gpio_direction_output(MX53_TVIN_RESET, 0); + msleep(5); + gpio_set_value(MX53_TVIN_RESET, 1); + + /* CAN1 enable GPIO*/ + gpio_request(MX53_CAN1_EN1, "can1-en1"); + gpio_direction_output(MX53_CAN1_EN1, 0); + + gpio_request(MX53_CAN1_EN2, "can1-en2"); + gpio_direction_output(MX53_CAN1_EN2, 0); + + /* CAN2 enable GPIO*/ + gpio_request(MX53_CAN2_EN1, "can2-en1"); + gpio_direction_output(MX53_CAN2_EN1, 0); + + gpio_request(MX53_CAN2_EN2, "can2-en2"); + gpio_direction_output(MX53_CAN2_EN2, 0); + + if (enable_spdif) { + struct pad_desc spdif_pin = MX53_PAD_GPIO_19__SPDIF_TX1; + mxc_iomux_v3_setup_pad(&spdif_pin); + } else { + /* GPIO for 12V */ + gpio_request(MX53_12V_EN, "12v-en"); + gpio_direction_output(MX53_12V_EN, 0); + } } /*! @@ -566,20 +1622,22 @@ static void __init mxc_board_init(void) { mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk"); mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk"); + mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); + clk_put(mxc_spdif_data.spdif_core_clk); /* SD card detect irqs */ if (board_is_mx53_arm2()) { - mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX53_PIN_GPIO_1); - mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX53_PIN_GPIO_1); + mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ_V3(ARM2_SD1_CD); + mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ_V3(ARM2_SD1_CD); mmc3_data.card_inserted_state = 1; mmc3_data.status = NULL; mmc3_data.wp_status = NULL; mmc1_data.wp_status = NULL; } else { - mxcsdhc3_device.resource[2].start = IOMUX_TO_IRQ(MX53_PIN_EIM_DA11); - mxcsdhc3_device.resource[2].end = IOMUX_TO_IRQ(MX53_PIN_EIM_DA11); - mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX53_PIN_EIM_DA13); - mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX53_PIN_EIM_DA13); + mxcsdhc3_device.resource[2].start = IOMUX_TO_IRQ_V3(EVK_SD3_CD); + mxcsdhc3_device.resource[2].end = IOMUX_TO_IRQ_V3(EVK_SD3_CD); + mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ_V3(EVK_SD1_CD); + mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ_V3(EVK_SD1_CD); } mxc_cpu_common_init(); @@ -596,7 +1654,7 @@ static void __init mxc_board_init(void) mxc_register_device(&mxc_rtc_device, &srtc_data); mxc_register_device(&mxc_w1_master_device, &mxc_w1_data); mxc_register_device(&mxc_ipu_device, &mxc_ipu_data); - mxc_register_device(&lcd_wvga_device, &lcd_wvga_data); + mxc_register_device(&mxc_ldb_device, &ldb_data); mxc_register_device(&mxc_tve_device, &tve_data); mxc_register_device(&mxcvpu_device, &mxc_vpu_data); mxc_register_device(&gpu_device, NULL); @@ -605,41 +1663,60 @@ static void __init mxc_board_init(void) mxc_register_device(&mx53_lpmode_device, NULL); mxc_register_device(&busfreq_device, NULL); mxc_register_device(&sdram_autogating_device, NULL); + */ mxc_register_device(&mxc_dvfs_core_device, &dvfs_core_data); + mxc_register_device(&busfreq_device, NULL); + + /* mxc_register_device(&mxc_dvfs_per_device, &dvfs_per_data); */ + mxc_register_device(&mxc_iim_device, NULL); if (!board_is_mx53_arm2()) { mxc_register_device(&mxc_pwm2_device, NULL); mxc_register_device(&mxc_pwm_backlight_device, &mxc_pwm_backlight_data); } + mxc_register_device(&mxc_flexcan0_device, &flexcan0_data); + mxc_register_device(&mxc_flexcan1_device, &flexcan1_data); + /* mxc_register_device(&mxc_keypad_device, &keypad_plat_data); */ mxc_register_device(&mxcsdhc1_device, &mmc1_data); mxc_register_device(&mxcsdhc3_device, &mmc3_data); mxc_register_device(&mxc_ssi1_device, NULL); mxc_register_device(&mxc_ssi2_device, NULL); - /* + mxc_register_device(&ahci_fsl_device, &sata_data); mxc_register_device(&mxc_alsa_spdif_device, &mxc_spdif_data); - */ - mxc_register_device(&mxc_fec_device, NULL); -/* - spi_register_board_info(mxc_spi_nor_device, - ARRAY_SIZE(mxc_spi_nor_device)); -*/ - + if (!mxc_apc_on) + mxc_register_device(&mxc_fec_device, &fec_data); + spi_register_board_info(mxc_dataflash_device, + ARRAY_SIZE(mxc_dataflash_device)); i2c_register_board_info(0, mxc_i2c0_board_info, ARRAY_SIZE(mxc_i2c0_board_info)); i2c_register_board_info(1, mxc_i2c1_board_info, ARRAY_SIZE(mxc_i2c1_board_info)); - + mxc_register_device(&mxc_android_pmem_device, &android_pmem_pdata); + mxc_register_device(&mxc_android_pmem_gpu_device, &android_pmem_gpu_pdata); + mxc_register_device(&android_usb_device, &android_usb_pdata); + mxc_register_device(&mxc_powerkey_device, NULL); mx53_evk_init_mc13892(); /* pm_power_off = mxc_power_off; */ mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data); + mxc_register_device(&mxc_mlb_device, &mlb_data); + mx5_set_otghost_vbus_func(mx53_gpio_usbotg_driver_vbus); mx5_usb_dr_init(); + mx5_set_host1_vbus_func(mx53_gpio_host1_driver_vbus); mx5_usbh1_init(); + mxc_register_device(&mxc_nandv2_mtd_device, &mxc_nand_data); + if (mxc_apc_on) { + mxc_register_device(&mxc_esai_device, &esai_data); + mxc_register_device(&mxc_alsa_surround_device, + &mxc_surround_audio_data); + } + mxc_register_device(&mxc_v4l2_device, NULL); + mxc_register_device(&mxc_v4l2out_device, NULL); } static void __init mx53_evk_timer_init(void) diff --git a/arch/arm/mach-mx5/mx53_evk_pmic_mc13892.c b/arch/arm/mach-mx5/mx53_evk_pmic_mc13892.c index f8ec651cd459..be5f850fcf97 100644 --- a/arch/arm/mach-mx5/mx53_evk_pmic_mc13892.c +++ b/arch/arm/mach-mx5/mx53_evk_pmic_mc13892.c @@ -23,8 +23,8 @@ #include <linux/regulator/machine.h> #include <linux/mfd/mc13892/core.h> #include <mach/irqs.h> -#include "iomux.h" -#include "mx53_pins.h" + +#include <mach/iomux-mx53.h> /* * Convenience conversion. @@ -183,6 +183,8 @@ static struct regulator_init_data vvideo_init = { .min_uV = mV_to_uV(2500), .max_uV = mV_to_uV(2775), .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, } }; @@ -266,7 +268,7 @@ static struct regulator_init_data gpo4_init = { .name = "GPO4", } }; - +#if 0 /*! * the event handler for power on event */ @@ -274,20 +276,20 @@ static void power_on_evt_handler(void) { pr_info("pwr on event1 is received \n"); } - +#endif static int mc13892_regulator_init(struct mc13892 *mc13892) { unsigned int value; - pmic_event_callback_t power_key_event; +// pmic_event_callback_t power_key_event; int register_mask; pr_info("Initializing regulators for MX53 EVK \n"); - +#if 0 /* subscribe PWRON1 event to enable ON_OFF key */ power_key_event.param = NULL; power_key_event.func = (void *)power_on_evt_handler; pmic_event_subscribe(EVENT_PWRONI, power_key_event); - +#endif /* Bit 4 DRM: keep VSRTC and CLK32KMCU on for all states */ #if defined(CONFIG_RTC_DRV_MXC_V2) || defined(CONFIG_RTC_DRV_MXC_V2_MODULE) value = BITFVAL(DRM, 1); @@ -337,7 +339,7 @@ static struct mc13892_platform_data mc13892_plat = { static struct i2c_board_info __initdata mc13892_i2c_device = { I2C_BOARD_INFO("mc13892", 0x08), - .irq = IOMUX_TO_IRQ(MX53_PIN_GPIO_16), + .irq = IOMUX_TO_IRQ_V3(203), .platform_data = &mc13892_plat, }; diff --git a/arch/arm/mach-mx5/pm.c b/arch/arm/mach-mx5/pm.c index a63d6e725e8f..b2bf2f8355fd 100644 --- a/arch/arm/mach-mx5/pm.c +++ b/arch/arm/mach-mx5/pm.c @@ -25,9 +25,15 @@ #include <asm/tlb.h> #include <asm/mach/map.h> #include <mach/hardware.h> -#include "crm_regs.h" #include "mach/irqs.h" +#define MXC_SRPG_EMPGC0_SRPGCR (IO_ADDRESS(GPC_BASE_ADDR) + 0x2C0) +#define MXC_SRPG_EMPGC1_SRPGCR (IO_ADDRESS(GPC_BASE_ADDR) + 0x2D0) +#define DATABAHN_CTL_REG0 0 +#define DATABAHN_CTL_REG19 0x4c +#define DATABAHN_CTL_REG79 0x13c +#define DATABAHN_PHY_REG25 0x264 + static struct cpu_wp *cpu_wp_tbl; static struct clk *cpu_clk; @@ -41,16 +47,17 @@ extern int set_cpu_freq(int wp); static struct device *pm_dev; struct clk *gpc_dvfs_clk; extern void cpu_do_suspend_workaround(u32 sdclk_iomux_addr); -extern void cpu_cortexa8_do_idle(void *); +extern void mx50_suspend(u32 databahn_addr); extern struct cpu_wp *(*get_cpu_wp)(int *wp); +extern void __iomem *databahn_base; extern int iram_ready; void *suspend_iram_base; void (*suspend_in_iram)(void *sdclk_iomux_addr) = NULL; +void __iomem *suspend_param1; -static int mx51_suspend_enter(suspend_state_t state) +static int mx5_suspend_enter(suspend_state_t state) { - void __iomem *sdclk_iomux_addr = IO_ADDRESS(IOMUXC_BASE_ADDR + 0x4b8); u32 * wake_src; /* Check that we have a wake up source. We don't want to suspend if not.*/ @@ -82,12 +89,15 @@ static int mx51_suspend_enter(suspend_state_t state) local_flush_tlb_all(); flush_cache_all(); - /* Run the suspend code from iRAM. */ - suspend_in_iram(sdclk_iomux_addr); + if (cpu_is_mx51() || cpu_is_mx53()) { + /* Run the suspend code from iRAM. */ + suspend_in_iram(suspend_param1); - /*clear the EMPGC0/1 bits */ - __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR); - __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR); + /*clear the EMPGC0/1 bits */ + __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR); + __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR); + } else + suspend_in_iram(databahn_base); } else { cpu_do_idle(); } @@ -99,7 +109,7 @@ static int mx51_suspend_enter(suspend_state_t state) /* * Called after processes are frozen, but before we shut down devices. */ -static int mx51_suspend_prepare(void) +static int mx5_suspend_prepare(void) { #if defined(CONFIG_CPU_FREQ) struct cpufreq_freqs freqs; @@ -122,7 +132,7 @@ static int mx51_suspend_prepare(void) /* * Called before devices are re-setup. */ -static void mx51_suspend_finish(void) +static void mx5_suspend_finish(void) { #if defined(CONFIG_CPU_FREQ) struct cpufreq_freqs freqs; @@ -145,35 +155,35 @@ static void mx51_suspend_finish(void) /* * Called after devices are re-setup, but before processes are thawed. */ -static void mx51_suspend_end(void) +static void mx5_suspend_end(void) { } -static int mx51_pm_valid(suspend_state_t state) +static int mx5_pm_valid(suspend_state_t state) { return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX); } -struct platform_suspend_ops mx51_suspend_ops = { - .valid = mx51_pm_valid, - .prepare = mx51_suspend_prepare, - .enter = mx51_suspend_enter, - .finish = mx51_suspend_finish, - .end = mx51_suspend_end, +struct platform_suspend_ops mx5_suspend_ops = { + .valid = mx5_pm_valid, + .prepare = mx5_suspend_prepare, + .enter = mx5_suspend_enter, + .finish = mx5_suspend_finish, + .end = mx5_suspend_end, }; -static int __devinit mx51_pm_probe(struct platform_device *pdev) +static int __devinit mx5_pm_probe(struct platform_device *pdev) { pm_dev = &pdev->dev; return 0; } -static struct platform_driver mx51_pm_driver = { +static struct platform_driver mx5_pm_driver = { .driver = { - .name = "mx51_pm", + .name = "mx5_pm", }, - .probe = mx51_pm_probe, + .probe = mx5_pm_probe, }; static int __init pm_init(void) @@ -181,19 +191,32 @@ static int __init pm_init(void) int cpu_wp_nr; unsigned long iram_paddr; - pr_info("Static Power Management for Freescale i.MX51\n"); - if (platform_driver_register(&mx51_pm_driver) != 0) { - printk(KERN_ERR "mx51_pm_driver register failed\n"); + pr_info("Static Power Management for Freescale i.MX5\n"); + if (platform_driver_register(&mx5_pm_driver) != 0) { + printk(KERN_ERR "mx5_pm_driver register failed\n"); return -ENODEV; } - suspend_set_ops(&mx51_suspend_ops); + suspend_set_ops(&mx5_suspend_ops); /* Move suspend routine into iRAM */ iram_alloc(SZ_4K, &iram_paddr); /* Need to remap the area here since we want the memory region to be executable. */ suspend_iram_base = __arm_ioremap(iram_paddr, SZ_4K, MT_HIGH_VECTORS); - memcpy(suspend_iram_base, cpu_do_suspend_workaround, SZ_4K); + + if (cpu_is_mx51() || cpu_is_mx53()) { + suspend_param1 = IO_ADDRESS(IOMUXC_BASE_ADDR + 0x4b8); + memcpy(suspend_iram_base, cpu_do_suspend_workaround, + SZ_4K); + } else if (cpu_is_mx50()) { + /* + * Need to run the suspend code from IRAM as the DDR needs + * to be put into self refresh mode manually. + */ + memcpy(suspend_iram_base, mx50_suspend, SZ_4K); + + suspend_param1 = databahn_base; + } suspend_in_iram = (void *)suspend_iram_base; cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr); @@ -212,7 +235,7 @@ static int __init pm_init(void) static void __exit pm_cleanup(void) { /* Unregister the device structure */ - platform_driver_unregister(&mx51_pm_driver); + platform_driver_unregister(&mx5_pm_driver); } module_init(pm_init); diff --git a/arch/arm/mach-mx5/sdram_autogating.c b/arch/arm/mach-mx5/sdram_autogating.c index fa9f0ccfe283..0b05d791c4f9 100644 --- a/arch/arm/mach-mx5/sdram_autogating.c +++ b/arch/arm/mach-mx5/sdram_autogating.c @@ -80,6 +80,8 @@ int sdram_autogating_active() void start_sdram_autogating() { + if (cpu_is_mx50()) + return; if (sdram_autogating_paused) { enable(); sdram_autogating_paused = 0; @@ -88,6 +90,9 @@ void start_sdram_autogating() void stop_sdram_autogating() { + if (cpu_is_mx50()) + return; + if (sdram_autogating_is_active) { sdram_autogating_paused = 1; disable(); diff --git a/arch/arm/mach-mx5/serial.c b/arch/arm/mach-mx5/serial.c index 053829cd3b4e..6d01de55c50b 100644 --- a/arch/arm/mach-mx5/serial.c +++ b/arch/arm/mach-mx5/serial.c @@ -23,7 +23,6 @@ #include <mach/hardware.h> #include <mach/mxc_uart.h> #include "serial.h" -#include "board-mx53_evk.h" #if defined(CONFIG_SERIAL_MXC) || defined(CONFIG_SERIAL_MXC_MODULE) @@ -42,13 +41,12 @@ static uart_mxc_port mxc_ports[] = { .flags = ASYNC_BOOT_AUTOCONF, .line = 0, }, - .ints_muxed = UART1_MUX_INTS, + .ints_muxed = 1, .mode = UART1_MODE, .ir_mode = UART1_IR, .enabled = UART1_ENABLED, - .hardware_flow = UART1_HW_FLOW, .cts_threshold = UART1_UCR4_CTSTL, - .dma_enabled = UART1_DMA_ENABLE, + .dma_enabled = UART1_DMA_ENABLED, .dma_rxbuf_size = UART1_DMA_RXBUFSIZE, .rx_threshold = UART1_UFCR_RXTL, .tx_threshold = UART1_UFCR_TXTL, @@ -63,13 +61,12 @@ static uart_mxc_port mxc_ports[] = { .flags = ASYNC_BOOT_AUTOCONF, .line = 1, }, - .ints_muxed = UART2_MUX_INTS, + .ints_muxed = 1, .mode = UART2_MODE, .ir_mode = UART2_IR, .enabled = UART2_ENABLED, - .hardware_flow = UART2_HW_FLOW, .cts_threshold = UART2_UCR4_CTSTL, - .dma_enabled = UART2_DMA_ENABLE, + .dma_enabled = UART2_DMA_ENABLED, .dma_rxbuf_size = UART2_DMA_RXBUFSIZE, .rx_threshold = UART2_UFCR_RXTL, .tx_threshold = UART2_UFCR_TXTL, @@ -84,13 +81,12 @@ static uart_mxc_port mxc_ports[] = { .flags = ASYNC_BOOT_AUTOCONF, .line = 2, }, - .ints_muxed = UART3_MUX_INTS, + .ints_muxed = 1, .mode = UART3_MODE, .ir_mode = UART3_IR, .enabled = UART3_ENABLED, - .hardware_flow = UART3_HW_FLOW, .cts_threshold = UART3_UCR4_CTSTL, - .dma_enabled = UART3_DMA_ENABLE, + .dma_enabled = UART3_DMA_ENABLED, .dma_rxbuf_size = UART3_DMA_RXBUFSIZE, .rx_threshold = UART3_UFCR_RXTL, .tx_threshold = UART3_UFCR_TXTL, @@ -105,13 +101,11 @@ static uart_mxc_port mxc_ports[] = { .flags = ASYNC_BOOT_AUTOCONF, .line = 3, }, - .ints_muxed = UART4_MUX_INTS, - .mode = UART4_MODE, - .ir_mode = UART4_IR, - .enabled = UART4_ENABLED, - .hardware_flow = UART4_HW_FLOW, + .ints_muxed = 1, + .mode = MODE_DCE, + .ir_mode = NO_IRDA, + .enabled = 1, .cts_threshold = UART4_UCR4_CTSTL, - .dma_enabled = UART4_DMA_ENABLE, .dma_rxbuf_size = UART4_DMA_RXBUFSIZE, .rx_threshold = UART4_UFCR_RXTL, .tx_threshold = UART4_UFCR_TXTL, @@ -126,13 +120,11 @@ static uart_mxc_port mxc_ports[] = { .flags = ASYNC_BOOT_AUTOCONF, .line = 4, }, - .ints_muxed = UART5_MUX_INTS, - .mode = UART5_MODE, - .ir_mode = UART5_IR, - .enabled = UART5_ENABLED, - .hardware_flow = UART5_HW_FLOW, + .ints_muxed = 1, + .mode = MODE_DCE, + .ir_mode = NO_IRDA, + .enabled = 1, .cts_threshold = UART5_UCR4_CTSTL, - .dma_enabled = UART5_DMA_ENABLE, .dma_rxbuf_size = UART5_DMA_RXBUFSIZE, .rx_threshold = UART5_UFCR_RXTL, .tx_threshold = UART5_UFCR_TXTL, @@ -149,18 +141,9 @@ static struct resource mxc_uart_resources1[] = { .flags = IORESOURCE_MEM, }, { - .start = UART1_INT1, + .start = MXC_INT_UART1, .flags = IORESOURCE_IRQ, }, - { - .start = UART1_INT2, - .flags = IORESOURCE_IRQ, - }, - { - .start = UART1_INT3, - .flags = IORESOURCE_IRQ, - }, - }; static struct platform_device mxc_uart_device1 = { @@ -180,15 +163,7 @@ static struct resource mxc_uart_resources2[] = { .flags = IORESOURCE_MEM, }, { - .start = UART2_INT1, - .flags = IORESOURCE_IRQ, - }, - { - .start = UART2_INT2, - .flags = IORESOURCE_IRQ, - }, - { - .start = UART2_INT3, + .start = MXC_INT_UART2, .flags = IORESOURCE_IRQ, }, }; @@ -210,15 +185,7 @@ static struct resource mxc_uart_resources3[] = { .flags = IORESOURCE_MEM, }, { - .start = UART3_INT1, - .flags = IORESOURCE_IRQ, - }, - { - .start = UART3_INT2, - .flags = IORESOURCE_IRQ, - }, - { - .start = UART3_INT3, + .start = MXC_INT_UART3, .flags = IORESOURCE_IRQ, }, }; @@ -240,15 +207,7 @@ static struct resource mxc_uart_resources4[] = { .flags = IORESOURCE_MEM, }, { - .start = UART4_INT1, - .flags = IORESOURCE_IRQ, - }, - { - .start = UART4_INT2, - .flags = IORESOURCE_IRQ, - }, - { - .start = UART4_INT3, + .start = MXC_INT_UART4, .flags = IORESOURCE_IRQ, }, }; @@ -270,15 +229,7 @@ static struct resource mxc_uart_resources5[] = { .flags = IORESOURCE_MEM, }, { - .start = UART5_INT1, - .flags = IORESOURCE_IRQ, - }, - { - .start = UART5_INT2, - .flags = IORESOURCE_IRQ, - }, - { - .start = UART5_INT3, + .start = MXC_INT_UART5, .flags = IORESOURCE_IRQ, }, }; @@ -295,7 +246,7 @@ static struct platform_device mxc_uart_device5 = { static int __init mxc_init_uart(void) { - if (cpu_is_mx53()) { + if (cpu_is_mx53() || cpu_is_mx50()) { mxc_uart_resources1[0].start -= 0x20000000; mxc_uart_resources1[0].end -= 0x20000000; mxc_uart_resources2[0].start -= 0x20000000; @@ -311,16 +262,10 @@ static int __init mxc_init_uart(void) /* Register all the MXC UART platform device structures */ platform_device_register(&mxc_uart_device1); platform_device_register(&mxc_uart_device2); -#if UART3_ENABLED == 1 platform_device_register(&mxc_uart_device3); -#endif /* UART3_ENABLED */ if (cpu_is_mx53()) { -#if UART4_ENABLED == 1 platform_device_register(&mxc_uart_device4); -#endif /* UART4_ENABLED */ -#if UART5_ENABLED == 1 platform_device_register(&mxc_uart_device5); -#endif /* UART5_ENABLED */ } return 0; } diff --git a/arch/arm/mach-mx5/serial.h b/arch/arm/mach-mx5/serial.h index aa97228e3865..b74cd0b2661c 100644 --- a/arch/arm/mach-mx5/serial.h +++ b/arch/arm/mach-mx5/serial.h @@ -14,17 +14,8 @@ #ifndef __ARCH_ARM_MACH_MX51_SERIAL_H__ #define __ARCH_ARM_MACH_MX51_SERIAL_H__ -#include <mach/mxc_uart.h> - /* UART 1 configuration */ /*! - * This option allows to choose either an interrupt-driven software controlled - * hardware flow control (set this option to 0) or hardware-driven hardware - * flow control (set this option to 1). - */ -/* UART used as wakeup source */ -#define UART1_HW_FLOW 0 -/*! * This specifies the threshold at which the CTS pin is deasserted by the * RXFIFO. Set this value in Decimal to anything from 0 to 32 for * hardware-driven hardware flow control. Read the HW spec while specifying @@ -33,10 +24,6 @@ */ #define UART1_UCR4_CTSTL 16 /*! - * This is option to enable (set this option to 1) or disable DMA data transfer - */ -#define UART1_DMA_ENABLE 0 -/*! * Specify the size of the DMA receive buffer. The minimum buffer size is 512 * bytes. The buffer size should be a multiple of 256. */ @@ -56,88 +43,28 @@ */ #define UART1_UFCR_TXTL 16 /* UART 2 configuration */ -#define UART2_HW_FLOW 0 -#define UART2_UCR4_CTSTL -1 -#define UART2_DMA_ENABLE 0 +#define UART2_UCR4_CTSTL 16 #define UART2_DMA_RXBUFSIZE 512 #define UART2_UFCR_RXTL 16 #define UART2_UFCR_TXTL 16 /* UART 3 configuration */ -#define UART3_HW_FLOW 1 #define UART3_UCR4_CTSTL 16 -#define UART3_DMA_ENABLE 1 #define UART3_DMA_RXBUFSIZE 1024 #define UART3_UFCR_RXTL 16 #define UART3_UFCR_TXTL 16 /* UART 4 configuration */ -#define UART4_HW_FLOW 0 #define UART4_UCR4_CTSTL -1 -#define UART4_DMA_ENABLE 0 #define UART4_DMA_RXBUFSIZE 512 #define UART4_UFCR_RXTL 16 #define UART4_UFCR_TXTL 16 /* UART 5 configuration */ -#define UART5_HW_FLOW 0 #define UART5_UCR4_CTSTL -1 -#define UART5_DMA_ENABLE 0 #define UART5_DMA_RXBUFSIZE 512 #define UART5_UFCR_RXTL 16 #define UART5_UFCR_TXTL 16 -/* - * UART Chip level Configuration that a user may not have to edit. These - * configuration vary depending on how the UART module is integrated with - * the ARM core - */ -/* - * Is the MUXED interrupt output sent to the ARM core - */ -#define INTS_NOTMUXED 0 -#define INTS_MUXED 1 -/* UART 1 configuration */ -/*! - * This define specifies whether the muxed ANDed interrupt line or the - * individual interrupts from the UART port is integrated with the ARM core. - * There exists a define like this for each UART port. Valid values that can - * be used are \b INTS_NOTMUXED or \b INTS_MUXED. - */ -#define UART1_MUX_INTS INTS_MUXED -/*! - * This define specifies the transmitter interrupt number or the interrupt - * number of the ANDed interrupt in case the interrupts are muxed. There exists - * a define like this for each UART port. - */ -#define UART1_INT1 MXC_INT_UART1 -/*! - * This define specifies the receiver interrupt number. If the interrupts of - * the UART are muxed, then we specify here a dummy value -1. There exists a - * define like this for each UART port. - */ -#define UART1_INT2 -1 -/*! - * This specifies the master interrupt number. If the interrupts of the UART - * are muxed, then we specify here a dummy value of -1. There exists a define - * like this for each UART port. - */ -#define UART1_INT3 -1 -/* UART 2 configuration */ -#define UART2_MUX_INTS INTS_MUXED -#define UART2_INT1 MXC_INT_UART2 -#define UART2_INT2 -1 -#define UART2_INT3 -1 -/* UART 3 configuration */ -#define UART3_MUX_INTS INTS_MUXED -#define UART3_INT1 MXC_INT_UART3 -#define UART3_INT2 -1 -#define UART3_INT3 -1 -/* UART 4 configuration */ -#define UART4_MUX_INTS INTS_MUXED -#define UART4_INT1 MXC_INT_UART4 -#define UART4_INT2 -1 -#define UART4_INT3 -1 -/* UART 5 configuration */ -#define UART5_MUX_INTS INTS_MUXED -#define UART5_INT1 MXC_INT_UART5 -#define UART5_INT2 -1 -#define UART5_INT3 -1 + +#ifdef CONFIG_MODULE_CCXMX51 +#include "board-ccwmx51.h" +#endif #endif /* __ARCH_ARM_MACH_MX51_SERIAL_H__ */ diff --git a/arch/arm/mach-mx5/system.c b/arch/arm/mach-mx5/system.c index 669be9c4c9cb..199c30e26947 100644 --- a/arch/arm/mach-mx5/system.c +++ b/arch/arm/mach-mx5/system.c @@ -16,6 +16,7 @@ #include <linux/platform_device.h> #include <asm/io.h> #include <mach/hardware.h> +#include <mach/clock.h> #include <asm/proc-fns.h> #include <asm/system.h> #include "crm_regs.h" @@ -33,10 +34,13 @@ extern int mxc_jtag_enabled; extern int iram_ready; -static struct clk *gpc_dvfs_clk; - -extern void cpu_cortexa8_do_idle(void *addr); +extern void __iomem *ccm_base; +extern void __iomem *databahn_base; +extern void (*wait_in_iram)(void *ccm_addr, void *databahn_addr); +extern void *wait_in_iram_base; +extern void mx50_wait(u32 ccm_base, u32 databahn_addr); +static struct clk *gpc_dvfs_clk; /* set cpu low power mode before WFI instruction */ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) @@ -66,6 +70,7 @@ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) if (mode == WAIT_UNCLOCKED_POWER_OFF) { ccm_clpcr |= (0x1 << MXC_CCM_CLPCR_LPM_OFFSET); ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY; + ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS; stop_mode = 0; } else { ccm_clpcr |= (0x2 << MXC_CCM_CLPCR_LPM_OFFSET); @@ -96,7 +101,8 @@ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) __raw_writel(ccm_clpcr, MXC_CCM_CLPCR); if (cpu_is_mx51()) __raw_writel(arm_srpgcr, MXC_SRPG_ARM_SRPGCR); - __raw_writel(arm_srpgcr, MXC_SRPG_NEON_SRPGCR); + if (!cpu_is_mx50()) + __raw_writel(arm_srpgcr, MXC_SRPG_NEON_SRPGCR); if (stop_mode) { __raw_writel(empgc0, MXC_SRPG_EMPGC0_SRPGCR); __raw_writel(empgc1, MXC_SRPG_EMPGC1_SRPGCR); @@ -150,14 +156,21 @@ static int arch_idle_mode = WAIT_UNCLOCKED_POWER_OFF; */ void arch_idle(void) { - if (likely(!mxc_jtag_enabled)) { +/* if (likely(!mxc_jtag_enabled)) */{ + struct clk *ddr_clk = clk_get(NULL, "ddr_clk"); if (gpc_dvfs_clk == NULL) gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs_clk"); /* gpc clock is needed for SRPG */ clk_enable(gpc_dvfs_clk); mxc_cpu_lp_set(arch_idle_mode); - cpu_do_idle(); + if (cpu_is_mx50() && (clk_get_usecount(ddr_clk) == 0)) { + memcpy(wait_in_iram_base, mx50_wait, SZ_4K); + wait_in_iram = (void *)wait_in_iram_base; + wait_in_iram(ccm_base, databahn_base); + } else + cpu_do_idle(); clk_disable(gpc_dvfs_clk); + clk_put(ddr_clk); } } @@ -171,8 +184,99 @@ void arch_reset(char mode) /* Workaround to reset NFC_CONFIG3 register * due to the chip warm reset does not reset it */ - __raw_writel(0x20600, IO_ADDRESS(NFC_BASE_ADDR) + 0x28); + if (cpu_is_mx51() || cpu_is_mx53()) + __raw_writel(0x20600, IO_ADDRESS(NFC_BASE_ADDR) + 0x28); /* Assert SRS signal */ mxc_wd_reset(); } + + +static int __mxs_reset_block(void __iomem *hwreg, int just_enable) +{ + u32 c; + int timeout; + + /* the process of software reset of IP block is done + in several steps: + + - clear SFTRST and wait for block is enabled; + - clear clock gating (CLKGATE bit); + - set the SFTRST again and wait for block is in reset; + - clear SFTRST and wait for reset completion. + */ + c = __raw_readl(hwreg); + c &= ~(1 << 31); /* clear SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1 << 31)) == 0) + break; + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when enabling\n", + __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1 << 30); /* clear CLKGATE */ + __raw_writel(c, hwreg); + + if (!just_enable) { + c = __raw_readl(hwreg); + c |= (1 << 31); /* now again set SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* poll until CLKGATE set */ + if (__raw_readl(hwreg) & (1 << 30)) + break; + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when resetting\n", + __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1 << 31); /* clear SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1 << 31)) == 0) + break; + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when enabling " + "after reset\n", __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1 << 30); /* clear CLKGATE */ + __raw_writel(c, hwreg); + } + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1 << 30)) == 0) + break; + + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when unclockgating\n", + __func__, hwreg); + return -ETIME; + } + + return 0; +} + +int mxs_reset_block(void __iomem *hwreg, int just_enable) +{ + int try = 10; + int r; + + while (try--) { + r = __mxs_reset_block(hwreg, just_enable); + if (!r) + break; + pr_debug("%s: try %d failed\n", __func__, 10 - try); + } + return r; +} diff --git a/arch/arm/mach-mx5/usb.h b/arch/arm/mach-mx5/usb.h index f451e6fe8582..6115d3375c05 100644 --- a/arch/arm/mach-mx5/usb.h +++ b/arch/arm/mach-mx5/usb.h @@ -30,6 +30,9 @@ extern void __init mx5_usb_dr_init(void); extern void __init mx5_usbh1_init(void); extern void __init mx5_usbh2_init(void); +typedef void (*driver_vbus_func)(bool); +extern void mx5_set_host1_vbus_func(driver_vbus_func); +extern void mx5_set_otghost_vbus_func(driver_vbus_func); /* * Used to set pdata->operating_mode before registering the platform_device. * If OTG is configured, the controller operates in OTG mode, diff --git a/arch/arm/mach-mx5/usb_dr.c b/arch/arm/mach-mx5/usb_dr.c index 658583b65ab6..4f36379b8d64 100644 --- a/arch/arm/mach-mx5/usb_dr.c +++ b/arch/arm/mach-mx5/usb_dr.c @@ -18,12 +18,12 @@ #include <linux/fsl_devices.h> #include <mach/arc_otg.h> #include <mach/hardware.h> +#include <asm/delay.h> #include "usb.h" #if defined(CONFIG_USB_OTG) || defined(CONFIG_USB_EHCI_ARC_OTG) || defined(CONFIG_USB_GADGET_ARC) static int usbotg_init_ext(struct platform_device *pdev); static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata); -static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable); static void usbotg_clock_gate(bool on); /* @@ -40,7 +40,6 @@ static struct fsl_usb2_platform_data dr_utmi_config = { .gpio_usb_active = gpio_usbotg_hs_active, .gpio_usb_inactive = gpio_usbotg_hs_inactive, .usb_clock_for_pm = usbotg_clock_gate, - .wake_up_enable = _wake_up_enable, .transceiver = "utmi", }; @@ -48,6 +47,13 @@ static struct fsl_usb2_platform_data dr_utmi_config = { static int usbotg_init_ext(struct platform_device *pdev) { struct clk *usb_clk; + if (cpu_is_mx50()) { + usb_clk = clk_get(&pdev->dev, "usb_phy1_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + + return usbotg_init(pdev); + } usb_clk = clk_get(NULL, "usboh3_clk"); clk_enable(usb_clk); @@ -69,6 +75,15 @@ static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata) { struct clk *usb_clk; + if (cpu_is_mx50()) { + usb_clk = clk_get(&pdata->pdev->dev, "usb_phy1_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + + usbotg_uninit(pdata); + return; + } + usb_clk = clk_get(NULL, "usboh3_clk"); clk_disable(usb_clk); clk_put(usb_clk); @@ -80,33 +95,149 @@ static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata) usbotg_uninit(pdata); } -static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable) +#define ENABLED_BY_HOST (0x1 << 0) +#define ENABLED_BY_DEVICE (0x1 << 1) +#if defined(CONFIG_USB_EHCI_ARC_OTG) && defined(CONFIG_USB_GADGET_ARC) +/* Below two macros are used at otg mode to indicate usb mode*/ +static u32 wakeup_irq_enable_src = 0; +static void __wakeup_irq_enable(bool on, int source) { - if (get_usb_mode(pdata) == FSL_USB_DR_DEVICE) { - if (enable) { + /* otg host and device share the OWIE bit, only when host and device + * all enable the wakeup irq, we can enable the OWIE bit + */ + if (on) { + wakeup_irq_enable_src |= source; + if (wakeup_irq_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) { USBCTRL |= UCTRL_OWIE; - USBCTRL_HOST2 |= UCTRL_H2OVBWK_EN; USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_CONF2; - } else { - USBCTRL &= ~UCTRL_OWIE; - USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN; - USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CONF2; + printk("OTG wakeup irq is enabled\n"); } - } else { - if (enable) { - USBCTRL |= UCTRL_OWIE; - USBCTRL_HOST2 |= (1 << 5); - } else { - USBCTRL &= ~UCTRL_OWIE; - USBCTRL_HOST2 &= ~(1 << 5); + }else { + printk("OTG wakeup irq disable\n"); + USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CONF2; + USBCTRL &= ~UCTRL_OWIE; + wakeup_irq_enable_src &= ~source; + /* The interrupt must be disabled for at least 3 clock + * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ + udelay(100); + } +} +#else +static void __wakeup_irq_enable(bool on, int source) +{ + if (on) { + USBCTRL |= UCTRL_OWIE; + USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_CONF2; + }else { + USBCTRL &= ~UCTRL_OWIE; + USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CONF2; + /* The interrupt must be disabled for at least 3 clock + * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ + udelay(100); + } +} +#endif + +#ifdef CONFIG_USB_EHCI_ARC_OTG +static void _host_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + __wakeup_irq_enable(enable, ENABLED_BY_HOST); + /* host only care the ID change wakeup event */ + if (enable) { + USBCTRL_HOST2 |= UCTRL_H2OIDWK_EN; + }else { + USBCTRL_HOST2 &= ~UCTRL_H2OIDWK_EN; + /* The interrupt must be disabled for at least 2 clock + * cycles of the standby clock(32k Hz) , that is 0.0625 ms*/ + udelay(100); + } +} +#endif + +#ifdef CONFIG_USB_GADGET_ARC +static void _device_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + __wakeup_irq_enable(enable, ENABLED_BY_DEVICE); + /* if udc is not used by any gadget, we can not enable the vbus wakeup */ + if (!pdata->port_enables) + { + USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN; + return; + } + if (enable) { + USBCTRL_HOST2 |= UCTRL_H2OVBWK_EN; + }else { + USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN; + } +} +#endif + +#if defined(CONFIG_USB_EHCI_ARC_OTG) && defined(CONFIG_USB_GADGET_ARC) +static u32 low_power_enable_src = 0; +static void __phy_lowpower_suspend(bool enable, int source) +{ + if (enable) { + low_power_enable_src |= source; + if (low_power_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) { + UOG_PORTSC1 |= PORTSC_PHCD; + printk("OTG phy lowpower enable\n"); } + }else { + printk("OTG phy lowpower disable\n"); + UOG_PORTSC1 &= ~PORTSC_PHCD; + low_power_enable_src &= ~source; + } +} +#else +static void __phy_lowpower_suspend(bool enable, int source) +{ + if (enable) { + UOG_PORTSC1 |= PORTSC_PHCD; + }else { + UOG_PORTSC1 &= ~PORTSC_PHCD; } } +#endif + +#ifdef CONFIG_USB_EHCI_ARC_OTG +static void _host_phy_lowpower_suspend(bool enable) +{ + __phy_lowpower_suspend(enable, ENABLED_BY_HOST); +} +#endif + +#ifdef CONFIG_USB_GADGET_ARC +static void _device_phy_lowpower_suspend(bool enable) +{ + __phy_lowpower_suspend(enable, ENABLED_BY_DEVICE); +} +#endif static void usbotg_clock_gate(bool on) { struct clk *usb_clk; + if (cpu_is_mx50()) { + if (on) { + usb_clk = clk_get(NULL, "usb_ahb_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + + usb_clk = clk_get(NULL, "usb_phy1_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + } else { + usb_clk = clk_get(NULL, "usb_phy1_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + + usb_clk = clk_get(NULL, "usb_ahb_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + } + return; + } + if (on) { usb_clk = clk_get(NULL, "usb_ahb_clk"); clk_enable(usb_clk); @@ -140,6 +271,13 @@ static void usbotg_clock_gate(bool on) } #endif +void mx5_set_otghost_vbus_func(driver_vbus_func driver_vbus) +{ +#if defined(CONFIG_USB_OTG) || defined(CONFIG_USB_EHCI_ARC_OTG) || defined(CONFIG_USB_GADGET_ARC) + dr_utmi_config.platform_driver_vbus = driver_vbus; +#endif +} + void __init mx5_usb_dr_init(void) { #ifdef CONFIG_USB_OTG @@ -149,11 +287,15 @@ void __init mx5_usb_dr_init(void) #endif #ifdef CONFIG_USB_EHCI_ARC_OTG dr_utmi_config.operating_mode = DR_HOST_MODE; + dr_utmi_config.wake_up_enable = _host_wakeup_enable; + dr_utmi_config.phy_lowpower_suspend = _host_phy_lowpower_suspend; platform_device_add_data(&mxc_usbdr_host_device, &dr_utmi_config, sizeof(dr_utmi_config)); platform_device_register(&mxc_usbdr_host_device); #endif #ifdef CONFIG_USB_GADGET_ARC dr_utmi_config.operating_mode = DR_UDC_MODE; + dr_utmi_config.wake_up_enable = _device_wakeup_enable; + dr_utmi_config.phy_lowpower_suspend = _device_phy_lowpower_suspend; platform_device_add_data(&mxc_usbdr_udc_device, &dr_utmi_config, sizeof(dr_utmi_config)); platform_device_register(&mxc_usbdr_udc_device); #endif diff --git a/arch/arm/mach-mx5/usb_h1.c b/arch/arm/mach-mx5/usb_h1.c index 7f0c463d45c1..3c53ed8901ae 100644 --- a/arch/arm/mach-mx5/usb_h1.c +++ b/arch/arm/mach-mx5/usb_h1.c @@ -17,14 +17,15 @@ #include <linux/clk.h> #include <linux/platform_device.h> #include <linux/fsl_devices.h> +#include <asm/delay.h> #include <mach/arc_otg.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include "usb.h" #include "iomux.h" #include "mx51_pins.h" - - +//#undef pr_debug +//#define pr_debug printk /* * USB Host1 HS port */ @@ -70,25 +71,67 @@ static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable) { if (enable) USBCTRL |= UCTRL_H1WIE; - else + else { USBCTRL &= ~UCTRL_H1WIE; + /* The interrupt must be disabled for at least 3 + * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ + udelay(100); + } +} + +static void _phy_lowpower_suspend(bool enable) +{ + if (enable) { + UH1_PORTSC1 |= PORTSC_PHCD; + }else { + UH1_PORTSC1 &= ~PORTSC_PHCD; + } } static void usbotg_clock_gate(bool on) { - struct clk *usboh3_clk = clk_get(NULL, "usboh3_clk"); - struct clk *usb_ahb_clk = clk_get(NULL, "usb_ahb_clk"); + struct clk *usb_clk; + if (cpu_is_mx50()) { + if (on) { + usb_clk = clk_get(NULL, "usb_ahb_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + + } else { + usb_clk = clk_get(NULL, "usb_ahb_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + } + return; + } + if (cpu_is_mx53()) { + usb_clk = clk_get(NULL, "usb_phy2_clk"); + if (on) { + clk_enable(usb_clk); + } else { + clk_disable(usb_clk); + } + clk_put(usb_clk); + } if (on) { - clk_enable(usb_ahb_clk); - clk_enable(usboh3_clk); + usb_clk = clk_get(NULL, "usb_ahb_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + } else { - clk_disable(usboh3_clk); - clk_disable(usb_ahb_clk); - } + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); - clk_put(usboh3_clk); - clk_put(usb_ahb_clk); + usb_clk = clk_get(NULL, "usb_ahb_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + } } static int fsl_usb_host_init_ext(struct platform_device *pdev) @@ -109,6 +152,10 @@ static int fsl_usb_host_init_ext(struct platform_device *pdev) usb_clk = clk_get(NULL, "usb_utmi_clk"); clk_disable(usb_clk); clk_put(usb_clk); + } else if (cpu_is_mx50()) { + usb_clk = clk_get(NULL, "usb_phy2_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); } ret = fsl_usb_host_init(pdev); @@ -143,7 +190,12 @@ static void fsl_usb_host_uninit_ext(struct fsl_usb2_platform_data *pdata) usb_clk = clk_get(&pdata->pdev->dev, "usb_phy2_clk"); clk_disable(usb_clk); clk_put(usb_clk); + } else if (cpu_is_mx50()) { + usb_clk = clk_get(NULL, "usb_phy2_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); } + fsl_usb_host_uninit(pdata); } @@ -156,9 +208,14 @@ static struct fsl_usb2_platform_data usbh1_config = { .power_budget = 500, /* 500 mA max power */ .wake_up_enable = _wake_up_enable, .usb_clock_for_pm = usbotg_clock_gate, + .phy_lowpower_suspend = _phy_lowpower_suspend, .transceiver = "utmi", }; +void mx5_set_host1_vbus_func(driver_vbus_func driver_vbus) +{ + usbh1_config.platform_driver_vbus = driver_vbus; +} void __init mx5_usbh1_init(void) { if (cpu_is_mx51()) { diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c index 911908164efb..d2b51a1357c1 100644 --- a/arch/arm/plat-mxc/clock.c +++ b/arch/arm/plat-mxc/clock.c @@ -4,7 +4,7 @@ * Copyright (C) 2004 - 2005 Nokia corporation * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> - * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2007-2010 Freescale Semiconductor, Inc. * Copyright 2008 Juergen Beisert, kernel@pengutronix.de * * This program is free software; you can redistribute it and/or @@ -173,14 +173,8 @@ int clk_enable(struct clk *clk) if (clk == NULL || IS_ERR(clk)) return -EINVAL; - spin_lock_irqsave(&clockfw_lock, flags); - - ret = __clk_enable(clk); - - spin_unlock_irqrestore(&clockfw_lock, flags); - if ((clk->flags & CPU_FREQ_TRIG_UPDATE) - && (clk_get_usecount(clk) == 1)) { + && (clk_get_usecount(clk) == 0)) { #if (defined(CONFIG_ARCH_MX5) || defined(CONFIG_ARCH_MX37)) if (low_freq_bus_used() && !low_bus_freq_mode) set_low_bus_freq(); @@ -200,6 +194,13 @@ int clk_enable(struct clk *clk) #endif } + + spin_lock_irqsave(&clockfw_lock, flags); + + ret = __clk_enable(clk); + + spin_unlock_irqrestore(&clockfw_lock, flags); + return ret; } EXPORT_SYMBOL(clk_enable); @@ -228,12 +229,12 @@ void clk_disable(struct clk *clk) set_low_bus_freq(); else { if (!high_bus_freq_mode) { - /* Currently at ow or medium set point, + /* Currently at low or medium set point, * need to set to high setpoint */ set_high_bus_freq(0); } else if (high_bus_freq_mode || low_bus_freq_mode) { - /* Currently at ow or high set point, + /* Currently at low or high set point, * need to set to medium setpoint */ set_high_bus_freq(0); diff --git a/arch/arm/plat-mxc/dptc.c b/arch/arm/plat-mxc/dptc.c index 6b7f5599909e..a26fd9b8d516 100644 --- a/arch/arm/plat-mxc/dptc.c +++ b/arch/arm/plat-mxc/dptc.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -67,6 +67,7 @@ enum { struct device *dev_data0; struct device *dev_data1; +struct dptc_device *dptc_device_data; /*! * In case the MXC device has multiple DPTC modules, this structure is used to @@ -89,6 +90,8 @@ struct dptc_device { int curr_wp; /* DPTC vai bits */ u32 ptvai; + /* The base address of the DPTC */ + void __iomem *membase; /* The interrupt number used by the DPTC device */ int irq; /* DPTC platform data pointer */ @@ -104,13 +107,13 @@ static void update_dptc_wp(struct dptc_device *drv_data, u32 wp) voltage_uV = dptc_data->dptc_wp_allfreq[wp].voltage * 1000; __raw_writel(dptc_data->dptc_wp_allfreq[wp].dcvr0, - dptc_data->dcvr0_reg_addr); + drv_data->membase + dptc_data->dcvr0_reg_addr); __raw_writel(dptc_data->dptc_wp_allfreq[wp].dcvr1, - dptc_data->dcvr0_reg_addr + 0x4); + drv_data->membase + dptc_data->dcvr0_reg_addr + 0x4); __raw_writel(dptc_data->dptc_wp_allfreq[wp].dcvr2, - dptc_data->dcvr0_reg_addr + 0x8); + drv_data->membase + dptc_data->dcvr0_reg_addr + 0x8); __raw_writel(dptc_data->dptc_wp_allfreq[wp].dcvr3, - dptc_data->dcvr0_reg_addr + 0xC); + drv_data->membase + dptc_data->dcvr0_reg_addr + 0xC); /* Set the voltage */ ret = regulator_set_voltage(drv_data->dptc_reg, voltage_uV, voltage_uV); @@ -130,7 +133,8 @@ static irqreturn_t dptc_irq(int irq, void *dev_id) struct device *dev = dev_id; struct dptc_device *drv_data = dev->driver_data; struct mxc_dptc_data *dptc_data = dev->platform_data; - u32 dptccr = __raw_readl(dptc_data->dptccr_reg_addr); + u32 dptccr = __raw_readl(drv_data->membase + + dptc_data->dptccr_reg_addr); u32 gpc_cntr = __raw_readl(dptc_data->gpc_cntr_reg_addr); gpc_cntr = (gpc_cntr & dptc_data->dptccr); @@ -145,7 +149,8 @@ static irqreturn_t dptc_irq(int irq, void *dev_id) dptccr = (dptccr & ~(dptc_data->dptc_enable_bit)) | (dptc_data->irq_mask); dptccr = (dptccr & ~(dptc_data->dptc_nvcr_bit)); - __raw_writel(dptccr, dptc_data->dptccr_reg_addr); + __raw_writel(dptccr, drv_data->membase + + dptc_data->dptccr_reg_addr); if (drv_data->turbo_mode_active == 1) schedule_delayed_work(&drv_data->dptc_work, 0); @@ -162,7 +167,8 @@ static void dptc_workqueue_handler(struct work_struct *work1) struct dptc_device *drv_data = container_of(dptc_work_tmp, struct dptc_device, dptc_work); struct mxc_dptc_data *dptc_data = drv_data->dptc_platform_data; - u32 dptccr = __raw_readl(dptc_data->dptccr_reg_addr); + u32 dptccr = __raw_readl(drv_data->membase + + dptc_data->dptccr_reg_addr); switch (drv_data->ptvai) { case DPTC_PTVAI_DECREASE: @@ -193,7 +199,7 @@ static void dptc_workqueue_handler(struct work_struct *work1) /* Enable DPTC and unmask its interrupt */ dptccr = (dptccr & ~(dptc_data->irq_mask)) | dptc_data->dptc_nvcr_bit | dptc_data->dptc_enable_bit; - __raw_writel(dptccr, dptc_data->dptccr_reg_addr); + __raw_writel(dptccr, drv_data->membase + dptc_data->dptccr_reg_addr); } /* Start DPTC unconditionally */ @@ -228,12 +234,12 @@ static int start_dptc(struct device *dev) dptc_data->gpc_cntr_reg_addr); } - dptccr = __raw_readl(dptc_data->dptccr_reg_addr); + dptccr = __raw_readl(drv_data->membase + dptc_data->dptccr_reg_addr); /* Enable DPTC and unmask its interrupt */ dptccr = ((dptccr & ~(dptc_data->irq_mask)) | dptc_data->enable_config); - __raw_writel(dptccr, dptc_data->dptccr_reg_addr); + __raw_writel(dptccr, drv_data->membase + dptc_data->dptccr_reg_addr); spin_unlock_irqrestore(&drv_data->lock, flags); @@ -257,13 +263,13 @@ static void stop_dptc(struct device *dev) struct dptc_device *drv_data = dev->driver_data; u32 dptccr; - dptccr = __raw_readl(dptc_data->dptccr_reg_addr); + dptccr = __raw_readl(drv_data->membase + dptc_data->dptccr_reg_addr); /* disable DPTC and mask its interrupt */ dptccr = ((dptccr & ~(dptc_data->dptc_enable_bit)) | dptc_data->irq_mask) & (~dptc_data->dptc_nvcr_bit); - __raw_writel(dptccr, dptc_data->dptccr_reg_addr); + __raw_writel(dptccr, drv_data->membase + dptc_data->dptccr_reg_addr); /* Restore Turbo Mode voltage to highest wp */ update_dptc_wp(drv_data, 0); @@ -304,12 +310,12 @@ void dptc_suspend(int id) if (!drv_data->dptc_is_active) return; - dptccr = __raw_readl(dptc_data->dptccr_reg_addr); + dptccr = __raw_readl(drv_data->membase + dptc_data->dptccr_reg_addr); /* Disable DPTC and mask its interrupt */ dptccr = (dptccr & ~(dptc_data->dptc_enable_bit)) | dptc_data->irq_mask; - __raw_writel(dptccr, dptc_data->dptccr_reg_addr); + __raw_writel(dptccr, drv_data->membase + dptc_data->dptccr_reg_addr); } EXPORT_SYMBOL(dptc_suspend); @@ -344,20 +350,20 @@ void dptc_resume(int id) return; __raw_writel(dptc_data->dptc_wp_allfreq[0].dcvr0, - dptc_data->dcvr0_reg_addr); + drv_data->membase + dptc_data->dcvr0_reg_addr); __raw_writel(dptc_data->dptc_wp_allfreq[0].dcvr1, - dptc_data->dcvr0_reg_addr + 0x4); + drv_data->membase + dptc_data->dcvr0_reg_addr + 0x4); __raw_writel(dptc_data->dptc_wp_allfreq[0].dcvr2, - dptc_data->dcvr0_reg_addr + 0x8); + drv_data->membase + dptc_data->dcvr0_reg_addr + 0x8); __raw_writel(dptc_data->dptc_wp_allfreq[0].dcvr3, - dptc_data->dcvr0_reg_addr + 0xC); + drv_data->membase + dptc_data->dcvr0_reg_addr + 0xC); - dptccr = __raw_readl(dptc_data->dptccr_reg_addr); + dptccr = __raw_readl(drv_data->membase + dptc_data->dptccr_reg_addr); /* Enable DPTC and unmask its interrupt */ dptccr = (dptccr & ~(dptc_data->irq_mask)) | dptc_data->dptc_enable_bit; - __raw_writel(dptccr, dptc_data->dptccr_reg_addr); + __raw_writel(dptccr, drv_data->membase + dptc_data->dptccr_reg_addr); } EXPORT_SYMBOL(dptc_resume); @@ -426,7 +432,6 @@ static DEVICE_ATTR(enable, 0644, dptc_show, dptc_store); */ static int __devinit mxc_dptc_probe(struct platform_device *pdev) { - struct dptc_device *dptc_device_data; int ret = 0; struct resource *res; u32 dptccr = 0; @@ -449,13 +454,16 @@ static int __devinit mxc_dptc_probe(struct platform_device *pdev) goto err1; } + dptc_device_data->membase = ioremap(res->start, + res->end - res->start + 1); + /* * Request the DPTC interrupt */ dptc_device_data->irq = platform_get_irq(pdev, 0); if (dptc_device_data->irq < 0) { ret = dptc_device_data->irq; - goto err1; + goto err2; } ret = @@ -463,7 +471,7 @@ static int __devinit mxc_dptc_probe(struct platform_device *pdev) pdev->name, &pdev->dev); if (ret) { printk(KERN_ERR "DPTC: Unable to attach to DPTC interrupt\n"); - goto err1; + goto err2; } dptc_device_data->curr_wp = 0; @@ -471,7 +479,8 @@ static int __devinit mxc_dptc_probe(struct platform_device *pdev) dptc_device_data->turbo_mode_active = 0; dptc_device_data->ptvai = 0; - dptccr = __raw_readl(dptc_data->dptccr_reg_addr); + dptccr = __raw_readl(dptc_device_data->membase + + dptc_data->dptccr_reg_addr); printk(KERN_INFO "DPTC mxc_dptc_probe()\n"); @@ -487,32 +496,33 @@ static int __devinit mxc_dptc_probe(struct platform_device *pdev) else printk(KERN_ERR "DPTC: Pointer to DPTC table is NULL\ not started\n"); - goto err1; + goto err3; } dptc_device_data->dptc_reg = regulator_get(NULL, dptc_data->reg_id); if (IS_ERR(dptc_device_data->dptc_reg)) { clk_put(dptc_device_data->dptc_clk); printk(KERN_ERR "%s: failed to get regulator\n", __func__); - goto err1; + goto err3; } INIT_DELAYED_WORK(&dptc_device_data->dptc_work, dptc_workqueue_handler); /* Enable Reference Circuits */ dptccr = (dptccr & ~(dptc_data->dcr_mask)) | dptc_data->init_config; - __raw_writel(dptccr, dptc_data->dptccr_reg_addr); + __raw_writel(dptccr, dptc_device_data->membase + + dptc_data->dptccr_reg_addr); ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_enable.attr); if (ret) { printk(KERN_ERR "DPTC: Unable to register sysdev entry for dptc"); - goto err1; + goto err3; } if (ret != 0) { printk(KERN_ERR "DPTC: Unable to start"); - goto err1; + goto err3; } dptc_device_data->dptc_clk = clk_get(NULL, dptc_data->clk_id); @@ -529,6 +539,10 @@ static int __devinit mxc_dptc_probe(struct platform_device *pdev) return 0; +err3: + free_irq(dptc_device_data->irq, &pdev->dev); +err2: + iounmap(dptc_device_data->membase); err1: dev_err(&pdev->dev, "Failed to probe DPTC\n"); kfree(dptc_device_data); @@ -607,6 +621,10 @@ static int __init dptc_init(void) static void __exit dptc_cleanup(void) { + free_irq(dptc_device_data->irq, NULL); + iounmap(dptc_device_data->membase); + kfree(dptc_device_data); + /* Unregister the device structure */ platform_driver_unregister(&mxc_dptc_driver); diff --git a/arch/arm/plat-mxc/dvfs_core.c b/arch/arm/plat-mxc/dvfs_core.c index 43d0a3a8adeb..143bc07834ed 100644 --- a/arch/arm/plat-mxc/dvfs_core.c +++ b/arch/arm/plat-mxc/dvfs_core.c @@ -135,18 +135,19 @@ static void dvfs_load_config(int set_point) reg |= dvfs_core_setpoint[set_point].downthr << MXC_DVFSTHRS_DNTHR_OFFSET; reg |= dvfs_core_setpoint[set_point].panicthr; - __raw_writel(reg, dvfs_data->dvfs_thrs_reg_addr); + __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_THRS); reg = 0; reg |= dvfs_core_setpoint[set_point].downcnt << MXC_DVFSCOUN_DNCNT_OFFSET; reg |= dvfs_core_setpoint[set_point].upcnt << MXC_DVFSCOUN_UPCNT_OFFSET; - __raw_writel(reg, dvfs_data->dvfs_coun_reg_addr); + __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_COUN); /* Set EMAC value */ __raw_writel((dvfs_core_setpoint[set_point].emac << MXC_DVFSEMAC_EMAC_OFFSET), - dvfs_data->dvfs_emac_reg_addr); + dvfs_data->membase + + MXC_DVFSCORE_EMAC); } @@ -187,14 +188,14 @@ static int set_cpu_freq(int wp) } spin_lock_irqsave(&mxc_dvfs_core_lock, flags); /* PLL_RELOCK, set ARM_FREQ_SHIFT_DIVIDER */ - reg = __raw_readl(dvfs_data->ccm_cdcr_reg_addr); + reg = __raw_readl(ccm_base + dvfs_data->ccm_cdcr_offset); reg &= 0xFFFFFFFB; - __raw_writel(reg, dvfs_data->ccm_cdcr_reg_addr); + __raw_writel(reg, ccm_base + dvfs_data->ccm_cdcr_offset); setup_pll(); /* START the GPC main control FSM */ /* set VINC */ - reg = __raw_readl(dvfs_data->gpc_vcr_reg_addr); + reg = __raw_readl(gpc_base + dvfs_data->gpc_vcr_offset); reg &= ~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK | MXC_GPCVCR_VCNT_MASK); @@ -202,18 +203,19 @@ static int set_cpu_freq(int wp) reg |= 1 << MXC_GPCVCR_VINC_OFFSET; reg |= (1 << MXC_GPCVCR_VCNTU_OFFSET) | - (1 << MXC_GPCVCR_VCNT_OFFSET); - __raw_writel(reg, dvfs_data->gpc_vcr_reg_addr); + (1 << MXC_GPCVCR_VCNT_OFFSET); + __raw_writel(reg, gpc_base + dvfs_data->gpc_vcr_offset); - reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr); + reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset); reg &= ~(MXC_GPCCNTR_ADU_MASK | MXC_GPCCNTR_FUPD_MASK); reg |= MXC_GPCCNTR_FUPD; reg |= MXC_GPCCNTR_ADU; - __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); + __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset); reg |= MXC_GPCCNTR_STRT; - __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); - while (__raw_readl(dvfs_data->gpc_cntr_reg_addr) & 0x4000) + __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset); + while (__raw_readl(gpc_base + dvfs_data->gpc_cntr_offset) + & 0x4000) udelay(10); spin_unlock_irqrestore(&mxc_dvfs_core_lock, flags); @@ -234,13 +236,13 @@ static int set_cpu_freq(int wp) /* Change arm_podf only */ /* set ARM_FREQ_SHIFT_DIVIDER */ - reg = __raw_readl(dvfs_data->ccm_cdcr_reg_addr); + reg = __raw_readl(ccm_base + dvfs_data->ccm_cdcr_offset); reg &= 0xFFFFFFFB; reg |= 1 << 2; - __raw_writel(reg, dvfs_data->ccm_cdcr_reg_addr); + __raw_writel(reg, ccm_base + dvfs_data->ccm_cdcr_offset); /* Get ARM_PODF */ - reg = __raw_readl(dvfs_data->ccm_cacrr_reg_addr); + reg = __raw_readl(ccm_base + dvfs_data->ccm_cacrr_offset); arm_podf = reg & 0x07; if (podf == arm_podf) { printk(KERN_DEBUG @@ -268,37 +270,38 @@ static int set_cpu_freq(int wp) reg &= 0xFFFFFFF8; reg |= arm_podf; - reg1 = __raw_readl(dvfs_data->ccm_cdhipr_reg_addr); + reg1 = __raw_readl(ccm_base + dvfs_data->ccm_cdhipr_offset); if ((reg1 & 0x00010000) == 0) - __raw_writel(reg, dvfs_data->ccm_cacrr_reg_addr); + __raw_writel(reg, + ccm_base + dvfs_data->ccm_cacrr_offset); else { printk(KERN_DEBUG "ARM_PODF still in busy!!!!\n"); return 0; } /* START the GPC main control FSM */ - reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr); + reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset); reg |= MXC_GPCCNTR_FUPD; /* ADU=1, select ARM domain */ reg |= MXC_GPCCNTR_ADU; - __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); + __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset); /* set VINC */ - reg = __raw_readl(dvfs_data->gpc_vcr_reg_addr); + reg = __raw_readl(gpc_base + dvfs_data->gpc_vcr_offset); reg &= ~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK | MXC_GPCVCR_VCNT_MASK); reg |= (1 << MXC_GPCVCR_VCNTU_OFFSET) | (100 << MXC_GPCVCR_VCNT_OFFSET) | (vinc << MXC_GPCVCR_VINC_OFFSET); - __raw_writel(reg, dvfs_data->gpc_vcr_reg_addr); + __raw_writel(reg, gpc_base + dvfs_data->gpc_vcr_offset); - reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr); + reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset); reg &= (~(MXC_GPCCNTR_ADU | MXC_GPCCNTR_FUPD)); reg |= MXC_GPCCNTR_ADU | MXC_GPCCNTR_FUPD | MXC_GPCCNTR_STRT; - __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); + __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset); /* Wait for arm podf Enable */ - while ((__raw_readl(dvfs_data->gpc_cntr_reg_addr) & + while ((__raw_readl(gpc_base + dvfs_data->gpc_cntr_offset) & MXC_GPCCNTR_STRT) == MXC_GPCCNTR_STRT) { printk(KERN_DEBUG "Waiting arm_podf enabled!\n"); udelay(10); @@ -317,9 +320,9 @@ static int set_cpu_freq(int wp) propagate_rate(pll1_sw_clk); /* Clear the ARM_FREQ_SHIFT_DIVIDER */ - reg = __raw_readl(dvfs_data->ccm_cdcr_reg_addr); + reg = __raw_readl(ccm_base + dvfs_data->ccm_cdcr_offset); reg &= 0xFFFFFFFB; - __raw_writel(reg, dvfs_data->ccm_cdcr_reg_addr); + __raw_writel(reg, ccm_base + dvfs_data->ccm_cdcr_offset); } #if defined(CONFIG_CPU_FREQ_IMX) cpufreq_trig_needed = 1; @@ -344,23 +347,23 @@ static int start_dvfs(void) dvfs_load_config(0); /* config reg GPC_CNTR */ - reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr); + reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset); reg &= ~MXC_GPCCNTR_GPCIRQM; /* GPCIRQ=1, select ARM IRQ */ reg |= MXC_GPCCNTR_GPCIRQ_ARM; /* ADU=1, select ARM domain */ reg |= MXC_GPCCNTR_ADU; - __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); + __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset); /* Set PREDIV bits */ - reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); reg = (reg & ~(dvfs_data->prediv_mask)); reg |= (dvfs_data->prediv_val) << (dvfs_data->prediv_offset); - __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); + __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); /* Enable DVFS interrupt */ - reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); /* FSVAIM=0 */ reg = (reg & ~MXC_DVFSCNTR_FSVAIM); /* Set MAXF, MINF */ @@ -376,12 +379,12 @@ static int start_dvfs(void) /* Set DIV3CK */ reg = (reg & ~(dvfs_data->div3ck_mask)); reg |= (dvfs_data->div3ck_val) << (dvfs_data->div3ck_offset); - __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); + __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); /* Enable DVFS */ - reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); reg |= MXC_DVFSCNTR_DVFEN; - __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); + __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); dvfs_core_is_active = 1; @@ -416,20 +419,20 @@ static irqreturn_t dvfs_irq(int irq, void *dev_id) u32 reg; /* Check if DVFS0 (ARM) id requesting for freqency/voltage update */ - if ((__raw_readl(dvfs_data->gpc_cntr_reg_addr) & MXC_GPCCNTR_DVFS0CR) == - 0) + if ((__raw_readl(gpc_base + dvfs_data->gpc_cntr_offset) + & MXC_GPCCNTR_DVFS0CR) == 0) return IRQ_NONE; /* Mask DVFS irq */ - reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); /* FSVAIM=1 */ reg |= MXC_DVFSCNTR_FSVAIM; - __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); + __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); /* Mask GPC1 irq */ - reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr); + reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset); reg |= MXC_GPCCNTR_GPCIRQM | 0x1000000; - __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); + __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset); schedule_delayed_work(&dvfs_core_handler, 0); return IRQ_HANDLED; @@ -448,7 +451,7 @@ static void dvfs_core_work_handler(struct work_struct *work) low_freq_bus_ready = low_freq_bus_used(); /* Check DVFS frequency adjustment interrupt status */ - reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); fsvai = (reg & MXC_DVFSCNTR_FSVAI_MASK) >> MXC_DVFSCNTR_FSVAI_OFFSET; /* Check FSVAI, FSVAI=0 is error */ if (fsvai == FSVAI_FREQ_NOCHANGE) { @@ -520,7 +523,7 @@ static void dvfs_core_work_handler(struct work_struct *work) END: /* Set MAXF, MINF */ - reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); reg = (reg & ~(MXC_DVFSCNTR_MAXF_MASK | MXC_DVFSCNTR_MINF_MASK)); reg |= maxf << MXC_DVFSCNTR_MAXF_OFFSET; reg |= minf << MXC_DVFSCNTR_MINF_OFFSET; @@ -532,11 +535,11 @@ END: /* Set MAXF, MINF */ /* LBFL=1 */ reg = (reg & ~MXC_DVFSCNTR_LBFL); reg |= MXC_DVFSCNTR_LBFL; - __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); + __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); /*Unmask GPC1 IRQ */ - reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr); + reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset); reg &= ~MXC_GPCCNTR_GPCIRQM; - __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); + __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset); #if defined(CONFIG_CPU_FREQ_IMX) if (cpufreq_trig_needed == 1) { @@ -559,10 +562,12 @@ static void stop_dvfs(void) if (dvfs_core_is_active) { /* Mask dvfs irq, disable DVFS */ - reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + reg = __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_CNTR); /* FSVAIM=1 */ reg |= MXC_DVFSCNTR_FSVAIM; - __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); + __raw_writel(reg, dvfs_data->membase + + MXC_DVFSCORE_CNTR); curr_wp = 0; if (!high_bus_freq_mode) @@ -580,9 +585,11 @@ static void stop_dvfs(void) } spin_lock_irqsave(&mxc_dvfs_core_lock, flags); - reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + reg = __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_CNTR); reg = (reg & ~MXC_DVFSCNTR_DVFEN); - __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); + __raw_writel(reg, dvfs_data->membase + + MXC_DVFSCORE_CNTR); spin_unlock_irqrestore(&mxc_dvfs_core_lock, flags); @@ -610,39 +617,56 @@ void dump_dvfs_core_regs() printk(KERN_DEBUG "diff = %d\n", diff); printk(KERN_INFO "THRS = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS)); printk(KERN_INFO "COUNT = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x04)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x04)); printk(KERN_INFO "SIG1 = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x08)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x08)); printk(KERN_INFO "SIG0 = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x0c)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x0c)); printk(KERN_INFO "GPC0 = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x10)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x10)); printk(KERN_INFO "GPC1 = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x14)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x14)); printk(KERN_INFO "GPBT = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x18)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x18)); printk(KERN_INFO "EMAC = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x1c)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x1c)); printk(KERN_INFO "CNTR = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x20)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x20)); printk(KERN_INFO "LTR0_0 = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x24)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x24)); printk(KERN_INFO "LTR0_1 = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x28)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x28)); printk(KERN_INFO "LTR1_0 = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x2c)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x2c)); printk(KERN_DEBUG "LTR1_1 = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x30)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x30)); printk(KERN_INFO "PT0 = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x34)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x34)); printk(KERN_INFO "PT1 = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x38)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x38)); printk(KERN_INFO "PT2 = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x3c)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x3c)); printk(KERN_INFO "PT3 = 0x%08x\n", - __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x40)); + __raw_readl(dvfs_data->membase + + MXC_DVFSCORE_THRS + 0x40)); } static ssize_t downthreshold_show(struct device *dev, @@ -741,7 +765,6 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev) { int err = 0; struct resource *res; - int irq; printk(KERN_INFO "mxc_dvfs_core_probe\n"); dvfs_dev = &pdev->dev; @@ -780,22 +803,25 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev) err = -ENODEV; goto err1; } - + dvfs_data->membase = ioremap(res->start, res->end - res->start + 1); /* * Request the DVFS interrupt */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - err = irq; - goto err1; + dvfs_data->irq = platform_get_irq(pdev, 0); + if (dvfs_data->irq < 0) { + err = dvfs_data->irq; + goto err2; } /* request the DVFS interrupt */ - err = request_irq(irq, dvfs_irq, IRQF_SHARED, "dvfs", dvfs_dev); - if (err) + err = request_irq(dvfs_data->irq, dvfs_irq, IRQF_SHARED, "dvfs", + dvfs_dev); + if (err) { printk(KERN_ERR "DVFS: Unable to attach to DVFS interrupt,err = %d", err); + goto err2; + } clk_enable(dvfs_clk); err = init_dvfs_controller(); @@ -809,14 +835,14 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev) if (err) { printk(KERN_ERR "DVFS: Unable to register sysdev entry for DVFS"); - return err; + goto err3; } err = sysfs_create_file(&dvfs_dev->kobj, &dev_attr_show_regs.attr); if (err) { printk(KERN_ERR "DVFS: Unable to register sysdev entry for DVFS"); - return err; + goto err3; } @@ -824,14 +850,14 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev) if (err) { printk(KERN_ERR "DVFS: Unable to register sysdev entry for DVFS"); - return err; + goto err3; } err = sysfs_create_file(&dvfs_dev->kobj, &dev_attr_down_count.attr); if (err) { printk(KERN_ERR "DVFS: Unable to register sysdev entry for DVFS"); - return err; + goto err3; } /* Set the current working point. */ @@ -844,7 +870,10 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev) #endif return err; - +err3: + free_irq(dvfs_data->irq, dvfs_dev); +err2: + iounmap(dvfs_data->membase); err1: dev_err(&pdev->dev, "Failed to probe DVFS CORE\n"); return err; @@ -914,13 +943,15 @@ static void __exit dvfs_cleanup(void) stop_dvfs(); /* release the DVFS interrupt */ - free_irq(MXC_INT_GPC1, NULL); + free_irq(dvfs_data->irq, dvfs_dev); sysfs_remove_file(&dvfs_dev->kobj, &dev_attr_enable.attr); /* Unregister the device structure */ platform_driver_unregister(&mxc_dvfs_core_driver); + iounmap(ccm_base); + iounmap(dvfs_data->membase); clk_put(cpu_clk); clk_put(dvfs_clk); diff --git a/arch/arm/plat-mxc/dvfs_per.c b/arch/arm/plat-mxc/dvfs_per.c index 43d0dfccff50..e57f8a2fefcd 100644 --- a/arch/arm/plat-mxc/dvfs_per.c +++ b/arch/arm/plat-mxc/dvfs_per.c @@ -51,15 +51,14 @@ #endif /* DVFS PER */ -static void __iomem *dvfs_per_base; -#define MXC_DVFS_PER_LTR0 (dvfs_per_base) -#define MXC_DVFS_PER_LTR1 (dvfs_per_base + 0x04) -#define MXC_DVFS_PER_LTR2 (dvfs_per_base + 0x08) -#define MXC_DVFS_PER_LTR3 (dvfs_per_base + 0x0C) -#define MXC_DVFS_PER_LTBR0 (dvfs_per_base + 0x10) -#define MXC_DVFS_PER_LTBR1 (dvfs_per_base + 0x14) -#define MXC_DVFS_PER_PMCR0 (dvfs_per_base + 0x18) -#define MXC_DVFS_PER_PMCR1 (dvfs_per_base + 0x1C) +#define MXC_DVFS_PER_LTR0 0x00 +#define MXC_DVFS_PER_LTR1 0x04 +#define MXC_DVFS_PER_LTR2 0x08 +#define MXC_DVFS_PER_LTR3 0x0C +#define MXC_DVFS_PER_LTBR0 0x10 +#define MXC_DVFS_PER_LTBR1 0x14 +#define MXC_DVFS_PER_PMCR0 0x18 +#define MXC_DVFS_PER_PMCR1 0x1C #define DRIVER_NAME "DVFSPER" #define DVFS_PER_DEBUG 0 @@ -134,16 +133,16 @@ static void dvfs_per_load_config(void) { u32 reg; - reg = __raw_readl(MXC_DVFS_PER_LTR0); + reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR0); reg &= ~MXC_DVFSLTR0_UPTHR_MASK; reg &= ~MXC_DVFSLTR0_DNTHR_MASK; reg |= dvfs_per_setpoint[cur_setpoint].upthr << MXC_DVFSLTR0_UPTHR_OFFSET; reg |= dvfs_per_setpoint[cur_setpoint].downthr << MXC_DVFSLTR0_DNTHR_OFFSET; - __raw_writel(reg, MXC_DVFS_PER_LTR0); + __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR0); - reg = __raw_readl(MXC_DVFS_PER_LTR1); + reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR1); reg &= ~MXC_DVFSLTR1_PNCTHR_MASK; reg &= ~MXC_DVFSLTR1_DNCNT_MASK; reg &= ~MXC_DVFSLTR1_UPCNT_MASK; @@ -153,11 +152,11 @@ static void dvfs_per_load_config(void) MXC_DVFSLTR1_UPCNT_OFFSET; reg |= dvfs_per_setpoint[cur_setpoint].panicthr << MXC_DVFSLTR1_PNCTHR_OFFSET; - __raw_writel(reg, MXC_DVFS_PER_LTR1); + __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR1); reg = dvfs_per_setpoint[cur_setpoint].emac << MXC_DVFSLTR2_EMAC_OFFSET; - __raw_writel(reg, MXC_DVFS_PER_LTR2); + __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR2); } /*! @@ -175,29 +174,29 @@ static int init_dvfs_per_controller(void) { u32 reg; - reg = __raw_readl(MXC_DVFS_PER_LTR0); + reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR0); /* DIV3CLK */ reg &= ~dvfsper_plt_data->div3_mask; reg |= (dvfsper_plt_data->div3_div << dvfsper_plt_data->div3_offset); - __raw_writel(reg, MXC_DVFS_PER_LTR0); + __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR0); - reg = __raw_readl(MXC_DVFS_PER_LTR1); + reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR1); /* Set load tracking buffer register source */ reg &= ~MXC_DVFSLTR1_LTBRSR; reg |= MXC_DVFSLTR1_LTBRSR; reg &= ~MXC_DVFSLTR1_LTBRSH; - __raw_writel(reg, MXC_DVFS_PER_LTR1); + __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR1); /* Enable all the peripheral signals, but VPU and IPU panic*/ - __raw_writel(0x30000, MXC_DVFS_PER_PMCR1); + __raw_writel(0x30000, dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR1); /* Disable weighted load tracking signals */ - __raw_writel(0, MXC_DVFS_PER_LTR3); + __raw_writel(0, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR3); - reg = __raw_readl(MXC_DVFS_PER_PMCR0); + reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0); reg &= ~MXC_DVFSPMCR0_DVFEV; reg |= MXC_DVFSPMCR0_LBMI; - __raw_writel(reg, MXC_DVFS_PER_PMCR0); + __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0); /* DVFS loading config */ dvfs_per_load_config(); @@ -220,14 +219,22 @@ static void dump_dvfs_per_regs(void) if (diff < 90000) printk(KERN_INFO "diff = %d\n", diff); - printk(KERN_INFO "LTRO = 0x%08x\n", __raw_readl(MXC_DVFS_PER_LTR0)); - printk(KERN_INFO "LTR1 = 0x%08x\n", __raw_readl(MXC_DVFS_PER_LTR1)); - printk(KERN_INFO "LTR2 = 0x%08x\n", __raw_readl(MXC_DVFS_PER_LTR2)); - printk(KERN_INFO "LTR3 = 0x%08x\n", __raw_readl(MXC_DVFS_PER_LTR3)); - printk(KERN_INFO "LBTR0 = 0x%08x\n", __raw_readl(MXC_DVFS_PER_LTBR0)); - printk(KERN_INFO "LBTR1 = 0x%08x\n", __raw_readl(MXC_DVFS_PER_LTBR1)); - printk(KERN_INFO "PMCR0 = 0x%08x\n", __raw_readl(MXC_DVFS_PER_PMCR0)); - printk(KERN_INFO "PMCR1 = 0x%08x\n", __raw_readl(MXC_DVFS_PER_PMCR1)); + printk(KERN_INFO "LTRO = 0x%08x\n", + __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR0)); + printk(KERN_INFO "LTR1 = 0x%08x\n", + __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR1)); + printk(KERN_INFO "LTR2 = 0x%08x\n", + __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR2)); + printk(KERN_INFO "LTR3 = 0x%08x\n", + __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR3)); + printk(KERN_INFO "LBTR0 = 0x%08x\n", + __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTBR0)); + printk(KERN_INFO "LBTR1 = 0x%08x\n", + __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTBR1)); + printk(KERN_INFO "PMCR0 = 0x%08x\n", + __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0)); + printk(KERN_INFO "PMCR1 = 0x%08x\n", + __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR1)); } #endif @@ -240,21 +247,22 @@ static irqreturn_t dvfs_per_irq(int irq, void *dev_id) MXC_GPCCNTR_DVFS1CR) == 0) return IRQ_NONE; /* Mask DVFS irq */ - reg = __raw_readl(MXC_DVFS_PER_PMCR0); + reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0); /* FSVAIM=1 */ reg |= MXC_DVFSPMCR0_FSVAIM; - __raw_writel(reg, MXC_DVFS_PER_PMCR0); + __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0); /* Mask GPC1 irq */ reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr); reg |= MXC_GPCCNTR_GPCIRQM | 0x1000000; __raw_writel(reg, dvfsper_plt_data->gpc_cntr_reg_addr); - reg = __raw_readl(MXC_DVFS_PER_PMCR0); + reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0); if (reg & MXC_DVFSPMCR0_LBFL) { /* clear LBFL */ reg = (reg & ~MXC_DVFSPMCR0_LBFL); reg |= MXC_DVFSPMCR0_LBFL; - __raw_writel(reg, MXC_DVFS_PER_PMCR0); + __raw_writel(reg, dvfsper_plt_data->membase + + MXC_DVFS_PER_PMCR0); } schedule_delayed_work(&dvfs_per_work, 0); return IRQ_HANDLED; @@ -269,7 +277,7 @@ static void dvfs_per_handler(struct work_struct *work) int retry = 20; /* Check DVFS frequency adjustment interrupt status */ - reg = __raw_readl(MXC_DVFS_PER_PMCR0); + reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0); fsvai = (reg & MXC_DVFSPMCR0_FSVAI_MASK) >> MXC_DVFSPMCR0_FSVAI_OFFSET; /* Check FSVAI, FSVAI=0 is error */ if (fsvai == FSVAI_FREQ_NOCHANGE) { @@ -290,9 +298,11 @@ static void dvfs_per_handler(struct work_struct *work) #ifndef DVFS_SW_WORKAROUND spin_lock_irqsave(&mxc_dvfs_per_lock, flags); - reg = __raw_readl(MXC_DVFS_PER_PMCR0); + reg = __raw_readl(dvfsper_plt_data->membase + + MXC_DVFS_PER_PMCR0); reg &= ~MXC_DVFSPMCR0_UDCS; - __raw_writel(reg, MXC_DVFS_PER_PMCR0); + __raw_writel(reg, dvfsper_plt_data->membase + + MXC_DVFS_PER_PMCR0); /* Set the peripheral divider */ reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr); @@ -367,9 +377,11 @@ static void dvfs_per_handler(struct work_struct *work) #ifndef DVFS_SW_WORKAROUND spin_lock_irqsave(&mxc_dvfs_per_lock, flags); - reg = __raw_readl(MXC_DVFS_PER_PMCR0); + reg = __raw_readl(dvfsper_plt_data->membase + + MXC_DVFS_PER_PMCR0); reg |= MXC_DVFSPMCR0_UDCS; - __raw_writel(reg, MXC_DVFS_PER_PMCR0); + __raw_writel(reg, dvfsper_plt_data->membase + + MXC_DVFS_PER_PMCR0); reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr); reg &= ~(MXC_GPCCNTR_ADU_MASK | MXC_GPCCNTR_FUPD_MASK); @@ -432,13 +444,15 @@ END: dump_dvfs_per_regs(void)(); #endif if (dvfs_per_is_active) { - reg = __raw_readl(MXC_DVFS_PER_PMCR0); + reg = __raw_readl(dvfsper_plt_data->membase + + MXC_DVFS_PER_PMCR0); /* Enable dVFS interrupt */ /* FSVAIM=0 */ reg &= ~MXC_DVFSPMCR0_FSVAI_MASK; reg |= FSVAI_FREQ_NOCHANGE; reg = (reg & ~MXC_DVFSPMCR0_FSVAIM); - __raw_writel(reg, MXC_DVFS_PER_PMCR0); + __raw_writel(reg, dvfsper_plt_data->membase + + MXC_DVFS_PER_PMCR0); /*Unmask GPC1 IRQ */ reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr); reg &= ~MXC_GPCCNTR_GPCIRQM; @@ -453,9 +467,9 @@ static void force_freq_change(void) freq_increased = 0; - reg = __raw_readl(MXC_DVFS_PER_PMCR0); + reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0); reg |= MXC_DVFSPMCR0_UDCS; - __raw_writel(reg, MXC_DVFS_PER_PMCR0); + __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0); if (cpu_is_mx51()) { /*Change the DDR freq to 133Mhz. */ @@ -513,7 +527,8 @@ static int start(void) if (bus_freq_scaling_is_active) { dvfs_per_is_paused = 1; - printk(KERN_INFO "Cannot start DVFS-PER since bus_freq_scaling is active\n"); + printk(KERN_INFO "Cannot start DVFS-PER since bus_freq_scaling\ + is active\n"); return 0; } @@ -539,7 +554,7 @@ static int start(void) reg &= ~MXC_GPCCNTR_ADU; __raw_writel(reg, dvfsper_plt_data->gpc_cntr_reg_addr); - reg = __raw_readl(MXC_DVFS_PER_PMCR0); + reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0); /* Select ARM domain */ reg |= MXC_DVFSPMCR0_DVFIS; /* Set the UDCS bit */ @@ -550,7 +565,7 @@ static int start(void) /*Set the FSVAI to no_freq_change */ reg &= ~MXC_DVFSPMCR0_FSVAI_MASK; reg |= FSVAI_FREQ_NOCHANGE << MXC_DVFSPMCR0_FSVAI_OFFSET; - __raw_writel(reg, MXC_DVFS_PER_PMCR0); + __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0); /* config reg GPC_CNTR */ reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr); @@ -560,9 +575,9 @@ static int start(void) __raw_writel(reg, dvfsper_plt_data->gpc_cntr_reg_addr); /* Enable DVFS */ - reg = __raw_readl(MXC_DVFS_PER_PMCR0); + reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0); reg |= MXC_DVFSPMCR0_DVFEN; - __raw_writel(reg, MXC_DVFS_PER_PMCR0); + __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0); dvfs_per_is_active = 1; spin_unlock_irqrestore(&mxc_dvfs_per_lock, flags); @@ -598,17 +613,21 @@ static void stop(void) spin_lock_irqsave(&mxc_dvfs_per_lock, flags); /* Mask dvfs irq, disable DVFS */ - reg = __raw_readl(MXC_DVFS_PER_PMCR0); + reg = __raw_readl(dvfsper_plt_data->membase + + MXC_DVFS_PER_PMCR0); /* FSVAIM=1 */ reg |= MXC_DVFSPMCR0_FSVAIM; - __raw_writel(reg, MXC_DVFS_PER_PMCR0); + __raw_writel(reg, dvfsper_plt_data->membase + + MXC_DVFS_PER_PMCR0); if (cur_setpoint != 0) force_freq_change(); - reg = __raw_readl(MXC_DVFS_PER_PMCR0); + reg = __raw_readl(dvfsper_plt_data->membase + + MXC_DVFS_PER_PMCR0); reg = (reg & ~MXC_DVFSPMCR0_DVFEN); - __raw_writel(reg, MXC_DVFS_PER_PMCR0); + __raw_writel(reg, dvfsper_plt_data->membase + + MXC_DVFS_PER_PMCR0); spin_unlock_irqrestore(&mxc_dvfs_per_lock, flags); clk_disable(dvfs_clk); @@ -770,7 +789,8 @@ static int __devinit mxc_dvfsper_probe(struct platform_device *pdev) ret = -ENODEV; goto err1; } - dvfs_per_base = gpc_base + 0x1C4; + dvfsper_plt_data->membase = ioremap(res->start, + res->end - res->start + 1); /* * Request the DVFSPER interrupt diff --git a/arch/arm/plat-mxc/include/mach/arc_otg.h b/arch/arm/plat-mxc/include/mach/arc_otg.h index 1b2511079560..2a58492ccc70 100644 --- a/arch/arm/plat-mxc/include/mach/arc_otg.h +++ b/arch/arm/plat-mxc/include/mach/arc_otg.h @@ -147,6 +147,7 @@ #define USBCTRL_HOST3 USBOTHER_REG(0x18) /* USB Cotrol Register 1*/ #define USBH1_PHY_CTRL0 USBOTHER_REG(0x1c) /* USB Cotrol Register 1*/ #define USBH1_PHY_CTRL1 USBOTHER_REG(0x20) /* USB Cotrol Register 1*/ +#define USB_CLKONOFF_CTRL USBOTHER_REG(0x24) /* USB Clock on/off Control Register */ /* * register bits @@ -245,6 +246,7 @@ #define UCTRL_OBPVAL_RXDP (1 << 26) /* OTG RxDp status in bypass mode */ #define UCTRL_OBPVAL_RXDM (1 << 25) /* OTG RxDm status in bypass mode */ #define UCTRL_OPM (1 << 24) /* OTG power mask */ +#define UCTRL_O_PWR_POL (1 << 24) /* OTG power pin polarity */ #define UCTRL_H2WIR (1 << 23) /* HOST2 wakeup intr request received */ #define UCTRL_H2SIC_MASK (3 << 21) /* HOST2 Serial Interface Config: */ #define UCTRL_H2SIC_DU6 (0 << 21) /* Differential/unidirectional 6 wire */ @@ -329,6 +331,7 @@ #define USB_UTMI_PHYCTRL_OC_POL (1 << 9) /* OTG Polarity of Overcurrent */ #define USB_UTMI_PHYCTRL_OC_DIS (1 << 8) /* OTG Disable Overcurrent Event */ #define USB_UH1_OC_DIS (1 << 5) /* UH1 Disable Overcurrent Event */ +#define USB_UH1_OC_POL (1 << 6) /* UH1 Polarity of OC,Low active */ /* USB_PHY_CTRL_FUNC2*/ #define USB_UTMI_PHYCTRL2_PLLDIV_MASK 0x3 #define USB_UTMI_PHYCTRL2_PLLDIV_SHIFT 0 @@ -355,6 +358,8 @@ #define ULPIVW_WDATA_SHIFT 0 #define HCSPARAMS_PPC (0x1<<4) /* Port Power Control */ - +/* USB Clock on/off Control Register */ +#define OTG_AHBCLK_OFF (0x1<<17) /* 1: OFF */ +#define H1_AHBCLK_OFF (0x1<<18) /* 1: OFF */ extern enum fsl_usb2_modes get_usb_mode(struct fsl_usb2_platform_data *pdata); #endif diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h index 742fb43592b7..990c3a00567c 100644 --- a/arch/arm/plat-mxc/include/mach/common.h +++ b/arch/arm/plat-mxc/include/mach/common.h @@ -34,6 +34,7 @@ extern int mx27_clocks_init(unsigned long fref); extern int mx31_clocks_init(unsigned long fref); extern int mx35_clocks_init(void); extern int mx37_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2); +extern int mx50_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih); extern int mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2); extern int mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2); extern int mxc_init_devices(void); diff --git a/arch/arm/plat-mxc/include/mach/fsl_usb.h b/arch/arm/plat-mxc/include/mach/fsl_usb.h index d1235fc337ff..71263360dc69 100644 --- a/arch/arm/plat-mxc/include/mach/fsl_usb.h +++ b/arch/arm/plat-mxc/include/mach/fsl_usb.h @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -88,4 +88,13 @@ static inline void fsl_platform_set_ahb_burst(struct usb_hcd *hcd) writel((temp & (~(0x3f << 16))) | (0x20 << 16), hcd->regs + FSL_SOC_USB_TXFILLTUNING); } + + /* Increase TX fifo threshold for USB+SD in Hostx */ + if (cpu_is_mx53() && (strcmp("DR", pdata->name))) { + temp = readl(hcd->regs + FSL_SOC_USB_TXFILLTUNING); + /* Change TX FIFO threshold to be 0x08 */ + writel((temp & (~(0x3f << 16))) | (0x08 << 16), + hcd->regs + FSL_SOC_USB_TXFILLTUNING); + } + } diff --git a/arch/arm/plat-mxc/include/mach/hardware.h b/arch/arm/plat-mxc/include/mach/hardware.h index e47a97bdfbd8..f48456869730 100644 --- a/arch/arm/plat-mxc/include/mach/hardware.h +++ b/arch/arm/plat-mxc/include/mach/hardware.h @@ -41,6 +41,7 @@ #define BOARD_REV_1 0x000 #define BOARD_REV_2 0x100 +#define BOARD_REV_3 0x200 #ifdef CONFIG_ARCH_MX3 #include <mach/mx3x.h> @@ -85,6 +86,8 @@ extern unsigned int system_rev; #ifdef CONFIG_ARCH_MX5 #define board_is_mx53_arm2() (cpu_is_mx53() && board_is_rev(BOARD_REV_2)) +#define board_is_mx53_evk_a() (cpu_is_mx53() && board_is_rev(BOARD_REV_1)) +#define board_is_mx53_evk_b() (cpu_is_mx53() && board_is_rev(BOARD_REV_3)) #endif #include <mach/mxc.h> diff --git a/arch/arm/plat-mxc/include/mach/iomux-v3.h b/arch/arm/plat-mxc/include/mach/iomux-v3.h index 7cd84547658f..6beaf8cd69b5 100644 --- a/arch/arm/plat-mxc/include/mach/iomux-v3.h +++ b/arch/arm/plat-mxc/include/mach/iomux-v3.h @@ -68,33 +68,31 @@ struct pad_desc { /* * 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_NO_HYSTERESIS 0 -#define PAD_CTL_HYSTERESIS 1 +#define PAD_CTL_DVS (1 << 13) +#define PAD_CTL_HYS (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_PKE (1 << 7) +#define PAD_CTL_PUE (1 << 6) +#define PAD_CTL_PUS_100K_DOWN (0 << 4) +#define PAD_CTL_PUS_360K_DOWN (0 << 4) +#define PAD_CTL_PUS_47K_UP (1 << 4) +#define PAD_CTL_PUS_75K_UP (1 << 4) +#define PAD_CTL_PUS_100K_UP (2 << 4) +#define PAD_CTL_PUS_22K_UP (3 << 4) -#define PAD_CTL_OUTPUT_CMOS 0 -#define PAD_CTL_OUTPUT_OPEN_DRAIN 1 +#define PAD_CTL_ODE (1 << 3) -#define PAD_CTL_DRIVE_STRENGTH_NORM 0 -#define PAD_CTL_DRIVE_STRENGTH_HIGH 1 -#define PAD_CTL_DRIVE_STRENGTH_MAX 2 +#define PAD_CTL_DSE_LOW (0 << 1) +#define PAD_CTL_DSE_MED (1 << 1) +#define PAD_CTL_DSE_HIGH (2 << 1) +#define PAD_CTL_DSE_MAX (3 << 1) -#define PAD_CTL_SLEW_RATE_SLOW 0 -#define PAD_CTL_SLEW_RATE_FAST 1 +#define PAD_CTL_SRE_FAST (1 << 0) +#define PAD_CTL_SRE_SLOW (0 << 0) /* - * setups a single pad: - * - reserves the pad so that it is not claimed by another driver - * - setups the iomux according to the configuration + * setups a single pad in the iomuxer */ int mxc_iomux_v3_setup_pad(struct pad_desc *pad); @@ -105,17 +103,9 @@ int mxc_iomux_v3_setup_pad(struct pad_desc *pad); int mxc_iomux_v3_setup_multiple_pads(struct pad_desc *pad_list, unsigned count); /* - * releases a single pad: - * - make it available for a future use by another driver - * - DOES NOT reconfigure the IOMUX in its reset state + * Initialise the iomux controller */ -void mxc_iomux_v3_release_pad(struct pad_desc *pad); - -/* - * releases multiple pads - * convenvient way to call the above function with tables - */ -void mxc_iomux_v3_release_multiple_pads(struct pad_desc *pad_list, int count); +void mxc_iomux_v3_init(void __iomem *iomux_v3_base); #endif /* __MACH_IOMUX_V3_H__*/ diff --git a/arch/arm/plat-mxc/include/mach/memory.h b/arch/arm/plat-mxc/include/mach/memory.h index 3861342d1be0..ff05850287af 100644 --- a/arch/arm/plat-mxc/include/mach/memory.h +++ b/arch/arm/plat-mxc/include/mach/memory.h @@ -32,6 +32,10 @@ #define PHYS_OFFSET UL(0x90000000) #endif +#ifdef CONFIG_ARCH_MX50 +#define PHYS_OFFSET UL(0x70000000) +#endif + #ifdef CONFIG_ARCH_MX53 #define PHYS_OFFSET UL(0x70000000) #endif diff --git a/arch/arm/plat-mxc/include/mach/mmc.h b/arch/arm/plat-mxc/include/mach/mmc.h index d563c157bad7..7be75bd5756e 100644 --- a/arch/arm/plat-mxc/include/mach/mmc.h +++ b/arch/arm/plat-mxc/include/mach/mmc.h @@ -40,6 +40,9 @@ struct mxc_mmc_platform_data { unsigned int min_clk; unsigned int max_clk; unsigned int clk_flg; /* 1 clock enable, 0 not */ + unsigned int clk_always_on; /* Needed by SDIO cards and etc */ + unsigned int dll_override_en; /* Enable dll override delay line */ + unsigned int dll_delay_cells; /* The number of delay cells (0-0x3f) */ unsigned int reserved:16; unsigned int card_fixed:1; unsigned int card_inserted_state:1; diff --git a/arch/arm/plat-mxc/include/mach/mx37.h b/arch/arm/plat-mxc/include/mach/mx37.h index 3013d197f206..d83bdfd8824b 100644 --- a/arch/arm/plat-mxc/include/mach/mx37.h +++ b/arch/arm/plat-mxc/include/mach/mx37.h @@ -225,6 +225,9 @@ #define WEIM_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DA000) #define NFC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DB000) +#define DPTCLP_BASE_ADDR (GPC_BASE_ADDR + 0x80) +#define DPTCGP_BASE_ADDR (GPC_BASE_ADDR + 0x100) +#define DVFSCORE_BASE_ADDR (GPC_BASE_ADDR + 0x180) #define DVFSPER_BASE_ADDR (GPC_BASE_ADDR + 0x1C4) /* diff --git a/arch/arm/plat-mxc/include/mach/mx5x.h b/arch/arm/plat-mxc/include/mach/mx5x.h index 5be0f426c7da..0e25133736d2 100644 --- a/arch/arm/plat-mxc/include/mach/mx5x.h +++ b/arch/arm/plat-mxc/include/mach/mx5x.h @@ -93,7 +93,7 @@ #endif #ifdef CONFIG_MXC_VPU_IRAM -#define VPU_IRAM_SIZE 0x11000 +#define VPU_IRAM_SIZE 0x14000 #else #define VPU_IRAM_SIZE 0 #endif @@ -129,6 +129,36 @@ #define MX51_TZIC_BASE_ADDR 0xE0000000 #define TZIC_SIZE SZ_16K +/* + * AHCI SATA + */ +#define MX53_SATA_BASE_ADDR 0x10000000 + +/* + * Databahn MX50 + */ +#define MX50_DATABAHN_BASE_ADDR 0x14000000 +#define DATABAHN_CTL_REG19 0x4c +#define DATABAHN_CTL_REG20 0x50 +#define DATABAHN_CTL_REG21 0x54 +#define DATABAHN_CTL_REG22 0x58 +#define DATABAHN_CTL_REG23 0x5c +#define DATABAHN_CTL_REG42 0xa8 +#define DATABAHN_CTL_REG43 0xac +#define DATABAHN_CTL_REG55 0xdc +#define DATABAHN_CTL_REG63 0xFC +#define LOWPOWER_CONTROL_MASK 0x1F +#define LOWPOWER_AUTOENABLE_MASK 0x1F +#define LOWPOWER_EXTERNAL_CNT_MASK (0xFFFF << 16) +#define LOWPOWER_EXTERNAL_CNT_OFFSET 16 +#define LOWPOWER_INTERNAL_CNT_MASK (0xFFFF << 8) +#define LOWPOWER_INTERNAL_CNT_OFFSET 8 +#define LOWPOWER_REFRESH_ENABLE_MASK (3 << 16) +#define LOWPOWER_REFRESH_ENABLE_OFFSET 16 +#define LOWPOWER_REFRESH_HOLD_MASK 0xFFFF +#define LOWPOWER_REFRESH_HOLD_OFFSET 0 + + #define DEBUG_BASE_ADDR 0x40000000 /*MX53 + 0x2000000 */ #define DEBUG_SIZE SZ_1M @@ -141,6 +171,22 @@ #define CTI3_BASE_ADDR (DEBUG_BASE_ADDR + 0x00007000) #define CORTEX_DBG_BASE_ADDR (DEBUG_BASE_ADDR + 0x00008000) +#define APBHDMA_BASE_ADDR (DEBUG_BASE_ADDR + 0x01000000) +#define OCOTP_CTRL_BASE_ADDR (DEBUG_BASE_ADDR + 0x01002000) +#define DIGCTL_BASE_ADDR (DEBUG_BASE_ADDR + 0x01004000) +#define GPMI_BASE_ADDR (DEBUG_BASE_ADDR + 0x01006000) +#define BCH_BASE_ADDR (DEBUG_BASE_ADDR + 0x01008000) +#define ELCDIF_BASE_ADDR (DEBUG_BASE_ADDR + 0x0100A000) +#define EPXP_BASE_ADDR (DEBUG_BASE_ADDR + 0x0100C000) +#define DCP_BASE_ADDR (DEBUG_BASE_ADDR + 0x0100E000) +#define EPDC_BASE_ADDR (DEBUG_BASE_ADDR + 0x01010000) +#define QOSC_BASE_ADDR (DEBUG_BASE_ADDR + 0x01012000) +#define PERFMON_BASE_ADDR (DEBUG_BASE_ADDR + 0x01014000) +#define SSP_BASE_ADDR (DEBUG_BASE_ADDR + 0x01016000) +#define ANATOP_BASE_ADDR (DEBUG_BASE_ADDR + 0x01018000) + +#define MX50_NIC_BASE_ADDR (DEBUG_BASE_ADDR + 0x08000000) + /* * SPBA global module enabled #0 */ @@ -216,6 +262,7 @@ #define MX53_ATA_BASE_ADDR (AIPS1_BASE_ADDR + 0x000E8000) #define I2C3_BASE_ADDR (AIPS1_BASE_ADDR + 0x000EC000) #define UART4_BASE_ADDR (AIPS1_BASE_ADDR + 0x000F0000) +#define RNGB_BASE_ADDR (AIPS1_BASE_ADDR + 0x000F8000) /* MX50 */ #define DVFSCORE_BASE_ADDR (GPC_BASE_ADDR + 0x180) #define DVFSPER_BASE_ADDR (GPC_BASE_ADDR + 0x1C4) @@ -371,7 +418,7 @@ #define NFC_AXI_IO_ADDRESS(x) \ (((x) - NFC_BASE_ADDR_AXI) + NFC_BASE_ADDR_AXI_VIRT) -#define MX53_BASE_ADDR(x) (cpu_is_mx53() ? (x) - 0x20000000 : (x)) +#define MX53_BASE_ADDR(x) (cpu_is_mx53() || cpu_is_mx50() ? (x) - 0x20000000 : (x)) #define IS_MEM_DEVICE_NONSHARED(x) 0 @@ -388,6 +435,8 @@ #define DMA_REQ_SLIM_B_TX 42 /* MX51 */ #define DMA_REQ_UART3_TX_MX51 44 #define DMA_REQ_UART3_RX_MX51 43 +#define DMA_REQ_UART3_TX_MX50 43 +#define DMA_REQ_UART3_RX_MX50 42 #define DMA_REQ_ESAI_TX 41 #define DMA_REQ_SDHC4_MX51 41 #define DMA_REQ_ESAI_RX 40 @@ -434,9 +483,13 @@ #define DMA_REQ_UART5_RX 16 #define DMA_REQ_SPDIF_TX 15 #define DMA_REQ_SPDIF_RX 14 +#define DMA_REQ_EXTREQ0_MX50 14 +#define DMA_REQ_EXTREQ1_MX50 15 /* UART2 is shared w/FIRI on MX53 */ #define DMA_REQ_FIRI_TX 13 #define DMA_REQ_FIRI_RX 12 +#define DMA_REQ_UART2_TX_MX50 13 +#define DMA_REQ_UART2_RX_MX50 12 #define DMA_REQ_SDHC4_MX53 11 #define DMA_REQ_HS_I2C_RX 11 /* MX51 */ @@ -453,7 +506,9 @@ #define DMA_REQ_SLIM_B 5 /* MX51 */ #define DMA_REQ_ATA_TX_END 4 #define DMA_REQ_ATA_TX 3 +#define DMA_REQ_UART4_TX_MX50 3 #define DMA_REQ_ATA_RX 2 +#define DMA_REQ_UART4_RX_MX50 2 #define DMA_REQ_GPC 1 #define DMA_REQ_VPU 0 @@ -481,16 +536,21 @@ #define MXC_INT_USB_H3 17 #define MXC_INT_USB_OTG 18 #define MXC_INT_SAHARA_H0 19 +#define MXC_INT_DATABAHN 19 /* MX50 */ #define MXC_INT_SAHARA_H1 20 +#define MXC_INT_ELCDIF 20 /* MX50 */ #define MXC_INT_SCC_SMN 21 +#define MXC_INT_EPXP 21 /* MX50 */ #define MXC_INT_SCC_STZ 22 #define MXC_INT_SCC_SCM 23 #define MXC_INT_SRTC_NTZ 24 #define MXC_INT_SRTC_TZ 25 #define MXC_INT_RTIC 26 #define MXC_INT_CSU 27 +#define MXC_INT_EPDC 27 /* MX50 */ #define MXC_INT_SATA 28 #define MXC_INT_SLIM_B 28 /* MX51 */ +#define MXC_INT_NIC 28 /* MX50 Perfmon IRQ */ #define MXC_INT_SSI1 29 #define MXC_INT_SSI2 30 #define MXC_INT_UART1 31 @@ -534,6 +594,10 @@ #define MXC_INT_SIM_IPB 67 #define MXC_INT_SIM_DAT 68 #define MXC_INT_IIM 69 +#define MXC_INT_ANATOP1 66 /* MX50 what's it? */ +#define MXC_INT_ANATOP2 67 +#define MXC_INT_ANATOP3 68 +#define MXC_INT_ANATOP4 69 #define MXC_INT_ATA 70 #define MXC_INT_CCM1 71 #define MXC_INT_CCM2 72 @@ -559,23 +623,46 @@ #define MXC_INT_CTI1_TG2 89 #define MXC_INT_SJC 90 #define MXC_INT_SPDIF_MX51 91 +#define MXC_INT_DCP_CHAN1_3 91 /* MX50 */ #define MXC_INT_TVE 92 +#define MXC_INT_DCP_CHAN0 92 /* MX50 */ #define MXC_INT_FIRI 93 +#define MXC_INT_DCP_CHAN0_3_SEC 93 /* MX50 */ #define MXC_INT_PWM2 94 #define MXC_INT_SLIM_EXP 95 #define MXC_INT_SSI3 96 #define MXC_INT_EMI_BOOT 97 +#define MXC_INT_RNGB_BLOCK 97 /* MX50 */ #define MXC_INT_CTI1_TG3 98 #define MXC_INT_SMC_RX 99 #define MXC_INT_VPU_IDLE 100 +#define MXC_INT_RAWNAND_BCH 100 /* MX50 */ #define MXC_INT_EMI_NFC 101 #define MXC_INT_GPU_IDLE 102 +#define MXC_INT_RAWNAND_GPMI 102 /* MX50 */ #define MXC_INT_GPIO5_LOW 103 #define MXC_INT_GPIO5_HIGH 104 #define MXC_INT_GPIO6_LOW 105 #define MXC_INT_GPIO6_HIGH 106 #define MXC_INT_GPIO7_LOW 107 #define MXC_INT_GPIO7_HIGH 108 +#define MXC_INT_MSHC 109 /* MX50 */ +#define MXC_INT_APBHDMA_CHAN0 110 +#define MXC_INT_APBHDMA_CHAN1 111 +#define MXC_INT_APBHDMA_CHAN2 112 +#define MXC_INT_APBHDMA_CHAN3 113 +#define MXC_INT_APBHDMA_CHAN4 114 +#define MXC_INT_APBHDMA_CHAN5 115 +#define MXC_INT_APBHDMA_CHAN6 116 +#define MXC_INT_APBHDMA_CHAN7 117 +#define MXC_INT_APBHDMA_CHAN8 118 +#define MXC_INT_APBHDMA_CHAN9 119 +#define MXC_INT_APBHDMA_CHAN10 120 +#define MXC_INT_APBHDMA_CHAN11 121 +#define MXC_INT_APBHDMA_CHAN12 122 +#define MXC_INT_APBHDMA_CHAN13 123 +#define MXC_INT_APBHDMA_CHAN14 124 +#define MXC_INT_APBHDMA_CHAN15 125 /* gpio and gpio based interrupt handling */ #define GPIO_DR 0x00 diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h index a47e599c54d4..808adf67552d 100644 --- a/arch/arm/plat-mxc/include/mach/mxc.h +++ b/arch/arm/plat-mxc/include/mach/mxc.h @@ -34,6 +34,7 @@ #define MXC_CPU_MX37 37 #define MXC_CPU_MX51 51 #define MXC_CPU_MX53 53 +#define MXC_CPU_MX50 50 #ifndef __ASSEMBLY__ extern unsigned int __mxc_cpu_type; @@ -147,6 +148,18 @@ extern unsigned int __mxc_cpu_type; # define cpu_is_mx53() (0) #endif +#ifdef CONFIG_ARCH_MX50 +# ifdef mxc_cpu_type +# undef mxc_cpu_type +# define mxc_cpu_type __mxc_cpu_type +# else +# define mxc_cpu_type MXC_CPU_MX50 +# endif +# define cpu_is_mx50() (mxc_cpu_type == MXC_CPU_MX50) +#else +# define cpu_is_mx50() (0) +#endif + #define cpu_is_mx32() (0) /* @@ -222,6 +235,7 @@ struct mxc_ipu_config { int rev; void (*reset) (void); struct clk *di_clk[2]; + struct clk *csi_clk[2]; }; struct mxc_ir_platform_data { @@ -292,6 +306,7 @@ struct mxc_lightsensor_platform_data { struct mxc_fb_platform_data { struct fb_videomode *mode; + int num_modes; char *mode_str; u32 interface_pix_fmt; }; @@ -306,8 +321,32 @@ struct mxc_lcd_platform_data { struct ccwmx51_lcd_pdata { int vif; struct mxc_fb_platform_data fb_pdata; - void (*reset) (void); - void (*bl_enable) (int); + void (*init) (int); + void (*deinit) (int); + void (*bl_enable) (int, int); +}; + +struct mxc_epdc_fb_mode { + struct fb_videomode *vmode; + int vscan_holdoff; + int sdoed_width; + int sdoed_delay; + int sdoez_width; + int sdoez_delay; + int gdclk_hp_offs; + int gdsp_offs; + int gdoe_offs; + int gdclk_offs; + int num_ce; +}; + +struct mxc_epdc_fb_platform_data { + struct mxc_epdc_fb_mode *epdc_mode; + int num_modes; + void (*get_pins) (void); + void (*put_pins) (void); + void (*enable_pins) (void); + void (*disable_pins) (void); }; struct mxc_tsc_platform_data { @@ -346,6 +385,7 @@ struct mxc_camera_platform_data { char *gpo_regulator; u32 mclk; u32 csi; + void (*pwdn) (int pwdn); }; /*gpo1-3 is in fixed state by hardware design, @@ -465,10 +505,20 @@ struct tve_platform_data { char *dig_reg; }; +struct ldb_platform_data { + char *lvds_bg_reg; + u32 ext_ref; +}; + struct mxc_vpu_platform_data { void (*reset) (void); }; +struct mxc_esai_platform_data { + void (*activate_esai_ports) (void); + void (*deactivate_esai_ports) (void); +}; + /* The name that links the i.MX NAND Flash Controller driver to its devices. */ #define IMX_NFC_DRIVER_NAME ("imx_nfc") @@ -584,6 +634,18 @@ struct mxc_sim_platform_data { unsigned int detect; /* 1 have detect pin, 0 not */ }; +struct fsl_otp_data { + char **fuse_name; + char *regulator_name; + unsigned int fuse_num; +}; + +struct mxs_dma_plat_data { + unsigned int burst8:1; + unsigned int burst:1; + unsigned int chan_base; + unsigned int chan_num; +}; #endif /* __ASSEMBLY__ */ #define MUX_IO_P 29 @@ -649,7 +711,7 @@ void gpio_deactivate_esai_ports(void); #define CSCR_A(n) (IO_ADDRESS(WEIM_BASE_ADDR) + n * 0x10 + 0x8) #endif -#define cpu_is_mx5() (cpu_is_mx51() || cpu_is_mx53()) +#define cpu_is_mx5() (cpu_is_mx51() || cpu_is_mx53() || cpu_is_mx50()) #define cpu_is_mx3() (cpu_is_mx31() || cpu_is_mx35()) #define cpu_is_mx2() (cpu_is_mx21() || cpu_is_mx27()) diff --git a/arch/arm/plat-mxc/include/mach/mxc_dvfs.h b/arch/arm/plat-mxc/include/mach/mxc_dvfs.h index fd0179b4d8f9..05c6ea4bda77 100644 --- a/arch/arm/plat-mxc/include/mach/mxc_dvfs.h +++ b/arch/arm/plat-mxc/include/mach/mxc_dvfs.h @@ -35,6 +35,7 @@ #include <linux/device.h> extern void __iomem *gpc_base; +extern void __iomem *ccm_base; #define MXC_GPCCNTR_GPCIRQ2M (1 << 25) #define MXC_GPCCNTR_GPCIRQ2 (1 << 24) @@ -101,6 +102,25 @@ extern void __iomem *gpc_base; #define MXC_DVFSPMCR1_P4PM 0x00020000 #define MXC_DVFSPMCR1_P2PM 0x00010000 +/* DVFS CORE register offsets*/ +#define MXC_DVFSCORE_THRS 0x00 +#define MXC_DVFSCORE_COUN 0x04 +#define MXC_DVFSCORE_SIG1 0x08 +#define MXC_DVFSCORE_SIG0 0x0C +#define MXC_DVFSCORE_GPC0 0x10 +#define MXC_DVFSCORE_GPC1 0x14 +#define MXC_DVFSCORE_GPBT 0x18 +#define MXC_DVFSCORE_EMAC 0x1C +#define MXC_DVFSCORE_CNTR 0x20 +#define MXC_DVFSCORE_LTR0_0 0x24 +#define MXC_DVFSCORE_LTR0_1 0x28 +#define MXC_DVFSCORE_LTR1_0 0x2C +#define MXC_DVFSCORE_LTR1_1 0x30 +#define MXC_DVFSCORE_PT0 0x34 +#define MXC_DVFSCORE_PT1 0x38 +#define MXC_DVFSCORE_PT2 0x3C +#define MXC_DVFSCORE_PT3 0x40 + /* * DVFS structure */ @@ -120,24 +140,20 @@ struct mxc_dvfs_platform_data { char *clk1_id; /* DVFS clock name string */ char *clk2_id; - /* GPC control reg address */ - void __iomem *gpc_cntr_reg_addr; - /* GPC voltage counter reg address */ - void __iomem *gpc_vcr_reg_addr; - /* CCM DVFS control reg address */ - void __iomem *ccm_cdcr_reg_addr; - /* CCM ARM clock root reg address */ - void __iomem *ccm_cacrr_reg_addr; - /* CCM divider handshake in-progree reg address */ - void __iomem *ccm_cdhipr_reg_addr; - /* DVFS threshold reg address */ - void __iomem *dvfs_thrs_reg_addr; - /* DVFS counters reg address */ - void __iomem *dvfs_coun_reg_addr; - /* DVFS EMAC reg address */ - void __iomem *dvfs_emac_reg_addr; - /* DVFS control reg address */ - void __iomem *dvfs_cntr_reg_addr; + /* The base address of the DVFS core */ + void __iomem *membase; + /* The interrupt number used by the DVFS core */ + int irq; + /* GPC control reg offset */ + int gpc_cntr_offset; + /* GPC voltage counter reg offset */ + int gpc_vcr_offset; + /* CCM DVFS control reg offset */ + int ccm_cdcr_offset; + /* CCM ARM clock root reg offset */ + int ccm_cacrr_offset; + /* CCM divider handshake in-progress reg offset */ + int ccm_cdhipr_offset; /* PREDIV mask */ u32 prediv_mask; /* PREDIV offset */ @@ -182,6 +198,8 @@ struct mxc_dvfsper_data { char *reg_id; /* DVFS clock name string */ char *clk_id; + /* The base address of the DVFS per */ + void __iomem *membase; /* GPC control reg address */ void __iomem *gpc_cntr_reg_addr; /* GPC VCR reg address */ diff --git a/arch/arm/plat-mxc/include/mach/system.h b/arch/arm/plat-mxc/include/mach/system.h index 126bc8713159..604abbc77da0 100644 --- a/arch/arm/plat-mxc/include/mach/system.h +++ b/arch/arm/plat-mxc/include/mach/system.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999 ARM Limited * Copyright (C) 2000 Deep Blue Solutions Ltd - * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2010 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 as published by @@ -24,5 +24,6 @@ extern void arch_idle(void); void arch_reset(char mode, const char *cmd); +int mxs_reset_block(void __iomem *hwreg, int just_enable); #endif /* __ASM_ARCH_MXC_SYSTEM_H__ */ diff --git a/arch/arm/plat-mxc/iomux-v3.c b/arch/arm/plat-mxc/iomux-v3.c index 77a078f9513f..b318c6a222d5 100644 --- a/arch/arm/plat-mxc/iomux-v3.c +++ b/arch/arm/plat-mxc/iomux-v3.c @@ -29,30 +29,22 @@ #include <asm/mach/map.h> #include <mach/iomux-v3.h> -#define IOMUX_BASE IO_ADDRESS(IOMUXC_BASE_ADDR) - -static unsigned long iomux_v3_pad_alloc_map[0x200 / BITS_PER_LONG]; +static void __iomem *base; /* - * setups a single pin: - * - reserves the pin so that it is not claimed by another driver - * - setups the iomux according to the configuration + * setups a single pad in the iomuxer */ int mxc_iomux_v3_setup_pad(struct pad_desc *pad) { - unsigned int pad_ofs = pad->pad_ctrl_ofs; - - if (test_and_set_bit(pad_ofs >> 2, iomux_v3_pad_alloc_map)) - return -EBUSY; if (pad->mux_ctrl_ofs) - __raw_writel(pad->mux_mode, IOMUX_BASE + pad->mux_ctrl_ofs); + __raw_writel(pad->mux_mode, base + pad->mux_ctrl_ofs); if (pad->select_input_ofs) __raw_writel(pad->select_input, - IOMUX_BASE + pad->select_input_ofs); + base + pad->select_input_ofs); - if (!(pad->pad_ctrl & NO_PAD_CTRL)) - __raw_writel(pad->pad_ctrl, IOMUX_BASE + pad->pad_ctrl_ofs); + if (!(pad->pad_ctrl & NO_PAD_CTRL) && pad->pad_ctrl_ofs) + __raw_writel(pad->pad_ctrl, base + pad->pad_ctrl_ofs); return 0; } EXPORT_SYMBOL(mxc_iomux_v3_setup_pad); @@ -66,33 +58,14 @@ int mxc_iomux_v3_setup_multiple_pads(struct pad_desc *pad_list, unsigned count) for (i = 0; i < count; i++) { ret = mxc_iomux_v3_setup_pad(p); if (ret) - goto setup_error; + return ret; p++; } return 0; - -setup_error: - mxc_iomux_v3_release_multiple_pads(pad_list, i); - return ret; } EXPORT_SYMBOL(mxc_iomux_v3_setup_multiple_pads); -void mxc_iomux_v3_release_pad(struct pad_desc *pad) -{ - unsigned int pad_ofs = pad->pad_ctrl_ofs; - - clear_bit(pad_ofs >> 2, iomux_v3_pad_alloc_map); -} -EXPORT_SYMBOL(mxc_iomux_v3_release_pad); - -void mxc_iomux_v3_release_multiple_pads(struct pad_desc *pad_list, int count) +void mxc_iomux_v3_init(void __iomem *iomux_v3_base) { - struct pad_desc *p = pad_list; - int i; - - for (i = 0; i < count; i++) { - mxc_iomux_v3_release_pad(p); - p++; - } + base = iomux_v3_base; } -EXPORT_SYMBOL(mxc_iomux_v3_release_multiple_pads); diff --git a/arch/arm/plat-mxc/iram.c b/arch/arm/plat-mxc/iram.c index 3d2a391bd2d1..c63b0a2a9a10 100644 --- a/arch/arm/plat-mxc/iram.c +++ b/arch/arm/plat-mxc/iram.c @@ -36,6 +36,11 @@ void *iram_alloc(unsigned int size, unsigned long *dma_addr) *dma_addr = gen_pool_alloc(iram_pool, size); pr_debug("iram alloc - %dB@0x%p\n", size, (void *)*dma_addr); + + WARN_ON(!*dma_addr); + if (!*dma_addr) + return NULL; + return iram_phys_to_virt(*dma_addr); } EXPORT_SYMBOL(iram_alloc); diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c index f159feb01f83..77eb52ce477c 100644 --- a/arch/arm/plat-mxc/pwm.c +++ b/arch/arm/plat-mxc/pwm.c @@ -61,7 +61,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) return -EINVAL; - if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx51() || cpu_is_mx53()) { + if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx5()) { unsigned long long c; unsigned long period_cycles, duty_cycles, prescale; c = clk_get_rate(pwm->clk); diff --git a/arch/arm/plat-mxc/usb_common.c b/arch/arm/plat-mxc/usb_common.c index 2f5f597f806e..71583e465046 100644 --- a/arch/arm/plat-mxc/usb_common.c +++ b/arch/arm/plat-mxc/usb_common.c @@ -275,21 +275,25 @@ static void usbh1_set_utmi_xcvr(void) while ((UH1_USBCMD) & (UCMD_RESET)) ; - /* MX53 EVK is not using OC */ - USB_PHY_CTR_FUNC |= USB_UH1_OC_DIS; - - USBCTRL &= ~UCTRL_H1PM; /* OTG Power Mask */ - USBCTRL &= ~UCTRL_H1WIE; /* OTG Wakeup Intr Disable */ - - /* Over current disable */ - USB_PHY_CTR_FUNC |= (0x1 << 5); - + /* For OC and PWR, it is board level setting + * The default setting is for mx53 evk + */ + USBCTRL &= ~UCTRL_H1PM; /* Host1 Power Mask */ + USBCTRL &= ~UCTRL_H1WIE; /* Host1 Wakeup Intr Disable */ + USB_PHY_CTR_FUNC |= USB_UH1_OC_DIS; /* Over current disable */ + + if (machine_is_mx50_arm2()) { + USBCTRL |= UCTRL_H1PM; /* Host1 Power Mask */ + USB_PHY_CTR_FUNC &= ~USB_UH1_OC_DIS; /* Over current enable */ + /* Over current polarity low active */ + USB_PHY_CTR_FUNC |= USB_UH1_OC_POL; + } /* set UTMI xcvr */ tmp = UH1_PORTSC1 & ~PORTSC_PTS_MASK; tmp |= PORTSC_PTS_UTMI; UH1_PORTSC1 = tmp; - /* Set the PHY clock to 19.2MHz */ + /* Set the PHY clock to 24MHz */ USBH1_PHY_CTRL1 &= ~USB_UTMI_PHYCTRL2_PLLDIV_MASK; USBH1_PHY_CTRL1 |= 0x01; @@ -428,14 +432,7 @@ static int usb_register_remote_wakeup(struct platform_device *pdev) int irq; pr_debug("%s: pdev=0x%p \n", __func__, pdev); - if (!cpu_is_mx51() && !cpu_is_mx25()) - return -ECANCELED; - - /* The Host2 USB controller On mx25 platform - * is no path available from internal USB FS - * PHY to FS PHY wake up interrupt, So to - * remove the function of USB Remote Wakeup on Host2 */ - if (cpu_is_mx25() && (!strcmp("Host 2", pdata->name))) + if (!(pdata->wake_up_enable)) return -ECANCELED; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -485,6 +482,10 @@ int fsl_usb_host_init(struct platform_device *pdev) clk_put(usboh3_clk); } + if (cpu_is_mx50()) + /* Turn on AHB CLK for H1*/ + USB_CLKONOFF_CTRL &= ~H1_AHBCLK_OFF; + /* enable board power supply for xcvr */ if (pdata->xcvr_pwr) { if (pdata->xcvr_pwr->regu1) @@ -704,6 +705,11 @@ static void otg_set_utmi_xcvr(void) } else if (cpu_is_mx25()) { USBCTRL |= UCTRL_OCPOL; USBCTRL &= ~UCTRL_PP; + } else if (cpu_is_mx50()) { + USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_OC_DIS; + if (machine_is_mx50_arm2()) + /* OTG Power pin polarity low */ + USBCTRL |= UCTRL_O_PWR_POL; } else { /* USBOTG_PWR low active */ USBCTRL &= ~UCTRL_PP; @@ -715,8 +721,9 @@ static void otg_set_utmi_xcvr(void) USBCTRL |= UCTRL_OLOCKD; } - if (!cpu_is_mx53()) + if (cpu_is_mx51()) USBCTRL &= ~UCTRL_OPM; /* OTG Power Mask */ + USBCTRL &= ~UCTRL_OWIE; /* OTG Wakeup Intr Disable */ /* set UTMI xcvr */ @@ -793,9 +800,12 @@ int usbotg_init(struct platform_device *pdev) pdata->xcvr_type = xops->xcvr_type; pdata->pdev = pdev; + if (fsl_check_usbclk() != 0) + return -EINVAL; if (!otg_used) { - if (fsl_check_usbclk() != 0) - return -EINVAL; + if (cpu_is_mx50()) + /* Turn on AHB CLK for OTG*/ + USB_CLKONOFF_CTRL &= ~OTG_AHBCLK_OFF; pr_debug("%s: grab pins\n", __func__); if (pdata->gpio_usb_active && pdata->gpio_usb_active()) @@ -871,8 +881,8 @@ int usb_host_wakeup_irq(struct device *wkup_dev) wakeup_req = USBCTRL & UCTRL_H1WIR; } else if (!strcmp("DR", pdata->name)) { wakeup_req = USBCTRL & UCTRL_OWIR; - /* If DR is in device mode, let udc handle it */ - if (wakeup_req && ((UOG_USBMODE & 0x3) == 0x2)) + /* If not ID wakeup, let udc handle it */ + if (wakeup_req && (UOG_OTGSC & OTGSC_STS_USB_ID)) wakeup_req = 0; } diff --git a/arch/arm/plat-mxc/utmixc.c b/arch/arm/plat-mxc/utmixc.c index 6a13e8fbbe70..59207ab9ff67 100644 --- a/arch/arm/plat-mxc/utmixc.c +++ b/arch/arm/plat-mxc/utmixc.c @@ -73,6 +73,8 @@ static void set_power(struct fsl_xcvr_ops *this, regulator_put(usbotg_regux); } } + if (pdata && pdata->platform_driver_vbus) + pdata->platform_driver_vbus(on); } static struct fsl_xcvr_ops utmi_ops = { diff --git a/arch/arm/plat-mxs/Kconfig b/arch/arm/plat-mxs/Kconfig index dd6689ecf5d0..63768f85a327 100644 --- a/arch/arm/plat-mxs/Kconfig +++ b/arch/arm/plat-mxs/Kconfig @@ -19,6 +19,7 @@ config ARCH_MX28 config ARCH_MX23 bool "Freescale MX23" select CPU_ARM926T + select FIQ select ZONE_DMA select MXS_ICOLL select MXS_DMA_ENGINE diff --git a/arch/arm/plat-mxs/Makefile b/arch/arm/plat-mxs/Makefile index 2c271285bdfd..e252630479d9 100644 --- a/arch/arm/plat-mxs/Makefile +++ b/arch/arm/plat-mxs/Makefile @@ -8,6 +8,8 @@ obj-$(CONFIG_MXS_TIMER_WITH_MACH) += timer-match.o obj-$(CONFIG_IRAM_ALLOC) += iram.o obj-$(CONFIG_GENERIC_GPIO) += gpio.o +obj-$(CONFIG_MXS_UNIQUE_ID) += unique-id.o + obj-$(CONFIG_MXS_ICOLL) += icoll.o obj-$(CONFIG_MXS_DMA_ENGINE) += dmaengine.o dma-apbh.o dma-apbx.o diff --git a/arch/arm/plat-mxs/clock.c b/arch/arm/plat-mxs/clock.c index 9fecdbde49ad..1b98b1e51164 100644 --- a/arch/arm/plat-mxs/clock.c +++ b/arch/arm/plat-mxs/clock.c @@ -29,6 +29,9 @@ #include <mach/clock.h> extern int cpufreq_trig_needed; +static bool (*mxs_enable_h_autoslow)(bool enable); +static void (*mxs_set_h_autoslow_flags)(u16 flags); + static DEFINE_SPINLOCK(clockfw_lock); /* @@ -109,7 +112,11 @@ int clk_enable(struct clk *clk) return -EINVAL; spin_lock_irqsave(&clockfw_lock, flags); - pre_usage = clk->ref; + pre_usage = (clk->ref & CLK_EN_MASK); + + if (clk->set_sys_dependent_parent) + clk->set_sys_dependent_parent(clk); + ret = __clk_enable(clk); spin_unlock_irqrestore(&clockfw_lock, flags); if ((clk->flags & CPU_FREQ_TRIG_UPDATE) @@ -133,7 +140,7 @@ void clk_disable(struct clk *clk) __clk_disable(clk); spin_unlock_irqrestore(&clockfw_lock, flags); if ((clk->flags & CPU_FREQ_TRIG_UPDATE) - && (clk->ref == 0)) { + && ((clk->ref & CLK_EN_MASK) == 0)) { cpufreq_trig_needed = 1; cpufreq_update_policy(0); } @@ -279,3 +286,40 @@ void clk_unregister(struct clk_lookup *lookup) lookup->clk->get_rate = NULL; } EXPORT_SYMBOL(clk_unregister); + +bool clk_enable_h_autoslow(bool enable) +{ + unsigned long flags; + bool ret = false; + + if (mxs_enable_h_autoslow == NULL) + return ret; + + spin_lock_irqsave(&clockfw_lock, flags); + ret = mxs_enable_h_autoslow(enable); + spin_unlock_irqrestore(&clockfw_lock, flags); + + return ret; +} +EXPORT_SYMBOL(clk_enable_h_autoslow); + +void clk_set_h_autoslow_flags(u16 mask) +{ + unsigned long flags; + + if (mxs_set_h_autoslow_flags == NULL) + return; + + spin_lock_irqsave(&clockfw_lock, flags); + mxs_set_h_autoslow_flags(mask); + spin_unlock_irqrestore(&clockfw_lock, flags); +} +EXPORT_SYMBOL(clk_set_h_autoslow_flags); + +void clk_en_public_h_asm_ctrl(bool (*enable_func)(bool), + void (*set_func)(u16)) +{ + mxs_enable_h_autoslow = enable_func; + mxs_set_h_autoslow_flags = set_func; +} +EXPORT_SYMBOL(clk_en_public_h_asm_ctrl); diff --git a/arch/arm/plat-mxs/cpufreq.c b/arch/arm/plat-mxs/cpufreq.c index d36baa740dbc..a188b21d9bf4 100644 --- a/arch/arm/plat-mxs/cpufreq.c +++ b/arch/arm/plat-mxs/cpufreq.c @@ -40,6 +40,7 @@ static struct regulator *cpu_regulator; static struct clk *cpu_clk; static struct clk *ahb_clk; +static struct clk *x_clk; static struct clk *emi_clk; static struct regulator *vddd; static struct regulator *vdddbo; @@ -62,11 +63,19 @@ static int set_freq_table(struct cpufreq_policy *policy, int end_index) { int ret = 0; int i; + int zero_no = 0; + + for (i = 0; i < end_index; i++) { + if (profiles[i].cpu == 0) + zero_no++; + } + + end_index -= zero_no; cpu_freq_khz_min = profiles[0].cpu; cpu_freq_khz_max = profiles[0].cpu; for (i = 0; i < end_index; i++) { - imx_freq_table[end_index - 1 - i].index = end_index - i; + imx_freq_table[end_index - 1 - i].index = end_index - i; imx_freq_table[end_index - 1 - i].frequency = profiles[i].cpu; @@ -135,8 +144,6 @@ static int set_op(struct cpufreq_policy *policy, unsigned int target_freq) return 0; } - cpu_clk_set_pll_on(cpu_clk, freqs.new); - if (cpu_regulator && (freqs.old < freqs.new)) { ret = regulator_set_current_limit(cpu_regulator, profiles[i].cur, profiles[i].cur); @@ -149,10 +156,16 @@ static int set_op(struct cpufreq_policy *policy, unsigned int target_freq) if (freqs.old > freqs.new) { int ss = profiles[i].ss; + /* change emi while cpu is fastest to minimize + * time spent changing emiclk + */ + clk_set_rate(emi_clk, (profiles[i].emi) * 1000); clk_set_rate(cpu_clk, (profiles[i].cpu) * 1000); clk_set_rate(ahb_clk, (profiles[i].ahb) * 1000); - clk_set_rate(emi_clk, (profiles[i].emi) * 1000); + /* x_clk order doesn't really matter */ + clk_set_rate(x_clk, (profiles[i].xbus) * 1000); timing_ctrl_rams(ss); + if (vddd && vdddbo && vddio && vdda) { ret = regulator_set_voltage(vddd, profiles[i].vddd, @@ -208,17 +221,18 @@ static int set_op(struct cpufreq_policy *policy, unsigned int target_freq) profiles[i].vdda, profiles[i].vdda); } + /* x_clk order doesn't really matter */ + clk_set_rate(x_clk, (profiles[i].xbus) * 1000); timing_ctrl_rams(ss); - if (freqs.old == 64000) - clk_set_rate(ahb_clk, (profiles[i].ahb) * 1000); clk_set_rate(cpu_clk, (profiles[i].cpu) * 1000); - if (freqs.old != 64000) - clk_set_rate(ahb_clk, (profiles[i].ahb) * 1000); + clk_set_rate(ahb_clk, (profiles[i].ahb) * 1000); clk_set_rate(emi_clk, (profiles[i].emi) * 1000); } - udelay(100); - cpu_clk_set_pll_off(cpu_clk, freqs.new); + if (is_hclk_autoslow_ok()) + clk_set_h_autoslow_flags(profiles[i].h_autoslow_flags); + else + clk_enable_h_autoslow(false); if (high_freq_needed == 0) cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); @@ -231,7 +245,6 @@ static int set_op(struct cpufreq_policy *policy, unsigned int target_freq) if (high_freq_needed == 1) { high_freq_needed = 0; cur_freq_table_size = lcd_on_freq_table_size; - hbus_auto_slow_mode_disable(); set_freq_table(policy, cur_freq_table_size); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); } @@ -293,11 +306,22 @@ static int mxs_target(struct cpufreq_policy *policy, cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); low_freq_bus_ready = low_freq_used(); if (low_freq_bus_ready) { + int i; cur_freq_table_size = lcd_off_freq_table_size; - hbus_auto_slow_mode_enable(); + /* find current table index to get + * hbus autoslow flags and enable hbus autoslow. + */ + for (i = cur_freq_table_size - 1; i > 0; i--) { + if (profiles[i].cpu <= target_freq && + target_freq < profiles[i - 1].cpu) { + clk_set_h_autoslow_flags( + profiles[i].h_autoslow_flags); + break; + } + } } else { cur_freq_table_size = lcd_on_freq_table_size; - hbus_auto_slow_mode_disable(); + clk_enable_h_autoslow(false); } set_freq_table(policy, cur_freq_table_size); @@ -354,6 +378,12 @@ static int __init mxs_cpu_init(struct cpufreq_policy *policy) goto out_ahb; } + x_clk = clk_get(NULL, "x"); + if (IS_ERR(ahb_clk)) { + ret = PTR_ERR(x_clk); + goto out_x; + } + emi_clk = clk_get(NULL, "emi"); if (IS_ERR(emi_clk)) { ret = PTR_ERR(emi_clk); @@ -419,13 +449,13 @@ static int __init mxs_cpu_init(struct cpufreq_policy *policy) for (i = 0; i < ARRAY_SIZE(profiles); i++) { if ((profiles[i].cpu) == 0) { - lcd_off_freq_table_size = i + 1; + lcd_off_freq_table_size = i; break; } } if (i == ARRAY_SIZE(profiles)) - lcd_off_freq_table_size = i + 1; + lcd_off_freq_table_size = i; /* Set the current working point. */ set_freq_table(policy, lcd_on_freq_table_size); @@ -447,6 +477,8 @@ out_cur: clk_put(emi_clk); out_emi: + clk_put(x_clk); +out_x: clk_put(ahb_clk); out_ahb: clk_put(cpu_clk); diff --git a/arch/arm/plat-mxs/device.c b/arch/arm/plat-mxs/device.c index 00180846885b..e3783d3fe87d 100644 --- a/arch/arm/plat-mxs/device.c +++ b/arch/arm/plat-mxs/device.c @@ -24,6 +24,7 @@ #include <linux/bitops.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/gpmi-nfc.h> #include <mach/device.h> @@ -138,10 +139,10 @@ static struct platform_device mxs_i2c[] = { }; #endif -#if defined(CONFIG_MTD_NAND_GPMI1) || \ - defined(CONFIG_MTD_NAND_GPMI1_MODULE) -static struct platform_device mxs_gpmi = { - .name = "gpmi", +#if defined(CONFIG_MTD_NAND_GPMI_NFC) || \ + defined(CONFIG_MTD_NAND_GPMI_NFC_MODULE) +static struct platform_device gpmi_nfc = { + .name = GPMI_NFC_DRIVER_NAME, .id = 0, .dev = { .dma_mask = &common_dmamask, @@ -175,6 +176,20 @@ static struct platform_device mxs_mmc[] = { }; #endif +#if defined(CONFIG_SPI_MXS) || defined(CONFIG_SPI_MXS_MODULE) +static struct platform_device mxs_spi[] = { + { + .name = "mxs-spi", + .id = 0, + .dev = { + .dma_mask = &common_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .release = mxs_nop_release, + }, + }, +}; +#endif + #if defined(CONFIG_MXS_WATCHDOG) || defined(CONFIG_MXS_WATCHDOG_MODULE) static struct platform_device mxs_wdt = { .name = "mxs-wdt", @@ -195,6 +210,25 @@ static struct platform_device mxs_fec[] = { .release = mxs_nop_release, }, }, + { + .name = "fec", + .id = 1, + .dev = { + .release = mxs_nop_release, + }, + }, +}; +#endif + +#if defined(CONFIG_FEC_L2SWITCH) +static struct platform_device mxs_l2switch[] = { + { + .name = "mxs-l2switch", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, + }, }; #endif @@ -451,6 +485,16 @@ static struct platform_device mxs_persistent = { }; #endif +#ifdef CONFIG_FSL_OTP +static struct platform_device otp_device = { + .name = "ocotp", + .id = 0, + .dev = { + .release = mxs_nop_release, + }, +}; +#endif + static inline void mxs_init_busfreq(void) { (void)platform_device_register(&busfreq_device); @@ -482,12 +526,12 @@ static struct mxs_dev_lookup dev_lookup[] = { }, #endif -#if defined(CONFIG_MTD_NAND_GPMI1) || \ - defined(CONFIG_MTD_NAND_GPMI1_MODULE) +#if defined(CONFIG_MTD_NAND_GPMI_NFC) || \ + defined(CONFIG_MTD_NAND_GPMI_NFC_MODULE) { - .name = "gpmi", + .name = GPMI_NFC_DRIVER_NAME, .size = 1, - .pdev = &mxs_gpmi, + .pdev = &gpmi_nfc, }, #endif @@ -500,6 +544,14 @@ static struct mxs_dev_lookup dev_lookup[] = { }, #endif +#if defined(CONFIG_SPI_MXS) || defined(CONFIG_SPI_MXS_MODULE) + { + .name = "mxs-spi", + .size = ARRAY_SIZE(mxs_spi), + .pdev = mxs_spi, + }, +#endif + #if defined(CONFIG_MXS_WATCHDOG) || defined(CONFIG_MXS_WATCHDOG_MODULE) { .name = "mxs-wdt", @@ -524,6 +576,14 @@ static struct mxs_dev_lookup dev_lookup[] = { }, #endif +#if defined(CONFIG_FSL_OTP) + { + .name = "ocotp", + .size = 1, + .pdev = &otp_device, + }, +#endif + #if defined(CONFIG_FB_MXS) || defined(CONFIG_FB_MXS_MODULE) { .name = "mxs-fb", @@ -565,6 +625,14 @@ static struct mxs_dev_lookup dev_lookup[] = { }, #endif +#if defined(CONFIG_FEC_L2SWITCH) + { + .name = "mxs-l2switch", + .size = ARRAY_SIZE(mxs_l2switch), + .pdev = mxs_l2switch, + }, +#endif + #ifdef CONFIG_MXS_LRADC { .name = "mxs-lradc", diff --git a/arch/arm/plat-mxs/dma-apbx.c b/arch/arm/plat-mxs/dma-apbx.c index c27414f8c18d..6d77a6933d98 100644 --- a/arch/arm/plat-mxs/dma-apbx.c +++ b/arch/arm/plat-mxs/dma-apbx.c @@ -99,6 +99,9 @@ static void mxs_dma_apbx_info(struct mxs_dma_device *pdev, reg = __raw_readl(pdev->base + HW_APBX_CTRL2); info->status = reg >> chan; info->buf_addr = __raw_readl(pdev->base + HW_APBX_CHn_BAR(chan)); + reg = __raw_readl(pdev->base + HW_APBX_CHn_CMD(chan)); + info->xfer_count = (reg & BM_APBX_CHn_CMD_XFER_COUNT) >> \ + BP_APBX_CHn_CMD_XFER_COUNT; } static int diff --git a/arch/arm/plat-mxs/dmaengine.c b/arch/arm/plat-mxs/dmaengine.c index 453346e4057f..0c2485b18506 100644 --- a/arch/arm/plat-mxs/dmaengine.c +++ b/arch/arm/plat-mxs/dmaengine.c @@ -127,14 +127,16 @@ int mxs_dma_enable(int channel) if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED)) return -EINVAL; + /* + * neednot mutex lock, this function will be called in irq context. + * The mutex may cause process schedule. + */ pdma = pchan->dma; - mutex_lock(&mxs_dma_mutex); spin_lock_irqsave(&pchan->lock, flags); if (pchan->pending_num && pdma->enable) ret = pdma->enable(pchan, channel - pdma->chan_base); pchan->flags |= MXS_DMA_FLAGS_BUSY; spin_unlock_irqrestore(&pchan->lock, flags); - mutex_unlock(&mxs_dma_mutex); return ret; } EXPORT_SYMBOL(mxs_dma_enable); @@ -151,17 +153,19 @@ void mxs_dma_disable(int channel) return; if (!(pchan->flags & MXS_DMA_FLAGS_BUSY)) return; + /* + * neednot mutex lock, this function will be called in irq context. + * The mutex may cause process schedule. + */ pdma = pchan->dma; - mutex_lock(&mxs_dma_mutex); spin_lock_irqsave(&pchan->lock, flags); if (pdma->disable) pdma->disable(pchan, channel - pdma->chan_base); pchan->flags &= ~MXS_DMA_FLAGS_BUSY; pchan->active_num = 0; pchan->pending_num = 0; - list_splice(&pchan->active, &pchan->done); + list_splice_init(&pchan->active, &pchan->done); spin_unlock_irqrestore(&pchan->lock, flags); - mutex_unlock(&mxs_dma_mutex); } EXPORT_SYMBOL(mxs_dma_disable); diff --git a/arch/arm/plat-mxs/gpio.c b/arch/arm/plat-mxs/gpio.c index f12d417b03e9..6c67c2bcfc5b 100644 --- a/arch/arm/plat-mxs/gpio.c +++ b/arch/arm/plat-mxs/gpio.c @@ -175,6 +175,8 @@ static struct irq_chip gpio_irq_chip = { .ack = mxs_gpio_ack_irq, .mask = mxs_gpio_mask_irq, .unmask = mxs_gpio_unmask_irq, + .enable = mxs_gpio_unmask_irq, + .disable = mxs_gpio_mask_irq, .set_type = mxs_gpio_set_irq_type, }; diff --git a/arch/arm/plat-mxs/icoll.c b/arch/arm/plat-mxs/icoll.c index bb4e4c12cb23..1e0b55bd26a9 100644 --- a/arch/arm/plat-mxs/icoll.c +++ b/arch/arm/plat-mxs/icoll.c @@ -56,10 +56,16 @@ static void icoll_unmask_irq(unsigned int irq) g_icoll_base + HW_ICOLL_INTERRUPTn_SET(irq)); } +static int icoll_set_wake_irq(unsigned int irq, unsigned int enabled) +{ + return 0; +} + static struct irq_chip icoll_chip = { .ack = icoll_ack_irq, .mask = icoll_mask_irq, .unmask = icoll_unmask_irq, + .set_wake = icoll_set_wake_irq, }; void __init avic_init_irq(void __iomem *base, int nr_irqs) diff --git a/arch/arm/plat-mxs/include/mach/bus_freq.h b/arch/arm/plat-mxs/include/mach/bus_freq.h index a0254e84ca5c..0c41cd2205ff 100644 --- a/arch/arm/plat-mxs/include/mach/bus_freq.h +++ b/arch/arm/plat-mxs/include/mach/bus_freq.h @@ -33,13 +33,14 @@ struct profile { int cur; int vddio; int vdda; - int pll_off; + u16 xbus; + /* map of the upper 16 bits of HW_CLKCTRL_HBUS register */ + u16 h_autoslow_flags; }; -void hbus_auto_slow_mode_enable(void); -void hbus_auto_slow_mode_disable(void); -extern int cpu_clk_set_pll_on(struct clk *clk, unsigned int freq); -extern int cpu_clk_set_pll_off(struct clk *clk, unsigned int freq); +/* map of the upper 16 bits of HW_CLKCTRL_HBUS register */ +int is_hclk_autoslow_ok(void); + extern int timing_ctrl_rams(int ss); #endif diff --git a/arch/arm/plat-mxs/include/mach/clock.h b/arch/arm/plat-mxs/include/mach/clock.h index 744a031b42b6..b506468976b5 100644 --- a/arch/arm/plat-mxs/include/mach/clock.h +++ b/arch/arm/plat-mxs/include/mach/clock.h @@ -30,11 +30,12 @@ struct clk { struct clk *secondary; unsigned long flags; - __s8 ref; + int ref; unsigned int scale_bits; unsigned int enable_bits; unsigned int bypass_bits; unsigned int busy_bits; + unsigned int xtal_busy_bits; unsigned int wait:1; unsigned int invert:1; @@ -71,16 +72,24 @@ struct clk { void (*disable) (struct clk *); /* Function ptr to set the parent clock of the clock. */ int (*set_parent) (struct clk *, struct clk *); + + /* Function ptr to change the parent clock depending + * the system configuration at that time. Will only + * change the parent clock if the ref count is 0 (the clock + * is not being used) + */ + int (*set_sys_dependent_parent) (struct clk *); + }; int clk_get_usecount(struct clk *clk); extern int clk_register(struct clk_lookup *lookup); extern void clk_unregister(struct clk_lookup *lookup); -static inline int clk_is_busy(struct clk *clk) -{ - return __raw_readl(clk->busy_reg) & (1 << clk->busy_bits); -} +bool clk_enable_h_autoslow(bool enable); +void clk_set_h_autoslow_flags(u16 mask); +void clk_en_public_h_asm_ctrl(bool (*enable_func)(bool), + void (*set_func)(u16)); struct mxs_emi_scaling_data { u32 emi_div; @@ -89,6 +98,8 @@ struct mxs_emi_scaling_data { u32 new_freq; }; + + #ifdef CONFIG_MXS_RAM_FREQ_SCALING extern int mxs_ram_freq_scale(struct mxs_emi_scaling_data *); extern u32 mxs_ram_funcs_sz; diff --git a/arch/arm/plat-mxs/include/mach/device.h b/arch/arm/plat-mxs/include/mach/device.h index 7a99647ed0ff..199ec1e62963 100644 --- a/arch/arm/plat-mxs/include/mach/device.h +++ b/arch/arm/plat-mxs/include/mach/device.h @@ -54,6 +54,12 @@ struct mxs_dma_plat_data { unsigned int chan_num; }; +struct fsl_otp_data { + char **fuse_name; + char *regulator_name; + unsigned int fuse_num; +}; + struct mxs_i2c_plat_data { unsigned int pioqueue_mode:1; }; @@ -119,6 +125,11 @@ struct mxs_mma7450_platform_data { int int2; }; +struct mxs_spi_platform_data { + int (*hw_pin_init)(void); + int (*hw_pin_release)(void); +}; + struct flexcan_platform_data { char *core_reg; char *io_reg; @@ -169,57 +180,6 @@ struct mxs_audio_platform_data { void *priv; /* used by board specific functions */ }; -/** - * struct gpmi_platform_data - GPMI driver platform data. - * - * This structure communicates platform-specific information to the GPMI driver - * that can't be expressed as resources. - * - * @io_uA: The current limit, in uA. - * @min_prop_delay_in_ns: Minimum propagation delay of GPMI signals to and - * from the NAND Flash device, in nanoseconds. - * @max_prop_delay_in_ns: Maximum propagation delay of GPMI signals to and - * from the NAND Flash device, in nanoseconds. - * @pinmux_handler: A pointer to a function the driver will call to - * request the pins it needs. - * @boot_area_size_in_bytes: The amount of space reserved for use by the boot - * ROM on the first and second chips. If this value is - * zero, it indicates we're not reserving any space - * for the boot area. - * @partition_source_types: An array of strings that name sources of - * partitioning information (e.g., the boot loader, - * the kernel command line, etc.). The function - * parse_mtd_partitions() recognizes these names and - * applies the appropriate "plugins" to discover - * partitioning information. If any is found, it will - * be applied to the "general use" MTD (it will NOT - * override the boot area protection mechanism). - * @partitions: An optional pointer to an array of partition - * descriptions. If the driver finds no partitioning - * information elsewhere, it will apply these to the - * "general use" MTD (they do NOT override the boot - * area protection mechanism). - * @partition_count: The number of elements in the partitions array. - */ - -struct gpmi_platform_data { - - int io_uA; - - unsigned min_prop_delay_in_ns; - unsigned max_prop_delay_in_ns; - - int (*pinmux_handler)(void); - - uint32_t boot_area_size_in_bytes; - - const char **partition_source_types; - - struct mtd_partition *partitions; - unsigned partition_count; - -}; - struct mxs_persistent_bit_config { int reg; int start; diff --git a/arch/arm/plat-mxs/include/mach/dmaengine.h b/arch/arm/plat-mxs/include/mach/dmaengine.h index eecd260ac5b4..cdf6b1e32a43 100644 --- a/arch/arm/plat-mxs/include/mach/dmaengine.h +++ b/arch/arm/plat-mxs/include/mach/dmaengine.h @@ -106,6 +106,7 @@ struct mxs_dma_info { #define MXS_DMA_INFO_ERR 0x00000001 #define MXS_DMA_INFO_ERR_STAT 0x00010000 unsigned int buf_addr; + unsigned int xfer_count; }; /** diff --git a/arch/arm/plat-mxs/include/mach/system.h b/arch/arm/plat-mxs/include/mach/system.h index 63604de8d74a..faaa2ff3cf13 100644 --- a/arch/arm/plat-mxs/include/mach/system.h +++ b/arch/arm/plat-mxs/include/mach/system.h @@ -25,5 +25,6 @@ extern void arch_idle(void); void arch_reset(char mode, const char *cmd); extern void (*machine_arch_reset)(char mode, const char *cmd); int mxs_reset_block(void __iomem *hwreg, int just_enable); +int get_evk_board_version(void); #endif /* __ASM_ARCH_SYSTEM_H__ */ diff --git a/arch/arm/plat-mxs/include/mach/timex.h b/arch/arm/plat-mxs/include/mach/timex.h index 9db3d688223a..d622dda141f2 100644 --- a/arch/arm/plat-mxs/include/mach/timex.h +++ b/arch/arm/plat-mxs/include/mach/timex.h @@ -20,4 +20,4 @@ /* * System time clock is sourced from the 32k clock */ -#define CLOCK_TICK_RATE 32768 +#define CLOCK_TICK_RATE 32000 diff --git a/arch/arm/plat-mxs/iram.c b/arch/arm/plat-mxs/iram.c index 3d2a391bd2d1..c63b0a2a9a10 100644 --- a/arch/arm/plat-mxs/iram.c +++ b/arch/arm/plat-mxs/iram.c @@ -36,6 +36,11 @@ void *iram_alloc(unsigned int size, unsigned long *dma_addr) *dma_addr = gen_pool_alloc(iram_pool, size); pr_debug("iram alloc - %dB@0x%p\n", size, (void *)*dma_addr); + + WARN_ON(!*dma_addr); + if (!*dma_addr) + return NULL; + return iram_phys_to_virt(*dma_addr); } EXPORT_SYMBOL(iram_alloc); diff --git a/arch/arm/plat-mxs/timer-nomatch.c b/arch/arm/plat-mxs/timer-nomatch.c index 66c488c99b42..db8906192f16 100644 --- a/arch/arm/plat-mxs/timer-nomatch.c +++ b/arch/arm/plat-mxs/timer-nomatch.c @@ -21,6 +21,7 @@ #include <linux/clocksource.h> #include <linux/clockchips.h> #include <linux/io.h> +#include <linux/clk.h> #include <linux/irq.h> #include <linux/interrupt.h> @@ -119,9 +120,9 @@ void mxs_nomatch_timer_init(struct mxs_sys_timer *timer) online_timer = timer; - cksrc_mxs_nomatch.mult = clocksource_hz2mult(CLOCK_TICK_RATE, + cksrc_mxs_nomatch.mult = clocksource_hz2mult(clk_get_rate(timer->clk), cksrc_mxs_nomatch.shift); - ckevt_timrot.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, + ckevt_timrot.mult = div_sc(clk_get_rate(timer->clk), NSEC_PER_SEC, ckevt_timrot.shift); ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot); ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot); @@ -145,7 +146,7 @@ void mxs_nomatch_timer_init(struct mxs_sys_timer *timer) BM_TIMROT_TIMCTRLn_IRQ_EN, online_timer->base + HW_TIMROT_TIMCTRLn(1)); - __raw_writel(CLOCK_TICK_RATE / HZ - 1, + __raw_writel(clk_get_rate(timer->clk) / HZ - 1, online_timer->base + HW_TIMROT_TIMCOUNTn(0)); __raw_writel(0xFFFF, online_timer->base + HW_TIMROT_TIMCOUNTn(1)); @@ -181,7 +182,7 @@ void mxs_nomatch_resume_timer(void) BM_TIMROT_TIMCTRLn_UPDATE | BM_TIMROT_TIMCTRLn_IRQ_EN, online_timer->base + HW_TIMROT_TIMCTRLn(1)); - __raw_writel(CLOCK_TICK_RATE / HZ - 1, + __raw_writel(clk_get_rate(online_timer->clk) / HZ - 1, online_timer->base + HW_TIMROT_TIMCOUNTn(0)); __raw_writel(0xFFFF, online_timer->base + HW_TIMROT_TIMCOUNTn(1)); } diff --git a/arch/arm/plat-mxs/usb_common.c b/arch/arm/plat-mxs/usb_common.c index 5d8d0b6d9285..23134489472e 100644 --- a/arch/arm/plat-mxs/usb_common.c +++ b/arch/arm/plat-mxs/usb_common.c @@ -264,13 +264,16 @@ int usbotg_init(struct platform_device *pdev) pdata->xcvr_type = xops->xcvr_type; pdata->pdev = pdev; - otg_used = 0; if (!otg_used) { pr_debug("%s: grab pins\n", __func__); if (xops->init) xops->init(xops); usb_phy_enable(pdata); } + /* Enable internal Phy clock */ + tmp = __raw_readl(pdata->regs + UOG_PORTSC1); + tmp &= ~PORTSC_PHCD; + __raw_writel(tmp, pdata->regs + UOG_PORTSC1); if (pdata->operating_mode == FSL_USB2_DR_HOST) { /* enable FS/LS device */ @@ -288,11 +291,22 @@ EXPORT_SYMBOL(usbotg_init); void usbotg_uninit(struct fsl_usb2_platform_data *pdata) { + int tmp; + struct clk *usb_clk; pr_debug("%s\n", __func__); if (pdata->xcvr_ops && pdata->xcvr_ops->uninit) pdata->xcvr_ops->uninit(pdata->xcvr_ops); + /* Disable internal Phy clock */ + tmp = __raw_readl(pdata->regs + UOG_PORTSC1); + tmp |= PORTSC_PHCD; + __raw_writel(tmp, pdata->regs + UOG_PORTSC1); + + usb_clk = clk_get(NULL, "usb_clk0"); + clk_disable(usb_clk); + clk_put(usb_clk); + pdata->regs = NULL; otg_used--; } @@ -331,11 +345,16 @@ EXPORT_SYMBOL(fsl_usb_host_init); void fsl_usb_host_uninit(struct fsl_usb2_platform_data *pdata) { + struct clk *usb_clk; pr_debug("%s\n", __func__); if (pdata->xcvr_ops && pdata->xcvr_ops->uninit) pdata->xcvr_ops->uninit(pdata->xcvr_ops); + usb_clk = clk_get(NULL, "usb_clk1"); + clk_disable(usb_clk); + clk_put(usb_clk); + pdata->regs = NULL; } EXPORT_SYMBOL(fsl_usb_host_uninit); diff --git a/arch/arm/plat-mxs/utmixc.c b/arch/arm/plat-mxs/utmixc.c index 1e9015d6de3f..8e842840e87a 100644 --- a/arch/arm/plat-mxs/utmixc.c +++ b/arch/arm/plat-mxs/utmixc.c @@ -45,7 +45,7 @@ static void set_vbus_draw(struct fsl_xcvr_ops *this, { #ifdef CONFIG_MXS_VBUS_CURRENT_DRAW if ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) - & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x8000) { + & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x20000) { printk(KERN_INFO "USB enumeration done,current limitation release\r\n"); __raw_writel(__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) | BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT, REGS_POWER_BASE + @@ -80,7 +80,7 @@ static void __exit utmixc_exit(void) #ifdef CONFIG_MXS_VBUS_CURRENT_DRAW fs_initcall(utmixc_init); #else - module_init(utmixc_init); + subsys_initcall(utmixc_init); #endif module_exit(utmixc_exit); diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index ebe0ea313658..817425c8e732 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -1319,7 +1319,7 @@ mistral MACH_MISTRAL MISTRAL 1315 msm MACH_MSM MSM 1316 ct5910 MACH_CT5910 CT5910 1317 ct5912 MACH_CT5912 CT5912 1318 -hynet_ine MACH_HYNET_INE HYNET_INE 1319 +argonst_foundation MACH_HYNET_INE HYNET_INE 1319 hynet_app MACH_HYNET_APP HYNET_APP 1320 msm7200 MACH_MSM7200 MSM7200 1321 msm7600 MACH_MSM7600 MSM7600 1322 @@ -2257,7 +2257,7 @@ oratisalog MACH_ORATISALOG ORATISALOG 2268 oratismadi MACH_ORATISMADI ORATISMADI 2269 oratisot16 MACH_ORATISOT16 ORATISOT16 2270 oratisdesk MACH_ORATISDESK ORATISDESK 2271 -v2_ca9 MACH_V2P_CA9 V2P_CA9 2272 +vexpress MACH_VEXPRESS VEXPRESS 2272 sintexo MACH_SINTEXO SINTEXO 2273 cm3389 MACH_CM3389 CM3389 2274 omap3_cio MACH_OMAP3_CIO OMAP3_CIO 2275 @@ -2308,7 +2308,7 @@ ecac2378 MACH_ECAC2378 ECAC2378 2319 tazkiosk MACH_TAZKIOSK TAZKIOSK 2320 whiterabbit_mch MACH_WHITERABBIT_MCH WHITERABBIT_MCH 2321 sbox9263 MACH_SBOX9263 SBOX9263 2322 -oreo MACH_OREO OREO 2323 +oreo_camera MACH_OREO OREO 2323 smdk6442 MACH_SMDK6442 SMDK6442 2324 openrd_base MACH_OPENRD_BASE OPENRD_BASE 2325 incredible MACH_INCREDIBLE INCREDIBLE 2326 @@ -2498,7 +2498,7 @@ hiram MACH_HIRAM HIRAM 2510 phy3250 MACH_PHY3250 PHY3250 2511 ea3250 MACH_EA3250 EA3250 2512 fdi3250 MACH_FDI3250 FDI3250 2513 -whitestone MACH_WHITESTONE WHITESTONE 2514 +htcwhitestone MACH_WHITESTONE WHITESTONE 2514 at91sam9263nit MACH_AT91SAM9263NIT AT91SAM9263NIT 2515 ccmx51 MACH_CCMX51 CCMX51 2516 ccmx51js MACH_CCMX51JS CCMX51JS 2517 @@ -2594,4 +2594,7 @@ spacecom1 MACH_SPACECOM1 SPACECOM1 2604 pingu920 MACH_PINGU920 PINGU920 2605 bravoc MACH_BRAVOC BRAVOC 2606 cybo2440 MACH_CYBO2440 CYBO2440 2607 +mx50_arm2 MACH_MX50_ARM2 MX50_ARM2 2955 +mx50_rdp MACH_MX50_RDP MX50_RDP 2988 + diff --git a/block/genhd.c b/block/genhd.c index f4c64c2b303a..c0c7f38c7012 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -992,6 +992,22 @@ static void disk_release(struct device *dev) free_part_stats(&disk->part0); kfree(disk); } + +static int disk_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct gendisk *disk = dev_to_disk(dev); + struct disk_part_iter piter; + struct hd_struct *part; + int cnt = 0; + + disk_part_iter_init(&piter, disk, 0); + while((part = disk_part_iter_next(&piter))) + cnt++; + disk_part_iter_exit(&piter); + add_uevent_var(env, "NPARTS=%u", cnt); + return 0; +} + struct class block_class = { .name = "block", }; @@ -1010,6 +1026,7 @@ static struct device_type disk_type = { .groups = disk_attr_groups, .release = disk_release, .nodename = block_nodename, + .uevent = disk_uevent, }; #ifdef CONFIG_PROC_FS diff --git a/drivers/Kconfig b/drivers/Kconfig index 48bbdbe43e69..5dacbbd42483 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -90,6 +90,8 @@ source "drivers/memstick/Kconfig" source "drivers/leds/Kconfig" +source "drivers/switch/Kconfig" + source "drivers/accessibility/Kconfig" source "drivers/infiniband/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 4a9a1c55b598..c19a0c18e5ed 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -95,6 +95,7 @@ obj-$(CONFIG_ARCH_MXC) += mxc/ obj-$(CONFIG_MMC) += mmc/ obj-$(CONFIG_MEMSTICK) += memstick/ obj-$(CONFIG_NEW_LEDS) += leds/ +obj-$(CONFIG_SWITCH) += switch/ obj-$(CONFIG_INFINIBAND) += infiniband/ obj-$(CONFIG_SGI_SN) += sn/ obj-y += firmware/ diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index ae02b4114a6f..d7198890cdd3 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -55,6 +55,14 @@ config SATA_AHCI If unsure, say N. +config SATA_AHCI_PLATFORM + tristate "Platform AHCI SATA support" + help + This option enables support for Platform AHCI Serial ATA + controllers. + + If unsure, say N. + config SATA_SIL24 tristate "Silicon Image 3124/3132 SATA support" depends on PCI @@ -72,6 +80,7 @@ config SATA_FSL If unsure, say N. + config ATA_SFF bool "ATA SFF support" default y @@ -759,6 +768,14 @@ config PATA_FSL ATA interface. If you are unsure, say N to this. +config PATA_FSL_DISABLE_DMA + bool "Disable DMA on Freescale on-chip PATA devices" + depends on PATA_FSL + default y + help + Say yes to disable the Ultra DMA and Multi Word DMA transfers on + Freescale PATA SoC interface. + endif # ATA_SFF endif # ATA diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index de9fda120642..69bcefa0df6b 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -1,7 +1,8 @@ obj-$(CONFIG_ATA) += libata.o -obj-$(CONFIG_SATA_AHCI) += ahci.o +obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o +obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o obj-$(CONFIG_SATA_SVW) += sata_svw.o obj-$(CONFIG_ATA_PIIX) += ata_piix.o obj-$(CONFIG_SATA_PROMISE) += sata_promise.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index fe3eba5d6b3e..edc9b0ec9f39 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -45,64 +45,13 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_cmnd.h> #include <linux/libata.h> +#include "ahci.h" #define DRV_NAME "ahci" #define DRV_VERSION "3.0" -/* Enclosure Management Control */ -#define EM_CTRL_MSG_TYPE 0x000f0000 - -/* Enclosure Management LED Message Type */ -#define EM_MSG_LED_HBA_PORT 0x0000000f -#define EM_MSG_LED_PMP_SLOT 0x0000ff00 -#define EM_MSG_LED_VALUE 0xffff0000 -#define EM_MSG_LED_VALUE_ACTIVITY 0x00070000 -#define EM_MSG_LED_VALUE_OFF 0xfff80000 -#define EM_MSG_LED_VALUE_ON 0x00010000 - -static int ahci_skip_host_reset; -static int ahci_ignore_sss; - -module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444); -MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)"); - -module_param_named(ignore_sss, ahci_ignore_sss, int, 0444); -MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)"); - -static int ahci_enable_alpm(struct ata_port *ap, - enum link_pm policy); -static void ahci_disable_alpm(struct ata_port *ap); -static ssize_t ahci_led_show(struct ata_port *ap, char *buf); -static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, - size_t size); -static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, - ssize_t size); - enum { AHCI_PCI_BAR = 5, - AHCI_MAX_PORTS = 32, - AHCI_MAX_SG = 168, /* hardware max is 64K */ - AHCI_DMA_BOUNDARY = 0xffffffff, - AHCI_MAX_CMDS = 32, - AHCI_CMD_SZ = 32, - AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ, - AHCI_RX_FIS_SZ = 256, - AHCI_CMD_TBL_CDB = 0x40, - AHCI_CMD_TBL_HDR_SZ = 0x80, - AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16), - AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS, - AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + - AHCI_RX_FIS_SZ, - AHCI_IRQ_ON_SG = (1 << 31), - AHCI_CMD_ATAPI = (1 << 5), - AHCI_CMD_WRITE = (1 << 6), - AHCI_CMD_PREFETCH = (1 << 7), - AHCI_CMD_RESET = (1 << 8), - AHCI_CMD_CLR_BUSY = (1 << 10), - - RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ - RX_FIS_SDB = 0x58, /* offset of SDB FIS data */ - RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ board_ahci = 0, board_ahci_vt8251 = 1, @@ -113,280 +62,20 @@ enum { board_ahci_mcp65 = 6, board_ahci_nopmp = 7, board_ahci_yesncq = 8, - - /* global controller registers */ - HOST_CAP = 0x00, /* host capabilities */ - HOST_CTL = 0x04, /* global host control */ - HOST_IRQ_STAT = 0x08, /* interrupt status */ - HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */ - HOST_VERSION = 0x10, /* AHCI spec. version compliancy */ - HOST_EM_LOC = 0x1c, /* Enclosure Management location */ - HOST_EM_CTL = 0x20, /* Enclosure Management Control */ - - /* HOST_CTL bits */ - HOST_RESET = (1 << 0), /* reset controller; self-clear */ - HOST_IRQ_EN = (1 << 1), /* global IRQ enable */ - HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ - - /* HOST_CAP bits */ - HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */ - HOST_CAP_SSC = (1 << 14), /* Slumber capable */ - HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ - HOST_CAP_CLO = (1 << 24), /* Command List Override support */ - HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */ - HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ - HOST_CAP_SNTF = (1 << 29), /* SNotification register */ - HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ - HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ - - /* registers for each SATA port */ - PORT_LST_ADDR = 0x00, /* command list DMA addr */ - PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */ - PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */ - PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */ - PORT_IRQ_STAT = 0x10, /* interrupt status */ - PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */ - PORT_CMD = 0x18, /* port command */ - PORT_TFDATA = 0x20, /* taskfile data */ - PORT_SIG = 0x24, /* device TF signature */ - PORT_CMD_ISSUE = 0x38, /* command issue */ - PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */ - PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */ - PORT_SCR_ERR = 0x30, /* SATA phy register: SError */ - PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */ - PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */ - - /* PORT_IRQ_{STAT,MASK} bits */ - PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ - PORT_IRQ_TF_ERR = (1 << 30), /* task file error */ - PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */ - PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */ - PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */ - PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */ - PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */ - PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */ - - PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */ - PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */ - PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */ - PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */ - PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */ - PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */ - PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */ - PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ - PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ - - PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | - PORT_IRQ_IF_ERR | - PORT_IRQ_CONNECT | - PORT_IRQ_PHYRDY | - PORT_IRQ_UNK_FIS | - PORT_IRQ_BAD_PMP, - PORT_IRQ_ERROR = PORT_IRQ_FREEZE | - PORT_IRQ_TF_ERR | - PORT_IRQ_HBUS_DATA_ERR, - DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | - PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | - PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, - - /* PORT_CMD bits */ - PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */ - PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */ - PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ - PORT_CMD_PMP = (1 << 17), /* PMP attached */ - PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ - PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ - PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ - PORT_CMD_CLO = (1 << 3), /* Command list override */ - PORT_CMD_POWER_ON = (1 << 2), /* Power up device */ - PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ - PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ - - PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */ - PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ - PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ - PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ - - /* hpriv->flags bits */ - AHCI_HFLAG_NO_NCQ = (1 << 0), - AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ - AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */ - AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */ - AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ - AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ - AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ - AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */ - AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ - AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ - AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */ - AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = (1 << 11), /* treat SRST timeout as - link offline */ - - /* ap->flags bits */ - - AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | - ATA_FLAG_ACPI_SATA | ATA_FLAG_AN | - ATA_FLAG_IPM, - - ICH_MAP = 0x90, /* ICH MAP register */ - - /* em constants */ - EM_MAX_SLOTS = 8, - EM_MAX_RETRY = 5, - - /* em_ctl bits */ - EM_CTL_RST = (1 << 9), /* Reset */ - EM_CTL_TM = (1 << 8), /* Transmit Message */ - EM_CTL_ALHD = (1 << 26), /* Activity LED */ -}; - -struct ahci_cmd_hdr { - __le32 opts; - __le32 status; - __le32 tbl_addr; - __le32 tbl_addr_hi; - __le32 reserved[4]; -}; - -struct ahci_sg { - __le32 addr; - __le32 addr_hi; - __le32 reserved; - __le32 flags_size; + board_ahci_nosntf = 9, }; -struct ahci_em_priv { - enum sw_activity blink_policy; - struct timer_list timer; - unsigned long saved_activity; - unsigned long activity; - unsigned long led_state; -}; - -struct ahci_host_priv { - unsigned int flags; /* AHCI_HFLAG_* */ - u32 cap; /* cap to use */ - u32 port_map; /* port map to use */ - u32 saved_cap; /* saved initial cap */ - u32 saved_port_map; /* saved initial port_map */ - u32 em_loc; /* enclosure management location */ -}; - -struct ahci_port_priv { - struct ata_link *active_link; - struct ahci_cmd_hdr *cmd_slot; - dma_addr_t cmd_slot_dma; - void *cmd_tbl; - dma_addr_t cmd_tbl_dma; - void *rx_fis; - dma_addr_t rx_fis_dma; - /* for NCQ spurious interrupt analysis */ - unsigned int ncq_saw_d2h:1; - unsigned int ncq_saw_dmas:1; - unsigned int ncq_saw_sdb:1; - u32 intr_mask; /* interrupts to enable */ - /* enclosure management info per PM slot */ - struct ahci_em_priv em_priv[EM_MAX_SLOTS]; -}; - -static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); -static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); -static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc); -static int ahci_port_start(struct ata_port *ap); -static void ahci_port_stop(struct ata_port *ap); -static void ahci_qc_prep(struct ata_queued_cmd *qc); -static void ahci_freeze(struct ata_port *ap); -static void ahci_thaw(struct ata_port *ap); -static void ahci_pmp_attach(struct ata_port *ap); -static void ahci_pmp_detach(struct ata_port *ap); -static int ahci_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline); -static int ahci_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline); static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); -static void ahci_postreset(struct ata_link *link, unsigned int *class); -static void ahci_error_handler(struct ata_port *ap); -static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); -static int ahci_port_resume(struct ata_port *ap); -static void ahci_dev_config(struct ata_device *dev); -static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, - u32 opts); #ifdef CONFIG_PM -static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); static int ahci_pci_device_resume(struct pci_dev *pdev); #endif -static ssize_t ahci_activity_show(struct ata_device *dev, char *buf); -static ssize_t ahci_activity_store(struct ata_device *dev, - enum sw_activity val); -static void ahci_init_sw_activity(struct ata_link *link); - -static struct device_attribute *ahci_shost_attrs[] = { - &dev_attr_link_power_management_policy, - &dev_attr_em_message_type, - &dev_attr_em_message, - NULL -}; - -static struct device_attribute *ahci_sdev_attrs[] = { - &dev_attr_sw_activity, - &dev_attr_unload_heads, - NULL -}; - -static struct scsi_host_template ahci_sht = { - ATA_NCQ_SHT(DRV_NAME), - .can_queue = AHCI_MAX_CMDS - 1, - .sg_tablesize = AHCI_MAX_SG, - .dma_boundary = AHCI_DMA_BOUNDARY, - .shost_attrs = ahci_shost_attrs, - .sdev_attrs = ahci_sdev_attrs, -}; - -static struct ata_port_operations ahci_ops = { - .inherits = &sata_pmp_port_ops, - - .qc_defer = sata_pmp_qc_defer_cmd_switch, - .qc_prep = ahci_qc_prep, - .qc_issue = ahci_qc_issue, - .qc_fill_rtf = ahci_qc_fill_rtf, - - .freeze = ahci_freeze, - .thaw = ahci_thaw, - .softreset = ahci_softreset, - .hardreset = ahci_hardreset, - .postreset = ahci_postreset, - .pmp_softreset = ahci_softreset, - .error_handler = ahci_error_handler, - .post_internal_cmd = ahci_post_internal_cmd, - .dev_config = ahci_dev_config, - - .scr_read = ahci_scr_read, - .scr_write = ahci_scr_write, - .pmp_attach = ahci_pmp_attach, - .pmp_detach = ahci_pmp_detach, - - .enable_pm = ahci_enable_alpm, - .disable_pm = ahci_disable_alpm, - .em_show = ahci_led_show, - .em_store = ahci_led_store, - .sw_activity_show = ahci_activity_show, - .sw_activity_store = ahci_activity_store, -#ifdef CONFIG_PM - .port_suspend = ahci_port_suspend, - .port_resume = ahci_port_resume, -#endif - .port_start = ahci_port_start, - .port_stop = ahci_port_stop, -}; static struct ata_port_operations ahci_vt8251_ops = { .inherits = &ahci_ops, @@ -473,7 +162,7 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, - /* board_ahci_yesncq */ + [board_ahci_yesncq] = { AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ), .flags = AHCI_FLAG_COMMON, @@ -481,6 +170,14 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, + [board_ahci_nosntf] = + { + AHCI_HFLAGS (AHCI_HFLAG_NO_SNTF), + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, }; static const struct pci_device_id ahci_pci_tbl[] = { @@ -496,7 +193,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */ + { PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf }, /* ICH8 */ { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */ { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */ { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */ @@ -644,12 +341,6 @@ static struct pci_driver ahci_pci_driver = { #endif }; -static int ahci_em_messages = 1; -module_param(ahci_em_messages, int, 0444); -/* add other LED protocol types when they become supported */ -MODULE_PARM_DESC(ahci_em_messages, - "Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED"); - #if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE) static int marvell_enable; #else @@ -659,112 +350,15 @@ module_param(marvell_enable, int, 0644); MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)"); -static inline int ahci_nr_ports(u32 cap) -{ - return (cap & 0x1f) + 1; -} - -static inline void __iomem *__ahci_port_base(struct ata_host *host, - unsigned int port_no) -{ - void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; - - return mmio + 0x100 + (port_no * 0x80); -} - -static inline void __iomem *ahci_port_base(struct ata_port *ap) -{ - return __ahci_port_base(ap->host, ap->port_no); -} - -static void ahci_enable_ahci(void __iomem *mmio) -{ - int i; - u32 tmp; - - /* turn on AHCI_EN */ - tmp = readl(mmio + HOST_CTL); - if (tmp & HOST_AHCI_EN) - return; - - /* Some controllers need AHCI_EN to be written multiple times. - * Try a few times before giving up. - */ - for (i = 0; i < 5; i++) { - tmp |= HOST_AHCI_EN; - writel(tmp, mmio + HOST_CTL); - tmp = readl(mmio + HOST_CTL); /* flush && sanity check */ - if (tmp & HOST_AHCI_EN) - return; - msleep(10); - } - - WARN_ON(1); -} - -/** - * ahci_save_initial_config - Save and fixup initial config values - * @pdev: target PCI device - * @hpriv: host private area to store config values - * - * Some registers containing configuration info might be setup by - * BIOS and might be cleared on reset. This function saves the - * initial values of those registers into @hpriv such that they - * can be restored after controller reset. - * - * If inconsistent, config values are fixed up by this function. - * - * LOCKING: - * None. - */ -static void ahci_save_initial_config(struct pci_dev *pdev, - struct ahci_host_priv *hpriv) +static void ahci_pci_save_initial_config(struct pci_dev *pdev, + struct ahci_host_priv *hpriv) { - void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; - u32 cap, port_map; - int i; - int mv; - - /* make sure AHCI mode is enabled before accessing CAP */ - ahci_enable_ahci(mmio); + unsigned int force_port_map = 0; + unsigned int mask_port_map = 0; - /* Values prefixed with saved_ are written back to host after - * reset. Values without are used for driver operation. - */ - hpriv->saved_cap = cap = readl(mmio + HOST_CAP); - hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); - - /* some chips have errata preventing 64bit use */ - if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) { - dev_printk(KERN_INFO, &pdev->dev, - "controller can't do 64bit DMA, forcing 32bit\n"); - cap &= ~HOST_CAP_64; - } - - if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) { - dev_printk(KERN_INFO, &pdev->dev, - "controller can't do NCQ, turning off CAP_NCQ\n"); - cap &= ~HOST_CAP_NCQ; - } - - if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) { - dev_printk(KERN_INFO, &pdev->dev, - "controller can do NCQ, turning on CAP_NCQ\n"); - cap |= HOST_CAP_NCQ; - } - - if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { - dev_printk(KERN_INFO, &pdev->dev, - "controller can't do PMP, turning off CAP_PMP\n"); - cap &= ~HOST_CAP_PMP; - } - - if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 && - port_map != 1) { - dev_printk(KERN_INFO, &pdev->dev, - "JMB361 has only one port, port_map 0x%x -> 0x%x\n", - port_map, 1); - port_map = 1; + if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) { + dev_info(&pdev->dev, "JMB361 has only one port\n"); + force_port_map = 1; } /* @@ -774,466 +368,25 @@ static void ahci_save_initial_config(struct pci_dev *pdev, */ if (hpriv->flags & AHCI_HFLAG_MV_PATA) { if (pdev->device == 0x6121) - mv = 0x3; + mask_port_map = 0x3; else - mv = 0xf; - dev_printk(KERN_ERR, &pdev->dev, - "MV_AHCI HACK: port_map %x -> %x\n", - port_map, - port_map & mv); - dev_printk(KERN_ERR, &pdev->dev, + mask_port_map = 0xf; + dev_info(&pdev->dev, "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n"); - - port_map &= mv; - } - - /* cross check port_map and cap.n_ports */ - if (port_map) { - int map_ports = 0; - - for (i = 0; i < AHCI_MAX_PORTS; i++) - if (port_map & (1 << i)) - map_ports++; - - /* If PI has more ports than n_ports, whine, clear - * port_map and let it be generated from n_ports. - */ - if (map_ports > ahci_nr_ports(cap)) { - dev_printk(KERN_WARNING, &pdev->dev, - "implemented port map (0x%x) contains more " - "ports than nr_ports (%u), using nr_ports\n", - port_map, ahci_nr_ports(cap)); - port_map = 0; - } - } - - /* fabricate port_map from cap.nr_ports */ - if (!port_map) { - port_map = (1 << ahci_nr_ports(cap)) - 1; - dev_printk(KERN_WARNING, &pdev->dev, - "forcing PORTS_IMPL to 0x%x\n", port_map); - - /* write the fixed up value to the PI register */ - hpriv->saved_port_map = port_map; - } - - /* record values to use during operation */ - hpriv->cap = cap; - hpriv->port_map = port_map; -} - -/** - * ahci_restore_initial_config - Restore initial config - * @host: target ATA host - * - * Restore initial config stored by ahci_save_initial_config(). - * - * LOCKING: - * None. - */ -static void ahci_restore_initial_config(struct ata_host *host) -{ - struct ahci_host_priv *hpriv = host->private_data; - void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; - - writel(hpriv->saved_cap, mmio + HOST_CAP); - writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL); - (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ -} - -static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg) -{ - static const int offset[] = { - [SCR_STATUS] = PORT_SCR_STAT, - [SCR_CONTROL] = PORT_SCR_CTL, - [SCR_ERROR] = PORT_SCR_ERR, - [SCR_ACTIVE] = PORT_SCR_ACT, - [SCR_NOTIFICATION] = PORT_SCR_NTF, - }; - struct ahci_host_priv *hpriv = ap->host->private_data; - - if (sc_reg < ARRAY_SIZE(offset) && - (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF))) - return offset[sc_reg]; - return 0; -} - -static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) -{ - void __iomem *port_mmio = ahci_port_base(link->ap); - int offset = ahci_scr_offset(link->ap, sc_reg); - - if (offset) { - *val = readl(port_mmio + offset); - return 0; - } - return -EINVAL; -} - -static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) -{ - void __iomem *port_mmio = ahci_port_base(link->ap); - int offset = ahci_scr_offset(link->ap, sc_reg); - - if (offset) { - writel(val, port_mmio + offset); - return 0; - } - return -EINVAL; -} - -static void ahci_start_engine(struct ata_port *ap) -{ - void __iomem *port_mmio = ahci_port_base(ap); - u32 tmp; - - /* start DMA */ - tmp = readl(port_mmio + PORT_CMD); - tmp |= PORT_CMD_START; - writel(tmp, port_mmio + PORT_CMD); - readl(port_mmio + PORT_CMD); /* flush */ -} - -static int ahci_stop_engine(struct ata_port *ap) -{ - void __iomem *port_mmio = ahci_port_base(ap); - u32 tmp; - - tmp = readl(port_mmio + PORT_CMD); - - /* check if the HBA is idle */ - if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0) - return 0; - - /* setting HBA to idle */ - tmp &= ~PORT_CMD_START; - writel(tmp, port_mmio + PORT_CMD); - - /* wait for engine to stop. This could be as long as 500 msec */ - tmp = ata_wait_register(port_mmio + PORT_CMD, - PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500); - if (tmp & PORT_CMD_LIST_ON) - return -EIO; - - return 0; -} - -static void ahci_start_fis_rx(struct ata_port *ap) -{ - void __iomem *port_mmio = ahci_port_base(ap); - struct ahci_host_priv *hpriv = ap->host->private_data; - struct ahci_port_priv *pp = ap->private_data; - u32 tmp; - - /* set FIS registers */ - if (hpriv->cap & HOST_CAP_64) - writel((pp->cmd_slot_dma >> 16) >> 16, - port_mmio + PORT_LST_ADDR_HI); - writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); - - if (hpriv->cap & HOST_CAP_64) - writel((pp->rx_fis_dma >> 16) >> 16, - port_mmio + PORT_FIS_ADDR_HI); - writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR); - - /* enable FIS reception */ - tmp = readl(port_mmio + PORT_CMD); - tmp |= PORT_CMD_FIS_RX; - writel(tmp, port_mmio + PORT_CMD); - - /* flush */ - readl(port_mmio + PORT_CMD); -} - -static int ahci_stop_fis_rx(struct ata_port *ap) -{ - void __iomem *port_mmio = ahci_port_base(ap); - u32 tmp; - - /* disable FIS reception */ - tmp = readl(port_mmio + PORT_CMD); - tmp &= ~PORT_CMD_FIS_RX; - writel(tmp, port_mmio + PORT_CMD); - - /* wait for completion, spec says 500ms, give it 1000 */ - tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON, - PORT_CMD_FIS_ON, 10, 1000); - if (tmp & PORT_CMD_FIS_ON) - return -EBUSY; - - return 0; -} - -static void ahci_power_up(struct ata_port *ap) -{ - struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *port_mmio = ahci_port_base(ap); - u32 cmd; - - cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; - - /* spin up device */ - if (hpriv->cap & HOST_CAP_SSS) { - cmd |= PORT_CMD_SPIN_UP; - writel(cmd, port_mmio + PORT_CMD); - } - - /* wake up link */ - writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); -} - -static void ahci_disable_alpm(struct ata_port *ap) -{ - struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *port_mmio = ahci_port_base(ap); - u32 cmd; - struct ahci_port_priv *pp = ap->private_data; - - /* IPM bits should be disabled by libata-core */ - /* get the existing command bits */ - cmd = readl(port_mmio + PORT_CMD); - - /* disable ALPM and ASP */ - cmd &= ~PORT_CMD_ASP; - cmd &= ~PORT_CMD_ALPE; - - /* force the interface back to active */ - cmd |= PORT_CMD_ICC_ACTIVE; - - /* write out new cmd value */ - writel(cmd, port_mmio + PORT_CMD); - cmd = readl(port_mmio + PORT_CMD); - - /* wait 10ms to be sure we've come out of any low power state */ - msleep(10); - - /* clear out any PhyRdy stuff from interrupt status */ - writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT); - - /* go ahead and clean out PhyRdy Change from Serror too */ - ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18))); - - /* - * Clear flag to indicate that we should ignore all PhyRdy - * state changes - */ - hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG; - - /* - * Enable interrupts on Phy Ready. - */ - pp->intr_mask |= PORT_IRQ_PHYRDY; - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); - - /* - * don't change the link pm policy - we can be called - * just to turn of link pm temporarily - */ -} - -static int ahci_enable_alpm(struct ata_port *ap, - enum link_pm policy) -{ - struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *port_mmio = ahci_port_base(ap); - u32 cmd; - struct ahci_port_priv *pp = ap->private_data; - u32 asp; - - /* Make sure the host is capable of link power management */ - if (!(hpriv->cap & HOST_CAP_ALPM)) - return -EINVAL; - - switch (policy) { - case MAX_PERFORMANCE: - case NOT_AVAILABLE: - /* - * if we came here with NOT_AVAILABLE, - * it just means this is the first time we - * have tried to enable - default to max performance, - * and let the user go to lower power modes on request. - */ - ahci_disable_alpm(ap); - return 0; - case MIN_POWER: - /* configure HBA to enter SLUMBER */ - asp = PORT_CMD_ASP; - break; - case MEDIUM_POWER: - /* configure HBA to enter PARTIAL */ - asp = 0; - break; - default: - return -EINVAL; - } - - /* - * Disable interrupts on Phy Ready. This keeps us from - * getting woken up due to spurious phy ready interrupts - * TBD - Hot plug should be done via polling now, is - * that even supported? - */ - pp->intr_mask &= ~PORT_IRQ_PHYRDY; - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); - - /* - * Set a flag to indicate that we should ignore all PhyRdy - * state changes since these can happen now whenever we - * change link state - */ - hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG; - - /* get the existing command bits */ - cmd = readl(port_mmio + PORT_CMD); - - /* - * Set ASP based on Policy - */ - cmd |= asp; - - /* - * Setting this bit will instruct the HBA to aggressively - * enter a lower power link state when it's appropriate and - * based on the value set above for ASP - */ - cmd |= PORT_CMD_ALPE; - - /* write out new cmd value */ - writel(cmd, port_mmio + PORT_CMD); - cmd = readl(port_mmio + PORT_CMD); - - /* IPM bits should be set by libata-core */ - return 0; -} - -#ifdef CONFIG_PM -static void ahci_power_down(struct ata_port *ap) -{ - struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *port_mmio = ahci_port_base(ap); - u32 cmd, scontrol; - - if (!(hpriv->cap & HOST_CAP_SSS)) - return; - - /* put device into listen mode, first set PxSCTL.DET to 0 */ - scontrol = readl(port_mmio + PORT_SCR_CTL); - scontrol &= ~0xf; - writel(scontrol, port_mmio + PORT_SCR_CTL); - - /* then set PxCMD.SUD to 0 */ - cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; - cmd &= ~PORT_CMD_SPIN_UP; - writel(cmd, port_mmio + PORT_CMD); -} -#endif - -static void ahci_start_port(struct ata_port *ap) -{ - struct ahci_port_priv *pp = ap->private_data; - struct ata_link *link; - struct ahci_em_priv *emp; - ssize_t rc; - int i; - - /* enable FIS reception */ - ahci_start_fis_rx(ap); - - /* enable DMA */ - ahci_start_engine(ap); - - /* turn on LEDs */ - if (ap->flags & ATA_FLAG_EM) { - ata_for_each_link(link, ap, EDGE) { - emp = &pp->em_priv[link->pmp]; - - /* EM Transmit bit maybe busy during init */ - for (i = 0; i < EM_MAX_RETRY; i++) { - rc = ahci_transmit_led_message(ap, - emp->led_state, - 4); - if (rc == -EBUSY) - msleep(1); - else - break; - } - } - } - - if (ap->flags & ATA_FLAG_SW_ACTIVITY) - ata_for_each_link(link, ap, EDGE) - ahci_init_sw_activity(link); - -} - -static int ahci_deinit_port(struct ata_port *ap, const char **emsg) -{ - int rc; - - /* disable DMA */ - rc = ahci_stop_engine(ap); - if (rc) { - *emsg = "failed to stop engine"; - return rc; - } - - /* disable FIS reception */ - rc = ahci_stop_fis_rx(ap); - if (rc) { - *emsg = "failed stop FIS RX"; - return rc; } - return 0; + ahci_save_initial_config(&pdev->dev, hpriv, force_port_map, + mask_port_map); } -static int ahci_reset_controller(struct ata_host *host) +static int ahci_pci_reset_controller(struct ata_host *host) { struct pci_dev *pdev = to_pci_dev(host->dev); - struct ahci_host_priv *hpriv = host->private_data; - void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; - u32 tmp; - /* we must be in AHCI mode, before using anything - * AHCI-specific, such as HOST_RESET. - */ - ahci_enable_ahci(mmio); - - /* global controller reset */ - if (!ahci_skip_host_reset) { - tmp = readl(mmio + HOST_CTL); - if ((tmp & HOST_RESET) == 0) { - writel(tmp | HOST_RESET, mmio + HOST_CTL); - readl(mmio + HOST_CTL); /* flush */ - } - - /* - * to perform host reset, OS should set HOST_RESET - * and poll until this bit is read to be "0". - * reset must complete within 1 second, or - * the hardware should be considered fried. - */ - tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET, - HOST_RESET, 10, 1000); - - if (tmp & HOST_RESET) { - dev_printk(KERN_ERR, host->dev, - "controller reset failed (0x%x)\n", tmp); - return -EIO; - } - - /* turn on AHCI mode */ - ahci_enable_ahci(mmio); - - /* Some registers might be cleared on reset. Restore - * initial values. - */ - ahci_restore_initial_config(host); - } else - dev_printk(KERN_INFO, host->dev, - "skipping global host reset\n"); + ahci_reset_controller(host); if (pdev->vendor == PCI_VENDOR_ID_INTEL) { + struct ahci_host_priv *hpriv = host->private_data; u16 tmp16; /* configure PCS */ @@ -1247,267 +400,10 @@ static int ahci_reset_controller(struct ata_host *host) return 0; } -static void ahci_sw_activity(struct ata_link *link) -{ - struct ata_port *ap = link->ap; - struct ahci_port_priv *pp = ap->private_data; - struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; - - if (!(link->flags & ATA_LFLAG_SW_ACTIVITY)) - return; - - emp->activity++; - if (!timer_pending(&emp->timer)) - mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10)); -} - -static void ahci_sw_activity_blink(unsigned long arg) -{ - struct ata_link *link = (struct ata_link *)arg; - struct ata_port *ap = link->ap; - struct ahci_port_priv *pp = ap->private_data; - struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; - unsigned long led_message = emp->led_state; - u32 activity_led_state; - unsigned long flags; - - led_message &= EM_MSG_LED_VALUE; - led_message |= ap->port_no | (link->pmp << 8); - - /* check to see if we've had activity. If so, - * toggle state of LED and reset timer. If not, - * turn LED to desired idle state. - */ - spin_lock_irqsave(ap->lock, flags); - if (emp->saved_activity != emp->activity) { - emp->saved_activity = emp->activity; - /* get the current LED state */ - activity_led_state = led_message & EM_MSG_LED_VALUE_ON; - - if (activity_led_state) - activity_led_state = 0; - else - activity_led_state = 1; - - /* clear old state */ - led_message &= ~EM_MSG_LED_VALUE_ACTIVITY; - - /* toggle state */ - led_message |= (activity_led_state << 16); - mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100)); - } else { - /* switch to idle */ - led_message &= ~EM_MSG_LED_VALUE_ACTIVITY; - if (emp->blink_policy == BLINK_OFF) - led_message |= (1 << 16); - } - spin_unlock_irqrestore(ap->lock, flags); - ahci_transmit_led_message(ap, led_message, 4); -} - -static void ahci_init_sw_activity(struct ata_link *link) -{ - struct ata_port *ap = link->ap; - struct ahci_port_priv *pp = ap->private_data; - struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; - - /* init activity stats, setup timer */ - emp->saved_activity = emp->activity = 0; - setup_timer(&emp->timer, ahci_sw_activity_blink, (unsigned long)link); - - /* check our blink policy and set flag for link if it's enabled */ - if (emp->blink_policy) - link->flags |= ATA_LFLAG_SW_ACTIVITY; -} - -static int ahci_reset_em(struct ata_host *host) -{ - void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; - u32 em_ctl; - - em_ctl = readl(mmio + HOST_EM_CTL); - if ((em_ctl & EM_CTL_TM) || (em_ctl & EM_CTL_RST)) - return -EINVAL; - - writel(em_ctl | EM_CTL_RST, mmio + HOST_EM_CTL); - return 0; -} - -static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, - ssize_t size) -{ - struct ahci_host_priv *hpriv = ap->host->private_data; - struct ahci_port_priv *pp = ap->private_data; - void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; - u32 em_ctl; - u32 message[] = {0, 0}; - unsigned long flags; - int pmp; - struct ahci_em_priv *emp; - - /* get the slot number from the message */ - pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8; - if (pmp < EM_MAX_SLOTS) - emp = &pp->em_priv[pmp]; - else - return -EINVAL; - - spin_lock_irqsave(ap->lock, flags); - - /* - * if we are still busy transmitting a previous message, - * do not allow - */ - em_ctl = readl(mmio + HOST_EM_CTL); - if (em_ctl & EM_CTL_TM) { - spin_unlock_irqrestore(ap->lock, flags); - return -EBUSY; - } - - /* - * create message header - this is all zero except for - * the message size, which is 4 bytes. - */ - message[0] |= (4 << 8); - - /* ignore 0:4 of byte zero, fill in port info yourself */ - message[1] = ((state & ~EM_MSG_LED_HBA_PORT) | ap->port_no); - - /* write message to EM_LOC */ - writel(message[0], mmio + hpriv->em_loc); - writel(message[1], mmio + hpriv->em_loc+4); - - /* save off new led state for port/slot */ - emp->led_state = state; - - /* - * tell hardware to transmit the message - */ - writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL); - - spin_unlock_irqrestore(ap->lock, flags); - return size; -} - -static ssize_t ahci_led_show(struct ata_port *ap, char *buf) -{ - struct ahci_port_priv *pp = ap->private_data; - struct ata_link *link; - struct ahci_em_priv *emp; - int rc = 0; - - ata_for_each_link(link, ap, EDGE) { - emp = &pp->em_priv[link->pmp]; - rc += sprintf(buf, "%lx\n", emp->led_state); - } - return rc; -} - -static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, - size_t size) -{ - int state; - int pmp; - struct ahci_port_priv *pp = ap->private_data; - struct ahci_em_priv *emp; - - state = simple_strtoul(buf, NULL, 0); - - /* get the slot number from the message */ - pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8; - if (pmp < EM_MAX_SLOTS) - emp = &pp->em_priv[pmp]; - else - return -EINVAL; - - /* mask off the activity bits if we are in sw_activity - * mode, user should turn off sw_activity before setting - * activity led through em_message - */ - if (emp->blink_policy) - state &= ~EM_MSG_LED_VALUE_ACTIVITY; - - return ahci_transmit_led_message(ap, state, size); -} - -static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val) -{ - struct ata_link *link = dev->link; - struct ata_port *ap = link->ap; - struct ahci_port_priv *pp = ap->private_data; - struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; - u32 port_led_state = emp->led_state; - - /* save the desired Activity LED behavior */ - if (val == OFF) { - /* clear LFLAG */ - link->flags &= ~(ATA_LFLAG_SW_ACTIVITY); - - /* set the LED to OFF */ - port_led_state &= EM_MSG_LED_VALUE_OFF; - port_led_state |= (ap->port_no | (link->pmp << 8)); - ahci_transmit_led_message(ap, port_led_state, 4); - } else { - link->flags |= ATA_LFLAG_SW_ACTIVITY; - if (val == BLINK_OFF) { - /* set LED to ON for idle */ - port_led_state &= EM_MSG_LED_VALUE_OFF; - port_led_state |= (ap->port_no | (link->pmp << 8)); - port_led_state |= EM_MSG_LED_VALUE_ON; /* check this */ - ahci_transmit_led_message(ap, port_led_state, 4); - } - } - emp->blink_policy = val; - return 0; -} - -static ssize_t ahci_activity_show(struct ata_device *dev, char *buf) -{ - struct ata_link *link = dev->link; - struct ata_port *ap = link->ap; - struct ahci_port_priv *pp = ap->private_data; - struct ahci_em_priv *emp = &pp->em_priv[link->pmp]; - - /* display the saved value of activity behavior for this - * disk. - */ - return sprintf(buf, "%d\n", emp->blink_policy); -} - -static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap, - int port_no, void __iomem *mmio, - void __iomem *port_mmio) -{ - const char *emsg = NULL; - int rc; - u32 tmp; - - /* make sure port is not active */ - rc = ahci_deinit_port(ap, &emsg); - if (rc) - dev_printk(KERN_WARNING, &pdev->dev, - "%s (%d)\n", emsg, rc); - - /* clear SError */ - tmp = readl(port_mmio + PORT_SCR_ERR); - VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); - writel(tmp, port_mmio + PORT_SCR_ERR); - - /* clear port IRQ */ - tmp = readl(port_mmio + PORT_IRQ_STAT); - VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); - if (tmp) - writel(tmp, port_mmio + PORT_IRQ_STAT); - - writel(1 << port_no, mmio + HOST_IRQ_STAT); -} - -static void ahci_init_controller(struct ata_host *host) +static void ahci_pci_init_controller(struct ata_host *host) { struct ahci_host_priv *hpriv = host->private_data; struct pci_dev *pdev = to_pci_dev(host->dev); - void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; - int i; void __iomem *port_mmio; u32 tmp; int mv; @@ -1528,222 +424,7 @@ static void ahci_init_controller(struct ata_host *host) writel(tmp, port_mmio + PORT_IRQ_STAT); } - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - - port_mmio = ahci_port_base(ap); - if (ata_port_is_dummy(ap)) - continue; - - ahci_port_init(pdev, ap, i, mmio, port_mmio); - } - - tmp = readl(mmio + HOST_CTL); - VPRINTK("HOST_CTL 0x%x\n", tmp); - writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); - tmp = readl(mmio + HOST_CTL); - VPRINTK("HOST_CTL 0x%x\n", tmp); -} - -static void ahci_dev_config(struct ata_device *dev) -{ - struct ahci_host_priv *hpriv = dev->link->ap->host->private_data; - - if (hpriv->flags & AHCI_HFLAG_SECT255) { - dev->max_sectors = 255; - ata_dev_printk(dev, KERN_INFO, - "SB600 AHCI: limiting to 255 sectors per cmd\n"); - } -} - -static unsigned int ahci_dev_classify(struct ata_port *ap) -{ - void __iomem *port_mmio = ahci_port_base(ap); - struct ata_taskfile tf; - u32 tmp; - - tmp = readl(port_mmio + PORT_SIG); - tf.lbah = (tmp >> 24) & 0xff; - tf.lbam = (tmp >> 16) & 0xff; - tf.lbal = (tmp >> 8) & 0xff; - tf.nsect = (tmp) & 0xff; - - return ata_dev_classify(&tf); -} - -static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, - u32 opts) -{ - dma_addr_t cmd_tbl_dma; - - cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ; - - pp->cmd_slot[tag].opts = cpu_to_le32(opts); - pp->cmd_slot[tag].status = 0; - pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff); - pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); -} - -static int ahci_kick_engine(struct ata_port *ap, int force_restart) -{ - void __iomem *port_mmio = ahci_port_base(ap); - struct ahci_host_priv *hpriv = ap->host->private_data; - u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; - u32 tmp; - int busy, rc; - - /* do we need to kick the port? */ - busy = status & (ATA_BUSY | ATA_DRQ); - if (!busy && !force_restart) - return 0; - - /* stop engine */ - rc = ahci_stop_engine(ap); - if (rc) - goto out_restart; - - /* need to do CLO? */ - if (!busy) { - rc = 0; - goto out_restart; - } - - if (!(hpriv->cap & HOST_CAP_CLO)) { - rc = -EOPNOTSUPP; - goto out_restart; - } - - /* perform CLO */ - tmp = readl(port_mmio + PORT_CMD); - tmp |= PORT_CMD_CLO; - writel(tmp, port_mmio + PORT_CMD); - - rc = 0; - tmp = ata_wait_register(port_mmio + PORT_CMD, - PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); - if (tmp & PORT_CMD_CLO) - rc = -EIO; - - /* restart engine */ - out_restart: - ahci_start_engine(ap); - return rc; -} - -static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, - struct ata_taskfile *tf, int is_cmd, u16 flags, - unsigned long timeout_msec) -{ - const u32 cmd_fis_len = 5; /* five dwords */ - struct ahci_port_priv *pp = ap->private_data; - void __iomem *port_mmio = ahci_port_base(ap); - u8 *fis = pp->cmd_tbl; - u32 tmp; - - /* prep the command */ - ata_tf_to_fis(tf, pmp, is_cmd, fis); - ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12)); - - /* issue & wait */ - writel(1, port_mmio + PORT_CMD_ISSUE); - - if (timeout_msec) { - tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, - 1, timeout_msec); - if (tmp & 0x1) { - ahci_kick_engine(ap, 1); - return -EBUSY; - } - } else - readl(port_mmio + PORT_CMD_ISSUE); /* flush */ - - return 0; -} - -static int ahci_do_softreset(struct ata_link *link, unsigned int *class, - int pmp, unsigned long deadline, - int (*check_ready)(struct ata_link *link)) -{ - struct ata_port *ap = link->ap; - struct ahci_host_priv *hpriv = ap->host->private_data; - const char *reason = NULL; - unsigned long now, msecs; - struct ata_taskfile tf; - int rc; - - DPRINTK("ENTER\n"); - - /* prepare for SRST (AHCI-1.1 10.4.1) */ - rc = ahci_kick_engine(ap, 1); - if (rc && rc != -EOPNOTSUPP) - ata_link_printk(link, KERN_WARNING, - "failed to reset engine (errno=%d)\n", rc); - - ata_tf_init(link->device, &tf); - - /* issue the first D2H Register FIS */ - msecs = 0; - now = jiffies; - if (time_after(now, deadline)) - msecs = jiffies_to_msecs(deadline - now); - - tf.ctl |= ATA_SRST; - if (ahci_exec_polled_cmd(ap, pmp, &tf, 0, - AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) { - rc = -EIO; - reason = "1st FIS failed"; - goto fail; - } - - /* spec says at least 5us, but be generous and sleep for 1ms */ - msleep(1); - - /* issue the second D2H Register FIS */ - tf.ctl &= ~ATA_SRST; - ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0); - - /* wait for link to become ready */ - rc = ata_wait_after_reset(link, deadline, check_ready); - if (rc == -EBUSY && hpriv->flags & AHCI_HFLAG_SRST_TOUT_IS_OFFLINE) { - /* - * Workaround for cases where link online status can't - * be trusted. Treat device readiness timeout as link - * offline. - */ - ata_link_printk(link, KERN_INFO, - "device not ready, treating as offline\n"); - *class = ATA_DEV_NONE; - } else if (rc) { - /* link occupied, -ENODEV too is an error */ - reason = "device not ready"; - goto fail; - } else - *class = ahci_dev_classify(ap); - - DPRINTK("EXIT, class=%u\n", *class); - return 0; - - fail: - ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason); - return rc; -} - -static int ahci_check_ready(struct ata_link *link) -{ - void __iomem *port_mmio = ahci_port_base(link->ap); - u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; - - return ata_check_ready(status); -} - -static int ahci_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - int pmp = sata_srst_pmp(link); - - DPRINTK("ENTER\n"); - - return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready); + ahci_init_controller(host); } static int ahci_sb600_check_ready(struct ata_link *link) @@ -1795,38 +476,6 @@ static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, return rc; } -static int ahci_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); - struct ata_port *ap = link->ap; - struct ahci_port_priv *pp = ap->private_data; - u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; - struct ata_taskfile tf; - bool online; - int rc; - - DPRINTK("ENTER\n"); - - ahci_stop_engine(ap); - - /* clear D2H reception area to properly wait for D2H FIS */ - ata_tf_init(link->device, &tf); - tf.command = 0x80; - ata_tf_to_fis(&tf, 0, 0, d2h_fis); - - rc = sata_link_hardreset(link, timing, deadline, &online, - ahci_check_ready); - - ahci_start_engine(ap); - - if (online) - *class = ahci_dev_classify(ap); - - DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); - return rc; -} - static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { @@ -1890,453 +539,17 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, rc = ata_wait_after_reset(link, jiffies + 2 * HZ, ahci_check_ready); if (rc) - ahci_kick_engine(ap, 0); + ahci_kick_engine(ap); } return rc; } -static void ahci_postreset(struct ata_link *link, unsigned int *class) -{ - struct ata_port *ap = link->ap; - void __iomem *port_mmio = ahci_port_base(ap); - u32 new_tmp, tmp; - - ata_std_postreset(link, class); - - /* Make sure port's ATAPI bit is set appropriately */ - new_tmp = tmp = readl(port_mmio + PORT_CMD); - if (*class == ATA_DEV_ATAPI) - new_tmp |= PORT_CMD_ATAPI; - else - new_tmp &= ~PORT_CMD_ATAPI; - if (new_tmp != tmp) { - writel(new_tmp, port_mmio + PORT_CMD); - readl(port_mmio + PORT_CMD); /* flush */ - } -} - -static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) -{ - struct scatterlist *sg; - struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ; - unsigned int si; - - VPRINTK("ENTER\n"); - - /* - * Next, the S/G list. - */ - for_each_sg(qc->sg, sg, qc->n_elem, si) { - dma_addr_t addr = sg_dma_address(sg); - u32 sg_len = sg_dma_len(sg); - - ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff); - ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16); - ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1); - } - - return si; -} - -static void ahci_qc_prep(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ahci_port_priv *pp = ap->private_data; - int is_atapi = ata_is_atapi(qc->tf.protocol); - void *cmd_tbl; - u32 opts; - const u32 cmd_fis_len = 5; /* five dwords */ - unsigned int n_elem; - - /* - * Fill in command table information. First, the header, - * a SATA Register - Host to Device command FIS. - */ - cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ; - - ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl); - if (is_atapi) { - memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); - memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len); - } - - n_elem = 0; - if (qc->flags & ATA_QCFLAG_DMAMAP) - n_elem = ahci_fill_sg(qc, cmd_tbl); - - /* - * Fill in command slot information. - */ - opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12); - if (qc->tf.flags & ATA_TFLAG_WRITE) - opts |= AHCI_CMD_WRITE; - if (is_atapi) - opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH; - - ahci_fill_cmd_slot(pp, qc->tag, opts); -} - -static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) -{ - struct ahci_host_priv *hpriv = ap->host->private_data; - struct ahci_port_priv *pp = ap->private_data; - struct ata_eh_info *host_ehi = &ap->link.eh_info; - struct ata_link *link = NULL; - struct ata_queued_cmd *active_qc; - struct ata_eh_info *active_ehi; - u32 serror; - - /* determine active link */ - ata_for_each_link(link, ap, EDGE) - if (ata_link_active(link)) - break; - if (!link) - link = &ap->link; - - active_qc = ata_qc_from_tag(ap, link->active_tag); - active_ehi = &link->eh_info; - - /* record irq stat */ - ata_ehi_clear_desc(host_ehi); - ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat); - - /* AHCI needs SError cleared; otherwise, it might lock up */ - ahci_scr_read(&ap->link, SCR_ERROR, &serror); - ahci_scr_write(&ap->link, SCR_ERROR, serror); - host_ehi->serror |= serror; - - /* some controllers set IRQ_IF_ERR on device errors, ignore it */ - if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR) - irq_stat &= ~PORT_IRQ_IF_ERR; - - if (irq_stat & PORT_IRQ_TF_ERR) { - /* If qc is active, charge it; otherwise, the active - * link. There's no active qc on NCQ errors. It will - * be determined by EH by reading log page 10h. - */ - if (active_qc) - active_qc->err_mask |= AC_ERR_DEV; - else - active_ehi->err_mask |= AC_ERR_DEV; - - if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL) - host_ehi->serror &= ~SERR_INTERNAL; - } - - if (irq_stat & PORT_IRQ_UNK_FIS) { - u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); - - active_ehi->err_mask |= AC_ERR_HSM; - active_ehi->action |= ATA_EH_RESET; - ata_ehi_push_desc(active_ehi, - "unknown FIS %08x %08x %08x %08x" , - unk[0], unk[1], unk[2], unk[3]); - } - - if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) { - active_ehi->err_mask |= AC_ERR_HSM; - active_ehi->action |= ATA_EH_RESET; - ata_ehi_push_desc(active_ehi, "incorrect PMP"); - } - - if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { - host_ehi->err_mask |= AC_ERR_HOST_BUS; - host_ehi->action |= ATA_EH_RESET; - ata_ehi_push_desc(host_ehi, "host bus error"); - } - - if (irq_stat & PORT_IRQ_IF_ERR) { - host_ehi->err_mask |= AC_ERR_ATA_BUS; - host_ehi->action |= ATA_EH_RESET; - ata_ehi_push_desc(host_ehi, "interface fatal error"); - } - - if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { - ata_ehi_hotplugged(host_ehi); - ata_ehi_push_desc(host_ehi, "%s", - irq_stat & PORT_IRQ_CONNECT ? - "connection status changed" : "PHY RDY changed"); - } - - /* okay, let's hand over to EH */ - - if (irq_stat & PORT_IRQ_FREEZE) - ata_port_freeze(ap); - else - ata_port_abort(ap); -} - -static void ahci_port_intr(struct ata_port *ap) -{ - void __iomem *port_mmio = ahci_port_base(ap); - struct ata_eh_info *ehi = &ap->link.eh_info; - struct ahci_port_priv *pp = ap->private_data; - struct ahci_host_priv *hpriv = ap->host->private_data; - int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); - u32 status, qc_active; - int rc; - - status = readl(port_mmio + PORT_IRQ_STAT); - writel(status, port_mmio + PORT_IRQ_STAT); - - /* ignore BAD_PMP while resetting */ - if (unlikely(resetting)) - status &= ~PORT_IRQ_BAD_PMP; - - /* If we are getting PhyRdy, this is - * just a power state change, we should - * clear out this, plus the PhyRdy/Comm - * Wake bits from Serror - */ - if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) && - (status & PORT_IRQ_PHYRDY)) { - status &= ~PORT_IRQ_PHYRDY; - ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18))); - } - - if (unlikely(status & PORT_IRQ_ERROR)) { - ahci_error_intr(ap, status); - return; - } - - if (status & PORT_IRQ_SDB_FIS) { - /* If SNotification is available, leave notification - * handling to sata_async_notification(). If not, - * emulate it by snooping SDB FIS RX area. - * - * Snooping FIS RX area is probably cheaper than - * poking SNotification but some constrollers which - * implement SNotification, ICH9 for example, don't - * store AN SDB FIS into receive area. - */ - if (hpriv->cap & HOST_CAP_SNTF) - sata_async_notification(ap); - else { - /* If the 'N' bit in word 0 of the FIS is set, - * we just received asynchronous notification. - * Tell libata about it. - */ - const __le32 *f = pp->rx_fis + RX_FIS_SDB; - u32 f0 = le32_to_cpu(f[0]); - - if (f0 & (1 << 15)) - sata_async_notification(ap); - } - } - - /* pp->active_link is valid iff any command is in flight */ - if (ap->qc_active && pp->active_link->sactive) - qc_active = readl(port_mmio + PORT_SCR_ACT); - else - qc_active = readl(port_mmio + PORT_CMD_ISSUE); - - rc = ata_qc_complete_multiple(ap, qc_active); - - /* while resetting, invalid completions are expected */ - if (unlikely(rc < 0 && !resetting)) { - ehi->err_mask |= AC_ERR_HSM; - ehi->action |= ATA_EH_RESET; - ata_port_freeze(ap); - } -} - -static irqreturn_t ahci_interrupt(int irq, void *dev_instance) -{ - struct ata_host *host = dev_instance; - struct ahci_host_priv *hpriv; - unsigned int i, handled = 0; - void __iomem *mmio; - u32 irq_stat, irq_masked; - - VPRINTK("ENTER\n"); - - hpriv = host->private_data; - mmio = host->iomap[AHCI_PCI_BAR]; - - /* sigh. 0xffffffff is a valid return from h/w */ - irq_stat = readl(mmio + HOST_IRQ_STAT); - if (!irq_stat) - return IRQ_NONE; - - irq_masked = irq_stat & hpriv->port_map; - - spin_lock(&host->lock); - - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap; - - if (!(irq_masked & (1 << i))) - continue; - - ap = host->ports[i]; - if (ap) { - ahci_port_intr(ap); - VPRINTK("port %u\n", i); - } else { - VPRINTK("port %u (no irq)\n", i); - if (ata_ratelimit()) - dev_printk(KERN_WARNING, host->dev, - "interrupt on disabled port %u\n", i); - } - - handled = 1; - } - - /* HOST_IRQ_STAT behaves as level triggered latch meaning that - * it should be cleared after all the port events are cleared; - * otherwise, it will raise a spurious interrupt after each - * valid one. Please read section 10.6.2 of ahci 1.1 for more - * information. - * - * Also, use the unmasked value to clear interrupt as spurious - * pending event on a dummy port might cause screaming IRQ. - */ - writel(irq_stat, mmio + HOST_IRQ_STAT); - - spin_unlock(&host->lock); - - VPRINTK("EXIT\n"); - - return IRQ_RETVAL(handled); -} - -static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - void __iomem *port_mmio = ahci_port_base(ap); - struct ahci_port_priv *pp = ap->private_data; - - /* Keep track of the currently active link. It will be used - * in completion path to determine whether NCQ phase is in - * progress. - */ - pp->active_link = qc->dev->link; - - if (qc->tf.protocol == ATA_PROT_NCQ) - writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); - writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE); - - ahci_sw_activity(qc->dev->link); - - return 0; -} - -static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) -{ - struct ahci_port_priv *pp = qc->ap->private_data; - u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; - - ata_tf_from_fis(d2h_fis, &qc->result_tf); - return true; -} - -static void ahci_freeze(struct ata_port *ap) -{ - void __iomem *port_mmio = ahci_port_base(ap); - - /* turn IRQ off */ - writel(0, port_mmio + PORT_IRQ_MASK); -} - -static void ahci_thaw(struct ata_port *ap) -{ - void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; - void __iomem *port_mmio = ahci_port_base(ap); - u32 tmp; - struct ahci_port_priv *pp = ap->private_data; - - /* clear IRQ */ - tmp = readl(port_mmio + PORT_IRQ_STAT); - writel(tmp, port_mmio + PORT_IRQ_STAT); - writel(1 << ap->port_no, mmio + HOST_IRQ_STAT); - - /* turn IRQ back on */ - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); -} - -static void ahci_error_handler(struct ata_port *ap) -{ - if (!(ap->pflags & ATA_PFLAG_FROZEN)) { - /* restart engine */ - ahci_stop_engine(ap); - ahci_start_engine(ap); - } - - sata_pmp_error_handler(ap); -} - -static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - - /* make DMA engine forget about the failed command */ - if (qc->flags & ATA_QCFLAG_FAILED) - ahci_kick_engine(ap, 1); -} - -static void ahci_pmp_attach(struct ata_port *ap) -{ - void __iomem *port_mmio = ahci_port_base(ap); - struct ahci_port_priv *pp = ap->private_data; - u32 cmd; - - cmd = readl(port_mmio + PORT_CMD); - cmd |= PORT_CMD_PMP; - writel(cmd, port_mmio + PORT_CMD); - - pp->intr_mask |= PORT_IRQ_BAD_PMP; - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); -} - -static void ahci_pmp_detach(struct ata_port *ap) -{ - void __iomem *port_mmio = ahci_port_base(ap); - struct ahci_port_priv *pp = ap->private_data; - u32 cmd; - - cmd = readl(port_mmio + PORT_CMD); - cmd &= ~PORT_CMD_PMP; - writel(cmd, port_mmio + PORT_CMD); - - pp->intr_mask &= ~PORT_IRQ_BAD_PMP; - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); -} - -static int ahci_port_resume(struct ata_port *ap) -{ - ahci_power_up(ap); - ahci_start_port(ap); - - if (sata_pmp_attached(ap)) - ahci_pmp_attach(ap); - else - ahci_pmp_detach(ap); - - return 0; -} - #ifdef CONFIG_PM -static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) -{ - const char *emsg = NULL; - int rc; - - rc = ahci_deinit_port(ap, &emsg); - if (rc == 0) - ahci_power_down(ap); - else { - ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc); - ahci_start_port(ap); - } - - return rc; -} - static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) { struct ata_host *host = dev_get_drvdata(&pdev->dev); struct ahci_host_priv *hpriv = host->private_data; - void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; + void __iomem *mmio = hpriv->mmio; u32 ctl; if (mesg.event & PM_EVENT_SUSPEND && @@ -2370,11 +583,11 @@ static int ahci_pci_device_resume(struct pci_dev *pdev) return rc; if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { - rc = ahci_reset_controller(host); + rc = ahci_pci_reset_controller(host); if (rc) return rc; - ahci_init_controller(host); + ahci_pci_init_controller(host); } ata_host_resume(host); @@ -2383,72 +596,6 @@ static int ahci_pci_device_resume(struct pci_dev *pdev) } #endif -static int ahci_port_start(struct ata_port *ap) -{ - struct device *dev = ap->host->dev; - struct ahci_port_priv *pp; - void *mem; - dma_addr_t mem_dma; - - pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); - if (!pp) - return -ENOMEM; - - mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, - GFP_KERNEL); - if (!mem) - return -ENOMEM; - memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); - - /* - * First item in chunk of DMA memory: 32-slot command table, - * 32 bytes each in size - */ - pp->cmd_slot = mem; - pp->cmd_slot_dma = mem_dma; - - mem += AHCI_CMD_SLOT_SZ; - mem_dma += AHCI_CMD_SLOT_SZ; - - /* - * Second item: Received-FIS area - */ - pp->rx_fis = mem; - pp->rx_fis_dma = mem_dma; - - mem += AHCI_RX_FIS_SZ; - mem_dma += AHCI_RX_FIS_SZ; - - /* - * Third item: data area for storing a single command - * and its scatter-gather table - */ - pp->cmd_tbl = mem; - pp->cmd_tbl_dma = mem_dma; - - /* - * Save off initial list of interrupts to be enabled. - * This could be changed later - */ - pp->intr_mask = DEF_PORT_IRQ; - - ap->private_data = pp; - - /* engage engines, captain */ - return ahci_port_resume(ap); -} - -static void ahci_port_stop(struct ata_port *ap) -{ - const char *emsg = NULL; - int rc; - - /* de-initialize port */ - rc = ahci_deinit_port(ap, &emsg); - if (rc) - ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); -} - static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) { int rc; @@ -2481,30 +628,12 @@ static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) return 0; } -static void ahci_print_info(struct ata_host *host) +static void ahci_pci_print_info(struct ata_host *host) { - struct ahci_host_priv *hpriv = host->private_data; struct pci_dev *pdev = to_pci_dev(host->dev); - void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; - u32 vers, cap, impl, speed; - const char *speed_s; u16 cc; const char *scc_s; - vers = readl(mmio + HOST_VERSION); - cap = hpriv->cap; - impl = hpriv->port_map; - - speed = (cap >> 20) & 0xf; - if (speed == 1) - speed_s = "1.5"; - else if (speed == 2) - speed_s = "3"; - else if (speed == 3) - speed_s = "6"; - else - speed_s = "?"; - pci_read_config_word(pdev, 0x0a, &cc); if (cc == PCI_CLASS_STORAGE_IDE) scc_s = "IDE"; @@ -2515,46 +644,7 @@ static void ahci_print_info(struct ata_host *host) else scc_s = "unknown"; - dev_printk(KERN_INFO, &pdev->dev, - "AHCI %02x%02x.%02x%02x " - "%u slots %u ports %s Gbps 0x%x impl %s mode\n" - , - - (vers >> 24) & 0xff, - (vers >> 16) & 0xff, - (vers >> 8) & 0xff, - vers & 0xff, - - ((cap >> 8) & 0x1f) + 1, - (cap & 0x1f) + 1, - speed_s, - impl, - scc_s); - - dev_printk(KERN_INFO, &pdev->dev, - "flags: " - "%s%s%s%s%s%s%s" - "%s%s%s%s%s%s%s" - "%s\n" - , - - cap & (1 << 31) ? "64bit " : "", - cap & (1 << 30) ? "ncq " : "", - cap & (1 << 29) ? "sntf " : "", - cap & (1 << 28) ? "ilck " : "", - cap & (1 << 27) ? "stag " : "", - cap & (1 << 26) ? "pm " : "", - cap & (1 << 25) ? "led " : "", - - cap & (1 << 24) ? "clo " : "", - cap & (1 << 19) ? "nz " : "", - cap & (1 << 18) ? "only " : "", - cap & (1 << 17) ? "pmp " : "", - cap & (1 << 15) ? "pio " : "", - cap & (1 << 14) ? "slum " : "", - cap & (1 << 13) ? "part " : "", - cap & (1 << 6) ? "ems ": "" - ); + ahci_print_info(host, scc_s); } /* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is @@ -2789,6 +879,55 @@ static bool ahci_broken_online(struct pci_dev *pdev) return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff); } +#ifdef CONFIG_ATA_ACPI +static void ahci_gtf_filter_workaround(struct ata_host *host) +{ + static const struct dmi_system_id sysids[] = { + /* + * Aspire 3810T issues a bunch of SATA enable commands + * via _GTF including an invalid one and one which is + * rejected by the device. Among the successful ones + * is FPDMA non-zero offset enable which when enabled + * only on the drive side leads to NCQ command + * failures. Filter it out. + */ + { + .ident = "Aspire 3810T", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3810T"), + }, + .driver_data = (void *)ATA_ACPI_FILTER_FPDMA_OFFSET, + }, + { } + }; + const struct dmi_system_id *dmi = dmi_first_match(sysids); + unsigned int filter; + int i; + + if (!dmi) + return; + + filter = (unsigned long)dmi->driver_data; + dev_printk(KERN_INFO, host->dev, + "applying extra ACPI _GTF filter 0x%x for %s\n", + filter, dmi->ident); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + struct ata_link *link; + struct ata_device *dev; + + ata_for_each_link(link, ap, EDGE) + ata_for_each_dev(dev, link, ALL) + dev->gtf_filter |= filter; + } +} +#else +static inline void ahci_gtf_filter_workaround(struct ata_host *host) +{} +#endif + static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; @@ -2864,33 +1003,19 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) pci_enable_msi(pdev); + hpriv->mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; + /* save initial config */ - ahci_save_initial_config(pdev, hpriv); + ahci_pci_save_initial_config(pdev, hpriv); /* prepare host */ if (hpriv->cap & HOST_CAP_NCQ) - pi.flags |= ATA_FLAG_NCQ; + pi.flags |= ATA_FLAG_NCQ | ATA_FLAG_FPDMA_AA; if (hpriv->cap & HOST_CAP_PMP) pi.flags |= ATA_FLAG_PMP; - if (ahci_em_messages && (hpriv->cap & HOST_CAP_EMS)) { - u8 messages; - void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; - u32 em_loc = readl(mmio + HOST_EM_LOC); - u32 em_ctl = readl(mmio + HOST_EM_CTL); - - messages = (em_ctl & EM_CTRL_MSG_TYPE) >> 16; - - /* we only support LED message type right now */ - if ((messages & 0x01) && (ahci_em_messages == 1)) { - /* store em_loc */ - hpriv->em_loc = ((em_loc >> 16) * 4); - pi.flags |= ATA_FLAG_EM; - if (!(em_ctl & EM_CTL_ALHD)) - pi.flags |= ATA_FLAG_SW_ACTIVITY; - } - } + ahci_set_em_messages(hpriv, &pi); if (ahci_broken_system_poweroff(pdev)) { pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN; @@ -2920,7 +1045,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); if (!host) return -ENOMEM; - host->iomap = pcim_iomap_table(pdev); host->private_data = hpriv; if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) @@ -2954,17 +1078,20 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* apply workaround for ASUS P5W DH Deluxe mainboard */ ahci_p5wdh_workaround(host); + /* apply gtf filter quirk */ + ahci_gtf_filter_workaround(host); + /* initialize adapter */ rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); if (rc) return rc; - rc = ahci_reset_controller(host); + rc = ahci_pci_reset_controller(host); if (rc) return rc; - ahci_init_controller(host); - ahci_print_info(host); + ahci_pci_init_controller(host); + ahci_pci_print_info(host); pci_set_master(pdev); return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 072ba5ea138f..98af50f16e0c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2299,29 +2299,49 @@ static inline u8 ata_dev_knobble(struct ata_device *dev) return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); } -static void ata_dev_config_ncq(struct ata_device *dev, +static int ata_dev_config_ncq(struct ata_device *dev, char *desc, size_t desc_sz) { struct ata_port *ap = dev->link->ap; int hdepth = 0, ddepth = ata_id_queue_depth(dev->id); + unsigned int err_mask; + char *aa_desc = ""; if (!ata_id_has_ncq(dev->id)) { desc[0] = '\0'; - return; + return 0; } if (dev->horkage & ATA_HORKAGE_NONCQ) { snprintf(desc, desc_sz, "NCQ (not used)"); - return; + return 0; } if (ap->flags & ATA_FLAG_NCQ) { hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE - 1); dev->flags |= ATA_DFLAG_NCQ; } + if (!(dev->horkage & ATA_HORKAGE_BROKEN_FPDMA_AA) && + (ap->flags & ATA_FLAG_FPDMA_AA) && + ata_id_has_fpdma_aa(dev->id)) { + err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_ENABLE, + SATA_FPDMA_AA); + if (err_mask) { + ata_dev_printk(dev, KERN_ERR, "failed to enable AA" + "(error_mask=0x%x)\n", err_mask); + if (err_mask != AC_ERR_DEV) { + dev->horkage |= ATA_HORKAGE_BROKEN_FPDMA_AA; + return -EIO; + } + } else + aa_desc = ", AA"; + } + if (hdepth >= ddepth) - snprintf(desc, desc_sz, "NCQ (depth %d)", ddepth); + snprintf(desc, desc_sz, "NCQ (depth %d)%s", ddepth, aa_desc); else - snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth); + snprintf(desc, desc_sz, "NCQ (depth %d/%d)%s", hdepth, + ddepth, aa_desc); + return 0; } /** @@ -2461,7 +2481,7 @@ int ata_dev_configure(struct ata_device *dev) if (ata_id_has_lba(id)) { const char *lba_desc; - char ncq_desc[20]; + char ncq_desc[24]; lba_desc = "LBA"; dev->flags |= ATA_DFLAG_LBA; @@ -2475,7 +2495,9 @@ int ata_dev_configure(struct ata_device *dev) } /* config NCQ */ - ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); + rc = ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); + if (rc) + return rc; /* print device info to dmesg */ if (ata_msg_drv(ap) && print_info) { diff --git a/drivers/ata/pata_fsl.c b/drivers/ata/pata_fsl.c index c1d05282da03..955095039257 100644 --- a/drivers/ata/pata_fsl.c +++ b/drivers/ata/pata_fsl.c @@ -3,7 +3,7 @@ */ /* - * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -766,10 +766,11 @@ static int __devinit pata_fsl_probe(struct platform_device *pdev) /* * Set up resources */ - if (unlikely(pdev->num_resources != 3)) { + if (unlikely(pdev->num_resources != 2)) { dev_err(&pdev->dev, "invalid number of resources\n"); return -EINVAL; } + /* * Get an ata_host structure for this device */ diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index dc99e26f8e5b..c4647f5b6a22 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -136,7 +136,7 @@ static unsigned int ata_data_xfer_8bit(struct ata_device *dev, * */ -void pcmcia_8bit_drain_fifo(struct ata_queued_cmd *qc) +static void pcmcia_8bit_drain_fifo(struct ata_queued_cmd *qc) { int count; struct ata_port *ap; diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 8efaa5ca8a03..49f086977c37 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -444,7 +444,7 @@ config MXC_IIM config MXS_VIIM tristate "MXS Virtual IIM device driver" - depends on (ARCH_STMP3XXX || ARCH_MXS) + depends on (ARCH_STMP3XXX || ARCH_MXS || ARCH_MX5) help Support for access to MXS Virtual IIM device, most people should say N here. @@ -564,6 +564,22 @@ config BFIN_OTP_WRITE_ENABLE If unsure, say N. +config FSL_OTP + tristate "Freescale On-Chip OTP Memory Support" + depends on (ARCH_MX23 || ARCH_MX28 || ARCH_MX50) + default n + help + If you say Y here, you will get support for a character device + interface into the One Time Programmable memory pages that are + stored on the iMX23/28/50 processor. This will not get you access + to the secure memory pages however. You will need to write your + own secure code and reader for that. + + To compile this driver as a module, choose M here: the module + will be called fsl_otp. + + If unsure, it is safe to say Y. + config PRINTER tristate "Parallel printer support" depends on PARPORT diff --git a/drivers/char/Makefile b/drivers/char/Makefile index c711f02de8f7..898ce27e335d 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_IBM_BSR) += bsr.o obj-$(CONFIG_SGI_MBCS) += mbcs.o obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o obj-$(CONFIG_BFIN_OTP) += bfin-otp.o +obj-$(CONFIG_FSL_OTP) += fsl_otp.o obj-$(CONFIG_PRINTER) += lp.o diff --git a/drivers/char/hw_random/fsl-rngc.c b/drivers/char/hw_random/fsl-rngc.c index 9bf78e846fa0..9e788f97c4d8 100644 --- a/drivers/char/hw_random/fsl-rngc.c +++ b/drivers/char/hw_random/fsl-rngc.c @@ -1,7 +1,7 @@ /* * RNG driver for Freescale RNGC * - * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2008-2010 Freescale Semiconductor, Inc. */ /* @@ -42,7 +42,6 @@ #include <linux/interrupt.h> #include <linux/hw_random.h> #include <linux/io.h> -#include <asm/hardware.h> #define RNGC_VERSION_MAJOR3 3 @@ -292,7 +291,7 @@ static int __init fsl_rngc_probe(struct platform_device *pdev) if (rng_dev) return -EBUSY; - clk = clk_get(NULL, "rng_clk"); + clk = clk_get(&pdev->dev, "rng_clk"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Can not get rng_clk\n"); @@ -334,9 +333,17 @@ static int __init fsl_rngc_probe(struct platform_device *pdev) static int __exit fsl_rngc_remove(struct platform_device *pdev) { + struct clk *clk; struct resource *mem = dev_get_drvdata(&pdev->dev); void __iomem *rngc_base = (void __iomem *)fsl_rngc.priv; + clk = clk_get(&pdev->dev, "rng_clk"); + + if (IS_ERR(clk)) + dev_err(&pdev->dev, "Can not get rng_clk\n"); + else + clk_disable(clk); + hwrng_unregister(&fsl_rngc); release_resource(mem); @@ -346,12 +353,47 @@ static int __exit fsl_rngc_remove(struct platform_device *pdev) return 0; } +static int fsl_rngc_suspend(struct platform_device *pdev, + pm_message_t state) +{ +#ifdef CONFIG_PM + struct clk *clk = clk_get(&pdev->dev, "rng_clk"); + + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Can not get rng_clk\n"); + return PTR_ERR(clk); + } + + clk_disable(clk); +#endif + + return 0; +} + +static int fsl_rngc_resume(struct platform_device *pdev) +{ +#ifdef CONFIG_PM + struct clk *clk = clk_get(&pdev->dev, "rng_clk"); + + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Can not get rng_clk\n"); + return PTR_ERR(clk); + } + + clk_enable(clk); +#endif + + return 0; +} + static struct platform_driver fsl_rngc_driver = { .driver = { .name = "fsl_rngc", .owner = THIS_MODULE, }, .remove = __exit_p(fsl_rngc_remove), + .suspend = fsl_rngc_suspend, + .resume = fsl_rngc_resume, }; static int __init mod_init(void) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 9c2919a431a8..5057cb958230 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -211,7 +211,7 @@ config CRYPTO_DEV_PPC4XX config CRYPTO_DEV_DCP tristate "Support for the DCP engine" - depends on ARCH_MX28 || ARCH_MX23 + depends on ARCH_MX28 || ARCH_MX23 || ARCH_MX50 select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER help diff --git a/drivers/crypto/dcp.c b/drivers/crypto/dcp.c index a72d73382778..eb7a83d276b7 100644 --- a/drivers/crypto/dcp.c +++ b/drivers/crypto/dcp.c @@ -17,10 +17,16 @@ #include <linux/module.h> #include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/sysdev.h> +#include <linux/bitops.h> #include <linux/crypto.h> #include <linux/spinlock.h> +#include <linux/miscdevice.h> #include <linux/platform_device.h> #include <linux/err.h> +#include <linux/sysfs.h> +#include <linux/fs.h> #include <crypto/algapi.h> #include <crypto/aes.h> #include <crypto/sha.h> @@ -29,13 +35,21 @@ #include <linux/dma-mapping.h> #include <linux/interrupt.h> #include <linux/delay.h> - +#include <linux/uaccess.h> +#include <linux/clk.h> #include <linux/io.h> #include <linux/delay.h> #include <asm/cacheflush.h> #include <mach/hardware.h> #include "dcp.h" +#include "dcp_bootstream_ioctl.h" + +/* Following data only used by DCP bootstream interface */ +struct dcpboot_dma_area { + struct dcp_hw_packet hw_packet; + uint16_t block[16]; +}; struct dcp { struct device *dev; @@ -46,6 +60,8 @@ struct dcp { int dcp_vmi_irq; int dcp_irq; u32 dcp_regs_base; + ulong clock_state; + bool chan_in_use[DCP_NUM_CHANNELS]; /* Following buffers used in hashing to meet 64-byte len alignment */ char *buf1; @@ -55,6 +71,10 @@ struct dcp { struct dcp_hash_coherent_block *buf1_desc; struct dcp_hash_coherent_block *buf2_desc; struct dcp_hash_coherent_block *user_buf_desc; + + /* Following data only used by DCP bootstream interface */ + struct dcpboot_dma_area *dcpboot_dma_area; + dma_addr_t dcpboot_dma_area_phys; }; /* cipher flags */ @@ -77,6 +97,10 @@ struct dcp { #define DCP_FILL 0x5000 #define DCP_MODE_MASK 0xf000 +/* clock defines */ +#define CLOCK_ON 1 +#define CLOCK_OFF 0 + struct dcp_op { unsigned int flags; @@ -159,6 +183,45 @@ struct dcp_hash_op { /* only one */ static struct dcp *global_sdcp; +static void dcp_clock(struct dcp *sdcp, ulong state, bool force) +{ + u32 chan; + struct clk *clk = clk_get(sdcp->dev, "dcp_clk"); + + /* unless force is true (used during suspend/resume), if any + * channel is running, then clk is already on, and must stay on */ + if (!force) + for (chan = 0; chan < DCP_NUM_CHANNELS; chan++) + if (sdcp->chan_in_use[chan]) + goto exit; + + if (state == CLOCK_OFF) { + /* gate at clock source */ + if (!IS_ERR(clk)) + clk_disable(clk); + /* gate at DCP */ + else + __raw_writel(BM_DCP_CTRL_CLKGATE, + sdcp->dcp_regs_base + HW_DCP_CTRL_SET); + + sdcp->clock_state = CLOCK_OFF; + + } else { + /* ungate at clock source */ + if (!IS_ERR(clk)) + clk_enable(clk); + /* ungate at DCP */ + else + __raw_writel(BM_DCP_CTRL_CLKGATE, + sdcp->dcp_regs_base + HW_DCP_CTRL_CLR); + + sdcp->clock_state = CLOCK_ON; + } + +exit: + return; +} + static void dcp_perform_op(struct dcp_op *op) { struct dcp *sdcp = global_sdcp; @@ -244,6 +307,8 @@ static void dcp_perform_op(struct dcp_op *op) /* submit the work */ mutex_lock(mutex); + dcp_clock(sdcp, CLOCK_ON, false); + sdcp->chan_in_use[chan] = true; __raw_writel(-1, sdcp->dcp_regs_base + HW_DCP_CHnSTAT_CLR(chan)); @@ -272,8 +337,9 @@ static void dcp_perform_op(struct dcp_op *op) __raw_readl(sdcp->dcp_regs_base + HW_DCP_CHnSTAT(chan)) & 0xff); out: + sdcp->chan_in_use[chan] = false; + dcp_clock(sdcp, CLOCK_OFF, false); mutex_unlock(mutex); - dma_unmap_single(sdcp->dev, pkt_phys, sizeof(*pkt), DMA_TO_DEVICE); } @@ -1043,6 +1109,8 @@ static int dcp_sha_init(struct shash_desc *desc) struct mutex *mutex = &sdcp->op_mutex[HASH_CHAN]; mutex_lock(mutex); + dcp_clock(sdcp, CLOCK_ON, false); + sdcp->chan_in_use[HASH_CHAN] = true; op->length = 0; @@ -1172,6 +1240,8 @@ static int dcp_sha_final(struct shash_desc *desc, u8 *out) for (i = 0; i < digest_len; i++) *out++ = *--digest; + sdcp->chan_in_use[HASH_CHAN] = false; + dcp_clock(sdcp, CLOCK_OFF, false); mutex_unlock(mutex); return ret; @@ -1245,6 +1315,110 @@ static irqreturn_t dcp_irq(int irq, void *context) return dcp_common_irq(irq, context); } +/* DCP bootstream verification interface: uses OTP key for crypto */ +static int dcp_bootstream_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct dcp *sdcp = global_sdcp; + struct dcpboot_dma_area *da = sdcp->dcpboot_dma_area; + void __user *argp = (void __user *)arg; + int chan = ROM_DCP_CHAN; + unsigned long timeout; + struct mutex *mutex; + int retVal; + + /* be paranoid */ + if (sdcp == NULL) + return -EBADF; + + if (cmd != DBS_ENC && cmd != DBS_DEC) + return -EINVAL; + + /* copy to (aligned) block */ + if (copy_from_user(da->block, argp, 16)) + return -EFAULT; + + mutex = &sdcp->op_mutex[chan]; + mutex_lock(mutex); + dcp_clock(sdcp, CLOCK_ON, false); + sdcp->chan_in_use[chan] = true; + + __raw_writel(-1, sdcp->dcp_regs_base + + HW_DCP_CHnSTAT_CLR(ROM_DCP_CHAN)); + __raw_writel(BF(ROM_DCP_CHAN_MASK, DCP_STAT_IRQ), + sdcp->dcp_regs_base + HW_DCP_STAT_CLR); + + da->hw_packet.pNext = 0; + da->hw_packet.pkt1 = BM_DCP_PACKET1_DECR_SEMAPHORE | + BM_DCP_PACKET1_ENABLE_CIPHER | BM_DCP_PACKET1_OTP_KEY | + BM_DCP_PACKET1_INTERRUPT | + (cmd == DBS_ENC ? BM_DCP_PACKET1_CIPHER_ENCRYPT : 0); + da->hw_packet.pkt2 = BF(0, DCP_PACKET2_CIPHER_CFG) | + BF(0, DCP_PACKET2_KEY_SELECT) | + BF(BV_DCP_PACKET2_CIPHER_MODE__ECB, DCP_PACKET2_CIPHER_MODE) | + BF(BV_DCP_PACKET2_CIPHER_SELECT__AES128, DCP_PACKET2_CIPHER_SELECT); + da->hw_packet.pSrc = sdcp->dcpboot_dma_area_phys + + offsetof(struct dcpboot_dma_area, block); + da->hw_packet.pDst = da->hw_packet.pSrc; /* in-place */ + da->hw_packet.size = 16; + da->hw_packet.pPayload = 0; + da->hw_packet.stat = 0; + + /* Load the work packet pointer and bump the channel semaphore */ + __raw_writel(sdcp->dcpboot_dma_area_phys + + offsetof(struct dcpboot_dma_area, hw_packet), + sdcp->dcp_regs_base + HW_DCP_CHnCMDPTR(ROM_DCP_CHAN)); + + sdcp->wait[chan] = 0; + __raw_writel(BF(1, DCP_CHnSEMA_INCREMENT), + sdcp->dcp_regs_base + HW_DCP_CHnSEMA(ROM_DCP_CHAN)); + + timeout = jiffies + msecs_to_jiffies(100); + + while (time_before(jiffies, timeout) && sdcp->wait[chan] == 0) + cpu_relax(); + + if (!time_before(jiffies, timeout)) { + dev_err(sdcp->dev, + "Timeout while waiting for operation to complete\n"); + retVal = -ETIMEDOUT; + goto exit; + } + + if ((__raw_readl(sdcp->dcp_regs_base + HW_DCP_CHnSTAT(ROM_DCP_CHAN)) + & 0xff) != 0) { + dev_err(sdcp->dev, "Channel stat error 0x%02x\n", + __raw_readl(sdcp->dcp_regs_base + + HW_DCP_CHnSTAT(ROM_DCP_CHAN)) & 0xff); + retVal = -EFAULT; + goto exit; + } + + if (copy_to_user(argp, da->block, 16)) { + retVal = -EFAULT; + goto exit; + } + + retVal = 0; + +exit: + sdcp->chan_in_use[chan] = false; + dcp_clock(sdcp, CLOCK_OFF, false); + mutex_unlock(mutex); + return retVal; +} + +static const struct file_operations dcp_bootstream_fops = { + .owner = THIS_MODULE, + .ioctl = dcp_bootstream_ioctl, +}; + +static struct miscdevice dcp_bootstream_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "dcpboot", + .fops = &dcp_bootstream_fops, +}; + static int dcp_probe(struct platform_device *pdev) { struct dcp *sdcp = NULL; @@ -1272,6 +1446,7 @@ static int dcp_probe(struct platform_device *pdev) for (i = 0; i < DCP_NUM_CHANNELS; i++) { mutex_init(&sdcp->op_mutex[i]); init_completion(&sdcp->op_wait[i]); + sdcp->chan_in_use[i] = false; } platform_set_drvdata(pdev, sdcp); @@ -1282,7 +1457,8 @@ static int dcp_probe(struct platform_device *pdev) ret = -ENXIO; goto err_kfree; } - sdcp->dcp_regs_base = (u32) IO_ADDRESS(r->start); + sdcp->dcp_regs_base = (u32) ioremap(r->start, r->end - r->start + 1); + dcp_clock(sdcp, CLOCK_ON, true); /* Soft reset and remove the clock gate */ __raw_writel(BM_DCP_CTRL_SFTRST, sdcp->dcp_regs_base + HW_DCP_CTRL_SET); @@ -1318,14 +1494,14 @@ static int dcp_probe(struct platform_device *pdev) if (!r) { dev_err(&pdev->dev, "can't get IRQ resource (0)\n"); ret = -EIO; - goto err_kfree; + goto err_gate_clk; } sdcp->dcp_vmi_irq = r->start; ret = request_irq(sdcp->dcp_vmi_irq, dcp_vmi_irq, 0, "dcp", sdcp); if (ret != 0) { dev_err(&pdev->dev, "can't request_irq (0)\n"); - goto err_kfree; + goto err_gate_clk; } r = platform_get_resource(pdev, IORESOURCE_IRQ, 1); @@ -1346,7 +1522,7 @@ static int dcp_probe(struct platform_device *pdev) ret = crypto_register_alg(&dcp_aes_alg); if (ret != 0) { dev_err(&pdev->dev, "Failed to register aes crypto\n"); - goto err_kfree; + goto err_free_irq1; } ret = crypto_register_alg(&dcp_aes_ecb_alg); @@ -1439,9 +1615,30 @@ static int dcp_probe(struct platform_device *pdev) } } + /* register dcpboot interface to allow apps (such as kobs-ng) to + * verify files (such as the bootstream) using the OTP key for crypto */ + ret = misc_register(&dcp_bootstream_misc); + if (ret != 0) { + dev_err(&pdev->dev, "Unable to register misc device\n"); + goto err_unregister_sha1; + } + + sdcp->dcpboot_dma_area = dma_alloc_coherent(&pdev->dev, + sizeof(*sdcp->dcpboot_dma_area), &sdcp->dcpboot_dma_area_phys, + GFP_KERNEL); + if (sdcp->dcpboot_dma_area == NULL) { + dev_err(&pdev->dev, + "Unable to allocate DMAable memory \ + for dcpboot interface\n"); + goto err_dereg; + } + + dcp_clock(sdcp, CLOCK_OFF, false); dev_notice(&pdev->dev, "DCP crypto enabled.!\n"); return 0; +err_dereg: + misc_deregister(&dcp_bootstream_misc); err_unregister_sha1: crypto_unregister_shash(&dcp_sha1_alg); err_unregister_aes_cbc: @@ -1450,8 +1647,12 @@ err_unregister_aes_ecb: crypto_unregister_alg(&dcp_aes_ecb_alg); err_unregister_aes: crypto_unregister_alg(&dcp_aes_alg); +err_free_irq1: + free_irq(sdcp->dcp_irq, sdcp); err_free_irq0: free_irq(sdcp->dcp_vmi_irq, sdcp); +err_gate_clk: + dcp_clock(sdcp, CLOCK_OFF, false); err_kfree: kfree(sdcp); err: @@ -1466,6 +1667,8 @@ static int dcp_remove(struct platform_device *pdev) sdcp = platform_get_drvdata(pdev); platform_set_drvdata(pdev, NULL); + dcp_clock(sdcp, CLOCK_ON, false); + free_irq(sdcp->dcp_irq, sdcp); free_irq(sdcp->dcp_vmi_irq, sdcp); @@ -1487,34 +1690,58 @@ static int dcp_remove(struct platform_device *pdev) sdcp->user_buf_desc, sdcp->user_buf_desc->my_phys); } + if (sdcp->dcpboot_dma_area) { + dma_free_coherent(&pdev->dev, sizeof(*sdcp->dcpboot_dma_area), + sdcp->dcpboot_dma_area, sdcp->dcpboot_dma_area_phys); + misc_deregister(&dcp_bootstream_misc); + } + + crypto_unregister_shash(&dcp_sha1_alg); - crypto_unregister_shash(&dcp_sha256_alg); + + if (__raw_readl(sdcp->dcp_regs_base + HW_DCP_CAPABILITY1) & + BF_DCP_CAPABILITY1_HASH_ALGORITHMS( + BV_DCP_CAPABILITY1_HASH_ALGORITHMS__SHA256)) + crypto_unregister_shash(&dcp_sha256_alg); crypto_unregister_alg(&dcp_aes_cbc_alg); crypto_unregister_alg(&dcp_aes_ecb_alg); crypto_unregister_alg(&dcp_aes_alg); + + dcp_clock(sdcp, CLOCK_OFF, true); + iounmap((void *) sdcp->dcp_regs_base); kfree(sdcp); global_sdcp = NULL; return 0; } - -#ifdef CONFIG_PM static int dcp_suspend(struct platform_device *pdev, pm_message_t state) { +#ifdef CONFIG_PM + struct dcp *sdcp = platform_get_drvdata(pdev); + + if (sdcp->clock_state == CLOCK_ON) { + dcp_clock(sdcp, CLOCK_OFF, true); + /* indicate that clock needs to be turned on upon resume */ + sdcp->clock_state = CLOCK_ON; + } +#endif return 0; } static int dcp_resume(struct platform_device *pdev) { +#ifdef CONFIG_PM + struct dcp *sdcp = platform_get_drvdata(pdev); + + /* if clock was on prior to suspend, turn it back on */ + if (sdcp->clock_state == CLOCK_ON) + dcp_clock(sdcp, CLOCK_ON, true); +#endif return 0; } -#else -#define dcp_suspend NULL -#define dcp_resume NULL -#endif static struct platform_driver dcp_driver = { .probe = dcp_probe, diff --git a/drivers/crypto/dcp.h b/drivers/crypto/dcp.h index 00cd27b479c0..a4db91334d06 100644 --- a/drivers/crypto/dcp.h +++ b/drivers/crypto/dcp.h @@ -19,7 +19,12 @@ #define HASH_CHAN 0 #define HASH_MASK (1 << HASH_CHAN) -#define ALL_MASK (CIPHER_MASK | HASH_MASK) +/* DCP boostream interface uses this channel (same as the ROM) */ +#define ROM_DCP_CHAN 3 +#define ROM_DCP_CHAN_MASK (1 << ROM_DCP_CHAN) + + +#define ALL_MASK (CIPHER_MASK | HASH_MASK | ROM_DCP_CHAN_MASK) /* Defines the initialization value for the dcp control register */ #define DCP_CTRL_INIT \ diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 81e1020fb514..27e06ebc2a59 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -89,6 +89,15 @@ config MX3_IPU_IRQS To avoid bloating the irq_desc[] array we allocate a sufficient number of IRQ slots and map them dynamically to specific sources. +config MXC_PXP + bool "MXC PxP support" + select DMA_ENGINE + +config MXC_PXP_CLIENT_DEVICE + bool "MXC PxP Client Device" + default y + depends on MXC_PXP + config TXX9_DMAC tristate "Toshiba TXx9 SoC DMA support" depends on MACH_TX49XX || MACH_TX39XX diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 40e1e0083571..72c212ac6b79 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_MV_XOR) += mv_xor.o obj-$(CONFIG_DW_DMAC) += dw_dmac.o obj-$(CONFIG_AT_HDMAC) += at_hdmac.o obj-$(CONFIG_MX3_IPU) += ipu/ +obj-$(CONFIG_MXC_PXP) += pxp/ obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index e3235ff8e551..8bb795e7d7b2 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -68,10 +68,19 @@ static u8 *i2c_buf_virt; static void hw_i2c_dmachan_reset(struct mxs_i2c_dev *dev) { + mxs_dma_disable(dev->dma_chan); mxs_dma_reset(dev->dma_chan); mxs_dma_ack_irq(dev->dma_chan); } +static mxs_i2c_reset(struct mxs_i2c_dev *mxs_i2c) +{ + hw_i2c_dmachan_reset(mxs_i2c); + mxs_dma_enable_irq(mxs_i2c->dma_chan, 1); + mxs_reset_block((void __iomem *)mxs_i2c->regbase, 0); + __raw_writel(0x0000FF00, mxs_i2c->regbase + HW_I2C_CTRL1_SET); +} + static int hw_i2c_dma_init(struct platform_device *pdev) { struct mxs_i2c_dev *mxs_i2c = platform_get_drvdata(pdev); @@ -159,7 +168,7 @@ static void hw_i2c_dma_setup_read(u8 addr, void *buff, int len, int flags) desc[0]->cmd.cmd.bits.pio_words = 1; desc[0]->cmd.cmd.bits.wait4end = 1; desc[0]->cmd.cmd.bits.dec_sem = 1; - desc[0]->cmd.cmd.bits.irq = 1; + desc[0]->cmd.cmd.bits.irq = 0; desc[0]->cmd.cmd.bits.chain = 1; desc[0]->cmd.cmd.bits.command = DMA_READ; desc[0]->cmd.address = i2c_buf_phys; @@ -319,6 +328,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, msecs_to_jiffies(1000) ); if (err <= 0) { + mxs_i2c_reset(dev); dev_dbg(dev->dev, "controller is timed out\n"); return -ETIMEDOUT; } @@ -365,9 +375,19 @@ static irqreturn_t mxs_i2c_dma_isr(int this_irq, void *dev_id) mxs_dma_ack_irq(mxs_i2c->dma_chan); mxs_dma_cooked(mxs_i2c->dma_chan, &list); + complete(&mxs_i2c->cmd_complete); + return IRQ_HANDLED; } +static void mxs_i2c_task(struct work_struct *work) +{ + struct mxs_i2c_dev *mxs_i2c = container_of(work, + struct mxs_i2c_dev, work); + mxs_i2c_reset(mxs_i2c); + complete(&mxs_i2c->cmd_complete); +} + #define I2C_IRQ_MASK 0x000000FF static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) { @@ -382,20 +402,8 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) if (stat & BM_I2C_CTRL1_NO_SLAVE_ACK_IRQ) { mxs_i2c->cmd_err = -EREMOTEIO; - - /* - * Stop DMA - * Clear NAK - */ - __raw_writel(BM_I2C_CTRL1_CLR_GOT_A_NAK, - mxs_i2c->regbase + HW_I2C_CTRL1_SET); - hw_i2c_dmachan_reset(mxs_i2c); - mxs_reset_block((void __iomem *)mxs_i2c->regbase, 1); - /* Will catch all error (IRQ mask) */ - __raw_writel(0x0000FF00, mxs_i2c->regbase + HW_I2C_CTRL1_SET); - - complete(&mxs_i2c->cmd_complete); - + /* it takes long time to reset i2c */ + schedule_work(&mxs_i2c->work); goto done; } @@ -407,7 +415,10 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) complete(&mxs_i2c->cmd_complete); goto done; } - if ((stat & done_mask) == done_mask) + + if ((stat & done_mask) == done_mask && + (mxs_i2c->flags & MXS_I2C_PIOQUEUE_MODE)) + complete(&mxs_i2c->cmd_complete); done: @@ -524,6 +535,8 @@ static int mxs_i2c_probe(struct platform_device *pdev) } + INIT_WORK(&mxs_i2c->work, mxs_i2c_task); + return 0; no_i2c_adapter: diff --git a/drivers/i2c/busses/i2c-mxs.h b/drivers/i2c/busses/i2c-mxs.h index 4ddca007624a..1a35385b793b 100644 --- a/drivers/i2c/busses/i2c-mxs.h +++ b/drivers/i2c/busses/i2c-mxs.h @@ -37,5 +37,6 @@ struct mxs_i2c_dev { struct i2c_adapter adapter; spinlock_t lock; wait_queue_head_t queue; + struct work_struct work; }; #endif diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 1148140d08a1..5598ecb48c5b 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -19,6 +19,9 @@ #include <linux/input.h> #include <linux/major.h> #include <linux/device.h> +#ifdef CONFIG_WAKELOCK +#include <linux/wakelock.h> +#endif #include "input-compat.h" struct evdev { @@ -42,6 +45,10 @@ struct evdev_client { struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; +#ifdef CONFIG_WAKELOCK + struct wake_lock wake_lock; + char name[28]; +#endif }; static struct evdev *evdev_table[EVDEV_MINORS]; @@ -54,6 +61,9 @@ static void evdev_pass_event(struct evdev_client *client, * Interrupts are disabled, just acquire the lock */ spin_lock(&client->buffer_lock); +#ifdef CONFIG_WAKELOCK + wake_lock_timeout(&client->wake_lock, 5 * HZ); +#endif client->buffer[client->head++] = *event; client->head &= EVDEV_BUFFER_SIZE - 1; spin_unlock(&client->buffer_lock); @@ -70,8 +80,15 @@ static void evdev_event(struct input_handle *handle, struct evdev *evdev = handle->private; struct evdev_client *client; struct input_event event; +#ifdef CONFIG_WAKELOCK + struct timespec ts; + ktime_get_ts(&ts); + event.time.tv_sec = ts.tv_sec; + event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC; +#else do_gettimeofday(&event.time); +#endif event.type = type; event.code = code; event.value = value; @@ -232,6 +249,9 @@ static int evdev_release(struct inode *inode, struct file *file) mutex_unlock(&evdev->mutex); evdev_detach_client(evdev, client); +#ifdef CONFIG_WAKELOCK + wake_lock_destroy(&client->wake_lock); +#endif kfree(client); evdev_close_device(evdev); @@ -268,6 +288,11 @@ static int evdev_open(struct inode *inode, struct file *file) } spin_lock_init(&client->buffer_lock); +#ifdef CONFIG_WAKELOCK + snprintf(client->name, sizeof(client->name), "%s-%d", dev_name(&evdev->dev), + task_tgid_vnr(current)); + wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name); +#endif client->evdev = evdev; evdev_attach_client(evdev, client); @@ -331,6 +356,10 @@ static int evdev_fetch_next_event(struct evdev_client *client, if (have_event) { *event = client->buffer[client->tail++]; client->tail &= EVDEV_BUFFER_SIZE - 1; +#ifdef CONFIG_WAKELOCK + if (client->head == client->tail) + wake_unlock(&client->wake_lock); +#endif } spin_unlock_irq(&client->buffer_lock); diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index fea01a591076..88e2a24d9cff 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -31,7 +31,7 @@ obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o -obj-$(CONFIG_KEYBOARD_MXC) += mxc_keyb.o +obj-$(CONFIG_KEYBOARD_MXC) += mxc_keyb.o mxc_pwrkey.o obj-$(CONFIG_KEYBOARD_MPR084) += mpr084.o obj-$(CONFIG_KEYBOARD_STMP3XXX) += stmp3xxx-kbd.o obj-$(CONFIG_KEYBOARD_MXS) += mxs-kbd.o diff --git a/drivers/input/keyboard/mxc_keyb.c b/drivers/input/keyboard/mxc_keyb.c index 99dd7cf51cb5..bd5ecd8c20f1 100644 --- a/drivers/input/keyboard/mxc_keyb.c +++ b/drivers/input/keyboard/mxc_keyb.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -58,12 +58,168 @@ #include <linux/clk.h> #include <asm/mach/keypad.h> +/*! + * Keypad Module Name + */ +#define MOD_NAME "mxckpd" + +/*! + * XLATE mode selection + */ +#define KEYPAD_XLATE 0 + +/*! + * RAW mode selection + */ +#define KEYPAD_RAW 1 + +/*! + * Maximum number of keys. + */ +#define MAXROW 8 +#define MAXCOL 8 +#define MXC_MAXKEY (MAXROW * MAXCOL) + +/*! + * This define indicates break scancode for every key release. A constant + * of 128 is added to the key press scancode. + */ +#define MXC_KEYRELEASE 128 + +/* + * _reg_KPP_KPCR _reg_KPP_KPSR _reg_KPP_KDDR _reg_KPP_KPDR + * The offset of Keypad Control Register Address + */ +#define KPCR 0x00 + +/* + * The offset of Keypad Status Register Address + */ +#define KPSR 0x02 + +/* + * The offset of Keypad Data Direction Address + */ +#define KDDR 0x04 + +/* + * The offset of Keypad Data Register + */ +#define KPDR 0x06 + +/* + * Key Press Interrupt Status bit + */ +#define KBD_STAT_KPKD 0x01 + +/* + * Key Release Interrupt Status bit + */ +#define KBD_STAT_KPKR 0x02 + +/* + * Key Depress Synchronizer Chain Status bit + */ +#define KBD_STAT_KDSC 0x04 + +/* + * Key Release Synchronizer Status bit + */ +#define KBD_STAT_KRSS 0x08 + +/* + * Key Depress Interrupt Enable Status bit + */ +#define KBD_STAT_KDIE 0x100 + /* - * Module header file + * Key Release Interrupt Enable */ -#include "mxc_keyb.h" +#define KBD_STAT_KRIE 0x200 + +/* + * Keypad Clock Enable + */ +#define KBD_STAT_KPPEN 0x400 + +/*! + * Buffer size of keypad queue. Should be a power of 2. + */ +#define KPP_BUF_SIZE 128 + +/*! + * Test whether bit is set for integer c + */ +#define TEST_BIT(c, n) ((c) & (0x1 << (n))) + +/*! + * Set nth bit in the integer c + */ +#define BITSET(c, n) ((c) | (1 << (n))) + +/*! + * Reset nth bit in the integer c + */ +#define BITRESET(c, n) ((c) & ~(1 << (n))) + +/*! + * This enum represents the keypad state machine to maintain debounce logic + * for key press/release. + */ +enum KeyState { + + /*! + * Key press state. + */ + KStateUp, + + /*! + * Key press debounce state. + */ + KStateFirstDown, + + /*! + * Key release state. + */ + KStateDown, + + /*! + * Key release debounce state. + */ + KStateFirstUp +}; /*! + * Keypad Private Data Structure + */ +struct keypad_priv { + + /*! + * Keypad state machine. + */ + enum KeyState iKeyState; + + /*! + * Number of rows configured in the keypad matrix + */ + unsigned long kpp_rows; + + /*! + * Number of Columns configured in the keypad matrix + */ + unsigned long kpp_cols; + + /*! + * Timer used for Keypad polling. + */ + struct timer_list poll_timer; + + /*! + * The base address + */ + void __iomem *base; +}; +/*! * This structure holds the keypad private data structure. */ static struct keypad_priv kpp_dev; @@ -269,26 +425,26 @@ static int mxc_kpp_scan_matrix(void) for (col = 0; col < kpp_dev.kpp_cols; col++) { /* Col */ /* 2. Write 1.s to KPDR[15:8] setting column data to 1.s */ - reg_val = __raw_readw(KPDR); + reg_val = __raw_readw(kpp_dev.base + KPDR); reg_val |= 0xff00; - __raw_writew(reg_val, KPDR); + __raw_writew(reg_val, kpp_dev.base + KPDR); /* * 3. Configure columns as totem pole outputs(for quick * discharging of keypad capacitance) */ - reg_val = __raw_readw(KPCR); + reg_val = __raw_readw(kpp_dev.base + KPCR); reg_val &= 0x00ff; - __raw_writew(reg_val, KPCR); + __raw_writew(reg_val, kpp_dev.base + KPCR); udelay(2); /* * 4. Configure columns as open-drain */ - reg_val = __raw_readw(KPCR); + reg_val = __raw_readw(kpp_dev.base + KPCR); reg_val |= ((1 << kpp_dev.kpp_cols) - 1) << 8; - __raw_writew(reg_val, KPCR); + __raw_writew(reg_val, kpp_dev.base + KPCR); /* * 5. Write a single column to 0, others to 1. @@ -298,9 +454,9 @@ static int mxc_kpp_scan_matrix(void) */ /* Col bit starts at 8th bit in KPDR */ - reg_val = __raw_readw(KPDR); + reg_val = __raw_readw(kpp_dev.base + KPDR); reg_val &= ~(1 << (8 + col)); - __raw_writew(reg_val, KPDR); + __raw_writew(reg_val, kpp_dev.base + KPDR); /* Delay added to avoid propagating the 0 from column to row * when scanning. */ @@ -308,7 +464,7 @@ static int mxc_kpp_scan_matrix(void) udelay(5); /* Read row input */ - reg_val = __raw_readw(KPDR); + reg_val = __raw_readw(kpp_dev.base + KPDR); for (row = 0; row < kpp_dev.kpp_rows; row++) { /* sample row */ if (TEST_BIT(reg_val, row) == 0) { cur_rcmap[row] = BITSET(cur_rcmap[row], col); @@ -324,12 +480,12 @@ static int mxc_kpp_scan_matrix(void) * clear the KPKD synchronizer chain by writing "1" to KDSC register */ reg_val = 0x00; - __raw_writew(reg_val, KPDR); - reg_val = __raw_readw(KPDR); - reg_val = __raw_readw(KPSR); + __raw_writew(reg_val, kpp_dev.base + KPDR); + reg_val = __raw_readw(kpp_dev.base + KPDR); + reg_val = __raw_readw(kpp_dev.base + KPSR); reg_val |= KBD_STAT_KPKD | KBD_STAT_KPKR | KBD_STAT_KRSS | KBD_STAT_KDSC; - __raw_writew(reg_val, KPSR); + __raw_writew(reg_val, kpp_dev.base + KPSR); /* Check key press status change */ @@ -558,14 +714,14 @@ static void mxc_kpp_handle_timer(unsigned long data) * Stop scanning and wait for interrupt. * Enable press interrupt and disable release interrupt. */ - __raw_writew(0x00FF, KPDR); - reg_val = __raw_readw(KPSR); + __raw_writew(0x00FF, kpp_dev.base + KPDR); + reg_val = __raw_readw(kpp_dev.base + KPSR); reg_val |= (KBD_STAT_KPKR | KBD_STAT_KPKD); reg_val |= KBD_STAT_KRSS | KBD_STAT_KDSC; - __raw_writew(reg_val, KPSR); + __raw_writew(reg_val, kpp_dev.base + KPSR); reg_val |= KBD_STAT_KDIE; reg_val &= ~KBD_STAT_KRIE; - __raw_writew(reg_val, KPSR); + __raw_writew(reg_val, kpp_dev.base + KPSR); /* * No more keys pressed... make sure unwanted key codes are @@ -613,7 +769,7 @@ static irqreturn_t mxc_kpp_interrupt(int irq, void *dev_id) /* Delete the polling timer */ del_timer(&kpp_dev.poll_timer); - reg_val = __raw_readw(KPSR); + reg_val = __raw_readw(kpp_dev.base + KPSR); /* Check if it is key press interrupt */ if (reg_val & KBD_STAT_KPKD) { @@ -621,7 +777,7 @@ static irqreturn_t mxc_kpp_interrupt(int irq, void *dev_id) * Disable key press(KDIE status bit) interrupt */ reg_val &= ~KBD_STAT_KDIE; - __raw_writew(reg_val, KPSR); + __raw_writew(reg_val, kpp_dev.base + KPSR); } else { /* spurious interrupt */ return IRQ_RETVAL(0); @@ -767,6 +923,7 @@ static int mxc_kpp_probe(struct platform_device *pdev) int i, irq; int retval; unsigned int reg_val; + struct resource *res; keypad = (struct keypad_data *)pdev->dev.platform_data; @@ -774,6 +931,14 @@ static int mxc_kpp_probe(struct platform_device *pdev) kpp_dev.kpp_rows = keypad->rowmax; key_pad_enabled = 0; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + kpp_dev.base = ioremap(res->start, res->end - res->start + 1); + if (!kpp_dev.base) + return -ENOMEM; + irq = platform_get_irq(pdev, 0); keypad->irq = irq; @@ -793,30 +958,30 @@ static int mxc_kpp_probe(struct platform_device *pdev) * LSB nibble in KPP is for 8 rows * MSB nibble in KPP is for 8 cols */ - reg_val = __raw_readw(KPCR); + reg_val = __raw_readw(kpp_dev.base + KPCR); reg_val |= (1 << keypad->rowmax) - 1; /* LSB */ reg_val |= ((1 << keypad->colmax) - 1) << 8; /* MSB */ - __raw_writew(reg_val, KPCR); + __raw_writew(reg_val, kpp_dev.base + KPCR); /* Write 0's to KPDR[15:8] */ - reg_val = __raw_readw(KPDR); + reg_val = __raw_readw(kpp_dev.base + KPDR); reg_val &= 0x00ff; - __raw_writew(reg_val, KPDR); + __raw_writew(reg_val, kpp_dev.base + KPDR); /* Configure columns as output, rows as input (KDDR[15:0]) */ - reg_val = __raw_readw(KDDR); + reg_val = __raw_readw(kpp_dev.base + KDDR); reg_val |= 0xff00; reg_val &= 0xff00; - __raw_writew(reg_val, KDDR); + __raw_writew(reg_val, kpp_dev.base + KDDR); - reg_val = __raw_readw(KPSR); + reg_val = __raw_readw(kpp_dev.base + KPSR); reg_val &= ~(KBD_STAT_KPKR | KBD_STAT_KPKD); reg_val |= KBD_STAT_KPKD; reg_val |= KBD_STAT_KRSS | KBD_STAT_KDSC; - __raw_writew(reg_val, KPSR); + __raw_writew(reg_val, kpp_dev.base + KPSR); reg_val |= KBD_STAT_KDIE; reg_val &= ~KBD_STAT_KRIE; - __raw_writew(reg_val, KPSR); + __raw_writew(reg_val, kpp_dev.base + KPSR); has_leaning_key = keypad->learning; mxckpd_keycodes = keypad->matrix; @@ -912,7 +1077,7 @@ static int mxc_kpp_probe(struct platform_device *pdev) retval = request_irq(irq, mxc_kpp_interrupt, 0, MOD_NAME, MOD_NAME); if (retval) { pr_debug("KPP: request_irq(%d) returned error %d\n", - MXC_INT_KPP, retval); + irq, retval); goto err3; } @@ -950,16 +1115,16 @@ static int mxc_kpp_remove(struct platform_device *pdev) * Set KDIE control bit, clear KRIE control bit (avoid false release * events. Disable the keypad GPIO pins. */ - __raw_writew(0x00, KPCR); - __raw_writew(0x00, KPDR); - __raw_writew(0x00, KDDR); + __raw_writew(0x00, kpp_dev.base + KPCR); + __raw_writew(0x00, kpp_dev.base + KPDR); + __raw_writew(0x00, kpp_dev.base + KDDR); - reg_val = __raw_readw(KPSR); + reg_val = __raw_readw(kpp_dev.base + KPSR); reg_val |= KBD_STAT_KPKD; reg_val &= ~KBD_STAT_KRSS; reg_val |= KBD_STAT_KDIE; reg_val &= ~KBD_STAT_KRIE; - __raw_writew(reg_val, KPSR); + __raw_writew(reg_val, kpp_dev.base + KPSR); gpio_keypad_inactive(); clk_disable(kpp_clk); diff --git a/drivers/input/misc/mma7455l.c b/drivers/input/misc/mma7455l.c index 1cee2d1add04..48dca60d2cfe 100644 --- a/drivers/input/misc/mma7455l.c +++ b/drivers/input/misc/mma7455l.c @@ -583,6 +583,8 @@ static int __devexit mma7455l_remove(struct i2c_client *client) { struct mma7455l_info *mma = dev_get_drvdata(&client->dev); + free_irq(client->irq, mma); + sysfs_remove_group(&client->dev.kobj, &mma7455l_attr_group); input_unregister_device(mma->input_dev); dev_set_drvdata(&client->dev, NULL); diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index ba9d38c3f412..0f74aeee2aea 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -17,14 +17,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include <linux/hwmon.h> +#include <linux/device.h> #include <linux/init.h> -#include <linux/err.h> #include <linux/delay.h> #include <linux/input.h> #include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/gpio.h> #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> #include <asm/irq.h> @@ -33,9 +30,7 @@ /* * This code has been heavily tested on a Nokia 770, and lightly * tested on other ads7846 devices (OSK/Mistral, Lubbock). - * TSC2046 is just newer ads7846 silicon. - * Support for ads7843 tested on Atmel at91sam926x-EK. - * Support for ads7845 has only been stubbed in. + * Support for ads7843 and ads7845 has only been stubbed in. * * IRQ handling needs a workaround because of a shortcoming in handling * edge triggered IRQs on some platforms like the OMAP1/2. These @@ -51,8 +46,7 @@ * files. */ -#define TS_POLL_DELAY (1 * 1000000) /* ns delay before the first sample */ -#define TS_POLL_PERIOD (5 * 1000000) /* ns delay between samples */ +#define TS_POLL_PERIOD msecs_to_jiffies(10) /* this driver doesn't aim at the peak continuous sample rate */ #define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */) @@ -61,77 +55,57 @@ struct ts_event { /* For portability, we can't read 12 bit values using SPI (which * would make the controller deliver them as native byteorder u16 * with msbs zeroed). Instead, we read them as two 8-bit values, - * *** WHICH NEED BYTESWAPPING *** and range adjustment. + * which need byteswapping then range adjustment. */ - u16 x; - u16 y; - u16 z1, z2; - int ignore; -}; - -/* - * We allocate this separately to avoid cache line sharing issues when - * driver is used with DMA-based SPI controllers (like atmel_spi) on - * systems where main memory is not DMA-coherent (most non-x86 boards). - */ -struct ads7846_packet { - u8 read_x, read_y, read_z1, read_z2, pwrdown; - u16 dummy; /* for the pwrdown read */ - struct ts_event tc; + __be16 x; + __be16 y; + __be16 z1, z2; + int ignore; }; struct ads7846 { struct input_dev *input; char phys[32]; - char name[32]; - struct spi_device *spi; - -#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE) - struct attribute_group *attr_group; - struct device *hwmon; -#endif + u32 *txbuf; + u32 *rxbuf; + u8 buflen; + u8 skip_samples; + u16 rotate; + struct spi_device *spi; u16 model; - u16 vref_mv; u16 vref_delay_usecs; u16 x_plate_ohms; u16 pressure_max; - bool swap_xy; - - struct ads7846_packet *packet; + u8 read_x, read_y, read_z1, read_z2, pwrdown; + u16 zerro; /* to send zerros while receiving */ + u16 dummy; /* for the pwrdown read */ + struct ts_event tc; - struct spi_transfer xfer[18]; + struct spi_transfer xfer[10]; struct spi_message msg[5]; struct spi_message *last_msg; int msg_idx; int read_cnt; int read_rep; int last_read; + int skip_this_sample; u16 debounce_max; u16 debounce_tol; u16 debounce_rep; - u16 penirq_recheck_delay_usecs; - spinlock_t lock; - struct hrtimer timer; + struct timer_list timer; /* P: lock */ unsigned pendown:1; /* P: lock */ unsigned pending:1; /* P: lock */ // FIXME remove "irq_disabled" unsigned irq_disabled:1; /* P: lock */ unsigned disabled:1; - unsigned is_suspended:1; - int (*filter)(void *data, int data_idx, int *val); - void *filter_data; - void (*filter_cleanup)(void *data); int (*get_pendown_state)(void); - int gpio_pendown; - - void (*wait_for_sync)(void); }; /* leave chip selected when we're done, for quicker re-select? */ @@ -141,6 +115,7 @@ struct ads7846 { #define CS_CHANGE(xfer) ((xfer).cs_change = 0) #endif + /*--------------------------------------------------------------------------*/ /* The ADS7846 has touchscreen and other sensors. @@ -167,16 +142,19 @@ struct ads7846 { #define MAX_12BIT ((1<<12)-1) /* leave ADC powered up (disables penirq) between differential samples */ -#define READ_12BIT_DFR(x, adc, vref) (ADS_START | ADS_A2A1A0_d_ ## x \ - | ADS_12_BIT | ADS_DFR | \ - (adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0)) +#define READ_12BIT_DFR(x) (ADS_START | ADS_A2A1A0_d_ ## x \ + | ADS_12_BIT | ADS_DFR) + +#define READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ADC_ON) +#define READ_Z1 (READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON) +#define READ_Z2 (READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON) -#define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref)) -#define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref)) -#define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref)) +#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_ADC_ON) +#define PWRDOWN (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) /* LAST */ -#define READ_X(vref) (READ_12BIT_DFR(x, 1, vref)) -#define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */ +/* alternate ads7843 commands */ +#define ALT_READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ALL_ON) +#define ALT_READ_X (READ_12BIT_DFR(x) | ADS_PD10_ALL_ON) /* single-ended samples need to first power up reference voltage; * we leave both ADC and VREF powered @@ -184,15 +162,21 @@ struct ads7846 { #define READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \ | ADS_12_BIT | ADS_SER) -#define REF_ON (READ_12BIT_DFR(x, 1, 1)) -#define REF_OFF (READ_12BIT_DFR(y, 0, 0)) +#define REF_ON (READ_12BIT_DFR(x) | ADS_PD10_ALL_ON) +#define REF_OFF (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) + +#define MAX_BUF_SAMPLE_LEN (20) +/* Following configuration should be done in the platform configuration */ +#define SCREEN_LANDSCAPE 1 +#undef SCREEN_PORTRAIT +#define MAX_DIFF_BETWEEN_SAMPLES_X 100 +#define MAX_DIFF_BETWEEN_SAMPLES_Y 100 + /*--------------------------------------------------------------------------*/ /* * Non-touchscreen sensors only use single-ended conversions. - * The range is GND..vREF. The ads7843 and ads7835 must use external vREF; - * ads7846 lets that pin be unconnected, to use internal vREF. */ struct ser_req { @@ -200,6 +184,7 @@ struct ser_req { u8 command; u8 ref_off; u16 scratch; + u16 zerro; __be16 sample; struct spi_message msg; struct spi_transfer xfer[6]; @@ -211,247 +196,132 @@ static void ads7846_disable(struct ads7846 *ts); static int device_suspended(struct device *dev) { struct ads7846 *ts = dev_get_drvdata(dev); - return ts->is_suspended || ts->disabled; + return dev->power.power_state.event != PM_EVENT_ON || ts->disabled; } +static int ads7843_setup_buffers(struct device *dev) +{ + struct ads7846 *ts = dev_get_drvdata(dev); + int i; + + ts->txbuf = kzalloc(sizeof(u32) * ts->buflen * 3, GFP_KERNEL); + if (!ts->txbuf) + return -ENOMEM; + + ts->rxbuf = kzalloc(sizeof(u32) * ts->buflen * 3, GFP_KERNEL); + if (!ts->rxbuf) { + kfree(ts->txbuf); + return -ENOMEM; + } + for (i = 0; i < ((ts->buflen * 3) / 2); i++) +#if defined( SCREEN_LANDSCAPE ) + ts->txbuf[i] = (READ_12BIT_DFR(x) | ADS_PD10_PDOWN) << 8; +#else + ts->txbuf[i] = (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) << 8; +#endif + for (; i < ts->buflen * 3; i++) +#if defined( SCREEN_LANDSCAPE ) + ts->txbuf[i] = (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) << 8; +#else + ts->txbuf[i] = (READ_12BIT_DFR(x) | ADS_PD10_PDOWN) << 8; +#endif + return 0; +} + + static int ads7846_read12_ser(struct device *dev, unsigned command) { struct spi_device *spi = to_spi_device(dev); struct ads7846 *ts = dev_get_drvdata(dev); struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL); int status; - int use_internal; + int sample; + int i; if (!req) return -ENOMEM; spi_message_init(&req->msg); - /* FIXME boards with ads7846 might use external vref instead ... */ - use_internal = (ts->model == 7846); - - /* maybe turn on internal vREF, and let it settle */ - if (use_internal) { - req->ref_on = REF_ON; - req->xfer[0].tx_buf = &req->ref_on; - req->xfer[0].len = 1; - spi_message_add_tail(&req->xfer[0], &req->msg); - - req->xfer[1].rx_buf = &req->scratch; - req->xfer[1].len = 2; - - /* for 1uF, settle for 800 usec; no cap, 100 usec. */ - req->xfer[1].delay_usecs = ts->vref_delay_usecs; - spi_message_add_tail(&req->xfer[1], &req->msg); - } + /* activate reference, so it has time to settle; */ + req->ref_on = REF_ON; + req->xfer[0].tx_buf = &req->ref_on; + req->xfer[0].len = 1; + req->xfer[1].tx_buf = &req->zerro; + req->xfer[1].rx_buf = &req->scratch; + req->xfer[1].len = 2; + + /* + * for external VREF, 0 usec (and assume it's always on); + * for 1uF, use 800 usec; + * no cap, 100 usec. + */ + req->xfer[1].delay_usecs = ts->vref_delay_usecs; /* take sample */ req->command = (u8) command; req->xfer[2].tx_buf = &req->command; req->xfer[2].len = 1; - spi_message_add_tail(&req->xfer[2], &req->msg); - + req->xfer[3].tx_buf = &req->zerro; req->xfer[3].rx_buf = &req->sample; req->xfer[3].len = 2; - spi_message_add_tail(&req->xfer[3], &req->msg); /* REVISIT: take a few more samples, and compare ... */ - /* converter in low power mode & enable PENIRQ */ - req->ref_off = PWRDOWN; + /* turn off reference */ + req->ref_off = REF_OFF; req->xfer[4].tx_buf = &req->ref_off; req->xfer[4].len = 1; - spi_message_add_tail(&req->xfer[4], &req->msg); - + // TODO req->xfer[3].tx_buf = &req->zerro; + req->xfer[5].tx_buf = &req->zerro; req->xfer[5].rx_buf = &req->scratch; req->xfer[5].len = 2; + CS_CHANGE(req->xfer[5]); - spi_message_add_tail(&req->xfer[5], &req->msg); + + /* group all the transfers together, so we can't interfere with + * reading touchscreen state; disable penirq while sampling + */ + for (i = 0; i < 6; i++) + spi_message_add_tail(&req->xfer[i], &req->msg); ts->irq_disabled = 1; - disable_irq(spi->irq); + disable_irq_nosync(spi->irq); status = spi_sync(spi, &req->msg); ts->irq_disabled = 0; enable_irq(spi->irq); - if (status == 0) { - /* on-wire is a must-ignore bit, a BE12 value, then padding */ - status = be16_to_cpu(req->sample); - status = status >> 3; - status &= 0x0fff; - } + if (req->msg.status) + status = req->msg.status; + + /* on-wire is a must-ignore bit, a BE12 value, then padding */ + sample = be16_to_cpu(req->sample); + sample = sample >> 3; + sample &= 0x0fff; kfree(req); - return status; + return status ? status : sample; } -#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE) - -#define SHOW(name, var, adjust) static ssize_t \ +#define SHOW(name) static ssize_t \ name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \ { \ - struct ads7846 *ts = dev_get_drvdata(dev); \ ssize_t v = ads7846_read12_ser(dev, \ - READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \ + READ_12BIT_SER(name) | ADS_PD10_ALL_ON); \ if (v < 0) \ return v; \ - return sprintf(buf, "%u\n", adjust(ts, v)); \ + return sprintf(buf, "%u\n", (unsigned) v); \ } \ static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL); - -/* Sysfs conventions report temperatures in millidegrees Celsius. - * ADS7846 could use the low-accuracy two-sample scheme, but can't do the high - * accuracy scheme without calibration data. For now we won't try either; - * userspace sees raw sensor values, and must scale/calibrate appropriately. - */ -static inline unsigned null_adjust(struct ads7846 *ts, ssize_t v) -{ - return v; -} - -SHOW(temp0, temp0, null_adjust) /* temp1_input */ -SHOW(temp1, temp1, null_adjust) /* temp2_input */ - - -/* sysfs conventions report voltages in millivolts. We can convert voltages - * if we know vREF. userspace may need to scale vAUX to match the board's - * external resistors; we assume that vBATT only uses the internal ones. - */ -static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v) -{ - unsigned retval = v; - - /* external resistors may scale vAUX into 0..vREF */ - retval *= ts->vref_mv; - retval = retval >> 12; - return retval; -} - -static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v) -{ - unsigned retval = vaux_adjust(ts, v); - - /* ads7846 has a resistor ladder to scale this signal down */ - if (ts->model == 7846) - retval *= 4; - return retval; -} - -SHOW(in0_input, vaux, vaux_adjust) -SHOW(in1_input, vbatt, vbatt_adjust) - - -static struct attribute *ads7846_attributes[] = { - &dev_attr_temp0.attr, - &dev_attr_temp1.attr, - &dev_attr_in0_input.attr, - &dev_attr_in1_input.attr, - NULL, -}; - -static struct attribute_group ads7846_attr_group = { - .attrs = ads7846_attributes, -}; - -static struct attribute *ads7843_attributes[] = { - &dev_attr_in0_input.attr, - &dev_attr_in1_input.attr, - NULL, -}; - -static struct attribute_group ads7843_attr_group = { - .attrs = ads7843_attributes, -}; - -static struct attribute *ads7845_attributes[] = { - &dev_attr_in0_input.attr, - NULL, -}; - -static struct attribute_group ads7845_attr_group = { - .attrs = ads7845_attributes, -}; - -static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts) -{ - struct device *hwmon; - int err; - - /* hwmon sensors need a reference voltage */ - switch (ts->model) { - case 7846: - if (!ts->vref_mv) { - dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n"); - ts->vref_mv = 2500; - } - break; - case 7845: - case 7843: - if (!ts->vref_mv) { - dev_warn(&spi->dev, - "external vREF for ADS%d not specified\n", - ts->model); - return 0; - } - break; - } - - /* different chips have different sensor groups */ - switch (ts->model) { - case 7846: - ts->attr_group = &ads7846_attr_group; - break; - case 7845: - ts->attr_group = &ads7845_attr_group; - break; - case 7843: - ts->attr_group = &ads7843_attr_group; - break; - default: - dev_dbg(&spi->dev, "ADS%d not recognized\n", ts->model); - return 0; - } - - err = sysfs_create_group(&spi->dev.kobj, ts->attr_group); - if (err) - return err; - - hwmon = hwmon_device_register(&spi->dev); - if (IS_ERR(hwmon)) { - sysfs_remove_group(&spi->dev.kobj, ts->attr_group); - return PTR_ERR(hwmon); - } - - ts->hwmon = hwmon; - return 0; -} - -static void ads784x_hwmon_unregister(struct spi_device *spi, - struct ads7846 *ts) -{ - if (ts->hwmon) { - sysfs_remove_group(&spi->dev.kobj, ts->attr_group); - hwmon_device_unregister(ts->hwmon); - } -} - -#else -static inline int ads784x_hwmon_register(struct spi_device *spi, - struct ads7846 *ts) -{ - return 0; -} - -static inline void ads784x_hwmon_unregister(struct spi_device *spi, - struct ads7846 *ts) -{ -} -#endif +SHOW(temp0) +SHOW(temp1) +SHOW(vaux) +SHOW(vbatt) static int is_pen_down(struct device *dev) { - struct ads7846 *ts = dev_get_drvdata(dev); + struct ads7846 *ts = dev_get_drvdata(dev); return ts->pendown; } @@ -477,11 +347,10 @@ static ssize_t ads7846_disable_store(struct device *dev, const char *buf, size_t count) { struct ads7846 *ts = dev_get_drvdata(dev); - unsigned long i; - - if (strict_strtoul(buf, 10, &i)) - return -EINVAL; + char *endp; + int i; + i = simple_strtoul(buf, &endp, 10); spin_lock_irq(&ts->lock); if (i) @@ -496,30 +365,8 @@ static ssize_t ads7846_disable_store(struct device *dev, static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store); -static struct attribute *ads784x_attributes[] = { - &dev_attr_pen_down.attr, - &dev_attr_disable.attr, - NULL, -}; - -static struct attribute_group ads784x_attr_group = { - .attrs = ads784x_attributes, -}; - /*--------------------------------------------------------------------------*/ -static int get_pendown_state(struct ads7846 *ts) -{ - if (ts->get_pendown_state) - return ts->get_pendown_state(); - - return !gpio_get_value(ts->gpio_pendown); -} - -static void null_wait_for_sync(void) -{ -} - /* * PENIRQ only kicks the timer. The timer only reissues the SPI transfer, * to retrieve touchscreen status. @@ -531,25 +378,25 @@ static void null_wait_for_sync(void) static void ads7846_rx(void *ads) { struct ads7846 *ts = ads; - struct ads7846_packet *packet = ts->packet; + struct input_dev *input_dev = ts->input; unsigned Rt; + unsigned sync = 0; u16 x, y, z1, z2; + unsigned long flags; - /* ads7846_rx_val() did in-place conversion (including byteswap) from - * on-the-wire format as part of debouncing to get stable readings. + /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding; + * built from two 8 bit values written msb-first. */ - x = packet->tc.x; - y = packet->tc.y; - z1 = packet->tc.z1; - z2 = packet->tc.z2; + x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff; + y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff; + z1 = (be16_to_cpu(ts->tc.z1) >> 3) & 0x0fff; + z2 = (be16_to_cpu(ts->tc.z2) >> 3) & 0x0fff; /* range filtering */ if (x == MAX_12BIT) x = 0; - if (ts->model == 7843) { - Rt = ts->pressure_max / 2; - } else if (likely(x && z1)) { + if (likely(x && z1 && !device_suspended(&ts->spi->dev))) { /* compute touch pressure resistance using equation #2 */ Rt = z2; Rt -= z1; @@ -557,194 +404,281 @@ static void ads7846_rx(void *ads) Rt *= ts->x_plate_ohms; Rt /= z1; Rt = (Rt + 2047) >> 12; - } else { + } else Rt = 0; - } /* Sample found inconsistent by debouncing or pressure is beyond - * the maximum. Don't report it to user space, repeat at least - * once more the measurement - */ - if (packet->tc.ignore || Rt > ts->pressure_max) { -#ifdef VERBOSE - pr_debug("%s: ignored %d pressure %d\n", - dev_name(&ts->spi->dev), packet->tc.ignore, Rt); -#endif - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), - HRTIMER_MODE_REL); + * the maximum. Don't report it to user space, repeat at least + * once more the measurement */ + if (ts->tc.ignore || Rt > ts->pressure_max) { + mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); return; } - /* Maybe check the pendown state before reporting. This discards - * false readings when the pen is lifted. + /* NOTE: "pendown" is inferred from pressure; we don't rely on + * being able to check nPENIRQ status, or "friendly" trigger modes + * (both-edges is much better than just-falling or low-level). + * + * REVISIT: some boards may require reading nPENIRQ; it's + * needed on 7843. and 7845 reads pressure differently... + * + * REVISIT: the touchscreen might not be connected; this code + * won't notice that, even if nPENIRQ never fires ... */ - if (ts->penirq_recheck_delay_usecs) { - udelay(ts->penirq_recheck_delay_usecs); - if (!get_pendown_state(ts)) - Rt = 0; + if (!ts->pendown && Rt != 0) { + input_report_key(input_dev, BTN_TOUCH, 1); + sync = 1; + } else if (ts->pendown && Rt == 0) { + input_report_key(input_dev, BTN_TOUCH, 0); + sync = 1; } - /* NOTE: We can't rely on the pressure to determine the pen down - * state, even this controller has a pressure sensor. The pressure - * value can fluctuate for quite a while after lifting the pen and - * in some cases may not even settle at the expected value. - * - * The only safe way to check for the pen up condition is in the - * timer by reading the pen signal state (it's a GPIO _and_ IRQ). - */ if (Rt) { - struct input_dev *input = ts->input; + input_report_abs(input_dev, ABS_X, x); + input_report_abs(input_dev, ABS_Y, y); + sync = 1; + } - if (!ts->pendown) { - input_report_key(input, BTN_TOUCH, 1); - ts->pendown = 1; -#ifdef VERBOSE - dev_dbg(&ts->spi->dev, "DOWN\n"); + if (sync) { + input_report_abs(input_dev, ABS_PRESSURE, Rt); + input_sync(input_dev); + } + +#ifdef VERBOSE + if (Rt || ts->pendown) + pr_debug("%s: %d/%d/%d%s\n", dev_name(&ts->spi->dev), + x, y, Rt, Rt ? "" : " UP"); #endif + + spin_lock_irqsave(&ts->lock, flags); + + ts->pendown = (Rt != 0); + mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); + + spin_unlock_irqrestore(&ts->lock, flags); +} + +static inline u16 ad7843_get_sample_val(u32 sample) +{ + return (((((sample & 0x00ff0000) >> 8) | (sample >> 24)) >> 3) & 0x0fff); +} + +static u32 ad7843_get_better_values(struct ads7846 *ts, int index, int skiplimit) +{ + u32 diff12, diff23, diff31; + u32 vals[3]; + int i; + + for (i = 0; i < 3; i++) { + vals[i] = ad7843_get_sample_val(ts->rxbuf[index+i]); + if (vals[i] == 0x0fff || vals[i] == 0) { + ts->skip_this_sample = 1; + return 0; } + } - if (ts->swap_xy) - swap(x, y); + diff12 = (vals[0] > vals[1]) ? vals[0] - vals[1] : vals[1] - vals[0]; + if (diff12 > skiplimit) { + ts->skip_this_sample = 1; + return 0; + } - input_report_abs(input, ABS_X, x); - input_report_abs(input, ABS_Y, y); - input_report_abs(input, ABS_PRESSURE, Rt); + diff23 = (vals[1] > vals[2]) ? vals[1] - vals[2] : vals[2] - vals[1]; + if (diff23 > skiplimit) { + ts->skip_this_sample = 1; + return 0; + } - input_sync(input); -#ifdef VERBOSE - dev_dbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt); -#endif + diff31 = (vals[2] > vals[0]) ? vals[2] - vals[0] : vals[0] - vals[2]; + if (diff31 > skiplimit) { + ts->skip_this_sample = 1; + return 0; } - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), - HRTIMER_MODE_REL); + if (diff12 < diff23 && diff12 < diff31) + return (vals[0] + vals[1]) / 2; + if (diff23 < diff12 && diff23 < diff31) + return (vals[1] + vals[2]) / 2; + + return (vals[0] + vals[2]) / 2; } -static int ads7846_debounce(void *ads, int data_idx, int *val) +static void ads7843_rx_average(void *ads) +{ + struct ads7846 *ts = ads; + struct input_dev *input_dev = ts->input; + u16 x, y, temp; + unsigned long flags; + int i, sample_count; + + dev_dbg(&ts->spi->dev, "%s\n", __FUNCTION__); + + for (i = 0, y = 0, x = 0, sample_count = 0; i < (ts->buflen * 3 / 2); i+=3) { + if (i >= ts->skip_samples*3) { + temp = ad7843_get_better_values(ts, i, MAX_DIFF_BETWEEN_SAMPLES_Y); + if (!ts->skip_this_sample) { + if (ts->rotate == 180) { + y += MAX_12BIT - temp; + } else if (ts->rotate == 0) { + y += temp; + } else { + dev_info(&ts->spi->dev, + "Rotate mode %d, not implemented yet\n", + ts->rotate); + } + sample_count++; + } + } + ts->skip_this_sample = 0; + } + + if (!sample_count) + goto sample_taken; + + y /= sample_count; + + for (sample_count = 0; i < (ts->buflen * 3); i+=3) { + if (i >= (ts->skip_samples + ts->buflen / 2)*3) { + temp = ad7843_get_better_values(ts, i, MAX_DIFF_BETWEEN_SAMPLES_X); + if (!ts->skip_this_sample) { + if (ts->rotate == 180) { + x += MAX_12BIT - temp; + } else if (ts->rotate == 0) { + x += temp; + } else { + dev_info(&ts->spi->dev, + "Rotate mode %d, not implemented yet\n", + ts->rotate); + } + sample_count++; + } + } + ts->skip_this_sample = 0; + } + + if (!sample_count) + goto sample_taken; + + x /= sample_count; + + if (ts->pendown) { + + input_report_key(input_dev, BTN_TOUCH, 1); + input_report_abs(input_dev, ABS_PRESSURE, ts->pressure_max / 2); + input_report_abs(input_dev, ABS_X, x); + input_report_abs(input_dev, ABS_Y, y); + } else { + input_report_key(input_dev, BTN_TOUCH, 0); + input_report_abs(input_dev, ABS_PRESSURE, 0); + } + + input_sync(input_dev); + dev_dbg(&ts->spi->dev, "%d/%d %s\n", x, y, ts->pendown ? "" : " UP"); + +sample_taken: + if (ts->pendown) { + spin_lock_irqsave(&ts->lock, flags); + mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); + spin_unlock_irqrestore(&ts->lock, flags); + } +} + +static void ads7846_debounce(void *ads) { struct ads7846 *ts = ads; + struct spi_message *m; + struct spi_transfer *t; + int val; + int status; - if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) { - /* Start over collecting consistent readings. */ - ts->read_rep = 0; + m = &ts->msg[ts->msg_idx]; + t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); + val = (be16_to_cpu(*(__be16 *)t->rx_buf) >> 3) & 0x0fff; + if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) { /* Repeat it, if this was the first read or the read * wasn't consistent enough. */ if (ts->read_cnt < ts->debounce_max) { - ts->last_read = *val; + ts->last_read = val; ts->read_cnt++; - return ADS7846_FILTER_REPEAT; } else { /* Maximum number of debouncing reached and still * not enough number of consistent readings. Abort * the whole sample, repeat it in the next sampling * period. */ + ts->tc.ignore = 1; ts->read_cnt = 0; - return ADS7846_FILTER_IGNORE; + /* Last message will contain ads7846_rx() as the + * completion function. + */ + m = ts->last_msg; } + /* Start over collecting consistent readings. */ + ts->read_rep = 0; } else { if (++ts->read_rep > ts->debounce_rep) { /* Got a good reading for this coordinate, * go for the next one. */ + ts->tc.ignore = 0; + ts->msg_idx++; ts->read_cnt = 0; ts->read_rep = 0; - return ADS7846_FILTER_OK; - } else { + m++; + } else /* Read more values that are consistent. */ ts->read_cnt++; - return ADS7846_FILTER_REPEAT; - } } -} - -static int ads7846_no_filter(void *ads, int data_idx, int *val) -{ - return ADS7846_FILTER_OK; -} - -static void ads7846_rx_val(void *ads) -{ - struct ads7846 *ts = ads; - struct ads7846_packet *packet = ts->packet; - struct spi_message *m; - struct spi_transfer *t; - int val; - int action; - int status; - - m = &ts->msg[ts->msg_idx]; - t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); - - /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding; - * built from two 8 bit values written msb-first. - */ - val = be16_to_cpup((__be16 *)t->rx_buf) >> 3; - - action = ts->filter(ts->filter_data, ts->msg_idx, &val); - switch (action) { - case ADS7846_FILTER_REPEAT: - break; - case ADS7846_FILTER_IGNORE: - packet->tc.ignore = 1; - /* Last message will contain ads7846_rx() as the - * completion function. - */ - m = ts->last_msg; - break; - case ADS7846_FILTER_OK: - *(u16 *)t->rx_buf = val; - packet->tc.ignore = 0; - m = &ts->msg[++ts->msg_idx]; - break; - default: - BUG(); - } - ts->wait_for_sync(); status = spi_async(ts->spi, m); if (status) dev_err(&ts->spi->dev, "spi_async --> %d\n", status); } -static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) +static void ads7846_timer(unsigned long handle) { - struct ads7846 *ts = container_of(handle, struct ads7846, timer); - int status = 0; + struct ads7846 *ts = (void *)handle; + struct input_dev *input_dev = ts->input; + int status = 0; - spin_lock(&ts->lock); - - if (unlikely(!get_pendown_state(ts) || - device_suspended(&ts->spi->dev))) { - if (ts->pendown) { - struct input_dev *input = ts->input; - - input_report_key(input, BTN_TOUCH, 0); - input_report_abs(input, ABS_PRESSURE, 0); - input_sync(input); + /* get sample */ + ts->pendown = ts->get_pendown_state(); + spin_lock_irq(&ts->lock); + if (ts->model == 7843) { + ts->pending = 0; + if (unlikely(!ts->pendown)) { - ts->pendown = 0; -#ifdef VERBOSE - dev_dbg(&ts->spi->dev, "UP\n"); -#endif - } + input_report_key(input_dev, BTN_TOUCH, 0); + input_report_abs(input_dev, ABS_PRESSURE, 0); + input_sync(input_dev); - /* measurement cycle ended */ - if (!device_suspended(&ts->spi->dev)) { - ts->irq_disabled = 0; - enable_irq(ts->spi->irq); + if (!device_suspended(&ts->spi->dev)) { + ts->irq_disabled = 0; + enable_irq(ts->spi->irq); + } + } else { + /* pen is still down, continue with the measurement */ + status = spi_async(ts->spi, &ts->msg[0]); + if (status) + dev_err(&ts->spi->dev, "spi_async --> %d\n", status); } - ts->pending = 0; } else { - /* pen is still down, continue with the measurement */ - ts->msg_idx = 0; - ts->wait_for_sync(); - status = spi_async(ts->spi, &ts->msg[0]); - if (status) - dev_err(&ts->spi->dev, "spi_async --> %d\n", status); + if (unlikely(ts->msg_idx && !ts->pendown)) { + /* measurement cycle ended */ + if (!device_suspended(&ts->spi->dev)) { + ts->irq_disabled = 0; + enable_irq(ts->spi->irq); + } + ts->pending = 0; + ts->msg_idx = 0; + } else { + /* pen is still down, continue with the measurement */ + ts->msg_idx = 0; + status = spi_async(ts->spi, &ts->msg[0]); + if (status) + dev_err(&ts->spi->dev, "spi_async --> %d\n", status); + } } - - spin_unlock(&ts->lock); - return HRTIMER_NORESTART; + spin_unlock_irq(&ts->lock); } static irqreturn_t ads7846_irq(int irq, void *handle) @@ -753,7 +687,8 @@ static irqreturn_t ads7846_irq(int irq, void *handle) unsigned long flags; spin_lock_irqsave(&ts->lock, flags); - if (likely(get_pendown_state(ts))) { + + if (likely(ts->get_pendown_state())) { if (!ts->irq_disabled) { /* The ARM do_simple_IRQ() dispatcher doesn't act * like the other dispatchers: it will report IRQs @@ -763,8 +698,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) ts->irq_disabled = 1; disable_irq_nosync(ts->spi->irq); ts->pending = 1; - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY), - HRTIMER_MODE_REL); + mod_timer(&ts->timer, jiffies); } } spin_unlock_irqrestore(&ts->lock, flags); @@ -785,7 +719,7 @@ static void ads7846_disable(struct ads7846 *ts) /* are we waiting for IRQ, or polling? */ if (!ts->pending) { ts->irq_disabled = 1; - disable_irq(ts->spi->irq); + disable_irq_nosync(ts->spi->irq); } else { /* the timer will run at least once more, and * leave everything in a clean state, IRQ disabled @@ -800,6 +734,7 @@ static void ads7846_disable(struct ads7846 *ts) /* we know the chip's in lowpower mode since we always * leave it that way after every request */ + } /* Must be called with ts->lock held */ @@ -819,7 +754,7 @@ static int ads7846_suspend(struct spi_device *spi, pm_message_t message) spin_lock_irq(&ts->lock); - ts->is_suspended = 1; + spi->dev.power.power_state = message; ads7846_disable(ts); spin_unlock_irq(&ts->lock); @@ -834,7 +769,7 @@ static int ads7846_resume(struct spi_device *spi) spin_lock_irq(&ts->lock); - ts->is_suspended = 0; + spi->dev.power.power_state = PMSG_ON; ads7846_enable(ts); spin_unlock_irq(&ts->lock); @@ -842,45 +777,13 @@ static int ads7846_resume(struct spi_device *spi) return 0; } -static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts) -{ - struct ads7846_platform_data *pdata = spi->dev.platform_data; - int err; - - /* REVISIT when the irq can be triggered active-low, or if for some - * reason the touchscreen isn't hooked up, we don't need to access - * the pendown state. - */ - if (!pdata->get_pendown_state && !gpio_is_valid(pdata->gpio_pendown)) { - dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n"); - return -EINVAL; - } - - if (pdata->get_pendown_state) { - ts->get_pendown_state = pdata->get_pendown_state; - return 0; - } - - err = gpio_request(pdata->gpio_pendown, "ads7846_pendown"); - if (err) { - dev_err(&spi->dev, "failed to request pendown GPIO%d\n", - pdata->gpio_pendown); - return err; - } - - ts->gpio_pendown = pdata->gpio_pendown; - return 0; -} - static int __devinit ads7846_probe(struct spi_device *spi) { struct ads7846 *ts; - struct ads7846_packet *packet; struct input_dev *input_dev; struct ads7846_platform_data *pdata = spi->dev.platform_data; struct spi_message *m; struct spi_transfer *x; - int vref; int err; if (!spi->irq) { @@ -900,33 +803,46 @@ static int __devinit ads7846_probe(struct spi_device *spi) return -EINVAL; } + /* REVISIT when the irq can be triggered active-low, or if for some + * reason the touchscreen isn't hooked up, we don't need to access + * the pendown state. + */ + if (pdata->get_pendown_state == NULL) { + dev_dbg(&spi->dev, "no get_pendown_state function?\n"); + return -EINVAL; + } + /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except * that even if the hardware can do that, the SPI controller driver * may not. So we stick to very-portable 8 bit words, both RX and TX. */ spi->bits_per_word = 8; - spi->mode = SPI_MODE_0; - err = spi_setup(spi); - if (err < 0) - return err; ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL); - packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL); input_dev = input_allocate_device(); - if (!ts || !packet || !input_dev) { + if (!ts || !input_dev) { err = -ENOMEM; goto err_free_mem; } dev_set_drvdata(&spi->dev, ts); - ts->packet = packet; + spi->dev.power.power_state = PMSG_ON; + ts->spi = spi; ts->input = input_dev; - ts->vref_mv = pdata->vref_mv; - ts->swap_xy = pdata->swap_xy; - hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->buflen = pdata->buflen ? : MAX_BUF_SAMPLE_LEN; + ts->buflen = ts->buflen & ~0x1; /* must be even */ + + if (ads7843_setup_buffers(&spi->dev)) { + dev_dbg(&spi->dev, "error allocating memory for sample buffers\n"); + err = -ENOMEM; + goto err_free_mem; + } + + init_timer(&ts->timer); + ts->timer.data = (unsigned long) ts; ts->timer.function = ads7846_timer; spin_lock_init(&ts->lock); @@ -935,40 +851,22 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; ts->pressure_max = pdata->pressure_max ? : ~0; + ts->skip_samples = pdata->skip_samples ? : 0; + ts->rotate = pdata->rotate ? : 0; - if (pdata->filter != NULL) { - if (pdata->filter_init != NULL) { - err = pdata->filter_init(pdata, &ts->filter_data); - if (err < 0) - goto err_free_mem; - } - ts->filter = pdata->filter; - ts->filter_cleanup = pdata->filter_cleanup; - } else if (pdata->debounce_max) { + if (pdata->debounce_max) { ts->debounce_max = pdata->debounce_max; - if (ts->debounce_max < 2) - ts->debounce_max = 2; ts->debounce_tol = pdata->debounce_tol; ts->debounce_rep = pdata->debounce_rep; - ts->filter = ads7846_debounce; - ts->filter_data = ts; + if (ts->debounce_rep > ts->debounce_max + 1) + ts->debounce_rep = ts->debounce_max - 1; } else - ts->filter = ads7846_no_filter; - - err = setup_pendown(spi, ts); - if (err) - goto err_cleanup_filter; - - if (pdata->penirq_recheck_delay_usecs) - ts->penirq_recheck_delay_usecs = - pdata->penirq_recheck_delay_usecs; - - ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync; + ts->debounce_tol = ~0; + ts->get_pendown_state = pdata->get_pendown_state; snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev)); - snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model); - input_dev->name = ts->name; + input_dev->name = "ADS784x Touchscreen"; input_dev->phys = ts->phys; input_dev->dev.parent = &spi->dev; @@ -983,9 +881,8 @@ static int __devinit ads7846_probe(struct spi_device *spi) pdata->y_max ? : MAX_12BIT, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, - pdata->pressure_min, pdata->pressure_max, 0, 0); - - vref = pdata->keep_vref_on; + pdata->pressure_min ? : 0, + pdata->pressure_max ? : 1, 0, 0); /* set up the transfers to read touchscreen state; this assumes we * use formula #2 for pressure, not #3. @@ -995,209 +892,176 @@ static int __devinit ads7846_probe(struct spi_device *spi) spi_message_init(m); - /* y- still on; turn on only y+ (and ADC) */ - packet->read_y = READ_Y(vref); - x->tx_buf = &packet->read_y; - x->len = 1; - spi_message_add_tail(x, m); - - x++; - x->rx_buf = &packet->tc.y; - x->len = 2; - spi_message_add_tail(x, m); - - /* the first sample after switching drivers can be low quality; - * optionally discard it, using a second one after the signals - * have had enough time to stabilize. - */ - if (pdata->settle_delay_usecs) { - x->delay_usecs = pdata->settle_delay_usecs; - - x++; - x->tx_buf = &packet->read_y; - x->len = 1; + if (ts->model == 7843) { + x->tx_buf = ts->txbuf; + x->rx_buf = ts->rxbuf; + x->len = ts->buflen * sizeof(u32) * 3; /* For every sample we take 3 samples and choose the better 2 */ spi_message_add_tail(x, m); - x++; - x->rx_buf = &packet->tc.y; - x->len = 2; - spi_message_add_tail(x, m); - } - - m->complete = ads7846_rx_val; - m->context = ts; - - m++; - spi_message_init(m); - - /* turn y- off, x+ on, then leave in lowpower */ - x++; - packet->read_x = READ_X(vref); - x->tx_buf = &packet->read_x; - x->len = 1; - spi_message_add_tail(x, m); - - x++; - x->rx_buf = &packet->tc.x; - x->len = 2; - spi_message_add_tail(x, m); - - /* ... maybe discard first sample ... */ - if (pdata->settle_delay_usecs) { - x->delay_usecs = pdata->settle_delay_usecs; + m->complete = ads7843_rx_average; + m->context = ts; - x++; - x->tx_buf = &packet->read_x; + ts->last_msg = m; + } else { + /* y- still on; turn on only y+ (and ADC) */ + ts->read_y = READ_Y; + x->tx_buf = &ts->read_y; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &packet->tc.x; + x->rx_buf = &ts->tc.y; x->len = 2; spi_message_add_tail(x, m); - } - m->complete = ads7846_rx_val; - m->context = ts; + m->complete = ads7846_debounce; + m->context = ts; - /* turn y+ off, x- on; we'll use formula #2 */ - if (ts->model == 7846) { m++; spi_message_init(m); + /* turn y- off, x+ on, then leave in lowpower */ x++; - packet->read_z1 = READ_Z1(vref); - x->tx_buf = &packet->read_z1; + ts->read_x = READ_X; + x->tx_buf = &ts->read_x; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &packet->tc.z1; + x->rx_buf = &ts->tc.x; x->len = 2; spi_message_add_tail(x, m); - /* ... maybe discard first sample ... */ - if (pdata->settle_delay_usecs) { - x->delay_usecs = pdata->settle_delay_usecs; + m->complete = ads7846_debounce; + m->context = ts; + + /* turn y+ off, x- on; we'll use formula #2 */ + if (ts->model == 7846) { + m++; + spi_message_init(m); x++; - x->tx_buf = &packet->read_z1; + ts->read_z1 = READ_Z1; + x->tx_buf = &ts->read_z1; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &packet->tc.z1; + x->rx_buf = &ts->tc.z1; x->len = 2; spi_message_add_tail(x, m); - } - - m->complete = ads7846_rx_val; - m->context = ts; - - m++; - spi_message_init(m); - x++; - packet->read_z2 = READ_Z2(vref); - x->tx_buf = &packet->read_z2; - x->len = 1; - spi_message_add_tail(x, m); - - x++; - x->rx_buf = &packet->tc.z2; - x->len = 2; - spi_message_add_tail(x, m); + m->complete = ads7846_debounce; + m->context = ts; - /* ... maybe discard first sample ... */ - if (pdata->settle_delay_usecs) { - x->delay_usecs = pdata->settle_delay_usecs; + m++; + spi_message_init(m); x++; - x->tx_buf = &packet->read_z2; + ts->read_z2 = READ_Z2; + x->tx_buf = &ts->read_z2; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &packet->tc.z2; + x->rx_buf = &ts->tc.z2; x->len = 2; spi_message_add_tail(x, m); - } - m->complete = ads7846_rx_val; - m->context = ts; - } + m->complete = ads7846_debounce; + m->context = ts; + } - /* power down */ - m++; - spi_message_init(m); + /* power down */ + m++; + spi_message_init(m); - x++; - packet->pwrdown = PWRDOWN; - x->tx_buf = &packet->pwrdown; - x->len = 1; - spi_message_add_tail(x, m); + x++; + ts->pwrdown = PWRDOWN; + x->tx_buf = &ts->pwrdown; + x->len = 1; + spi_message_add_tail(x, m); - x++; - x->rx_buf = &packet->dummy; - x->len = 2; - CS_CHANGE(*x); - spi_message_add_tail(x, m); + x++; + x->rx_buf = &ts->dummy; + x->len = 2; + CS_CHANGE(*x); + spi_message_add_tail(x, m); - m->complete = ads7846_rx; - m->context = ts; + m->complete = ads7846_rx; + m->context = ts; - ts->last_msg = m; + ts->last_msg = m; + } if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING, spi->dev.driver->name, ts)) { - dev_info(&spi->dev, - "trying pin change workaround on irq %d\n", spi->irq); - err = request_irq(spi->irq, ads7846_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - spi->dev.driver->name, ts); - if (err) { - dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); - goto err_free_gpio; - } + dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); + err = -EBUSY; + goto err_free_buf; } - err = ads784x_hwmon_register(spi, ts); - if (err) - goto err_free_irq; - dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq); - /* take a first sample, leaving nPENIRQ active and vREF off; avoid + /* take a first sample, leaving nPENIRQ active; avoid * the touchscreen, in case it's not connected. */ - (void) ads7846_read12_ser(&spi->dev, - READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON); + if (ts->model != 7843) { + /* take a first sample, leaving nPENIRQ active; avoid + * the touchscreen, in case it's not connected. + */ + (void) ads7846_read12_ser(&spi->dev, + READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON); + } - err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group); - if (err) - goto err_remove_hwmon; + /* ads7843/7845 don't have temperature sensors, and + * use the other sensors a bit differently too + */ + if (ts->model == 7846) { + device_create_file(&spi->dev, &dev_attr_temp0); + device_create_file(&spi->dev, &dev_attr_temp1); + } + + if (ts->model != 7845 && ts->model != 7843) + device_create_file(&spi->dev, &dev_attr_vbatt); + + if (ts->model != 7843) { + device_create_file(&spi->dev, &dev_attr_vaux); + } + + device_create_file(&spi->dev, &dev_attr_pen_down); + device_create_file(&spi->dev, &dev_attr_disable); err = input_register_device(input_dev); if (err) - goto err_remove_attr_group; + goto err_remove_attr; return 0; - err_remove_attr_group: - sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group); - err_remove_hwmon: - ads784x_hwmon_unregister(spi, ts); - err_free_irq: + err_remove_attr: + device_remove_file(&spi->dev, &dev_attr_disable); + device_remove_file(&spi->dev, &dev_attr_pen_down); + if (ts->model == 7846) { + device_remove_file(&spi->dev, &dev_attr_temp1); + device_remove_file(&spi->dev, &dev_attr_temp0); + } + + if (ts->model != 7845 && ts->model != 7843) + device_remove_file(&spi->dev, &dev_attr_vbatt); + + if (ts->model != 7843) { + device_remove_file(&spi->dev, &dev_attr_vaux); + } + free_irq(spi->irq, ts); - err_free_gpio: - if (ts->gpio_pendown != -1) - gpio_free(ts->gpio_pendown); - err_cleanup_filter: - if (ts->filter_cleanup) - ts->filter_cleanup(ts->filter_data); + + err_free_buf: + if (ts->txbuf) + kfree(ts->txbuf); + if (ts->rxbuf) + kfree(ts->rxbuf); err_free_mem: input_free_device(input_dev); - kfree(packet); kfree(ts); return err; } @@ -1206,24 +1070,33 @@ static int __devexit ads7846_remove(struct spi_device *spi) { struct ads7846 *ts = dev_get_drvdata(&spi->dev); - ads784x_hwmon_unregister(spi, ts); input_unregister_device(ts->input); ads7846_suspend(spi, PMSG_SUSPEND); - sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group); + if (ts->txbuf) + kfree(ts->txbuf); + if (ts->rxbuf) + kfree(ts->rxbuf); - free_irq(ts->spi->irq, ts); - /* suspend left the IRQ disabled */ - enable_irq(ts->spi->irq); + device_remove_file(&spi->dev, &dev_attr_disable); + device_remove_file(&spi->dev, &dev_attr_pen_down); + if (ts->model == 7846) { + device_remove_file(&spi->dev, &dev_attr_temp1); + device_remove_file(&spi->dev, &dev_attr_temp0); + } + + if (ts->model != 7845 && ts->model != 7843) + device_remove_file(&spi->dev, &dev_attr_vbatt); - if (ts->gpio_pendown != -1) - gpio_free(ts->gpio_pendown); + if (ts->model != 7843) { + device_remove_file(&spi->dev, &dev_attr_vaux); + } - if (ts->filter_cleanup) - ts->filter_cleanup(ts->filter_data); + free_irq(ts->spi->irq, ts); + /* suspend left the IRQ disabled */ + disable_irq_nosync(ts->spi->irq); - kfree(ts->packet); kfree(ts); dev_dbg(&spi->dev, "unregistered touchscreen\n"); diff --git a/drivers/input/touchscreen/mxc_ts.c b/drivers/input/touchscreen/mxc_ts.c index 610f31e65778..6cce76f1494f 100644 --- a/drivers/input/touchscreen/mxc_ts.c +++ b/drivers/input/touchscreen/mxc_ts.c @@ -43,6 +43,9 @@ #include <linux/pmic_external.h> #include <linux/pmic_adc.h> #include <linux/kthread.h> +#ifdef CONFIG_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif #define MXC_TS_NAME "mxc_ts" @@ -60,6 +63,30 @@ static struct task_struct *tstask; static int calibration[7]; module_param_array(calibration, int, NULL, S_IRUGO | S_IWUSR); +#ifdef CONFIG_EARLYSUSPEND + +static wait_queue_head_t ts_wait; +static int ts_suspend; + +static void stop_ts_early_suspend(struct early_suspend *h) +{ + ts_suspend = 1; +} + +static void start_ts_late_resume(struct early_suspend *h) +{ + ts_suspend = 0; + wake_up_interruptible(&ts_wait); +} + +static struct early_suspend stop_ts_early_suspend_desc = { + .level = EARLY_SUSPEND_LEVEL_STOP_DRAWING, + .suspend = stop_ts_early_suspend, + .resume = start_ts_late_resume, +}; + +#endif + static int ts_thread(void *arg) { t_touch_screen ts_sample; @@ -69,6 +96,9 @@ static int ts_thread(void *arg) int x, y; static int last_x = -1, last_y = -1, last_press = -1; +#ifdef CONFIG_EARLYSUSPEND + wait_event_interruptible(ts_wait, !ts_suspend); +#endif memset(&ts_sample, 0, sizeof(t_touch_screen)); /* After 2 consecutive samples with the pen up, enable irq waiting */ @@ -76,14 +106,13 @@ static int ts_thread(void *arg) msleep(20); continue; } - if (!(ts_sample.contact_resistance || wait)) - { + if (!(ts_sample.contact_resistance || wait)) { msleep(20); continue; } if (ts_sample.x_position == 0 && ts_sample.y_position == 0 && - ts_sample.contact_resistance == 0) { + ts_sample.contact_resistance == 0) { x = last_x; y = last_y; } else if (calibration[6] == 0) { @@ -91,14 +120,14 @@ static int ts_thread(void *arg) y = ts_sample.y_position; } else { x = calibration[0] * (int)ts_sample.x_position + - calibration[1] * (int)ts_sample.y_position + - calibration[2]; + calibration[1] * (int)ts_sample.y_position + + calibration[2]; x /= calibration[6]; if (x < 0) x = 0; y = calibration[3] * (int)ts_sample.x_position + - calibration[4] * (int)ts_sample.y_position + - calibration[5]; + calibration[4] * (int)ts_sample.y_position + + calibration[5]; y /= calibration[6]; if (y < 0) y = 0; @@ -127,7 +156,7 @@ static int ts_thread(void *arg) /* report the BTN_TOUCH */ if (ts_sample.contact_resistance != last_press) input_event(mxc_inputdev, EV_KEY, - BTN_TOUCH, ts_sample.contact_resistance); + BTN_TOUCH, ts_sample.contact_resistance); input_sync(mxc_inputdev); last_press = ts_sample.contact_resistance; @@ -148,8 +177,7 @@ static int __init mxc_ts_init(void) mxc_inputdev = input_allocate_device(); if (!mxc_inputdev) { - printk(KERN_ERR - "mxc_ts_init: not enough memory\n"); + printk(KERN_ERR "mxc_ts_init: not enough memory\n"); return -ENOMEM; } @@ -166,11 +194,14 @@ static int __init mxc_ts_init(void) tstask = kthread_run(ts_thread, NULL, "mxc_ts"); if (IS_ERR(tstask)) { - printk(KERN_ERR - "mxc_ts_init: failed to create kthread"); + printk(KERN_ERR "mxc_ts_init: failed to create kthread"); tstask = NULL; return -1; } +#ifdef CONFIG_EARLYSUSPEND + init_waitqueue_head(&ts_wait); + register_early_suspend(&stop_ts_early_suspend_desc); +#endif printk("mxc input touchscreen loaded\n"); return 0; } @@ -186,6 +217,9 @@ static void __exit mxc_ts_exit(void) input_free_device(mxc_inputdev); mxc_inputdev = NULL; } +#ifdef CONFIG_EARLYSUSPEND + unregister_early_suspend(&stop_ts_early_suspend_desc); +#endif } late_initcall(mxc_ts_init); diff --git a/drivers/leds/leds-mxs-pwm.c b/drivers/leds/leds-mxs-pwm.c index c76821770446..a546900a44d0 100644 --- a/drivers/leds/leds-mxs-pwm.c +++ b/drivers/leds/leds-mxs-pwm.c @@ -165,10 +165,35 @@ static int __devexit mxs_pwm_led_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int mxs_led_suspend(struct platform_device *dev, pm_message_t state) +{ + int i; + + for (i = 0; i < leds.led_num; i++) + led_classdev_suspend(&leds.leds[i].dev); + return 0; +} + +static int mxs_led_resume(struct platform_device *dev) +{ + int i; + + for (i = 0; i < leds.led_num; i++) + led_classdev_resume(&leds.leds[i].dev); + return 0; +} +#else +#define mxs_led_suspend NULL +#define mxs_led_resume NULL +#endif + static struct platform_driver mxs_pwm_led_driver = { .probe = mxs_pwm_led_probe, .remove = __devexit_p(mxs_pwm_led_remove), + .suspend = mxs_led_suspend, + .resume = mxs_led_resume, .driver = { .name = "mxs-leds", }, diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c64c8d201262..e7185d1cf281 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -592,6 +592,17 @@ config VIDEO_MXS_PXP To compile this driver as a module, choose M here: the module will be called pxp. +config VIDEO_MXC_PXP_V4L2 + tristate "MXC PxP V4L2 driver" + depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_MX5 + select VIDEOBUF_DMA_CONTIG + ---help--- + This is a video4linux driver for the Freescale PxP + (Pixel Pipeline). This module supports output overlay of + the MXC framebuffer on a video stream. + + To compile this driver as a module, choose M here. + config VIDEO_MXC_OPL tristate depends on VIDEO_DEV && ARCH_MXC diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 49cb18802024..a4de2a151253 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -94,6 +94,7 @@ obj-$(CONFIG_VIDEO_MXC_CSI_CAMERA) += mxc/capture/ obj-$(CONFIG_VIDEO_MXC_IPU_OUTPUT) += mxc/output/ obj-$(CONFIG_VIDEO_MXC_IPUV1_WVGA_OUTPUT) += mxc/output/ obj-$(CONFIG_VIDEO_MXC_EMMA_OUTPUT) += mxc/output/ +obj-$(CONFIG_VIDEO_MXC_PXP_V4L2) += mxc/output/ obj-$(CONFIG_VIDEO_MXC_OPL) += mxc/opl/ obj-$(CONFIG_VIDEO_PXP) += pxp.o obj-$(CONFIG_VIDEO_MXS_PXP) += mxs_pxp.o diff --git a/drivers/media/video/mxc/capture/Kconfig b/drivers/media/video/mxc/capture/Kconfig index adab0a886f36..276dfa424feb 100644 --- a/drivers/media/video/mxc/capture/Kconfig +++ b/drivers/media/video/mxc/capture/Kconfig @@ -58,6 +58,22 @@ config MXC_CAMERA_MICRON111 ---help--- If you plan to use the mt9v111 Camera with your MXC system, say Y here. +config MXC_CAMERA_MICRON111_1 + tristate "Micron mt9v111 camera 1 support" + select I2C_MXC + depends on ! VIDEO_MXC_EMMA_CAMERA + depends on MXC_CAMERA_MICRON111 + ---help--- + If you plan to use the mt9v111 Camera 1 with your MXC system, say Y here. + +config MXC_CAMERA_MICRON111_2 + tristate "Micron mt9v111 camera 2 support" + select I2C_MXC + depends on ! VIDEO_MXC_EMMA_CAMERA + depends on MXC_CAMERA_MICRON111 + ---help--- + If you plan to use the mt9v111 Camera 2 with your MXC system, say Y here. + config MXC_CAMERA_OV2640 tristate "OmniVision ov2640 camera support" depends on !VIDEO_MXC_EMMA_CAMERA @@ -72,7 +88,7 @@ config MXC_CAMERA_OV3640 config MXC_TVIN_ADV7180 tristate "Analog Device adv7180 TV Decoder Input support" - depends on MACH_MX35_3DS + depends on (MACH_MX35_3DS || MACH_MX51_3DS) ---help--- If you plan to use the adv7180 video decoder with your MXC system, say Y here. diff --git a/drivers/media/video/mxc/capture/Makefile b/drivers/media/video/mxc/capture/Makefile index 112923c8fc8f..03ff094171bf 100644 --- a/drivers/media/video/mxc/capture/Makefile +++ b/drivers/media/video/mxc/capture/Makefile @@ -35,5 +35,5 @@ obj-$(CONFIG_MXC_CAMERA_OV2640) += ov2640_camera.o ov3640_camera-objs := ov3640.o sensor_clock.o obj-$(CONFIG_MXC_CAMERA_OV3640) += ov3640_camera.o -adv7180_tvin-objs := adv7180.o sensor_clock.o +adv7180_tvin-objs := adv7180.o obj-$(CONFIG_MXC_TVIN_ADV7180) += adv7180_tvin.o diff --git a/drivers/media/video/mxc/capture/adv7180.c b/drivers/media/video/mxc/capture/adv7180.c index 1edee763bebc..527a0d1ad9fa 100644 --- a/drivers/media/video/mxc/capture/adv7180.c +++ b/drivers/media/video/mxc/capture/adv7180.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -39,6 +39,7 @@ static struct regulator *dvddio_regulator; static struct regulator *dvdd_regulator; static struct regulator *avdd_regulator; static struct regulator *pvdd_regulator; +static struct mxc_tvin_platform_data *tvin_plat; extern void gpio_sensor_active(void); extern void gpio_sensor_inactive(void); @@ -118,26 +119,26 @@ static video_fmt_t video_fmts[] = { { /*! NTSC */ .v4l2_id = V4L2_STD_NTSC, .name = "NTSC", - .raw_width = 720 - 1, /* SENS_FRM_WIDTH */ - .raw_height = 288 - 1, /* SENS_FRM_HEIGHT */ + .raw_width = 720, /* SENS_FRM_WIDTH */ + .raw_height = 525, /* SENS_FRM_HEIGHT */ .active_width = 720, /* ACT_FRM_WIDTH plus 1 */ - .active_height = (480 / 2), /* ACT_FRM_WIDTH plus 1 */ + .active_height = 480, /* ACT_FRM_WIDTH plus 1 */ }, { /*! (B, G, H, I, N) PAL */ .v4l2_id = V4L2_STD_PAL, .name = "PAL", - .raw_width = 720 - 1, - .raw_height = (576 / 2) + 24 * 2 - 1, + .raw_width = 720, + .raw_height = 625, .active_width = 720, - .active_height = (576 / 2), + .active_height = 576, }, { /*! Unlocked standard */ .v4l2_id = V4L2_STD_ALL, .name = "Autodetect", - .raw_width = 720 - 1, - .raw_height = (576 / 2) + 24 * 2 - 1, + .raw_width = 720, + .raw_height = 625, .active_width = 720, - .active_height = (576 / 2), + .active_height = 576, }, }; @@ -246,6 +247,10 @@ static void adv7180_get_std(v4l2_std_id *std) dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180_get_std\n"); + /* Make sure power on */ + if (tvin_plat->pwdn) + tvin_plat->pwdn(0); + /* Read the AD_RESULT to get the detect output video standard */ tmp = adv7180_read(ADV7180_STATUS_1) & 0x70; @@ -335,6 +340,11 @@ static int ioctl_s_power(struct v4l2_int_device *s, int on) if (on && !sensor->on) { gpio_sensor_active(); + + /* Make sure pwoer on */ + if (tvin_plat->pwdn) + tvin_plat->pwdn(0); + if (adv7180_write_reg(ADV7180_PWR_MNG, 0) != 0) return -EIO; } else if (!on && sensor->on) { @@ -500,6 +510,10 @@ static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_g_ctrl\n"); + /* Make sure power on */ + if (tvin_plat->pwdn) + tvin_plat->pwdn(0); + switch (vc->id) { case V4L2_CID_BRIGHTNESS: dev_dbg(&adv7180_data.i2c_client->dev, @@ -593,6 +607,10 @@ static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_s_ctrl\n"); + /* Make sure power on */ + if (tvin_plat->pwdn) + tvin_plat->pwdn(0); + switch (vc->id) { case V4L2_CID_BRIGHTNESS: dev_dbg(&adv7180_data.i2c_client->dev, @@ -803,13 +821,13 @@ static int adv7180_probe(struct i2c_client *client, { int rev_id; int ret = 0; - struct mxc_tvin_platform_data *plat_data = client->dev.platform_data; + tvin_plat = client->dev.platform_data; dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180_probe\n"); - if (plat_data->dvddio_reg) { + if (tvin_plat->dvddio_reg) { dvddio_regulator = - regulator_get(&client->dev, plat_data->dvddio_reg); + regulator_get(&client->dev, tvin_plat->dvddio_reg); if (!IS_ERR_VALUE((unsigned long)dvddio_regulator)) { regulator_set_voltage(dvddio_regulator, 3300000, 3300000); if (regulator_enable(dvddio_regulator) != 0) @@ -817,9 +835,9 @@ static int adv7180_probe(struct i2c_client *client, } } - if (plat_data->dvdd_reg) { + if (tvin_plat->dvdd_reg) { dvdd_regulator = - regulator_get(&client->dev, plat_data->dvdd_reg); + regulator_get(&client->dev, tvin_plat->dvdd_reg); if (!IS_ERR_VALUE((unsigned long)dvdd_regulator)) { regulator_set_voltage(dvdd_regulator, 1800000, 1800000); if (regulator_enable(dvdd_regulator) != 0) @@ -827,9 +845,9 @@ static int adv7180_probe(struct i2c_client *client, } } - if (plat_data->avdd_reg) { + if (tvin_plat->avdd_reg) { avdd_regulator = - regulator_get(&client->dev, plat_data->avdd_reg); + regulator_get(&client->dev, tvin_plat->avdd_reg); if (!IS_ERR_VALUE((unsigned long)avdd_regulator)) { regulator_set_voltage(avdd_regulator, 1800000, 1800000); if (regulator_enable(avdd_regulator) != 0) @@ -837,9 +855,9 @@ static int adv7180_probe(struct i2c_client *client, } } - if (plat_data->pvdd_reg) { + if (tvin_plat->pvdd_reg) { pvdd_regulator = - regulator_get(&client->dev, plat_data->pvdd_reg); + regulator_get(&client->dev, tvin_plat->pvdd_reg); if (!IS_ERR_VALUE((unsigned long)pvdd_regulator)) { regulator_set_voltage(pvdd_regulator, 1800000, 1800000); if (regulator_enable(pvdd_regulator) != 0) @@ -847,11 +865,12 @@ static int adv7180_probe(struct i2c_client *client, } } - if (plat_data->reset) - plat_data->reset(); - if (plat_data->pwdn) - plat_data->pwdn(1); + if (tvin_plat->reset) + tvin_plat->reset(); + + if (tvin_plat->pwdn) + tvin_plat->pwdn(0); msleep(1); @@ -913,7 +932,7 @@ static int adv7180_detach(struct i2c_client *client) __func__, IF_NAME, client->addr << 1, client->adapter->name); if (plat_data->pwdn) - plat_data->pwdn(0); + plat_data->pwdn(1); if (dvddio_regulator) { regulator_disable(dvddio_regulator); diff --git a/drivers/media/video/mxc/capture/csi_v4l2_capture.c b/drivers/media/video/mxc/capture/csi_v4l2_capture.c index 9bddc3692996..cf224e0673f0 100644 --- a/drivers/media/video/mxc/capture/csi_v4l2_capture.c +++ b/drivers/media/video/mxc/capture/csi_v4l2_capture.c @@ -1,5 +1,5 @@ /* - * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -789,15 +789,15 @@ static ssize_t csi_v4l_read(struct file *file, char *buf, size_t count, (cam->v2f.fmt. pix.sizeimage), &cam-> - still_buf, + still_buf[0], GFP_DMA | GFP_KERNEL); if (cam->still_buf_vaddr == NULL) { pr_err("alloc dma memory failed\n"); return -ENOMEM; } cam->still_counter = 0; - __raw_writel(cam->still_buf, CSI_CSIDMASA_FB2); - __raw_writel(cam->still_buf, CSI_CSIDMASA_FB1); + __raw_writel(cam->still_buf[0], CSI_CSIDMASA_FB2); + __raw_writel(cam->still_buf[0], CSI_CSIDMASA_FB1); __raw_writel(__raw_readl(CSI_CSICR3) | BIT_DMA_REFLASH_RFF, CSI_CSICR3); __raw_writel(__raw_readl(CSI_CSISR), CSI_CSISR); @@ -813,8 +813,8 @@ static ssize_t csi_v4l_read(struct file *file, char *buf, size_t count, if (cam->still_buf_vaddr != NULL) { dma_free_coherent(0, PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), - cam->still_buf_vaddr, cam->still_buf); - cam->still_buf = 0; + cam->still_buf_vaddr, cam->still_buf[0]); + cam->still_buf[0] = 0; cam->still_buf_vaddr = NULL; } diff --git a/drivers/media/video/mxc/capture/emma_v4l2_capture.c b/drivers/media/video/mxc/capture/emma_v4l2_capture.c index 9cb08b26f1cd..170807716ec6 100644 --- a/drivers/media/video/mxc/capture/emma_v4l2_capture.c +++ b/drivers/media/video/mxc/capture/emma_v4l2_capture.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -858,7 +858,7 @@ static void mxc_csi_dma_chaining(void *data) /* Config DMA */ memset(&dma_request, 0, sizeof(mxc_dma_requestbuf_t)); - dma_request.dst_addr = cam->still_buf + dma_request.dst_addr = cam->still_buf[0] + (chained % max_dma) * CSI_DMA_LENGTH; dma_request.src_addr = (dma_addr_t) CSI_CSIRXFIFO_PHYADDR; dma_request.num_of_bytes = count; @@ -1040,7 +1040,7 @@ mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t *ppos) cam->still_buf_vaddr = dma_alloc_coherent(0, PAGE_ALIGN(CSI_MEM_SIZE), - &cam->still_buf, + &cam->still_buf[0], GFP_DMA | GFP_KERNEL); if (!cam->still_buf_vaddr) { @@ -1120,8 +1120,8 @@ mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t *ppos) exit1: dma_free_coherent(0, PAGE_ALIGN(CSI_MEM_SIZE), - cam->still_buf_vaddr, cam->still_buf); - cam->still_buf = 0; + cam->still_buf_vaddr, cam->still_buf[0]); + cam->still_buf[0] = 0; exit0: up(&cam->busy_lock); @@ -1160,7 +1160,8 @@ mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t *ppos) v_address = dma_alloc_coherent(0, PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), - &cam->still_buf, GFP_DMA | GFP_KERNEL); + &cam->still_buf[0], + GFP_DMA | GFP_KERNEL); if (!v_address) { pr_info("mxc_v4l_read failed at allocate still_buf\n"); @@ -1194,8 +1195,8 @@ mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t *ppos) exit1: dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address, - cam->still_buf); - cam->still_buf = 0; + cam->still_buf[0]); + cam->still_buf[0] = 0; exit0: up(&cam->busy_lock); diff --git a/drivers/media/video/mxc/capture/ipu_csi_enc.c b/drivers/media/video/mxc/capture/ipu_csi_enc.c index fd3f0c132c14..0b87282551ff 100644 --- a/drivers/media/video/mxc/capture/ipu_csi_enc.c +++ b/drivers/media/video/mxc/capture/ipu_csi_enc.c @@ -25,6 +25,7 @@ #include "ipu_prp_sw.h" #ifdef CAMERA_DBG + extern void ipu_dump_registers(void); #define CAMERA_TRACE(x) (printk)x #else #define CAMERA_TRACE(x) @@ -66,6 +67,7 @@ static int csi_enc_setup(cam_data *cam) u32 pixel_fmt; int err = 0; dma_addr_t dummy = cam->dummy_frame.buffer.m.offset; + ipu_channel_t channel; CAMERA_TRACE("In csi_enc_setup\n"); if (!cam) { @@ -101,13 +103,18 @@ static int csi_enc_setup(cam_data *cam) ipu_csi_enable_mclk_if(CSI_MCLK_ENC, cam->csi, true, true); - err = ipu_init_channel(CSI_MEM, ¶ms); + if (cam->csi == 0) + channel = CSI_MEM0; + else + channel = CSI_MEM1; + + err = ipu_init_channel(channel, ¶ms); if (err != 0) { printk(KERN_ERR "ipu_init_channel %d\n", err); return err; } - err = ipu_init_channel_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, + err = ipu_init_channel_buffer(channel, IPU_OUTPUT_BUFFER, pixel_fmt, cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height, cam->v2f.fmt.pix.width, IPU_ROTATE_NONE, @@ -115,12 +122,12 @@ static int csi_enc_setup(cam_data *cam) cam->offset.u_offset, cam->offset.v_offset); if (err != 0) { - printk(KERN_ERR "CSI_MEM output buffer\n"); + printk(KERN_ERR "CSI_MEM%d output buffer\n",cam->csi); return err; } - err = ipu_enable_channel(CSI_MEM); + err = ipu_enable_channel(channel); if (err < 0) { - printk(KERN_ERR "ipu_enable_channel CSI_MEM\n"); + printk(KERN_ERR "ipu_enable_channel CSI_MEM%d\n",cam->csi); return err; } @@ -135,24 +142,34 @@ static int csi_enc_setup(cam_data *cam) * * @return status */ -static int csi_enc_eba_update(dma_addr_t eba, int *buffer_num) +static int csi_enc_eba_update(int csi, dma_addr_t eba, int *buffer_num) { int err = 0; + ipu_channel_t channel; + + if (csi == 0) + channel = CSI_MEM0; + else + channel = CSI_MEM1; - pr_debug("eba %x\n", eba); - err = ipu_update_channel_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, + err = ipu_update_channel_buffer(channel, IPU_OUTPUT_BUFFER, *buffer_num, eba); + if (err != 0) { - ipu_clear_buffer_ready(CSI_MEM, IPU_OUTPUT_BUFFER, + ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, *buffer_num); printk(KERN_ERR "err %d buffer_num %d\n", err, *buffer_num); return err; } - ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num); + ipu_select_buffer(channel, IPU_OUTPUT_BUFFER, *buffer_num); *buffer_num = (*buffer_num == 0) ? 1 : 0; +#ifdef CAMERA_DBG + ipu_dump_registers (); +#endif + return 0; } @@ -166,6 +183,7 @@ static int csi_enc_enabling_tasks(void *private) { cam_data *cam = (cam_data *) private; int err = 0; + int ipu_irq_csi_out_eof; CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n"); cam->dummy_frame.vaddress = dma_alloc_coherent(0, @@ -182,11 +200,16 @@ static int csi_enc_enabling_tasks(void *private) PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage); cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress; - ipu_clear_irq(IPU_IRQ_CSI0_OUT_EOF); - err = ipu_request_irq(IPU_IRQ_CSI0_OUT_EOF, - csi_enc_callback, 0, "Mxc Camera", cam); + if (cam->csi == 0) + ipu_irq_csi_out_eof = IPU_IRQ_CSI0_OUT_EOF; + else + ipu_irq_csi_out_eof = IPU_IRQ_CSI1_OUT_EOF; + ipu_clear_irq(ipu_irq_csi_out_eof); + err = ipu_request_irq(ipu_irq_csi_out_eof, + csi_enc_callback, 0, "Mxc Camera", cam); + if (err != 0) { - printk(KERN_ERR "Error registering rot irq\n"); + printk(KERN_ERR "Error registering eot irq for csi %d\n",cam->csi); return err; } @@ -209,12 +232,24 @@ static int csi_enc_disabling_tasks(void *private) { cam_data *cam = (cam_data *) private; int err = 0; + ipu_channel_t channel; + int ipu_irq_csi_out_eof; - ipu_free_irq(IPU_IRQ_CSI0_OUT_EOF, cam); + if (cam->csi == 0) + { + channel = CSI_MEM0; + ipu_irq_csi_out_eof = IPU_IRQ_CSI0_OUT_EOF; + } + else + { + channel = CSI_MEM1; + ipu_irq_csi_out_eof = IPU_IRQ_CSI1_OUT_EOF; + } - err = ipu_disable_channel(CSI_MEM, true); + ipu_free_irq(ipu_irq_csi_out_eof, cam); + err = ipu_disable_channel(channel, true); - ipu_uninit_channel(CSI_MEM); + ipu_uninit_channel(channel); if (cam->dummy_frame.vaddress != 0) { dma_free_coherent(0, cam->dummy_frame.buffer.length, diff --git a/drivers/media/video/mxc/capture/ipu_prp_enc.c b/drivers/media/video/mxc/capture/ipu_prp_enc.c index 4b5426cb887d..0df8050ad7de 100644 --- a/drivers/media/video/mxc/capture/ipu_prp_enc.c +++ b/drivers/media/video/mxc/capture/ipu_prp_enc.c @@ -19,12 +19,14 @@ * @ingroup IPU */ +#include <linux/types.h> #include <linux/dma-mapping.h> #include <linux/ipu.h> #include "mxc_v4l2_capture.h" #include "ipu_prp_sw.h" #ifdef CAMERA_DBG + extern void ipu_dump_registers(void); #define CAMERA_TRACE(x) (printk)x #else #define CAMERA_TRACE(x) @@ -266,11 +268,10 @@ static int prp_enc_setup(cam_data * cam) * * @return status */ -static int prp_enc_eba_update(dma_addr_t eba, int *buffer_num) +static int prp_enc_eba_update(int csi, dma_addr_t eba, int *buffer_num) { int err = 0; - pr_debug("eba %x\n", eba); if (grotation >= IPU_ROTATE_90_RIGHT) { err = ipu_update_channel_buffer(MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER, *buffer_num, @@ -294,6 +295,11 @@ static int prp_enc_eba_update(dma_addr_t eba, int *buffer_num) } *buffer_num = (*buffer_num == 0) ? 1 : 0; + +#ifdef CAMERA_DBG + ipu_dump_registers (); +#endif + return 0; } @@ -350,7 +356,6 @@ static int prp_enc_disabling_tasks(void *private) if (cam->rotation >= IPU_ROTATE_90_RIGHT) { ipu_unlink_channels(CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM); } - err = ipu_disable_channel(CSI_PRP_ENC_MEM, true); if (cam->rotation >= IPU_ROTATE_90_RIGHT) { err |= ipu_disable_channel(MEM_ROT_ENC_MEM, true); diff --git a/drivers/media/video/mxc/capture/ipu_prp_vf_sdc_bg.c b/drivers/media/video/mxc/capture/ipu_prp_vf_sdc_bg.c index 7f0984c42950..9f8078d558b0 100644 --- a/drivers/media/video/mxc/capture/ipu_prp_vf_sdc_bg.c +++ b/drivers/media/video/mxc/capture/ipu_prp_vf_sdc_bg.c @@ -182,6 +182,7 @@ static int prpvf_start(void *private) printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n"); goto out_3; } + err = ipu_init_channel(MEM_ROT_VF_MEM, NULL); if (err != 0) { printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n"); @@ -200,6 +201,7 @@ static int prpvf_start(void *private) } if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) { + err = ipu_init_channel_buffer(MEM_ROT_VF_MEM, IPU_OUTPUT_BUFFER, format, vf.csi_prp_vf_mem.out_height, diff --git a/drivers/media/video/mxc/capture/ipu_still.c b/drivers/media/video/mxc/capture/ipu_still.c index 348bf2b9b564..22cf3f51e1cb 100644 --- a/drivers/media/video/mxc/capture/ipu_still.c +++ b/drivers/media/video/mxc/capture/ipu_still.c @@ -26,6 +26,9 @@ #include "ipu_prp_sw.h" static int callback_eof_flag; +#ifndef CONFIG_MXC_IPU_V1 +static int buffer_num; +#endif #ifdef CONFIG_MXC_IPU_V1 static int callback_flag; @@ -42,10 +45,10 @@ static int callback_flag; */ static irqreturn_t prp_csi_eof_callback(int irq, void *dev_id) { - if (callback_flag == 2) { - ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, 0); + ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, + callback_flag%2 ? 1 : 0); + if (callback_flag == 0) ipu_enable_channel(CSI_MEM); - } callback_flag++; return IRQ_HANDLED; @@ -65,9 +68,12 @@ static irqreturn_t prp_still_callback(int irq, void *dev_id) cam_data *cam = (cam_data *) dev_id; callback_eof_flag++; - if (callback_eof_flag < 5) - ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, 0); - else { + if (callback_eof_flag < 5) { +#ifndef CONFIG_MXC_IPU_V1 + buffer_num = (buffer_num == 0) ? 1 : 0; + ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, buffer_num); +#endif + } else { cam->still_counter++; wake_up_interruptible(&cam->still_queue); } @@ -87,6 +93,8 @@ static int prp_still_start(void *private) u32 pixel_fmt; int err; ipu_channel_params_t params; + ipu_channel_t channel; + int ipu_irq_csi_out_eof; if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) pixel_fmt = IPU_PIX_FMT_YUV420P; @@ -113,20 +121,32 @@ static int prp_still_start(void *private) ipu_csi_enable_mclk_if(CSI_MCLK_RAW, cam->csi, true, true); + if (cam->csi == 0) { + channel = CSI_MEM0; + ipu_irq_csi_out_eof = IPU_IRQ_CSI0_OUT_EOF; + } + else { + channel = CSI_MEM1; + ipu_irq_csi_out_eof = IPU_IRQ_CSI1_OUT_EOF; + } + memset(¶ms, 0, sizeof(params)); - err = ipu_init_channel(CSI_MEM, ¶ms); + params.csi_mem.csi = cam->csi; + err = ipu_init_channel(channel, ¶ms); if (err != 0) return err; - err = ipu_init_channel_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, + err = ipu_init_channel_buffer(channel, IPU_OUTPUT_BUFFER, pixel_fmt, cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height, cam->v2f.fmt.pix.width, IPU_ROTATE_NONE, - cam->still_buf, 0, 0, 0); + cam->still_buf[0], cam->still_buf[1], + 0, 0); if (err != 0) return err; #ifdef CONFIG_MXC_IPU_V1 + ipu_clear_irq(IPU_IRQ_SENSOR_OUT_EOF); err = ipu_request_irq(IPU_IRQ_SENSOR_OUT_EOF, prp_still_callback, 0, "Mxc Camera", cam); if (err != 0) { @@ -135,6 +155,7 @@ static int prp_still_start(void *private) } callback_flag = 0; callback_eof_flag = 0; + ipu_clear_irq(IPU_IRQ_SENSOR_EOF); err = ipu_request_irq(IPU_IRQ_SENSOR_EOF, prp_csi_eof_callback, 0, "Mxc Camera", NULL); if (err != 0) { @@ -142,8 +163,9 @@ static int prp_still_start(void *private) return err; } #else - ipu_clear_irq(IPU_IRQ_CSI0_OUT_EOF); - err = ipu_request_irq(IPU_IRQ_CSI0_OUT_EOF, prp_still_callback, + + ipu_clear_irq(ipu_irq_csi_out_eof); + err = ipu_request_irq(ipu_irq_csi_out_eof, prp_still_callback, 0, "Mxc Camera", cam); if (err != 0) { printk(KERN_ERR "Error registering irq.\n"); @@ -151,9 +173,9 @@ static int prp_still_start(void *private) } callback_eof_flag = 0; + ipu_select_buffer(channel, IPU_OUTPUT_BUFFER, 0); + ipu_enable_channel(channel); - ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, 0); - ipu_enable_channel(CSI_MEM); ipu_enable_csi(cam->csi); #endif @@ -170,17 +192,28 @@ static int prp_still_stop(void *private) { cam_data *cam = (cam_data *) private; int err = 0; + ipu_channel_t channel; + int ipu_irq_csi_out_eof; + + if (cam->csi == 0) { + channel = CSI_MEM0; + ipu_irq_csi_out_eof = IPU_IRQ_CSI0_OUT_EOF; + } + else { + channel = CSI_MEM1; + ipu_irq_csi_out_eof = IPU_IRQ_CSI1_OUT_EOF; + } #ifdef CONFIG_MXC_IPU_V1 ipu_free_irq(IPU_IRQ_SENSOR_EOF, NULL); ipu_free_irq(IPU_IRQ_SENSOR_OUT_EOF, cam); #else - ipu_free_irq(IPU_IRQ_CSI0_OUT_EOF, cam); + ipu_free_irq(ipu_irq_csi_out_eof, cam); #endif ipu_disable_csi(cam->csi); - ipu_disable_channel(CSI_MEM, true); - ipu_uninit_channel(CSI_MEM); + ipu_disable_channel(channel, true); + ipu_uninit_channel(channel); ipu_csi_enable_mclk_if(CSI_MCLK_RAW, cam->csi, false, false); return err; diff --git a/drivers/media/video/mxc/capture/mt9v111.c b/drivers/media/video/mxc/capture/mt9v111.c index c95a20683924..dfdd455db3dd 100644 --- a/drivers/media/video/mxc/capture/mt9v111.c +++ b/drivers/media/video/mxc/capture/mt9v111.c @@ -18,6 +18,9 @@ * * @ingroup Camera */ + +//#define MT9V111_DEBUG + #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -40,7 +43,6 @@ static mt9v111_conf mt9v111_device; /*! * Holds the current frame rate. */ -static int reset_frame_rate = MT9V111_FRAME_RATE; struct sensor { const struct mt9v111_platform_data *platform_data; @@ -49,33 +51,45 @@ struct sensor { struct v4l2_pix_format pix; struct v4l2_captureparm streamcap; bool on; + bool used; /* control settings */ int brightness; - int hue; - int contrast; int saturation; - int red; - int green; - int blue; + int sharpness; + int gain; int ae_mode; -} mt9v111_data; - -extern void gpio_sensor_active(void); -extern void gpio_sensor_inactive(void); +}; static int mt9v111_probe(struct i2c_client *client, const struct i2c_device_id *id); static int mt9v111_remove(struct i2c_client *client); static const struct i2c_device_id mt9v111_id[] = { - {"mt9v111", 0}, + {"mt9v111_1", 2}, + {"mt9v111_2", 3}, {}, }; +struct sensor mt9v111_data[ARRAY_SIZE(mt9v111_id)-1]; + MODULE_DEVICE_TABLE(i2c, mt9v111_id); +static int mt9v111_suspend(struct i2c_client *client, pm_message_t mesg) +{ + pr_debug("In mt9v111_suspend\n"); + + return 0; +} + +static int mt9v111_resume(struct i2c_client *client) +{ + pr_debug("In mt9v111_resume\n"); + + return 0; +} + static struct i2c_driver mt9v111_i2c_driver = { .driver = { .owner = THIS_MODULE, @@ -84,37 +98,52 @@ static struct i2c_driver mt9v111_i2c_driver = { .probe = mt9v111_probe, .remove = mt9v111_remove, .id_table = mt9v111_id, -/* To add power management add .suspend and .resume functions */ + .suspend = mt9v111_suspend, + .resume = mt9v111_resume, }; /* * Function definitions */ -#ifdef MT9V111_DEBUG -static inline int mt9v111_read_reg(u8 reg) +static int mt9v111_id_from_name ( const char * name ) +{ + int id = -1; + + if( name == NULL || ( strlen(name) < strlen("mt9v111_n") ) ) + return -1; + + id = (int)simple_strtol(name+strlen("mt9v111_"),NULL,0) - 1; + if( id >= ARRAY_SIZE(mt9v111_id) ) { + printk("Invalid sensor index %d for %s\n",id,name); + return -1; + } + + return id; +} + +static inline int mt9v111_read_reg(int sensorid , u8 reg) { - int val = i2c_smbus_read_word_data(mt9v111_data.i2c_client, reg); + int val = i2c_smbus_read_word_data(mt9v111_data[sensorid].i2c_client, reg); if (val != -1) val = cpu_to_be16(val); return val; } -#endif /*! * Writes to the register via I2C. */ -static inline int mt9v111_write_reg(u8 reg, u16 val) +static inline int mt9v111_write_reg(int sensorid , u8 reg, u16 val) { - pr_debug("In mt9v111_write_reg (0x%x, 0x%x)\n", reg, val); + pr_debug("[%d] In mt9v111_write_reg (0x%x, 0x%x)\n", sensorid , reg, val); pr_debug(" write reg %x val %x.\n", reg, val); - return i2c_smbus_write_word_data(mt9v111_data.i2c_client, + return i2c_smbus_write_word_data(mt9v111_data[sensorid].i2c_client, reg, cpu_to_be16(val)); } /*! - * Initialize mt9v111_sensor_lib + * Initialize mt9v111_sensor_lib_datasheet * Libarary for Sensor configuration through I2C * * @param coreReg Core Registers @@ -122,7 +151,7 @@ static inline int mt9v111_write_reg(u8 reg, u16 val) * * @return status */ -static u8 mt9v111_sensor_lib(mt9v111_coreReg * coreReg, mt9v111_IFPReg * ifpReg) +static u8 mt9v111_sensor_lib_datasheet(int sensorid , mt9v111_coreReg * coreReg, mt9v111_IFPReg * ifpReg) { u8 reg; u16 data; @@ -130,200 +159,103 @@ static u8 mt9v111_sensor_lib(mt9v111_coreReg * coreReg, mt9v111_IFPReg * ifpReg) pr_debug("In mt9v111_sensor_lib\n"); + /* IFP R51(0x33)=5137,R57(0x39)=290,R59(0x3B)=1068,R62(0x3E)=4095,R89(0x59)=504,R90(0x5A)=605,R92(0x5C)=8222,R93(0x5D)=10021,R100(0x64)=4477 */ + /* * setup to IFP registers */ reg = MT9V111I_ADDR_SPACE_SEL; data = ifpReg->addrSpaceSel; - mt9v111_write_reg(reg, data); - - /* Operation Mode Control */ - reg = MT9V111I_MODE_CONTROL; - data = ifpReg->modeControl; - mt9v111_write_reg(reg, data); - - /* Output format */ - reg = MT9V111I_FORMAT_CONTROL; - data = ifpReg->formatControl; /* Set bit 12 */ - mt9v111_write_reg(reg, data); - - /* AE limit 4 */ - reg = MT9V111I_SHUTTER_WIDTH_LIMIT_AE; - data = ifpReg->gainLimitAE; - mt9v111_write_reg(reg, data); - - reg = MT9V111I_OUTPUT_FORMAT_CTRL2; - data = ifpReg->outputFormatCtrl2; - mt9v111_write_reg(reg, data); - - reg = MT9V111I_AE_SPEED; - data = ifpReg->AESpeed; - mt9v111_write_reg(reg, data); - - /* output image size */ - reg = MT9V111i_H_PAN; - data = 0x8000 | ifpReg->HPan; - mt9v111_write_reg(reg, data); - - reg = MT9V111i_H_ZOOM; - data = 0x8000 | ifpReg->HZoom; - mt9v111_write_reg(reg, data); - - reg = MT9V111i_H_SIZE; - data = 0x8000 | ifpReg->HSize; - mt9v111_write_reg(reg, data); - - reg = MT9V111i_V_PAN; - data = 0x8000 | ifpReg->VPan; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); - reg = MT9V111i_V_ZOOM; - data = 0x8000 | ifpReg->VZoom; - mt9v111_write_reg(reg, data); + reg = MT9V111I_LIMIT_SHARP_SATU_CTRL; + data = ifpReg->limitSharpSatuCtrl; + mt9v111_write_reg(sensorid,reg, data); - reg = MT9V111i_V_SIZE; - data = 0x8000 | ifpReg->VSize; - mt9v111_write_reg(reg, data); - - reg = MT9V111i_H_PAN; - data = ~0x8000 & ifpReg->HPan; - mt9v111_write_reg(reg, data); -#if 0 reg = MT9V111I_UPPER_SHUTTER_DELAY_LIM; data = ifpReg->upperShutterDelayLi; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111I_IPF_BLACK_LEVEL_SUB; + data = ifpReg->ipfBlackLevelSub; + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111I_GAIN_THRE_CCAM_ADJ; + data = ifpReg->agimnThreCamAdj; + mt9v111_write_reg(sensorid,reg, data); reg = MT9V111I_SHUTTER_60; data = ifpReg->shutter_width_60; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111I_AUTO_EXPOSURE_17; + data = ifpReg->auto_exposure_17; + mt9v111_write_reg(sensorid,reg, data); reg = MT9V111I_SEARCH_FLICK_60; data = ifpReg->search_flicker_60; - mt9v111_write_reg(reg, data); -#endif + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111I_RESERVED93; + data = ifpReg->reserved93; + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111I_RESERVED100; + data = ifpReg->reserved100; + mt9v111_write_reg(sensorid,reg, data); /* * setup to sensor core registers */ reg = MT9V111I_ADDR_SPACE_SEL; data = coreReg->addressSelect; - mt9v111_write_reg(reg, data); - - /* enable changes and put the Sync bit on */ - reg = MT9V111S_OUTPUT_CTRL; - data = MT9V111S_OUTCTRL_SYNC | MT9V111S_OUTCTRL_CHIP_ENABLE | 0x3000; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); - /* min PIXCLK - Default */ - reg = MT9V111S_PIXEL_CLOCK_SPEED; - data = coreReg->pixelClockSpeed; - mt9v111_write_reg(reg, data); + /* Core R5=46, R7[4]=0 (DEFAULT) ,R33=58369*/ - /* Setup image flipping / Dark rows / row/column skip */ - reg = MT9V111S_READ_MODE; - data = coreReg->readMode; - mt9v111_write_reg(reg, data); - - /* zoom 0 */ - reg = MT9V111S_DIGITAL_ZOOM; - data = coreReg->digitalZoom; - mt9v111_write_reg(reg, data); - - /* min H-blank */ reg = MT9V111S_HOR_BLANKING; data = coreReg->horizontalBlanking; - mt9v111_write_reg(reg, data); - - /* min V-blank */ - reg = MT9V111S_VER_BLANKING; - data = coreReg->verticalBlanking; - mt9v111_write_reg(reg, data); - - reg = MT9V111S_SHUTTER_WIDTH; - data = coreReg->shutterWidth; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); - reg = MT9V111S_SHUTTER_DELAY; - data = ifpReg->upperShutterDelayLi; - mt9v111_write_reg(reg, data); - - /* changes become effective */ - reg = MT9V111S_OUTPUT_CTRL; - data = MT9V111S_OUTCTRL_CHIP_ENABLE | 0x3000; - mt9v111_write_reg(reg, data); + reg = MT9V111S_RESERVED33; + data = coreReg->reserved33; + mt9v111_write_reg(sensorid,reg, data); return error; } -/*! - * MT9V111 frame rate calculate - * - * @param frame_rate int * - * @param mclk int - * @return None - */ -static void mt9v111_rate_cal(int *frame_rate, int mclk) +void mt9v111_config_datasheet(void) { - int num_clock_per_row; - int max_rate = 0; + pr_debug("In mt9v111_config_datasheet\n"); - pr_debug("In mt9v111_rate_cal\n"); + mt9v111_device.coreReg->addressSelect = MT9V111I_SEL_SCA; - num_clock_per_row = (MT9V111_MAX_WIDTH + 114 + MT9V111_HORZBLANK_MIN) - * 2; - max_rate = mclk / (num_clock_per_row * - (MT9V111_MAX_HEIGHT + MT9V111_VERTBLANK_DEFAULT)); + /* MT9V111I_ADDR_SPACE_SEL */ + mt9v111_device.ifpReg->addrSpaceSel = MT9V111I_SEL_IFP; - if ((*frame_rate > max_rate) || (*frame_rate == 0)) { - *frame_rate = max_rate; - } + /* Recommended values for 30fps @ 27MHz from datasheet*/ - mt9v111_device.coreReg->verticalBlanking - = mclk / (*frame_rate * num_clock_per_row) - MT9V111_MAX_HEIGHT; + /* Core R5=132, R6=10 , R7[4]=0 (DEFAULT) ,R33=58369*/ - reset_frame_rate = *frame_rate; -} + mt9v111_device.coreReg->horizontalBlanking = 132; + mt9v111_device.coreReg->verticalBlanking = 10; + mt9v111_device.coreReg->reserved33 = 58369; -/*! - * MT9V111 sensor configuration - */ -void mt9v111_config(void) -{ - pr_debug("In mt9v111_config\n"); + /* IFP R51(0x33)=5137,R57(0x39)=290,R59(0x3B)=1068,R62(0x3E)=4095,R89(0x59)=504,R90(0x5A)=605,R92(0x5C)=8222,R93(0x5D)=10021,R100(0x64)=4477 */ - mt9v111_device.coreReg->addressSelect = MT9V111I_SEL_SCA; - mt9v111_device.ifpReg->addrSpaceSel = MT9V111I_SEL_IFP; + mt9v111_device.ifpReg->limitSharpSatuCtrl = 5137; + mt9v111_device.ifpReg->upperShutterDelayLi = 290; + mt9v111_device.ifpReg->ipfBlackLevelSub = 1068; + mt9v111_device.ifpReg->agimnThreCamAdj = 4095; - mt9v111_device.coreReg->windowHeight = MT9V111_WINHEIGHT; - mt9v111_device.coreReg->windowWidth = MT9V111_WINWIDTH; - mt9v111_device.coreReg->zoomColStart = 0; - mt9v111_device.coreReg->zomRowStart = 0; - mt9v111_device.coreReg->digitalZoom = 0x0; - - mt9v111_device.coreReg->verticalBlanking = MT9V111_VERTBLANK_DEFAULT; - mt9v111_device.coreReg->horizontalBlanking = MT9V111_HORZBLANK_MIN; - mt9v111_device.coreReg->pixelClockSpeed = 0; - mt9v111_device.coreReg->readMode = 0xd0a1; - - mt9v111_device.ifpReg->outputFormatCtrl2 = 0; - mt9v111_device.ifpReg->gainLimitAE = 0x300; - mt9v111_device.ifpReg->AESpeed = 0x80; - - /* here is the default value */ - mt9v111_device.ifpReg->formatControl = 0xc800; - mt9v111_device.ifpReg->modeControl = 0x708e; - mt9v111_device.ifpReg->awbSpeed = 0x4514; - mt9v111_device.coreReg->shutterWidth = 0xf8; - - /* output size */ - mt9v111_device.ifpReg->HPan = 0; - mt9v111_device.ifpReg->HZoom = MT9V111_MAX_WIDTH; - mt9v111_device.ifpReg->HSize = MT9V111_MAX_WIDTH; - mt9v111_device.ifpReg->VPan = 0; - mt9v111_device.ifpReg->VZoom = MT9V111_MAX_HEIGHT; - mt9v111_device.ifpReg->VSize = MT9V111_MAX_HEIGHT; + mt9v111_device.ifpReg->shutter_width_60 = 504; + mt9v111_device.ifpReg->auto_exposure_17 = 605; + mt9v111_device.ifpReg->search_flicker_60 = 8222; + mt9v111_device.ifpReg->reserved93 = 10021; + mt9v111_device.ifpReg->reserved100 = 4477; } + /*! * mt9v111 sensor set saturtionn * @@ -331,7 +263,7 @@ void mt9v111_config(void) * @return Error code of 0. */ -static int mt9v111_set_saturation(int saturation) +static int mt9v111_set_saturation(int sensorid , int saturation) { u8 reg; u16 data; @@ -357,6 +289,9 @@ static int mt9v111_set_saturation(int saturation) case 25: mt9v111_device.ifpReg->awbSpeed = 0x6514; break; + case 0: + mt9v111_device.ifpReg->awbSpeed = 0x7514; + break; default: mt9v111_device.ifpReg->awbSpeed = 0x4514; break; @@ -364,12 +299,348 @@ static int mt9v111_set_saturation(int saturation) reg = MT9V111I_ADDR_SPACE_SEL; data = mt9v111_device.ifpReg->addrSpaceSel; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); /* Operation Mode Control */ reg = MT9V111I_AWB_SPEED; data = mt9v111_device.ifpReg->awbSpeed; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); + + return 0; +} + +#if 0 +/*! + * mt9v111 sensor set digital zoom + * + * @param on/off int + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_digitalzoom(int sensorid , unsigned int on) +{ + u8 reg; + u16 data; + pr_debug("In mt9v111_set_digitalzoom(%d)\n",on); + + if( on > 1 ) + return -1; + + mt9v111_device.coreReg->digitalZoom = on; + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.coreReg->addressSelect; + mt9v111_write_reg(sensorid,reg, data); + + /* Operation Mode Control */ + reg = MT9V111S_DIGITAL_ZOOM; + data = mt9v111_device.coreReg->digitalZoom; + mt9v111_write_reg(sensorid,reg, data); + + return 0; +} + +/*! + * mt9v111 sensor set digital pan + * + * @param pan_level int + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_digitalpan (int sensorid , int pan_level) +{ + u8 reg; + u16 data; + pr_debug("In mt9v111_set_digitalpan(%d)\n", + pan_level); + + mt9v111_device.ifpReg->HPan = 8; + if (pan_level & 0xFFFF0000) { + pan_level = (0xFFFFFFFF - pan_level); + pan_level = pan_level / 0x14; + mt9v111_device.ifpReg->HPan = + mt9v111_device.ifpReg->HPan - (pan_level & 0x3FF); + } else { + pan_level = pan_level / 0x14; + mt9v111_device.ifpReg->HPan = + mt9v111_device.ifpReg->HPan + (pan_level - 1); + } + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.ifpReg->addrSpaceSel; + mt9v111_write_reg(sensorid,reg, data); + + /* Operation Mode Control */ + reg = MT9V111i_H_PAN; + data = mt9v111_device.ifpReg->HPan; + mt9v111_write_reg(sensorid,reg, data); + + return 0; +} + +/*! + * mt9v111 sensor set digital tilt + * + * @param tilt_level int + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_digitaltilt (int sensorid , int tilt_level) +{ + u8 reg; + u16 data; + pr_debug("In mt9v111_set_digitaltilt(%d)\n", + tilt_level); + + mt9v111_device.ifpReg->VPan = 8; + if( tilt_level & 0xFFFF0000 ) { + tilt_level = (0xFFFFFFFF - tilt_level); + tilt_level = tilt_level / 0x14; + mt9v111_device.ifpReg->VPan = mt9v111_device.ifpReg->VPan - (tilt_level & 0x3FF); + } + else { + tilt_level = tilt_level / 0x14; + mt9v111_device.ifpReg->VPan = mt9v111_device.ifpReg->VPan + (tilt_level - 1); + } + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.ifpReg->addrSpaceSel; + mt9v111_write_reg(sensorid,reg, data); + + /* Operation Mode Control */ + reg = MT9V111i_V_PAN; + data = mt9v111_device.ifpReg->VPan; + mt9v111_write_reg(sensorid,reg, data); + + return 0; +} + +/*! + * mt9v111 sensor set output resolution + * + * @param resolution res + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_outputresolution(int sensorid , MT9V111_OutputResolution res) +{ + u8 reg; + u16 data; + int zoom = 0; + + pr_debug("In mt9v111_set_outputresolution(%d)\n",res); + + switch (res) { + case MT9V111_OutputResolution_VGA: + /* 640x480 */ + mt9v111_device.ifpReg->HSize = 0x0280; + mt9v111_device.ifpReg->VSize = 0x01E0; + break; + + case MT9V111_OutputResolution_QVGA: + /* 320x240 */ + mt9v111_device.ifpReg->HSize = 0x0140; + mt9v111_device.ifpReg->VSize = 0x00F0; + break; + + case MT9V111_OutputResolution_CIF: + /* 352x288 */ + mt9v111_device.ifpReg->HSize = 0x0160; + mt9v111_device.ifpReg->VSize = 0x0120; + mt9v111_device.ifpReg->HZoom = 0x0160; + mt9v111_device.ifpReg->VZoom = 0x0120; + zoom = 1; + break; + + case MT9V111_OutputResolution_QCIF: + /* 176X220 */ + mt9v111_device.ifpReg->HSize = 0x00B0; + mt9v111_device.ifpReg->VSize = 0x0090; + mt9v111_device.ifpReg->HZoom = 0x00B0; + mt9v111_device.ifpReg->VZoom = 0x0090; + zoom = 1; + break; + + case MT9V111_OutputResolution_QQVGA: + /* 2048*1536 */ + mt9v111_device.ifpReg->HSize = 0x00A0; + mt9v111_device.ifpReg->VSize = 0x0078; + mt9v111_device.ifpReg->HZoom = 0x00A0; + mt9v111_device.ifpReg->VZoom = 0x0078; + zoom = 1; + break; + + case MT9V111_OutputResolution_SXGA: + /* 1280x1024 */ + break; + + default: + break; + } + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.ifpReg->addrSpaceSel; + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111i_V_SIZE; + data = mt9v111_device.ifpReg->VSize; + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111i_H_SIZE; + data = mt9v111_device.ifpReg->HSize; + mt9v111_write_reg(sensorid,reg, data); + + if ( zoom ) { + reg = MT9V111i_V_ZOOM; + data = mt9v111_device.ifpReg->VZoom; + mt9v111_write_reg(sensorid,reg, data); + + reg = MT9V111i_H_ZOOM; + data = mt9v111_device.ifpReg->HZoom; + mt9v111_write_reg(sensorid,reg, data); + } + + return 0; +} + +/*! + * mt9v111 sensor set digital flash + * + * @param flash_level int + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_digitalflash (int sensorid , int flash_level) +{ + u8 reg; + u16 data = mt9v111_read_reg(sensorid,MT9V111i_FLASH_CTRL); + pr_debug("In mt9v111_set_digitalflash(%d)\n", + flash_level); + + if(flash_level) { + data &= (0xFF00); + data |= ((flash_level & 0x00FF) | (1<<13)); + } + else { + data &= ~(1<<13); + } + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.ifpReg->addrSpaceSel; + mt9v111_write_reg(sensorid,reg, data); + + /* Operation Mode Control */ + reg = MT9V111i_FLASH_CTRL; + mt9v111_device.ifpReg->flashCtrl = data; + mt9v111_write_reg(sensorid,reg, data); + + return 0; +} + +/*! + * mt9v111 sensor set digital monochrome + * + * @param on int + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_digitalmonochrome (int sensorid , int on) +{ + u8 reg; + u16 data = mt9v111_read_reg(sensorid,MT9V111I_FORMAT_CONTROL); + pr_debug("In mt9v111_set_digitalmonochrome(%d)\n", + on); + + /* clear the monochrome bit field */ + data &= ~(1<<5); + + /* enable or disable monochrome mode */ + if( on ) + data |= (0<<5); + else + data |= (1<<5); + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.ifpReg->addrSpaceSel; + mt9v111_write_reg(sensorid,reg, data); + + /* Operation Mode Control */ + reg = MT9V111I_FORMAT_CONTROL; + mt9v111_device.ifpReg->formatControl = data; + mt9v111_write_reg(sensorid,reg, data); + + return 0; +} +#endif + +/*! + * mt9v111 sensor set digital sharpness + * + * @param value int + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_digitalsharpness (int sensorid , int value) +{ + u8 reg; + u16 data ; + + pr_debug("In mt9v111_set_digitalsharpness(%d)\n",value); + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.ifpReg->addrSpaceSel; + mt9v111_write_reg(sensorid,reg, data); + + data = mt9v111_read_reg(sensorid,MT9V111I_APERTURE_GAIN); + + /* erase current and remove auto reduce sharpness in low light */ + data &= ~(0x000F); + data |= (value & (0x000F)); + if( data > (0x000F) ) + return -1; + + /* Operation Mode Control */ + reg = MT9V111I_APERTURE_GAIN; + mt9v111_device.ifpReg->apertureGain = data; + mt9v111_write_reg(sensorid,reg, data); + + return 0; +} + +/*! + * mt9v111 sensor set digital brightness + * + * @param value int + + * @return 0 on success, -1 on error. + */ +static int mt9v111_set_digitalbrightness (int sensorid , int value) +{ + u8 reg; + u16 data; + u32 max_brightness, min_brightness; + + data = mt9v111_read_reg(sensorid,MT9V111I_CLIP_LIMIT_OUTPUT_LUMI); + max_brightness = data >> 8; + min_brightness = (u8)data; + + if( value > max_brightness ) + value = max_brightness; + else if( value < min_brightness ) + value = min_brightness; + + reg = MT9V111I_ADDR_SPACE_SEL; + data = mt9v111_device.ifpReg->addrSpaceSel; + mt9v111_write_reg(sensorid,reg, data); + + data = mt9v111_read_reg(sensorid,MT9V111I_AE_PRECISION_TARGET); + data &= 0xFF00; /* Clear target luminance */ + data |= ((u8)value ); + + /* Operation Mode Control */ + reg = MT9V111I_AE_PRECISION_TARGET; + mt9v111_device.ifpReg->AEPrecisionTarget = data; + mt9v111_write_reg(sensorid,reg, data); return 0; } @@ -380,7 +651,7 @@ static int mt9v111_set_saturation(int saturation) * @param ae_mode int * @return Error code of 0 (no Error) */ -static int mt9v111_set_ae_mode(int ae_mode) +static int mt9v111_set_ae_mode(int sensorid , int ae_mode) { u8 reg; u16 data; @@ -408,19 +679,20 @@ static int mt9v111_set_ae_mode(int ae_mode) /* V4L2_EXPOSURE_MANUAL = 1 needs register setting of 0x308E */ mt9v111_device.ifpReg->modeControl &= 0x3fff; mt9v111_device.ifpReg->modeControl |= (ae_mode & 0x03) << 14; - mt9v111_data.ae_mode = ae_mode; + mt9v111_data[sensorid].ae_mode = ae_mode; reg = MT9V111I_ADDR_SPACE_SEL; data = mt9v111_device.ifpReg->addrSpaceSel; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); reg = MT9V111I_MODE_CONTROL; data = mt9v111_device.ifpReg->modeControl; - mt9v111_write_reg(reg, data); + mt9v111_write_reg(sensorid,reg, data); return 0; } +#if 0 /*! * mt9v111 sensor get AE measurement window mode configuration * @@ -435,6 +707,7 @@ static void mt9v111_get_ae_mode(int *ae_mode) *ae_mode = (mt9v111_device.ifpReg->modeControl & 0xc) >> 2; } } +#endif #ifdef MT9V111_DEBUG /*! @@ -442,33 +715,33 @@ static void mt9v111_get_ae_mode(int *ae_mode) * * @return none */ -static void mt9v111_test_pattern(bool flag) +static void mt9v111_test_pattern(int sensorid , bool flag) { u16 data; /* switch to sensor registers */ - mt9v111_write_reg(MT9V111I_ADDR_SPACE_SEL, MT9V111I_SEL_SCA); + mt9v111_write_reg(sensorid,MT9V111I_ADDR_SPACE_SEL, MT9V111I_SEL_SCA); if (flag == true) { testpattern = MT9V111S_OUTCTRL_TEST_MODE; - data = mt9v111_read_reg(MT9V111S_ROW_NOISE_CTRL) & 0xBF; - mt9v111_write_reg(MT9V111S_ROW_NOISE_CTRL, data); + data = mt9v111_read_reg(sensorid,MT9V111S_ROW_NOISE_CTRL) & 0xBF; + mt9v111_write_reg(sensorid,MT9V111S_ROW_NOISE_CTRL, data); - mt9v111_write_reg(MT9V111S_TEST_DATA, 0); + mt9v111_write_reg(sensorid,MT9V111S_TEST_DATA, 0); /* changes take effect */ data = MT9V111S_OUTCTRL_CHIP_ENABLE | testpattern | 0x3000; - mt9v111_write_reg(MT9V111S_OUTPUT_CTRL, data); + mt9v111_write_reg(sensorid,MT9V111S_OUTPUT_CTRL, data); } else { testpattern = 0; - data = mt9v111_read_reg(MT9V111S_ROW_NOISE_CTRL) | 0x40; + data = mt9v111_read_reg(sensorid,MT9V111S_ROW_NOISE_CTRL) | 0x40; mt9v111_write_reg(MT9V111S_ROW_NOISE_CTRL, data); /* changes take effect */ data = MT9V111S_OUTCTRL_CHIP_ENABLE | testpattern | 0x3000; - mt9v111_write_reg(MT9V111S_OUTPUT_CTRL, data); + mt9v111_write_reg(sensorid,MT9V111S_OUTPUT_CTRL, data); } } #endif @@ -507,6 +780,7 @@ static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) p->u.bt656.clock_curr = MT9V111_MCLK; p->if_type = V4L2_IF_TYPE_BT656; p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT; + p->u.bt656.bt_sync_correct = 1; // translates to CSI ext vsync p->u.bt656.clock_min = MT9V111_CLK_MIN; p->u.bt656.clock_max = MT9V111_CLK_MAX; @@ -534,10 +808,12 @@ static int ioctl_s_power(struct v4l2_int_device *s, int on) sensor->on = on; - if (on) - gpio_sensor_active(); - else - gpio_sensor_inactive(); + if(on) { + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */, true, true); + } + else { + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */, false, false); + } return 0; } @@ -554,19 +830,23 @@ static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) int ret = 0; struct v4l2_captureparm *cparm = &a->parm.capture; /* s->priv points to mt9v111_data */ + int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); pr_debug("In mt9v111:ioctl_g_parm\n"); + if( sensorid < 0 ) + return ret; + switch (a->type) { /* This is the only case currently handled. */ case V4L2_BUF_TYPE_VIDEO_CAPTURE: pr_debug(" type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); memset(a, 0, sizeof(*a)); a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cparm->capability = mt9v111_data.streamcap.capability; + cparm->capability = mt9v111_data[sensorid].streamcap.capability; cparm->timeperframe = - mt9v111_data.streamcap.timeperframe; - cparm->capturemode = mt9v111_data.streamcap.capturemode; + mt9v111_data[sensorid].streamcap.timeperframe; + cparm->capturemode = mt9v111_data[sensorid].streamcap.capturemode; ret = 0; break; @@ -605,9 +885,13 @@ static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) int ret = 0; struct v4l2_captureparm *cparm = &a->parm.capture; /* s->priv points to mt9v111_data */ + int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); pr_debug("In mt9v111:ioctl_s_parm\n"); + if( sensorid < 0 ) + return ret; + switch (a->type) { /* This is the only case currently handled. */ case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -617,13 +901,13 @@ static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) * Changing the frame rate is not allowed on this *camera. */ if (cparm->timeperframe.denominator != - mt9v111_data.streamcap.timeperframe.denominator) { + mt9v111_data[sensorid].streamcap.timeperframe.denominator) { pr_err("ERROR: mt9v111: ioctl_s_parm: " \ "This camera does not allow frame rate " "changes.\n"); ret = -EINVAL; } else { - mt9v111_data.streamcap.timeperframe = + mt9v111_data[sensorid].streamcap.timeperframe = cparm->timeperframe; /* Call any camera functions to match settings. */ } @@ -635,7 +919,7 @@ static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) "unsupported capture mode\n"); ret = -EINVAL; } else { - mt9v111_data.streamcap.capturemode = + mt9v111_data[sensorid].streamcap.capturemode = cparm->capturemode; /* Call any camera functions to match settings. */ /* Right now this camera only supports 1 mode. */ @@ -685,6 +969,7 @@ static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) return 0; } +#if 0 /*! * ioctl_queryctrl - V4L2 sensor interface handler for VIDIOC_QUERYCTRL ioctl * @s: pointer to standard V4L2 device structure @@ -700,6 +985,7 @@ static int ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qc) return 0; } +#endif /*! * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl @@ -712,66 +998,29 @@ static int ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qc) */ static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) { + int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); + pr_debug("In mt9v111:ioctl_g_ctrl\n"); + if( sensorid < 0 ) + return 0; + switch (vc->id) { case V4L2_CID_BRIGHTNESS: pr_debug(" V4L2_CID_BRIGHTNESS\n"); - vc->value = mt9v111_data.brightness; - break; - case V4L2_CID_CONTRAST: - pr_debug(" V4L2_CID_CONTRAST\n"); - vc->value = mt9v111_data.contrast; + vc->value = mt9v111_data[sensorid].brightness; break; case V4L2_CID_SATURATION: pr_debug(" V4L2_CID_SATURATION\n"); - vc->value = mt9v111_data.saturation; - break; - case V4L2_CID_HUE: - pr_debug(" V4L2_CID_HUE\n"); - vc->value = mt9v111_data.hue; - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - pr_debug( - " V4L2_CID_AUTO_WHITE_BALANCE\n"); - vc->value = 0; - break; - case V4L2_CID_DO_WHITE_BALANCE: - pr_debug( - " V4L2_CID_DO_WHITE_BALANCE\n"); - vc->value = 0; - break; - case V4L2_CID_RED_BALANCE: - pr_debug(" V4L2_CID_RED_BALANCE\n"); - vc->value = mt9v111_data.red; - break; - case V4L2_CID_BLUE_BALANCE: - pr_debug(" V4L2_CID_BLUE_BALANCE\n"); - vc->value = mt9v111_data.blue; - break; - case V4L2_CID_GAMMA: - pr_debug(" V4L2_CID_GAMMA\n"); - vc->value = 0; + vc->value = mt9v111_data[sensorid].saturation; break; case V4L2_CID_EXPOSURE: pr_debug(" V4L2_CID_EXPOSURE\n"); - vc->value = mt9v111_data.ae_mode; - break; - case V4L2_CID_AUTOGAIN: - pr_debug(" V4L2_CID_AUTOGAIN\n"); - vc->value = 0; + vc->value = mt9v111_data[sensorid].ae_mode; break; case V4L2_CID_GAIN: pr_debug(" V4L2_CID_GAIN\n"); - vc->value = 0; - break; - case V4L2_CID_HFLIP: - pr_debug(" V4L2_CID_HFLIP\n"); - vc->value = 0; - break; - case V4L2_CID_VFLIP: - pr_debug(" V4L2_CID_VFLIP\n"); - vc->value = 0; + vc->value = mt9v111_data[sensorid].gain; break; default: pr_debug(" Default case\n"); @@ -794,56 +1043,34 @@ static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) { int retval = 0; + int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); pr_debug("In mt9v111:ioctl_s_ctrl %d\n", vc->id); + if( sensorid < 0 ) + return retval; + switch (vc->id) { case V4L2_CID_BRIGHTNESS: pr_debug(" V4L2_CID_BRIGHTNESS\n"); - break; - case V4L2_CID_CONTRAST: - pr_debug(" V4L2_CID_CONTRAST\n"); + mt9v111_set_digitalbrightness(sensorid,vc->value); + mt9v111_data[sensorid].brightness = vc->value; break; case V4L2_CID_SATURATION: pr_debug(" V4L2_CID_SATURATION\n"); - retval = mt9v111_set_saturation(vc->value); - break; - case V4L2_CID_HUE: - pr_debug(" V4L2_CID_HUE\n"); - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - pr_debug( - " V4L2_CID_AUTO_WHITE_BALANCE\n"); - break; - case V4L2_CID_DO_WHITE_BALANCE: - pr_debug( - " V4L2_CID_DO_WHITE_BALANCE\n"); - break; - case V4L2_CID_RED_BALANCE: - pr_debug(" V4L2_CID_RED_BALANCE\n"); - break; - case V4L2_CID_BLUE_BALANCE: - pr_debug(" V4L2_CID_BLUE_BALANCE\n"); - break; - case V4L2_CID_GAMMA: - pr_debug(" V4L2_CID_GAMMA\n"); + retval = mt9v111_set_saturation(sensorid,vc->value); + mt9v111_data[sensorid].saturation = vc->value; break; case V4L2_CID_EXPOSURE: pr_debug(" V4L2_CID_EXPOSURE\n"); - retval = mt9v111_set_ae_mode(vc->value); - break; - case V4L2_CID_AUTOGAIN: - pr_debug(" V4L2_CID_AUTOGAIN\n"); + retval = mt9v111_set_ae_mode(sensorid,vc->value); + mt9v111_data[sensorid].ae_mode = vc->value; break; case V4L2_CID_GAIN: pr_debug(" V4L2_CID_GAIN\n"); - break; - case V4L2_CID_HFLIP: - pr_debug(" V4L2_CID_HFLIP\n"); - break; - case V4L2_CID_VFLIP: - pr_debug(" V4L2_CID_VFLIP\n"); + mt9v111_set_digitalsharpness(sensorid,vc->value); + mt9v111_data[sensorid].gain = vc->value; break; default: pr_debug(" Default case\n"); @@ -854,13 +1081,41 @@ static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) return retval; } +static void mt9v111_ifp_reset ( int sensorid ) +{ + mt9v111_write_reg(sensorid,MT9V111S_ADDR_SPACE_SEL, 0x0001); + mt9v111_write_reg(sensorid,MT9V111I_SOFT_RESET, 0x0001); + msleep(100); + mt9v111_write_reg(sensorid,MT9V111I_SOFT_RESET, 0x0000); + msleep(100); +} + +static void mt9v111_sensor_reset ( int sensorid ) +{ + mt9v111_write_reg(sensorid,MT9V111S_ADDR_SPACE_SEL, 0x0004); + mt9v111_write_reg(sensorid,MT9V111S_RESET, 0x0001); + msleep(100); + mt9v111_write_reg(sensorid,MT9V111S_RESET, 0x0000); + msleep(100); +} + /*! * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT * @s: pointer to standard V4L2 device structure */ static int ioctl_init(struct v4l2_int_device *s) { - pr_debug("In mt9v111:ioctl_init\n"); + int sensorid = 0; + + sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); + if( sensorid < 0 ) + return 0; + + pr_debug("In mt9v111:ioctl_init for sensor %d\n",sensorid); + + mt9v111_sensor_reset(sensorid); + mt9v111_ifp_reset(sensorid); + mt9v111_sensor_lib_datasheet(sensorid,mt9v111_device.coreReg, mt9v111_device.ifpReg); return 0; } @@ -873,19 +1128,146 @@ static int ioctl_init(struct v4l2_int_device *s) */ static int ioctl_dev_init(struct v4l2_int_device *s) { + int sensorid = 0; uint32_t clock_rate = MT9V111_MCLK; + sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); + if( sensorid < 0 ) + return 0; + pr_debug("In mt9v111:ioctl_dev_init\n"); - gpio_sensor_active(); + set_mclk_rate(&clock_rate, 0); // Both sensors use mclk0 on Digi ccwmx51 + + mt9v111_sensor_reset(sensorid); + mt9v111_ifp_reset(sensorid); + mt9v111_sensor_lib_datasheet(sensorid,mt9v111_device.coreReg, mt9v111_device.ifpReg); - set_mclk_rate(&clock_rate); - mt9v111_rate_cal(&reset_frame_rate, clock_rate); - mt9v111_sensor_lib(mt9v111_device.coreReg, mt9v111_device.ifpReg); + return 0; +} + +/* list of image formats supported by sensor */ +static const struct v4l2_fmtdesc mt9v111_formats[] = { + { + .description = "RGB565", + .pixelformat = V4L2_PIX_FMT_RGB565, + }, + { + .description = "YUV422 UYVY", + .pixelformat = V4L2_PIX_FMT_UYVY, + }, +}; + +#define MT9V111_NUM_CAPTURE_FORMATS ARRAY_SIZE(mt9v111_formats) + +static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, + struct v4l2_fmtdesc *fmt) +{ + int index = fmt->index; + + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (index >= MT9V111_NUM_CAPTURE_FORMATS) + return -EINVAL; + break; + + default: + return -EINVAL; + } + + fmt->flags = mt9v111_formats[index].flags; + strlcpy(fmt->description, mt9v111_formats[index].description, + sizeof(fmt->description)); + fmt->pixelformat = mt9v111_formats[index].pixelformat; return 0; } +static int ioctl_s_fmt_cap(struct v4l2_int_device *s, + struct v4l2_format *f) +{ + unsigned short reg; + int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); + struct sensor *sensor = s->priv; + /* s->priv points to mt9v111_data */ + + if( sensorid < 0 ) + return -ENODEV; + + /* Select IFP registers */ + mt9v111_write_reg (sensorid,MT9V111S_ADDR_SPACE_SEL, 0x0001); + + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB565: + /*MT9V111I_OUTPUT_FORMAT_CTRL2*/ + reg = mt9v111_read_reg (sensorid,MT9V111I_OUTPUT_FORMAT_CTRL2); + reg &= ~(0x3 << 6); + mt9v111_write_reg (sensorid,MT9V111I_OUTPUT_FORMAT_CTRL2, reg); + + /* MT9V111I_FORMAT_CONTROL */ + reg = mt9v111_read_reg(sensorid,MT9V111I_FORMAT_CONTROL); + reg |= 1 << 12; + mt9v111_write_reg(sensorid,MT9V111I_FORMAT_CONTROL, reg); + break; + + case V4L2_PIX_FMT_YUV444: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUYV: + /* MT9V111I_FORMAT_CONTROL */ + reg = mt9v111_read_reg(sensorid,MT9V111I_FORMAT_CONTROL); + reg &= ~(1 << 12); + mt9v111_write_reg(sensorid,MT9V111I_FORMAT_CONTROL, reg); + break; + + default: + return -EINVAL; + } + + sensor->pix.width = f->fmt.pix.width; + sensor->pix.height = f->fmt.pix.height; + sensor->pix.sizeimage = f->fmt.pix.sizeimage; + sensor->pix.pixelformat = f->fmt.pix.pixelformat; + return 0; +} + +static int ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) +{ + int i; + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + for( i=0 ; i < MT9V111_NUM_CAPTURE_FORMATS ; i++) { + if( f->fmt.pix.pixelformat == mt9v111_formats[i].pixelformat ) + return 0; + } + + return -EINVAL; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ioctl_get_register(struct v4l2_int_device *s,struct v4l2_dbg_register * dreg) +{ + int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); + + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */ , true, true); + dreg->val = mt9v111_read_reg (sensorid,dreg->reg); + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */ , false, false); + return 0; +} + +static int ioctl_set_register(struct v4l2_int_device *s,struct v4l2_dbg_register * dreg) +{ + int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name); + + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */ , true, true); + mt9v111_write_reg (sensorid,dreg->reg, dreg->val); + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */ , false, false); + return 0; +} +#endif + /*! * This structure defines all the ioctls for this module and links them to the * enumeration. @@ -910,16 +1292,23 @@ static struct v4l2_int_ioctl_desc mt9v111_ioctl_desc[] = { /*! * VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type. */ -/* {vidioc_int_enum_fmt_cap_num, - (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap}, */ + {vidioc_int_enum_fmt_cap_num, + (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap}, + +#ifdef CONFIG_VIDEO_ADV_DEBUG + {vidioc_int_g_register_num, + (v4l2_int_ioctl_func *) ioctl_get_register}, + {vidioc_int_s_register_num, + (v4l2_int_ioctl_func *) ioctl_set_register}, +#endif /*! * VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. * This ioctl is used to negotiate the image capture size and * pixel format without actually making it take effect. */ -/* {vidioc_int_try_fmt_cap_num, - (v4l2_int_ioctl_func *) ioctl_try_fmt_cap}, */ + {vidioc_int_try_fmt_cap_num, + (v4l2_int_ioctl_func *) ioctl_try_fmt_cap}, {vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func *) ioctl_g_fmt_cap}, @@ -928,7 +1317,7 @@ static struct v4l2_int_ioctl_desc mt9v111_ioctl_desc[] = { * format, returns error code if format not supported or HW can't be * correctly configured. */ -/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap}, */ + {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap}, {vidioc_int_g_parm_num, (v4l2_int_ioctl_func *) ioctl_g_parm}, {vidioc_int_s_parm_num, (v4l2_int_ioctl_func *) ioctl_s_parm}, @@ -937,20 +1326,56 @@ static struct v4l2_int_ioctl_desc mt9v111_ioctl_desc[] = { {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *) ioctl_s_ctrl}, }; -static struct v4l2_int_slave mt9v111_slave = { - .ioctls = mt9v111_ioctl_desc, - .num_ioctls = ARRAY_SIZE(mt9v111_ioctl_desc), +static struct v4l2_int_slave mt9v111_slave[] = { + { + .ioctls = mt9v111_ioctl_desc, + .num_ioctls = ARRAY_SIZE(mt9v111_ioctl_desc), + .attach_to = "mxc_v4l2_cap_1", + }, + { + .ioctls = mt9v111_ioctl_desc, + .num_ioctls = ARRAY_SIZE(mt9v111_ioctl_desc), + .attach_to = "mxc_v4l2_cap_2", + }, }; -static struct v4l2_int_device mt9v111_int_device = { - .module = THIS_MODULE, - .name = "mt9v111", - .type = v4l2_int_type_slave, - .u = { - .slave = &mt9v111_slave, +static struct v4l2_int_device mt9v111_int_device [] = { + { + .module = THIS_MODULE, + .type = v4l2_int_type_slave, + .u = { + .slave = &mt9v111_slave[0], + }, + }, + { + .module = THIS_MODULE, + .type = v4l2_int_type_slave, + .u = { + .slave = &mt9v111_slave[1], + }, }, }; +static int mt9v111_read_id( int sensoridx ) +{ + int sensorid = 0; + int ret = 0; + + mt9v111_write_reg (sensoridx,MT9V111S_ADDR_SPACE_SEL, 0x0004); + + sensorid = mt9v111_read_reg (sensoridx,MT9V111S_CHIP_VERSION); + if( sensorid == 0x823a ) + { + printk(KERN_INFO" MT9V111 ID %x\n",sensorid); + } + else + { + printk(KERN_ERR" MT9V111 Could not detect sensor (read %x)\n",sensorid); + ret = -ENODEV; + } + return ret; +} + /*! * mt9v111 I2C probe function * Function set in i2c_driver struct. @@ -962,32 +1387,56 @@ static int mt9v111_probe(struct i2c_client *client, const struct i2c_device_id *id) { int retval; + int sensorid; pr_debug("In mt9v111_probe device id is %s\n", id->name); + sensorid = mt9v111_id_from_name(id->name); + + if( sensorid < 0 ) + return -ENODEV; + /* Set initial values for the sensor struct. */ - memset(&mt9v111_data, 0, sizeof(mt9v111_data)); - mt9v111_data.i2c_client = client; + memset(&mt9v111_data[sensorid], 0, sizeof(struct sensor)); + mt9v111_data[sensorid].i2c_client = client; pr_debug(" client name is %s\n", client->name); - mt9v111_data.pix.pixelformat = V4L2_PIX_FMT_UYVY; - mt9v111_data.pix.width = MT9V111_MAX_WIDTH; - mt9v111_data.pix.height = MT9V111_MAX_HEIGHT; - mt9v111_data.streamcap.capability = 0; /* No higher resolution or frame - * frame rate changes supported. - */ - mt9v111_data.streamcap.timeperframe.denominator = MT9V111_FRAME_RATE; - mt9v111_data.streamcap.timeperframe.numerator = 1; + mt9v111_data[sensorid].pix.pixelformat = V4L2_PIX_FMT_UYVY; + mt9v111_data[sensorid].pix.width = MT9V111_MAX_WIDTH; + mt9v111_data[sensorid].pix.height = MT9V111_MAX_HEIGHT; + mt9v111_data[sensorid].streamcap.capability = 0; /* No higher resolution or frame + * frame rate changes supported.*/ + mt9v111_data[sensorid].streamcap.timeperframe.denominator = MT9V111_FRAME_RATE; + mt9v111_data[sensorid].streamcap.timeperframe.numerator = 1; + + strcpy(mt9v111_int_device[sensorid].name,id->name); + pr_debug(" video device name is %s\n", mt9v111_data[sensorid].v4l2_int_device->name); + mt9v111_data[sensorid].v4l2_int_device = &mt9v111_int_device[sensorid]; + mt9v111_int_device[sensorid].priv = &mt9v111_data[sensorid]; + + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, sensorid , true, true); + + if( mt9v111_read_id(sensorid) != 0) { + printk(KERN_ERR"mt9v111_probe: No sensor found\n"); + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, sensorid , false, false); + return -ENXIO; + } - mt9v111_int_device.priv = &mt9v111_data; +#ifdef MT9V111_DEBUG + mt9v111_test_pattern(1); +#endif + + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, sensorid , false, false); pr_debug(" type is %d (expect %d)\n", - mt9v111_int_device.type, v4l2_int_type_slave); + mt9v111_int_device[sensorid].type, v4l2_int_type_slave); pr_debug(" num ioctls is %d\n", - mt9v111_int_device.u.slave->num_ioctls); + mt9v111_int_device[sensorid].u.slave->num_ioctls); /* This function attaches this structure to the /dev/video0 device. * The pointer in priv points to the mt9v111_data structure here.*/ - retval = v4l2_int_device_register(&mt9v111_int_device); + retval = v4l2_int_device_register(&mt9v111_int_device[sensorid]); + if( retval == 0 ) + mt9v111_data[sensorid].used = 1; return retval; } @@ -998,9 +1447,14 @@ static int mt9v111_probe(struct i2c_client *client, */ static int mt9v111_remove(struct i2c_client *client) { + int i; + pr_debug("In mt9v111_remove\n"); - v4l2_int_device_unregister(&mt9v111_int_device); + for ( i=0 ; i < ARRAY_SIZE(mt9v111_int_device) ; i++ ) { + if( mt9v111_data[i].used ) + v4l2_int_device_unregister(&mt9v111_int_device[i]); + } return 0; } @@ -1033,13 +1487,13 @@ static __init int mt9v111_init(void) memset(mt9v111_device.ifpReg, 0, sizeof(mt9v111_IFPReg)); /* Set contents of the just created structures. */ - mt9v111_config(); + mt9v111_config_datasheet(); /* Tells the i2c driver what functions to call for this driver. */ err = i2c_add_driver(&mt9v111_i2c_driver); if (err != 0) pr_err("%s:driver registration failed, error=%d \n", - __func__, err); + __func__, err); return err; } @@ -1055,7 +1509,6 @@ static void __exit mt9v111_clean(void) pr_debug("In mt9v111_clean()\n"); i2c_del_driver(&mt9v111_i2c_driver); - gpio_sensor_inactive(); if (mt9v111_device.coreReg) { kfree(mt9v111_device.coreReg); diff --git a/drivers/media/video/mxc/capture/mt9v111.h b/drivers/media/video/mxc/capture/mt9v111.h index cf38cec4757c..ba91a722a076 100644 --- a/drivers/media/video/mxc/capture/mt9v111.h +++ b/drivers/media/video/mxc/capture/mt9v111.h @@ -111,11 +111,14 @@ #define MT9V111I_GAMMA_KNEE_Y90 0x57 #define MT9V111I_GAMMA_VALUE_Y0 0x58 #define MT9V111I_SHUTTER_60 0x59 +#define MT9V111I_AUTO_EXPOSURE_17 0x5A #define MT9V111I_SEARCH_FLICK_60 0x5c +#define MT9V111I_RESERVED93 0x5d #define MT9V111I_RATIO_IMAGE_GAIN_BASE 0x5e #define MT9V111I_RATIO_IMAGE_GAIN_DELTA 0x5f #define MT9V111I_SIGN_VALUE_REG5F 0x60 #define MT9V111I_AE_GAIN 0x62 +#define MT9V111I_RESERVED100 0x64 #define MT9V111I_MAX_GAIN_AE 0x67 #define MT9V111I_LENS_CORRECT_CTRL 0x80 #define MT9V111I_SHADING_PARAMETER1 0x81 @@ -173,6 +176,7 @@ #define MT9V111S_ROW_START_IN_ZOOM 0x13 #define MT9V111S_DIGITAL_ZOOM 0x1e #define MT9V111S_READ_MODE 0x20 +#define MT9V111S_RESERVED33 0x21 #define MT9V111S_DAC_CTRL 0x27 #define MT9V111S_GREEN1_GAIN 0x2b #define MT9V111S_BLUE_GAIN 0x2c @@ -278,6 +282,7 @@ typedef struct { u32 rowNoiseControl; u32 darkTargetwNC; u32 testData; /*!< test mode */ + u32 reserved33; u32 globalGain; u32 chipVersion; u32 darkTargetwoNC; @@ -375,11 +380,14 @@ typedef struct { u32 gammaKneeY90; /*!< Gamma knee points Y9 and Y10 */ u32 gammaKneeY0; /*!< Gamma knee point Y0 */ u32 shutter_width_60; + u32 auto_exposure_17; u32 search_flicker_60; + u32 reserved93; u32 ratioImageGainBase; u32 ratioImageGainDelta; u32 signValueReg5F; u32 aeGain; + u32 reserved100; u32 maxGainAE; u32 lensCorrectCtrl; u32 shadingParameter1; /*!< Shade Parameters */ diff --git a/drivers/media/video/mxc/capture/mx27_prpsw.c b/drivers/media/video/mxc/capture/mx27_prpsw.c index ce7db16913ec..eca200a580f2 100644 --- a/drivers/media/video/mxc/capture/mx27_prpsw.c +++ b/drivers/media/video/mxc/capture/mx27_prpsw.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -702,7 +702,7 @@ static int prp_still_start(void *private) cam_data *cam = (cam_data *) private; g_still_on = 1; - g_prp_cfg.ch2_ptr = (unsigned int)cam->still_buf; + g_prp_cfg.ch2_ptr = (unsigned int)cam->still_buf[0]; g_prp_cfg.ch2_ptr2 = 0; if (prp_v4l2_cfg(&g_prp_cfg, cam)) diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.c b/drivers/media/video/mxc/capture/mxc_v4l2_capture.c index 30ad533b0ebd..be9a988aff2f 100644 --- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.c +++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.c @@ -18,6 +18,8 @@ * * @ingroup MXC_V4L2_CAPTURE */ + + #include <linux/version.h> #include <linux/module.h> #include <linux/init.h> @@ -37,9 +39,9 @@ #include <media/v4l2-int-device.h> #include "mxc_v4l2_capture.h" #include "ipu_prp_sw.h" +#include "asm/delay.h" static int video_nr = -1; -static cam_data *g_cam; /*! This data is used for the output to the display. */ #define MXC_V4L2_CAPTURE_NUM_OUTPUTS 3 @@ -74,21 +76,23 @@ static struct v4l2_output mxc_capture_outputs[MXC_V4L2_CAPTURE_NUM_OUTPUTS] = { static struct v4l2_input mxc_capture_inputs[MXC_V4L2_CAPTURE_NUM_INPUTS] = { { .index = 0, - .name = "CSI IC MEM", + .name = "CSI MEM", .type = V4L2_INPUT_TYPE_CAMERA, .audioset = 0, .tuner = 0, .std = V4L2_STD_UNKNOWN, - .status = 0, + .status = V4L2_IN_ST_NO_POWER, }, { .index = 1, +// AG: CSI IC MEM works but has problems +// .name = "CSI IC MEM", .name = "CSI MEM", .type = V4L2_INPUT_TYPE_CAMERA, .audioset = 0, .tuner = 0, .std = V4L2_STD_UNKNOWN, - .status = V4L2_IN_ST_NO_POWER, + .status = 0, }, }; @@ -118,6 +122,7 @@ typedef struct { u16 active_left; /*!< Active left. */ } video_fmt_t; +#if 0 /*! * Description of video formats supported. * @@ -128,37 +133,39 @@ static video_fmt_t video_fmts[] = { { /*! NTSC */ .v4l2_id = V4L2_STD_NTSC, .name = "NTSC", - .raw_width = 720 - 1, /* SENS_FRM_WIDTH */ - .raw_height = 288 - 1, /* SENS_FRM_HEIGHT */ - .active_width = 720, /* ACT_FRM_WIDTH plus 1 */ - .active_height = (480 / 2), /* ACT_FRM_HEIGHT plus 1 */ - .active_top = 12, + .raw_width = 720, /* SENS_FRM_WIDTH */ + .raw_height = 525, /* SENS_FRM_HEIGHT */ + .active_width = 720, /* ACT_FRM_WIDTH */ + .active_height = 240, /* ACT_FRM_HEIGHT */ + .active_top = 0, .active_left = 0, }, { /*! (B, G, H, I, N) PAL */ .v4l2_id = V4L2_STD_PAL, .name = "PAL", - .raw_width = 720 - 1, - .raw_height = (576 / 2) + 24 * 2 - 1, + .raw_width = 720, + .raw_height = 625, .active_width = 720, - .active_height = (576 / 2), + .active_height = 288, .active_top = 0, .active_left = 0, }, { /*! Unlocked standard */ .v4l2_id = V4L2_STD_ALL, .name = "Autodetect", - .raw_width = 720 - 1, - .raw_height = (576 / 2) + 24 * 2 - 1, + .raw_width = 720, + .raw_height = 625, .active_width = 720, - .active_height = (576 / 2), + .active_height = 288, .active_top = 0, .active_left = 0, }, }; + /*!* Standard index of TV. */ static video_fmt_idx video_index = TV_NOT_LOCKED; +#endif static int mxc_v4l2_master_attach(struct v4l2_int_device *slave); static void mxc_v4l2_master_detach(struct v4l2_int_device *slave); @@ -172,15 +179,27 @@ static struct v4l2_int_master mxc_v4l2_master = { .detach = mxc_v4l2_master_detach, }; -static struct v4l2_int_device mxc_v4l2_int_device = { +static struct v4l2_int_device mxc_v4l2_int_device [] = { + { + .module = THIS_MODULE, + .name = "mxc_v4l2_cap_1", + .type = v4l2_int_type_master, + .u = { + .master = &mxc_v4l2_master, + }, + }, + { .module = THIS_MODULE, - .name = "mxc_v4l2_cap", + .name = "mxc_v4l2_cap_2", .type = v4l2_int_type_master, .u = { .master = &mxc_v4l2_master, }, + }, }; +static cam_data *g_cam[ARRAY_SIZE(mxc_v4l2_int_device)]; + /*************************************************************************** * Functions for handling Frame buffers. **************************************************************************/ @@ -260,6 +279,7 @@ static int mxc_allocate_frame_buf(cam_data *cam, int count) static void mxc_free_frames(cam_data *cam) { int i; + unsigned long lock_flags; pr_debug("In MVC:mxc_free_frames\n"); @@ -269,9 +289,11 @@ static void mxc_free_frames(cam_data *cam) cam->enc_counter = 0; cam->skip_frame = 0; + spin_lock_irqsave(&cam->dqueue_int_lock, lock_flags); INIT_LIST_HEAD(&cam->ready_q); INIT_LIST_HEAD(&cam->working_q); INIT_LIST_HEAD(&cam->done_q); + spin_unlock_irqrestore(&cam->dqueue_int_lock, lock_flags); } /*! @@ -331,8 +353,7 @@ static int mxc_streamon(cam_data *cam) { struct mxc_v4l_frame *frame; int err = 0; - - pr_debug("In MVC:mxc_streamon\n"); + unsigned long lock_flags; if (NULL == cam) { pr_err("ERROR! cam parameter is NULL\n"); @@ -363,23 +384,27 @@ static int mxc_streamon(cam_data *cam) } } + spin_lock_irqsave(&cam->queue_int_lock, lock_flags); cam->ping_pong_csi = 0; if (cam->enc_update_eba) { - frame = - list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); - list_del(cam->ready_q.next); - list_add_tail(&frame->queue, &cam->working_q); - err = cam->enc_update_eba(frame->buffer.m.offset, - &cam->ping_pong_csi); frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); list_del(cam->ready_q.next); list_add_tail(&frame->queue, &cam->working_q); - err |= cam->enc_update_eba(frame->buffer.m.offset, - &cam->ping_pong_csi); + err = cam->enc_update_eba(cam->csi,frame->buffer.m.offset, + &cam->ping_pong_csi); + if (!list_empty(&cam->ready_q)) { + frame = + list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); + list_del(cam->ready_q.next); + list_add_tail(&frame->queue, &cam->working_q); + err |= cam->enc_update_eba(cam->csi,frame->buffer.m.offset, + &cam->ping_pong_csi); + } + cam->capture_on = true; } else { - return -EINVAL; + err = -EINVAL; } if (cam->overlay_on == true) @@ -387,11 +412,9 @@ static int mxc_streamon(cam_data *cam) if (cam->enc_enable_csi) { err = cam->enc_enable_csi(cam); - if (err != 0) - return err; } - cam->capture_on = true; + spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags); return err; } @@ -543,8 +566,6 @@ static int start_preview(cam_data *cam) { int err = 0; - pr_debug("MVC: start_preview\n"); - #if defined(CONFIG_MXC_IPU_PRP_VF_SDC) || defined(CONFIG_MXC_IPU_PRP_VF_SDC_MODULE) pr_debug(" This is an SDC display\n"); if (cam->output == 0 || cam->output == 2) { @@ -602,8 +623,6 @@ static int stop_preview(cam_data *cam) { int err = 0; - pr_debug("MVC: stop preview\n"); - #if defined(CONFIG_MXC_IPU_PRP_VF_ADC) || defined(CONFIG_MXC_IPU_PRP_VF_ADC_MODULE) if (cam->output == 1) { err = prp_vf_adc_deselect(cam); @@ -674,6 +693,29 @@ static int mxc_v4l2_g_fmt(cam_data *cam, struct v4l2_format *f) __func__, cam->crop_current.width, cam->crop_current.height); + retval = vidioc_int_g_fmt_cap(cam->sensor,f); + return retval; +} + +/*! + * V4L2 - mxc_v4l2_enum_fmt function + * + * @param cam structure cam_data * + * + * @param f structure v4l2_fmtdesc * + * + * @return status 0 success, EINVAL failed + */ +static int mxc_v4l2_enum_fmt(cam_data *cam, struct v4l2_fmtdesc *f) +{ + int retval = 0; + + pr_debug("In MVC: mxc_v4l2_enum_fmt\n"); + + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true); + retval = vidioc_int_enum_fmt_cap(cam->sensor,f); + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false); + return retval; } @@ -709,10 +751,14 @@ static int mxc_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f) * for CSI MEM input mode. */ if (strcmp(mxc_capture_inputs[cam->current_input].name, - "CSI MEM") == 0) { + "CSI MEM") == 0 || strcmp(mxc_capture_inputs[cam->current_input].name, + "CSI IC MEM") == 0) { f->fmt.pix.width = cam->crop_current.width; f->fmt.pix.height = cam->crop_current.height; } + else { + printk("Error no match %s\n",mxc_capture_inputs[cam->current_input].name); + } if (cam->rotation >= IPU_ROTATE_90_RIGHT) { height = &f->fmt.pix.width; @@ -811,6 +857,13 @@ static int mxc_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f) break; } } + + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, + true, true); + vidioc_int_s_fmt_cap(cam->sensor, f); + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, + false, false); + break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: pr_debug(" type=V4L2_BUF_TYPE_VIDEO_OVERLAY\n"); @@ -1057,63 +1110,10 @@ static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c) return ret; } -/*! - * V4L2 - mxc_v4l2_s_param function - * Allows setting of capturemode and frame rate. - * - * @param cam structure cam_data * - * @param parm structure v4l2_streamparm * - * - * @return status 0 success, EINVAL failed - */ -static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm) -{ - struct v4l2_ifparm ifparm; +static int mxc_v4l2_init_csi( cam_data *cam ) { struct v4l2_format cam_fmt; - struct v4l2_streamparm currentparm; ipu_csi_signal_cfg_t csi_param; - int err = 0; - - pr_debug("In mxc_v4l2_s_param\n"); - - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - pr_err(KERN_ERR "mxc_v4l2_s_param invalid type\n"); - return -EINVAL; - } - - /* Stop the viewfinder */ - if (cam->overlay_on == true) { - stop_preview(cam); - } - - currentparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - /* First check that this device can support the changes requested. */ - err = vidioc_int_g_parm(cam->sensor, ¤tparm); - if (err) { - pr_err("%s: vidioc_int_g_parm returned an error %d\n", - __func__, err); - goto exit; - } - - pr_debug(" Current capabilities are %x\n", - currentparm.parm.capture.capability); - pr_debug(" Current capturemode is %d change to %d\n", - currentparm.parm.capture.capturemode, - parm->parm.capture.capturemode); - pr_debug(" Current framerate is %d change to %d\n", - currentparm.parm.capture.timeperframe.denominator, - parm->parm.capture.timeperframe.denominator); - - /* This will change any camera settings needed. */ - ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true); - err = vidioc_int_s_parm(cam->sensor, parm); - ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false); - if (err) { - pr_err("%s: vidioc_int_s_parm returned an error %d\n", - __func__, err); - goto exit; - } + struct v4l2_ifparm ifparm; /* If resolution changed, need to re-program the CSI */ /* Get new values. */ @@ -1131,13 +1131,13 @@ static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm) csi_param.force_eof = 0; csi_param.data_en_pol = 0; csi_param.data_fmt = 0; - csi_param.csi = 0; + csi_param.csi = cam->csi; csi_param.mclk = 0; /* This may not work on other platforms. Check when adding a new one.*/ pr_debug(" clock_curr=mclk=%d\n", ifparm.u.bt656.clock_curr); if (ifparm.u.bt656.clock_curr == 0) { - csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE; + csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED; } else { csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; } @@ -1189,7 +1189,63 @@ static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm) ipu_csi_init_interface(cam->crop_bounds.width, cam->crop_bounds.height, cam_fmt.fmt.pix.pixelformat, csi_param); + return 0; +} +/*! + * V4L2 - mxc_v4l2_s_param function + * Allows setting of capturemode and frame rate. + * + * @param cam structure cam_data * + * @param parm structure v4l2_streamparm * + * + * @return status 0 success, EINVAL failed + */ +static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm) +{ + struct v4l2_streamparm currentparm; + int err = 0; + + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + pr_err(KERN_ERR "mxc_v4l2_s_param invalid type\n"); + return -EINVAL; + } + + /* Stop the viewfinder */ + if (cam->overlay_on == true) { + stop_preview(cam); + } + + currentparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* First check that this device can support the changes requested. */ + err = vidioc_int_g_parm(cam->sensor, ¤tparm); + if (err) { + pr_err("%s: vidioc_int_g_parm returned an error %d\n", + __func__, err); + goto exit; + } + + pr_debug(" Current capabilities are %x\n", + currentparm.parm.capture.capability); + pr_debug(" Current capturemode is %d change to %d\n", + currentparm.parm.capture.capturemode, + parm->parm.capture.capturemode); + pr_debug(" Current framerate is %d change to %d\n", + currentparm.parm.capture.timeperframe.denominator, + parm->parm.capture.timeperframe.denominator); + + /* This will change any camera settings needed. */ + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true); + err = vidioc_int_s_parm(cam->sensor, parm); + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false); + if (err) { + pr_err("%s: vidioc_int_s_parm returned an error %d\n", + __func__, err); + goto exit; + } + + err = mxc_v4l2_init_csi(cam); exit: if (cam->overlay_on == true) @@ -1198,6 +1254,7 @@ exit: return err; } +#if 0 /*! * V4L2 - mxc_v4l2_s_std function * @@ -1287,6 +1344,7 @@ static int mxc_v4l2_g_std(cam_data *cam, v4l2_std_id *e) return 0; } +#endif /*! * Dequeue one V4L capture buffer @@ -1372,6 +1430,11 @@ static int mxc_v4l_open(struct file *file) return -EBADF; } + if(!cam->sensor) { + pr_err("ERROR: v4l2 capture: Unattached sensor!\n"); + return -EBADF; + } + down(&cam->busy_lock); err = 0; if (signal_pending(current)) @@ -1411,12 +1474,9 @@ static int mxc_v4l_open(struct file *file) csi_param.force_eof = 0; csi_param.data_en_pol = 0; csi_param.mclk = ifparm.u.bt656.clock_curr; - + csi_param.ext_vsync = ifparm.u.bt656.bt_sync_correct; csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv; - /* Once we handle multiple inputs this will need to change. */ - csi_param.csi = 0; - if (ifparm.u.bt656.mode == V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT) csi_param.data_width = IPU_CSI_DATA_WIDTH_8; @@ -1464,11 +1524,13 @@ static int mxc_v4l_open(struct file *file) __func__, cam->crop_current.width, cam->crop_current.height); + udelay(100); + csi_param.data_fmt = cam_fmt.fmt.pix.pixelformat; pr_debug("On Open: Input to ipu size is %d x %d\n", cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height); ipu_csi_set_window_size(cam->crop_current.width, - cam->crop_current.width, + cam->crop_current.height, cam->csi); ipu_csi_set_window_pos(cam->crop_current.left, cam->crop_current.top, @@ -1478,12 +1540,16 @@ static int mxc_v4l_open(struct file *file) cam_fmt.fmt.pix.pixelformat, csi_param); + udelay(100); + ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true); vidioc_int_init(cam->sensor); ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false); + + udelay(100); } file->private_data = dev; @@ -1519,7 +1585,7 @@ static int mxc_v4l_close(struct file *file) err = stop_preview(cam); cam->overlay_on = false; } - if (cam->capture_pid == current->pid) { + if (cam->capture_pid == current->tgid) { err |= mxc_streamoff(cam); wake_up_interruptible(&cam->enc_queue); } @@ -1570,7 +1636,7 @@ static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t *ppos) { int err = 0; - u8 *v_address; + u8 *v_address[2]; struct video_device *dev = video_devdata(file); cam_data *cam = video_get_drvdata(dev); @@ -1581,11 +1647,17 @@ static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count, if (cam->overlay_on == true) stop_preview(cam); - v_address = dma_alloc_coherent(0, + v_address[0] = dma_alloc_coherent(0, PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), - &cam->still_buf, GFP_DMA | GFP_KERNEL); + &cam->still_buf[0], + GFP_DMA | GFP_KERNEL); + + v_address[1] = dma_alloc_coherent(0, + PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), + &cam->still_buf[1], + GFP_DMA | GFP_KERNEL); - if (!v_address) { + if (!v_address[0] || !v_address[1]) { err = -ENOBUFS; goto exit0; } @@ -1593,14 +1665,14 @@ static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count, err = prp_still_select(cam); if (err != 0) { err = -EIO; - goto exit1; + goto exit0; } cam->still_counter = 0; err = cam->csi_start(cam); if (err != 0) { err = -EIO; - goto exit2; + goto exit1; } if (!wait_event_interruptible_timeout(cam->still_queue, @@ -1609,19 +1681,23 @@ static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count, pr_err("ERROR: v4l2 capture: mxc_v4l_read timeout counter %x\n", cam->still_counter); err = -ETIME; - goto exit2; + goto exit1; } - err = copy_to_user(buf, v_address, cam->v2f.fmt.pix.sizeimage); - - exit2: - prp_still_deselect(cam); + err = copy_to_user(buf, v_address[1], cam->v2f.fmt.pix.sizeimage); exit1: - dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address, - cam->still_buf); - cam->still_buf = 0; + prp_still_deselect(cam); exit0: + if (v_address[0] != 0) + dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address[0], + cam->still_buf[0]); + if (v_address[1] != 0) + dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address[1], + cam->still_buf[1]); + + cam->still_buf[0] = cam->still_buf[1] = 0; + if (cam->overlay_on == true) { start_preview(cam); } @@ -1661,6 +1737,21 @@ static long mxc_v4l_do_ioctl(struct file *file, return -EBUSY; switch (ioctlnr) { + +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_DBG_S_REGISTER: { + struct v4l2_dbg_register * dreg = arg; + vidioc_int_s_register(cam->sensor,dreg); + break; + } + + case VIDIOC_DBG_G_REGISTER: { + struct v4l2_dbg_register * dreg = arg; + vidioc_int_g_register(cam->sensor,dreg); + break; + } +#endif + /*! * V4l2 VIDIOC_QUERYCAP ioctl */ @@ -1695,6 +1786,14 @@ static long mxc_v4l_do_ioctl(struct file *file, struct v4l2_format *sf = arg; pr_debug(" case VIDIOC_S_FMT\n"); retval = mxc_v4l2_s_fmt(cam, sf); + mxc_v4l2_init_csi(cam); + break; + } + + case VIDIOC_ENUM_FMT: { + struct v4l2_fmtdesc *fd = arg; + pr_debug(" case VIDIOC_ENUM_FMT\n"); + retval = mxc_v4l2_enum_fmt(cam, fd); break; } @@ -1775,9 +1874,8 @@ static long mxc_v4l_do_ioctl(struct file *file, if (cam->skip_frame > 0) { list_add_tail(&cam->frame[index].queue, &cam->working_q); - retval = - cam->enc_update_eba(cam-> + cam->enc_update_eba(cam->csi,cam-> frame[index]. buffer.m.offset, &cam-> @@ -1999,28 +2097,6 @@ static long mxc_v4l_do_ioctl(struct file *file, break; } - /* linux v4l2 bug, kernel c0485619 user c0405619 */ - case VIDIOC_ENUMSTD: { - struct v4l2_standard *e = arg; - pr_debug(" case VIDIOC_ENUMSTD\n"); - *e = cam->standard; - break; - } - - case VIDIOC_G_STD: { - v4l2_std_id *e = arg; - pr_debug(" case VIDIOC_G_STD\n"); - retval = mxc_v4l2_g_std(cam, e); - break; - } - - case VIDIOC_S_STD: { - v4l2_std_id *e = arg; - pr_debug(" case VIDIOC_S_STD\n"); - retval = mxc_v4l2_s_std(cam, *e); - - break; - } case VIDIOC_ENUMOUTPUT: { struct v4l2_output *output = arg; @@ -2109,8 +2185,13 @@ static long mxc_v4l_do_ioctl(struct file *file, break; } - case VIDIOC_ENUM_FMT: - case VIDIOC_TRY_FMT: + case VIDIOC_TRY_FMT: { + struct v4l2_format * f = arg; + pr_debug(" case VIDIOC_TRY_FMT\n"); + retval = vidioc_int_try_fmt_cap(cam->sensor,f); + break; + } + case VIDIOC_QUERYCTRL: case VIDIOC_G_TUNER: case VIDIOC_S_TUNER: @@ -2163,7 +2244,7 @@ static int mxc_mmap(struct file *file, struct vm_area_struct *vma) return -EINTR; size = vma->vm_end - vma->vm_start; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, size, vma->vm_page_prot)) { @@ -2236,12 +2317,21 @@ static void camera_platform_release(struct device *device) } /*! Device Definition for Mt9v111 devices */ -static struct platform_device mxc_v4l2_devices = { - .name = "mxc_v4l2", - .dev = { - .release = camera_platform_release, - }, - .id = 0, +static struct platform_device mxc_v4l2_devices[] = { + { + .name = "mxc_v4l2_1", + .dev = { + .release = camera_platform_release, + }, + .id = 0, + }, + { + .name = "mxc_v4l2_2", + .dev = { + .release = camera_platform_release, + }, + .id = 1, + } }; /*! @@ -2302,7 +2392,7 @@ static void camera_callback(u32 mask, void *dev) struct mxc_v4l_frame, queue); - if (cam->enc_update_eba( + if (cam->enc_update_eba(cam->csi, ready_frame->buffer.m.offset, &cam->ping_pong_csi) == 0) { list_del(cam->ready_q.next); @@ -2354,7 +2444,7 @@ static void camera_callback(u32 mask, void *dev) ready_frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); - if (cam->enc_update_eba(ready_frame->buffer.m.offset, + if (cam->enc_update_eba(cam->csi,ready_frame->buffer.m.offset, &cam->ping_pong_csi) == 0) { list_del(cam->ready_q.next); list_add_tail(&ready_frame->queue, @@ -2362,7 +2452,7 @@ static void camera_callback(u32 mask, void *dev) } else return; } else { - if (cam->enc_update_eba( + if (cam->enc_update_eba(cam->csi, cam->dummy_frame.buffer.m.offset, &cam->ping_pong_csi) == -EACCES) return; @@ -2379,13 +2469,15 @@ static void camera_callback(u32 mask, void *dev) * * @return status 0 Success */ -static void init_camera_struct(cam_data *cam) +static void init_camera_struct(cam_data *cam,unsigned int csi) { - pr_debug("In MVC: init_camera_struct\n"); + pr_debug("In MVC: init_camera_struct for csi %d\n",csi); /* Default everything to 0 */ memset(cam, 0, sizeof(cam_data)); + cam->csi = csi; + init_MUTEX(&cam->param_lock); init_MUTEX(&cam->busy_lock); @@ -2396,7 +2488,7 @@ static void init_camera_struct(cam_data *cam) *(cam->video_dev) = mxc_v4l_template; video_set_drvdata(cam->video_dev, cam); - dev_set_drvdata(&mxc_v4l2_devices.dev, (void *)cam); + dev_set_drvdata(&mxc_v4l2_devices[csi].dev, (void *)cam); cam->video_dev->minor = -1; init_waitqueue_head(&cam->enc_queue); @@ -2428,6 +2520,8 @@ static void init_camera_struct(cam_data *cam) cam->skip_frame = 0; cam->v4l2_fb.flags = V4L2_FBUF_FLAG_OVERLAY; + cam->current_input = cam->csi; + cam->v2f.fmt.pix.sizeimage = 352 * 288 * 3 / 2; cam->v2f.fmt.pix.bytesperline = 288 * 3 / 2; cam->v2f.fmt.pix.width = 288; @@ -2438,9 +2532,6 @@ static void init_camera_struct(cam_data *cam) cam->win.w.left = 0; cam->win.w.top = 0; - cam->csi = 0; /* Need to determine how to set this correctly with - * multiple video input devices. */ - cam->enc_callback = camera_callback; init_waitqueue_head(&cam->power_queue); spin_lock_init(&cam->queue_int_lock); @@ -2460,11 +2551,12 @@ static u8 camera_power(cam_data *cam, bool cameraOn) { pr_debug("In MVC:camera_power on=%d\n", cameraOn); + if( !cam->open_count ) + return 0; + if (cameraOn == true) { - ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true); vidioc_int_s_power(cam->sensor, 1); } else { - ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false); vidioc_int_s_power(cam->sensor, 0); } return 0; @@ -2491,15 +2583,15 @@ static int mxc_v4l2_suspend(struct platform_device *pdev, pm_message_t state) return -1; } + if (!cam->open_count) { + return 0; + } + cam->low_power = true; if (cam->overlay_on == true) stop_preview(cam); - if ((cam->capture_on == true) && cam->enc_disable) { - cam->enc_disable(cam); - } camera_power(cam, false); - return 0; } @@ -2522,14 +2614,19 @@ static int mxc_v4l2_resume(struct platform_device *pdev) return -1; } + if( !cam->open_count ) + return 0; + cam->low_power = false; wake_up_interruptible(&cam->power_queue); + camera_power(cam, true); if (cam->overlay_on == true) start_preview(cam); + if (cam->capture_on == true) - mxc_streamon(cam); + mxc_streamon(cam); return 0; } @@ -2537,15 +2634,27 @@ static int mxc_v4l2_resume(struct platform_device *pdev) /*! * This structure contains pointers to the power management callback functions. */ -static struct platform_driver mxc_v4l2_driver = { - .driver = { - .name = "mxc_v4l2", - }, - .probe = NULL, - .remove = NULL, - .suspend = mxc_v4l2_suspend, - .resume = mxc_v4l2_resume, - .shutdown = NULL, +static struct platform_driver mxc_v4l2_driver[] = { + { + .driver = { + .name = "mxc_v4l2_1", + }, + .probe = NULL, + .remove = NULL, + .suspend = mxc_v4l2_suspend, + .resume = mxc_v4l2_resume, + .shutdown = NULL, + }, + { + .driver = { + .name = "mxc_v4l2_2", + }, + .probe = NULL, + .remove = NULL, + .suspend = mxc_v4l2_suspend, + .resume = mxc_v4l2_resume, + .shutdown = NULL, + }, }; /*! @@ -2567,6 +2676,7 @@ static int mxc_v4l2_master_attach(struct v4l2_int_device *slave) } ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true); + vidioc_int_s_power(cam->sensor, 1); vidioc_int_dev_init(slave); ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false); cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -2623,53 +2733,55 @@ static void mxc_v4l2_master_detach(struct v4l2_int_device *slave) static __init int camera_init(void) { u8 err = 0; + int i; pr_debug("In MVC:camera_init\n"); - /* Register the device driver structure. */ - err = platform_driver_register(&mxc_v4l2_driver); - if (err != 0) { - pr_err("ERROR: v4l2 capture:camera_init: " - "platform_driver_register failed.\n"); - return err; - } + for (i = 0; i < ARRAY_SIZE(mxc_v4l2_int_device); i++) { + /* Register the device driver structure. */ + err = platform_driver_register(&mxc_v4l2_driver[i]); + if (err != 0) { + pr_err("ERROR: v4l2 capture:camera_init: " + "platform_driver_register failed.\n"); + return err; + } - /* Create g_cam and initialize it. */ - if ((g_cam = kmalloc(sizeof(cam_data), GFP_KERNEL)) == NULL) { - pr_err("ERROR: v4l2 capture: failed to register camera\n"); - platform_driver_unregister(&mxc_v4l2_driver); - return -1; - } - init_camera_struct(g_cam); + /* Create g_cam and initialize it. */ + if ((g_cam [i] = kmalloc(sizeof(cam_data), GFP_KERNEL)) == NULL) { + pr_err("ERROR: v4l2 capture: failed to register camera\n"); + platform_driver_unregister(&mxc_v4l2_driver[i]); + return -1; + } + init_camera_struct(g_cam [i], i); - /* Set up the v4l2 device and register it*/ - mxc_v4l2_int_device.priv = g_cam; - /* This function contains a bug that won't let this be rmmod'd. */ - v4l2_int_device_register(&mxc_v4l2_int_device); + /* Set up the v4l2 device and register it*/ + mxc_v4l2_int_device[i].priv = g_cam [i]; + /* This function contains a bug that won't let this be rmmod'd. */ + v4l2_int_device_register(&mxc_v4l2_int_device[i]); - /* Register the I2C device */ - err = platform_device_register(&mxc_v4l2_devices); - if (err != 0) { - pr_err("ERROR: v4l2 capture: camera_init: " - "platform_device_register failed.\n"); - platform_driver_unregister(&mxc_v4l2_driver); - kfree(g_cam); - g_cam = NULL; - return err; - } + /* Register the I2C device */ + err = platform_device_register(&mxc_v4l2_devices[i]); + if (err != 0) { + pr_err("ERROR: v4l2 capture: camera_init: " + "platform_device_register failed.\n"); + platform_driver_unregister(&mxc_v4l2_driver[i]); + kfree(g_cam [i]); + g_cam [i] = NULL; + return err; + } - /* register v4l video device */ - if (video_register_device(g_cam->video_dev, VFL_TYPE_GRABBER, video_nr) - == -1) { - platform_device_unregister(&mxc_v4l2_devices); - platform_driver_unregister(&mxc_v4l2_driver); - kfree(g_cam); - g_cam = NULL; - pr_err("ERROR: v4l2 capture: video_register_device failed\n"); - return -1; + /* register v4l video device */ + if (video_register_device(g_cam[i]->video_dev, VFL_TYPE_GRABBER, video_nr)== -1) { + platform_device_unregister(&mxc_v4l2_devices[i]); + platform_driver_unregister(&mxc_v4l2_driver[i]); + kfree(g_cam[i]); + g_cam [i] = NULL; + pr_err("ERROR: v4l2 capture: video_register_device failed\n"); + return -1; + } + pr_debug(" Video device registered: %s #%d\n", + g_cam[i]->video_dev->name, g_cam[i]->video_dev->minor); } - pr_debug(" Video device registered: %s #%d\n", - g_cam->video_dev->name, g_cam->video_dev->minor); return err; } @@ -2683,19 +2795,34 @@ static void __exit camera_exit(void) pr_info("V4L2 unregistering video\n"); - if (g_cam->open_count) { + if (g_cam[0]->open_count) { + pr_err("ERROR: v4l2 capture:camera open " + "-- setting ops to NULL\n"); + } else { + pr_info("V4L2 freeing image input device\n"); + v4l2_int_device_unregister(&mxc_v4l2_int_device[0]); + video_unregister_device(g_cam[0]->video_dev); + platform_driver_unregister(&mxc_v4l2_driver[0]); + platform_device_unregister(&mxc_v4l2_devices[0]); + + mxc_free_frame_buf(g_cam[0]); + kfree(g_cam[0]); + g_cam[0] = NULL; + } + + if (g_cam[1]->open_count) { pr_err("ERROR: v4l2 capture:camera open " "-- setting ops to NULL\n"); } else { pr_info("V4L2 freeing image input device\n"); - v4l2_int_device_unregister(&mxc_v4l2_int_device); - video_unregister_device(g_cam->video_dev); - platform_driver_unregister(&mxc_v4l2_driver); - platform_device_unregister(&mxc_v4l2_devices); - - mxc_free_frame_buf(g_cam); - kfree(g_cam); - g_cam = NULL; + v4l2_int_device_unregister(&mxc_v4l2_int_device[1]); + video_unregister_device(g_cam[1]->video_dev); + platform_driver_unregister(&mxc_v4l2_driver[1]); + platform_device_unregister(&mxc_v4l2_devices[1]); + + mxc_free_frame_buf(g_cam[1]); + kfree(g_cam[1]); + g_cam[1] = NULL; } } diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h index 45a211a80a38..abaaaea48447 100644 --- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h +++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h @@ -36,6 +36,7 @@ #include <media/v4l2-dev.h> #define FRAME_NUM 3 +//#define FRAME_NUM 4 /*! * v4l2 frame structure. @@ -123,7 +124,7 @@ typedef struct _cam_data { /* still image capture */ wait_queue_head_t still_queue; int still_counter; - dma_addr_t still_buf; + dma_addr_t still_buf[2]; void *still_buf_vaddr; /* overlay */ @@ -166,7 +167,7 @@ typedef struct _cam_data { struct v4l2_rect crop_defrect; struct v4l2_rect crop_current; - int (*enc_update_eba) (dma_addr_t eba, int *bufferNum); + int (*enc_update_eba) (int csi,dma_addr_t eba, int *bufferNum); int (*enc_enable) (void *private); int (*enc_disable) (void *private); int (*enc_enable_csi) (void *private); @@ -194,6 +195,7 @@ typedef struct _cam_data { /* camera sensor interface */ struct camera_sensor *cam_sensor; /* old version */ struct v4l2_int_device *sensor; + struct timeval tv_wakeup; // TODO - for testing. Remove later } cam_data; #if defined(CONFIG_MXC_IPU_V1) || defined(CONFIG_VIDEO_MXC_EMMA_CAMERA) \ diff --git a/drivers/media/video/mxc/capture/ov3640.c b/drivers/media/video/mxc/capture/ov3640.c index 29e61234e7f8..899945b7d071 100644 --- a/drivers/media/video/mxc/capture/ov3640.c +++ b/drivers/media/video/mxc/capture/ov3640.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -26,7 +26,7 @@ #define OV3640_VOLTAGE_ANALOG 2800000 #define OV3640_VOLTAGE_DIGITAL_CORE 1500000 #define OV3640_VOLTAGE_DIGITAL_IO 1800000 - +#define OV3640_VOLTAGE_DIGITAL_GPO 2800000 /* Check these values! */ #define MIN_FPS 15 @@ -40,8 +40,8 @@ enum ov3640_mode { ov3640_mode_MIN = 0, ov3640_mode_VGA_640_480 = 0, ov3640_mode_QVGA_320_240 = 1, - ov3640_mode_QXGA_2048_1536 = 2, - ov3640_mode_XGA_1024_768 = 3, + ov3640_mode_XGA_1024_768 = 2, + ov3640_mode_QXGA_2048_1536 = 3, ov3640_mode_NTSC_720_480 = 4, ov3640_mode_PAL_720_576 = 5, ov3640_mode_MAX = 5 @@ -93,6 +93,44 @@ struct sensor { } ov3640_data; static struct reg_value ov3640_setting_15fps_QXGA_2048_1536[] = { +#if 0 + /* The true 15fps QXGA setting. */ + {0x3012, 0x80, 0, 0}, {0x304d, 0x41, 0, 0}, {0x3087, 0x16, 0, 0}, + {0x30aa, 0x45, 0, 0}, {0x30b0, 0xff, 0, 0}, {0x30b1, 0xff, 0, 0}, + {0x30b2, 0x13, 0, 0}, {0x30d7, 0x10, 0, 0}, {0x309e, 0x00, 0, 0}, + {0x3602, 0x26, 0, 0}, {0x3603, 0x4D, 0, 0}, {0x364c, 0x04, 0, 0}, + {0x360c, 0x12, 0, 0}, {0x361e, 0x00, 0, 0}, {0x361f, 0x11, 0, 0}, + {0x3633, 0x03, 0, 0}, {0x3629, 0x3c, 0, 0}, {0x300e, 0x33, 0, 0}, + {0x300f, 0x21, 0, 0}, {0x3010, 0x20, 0, 0}, {0x3011, 0x00, 0, 0}, + {0x304c, 0x81, 0, 0}, {0x3029, 0x47, 0, 0}, {0x3070, 0x00, 0, 0}, + {0x3071, 0xEC, 0, 0}, {0x301C, 0x06, 0, 0}, {0x3072, 0x00, 0, 0}, + {0x3073, 0xC5, 0, 0}, {0x301D, 0x07, 0, 0}, {0x3018, 0x38, 0, 0}, + {0x3019, 0x30, 0, 0}, {0x301a, 0x61, 0, 0}, {0x307d, 0x00, 0, 0}, + {0x3087, 0x02, 0, 0}, {0x3082, 0x20, 0, 0}, {0x303c, 0x08, 0, 0}, + {0x303d, 0x18, 0, 0}, {0x303e, 0x06, 0, 0}, {0x303F, 0x0c, 0, 0}, + {0x3030, 0x62, 0, 0}, {0x3031, 0x26, 0, 0}, {0x3032, 0xe6, 0, 0}, + {0x3033, 0x6e, 0, 0}, {0x3034, 0xea, 0, 0}, {0x3035, 0xae, 0, 0}, + {0x3036, 0xa6, 0, 0}, {0x3037, 0x6a, 0, 0}, {0x3015, 0x12, 0, 0}, + {0x3014, 0x04, 0, 0}, {0x3013, 0xf7, 0, 0}, {0x3104, 0x02, 0, 0}, + {0x3105, 0xfd, 0, 0}, {0x3106, 0x00, 0, 0}, {0x3107, 0xff, 0, 0}, + {0x3308, 0xa5, 0, 0}, {0x3316, 0xff, 0, 0}, {0x3317, 0x00, 0, 0}, + {0x3087, 0x02, 0, 0}, {0x3082, 0x20, 0, 0}, {0x3300, 0x13, 0, 0}, + {0x3301, 0xd6, 0, 0}, {0x3302, 0xef, 0, 0}, {0x30b8, 0x20, 0, 0}, + {0x30b9, 0x17, 0, 0}, {0x30ba, 0x04, 0, 0}, {0x30bb, 0x08, 0, 0}, + {0x3100, 0x02, 0, 0}, {0x3304, 0x00, 0, 0}, {0x3400, 0x00, 0, 0}, + {0x3404, 0x02, 0, 0}, {0x3020, 0x01, 0, 0}, {0x3021, 0x1d, 0, 0}, + {0x3022, 0x00, 0, 0}, {0x3023, 0x0a, 0, 0}, {0x3024, 0x08, 0, 0}, + {0x3025, 0x18, 0, 0}, {0x3026, 0x06, 0, 0}, {0x3027, 0x0c, 0, 0}, + {0x335f, 0x68, 0, 0}, {0x3360, 0x18, 0, 0}, {0x3361, 0x0c, 0, 0}, + {0x3362, 0x68, 0, 0}, {0x3363, 0x08, 0, 0}, {0x3364, 0x04, 0, 0}, + {0x3403, 0x42, 0, 0}, {0x3088, 0x08, 0, 0}, {0x3089, 0x00, 0, 0}, + {0x308a, 0x06, 0, 0}, {0x308b, 0x00, 0, 0}, {0x3507, 0x06, 0, 0}, + {0x350a, 0x4f, 0, 0}, {0x3600, 0xc4, 0, 0}, +#endif + /* + * Only support 7.5fps for QXGA to workaround screen tearing issue + * for 15fps when capturing still image. + */ {0x3012, 0x80, 0, 0}, {0x304d, 0x45, 0, 0}, {0x30a7, 0x5e, 0, 0}, {0x3087, 0x16, 0, 0}, {0x309c, 0x1a, 0, 0}, {0x30a2, 0xe4, 0, 0}, {0x30aa, 0x42, 0, 0}, {0x30b0, 0xff, 0, 0}, {0x30b1, 0xff, 0, 0}, @@ -118,25 +156,9 @@ static struct reg_value ov3640_setting_15fps_QXGA_2048_1536[] = { {0x30bb, 0x08, 0, 0}, {0x3507, 0x06, 0, 0}, {0x350a, 0x4f, 0, 0}, {0x3100, 0x02, 0, 0}, {0x3301, 0xde, 0, 0}, {0x3304, 0x00, 0, 0}, {0x3400, 0x00, 0, 0}, {0x3404, 0x02, 0, 0}, {0x3600, 0xc4, 0, 0}, - {0x3302, 0xef, 0, 0}, {0x3020, 0x01, 0, 0}, {0x3021, 0x1d, 0, 0}, - {0x3022, 0x00, 0, 0}, {0x3023, 0x0a, 0, 0}, {0x3024, 0x08, 0, 0}, - {0x3025, 0x00, 0, 0}, {0x3026, 0x06, 0, 0}, {0x3027, 0x00, 0, 0}, - {0x335f, 0x68, 0, 0}, {0x3360, 0x00, 0, 0}, {0x3361, 0x00, 0, 0}, - {0x3362, 0x68, 0, 0}, {0x3363, 0x00, 0, 0}, {0x3364, 0x00, 0, 0}, - {0x3403, 0x00, 0, 0}, {0x3088, 0x08, 0, 0}, {0x3089, 0x00, 0, 0}, - {0x308a, 0x06, 0, 0}, {0x308b, 0x00, 0, 0}, {0x307c, 0x10, 0, 0}, - {0x3090, 0xc0, 0, 0}, {0x304c, 0x84, 0, 0}, {0x308d, 0x04, 0, 0}, - {0x3086, 0x03, 0, 0}, {0x3086, 0x00, 0, 0}, {0x3012, 0x00, 0, 0}, - {0x3020, 0x01, 0, 0}, {0x3021, 0x1d, 0, 0}, {0x3022, 0x00, 0, 0}, - {0x3023, 0x0a, 0, 0}, {0x3024, 0x08, 0, 0}, {0x3025, 0x18, 0, 0}, - {0x3026, 0x06, 0, 0}, {0x3027, 0x0c, 0, 0}, {0x302a, 0x06, 0, 0}, - {0x302b, 0x20, 0, 0}, {0x3075, 0x44, 0, 0}, {0x300d, 0x00, 0, 0}, - {0x30d7, 0x00, 0, 0}, {0x3069, 0x40, 0, 0}, {0x303e, 0x01, 0, 0}, - {0x303f, 0x80, 0, 0}, {0x3302, 0x20, 0, 0}, {0x335f, 0x68, 0, 0}, - {0x3360, 0x18, 0, 0}, {0x3361, 0x0c, 0, 0}, {0x3362, 0x68, 0, 0}, - {0x3363, 0x08, 0, 0}, {0x3364, 0x04, 0, 0}, {0x3403, 0x42, 0, 0}, {0x3088, 0x08, 0, 0}, {0x3089, 0x00, 0, 0}, {0x308a, 0x06, 0, 0}, - {0x308b, 0x00, 0, 0}, + {0x308b, 0x00, 0, 0}, {0x308d, 0x04, 0, 0}, {0x3086, 0x03, 0, 0}, + {0x3086, 0x00, 0, 0}, {0x3011, 0x01, 0, 0}, }; static struct reg_value ov3640_setting_15fps_XGA_1024_768[] = { @@ -674,6 +696,7 @@ static struct regulator *io_regulator; static struct regulator *core_regulator; static struct regulator *analog_regulator; static struct regulator *gpo_regulator; +static struct mxc_camera_platform_data *camera_plat; static int ov3640_probe(struct i2c_client *adapter, const struct i2c_device_id *device_id); @@ -843,6 +866,10 @@ static int ioctl_s_power(struct v4l2_int_device *s, int on) if (analog_regulator) if (regulator_enable(analog_regulator) != 0) return -EIO; + /* Make sure power on */ + if (camera_plat->pwdn) + camera_plat->pwdn(0); + } else if (!on && sensor->on) { if (analog_regulator) regulator_disable(analog_regulator); @@ -920,6 +947,10 @@ static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) enum ov3640_frame_rate frame_rate; int ret = 0; + /* Make sure power on */ + if (camera_plat->pwdn) + camera_plat->pwdn(0); + switch (a->type) { /* This is the only case currently handled. */ case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -1286,17 +1317,25 @@ static int ov3640_probe(struct i2c_client *client, gpo_regulator = regulator_get(&client->dev, plat_data->gpo_regulator); if (!IS_ERR(gpo_regulator)) { + regulator_set_voltage(gpo_regulator, + OV3640_VOLTAGE_DIGITAL_GPO, + OV3640_VOLTAGE_DIGITAL_GPO); if (regulator_enable(gpo_regulator) != 0) { - pr_err("%s:gpo3 enable error\n", __func__); + pr_err("%s:gpo enable error\n", __func__); goto err4; } else { dev_dbg(&client->dev, - "%s:gpo3 enable ok\n", __func__); + "%s:gpo enable ok\n", __func__); } } else gpo_regulator = NULL; } + if (plat_data->pwdn) + plat_data->pwdn(0); + + camera_plat = plat_data; + ov3640_int_device.priv = &ov3640_data; retval = v4l2_int_device_register(&ov3640_int_device); diff --git a/drivers/media/video/mxc/output/Makefile b/drivers/media/video/mxc/output/Makefile index 1713fa3bf3ab..500442544902 100644 --- a/drivers/media/video/mxc/output/Makefile +++ b/drivers/media/video/mxc/output/Makefile @@ -6,6 +6,9 @@ endif ifeq ($(CONFIG_VIDEO_MXC_IPU_OUTPUT),y) obj-$(CONFIG_VIDEO_MXC_OUTPUT) += mxc_v4l2_output.o endif +ifeq ($(CONFIG_VIDEO_MXC_PXP_V4L2),y) + obj-$(CONFIG_VIDEO_MXC_PXP_V4L2) += mxc_pxp_v4l2.o +endif ifeq ($(CONFIG_VIDEO_MXC_IPUV1_WVGA_OUTPUT),y) obj-$(CONFIG_VIDEO_MXC_OUTPUT) += mx31_v4l2_wvga_output.o endif diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.c b/drivers/media/video/mxc/output/mxc_v4l2_output.c index 408f9b7871a8..b7bbfed73019 100644 --- a/drivers/media/video/mxc/output/mxc_v4l2_output.c +++ b/drivers/media/video/mxc/output/mxc_v4l2_output.c @@ -44,9 +44,7 @@ vout_data *g_vout; #define LOAD_3FIELDS(vout) ((INTERLACED_CONTENT(vout)) && \ ((vout)->motion_sel != HIGH_MOTION)) -#define SDC_FG_FB_FORMAT IPU_PIX_FMT_RGB565 - -struct v4l2_output mxc_outputs[2] = { +struct v4l2_output mxc_outputs[1] = { { .index = MXC_V4L2_OUT_2_SDC, .name = "DISP3 Video Out", @@ -54,23 +52,14 @@ struct v4l2_output mxc_outputs[2] = { but no other choice */ .audioset = 0, .modulator = 0, - .std = V4L2_STD_UNKNOWN}, - { - .index = MXC_V4L2_OUT_2_ADC, - .name = "DISPx Video Out", - .type = V4L2_OUTPUT_TYPE_ANALOG, /* not really correct, - but no other choice */ - .audioset = 0, - .modulator = 0, .std = V4L2_STD_UNKNOWN} }; static int video_nr = 16; static spinlock_t g_lock = SPIN_LOCK_UNLOCKED; static int last_index_n; -static int last_index_c; static unsigned int ipu_ic_out_max_width_size; - +static unsigned int ipu_ic_out_max_height_size; /* debug counters */ uint32_t g_irq_cnt; uint32_t g_buf_output_cnt; @@ -256,10 +245,14 @@ static int select_display_buffer(vout_data *vout, int next_buf) { int ret = 0; + vout->disp_buf_num = next_buf; if (ipu_get_cur_buffer_idx(vout->display_ch, IPU_INPUT_BUFFER) != next_buf) ret = ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER, next_buf); + else + dev_dbg(&vout->video_dev->dev, + "display buffer not ready for select\n"); return ret; } @@ -290,110 +283,138 @@ static void setup_next_buf_timer(vout_data *vout, int index) "timer handler next schedule: %lu\n", timeout); } -static int wait_for_disp_vsync(vout_data *vout) +static int finish_previous_frame(vout_data *vout) { struct fb_info *fbi = registered_fb[vout->output_fb_num[vout->cur_disp_output]]; mm_segment_t old_fs; int ret = 0; - /* wait for display frame finish */ - if (fbi->fbops->fb_ioctl) { - old_fs = get_fs(); - set_fs(KERNEL_DS); - ret = fbi->fbops->fb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC, - (unsigned int)NULL); - set_fs(old_fs); + /* make sure buf[vout->disp_buf_num] in showing */ + while (ipu_check_buffer_busy(vout->display_ch, + IPU_INPUT_BUFFER, vout->disp_buf_num)) { + if (fbi->fbops->fb_ioctl) { + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = fbi->fbops->fb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC, + (unsigned int)NULL); + set_fs(old_fs); + + if (ret < 0) { + /* ic_bypass need clear display buffer ready for next update*/ + ipu_clear_buffer_ready(vout->display_ch, IPU_INPUT_BUFFER, + vout->disp_buf_num); + } + } + } + + return ret; +} + +static int show_current_frame(vout_data *vout) +{ + struct fb_info *fbi = + registered_fb[vout->output_fb_num[vout->cur_disp_output]]; + mm_segment_t old_fs; + int ret = 0; + + /* make sure buf[vout->disp_buf_num] begin to show */ + if (ipu_get_cur_buffer_idx(vout->display_ch, IPU_INPUT_BUFFER) + != vout->disp_buf_num) { + /* wait for display frame finish */ + if (fbi->fbops->fb_ioctl) { + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = fbi->fbops->fb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC, + (unsigned int)NULL); + set_fs(old_fs); + } } + return ret; } -static void timer_work_func(struct work_struct *work) +static void icbypass_work_func(struct work_struct *work) { vout_data *vout = - container_of(work, vout_data, timer_work); + container_of(work, vout_data, icbypass_work); int index, ret; int last_buf; unsigned long lock_flags = 0; - /* wait 2 first frame finish for ic bypass mode*/ - if ((g_buf_output_cnt == 0) && vout->ic_bypass) { - wait_for_disp_vsync(vout); - wait_for_disp_vsync(vout); - spin_lock_irqsave(&g_lock, lock_flags); - last_buf = vout->ipu_buf[0]; - vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE; - queue_buf(&vout->done_q, last_buf); - vout->ipu_buf[0] = -1; - last_buf = vout->ipu_buf[1]; - vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE; - queue_buf(&vout->done_q, last_buf); - vout->ipu_buf[1] = -1; - g_buf_output_cnt = 2; - wake_up_interruptible(&vout->v4l_bufq); - if (vout->state == STATE_STREAM_PAUSED) { - index = peek_next_buf(&vout->ready_q); - if (index != -1) { - /* Setup timer for next buffer, when stream has been paused */ - pr_debug("next index %d\n", index); - setup_next_buf_timer(vout, index); - vout->state = STATE_STREAM_ON; - } - } - spin_unlock_irqrestore(&g_lock, lock_flags); - return; - } - - if (wait_for_disp_vsync(vout) < 0) { - /* ic_bypass need clear display buffer ready for next update*/ - ipu_clear_buffer_ready(vout->display_ch, IPU_INPUT_BUFFER, - !vout->next_done_ipu_buf); - } + finish_previous_frame(vout); spin_lock_irqsave(&g_lock, lock_flags); - if (vout->ic_bypass) { - last_buf = vout->ipu_buf[vout->next_done_ipu_buf]; - if (last_buf != -1) { - g_buf_output_cnt++; - vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE; - queue_buf(&vout->done_q, last_buf); - wake_up_interruptible(&vout->v4l_bufq); - vout->ipu_buf[vout->next_done_ipu_buf] = -1; - vout->next_done_ipu_buf = !vout->next_done_ipu_buf; - } + index = dequeue_buf(&vout->ready_q); + if (index == -1) { /* no buffers ready, should never occur */ + dev_err(&vout->video_dev->dev, + "mxc_v4l2out: timer - no queued buffers ready\n"); + goto exit; } + g_buf_dq_cnt++; + vout->frame_count++; - if (vout->ic_bypass) - ret = select_display_buffer(vout, vout->next_rdy_ipu_buf); - else if (LOAD_3FIELDS(vout)) - ret = ipu_select_multi_vdi_buffer(vout->next_rdy_ipu_buf); - else - ret = ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, - vout->next_rdy_ipu_buf); + vout->ipu_buf[vout->next_rdy_ipu_buf] = index; + ret = ipu_update_channel_buffer(vout->display_ch, IPU_INPUT_BUFFER, + vout->next_rdy_ipu_buf, + vout->v4l2_bufs[index].m.offset); + ret += select_display_buffer(vout, vout->next_rdy_ipu_buf); if (ret < 0) { dev_err(&vout->video_dev->dev, - "unable to set IPU buffer ready\n"); + "unable to update buffer %d address rc=%d\n", + vout->next_rdy_ipu_buf, ret); + goto exit; } + spin_unlock_irqrestore(&g_lock, lock_flags); + show_current_frame(vout); + spin_lock_irqsave(&g_lock, lock_flags); + vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf; - /* Non IC split action */ - if (!vout->pp_split) - vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf; + last_buf = vout->ipu_buf[vout->next_done_ipu_buf]; + if (last_buf != -1) { + g_buf_output_cnt++; + vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE; + queue_buf(&vout->done_q, last_buf); + wake_up_interruptible(&vout->v4l_bufq); + vout->ipu_buf[vout->next_done_ipu_buf] = -1; + vout->next_done_ipu_buf = !vout->next_done_ipu_buf; + } - /* Setup timer for next buffer */ - index = peek_next_buf(&vout->ready_q); - if (index != -1) - setup_next_buf_timer(vout, index); - else - vout->state = STATE_STREAM_PAUSED; + if (g_buf_output_cnt > 0) { + /* Setup timer for next buffer */ + index = peek_next_buf(&vout->ready_q); + if (index != -1) + setup_next_buf_timer(vout, index); + else + vout->state = STATE_STREAM_PAUSED; + if (vout->state == STATE_STREAM_STOPPING) { + if ((vout->ipu_buf[0] == -1) && (vout->ipu_buf[1] == -1)) { + vout->state = STATE_STREAM_OFF; + } + } + } +exit: spin_unlock_irqrestore(&g_lock, lock_flags); +} - if (vout->state == STATE_STREAM_STOPPING) { - if ((vout->ipu_buf[0] == -1) && (vout->ipu_buf[1] == -1)) { - vout->state = STATE_STREAM_OFF; - } +static int get_cur_fb_blank(vout_data *vout) +{ + struct fb_info *fbi = + registered_fb[vout->output_fb_num[vout->cur_disp_output]]; + mm_segment_t old_fs; + int ret = 0; + + if (fbi->fbops->fb_ioctl) { + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_BLANK, + (unsigned int)(&vout->fb_blank)); + set_fs(old_fs); } + + return ret; } static void mxc_v4l2out_timer_handler(unsigned long arg) @@ -401,13 +422,13 @@ static void mxc_v4l2out_timer_handler(unsigned long arg) int index, ret; unsigned long lock_flags = 0; vout_data *vout = (vout_data *) arg; - unsigned int aid_field_offset = 0, current_field_offset = 0; spin_lock_irqsave(&g_lock, lock_flags); if ((vout->state == STATE_STREAM_STOPPING) || (vout->state == STATE_STREAM_OFF)) goto exit0; + /* * If timer occurs before IPU h/w is ready, then set the state to * paused and the timer will be set again when next buffer is queued @@ -419,98 +440,92 @@ static void mxc_v4l2out_timer_handler(unsigned long arg) goto exit0; } - /* Dequeue buffer and pass to IPU */ - if (INTERLACED_CONTENT(vout)) { - if (((LOAD_3FIELDS(vout)) && (vout->next_rdy_ipu_buf)) || - ((!LOAD_3FIELDS(vout)) && !(vout->next_rdy_ipu_buf))) { - aid_field_offset = vout->bytesperline; - current_field_offset = 0; - index = last_index_n; - } else { - aid_field_offset = 0; - current_field_offset = vout->bytesperline; - index = dequeue_buf(&vout->ready_q); - if (index == -1) { /* no buffers ready, should never occur */ - dev_err(&vout->video_dev->dev, - "mxc_v4l2out: timer - no queued buffers ready\n"); - goto exit0; - } - g_buf_dq_cnt++; - vout->frame_count++; - last_index_n = index; - } - } else { - current_field_offset = 0; - index = dequeue_buf(&vout->ready_q); - if (index == -1) { /* no buffers ready, should never occur */ + /* VDI need both buffer done before update buffer? */ + if (INTERLACED_CONTENT(vout) && + (vout->ipu_buf[!vout->next_rdy_ipu_buf] != -1)) { + dev_dbg(&vout->video_dev->dev, "IPU buffer busy\n"); + vout->state = STATE_STREAM_PAUSED; + goto exit0; + } + + /* Handle ic bypass mode in work queue */ + if (vout->ic_bypass) { + if (queue_work(vout->v4l_wq, &vout->icbypass_work) == 0) { dev_err(&vout->video_dev->dev, - "mxc_v4l2out: timer - no queued buffers ready\n"); - goto exit0; + "ic bypass work was in queue already!\n "); + vout->state = STATE_STREAM_PAUSED; } - g_buf_dq_cnt++; - vout->frame_count++; + goto exit0; + } else if (!vout->fb_blank && + (ipu_get_cur_buffer_idx(vout->display_ch, IPU_INPUT_BUFFER) + == vout->next_disp_ipu_buf)) { + dev_dbg(&vout->video_dev->dev, "IPU disp busy\n"); + get_cur_fb_blank(vout); + index = peek_next_buf(&vout->ready_q); + setup_next_buf_timer(vout, index); + goto exit0; } + vout->fb_blank = 0; + + /* Dequeue buffer and pass to IPU */ + index = dequeue_buf(&vout->ready_q); + if (index == -1) { /* no buffers ready, should never occur */ + dev_err(&vout->video_dev->dev, + "mxc_v4l2out: timer - no queued buffers ready\n"); + goto exit0; + } + g_buf_dq_cnt++; + vout->frame_count++; /* update next buffer */ - if (vout->ic_bypass) { + if (LOAD_3FIELDS(vout)) { + int index_n = index; + int index_p = last_index_n; + vout->ipu_buf_p[vout->next_rdy_ipu_buf] = last_index_n; vout->ipu_buf[vout->next_rdy_ipu_buf] = index; - ret = ipu_update_channel_buffer(vout->display_ch, IPU_INPUT_BUFFER, - vout->next_rdy_ipu_buf, - vout->v4l2_bufs[index].m.offset); + vout->ipu_buf_n[vout->next_rdy_ipu_buf] = index; + ret = ipu_update_channel_buffer(vout->post_proc_ch, + IPU_INPUT_BUFFER, + vout->next_rdy_ipu_buf, + vout->v4l2_bufs[index].m.offset); + ret += ipu_update_channel_buffer(MEM_VDI_PRP_VF_MEM_P, + IPU_INPUT_BUFFER, + vout->next_rdy_ipu_buf, + vout->v4l2_bufs[index_p].m.offset + vout->bytesperline); + ret += ipu_update_channel_buffer(MEM_VDI_PRP_VF_MEM_N, + IPU_INPUT_BUFFER, + vout->next_rdy_ipu_buf, + vout->v4l2_bufs[index_n].m.offset) + vout->bytesperline; + last_index_n = index; } else { - if (LOAD_3FIELDS(vout)) { - int index_n = index; - int index_p = last_index_c; - index = last_index_n; - vout->ipu_buf_p[vout->next_rdy_ipu_buf] = index_p; - vout->ipu_buf[vout->next_rdy_ipu_buf] = last_index_c = index; - vout->ipu_buf_n[vout->next_rdy_ipu_buf] = last_index_n = index_n; - last_index_n = vout->ipu_buf_n[vout->next_rdy_ipu_buf]; - last_index_c = vout->ipu_buf[vout->next_rdy_ipu_buf]; + vout->ipu_buf[vout->next_rdy_ipu_buf] = index; + if (vout->pp_split) { + vout->ipu_buf[!vout->next_rdy_ipu_buf] = index; + /* always left stripe */ ret = ipu_update_channel_buffer(vout->post_proc_ch, - IPU_INPUT_BUFFER, - vout->next_rdy_ipu_buf, - vout->v4l2_bufs[index].m.offset+current_field_offset); - ret += ipu_update_channel_buffer(MEM_VDI_PRP_VF_MEM_P, - IPU_INPUT_BUFFER, - vout->next_rdy_ipu_buf, - vout->v4l2_bufs[index_p].m.offset+aid_field_offset); - ret += ipu_update_channel_buffer(MEM_VDI_PRP_VF_MEM_N, - IPU_INPUT_BUFFER, - vout->next_rdy_ipu_buf, - vout->v4l2_bufs[index_n].m.offset+aid_field_offset); - } else { - vout->ipu_buf[vout->next_rdy_ipu_buf] = index; - if (vout->pp_split) { - vout->ipu_buf[!vout->next_rdy_ipu_buf] = index; - /* always left stripe */ - ret = ipu_update_channel_buffer(vout->post_proc_ch, - IPU_INPUT_BUFFER, - 0,/* vout->next_rdy_ipu_buf,*/ - (vout->v4l2_bufs[index].m.offset) + - vout->pp_left_stripe.input_column + - current_field_offset); - - /* the U/V offset has to be updated inside of IDMAC */ - /* according to stripe offset */ - ret += ipu_update_channel_offset(vout->post_proc_ch, - IPU_INPUT_BUFFER, - vout->v2f.fmt.pix.pixelformat, - vout->v2f.fmt.pix.width, - vout->v2f.fmt.pix.height, - vout->bytesperline, - vout->offset.u_offset, - vout->offset.v_offset, - 0, - vout->pp_left_stripe.input_column + current_field_offset); - - } else - ret = ipu_update_channel_buffer(vout->post_proc_ch, - IPU_INPUT_BUFFER, - vout->next_rdy_ipu_buf, - vout->v4l2_bufs[index].m.offset + - current_field_offset); - } + IPU_INPUT_BUFFER, + 0,/* vout->next_rdy_ipu_buf,*/ + (vout->v4l2_bufs[index].m.offset) + + vout->pp_left_stripe.input_column + + vout->pp_up_stripe.input_column * vout->bytesperline); + + /* the U/V offset has to be updated inside of IDMAC */ + /* according to stripe offset */ + ret += ipu_update_channel_offset(vout->post_proc_ch, + IPU_INPUT_BUFFER, + vout->v2f.fmt.pix.pixelformat, + vout->v2f.fmt.pix.width, + vout->v2f.fmt.pix.height, + vout->bytesperline, + vout->offset.u_offset, + vout->offset.v_offset, + vout->pp_up_stripe.input_column, + vout->pp_left_stripe.input_column); + } else + ret = ipu_update_channel_buffer(vout->post_proc_ch, + IPU_INPUT_BUFFER, + vout->next_rdy_ipu_buf, + vout->v4l2_bufs[index].m.offset); } if (ret < 0) { @@ -521,9 +536,35 @@ static void mxc_v4l2out_timer_handler(unsigned long arg) } /* set next buffer ready */ - if (queue_work(vout->v4l_wq, &vout->timer_work) == 0) { - dev_err(&vout->video_dev->dev, "work was in queue already!\n "); + if (LOAD_3FIELDS(vout)) + ret = ipu_select_multi_vdi_buffer(vout->next_rdy_ipu_buf); + else + ret = ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, + vout->next_rdy_ipu_buf); + if (ret < 0) { + dev_err(&vout->video_dev->dev, + "unable to set IPU buffer ready\n"); + goto exit0; + } + + /* Split mode use buf 0 only, no need swith buf */ + if (!vout->pp_split) + vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf; + + /* Always assume display in double buffers */ + vout->next_disp_ipu_buf = !vout->next_disp_ipu_buf; + + /* Setup timer for next buffer */ + index = peek_next_buf(&vout->ready_q); + if (index != -1) + setup_next_buf_timer(vout, index); + else vout->state = STATE_STREAM_PAUSED; + + if (vout->state == STATE_STREAM_STOPPING) { + if ((vout->ipu_buf[0] == -1) && (vout->ipu_buf[1] == -1)) { + vout->state = STATE_STREAM_OFF; + } } spin_unlock_irqrestore(&g_lock, lock_flags); @@ -540,12 +581,15 @@ static irqreturn_t mxc_v4l2out_work_irq_handler(int irq, void *dev_id) int index; unsigned long lock_flags = 0; vout_data *vout = dev_id; - int pp_out_buf_num = 0; + int pp_out_buf_left_right = 0; int disp_buf_num = 0; int disp_buf_num_next = 1; + int local_buffer = 0; int pp_out_buf_offset = 0; + int pp_out_buf_up_down = 0; int release_buffer = 0; - u32 eba_offset; + u32 eba_offset = 0; + u32 vertical_offset = 0; u16 x_pos; u16 y_pos; int ret = -1; @@ -563,17 +607,37 @@ static irqreturn_t mxc_v4l2out_work_irq_handler(int irq, void *dev_id) if (last_buf != -1) { /* If IC split mode on, update output buffer number */ if (vout->pp_split) { - pp_out_buf_num = vout->pp_split_buf_num & 1;/* left/right stripe */ - disp_buf_num = vout->pp_split_buf_num >> 1; - disp_buf_num_next = ((vout->pp_split_buf_num+2) & 3) >> 1; - if (!pp_out_buf_num) {/* next buffer is right stripe*/ - eba_offset = vout->pp_right_stripe.input_column;/*always right stripe*/ + pp_out_buf_up_down = vout->pp_split_buf_num & 1;/* left/right stripe */ + pp_out_buf_left_right = (vout->pp_split_buf_num >> 1) & 1; /* up/down */ + local_buffer = (vout->pp_split == 1) ? pp_out_buf_up_down : + pp_out_buf_left_right; + disp_buf_num = vout->pp_split_buf_num >> 2; + disp_buf_num_next = + ((vout->pp_split_buf_num + (vout->pp_split << 0x1)) & 7) >> 2; + if ((!pp_out_buf_left_right) || + ((!pp_out_buf_up_down) && (vout->pp_split == 1))) { + if (vout->pp_split == 1) { + eba_offset = ((pp_out_buf_left_right + pp_out_buf_up_down) & 1) ? + vout->pp_right_stripe.input_column : + vout->pp_left_stripe.input_column; + vertical_offset = pp_out_buf_up_down ? + vout->pp_up_stripe.input_column : + vout->pp_down_stripe.input_column; + + } else { + eba_offset = pp_out_buf_left_right ? + vout->pp_left_stripe.input_column : + vout->pp_right_stripe.input_column; + vertical_offset = pp_out_buf_left_right ? + vout->pp_up_stripe.input_column : + vout->pp_down_stripe.input_column; + } + ret = ipu_update_channel_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, - 1, /* right stripe */ + (1 - local_buffer), (vout->v4l2_bufs[vout->ipu_buf[disp_buf_num]].m.offset) - + eba_offset); - + + eba_offset + vertical_offset * vout->bytesperline); ret += ipu_update_channel_offset(vout->post_proc_ch, IPU_INPUT_BUFFER, vout->v2f.fmt.pix.pixelformat, @@ -582,68 +646,78 @@ static irqreturn_t mxc_v4l2out_work_irq_handler(int irq, void *dev_id) vout->bytesperline, vout->offset.u_offset, vout->offset.v_offset, - 0, - vout->pp_right_stripe.input_column); + vertical_offset, + eba_offset); /* select right stripe */ - ret += ipu_select_buffer(vout->post_proc_ch, - IPU_INPUT_BUFFER, 1); + ret += ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, + (1 - local_buffer)); if (ret < 0) dev_err(&vout->video_dev->dev, "unable to set IPU buffer ready\n"); + } - vout->ipu_buf[vout->next_done_ipu_buf] = -1; - vout->next_done_ipu_buf = !vout->next_done_ipu_buf; + /* offset for next buffer's EBA */ + eba_offset = 0; + if (vout->pp_split == 1) { + pp_out_buf_offset = ((vout->pp_split_buf_num >> 1) & 1) ? + vout->pp_left_stripe.output_column : + vout->pp_right_stripe.output_column; - } else /* right stripe is done, run display refresh */ - select_display_buffer(vout, disp_buf_num); + eba_offset = ((vout->pp_split_buf_num & 1) ? + vout->pp_down_stripe.output_column : + vout->pp_up_stripe.output_column); - vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf; + } else { + pp_out_buf_offset = ((vout->pp_split_buf_num >> 1) & 1) ? + vout->pp_right_stripe.output_column : + vout->pp_left_stripe.output_column; + eba_offset = ((vout->pp_split_buf_num >> 1) & 1) ? + vout->pp_down_stripe.output_column : + vout->pp_up_stripe.output_column; + } - /* offset for next buffer's EBA */ - pp_out_buf_offset = pp_out_buf_num ? vout->pp_right_stripe.output_column : - vout->pp_left_stripe.output_column; - eba_offset = 0; if (vout->cur_disp_output == 5) { x_pos = (vout->crop_current.left / 8) * 8; y_pos = vout->crop_current.top; - eba_offset = (vout->xres * y_pos + x_pos) * vout->bpp / 8; + eba_offset += (vout->xres * y_pos + x_pos) * vout->bpp / 8; } + /* next buffer update */ eba_offset = vout->display_bufs[disp_buf_num_next] + - pp_out_buf_offset + eba_offset; + pp_out_buf_offset + eba_offset; ipu_update_channel_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, - pp_out_buf_num, eba_offset); + local_buffer, eba_offset); /* next buffer ready */ - ret = ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, pp_out_buf_num); + ret = ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, local_buffer); - /* next stripe_buffer index 0..3 */ - vout->pp_split_buf_num = (vout->pp_split_buf_num + 1) & 3; + /* next stripe_buffer index 0..7 */ + vout->pp_split_buf_num = (vout->pp_split_buf_num + vout->pp_split) & 0x7; } else { - /* show to display */ - select_display_buffer(vout, vout->next_done_ipu_buf); + disp_buf_num = vout->next_done_ipu_buf; ret += ipu_select_buffer(vout->display_input_ch, IPU_OUTPUT_BUFFER, vout->next_done_ipu_buf); } /* release buffer. For split mode: if second stripe is done */ - release_buffer = vout->pp_split ? pp_out_buf_num : 1; + release_buffer = vout->pp_split ? (!(vout->pp_split_buf_num & 0x3)) : 1; if (release_buffer) { - if ((!INTERLACED_CONTENT(vout)) || (vout->next_done_ipu_buf)) { - g_buf_output_cnt++; - vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE; - queue_buf(&vout->done_q, last_buf); - wake_up_interruptible(&vout->v4l_bufq); - } + select_display_buffer(vout, disp_buf_num); + g_buf_output_cnt++; + vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE; + queue_buf(&vout->done_q, last_buf); + wake_up_interruptible(&vout->v4l_bufq); vout->ipu_buf[vout->next_done_ipu_buf] = -1; if (LOAD_3FIELDS(vout)) { vout->ipu_buf_p[vout->next_done_ipu_buf] = -1; vout->ipu_buf_n[vout->next_done_ipu_buf] = -1; } - vout->next_done_ipu_buf = !vout->next_done_ipu_buf; + /* split mode use buf 0 only, no need switch buf */ + if (!vout->pp_split) + vout->next_done_ipu_buf = !vout->next_done_ipu_buf; } } /* end of last_buf != -1 */ @@ -702,7 +776,6 @@ static int init_VDI_channel(vout_data *vout, ipu_channel_params_t params) static int init_VDI_in_channel_buffer(vout_data *vout, uint32_t in_pixel_fmt, uint16_t in_width, uint16_t in_height, uint32_t stride, - dma_addr_t phyaddr_0, dma_addr_t phyaddr_1, uint32_t u_offset, uint32_t v_offset) { struct device *dev = &vout->video_dev->dev; @@ -710,7 +783,7 @@ static int init_VDI_in_channel_buffer(vout_data *vout, uint32_t in_pixel_fmt, if (ipu_init_channel_buffer(MEM_VDI_PRP_VF_MEM, IPU_INPUT_BUFFER, in_pixel_fmt, in_width, in_height, stride, IPU_ROTATE_NONE, - vout->v4l2_bufs[vout->ipu_buf[0]].m.offset+vout->bytesperline, + vout->v4l2_bufs[vout->ipu_buf[0]].m.offset, vout->v4l2_bufs[vout->ipu_buf[0]].m.offset, u_offset, v_offset) != 0) { dev_err(dev, "Error initializing VDI current input buffer\n"); @@ -721,7 +794,7 @@ static int init_VDI_in_channel_buffer(vout_data *vout, uint32_t in_pixel_fmt, IPU_INPUT_BUFFER, in_pixel_fmt, in_width, in_height, stride, IPU_ROTATE_NONE, - vout->v4l2_bufs[vout->ipu_buf_p[0]].m.offset, + vout->v4l2_bufs[vout->ipu_buf_p[0]].m.offset+vout->bytesperline, vout->v4l2_bufs[vout->ipu_buf_p[0]].m.offset+vout->bytesperline, u_offset, v_offset) != 0) { dev_err(dev, "Error initializing VDI previous input buffer\n"); @@ -731,7 +804,7 @@ static int init_VDI_in_channel_buffer(vout_data *vout, uint32_t in_pixel_fmt, IPU_INPUT_BUFFER, in_pixel_fmt, in_width, in_height, stride, IPU_ROTATE_NONE, - vout->v4l2_bufs[vout->ipu_buf_n[0]].m.offset, + vout->v4l2_bufs[vout->ipu_buf_n[0]].m.offset+vout->bytesperline, vout->v4l2_bufs[vout->ipu_buf_n[0]].m.offset+vout->bytesperline, u_offset, v_offset) != 0) { dev_err(dev, "Error initializing VDI next input buffer\n"); @@ -759,10 +832,7 @@ static int init_VDI(ipu_channel_params_t params, vout_data *vout, params.mem_prp_vf_mem.in_pixel_fmt = vout->v2f.fmt.pix.pixelformat; params.mem_prp_vf_mem.out_width = out_width; params.mem_prp_vf_mem.out_height = out_height; - if (vout->display_ch == ADC_SYS2) - params.mem_prp_vf_mem.out_pixel_fmt = SDC_FG_FB_FORMAT; - else - params.mem_prp_vf_mem.out_pixel_fmt = bpp_to_fmt(fbi); + params.mem_prp_vf_mem.out_pixel_fmt = bpp_to_fmt(fbi); if (init_VDI_channel(vout, params) != 0) { dev_err(dev, "Error init_VDI_channel channel\n"); @@ -775,8 +845,6 @@ static int init_VDI(ipu_channel_params_t params, vout_data *vout, params.mem_prp_vf_mem.in_height, bytes_per_pixel(params.mem_prp_vf_mem. in_pixel_fmt), - vout->v4l2_bufs[vout->ipu_buf[0]].m.offset, - vout->v4l2_bufs[vout->ipu_buf[1]].m.offset, vout->offset.u_offset, vout->offset.v_offset) != 0) { return -EINVAL; @@ -805,7 +873,6 @@ static int init_VDI(ipu_channel_params_t params, vout_data *vout, dev_err(dev, "Error initializing PRP output buffer\n"); return -EINVAL; } - if (ipu_init_channel(MEM_ROT_VF_MEM, NULL) != 0) { dev_err(dev, "Error initializing PP ROT channel\n"); return -EINVAL; @@ -883,14 +950,14 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout, u32 eba_offset; u16 x_pos; u16 y_pos; + dma_addr_t phy_addr0; + dma_addr_t phy_addr1; + eba_offset = 0; x_pos = 0; y_pos = 0; - if (vout->display_ch == ADC_SYS2) - params->mem_pp_mem.out_pixel_fmt = SDC_FG_FB_FORMAT; - else - params->mem_pp_mem.out_pixel_fmt = bpp_to_fmt(fbi); + params->mem_pp_mem.out_pixel_fmt = bpp_to_fmt(fbi); if (vout->cur_disp_output == 5) { x_pos = (vout->crop_current.left / 8) * 8; @@ -907,37 +974,66 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout, params->mem_pp_mem.in_pixel_fmt = vout->v2f.fmt.pix.pixelformat; params->mem_pp_mem.out_width = out_width; params->mem_pp_mem.out_height = out_height; - params->mem_pp_mem.out_resize_ratio = 0; /* 0 means unused */ - + params->mem_pp_mem.outh_resize_ratio = 0; /* 0 means unused */ + params->mem_pp_mem.outv_resize_ratio = 0; /* 0 means unused */ /* split IC by two stripes, the by pass is impossible*/ if (vout->pp_split) { - ipu_calc_stripes_sizes( - params->mem_pp_mem.in_width, /* input frame width;>1 */ - params->mem_pp_mem.out_width, /* output frame width; >1 */ - ipu_ic_out_max_width_size, - (((unsigned long long)1) << 32), /* 32bit for fractional*/ - 1, /* equal stripes */ - params->mem_pp_mem.in_pixel_fmt, - params->mem_pp_mem.out_pixel_fmt, - &(vout->pp_left_stripe), - &(vout->pp_right_stripe)); - - vout->pp_left_stripe.input_column = vout->pp_left_stripe.input_column * + vout->pp_left_stripe.input_column = 0; + vout->pp_left_stripe.output_column = 0; + vout->pp_right_stripe.input_column = 0; + vout->pp_right_stripe.output_column = 0; + vout->pp_up_stripe.input_column = 0; + vout->pp_up_stripe.output_column = 0; + vout->pp_down_stripe.input_column = 0; + vout->pp_down_stripe.output_column = 0; + if (vout->pp_split != 3) { + ipu_calc_stripes_sizes( + params->mem_pp_mem.in_width, /* input frame width;>1 */ + params->mem_pp_mem.out_width, /* output frame width; >1 */ + ipu_ic_out_max_width_size, + (((unsigned long long)1) << 32), /* 32bit for fractional*/ + 1, /* equal stripes */ + params->mem_pp_mem.in_pixel_fmt, + params->mem_pp_mem.out_pixel_fmt, + &(vout->pp_left_stripe), + &(vout->pp_right_stripe)); + + vout->pp_left_stripe.input_column = vout->pp_left_stripe.input_column * fmt_to_bpp(vout->v2f.fmt.pix.pixelformat) / 8; - vout->pp_left_stripe.output_column = vout->pp_left_stripe.output_column * + vout->pp_left_stripe.output_column = vout->pp_left_stripe.output_column * fmt_to_bpp(params->mem_pp_mem.out_pixel_fmt) / 8; - vout->pp_right_stripe.input_column = vout->pp_right_stripe.input_column * + vout->pp_right_stripe.input_column = vout->pp_right_stripe.input_column * fmt_to_bpp(vout->v2f.fmt.pix.pixelformat) / 8; - vout->pp_right_stripe.output_column = vout->pp_right_stripe.output_column * + vout->pp_right_stripe.output_column = vout->pp_right_stripe.output_column * fmt_to_bpp(params->mem_pp_mem.out_pixel_fmt) / 8; + /* updare parameters */ params->mem_pp_mem.in_width = vout->pp_left_stripe.input_width; params->mem_pp_mem.out_width = vout->pp_left_stripe.output_width; out_width = vout->pp_left_stripe.output_width; /* for using in ic_init*/ - params->mem_pp_mem.out_resize_ratio = vout->pp_left_stripe.irr; - + params->mem_pp_mem.outh_resize_ratio = vout->pp_left_stripe.irr; + } + if (vout->pp_split != 2) { + ipu_calc_stripes_sizes( + params->mem_pp_mem.in_height, /* input frame width;>1 */ + params->mem_pp_mem.out_height, /* output frame width; >1 */ + ipu_ic_out_max_height_size, + (((unsigned long long)1) << 32),/* 32bit for fractional */ + 1, /* equal stripes */ + params->mem_pp_mem.in_pixel_fmt, + params->mem_pp_mem.out_pixel_fmt, + &(vout->pp_up_stripe), + &(vout->pp_down_stripe)); + vout->pp_down_stripe.output_column = vout->pp_down_stripe.output_column * out_stride; + vout->pp_up_stripe.output_column = vout->pp_up_stripe.output_column * out_stride; + params->mem_pp_mem.outv_resize_ratio = vout->pp_up_stripe.irr; + params->mem_pp_mem.in_height = vout->pp_up_stripe.input_width;/*height*/ + out_height = vout->pp_up_stripe.output_width;/*height*/ + if (vout->pp_split == 3) + vout->pp_split = 2;/*2 vertical stripe as two horizontal stripes */ + } vout->pp_split_buf_num = 0; } @@ -946,6 +1042,12 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout, return -EINVAL; } + /* always enable double buffer */ + phy_addr0 = vout->v4l2_bufs[vout->ipu_buf[0]].m.offset; + if (vout->ipu_buf[1] == -1) + phy_addr1 = phy_addr0; + else + phy_addr1 = vout->v4l2_bufs[vout->ipu_buf[1]].m.offset; if (ipu_init_channel_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, params->mem_pp_mem.in_pixel_fmt, @@ -955,8 +1057,8 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout, bytes_per_pixel(params->mem_pp_mem. in_pixel_fmt), IPU_ROTATE_NONE, - vout->v4l2_bufs[vout->ipu_buf[0]].m.offset, - vout->v4l2_bufs[vout->ipu_buf[1]].m.offset, + phy_addr0, + phy_addr1, vout->offset.u_offset, vout->offset.v_offset) != 0) { dev_err(dev, "Error initializing PP input buffer\n"); @@ -1048,20 +1150,27 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout, ipu_update_channel_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0, vout->v4l2_bufs[vout->ipu_buf[0]].m.offset + - vout->pp_left_stripe.input_column); + vout->pp_left_stripe.input_column + + vout->pp_up_stripe.input_column * vout->bytesperline); + + ipu_update_channel_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 1, vout->v4l2_bufs[vout->ipu_buf[0]].m.offset + - vout->pp_right_stripe.input_column); + vout->pp_right_stripe.input_column + + vout->pp_up_stripe.input_column * vout->bytesperline); + ipu_update_channel_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 0, vout->display_bufs[0] + eba_offset + - vout->pp_left_stripe.output_column); + vout->pp_left_stripe.output_column + + vout->pp_up_stripe.output_column); ipu_update_channel_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 1, vout->display_bufs[0] + eba_offset + - vout->pp_right_stripe.output_column); + vout->pp_right_stripe.output_column + + vout->pp_up_stripe.output_column); } return 0; @@ -1084,8 +1193,8 @@ static int mxc_v4l2out_streamon(vout_data * vout) registered_fb[vout->output_fb_num[vout->cur_disp_output]]; u16 out_width; u16 out_height; - bool use_direct_adc = false; mm_segment_t old_fs; + unsigned int ipu_ch = CHAN_NONE; int rc = 0; dev_dbg(dev, "mxc_v4l2out_streamon: field format=%d\n", @@ -1107,241 +1216,132 @@ static int mxc_v4l2out_streamon(vout_data * vout) return -EINVAL; } + /* + * params init, check whether operation exceed the IC limitation: + * whether split mode used ( ipu version >= ipuv3 only) + */ g_irq_cnt = g_buf_output_cnt = g_buf_q_cnt = g_buf_dq_cnt = 0; out_width = vout->crop_current.width; out_height = vout->crop_current.height; + vout->disp_buf_num = 0; vout->next_done_ipu_buf = 0; - vout->next_rdy_ipu_buf = 1; + vout->next_rdy_ipu_buf = vout->next_disp_ipu_buf = 1; + vout->fb_blank = 0; vout->pp_split = 0; - - if (!INTERLACED_CONTENT(vout)) { - vout->next_done_ipu_buf = vout->next_rdy_ipu_buf = 0; - vout->ipu_buf[0] = dequeue_buf(&vout->ready_q); + ipu_ic_out_max_height_size = 1024; #ifdef CONFIG_MXC_IPU_V1 + if (cpu_is_mx35()) ipu_ic_out_max_width_size = 800; + else + ipu_ic_out_max_width_size = 720; #else - ipu_ic_out_max_width_size = 1024; + ipu_ic_out_max_width_size = 1024; #endif + if ((out_width > ipu_ic_out_max_width_size) || + (out_height > ipu_ic_out_max_height_size)) + vout->pp_split = 4; + if (!INTERLACED_CONTENT(vout)) { + vout->ipu_buf[0] = dequeue_buf(&vout->ready_q); /* split IC by two stripes, the by pass is impossible*/ if ((out_width != vout->v2f.fmt.pix.width || out_height != vout->v2f.fmt.pix.height) && - out_width > ipu_ic_out_max_width_size) { - vout->pp_split = 1; + vout->pp_split) { + vout->next_done_ipu_buf = vout->next_rdy_ipu_buf = 0; vout->ipu_buf[1] = vout->ipu_buf[0]; vout->frame_count = 1; + if ((out_width > ipu_ic_out_max_width_size) && + (out_height > ipu_ic_out_max_height_size)) + vout->pp_split = 1; /*4 stripes*/ + else if (!(out_height > ipu_ic_out_max_height_size)) + vout->pp_split = 2; /*two horizontal stripes */ + else + vout->pp_split = 3; /*2 vertical stripes*/ } else { - vout->ipu_buf[1] = dequeue_buf(&vout->ready_q); - vout->frame_count = 2; + vout->ipu_buf[1] = -1; + vout->frame_count = 1; } } else if (!LOAD_3FIELDS(vout)) { vout->ipu_buf[0] = dequeue_buf(&vout->ready_q); vout->ipu_buf[1] = -1; vout->frame_count = 1; - last_index_n = vout->ipu_buf[0]; } else { vout->ipu_buf_p[0] = dequeue_buf(&vout->ready_q); - vout->ipu_buf[0] = vout->ipu_buf_p[0]; - vout->ipu_buf_n[0] = dequeue_buf(&vout->ready_q); + vout->ipu_buf[0] = dequeue_buf(&vout->ready_q); + vout->ipu_buf_n[0] = vout->ipu_buf[0]; vout->ipu_buf_p[1] = -1; vout->ipu_buf[1] = -1; vout->ipu_buf_n[1] = -1; - last_index_c = vout->ipu_buf[0]; last_index_n = vout->ipu_buf_n[0]; vout->frame_count = 2; } - /* Init Display Channel */ -#ifdef CONFIG_FB_MXC_ASYNC_PANEL - if (vout->cur_disp_output < DISP3) { - vout->work_irq = IPU_IRQ_PP_IN_EOF; - ipu_clear_irq(vout->work_irq); - ipu_request_irq(vout->work_irq, - mxc_v4l2out_work_irq_handler, - 0, vout->video_dev->name, vout); - mxcfb_set_refresh_mode(fbi, MXCFB_REFRESH_OFF, 0); - fbi = NULL; - if (ipu_can_rotate_in_place(vout->rotate)) { - dev_dbg(dev, "Using PP direct to ADC channel\n"); - use_direct_adc = true; - vout->display_ch = MEM_PP_ADC; - vout->post_proc_ch = MEM_PP_ADC; - - memset(¶ms, 0, sizeof(params)); - params.mem_pp_adc.in_width = vout->v2f.fmt.pix.width; - params.mem_pp_adc.in_height = vout->v2f.fmt.pix.height; - params.mem_pp_adc.in_pixel_fmt = - vout->v2f.fmt.pix.pixelformat; - params.mem_pp_adc.out_width = out_width; - params.mem_pp_adc.out_height = out_height; - params.mem_pp_adc.out_pixel_fmt = SDC_FG_FB_FORMAT; -#ifdef CONFIG_FB_MXC_EPSON_PANEL - params.mem_pp_adc.out_left = - 2 + vout->crop_current.left; -#else - params.mem_pp_adc.out_left = - 12 + vout->crop_current.left; -#endif - params.mem_pp_adc.out_top = vout->crop_current.top; - if (ipu_init_channel(vout->post_proc_ch, ¶ms) != 0) { - dev_err(dev, "Error initializing PP chan\n"); - return -EINVAL; - } - if (ipu_init_channel_buffer(vout->post_proc_ch, - IPU_INPUT_BUFFER, - params.mem_pp_adc. - in_pixel_fmt, - params.mem_pp_adc.in_width, - params.mem_pp_adc.in_height, - vout->v2f.fmt.pix. - bytesperline / - bytes_per_pixel(params. - mem_pp_adc. - in_pixel_fmt), - vout->rotate, - vout->v4l2_bufs[vout->ipu_buf[0]].m.offset, - vout->v4l2_bufs[vout->ipu_buf[1]].m.offset, - vout->offset.u_offset, - vout->offset.v_offset) != - 0) { - dev_err(dev, "Error initializing PP in buf\n"); - return -EINVAL; - } - - if (ipu_init_channel_buffer(vout->post_proc_ch, - IPU_OUTPUT_BUFFER, - params.mem_pp_adc. - out_pixel_fmt, out_width, - out_height, out_width, - vout->rotate, 0, 0, 0, - 0) != 0) { - dev_err(dev, - "Error initializing PP output buffer\n"); - return -EINVAL; - } - - } else { - dev_dbg(dev, "Using ADC SYS2 channel\n"); - vout->display_ch = ADC_SYS2; - vout->post_proc_ch = MEM_PP_MEM; - - if (vout->display_bufs[0]) { - mxc_free_buffers(vout->display_bufs, - vout->display_bufs_vaddr, - 2, vout->display_buf_size); - } - - vout->display_buf_size = vout->crop_current.width * - vout->crop_current.height * - fmt_to_bpp(SDC_FG_FB_FORMAT) / 8; - mxc_allocate_buffers(vout->display_bufs, - vout->display_bufs_vaddr, - 2, vout->display_buf_size); - - memset(¶ms, 0, sizeof(params)); - params.adc_sys2.disp = vout->cur_disp_output; - params.adc_sys2.ch_mode = WriteTemplateNonSeq; -#ifdef CONFIG_FB_MXC_EPSON_PANEL - params.adc_sys2.out_left = 2 + vout->crop_current.left; -#else - params.adc_sys2.out_left = 12 + vout->crop_current.left; -#endif - params.adc_sys2.out_top = vout->crop_current.top; - if (ipu_init_channel(ADC_SYS2, ¶ms) < 0) - return -EINVAL; - - if (ipu_init_channel_buffer(vout->display_ch, - IPU_INPUT_BUFFER, - SDC_FG_FB_FORMAT, - out_width, out_height, - out_width, IPU_ROTATE_NONE, - vout->display_bufs[0], - vout->display_bufs[1], 0, - 0) != 0) { - dev_err(dev, - "Error initializing SDC FG buffer\n"); - return -EINVAL; - } - } - } else -#endif - { /* Use SDC */ - unsigned int ipu_ch = CHAN_NONE; - - dev_dbg(dev, "Using SDC channel\n"); - - if (INTERLACED_CONTENT(vout)) - vout->work_irq = IPU_IRQ_PRP_VF_OUT_EOF; - else - vout->work_irq = IPU_IRQ_PP_IN_EOF; - - /* - * Bypass IC if resizing and rotation are not needed - * Meanwhile, apply IC bypass to SDC only - */ - fbvar = fbi->var; - vout->xres = fbvar.xres; - vout->yres = fbvar.yres; - - if (vout->cur_disp_output == 3 || vout->cur_disp_output == 5) { - fbvar.bits_per_pixel = 16; + /* + * Bypass IC if resizing and rotation are not needed + * Meanwhile, apply IC bypass to SDC only + */ + fbvar = fbi->var; + vout->xres = fbvar.xres; + vout->yres = fbvar.yres; + + if (vout->cur_disp_output == 3 || vout->cur_disp_output == 5) { + fbvar.bits_per_pixel = 16; + if (vout->cur_disp_output == 3) { + /* Only set YUV for the first display. The second display can + * only work in RGB */ if (format_is_yuv(vout->v2f.fmt.pix.pixelformat)) fbvar.nonstd = IPU_PIX_FMT_UYVY; else fbvar.nonstd = 0; - if (vout->cur_disp_output == 3) { - fbvar.xres = out_width; - fbvar.yres = out_height; - vout->xres = fbvar.xres; - vout->yres = fbvar.yres; - } - fbvar.xres_virtual = fbvar.xres; - fbvar.yres_virtual = fbvar.yres * 2; + fbvar.xres = out_width; + fbvar.yres = out_height; + vout->xres = fbvar.xres; + vout->yres = fbvar.yres; } - if (out_width == vout->v2f.fmt.pix.width && - out_height == vout->v2f.fmt.pix.height && - vout->xres == out_width && - vout->yres == out_height && - ipu_can_rotate_in_place(vout->rotate)) { - vout->ic_bypass = 1; - } else { - vout->ic_bypass = 0; - } + fbvar.xres_virtual = fbvar.xres; + fbvar.yres_virtual = fbvar.yres * 2; + } + + if (out_width == vout->v2f.fmt.pix.width && + out_height == vout->v2f.fmt.pix.height && + vout->xres == out_width && + vout->yres == out_height && + ipu_can_rotate_in_place(vout->rotate) && + (vout->bytesperline == + bytes_per_pixel(vout->v2f.fmt.pix.pixelformat) * out_width) && + !INTERLACED_CONTENT(vout)) { + vout->ic_bypass = 1; + } else { + vout->ic_bypass = 0; + } #ifdef CONFIG_MXC_IPU_V1 - /* IPUv1 needs IC to do CSC */ - if (format_is_yuv(vout->v2f.fmt.pix.pixelformat) != - format_is_yuv(bpp_to_fmt(fbi))) - vout->ic_bypass = 0; + /* IPUv1 needs IC to do CSC */ + if (format_is_yuv(vout->v2f.fmt.pix.pixelformat) != + format_is_yuv(bpp_to_fmt(fbi))) + vout->ic_bypass = 0; #endif - /* We are using IC to do input cropping */ - if (vout->queue_buf_paddr[vout->ipu_buf[0]] != - vout->v4l2_bufs[vout->ipu_buf[0]].m.offset || - vout->queue_buf_paddr[vout->ipu_buf[1]] != - vout->v4l2_bufs[vout->ipu_buf[1]].m.offset) - vout->ic_bypass = 0; - - if (fbi->fbops->fb_ioctl) { - old_fs = get_fs(); - set_fs(KERNEL_DS); - fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_IPU_CHAN, - (unsigned long)&ipu_ch); - set_fs(old_fs); - } + if (fbi->fbops->fb_ioctl) { + old_fs = get_fs(); + set_fs(KERNEL_DS); + fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_IPU_CHAN, + (unsigned long)&ipu_ch); + set_fs(old_fs); + } - if (ipu_ch == CHAN_NONE) { - dev_err(dev, "Can not get display ipu channel\n"); - return -EINVAL; - } + if (ipu_ch == CHAN_NONE) { + dev_err(dev, "Can not get display ipu channel\n"); + return -EINVAL; + } - vout->display_ch = ipu_ch; + vout->display_ch = ipu_ch; - if (vout->ic_bypass) { - pr_debug("Bypassing IC\n"); - vout->work_irq = -1; - switch (vout->v2f.fmt.pix.pixelformat) { + if (vout->ic_bypass) { + pr_debug("Bypassing IC\n"); + vout->pp_split = 0; + switch (vout->v2f.fmt.pix.pixelformat) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: case V4L2_PIX_FMT_NV12: @@ -1353,87 +1353,80 @@ static int mxc_v4l2out_streamon(vout_data * vout) default: fbvar.bits_per_pixel = 8* bytes_per_pixel(vout->v2f.fmt.pix.pixelformat); - } - fbvar.nonstd = vout->v2f.fmt.pix.pixelformat; } + fbvar.nonstd = vout->v2f.fmt.pix.pixelformat; + } - fbvar.activate |= FB_ACTIVATE_FORCE; - fb_set_var(fbi, &fbvar); + /* Init display channel through fb API */ + fbvar.activate |= FB_ACTIVATE_FORCE; + fb_set_var(fbi, &fbvar); - if (fbi->fbops->fb_ioctl && vout->display_ch == MEM_FG_SYNC) { - fb_pos.x = vout->crop_current.left; - fb_pos.y = vout->crop_current.top; - old_fs = get_fs(); - set_fs(KERNEL_DS); - fbi->fbops->fb_ioctl(fbi, MXCFB_SET_OVERLAY_POS, - (unsigned long)&fb_pos); - set_fs(old_fs); - } + if (fbi->fbops->fb_ioctl && vout->display_ch == MEM_FG_SYNC) { + fb_pos.x = vout->crop_current.left; + fb_pos.y = vout->crop_current.top; + old_fs = get_fs(); + set_fs(KERNEL_DS); + fbi->fbops->fb_ioctl(fbi, MXCFB_SET_OVERLAY_POS, + (unsigned long)&fb_pos); + set_fs(old_fs); + } + + vout->display_bufs[1] = fbi->fix.smem_start; + vout->display_bufs[0] = fbi->fix.smem_start + + (fbi->fix.line_length * vout->yres); + vout->display_buf_size = vout->xres * + vout->yres * fbi->var.bits_per_pixel / 8; + + /* fill black color for init fb, we assume fb has double buffer*/ + if (format_is_yuv(vout->v2f.fmt.pix.pixelformat)) { + int i; - vout->display_bufs[1] = fbi->fix.smem_start; - vout->display_bufs[0] = fbi->fix.smem_start + - (fbi->fix.line_length * vout->yres); - vout->display_buf_size = vout->xres * - vout->yres * fbi->var.bits_per_pixel / 8; - - /* fill black color for init fb, we assume fb has double buffer*/ - if (format_is_yuv(vout->v2f.fmt.pix.pixelformat)) { - int i; - - if ((vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) || - (vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) || - (!vout->ic_bypass)) { - short * tmp = (short *) fbi->screen_base; - short color; - if (vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) - color = 0x8000; - else - color = 0x80; - for (i = 0; i < (fbi->fix.line_length * fbi->var.yres_virtual)/2; + if ((vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) || + (vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) || + (!vout->ic_bypass)) { + short * tmp = (short *) fbi->screen_base; + short color; + if (vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) + color = 0x8000; + else + color = 0x80; + for (i = 0; i < (fbi->fix.line_length * fbi->var.yres_virtual)/2; i++, tmp++) - *tmp = color; - } else if ((vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) || + *tmp = color; + } else if ((vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) || (vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) || (vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12)) { - char * base = (char *)fbi->screen_base; - int j, screen_size = fbi->var.xres * fbi->var.yres; - - for (j = 0; j < 2; j++) { - memset(base, 0, screen_size); - base += screen_size; - for (i = 0; i < screen_size/2; i++, base++) - *base = 0x80; - } - } else if (vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) { - char * base = (char *)fbi->screen_base; - int j, screen_size = fbi->var.xres * fbi->var.yres; - - for (j = 0; j < 2; j++) { - memset(base, 0, screen_size); - base += screen_size; - for (i = 0; i < screen_size; i++, base++) - *base = 0x80; - } + char * base = (char *)fbi->screen_base; + int j, screen_size = fbi->var.xres * fbi->var.yres; + + for (j = 0; j < 2; j++) { + memset(base, 0, screen_size); + base += screen_size; + for (i = 0; i < screen_size/2; i++, base++) + *base = 0x80; + } + } else if (vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) { + char * base = (char *)fbi->screen_base; + int j, screen_size = fbi->var.xres * fbi->var.yres; + + for (j = 0; j < 2; j++) { + memset(base, 0, screen_size); + base += screen_size; + for (i = 0; i < screen_size; i++, base++) + *base = 0x80; } - } else - memset(fbi->screen_base, 0x0, - fbi->fix.line_length * fbi->var.yres_virtual); - - if (INTERLACED_CONTENT(vout)) - vout->post_proc_ch = MEM_VDI_PRP_VF_MEM; - else - vout->post_proc_ch = MEM_PP_MEM; - - if (!vout->ic_bypass) { - ipu_clear_irq(vout->work_irq); - ipu_request_irq(vout->work_irq, - mxc_v4l2out_work_irq_handler, - 0, vout->video_dev->name, vout); } - } + } else + memset(fbi->screen_base, 0x0, + fbi->fix.line_length * fbi->var.yres_virtual); + + if (INTERLACED_CONTENT(vout)) + vout->post_proc_ch = MEM_VDI_PRP_VF_MEM; + else if (!vout->ic_bypass) + vout->post_proc_ch = MEM_PP_MEM; - /* Init PP */ - if (use_direct_adc == false && !vout->ic_bypass) { + /* Init IC channel */ + if (!vout->ic_bypass) { if (vout->rotate >= IPU_ROTATE_90_RIGHT) { out_width = vout->crop_current.height; out_height = vout->crop_current.width; @@ -1441,7 +1434,11 @@ static int mxc_v4l2out_streamon(vout_data * vout) vout->display_input_ch = vout->post_proc_ch; memset(¶ms, 0, sizeof(params)); if (INTERLACED_CONTENT(vout)) { - rc = init_VDI(params, vout, dev, fbi, out_width, out_height); + if (vout->pp_split) { + dev_err(&vout->video_dev->dev, "VDI split has not supported yet.\n"); + return -1; + } else + rc = init_VDI(params, vout, dev, fbi, out_width, out_height); } else { rc = init_PP(¶ms, vout, dev, fbi, out_width, out_height); } @@ -1449,52 +1446,79 @@ static int mxc_v4l2out_streamon(vout_data * vout) return rc; } + if (!vout->ic_bypass) { + switch (vout->display_input_ch) { + case MEM_PP_MEM: + vout->work_irq = IPU_IRQ_PP_OUT_EOF; + break; + case MEM_VDI_PRP_VF_MEM: + vout->work_irq = IPU_IRQ_PRP_VF_OUT_EOF; + break; + case MEM_ROT_VF_MEM: + vout->work_irq = IPU_IRQ_PRP_VF_ROT_OUT_EOF; + break; + case MEM_ROT_PP_MEM: + vout->work_irq = IPU_IRQ_PP_ROT_OUT_EOF; + break; + default: + dev_err(&vout->video_dev->dev, + "not support channel, should not be here\n"); + } + } else + vout->work_irq = -1; + + if (!vout->ic_bypass && (vout->work_irq > 0)) { + ipu_clear_irq(vout->work_irq); + ipu_request_irq(vout->work_irq, + mxc_v4l2out_work_irq_handler, + 0, vout->video_dev->name, vout); + } + vout->state = STATE_STREAM_PAUSED; - if (use_direct_adc == false) { - if (fbi) { - acquire_console_sem(); - fb_blank(fbi, FB_BLANK_UNBLANK); - release_console_sem(); - } else { - ipu_enable_channel(vout->display_ch); - } - if (!vout->ic_bypass) { + /* Enable display and IC channels */ + if (fbi) { + acquire_console_sem(); + fb_blank(fbi, FB_BLANK_UNBLANK); + release_console_sem(); + } else { + ipu_enable_channel(vout->display_ch); + } + if (!vout->ic_bypass) { #ifndef CONFIG_MXC_IPU_V1 - ipu_enable_channel(vout->post_proc_ch); + ipu_enable_channel(vout->post_proc_ch); #endif - if (LOAD_3FIELDS(vout)) { - ipu_enable_channel(MEM_VDI_PRP_VF_MEM_P); - ipu_enable_channel(MEM_VDI_PRP_VF_MEM_N); - ipu_select_multi_vdi_buffer(0); - } else if (INTERLACED_CONTENT(vout)) { - ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0); - } else { - ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0); - if (!vout->pp_split) - ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 1); - } - ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 0); - ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 1); + if (LOAD_3FIELDS(vout)) { + ipu_enable_channel(MEM_VDI_PRP_VF_MEM_P); + ipu_enable_channel(MEM_VDI_PRP_VF_MEM_N); + ipu_select_multi_vdi_buffer(0); + } else + ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0); + ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 0); + ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 1); #ifdef CONFIG_MXC_IPU_V1 - ipu_enable_channel(vout->post_proc_ch); + ipu_enable_channel(vout->post_proc_ch); #endif - } else { - ipu_update_channel_buffer(vout->display_ch, + } else { + ipu_update_channel_buffer(vout->display_ch, IPU_INPUT_BUFFER, 0, vout->v4l2_bufs[vout->ipu_buf[0]].m.offset); - ipu_update_channel_buffer(vout->display_ch, - IPU_INPUT_BUFFER, - 1, vout->v4l2_bufs[vout->ipu_buf[1]].m.offset); - ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER, 0); - ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER, 1); - queue_work(vout->v4l_wq, &vout->timer_work); - } - } else { - ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0); - ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 1); - ipu_enable_channel(vout->post_proc_ch); + if (vout->offset.u_offset || vout->offset.v_offset) + /* only update u/v offset */ + ipu_update_channel_offset(vout->display_ch, + IPU_INPUT_BUFFER, + vout->v2f.fmt.pix.pixelformat, + vout->v2f.fmt.pix.width, + vout->v2f.fmt.pix.height, + vout->bytesperline, + vout->offset.u_offset, + vout->offset.v_offset, + 0, + 0); + ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER, 0); + queue_work(vout->v4l_wq, &vout->icbypass_work); } + vout->start_jiffies = jiffies; msleep(1); @@ -1529,7 +1553,8 @@ static int mxc_v4l2out_streamoff(vout_data * vout) if (!vout->ic_bypass) ipu_free_irq(vout->work_irq, vout); - cancel_work_sync(&vout->timer_work); + if (vout->ic_bypass) + cancel_work_sync(&vout->icbypass_work); spin_lock_irqsave(&g_lock, lockflag); @@ -1556,9 +1581,21 @@ static int mxc_v4l2out_streamoff(vout_data * vout) } } - if (vout->post_proc_ch == MEM_PP_MEM || + if (vout->ic_bypass) { + fbi->var.activate |= FB_ACTIVATE_FORCE; + fb_set_var(fbi, &fbi->var); + + if (vout->display_ch == MEM_FG_SYNC) { + acquire_console_sem(); + fb_blank(fbi, FB_BLANK_POWERDOWN); + release_console_sem(); + } + + vout->display_bufs[0] = 0; + vout->display_bufs[1] = 0; + } else if (vout->post_proc_ch == MEM_PP_MEM || vout->post_proc_ch == MEM_PRP_VF_MEM) { - /* SDC or ADC with Rotation */ + /* SDC with Rotation */ if (!ipu_can_rotate_in_place(vout->rotate)) { ipu_unlink_channels(MEM_PP_MEM, MEM_ROT_PP_MEM); ipu_disable_channel(MEM_ROT_PP_MEM, true); @@ -1571,28 +1608,23 @@ static int mxc_v4l2out_streamoff(vout_data * vout) } ipu_disable_channel(MEM_PP_MEM, true); - if (vout->display_ch == ADC_SYS2 || - vout->display_ch == MEM_FG_SYNC) { - ipu_disable_channel(vout->display_ch, true); - ipu_uninit_channel(vout->display_ch); - } else { - fbi->var.activate |= FB_ACTIVATE_FORCE; - fb_set_var(fbi, &fbi->var); + fbi->var.activate |= FB_ACTIVATE_FORCE; + fb_set_var(fbi, &fbi->var); - if (vout->display_ch == MEM_FG_SYNC) { - acquire_console_sem(); - fb_blank(fbi, FB_BLANK_POWERDOWN); - release_console_sem(); - } - - vout->display_bufs[0] = 0; - vout->display_bufs[1] = 0; + if (vout->display_ch == MEM_FG_SYNC) { + acquire_console_sem(); + fb_blank(fbi, FB_BLANK_POWERDOWN); + release_console_sem(); } + vout->display_bufs[0] = 0; + vout->display_bufs[1] = 0; + ipu_uninit_channel(MEM_PP_MEM); if (!ipu_can_rotate_in_place(vout->rotate)) ipu_uninit_channel(MEM_ROT_PP_MEM); - } else if (INTERLACED_CONTENT(vout) && (vout->post_proc_ch == MEM_VDI_PRP_VF_MEM)) { + } else if (INTERLACED_CONTENT(vout) && + (vout->post_proc_ch == MEM_VDI_PRP_VF_MEM)) { if (!ipu_can_rotate_in_place(vout->rotate)) { ipu_unlink_channels(MEM_VDI_PRP_VF_MEM, MEM_ROT_VF_MEM); @@ -1606,32 +1638,32 @@ static int mxc_v4l2out_streamoff(vout_data * vout) } ipu_disable_channel(MEM_VDI_PRP_VF_MEM, true); + if (LOAD_3FIELDS(vout)) { + ipu_disable_channel(MEM_VDI_PRP_VF_MEM_P, true); + ipu_disable_channel(MEM_VDI_PRP_VF_MEM_N, true); + } - if (vout->display_ch == ADC_SYS2 || - vout->display_ch == MEM_FG_SYNC) { - ipu_disable_channel(vout->display_ch, true); - ipu_uninit_channel(vout->display_ch); - } else { - fbi->var.activate |= FB_ACTIVATE_FORCE; - fb_set_var(fbi, &fbi->var); + fbi->var.activate |= FB_ACTIVATE_FORCE; + fb_set_var(fbi, &fbi->var); - if (vout->display_ch == MEM_FG_SYNC) { - acquire_console_sem(); - fb_blank(fbi, FB_BLANK_POWERDOWN); - release_console_sem(); - } - - vout->display_bufs[0] = 0; - vout->display_bufs[1] = 0; + if (vout->display_ch == MEM_FG_SYNC) { + acquire_console_sem(); + fb_blank(fbi, FB_BLANK_POWERDOWN); + release_console_sem(); } + vout->display_bufs[0] = 0; + vout->display_bufs[1] = 0; + ipu_uninit_channel(MEM_VDI_PRP_VF_MEM); + if (LOAD_3FIELDS(vout)) { + ipu_uninit_channel(MEM_VDI_PRP_VF_MEM_P); + ipu_uninit_channel(MEM_VDI_PRP_VF_MEM_N); + } if (!ipu_can_rotate_in_place(vout->rotate)) ipu_uninit_channel(MEM_ROT_VF_MEM); - } else { /* ADC Direct */ - ipu_disable_channel(MEM_PP_ADC, true); - ipu_uninit_channel(MEM_PP_ADC); } + vout->ready_q.head = vout->ready_q.tail = 0; vout->done_q.head = vout->done_q.tail = 0; for (i = 0; i < vout->buffer_cnt; i++) { @@ -1640,23 +1672,9 @@ static int mxc_v4l2out_streamoff(vout_data * vout) vout->v4l2_bufs[i].timestamp.tv_usec = 0; } + vout->post_proc_ch = CHAN_NONE; vout->state = STATE_STREAM_OFF; -#ifdef CONFIG_FB_MXC_ASYNC_PANEL - if (vout->cur_disp_output < DISP3) { - if (vout->display_bufs[0] != 0) { - mxc_free_buffers(vout->display_bufs, - vout->display_bufs_vaddr, 2, - vout->display_buf_size); - } - - mxcfb_set_refresh_mode(registered_fb - [vout-> - output_fb_num[vout->cur_disp_output]], - MXCFB_REFRESH_PARTIAL, 0); - } -#endif - return retval; } @@ -1751,7 +1769,6 @@ static int mxc_v4l2out_s_fmt(vout_data * vout, struct v4l2_format *f) dev_err(&vout->video_dev->dev, "De-interlacing not supported in this device!\n"); vout->field_fmt = V4L2_FIELD_NONE; - break; case V4L2_FIELD_INTERLACED_BT: dev_err(&vout->video_dev->dev, "V4L2_FIELD_INTERLACED_BT field format not supported yet!\n"); @@ -1898,7 +1915,7 @@ static int mxc_v4l2out_open(struct file *file) goto oops; } - INIT_WORK(&vout->timer_work, timer_work_func); + INIT_WORK(&vout->icbypass_work, icbypass_work_func); } file->private_data = dev; @@ -2284,12 +2301,8 @@ mxc_v4l2out_do_ioctl(struct file *file, break; } - if (output->index < 3) { - *output = mxc_outputs[MXC_V4L2_OUT_2_ADC]; - output->name[4] = '0' + output->index; - } else { + if (output->index >= 3) *output = mxc_outputs[MXC_V4L2_OUT_2_SDC]; - } break; } case VIDIOC_G_OUTPUT: diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.h b/drivers/media/video/mxc/output/mxc_v4l2_output.h index 0dd8eb0076a9..c26194f5ff90 100644 --- a/drivers/media/video/mxc/output/mxc_v4l2_output.h +++ b/drivers/media/video/mxc/output/mxc_v4l2_output.h @@ -39,7 +39,6 @@ #define MXC_V4L2_OUT_NUM_OUTPUTS 6 #define MXC_V4L2_OUT_2_SDC 0 -#define MXC_V4L2_OUT_2_ADC 1 typedef struct { @@ -80,7 +79,9 @@ typedef struct _vout_data { struct timer_list output_timer; struct workqueue_struct *v4l_wq; - struct work_struct timer_work; + struct work_struct icbypass_work; + int disp_buf_num; + int fb_blank; unsigned long start_jiffies; u32 frame_count; @@ -89,6 +90,7 @@ typedef struct _vout_data { s8 next_rdy_ipu_buf; s8 next_done_ipu_buf; + s8 next_disp_ipu_buf; s8 ipu_buf[2]; s8 ipu_buf_p[2]; s8 ipu_buf_n[2]; @@ -141,8 +143,10 @@ typedef struct _vout_data { int pp_split; /* 0,1 */ struct stripe_param pp_left_stripe; struct stripe_param pp_right_stripe; /* struct for split parameters */ - /* IC ouput buffer number. Counting from 0 to 3 */ - int pp_split_buf_num; /* 0..3 */ + struct stripe_param pp_up_stripe; + struct stripe_param pp_down_stripe; + /* IC ouput buffer number. Counting from 0 to 7 */ + int pp_split_buf_num; /* 0..7 */ u16 bpp ; /* bit per pixel */ u16 xres; /* width of physical frame (BGs) */ u16 yres; /* heigth of physical frame (BGs)*/ diff --git a/drivers/media/video/mxs_pxp.c b/drivers/media/video/mxs_pxp.c index 83c9c52c3b0c..017d22458a22 100644 --- a/drivers/media/video/mxs_pxp.c +++ b/drivers/media/video/mxs_pxp.c @@ -31,6 +31,7 @@ #include <linux/platform_device.h> #include <linux/vmalloc.h> #include <linux/videodev2.h> +#include <linux/delay.h> #include <media/videobuf-dma-contig.h> #include <media/v4l2-common.h> @@ -671,6 +672,7 @@ static int pxp_streamon(struct file *file, void *priv, enum v4l2_buf_type t) pxp_set_outbuf(pxp); ret = videobuf_streamon(&pxp->s0_vbq); + msleep(20); if (!ret && (pxp->output == 0)) mxsfb_cfg_pxp(1, pxp->outb_phys); @@ -686,7 +688,9 @@ static int pxp_streamoff(struct file *file, void *priv, enum v4l2_buf_type t) if ((t != V4L2_BUF_TYPE_VIDEO_OUTPUT)) return -EINVAL; + cancel_work_sync(&pxp->work); ret = videobuf_streamoff(&pxp->s0_vbq); + msleep(20); if (!ret) mxsfb_cfg_pxp(0, 0); @@ -1101,8 +1105,10 @@ static int pxp_close(struct file *file) { struct pxps *pxp = video_get_drvdata(video_devdata(file)); - if (pxp->workqueue) + if (pxp->workqueue) { + flush_workqueue(pxp->workqueue); destroy_workqueue(pxp->workqueue); + } videobuf_stop(&pxp->s0_vbq); videobuf_mmap_free(&pxp->s0_vbq); diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 01b633c73480..be99c8797dcc 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -707,6 +707,10 @@ static void uvc_video_complete(struct urb *urb) if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n", ret); + if (ret == -ENODEV) { + uvc_queue_cancel(queue, 1); + return; + } } } diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c index 2ac8c2421ad2..dc4f32bbd83d 100644 --- a/drivers/media/video/videobuf-dma-contig.c +++ b/drivers/media/video/videobuf-dma-contig.c @@ -319,7 +319,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, mem->size = PAGE_ALIGN(q->bufs[first]->bsize); mem->vaddr = dma_alloc_coherent(q->dev, mem->size, - &mem->dma_handle, GFP_KERNEL); + &mem->dma_handle, GFP_DMA); if (!mem->vaddr) { dev_err(q->dev, "dma_alloc_coherent size %ld failed\n", mem->size); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 281b61b3b5f3..72c10192d802 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -13,6 +13,10 @@ menuconfig MISC_DEVICES if MISC_DEVICES +config ANDROID_PMEM + bool "Android pmem allocator" + default y + config ATMEL_PWM tristate "Atmel AT32/AT91 PWM support" depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 @@ -238,6 +242,14 @@ config MXS_PERSISTENT depends on ARCH_MXS default y +config UID_STAT + bool "UID based statistics tracking exported to /proc/uid_stat" + default n + +config FSL_CACHE + tristate "Freescale Cache manipulate driver" + default n + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 03dd5ee05ce2..c435ec82d664 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -21,5 +21,8 @@ obj-$(CONFIG_HP_ILO) += hpilo.o obj-$(CONFIG_ISL29003) += isl29003.o obj-$(CONFIG_C2PORT) += c2port/ obj-$(CONFIG_MXS_PERSISTENT) += mxs-persistent.o +obj-$(CONFIG_ANDROID_PMEM) += pmem.o +obj-$(CONFIG_UID_STAT) += uid_stat.o +obj-$(CONFIG_FSL_CACHE) += fsl_cache.o obj-y += eeprom/ obj-y += cb710/ diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index ab37a6d9d32a..bb22ffd76ef8 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -3,7 +3,7 @@ # config MMC_UNSAFE_RESUME - bool "Allow unsafe resume (DANGEROUS)" + bool "Assume MMC/SD cards are non-removable (DANGEROUS)" help If you say Y here, the MMC layer will assume that all cards stayed in their respective slots during the suspend. The @@ -14,3 +14,5 @@ config MMC_UNSAFE_RESUME This option is usually just for embedded systems which use a MMC/SD card for rootfs. Most people should say N here. + This option sets a default which can be overridden by the + module parameter "removable=0" or "removable=1". diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 50b208253440..91ba2f812d73 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -48,6 +48,22 @@ int use_spi_crc = 1; module_param(use_spi_crc, bool, 0); /* + * We normally treat cards as removed during suspend if they are not + * known to be on a non-removable bus, to avoid the risk of writing + * back data to a different card after resume. Allow this to be + * overridden if necessary. + */ +#ifdef CONFIG_MMC_UNSAFE_RESUME +int mmc_assume_removable; +#else +int mmc_assume_removable = 1; +#endif +module_param_named(removable, mmc_assume_removable, bool, 0644); +MODULE_PARM_DESC( + removable, + "MMC/SD cards are removable and may be removed during suspend"); + +/* * Internal function. Schedule delayed work in the MMC work queue. */ static int mmc_schedule_delayed_work(struct delayed_work *work, @@ -344,6 +360,101 @@ unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz) EXPORT_SYMBOL(mmc_align_data_size); /** + * mmc_host_enable - enable a host. + * @host: mmc host to enable + * + * Hosts that support power saving can use the 'enable' and 'disable' + * methods to exit and enter power saving states. For more information + * see comments for struct mmc_host_ops. + */ +int mmc_host_enable(struct mmc_host *host) +{ + if (!(host->caps & MMC_CAP_DISABLE)) + return 0; + + if (host->en_dis_recurs) + return 0; + + if (host->nesting_cnt++) + return 0; + + cancel_delayed_work_sync(&host->disable); + + if (host->enabled) + return 0; + + if (host->ops->enable) { + int err; + + host->en_dis_recurs = 1; + err = host->ops->enable(host); + host->en_dis_recurs = 0; + + if (err) { + pr_debug("%s: enable error %d\n", + mmc_hostname(host), err); + return err; + } + } + host->enabled = 1; + return 0; +} +EXPORT_SYMBOL(mmc_host_enable); + +static int mmc_host_do_disable(struct mmc_host *host, int lazy) +{ + if (host->ops->disable) { + int err; + + host->en_dis_recurs = 1; + err = host->ops->disable(host, lazy); + host->en_dis_recurs = 0; + + if (err < 0) { + pr_debug("%s: disable error %d\n", + mmc_hostname(host), err); + return err; + } + if (err > 0) { + unsigned long delay = msecs_to_jiffies(err); + + mmc_schedule_delayed_work(&host->disable, delay); + } + } + host->enabled = 0; + return 0; +} + +/** + * mmc_host_disable - disable a host. + * @host: mmc host to disable + * + * Hosts that support power saving can use the 'enable' and 'disable' + * methods to exit and enter power saving states. For more information + * see comments for struct mmc_host_ops. + */ +int mmc_host_disable(struct mmc_host *host) +{ + int err; + + if (!(host->caps & MMC_CAP_DISABLE)) + return 0; + + if (host->en_dis_recurs) + return 0; + + if (--host->nesting_cnt) + return 0; + + if (!host->enabled) + return 0; + + err = mmc_host_do_disable(host, 0); + return err; +} +EXPORT_SYMBOL(mmc_host_disable); + +/** * __mmc_claim_host - exclusively claim a host * @host: mmc host to claim * @abort: whether or not the operation should be aborted @@ -366,25 +477,111 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort) while (1) { set_current_state(TASK_UNINTERRUPTIBLE); stop = abort ? atomic_read(abort) : 0; - if (stop || !host->claimed) + if (stop || !host->claimed || host->claimer == current) break; spin_unlock_irqrestore(&host->lock, flags); schedule(); spin_lock_irqsave(&host->lock, flags); } set_current_state(TASK_RUNNING); - if (!stop) + if (!stop) { host->claimed = 1; - else + host->claimer = current; + host->claim_cnt += 1; + } else wake_up(&host->wq); spin_unlock_irqrestore(&host->lock, flags); remove_wait_queue(&host->wq, &wait); + if (!stop) + mmc_host_enable(host); return stop; } EXPORT_SYMBOL(__mmc_claim_host); /** + * mmc_try_claim_host - try exclusively to claim a host + * @host: mmc host to claim + * + * Returns %1 if the host is claimed, %0 otherwise. + */ +int mmc_try_claim_host(struct mmc_host *host) +{ + int claimed_host = 0; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + if (!host->claimed || host->claimer == current) { + host->claimed = 1; + host->claimer = current; + host->claim_cnt += 1; + claimed_host = 1; + } + spin_unlock_irqrestore(&host->lock, flags); + return claimed_host; +} +EXPORT_SYMBOL(mmc_try_claim_host); + +static void mmc_do_release_host(struct mmc_host *host) +{ + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + if (--host->claim_cnt) { + /* Release for nested claim */ + spin_unlock_irqrestore(&host->lock, flags); + } else { + host->claimed = 0; + host->claimer = NULL; + spin_unlock_irqrestore(&host->lock, flags); + wake_up(&host->wq); + } +} + +void mmc_host_deeper_disable(struct work_struct *work) +{ + struct mmc_host *host = + container_of(work, struct mmc_host, disable.work); + + /* If the host is claimed then we do not want to disable it anymore */ + if (!mmc_try_claim_host(host)) + return; + mmc_host_do_disable(host, 1); + mmc_do_release_host(host); +} + +/** + * mmc_host_lazy_disable - lazily disable a host. + * @host: mmc host to disable + * + * Hosts that support power saving can use the 'enable' and 'disable' + * methods to exit and enter power saving states. For more information + * see comments for struct mmc_host_ops. + */ +int mmc_host_lazy_disable(struct mmc_host *host) +{ + if (!(host->caps & MMC_CAP_DISABLE)) + return 0; + + if (host->en_dis_recurs) + return 0; + + if (--host->nesting_cnt) + return 0; + + if (!host->enabled) + return 0; + + if (host->disable_delay) { + mmc_schedule_delayed_work(&host->disable, + msecs_to_jiffies(host->disable_delay)); + return 0; + } else + return mmc_host_do_disable(host, 1); +} +EXPORT_SYMBOL(mmc_host_lazy_disable); + +/** * mmc_release_host - release a host * @host: mmc host to release * @@ -393,15 +590,11 @@ EXPORT_SYMBOL(__mmc_claim_host); */ void mmc_release_host(struct mmc_host *host) { - unsigned long flags; - WARN_ON(!host->claimed); - spin_lock_irqsave(&host->lock, flags); - host->claimed = 0; - spin_unlock_irqrestore(&host->lock, flags); + mmc_host_lazy_disable(host); - wake_up(&host->wq); + mmc_do_release_host(host); } EXPORT_SYMBOL(mmc_release_host); @@ -687,7 +880,13 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing) */ static void mmc_power_up(struct mmc_host *host) { - int bit = fls(host->ocr_avail) - 1; + int bit; + + /* If ocr is set, we use it */ + if (host->ocr) + bit = ffs(host->ocr) - 1; + else + bit = fls(host->ocr_avail) - 1; host->ios.vdd = bit; if (mmc_host_is_spi(host)) { @@ -858,6 +1057,17 @@ void mmc_rescan(struct work_struct *work) container_of(work, struct mmc_host, detect.work); u32 ocr; int err; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + if (host->rescan_disable) { + spin_unlock_irqrestore(&host->lock, flags); + return; + } + + spin_unlock_irqrestore(&host->lock, flags); + mmc_bus_get(host); @@ -890,8 +1100,7 @@ void mmc_rescan(struct work_struct *work) mmc_claim_host(host); mmc_power_up(host); - sdio_go_idle(host); - + sdio_reset(host); mmc_go_idle(host); mmc_send_if_cond(host, host->ocr_avail); @@ -949,9 +1158,14 @@ void mmc_stop_host(struct mmc_host *host) spin_unlock_irqrestore(&host->lock, flags); #endif + if (host->caps & MMC_CAP_DISABLE) + cancel_delayed_work(&host->disable); cancel_delayed_work(&host->detect); mmc_flush_scheduled_work(); + /* clear pm flags now and let card drivers set them as needed */ + host->pm_flags = 0; + mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { if (host->bus_ops->remove) @@ -960,6 +1174,8 @@ void mmc_stop_host(struct mmc_host *host) mmc_claim_host(host); mmc_detach_bus(host); mmc_release_host(host); + mmc_bus_put(host); + return; } mmc_bus_put(host); @@ -968,6 +1184,80 @@ void mmc_stop_host(struct mmc_host *host) mmc_power_off(host); } +void mmc_power_save_host(struct mmc_host *host) +{ + mmc_bus_get(host); + + if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { + mmc_bus_put(host); + return; + } + + if (host->bus_ops->power_save) + host->bus_ops->power_save(host); + + mmc_bus_put(host); + + mmc_power_off(host); +} +EXPORT_SYMBOL(mmc_power_save_host); + +void mmc_power_restore_host(struct mmc_host *host) +{ + mmc_bus_get(host); + + if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { + mmc_bus_put(host); + return; + } + + mmc_power_up(host); + host->bus_ops->power_restore(host); + + mmc_bus_put(host); +} +EXPORT_SYMBOL(mmc_power_restore_host); + +int mmc_card_awake(struct mmc_host *host) +{ + int err = -ENOSYS; + + mmc_bus_get(host); + + if (host->bus_ops && !host->bus_dead && host->bus_ops->awake) + err = host->bus_ops->awake(host); + + mmc_bus_put(host); + + return err; +} +EXPORT_SYMBOL(mmc_card_awake); + +int mmc_card_sleep(struct mmc_host *host) +{ + int err = -ENOSYS; + + mmc_bus_get(host); + + if (host->bus_ops && !host->bus_dead && host->bus_ops->awake) + err = host->bus_ops->sleep(host); + + mmc_bus_put(host); + + return err; +} +EXPORT_SYMBOL(mmc_card_sleep); + +int mmc_card_can_sleep(struct mmc_host *host) +{ + struct mmc_card *card = host->card; + + if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3) + return 1; + return 0; +} +EXPORT_SYMBOL(mmc_card_can_sleep); + #ifdef CONFIG_PM /** @@ -977,27 +1267,37 @@ void mmc_stop_host(struct mmc_host *host) */ int mmc_suspend_host(struct mmc_host *host, pm_message_t state) { + int err = 0; + + if (host->caps & MMC_CAP_DISABLE) + cancel_delayed_work(&host->disable); cancel_delayed_work(&host->detect); mmc_flush_scheduled_work(); mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { if (host->bus_ops->suspend) - host->bus_ops->suspend(host); - if (!host->bus_ops->resume) { + err = host->bus_ops->suspend(host); + if (err == -ENOSYS || !host->bus_ops->resume) { + /* + * We simply "remove" the card in this case. + * It will be redetected on resume. + */ if (host->bus_ops->remove) host->bus_ops->remove(host); - mmc_claim_host(host); mmc_detach_bus(host); mmc_release_host(host); + host->pm_flags = 0; + err = 0; } } mmc_bus_put(host); - mmc_power_off(host); + if (!err && !(host->pm_flags & MMC_PM_KEEP_POWER)) + mmc_power_off(host); - return 0; + return err; } EXPORT_SYMBOL(mmc_suspend_host); @@ -1008,26 +1308,75 @@ EXPORT_SYMBOL(mmc_suspend_host); */ int mmc_resume_host(struct mmc_host *host) { + int err = 0; + mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { - mmc_power_up(host); - mmc_select_voltage(host, host->ocr); + if (!(host->pm_flags & MMC_PM_KEEP_POWER)) { + mmc_power_up(host); + mmc_select_voltage(host, host->ocr); + } BUG_ON(!host->bus_ops->resume); - host->bus_ops->resume(host); + err = host->bus_ops->resume(host); + if (err) { + printk(KERN_WARNING "%s: error %d during resume " + "(card was removed?)\n", + mmc_hostname(host), err); + err = 0; + } } mmc_bus_put(host); - /* - * We add a slight delay here so that resume can progress - * in parallel. - */ - mmc_detect_change(host, 1); - - return 0; + return err; } - EXPORT_SYMBOL(mmc_resume_host); +/* Do the card removal on suspend if card is assumed removeable + * Do that in pm notifier while userspace isn't yet frozen, so we will be able + to sync the card. +*/ +int mmc_pm_notify(struct notifier_block *notify_block, + unsigned long mode, void *unused) +{ + struct mmc_host *host = container_of( + notify_block, struct mmc_host, pm_notify); + unsigned long flags; + + + switch (mode) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + + spin_lock_irqsave(&host->lock, flags); + host->rescan_disable = 1; + spin_unlock_irqrestore(&host->lock, flags); + cancel_delayed_work_sync(&host->detect); + + if (!host->bus_ops || host->bus_ops->suspend) + break; + + mmc_claim_host(host); + + if (host->bus_ops->remove) + host->bus_ops->remove(host); + + mmc_detach_bus(host); + mmc_release_host(host); + host->pm_flags = 0; + break; + + case PM_POST_SUSPEND: + case PM_POST_HIBERNATION: + + spin_lock_irqsave(&host->lock, flags); + host->rescan_disable = 0; + spin_unlock_irqrestore(&host->lock, flags); + mmc_detect_change(host, 0); + + } + + return 0; +} #endif static int __init mmc_init(void) diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index c819effa1032..a811c52a1659 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -16,10 +16,14 @@ #define MMC_CMD_RETRIES 3 struct mmc_bus_ops { + int (*awake)(struct mmc_host *); + int (*sleep)(struct mmc_host *); void (*remove)(struct mmc_host *); void (*detect)(struct mmc_host *); - void (*suspend)(struct mmc_host *); - void (*resume)(struct mmc_host *); + int (*suspend)(struct mmc_host *); + int (*resume)(struct mmc_host *); + void (*power_save)(struct mmc_host *); + void (*power_restore)(struct mmc_host *); }; void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); @@ -50,7 +54,9 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr); int mmc_attach_sd(struct mmc_host *host, u32 ocr); int mmc_attach_sdio(struct mmc_host *host, u32 ocr); +/* Module parameters */ extern int use_spi_crc; +extern int mmc_assume_removable; /* Debugfs information for hosts and cards */ void mmc_add_host_debugfs(struct mmc_host *host); diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 5e945e64ead7..0efe631e50ca 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -16,6 +16,8 @@ #include <linux/idr.h> #include <linux/pagemap.h> #include <linux/leds.h> +#include <linux/slab.h> +#include <linux/suspend.h> #include <linux/mmc/host.h> @@ -83,6 +85,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); INIT_DELAYED_WORK(&host->detect, mmc_rescan); + INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable); + host->pm_notify.notifier_call = mmc_pm_notify; /* * By default, hosts do not support SGIO or large requests. @@ -131,6 +135,7 @@ int mmc_add_host(struct mmc_host *host) #endif mmc_start_host(host); + register_pm_notifier(&host->pm_notify); return 0; } @@ -147,6 +152,7 @@ EXPORT_SYMBOL(mmc_add_host); */ void mmc_remove_host(struct mmc_host *host) { + unregister_pm_notifier(&host->pm_notify); mmc_stop_host(host); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h index c2dc3d2d9f9a..8c87e1109a34 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h @@ -14,5 +14,7 @@ int mmc_register_host_class(void); void mmc_unregister_host_class(void); +void mmc_host_deeper_disable(struct work_struct *work); + #endif diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index e207dcf9e754..2338c761c74f 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -160,7 +160,6 @@ static int mmc_read_ext_csd(struct mmc_card *card) { int err; u8 *ext_csd; - unsigned int ext_csd_struct; BUG_ON(!card); @@ -207,16 +206,16 @@ static int mmc_read_ext_csd(struct mmc_card *card) goto out; } - ext_csd_struct = ext_csd[EXT_CSD_REV]; - if (ext_csd_struct > 5) { + card->ext_csd.rev = ext_csd[EXT_CSD_REV]; + if (card->ext_csd.rev > 3) { printk(KERN_ERR "%s: unrecognised EXT_CSD structure " "version %d\n", mmc_hostname(card->host), - ext_csd_struct); + card->ext_csd.rev); err = -EINVAL; goto out; } - if (ext_csd_struct >= 2) { + if (card->ext_csd.rev >= 2) { card->ext_csd.sectors = ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | @@ -226,7 +225,17 @@ static int mmc_read_ext_csd(struct mmc_card *card) mmc_card_set_blockaddr(card); } + card->ext_csd.boot_info = ext_csd[EXT_CSD_BOOT_INFO]; + card->ext_csd.boot_size_mult = ext_csd[EXT_CSD_BOOT_SIZE_MULT]; + card->ext_csd.boot_config = ext_csd[EXT_CSD_BOOT_CONFIG]; + card->ext_csd.boot_bus_width = ext_csd[EXT_CSD_BOOT_BUS_WIDTH]; + card->ext_csd.card_type = ext_csd[EXT_CSD_CARD_TYPE]; + switch (ext_csd[EXT_CSD_CARD_TYPE]) { + case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 + | EXT_CSD_CARD_TYPE_26: + card->ext_csd.hs_max_dtr = 52000000; + break; case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: card->ext_csd.hs_max_dtr = 52000000; break; @@ -238,15 +247,301 @@ static int mmc_read_ext_csd(struct mmc_card *card) printk(KERN_WARNING "%s: card is mmc v4 but doesn't " "support any high-speed modes.\n", mmc_hostname(card->host)); + printk(KERN_WARNING "%s: card type is 0x%x\n", + mmc_hostname(card->host), ext_csd[EXT_CSD_CARD_TYPE]); goto out; } + if (card->ext_csd.rev >= 3) { + u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; + + /* Sleep / awake timeout in 100ns units */ + if (sa_shift > 0 && sa_shift <= 0x17) + card->ext_csd.sa_timeout = + 1 << ext_csd[EXT_CSD_S_A_TIMEOUT]; + } + out: kfree(ext_csd); return err; } +/* configure the boot partitions */ +static ssize_t +setup_boot_partitions(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int err, busy = 0; + u32 part, new_part; + u8 *ext_csd, boot_config; + struct mmc_command cmd; + struct mmc_card *card = container_of(dev, struct mmc_card, dev); + + BUG_ON(!card); + + sscanf(buf, "%d\n", &part); + + if (card->csd.mmca_vsn < CSD_SPEC_VER_4) { + printk(KERN_ERR "%s: invalid mmc version" + " mmc version is below version 4!)\n", + mmc_hostname(card->host)); + return -EINVAL; + } + + /* it's a normal SD/MMC but user request to configure boot partition */ + if (card->ext_csd.boot_size_mult <= 0) { + printk(KERN_ERR "%s: this is a normal SD/MMC card" + " but you request to access boot partition!\n", + mmc_hostname(card->host)); + return -EINVAL; + } + + ext_csd = kmalloc(512, GFP_KERNEL); + if (!ext_csd) { + printk(KERN_ERR "%s: could not allocate a buffer to " + "receive the ext_csd.\n", mmc_hostname(card->host)); + return -ENOMEM; + } + + mmc_claim_host(card->host); + err = mmc_send_ext_csd(card, ext_csd); + if (err) { + printk(KERN_ERR "%s: unable to read EXT_CSD.\n", + mmc_hostname(card->host)); + goto err_rtn; + } + + /* enable the boot partition in boot mode */ + /* boot enable be - + * 0x00 - disable boot enable. + * 0x08 - boot partition 1 is enabled for boot. + * 0x10 - boot partition 2 is enabled for boot. + * 0x38 - User area is enabled for boot. + */ + switch (part & EXT_CSD_BOOT_PARTITION_ENABLE_MASK) { + case 0: + boot_config = (ext_csd[EXT_CSD_BOOT_CONFIG] + & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK + & ~EXT_CSD_BOOT_ACK_ENABLE); + break; + case EXT_CSD_BOOT_PARTITION_PART1: + boot_config = ((ext_csd[EXT_CSD_BOOT_CONFIG] + & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK) + | EXT_CSD_BOOT_PARTITION_PART1 + | EXT_CSD_BOOT_ACK_ENABLE); + break; + case EXT_CSD_BOOT_PARTITION_PART2: + boot_config = ((ext_csd[EXT_CSD_BOOT_CONFIG] + & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK) + | EXT_CSD_BOOT_PARTITION_PART2 + | EXT_CSD_BOOT_ACK_ENABLE); + break; + case EXT_CSD_BOOT_PARTITION_ENABLE_MASK: + boot_config = ((ext_csd[EXT_CSD_BOOT_CONFIG] + | EXT_CSD_BOOT_PARTITION_ENABLE_MASK) + & ~EXT_CSD_BOOT_ACK_ENABLE); + break; + default: + printk(KERN_ERR "%s: wrong boot config parameter" + " 00 (disable boot), 08 (enable boot1)," + "16 (enable boot2), 56 (User area)\n", + mmc_hostname(card->host)); + err = -EINVAL; + goto err_rtn; + } + + /* switch the partitions that used to be accessed in OS layer */ + /* partition must be - + * 0 - user area + * 1 - boot partition 1 + * 2 - boot partition 2 + */ + if ((part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK) > 2) { + printk(KERN_ERR "%s: wrong partition id" + " 0 (user area), 1 (boot1), 2 (boot2)\n", + mmc_hostname(card->host)); + err = -EINVAL; + goto err_rtn; + } + + /* Send SWITCH command to change partition for access */ + boot_config &= ~EXT_CSD_BOOT_PARTITION_ACCESS_MASK; + boot_config |= (part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK); + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_BOOT_CONFIG, boot_config); + if (err) { + printk(KERN_ERR "%s: fail to send SWITCH command" + " to card to swich partition for access!\n", + mmc_hostname(card->host)); + goto err_rtn; + } + + /* waiting for the card to finish the busy state */ + do { + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SEND_STATUS; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(card->host, &cmd, 0); + if (err || busy > 100) { + printk(KERN_ERR "%s: failed to wait for" + "the busy state to end.\n", + mmc_hostname(card->host)); + break; + } + + if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) { + printk(KERN_INFO "%s: card is in busy state" + "pls wait for busy state to end.\n", + mmc_hostname(card->host)); + } + busy++; + } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); + + /* Now check whether it works */ + err = mmc_send_ext_csd(card, ext_csd); + if (err) { + printk(KERN_ERR "%s: %d unable to re-read EXT_CSD.\n", + mmc_hostname(card->host), err); + goto err_rtn; + } + + new_part = ext_csd[EXT_CSD_BOOT_CONFIG] & + EXT_CSD_BOOT_PARTITION_ACCESS_MASK; + if ((part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK) != new_part) { + printk(KERN_ERR "%s: after SWITCH, current part id %d is not" + " same as requested partition %d!\n", + mmc_hostname(card->host), new_part, part); + goto err_rtn; + } + card->ext_csd.boot_config = ext_csd[EXT_CSD_BOOT_CONFIG]; + +err_rtn: + mmc_release_host(card->host); + kfree(ext_csd); + if (err) + return err; + else + return count; +} + +/* configure the boot bus */ +static ssize_t +setup_boot_bus(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int err, busy = 0; + u32 boot_bus, new_bus; + u8 *ext_csd; + struct mmc_command cmd; + struct mmc_card *card = container_of(dev, struct mmc_card, dev); + + BUG_ON(!card); + + sscanf(buf, "%d\n", &boot_bus); + + if (card->csd.mmca_vsn < CSD_SPEC_VER_4) { + printk(KERN_ERR "%s: invalid mmc version" + " mmc version is below version 4!)\n", + mmc_hostname(card->host)); + return -EINVAL; + } + + /* it's a normal SD/MMC but user request to configure boot bus */ + if (card->ext_csd.boot_size_mult <= 0) { + printk(KERN_ERR "%s: this is a normal SD/MMC card" + " but you request to configure boot bus !\n", + mmc_hostname(card->host)); + return -EINVAL; + } + + ext_csd = kmalloc(512, GFP_KERNEL); + if (!ext_csd) { + printk(KERN_ERR "%s: could not allocate a buffer to " + "receive the ext_csd.\n", mmc_hostname(card->host)); + return -ENOMEM; + } + + mmc_claim_host(card->host); + err = mmc_send_ext_csd(card, ext_csd); + if (err) { + printk(KERN_ERR "%s: unable to read EXT_CSD.\n", + mmc_hostname(card->host)); + goto err_rtn; + } + + /* Configure the boot bus width when boot partition is enabled */ + if (((boot_bus & EXT_CSD_BOOT_BUS_WIDTH_MODE_MASK) >> 3) > 2 + || (boot_bus & EXT_CSD_BOOT_BUS_WIDTH_WIDTH_MASK) > 2 + || (boot_bus & ~EXT_CSD_BOOT_BUS_WIDTH_MASK) > 0) { + printk(KERN_ERR "%s: Invalid inputs!\n", + mmc_hostname(card->host)); + err = -EINVAL; + goto err_rtn; + } + + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_BOOT_BUS_WIDTH, boot_bus); + if (err) { + printk(KERN_ERR "%s: fail to send SWITCH command to " + "card to swich partition for access!\n", + mmc_hostname(card->host)); + goto err_rtn; + } + + /* waiting for the card to finish the busy state */ + do { + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SEND_STATUS; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(card->host, &cmd, 0); + if (err || busy > 100) { + printk(KERN_ERR "%s: failed to wait for" + "the busy state to end.\n", + mmc_hostname(card->host)); + break; + } + + if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) { + printk(KERN_INFO "%s: card is in busy state" + "pls wait for busy state to end.\n", + mmc_hostname(card->host)); + } + busy++; + } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); + + /* Now check whether it works */ + err = mmc_send_ext_csd(card, ext_csd); + if (err) { + printk(KERN_ERR "%s: %d unable to re-read EXT_CSD.\n", + mmc_hostname(card->host), err); + goto err_rtn; + } + + new_bus = ext_csd[EXT_CSD_BOOT_BUS_WIDTH]; + if (boot_bus != new_bus) { + printk(KERN_ERR "%s: after SWITCH, current boot bus mode %d" + " is not same as requested bus mode %d!\n", + mmc_hostname(card->host), new_bus, boot_bus); + goto err_rtn; + } + card->ext_csd.boot_bus_width = ext_csd[EXT_CSD_BOOT_BUS_WIDTH]; + +err_rtn: + mmc_release_host(card->host); + kfree(ext_csd); + if (err) + return err; + else + return count; +} + MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], card->raw_cid[2], card->raw_cid[3]); MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], @@ -258,6 +553,12 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); +MMC_DEV_ATTR(boot_info, "boot_info:0x%02x; boot_size:%04dKB;" + " boot_partition:0x%02x; boot_bus:0x%02x\n", + card->ext_csd.boot_info, card->ext_csd.boot_size_mult * 128, + card->ext_csd.boot_config, card->ext_csd.boot_bus_width); +DEVICE_ATTR(boot_config, S_IWUGO, NULL, setup_boot_partitions); +DEVICE_ATTR(boot_bus_config, S_IWUGO, NULL, setup_boot_bus); static struct attribute *mmc_std_attrs[] = { &dev_attr_cid.attr, @@ -269,6 +570,9 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_name.attr, &dev_attr_oemid.attr, &dev_attr_serial.attr, + &dev_attr_boot_info.attr, + &dev_attr_boot_config.attr, + &dev_attr_boot_bus_config.attr, NULL, }; @@ -434,10 +738,21 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * Activate wide bus (if supported). */ if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) && - (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) { + (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA + | MMC_CAP_DATA_DDR))) { unsigned ext_csd_bit, bus_width; - if (host->caps & MMC_CAP_8_BIT_DATA) { + if ((host->caps & MMC_CAP_8_BIT_DATA) && + (host->caps & MMC_CAP_DATA_DDR) && + (card->ext_csd.card_type & MMC_DDR_MODE_MASK)) { + ext_csd_bit = EXT_CSD_BUS_WIDTH_8_DDR; + bus_width = MMC_BUS_WIDTH_8 | MMC_BUS_WIDTH_DDR; + } else if ((host->caps & MMC_CAP_4_BIT_DATA) && + (host->caps & MMC_CAP_DATA_DDR) && + (card->ext_csd.card_type & MMC_DDR_MODE_MASK)) { + ext_csd_bit = EXT_CSD_BUS_WIDTH_4_DDR; + bus_width = MMC_BUS_WIDTH_4 | MMC_BUS_WIDTH_DDR; + } else if (host->caps & MMC_CAP_8_BIT_DATA) { ext_csd_bit = EXT_CSD_BUS_WIDTH_8; bus_width = MMC_BUS_WIDTH_8; } else { @@ -507,12 +822,10 @@ static void mmc_detect(struct mmc_host *host) } } -#ifdef CONFIG_MMC_UNSAFE_RESUME - /* * Suspend callback from host. */ -static void mmc_suspend(struct mmc_host *host) +static int mmc_suspend(struct mmc_host *host) { BUG_ON(!host); BUG_ON(!host->card); @@ -522,6 +835,8 @@ static void mmc_suspend(struct mmc_host *host) mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); + + return 0; } /* @@ -530,7 +845,7 @@ static void mmc_suspend(struct mmc_host *host) * This function tries to determine if the same card is still present * and, if so, restore all state to it. */ -static void mmc_resume(struct mmc_host *host) +static int mmc_resume(struct mmc_host *host) { int err; @@ -541,30 +856,78 @@ static void mmc_resume(struct mmc_host *host) err = mmc_init_card(host, host->ocr, host->card); mmc_release_host(host); - if (err) { - mmc_remove(host); + return err; +} - mmc_claim_host(host); - mmc_detach_bus(host); - mmc_release_host(host); +static void mmc_power_restore(struct mmc_host *host) +{ + host->card->state &= ~MMC_STATE_HIGHSPEED; + mmc_claim_host(host); + mmc_init_card(host, host->ocr, host->card); + mmc_release_host(host); +} + +static int mmc_sleep(struct mmc_host *host) +{ + struct mmc_card *card = host->card; + int err = -ENOSYS; + + if (card && card->ext_csd.rev >= 3) { + err = mmc_card_sleepawake(host, 1); + if (err < 0) + pr_debug("%s: Error %d while putting card into sleep", + mmc_hostname(host), err); } + return err; } -#else - -#define mmc_suspend NULL -#define mmc_resume NULL +static int mmc_awake(struct mmc_host *host) +{ + struct mmc_card *card = host->card; + int err = -ENOSYS; + + if (card && card->ext_csd.rev >= 3) { + err = mmc_card_sleepawake(host, 0); + if (err < 0) + pr_debug("%s: Error %d while awaking sleeping card", + mmc_hostname(host), err); + } -#endif + return err; +} static const struct mmc_bus_ops mmc_ops = { + .awake = mmc_awake, + .sleep = mmc_sleep, + .remove = mmc_remove, + .detect = mmc_detect, + .suspend = NULL, + .resume = NULL, + .power_restore = mmc_power_restore, +}; + +static const struct mmc_bus_ops mmc_ops_unsafe = { + .awake = mmc_awake, + .sleep = mmc_sleep, .remove = mmc_remove, .detect = mmc_detect, .suspend = mmc_suspend, .resume = mmc_resume, + .power_restore = mmc_power_restore, }; +static void mmc_attach_bus_ops(struct mmc_host *host) +{ + const struct mmc_bus_ops *bus_ops; + + if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable) + bus_ops = &mmc_ops_unsafe; + else + bus_ops = &mmc_ops; + mmc_attach_bus(host, bus_ops); +} + /* * Starting point for MMC card init. */ @@ -575,7 +938,7 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) BUG_ON(!host); WARN_ON(!host->claimed); - mmc_attach_bus(host, &mmc_ops); + mmc_attach_bus_ops(host); /* * We need to get OCR a different way for SPI. diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 34ce2703d29a..355c6042cf65 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -57,6 +57,42 @@ int mmc_deselect_cards(struct mmc_host *host) return _mmc_select_card(host, NULL); } +int mmc_card_sleepawake(struct mmc_host *host, int sleep) +{ + struct mmc_command cmd; + struct mmc_card *card = host->card; + int err; + + if (sleep) + mmc_deselect_cards(host); + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SLEEP_AWAKE; + cmd.arg = card->rca << 16; + if (sleep) + cmd.arg |= 1 << 15; + + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) + return err; + + /* + * If the host does not wait while the card signals busy, then we will + * will have to wait the sleep/awake timeout. Note, we cannot use the + * SEND_STATUS command to poll the status because that command (and most + * others) is invalid while the card sleeps. + */ + if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY)) + mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000)); + + if (!sleep) + err = mmc_select_card(card); + + return err; +} + int mmc_go_idle(struct mmc_host *host) { int err; diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 17854bf7cf0d..653eb8e84178 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -25,6 +25,7 @@ int mmc_send_status(struct mmc_card *card, u32 *status); int mmc_send_cid(struct mmc_host *host, u32 *cid); int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); int mmc_spi_set_crc(struct mmc_host *host, int use_crc); +int mmc_card_sleepawake(struct mmc_host *host, int sleep); #endif diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index cd81c395e164..4a73e34f9200 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -561,12 +561,10 @@ static void mmc_sd_detect(struct mmc_host *host) } } -#ifdef CONFIG_MMC_UNSAFE_RESUME - /* * Suspend callback from host. */ -static void mmc_sd_suspend(struct mmc_host *host) +static int mmc_sd_suspend(struct mmc_host *host) { BUG_ON(!host); BUG_ON(!host->card); @@ -576,6 +574,8 @@ static void mmc_sd_suspend(struct mmc_host *host) mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); + + return 0; } /* @@ -584,7 +584,7 @@ static void mmc_sd_suspend(struct mmc_host *host) * This function tries to determine if the same card is still present * and, if so, restore all state to it. */ -static void mmc_sd_resume(struct mmc_host *host) +static int mmc_sd_resume(struct mmc_host *host) { int err; @@ -595,30 +595,44 @@ static void mmc_sd_resume(struct mmc_host *host) err = mmc_sd_init_card(host, host->ocr, host->card); mmc_release_host(host); - if (err) { - mmc_sd_remove(host); - - mmc_claim_host(host); - mmc_detach_bus(host); - mmc_release_host(host); - } - + return err; } -#else - -#define mmc_sd_suspend NULL -#define mmc_sd_resume NULL - -#endif +static void mmc_sd_power_restore(struct mmc_host *host) +{ + host->card->state &= ~MMC_STATE_HIGHSPEED; + mmc_claim_host(host); + mmc_sd_init_card(host, host->ocr, host->card); + mmc_release_host(host); +} static const struct mmc_bus_ops mmc_sd_ops = { .remove = mmc_sd_remove, .detect = mmc_sd_detect, + .suspend = NULL, + .resume = NULL, + .power_restore = mmc_sd_power_restore, +}; + +static const struct mmc_bus_ops mmc_sd_ops_unsafe = { + .remove = mmc_sd_remove, + .detect = mmc_sd_detect, .suspend = mmc_sd_suspend, .resume = mmc_sd_resume, + .power_restore = mmc_sd_power_restore, }; +static void mmc_sd_attach_bus_ops(struct mmc_host *host) +{ + const struct mmc_bus_ops *bus_ops; + + if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable) + bus_ops = &mmc_sd_ops_unsafe; + else + bus_ops = &mmc_sd_ops; + mmc_attach_bus(host, bus_ops); +} + /* * Starting point for SD card init. */ @@ -629,7 +643,7 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) BUG_ON(!host); WARN_ON(!host->claimed); - mmc_attach_bus(host, &mmc_sd_ops); + mmc_sd_attach_bus_ops(host); /* * We need to get OCR a different way for SPI. diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index fb99ccff9080..7f3093dd2b49 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -195,6 +195,135 @@ static int sdio_enable_hs(struct mmc_card *card) } /* + * Handle the detection and initialisation of a card. + * + * In the case of a resume, "oldcard" will contain the card + * we're trying to reinitialise. + */ +static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, + struct mmc_card *oldcard) +{ + struct mmc_card *card; + int err; + + BUG_ON(!host); + WARN_ON(!host->claimed); + + /* + * Inform the card of the voltage + */ + err = mmc_send_io_op_cond(host, host->ocr, &ocr); + if (err) + goto err; + + /* + * For SPI, enable CRC as appropriate. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host, use_spi_crc); + if (err) + goto err; + } + + /* + * Allocate card structure. + */ + card = mmc_alloc_card(host, NULL); + if (IS_ERR(card)) { + err = PTR_ERR(card); + goto err; + } + + card->type = MMC_TYPE_SDIO; + + /* + * For native busses: set card RCA and quit open drain mode. + */ + if (!mmc_host_is_spi(host)) { + err = mmc_send_relative_addr(host, &card->rca); + if (err) + goto remove; + + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); + } + + /* + * Select card, as all following commands rely on that. + */ + if (!mmc_host_is_spi(host)) { + err = mmc_select_card(card); + if (err) + goto remove; + } + + /* + * Read the common registers. + */ + err = sdio_read_cccr(card); + if (err) + goto remove; + + /* + * Read the common CIS tuples. + */ + err = sdio_read_common_cis(card); + if (err) + goto remove; + + if (oldcard) { + int same = (card->cis.vendor == oldcard->cis.vendor && + card->cis.device == oldcard->cis.device); + mmc_remove_card(card); + if (!same) { + err = -ENOENT; + goto err; + } + card = oldcard; + return 0; + } + + /* + * Switch to high-speed (if supported). + */ + err = sdio_enable_hs(card); + if (err) + goto remove; + + /* + * Change to the card's maximum speed. + */ + if (mmc_card_highspeed(card)) { + /* + * The SDIO specification doesn't mention how + * the CIS transfer speed register relates to + * high-speed, but it seems that 50 MHz is + * mandatory. + */ + mmc_set_clock(host, 50000000); + } else { + mmc_set_clock(host, card->cis.max_dtr); + } + + /* + * Switch to wider bus (if supported). + */ + err = sdio_enable_wide(card); + if (err) + goto remove; + + if (!oldcard) + host->card = card; + return 0; + +remove: + if (!oldcard) + mmc_remove_card(card); + +err: + return err; +} + +/* * Host is being removed. Free up the current card. */ static void mmc_sdio_remove(struct mmc_host *host) @@ -243,10 +372,77 @@ static void mmc_sdio_detect(struct mmc_host *host) } } +/* + * SDIO suspend. We need to suspend all functions separately. + * Therefore all registered functions must have drivers with suspend + * and resume methods. Failing that we simply remove the whole card. + */ +static int mmc_sdio_suspend(struct mmc_host *host) +{ + int i, err = 0; + + for (i = 0; i < host->card->sdio_funcs; i++) { + struct sdio_func *func = host->card->sdio_func[i]; + if (func && sdio_func_present(func) && func->dev.driver) { + const struct dev_pm_ops *pmops = func->dev.driver->pm; + if (!pmops || !pmops->suspend || !pmops->resume) { + /* force removal of entire card in that case */ + err = -ENOSYS; + } else + err = pmops->suspend(&func->dev); + if (err) + break; + } + } + while (err && --i >= 0) { + struct sdio_func *func = host->card->sdio_func[i]; + if (func && sdio_func_present(func) && func->dev.driver) { + const struct dev_pm_ops *pmops = func->dev.driver->pm; + pmops->resume(&func->dev); + } + } + + return err; +} + +static int mmc_sdio_resume(struct mmc_host *host) +{ + int i, err; + + BUG_ON(!host); + BUG_ON(!host->card); + + /* Basic card reinitialization. */ + mmc_claim_host(host); + err = mmc_sdio_init_card(host, host->ocr, host->card); + mmc_release_host(host); + + /* + * If the card looked to be the same as before suspending, then + * we proceed to resume all card functions. If one of them returns + * an error then we simply return that error to the core and the + * card will be redetected as new. It is the responsibility of + * the function driver to perform further tests with the extra + * knowledge it has of the card to confirm the card is indeed the + * same as before suspending (same MAC address for network cards, + * etc.) and return an error otherwise. + */ + for (i = 0; !err && i < host->card->sdio_funcs; i++) { + struct sdio_func *func = host->card->sdio_func[i]; + if (func && sdio_func_present(func) && func->dev.driver) { + const struct dev_pm_ops *pmops = func->dev.driver->pm; + err = pmops->resume(&func->dev); + } + } + + return err; +} static const struct mmc_bus_ops mmc_sdio_ops = { .remove = mmc_sdio_remove, .detect = mmc_sdio_detect, + .suspend = mmc_sdio_suspend, + .resume = mmc_sdio_resume, }; diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index f61fc2d4cd0a..ff69a2feecd5 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -635,3 +635,52 @@ void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, *err_ret = ret; } EXPORT_SYMBOL_GPL(sdio_f0_writeb); + +/** + * sdio_get_host_pm_caps - get host power management capabilities + * @func: SDIO function attached to host + * + * Returns a capability bitmask corresponding to power management + * features supported by the host controller that the card function + * might rely upon during a system suspend. The host doesn't need + * to be claimed, nor the function active, for this information to be + * obtained. + */ +mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func) +{ + BUG_ON(!func); + BUG_ON(!func->card); + + return func->card->host->pm_caps; +} +EXPORT_SYMBOL_GPL(sdio_get_host_pm_caps); + +/** + * sdio_set_host_pm_flags - set wanted host power management capabilities + * @func: SDIO function attached to host + * + * Set a capability bitmask corresponding to wanted host controller + * power management features for the upcoming suspend state. + * This must be called, if needed, each time the suspend method of + * the function driver is called, and must contain only bits that + * were returned by sdio_get_host_pm_caps(). + * The host doesn't need to be claimed, nor the function active, + * for this information to be set. + */ +int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags) +{ + struct mmc_host *host; + + BUG_ON(!func); + BUG_ON(!func->card); + + host = func->card->host; + + if (flags & ~host->pm_caps) + return -EINVAL; + + /* function suspend methods are serialized, hence no lock needed */ + host->pm_flags |= flags; + return 0; +} +EXPORT_SYMBOL_GPL(sdio_set_host_pm_flags); diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 208beeb23ed6..b6304fb8bf90 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -67,6 +67,61 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) return err; } +static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn, + unsigned addr, u8 in, u8 *out) +{ + struct mmc_command cmd; + int err; + + BUG_ON(!host); + BUG_ON(fn > 7); + + /* sanity check */ + if (addr & ~0x1FFFF) + return -EINVAL; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_IO_RW_DIRECT; + cmd.arg = write ? 0x80000000 : 0x00000000; + cmd.arg |= fn << 28; + cmd.arg |= (write && out) ? 0x08000000 : 0x00000000; + cmd.arg |= addr << 9; + cmd.arg |= in; + cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) + return err; + + if (mmc_host_is_spi(host)) { + /* host driver already reported errors */ + } else { + if (cmd.resp[0] & R5_ERROR) + return -EIO; + if (cmd.resp[0] & R5_FUNCTION_NUMBER) + return -EINVAL; + if (cmd.resp[0] & R5_OUT_OF_RANGE) + return -ERANGE; + } + + if (out) { + if (mmc_host_is_spi(host)) + *out = (cmd.resp[0] >> 8) & 0xFF; + else + *out = cmd.resp[0] & 0xFF; + } + + return 0; +} + +int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, + unsigned addr, u8 in, u8 *out) +{ + BUG_ON(!card); + return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out); +} + int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) { @@ -134,62 +189,7 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, return 0; } -static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn, - unsigned addr, u8 in, u8 *out) -{ - struct mmc_command cmd; - int err; - - BUG_ON(!host); - BUG_ON(fn > 7); - - /* sanity check */ - if (addr & ~0x1FFFF) - return -EINVAL; - - memset(&cmd, 0, sizeof(struct mmc_command)); - - cmd.opcode = SD_IO_RW_DIRECT; - cmd.arg = write ? 0x80000000 : 0x00000000; - cmd.arg |= fn << 28; - cmd.arg |= (write && out) ? 0x08000000 : 0x00000000; - cmd.arg |= addr << 9; - cmd.arg |= in; - cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; - - err = mmc_wait_for_cmd(host, &cmd, 0); - if (err) - return err; - - if (mmc_host_is_spi(host)) { - /* host driver already reported errors */ - } else { - if (cmd.resp[0] & R5_ERROR) - return -EIO; - if (cmd.resp[0] & R5_FUNCTION_NUMBER) - return -EINVAL; - if (cmd.resp[0] & R5_OUT_OF_RANGE) - return -ERANGE; - } - - if (out) { - if (mmc_host_is_spi(host)) - *out = (cmd.resp[0] >> 8) & 0xFF; - else - *out = cmd.resp[0] & 0xFF; - } - - return 0; -} - -int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, - unsigned addr, u8 in, u8 *out) -{ - BUG_ON(!card); - return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out); -} - -int sdio_go_idle(struct mmc_host *host) +int sdio_reset(struct mmc_host *host) { int ret; u8 abort; diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index 9b546c71eb5e..85c7ecf809f4 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -18,6 +18,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz); int sdio_go_idle(struct mmc_host *host); +int sdio_reset(struct mmc_host *host); #endif diff --git a/drivers/mmc/host/mx_sdhci.c b/drivers/mmc/host/mx_sdhci.c index 5a68a8e02fe2..732135308eb6 100644 --- a/drivers/mmc/host/mx_sdhci.c +++ b/drivers/mmc/host/mx_sdhci.c @@ -142,32 +142,32 @@ EXPORT_SYMBOL(mxc_mmc_force_detect); static void sdhci_dumpregs(struct sdhci_host *host) { - printk(KERN_DEBUG DRIVER_NAME + printk(KERN_INFO DRIVER_NAME ": ============== REGISTER DUMP ==============\n"); - printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", readl(host->ioaddr + SDHCI_DMA_ADDRESS), readl(host->ioaddr + SDHCI_HOST_VERSION)); - printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", (readl(host->ioaddr + SDHCI_BLOCK_SIZE) & 0xFFFF), (readl(host->ioaddr + SDHCI_BLOCK_COUNT) >> 16)); - printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", readl(host->ioaddr + SDHCI_ARGUMENT), readl(host->ioaddr + SDHCI_TRANSFER_MODE)); - printk(KERN_DEBUG DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", readl(host->ioaddr + SDHCI_PRESENT_STATE), readl(host->ioaddr + SDHCI_HOST_CONTROL)); - printk(KERN_DEBUG DRIVER_NAME ": Clock: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Clock: 0x%08x\n", readl(host->ioaddr + SDHCI_CLOCK_CONTROL)); - printk(KERN_DEBUG DRIVER_NAME ": Int stat: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Int stat: 0x%08x\n", readl(host->ioaddr + SDHCI_INT_STATUS)); - printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", readl(host->ioaddr + SDHCI_INT_ENABLE), readl(host->ioaddr + SDHCI_SIGNAL_ENABLE)); - printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Caps: 0x%08x\n", readl(host->ioaddr + SDHCI_CAPABILITIES)); - printk(KERN_DEBUG DRIVER_NAME + printk(KERN_INFO DRIVER_NAME ": ===========================================\n"); } @@ -506,6 +506,30 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) host->flags &= ~SDHCI_REQ_USE_DMA; } + if (cpu_is_mx25() && (data->blksz * data->blocks < 0x10)) { + host->flags &= ~SDHCI_REQ_USE_DMA; + DBG("Reverting to PIO in small data transfer.\n"); + writel(readl(host->ioaddr + SDHCI_INT_ENABLE) + | SDHCI_INT_DATA_AVAIL + | SDHCI_INT_SPACE_AVAIL, + host->ioaddr + SDHCI_INT_ENABLE); + writel(readl(host->ioaddr + SDHCI_SIGNAL_ENABLE) + | SDHCI_INT_DATA_AVAIL + | SDHCI_INT_SPACE_AVAIL, + host->ioaddr + SDHCI_SIGNAL_ENABLE); + } else if (cpu_is_mx25() && (host->flags & SDHCI_USE_DMA)) { + host->flags |= SDHCI_REQ_USE_DMA; + DBG("Reverting to DMA in large data transfer.\n"); + writel(readl(host->ioaddr + SDHCI_INT_ENABLE) + & ~(SDHCI_INT_DATA_AVAIL + | SDHCI_INT_SPACE_AVAIL), + host->ioaddr + SDHCI_INT_ENABLE); + writel(readl(host->ioaddr + SDHCI_SIGNAL_ENABLE) + & ~(SDHCI_INT_DATA_AVAIL + | SDHCI_INT_SPACE_AVAIL), + host->ioaddr + SDHCI_SIGNAL_ENABLE); + } + if (host->flags & SDHCI_REQ_USE_DMA) { int i; struct scatterlist *tsg; @@ -644,7 +668,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) WARN_ON(host->cmd); /* Wait max 10 ms */ - timeout = 5000; + timeout = 500; mask = SDHCI_CMD_INHIBIT; if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY)) @@ -695,7 +719,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) mode |= SDHCI_TRNS_READ; else mode &= ~SDHCI_TRNS_READ; - if (host->flags & SDHCI_USE_DMA) + if (host->flags & SDHCI_REQ_USE_DMA) mode |= SDHCI_TRNS_DMA; if (host->flags & SDHCI_USE_EXTERNAL_DMA) DBG("Prepare data completely in %s transfer mode.\n", @@ -727,6 +751,11 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) flags |= SDHCI_CMD_DATA; mode |= SDHCI_MAKE_CMD(cmd->opcode, flags); + if (host->mmc->ios.bus_width & MMC_BUS_WIDTH_DDR) { + /* Eanble the DDR mode */ + mode |= SDHCI_TRNS_DDR_EN; + } else + mode &= ~SDHCI_TRNS_DDR_EN; DBG("Complete sending cmd, transfer mode would be 0x%x.\n", mode); writel(mode, host->ioaddr + SDHCI_TRANSFER_MODE); } @@ -775,6 +804,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) int clk_rate = 0; u32 clk; unsigned long timeout; + struct mmc_ios ios = host->mmc->ios; if (clock == 0) { goto out; @@ -784,17 +814,21 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) host->plat_data->clk_flg = 1; } } - if (clock == host->clock) + + if (clock == host->clock && !(ios.bus_width & MMC_BUS_WIDTH_DDR)) return; clk_rate = clk_get_rate(host->clk); clk = readl(host->ioaddr + SDHCI_CLOCK_CONTROL) & ~SDHCI_CLOCK_MASK; - if (!cpu_is_mx53()) + if (cpu_is_mx53() || cpu_is_mx50()) + writel(clk | SDHCI_CLOCK_SDCLKFS1, + host->ioaddr + SDHCI_CLOCK_CONTROL); + else writel(clk, host->ioaddr + SDHCI_CLOCK_CONTROL); if (clock == host->min_clk) prescaler = 16; - else if (cpu_is_mx53()) + else if (cpu_is_mx53() || cpu_is_mx50()) prescaler = 1; else prescaler = 0; @@ -820,6 +854,21 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) DBG("prescaler = 0x%x, divider = 0x%x\n", prescaler, div); clk |= (prescaler << 8) | (div << 4); + if (host->plat_data->clk_always_on + | (host->mmc->card && mmc_card_sdio(host->mmc->card))) + clk |= SDHCI_CLOCK_PER_EN | SDHCI_CLOCK_HLK_EN + | SDHCI_CLOCK_IPG_EN; + else + clk &= ~(SDHCI_CLOCK_PER_EN | SDHCI_CLOCK_HLK_EN + | SDHCI_CLOCK_IPG_EN); + + /* Configure the clock delay line */ + if ((host->plat_data->vendor_ver >= ESDHC_VENDOR_V3) + && host->plat_data->dll_override_en) + writel((host->plat_data->dll_delay_cells << 10) + | DLL_CTRL_SLV_OVERRIDE, + host->ioaddr + SDHCI_DLL_CONTROL); + /* Configure the clock control register */ clk |= (readl(host->ioaddr + SDHCI_CLOCK_CONTROL) & (~SDHCI_CLOCK_MASK)); @@ -830,7 +879,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) host->ioaddr + SDHCI_CLOCK_CONTROL); /* Wait max 10 ms */ - timeout = 5000; + timeout = 500; while (timeout > 0) { timeout--; udelay(20); @@ -933,8 +982,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) u32 tmp; mxc_dma_device_t dev_id = 0; - DBG("%s: clock %u, bus %lu, power %u, vdd %u\n", DRIVER_NAME, - ios->clock, 1UL << ios->bus_width, ios->power_mode, ios->vdd); + DBG("%s: clock %u, bus %u, power %u, vdd %u\n", DRIVER_NAME, + ios->clock, ios->bus_width, ios->power_mode, ios->vdd); host = mmc_priv(mmc); @@ -1000,10 +1049,10 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) tmp = readl(host->ioaddr + SDHCI_HOST_CONTROL); - if (ios->bus_width == MMC_BUS_WIDTH_4) { + if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_4) { tmp &= ~SDHCI_CTRL_8BITBUS; tmp |= SDHCI_CTRL_4BITBUS; - } else if (ios->bus_width == MMC_BUS_WIDTH_8) { + } else if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_8) { tmp &= ~SDHCI_CTRL_4BITBUS; tmp |= SDHCI_CTRL_8BITBUS; } else if (ios->bus_width == MMC_BUS_WIDTH_1) { @@ -1044,7 +1093,7 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) { struct sdhci_host *host; unsigned long flags; - u32 ier, prot, clk, present; + u32 ier, prot, present; host = mmc_priv(mmc); @@ -1057,19 +1106,12 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) if (--(host->sdio_enable)) goto exit_unlock; } - /* Enable the clock */ - if (!host->plat_data->clk_flg) { - clk_enable(host->clk); - host->plat_data->clk_flg = 1; - } - ier = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE); + + ier = readl(host->ioaddr + SDHCI_INT_ENABLE); prot = readl(host->ioaddr + SDHCI_HOST_CONTROL); - clk = readl(host->ioaddr + SDHCI_CLOCK_CONTROL); if (enable) { ier |= SDHCI_INT_CARD_INT; - prot |= SDHCI_CTRL_D3CD; - clk |= SDHCI_CLOCK_PER_EN | SDHCI_CLOCK_IPG_EN; present = readl(host->ioaddr + SDHCI_PRESENT_STATE); if ((present & SDHCI_CARD_INT_MASK) != SDHCI_CARD_INT_ID) writel(SDHCI_INT_CARD_INT, @@ -1077,12 +1119,24 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) } else { ier &= ~SDHCI_INT_CARD_INT; prot &= ~SDHCI_CTRL_D3CD; - clk &= ~(SDHCI_CLOCK_PER_EN | SDHCI_CLOCK_IPG_EN); } writel(prot, host->ioaddr + SDHCI_HOST_CONTROL); + writel(ier, host->ioaddr + SDHCI_INT_ENABLE); writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE); - writel(clk, host->ioaddr + SDHCI_CLOCK_CONTROL); + + /* + * Using D3CD to manually driver the HW to re-sample the SDIO interrupt + * on bus one more time to guarantee the SDIO interrupt signal sent + * from card during the interrupt signal disabled period will not + * be lost. + */ + prot |= SDHCI_CTRL_CDSS; + writel(prot, host->ioaddr + SDHCI_HOST_CONTROL); + prot &= ~SDHCI_CTRL_D3CD; + writel(prot, host->ioaddr + SDHCI_HOST_CONTROL); + prot |= SDHCI_CTRL_D3CD; + writel(prot, host->ioaddr + SDHCI_HOST_CONTROL); mmiowb(); exit_unlock: @@ -1208,7 +1262,7 @@ static void sdhci_tasklet_finish(unsigned long param) * The root cause is that the ROM code don't ensure * the SD/MMC clk is running when boot system. * */ - if (!machine_is_mx35_3ds() && req_done && host->plat_data->clk_flg && + if (req_done && host->plat_data->clk_flg && !(host->mmc && host->mmc->card && mmc_card_sdio(host->mmc->card))) { clk_disable(host->clk); host->plat_data->clk_flg = 0; @@ -1786,8 +1840,10 @@ static int __devinit sdhci_probe_slot(struct platform_device /* Get the SDHC clock from clock system APIs */ host->clk = clk_get(&pdev->dev, mmc_plat->clock_mmc); - if (NULL == host->clk) + if (NULL == host->clk) { printk(KERN_ERR "MXC MMC can't get clock.\n"); + goto out1; + } DBG("SDHC:%d clock:%lu\n", pdev->id, clk_get_rate(host->clk)); host->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -2001,9 +2057,6 @@ static int __devinit sdhci_probe_slot(struct platform_device } mxc_dma_callback_set(host->dma, sdhci_dma_irq, (void *)host); } -#ifdef CONFIG_MMC_DEBUG - sdhci_dumpregs(host); -#endif mmiowb(); diff --git a/drivers/mmc/host/mx_sdhci.h b/drivers/mmc/host/mx_sdhci.h index 0bd79934952e..83d02975ecd1 100644 --- a/drivers/mmc/host/mx_sdhci.h +++ b/drivers/mmc/host/mx_sdhci.h @@ -2,7 +2,6 @@ * linux/drivers/mmc/host/mx_sdhci.h - Secure Digital Host * Controller Interface driver * - * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. * Copyright (C) 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify @@ -28,6 +27,7 @@ #define SDHCI_TRNS_DMA 0x00000001 #define SDHCI_TRNS_BLK_CNT_EN 0x00000002 #define SDHCI_TRNS_ACMD12 0x00000004 +#define SDHCI_TRNS_DDR_EN 0x00000008 #define SDHCI_TRNS_READ 0x00000010 #define SDHCI_TRNS_MULTI 0x00000020 #define SDHCI_TRNS_DPSEL 0x00200000 @@ -69,6 +69,7 @@ #define SDHCI_CTRL_4BITBUS 0x00000002 #define SDHCI_CTRL_8BITBUS 0x00000004 #define SDHCI_CTRL_HISPD 0x00000004 +#define SDHCI_CTRL_CDSS 0x80 #define SDHCI_CTRL_DMA_MASK 0x18 #define SDHCI_CTRL_SDMA 0x00 #define SDHCI_CTRL_ADMA1 0x08 @@ -95,6 +96,7 @@ #define SDHCI_CLOCK_PER_EN 0x00000004 #define SDHCI_CLOCK_HLK_EN 0x00000002 #define SDHCI_CLOCK_IPG_EN 0x00000001 +#define SDHCI_CLOCK_SDCLKFS1 0x00000100 #define SDHCI_CLOCK_MASK 0x0000FFFF #define SDHCI_TIMEOUT_CONTROL 0x2E @@ -188,6 +190,18 @@ #define SDHCI_ADMA_ADDRESS 0x58 /* 60-FB reserved */ +#define SDHCI_DLL_CONTROL 0x60 +#define DLL_CTRL_ENABLE 0x00000001 +#define DLL_CTRL_RESET 0x00000002 +#define DLL_CTRL_SLV_FORCE_UPD 0x00000004 +#define DLL_CTRL_SLV_OVERRIDE 0x00000200 +#define DLL_CTRL_SLV_DLY_TAR 0x00000000 +#define DLL_CTRL_SLV_UP_INT 0x00200000 +#define DLL_CTRL_REF_UP_INT 0x20000000 + +#define SDHCI_DLL_STATUS 0x64 +#define DLL_STS_SLV_LOCK 0x00000001 +#define DLL_STS_REF_LOCK 0x00000002 /* ADMA Addr Descriptor Attribute Filed */ enum { @@ -207,6 +221,7 @@ enum { #define SDHCI_SPEC_100 0 #define SDHCI_SPEC_200 1 #define ESDHC_VENDOR_V22 0x12 +#define ESDHC_VENDOR_V3 0x13 struct sdhci_chip; diff --git a/drivers/mmc/host/mxc_mmc.c b/drivers/mmc/host/mxc_mmc.c index 980dc98c9b5f..9cb492f40145 100644 --- a/drivers/mmc/host/mxc_mmc.c +++ b/drivers/mmc/host/mxc_mmc.c @@ -13,7 +13,7 @@ */ /* - * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -1232,7 +1232,7 @@ static int mxcmci_probe(struct platform_device *pdev) mmc->f_max = mmc_plat->max_clk; mmc->max_req_size = 32 * 1024; mmc->max_seg_size = mmc->max_req_size; - mmc->max_blk_count = 65536; + mmc->max_blk_count = 32; spin_lock_init(&host->lock); host->mmc = mmc; diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index c60352247c49..b7210b7d7af3 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -49,7 +49,7 @@ #define MXS_MMC_DETECT_TIMEOUT (HZ/2) /* Max value supported for XFER_COUNT */ -#define SSP_BUFFER_SIZE (65536) +#define SSP_BUFFER_SIZE (65535) #ifndef BF #define BF(value, field) (((value) << BP_##field) & BM_##field) @@ -93,6 +93,9 @@ #define BF_SSP_BLOCK_SIZE_BLOCK_SIZE(v) \ (((v) << 16) & BM_SSP_BLOCK_SIZE_BLOCK_SIZE) #endif +#ifndef BM_SSP_CMD0_DBL_DATA_RATE_EN +#define BM_SSP_CMD0_DBL_DATA_RATE_EN 0x02000000 +#endif struct mxs_mmc_host { struct device *dev; @@ -159,6 +162,7 @@ static inline int mxs_mmc_is_plugged(struct mxs_mmc_host *host) return !(status & BM_SSP_STATUS_CARD_DETECT); } +static void mxs_mmc_reset(struct mxs_mmc_host *host); /* Card detection polling function */ static void mxs_mmc_detect_poll(unsigned long arg) { @@ -167,6 +171,8 @@ static void mxs_mmc_detect_poll(unsigned long arg) card_status = mxs_mmc_is_plugged(host); if (card_status != host->present) { + /* Reset MMC block */ + mxs_mmc_reset(host); host->present = card_status; mmc_detect_change(host->mmc, 0); } @@ -183,6 +189,12 @@ static void mxs_mmc_detect_poll(unsigned long arg) BM_SSP_CTRL1_RECV_TIMEOUT_IRQ | \ BM_SSP_CTRL1_FIFO_OVERRUN_IRQ) +#define MXS_MMC_ERR_BITS (BM_SSP_CTRL1_RESP_ERR_IRQ | \ + BM_SSP_CTRL1_RESP_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_DATA_CRC_IRQ | \ + BM_SSP_CTRL1_RECV_TIMEOUT_IRQ) + /* SSP DMA interrupt handler */ static irqreturn_t mmc_irq_handler(int irq, void *dev_id) { @@ -198,19 +210,17 @@ static irqreturn_t mmc_irq_handler(int irq, void *dev_id) /* STOP the dma transfer here. */ mxs_dma_cooked(host->dmach, NULL); } - host->status = - __raw_readl(host->ssp_base + HW_SSP_STATUS); - if (host->cmd) /* else it is a bogus interrupt */ - complete(&host->dma_done); + if ((irq == host->dmairq) || (c1 & MXS_MMC_ERR_BITS)) + if (host->cmd) { + host->status = + __raw_readl(host->ssp_base + HW_SSP_STATUS); + complete(&host->dma_done); + } - if ((c1 & BM_SSP_CTRL1_SDIO_IRQ) && (c1 & BM_SSP_CTRL1_SDIO_IRQ_EN)) { - __raw_writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, host->ssp_base + \ - HW_SSP_CTRL0_CLR); - __raw_writel(BM_SSP_CTRL1_SDIO_IRQ_EN, host->ssp_base + \ - HW_SSP_CTRL1_CLR); + if ((c1 & BM_SSP_CTRL1_SDIO_IRQ) && (c1 & BM_SSP_CTRL1_SDIO_IRQ_EN)) mmc_signal_sdio_irq(host->mmc); - } + return IRQ_HANDLED; } @@ -239,6 +249,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host) { struct mmc_command *cmd = host->cmd; struct mxs_dma_desc *dma_desc = host->dma_desc; + unsigned long flags; dma_desc->cmd.cmd.bits.command = NO_DMA_XFER; dma_desc->cmd.cmd.bits.irq = 1; @@ -255,7 +266,8 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host) if (host->sdio_irq_en) { dma_desc->cmd.pio_words[0] |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; - dma_desc->cmd.pio_words[1] |= BM_SSP_CMD0_CONT_CLKING_EN; + dma_desc->cmd.pio_words[1] |= BM_SSP_CMD0_CONT_CLKING_EN \ + | BM_SSP_CMD0_SLOW_CLKING_EN; } init_completion(&host->dma_done); @@ -265,6 +277,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host) dev_dbg(host->dev, "%s start DMA.\n", __func__); if (mxs_dma_enable(host->dmach) < 0) dev_err(host->dev, "mmc_dma_enable failed\n"); + wait_for_completion(&host->dma_done); cmd->error = mxs_mmc_cmd_error(host->status); @@ -273,6 +286,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host) dev_dbg(host->dev, "Command error 0x%x\n", cmd->error); mxs_dma_reset(host->dmach); } + mxs_dma_disable(host->dmach); } /* Send the ac command to the device */ @@ -284,6 +298,7 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) u32 ssp_ctrl0; u32 ssp_cmd0; u32 ssp_cmd1; + unsigned long flags; ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ? 0 : BM_SSP_CTRL0_IGNORE_CRC; @@ -305,7 +320,8 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) if (host->sdio_irq_en) { ssp_ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; - ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN; + ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN \ + | BM_SSP_CMD0_SLOW_CLKING_EN; } dma_desc->cmd.pio_words[0] = ssp_ctrl0; @@ -356,6 +372,7 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) dev_dbg(host->dev, "Command error 0x%x\n", cmd->error); mxs_dma_reset(host->dmach); } + mxs_dma_disable(host->dmach); } /* Copy data between sg list and dma buffer */ @@ -451,6 +468,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) u32 data_size = cmd->data->blksz * cmd->data->blocks; u32 log2_block_size; + unsigned long flags; ignore_crc = mmc_resp_type(cmd) & MMC_RSP_CRC ? 0 : 1; resp = mmc_resp_type(cmd) & MMC_RSP_PRESENT ? 1 : 0; @@ -540,6 +558,9 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) dev_dbg(host->dev, "%s blksz is 0x%x.\n", __func__, log2_block_size); if (ssp_ver_major > 3) { + /* Configure the CMD0 */ + ssp_cmd0 = BF(cmd->opcode, SSP_CMD0_CMD); + /* Configure the BLOCK SIZE and BLOCK COUNT */ if ((1<<log2_block_size) != cmd->data->blksz) { BUG_ON(cmd->data->blocks > 1); @@ -548,20 +569,32 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) val = BF(log2_block_size, SSP_BLOCK_SIZE_BLOCK_SIZE) | BF(cmd->data->blocks - 1, SSP_BLOCK_SIZE_BLOCK_COUNT); __raw_writel(val, host->ssp_base + HW_SSP_BLOCK_SIZE); - } - /* Configure the CMD0 */ - ssp_cmd0 = BF(cmd->opcode, SSP_CMD0_CMD); - } else - ssp_cmd0 = - BF(log2_block_size, SSP_BLOCK_SIZE_BLOCK_SIZE) | - BF(cmd->opcode, SSP_CMD0_CMD) | - BF(cmd->data->blocks - 1, SSP_BLOCK_SIZE_BLOCK_COUNT); + if (host->mmc->ios.bus_width & MMC_BUS_WIDTH_DDR) + /* Enable the DDR mode */ + ssp_cmd0 |= BM_SSP_CMD0_DBL_DATA_RATE_EN; + else + ssp_cmd0 &= ~BM_SSP_CMD0_DBL_DATA_RATE_EN; + } + } else { + if ((1<<log2_block_size) != cmd->data->blksz) { + BUG_ON(cmd->data->blocks > 1); + ssp_cmd0 = + BF(0, SSP_BLOCK_SIZE_BLOCK_SIZE) | + BF(cmd->opcode, SSP_CMD0_CMD) | + BF(0, SSP_BLOCK_SIZE_BLOCK_COUNT); + } else + ssp_cmd0 = + BF(log2_block_size, SSP_BLOCK_SIZE_BLOCK_SIZE) | + BF(cmd->opcode, SSP_CMD0_CMD) | + BF(cmd->data->blocks - 1, SSP_BLOCK_SIZE_BLOCK_COUNT); + } if (host->sdio_irq_en) { ssp_ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; - ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN; + ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN \ + | BM_SSP_CMD0_SLOW_CLKING_EN; } - if (cmd->opcode == 12) + if ((cmd->opcode == 12) || (cmd->opcode == 53)) ssp_cmd0 |= BM_SSP_CMD0_APPEND_8CYC; ssp_cmd1 = BF(cmd->arg, SSP_CMD1_CMD_ARG); @@ -628,6 +661,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) dev_dbg(host->dev, "Transferred %u bytes\n", cmd->data->bytes_xfered); } + mxs_dma_disable(host->dmach); } /* Begin sedning a command to the card */ @@ -672,6 +706,13 @@ static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) dev_dbg(host->dev, "MMC request\n"); + if (!host->present) { + mrq->cmd->error = -ETIMEDOUT; + mmc_request_done(mmc, mrq); + return; + } + + BUG_ON(host->mrq != NULL); host->mrq = mrq; mxs_mmc_start_cmd(host, mrq->cmd); @@ -777,9 +818,9 @@ static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) dev_warn(host->dev, "Platform does not support CMD pin pullup control\n"); - if (ios->bus_width == MMC_BUS_WIDTH_8) + if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_8) host->bus_width = 2; - else if (ios->bus_width == MMC_BUS_WIDTH_4) + else if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_4) host->bus_width = 1; else host->bus_width = 0; @@ -851,7 +892,6 @@ static void mxs_mmc_reset(struct mxs_mmc_host *host) /* Configure SSP Control Register 1 */ ssp_ctrl1 = BM_SSP_CTRL1_DMA_ENABLE | - BM_SSP_CTRL1_POLARITY | BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN | BM_SSP_CTRL1_DATA_CRC_IRQ_EN | BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN | diff --git a/drivers/mtd/devices/mxc_dataflash.c b/drivers/mtd/devices/mxc_dataflash.c index ab75d743a05b..0ed701d6778c 100644 --- a/drivers/mtd/devices/mxc_dataflash.c +++ b/drivers/mtd/devices/mxc_dataflash.c @@ -1,5 +1,5 @@ /* - * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. * (c) 2005 MontaVista Software, Inc. * * This code is based on mtd_dataflash.c by adding FSL spi access. @@ -22,10 +22,10 @@ #include <linux/err.h> #include <linux/spi/spi.h> -#include <linux/spi/flash.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> +#include <asm/mach/flash.h> /* * DataFlash is a kind of SPI flash. Most AT45 chips have two buffers in diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 8f1eebf8d3b3..1a85f6d5543b 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -434,49 +434,9 @@ config MXC_NAND_LOW_LEVEL_ERASE This enables the erase of whole NAND flash. By default low level erase operation is disabled. -config MTD_NAND_GPMI_LBA - tristate "GPMI LBA NAND driver" - depends on MTD_NAND && ARCH_STMP3XXX - help - Enables support of LBA devices on GPMI on 37xx/378x SigmaTel - boards - -config MTD_NAND_GPMI - tristate "GPMI NAND driver" - depends on MTD_NAND && ARCH_STMP3XXX && !MTD_NAND_GPMI_LBA - help - Enables support of NAND devices on GPMI on 37xx/378x SigmaTel - boards - -config MTD_NAND_GPMI_SYSFS_ENTRIES - bool "Create /sys entries for GPMI device" - depends on MTD_NAND_GPMI - help - Check this to enable /sys entries for GPMI devices - -config MTD_NAND_GPMI_BCH - bool "Enable BCH HWECC" - depends on MTD_NAND_GPMI - depends on ARCH_STMP378X - default y - help - Check this to enable /sys entries for GPMI devices - -config MTD_NAND_GPMI_TA1 - bool "Support for TA1 NCB format (Hamming code 22,16)" - depends on MTD_NAND_GPMI - depends on ARCH_STMP378X - default y - -config MTD_NAND_GPMI_TA3 - bool "Support for TA3 NCB format (Hamming code 13,8)" - depends on MTD_NAND_GPMI - depends on ARCH_STMP378X - default y - -config MTD_NAND_GPMI1 - tristate "GPMI NAND Flash driver" - depends on MTD_NAND && ARCH_MX28 +config MTD_NAND_GPMI_NFC + tristate "GPMI NAND Flash Controller driver" + depends on MTD_NAND && (ARCH_MX23 || ARCH_MX28 || ARCH_MX50) help Enables NAND Flash support. diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 730f5db16e1d..2245a8df441b 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -41,9 +41,7 @@ obj-$(CONFIG_MTD_NAND_IMX_NFC) += imx_nfc.o obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o obj-$(CONFIG_MTD_NAND_MXC_V2) += mxc_nd2.o nand_device_info.o obj-$(CONFIG_MTD_NAND_MXC_V3) += mxc_nd2.o nand_device_info.o -obj-$(CONFIG_MTD_NAND_GPMI) += gpmi/ nand_device_info.o -obj-$(CONFIG_MTD_NAND_GPMI1) += gpmi1/ nand_device_info.o -obj-$(CONFIG_MTD_NAND_GPMI_LBA) += lba/ +obj-$(CONFIG_MTD_NAND_GPMI_NFC) += gpmi-nfc/ nand_device_info.o obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o diff --git a/drivers/mtd/nand/mxc_nd2.c b/drivers/mtd/nand/mxc_nd2.c index 46e6380fe462..80533ac42e9c 100644 --- a/drivers/mtd/nand/mxc_nd2.c +++ b/drivers/mtd/nand/mxc_nd2.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -32,12 +32,15 @@ /* Global address Variables */ static void __iomem *nfc_axi_base, *nfc_ip_base; +static int nfc_irq; struct mxc_mtd_s { struct mtd_info mtd; struct nand_chip nand; struct mtd_partition *parts; struct device *dev; + int disable_bi_swap; /* disable bi swap */ + int clk_active; }; static struct mxc_mtd_s *mxc_nand_data; @@ -117,6 +120,49 @@ static const char *part_probes[] = { static wait_queue_head_t irq_waitq; +#if 0 +static void nand_page_dump(struct mtd_info *mtd, u8 *dbuf, u8* obuf) +{ + int i; + + if (dbuf != NULL) { + printk("\nData buffer:"); + for (i = 0; i < mtd->writesize; i++) { + if (!(i % 8)) printk("\n%03x: ", i); + printk("%02x ", dbuf[i]); + } + } + printk("\n"); + if (obuf != NULL) { + printk("\nOOB buffer:"); + for (i = 0; i < mtd->oobsize; i++) { + if (!(i % 8)) printk("\n%02x: ", i); + printk("%02x ", obuf[i]); + } + } + printk("\n"); +} +#endif + +#ifdef CONFIG_MXC_NAND_SWAP_BI +#define PART_UBOOT_SIZE 0xc0000 +#define SKIP_SWAP_BI_MAX_PAGE (PART_UBOOT_SIZE / 0x800) +inline int skip_swap_bi(int page) +{ + /** + * Seems that the boot code of the i.mx515 rom is not able to + * boot from a nand flash when the data has been written swapping + * the bad block byte. Avoid doing that (the swapping) when + * programming U-Boot into the flash. + */ + if (page < SKIP_SWAP_BI_MAX_PAGE) + return 1; + return 0; +} +#else +inline int skip_swap_bi(int page_addr) { return 1; } +#endif + static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) { /* Disable Interuupt */ @@ -126,6 +172,30 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static void mxc_nand_bi_swap(struct mtd_info *mtd, int page_addr) +{ + u16 ma, sa, nma, nsa; + + if (!IS_LARGE_PAGE_NAND) + return; + + /* Disable bi swap if the user set disable_bi_swap at sys entry */ + if (mxc_nand_data->disable_bi_swap) + return; + + if (skip_swap_bi(page_addr)) + return; + + ma = __raw_readw(BAD_BLK_MARKER_MAIN); + sa = __raw_readw(BAD_BLK_MARKER_SP); + + nma = (ma & 0xFF00) | (sa >> 8); + nsa = (sa & 0x00FF) | (ma << 8); + + __raw_writew(nma, BAD_BLK_MARKER_MAIN); + __raw_writew(nsa, BAD_BLK_MARKER_SP); +} + static void nfc_memcpy(void *dest, void *src, int len) { u8 *d = dest; @@ -287,6 +357,7 @@ static void auto_cmd_interleave(struct mtd_info *mtd, u16 cmd) /* data transfer */ memcpy(MAIN_AREA0, dbuf, dlen); copy_spare(mtd, obuf, SPARE_AREA0, olen, false); + mxc_nand_bi_swap(mtd, page_addr - 1); /* update the value */ dbuf += dlen; @@ -316,6 +387,7 @@ static void auto_cmd_interleave(struct mtd_info *mtd, u16 cmd) mxc_check_ecc_status(mtd); /* data transfer */ + mxc_nand_bi_swap(mtd, page_addr - 1); memcpy(dbuf, MAIN_AREA0, dlen); copy_spare(mtd, obuf, SPARE_AREA0, olen, true); @@ -558,10 +630,7 @@ static int mxc_check_ecc_status(struct mtd_info *mtd) u32 ecc_stat, err; int no_subpages = 1; int ret = 0; - u8 ecc_bit_mask, err_limit; - - ecc_bit_mask = (IS_4BIT_ECC ? 0x7 : 0xf); - err_limit = (IS_4BIT_ECC ? 0x4 : 0x8); + u8 ecc_bit_mask = 0xf; no_subpages = mtd->writesize >> 9; @@ -570,7 +639,7 @@ static int mxc_check_ecc_status(struct mtd_info *mtd) ecc_stat = GET_NFC_ECC_STATUS(); do { err = ecc_stat & ecc_bit_mask; - if (err > err_limit) { + if (err == ecc_bit_mask) { mtd->ecc_stats.failed++; printk(KERN_WARNING "UnCorrectable RS-ECC Error\n"); return -1; @@ -580,8 +649,7 @@ static int mxc_check_ecc_status(struct mtd_info *mtd) ecc_stat >>= 4; } while (--no_subpages); - mtd->ecc_stats.corrected += ret; - pr_debug("%d Symbol Correctable RS-ECC Error\n", ret); + pr_debug("Correctable ECC Error(%d)\n", ret); return ret; } @@ -774,6 +842,30 @@ static int mxc_nand_verify_buf(struct mtd_info *mtd, const u_char * buf, } /*! + * This function will enable NFC clock + * + */ +static inline void mxc_nand_clk_enable(void) +{ + if (!mxc_nand_data->clk_active) { + clk_enable(nfc_clk); + mxc_nand_data->clk_active = 1; + } +} + +/*! + * This function will disable NFC clock + * + */ +static inline void mxc_nand_clk_disable(void) +{ + if (mxc_nand_data->clk_active) { + clk_disable(nfc_clk); + mxc_nand_data->clk_active = 0; + } +} + +/*! * This function is used by upper layer for select and deselect of the NAND * chip * @@ -786,13 +878,14 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) switch (chip) { case -1: /* Disable the NFC clock */ - clk_disable(nfc_clk); + mxc_nand_clk_disable(); + break; - case 0 ... 7: + case 0 ... NFC_GET_MAXCHIP_SP(): /* Enable the NFC clock */ - clk_enable(nfc_clk); - + mxc_nand_clk_enable(); NFC_SET_NFC_ACTIVE_CS(chip); + break; default: @@ -930,6 +1023,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, */ nfc_memcpy(MAIN_AREA0, data_buf, mtd->writesize); copy_spare(mtd, oob_buf, SPARE_AREA0, mtd->oobsize, false); + mxc_nand_bi_swap(mtd, page_addr); #endif if (IS_LARGE_PAGE_NAND) @@ -980,10 +1074,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, * byte alignment, so we can use * memcpy safely */ + mxc_nand_bi_swap(mtd, page_addr); nfc_memcpy(data_buf, MAIN_AREA0, mtd->writesize); copy_spare(mtd, oob_buf, SPARE_AREA0, mtd->oobsize, true); #endif - break; case NAND_CMD_READID: @@ -1096,6 +1190,14 @@ static int mxc_nand_scan_bbt(struct mtd_info *mtd) /* jffs2 not write oob */ mtd->flags &= ~MTD_OOB_WRITEABLE; + /* fix up the offset */ + largepage_memorybased.offs = BAD_BLK_MARKER_OOB_OFFS; + /* keep compatible for bbt table with old soc */ + if (cpu_is_mx53()) { + bbt_mirror_descr.offs = BAD_BLK_MARKER_OOB_OFFS + 2; + bbt_main_descr.offs = BAD_BLK_MARKER_OOB_OFFS + 2; + } + /* use flash based bbt */ this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; @@ -1126,6 +1228,53 @@ static int mxc_nand_scan_bbt(struct mtd_info *mtd) return nand_scan_bbt(mtd, this->badblock_pattern); } +static int mxc_get_resources(struct platform_device *pdev) +{ + struct resource *r; + int error = 0; + +#define MXC_NFC_NO_IP_REG \ + (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx32() || cpu_is_mx35()) + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + error = -ENXIO; + goto out_0; + } + nfc_axi_base = ioremap(r->start, resource_size(r)); + + if (!MXC_NFC_NO_IP_REG) { + r = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!r) { + error = -ENXIO; + goto out_1; + } + } + nfc_ip_base = ioremap(r->start, resource_size(r)); + + r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!r) { + error = -ENXIO; + goto out_2; + } + nfc_irq = r->start; + + init_waitqueue_head(&irq_waitq); + error = request_irq(nfc_irq, mxc_nfc_irq, 0, "mxc_nd", NULL); + if (error) + goto out_3; + + return 0; +out_3: +out_2: + if (!MXC_NFC_NO_IP_REG) + iounmap(nfc_ip_base); +out_1: + iounmap(nfc_axi_base); +out_0: + return error; +} + static void mxc_nfc_init(void) { /* Disable interrupt */ @@ -1137,11 +1286,13 @@ static void mxc_nfc_init(void) /* Unlock the internal RAM Buffer */ raw_write(NFC_SET_BLS(NFC_BLS_UNLCOKED), REG_NFC_BLS); - /* Blocks to be unlocked */ - UNLOCK_ADDR(0x0, 0xFFFF); + if (!(cpu_is_mx53())) { + /* Blocks to be unlocked */ + UNLOCK_ADDR(0x0, 0xFFFF); - /* Unlock Block Command for given address range */ - raw_write(NFC_SET_WPC(NFC_WPC_UNLOCK), REG_NFC_WPC); + /* Unlock Block Command for given address range */ + raw_write(NFC_SET_WPC(NFC_WPC_UNLOCK), REG_NFC_WPC); + } /* Enable symetric mode by default except mx37TO1.0 */ if (!(cpu_is_mx37_rev(CHIP_REV_1_0) == 1)) @@ -1232,6 +1383,81 @@ int nand_scan_mid(struct mtd_info *mtd) return 0; } +/*! + * show_device_disable_bi_swap() + * Shows the value of the 'disable_bi_swap' flag. + * + * @dev: The device of interest. + * @attr: The attribute of interest. + * @buf: A buffer that will receive a representation of the attribute. + */ +static ssize_t show_device_disable_bi_swap(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", mxc_nand_data->disable_bi_swap); +} + +/*! + * store_device_disable_bi_swap() + * Sets the value of the 'disable_bi_swap' flag. + * + * @dev: The device of interest. + * @attr: The attribute of interest. + * @buf: A buffer containing a new attribute value. + * @size: The size of the buffer. + */ +static ssize_t store_device_disable_bi_swap(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + const char *p = buf; + unsigned long v; + + /* Try to make sense of what arrived from user space. */ + + if (strict_strtoul(p, 0, &v) < 0) + return size; + + if (v > 0) + v = 1; + mxc_nand_data->disable_bi_swap = v; + return size; + +} + +static DEVICE_ATTR(disable_bi_swap, 0644, + show_device_disable_bi_swap, store_device_disable_bi_swap); +static struct device_attribute *device_attributes[] = { + &dev_attr_disable_bi_swap, +}; +/*! + * manage_sysfs_files() - Creates/removes sysfs files for this device. + * + * @create: create/remove the sys entry. + */ +static void manage_sysfs_files(int create) +{ + struct device *dev = mxc_nand_data->dev; + int error; + unsigned int i; + struct device_attribute **attr; + + for (i = 0, attr = device_attributes; + i < ARRAY_SIZE(device_attributes); i++, attr++) { + + if (create) { + error = device_create_file(dev, *attr); + if (error) { + while (--attr >= device_attributes) + device_remove_file(dev, *attr); + return; + } + } else { + device_remove_file(dev, *attr); + } + } + +} + /*! * This function is called during the driver binding process. @@ -1249,8 +1475,10 @@ static int __init mxcnd_probe(struct platform_device *pdev) struct flash_platform_data *flash = pdev->dev.platform_data; int nr_parts = 0, err = 0; - nfc_axi_base = IO_ADDRESS(NFC_AXI_BASE_ADDR); - nfc_ip_base = IO_ADDRESS(NFC_BASE_ADDR); + /* get the resource */ + err = mxc_get_resources(pdev); + if (err) + goto out; /* init the nfc */ mxc_nfc_init(); @@ -1298,12 +1526,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) nfc_clk = clk_get(&pdev->dev, "nfc_clk"); clk_enable(nfc_clk); - - init_waitqueue_head(&irq_waitq); - err = request_irq(MXC_INT_NANDFC, mxc_nfc_irq, 0, "mxc_nd", NULL); - if (err) { - goto out_1; - } + mxc_nand_data->clk_active = 1; if (hardware_ecc) { this->ecc.read_page = mxc_nand_read_page; @@ -1359,6 +1582,16 @@ static int __init mxcnd_probe(struct platform_device *pdev) add_mtd_device(mtd); } +#ifdef CONFIG_MODULE_CCXMX51 + { + extern u8 ccwmx51_swap_bi; + mxc_nand_data->disable_bi_swap = !ccwmx51_swap_bi; + pr_info("%sUsing swap BI (%x)\n", ccwmx51_swap_bi ? "" : "No ", ccwmx51_swap_bi); + } +#endif + /* Create sysfs entries for this device. */ + manage_sysfs_files(true); + platform_set_drvdata(pdev, mtd); return 0; @@ -1386,15 +1619,16 @@ static int __exit mxcnd_remove(struct platform_device *pdev) if (flash->exit) flash->exit(); + manage_sysfs_files(false); mxc_free_buf(); - clk_disable(nfc_clk); + mxc_nand_clk_disable(); clk_put(nfc_clk); platform_set_drvdata(pdev, NULL); if (mxc_nand_data) { nand_release(mtd); - free_irq(MXC_INT_NANDFC, NULL); + free_irq(nfc_irq, NULL); kfree(mxc_nand_data); } @@ -1419,7 +1653,7 @@ static int mxcnd_suspend(struct platform_device *pdev, pm_message_t state) DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND2 : NAND suspend\n"); /* Disable the NFC clock */ - clk_disable(nfc_clk); + mxc_nand_clk_disable(); return 0; } @@ -1438,7 +1672,7 @@ static int mxcnd_resume(struct platform_device *pdev) DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND2 : NAND resume\n"); /* Enable the NFC clock */ - clk_enable(nfc_clk); + mxc_nand_clk_enable(); return 0; } diff --git a/drivers/mtd/nand/mxc_nd2.h b/drivers/mtd/nand/mxc_nd2.h index ea128f6da41b..e8ef125ce8e7 100644 --- a/drivers/mtd/nand/mxc_nd2.h +++ b/drivers/mtd/nand/mxc_nd2.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -32,16 +32,37 @@ #define IS_LARGE_PAGE_NAND ((mtd->writesize / num_of_interleave) > 512) #define GET_NAND_OOB_SIZE (mtd->oobsize / num_of_interleave) +#define GET_NAND_PAGE_SIZE (mtd->writesize / num_of_interleave) #define NAND_PAGESIZE_2KB 2048 #define NAND_PAGESIZE_4KB 4096 +/* + * main area for bad block marker is in the last data section + * the spare area for swapped bad block marker is the second + * byte of last spare section + */ +#define NAND_SECTIONS (GET_NAND_PAGE_SIZE >> 9) +#define NAND_OOB_PER_SECTION (((GET_NAND_OOB_SIZE / NAND_SECTIONS) >> 1) << 1) +#define NAND_CHUNKS (GET_NAND_PAGE_SIZE / (512 + NAND_OOB_PER_SECTION)) + +#define BAD_BLK_MARKER_MAIN_OFFS \ + (GET_NAND_PAGE_SIZE - NAND_CHUNKS * NAND_OOB_PER_SECTION) + +#define BAD_BLK_MARKER_SP_OFFS (NAND_CHUNKS * SPARE_LEN) + +#define BAD_BLK_MARKER_OOB_OFFS (NAND_CHUNKS * NAND_OOB_PER_SECTION) + +#define BAD_BLK_MARKER_MAIN \ + ((u32)MAIN_AREA0 + BAD_BLK_MARKER_MAIN_OFFS) + +#define BAD_BLK_MARKER_SP \ + ((u32)SPARE_AREA0 + BAD_BLK_MARKER_SP_OFFS) + #ifdef CONFIG_ARCH_MXC_HAS_NFC_V3 /* * For V3 NFC registers Definition */ -/* AXI Bus Mapped */ -#define NFC_AXI_BASE_ADDR MX51_NFC_BASE_ADDR_AXI #if defined(CONFIG_ARCH_MXC_HAS_NFC_V3_1) /* mx37 */ #define MXC_INT_NANDFC MXC_INT_EMI @@ -106,13 +127,6 @@ #define NFC_SPAS_WIDTH 8 #define NFC_SPAS_SHIFT 16 -#define IS_4BIT_ECC \ -( \ - cpu_is_mx51_rev(CHIP_REV_2_0) > 0 ? \ - !((raw_read(NFC_CONFIG2) & NFC_ECC_MODE_4) >> 6) : \ - ((raw_read(NFC_CONFIG2) & NFC_ECC_MODE_4) >> 6) \ -) - #define NFC_SET_SPAS(v) \ raw_write((((raw_read(NFC_CONFIG2) & \ NFC_FIELD_RESET(NFC_SPAS_WIDTH, NFC_SPAS_SHIFT)) | ((v) << 16))), \ @@ -120,24 +134,32 @@ #define NFC_SET_ECC_MODE(v) \ do { \ - if (cpu_is_mx51_rev(CHIP_REV_2_0) > 0) { \ + if (cpu_is_mx53() > 0) { \ if ((v) == NFC_SPAS_218 || (v) == NFC_SPAS_112) \ raw_write(((raw_read(NFC_CONFIG2) & \ - NFC_ECC_MODE_MASK) | \ - NFC_ECC_MODE_4), NFC_CONFIG2); \ + ~(3 << 6)) | \ + NFC_ECC_MODE_16), NFC_CONFIG2); \ else \ raw_write(((raw_read(NFC_CONFIG2) & \ - NFC_ECC_MODE_MASK) & \ + ~(3 << 6)) & \ + NFC_ECC_MODE_4), NFC_CONFIG2); \ + } else if (cpu_is_mx51_rev(CHIP_REV_2_0) > 0) { \ + if ((v) == NFC_SPAS_218 || (v) == NFC_SPAS_112) \ + raw_write(((raw_read(NFC_CONFIG2) & \ + ~(1 << 6)) | \ NFC_ECC_MODE_8), NFC_CONFIG2); \ + else \ + raw_write(((raw_read(NFC_CONFIG2) & \ + ~(1 << 6)) & \ + ~NFC_ECC_MODE_8), NFC_CONFIG2); \ } else { \ if ((v) == NFC_SPAS_218 || (v) == NFC_SPAS_112) \ raw_write(((raw_read(NFC_CONFIG2) & \ - NFC_ECC_MODE_MASK) & \ - NFC_ECC_MODE_8), NFC_CONFIG2); \ + ~(1 << 6))), NFC_CONFIG2); \ else \ raw_write(((raw_read(NFC_CONFIG2) & \ - NFC_ECC_MODE_MASK) | \ - NFC_ECC_MODE_4), NFC_CONFIG2); \ + ~(1 << 6)) | \ + NFC_ECC_MODE_8), NFC_CONFIG2); \ } \ } while (0) @@ -151,7 +173,6 @@ do { \ } while(0) #else -#define IS_4BIT_ECC 1 #define NFC_SET_SPAS(v) #define NFC_SET_ECC_MODE(v) #define NFC_SET_NFMS(v) (NFMS |= (v)) @@ -292,9 +313,10 @@ do { \ #define NFC_WPC_RESET ~(7) #if defined(CONFIG_ARCH_MXC_HAS_NFC_V3_1) || \ defined(CONFIG_ARCH_MXC_HAS_NFC_V3_2) -#define NFC_ECC_MODE_4 (1 << 6) -#define NFC_ECC_MODE_8 ~(1 << 6) -#define NFC_ECC_MODE_MASK ~(1 << 6) +#define NFC_ECC_MODE_4 (0x0 << 6) +#define NFC_ECC_MODE_8 (0x1 << 6) +#define NFC_ECC_MODE_14 (0x3 << 6) +#define NFC_ECC_MODE_16 (0x3 << 6) #define NFC_SPAS_16 8 #define NFC_SPAS_64 32 #define NFC_SPAS_128 64 @@ -454,7 +476,8 @@ do { \ NFC_SET_ST_CMD(0x70); \ raw_write(raw_read(NFC_CONFIG3) | NFC_NO_SDMA, NFC_CONFIG3); \ raw_write(raw_read(NFC_CONFIG3) | NFC_RBB_MODE, NFC_CONFIG3); \ - SET_NFC_DELAY_LINE(0); \ + if (cpu_is_mx51()) \ + SET_NFC_DELAY_LINE(0); \ } \ } while (0) #endif @@ -472,14 +495,13 @@ do { \ * For V1/V2 NFC registers Definition */ -#define NFC_AXI_BASE_ADDR 0x00 /* * Addresses for NFC registers */ #ifdef CONFIG_ARCH_MXC_HAS_NFC_V2_1 -#define NFC_REG_BASE (nfc_ip_base + 0x1000) +#define NFC_REG_BASE (nfc_axi_base + 0x1000) #else -#define NFC_REG_BASE nfc_ip_base +#define NFC_REG_BASE nfc_axi_base #endif #define NFC_BUF_SIZE (NFC_REG_BASE + 0xE00) #define NFC_BUF_ADDR (NFC_REG_BASE + 0xE04) @@ -517,18 +539,18 @@ do { \ /*! * Addresses for NFC RAM BUFFER Main area 0 */ -#define MAIN_AREA0 (u16 *)(nfc_ip_base + 0x000) -#define MAIN_AREA1 (u16 *)(nfc_ip_base + 0x200) +#define MAIN_AREA0 (u16 *)(nfc_axi_base + 0x000) +#define MAIN_AREA1 (u16 *)(nfc_axi_base + 0x200) /*! * Addresses for NFC SPARE BUFFER Spare area 0 */ #ifdef CONFIG_ARCH_MXC_HAS_NFC_V2_1 -#define SPARE_AREA0 (u16 *)(nfc_ip_base + 0x1000) +#define SPARE_AREA0 (u16 *)(nfc_axi_base + 0x1000) #define SPARE_LEN 64 #define SPARE_COUNT 8 #else -#define SPARE_AREA0 (u16 *)(nfc_ip_base + 0x800) +#define SPARE_AREA0 (u16 *)(nfc_axi_base + 0x800) #define SPARE_LEN 16 #define SPARE_COUNT 4 #endif @@ -539,8 +561,6 @@ do { \ #define SPAS_SHIFT (0) #define REG_NFC_SPAS NFC_SPAS #define SPAS_MASK (0xFF00) -#define IS_4BIT_ECC \ - ((raw_read(REG_NFC_ECC_MODE) & NFC_ECC_MODE_4) >> 0) #define NFC_SET_SPAS(v) \ raw_write(((raw_read(REG_NFC_SPAS) & SPAS_MASK) | ((v<<SPAS_SHIFT))), \ @@ -578,7 +598,6 @@ do { \ } \ } while (0) #else -#define IS_4BIT_ECC (1) #define NFC_SET_SPAS(v) #define NFC_SET_ECC_MODE(v) #define GET_ECC_STATUS() raw_read(REG_NFC_ECC_STATUS_RESULT); diff --git a/drivers/mtd/nand/nand_device_info.c b/drivers/mtd/nand/nand_device_info.c index ecd5b21189cc..1ab1d1d21811 100644 --- a/drivers/mtd/nand/nand_device_info.c +++ b/drivers/mtd/nand/nand_device_info.c @@ -1,5 +1,5 @@ /* - * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -1284,9 +1284,9 @@ static struct nand_device_info nand_device_info_table_type_9[] __initdata = .data_hold_in_ns = 10, .address_setup_in_ns = 25, .gpmi_sample_delay_in_ns = 6, - .tREA_in_ns = -1, - .tRLOH_in_ns = -1, - .tRHOH_in_ns = -1, + .tREA_in_ns = 20, + .tRLOH_in_ns = 5, + .tRHOH_in_ns = 15, "K9LBG08U0D", }, { diff --git a/drivers/mxc/Kconfig b/drivers/mxc/Kconfig index 6e67087d2efa..b26c1dc11ad6 100644 --- a/drivers/mxc/Kconfig +++ b/drivers/mxc/Kconfig @@ -33,6 +33,7 @@ source "drivers/mxc/bt/Kconfig" source "drivers/mxc/gps_ioctrl/Kconfig" source "drivers/mxc/mlb/Kconfig" source "drivers/mxc/adc/Kconfig" +source "drivers/mxc/amd-gpu/Kconfig" endmenu diff --git a/drivers/mxc/Makefile b/drivers/mxc/Makefile index 6416bc429888..5193fa50eb9f 100644 --- a/drivers/mxc/Makefile +++ b/drivers/mxc/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_MXC_BLUETOOTH) += bt/ obj-$(CONFIG_GPS_IOCTRL) += gps_ioctrl/ obj-$(CONFIG_MXC_MLB) += mlb/ obj-$(CONFIG_IMX_ADC) += adc/ +obj-$(CONFIG_MXC_AMD_GPU) += amd-gpu/ diff --git a/drivers/mxc/ipu/ipu_common.c b/drivers/mxc/ipu/ipu_common.c index 43ba100b5c5d..a1dc566e7f8f 100644 --- a/drivers/mxc/ipu/ipu_common.c +++ b/drivers/mxc/ipu/ipu_common.c @@ -707,6 +707,38 @@ int32_t ipu_select_buffer(ipu_channel_t channel, ipu_buffer_t type, } /*! + * This function check buffer ready for a logical channel. + * + * @param channel Input parameter for the logical channel ID. + * + * @param type Input parameter which buffer to clear. + * + * @param bufNum Input parameter for which buffer number clear + * ready state. + * + */ +int32_t ipu_check_buffer_busy(ipu_channel_t channel, ipu_buffer_t type, + uint32_t bufNum) +{ + uint32_t dma_chan = channel_2_dma(channel, type); + uint32_t reg; + + if (dma_chan == IDMA_CHAN_INVALID) + return -EINVAL; + + if (bufNum == 0) + reg = __raw_readl(IPU_CHA_BUF0_RDY); + else + reg = __raw_readl(IPU_CHA_BUF1_RDY); + + if (reg & (1UL << dma_chan)) + return 1; + else + return 0; +} +EXPORT_SYMBOL(ipu_check_buffer_busy); + +/*! * This function links 2 channels together for automatic frame * synchronization. The output of the source channel is linked to the input of * the destination channel. diff --git a/drivers/mxc/ipu/ipu_csi.c b/drivers/mxc/ipu/ipu_csi.c index 10708cf3ba54..58d58c10af51 100644 --- a/drivers/mxc/ipu/ipu_csi.c +++ b/drivers/mxc/ipu/ipu_csi.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -90,10 +90,13 @@ ipu_csi_init_interface(uint16_t width, uint16_t height, uint32_t pixel_fmt, __raw_writel(height << 16 | 0x22, CSI_FLASH_STROBE_2); /* Set CCIR registers */ - if ((sig.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) || - (sig.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED)) { + if (sig.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) { __raw_writel(0x40030, CSI_CCIR_CODE_1); __raw_writel(0xFF0000, CSI_CCIR_CODE_3); + } else if (sig.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED) { + __raw_writel(0xD07DF, CSI_CCIR_CODE_1); + __raw_writel(0x40596, CSI_CCIR_CODE_2); + __raw_writel(0xFF0000, CSI_CCIR_CODE_3); } dev_dbg(g_ipu_dev, "CSI_SENS_CONF = 0x%08X\n", diff --git a/drivers/mxc/ipu/ipu_device.c b/drivers/mxc/ipu/ipu_device.c index 5fd1c51ec9b1..713ba2005ae9 100644 --- a/drivers/mxc/ipu/ipu_device.c +++ b/drivers/mxc/ipu/ipu_device.c @@ -169,6 +169,7 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file, sizeof(ipu_channel_buf_parm))) { return -EFAULT; } + ret = ipu_init_channel_buffer(parm.channel, parm.type, parm.pixel_fmt, diff --git a/drivers/mxc/ipu/ipu_ic.c b/drivers/mxc/ipu/ipu_ic.c index cdf823a2760b..9fe087590368 100644 --- a/drivers/mxc/ipu/ipu_ic.c +++ b/drivers/mxc/ipu/ipu_ic.c @@ -71,8 +71,7 @@ void _ipu_ic_enable_task(ipu_channel_t channel) case MEM_ROT_PP_MEM: ic_conf |= IC_CONF_PP_ROT_EN; break; - case CSI_MEM: - // ??? + case CSI_MEM1: ic_conf |= IC_CONF_RWS_EN | IC_CONF_PRPENC_EN; break; default: @@ -110,8 +109,7 @@ void _ipu_ic_disable_task(ipu_channel_t channel) case MEM_ROT_PP_MEM: ic_conf &= ~IC_CONF_PP_ROT_EN; break; - case CSI_MEM: - // ??? + case CSI_MEM1: ic_conf &= ~(IC_CONF_RWS_EN | IC_CONF_PRPENC_EN); break; default: diff --git a/drivers/mxc/ipu/pf/mxc_pf.c b/drivers/mxc/ipu/pf/mxc_pf.c index 744152415e3a..8abffb4d8d44 100644 --- a/drivers/mxc/ipu/pf/mxc_pf.c +++ b/drivers/mxc/ipu/pf/mxc_pf.c @@ -108,6 +108,7 @@ static int mxc_pf_init(pf_init_params * pf_init) memset(¶ms, 0, sizeof(params)); params.mem_pf_mem.operation = pf_data.mode; + err = ipu_init_channel(MEM_PF_Y_MEM, ¶ms); if (err < 0) { printk(KERN_ERR "mxc_pf: error initializing channel\n"); diff --git a/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c index 6a29c90fe095..5d5e0b9155a0 100644 --- a/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c +++ b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c @@ -260,7 +260,7 @@ int ipu_calc_stripes_sizes(const unsigned int input_frame_width, input_frame_width >> 1; left->output_width = right->output_width = right->output_column = output_frame_width >> 1; - left->input_column = right->input_column = 0; + left->input_column = 0; div = _do_div(((((u64)irr_steps) << 32) * (right->input_width - 1)), (right->output_width - 1)); left->irr = right->irr = truncate(0, div, 1); diff --git a/drivers/mxc/ipu3/ipu_capture.c b/drivers/mxc/ipu3/ipu_capture.c index 5d084ab37b0b..b9967135eac1 100644 --- a/drivers/mxc/ipu3/ipu_capture.c +++ b/drivers/mxc/ipu3/ipu_capture.c @@ -26,6 +26,7 @@ #include <linux/delay.h> #include <linux/ipu.h> #include <linux/clk.h> +#include <mach/mxc_dvfs.h> #include "ipu_prv.h" #include "ipu_regs.h" @@ -93,6 +94,12 @@ ipu_csi_init_interface(uint16_t width, uint16_t height, uint32_t pixel_fmt, cfg_param.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT | cfg_param.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); __raw_writel(data, CSI_SENS_CONF(csi)); @@ -101,11 +108,18 @@ ipu_csi_init_interface(uint16_t width, uint16_t height, uint32_t pixel_fmt, __raw_writel((width - 1) | (height - 1) << 16, CSI_SENS_FRM_SIZE(csi)); /* Set CCIR registers */ - if ((cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) || - (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED)) { - _ipu_csi_ccir_err_detection_enable(csi); + if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) { __raw_writel(0x40030, CSI_CCIR_CODE_1(csi)); __raw_writel(0xFF0000, CSI_CCIR_CODE_3(csi)); + } else if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED) { + _ipu_csi_ccir_err_detection_enable(csi); + /* Field0BlankEnd = 0x7, Field0BlankStart = 0x3, + Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1 */ + __raw_writel(0xD07DF, CSI_CCIR_CODE_1(csi)); + /* Field1BlankEnd = 0x6, Field1BlankStart = 0x2, + Field1ActiveEnd = 0x4, Field1ActiveStart = 0 */ + __raw_writel(0x40596, CSI_CCIR_CODE_2(csi)); + __raw_writel(0xFF0000, CSI_CCIR_CODE_3(csi)); } else if ((cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR) || (cfg_param.clk_mode == @@ -171,34 +185,13 @@ int _ipu_csi_mclk_set(uint32_t pixel_clk, uint32_t csi) */ int ipu_csi_enable_mclk(int csi, bool flag, bool wait) { - struct clk *clk; if (flag) { - if (cpu_is_mx53()) { - if (csi == 0) { - clk = clk_get(NULL, "ssi_ext1_clk"); - clk_enable(clk); - clk_put(clk); - } else { - pr_err("invalid csi num %d\n", csi); - return -EINVAL; - } - } else - clk_enable(g_csi_clk[csi]); + clk_enable(g_csi_clk[csi]); if (wait == true) msleep(10); } else { - if (cpu_is_mx53()) { - if (csi == 0) { - clk = clk_get(NULL, "ssi_ext1_clk"); - clk_disable(clk); - clk_put(clk); - } else { - pr_err("invalid csi num %d\n", csi); - return -EINVAL; - } - } else - clk_disable(g_csi_clk[csi]); + clk_disable(g_csi_clk[csi]); } return 0; @@ -217,6 +210,12 @@ void ipu_csi_get_window_size(uint32_t *width, uint32_t *height, uint32_t csi) uint32_t reg; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); reg = __raw_readl(CSI_ACT_FRM_SIZE(csi)); @@ -238,6 +237,12 @@ void ipu_csi_set_window_size(uint32_t width, uint32_t height, uint32_t csi) { unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); __raw_writel((width - 1) | (height - 1) << 16, CSI_ACT_FRM_SIZE(csi)); @@ -258,6 +263,12 @@ void ipu_csi_set_window_pos(uint32_t left, uint32_t top, uint32_t csi) uint32_t temp; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_OUT_FRM_CTRL(csi)); @@ -280,6 +291,12 @@ void _ipu_csi_horizontal_downsize_enable(uint32_t csi) uint32_t temp; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_OUT_FRM_CTRL(csi)); @@ -300,6 +317,12 @@ void _ipu_csi_horizontal_downsize_disable(uint32_t csi) uint32_t temp; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_OUT_FRM_CTRL(csi)); @@ -320,6 +343,12 @@ void _ipu_csi_vertical_downsize_enable(uint32_t csi) uint32_t temp; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_OUT_FRM_CTRL(csi)); @@ -340,6 +369,12 @@ void _ipu_csi_vertical_downsize_disable(uint32_t csi) uint32_t temp; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_OUT_FRM_CTRL(csi)); @@ -366,6 +401,12 @@ void ipu_csi_set_test_generator(bool active, uint32_t r_value, uint32_t temp; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_TST_CTRL(csi)); @@ -401,6 +442,12 @@ void _ipu_csi_ccir_err_detection_enable(uint32_t csi) { uint32_t temp; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + temp = __raw_readl(CSI_CCIR_CODE_1(csi)); temp |= CSI_CCIR_ERR_DET_EN; __raw_writel(temp, CSI_CCIR_CODE_1(csi)); @@ -417,6 +464,12 @@ void _ipu_csi_ccir_err_detection_disable(uint32_t csi) { uint32_t temp; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + temp = __raw_readl(CSI_CCIR_CODE_1(csi)); temp &= ~CSI_CCIR_ERR_DET_EN; __raw_writel(temp, CSI_CCIR_CODE_1(csi)); @@ -442,6 +495,12 @@ int _ipu_csi_set_mipi_di(uint32_t num, uint32_t di_val, uint32_t csi) goto err; } + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_MIPI_DI(csi)); @@ -499,6 +558,12 @@ int _ipu_csi_set_skip_isp(uint32_t skip, uint32_t max_ratio, uint32_t csi) goto err; } + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_SKIP(csi)); @@ -536,6 +601,12 @@ int _ipu_csi_set_skip_smfc(uint32_t skip, uint32_t max_ratio, goto err; } + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(CSI_SKIP(csi)); @@ -585,7 +656,6 @@ void _ipu_smfc_init(ipu_channel_t channel, uint32_t mipi_id, uint32_t csi) default: return; } - __raw_writel(temp, SMFC_MAP); } @@ -604,6 +674,12 @@ void _ipu_smfc_set_wmc(ipu_channel_t channel, bool set, uint32_t level) uint32_t temp; unsigned long lock_flags; + if (g_ipu_clk_enabled == false) { + stop_dvfs_per(); + g_ipu_clk_enabled = true; + clk_enable(g_ipu_clk); + } + spin_lock_irqsave(&ipu_lock, lock_flags); temp = __raw_readl(SMFC_WMC); diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c index 68be542e8370..b1b8a8b39ae1 100644 --- a/drivers/mxc/ipu3/ipu_common.c +++ b/drivers/mxc/ipu3/ipu_common.c @@ -52,8 +52,8 @@ unsigned char g_dc_di_assignment[10]; ipu_channel_t g_ipu_csi_channel[2]; int g_ipu_irq[2]; int g_ipu_hw_rev; -bool g_sec_chan_en[22]; -bool g_thrd_chan_en[21]; +bool g_sec_chan_en[24]; +bool g_thrd_chan_en[24]; uint32_t g_channel_init_mask; uint32_t g_channel_enable_mask; DEFINE_SPINLOCK(ipu_lock); @@ -354,8 +354,8 @@ static int ipu_probe(struct platform_device *pdev) g_di_clk[0] = plat_data->di_clk[0]; g_di_clk[1] = plat_data->di_clk[1]; - g_csi_clk[0] = clk_get(&pdev->dev, "csi_mclk1"); - g_csi_clk[1] = clk_get(&pdev->dev, "csi_mclk2"); + g_csi_clk[0] = plat_data->csi_clk[0]; + g_csi_clk[1] = plat_data->csi_clk[1]; __raw_writel(0x807FFFFF, IPU_MEM_RST); while (__raw_readl(IPU_MEM_RST) & 0x80000000) ; @@ -372,7 +372,7 @@ static int ipu_probe(struct platform_device *pdev) _ipu_dmfc_init(DMFC_NORMAL, 1); /* Set sync refresh channels and CSI->mem channel as high priority */ - __raw_writel(0x18800001L, IDMAC_CHA_PRI(0)); + __raw_writel(0x18800003L, IDMAC_CHA_PRI(0)); /* Set MCU_T to divide MCU access window into 2 */ __raw_writel(0x00400000L | (IPU_MCU_T_DEFAULT << 18), IPU_DISP_GEN); @@ -415,7 +415,10 @@ int ipu_remove(struct platform_device *pdev) void ipu_dump_registers(void) { + printk(KERN_DEBUG "--------------------------------------------\n"); printk(KERN_DEBUG "IPU_CONF = \t0x%08X\n", __raw_readl(IPU_CONF)); + printk(KERN_DEBUG "SMFC_MAP = \t0x%08X\n", __raw_readl(SMFC_MAP)); + printk(KERN_DEBUG "SMFC_WMC = \t0x%08X\n", __raw_readl(SMFC_WMC)); printk(KERN_DEBUG "IDMAC_CONF = \t0x%08X\n", __raw_readl(IDMAC_CONF)); printk(KERN_DEBUG "IDMAC_CHA_EN1 = \t0x%08X\n", __raw_readl(IDMAC_CHA_EN(0))); @@ -451,6 +454,25 @@ void ipu_dump_registers(void) __raw_readl(IPU_FS_PROC_FLOW3)); printk(KERN_DEBUG "IPU_FS_DISP_FLOW1 = \t0x%08X\n", __raw_readl(IPU_FS_DISP_FLOW1)); + + printk(KERN_DEBUG "IPU_INT_CTRL_1 = \t0x%08X\n", __raw_readl(IPU_INT_CTRL (1))); + printk(KERN_DEBUG "IPU_INT_STAT_1 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (1))); + printk(KERN_DEBUG "IPU_INT_STAT_2 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (2))); + printk(KERN_DEBUG "IPU_INT_STAT_3 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (3))); + printk(KERN_DEBUG "IPU_INT_STAT_4 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (4))); + printk(KERN_DEBUG "IPU_INT_STAT_5 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (5))); + printk(KERN_DEBUG "IPU_INT_STAT_6 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (6))); + + printk(KERN_DEBUG "CSI0_SENS_CONF = \t0x%08X\n", __raw_readl(CSI_SENS_CONF (0))); + printk(KERN_DEBUG "CSI0_SENS_FRM_SIZE = \t0x%08X\n", __raw_readl(CSI_SENS_FRM_SIZE(0))); + printk(KERN_DEBUG "CSI0_ACT_FRM_SIZE = \t0x%08X\n", __raw_readl(CSI_ACT_FRM_SIZE(0))); + printk(KERN_DEBUG "CSI0_SKIP = \t0x%08X\n", __raw_readl(CSI_SKIP(0))); + + printk(KERN_DEBUG "CSI1_SENS_CONF = \t0x%08X\n", __raw_readl(CSI_SENS_CONF (1))); + printk(KERN_DEBUG "CSI1_SENS_FRM_SIZE = \t0x%08X\n", __raw_readl(CSI_SENS_FRM_SIZE(1))); + printk(KERN_DEBUG "CSI1_ACT_FRM_SIZE = \t0x%08X\n", __raw_readl(CSI_ACT_FRM_SIZE(1))); + printk(KERN_DEBUG "CSI1_SKIP = \t0x%08X\n", __raw_readl(CSI_SKIP(1))); + printk(KERN_DEBUG "--------------------------------------------\n"); } /*! @@ -660,7 +682,8 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) g_dc_di_assignment[1] = params->mem_dc_sync.di; _ipu_dc_init(1, params->mem_dc_sync.di, - params->mem_dc_sync.interlaced); + params->mem_dc_sync.interlaced, + params->mem_dc_sync.out_pixel_fmt); ipu_di_use_count[params->mem_dc_sync.di]++; ipu_dc_use_count++; ipu_dmfc_use_count++; @@ -678,7 +701,8 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) _ipu_dp_init(channel, params->mem_dp_bg_sync.in_pixel_fmt, params->mem_dp_bg_sync.out_pixel_fmt); _ipu_dc_init(5, params->mem_dp_bg_sync.di, - params->mem_dp_bg_sync.interlaced); + params->mem_dp_bg_sync.interlaced, + params->mem_dp_bg_sync.out_pixel_fmt); ipu_di_use_count[params->mem_dp_bg_sync.di]++; ipu_dc_use_count++; ipu_dp_use_count++; @@ -702,7 +726,7 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) } g_dc_di_assignment[8] = params->direct_async.di; - _ipu_dc_init(8, params->direct_async.di, false); + _ipu_dc_init(8, params->direct_async.di, false, IPU_PIX_FMT_GENERIC); ipu_di_use_count[params->direct_async.di]++; ipu_dc_use_count++; break; @@ -713,7 +737,7 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) } g_dc_di_assignment[9] = params->direct_async.di; - _ipu_dc_init(9, params->direct_async.di, false); + _ipu_dc_init(9, params->direct_async.di, false, IPU_PIX_FMT_GENERIC); ipu_di_use_count[params->direct_async.di]++; ipu_dc_use_count++; break; @@ -724,31 +748,8 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) /* Enable IPU sub module */ g_channel_init_mask |= 1L << IPU_CHAN_ID(channel); - if (ipu_ic_use_count == 1) - ipu_conf |= IPU_CONF_IC_EN; - if (ipu_vdi_use_count == 1) { - ipu_conf |= IPU_CONF_VDI_EN; - ipu_conf |= IPU_CONF_IC_INPUT; - } - if (ipu_rot_use_count == 1) - ipu_conf |= IPU_CONF_ROT_EN; - if (ipu_dc_use_count == 1) - ipu_conf |= IPU_CONF_DC_EN; - if (ipu_dp_use_count == 1) - ipu_conf |= IPU_CONF_DP_EN; - if (ipu_dmfc_use_count == 1) - ipu_conf |= IPU_CONF_DMFC_EN; - if (ipu_di_use_count[0] == 1) { - ipu_conf |= IPU_CONF_DI0_EN; - } - if (ipu_di_use_count[1] == 1) { - ipu_conf |= IPU_CONF_DI1_EN; - } - if (ipu_smfc_use_count == 1) - ipu_conf |= IPU_CONF_SMFC_EN; __raw_writel(ipu_conf, IPU_CONF); - err: spin_unlock_irqrestore(&ipu_lock, lock_flags); return ret; @@ -775,8 +776,8 @@ void ipu_uninit_channel(ipu_channel_t channel) /* Make sure channel is disabled */ /* Get input and output dma channels */ - in_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER); - out_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER); + in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER); + out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER); if (idma_is_set(IDMAC_CHA_EN, in_dma) || idma_is_set(IDMAC_CHA_EN, out_dma)) { @@ -796,8 +797,10 @@ void ipu_uninit_channel(ipu_channel_t channel) reg = __raw_readl(IPU_CHA_DB_MODE_SEL(out_dma)); __raw_writel(reg & ~idma_mask(out_dma), IPU_CHA_DB_MODE_SEL(out_dma)); - g_sec_chan_en[IPU_CHAN_ID(channel)] = false; - g_thrd_chan_en[IPU_CHAN_ID(channel)] = false; + if (_ipu_is_ic_chan(in_dma) || _ipu_is_dp_graphic_chan(in_dma)) { + g_sec_chan_en[IPU_CHAN_ID(channel)] = false; + g_thrd_chan_en[IPU_CHAN_ID(channel)] = false; + } switch (channel) { case CSI_MEM0: @@ -849,6 +852,9 @@ void ipu_uninit_channel(ipu_channel_t channel) reg = __raw_readl(IPU_FS_PROC_FLOW1); __raw_writel(reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1); break; + case MEM_VDI_PRP_VF_MEM_P: + case MEM_VDI_PRP_VF_MEM_N: + break; case MEM_ROT_VF_MEM: ipu_rot_use_count--; ipu_ic_use_count--; @@ -913,6 +919,7 @@ void ipu_uninit_channel(ipu_channel_t channel) if (ipu_ic_use_count == 0) ipu_conf &= ~IPU_CONF_IC_EN; if (ipu_vdi_use_count == 0) { + ipu_conf &= ~IPU_CONF_ISP_EN; ipu_conf &= ~IPU_CONF_VDI_EN; ipu_conf &= ~IPU_CONF_IC_INPUT; } @@ -1239,8 +1246,6 @@ int32_t ipu_select_buffer(ipu_channel_t channel, ipu_buffer_t type, __raw_writel(idma_mask(dma_chan) | reg, IPU_CHA_BUF1_RDY(dma_chan)); } - if (channel == MEM_VDI_PRP_VF_MEM) - _ipu_vdi_toggle_top_field_man(); return 0; } EXPORT_SYMBOL(ipu_select_buffer); @@ -1269,10 +1274,9 @@ int32_t ipu_select_multi_vdi_buffer(uint32_t bufNum) __raw_writel(mask_bit | reg, IPU_CHA_BUF0_RDY(dma_chan)); } else { /*Mark buffer 1 as ready. */ - reg = __raw_readl(IPU_CHA_BUF0_RDY(dma_chan)); + reg = __raw_readl(IPU_CHA_BUF1_RDY(dma_chan)); __raw_writel(mask_bit | reg, IPU_CHA_BUF1_RDY(dma_chan)); } - _ipu_vdi_toggle_top_field_man(); return 0; } EXPORT_SYMBOL(ipu_select_multi_vdi_buffer); @@ -1282,7 +1286,7 @@ static int proc_dest_sel[] = { 0, 1, 1, 3, 5, 5, 4, 7, 8, 9, 10, 11, 12, 14, 15, 16, 0, 1, 1, 5, 5, 5, 5, 5, 7, 8, 9, 10, 11, 12, 14, 31 }; static int proc_src_sel[] = { 0, 6, 7, 6, 7, 8, 5, NA, NA, NA, - NA, NA, NA, NA, NA, 1, 2, 3, 4, 7, 8, NA, NA, NA }; + NA, NA, NA, NA, NA, 1, 2, 3, 4, 7, 8, NA, 8, NA }; static int disp_src_sel[] = { 0, 6, 7, 8, 3, 4, 5, NA, NA, NA, NA, NA, NA, NA, NA, 1, NA, 2, NA, 3, 4, 4, 4, 4 }; @@ -1659,6 +1663,7 @@ int32_t ipu_enable_channel(ipu_channel_t channel) { uint32_t reg; unsigned long lock_flags; + uint32_t ipu_conf; uint32_t in_dma; uint32_t out_dma; uint32_t sec_dma; @@ -1675,6 +1680,32 @@ int32_t ipu_enable_channel(ipu_channel_t channel) spin_lock_irqsave(&ipu_lock, lock_flags); + ipu_conf = __raw_readl(IPU_CONF); + if (ipu_di_use_count[0] > 0) { + ipu_conf |= IPU_CONF_DI0_EN; + } + if (ipu_di_use_count[1] > 0) { + ipu_conf |= IPU_CONF_DI1_EN; + } + if (ipu_dp_use_count > 0) + ipu_conf |= IPU_CONF_DP_EN; + if (ipu_dc_use_count > 0) + ipu_conf |= IPU_CONF_DC_EN; + if (ipu_dmfc_use_count > 0) + ipu_conf |= IPU_CONF_DMFC_EN; + if (ipu_ic_use_count > 0) + ipu_conf |= IPU_CONF_IC_EN; + if (ipu_vdi_use_count > 0) { + ipu_conf |= IPU_CONF_ISP_EN; + ipu_conf |= IPU_CONF_VDI_EN; + ipu_conf |= IPU_CONF_IC_INPUT; + } + if (ipu_rot_use_count > 0) + ipu_conf |= IPU_CONF_ROT_EN; + if (ipu_smfc_use_count > 0) + ipu_conf |= IPU_CONF_SMFC_EN; + __raw_writel(ipu_conf, IPU_CONF); + if (idma_is_valid(in_dma)) { reg = __raw_readl(IDMAC_CHA_EN(in_dma)); __raw_writel(reg | idma_mask(in_dma), IDMAC_CHA_EN(in_dma)); @@ -1710,8 +1741,11 @@ int32_t ipu_enable_channel(ipu_channel_t channel) } if ((channel == MEM_DC_SYNC) || (channel == MEM_BG_SYNC) || - (channel == MEM_FG_SYNC)) + (channel == MEM_FG_SYNC)) { + reg = __raw_readl(IDMAC_WM_EN(in_dma)); + __raw_writel(reg | idma_mask(in_dma), IDMAC_WM_EN(in_dma)); _ipu_dp_dc_enable(channel); + } if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) || _ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma)) @@ -1726,6 +1760,38 @@ int32_t ipu_enable_channel(ipu_channel_t channel) EXPORT_SYMBOL(ipu_enable_channel); /*! + * This function check buffer ready for a logical channel. + * + * @param channel Input parameter for the logical channel ID. + * + * @param type Input parameter which buffer to clear. + * + * @param bufNum Input parameter for which buffer number clear + * ready state. + * + */ +int32_t ipu_check_buffer_busy(ipu_channel_t channel, ipu_buffer_t type, + uint32_t bufNum) +{ + uint32_t dma_chan = channel_2_dma(channel, type); + uint32_t reg; + + if (dma_chan == IDMA_CHAN_INVALID) + return -EINVAL; + + if (bufNum == 0) + reg = __raw_readl(IPU_CHA_BUF0_RDY(dma_chan)); + else + reg = __raw_readl(IPU_CHA_BUF1_RDY(dma_chan)); + + if (reg & idma_mask(dma_chan)) + return 1; + else + return 0; +} +EXPORT_SYMBOL(ipu_check_buffer_busy); + +/*! * This function clear buffer ready for a logical channel. * * @param channel Input parameter for the logical channel ID. @@ -1817,7 +1883,30 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop) if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) || (channel == MEM_DC_SYNC)) { + if (channel == MEM_FG_SYNC) + ipu_disp_set_window_pos(channel, 0, 0); + _ipu_dp_dc_disable(channel, false); + + /* + * wait for BG channel EOF then disable FG-IDMAC, + * it avoid FG NFB4EOF error. + */ + if (channel == MEM_FG_SYNC) { + int timeout = 50; + + __raw_writel(IPUIRQ_2_MASK(IPU_IRQ_BG_SYNC_EOF), + IPUIRQ_2_STATREG(IPU_IRQ_BG_SYNC_EOF)); + while ((__raw_readl(IPUIRQ_2_STATREG(IPU_IRQ_BG_SYNC_EOF)) & + IPUIRQ_2_MASK(IPU_IRQ_BG_SYNC_EOF)) == 0) { + msleep(10); + timeout -= 10; + if (timeout <= 0) { + dev_err(g_ipu_dev, "warning: wait for bg sync eof timeout\n"); + break; + } + } + } } else if (wait_for_stop) { while (idma_is_set(IDMAC_CHA_BUSY, in_dma) || idma_is_set(IDMAC_CHA_BUSY, out_dma) || @@ -1861,6 +1950,12 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop) spin_lock_irqsave(&ipu_lock, lock_flags); + if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) || + (channel == MEM_DC_SYNC)) { + reg = __raw_readl(IDMAC_WM_EN(in_dma)); + __raw_writel(reg & ~idma_mask(in_dma), IDMAC_WM_EN(in_dma)); + } + /* Disable IC task */ if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) || _ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma)) @@ -1897,8 +1992,6 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop) g_channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel)); - spin_unlock_irqrestore(&ipu_lock, lock_flags); - /* Set channel buffers NOT to be ready */ if (idma_is_valid(in_dma)) { ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 0); @@ -1917,6 +2010,8 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop) ipu_clear_buffer_ready(channel, IPU_ALPHA_IN_BUFFER, 1); } + spin_unlock_irqrestore(&ipu_lock, lock_flags); + return 0; } EXPORT_SYMBOL(ipu_disable_channel); @@ -2029,7 +2124,6 @@ static irqreturn_t ipu_irq_handler(int irq, void *desc) dev_id); } } - return result; } diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c index 27455fe26ab6..bf71ea833f58 100644 --- a/drivers/mxc/ipu3/ipu_device.c +++ b/drivers/mxc/ipu3/ipu_device.c @@ -124,7 +124,6 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file, (&parm, (ipu_channel_buf_parm *) arg, sizeof(ipu_channel_buf_parm))) return -EFAULT; - ret = ipu_init_channel_buffer( parm.channel, parm.type, @@ -183,6 +182,17 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file, } break; + case IPU_SELECT_MULTI_VDI_BUFFER: + { + uint32_t parm; + if (copy_from_user + (&parm, (uint32_t *) arg, + sizeof(uint32_t))) + return -EFAULT; + + ret = ipu_select_multi_vdi_buffer(parm); + } + break; case IPU_LINK_CHANNELS: { ipu_channel_link link; @@ -225,7 +235,6 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file, (&info, (ipu_channel_info *) arg, sizeof(ipu_channel_info))) return -EFAULT; - ret = ipu_disable_channel(info.channel, info.stop); } @@ -435,7 +444,7 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file, static int mxc_ipu_mmap(struct file *file, struct vm_area_struct *vma) { -// vma->vm_page_prot = pgprot_writethru(vma->vm_page_prot); + vma->vm_page_prot = pgprot_writethru(vma->vm_page_prot); if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, @@ -452,12 +461,20 @@ static int mxc_ipu_release(struct inode *inode, struct file *file) return 0; } +int mxc_ipu_fsync(struct file *filp, struct dentry *dentry, int datasync) +{ + flush_cache_all(); + outer_flush_all(); + return 0; +} + static struct file_operations mxc_ipu_fops = { .owner = THIS_MODULE, .open = mxc_ipu_open, .mmap = mxc_ipu_mmap, .release = mxc_ipu_release, - .ioctl = mxc_ipu_ioctl + .ioctl = mxc_ipu_ioctl, + .fsync = mxc_ipu_fsync }; int register_ipu_device() diff --git a/drivers/mxc/ipu3/ipu_disp.c b/drivers/mxc/ipu3/ipu_disp.c index 00c5008d149f..14dde404990b 100644 --- a/drivers/mxc/ipu3/ipu_disp.c +++ b/drivers/mxc/ipu3/ipu_disp.c @@ -147,6 +147,37 @@ static int __init dmfc_setup(char *options) } __setup("dmfc=", dmfc_setup); +static bool _ipu_update_dmfc_used_size(int dma_chan, int width, int dmfc_size) +{ + u32 fifo_size_5f = 1; + u32 dmfc_dp_chan = __raw_readl(DMFC_DP_CHAN); + + if ((width > 352) && (dmfc_size == (256 * 4))) + fifo_size_5f = 1; + else if (width > 176) + fifo_size_5f = 2; + else if (width > 88) + fifo_size_5f = 3; + else if (width > 44) + fifo_size_5f = 4; + else if (width > 22) + fifo_size_5f = 5; + else if (width > 11) + fifo_size_5f = 6; + else if (width > 6) + fifo_size_5f = 7; + else + return false; + + if (dma_chan == 27) { + dmfc_dp_chan &= ~DMFC_FIFO_SIZE_5F; + dmfc_dp_chan |= fifo_size_5f << 11; + __raw_writel(dmfc_dp_chan, DMFC_DP_CHAN); + } + + return true; +} + void _ipu_dmfc_set_wait4eot(int dma_chan, int width) { u32 dmfc_gen1 = __raw_readl(DMFC_GENERAL1); @@ -169,7 +200,7 @@ void _ipu_dmfc_set_wait4eot(int dma_chan, int width) else dmfc_gen1 &= ~(1UL << 22); } else if (dma_chan == 27) { /*5F*/ - if (dmfc_size_27/width > 2) + if (!_ipu_update_dmfc_used_size(dma_chan, width, dmfc_size_27)) dmfc_gen1 |= 1UL << 21; else dmfc_gen1 &= ~(1UL << 21); @@ -245,6 +276,24 @@ static void _ipu_di_sync_config(int di, int wave_gen, __raw_writel(reg, DI_STP_REP(di, wave_gen)); } +static void _ipu_dc_map_link(int current_map, + int base_map_0, int buf_num_0, + int base_map_1, int buf_num_1, + int base_map_2, int buf_num_2) +{ + int ptr_0 = base_map_0 * 3 + buf_num_0; + int ptr_1 = base_map_1 * 3 + buf_num_1; + int ptr_2 = base_map_2 * 3 + buf_num_2; + int ptr; + u32 reg; + ptr = (ptr_2 << 10) + (ptr_1 << 5) + ptr_0; + + reg = __raw_readl(DC_MAP_CONF_PTR(current_map)); + reg &= ~(0x1F << ((16 * (current_map & 0x1)))); + reg |= ptr << ((16 * (current_map & 0x1))); + __raw_writel(reg, DC_MAP_CONF_PTR(current_map)); +} + static void _ipu_dc_map_config(int map, int byte_num, int offset, int mask) { int ptr = map * 3 + byte_num; @@ -269,32 +318,63 @@ static void _ipu_dc_map_clear(int map) } static void _ipu_dc_write_tmpl(int word, u32 opcode, u32 operand, int map, - int wave, int glue, int sync) + int wave, int glue, int sync, int stop) { u32 reg; - int stop = 1; - - reg = sync; - reg |= (glue << 4); - reg |= (++wave << 11); - reg |= (++map << 15); - reg |= (operand << 20) & 0xFFF00000; - __raw_writel(reg, ipu_dc_tmpl_reg + word * 2); - - reg = (operand >> 12); - reg |= opcode << 4; - reg |= (stop << 9); - __raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1); + + if (opcode == WRG) { + reg = sync; + reg |= (glue << 4); + reg |= (++wave << 11); + reg |= ((operand & 0x1FFFF) << 15); + __raw_writel(reg, ipu_dc_tmpl_reg + word * 2); + + reg = (operand >> 17); + reg |= opcode << 7; + reg |= (stop << 9); + __raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1); + } else { + reg = sync; + reg |= (glue << 4); + reg |= (++wave << 11); + reg |= (++map << 15); + reg |= (operand << 20) & 0xFFF00000; + __raw_writel(reg, ipu_dc_tmpl_reg + word * 2); + + reg = (operand >> 12); + reg |= opcode << 4; + reg |= (stop << 9); + __raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1); + } } static void _ipu_dc_link_event(int chan, int event, int addr, int priority) { u32 reg; - - reg = __raw_readl(DC_RL_CH(chan, event)); - reg &= ~(0xFFFF << (16 * (event & 0x1))); - reg |= ((addr << 8) | priority) << (16 * (event & 0x1)); - __raw_writel(reg, DC_RL_CH(chan, event)); + u32 address_shift; + if (event < DC_EVEN_UGDE0) { + reg = __raw_readl(DC_RL_CH(chan, event)); + reg &= ~(0xFFFF << (16 * (event & 0x1))); + reg |= ((addr << 8) | priority) << (16 * (event & 0x1)); + __raw_writel(reg, DC_RL_CH(chan, event)); + } else { + reg = __raw_readl(DC_UGDE_0((event - DC_EVEN_UGDE0) / 2)); + if ((event - DC_EVEN_UGDE0) & 0x1) { + reg &= ~(0x2FF << 16); + reg |= (addr << 16); + reg |= priority ? (2 << 24) : 0x0; + } else { + reg &= ~0xFC00FFFF; + if (priority) + chan = (chan >> 1) + + ((((chan & 0x1) + ((chan & 0x2) >> 1))) | (chan >> 3)); + else + chan = 0x7; + address_shift = ((event - DC_EVEN_UGDE0) >> 1) ? 7 : 8; + reg |= (addr << address_shift) | (priority << 3) | chan; + } + __raw_writel(reg, DC_UGDE_0((event - DC_EVEN_UGDE0) / 2)); + } } /* Y = R * 1.200 + G * 2.343 + B * .453 + 0.250; @@ -503,7 +583,7 @@ void _ipu_dp_uninit(ipu_channel_t channel) __ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], false); } -void _ipu_dc_init(int dc_chan, int di, bool interlaced) +void _ipu_dc_init(int dc_chan, int di, bool interlaced, uint32_t pixel_fmt) { u32 reg = 0; @@ -517,10 +597,24 @@ void _ipu_dc_init(int dc_chan, int di, bool interlaced) _ipu_dc_link_event(dc_chan, DC_EVT_NL, 2, 3); _ipu_dc_link_event(dc_chan, DC_EVT_EOL, 3, 2); _ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 4, 1); + if ((pixel_fmt == IPU_PIX_FMT_YUYV) || + (pixel_fmt == IPU_PIX_FMT_UYVY) || + (pixel_fmt == IPU_PIX_FMT_YVYU) || + (pixel_fmt == IPU_PIX_FMT_VYUY)) { + _ipu_dc_link_event(dc_chan, DC_ODD_UGDE1, 9, 5); + _ipu_dc_link_event(dc_chan, DC_EVEN_UGDE1, 8, 5); + } } else { _ipu_dc_link_event(dc_chan, DC_EVT_NL, 5, 3); _ipu_dc_link_event(dc_chan, DC_EVT_EOL, 6, 2); _ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 7, 1); + if ((pixel_fmt == IPU_PIX_FMT_YUYV) || + (pixel_fmt == IPU_PIX_FMT_UYVY) || + (pixel_fmt == IPU_PIX_FMT_YVYU) || + (pixel_fmt == IPU_PIX_FMT_VYUY)) { + _ipu_dc_link_event(dc_chan, DC_ODD_UGDE0, 10, 5); + _ipu_dc_link_event(dc_chan, DC_EVEN_UGDE0, 11, 5); + } } } _ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0); @@ -562,6 +656,10 @@ void _ipu_dc_uninit(int dc_chan) _ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0); _ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0); _ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0); + _ipu_dc_link_event(dc_chan, DC_ODD_UGDE0, 0, 0); + _ipu_dc_link_event(dc_chan, DC_EVEN_UGDE0, 0, 0); + _ipu_dc_link_event(dc_chan, DC_ODD_UGDE1, 0, 0); + _ipu_dc_link_event(dc_chan, DC_EVEN_UGDE1, 0, 0); } else if ((dc_chan == 8) || (dc_chan == 9)) { _ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_0, 0, 0); _ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_1, 0, 0); @@ -637,6 +735,26 @@ static bool dc_swap; static irqreturn_t dc_irq_handler(int irq, void *dev_id) { struct completion *comp = dev_id; + uint32_t reg; + uint32_t dc_chan; + + if (irq == IPU_IRQ_DC_FC_1) + dc_chan = 1; + else + dc_chan = 5; + + if (!dc_swap) { + reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); + reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; + __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); + + reg = __raw_readl(IPU_DISP_GEN); + if (g_dc_di_assignment[dc_chan]) + reg &= ~DI1_COUNTER_RELEASE; + else + reg &= ~DI0_COUNTER_RELEASE; + __raw_writel(reg, IPU_DISP_GEN); + } complete(comp); return IRQ_HANDLED; @@ -689,29 +807,6 @@ void _ipu_dp_dc_disable(ipu_channel_t channel, bool swap) if (timeout <= 0) break; } - - timeout = 50; - - /* - * Wait for DC triple buffer to empty, - * this check is useful for tv overlay. - */ - if (g_dc_di_assignment[dc_chan] == 0) - while ((__raw_readl(DC_STAT) & 0x00000002) - != 0x00000002) { - msleep(2); - timeout -= 2; - if (timeout <= 0) - break; - } - else if (g_dc_di_assignment[dc_chan] == 1) - while ((__raw_readl(DC_STAT) & 0x00000020) - != 0x00000020) { - msleep(2); - timeout -= 2; - if (timeout <= 0) - break; - } return; } else { return; @@ -743,39 +838,6 @@ void _ipu_dp_dc_disable(ipu_channel_t channel, bool swap) __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); spin_unlock_irqrestore(&ipu_lock, lock_flags); } else { - timeout = 50; - - /* Wait for DC triple buffer to empty */ - if (g_dc_di_assignment[dc_chan] == 0) - while ((__raw_readl(DC_STAT) & 0x00000002) - != 0x00000002) { - msleep(2); - timeout -= 2; - if (timeout <= 0) - break; - } - else if (g_dc_di_assignment[dc_chan] == 1) - while ((__raw_readl(DC_STAT) & 0x00000020) - != 0x00000020) { - msleep(2); - timeout -= 2; - if (timeout <= 0) - break; - } - - spin_lock_irqsave(&ipu_lock, lock_flags); - reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); - reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; - __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); - - reg = __raw_readl(IPU_DISP_GEN); - if (g_dc_di_assignment[dc_chan]) - reg &= ~DI1_COUNTER_RELEASE; - else - reg &= ~DI0_COUNTER_RELEASE; - __raw_writel(reg, IPU_DISP_GEN); - - spin_unlock_irqrestore(&ipu_lock, lock_flags); /* Clock is already off because it must be done quickly, but we need to fix the ref count */ clk_disable(g_pixel_clk[g_dc_di_assignment[dc_chan]]); @@ -821,6 +883,34 @@ void _ipu_init_dc_mappings(void) _ipu_dc_map_config(4, 0, 5, 0xFC); _ipu_dc_map_config(4, 1, 13, 0xFC); _ipu_dc_map_config(4, 2, 21, 0xFC); + + /* IPU_PIX_FMT_VYUY 16bit width */ + _ipu_dc_map_clear(5); + _ipu_dc_map_config(5, 0, 7, 0xFF); + _ipu_dc_map_config(5, 1, 0, 0x0); + _ipu_dc_map_config(5, 2, 15, 0xFF); + _ipu_dc_map_clear(6); + _ipu_dc_map_config(6, 0, 0, 0x0); + _ipu_dc_map_config(6, 1, 7, 0xFF); + _ipu_dc_map_config(6, 2, 15, 0xFF); + + /* IPU_PIX_FMT_UYUV 16bit width */ + _ipu_dc_map_clear(7); + _ipu_dc_map_link(7, 6, 0, 6, 1, 6, 2); + _ipu_dc_map_clear(8); + _ipu_dc_map_link(8, 5, 0, 5, 1, 5, 2); + + /* IPU_PIX_FMT_YUYV 16bit width */ + _ipu_dc_map_clear(9); + _ipu_dc_map_link(9, 5, 2, 5, 1, 5, 0); + _ipu_dc_map_clear(10); + _ipu_dc_map_link(10, 5, 1, 5, 2, 5, 0); + + /* IPU_PIX_FMT_YVYU 16bit width */ + _ipu_dc_map_clear(11); + _ipu_dc_map_link(11, 5, 1, 5, 2, 5, 0); + _ipu_dc_map_clear(12); + _ipu_dc_map_link(12, 5, 2, 5, 1, 5, 0); } int _ipu_pixfmt_to_map(uint32_t fmt) @@ -837,6 +927,14 @@ int _ipu_pixfmt_to_map(uint32_t fmt) return 3; case IPU_PIX_FMT_LVDS666: return 4; + case IPU_PIX_FMT_VYUY: + return 6; + case IPU_PIX_FMT_UYVY: + return 8; + case IPU_PIX_FMT_YUYV: + return 10; + case IPU_PIX_FMT_YVYU: + return 12; } return -1; @@ -964,22 +1062,22 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, dev_dbg(g_ipu_dev, "pixel clk = %d\n", pixel_clk); if (sig.ext_clk) { - /* Set the PLL to be an even multiple of the pixel clock. not round div for tvout*/ - if ((clk_get_usecount(g_pixel_clk[0]) == 0) && - (clk_get_usecount(g_pixel_clk[1]) == 0)) { + /* + * Set the PLL to be an even multiple of the pixel clock. + * Not round div for tvout and ldb. + * Did not consider both DI come from the same ext clk, if + * meet such case, ext clk rate should be set specially. + */ + if (clk_get_usecount(g_pixel_clk[disp]) == 0) { di_parent = clk_get_parent(g_di_clk[disp]); - if (strcmp(di_parent->name, "tve_clk") != 0) { - rounded_pixel_clk = - clk_round_rate(g_pixel_clk[disp], pixel_clk); - div = clk_get_rate(di_parent) / rounded_pixel_clk; - if (div % 2) - div++; - - if (clk_get_rate(di_parent) != div * rounded_pixel_clk) - clk_set_rate(di_parent, div * rounded_pixel_clk); - msleep(10); - clk_set_rate(g_di_clk[disp], 2 * rounded_pixel_clk); - msleep(10); + if (strcmp(di_parent->name, "tve_clk") != 0 && + strcmp(di_parent->name, "ldb_di0_clk") != 0 && + strcmp(di_parent->name, "ldb_di1_clk") != 0) { + rounded_pixel_clk = pixel_clk * 2; + while (rounded_pixel_clk < 150000000) + rounded_pixel_clk += pixel_clk * 2; + clk_set_rate(di_parent, rounded_pixel_clk); + clk_set_rate(g_di_clk[disp], pixel_clk); } } clk_set_parent(g_pixel_clk[disp], g_di_clk[disp]); @@ -1019,7 +1117,7 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, di_gen = __raw_readl(DI_GENERAL(disp)); if (sig.interlaced) { - if (cpu_is_mx51_rev(CHIP_REV_2_0)) { + if (g_ipu_hw_rev >= 2) { /* Setup internal HSYNC waveform */ _ipu_di_sync_config( disp, /* display */ @@ -1259,7 +1357,7 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, } /* Init template microcode */ - _ipu_dc_write_tmpl(0, WROD(0), 0, map, SYNC_WAVE, 0, 8); + _ipu_dc_write_tmpl(0, WROD(0), 0, map, SYNC_WAVE, 0, 8, 1); if (sig.Hsync_pol) di_gen |= DI_GEN_POLARITY_3; @@ -1322,13 +1420,31 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, /* Init template microcode */ if (disp) { - _ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5); - _ipu_dc_write_tmpl(3, WROD(0), 0, map, SYNC_WAVE, 4, 5); - _ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5); + if ((pixel_fmt == IPU_PIX_FMT_YUYV) || + (pixel_fmt == IPU_PIX_FMT_UYVY) || + (pixel_fmt == IPU_PIX_FMT_YVYU) || + (pixel_fmt == IPU_PIX_FMT_VYUY)) { + _ipu_dc_write_tmpl(8, WROD(0), 0, (map - 1), SYNC_WAVE, 0, 5, 1); + _ipu_dc_write_tmpl(9, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1); + /* configure user events according to DISP NUM */ + __raw_writel((width - 1), DC_UGDE_3(disp)); + } + _ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1); + _ipu_dc_write_tmpl(3, WRG, 0, map, SYNC_WAVE, 4, 5, 1); + _ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1); } else { - _ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5); - _ipu_dc_write_tmpl(6, WROD(0), 0, map, SYNC_WAVE, 4, 5); - _ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5); + if ((pixel_fmt == IPU_PIX_FMT_YUYV) || + (pixel_fmt == IPU_PIX_FMT_UYVY) || + (pixel_fmt == IPU_PIX_FMT_YVYU) || + (pixel_fmt == IPU_PIX_FMT_VYUY)) { + _ipu_dc_write_tmpl(10, WROD(0), 0, (map - 1), SYNC_WAVE, 0, 5, 1); + _ipu_dc_write_tmpl(11, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1); + /* configure user events according to DISP NUM */ + __raw_writel(width - 1, DC_UGDE_3(disp)); + } + _ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1); + _ipu_dc_write_tmpl(6, WRG, 0, map, SYNC_WAVE, 4, 5, 1); + _ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1); } if (sig.Hsync_pol) @@ -1340,6 +1456,19 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, /* Set the clock to stop at counter 6. */ di_gen |= 0x6000000; } + /* changinc DISP_CLK polarity: it can be wrong for some applications */ + if ((pixel_fmt == IPU_PIX_FMT_YUYV) || + (pixel_fmt == IPU_PIX_FMT_UYVY) || + (pixel_fmt == IPU_PIX_FMT_YVYU) || + (pixel_fmt == IPU_PIX_FMT_VYUY)) + di_gen |= 0x00020000; + else { + /* Configure accordingly to the received configuration */ + if (sig.clk_pol) + di_gen |= 0x00020000; + else + di_gen &= ~0x00020000; + } __raw_writel(di_gen, DI_GENERAL(disp)); @@ -1402,7 +1531,7 @@ int ipu_init_async_panel(int disp, int type, uint32_t cycle_time, _ipu_di_data_pin_config(disp, ASYNC_SER_WAVE, DI_PIN_SER_RS, 2, 0, 0); - _ipu_dc_write_tmpl(0x64, WROD(0), 0, map, ASYNC_SER_WAVE, 0, 0); + _ipu_dc_write_tmpl(0x64, WROD(0), 0, map, ASYNC_SER_WAVE, 0, 0, 1); /* Configure DC for serial panel */ __raw_writel(0x14, DC_DISP_CONF1(DC_DISP_ID_SERIAL)); @@ -1679,6 +1808,39 @@ int32_t ipu_disp_set_window_pos(ipu_channel_t channel, int16_t x_pos, } EXPORT_SYMBOL(ipu_disp_set_window_pos); +int32_t ipu_disp_get_window_pos(ipu_channel_t channel, int16_t *x_pos, + int16_t *y_pos) +{ + u32 reg; + unsigned long lock_flags; + uint32_t flow = 0; + + if (channel == MEM_FG_SYNC) + flow = DP_SYNC; + else if (channel == MEM_FG_ASYNC0) + flow = DP_ASYNC0; + else if (channel == MEM_FG_ASYNC1) + flow = DP_ASYNC1; + else + return -EINVAL; + + if (!g_ipu_clk_enabled) + clk_enable(g_ipu_clk); + spin_lock_irqsave(&ipu_lock, lock_flags); + + reg = __raw_readl(DP_FG_POS(flow)); + + *x_pos = (reg >> 16) & 0x7FF; + *y_pos = reg & 0x7FF; + + spin_unlock_irqrestore(&ipu_lock, lock_flags); + if (!g_ipu_clk_enabled) + clk_disable(g_ipu_clk); + + return 0; +} +EXPORT_SYMBOL(ipu_disp_get_window_pos); + void ipu_disp_direct_write(ipu_channel_t channel, u32 value, u32 offset) { if (channel == DIRECT_ASYNC0) diff --git a/drivers/mxc/ipu3/ipu_ic.c b/drivers/mxc/ipu3/ipu_ic.c index 564fab0b699a..78c3a9228941 100644 --- a/drivers/mxc/ipu3/ipu_ic.c +++ b/drivers/mxc/ipu3/ipu_ic.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -157,7 +157,6 @@ void _ipu_vdi_init(ipu_channel_t channel, ipu_channel_params_t *params) { uint32_t reg; uint32_t pixel_fmt; - bool top_field_0; reg = ((params->mem_prp_vf_mem.in_height-1) << 16) | (params->mem_prp_vf_mem.in_width-1); @@ -186,19 +185,7 @@ void _ipu_vdi_init(ipu_channel_t channel, ipu_channel_params_t *params) } __raw_writel(reg, VDI_C); - /* MED_MOTION and LOW_MOTION algorithm that are using 3 fields - * should start presenting using the 2nd field. - */ - if (((params->mem_prp_vf_mem.field_fmt == V4L2_FIELD_INTERLACED_TB) && - (params->mem_prp_vf_mem.motion_sel != HIGH_MOTION)) || - ((params->mem_prp_vf_mem.field_fmt == V4L2_FIELD_INTERLACED_BT) && - (params->mem_prp_vf_mem.motion_sel == HIGH_MOTION))) - top_field_0 = false; - else - top_field_0 = true; - - /* Buffer selection toggle the value therefore init val is inverted. */ - _ipu_vdi_set_top_field_man(!top_field_0); + _ipu_vdi_set_top_field_man(false); _ipu_vdi_set_motion(params->mem_prp_vf_mem.motion_sel); @@ -227,13 +214,13 @@ void _ipu_ic_init_prpvf(ipu_channel_params_t *params, bool src_is_csi) /* Setup horizontal resizing */ /* Upadeted for IC split case */ - if (!(params->mem_prp_vf_mem.out_resize_ratio)) { + if (!(params->mem_prp_vf_mem.outh_resize_ratio)) { _calc_resize_coeffs(params->mem_prp_vf_mem.in_width, params->mem_prp_vf_mem.out_width, &resizeCoeff, &downsizeCoeff); reg |= (downsizeCoeff << 14) | resizeCoeff; } else - reg |= params->mem_prp_vf_mem.out_resize_ratio; + reg |= params->mem_prp_vf_mem.outh_resize_ratio; __raw_writel(reg, IC_PRP_VF_RSC); @@ -349,13 +336,13 @@ void _ipu_ic_init_prpenc(ipu_channel_params_t *params, bool src_is_csi) /* Setup horizontal resizing */ /* Upadeted for IC split case */ - if (!(params->mem_prp_enc_mem.out_resize_ratio)) { + if (!(params->mem_prp_enc_mem.outh_resize_ratio)) { _calc_resize_coeffs(params->mem_prp_enc_mem.in_width, params->mem_prp_enc_mem.out_width, &resizeCoeff, &downsizeCoeff); reg |= (downsizeCoeff << 14) | resizeCoeff; } else - reg |= params->mem_prp_enc_mem.out_resize_ratio; + reg |= params->mem_prp_enc_mem.outh_resize_ratio; __raw_writel(reg, IC_PRP_ENC_RSC); @@ -387,6 +374,8 @@ void _ipu_ic_init_prpenc(ipu_channel_params_t *params, bool src_is_csi) ic_conf |= IC_CONF_RWS_EN; __raw_writel(ic_conf, IC_CONF); + +// ic_dump_register(); } void _ipu_ic_uninit_prpenc(void) @@ -418,20 +407,24 @@ void _ipu_ic_init_pp(ipu_channel_params_t *params) ipu_color_space_t in_fmt, out_fmt; /* Setup vertical resizing */ - _calc_resize_coeffs(params->mem_pp_mem.in_height, + if (!(params->mem_pp_mem.outv_resize_ratio)) { + _calc_resize_coeffs(params->mem_pp_mem.in_height, params->mem_pp_mem.out_height, &resizeCoeff, &downsizeCoeff); - reg = (downsizeCoeff << 30) | (resizeCoeff << 16); + reg = (downsizeCoeff << 30) | (resizeCoeff << 16); + } else { + reg = (params->mem_pp_mem.outv_resize_ratio) << 16; + } /* Setup horizontal resizing */ /* Upadeted for IC split case */ - if (!(params->mem_pp_mem.out_resize_ratio)) { + if (!(params->mem_pp_mem.outh_resize_ratio)) { _calc_resize_coeffs(params->mem_pp_mem.in_width, params->mem_pp_mem.out_width, &resizeCoeff, &downsizeCoeff); reg |= (downsizeCoeff << 14) | resizeCoeff; } else { - reg |= params->mem_pp_mem.out_resize_ratio; + reg |= params->mem_pp_mem.outh_resize_ratio; } __raw_writel(reg, IC_PP_RSC); diff --git a/drivers/mxc/ipu3/ipu_param_mem.h b/drivers/mxc/ipu3/ipu_param_mem.h index dab3b617db1c..30e6dc1005ba 100644 --- a/drivers/mxc/ipu3/ipu_param_mem.h +++ b/drivers/mxc/ipu3/ipu_param_mem.h @@ -155,8 +155,15 @@ static inline void _ipu_ch_param_init(int ch, ipu_ch_param_set_field(¶ms, 1, 102, 14, stride - 1); } + /* EBA is 8-byte aligned */ ipu_ch_param_set_field(¶ms, 1, 0, 29, addr0 >> 3); ipu_ch_param_set_field(¶ms, 1, 29, 29, addr1 >> 3); + if (addr0%8) + dev_warn(g_ipu_dev, + "IDMAC%d's EBA0 is not 8-byte aligned\n", ch); + if (addr1%8) + dev_warn(g_ipu_dev, + "IDMAC%d's EBA1 is not 8-byte aligned\n", ch); switch (pixel_fmt) { case IPU_PIX_FMT_GENERIC: @@ -210,13 +217,14 @@ static inline void _ipu_ch_param_init(int ch, case IPU_PIX_FMT_ABGR32: ipu_ch_param_set_field(¶ms, 0, 107, 3, 0); /* bits/pixel */ ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ + ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ _ipu_ch_params_set_packing(¶ms, 8, 0, 8, 8, 8, 16, 8, 24); break; case IPU_PIX_FMT_UYVY: ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ ipu_ch_param_set_field(¶ms, 1, 85, 4, 0xA); /* pix format */ - ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ + ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ break; case IPU_PIX_FMT_YUYV: ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ @@ -289,13 +297,19 @@ static inline void _ipu_ch_param_init(int ch, v_offset = v; } - /* UBO and VBO are 22-bit */ + /* UBO and VBO are 22-bit and 8-byte aligned */ if (u_offset/8 > 0x3fffff) - dev_err(g_ipu_dev, - "The value of U offset exceeds IPU limitation\n"); + dev_warn(g_ipu_dev, + "IDMAC%d's U offset exceeds IPU limitation\n", ch); if (v_offset/8 > 0x3fffff) - dev_err(g_ipu_dev, - "The value of V offset exceeds IPU limitation\n"); + dev_warn(g_ipu_dev, + "IDMAC%d's V offset exceeds IPU limitation\n", ch); + if (u_offset%8) + dev_warn(g_ipu_dev, + "IDMAC%d's U offset is not 8-byte aligned\n", ch); + if (v_offset%8) + dev_warn(g_ipu_dev, + "IDMAC%d's V offset is not 8-byte aligned\n", ch); ipu_ch_param_set_field(¶ms, 0, 46, 22, u_offset / 8); ipu_ch_param_set_field(¶ms, 0, 68, 22, v_offset / 8); @@ -386,6 +400,13 @@ static inline void _ipu_ch_param_set_interlaced_scan(uint32_t ch) u32 stride; ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 113, 1, 1); stride = ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 102, 14) + 1; + /* ILO is 20-bit and 8-byte aligned */ + if (stride/8 > 0xfffff) + dev_warn(g_ipu_dev, + "IDMAC%d's ILO exceeds IPU limitation\n", ch); + if (stride%8) + dev_warn(g_ipu_dev, + "IDMAC%d's ILO is not 8-byte aligned\n", ch); ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 58, 20, stride / 8); stride *= 2; ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 102, 14, stride - 1); @@ -442,7 +463,7 @@ static inline void _ipu_ch_offset_update(int ch, (uv_stride * vertical_offset / 2) + horizontal_offset / 2; v_offset = u_offset + (uv_stride * height / 2); - u_fix = u ? (u + (uv_stride * vertical_offset) + + u_fix = u ? (u + (uv_stride * vertical_offset / 2) + (horizontal_offset / 2) - (stride * vertical_offset) - (horizontal_offset)) : u_offset; @@ -493,9 +514,9 @@ static inline void _ipu_ch_offset_update(int ch, uv_stride = stride; u_offset = stride * (height - vertical_offset - 1) + (stride - horizontal_offset) + - (uv_stride * vertical_offset) + + (uv_stride * vertical_offset / 2) + horizontal_offset; - u_fix = u ? (u + (uv_stride * vertical_offset) + + u_fix = u ? (u + (uv_stride * vertical_offset / 2) + horizontal_offset - (stride * vertical_offset) - (horizontal_offset)) : u_offset; @@ -514,13 +535,19 @@ static inline void _ipu_ch_offset_update(int ch, if (v_fix > v_offset) v_offset = v_fix; - /* UBO and VBO are 22-bit */ + /* UBO and VBO are 22-bit and 8-byte aligned */ if (u_offset/8 > 0x3fffff) - dev_err(g_ipu_dev, - "The value of U offset exceeds IPU limitation\n"); + dev_warn(g_ipu_dev, + "IDMAC%d's U offset exceeds IPU limitation\n", ch); if (v_offset/8 > 0x3fffff) - dev_err(g_ipu_dev, - "The value of V offset exceeds IPU limitation\n"); + dev_warn(g_ipu_dev, + "IDMAC%d's V offset exceeds IPU limitation\n", ch); + if (u_offset%8) + dev_warn(g_ipu_dev, + "IDMAC%d's U offset is not 8-byte aligned\n", ch); + if (v_offset%8) + dev_warn(g_ipu_dev, + "IDMAC%d's V offset is not 8-byte aligned\n", ch); ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 0, 46, 22, u_offset / 8); ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 0, 68, 22, v_offset / 8); diff --git a/drivers/mxc/ipu3/ipu_prv.h b/drivers/mxc/ipu3/ipu_prv.h index 213ded04c87d..4e62b256889f 100644 --- a/drivers/mxc/ipu3/ipu_prv.h +++ b/drivers/mxc/ipu3/ipu_prv.h @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -60,7 +60,7 @@ void _ipu_init_dc_mappings(void); int _ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt, uint32_t out_pixel_fmt); void _ipu_dp_uninit(ipu_channel_t channel); -void _ipu_dc_init(int dc_chan, int di, bool interlaced); +void _ipu_dc_init(int dc_chan, int di, bool interlaced, uint32_t pixel_fmt); void _ipu_dc_uninit(int dc_chan); void _ipu_dp_dc_enable(ipu_channel_t channel); void _ipu_dp_dc_disable(ipu_channel_t channel, bool swap); diff --git a/drivers/mxc/ipu3/ipu_regs.h b/drivers/mxc/ipu3/ipu_regs.h index 2438df60a0ce..4a78e14df560 100644 --- a/drivers/mxc/ipu3/ipu_regs.h +++ b/drivers/mxc/ipu3/ipu_regs.h @@ -261,6 +261,14 @@ extern u32 *ipu_vdi_reg; #define DC_EVT_NEW_CHAN_R_1 9 #define DC_EVT_NEW_DATA_R_0 10 #define DC_EVT_NEW_DATA_R_1 11 +#define DC_EVEN_UGDE0 12 +#define DC_ODD_UGDE0 13 +#define DC_EVEN_UGDE1 14 +#define DC_ODD_UGDE1 15 +#define DC_EVEN_UGDE2 16 +#define DC_ODD_UGDE2 17 +#define DC_EVEN_UGDE3 18 +#define DC_ODD_UGDE3 19 #define dc_ch_offset(ch) \ ({ \ @@ -627,6 +635,8 @@ enum { VDI_C_VWM3_CLR_2 = 0x02000000, VDI_C_TOP_FIELD_MAN_1 = 0x40000000, VDI_C_TOP_FIELD_AUTO_1 = 0x80000000, + + DMFC_FIFO_SIZE_5F = 0x00003800, }; enum di_pins { @@ -654,5 +664,6 @@ enum di_sync_wave { /* DC template opcodes */ #define WROD(lf) (0x18 | (lf << 1)) +#define WRG (0x01) #endif diff --git a/drivers/mxc/mlb/Kconfig b/drivers/mxc/mlb/Kconfig index 294c9776fb4d..7e3b16c2ddae 100644 --- a/drivers/mxc/mlb/Kconfig +++ b/drivers/mxc/mlb/Kconfig @@ -6,7 +6,7 @@ menu "MXC Media Local Bus Driver" config MXC_MLB tristate "MLB support" - depends on ARCH_MX35 + depends on ARCH_MX35 || ARCH_MX53 ---help--- Say Y to get the MLB support. diff --git a/drivers/mxc/pmic/core/mc13892.c b/drivers/mxc/pmic/core/mc13892.c index 9f232a4f5718..1175ab633fc6 100644 --- a/drivers/mxc/pmic/core/mc13892.c +++ b/drivers/mxc/pmic/core/mc13892.c @@ -262,6 +262,7 @@ int pmic_event_unmask(type_event event) return ret; } +EXPORT_SYMBOL(pmic_event_unmask); int pmic_event_mask(type_event event) { @@ -294,7 +295,7 @@ int pmic_event_mask(type_event event) return ret; } - +EXPORT_SYMBOL(pmic_event_mask); /*! * This function returns the PMIC version in system. * diff --git a/drivers/mxc/pmic/core/pmic.h b/drivers/mxc/pmic/core/pmic.h index 964c44a06bc1..da61b19a3f31 100644 --- a/drivers/mxc/pmic/core/pmic.h +++ b/drivers/mxc/pmic/core/pmic.h @@ -58,8 +58,6 @@ static inline int spi_rw(struct spi_device *spi, u8 * buf, size_t len) .cs_change = 0, .delay_usecs = 0, }; - mxc_spi_poll_transfer(spi, &t); - return 0; #if 0 struct spi_message m; @@ -68,6 +66,9 @@ static inline int spi_rw(struct spi_device *spi, u8 * buf, size_t len) if (spi_sync(spi, &m) != 0 || m.status != 0) return PMIC_ERROR; return (len - m.actual_length); +#else + mxc_spi_poll_transfer(spi, &t); + return 0; #endif } diff --git a/drivers/mxc/pmic/mc13892/pmic_adc.c b/drivers/mxc/pmic/mc13892/pmic_adc.c index 68588a40d7e4..60ce35e86a06 100644 --- a/drivers/mxc/pmic/mc13892/pmic_adc.c +++ b/drivers/mxc/pmic/mc13892/pmic_adc.c @@ -17,6 +17,7 @@ #include <linux/delay.h> #include <linux/wait.h> #include <linux/device.h> +#include <linux/cdev.h> #include <linux/pmic_adc.h> #include <linux/pmic_status.h> @@ -33,6 +34,9 @@ #define MC13892_ADC0_TS_M_LSH 14 #define MC13892_ADC0_TS_M_WID 3 +static int pmic_adc_major; +static struct class *pmic_adc_class; + /* * Maximun allowed variation in the three X/Y co-ordinates acquired from * touch-screen @@ -924,17 +928,322 @@ static ssize_t adc_ctl(struct device *dev, struct device_attribute *attr, #endif +/*! + * This function triggers a conversion and returns sampling results of each + * specified channel. + * + * @param channels This input parameter is bitmap to specify channels + * to be sampled. + * @param result The pointer to array to store sampling results. + * The memory should be allocated by the caller of this + * function. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_adc_convert_multichnnel(t_channel channels, + unsigned short *result) +{ + t_adc_param adc_param; + int i; + PMIC_STATUS ret; + if (suspend_flag == 1) { + return -EBUSY; + } + mc13892_adc_init_param(&adc_param); + pr_debug("pmic_adc_convert_multichnnel\n"); + + channels = channel_num[channels]; + + if (channels == -1) { + pr_debug("Wrong channel ID\n"); + return PMIC_PARAMETER_ERROR; + } + + adc_param.read_ts = false; + adc_param.single_channel = false; + if ((channels >= 0) && (channels <= 7)) { + adc_param.channel_0 = channels; + adc_param.channel_1 = ((channels + 4) % 4) + 4; + } else { + return PMIC_PARAMETER_ERROR; + } + adc_param.read_mode = 0x00003f; + adc_param.read_ts = false; + ret = mc13892_adc_convert(&adc_param); + + for (i = 0; i <= 7; i++) { + result[i] = adc_param.value[i]; + } + return ret; +} + +/*! + * This function starts a Battery Current mode conversion. + * + * @param mode Conversion mode. + * @param result Battery Current measurement result. + * if \a mode = ADC_8CHAN_1X, the result is \n + * result[0] = (BATTP - BATT_I) \n + * if \a mode = ADC_1CHAN_8X, the result is \n + * result[0] = BATTP \n + * result[1] = BATT_I \n + * result[2] = BATTP \n + * result[3] = BATT_I \n + * result[4] = BATTP \n + * result[5] = BATT_I \n + * result[6] = BATTP \n + * result[7] = BATT_I + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_adc_get_battery_current(t_conversion_mode mode, + unsigned short *result) +{ + PMIC_STATUS ret; + t_channel channel; + if (suspend_flag == 1) { + return -EBUSY; + } + channel = BATTERY_CURRENT; + if (mode == ADC_8CHAN_1X) { + ret = pmic_adc_convert(channel, result); + } else { + ret = pmic_adc_convert_8x(channel, result); + } + return ret; +} + +/*! + * This function implements the open method on a MC13892 ADC device. + * + * @param inode pointer on the node + * @param file pointer on the file + * @return This function returns 0. + */ +static int pmic_adc_open(struct inode *inode, struct file *file) +{ + while (suspend_flag == 1) { + swait++; + /* Block if the device is suspended */ + if (wait_event_interruptible(suspendq, (suspend_flag == 0))) { + return -ERESTARTSYS; + } + } + pr_debug("mc13892_adc : mc13892_adc_open()\n"); + return 0; +} + +/*! + * This function implements the release method on a MC13892 ADC device. + * + * @param inode pointer on the node + * @param file pointer on the file + * @return This function returns 0. + */ +static int pmic_adc_free(struct inode *inode, struct file *file) +{ + pr_debug("mc13892_adc : mc13892_adc_free()\n"); + return 0; +} + +/*! + * This function implements IOCTL controls on a MC13892 ADC device. + * + * @param inode pointer on the node + * @param file pointer on the file + * @param cmd the command + * @param arg the parameter + * @return This function returns 0 if successful. + */ +static int pmic_adc_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + t_adc_convert_param *convert_param; + t_touch_mode touch_mode; + t_touch_screen touch_sample; + unsigned short b_current; + + if ((_IOC_TYPE(cmd) != 'p') && (_IOC_TYPE(cmd) != 'D')) + return -ENOTTY; + + while (suspend_flag == 1) { + swait++; + /* Block if the device is suspended */ + if (wait_event_interruptible(suspendq, (suspend_flag == 0))) { + return -ERESTARTSYS; + } + } + + switch (cmd) { + case PMIC_ADC_INIT: + CHECK_ERROR(pmic_adc_init()); + break; + + case PMIC_ADC_DEINIT: + CHECK_ERROR(pmic_adc_deinit()); + break; + + case PMIC_ADC_CONVERT: + if ((convert_param = kmalloc(sizeof(t_adc_convert_param), + GFP_KERNEL)) == NULL) { + return -ENOMEM; + } + if (copy_from_user(convert_param, (t_adc_convert_param *) arg, + sizeof(t_adc_convert_param))) { + kfree(convert_param); + return -EFAULT; + } + CHECK_ERROR_KFREE(pmic_adc_convert(convert_param->channel, + convert_param->result), + (kfree(convert_param))); + + if (copy_to_user((t_adc_convert_param *) arg, convert_param, + sizeof(t_adc_convert_param))) { + kfree(convert_param); + return -EFAULT; + } + kfree(convert_param); + break; + + case PMIC_ADC_CONVERT_8X: + if ((convert_param = kmalloc(sizeof(t_adc_convert_param), + GFP_KERNEL)) == NULL) { + return -ENOMEM; + } + if (copy_from_user(convert_param, (t_adc_convert_param *) arg, + sizeof(t_adc_convert_param))) { + kfree(convert_param); + return -EFAULT; + } + CHECK_ERROR_KFREE(pmic_adc_convert_8x(convert_param->channel, + convert_param->result), + (kfree(convert_param))); + + if (copy_to_user((t_adc_convert_param *) arg, convert_param, + sizeof(t_adc_convert_param))) { + kfree(convert_param); + return -EFAULT; + } + kfree(convert_param); + break; + + case PMIC_ADC_CONVERT_MULTICHANNEL: + if ((convert_param = kmalloc(sizeof(t_adc_convert_param), + GFP_KERNEL)) == NULL) { + return -ENOMEM; + } + if (copy_from_user(convert_param, (t_adc_convert_param *) arg, + sizeof(t_adc_convert_param))) { + kfree(convert_param); + return -EFAULT; + } + + CHECK_ERROR_KFREE(pmic_adc_convert_multichnnel + (convert_param->channel, + convert_param->result), + (kfree(convert_param))); + + if (copy_to_user((t_adc_convert_param *) arg, convert_param, + sizeof(t_adc_convert_param))) { + kfree(convert_param); + return -EFAULT; + } + kfree(convert_param); + break; + + case PMIC_ADC_SET_TOUCH_MODE: + CHECK_ERROR(pmic_adc_set_touch_mode((t_touch_mode) arg)); + break; + + case PMIC_ADC_GET_TOUCH_MODE: + CHECK_ERROR(pmic_adc_get_touch_mode(&touch_mode)); + if (copy_to_user((t_touch_mode *) arg, &touch_mode, + sizeof(t_touch_mode))) { + return -EFAULT; + } + break; + + case PMIC_ADC_GET_TOUCH_SAMPLE: + CHECK_ERROR(pmic_adc_get_touch_sample(&touch_sample, 1)); + if (copy_to_user((t_touch_screen *) arg, &touch_sample, + sizeof(t_touch_screen))) { + return -EFAULT; + } + break; + + case PMIC_ADC_GET_BATTERY_CURRENT: + CHECK_ERROR(pmic_adc_get_battery_current(ADC_8CHAN_1X, + &b_current)); + if (copy_to_user((unsigned short *)arg, &b_current, + sizeof(unsigned short))) { + + return -EFAULT; + } + break; + + default: + pr_debug("pmic_adc_ioctl: unsupported ioctl command 0x%x\n", + cmd); + return -EINVAL; + } + return 0; +} + +static struct file_operations mc13892_adc_fops = { + .owner = THIS_MODULE, + .ioctl = pmic_adc_ioctl, + .open = pmic_adc_open, + .release = pmic_adc_free, +}; + +static struct cdev pmic_adc_cdev; static DEVICE_ATTR(adc, 0644, adc_info, adc_ctl); static int pmic_adc_module_probe(struct platform_device *pdev) { int ret = 0; + struct device * sdev; + dev_t devid; pr_debug("PMIC ADC start probe\n"); + + if( (ret = alloc_chrdev_region(&devid, 0, 8, "pmic_adc")) < 0 ) { + pr_debug(KERN_ERR "Unable to allocate device range for pmic_adc\n"); + return ret; + } + pmic_adc_major = MAJOR(devid); + if (pmic_adc_major < 0) { + pr_debug(KERN_ERR "Unable to get a major for pmic_adc\n"); + ret = pmic_adc_major; + goto unreg_char; + } + + cdev_init(&pmic_adc_cdev, &mc13892_adc_fops); + ret =cdev_add(&pmic_adc_cdev, devid, 8); + if (ret < 0) { + pr_err("pmic_adc: cannot add character device\n"); + goto unreg_char; + } + + pmic_adc_class = class_create(THIS_MODULE, "pmic_adc"); + if (IS_ERR(pmic_adc_class)) { + pr_debug(KERN_ERR "Error creating pmic_adc class.\n"); + ret = PTR_ERR(pmic_adc_class); + goto unreg_char; + } + + sdev = device_create(pmic_adc_class, NULL, devid, NULL, "pmic_adc"); + if (IS_ERR(sdev) ) { + pr_debug(KERN_ERR "Error creating pmic_adc class device.\n"); + ret = PTR_ERR(sdev); + goto cl_destroy; + } + ret = device_create_file(&(pdev->dev), &dev_attr_adc); if (ret) { pr_debug("Can't create device file!\n"); - return -ENODEV; + ret = -ENODEV; + goto dev_destroy; } init_waitqueue_head(&suspendq); @@ -946,11 +1255,17 @@ static int pmic_adc_module_probe(struct platform_device *pdev) } pmic_adc_ready = 1; - pr_debug("PMIC ADC successfully probed\n"); + printk(KERN_DEBUG"PMIC ADC successfully probed\n"); return 0; - rm_dev_file: +rm_dev_file: device_remove_file(&(pdev->dev), &dev_attr_adc); +dev_destroy: + device_destroy(pmic_adc_class, MKDEV(pmic_adc_major, 0)); +cl_destroy: + class_destroy(pmic_adc_class); +unreg_char: + unregister_chrdev(pmic_adc_major, "pmic_adc"); return ret; } diff --git a/drivers/mxc/pmic/mc13892/pmic_battery.c b/drivers/mxc/pmic/mc13892/pmic_battery.c index 8535eb0a34e4..c355e0c4338f 100644 --- a/drivers/mxc/pmic/mc13892/pmic_battery.c +++ b/drivers/mxc/pmic/mc13892/pmic_battery.c @@ -1,5 +1,5 @@ /* - * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -104,6 +104,19 @@ enum chg_setting { VI_PROGRAM_EN }; + +static unsigned int max_voltage_design = 3800000; +module_param(max_voltage_design, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(max_voltage_design, "Maximum battery voltage by design."); + +static unsigned int min_voltage_design = 3300000; +module_param(min_voltage_design, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(min_voltage_design, "Minimum battery voltage by design."); + +static unsigned int main_charger_current = 0x8; /* 720 mA */ +module_param(main_charger_current, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(main_charger_current, "Main charge path regulator current limit."); + static int pmic_set_chg_current(unsigned short curr) { unsigned int mask; @@ -180,15 +193,35 @@ static int pmic_set_chg_misc(enum chg_setting type, unsigned short flag) return 0; } +static void pmic_stop_charging(void) +{ + pmic_set_chg_misc(AUTO_CHG_DIS, 0); + pmic_set_chg_current(0); +} + +static int pmic_restart_charging(void) +{ + pmic_set_chg_misc(BAT_TH_CHECK_DIS, 1); + pmic_set_chg_misc(AUTO_CHG_DIS, 0); + pmic_set_chg_misc(VI_PROGRAM_EN, 1); + pmic_set_chg_current(main_charger_current); + pmic_set_chg_misc(RESTART_CHG_STAT, 1); + return 0; +} + static int pmic_get_batt_voltage(unsigned short *voltage) { t_channel channel; unsigned short result[8]; + pmic_stop_charging(); + channel = BATTERY_VOLTAGE; CHECK_ERROR(pmic_adc_convert(channel, result)); *voltage = result[0]; + pmic_restart_charging(); + return 0; } @@ -197,10 +230,14 @@ static int pmic_get_batt_current(unsigned short *curr) t_channel channel; unsigned short result[8]; + pmic_stop_charging(); + channel = BATTERY_CURRENT; CHECK_ERROR(pmic_adc_convert(channel, result)); *curr = result[0]; + pmic_restart_charging(); + return 0; } @@ -284,16 +321,6 @@ static int pmic_get_charger_coulomb(int *coulomb) return 0; } -static int pmic_restart_charging(void) -{ - pmic_set_chg_misc(BAT_TH_CHECK_DIS, 1); - pmic_set_chg_misc(AUTO_CHG_DIS, 0); - pmic_set_chg_misc(VI_PROGRAM_EN, 1); - pmic_set_chg_current(0x8); - pmic_set_chg_misc(RESTART_CHG_STAT, 1); - return 0; -} - struct mc13892_dev_info { struct device *dev; @@ -353,8 +380,8 @@ static int mc13892_charger_update_status(struct mc13892_dev_info *di) pmic_restart_charging(); } else pmic_stop_coulomb_counter(); + } } - } return ret; } @@ -422,7 +449,7 @@ static void mc13892_battery_update_status(struct mc13892_dev_info *di) else di->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING; - } + } if (di->battery_status == POWER_SUPPLY_STATUS_NOT_CHARGING) di->full_counter++; @@ -491,10 +518,10 @@ static int mc13892_battery_get_property(struct power_supply *psy, val->intval = di->accum_current_uAh; break; case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: - val->intval = 3800000; + val->intval = max_voltage_design; break; case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: - val->intval = 3300000; + val->intval = min_voltage_design; break; default: return -EINVAL; @@ -536,7 +563,7 @@ static int pmic_battery_probe(struct platform_device *pdev) pr_debug("Battery driver is only applied for MC13892 V2.0\n"); return -1; } - if (machine_is_mx51_babbage()) { + if (machine_is_mx51_babbage() || machine_is_mx50_arm2()) { pr_debug("mc13892 charger is not used for this platform\n"); return -1; } diff --git a/drivers/mxc/security/Kconfig b/drivers/mxc/security/Kconfig index 875848b2c69c..3e36a29ace64 100644 --- a/drivers/mxc/security/Kconfig +++ b/drivers/mxc/security/Kconfig @@ -27,6 +27,7 @@ config MXC_SECURITY_RNG depends on ARCH_MXC depends on !ARCH_MXC91321 depends on !ARCH_MX27 + depends on !ARCH_MX51 default n select MXC_SECURITY_CORE ---help--- diff --git a/drivers/mxc/security/sahara2/fsl_shw_auth.c b/drivers/mxc/security/sahara2/fsl_shw_auth.c index d3100f01380a..b3f8788b553a 100644 --- a/drivers/mxc/security/sahara2/fsl_shw_auth.c +++ b/drivers/mxc/security/sahara2/fsl_shw_auth.c @@ -326,7 +326,7 @@ static inline fsl_shw_return_t add_assoc_preamble(sah_Head_Desc ** desc_chain, return status; } /* add_assoc_preamble() */ -#if SUPPORT_SSL +#ifdef SUPPORT_SSL /*! * Generate an SSL value * @@ -473,7 +473,7 @@ fsl_shw_return_t fsl_shw_gen_encrypt(fsl_shw_uco_t * user_ctx, SAH_SF_USER_CHECK(); if (auth_ctx->mode == FSL_ACC_MODE_SSL) { -#if SUPPORT_SSL +#ifdef SUPPORT_SSL ret = do_ssl_gen(user_ctx, auth_ctx, cipher_key_info, auth_key_info, auth_data_length, auth_data, payload_length, payload, ct, auth_value); diff --git a/drivers/mxc/security/scc2_driver.c b/drivers/mxc/security/scc2_driver.c index 3249405c86a1..5c0d8b4dc26d 100644 --- a/drivers/mxc/security/scc2_driver.c +++ b/drivers/mxc/security/scc2_driver.c @@ -415,6 +415,7 @@ extern scc_partition_status_t scc_partition_status(void *part_base) break; } } +EXPORT_SYMBOL(scc_partition_status); /** * Calculate the physical address from the kernel virtual address. @@ -427,6 +428,7 @@ uint32_t scc_virt_to_phys(void *address) return (uint32_t) address - (uint32_t) scm_ram_base + (uint32_t) scm_ram_phys_base; } +EXPORT_SYMBOL(scc_virt_to_phys); /** * Engage partition of secure memory diff --git a/drivers/mxc/vpu/mxc_vpu.c b/drivers/mxc/vpu/mxc_vpu.c index b9ae23928c5d..9fc25edc33fa 100644 --- a/drivers/mxc/vpu/mxc_vpu.c +++ b/drivers/mxc/vpu/mxc_vpu.c @@ -73,6 +73,7 @@ static struct vpu_mem_desc user_data_mem = { 0 }; static struct vpu_mem_desc share_mem = { 0 }; static void __iomem *vpu_base; +static int vpu_irq; static u32 phy_vpu_base_addr; static struct mxc_vpu_platform_data *vpu_plat; @@ -539,7 +540,7 @@ static int vpu_map_mem(struct file *fp, struct vm_area_struct *vm) request_size); vm->vm_flags |= VM_IO | VM_RESERVED; - vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot); + vm->vm_page_prot = pgprot_writecombine(vm->vm_page_prot); return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, request_size, vm->vm_page_prot) ? -EAGAIN : 0; @@ -635,8 +636,9 @@ static int vpu_dev_probe(struct platform_device *pdev) err = -ENXIO; goto err_out_class; } + vpu_irq = res->start; - err = request_irq(res->start, vpu_irq_handler, 0, "VPU_CODEC_IRQ", + err = request_irq(vpu_irq, vpu_irq_handler, 0, "VPU_CODEC_IRQ", (void *)(&vpu_data)); if (err) goto err_out_class; @@ -660,6 +662,7 @@ static int vpu_dev_probe(struct platform_device *pdev) static int vpu_dev_remove(struct platform_device *pdev) { + free_irq(vpu_irq, &vpu_data); iounmap(vpu_base); iram_free(iram.start, VPU_IRAM_SIZE); @@ -690,22 +693,25 @@ static int vpu_suspend(struct platform_device *pdev, pm_message_t state) for (i = 0; i < vpu_clk_usercount; i++) clk_disable(vpu_clk); - clk_enable(vpu_clk); - if (bitwork_mem.cpu_addr != 0) { - SAVE_WORK_REGS; - SAVE_CTRL_REGS; - SAVE_RDWR_PTR_REGS; - SAVE_DIS_FLAG_REGS; - - WRITE_REG(0x1, BIT_BUSY_FLAG); - WRITE_REG(VPU_SLEEP_REG_VALUE, BIT_RUN_COMMAND); - while (READ_REG(BIT_BUSY_FLAG)) ; + if (!cpu_is_mx37()) + return 0; + else { + clk_enable(vpu_clk); + if (bitwork_mem.cpu_addr != 0) { + SAVE_WORK_REGS; + SAVE_CTRL_REGS; + SAVE_RDWR_PTR_REGS; + SAVE_DIS_FLAG_REGS; + + WRITE_REG(0x1, BIT_BUSY_FLAG); + WRITE_REG(VPU_SLEEP_REG_VALUE, BIT_RUN_COMMAND); + while (READ_REG(BIT_BUSY_FLAG)) + ; + } + clk_disable(vpu_clk); } - clk_disable(vpu_clk); - - if (cpu_is_mx37() || cpu_is_mx51()) - mxc_pg_enable(pdev); + mxc_pg_enable(pdev); return 0; @@ -719,11 +725,12 @@ static int vpu_resume(struct platform_device *pdev) { int i; - if (cpu_is_mx37() || cpu_is_mx51()) + if (cpu_is_mx37()) mxc_pg_disable(pdev); + else + goto recover_clk; clk_enable(vpu_clk); - if (bitwork_mem.cpu_addr != 0) { u32 *p = (u32 *) bitwork_mem.cpu_addr; u32 data; @@ -786,12 +793,13 @@ static int vpu_resume(struct platform_device *pdev) WRITE_REG(VPU_WAKE_REG_VALUE, BIT_RUN_COMMAND); while (READ_REG(BIT_BUSY_FLAG)) ; } - clk_disable(vpu_clk); +recover_clk: /* Recover vpu clock */ for (i = 0; i < vpu_clk_usercount; i++) clk_enable(vpu_clk); + printk("vpu_resume end\n"); return 0; } @@ -824,7 +832,6 @@ static int __init vpu_init(void) static void __exit vpu_exit(void) { - free_irq(MXC_INT_VPU, (void *)(&vpu_data)); if (vpu_major > 0) { device_destroy(vpu_class, MKDEV(vpu_major, 0)); class_destroy(vpu_class); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bd5d0e026b02..28318f4236b1 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1885,6 +1885,13 @@ config FEC_1588 bool "Enable FEC 1588 timestamping" depends on FEC +config FEC_L2SWITCH + bool "L2 Switch Ethernet Controller (of ColdFire CPUs)" + depends on ARCH_MX28 && !FEC + help + Say Y here if you want to use the built-in 10/100 Ethernet Switch + Controller on some Motorola ColdFire processors. + config FEC2 bool "Second FEC ethernet controller (on some ColdFire CPUs)" depends on FEC diff --git a/drivers/net/Makefile b/drivers/net/Makefile index f3c89fb1b799..11bb1b5623bf 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -115,6 +115,7 @@ obj-$(CONFIG_HP100) += hp100.o obj-$(CONFIG_SMC9194) += smc9194.o obj-$(CONFIG_FEC) += fec.o obj-$(CONFIG_FEC_1588) += fec_1588.o +obj-$(CONFIG_FEC_L2SWITCH) += fec_switch.o obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y) obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index a6bf9a7fddd9..481990fd3f2b 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -86,8 +86,8 @@ config CAN_DEBUG_DEVICES config CAN_FLEXCAN tristate "Freescale FlexCAN" - depends on CAN && (ARCH_MX25 || ARCH_MX35 || ARCH_MX28) - default m + depends on CAN && (ARCH_MX25 || ARCH_MX35 || ARCH_MX28 || ARCH_MX53) + default y ---help--- This select the support of Freescale CAN(FlexCAN). This driver can also be built as a module. diff --git a/drivers/net/can/flexcan/dev.c b/drivers/net/can/flexcan/dev.c index 389f85d75709..404877c33eab 100644 --- a/drivers/net/can/flexcan/dev.c +++ b/drivers/net/can/flexcan/dev.c @@ -35,6 +35,74 @@ #endif #include "flexcan.h" +#define DEFAULT_BITRATE 500000 +#define TIME_SEGMENT_MIN 8 +#define TIME_SEGMENT_MAX 25 +#define TIME_SEGMENT_MID ((TIME_SEGMENT_MIN + TIME_SEGMENT_MAX)/2) + +struct time_segment { + char propseg; + char pseg1; + char pseg2; +}; + +struct time_segment time_segments[] = { + { /* total 8 timequanta */ + 1, 2, 1 + }, + { /* total 9 timequanta */ + 1, 2, 2 + }, + { /* total 10 timequanta */ + 2, 2, 2 + }, + { /* total 11 timequanta */ + 2, 2, 3 + }, + { /* total 12 timequanta */ + 2, 3, 3 + }, + { /* total 13 timequanta */ + 3, 3, 3 + }, + { /* total 14 timequanta */ + 3, 3, 4 + }, + { /* total 15 timequanta */ + 3, 4, 4 + }, + { /* total 16 timequanta */ + 4, 4, 4 + }, + { /* total 17 timequanta */ + 4, 4, 5 + }, + { /* total 18 timequanta */ + 4, 5, 5 + }, + { /* total 19 timequanta */ + 5, 5, 5 + }, + { /* total 20 timequanta */ + 5, 5, 6 + }, + { /* total 21 timequanta */ + 5, 6, 6 + }, + { /* total 22 timequanta */ + 6, 6, 6 + }, + { /* total 23 timequanta */ + 6, 6, 7 + }, + { /* total 24 timequanta */ + 6, 7, 7 + }, + { /* total 25 timequanta */ + 7, 7, 7 + }, +}; + enum { FLEXCAN_ATTR_STATE = 0, FLEXCAN_ATTR_BITRATE, @@ -138,6 +206,45 @@ static void flexcan_set_bitrate(struct flexcan_device *flexcan, int bitrate) * based on the bitrate to get the timing of * presdiv, pseg1, pseg2, propseg */ + int i, rate, div; + bool found = false; + struct time_segment *segment; + rate = clk_get_rate(flexcan->clk); + + if (!bitrate) + bitrate = DEFAULT_BITRATE; + + if (rate % bitrate == 0) { + div = rate / bitrate; + for (i = TIME_SEGMENT_MID; i <= TIME_SEGMENT_MAX; i++) { + if (div % i == 0) { + found = true; + break; + } + } + if (!found) { + for (i = TIME_SEGMENT_MID - 1; + i >= TIME_SEGMENT_MIN; i--) { + if (div % i == 0) { + found = true; + break; + } + } + + } + } + + if (found) { + segment = &time_segments[i - TIME_SEGMENT_MIN]; + flexcan->br_presdiv = div/i - 1; + flexcan->br_propseg = segment->propseg; + flexcan->br_pseg1 = segment->pseg1; + flexcan->br_pseg2 = segment->pseg2; + flexcan->bitrate = bitrate; + } else { + pr_info("The bitrate %d can't supported with clock \ + rate of %d \n", bitrate, rate); + } } static void flexcan_update_bitrate(struct flexcan_device *flexcan) @@ -201,7 +308,7 @@ static int flexcan_dump_xmit_mb(struct flexcan_device *flexcan, char *buf) ret += sprintf(buf + ret, "mb[%d]::CS:0x%x ID:0x%x DATA[1~2]:0x%02x,0x%02x\n", - i, flexcan->hwmb[i].mb_cs.data, + i, flexcan->hwmb[i].mb_cs, flexcan->hwmb[i].mb_id, flexcan->hwmb[i].mb_data[1], flexcan->hwmb[i].mb_data[2]); return ret; @@ -214,7 +321,7 @@ static int flexcan_dump_rx_mb(struct flexcan_device *flexcan, char *buf) ret += sprintf(buf + ret, "mb[%d]::CS:0x%x ID:0x%x DATA[1~2]:0x%02x,0x%02x\n", - i, flexcan->hwmb[i].mb_cs.data, + i, flexcan->hwmb[i].mb_cs, flexcan->hwmb[i].mb_id, flexcan->hwmb[i].mb_data[1], flexcan->hwmb[i].mb_data[2]); return ret; @@ -575,6 +682,7 @@ struct net_device *flexcan_device_alloc(struct platform_device *pdev, return NULL; } flexcan_device_default(flexcan); + flexcan_set_bitrate(flexcan, flexcan->bitrate); flexcan_update_bitrate(flexcan); num = ARRAY_SIZE(flexcan_dev_attr); diff --git a/drivers/net/can/flexcan/flexcan.h b/drivers/net/can/flexcan/flexcan.h index d19cc1ee0620..51a800bd8e55 100644 --- a/drivers/net/can/flexcan/flexcan.h +++ b/drivers/net/can/flexcan/flexcan.h @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -32,17 +32,6 @@ #define FLEXCAN_DEVICE_NAME "FlexCAN" -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 @@ -55,14 +44,24 @@ struct can_mb_cs { #define CAN_MB_TX_REMOTE 0xA struct can_hw_mb { - union { - struct can_mb_cs cs; - unsigned int data; - } mb_cs; + unsigned int mb_cs; unsigned int mb_id; unsigned char mb_data[8]; }; +#define MB_CS_CODE_OFFSET 24 +#define MB_CS_CODE_MASK (0xF << MB_CS_CODE_OFFSET) +#define MB_CS_SRR_OFFSET 22 +#define MB_CS_SRR_MASK (0x1 << MB_CS_SRR_OFFSET) +#define MB_CS_IDE_OFFSET 21 +#define MB_CS_IDE_MASK (0x1 << MB_CS_IDE_OFFSET) +#define MB_CS_RTR_OFFSET 20 +#define MB_CS_RTR_MASK (0x1 << MB_CS_RTR_OFFSET) +#define MB_CS_LENGTH_OFFSET 16 +#define MB_CS_LENGTH_MASK (0xF << MB_CS_LENGTH_OFFSET) +#define MB_CS_TIMESTAMP_OFFSET 0 +#define MB_CS_TIMESTAMP_MASK (0xFF << MB_CS_TIMESTAMP_OFFSET) + #define CAN_HW_REG_MCR 0x00 #define CAN_HW_REG_CTRL 0x04 #define CAN_HW_REG_TIMER 0x08 diff --git a/drivers/net/can/flexcan/mbm.c b/drivers/net/can/flexcan/mbm.c index b0341ba9128e..c846d97daadb 100644 --- a/drivers/net/can/flexcan/mbm.c +++ b/drivers/net/can/flexcan/mbm.c @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -55,10 +55,13 @@ static void flexcan_mb_bottom(struct net_device *dev, int index) hwmb = flexcan->hwmb + index; if (flexcan->fifo || (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) { - if (hwmb->mb_cs.cs.code == CAN_MB_TX_ABORT) - hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE; + if ((hwmb->mb_cs & MB_CS_CODE_MASK) >> MB_CS_CODE_OFFSET == + CAN_MB_TX_ABORT) { + hwmb->mb_cs &= ~MB_CS_CODE_MASK; + hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET; + } - if (hwmb->mb_cs.cs.code & CAN_MB_TX_INACTIVE) { + if (hwmb->mb_cs & (CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET)) { if (netif_queue_stopped(dev)) netif_start_queue(dev); return; @@ -68,16 +71,17 @@ static void flexcan_mb_bottom(struct net_device *dev, int index) if (skb) { frame = (struct can_frame *)skb_put(skb, sizeof(*frame)); memset(frame, 0, sizeof(*frame)); - if (hwmb->mb_cs.cs.ide) + if (hwmb->mb_cs & MB_CS_IDE_MASK) frame->can_id = (hwmb->mb_id & CAN_EFF_MASK) | CAN_EFF_FLAG; else frame->can_id = (hwmb->mb_id >> 18) & CAN_SFF_MASK; - if (hwmb->mb_cs.cs.rtr) + if (hwmb->mb_cs & MB_CS_RTR_MASK) frame->can_id |= CAN_RTR_FLAG; - frame->can_dlc = hwmb->mb_cs.cs.length; + frame->can_dlc = + (hwmb->mb_cs & MB_CS_LENGTH_MASK) >> MB_CS_LENGTH_OFFSET; if (frame->can_dlc && frame->can_dlc) flexcan_memcpy(frame->data, hwmb->mb_data, @@ -85,7 +89,8 @@ static void flexcan_mb_bottom(struct net_device *dev, int index) if (flexcan->fifo || (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) { - hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE; + hwmb->mb_cs &= ~MB_CS_CODE_MASK; + hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET; if (netif_queue_stopped(dev)) netif_start_queue(dev); } @@ -101,13 +106,13 @@ static void flexcan_mb_bottom(struct net_device *dev, int index) skb->ip_summed = CHECKSUM_UNNECESSARY; netif_rx(skb); } else { - tmp = hwmb->mb_cs.data; + tmp = hwmb->mb_cs; tmp = hwmb->mb_id; tmp = hwmb->mb_data[0]; if (flexcan->fifo || (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) { - - hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE; + hwmb->mb_cs &= ~MB_CS_CODE_MASK; + hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET; if (netif_queue_stopped(dev)) netif_start_queue(dev); } @@ -131,17 +136,19 @@ static void flexcan_fifo_isr(struct net_device *dev, unsigned int iflag1) frame = (struct can_frame *)skb_put(skb, sizeof(*frame)); memset(frame, 0, sizeof(*frame)); - if (hwmb->mb_cs.cs.ide) + if (hwmb->mb_cs & MB_CS_IDE_MASK) frame->can_id = (hwmb->mb_id & CAN_EFF_MASK) | CAN_EFF_FLAG; else frame->can_id = (hwmb->mb_id >> 18) & CAN_SFF_MASK; - if (hwmb->mb_cs.cs.rtr) + if (hwmb->mb_cs & MB_CS_RTR_MASK) frame->can_id |= CAN_RTR_FLAG; - frame->can_dlc = hwmb->mb_cs.cs.length; + frame->can_dlc = + (hwmb->mb_cs & MB_CS_LENGTH_MASK) >> + MB_CS_LENGTH_OFFSET; if (frame->can_dlc && (frame->can_dlc <= 8)) flexcan_memcpy(frame->data, hwmb->mb_data, @@ -158,7 +165,7 @@ static void flexcan_fifo_isr(struct net_device *dev, unsigned int iflag1) skb->ip_summed = CHECKSUM_UNNECESSARY; netif_rx(skb); } else { - tmp = hwmb->mb_cs.data; + tmp = hwmb->mb_cs; tmp = hwmb->mb_id; tmp = hwmb->mb_data[0]; tmp = __raw_readl(flexcan->io_base + CAN_HW_REG_TIMER); @@ -252,7 +259,8 @@ int flexcan_mbm_xmit(struct flexcan_device *flexcan, struct can_frame *frame) struct can_hw_mb *hwmb = flexcan->hwmb; do { - if (hwmb[i].mb_cs.cs.code == CAN_MB_TX_INACTIVE) + if ((hwmb[i].mb_cs & MB_CS_CODE_MASK) >> MB_CS_CODE_OFFSET == + CAN_MB_TX_INACTIVE) break; if ((++i) > flexcan->maxmb) { if (flexcan->fifo) @@ -273,22 +281,24 @@ int flexcan_mbm_xmit(struct flexcan_device *flexcan, struct can_frame *frame) } if (frame->can_id & CAN_RTR_FLAG) - hwmb[i].mb_cs.cs.rtr = 1; + hwmb[i].mb_cs |= 1 << MB_CS_RTR_OFFSET; else - hwmb[i].mb_cs.cs.rtr = 0; + hwmb[i].mb_cs &= ~MB_CS_RTR_MASK; if (frame->can_id & CAN_EFF_FLAG) { - hwmb[i].mb_cs.cs.ide = 1; - hwmb[i].mb_cs.cs.srr = 1; + hwmb[i].mb_cs |= 1 << MB_CS_IDE_OFFSET; + hwmb[i].mb_cs |= 1 << MB_CS_SRR_OFFSET; hwmb[i].mb_id = frame->can_id & CAN_EFF_MASK; } else { - hwmb[i].mb_cs.cs.ide = 0; + hwmb[i].mb_cs &= ~MB_CS_IDE_MASK; hwmb[i].mb_id = (frame->can_id & CAN_SFF_MASK) << 18; } - hwmb[i].mb_cs.cs.length = frame->can_dlc; + hwmb[i].mb_cs &= ~MB_CS_LENGTH_MASK; + hwmb[i].mb_cs |= frame->can_dlc << MB_CS_LENGTH_OFFSET; flexcan_memcpy(hwmb[i].mb_data, frame->data, frame->can_dlc); - hwmb[i].mb_cs.cs.code = CAN_MB_TX_ONCE; + hwmb[i].mb_cs &= ~MB_CS_CODE_MASK; + hwmb[i].mb_cs |= CAN_MB_TX_ONCE << MB_CS_CODE_OFFSET; return 0; } @@ -325,23 +335,27 @@ void flexcan_mbm_init(struct flexcan_device *flexcan) id_table[i] = 0; } else { for (i = 0; i < rx_mb; i++) { - hwmb[i].mb_cs.cs.code = CAN_MB_RX_EMPTY; + hwmb[i].mb_cs &= ~MB_CS_CODE_MASK; + hwmb[i].mb_cs |= CAN_MB_RX_EMPTY << MB_CS_CODE_OFFSET; /* * IDE bit can not control by mask registers * So set message buffer to receive extend * or standard message. */ - if (flexcan->ext_msg && flexcan->std_msg) - hwmb[i].mb_cs.cs.ide = i & 1; - else { + if (flexcan->ext_msg && flexcan->std_msg) { + hwmb[i].mb_cs &= ~MB_CS_IDE_MASK; + hwmb[i].mb_cs |= (i & 1) << MB_CS_IDE_OFFSET; + } else { if (flexcan->ext_msg) - hwmb[i].mb_cs.cs.ide = 1; + hwmb[i].mb_cs |= 1 << MB_CS_IDE_OFFSET; } } } - for (; i <= flexcan->maxmb; i++) - hwmb[i].mb_cs.cs.code = CAN_MB_TX_INACTIVE; + for (; i <= flexcan->maxmb; i++) { + hwmb[i].mb_cs &= ~MB_CS_CODE_MASK; + hwmb[i].mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET; + } flexcan->xmit_mb = rx_mb; } diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 582eb37390ed..8a34f4679fa5 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -30,8 +30,6 @@ #include <linux/delay.h> #include <linux/spi/spi.h> -#include <mach/platform.h> - #include "enc28j60_hw.h" #define DRV_NAME "enc28j60" @@ -53,9 +51,17 @@ #define MAX_TX_RETRYCOUNT 16 #ifdef CONFIG_ARCH_STMP3XXX +#include <mach/platform.h> #include <mach/stmp3xxx.h> #include <mach/regs-ocotp.h> #endif +#ifdef CONFIG_ARCH_MXS +#include <mach/system.h> +#include <mach/hardware.h> +#include <mach/regs-ocotp.h> +#define REGS_OCOTP_BASE IO_ADDRESS(OCOTP_PHYS_ADDR) +#endif + enum { RXFILTER_NORMAL, RXFILTER_MULTI, @@ -104,12 +110,14 @@ static int enc28j60_get_mac(unsigned char *dev_addr, int idx) return false; if (!mac[idx]) { -#ifdef CONFIG_ARCH_STMP3XXX +#if defined(CONFIG_ARCH_STMP3XXX) || defined(CONFIG_ARCH_MXS) if (get_evk_board_version() >= 1) { int mac1 , mac2 , retry = 0; - stmp3xxx_setl(BM_OCOTP_CTRL_RD_BANK_OPEN, REGS_OCOTP_BASE + HW_OCOTP_CTRL); - while (__raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL) & BM_OCOTP_CTRL_BUSY) { + __raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN, + REGS_OCOTP_BASE + HW_OCOTP_CTRL_SET); + while (__raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL) & + BM_OCOTP_CTRL_BUSY) { msleep(10); retry++; if (retry > 10) diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 46799e092bc1..206be36f0d19 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -296,6 +296,17 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) bufaddr = fep->tx_bounce[index]; } + if (fep->ptimer_present) { + if (fec_ptp_do_txstamp(skb)) + estatus = BD_ENET_TX_TS; + else + estatus = 0; +#ifdef CONFIG_FEC_1588 + bdp->cbd_esc = (estatus | BD_ENET_TX_INT); + bdp->cbd_bdu = 0; +#endif + } + #ifdef CONFIG_ARCH_MXS swap_buffer(bufaddr, skb->len); #endif @@ -318,16 +329,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | BD_ENET_TX_LAST | BD_ENET_TX_TC); bdp->cbd_sc = status; - if (fep->ptimer_present) { - if (fec_ptp_do_txstamp(skb)) - estatus = BD_ENET_TX_TS; - else - estatus = 0; -#ifdef CONFIG_FEC_1588 - bdp->cbd_esc = (estatus | BD_ENET_TX_INT); - bdp->cbd_bdu = 0; -#endif - } dev->trans_start = jiffies; /* Trigger transmission start */ @@ -807,7 +808,7 @@ static struct mii_bus *fec_enet_mii_init(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct fec_enet_private *fep = netdev_priv(dev); - struct fec_enet_platform_data *pdata; + struct fec_platform_data *pdata; int err = -ENXIO, i; fep->mii_timeout = 0; @@ -836,6 +837,7 @@ static struct mii_bus *fec_enet_mii_init(struct platform_device *pdev) fep->mii_bus->priv = fep; fep->mii_bus->parent = &pdev->dev; pdata = pdev->dev.platform_data; + fep->mii_bus->phy_mask = pdata->phy_mask; fep->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); if (!fep->mii_bus->irq) { @@ -1131,17 +1133,18 @@ fec_set_mac_address(struct net_device *dev, void *p) { struct fec_enet_private *fep = netdev_priv(dev); struct sockaddr *addr = p; + u32 temp_mac[2]; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - writel(dev->dev_addr[3] | (dev->dev_addr[2] << 8) | - (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24), - fep->hwp + FEC_ADDR_LOW); - writel((dev->dev_addr[5] << 16) | (dev->dev_addr[4] << 24), - fep + FEC_ADDR_HIGH); + memcpy(&temp_mac, dev->dev_addr, ETH_ALEN); + + writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW); + writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH); + return 0; } @@ -1277,6 +1280,7 @@ fec_restart(struct net_device *dev, int duplex) /* Clear any outstanding interrupt. */ writel(0xffc00000, fep->hwp + FEC_IEVENT); +#if !defined(CONFIG_MACH_CCMX51JS) && !defined(CONFIG_MACH_CCWMX51JS) /* Reset all multicast. */ writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); @@ -1284,6 +1288,7 @@ fec_restart(struct net_device *dev, int duplex) writel(0, fep->hwp + FEC_HASH_TABLE_HIGH); writel(0, fep->hwp + FEC_HASH_TABLE_LOW); #endif +#endif /* !defined(CONFIG_MACH_CCMX51JS) && !defined(CONFIG_MACH_CCWMX51JS) */ #ifndef CONFIG_ARCH_MXS if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) { @@ -1407,6 +1412,15 @@ fec_stop(struct net_device *dev) writel(1, fep->hwp + FEC_ECNTRL); udelay(10); +#ifdef CONFIG_ARCH_MXS + /* Check MII or RMII */ + if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) + writel(readl(fep->hwp + FEC_R_CNTRL) | 0x100, + fep->hwp + FEC_R_CNTRL); + else + writel(readl(fep->hwp + FEC_R_CNTRL) & ~0x100, + fep->hwp + FEC_R_CNTRL); +#endif /* Clear outstanding MII command interrupts. */ writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT); @@ -1482,6 +1496,18 @@ fec_probe(struct platform_device *pdev) fep->phy_interface = pdata->phy; if (pdata->init && pdata->init()) goto failed_platform_init; + + /* + * The priority for getting MAC address is: + * (1) kernel command line fec_mac = xx:xx:xx... + * (2) platform data mac field got from fuse etc + * (3) bootloader set the FEC mac register + */ + + if (!is_valid_ether_addr(fec_mac_default) && + pdata->mac && is_valid_ether_addr(pdata->mac)) + memcpy(fec_mac_default, pdata->mac, + sizeof(fec_mac_default)); } else fep->phy_interface = PHY_INTERFACE_MODE_MII; @@ -1499,10 +1525,10 @@ fec_probe(struct platform_device *pdev) fep->mii_bus = fec_mii_bus; } - fep->ptp_priv = kmalloc(sizeof(struct fec_ptp_private), GFP_KERNEL); + fep->ptp_priv = kzalloc(sizeof(struct fec_ptp_private), GFP_KERNEL); if (fep->ptp_priv) { fep->ptp_priv->hwp = fep->hwp; - ret = fec_ptp_init(fep->ptp_priv); + ret = fec_ptp_init(fep->ptp_priv, pdev->id); if (ret) printk(KERN_WARNING "IEEE1588: ptp-timer is unavailable\n"); diff --git a/drivers/net/fec_1588.c b/drivers/net/fec_1588.c index 5babcc29de78..c4bf278c7f19 100644 --- a/drivers/net/fec_1588.c +++ b/drivers/net/fec_1588.c @@ -35,7 +35,7 @@ static DECLARE_WAIT_QUEUE_HEAD(ptp_rx_ts_wait); #define PTP_GET_RX_TIMEOUT (HZ/10) -static struct fec_ptp_private *ptp_private; +static struct fec_ptp_private *ptp_private[2]; /* Alloc the ring resource */ static int fec_ptp_init_circ(struct circ_buf *ptp_buf) @@ -88,14 +88,15 @@ static int fec_ptp_is_full(struct circ_buf *buf) } static int fec_ptp_insert(struct circ_buf *ptp_buf, - struct fec_ptp_data_t *data) + struct fec_ptp_data_t *data, + struct fec_ptp_private *priv) { struct fec_ptp_data_t *tmp; if (fec_ptp_is_full(ptp_buf)) return 1; - spin_lock(&ptp_private->ptp_lock); + spin_lock(&priv->ptp_lock); tmp = (struct fec_ptp_data_t *)(ptp_buf->buf) + ptp_buf->tail; tmp->key = data->key; @@ -104,13 +105,15 @@ static int fec_ptp_insert(struct circ_buf *ptp_buf, ptp_buf->tail = fec_ptp_calc_index(DEFAULT_PTP_RX_BUF_SZ, ptp_buf->tail, 1); - spin_unlock(&ptp_private->ptp_lock); + spin_unlock(&priv->ptp_lock); return 0; } static int fec_ptp_find_and_remove(struct circ_buf *ptp_buf, - int key, struct fec_ptp_data_t *data) + int key, + struct fec_ptp_data_t *data, + struct fec_ptp_private *priv) { int i; int size = DEFAULT_PTP_RX_BUF_SZ; @@ -129,10 +132,10 @@ static int fec_ptp_find_and_remove(struct circ_buf *ptp_buf, i = fec_ptp_calc_index(size, i, 1); } - spin_lock_irqsave(&ptp_private->ptp_lock, flags); + spin_lock_irqsave(&priv->ptp_lock, flags); if (i == end) { ptp_buf->head = end; - spin_unlock_irqrestore(&ptp_private->ptp_lock, flags); + spin_unlock_irqrestore(&priv->ptp_lock, flags); return 1; } @@ -140,7 +143,7 @@ static int fec_ptp_find_and_remove(struct circ_buf *ptp_buf, data->ts_time.nsec = tmp->ts_time.nsec; ptp_buf->head = fec_ptp_calc_index(size, i, 1); - spin_unlock_irqrestore(&ptp_private->ptp_lock, flags); + spin_unlock_irqrestore(&priv->ptp_lock, flags); return 0; } @@ -154,9 +157,9 @@ int fec_ptp_start(struct fec_ptp_private *priv) writel(FEC_T_CTRL_RESTART, fpp->hwp + FEC_ATIME_CTRL); writel(FEC_T_INC_40MHZ << FEC_T_INC_OFFSET, fpp->hwp + FEC_ATIME_INC); writel(FEC_T_PERIOD_ONE_SEC, fpp->hwp + FEC_ATIME_EVT_PERIOD); - writel(FEC_T_CTRL_PERIOD_RST, fpp->hwp + FEC_ATIME_CTRL); /* start counter */ - writel(FEC_T_CTRL_ENABLE, fpp->hwp + FEC_ATIME_CTRL); + writel(FEC_T_CTRL_PERIOD_RST | FEC_T_CTRL_ENABLE, + fpp->hwp + FEC_ATIME_CTRL); return 0; } @@ -175,12 +178,19 @@ void fec_ptp_stop(struct fec_ptp_private *priv) static void fec_get_curr_cnt(struct fec_ptp_private *priv, struct ptp_rtc_time *curr_time) { + u32 tempval; + + writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL); writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL); curr_time->rtc_time.nsec = readl(priv->hwp + FEC_ATIME); curr_time->rtc_time.sec = priv->prtc; + writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL); - if (readl(priv->hwp + FEC_ATIME) < curr_time->rtc_time.nsec) - curr_time->rtc_time.sec++; + tempval = readl(priv->hwp + FEC_ATIME); + if (tempval < curr_time->rtc_time.nsec) { + curr_time->rtc_time.nsec = tempval; + curr_time->rtc_time.sec = priv->prtc; + } } /* Set the 1588 timer counter registers */ @@ -190,12 +200,12 @@ static void fec_set_1588cnt(struct fec_ptp_private *priv, u32 tempval; unsigned long flags; - spin_lock_irqsave(&ptp_private->cnt_lock, flags); + spin_lock_irqsave(&priv->cnt_lock, flags); priv->prtc = fec_time->rtc_time.sec; tempval = fec_time->rtc_time.nsec; writel(tempval, priv->hwp + FEC_ATIME); - spin_unlock_irqrestore(&ptp_private->cnt_lock, flags); + spin_unlock_irqrestore(&priv->cnt_lock, flags); } /* Set the BD to ptp */ @@ -207,11 +217,11 @@ int fec_ptp_do_txstamp(struct sk_buff *skb) if (skb->len > 44) { /* Check if port is 319 for PTP Event, and check for UDP */ iph = ip_hdr(skb); - if (iph->protocol != FEC_PACKET_TYPE_UDP) + if (iph == NULL || iph->protocol != FEC_PACKET_TYPE_UDP) return 0; udph = udp_hdr(skb); - if (udph->source == 319) + if (udph != NULL && ntohs(udph->source) == 319) return 1; } @@ -244,24 +254,24 @@ void fec_ptp_store_rxstamp(struct fec_ptp_private *priv, return; udph = (struct udphdr *)(skb->data + FEC_PTP_UDP_OFFS); - if (udph->source != 319) + if (ntohs(udph->source) != 319) return; seq_id = *((u16 *)(skb->data + FEC_PTP_SEQ_ID_OFFS)); control = *((u8 *)(skb->data + FEC_PTP_CTRL_OFFS)); - tmp_rx_time.key = seq_id; + tmp_rx_time.key = ntohs(seq_id); tmp_rx_time.ts_time.sec = fpp->prtc; tmp_rx_time.ts_time.nsec = bdp->ts; switch (control) { case PTP_MSG_SYNC: - fec_ptp_insert(&(priv->rx_time_sync), &tmp_rx_time); + fec_ptp_insert(&(priv->rx_time_sync), &tmp_rx_time, priv); break; case PTP_MSG_DEL_REQ: - fec_ptp_insert(&(priv->rx_time_del_req), &tmp_rx_time); + fec_ptp_insert(&(priv->rx_time_del_req), &tmp_rx_time, priv); break; /* clear transportSpecific field*/ @@ -271,11 +281,11 @@ void fec_ptp_store_rxstamp(struct fec_ptp_private *priv, switch (msg_type) { case PTP_MSG_P_DEL_REQ: fec_ptp_insert(&(priv->rx_time_pdel_req), - &tmp_rx_time); + &tmp_rx_time, priv); break; case PTP_MSG_P_DEL_RESP: fec_ptp_insert(&(priv->rx_time_pdel_resp), - &tmp_rx_time); + &tmp_rx_time, priv); break; default: break; @@ -308,20 +318,20 @@ static uint8_t fec_get_rx_time(struct fec_ptp_private *priv, switch (mode) { case PTP_MSG_SYNC: flag = fec_ptp_find_and_remove(&(priv->rx_time_sync), - key, &tmp); + key, &tmp, priv); break; case PTP_MSG_DEL_REQ: flag = fec_ptp_find_and_remove(&(priv->rx_time_del_req), - key, &tmp); + key, &tmp, priv); break; case PTP_MSG_P_DEL_REQ: flag = fec_ptp_find_and_remove(&(priv->rx_time_pdel_req), - key, &tmp); + key, &tmp, priv); break; case PTP_MSG_P_DEL_RESP: flag = fec_ptp_find_and_remove(&(priv->rx_time_pdel_resp), - key, &tmp); + key, &tmp, priv); break; default: @@ -341,19 +351,19 @@ static uint8_t fec_get_rx_time(struct fec_ptp_private *priv, switch (mode) { case PTP_MSG_SYNC: flag = fec_ptp_find_and_remove(&(priv->rx_time_sync), - key, &tmp); + key, &tmp, priv); break; case PTP_MSG_DEL_REQ: flag = fec_ptp_find_and_remove( - &(priv->rx_time_del_req), key, &tmp); + &(priv->rx_time_del_req), key, &tmp, priv); break; case PTP_MSG_P_DEL_REQ: flag = fec_ptp_find_and_remove( - &(priv->rx_time_pdel_req), key, &tmp); + &(priv->rx_time_pdel_req), key, &tmp, priv); break; case PTP_MSG_P_DEL_RESP: flag = fec_ptp_find_and_remove( - &(priv->rx_time_pdel_resp), key, &tmp); + &(priv->rx_time_pdel_resp), key, &tmp, priv); break; } @@ -367,6 +377,75 @@ static uint8_t fec_get_rx_time(struct fec_ptp_private *priv, } } +static void fec_handle_ptpdrift(struct ptp_set_comp *comp, + struct ptp_time_correct *ptc) +{ + u32 ndrift; + u32 i; + u32 tmp, tmp_ns, tmp_prid; + u32 min_ns, min_prid, miss_ns; + + ndrift = comp->drift; + if (ndrift == 0) { + ptc->corr_inc = 0; + ptc->corr_period = 0; + return; + } + + if (ndrift >= FEC_ATIME_40MHZ) { + ptc->corr_inc = (u32)(ndrift / FEC_ATIME_40MHZ); + ptc->corr_period = 1; + return; + } + + min_ns = 1; + tmp = FEC_ATIME_40MHZ % ndrift; + tmp_prid = (u32)(FEC_ATIME_40MHZ / ndrift); + min_prid = tmp_prid; + miss_ns = tmp / tmp_prid; + for (i = 2; i <= FEC_T_INC_40MHZ; i++) { + tmp = (FEC_ATIME_40MHZ * i) % ndrift; + tmp_prid = (FEC_ATIME_40MHZ * i) / ndrift; + tmp_ns = tmp / tmp_prid; + if (tmp_ns <= 10) { + min_ns = i; + min_prid = tmp_prid; + break; + } + if (tmp_ns < miss_ns) { + min_ns = i; + min_prid = tmp_prid; + miss_ns = tmp_ns; + } + } + + ptc->corr_inc = min_ns; + ptc->corr_period = min_prid; +} + +static void fec_set_drift(struct fec_ptp_private *priv, + struct ptp_set_comp *comp) +{ + struct ptp_time_correct tc; + struct fec_ptp_private *fpp = priv; + u32 tmp, corr_ns; + + fec_handle_ptpdrift(comp, &tc); + if (tc.corr_inc == 0) + return; + + if (comp->o_ops == TRUE) + corr_ns = FEC_T_INC_40MHZ + tc.corr_inc; + else + corr_ns = FEC_T_INC_40MHZ - tc.corr_inc; + + tmp = readl(fpp->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK; + tmp |= corr_ns << FEC_T_INC_CORR_OFFSET; + writel(tmp, fpp->hwp + FEC_ATIME_INC); + + writel(tc.corr_period, fpp->hwp + FEC_ATIME_CORR); +} + static int ptp_open(struct inode *inode, struct file *file) { return 0; @@ -387,10 +466,12 @@ static int ptp_ioctl( struct ptp_rtc_time curr_time; struct ptp_time rx_time, tx_time; struct ptp_ts_data *p_ts; + struct ptp_set_comp *p_comp; struct fec_ptp_private *priv; + unsigned int minor = MINOR(inode->i_rdev); int retval = 0; - priv = (struct fec_ptp_private *) ptp_private; + priv = (struct fec_ptp_private *) ptp_private[minor]; switch (cmd) { case PTP_GET_RX_TIMESTAMP: p_ts = (struct ptp_ts_data *)arg; @@ -428,10 +509,11 @@ static int ptp_ioctl( priv->rx_time_pdel_resp.tail = 0; break; case PTP_SET_COMPENSATION: - /* TBD */ + p_comp = (struct ptp_set_comp *)arg; + fec_set_drift(priv, p_comp); break; case PTP_GET_ORIG_COMP: - /* TBD */ + ((struct ptp_get_comp *)arg)->dw_origcomp = FEC_PTP_ORIG_COMP; break; default: return -EINVAL; @@ -466,7 +548,7 @@ static void ptp_free(void) /* * Resource required for accessing 1588 Timer Registers. */ -int fec_ptp_init(struct fec_ptp_private *priv) +int fec_ptp_init(struct fec_ptp_private *priv, int id) { fec_ptp_init_circ(&(priv->rx_time_sync)); fec_ptp_init_circ(&(priv->rx_time_del_req)); @@ -475,8 +557,9 @@ int fec_ptp_init(struct fec_ptp_private *priv) spin_lock_init(&priv->ptp_lock); spin_lock_init(&priv->cnt_lock); - ptp_private = priv; - init_ptp(); + ptp_private[id] = priv; + if (id == 0) + init_ptp(); return 0; } EXPORT_SYMBOL(fec_ptp_init); diff --git a/drivers/net/fec_1588.h b/drivers/net/fec_1588.h index 55b1a8c995bd..800ff310668f 100644 --- a/drivers/net/fec_1588.h +++ b/drivers/net/fec_1588.h @@ -24,6 +24,9 @@ #include <linux/circ_buf.h> +#define FALSE 0 +#define TRUE 1 + /* FEC 1588 register bits */ #define FEC_T_CTRL_CAPTURE 0x00000800 #define FEC_T_CTRL_RESTART 0x00000200 @@ -32,8 +35,11 @@ #define FEC_T_INC_MASK 0x0000007f #define FEC_T_INC_OFFSET 0 +#define FEC_T_INC_CORR_MASK 0x00007f00 +#define FEC_T_INC_CORR_OFFSET 8 -#define FEC_T_INC_40MHZ 20 +#define FEC_T_INC_40MHZ 25 +#define FEC_ATIME_40MHZ 40000000 #define FEC_T_PERIOD_ONE_SEC 0x3B9ACA00 @@ -52,7 +58,7 @@ #define PTP_MSG_ALL_OTHER 0x5 #define PTP_GET_TX_TIMESTAMP 0x1 -#define PTP_GET_RX_TIMESTAMP 0x2 +#define PTP_GET_RX_TIMESTAMP 0x9 #define PTP_SET_RTC_TIME 0x3 #define PTP_SET_COMPENSATION 0x4 #define PTP_GET_CURRENT_TIME 0x5 @@ -64,13 +70,15 @@ #define PTP_GET_RX_TIMESTAMP_PDELAY_RESP 0xD #define FEC_PTP_DOMAIN_DLFT 0xe0000181 -#define FEC_PTP_IP_OFFS 0xE -#define FEC_PTP_UDP_OFFS 0x22 -#define FEC_PTP_MSG_TYPE_OFFS 0x2A -#define FEC_PTP_SEQ_ID_OFFS 0x48 -#define FEC_PTP_CTRL_OFFS 0x4A +#define FEC_PTP_IP_OFFS 0x0 +#define FEC_PTP_UDP_OFFS 0x14 +#define FEC_PTP_MSG_TYPE_OFFS 0x1C +#define FEC_PTP_SEQ_ID_OFFS 0x3A +#define FEC_PTP_CTRL_OFFS 0x3C #define FEC_PACKET_TYPE_UDP 0x11 +#define FEC_PTP_ORIG_COMP 0x15555555 + /* PTP standard time representation structure */ struct ptp_time{ u64 sec; /* seconds */ @@ -102,6 +110,31 @@ struct ptp_rtc_time { struct ptp_time rtc_time; }; +/* interface for PTP driver command SET_COMPENSATION */ +struct ptp_set_comp { + u32 drift; + bool o_ops; +}; + +/* interface for PTP driver command GET_ORIG_COMP */ +struct ptp_get_comp { + /* the initial compensation value */ + u32 dw_origcomp; + /* the minimum compensation value */ + u32 dw_mincomp; + /*the max compensation value*/ + u32 dw_maxcomp; + /*the min drift applying min compensation value in ppm*/ + u32 dw_mindrift; + /*the max drift applying max compensation value in ppm*/ + u32 dw_maxdrift; +}; + +struct ptp_time_correct { + u32 corr_period; + u32 corr_inc; +}; + /* PTP message version */ #define PTP_1588_MSG_VER_1 1 #define PTP_1588_MSG_VER_2 2 @@ -124,7 +157,7 @@ struct fec_ptp_private { }; #ifdef CONFIG_FEC_1588 -extern int fec_ptp_init(struct fec_ptp_private *priv); +extern int fec_ptp_init(struct fec_ptp_private *priv, int id); extern void fec_ptp_cleanup(struct fec_ptp_private *priv); extern int fec_ptp_start(struct fec_ptp_private *priv); extern void fec_ptp_stop(struct fec_ptp_private *priv); @@ -134,7 +167,7 @@ extern void fec_ptp_store_rxstamp(struct fec_ptp_private *priv, struct sk_buff *skb, struct bufdesc *bdp); #else -static inline int fec_ptp_init(struct fec_ptp_private *priv) +static inline int fec_ptp_init(struct fec_ptp_private *priv, int id) { return 1; } diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index bd4e8d72dc08..e17b70291bbc 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -264,6 +264,8 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv) (phydev->phy_id & phydrv->phy_id_mask)); } +#ifdef CONFIG_PM + static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) { struct device_driver *drv = phydev->dev.driver; @@ -295,34 +297,88 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) return true; } -/* Suspend and resume. Copied from platform_suspend and - * platform_resume - */ -static int mdio_bus_suspend(struct device * dev, pm_message_t state) +static int mdio_bus_suspend(struct device *dev) { struct phy_driver *phydrv = to_phy_driver(dev->driver); struct phy_device *phydev = to_phy_device(dev); + /* + * We must stop the state machine manually, otherwise it stops out of + * control, possibly with the phydev->lock held. Upon resume, netdev + * may call phy routines that try to grab the same lock, and that may + * lead to a deadlock. + */ + if (phydev->attached_dev) + phy_stop_machine(phydev); + if (!mdio_bus_phy_may_suspend(phydev)) return 0; + return phydrv->suspend(phydev); } -static int mdio_bus_resume(struct device * dev) +static int mdio_bus_resume(struct device *dev) { struct phy_driver *phydrv = to_phy_driver(dev->driver); struct phy_device *phydev = to_phy_device(dev); + int ret; if (!mdio_bus_phy_may_suspend(phydev)) + goto no_resume; + + ret = phydrv->resume(phydev); + if (ret < 0) + return ret; + +no_resume: + if (phydev->attached_dev) + phy_start_machine(phydev, NULL); + + return 0; +} + +static int mdio_bus_restore(struct device *dev) +{ + struct phy_device *phydev = to_phy_device(dev); + struct net_device *netdev = phydev->attached_dev; + int ret; + + if (!netdev) return 0; - return phydrv->resume(phydev); + + ret = phy_init_hw(phydev); + if (ret < 0) + return ret; + + /* The PHY needs to renegotiate. */ + phydev->link = 0; + phydev->state = PHY_UP; + + phy_start_machine(phydev, NULL); + + return 0; } +static struct dev_pm_ops mdio_bus_pm_ops = { + .suspend = mdio_bus_suspend, + .resume = mdio_bus_resume, + .freeze = mdio_bus_suspend, + .thaw = mdio_bus_resume, + .restore = mdio_bus_restore, +}; + +#define MDIO_BUS_PM_OPS (&mdio_bus_pm_ops) + +#else + +#define MDIO_BUS_PM_OPS NULL + +#endif /* CONFIG_PM */ + struct bus_type mdio_bus_type = { .name = "mdio_bus", .match = mdio_bus_match, - .suspend = mdio_bus_suspend, - .resume = mdio_bus_resume, + .pm = MDIO_BUS_PM_OPS, }; EXPORT_SYMBOL(mdio_bus_type); diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index eda94fcd4065..d2df6382e123 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -413,7 +413,6 @@ EXPORT_SYMBOL(phy_start_aneg); static void phy_change(struct work_struct *work); -static void phy_state_machine(struct work_struct *work); /** * phy_start_machine - start PHY state machine tracking @@ -433,7 +432,6 @@ void phy_start_machine(struct phy_device *phydev, { phydev->adjust_state = handler; - INIT_DELAYED_WORK(&phydev->state_queue, phy_state_machine); schedule_delayed_work(&phydev->state_queue, HZ); } @@ -764,7 +762,7 @@ EXPORT_SYMBOL(phy_start); * phy_state_machine - Handle the state machine * @work: work_struct that describes the work to be done */ -static void phy_state_machine(struct work_struct *work) +void phy_state_machine(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); struct phy_device *phydev = diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index b10fedd82143..adbc0fded130 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -177,6 +177,7 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) dev->state = PHY_DOWN; mutex_init(&dev->lock); + INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); return dev; } @@ -378,6 +379,20 @@ void phy_disconnect(struct phy_device *phydev) } EXPORT_SYMBOL(phy_disconnect); +int phy_init_hw(struct phy_device *phydev) +{ + int ret; + + if (!phydev->drv || !phydev->drv->config_init) + return 0; + + ret = phy_scan_fixups(phydev); + if (ret < 0) + return ret; + + return phydev->drv->config_init(phydev); +} + /** * phy_attach_direct - attach a network device to a given PHY device pointer * @dev: network device to attach @@ -425,21 +440,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, /* Do initial configuration here, now that * we have certain key parameters * (dev_flags and interface) */ - if (phydev->drv->config_init) { - int err; - - err = phy_scan_fixups(phydev); - - if (err < 0) - return err; - - err = phydev->drv->config_init(phydev); - - if (err < 0) - return err; - } - - return 0; + return phy_init_hw(phydev); } EXPORT_SYMBOL(phy_attach_direct); diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index d4c82f5fa555..a13d107a412b 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -789,6 +789,7 @@ static void smsc911x_phy_adjust_link(struct net_device *dev) } pdata->last_carrier = carrier; } + udelay(10); } static int smsc911x_mii_probe(struct net_device *dev) @@ -1011,7 +1012,7 @@ static int smsc911x_poll(struct napi_struct *napi, int budget) struct net_device *dev = pdata->dev; int npackets = 0; - while (likely(netif_running(dev)) && (npackets < budget)) { + while (npackets < budget) { unsigned int pktlength; unsigned int pktwords; struct sk_buff *skb; @@ -1584,7 +1585,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id) if (unlikely(intsts & inten & INT_STS_PHY_INT_)) { smsc911x_reg_write( pdata, INT_STS , INT_STS_PHY_INT_); temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, MII_INTSTS); - SMSC_TRACE("PHY interrupt, sts 0x%04X", (u16)temp); + SMSC_TRACE(DRV,"PHY interrupt, sts 0x%04X", (u16)temp); smsc911x_phy_adjust_link(dev); serviced = IRQ_HANDLED; } diff --git a/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c b/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c index 1ca77e513493..9d0c3773d4d7 100644 --- a/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c +++ b/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c @@ -56,7 +56,7 @@ ATH_DEBUG_INSTANTIATE_MODULE_VAR(android, #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) -char fwpath[256] = "/system/wifi"; +char fwpath[256] = "/lib/firmware/ath6k/AR6102"; #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */ int buspm = WLAN_PWR_CTRL_CUT_PWR; int wow2mode = WLAN_PWR_CTRL_CUT_PWR; diff --git a/drivers/power/mxs/Makefile b/drivers/power/mxs/Makefile index 6662defd9c70..c7675a9ec52b 100644 --- a/drivers/power/mxs/Makefile +++ b/drivers/power/mxs/Makefile @@ -5,5 +5,5 @@ obj-$(CONFIG_BATTERY_MXS) += mxs-battery.o mxs-battery-objs := ddi_bc_api.o ddi_bc_hw.o ddi_bc_init.o \ - ddi_bc_ramp.o ddi_bc_sm.o ddi_power_battery.o linux.o + ddi_bc_ramp.o ddi_bc_sm.o ddi_power_battery.o linux.o fiq.o diff --git a/drivers/power/mxs/ddi_bc_internal.h b/drivers/power/mxs/ddi_bc_internal.h index a8510d08935c..b5bceeffae98 100644 --- a/drivers/power/mxs/ddi_bc_internal.h +++ b/drivers/power/mxs/ddi_bc_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2010 Freescale Semiconductor, Inc. */ /* @@ -41,6 +41,7 @@ /* Externs */ +#include <linux/kernel.h> extern bool g_ddi_bc_Configured; extern ddi_bc_Cfg_t g_ddi_bc_Configuration; diff --git a/drivers/power/mxs/ddi_power_battery.c b/drivers/power/mxs/ddi_power_battery.c index 6e2119af1676..762f29bd784e 100644 --- a/drivers/power/mxs/ddi_power_battery.c +++ b/drivers/power/mxs/ddi_power_battery.c @@ -1805,9 +1805,11 @@ void ddi_power_enable_vddio_interrupt(bool enable) } + void ddi_power_handle_vddio_brnout(void) { - if (ddi_power_GetPmu5vStatus() == new_5v_connection) { + if (ddi_power_GetPmu5vStatus() == new_5v_connection || + (ddi_power_GetPmu5vStatus() == new_5v_disconnection)) { ddi_power_enable_vddio_interrupt(false); } else { #ifdef DEBUG_IRQS diff --git a/drivers/power/mxs/fiq.S b/drivers/power/mxs/fiq.S index ee71730c85c9..1ad380d07efd 100644 --- a/drivers/power/mxs/fiq.S +++ b/drivers/power/mxs/fiq.S @@ -19,11 +19,10 @@ #include <linux/linkage.h> #include <asm/assembler.h> -#include <mach/platform.h> #include <mach/hardware.h> #include <asm/pgtable-hwdef.h> #include <mach/regs-power.h> -#include <mach/regs-clkctrl.h> +#include <mach/../../regs-clkctrl.h> #include <mach/regs-timrot.h> .align 5 @@ -33,7 +32,6 @@ .globl lock_vector_tlb power_fiq_start: - ldr r8,power_reg ldr r9,[r8,#HW_POWER_CTRL ] ldr r10,power_off @@ -101,7 +99,7 @@ check_dcdc4p2: subs pc,lr, #4 power_reg: - .long REGS_POWER_BASE + .long IO_ADDRESS(POWER_PHYS_ADDR) power_off: .long 0x3e770001 power_bo: diff --git a/drivers/power/mxs/linux.c b/drivers/power/mxs/linux.c index 6a3172415145..1c2dfc10f7ca 100644 --- a/drivers/power/mxs/linux.c +++ b/drivers/power/mxs/linux.c @@ -102,7 +102,7 @@ struct mxs_info { #define IRQ_DCDC4P2_BRNOUT IRQ_DCDC4P2_BO #endif -/* #define POWER_FIQ */ +#define POWER_FIQ /* #define DEBUG_IRQS */ @@ -129,9 +129,7 @@ void init_protection(struct mxs_info *info) battery_voltage = ddi_power_GetBattery(); /* InitializeFiqSystem(); */ -#ifdef CONFIG_ARCH_MX23 ddi_power_InitOutputBrownouts(); -#endif /* if we start the kernel with 4p2 already started @@ -238,12 +236,12 @@ static void check_and_handle_5v_connection(struct mxs_info *info) */ if ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == - (0x8 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT)) { + (0x20 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT)) { dev_info(info->dev, "waiting USB enum done...\r\n"); } while ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) - == (0x8 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT)) { + == (0x20 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT)) { msleep(50); } #endif @@ -299,7 +297,7 @@ static void check_and_handle_5v_connection(struct mxs_info *info) __raw_writel(__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) & (~BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) - | (0x8 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT), + | (0x20 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT), REGS_POWER_BASE + HW_POWER_5VCTRL); } @@ -659,6 +657,8 @@ static irqreturn_t mxs_irq_batt_brnout(int irq, void *cookie) #endif return IRQ_HANDLED; } + + static irqreturn_t mxs_irq_vddd_brnout(int irq, void *cookie) { #ifdef DEBUG_IRQS @@ -1144,13 +1144,13 @@ static int __init mxs_bat_init(void) #ifdef CONFIG_MXS_VBUS_CURRENT_DRAW if (((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) & - BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x8000) + BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x20000) && ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) & BM_POWER_5VCTRL_PWD_CHARGE_4P2) == 0)) { #ifdef CONFIG_USB_GADGET printk(KERN_INFO "USB GADGET exist,wait USB enum done...\r\n"); while (((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) - & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x8000) && + & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x20000) && ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) & BM_POWER_5VCTRL_PWD_CHARGE_4P2) == 0)) ; @@ -1161,8 +1161,7 @@ static int __init mxs_bat_init(void) } cpu = clk_get(NULL, "cpu"); pll0 = clk_get(NULL, "ref_cpu"); - if (cpu->set_parent) - cpu->set_parent(cpu, pll0); + clk_set_parent(cpu, pll0); #endif return platform_driver_register(&mxs_batdrv); } diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index fd3183e30a1c..804c32cabb50 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -153,4 +153,9 @@ config REGULATOR_MC9S08DZ60 depends on MXC_PMIC_MC9S08DZ60 default y +config REGULATOR_MAX17135 + tristate "Maxim MAX17135 Regulator Support" + depends on REGULATOR + default n + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index a10178d99acc..d88116ba8139 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o +obj-$(CONFIG_REGULATOR_MAX17135) += max17135-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += reg-mc13892.o obj-$(CONFIG_REGULATOR_MC13783) += reg-mc13783.o diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 09492700cddf..bd320c1ab70c 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -109,6 +109,16 @@ config RTC_INTF_DEV_UIE_EMUL clock several times per second, please enable this option only if you know that you really need it. +config RTC_INTF_ALARM + bool "Android alarm driver" + depends on RTC_CLASS + default y + help + Provides non-wakeup and rtc backed wakeup alarms based on rtc or + elapsed realtime, and a non-wakeup alarm on the monotonic clock. + Also provides an ioctl to set the wall time which must be used + for elapsed realtime to work. + config RTC_DRV_TEST tristate "Test driver/device" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 91da97eca589..c8df86258348 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o obj-$(CONFIG_RTC_CLASS) += rtc-core.o rtc-core-y := class.o interface.o +rtc-core-$(CONFIG_RTC_INTF_ALARM) += alarm.o rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c index 5d410fd9d5d2..beb31415a4da 100644 --- a/drivers/rtc/rtc-mxc_v2.c +++ b/drivers/rtc/rtc-mxc_v2.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -37,6 +37,10 @@ #include <linux/uaccess.h> #include <mach/hardware.h> #include <asm/io.h> +#include <linux/mxc_srtc.h> + + +#define SRTC_LPSCLR_LLPSC_LSH 17 /* start bit for LSB time value */ #define SRTC_LPPDR_INIT 0x41736166 /* init for glitch detect */ @@ -147,6 +151,12 @@ struct rtc_drv_data { bool irq_enable; }; + +/* completion event for implementing RTC_WAIT_FOR_TIME_SET ioctl */ +DECLARE_COMPLETION(srtc_completion); +/* global to save difference of 47-bit counter value */ +static int64_t time_diff; + /*! * @defgroup RTC Real Time Clock (RTC) Driver */ @@ -313,6 +323,8 @@ static int mxc_rtc_ioctl(struct device *dev, unsigned int cmd, void __iomem *ioaddr = pdata->ioaddr; unsigned long lock_flags = 0; u32 lp_cr; + u64 time_47bit; + int retVal; switch (cmd) { case RTC_AIE_OFF: @@ -339,6 +351,36 @@ static int mxc_rtc_ioctl(struct device *dev, unsigned int cmd, __raw_writel(lp_cr, ioaddr + SRTC_LPCR); spin_unlock_irqrestore(&rtc_lock, lock_flags); return 0; + + case RTC_READ_TIME_47BIT: + time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 | + ((u64) __raw_readl(ioaddr + SRTC_LPSCLR))); + time_47bit >>= SRTC_LPSCLR_LLPSC_LSH; + + if (arg && copy_to_user((u64 *) arg, &time_47bit, sizeof(u64))) + return -EFAULT; + + return 0; + + case RTC_WAIT_TIME_SET: + + /* don't block without releasing mutex first */ + mutex_unlock(&pdata->rtc->ops_lock); + + /* sleep until awakened by SRTC driver when LPSCMR is changed */ + wait_for_completion(&srtc_completion); + + /* relock mutex because rtc_dev_ioctl will unlock again */ + retVal = mutex_lock_interruptible(&pdata->rtc->ops_lock); + + /* copy the new time difference = new time - previous time + * to the user param. The difference is a signed value */ + if (arg && copy_to_user((int64_t *) arg, &time_diff, + sizeof(int64_t))) + return -EFAULT; + + return retVal; + } return -ENOIOCTLCMD; @@ -372,14 +414,31 @@ static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm) struct rtc_drv_data *pdata = dev_get_drvdata(dev); void __iomem *ioaddr = pdata->ioaddr; unsigned long time; + u64 old_time_47bit, new_time_47bit; int ret; ret = rtc_tm_to_time(tm, &time); if (ret != 0) return ret; + old_time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 | + ((u64) __raw_readl(ioaddr + SRTC_LPSCLR))); + old_time_47bit >>= SRTC_LPSCLR_LLPSC_LSH; + __raw_writel(time, ioaddr + SRTC_LPSCMR); rtc_write_sync_lp(ioaddr); + new_time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 | + ((u64) __raw_readl(ioaddr + SRTC_LPSCLR))); + new_time_47bit >>= SRTC_LPSCLR_LLPSC_LSH; + + /* update the difference between previous time and new time */ + time_diff = new_time_47bit - old_time_47bit; + + /* signal all waiting threads that time changed */ + complete_all(&srtc_completion); + /* reinitialize completion variable */ + INIT_COMPLETION(srtc_completion); + return 0; } @@ -549,41 +608,30 @@ static int mxc_rtc_probe(struct platform_device *pdev) /* clear lp interrupt status */ __raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR); - udelay(100);; + udelay(100); plat_data = (struct mxc_srtc_platform_data *)pdev->dev.platform_data; - clk = clk_get(NULL, "iim_clk"); - clk_enable(clk); - srtc_secmode_addr = ioremap(plat_data->srtc_sec_mode_addr, 1); - - /* Check SRTC security mode */ - if (((__raw_readl(srtc_secmode_addr) & SRTC_SECMODE_MASK) == - SRTC_SECMODE_LOW) && (cpu_is_mx51_rev(CHIP_REV_1_0) == 1)) { - /* Workaround for MX51 TO1 due to inaccurate CKIL clock */ - __raw_writel(SRTC_LPCR_EN_LP, ioaddr + SRTC_LPCR); - udelay(100); - } else { - /* move out of init state */ - __raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), - ioaddr + SRTC_LPCR); - udelay(100); + /* move out of init state */ + __raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), + ioaddr + SRTC_LPCR); - while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0); + udelay(100); - /* move out of non-valid state */ - __raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA | - SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR); + while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0) + ; - udelay(100); + /* move out of non-valid state */ + __raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA | + SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR); - while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0); + udelay(100); - __raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR); - udelay(100); - } - clk_disable(clk); - clk_put(clk); + while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0) + ; + + __raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR); + udelay(100); rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops, THIS_MODULE); diff --git a/drivers/rtc/rtc-mxs.c b/drivers/rtc/rtc-mxs.c index 0e2b0e1e14f6..bb4c33b1a0ba 100644 --- a/drivers/rtc/rtc-mxs.c +++ b/drivers/rtc/rtc-mxs.c @@ -254,6 +254,8 @@ static int mxs_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc_data); + device_init_wakeup(&pdev->dev, 1); + return 0; } diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 869337a7fd68..b41db4d22436 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -373,6 +373,24 @@ config SERIAL_MXS_AUART help Driver for Freescale i.MXS internal application serial port +config SERIAL_MXS_AUART_CONSOLE + bool "Support for console on i.MXS application serial port" + depends on SERIAL_MXS_AUART=y + select SERIAL_CORE_CONSOLE + ---help--- + Say Y here if you wish to use the i.MXS app serial port as the + system console (the system console is the device which receives all + kernel messages and warnings and which allows logins in single user + mode). + + Even if you say Y here, the currently visible framebuffer console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttySP1". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + + config SERIAL_MXS_DUART_CONSOLE bool "Support for console on i.MXS debug serial port" depends on SERIAL_MXS_DUART=y diff --git a/drivers/serial/mxs-auart.c b/drivers/serial/mxs-auart.c index 0eea46d71979..63d7d9128efc 100644 --- a/drivers/serial/mxs-auart.c +++ b/drivers/serial/mxs-auart.c @@ -19,6 +19,7 @@ #include <linux/device.h> #include <linux/errno.h> #include <linux/init.h> +#include <linux/console.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/slab.h> @@ -47,6 +48,8 @@ #define MXS_AUART_MAJOR 242 #define MXS_AUART_RX_THRESHOLD 16 +static struct uart_driver auart_driver; + struct mxs_auart_port { struct uart_port port; @@ -514,7 +517,7 @@ static void mxs_auart_settermios(struct uart_port *u, /* parity */ if (cflag & PARENB) { - ctrl |= BM_UARTAPP_LINECTRL_PEN | BM_UARTAPP_LINECTRL_SPS; + ctrl |= BM_UARTAPP_LINECTRL_PEN; if ((cflag & PARODD) == 0) ctrl |= BM_UARTAPP_LINECTRL_EPS; } @@ -565,9 +568,33 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context) mxs_auart_tx_chars(s); istat &= ~BM_UARTAPP_INTR_TXIS; } - if (istat & 0xFFFF) + /* modem status interrupt bits are undefined + after reset,and the hardware do not support + DSRMIS,DCDMIS and RIMIS bit,so we should ingore + them when they are pending. */ + if (istat & (BM_UARTAPP_INTR_ABDIS + | BM_UARTAPP_INTR_OEIS + | BM_UARTAPP_INTR_BEIS + | BM_UARTAPP_INTR_PEIS + | BM_UARTAPP_INTR_FEIS + | BM_UARTAPP_INTR_RTIS + | BM_UARTAPP_INTR_TXIS + | BM_UARTAPP_INTR_RXIS + | BM_UARTAPP_INTR_CTSMIS)) { dev_info(s->dev, "Unhandled status %x\n", istat); - __raw_writel(istatus & 0xFFFF, + } + __raw_writel(istatus & (BM_UARTAPP_INTR_ABDIS + | BM_UARTAPP_INTR_OEIS + | BM_UARTAPP_INTR_BEIS + | BM_UARTAPP_INTR_PEIS + | BM_UARTAPP_INTR_FEIS + | BM_UARTAPP_INTR_RTIS + | BM_UARTAPP_INTR_TXIS + | BM_UARTAPP_INTR_RXIS + | BM_UARTAPP_INTR_DSRMIS + | BM_UARTAPP_INTR_DCDMIS + | BM_UARTAPP_INTR_CTSMIS + | BM_UARTAPP_INTR_RIMIS), s->port.membase + HW_UARTAPP_INTR_CLR); return IRQ_HANDLED; @@ -761,7 +788,160 @@ static struct uart_ops mxs_auart_ops = { .config_port = mxs_auart_config_port, .verify_port = mxs_auart_verify_port, }; +#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE +static struct mxs_auart_port auart_port[CONFIG_MXS_AUART_PORTS] = {}; + +static void +auart_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *port; + unsigned int status, old_cr; + int i; + + if (co->index > CONFIG_MXS_AUART_PORTS || co->index < 0) + return; + + port = &auart_port[co->index].port; + + /* First save the CR then disable the interrupts */ + old_cr = __raw_readl(port->membase + HW_UARTAPP_CTRL2); + __raw_writel(BM_UARTAPP_CTRL2_UARTEN | BM_UARTAPP_CTRL2_TXE, + port->membase + HW_UARTAPP_CTRL2_SET); + + /* Now, do each character */ + for (i = 0; i < count; i++) { + do { + status = __raw_readl(port->membase + HW_UARTAPP_STAT); + } while (status & BM_UARTAPP_STAT_TXFF); + + __raw_writel(s[i], port->membase + HW_UARTAPP_DATA); + if (s[i] == '\n') { + do { + status = __raw_readl(port->membase + + HW_UARTAPP_STAT); + } while (status & BM_UARTAPP_STAT_TXFF); + __raw_writel('\r', port->membase + HW_UARTAPP_DATA); + } + } + + /* + * Finally, wait for transmitter to become empty + * and restore the TCR + */ + do { + status = __raw_readl(port->membase + HW_UARTAPP_STAT); + } while (status & BM_UARTAPP_STAT_BUSY); + __raw_writel(old_cr, port->membase + HW_UARTAPP_CTRL2); +} + +static void __init +auart_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + if (__raw_readl(port->membase + HW_UARTAPP_CTRL2) + & BM_UARTAPP_CTRL2_UARTEN) { + unsigned int lcr_h, quot; + lcr_h = __raw_readl(port->membase + HW_UARTAPP_LINECTRL); + + *parity = 'n'; + if (lcr_h & BM_UARTAPP_LINECTRL_PEN) { + if (lcr_h & BM_UARTAPP_LINECTRL_EPS) + *parity = 'e'; + else + *parity = 'o'; + } + + if ((lcr_h & BM_UARTAPP_LINECTRL_WLEN) + == BF_UARTAPP_LINECTRL_WLEN(2)) + *bits = 7; + else + *bits = 8; + + quot = (((__raw_readl(port->membase + HW_UARTAPP_LINECTRL) + & BM_UARTAPP_LINECTRL_BAUD_DIVINT)) + >> (BP_UARTAPP_LINECTRL_BAUD_DIVINT - 6)) + | (((__raw_readl(port->membase + HW_UARTAPP_LINECTRL) + & BM_UARTAPP_LINECTRL_BAUD_DIVFRAC)) + >> BP_UARTAPP_LINECTRL_BAUD_DIVFRAC); + if (quot == 0) + quot = 1; + *baud = (port->uartclk << 2) / quot; + } +} + +static int __init auart_console_setup(struct console *co, char *options) +{ + struct mxs_auart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index > CONFIG_MXS_AUART_PORTS || co->index < 0) + return -EINVAL; + + port = &auart_port[co->index].port; + + if (port->port.membase == 0) { + if (cpu_is_mx23()) { + if (co->index == 1) { + port->port.membase = IO_ADDRESS(0x8006C000); + port->port.mapbase = 0x8006C000; + } else { + port->port.membase = IO_ADDRESS(0x8006E000); + port->port.mapbase = 0x8006E000; + } + } + + port->port.fifosize = 16; + port->port.ops = &mxs_auart_ops; + port->port.flags = ASYNC_BOOT_AUTOCONF; + port->port.line = 0; + } + mxs_auart_reset(port); + + __raw_writel(BM_UARTAPP_CTRL2_UARTEN, + port->port.membase + HW_UARTAPP_CTRL2_SET); + + if (port->clk == NULL || IS_ERR(port->clk)) { + port->clk = clk_get(NULL, "uart"); + if (port->clk == NULL || IS_ERR(port->clk)) + return -ENODEV; + port->port.uartclk = clk_get_rate(port->clk); + } + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + auart_console_get_options(port, &baud, &parity, &bits); + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console auart_console = { + .name = "ttySP", + .write = auart_console_write, + .device = uart_console_device, + .setup = auart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &auart_driver, +}; +#ifdef CONFIG_MXS_EARLY_CONSOLE +static int __init auart_console_init(void) +{ + register_console(&auart_console); + return 0; +} + +console_initcall(auart_console_init); +#endif + +#endif static struct uart_driver auart_driver = { .owner = THIS_MODULE, .driver_name = "auart", @@ -769,6 +949,9 @@ static struct uart_driver auart_driver = { .major = MXS_AUART_MAJOR, .minor = 0, .nr = CONFIG_MXS_AUART_PORTS, +#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE + .cons = &auart_console, +#endif }; static int __devinit mxs_auart_probe(struct platform_device *pdev) @@ -849,6 +1032,10 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); +#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE + memcpy(&auart_port[pdev->id], s, sizeof(struct mxs_auart_port)); +#endif + ret = uart_add_one_port(&auart_driver, &s->port); if (ret) goto out_free_clk; diff --git a/drivers/serial/mxs-duart.c b/drivers/serial/mxs-duart.c index 5d006f380930..171b8628faee 100644 --- a/drivers/serial/mxs-duart.c +++ b/drivers/serial/mxs-duart.c @@ -735,9 +735,40 @@ static int __devexit duart_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int duart_suspend(struct platform_device *pdev, + pm_message_t state) +{ + int ret = 0; + if (!duart_port.suspended) { + ret = uart_suspend_port(&duart_drv, &duart_port.port); + if (!ret) + duart_port.suspended = 1; + } + return ret; +} + +static int duart_resume(struct platform_device *pdev, + pm_message_t state) +{ + int ret = 0; + if (duart_port.suspended) { + ret = uart_resume_port(&duart_drv, &duart_port.port); + if (!ret) + duart_port.suspended = 0; + } + return ret; +} +#else +#define duart_suspend NULL +#define duart_resume NULL +#endif + static struct platform_driver duart_driver = { .probe = duart_probe, .remove = __devexit_p(duart_remove), + .suspend = duart_suspend, + .resume = duart_resume, .driver = { .name = "mxs-duart", .owner = THIS_MODULE, diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index e16915107c6b..736a12ff9045 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -261,6 +261,11 @@ config SPI_STMP3XXX help SPI driver for Freescale STMP37xx/378x SoC SSP interface +config SPI_MXS + tristate "Freescale MXS SPI/SSP controller" + depends on ARCH_MXS && SPI_MASTER + help + SPI driver for Freescale MXS SoC SSP interface # # Add new SPI master controllers in alphabetical order above this line # diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index b7cfb6245c0b..b6dbdf064181 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_SPI_MXC) += mxc_spi.o obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o +obj-$(CONFIG_SPI_MXS) += spi_mxs.o # ... add above this line ... # SPI protocol drivers (device/link on bus) diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index cfe40a4526a7..5f4aa2e90392 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -657,7 +657,7 @@ void mxc_spi_chipselect(struct spi_device *spi, int is_active) if (spi->mode & SPI_CPHA) ctrl_reg |= spi_ver_def->mode_mask << spi_ver_def->pha_shift; - if (!(spi->mode & SPI_CPOL)) + if (spi->mode & SPI_CPOL) ctrl_reg |= spi_ver_def->mode_mask << spi_ver_def-> low_pol_shift; @@ -824,16 +824,23 @@ int mxc_spi_poll_transfer(struct spi_device *spi, struct spi_transfer *t) master_drv_data->transfer.count = t->len; fifo_size = master_drv_data->spi_ver_def->fifo_size; - count = (t->len > fifo_size) ? fifo_size : t->len; - spi_put_tx_data(master_drv_data->base, count, master_drv_data); + while (master_drv_data->transfer.count) { + count = (master_drv_data->transfer.count > fifo_size) ? + fifo_size : master_drv_data->transfer.count; - while ((((status = __raw_readl(master_drv_data->test_addr)) & - master_drv_data->spi_ver_def->rx_cnt_mask) >> master_drv_data-> - spi_ver_def->rx_cnt_off) != count); + spi_put_tx_data(master_drv_data->base, count, master_drv_data); - for (i = 0; i < count; i++) { - rx_tmp = __raw_readl(master_drv_data->base + MXC_CSPIRXDATA); - master_drv_data->transfer.rx_get(master_drv_data, rx_tmp); + while ((((status = __raw_readl(master_drv_data->test_addr)) & + master_drv_data->spi_ver_def->rx_cnt_mask) >> master_drv_data-> + spi_ver_def->rx_cnt_off) != count) + ; + + for (i = 0; i < count; i++) { + rx_tmp = __raw_readl(master_drv_data->base + MXC_CSPIRXDATA); + master_drv_data->transfer.rx_get(master_drv_data, rx_tmp); + } + + master_drv_data->transfer.count -= count; } clk_disable(master_drv_data->clk); @@ -864,8 +871,19 @@ int mxc_spi_transfer(struct spi_device *spi, struct spi_transfer *t) int chipselect_status; u32 fifo_size; +#if defined(CONFIG_MODULE_CCXMX51) + /** + * The ConnectCore i.MX51/Wi-i.MX51 use this bus to communicate with + * the pmic, using poll transfers. Because that bus is also used to + * communicate the cpu with other devices, use also poll transfers + * to avoid conflicts. + */ + if (spi->master->bus_num == 1) { + mxc_spi_poll_transfer(spi, t); + return t->len; + } +#endif /* Get the master controller driver data from spi device's master */ - master_drv_data = spi_master_get_devdata(spi->master); chipselect_status = __raw_readl(MXC_CSPICONFIG + diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 17d89a8124ad..da7c984b5641 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -43,6 +43,7 @@ static struct proc_dir_entry *binder_proc_dir_entry_proc; static struct hlist_head binder_dead_nodes; static HLIST_HEAD(binder_deferred_list); static DEFINE_MUTEX(binder_deferred_lock); +static struct workqueue_struct *binder_deferred_workqueue; static int binder_read_proc_proc(char *page, char **start, off_t off, int count, int *eof, void *data); @@ -2986,6 +2987,7 @@ static void binder_deferred_release(struct binder_proc *proc) int i; for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) { if (proc->pages[i]) { + void *page_addr = proc->buffer + i * PAGE_SIZE; if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) printk(KERN_INFO @@ -2993,6 +2995,8 @@ static void binder_deferred_release(struct binder_proc *proc) "page %d at %p not freed\n", proc->pid, i, proc->buffer + i * PAGE_SIZE); + unmap_kernel_range((unsigned long)page_addr, + PAGE_SIZE); __free_page(proc->pages[i]); page_count++; } @@ -3062,7 +3066,7 @@ static void binder_defer_work(struct binder_proc *proc, int defer) if (hlist_unhashed(&proc->deferred_work_node)) { hlist_add_head(&proc->deferred_work_node, &binder_deferred_list); - schedule_work(&binder_deferred_work); + queue_work(binder_deferred_workqueue, &binder_deferred_work); } mutex_unlock(&binder_deferred_lock); } @@ -3690,6 +3694,10 @@ static int __init binder_init(void) { int ret; + binder_deferred_workqueue = create_singlethread_workqueue("binder"); + if (!binder_deferred_workqueue) + return -ENOMEM; + binder_proc_dir_entry_root = proc_mkdir("binder", NULL); if (binder_proc_dir_entry_root) binder_proc_dir_entry_proc = proc_mkdir("proc", diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c index 6c10b456c6cc..7f64f8fb26b0 100644 --- a/drivers/staging/android/logger.c +++ b/drivers/staging/android/logger.c @@ -556,6 +556,7 @@ static struct logger_log VAR = { \ DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024) DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024) DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024) +DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 64*1024) static struct logger_log *get_log_from_minor(int minor) { @@ -565,6 +566,8 @@ static struct logger_log *get_log_from_minor(int minor) return &log_events; if (log_radio.misc.minor == minor) return &log_radio; + if (log_system.misc.minor == minor) + return &log_system; return NULL; } @@ -601,6 +604,10 @@ static int __init logger_init(void) if (unlikely(ret)) goto out; + ret = init_log(&log_system); + if (unlikely(ret)) + goto out; + out: return ret; } diff --git a/drivers/staging/android/logger.h b/drivers/staging/android/logger.h index a562434d7419..2cb06e9d8f98 100644 --- a/drivers/staging/android/logger.h +++ b/drivers/staging/android/logger.h @@ -32,6 +32,7 @@ struct logger_entry { #define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */ #define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */ +#define LOGGER_LOG_SYSTEM "log_system" /* system/framework messages */ #define LOGGER_LOG_MAIN "log_main" /* everything else */ #define LOGGER_ENTRY_MAX_LEN (4*1024) diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 803b891dc85e..572dc062759a 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -18,6 +18,9 @@ #include <linux/mm.h> #include <linux/oom.h> #include <linux/sched.h> +#include <linux/nodemask.h> +#include <linux/vmstat.h> +#include <linux/notifier.h> static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask); @@ -41,6 +44,8 @@ static size_t lowmem_minfree[6] = { }; static int lowmem_minfree_size = 4; +static struct task_struct *lowmem_deathpending; + #define lowmem_print(level, x...) \ do { \ if (lowmem_debug_level >= (level)) \ @@ -54,6 +59,24 @@ module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size, S_IRUGO | S_IWUSR); module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR); +static int +task_notify_func(struct notifier_block *self, unsigned long val, void *data); + +static struct notifier_block task_nb = { + .notifier_call = task_notify_func, +}; + +static int +task_notify_func(struct notifier_block *self, unsigned long val, void *data) +{ + struct task_struct *task = data; + if (task == lowmem_deathpending) { + lowmem_deathpending = NULL; + task_free_unregister(&task_nb); + } + return NOTIFY_OK; +} + static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask) { struct task_struct *p; @@ -67,6 +90,24 @@ static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask) int array_size = ARRAY_SIZE(lowmem_adj); int other_free = global_page_state(NR_FREE_PAGES); int other_file = global_page_state(NR_FILE_PAGES); + int node; + + /* + * If we already have a death outstanding, then + * bail out right away; indicating to vmscan + * that we have nothing further to offer on + * this pass. + */ + if (lowmem_deathpending) + return 0; + + for_each_node_state(node, N_HIGH_MEMORY) { + struct zone *z = + &NODE_DATA(node)->node_zones[ZONE_DMA]; + + other_free -= zone_page_state(z, NR_FREE_PAGES); + other_file -= zone_page_state(z, NR_FILE_PAGES); + } if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; @@ -128,9 +169,19 @@ static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask) p->pid, p->comm, oom_adj, tasksize); } if (selected) { + if (fatal_signal_pending(selected)) { + pr_warning("process %d is suffering a slow death\n", + selected->pid); + read_unlock(&tasklist_lock); + return rem; + } lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", selected->pid, selected->comm, selected_oom_adj, selected_tasksize); + + lowmem_deathpending = selected; + task_free_register(&task_nb); + force_sig(SIGKILL, selected); rem -= selected_tasksize; } diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 3f06818cf9fa..31fcd3270b26 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -157,6 +157,12 @@ static int uio_pdrv_genirq_remove(struct platform_device *pdev) struct uio_pdrv_genirq_platdata *priv = platform_get_drvdata(pdev); uio_unregister_device(priv->uioinfo); + + priv->uioinfo->irq_flags = 0; + priv->uioinfo->handler = NULL; + priv->uioinfo->irqcontrol = NULL; + priv->uioinfo->priv = NULL; + kfree(priv); return 0; } diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 2bfc41ece0e1..b8134ad5f05f 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -59,6 +59,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> +#include <linux/serial.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/module.h> @@ -609,6 +610,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) acm->throttle = 0; tasklet_schedule(&acm->urb_task); + set_bit(ASYNCB_INITIALIZED, &acm->port.flags); rv = tty_port_block_til_ready(&acm->port, tty, filp); done: mutex_unlock(&acm->mutex); diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 69e5773abfce..07f503aa9078 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1754,6 +1754,9 @@ int usb_resume(struct device *dev, pm_message_t msg) udev = to_usb_device(dev); +/* At otg mode, if it is a device wakeup interrupt, the host should do nothing */ + if (udev->bus->is_b_host) + return 0; /* If udev->skip_sys_resume is set then udev was already suspended * when the system sleep started, so we don't want to resume it * during this system wakeup. @@ -1765,7 +1768,7 @@ int usb_resume(struct device *dev, pm_message_t msg) /* Avoid PM error messages for devices disconnected while suspended * as we'll display regular disconnect messages just a bit later. */ - if (status == -ENODEV) + if (status == -ENODEV || status == -ESHUTDOWN) return 0; return status; } diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 66e8a424c9f4..539a2c0dde00 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -196,7 +196,6 @@ extern void usb_host_set_wakeup(struct device *wkup_dev, bool para); static int generic_suspend(struct usb_device *udev, pm_message_t msg) { int rc; - u32 temp; /* Normal USB devices suspend through their upstream port. * Root hubs don't have upstream ports to suspend, @@ -204,25 +203,7 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) * interfaces manually by doing a bus (or "global") suspend. */ if (!udev->parent) { - struct usb_hcd *hcd = - container_of(udev->bus, struct usb_hcd, self); - struct fsl_usb2_platform_data *pdata; - pdata = hcd->self.controller->platform_data; - rc = hcd_bus_suspend(udev, msg); - - if (device_may_wakeup(hcd->self.controller)) { - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - /* enable remote wake up irq */ - usb_host_set_wakeup(hcd->self.controller, true); - - /* Put PHY into low power mode */ - temp = readl(hcd->regs + 0x184); - writel(temp | (1 << 23), (hcd->regs + 0x184)); - - if (pdata->usb_clock_for_pm) - pdata->usb_clock_for_pm(false); - } /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ } else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) @@ -236,7 +217,6 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) static int generic_resume(struct usb_device *udev, pm_message_t msg) { int rc; - u32 temp; /* Normal USB devices resume/reset through their upstream port. * Root hubs don't have upstream ports to resume or reset, @@ -244,13 +224,6 @@ static int generic_resume(struct usb_device *udev, pm_message_t msg) * interfaces manually by doing a bus (or "global") resume. */ if (!udev->parent) { - struct usb_hcd *hcd = - container_of(udev->bus, struct usb_hcd, self); - - if (device_may_wakeup(hcd->self.controller)) { - temp = readl(hcd->regs + 0x184); - writel(temp & (~(1 << 23)), (hcd->regs + 0x184)); - } rc = hcd_bus_resume(udev, msg); } else rc = usb_port_resume(udev, msg); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index d27ad104731c..2f47bdc7c93a 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1739,6 +1739,7 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) int status; int old_state = hcd->state; + printk("%s\n", __func__); dev_dbg(&rhdev->dev, "bus %s%s\n", (msg.event & PM_EVENT_AUTO ? "auto-" : ""), "suspend"); if (!hcd->driver->bus_suspend) { @@ -1876,7 +1877,6 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum); irqreturn_t usb_hcd_irq (int irq, void *__hcd) { struct usb_hcd *hcd = __hcd; - struct fsl_usb2_platform_data *pdata; unsigned long flags; irqreturn_t rc; @@ -1885,25 +1885,14 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) * assume it's never used. */ local_irq_save(flags); - - if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { - /* Need open clock for register access */ - pdata = hcd->self.controller->platform_data; - if (pdata->usb_clock_for_pm) - pdata->usb_clock_for_pm(true); - - /* if receive a remote wakeup interrrupt after suspend */ - if (usb_host_wakeup_irq(hcd->self.controller)) { - /* disable remote wake up irq */ - usb_host_set_wakeup(hcd->self.controller, false); - - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - hcd->driver->irq(hcd); - rc = IRQ_HANDLED; - } else + /* At otg mode, the host does need to handle device interrupt */ + if (hcd->self.is_b_host){ + local_irq_restore(flags); + return IRQ_NONE; + } + else if (unlikely(hcd->state == HC_STATE_HALT || + !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { rc = IRQ_NONE; - } else if (unlikely(hcd->state == HC_STATE_HALT)) { - rc = IRQ_NONE; } else if (hcd->driver->irq(hcd) == IRQ_NONE) { rc = IRQ_NONE; } else { diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index d47201c75915..cc8f911afbc4 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1177,12 +1177,6 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) "Unsupported bus topology: hub nested too deep\n"); return -E2BIG; } -#ifdef CONFIG_PM - /* Defaultly disable autosuspend for hub and reley on sys - * to enable it. - */ - hdev->autosuspend_disabled = 1; -#endif #ifdef CONFIG_USB_OTG_BLACKLIST_HUB if (hdev->parent) { @@ -2304,7 +2298,6 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_hub *hub = usb_get_intfdata (intf); struct usb_device *hdev = hub->hdev; unsigned port1; - /* fail if children aren't already suspended */ for (port1 = 1; port1 <= hdev->maxchild; port1++) { struct usb_device *udev; @@ -2328,8 +2321,15 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) static int hub_resume(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata(intf); + struct usb_hcd *hcd = bus_to_hcd(hub->hdev->bus); dev_dbg(&intf->dev, "%s\n", __func__); + /* At otg mode, if the hcd which the hub is attached to is not accessible, + * It should do nothing. + */ + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) + return 0; + hub_activate(hub, HUB_RESUME); return 0; } diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index ce44379bd172..c29ebda61b2f 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -466,7 +466,6 @@ config USB_GOKU config USB_GADGET_ARC boolean "Freescale USB Device Controller" depends on ARCH_MXC || ARCH_STMP3XXX || ARCH_MXS - depends on !USB_EHCI_ARC_OTG select USB_GADGET_DUALSPEED select USB_OTG_UTILS select USB_GADGET_DUALSPEED if USB_GADGET_FSL_1504 || USB_GADGET_FSL_UTMI @@ -792,6 +791,15 @@ config USB_G_PRINTER For more information, see Documentation/usb/gadget_printer.txt which includes sample code for accessing the device file. +config USB_ANDROID + tristate "Android Gadget" + depends on SWITCH + help + The Android gadget provides mass storage and adb transport. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_android". + config USB_CDC_COMPOSITE tristate "CDC Composite Device (Ethernet and ACM)" depends on NET diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 477114e43372..545c0e256e28 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -41,6 +41,7 @@ gadgetfs-objs := inode.o g_file_storage-objs := file_storage.o g_printer-objs := printer.o g_cdc-objs := cdc2.o +g_android-objs := android.o f_adb.o f_mass_storage.o obj-$(CONFIG_USB_ZERO) += g_zero.o obj-$(CONFIG_USB_AUDIO) += g_audio.o @@ -51,4 +52,5 @@ obj-$(CONFIG_USB_G_SERIAL) += g_serial.o obj-$(CONFIG_USB_G_PRINTER) += g_printer.o obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o +obj-$(CONFIG_USB_ANDROID) += g_android.o diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c index 1577c93c35bb..8e94549f891e 100644 --- a/drivers/usb/gadget/arcotg_udc.c +++ b/drivers/usb/gadget/arcotg_udc.c @@ -106,19 +106,6 @@ extern struct resource *otg_get_resources(void); extern void fsl_platform_set_test_mode(struct fsl_usb2_platform_data *pdata, enum usb_test_mode mode); -static inline void -dr_wake_up_enable(struct fsl_udc *udc, bool enable) -{ - struct fsl_usb2_platform_data *pdata; - pdata = udc->pdata; - - if (enable && (!device_may_wakeup(udc_controller->gadget.dev.parent))) - return; - - if (pdata->wake_up_enable) - pdata->wake_up_enable(pdata, enable); -} - #ifdef CONFIG_WORKAROUND_ARCUSB_REG_RW static void safe_writel(u32 val32, void *addr) { @@ -177,6 +164,25 @@ static inline void dump_ep_queue(struct fsl_ep *ep) } #endif +#if (defined CONFIG_ARCH_MX35 || defined CONFIG_ARCH_MX25) +/* + * The Phy at MX35 and MX25 have bugs, it must disable, and re-eable phy + * if the phy clock is disabled before + */ +static void reset_phy(void) +{ + u32 phyctrl; + phyctrl = fsl_readl(&dr_regs->phyctrl1); + phyctrl &= ~PHY_CTRL0_USBEN; + fsl_writel(phyctrl, &dr_regs->phyctrl1); + + phyctrl = fsl_readl(&dr_regs->phyctrl1); + phyctrl |= PHY_CTRL0_USBEN; + fsl_writel(phyctrl, &dr_regs->phyctrl1); +} +#else +static void reset_phy(void){; } +#endif /*----------------------------------------------------------------- * done() - retire a request; caller blocked irqs * @status : request status to be set, only works when @@ -264,9 +270,12 @@ static void done(struct fsl_ep *ep, struct fsl_req *req, int status) static void nuke(struct fsl_ep *ep, int status) { ep->stopped = 1; - - /* Flush fifo */ - fsl_ep_fifo_flush(&ep->ep); + /* + * At udc stop mode, the clock is already off + * So flush fifo, should be done at clock on mode. + */ + if (!ep->udc->stopped) + fsl_ep_fifo_flush(&ep->ep); /* Whether this eq has request linked */ while (!list_empty(&ep->queue)) { @@ -281,31 +290,85 @@ static void nuke(struct fsl_ep *ep, int status) /*------------------------------------------------------------------ Internal Hardware related function ------------------------------------------------------------------*/ +static inline void +dr_wake_up_enable(struct fsl_udc *udc, bool enable) +{ + struct fsl_usb2_platform_data *pdata; + pdata = udc->pdata; -static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable) + if (pdata && pdata->wake_up_enable) + pdata->wake_up_enable(pdata, enable); +} +static bool clk_stoped = false; +static inline void dr_clk_gate(bool on) { - u32 temp; + struct fsl_usb2_platform_data *pdata = udc_controller->pdata; - if (!device_may_wakeup(udc_controller->gadget.dev.parent)) + if (!pdata || !pdata->usb_clock_for_pm) return; + if (on && clk_stoped) { + pdata->usb_clock_for_pm(true); + clk_stoped = false; + } + if (!on && !clk_stoped) { + pdata->usb_clock_for_pm(false); + clk_stoped = true; + } + if (on) + reset_phy(); +} - if (enable) { - temp = fsl_readl(&dr_regs->portsc1); - temp |= PORTSCX_PHY_LOW_POWER_SPD; - fsl_writel(temp, &dr_regs->portsc1); +static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable) +{ + struct fsl_usb2_platform_data *pdata = udc->pdata; + u32 portsc; - if (udc_controller->pdata->usb_clock_for_pm) - udc_controller->pdata->usb_clock_for_pm(false); + if (pdata && pdata->phy_lowpower_suspend) { + pdata->phy_lowpower_suspend(enable); } else { - if (udc_controller->pdata->usb_clock_for_pm) - udc_controller->pdata->usb_clock_for_pm(true); - - temp = fsl_readl(&dr_regs->portsc1); - temp &= ~PORTSCX_PHY_LOW_POWER_SPD; - fsl_writel(temp, &dr_regs->portsc1); + if (enable){ + portsc = fsl_readl(&dr_regs->portsc1); + portsc |= PORTSCX_PHY_LOW_POWER_SPD; + fsl_writel(portsc, &dr_regs->portsc1); + } else { + portsc = fsl_readl(&dr_regs->portsc1); + portsc &= ~PORTSCX_PHY_LOW_POWER_SPD; + fsl_writel(portsc, &dr_regs->portsc1); + } } } + +/* workaroud for some boards, maybe there is a large capacitor between the ground and the Vbus + * that will cause the vbus dropping very slowly when device is detached, + * may cost 2-3 seconds to below 0.8V */ +static void udc_wait_b_session_low(void) +{ + u32 temp; + u32 wait = 5000; /* max wait time is 5000 ms */ + /* if we are in host mode, don't need to care the B session */ + if ((fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) == 0) + return; + /* if the udc is dettached , there will be a suspend irq */ + if (udc_controller->usb_state != USB_STATE_SUSPENDED) + return; + temp = fsl_readl(&dr_regs->otgsc); + temp &= ~(OTGSC_B_SESSION_VALID_IRQ_EN ); + fsl_writel(temp, &dr_regs->otgsc); + + do { + if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_B_SESSION_VALID)) + break; + mdelay(1); + wait -= 1; + } while(wait); + if (!wait) + printk("ERROR!!!!!: the vbus can not be lower then 0.8V for 5 seconds, Pls Check your HW design\n"); + temp = fsl_readl(&dr_regs->otgsc); + temp |= (OTGSC_B_SESSION_VALID_IRQ_EN ); + fsl_writel(temp, &dr_regs->otgsc); +} + static int dr_controller_setup(struct fsl_udc *udc) { unsigned int tmp = 0, portctrl = 0; @@ -427,37 +490,36 @@ static void dr_controller_run(struct fsl_udc *udc) fsl_writel(temp, &dr_regs->usbintr); - if (device_may_wakeup(udc_controller->gadget.dev.parent)) { - /* enable BSV irq */ - temp = fsl_readl(&dr_regs->otgsc); - temp |= OTGSC_B_SESSION_VALID_IRQ_EN; - fsl_writel(temp, &dr_regs->otgsc); - } + /* enable BSV irq */ + temp = fsl_readl(&dr_regs->otgsc); + temp |= OTGSC_B_SESSION_VALID_IRQ_EN; + fsl_writel(temp, &dr_regs->otgsc); /* If vbus not on and used low power mode */ - if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_B_SESSION_VALID) - && device_may_wakeup(udc_controller->gadget.dev.parent)) { - /* enable wake up */ - dr_wake_up_enable(udc, true); + if (!(temp & OTGSC_B_SESSION_VALID)) { /* Set stopped before low power mode */ udc->stopped = 1; - /* close PHY clock */ + /* enable wake up */ + dr_wake_up_enable(udc, true); + /* enter lower power mode */ dr_phy_low_power_mode(udc, true); - printk(KERN_INFO "udc enter low power mode \n"); + printk(KERN_INFO "%s: udc enter low power mode \n", __func__); } else { +#ifdef CONFIG_ARCH_MX37 /* add some delay for USB timing issue. USB may be recognize as FS device during USB gadget remote wake up function */ mdelay(100); +#endif /* Clear stopped bit */ udc->stopped = 0; - /* Set controller to Run */ + + /* The usb line has already been connected to pc */ temp = fsl_readl(&dr_regs->usbcmd); temp |= USB_CMD_RUN_STOP; fsl_writel(temp, &dr_regs->usbcmd); - printk(KERN_INFO "udc run \n"); } return; @@ -680,7 +742,7 @@ static int fsl_ep_enable(struct usb_ep *_ep, case USB_ENDPOINT_XFER_ISOC: /* Calculate transactions needed for high bandwidth iso */ mult = (unsigned char)(1 + ((max >> 11) & 0x03)); - max = max & 0x8ff; /* bit 0~10 */ + max = max & 0x7ff; /* bit 0~10 */ /* 3 transactions at most */ if (mult > 3) goto en_done; @@ -1953,15 +2015,36 @@ static void suspend_irq(struct fsl_udc *udc) udc->driver->suspend(&udc->gadget); } -/* Process Wake up interrupt */ -static void wake_up_irq(struct fsl_udc *udc) -{ - pr_debug("%s\n", __func__); - - /* disable wake up irq */ - dr_wake_up_enable(udc_controller, false); - - udc->stopped = 0; +/* Process Wake up interrupt + * Be careful that some boards will use ID pin to control the VBUS on/off + * in these case, after the device enter the lowpower mode(clk off, + * phy lowpower mode, wakeup enable), then an udisk is attaced to the otg port, + * there will be an Vbus wakeup event and then an ID change wakeup, But the Vbus + * event is not expected, so there is an workaround that will detect the ID, if ID=0 + * we just need the ID event so we can not disable the wakeup + * + * false: host wakeup event + * true: device wakeup event +*/ +static bool wake_up_irq(struct fsl_udc *udc) +{ + /* Because the IC design needs to remove the glitch on ID so the otgsc bit 8 will + * be delayed max 2 ms to show the real ID pin value + */ + mdelay(3); + + /* if the ID=0, let arc host process the wakeup */ + if (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) { + dr_wake_up_enable(udc_controller, false); + dr_phy_low_power_mode(udc, false); + printk("device wake up event\n"); + return true; + }else {/* wakeup is vbus wake event, but not for device so we need to clear b session */ + int irq_src = fsl_readl(&dr_regs->otgsc) & (~OTGSC_ID_CHANGE_IRQ_STS); + fsl_writel(irq_src, &dr_regs->otgsc); + printk("The host wakeup event, should be handled by host\n"); + return false; + } } static void bus_resume(struct fsl_udc *udc) @@ -2018,72 +2101,60 @@ static void reset_irq(struct fsl_udc *udc) /* Write 1s to the flush register */ fsl_writel(0xffffffff, &dr_regs->endptflush); - if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) { - VDBG("Bus reset"); - /* Bus is reseting */ - udc->bus_reset = 1; - /* Reset all the queues, include XD, dTD, EP queue - * head and TR Queue */ - reset_queues(udc); - udc->usb_state = USB_STATE_DEFAULT; - } else { - VDBG("Controller reset"); - /* initialize usb hw reg except for regs for EP, not - * touch usbintr reg */ - dr_controller_setup(udc); - - /* Reset all internal used Queues */ - reset_queues(udc); - - ep0_setup(udc); - - /* Enable DR IRQ reg, Set Run bit, change udc state */ - dr_controller_run(udc); - udc->usb_state = USB_STATE_ATTACHED; - } + /* Bus is reseting */ + udc->bus_reset = 1; + /* Reset all the queues, include XD, dTD, EP queue + * head and TR Queue */ + reset_queues(udc); + udc->usb_state = USB_STATE_DEFAULT; } /* if wakup udc, return true; else return false*/ bool try_wake_up_udc(struct fsl_udc *udc) { u32 irq_src; + bool b_device; /* when udc is stopped, only handle wake up irq */ if (udc->stopped) { - if (!device_may_wakeup(&(udc->pdata->pdev->dev))) - return false; - - dr_phy_low_power_mode(udc_controller, false); - /* check to see if wake up irq */ irq_src = fsl_readl(&dr_regs->usbctrl); if (irq_src & USB_CTRL_OTG_WUIR) { - wake_up_irq(udc); - } else { - dr_phy_low_power_mode(udc_controller, true); + if (wake_up_irq(udc) == false){ + return false; /* host wakeup event */ + } } } - if (!device_may_wakeup(udc_controller->gadget.dev.parent)) - return true; - /* check if Vbus change irq */ irq_src = fsl_readl(&dr_regs->otgsc); if (irq_src & OTGSC_B_SESSION_VALID_IRQ_STS) { u32 tmp; + /* Because the IC design needs to remove the glitch on ID so the otgsc bit 8 will + * be delayed max 2 ms to show the real ID pin value, as it needs to use ID to judge + * host or device + */ + mdelay(3); + b_device = (irq_src & OTGSC_STS_USB_ID)? true:false; fsl_writel(irq_src, &dr_regs->otgsc); + if (!b_device) + return false; tmp = fsl_readl(&dr_regs->usbcmd); /* check BSV bit to see if fall or rise */ if (irq_src & OTGSC_B_SESSION_VALID) { + if (udc->suspended) /*let the system pm resume the udc */ + return true; udc->stopped = 0; fsl_writel(tmp | USB_CMD_RUN_STOP, &dr_regs->usbcmd); - printk(KERN_INFO "udc out low power mode\n"); + printk(KERN_INFO "%s: udc out low power mode\n", __func__); } else { - printk(KERN_INFO "udc enter low power mode \n"); + printk(KERN_INFO "%s: udc enter low power mode \n", __func__); + if (udc->driver) + udc->driver->disconnect(&udc->gadget); fsl_writel(tmp & ~USB_CMD_RUN_STOP, &dr_regs->usbcmd); + udc->stopped = 1; /* enable wake up */ dr_wake_up_enable(udc, true); - udc->stopped = 1; /* close USB PHY clock */ dr_phy_low_power_mode(udc, true); return false; @@ -2092,7 +2163,6 @@ bool try_wake_up_udc(struct fsl_udc *udc) return true; } - /* * USB device controller interrupt handler */ @@ -2103,15 +2173,29 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) irqreturn_t status = IRQ_NONE; unsigned long flags; - if (try_wake_up_udc(udc) == false) - return IRQ_NONE; - spin_lock_irqsave(&udc->lock, flags); + if (udc->stopped) + dr_clk_gate(true); + + if (try_wake_up_udc(udc) == false) { + goto irq_end; + } +#ifdef CONFIG_USB_OTG + /* if no gadget register in this driver, we need do noting */ + if (udc->transceiver->gadget == NULL) + goto irq_end; + + /* only handle device interrupt event */ + if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) { + goto irq_end; + } +#endif + irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr); /* Clear notification bits */ fsl_writel(irq_src, &dr_regs->usbsts); - /* VDBG("irq_src [0x%8x]", irq_src); */ + VDBG("0x%x\n", irq_src); /* Need to resume? */ if (udc->usb_state == USB_STATE_SUSPENDED) @@ -2156,12 +2240,24 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) /* Sleep Enable (Suspend) */ if (irq_src & USB_STS_SUSPEND) { + VDBG("suspend int"); suspend_irq(udc); status = IRQ_HANDLED; } if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) { - VDBG("Error IRQ %x ", irq_src); + printk(KERN_ERR "Error IRQ %x ", irq_src); + if (irq_src & USB_STS_SYS_ERR) { + printk(KERN_ERR "This error can't be recoveried, \ + please reboot your board\n"); + printk(KERN_ERR "If this error happens frequently, \ + please check your dma buffer\n"); + } + } + +irq_end: + if (udc->stopped){ + dr_clk_gate(false); } spin_unlock_irqrestore(&udc->lock, flags); @@ -2176,9 +2272,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) { int retval = -ENODEV; unsigned long flags = 0; -#ifndef CONFIG_USB_OTG - u32 portsc; -#endif if (!udc_controller) return -ENODEV; @@ -2196,18 +2289,19 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) spin_lock_irqsave(&udc_controller->lock, flags); driver->driver.bus = 0; + udc_controller->pdata->port_enables = 1; /* hook up the driver */ udc_controller->driver = driver; udc_controller->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc_controller->lock, flags); -#ifndef CONFIG_USB_OTG - if (udc_controller->pdata->usb_clock_for_pm) - udc_controller->pdata->usb_clock_for_pm(true); + dr_clk_gate(true); + /* It doesn't need to switch usb from low power mode to normal mode + * at otg mode + */ + if (!udc_controller->transceiver){ + dr_phy_low_power_mode(udc_controller, false); + } - portsc = fsl_readl(&dr_regs->portsc1); - portsc &= ~PORTSCX_PHY_LOW_POWER_SPD; - fsl_writel(portsc, &dr_regs->portsc1); -#endif /* bind udc driver to gadget driver */ retval = driver->bind(&udc_controller->gadget); if (retval) { @@ -2219,30 +2313,30 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (udc_controller->transceiver) { /* Suspend the controller until OTG enable it */ - udc_controller->stopped = 1; + udc_controller->suspended = 1;/* let the otg resume it */ printk(KERN_INFO "Suspend udc for OTG auto detect\n"); dr_wake_up_enable(udc_controller, true); - dr_phy_low_power_mode(udc_controller, true); /* export udc suspend/resume call to OTG */ udc_controller->gadget.dev.driver->suspend = (dev_sus)fsl_udc_suspend; udc_controller->gadget.dev.driver->resume = (dev_res)fsl_udc_resume; /* connect to bus through transceiver */ - if (udc_controller->transceiver) { - retval = otg_set_peripheral(udc_controller->transceiver, - &udc_controller->gadget); - if (retval < 0) { - ERR("can't bind to transceiver\n"); - driver->unbind(&udc_controller->gadget); - udc_controller->gadget.dev.driver = 0; - udc_controller->driver = 0; - return retval; - } + retval = otg_set_peripheral(udc_controller->transceiver, + &udc_controller->gadget); + if (retval < 0) { + ERR("can't bind to transceiver\n"); + driver->unbind(&udc_controller->gadget); + udc_controller->gadget.dev.driver = 0; + udc_controller->driver = 0; + return retval; } + //dr_clk_gate(false); } else { /* Enable DR IRQ reg and Set usbcmd reg Run bit */ dr_controller_run(udc_controller); + if (udc_controller->stopped) + dr_clk_gate(false); udc_controller->usb_state = USB_STATE_ATTACHED; udc_controller->ep0_dir = 0; } @@ -2250,8 +2344,10 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) udc_controller->gadget.name, driver->driver.name); out: - if (retval) + if (retval){ printk(KERN_DEBUG "retval %d \n", retval); + udc_controller->pdata->port_enables = 0; + } return retval; } EXPORT_SYMBOL(usb_gadget_register_driver); @@ -2261,7 +2357,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { struct fsl_ep *loop_ep; unsigned long flags; - u32 portsc; if (!udc_controller) return -ENODEV; @@ -2269,15 +2364,16 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!driver || driver != udc_controller->driver || !driver->unbind) return -EINVAL; + if(udc_controller->stopped) + dr_clk_gate(true); + if (udc_controller->transceiver) (void)otg_set_peripheral(udc_controller->transceiver, 0); - /* open phy clock for following operation */ - dr_phy_low_power_mode(udc_controller, false); - /* stop DR, disable intr */ dr_controller_stop(udc_controller); + udc_controller->pdata->port_enables = 0; /* in fact, no needed */ udc_controller->usb_state = USB_STATE_ATTACHED; udc_controller->ep0_dir = 0; @@ -2299,14 +2395,11 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) udc_controller->gadget.dev.driver = 0; udc_controller->driver = 0; - dr_wake_up_enable(udc_controller, false); - - portsc = fsl_readl(&dr_regs->portsc1); - portsc |= PORTSCX_PHY_LOW_POWER_SPD; - fsl_writel(portsc, &dr_regs->portsc1); + if (udc_controller->gadget.is_otg) { + dr_wake_up_enable(udc_controller, true); + } - if (udc_controller->pdata->usb_clock_for_pm) - udc_controller->pdata->usb_clock_for_pm(false); + dr_phy_low_power_mode(udc_controller, true); printk(KERN_INFO "unregistered gadget driver '%s'\r\n", driver->driver.name); @@ -2705,14 +2798,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev) int ret = -ENODEV; unsigned int i; u32 dccparams; -#ifndef CONFIG_USB_OTG - u32 portsc; -#endif - - if (strcmp(pdev->name, driver_name)) { - VDBG("Wrong device\n"); - return -ENODEV; - } udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); if (udc_controller == NULL) { @@ -2729,6 +2814,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) ret = -ENODEV; goto err1a; } + udc_controller->gadget.is_otg = 1; #endif if ((pdev->dev.parent) && @@ -2768,6 +2854,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev) goto err2a; } + /* Due to mx35/mx25's phy's bug */ + reset_phy(); + if (pdata->have_sysif_regs) usb_sys_regs = (struct usb_sys_interface *) ((u32)dr_regs + USB_DR_SYS_OFFSET); @@ -2826,12 +2915,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev) if (ret < 0) goto err3; - if (udc_controller->transceiver) { - udc_controller->gadget.is_otg = 1; - /* now didn't support lpm in OTG mode*/ - device_set_wakeup_capable(&pdev->dev, 0); - } - /* setup QH and epctrl for ep0 */ ep0_setup(udc_controller); @@ -2874,20 +2957,29 @@ static int __init fsl_udc_probe(struct platform_device *pdev) #ifdef POSTPONE_FREE_LAST_DTD last_free_td = NULL; #endif + #ifndef CONFIG_USB_OTG /* disable all INTR */ fsl_writel(0, &dr_regs->usbintr); - dr_wake_up_enable(udc_controller, false); +#else + dr_wake_up_enable(udc_controller, true); +#endif + +/* + * As mx25/mx35 does not implement clk_gate, should not let phy to low + * power mode due to IC bug + */ +#if !(defined CONFIG_ARCH_MX35 || defined CONFIG_ARCH_MX25) +{ + dr_phy_low_power_mode(udc_controller, true); +} +#endif udc_controller->stopped = 1; - portsc = fsl_readl(&dr_regs->portsc1); - portsc |= PORTSCX_PHY_LOW_POWER_SPD; - fsl_writel(portsc, &dr_regs->portsc1); + /* let the gadget register function open the clk */ + dr_clk_gate(false); - if (udc_controller->pdata->usb_clock_for_pm) - udc_controller->pdata->usb_clock_for_pm(false); -#endif create_proc_file(); return 0; @@ -2914,9 +3006,6 @@ err1a: */ static int __exit fsl_udc_remove(struct platform_device *pdev) { -#ifndef CONFIG_USB_OTG - struct resource *res; -#endif struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; DECLARE_COMPLETION(done); @@ -2925,7 +3014,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) return -ENODEV; udc_controller->done = &done; /* open USB PHY clock */ - dr_phy_low_power_mode(udc_controller, false); + if (udc_controller->stopped) + dr_clk_gate(true); /* DR has been stopped in usb_gadget_unregister_driver() */ remove_proc_file(); @@ -2948,8 +3038,11 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) iounmap((u8 __iomem *)dr_regs); #ifndef CONFIG_USB_OTG +{ + struct resource *res; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); +} #endif device_unregister(&udc_controller->gadget.dev); @@ -2963,6 +3056,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) if (pdata->platform_uninit) pdata->platform_uninit(pdata); + if (udc_controller->stopped) + dr_clk_gate(false); return 0; } @@ -2970,10 +3065,19 @@ static int udc_suspend(struct fsl_udc *udc) { u32 mode, usbcmd; - /* open clock for register access */ - if (udc_controller->pdata->usb_clock_for_pm) - udc_controller->pdata->usb_clock_for_pm(true); - + /* + * When it is the PM suspend routine and the device has no + * abilities to wakeup system, it should not set wakeup enable. + * Otherwise, the system will wakeup even the user only wants to + * charge using usb + */ + if (udc_controller->gadget.dev.parent->power.status + == DPM_SUSPENDING) { + if (!device_may_wakeup(udc_controller->gadget.dev.parent)) + dr_wake_up_enable(udc, false); + else + dr_wake_up_enable(udc, true); + } mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK; usbcmd = fsl_readl(&dr_regs->usbcmd); @@ -2984,9 +3088,8 @@ static int udc_suspend(struct fsl_udc *udc) * PM suspend. Remember this fact, so that we will leave the * controller stopped at PM resume time. */ - if (udc->stopped) { + if (udc->suspended) { pr_debug("gadget already stopped, leaving early\n"); - udc->already_stopped = 1; goto out; } @@ -2995,22 +3098,30 @@ static int udc_suspend(struct fsl_udc *udc) goto out; } + /* For some buggy hardware designs, see comment of this function for detail */ + udc_wait_b_session_low(); + udc->stopped = 1; - /* if the suspend is not for switch to host in otg mode */ - if ((!(udc->gadget.is_otg)) || - (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) { - dr_wake_up_enable(udc, true); - dr_phy_low_power_mode(udc, true); - } /* stop the controller */ usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP; fsl_writel(usbcmd, &dr_regs->usbcmd); + /* if the suspend is not for switch to host in otg mode */ + if ((!(udc->gadget.is_otg)) || + (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) { + if (device_may_wakeup(udc_controller->gadget.dev.parent)) { + dr_wake_up_enable(udc, true); + } + } + + dr_phy_low_power_mode(udc, true); printk(KERN_INFO "USB Gadget suspended\n"); out: - if (udc_controller->pdata->usb_clock_for_pm) - udc_controller->pdata->usb_clock_for_pm(false); + udc->suspended++; + if (udc->suspended > 2) + printk("ERROR: suspended times > 2\n"); + return 0; } @@ -3020,13 +3131,24 @@ out: -----------------------------------------------------------------*/ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) { + int ret; +#ifdef CONFIG_USB_OTG + if (udc_controller->transceiver->gadget == NULL) + return 0; +#endif + if (udc_controller->stopped) + dr_clk_gate(true); if (((!(udc_controller->gadget.is_otg)) || (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) && (udc_controller->usb_state > USB_STATE_POWERED) && - (udc_controller->usb_state < USB_STATE_SUSPENDED)) - return -EBUSY; + (udc_controller->usb_state < USB_STATE_SUSPENDED)) { + return -EBUSY;/* keep the clk on */ + } + else + ret = udc_suspend(udc_controller); + dr_clk_gate(false); - return udc_suspend(udc_controller); + return ret; } /*----------------------------------------------------------------- @@ -3035,30 +3157,54 @@ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) *-----------------------------------------------------------------*/ static int fsl_udc_resume(struct platform_device *pdev) { - pr_debug("%s(): stopped %d already_stopped %d\n", __func__, - udc_controller->stopped, udc_controller->already_stopped); - + pr_debug("%s(): stopped %d suspended %d\n", __func__, + udc_controller->stopped, udc_controller->suspended); + printk("udc resume\n"); +#ifdef CONFIG_USB_OTG + if (udc_controller->transceiver->gadget == NULL) + return 0; +#endif + if (udc_controller->stopped) + dr_clk_gate(true); /* * If the controller was stopped at suspend time, then * don't resume it now. */ - if (udc_controller->already_stopped) { - udc_controller->already_stopped = 0; - pr_debug("gadget was already stopped, leaving early\n"); - return 0; - } + /* + * If it is PM resume routine, the udc is at low power mode, + * and the udc has no abilities to wakeup system, it should + * set the abilities to wakeup itself. Otherwise, the usb + * subsystem will not leave from low power mode. + */ + if (!device_may_wakeup(udc_controller->gadget.dev.parent) && + udc_controller->gadget.dev.parent->power.status + == DPM_RESUMING){ + dr_wake_up_enable(udc_controller, true); + } + if (--udc_controller->suspended) { + printk("gadget was already stopped, leaving early\n"); + goto out; + } /* Enable DR irq reg and set controller Run */ if (udc_controller->stopped) { + /* if in host mode, we need to do nothing */ + if ((fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) == 0) { + goto out; + } dr_wake_up_enable(udc_controller, false); dr_phy_low_power_mode(udc_controller, false); - mdelay(1); - + mdelay(10); dr_controller_setup(udc_controller); dr_controller_run(udc_controller); } udc_controller->usb_state = USB_STATE_ATTACHED; udc_controller->ep0_dir = 0; +out: + /* if udc is resume by otg id change and no device + * connecting to the otg, otg will enter low power mode*/ + if (udc_controller->stopped) + dr_clk_gate(false); printk(KERN_INFO "USB Gadget resumed\n"); return 0; diff --git a/drivers/usb/gadget/arcotg_udc.h b/drivers/usb/gadget/arcotg_udc.h index 480d953dcf58..8d344acb8fef 100644 --- a/drivers/usb/gadget/arcotg_udc.h +++ b/drivers/usb/gadget/arcotg_udc.h @@ -266,6 +266,7 @@ struct usb_sys_interface { #define PORTSCX_SPEED_BIT_POS (26) /* OTGSC Register Bit Masks */ +#define OTGSC_ID_CHANGE_IRQ_STS (1 << 16) #define OTGSC_B_SESSION_VALID_IRQ_EN (1 << 27) #define OTGSC_B_SESSION_VALID_IRQ_STS (1 << 19) #define OTGSC_B_SESSION_VALID (1 << 11) @@ -365,6 +366,7 @@ struct usb_sys_interface { /* PHY control0 Register Bit Masks */ #define PHY_CTRL0_CONF2 (1 << 26) +#define PHY_CTRL0_USBEN (1 << 24) /* USB UTMI PHY Enable */ /* USB UH2 CTRL Register Bits */ #define USB_UH2_OVBWK_EN (1 << 6) /* OTG VBUS Wakeup Enable */ @@ -592,9 +594,15 @@ struct fsl_udc { struct otg_transceiver *transceiver; unsigned softconnect:1; unsigned vbus_active:1; - unsigned stopped:1; unsigned remote_wakeup:1; - unsigned already_stopped:1; + /* we must distinguish the stopped and suspended state, + * stopped means the udc enter lowpower mode, suspended + * means the udc is suspended by system pm or by otg + * switching to host mode.if the udc in suspended state + * it also in the stopped state, while if the udc in + * stopped state,it may not be in the suspended state*/ + unsigned stopped:1; + int suspended; struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */ struct fsl_req *status_req; /* ep0 status request */ diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 59e85234fa0a..2e79b8c389a4 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -236,6 +236,7 @@ static int config_buf(struct usb_configuration *config, int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE; struct usb_function *f; int status; + int interfaceCount = 0; /* write the config descriptor */ c = buf; @@ -266,8 +267,16 @@ static int config_buf(struct usb_configuration *config, descriptors = f->hs_descriptors; else descriptors = f->descriptors; - if (!descriptors) + if (f->hidden || !descriptors || descriptors[0] == NULL) { + for (; f != config->interface[interfaceCount];) { + interfaceCount++; + c->bNumInterfaces--; + } continue; + } + for (; f != config->interface[interfaceCount];) + interfaceCount++; + status = usb_descriptor_fillbuf(next, len, (const struct usb_descriptor_header **) descriptors); if (status < 0) @@ -756,11 +765,11 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) goto unknown; - if (cdev->config) + if (cdev->config) { *(u8 *)req->buf = cdev->config->bConfigurationValue; - else + value = min(w_length, (u16) 1); + } else *(u8 *)req->buf = 0; - value = min(w_length, (u16) 1); break; /* function drivers must handle get/set altsetting; if there's @@ -810,6 +819,9 @@ unknown: */ if ((ctrl->bRequestType & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { + if (cdev->config == NULL) + return value; + f = cdev->config->interface[intf]; if (f && f->setup) value = f->setup(f, ctrl); @@ -824,6 +836,25 @@ unknown: value = c->setup(c, ctrl); } + /* If the vendor request is not processed (value < 0), + * call all device registered configure setup callbacks + * to process it. + * This is used to handle the following cases: + * - vendor request is for the device and arrives before + * setconfiguration. + * - Some devices are required to handle vendor request before + * setconfiguration such as MTP, USBNET. + */ + + if (value < 0) { + struct usb_configuration *cfg; + + list_for_each_entry(cfg, &cdev->configs, list) { + if (cfg && cfg->setup) + value = cfg->setup(cfg, ctrl); + } + } + goto done; } diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index 7953948bfe4a..7dd1a8bbe382 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -761,3 +761,12 @@ int __init acm_bind_config(struct usb_configuration *c, u8 port_num) kfree(acm); return status; } + +int __init acm_function_add(struct usb_composite_dev *cdev, + struct usb_configuration *c) +{ + int ret = acm_bind_config(c, 0); + if (ret == 0) + gserial_setup(c->cdev->gadget, 1); + return ret; +} diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 66105ce49672..8b0a13202573 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -728,6 +728,7 @@ struct fsg_dev { #include "fsl_updater.h" #endif +static int do_set_interface(struct fsg_dev *fsg, int altsetting); typedef void (*fsg_routine_t)(struct fsg_dev *); static int exception_in_progress(struct fsg_dev *fsg) @@ -1108,6 +1109,14 @@ static void fsg_disconnect(struct usb_gadget *gadget) struct fsg_dev *fsg = get_gadget_data(gadget); DBG(fsg, "disconnect or port reset\n"); + /* + * The disconnect exception will call do_set_config, and therefore will + * visit controller registers. However it is a delayed event, and will be + * handled at another process, so the controller maybe have already close the + * usb clock.*/ + if (fsg->new_config) + do_set_interface(fsg, -1);/* disable the interface */ + raise_exception(fsg, FSG_STATE_DISCONNECT); } diff --git a/drivers/usb/gadget/fsl_updater.c b/drivers/usb/gadget/fsl_updater.c index 8b4b54f8cca7..50acce441a90 100644 --- a/drivers/usb/gadget/fsl_updater.c +++ b/drivers/usb/gadget/fsl_updater.c @@ -29,6 +29,7 @@ static int utp_init(struct fsg_dev *fsg) INIT_LIST_HEAD(&utp_context.write); mutex_init(&utp_context.lock); + /* the max message is 64KB */ utp_context.buffer = vmalloc(0x10000); if (!utp_context.buffer) return -EIO; @@ -63,6 +64,7 @@ static void utp_user_data_free(struct utp_user_data *uud) kfree(uud); } +/* Get the number of element for list */ static u32 count_list(struct list_head *l) { u32 count = 0; @@ -74,10 +76,11 @@ static u32 count_list(struct list_head *l) return count; } - +/* The routine will not go on if utp_context.queue is empty */ #define WAIT_ACTIVITY(queue) \ wait_event_interruptible(utp_context.wq, !list_empty(&utp_context.queue)) +/* Called by userspace program (uuc) */ static ssize_t utp_file_read(struct file *file, char __user *buf, size_t size, @@ -109,12 +112,15 @@ static ssize_t utp_file_read(struct file *file, "need to put %d\n", size, size_to_put); } + /* + * The user program has already finished data process, + * go on getting data from the host + */ wake_up(&utp_context.list_full_wq); return size_to_put; } - static ssize_t utp_file_write(struct file *file, const char __user *buf, size_t size, loff_t *off) { @@ -127,11 +133,13 @@ static ssize_t utp_file_write(struct file *file, const char __user *buf, return -EACCES; mutex_lock(&utp_context.lock); list_add_tail(&uud->link, &utp_context.write); + /* Go on EXEC routine process */ wake_up(&utp_context.wq); mutex_unlock(&utp_context.lock); return size; } +/* Will be called when the host wants to get the sense data */ static int utp_get_sense(struct fsg_dev *fsg) { if (UTP_CTX(fsg)->processed == 0) @@ -186,6 +194,7 @@ static int utp_do_read(struct fsg_dev *fsg, void *data, size_t size) /* Perform the read */ pr_info("Copied to %p, %d bytes started from %d\n", bh->buf, amount, size - amount_left); + /* from upt buffer to file_storeage buffer */ memcpy(bh->buf, data + size - amount_left, amount); amount_left -= amount; fsg->residue -= amount; @@ -196,6 +205,7 @@ static int utp_do_read(struct fsg_dev *fsg, void *data, size_t size) /* Send this buffer and go read some more */ bh->inreq->zero = 0; + /* USB Physical transfer: Data from device to host */ start_transfer(fsg, fsg->bulk_in, bh->inreq, &bh->inreq_busy, &bh->state); @@ -326,8 +336,8 @@ static void utp_poll(struct fsg_dev *fsg) if (uud) { if (uud->data.flags & UTP_FLAG_STATUS) { - pr_debug("%s: exit with status %d\n", __func__, - uud->data.status); + printk(KERN_WARNING "%s: exit with status %d\n", + __func__, uud->data.status); UTP_SS_EXIT(fsg, uud->data.status); } else { pr_debug("%s: pass\n", __func__); @@ -356,11 +366,16 @@ static int utp_exec(struct fsg_dev *fsg, mutex_lock(&ctx->lock); list_add_tail(&uud2r->link, &ctx->read); mutex_unlock(&ctx->lock); + /* wake up the read routine */ wake_up(&ctx->wq); if (command[0] == '!') /* there will be no response */ return 0; + /* + * the user program (uuc) will return utp_message + * and add list to write list + */ WAIT_ACTIVITY(write); mutex_lock(&ctx->lock); @@ -382,21 +397,19 @@ static int utp_exec(struct fsg_dev *fsg, if (uud->data.flags & UTP_FLAG_DATA) { memcpy(ctx->buffer, uud->data.data, uud->data.bufsize); UTP_SS_SIZE(fsg, uud->data.bufsize); - utp_user_data_free(uud); - return 0; - } - - if (uud->data.flags & UTP_FLAG_REPORT_BUSY) { - utp_user_data_free(uud); + } else if (uud->data.flags & UTP_FLAG_REPORT_BUSY) { ctx->counter = 0xFFFF; UTP_SS_BUSY(fsg, ctx->counter); - return 0; + } else if (uud->data.flags & UTP_FLAG_STATUS) { + printk(KERN_WARNING "%s: exit with status %d\n", __func__, + uud->data.status); + UTP_SS_EXIT(fsg, uud->data.status); + } else { + pr_debug("%s: pass\n", __func__); + UTP_SS_PASS(fsg); } - utp_user_data_free(uud); - UTP_SS_PASS(fsg); - - return -1; + return 0; } static int utp_send_status(struct fsg_dev *fsg) @@ -470,16 +483,17 @@ static int utp_handle_message(struct fsg_dev *fsg, case UTP_EXEC: pr_debug("%s: EXEC\n", __func__); data = kzalloc(fsg->data_size, GFP_KERNEL); + /* copy data from usb buffer to utp buffer */ utp_do_write(fsg, data, fsg->data_size); utp_exec(fsg, data, fsg->data_size, param); kfree(data); break; - case UTP_GET: + case UTP_GET: /* data from device to host */ pr_debug("%s: GET, %d bytes\n", __func__, fsg->data_size); r = utp_do_read(fsg, UTP_CTX(fsg)->buffer, fsg->data_size); UTP_SS_PASS(fsg); break; - case UTP_PUT: + case UTP_PUT: /* data from host to device */ pr_debug("%s: PUT, %d bytes\n", __func__, fsg->data_size); uud2r = utp_user_data_alloc(fsg->data_size); uud2r->data.bufsize = fsg->data_size; @@ -490,6 +504,37 @@ static int utp_handle_message(struct fsg_dev *fsg, list_add_tail(&uud2r->link, &UTP_CTX(fsg)->read); mutex_unlock(&UTP_CTX(fsg)->lock); wake_up(&UTP_CTX(fsg)->wq); + /* + * Return PASS or FAIL according to uuc's status + * Please open it if need to check uuc's status + * and use another version uuc + */ +#if 0 + struct utp_user_data *uud = NULL; + struct utp_context *ctx; + WAIT_ACTIVITY(write); + ctx = UTP_CTX(fsg); + mutex_lock(&ctx->lock); + + if (!list_empty(&ctx->write)) + uud = list_first_entry(&ctx->write, + struct utp_user_data, link); + + mutex_unlock(&ctx->lock); + if (uud) { + if (uud->data.flags & UTP_FLAG_STATUS) { + printk(KERN_WARNING "%s: exit with status %d\n", + __func__, uud->data.status); + UTP_SS_EXIT(fsg, uud->data.status); + } else { + pr_debug("%s: pass\n", __func__); + UTP_SS_PASS(fsg); + } + utp_user_data_free(uud); + } else{ + UTP_SS_PASS(fsg); + } +#endif UTP_SS_PASS(fsg); wait_event_interruptible(UTP_CTX(fsg)->list_full_wq, diff --git a/drivers/usb/gadget/fsl_updater.h b/drivers/usb/gadget/fsl_updater.h index 44329a9af58a..70e4defa1a9c 100644 --- a/drivers/usb/gadget/fsl_updater.h +++ b/drivers/usb/gadget/fsl_updater.h @@ -59,6 +59,7 @@ static int utp_handle_message(struct fsg_dev *fsg, #define UTP_SS_BUSY(fsg, r) utp_set_sense(fsg, UTP_REPLY_BUSY, (u64)r) #define UTP_SS_SIZE(fsg, r) utp_set_sense(fsg, UTP_REPLY_SIZE, (u64)r) +/* the structure of utp message which is mapped to 16-byte SCSI CBW's CDB */ #pragma pack(1) struct utp_msg { u8 f0; diff --git a/drivers/usb/host/ehci-arc.c b/drivers/usb/host/ehci-arc.c index 21133fb8e47a..5cfcf169e7c7 100644 --- a/drivers/usb/host/ehci-arc.c +++ b/drivers/usb/host/ehci-arc.c @@ -23,9 +23,28 @@ #include <linux/fsl_devices.h> #include <linux/usb/otg.h> +#include "../core/usb.h" #include "ehci-fsl.h" #include <mach/fsl_usb.h> +extern int usb_host_wakeup_irq(struct device *wkup_dev); +extern void usb_host_set_wakeup(struct device *wkup_dev, bool para); +static void fsl_usb_lowpower_mode(struct fsl_usb2_platform_data *pdata, bool enable) +{ + if (enable){ + if (pdata->phy_lowpower_suspend) + pdata->phy_lowpower_suspend(true); + } else { + if (pdata->phy_lowpower_suspend) + pdata->phy_lowpower_suspend(false); + } +} + +static void fsl_usb_clk_gate(struct fsl_usb2_platform_data *pdata, bool enable) +{ + if (pdata->usb_clock_for_pm) + pdata->usb_clock_for_pm(enable); +} #undef EHCI_PROC_PTC #ifdef EHCI_PROC_PTC /* /proc PORTSC:PTC support */ /* @@ -90,8 +109,39 @@ static int ehci_testmode_init(struct ehci_hcd *ehci) #endif /* /proc PORTSC:PTC support */ -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ +/* + * This irq is used to open the hw access and let usb_hcd_irq process the usb event + * ehci_fsl_pre_irq will be called before usb_hcd_irq + */ +static irqreturn_t ehci_fsl_pre_irq(int irq, void *dev) +{ + struct platform_device *pdev = (struct platform_device *)dev; + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct fsl_usb2_platform_data *pdata; + + pdata = hcd->self.controller->platform_data; + + /* if it is an otg module and in b device mode, we need to do noting here */ + if (ehci->transceiver && !ehci->transceiver->default_a) + return IRQ_NONE; + + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + /* Need to open clk for accessing the register */ + fsl_usb_clk_gate(hcd->self.controller->platform_data, true); + /* if receive a remote wakeup interrrupt after suspend */ + if (usb_host_wakeup_irq(hcd->self.controller)) { + printk("host wakeup event happens\n"); + /* disable remote wake up irq */ + usb_host_set_wakeup(hcd->self.controller, false); + fsl_usb_lowpower_mode(pdata, false); + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + }else { + fsl_usb_clk_gate(hcd->self.controller->platform_data, false); + } + } + return IRQ_NONE; +} /** * usb_hcd_fsl_probe - initialize FSL-based HCDs @@ -182,10 +232,19 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver, fsl_platform_set_host_mode(hcd); hcd->power_budget = pdata->power_budget; - retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); + /* + * The ehci_fsl_pre_irq must be registered before usb_hcd_irq, in that case + * it can be called before usb_hcd_irq when irq occurs + */ + retval = request_irq(irq, ehci_fsl_pre_irq, IRQF_SHARED, + "fsl ehci pre interrupt", (void *)pdev); if (retval != 0) goto err4; + retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); + if (retval != 0) + goto err5; + fsl_platform_set_vbus_power(pdata, 1); if (pdata->operating_mode == FSL_USB2_DR_OTG) { @@ -199,7 +258,7 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver, if (!ehci->transceiver) { printk(KERN_ERR "can't find transceiver\n"); retval = -ENODEV; - goto err4; + goto err5; } retval = otg_set_host(ehci->transceiver, &ehci_to_hcd(ehci)->self); @@ -216,7 +275,8 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver, fsl_platform_set_ahb_burst(hcd); ehci_testmode_init(hcd_to_ehci(hcd)); return retval; - +err5: + free_irq(irq, (void *)pdev); err4: iounmap(hcd->regs); err3: @@ -231,9 +291,6 @@ err1: return retval; } -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - /** * usb_hcd_fsl_remove - shutdown processing for FSL-based HCDs * @dev: USB Host Controller being removed @@ -324,6 +381,59 @@ static int ehci_fsl_reinit(struct ehci_hcd *ehci) return 0; } +static int ehci_fsl_bus_suspend(struct usb_hcd *hcd) +{ + int ret = 0; + struct fsl_usb2_platform_data *pdata; + pdata = hcd->self.controller->platform_data; + pr_debug("%s, %s\n", __func__, pdata->name); + + /* the host is already at low power mode */ + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + return 0; + } + + pr_debug("%s, it is the host mode, %s\n", __func__, pdata->name); + + ehci_bus_suspend(hcd); + + if (pdata->platform_suspend) + pdata->platform_suspend(pdata); + + usb_host_set_wakeup(hcd->self.controller, true); + fsl_usb_lowpower_mode(pdata, true); + fsl_usb_clk_gate(hcd->self.controller->platform_data, false); + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + return ret; +} + +static int ehci_fsl_bus_resume(struct usb_hcd *hcd) +{ + int ret = 0; + struct fsl_usb2_platform_data *pdata; + + pdata = hcd->self.controller->platform_data; + pr_debug("%s, %s\n", __func__, pdata->name); + + /* if it is a remote wakeup, it will open clock and clear PHCD automatically */ + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + fsl_usb_clk_gate(hcd->self.controller->platform_data, true); + usb_host_set_wakeup(hcd->self.controller, false); + fsl_usb_lowpower_mode(pdata, false); + } + + if (pdata->platform_resume) + pdata->platform_resume(pdata); + ret = ehci_bus_resume(hcd); + if (ret) + return ret; + + return ret; +} + + /* called during probe() after chip reset completes */ static int ehci_fsl_setup(struct usb_hcd *hcd) { @@ -396,8 +506,8 @@ static const struct hc_driver ehci_fsl_hc_driver = { */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, + .bus_suspend = ehci_fsl_bus_suspend, + .bus_resume = ehci_fsl_bus_resume, .start_port_reset = ehci_start_port_reset, .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, @@ -438,13 +548,36 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, { struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); - u32 tmp, port_status; + struct usb_device *roothub = hcd->self.root_hub; + u32 port_status; struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; - if (device_may_wakeup(&(pdev->dev))) { - /* Need open clock for register access */ - if (pdata->usb_clock_for_pm) - pdata->usb_clock_for_pm(true); + /* Only handles OTG mode switch event, system suspend event will be done in bus suspend */ + if (pdev->dev.power.status == DPM_SUSPENDING){ + pr_debug("%s, system pm event \n", __func__); + if (!device_may_wakeup(&(pdev->dev))){ + /* Need open clock for register access */ + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) + fsl_usb_clk_gate(hcd->self.controller->platform_data, true); + usb_host_set_wakeup(hcd->self.controller, false); + fsl_usb_clk_gate(hcd->self.controller->platform_data, false); + } + return 0; + } + /* only the otg host can go here */ + /* wait for all usb device on the hcd dettached */ + while(roothub->children[0] != NULL) + msleep(1); + if ((pdata->operating_mode != FSL_USB2_MPH_HOST) && (!(hcd->state & HC_STATE_SUSPENDED))) + { + usb_lock_device(roothub); + usb_external_suspend_device(roothub, PMSG_USER_SUSPEND); + usb_unlock_device(roothub); + } + + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + fsl_usb_clk_gate(hcd->self.controller->platform_data, true); + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); } #ifdef DEBUG @@ -457,27 +590,9 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, pdata->suspended, pdata->already_suspended, mode, tmp); #endif - /* - * If the controller is already suspended, then this must be a - * PM suspend. Remember this fact, so that we will leave the - * controller suspended at PM resume time. - */ - if (pdata->suspended) { - pr_debug("%s: already suspended, leaving early\n", __func__); - pdata->already_suspended = 1; - goto err1; - } - - pr_debug("%s: suspending...\n", __func__); - printk(KERN_INFO "USB Host suspended\n"); port_status = ehci_readl(ehci, &ehci->regs->port_status[0]); - pdev->dev.power.power_state = PMSG_SUSPEND; - - /* ignore non-host interrupts */ - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - /* save EHCI registers */ pdata->pm_command = ehci_readl(ehci, &ehci->regs->command); pdata->pm_command &= ~CMD_RUN; @@ -496,25 +611,11 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, /* clear PHCD bit */ pdata->pm_portsc &= ~PORT_PHCD; - - pdata->suspended = 1; - - if (!device_may_wakeup(&(pdev->dev))) { - /* clear PP to cut power to the port */ - tmp = ehci_readl(ehci, &ehci->regs->port_status[0]); - tmp &= ~PORT_POWER; - ehci_writel(ehci, tmp, &ehci->regs->port_status[0]); - goto err1; - } - - tmp = ehci_readl(ehci, &ehci->regs->port_status[0]); - - if (pdata->platform_suspend) - pdata->platform_suspend(pdata); -err1: - if (device_may_wakeup(&(pdev->dev))) { - if (pdata->usb_clock_for_pm) - pdata->usb_clock_for_pm(false); + if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + //fsl_usb_lowpower_mode(pdata ,true); + //usb_host_set_wakeup(hcd->self.controller, true); + fsl_usb_clk_gate(hcd->self.controller->platform_data, false); + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); } return 0; } @@ -523,47 +624,35 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct usb_device *roothub = hcd->self.root_hub; u32 tmp; struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; - - pr_debug("%s('%s'): suspend=%d already_suspended=%d\n", __func__, - pdata->name, pdata->suspended, pdata->already_suspended); - - /* - * If the controller was already suspended at suspend time, - * then don't resume it now. - */ - if (pdata->already_suspended) { - pr_debug("already suspended, leaving early\n"); - pdata->already_suspended = 0; - return 0; - } - - if (!pdata->suspended) { - pr_debug("not suspended, leaving early\n"); + /* Only handles OTG mode switch event */ + if (pdev->dev.power.status == DPM_RESUMING){ + pr_debug("%s, system pm event \n", __func__); + if (hcd->self.is_b_host) { + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + fsl_usb_clk_gate(hcd->self.controller->platform_data, true); + } + usb_host_set_wakeup(hcd->self.controller, true); + + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + fsl_usb_clk_gate(hcd->self.controller->platform_data, false); + } + } return 0; } - - /* If hcd is resumed by non-usb wakeup events, - * then usb clocks are still not open when come here */ - if (device_may_wakeup(&(pdev->dev))) { - /* Need open clock for register access */ - if (pdata->usb_clock_for_pm) - pdata->usb_clock_for_pm(true); + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + fsl_usb_clk_gate(hcd->self.controller->platform_data, true); + //usb_host_set_wakeup(hcd->self.controller, false); + //fsl_usb_lowpower_mode(pdata, false); } - tmp = ehci_readl(ehci, &ehci->regs->port_status[0]); - - pdata->suspended = 0; - - pr_debug("%s resuming...\n", __func__); - + printk("USB Host resume ... %s\n", pdata->name); /* set host mode */ fsl_platform_set_host_mode(hcd); - if (pdata->platform_resume) - pdata->platform_resume(pdata); - /* restore EHCI registers */ ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]); ehci_writel(ehci, pdata->pm_command, &ehci->regs->command); @@ -575,32 +664,21 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev) ehci_writel(ehci, pdata->pm_configured_flag, &ehci->regs->configured_flag); - /* set bit should be done by wakeup irq routine if may wakeup */ - if (!device_may_wakeup(&(pdev->dev))) - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - else - while (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) - msleep(1); - - pdev->dev.power.power_state = PMSG_ON; tmp = ehci_readl(ehci, &ehci->regs->command); tmp |= CMD_RUN; ehci_writel(ehci, tmp, &ehci->regs->command); - usb_hcd_resume_root_hub(hcd); - - printk(KERN_INFO "USB Host resumed\n"); - - if (device_may_wakeup(&(pdev->dev))) { - if (pdata->usb_clock_for_pm) - pdata->usb_clock_for_pm(false); + if ((hcd->state & HC_STATE_SUSPENDED)){ + usb_lock_device(roothub); + usb_external_resume_device(roothub, PMSG_USER_RESUME); + usb_unlock_device(roothub); } + printk(KERN_INFO "USB Host resume ok\n"); return 0; } -#endif /* CONFIG_USB_OTG */ - +#endif MODULE_ALIAS("platform:fsl-ehci"); static struct platform_driver ehci_fsl_driver = { diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index de459bbd1eb1..44ff32306362 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -112,6 +112,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) int port; int mask; + printk("%s\n", __func__); ehci_dbg(ehci, "suspend root hub\n"); if (time_before (jiffies, ehci->next_statechange)) diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c index b1454886fd7a..81a2985632b6 100644 --- a/drivers/usb/otg/fsl_otg.c +++ b/drivers/usb/otg/fsl_otg.c @@ -34,6 +34,7 @@ #include <linux/init.h> #include <linux/reboot.h> #include <linux/timer.h> +#include <linux/jiffies.h> #include <linux/list.h> #include <linux/usb.h> #include <linux/device.h> @@ -41,6 +42,7 @@ #include <linux/usb/gadget.h> #include <linux/workqueue.h> #include <linux/time.h> +#include <linux/usb/fsl_xcvr.h> #include <linux/fsl_devices.h> #include <linux/platform_device.h> #include <linux/irq.h> @@ -60,6 +62,8 @@ #define DRIVER_DESC "Freescale USB OTG Driver" #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC +#define TIMER_FREQ 1000 /* 100 ms*/ +#define IDLE_TIME 5000 /* 1000 ms */ MODULE_DESCRIPTION("Freescale USB OTG Transceiver Driver"); @@ -89,6 +93,13 @@ static struct fsl_otg_config fsl_otg_initdata = { .otg_port = 1, }; +/* the timer is used to monitor the otg loading, if idle for some times + * we will close the otg clk + */ +static unsigned long last_busy; +static bool clk_stopped; +static struct timer_list monitor_timer; + int write_ulpi(u8 addr, u8 data) { u32 temp; @@ -136,17 +147,10 @@ void fsl_otg_dischrg_vbus(int on) } /* A-device driver vbus, controlled through PP bit in PORTSC */ -void fsl_otg_drv_vbus(int on) +void fsl_otg_drv_vbus(struct fsl_usb2_platform_data *pdata, int on) { -/* if (on) - usb_dr_regs->portsc = - cpu_to_le32((le32_to_cpu(usb_dr_regs->portsc) & - ~PORTSC_W1C_BITS) | PORTSC_PORT_POWER); - else - usb_dr_regs->portsc = - cpu_to_le32(le32_to_cpu(usb_dr_regs->portsc) & - ~PORTSC_W1C_BITS & ~PORTSC_PORT_POWER); -*/ + if (pdata->xcvr_ops && pdata->xcvr_ops->set_vbus_power) + pdata->xcvr_ops->set_vbus_power(pdata->xcvr_ops, pdata, on); } /* @@ -395,6 +399,61 @@ int fsl_otg_tick_timer(void) return expired; } +static void fsl_otg_clk_gate(bool on) +{ + struct device *dev = fsl_otg_dev->otg.dev; + struct fsl_usb2_platform_data *pdata; + + if (dev) { + pdata = dev->platform_data; + if (pdata && pdata->usb_clock_for_pm) + pdata->usb_clock_for_pm(on); + } +} + +static void fsl_otg_clk_ctl(void) +{ + if (clk_stopped){ + fsl_otg_clk_gate(true); + clk_stopped = false; + } + last_busy = jiffies; +} + +static void fsl_otg_loading_monitor(unsigned long data) +{ + unsigned long now = jiffies; + if (!clk_stopped){ + if (time_after(now, last_busy + msecs_to_jiffies(IDLE_TIME))){ + printk("otg is idle for some times,so we close the clock %x\n", le32_to_cpu(usb_dr_regs->otgsc)); + clk_stopped = true; + fsl_otg_clk_gate(false); + printk("close otg clk ok\n"); + } + } + mod_timer(&monitor_timer, jiffies + msecs_to_jiffies(TIMER_FREQ)); +} + +/** + * Enable vbus interrupt + * The otg cares USB_ID interrupt + * The device cares B Sesstion Valid + */ +static void b_session_irq_enable(bool enable) +{ + int osc = le32_to_cpu(usb_dr_regs->otgsc); + /* The other interrupts' status should not be cleared */ + osc &= ~(OTGSC_INTSTS_USB_ID | OTGSC_INTSTS_A_VBUS_VALID + | OTGSC_INTSTS_A_SESSION_VALID | OTGSC_INTSTS_B_SESSION_VALID); + osc |= OTGSC_INTSTS_B_SESSION_VALID; + + if (enable) + osc |= OTGSC_INTR_B_SESSION_VALID_EN; + else + osc &= ~OTGSC_INTR_B_SESSION_VALID_EN; + usb_dr_regs->otgsc = cpu_to_le32(osc); +} + /* Reset controller, not reset the bus */ void otg_reset_controller(void) { @@ -438,7 +497,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on) retval = host_pdrv->resume(host_pdev); if (fsm->id) { /* default-b */ - fsl_otg_drv_vbus(1); + fsl_otg_drv_vbus(dev->platform_data, 1); /* Workaround: b_host can't driver * vbus, but PP in PORTSC needs to * be 1 for host to work. @@ -463,7 +522,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on) otg_suspend_state); if (fsm->id) /* default-b */ - fsl_otg_drv_vbus(0); + fsl_otg_drv_vbus(dev->platform_data, 0); } otg_dev->host_working = 0; } @@ -481,7 +540,6 @@ int fsl_otg_start_gadget(struct otg_fsm *fsm, int on) struct device *dev; struct platform_driver *gadget_pdrv; struct platform_device *gadget_pdev; - if (!xceiv->gadget || !xceiv->gadget->dev.parent) return -ENODEV; @@ -517,7 +575,6 @@ static int fsl_otg_set_host(struct otg_transceiver *otg_p, struct usb_bus *host) if (host) { VDBG("host off......\n"); - otg_p->host->otg_port = fsl_otg_initdata.otg_port; otg_p->host->is_b_host = otg_dev->fsm.id; /* must leave time for khubd to finish its thing @@ -634,11 +691,29 @@ static void fsl_otg_event(struct work_struct *work) { struct fsl_otg *og = container_of(work, struct fsl_otg, otg_event.work); struct otg_fsm *fsm = &og->fsm; + struct otg_transceiver *otg = &og->otg; + + otg->default_a = (fsm->id == 0); + /* clear conn information */ + if (fsm->id) + fsm->b_conn = 0; + else + fsm->a_conn = 0; + + if (otg->host) + otg->host->is_b_host = fsm->id; + if (otg->gadget) + otg->gadget->is_a_peripheral = !fsm->id; if (fsm->id) { /* switch to gadget */ + b_session_irq_enable(true); fsl_otg_start_host(fsm, 0); otg_drv_vbus(fsm, 0); fsl_otg_start_gadget(fsm, 1); + }else { /* switch to host */ + fsl_otg_start_gadget(fsm, 0); + otg_drv_vbus(fsm, 1); + fsl_otg_start_host(fsm, 1); } } @@ -678,12 +753,13 @@ irqreturn_t fsl_otg_isr_gpio(int irq, void *dev_id) struct otg_fsm *fsm; struct fsl_usb2_platform_data *pdata = (struct fsl_usb2_platform_data *)dev_id; - struct fsl_otg *p_otg; + struct fsl_otg *f_otg; struct otg_transceiver *otg_trans = otg_get_transceiver(); - p_otg = container_of(otg_trans, struct fsl_otg, otg); - fsm = &p_otg->fsm; int value; + f_otg = container_of(otg_trans, struct fsl_otg, otg); + fsm = &f_otg->fsm; + fsl_otg_clk_ctl(); if (pdata->id_gpio == 0) return IRQ_NONE; @@ -695,35 +771,25 @@ irqreturn_t fsl_otg_isr_gpio(int irq, void *dev_id) set_irq_type(gpio_to_irq(pdata->id_gpio), IRQ_TYPE_LEVEL_HIGH); - if (value == p_otg->fsm.id) + if (value == f_otg->fsm.id) return IRQ_HANDLED; - p_otg->fsm.id = value; - - otg_trans->default_a = (fsm->id == 0); - /* clear conn information */ - if (fsm->id) - fsm->b_conn = 0; - else - fsm->a_conn = 0; - - if (otg_trans->host) - otg_trans->host->is_b_host = fsm->id; - if (otg_trans->gadget) - otg_trans->gadget->is_a_peripheral = !fsm->id; - - VDBG("ID int (ID is %d)\n", fsm->id); - if (fsm->id) { /* switch to gadget */ - schedule_delayed_work(&p_otg->otg_event, 100); + f_otg->fsm.id = value; - } else { /* switch to host */ - cancel_delayed_work(&p_otg->otg_event); - fsl_otg_start_gadget(fsm, 0); - otg_drv_vbus(fsm, 1); - fsl_otg_start_host(fsm, 1); + cancel_delayed_work(&f_otg->otg_event); + schedule_delayed_work(&f_otg->otg_event, msecs_to_jiffies(10)); + /* if host mode, we should clear B_SESSION_VLD event and disable + * B_SESSION_VLD irq + */ + if (!f_otg->fsm.id) { + b_session_irq_enable(false); + }else { + //b_session_irq_enable(true); } + return IRQ_HANDLED; } + /* Interrupt handler. OTG/host/peripheral share the same int line. * OTG driver clears OTGSC interrupts and leaves USB interrupts * intact. It needs to have knowledge of some USB interrupts @@ -731,60 +797,70 @@ irqreturn_t fsl_otg_isr_gpio(int irq, void *dev_id) */ irqreturn_t fsl_otg_isr(int irq, void *dev_id) { - struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm; - struct otg_transceiver *otg = &((struct fsl_otg *)dev_id)->otg; + struct fsl_otg *fotg = (struct fsl_otg *)dev_id; + struct otg_transceiver *otg = &fotg->otg; u32 otg_int_src, otg_sc; + irqreturn_t ret = IRQ_NONE; + fsl_otg_clk_ctl(); otg_sc = le32_to_cpu(usb_dr_regs->otgsc); otg_int_src = otg_sc & OTGSC_INTSTS_MASK & (otg_sc >> 8); - /* Only clear otg interrupts */ - usb_dr_regs->otgsc |= cpu_to_le32(otg_sc & OTGSC_INTSTS_MASK); + /* Only clear otg interrupts, expect B_SESSION_VALID, + * Leave it to be handled by arcotg_udc */ + usb_dr_regs->otgsc = ((usb_dr_regs->otgsc | cpu_to_le32(otg_sc & OTGSC_INTSTS_MASK))& + (~OTGSC_INTSTS_B_SESSION_VALID)); /*FIXME: ID change not generate when init to 0 */ - fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0; - otg->default_a = (fsm->id == 0); + fotg->fsm.id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0; + otg->default_a = (fotg->fsm.id == 0); /* process OTG interrupts */ if (otg_int_src) { if (otg_int_src & OTGSC_INTSTS_USB_ID) { - fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0; - otg->default_a = (fsm->id == 0); - /* clear conn information */ - if (fsm->id) - fsm->b_conn = 0; - else - fsm->a_conn = 0; - - if (otg->host) - otg->host->is_b_host = fsm->id; - if (otg->gadget) - otg->gadget->is_a_peripheral = !fsm->id; - VDBG("ID int (ID is %d)\n", fsm->id); - - if (fsm->id) { /* switch to gadget */ - schedule_delayed_work(&((struct fsl_otg *) - dev_id)->otg_event, - 100); - } else { /* switch to host */ - cancel_delayed_work(& - ((struct fsl_otg *)dev_id)-> - otg_event); - fsl_otg_start_gadget(fsm, 0); - otg_drv_vbus(fsm, 1); - fsl_otg_start_host(fsm, 1); + fotg->fsm.id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0; + + printk("ID int (ID is %d)\n", fotg->fsm.id); + + cancel_delayed_work(&fotg->otg_event); + schedule_delayed_work(&fotg->otg_event, msecs_to_jiffies(10)); + /* if host mode, we should clear B_SESSION_VLD event and disable + * B_SESSION_VLD irq + */ + if (!fotg->fsm.id) { + b_session_irq_enable(false); + }else { + //b_session_irq_enable(true); } - - return IRQ_HANDLED; + ret = IRQ_HANDLED; } } - return IRQ_NONE; + return ret; +} + +static void fsl_otg_fsm_drv_vbus(int on) +{ + struct otg_fsm *fsm = &(fsl_otg_dev->fsm); + struct otg_transceiver *xceiv = fsm->transceiver; + + struct device *dev; + /* + * The host is assigned at otg_set_host + */ + if (!xceiv->host) + return; + /* + * The dev is assigned at usb_create_hcd which is called earlier + * than otg_set_host at host driver's probe + */ + dev = xceiv->host->controller; + fsl_otg_drv_vbus(dev->platform_data, on); } static struct otg_fsm_ops fsl_otg_ops = { .chrg_vbus = fsl_otg_chrg_vbus, - .drv_vbus = fsl_otg_drv_vbus, + .drv_vbus = fsl_otg_fsm_drv_vbus, .loc_conn = fsl_otg_loc_conn, .loc_sof = fsl_otg_loc_sof, .start_pulse = fsl_otg_start_pulse, @@ -837,6 +913,7 @@ static int fsl_otg_conf(struct platform_device *pdev) fsl_otg_tc->otg.set_power = fsl_otg_set_power; fsl_otg_tc->otg.start_hnp = fsl_otg_start_hnp; fsl_otg_tc->otg.start_srp = fsl_otg_start_srp; + fsl_otg_tc->otg.dev = &pdev->dev; fsl_otg_dev = fsl_otg_tc; @@ -903,6 +980,8 @@ int usb_otg_start(struct platform_device *pdev) if (pdata->platform_init && pdata->platform_init(pdev) != 0) return -EINVAL; + clk_stopped = false; /* platform_init will open the otg clk */ + /* stop the controller */ temp = readl(&p_otg->dr_mem_map->usbcmd); temp &= ~USB_CMD_RUN_STOP; @@ -1229,6 +1308,10 @@ static int __init fsl_otg_probe(struct platform_device *pdev) return -EIO; } + last_busy = jiffies; + setup_timer(&monitor_timer, fsl_otg_loading_monitor, (unsigned long)pdev); + mod_timer(&monitor_timer, jiffies + msecs_to_jiffies(TIMER_FREQ)); + create_proc_file(); return status; } diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 34e4e7995169..9c4739c8b19c 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -35,6 +35,11 @@ EXPORT_SYMBOL_GPL(fb_mode_option); */ static const struct fb_videomode modedb[] = { + { + /* 800x480 @ 60 Hz, 31.5 kHz hsync */ + "LQ070Y3DG3B", 60, 800, 480, 44000, 0, 50, 25, 10, 128, 10, + FB_SYNC_EXT,FB_VMODE_NONINTERLACED + }, { /* 640x400 @ 70 Hz, 31.5 kHz hsync */ NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, diff --git a/drivers/video/mxc/Kconfig b/drivers/video/mxc/Kconfig index 268879626fc2..42f990ac3499 100644 --- a/drivers/video/mxc/Kconfig +++ b/drivers/video/mxc/Kconfig @@ -26,12 +26,21 @@ config FB_MXC_EPSON_VGA_SYNC_PANEL config FB_MXC_TVOUT_TVE tristate "MXC TVE TV Out Encoder" - depends on FB_MXC_SYNC_PANEL - depends on MXC_IPU_V3 + depends on FB_MXC_SYNC_PANEL + depends on MXC_IPU_V3 + +config FB_MXC_LDB + tristate "MXC LDB" + depends on FB_MXC_SYNC_PANEL + depends on MXC_IPU_V3 config FB_MXC_CLAA_WVGA_SYNC_PANEL + depends on FB_MXC_SYNC_PANEL + tristate "CLAA WVGA Panel" + +config FB_MXC_SII9022 depends on FB_MXC_SYNC_PANEL - tristate "CLAA WVGA Panel" + tristate "Si Image SII9022 DVI/HDMI Interface Chip" config FB_MXC_CH7026 depends on FB_MXC_SYNC_PANEL @@ -43,12 +52,21 @@ config FB_MXC_TVOUT_CH7024 config FB_MXC_LOW_PWR_DISPLAY bool "Low Power Display Refresh Mode" - depends on FB_MXC_SYNC_PANEL && MXC_FB_IRAM - default y + depends on FB_MXC_SYNC_PANEL && MXC_FB_IRAM + default y + +config VIDEO_AD9389 + tristate "Analog Devices AD9389/AD9889 digital video encoders" + depends on I2C && FB_MXC_SYNC_PANEL + ---help--- + Support for the AD9389/AD9889 HDMI/DVI Video transmiter. + + To compile this driver as a module, choose M here: the + module will be called ad9389. config FB_MXC_INTERNAL_MEM - bool "Framebuffer in Internal RAM" - depends on FB_MXC_SYNC_PANEL && MXC_FB_IRAM + bool "Framebuffer in Internal RAM" + depends on FB_MXC_SYNC_PANEL && MXC_FB_IRAM default y config FB_MXC_ASYNC_PANEL @@ -66,9 +84,24 @@ config FB_MXC_EPSON_PANEL endmenu +config FB_MXC_EINK_PANEL + depends on FB_MXC + depends on DMA_ENGINE + select FB_DEFERRED_IO + tristate "E-Ink Panel Framebuffer" + +config FB_MXC_EINK_AUTO_UPDATE_MODE + bool "E-Ink Auto-update Mode Support" + default n + depends on FB_MXC_EINK_PANEL + +config FB_MXC_ELCDIF_FB + depends on FB && ARCH_MXC + tristate "Support MXC ELCDIF framebuffer" + choice - prompt "Async Panel Interface Type" - depends on FB_MXC_ASYNC_PANEL && FB_MXC + prompt "Async Panel Interface Type" + depends on FB_MXC_ASYNC_PANEL && FB_MXC default FB_MXC_ASYNC_PANEL_IFC_16_BIT config FB_MXC_ASYNC_PANEL_IFC_8_BIT diff --git a/drivers/video/mxc/Makefile b/drivers/video/mxc/Makefile index d2454aac2604..d823ab29f030 100644 --- a/drivers/video/mxc/Makefile +++ b/drivers/video/mxc/Makefile @@ -18,5 +18,7 @@ obj-$(CONFIG_FB_MXC_EPSON_VGA_SYNC_PANEL) += mxcfb_epson_vga.o obj-$(CONFIG_FB_MXC_CLAA_WVGA_SYNC_PANEL) += mxcfb_claa_wvga.o obj-$(CONFIG_FB_MXC_TVOUT_CH7024) += ch7024.o obj-$(CONFIG_FB_MXC_TVOUT_TVE) += tve.o -obj-$(CONFIG_FB_MXC_CH7026) += mxcfb_ch7026.o -#obj-$(CONFIG_FB_MODE_HELPERS) += mxc_edid.o +obj-$(CONFIG_FB_MXC_CH7026) += mxcfb_ch7026.o +#obj-$(CONFIG_FB_MODE_HELPERS) += mxc_edid.o +obj-$(CONFIG_VIDEO_AD9389) += ad9389.o +obj-$(CONFIG_FB_MXC_SII9022) += mxcfb_sii9022.o diff --git a/drivers/video/mxc/ccwmx51_display.c b/drivers/video/mxc/ccwmx51_display.c index 70a5b25f3fe9..212f59e919e4 100755 --- a/drivers/video/mxc/ccwmx51_display.c +++ b/drivers/video/mxc/ccwmx51_display.c @@ -22,23 +22,37 @@ #include <mach/hardware.h> #include <mach/mxc.h> +#define MAX_DISPLAYS 2 +#define DISP0_ID "DISP3 BG" +#define DISP1_ID "DISP3 BG - DI1" + static void lcd_poweron(struct ccwmx51_lcd_pdata *plat); static void lcd_poweroff(struct ccwmx51_lcd_pdata *plat); -static struct platform_device *plcd_dev; +static struct platform_device *plcd_dev[MAX_DISPLAYS] = {NULL, NULL}; + +static int lcd_get_index(struct fb_info *info) +{ + if (!strcmp(info->fix.id, DISP0_ID)) + return 0; + else if (!strcmp(info->fix.id, DISP1_ID)) + return 1; + return -1; +} static void lcd_init_fb(struct fb_info *info) { - struct ccwmx51_lcd_pdata *plat = plcd_dev->dev.platform_data; struct fb_var_screeninfo var; + struct ccwmx51_lcd_pdata *plat; + int i = lcd_get_index(info); - memset(&var, 0, sizeof(var)); + if (i < 0) + return; + plat = plcd_dev[i]->dev.platform_data; + memset(&var, 0, sizeof(var)); fb_videomode_to_var(&var, plat->fb_pdata.mode); - var.activate = FB_ACTIVATE_ALL; - var.yres_virtual = var.yres; - acquire_console_sem(); info->flags |= FBINFO_MISC_USEREVENT; fb_set_var(info, &var); @@ -74,18 +88,37 @@ static struct notifier_block nb = { static int __devinit lcd_sync_probe(struct platform_device *pdev) { struct ccwmx51_lcd_pdata *plat = pdev->dev.platform_data; + int i; + + if (!plat) + return -ENODEV; - if (!plat) - return -ENODEV; + if (plat->vif < 0 || plat->vif > (MAX_DISPLAYS - 1)) + return -EINVAL; - if (plat->reset) - plat->reset(); + if (plat->init) + plat->init(plat->vif); - plcd_dev = pdev; - lcd_init_fb(registered_fb[plat->vif]); - fb_show_logo(registered_fb[plat->vif], 0); - fb_register_client(&nb); + plcd_dev[plat->vif] = pdev; + for (i = 0; i < num_registered_fb; i++) { + if ((!strcmp(registered_fb[i]->fix.id, DISP0_ID) && plat->vif == 0) || + (!strcmp(registered_fb[i]->fix.id, DISP1_ID) && plat->vif == 1)) { + lcd_init_fb(registered_fb[i]); + /* Clear the screen */ + memset((char *)registered_fb[i]->screen_base, 0, + registered_fb[i]->fix.smem_len); + fb_show_logo(registered_fb[i], 0); + } + } + + /** + * Register the block notifier only once. The device being notified can be + * retrieved from the received event. There are some issues when the same + * notifier is registered multiple times. + */ + if (plcd_dev[0] == NULL && plcd_dev[1] == NULL) + fb_register_client(&nb); lcd_poweron(plat); return 0; @@ -95,9 +128,14 @@ static int __devexit lcd_sync_remove(struct platform_device *pdev) { struct ccwmx51_lcd_pdata *plat = pdev->dev.platform_data; - fb_unregister_client(&nb); lcd_poweroff(plat); - plcd_dev = NULL; + if (plat->deinit) + plat->deinit(plat->vif); + + plcd_dev[plat->vif] = NULL; + + if (plcd_dev[0] == NULL && plcd_dev[1] == NULL) + fb_unregister_client(&nb); return 0; } @@ -129,14 +167,14 @@ static struct platform_driver lcd_driver = { static void lcd_poweron(struct ccwmx51_lcd_pdata *plat) { - if (plat && plat->bl_enable) - plat->bl_enable(0); + if (plat && plat->bl_enable) + plat->bl_enable(1, plat->vif); } static void lcd_poweroff(struct ccwmx51_lcd_pdata *plat) { - if (plat && plat->bl_enable) - plat->bl_enable(1); + if (plat && plat->bl_enable) + plat->bl_enable(0, plat->vif); } static int __init lcd_sync_init(void) diff --git a/drivers/video/mxc/mxc_ipuv3_fb.c b/drivers/video/mxc/mxc_ipuv3_fb.c index 76c6d523c291..cc48e62637ca 100644 --- a/drivers/video/mxc/mxc_ipuv3_fb.c +++ b/drivers/video/mxc/mxc_ipuv3_fb.c @@ -22,7 +22,6 @@ * * @ingroup Framebuffer */ - /*! * Include files */ @@ -44,9 +43,13 @@ #include <linux/io.h> #include <linux/ipu.h> #include <linux/mxcfb.h> +#include <linux/earlysuspend.h> #include <asm/mach-types.h> #include <asm/uaccess.h> #include <mach/hardware.h> +#include <linux/suspend.h> + +static int vt_switch; /* * Driver name @@ -56,11 +59,14 @@ * Structure containing the MXC specific framebuffer information. */ struct mxcfb_info { + char *fb_mode_str; + int default_bpp; int cur_blank; int next_blank; ipu_channel_t ipu_ch; int ipu_di; u32 ipu_di_pix_fmt; + bool ipu_ext_clk; bool overlay; bool alpha_chan_en; dma_addr_t alpha_phy_addr0; @@ -74,6 +80,8 @@ struct mxcfb_info { u32 pseudo_palette[16]; + bool wait4vsync; + uint32_t waitcnt; struct semaphore flip_sem; struct semaphore alpha_flip_sem; struct completion vsync_complete; @@ -93,12 +101,10 @@ enum { BOTH_OFF }; -static char *fb_mode; -static unsigned long default_bpp = 16; +#define FB_DEVICE_NUM 3 static bool g_dp_in_use; LIST_HEAD(fb_alloc_list); -static struct fb_info *mxcfb_info[3]; -static int ext_clk_used; +static struct fb_info *mxcfb_info[FB_DEVICE_NUM]; static uint32_t bpp_to_pixfmt(struct fb_info *fbi) { @@ -125,6 +131,7 @@ static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id); static int mxcfb_blank(int blank, struct fb_info *info); static int mxcfb_map_video_memory(struct fb_info *fbi); static int mxcfb_unmap_video_memory(struct fb_info *fbi); +static int mxcfb_option_setup(struct fb_info *info, char *options); /* * Set fixed framebuffer parameters based on variable settings. @@ -165,30 +172,42 @@ static int _setup_disp_channel1(struct fb_info *fbi) for (i = 0; i < num_registered_fb; i++) { mxc_fbi_tmp = (struct mxcfb_info *) - (registered_fb[i]->par); + (registered_fb[i]->par); if (mxc_fbi_tmp->ipu_ch == MEM_BG_SYNC) { - fbi->var.vmode = - registered_fb[i]->var.vmode; + fbi->var.vmode = registered_fb[i]->var.vmode; mxc_fbi->ipu_di_pix_fmt = - mxc_fbi_tmp->ipu_di_pix_fmt; + mxc_fbi_tmp->ipu_di_pix_fmt; break; } } } - if (fbi->var.vmode & FB_VMODE_INTERLACED) { - params.mem_dp_bg_sync.interlaced = true; - params.mem_dp_bg_sync.out_pixel_fmt = - IPU_PIX_FMT_YUV444; + if (mxc_fbi->ipu_ch == MEM_DC_SYNC) { + if (fbi->var.vmode & FB_VMODE_INTERLACED) { + params.mem_dc_sync.interlaced = true; + params.mem_dc_sync.out_pixel_fmt = + IPU_PIX_FMT_YUV444; + } else { + if (mxc_fbi->ipu_di_pix_fmt) + params.mem_dc_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt; + else + params.mem_dc_sync.out_pixel_fmt = IPU_PIX_FMT_RGB666; + } + params.mem_dc_sync.in_pixel_fmt = bpp_to_pixfmt(fbi); } else { - if (mxc_fbi->ipu_di_pix_fmt) - params.mem_dp_bg_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt; - else - params.mem_dp_bg_sync.out_pixel_fmt = IPU_PIX_FMT_RGB666; + if (fbi->var.vmode & FB_VMODE_INTERLACED) { + params.mem_dp_bg_sync.interlaced = true; + params.mem_dp_bg_sync.out_pixel_fmt = + IPU_PIX_FMT_YUV444; + } else { + if (mxc_fbi->ipu_di_pix_fmt) + params.mem_dp_bg_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt; + else + params.mem_dp_bg_sync.out_pixel_fmt = IPU_PIX_FMT_RGB666; + } + params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi); + if (mxc_fbi->alpha_chan_en) + params.mem_dp_bg_sync.alpha_chan_en = true; } - params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi); - if (mxc_fbi->alpha_chan_en) - params.mem_dp_bg_sync.alpha_chan_en = true; - ipu_init_channel(mxc_fbi->ipu_ch, ¶ms); return 0; @@ -201,10 +220,12 @@ static int _setup_disp_channel2(struct fb_info *fbi) int fb_stride; switch (bpp_to_pixfmt(fbi)) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_YUV422P: + case IPU_PIX_FMT_YUV420P2: + case IPU_PIX_FMT_YVU420P: + case IPU_PIX_FMT_NV12: + case IPU_PIX_FMT_YUV422P: + case IPU_PIX_FMT_YVU422P: + case IPU_PIX_FMT_YUV420P: fb_stride = fbi->var.xres_virtual; break; default: @@ -212,7 +233,7 @@ static int _setup_disp_channel2(struct fb_info *fbi) } mxc_fbi->cur_ipu_buf = 1; - sema_init(&mxc_fbi->flip_sem, 1); + sema_init(&mxc_fbi->flip_sem, 0); if (mxc_fbi->alpha_chan_en) { mxc_fbi->cur_ipu_alpha_buf = 1; sema_init(&mxc_fbi->alpha_flip_sem, 1); @@ -226,8 +247,7 @@ static int _setup_disp_channel2(struct fb_info *fbi) IPU_ROTATE_NONE, fbi->fix.smem_start + (fbi->fix.line_length * fbi->var.yres), - fbi->fix.smem_start, - 0, 0); + fbi->fix.smem_start, 0, 0); if (retval) { dev_err(fbi->device, "ipu_init_channel_buffer error %d\n", retval); @@ -297,38 +317,47 @@ static int mxcfb_set_par(struct fb_info *fbi) mxc_fbi->alpha_phy_addr1); mxc_fbi->alpha_virt_addr0 = - dma_alloc_coherent(fbi->device, - alpha_mem_len, - &mxc_fbi->alpha_phy_addr0, - GFP_DMA | GFP_KERNEL); + dma_alloc_coherent(fbi->device, + alpha_mem_len, + &mxc_fbi->alpha_phy_addr0, + GFP_DMA | GFP_KERNEL); mxc_fbi->alpha_virt_addr1 = - dma_alloc_coherent(fbi->device, - alpha_mem_len, - &mxc_fbi->alpha_phy_addr1, - GFP_DMA | GFP_KERNEL); + dma_alloc_coherent(fbi->device, + alpha_mem_len, + &mxc_fbi->alpha_phy_addr1, + GFP_DMA | GFP_KERNEL); if (mxc_fbi->alpha_virt_addr0 == NULL || mxc_fbi->alpha_virt_addr1 == NULL) { dev_err(fbi->device, "mxcfb: dma alloc for" " alpha buffer failed.\n"); if (mxc_fbi->alpha_virt_addr0) dma_free_coherent(fbi->device, - mxc_fbi->alpha_mem_len, - mxc_fbi->alpha_virt_addr0, - mxc_fbi->alpha_phy_addr0); + mxc_fbi-> + alpha_mem_len, + mxc_fbi-> + alpha_virt_addr0, + mxc_fbi-> + alpha_phy_addr0); if (mxc_fbi->alpha_virt_addr1) dma_free_coherent(fbi->device, - mxc_fbi->alpha_mem_len, - mxc_fbi->alpha_virt_addr1, - mxc_fbi->alpha_phy_addr1); + mxc_fbi-> + alpha_mem_len, + mxc_fbi-> + alpha_virt_addr1, + mxc_fbi-> + alpha_phy_addr1); return -ENOMEM; } mxc_fbi->alpha_mem_len = alpha_mem_len; } } +#if !(defined(CONFIG_CCWMX51_DISP0) && defined(CONFIG_CCWMX51_DISP1)) + /* FIXME this lines of code doesnt allow to run the dual head... */ if (mxc_fbi->next_blank != FB_BLANK_UNBLANK) return retval; +#endif _setup_disp_channel1(fbi); @@ -345,9 +374,9 @@ static int mxcfb_set_par(struct fb_info *fbi) else out_pixel_fmt = IPU_PIX_FMT_RGB666; } - if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */ + if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */ sig_cfg.odd_field_first = true; - if ((fbi->var.sync & FB_SYNC_EXT) || ext_clk_used) + if ((fbi->var.sync & FB_SYNC_EXT) || mxc_fbi->ipu_ext_clk) sig_cfg.ext_clk = true; if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT) sig_cfg.Hsync_pol = true; @@ -453,8 +482,7 @@ static int swap_channels(struct fb_info *fbi) ch_to = MEM_BG_SYNC; for (i = 0; i < num_registered_fb; i++) { - mxc_fbi_to = - (struct mxcfb_info *)mxcfb_info[i]->par; + mxc_fbi_to = (struct mxcfb_info *)mxcfb_info[i]->par; if (mxc_fbi_to->ipu_ch == ch_to) { fbi_to = mxcfb_info[i]; break; @@ -519,14 +547,14 @@ static int swap_channels(struct fb_info *fbi) } if (ipu_request_irq(mxc_fbi_from->ipu_ch_irq, mxcfb_irq_handler, 0, - MXCFB_NAME, fbi) != 0) { + MXCFB_NAME, fbi) != 0) { dev_err(fbi->device, "Error registering irq %d\n", mxc_fbi_from->ipu_ch_irq); return -EBUSY; } ipu_disable_irq(mxc_fbi_from->ipu_ch_irq); if (ipu_request_irq(mxc_fbi_to->ipu_ch_irq, mxcfb_irq_handler, 0, - MXCFB_NAME, fbi_to) != 0) { + MXCFB_NAME, fbi_to) != 0) { dev_err(fbi_to->device, "Error registering irq %d\n", mxc_fbi_to->ipu_ch_irq); return -EBUSY; @@ -545,17 +573,48 @@ static int swap_channels(struct fb_info *fbi) */ static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { + struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par; u32 vtotal; u32 htotal; + /* fg should not bigger than bg */ + if (mxc_fbi->ipu_ch == MEM_FG_SYNC) { + struct fb_info *fbi_tmp; + struct mxcfb_info *mxc_fbi_tmp; + int i, bg_xres, bg_yres; + int16_t pos_x, pos_y; + + bg_xres = var->xres; + bg_yres = var->yres; + + for (i = 0; i < num_registered_fb; i++) { + fbi_tmp = registered_fb[i]; + mxc_fbi_tmp = (struct mxcfb_info *) + (fbi_tmp->par); + if (mxc_fbi_tmp->ipu_ch == MEM_BG_SYNC) { + bg_xres = fbi_tmp->var.xres; + bg_yres = fbi_tmp->var.yres; + break; + } + } + + ipu_disp_get_window_pos(mxc_fbi->ipu_ch, &pos_x, &pos_y); + + if ((var->xres + pos_x) > bg_xres) + var->xres = bg_xres - pos_x; + if ((var->yres + pos_y) > bg_yres) + var->yres = bg_yres - pos_y; + } + if (var->xres_virtual < var->xres) var->xres_virtual = var->xres; if (var->yres_virtual < var->yres) var->yres_virtual = var->yres; if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) && - (var->bits_per_pixel != 16) && (var->bits_per_pixel != 8)) - var->bits_per_pixel = default_bpp; + (var->bits_per_pixel != 16) && (var->bits_per_pixel != 12) && + (var->bits_per_pixel != 8)) + var->bits_per_pixel = mxc_fbi->default_bpp; switch (var->bits_per_pixel) { case 8: @@ -723,7 +782,7 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) } if (ipu_disp_set_global_alpha(mxc_fbi->ipu_ch, - (bool)ga.enable, + (bool) ga.enable, ga.alpha)) { retval = -EINVAL; break; @@ -750,7 +809,7 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) } if (ipu_disp_set_global_alpha(mxc_fbi->ipu_ch, - !(bool)la.enable, 0)) { + !(bool) la.enable, 0)) { retval = -EINVAL; break; } @@ -765,8 +824,11 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) for (i = 0; i < num_registered_fb; i++) { char *idstr = registered_fb[i]->fix.id; - if (strcmp(idstr, video_plane_idstr) == 0) { - ((struct mxcfb_info *)(registered_fb[i]->par))->alpha_chan_en = false; + if (strcmp(idstr, video_plane_idstr) == + 0) { + ((struct mxcfb_info + *)(registered_fb[i]->par))-> + alpha_chan_en = false; break; } } @@ -794,8 +856,8 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) uint32_t ipu_alp_ch_irq; if (!(((mxc_fbi->ipu_ch == MEM_FG_SYNC) || - (mxc_fbi->ipu_ch == MEM_BG_SYNC)) && - (mxc_fbi->alpha_chan_en))) { + (mxc_fbi->ipu_ch == MEM_BG_SYNC)) && + (mxc_fbi->alpha_chan_en))) { dev_err(fbi->device, "Should use background or overlay " "framebuffer to set the alpha buffer " @@ -822,11 +884,10 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) down(&mxc_fbi->alpha_flip_sem); mxc_fbi->cur_ipu_alpha_buf = - !mxc_fbi->cur_ipu_alpha_buf; + !mxc_fbi->cur_ipu_alpha_buf; if (ipu_update_channel_buffer(mxc_fbi->ipu_ch, IPU_ALPHA_IN_BUFFER, - mxc_fbi-> - cur_ipu_alpha_buf, + mxc_fbi->cur_ipu_alpha_buf, base) == 0) { ipu_select_buffer(mxc_fbi->ipu_ch, IPU_ALPHA_IN_BUFFER, @@ -864,9 +925,9 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) break; } retval = ipu_disp_set_gamma_correction(mxc_fbi->ipu_ch, - gamma.enable, - gamma.constk, - gamma.slopek); + gamma.enable, + gamma.constk, + gamma.slopek); break; } case MXCFB_WAIT_FOR_VSYNC: @@ -876,7 +937,8 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) int i; for (i = 0; i < num_registered_fb; i++) { bg_mxcfbi = - ((struct mxcfb_info *)(registered_fb[i]->par)); + ((struct mxcfb_info + *)(registered_fb[i]->par)); if (bg_mxcfbi->ipu_ch == MEM_BG_SYNC) break; @@ -891,21 +953,25 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) break; } - down(&mxc_fbi->flip_sem); init_completion(&mxc_fbi->vsync_complete); ipu_clear_irq(mxc_fbi->ipu_ch_irq); + mxc_fbi->wait4vsync = 1; ipu_enable_irq(mxc_fbi->ipu_ch_irq); - retval = wait_for_completion_interruptible_timeout( - &mxc_fbi->vsync_complete, 1 * HZ); + retval = + wait_for_completion_interruptible_timeout(&mxc_fbi-> + vsync_complete, + 1 * HZ); if (retval == 0) { dev_err(fbi->device, "MXCFB_WAIT_FOR_VSYNC: timeout %d\n", retval); + mxc_fbi->wait4vsync = 0; retval = -ETIME; } else if (retval > 0) { retval = 0; } + break; } case FBIO_ALLOC: @@ -986,7 +1052,8 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) for (i = 0; i < num_registered_fb; i++) { bg_mxcfbi = - ((struct mxcfb_info *)(registered_fb[i]->par)); + ((struct mxcfb_info *)(registered_fb[i]-> + par)); if (bg_mxcfbi->ipu_ch == MEM_BG_SYNC) { bg_fbi = registered_fb[i]; @@ -1005,13 +1072,15 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) if (bg_fbi->var.xres < fbi->var.xres) pos.x = 0; else - pos.x = bg_fbi->var.xres - fbi->var.xres; + pos.x = + bg_fbi->var.xres - fbi->var.xres; } if (fbi->var.yres + pos.y > bg_fbi->var.yres) { if (bg_fbi->var.yres < fbi->var.yres) pos.y = 0; else - pos.y = bg_fbi->var.yres - fbi->var.yres; + pos.y = + bg_fbi->var.yres - fbi->var.yres; } retval = ipu_disp_set_window_pos(mxc_fbi->ipu_ch, @@ -1026,12 +1095,39 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) case MXCFB_GET_FB_IPU_CHAN: { struct mxcfb_info *mxc_fbi = - (struct mxcfb_info *)fbi->par; + (struct mxcfb_info *)fbi->par; if (put_user(mxc_fbi->ipu_ch, argp)) return -EFAULT; break; } + case MXCFB_GET_DIFMT: + { + struct mxcfb_info *mxc_fbi = + (struct mxcfb_info *)fbi->par; + + if (put_user(mxc_fbi->ipu_di_pix_fmt, argp)) + return -EFAULT; + break; + } + case MXCFB_GET_FB_IPU_DI: + { + struct mxcfb_info *mxc_fbi = + (struct mxcfb_info *)fbi->par; + + if (put_user(mxc_fbi->ipu_di, argp)) + return -EFAULT; + break; + } + case MXCFB_GET_FB_BLANK: + { + struct mxcfb_info *mxc_fbi = + (struct mxcfb_info *)fbi->par; + + if (put_user(mxc_fbi->cur_blank, argp)) + return -EFAULT; + break; + } default: retval = -EINVAL; } @@ -1081,7 +1177,7 @@ static int mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par, - *mxc_graphic_fbi = NULL; + *mxc_graphic_fbi = NULL; u_int y_bottom; unsigned long base, active_alpha_phy_addr = 0; bool loc_alpha_en = false; @@ -1102,7 +1198,7 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) int j; for (j = 0; j < num_registered_fb; j++) { bg_mxcfbi = - ((struct mxcfb_info *)(registered_fb[j]->par)); + ((struct mxcfb_info *)(registered_fb[j]->par)); if (bg_mxcfbi->ipu_ch == MEM_BG_SYNC) break; @@ -1122,12 +1218,9 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) return -EINVAL; base = (var->yoffset * var->xres_virtual + var->xoffset); - base *= (var->bits_per_pixel) / 8; + base = (var->bits_per_pixel) * base / 8; base += info->fix.smem_start; - dev_dbg(info->device, "Updating SDC %s buf %d address=0x%08lX\n", - info->fix.id, mxc_fbi->cur_ipu_buf, base); - /* Check if DP local alpha is enabled and find the graphic fb */ if (mxc_fbi->ipu_ch == MEM_BG_SYNC || mxc_fbi->ipu_ch == MEM_FG_SYNC) { for (i = 0; i < num_registered_fb; i++) { @@ -1135,13 +1228,13 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) if ((strcmp(idstr, "DISP3 BG") == 0 || strcmp(idstr, "DISP3 FG") == 0) && ((struct mxcfb_info *) - (registered_fb[i]->par))->alpha_chan_en) { + (registered_fb[i]->par))->alpha_chan_en) { loc_alpha_en = true; mxc_graphic_fbi = (struct mxcfb_info *) - (registered_fb[i]->par); + (registered_fb[i]->par); active_alpha_phy_addr = mxc_fbi->cur_ipu_buf ? - mxc_graphic_fbi->alpha_phy_addr1 : - mxc_graphic_fbi->alpha_phy_addr0; + mxc_graphic_fbi->alpha_phy_addr1 : + mxc_graphic_fbi->alpha_phy_addr0; dev_dbg(info->device, "Updating SDC graphic " "buf %d address=0x%08lX\n", mxc_fbi->cur_ipu_buf, @@ -1151,10 +1244,13 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) } } - down(&mxc_fbi->flip_sem); init_completion(&mxc_fbi->vsync_complete); mxc_fbi->cur_ipu_buf = !mxc_fbi->cur_ipu_buf; + + dev_dbg(info->device, "Updating SDC %s buf %d address=0x%08lX\n", + info->fix.id, mxc_fbi->cur_ipu_buf, base); + if (ipu_update_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER, mxc_fbi->cur_ipu_buf, base) == 0) { /* Update the DP local alpha buffer only for graphic plane */ @@ -1176,8 +1272,13 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) dev_err(info->device, "Error updating SDC buf %d to address=0x%08lX\n", mxc_fbi->cur_ipu_buf, base); + mxc_fbi->cur_ipu_buf = !mxc_fbi->cur_ipu_buf; + ipu_clear_irq(mxc_fbi->ipu_ch_irq); + ipu_enable_irq(mxc_fbi->ipu_ch_irq); + return -EBUSY; } + down(&mxc_fbi->flip_sem); dev_dbg(info->device, "Update complete\n"); info->var.xoffset = var->xoffset; @@ -1211,9 +1312,9 @@ static int mxcfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) len = fbi->fix.smem_len - offset; vma->vm_pgoff = (fbi->fix.smem_start + offset) >> PAGE_SHIFT; } else if ((vma->vm_pgoff == - (mxc_fbi->alpha_phy_addr0 >> PAGE_SHIFT)) || + (mxc_fbi->alpha_phy_addr0 >> PAGE_SHIFT)) || (vma->vm_pgoff == - (mxc_fbi->alpha_phy_addr1 >> PAGE_SHIFT))) { + (mxc_fbi->alpha_phy_addr1 >> PAGE_SHIFT))) { len = mxc_fbi->alpha_mem_len; } else { list_for_each_entry(mem, &fb_alloc_list, list) { @@ -1269,9 +1370,14 @@ static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id) struct fb_info *fbi = dev_id; struct mxcfb_info *mxc_fbi = fbi->par; - complete(&mxc_fbi->vsync_complete); - up(&mxc_fbi->flip_sem); - ipu_disable_irq(irq); + if (mxc_fbi->wait4vsync) { + complete(&mxc_fbi->vsync_complete); + ipu_disable_irq(irq); + mxc_fbi->wait4vsync = 0; + } else { + up(&mxc_fbi->flip_sem); + ipu_disable_irq(irq); + } return IRQ_HANDLED; } @@ -1288,14 +1394,10 @@ static irqreturn_t mxcfb_alpha_irq_handler(int irq, void *dev_id) /* * Suspends the framebuffer and blanks the screen. Power management support */ -static int mxcfb_suspend(struct platform_device *pdev, pm_message_t state) +static void mxcfb_suspend_one(struct fb_info *fbi) { - struct fb_info *fbi = platform_get_drvdata(pdev); struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; int saved_blank; -#ifdef CONFIG_FB_MXC_LOW_PWR_DISPLAY - void *fbmem; -#endif acquire_console_sem(); fb_set_suspend(fbi, 1); @@ -1303,25 +1405,43 @@ static int mxcfb_suspend(struct platform_device *pdev, pm_message_t state) mxcfb_blank(FB_BLANK_POWERDOWN, fbi); mxc_fbi->next_blank = saved_blank; release_console_sem(); - - return 0; } /* * Resumes the framebuffer and unblanks the screen. Power management support */ -static int mxcfb_resume(struct platform_device *pdev) +static void mxcfb_resume_one(struct fb_info *fbi) { - struct fb_info *fbi = platform_get_drvdata(pdev); struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; acquire_console_sem(); mxcfb_blank(mxc_fbi->next_blank, fbi); fb_set_suspend(fbi, 0); release_console_sem(); +} + +#ifndef CONFIG_HAS_EARLYSUSPEND + +static int mxcfb_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct fb_info *fbi = platform_get_drvdata(pdev); + + if (fbi && (strcmp(fbi->fix.id, "DISP3 FG") == 0)) + mxcfb_suspend_one(fbi); + + return 0; +} + +static int mxcfb_resume(struct platform_device *pdev) +{ + struct fb_info *fbi = platform_get_drvdata(pdev); + + if (fbi && (strcmp(fbi->fix.id, "DISP3 FG") == 0)) + mxcfb_resume_one(fbi); return 0; } +#endif /* * Main framebuffer functions @@ -1341,12 +1461,12 @@ static int mxcfb_map_video_memory(struct fb_info *fbi) { if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length) fbi->fix.smem_len = fbi->var.yres_virtual * - fbi->fix.line_length; + fbi->fix.line_length; fbi->screen_base = dma_alloc_writecombine(fbi->device, - fbi->fix.smem_len, - (dma_addr_t *)&fbi->fix.smem_start, - GFP_DMA); + fbi->fix.smem_len, + (dma_addr_t *) & fbi->fix. + smem_start, GFP_DMA); if (fbi->screen_base == 0) { dev_err(fbi->device, "Unable to allocate framebuffer memory\n"); fbi->fix.smem_len = 0; @@ -1443,6 +1563,7 @@ static ssize_t swap_disp_chan(struct device *dev, struct mxcfb_info *mxcfbi = (struct mxcfb_info *)info->par; struct mxcfb_info *fg_mxcfbi = NULL; + acquire_console_sem(); /* swap only happen between DP-BG and DC, while DP-FG disable */ if (((mxcfbi->ipu_ch == MEM_BG_SYNC) && (strstr(buf, "1-layer-fb") != NULL)) || @@ -1451,17 +1572,16 @@ static ssize_t swap_disp_chan(struct device *dev, int i; for (i = 0; i < num_registered_fb; i++) { - fg_mxcfbi = - (struct mxcfb_info *)mxcfb_info[i]->par; + fg_mxcfbi = (struct mxcfb_info *)mxcfb_info[i]->par; if (fg_mxcfbi->ipu_ch == MEM_FG_SYNC) break; else fg_mxcfbi = NULL; } - if (!fg_mxcfbi || - fg_mxcfbi->cur_blank == FB_BLANK_UNBLANK) { + if (!fg_mxcfbi || fg_mxcfbi->cur_blank == FB_BLANK_UNBLANK) { dev_err(dev, "Can not switch while fb2(fb-fg) is on.\n"); + release_console_sem(); return count; } @@ -1469,8 +1589,10 @@ static ssize_t swap_disp_chan(struct device *dev, dev_err(dev, "Swap display channel failed.\n"); } + release_console_sem(); return count; } + DEVICE_ATTR(fsl_disp_property, 644, show_disp_chan, swap_disp_chan); /*! @@ -1487,6 +1609,8 @@ static int mxcfb_probe(struct platform_device *pdev) struct mxcfb_info *mxcfbi; struct mxc_fb_platform_data *plat_data = pdev->dev.platform_data; struct resource *res; + char *options, *mstr; + char name[] = "mxcdi0fb"; int ret = 0; /* @@ -1499,6 +1623,13 @@ static int mxcfb_probe(struct platform_device *pdev) } mxcfbi = (struct mxcfb_info *)fbi->par; + name[5] += pdev->id; + if (fb_get_options(name, &options)) + return -ENODEV; + + if (options) + mxcfb_option_setup(fbi, options); + if (!g_dp_in_use) { mxcfbi->ipu_ch_irq = IPU_IRQ_BG_SYNC_EOF; mxcfbi->ipu_ch = MEM_BG_SYNC; @@ -1521,7 +1652,7 @@ static int mxcfb_probe(struct platform_device *pdev) mxcfb_alpha_irq_handler, 0, MXCFB_NAME, fbi) != 0) { dev_err(&pdev->dev, "Error registering BG " - "alpha irq handler.\n"); + "alpha irq handler.\n"); ret = -EBUSY; goto err1; } @@ -1534,7 +1665,7 @@ static int mxcfb_probe(struct platform_device *pdev) mxcfb_alpha_irq_handler, 0, MXCFB_NAME, fbi) != 0) { dev_err(&pdev->dev, "Error registering BG " - "alpha irq handler.\n"); + "alpha irq handler.\n"); ret = -EBUSY; goto err1; } @@ -1552,7 +1683,7 @@ static int mxcfb_probe(struct platform_device *pdev) mxcfb_alpha_irq_handler, 0, MXCFB_NAME, fbi) != 0) { dev_err(&pdev->dev, "Error registering FG alpha irq " - "handler.\n"); + "handler.\n"); ret = -EBUSY; goto err1; } @@ -1572,31 +1703,63 @@ static int mxcfb_probe(struct platform_device *pdev) if (res && res->end) { fbi->fix.smem_len = res->end - res->start + 1; fbi->fix.smem_start = res->start; - fbi->screen_base = ioremap(fbi->fix.smem_start, fbi->fix.smem_len); + fbi->screen_base = + ioremap(fbi->fix.smem_start, fbi->fix.smem_len); } /* Need dummy values until real panel is configured */ fbi->var.xres = 240; fbi->var.yres = 320; - if (!fb_mode && plat_data && plat_data->mode_str) - fb_find_mode(&fbi->var, fbi, plat_data->mode_str, NULL, 0, NULL, - default_bpp); - - if (fb_mode) - fb_find_mode(&fbi->var, fbi, fb_mode, NULL, 0, NULL, - default_bpp); + if (!mxcfbi->default_bpp) +#ifdef CONFIG_CCWMX51_DEFAULT_VIDEO_BPP + mxcfbi->default_bpp = CONFIG_CCWMX51_DEFAULT_VIDEO_BPP; +#else + mxcfbi->default_bpp = 16; +#endif - if (plat_data) { + if (plat_data && !mxcfbi->ipu_di_pix_fmt) mxcfbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt; - if (!fb_mode && plat_data->mode) - fb_videomode_to_var(&fbi->var, plat_data->mode); + + if (plat_data && plat_data->mode && plat_data->num_modes) + fb_videomode_to_modelist(plat_data->mode, plat_data->num_modes, + &fbi->modelist); + + if (!mxcfbi->fb_mode_str && plat_data && plat_data->mode_str) + mxcfbi->fb_mode_str = plat_data->mode_str; + + if (mxcfbi->fb_mode_str) { + +#ifdef CONFIG_MODULE_CCXMX51 + if ((mstr = strstr(mxcfbi->fb_mode_str, "VGA@")) != NULL) + mxcfbi->fb_mode_str = mstr + 4; +#endif + + ret = + fb_find_mode(&fbi->var, fbi, mxcfbi->fb_mode_str, NULL, 0, + NULL, mxcfbi->default_bpp); + if ((!ret || (ret > 2)) && plat_data && plat_data->mode + && plat_data->num_modes) + fb_find_mode(&fbi->var, fbi, mxcfbi->fb_mode_str, + plat_data->mode, plat_data->num_modes, + NULL, mxcfbi->default_bpp); + +#ifdef CONFIG_MODULE_CCXMX51 + /* This improves the VGA modes on the CCWi-i.MX51 */ + if (mstr != NULL) { + mxcfbi->ipu_ext_clk = true; + fbi->var.sync |= FB_SYNC_CLK_LAT_FALL; + } +#endif } mxcfb_check_var(&fbi->var, fbi); + pm_set_vt_switch(vt_switch); + /* Default Y virtual size is 2x panel size */ - fbi->var.yres_virtual = fbi->var.yres * 3; + fbi->var.yres_virtual = ((fbi->var.yres + 127) & ~127) * 2; + fbi->var.xres_virtual = (fbi->var.xres + 31) & ~31; mxcfb_set_fix(fbi); @@ -1617,12 +1780,12 @@ static int mxcfb_probe(struct platform_device *pdev) return 0; -err2: + err2: ipu_free_irq(mxcfbi->ipu_ch_irq, fbi); -err1: + err1: fb_dealloc_cmap(&fbi->cmap); framebuffer_release(fbi); -err0: + err0: return ret; } @@ -1655,38 +1818,108 @@ static struct platform_driver mxcfb_driver = { }, .probe = mxcfb_probe, .remove = mxcfb_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND .suspend = mxcfb_suspend, .resume = mxcfb_resume, +#endif }; /* * Parse user specified options (`video=trident:') * example: - * video=trident:800x600,bpp=16,noaccel + * video=mxcdi0fb:RGB24, 1024x768M-16@60,bpp=16,noaccel */ -int mxcfb_setup(char *options) +static int mxcfb_option_setup(struct fb_info *info, char *options) { + struct mxcfb_info *mxcfbi = info->par; char *opt; + if (!options || !*options) return 0; + while ((opt = strsep(&options, ",")) != NULL) { if (!*opt) continue; + + if (!strncmp(opt, "RGB24", 5)) { + mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_RGB24; + continue; + } + if (!strncmp(opt, "BGR24", 5)) { + mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_BGR24; + continue; + } + if (!strncmp(opt, "RGB565", 6)) { + mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_RGB565; + continue; + } + if (!strncmp(opt, "RGB666", 6)) { + mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_RGB666; + continue; + } + if (!strncmp(opt, "YUV444", 6)) { + mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_YUV444; + continue; + } + if (!strncmp(opt, "LVDS666", 7)) { + mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_LVDS666; + continue; + } + if (!strncmp(opt, "YUYV16", 6)) { + mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_YUYV; + continue; + } + if (!strncmp(opt, "UYVY16", 6)) { + mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_UYVY; + continue; + } + if (!strncmp(opt, "YVYU16", 6)) { + mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_YVYU; + continue; + } + if (!strncmp(opt, "VYUY16", 6)) { + mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_VYUY; + continue; + } if (!strncmp(opt, "ext_clk", 7)) { - ext_clk_used = true; + mxcfbi->ipu_ext_clk = true; continue; - } else - ext_clk_used = false; - + } if (!strncmp(opt, "bpp=", 4)) - default_bpp = simple_strtoul(opt + 4, NULL, 0); + mxcfbi->default_bpp = simple_strtoul(opt + 4, NULL, 0); else - fb_mode = opt; - + mxcfbi->fb_mode_str = opt; } + return 0; } +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mxcfb_early_suspend(struct early_suspend *h) +{ + int i; + for (i = FB_DEVICE_NUM - 1; i >= 0; i--) { + if (mxcfb_info[i]) + mxcfb_suspend_one(mxcfb_info[i]); + } +} + +static void mxcfb_later_resume(struct early_suspend *h) +{ + int i; + for (i = 0; i < FB_DEVICE_NUM; i++) { + if (mxcfb_info[i]) + mxcfb_resume_one(mxcfb_info[i]); + } +} + +struct early_suspend fbdrv_earlysuspend = { + .level = EARLY_SUSPEND_LEVEL_DISABLE_FB, + .suspend = mxcfb_early_suspend, + .resume = mxcfb_later_resume, +}; +#endif + /*! * Main entry function for the framebuffer. The function registers the power * management callback functions with the kernel and also registers the MXCFB @@ -1696,26 +1929,23 @@ int mxcfb_setup(char *options) */ int __init mxcfb_init(void) { - int ret = 0; -#ifndef MODULE - char *option = NULL; -#endif - -#ifndef MODULE - if (fb_get_options("mxcfb", &option)) - return -ENODEV; - mxcfb_setup(option); -#endif + int ret; ret = platform_driver_register(&mxcfb_driver); + if (!ret) + register_early_suspend(&fbdrv_earlysuspend); return ret; } void mxcfb_exit(void) { + unregister_early_suspend(&fbdrv_earlysuspend); platform_driver_unregister(&mxcfb_driver); } +module_param(vt_switch, int, 0); +MODULE_PARM_DESC(vt_switch, "enable VT switch during suspend/resume"); + module_init(mxcfb_init); module_exit(mxcfb_exit); diff --git a/drivers/video/mxc/mxcfb_claa_wvga.c b/drivers/video/mxc/mxcfb_claa_wvga.c index bd5ff7b83f8c..8f696c19e7d9 100644 --- a/drivers/video/mxc/mxcfb_claa_wvga.c +++ b/drivers/video/mxc/mxcfb_claa_wvga.c @@ -48,8 +48,8 @@ static int lcd_on; static struct fb_videomode video_modes[] = { { - /* 800x480 @ 55 Hz , pixel clk @ 25MHz */ - "CLAA-WVGA", 55, 800, 480, 40000, 40, 40, 5, 5, 20, 10, + /* 800x480 @ 57 Hz , pixel clk @ 27MHz */ + "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10, FB_SYNC_CLK_LAT_FALL, FB_VMODE_NONINTERLACED, 0,}, @@ -77,13 +77,14 @@ static int lcd_fb_event(struct notifier_block *nb, unsigned long val, void *v) { struct fb_event *event = v; - if (strcmp(event->info->fix.id, "DISP3 BG")) { + if (strcmp(event->info->fix.id, "DISP3 BG") && + strcmp(event->info->fix.id, "mxc_elcdif_fb")) return 0; - } switch (val) { case FB_EVENT_FB_REGISTERED: lcd_init_fb(event->info); + fb_show_logo(event->info, 0); lcd_poweron(); break; case FB_EVENT_BLANK: @@ -133,7 +134,8 @@ static int __devinit lcd_probe(struct platform_device *pdev) } for (i = 0; i < num_registered_fb; i++) { - if (strcmp(registered_fb[i]->fix.id, "DISP3 BG") == 0) { + if (strcmp(registered_fb[i]->fix.id, "DISP3 BG") == 0 || + strcmp(registered_fb[i]->fix.id, "mxc_elcdif_fb") == 0) { lcd_init_fb(registered_fb[i]); fb_show_logo(registered_fb[i], 0); lcd_poweron(); diff --git a/drivers/video/mxc/tve.c b/drivers/video/mxc/tve.c index 2d2929c0cbd9..793b470cdce4 100644 --- a/drivers/video/mxc/tve.c +++ b/drivers/video/mxc/tve.c @@ -68,6 +68,8 @@ static int enabled; /* enable power on or not */ DEFINE_SPINLOCK(tve_lock); static struct fb_info *tve_fbi; +static struct fb_modelist tve_modelist; +static bool g_enable_tve; struct tve_data { struct platform_device *pdev; @@ -77,6 +79,7 @@ struct tve_data { int detect; void *base; int irq; + int blank; struct clk *clk; struct regulator *dac_reg; struct regulator *dig_reg; @@ -221,40 +224,50 @@ static int _is_tvout_mode_hd_compatible(void) static int tve_setup(int mode) { u32 reg; - struct clk *pll3_clk; - unsigned long pll3_clock_rate = 216000000, di1_clock_rate = 27000000; + struct clk *tve_parent_clk; + unsigned long parent_clock_rate = 216000000, di1_clock_rate = 27000000; + unsigned long tve_clock_rate = 216000000; struct clk *ipu_di1_clk; unsigned long lock_flags; - if (tve.cur_mode == mode) - return 0; - spin_lock_irqsave(&tve_lock, lock_flags); - tve.cur_mode = mode; - switch (mode) { case TVOUT_FMT_PAL: case TVOUT_FMT_NTSC: - pll3_clock_rate = 216000000; + parent_clock_rate = 216000000; di1_clock_rate = 27000000; break; case TVOUT_FMT_720P60: - pll3_clock_rate = 297000000; + parent_clock_rate = 297000000; + if (cpu_is_mx53()) + tve_clock_rate = 297000000; di1_clock_rate = 74250000; break; } if (enabled) clk_disable(tve.clk); - pll3_clk = clk_get(NULL, "pll3"); + tve_parent_clk = clk_get_parent(tve.clk); ipu_di1_clk = clk_get(NULL, "ipu_di1_clk"); - clk_disable(pll3_clk); - clk_set_rate(pll3_clk, pll3_clock_rate); - clk_set_rate(ipu_di1_clk, di1_clock_rate); + clk_disable(tve_parent_clk); + clk_set_rate(tve_parent_clk, parent_clock_rate); + + if (cpu_is_mx53()) + clk_set_rate(tve.clk, tve_clock_rate); clk_enable(tve.clk); + clk_set_rate(ipu_di1_clk, di1_clock_rate); + + if (tve.cur_mode == mode) { + if (!enabled) + clk_disable(tve.clk); + spin_unlock_irqrestore(&tve_lock, lock_flags); + return 0; + } + + tve.cur_mode = mode; /* select output video format */ if (mode == TVOUT_FMT_PAL) { @@ -497,6 +510,14 @@ static irqreturn_t tve_detect_handler(int irq, void *data) return IRQ_HANDLED; } +/* Re-construct clk for tve display */ +static inline void tve_recfg_fb(struct fb_info *fbi) +{ + fbi->flags &= ~FBINFO_MISC_USEREVENT; + fbi->var.activate |= FB_ACTIVATE_FORCE; + fb_set_var(fbi, &fbi->var); +} + int tve_fb_event(struct notifier_block *nb, unsigned long val, void *v) { struct fb_event *event = v; @@ -509,9 +530,9 @@ int tve_fb_event(struct notifier_block *nb, unsigned long val, void *v) break; tve_fbi = fbi; - fb_add_videomode(&video_modes[0], &tve_fbi->modelist); - fb_add_videomode(&video_modes[1], &tve_fbi->modelist); - fb_add_videomode(&video_modes[2], &tve_fbi->modelist); + fb_add_videomode(&video_modes[0], &tve_modelist.list); + fb_add_videomode(&video_modes[1], &tve_modelist.list); + fb_add_videomode(&video_modes[2], &tve_modelist.list); break; case FB_EVENT_MODE_CHANGE: { @@ -525,7 +546,7 @@ int tve_fb_event(struct notifier_block *nb, unsigned long val, void *v) fb_var_to_videomode(&cur_mode, &fbi->var); - list_for_each(pos, &tve_fbi->modelist) { + list_for_each(pos, &tve_modelist.list) { modelist = list_entry(pos, struct fb_modelist, list); mode = &modelist->mode; if (fb_mode_is_equal(&cur_mode, mode)) { @@ -564,31 +585,33 @@ int tve_fb_event(struct notifier_block *nb, unsigned long val, void *v) return 0; if (*((int *)event->data) == FB_BLANK_UNBLANK) { - if (fb_mode_is_equal(fbi->mode, &video_modes[0])) { - if (tve.cur_mode != TVOUT_FMT_NTSC) { + if (tve.blank != FB_BLANK_UNBLANK) { + if (fb_mode_is_equal(fbi->mode, &video_modes[0])) { tve_disable(); tve_setup(TVOUT_FMT_NTSC); - } - tve_enable(); - } else if (fb_mode_is_equal(fbi->mode, - &video_modes[1])) { - if (tve.cur_mode != TVOUT_FMT_PAL) { + tve_enable(); + tve_recfg_fb(fbi); + } else if (fb_mode_is_equal(fbi->mode, + &video_modes[1])) { tve_disable(); tve_setup(TVOUT_FMT_PAL); - } - tve_enable(); - } else if (fb_mode_is_equal(fbi->mode, - &video_modes[2])) { - if (tve.cur_mode != TVOUT_FMT_720P60) { + tve_enable(); + tve_recfg_fb(fbi); + } else if (fb_mode_is_equal(fbi->mode, + &video_modes[2])) { tve_disable(); tve_setup(TVOUT_FMT_720P60); + tve_enable(); + tve_recfg_fb(fbi); + } else { + tve_setup(TVOUT_FMT_OFF); } - tve_enable(); - } else { - tve_setup(TVOUT_FMT_OFF); + tve.blank = FB_BLANK_UNBLANK; } - } else + } else { tve_disable(); + tve.blank = FB_BLANK_POWERDOWN; + } break; } return 0; @@ -652,6 +675,11 @@ static int tve_probe(struct platform_device *pdev) struct tve_platform_data *plat_data = pdev->dev.platform_data; u32 conf_reg; + if (g_enable_tve == false) + return -ENODEV; + + INIT_LIST_HEAD(&tve_modelist.list); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) return -ENOMEM; @@ -699,9 +727,9 @@ static int tve_probe(struct platform_device *pdev) } if (tve_fbi != NULL) { - fb_add_videomode(&video_modes[0], &tve_fbi->modelist); - fb_add_videomode(&video_modes[1], &tve_fbi->modelist); - fb_add_videomode(&video_modes[2], &tve_fbi->modelist); + fb_add_videomode(&video_modes[0], &tve_modelist.list); + fb_add_videomode(&video_modes[1], &tve_modelist.list); + fb_add_videomode(&video_modes[2], &tve_modelist.list); } tve.dac_reg = regulator_get(&pdev->dev, plat_data->dac_reg); @@ -748,22 +776,40 @@ static int tve_probe(struct platform_device *pdev) clk_disable(tve.clk); + ret = fb_register_client(&nb); + if (ret < 0) + goto err2; + + tve.blank = -1; + /* is primary display? */ if (primary) { - struct fb_event event; + struct fb_var_screeninfo var; + const struct fb_videomode *mode; + + memset(&var, 0, sizeof(var)); + mode = fb_match_mode(&tve_fbi->var, &tve_modelist.list); + if (mode) { + pr_debug("TVE: fb mode found\n"); + fb_videomode_to_var(&var, mode); + } else { + pr_warning("TVE: can not find video mode\n"); + goto done; + } + acquire_console_sem(); + tve_fbi->flags |= FBINFO_MISC_USEREVENT; + fb_set_var(tve_fbi, &var); + tve_fbi->flags &= ~FBINFO_MISC_USEREVENT; + release_console_sem(); - event.info = tve_fbi; - tve_fb_event(NULL, FB_EVENT_MODE_CHANGE, &event); acquire_console_sem(); fb_blank(tve_fbi, FB_BLANK_UNBLANK); release_console_sem(); + fb_show_logo(tve_fbi, 0); } - ret = fb_register_client(&nb); - if (ret < 0) - goto err2; - +done: return 0; err2: device_remove_file(&pdev->dev, &dev_attr_headphone); @@ -842,6 +888,14 @@ static struct platform_driver tve_driver = { .resume = tve_resume, }; +static int __init enable_tve_setup(char *options) +{ + g_enable_tve = true; + + return 1; +} +__setup("tve", enable_tve_setup); + static int __init tve_init(void) { return platform_driver_register(&tve_driver); diff --git a/drivers/video/mxs/Kconfig b/drivers/video/mxs/Kconfig index aef4aa59dcad..35b896e95d4f 100644 --- a/drivers/video/mxs/Kconfig +++ b/drivers/video/mxs/Kconfig @@ -20,3 +20,9 @@ config FB_MXS_LCD_LMS430 default y if ARCH_MX23 ---help--- Use LMS430 dotclock LCD panel for MXS + +config FB_MXS_TVENC + depends on ARCH_MXS + bool "TVENC" + ---help--- + Use TVOUT encoder for MXS diff --git a/drivers/video/mxs/Makefile b/drivers/video/mxs/Makefile index a9580add3757..fbab953718c7 100644 --- a/drivers/video/mxs/Makefile +++ b/drivers/video/mxs/Makefile @@ -2,3 +2,5 @@ obj-$(CONFIG_ARCH_MXS) += lcdif.o obj-$(CONFIG_FB_MXS) += mxsfb.o obj-$(CONFIG_FB_MXS_LCD_43WVF1G) += lcd_43wvf1g.o obj-$(CONFIG_FB_MXS_LCD_LMS430) += lcd_lms430.o +# TVOUT support +obj-$(CONFIG_FB_MXS_TVENC) += tvenc.o diff --git a/drivers/watchdog/mxc_wdt.c b/drivers/watchdog/mxc_wdt.c index 3626a51e557d..0114fab70253 100644 --- a/drivers/watchdog/mxc_wdt.c +++ b/drivers/watchdog/mxc_wdt.c @@ -200,7 +200,7 @@ mxc_wdt_ioctl(struct inode *inode, struct file *file, switch (cmd) { default: - return -ENOIOCTLCMD; + return -ENOTTY; case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info __user *)arg, &ident, sizeof(ident)); diff --git a/firmware/Makefile b/firmware/Makefile index 621de8e952f7..19d80a6cc763 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -110,6 +110,8 @@ fw-shipped-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda/xircom_pgs.fw fw-shipped-$(CONFIG_USB_VICAM) += vicam/firmware.fw fw-shipped-$(CONFIG_VIDEO_CPIA2) += cpia2/stv0672_vp4.bin fw-shipped-$(CONFIG_YAM) += yam/1200.bin yam/9600.bin +fw-shipped-$(CONFIG_FB_MXC_EINK_PANEL) += imx/epdc_E60.fw \ + imx/epdc_E97.fw fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-) diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 530b4ca01510..4ceff5110417 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -758,6 +758,13 @@ static int fat_ioctl_readdir(struct inode *inode, struct file *filp, return ret; } +static int fat_ioctl_volume_id(struct inode *dir) +{ + struct super_block *sb = dir->i_sb; + struct msdos_sb_info *sbi = MSDOS_SB(sb); + return sbi->vol_id; +} + static int fat_dir_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -773,6 +780,8 @@ static int fat_dir_ioctl(struct inode *inode, struct file *filp, short_only = 0; both = 1; break; + case VFAT_IOCTL_GET_VOLUME_ID: + return fat_ioctl_volume_id(inode); default: return fat_generic_ioctl(inode, filp, cmd, arg); } diff --git a/fs/fat/fat.h b/fs/fat/fat.h index adb0e72a176d..09305185330f 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -76,6 +76,7 @@ struct msdos_sb_info { const void *dir_ops; /* Opaque; default directory operations */ int dir_per_block; /* dir entries per block */ int dir_per_block_bits; /* log2(dir_per_block) */ + unsigned long vol_id; /* volume ID */ int fatent_shift; struct fatent_operations *fatent_ops; diff --git a/fs/partitions/check.c b/fs/partitions/check.c index ea4e6cb29e13..5ff78a202e0a 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -317,10 +317,19 @@ static void part_release(struct device *dev) kfree(p); } +static int part_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct hd_struct *part = dev_to_part(dev); + + add_uevent_var(env, "PARTN=%u", part->partno); + return 0; +} + struct device_type part_type = { .name = "partition", .groups = part_attr_groups, .release = part_release, + .uevent = part_uevent, }; static void delete_partition_rcu_cb(struct rcu_head *head) diff --git a/fs/proc/base.c b/fs/proc/base.c index 6f742f6658a9..a0f94952faf2 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -127,6 +127,8 @@ struct pid_entry { NOD(NAME, (S_IFREG|(MODE)), \ NULL, &proc_single_file_operations, \ { .proc_show = show } ) +#define ARD(NAME, MODE, iops, fops) \ + NOD(NAME, (S_IFREG|(MODE)), &iops, &fops, {} ) /* * Count the number of hardlinks for the pid_entry table, excluding the . @@ -1043,6 +1045,35 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, return end - buffer; } +#ifdef CONFIG_ANDROID +static int oom_adjust_permission(struct inode *inode, int mask) +{ + uid_t uid; + struct task_struct *p = get_proc_task(inode); + if(p) { + uid = task_uid(p); + put_task_struct(p); + } + + /* + * System Server (uid == 1000) is granted access to oom_adj of all + * android applications (uid > 10000) as and services (uid >= 1000) + */ + if (p && (current_fsuid() == 1000) && (uid >= 1000)) { + if (inode->i_mode >> 6 & mask) { + return 0; + } + } + + /* Fall back to default. */ + return generic_permission(inode, mask, NULL); +} + +static const struct inode_operations proc_oom_adjust_inode_operations = { + .permission = oom_adjust_permission, +}; +#endif + static const struct file_operations proc_oom_adjust_operations = { .read = oom_adjust_read, .write = oom_adjust_write, @@ -2531,7 +2562,11 @@ static const struct pid_entry tgid_base_stuff[] = { REG("cgroup", S_IRUGO, proc_cgroup_operations), #endif INF("oom_score", S_IRUGO, proc_oom_score), +#ifndef CONFIG_ANDROID REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_operations), +#else + ARD("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_inode_operations, proc_oom_adjust_operations), +#endif #ifdef CONFIG_AUDITSYSCALL REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), REG("sessionid", S_IRUGO, proc_sessionid_operations), diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 9bd8be1d235c..07376a4a3ed1 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -689,8 +689,6 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, down_read(¤t->mm->mmap_sem); ret = get_user_pages(current, current->mm, uaddr, pagecount, 1, 0, pages, NULL); - up_read(¤t->mm->mmap_sem); - if (ret < 0) goto out_free; @@ -739,6 +737,7 @@ out_pages: page_cache_release(page); } out_free: + up_read(¤t->mm->mmap_sem); kfree(pages); out_mm: mmput(mm); diff --git a/include/linux/Kbuild b/include/linux/Kbuild index a062aa3e2525..a9ad1f14f927 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -385,6 +385,7 @@ unifdef-y += mxc_mlb.h unifdef-y += mxc_pf.h unifdef-y += mxc_scc2_driver.h unifdef-y += mxc_scc_driver.h +unifdef-y += mxc_srtc.h unifdef-y += mxc_si4702.h unifdef-y += mxc_sim_interface.h unifdef-y += mxc_v4l2.h @@ -396,6 +397,7 @@ unifdef-y += pmic_light.h unifdef-y += pmic_rtc.h unifdef-y += pmic_status.h unifdef-y += soundcard.h +unifdef-y += pxp_dma.h objhdr-y += version.h header-y += wimax.h diff --git a/include/linux/ata.h b/include/linux/ata.h index 9c75921f0c16..f5494050df83 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -306,6 +306,7 @@ enum { /* SETFEATURE Sector counts for SATA features */ SATA_AN = 0x05, /* Asynchronous Notification */ SATA_DIPM = 0x03, /* Device Initiated Power Management */ + SATA_FPDMA_AA = 0x02, /* DMA Setup FIS Auto-Activate */ /* feature values for SET_MAX */ ATA_SET_MAX_ADDR = 0x00, @@ -525,6 +526,9 @@ static inline int ata_is_data(u8 prot) #define ata_id_has_atapi_AN(id) \ ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \ ((id)[78] & (1 << 5)) ) +#define ata_id_has_fpdma_aa(id) \ + ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \ + ((id)[78] & (1 << 2)) ) #define ata_id_iordy_disable(id) ((id)[ATA_ID_CAPABILITY] & (1 << 10)) #define ata_id_has_iordy(id) ((id)[ATA_ID_CAPABILITY] & (1 << 11)) #define ata_id_u32(id,n) \ diff --git a/include/linux/fec.h b/include/linux/fec.h index 2ad61317d32b..39ba482298e1 100644 --- a/include/linux/fec.h +++ b/include/linux/fec.h @@ -13,13 +13,34 @@ #ifndef __LINUX_FEC_H__ #define __LINUX_FEC_H__ +#include <linux/etherdevice.h> #include <linux/phy.h> struct fec_platform_data { phy_interface_t phy; + unsigned int phy_mask; + unsigned char mac[ETH_ALEN]; int (*init)(void); int (*uninit)(void); struct regulator *vddio_reg; }; +struct switch_platform_data { + int id; + int hash_table; + unsigned int *switch_hw; + struct fec_platform_data *fec_enet; + void (*request_intrs)(struct net_device *dev, + irqreturn_t (*)(int, void *), + void *irq_privatedata); + void (*set_mii)(struct net_device *dev); + void (*get_mac)(struct net_device *dev); + void (*enable_phy_intr)(void); + void (*disable_phy_intr)(void); + void (*phy_ack_intr)(void); + void (*localhw_setup)(void); + void (*uncache)(unsigned long addr); + void (*platform_flush_cache)(void); +}; + #endif diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 30a7ca46fa35..8ee3006f4678 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -93,6 +93,8 @@ struct fsl_usb2_platform_data { void (*platform_suspend)(struct fsl_usb2_platform_data *); void (*platform_resume)(struct fsl_usb2_platform_data *); void (*wake_up_enable)(struct fsl_usb2_platform_data *pdata, bool on); + void (*phy_lowpower_suspend)(bool); + void (*platform_driver_vbus)(bool on); /* platform special function for vbus shutdown/open */ unsigned big_endian_mmio : 1; unsigned big_endian_desc : 1; unsigned es : 1; /* need USBMODE:ES */ diff --git a/include/linux/ipu.h b/include/linux/ipu.h index 5a03856b1ac3..54a889b57f73 100644 --- a/include/linux/ipu.h +++ b/include/linux/ipu.h @@ -121,6 +121,8 @@ typedef enum { /*! @{ */ #define IPU_PIX_FMT_YUYV fourcc('Y', 'U', 'Y', 'V') /*!< 16 YUV 4:2:2 */ #define IPU_PIX_FMT_UYVY fourcc('U', 'Y', 'V', 'Y') /*!< 16 YUV 4:2:2 */ +#define IPU_PIX_FMT_YVYU fourcc('Y', 'V', 'Y', 'U') /*!< 16 YVYU 4:2:2 */ +#define IPU_PIX_FMT_VYUY fourcc('V', 'Y', 'U', 'Y') /*!< 16 VYYU 4:2:2 */ #define IPU_PIX_FMT_Y41P fourcc('Y', '4', '1', 'P') /*!< 12 YUV 4:1:1 */ #define IPU_PIX_FMT_YUV444 fourcc('Y', '4', '4', '4') /*!< 24 YUV 4:4:4 */ /* two planes -- one Y, one Cb + Cr interleaved */ @@ -321,7 +323,8 @@ typedef union { uint32_t out_width; uint32_t out_height; uint32_t out_pixel_fmt; - uint32_t out_resize_ratio; + uint32_t outh_resize_ratio; + uint32_t outv_resize_ratio; } mem_prp_enc_mem; struct { uint32_t in_width; @@ -364,7 +367,8 @@ typedef union { uint32_t out_width; uint32_t out_height; uint32_t out_pixel_fmt; - uint32_t out_resize_ratio; + uint32_t outh_resize_ratio; + uint32_t outv_resize_ratio; bool graphics_combine_en; bool global_alpha_en; bool key_color_en; @@ -388,7 +392,8 @@ typedef union { uint32_t out_width; uint32_t out_height; uint32_t out_pixel_fmt; - uint32_t out_resize_ratio; + uint32_t outh_resize_ratio; + uint32_t outv_resize_ratio; bool graphics_combine_en; bool global_alpha_en; bool key_color_en; @@ -420,6 +425,8 @@ typedef union { struct { uint32_t di; bool interlaced; + uint32_t in_pixel_fmt; + uint32_t out_pixel_fmt; } mem_dc_sync; struct { uint32_t temp; @@ -604,6 +611,9 @@ enum ipu_irq_line { IPU_IRQ_CSI1_OUT_EOF = 1, IPU_IRQ_CSI2_OUT_EOF = 2, IPU_IRQ_CSI3_OUT_EOF = 3, + IPU_IRQ_VDI_P_IN_EOF = 8, + IPU_IRQ_VDI_C_IN_EOF = 9, + IPU_IRQ_VDI_N_IN_EOF = 10, IPU_IRQ_PP_IN_EOF = 11, IPU_IRQ_PRP_IN_EOF = 12, IPU_IRQ_PRP_GRAPH_IN_EOF = 14, @@ -895,6 +905,8 @@ int32_t ipu_link_channels(ipu_channel_t src_ch, ipu_channel_t dest_ch); int32_t ipu_unlink_channels(ipu_channel_t src_ch, ipu_channel_t dest_ch); int32_t ipu_is_channel_busy(ipu_channel_t channel); +int32_t ipu_check_buffer_busy(ipu_channel_t channel, ipu_buffer_t type, + uint32_t bufNum); void ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type, uint32_t bufNum); uint32_t ipu_get_cur_buffer_idx(ipu_channel_t channel, ipu_buffer_t type); @@ -944,6 +956,8 @@ int32_t ipu_init_sync_panel(int disp, int32_t ipu_disp_set_window_pos(ipu_channel_t channel, int16_t x_pos, int16_t y_pos); +int32_t ipu_disp_get_window_pos(ipu_channel_t channel, int16_t *x_pos, + int16_t *y_pos); int32_t ipu_disp_set_global_alpha(ipu_channel_t channel, bool enable, uint8_t alpha); int32_t ipu_disp_set_color_key(ipu_channel_t channel, bool enable, @@ -1260,6 +1274,7 @@ typedef struct _ipu_csc_update { #define IPU_CALC_STRIPES_SIZE _IOWR('I', 0x27, ipu_stripe_parm) #define IPU_UPDATE_BUF_OFFSET _IOW('I', 0x28, ipu_buf_offset_parm) #define IPU_CSC_UPDATE _IOW('I', 0x29, ipu_csc_update) +#define IPU_SELECT_MULTI_VDI_BUFFER _IOW('I', 0x2A, uint32_t) int ipu_calc_stripes_sizes(const unsigned int input_frame_width, unsigned int output_frame_width, diff --git a/include/linux/libata.h b/include/linux/libata.h index e5b6e33c6571..d3f7cab4873e 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -190,6 +190,7 @@ enum { ATA_FLAG_NO_POWEROFF_SPINDOWN = (1 << 11), /* don't spindown before poweroff */ ATA_FLAG_NO_HIBERNATE_SPINDOWN = (1 << 12), /* don't spindown before hibernation */ ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_FPDMA_AA = (1 << 14), /* driver supports Auto-Activate */ ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */ ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */ ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */ @@ -386,6 +387,7 @@ enum { ATA_HORKAGE_FIRMWARE_WARN = (1 << 12), /* firmware update warning */ ATA_HORKAGE_1_5_GBPS = (1 << 13), /* force 1.5 Gbps */ ATA_HORKAGE_NOSETXFER = (1 << 14), /* skip SETXFER, SATA only */ + ATA_HORKAGE_BROKEN_FPDMA_AA = (1 << 15), /* skip AA */ /* DMA mask for user DMA control: User visible values; DO NOT renumber */ diff --git a/include/linux/mm.h b/include/linux/mm.h index 9a72cc78e6b8..291bc1c9d0ed 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -710,6 +710,7 @@ static inline int shmem_lock(struct file *file, int lock, } #endif struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags); +void shmem_set_file(struct vm_area_struct *vma, struct file *file); int shmem_zero_setup(struct vm_area_struct *); diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 403aa505f27e..9167c389779e 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -40,8 +40,16 @@ struct mmc_csd { }; struct mmc_ext_csd { + u8 rev; + unsigned int sa_timeout; /* Units: 100ns */ unsigned int hs_max_dtr; unsigned int sectors; + unsigned int card_type; +#define MMC_DDR_MODE_MASK (0x3<<2) + unsigned char boot_info; + unsigned char boot_size_mult; + unsigned char boot_config; + unsigned char boot_bus_width; }; struct sd_scr { diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 7ac8b500d55c..e4898e9eeb59 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -139,6 +139,7 @@ extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int); extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort); extern void mmc_release_host(struct mmc_host *host); +extern int mmc_try_claim_host(struct mmc_host *host); /** * mmc_claim_host - exclusively claim a host diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 3e7615e9087e..289c17d3e705 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -13,6 +13,7 @@ #include <linux/leds.h> #include <linux/mmc/core.h> +#include <linux/mmc/pm.h> struct mmc_ios { unsigned int clock; /* clock rate */ @@ -42,6 +43,7 @@ struct mmc_ios { #define MMC_BUS_WIDTH_1 0 #define MMC_BUS_WIDTH_4 2 #define MMC_BUS_WIDTH_8 3 +#define MMC_BUS_WIDTH_DDR 8 unsigned char timing; /* timing specification used */ @@ -51,6 +53,35 @@ struct mmc_ios { }; struct mmc_host_ops { + /* + * Hosts that support power saving can use the 'enable' and 'disable' + * methods to exit and enter power saving states. 'enable' is called + * when the host is claimed and 'disable' is called (or scheduled with + * a delay) when the host is released. The 'disable' is scheduled if + * the disable delay set by 'mmc_set_disable_delay()' is non-zero, + * otherwise 'disable' is called immediately. 'disable' may be + * scheduled repeatedly, to permit ever greater power saving at the + * expense of ever greater latency to re-enable. Rescheduling is + * determined by the return value of the 'disable' method. A positive + * value gives the delay in milliseconds. + * + * In the case where a host function (like set_ios) may be called + * with or without the host claimed, enabling and disabling can be + * done directly and will nest correctly. Call 'mmc_host_enable()' and + * 'mmc_host_lazy_disable()' for this purpose, but note that these + * functions must be paired. + * + * Alternatively, 'mmc_host_enable()' may be paired with + * 'mmc_host_disable()' which calls 'disable' immediately. In this + * case the 'disable' method will be called with 'lazy' set to 0. + * This is mainly useful for error paths. + * + * Because lazy disable may be called from a work queue, the 'disable' + * method must claim the host when 'lazy' != 0, which will work + * correctly because recursion is detected and handled. + */ + int (*enable)(struct mmc_host *host); + int (*disable)(struct mmc_host *host, int lazy); void (*request)(struct mmc_host *host, struct mmc_request *req); /* * Avoid calling these three functions too often or in a "fast path", @@ -90,6 +121,7 @@ struct mmc_host { unsigned int f_min; unsigned int f_max; u32 ocr_avail; + struct notifier_block pm_notify; #define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */ #define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */ @@ -118,6 +150,12 @@ struct mmc_host { #define MMC_CAP_SPI (1 << 4) /* Talks only SPI protocols */ #define MMC_CAP_NEEDS_POLL (1 << 5) /* Needs polling for card-detection */ #define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */ +#define MMC_CAP_DATA_DDR (1 << 7) /* Can the host do ddr transfers */ +#define MMC_CAP_DISABLE (1 << 7) /* Can the host be disabled */ +#define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */ +#define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */ + + mmc_pm_flag_t pm_caps; /* supported pm features */ /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ @@ -142,9 +180,19 @@ struct mmc_host { unsigned int removed:1; /* host is being removed */ #endif + /* Only used with MMC_CAP_DISABLE */ + int enabled; /* host is enabled */ + int rescan_disable; /* disable card detection */ + int nesting_cnt; /* "enable" nesting count */ + int en_dis_recurs; /* detect recursion */ + unsigned int disable_delay; /* disable delay in msecs */ + struct delayed_work disable; /* disabling work */ + struct mmc_card *card; /* device attached to this host */ wait_queue_head_t wq; + struct task_struct *claimer; /* task that has host claimed */ + int claim_cnt; /* "claim" nesting count */ struct delayed_work detect; @@ -155,6 +203,8 @@ struct mmc_host { struct task_struct *sdio_irq_thread; atomic_t sdio_irq_thread_abort; + mmc_pm_flag_t pm_flags; /* requested pm features */ + #ifdef CONFIG_LEDS_TRIGGERS struct led_trigger *led; /* activity led */ #endif @@ -183,6 +233,9 @@ static inline void *mmc_priv(struct mmc_host *host) extern int mmc_suspend_host(struct mmc_host *, pm_message_t); extern int mmc_resume_host(struct mmc_host *); +extern void mmc_power_save_host(struct mmc_host *host); +extern void mmc_power_restore_host(struct mmc_host *host); + extern void mmc_detect_change(struct mmc_host *, unsigned long delay); extern void mmc_request_done(struct mmc_host *, struct mmc_request *); @@ -197,5 +250,20 @@ struct regulator; int mmc_regulator_get_ocrmask(struct regulator *supply); int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit); +int mmc_card_awake(struct mmc_host *host); +int mmc_card_sleep(struct mmc_host *host); +int mmc_card_can_sleep(struct mmc_host *host); + +int mmc_host_enable(struct mmc_host *host); +int mmc_host_disable(struct mmc_host *host); +int mmc_host_lazy_disable(struct mmc_host *host); +int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *); + +static inline void mmc_set_disable_delay(struct mmc_host *host, + unsigned int disable_delay) +{ + host->disable_delay = disable_delay; +} + #endif diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 14b81f3e5232..37a51b3122df 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -31,6 +31,7 @@ #define MMC_ALL_SEND_CID 2 /* bcr R2 */ #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ #define MMC_SET_DSR 4 /* bc [31:16] RCA */ +#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */ #define MMC_SWITCH 6 /* ac [31:0] See below R1b */ #define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ #define MMC_SEND_EXT_CSD 8 /* adtc R1 */ @@ -249,11 +250,16 @@ struct _mmc_csd { * EXT_CSD fields */ +#define EXT_CSD_BOOT_BUS_WIDTH 177 /* R/W */ +#define EXT_CSD_BOOT_CONFIG 179 /* R/W */ #define EXT_CSD_BUS_WIDTH 183 /* R/W */ #define EXT_CSD_HS_TIMING 185 /* R/W */ #define EXT_CSD_CARD_TYPE 196 /* RO */ #define EXT_CSD_REV 192 /* RO */ #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ +#define EXT_CSD_S_A_TIMEOUT 217 +#define EXT_CSD_BOOT_SIZE_MULT 226 /* RO, 1 bytes */ +#define EXT_CSD_BOOT_INFO 228 /* RO, 1 bytes */ /* * EXT_CSD field definitions @@ -265,10 +271,36 @@ struct _mmc_csd { #define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */ #define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */ +#define EXT_CSD_CARD_TYPE_DDR_52 (2<<1) /* Card can run at DDR 52MHz */ #define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ #define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ #define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ +#define EXT_CSD_BUS_WIDTH_4_DDR 5 /* Card is in 4 bit ddr mode */ +#define EXT_CSD_BUS_WIDTH_8_DDR 6 /* Card is in 8 bit ddr mode */ + +#define EXT_CSD_BOOT_BUS_WIDTH_MASK (0x1F) +#define EXT_CSD_BOOT_BUS_WIDTH_MODE_MASK (0x3 << 3) +#define EXT_CSD_BOOT_BUS_WIDTH_MODE_SDR_NORMAL (0x0) +#define EXT_CSD_BOOT_BUS_WIDTH_MODE_SDR_HIGH (0x1) +#define EXT_CSD_BOOT_BUS_WIDTH_MODE_DDR (0x2) +#define EXT_CSD_BOOT_BUS_WIDTH_RST_WIDTH (1 << 2) +#define EXT_CSD_BOOT_BUS_WIDTH_WIDTH_MASK (0x3) +#define EXT_CSD_BOOT_BUS_WIDTH_1_SDR_4_DDR (0x0) +#define EXT_CSD_BOOT_BUS_WIDTH_4_SDR_4_DDR (0x1) +#define EXT_CSD_BOOT_BUS_WIDTH_8_SDR_8_DDR (0x2) + +#define EXT_CSD_BOOT_ACK_ENABLE (0x1 << 6) +#define EXT_CSD_BOOT_PARTITION_ENABLE_MASK (0x7 << 3) +#define EXT_CSD_BOOT_PARTITION_DISABLE (0x0) +#define EXT_CSD_BOOT_PARTITION_PART1 (0x1 << 3) +#define EXT_CSD_BOOT_PARTITION_PART2 (0x2 << 3) +#define EXT_CSD_BOOT_PARTITION_USER (0x7 << 3) + +#define EXT_CSD_BOOT_PARTITION_ACCESS_MASK (0x7) +#define EXT_CSD_BOOT_PARTITION_ACCESS_DISABLE (0x0) +#define EXT_CSD_BOOT_PARTITION_ACCESS_PART1 (0x1) +#define EXT_CSD_BOOT_PARTITION_ACCESS_PART2 (0x2) /* * MMC_SWITCH access modes diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 451bdfc85830..51332c5bc2ef 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -15,6 +15,8 @@ #include <linux/device.h> #include <linux/mod_devicetable.h> +#include <linux/mmc/pm.h> + struct mmc_card; struct sdio_func; @@ -150,5 +152,8 @@ extern unsigned char sdio_f0_readb(struct sdio_func *func, extern void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, int *err_ret); +extern mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func); +extern int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags); + #endif diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index ce38f1caa5e1..844d77ddfb34 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -100,6 +100,7 @@ struct __fat_dirent { /* <linux/videotext.h> has used 0x72 ('r') in collision, so skip a few */ #define FAT_IOCTL_GET_ATTRIBUTES _IOR('r', 0x10, __u32) #define FAT_IOCTL_SET_ATTRIBUTES _IOW('r', 0x11, __u32) +#define VFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32) struct fat_boot_sector { __u8 ignored[3]; /* Boot strap short or near jump */ @@ -137,6 +138,17 @@ struct fat_boot_fsinfo { __le32 reserved2[4]; }; +struct fat_boot_bsx { + __u8 drive; /* drive number */ + __u8 reserved1; + __u8 signature; /* extended boot signature */ + __u8 vol_id[4]; /* volume ID */ + __u8 vol_label[11]; /* volume label */ + __u8 type[8]; /* file system type */ +}; +#define FAT16_BSX_OFFSET 36 /* offset of fat_boot_bsx in FAT12 and FAT16 */ +#define FAT32_BSX_OFFSET 64 /* offset of fat_boot_bsx in FAT32 */ + struct msdos_dir_entry { __u8 name[MSDOS_NAME];/* name and extension */ __u8 attr; /* attribute bits */ diff --git a/include/linux/mxcfb.h b/include/linux/mxcfb.h index f0ea365753a9..0f92ad04942c 100644 --- a/include/linux/mxcfb.h +++ b/include/linux/mxcfb.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -58,6 +58,58 @@ struct mxcfb_gamma { int slopek[16]; }; +struct mxcfb_rect { + __u32 top; + __u32 left; + __u32 width; + __u32 height; +}; + +#define GRAYSCALE_8BIT 0x1 +#define GRAYSCALE_8BIT_INVERTED 0x2 + +#define AUTO_UPDATE_MODE_REGION_MODE 0 +#define AUTO_UPDATE_MODE_AUTOMATIC_MODE 1 + +#define UPDATE_MODE_PARTIAL 0x0 +#define UPDATE_MODE_FULL 0x1 + +#define WAVEFORM_MODE_AUTO 257 + +#define TEMP_USE_AMBIENT 0x1000 + +#define FB_POWERDOWN_DISABLE -1 + +struct mxcfb_alt_buffer_data { + __u32 phys_addr; + __u32 width; /* width of entire buffer */ + __u32 height; /* height of entire buffer */ + struct mxcfb_rect alt_update_region; /* region within buffer to update */ +}; + +struct mxcfb_update_data { + struct mxcfb_rect update_region; + __u32 waveform_mode; + __u32 update_mode; + __u32 update_marker; + int temp; + int use_alt_buffer; + struct mxcfb_alt_buffer_data alt_buffer_data; +}; + +/* + * Structure used to define waveform modes for driver + * Needed for driver to perform auto-waveform selection + */ +struct mxcfb_waveform_modes { + int mode_init; + int mode_du; + int mode_gc4; + int mode_gc8; + int mode_gc16; + int mode_gc32; +}; + #define MXCFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t) #define MXCFB_SET_GBL_ALPHA _IOW('F', 0x21, struct mxcfb_gbl_alpha) #define MXCFB_SET_CLR_KEY _IOW('F', 0x22, struct mxcfb_color_key) @@ -66,6 +118,18 @@ struct mxcfb_gamma { #define MXCFB_SET_LOC_ALPHA _IOWR('F', 0x26, struct mxcfb_loc_alpha) #define MXCFB_SET_LOC_ALP_BUF _IOW('F', 0x27, unsigned long) #define MXCFB_SET_GAMMA _IOW('F', 0x28, struct mxcfb_gamma) +#define MXCFB_GET_FB_IPU_DI _IOR('F', 0x29, u_int32_t) +#define MXCFB_GET_DIFMT _IOR('F', 0x2A, u_int32_t) +#define MXCFB_GET_FB_BLANK _IOR('F', 0x2B, u_int32_t) + +/* IOCTLs for E-ink panel updates */ +#define MXCFB_SET_WAVEFORM_MODES _IOW('F', 0x2B, struct mxcfb_waveform_modes) +#define MXCFB_SET_TEMPERATURE _IOW('F', 0x2C, int32_t) +#define MXCFB_SET_AUTO_UPDATE_MODE _IOW('F', 0x2D, __u32) +#define MXCFB_SEND_UPDATE _IOW('F', 0x2E, struct mxcfb_update_data) +#define MXCFB_WAIT_FOR_UPDATE_COMPLETE _IOW('F', 0x2F, __u32) +#define MXCFB_SET_PWRDOWN_DELAY _IOW('F', 0x30, int32_t) +#define MXCFB_GET_PWRDOWN_DELAY _IOR('F', 0x31, int32_t) #ifdef __KERNEL__ @@ -78,15 +142,9 @@ enum { MXCFB_REFRESH_PARTIAL, }; -struct mxcfb_rect { - u32 top; - u32 left; - u32 width; - u32 height; -}; - int mxcfb_set_refresh_mode(struct fb_info *fbi, int mode, struct mxcfb_rect *update_region); +int mxc_elcdif_frame_addr_setup(dma_addr_t phys); #endif /* __KERNEL__ */ #endif diff --git a/include/linux/phy.h b/include/linux/phy.h index b1368b8f6572..6a7eb402165d 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -447,6 +447,7 @@ struct phy_device* get_phy_device(struct mii_bus *bus, int addr); int phy_device_register(struct phy_device *phy); int phy_clear_interrupt(struct phy_device *phydev); int phy_config_interrupt(struct phy_device *phydev, u32 interrupts); +int phy_init_hw(struct phy_device *phydev); int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, u32 flags, phy_interface_t interface); struct phy_device * phy_attach(struct net_device *dev, @@ -484,6 +485,7 @@ void phy_driver_unregister(struct phy_driver *drv); int phy_driver_register(struct phy_driver *new_driver); void phy_prepare_link(struct phy_device *phydev, void (*adjust_link)(struct net_device *)); +void phy_state_machine(struct work_struct *work); void phy_start_machine(struct phy_device *phydev, void (*handler)(struct net_device *)); void phy_stop_machine(struct phy_device *phydev); diff --git a/include/linux/sched.h b/include/linux/sched.h index 0f1ea4a66957..5c6993ea13c5 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1665,6 +1665,9 @@ extern cputime_t task_utime(struct task_struct *p); extern cputime_t task_stime(struct task_struct *p); extern cputime_t task_gtime(struct task_struct *p); +extern int task_free_register(struct notifier_block *n); +extern int task_free_unregister(struct notifier_block *n); + /* * Per process flags */ diff --git a/include/linux/sockios.h b/include/linux/sockios.h index 241f179347d9..f4fa1a164c74 100644 --- a/include/linux/sockios.h +++ b/include/linux/sockios.h @@ -65,6 +65,7 @@ #define SIOCDIFADDR 0x8936 /* delete PA address */ #define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */ #define SIOCGIFCOUNT 0x8938 /* get number of devices */ +#define SIOCKILLADDR 0x8939 /* kill sockets with this local addr */ #define SIOCGIFBR 0x8940 /* Bridging support */ #define SIOCSIFBR 0x8941 /* Set bridging options */ diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h index 51948eb6927a..c87aa2680947 100644 --- a/include/linux/spi/ads7846.h +++ b/include/linux/spi/ads7846.h @@ -5,36 +5,17 @@ * * It's OK if the min/max values are zero. */ -enum ads7846_filter { - ADS7846_FILTER_OK, - ADS7846_FILTER_REPEAT, - ADS7846_FILTER_IGNORE, -}; struct ads7846_platform_data { u16 model; /* 7843, 7845, 7846. */ u16 vref_delay_usecs; /* 0 for external vref; etc */ - u16 vref_mv; /* external vref value, milliVolts */ - bool keep_vref_on; /* set to keep vref on for differential - * measurements as well */ - bool swap_xy; /* swap x and y axes */ - - /* Settling time of the analog signals; a function of Vcc and the - * capacitance on the X/Y drivers. If set to non-zero, two samples - * are taken with settle_delay us apart, and the second one is used. - * ~150 uSec with 0.01uF caps. - */ - u16 settle_delay_usecs; - - /* If set to non-zero, after samples are taken this delay is applied - * and penirq is rechecked, to help avoid false events. This value - * is affected by the material used to build the touch layer. - */ - u16 penirq_recheck_delay_usecs; - u16 x_plate_ohms; u16 y_plate_ohms; + u8 buflen; + u8 skip_samples; + u16 rotate; + u16 x_min, x_max; u16 y_min, y_max; u16 pressure_min, pressure_max; @@ -44,14 +25,5 @@ struct ads7846_platform_data { u16 debounce_tol; /* tolerance used for filtering */ u16 debounce_rep; /* additional consecutive good readings * required after the first two */ - int gpio_pendown; /* the GPIO used to decide the pendown - * state if get_pendown_state == NULL - */ int (*get_pendown_state)(void); - int (*filter_init) (struct ads7846_platform_data *pdata, - void **filter_data); - int (*filter) (void *filter_data, int data_idx, int *val); - void (*filter_cleanup)(void *filter_data); - void (*wait_for_sync)(void); }; - diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 4f6bb3d2160e..8f33ae3e00f3 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -100,6 +100,7 @@ struct usb_function { struct usb_descriptor_header **hs_descriptors; struct usb_configuration *config; + int hidden; /* REVISIT: bind() functions can be marked __init, which * makes trouble for section mismatch analysis. See if diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h index fbf585561570..08d9ad2947a8 100644 --- a/include/media/v4l2-int-device.h +++ b/include/media/v4l2-int-device.h @@ -186,6 +186,8 @@ enum v4l2_int_ioctl_num { vidioc_int_querystd_num, vidioc_int_s_std_num, vidioc_int_s_video_routing_num, + vidioc_int_g_register_num, + vidioc_int_s_register_num, /* * @@ -290,6 +292,8 @@ V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *); V4L2_INT_WRAPPER_1(querystd, v4l2_std_id, *); V4L2_INT_WRAPPER_1(s_std, v4l2_std_id, *); V4L2_INT_WRAPPER_1(s_video_routing, struct v4l2_routing, *); +V4L2_INT_WRAPPER_1(g_register, struct v4l2_dbg_register , *); +V4L2_INT_WRAPPER_1(s_register, struct v4l2_dbg_register , *); V4L2_INT_WRAPPER_0(dev_init); V4L2_INT_WRAPPER_0(dev_exit); diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ed3aea1605e8..59cdece3a1a4 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -139,8 +139,10 @@ enum { #define ESCO_2EV5 0x0100 #define ESCO_3EV5 0x0200 -#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3) -#define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5) +#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3) +#define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5) +#define ALL_ESCO_MASK (SCO_ESCO_MASK | ESCO_EV3 | ESCO_EV4 | ESCO_EV5 | \ + EDR_ESCO_MASK) /* ACL flags */ #define ACL_CONT 0x01 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c4ca4228b083..2b8fc2c58b14 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -325,12 +325,15 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason); void hci_add_sco(struct hci_conn *conn, __u16 handle); void hci_setup_sync(struct hci_conn *conn, __u16 handle); -struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, + __u16 pkt_type, bdaddr_t *dst); int hci_conn_del(struct hci_conn *conn); void hci_conn_hash_flush(struct hci_dev *hdev); void hci_conn_check_pending(struct hci_dev *hdev); -struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type); +struct hci_conn *hci_connect(struct hci_dev *hdev, int type, + __u16 pkt_type, bdaddr_t *dst, + __u8 sec_level, __u8 auth_type); int hci_conn_check_link_mode(struct hci_conn *conn); int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); int hci_conn_change_link_key(struct hci_conn *conn); diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h index e28a2a771471..924338ac3223 100644 --- a/include/net/bluetooth/sco.h +++ b/include/net/bluetooth/sco.h @@ -37,6 +37,7 @@ struct sockaddr_sco { sa_family_t sco_family; bdaddr_t sco_bdaddr; + __u16 sco_pkt_type; }; /* SCO socket options */ @@ -72,7 +73,8 @@ struct sco_conn { struct sco_pinfo { struct bt_sock bt; - __u32 flags; + __u16 pkt_type; + struct sco_conn *conn; }; diff --git a/include/net/tcp.h b/include/net/tcp.h index 88af84306471..eb2ed40659c6 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1396,6 +1396,8 @@ extern struct sk_buff **tcp4_gro_receive(struct sk_buff **head, extern int tcp_gro_complete(struct sk_buff *skb); extern int tcp4_gro_complete(struct sk_buff *skb); +extern void tcp_v4_nuke_addr(__u32 saddr); + #ifdef CONFIG_PROC_FS extern int tcp4_proc_init(void); extern void tcp4_proc_exit(void); diff --git a/init/Kconfig b/init/Kconfig index 3f7e60995c80..419134cfc80d 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -976,6 +976,15 @@ config EVENT_PROFILE endmenu +config ASHMEM + bool "Enable the Anonymous Shared Memory Subsystem" + default n + depends on SHMEM || TINY_SHMEM + help + The ashmem subsystem is a new shared memory allocator, similar to + POSIX SHM but with different behavior and sporting a simpler + file-based API. + config VM_EVENT_COUNTERS default y bool "Enable VM event counters for /proc/vmstat" if EMBEDDED diff --git a/kernel/fork.c b/kernel/fork.c index e6c04d462ab2..4c21988d6195 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -136,6 +136,9 @@ struct kmem_cache *vm_area_cachep; /* SLAB cache for mm_struct structures (tsk->mm) */ static struct kmem_cache *mm_cachep; +/* Notifier list called when a task struct is freed */ +static ATOMIC_NOTIFIER_HEAD(task_free_notifier); + void free_task(struct task_struct *tsk) { prop_local_destroy_single(&tsk->dirties); @@ -146,6 +149,18 @@ void free_task(struct task_struct *tsk) } EXPORT_SYMBOL(free_task); +int task_free_register(struct notifier_block *n) +{ + return atomic_notifier_chain_register(&task_free_notifier, n); +} +EXPORT_SYMBOL(task_free_register); + +int task_free_unregister(struct notifier_block *n) +{ + return atomic_notifier_chain_unregister(&task_free_notifier, n); +} +EXPORT_SYMBOL(task_free_unregister); + void __put_task_struct(struct task_struct *tsk) { WARN_ON(!tsk->exit_state); @@ -156,6 +171,7 @@ void __put_task_struct(struct task_struct *tsk) put_cred(tsk->cred); delayacct_tsk_free(tsk); + atomic_notifier_call_chain(&task_free_notifier, 0, tsk); if (!profile_handoff_task(tsk)) free_task(tsk); } diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 065205bdd920..e8108a1a0eaf 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -274,6 +274,7 @@ struct irq_desc *irq_to_desc(unsigned int irq) { return (irq < NR_IRQS) ? irq_desc + irq : NULL; } +EXPORT_SYMBOL(irq_to_desc); struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node) { @@ -368,9 +369,6 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) irqreturn_t ret, retval = IRQ_NONE; unsigned int status = 0; - if (!(action->flags & IRQF_DISABLED)) - local_irq_enable_in_hardirq(); - do { trace_irq_handler_entry(irq, action); ret = action->handler(irq, action->dev_id); diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 72067cbdb37f..bd007aa74549 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -119,6 +119,73 @@ config SUSPEND_FREEZER config HIBERNATION_NVS bool +config HAS_WAKELOCK + bool + +config HAS_EARLYSUSPEND + bool + +config WAKELOCK + bool "Wake lock" + depends on PM && RTC_CLASS + default n + select HAS_WAKELOCK + ---help--- + Enable wakelocks. When user space request a sleep state the + sleep request will be delayed until no wake locks are held. + +config WAKELOCK_STAT + bool "Wake lock stats" + depends on WAKELOCK + default y + ---help--- + Report wake lock stats in /proc/wakelocks + +config USER_WAKELOCK + bool "Userspace wake locks" + depends on WAKELOCK + default y + ---help--- + User-space wake lock api. Write "lockname" or "lockname timeout" + to /sys/power/wake_lock lock and if needed create a wake lock. + Write "lockname" to /sys/power/wake_unlock to unlock a user wake + lock. + +config EARLYSUSPEND + bool "Early suspend" + depends on WAKELOCK + default y + select HAS_EARLYSUSPEND + ---help--- + Call early suspend handlers when the user requested sleep state + changes. + +choice + prompt "User-space screen access" + default FB_EARLYSUSPEND if !FRAMEBUFFER_CONSOLE + default CONSOLE_EARLYSUSPEND + depends on HAS_EARLYSUSPEND + + config NO_USER_SPACE_SCREEN_ACCESS_CONTROL + bool "None" + + config CONSOLE_EARLYSUSPEND + bool "Console switch on early-suspend" + depends on HAS_EARLYSUSPEND && VT + ---help--- + Register early suspend handler to perform a console switch to + when user-space should stop drawing to the screen and a switch + back when it should resume. + + config FB_EARLYSUSPEND + bool "Sysfs interface" + depends on HAS_EARLYSUSPEND + ---help--- + Register early suspend handler that notifies and waits for + user-space through sysfs when user-space should stop drawing + to the screen and notifies user-space when it should resume. +endchoice + config HIBERNATION bool "Hibernation (aka 'suspend to disk')" depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE diff --git a/kernel/power/Makefile b/kernel/power/Makefile index c3b81c30e5d5..058ec85a98bd 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -12,3 +12,8 @@ obj-$(CONFIG_HIBERNATION) += swsusp.o hibernate.o snapshot.o swap.o user.o obj-$(CONFIG_HIBERNATION_NVS) += hibernate_nvs.o obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o +obj-$(CONFIG_WAKELOCK) += wakelock.o +obj-$(CONFIG_USER_WAKELOCK) += userwakelock.o +obj-$(CONFIG_EARLYSUSPEND) += earlysuspend.o +obj-$(CONFIG_CONSOLE_EARLYSUSPEND) += consoleearlysuspend.o +obj-$(CONFIG_FB_EARLYSUSPEND) += fbearlysuspend.o diff --git a/kernel/power/main.c b/kernel/power/main.c index f710e36930cc..ef94a083302f 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -146,7 +146,11 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { #ifdef CONFIG_SUSPEND +#ifdef CONFIG_EARLYSUSPEND + suspend_state_t state = PM_SUSPEND_ON; +#else suspend_state_t state = PM_SUSPEND_STANDBY; +#endif const char * const *s; #endif char *p; @@ -168,8 +172,15 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, break; } if (state < PM_SUSPEND_MAX && *s) +#ifdef CONFIG_EARLYSUSPEND + if (state == PM_SUSPEND_ON || valid_state(state)) { + error = 0; + request_suspend_state(state); + } +#else error = enter_state(state); #endif +#endif Exit: return error ? error : n; @@ -202,6 +213,11 @@ pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr, power_attr(pm_trace); #endif /* CONFIG_PM_TRACE */ +#ifdef CONFIG_USER_WAKELOCK +power_attr(wake_lock); +power_attr(wake_unlock); +#endif + static struct attribute * g[] = { &state_attr.attr, #ifdef CONFIG_PM_TRACE @@ -210,6 +226,10 @@ static struct attribute * g[] = { #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG) &pm_test_attr.attr, #endif +#ifdef CONFIG_USER_WAKELOCK + &wake_lock_attr.attr, + &wake_unlock_attr.attr, +#endif NULL, }; diff --git a/kernel/power/power.h b/kernel/power/power.h index 26d5a26f82e3..a665c1e4e597 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -236,3 +236,27 @@ static inline void suspend_thaw_processes(void) { } #endif + +#ifdef CONFIG_WAKELOCK +/* kernel/power/wakelock.c */ +extern struct workqueue_struct *suspend_work_queue; +extern struct wake_lock main_wake_lock; +extern suspend_state_t requested_suspend_state; +#endif + +#ifdef CONFIG_USER_WAKELOCK +ssize_t wake_lock_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf); +ssize_t wake_lock_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n); +ssize_t wake_unlock_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf); +ssize_t wake_unlock_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n); +#endif + +#ifdef CONFIG_EARLYSUSPEND +/* kernel/power/earlysuspend.c */ +void request_suspend_state(suspend_state_t state); +suspend_state_t get_suspend_state(void); +#endif diff --git a/kernel/power/process.c b/kernel/power/process.c index da2072d73811..d366c35f8ba0 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/syscalls.h> #include <linux/freezer.h> +#include <linux/wakelock.h> /* * Timeout for stopping processes @@ -36,6 +37,7 @@ static int try_to_freeze_tasks(bool sig_only) struct timeval start, end; u64 elapsed_csecs64; unsigned int elapsed_csecs; + unsigned int wakeup = 0; do_gettimeofday(&start); @@ -62,6 +64,12 @@ static int try_to_freeze_tasks(bool sig_only) } while_each_thread(g, p); read_unlock(&tasklist_lock); yield(); /* Yield is okay here */ +#ifdef CONFIG_WAKELOCK + if (todo && has_wake_lock(WAKE_LOCK_SUSPEND)) { + wakeup = 1; + break; + } +#endif if (time_after(jiffies, end_time)) break; } while (todo); @@ -77,11 +85,18 @@ static int try_to_freeze_tasks(bool sig_only) * and caller must call thaw_processes() if something fails), * but it cleans up leftover PF_FREEZE requests. */ - printk("\n"); - printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds " - "(%d tasks refusing to freeze):\n", - elapsed_csecs / 100, elapsed_csecs % 100, todo); - show_state(); + if(wakeup) { + printk("\n"); + printk(KERN_ERR "Freezing of %s aborted\n", + sig_only ? "user space " : "tasks "); + } + else { + printk("\n"); + printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds " + "(%d tasks refusing to freeze):\n", + elapsed_csecs / 100, elapsed_csecs % 100, todo); + show_state(); + } read_lock(&tasklist_lock); do_each_thread(g, p) { task_lock(p); diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 6f10dfc2d3e9..cd515ba1c8ce 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -19,6 +19,9 @@ #include "power.h" const char *const pm_states[PM_SUSPEND_MAX] = { +#ifdef CONFIG_EARLYSUSPEND + [PM_SUSPEND_ON] = "on", +#endif [PM_SUSPEND_STANDBY] = "standby", [PM_SUSPEND_MEM] = "mem", }; diff --git a/mm/Makefile b/mm/Makefile index 5e0bd6426693..f4e009cba6a5 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_HUGETLBFS) += hugetlb.o obj-$(CONFIG_NUMA) += mempolicy.o obj-$(CONFIG_SPARSEMEM) += sparse.o obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o +obj-$(CONFIG_ASHMEM) += ashmem.o obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o obj-$(CONFIG_SLOB) += slob.o obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o diff --git a/mm/shmem.c b/mm/shmem.c index d713239ce2ce..fb7861108d31 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2668,6 +2668,14 @@ put_memory: } EXPORT_SYMBOL_GPL(shmem_file_setup); +void shmem_set_file(struct vm_area_struct *vma, struct file *file) +{ + if (vma->vm_file) + fput(vma->vm_file); + vma->vm_file = file; + vma->vm_ops = &shmem_vm_ops; +} + /** * shmem_zero_setup - setup a shared anonymous mapping * @vma: the vma to be mmapped is prepared by do_mmap_pgoff @@ -2680,11 +2688,8 @@ int shmem_zero_setup(struct vm_area_struct *vma) file = shmem_file_setup("dev/zero", size, vma->vm_flags); if (IS_ERR(file)) return PTR_ERR(file); + shmem_set_file(vma, file); - if (vma->vm_file) - fput(vma->vm_file); - vma->vm_file = file; - vma->vm_ops = &shmem_vm_ops; return 0; } diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index fa47d5d84f5c..6b25e6eaed19 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -196,7 +196,8 @@ static void hci_conn_idle(unsigned long arg) hci_conn_enter_sniff_mode(conn); } -struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, + __u16 pkt_type, bdaddr_t *dst) { struct hci_conn *conn; @@ -220,14 +221,22 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; break; case SCO_LINK: - if (lmp_esco_capable(hdev)) - conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) | - (hdev->esco_type & EDR_ESCO_MASK); - else - conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK; - break; + if (!pkt_type) + pkt_type = SCO_ESCO_MASK; case ESCO_LINK: - conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK; + if (!pkt_type) + pkt_type = ALL_ESCO_MASK; + if (lmp_esco_capable(hdev)) { + /* HCI Setup Synchronous Connection Command uses + reverse logic on the EDR_ESCO_MASK bits */ + conn->pkt_type = (pkt_type ^ EDR_ESCO_MASK) & + hdev->esco_type; + } else { + /* Legacy HCI Add Sco Connection Command uses a + shifted bitmask */ + conn->pkt_type = (pkt_type << 5) & hdev->pkt_type & + SCO_PTYPE_MASK; + } break; } @@ -337,7 +346,9 @@ EXPORT_SYMBOL(hci_get_route); /* Create SCO or ACL connection. * Device _must_ be locked */ -struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type) +struct hci_conn *hci_connect(struct hci_dev *hdev, int type, + __u16 pkt_type, bdaddr_t *dst, + __u8 sec_level, __u8 auth_type) { struct hci_conn *acl; struct hci_conn *sco; @@ -345,7 +356,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 BT_DBG("%s dst %s", hdev->name, batostr(dst)); if (!(acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst))) { - if (!(acl = hci_conn_add(hdev, ACL_LINK, dst))) + if (!(acl = hci_conn_add(hdev, ACL_LINK, 0, dst))) return NULL; } @@ -361,7 +372,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 return acl; if (!(sco = hci_conn_hash_lookup_ba(hdev, type, dst))) { - if (!(sco = hci_conn_add(hdev, type, dst))) { + if (!(sco = hci_conn_add(hdev, type, pkt_type, dst))) { hci_conn_put(acl); return NULL; } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 184ba0a88ec0..39f13cc05e5c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -579,7 +579,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) } } else { if (!conn) { - conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr); + conn = hci_conn_add(hdev, ACL_LINK, 0, &cp->bdaddr); if (conn) { conn->out = 1; conn->link_mode |= HCI_LM_MASTER; @@ -963,7 +963,9 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); if (!conn) { - if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) { + /* pkt_type not yet used for incoming connections */ + if (!(conn = hci_conn_add(hdev, ev->link_type, 0, + &ev->bdaddr))) { BT_ERR("No memmory for new connection"); hci_dev_unlock(hdev); return; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index bd0a4c1bced0..d780295364da 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -403,7 +403,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) struct sock *parent = bt_sk(sk)->parent; rsp.result = cpu_to_le16(L2CAP_CR_PEND); rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); - parent->sk_data_ready(parent, 0); + if (parent) + parent->sk_data_ready(parent, 0); } else { sk->sk_state = BT_CONFIG; @@ -896,7 +897,7 @@ static int l2cap_do_connect(struct sock *sk) } } - hcon = hci_connect(hdev, ACL_LINK, dst, + hcon = hci_connect(hdev, ACL_LINK, 0, dst, l2cap_pi(sk)->sec_level, auth_type); if (!hcon) goto done; diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 94b3388c188b..4e6e1c637de9 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -448,7 +448,6 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) break; case BT_OPEN: - case BT_CONNECT2: if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) { set_bit(RFCOMM_AUTH_REJECT, &d->flags); rfcomm_schedule(RFCOMM_SCHED_AUTH); @@ -1194,8 +1193,6 @@ void rfcomm_dlc_accept(struct rfcomm_dlc *d) rfcomm_send_ua(d->session, d->dlci); - rfcomm_dlc_clear_timer(d); - rfcomm_dlc_lock(d); d->state = BT_CONNECTED; d->state_change(d, 0); @@ -1213,11 +1210,6 @@ static void rfcomm_check_accept(struct rfcomm_dlc *d) if (d->defer_setup) { set_bit(RFCOMM_DEFER_SETUP, &d->flags); rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); - - rfcomm_dlc_lock(d); - d->state = BT_CONNECT2; - d->state_change(d, 0); - rfcomm_dlc_unlock(d); } else rfcomm_dlc_accept(d); } else { @@ -1759,11 +1751,6 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s) if (d->defer_setup) { set_bit(RFCOMM_DEFER_SETUP, &d->flags); rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); - - rfcomm_dlc_lock(d); - d->state = BT_CONNECT2; - d->state_change(d, 0); - rfcomm_dlc_unlock(d); } else rfcomm_dlc_accept(d); } diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 51ae0c3e470a..98d9d07ddbff 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -176,6 +176,7 @@ static int sco_connect(struct sock *sk) { bdaddr_t *src = &bt_sk(sk)->src; bdaddr_t *dst = &bt_sk(sk)->dst; + __u16 pkt_type = sco_pi(sk)->pkt_type; struct sco_conn *conn; struct hci_conn *hcon; struct hci_dev *hdev; @@ -192,10 +193,13 @@ static int sco_connect(struct sock *sk) if (lmp_esco_capable(hdev) && !disable_esco) type = ESCO_LINK; - else + else { type = SCO_LINK; + pkt_type &= SCO_ESCO_MASK; + } - hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING); + hcon = hci_connect(hdev, type, pkt_type, dst, + BT_SECURITY_LOW, HCI_AT_NO_BONDING); if (!hcon) goto done; @@ -456,18 +460,22 @@ static int sco_sock_create(struct net *net, struct socket *sock, int protocol) return 0; } -static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) +static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) { - struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; + struct sockaddr_sco sa; struct sock *sk = sock->sk; - bdaddr_t *src = &sa->sco_bdaddr; - int err = 0; + bdaddr_t *src = &sa.sco_bdaddr; + int len, err = 0; - BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr)); + BT_DBG("sk %p %s", sk, batostr(&sa.sco_bdaddr)); if (!addr || addr->sa_family != AF_BLUETOOTH) return -EINVAL; + memset(&sa, 0, sizeof(sa)); + len = min_t(unsigned int, sizeof(sa), alen); + memcpy(&sa, addr, len); + lock_sock(sk); if (sk->sk_state != BT_OPEN) { @@ -481,7 +489,8 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le err = -EADDRINUSE; } else { /* Save source address */ - bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr); + bacpy(&bt_sk(sk)->src, &sa.sco_bdaddr); + sco_pi(sk)->pkt_type = sa.sco_pkt_type; sk->sk_state = BT_BOUND; } @@ -494,26 +503,34 @@ done: static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) { - struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; struct sock *sk = sock->sk; - int err = 0; - + struct sockaddr_sco sa; + int len, err = 0; BT_DBG("sk %p", sk); - if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco)) + if (!addr || addr->sa_family != AF_BLUETOOTH) return -EINVAL; - if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) - return -EBADFD; - - if (sk->sk_type != SOCK_SEQPACKET) - return -EINVAL; + memset(&sa, 0, sizeof(sa)); + len = min_t(unsigned int, sizeof(sa), alen); + memcpy(&sa, addr, len); lock_sock(sk); + if (sk->sk_type != SOCK_SEQPACKET) { + err = -EINVAL; + goto done; + } + + if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) { + err = -EBADFD; + goto done; + } + /* Set destination address and psm */ - bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr); + bacpy(&bt_sk(sk)->dst, &sa.sco_bdaddr); + sco_pi(sk)->pkt_type = sa.sco_pkt_type; if ((err = sco_connect(sk))) goto done; @@ -619,6 +636,7 @@ static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst); else bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src); + sa->sco_pkt_type = sco_pi(sk)->pkt_type; return 0; } diff --git a/net/core/dev.c b/net/core/dev.c index f956b9cbe963..ec28414f3564 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4345,6 +4345,12 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) default: if ((cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 15) || + +#if defined(CONFIG_FEC_L2SWITCH) + (cmd >= 0x9101 && + cmd <= 0x92ff) || +#endif + cmd == SIOCBONDENSLAVE || cmd == SIOCBONDRELEASE || cmd == SIOCBONDSETHWADDR || @@ -4537,6 +4543,10 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) */ default: if (cmd == SIOCWANDEV || +#if defined(CONFIG_FEC_L2SWITCH) + (cmd >= 0x9101 && + cmd <= 0x92ff) || +#endif (cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 15)) { dev_load(net, ifr.ifr_name); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 566ea6c4321d..3b478b320ad5 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -257,6 +257,7 @@ static inline int inet_netns_ok(struct net *net, int protocol) return ipprot->netns_ok; } + /* * Create an inet socket. */ @@ -825,6 +826,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCSIFPFLAGS: case SIOCGIFPFLAGS: case SIOCSIFFLAGS: + case SIOCKILLADDR: err = devinet_ioctl(net, cmd, (void __user *)arg); break; default: diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 3863c3a4223f..11b2ea9d2a56 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -57,6 +57,7 @@ #include <net/arp.h> #include <net/ip.h> +#include <net/tcp.h> #include <net/route.h> #include <net/ip_fib.h> #include <net/rtnetlink.h> @@ -631,6 +632,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) case SIOCSIFBRDADDR: /* Set the broadcast address */ case SIOCSIFDSTADDR: /* Set the destination address */ case SIOCSIFNETMASK: /* Set the netmask for the interface */ + case SIOCKILLADDR: /* Nuke all sockets on this address */ ret = -EACCES; if (!capable(CAP_NET_ADMIN)) goto out; @@ -680,7 +682,8 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) } ret = -EADDRNOTAVAIL; - if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS) + if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS + && cmd != SIOCKILLADDR) goto done; switch (cmd) { @@ -804,6 +807,10 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) inet_insert_ifa(ifa); } break; + case SIOCKILLADDR: /* Nuke all connections on this address */ + ret = 0; + tcp_v4_nuke_addr(sin->sin_addr.s_addr); + break; } done: rtnl_unlock(); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 6d88219c5e22..770fd759a6e9 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1846,6 +1846,49 @@ void tcp_v4_destroy_sock(struct sock *sk) EXPORT_SYMBOL(tcp_v4_destroy_sock); +/* + * tcp_v4_nuke_addr - destroy all sockets on the given local address + */ +void tcp_v4_nuke_addr(__u32 saddr) +{ + unsigned int bucket; + + for (bucket = 0; bucket < tcp_hashinfo.ehash_size; bucket++) { + struct hlist_nulls_node *node; + struct sock *sk; + spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, bucket); + +restart: + spin_lock_bh(lock); + sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) { + struct inet_sock *inet = inet_sk(sk); + + if (inet->rcv_saddr != saddr) + continue; + if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT) + continue; + if (sock_flag(sk, SOCK_DEAD)) + continue; + + sock_hold(sk); + spin_unlock_bh(lock); + + local_bh_disable(); + bh_lock_sock(sk); + sk->sk_err = ETIMEDOUT; + sk->sk_error_report(sk); + + tcp_done(sk); + bh_unlock_sock(sk); + local_bh_enable(); + sock_put(sk); + + goto restart; + } + spin_unlock_bh(lock); + } +} + #ifdef CONFIG_PROC_FS /* Proc filesystem TCP sock list dumping. */ @@ -2455,4 +2498,3 @@ EXPORT_SYMBOL(tcp_proc_register); EXPORT_SYMBOL(tcp_proc_unregister); #endif EXPORT_SYMBOL(sysctl_tcp_low_latency); - diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 2fc4a1724eb8..a88743bc0032 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -121,6 +121,7 @@ static struct { static bool rfkill_epo_lock_active; +static unsigned long rfkill_no; #ifdef CONFIG_RFKILL_LEDS static void rfkill_led_trigger_event(struct rfkill *rfkill) @@ -693,7 +694,7 @@ static struct device_attribute rfkill_dev_attrs[] = { __ATTR(type, S_IRUGO, rfkill_type_show, NULL), __ATTR(index, S_IRUGO, rfkill_idx_show, NULL), __ATTR(persistent, S_IRUGO, rfkill_persistent_show, NULL), - __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store), + __ATTR(state, S_IRUGO|S_IWUGO, rfkill_state_show, rfkill_state_store), __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store), __ATTR_NULL }; @@ -880,7 +881,6 @@ static void rfkill_sync_work(struct work_struct *work) int __must_check rfkill_register(struct rfkill *rfkill) { - static unsigned long rfkill_no; struct device *dev = &rfkill->dev; int error; @@ -960,8 +960,8 @@ void rfkill_unregister(struct rfkill *rfkill) mutex_lock(&rfkill_global_mutex); rfkill_send_events(rfkill, RFKILL_OP_DEL); list_del_init(&rfkill->node); + rfkill_no--; mutex_unlock(&rfkill_global_mutex); - rfkill_led_trigger_unregister(rfkill); } EXPORT_SYMBOL(rfkill_unregister); diff --git a/net/socket.c b/net/socket.c index 6d4716559047..f3cfd48191af 100644 --- a/net/socket.c +++ b/net/socket.c @@ -96,6 +96,10 @@ #include <net/sock.h> #include <linux/netfilter.h> +#ifdef CONFIG_UID_STAT +#include <linux/uid_stat.h> +#endif + static int sock_no_open(struct inode *irrelevant, struct file *dontcare); static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos); @@ -570,7 +574,12 @@ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, if (err) return err; - return sock->ops->sendmsg(iocb, sock, msg, size); + err = sock->ops->sendmsg(iocb, sock, msg, size); +#ifdef CONFIG_UID_STAT + if (err > 0) + update_tcp_snd(current_uid(), err); +#endif + return err; } int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) @@ -684,7 +693,12 @@ static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, if (err) return err; - return sock->ops->recvmsg(iocb, sock, msg, size, flags); + err = sock->ops->recvmsg(iocb, sock, msg, size, flags); +#ifdef CONFIG_UID_STAT + if (err > 0) + update_tcp_rcv(current_uid(), err); +#endif + return err; } int sock_recvmsg(struct socket *sock, struct msghdr *msg, diff --git a/sound/arm/mxc-alsa-spdif.c b/sound/arm/mxc-alsa-spdif.c index 93a34cd03e11..ae48051b49e8 100644 --- a/sound/arm/mxc-alsa-spdif.c +++ b/sound/arm/mxc-alsa-spdif.c @@ -257,6 +257,7 @@ struct mxc_spdif_device { * SPDIF module register base address */ unsigned long __iomem *reg_base; + unsigned long reg_phys_base; /*! * spdif tx available or not @@ -943,8 +944,9 @@ static void spdif_stop_tx(struct mxc_spdif_stream *s) */ static void spdif_start_tx(struct mxc_spdif_stream *s) { - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; + struct snd_pcm_substream *substream = s->stream; + struct snd_pcm_runtime *runtime = substream->runtime; + struct mxc_spdif_device *chip = snd_pcm_substream_chip(substream); unsigned int dma_size = 0; unsigned int offset; int ret = 0; @@ -960,7 +962,7 @@ static void spdif_start_tx(struct mxc_spdif_stream *s) (NULL, runtime->dma_area + offset, dma_size, DMA_TO_DEVICE)); - dma_request.dst_addr = (dma_addr_t) (SPDIF_BASE_ADDR + 0x2c); + dma_request.dst_addr = (dma_addr_t) (chip->reg_phys_base + 0x2c); dma_request.num_of_bytes = dma_size; mxc_dma_config(s->dma_wchannel, &dma_request, 1, @@ -1279,15 +1281,14 @@ static void spdif_stop_rx(struct mxc_spdif_stream *s) */ static void spdif_start_rx(struct mxc_spdif_stream *s) { - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; + struct snd_pcm_substream *substream = s->stream; + struct snd_pcm_runtime *runtime = substream->runtime; + struct mxc_spdif_device *chip = snd_pcm_substream_chip(substream); unsigned int dma_size = 0; unsigned int offset; int ret = 0; mxc_dma_requestbuf_t dma_request; - substream = s->stream; - runtime = substream->runtime; memset(&dma_request, 0, sizeof(mxc_dma_requestbuf_t)); if (s->active) { @@ -1305,7 +1306,7 @@ static void spdif_start_rx(struct mxc_spdif_stream *s) DMA_FROM_DEVICE)); dma_request.src_addr = - (dma_addr_t) (SPDIF_BASE_ADDR + SPDIF_REG_SRL); + (dma_addr_t) (chip->reg_phys_base + SPDIF_REG_SRL); dma_request.num_of_bytes = dma_size; /* config and enable sdma for RX */ mxc_dma_config(s->dma_wchannel, &dma_request, 1, @@ -2089,6 +2090,7 @@ static int mxc_alsa_spdif_probe(struct platform_device chip = card->private_data; chip->card = card; card->dev = &pdev->dev; + chip->reg_phys_base = res->start; chip->reg_base = ioremap(res->start, res->end - res->start + 1); spdif_base_addr = (unsigned long)chip->reg_base; plat_data = (struct mxc_spdif_platform_data *)pdev->dev.platform_data; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 4362689dd639..dd28cad09934 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -17,6 +17,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_AK4104 if SPI_MASTER select SND_SOC_AK4535 if I2C select SND_SOC_CS4270 if I2C + select SND_SOC_CS42888 if I2C select SND_SOC_PCM3008 select SND_SOC_SPDIF select SND_SOC_SSM2602 if I2C @@ -90,6 +91,9 @@ config SND_SOC_CS4270_VD33_ERRATA bool depends on SND_SOC_CS4270 +config SND_SOC_CS42888 + tristate + config SND_SOC_L3 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 8add6333d7c5..8fd4da08392c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -5,6 +5,7 @@ snd-soc-ak4104-objs := ak4104.o snd-soc-ak4535-objs := ak4535.o snd-soc-ak5702-objs := ak5702.o snd-soc-cs4270-objs := cs4270.o +snd-soc-cs42888-objs := cs42888.o snd-soc-l3-objs := l3.o snd-soc-pcm3008-objs := pcm3008.o snd-soc-spdif-objs := spdif_transciever.o @@ -50,6 +51,7 @@ obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_AK5702) += snd-soc-ak5702.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o +obj-$(CONFIG_SND_SOC_CS42888) += snd-soc-cs42888.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o diff --git a/sound/soc/codecs/mxs-adc-codec.c b/sound/soc/codecs/mxs-adc-codec.c index 246dab352342..f8f10619731a 100644 --- a/sound/soc/codecs/mxs-adc-codec.c +++ b/sound/soc/codecs/mxs-adc-codec.c @@ -48,6 +48,8 @@ #define BF(value, field) (((value) << BP_##field) & BM_##field) #endif +#define BM_RTC_PERSISTENT0_RELEASE_GND BF(0x2, RTC_PERSISTENT0_SPARE_ANALOG) + #define REGS_RTC_BASE (IO_ADDRESS(RTC_PHYS_ADDR)) struct mxs_codec_priv { @@ -252,6 +254,47 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol, return 0; } +static int pga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Prepare powering up HP and SPEAKER output */ + __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET); + __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND, + REGS_RTC_BASE + HW_RTC_PERSISTENT0_SET); + msleep(100); + break; + case SND_SOC_DAPM_POST_PMU: + __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR); + break; + case SND_SOC_DAPM_POST_PMD: + __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND, + REGS_RTC_BASE + HW_RTC_PERSISTENT0_CLR); + break; + } + return 0; +} + +static int adc_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND, + REGS_RTC_BASE + HW_RTC_PERSISTENT0_SET); + msleep(100); + break; + case SND_SOC_DAPM_POST_PMD: + __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND, + REGS_RTC_BASE + HW_RTC_PERSISTENT0_CLR); + break; + } + return 0; +} + static const char *mxs_codec_adc_input_sel[] = { "Mic", "Line In 1", "Head Phone", "Line In 2" }; @@ -282,8 +325,6 @@ static const struct snd_kcontrol_new mxs_snd_controls[] = { SOC_DOUBLE_R("DAC Playback Switch", DAC_VOLUME_H, DAC_VOLUME_L, 8, 0x01, 1), SOC_DOUBLE("HP Playback Volume", DAC_HPVOL_L, 8, 0, 0x7F, 1), - SOC_SINGLE("HP Playback Switch", DAC_HPVOL_H, 8, 0x1, 1), - SOC_SINGLE("Speaker Playback Switch", DAC_SPEAKERCTRL_H, 8, 0x1, 1), /* Capture Volume */ SOC_DOUBLE_R("ADC Capture Volume", @@ -310,10 +351,10 @@ SOC_DAPM_ENUM("Route", mxs_codec_enum[2]); static const struct snd_soc_dapm_widget mxs_codec_widgets[] = { - SND_SOC_DAPM_ADC("Left ADC", "Left Capture", DAC_PWRDN_L, 8, 1), - SND_SOC_DAPM_ADC("Right ADC", "Right Capture", DAC_PWRDN_H, 0, 1), + SND_SOC_DAPM_ADC_E("ADC", "Capture", DAC_PWRDN_L, 8, 1, adc_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC", "Playback", DAC_PWRDN_L, 12, 1), SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, &mxs_left_adc_controls), @@ -321,7 +362,10 @@ static const struct snd_soc_dapm_widget mxs_codec_widgets[] = { &mxs_right_adc_controls), SND_SOC_DAPM_MUX("HP Mux", SND_SOC_NOPM, 0, 0, &mxs_hp_controls), - + SND_SOC_DAPM_PGA_E("HP AMP", DAC_PWRDN_L, 0, 1, NULL, 0, pga_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA("SPEAKER AMP", DAC_PWRDN_H, 8, 1, NULL, 0), SND_SOC_DAPM_INPUT("LINE1L"), SND_SOC_DAPM_INPUT("LINE1R"), SND_SOC_DAPM_INPUT("LINE2L"), @@ -348,20 +392,23 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right ADC Mux", "Head Phone", "HPR"}, /* ADC */ - {"Left ADC", NULL, "Left ADC Mux"}, - {"Right ADC", NULL, "Right ADC Mux"}, + {"ADC", NULL, "Left ADC Mux"}, + {"ADC", NULL, "Right ADC Mux"}, /* HP Mux */ {"HP Mux", "DAC Out", "DAC"}, {"HP Mux", "Line In 1", "LINE1L"}, {"HP Mux", "Line In 1", "LINE1R"}, + /* HP amp */ + {"HP AMP", NULL, "HP Mux"}, /* HP output */ - {"HPR", NULL, "HP MUX"}, - {"HPL", NULL, "HP MUX"}, + {"HPR", NULL, "HP AMP"}, + {"HPL", NULL, "HP AMP"}, /* Speaker amp */ - {"SPEAKER", NULL, "DAC"}, + {"SPEAKER AMP", NULL, "DAC"}, + {"SPEAKER", NULL, "SPEAKER AMP"}, }; static int mxs_codec_add_widgets(struct snd_soc_codec *codec) @@ -488,29 +535,84 @@ static int mxs_codec_hw_params(struct snd_pcm_substream *substream, static int mxs_codec_dig_mute(struct snd_soc_dai *dai, int mute) { + int l, r; + int ll, rr; + u32 reg, reg1, reg2; u32 dac_mask = BM_AUDIOOUT_DACVOLUME_MUTE_LEFT | BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT; - u32 reg1 = 0; - u32 reg = 0; if (mute) { - reg1 = __raw_readl(REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL); - reg = reg1 | BF_AUDIOOUT_HPVOL_VOL_LEFT(0x7f) | \ - BF_AUDIOOUT_HPVOL_VOL_RIGHT(0x7f); - __raw_writel(reg, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL); + reg = __raw_readl(REGS_AUDIOOUT_BASE + \ + HW_AUDIOOUT_DACVOLUME); + + reg1 = reg & ~BM_AUDIOOUT_DACVOLUME_VOLUME_LEFT; + reg1 = reg1 & ~BM_AUDIOOUT_DACVOLUME_VOLUME_RIGHT; + + l = (reg & BM_AUDIOOUT_DACVOLUME_VOLUME_LEFT) >> + BP_AUDIOOUT_DACVOLUME_VOLUME_LEFT; + r = (reg & BM_AUDIOOUT_DACVOLUME_VOLUME_RIGHT) >> + BP_AUDIOOUT_DACVOLUME_VOLUME_RIGHT; + + /* fade out dac vol */ + while ((l > DAC_VOLUME_MIN) || (r > DAC_VOLUME_MIN)) { + l -= 0x8; + r -= 0x8; + ll = l > DAC_VOLUME_MIN ? l : DAC_VOLUME_MIN; + rr = r > DAC_VOLUME_MIN ? r : DAC_VOLUME_MIN; + reg2 = reg1 | BF_AUDIOOUT_DACVOLUME_VOLUME_LEFT(ll) + | BF_AUDIOOUT_DACVOLUME_VOLUME_RIGHT(rr); + __raw_writel(reg2, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME); + msleep(1); + } __raw_writel(dac_mask, - REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME_SET); - __raw_writel(BM_AUDIOOUT_HPVOL_MUTE, - REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET); - - __raw_writel(reg1, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL); - } else { + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME_SET); + reg = reg | dac_mask; + __raw_writel(reg, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME); + } else __raw_writel(dac_mask, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME_CLR); - __raw_writel(BM_AUDIOOUT_HPVOL_MUTE, - REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_CLR); + + return 0; +} + +static int mxs_codec_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + pr_debug("dapm level %d\n", level); + switch (level) { + case SND_SOC_BIAS_ON: /* full On */ + if (codec->bias_level == SND_SOC_BIAS_ON) + break; + break; + + case SND_SOC_BIAS_PREPARE: /* partial On */ + if (codec->bias_level == SND_SOC_BIAS_PREPARE) + break; + /* Set Capless mode */ + __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR); + break; + + case SND_SOC_BIAS_STANDBY: /* Off, with power */ + if (codec->bias_level == SND_SOC_BIAS_STANDBY) + break; + /* Unset Capless mode */ + __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_SET); + break; + + case SND_SOC_BIAS_OFF: /* Off, without power */ + if (codec->bias_level == SND_SOC_BIAS_OFF) + break; + /* Unset Capless mode */ + __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_SET); + break; } + codec->bias_level = level; return 0; } @@ -533,6 +635,58 @@ static void mxs_codec_dac_set_vag(void) __raw_writel(refctrl_val, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_REFCTRL); } +static bool mxs_codec_dac_is_capless() +{ + if ((__raw_readl(REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN) + & BM_AUDIOOUT_PWRDN_CAPLESS) == 0) + return false; + else + return true; +} +static void mxs_codec_dac_arm_short_cm(bool bShort) +{ + __raw_writel(BF(3, AUDIOOUT_ANACTRL_SHORTMODE_CM), + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR); + __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_CM_STS, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR); + if (bShort) + __raw_writel(BF(1, AUDIOOUT_ANACTRL_SHORTMODE_CM), + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET); +} +static void mxs_codec_dac_arm_short_lr(bool bShort) +{ + __raw_writel(BF(3, AUDIOOUT_ANACTRL_SHORTMODE_LR), + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR); + __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_LR_STS, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR); + if (bShort) + __raw_writel(BF(1, AUDIOOUT_ANACTRL_SHORTMODE_LR), + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET); +} +static void mxs_codec_dac_set_short_trip_level(u8 u8level) +{ + __raw_writel(__raw_readl(REGS_AUDIOOUT_BASE + + HW_AUDIOOUT_ANACTRL) + & (~BM_AUDIOOUT_ANACTRL_SHORT_LVLADJL) + & (~BM_AUDIOOUT_ANACTRL_SHORT_LVLADJR) + | BF(u8level, AUDIOOUT_ANACTRL_SHORT_LVLADJL) + | BF(u8level, AUDIOOUT_ANACTRL_SHORT_LVLADJR), + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL); +} +static void mxs_codec_dac_arm_short(bool bLatchCM, bool bLatchLR) +{ + if (bLatchCM) { + if (mxs_codec_dac_is_capless()) + mxs_codec_dac_arm_short_cm(true); + } else + mxs_codec_dac_arm_short_cm(false); + + if (bLatchLR) + mxs_codec_dac_arm_short_lr(true); + else + mxs_codec_dac_arm_short_lr(false); + +} static void mxs_codec_dac_power_on(struct mxs_codec_priv *mxs_adc) { @@ -542,17 +696,13 @@ mxs_codec_dac_power_on(struct mxs_codec_priv *mxs_adc) __raw_writel(BM_AUDIOOUT_ANACLKCTRL_CLKGATE, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACLKCTRL_CLR); - /* Set capless mode */ - __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS, REGS_AUDIOOUT_BASE - + HW_AUDIOOUT_PWRDN_CLR); - /* 16 bit word length */ __raw_writel(BM_AUDIOOUT_CTRL_WORD_LENGTH, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_SET); - /* Powerup DAC */ - __raw_writel(BM_AUDIOOUT_PWRDN_DAC, - REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR); + /* Arm headphone LR short protect */ + mxs_codec_dac_set_short_trip_level(0); + mxs_codec_dac_arm_short(false, true); /* Update DAC volume over zero crossings */ __raw_writel(BM_AUDIOOUT_DACVOLUME_EN_ZCD, @@ -566,30 +716,26 @@ mxs_codec_dac_power_on(struct mxs_codec_priv *mxs_adc) __raw_writel(BM_AUDIOOUT_HPVOL_EN_MSTR_ZCD, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET); - /* Prepare powering up HP output */ - __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND, - REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET); - __raw_writel(BF(0x2, RTC_PERSISTENT0_SPARE_ANALOG), - REGS_RTC_BASE + HW_RTC_PERSISTENT0_SET); - __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE, - REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR); __raw_writel(BM_AUDIOOUT_ANACTRL_HP_CLASSAB, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET); - __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND, - REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR); + /* Mute HP output */ __raw_writel(BM_AUDIOOUT_HPVOL_MUTE, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET); - __raw_writel(BM_AUDIOOUT_PWRDN_SPEAKER, - REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR); /* Mute speaker amp */ __raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_SPEAKERCTRL_SET); + /* Enable the audioout */ + __raw_writel(BM_AUDIOOUT_CTRL_RUN, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_SET); } static void mxs_codec_dac_power_down(struct mxs_codec_priv *mxs_adc) { + /* Disable the audioout */ + __raw_writel(BM_AUDIOOUT_CTRL_RUN, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_CLR); /* Disable class AB */ __raw_writel(BM_AUDIOOUT_ANACTRL_HP_CLASSAB, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR); @@ -858,7 +1004,8 @@ static int mxs_codec_probe(struct platform_device *pdev) snd_soc_free_pcms(socdev); return ret; } - + /* Set default bias level*/ + mxs_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; } @@ -982,6 +1129,8 @@ static int __init mxs_codec_audio_probe(struct platform_device *pdev) codec->private_data = mxs_adc; codec->read = mxs_codec_read; codec->write = mxs_codec_write; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = mxs_codec_set_bias_level; codec->dai = &mxs_codec_dai; codec->num_dai = 1; codec->reg_cache_size = sizeof(mxs_audio_regs) >> 1; diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index a63b65cdc04d..9bea4d8a523d 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -200,39 +200,6 @@ static void dump_reg(struct snd_soc_codec *codec) } #endif -static int dac_mux_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); - struct snd_soc_codec *codec = widget->codec; - unsigned int reg; - - if (ucontrol->value.enumerated.item[0]) { - reg = sgtl5000_read(codec, SGTL5000_CHIP_CLK_TOP_CTRL); - reg |= SGTL5000_INT_OSC_EN; - sgtl5000_write(codec, SGTL5000_CHIP_CLK_TOP_CTRL, reg); - - if (codec->bias_level != SND_SOC_BIAS_ON) { - sgtl5000_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - snd_soc_dapm_put_enum_double(kcontrol, ucontrol); - sgtl5000_set_bias_level(codec, SND_SOC_BIAS_ON); - } else - snd_soc_dapm_put_enum_double(kcontrol, ucontrol); - - reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_CTRL); - reg &= ~(SGTL5000_LINE_OUT_MUTE | SGTL5000_HP_MUTE); - sgtl5000_write(codec, SGTL5000_CHIP_ANA_CTRL, reg); - } else { - reg = sgtl5000_read(codec, SGTL5000_CHIP_CLK_TOP_CTRL); - reg &= ~SGTL5000_INT_OSC_EN; - sgtl5000_write(codec, SGTL5000_CHIP_CLK_TOP_CTRL, reg); - - snd_soc_dapm_put_enum_double(kcontrol, ucontrol); - sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - } - return 0; -} - static const char *adc_mux_text[] = { "MIC_IN", "LINE_IN" }; @@ -250,16 +217,8 @@ SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 6, 2, dac_mux_text); static const struct snd_kcontrol_new adc_mux = SOC_DAPM_ENUM("ADC Mux", adc_enum); -static const struct snd_kcontrol_new dac_mux = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "DAC Mux", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE - | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = snd_soc_info_enum_double, - .get = snd_soc_dapm_get_enum_double, - .put = dac_mux_put, - .private_value = (unsigned long)&dac_enum, -}; +static const struct snd_kcontrol_new dac_mux = +SOC_DAPM_ENUM("DAC Mux", dac_enum); static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = { SND_SOC_DAPM_INPUT("LINE_IN"), @@ -649,6 +608,8 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream, fs = sgtl5000->lrclk; /* SGTL5000 rev1 has a IC bug to prevent switching to MCLK from PLL. */ if (!sgtl5000->master) { + sys_fs = sgtl5000->lrclk; + clk_ctl = SGTL5000_RATE_MODE_DIV_1 << SGTL5000_RATE_MODE_SHIFT; if (fs * 256 == sgtl5000->sysclk) clk_ctl |= SGTL5000_MCLK_FREQ_256FS << \ SGTL5000_MCLK_FREQ_SHIFT; @@ -783,7 +744,7 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec, avoid pops. */ reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_POWER); if (reg & SGTL5000_VAG_POWERUP) - delay = 400; + delay = 600; reg &= ~SGTL5000_VAG_POWERUP; reg |= SGTL5000_DAC_POWERUP; reg |= SGTL5000_HP_POWERUP; diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 921932ab2d3a..7b3963461234 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -595,6 +595,7 @@ static const struct snd_soc_dapm_route audio_map[] = { /* Mono Capture mixer-mux */ {"Capture Right Mixer", "Stereo", "Capture Right Mux"}, + {"Capture Left Mixer", "Stereo", "Capture Left Mux"}, {"Capture Left Mixer", "Analogue Mix Left", "Capture Left Mux"}, {"Capture Left Mixer", "Analogue Mix Left", "Capture Right Mux"}, {"Capture Right Mixer", "Analogue Mix Right", "Capture Left Mux"}, @@ -1265,6 +1266,13 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_ON: /* set vmid to 50k and unmute dac */ wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); + + /* wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); */ + /* + * Force the enable of the MICBIAS, otherwise the microphone will not + * work. + */ + wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00e0); break; case SND_SOC_BIAS_PREPARE: /* set vmid to 5k for quick power up */ @@ -1702,6 +1710,12 @@ static int wm8753_register(struct wm8753_priv *wm8753) wm8753_codec = codec; + /* Configure bclk as mclk/4 */ + reg = wm8753_read_reg_cache(codec, WM8753_SRATE2); + reg &= ~WM8753_BCLK_DIV_MASK; + reg |= WM8753_BCLK_DIV_4; + wm8753_write(codec, WM8753_SRATE2, reg); + for (i = 0; i < ARRAY_SIZE(wm8753_dai); i++) wm8753_dai[i].dev = codec->dev; diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h index 57b2ba244040..40c55ad713aa 100644 --- a/sound/soc/codecs/wm8753.h +++ b/sound/soc/codecs/wm8753.h @@ -99,6 +99,7 @@ #define WM8753_PCM_DIV_8 (7 << 6) /* BCLK clock dividers */ +#define WM8753_BCLK_DIV_MASK (7 << 3) #define WM8753_BCLK_DIV_1 (0 << 3) #define WM8753_BCLK_DIV_2 (1 << 3) #define WM8753_BCLK_DIV_4 (2 << 3) diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index 43b6d8e3b10c..afefe2c5585c 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -79,4 +79,14 @@ config SND_SOC_IMX_3STACK_BLUETOOTH help Say Y if you want to add support for Soc audio on IMX 3STACK with the BLUETOOTH + +config SND_SOC_IMX_3STACK_CS42888 + tristate "SoC Audio support for IMX - CS42888" + select SND_MXC_SOC_ESAI + select SND_SOC_CS42888 + help + Say Y if you want to add support for Soc audio on IMX 3STACK + with the CS42888 + + endif diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile index 284be7777de7..7cc8d1f32674 100644 --- a/sound/soc/imx/Makefile +++ b/sound/soc/imx/Makefile @@ -24,3 +24,6 @@ snd-soc-imx-3stack-ak5702-objs := imx-3stack-ak5702.o obj-$(CONFIG_SND_SOC_IMX_3STACK_AK5702) += snd-soc-imx-3stack-ak5702.o snd-soc-imx-3stack-bt-objs := imx-3stack-bt.o obj-$(CONFIG_SND_SOC_IMX_3STACK_BLUETOOTH) += snd-soc-imx-3stack-bt.o +snd-soc-imx-3stack-cs42888-objs := imx-3stack-cs42888.o +obj-$(CONFIG_SND_SOC_IMX_3STACK_CS42888) += snd-soc-imx-3stack-cs42888.o + diff --git a/sound/soc/imx/imx-3stack-ak4647.c b/sound/soc/imx/imx-3stack-ak4647.c index 6d6a98fd02e0..56c7a498e5b1 100644 --- a/sound/soc/imx/imx-3stack-ak4647.c +++ b/sound/soc/imx/imx-3stack-ak4647.c @@ -363,8 +363,6 @@ static int __init imx_3stack_ak4647_probe(struct platform_device *pdev) imx_3stack_dai.cpu_dai = ak4647_cpu_dai; - /* Configure audio port 3 */ - gpio_activate_audio_ports(); imx_3stack_init_dam(dev_data->src_port, dev_data->ext_port); ret = request_irq(dev_data->intr_id_hp, imx_headphone_detect_handler, 0, @@ -388,7 +386,6 @@ err: static int __devexit imx_3stack_ak4647_remove(struct platform_device *pdev) { struct mxc_audio_platform_data *dev_data = pdev->dev.platform_data; - gpio_inactivate_audio_ports(); free_irq(dev_data->intr_id_hp, NULL); driver_remove_file(pdev->dev.driver, &driver_attr_headphone); return 0; diff --git a/sound/soc/imx/imx-3stack-ak5702.c b/sound/soc/imx/imx-3stack-ak5702.c index 7603c0f0ae19..734399434aa9 100644 --- a/sound/soc/imx/imx-3stack-ak5702.c +++ b/sound/soc/imx/imx-3stack-ak5702.c @@ -1,7 +1,7 @@ /* * imx-3stack-ak5702.c -- SoC audio for imx_3stack * - * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -171,13 +171,11 @@ static int __devinit imx_3stack_ak5702_probe(struct platform_device *pdev) setup->i2c_address = 0x13; imx_3stack_snd_devdata.codec_data = setup; - gpio_activate_esai_ports(); return 0; } static int imx_3stack_ak5702_remove(struct platform_device *pdev) { - gpio_deactivate_esai_ports(); return 0; } diff --git a/sound/soc/imx/imx-3stack-wm8580.c b/sound/soc/imx/imx-3stack-wm8580.c index 631571ddb5ef..f3f9f85ca0f0 100644 --- a/sound/soc/imx/imx-3stack-wm8580.c +++ b/sound/soc/imx/imx-3stack-wm8580.c @@ -1,7 +1,7 @@ /* * imx-3stack-wm8580.c -- SoC 5.1 audio for imx_3stack * - * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -69,9 +69,6 @@ struct imx_3stack_pcm_state { int lr_clk_active; }; -extern void gpio_activate_esai_ports(void); -extern void gpio_deactivate_esai_ports(void); - static struct imx_3stack_pcm_state clk_state; static int imx_3stack_startup(struct snd_pcm_substream *substream) @@ -374,20 +371,17 @@ static int __devinit imx_3stack_wm8580_probe(struct platform_device *pdev) struct wm8580_setup_data *setup; imx_3stack_dai.cpu_dai = &imx_esai_dai[2]; + imx_3stack_dai.cpu_dai->dev = &pdev->dev; setup = kzalloc(sizeof(struct wm8580_setup_data), GFP_KERNEL); setup->spi = 1; imx_3stack_snd_devdata.codec_data = setup; - /* Configure audio port 3 */ - gpio_activate_esai_ports(); - return 0; } static int __devexit imx_3stack_wm8580_remove(struct platform_device *pdev) { - gpio_deactivate_esai_ports(); return 0; } diff --git a/sound/soc/imx/imx-ccwmx51-wm8753.c b/sound/soc/imx/imx-ccwmx51-wm8753.c index a12285fb1a8d..e92df8914b1c 100644 --- a/sound/soc/imx/imx-ccwmx51-wm8753.c +++ b/sound/soc/imx/imx-ccwmx51-wm8753.c @@ -54,14 +54,47 @@ static int imx_ccwmx51_audio_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; + unsigned int rate = params_rate(params); struct imx_ccwmx51_priv *priv = &card_priv; struct imx_ssi *ssi_mode = (struct imx_ssi *)cpu_dai->private_data; int ret = 0; + unsigned int pll_out = 0; unsigned int channels = params_channels(params); u32 dai_format; - snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, priv->sysclk, 0); + switch (rate) { + case 8000: + pll_out = 12288000; + break; + case 11025: + pll_out = 11289600; + break; + case 16000: + pll_out = 12288000; + break; + case 22050: + pll_out = 11289600; + break; + case 32000: + pll_out = 12288000; + break; + case 44100: + pll_out = 11289600; + break; + case 48000: + pll_out = 12288000; + break; + case 88200: + pll_out = 11289600; + break; + case 96000: + pll_out = 12288000; + break; + default: + pr_info("Rate not supported.\n"); + return -EINVAL;; + } #if WM8753_SSI_MASTER dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | @@ -94,6 +127,9 @@ static int imx_ccwmx51_audio_hw_params(struct snd_pcm_substream *substream, /* set the SSI system clock as input (unused) */ snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, SND_SOC_CLOCK_IN); + priv->sysclk = pll_out; + snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, priv->sysclk, 0); + snd_soc_dai_set_pll(codec_dai, WM8753_MCLK, 13000000, pll_out); return 0; } diff --git a/sound/soc/imx/imx-esai.c b/sound/soc/imx/imx-esai.c index 71dd62cff509..0c6b234f29ec 100644 --- a/sound/soc/imx/imx-esai.c +++ b/sound/soc/imx/imx-esai.c @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -35,292 +35,9 @@ #include "imx-esai.h" #include "imx-pcm.h" -/*#define IMX_ESAI_DUMP 1*/ - -#ifdef IMX_ESAI_DUMP -#define ESAI_DUMP() \ - do {pr_info("dump @ %s\n", __func__); \ - pr_info("ecr %x\n", __raw_readl(ESAI_ECR)); \ - pr_info("esr %x\n", __raw_readl(ESAI_ESR)); \ - pr_info("tfcr %x\n", __raw_readl(ESAI_TFCR)); \ - pr_info("tfsr %x\n", __raw_readl(ESAI_TFSR)); \ - pr_info("rfcr %x\n", __raw_readl(ESAI_RFCR)); \ - pr_info("rfsr %x\n", __raw_readl(ESAI_RFSR)); \ - pr_info("tsr %x\n", __raw_readl(ESAI_TSR)); \ - pr_info("saisr %x\n", __raw_readl(ESAI_SAISR)); \ - pr_info("saicr %x\n", __raw_readl(ESAI_SAICR)); \ - pr_info("tcr %x\n", __raw_readl(ESAI_TCR)); \ - pr_info("tccr %x\n", __raw_readl(ESAI_TCCR)); \ - pr_info("rcr %x\n", __raw_readl(ESAI_RCR)); \ - pr_info("rccr %x\n", __raw_readl(ESAI_RCCR)); \ - pr_info("tsma %x\n", __raw_readl(ESAI_TSMA)); \ - pr_info("tsmb %x\n", __raw_readl(ESAI_TSMB)); \ - pr_info("rsma %x\n", __raw_readl(ESAI_RSMA)); \ - pr_info("rsmb %x\n", __raw_readl(ESAI_RSMB)); \ - pr_info("prrc %x\n", __raw_readl(ESAI_PRRC)); \ - pr_info("pcrc %x\n", __raw_readl(ESAI_PCRC)); } while (0); -#else -#define ESAI_DUMP() -#endif - -#define ESAI_IO_BASE_ADDR IO_ADDRESS(ESAI_BASE_ADDR) - -#define ESAI_ETDR (ESAI_IO_BASE_ADDR + 0x00) -#define ESAI_ERDR (ESAI_IO_BASE_ADDR + 0x04) -#define ESAI_ECR (ESAI_IO_BASE_ADDR + 0x08) -#define ESAI_ESR (ESAI_IO_BASE_ADDR + 0x0C) -#define ESAI_TFCR (ESAI_IO_BASE_ADDR + 0x10) -#define ESAI_TFSR (ESAI_IO_BASE_ADDR + 0x14) -#define ESAI_RFCR (ESAI_IO_BASE_ADDR + 0x18) -#define ESAI_RFSR (ESAI_IO_BASE_ADDR + 0x1C) -#define ESAI_TX0 (ESAI_IO_BASE_ADDR + 0x80) -#define ESAI_TX1 (ESAI_IO_BASE_ADDR + 0x84) -#define ESAI_TX2 (ESAI_IO_BASE_ADDR + 0x88) -#define ESAI_TX3 (ESAI_IO_BASE_ADDR + 0x8C) -#define ESAI_TX4 (ESAI_IO_BASE_ADDR + 0x90) -#define ESAI_TX5 (ESAI_IO_BASE_ADDR + 0x94) -#define ESAI_TSR (ESAI_IO_BASE_ADDR + 0x98) -#define ESAI_RX0 (ESAI_IO_BASE_ADDR + 0xA0) -#define ESAI_RX1 (ESAI_IO_BASE_ADDR + 0xA4) -#define ESAI_RX2 (ESAI_IO_BASE_ADDR + 0xA8) -#define ESAI_RX3 (ESAI_IO_BASE_ADDR + 0xAC) -#define ESAI_SAISR (ESAI_IO_BASE_ADDR + 0xCC) -#define ESAI_SAICR (ESAI_IO_BASE_ADDR + 0xD0) -#define ESAI_TCR (ESAI_IO_BASE_ADDR + 0xD4) -#define ESAI_TCCR (ESAI_IO_BASE_ADDR + 0xD8) -#define ESAI_RCR (ESAI_IO_BASE_ADDR + 0xDC) -#define ESAI_RCCR (ESAI_IO_BASE_ADDR + 0xE0) -#define ESAI_TSMA (ESAI_IO_BASE_ADDR + 0xE4) -#define ESAI_TSMB (ESAI_IO_BASE_ADDR + 0xE8) -#define ESAI_RSMA (ESAI_IO_BASE_ADDR + 0xEC) -#define ESAI_RSMB (ESAI_IO_BASE_ADDR + 0xF0) -#define ESAI_PRRC (ESAI_IO_BASE_ADDR + 0xF8) -#define ESAI_PCRC (ESAI_IO_BASE_ADDR + 0xFC) - -#define ESAI_ECR_ETI (1 << 19) -#define ESAI_ECR_ETO (1 << 18) -#define ESAI_ECR_ERI (1 << 17) -#define ESAI_ECR_ERO (1 << 16) -#define ESAI_ECR_ERST (1 << 1) -#define ESAI_ECR_ESAIEN (1 << 0) - -#define ESAI_ESR_TINIT (1 << 10) -#define ESAI_ESR_RFF (1 << 9) -#define ESAI_ESR_TFE (1 << 8) -#define ESAI_ESR_TLS (1 << 7) -#define ESAI_ESR_TDE (1 << 6) -#define ESAI_ESR_TED (1 << 5) -#define ESAI_ESR_TD (1 << 4) -#define ESAI_ESR_RLS (1 << 3) -#define ESAI_ESR_RDE (1 << 2) -#define ESAI_ESR_RED (1 << 1) -#define ESAI_ESR_RD (1 << 0) - -#define ESAI_TFCR_TIEN (1 << 19) -#define ESAI_TFCR_TE5 (1 << 7) -#define ESAI_TFCR_TE4 (1 << 6) -#define ESAI_TFCR_TE3 (1 << 5) -#define ESAI_TFCR_TE2 (1 << 4) -#define ESAI_TFCR_TE1 (1 << 3) -#define ESAI_TFCR_TE0 (1 << 2) -#define ESAI_TFCR_TFR (1 << 1) -#define ESAI_TFCR_TFEN (1 << 0) -#define ESAI_TFCR_TE(x) ((0x3f >> (6 - ((x + 1) >> 1))) << 2) -#define ESAI_TFCR_TE_MASK 0xfff03 -#define ESAI_TFCR_TFWM(x) ((x - 1) << 8) -#define ESAI_TFCR_TWA_MASK 0xf8ffff - -#define ESAI_RFCR_REXT (1 << 19) -#define ESAI_RFCR_RE3 (1 << 5) -#define ESAI_RFCR_RE2 (1 << 4) -#define ESAI_RFCR_RE1 (1 << 3) -#define ESAI_RFCR_RE0 (1 << 2) -#define ESAI_RFCR_RFR (1 << 1) -#define ESAI_RFCR_RFEN (1 << 0) -#define ESAI_RFCR_RE(x) ((0xf >> (4 - ((x + 1) >> 1))) << 3) -#define ESAI_RFCR_RE_MASK 0xfffc3 -#define ESAI_RFCR_RFWM(x) ((x-1) << 8) -#define ESAI_RFCR_RWA_MASK 0xf8ffff - -#define ESAI_WORD_LEN_32 (0x00 << 16) -#define ESAI_WORD_LEN_28 (0x01 << 16) -#define ESAI_WORD_LEN_24 (0x02 << 16) -#define ESAI_WORD_LEN_20 (0x03 << 16) -#define ESAI_WORD_LEN_16 (0x04 << 16) -#define ESAI_WORD_LEN_12 (0x05 << 16) -#define ESAI_WORD_LEN_8 (0x06 << 16) -#define ESAI_WORD_LEN_4 (0x07 << 16) - -#define ESAI_SAISR_TODFE (1 << 17) -#define ESAI_SAISR_TEDE (1 << 16) -#define ESAI_SAISR_TDE (1 << 15) -#define ESAI_SAISR_TUE (1 << 14) -#define ESAI_SAISR_TFS (1 << 13) -#define ESAI_SAISR_RODF (1 << 10) -#define ESAI_SAISR_REDF (1 << 9) -#define ESAI_SAISR_RDF (1 << 8) -#define ESAI_SAISR_ROE (1 << 7) -#define ESAI_SAISR_RFS (1 << 6) -#define ESAI_SAISR_IF2 (1 << 2) -#define ESAI_SAISR_IF1 (1 << 1) -#define ESAI_SAISR_IF0 (1 << 0) - -#define ESAI_SAICR_ALC (1 << 8) -#define ESAI_SAICR_TEBE (1 << 7) -#define ESAI_SAICR_SYNC (1 << 6) -#define ESAI_SAICR_OF2 (1 << 2) -#define ESAI_SAICR_OF1 (1 << 1) -#define ESAI_SAICR_OF0 (1 << 0) - -#define ESAI_TCR_TLIE (1 << 23) -#define ESAI_TCR_TIE (1 << 22) -#define ESAI_TCR_TEDIE (1 << 21) -#define ESAI_TCR_TEIE (1 << 20) -#define ESAI_TCR_TPR (1 << 19) -#define ESAI_TCR_PADC (1 << 17) -#define ESAI_TCR_TFSR (1 << 16) -#define ESAI_TCR_TFSL (1 << 15) -#define ESAI_TCR_TWA (1 << 7) -#define ESAI_TCR_TSHFD_MSB (0 << 6) -#define ESAI_TCR_TSHFD_LSB (1 << 6) -#define ESAI_TCR_TE5 (1 << 5) -#define ESAI_TCR_TE4 (1 << 4) -#define ESAI_TCR_TE3 (1 << 3) -#define ESAI_TCR_TE2 (1 << 2) -#define ESAI_TCR_TE1 (1 << 1) -#define ESAI_TCR_TE0 (1 << 0) -#define ESAI_TCR_TE(x) (0x3f >> (6 - ((x + 1) >> 1))) - -#define ESAI_TCR_TSWS_MASK 0xff83ff -#define ESAI_TCR_TSWS_STL8_WDL8 (0x00 << 10) -#define ESAI_TCR_TSWS_STL12_WDL8 (0x04 << 10) -#define ESAI_TCR_TSWS_STL12_WDL12 (0x01 << 10) -#define ESAI_TCR_TSWS_STL16_WDL8 (0x08 << 10) -#define ESAI_TCR_TSWS_STL16_WDL12 (0x05 << 10) -#define ESAI_TCR_TSWS_STL16_WDL16 (0x02 << 10) -#define ESAI_TCR_TSWS_STL20_WDL8 (0x0c << 10) -#define ESAI_TCR_TSWS_STL20_WDL12 (0x09 << 10) -#define ESAI_TCR_TSWS_STL20_WDL16 (0x06 << 10) -#define ESAI_TCR_TSWS_STL20_WDL20 (0x03 << 10) -#define ESAI_TCR_TSWS_STL24_WDL8 (0x10 << 10) -#define ESAI_TCR_TSWS_STL24_WDL12 (0x0d << 10) -#define ESAI_TCR_TSWS_STL24_WDL16 (0x0a << 10) -#define ESAI_TCR_TSWS_STL24_WDL20 (0x07 << 10) -#define ESAI_TCR_TSWS_STL24_WDL24 (0x1e << 10) -#define ESAI_TCR_TSWS_STL32_WDL8 (0x18 << 10) -#define ESAI_TCR_TSWS_STL32_WDL12 (0x15 << 10) -#define ESAI_TCR_TSWS_STL32_WDL16 (0x12 << 10) -#define ESAI_TCR_TSWS_STL32_WDL20 (0x0f << 10) -#define ESAI_TCR_TSWS_STL32_WDL24 (0x1f << 10) - -#define ESAI_TCR_TMOD_MASK 0xfffcff -#define ESAI_TCR_TMOD_NORMAL (0x00 << 8) -#define ESAI_TCR_TMOD_ONDEMAND (0x01 << 8) -#define ESAI_TCR_TMOD_NETWORK (0x01 << 8) -#define ESAI_TCR_TMOD_RESERVED (0x02 << 8) -#define ESAI_TCR_TMOD_AC97 (0x03 << 8) - -#define ESAI_TCCR_THCKD (1 << 23) -#define ESAI_TCCR_TFSD (1 << 22) -#define ESAI_TCCR_TCKD (1 << 21) -#define ESAI_TCCR_THCKP (1 << 20) -#define ESAI_TCCR_TFSP (1 << 19) -#define ESAI_TCCR_TCKP (1 << 18) - -#define ESAI_TCCR_TPSR_MASK 0xfffeff -#define ESAI_TCCR_TPSR_BYPASS (1 << 8) -#define ESAI_TCCR_TPSR_DIV8 (0 << 8) - -#define ESAI_TCCR_TFP_MASK 0xfc3fff -#define ESAI_TCCR_TFP(x) ((x & 0xf) << 14) - -#define ESAI_TCCR_TDC_MASK 0xffc1ff -#define ESAI_TCCR_TDC(x) (((x) & 0x1f) << 9) - -#define ESAI_TCCR_TPM_MASK 0xffff00 -#define ESAI_TCCR_TPM(x) (x & 0xff) - -#define ESAI_RCR_RLIE (1 << 23) -#define ESAI_RCR_RIE (1 << 22) -#define ESAI_RCR_REDIE (1 << 21) -#define ESAI_RCR_REIE (1 << 20) -#define ESAI_RCR_RPR (1 << 19) -#define ESAI_RCR_RFSR (1 << 16) -#define ESAI_RCR_RFSL (1 << 15) -#define ESAI_RCR_RWA (1 << 7) -#define ESAI_RCR_RSHFD_MSB (0 << 6) -#define ESAI_RCR_RSHFD_LSB (1 << 6) -#define ESAI_RCR_RE3 (1 << 3) -#define ESAI_RCR_RE2 (1 << 2) -#define ESAI_RCR_RE1 (1 << 1) -#define ESAI_RCR_RE0 (1 << 0) -#define ESAI_RCR_RE(x) ((0xf >> (4 - ((x + 1) >> 1))) << 1) - -#define ESAI_RCR_RSWS_MASK 0xff83ff -#define ESAI_RCR_RSWS_STL8_WDL8 (0x00 << 10) -#define ESAI_RCR_RSWS_STL12_WDL8 (0x04 << 10) -#define ESAI_RCR_RSWS_STL12_WDL12 (0x01 << 10) -#define ESAI_RCR_RSWS_STL16_WDL8 (0x08 << 10) -#define ESAI_RCR_RSWS_STL16_WDL12 (0x05 << 10) -#define ESAI_RCR_RSWS_STL16_WDL16 (0x02 << 10) -#define ESAI_RCR_RSWS_STL20_WDL8 (0x0c << 10) -#define ESAI_RCR_RSWS_STL20_WDL12 (0x09 << 10) -#define ESAI_RCR_RSWS_STL20_WDL16 (0x06 << 10) -#define ESAI_RCR_RSWS_STL20_WDL20 (0x03 << 10) -#define ESAI_RCR_RSWS_STL24_WDL8 (0x10 << 10) -#define ESAI_RCR_RSWS_STL24_WDL12 (0x0d << 10) -#define ESAI_RCR_RSWS_STL24_WDL16 (0x0a << 10) -#define ESAI_RCR_RSWS_STL24_WDL20 (0x07 << 10) -#define ESAI_RCR_RSWS_STL24_WDL24 (0x1e << 10) -#define ESAI_RCR_RSWS_STL32_WDL8 (0x18 << 10) -#define ESAI_RCR_RSWS_STL32_WDL12 (0x15 << 10) -#define ESAI_RCR_RSWS_STL32_WDL16 (0x12 << 10) -#define ESAI_RCR_RSWS_STL32_WDL20 (0x0f << 10) -#define ESAI_RCR_RSWS_STL32_WDL24 (0x1f << 10) - -#define ESAI_RCR_RMOD_MASK 0xfffcff -#define ESAI_RCR_RMOD_NORMAL (0x00 << 8) -#define ESAI_RCR_RMOD_ONDEMAND (0x01 << 8) -#define ESAI_RCR_RMOD_NETWORK (0x01 << 8) -#define ESAI_RCR_RMOD_RESERVED (0x02 << 8) -#define ESAI_RCR_RMOD_AC97 (0x03 << 8) - -#define ESAI_RCCR_RHCKD (1 << 23) -#define ESAI_RCCR_RFSD (1 << 22) -#define ESAI_RCCR_RCKD (1 << 21) -#define ESAI_RCCR_RHCKP (1 << 20) -#define ESAI_RCCR_RFSP (1 << 19) -#define ESAI_RCCR_RCKP (1 << 18) - -#define ESAI_RCCR_RPSR_MASK 0xfffeff -#define ESAI_RCCR_RPSR_BYPASS (1 << 8) -#define ESAI_RCCR_RPSR_DIV8 (0 << 8) - -#define ESAI_RCCR_RFP_MASK 0xfc3fff -#define ESAI_RCCR_RFP(x) ((x & 0xf) << 14) - -#define ESAI_RCCR_RDC_MASK 0xffc1ff -#define ESAI_RCCR_RDC(x) (((x) & 0x1f) << 9) - -#define ESAI_RCCR_RPM_MASK 0xffff00 -#define ESAI_RCCR_RPM(x) (x & 0xff) - -#define ESAI_GPIO_ESAI 0xfff - -/* ESAI clock source */ -#define ESAI_CLK_FSYS 0 -#define ESAI_CLK_EXTAL 1 - -/* ESAI clock divider */ -#define ESAI_TX_DIV_PSR 0 -#define ESAI_TX_DIV_PM 1 -#define ESAI_TX_DIV_FP 2 -#define ESAI_RX_DIV_PSR 3 -#define ESAI_RX_DIV_PM 4 -#define ESAI_RX_DIV_FP 5 - static int imx_esai_txrx_state; static struct imx_esai imx_esai_priv[3]; +static void __iomem *esai_ioaddr; static int imx_esai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) @@ -341,10 +58,8 @@ static int imx_esai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, ~(ESAI_RCCR_RHCKD | ESAI_RCCR_RCKD | ESAI_RCCR_RFSD); } else { - if (cpu_dai->id & IMX_DAI_ESAI_TX) tccr |= ESAI_TCCR_THCKD | ESAI_TCCR_TCKD | ESAI_TCCR_TFSD; - if (cpu_dai->id & IMX_DAI_ESAI_RX) rccr |= ESAI_RCCR_RHCKD | ESAI_RCCR_RCKD | ESAI_RCCR_RFSD; if (clk_id == ESAI_CLK_FSYS) { @@ -353,14 +68,10 @@ static int imx_esai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, if (cpu_dai->id & IMX_DAI_ESAI_RX) ecr &= ~(ESAI_ECR_ERI | ESAI_ECR_ERO); } else if (clk_id == ESAI_CLK_EXTAL) { - if (cpu_dai->id & IMX_DAI_ESAI_TX) { ecr |= ESAI_ECR_ETI; ecr &= ~ESAI_ECR_ETO; - } - if (cpu_dai->id & IMX_DAI_ESAI_RX) { ecr |= ESAI_ECR_ERI; ecr &= ~ESAI_ECR_ERO; - } } } @@ -386,7 +97,10 @@ static int imx_esai_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, switch (div_id) { case ESAI_TX_DIV_PSR: tccr &= ESAI_TCCR_TPSR_MASK; - tccr |= div; + if (div) + tccr |= ESAI_TCCR_TPSR_BYPASS; + else + tccr &= ~ESAI_TCCR_TPSR_DIV8; break; case ESAI_TX_DIV_PM: tccr &= ESAI_TCCR_TPM_MASK; @@ -398,7 +112,10 @@ static int imx_esai_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, break; case ESAI_RX_DIV_PSR: rccr &= ESAI_RCCR_RPSR_MASK; - rccr |= div; + if (div) + rccr |= ESAI_RCCR_RPSR_BYPASS; + else + rccr &= ~ESAI_RCCR_RPSR_DIV8; break; case ESAI_RX_DIV_PM: rccr &= ESAI_RCCR_RPM_MASK; @@ -691,7 +408,7 @@ static int imx_esai_hw_rx_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: rfcr |= ESAI_WORD_LEN_16; - rcr |= ESAI_RCR_RSHFD_MSB | ESAI_RCR_RSWS_STL16_WDL16; + rcr |= ESAI_RCR_RSHFD_MSB | ESAI_RCR_RSWS_STL32_WDL16; break; } @@ -729,6 +446,7 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { u32 reg, tfcr = 0, rfcr = 0; + u32 temp; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { tfcr = __raw_readl(ESAI_TFCR); @@ -748,6 +466,9 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd, reg |= ESAI_TCR_TE(substream->runtime->channels); __raw_writel(reg, ESAI_TCR); } else { + temp = __raw_readl(ESAI_TCR); + temp &= ~ESAI_TCR_TPR; + __raw_writel(temp, ESAI_TCR); rfcr |= ESAI_RFCR_RFEN; __raw_writel(rfcr, ESAI_RFCR); reg &= ~ESAI_RCR_RPR; @@ -783,7 +504,6 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd, default: return -EINVAL; } - ESAI_DUMP(); return 0; } @@ -932,14 +652,53 @@ struct snd_soc_dai imx_esai_dai[] = { EXPORT_SYMBOL_GPL(imx_esai_dai); +static int imx_esai_dev_probe(struct platform_device *pdev) +{ + struct resource *res; + struct mxc_esai_platform_data *plat_data = pdev->dev.platform_data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + esai_ioaddr = ioremap(res->start, res->end - res->start + 1); + + if (plat_data->activate_esai_ports) + plat_data->activate_esai_ports(); + + snd_soc_register_dais(imx_esai_dai, ARRAY_SIZE(imx_esai_dai)); + return 0; +} + +static int __devexit imx_esai_dev_remove(struct platform_device *pdev) +{ + + struct mxc_esai_platform_data *plat_data = pdev->dev.platform_data; + iounmap(esai_ioaddr); + if (plat_data->deactivate_esai_ports) + plat_data->deactivate_esai_ports(); + + snd_soc_unregister_dais(imx_esai_dai, ARRAY_SIZE(imx_esai_dai)); + return 0; +} + + +static struct platform_driver imx_esai_driver = { + .probe = imx_esai_dev_probe, + .remove = __devexit_p(imx_esai_dev_remove), + .driver = { + .name = "mxc_esai", + }, +}; + static int __init imx_esai_init(void) { - return snd_soc_register_dais(imx_esai_dai, ARRAY_SIZE(imx_esai_dai)); + return platform_driver_register(&imx_esai_driver); } static void __exit imx_esai_exit(void) { - snd_soc_unregister_dais(imx_esai_dai, ARRAY_SIZE(imx_esai_dai)); + platform_driver_unregister(&imx_esai_driver); } module_init(imx_esai_init); diff --git a/sound/soc/imx/imx-esai.h b/sound/soc/imx/imx-esai.h index 58ad601c119f..6e2cce0eff4a 100644 --- a/sound/soc/imx/imx-esai.h +++ b/sound/soc/imx/imx-esai.h @@ -1,7 +1,7 @@ /* * imx-esai.h -- ESAI driver header file for Freescale IMX * - * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -16,6 +16,290 @@ #ifndef _MXC_ESAI_H #define _MXC_ESAI_H +/*#define IMX_ESAI_DUMP 1*/ + +#ifdef IMX_ESAI_DUMP +#define ESAI_DUMP() \ + do {pr_info("dump @ %s\n", __func__); \ + pr_info("ecr %x\n", __raw_readl(ESAI_ECR)); \ + pr_info("esr %x\n", __raw_readl(ESAI_ESR)); \ + pr_info("tfcr %x\n", __raw_readl(ESAI_TFCR)); \ + pr_info("tfsr %x\n", __raw_readl(ESAI_TFSR)); \ + pr_info("rfcr %x\n", __raw_readl(ESAI_RFCR)); \ + pr_info("rfsr %x\n", __raw_readl(ESAI_RFSR)); \ + pr_info("tsr %x\n", __raw_readl(ESAI_TSR)); \ + pr_info("saisr %x\n", __raw_readl(ESAI_SAISR)); \ + pr_info("saicr %x\n", __raw_readl(ESAI_SAICR)); \ + pr_info("tcr %x\n", __raw_readl(ESAI_TCR)); \ + pr_info("tccr %x\n", __raw_readl(ESAI_TCCR)); \ + pr_info("rcr %x\n", __raw_readl(ESAI_RCR)); \ + pr_info("rccr %x\n", __raw_readl(ESAI_RCCR)); \ + pr_info("tsma %x\n", __raw_readl(ESAI_TSMA)); \ + pr_info("tsmb %x\n", __raw_readl(ESAI_TSMB)); \ + pr_info("rsma %x\n", __raw_readl(ESAI_RSMA)); \ + pr_info("rsmb %x\n", __raw_readl(ESAI_RSMB)); \ + pr_info("prrc %x\n", __raw_readl(ESAI_PRRC)); \ + pr_info("pcrc %x\n", __raw_readl(ESAI_PCRC)); } while (0); +#else +#define ESAI_DUMP() +#endif + +#define ESAI_IO_BASE_ADDR (esai_ioaddr) + +#define ESAI_ETDR (ESAI_IO_BASE_ADDR + 0x00) +#define ESAI_ERDR (ESAI_IO_BASE_ADDR + 0x04) +#define ESAI_ECR (ESAI_IO_BASE_ADDR + 0x08) +#define ESAI_ESR (ESAI_IO_BASE_ADDR + 0x0C) +#define ESAI_TFCR (ESAI_IO_BASE_ADDR + 0x10) +#define ESAI_TFSR (ESAI_IO_BASE_ADDR + 0x14) +#define ESAI_RFCR (ESAI_IO_BASE_ADDR + 0x18) +#define ESAI_RFSR (ESAI_IO_BASE_ADDR + 0x1C) +#define ESAI_TX0 (ESAI_IO_BASE_ADDR + 0x80) +#define ESAI_TX1 (ESAI_IO_BASE_ADDR + 0x84) +#define ESAI_TX2 (ESAI_IO_BASE_ADDR + 0x88) +#define ESAI_TX3 (ESAI_IO_BASE_ADDR + 0x8C) +#define ESAI_TX4 (ESAI_IO_BASE_ADDR + 0x90) +#define ESAI_TX5 (ESAI_IO_BASE_ADDR + 0x94) +#define ESAI_TSR (ESAI_IO_BASE_ADDR + 0x98) +#define ESAI_RX0 (ESAI_IO_BASE_ADDR + 0xA0) +#define ESAI_RX1 (ESAI_IO_BASE_ADDR + 0xA4) +#define ESAI_RX2 (ESAI_IO_BASE_ADDR + 0xA8) +#define ESAI_RX3 (ESAI_IO_BASE_ADDR + 0xAC) +#define ESAI_SAISR (ESAI_IO_BASE_ADDR + 0xCC) +#define ESAI_SAICR (ESAI_IO_BASE_ADDR + 0xD0) +#define ESAI_TCR (ESAI_IO_BASE_ADDR + 0xD4) +#define ESAI_TCCR (ESAI_IO_BASE_ADDR + 0xD8) +#define ESAI_RCR (ESAI_IO_BASE_ADDR + 0xDC) +#define ESAI_RCCR (ESAI_IO_BASE_ADDR + 0xE0) +#define ESAI_TSMA (ESAI_IO_BASE_ADDR + 0xE4) +#define ESAI_TSMB (ESAI_IO_BASE_ADDR + 0xE8) +#define ESAI_RSMA (ESAI_IO_BASE_ADDR + 0xEC) +#define ESAI_RSMB (ESAI_IO_BASE_ADDR + 0xF0) +#define ESAI_PRRC (ESAI_IO_BASE_ADDR + 0xF8) +#define ESAI_PCRC (ESAI_IO_BASE_ADDR + 0xFC) + +#define ESAI_ECR_ETI (1 << 19) +#define ESAI_ECR_ETO (1 << 18) +#define ESAI_ECR_ERI (1 << 17) +#define ESAI_ECR_ERO (1 << 16) +#define ESAI_ECR_ERST (1 << 1) +#define ESAI_ECR_ESAIEN (1 << 0) + +#define ESAI_ESR_TINIT (1 << 10) +#define ESAI_ESR_RFF (1 << 9) +#define ESAI_ESR_TFE (1 << 8) +#define ESAI_ESR_TLS (1 << 7) +#define ESAI_ESR_TDE (1 << 6) +#define ESAI_ESR_TED (1 << 5) +#define ESAI_ESR_TD (1 << 4) +#define ESAI_ESR_RLS (1 << 3) +#define ESAI_ESR_RDE (1 << 2) +#define ESAI_ESR_RED (1 << 1) +#define ESAI_ESR_RD (1 << 0) + +#define ESAI_TFCR_TIEN (1 << 19) +#define ESAI_TFCR_TE5 (1 << 7) +#define ESAI_TFCR_TE4 (1 << 6) +#define ESAI_TFCR_TE3 (1 << 5) +#define ESAI_TFCR_TE2 (1 << 4) +#define ESAI_TFCR_TE1 (1 << 3) +#define ESAI_TFCR_TE0 (1 << 2) +#define ESAI_TFCR_TFR (1 << 1) +#define ESAI_TFCR_TFEN (1 << 0) +#define ESAI_TFCR_TE(x) ((0x3f >> (6 - ((x + 1) >> 1))) << 2) +#define ESAI_TFCR_TE_MASK 0xfff03 +#define ESAI_TFCR_TFWM(x) ((x - 1) << 8) +#define ESAI_TFCR_TWA_MASK 0xf8ffff + +#define ESAI_RFCR_REXT (1 << 19) +#define ESAI_RFCR_RE3 (1 << 5) +#define ESAI_RFCR_RE2 (1 << 4) +#define ESAI_RFCR_RE1 (1 << 3) +#define ESAI_RFCR_RE0 (1 << 2) +#define ESAI_RFCR_RFR (1 << 1) +#define ESAI_RFCR_RFEN (1 << 0) +#define ESAI_RFCR_RE(x) ((0xf >> (4 - ((x + 1) >> 1))) << 2) +#define ESAI_RFCR_RE_MASK 0xfffc3 +#define ESAI_RFCR_RFWM(x) ((x-1) << 8) +#define ESAI_RFCR_RWA_MASK 0xf8ffff + +#define ESAI_WORD_LEN_32 (0x00 << 16) +#define ESAI_WORD_LEN_28 (0x01 << 16) +#define ESAI_WORD_LEN_24 (0x02 << 16) +#define ESAI_WORD_LEN_20 (0x03 << 16) +#define ESAI_WORD_LEN_16 (0x04 << 16) +#define ESAI_WORD_LEN_12 (0x05 << 16) +#define ESAI_WORD_LEN_8 (0x06 << 16) +#define ESAI_WORD_LEN_4 (0x07 << 16) + +#define ESAI_SAISR_TODFE (1 << 17) +#define ESAI_SAISR_TEDE (1 << 16) +#define ESAI_SAISR_TDE (1 << 15) +#define ESAI_SAISR_TUE (1 << 14) +#define ESAI_SAISR_TFS (1 << 13) +#define ESAI_SAISR_RODF (1 << 10) +#define ESAI_SAISR_REDF (1 << 9) +#define ESAI_SAISR_RDF (1 << 8) +#define ESAI_SAISR_ROE (1 << 7) +#define ESAI_SAISR_RFS (1 << 6) +#define ESAI_SAISR_IF2 (1 << 2) +#define ESAI_SAISR_IF1 (1 << 1) +#define ESAI_SAISR_IF0 (1 << 0) + +#define ESAI_SAICR_ALC (1 << 8) +#define ESAI_SAICR_TEBE (1 << 7) +#define ESAI_SAICR_SYNC (1 << 6) +#define ESAI_SAICR_OF2 (1 << 2) +#define ESAI_SAICR_OF1 (1 << 1) +#define ESAI_SAICR_OF0 (1 << 0) + +#define ESAI_TCR_TLIE (1 << 23) +#define ESAI_TCR_TIE (1 << 22) +#define ESAI_TCR_TEDIE (1 << 21) +#define ESAI_TCR_TEIE (1 << 20) +#define ESAI_TCR_TPR (1 << 19) +#define ESAI_TCR_PADC (1 << 17) +#define ESAI_TCR_TFSR (1 << 16) +#define ESAI_TCR_TFSL (1 << 15) +#define ESAI_TCR_TWA (1 << 7) +#define ESAI_TCR_TSHFD_MSB (0 << 6) +#define ESAI_TCR_TSHFD_LSB (1 << 6) +#define ESAI_TCR_TE5 (1 << 5) +#define ESAI_TCR_TE4 (1 << 4) +#define ESAI_TCR_TE3 (1 << 3) +#define ESAI_TCR_TE2 (1 << 2) +#define ESAI_TCR_TE1 (1 << 1) +#define ESAI_TCR_TE0 (1 << 0) +#define ESAI_TCR_TE(x) (0x3f >> (6 - ((x + 1) >> 1))) + +#define ESAI_TCR_TSWS_MASK 0xff83ff +#define ESAI_TCR_TSWS_STL8_WDL8 (0x00 << 10) +#define ESAI_TCR_TSWS_STL12_WDL8 (0x04 << 10) +#define ESAI_TCR_TSWS_STL12_WDL12 (0x01 << 10) +#define ESAI_TCR_TSWS_STL16_WDL8 (0x08 << 10) +#define ESAI_TCR_TSWS_STL16_WDL12 (0x05 << 10) +#define ESAI_TCR_TSWS_STL16_WDL16 (0x02 << 10) +#define ESAI_TCR_TSWS_STL20_WDL8 (0x0c << 10) +#define ESAI_TCR_TSWS_STL20_WDL12 (0x09 << 10) +#define ESAI_TCR_TSWS_STL20_WDL16 (0x06 << 10) +#define ESAI_TCR_TSWS_STL20_WDL20 (0x03 << 10) +#define ESAI_TCR_TSWS_STL24_WDL8 (0x10 << 10) +#define ESAI_TCR_TSWS_STL24_WDL12 (0x0d << 10) +#define ESAI_TCR_TSWS_STL24_WDL16 (0x0a << 10) +#define ESAI_TCR_TSWS_STL24_WDL20 (0x07 << 10) +#define ESAI_TCR_TSWS_STL24_WDL24 (0x1e << 10) +#define ESAI_TCR_TSWS_STL32_WDL8 (0x18 << 10) +#define ESAI_TCR_TSWS_STL32_WDL12 (0x15 << 10) +#define ESAI_TCR_TSWS_STL32_WDL16 (0x12 << 10) +#define ESAI_TCR_TSWS_STL32_WDL20 (0x0f << 10) +#define ESAI_TCR_TSWS_STL32_WDL24 (0x1f << 10) + +#define ESAI_TCR_TMOD_MASK 0xfffcff +#define ESAI_TCR_TMOD_NORMAL (0x00 << 8) +#define ESAI_TCR_TMOD_ONDEMAND (0x01 << 8) +#define ESAI_TCR_TMOD_NETWORK (0x01 << 8) +#define ESAI_TCR_TMOD_RESERVED (0x02 << 8) +#define ESAI_TCR_TMOD_AC97 (0x03 << 8) + +#define ESAI_TCCR_THCKD (1 << 23) +#define ESAI_TCCR_TFSD (1 << 22) +#define ESAI_TCCR_TCKD (1 << 21) +#define ESAI_TCCR_THCKP (1 << 20) +#define ESAI_TCCR_TFSP (1 << 19) +#define ESAI_TCCR_TCKP (1 << 18) + +#define ESAI_TCCR_TPSR_MASK 0xfffeff +#define ESAI_TCCR_TPSR_BYPASS (1 << 8) +#define ESAI_TCCR_TPSR_DIV8 (0 << 8) + +#define ESAI_TCCR_TFP_MASK 0xfc3fff +#define ESAI_TCCR_TFP(x) ((x & 0xf) << 14) + +#define ESAI_TCCR_TDC_MASK 0xffc1ff +#define ESAI_TCCR_TDC(x) (((x) & 0x1f) << 9) + +#define ESAI_TCCR_TPM_MASK 0xffff00 +#define ESAI_TCCR_TPM(x) (x & 0xff) + +#define ESAI_RCR_RLIE (1 << 23) +#define ESAI_RCR_RIE (1 << 22) +#define ESAI_RCR_REDIE (1 << 21) +#define ESAI_RCR_REIE (1 << 20) +#define ESAI_RCR_RPR (1 << 19) +#define ESAI_RCR_RFSR (1 << 16) +#define ESAI_RCR_RFSL (1 << 15) +#define ESAI_RCR_RWA (1 << 7) +#define ESAI_RCR_RSHFD_MSB (0 << 6) +#define ESAI_RCR_RSHFD_LSB (1 << 6) +#define ESAI_RCR_RE3 (1 << 3) +#define ESAI_RCR_RE2 (1 << 2) +#define ESAI_RCR_RE1 (1 << 1) +#define ESAI_RCR_RE0 (1 << 0) +#define ESAI_RCR_RE(x) (0xf >> (4 - ((x + 1) >> 1))) + +#define ESAI_RCR_RSWS_MASK 0xff83ff +#define ESAI_RCR_RSWS_STL8_WDL8 (0x00 << 10) +#define ESAI_RCR_RSWS_STL12_WDL8 (0x04 << 10) +#define ESAI_RCR_RSWS_STL12_WDL12 (0x01 << 10) +#define ESAI_RCR_RSWS_STL16_WDL8 (0x08 << 10) +#define ESAI_RCR_RSWS_STL16_WDL12 (0x05 << 10) +#define ESAI_RCR_RSWS_STL16_WDL16 (0x02 << 10) +#define ESAI_RCR_RSWS_STL20_WDL8 (0x0c << 10) +#define ESAI_RCR_RSWS_STL20_WDL12 (0x09 << 10) +#define ESAI_RCR_RSWS_STL20_WDL16 (0x06 << 10) +#define ESAI_RCR_RSWS_STL20_WDL20 (0x03 << 10) +#define ESAI_RCR_RSWS_STL24_WDL8 (0x10 << 10) +#define ESAI_RCR_RSWS_STL24_WDL12 (0x0d << 10) +#define ESAI_RCR_RSWS_STL24_WDL16 (0x0a << 10) +#define ESAI_RCR_RSWS_STL24_WDL20 (0x07 << 10) +#define ESAI_RCR_RSWS_STL24_WDL24 (0x1e << 10) +#define ESAI_RCR_RSWS_STL32_WDL8 (0x18 << 10) +#define ESAI_RCR_RSWS_STL32_WDL12 (0x15 << 10) +#define ESAI_RCR_RSWS_STL32_WDL16 (0x12 << 10) +#define ESAI_RCR_RSWS_STL32_WDL20 (0x0f << 10) +#define ESAI_RCR_RSWS_STL32_WDL24 (0x1f << 10) + +#define ESAI_RCR_RMOD_MASK 0xfffcff +#define ESAI_RCR_RMOD_NORMAL (0x00 << 8) +#define ESAI_RCR_RMOD_ONDEMAND (0x01 << 8) +#define ESAI_RCR_RMOD_NETWORK (0x01 << 8) +#define ESAI_RCR_RMOD_RESERVED (0x02 << 8) +#define ESAI_RCR_RMOD_AC97 (0x03 << 8) + +#define ESAI_RCCR_RHCKD (1 << 23) +#define ESAI_RCCR_RFSD (1 << 22) +#define ESAI_RCCR_RCKD (1 << 21) +#define ESAI_RCCR_RHCKP (1 << 20) +#define ESAI_RCCR_RFSP (1 << 19) +#define ESAI_RCCR_RCKP (1 << 18) + +#define ESAI_RCCR_RPSR_MASK 0xfffeff +#define ESAI_RCCR_RPSR_BYPASS (1 << 8) +#define ESAI_RCCR_RPSR_DIV8 (0 << 8) + +#define ESAI_RCCR_RFP_MASK 0xfc3fff +#define ESAI_RCCR_RFP(x) ((x & 0xf) << 14) + +#define ESAI_RCCR_RDC_MASK 0xffc1ff +#define ESAI_RCCR_RDC(x) (((x) & 0x1f) << 9) + +#define ESAI_RCCR_RPM_MASK 0xffff00 +#define ESAI_RCCR_RPM(x) (x & 0xff) + +#define ESAI_GPIO_ESAI 0xfff + +/* ESAI clock source */ +#define ESAI_CLK_FSYS 0 +#define ESAI_CLK_EXTAL 1 + +/* ESAI clock divider */ +#define ESAI_TX_DIV_PSR 0 +#define ESAI_TX_DIV_PM 1 +#define ESAI_TX_DIV_FP 2 +#define ESAI_RX_DIV_PSR 3 +#define ESAI_RX_DIV_PM 4 +#define ESAI_RX_DIV_FP 5 + #define IMX_DAI_ESAI_TX 0x04 #define IMX_DAI_ESAI_RX 0x08 #define IMX_DAI_ESAI_TXRX (IMX_DAI_ESAI_TX | IMX_DAI_ESAI_RX) diff --git a/sound/soc/imx/imx-pcm.c b/sound/soc/imx/imx-pcm.c index 2487d9284ac3..3e8a90da35c2 100644 --- a/sound/soc/imx/imx-pcm.c +++ b/sound/soc/imx/imx-pcm.c @@ -579,6 +579,14 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) else { buf->area = iram_alloc(size, &buf_paddr); buf->addr = buf_paddr; + + if (!buf->area) { + pr_warning("imx-pcm: Falling back to external ram.\n"); + UseIram = 0; + buf->area = + dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + } } if (!buf->area) diff --git a/sound/soc/mxs/mxs-adc.c b/sound/soc/mxs/mxs-adc.c index e8bb4255fff5..7069927b1ac3 100644 --- a/sound/soc/mxs/mxs-adc.c +++ b/sound/soc/mxs/mxs-adc.c @@ -37,6 +37,7 @@ #define MXS_ADC_RATES SNDRV_PCM_RATE_8000_192000 #define MXS_ADC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S32_LE) +#define ADC_VOLUME_MIN 0x37 struct mxs_pcm_dma_params mxs_audio_in = { .name = "mxs-audio-in", @@ -50,6 +51,166 @@ struct mxs_pcm_dma_params mxs_audio_out = { .irq = IRQ_DAC_DMA, }; +static struct delayed_work work; +static struct delayed_work adc_ramp_work; +static struct delayed_work dac_ramp_work; +static bool adc_ramp_done = 1; +static bool dac_ramp_done = 1; + +static void mxs_adc_schedule_work(struct delayed_work *work) +{ + schedule_delayed_work(work, HZ / 10); +} +static void mxs_adc_work(struct work_struct *work) +{ + /* disable irq */ + disable_irq(IRQ_HEADPHONE_SHORT); + + while (true) { + __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR); + msleep(10); + if ((__raw_readl(REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL) + & BM_AUDIOOUT_ANACTRL_SHORT_LR_STS) != 0) { + /* rearm the short protection */ + __raw_writel(BM_AUDIOOUT_ANACTRL_SHORTMODE_LR, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR); + __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_LR_STS, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR); + __raw_writel(BF_AUDIOOUT_ANACTRL_SHORTMODE_LR(0x1), + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET); + + __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_SET); + printk(KERN_WARNING "WARNING : Headphone LR short!\r\n"); + } else { + printk(KERN_WARNING "INFO : Headphone LR no longer short!\r\n"); + break; + } + msleep(1000); + } + + /* power up the HEADPHONE and un-mute the HPVOL */ + __raw_writel(BM_AUDIOOUT_HPVOL_MUTE, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_CLR); + __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR); + + /* enable irq for next short detect*/ + enable_irq(IRQ_HEADPHONE_SHORT); +} + +static void mxs_adc_schedule_ramp_work(struct delayed_work *work) +{ + schedule_delayed_work(work, msecs_to_jiffies(2)); + adc_ramp_done = 0; +} + +static void mxs_adc_ramp_work(struct work_struct *work) +{ + u32 reg = 0; + u32 reg1 = 0; + u32 reg2 = 0; + u32 l, r; + u32 ll, rr; + int i; + + reg = __raw_readl(REGS_AUDIOIN_BASE + \ + HW_AUDIOIN_ADCVOLUME); + + reg1 = reg & ~BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT; + reg1 = reg1 & ~BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT; + /* minimize adc volume */ + reg2 = reg1 | + BF_AUDIOIN_ADCVOLUME_VOLUME_LEFT(ADC_VOLUME_MIN) | + BF_AUDIOIN_ADCVOLUME_VOLUME_RIGHT(ADC_VOLUME_MIN); + __raw_writel(reg2, + REGS_AUDIOIN_BASE + HW_AUDIOIN_ADCVOLUME); + msleep(1); + + l = (reg & BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT) >> + BP_AUDIOIN_ADCVOLUME_VOLUME_LEFT; + r = (reg & BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT) >> + BP_AUDIOIN_ADCVOLUME_VOLUME_RIGHT; + + /* fade in adc vol */ + for (i = ADC_VOLUME_MIN; (i < l) || (i < r);) { + i += 0x8; + ll = i < l ? i : l; + rr = i < r ? i : r; + reg2 = reg1 | + BF_AUDIOIN_ADCVOLUME_VOLUME_LEFT(ll) | + BF_AUDIOIN_ADCVOLUME_VOLUME_RIGHT(rr); + __raw_writel(reg2, + REGS_AUDIOIN_BASE + HW_AUDIOIN_ADCVOLUME); + msleep(1); + } + adc_ramp_done = 1; +} + +static void mxs_dac_schedule_ramp_work(struct delayed_work *work) +{ + schedule_delayed_work(work, msecs_to_jiffies(2)); + dac_ramp_done = 0; +} + +static void mxs_dac_ramp_work(struct work_struct *work) +{ + u32 reg = 0; + u32 reg1 = 0; + u32 l, r; + u32 ll, rr; + int i; + + /* unmute hp and speaker */ + __raw_writel(BM_AUDIOOUT_HPVOL_MUTE, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_CLR); + __raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_SPEAKERCTRL_CLR); + + reg = __raw_readl(REGS_AUDIOOUT_BASE + \ + HW_AUDIOOUT_HPVOL); + + reg1 = reg & ~BM_AUDIOOUT_HPVOL_VOL_LEFT; + reg1 = reg1 & ~BM_AUDIOOUT_HPVOL_VOL_RIGHT; + + l = (reg & BM_AUDIOOUT_HPVOL_VOL_LEFT) >> + BP_AUDIOOUT_HPVOL_VOL_LEFT; + r = (reg & BM_AUDIOOUT_HPVOL_VOL_RIGHT) >> + BP_AUDIOOUT_HPVOL_VOL_RIGHT; + /* fade in hp vol */ + for (i = 0x7f; i > 0 ;) { + i -= 0x8; + ll = i > (int)l ? i : l; + rr = i > (int)r ? i : r; + reg = reg1 | BF_AUDIOOUT_HPVOL_VOL_LEFT(ll) + | BF_AUDIOOUT_HPVOL_VOL_RIGHT(rr); + __raw_writel(reg, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL); + msleep(1); + } + dac_ramp_done = 1; +} + +static irqreturn_t mxs_short_irq(int irq, void *dev_id) +{ + __raw_writel(BM_AUDIOOUT_ANACTRL_SHORTMODE_LR, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR); + __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_LR_STS, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR); + __raw_writel(BF_AUDIOOUT_ANACTRL_SHORTMODE_LR(0x1), + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET); + + __raw_writel(BM_AUDIOOUT_HPVOL_MUTE, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET); + __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_SET); + __raw_writel(BM_AUDIOOUT_ANACTRL_HP_CLASSAB, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET); + + mxs_adc_schedule_work(&work); + return IRQ_HANDLED; +} static irqreturn_t mxs_err_irq(int irq, void *dev_id) { struct snd_pcm_substream *substream = dev_id; @@ -104,68 +265,47 @@ static int mxs_adc_trigger(struct snd_pcm_substream *substream, { int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; int ret = 0; - u32 reg = 0; - u32 reg1 = 0; - u32 l, r; - u32 ll, rr; - int i; switch (cmd) { case SNDRV_PCM_TRIGGER_START: if (playback) { - reg = __raw_readl(REGS_AUDIOOUT_BASE + \ - HW_AUDIOOUT_HPVOL); - reg1 = BM_AUDIOOUT_HPVOL_VOL_LEFT | \ - BM_AUDIOOUT_HPVOL_VOL_RIGHT; - __raw_writel(reg1, REGS_AUDIOOUT_BASE + \ - HW_AUDIOOUT_HPVOL); - - __raw_writel(BM_AUDIOOUT_CTRL_RUN, + /* enable the fifo error interrupt */ + __raw_writel(BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_SET); - __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND, - REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR); - - reg1 = reg & ~BM_AUDIOOUT_HPVOL_VOL_LEFT; - reg1 = reg1 & ~BM_AUDIOOUT_HPVOL_VOL_RIGHT; - - l = (reg & BM_AUDIOOUT_HPVOL_VOL_LEFT) >> - BP_AUDIOOUT_HPVOL_VOL_LEFT; - r = (reg & BM_AUDIOOUT_HPVOL_VOL_RIGHT) >> - BP_AUDIOOUT_HPVOL_VOL_RIGHT; - for (i = 0x7f; i > 0 ; i -= 0x8) { - ll = i > l ? i : l; - rr = i > r ? i : r; - /* fade in hp vol */ - reg = reg1 | BF_AUDIOOUT_HPVOL_VOL_LEFT(ll) - | BF_AUDIOOUT_HPVOL_VOL_RIGHT(rr); - __raw_writel(reg, - REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL); - udelay(100); - } - __raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE, - REGS_AUDIOIN_BASE + HW_AUDIOOUT_SPEAKERCTRL_CLR); - } - else + /* write a data to data reg to trigger the transfer */ + __raw_writel(0x0, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DATA); + mxs_dac_schedule_ramp_work(&dac_ramp_work); + } else { __raw_writel(BM_AUDIOIN_CTRL_RUN, REGS_AUDIOIN_BASE + HW_AUDIOIN_CTRL_SET); - + mxs_adc_schedule_ramp_work(&adc_ramp_work); + } break; case SNDRV_PCM_TRIGGER_STOP: if (playback) { - __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND, - REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET); + if (dac_ramp_done == 0) { + cancel_delayed_work(&dac_ramp_work); + dac_ramp_done = 1; + } + __raw_writel(BM_AUDIOOUT_HPVOL_MUTE, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET); __raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE, - REGS_AUDIOOUT_BASE + HW_AUDIOOUT_SPEAKERCTRL_SET); - - __raw_writel(BM_AUDIOOUT_CTRL_RUN, + REGS_AUDIOOUT_BASE + HW_AUDIOOUT_SPEAKERCTRL_SET); + /* disable the fifo error interrupt */ + __raw_writel(BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_CLR); - } - else + } else { + if (adc_ramp_done == 0) { + cancel_delayed_work(&adc_ramp_work); + adc_ramp_done = 1; + } __raw_writel(BM_AUDIOIN_CTRL_RUN, REGS_AUDIOIN_BASE + HW_AUDIOIN_CTRL_CLR); + } break; case SNDRV_PCM_TRIGGER_RESUME: @@ -187,8 +327,13 @@ static int mxs_adc_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; int irq; + int irq_short; int ret; + INIT_DELAYED_WORK(&work, mxs_adc_work); + INIT_DELAYED_WORK(&adc_ramp_work, mxs_adc_ramp_work); + INIT_DELAYED_WORK(&dac_ramp_work, mxs_dac_ramp_work); + if (playback) { irq = IRQ_DAC_ERROR; cpu_dai->dma_data = &mxs_audio_out; @@ -205,14 +350,21 @@ static int mxs_adc_startup(struct snd_pcm_substream *substream, return ret; } + irq_short = IRQ_HEADPHONE_SHORT; + ret = request_irq(irq_short, mxs_short_irq, + IRQF_DISABLED | IRQF_SHARED, "MXS DAC/ADC HP SHORT", substream); + if (ret) { + printk(KERN_ERR "%s: Unable to request ADC/DAC HP SHORT irq %d\n", + __func__, IRQ_DAC_ERROR); + return ret; + } + /* Enable error interrupt */ if (playback) { __raw_writel(BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_CLR); __raw_writel(BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_CLR); - __raw_writel(BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN, - REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_SET); } else { __raw_writel(BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ, REGS_AUDIOIN_BASE + HW_AUDIOIN_CTRL_CLR); diff --git a/sound/soc/mxs/mxs-dai.c b/sound/soc/mxs/mxs-dai.c index a548b9948516..9ca22ecdb4b0 100644 --- a/sound/soc/mxs/mxs-dai.c +++ b/sound/soc/mxs/mxs-dai.c @@ -288,6 +288,7 @@ static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, default: return -EINVAL; } + break; default: return -EINVAL; } diff --git a/sound/soc/mxs/mxs-evk-adc.c b/sound/soc/mxs/mxs-evk-adc.c index bd1ed6bf691f..16c1cb4fab96 100644 --- a/sound/soc/mxs/mxs-evk-adc.c +++ b/sound/soc/mxs/mxs-evk-adc.c @@ -33,12 +33,119 @@ #include "mxs-adc.h" #include "mxs-pcm.h" +/* mxs evk machine connections to the codec pins */ +static const struct snd_soc_dapm_route audio_map[] = { + /* HPR/HPL OUT --> Headphone Jack */ + {"Headphone Jack", NULL, "HPR"}, + {"Headphone Jack", NULL, "HPL"}, + + /* SPEAKER OUT --> Ext Speaker */ + {"Ext Spk", NULL, "SPEAKER"}, +}; + +static int mxs_evk_jack_func; +static int mxs_evk_spk_func; + +static const char *jack_function[] = { "off", "on"}; + +static const char *spk_function[] = { "off", "on" }; + + +static const struct soc_enum mxs_evk_enum[] = { + SOC_ENUM_SINGLE_EXT(2, jack_function), + SOC_ENUM_SINGLE_EXT(2, spk_function), +}; + +static int mxs_evk_get_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.enumerated.item[0] = mxs_evk_jack_func; + return 0; +} + +static int mxs_evk_set_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (mxs_evk_jack_func == ucontrol->value.enumerated.item[0]) + return 0; + + mxs_evk_jack_func = ucontrol->value.enumerated.item[0]; + if (mxs_evk_jack_func) + snd_soc_dapm_enable_pin(codec, "Headphone Jack"); + else + snd_soc_dapm_disable_pin(codec, "Headphone Jack"); + + snd_soc_dapm_sync(codec); + return 1; +} + +static int mxs_evk_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.enumerated.item[0] = mxs_evk_spk_func; + return 0; +} + +static int mxs_evk_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (mxs_evk_spk_func == ucontrol->value.enumerated.item[0]) + return 0; + + mxs_evk_spk_func = ucontrol->value.enumerated.item[0]; + if (mxs_evk_spk_func) + snd_soc_dapm_enable_pin(codec, "Ext Spk"); + else + snd_soc_dapm_disable_pin(codec, "Ext Spk"); + + snd_soc_dapm_sync(codec); + return 1; +} +/* mxs evk card dapm widgets */ +static const struct snd_soc_dapm_widget mxs_evk_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), +}; + +static const struct snd_kcontrol_new mxs_evk_controls[] = { + SOC_ENUM_EXT("HP Playback Switch", mxs_evk_enum[0], mxs_evk_get_jack, + mxs_evk_set_jack), + SOC_ENUM_EXT("Speaker Playback Switch", mxs_evk_enum[1], + mxs_evk_get_spk, mxs_evk_set_spk), +}; + +static int mxs_evk_codec_init(struct snd_soc_codec *codec) +{ + int i, ret; + /* Add mxs evk specific controls */ + snd_soc_add_controls(codec, mxs_evk_controls, + ARRAY_SIZE(mxs_evk_controls)); + + /* Add mxs evk specific widgets */ + snd_soc_dapm_new_controls(codec, mxs_evk_dapm_widgets, + ARRAY_SIZE(mxs_evk_dapm_widgets)); + + /* Set up mxs evk specific audio path audio_map */ + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + snd_soc_dapm_sync(codec); + /* default on */ + mxs_evk_jack_func = 1; + mxs_evk_spk_func = 1; + + return ret; +} /* mxs evk dac/adc audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link mxs_evk_codec_dai = { .name = "MXS ADC/DAC", .stream_name = "MXS ADC/DAC", .cpu_dai = &mxs_adc_dai, .codec_dai = &mxs_codec_dai, + .init = mxs_evk_codec_init, }; /* mxs evk audio machine driver */ diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c index a9f0358687f4..dac91e3eb8fb 100644 --- a/sound/soc/mxs/mxs-pcm.c +++ b/sound/soc/mxs/mxs-pcm.c @@ -141,6 +141,7 @@ static int mxs_pcm_prepare(struct snd_pcm_substream *substream) /* Link with previous command */ prtd->dma_desc_array[i]->cmd.cmd.bits.bytes = prtd->dma_period; prtd->dma_desc_array[i]->cmd.cmd.bits.irq = 1; + prtd->dma_desc_array[i]->cmd.cmd.bits.dec_sem = 0; prtd->dma_desc_array[i]->cmd.cmd.bits.chain = 1; /* Set DMA direction */ if (playback) @@ -194,6 +195,8 @@ static void mxs_pcm_stop(struct snd_pcm_substream *substream) prtd->dma_desc_array[(desc + 1)%8]->cmd.cmd.bits.command = NO_DMA_XFER; mxs_dma_unfreeze(prtd->dma_ch); + + mxs_dma_disable(prtd->dma_ch); } static int mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd) @@ -375,6 +378,7 @@ static int mxs_pcm_close(struct snd_pcm_substream *substream) free_irq(prtd->params->irq, substream); mxs_dma_get_cooked(prtd->dma_ch, &list); /* Free DMA channel*/ + mxs_dma_reset(prtd->dma_ch); for (desc = 0; desc < desc_num; desc++) mxs_dma_free_desc(prtd->dma_desc_array[desc]); mxs_dma_release(prtd->dma_ch, mxs_pcm_dev); |